IBM Support

Logging data in Maximo with a Raspberry PI using Node-Red.

Technical Blog Post


Abstract

Logging data in Maximo with a Raspberry PI using Node-Red.

Body

A while ago I wrote a blog about using the BeagleBone to log data into Maximo, /support/pages/node/1131909

Since then I took a class about IOT and Bluemix that involved a Raspberry PI, https://www.coursera.org/learn/developer-iot

The class uses a graphical programming language called Node-Red that is running on the Raspberry PI and can be accessed through a browser. The Node-Red programming language was developed by IBM specifically for IOT and is easy to learn but still very powerful. The Raspberry PI used in the training comes with a so called Sense Hat that can sense temperature, humidity and pressure.

I wanted to do a similar example but using the Raspberry PI and a different application in Maximo so I came up with a scenario that logs the temperature against a location in Maximo. I'm using the Temperature sensor on the Sense Hat to read the temperature and then inserts it into Maximo as a temperature reading against a Location. The previous example used the REST services in Maximo and this example will use them as well. So, in Maximo, we need a new Location and Object Structure.

image

 

 

 

 

 

 

 

 

 

 

 

 

 

If you are not using the Maxdemo Database, you might not have TEMP-C Meter predefined, here is how it looks like:

image

 

 

And finally the Object Structure,

image

 

 

I'm not going to explain the Node-Red programming language, the course from Coursera does a good job introducing the language and is highly recommended.

The program itself looks like,

 

image

 

 

 

 

The top process reads the temperature from the Sense hat and store it internally, the node "Sense Hat" has been set to only report the Environmental events and we only store the Temperature. The code in the Functional node looks like this,

  // Save the incomming temperature in a variable that can be used in the flow.  // The Sense hat is reporting temperature much faster than we want to log in Maximo.  flow.set("temp",msg.payload.temperature);  return msg;

It just store the incoming temperature in a variable so that the bottom process can grab it when ready to log it in Maximo.

The bottom process starts with an inject node, currently a timestamp. Even though the time stamp is currently ignored, it could be used to update the time stamp in Maximo as well, currently we let the Maximo server generate it's own time stamp. You can also set the inject node to insert values on a regular basis, for example every 5 minutes or once per hour. The second is a function node that generates the REST GET request,

  // Set initial parameters.  maximoIP = "192.168.0.19";  maximoUser = "wilson";  maximoPassword = "wilson";  maximoLoc = "PISTORAGE";  maximoMetername = "TEMP-C";    // Save parameters for other node.  msg.maximoIP = maximoIP  msg.maximoUser = maximoUser  msg.maximoPassword = maximoPassword  msg.maximoMetername = maximoMetername    // Greate URL  msg.url = "http://" + maximoIP + "/maxrest/rest/mbo/locations?_lid=" + maximoUser + "&_lpwd=" + maximoPassword + "&_compact=true&_format=json&location=" + maximoLoc;  msg.method="GET"    // Pass along Message.  return msgFirst we set some variables, here is where you change those to your own settings and we also add these variables to the message passed down the process for future nodes.  

The important part is the msg.url, it build a REST call that let us query the current ID and SITEID for the Location. We bascially end up with,

  http://MaximoServerHostName/maxrest/rest/mbo/locations?_lid=wilson&_lpwd=wilson&_compact=true&_format=json&assetnum=PISTORAGE

This will return a JSON data structure that we can parse in Node-Red, Node-Red uses Node.js and the JSON structure is native to the language.

The Node marked "Maximo REST GET" is a HTTP Request Node that takes care of sending the REST request to your Maximo host.

The next Node on the top, "Maximo URL to add Temperature" grabs the result from the REST request and constructs the URL that adds the temperature Data,

  // Get Location Id and Site from Maximo response.  locationid = msg.payload.LOCATIONSMboSet.LOCATIONS[0].LOCATIONSID;  siteid = msg.payload.LOCATIONSMboSet.LOCATIONS[0].SITEID;    //Get saved parameters.  maximoIP = msg.maximoIP;  maximoUser = msg.maximoUser;  maximoPassword = msg.maximoPassword;  maximoMetername = msg.maximoMetername;    // Get Temperature from Sense Hat that was stored in the Flow variable. If there in none, return zero.  temperature = flow.get('temp') || 0;    // Construct URL to send data.  msg.url="http://" + maximoIP + "/maxrest/rest/os/pitemp/" + locationid + "?_lid=" + maximoUser + "&_lpwd=" + maximoPassword + "&_compact=true&_format=json" +  "&locationmeter.id1.metername=" + maximoMetername +  "&locationmeter.id1.measurement.id2.measurementvalue=" + temperature +  "&locationmeter.id1.measurement.id2.siteid=" + siteid;  msg.method="POST";  return msg;

First we get the result from the precious REST call, the parameters passed along earlier and the temperature. Then we construct a URL such as,

  http://MaximoServerHostName/maxrest/rest/os/pitemp/123?_lid=wilson&_lpwd=wilson&_compact=true&_format=json&locationmeter.id1.metername=TEMP-C&locationmeter.id1.measurement.id2.measurementvalue=29.95&locationmeter.id1.measurement.id2.siteid=BEDFORD

Where 123 is the unique ID of your Location and BEDFORD is the SiteID that was returned from the previous REST query, we also add Username, password and metername passed along earlier. The temperature 29.95 is an example reading from the Sense Hat. The last HTTP request node then POST this URL to Maximo which will insert the temperature measurement. I set the Inject node to insert a value each minute and here is the result,

image

 

 

