Technology Blogs by Members
Explore a vibrant mix of technical expertise, industry insights, and tech buzz in member blogs covering SAP products, technology, and events. Get in the mix!
cancel
Showing results for 
Search instead for 
Did you mean: 
ferrygun18
Contributor
In this blog, we'll learn how to send the IoT data to the IOTA Tangle with SAP HANA XSA and display it real time in SAP Analytics Cloud.

In order to build this app, you need to have the following components:

  • IOTA Tangle (www.iota.org)

  • SAP HANA XS Advanced (XSA)

  • NodeJS

  • Socket.IO

  • SAP Analytics Cloud


IOTA


IOTA is an open source distributed ledger called Tangle that is developed for Internet of Things (IoTs) or Machine to Machine (M2M) economy. But its technology is also well suited for payments between humans as well. You can read more information on iota.org.

Scenarios


In this tutorial, we will create simple scenarios to send the IoT temperature data to the IOTA Tangle using Masked Authentication Messaging (MAM) which means that:

  • The message is encrypted (Masked)

  • The message is confirmed to be coming from the device (Authenticated).

  • A continuous message stream is created on the Tangle and will continue until the device stop publishing the data (Messaging).


IOTA MAM makes possible for the the devices to encrypt the data streams and securely store those in Tangle each on separate address and only authorized parties that will be able to read and parse the message streams. Only those with the right channel IDs (The channel ID is also called the root) can get access to the message.

There are different type of privacy modes when we publish the message with MAM to Tangle:

  • Public mode: Anyone has access to the message.

  • Private mode: Only the publisher has access to the message.

  • Restricted mode: Anyone with a side_key has access to the message. The message is encrypted by the side_key. To decrypt, use the same side_key.




In a nutshell, we will create the following parts:

  • Sensor Device: NodeJS app mam_publish.js to emulate the sensor temperature data reading and send the data in MAM to Tangle with restricted mode. We will use the side_key to encrypt and decrypt the data.

  • NodeJS & HTML App in HANA XSA:
    NodeJS app to receive the stream of data from Tangle and send to HTML app via websocket, socket.io that we installed in HANA XSA.
    HTML app to embed the SAP Analytics Cloud in an iFrame and receive the stream of data from NodeJS App and send to SAP Analytics Cloud.

  • SAP Analytics Cloud Analytics Application.
    To display the temperature data in real time without need to refresh the browser.


Sensor Device



  • Install the required libraries:
    npm install moment iota.lib.js​


  • Create NodeJS app mam_publish.js to emulate the sensor reading and publish the data to Tangle.
    /*
    Author: Robert Lie (mobilefish.com)

    The mam_publish.js file publishes random generated numbers on the tangle using MAM.
    This file will work on a computer or Raspberry Pi.
    The published data can be viewed using the mam_receive.js file or
    https://www.mobilefish.com/services/cryptocurrency/mam.html (Select option: Data receiver)

    Usage:
    1) You can change the default settings: MODE, SIDEKEY, SECURITYLEVEL or TIMEINTERVAL
    If you do, make the same changes in mam_receive.js file.
    2) Start the app: node mam_publish.js

    More information:
    https://www.mobilefish.com/developer/iota/iota_quickguide_raspi_mam.html
    */

    const Mam = require('./lib/mam.client.js');
    const IOTA = require('iota.lib.js');
    const moment = require('moment');
    const iota = new IOTA({ provider: 'https://node.deviceproof.org' });

    const MODE = 'restricted'; // public, private or restricted
    const SIDEKEY = 'mysecret'; // Enter only ASCII characters. Used only in restricted mode
    const SECURITYLEVEL = 3; // 1, 2 or 3
    const TIMEINTERVAL = 30; // seconds

    // Initialise MAM State
    let mamState = Mam.init(iota, undefined, SECURITYLEVEL);

    // Set channel mode
    if (MODE == 'restricted') {
    const key = iota.utils.toTrytes(SIDEKEY);
    mamState = Mam.changeMode(mamState, MODE, key);
    } else {
    mamState = Mam.changeMode(mamState, MODE);
    }

    // Publish data to the tangle
    const publish = async function(packet) {
    // Create MAM Payload
    const trytes = iota.utils.toTrytes(JSON.stringify(packet));
    const message = Mam.create(mamState, trytes);

    // Save new mamState
    mamState = message.state;
    console.log('Root: ', message.root);
    console.log('Address: ', message.address);

    // Attach the payload.
    await Mam.attach(message.payload, message.address);

    return message.root;
    }

    const generateJSON = function() {
    // Generate some random numbers simulating sensor data
    const data = Math.floor((Math.random()*89)+10);
    const dateTime = moment().utc().format('DD/MM/YYYY hh:mm:ss');
    const json = {"data": data, "dateTime": dateTime};
    return json;
    }

    const executeDataPublishing = async function() {
    const json = generateJSON();
    console.log("json=",json);

    const root = await publish(json);
    console.log(`dateTime: ${json.dateTime}, data: ${json.data}, root: ${root}`);
    }

    // Start it immediately
    executeDataPublishing();

    setInterval(executeDataPublishing, TIMEINTERVAL*1000);




