Maria Carlina HernandezRAKwireless
Published © GPL3+

Connect a RAK7204 to Helium and Forward Its Data to Ubidots

Start working with Helium along with your RAK devices. This project presents the integration of a RAK7204 to Ubidots over Helium LongFi.

BeginnerProtip3 hours499
Connect a RAK7204 to Helium and Forward Its Data to Ubidots

Things used in this project

Hardware components

Helium Hotspot (LoRaWAN)
Helium Hotspot (LoRaWAN)
×1
WisNode Sense Home RAK7204
RAKwireless WisNode Sense Home RAK7204
×1

Software apps and online services

Ubidots
Ubidots

Story

Read more

Code

RAK7204 WisNode Sense Home Decoder

JavaScript
// Function to decode uplink data.
// Decode decodes an array of bytes into an object.
//  - port contains the LoRaWAN fPort number
//  - bytes is an array of bytes, e.g. [225, 230, 255, 0]
// The function must return an object, e.g. {"temperature": 22.5}
function Decoder(bytes, port) {
 var decoded = {};
 var hexString=bin2HexStr(bytes);
 return rakSensorDataDecode(hexString);
}
 
// convert array of bytes to hex string.
// e.g: 0188053797109D5900DC140802017A0768580673256D0267011D040214AF0371FFFFFFDDFC2E
function bin2HexStr(bytesArr) {
 var str = "";
 for(var i=0; i<bytesArr.length; i++) {
   var tmp = (bytesArr[i] & 0xff).toString(16);
   if(tmp.length == 1) {
     tmp = "0" + tmp;
   }
   str += tmp;
 }
 return str;
}
 
// convert string to short integer
function parseShort(str, base) {
 var n = parseInt(str, base);
 return (n << 16) >> 16;
}
 
// convert string to triple bytes integer
function parseTriple(str, base) {
 var n = parseInt(str, base);
 return (n << 8) >> 8;
}
 
// decode Hex sensor string data to object
function rakSensorDataDecode(hexStr) {
 var str = hexStr;
 var myObj = {};
 
 while (str.length > 4) {
   var flag = parseInt(str.substring(0, 4), 16);
   switch (flag) {
     case 0x0768:// Humidity
       myObj.humidity = parseFloat(((parseShort(str.substring(4, 6), 16) * 0.01 / 2) * 100).toFixed(1)) + "%RH";//unit:%RH
       str = str.substring(6);
       break;
     case 0x0673:// Atmospheric pressure
       myObj.barometer = parseFloat((parseShort(str.substring(4, 8), 16) * 0.1).toFixed(2)) + "hPa";//unit:hPa
       str = str.substring(8);
       break;
     case 0x0267:// Temperature
       myObj.temperature = parseFloat((parseShort(str.substring(4, 8), 16) * 0.1).toFixed(2)) + "°C";//unit: °C
       str = str.substring(8);
       break;
     case 0x0188:// GPS
       myObj.latitude = parseFloat((parseTriple(str.substring(4, 10), 16) * 0.0001).toFixed(4)) + "°";//unit:°
       myObj.longitude = parseFloat((parseTriple(str.substring(10, 16), 16) * 0.0001).toFixed(4)) + "°";//unit:°
       myObj.altitude = parseFloat((parseTriple(str.substring(16, 22), 16) * 0.01).toFixed(1)) + "m";//unit:m
       str = str.substring(22);
       break;
     case 0x0371:// Triaxial acceleration
       myObj.acceleration_x = parseFloat((parseShort(str.substring(4, 8), 16) * 0.001).toFixed(3)) + "g";//unit:g
       myObj.acceleration_y = parseFloat((parseShort(str.substring(8, 12), 16) * 0.001).toFixed(3)) + "g";//unit:g
       myObj.acceleration_z = parseFloat((parseShort(str.substring(12, 16), 16) * 0.001).toFixed(3)) + "g";//unit:g
       str = str.substring(16);
       break;
     case 0x0402:// air resistance
       myObj.gasResistance = parseFloat((parseShort(str.substring(4, 8), 16) * 0.01).toFixed(2)) + "KΩ";//unit:KΩ
       str = str.substring(8);
       break;
     case 0x0802:// Battery Voltage
       myObj.battery = parseFloat((parseShort(str.substring(4, 8), 16) * 0.01).toFixed(2)) + "V";//unit:V
       str = str.substring(8);
       break;
     case 0x0586:// gyroscope
       myObj.gyroscope_x = parseFloat((parseShort(str.substring(4, 8), 16) * 0.01).toFixed(2)) + "°/s";//unit:°/s
       myObj.gyroscope_y = parseFloat((parseShort(str.substring(8, 12), 16) * 0.01).toFixed(2)) + "°/s";//unit:°/s
       myObj.gyroscope_z = parseFloat((parseShort(str.substring(12, 16), 16) * 0.01).toFixed(2)) + "°/s";//unit:°/s
       str = str.substring(16);
       break;
     case 0x0902:// magnetometer x
       myObj.magnetometer_x = parseFloat((parseShort(str.substring(4, 8), 16) * 0.01).toFixed(2)) + "μT";//unit:μT
       str = str.substring(8);
       break;
     case 0x0a02:// magnetometer y
       myObj.magnetometer_y = parseFloat((parseShort(str.substring(4, 8), 16) * 0.01).toFixed(2)) + "μT";//unit:μT
       str = str.substring(8);
       break;
     case 0x0b02:// magnetometer z
       myObj.magnetometer_z = parseFloat((parseShort(str.substring(4, 8), 16) * 0.01).toFixed(2)) + "μT";//unit:μT
       str = str.substring(8);
       break;
     default:
       str = str.substring(7);
       break;
   }
 }
 
 return myObj;
}

