The MachineQ Platform by Comcast is a powerful data collection and aggregation platform for the IoT. Connect your MachineQ data to Ubidots to develop and deploy Business Intelligence Apps in days not months. In this Ubidots UbiFunctions article, we will explore how to communicate your devices data with Machine Q then relay all data to Ubidots where it can be made intelligent and add value to your business.

Contents:

  1. Ubidots Setup
  2. Machine Q Setup
  3. Sample Codes for Machine Q data parser function in UbiFunctions
    * PREDEFINED DECODER - Python and NodeJS
    * UNKNOWN DECODER - Python and NodesJS

1. Ubidots Setup

1. Create a function in your Ubidots account:

1.1 Click on "Function" from the "Devices Management" tab of your Ubidots header:

1.2 Click the blue "+" icon to create a new function:

1.3 Name the function that describes the type of device you're using. We recommend using the format "Brand-Reference", i.e. "mq-stm" or "mq-mqspark".

1.4. Select "POST" as method:

1.5. Click on "Make it live" to deploy an API endpoint URL containing the name of your function. You will find the updated URL in the Function as shown below:

1.6. Next, choose your preferred language (NodeJS or Python) and copy and paste inside the function the sample codes found below (.py if you choose python, .txt if you choose nodejs).

2. MACHINE Q Setup

1. From your home MachineQ dashboard, navigate to Output profiles

2. Create a new Output profile

3. Then click  "ADD REST PROFILE"

4. Fill in with the following parameters:

5. Complete the Output Profile Name with an identifier -  we use "Ubidots" as an example. 

NOTE: If you have multiples devices of different brands, it is recommend to assign the name of Output Profile based on the brand. For example, “ubidots-mqspark

6. Click on "submit" at the bottom of the Output Profile to save your work.

7. Next, navigate to the Devices Section and Edit settings.

8. Edit your actual device's settings

9. Select a Decode Type (if you do not choose one, MQ will send the data as Hexadecimal and the function will not work properly) and choose the Ubidots Profile Output created in step 6.

IMPORTANT NOTE: The data can be received in different ways, PREDEFINED DECODER or UNKNOWN DECODER. Based on how the data is being sent use the respective code found at the bottom of this tutorial. 

10. Submit and Save your device settings.

11. Return to Ubidots to see data reporting in your Device Section. Now it's time to develop your BI application with:

Sample Codes for Machine Q Function in Ubidots

1. Using a PREDEFINED DECODER

  • Python Sample Code
import requests
import time
import struct
import binascii

def parse_data(comcast_payload):
  '''
  parses the payload that comes from comcast and returns the Ubidots Token, DEVEUI
  and the decoded_payload keys, below you can find a payload example
  '''
  ubi_token = comcast_payload.get("token", None)
  ubi_device = comcast_payload.get("DevEUI", None)
  ubi_payload = comcast_payload.get("decoded_payload", None)
  return (ubi_token, ubi_device, ubi_payload)


def send_to_ubidots(token, device, payload):
  '''
  Function to send data to ubidots
  '''
  url = "http://industrial.api.ubidots.com"
  url = "{}/api/v1.6/devices/{}".format(url, device)

  headers = {"X-Auth-Token": token, "Content-Type": "application/json"}

  status = 400
  attempts = 0
  print("[INFO] attempting to send data to Ubidots")

  while status >= 400 and attempts <= 5:
      req = requests.post(url=url, headers=headers, json=payload)
      status = req.status_code
      attempts += 1
      if status >= 400:
          time.sleep(1)

  if status == 200 or status == 201:
      print("[INFO] Data posted properly")
      return True

  print("[ERROR] Could not post data")
  return False


def main(comcast_payload):
  print("[INFO] Attempting to decode data")
  ubi_token, ubi_device, ubi_payload = parse_data(comcast_payload)
  '''
  Parse the incoming data from machineQ
  '''
  payload = ubi_payload
   if ubi_payload is not None and ubi_device is not None:
      result = send_to_ubidots(ubi_token, ubi_device, ubi_payload)
      return {"status": result}

  print("[ERROR] Could not send data to Ubidots")
  return {"status": False}
  • NodeJS Sample Code
var request = require('request-promise');

async function main(args) {  
   /*
   Parses the payload that comes from comcast. Returning:
    - Ubidots TOKEN
    - Device EUI
    - Data already decoded
   */

   // Get the token
   var ubidots_token = args.token;
 
   // Get the device label
   var device_label = args.DevEUI;
 
   // Get payload
   var data = args.decoded_payload;

   // Make POST request to Ubidots
   var post_response = await send_to_ubidots(ubidots_token, device_label, data);
 
   // Pass Ubidots' API response to the function' response
   return post_response;
}