SAP HANA XSA


Setup Project

  • Logon to SAP HANA XSA Web IDE and create new project from template then click Next to continue.

  • Give a project name ziota and click Next to continue.

  • On this screen, just click Next to continue.

  • Set Service (srv) and Database (db) to Not included. We will add the NodeJS module later. Click Next to continue.

  • On the confirmation page, click Finish to complete the setup.

  • You will see the ziota project created in the workspace.


Add NodeJS Module

We will create the NodeJS app in HANA XSA.

  • Right click on the ziota project and select New > Node.js Module.

  • Give a module name srv and click Next to continue.

  • Don't tick the Enable XSJS support. Click Next to continue.

  • Click Finish to complete.

  • Now you should see the srv folder.

  • Open server.js in srv folder and replace with the following codes:
    /*eslint no-console: 0, no-unused-vars: 0, no-undef:0, no-process-exit:0*/
    /*eslint-env node, es6 */
    "use strict";
    const port = process.env.PORT || 3000;
    const server = require("http").createServer();

    const cds = require("@sap/cds");
    //Initialize Express App for XSA UAA and HDBEXT Middleware
    const xsenv = require("@sap/xsenv");
    const passport = require("passport");
    const xssec = require("@sap/xssec");
    const xsHDBConn = require("@sap/hdbext");
    const express = require("express");
    global.__base = __dirname + "/";

    //Iota
    const Mam = require('./lib/mam.client.js');
    const IOTA = require('iota.lib.js');
    const iota = new IOTA({
    provider: 'https://node.deviceproof.org'
    });

    const MODE = 'restricted'; // public, private or restricted
    const SIDEKEY = 'mysecret'; // Enter only ASCII characters. Used only in restricted mode

    let root;
    let key;
    let Socket = null;

    //logging
    var logging = require("@sap/logging");
    var appContext = logging.createAppContext();

    //Initialize Express App for XS UAA and HDBEXT Middleware
    var app = express();

    //Compression
    app.use(require("compression")({
    threshold: "1b"
    }));

    //Helmet for Security Policy Headers
    const helmet = require("helmet");
    app.use(helmet());
    app.use(helmet.contentSecurityPolicy({
    directives: {
    defaultSrc: ["'self'"],
    styleSrc: ["'self'", "sapui5.hana.ondemand.com"],
    scriptSrc: ["'self'", "sapui5.hana.ondemand.com"]
    }
    }));
    // Sets "Referrer-Policy: no-referrer".
    app.use(helmet.referrerPolicy({
    policy: "no-referrer"
    }));

    passport.use("JWT", new xssec.JWTStrategy(xsenv.getServices({
    uaa: {
    tag: "xsuaa"
    }
    }).uaa));
    app.use(logging.middleware({
    appContext: appContext,
    logNetwork: true
    }));
    app.use(passport.initialize());
    app.use(
    passport.authenticate("JWT", {
    session: false
    })
    );

    // Initialise MAM State
    let mamState = Mam.init(iota);

    // Set channel mode
    if (MODE == 'restricted') {
    key = iota.utils.toTrytes(SIDEKEY);
    mamState = Mam.changeMode(mamState, MODE, key);
    } else {
    mamState = Mam.changeMode(mamState, MODE);
    }

    // Receive data from the tangle
    const executeDataRetrieval = async function(rootVal, keyVal) {
    let resp = await Mam.fetch(rootVal, MODE, keyVal, function(data) {
    let json = JSON.parse(iota.utils.fromTrytes(data));

    Socket.emit('client_data', {'dateTime': json.dateTime, 'data': json.data})
    console.log(`dateTime: ${json.dateTime}, data: ${json.data}`);
    });

    executeDataRetrieval(resp.nextRoot, keyVal);
    }

    app.get("/node", (req, res) => {
    var root = req.query.root;
    console.log(root);
    executeDataRetrieval(root, key);

    res.send("Use the root:" + root);
    });

    //Start the Server
    server.on("request", app);

    // use socket.io
    var io = require('socket.io').listen(server);
    // define interactions with client
    io.sockets.on('connection', function (socket) {
    Socket = socket;
    });

    //Start the Server
    server.listen(port, function () {
    console.info(`HTTP Server: ${server.address().port}`);
    });​


  • We include the iota libraries and define the iota provider from Devnet https://node.deviceproof.org.

  • We will use the restricted mode with sidekey to publish the data to Tangle.

  • We subscribe to channel ID (root) to receive the stream of data from Tangle and send to HTML app via websocket.

  • Open package.json, we will install the required libraries for iota: iota.lib.js and socket.io: socket.io & socket.io-client.
    Replace with the following codes:
    {
    "name": "serve",
    "description": "Generated from ../package.json, do not change!",
    "version": "1.0.0",
    "dependencies": {
    "@sap/cds": "^3.10.0",
    "express": "^4.17.1",
    "@sap/xssec": "^2.1.17",
    "@sap/xsenv": "^2.0.0",
    "hdb": "^0.17.0",
    "@sap/hdbext": "^6.0.0",
    "@sap/hana-client": "^2.4.139",
    "@sap/textbundle": "latest",
    "@sap/logging": "^5.0.1",
    "@sap/audit-logging": "^3.0.0",
    "nodemailer": "^6.2.1",
    "passport": "~0.4.0",
    "async": "^3.0.1",
    "ws": "^7.0.0",
    "accept-language-parser": "latest",
    "node-xlsx": "^0.15.0",
    "node-zip": "~1.1.1",
    "xmldoc": "~1.1.2",
    "winston": "^3.2.1",
    "body-parser": "^1.19.0",
    "elementtree": "latest",
    "then-request": "latest",
    "compression": "~1.7",
    "helmet": "^3.18.0",
    "iota.lib.js": "^0.4.7",
    "socket.io": "^2.2.0",
    "socket.io-client": "^2.2.0"
    },
    "engines": {
    "node": "^8.9",
    "npm": "^6"
    },
    "devDependencies": {},
    "scripts": {
    "postinstall": "cds build/all --project .. --clean",
    "start": "node server.js"
    },
    "i18n": {
    "folders": [
    "_i18n"
    ]
    },
    "cds": {
    "data": {
    "driver": "hana"
    }
    }
    }​


  • Create a folder lib in srv and copy mam.client.js from https://github.com/ferrygun/ziota/blob/master/srv/lib/mam.client.js.


