How to use live data?

If you have set up historical data in the IXON Cloud, your IXrouter or IXagent will send PLC data to the IXON Cloud. A live data connection where your machine data will be sent every 0.5 second to your PC can be established using a WebSocket. Data retrieved through this connection will not be stored in the IXON Cloud. Please follow the steps below to establish a real-time WebSocket connection using the APIv2.

Step 1: Retrieve the required identifiers

To get started, you first need to retrieve an application ID, bearer token, company ID and agent ID. These values are necessary for proper authorisation and for the APIv2 to find the correct IXrouter or IXagent. This article explains how to request these values.

Step 2: Create a JWT Token

You need a JWT authorization token to create a live data stream. You can request a JWT Token using the AuthTokenDataList endpoint. You have to include the values you requested in step 1 in the request. You also have to set the expiration time for the token. The expiration time has to be between 1 minute (60 seconds) and 1 hour (3600 seconds). The example below contains the format for the request for a JWT Token and its response:

curl --request POST \
     --url '<<url>>:443/api/auth-tokens/data' \
     --header 'Api-Version: 2' \
     --header "Api-Application: $application_id" \
     --header "Api-Company: $company_id" \
     --header 'Content-Type: application/json' \
     --header "Authorization: Bearer $bearer_token" \
     --data '{
         "expiresIn": 3600,
         "agents": [
             {
                 "publicId": "$agent_id"
             }
         ]
     }'
{
    "status": "success",
    "type": "AuthTokenCreateResponse",
    "data": {
        "publicId": "$token_id",
        "secretId": "$jwt-token",
        "expiresOn": "2021-02-02T01:00:00Z"
    }
}

Step 3: Create a WebSocket entry

The next step is to set up a WebSocket connection to read the live data. You can find the correct URL under the AgentDataRealTimeWebSocket endpoint in the discovery request to https://portal.ixon.cloud:443/api/. The WebSocket URL may change in the future. It is recommended to request the URL from the above endpoint instead of hardcoding it.

Step 4: Authenticate your connection

When setting up a datastream in your software solution, you have to add a message with the JWT-token you requested in step 2. You have to put an event listener on onopen to prevent that the WebSocket will be closed by the server. You can prevent this by sending the JWT-Token with the onopen event listener. An HTML example of how this live data stream should be handled is provided below.

<!DOCTYPE html>
 <meta charset="utf-8" />
 <title>WebSocket Test</title>
 <script language="javascript" type="text/javascript">

 <!-- Fill in the correct URL from AgentDataRealTimeWebSocket (see step 3). -->
 <!-- The comma is mandatory as it is a list. -->
 var wsUri = "wss://wse-mdr.dkn-core-nl-ams-02.dkn.ayayot.com/agents/{AgentId},/data-realtime";
 var output;

 function init()
 {
   output = document.getElementById("output");
   testWebSocket();
 }

 function testWebSocket()
 {
   websocket = new WebSocket(wsUri);
   websocket.onopen = function(evt) { onOpen(evt) };
   websocket.onclose = function(evt) { onClose(evt) };
   websocket.onmessage = function(evt) { onMessage(evt) };
   websocket.onerror = function(evt) { onError(evt) };
 }

 <!-- Enter your JWT token here. -->
 function onOpen(evt)
 {
   writeToScreen("CONNECTED");
   doSend("Authorization: {JWT-Token}");
 }

 function onClose(evt)
 {
   writeToScreen("DISCONNECTED");
 }

 function onMessage(evt)
 {
   writeToScreen('<span style="color: blue;">RESPONSE: ' + evt.data+'</span>');
 }

 function onError(evt)
 {
   writeToScreen('<span style="color: red;">ERROR:</span> ' + evt.data);
 }

 function doSend(message)
 {
   writeToScreen("SENT: " + message);
   websocket.send(message);
 }

 function writeToScreen(message)
 {
   var pre = document.createElement("p");
   pre.style.wordWrap = "break-word";
   pre.innerHTML = message;
   output.appendChild(pre);
 }


 window.addEventListener("load", init, false);

 </script>

 <h2>WebSocket Test</h2>

 <div id="output"></div>

 </script>

Step 5: Interpret your data-output

Live data is being returned in a JSON format. As the output is compressed to ensure the fastest connection possible, the data is a little difficult to interpret. In the output you will find a row that is called "tags". The values in this row are variable ID's, which are the key to interpret the data.

To understand the variable ID's, you send a GET request to the AgentDataVariableList endpoint with at least the fields "variableId", "name", "type", "signed" and "width". Your response should look like the example below.

{		
	"type": "AgentDataVariable",
	"data": [
 		{...},
		{
           	"publicId": "$public_id",
           	"variableId": 6,
           	"name": "Weight",
           	"type": "int",
         	"signed": true,
           	"width": "16"
       	},
  		{...}
	],
    "moreAfter": null,
    "status": "success"
}

The variable ID corresponds with the value you can find in the "tags" row of the live data output. The name is the name of the variable to which that ID belongs, so we can see here that variable 6 is the weight. The other 3 fields can be used to determine the data type. In this case the data type is a 16 bit signed integer (int16).

With this information we can search for the weight in the live data output, which is shown in the example below. The first value for a data type is the one with the lowest variable ID, the second value for a data type is the one with the second lowest variable ID etcetera. So if you obtained the Variable IDs, data types and names, you can match the output with the names.

In the output below, variable numbers 6, 7, 11 and 12 are from the data type int16 (as we know from the full output of the example above). This means that variable 6 has value 225 and variable 11 has value 3 in the example below. From the previous request, we know that variable 6 has the name "weight" and thus the measured weight at the given time was 225.

In the whole output with all variable IDs we could also see that variables 8 and 9 are uint16 data types with the names "upperweight" and "underweight". Which are the highest and lowest reported weights at the given moment. Thus we can see that the highest weight was 250 and the lowest 200 in the given time.

{
  "message": {
    "points": [
      {
        "bool": [false],
        "int16": [225,175,3,2],
        "str": [""],
        "tags": [1,2,3,4,5,6,7,8,9,10,11,12,13],
        "time": 1607079466500,
        "uint16": [250,200,86,83,61,86],
        "uint32": [1655898122]
      }
    ],
    "sentTime": 1607079466590
  },
  "agent": {
    "publicId": "$agent_id"
  },
  "device": {
    "publicId": "$source_id"
  }
}

When using two or more data sources

When the AgentDataVariable endpoint is used on a device with two or more data sources, the same variableId can be used by both data sources. In this case, you can add the field device to your query so it also returns the device publicId (which is the data source) that the variable belongs to:

curl --request GET \
     --url '<<url>>:443/api/agents/$agent_id/data-variables?fields=variableId,name,device' \
     --header 'Api-Version: 2' \
     --header "Api-Application: $application_id" \
     --header "Api-Company: $company_id" \
     --header 'content-type: application/json' \
     --header "Authorization: Bearer $bearer_token"