UbiFunction: Helium Integration

JavaScript
// Import the 'axios' library so we can make HTTP request from the function
var axios = require("axios");
 
// Define Ubidots constant
const UBI_TOKEN = "BBFF-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
const UBI_URL_API_2 = "https://industrial.api.ubidots.com/api/v2.0";
const UBI_URL = "https://industrial.api.ubidots.com/api/v1.6";
 
// Main function - runs every time the function is executed.
// "args" is a dictionary containing both the URL params and the HTTP body (for POST requests).
async function main(args) {
 
 var data = {};
  var appEUI = args["app_eui"];
 var payload = args["decoded"]["payload"];
 var payloadStatus = args["decoded"]["status"];
 var devEUI = args["dev_eui"];
 var devAddr = args["devaddr"];
 var downlinkUrl = args["downlink_url"];
 var nodeId = args["id"];
 var organizationId = args["metadata"]["organization_id"];
 var name = args["name"];
 var payloadBase64 = args["payload"];
 var reportedAt = args["reported_at"];
 
 // Check if the device does not exist in Ubidots Platform
 var deviceStatus = await ubidotsGetDevice(UBI_TOKEN, devAddr);
 // If the device does not exist, create it
 if (deviceStatus == 404) {
   await ubidotsDeviceCreation(UBI_TOKEN, name, devAddr);
 };
 
 // Filter the payload received from helium
 const variables = Object.entries(payload).reduce((previous, current) => {
   const [key, value] = current;
   const varValue = parseFloat(value);
   const unit = value.replace(/[\d\.]/g, '')
 
   return [...previous, [key, varValue, unit]];
 }, []);
 
 // Create respective custom variables
 for (const variable of variables) {
   var variableStatus = await ubidotsVariableCreation(UBI_TOKEN, devAddr, variable[0], variable[0], variable[2]);
   data[variable[0]] = variable[1]
 }
 // Send variables' values to Ubidots
 var variablesRequest = await ubidotsSendVariableValues(UBI_TOKEN, devAddr, data);
  return {"status": variablesRequest};
}
 