Add Web Module

We will create the HTML App in HANA XSA.

  • Right click on the ziota project and select New > Basic HTML5 Module.

  • Give a module name web. Click Next to continue.

  • Click Finish to complete.

  • Now you should see the web folder.

  • Open index.html and replace the content with the following codes:
    <html>
    <title>IOTA Tangle with SAP HANA XSA and Cloud Analytics</title>
    <body>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
    <script src="/socket.io/socket.io.js"></script>
    <script>
    function bindEvent(element, eventName, eventHandler) {
    if (element.addEventListener){
    element.addEventListener(eventName, eventHandler, false);
    } else if (element.attachEvent) {
    element.attachEvent('on' + eventName, eventHandler);
    }
    }

    var socket = io.connect();

    var iframeSource = 'REPLACE_WITH_SAP_ANALYTICS_CLOUD_APP_URL';
    // Create the iframe
    var iframe = document.createElement('iframe');
    iframe.setAttribute('src', iframeSource);
    iframe.setAttribute('id', 'the_iframe');
    iframe.setAttribute('frameborder', 0);
    iframe.setAttribute('style', 'overflow: hidden; height: 100%; width: 100%; position: absolute;');

    document.body.appendChild(iframe);

    // Send a message to the child iframe
    var iframeEl = document.getElementById('the_iframe');
    // Send a message to the child iframe
    var sendMessage = function(msg) {
    // Make sure you are sending a string, and to stringify JSON
    iframeEl.contentWindow.postMessage(msg, '*');
    };


    // Listen to message from child window
    bindEvent(window, 'message', function (e) {
    console.log(e.data);
    });

    socket.on('client_data', function(data){
    console.log(data.data);
    var temperature = data.data.toString();
    sendMessage(temperature);
    });
    </script>
    </body>
    </html>​


  • We need to get the SAP Analytics Cloud App URL later and update the variable iframeSource.

  • Open xs-app.json and replace with the following codes:
    {
    "welcomeFile": "index.html",
    "authenticationMethod": "route",
    "routes": [{
    "source": "/node(.*)",
    "destination": "srv_api",
    "csrfProtection": true,
    "authenticationType": "none"
    },{
    "source": "/socket.io(.*)",
    "destination": "srv_api",
    "csrfProtection": true,
    "authenticationType": "none"
    }]
    }​



