Message Context

Message is nothing but an object of the incoming data, the message data structure has also more fields at runtime (metadata) than originally defined by the user. The message object that arrives the rules engine for the regular simple message and binary message greatly differs. Binary message has invokable utility methods to perform most common data conversion operations.

  • Defined Fields
    • Whatever fields you have predefined in the platform, along with any new fields you push through the message will be available in this message object
    • Notes
      • You don't have to send all the fields that you predefined
      • You can also send any new fields in a message that was not predefined
        • If you send random fields without predefining them, then you may encounter issues if you try to edit/modify your message structure.
  • Metadata fields
    • id : uuid (each message has universally unique id)
    • receivedstamp: TIMESTAMP (epoch millis)
    • deliveredstamp : TIMESTAMP (epoch millis)
    • channel: ENUM (UDP, MQTT, HTTP, COAP, TCP, FCM, LORA, FTP, TFTP)
    • ipaddress: VARCHAR (may not be always available)
    • port : INTEGER (may not be always available)
    • nodeid: VARCHAR (unique node identifier)
    • nodeuid: VARCHAR (unique node identifier, consistent after reboots)
    • domainkey: VARCHAR
    • deviceid : VARCHAR
    • dmdl : VARCHAR
    • fwver: VARCHAR
  • Context Variable: msg & old
    • Variables msg and old are similar objects, the only difference is, old refers to the previous message that got received from the same device
      • For the very first message from a device, old will not be available at the runtime
  • Only Applicable To: Message Rules

  • Metadata fields
    • id : uuid (each message has universally unique id)
    • receivedstamp: DATE Object (epoch millis)
    • channel: ENUM (UDP, MQTT, HTTP, COAP, TCP, FCM, LORA, FTP, TFTP)
    • ipaddress: VARCHAR (may not be always available)
    • port : INTEGER (may not be always available)
    • nodeid: VARCHAR (unique node identifier)
    • nodeuid: UUID (unique node identifier, consistent after reboots)
    • domainKey: VARCHAR
    • deviceId : VARCHAR
    • deviceModel : VARCHAR
    • firmwareVersion: VARCHAR
    • properties: VARCHAR
    • contentType: VARCHAR
    • state: ENUM (QUEUED, BUSY_REJECTED, PROCESSED, FAILED)
    • reason: VARCHAR
    • systemQueue: INTEGER
    • fileName: VARCHAR
    • filePath: VARCHAR
  • Context Variable: msg
  • Only Applicable To: Binary Rules
/**
* Method to get the direct byte[]
*/
public byte[] getData();

/**
* This method returns your binary data converted into Groovy/Java Map
* Very convenient when you send a complex JSON Document as binary message
*/
public HashMap<String, Object> map();

/**
* If you want to handle with the JSON directly, use this method
* http://javadox.com/org.codehaus.jettison/jettison/1.1/org/codehaus/jettison/json/JSONObject.html
*/
public JSONObject json();

/**
* If your data is url encoded form object, then you can convert into mapped fields
*/
public Map<String, String> urlEncoded();

/**
* If your data is is in CSV format, you could get the CSVParser library to further handle it. Parser is created using default preset format
* https://commons.apache.org/proper/commons-csv/apidocs/org/apache/commons/csv/CSVParser.html
*/
public CSVParser csv();

/**
* If your data is is in CSV format, you could get the CSVParser library to further handle it, parser is created using specified format
* Allowed Formats (DEFAULT, EXCEL, INFORMIX_UNLOAD,INFORMIX_UNLOAD_CSV,MYSQL, ORACLE, POSTGRESQL_CSV, POSTGRESQL_TEXT, RFC4180, TDF)
* https://commons.apache.org/proper/commons-csv/apidocs/org/apache/commons/csv/CSVParser.html
*/
public CSVParser csv(String format);

/**
* Convenient method to convert the binary data to String object
*/
public String string();

/**
* Split the data using regular expression
*/
public String[] split(String regex);

/**
* Split the data into multiple lines using \r\n
*/
public List<String> lines();

/**
* Just in case if you want to modify the data and update in the storage
*/
public void update();

/**
* Mark the message as preocessed
*/
public void processed();

/**
* Permanently delete from the storage
*/
public void delete();

Example Message Rule

In this example we are going to insert a new record each time if a sensor reports >= 75 degrees and previously it has reported less than 75 degrees.

You should have the following record defined with a unique ID of 5000

{
  'sensor': 'VARCHAR',
  'stamp': 'TIMESTAMP',
  'temperature': 'INTEGER'
}

You should have message with ID 1000 defined and a corresponding rule should be created in the platform's rules engine with the below code

if(msg.temperature >= 75 && (null == old || old.temperature < 75)){
    //log the critical temperature events
    record.insert(5000, ['sensor': msg.deviceid, 'temperature': msg.temperature, 'stamp': util.millis()]);
}

Example Binary Message Rule

In this example we are going to insert a new record item from a TEXT data that was delimited by lines and each line has the following fields separated by comma (,). Imagine a data logger which is going to upload a file periodically after collecting (n) number of data

  • Field 1 - temperature
  • Field 2 - humidity
  • Field 3 - wind speed (m/s)

You should have the following record defined with a unique ID of 5001

{
  'sensor': 'VARCHAR',
  'stamp': 'TIMESTAMP',
  'temperature': 'INTEGER',
  'humidity': 'INTEGER',
  'windspeed': 'INTEGER'
}

You should have a binary rule named DataLogger with the following code created in the platform's rules engine

def lines = msg.lines(); //split the data into lines

lines.each(){
  
  def vals = ${it}.split(",");
  def rec = [:];

  rec['sensor'] = msg.deviceId;
  rec['stamp'] = util.millis();
  rec['temperature'] = vals[0];
  rec['humidity'] = vals[1];
  rec['windspeed'] = vals[2];
  
  record.insert(5001, rec);
}

Worth Seeing