Skip to content

Commit

Permalink
Loriot integration - verification still needed (downlink not working …
Browse files Browse the repository at this point in the history
…correctly)
  • Loading branch information
dhakke committed Nov 7, 2024
1 parent 29149ad commit 52abc6c
Show file tree
Hide file tree
Showing 8 changed files with 44 additions and 0 deletions.
19 changes: 19 additions & 0 deletions VENDORS/Yobiiq/SD1001/Loriot/downlink/converter.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"name": "Loriot Downlink data converter for Yobiiq SD-1001",
"type": "DOWNLINK",
"debugMode": true,
"configuration": {
"scriptLang": "TBEL",
"decoder": "// Decode an uplink message from a buffer\n// payload - array of bytes\n// metadata - key/value object\n\n/** Decoder **/\n\n// decode payload to string\nvar payloadStr = decodeToString(payload);\n\n// decode payload to JSON\n// var data = decodeToJson(payload);\n\nvar deviceName = 'Device A';\nvar deviceType = 'thermostat';\nvar customerName = 'Customer C';\nvar groupName = 'thermostat devices';\nvar manufacturer = 'Example corporation';\n// use assetName and assetType instead of deviceName and deviceType\n// to automatically create assets instead of devices.\n// var assetName = 'Asset A';\n// var assetType = 'building';\n\n// Result object with device/asset attributes/telemetry data\nvar result = {\n// Use deviceName and deviceType or assetName and assetType, but not both.\n deviceName: deviceName,\n deviceType: deviceType,\n// assetName: assetName,\n// assetType: assetType,\n// customerName: customerName,\n groupName: groupName,\n attributes: {\n model: 'Model A',\n serialNumber: 'SN111',\n integrationName: metadata['integrationName'],\n manufacturer: manufacturer\n },\n telemetry: {\n temperature: 42,\n humidity: 80,\n rawData: payloadStr\n }\n};\n\n/** Helper functions **/\n\nfunction decodeToString(payload) {\n return String.fromCharCode.apply(String, payload);\n}\n\nfunction decodeToJson(payload) {\n // covert payload to string.\n var str = decodeToString(payload);\n\n // parse string to JSON\n var data = JSON.parse(str);\n return data;\n}\n\nreturn result;",
"tbelDecoder": "// Decode an uplink message from a buffer\n// payload - array of bytes\n// metadata - key/value object\n\n/** Decoder **/\n\n// decode payload to string\nvar payloadStr = decodeToString(payload);\n\n// decode payload to JSON\n// var data = decodeToJson(payload);\n\nvar deviceName = 'Device A';\nvar deviceType = 'thermostat';\nvar customerName = 'Customer C';\nvar groupName = 'thermostat devices';\nvar manufacturer = 'Example corporation';\n// use assetName and assetType instead of deviceName and deviceType\n// to automatically create assets instead of devices.\n// var assetName = 'Asset A';\n// var assetType = 'building';\n\n// Result object with device/asset attributes/telemetry data\nvar result = {\n// Use deviceName and deviceType or assetName and assetType, but not both.\n deviceName: deviceName,\n deviceType: deviceType,\n// assetName: assetName,\n// assetType: assetType,\n// customerName: customerName,\n groupName: groupName,\n attributes: {\n model: 'Model A',\n serialNumber: 'SN111',\n integrationName: metadata['integrationName'],\n manufacturer: manufacturer\n },\n telemetry: {\n temperature: 42,\n humidity: 80,\n rawData: payloadStr\n }\n};\n\n/** Helper functions 'decodeToString' and 'decodeToJson' are already built-in **/\n\nreturn result;",
"encoder": null,
"tbelEncoder": "// Encode downlink data from incoming Rule Engine message\r\n\r\n// msg - JSON message payload downlink message json\r\n// msgType - type of message, for ex. 'ATTRIBUTES_UPDATED', 'POST_TELEMETRY_REQUEST', etc.\r\n// metadata - list of key-value pairs with additional data about the message\r\n// integrationMetadata - list of key-value pairs with additional data defined in Integration executing this converter\r\n\r\n/** Encoder **/\r\n\r\n\r\n// Process data from incoming message and metadata\r\nvar input = {\r\n fPort : parseInt(metadata.rc_fPort),\r\n confirmed : metadata.rc_confirmed === \"true\" ? true : false,\r\n data : msg,\r\n variables: null,\r\n devEui : metadata.cs_devEui,\r\n devId : metadata.cs_devId,\r\n applicationId: metadata.cs_applicationId,\r\n};\r\n\r\n// Result object with encoded downlink payload\r\nvar result = {\r\n\r\n // downlink data content type: JSON, TEXT or BINARY (base64 format)\r\n contentType: \"TEXT\",\r\n\r\n // downlink data\r\n data: base64ToHex(bytesToBase64(encodeDownlink(input).bytes)),\r\n \r\n // Optional metadata object presented in key/value format\r\n metadata: {\r\n EUI : input.devEui,\r\n port : input.fPort,\r\n }\r\n\r\n};\r\n\r\n\r\nreturn result;\r\n\r\n\r\n\r\n/************************************************************************************************************/\r\n\r\n// Encode encodes the given object into an array of bytes. (ChirpStack v3)\r\n// - fPort contains the LoRaWAN fPort number\r\n// - obj is an object, e.g. {\"temperature\": 22.5}\r\n// - variables contains the device variables e.g. {\"calibration\": \"3.5\"} (both the key / value are of type string)\r\n// The function must return an array of bytes, e.g. [225, 230, 255, 0]\r\nfunction Encode(fPort, obj, variables) {\r\n // Constants for downlink\r\n var CONFIG_DOWNLINK = {\r\n TYPE : \"Type\",\r\n CONFIG : \"Config\"\r\n };\r\n\r\n if(obj[CONFIG_DOWNLINK.TYPE] == CONFIG_DOWNLINK.CONFIG)\r\n {\r\n return encodeDeviceConfiguration(obj[CONFIG_DOWNLINK.CONFIG], variables);\r\n }\r\n return [];\r\n}\r\n\r\n// Encode downlink function. (ChirpStack v4 , TTN)\r\n//\r\n// Input is an object with the following fields:\r\n// - data = Object representing the payload that must be encoded.\r\n// - variables = Object containing the configured device variables.\r\n//\r\n// Output must be an object with the following fields:\r\n// - bytes = Byte array containing the downlink payload.\r\nfunction encodeDownlink(input) {\r\n return {\r\n bytes: Encode(null, input.data, input.variables)\r\n };\r\n}\r\n\r\n\r\n/************************************************************************************************************/\r\n\r\n\r\nfunction encodeDeviceConfiguration(objArray, variables)\r\n{\r\n // Constants for device configuration \r\n var CONFIG_DEVICE = {\r\n FPORT : 50,\r\n CHANNEL : 0xFF,\r\n TYPES : {\r\n \"reportingInterval\" : {TYPE : 0x03, SIZE : 2, MIN : 1, MAX : 65535,},\r\n \"smokeDetector\" : {TYPE : 0x00, SIZE : 1, MIN : 0, MAX : 1,},\r\n \"silenceBuzzer\" : {TYPE : 0x0A, SIZE : 2, MIN : 0, MAX : 65535,},\r\n \"confirmedUplink\" : {TYPE : 0x01, SIZE : 1, MIN : 0, MAX : 1,},\r\n }\r\n };\r\n var encoded = [];\r\n var field = [\"Param\", \"Value\"];\r\n\r\n for(var i=0; i<objArray.length; i=i+1)\r\n {\r\n var obj = objArray[i];\r\n var config = CONFIG_DEVICE.TYPES.get(obj.get(field[0]));\r\n var value = obj.get(field[1]);\r\n if(value >= config.MIN && value <= config.MAX)\r\n {\r\n encoded.push(CONFIG_DEVICE.CHANNEL);\r\n encoded.push(config.TYPE);\r\n if(config.SIZE == 1)\r\n {\r\n encoded.push(value);\r\n }else if(config.SIZE == 2)\r\n {\r\n if(config.TYPE == 3)\r\n {\r\n var lowByte = value % 256;\r\n encoded.push( ((lowByte & 0x0F) << 4) + (lowByte >> 4) );\r\n encoded.push( (value >> 8) % 256 );\r\n }else\r\n {\r\n encoded.push( (value >> 8) % 256 );\r\n encoded.push( value % 256 );\r\n }\r\n }\r\n }else\r\n {\r\n return [];\r\n }\r\n }\r\n\r\n return encoded;\r\n}",
"updateOnlyKeys": [
"manufacturer"
]
},
"additionalInfo": {
"description": ""
},
"edgeTemplate": false
}
3 changes: 3 additions & 0 deletions VENDORS/Yobiiq/SD1001/Loriot/downlink/metadata.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"integrationName": "Loriot integration"
}
Empty file.
Empty file.
19 changes: 19 additions & 0 deletions VENDORS/Yobiiq/SD1001/Loriot/uplink/converter.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"name": "Loriot Uplink data converter for Yobiiq SD-1001",
"type": "UPLINK",
"debugMode": true,
"configuration": {
"scriptLang": "TBEL",
"decoder": "// Decode an uplink message from a buffer\n// payload - array of bytes\n// metadata - key/value object\n\n/** Decoder **/\n\n// decode payload to string\nvar payloadStr = decodeToString(payload);\n\n// decode payload to JSON\n// var data = decodeToJson(payload);\n\nvar deviceName = 'Device A';\nvar deviceType = 'thermostat';\nvar customerName = 'Customer C';\nvar groupName = 'thermostat devices';\nvar manufacturer = 'Example corporation';\n// use assetName and assetType instead of deviceName and deviceType\n// to automatically create assets instead of devices.\n// var assetName = 'Asset A';\n// var assetType = 'building';\n\n// Result object with device/asset attributes/telemetry data\nvar result = {\n// Use deviceName and deviceType or assetName and assetType, but not both.\n deviceName: deviceName,\n deviceType: deviceType,\n// assetName: assetName,\n// assetType: assetType,\n// customerName: customerName,\n groupName: groupName,\n attributes: {\n model: 'Model A',\n serialNumber: 'SN111',\n integrationName: metadata['integrationName'],\n manufacturer: manufacturer\n },\n telemetry: {\n temperature: 42,\n humidity: 80,\n rawData: payloadStr\n }\n};\n\n/** Helper functions **/\n\nfunction decodeToString(payload) {\n return String.fromCharCode.apply(String, payload);\n}\n\nfunction decodeToJson(payload) {\n // covert payload to string.\n var str = decodeToString(payload);\n\n // parse string to JSON\n var data = JSON.parse(str);\n return data;\n}\n\nreturn result;",
"tbelDecoder": "var data = decodeToJson(payload);\r\n\r\nvar deviceName = data.EUI;\r\nvar deviceType = 'Smoke Detector';\r\nvar groupName = 'Smoke Detectors';\r\n// var customerName = 'Customer A';\r\n// use assetName and assetType instead of deviceName and deviceType\r\n// to automatically create assets instead of devices.\r\n// var assetName = 'Asset A';\r\n// var assetType = 'building';\r\n\r\n\r\n// --- attributes and telemetry objects ---\r\nvar telemetry = {};\r\nvar attributes = {};\r\n// --- attributes and telemetry objects ---\r\n\r\n\r\nvar timestamp = -1;\r\nif(data.ts > 0)\r\n{\r\n timestamp = data.ts;\r\n}\r\nif (timestamp == -1) {\r\n timestamp = Date.now();\r\n}\r\n\r\n// You can add some keys manually to attributes or telemetry\r\nattributes.devEui = data.EUI;\r\nattributes.fPort = data.port;\r\n\r\n// You can exclude some keys from the result\r\nvar excludeFromTelemetryList = [\"cmd\", \"EUI\", \"devaddr\", \"seqno\", \"port\", \"time\", \"ts\", \"received_at\"];\r\nvar excludeFromAttributesList = [\"cmd\",\"EUI\", \"devaddr\", \"seqno\", \"port\", \"time\", \"ts\", \"received_at\",\"toa\",\"freq\",\"faultAlarm\",\"smokeAlarm\",\"faultAlarm\",\"interconnectAlarm\",\"lowBatteryAlarm\",\"batteryLevelInPercentage\",\"powerEvent\",\"rssi\",\"snr\",\"confirmed\",\"frm_payload\",\"fcnt\"];\r\n\r\n// Message parsing\r\n// To avoid paths in the decoded objects we passing false value to function as \"pathInKey\" argument.\r\n// Warning: pathInKey can cause already found fields to be overwritten with the last value found, e.g. receive_at from uplink_message will be written receive_at in the root.\r\nvar telemetryData = toFlatMap(data, excludeFromTelemetryList, false);\r\nvar attributesData = {};\r\nattributesData.putAll(toFlatMap(data, excludeFromAttributesList, false));\r\n\r\ntelemetry.putAll(telemetryData);\r\nattributes.putAll(attributesData);\r\n\r\nvar result = {\r\n deviceName: deviceName,\r\n deviceType: deviceType,\r\n// assetName: assetName,\r\n// assetType: assetType,\r\n// customerName: customerName,\r\n groupName: groupName,\r\n attributes: attributes,\r\n telemetry: {\r\n ts: timestamp,\r\n values: telemetry\r\n }\r\n};\r\n\r\nreturn result;",
"encoder": null,
"tbelEncoder": null,
"updateOnlyKeys": [
"manufacturer"
]
},
"additionalInfo": {
"description": ""
},
"edgeTemplate": false
}
3 changes: 3 additions & 0 deletions VENDORS/Yobiiq/SD1001/Loriot/uplink/metadata.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"integrationName": "Loriot integration"
}
Empty file.
Empty file.

0 comments on commit 52abc6c

Please sign in to comment.