From 52abc6c3843e0bdc835a4c7dc6c6fb1ef3b3d70c Mon Sep 17 00:00:00 2001 From: Dominic Hakke Date: Thu, 7 Nov 2024 12:21:15 +0100 Subject: [PATCH] Loriot integration - verification still needed (downlink not working correctly) --- .../SD1001/Loriot/downlink/converter.json | 19 +++++++++++++++++++ .../SD1001/Loriot/downlink/metadata.json | 3 +++ .../SD1001/Loriot/downlink/payload.json | 0 .../Yobiiq/SD1001/Loriot/downlink/result.json | 0 .../SD1001/Loriot/uplink/converter.json | 19 +++++++++++++++++++ .../Yobiiq/SD1001/Loriot/uplink/metadata.json | 3 +++ .../Yobiiq/SD1001/Loriot/uplink/payload.json | 0 .../Yobiiq/SD1001/Loriot/uplink/result.json | 0 8 files changed, 44 insertions(+) create mode 100644 VENDORS/Yobiiq/SD1001/Loriot/downlink/converter.json create mode 100644 VENDORS/Yobiiq/SD1001/Loriot/downlink/metadata.json create mode 100644 VENDORS/Yobiiq/SD1001/Loriot/downlink/payload.json create mode 100644 VENDORS/Yobiiq/SD1001/Loriot/downlink/result.json create mode 100644 VENDORS/Yobiiq/SD1001/Loriot/uplink/converter.json create mode 100644 VENDORS/Yobiiq/SD1001/Loriot/uplink/metadata.json create mode 100644 VENDORS/Yobiiq/SD1001/Loriot/uplink/payload.json create mode 100644 VENDORS/Yobiiq/SD1001/Loriot/uplink/result.json diff --git a/VENDORS/Yobiiq/SD1001/Loriot/downlink/converter.json b/VENDORS/Yobiiq/SD1001/Loriot/downlink/converter.json new file mode 100644 index 00000000..212c83ec --- /dev/null +++ b/VENDORS/Yobiiq/SD1001/Loriot/downlink/converter.json @@ -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= 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 + } \ No newline at end of file diff --git a/VENDORS/Yobiiq/SD1001/Loriot/downlink/metadata.json b/VENDORS/Yobiiq/SD1001/Loriot/downlink/metadata.json new file mode 100644 index 00000000..751fee8b --- /dev/null +++ b/VENDORS/Yobiiq/SD1001/Loriot/downlink/metadata.json @@ -0,0 +1,3 @@ +{ + "integrationName": "Loriot integration" +} \ No newline at end of file diff --git a/VENDORS/Yobiiq/SD1001/Loriot/downlink/payload.json b/VENDORS/Yobiiq/SD1001/Loriot/downlink/payload.json new file mode 100644 index 00000000..e69de29b diff --git a/VENDORS/Yobiiq/SD1001/Loriot/downlink/result.json b/VENDORS/Yobiiq/SD1001/Loriot/downlink/result.json new file mode 100644 index 00000000..e69de29b diff --git a/VENDORS/Yobiiq/SD1001/Loriot/uplink/converter.json b/VENDORS/Yobiiq/SD1001/Loriot/uplink/converter.json new file mode 100644 index 00000000..b526b65c --- /dev/null +++ b/VENDORS/Yobiiq/SD1001/Loriot/uplink/converter.json @@ -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 + } \ No newline at end of file diff --git a/VENDORS/Yobiiq/SD1001/Loriot/uplink/metadata.json b/VENDORS/Yobiiq/SD1001/Loriot/uplink/metadata.json new file mode 100644 index 00000000..751fee8b --- /dev/null +++ b/VENDORS/Yobiiq/SD1001/Loriot/uplink/metadata.json @@ -0,0 +1,3 @@ +{ + "integrationName": "Loriot integration" +} \ No newline at end of file diff --git a/VENDORS/Yobiiq/SD1001/Loriot/uplink/payload.json b/VENDORS/Yobiiq/SD1001/Loriot/uplink/payload.json new file mode 100644 index 00000000..e69de29b diff --git a/VENDORS/Yobiiq/SD1001/Loriot/uplink/result.json b/VENDORS/Yobiiq/SD1001/Loriot/uplink/result.json new file mode 100644 index 00000000..e69de29b