async function send_to_ubidots(ubidots_token, device_label, data) {
  /*
  Function to send data to ubidots
  */
  var options = {
      method: 'POST',
      url: 'https://industrial.api.ubidots.com/api/v1.6/devices/' + device_label + '?force=true',
      body: data,
      json: true,
      headers: {
          'Content-Type': 'application/json',
          'X-Auth-Token': ubidots_token
      }
  };
  return await request.post(options);
}

2. Using an UNKNOWN DECODER 

The codes provided below show how to decode the hexadecimal data received from machineQ. Please note that this should be modified based on how the data is being sent from the device. 

As an example let's suppose that the device used is sending the data: 0x1B37 , where the first byte is related to a temperature value and the latter to humidity value, resulting in...

Data sent: 0x1B = 27 (temperature), 0x37 = 55 (humidity)

  • Python Sample Code
import requests
import time
import struct
import binascii

def parse_data(comcast_payload):
   '''
   parses the payload that comes from comcast and returns the Ubidots Token, DEVEUI
   and the decoded_payload keys, below you can find a payload example
   '''
   ubi_token = comcast_payload.get("token", None)
   ubi_device = comcast_payload.get("DevEUI", None)
   ubi_payload = comcast_payload.get("decoded_payload", None)
   ubi_payload = ubi_payload["RawData"]
   return (ubi_token, ubi_device, ubi_payload)


def send_to_ubidots(token, device, payload):
   '''
   Function to send data to ubidots
   '''
   url = "http://industrial.api.ubidots.com"
   url = "{}/api/v1.6/devices/{}".format(url, device)

   headers = {"X-Auth-Token": token, "Content-Type": "application/json"}

   status = 400
   attempts = 0
   print("[INFO] attempting to send data to Ubidots")

   while status >= 400 and attempts <= 5:
       req = requests.post(url=url, headers=headers, json=payload)
       status = req.status_code
       attempts += 1
       if status >= 400:
           time.sleep(1)

   if status == 200 or status == 201:
       print("[INFO] Data posted properly")
       return True

   print("[ERROR] Could not post data")
   return False


def main(comcast_payload):
   print("[INFO] Attempting to decode data")
   ubi_token, ubi_device, ubi_payload = parse_data(comcast_payload)
   '''
   Parse the incoming data from machineQ
   '''
   payload = ubi_payload
   len_payload_odd = int(round(len(payload) / 2.0) * 2.0)
   fill = payload.rjust(len_payload_odd, '0')  
   temp_value, hum_value = struct.unpack('b'*int(len_payload_odd / 2), binascii.unhexlify(fill))
 
   '''
   Build the payload to be posted
   '''
   ubi_payload = {"temperature": temp_value, "humidity": hum_value}
 
   if ubi_payload is not None and ubi_device is not None:
       result = send_to_ubidots(ubi_token, ubi_device, ubi_payload)
       return {"status": result}

   print("[ERROR] Could not send data to Ubidots")
   return {"status": False}
  • NodeJS Sample Code
var request = require('request-promise');

async function main(args) {
   /*
   Parses the payload that comes from comcast. Returning:
    - Ubidots TOKEN
    - Device EUI
    - Data (2 bytes)
   */
 
   // Get Ubidots Token
   var ubidots_token = args.token;
 
   // Get the device label
   var device_label = args.DevEUI;
 
   // Get payload
   var data = args.decoded_payload.RawData;
 
   // Parsing data to be posted
   var buf = new Buffer(data, 'hex');    
   var temperature = buf.readInt8(0);
   var humidity = buf.readInt8(1);

   // Build Payload
   var payload = {"temperature": temperature, "humidity": humidity};
 
   // Make POST request to Ubidots
   var post_response = await send_to_ubidots(ubidots_token, device_label, payload);

   // Pass Ubidots' API response to the function' response
   return post_response;
}

async function send_to_ubidots(ubidots_token, device_label, data) {
   /*
   Function to send data to ubidots
   */
   var options = {
       method: 'POST',
       url: 'https://industrial.api.ubidots.com/api/v1.6/devices/' + device_label + '?force=true',
       body: data,
       json: true,
       headers: {
           'Content-Type': 'application/json',
           'X-Auth-Token': ubidots_token
       }
   };
   return await request.post(options);
}


WARNING: Remember that the UNKNOWN DECODER codes needs to be updated following the structure of how your device is sending the data. 


Other users also found useful:

Did this answer your question?