[{"title":"Part 1 — Maximo Automation Testing through Selenium with Python — Dev Environment Setup and SSO","permalink":"https://eamstream.com/posts/maximo-automation-testing-selenium-python-part1/","summary":"1. Background Comparing to manual testing, automation testing definitely has a lot of advantages: More precise testing, decrease testing time dramatically, integrate with DevOps process, etc. But the major challenge is to implement automation testing, especially for the complicate scenario. For example, some test cases required combine the functional and integration testing together. In my current Maximo project, there are a lot of test cases complicate like this. Each release requires a lot of effort to retest some of the test cases manually, also need to do the full regression testing manually to make sure the updates in the new release not breaking existing functions / interfaces. I started to look into automation testing solution for Maximo.\n","content":"1. Background Comparing to manual testing, automation testing definitely has a lot of advantages: More precise testing, decrease testing time dramatically, integrate with DevOps process, etc. But the major challenge is to implement automation testing, especially for the complicate scenario. For example, some test cases required combine the functional and integration testing together. In my current Maximo project, there are a lot of test cases complicate like this. Each release requires a lot of effort to retest some of the test cases manually, also need to do the full regression testing manually to make sure the updates in the new release not breaking existing functions / interfaces. I started to look into automation testing solution for Maximo.\nIf your organization already upgraded / implemented to Maximo Application Suite (MAS), and your automation testing requirement only focus on functions, maybe you can try IBM Maximo Test Automation Framework, which you can find detail information from here:\nOn these serial blogs, I will only focus on the Maximo automation testing through Selenium with Python, not leveraging the IBM Maximo Test Automation Framework. There are couple reasons for it, but the major one is my project is not on the MAS boat, and my testing requirement is more complicate than functional testing in Maximo. Selenium is a powerful tool for controlling web browsers through programs and performing browser automation. It is functional for all browsers, works on all major OS and its scripts are written in various languages i.e. Python, Java, C#, etc. Selenium with Python opens up many possibilities for efficient and effective web application testing. Through Selenium with Python, we can implement the automation testing to meet the complicate testing case scenario requirement.\n2. Development Environment Setup The following is the technical stack we will leverage in this experiment.\n(1) Coding Editor — VS Code\n(2) Coding language — Python\n(3) Unit Testing Package — Python unittest\n(4) Automation Testing Framework / Tool — Selenium\n(5) Browser — Chrome\n(6) OS — Windows 10 /11\nIf you are not familiar with above technologies, strongly recommend you go through the following topics to have basic concept of them before we move to next step.\n**Python unittest — **Python unit testing framework was originally inspired by JUnit and has a similar flavor as major unit testing frameworks in other languages. It supports test automation, sharing of setup and shutdown code for tests, aggregation of tests into collections, and independence of the tests from the reporting framework.\nhttps://docs.python.org/3/library/unittest.html#\n**Selenium WebDriver **— Selenium supports automation of all the major browsers in the market through the use of WebDriver. WebDriver is an API and protocol that defines a language-neutral interface for controlling the behaviour of web browsers. Each browser is backed by a specific WebDriver implementation, called a driver. The driver is the component responsible for delegating down to the browser, and handles communication to and from Selenium and the browser.\nhttps://www.selenium.dev/documentation/webdriver/getting_started/\nNow before we can start our automation testing coding, we need to setup our development environment. The following are the high level setup steps, you can refer to the links on each step from official website for the tool’s setup and configuration.\nStep 1: Install VS Code\nVS Code is the most popular light weight coding editor, which has tons of the extension tools can be used. You can download it from official website and install it.\nhttps://code.visualstudio.com/download\nPlease select the right version which match to your OS.\nStep 2: Install Python and Pythons extension in VS Code.\nPlease follow the steps on this page to install Python and VS Code Python Extension\nStep 3: Install Selenium\nOpen VS Code, in the terminal window (if you don’t have one, you can open a new one through menu Terminal -\u0026gt; New Terminal to open one. Type the following command in the terminal to install Selenium package.\npip install -U selenium After install selenium successfully through pip, you can type the below command in the terminal to check the installed selenium version.\npip show selenium You should be able to see similar information as following:\n**Step 4: **Install ChromeDriver and configure the path\nWebDriver is an open source tool for automated testing of webapps across many browsers. It provides capabilities for navigating to web pages, user input, JavaScript execution, and more. ChromeDriver is a standalone server that implements the W3C WebDriver standard. ChromeDriver is available for Chrome on Android and Chrome on Desktop (Mac, Linux, Windows and ChromeOS). In our experiment, we will use ChromeDriver as the webdriver for our testing. You can download the latest ChromeDriver stable version from the below link:\nhttps://googlechromelabs.github.io/chrome-for-testing/#stable\nAfter you download the ChromeDriver package, unzip to a folder, use the below command add ChromeDriver to the path, then you don’t need to pass ChromeDriver folder information in the code every time.\nsetx /M path \u0026#34;%path%; your chromedrive folder path\u0026#34; Note: If you don’t have administrator permission, you can remove /M parameter from the above command to add the path to current user only.\n3. Requirement After complete development environment setup, let’s take a look what test case we gotten implement automation test through above technical stack. Assume Maximo was implemented authentication through Single Sign On (SSO) solution, we would like to use Selenium with Python to implement a user login. This scenario is a pretty common start point for most of the automation testing, simulate a particular role user (for example Asset Manager) login the system to perform some functions test case later.\n4. Implementation To be able to implement above requirement, we need to use chrome browser incognito mode which can separate simulated login user session will not be impacted by current windows login user session.\nIn the VS Code, open a blank folder for your project, create a new python file, type the following code in the new python file.\nimport unittest from selenium import webdriver from selenium.webdriver import Keys,ChromeOptions from selenium.webdriver.common.by import By import time class LoginTestCase(unittest.TestCase): # setUp function will be run before any test case to be executed def setUp(self): #Open incognito mode for simulated user login chrome_options = ChromeOptions() chrome_options.add_argument(\u0026#34;--incognito\u0026#34;) self.browser = webdriver.Chrome(options=chrome_options) self.addCleanup(self.browser.quit) # Test case for single sign on login def test_SSO_Login(self): #Give 5 second to allow browser to redirect to single sign on login page self.browser.implicitly_wait(5) #Need to update to your maximo instance url self.browser.get(\u0026#39;https//yourmaximo.com\u0026#39;) #Find login email textbox on the SSO login page and auto fill in the login email userelement=self.browser.find_element(By.ID,\u0026#34;i0116\u0026#34;) #Need to update to your user email account to login userelement.send_keys(\u0026#34;your@email.com\u0026#34;) userelement.send_keys(Keys.ENTER) #Allow 5 second to load password page time.sleep(5) #Find password textbox on the SSO login page and auto fill in the login email pwdelement=self.browser.find_element(By.ID,\u0026#34;i0118\u0026#34;) #Need to update to your user password pwdelement.send_keys(\u0026#34;yourpassword\u0026#34;) pwdelement.send_keys(Keys.ENTER) time.sleep(5) #Sometime after login there is popup window ask user whether Stay signed in. Find yes button and simulate click it. yesbutton=self.browser.find_element(By.ID,\u0026#34;idSIButton9\u0026#34;) if yesbutton is not None: yesbutton.send_keys(Keys.ENTER) #Allow 5 second to redirect to Maximo Start Center after SSO login successfully time.sleep(5) #Check if successfuly login Maximo or not through assert current page title is start center or not. self.assertIn(\u0026#39;Start Center\u0026#39;, self.browser.title) if __name__ == \u0026#39;__main__\u0026#39;: unittest.main(verbosity=2) The comments in above code already have pretty good explanation. The only tip I would like to provide here is how to get html element ID which can be provided to the function *find_element(). *When you open the page you are trying to find element ID in chrome, click 3 dot icon at the right top, select the menu More tools -\u0026gt;Developer Tools.\nOn the developers tool screen, click left top arrow button.\nIt will allow you when you click the web page element, it will automatically locate the html element on the development tools source code tab, which you can identify the element ID if it has.\nAfter you run the python code in VS Code, if it is successful pass the test case, you should see the OK result in the output as following:\n5. Summary Let’s recap what I introduce in this blog: We setup development environment for automation testing development for Selenium with Python in VS Code. We develop python script to implement automation test case for Maximo login through Single Sign On (SSO). In next blog, we will explore the implementation of automation testing for more complicate test case to combine business function with integration.\n"},{"title":"Customized Inbound Message Processing Logic for Maximo Enterprise Service through Automation Script","permalink":"https://eamstream.com/posts/customized-inbound-message-processing-automation-script/","summary":"If you don’t have Medium account, you can read this blog through this friend link.\nIn my previous blog “Introduce Maximo Enterprise Service to Accept Inbound Messages from Other Systems”, I introduced how to configure Maximo Enterprise Service for accepting inbound messages. In this blog, we will discuss how to implement customized logic in Maximo Enterprise Service through automation script to meet some special requirement.\n1. Automation Script VS Java Maximo provides multiple options to allow you customize out of box (OOO) Maximo function / feature. For the Maximo Integration Framework (MIF), You can develop your customized integration logic through Java or Automation Script. The major difference between the java and Automation Script options is that Automation Script doesn’t require redeploy EAR file, but Java code need to rebuild EAR and redeploy it to Maximo Server.\n","content":"If you don’t have Medium account, you can read this blog through this friend link.\nIn my previous blog “Introduce Maximo Enterprise Service to Accept Inbound Messages from Other Systems”, I introduced how to configure Maximo Enterprise Service for accepting inbound messages. In this blog, we will discuss how to implement customized logic in Maximo Enterprise Service through automation script to meet some special requirement.\n1. Automation Script VS Java Maximo provides multiple options to allow you customize out of box (OOO) Maximo function / feature. For the Maximo Integration Framework (MIF), You can develop your customized integration logic through Java or Automation Script. The major difference between the java and Automation Script options is that Automation Script doesn’t require redeploy EAR file, but Java code need to rebuild EAR and redeploy it to Maximo Server.\nIn this blog, we will only focus on the option to use automation script to implement customize inbound integration logic for Maximo Enterprise Service.\n2. Requirement Assume we have a System A is to send new / updated asset data to Maximo, asset description will default to concatenate asset description in the payload and current system date. And System A would like to received the response information from Maximo to know if the asset is created or updated in Maximo for the current payload.\n3. Solution Based on above requirement, we can build a synchronized Enterprise Service in Maximo to receive the new / updated asset data from System A, and build automation script for enterprise service request user exist class to implement the default asset description, and build automation script for enterprise response user exist class to provide the action (Create or Update) back to System A.\n4. Implementation Step 1: Create Object Structure, Enterprise Service and External System\nFollow the steps in Implementation section on this Enterprise Services introduction blog to create Object Structure, Enterprise Service and External System.\nStep 2: Create Automation Script for Enterprise Services Request User Exist\nGo to System Configuration =\u0026gt; Platform Configuration =\u0026gt; Automation Scripts. Click on Select Action=\u0026gt; Create=\u0026gt;Script for Integration. Select Enterprise Service option on the popup create script window, and select the Enterprise service “ESASSET” which created on step 1. Select the other options as highlighted on the below screenshot.\nOn the Script Language, I selected jython, which is Python in Java, providing the benefit of writing the Python script which can run on the JVM and access to classes written in Java. You can also choose other script language in the following list which you are familiar to:\nAt the bottom of this Create Script for Integration page, there is a script box. Type in the following script:\n#AUTOSCRIPT:SYNC.ESASSET.USEREXIT.IN.AFTER #DESCRIPTION:Demo script to demostrate Enterprise Service Request customized logic from psdi.server import MXServer #Get current server time string currentTime=MXServer.getMXServer().getDate().toString(); #This command breaks the input XML so the data can be manipulated. #This line should not be necessary, because the framework should do this for you. #Only add this breakData() function if you have java.lang.NullPointerException when you call getCurrentData function irData.breakData(); #Get Asset Description field from payload assetDescription = irData.getCurrentData(\u0026#34;DESCRIPTION\u0026#34;); #Update Asset Description field to append current server time irData.setCurrentData(\u0026#34;DESCRIPTION\u0026#34;,assetDescription + \u0026#34; - \u0026#34; + currentTime); The comments in the code already explain the code logic. Click “Create” button to create the automation script to build customized logic for Enterprise Service request user exist to append the system time to the asset description field.\nStep 3: Validate the Enterprise Service Request Automation Script\nOpen the postman, refer to the “**Step 4: Verify the configuration” **on my previous blog “Introduce Maximo Enterprise Service to Accept Inbound Messages from Other Systems”, to setup postman, use the following payload to test the automation script:\n\u0026lt;?xml version=\u0026#34;1.0\u0026#34; encoding=\u0026#34;UTF-8\u0026#34;?\u0026gt; \u0026lt;SyncOSASSET xmlns=\u0026#34;http://www.ibm.com/maximo\u0026#34; xmlns:xsi=\u0026#34;http://www.w3.org/2001/XMLSchema-instance\u0026#34;\u0026gt; \u0026lt;OSASSETSet\u0026gt; \u0026lt;ASSET action=\u0026#34;AddChange\u0026#34;\u0026gt; \u0026lt;ASSETNUM\u0026gt;DEMOASSET\u0026lt;/ASSETNUM\u0026gt; \u0026lt;DESCRIPTION\u0026gt;Add asset description Asset for demo\u0026lt;/DESCRIPTION\u0026gt; \u0026lt;SITEID\u0026gt;AMTRAK\u0026lt;/SITEID\u0026gt; \u0026lt;STATUS\u0026gt;ACTIVE\u0026lt;/STATUS\u0026gt; \u0026lt;/ASSET\u0026gt; \u0026lt;/OSASSETSet\u0026gt; \u0026lt;/SyncOSASSET\u0026gt; After you execute the payload, you should see the following response from Maximo:\nOpen Asset application in Maximo, search for the asset created / updated through the payload, you should be able to see the asset description automatically appended system time stamp to it.\nSummary: In this blog, we learn how to use automation script to implement a simple customize logic for processing inbound message in Maximo Enterprise Service. Of cause, you can expand this option to implement more complicate logic through automation script in Maximo.\n"},{"title":"Introduce Maximo Enterprise Service to Accept Inbound Messages from Other Systems","permalink":"https://eamstream.com/posts/maximo-enterprise-service-inbound-messages/","summary":"If you don’t have Medium member, you can try this friend link to read.\nIn my previous blog Maximo Publish Channel for Sending Outbound Messages introduces outbound message from Maximo. How Maximo can accept inbound message from other system? There are 2 ways Maximo can receive outbound message from outside system to update the data in Maximo: (1) Through Object Structure Restful API (You can refer to my other blog “Introduction of Maximo NextGen Rest APIs — Part 2 Update Maximo Data”, or (2) Through Enterprise Service, which will provide step by step instruction in this blog.\n","content":"If you don’t have Medium member, you can try this friend link to read.\nIn my previous blog Maximo Publish Channel for Sending Outbound Messages introduces outbound message from Maximo. How Maximo can accept inbound message from other system? There are 2 ways Maximo can receive outbound message from outside system to update the data in Maximo: (1) Through Object Structure Restful API (You can refer to my other blog “Introduction of Maximo NextGen Rest APIs — Part 2 Update Maximo Data”, or (2) Through Enterprise Service, which will provide step by step instruction in this blog.\nMaximo Enterprise is part of Maximo Integration Frame (MIF) to receive outbound message / data from external system. This article is to provide the instruction on how to configure Maximo Enterprise Service along with other MIF modules to receive the data from other systems.\nYou will gain the following knowledges on the following modules in MIF after following this instruction, which was introduced on my other Publish Channel intruction blog too:\n(a) Object Structure (OS)\n(b) Enterprise Service (ES)\n(c) External System\n1. Requirement: Assume that we have the integration requirement to reeive the asset information from other system (for example SAP). When any new asset is created, updated in external system, like SAP, it will call Maximo interface to create or update asset data in Maximo. That means SAP is the system of record for asset data, but need sync up asset data to Maximo for asset maintenance process, like work order management.\n2. Technical Solution:\nTo implement the above requirement, we can leverage Maximo NextGen Restful API which I introduced in my this article to update asset data in Maximo:\nIntroduction of Maximo NextGen Rest APIs — Part 2 Update Maximo Data\nBut there is a limitation with NextGen Restful API solution to update / delete data in Maximo. You need to query the record to obtain resource ID, and then use resource ID to form the URI to update the record. It required to access Maximo twice to update one record. With the Enterprise Service, you just need to post once, and you can customize your interface logic through customized Enterprise Service User Exit class. This blog will not cover customized interface process logic through User Exit class, might have other blog in future to cover this topic.\nAn enterprise service is a pipeline for querying system data and importing data into Maximo IT from an external system. Data processing layers that transform data and apply business processing rules to data before it reaches the system objects. These processing layers include: (a) Processing rules — The integration framework provides a rule engine where you can filter and transform the XML message. (b) User exit — The user exit specifies a Java™ class that you can use to filter, transform data, and implement business logic. You can use this class as part of an installation-customization. (c) Data processing class — The processing class specifies a Java class that you can use to filter, transform data, and implement business logic. (d) XSL map — The XSL map specifies an XSLT style sheet that you can use to transform data and map the XML data message to another format.\nEnterpise Service\n3. Implementation\nThe following is the step by step instruction along with explanation to use publish channel to implement above requirement.\nStep 1: Create Object Structure (OS) to organize the inbound data structure\nAn object structure is the common data layer that the integration framework components use for outbound and inbound application message processing. An object structure consists of one or more related business objects that define the content of an XML or JSON message (schema).\nOpen Object Structures application through Integration -\u0026gt; Object Structures menu. Click New Object Structure Button to create a new Object Structure to organize the asset data we plan to send out to other system. Fill out the required information for the OS.\nIn Source Objects section, click New Row button to add a new Maximo Business Object (MBO), in our case, we will add Asset MBO to this object structure.\nAdd Asset MBO. Click New Row again in Source Objects section, to add a child MBO ServiceAddress to send address information along with Asset to other system. Make sure select Parent Object to be Asset which we added before, and pick up the relationship “SERVICEADDRESS” for Asset and ServiceAddress MBO. You can understand relationship is how to join Asset and ServiceAddress tables in SQL Query.\nSave the above OS settings. Click Select Action -\u0026gt; Exclude/Include Fields menu from Object Structures Application to open Exclude/Include Fields window. This setting is to configure what fields we would like to explore to the external system in Asset and ServiceAddress MBOs we added to the OSASSET object structure in previous step. Select ASSET MBO in the Source Object section, check all of the fields in Persistent Fields section except for AssetNum , Status and Description fields, which we plan to send only those fields to the external system.\nSelect ServiceAddress MBO and set AddressLine, City, County to be uncheck which we plan to explore asset service address information along with Asset information to other system .\nClick OK to save the Exclude/Include Fields setting to complete OS configuration.\nStep 2: Create Enterprise Service\nOpen Enterprise Services application through the menu Integration -\u0026gt; Enterprise Services. Click New button to create a new Enterprise Service. Input the Enterprise Service name, description, and pick up the Object Structure OSASSET we created in previous step. After select OSASSET as object structure for the Publish Channel, the asset and serviceaddress MBOs in the object structure OSASSET is pulled to Object Structure Sub-Records section. Click Save button to save the configuration.\nClick menu “Select Action -\u0026gt; Message Tracking” to open Publish Channel Message Tracking Setting, check Enable Message Tracking and Store Message checkboxes, which will allow us to view the outbound message for this PC in Message Tracking application.\nYou can configure process rule at Object Structure Business Processing Rules section. For example, if you want to skip to process the asset with status is decommissioned, you can click “New Row” button to add a skip rule as following:\nAnd click “Add/Modify Conditions” button to define asset =DECOMMISSIONED condition as below:\nClick OK button to save the configuration.\nStep3: Create an External System to receive Asset data from external application.\nAn external system in Maximo is any business application that sends data to Maximo or receives data from Maximo Asset Management. You can use and configure enterprise services and publish channels to exchange data with one or more external systems. The Maximo system sends messages to an external system or application. You create an external system to exchange with external applications.\nOpen the External Systems Application through Integration -\u0026gt; External Systems. Input system name and description. Check Enable checkbox. For Enterprise Service, there are 2 types of inbound queue: Sequential and Continuous. If your inbound messages need to be processed in the order based on the arrive time sequence, for example, the external system sends work order process data to Maximo with different status based on the defined work flow process, Maximo should process the work order status with the messages arrive time sequence, then you should choose sequential queue for the enterprise. If the inbound messages to be processed doesn’t care about the order, you can choose continual inbound queue. Another big difference between Sequential and Continuous queue is that when there is error happen, the sequential queue will be blocked (cannot process the following messages until the error message is cleaned up), but continual queue can continue processing the following messages.\nFor our case, the Asset inbound messages can be processed without sequence, we can set Inbound Continuous Queue with the out of box inbound queue: jms/maximo/int/queues/cqin. Of course you can configure your own inbound sequential / continuous queue, which is not in this instruction scope.\nClick on Enterprise Services tab, select the enterprise service ESASSET we created at Step 2. And check Enable checkbox to enable the enterprise service. And check “Use Continuous Queue” to configure this enterprise service will use continuous queue. If you don’t check this checkbox, it will default to use sequential queue.\nStep 4: Verify the configuration.\nNow we are ready to test enterprise service to receive the payload from external system. We will use postman to simulate SAP to send payload to external.\nOpen postman, create a new request, input the following url on the new request url box, select request type to be POST. In the below url, the first “ESASSET” is the external system name we created on step 3, and the last “ESASSET” is the enterprise service name we created on step 2. (I should use better naming convention for it.)\nhttps://{yourmaximoserver}.com/meaweb/esqueue/ESASSET/ESASSET\nOn the postman Authorization tab, select your Maximo integration authorization type. For this case, we use basic auth to input username and password.\nYou can get more information regarding Maximo integration authorization at the **Authentication **section on my other blog: Introduction of Maximo NextGen Rest APIs — Part 1 Query Maximo Data\nClick the Body tab on postman request, select raw option, and pickup XML as format from the dropdown list.\nInput the following XML payload on the body textbox.\n\u0026lt;?xml version=\u0026#34;1.0\u0026#34; encoding=\u0026#34;UTF-8\u0026#34;?\u0026gt; \u0026lt;SyncOSASSET xmlns=\u0026#34;http://www.ibm.com/maximo\u0026#34; xmlns:xsi=\u0026#34;http://www.w3.org/2001/XMLSchema-instance\u0026#34;\u0026gt; \u0026lt;OSASSETSet\u0026gt; \u0026lt;ASSET action=\u0026#34;AddChange\u0026#34;\u0026gt; \u0026lt;ASSETNUM\u0026gt;DEMOASSET\u0026lt;/ASSETNUM\u0026gt; \u0026lt;DESCRIPTION\u0026gt;Add asset description Asset for demo\u0026lt;/DESCRIPTION\u0026gt; \u0026lt;SITEID\u0026gt;DEMOSITE\u0026lt;/SITEID\u0026gt; \u0026lt;STATUS\u0026gt;ACTIVE\u0026lt;/STATUS\u0026gt; \u0026lt;SERVICEADDRESS\u0026gt; \u0026lt;ADDRESSCODE\u0026gt;DEMOADDR\u0026lt;/ADDRESSCODE\u0026gt; \u0026lt;CITY\u0026gt;ATLANTA\u0026lt;/CITY\u0026gt; \u0026lt;COUNTRY\u0026gt;US\u0026lt;/COUNTRY\u0026gt; \u0026lt;COUNTY /\u0026gt; \u0026lt;DESCRIPTION\u0026gt;Demo Address\u0026lt;/DESCRIPTION\u0026gt; \u0026lt;ORGID\u0026gt;DEMOORG\u0026lt;/ORGID\u0026gt; \u0026lt;POSTALCODE\u0026gt;30038\u0026lt;/POSTALCODE\u0026gt; \u0026lt;STREETADDRESS\u0026gt;1000 Demo Street\u0026lt;/STREETADDRESS\u0026gt; \u0026lt;/SERVICEADDRESS\u0026gt; \u0026lt;/ASSET\u0026gt; \u0026lt;/OSASSETSet\u0026gt; \u0026lt;/SyncOSASSET\u0026gt; The above XML payload is to create / update an Asset with Assetnum= DEMOASSET. You might notice there is an action property at the Asset node in this payload. The following action value you can leverage in your payload for the differernt scenario.\nClick Send button on the request page, if everything is good, you will receive 200 response code from Maximo.\nTo check what have been sent to Maximo, open Message Tracking application in Maximo, filter Integration Component with Enterprise name “ESASSET”, we would see the following payload have been processed\nAnd open the Asset application in Maximo, look for the DEMOASSET record, we can find it is created in Maximo.\n4. Summary\nLet’s recap what we learn on this blog: We create an Object Structure to organize the data structure to be processed, and then create an Enterprise Service to define the process rules for this interface, and use External Service to define what type of the message queue to be used to process this interface. Last we learn how to use postman to simulate the integration testing.\nHope you enjoy this blog, and feel free to leave your comments if you have any question / comment on it.\n"},{"title":"Maximo Asset/Location Hierarchy Query","permalink":"https://eamstream.com/posts/maximo-asset-location-hierarchy-query/","summary":"In Maximo, Asset / Location hierarchy is a pretty standard data format for asset and location management. The following is an example of HVAC asset hierarchy in Maximo asset drilldown function.\nIt would be very common for the business user asks to have asset / location hierarchy report along with other information. There is an out of box (OOO) Asset Hierarchy in Maximo with very limit information (only asset num and description fields). To query the asset / location hierarchy information along with other information, for example, level information, custom format description which can show the layer indent description make it looks like a tree instead of flat table.\n","content":"In Maximo, Asset / Location hierarchy is a pretty standard data format for asset and location management. The following is an example of HVAC asset hierarchy in Maximo asset drilldown function.\nIt would be very common for the business user asks to have asset / location hierarchy report along with other information. There is an out of box (OOO) Asset Hierarchy in Maximo with very limit information (only asset num and description fields). To query the asset / location hierarchy information along with other information, for example, level information, custom format description which can show the layer indent description make it looks like a tree instead of flat table.\nIn Maximo, Asset and location hierarchy are managed in a little different tables structure. The following would provide the sample sql query script to pull the asset or location hierarchy information.\n(1) Asset Hierarchy\nIn Maximo, there are 2 major tables to maintain asset hierarchy information: ASSET and ASSETANCESTOR. Asset table contain asset detail information along with parent asset field, ASSETANCESTOR table contain asset hierarchy level and asset Ancestor (top level asset) information. The following sql script can help you pull HVAC asset 1359 hierarchy information in previous screenshot.\nselect a.ASSETNUM ,a.PARENT , s.HIERARCHYLEVELS AS level, a.DESCRIPTION, lpad(\u0026#39;.\u0026#39;,(s.HIERARCHYLEVELS)*4) CONCAT a.DESCRIPTION as padded_asset from maximo.ASSET a INNER JOIN maximo.ASSETANCESTOR s ON a.ASSETNUM =s.ASSETNUM where s.ANCESTOR = \u0026#39;1359\u0026#39; After execute the above script, we will retrieve the following data:\nIt looks good except the order. If we would like to get the data with the tree structure order like below:\nwe need to adjust our query to add a field for sorting purpose. The following is the updated script to pull the data with tree structure order.\nwith assetparent (assetnum,parent, level, DESCRIPTION,padded_asset,order_sequence ) as ( select a.ASSETNUM ,a.PARENT, 0 AS level, a.DESCRIPTION, a.DESCRIPTION as padded_asset,CAST(a.ASSETNUM AS nvarchar(1000)) AS order_sequence from maximo.asset a where a.ASSETNUM = \u0026#39;1359\u0026#39; union all select a.ASSETNUM ,a.PARENT,p.LEVEL+1 AS level,a.DESCRIPTION, lpad(\u0026#39;.\u0026#39;,(p.LEVEL+1)*4) CONCAT a.DESCRIPTION as padded_asset, CAST(p.order_sequence CONCAT \u0026#39;_\u0026#39; CONCAT a.ASSETNUM AS nvarchar(1000)) AS order_sequence from maximo.ASSET a, assetparent p where p.assetnum = a.PARENT ) select * from assetparent ORDER BY order_sequence; In above sql script, we used recursive query to generate the level and the field “order_sequence” for sorting as tree structure. After execute the above script, we can pull the Asset hierarchy from Maximo database as tree structure order.\nIf your Maximo instance database is Oracle which supports “connect by” recursive query, you can simply the above query as below:\nselect assetnum, parent, level, lpad(\u0026#39;.\u0026#39;,level*4) || assetum as padded_asset from maximo.asset connect by prior assetnum = parent and prior siteid = siteid start with assetnum = \u0026#39;1359\u0026#39; In Maximo, Locations table structure has a little difference with Asset table for hierarchy perspective. In locations table, the Parent field in Maximo is non-persistent field, that means this field doesn’t existing in Maximo Locations table. Maximo uses Lochierarch to maintain location parent-child relationship. The following script can pull location hierarchy data start from the parent location “HVACROOM1” from Maximo database.\nwith locparent (location,parent, level, DESCRIPTION, padded_loc,order_sequence ) as ( select l.location,h.PARENT, 0 AS level,l.DESCRIPTION, l.DESCRIPTION as padded_loc,CAST(l.location AS nvarchar(100)) AS order_sequence from maximo.locations l INNER JOIN maximo.lochierarchy h ON l.LOCATION =h.LOCATION where l.LOCATION = \u0026#39;HVACROOM1\u0026#39; union all select l.location,h.PARENT,p.LEVEL+1 AS level, l.DESCRIPTION, lpad(\u0026#39;.\u0026#39;,(p.LEVEL+1)*4) CONCAT l.DESCRIPTION as padded_loc, CAST(p.order_sequence CONCAT \u0026#39;_\u0026#39; CONCAT l.location AS nvarchar(100)) AS order_sequence from maximo.locations l , maximo.lochierarchy h , locparent p where p.location = h.PARENT AND l.LOCATION =h.LOCATION ) select * from locparent ORDER BY order_sequence; And if your Maximo database instance is Oracle, you can simplify the above query as following:\nselect l.location,level,l.description, lpad(\u0026#39;.\u0026#39;,level*4) || l.location as padded_loc from maximo.lochierarchy h INNER JOIN maximo.location l ON h.location=l.location connect by prior h.location = h.parent and prior h.siteid = h.siteid start with h.location = \u0026#39;HVACROOM1\u0026#39; "},{"title":"Object structure in Maximo is how you construct your data to bind the inbound payload to Maximo","permalink":"https://eamstream.com/posts/maximo-object-structure-inbound-payload/","summary":"Object structure in Maximo is how you construct your data to bind the inbound payload to Maximo database\n","content":"Object structure in Maximo is how you construct your data to bind the inbound payload to Maximo database\n"},{"title":"Introduce Maximo Publish Channel for Sending Outbound Messages","permalink":"https://eamstream.com/posts/maximo-publish-channel-outbound-messages/","summary":"Maximo Publish Channel is part of Maximo Integration Frame (MIF) to send outbound message / data from Maximo to external system. This article is to provide the instruction on how to configure Maximo Publish Channel along with other MIF modules to send data from Maximo to other systems.\nYou will gain the following knowledges on the following modules in MIF after following this instruction:\n(a) Object Structure (OS)\n(b) Publish Channel (PC)\n","content":"Maximo Publish Channel is part of Maximo Integration Frame (MIF) to send outbound message / data from Maximo to external system. This article is to provide the instruction on how to configure Maximo Publish Channel along with other MIF modules to send data from Maximo to other systems.\nYou will gain the following knowledges on the following modules in MIF after following this instruction:\n(a) Object Structure (OS)\n(b) Publish Channel (PC)\n(c) End Point\n(d) External System\n1. Requirement: Assume that we have the integration requirement to send the asset information from Maximo to other system (for example ServiceNow) when any new asset is created, updated in Maximo. That means Maximo is the system of record for asset data.\n2. Technical Solution:\nTo implement the above requirement, we can leverage Maximo NextGen Restful API which I introduced in my this article:\nIntroduction of Maximo NextGen Rest APIs — Part 1 Query Maximo Data\nBut the downside of this solution is that you need to build a batch job to query new / updated asset data through Maximo Restful API periodically. And it is not the real time integration. If we need to implement Asset data in time (event trigger) integration with other system, Publish Channel is the better option.\nPublish Channels are used in Maximo to send data asynchronously from the system to an external system. They are the outbound integration backbone of Maximo. Publish Channels can be event-enabled to trap events when some MBOs get added, updated or deleted, and publish a message to the outbound JMS queues. The following is the architecture diagram for Maximo Publish Channel.\nPublish Channel\n3. Implementation\nThe following is the instruction along with explanation to use publish channel to implement above requirement.\nStep 1: Create Object Structure (OS) to organize the outbound data structure\nAn object structure is the common data layer that the integration framework components use for outbound and inbound application message processing. An object structure consists of one or more related business objects that define the content of an XML or JSON message (schema).\nOpen Object Structures application through Integration -\u0026gt; Object Structures menu. Click New Object Structure Button to create a new Object Structure to organize the asset data we plan to send out to other system. Fill out the required information for the OS.\nIn Source Objects section, click New Row button to add a new Maximo Business Object (MBO), in our case, we will add Asset MBO to this object structure.\nAdd Asset MBO\nClick New Row again in Source Objects section, to add a child MBO ServiceAddress to send address information along with Asset to other system. Make sure select Parent Object to be Asset which we added before, and pick up the relationship “SERVICEADDRESS” for Asset and ServiceAddress MBO. You can understand relationship is how to join Asset and ServiceAddress tables in SQL Query.\nSave the above OS settings. Click Select Action -\u0026gt; Exclude/Include Fields menu from Object Structures Application to open Exclude/Include Fields window. This setting is to configure what fields we would like to explore to the external system in Asset and ServiceAddress MBOs we added to the OSASSET object structure in previous step. Select ASSET MBO in the Source Object section, check all of the fields in Persistent Fields section except for AssetNum , Status and Description fields, which we plan to send only those fields to the external system.\nSelect ServiceAddress MBO and set AddressLine, City, County to be uncheck which we plan to explore asset service address information along with Asset information to other system .\nClick OK to save the Exclude/Include Fields setting to complete OS configuration.\nStep 2: Create Publish Channel to configure the outbound trigger event and filter condition\nA publish channel is the pipeline for sending data asynchronously from Maximo® Asset Management to an external system. Events that initiate publish channel processing are object events (insert, update, and delete), application-initiated calls,and data export. The content of a publish channel XML message is based on the associated object structure.\nOpen Publish Channels application through the menu Integration -\u0026gt; Publish Channels. Click New button to create a new Publish Channel. Input the publish channel name, description, and pick up the Object Structure OSASSET we created in previous step. After select OSASSET as object structure for the Publish Channel, the asset and serviceaddress MBOs in the object structure OSASSET is pulled to Object Structure Sub-Records section.\nAssume we only need to send Asset information when the asset is created and updated in Maximo, and only need to be sent in curtain Asset status, such as Active, Inactive and Decommissioned. For other Asset status, we will skip the outbound message. To achieve it, we need to turn on the publish channel event listening, and configure processing rule.\nSave the publish channel, click “Select Action-\u0026gt; Enable Event Listener” menu, you will found the Enable Listern checkbox is check for the publish channel PCASSET.\nClick New Row button under the Processing Rules for Sub-Record section, input rule’s name, description, and select SKIP for action, check Primary Object Insert and Update checkboxes, which mean only apply this process rule when insert or update asset record in Maximo.\nClick Add/Modify Conditions button, click New Row button under conditions section to add a new condition, and then click New Row in XML Field Tab to create a new XML Field Evaluation. Select Status for the field value, evaluation type as NOTEQUALS, Select VALUE option and ACTIVE as the value. This evaluation means if ASSET STATUS != ACTIVE, then Skip sending outbound message.\nWe need to configure the same evaluation for other 2 asset status: INACTIVE and DISCOMMISSIONED.\nClick New Row in XML Field Tab to create a new XML Field Evaluation for Asset status is not equal to INACTIVE, and click New Row in XML Field Tab again to create a new XML Field Evaluation for Asset status is not equal to DISCOMMISSIONED. The final result looks like following:\nClick OK button to save the setting.\nClick menu “Select Action -\u0026gt; Message Tracking” to open Publish Channel Message Tracking Setting, check Enable Message Tracking and Store Message checkboxes, which will allow us to view the outbound message for this PC in Message Tracking application.\nStep 3: Create an ENDPOINT for the url which to receive outbound message payload from Maximo.\nAn endpoint in IBM Maximo Asset Management is a location to which an outbound queue sends data. It specifies how outbound transactions are delivered and the handler that routes them. You can create an endpoint to identify a target location and the transport mechanism that the integration framework, or deployment manager uses to publish data, or to invoke a service.\nClick Integration-\u0026gt; End Points to open End Points application. Input end point and description, select HTTP as handler. Input url information (The url in the below screenshot is just for demo purpose).\nSave the end point setting by click Save button.\nStep 4: Create an External System to send Asset data to external application.\nAn external system in Maximo is any business application that sends data to Maximo or receives data from Maximo Asset Management. You can use and configure enterprise services and publish channels to exchange data with one or more external systems. The Maximo system sends messages to an external system or application. You create an external system to exchange with external applications.\nOpen the External Systems Application through Integration -\u0026gt; External Systems. Input system and description. Check Enable checkbox. Set Outbound Sequential Queue with the out of box outbound queue: jms/maximo/int/queues/sqout. Of couse you can configure your own outbound sequential queue, which is not in this instruction scope.\nClick Publish Channels Tab, Click New Row button to add the publish channel PCAsset we created on Step2 to this external system. Check Enable checkbox, and select End Point EPSERVICENOW which we created on step3.\nClick Save button to save the configuration.\nStep 5: Verify the configuration.\nSo far we complete all the required configurations. Now we can start to verify our settings. Open Asset application to create a new asset.\nClick Service Address tab to select a service address record for the asset\nChange Asset Status through change status tool, and select Active status. Save the change, and Asset current status is Active now. Per our configuration, the Publish Channel PCAsset we configured before should be triggered and send outbound message through the Outbound Sequential Queue. Since we enable the message tracking for the Publish Channel PCAsset on Step2, we can use message tracking application to view the outbound message.\nOpen Message Tracking application through Integration -\u0026gt; Message Tracking, we would find a message is triggered by PCAsset in the list.\nClick the pencil icon at the right end of the message, we can view the XML payload to be sent to external application.\n\u0026lt;?xml version=\u0026#34;1.0\u0026#34; encoding=\u0026#34;UTF-8\u0026#34;?\u0026gt; \u0026lt;PublishOSASSET xmlns=\u0026#34;http://www.ibm.com/maximo\u0026#34; xmlns:xsi=\u0026#34;http://www.w3.org/2001/XMLSchema-instance\u0026#34; creationDateTime=\u0026#34;2024-01-21T16:02:24-05:00\u0026#34; transLanguage=\u0026#34;EN\u0026#34; baseLanguage=\u0026#34;EN\u0026#34; messageID=\u0026#34;4761787.1705870944896610290\u0026#34; maximoVersion=\u0026#34;7 6 20220823-0909 V7613-344\u0026#34; event=\u0026#34;1\u0026#34;\u0026gt; \u0026lt;OSASSETSet\u0026gt; \u0026lt;ASSET action=\u0026#34;Replace\u0026#34;\u0026gt; \u0026lt;ASSETNUM\u0026gt;DEMOASSET\u0026lt;/ASSETNUM\u0026gt; \u0026lt;DESCRIPTION\u0026gt;Asset for demo\u0026lt;/DESCRIPTION\u0026gt; \u0026lt;SITEID\u0026gt;DEMOSITE\u0026lt;/SITEID\u0026gt; \u0026lt;STATUS changed=\u0026#34;1\u0026#34; maxvalue=\u0026#34;OPERATING\u0026#34;\u0026gt;ACTIVE\u0026lt;/STATUS\u0026gt; \u0026lt;SERVICEADDRESS\u0026gt; \u0026lt;ADDRESSCODE\u0026gt;DEMOADDR\u0026lt;/ADDRESSCODE\u0026gt; \u0026lt;CITY\u0026gt;ATLANTA\u0026lt;/CITY\u0026gt; \u0026lt;COUNTRY\u0026gt;US\u0026lt;/COUNTRY\u0026gt; \u0026lt;COUNTY /\u0026gt; \u0026lt;DESCRIPTION\u0026gt;Demo Address\u0026lt;/DESCRIPTION\u0026gt; \u0026lt;ORGID\u0026gt;DEMOORG\u0026lt;/ORGID\u0026gt; \u0026lt;POSTALCODE\u0026gt;30038\u0026lt;/POSTALCODE\u0026gt; \u0026lt;STREETADDRESS\u0026gt;1000 Demo Street\u0026lt;/STREETADDRESS\u0026gt; \u0026lt;/SERVICEADDRESS\u0026gt; \u0026lt;/ASSET\u0026gt; \u0026lt;/OSASSETSet\u0026gt; \u0026lt;/PublishOSASSET\u0026gt; (6) JSON format?\nThe default outbound message is XML format. Does Maximo Publish Channel support JSON format payload? The answer is yes, and it is pretty easy to implement but checking one configuration on Publish Channel. What you need to do is just need to open the Publish Channel record and check “Publish JSON” checkbox.\n4. Summary\nLet’s recap what we have learned in previous section: We created an object structure to organize the data structure, and then create a publish channel to define the conditions to trigger the outbound message to send object structure data to external application. Configure external system to setup sequential outbound queue and end point to send outbound message to target system.\n"},{"title":"Maximo Login Error “loginerror.jsp?group=system\u0026key=NoLogin”","permalink":"https://eamstream.com/posts/maximo-login-error-nologin/","summary":"Recently I tried to install Maximo Spatial package to a Maximo instance. After the Spatial package was installed, I tried to login Maximo to verify the result of the installation, got the following error:\nLogin Error You cannot login at this time. Contact the system administrator\nAnd the error page parameters are loginerror.jsp?group=system\u0026amp;key=NoLogin\nInvestigated on the log, cannot find any useful information since no exception happened for this case. After research through Mr. Google, looks like it was caused by useAppServerSecurity was updated issue. To verify my assumption, opened the file maximo.properties (default location in Windows C:\\IBM\\SMP\\maximo\\applications\\maximo\\properties), the value mxe.useAppServerSecurity=1, means it will use LDAP authentification. But in my Maximo instance I was configured it used Maximo application authentication. It might be updated during the Maximo Spatial package installation.\n","content":"Recently I tried to install Maximo Spatial package to a Maximo instance. After the Spatial package was installed, I tried to login Maximo to verify the result of the installation, got the following error:\nLogin Error You cannot login at this time. Contact the system administrator\nAnd the error page parameters are loginerror.jsp?group=system\u0026amp;key=NoLogin\nInvestigated on the log, cannot find any useful information since no exception happened for this case. After research through Mr. Google, looks like it was caused by useAppServerSecurity was updated issue. To verify my assumption, opened the file maximo.properties (default location in Windows C:\\IBM\\SMP\\maximo\\applications\\maximo\\properties), the value mxe.useAppServerSecurity=1, means it will use LDAP authentification. But in my Maximo instance I was configured it used Maximo application authentication. It might be updated during the Maximo Spatial package installation.\nAnd checking the *useAppServerSecurity *property value in the web.xml file under the following folders:\n*- IBM\\SMP\\maximo\\applications\\maximo\\maximouiweb\\webmodule\\WEB-INF\nIBM\\SMP\\maximo\\applications\\maximo\\mboweb\\webmodule\\WEB-INF IBM\\SMP\\maximo\\applications\\maximo\\meaweb\\webmodule\\WEB-INF IBM\\SMP\\maximo\\applications\\maximo\\maxrestweb\\webmodule\\WEB-INF* I found the *useAppServerSecurity *value was set to 1 as well.\nAfter performed the below steps, the issue was solved.\n**Step-1: Update maximo.properties File under the folder C:\\IBM\\SMP\\maximo\\applications\\maximo\\properties\nWe need to change mxe.useAppServerSecurity=1 to mxe.useAppServerSecurity=0 on this file. You cannot modify this file directly, since it was encrypt. Follow the below sub steps to modifiy this file.\n(1) Delete or rename the existing maximo.properties\n(2) Copy* the file c:\\ibm\\smp\\etc\\maximo.properties_orig* to folder c:\\ibm\\smp\\maximo\\applications\\maximo\\properties\\\n(3) Rename maximo.properties_orig to be maximo.properties.\n(4) Open this file,\nupdate mxe.useAppServerSecurity=1 to be mxe.useAppServerSecurity=0,\nAdd *mxe.db.password={Replace with your DB password} *line under below session:\nSave the changes.\n(5) From an Administrative command prompt, navigate to c:\\ibm\\smp\\maximo\\tools\\maximo directory\n(6) Run encryptproperties.bat This command encrypts the database user password in maximo.properties.\nStep-2: Update web.xml files\nOpen web.xml file under folder c:*IBM\\SMP\\maximo\\applications\\maximo\\maximouiweb\\webmodule\\WEB-INF*\nSearch useAppServerSecurity in web.xml, and update *useAppServerSecurity *value to be 0.\nSearch security-constraint and comment all of the* security-constraint *sections.\nSearch login-config and comment login-config section for ***BASIC ***auth-method\nUncomment login-config and comment login-config section for ***Form ***auth-method\nSave the above changes.\nAnd make the change to update *useAppServerSecurity *value to be 0 in *web.xml *file under the following folders\n*IBM\\SMP\\maximo\\applications\\maximo\\mboweb\\webmodule\\WEB-INF IBM\\SMP\\maximo\\applications\\maximo\\meaweb\\webmodule\\WEB-INF IBM\\SMP\\maximo\\applications\\maximo\\maxrestweb\\webmodule\\WEB-INF* Step-3: Rebuild and redeploy the Maximo application.\nYou can use Configuration Tool ConfigUI.exe under the folder C:\\IBM\\SMP_2\\ConfigTool, use the option “Update Database and Build and Deploy Application EAR files” to rebuild and redeploy the Maximo application.\nOr you can follow the step on this page to rebuild and redeploy it manually.\nhttps://www.ibm.com/support/pages/node/416993\nAfter Maximo application deploy complete, I can get my Maximo login page back. And after login, I can verify Maximo Spatial package is installed.\nIf you think this blog helping you, welcome to buy me a coffee through below Green Give a Tip button :)\n"},{"title":"Introduction of Maximo NextGen Rest APIs — Part 2 Update Maximo Data","permalink":"https://eamstream.com/posts/maximo-nextgen-rest-apis-part2-update-data/","summary":"In previous blog “Introduction of Maximo NextGen Rest APIs — Part 1 Query Maximo Data”, I introduced how to query Maximo data through NextGen Rest APIs. In this blog, we will have experiment on how to update Maxim data in through NextGen Rest APIs.\nWe will continue using the MXASSETSPEC OS we built in previous blog for the this experiment. If you don’t get chance going through my previous blog, please follow the section “**2. Object Structure (OS)” **to create MXASSETSPEC OS first.\n","content":"In previous blog “Introduction of Maximo NextGen Rest APIs — Part 1 Query Maximo Data”, I introduced how to query Maximo data through NextGen Rest APIs. In this blog, we will have experiment on how to update Maxim data in through NextGen Rest APIs.\nWe will continue using the MXASSETSPEC OS we built in previous blog for the this experiment. If you don’t get chance going through my previous blog, please follow the section “**2. Object Structure (OS)” **to create MXASSETSPEC OS first.\nOn this blog, we will cover the following scenarios through Maximo NextGen Rest APIs:\n(1) Create\n(2) Update\n(3) Delete\n(4) Action\nBefore getting start, we might need to understand the essential http methods in Restful: Get, Post, Put, Patch and Delete. Please go through this link if you are not familiar with it.\nhttps://www.techtarget.com/searchapparchitecture/tip/The-5-essential-HTTP-methods-in-RESTful-API-development\nBefore we start the experiment, we need to make some changes to OS MXASSETSPEC to allow update asset status through the inbound message. Open Object Structure application in Maximo, locate “MXASSETSPEC” OS and open it. Click “Inbound Setting Restrictions” at the left panel, and click on “ASSET” in the MBOs list. In the Inbound Setting Restrictions for MBO ASSET list, STATUS and STATUSDATE fields are default to be noneditable (Restricted checkbox is checked). Check Override checkbox for both of the fields, and then uncheck Restricted checkbox. Save the change by click OK button.\n1. Create\nCreating resources are almost always done using the collection URI— the same uri you would use to query the resources. For example, we can use the following URI to create an Asset along with Asset Specfication with the OS MXASSETSPEC we built in the part 1 blog.\nhttp://{your maximo server url}/maximo/oslc/os/mxassetspec?lean=1\nOpen the postman, create a new tab, add a new line for ““maxauth” and base64 encryption string of user name and password on headers tab (please refer to Authentication section in the part 1 blog)\nAt the new row of the Headers, add a new key “properties”, value as “*”. This setting is used to ask Maximo NextGen Rest API to return all of the information for the new Asset is created by the payload. Of course you can restrict the return information by identify the columns in the value of this properties header.\nPaste the below url in postman address textbox, change {your maximo server url*} *to your Maximo server name and port.\nhttp://{your maximo server url}/maximo/oslc/os/mxassetspec?lean=1\nClick Body tab, click on “raw” option, select json from the format dropdown list. Paste the blew payload to the body text box.\n{ \u0026#34;siteid\u0026#34;: \u0026#34;BEDFORD\u0026#34;, \u0026#34;assetnum\u0026#34;: \u0026#34;DEMOASSET\u0026#34;, \u0026#34;description\u0026#34;: \u0026#34;NextGen Rest API Demo asset\u0026#34;, \u0026#34;status\u0026#34;: \u0026#34;ACTIVE\u0026#34;, \u0026#34;classstructureid\u0026#34;:1015 } Select the method to be “POST”, Click “Send” button, you will see the response message along with 201 Created status.\nIn the response content, one of the information we need to pay attention is the new asset resource ID, which we need to use it for the rest of experiment on update and delete scenario. You can get the new asset resource ID from the following node in the response content:\n“href”: “http://MaximoSV.upgk5qkznuru1ao1jz40nyn2pb.bx.internal.cloudapp.net:80/maximo/oslc/os/mxassetspec/_REVNT0FTU0VUL0JFREZPUkQ-\u0026quot;\nThe string “*_REVNT0FTU0VUL0JFREZPUkQ-” *after OS in above node is the new asset resource ID.\nLet’s open Asset application in Maximo and locate asset “DEMOASSET” to validate the new asset.\nAnd click Specifications tab, we can see the classstructureid=1015 (Classification as TTAXLE) is assigned to the new asset DEMOASSET.\nFor the next experiment, we will demostrate how to update Asset Specifications through NextGen APIs.\n2. Update\nLet’s go back to Postman Headers tab, append a new header “x-method-override” with the value of “PATCH”. This instructs the server side to update the resource.\nClick Body tab, update the payload as following. In the updated payload, we will update the values Asset Specification “FUELTP” and “FUELCAP”.\n{ \u0026#34;siteid\u0026#34;: \u0026#34;BEDFORD\u0026#34;, \u0026#34;assetnum\u0026#34;: \u0026#34;DEMOASSET\u0026#34;, \u0026#34;description\u0026#34;: \u0026#34;NextGen Rest API Demo asset\u0026#34;, \u0026#34;status\u0026#34;: \u0026#34;ACTIVE\u0026#34;, \u0026#34;classstructureid\u0026#34;:1015, \u0026#34;assetspec\u0026#34;: [ { \u0026#34;assetattrid\u0026#34;: \u0026#34;FUELTP\u0026#34;, \u0026#34;alnvalue\u0026#34;: \u0026#34;#93\u0026#34;, \u0026#34;linearassetspecid\u0026#34;:0 }, { \u0026#34;assetattrid\u0026#34;: \u0026#34;FUELCAP\u0026#34;, \u0026#34;numvalue\u0026#34;: 15, \u0026#34;linearassetspecid\u0026#34;:0 } ] } Update url to append Asset Resource ID “*_REVNT0FTU0VUL0JFREZPUkQ-” *which we retrieved it from Create scenario response content after the mxassetspec OS:\nhttp://{your maximo server url}/maximo/oslc/os/mxassetspec/_REVNT0FTU0VUL0JFREZPUkQ-?lean=1\nClick Send button, the following response along with Status 200 will be returned.\nNow let’s go back to Asset application in Maximo and locate asset “DEMOASSET”, click Specifications tab, you will see the values Asset Specifications “FUELTP” and “FUELCAP” were updated.\nBut if you compare this screenshot with the screenshot when the Asset created, you might notice other 3 Specifications which was not in the payload were removed.\nTo avoid remove the child objects which are not in the payload to be removed, we can use additional header “patchtype” with the value of “MERGE”. Now let’s add this header to the postman headers:\nAnd in the payload, remove “FUELTP” specification node from the payload, update “FUELCAP” specification’s value to be 21.\n{ \u0026#34;siteid\u0026#34;: \u0026#34;BEDFORD\u0026#34;, \u0026#34;assetnum\u0026#34;: \u0026#34;DEMOASSET\u0026#34;, \u0026#34;description\u0026#34;: \u0026#34;NextGen Rest API Demo asset\u0026#34;, \u0026#34;status\u0026#34;: \u0026#34;ACTIVE\u0026#34;, \u0026#34;classstructureid\u0026#34;:1015, \u0026#34;assetspec\u0026#34;: [ { \u0026#34;assetattrid\u0026#34;: \u0026#34;FUELCAP\u0026#34;, \u0026#34;numvalue\u0026#34;: 15, \u0026#34;linearassetspecid\u0026#34;:0 } ] } Click send button to post the payload. If return status code is 200, open Asset application in Maximo and locate asset “DEMOASSET”, click Specifications tab, we will see “FUELTP” specification is still in the list even it is not included in the payload, and the “FUELCAP” specification’s value was updated to be 21.\nDelete To delete child object, for our example, to delete selectively asset specifications, we can use action in the payload. The following payload is to used to remove asset specification “FUELCAP”.\n{ \u0026#34;siteid\u0026#34;: \u0026#34;BEDFORD\u0026#34;, \u0026#34;assetnum\u0026#34;: \u0026#34;DEMOASSET\u0026#34;, \u0026#34;description\u0026#34;: \u0026#34;NextGen Rest API Demo asset\u0026#34;, \u0026#34;status\u0026#34;: \u0026#34;ACTIVE\u0026#34;, \u0026#34;classstructureid\u0026#34;:1015, \u0026#34;assetspec\u0026#34;: [ { \u0026#34;assetattrid\u0026#34;: \u0026#34;FUELCAP\u0026#34;, \u0026#34;numvalue\u0026#34;: 21, \u0026#34;linearassetspecid\u0026#34;:0, \u0026#34;_action\u0026#34;:\u0026#34;Delete\u0026#34; } ] } After post the above payload, the asset “DEMOASSET” specification “FUELCAP” was deleted.\nTo delete MBO, for example, if we want to delete “DEMOASSET”, we can use DELETE Method. Let’s change the payload method to be “DELETE” in postman, and update the payload as following:\n{ \u0026#34;siteid\u0026#34;: \u0026#34;BEDFORD\u0026#34;, \u0026#34;assetnum\u0026#34;: \u0026#34;DEMOASSET\u0026#34;, \u0026#34;description\u0026#34;: \u0026#34;NextGen Rest API Demo asset\u0026#34;, \u0026#34;status\u0026#34;: \u0026#34;ACTIVE\u0026#34;, \u0026#34;classstructureid\u0026#34;:1015 } You will receive 204 status since asset is deleted if the payload is processed successfully.\nAnd open Asset application in Maximo, try to locate Asset “DEMOASSET”, you will not be able to find it.\n4. Action\nSometime back in Maximo we had introduced the functionality of “Standard Services”. The name may sound confusing the but the intent was fairly simple. Maximo has a bunch of application services — aka Appservices which provide a bunch of service methods that act on MBOs to perform some business task. While most of these calls end up modifying the state of the system, some of these calls are merely for getting information. We have leveraged the JSR 181 annotations to expose these methods as “WebMethods” which can be accessed using SOAP and REST calls. For the purpose of this discussion, we are only going to focus on the RESTFul aspects of these methods. Simply put, we can add a WebMethod to any existing Maximo App service by extending the service class and adding a method like below. This example is from say extending the Workorder Service (psdi.app.workorder.WOService):\n@WebMethod public void approve(@WSMboKey(value=\u0026#34;WORKORDER\u0026#34;) MboRemote wo, String memo) { wo.changeStatus(\u0026#34;APPR\u0026#34;,MXServer.getMXServer().getDate(),memo); } Next you want to make sure that your method is now available for REST API calls. To do that you can select any workorder record and use the rest api to get the set of allowed actions on that resource. For example the query below will do the job.\nGET http://{your* maximo server url}/oslc/os/mxwo?oslc.where=wonum=”1001”\u0026amp;oslc,select=allowedactions*\nYou will see the list of allowed actions, which are nothing but the list of WebMethods for the service corresponding to the root object of the Object Structure along with the list of actions registered with the Object structure (using the application menu “Action Definition”). Theresulting json would provide the json schema for web method as well as the HTTP method and the name of the action, which can be used to invoke the action. A sample call below will demonstrate how these methods can be invoked.\nPOST \u0026lt;uri of the workorder 1001\u0026gt;?action=wsmethod:approve\nx-method-override: PATCH\n{ \u0026#34;memo\u0026#34;:\u0026#34;Testing\u0026#34; } Note we need to set the request header x-method-override as PATCH for invoking this action api, as this is operating on an existing Mbo (the first parameter to the method). As expected, this MBO reference is derived from the request URI (say — uri of the workorder 1001) and passed into the method as part of the api invocation. The json schema for the payload will reflect the parameter data types (in the method) and the parameter names.\nAs you can figure out, the query parameter action=wsmethod:approve is the fully qualified name of the action. The format is : where name is the java method name for the action type wsmethod.\nLet’s recap what we discuss on the above experiments. We learn how to use Maximo NextGen Rest API to create, update and delete data, and how to call OS action for the open web methods.\nIf you think this blog helping you, welcome to buy me a coffee through below Green Give a Tip button :)\n"},{"title":"Introduction of Maximo NextGen Rest APIs — Part 1 Query Maximo Data","permalink":"https://eamstream.com/posts/maximo-nextgen-rest-apis-part1-query-data/","summary":"I received couple private messages from audiences for my previous blogs relate Azure IoT integration with Maximo to ask for more detail on the instruction on Maximo NextGen Rest API. I would like to have these serial blogs to introduce how to query and update data through Maximo NextGen Rest API. In this part 1 blog, I will provide the information on Maximo NextGen Rest API, and how to construct Object Structure (OS) in Maximo and query OS data through Maximo NextGen Rest API. In Part 2 blog, I will leverage the same OS in part 1 blog to update Maximo data through NextGen Rest API. After you walk through the experiment of these serial blogs, you should have clear picture on how to query and update Maximo data through IBM recommended approach NextGen Rest API.\n","content":"I received couple private messages from audiences for my previous blogs relate Azure IoT integration with Maximo to ask for more detail on the instruction on Maximo NextGen Rest API. I would like to have these serial blogs to introduce how to query and update data through Maximo NextGen Rest API. In this part 1 blog, I will provide the information on Maximo NextGen Rest API, and how to construct Object Structure (OS) in Maximo and query OS data through Maximo NextGen Rest API. In Part 2 blog, I will leverage the same OS in part 1 blog to update Maximo data through NextGen Rest API. After you walk through the experiment of these serial blogs, you should have clear picture on how to query and update Maximo data through IBM recommended approach NextGen Rest API.\nIn one of my previous blogs “How to query data in Maximo through Restful API”, the rest APIs on this blog were released after Maximo Asset Management version 7.1. From IBM Maximoversion 7.6.0.2 onwards, IBM has provided a new REST APIs call NextGen Rest API which are a complete rewrite of the existing REST APIs. There are numerous benefits of using the NextGen APIs with a few highlighted here:\n● Significantly enhanced support for querying maximo data — subselects, related object queries, multi-attribute text search, custom queries (java/scripting).\n● Support for system level actions — bookmarking, notifications, e-sig, image association etc.\n● Tight integration to automation scripts — query, actions, custom apis.\n● Enhanced REST support for MIF Standard Services — support json data type for those service methods.\n● Metadata support using json schema.\n● Supports dynamic query views.\n● Support for group by queries.\n● Supports custom json elements appended to the Object structure JSON.\n● Integration with Maximo Cache framework.\n● Integration with Maximo formulas.\n● Integration with Maximo Federated MBOs/Resources\nThe following is high level overview of the architecture\nWe will have the experiment on this blog in the following sections about Authentication, Object Structure and Options on NextGen APIs query.\nAnd we will use Postman as the API tool in this experiment. You can download it through official site: https://www.postman.com/downloads/\nAuthentication Maximo NextGen Rest APIs support 2 authentication approaches: Maximo native authentication and LDAP based authentication.\n(1) Maximo native authentication\nThis is where Maximo owns the user repository along with the user credentials. Maximo is responsible for authenticating the incoming REST call. The REST api expects the HTTP request with a “maxauth” request header that has a base64 encoded userid:password. For example, if your maximo user account is maxadmin, password is maxadmin, the user credential format is *maxadmin:maxadmin. *And then use base64 encryption tool (for example https://www.base64encode.org/) to encode the string *maxadmin:maxadmin. *The encode string is bWF4YWRtaW46bWF4YWRtaW4=\nWe will use this authentication approach in our experiment on this blog.\n(2) LDAP based authentication\nThis is where Maximo does not own the authentication credentials. Its owned by the application server (for example WebSphere), and hence the authentication is validated by the application server.\n2. Object Structure (OS)\nAn object structure (OS) is the common data layer that the integration framework components use for sending and receiving data in Maximo. An object structure consists of one or more related Maximo business objects (MBO) that define the content of an integration message.\nAn object structure provides the message content for channels and services and enables application-based import and export. In addition, an object structure, on its own, can be called as a service, supporting the Create, Update, Delete, Sync, and Query operations.\nIn the next sections, assume you would like to explore Asset data along with Asset specifications information to the external system, we will build a new OS in Maximo to structure the asset and asset specification.\nLogin Maximo, open Object Structure Application, click “New Object Structure” Menu on the left panel or Create button on the tool bar. Fill out object structure name as MXASSETSPEC, and other required field.\nUnder Source Object section, click “New Row” Button, select ASSET from the Object lookup list.\nClick “New Row” button again, select ASSETSPEC from the Object lookup list. Pick Asset as Parent object, and select ASSETSPEC relationship from relationship lookup list.\nSave the above change. We built an OS with Asset and Asset Specifications structure, which we can leverage to query the asset with its specification information in next step.\n3. Query through NextGen Rest API\nOpen Postman, create a new tab. Click headers, at the blank row, input “maxauth” at the key column, please refer to Maximo native authentication section to get your base64 encode string of your Maximo login account and password, and then paste it to the value column.\nChange the {your maximo server url} to your maximo server name and port, and put it to the postman url.\nhttp://{your maximo server url}/maximo/oslc/os/mxassetspec?lean=1\nPlease Make sure the request action is GET, and click “Send” button after the url box. You should receive 200 return status code and the response payload in the response Body section. I will explain more detail on the url and response content in the next section.\nIn the response content, it returns MXASSETSPEC resource (which is based on the ASSET Mbo in Maximo) — each member pointing to an asset record with a “href” that contains the link to get the details for that MXASSETSPEC. Any collection resource in this REST api will follow this same basic structure.\nYou might ask how to return all of the members’ attributes along with values instead of need to loop each url in the members to get detail of each Asset along with Asset Spec information. The following are the most important aspects this NextGen Rest APIs framework to query the data.\n● Being able to select the list of attributes that we want the API to fetch. Being able to filter and sort Maximo business objects using a higher level query language which internally will map to the native sql for the corresponding relation db used by Maximo deployment.\n● Being able to fetch data from related objects leveraging existing Maximo relationships — without needing any additional configuration.\n● Being able to page data as needed.\nLet’s get into more detail on each of them with the example OS MXASSETSPEC we built before.\n(1) Select attributes, Filter and Sort\nIn NexGen Rest API, we can use the below query parameters to query the data.\noslc.select: this is used to specify the set of attributes to fetch from the Object structures as well as the related objects.\noslc.where: This is used to specify the where clause which follows the syntax detailed in the next section (Where clause syntax).\noslc.orderBy: this is used to specify the order by clause.\nNow assume we have the following requirements to query the Asset and Asset Specifications data through NextGen Rest API:\n● Return the fields of assetnum,location,description and status from Asset MBO, return the fields of assetattrid,description,alnvalue,numvalue abd tablevalue from Child AssetSpec MBO.\n● Only show the assets with status equals to OPERATING.\n● The return asset data need to be sorted by ASSETNUM field in ascending order.\nFor the first requirement, we can constructure oslc.select query paramenter as following. For the fields in child MBO AssetSpec, using the notation — {comma separated attribute names or * to get all properties}. So assetmeter{*} is going to fetch all properties for the assetmeter. This notation can easily be nested any levels deep. For example you can do obj1{prop1,prop2,obj2{prop21,prop22}} — where obj2 is defined as a child object of obj1.\noslc.select=assetnum,location,description,status,assetspec{assetattrid,description,alnvalue,numvalue,tablevalue}\nFor the second requirement, we can use query parament oslc.where to implement it. This internally maps to the Maximo Qbe framework. We can filter data based on all persistent attributes — at the main MBO (for the os) or any related MBO. Please refer to the below example based on the second requirement:\noslc.where=status=”OPERATING”\nApart from “=” operator in *oslc.where, *we can use below operators to achieve more complicate query.\nFor the 3rd requirement, to specify what attributes (fields) we would like to return from the API, we can identify it in oslc.oslc.orderBy query parameter. The format for this is\noslc.orderBy=-attr1,+attr2\nThe attributes prefixed with the minus sign (-) will be sorted in the descending order and the ones with the plus (+) sign will be sorted in the ascending order. All attributes listed here should be prefixed with a + or — sign. There is not default sort order here. Also related attributes are not supported here. Only persistent attributes from the main object are supported here. The following is the query parameter example to meet the requirement:\noslc.orderby=+assetnum\nNow let’s consolidate what we discussed above into the url. Change the {your maximo server url} to your maximo server name and port, and put it to the postman url.\nhttp://{your maximo server url}/maximo/oslc/os/mxassetspec?lean=1\u0026amp;oslc.select=assetnum,location,description,status,assetspec{assetattrid,description,alnvalue,numvalue,tablevalue}\u0026amp;oslc.orderby=+assetnum\u0026amp;oslc.where=status=\u0026ldquo;OPERATING\u0026rdquo;\nAfter click Send button after the url box in Postman, you should receive response similar to this:\n(2) Fetch data from related objects\nIn pervious olsc.select section, we discussed on how to identify return attributes for the child MBO in the OS with notation {comma separated attribute names or * to get all properties}. While this notation works for child objects, you often will need to get more data from a related objects (say Location for the Asset) which is not defined in the Object structure. The notation below will help us do this.\noslc.select=assetnum,status,description,location,location.description,location.status\nLet’s change url in postman as following to return Asset’s location information, such as location.description, location.status:\nhttp://{your maximo server url}/maximo/oslc/os/mxassetspec?lean=1\u0026amp;oslc.select=assetnum,location,description,status,location.description,location.status,assetspec{assetattrid,description,alnvalue,numvalue,tablevalue}\u0026amp;oslc.orderby=+assetnum\u0026amp;oslc.where=status=\u0026ldquo;OPERATING\u0026rdquo;\nWe will get location information at location section in the response content. Please keep in mind we don’t have Locations MBO in the MXASSETSPEC OS we built before.\n(3) Page data\nPaging of data is good fit to the scenario when your query return a big amount of the data. Query parameter oslc.pageSize is used to specify the max records to fetch for a page. This causes the responseInfo object to have the nextPage , previousPage , pagenum , totalCount (optional) and totalPages (optional) properties to describe page navigation information. If we don’t specify this pagesize query parameter in our query, the default page size setting will use the setting in OS. An attribute in the Object structure application to set the auto-paging threshold.\nNote:This field AUTOPAGINGTHRESHOLD was available on backend in Maximo 7.6.1.2.\nLet’s modify our previous url to be the following to add pagesize query paraneter:\nhttp://{your maximo server url}/maximo/oslc/os/mxassetspec?lean=1\u0026amp;oslc.select=assetnum,location,description,status,location.description,location.status,assetspec{assetattrid,description,alnvalue,numvalue,tablevalue}\u0026amp;oslc.orderby=+assetnum\u0026amp;oslc.where=status=\u0026ldquo;OPERATING\u0026rdquo;\u0026amp;oslc.pageSize=10\nWe will find page information at the end of response.\nNow let’s recap what we discuss on this blog. I introduced authentication of Maximo NextGen Rest APIs, how to build Object Structure (OS) in Maximo, and how to leverage query parameters to query OS data through NextGen Rest APIs.\nIn next blog, I will introduce how to update Maximo data through NextGen Rest APIs.\nIf you think this blog helping you, welcome to buy me a coffee through below Green Give a Tip button :)\n"},{"title":"Turn Your Lego EV3 Robot to Azure IoT Device — Part 1 Connect to IoT Hub through MQTT","permalink":"https://eamstream.com/posts/lego-ev3-azure-iot-part1-mqtt/","summary":"In my previous serial blogs “Azure IoT integration with Maximo”, introducing how to build a python IoT device simulator sending IoT device sensor data (for example, temperature data) to Azure IoT hub, through Azure Event Grid to pass telemetry to Azure Function. In Azure Function, call Maximo NexGen Rest API to post telemetry data to Maximo Asset meter reading.\nIn this serial blogs, I will introduce how to turn your Lego EV3 robot to be IoT device to replace the IoT simulator in previous blog, and how to connect EV3 through MQTT instead of Azure IoT Device SDK. In the part 2 blog, I will demonstrate how to create Work Order in Maximo through Maximo NextGen Rest API based on the color sensor data from Lego EV3 Robot.\n","content":"In my previous serial blogs “Azure IoT integration with Maximo”, introducing how to build a python IoT device simulator sending IoT device sensor data (for example, temperature data) to Azure IoT hub, through Azure Event Grid to pass telemetry to Azure Function. In Azure Function, call Maximo NexGen Rest API to post telemetry data to Maximo Asset meter reading.\nIn this serial blogs, I will introduce how to turn your Lego EV3 robot to be IoT device to replace the IoT simulator in previous blog, and how to connect EV3 through MQTT instead of Azure IoT Device SDK. In the part 2 blog, I will demonstrate how to create Work Order in Maximo through Maximo NextGen Rest API based on the color sensor data from Lego EV3 Robot.\nThe following is the high level architect diagram for this experiment.\nTo be able to perform this experiment, you need to have:\n(1) Lego EV3 robot\nLEGO Mindstorms EV3 is the third generation robotics kit in LEGO’s Mindstorms line. You can build a lot of interesting projects with Lego EV3 essential kit or extension set. You can program on its original built-in OS with Scratch language, or program it on external Debian OS launched through SD card with MicroPython / Pythhon. In this experiment, I will demonstrate how to use the second option to develop customized code to send color sensor data from Lego EV3 robot to Azure IoT hub through MQTT with MicroPython.\nLego Ev3 Robot\n(2) A microSD or microSDHC card (2GB or larger). microSDXC is not supported on the EV3. All cards larger than 32GB will not work with the EV3.\nThe reason we need miscroSD / miscroSDHC card is to run ev3dev stretch (Debian OS) in this SD card without messing up original OS of EV3, and also will allow us to run customized MicroPython code in the ev3dev stretch (Debian OS).\n(3) An Azure account. You can register an Azure account with $200 credit through this link:https://azure.microsoft.com/en-us/free/\n(4) Maximo Environment. If you would like to try the whole experiment to develop Azure function to call Maximo NextGen Rest API to create work order in Maximo when EV3 robot color sensor detect red color, you also need to have an Maximo environment to complete the whole experiment. But if you don’t have Maximo environment, or you are not interested in EAM section, follow the sections from 1 to 4 in this blog still give your the idea on how to connect your real IoT device to Azure IoT hub through MQTT with MicroPython.\nIn this blog, you will have hand-on experience to prepare your EV3 to be launched through ev3dev stretch Debian OS in SD card instead of EV3 built-in OS. And also learn how to connect your EV3 to internet. You will learn how to use MQTT client in MicroPython to connect to Azure IoT hub instead of using Azure IoT Device SDK. The purpose of this experiment is to develop customized MicroPython code to turn your EV3 to be Azure IoT device to send telemetry data (for example EV3 sensor data) to Azure IoT Hub, and in Azure IoT Function, we will update the Azure function which we built in my previous blog “Azure IoT integration with Maximo — Part 1“ to call Maximo NextGen Rest API to create work order when the EV3 color sensor data value is “Red”.\n1. Launch your EV3 through ev3dev stretch Debian OS in SD card\nYou can follow the steps on ev3dev.org to write the ev3dev stretch (Debian OS) image to the SD card.\nhttps://pybricks.com/ev3-micropython/startinstall.html\nAfter burn ev3dev stretch image to SD card, insert SD card to your EV3 SD card slot, turn on your EV3, it will launch ev3dev stretch (Debian OS) from SD card instead of the build-in EV3 OS.\n2. Connect your EV3 to internet\nOnce your EV3 complete start, follow the steps in below link to choose the internet connection option which is suitable for you to connect your EV3 to internet.\nhttps://www.ev3dev.org/docs/networking/\nFor Bluetooth option, you can connect your EV3 to internet with win10 which is the option I am using. You just need to turn on your mobile hotspot with bluetooth on your windows 10, and connect your EV3 Bluetoothto this Bluetooth mobile hotspot.\n3. Setup Development Environment\nWe will develop the MicroPython programs using Visual Studio Code. Follow the steps below to download, install, and configure this application:\n(1) Download Visual Studio Code.\n(2) Follow the on-screen instructions to install the application.\n(3) Launch Visual Studio Code.\n(4) Open the extensions tab.\n(5) Install the EV3 MicroPython extension as shown below\nInstalling the extension from the Visual Studio Code marketplace\n4. Start to code\nThe following section we will start to develop MicroPython code to connect EV3 to IoT hub through MQTT. You might ask why we don’t use Azure IoT Device SDK in this experiment like what we did in my previous blog “Azure IoT integration with Maximo — Part 1”. The major reason is Azure IoT Device SDK is required at least Python 3.6 version, but in current Ev3Dev Stretch Image (Debian Stretch OS), it is only support Python3.5.3.\nAnd let’s talking about a little bit about MicroPython. MicroPython is a software implementation of a programming language largely compatible with Python 3, written in C, that is optimized to run on a microcontroller. MicroPython consists of a Python compiler to bytecode and a runtime interpreter of that bytecode. If you are familiar with Python, MicroPython looks almost the same from development perspective.\nNow let’s getting start to have fun on coding.\n(1) Create a new project.\nTo create a new project, open Visual Studio Code, and then open the EV3 MicroPython tab and click create a new project, as shown in below figure. Enter a project name in the text field that appears and press Enter. When prompted, choose a location for this program and confirm by clicking choose folder.\nCreate a new project\nWhen you create a new project, it already includes a file called main.py. To see its contents and to modify it, open it from the file browser as shown in below figure. This is where you’ll write your programs.\nDefault main.py program.\nThe following is the project folders structure, as shown in below figure. A project folder is a directory on your computer that contains the main program (main.py) and other optional scripts or files. This project folder and all of its contents will be copied to the EV3 Brick, where the main program will be run.\nFolder structure\nOpen main.py in VS Code, and update the code to be the following:\n#!/usr/bin/env pybricks-micropython from pybricks.hubs import EV3Brick from pybricks.ev3devices import ( ColorSensor) from pybricks.parameters import Port, Color import time from util import create_mqtt_client, get_telemetry_topic, get_c2d_topic, parse_connection import json from json import dumps # This program requires LEGO EV3 MicroPython v2.0 or higher. # Click \u0026#34;Open user guide\u0026#34; on the EV3 extension tab for more information. # Write your program here. HOST_NAME = \u0026#34;HostName\u0026#34; SHARED_ACCESS_KEY_NAME = \u0026#34;SharedAccessKeyName\u0026#34; SHARED_ACCESS_KEY = \u0026#34;SharedAccessKey\u0026#34; SHARED_ACCESS_SIGNATURE = \u0026#34;SharedAccessSignature\u0026#34; DEVICE_ID = \u0026#34;DeviceId\u0026#34; ## Parse the connection string into constituent parts dict_keys = parse_connection(\u0026#34;\u0026lt;YOUR CONNECTION STRING\u0026gt;\u0026#34;) shared_access_key = dict_keys.get(SHARED_ACCESS_KEY) shared_access_key_name = dict_keys.get(SHARED_ACCESS_KEY_NAME) hostname = dict_keys.get(HOST_NAME) device_id = dict_keys.get(DEVICE_ID) ## Create you own shared access signature from the connection string that you have ## You can use Azure IOT HUB VS Code extenstion to generate SAS token, but it has time limit. ## Need to implement token auto generate service for real use case sas_token_str = \u0026#34;\u0026lt;YOUR SAS TOKEN STRING\u0026gt;\u0026#34; ## Create username following the below format \u0026#39;\u0026lt;HOSTNAME\u0026gt;/\u0026lt;DEVICE_ID\u0026gt;\u0026#39; username = hostname + \u0026#39;/\u0026#39; + device_id ## Create UMQTT ROBUST or UMQTT SIMPLE CLIENT mqtt_client = create_mqtt_client(client_id=device_id, hostname=hostname, username=username, password=sas_token_str, port=8883, keepalive=120, ssl=True) print(\u0026#34;connecting\u0026#34;) mqtt_client.reconnect() def callback_handler(topic, message_receive): print(\u0026#34;Received message\u0026#34;) print(message_receive) subscribe_topic = get_c2d_topic(device_id) mqtt_client.set_callback(callback_handler) mqtt_client.subscribe(topic=subscribe_topic) ## Send telemetry from EV3 color sensor ev3 = EV3Brick() topic = get_telemetry_topic(device_id) ## Send a C2D message and wait for it to arrive at the device color_sensor = ColorSensor(Port.S1) while True: curColor =color_sensor.color() colorStr=str(curColor).split(\u0026#34;.\u0026#34;)[1] print(\u0026#34;Current color:\u0026#34; +colorStr) color_msg = {\u0026#34;telemetry\u0026#34;: colorStr,\u0026#34;metername\u0026#34;:\u0026#34;COLOR_SEN2\u0026#34;} print(\u0026#34;Sending message: \u0026#34; + str(color_msg)) mqtt_client.publish(topic=topic, msg=str(color_msg)) time.sleep(10) In the above code, update the following line with your Azure IoT Device Connection String.\ndict_keys = parse_connection(\u0026#34;\u0026lt;YOUR CONNECTION STRING\u0026gt;\u0026#34;) To gain your Azure IoT Device Connection String, Login your Azure portal, open your IOT Hub (you can refer to my previous blog “Azure IoT integration with Maximo — Part 1” on how to create Azure IoT hub) , under Device management section, click “Devices” to open device list. Create a new device call “EV3”.\nClick the device “EV3” in the device list to open device detail information. At the end of Primary connection string field, click copy button to copy device connection string.\nNow let’s switch back to VS Code to update connection string in the IoT.\nAnd we also need to update the SAS Token String in the following code\nsas_token_str = \u0026#34;\u0026lt;YOUR SAS TOKEN STRING\u0026gt;\u0026#34; To retrieve your SAS token, go back to your Azure IoT hub, select “Shared access policies” at the left panel, and click device policy, and then click Copy button to copy primary Connection string.\nFollow the below step in VS Code to generate a temperary SAS token with the device share access policy connection string.\n(1) Install Azure IoT Hub Extension in VS Code.\n(2) Expand the AZURE IOT HUB DEVICES tab in the bottom left corner of Visual Studio Code.\n(3) Right-click your device and select Generate SAS Token for Device.\n(4) Set expiration time and press ‘Enter’.\n(5) The SAS token is created and copied to clipboard. The SAS token that’s generated has the following structure:\nHostName={iotHub-hostname};DeviceId=EV3;SharedAccessSignature=SharedAccessSignature sr={iotHub-hostname}%2Fdevices%2FMyDevice01%2Fapi-version%3D2016-11-14\u0026amp;sig=vSgHBMUG.....Ntg%3d\u0026amp;se=1456481802\nThe part of this token to use as the Password (SAS token) field to connect using MQTT is: SharedAccessSignature sr={iotHub-hostname}%2Fdevices%2FMyDevice01%2Fapi-version%3D2016-11-14\u0026amp;sig=vSgHBMUG.....Ntg%3d\u0026amp;se=1456481802\nPaste the above SAS token to replace the following code section of sas_token_str = \u0026#34;\u0026lt;YOUR SAS TOKEN STRING\u0026gt;\u0026#34; Notes: Above approach to generate a temporary SAS token is not the right way to create SAS token for actual production environment, because the SAS token will be expired for curtain period, it doesn’t make sense to update SAS token in production manually every coupe dates. To automatically retrieve SAS token, you might need to build a SAS token service in Azure, and call this SAS token service from your device to retrieve a new SAS token once it is expired. To implement SAS token service, you can refer to this instruction to build a customized SAS token service in Azure.\nIn VS Code, click “File -\u0026gt; New File…”, typed util.py to create a new python file and enter.\nIn util.py file, copy and paste the below code to it.\nfrom umqtt.robust import MQTTClient def create_mqtt_client(client_id, hostname, username, password, port=8883, keepalive=120, ssl=True): if not keepalive: keepalive = 120 if not ssl: ssl = True c = MQTTClient(client_id=client_id, server=hostname, port=8883, user=username, password=password, keepalive=120, ssl=True) c.DEBUG = True return c def get_telemetry_topic(device_id): return get_topic_base(device_id) + \u0026#34;/messages/events/$.ct=application%2Fjson%3Bcharset%3Dutf-8\u0026#34; def get_c2d_topic(device_id): return get_topic_base(device_id) + \u0026#34;/messages/devicebound/#\u0026#34; def get_topic_base(device_id, module_id=None): if module_id: base_str = \u0026#34;devices/\u0026#34; + device_id + \u0026#34;/modules/\u0026#34; + module_id else: base_str = \u0026#34;devices/\u0026#34; + device_id return base_str DELIMITER = \u0026#34;;\u0026#34; VALUE_SEPARATOR = \u0026#34;=\u0026#34; def parse_connection(connection_string): cs_args = connection_string.split(DELIMITER) dictionary = dict(arg.split(VALUE_SEPARATOR, 1) for arg in cs_args) return dictionary After save the above code to util.py, you can click the download button at EV3Dev Device Browser extension to download the code to your EV3 robot device.\nExpand the folder to locate main.py file, right click on it, select “Run” to start running the code from EV3.\nOn the VS Code output window will be able to see the log as:\nIf you open your IoT Hub, on overview page, you will be able to see the messages were received by the IoT hub.\nIn this blog, we learned how to turn your EV3 robot to be Azure IoT device to connect to Azure IoT hub, and sent color sensor data to Azure IoT hub through MQTT.\nIn next blog, we will learn how to parse the telemetry color data from EV3 Robot device, and create work order in Maximo through NextGen Rest API.\nIf you think this blog helping you, welcome to buy me a coffee through below Green Give a Tip button :)\n"},{"title":"Turn Your Lego EV3 Robot to Azure IoT Device — Part 2 create work order in Maximo","permalink":"https://eamstream.com/posts/lego-ev3-azure-iot-part2-maximo-workorder/","summary":"In previous part 1 blog, we demonstrated how to connect Lego EV3 to Azure IoT hub through MQTT, and send EV3 color sensor data to IoT hub. In this blog, we will experiment to update Azure Function which we built on blog “Azure IoT integration with Maximo — Part 2” to create work order in Maximo through Maximo NextGen Rest API based on the color sensor data sent from Lego EV3.\n","content":"In previous part 1 blog, we demonstrated how to connect Lego EV3 to Azure IoT hub through MQTT, and send EV3 color sensor data to IoT hub. In this blog, we will experiment to update Azure Function which we built on blog “Azure IoT integration with Maximo — Part 2” to create work order in Maximo through Maximo NextGen Rest API based on the color sensor data sent from Lego EV3.\nThe following is the high level of the steps we will following in this experiment:\n(1) Configure required data in Maximo, such as Asset, Object Structure (OS).\n(2) Update Azure Function to parse color sensor telemetry data sent by Lego EV3, and call Maximo NextGen Rest API to create work order if the Lego EV3 robot detected color is red.\n1. Prepare data and configuration in Maximo Open Asset application in Maximo, click “New Asset” Link or button. Input EV3 as ASSETNUM, and then Save the change.\nChange Asset Status to be Active\nOpen Object Structure application in Maximo, click “New Asset” Link or button to create a new Object Structure. Object Structure (OS) is composed by Maximo Business Objects (MBO). OS is the foundation in Maximo Integration Framework, you can understand MBO as table in database, and OS as view in database which combines multiple tables (MBOs) to form the data you would like to explore to external system for integration. We will create an OS called MXEV3WO for this experiment.\nIn Source Objects section, we will use two MBOs for this MXEV3WO OS: Workorder and WOActivity. In the blew steps, we will configure this OS to allow us create a work order and a task through Maximo NextGen Rest API.\nClick New Row button under Source Objects section, select WORKORDER MBO from the popup list.\nClick New Row button again, select WOActivity MBO from the list, select WORKORDER at Parent Object field, and pick up NEWACTIVITY in the Relationship list. It will join WOActivity and Workorder MBOs through NEWACTIVITY relationship. If you are familiar with relationship database sql query, it is similar to use left join the Workorder and WOActivity tables in the sql query.\nThe purpose we build this OS is to use it as the structure to create workorder, and a new task under this work through Maximo NextGen Rest API.\n2. Update Azure function Save above changes in Maximo, open Azure portal to open Azure Function. We will update Azure Function which we built in my previous serial blogs “Azure IoT integration with Maximo — Part 1” and “Part 2”. If you don’t get chance to read it yet, please follow the instruction on that serial blogs to create an Azure Function “EventGridDataEventParser” first. I will not repeat the same steps in this blog.\nOpen “EventGridDataEventParser” Azure function, click on the “Code + Test”\nModify the “EventGridDataEventParser” Azure function to be following code. The comments in the code should explain the logic of the code.\n#r \u0026#34;Azure.Messaging.EventGrid\u0026#34; #r \u0026#34;System.Memory.Data\u0026#34; #r \u0026#34;Newtonsoft.Json\u0026#34; using Azure.Messaging.EventGrid; using Newtonsoft.Json.Linq; using Newtonsoft.Json; using System.Net.Http; using System.Net.Http.Headers; using System; using System.Text; public static async void Run(EventGridEvent eventGridEvent, ILogger log) { var eventData=eventGridEvent.Data.ToString(); log.LogInformation(\u0026#34;Functionlog: \u0026#34;+eventData); JObject json = JObject.Parse(eventData); JToken token = json.SelectToken(\u0026#34;systemProperties.iothub-connection-device-id\u0026#34;); var deviceID=token?.ToString(); log.LogInformation(\u0026#34;Device ID: \u0026#34;+deviceID); //token = json.SelectToken(\u0026#34;systemProperties.dt-subject\u0026#34;); token = json.SelectToken(\u0026#34;body.metername\u0026#34;); var meterID=token?.ToString(); log.LogInformation(\u0026#34;Meter ID: \u0026#34;+meterID); //token = json.SelectToken(\u0026#34;body.temperature\u0026#34;); token = json.SelectToken(\u0026#34;body.telemetry\u0026#34;); var meterReading=token?.ToString(); log.LogInformation(\u0026#34;Meter Reading: \u0026#34;+meterReading); token = json.SelectToken(\u0026#34;systemProperties.iothub-enqueuedtime\u0026#34;); var eventTime=token?.ToString(Formatting.None); log.LogInformation(\u0026#34;Event Time: \u0026#34;+eventTime); if(String.Equals(meterReading.ToUpper(),\u0026#34;RED\u0026#34;)) { //Warning: EV3 color sensor detects red color, need to raise work order in Maximo to fix the device var baseUrl = \u0026#34;http://{replace with your maximo server name}/maximo/oslc/os/mxev3wo?lean=1\u0026#34;; HttpClient client = new HttpClient(); //update the following maxauth header value to your maximo account value. client.DefaultRequestHeaders.Add(\u0026#34;maxauth\u0026#34;,\u0026#34;{User credentials encoded to base64 format}\u0026#34;); try { //The following code is to post work order payload against Object Structure (OS) MXEV3WO to Maximo through nextgen Rest API, //to create a new work order and a task under the work order //Structure Work Order Json information dynamic jObjectWO=new JObject(); eventTime=eventTime.Substring(1,eventTime.Length-2); //Default wonum format as \u0026#34;WO_EV3_{eventTime}\u0026#34; jObjectWO.wonum=\u0026#34;WO_EV3_\u0026#34;+eventTime; jObjectWO.description=\u0026#34;workorder for EV3 at \u0026#34;+eventTime; //Default Site ID to be BEDFORD jObjectWO.siteid=\u0026#34;BEDFORD\u0026#34;; //Default work order status WAPPR jObjectWO.status=\u0026#34;WAPPR\u0026#34;; jObjectWO.assetnum=deviceID; //Structure WOActivity information inside the work order dynamic jArrayWOActivities=new JArray(); dynamic jObjectWOActivity=new JObject(); jObjectWOActivity.taskid=5; jObjectWOActivity.wosequence=5; jObjectWOActivity.description=\u0026#34;Fixed device for detecting red color\u0026#34;; jArrayWOActivities.Add(jObjectWOActivity); //Assign WOActivity to work order jObjectWO.woactivity=jArrayWOActivities; String postJson=JsonConvert.SerializeObject(jObjectWO); log.LogInformation($\u0026#34;Post Json Content: {postJson}\u0026#34;); using (var postContent = new StringContent(postJson, System.Text.Encoding.UTF8, \u0026#34;application/json\u0026#34;)) { //add header for Maximo nextgen rest API update scenario HttpResponseMessage resultPost =await client.PostAsync(baseUrl, postContent); resultPost.EnsureSuccessStatusCode(); var postResultContent = await resultPost.Content.ReadAsStringAsync(); log.LogInformation($\u0026#34;Post request result: {postResultContent}\u0026#34;); } } catch (HttpRequestException e) { log.LogError(\u0026#34;\\nHttp Exception Caught!\u0026#34;); log.LogError(\u0026#34;Message :{0} \u0026#34;, e.ToString()); } catch (Exception e) { log.LogError(\u0026#34;\\nUnexpected Exception Caught!\u0026#34;); log.LogError(\u0026#34;Message :{0} \u0026#34;, e.ToString()); } } } There are 2 places you need to update on above code:\n(1) var baseUrl = “http://{replace with your maximo server name}/maximo/oslc/os/mxev3wo”;\nUpdate {replace with your maximo server name} to be your Maximo server name.\n(2) client.DefaultRequestHeaders.Add(“maxauth”,”{User credentials encoded to base64 format}”);\nUpdate* *{User credentials encoded to base64 format} to be your maximo user account and password in base64 format encode. For example, if your maximo user account is maxadmin, password is maxadmin, the user credential format is *maxadmin:maxadmin. *And then use base64 encryption tool (for example https://www.base64encode.org/) to encode the string *maxadmin:maxadmin. *The encode string is bWF4YWRtaW46bWF4YWRtaW4=\nSave the change of run.csx file. Click “Monitor” in the left panel, and then click Logs tab to open the log window.\nTurn your Lego EV3 on and connect to network, and open VS Code to open folder we built for EV3 in previous blog “Turn Your Lego EV3 Robot to Azure IoT Device — Part 1”. Connect EV3 to VS code through click “Click here to connect to a device” under EV3DEV Device Browser.\nSelect your EV3 Device from the list, once it is connected, expand the folder node to locate main.py file\nRight click on main.py file, select “Run” to execute the main.py in Ev3 device. On the VS Code output window will be able to see the log as:\nPut some red color object under EV3 Color sensor\nYou should be able to see some red color telemetry data to be sent to IoT hub. Let’s go back to Azure Function Monitor Log tab, we should be able see the log\nAnd if we open Work Order Tracking application in Maximo, filter wonum with “WO_EV3%”, we will be able to find a work order was created through Azure Function.\nClick the work order link to open the work order, and then click Plan tab, you will see there is a Task being created under this work order.\nLet’s recap what we learn in this experiment. We setup Object Structure (OS) to accept payload to create work order and task inside it in Maximo, in Azure Function create work order through Maximo NextGen Rest API when we receive telemetry color data is red from Lego EV3. Of course you can extend this experiment to your real business case to build Azure IoT solution integration with Maximo or your EAM solution.\nIf you think this blog helping you, welcome to buy me a coffee through below Green Give a Tip button :)\n"},{"title":"Azure IoT integration with Maximo — Part 1","permalink":"https://eamstream.com/posts/azure-iot-integration-maximo-part1/","summary":"IoT (Internet of Things) is getting more and more popular in the world, especially when 5G technology was rolled out to our real life and industries, more and more IoT use cases were adopted in different industries. In the following content, I would like to introduce a POC to leverage IoT technology in EAM (Enterprise Asset Management) area.\nIBM Maximo is the major player in EAM market, and Azure IoT is the most popular IoT platform, In this POC, I would introduce how to integrate Azure IoT platform with Maximo through Maximo NextGen Rest API. The purpose of this POC is to demonstrate sending IoT device sensor data (for example, temperature data) to Azure IoT hub, through Azure Event Grid to pass telemetry to Azure Function. In Azure Function, call Maximo NexGen Rest API to post telemetry data to Maximo Asset meter reading. The following is the high level of the architecture diagram:\n","content":"IoT (Internet of Things) is getting more and more popular in the world, especially when 5G technology was rolled out to our real life and industries, more and more IoT use cases were adopted in different industries. In the following content, I would like to introduce a POC to leverage IoT technology in EAM (Enterprise Asset Management) area.\nIBM Maximo is the major player in EAM market, and Azure IoT is the most popular IoT platform, In this POC, I would introduce how to integrate Azure IoT platform with Maximo through Maximo NextGen Rest API. The purpose of this POC is to demonstrate sending IoT device sensor data (for example, temperature data) to Azure IoT hub, through Azure Event Grid to pass telemetry to Azure Function. In Azure Function, call Maximo NexGen Rest API to post telemetry data to Maximo Asset meter reading. The following is the high level of the architecture diagram:\nDiagram 1 — High level architecture diagram\nIf you would like to follow this instruction to have hand-on experience on it, the following is the prerequisites:\n(1) An Azure account. You can register an Azure account with $200 credit through this link:https://azure.microsoft.com/en-us/free/\n(2) Maximo environment. (Only require in Part 2)\nIf you are only interested in how to send IoT device sensor data (for example, temperature data) to Azure IoT hub, through Azure Event Grid to pass telemetry to Azure Function, this part 1 will provide step by step instruction along with all the source code.\nIn this Part 1 content, we will focus on creating an IoT device simulator to connect to Azure IoT hub and send temperature data to IoT hub. Once Azure IoT hub receives telemetry data from IoT device, will trigger Azure Event Grid to send the event to Azure Function. In Azure Function, we will parse the event data to get telemetry data (temperature data from simulate IoT device).\nIn Part 2 blog, we will update Azure function to call Maximo NextGen Rest API to post temperature data to Maximo Asset meter reading table.\nThe following are the high level steps we will follow to build IoT device simulator connect and send telemetry data to Azure IoT Hub, and trigger event in Azure Event Grid to send to Azure Function, in Azure Function, we will parse the event data to get the telemetry data is sent from IoT device simulator.\nSetup Azure IoT Hub Create IoT Device in IoT hub, and build IoT device simulator code in local environment to simulate IoT device sending temperature data to Azure IoT Hub. Create Azure Function to receive event from IoT Hub. Setup Azure Event Grid to connect to Azure IoT Hub to receive telemetry events, and pass event message to Azure Function. Develop code in Azure Function to parse event message to get telemetry related data. Let’s getting start to setup Azure hub in Azure portal (Assume you already created / had Azure account).\nSetup Azure IoT Hub (1) Login Azure Portal through https://portal.azure.com/\n(2) Click “Create a resource” link under Azure services section:\n(3) Type IOT Hub in the search box and click “Create” link under IOT Hub Azure Service.\n(4) Fill in required fields in the IoT hub creation page, and click “Review + create” button.\n(5) Click “Create” once you review all of information:\n(6) After Azure IoT hub creation complete, you should be able find it from your resources list in your Azure portal\n2. Create IoT Device in IoT hub, and build IoT device simulator code in local environment to simulate IoT device sending temperature data to Azure IoT Hub.\nThe following steps will create a new device in the Azure IoT Hub we created in previous steps, and develop device simulator python code to simulate IoT device from local machine to connect and send data to IoT Hub through IoT device connection string.\n(1) Click at the IoT hub “JACKYIOTHUBDEMO” we just created, click the “Devices” link under Device management at the left panel, and then click + Add Device link to add a new IoT device.\n(2) On the create device screen, we will create a device call TempSimulator, we will select Symmetric Key as the Authentication Type. Don’t recommend this Authentication Type for production environment. Would suggest to use X.509 certificate for production. You can refer to this offical link for more detail on it: https://learn.microsoft.com/en-us/azure/iot-dps/concepts-device-oem-security-practices. Click Save button to add this device to IoT hub.\nOnce the new device creation complete, click refresh button, you should be able to find it in the device list:\n(3) In the following instruction, we will develop a simulator of IoT device in Python in the local machine (Windows 10) to connect and send out random temperature data to Azure IoT Hub. We will simplify our development through leveraging Azure IoT Device SDK. You can get more detail information through Microsoft offical site “https://learn.microsoft.com/en-us/azure/iot-develop/about-iot-sdks” on Azure IoT Device SDK. And we will use Visual Studio Code as code editor.\nTo start the following section, you need to install the following prerequisites in your local machine, assume it is windows 10.\n(I)Python 3.7+. To ensure that your Python version is up to date, run python --version\n(II) Install Visual Source Code (VS Code). You can download the latest version of VS Code from https://code.visualstudio.com/download\nAnd install VS Code Python extension. Refer to https://code.visualstudio.com/docs/python/python-tutorial\n(III) Install IoT Device SDK. Open command window with Administrator permission, execute the below command:\npip install azure-iot-device After above prerequisites installations were done, Open VS Code, and click “File” -\u0026gt; “Open Folder”, Locate an empty folder where you would like to hold your IoT Device simulator Python code.\nClick “File”-\u0026gt; “New File” in VS Code after open the empty folder, Click Python File Python option.\nIt will open a new empty Python file, copy the below code and paste it to the new Python file.\n# ------------------------------------------------------------------------- # Copyright (c) Jacky Qiu. All rights reserved. # Licensed under the MIT License. # -------------------------------------------------------------------------- import asyncio import time import uuid import random import json from azure.iot.device.aio import IoTHubDeviceClient from azure.iot.device import Message async def send_recurring_telemetry(device_client): # Connect the client. await device_client.connect() # Send recurring telemetry i = 0 while True: i += 1 curr_temp= random.randrange(10, 50) temperature_msg = {\u0026#34;temperature\u0026#34;: curr_temp,\u0026#34;metername\u0026#34;:\u0026#34;TEMP-C\u0026#34;} msg = Message(json.dumps(temperature_msg)) msg.message_id = uuid.uuid4() msg.correlation_id = \u0026#34;correlation-1234\u0026#34; #msg.custom_properties[\u0026#34;tornado-warning\u0026#34;] = \u0026#34;yes\u0026#34; msg.content_encoding = \u0026#34;utf-8\u0026#34; msg.content_type = \u0026#34;application/json\u0026#34; print(\u0026#34;sending message #\u0026#34; + str(i)) await device_client.send_message(msg) time.sleep(10) def main(): # The connection string for a device, you can get it from your IOT Hub -\u0026gt; Devices conn_str = \u0026#34;{Your Device Connection String}\u0026#34; # The client object is used to interact with your Azure IoT hub. device_client = IoTHubDeviceClient.create_from_connection_string(conn_str) print(\u0026#34;IoTHub Device Client Recurring Telemetry Sample\u0026#34;) print(\u0026#34;Press Ctrl+C to exit\u0026#34;) loop = asyncio.get_event_loop() try: loop.run_until_complete(send_recurring_telemetry(device_client)) except KeyboardInterrupt: print(\u0026#34;User initiated exit\u0026#34;) except Exception: print(\u0026#34;Unexpected exception!\u0026#34;) raise finally: loop.run_until_complete(device_client.shutdown()) loop.close() if __name__ == \u0026#34;__main__\u0026#34;: main() The above code is to simulate an IoT device to connect and send temperature data to Azure IoT Hub for every 10 seconds. You can adjust intervals by change the number in this line:\ntime.sleep(10) And in the above code, you need to update the device connecting with your IoT device connection string in Azure IoT Hub. Login your Azure portal, open IOT Hub “JACKYIOTHUBDEMO” created in Step 1 , under Device management section, click “Devices” to open device list.\nClick the device “TempSimulator” in the device list to open device detail information. At the end of Primary connection string field, click copy button to copy device connection string.\nNow let’s switch back to VS Code to update connection string in the IoT device simulator Python code. Replace the content at *{Your Device Connection String} *with the connection string copied from IoT Device Primary connection string.\nconn_str = “{Your Device Connection String}”\nSave Python code in VS code, for example IoTDevice.py. Select VS Code menu “Run”-\u0026gt; “Start Debugging”, or just press F5, will start to debug the IoTDevice.py code. And select Python File option.\nAfter the code execute, in the VS Code terminal window, you should see the random temperature data is created and sent to Azure IoT hub through the IoT device simulator python code.\nNow if you go back to your Azure portal, locate Azure IoT hub, at the IoT hub overview page, you should see some message has been sent from your local IoT device simulator code to Azure IoT hub:\nNow we completed building IoT device simulator, connected it to Azure IoT hub, and sent simulate temperature telemetry data to IoT hub. Next step we will create Azure Event Grid to receive the event from Azure IoT Hub when it receive telemetry data from IoT Device, and pass the event data to Azure Function which will parse event data to retrieve the information such as device id, temperature data, etc. Since creating Event Grid instance is required to define an end point which is Azure Function, we will create an Azure function first.\nCreate Azure Function to receive event from IoT Hub. Click “Create a resource” link in your Azure portal, type “function app” in the search box, click Create button under Function App in the search result list.\nOn Create Function App page, input the information and click “Review + Create” button. And then click “Create” button to create a new Azure Function. (Note: Consumption (serverless) option in Plan Type is good enough for testing purpose. You should select other advance plan for your production environment)\nAfter Azure Function App deployment complete, you can find it in the resource list through the resource group you assigned it to.\nClick Azure Function App we just created, select Functions in the left panel, and then click “+ Create” to create a new function.\nOn Create function page, we will select development environment as “Development in portal”. In actual project, usually we will use VS Code or other code editor for Azure function development. Scroll down the template list to select Azure Event Grid trigger, fill in New Function name, and then click Create button to create a empty function.\nAfter new function creation complete, you can click “Code + Test” at left panel to open online editor to modify Azure function code. We will keep the default code at run.csx, and update this function later.\nNow let switch back to Azure IoT Hub “JACKYIOTHUBDEMO”.\n4. Setup Azure Event Grid to connect to Azure IoT Hub to receive telemetry events, and pass event message to Azure Function.\nIn Azure IoT Hub, click Events in the left panel, and then click “+ Event Subscription” to create a new Azure Event Grid Subscription.\nIn the create event subscription page, fill in the required fields.\nIn the Event Types list, since we are only interested in Device Telemetry event data, will only select Device Telemetry option.\nAt Endpoint Detail section, select Azure Function as Endpoint Type\nAt the right popup page, select the Azure function we created in previous step, and click Confirm Selection Button.\nClick Create button to create a new Event Grid Subscription to be event channel between IoT hub and Azure Function.\nAfter Event Grid Subscription creation and deployment complete, you will see its status:\nNow let’s ran the local IoT device Simulator code again to send temperature telemetry data to Azure IoT hub, which will trigger Telemetry Event data pass through Azure Event Grid to Azure function. Let’s open Azure Function “EventGridDataEventParser” we built on previous step, click “Monitor” at the left panel, and click Logs tab. In the log window, we can see the IoT device simulator data events had been passed through Azure Event Grid.\nSince we only have one line code in Azure Function “EventGridDataEventParser” Run method in run.csx file.\nlog.LogInformation(eventGridEvent.EventType.ToString()); We will update the Azure function code to parse event data to retrieve temperature data, device ID, etc.\nClick “Code + Test” in Azure Function “EventGridDataEventParser”, select run.csx file from file list.\nCopy the below code and paste it to replace the code for run.csx. And click Save button to save the change.\nusing Azure.Messaging.EventGrid; using Newtonsoft.Json.Linq; using Newtonsoft.Json; using System.Net.Http; using System.Net.Http.Headers; using System; using System.Text; public static async void Run(EventGridEvent eventGridEvent, ILogger log) { var eventData=eventGridEvent.Data.ToString(); log.LogInformation(\u0026#34;Functionlog: \u0026#34;+eventData); JObject json = JObject.Parse(eventData); JToken token = json.SelectToken(\u0026#34;systemProperties.iothub-connection-device-id\u0026#34;); var deviceID=token?.ToString(); log.LogInformation(\u0026#34;Device ID: \u0026#34;+deviceID); //token = json.SelectToken(\u0026#34;systemProperties.dt-subject\u0026#34;); token = json.SelectToken(\u0026#34;body.metername\u0026#34;); var meterID=token?.ToString(); log.LogInformation(\u0026#34;Meter ID: \u0026#34;+meterID); token = json.SelectToken(\u0026#34;body.temperature\u0026#34;); var meterReading=token?.ToString(); log.LogInformation(\u0026#34;Meter Reading: \u0026#34;+meterReading); token = json.SelectToken(\u0026#34;systemProperties.iothub-enqueuedtime\u0026#34;); var eventTime=token?.ToString(Formatting.None); log.LogInformation(\u0026#34;Event Time: \u0026#34;+eventTime); } The above code is to parse the information in the event data section which is Jason format. Click on the Monitor at the left panel, and select Logs tab again. Now you will see the detail information such as Device ID, Meter ID, Temperature data, event time information have been parsed and logged.\nLet’s recap what we have done in above steps. We built Azure IoT Hub in Azure cloud, developed an IoT device simulator running in local machine to connect and send random temperature data to Azure IoT Hub , created an Azure function, and configure Azure event grid to pass through Azure IoT Hub telemetry data (temperature) to Azure Function. In Azure Function, we parsed event data to retrieve device and temperature information from event data and log them. We archived the below components inside the red rectangle in the architecture diagram.\nIn next part 2 blog, we will demonstrate how to integrate Azure IoT to Maximo through Maximo Integration Framework (MIF). We will setup asset and meter data in Maximo, continue update Azure function code to post temperature data to Maximo meter reading through Maximo NextGen Rest API.\nYou can get full source code from GitHub:\nIf you think this blog helping you, welcome to buy me a coffee through below Give a Tip button after this blog :)\n"},{"title":"Azure IoT integration with Maximo — Part 2","permalink":"https://eamstream.com/posts/azure-iot-integration-maximo-part2/","summary":"In the previous part 1 blog, we built Azure IoT Hub in Azure cloud, developed an IoT device simulator running in local machine to connect and send ramdom temperature data to Azure IoT Hub , created an Azure function, and configure Azure event grid to pass through Azure IoT Hub telemetry data (temperature) to Azure Function. In Azure Function, we parsed event data to retrieve device and temperature information from event data and log them. In this part 2 blog, we will continue to configure and build the rest of the components inside the red rectangle in the following architecture diagram.\n","content":"In the previous part 1 blog, we built Azure IoT Hub in Azure cloud, developed an IoT device simulator running in local machine to connect and send ramdom temperature data to Azure IoT Hub , created an Azure function, and configure Azure event grid to pass through Azure IoT Hub telemetry data (temperature) to Azure Function. In Azure Function, we parsed event data to retrieve device and temperature information from event data and log them. In this part 2 blog, we will continue to configure and build the rest of the components inside the red rectangle in the following architecture diagram.\nThe following are the high level of steps to configure asset and meter data in Maximo, update Azure function to call Maximo NextGen Restful API to post temperature data which is generated from IoT Device Simulator to Maximo.\nSetup Asset and Meter in Maximo, and review MIF (Maximo Integration Framework), Maximo NextGen Restful API and Object Structure (OS). Update Azure Function to post temperature data which receive from Azure Event Grid to Maximo Asset Reading through Object Structure MXASSET Restful API. The following steps assume that you have Maximo environment with a maxadmin user group permission which can access to OS MXASSET to query and update asset and meter reading data in Maximo.\nSetup Asset and Meter in Maximo, and review MIF (Maximo Integration Framework), Maximo NextGen Restful API and Object Structure (OS). Login maximo, and open Asset application.\nClick New Asset or “+” icon at the top tool bar, to open new Asset page. For assetnum field, we will use the same value of DeviceID we created in Azure IoT Device in Part 1, which is TempSimulator. Fill in the rest of required fields on the new Asset page, click “Save” button.\nClick Meters tab, and then click “New Row” button at the end of the page.\nSelect “TEMP-C” meter to the meter field to assign TEMP-C meter to the Asset TempSimulator we created in previous step. And save the change.\nChange Asset TempSimulator status to be Active by click “Change Status” under Common Actions section in the left panel, on the popup page, select Active as new status, and then click “OK” button to save the status change.\nNow we created a new Asset with assetnum=TempSimulator (Same as device ID in Azure IoT Device), and assign a new meter “TEMP-C” to this asset.\nThe following step we will leverage the out of box MXASSET Object Structure through Maximo Integration Framework (MIF) NextGen Restful API to post temperature data to Asset TempSimulator meter reading in Maximo. The following are the high level introduction of OS, MIF and Maximo NextGen Restful API. You can learn more detail information on them through the links if you are interesting.\n(1) Object Structure (OS): An object structure is the common data layer that the integration framework components use for sending and receiving data in Maximo® Asset Management. An object structure consists of one or more related business objects that define the content of an integration message. An object structure provides the message content for channels and services and enables application-based import and export. In addition, an object structure, on its own, can be called as a service, supporting the Create, Update, Delete, Sync, and Query operations.\nhttps://www.ibm.com/docs/es/mam/7.6.0?topic=os-modification-predefined-object-structure\nWe will use out of box OS MXASSET in Maximo to post temperature data through Maximo NextGen Restful API in Azure function. The following is the MXASSET OS setting in Maximo:\n(2) Maximo Integration Framework (MIF): The Maximo Integration Framework (MIF) is an integral part of the Tivoli Process Automation Engine (TPAE) that allows the synchronization and integration of data and of applications between TPAE and external systems in real time or batch mode by using a variety of communication protocols.\nhttps://www.ibm.com/docs/en/maximo-eam-saas?topic=integrating-data-external-applications\n(3) Maximo NextGen Restful API: Maximo NextGen REST APIs are a complete rewrite of the existing REST apis that was released around Maximo version 7.1. Maximo NextGen REST apis are in Maximo releases starting 7602 version. The NextGen apis are often referred to as the REST/JSON apis for the end to end support for JSON data format.\nhttps://www.ibm.com/support/pages/system/files/inline-files/Maximo_NextGen_REST_API_-_nextgen.pdf\n2.** Update Azure Function to post temperature data which receive from Azure Event Grid to Maximo Asset Reading through Object Structure MXASSET Restful API.**\nIn the following section, we will update Azure function code in Part 1to post temperate data from IoT device simulator to Maximo Asset meter reading through object structure MXASSET restful API.\nOpen Azure portal and locate Azure function EventGridDataEventParser we built in part 1.\nClick “Code + Test” in the left panel, update the run.csx code as the following:\n#r \u0026#34;Azure.Messaging.EventGrid\u0026#34; #r \u0026#34;System.Memory.Data\u0026#34; #r \u0026#34;Newtonsoft.Json\u0026#34; using Azure.Messaging.EventGrid; using Newtonsoft.Json.Linq; using Newtonsoft.Json; using System.Net.Http; using System.Net.Http.Headers; using System; using System.Text; public static async void Run(EventGridEvent eventGridEvent, ILogger log) { var eventData=eventGridEvent.Data.ToString(); log.LogInformation(\u0026#34;Functionlog: \u0026#34;+eventData); JObject json = JObject.Parse(eventData); JToken token = json.SelectToken(\u0026#34;systemProperties.iothub-connection-device-id\u0026#34;); var deviceID=token?.ToString(); log.LogInformation(\u0026#34;Device ID: \u0026#34;+deviceID); //token = json.SelectToken(\u0026#34;systemProperties.dt-subject\u0026#34;); token = json.SelectToken(\u0026#34;body.metername\u0026#34;); var meterID=token?.ToString(); log.LogInformation(\u0026#34;Meter ID: \u0026#34;+meterID); token = json.SelectToken(\u0026#34;body.temperature\u0026#34;); var meterReading=token?.ToString(); log.LogInformation(\u0026#34;Meter Reading: \u0026#34;+meterReading); token = json.SelectToken(\u0026#34;systemProperties.iothub-enqueuedtime\u0026#34;); var eventTime=token?.ToString(Formatting.None); log.LogInformation(\u0026#34;Event Time: \u0026#34;+eventTime); //call maximo api to get resouce uri var baseUrl = \u0026#34;http://{replace with your maximo server name}/maximo/oslc/os/mxasset\u0026#34;; HttpClient client = new HttpClient(); //update the following maxauth header value to your maximo account value. client.DefaultRequestHeaders.Add(\u0026#34;maxauth\u0026#34;,\u0026#34;{User credentials encoded to base64 format}\u0026#34;); var apimUrl=baseUrl+\u0026#34;?lean=1\u0026amp;oslc.where=assetnum=\\\u0026#34;\u0026#34;+deviceID+\u0026#34;\\\u0026#34;\u0026#34;; log.LogInformation($\u0026#34;Get Url: {apimUrl}\u0026#34;); try { /*The following code is to query Asset from Maximo nextgen rest API to get resource ID by assetnum (DeviceID in the event message body), which can be used to post meter reading to Maximo through nextgen Rest API. */ using HttpResponseMessage result =await client.GetAsync(apimUrl); result.EnsureSuccessStatusCode(); var content = await result.Content.ReadAsStringAsync(); log.LogInformation($\u0026#34;Get Request result: {content}\u0026#34;); JObject jsonResult = JObject.Parse(content); JToken tokenMember = jsonResult.SelectToken(\u0026#34;member\u0026#34;); String strMembers= tokenMember?.ToString(); log.LogInformation($\u0026#34;Query Member result: {strMembers}\u0026#34;); JArray jArrayResult= JArray.Parse(strMembers); if(jArrayResult is null || jArrayResult.Count==0) { log.LogError(\u0026#34;\\nNo result was found for Asset Num:\u0026#34;+deviceID); } else { JObject jObjecturl = jArrayResult.First.ToObject\u0026lt;JObject\u0026gt;(); JToken tokenUrl=jObjecturl.SelectToken(\u0026#34;href\u0026#34;); log.LogInformation(\u0026#34;Found Asset URL:\u0026#34;+tokenUrl?.ToString()); String assetUrl=tokenUrl?.ToString(); if(assetUrl.Length\u0026gt;0) { String[] strList=assetUrl.Split(new string[] { \u0026#34;/\u0026#34; }, StringSplitOptions.None); String resourceID=strList[strList.Length-1]; log.LogInformation($\u0026#34;ResourceID:{resourceID}\u0026#34;); //Post meter reading to Maximo dynamic jObjectMeter=new JObject(); jObjectMeter.metername=meterID; jObjectMeter.linearassetmeterid=0; jObjectMeter.newreading=meterReading; jObjectMeter.newreadingdate=eventTime.Substring(1,19)+\u0026#34;+00:00\u0026#34;; dynamic jObjectAsset=new JObject(); dynamic jArrayMeters=new JArray(); jArrayMeters.Add(jObjectMeter); jObjectAsset.assetmeter=jArrayMeters; String postJson=JsonConvert.SerializeObject(jObjectAsset); log.LogInformation($\u0026#34;Post Json Content: {postJson}\u0026#34;); using (var postContent = new StringContent(postJson, System.Text.Encoding.UTF8, \u0026#34;application/json\u0026#34;)) { var postUrl=baseUrl+\u0026#34;/\u0026#34;+resourceID+\u0026#34;?lean=1\u0026#34;; log.LogInformation($\u0026#34;Post Url: {postUrl}\u0026#34;); //add header for Maximo nextgen rest API update scenario client.DefaultRequestHeaders.Add(\u0026#34;x-method-override\u0026#34;,\u0026#34;PATCH\u0026#34;); client.DefaultRequestHeaders.Add(\u0026#34;patchtype\u0026#34;,\u0026#34;MERGE\u0026#34;); HttpResponseMessage resultPost =await client.PostAsync(postUrl, postContent); resultPost.EnsureSuccessStatusCode(); var postResultContent = await resultPost.Content.ReadAsStringAsync(); log.LogInformation($\u0026#34;Post request result: {postResultContent}\u0026#34;); } } else { log.LogError($\u0026#34;Error: Asset Num:{deviceID} url is empty\u0026#34;); } } } catch (HttpRequestException e) { log.LogError(\u0026#34;\\nHttp Exception Caught!\u0026#34;); log.LogError(\u0026#34;Message :{0} \u0026#34;, e.ToString()); } catch (Exception e) { log.LogError(\u0026#34;\\nUnexpected Exception Caught!\u0026#34;); log.LogError(\u0026#34;Message :{0} \u0026#34;, e.ToString()); } } There are 2 places you need to update on above code:\n(1) var baseUrl = “http://{replace with your maximo server name}/maximo/oslc/os/mxasset”;\nUpdate {replace with your maximo server name} to be your Maximo server name.\n(2) client.DefaultRequestHeaders.Add(“maxauth”,”{User credentials encoded to base64 format}”);\nUpdate* *{User credentials encoded to base64 format} to be your maximo user account and password in base64 format encode. For example, if your maximo user account is maxadmin, password is maxadmin, the user credential format is *maxadmin:maxadmin. *And then use base64 encryption tool (for example https://www.base64encode.org/) to encode the string *maxadmin:maxadmin. *The encode string is bWF4YWRtaW46bWF4YWRtaW4=\nSave the change of run.csx file. Click “Monitor” in the left panel, and then click Logs tab to open the log window.\nRun the IoT device simulator python code in the local machine to send random template data to Azure IoT hub.\nOn the Azure function monitor logs window, we will receive these event data from Azure IoT hub through Azure Event Grid, and are parsed by the code in Azure function EventGridDataEventParser:\nAnd open Asset application in Maximo, locate asset “TempSimulator”, click “Manage Meter Read History” under “More Action” section, and click “Characteristic and Gauge Meter Readings” tab, you will see the temperature data from IoT device simulator are posted to Maximo.\nIn the part 1 \u0026amp; this part 2 blogs, we leveraged Azure IoT solution to created IoT device simulator in local machine to generate random temperature data, connect and send them to Azure IoT hub, through Azure Event Grid to pass telemetry to Azure Function. In Azure Function, call Maximo NexGen Rest API to post telemetry data to Maximo Asset meter reading.\nOf course this POC can be expanded to add data analysis module in Azure Cloud, for example, all of the telemetry data will be stored in Azure Cosmos DB, build Azure machine learning module to analyze the telemetry data in Azure Cosmos, raise work order in Maximo through Maximo NextGen Restful API base on analysis result if need. This expansion solution will be covered in my future blog.\nYou can get full source code from GitHub:\nIf you think this blog helping you, welcome to buy me a coffee through below Give a Tip button after this blog :)\n"},{"title":"How to shrink docker volume after delete containers / images in Windows 10","permalink":"https://eamstream.com/posts/shrink-docker-volume-windows-10/","summary":"Docker becomes more and more popular in the development process, especially for the organization adopting DevOps process. I have couple projects require to use docker to build local development environment. My local hard disk space started to getting red after 2–3 rounds of rebuilding local docker environment for different branches of the code change. I did run rm command to remove containers, images and volumes. Since Docker Desktop for Windows uses WSL to manage all the images and container files and keeps them in a private virtual hard drive (VHDX) called ext4.vhdx. This vhdx will not automatically shrink when you remove docker, images or volumes. You need to follow the below step to shrink it.\n","content":"Docker becomes more and more popular in the development process, especially for the organization adopting DevOps process. I have couple projects require to use docker to build local development environment. My local hard disk space started to getting red after 2–3 rounds of rebuilding local docker environment for different branches of the code change. I did run rm command to remove containers, images and volumes. Since Docker Desktop for Windows uses WSL to manage all the images and container files and keeps them in a private virtual hard drive (VHDX) called ext4.vhdx. This vhdx will not automatically shrink when you remove docker, images or volumes. You need to follow the below step to shrink it.\n(1) Quick from your docker desktop application\n(2) Run Windows Powershell as Administrator\n(3) Run the following command to shut down wsl\nwsl \u0026ndash;shutdown\n(4) Run the follow command to mouth VHD file. Please modify yourusername to your current windows’ user\nMount-VHD -Path C:\\Users\\yourusername\\AppData\\Local\\Docker\\wsl\\data\\ext4.vhdx -ReadOnly\n(5) Run the following command to optimize the VHD file.\nOptimize-VHD -Path C:\\Users\\jacky\\AppData\\Local\\Docker\\wsl\\data\\ext4.vhdx -Mode Full\nThe Progress bar will be shown as following.\nAfter this step, you should be able to see your hard drive space coming back.\n(6) Run the following command to dismount VHD file\nDismount-VHD C:\\Users\\jacky\\AppData\\Local\\Docker\\wsl\\data\\ext4.vhdx\n(7) Restart your docker desktop. You all set.\nIf you think this blog helping you, welcome to buy me a coffee through below Give a Tip button after this blog :)\n"},{"title":"MAXIMO BIRT Report PDF format page crossing issue","permalink":"https://eamstream.com/posts/maximo-birt-pdf-page-crossing-issue/","summary":"Yes, I am still working on BIRT report as fire fighter for one of my projects. Now was into another tricky issue. The BIRT report I am helping on looks all good except when try to export it to PDF. Some particular page the content cross the footer, such as below:\nTried different options, such as setting page break, modified padding of the row. But none of them solved this issue. Tried asked MR. Google, but didn’t find any useful solution on it. The client can accept to move the paging number to the top, but it will require to update the master page template, and I thought it is not a good solution as well. I can understand this should be caused by pdf export function on calculating the page content might be different with how BIRT report, but cannot figure out which setting might cause the problem.\n","content":"Yes, I am still working on BIRT report as fire fighter for one of my projects. Now was into another tricky issue. The BIRT report I am helping on looks all good except when try to export it to PDF. Some particular page the content cross the footer, such as below:\nTried different options, such as setting page break, modified padding of the row. But none of them solved this issue. Tried asked MR. Google, but didn’t find any useful solution on it. The client can accept to move the paging number to the top, but it will require to update the master page template, and I thought it is not a good solution as well. I can understand this should be caused by pdf export function on calculating the page content might be different with how BIRT report, but cannot figure out which setting might cause the problem.\nTook a deep breath, and walked away from computer, came back with refresh eyes and reviewed page setting from the below IBM website.\nThe following page setting caused my attention. There is slight difference between US letter and A4 size. In US, Letter is US version of A4 page size. The following image shows what’s the different of them.\nWhen BIRT report export to PDF version, it might default to US letter page size. I went back to eclipse, opened the report, and located the master page size setting, the page type is A4, instead of US Letter.\nAfter change this page type to be US Letter, run the report again, the issue of content crossing the footer was gone. Tested different records in the report to make sure this issue is really fixed. Now can clapped my hand and release it to testing environment for business team to validate it.\nHope this article can give you a hint when you have the similar issue on BIRT report export to pdf.\nIf you think this blog helping you, welcome to buy me a coffee through below Give a Tip button after this blog :)\n"},{"title":"How to use Regular Expression in Maximo BIRT Report","permalink":"https://eamstream.com/posts/maximo-birt-regular-expression/","summary":"If you read my previous blog, you might know I am recently working as fire fighter on Maximo BIRT reports. One of requirement on a complicated report is required to retrieve number inside parentheses from long description, for example, need to get (2) from the following long description content:\n(2) this is long description text, might content rich text format\nThe solution in my mind when I heard this requirement is to use regular expression. Since in current project the Maximo database is DB2, asked Mr. Google to found DB2 did support regular expression in the query. After looked up regular expression functions on DB2 document, REGEXP_INSTR function is what I need. For example, if you run the following query:\n","content":"If you read my previous blog, you might know I am recently working as fire fighter on Maximo BIRT reports. One of requirement on a complicated report is required to retrieve number inside parentheses from long description, for example, need to get (2) from the following long description content:\n(2) this is long description text, might content rich text format\nThe solution in my mind when I heard this requirement is to use regular expression. Since in current project the Maximo database is DB2, asked Mr. Google to found DB2 did support regular expression in the query. After looked up regular expression functions on DB2 document, REGEXP_INSTR function is what I need. For example, if you run the following query:\nselect REGEXP_Substr(‘(2) this is long description text, might content rich text format’,’(\\b[0–9]+\\b)’,1,1) from sysibm.sysdummy1\nYou will get the result as:\n(2)\nYou can refer to DB2 document on more detail on REGEXP_INSTR function:\nAfter implemented this logic in the query, tested the whole query (more than 900 lines ), the result is what I expected. Merged the changes of the query to Maximo BIRT report script at the dataset open event. Ran the report in eclipse, the result was not what I expected, the REGEXP_INSTR function didn’t retrieve the number from the long description content. Went to the report log which contain the printed sql, found something interested in query string which was generated in the BIRT report script, the pattern expression string in REGEXP_INSTR function was changed to some characters:\nI guessed it might be caused by the backslash \\ is the special character in the BIRT report script. It might require double backslash to get one backslash in the script. After made the following change, the result of the report worked as I expected.\nThe regression expression is really powerful tool for handling the string. If you are interested, you can also refer to DB2 Regular expression control characters document (other languages / systems have pretty similar on regular expression control characters)\nIf you think this blog helping you, welcome to buy me a coffee through below Give a Tip button after this blog :)\n"},{"title":"Solution for Maximo BIRT Report Exception of “MXReportScriptContext” is not defined.","permalink":"https://eamstream.com/posts/maximo-birt-mxreportscriptcontext-not-defined/","summary":"2 years ago was working on developing Maximo BIRT report in client laptop, which was installed firefox browser by default. There was not issue when I installed and configured BIRT report development environment at that moment. Recently in my project one of the my team member was on paternity leave, I had to roll up my sleeve again to pick up the a BIRT Report he was working which was required hard deadline (Firefighter is always my other role in the projects). Followed the instruction to install and configure my local BIRT report development environment, everything was good until tried to run the report in Eclipse, got the following error:\n","content":"2 years ago was working on developing Maximo BIRT report in client laptop, which was installed firefox browser by default. There was not issue when I installed and configured BIRT report development environment at that moment. Recently in my project one of the my team member was on paternity leave, I had to roll up my sleeve again to pick up the a BIRT Report he was working which was required hard deadline (Firefighter is always my other role in the projects). Followed the instruction to install and configure my local BIRT report development environment, everything was good until tried to run the report in Eclipse, got the following error:\norg.mozilla.javascript.EcmaError: ReferenceError: “MXReportScriptContext” is not defined. at org.mozilla.javascript.ScriptRuntime.constructError(ScriptRuntime.java:3654) at org.mozilla.javascript.ScriptRuntime.constructError(ScriptRuntime.java:3632) at org.mozilla.javascript.ScriptRuntime.notFoundError(ScriptRuntime.java:3717) at org.mozilla.javascript.ScriptRuntime.nameOrFunction(ScriptRuntime.java:1758) at org.mozilla.javascript.ScriptRuntime.name(ScriptRuntime.java:1697) at org.mozilla.javascript.Interpreter.interpretLoop(Interpreter.java:3410) at org.mozilla.javascript.Interpreter.interpret(Interpreter.java:2487) at org.mozilla.javascript.InterpretedFunction.call(InterpretedFunction.java:164) at org.mozilla.javascript.ContextFactory.doTopCall(ContextFactory.java:398) at org.mozilla.javascript.ScriptRuntime.doTopCall(ScriptRuntime.java:3065) at org.mozilla.javascript.InterpretedFunction.exec(InterpretedFunction.java:175) at org.eclipse.birt.report.engine.javascript.JavascriptEngine.evaluate(JavascriptEngine.java:290) at org.eclipse.birt.core.script.ScriptContext.evaluate(ScriptContext.java:159) at org.eclipse.birt.report.engine.executor.ExecutionContext.evaluate(ExecutionContext.java:789) at org.eclipse.birt.report.engine.executor.ExecutionContext.evaluate(ExecutionContext.java:718) at org.eclipse.birt.report.engine.script.internal.ScriptExecutor.handleScriptInternal(ScriptExecutor.java:118) at org.eclipse.birt.report.engine.script.internal.ScriptExecutor.handleScript(ScriptExecutor.java:105) at org.eclipse.birt.report.engine.script.internal.ReportScriptExecutor.handleInitialize(ReportScriptExecutor.java:84) at org.eclipse.birt.report.engine.api.impl.EngineTask.loadDesign(EngineTask.java:1962) at org.eclipse.birt.report.engine.api.impl.RunAndRenderTask.doRun(RunAndRenderTask.java:99) at org.eclipse.birt.report.engine.api.impl.RunAndRenderTask.run(RunAndRenderTask.java:77) at org.eclipse.birt.report.debug.internal.core.launcher.ReportLauncher.createReport(ReportLauncher.java:620) at org.eclipse.birt.report.debug.internal.core.launcher.ReportLauncher.renderReport(ReportLauncher.java:566) at org.eclipse.birt.report.debug.internal.core.launcher.ReportLauncher.run(ReportLauncher.java:480) at org.eclipse.birt.report.debug.internal.core.launcher.ReportLauncher.main(ReportLauncher.java:124) at org.eclipse.birt.report.debug.internal.core.ReportDebugger.start(ReportDebugger.java:39) at org.eclipse.equinox.internal.app.EclipseAppHandle.run(EclipseAppHandle.java:196) at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.runApplication(EclipseAppLauncher.java:110) at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.start(EclipseAppLauncher.java:79) at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:354) at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:181) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:606) at org.eclipse.equinox.launcher.Main.invokeFramework(Main.java:636) at org.eclipse.equinox.launcher.Main.basicRun(Main.java:591) at org.eclipse.equinox.launcher.Main.run(Main.java:1450) at org.eclipse.equinox.launcher.Main.main(Main.java:1426)\nAs usual tried to ask Mr. Google, but didn’t find any useful information on this error. There is the reason I wrote this blog tried to give hint to you to solve this issue if you happen to encounter the same issue.\nAfter checked with the team who installed and configured BIRT report development environment, they mentioned need to use firefox browser to view report in Eclipse. That give me the hint after I reviewed the following error message:\norg.mozilla.javascript.EcmaError: ReferenceError: “MXReportScriptContext” is not defined.\nFirebox is also the product from Mozilla. Now it explain why it works fine on other team member’s environment which installed firefox browser.\nThe following steps is to fix the above issue:\n(1) Download firefox from the below official site and install it.\n(2) Open Eclipse, go to menu “Window -\u0026gt; Preference”, expand node “Report Design”, click on “Preview” node. Check “Always use external browsers”\n(3) Click link “Web Browser” Link under the “Always use external browsers” checkbox. Select option “Use external web browser”, and check “Firebox” checkbox in the list. Click OK button to save the change.\n(4) Restart Eclipse, and run your report through menu “Run -\u0026gt; View Report -\u0026gt; In Web Viewer”. Your report should be launched successfully now.\nIf you think this blog helping you, welcome to buy me a coffee through below Give a Tip button after this blog :)\n"},{"title":"Maximo: How to update system property value","permalink":"https://eamstream.com/posts/maximo-update-system-property-value/","summary":"In Maximo, there are a lot of system default property for different purposes. You can define your own property in System Properties Application, which can be used in your customized script code, configuration, or Maximo Integration Framework (MIF).\nAs default setting, you cannot change the value for system default property. For some special scenarios, you might have to change the system property default value. To be able to modify system default property, the following instruction will provide an example on how to change the property: mxe.int.binarytext\n","content":"In Maximo, there are a lot of system default property for different purposes. You can define your own property in System Properties Application, which can be used in your customized script code, configuration, or Maximo Integration Framework (MIF).\nAs default setting, you cannot change the value for system default property. For some special scenarios, you might have to change the system property default value. To be able to modify system default property, the following instruction will provide an example on how to change the property: mxe.int.binarytext\nConnect to Maximo database, run the following script against Maximo database (You need to have update permission to the maximo database):\nupdate maximo.maxprop set userdefined=1 where propname = ‘mxe.int.binarytext’\nGo to Maximo -\u0026gt; System Configuration -\u0026gt; Platform Configuration -\u0026gt; System Properties. Filter by mxe.int.binarytext in the column property name to locate the record:\nCheck Online Changes Allowed? checkbox, and Save the change.\nNow you can modify Global Value field. After modify the Global Value, Save the change, and click Live Refresh from action list to apply the global value to current value.\nWarning: Please make sure your fully understanding the impact of the system property you want to update before you make the change.\n"},{"title":"Maximo Workflow Error: BMXAA4299E","permalink":"https://eamstream.com/posts/maximo-workflow-error-bmxaa4299e/","summary":"Recently encountered a pretty strange issue when tried to release an simple Maximo workflow to production environment. The workflow is to allow business team (Maximo Support team) to review new service request, to decide to create related work order, or cancel service request. The following is the workflow diagram:\nThis workflow is working fine in testing environment. When we implemented the same workflow in production, doing the production check-out: created a new SR, attached it to this workflow, started the workflow, got the error message: BMXAA4299E\n","content":"Recently encountered a pretty strange issue when tried to release an simple Maximo workflow to production environment. The workflow is to allow business team (Maximo Support team) to review new service request, to decide to create related work order, or cancel service request. The following is the workflow diagram:\nThis workflow is working fine in testing environment. When we implemented the same workflow in production, doing the production check-out: created a new SR, attached it to this workflow, started the workflow, got the error message: BMXAA4299E\nTried to google BMXAA4299E, but got little related result on this issue. After couple hours’ research, finally figure the issue caused by the current user is not in the person group which is assigned to the role on task node:\nAfter assign the current user mapped person to the person group which assigned to the role in the task node, the issue was solved. Hope this article will give you the hint if you encounter the same error message id BMXAA4299E.\nIf you think this blog helping you, welcome to buy me a coffee through below Give a Tip button after this blog :)\n"},{"title":"How to query data in Maximo through Restful API","permalink":"https://eamstream.com/posts/maximo-query-data-restful-api/","summary":"For Maximo integration with external system, there are two directions from Maximo’s perspective: Inbound and outbound interfaces. There is a lot of business scenarios for the requirement of query data from Maximo, which we consider it as outbound interface for Maximo. For example, external system ServiceNow might need to query service request data in Maximo to pull out the service request current status.\nThere are couple ways to query data from Maximo. Maximo support Web Service and Restful. The return result can be xml or json format. In this article, will show you how to leverage Maximo Restful API to query data in Maximo.\n","content":"For Maximo integration with external system, there are two directions from Maximo’s perspective: Inbound and outbound interfaces. There is a lot of business scenarios for the requirement of query data from Maximo, which we consider it as outbound interface for Maximo. For example, external system ServiceNow might need to query service request data in Maximo to pull out the service request current status.\nThere are couple ways to query data from Maximo. Maximo support Web Service and Restful. The return result can be xml or json format. In this article, will show you how to leverage Maximo Restful API to query data in Maximo.\nThe REST API exposes business objects and integration object structures as REST resources. The REST API can provide resource data in either XML or JavaScript Object Notation (JSON) format. External applications can use the REST API to query and update application data. We will focus on the query in this article, will have other blog to explain on the update.\nThe following diagram provides an overview of how the REST API handles requests.\nAs you can see from the above diagram, to allow external system to query data from Maximo, you need to create your Object Structure (OS) to expose the business data you would like to allow external system to call, or external system can access to Maximo Business Object (MBO) data through Restful API if there is not complex data requirement. When an external consumer initiates a request, a REST API controller directs the resource request to the appropriate resource handler. The resource handler interacts with resources to execute the request. When the request is complete, the resulting resource or resource collection is processed by the resource serializer. The resource serializer returns the representation as the resource response. Serializers are provided for XML and JSON.\nNow let’s take a look how to query Maximo business object (MBO) and Object Structure (OS) through the examples.\nThe query will use GET action, the follow is an example to query locations MBO for the location of PT100, and the return format is Json\nhttps://yourmaximoserver/maxrest/rest/mbo/locations?location=PT100\u0026amp;_format=json The following will be return:\n{\n“LOCATIONSMboSet”: {\n“rsStart”: 0,\n“rsCount”: 1,\n“LOCATIONS”: [\n{\n“rowstamp”: “4874304”,\n“Attributes”: {\n“LOCATION”: {\n“content”: “PT100”\n},\n“DESCRIPTION”: {\n“content”: “Demo data”\n},\n“TYPE”: {\n“content”: “FPOS”\n},\n“GLACCOUNT”: {\n“content”: “0000–000000–0000–000000000000000000000000”\n},\n“CHANGEBY”: {\n“content”: “MAXADMIN”\n},\n“CHANGEDATE”: {\n“content”: “2020–12–06T21:24:42+00:00”\n},\n“DISABLED”: {\n*“content”: *false\n},\n“SITEID”: {\n“content”: “DEMOSITE”\n},\n“ORGID”: {\n“content”: “DEMOORG”\n},\n“ISDEFAULT”: {\n*“content”: *false\n},\n“CHILDREN”: {\n*“content”: *false\n},\n“STATUS”: {\n“content”: “OPERATING”\n},\n“LOCATIONSID”: {\n“content”: 1351,\n*“resourceid”: *true\n},\n“HASCHILDREN”: {\n*“content”: *false\n},\n“HASPARENT”: {\n*“content”: *false\n},\n“OBJECTNAME”: {\n“content”: “LOCATIONS”\n},\n“USEINPOPR”: {\n*“content”: *false\n},\n“LANGCODE”: {\n“content”: “EN”\n},\n“ADDTOSTORESITEID”: {\n“content”: “DEMOSITE”\n},\n“HASLD”: {\n*“content”: *false\n},\n“AUTOWOGEN”: {\n*“content”: *false\n},\n“STATUSIFACE”: {\n*“content”: *false\n},\n“STATUSDATE”: {\n“content”: “2020–12–06T21:24:42+00:00”\n},\n“ISREPAIRFACILITY”: {\n*“content”: *false\n},\n“EXPECTEDLIFE”: {\n“content”: 0\n},\n“REPLACECOST”: {\n“content”: 0.0\n},\n“PLUSCLOOP”: {\n*“content”: *false\n},\n“PLUSCPMEXTDATE”: {\n*“content”: *false\n},\n“SHOWFROMDATE”: {\n“content”: “2020–12–06T00:00:00+00:00”\n},\n“ASSIGNED”: {\n*“content”: *false\n},\n“PLUSGPERMITREQ”: {\n*“content”: *false\n},\n“PLUSGEXREGISTERED”: {\n*“content”: *false\n},\n“PLUSGRISKASSESSED”: {\n*“content”: *false\n},\n“PLUSGSAFETYCRIT”: {\n*“content”: *false\n},\n“PLUSGENVCRIT”: {\n*“content”: *false\n},\n“PLUSGCOMCRIT”: {\n*“content”: *false\n},\n“PLUSGHISTORYPERIOD”: {\n“content”: 365\n},\n“PLUSGOPENOMUID”: {\n“content”: 1351\n},\n“PLUSGISTEMP”: {\n*“content”: *false\n},\n“PLUSGISPASSVALVE”: {\n*“content”: *false\n},\n“PLUSGLEAKING”: {\n*“content”: *false\n},\n“PLUSGQUALITYCRITICAL”: {\n*“content”: *false\n},\n“PLUSPUSAGETORECORD”: {\n*“content”: *false\n},\n“PLUSSISGIS”: {\n*“content”: *false\n},\n“BRDPLOCPRESINFO”: {\n*“content”: *false\n},\n“BRDPRESTRICTED”: {\n*“content”: *false\n}\n}\n}\n]\n}\n}\nFrom above return, we can see there are some redundant content. You can use parameter _compact=1 to remove them:\nhttps://yourmaximoserver/maxrest/rest/mbo/locations?location=PT100\u0026amp;_format=json\u0026amp;_compact=1 "},{"title":"How to solve the issue of start center cannot be edited for being modified by someone","permalink":"https://eamstream.com/posts/maximo-start-center-cannot-be-edited/","summary":"On one of the Maximo production release, we need to modify one of the start center template in production. But when click the start center template would like to modify, but got the following error:\nBMXAA7941E — You cannot modify this template because it is being modified by another user\nThe issue was caused by someone open this start center template to modify, but forget to save or cancel the modification. It will keep this start center being locked by this user, until he/she save or cancel the change. We need to identify which user is modifying this template, and ask him / her to unlock the template by save / cancel. Unfortunately Maximo doesn’t provide the way to check who is locking the start center template. The only way you can figure out is through query the table “scconfig” in Maximo database directory. Open sql tool, execute the following sql script:\n","content":"On one of the Maximo production release, we need to modify one of the start center template in production. But when click the start center template would like to modify, but got the following error:\nBMXAA7941E — You cannot modify this template because it is being modified by another user\nThe issue was caused by someone open this start center template to modify, but forget to save or cancel the modification. It will keep this start center being locked by this user, until he/she save or cancel the change. We need to identify which user is modifying this template, and ask him / her to unlock the template by save / cancel. Unfortunately Maximo doesn’t provide the way to check who is locking the start center template. The only way you can figure out is through query the table “scconfig” in Maximo database directory. Open sql tool, execute the following sql script:\nselect * from maximo.scconfig where groupname is null\nYou will be able figure who (USERID column) is modifying the template (DESCRIPTION column)\nAsk the user to login Maximo, on the locked start center, click on the Save Template or Cancel Changes hyperlinks on the right top tool bar on the screen, will unlock the start center template.\nHow about if the user who is locking the template already left the organization? Or cannot be reached during the production release? Login as maxadmin security group user, find the user who is locking the start center template in the user application, reset the password for this user, and then login with this user to unlock the template.\nIt is really interested IBM doesn’t provide the function to allow maxadmin to unlock the start center, hope this function will be included in next release.\n"},{"title":"What is Maximo Recurrence of inbound transactions and how to use it?","permalink":"https://eamstream.com/posts/maximo-recurrence-inbound-transactions/","summary":"IBM Maximo is very powerful and flexible EAM Platform, especially its integration framework. In Maximo Integration Framework (MIF), there are a lot of options you can configure or develop inbound and outbound interfaces to integrate Maximo with other systems. I will try to introduce more details on MIF in other topics, this topic will introduce recursion of inbound interface in Maximo and how to use it in real business case.\n","content":"IBM Maximo is very powerful and flexible EAM Platform, especially its integration framework. In Maximo Integration Framework (MIF), there are a lot of options you can configure or develop inbound and outbound interfaces to integrate Maximo with other systems. I will try to introduce more details on MIF in other topics, this topic will introduce recursion of inbound interface in Maximo and how to use it in real business case.\nWhat is Maximo inbound recursion? Simplify the explanation: An inbound transaction from external system to Maximo will trigger an outbound transaction from Maximo to external system. If we don’t have mechanism or event filter configuration setup correctly, might cause a dead loop for external system send inbound transaction again to Maximo which is triggered by the previous outbound transaction from Maximo. To avoid this issue happen, Maximo default to set recursion to be false, that means outbound transaction will not be triggered by inbound transaction. But for some special business cases, we do need to open this recursion. For example, when an service ticket from ServiceNow system, is sent in Maximo using the Integration Framework. In Maximo, it will create service request from this inbound transaction, after service request is created, need to send services ID (ticket ID) back to ServiceNow. But since Maximo default to disable inbound recursion, this will prevent Maximo outbound interface to send out ticket ID to ServiceNow. To enable outbound interface trigger by the inbound transaction, you just need to extend event trigger class *MaximoEventFilter *and overwrite the function *stopRecurrence *to return false (Maximo default to return true). Set this new customized event class in your publish channel which will allow your outbound interface trigger by inbound transaction. The following is the java code for the customized event class:\npackage psdi.iface.app.common; import java.rmi.RemoteException; import psdi.iface.mic.MaximoEventFilter; import psdi.iface.mic.MicUtil; import psdi.iface.mic.PublishInfo; import psdi.mbo.MboRemote; import psdi.server.MXServer; import psdi.util.MXException; public class StopRecurEventFilterextends MaximoEventFilter { /** * This method stops recurrence, i.e it checks if this is incoming * transaction and if the MetaDataProperties.SOURCETYPE is specified stops the event * from going out. * This method can be overriden by individual event filter classes to allow * recurrence. * * @return - true for stopping the event and false otherwise. * @throws MXException * MAXIMO exception * @throws RemoteException * Remote exception */ protected boolean stopRecurrence(MboRemote mbo) throws MXException, RemoteException { return false; } } On your publish channel for your outbound, set this customized event class psdi.iface.app.common.StopRecurEventFilter on in the Event Filter Class field.\nPublish your java class to ear file and restart your Maximo applicaiton. Test inbound to see if it will trigger the outbound publish channel with this customized event class.\n"},{"title":"The Latest Ethereum Solidity Smart Contract Development Tutorial (Part -3) — Compile, Deploy and","permalink":"https://eamstream.com/posts/ethereum-solidity-tutorial-part3-compile-deploy/","summary":"If you following my previous 2 serials:\n(Part -1) — Solidity Smart Contract development environment setup for Visual Studio Code with Truffle framework\n(Part -2) — Develop solidity smart contract in truffle\nyou should be able to setup your solidity smart contract development environment and write your first smart contract. Now let’s take further adventure to compile, deploy and test the smart contract we developed in previous tutorial.\n**Step 1 **— Compile smart contract\n","content":"If you following my previous 2 serials:\n(Part -1) — Solidity Smart Contract development environment setup for Visual Studio Code with Truffle framework\n(Part -2) — Develop solidity smart contract in truffle\nyou should be able to setup your solidity smart contract development environment and write your first smart contract. Now let’s take further adventure to compile, deploy and test the smart contract we developed in previous tutorial.\n**Step 1 **— Compile smart contract\nIn a VS Code terminal window, make sure you are at the current DAPP folder, in our case, it is C:\\DAPPTutorial. Type the command “truffle compile” and enter, you will get the result like this:\nYou should find some json files is created under the folder .\\build\\contracts\nThose .json file are the ABI (Application Binary Interface) that describe the deployed contract and its functions. It allows us to contextualize the contract and call its functions, which will allow external application, for example, web3.js to call the exposed functions for the deployed smart contract. We will learn more detail on it on next serial Part-4 How to call smart contract from web javascript.\nStep 2— Create migration script in folder migrations\nMigrations are JavaScript files that help you deploy contracts to the Ethereum network. These files are responsible for staging your deployment tasks, and they’re written under the assumption that your deployment needs will change over time. As your project evolves, you’ll create new migration scripts to further this evolution on the blockchain. A history of previously run migrations is recorded on-chain through a special Migrations contract.\nCreate a new file call “2_deploy_RockScissorsPaper.js” under migration folders.\nNote that the filename is prefixed with a number and is suffixed by a description. The numbered prefix is required in order to record whether the migration ran successfully. The suffix is purely for human readability and comprehension.\nOpen this new created “2_deploy_RockScissorsPaper.js” file in VS Code and type the following code to it.\nvar MyContract = artifacts.require(“RockScissorsPaper”);\nmodule.exports = function(deployer) {\n// deployment steps\ndeployer.deploy(MyContract,5);\n};\nIn the above script, it is used to deployed our smart contract “RockScissorsPaper”. The script number 5 in the statement *deployer.deploy(MyContract,5) *is the parameter to pass to the contract construction function:\nconstructor(uint8 _commissionPercent) public\n{ // contract constructor\ncommissioner = msg.sender;\ncommissionPercent=_commissionPercent;\nhostNumber=0;\n}\nSave this js file and we will move to next step to migrate (deploy) this contract to ganache.\nStep 3 — Migrate (Deploy) smart contract to ganache\nMake sure the ganache-cli is running, and in the VS Code terminate, run the following command (please make sure in that terminate you are under current application folder) :\ntruffle migrate\nYou will see the following similar screen after the command being executed:\nThe first smart contract deployment is for the Migrations.sol which is to support truffle framework. The second contract deployment is for our Rockscissorspaper.sol smart contract. And from the result, we can get contract address, and how many gas cost to deploy the contract.\nAfter the contract deployed, the *constructor *function for the contract is executed, and it is the only chance to run this constructor.\nNow we deployed our smart contract to the blockchain. Next we will see how to call the mart contract functions through truffle console.\nStep 4 — Call smart contract function in truffle console\nIn a VS Code terminate, run the following command to launch truffle console:\ntruffle console\nThen you will see we are in the truffle console as following:\nYou can quit from the truffle console by execute the command *.exit *in the truffle console to quit from truffle console.\nIn the truffle console, let’s try to call *hostGame function in the *Rockscissorspaper smart contract by execute the following command:\nRockScissorsPaper.deployed().then(function(instance){return instance.hostGame( web3.utils.asciiToHex(‘Host’),{from:’0x15b7b19813454ba6904d6b233a6505fbdbc13e28\u0026rsquo;,value:web3.utils.toWei(‘1’, ‘ether’)})})\nYou might be curious in our hostGame function, only require one parameter bytes32 _hostName. Why in this command, looks like we pass 3 parameters. Actually the following section in the command is to identify account to call this function and how much Ether we will pass to this function, since this function is payable.{from:’0x15b7b19813454ba6904d6b233a6505fbdbc13e28\u0026rsquo;,value:web3.utils.toWei(‘1’, ‘ether’)}\nNote: The account address you can get from ganache-cli console when you launch ganache-cli.\nAfter you execute this command, you should be able to see the similar result as following:\nNow let call getAvailableHostList function to see if the account *’0x15b7b19813454ba6904d6b233a6505fbdbc13e28\u0026rsquo; *hosted the game.\nExecute the following command in truffle console:\nRockScissorsPaper.deployed().then(function(instance){return instance.getAvailableHostList();})\nWe will see the following result as we expect.\nIt is time for other user to call the function registerAsAnOpponent to join this hosted game.\nRockScissorsPaper.deployed().then(function(instance){return instance.registerAsAnOpponent(0,web3.utils.asciiToHex(‘client’),{from:’0xd533b3651588072cf662814434976d0375b395e5\u0026rsquo;,value:web3.utils.toWei(‘1’, ‘ether’)})})\nThe result should be similar as following:\nLet start to play the game. The host “0x15b7b19813454ba6904d6b233a6505fbdbc13e28” will play scissors (1) by the following command:\nRockScissorsPaper.deployed().then(function(instance){return instance.playGame(0,1,{from:’0x15b7b19813454ba6904d6b233a6505fbdbc13e28\u0026rsquo;})})\nThe result will be similar as:\nNow it is time for client “0xd533b3651588072cf662814434976d0375b395e5” to play. The client would like to play paper (2):\nRockScissorsPaper.deployed().then(function(instance){return instance.playGame(0,2,{from:’0xd533b3651588072cf662814434976d0375b395e5\u0026rsquo;})})\nAfter both of players play the game, let’s call getGameInfo to check who is winner:\nRockScissorsPaper.deployed().then(function(instance){return instance.getGameInfo(0)})\nPer the result, we can see the host win.\nCongratulation! Now you know how to write the smart contract, and how to deploy and test it in truffle if you follow this serial tutorials from part -1 to part -3.\nIn the last article Part -4 , I will show you how to call solidity smart contract from web through web3.js. You cannot expect your users to use truffle to play Rock_Scissors _Paper game, right?:)\n"},{"title":"The Latest Ethereum Solidity Smart Contract Development Tutorial (Part -2) — Develop solidity","permalink":"https://eamstream.com/posts/ethereum-solidity-tutorial-part2/","summary":"On the previous tutorial (Part -1) — Solidity Smart Contract development environment setup for Visual Studio Code with Truffle framework, we learned how to setup our development environment and the high level of the requirement for rock-scissors-paper game which we are planning to build smart contract for. Now in this tutorial, we will start to write a solidity smart contract and test it in truffle.\nBefore you start the following section, please make sure you follow the Part -1to complete development environment setup.\n","content":"On the previous tutorial (Part -1) — Solidity Smart Contract development environment setup for Visual Studio Code with Truffle framework, we learned how to setup our development environment and the high level of the requirement for rock-scissors-paper game which we are planning to build smart contract for. Now in this tutorial, we will start to write a solidity smart contract and test it in truffle.\nBefore you start the following section, please make sure you follow the Part -1to complete development environment setup.\nAnd to be able to have better understand each step and the code in the following, I would like to encourage you to walk through the basic concept on Solidity and Truffle through the below official sites . Of course you would be able to walk through the following steps without knowledge of Truffle and Solidity, but you would only know how to do it, instead of why to it (I think this is more important than how).\n(1) Solidity: https://solidity.readthedocs.io/en/develop/index.html\n(2) Truffle: https://truffleframework.com/docs/truffle/overview\nIn the VS Code, open the folder which we create for the DAPP, for my case, it is C:\\DAPPTutorial. The folder currently is empty.\nNow we are ready to start our exciting solidity smart contract coding.\nStep-1: Create a bare Truffle project.\nTruffle provided some of example applications and project templates at Truffle Boxes which you can pull them to your local through truffle unbox command. But for our tutorial, I would like to start from a blank project template to let you have better understanding on the folder structure of Truffle.\nOpen a new terminal in VS Code, make sure the current folder is at the C:\\DAPPTutorial.\nType the following command and enter on this terminal:\ntruffle init\nAfter this command execute, you will find there are couple files and folders are created under the folder of DAPPTutorial.\nLet’s have a quick walk-through of this folder and file structure:\n(1) Folder “contracts ”— this folder is for smart contract solidity file.\n(2) File “Migrations.sol” under contracts folder — Truffle migrations enable us to “push” the smart contracts to the Ethereum blockchain (either local, tesnet or mainnet) and to set up necessary steps for linking contracts with other contracts as well as populate contracts with initial data. The Migrations.sol file can look any way you want it to, but it must conform to a fixed interface which looks like the interface created by the truffle init command. What you can do in those files is some advanced mangling of migrations, but it’s rarely needed.\n(3) Folder “migrations” — this folder is used to manage deployment script.\n(4) File “1_initial_migration.js” under migration folder— The same goes for the 1_initial_migration.js file. What it does is simply push the Migrations.sol file to the desired blockchain.\n(5) Folder “test” — this folder is for the files for smart contract testing purpose.\n(6)File “truffle-config.js” — This file is a Javascript file and can execute any code necessary to create your configuration. We will cover more detail on this file in the next step.\nStep-2: Modify truffle-config.js to connect to ganache\nAs mentioned before, the file truffle-config.js is used for the truffle configuration. Uncomment the following code snippet by removing “//” in truffle-config.js which will allow us to connect to ganache blockchain we launched locally in Part-1.\ndevelopment: {\nhost: “127.0.0.1”, // Localhost (default: none)\nport: 8545, // Standard Ethereum port (default: none)\nnetwork_id: “*”, // Any network (default: none)\n},\nMake sure you save this file after the change.\nStep-3: Start the coding for smart contract to meet the requirement of rock-scissors-paper game.\nIn the VS Code Explorer, click to select “contracts” folder, and click on new file button at the top right.\nIn the input box, type “Rockscissorspaper.sol” as our smart contract file name (sol is solidity file).\nLet’s have a quick review on the requirement for rock-scissors-paper game smart contract:\n(1) Two players for each game, one is host, other one is client.\n(2) Anyone can host a rock-scissors-paper game with certain stake and wait for client to join the game.\n(3) Player can view all of the hosted games and select to join one of the game as client player with the same stake as the host player.\n(4) Once client player join the game, both host player and client player can play the game by providing input of Rock, Scissors or Paper.\n(5) After both of host and client players provide the input, the smart contract will reveal the winner and transfer the both of the stakes to the winner after reducing certain percentage of commission.\nThe following are the code snippets along with the explanation.\npragma solidity \u0026gt;=0.4.21 \u0026lt;0.6.0;\nAll of solidity smart contract will start from this pragma to identify which version of the solidity will be compatible for the smart contract.\ncontract RockScissorsPaper {\n…\n}\nThe smart contract name “RockScissorsPaper” which we will create.\nenum BetValue\n{ //enum to list all of the values the player can put for the game\nRock,Scissor,Paper\n}\nenum GameStatus\n{ // enum for the status of the game\nInvalid,Hosted,Joined,Finished\n}\nstruct Player\n{ // structure to store player information\nbytes32 playerName;\naddress payable player;\nBetValue playerBetValue;\nbool isPlayed;\nbool isWon;\n}\nstruct Game\n{ // structure to store game information\nuint gameID;\nPlayer host;\nPlayer client;\nGameStatus status;\nuint betAmount;\n}\n//Pending withdrawls amount for the players\nmapping(address =\u0026gt; uint) public pendingWithdrawls;\n//The list of the games\nGame[] private gamesList;\n//The address of contract owner who can receive commission for finished game.\naddress payable private commissioner;\n//The commission percentage of the stake\nuint8 private commissionPercent;\n//To keep acculated commission amount\nuint private totalCommission;\n//Total number of the hosted games\nuint private hostNumber;\nThe above code snippet is the data structure of this smart contract. They are used to keep the data of smart contract.\nmodifier verifyGame(uint _gameID) {\nrequire(gamesList.length\u0026gt;_gameID,’The game is not exist’);\n_;\n}\nYou can think of function modifier as an extension of a function. Modifier code will run first when assigned by a function. “_;” means to return the flow of execution to the original function code. Function modifier is mainly used to check a condition prior to executing the function. So you could re-use the same modifier in multiple functions if you are checking for the same condition. It reduces code redundancy.\nconstructor(uint8 _commissionPercent) public\n{ // contract constructor\ncommissioner = msg.sender;\ncommissionPercent=_commissionPercent;\nhostNumber=0;\n}\nThe constructor will be executed when the smart contract is deployed. Usually we use it to initialize some variables.\nfunction hostGame(bytes32 _hostName) public payable returns(uint)\n{ //host a game and return the game id\nrequire(msg.value\u0026gt;0,’Bet amount need to more than 0\u0026rsquo;);\nrequire(_hostName.length\u0026gt;0,’The name cannot empty’);\nPlayer memory hostPlayer;\nhostPlayer.player=msg.sender;\nhostPlayer.playerName=_hostName;\nhostPlayer.isPlayed=false;\nGame memory game;\nuint gameID;\ngameID=gamesList.length;\ngame.gameID=gameID;\ngame.host=hostPlayer;\ngame.betAmount=msg.value;\ngame.status=GameStatus.Hosted;\ngamesList.push(game);\npendingWithdrawls[msg.sender]+=msg.value;\nhostNumber+=1;\nreturn gameID;\n}\nThis function is used to allow the user to host a game and return the new game’s id.\nfunction registerAsAnOpponent(uint _gameID, bytes32 _clientName) public payable verifyGame(_gameID)\n{ // Register hosted game _gameID as oppenent (client player)\nrequire(gamesList[_gameID].client.player==address(0),’The game was occupied’);\nrequire(gamesList[_gameID].status==GameStatus.Hosted,’The game status is not allowed to join’);\nrequire(msg.value==gamesList[_gameID].betAmount,’You need to bet for the same amount as host’);\nrequire(_clientName.length\u0026gt;0,’The name cannot empty’);\nPlayer memory clientPlayer;\nclientPlayer.player=msg.sender;\nclientPlayer.playerName=_clientName;\nclientPlayer.isPlayed=false;\ngamesList[_gameID].client=clientPlayer;\ngamesList[_gameID].status=GameStatus.Joined;\npendingWithdrawls[msg.sender]+=msg.value;\nhostNumber-=1;\n}\nThis function will allow user to choose a hosted game to join as client player.\nfunction playGame(uint _gameID, uint8 _playValue) public payable verifyGame(_gameID)\n{ // Player provide input (rock, scissors or paper) for the game _gameID\n// Will reveal game result if both of the player are provide the input\nrequire(gamesList[_gameID].status==GameStatus.Joined,’No one join the game yet’);\nrequire(msg.sender == gamesList[_gameID].client.player || msg.sender ==gamesList[_gameID].host.player,’You are hacking to the game!!!!!!!!!’);\nrequire(_playValue\u0026gt;=0 \u0026amp;\u0026amp; _playValue\u0026lt;=2, ‘Wrong Bet input’);\nif(msg.sender == gamesList[_gameID].host.player)\n{\nif(!gamesList[_gameID].host.isPlayed)\n{\ngamesList[_gameID].host.isPlayed = true;\ngamesList[_gameID].host.playerBetValue=BetValue(_playValue);\n}\n} else\n{\nif(!gamesList[_gameID].client.isPlayed)\n{\ngamesList[_gameID].client.isPlayed = true;\ngamesList[_gameID].client.playerBetValue=BetValue(_playValue);\n}\n}\nif(gamesList[_gameID].host.isPlayed \u0026amp;\u0026amp; gamesList[_gameID].client.isPlayed)\n{\nint betResult=checkBetResult(gamesList[_gameID].host.playerBetValue,gamesList[_gameID].client.playerBetValue);\nif(betResult==1) //host win\n{\ngamesList[_gameID].host.isWon=true;\ngamesList[_gameID].client.isWon=false;\nendOfGame(_gameID,gamesList[_gameID].host.player,gamesList[_gameID].client.player);\n} else if (betResult==-1) //client win\n{\ngamesList[_gameID].host.isWon=false;\ngamesList[_gameID].client.isWon=true;\nendOfGame(_gameID,gamesList[_gameID].client.player,gamesList[_gameID].host.player);\n} else // equal\n{\ngamesList[_gameID].host.isPlayed=false;\ngamesList[_gameID].client.isPlayed=false;\n}\n}\n}\nThe playGame function will reveal game result if both of the player are provide the input.\nfunction getAvailableHostList() public view returns (bytes32[] memory,address[] memory, uint[] memory, uint[] memory)\n{\nbytes32[] memory hostNames=new bytes32;\naddress[] memory hostAddresses=new address;\nuint[] memory hostIDs=new uint;\nuint[] memory betAmounts=new uint;\nuint hostIndex=0;\nfor (uint index = 0; index \u0026lt; gamesList.length; index++)\n{\nGame memory game=gamesList[index];\nif(game.status==GameStatus.Hosted)\n{\nhostNames[hostIndex]=game.host.playerName;\nhostAddresses[hostIndex]=game.host.player;\nbetAmounts[hostIndex]=game.betAmount;\nhostIDs[hostIndex]=index;\nhostIndex+=1;\n}\n}\nreturn (hostNames,hostAddresses,hostIDs,betAmounts);\n}\nThis function will expose external application (for example, javascript) to get all of the available hosted game list.\n"},{"title":"The Latest Ethereum Solidity Smart Contract Development Tutorial (Part -1) — Develop Solidity","permalink":"https://eamstream.com/posts/ethereum-solidity-tutorial-part1-develop/","summary":"There is blossomed increasing blockchain development skills resource request in the job market in the last year (2018), and this trend is continuing in 2019. To increase your job opportunities if you are willing to embrace blockchain revolution, learning popular smart contract development technology such as solidity will arm yourself.\nThanks for many of selfless writers, there are a lot tutorials you can find through google. But since blockchain technology is still evolving, the related development tools / languages keep updating in months. If you are follow out of date articles to start your smart contract learning, I am pretty sure you will lose a lot of your hairs :). To save your hair, I write these serial tutorials to guide you how to develop smart contract in Solidity for a real use case, and more than that, you can learn some of the key technologies related to smart contract development, and the whole software development life cycle from requirement to production. You can get benefit from these articles whether you are developer or technical manager. Here are the highlights you will learn from these serial articles:\n","content":"There is blossomed increasing blockchain development skills resource request in the job market in the last year (2018), and this trend is continuing in 2019. To increase your job opportunities if you are willing to embrace blockchain revolution, learning popular smart contract development technology such as solidity will arm yourself.\nThanks for many of selfless writers, there are a lot tutorials you can find through google. But since blockchain technology is still evolving, the related development tools / languages keep updating in months. If you are follow out of date articles to start your smart contract learning, I am pretty sure you will lose a lot of your hairs :). To save your hair, I write these serial tutorials to guide you how to develop smart contract in Solidity for a real use case, and more than that, you can learn some of the key technologies related to smart contract development, and the whole software development life cycle from requirement to production. You can get benefit from these articles whether you are developer or technical manager. Here are the highlights you will learn from these serial articles:\nBasic concept of Ethereum Smart Contract. Hand-on experiment on Develop a real world smart contact use case in integral process from requirement to implementation in solidity language based on Ethereum blockchain: Rock Scissors Paper game Key points of the latest version solidity. The edge technologies or tools (such as Truffle, Visual Studio Code, GIT) along with blockchain to build entire smart contract solution. These serial tutorial is suitable to the readers who have basic concept of Ethereum blockchain, and the basic skill or hand-on experience on development with at least one language.\nThe following are of the serial tutorials I am planning to write:\n(1) (Part -1) — Solidity Smart Contract development environment setup for Visual Studio Code with Truffle framework\n(2) (Part -2) —Develop solidity smart contract in Truffle\n(3) (Part -3) — Compile, Deploy and Test solidity smart contract in Truffle\n(4) (Part -4) — Build Frontend html page with java script to connect to solidity smart contract ABI through Web3 and MetaMask\nThis article is for Part -1. I will publish part 2 , 3 \u0026amp; 4 in the near future.\nBefore we are getting start on technical section, let’s take quick look on what’s the requirement of this use case and why we need to use smart contract blockchain to solve this problem.\nI think most of the people know how to play rock-scissors-paper game (for the folks don’t know this game, please refer to wiki: https://en.wikipedia.org/wiki/Rock%E2%80%93paper%E2%80%93scissors).\nRock-Scissors-Paper Game\nAssume that you want to build a website to allow people to play this game. But how can you make sure your users trust you the website will not cheat them? Since it is impossible for both of the players to provide the input (Rock, Scissors or Paper) at the same time through internet, how can we build a solution to reveal the result base on the input from both of the players without being cheated (for example, the owner of the website can peep the competitor’s input). Yes, blockchain is the right solution to solve these trust problem. That is why most of the current DAPPs are occupied by gambling games in Ethereum and EOS ( of course DAPP is not the only purpose for gambling). Here are the key requirements / features we need to build a smart contract for this rock-scissors-paper game:\n(1) Two players for each game, one is host, other one is client.\n(2) Anyone can host a rock-scissors-paper game with certain stake and wait for client to join the game.\n(3) Player can view all of the hosted games and select to join one of the game as client player with the same stake as the host player.\n(4) Once client player join the game, both host player and client player can play the game by providing input of Rock, Scissors or Paper.\n(5) After both of host and client players provide the input, the smart contract will reveal the winner and transfer the both of the stakes to the winner after reducing certain percentage of commission.\nAll right, now we have requirement and good to start solidity smart contract coding. Hold on second, before we can really code, we need to setup our development environment. Let take an overview of technical stacks we gonna to use in this tutorial:\nOS: Windows 10\nIDE: Visual Studio Code 1.32.3\nTools / Packages:\n(1) Node.js 10.7.0 and NPM 6.1.0 (javascript package management)\nnpm is included as a recommended feature in Node.js installer. npm consists of a command line client that interacts with a remote registry. It allows users to consume and distribute JavaScript modules that are available on the registry.\n(2) Truffle v5.0.5\nTruffle is a development environment, testing framework and asset pipeline for Ethereum, aiming to make life as an Ethereum developer easier. It is one of the most widely used IDEs in the Ethereum community. Developers can use it to build and deploy DApps for testing purposes with many features that make it more attractive to users with a Web 3.0 dev background. It will include solidity language which is the language we are using for Ethereum smart contract development.\n(3) Ganache-cli v6.4.0\nGanache CLI is the latest version of TestRPC: a fast and customizable blockchain emulator. It allows you to make calls to the blockchain without the overheads of running an actual Ethereum node.\nPlease follow the below sequence to install and config the required tools for development environment. If your OS is different with Windows, please follow the installation instruction relate to your OS on the tools / packages website.\nInstall Node.js and npm Visit node.js website to download node.js and npm install package:\nSelect your OS related install package to download. Let’s choose Windows Installer (.msi) 64bit version to download and install it.\nInstall Visual Studio Code (VS Code) VS Code is a lite weight source code editor developed by Microsoft for Windows, Linux and macOS. It includes support for debugging, embedded Git control, syntax highlighting, intelligent code completion, snippets, and code refactoring. It can include new feature through install extensions.\nDownload VS Code from the below website for your OS: https://code.visualstudio.com/download\nIn my case, I download windows user installer 64 bit version. Install Visual Studio Code after download install file.\nSetup project folder in VS Code Open VS Code, click on “Open folder…” menu on the welcome window.\nCreate a new folder call “DAPPTutorial” folder under C drive and click select this folder button.\nInstall ganache-cli To install ganache-cli, you can use npm through command prompt window, or through terminal in VS Code. I will install it through VS Code terminal (for the rest of other javascript packages, if I don’t specify, will be installed through VS Code terminal).\nOpen a new terminal through menu Terminal -\u0026gt; New Terminal\nOn the terminal window, type the following command and enter:\nnpm install -g ganache-cli\nNotes: -g option is to install ganache-cli package globally in your current npm environment.\nAfter install successfully, type the following command to start ganache:\nganache-cli\nIt will launch a local Ethereum blockchain along with 10 accounts for development testing. And open a default local port 8545 for transaction.\nInstall Truffle Open a new split terminal through click split window button on the right top of terminal window.\nOn the new terminal window, type the following command and enter to install truffle:\nnpm install -g ganache-cli\nAfter install truffle, type the following command to see the version of truffle and related packages:\ntruffle version\nCongratulation, now your smart contract development environment is ready. I will walk your through on how to develop solidity smart contract to fulfill the requirement for the Rock-Scissors-Paper game in the next tutorial:\n(Part -2) — Develop solidity smart contract in Truffle\nPlease let me know if you have any issue / question on this tutorial.\nPlease don’t\n"},{"title":"Modify Maximo data through Restful API","permalink":"https://eamstream.com/posts/draft-modify-maximo-data-restful-api/","summary":"In my previous blog I introduced how to query Maximo data through Restful API, in this blog, I will show you how to modify (Create, Update, Delete) Maximo data through Restful API.\nYou can modify Maximo resources by using the HTTP PUT, POST, and DELETE methods with Restful API. The PUT, POST, and DELETE methods can be used to modify business object resources and object structure resources. However, the business rules of an object might prevent it from being updated by a REST API request. For example, a DELETE request on a work order resource might fail if the business object validations prevent deletions because of the current state of the work order.\n","content":"In my previous blog I introduced how to query Maximo data through Restful API, in this blog, I will show you how to modify (Create, Update, Delete) Maximo data through Restful API.\nYou can modify Maximo resources by using the HTTP PUT, POST, and DELETE methods with Restful API. The PUT, POST, and DELETE methods can be used to modify business object resources and object structure resources. However, the business rules of an object might prevent it from being updated by a REST API request. For example, a DELETE request on a work order resource might fail if the business object validations prevent deletions because of the current state of the work order.\nIn reality, most of the integrations require using Object Structure (OS) instead of Maximo Business Object (MBO). The following practice will demonstrate on how to create an OS in Maximo, and use this OS to create and update Maximo data.\nAssume we have the business requirement that an external system will call Maximo restful API to create and update asset along with meters. We can create an object structure MXRAsset in Maximo to hold the structure as following:\nAs above picture, Asset is the primary MBO, Meter is child MBO. We can post data to Maximo restful API through postman. You can download postman through https://www.postman.com/downloads/\nOpen a new tab in postman\n"},{"title":"The Latest Ethereum Solidity Smart Contract Development Tutorial (Part -4) — Build Frontend html","permalink":"https://eamstream.com/posts/draft-ethereum-solidity-tutorial-part4-build-frontend/","summary":"In previous serial articles, you learned how to setup development environment, built a solidity smart contract in truffle, and deployed it to a testing blockchain network ganache. You can refer to the following links for the previous sessions:\n(Part -1) — Solidity Smart Contract development environment setup for Visual Studio Code with Truffle framework\n(Part -2) — Develop solidity smart contract in truffle\n(Part -3) — Compile, Deploy and Test solidity smart contract in Truffle\n","content":"In previous serial articles, you learned how to setup development environment, built a solidity smart contract in truffle, and deployed it to a testing blockchain network ganache. You can refer to the following links for the previous sessions:\n(Part -1) — Solidity Smart Contract development environment setup for Visual Studio Code with Truffle framework\n(Part -2) — Develop solidity smart contract in truffle\n(Part -3) — Compile, Deploy and Test solidity smart contract in Truffle\nNow it is time for us to learn how to interact with our solidity smart contract in javascript through Web3.js.\nBefore we get into the detail, we might need to understand couple concepts:\nABI: The ABI, Application Binary Interface, is basically how you call functions in a contract and get data back.\nAn ABI determines such details as how functions are called and in which binary format information should be passed from one program component to the next…\nAn Ethereum smart contract is bytecode deployed on the Ethereum blockchain. There could be several functions in a contract. An ABI is necessary so that you can specify which function in the contract to invoke, as well as get a guarantee that the function will return data in the format you are expecting.\nFrom Ethereum’s ABI specification, an example:\ncontract Foo { function bar(real[2] xy) {} function baz(uint32 x, bool y) returns (bool r) { r = x \u0026gt; 32 || y; } function sam(bytes name, bool z, uint[] data) {} } If we wanted to call baz with the parameters 69 and true, we would pass 68 bytes in total, which can be broken down into:\n0xcdcd77c0: the Method ID. This is derived as the first 4 bytes of the Keccak-256 hash of the ASCII form of the signature baz(uint32,bool). 0x0000000000000000000000000000000000000000000000000000000000000045: the first parameter, a uint32 value 69 padded to 32 bytes 0x0000000000000000000000000000000000000000000000000000000000000001: the second parameter — boolean true, padded to 32 bytes\nThe 68 bytes is what would be specified in the data field of a transaction: a security note on that is here. (To summarise, be careful what you put in the data field, because it can have unintended, possibly malicious side-effects when passing it to the calling contract.)\nTo avoid a common pitfall **when deriving the Method ID, the canonical types must be used, for example uint256 instead of **uint.\nWeb3.js: The web3.js library is a collection of modules which contain specific functionality for the Ethereum ecosystem. Using a higher-level library such as web3.js abstracts most of these details, but the ABI in JSON format still needs to be provided to web3.js. I will show you how to get ABI in JSON format later for the smart contract Rockscissorspaper we built before. Note: the ABI is an abstraction that is not part of the core Ethereum protocol. Anyone can define their own ABI for their contracts, and any callers of such contracts would have to comply with that ABI to get meaningful results. However, it is simpler for all developers to use Solidity, Serpent, and web3.js which all comply with the ABI above.\nNow let’s start to build html and javascript files to call Rockscissorspaper smart contract to play rock, scissors and paper game.\nWe gotten to build the following front end files in a new folder web:\n"}]