/*
* Create a custom device in Ubidots Platform
* API Documentation: docs.ubidots.com
*
* @arg token [Mandatory], Ubidots account's Token
* @arg deviceName [Mandatory], device's friendly name
* @arg deviceLabel [Mandatory], single and unique label of device
* @arg lat [Optional], latitude corresponding to the device's location
* @arg lng [Optional], longitude corresponding to the device's location
*
* @return response/error, request response
*/
async function ubidotsDeviceCreation(token, deviceName, deviceLabel, lat = 0, lng = 0) {
 
 var endpoint = UBI_URL_API_2.concat("/devices");
 
 var deviceParams = {
   "label": deviceLabel,
   "name": deviceName
 };
 
 if (lat != 0 && lng != 0) {
   deviceParams.properties = {
     "_location_type":"manual",
     "_location_fixed": {
       "lat": lat,
       "lng": lng
     }
   };
 }
 
 return axios.post(endpoint, deviceParams, {
   headers: {
     "content-type": "application/json",
     "X-Auth-Token": token
   }
 })
 .then(function (response) {
   //console.log(response);
 })
 .catch(function (error) {
   //console.log(error.response);
 });
}
 
/*
* Get an existent device in Ubidots Platform
* API Documentation: docs.ubidots.com
*
* @arg token [Mandatory], Ubidots account's Token
* @arg deviceLabel [Mandatory], single and unique label of device
*
* @return response/error, request response
*/
async function ubidotsGetDevice(token, deviceLabel) {
 
 var endpoint = UBI_URL_API_2.concat("/devices/~" + deviceLabel);
 
 return axios.get(endpoint, {
   headers: {
     "content-type": "application/json",
     "X-Auth-Token": token
   }
 })
 .then(function (response) {
   return response.statusText;
 })
 .catch(function (error) { 
   return error.response.status;
 });
}
 
/*
* Create a custom variable in Ubidots Platform
* API Documentation: docs.ubidots.com
*
* @arg token [Mandatory], Ubidots account's Token
* @arg deviceLabel [Mandatory], single and unique label of device
* @arg variableName [Mandatory], variable's friendly name
* @arg variableLabel [Mandatory], single and unique label of variable
* @arg unit [Mandatory], unit associated to the value of the variable
*
* @return response/error, request response
*/
async function ubidotsVariableCreation(token, deviceLabel, variableName, variableLabel, unit) {
 
 var endpoint = UBI_URL_API_2.concat("/variables");
  var variableParams = {
   "label": variableLabel,
   "name": variableName,
   "device": "~".concat(deviceLabel).toLowerCase(),
   "unit": unit
 };
 
 return axios.post(endpoint, variableParams, {
   headers: {
     "content-type": "application/json",
     "X-Auth-Token": token
   }
 })
 .then(function (response) {
   return response.statusText;
 })
 .catch(function (error) {
   return error.response.status;
 });
}
 
/*
* Handle a POST request to Ubidots API
* API Documentation: https://ubidots.com/docs/sw/
*
* @arg token [Mandatory], Ubidots account's Token
* @arg device_label [Mandatory], single and unique label of device
* @arg payload [Mandatory], variables and values to be sent in a JSON format
*
* @return response/error, request response
*/
async function ubidotsSendVariableValues(token, deviceLabel, payload) {
 
 var endpoint = UBI_URL.concat("/devices/" + deviceLabel);
  return axios.post(endpoint, payload, {
   headers: {
     "content-type": "application/json",
     "X-Auth-Token": token
   }
 })
 .then(function (response) {
   return response.statusText;
 })
 .catch(function (error) {
   return error.response.status;
 });
}

Credits

Maria Carlina Hernandez

Maria Carlina Hernandez

27 projects • 89 followers
DevRel Lead @RAKwireless • @IoTMedellin Organizer • Ambassador at @ubidots @Sigfox
RAKwireless

RAKwireless

6 projects • 18 followers
A pioneer in providing innovated and diverse LPWA connectivity solutions for IoT edge devices.

Comments