Getting Sensor Data with Websocket
The HTML5 WebSockets specification defines an API that enables web pages to use the WebSockets protocol for two-way communication with a remote host. It introduces the WebSocket interface and defines a full-duplex communication channel that operates through a single socket over the Web. HTML5 WebSockets provide an enormous reduction in unnecessary network traffic and latency compared to the unscalable polling and long-polling solutions that were used to simulate a full-duplex connection by maintaining two connections.
In the IoT-Ignite environment, you can develop near-realtime dashboard application with Websockets. In this document, we will create a simple web page to show how to get sensor data from WebSocket in IoT-Ignite.
We should get OAuth Access Token before establishing WebSocket connection. Getting OAuth token explained in the IoT-Ignite Services Authentication document.
First, we should get WebSocket token for the device we will get data from. This token can be obtained from REST API.
https://api.ardich.com/api/v3/subscribe/device/token?device={DEVICE_ID}
This REST API will return subscribe token and URL for WebSocket.
{ "createDate": {TOKEN_CREATE_DATE}, "expireDate": {TOKEN_EXPIRE_DATE}, "id": {TOKEN_ID}, "token": {SUBSCRIBE_TOKEN}, "url": {URL_FOR_WS} }
Meaning of these parameters:
- createDate: Creation date of token in epoch format.
- expireDate: Expirition date of token in epoch format.
- id: Id of token which we will provide wen connection starting.
- token: Token for websocket
- url: Websocket url
Let’s get token with Javascript and JQuery:
apiUrl = https://api.ardich.com/v3
function apiGet(url, data, success, error){
$.ajax({
url : apiUrl + url,
type : 'GET',
data: data,
dataType : 'json',
headers : {'Authorization': 'Bearer ' + getAccessToken(), 'Content-Type': 'application/json'}
}).done(success).fail(error);
}
function getSubscribeToken(deviceId){
var data = {"device": deviceId};
var url = "/subscribe/device/token"
apiGet(url, data, onSuccess, onError);
}
function onSuccess(data){
console.log("token = " + data.token);
console.log("id = " + data.id);
console.log("url = " + data.url);
startWebSocket(data);
}
function onError(data){
// handleError
}
This code will get token and print token to the console. In the second part of the code, we will open WebSocket and then we will subscribe to a sensor to start listening sensor data.
fucntion startWebSocket(data){
var subscribeUrl = data.url;
var subscribeToken = data.token;
var subscribeId = data.id;
ws = new WebSocket(subscribeUrl);
ws.onopen = function(evt) {
console.log("Web socket connection is opened");
var subscribeMessage = new Object();
subscribeMessage.deviceId = DEVICE_ID;
subscribeMessage.nodeId = NODE_ID;
subscribeMessage.sensorId = SENSOR_ID;
subscribeMessage.id = subscribeId;
subscribeMessage.version = "2.0";
subscribeMessage.token = subscribeToken;
var subscribe = new Object();
subscribe.type = "subscribe";
subscribe.message = subscribeMessage;
console.log(JSON.stringify(subscribe));
ws.send(JSON.stringify(subscribe));
};
ws.onclose = function(evt) { onClose(evt) };
ws.onmessage = function(evt) { onMessage(evt) };
ws.onerror = function(evt) { onError(evt) };
}
In this subscription 3 parameters are provided. DEVICE_ID, NODE_ID, SENSOR_ID.
- DEVICE_ID: Subscribed device's id. You can only specify the device Id which you provided when requesting token.
- NODE_ID: Node Id of requested sensor data. This parameter optional. If every sensor data requested to all nodes it should not be provided.
- SENSOR_ID: Sensor Id of requested sensor data. This parameter optional. If all sensors' data requested this parameter should not be provided.
Websocket messages have 2 parts header and body. Header part includes message type and message date. After subscription WebSocket server will send "Success" or "UnAuthorized" messages. If "Success" message received that means socket connection is successful and sensor messages will be sent when available. SensorMessage's type is "DeviceInfo". Sample SensorInfo message is given below:
{
"header": {
"date": 1478854994111,
"type": "DeviceInfo"
},
"body": {
"nodeId": "NODE_ID",
"sensorId": "SENSOR_ID",
"command": "SensorData",
"messageId": "",
"deviceId": "DEVICE_ID",
"extras": {
"formatVersion": "2",
"sensorData": [
{
"values": [
"XX"
],
"date": 1478854994291
}
]
}
}
}
- In this example there are 2 date entries. First one is in the header part. This "date" means message's sent time. The other date field is inside the sensorData array. This date is the measurement time.
- A message can have more than one value. A device can store multiple measurements and then send them in one message. In this case, sensorData array will have more than one item.
- If sensor measures more than one dimensional value (GPS value, etc.) values array can have multiple values.
With the information above we can write onMessage function.
function onMessage(event) {
var response = JSON.parse(event.data);
console.log(JSON.stringify(response));
if (response.header.type == "Success") {
console.log("Connection established");
} else if (response.header.type == "UnAuthorized") {
console.log("Authorization Error");
} else if (response.header.type == "DeviceInfo") {
var newData = response.body.extras.sensorData;
for (index = 0; index < newData.length; index++) {
console.log("Sensor Date : " + new Date(newData[index].date)
+ " values: " + newData[index].values);
}
}
}
With the modification on "console.log" line, you can print sensorData to a web page or use value in your dashboard components.