The other node marked "Display Temperature sent to Maximo" displays the temperature on the 8x8 LED matrix by scrolling a message across it,

  // Settings for display  msg.color="#3344aa"  msg.background="off"  msg.speed=3    // Get Temperature  var temp = flow.get('temp')||0;    // Display message.  msg.payload="Sending " + temp + " to Maximo.";  return msg;

The message is constructed with the  temperature sent to Maximo and then scrolled across the LED Matrix.

 

Node-Red supports copy/paste of the code so here is the full code for the two processes,

  [{"id":"8da1c69e.22a27","type":"function","z":"8e5f4c8d.20ee68","name":"Display temperature sent to Maximo","func":"// Settings for display\nmsg.color=\"#3344aa\"\nmsg.background=\"off\"\nmsg.speed=3\n\n// Get Temperature\nvar temp = flow.get('temp')||0;\n\n// Display message.\nmsg.payload=\"Sending \" + temp + \" to Maximo.\";\nreturn msg;","outputs":1,"noerr":0,"x":950,"y":200,"wires":[["22827997.c25e76"]]},{"id":"9ccce53f.cc14d8","type":"http request","z":"8e5f4c8d.20ee68","name":"Maximo REST GET","method":"use","ret":"obj","url":"","tls":"","x":640,"y":140,"wires":[["806d82a8.4cda4","8da1c69e.22a27"]]},{"id":"a8405609.e43d78","type":"inject","z":"8e5f4c8d.20ee68","name":"","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"x":100,"y":140,"wires":[["7246bf2e.48f2d"]]},{"id":"9d2294ed.512e08","type":"http request","z":"8e5f4c8d.20ee68","name":"Maximo REST POST","method":"use","ret":"obj","url":"","tls":"","x":1200,"y":140,"wires":[[]]},{"id":"aae8cfc0.c9a84","type":"rpi-sensehat in","z":"8e5f4c8d.20ee68","name":"","motion":false,"env":true,"stick":false,"x":90,"y":40,"wires":[["78f493e6.289b9c"]]},{"id":"78f493e6.289b9c","type":"function","z":"8e5f4c8d.20ee68","name":"Set Flow temp variable to temperature reading from Sense Hat.","func":"// Save the incomming temperature in a variable that can be used in the flow.\n// The Sense hat is reporting temperature much faster than we want to log in Maximo.\nflow.set(\"temp\",msg.payload.temperature);\nreturn msg;","outputs":1,"noerr":0,"x":430,"y":40,"wires":[[]]},{"id":"806d82a8.4cda4","type":"function","z":"8e5f4c8d.20ee68","name":"Maximo URL to add Temperature","func":"// Get Location Id and Site from Maximo response.\nlocationid = msg.payload.LOCATIONSMboSet.LOCATIONS[0].LOCATIONSID;\nsiteid = msg.payload.LOCATIONSMboSet.LOCATIONS[0].SITEID;\n\n//Get saved parameters.\nmaximoIP = msg.maximoIP;\nmaximoUser = msg.maximoUser;\nmaximoPassword = msg.maximoPassword;\nmaximoMetername = msg.maximoMetername;\n\n// Get Temperature from Sense Hat that was stored in the Flow variable. If there in none, return zero.\ntemperature = flow.get('temp') || 0;\n\n// Construct URL to send data.\nmsg.url=\"http://\" + maximoIP + \"/maxrest/rest/os/pitemp/\" + locationid + \"?_lid=\" + maximoUser + \"&_lpwd=\" + maximoPassword + \"&_compact=true&_format=json\" + \n\"&locationmeter.id1.metername=\" + maximoMetername + \n\"&locationmeter.id1.measurement.id2.measurementvalue=\" + temperature +\n\"&locationmeter.id1.measurement.id2.siteid=\" + siteid;\nmsg.method=\"POST\";\nreturn msg;","outputs":1,"noerr":0,"x":920,"y":140,"wires":[["9d2294ed.512e08"]]},{"id":"7246bf2e.48f2d","type":"function","z":"8e5f4c8d.20ee68","name":"Maximo URL to query Location ID.","func":"// Set initial parameters.\nmaximoIP = \"192.168.0.19\";\nmaximoUser = \"wilson\";\nmaximoPassword = \"wilson\";\nmaximoLoc = \"PISTORAGE\";\nmaximoMetername = \"TEMP-C\";\n\n// Save parameters for other node.\nmsg.maximoIP = maximoIP\nmsg.maximoUser = maximoUser\nmsg.maximoPassword = maximoPassword\nmsg.maximoMetername = maximoMetername\n\n// Greate URL\nmsg.url = \"http://\" + maximoIP + \"/maxrest/rest/mbo/locations?_lid=\" + maximoUser + \"&_lpwd=\" + maximoPassword + \"&_compact=true&_format=json&location=\" + maximoLoc;\nmsg.method=\"GET\"\n\n// Pass along Message.\nreturn msg;","outputs":1,"noerr":0,"x":360,"y":140,"wires":[["9ccce53f.cc14d8"]]},{"id":"22827997.c25e76","type":"rpi-sensehat out","z":"8e5f4c8d.20ee68","name":"","x":1210,"y":200,"wires":[]}]

Here is the Raspberry PI in action,

image

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Enjoy...

 

[{"Business Unit":{"code":"BU059","label":"IBM Software w\/o TPS"},"Product":{"code":"SSLKT6","label":"IBM Maximo Asset Management"},"Component":"","Platform":[{"code":"PF025","label":"Platform Independent"}],"Version":"","Edition":"","Line of Business":{"code":"LOB59","label":"Sustainability Software"}}]

UID

ibm11130667