Update mta.yaml and xs-security.json

  • Open mta.yaml and replace with the following codes:
    ID: ziota
    _schema-version: "2.1"
    version: 0.0.1
    modules:
    - name: srv
    type: nodejs
    path: srv
    parameters:
    memory: 512M
    disk-quota: 256M
    provides:
    - name: srv_api
    properties:
    url: '${default-url}'
    requires:
    - name: zearnpfe-uaa

    - name: web
    type: html5
    path: web
    requires:
    - name: zearnpfe-uaa
    - name: srv_api
    group: destinations
    properties:
    name: srv_api
    url: '~{url}'
    forwardAuthToken: true

    resources:
    - name: zearnpfe-uaa
    type: com.sap.xs.uaa-space
    parameters:
    config-path: ./xs-security.json



    You need to adjust xsuaa parameter accordingly.

  • Create xs-security.json in the root folder and insert the following codes:
    {
    "xsappname": "ziota",
    "scopes": [{
    "name": "$XSAPPNAME.Display",
    "description": "display"
    }, {
    "name": "$XSAPPNAME.Create",
    "description": "create"
    }, {
    "name": "$XSAPPNAME.Edit",
    "description": "edit"
    }, {
    "name": "$XSAPPNAME.Delete",
    "description": "delete"
    }, {
    "name": "$XSAPPNAME.DataGenerator",
    "description": "data generator"
    }, {
    "name": "xs_authorization.read",
    "description": "Read authorization information from UAA"
    }, {
    "name": "xs_authorization.write",
    "description": "Write authorization information to UAA"
    }, {
    "name": "$XSAPPNAME.ODATASERVICEUSER",
    "description": "Enter"
    }, {
    "name": "$XSAPPNAME.ODATASERVICEADMIN",
    "description": "Enter"
    }],
    "attributes": [{
    "name": "client",
    "description": "Session Client",
    "valueType": "int"
    }, {
    "name": "country",
    "description": "country",
    "valueType": "s"
    }],
    "role-templates": [{
    "name": "Viewer",
    "description": "View all records",
    "scope-references": [
    "$XSAPPNAME.Display"
    ],
    "attribute-references": [
    "client", "country"
    ]
    }, {
    "name": "Editor",
    "description": "Edit and Delete records",
    "scope-references": [
    "$XSAPPNAME.Create",
    "$XSAPPNAME.Edit",
    "$XSAPPNAME.Delete",
    "$XSAPPNAME.Display",
    "$XSAPPNAME.DataGenerator",
    "$XSAPPNAME.ODATASERVICEUSER",
    "$XSAPPNAME.ODATASERVICEADMIN"
    ],
    "attribute-references": [
    "client"
    ]
    }]
    }​



     


SAP Analytics Cloud



  • Logon to SAP Analytics Cloud and create Analytic Application.

  • In canvas, insert Numeric Point Indicator chart Chart_1.

  • Create script variable int1 to store the temperature data.

  • Create the calculated measure in the Chart_1.

  • On onPostMessageReceived, insert the following code to get the data stream from the child frame.
    int1 = ConvertUtils.stringToInteger(message);​


  • Click Save and click Run Analytics Application.

  • You should see the following screen. Copy the URL and update the variable iframeSource in index.html with this URL


Run the App



  • Run the Sensor Device app mam_publish.js and get the channel ID (root).


  • Run the NodeJS and HTML App in HANA XSA. Make sure they have both run succesfully.

  • At this moment, you will get the blank screen and if you open the developer console, you will get this error message.

  • To resolve this issue, go back to SAP Analytics Cloud and go to System > Administration.

  • Select App Integration, click Add a Trusted Origin then insert the HTML App URL and save it.

  • Now reopen the HTML App URL and you should see the screen without error.

  • Open a new web browser to subscribe to channel ID (root).

    https://<HTML_APP_URL>:<HTML_APP_PORT>/node?root=CHANNEL_ID​


  • Now you should see the stream of temperature data coming from sensor device to SAP Analytics Cloud in real time.


You can find the source codes on my Git and I hope you learn something new on Iota. Please let me know if you have any comments or questions.

References:


4 Comments
Labels in this area