From 14077f95c012b7bf56d44f7c8cb7ac604682237e Mon Sep 17 00:00:00 2001 From: thingsboard017 Date: Wed, 11 Dec 2024 17:02:44 +0200 Subject: [PATCH 01/33] Revert "Added 4 LNS integrations for EM400-MUD" This reverts commit 7d86e764f4c835c702e588dab34a5c2a740737b5. --- .../ChirpStack/uplink/converter.json | 39 --------- .../EM400-MUD/ChirpStack/uplink/metadata.json | 4 - .../EM400-MUD/ChirpStack/uplink/payload.json | 48 ----------- .../ChirpStack/uplink/payload_1.json | 48 ----------- .../EM400-MUD/ChirpStack/uplink/result.json | 28 ------- .../EM400-MUD/ChirpStack/uplink/result_1.json | 28 ------- .../EM400-MUD/LORIOT/uplink/converter.json | 29 ------- .../EM400-MUD/LORIOT/uplink/metadata.json | 4 - .../EM400-MUD/LORIOT/uplink/payload.json | 17 ---- .../EM400-MUD/LORIOT/uplink/payload_1.json | 17 ---- .../EM400-MUD/LORIOT/uplink/result.json | 18 ---- .../EM400-MUD/LORIOT/uplink/result_1.json | 17 ---- .../uplink/converter.json | 39 --------- .../ThingsStackCommunity/uplink/metadata.json | 4 - .../ThingsStackCommunity/uplink/payload.json | 54 ------------ .../uplink/payload_1.json | 54 ------------ .../ThingsStackCommunity/uplink/result.json | 29 ------- .../ThingsStackCommunity/uplink/result_1.json | 29 ------- .../uplink/converter.json | 40 --------- .../uplink/metadata.json | 4 - .../ThingsStackIndustries/uplink/payload.json | 77 ------------------ .../uplink/payload_1.json | 77 ------------------ .../ThingsStackIndustries/uplink/result.json | 29 ------- .../uplink/result_1.json | 29 ------- VENDORS/Milesight/EM400-MUD/guide.md | 21 ----- VENDORS/Milesight/EM400-MUD/info.json | 6 -- VENDORS/Milesight/EM400-MUD/photo.png | Bin 46217 -> 0 bytes 27 files changed, 789 deletions(-) delete mode 100644 VENDORS/Milesight/EM400-MUD/ChirpStack/uplink/converter.json delete mode 100644 VENDORS/Milesight/EM400-MUD/ChirpStack/uplink/metadata.json delete mode 100644 VENDORS/Milesight/EM400-MUD/ChirpStack/uplink/payload.json delete mode 100644 VENDORS/Milesight/EM400-MUD/ChirpStack/uplink/payload_1.json delete mode 100644 VENDORS/Milesight/EM400-MUD/ChirpStack/uplink/result.json delete mode 100644 VENDORS/Milesight/EM400-MUD/ChirpStack/uplink/result_1.json delete mode 100644 VENDORS/Milesight/EM400-MUD/LORIOT/uplink/converter.json delete mode 100644 VENDORS/Milesight/EM400-MUD/LORIOT/uplink/metadata.json delete mode 100644 VENDORS/Milesight/EM400-MUD/LORIOT/uplink/payload.json delete mode 100644 VENDORS/Milesight/EM400-MUD/LORIOT/uplink/payload_1.json delete mode 100644 VENDORS/Milesight/EM400-MUD/LORIOT/uplink/result.json delete mode 100644 VENDORS/Milesight/EM400-MUD/LORIOT/uplink/result_1.json delete mode 100644 VENDORS/Milesight/EM400-MUD/ThingsStackCommunity/uplink/converter.json delete mode 100644 VENDORS/Milesight/EM400-MUD/ThingsStackCommunity/uplink/metadata.json delete mode 100644 VENDORS/Milesight/EM400-MUD/ThingsStackCommunity/uplink/payload.json delete mode 100644 VENDORS/Milesight/EM400-MUD/ThingsStackCommunity/uplink/payload_1.json delete mode 100644 VENDORS/Milesight/EM400-MUD/ThingsStackCommunity/uplink/result.json delete mode 100644 VENDORS/Milesight/EM400-MUD/ThingsStackCommunity/uplink/result_1.json delete mode 100644 VENDORS/Milesight/EM400-MUD/ThingsStackIndustries/uplink/converter.json delete mode 100644 VENDORS/Milesight/EM400-MUD/ThingsStackIndustries/uplink/metadata.json delete mode 100644 VENDORS/Milesight/EM400-MUD/ThingsStackIndustries/uplink/payload.json delete mode 100644 VENDORS/Milesight/EM400-MUD/ThingsStackIndustries/uplink/payload_1.json delete mode 100644 VENDORS/Milesight/EM400-MUD/ThingsStackIndustries/uplink/result.json delete mode 100644 VENDORS/Milesight/EM400-MUD/ThingsStackIndustries/uplink/result_1.json delete mode 100644 VENDORS/Milesight/EM400-MUD/guide.md delete mode 100644 VENDORS/Milesight/EM400-MUD/info.json delete mode 100644 VENDORS/Milesight/EM400-MUD/photo.png diff --git a/VENDORS/Milesight/EM400-MUD/ChirpStack/uplink/converter.json b/VENDORS/Milesight/EM400-MUD/ChirpStack/uplink/converter.json deleted file mode 100644 index 76438d0f..00000000 --- a/VENDORS/Milesight/EM400-MUD/ChirpStack/uplink/converter.json +++ /dev/null @@ -1,39 +0,0 @@ -{ - "name": "ChirpStack Uplink Decoder for EM400-MUD", - "type": "UPLINK", - "debugMode": false, - "debugSettings": { - "failuresEnabled": true, - "allEnabled": false, - "allEnabledUntil": 1733331880270 - }, - "configuration": { - "scriptLang": "TBEL", - "decoder": null, - "tbelDecoder": "var data = decodeToJson(payload);\nvar deviceName = data.deviceInfo.deviceName + \" \" + data.deviceInfo.devEui;\nvar deviceType = \"EM400-MUD\";\nvar groupName = null; // If groupName is not null - created device will be added to the entity group with such name.\nvar customerName = null; // If customerName is not null - created devices will be assigned to customer with such name. \n\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// If you want to parse incoming data somehow, you can add your code to this function.\n// input: bytes\n// expected output:\n// {\n// \"attributes\": {\"attributeKey\": \"attributeValue\"},\n// \"telemetry\": [{\"ts\": 1...1, \"values\": {\"telemetryKey\":\"telemetryValue\"}, {\"ts\": 1...2, \"values\": {\"telemetryKey\":\"telemetryValue\"}}]\n// }\n\nfunction decodePayload(input) {\n var output = {\n attributes: {},\n telemetry: []\n };\n \n // --- Decoding code --- //\n var decoded = {};\n for (var i = 0; i < input.length - 2 ; ) {\n var channel_id = input[i++] & 0xff;\n var channel_type = input[i++] & 0xff;\n \n // BATTERY\n if (channel_id === 0x01 && channel_type === 0x75) {\n decoded.battery = input[i];\n i += 1;\n }\n // TEMPERATURE\n else if (channel_id === 0x03 && channel_type === 0x67) {\n decoded.temperature = parseBytesToInt(input, i, 2, false) / 10;\n i += 2;\n }\n // DISTANCE\n else if (channel_id === 0x04 && channel_type === 0x82) {\n decoded.distance = parseBytesToInt(input, i, 2, false);\n i += 2;\n }\n // POSITION\n else if (channel_id === 0x05 && channel_type === 0x00) {\n decoded.position = input[i] === 0 ? \"normal\" : \"tilt\";\n i += 1;\n }\n // TEMPERATURE WITH ABNORMAL\n else if (channel_id === 0x83 && channel_type === 0x67) {\n decoded.temperature = parseBytesToInt(input, i, 2, false) / 10;\n decoded.temperature_abnormal = input[i + 2] == 0 ? false : true;\n i += 3;\n }\n // DISTANCE WITH ALARMING\n else if (channel_id === 0x84 && channel_type === 0x82) {\n decoded.distance = parseBytesToInt(input, i, 2, false);\n decoded.distance_alarming = input[i + 2] == 0 ? false : true;\n i += 3;\n }\n }\n\n output.telemetry = [{\n ts: timestamp,\n values: decoded\n }];\n \n // --- Decoding code --- //\n return output;\n}\n\n// --- attributes and telemetry objects ---\nvar telemetry = [];\nvar attributes = {};\n// --- attributes and telemetry objects ---\n\n// --- Timestamp parsing\nvar dateString = data.time;\ntimestamp = parseDateToTimestamp(dateString);\n// --- Timestamp parsing\n\n// Passing incoming bytes to decodePayload function, to get custom decoding\nvar customDecoding = decodePayload(base64ToBytes(data.data));\n\n\nattributes.eui = data.deviceInfo.devEui;\n\n// Collecting data to result\nif (customDecoding.?telemetry.size() > 0) {\n if (customDecoding.telemetry instanceof java.util.ArrayList) {\n foreach(telemetryObj: customDecoding.telemetry) {\n if (telemetryObj.ts != null && telemetryObj.values != null) {\n telemetry.add(telemetryObj);\n }\n }\n } else {\n telemetry.putAll(customDecoding.telemetry);\n }\n}\n\nif (customDecoding.?attributes.size() > 0) {\n attributes.putAll(customDecoding.attributes);\n}\n\n// You can add some keys manually to attributes or telemetry\nattributes.eui = data.deviceInfo.?devEui;\nattributes.devAddr = data.devAddr;\nattributes.fPort = data.fPort;\nattributes.applicationId = data.deviceInfo.?applicationId;\nattributes.applicationName = data.deviceInfo.?applicationName;\nattributes.tenantId = data.deviceInfo.?tenantId;\nattributes.tenantName = data.deviceInfo.?tenantName;\nattributes.deviceProfileId = data.deviceInfo.?deviceProfileId;\nattributes.deviceProfileName = data.deviceInfo.?deviceProfileName;\nattributes.frequency = data.txInfo.?frequency;\nattributes.bandwidth = data.txInfo.?modulation.?lora.?bandwidth;\nattributes.spreadingFactor = data.txInfo.?modulation.?lora.?spreadingFactor;\nattributes.codeRate = data.txInfo.?modulation.?lora.?codeRate;\n\nif(Boolean.parseBoolean(metadata[\"includeGatewayInfo\"])) {\n var gatewayInfo = getGatewayInfo();\n var addDataToTelemetry = {};\n addDataToTelemetry.snr = gatewayInfo.snr;\n addDataToTelemetry.rssi = gatewayInfo.rssi;\n addDataToTelemetry.channel = gatewayInfo.channel;\n addDataToTelemetry.rfChain = gatewayInfo.rfChain;\n addDataToTelemetry.fCnt = data.fCnt;\n \n telemetry = processTelemetryData(telemetry, addDataToTelemetry);\n}\n\nvar result = {\n deviceName: deviceName,\n deviceType: deviceType,\n // assetName: assetName,\n // assetType: assetType,\n attributes: attributes,\n telemetry: telemetry\n};\n\naddAdditionalInfoForDeviceMsg(result, customerName, groupName);\n\nreturn result;\n\nfunction addAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName) {\n if (customerName != null) {\n deviceInfo.customerName = customerName;\n }\n if (groupName != null) {\n deviceInfo.groupName = groupName;\n }\n}\n\nfunction parseDateToTimestamp(dateString) {\n var date = new Date(dateString);\n var timestamp = date.getTime();\n \n // If we cannot parse timestamp - we will use the current timestamp\n if (timestamp == -1) {\n timestamp = Date.now();\n }\n \n return timestamp;\n}\n\nfunction getGatewayInfo() {\n var gatewayList = data.rxInfo;\n var maxRssi = Integer.MIN_VALUE;\n var gatewayInfo = {};\n \n foreach (gateway : gatewayList) {\n if(gateway.rssi > maxRssi) {\n maxRssi = gateway.rssi;\n gatewayInfo = gateway;\n }\n }\n \n return gatewayInfo;\n}\n\nfunction processTelemetryData(telemetry, addDataToTelemetry) {\n if (telemetry.size >= 1) {\n telemetry = addDataToTelemetries(telemetry, addDataToTelemetry);\n }\n else {\n telemetry.add(addDataToTelemetry);\n }\n \n return telemetry;\n}\n\nfunction addDataToTelemetries(telemetries, addDataToTelemetry) {\n foreach(telemetry : telemetries) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[\"values\"].keys.contains(element.key)) {\n telemetry[\"values\"][element.key] = element.value;\n }\n } \n }\n \n return telemetries;\n}", - "encoder": null, - "tbelEncoder": null, - "updateOnlyKeys": [ - "tenantId", - "tenantName", - "applicationId", - "applicationName", - "deviceProfileId", - "deviceProfileName", - "devAddr", - "fPort", - "frequency", - "bandwidth", - "spreadingFactor", - "codeRate", - "channel", - "rfChain", - "eui", - "battery" - ] - }, - "additionalInfo": { - "description": "" - }, - "edgeTemplate": false -} \ No newline at end of file diff --git a/VENDORS/Milesight/EM400-MUD/ChirpStack/uplink/metadata.json b/VENDORS/Milesight/EM400-MUD/ChirpStack/uplink/metadata.json deleted file mode 100644 index 23f54b34..00000000 --- a/VENDORS/Milesight/EM400-MUD/ChirpStack/uplink/metadata.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "integrationName": "ChirpStack integration", - "includeGatewayInfo": "false" -} \ No newline at end of file diff --git a/VENDORS/Milesight/EM400-MUD/ChirpStack/uplink/payload.json b/VENDORS/Milesight/EM400-MUD/ChirpStack/uplink/payload.json deleted file mode 100644 index 3e3584b0..00000000 --- a/VENDORS/Milesight/EM400-MUD/ChirpStack/uplink/payload.json +++ /dev/null @@ -1,48 +0,0 @@ -{ - "deduplicationId": "57433366-50a6-4dc2-8145-2df1bbc70d9e", - "time": "2023-05-22T07:47:05.404859+00:00", - "deviceInfo": { - "tenantId": "52f14cd4-c6f1-4fbd-8f87-4025e1d49242", - "tenantName": "ChirpStack", - "applicationId": "ca739e26-7b67-4f14-b69e-d568c22a5a75", - "applicationName": "Chirpstack application", - "deviceProfileId": "605d08d4-65f5-4d2c-8a5a-3d2457662f79", - "deviceProfileName": "Chirpstack default device profile", - "deviceName": "Device name", - "devEui": "1000000000000001", - "tags": {} - }, - "devAddr": "20000001", - "adr": true, - "dr": 5, - "fCnt": 4, - "fPort": 85, - "confirmed": false, - "data": "g2foAAGEgkEGAQ==", - "rxInfo": [{ - "gatewayId": "6a7e111a10000000", - "uplinkId": 24022, - "time": "2023-05-22T07:47:05.404859+00:00", - "rssi": -35, - "snr": 11.5, - "channel": 2, - "rfChain": 1, - "location": {}, - "context": "EFwMtA==", - "metadata": { - "region_common_name": "EU868", - "region_config_id": "eu868" - }, - "crcStatus": "CRC_OK" - }], - "txInfo": { - "frequency": 868500000, - "modulation": { - "lora": { - "bandwidth": 125000, - "spreadingFactor": 7, - "codeRate": "CR_4_5" - } - } - } -} \ No newline at end of file diff --git a/VENDORS/Milesight/EM400-MUD/ChirpStack/uplink/payload_1.json b/VENDORS/Milesight/EM400-MUD/ChirpStack/uplink/payload_1.json deleted file mode 100644 index 154ca2e8..00000000 --- a/VENDORS/Milesight/EM400-MUD/ChirpStack/uplink/payload_1.json +++ /dev/null @@ -1,48 +0,0 @@ -{ - "deduplicationId": "57433366-50a6-4dc2-8145-2df1bbc70d9e", - "time": "2023-05-22T07:47:05.404859+00:00", - "deviceInfo": { - "tenantId": "52f14cd4-c6f1-4fbd-8f87-4025e1d49242", - "tenantName": "ChirpStack", - "applicationId": "ca739e26-7b67-4f14-b69e-d568c22a5a75", - "applicationName": "Chirpstack application", - "deviceProfileId": "605d08d4-65f5-4d2c-8a5a-3d2457662f79", - "deviceProfileName": "Chirpstack default device profile", - "deviceName": "Device name", - "devEui": "1000000000000001", - "tags": {} - }, - "devAddr": "20000001", - "adr": true, - "dr": 5, - "fCnt": 4, - "fPort": 85, - "confirmed": false, - "data": "AXVcA2cBAQSCRAgFAAE=", - "rxInfo": [{ - "gatewayId": "6a7e111a10000000", - "uplinkId": 24022, - "time": "2023-05-22T07:47:05.404859+00:00", - "rssi": -35, - "snr": 11.5, - "channel": 2, - "rfChain": 1, - "location": {}, - "context": "EFwMtA==", - "metadata": { - "region_common_name": "EU868", - "region_config_id": "eu868" - }, - "crcStatus": "CRC_OK" - }], - "txInfo": { - "frequency": 868500000, - "modulation": { - "lora": { - "bandwidth": 125000, - "spreadingFactor": 7, - "codeRate": "CR_4_5" - } - } - } -} \ No newline at end of file diff --git a/VENDORS/Milesight/EM400-MUD/ChirpStack/uplink/result.json b/VENDORS/Milesight/EM400-MUD/ChirpStack/uplink/result.json deleted file mode 100644 index 17e42a98..00000000 --- a/VENDORS/Milesight/EM400-MUD/ChirpStack/uplink/result.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "deviceName": "Device name 1000000000000001", - "deviceType": "EM400-MUD", - "attributes": { - "eui": "1000000000000001", - "devAddr": "20000001", - "fPort": 85, - "applicationId": "ca739e26-7b67-4f14-b69e-d568c22a5a75", - "applicationName": "Chirpstack application", - "tenantId": "52f14cd4-c6f1-4fbd-8f87-4025e1d49242", - "tenantName": "ChirpStack", - "deviceProfileId": "605d08d4-65f5-4d2c-8a5a-3d2457662f79", - "deviceProfileName": "Chirpstack default device profile", - "frequency": 868500000, - "bandwidth": 125000, - "spreadingFactor": 7, - "codeRate": "CR_4_5" - }, - "telemetry": [{ - "ts": 1684741625404, - "values": { - "temperature": 23.2, - "temperature_abnormal": true, - "distance": 1601, - "distance_alarming": true - } - }] -} \ No newline at end of file diff --git a/VENDORS/Milesight/EM400-MUD/ChirpStack/uplink/result_1.json b/VENDORS/Milesight/EM400-MUD/ChirpStack/uplink/result_1.json deleted file mode 100644 index 95b95f33..00000000 --- a/VENDORS/Milesight/EM400-MUD/ChirpStack/uplink/result_1.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "deviceName": "Device name 1000000000000001", - "deviceType": "EM400-MUD", - "attributes": { - "eui": "1000000000000001", - "devAddr": "20000001", - "fPort": 85, - "applicationId": "ca739e26-7b67-4f14-b69e-d568c22a5a75", - "applicationName": "Chirpstack application", - "tenantId": "52f14cd4-c6f1-4fbd-8f87-4025e1d49242", - "tenantName": "ChirpStack", - "deviceProfileId": "605d08d4-65f5-4d2c-8a5a-3d2457662f79", - "deviceProfileName": "Chirpstack default device profile", - "frequency": 868500000, - "bandwidth": 125000, - "spreadingFactor": 7, - "codeRate": "CR_4_5" - }, - "telemetry": [{ - "ts": 1684741625404, - "values": { - "battery": 92, - "temperature": 25.7, - "distance": 2116, - "position": "tilt" - } - }] -} \ No newline at end of file diff --git a/VENDORS/Milesight/EM400-MUD/LORIOT/uplink/converter.json b/VENDORS/Milesight/EM400-MUD/LORIOT/uplink/converter.json deleted file mode 100644 index fa75430a..00000000 --- a/VENDORS/Milesight/EM400-MUD/LORIOT/uplink/converter.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "name": "Loriot Uplink Decoder for EM400-MUD", - "type": "UPLINK", - "debugMode": false, - "debugSettings": { - "failuresEnabled": true, - "allEnabled": false, - "allEnabledUntil": 1733331880270 - }, - "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);\nvar deviceName = data.EUI;\nvar deviceType = \"EM400-MUD\";\nvar groupName = null; // If groupName is not null - created device will be added to the entity group with such name.\nvar customerName = null; // If customerName is not null - created devices will be assigned to customer with such name. \n\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// If you want to parse incoming data somehow, you can add your code to this function.\n// input: bytes\n// expected output:\n// {\n// \"attributes\": {\"attributeKey\": \"attributeValue\"},\n// \"telemetry\": {\"telemetryKey\": \"telemetryValue\"}\n// }\n\nfunction decodePayload(input) {\n var output = { attributes: {}, telemetry: []};\n \n var decoded = {};\n for (var i = 0; i < input.length - 2 ; ) {\n var channel_id = input[i++] & 0xff;\n var channel_type = input[i++] & 0xff;\n \n // BATTERY\n if (channel_id === 0x01 && channel_type === 0x75) {\n decoded.battery = input[i];\n i += 1;\n }\n // TEMPERATURE\n else if (channel_id === 0x03 && channel_type === 0x67) {\n decoded.temperature = parseBytesToInt(input, i, 2, false) / 10;\n i += 2;\n }\n // DISTANCE\n else if (channel_id === 0x04 && channel_type === 0x82) {\n decoded.distance = parseBytesToInt(input, i, 2, false);\n i += 2;\n }\n // POSITION\n else if (channel_id === 0x05 && channel_type === 0x00) {\n decoded.position = input[i] === 0 ? \"normal\" : \"tilt\";\n i += 1;\n }\n // TEMPERATURE WITH ABNORMAL\n else if (channel_id === 0x83 && channel_type === 0x67) {\n decoded.temperature = parseBytesToInt(input, i, 2, false) / 10;\n decoded.temperature_abnormal = input[i + 2] == 0 ? false : true;\n i += 3;\n }\n // DISTANCE WITH ALARMING\n else if (channel_id === 0x84 && channel_type === 0x82) {\n decoded.distance = parseBytesToInt(input, i, 2, false);\n decoded.distance_alarming = input[i + 2] == 0 ? false : true;\n i += 3;\n }\n }\n \n output.telemetry = [{\n ts: timestamp,\n values: decoded\n }];\n\n // --- Decoding code --- //\n return output;\n}\n\n// --- attributes and telemetry objects ---\nvar telemetry = [];\nvar attributes = {};\n// --- attributes and telemetry objects ---\n\n// --- Timestamp parsing\ntimestamp = data.ts;\n// --- Timestamp parsing\n\n// Message parsing\n// To avoid paths in the decoded objects we passing false value to function as \"pathInKey\" argument.\n// Warning: pathInKey can cause already found fields to be overwritten with the last value found.\n\nvar uplinkDataList = [];\n\n// Passing incoming bytes to decodePayload function, to get custom decoding\nvar customDecoding = decodePayload(hexToBytes(data.data));\n\n// Collecting data to result\nif (customDecoding.?telemetry.size() > 0) {\n if (customDecoding.telemetry instanceof java.util.ArrayList) {\n foreach(telemetryObj: customDecoding.telemetry) {\n if (telemetryObj.ts != null && telemetryObj.values != null) {\n telemetry.add(telemetryObj);\n }\n }\n } else {\n telemetry.putAll(customDecoding.telemetry);\n }\n}\n\nif (customDecoding.?attributes.size() > 0) {\n attributes.putAll(customDecoding.attributes);\n}\n\n// You can add some keys manually to attributes or telemetry\nattributes.eui = data.EUI;\nattributes.fPort = data.port;\nattributes.frequency = data.freq;\n\nvar isIncludeGatewayInfo = metadata[\"includeGatewayInfo\"];\nif(isIncludeGatewayInfo == true) {\n var addDataToTelemetry = {};\n addDataToTelemetry.rssi = data.rssi;\n addDataToTelemetry.seqno = data.seqno;\n addDataToTelemetry.snr = data.snr;\n addDataToTelemetry.ack = data.ack;\n addDataToTelemetry.toa = data.toa;\n addDataToTelemetry.fCnt = data.fcnt;\n \n telemetry = processTelemetryData(telemetry, addDataToTelemetry);\n}\n\nvar deviceInfo = {\n deviceName: deviceName,\n deviceType: deviceType,\n// assetName: assetName,\n// assetType: assetType,\n attributes: attributes,\n telemetry: telemetry, \n};\n\naddAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName);\n\nuplinkDataList.add(deviceInfo);\n\nvar gatewayDeviceNamePrefix = \"Gateway \";\nvar gatewayDeviceType = \"Lora gateway\";\nvar gatewayGroupName = null; // If gatewayGroupName is not null - created device will be added to the entity group with such name.\n\nif (data.cmd == \"gw\") {\n foreach( gatewayInfo : data.gws ) {\n var addGatewayInfo = {};\n\n // You can add some keys manually telemetry\n addGatewayInfo.rssi = gatewayInfo.rssi;\n addGatewayInfo.snr = gatewayInfo.snr;\n // You can add some keys manually telemetry\n \n var gatewayInfoMsg = {\n deviceName: gatewayDeviceNamePrefix + gatewayInfo.gweui,\n deviceType: gatewayDeviceType,\n telemetry: [{\n \"ts\": gatewayInfo.ts,\n \"values\": addGatewayInfo\n }],\n attributes: {\n eui: gatewayInfo.gweui\n }\n };\n addAdditionalInfoForDeviceMsg(gatewayInfoMsg, customerName, gatewayGroupName);\n uplinkDataList.add(gatewayInfoMsg);\n }\n}\n\nreturn uplinkDataList;\n\nfunction addAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName) {\n if (customerName != null) {\n deviceInfo.customerName = customerName;\n }\n if (groupName != null) {\n deviceInfo.groupName = groupName;\n }\n}\n\nfunction processTelemetryData(telemetry, addDataToTelemetry) {\n if (telemetry.size >= 1) {\n telemetry = addDataToTelemetries(telemetry, addDataToTelemetry);\n }\n else {\n telemetry.add(addDataToTelemetry);\n }\n \n return telemetry;\n}\n\nfunction addDataToTelemetries(telemetries, addDataToTelemetry) {\n foreach(telemetry : telemetries) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[\"values\"].keys.contains(element.key)) {\n telemetry[\"values\"][element.key] = element.value;\n }\n } \n }\n \n return telemetries;\n}", - "encoder": null, - "tbelEncoder": null, - "updateOnlyKeys": [ - "fPort", - "ack", - "eui", - "frequency", - "dr", - "battery" - ] - }, - "additionalInfo": { - "description": "" - }, - "edgeTemplate": false -} \ No newline at end of file diff --git a/VENDORS/Milesight/EM400-MUD/LORIOT/uplink/metadata.json b/VENDORS/Milesight/EM400-MUD/LORIOT/uplink/metadata.json deleted file mode 100644 index ae2ee743..00000000 --- a/VENDORS/Milesight/EM400-MUD/LORIOT/uplink/metadata.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "integrationName": "Loriot integration", - "includeGatewayInfo": "false" -} \ No newline at end of file diff --git a/VENDORS/Milesight/EM400-MUD/LORIOT/uplink/payload.json b/VENDORS/Milesight/EM400-MUD/LORIOT/uplink/payload.json deleted file mode 100644 index 95879188..00000000 --- a/VENDORS/Milesight/EM400-MUD/LORIOT/uplink/payload.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "cmd": "rx", - "seqno": 3040, - "EUI": "1000000000000001", - "ts": 1684478801936, - "fcnt": 2, - "port": 85, - "freq": 867500000, - "rssi": -21, - "snr": 10, - "toa": 206, - "dr": "SF9 BW125 4/5", - "ack": false, - "bat": 94, - "offline": false, - "data": "8367e800018482410601" -} \ No newline at end of file diff --git a/VENDORS/Milesight/EM400-MUD/LORIOT/uplink/payload_1.json b/VENDORS/Milesight/EM400-MUD/LORIOT/uplink/payload_1.json deleted file mode 100644 index ef349fd0..00000000 --- a/VENDORS/Milesight/EM400-MUD/LORIOT/uplink/payload_1.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "cmd": "rx", - "seqno": 3040, - "EUI": "1000000000000001", - "ts": 1684478801936, - "fcnt": 2, - "port": 85, - "freq": 867500000, - "rssi": -21, - "snr": 10, - "toa": 206, - "dr": "SF9 BW125 4/5", - "ack": false, - "bat": 94, - "offline": false, - "data": "01755C0367010104824408050001" -} \ No newline at end of file diff --git a/VENDORS/Milesight/EM400-MUD/LORIOT/uplink/result.json b/VENDORS/Milesight/EM400-MUD/LORIOT/uplink/result.json deleted file mode 100644 index 6961bcfc..00000000 --- a/VENDORS/Milesight/EM400-MUD/LORIOT/uplink/result.json +++ /dev/null @@ -1,18 +0,0 @@ -[{ - "deviceName": "1000000000000001", - "deviceType": "EM400-MUD", - "attributes": { - "eui": "1000000000000001", - "fPort": 85, - "frequency": 867500000 - }, - "telemetry": [{ - "ts": 1684478801936, - "values": { - "temperature": 23.2, - "temperature_abnormal": true, - "distance": 1601, - "distance_alarming": true - } - }] -}] \ No newline at end of file diff --git a/VENDORS/Milesight/EM400-MUD/LORIOT/uplink/result_1.json b/VENDORS/Milesight/EM400-MUD/LORIOT/uplink/result_1.json deleted file mode 100644 index ef349fd0..00000000 --- a/VENDORS/Milesight/EM400-MUD/LORIOT/uplink/result_1.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "cmd": "rx", - "seqno": 3040, - "EUI": "1000000000000001", - "ts": 1684478801936, - "fcnt": 2, - "port": 85, - "freq": 867500000, - "rssi": -21, - "snr": 10, - "toa": 206, - "dr": "SF9 BW125 4/5", - "ack": false, - "bat": 94, - "offline": false, - "data": "01755C0367010104824408050001" -} \ No newline at end of file diff --git a/VENDORS/Milesight/EM400-MUD/ThingsStackCommunity/uplink/converter.json b/VENDORS/Milesight/EM400-MUD/ThingsStackCommunity/uplink/converter.json deleted file mode 100644 index 281b7222..00000000 --- a/VENDORS/Milesight/EM400-MUD/ThingsStackCommunity/uplink/converter.json +++ /dev/null @@ -1,39 +0,0 @@ -{ - "name": "The Things Stack Community Uplink Decoder for EM400-MUD", - "type": "UPLINK", - "debugMode": false, - "debugSettings": { - "failuresEnabled": true, - "allEnabled": false, - "allEnabledUntil": 1733331880270 - }, - "configuration": { - "scriptLang": "TBEL", - "decoder": null, - "tbelDecoder": "var data = decodeToJson(payload);\n\nvar deviceName = data.end_device_ids.device_id;\nvar deviceType = \"EM400-MUD\";\nvar groupName = null; // If groupName is not null - created device will be added to the entity group with such name.\nvar customerName = null; // If customerName is not null - created devices will be assigned to customer with such name. \n\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// If you want to parse incoming data somehow, you can add your code to this function.\n// input: bytes\n// expected output:\n// {\n// \"attributes\": {\"attributeKey\": \"attributeValue\"},\n// \"telemetry\": [{\"ts\": 1...1, \"values\": {\"telemetryKey\":\"telemetryValue\"}, {\"ts\": 1...2, \"values\": {\"telemetryKey\":\"telemetryValue\"}}]\n// }\n\nfunction decodeFrmPayload(input) {\n var output = {\n attributes: {}, telemetry: {}\n };\n \n // --- Decoding code --- //\n var decoded = {};\n for (var i = 0; i < input.length - 2 ; ) {\n var channel_id = input[i++] & 0xff;\n var channel_type = input[i++] & 0xff;\n\n // BATTERY\n if (channel_id === 0x01 && channel_type === 0x75) {\n decoded.battery = input[i];\n i += 1;\n }\n // TEMPERATURE\n else if (channel_id === 0x03 && channel_type === 0x67) {\n decoded.temperature = parseBytesToInt(input, i, 2, false) / 10;\n i += 2;\n }\n // DISTANCE\n else if (channel_id === 0x04 && channel_type === 0x82) {\n decoded.distance = parseBytesToInt(input, i, 2, false);\n i += 2;\n }\n // POSITION\n else if (channel_id === 0x05 && channel_type === 0x00) {\n decoded.position = input[i] === 0 ? \"normal\" : \"tilt\";\n i += 1;\n }\n // TEMPERATURE WITH ABNORMAL\n else if (channel_id === 0x83 && channel_type === 0x67) {\n decoded.temperature = parseBytesToInt(input, i, 2, false) / 10;\n decoded.temperature_abnormal = input[i + 2] == 0 ? false : true;\n i += 3;\n }\n // DISTANCE WITH ALARMING\n else if (channel_id === 0x84 && channel_type === 0x82) {\n decoded.distance = parseBytesToInt(input, i, 2, false);\n decoded.distance_alarming = input[i + 2] == 0 ? false : true;\n i += 3;\n }\n }\n \n output.telemetry = [{\n ts: timestamp,\n values: decoded\n }];\n \n // --- Decoding code --- //\n return output;\n}\n\n\n// --- attributes and telemetry objects ---\nvar telemetry = [];\nvar attributes = {};\n// --- attributes and telemetry objects ---\n\n// --- Timestamp parsing\nvar dateString = data.uplink_message.received_at;\n// If data is simulated or device doesn't send his own date string - we will use date from upcoming message, set by network server\nif ((data.simulated != null && data.simulated) || dateString == null) {\n dateString = data.received_at;\n}\ntimestamp = parseDateToTimestamp(dateString);\n// --- Timestamp parsing\n\n// Message parsing\n// To avoid paths in the decoded objects we passing false value to function as \"pathInKey\" argument.\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.\n\n// Passing incoming bytes to decodeFrmPayload function, to get custom decoding\nvar customDecoding = {};\nif (data.uplink_message.get(\"frm_payload\") != null) {\n customDecoding = decodeFrmPayload(base64ToBytes(data.uplink_message.frm_payload));\n}\n\n// Collecting data to result\nif (customDecoding.?telemetry.size() > 0) {\n if (customDecoding.telemetry instanceof java.util.ArrayList) {\n foreach(telemetryObj: customDecoding.telemetry) {\n if (telemetryObj.ts != null && telemetryObj.values != null) {\n telemetry.add(telemetryObj);\n }\n }\n } else {\n telemetry.putAll(customDecoding.telemetry);\n }\n}\n\nif (customDecoding.?attributes.size() > 0) {\n attributes.putAll(customDecoding.attributes);\n}\n\n// You can add some keys manually to attributes or telemetry\nvar applicationId = data.end_device_ids.?application_ids.?application_id;\nvar devAddr = data.end_device_ids.?dev_addr;\nvar spreadingFactor = data.uplink_message.?settings.?data_rate.?lora.?spreading_factor;\nvar codeRate = data.uplink_message.?settings.?data_rate.?lora.?coding_rate;\nvar tenantId = data.uplink_message.?network_ids.?tenant_id;\nattributes.eui = data.end_device_ids.dev_eui;\nattributes.fPort = data.uplink_message.f_port;\nattributes.applicationId = applicationId;\nattributes.devAddr = devAddr;\nattributes.spreadingFactor = spreadingFactor;\nattributes.codeRate = codeRate;\nattributes.tenantId = tenantId;\nattributes.device_id = data.end_device_ids.?device_id;\nattributes.join_eui = data.end_device_ids.?join_eui;\nattributes.net_id = data.uplink_message.?network_ids.?net_id;\nattributes.cluster_id = data.uplink_message.?network_ids.?cluster_id;\nattributes.cluster_adress = data.uplink_message.?network_ids.?cluster_address;\nattributes.bandwidth = data.uplink_message.?settings.?data_rate.?lora.?bandwidth;\nattributes.frequency = data.uplink_message.?settings.?frequency;\n\n\nvar gatewayInfo = getGatewayInfo();\nvar addDataToTelemetry = {};\naddDataToTelemetry.snr = gatewayInfo.snr;\naddDataToTelemetry.rssi = gatewayInfo.rssi;\naddDataToTelemetry.channel = gatewayInfo.channel_index;\naddDataToTelemetry.consumed_airtime = data.uplink_message.?consumed_airtime;\naddDataToTelemetry.fCnt = data.uplink_message.?f_cnt;\n\nvar isIncludeGatewayInfo = metadata[\"includeGatewayInfo\"];\nif(isIncludeGatewayInfo == true) {\n telemetry = processTelemetryData(telemetry, addDataToTelemetry);\n}\n\nvar result = {\n deviceName: deviceName,\n deviceType: deviceType,\n// assetName: assetName,\n// assetType: assetType,\n attributes: attributes,\n telemetry: telemetry\n};\n\naddAdditionalInfoForDeviceMsg(result, customerName, groupName);\n\nreturn result;\n\n\nfunction addAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName) {\n if (customerName != null) {\n deviceInfo.customerName = customerName;\n }\n if (groupName != null) {\n deviceInfo.groupName = groupName;\n }\n}\n\nfunction parseDateToTimestamp(dateString) {\n var date = new Date(dateString);\n var timestamp = date.getTime();\n \n // If we cannot parse timestamp - we will use the current timestamp\n if (timestamp == -1) {\n timestamp = Date.now();\n }\n \n return timestamp;\n}\n\nfunction getGatewayInfo() {\n var gatewayList = data.uplink_message.?rx_metadata;\n var maxRssi = Integer.MIN_VALUE;\n var gatewayInfo = {};\n \n foreach (gateway : gatewayList) {\n if(gateway.rssi > maxRssi) {\n maxRssi = gateway.rssi;\n gatewayInfo = gateway;\n }\n }\n \n return gatewayInfo;\n}\n\nfunction processTelemetryData(telemetry, addDataToTelemetry) {\n if (telemetry.size >= 1) {\n telemetry = addDataToTelemetries(telemetry, addDataToTelemetry);\n }\n else {\n telemetry.add(addDataToTelemetry);\n }\n \n return telemetry;\n}\n\nfunction addDataToTelemetries(telemetries, addDataToTelemetry) {\n foreach(telemetry : telemetries) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[\"values\"].keys.contains(element.key)) {\n telemetry[\"values\"][element.key] = element.value;\n }\n } \n }\n \n return telemetries;\n}", - "encoder": null, - "tbelEncoder": null, - "updateOnlyKeys": [ - "fPort", - "bandwidth", - "frequency", - "net_id", - "cluster_id", - "cluster_address", - "device_id", - "join_eui", - "battery", - "eui", - "channel", - "applicationId", - "devAddr", - "spreadingFactor", - "codeRate", - "tenantId" - ] - }, - "additionalInfo": { - "description": "" - }, - "edgeTemplate": false -} \ No newline at end of file diff --git a/VENDORS/Milesight/EM400-MUD/ThingsStackCommunity/uplink/metadata.json b/VENDORS/Milesight/EM400-MUD/ThingsStackCommunity/uplink/metadata.json deleted file mode 100644 index 0d75c374..00000000 --- a/VENDORS/Milesight/EM400-MUD/ThingsStackCommunity/uplink/metadata.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "integrationName": "The Things Stack Community integration", - "includeGatewayInfo": "false" -} \ No newline at end of file diff --git a/VENDORS/Milesight/EM400-MUD/ThingsStackCommunity/uplink/payload.json b/VENDORS/Milesight/EM400-MUD/ThingsStackCommunity/uplink/payload.json deleted file mode 100644 index 281d8f45..00000000 --- a/VENDORS/Milesight/EM400-MUD/ThingsStackCommunity/uplink/payload.json +++ /dev/null @@ -1,54 +0,0 @@ -{ - "end_device_ids": { - "device_id": "eui-1000000000000001", - "application_ids": { - "application_id": "application-tts-name" - }, - "dev_eui": "1000000000000001", - "join_eui": "2000000000000001", - "dev_addr": "20000001" - }, - "correlation_ids": ["as:up:01H0S7ZJQ9MQPMVY49FT3SE07M", "gs:conn:01H03BQZ9342X3Y86DJ2P704E5", "gs:up:host:01H03BQZ99EGAM52KK1300GFKN", "gs:uplink:01H0S7ZJGS6D9TJSKJN8XNTMAV", "ns:uplink:01H0S7ZJGS9KKD4HTTPKFEMWCV", "rpc:/ttn.lorawan.v3.GsNs/HandleUplink:01H0S7ZJGSF3M38ZRZVTM38DEC", "rpc:/ttn.lorawan.v3.NsAs/HandleUplink:01H0S7ZJQ8R2EH5AA269AKM8DX"], - "received_at": "2023-05-19T05:33:35.848446463Z", - "uplink_message": { - "session_key_id": "AYfqmb0pc/1uRZv9xUydgQ==", - "f_port": 85, - "f_cnt": 10335, - "frm_payload": "g2foAAGEgkEGAQ==", - "rx_metadata": [{ - "gateway_ids": { - "gateway_id": "eui-6a7e111a10000000", - "eui": "6A7E111A10000000" - }, - "time": "2023-05-19T05:33:35.608982Z", - "timestamp": 3893546133, - "rssi": -35, - "channel_rssi": -35, - "snr": 13.2, - "frequency_offset": "69", - "uplink_token": "CiIKIAoUZXVpLTZhN2UxMTFhMTAwMDAwMDASCCThJP/+9k6eEJWZy8AOGgwIr5ScowYQvNbUsQIgiMy8y6jwpwE=", - "channel_index": 3, - "received_at": "2023-05-19T05:33:35.607383681Z" - }], - "settings": { - "data_rate": { - "lora": { - "bandwidth": 125000, - "spreading_factor": 7, - "coding_rate": "4/5" - } - }, - "frequency": "867100000", - "timestamp": 3893546133, - "time": "2023-05-19T05:33:35.608982Z" - }, - "received_at": "2023-05-19T05:33:35.641841782Z", - "consumed_airtime": "0.056576s", - "network_ids": { - "net_id": "000013", - "tenant_id": "ttn", - "cluster_id": "eu1", - "cluster_address": "eu1.cloud.thethings.network" - } - } -} \ No newline at end of file diff --git a/VENDORS/Milesight/EM400-MUD/ThingsStackCommunity/uplink/payload_1.json b/VENDORS/Milesight/EM400-MUD/ThingsStackCommunity/uplink/payload_1.json deleted file mode 100644 index 76ae9bd5..00000000 --- a/VENDORS/Milesight/EM400-MUD/ThingsStackCommunity/uplink/payload_1.json +++ /dev/null @@ -1,54 +0,0 @@ -{ - "end_device_ids": { - "device_id": "eui-1000000000000001", - "application_ids": { - "application_id": "application-tts-name" - }, - "dev_eui": "1000000000000001", - "join_eui": "2000000000000001", - "dev_addr": "20000001" - }, - "correlation_ids": ["as:up:01H0S7ZJQ9MQPMVY49FT3SE07M", "gs:conn:01H03BQZ9342X3Y86DJ2P704E5", "gs:up:host:01H03BQZ99EGAM52KK1300GFKN", "gs:uplink:01H0S7ZJGS6D9TJSKJN8XNTMAV", "ns:uplink:01H0S7ZJGS9KKD4HTTPKFEMWCV", "rpc:/ttn.lorawan.v3.GsNs/HandleUplink:01H0S7ZJGSF3M38ZRZVTM38DEC", "rpc:/ttn.lorawan.v3.NsAs/HandleUplink:01H0S7ZJQ8R2EH5AA269AKM8DX"], - "received_at": "2023-05-19T05:33:35.848446463Z", - "uplink_message": { - "session_key_id": "AYfqmb0pc/1uRZv9xUydgQ==", - "f_port": 85, - "f_cnt": 10335, - "frm_payload": "AXVcA2cBAQSCRAgFAAE=", - "rx_metadata": [{ - "gateway_ids": { - "gateway_id": "eui-6a7e111a10000000", - "eui": "6A7E111A10000000" - }, - "time": "2023-05-19T05:33:35.608982Z", - "timestamp": 3893546133, - "rssi": -35, - "channel_rssi": -35, - "snr": 13.2, - "frequency_offset": "69", - "uplink_token": "CiIKIAoUZXVpLTZhN2UxMTFhMTAwMDAwMDASCCThJP/+9k6eEJWZy8AOGgwIr5ScowYQvNbUsQIgiMy8y6jwpwE=", - "channel_index": 3, - "received_at": "2023-05-19T05:33:35.607383681Z" - }], - "settings": { - "data_rate": { - "lora": { - "bandwidth": 125000, - "spreading_factor": 7, - "coding_rate": "4/5" - } - }, - "frequency": "867100000", - "timestamp": 3893546133, - "time": "2023-05-19T05:33:35.608982Z" - }, - "received_at": "2023-05-19T05:33:35.641841782Z", - "consumed_airtime": "0.056576s", - "network_ids": { - "net_id": "000013", - "tenant_id": "ttn", - "cluster_id": "eu1", - "cluster_address": "eu1.cloud.thethings.network" - } - } -} \ No newline at end of file diff --git a/VENDORS/Milesight/EM400-MUD/ThingsStackCommunity/uplink/result.json b/VENDORS/Milesight/EM400-MUD/ThingsStackCommunity/uplink/result.json deleted file mode 100644 index 11b7016b..00000000 --- a/VENDORS/Milesight/EM400-MUD/ThingsStackCommunity/uplink/result.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "deviceName": "eui-1000000000000001", - "deviceType": "EM400-MUD", - "attributes": { - "eui": "1000000000000001", - "fPort": 85, - "applicationId": "application-tts-name", - "devAddr": "20000001", - "spreadingFactor": 7, - "codeRate": "4/5", - "tenantId": "ttn", - "device_id": "eui-1000000000000001", - "join_eui": "2000000000000001", - "net_id": "000013", - "cluster_id": "eu1", - "cluster_adress": "eu1.cloud.thethings.network", - "bandwidth": 125000, - "frequency": "867100000" - }, - "telemetry": [{ - "ts": 1684474415641, - "values": { - "temperature": 23.2, - "temperature_abnormal": true, - "distance": 1601, - "distance_alarming": true - } - }] -} \ No newline at end of file diff --git a/VENDORS/Milesight/EM400-MUD/ThingsStackCommunity/uplink/result_1.json b/VENDORS/Milesight/EM400-MUD/ThingsStackCommunity/uplink/result_1.json deleted file mode 100644 index 845fad27..00000000 --- a/VENDORS/Milesight/EM400-MUD/ThingsStackCommunity/uplink/result_1.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "deviceName": "eui-1000000000000001", - "deviceType": "EM400-MUD", - "attributes": { - "eui": "1000000000000001", - "fPort": 85, - "applicationId": "application-tts-name", - "devAddr": "20000001", - "spreadingFactor": 7, - "codeRate": "4/5", - "tenantId": "ttn", - "device_id": "eui-1000000000000001", - "join_eui": "2000000000000001", - "net_id": "000013", - "cluster_id": "eu1", - "cluster_adress": "eu1.cloud.thethings.network", - "bandwidth": 125000, - "frequency": "867100000" - }, - "telemetry": [{ - "ts": 1684474415641, - "values": { - "battery": 92, - "temperature": 25.7, - "distance": 2116, - "position": "tilt" - } - }] -} \ No newline at end of file diff --git a/VENDORS/Milesight/EM400-MUD/ThingsStackIndustries/uplink/converter.json b/VENDORS/Milesight/EM400-MUD/ThingsStackIndustries/uplink/converter.json deleted file mode 100644 index 3c0e197d..00000000 --- a/VENDORS/Milesight/EM400-MUD/ThingsStackIndustries/uplink/converter.json +++ /dev/null @@ -1,40 +0,0 @@ -{ - "name": "The Things Stack Industries Uplink Decoder for EM400-MUD", - "type": "UPLINK", - "debugMode": false, - "debugSettings": { - "failuresEnabled": true, - "allEnabled": false, - "allEnabledUntil": 1733331880270 - }, - "configuration": { - "scriptLang": "TBEL", - "decoder": null, - "tbelDecoder": "var data = decodeToJson(payload);\n\nvar deviceName = data.end_device_ids.device_id;\nvar deviceType = \"EM400-MUD\";\nvar groupName = null; // If groupName is not null - created device will be added to the entity group with such name.\nvar customerName = null; // If customerName is not null - created devices will be assigned to customer with such name. \n\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// If you want to parse incoming data somehow, you can add your code to this function.\n// input: bytes\n// expected output:\n// {\n// \"attributes\": {\"attributeKey\": \"attributeValue\"},\n// \"telemetry\": [{\"ts\": 1...1, \"values\": {\"telemetryKey\":\"telemetryValue\"}, {\"ts\": 1...2, \"values\": {\"telemetryKey\":\"telemetryValue\"}}]\n// }\n\nfunction decodeFrmPayload(input) {\n var output = { attributes: {}, telemetry: []};\n \n // --- Decoding code --- //\n var decoded = {};\n for (var i = 0; i < input.length - 2 ; ) {\n var channel_id = input[i++] & 0xff;\n var channel_type = input[i++] & 0xff;\n\n // BATTERY\n if (channel_id === 0x01 && channel_type === 0x75) {\n decoded.battery = input[i];\n i += 1;\n }\n // TEMPERATURE\n else if (channel_id === 0x03 && channel_type === 0x67) {\n decoded.temperature = parseBytesToInt(input, i, 2, false) / 10;\n i += 2;\n }\n // DISTANCE\n else if (channel_id === 0x04 && channel_type === 0x82) {\n decoded.distance = parseBytesToInt(input, i, 2, false);\n i += 2;\n }\n // POSITION\n else if (channel_id === 0x05 && channel_type === 0x00) {\n decoded.position = input[i] === 0 ? \"normal\" : \"tilt\";\n i += 1;\n }\n // TEMPERATURE WITH ABNORMAL\n else if (channel_id === 0x83 && channel_type === 0x67) {\n decoded.temperature = parseBytesToInt(input, i, 2, false) / 10;\n decoded.temperature_abnormal = input[i + 2] == 0 ? false : true;\n i += 3;\n }\n // DISTANCE WITH ALARMING\n else if (channel_id === 0x84 && channel_type === 0x82) {\n decoded.distance = parseBytesToInt(input, i, 2, false);\n decoded.distance_alarming = input[i + 2] == 0 ? false : true;\n i += 3;\n }\n }\n \n output.telemetry = [{\n ts: timestamp,\n values: decoded\n }];\n\n // --- Decoding code --- //\n return output;\n}\n\n// --- attributes and telemetry objects ---\nvar telemetry = [];\nvar attributes = {};\n// --- attributes and telemetry objects ---\n\n// --- Timestamp parsing\nvar dateString = data.uplink_message.received_at;\n\nif ((data.simulated != null && data.simulated) || dateString == null) {\n dateString = data.received_at;\n}\n\ntimestamp = parseDateToTimestamp(dateString);\n// --- Timestamp parsing\n\n// Message parsing\n// To avoid paths in the decoded objects we passing false value to function as \"pathInKey\" argument.\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.\n\n// Passing incoming bytes to decodeFrmPayload function, to get custom decoding\nvar customDecoding = {};\nif (data.uplink_message.get(\"frm_payload\") != null) {\n customDecoding = decodeFrmPayload(base64ToBytes(data.uplink_message.frm_payload));\n}\n\n// Collecting data to result\nif (customDecoding.?telemetry.size() > 0) {\n if (customDecoding.telemetry instanceof java.util.ArrayList) {\n foreach(telemetryObj: customDecoding.telemetry) {\n if (telemetryObj.ts != null && telemetryObj.values != null) {\n telemetry.add(telemetryObj);\n }\n }\n } else {\n telemetry.putAll(customDecoding.telemetry);\n }\n}\n\nif (customDecoding.?attributes.size() > 0) {\n attributes.putAll(customDecoding.attributes);\n}\n\n// You can add some keys manually to attributes or telemetry\nvar applicationId = data.end_device_ids.?application_ids.?application_id;\nvar devAddr = data.end_device_ids.?dev_addr;\nvar spreadingFactor = data.uplink_message.?settings.?data_rate.?lora.?spreading_factor;\nvar codeRate = data.uplink_message.?settings.?data_rate.?lora.?coding_rate;\nvar tenantId = data.uplink_message.?network_ids.?tenant_id;\nattributes.eui = data.end_device_ids.dev_eui;\nattributes.fPort = data.uplink_message.f_port;\nattributes.applicationId = applicationId;\nattributes.devAddr = devAddr;\nattributes.spreadingFactor = spreadingFactor;\nattributes.codeRate = codeRate;\nattributes.tenantId = tenantId;\nattributes.device_id = data.end_device_ids.?device_id;\nattributes.join_eui = data.end_device_ids.?join_eui;\nattributes.net_id = data.uplink_message.?network_ids.?net_id;\nattributes.cluster_id = data.uplink_message.?network_ids.?cluster_id;\nattributes.cluster_adress = data.uplink_message.?network_ids.?cluster_address;\nattributes.bandwidth = data.uplink_message.?settings.?data_rate.?lora.?bandwidth;\nattributes.frequency = data.uplink_message.?settings.?frequency;\n\nvar isIncludeGatewayInfo = metadata[\"includeGatewayInfo\"];\nif(isIncludeGatewayInfo == true) {\n var gatewayInfo = getGatewayInfo();\n var addDataToTelemetry = {};\n addDataToTelemetry.snr = gatewayInfo.snr;\n addDataToTelemetry.rssi = gatewayInfo.rssi;\n addDataToTelemetry.channel = gatewayInfo.channel_index;\n addDataToTelemetry.consumed_airtime = data.uplink_message.?consumed_airtime;\n addDataToTelemetry.fCnt = data.uplink_message.?f_cnt;\n\n telemetry = processTelemetryData(telemetry, addDataToTelemetry);\n}\n\nvar result = {\n deviceName: deviceName,\n deviceType: deviceType,\n // assetName: assetName,\n // assetType: assetType,\n attributes: attributes,\n telemetry: telemetry\n};\n\naddAdditionalInfoForDeviceMsg(result, customerName, groupName);\n\nreturn result;\n\nfunction addAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName) {\n if (customerName != null) {\n deviceInfo.customerName = customerName;\n }\n if (groupName != null) {\n deviceInfo.groupName = groupName;\n }\n}\n\nfunction parseDateToTimestamp(dateString) {\n var date = new Date(dateString);\n var timestamp = date.getTime();\n \n // If we cannot parse timestamp - we will use the current timestamp\n if (timestamp == -1) {\n timestamp = Date.now();\n }\n \n return timestamp;\n}\n\nfunction getGatewayInfo() {\n var gatewayList = data.uplink_message.?rx_metadata;\n var maxRssi = Integer. MIN_VALUE;\n var gatewayInfo = {};\n \n foreach (gateway : gatewayList) {\n if(gateway.rssi > maxRssi) {\n maxRssi = gateway.rssi;\n gatewayInfo = gateway;\n }\n }\n \n return gatewayInfo;\n}\n\nfunction processTelemetryData(telemetry, addDataToTelemetry) {\n if (telemetry.size >= 1) {\n telemetry = addDataToTelemetries(telemetry, addDataToTelemetry);\n }\n else {\n telemetry.add(addDataToTelemetry);\n }\n \n return telemetry;\n}\n\nfunction addDataToTelemetries(telemetries, addDataToTelemetry) {\n foreach(telemetry : telemetries) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[\"values\"].keys.contains(element.key)) {\n telemetry[\"values\"][element.key] = element.value;\n }\n } \n }\n \n return telemetries;\n}", - "encoder": null, - "tbelEncoder": null, - "updateOnlyKeys": [ - "fPort", - "bandwidth", - "frequency", - "net_id", - "cluster_id", - "cluster_address", - "tenant_address", - "device_id", - "join_eui", - "eui", - "channel", - "devAddr", - "spreadingFactor", - "codeRate", - "tenantId", - "applicationId", - "battery" - ] - }, - "additionalInfo": { - "description": "" - }, - "edgeTemplate": false -} \ No newline at end of file diff --git a/VENDORS/Milesight/EM400-MUD/ThingsStackIndustries/uplink/metadata.json b/VENDORS/Milesight/EM400-MUD/ThingsStackIndustries/uplink/metadata.json deleted file mode 100644 index 904c0fa0..00000000 --- a/VENDORS/Milesight/EM400-MUD/ThingsStackIndustries/uplink/metadata.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "integrationName": "The Things Stack Industries integration new", - "includeGatewayInfo": "false" -} \ No newline at end of file diff --git a/VENDORS/Milesight/EM400-MUD/ThingsStackIndustries/uplink/payload.json b/VENDORS/Milesight/EM400-MUD/ThingsStackIndustries/uplink/payload.json deleted file mode 100644 index 1763bfd0..00000000 --- a/VENDORS/Milesight/EM400-MUD/ThingsStackIndustries/uplink/payload.json +++ /dev/null @@ -1,77 +0,0 @@ -{ - "end_device_ids": { - "device_id": "eui-1000000000000001", - "application_ids": { - "application_id": "application-tti-name" - }, - "dev_eui": "1000000000000001", - "join_eui": "2000000000000001", - "dev_addr": "20000001" - }, - "correlation_ids": ["as:up:01H0PZDGB1NW6NAPD815NGHPF6", "gs:conn:01H0FJRSXSYT7VKNYXJ89F95XT", "gs:up:host:01H0FJRSY3MZMGPPFBQ4FZV4T8", "gs:uplink:01H0PZDG4HHGFRTXRTXD4PFTH7", "ns:uplink:01H0PZDG4JZ3BM0K6J89EQK1J7", "rpc:/ttn.lorawan.v3.GsNs/HandleUplink:01H0PZDG4J02F85RYFPCNSNXCR", "rpc:/ttn.lorawan.v3.NsAs/HandleUplink:01H0PZDGB081PMP806BJHNHX1A"], - "received_at": "2023-05-18T08:25:26.112483370Z", - "uplink_message": { - "session_key_id": "AYfg8rhha5n+FWx0ZaAprA==", - "f_port": 85, - "f_cnt": 5017, - "frm_payload": "g2foAAGEgkEGAQ==", - "rx_metadata": [{ - "gateway_ids": { - "gateway_id": "eui-6A7E111A10000000", - "eui": "6A7E111A10000000" - }, - "time": "2023-05-18T08:25:25.885310Z", - "timestamp": 818273765, - "rssi": -24, - "channel_rssi": -24, - "snr": 12, - "frequency_offset": "671", - "uplink_token": "CiIKIAoUZXVpLTZBN0UxMTFBMTAwMDAwMDASCCThJP/+9k6eEOW7l4YDGgwI9cGXowYQ5KPhrwMgiI2rp+jpOA=", - "channel_index": 2, - "received_at": "2023-05-18T08:25:25.869324983Z" - }, { - "gateway_ids": { - "gateway_id": "packetbroker" - }, - "packet_broker": { - "message_id": "01H0PZDG4MF9AYSMNY44MAVTDH", - "forwarder_net_id": "000013", - "forwarder_tenant_id": "ttn", - "forwarder_cluster_id": "eu1.cloud.thethings.network", - "forwarder_gateway_eui": "6A7E111A10000000", - "forwarder_gateway_id": "eui-6a7e111a10000000", - "home_network_net_id": "000013", - "home_network_tenant_id": "tenant", - "home_network_cluster_id": "eu1.cloud.thethings.industries" - }, - "time": "2023-05-18T08:25:25.885310Z", - "rssi": -24, - "channel_rssi": -24, - "snr": 12, - "frequency_offset": "671", - "uplink_token": "eyJnIjoiWlhsS2FHSkhZMmxQYVVwQ1RWUkpORkl3VGs1VE1XTnBURU5LYkdKdFRXbFBhVXBDVFZSSk5GSXdUazVKYVhkcFlWaFphVTlwU201a01uaGhWVlJvZDFSWFVuRmlSM1JtVFcxT2RVbHBkMmxrUjBadVNXcHZhV05ZY0RKT1IyeExaREpSZVZwR1pIUmpNRXBLVlVoR2RFNVZkR3BWVTBvNUxua3paVVJTWVRaM1lXOU1kbTQwVm5sdmIyWmlPWGN1ZUhCZmVrcElaa3hIWlZadGRVUlFVeTVuYlRaVlZXRXdkakpHV0VKMGJUUjZaMjVXUkVoeGVHRjRaMlJKTlVkS1VsbERhemc1VDNCbk5rVk1iM1JDUkVZM1VWbHdZbEJDTkdOblNqWjBlbkphYUV4MFRVMHhZMVZFTTFac01XdExURUo0YURaMFExTnhhMVJsWWw4eE5FdHlVVXcyZUhsRWFFbEhlakJITXpoTE0xaFdlRzR5VUVjMk4wNUViME5WTkhoTmRrazFZVk5oWkUwd2FXVnFjR294VGtoMFduZHlZMDFxVlVGNmRsbERUazlNY2s5eFdVeFpWMk5XTG1WVFFYVkpNVkptT1U5NWRqUTNhSEoxTUZoalYxRT0iLCJhIjp7ImZuaWQiOiIwMDAwMTMiLCJmdGlkIjoidHRuIiwiZmNpZCI6ImV1MS5jbG91ZC50aGV0aGluZ3MubmV0d29yayJ9fQ==", - "received_at": "2023-05-18T08:25:25.906038642Z" - }], - "settings": { - "data_rate": { - "lora": { - "bandwidth": 125000, - "spreading_factor": 7, - "coding_rate": "4/5" - } - }, - "frequency": "868500000", - "timestamp": 818273765, - "time": "2023-05-18T08:25:25.885310Z" - }, - "received_at": "2023-05-18T08:25:25.906399073Z", - "consumed_airtime": "0.097536s", - "network_ids": { - "net_id": "000013", - "tenant_id": "tenant", - "cluster_id": "eu1", - "cluster_address": "eu1.cloud.thethings.industries", - "tenant_address": "tenant.eu1.cloud.thethings.industries" - } - } -} \ No newline at end of file diff --git a/VENDORS/Milesight/EM400-MUD/ThingsStackIndustries/uplink/payload_1.json b/VENDORS/Milesight/EM400-MUD/ThingsStackIndustries/uplink/payload_1.json deleted file mode 100644 index 84cc5f8f..00000000 --- a/VENDORS/Milesight/EM400-MUD/ThingsStackIndustries/uplink/payload_1.json +++ /dev/null @@ -1,77 +0,0 @@ -{ - "end_device_ids": { - "device_id": "eui-1000000000000001", - "application_ids": { - "application_id": "application-tti-name" - }, - "dev_eui": "1000000000000001", - "join_eui": "2000000000000001", - "dev_addr": "20000001" - }, - "correlation_ids": ["as:up:01H0PZDGB1NW6NAPD815NGHPF6", "gs:conn:01H0FJRSXSYT7VKNYXJ89F95XT", "gs:up:host:01H0FJRSY3MZMGPPFBQ4FZV4T8", "gs:uplink:01H0PZDG4HHGFRTXRTXD4PFTH7", "ns:uplink:01H0PZDG4JZ3BM0K6J89EQK1J7", "rpc:/ttn.lorawan.v3.GsNs/HandleUplink:01H0PZDG4J02F85RYFPCNSNXCR", "rpc:/ttn.lorawan.v3.NsAs/HandleUplink:01H0PZDGB081PMP806BJHNHX1A"], - "received_at": "2023-05-18T08:25:26.112483370Z", - "uplink_message": { - "session_key_id": "AYfg8rhha5n+FWx0ZaAprA==", - "f_port": 85, - "f_cnt": 5017, - "frm_payload": "AXVcA2cBAQSCRAgFAAE=", - "rx_metadata": [{ - "gateway_ids": { - "gateway_id": "eui-6A7E111A10000000", - "eui": "6A7E111A10000000" - }, - "time": "2023-05-18T08:25:25.885310Z", - "timestamp": 818273765, - "rssi": -24, - "channel_rssi": -24, - "snr": 12, - "frequency_offset": "671", - "uplink_token": "CiIKIAoUZXVpLTZBN0UxMTFBMTAwMDAwMDASCCThJP/+9k6eEOW7l4YDGgwI9cGXowYQ5KPhrwMgiI2rp+jpOA=", - "channel_index": 2, - "received_at": "2023-05-18T08:25:25.869324983Z" - }, { - "gateway_ids": { - "gateway_id": "packetbroker" - }, - "packet_broker": { - "message_id": "01H0PZDG4MF9AYSMNY44MAVTDH", - "forwarder_net_id": "000013", - "forwarder_tenant_id": "ttn", - "forwarder_cluster_id": "eu1.cloud.thethings.network", - "forwarder_gateway_eui": "6A7E111A10000000", - "forwarder_gateway_id": "eui-6a7e111a10000000", - "home_network_net_id": "000013", - "home_network_tenant_id": "tenant", - "home_network_cluster_id": "eu1.cloud.thethings.industries" - }, - "time": "2023-05-18T08:25:25.885310Z", - "rssi": -24, - "channel_rssi": -24, - "snr": 12, - "frequency_offset": "671", - "uplink_token": "eyJnIjoiWlhsS2FHSkhZMmxQYVVwQ1RWUkpORkl3VGs1VE1XTnBURU5LYkdKdFRXbFBhVXBDVFZSSk5GSXdUazVKYVhkcFlWaFphVTlwU201a01uaGhWVlJvZDFSWFVuRmlSM1JtVFcxT2RVbHBkMmxrUjBadVNXcHZhV05ZY0RKT1IyeExaREpSZVZwR1pIUmpNRXBLVlVoR2RFNVZkR3BWVTBvNUxua3paVVJTWVRaM1lXOU1kbTQwVm5sdmIyWmlPWGN1ZUhCZmVrcElaa3hIWlZadGRVUlFVeTVuYlRaVlZXRXdkakpHV0VKMGJUUjZaMjVXUkVoeGVHRjRaMlJKTlVkS1VsbERhemc1VDNCbk5rVk1iM1JDUkVZM1VWbHdZbEJDTkdOblNqWjBlbkphYUV4MFRVMHhZMVZFTTFac01XdExURUo0YURaMFExTnhhMVJsWWw4eE5FdHlVVXcyZUhsRWFFbEhlakJITXpoTE0xaFdlRzR5VUVjMk4wNUViME5WTkhoTmRrazFZVk5oWkUwd2FXVnFjR294VGtoMFduZHlZMDFxVlVGNmRsbERUazlNY2s5eFdVeFpWMk5XTG1WVFFYVkpNVkptT1U5NWRqUTNhSEoxTUZoalYxRT0iLCJhIjp7ImZuaWQiOiIwMDAwMTMiLCJmdGlkIjoidHRuIiwiZmNpZCI6ImV1MS5jbG91ZC50aGV0aGluZ3MubmV0d29yayJ9fQ==", - "received_at": "2023-05-18T08:25:25.906038642Z" - }], - "settings": { - "data_rate": { - "lora": { - "bandwidth": 125000, - "spreading_factor": 7, - "coding_rate": "4/5" - } - }, - "frequency": "868500000", - "timestamp": 818273765, - "time": "2023-05-18T08:25:25.885310Z" - }, - "received_at": "2023-05-18T08:25:25.906399073Z", - "consumed_airtime": "0.097536s", - "network_ids": { - "net_id": "000013", - "tenant_id": "tenant", - "cluster_id": "eu1", - "cluster_address": "eu1.cloud.thethings.industries", - "tenant_address": "tenant.eu1.cloud.thethings.industries" - } - } -} \ No newline at end of file diff --git a/VENDORS/Milesight/EM400-MUD/ThingsStackIndustries/uplink/result.json b/VENDORS/Milesight/EM400-MUD/ThingsStackIndustries/uplink/result.json deleted file mode 100644 index 3a7a7c98..00000000 --- a/VENDORS/Milesight/EM400-MUD/ThingsStackIndustries/uplink/result.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "deviceName": "eui-1000000000000001", - "deviceType": "EM400-MUD", - "attributes": { - "eui": "1000000000000001", - "fPort": 85, - "applicationId": "application-tti-name", - "devAddr": "20000001", - "spreadingFactor": 7, - "codeRate": "4/5", - "tenantId": "tenant", - "device_id": "eui-1000000000000001", - "join_eui": "2000000000000001", - "net_id": "000013", - "cluster_id": "eu1", - "cluster_adress": "eu1.cloud.thethings.industries", - "bandwidth": 125000, - "frequency": "868500000" - }, - "telemetry": [{ - "ts": 1684398325906, - "values": { - "temperature": 23.2, - "temperature_abnormal": true, - "distance": 1601, - "distance_alarming": true - } - }] -} \ No newline at end of file diff --git a/VENDORS/Milesight/EM400-MUD/ThingsStackIndustries/uplink/result_1.json b/VENDORS/Milesight/EM400-MUD/ThingsStackIndustries/uplink/result_1.json deleted file mode 100644 index ea05fca1..00000000 --- a/VENDORS/Milesight/EM400-MUD/ThingsStackIndustries/uplink/result_1.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "deviceName": "eui-1000000000000001", - "deviceType": "EM400-MUD", - "attributes": { - "eui": "1000000000000001", - "fPort": 85, - "applicationId": "application-tti-name", - "devAddr": "20000001", - "spreadingFactor": 7, - "codeRate": "4/5", - "tenantId": "tenant", - "device_id": "eui-1000000000000001", - "join_eui": "2000000000000001", - "net_id": "000013", - "cluster_id": "eu1", - "cluster_adress": "eu1.cloud.thethings.industries", - "bandwidth": 125000, - "frequency": "868500000" - }, - "telemetry": [{ - "ts": 1684398325906, - "values": { - "battery": 92, - "temperature": 25.7, - "distance": 2116, - "position": "tilt" - } - }] -} \ No newline at end of file diff --git a/VENDORS/Milesight/EM400-MUD/guide.md b/VENDORS/Milesight/EM400-MUD/guide.md deleted file mode 100644 index 7d9ebac4..00000000 --- a/VENDORS/Milesight/EM400-MUD/guide.md +++ /dev/null @@ -1,21 +0,0 @@ -# Multifunctional Ultrasonic Distance/Level Sensor - Milesight IoT - -The payload decoder function is applicable to EM400-MUD. - -## Payload Definition - -| CHANNEL | ID | TYPE | LENGTH | DESCRIPTION | -| :--------------------: | :--: | :--: | :----: | ------------------------------------------------------ | -| Battery | 0x01 | 0x75 | 1 | battery(1B)
battery, unit: % | -| Temperature | 0x03 | 0x67 | 2 | temperature(2B)
temperature, unit: ℃ | -| Distance | 0x04 | 0x82 | 2 | distance(2B)
distance, unit: mm | -| Position | 0x05 | 0x00 | 1 | position(1B)
position, values(0: normal, 1: tilt) | -| Location
(NB-IoT) | 0x06 | 0x88 | 9 | longitude(4B) + latitude(4B) + motion_status(1B) | -| Temperature Abnormal | 0x83 | 0x67 | 3 | temperature(2B) + status(1B) | -| Distance Alarm | 0x84 | 0x82 | 3 | distance(2B) + status(1B) | - -### Motion Status Definition - -| BITS | 7..4 | 3..0 | -| :---------: | :-------------------------------------------------------------------- | :------------------------------------------------------------------------------ | -| DESCRIPTION | geofence_status, values: (0: inside, 1: outside, 2: unset, 3: unknown | motion_status, values: (0: unknown, 1: start moving, 2: moving, 3: stop moving) | \ No newline at end of file diff --git a/VENDORS/Milesight/EM400-MUD/info.json b/VENDORS/Milesight/EM400-MUD/info.json deleted file mode 100644 index a3e5ee6f..00000000 --- a/VENDORS/Milesight/EM400-MUD/info.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "url": "https://www.milesight.com/iot/product/lorawan-sensor/em400-mud", - "label": "EM400-MUD: Multifunctional Ultrasonic Distance Sensor", - "description": "EM400-MUD is a multifunctional ultrasonic distance sensor designed to detect small-range areas and small blind spots. It features switchable pre-set modes for different applications. EM400-MUD is also equipped with a 3-axis accelerometer and temperature sensor to detect device status. " -} - diff --git a/VENDORS/Milesight/EM400-MUD/photo.png b/VENDORS/Milesight/EM400-MUD/photo.png deleted file mode 100644 index 83c128c15836798901078ec7abec62ad71afd8f6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 46217 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 From 0bcc4b80bc3538ec0ecffaf63a45e4d6d1d03f71 Mon Sep 17 00:00:00 2001 From: thingsboard017 Date: Wed, 11 Dec 2024 17:20:50 +0200 Subject: [PATCH 02/33] Added 4 LNS integrations for EM400-TLD --- .../ChirpStack/uplink/converter.json | 39 +++++++++ .../EM400-TLD/ChirpStack/uplink/metadata.json | 4 + .../EM400-TLD/ChirpStack/uplink/payload.json | 48 +++++++++++ .../ChirpStack/uplink/payload_1.json | 48 +++++++++++ .../EM400-TLD/ChirpStack/uplink/result.json | 28 +++++++ .../EM400-TLD/ChirpStack/uplink/result_1.json | 28 +++++++ .../EM400-TLD/LORIOT/uplink/converter.json | 29 +++++++ .../EM400-TLD/LORIOT/uplink/metadata.json | 4 + .../EM400-TLD/LORIOT/uplink/payload.json | 17 ++++ .../EM400-TLD/LORIOT/uplink/payload_1.json | 17 ++++ .../EM400-TLD/LORIOT/uplink/result.json | 18 ++++ .../EM400-TLD/LORIOT/uplink/result_1.json | 18 ++++ .../uplink/converter.json | 39 +++++++++ .../ThingsStackCommunity/uplink/metadata.json | 4 + .../ThingsStackCommunity/uplink/payload.json | 54 ++++++++++++ .../uplink/payload_1.json | 54 ++++++++++++ .../ThingsStackCommunity/uplink/result.json | 29 +++++++ .../ThingsStackCommunity/uplink/result_1.json | 29 +++++++ .../uplink/converter.json | 40 +++++++++ .../uplink/metadata.json | 4 + .../ThingsStackIndustries/uplink/payload.json | 77 ++++++++++++++++++ .../uplink/payload_1.json | 77 ++++++++++++++++++ .../ThingsStackIndustries/uplink/result.json | 29 +++++++ .../uplink/result_1.json | 29 +++++++ VENDORS/Milesight/EM400-TLD/guide.md | 21 +++++ VENDORS/Milesight/EM400-TLD/info.json | 6 ++ VENDORS/Milesight/EM400-TLD/photo.png | Bin 0 -> 54661 bytes 27 files changed, 790 insertions(+) create mode 100644 VENDORS/Milesight/EM400-TLD/ChirpStack/uplink/converter.json create mode 100644 VENDORS/Milesight/EM400-TLD/ChirpStack/uplink/metadata.json create mode 100644 VENDORS/Milesight/EM400-TLD/ChirpStack/uplink/payload.json create mode 100644 VENDORS/Milesight/EM400-TLD/ChirpStack/uplink/payload_1.json create mode 100644 VENDORS/Milesight/EM400-TLD/ChirpStack/uplink/result.json create mode 100644 VENDORS/Milesight/EM400-TLD/ChirpStack/uplink/result_1.json create mode 100644 VENDORS/Milesight/EM400-TLD/LORIOT/uplink/converter.json create mode 100644 VENDORS/Milesight/EM400-TLD/LORIOT/uplink/metadata.json create mode 100644 VENDORS/Milesight/EM400-TLD/LORIOT/uplink/payload.json create mode 100644 VENDORS/Milesight/EM400-TLD/LORIOT/uplink/payload_1.json create mode 100644 VENDORS/Milesight/EM400-TLD/LORIOT/uplink/result.json create mode 100644 VENDORS/Milesight/EM400-TLD/LORIOT/uplink/result_1.json create mode 100644 VENDORS/Milesight/EM400-TLD/ThingsStackCommunity/uplink/converter.json create mode 100644 VENDORS/Milesight/EM400-TLD/ThingsStackCommunity/uplink/metadata.json create mode 100644 VENDORS/Milesight/EM400-TLD/ThingsStackCommunity/uplink/payload.json create mode 100644 VENDORS/Milesight/EM400-TLD/ThingsStackCommunity/uplink/payload_1.json create mode 100644 VENDORS/Milesight/EM400-TLD/ThingsStackCommunity/uplink/result.json create mode 100644 VENDORS/Milesight/EM400-TLD/ThingsStackCommunity/uplink/result_1.json create mode 100644 VENDORS/Milesight/EM400-TLD/ThingsStackIndustries/uplink/converter.json create mode 100644 VENDORS/Milesight/EM400-TLD/ThingsStackIndustries/uplink/metadata.json create mode 100644 VENDORS/Milesight/EM400-TLD/ThingsStackIndustries/uplink/payload.json create mode 100644 VENDORS/Milesight/EM400-TLD/ThingsStackIndustries/uplink/payload_1.json create mode 100644 VENDORS/Milesight/EM400-TLD/ThingsStackIndustries/uplink/result.json create mode 100644 VENDORS/Milesight/EM400-TLD/ThingsStackIndustries/uplink/result_1.json create mode 100644 VENDORS/Milesight/EM400-TLD/guide.md create mode 100644 VENDORS/Milesight/EM400-TLD/info.json create mode 100644 VENDORS/Milesight/EM400-TLD/photo.png diff --git a/VENDORS/Milesight/EM400-TLD/ChirpStack/uplink/converter.json b/VENDORS/Milesight/EM400-TLD/ChirpStack/uplink/converter.json new file mode 100644 index 00000000..37e8440b --- /dev/null +++ b/VENDORS/Milesight/EM400-TLD/ChirpStack/uplink/converter.json @@ -0,0 +1,39 @@ +{ + "name": "ChirpStack Uplink Decoder for EM400-TLD", + "type": "UPLINK", + "debugMode": false, + "debugSettings": { + "failuresEnabled": true, + "allEnabled": false, + "allEnabledUntil": 1733331880270 + }, + "configuration": { + "scriptLang": "TBEL", + "decoder": null, + "tbelDecoder": "var data = decodeToJson(payload);\nvar deviceName = data.deviceInfo.deviceName + \" \" + data.deviceInfo.devEui;\nvar deviceType = \"EM400-TLD\";\nvar groupName = null; // If groupName is not null - created device will be added to the entity group with such name.\nvar customerName = null; // If customerName is not null - created devices will be assigned to customer with such name. \n\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// If you want to parse incoming data somehow, you can add your code to this function.\n// input: bytes\n// expected output:\n// {\n// \"attributes\": {\"attributeKey\": \"attributeValue\"},\n// \"telemetry\": [{\"ts\": 1...1, \"values\": {\"telemetryKey\":\"telemetryValue\"}, {\"ts\": 1...2, \"values\": {\"telemetryKey\":\"telemetryValue\"}}]\n// }\n\nfunction decodePayload(input) {\n var output = {\n attributes: {},\n telemetry: []\n };\n \n // --- Decoding code --- //\n var decoded = {};\n for (var i = 0; i < input.length - 2 ; ) {\n var channel_id = input[i++] & 0xff;\n var channel_type = input[i++] & 0xff;\n \n // BATTERY\n if (channel_id === 0x01 && channel_type === 0x75) {\n decoded.battery = input[i];\n i += 1;\n }\n // TEMPERATURE\n else if (channel_id === 0x03 && channel_type === 0x67) {\n decoded.temperature = parseBytesToInt(input, i, 2, false) / 10;\n i += 2;\n }\n // DISTANCE\n else if (channel_id === 0x04 && channel_type === 0x82) {\n decoded.distance = parseBytesToInt(input, i, 2, false);\n i += 2;\n }\n // POSITION\n else if (channel_id === 0x05 && channel_type === 0x00) {\n decoded.position = input[i] === 0 ? \"normal\" : \"tilt\";\n i += 1;\n }\n // TEMPERATURE WITH ABNORMAL\n else if (channel_id === 0x83 && channel_type === 0x67) {\n decoded.temperature = parseBytesToInt(input, i, 2, false) / 10;\n decoded.temperature_abnormal = input[i + 2] == 0 ? false : true;\n i += 3;\n }\n // DISTANCE WITH ALARMING\n else if (channel_id === 0x84 && channel_type === 0x82) {\n decoded.distance = parseBytesToInt(input, i, 2, false);\n decoded.distance_alarming = input[i + 2] == 0 ? false : true;\n i += 3;\n }\n }\n\n output.telemetry = [{\n ts: timestamp,\n values: decoded\n }];\n \n // --- Decoding code --- //\n return output;\n}\n\n// --- attributes and telemetry objects ---\nvar telemetry = [];\nvar attributes = {};\n// --- attributes and telemetry objects ---\n\n// --- Timestamp parsing\nvar dateString = data.time;\ntimestamp = parseDateToTimestamp(dateString);\n// --- Timestamp parsing\n\n// Passing incoming bytes to decodePayload function, to get custom decoding\nvar customDecoding = decodePayload(base64ToBytes(data.data));\n\n\nattributes.eui = data.deviceInfo.devEui;\n\n// Collecting data to result\nif (customDecoding.?telemetry.size() > 0) {\n if (customDecoding.telemetry instanceof java.util.ArrayList) {\n foreach(telemetryObj: customDecoding.telemetry) {\n if (telemetryObj.ts != null && telemetryObj.values != null) {\n telemetry.add(telemetryObj);\n }\n }\n } else {\n telemetry.putAll(customDecoding.telemetry);\n }\n}\n\nif (customDecoding.?attributes.size() > 0) {\n attributes.putAll(customDecoding.attributes);\n}\n\n// You can add some keys manually to attributes or telemetry\nattributes.eui = data.deviceInfo.?devEui;\nattributes.devAddr = data.devAddr;\nattributes.fPort = data.fPort;\nattributes.applicationId = data.deviceInfo.?applicationId;\nattributes.applicationName = data.deviceInfo.?applicationName;\nattributes.tenantId = data.deviceInfo.?tenantId;\nattributes.tenantName = data.deviceInfo.?tenantName;\nattributes.deviceProfileId = data.deviceInfo.?deviceProfileId;\nattributes.deviceProfileName = data.deviceInfo.?deviceProfileName;\nattributes.frequency = data.txInfo.?frequency;\nattributes.bandwidth = data.txInfo.?modulation.?lora.?bandwidth;\nattributes.spreadingFactor = data.txInfo.?modulation.?lora.?spreadingFactor;\nattributes.codeRate = data.txInfo.?modulation.?lora.?codeRate;\n\nif(Boolean.parseBoolean(metadata[\"includeGatewayInfo\"])) {\n var gatewayInfo = getGatewayInfo();\n var addDataToTelemetry = {};\n addDataToTelemetry.snr = gatewayInfo.snr;\n addDataToTelemetry.rssi = gatewayInfo.rssi;\n addDataToTelemetry.channel = gatewayInfo.channel;\n addDataToTelemetry.rfChain = gatewayInfo.rfChain;\n addDataToTelemetry.fCnt = data.fCnt;\n \n telemetry = processTelemetryData(telemetry, addDataToTelemetry);\n}\n\nvar result = {\n deviceName: deviceName,\n deviceType: deviceType,\n // assetName: assetName,\n // assetType: assetType,\n attributes: attributes,\n telemetry: telemetry\n};\n\naddAdditionalInfoForDeviceMsg(result, customerName, groupName);\n\nreturn result;\n\nfunction addAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName) {\n if (customerName != null) {\n deviceInfo.customerName = customerName;\n }\n if (groupName != null) {\n deviceInfo.groupName = groupName;\n }\n}\n\nfunction parseDateToTimestamp(dateString) {\n var date = new Date(dateString);\n var timestamp = date.getTime();\n \n // If we cannot parse timestamp - we will use the current timestamp\n if (timestamp == -1) {\n timestamp = Date.now();\n }\n \n return timestamp;\n}\n\nfunction getGatewayInfo() {\n var gatewayList = data.rxInfo;\n var maxRssi = Integer.MIN_VALUE;\n var gatewayInfo = {};\n \n foreach (gateway : gatewayList) {\n if(gateway.rssi > maxRssi) {\n maxRssi = gateway.rssi;\n gatewayInfo = gateway;\n }\n }\n \n return gatewayInfo;\n}\n\nfunction processTelemetryData(telemetry, addDataToTelemetry) {\n if (telemetry.size >= 1) {\n telemetry = addDataToTelemetries(telemetry, addDataToTelemetry);\n }\n else {\n telemetry.add(addDataToTelemetry);\n }\n \n return telemetry;\n}\n\nfunction addDataToTelemetries(telemetries, addDataToTelemetry) {\n foreach(telemetry : telemetries) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[\"values\"].keys.contains(element.key)) {\n telemetry[\"values\"][element.key] = element.value;\n }\n } \n }\n \n return telemetries;\n}", + "encoder": null, + "tbelEncoder": null, + "updateOnlyKeys": [ + "tenantId", + "tenantName", + "applicationId", + "applicationName", + "deviceProfileId", + "deviceProfileName", + "devAddr", + "fPort", + "frequency", + "bandwidth", + "spreadingFactor", + "codeRate", + "channel", + "rfChain", + "eui", + "battery" + ] + }, + "additionalInfo": { + "description": "" + }, + "edgeTemplate": false +} \ No newline at end of file diff --git a/VENDORS/Milesight/EM400-TLD/ChirpStack/uplink/metadata.json b/VENDORS/Milesight/EM400-TLD/ChirpStack/uplink/metadata.json new file mode 100644 index 00000000..23f54b34 --- /dev/null +++ b/VENDORS/Milesight/EM400-TLD/ChirpStack/uplink/metadata.json @@ -0,0 +1,4 @@ +{ + "integrationName": "ChirpStack integration", + "includeGatewayInfo": "false" +} \ No newline at end of file diff --git a/VENDORS/Milesight/EM400-TLD/ChirpStack/uplink/payload.json b/VENDORS/Milesight/EM400-TLD/ChirpStack/uplink/payload.json new file mode 100644 index 00000000..3e3584b0 --- /dev/null +++ b/VENDORS/Milesight/EM400-TLD/ChirpStack/uplink/payload.json @@ -0,0 +1,48 @@ +{ + "deduplicationId": "57433366-50a6-4dc2-8145-2df1bbc70d9e", + "time": "2023-05-22T07:47:05.404859+00:00", + "deviceInfo": { + "tenantId": "52f14cd4-c6f1-4fbd-8f87-4025e1d49242", + "tenantName": "ChirpStack", + "applicationId": "ca739e26-7b67-4f14-b69e-d568c22a5a75", + "applicationName": "Chirpstack application", + "deviceProfileId": "605d08d4-65f5-4d2c-8a5a-3d2457662f79", + "deviceProfileName": "Chirpstack default device profile", + "deviceName": "Device name", + "devEui": "1000000000000001", + "tags": {} + }, + "devAddr": "20000001", + "adr": true, + "dr": 5, + "fCnt": 4, + "fPort": 85, + "confirmed": false, + "data": "g2foAAGEgkEGAQ==", + "rxInfo": [{ + "gatewayId": "6a7e111a10000000", + "uplinkId": 24022, + "time": "2023-05-22T07:47:05.404859+00:00", + "rssi": -35, + "snr": 11.5, + "channel": 2, + "rfChain": 1, + "location": {}, + "context": "EFwMtA==", + "metadata": { + "region_common_name": "EU868", + "region_config_id": "eu868" + }, + "crcStatus": "CRC_OK" + }], + "txInfo": { + "frequency": 868500000, + "modulation": { + "lora": { + "bandwidth": 125000, + "spreadingFactor": 7, + "codeRate": "CR_4_5" + } + } + } +} \ No newline at end of file diff --git a/VENDORS/Milesight/EM400-TLD/ChirpStack/uplink/payload_1.json b/VENDORS/Milesight/EM400-TLD/ChirpStack/uplink/payload_1.json new file mode 100644 index 00000000..154ca2e8 --- /dev/null +++ b/VENDORS/Milesight/EM400-TLD/ChirpStack/uplink/payload_1.json @@ -0,0 +1,48 @@ +{ + "deduplicationId": "57433366-50a6-4dc2-8145-2df1bbc70d9e", + "time": "2023-05-22T07:47:05.404859+00:00", + "deviceInfo": { + "tenantId": "52f14cd4-c6f1-4fbd-8f87-4025e1d49242", + "tenantName": "ChirpStack", + "applicationId": "ca739e26-7b67-4f14-b69e-d568c22a5a75", + "applicationName": "Chirpstack application", + "deviceProfileId": "605d08d4-65f5-4d2c-8a5a-3d2457662f79", + "deviceProfileName": "Chirpstack default device profile", + "deviceName": "Device name", + "devEui": "1000000000000001", + "tags": {} + }, + "devAddr": "20000001", + "adr": true, + "dr": 5, + "fCnt": 4, + "fPort": 85, + "confirmed": false, + "data": "AXVcA2cBAQSCRAgFAAE=", + "rxInfo": [{ + "gatewayId": "6a7e111a10000000", + "uplinkId": 24022, + "time": "2023-05-22T07:47:05.404859+00:00", + "rssi": -35, + "snr": 11.5, + "channel": 2, + "rfChain": 1, + "location": {}, + "context": "EFwMtA==", + "metadata": { + "region_common_name": "EU868", + "region_config_id": "eu868" + }, + "crcStatus": "CRC_OK" + }], + "txInfo": { + "frequency": 868500000, + "modulation": { + "lora": { + "bandwidth": 125000, + "spreadingFactor": 7, + "codeRate": "CR_4_5" + } + } + } +} \ No newline at end of file diff --git a/VENDORS/Milesight/EM400-TLD/ChirpStack/uplink/result.json b/VENDORS/Milesight/EM400-TLD/ChirpStack/uplink/result.json new file mode 100644 index 00000000..075f978a --- /dev/null +++ b/VENDORS/Milesight/EM400-TLD/ChirpStack/uplink/result.json @@ -0,0 +1,28 @@ +{ + "deviceName": "Device name 1000000000000001", + "deviceType": "EM400-TLD", + "attributes": { + "eui": "1000000000000001", + "devAddr": "20000001", + "fPort": 85, + "applicationId": "ca739e26-7b67-4f14-b69e-d568c22a5a75", + "applicationName": "Chirpstack application", + "tenantId": "52f14cd4-c6f1-4fbd-8f87-4025e1d49242", + "tenantName": "ChirpStack", + "deviceProfileId": "605d08d4-65f5-4d2c-8a5a-3d2457662f79", + "deviceProfileName": "Chirpstack default device profile", + "frequency": 868500000, + "bandwidth": 125000, + "spreadingFactor": 7, + "codeRate": "CR_4_5" + }, + "telemetry": [{ + "ts": 1684741625404, + "values": { + "temperature": 23.2, + "temperature_abnormal": true, + "distance": 1601, + "distance_alarming": true + } + }] +} \ No newline at end of file diff --git a/VENDORS/Milesight/EM400-TLD/ChirpStack/uplink/result_1.json b/VENDORS/Milesight/EM400-TLD/ChirpStack/uplink/result_1.json new file mode 100644 index 00000000..fa25878e --- /dev/null +++ b/VENDORS/Milesight/EM400-TLD/ChirpStack/uplink/result_1.json @@ -0,0 +1,28 @@ +{ + "deviceName": "Device name 1000000000000001", + "deviceType": "EM400-TLD", + "attributes": { + "eui": "1000000000000001", + "devAddr": "20000001", + "fPort": 85, + "applicationId": "ca739e26-7b67-4f14-b69e-d568c22a5a75", + "applicationName": "Chirpstack application", + "tenantId": "52f14cd4-c6f1-4fbd-8f87-4025e1d49242", + "tenantName": "ChirpStack", + "deviceProfileId": "605d08d4-65f5-4d2c-8a5a-3d2457662f79", + "deviceProfileName": "Chirpstack default device profile", + "frequency": 868500000, + "bandwidth": 125000, + "spreadingFactor": 7, + "codeRate": "CR_4_5" + }, + "telemetry": [{ + "ts": 1684741625404, + "values": { + "battery": 92, + "temperature": 25.7, + "distance": 2116, + "position": "tilt" + } + }] +} \ No newline at end of file diff --git a/VENDORS/Milesight/EM400-TLD/LORIOT/uplink/converter.json b/VENDORS/Milesight/EM400-TLD/LORIOT/uplink/converter.json new file mode 100644 index 00000000..44422245 --- /dev/null +++ b/VENDORS/Milesight/EM400-TLD/LORIOT/uplink/converter.json @@ -0,0 +1,29 @@ +{ + "name": "Loriot Uplink Decoder for EM400-TLD", + "type": "UPLINK", + "debugMode": false, + "debugSettings": { + "failuresEnabled": true, + "allEnabled": false, + "allEnabledUntil": 1733331880270 + }, + "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);\nvar deviceName = data.EUI;\nvar deviceType = \"EM400-TLD\";\nvar groupName = null; // If groupName is not null - created device will be added to the entity group with such name.\nvar customerName = null; // If customerName is not null - created devices will be assigned to customer with such name. \n\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// If you want to parse incoming data somehow, you can add your code to this function.\n// input: bytes\n// expected output:\n// {\n// \"attributes\": {\"attributeKey\": \"attributeValue\"},\n// \"telemetry\": {\"telemetryKey\": \"telemetryValue\"}\n// }\n\nfunction decodePayload(input) {\n var output = { attributes: {}, telemetry: []};\n \n var decoded = {};\n for (var i = 0; i < input.length - 2 ; ) {\n var channel_id = input[i++] & 0xff;\n var channel_type = input[i++] & 0xff;\n \n // BATTERY\n if (channel_id === 0x01 && channel_type === 0x75) {\n decoded.battery = input[i];\n i += 1;\n }\n // TEMPERATURE\n else if (channel_id === 0x03 && channel_type === 0x67) {\n decoded.temperature = parseBytesToInt(input, i, 2, false) / 10;\n i += 2;\n }\n // DISTANCE\n else if (channel_id === 0x04 && channel_type === 0x82) {\n decoded.distance = parseBytesToInt(input, i, 2, false);\n i += 2;\n }\n // POSITION\n else if (channel_id === 0x05 && channel_type === 0x00) {\n decoded.position = input[i] === 0 ? \"normal\" : \"tilt\";\n i += 1;\n }\n // TEMPERATURE WITH ABNORMAL\n else if (channel_id === 0x83 && channel_type === 0x67) {\n decoded.temperature = parseBytesToInt(input, i, 2, false) / 10;\n decoded.temperature_abnormal = input[i + 2] == 0 ? false : true;\n i += 3;\n }\n // DISTANCE WITH ALARMING\n else if (channel_id === 0x84 && channel_type === 0x82) {\n decoded.distance = parseBytesToInt(input, i, 2, false);\n decoded.distance_alarming = input[i + 2] == 0 ? false : true;\n i += 3;\n }\n }\n \n output.telemetry = [{\n ts: timestamp,\n values: decoded\n }];\n\n // --- Decoding code --- //\n return output;\n}\n\n// --- attributes and telemetry objects ---\nvar telemetry = [];\nvar attributes = {};\n// --- attributes and telemetry objects ---\n\n// --- Timestamp parsing\ntimestamp = data.ts;\n// --- Timestamp parsing\n\n// Message parsing\n// To avoid paths in the decoded objects we passing false value to function as \"pathInKey\" argument.\n// Warning: pathInKey can cause already found fields to be overwritten with the last value found.\n\nvar uplinkDataList = [];\n\n// Passing incoming bytes to decodePayload function, to get custom decoding\nvar customDecoding = decodePayload(hexToBytes(data.data));\n\n// Collecting data to result\nif (customDecoding.?telemetry.size() > 0) {\n if (customDecoding.telemetry instanceof java.util.ArrayList) {\n foreach(telemetryObj: customDecoding.telemetry) {\n if (telemetryObj.ts != null && telemetryObj.values != null) {\n telemetry.add(telemetryObj);\n }\n }\n } else {\n telemetry.putAll(customDecoding.telemetry);\n }\n}\n\nif (customDecoding.?attributes.size() > 0) {\n attributes.putAll(customDecoding.attributes);\n}\n\n// You can add some keys manually to attributes or telemetry\nattributes.eui = data.EUI;\nattributes.fPort = data.port;\nattributes.frequency = data.freq;\n\nvar isIncludeGatewayInfo = metadata[\"includeGatewayInfo\"];\nif(isIncludeGatewayInfo == true) {\n var addDataToTelemetry = {};\n addDataToTelemetry.rssi = data.rssi;\n addDataToTelemetry.seqno = data.seqno;\n addDataToTelemetry.snr = data.snr;\n addDataToTelemetry.ack = data.ack;\n addDataToTelemetry.toa = data.toa;\n addDataToTelemetry.fCnt = data.fcnt;\n \n telemetry = processTelemetryData(telemetry, addDataToTelemetry);\n}\n\nvar deviceInfo = {\n deviceName: deviceName,\n deviceType: deviceType,\n// assetName: assetName,\n// assetType: assetType,\n attributes: attributes,\n telemetry: telemetry, \n};\n\naddAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName);\n\nuplinkDataList.add(deviceInfo);\n\nvar gatewayDeviceNamePrefix = \"Gateway \";\nvar gatewayDeviceType = \"Lora gateway\";\nvar gatewayGroupName = null; // If gatewayGroupName is not null - created device will be added to the entity group with such name.\n\nif (data.cmd == \"gw\") {\n foreach( gatewayInfo : data.gws ) {\n var addGatewayInfo = {};\n\n // You can add some keys manually telemetry\n addGatewayInfo.rssi = gatewayInfo.rssi;\n addGatewayInfo.snr = gatewayInfo.snr;\n // You can add some keys manually telemetry\n \n var gatewayInfoMsg = {\n deviceName: gatewayDeviceNamePrefix + gatewayInfo.gweui,\n deviceType: gatewayDeviceType,\n telemetry: [{\n \"ts\": gatewayInfo.ts,\n \"values\": addGatewayInfo\n }],\n attributes: {\n eui: gatewayInfo.gweui\n }\n };\n addAdditionalInfoForDeviceMsg(gatewayInfoMsg, customerName, gatewayGroupName);\n uplinkDataList.add(gatewayInfoMsg);\n }\n}\n\nreturn uplinkDataList;\n\nfunction addAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName) {\n if (customerName != null) {\n deviceInfo.customerName = customerName;\n }\n if (groupName != null) {\n deviceInfo.groupName = groupName;\n }\n}\n\nfunction processTelemetryData(telemetry, addDataToTelemetry) {\n if (telemetry.size >= 1) {\n telemetry = addDataToTelemetries(telemetry, addDataToTelemetry);\n }\n else {\n telemetry.add(addDataToTelemetry);\n }\n \n return telemetry;\n}\n\nfunction addDataToTelemetries(telemetries, addDataToTelemetry) {\n foreach(telemetry : telemetries) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[\"values\"].keys.contains(element.key)) {\n telemetry[\"values\"][element.key] = element.value;\n }\n } \n }\n \n return telemetries;\n}", + "encoder": null, + "tbelEncoder": null, + "updateOnlyKeys": [ + "fPort", + "ack", + "eui", + "frequency", + "dr", + "battery" + ] + }, + "additionalInfo": { + "description": "" + }, + "edgeTemplate": false +} \ No newline at end of file diff --git a/VENDORS/Milesight/EM400-TLD/LORIOT/uplink/metadata.json b/VENDORS/Milesight/EM400-TLD/LORIOT/uplink/metadata.json new file mode 100644 index 00000000..ae2ee743 --- /dev/null +++ b/VENDORS/Milesight/EM400-TLD/LORIOT/uplink/metadata.json @@ -0,0 +1,4 @@ +{ + "integrationName": "Loriot integration", + "includeGatewayInfo": "false" +} \ No newline at end of file diff --git a/VENDORS/Milesight/EM400-TLD/LORIOT/uplink/payload.json b/VENDORS/Milesight/EM400-TLD/LORIOT/uplink/payload.json new file mode 100644 index 00000000..95879188 --- /dev/null +++ b/VENDORS/Milesight/EM400-TLD/LORIOT/uplink/payload.json @@ -0,0 +1,17 @@ +{ + "cmd": "rx", + "seqno": 3040, + "EUI": "1000000000000001", + "ts": 1684478801936, + "fcnt": 2, + "port": 85, + "freq": 867500000, + "rssi": -21, + "snr": 10, + "toa": 206, + "dr": "SF9 BW125 4/5", + "ack": false, + "bat": 94, + "offline": false, + "data": "8367e800018482410601" +} \ No newline at end of file diff --git a/VENDORS/Milesight/EM400-TLD/LORIOT/uplink/payload_1.json b/VENDORS/Milesight/EM400-TLD/LORIOT/uplink/payload_1.json new file mode 100644 index 00000000..ef349fd0 --- /dev/null +++ b/VENDORS/Milesight/EM400-TLD/LORIOT/uplink/payload_1.json @@ -0,0 +1,17 @@ +{ + "cmd": "rx", + "seqno": 3040, + "EUI": "1000000000000001", + "ts": 1684478801936, + "fcnt": 2, + "port": 85, + "freq": 867500000, + "rssi": -21, + "snr": 10, + "toa": 206, + "dr": "SF9 BW125 4/5", + "ack": false, + "bat": 94, + "offline": false, + "data": "01755C0367010104824408050001" +} \ No newline at end of file diff --git a/VENDORS/Milesight/EM400-TLD/LORIOT/uplink/result.json b/VENDORS/Milesight/EM400-TLD/LORIOT/uplink/result.json new file mode 100644 index 00000000..a2412303 --- /dev/null +++ b/VENDORS/Milesight/EM400-TLD/LORIOT/uplink/result.json @@ -0,0 +1,18 @@ +[{ + "deviceName": "1000000000000001", + "deviceType": "EM400-TLD", + "attributes": { + "eui": "1000000000000001", + "fPort": 85, + "frequency": 867500000 + }, + "telemetry": [{ + "ts": 1684478801936, + "values": { + "temperature": 23.2, + "temperature_abnormal": true, + "distance": 1601, + "distance_alarming": true + } + }] +}] \ No newline at end of file diff --git a/VENDORS/Milesight/EM400-TLD/LORIOT/uplink/result_1.json b/VENDORS/Milesight/EM400-TLD/LORIOT/uplink/result_1.json new file mode 100644 index 00000000..21f8b330 --- /dev/null +++ b/VENDORS/Milesight/EM400-TLD/LORIOT/uplink/result_1.json @@ -0,0 +1,18 @@ +[{ + "deviceName": "1000000000000001", + "deviceType": "EM400-TLD", + "attributes": { + "eui": "1000000000000001", + "fPort": 85, + "frequency": 867500000 + }, + "telemetry": [{ + "ts": 1684478801936, + "values": { + "battery": 92, + "temperature": 25.7, + "distance": 2116, + "position": "tilt" + } + }] +}] \ No newline at end of file diff --git a/VENDORS/Milesight/EM400-TLD/ThingsStackCommunity/uplink/converter.json b/VENDORS/Milesight/EM400-TLD/ThingsStackCommunity/uplink/converter.json new file mode 100644 index 00000000..74b384df --- /dev/null +++ b/VENDORS/Milesight/EM400-TLD/ThingsStackCommunity/uplink/converter.json @@ -0,0 +1,39 @@ +{ + "name": "The Things Stack Community Uplink Decoder for EM400-TLD", + "type": "UPLINK", + "debugMode": false, + "debugSettings": { + "failuresEnabled": true, + "allEnabled": false, + "allEnabledUntil": 1733331880270 + }, + "configuration": { + "scriptLang": "TBEL", + "decoder": null, + "tbelDecoder": "var data = decodeToJson(payload);\n\nvar deviceName = data.end_device_ids.device_id;\nvar deviceType = \"EM400-TLD\";\nvar groupName = null; // If groupName is not null - created device will be added to the entity group with such name.\nvar customerName = null; // If customerName is not null - created devices will be assigned to customer with such name. \n\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// If you want to parse incoming data somehow, you can add your code to this function.\n// input: bytes\n// expected output:\n// {\n// \"attributes\": {\"attributeKey\": \"attributeValue\"},\n// \"telemetry\": [{\"ts\": 1...1, \"values\": {\"telemetryKey\":\"telemetryValue\"}, {\"ts\": 1...2, \"values\": {\"telemetryKey\":\"telemetryValue\"}}]\n// }\n\nfunction decodeFrmPayload(input) {\n var output = {\n attributes: {}, telemetry: {}\n };\n \n // --- Decoding code --- //\n var decoded = {};\n for (var i = 0; i < input.length - 2 ; ) {\n var channel_id = input[i++] & 0xff;\n var channel_type = input[i++] & 0xff;\n\n // BATTERY\n if (channel_id === 0x01 && channel_type === 0x75) {\n decoded.battery = input[i];\n i += 1;\n }\n // TEMPERATURE\n else if (channel_id === 0x03 && channel_type === 0x67) {\n decoded.temperature = parseBytesToInt(input, i, 2, false) / 10;\n i += 2;\n }\n // DISTANCE\n else if (channel_id === 0x04 && channel_type === 0x82) {\n decoded.distance = parseBytesToInt(input, i, 2, false);\n i += 2;\n }\n // POSITION\n else if (channel_id === 0x05 && channel_type === 0x00) {\n decoded.position = input[i] === 0 ? \"normal\" : \"tilt\";\n i += 1;\n }\n // TEMPERATURE WITH ABNORMAL\n else if (channel_id === 0x83 && channel_type === 0x67) {\n decoded.temperature = parseBytesToInt(input, i, 2, false) / 10;\n decoded.temperature_abnormal = input[i + 2] == 0 ? false : true;\n i += 3;\n }\n // DISTANCE WITH ALARMING\n else if (channel_id === 0x84 && channel_type === 0x82) {\n decoded.distance = parseBytesToInt(input, i, 2, false);\n decoded.distance_alarming = input[i + 2] == 0 ? false : true;\n i += 3;\n }\n }\n \n output.telemetry = [{\n ts: timestamp,\n values: decoded\n }];\n \n // --- Decoding code --- //\n return output;\n}\n\n\n// --- attributes and telemetry objects ---\nvar telemetry = [];\nvar attributes = {};\n// --- attributes and telemetry objects ---\n\n// --- Timestamp parsing\nvar dateString = data.uplink_message.received_at;\n// If data is simulated or device doesn't send his own date string - we will use date from upcoming message, set by network server\nif ((data.simulated != null && data.simulated) || dateString == null) {\n dateString = data.received_at;\n}\ntimestamp = parseDateToTimestamp(dateString);\n// --- Timestamp parsing\n\n// Message parsing\n// To avoid paths in the decoded objects we passing false value to function as \"pathInKey\" argument.\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.\n\n// Passing incoming bytes to decodeFrmPayload function, to get custom decoding\nvar customDecoding = {};\nif (data.uplink_message.get(\"frm_payload\") != null) {\n customDecoding = decodeFrmPayload(base64ToBytes(data.uplink_message.frm_payload));\n}\n\n// Collecting data to result\nif (customDecoding.?telemetry.size() > 0) {\n if (customDecoding.telemetry instanceof java.util.ArrayList) {\n foreach(telemetryObj: customDecoding.telemetry) {\n if (telemetryObj.ts != null && telemetryObj.values != null) {\n telemetry.add(telemetryObj);\n }\n }\n } else {\n telemetry.putAll(customDecoding.telemetry);\n }\n}\n\nif (customDecoding.?attributes.size() > 0) {\n attributes.putAll(customDecoding.attributes);\n}\n\n// You can add some keys manually to attributes or telemetry\nvar applicationId = data.end_device_ids.?application_ids.?application_id;\nvar devAddr = data.end_device_ids.?dev_addr;\nvar spreadingFactor = data.uplink_message.?settings.?data_rate.?lora.?spreading_factor;\nvar codeRate = data.uplink_message.?settings.?data_rate.?lora.?coding_rate;\nvar tenantId = data.uplink_message.?network_ids.?tenant_id;\nattributes.eui = data.end_device_ids.dev_eui;\nattributes.fPort = data.uplink_message.f_port;\nattributes.applicationId = applicationId;\nattributes.devAddr = devAddr;\nattributes.spreadingFactor = spreadingFactor;\nattributes.codeRate = codeRate;\nattributes.tenantId = tenantId;\nattributes.device_id = data.end_device_ids.?device_id;\nattributes.join_eui = data.end_device_ids.?join_eui;\nattributes.net_id = data.uplink_message.?network_ids.?net_id;\nattributes.cluster_id = data.uplink_message.?network_ids.?cluster_id;\nattributes.cluster_adress = data.uplink_message.?network_ids.?cluster_address;\nattributes.bandwidth = data.uplink_message.?settings.?data_rate.?lora.?bandwidth;\nattributes.frequency = data.uplink_message.?settings.?frequency;\n\n\nvar gatewayInfo = getGatewayInfo();\nvar addDataToTelemetry = {};\naddDataToTelemetry.snr = gatewayInfo.snr;\naddDataToTelemetry.rssi = gatewayInfo.rssi;\naddDataToTelemetry.channel = gatewayInfo.channel_index;\naddDataToTelemetry.consumed_airtime = data.uplink_message.?consumed_airtime;\naddDataToTelemetry.fCnt = data.uplink_message.?f_cnt;\n\nvar isIncludeGatewayInfo = metadata[\"includeGatewayInfo\"];\nif(isIncludeGatewayInfo == true) {\n telemetry = processTelemetryData(telemetry, addDataToTelemetry);\n}\n\nvar result = {\n deviceName: deviceName,\n deviceType: deviceType,\n// assetName: assetName,\n// assetType: assetType,\n attributes: attributes,\n telemetry: telemetry\n};\n\naddAdditionalInfoForDeviceMsg(result, customerName, groupName);\n\nreturn result;\n\n\nfunction addAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName) {\n if (customerName != null) {\n deviceInfo.customerName = customerName;\n }\n if (groupName != null) {\n deviceInfo.groupName = groupName;\n }\n}\n\nfunction parseDateToTimestamp(dateString) {\n var date = new Date(dateString);\n var timestamp = date.getTime();\n \n // If we cannot parse timestamp - we will use the current timestamp\n if (timestamp == -1) {\n timestamp = Date.now();\n }\n \n return timestamp;\n}\n\nfunction getGatewayInfo() {\n var gatewayList = data.uplink_message.?rx_metadata;\n var maxRssi = Integer.MIN_VALUE;\n var gatewayInfo = {};\n \n foreach (gateway : gatewayList) {\n if(gateway.rssi > maxRssi) {\n maxRssi = gateway.rssi;\n gatewayInfo = gateway;\n }\n }\n \n return gatewayInfo;\n}\n\nfunction processTelemetryData(telemetry, addDataToTelemetry) {\n if (telemetry.size >= 1) {\n telemetry = addDataToTelemetries(telemetry, addDataToTelemetry);\n }\n else {\n telemetry.add(addDataToTelemetry);\n }\n \n return telemetry;\n}\n\nfunction addDataToTelemetries(telemetries, addDataToTelemetry) {\n foreach(telemetry : telemetries) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[\"values\"].keys.contains(element.key)) {\n telemetry[\"values\"][element.key] = element.value;\n }\n } \n }\n \n return telemetries;\n}", + "encoder": null, + "tbelEncoder": null, + "updateOnlyKeys": [ + "fPort", + "bandwidth", + "frequency", + "net_id", + "cluster_id", + "cluster_address", + "device_id", + "join_eui", + "battery", + "eui", + "channel", + "applicationId", + "devAddr", + "spreadingFactor", + "codeRate", + "tenantId" + ] + }, + "additionalInfo": { + "description": "" + }, + "edgeTemplate": false +} \ No newline at end of file diff --git a/VENDORS/Milesight/EM400-TLD/ThingsStackCommunity/uplink/metadata.json b/VENDORS/Milesight/EM400-TLD/ThingsStackCommunity/uplink/metadata.json new file mode 100644 index 00000000..0d75c374 --- /dev/null +++ b/VENDORS/Milesight/EM400-TLD/ThingsStackCommunity/uplink/metadata.json @@ -0,0 +1,4 @@ +{ + "integrationName": "The Things Stack Community integration", + "includeGatewayInfo": "false" +} \ No newline at end of file diff --git a/VENDORS/Milesight/EM400-TLD/ThingsStackCommunity/uplink/payload.json b/VENDORS/Milesight/EM400-TLD/ThingsStackCommunity/uplink/payload.json new file mode 100644 index 00000000..281d8f45 --- /dev/null +++ b/VENDORS/Milesight/EM400-TLD/ThingsStackCommunity/uplink/payload.json @@ -0,0 +1,54 @@ +{ + "end_device_ids": { + "device_id": "eui-1000000000000001", + "application_ids": { + "application_id": "application-tts-name" + }, + "dev_eui": "1000000000000001", + "join_eui": "2000000000000001", + "dev_addr": "20000001" + }, + "correlation_ids": ["as:up:01H0S7ZJQ9MQPMVY49FT3SE07M", "gs:conn:01H03BQZ9342X3Y86DJ2P704E5", "gs:up:host:01H03BQZ99EGAM52KK1300GFKN", "gs:uplink:01H0S7ZJGS6D9TJSKJN8XNTMAV", "ns:uplink:01H0S7ZJGS9KKD4HTTPKFEMWCV", "rpc:/ttn.lorawan.v3.GsNs/HandleUplink:01H0S7ZJGSF3M38ZRZVTM38DEC", "rpc:/ttn.lorawan.v3.NsAs/HandleUplink:01H0S7ZJQ8R2EH5AA269AKM8DX"], + "received_at": "2023-05-19T05:33:35.848446463Z", + "uplink_message": { + "session_key_id": "AYfqmb0pc/1uRZv9xUydgQ==", + "f_port": 85, + "f_cnt": 10335, + "frm_payload": "g2foAAGEgkEGAQ==", + "rx_metadata": [{ + "gateway_ids": { + "gateway_id": "eui-6a7e111a10000000", + "eui": "6A7E111A10000000" + }, + "time": "2023-05-19T05:33:35.608982Z", + "timestamp": 3893546133, + "rssi": -35, + "channel_rssi": -35, + "snr": 13.2, + "frequency_offset": "69", + "uplink_token": "CiIKIAoUZXVpLTZhN2UxMTFhMTAwMDAwMDASCCThJP/+9k6eEJWZy8AOGgwIr5ScowYQvNbUsQIgiMy8y6jwpwE=", + "channel_index": 3, + "received_at": "2023-05-19T05:33:35.607383681Z" + }], + "settings": { + "data_rate": { + "lora": { + "bandwidth": 125000, + "spreading_factor": 7, + "coding_rate": "4/5" + } + }, + "frequency": "867100000", + "timestamp": 3893546133, + "time": "2023-05-19T05:33:35.608982Z" + }, + "received_at": "2023-05-19T05:33:35.641841782Z", + "consumed_airtime": "0.056576s", + "network_ids": { + "net_id": "000013", + "tenant_id": "ttn", + "cluster_id": "eu1", + "cluster_address": "eu1.cloud.thethings.network" + } + } +} \ No newline at end of file diff --git a/VENDORS/Milesight/EM400-TLD/ThingsStackCommunity/uplink/payload_1.json b/VENDORS/Milesight/EM400-TLD/ThingsStackCommunity/uplink/payload_1.json new file mode 100644 index 00000000..76ae9bd5 --- /dev/null +++ b/VENDORS/Milesight/EM400-TLD/ThingsStackCommunity/uplink/payload_1.json @@ -0,0 +1,54 @@ +{ + "end_device_ids": { + "device_id": "eui-1000000000000001", + "application_ids": { + "application_id": "application-tts-name" + }, + "dev_eui": "1000000000000001", + "join_eui": "2000000000000001", + "dev_addr": "20000001" + }, + "correlation_ids": ["as:up:01H0S7ZJQ9MQPMVY49FT3SE07M", "gs:conn:01H03BQZ9342X3Y86DJ2P704E5", "gs:up:host:01H03BQZ99EGAM52KK1300GFKN", "gs:uplink:01H0S7ZJGS6D9TJSKJN8XNTMAV", "ns:uplink:01H0S7ZJGS9KKD4HTTPKFEMWCV", "rpc:/ttn.lorawan.v3.GsNs/HandleUplink:01H0S7ZJGSF3M38ZRZVTM38DEC", "rpc:/ttn.lorawan.v3.NsAs/HandleUplink:01H0S7ZJQ8R2EH5AA269AKM8DX"], + "received_at": "2023-05-19T05:33:35.848446463Z", + "uplink_message": { + "session_key_id": "AYfqmb0pc/1uRZv9xUydgQ==", + "f_port": 85, + "f_cnt": 10335, + "frm_payload": "AXVcA2cBAQSCRAgFAAE=", + "rx_metadata": [{ + "gateway_ids": { + "gateway_id": "eui-6a7e111a10000000", + "eui": "6A7E111A10000000" + }, + "time": "2023-05-19T05:33:35.608982Z", + "timestamp": 3893546133, + "rssi": -35, + "channel_rssi": -35, + "snr": 13.2, + "frequency_offset": "69", + "uplink_token": "CiIKIAoUZXVpLTZhN2UxMTFhMTAwMDAwMDASCCThJP/+9k6eEJWZy8AOGgwIr5ScowYQvNbUsQIgiMy8y6jwpwE=", + "channel_index": 3, + "received_at": "2023-05-19T05:33:35.607383681Z" + }], + "settings": { + "data_rate": { + "lora": { + "bandwidth": 125000, + "spreading_factor": 7, + "coding_rate": "4/5" + } + }, + "frequency": "867100000", + "timestamp": 3893546133, + "time": "2023-05-19T05:33:35.608982Z" + }, + "received_at": "2023-05-19T05:33:35.641841782Z", + "consumed_airtime": "0.056576s", + "network_ids": { + "net_id": "000013", + "tenant_id": "ttn", + "cluster_id": "eu1", + "cluster_address": "eu1.cloud.thethings.network" + } + } +} \ No newline at end of file diff --git a/VENDORS/Milesight/EM400-TLD/ThingsStackCommunity/uplink/result.json b/VENDORS/Milesight/EM400-TLD/ThingsStackCommunity/uplink/result.json new file mode 100644 index 00000000..81491dfb --- /dev/null +++ b/VENDORS/Milesight/EM400-TLD/ThingsStackCommunity/uplink/result.json @@ -0,0 +1,29 @@ +{ + "deviceName": "eui-1000000000000001", + "deviceType": "EM400-TLD", + "attributes": { + "eui": "1000000000000001", + "fPort": 85, + "applicationId": "application-tts-name", + "devAddr": "20000001", + "spreadingFactor": 7, + "codeRate": "4/5", + "tenantId": "ttn", + "device_id": "eui-1000000000000001", + "join_eui": "2000000000000001", + "net_id": "000013", + "cluster_id": "eu1", + "cluster_adress": "eu1.cloud.thethings.network", + "bandwidth": 125000, + "frequency": "867100000" + }, + "telemetry": [{ + "ts": 1684474415641, + "values": { + "temperature": 23.2, + "temperature_abnormal": true, + "distance": 1601, + "distance_alarming": true + } + }] +} \ No newline at end of file diff --git a/VENDORS/Milesight/EM400-TLD/ThingsStackCommunity/uplink/result_1.json b/VENDORS/Milesight/EM400-TLD/ThingsStackCommunity/uplink/result_1.json new file mode 100644 index 00000000..9cb5688c --- /dev/null +++ b/VENDORS/Milesight/EM400-TLD/ThingsStackCommunity/uplink/result_1.json @@ -0,0 +1,29 @@ +{ + "deviceName": "eui-1000000000000001", + "deviceType": "EM400-TLD", + "attributes": { + "eui": "1000000000000001", + "fPort": 85, + "applicationId": "application-tts-name", + "devAddr": "20000001", + "spreadingFactor": 7, + "codeRate": "4/5", + "tenantId": "ttn", + "device_id": "eui-1000000000000001", + "join_eui": "2000000000000001", + "net_id": "000013", + "cluster_id": "eu1", + "cluster_adress": "eu1.cloud.thethings.network", + "bandwidth": 125000, + "frequency": "867100000" + }, + "telemetry": [{ + "ts": 1684474415641, + "values": { + "battery": 92, + "temperature": 25.7, + "distance": 2116, + "position": "tilt" + } + }] +} \ No newline at end of file diff --git a/VENDORS/Milesight/EM400-TLD/ThingsStackIndustries/uplink/converter.json b/VENDORS/Milesight/EM400-TLD/ThingsStackIndustries/uplink/converter.json new file mode 100644 index 00000000..a3f57163 --- /dev/null +++ b/VENDORS/Milesight/EM400-TLD/ThingsStackIndustries/uplink/converter.json @@ -0,0 +1,40 @@ +{ + "name": "The Things Stack Industries Uplink Decoder for EM400-TLD", + "type": "UPLINK", + "debugMode": false, + "debugSettings": { + "failuresEnabled": true, + "allEnabled": false, + "allEnabledUntil": 1733331880270 + }, + "configuration": { + "scriptLang": "TBEL", + "decoder": null, + "tbelDecoder": "var data = decodeToJson(payload);\n\nvar deviceName = data.end_device_ids.device_id;\nvar deviceType = \"EM400-TLD\";\nvar groupName = null; // If groupName is not null - created device will be added to the entity group with such name.\nvar customerName = null; // If customerName is not null - created devices will be assigned to customer with such name. \n\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// If you want to parse incoming data somehow, you can add your code to this function.\n// input: bytes\n// expected output:\n// {\n// \"attributes\": {\"attributeKey\": \"attributeValue\"},\n// \"telemetry\": [{\"ts\": 1...1, \"values\": {\"telemetryKey\":\"telemetryValue\"}, {\"ts\": 1...2, \"values\": {\"telemetryKey\":\"telemetryValue\"}}]\n// }\n\nfunction decodeFrmPayload(input) {\n var output = { attributes: {}, telemetry: []};\n \n // --- Decoding code --- //\n var decoded = {};\n for (var i = 0; i < input.length - 2 ; ) {\n var channel_id = input[i++] & 0xff;\n var channel_type = input[i++] & 0xff;\n\n // BATTERY\n if (channel_id === 0x01 && channel_type === 0x75) {\n decoded.battery = input[i];\n i += 1;\n }\n // TEMPERATURE\n else if (channel_id === 0x03 && channel_type === 0x67) {\n decoded.temperature = parseBytesToInt(input, i, 2, false) / 10;\n i += 2;\n }\n // DISTANCE\n else if (channel_id === 0x04 && channel_type === 0x82) {\n decoded.distance = parseBytesToInt(input, i, 2, false);\n i += 2;\n }\n // POSITION\n else if (channel_id === 0x05 && channel_type === 0x00) {\n decoded.position = input[i] === 0 ? \"normal\" : \"tilt\";\n i += 1;\n }\n // TEMPERATURE WITH ABNORMAL\n else if (channel_id === 0x83 && channel_type === 0x67) {\n decoded.temperature = parseBytesToInt(input, i, 2, false) / 10;\n decoded.temperature_abnormal = input[i + 2] == 0 ? false : true;\n i += 3;\n }\n // DISTANCE WITH ALARMING\n else if (channel_id === 0x84 && channel_type === 0x82) {\n decoded.distance = parseBytesToInt(input, i, 2, false);\n decoded.distance_alarming = input[i + 2] == 0 ? false : true;\n i += 3;\n }\n }\n \n output.telemetry = [{\n ts: timestamp,\n values: decoded\n }];\n\n // --- Decoding code --- //\n return output;\n}\n\n// --- attributes and telemetry objects ---\nvar telemetry = [];\nvar attributes = {};\n// --- attributes and telemetry objects ---\n\n// --- Timestamp parsing\nvar dateString = data.uplink_message.received_at;\n\nif ((data.simulated != null && data.simulated) || dateString == null) {\n dateString = data.received_at;\n}\n\ntimestamp = parseDateToTimestamp(dateString);\n// --- Timestamp parsing\n\n// Message parsing\n// To avoid paths in the decoded objects we passing false value to function as \"pathInKey\" argument.\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.\n\n// Passing incoming bytes to decodeFrmPayload function, to get custom decoding\nvar customDecoding = {};\nif (data.uplink_message.get(\"frm_payload\") != null) {\n customDecoding = decodeFrmPayload(base64ToBytes(data.uplink_message.frm_payload));\n}\n\n// Collecting data to result\nif (customDecoding.?telemetry.size() > 0) {\n if (customDecoding.telemetry instanceof java.util.ArrayList) {\n foreach(telemetryObj: customDecoding.telemetry) {\n if (telemetryObj.ts != null && telemetryObj.values != null) {\n telemetry.add(telemetryObj);\n }\n }\n } else {\n telemetry.putAll(customDecoding.telemetry);\n }\n}\n\nif (customDecoding.?attributes.size() > 0) {\n attributes.putAll(customDecoding.attributes);\n}\n\n// You can add some keys manually to attributes or telemetry\nvar applicationId = data.end_device_ids.?application_ids.?application_id;\nvar devAddr = data.end_device_ids.?dev_addr;\nvar spreadingFactor = data.uplink_message.?settings.?data_rate.?lora.?spreading_factor;\nvar codeRate = data.uplink_message.?settings.?data_rate.?lora.?coding_rate;\nvar tenantId = data.uplink_message.?network_ids.?tenant_id;\nattributes.eui = data.end_device_ids.dev_eui;\nattributes.fPort = data.uplink_message.f_port;\nattributes.applicationId = applicationId;\nattributes.devAddr = devAddr;\nattributes.spreadingFactor = spreadingFactor;\nattributes.codeRate = codeRate;\nattributes.tenantId = tenantId;\nattributes.device_id = data.end_device_ids.?device_id;\nattributes.join_eui = data.end_device_ids.?join_eui;\nattributes.net_id = data.uplink_message.?network_ids.?net_id;\nattributes.cluster_id = data.uplink_message.?network_ids.?cluster_id;\nattributes.cluster_adress = data.uplink_message.?network_ids.?cluster_address;\nattributes.bandwidth = data.uplink_message.?settings.?data_rate.?lora.?bandwidth;\nattributes.frequency = data.uplink_message.?settings.?frequency;\n\nvar isIncludeGatewayInfo = metadata[\"includeGatewayInfo\"];\nif(isIncludeGatewayInfo == true) {\n var gatewayInfo = getGatewayInfo();\n var addDataToTelemetry = {};\n addDataToTelemetry.snr = gatewayInfo.snr;\n addDataToTelemetry.rssi = gatewayInfo.rssi;\n addDataToTelemetry.channel = gatewayInfo.channel_index;\n addDataToTelemetry.consumed_airtime = data.uplink_message.?consumed_airtime;\n addDataToTelemetry.fCnt = data.uplink_message.?f_cnt;\n\n telemetry = processTelemetryData(telemetry, addDataToTelemetry);\n}\n\nvar result = {\n deviceName: deviceName,\n deviceType: deviceType,\n // assetName: assetName,\n // assetType: assetType,\n attributes: attributes,\n telemetry: telemetry\n};\n\naddAdditionalInfoForDeviceMsg(result, customerName, groupName);\n\nreturn result;\n\nfunction addAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName) {\n if (customerName != null) {\n deviceInfo.customerName = customerName;\n }\n if (groupName != null) {\n deviceInfo.groupName = groupName;\n }\n}\n\nfunction parseDateToTimestamp(dateString) {\n var date = new Date(dateString);\n var timestamp = date.getTime();\n \n // If we cannot parse timestamp - we will use the current timestamp\n if (timestamp == -1) {\n timestamp = Date.now();\n }\n \n return timestamp;\n}\n\nfunction getGatewayInfo() {\n var gatewayList = data.uplink_message.?rx_metadata;\n var maxRssi = Integer. MIN_VALUE;\n var gatewayInfo = {};\n \n foreach (gateway : gatewayList) {\n if(gateway.rssi > maxRssi) {\n maxRssi = gateway.rssi;\n gatewayInfo = gateway;\n }\n }\n \n return gatewayInfo;\n}\n\nfunction processTelemetryData(telemetry, addDataToTelemetry) {\n if (telemetry.size >= 1) {\n telemetry = addDataToTelemetries(telemetry, addDataToTelemetry);\n }\n else {\n telemetry.add(addDataToTelemetry);\n }\n \n return telemetry;\n}\n\nfunction addDataToTelemetries(telemetries, addDataToTelemetry) {\n foreach(telemetry : telemetries) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[\"values\"].keys.contains(element.key)) {\n telemetry[\"values\"][element.key] = element.value;\n }\n } \n }\n \n return telemetries;\n}", + "encoder": null, + "tbelEncoder": null, + "updateOnlyKeys": [ + "fPort", + "bandwidth", + "frequency", + "net_id", + "cluster_id", + "cluster_address", + "tenant_address", + "device_id", + "join_eui", + "eui", + "channel", + "devAddr", + "spreadingFactor", + "codeRate", + "tenantId", + "applicationId", + "battery" + ] + }, + "additionalInfo": { + "description": "" + }, + "edgeTemplate": false +} \ No newline at end of file diff --git a/VENDORS/Milesight/EM400-TLD/ThingsStackIndustries/uplink/metadata.json b/VENDORS/Milesight/EM400-TLD/ThingsStackIndustries/uplink/metadata.json new file mode 100644 index 00000000..904c0fa0 --- /dev/null +++ b/VENDORS/Milesight/EM400-TLD/ThingsStackIndustries/uplink/metadata.json @@ -0,0 +1,4 @@ +{ + "integrationName": "The Things Stack Industries integration new", + "includeGatewayInfo": "false" +} \ No newline at end of file diff --git a/VENDORS/Milesight/EM400-TLD/ThingsStackIndustries/uplink/payload.json b/VENDORS/Milesight/EM400-TLD/ThingsStackIndustries/uplink/payload.json new file mode 100644 index 00000000..1763bfd0 --- /dev/null +++ b/VENDORS/Milesight/EM400-TLD/ThingsStackIndustries/uplink/payload.json @@ -0,0 +1,77 @@ +{ + "end_device_ids": { + "device_id": "eui-1000000000000001", + "application_ids": { + "application_id": "application-tti-name" + }, + "dev_eui": "1000000000000001", + "join_eui": "2000000000000001", + "dev_addr": "20000001" + }, + "correlation_ids": ["as:up:01H0PZDGB1NW6NAPD815NGHPF6", "gs:conn:01H0FJRSXSYT7VKNYXJ89F95XT", "gs:up:host:01H0FJRSY3MZMGPPFBQ4FZV4T8", "gs:uplink:01H0PZDG4HHGFRTXRTXD4PFTH7", "ns:uplink:01H0PZDG4JZ3BM0K6J89EQK1J7", "rpc:/ttn.lorawan.v3.GsNs/HandleUplink:01H0PZDG4J02F85RYFPCNSNXCR", "rpc:/ttn.lorawan.v3.NsAs/HandleUplink:01H0PZDGB081PMP806BJHNHX1A"], + "received_at": "2023-05-18T08:25:26.112483370Z", + "uplink_message": { + "session_key_id": "AYfg8rhha5n+FWx0ZaAprA==", + "f_port": 85, + "f_cnt": 5017, + "frm_payload": "g2foAAGEgkEGAQ==", + "rx_metadata": [{ + "gateway_ids": { + "gateway_id": "eui-6A7E111A10000000", + "eui": "6A7E111A10000000" + }, + "time": "2023-05-18T08:25:25.885310Z", + "timestamp": 818273765, + "rssi": -24, + "channel_rssi": -24, + "snr": 12, + "frequency_offset": "671", + "uplink_token": "CiIKIAoUZXVpLTZBN0UxMTFBMTAwMDAwMDASCCThJP/+9k6eEOW7l4YDGgwI9cGXowYQ5KPhrwMgiI2rp+jpOA=", + "channel_index": 2, + "received_at": "2023-05-18T08:25:25.869324983Z" + }, { + "gateway_ids": { + "gateway_id": "packetbroker" + }, + "packet_broker": { + "message_id": "01H0PZDG4MF9AYSMNY44MAVTDH", + "forwarder_net_id": "000013", + "forwarder_tenant_id": "ttn", + "forwarder_cluster_id": "eu1.cloud.thethings.network", + "forwarder_gateway_eui": "6A7E111A10000000", + "forwarder_gateway_id": "eui-6a7e111a10000000", + "home_network_net_id": "000013", + "home_network_tenant_id": "tenant", + "home_network_cluster_id": "eu1.cloud.thethings.industries" + }, + "time": "2023-05-18T08:25:25.885310Z", + "rssi": -24, + "channel_rssi": -24, + "snr": 12, + "frequency_offset": "671", + "uplink_token": "eyJnIjoiWlhsS2FHSkhZMmxQYVVwQ1RWUkpORkl3VGs1VE1XTnBURU5LYkdKdFRXbFBhVXBDVFZSSk5GSXdUazVKYVhkcFlWaFphVTlwU201a01uaGhWVlJvZDFSWFVuRmlSM1JtVFcxT2RVbHBkMmxrUjBadVNXcHZhV05ZY0RKT1IyeExaREpSZVZwR1pIUmpNRXBLVlVoR2RFNVZkR3BWVTBvNUxua3paVVJTWVRaM1lXOU1kbTQwVm5sdmIyWmlPWGN1ZUhCZmVrcElaa3hIWlZadGRVUlFVeTVuYlRaVlZXRXdkakpHV0VKMGJUUjZaMjVXUkVoeGVHRjRaMlJKTlVkS1VsbERhemc1VDNCbk5rVk1iM1JDUkVZM1VWbHdZbEJDTkdOblNqWjBlbkphYUV4MFRVMHhZMVZFTTFac01XdExURUo0YURaMFExTnhhMVJsWWw4eE5FdHlVVXcyZUhsRWFFbEhlakJITXpoTE0xaFdlRzR5VUVjMk4wNUViME5WTkhoTmRrazFZVk5oWkUwd2FXVnFjR294VGtoMFduZHlZMDFxVlVGNmRsbERUazlNY2s5eFdVeFpWMk5XTG1WVFFYVkpNVkptT1U5NWRqUTNhSEoxTUZoalYxRT0iLCJhIjp7ImZuaWQiOiIwMDAwMTMiLCJmdGlkIjoidHRuIiwiZmNpZCI6ImV1MS5jbG91ZC50aGV0aGluZ3MubmV0d29yayJ9fQ==", + "received_at": "2023-05-18T08:25:25.906038642Z" + }], + "settings": { + "data_rate": { + "lora": { + "bandwidth": 125000, + "spreading_factor": 7, + "coding_rate": "4/5" + } + }, + "frequency": "868500000", + "timestamp": 818273765, + "time": "2023-05-18T08:25:25.885310Z" + }, + "received_at": "2023-05-18T08:25:25.906399073Z", + "consumed_airtime": "0.097536s", + "network_ids": { + "net_id": "000013", + "tenant_id": "tenant", + "cluster_id": "eu1", + "cluster_address": "eu1.cloud.thethings.industries", + "tenant_address": "tenant.eu1.cloud.thethings.industries" + } + } +} \ No newline at end of file diff --git a/VENDORS/Milesight/EM400-TLD/ThingsStackIndustries/uplink/payload_1.json b/VENDORS/Milesight/EM400-TLD/ThingsStackIndustries/uplink/payload_1.json new file mode 100644 index 00000000..84cc5f8f --- /dev/null +++ b/VENDORS/Milesight/EM400-TLD/ThingsStackIndustries/uplink/payload_1.json @@ -0,0 +1,77 @@ +{ + "end_device_ids": { + "device_id": "eui-1000000000000001", + "application_ids": { + "application_id": "application-tti-name" + }, + "dev_eui": "1000000000000001", + "join_eui": "2000000000000001", + "dev_addr": "20000001" + }, + "correlation_ids": ["as:up:01H0PZDGB1NW6NAPD815NGHPF6", "gs:conn:01H0FJRSXSYT7VKNYXJ89F95XT", "gs:up:host:01H0FJRSY3MZMGPPFBQ4FZV4T8", "gs:uplink:01H0PZDG4HHGFRTXRTXD4PFTH7", "ns:uplink:01H0PZDG4JZ3BM0K6J89EQK1J7", "rpc:/ttn.lorawan.v3.GsNs/HandleUplink:01H0PZDG4J02F85RYFPCNSNXCR", "rpc:/ttn.lorawan.v3.NsAs/HandleUplink:01H0PZDGB081PMP806BJHNHX1A"], + "received_at": "2023-05-18T08:25:26.112483370Z", + "uplink_message": { + "session_key_id": "AYfg8rhha5n+FWx0ZaAprA==", + "f_port": 85, + "f_cnt": 5017, + "frm_payload": "AXVcA2cBAQSCRAgFAAE=", + "rx_metadata": [{ + "gateway_ids": { + "gateway_id": "eui-6A7E111A10000000", + "eui": "6A7E111A10000000" + }, + "time": "2023-05-18T08:25:25.885310Z", + "timestamp": 818273765, + "rssi": -24, + "channel_rssi": -24, + "snr": 12, + "frequency_offset": "671", + "uplink_token": "CiIKIAoUZXVpLTZBN0UxMTFBMTAwMDAwMDASCCThJP/+9k6eEOW7l4YDGgwI9cGXowYQ5KPhrwMgiI2rp+jpOA=", + "channel_index": 2, + "received_at": "2023-05-18T08:25:25.869324983Z" + }, { + "gateway_ids": { + "gateway_id": "packetbroker" + }, + "packet_broker": { + "message_id": "01H0PZDG4MF9AYSMNY44MAVTDH", + "forwarder_net_id": "000013", + "forwarder_tenant_id": "ttn", + "forwarder_cluster_id": "eu1.cloud.thethings.network", + "forwarder_gateway_eui": "6A7E111A10000000", + "forwarder_gateway_id": "eui-6a7e111a10000000", + "home_network_net_id": "000013", + "home_network_tenant_id": "tenant", + "home_network_cluster_id": "eu1.cloud.thethings.industries" + }, + "time": "2023-05-18T08:25:25.885310Z", + "rssi": -24, + "channel_rssi": -24, + "snr": 12, + "frequency_offset": "671", + "uplink_token": "eyJnIjoiWlhsS2FHSkhZMmxQYVVwQ1RWUkpORkl3VGs1VE1XTnBURU5LYkdKdFRXbFBhVXBDVFZSSk5GSXdUazVKYVhkcFlWaFphVTlwU201a01uaGhWVlJvZDFSWFVuRmlSM1JtVFcxT2RVbHBkMmxrUjBadVNXcHZhV05ZY0RKT1IyeExaREpSZVZwR1pIUmpNRXBLVlVoR2RFNVZkR3BWVTBvNUxua3paVVJTWVRaM1lXOU1kbTQwVm5sdmIyWmlPWGN1ZUhCZmVrcElaa3hIWlZadGRVUlFVeTVuYlRaVlZXRXdkakpHV0VKMGJUUjZaMjVXUkVoeGVHRjRaMlJKTlVkS1VsbERhemc1VDNCbk5rVk1iM1JDUkVZM1VWbHdZbEJDTkdOblNqWjBlbkphYUV4MFRVMHhZMVZFTTFac01XdExURUo0YURaMFExTnhhMVJsWWw4eE5FdHlVVXcyZUhsRWFFbEhlakJITXpoTE0xaFdlRzR5VUVjMk4wNUViME5WTkhoTmRrazFZVk5oWkUwd2FXVnFjR294VGtoMFduZHlZMDFxVlVGNmRsbERUazlNY2s5eFdVeFpWMk5XTG1WVFFYVkpNVkptT1U5NWRqUTNhSEoxTUZoalYxRT0iLCJhIjp7ImZuaWQiOiIwMDAwMTMiLCJmdGlkIjoidHRuIiwiZmNpZCI6ImV1MS5jbG91ZC50aGV0aGluZ3MubmV0d29yayJ9fQ==", + "received_at": "2023-05-18T08:25:25.906038642Z" + }], + "settings": { + "data_rate": { + "lora": { + "bandwidth": 125000, + "spreading_factor": 7, + "coding_rate": "4/5" + } + }, + "frequency": "868500000", + "timestamp": 818273765, + "time": "2023-05-18T08:25:25.885310Z" + }, + "received_at": "2023-05-18T08:25:25.906399073Z", + "consumed_airtime": "0.097536s", + "network_ids": { + "net_id": "000013", + "tenant_id": "tenant", + "cluster_id": "eu1", + "cluster_address": "eu1.cloud.thethings.industries", + "tenant_address": "tenant.eu1.cloud.thethings.industries" + } + } +} \ No newline at end of file diff --git a/VENDORS/Milesight/EM400-TLD/ThingsStackIndustries/uplink/result.json b/VENDORS/Milesight/EM400-TLD/ThingsStackIndustries/uplink/result.json new file mode 100644 index 00000000..ffca8352 --- /dev/null +++ b/VENDORS/Milesight/EM400-TLD/ThingsStackIndustries/uplink/result.json @@ -0,0 +1,29 @@ +{ + "deviceName": "eui-1000000000000001", + "deviceType": "EM400-TLD", + "attributes": { + "eui": "1000000000000001", + "fPort": 85, + "applicationId": "application-tti-name", + "devAddr": "20000001", + "spreadingFactor": 7, + "codeRate": "4/5", + "tenantId": "tenant", + "device_id": "eui-1000000000000001", + "join_eui": "2000000000000001", + "net_id": "000013", + "cluster_id": "eu1", + "cluster_adress": "eu1.cloud.thethings.industries", + "bandwidth": 125000, + "frequency": "868500000" + }, + "telemetry": [{ + "ts": 1684398325906, + "values": { + "temperature": 23.2, + "temperature_abnormal": true, + "distance": 1601, + "distance_alarming": true + } + }] +} \ No newline at end of file diff --git a/VENDORS/Milesight/EM400-TLD/ThingsStackIndustries/uplink/result_1.json b/VENDORS/Milesight/EM400-TLD/ThingsStackIndustries/uplink/result_1.json new file mode 100644 index 00000000..8d87d44e --- /dev/null +++ b/VENDORS/Milesight/EM400-TLD/ThingsStackIndustries/uplink/result_1.json @@ -0,0 +1,29 @@ +{ + "deviceName": "eui-1000000000000001", + "deviceType": "EM400-TLD", + "attributes": { + "eui": "1000000000000001", + "fPort": 85, + "applicationId": "application-tti-name", + "devAddr": "20000001", + "spreadingFactor": 7, + "codeRate": "4/5", + "tenantId": "tenant", + "device_id": "eui-1000000000000001", + "join_eui": "2000000000000001", + "net_id": "000013", + "cluster_id": "eu1", + "cluster_adress": "eu1.cloud.thethings.industries", + "bandwidth": 125000, + "frequency": "868500000" + }, + "telemetry": [{ + "ts": 1684398325906, + "values": { + "battery": 92, + "temperature": 25.7, + "distance": 2116, + "position": "tilt" + } + }] +} \ No newline at end of file diff --git a/VENDORS/Milesight/EM400-TLD/guide.md b/VENDORS/Milesight/EM400-TLD/guide.md new file mode 100644 index 00000000..9b39c828 --- /dev/null +++ b/VENDORS/Milesight/EM400-TLD/guide.md @@ -0,0 +1,21 @@ +# Multifunctional Ultrasonic Distance/Level Sensor - Milesight IoT + +The payload decoder function is applicable to EM400-TLD. + +## Payload Definition + +| CHANNEL | ID | TYPE | LENGTH | DESCRIPTION | +| :--------------------: | :--: | :--: | :----: | ------------------------------------------------------ | +| Battery | 0x01 | 0x75 | 1 | battery(1B)
battery, unit: % | +| Temperature | 0x03 | 0x67 | 2 | temperature(2B)
temperature, unit: ℃ | +| Distance | 0x04 | 0x82 | 2 | distance(2B)
distance, unit: mm | +| Position | 0x05 | 0x00 | 1 | position(1B)
position, values(0: normal, 1: tilt) | +| Location
(NB-IoT) | 0x06 | 0x88 | 9 | longitude(4B) + latitude(4B) + motion_status(1B) | +| Temperature Abnormal | 0x83 | 0x67 | 3 | temperature(2B) + status(1B) | +| Distance Alarm | 0x84 | 0x82 | 3 | distance(2B) + status(1B) | + +### Motion Status Definition + +| BITS | 7..4 | 3..0 | +| :---------: | :-------------------------------------------------------------------- | :------------------------------------------------------------------------------ | +| DESCRIPTION | geofence_status, values: (0: inside, 1: outside, 2: unset, 3: unknown | motion_status, values: (0: unknown, 1: start moving, 2: moving, 3: stop moving) | \ No newline at end of file diff --git a/VENDORS/Milesight/EM400-TLD/info.json b/VENDORS/Milesight/EM400-TLD/info.json new file mode 100644 index 00000000..9053f874 --- /dev/null +++ b/VENDORS/Milesight/EM400-TLD/info.json @@ -0,0 +1,6 @@ +{ + "url": "https://www.milesight.com/iot/product/lorawan-sensor/em400-tld", + "label": "EM400-TLD ToF Laser Distance Sensor", + "description": "EM400-TLD is a distance sensor based on ToF (time of flight), which is mainly used for detecting the fill level and position status. With an appropriate FOV with the maximum field angle of 27°, it has almost no blind spot when installed on small-sized waste bins or containers." +} + diff --git a/VENDORS/Milesight/EM400-TLD/photo.png b/VENDORS/Milesight/EM400-TLD/photo.png new file mode 100644 index 0000000000000000000000000000000000000000..336f7dea81ea84acf54bbe607e83da43ffb62cad GIT binary patch literal 54661 zcmd3t_dgZx`^V35jATY-A4*o_$jCZm6qRulh3rbmUU3eGgV3<|-m7Fp!f}p~viCY! z$96d8IUL8#xA*6-`2KP~?)%64ao^W`J+BW&hPo^lc`pJ00G5Xj?mYnjfcpRTzc0}L zTkn?io&W$Sz{7i*CjQo&Son~e>C>tJ=*njcDt_s+3ckf9=3{}+fzQJSS~N7*ZaF)OL=7 zEfMR*Y*SNH2>fuN?p(m;pKmtmUdvsA`qOu>=@b4guYD_gnd$8oTUp<{{j}zvTM4dnk=O*)17DzXnmg6dJbo=T>&;W%Ojxi~k{ zXs@mZR~sNBQin%ly-$+t)-1gY|74UDZ!HuZ)olgY?d;+^DADBo>bQOq9&bJ3-Zkyq ziPf*azW<%i>)?ZT%|^ZGy`AuFz7vs?Dd(!Qu&u2vn`Yvda(uv~eX80{8(YwBSS5zs zbB^o|51U(5d^$qd+}yXO-bD^XUFiW)+37EOsQ8&z5ZM_@z-1D@~=A@3#4qho( z+k#R5$w^hFdeYS7?7kDr@@S4+p`69!?$(|3%4|QZH%1p#$&7e5|I|_MRnmhO_Xc^L zkYuH*AhC+e$%cA7V!uw#l`VtMD4CrwGr@r9TZ9vm(m83-W5CGMO=9awhf+(D1>p|) z^Vtf;{#e@kU65NmVM*}(&?2e{6J!xHI|niRNvU&P_!f)YB*w=EF24yS5Hp-B8;=t7 zq>q;N22^+M6SBMq2-3=)k>>{BmEd$tcNKOUz44bA!RKbiqat%|Duiq2Fai6ONiPLr zs`dHG-g+=bO^f@1JWjfuaWC{;14iV3-A-#RRWo2dXWDbru58Rq}j(Qjnn}#9!d7R-}g8wb3PD*IOhg z>eC*dY{^om+O}tTCv^38`O8?P9~sbr@qF#bXQq~(zu$ze60fnryKJ%pwi|Kn??n{1 z<664QPy0S6;1xqitEK9c&yrdUq6-gU8ESoiiypjJ^R7iHome*A%I{qVJf{bLPu!v| zB^FOY{E@A0o`HI@DTKmKt$~QX5%0UmR08!=6V%V5ol!OgWyQZk@V#Zf&2?u)K8>=W zXWlD+veHDmN}jsV<$hwd+Wo_-iu0!{irDORb^Sx_J_iUb_EoK&^A)>0V?P}fhQN07 zwL;&zC@74YvIQTuo2FVL)`_7^5Ho}Ry>SqD7nM1vezHlOT>?`N`$X<;8{N&AkM;j0 ztWL|HT5X9)pN-QsL+uqA>|Q(xac}XizpQQ@2*zyQB|ZCf<<+OH&L%ui+z1MG;yMv# zZ_#w*2^O}7;T9o-*;3mTtW4PlOxzRXnTp0A7`$EMj7^U+(DIWK@9Fy{z#^k3`YZBh z5PVxK%tID6n^FDF{BFy;)$U5l#z`?x>lUF$Pr-l7Gd6gJI2;?aPh1-=EdOUB<4;Yk z>dws`2(7+!@v$l6En%>0>Sh!V)t%T@&V zFnOhtBlJh_@br4?@zg8$*xqUY9^T#|AF-gdWT*G&+&$FXv&Y{&%^hV_^@x&t@Wz%5>Fko~6onLYkLf97~%L)aPef$=^p| z7PEwAs`>1RI@Nmizsnr$kHUgS6U0jQ-M=J78b%y`8{U_WCDX!cE9KTk=U&jx9J&Z9 zx~GP0SneGMkt&3C{b7!5 zMdY6qg_ltMvz!S5@B5}=YHn4!CSjNJ{bF&wBYS;Eoqe7G$1K?AYc*rR+IZhu42xQ( z{wUvjJ-&W^97+NfiC zYX?-EeUEucJ8QEv8qqlHPV$yhY4(AjG3QynUS(FoU7eu>v()ePsF!Iaj<@~TDzWw%_g8GTGF*X6JBR9~;ht+TlbO#O+)XxCc4 zg6DV($3FZ)j{n_!zItA{wYeEpBko>QY?;(Vd^3j2Z|t**T(+^-JNkk1{krYa9s9k@ zW&+os>&sf`)iTHDyP)oa)jb{w*-(qFfr6>pN5$^A5Y#})4z3`~cd92xLaGnDt&5Yq{&v!(-3EEmGQhaQp`{Ni51yAN#CG)nkaZ{oHh1CVcWaOf*rx z{lWtql>98CSEk!=vCojWywDP}74i9g#WAn1HTqsIx&`}pEWpoQvC}1ao#J^{i2x@{ z^2C2|+3;{?aomf=(+RC0q>l_q$_L?}XMUA?$#L{4=PL9nysAUX<-pB4C1AyJtkaME zj4jDLE0r2p=2DV=dAa|g#Yw}`2)e@K_6ZGeMKD8VNh|Anm?Aw zVWMsXx(-FzzdExsUe(D!7)8$w-Zu=%*ER)hvIR#z0hp>tYAb_8m(2lPo@(=1a#pF` z3cYF?MmYUZ;Howx4+`NQpOd934PRLjV->n}ruy!K1C|v8LFzQJ^+Rsh^R0x1v2$JoJ@&-2&;Od#^%{ z`)UW6W!770lN_><&*(!?>tW#iym4hVD1jk0P`NnBuX!)~y#8fp%$b5fv(FQ`yjE1y zJZ(m-|FZBCJKm4UYu|JhL8@;4vpx&=GDt#WLCco|4I%@VJf!;(80^F^@KIf)bC)=Z zoeh@aeWDgsLIAGgW(1F|YuRqlYOHW&Z-k7>^@mxw?*m7)<-Wd5ORhpp`#iMT)G&3YGluftQAso~#!%ki7e@>uKZeA!)m%EhJjig$eT%PId3Q#HiCFD;2=+y@w<<32mPTebd zIX#+w=ftXW$~4yEqkC2*VTeJk#J}55P`NN`tkY);$mZWl{K*8F@n=Q;z~Iz_RkUcA z-bf-hnCM}9Q774#tWe7!@F8kkTkv>jJeBP^m)Bu zig{Lfa%<^t8W6O+w^f`@e|~ILXN$L8$5BT|l|U(K!O-7dyE~s{WBq@PZK0mItBLN!Rx92@zDBL-!t{x?5(yUpv%ATKBo=`D%a~1i^&dayY9tc<@3@ai*mEF?^$yCV+M76-=?XOR z6okXyd4@YcU?}5V0oyO9y1|@aZTPF`d@AW3 zL#Y@UxSvJ+ZU0jGxN<$sImM=tdvQ5G%l6b}m(Hg8(zZ{jYPJVvt})i{-;yX$9!W^) z6w}i^{0TYznP@!+V&y3bYADzwZvx2 zX3%QhhXP8o(C{2s)+&$hpnli=w+d?VKl7ctW!RSXm%#3pHk+KdK)RkG7IOd^?ya5_ z5|MZ7&}TCKsjrK=@ZkMyNk2gOqFEIdEX8>OYAzN#Y3F_v8Lta+C0isttZMg;kF0;P z@}QAql5y?1TmIc+>P@i0LzY~R*nk<~ev*UwUV3AUr`O#2%>ue*TMj}la;Y{FSjgE4 z9SvfL7S;&H=)?vMBDcMT>#wGE`HDIxMr{0PC1u8l8LG2oS>p%c1Ku3xyLGkF-+R)U zcn1Rlz=22TsuT2bNYL=g7t~1ne{FJ$CKwtX=5d4=t#ulo7hhd$?zr zblL;HIxF8XOm<&0*Mt+-v1^blaO{b|pSnHnM^(9Fl0)UPEJsfTiE~wy)OTPO&#&$! z6+Vy;%E8Mg7=jwaCKGUXQSC^g_Axn-JVV1Q6ai&U4+Jpfu;To4LL^ZyavgYE0eZl2 zR#e2c7+LeqdM@=;dB-`{l5f^#HyO z@1SHJqmNj6myTdhm*O<-2y`iZuuES3)%8!OL*e^Hh1(C?XCA)t$dOgwFdzH~wKaUc zI7INLHq9Y55}OBFYo3eaM`^R8LqBV(?xmrxL5P#BpXgBDL2tGMZ2tF+y}Cs@>24^B zvF&Z2>QE{YS4|kE6!uOZ9YimMxz7N*kj#h~{=6IWJ*_m~=q2)tqfnoJ{Ot8suF49k zJQ#)xL-ubu<}o1RP4kR8Y1<}N%1v>)J1g(V^08wjP1X|;xX9+Gg21EizLj5`ux^&4 zhyk>Ll^>F|0y_)Dzm54m5oT}dP%mugiX}({2n1Bo212GEjBaP>B_5vLd(uZV zN?2IQ$m1RV=;cVu9>DhysW@SlX|CqAaBXR)VHR^@Xll1|TQnXLxWJTnRXl-Bmd8hg zh19iILYPT9Ta)d+uh`pl+x{0*> zpc3=)J$DdXuZu?q7bSO;a+`^B5p;Qp4JA=^pfDmIKUQ8DtpxbG&w1}>Uux?EW46@e z&$zNk?Mz?$*~S)|>|>hiQkwEwAgd}a@OIL923+IwhEk6WB{{Nrz1igrn^ie$LL>#V z`v4iA_H1V?RjZ0&j}MYN5`W7&wj*%6ks!(nz5?d67A651`|oOkUb!4!yd9PNS|V;9 ziszU4UiV9RqRkYJd~izh5o8UpMp|FsX(a<*HRCE4!>@Qqt8+V zx7^mKy-!`_YVkkFiS0+Ngaf3;@8%RkqI*=U1NS%8yqVWRL_8O*XnGlccGX$$9uLK* z4ik`gLPaxKvc;=)aJ7LdLj9H#Hlt^anQ_io@&(&28qhod5k{RCX{yJUq|2kUB z>XLinD<}0(n}0-{YZh?1)kO4&$t`n1{=D0Ujopk0Bz~jGisCcj&6wW@O&PSpiJA?@ z9fZ5*N5l793wlR$N&5gZvnej#e_8OJwUwdj)_2kiuWAKqN$C7NL7&Sh`~lHRy6VJu zP#i7sF)Y#J_tR1pnQ3hiXl+YV&T;;wTMJ52?CvEzBGdSHbB>6s)hd_wBT_obp)pN? z(Xxv5Zbi12Y1$nv)~w5FIA8#e3i36>d0Mkwja$a$iGduZyD%sjuQI&%BSytmzw=I< zoZyIQkg)W6Irw@N=GWMgdQKhbR^o9HSTd)T;|=lkY`NSZkU)lBR-z-v*SqI;L-qIZ0o!ln~ZFU zrGF!DA0J}f#|%udtXj1+kH7J0P2k}I@D(ejJ|04N!EVA z5*GI(ZmHQ2;2Ub%xY_yLDX0hJ?Vog|OlaY=CvzJA7xmwv9|#JSZeMu=pp_NAaxmc? z)c$K%|3Y7Zw7gW3ij=(Bo}&BU{Z5+kh})?_#5?KW_OMCMc#bMQS1(cx!*_#38kl}CG%TO+1@#^%qMXKNFDS#K_&UxkpS|OagD0xx2 z$9s6&In`C*U_)P+BMrd3G?BT{@3BDg9n93!f{uWsgvu0k<)9$w_$HnHzBzqLY!*X^ zjL)KHOyI5*Fq;&wJ<26>!3@(Qzf+3bg9R@y5Sg-x9RKpgoh5U1XSJU&OP@MHDbkNjk0HF@g}etu~oN1bZ&@rQz>c$+gWAB&eAVPE*%~ zsjr>!VileE0I0st4K^R|yJ2@bcf^rt0%;9Ph$_I9eo6(X>7Tfgc?gS+UdIN zprQE~{pI2#YwPs~5T%TKr!L-GaK9n6AiT)kR%WLd4AgG3TOPIs#3LPV1+0x~yq+ls z2aT770pn=Wjx$=&(de&-aHWm=<6&$bKH}WjMpa!qyU_0kLdx#emRxW7V~@Y0AKBcn zP>Tv5Sl!YS%LiH=eQ2r6@qWa=a@+NR?II9(e}E~$AC~C%A$}ycl=|?m1`E4Kw!Bni zghRL7SKayrUjz7vJpG#k&Wqyt9TO!G1K*fo5OUFMvtM|;=RQ{tNXl$MENAty7X@`2hIuft-`4r{v}=Z zb8QM&hjtrDe>q$}@-@^q;&XntQac>Pip;H%>9iU_kwDQaZ@L<>8M9R+=P|l;R*|+p z(dK1uECpBv-tmfCV7Xb0-(M(^h86Ar-p6l$)%6Jgua@hx{PAA3lPjVwU5Ho{r+t&F z)MIj23sT5-W1WV(RV%$bislC52bcEUZCR{adbmgHpAlY+XjEhU2h)h59rM)L(O5T7 zCA{TJb5si{^lL!t-mBTN$b1kd&oA%(aSc~@w}@$z((Xri`Ny{{+d>t?feh6v{d6~U z-y|VN7>DM~FZSXw1pbwIGgQ8ySBS_F{gctFyFe#3J(QhXmOLPR6>A(>px2h5fk*MN z3x{D&gq~sgAC{7|#M!2YJz|g&`>7WOC6O6Y(_%%F_24cGTQXf7L_0*Bp+m1~``chW zRauy-ur`{x7`n#_)L#%1r*mYk4vES><;JaodWphA&p z#vQ+J^i;4FqydimGF`^vd*(?xN5@Ar-V7NlBOAo^ipXd#UHI6Y@Fwe?HEaK#CpAfG zKc3#%E~aFtRC1x56aYKn@GngiIqN5p#1&&iX8lUH_q;-$h5fpUPAUDfD!I8Qwq(X! z$(MGUPC78_#KH-lu0J`tAL$tFflzK2l#kB=`WUK52Fe3E9aKP2eSwVqC(`{Z{wc}y zX0Hdt4sI7~Hlr^PmlOqJ8N|5d1j&*oDviQz8k{K-os-BwUiSjf$1A!Ln2zU zL_3=P^2%lqU^G)P&pe+mLx%?h;$S*-G;@16x5NVZ{%XG>Vs6E^o%dwgIo2p_Wk!bh zk+bm%nxEwd=q011uWUB^I$ILkQ`{ie`@DK-gxV$Ad@^WL1s^xJDAoINR}<_zxp+Zi zC5B5o04{E06~0ksyiv9d^O4+Tv3g{UoAXwirO(?C8CBD70e7Q%XfGb~-+rJb-a`z0 zpr!>?J(da=b^?At6-!w%C?V|RJxMxrml2co+-0tVAgFvQT|Hj>q&2c8f7%hh)4wMb za=~+-!)CvLi=`~SV|e$Eg#iYq=MyAReebH!eR}ks*8A)UXfGG`@P4CPs)kN`uE$xI zpYkH?IoVEB3kBZ^=(l2?f_tY0f=~7ql!;mBJPB6u$&pmmlB>Wz)zHZFA*f#ctpC1f zioqYd3(sUaEa+!g9+$ak{21^R78D*dpr2m0Sl2~YGz$7~7t}E2tya15k{EHB*NorB z(i!AkJRHjnwAlNDY4R(U?yg!-J}jmVIXP^>FX>JaCCicsKXCOjCW2L;nL?1*h{up= z=W5rn`@aQih#2Z`Sr(A<@kOtg3fMK`UMqz`eK!P@29O+_d4&N)Jbp70qx_x|uHBNW}P^$R28&t(yb}e>;gf3Ynp;m4%lmWSQX9eajwRZih(?#nNN0cMomVr`b zOxS+)`0N@7_Hugv_nl1F&a%eGN@tR8Td^oSf$>msLPRW@MQftE7@lJs`STXT;~3Az ztgwz*4?PHwoR-njhuhwX&BWi{9k*+|&krU9ONE%QCwZ}FX?}k+1wmJIM0{n8JZAz4 zunv%`Enm)4p0x+Ynru2RknFeHs8RlTmX;e_`&-eKoVDe{%)Z_MhH`*Hpl3CL%M%`J`+ zob(a7N#%YDLaDMUg9-kD{~F6{y`0Pc@>z01(KqXyIEUeD0KBBLW<~*w#X;VTos|mt~qVD@jhv?elM1 z0)%G+*lBn_vDa1U#W~#r`wdBWx7LLG_Q7vj`DhZ=9RXL&wkP~Xr!#GKJ(y`p6Q^$?_JS^H^X?aX zxRB=}?I0f*T8K>HLw!;2+c!7t_W)c=a>N%h9osSE3Gg^W}bzoG_TO!z}wU9lveN^5ad0#FMlfWq9MHt9KYG zS!I0r(YQL&{7pY+HT#~5W69Fq8;4HC_Pd&TZ5Jwij5xS{;RA(!#j!8%tX(PhHXE?ID;x1;|kgtXu6g=wgh4vS0`#bLqh1 z^?3*UeC%A_%deKr_<@J;yAZZhlp#+Oh&!uul&^5)N-*dVAnEaf?00VKjo|&)zxikq zSaN9dRipmZ0gB^F#8N42xn0vf;TJ+=xWK-wLpe>npC1_v#<# z?2GZ^^*vh(8?e}Z=icvXZn%&W=Nw{fVE4V2t-5RR6PP5|psXGHXFojn;im7S&@F+p z!ZJK+I*O&N*)qI;m&NR_D|JH4Q9zAJOPxE&SY#WM?c~YThYW#$Xm)zXhg~=4Fh{v`(QZ>-~g7(+l)|b^xZG2v}Q0;2I#DF0FDD%Lj zKd1MZ4PY5Rctk2!dS!X7h5LUE*M1kg@^+w3hRwwwYIWVZR` z8HqEe<@>3YNuoyp(Q22oG+uqh7&}{TxE!sPqDh$TRKqjW5I44xc~oTZwU2gWPZMEq zVnev!%fhMOR6v2u@?PFi3Om5+y5u+egmoYH$r-+nq>wFJb=Bsv2@I`n^DCO$o!YpY zg_;e|9kdn63(t8Xk7B&6x;Wp?0$0Rxb!SxPG`?+?Z>H-EFXf(wc;&XGcUzBI6G@dRIk39bs*fki_u z?(8nNji#Y*R|`~2c=*QFc5=Prjn3oOLDvSgJ2{^4*UDe!}fkAo3?&l8G!bxYmG>rv#I z3A$;HveL{peD0O>M=nTqZeD`mfb zV!!>C-GsN@uJsB3lh-jHxOBf9e72dtaKrUuY*1hKD0GDZ`Gg1K^!7E|>(*MlI`>VG z;!g*EJC>9?g`g1DQJN1LYb10?yr|@Nn^E;zOH_$F=$-5sYclGG+d)^PqJ&~oj~0Jb z`7~gpfO#|4o5f9dhyKy>6TcL_Np*i3e5&T+Wx#kTZmTSJitU~r!=6Ci&DQnw=WLdo z)+IYD*2GEeo~IDjC4ZZ*FYUR-TS)uQzUEr%*q9-c_)!#iiu~h~FWTHe8eXrg1vvx& z(Vxx}6b)vgTtMn2`}!2uToD;fKil=v)Sop0Da$OhfUqzv|EjEiLg!b9ZlczBQAh1} zJ=9CGw|WtJ9|+$31W(bpHUIj}-~z?Q@{cPZO}uc3W^s+95%Zuj+itx}=~$Qx*}=5% zXJ&k;Wq;V5XAq|5{6nT475e#3JA7YPtmo}%$q`fTreH2rY+AW4#Hn~U?(sFGo(M}J zhdkX!AZwI{t|2yR_932ik=WN=)QevBLfWO=ul@u3E;9eCYepWj5_ay5hT%h^xyuFEpQlU3l_!|T>$ne8;t&sT|$2+kkXm--T zH=C(AQG=oE#$0yDpy(U=7dhnRMrAAOxwTr_pB8&uP=Ak~3F^Hh^A|`&_p;|m0h8BJ zXk_^9eO@_sV*}roKfpIu(nD8MiWV?oX2j6W2&(?Ee@bjN7t=z<`fkJ4o4jrAbgq<8 z9K7Pp!fU7T?JWi+TrN+J7+Lo!;Y9psSK66mtAXeVNc$;kq45DYW+7@c%*n|fL!0h(ZIqYW;auJ9K3#e1k`3MMK=8@cJ=eowO7Iy#J#%3>aZub@NT&)C zW~Q(B1>!F*T>Wd{9Z}Ebc!Xqs2@Md+T;K;;h~ahTu#Iq7VCttOkx|{#?m2kHuZ`C4 z0q@Xj$n>u6-fUN^J+PM>C{2NyaH7dG8VT10iYiWgBu6i5S6*^bq7NyEbokw2MwbE} zoIu0H#FOS$q5^q+CQV;2uVts$@rfOoAolo=ll!(qq8ZwnTS6n&<$bQLYAXmmQ8_kZ zN&8X#F5IGb)7L)s*x9}s9Khd;x1Sn&T0iy)_a<1_rUwnEAV)Zqf$c4o>+6n?-w0pt zuAI!I4WxSXRM#Fk-T35wfn$-<7OPR5@y#FQ6v4$!lBEDBch=`#25Y#I(Evtrl!IX2 zKc|nHivaPhaOmc-YTRb8RSVu0mx`Y@)wrnPhdXDu%)Z@^O!4mwdCv0UNFk=0zjx@V zDX7}VsLN{_veC2epSO|z>fvlndzd~9JNT>& zm4F`Zy_|>IOL9xF@m~m6EDn7;k=?S?UsHR)+;rQq^-g=FCP*7ABJ_k_frj3?`noG~ zJ!&*Fjdy!wC~_gey82@H2%9p$U&Ddz>1O>YV)uT2qypLP$d@O?L^5*aPPV72Pro8g zC2u32-;1q64Y5}TJ_gNJl?RL*q(1GPJM7tBF)5)GlEfX%{{|VRFZnyDKkFn#Z4Klr zb~|-+)JnlP{9m;e9kVnL0FNl79jb&tWKxi05>j>Ory2IeV#+q04?7}oNmse47pHxwP zq-(Cd?PSUANoFw?NZ6^SW!vTVH9b)BsL5PT>6^yGh+LhEot`!~4@a~oc4amueUfH0 zX20Fn{rL(s_&?#@DvMG(G?LdAhI%&Dhi z4_}TcVLLn-?pS1ADS6yn6CUY>_AGU2rd@j@u4D#T{d_v69X3qPa6&itc<0uLo@et& zS*4H)Qjbk%HtUZKm02tDi#BKesf#C0XU>Z^ow+iV_pUqjffr9U&y<>pYd=Gwc~YeCL@Eu<*~L(x5Od2$jwiFn=0TBwuT>J@-} zP-UdU2Gt-738>u4qz3Wj1lAL}XQYR(y4N-z0}Dt9KSDfQ4A11wMG-Qx*$2KxTt*g0 zI_xM{e=SiV@u$}ha#&@9S3do`l1cwAR~2$~gkX2f>?4MfZ|rQ^AhZW`-M$8Lh9K<7 z8o|#DX$CeqO9Dd@4n#n_(!JaOqL2M2fzO6gQL`7n)Hk-kg*F})u(lAk)R zvU!xINXAb14jyT5v?zeBB@oG6r9pg%A7sYcTKkebw7@jPWJZ-(P}_vc4np*DYw|i% z39h|ny8t5l_D+ikA^oGGB99sp#e27A_k~M@^LP2rs!~9`V@9TG)X1=h252m6`hv&M zCwWw=ynnR+TSOzm88s;Ja7}Bj00c$RxyLBcNan2gWIc@}{(0R15Dh-I2ayWBc|xio zv?Foqxz@4>>l|=gPiX;VT|B24FIUsBO5H&W%I8{{f39i(@6_b2WA~Lk?&5gnT6sPP z805_DvdqQpel*3rppZ>5fs~O{th~jso>)*IE^y}`Fqmqg*yW?TtvW?PWc^yUs_ks ziV%&YqBim)neMpVf9pvqDOtY)g)| zx0AjEhOoC@eHH#9stQ;NatC?YV}`Z!o?=?-yEi&}jM(g>8~&9Av@z=i-rbK&s<{RP z$Y*qUE+LA<+GXmoz_HNY5CUIJssGvz?V}832BGQ}Z{+qk-{sLV6Tq->cfB{wGk8uc z8UM74FEbrT9w1&f(M|32!Ll8DxHcYEjlOwDi?_`vGv=o`0?-NFFbXLieX|HOWPdbT zPjA-6$9+`Hf{4>i`J@URw0I?%_m10JizkV!vhD=-?uVyz2?b>=XjB}-qF>sS8F(!k zfo->L_wWAe01MjRaQ$0~jjmB$++hlHMl`NB-QTAD@$CkFdj_(x_^&^6yw|)8z9NOS zalx*_TMvn*EeMLh97&+u6ia+s?tb#a-2zKauCm0Er>%La;OG{?|7e!O*%fKOqbSC- z^V7IJuq*(M*B-Pm=-Abr2qN+LeJ8#wt%8JxqkckTGc8Ptp<>( zf5X3VFjsdKcnML+XGLQu-5KWnm^pK==o&Uh)Z>1t52Fmq`_*4R-55GWv=En79G%qC zx9tku_E87;SDhj1>eI-5sfS?>>++(_iDK@hy5_JkVK_xye}GdlzjZPf3H!-9or~q4E(IWl8nz5yKLW+Xh4Qy@* zJq%tSh8u~DrX6Oyf4zAyBZ89FfSGlid<~3i&%5Z=X!=e{yEFKNKSwN!Gq&y031k>| z=^W+Zr#2~IrDLki@*+K!b0_{GV9hZ0I_q)4r%#BoPo9Xxz!}qwg_)LYN^QOx9RCu1 z1HZqjSb;xXRjg_z1T;HPB6fn>i4=GLGa{ub_>8D(vzIL~IQFOk?u8yOC$Ad+Rh-3e zEt%*1qsc>Vcq{`&hw6O>8VO$q)TlG#M_gHVqhuqV(-#iYUq^&6IlhsaBwk9+_cZiB z@Yz&NAU3kPEWOF&y@gBGvt`$lf$xpW9bGqN9>m2px!>A0)BO+5h|0 z)DYMcF5e*Cb^7vlKD31Osd4tO&xs)A#U765)NV2!E<`^#5|V~8xBw!(^tQQvbP!VL zpHdeW;dL^0t>+#OT;i8A6ti7B)+@s5;g_vX?#{?otUNdHehFSZI3+mH$WcqJe@+PF zFy~nT{mwSE$A5Ru|Bh3GcBrD5m0RxS*mVQ<=g2|67O|mUpkhheHx+acGgB_$i$fa5 zGI4%DL%14C4MWj*BiXMdpy2i?J#Zlb_|fbM@5T% z?{7af##O|0BF)yWx@*STmBUd_uZFRI=XXi%KjNhaPSvImLS48T9}n zQpt%S!u0+bshMq}dDF*IA0)@pX0|f2yL2E}hbF<}eR1NaN_s9P%{yo*t~H_P;2a%w zd5SAOG3NNsA+DUAryEZ|~At6SykaNTbTPIB~Uq4|$w*M=T*7{-R#}=m#*AAlLs67V!F$hRtJ8flKR*z#CoZKg$#Qqyd z*ihHo4($0`(sOR8^Xnhk8(Gqlpg8c48CQ!usR98+0LD-h_X8eu$BWwMg@(2DP%f4r z?uR^&p+)qw;JdOHi)aS+HaA=m_|^TP{MLNM*FgtzIRJxYMq(&F2$|5sTJ&~xrwCb{ zlBbxLY5n!coNcLLeonI@2Ww~?xi!;)Ogk7ZCAjkMU9Rq3S~I7L9i>3)C)yh5`}}a6 znd8EU3FOn9`R}KNF3FWJ$?Gg}09w?jX0m(}b+zT|ib@CUZ{YR=q2@FAfaVSGk&@t( z*tpjXxvEo&Y4;J%^88pwX@`)QM~N_?Gp{kg0`F)u_VVR;ekjE;A~p2^+%aN$nSOEk zH*!?3uji3QLmspEI)}{M-(U@zB(hBHZci~|BvI@GE627dq)ml^uJa58N zDlg&xg*E!DpPX!o69C_J%=Uj;M8BEkx|nN4e1#kN;B*9pbo|FspZ{Ti)3beiEJ=c^Sf{Js_x#bpz`K*z*G zl&QVR_LCA1J_1uh7stfyvMuG{-ld6v;f+7gy(gKKFS8n-9r@T6IB0myo~AN!H*kL6 z8f21Ux^bsHzJINHPcfWj2!PRI860@HzSagG`Be+O6M%|}n0ELO6{V4yx|U@ab5i8f zVmt_d{oVjedL3)=F3)mNG}wM%*ip^aFQL7BtLHq6+*S{?;jZ|l74+4z91-OE0o;uo zuSuKAXZP5%rY^zZu*L{n3IBorr=HX+)SLXN2d5>) z=rZ15kYUPsw{sq{6C2sPFJ=e-oou=sWO!@T-GWRoCMrHYmo~nC+MDJF$3u4#TIUD< zy+zBy9<_ww#WT@B+K(OIFd z8Mfl;lWaOkLysVuL%n$p;(&sUdYk`ZpRG9`4TYqW)oIktF zF5Ed!$LJK27$!&y)zb(CI~}_XqR4uDucCoDp}aL#X*7rVd|;vTom*q4hE`?y5LCaT zzX7;(lJ#A9Bc6ZV6nt20S7B6+I!38vC z;Op2*n&kD9F5i7u`$38dVWP%=7O7brSjFf;b`Z2GumKf$VY#e=B9l6?F{)C+P1c6m zEwa)p83O=-7mR3b#9)7-FGX2z<f=QMfoQ^_rlg66NZ#^ zv6<`>f>M=()2JEFs#7;2io_@dT*eGRNKilM#``5vB&|BF&=& zYLQ^|y^?B%q^^T-4Riiq*TDpCrJuFm-Eqn5-P*0O3aVAvO_#Wr3#9jDvK!p6{xGzF z_g@xw|MuM*0fM5P8i|c*`X6=0Y$asAF*pq958wjq203)D6C#o$ z0-#M}{+s1HVNQ~#d&Tg2XYke5Pq)5V_CIfwzYk$E8BUswKEPn!q4)F#OK<~xe<>5S93{=$VWDie6&qtxn)*XLc(Za%hnVCFxL zY+Fo!v_3DI-xhGM`;!+(3uHtuh$j#I<8Qr#``--5Q-;CI4yW*`1#_++SUrHi(aj6l zjWGT_mImX5P23H^(%X!^QbUjJ$9kVadM-$P=xmHu*Uv&BhT-Qkx(xdpsIlHaYQQQI z3PW=>uV*$(teZ8Ig8oIYrEblpqbRw7h8Nw1(-e0^-rs4H&w`gyXhwtdTOZyP&DAC! z0JHec(pd5~9ROuK7#(G1_Av2w&&yLUwcM?FUzqjprrMh4jFw-fCy|v*Yd$2_i{;(? zLpN69Oh0Q+_5Q`_h4isLER|w1Uv>%t`6Si#IG^T}QsjEx_8&VJcS#(jbhimG7-MuW z8pG%v142TGC(GJ1qk#@(8y#Qk!jJXRm;aBXvv6ptfB*j2=o+CCQVJ4^jFNJ|5G5o9 zq=bP|BEm@7Mh#F9r9nDxN<>0H35gL>14bj#-7v=JdiMQ2f5Of=`o!_Wm~|PMlz})PkQlt2GO6$ZlaEbyJeoO=5E5wFtc>_Ky!M0IbG)B@BG}=^ zfvD~B!-LiDnr+&lMH*Gv3SEEByks-HPQrd)gx+!9yS*p;frmvkaCmPiSN6 zar%J=@?g_0?Qd+a-^-%Fc|cu7;QmX-8(!VTY&KfA0K$5nrx2Mrugfime?l~Akyb>_ z-PXanls!3o>B>p9!xO>a+`S`~JjmkEn(SMqZ#RFxQ0~E&VhV~xF^SG9gX-o)7L#E` z?Bk@9ANOOl7Vjt{&fU5~V6Q2eug`k*u+t`$fSzWGPbz5EJvA$1I+@&Tj^;#MWWE{u z<;j`k<2=)--xmt48{4$1EfG9$P_L^J zyeu6A4Annae$ma^&K6iasxfN3# zxfINo@3*G|&nRX2#pTv0Fs`EO_$Oz#mj7VNT{p+T2ofLoG<`X&rt!ix_%4Ho!ocEC zER5~9Q;D(-YV?b|f&O2HWUG4XOW{Aea?>e6z{FNIa8*qFq!3NY)_$E(?vYLXu9Y6& zyC^F`?ip*Y3`yP`m$O4Iwyk}`tks8<58Ww;hcE|AXqArPl&IOLhpU5i>+2wgz=-C? zLzerqNMnxt&d>jmww2bjH4bN{z~t%#8{oRG|E-E`jJ){@AATR_$%$7n!BdexytZR1 z=>~`NF2Wk_&VIE?LsA*~aGvQw_UDmgHD6$XThF9u)Ruq&xU+;~80YPRgyuY0!4#kO zCar{n&ThEQ{C?wCxKOb%u+uOEhFfAAfAh^nOr=$=19>SoS_j>g_0r}qyflC90q!ZE z0(HnPeSZoPPc}Z!f3jo$=vj(r1QH1We%IN%b7D=r7RWt;z6iFB84}pfp&((Vc8JM6*HqU7}`X$8te3 zbqeDlK(9duOD90~j3g(3>V;gHK8F^2;+^NcDnA1LX$n*4aCC(V${yrz#R$?qDMP_S z$K9hAQEr6;8!Q5}pXMEIFm+_`B3d&P)P{;PktWYpmdO_+re~z9>|1ilu(Hb8=K!fbUlP3qB zqo75IM09_j`>FCe&OW=rnwOTqG8AMPs@KX(yU*kc?QTRBcoT2yLp$mE%O<#Lcl&L` zq&^muT@33i4+Z^O_5bf-s7XFYl0{WQvR0qPA3sx@o-a?7-w3Piw(&rk-#kagG|k^^ zeyRJ^DY{_JJ23+i$hl3ECf+M3y8XNNl`^{ks1H~S$h0iq4b|4snsy5`F0hhP{wVL% zi2J;HAhF%nFxSe^fi*aitfK8Ctu)W39{pdDUXdc68qm{xN!P&{57*^N%o_6~JQ`@P zy|EYad5)-FE!xToulx#G5-KmO@#vjQ)@e524V;M? z`Jus-#g!eQ%}b@7Y5iro6#Ma(}C2_pyM2jUcT0AN4Gz|Z~F=&em3snU+_9m*jF z(X(@m$jP1EMpVDkiuzdofmF>8=u2;E+lz-j*mX)2nIxhnE>a1qR!R02&-d6ySA@xO zy}fJhNR{u@7j)PmwOY)f?6zbC8OiKKrnY8ElT>=A_NP&p2tOU(T$x_Z)EWL?*?Sp zofptvWGWMRIx91OY@0Ti>XgZ4;I(+>nYJ>#R|i(`^*Ono3|`~`L4A1aBnXt!4wBrR zf5&TaIR|c(#tR;LZ6f`-iqSI`;onbE<-zJl*M?0*G2e>zM(tn)YB@M&+Va$*V{ZV{ zfCTPW>~*e!8gd;nryu8;j<0N@MIAF3DMzvJ5?oKeHmeC(3NId9WQEtSHA-w6*!5nR zmeZ3zCK$oyg;zhQHQ$C+K@>8Su5oVn=~UMtKiEu4ince+z8yYFx$04rmXFe&)f^ba z<9Rc;^t10w1LI!o5mp916v~`dy?=2DEp2$5qv4fxjEV7rpw@ManA7Jmzk`Olp*kXE zn*okS^;a_055aPEmGN2bD~K^^?-8kGE|8|?3P*?+v^%_^`B-NxTLW!FDS5=iCH}R= z-n)st$a%+i@on?s^I0kQZGC-yKF6C|Ex3^mbhdCOyHnsU-%)L6kTr25;WGX12AAk3 zUu`Y^6-u2$=cLJ)3FTg9J&r}r+0?UQ`h}i^8uxd+6u3iI#^9YN^Uya zyHrq7;C%!<^$d*Fqr-o{|IEj>S8fsM$Z;*6W*zr}nT1lX1xpjH0Aju_f-TwPy|EI^ z8oB?)Cavs_U|;^59^b~>UQXMk7D>;{UThZbvDGV=uNjWtPmms&@DiLpJbj|pXz94y z7VDs#DAB=n@^k+ps5=$E`gEOA)tB-6n@R;h7ZgW4mM&fCkmDzILHXllGxExa92`Gc zq*hbfXn8&etZIPZ?#lDdesp2*VA*EZ>>bi@8+SHc<vc`z;}U(*pn+=OxYC2nIieNu$CpHg8Z+X;qHd=~YpLlrbkdt`Axg z{$u*4a6Df#s{eG{SY5@o8_28aSTT@)eX7f+g@H(S{Lbm?x`mNx!}#R`*5#SwkRoiR z3eIJ<`=sl@C8Kvw+`NPA(y4UY&UK-ZD3;<*HbvA7co&ur)xLlK?rnVb)EPl7@AE2w z2b^%a2ak)cM=jo*twry@m}x*Srq9%(aYs#eW`qg$Pi|j+0)o>3#(-?V5~>O{lfLqg z9`@5OdKIzIZ=0K>JMZy1R1EFi&S*zP3K$3QfE9@M&4{MEa6!O|W3LPS(3q zXHaabw0pn+RI7cm;O1v6mu>MU?hcEN>$~3tYb%b9a-*+^0pybH{qEIXY} zOaI#=8-4ILRT(jzI_AkD-h7ZyX~I?I%2MMNDM-4VkgPF%HnKefox=!)bavlNWxI&>iYQO_FGX` zty+x&pOL9t*u%uTSxWDpS%?uFSQRqgaLFDBW$>0 z(EnbDg-4HY&uO>PK&q0TeUec(SXgk?7+WUNVb#1eCbHQn65HJMV(w*ff8QRK82?$G zI&i^S#hZGWST6Qnu+J^J`Lv{22|yJaozI?(y}FufVYY(^4kbj!UEfLquz7+Q9sH#> zfCU13X?q7{@4tuX8aBCKXUp1+-GS+35Yy_LfF(HNS-ufxST1ZB_dR+g_dLrcW;|F} zOI~1#Xj%CDP?Tf!E(CwCjnu=b^t?W?6mAa-Ki>G2=yb^`L9K3e3tcshBnRBc zMbxBF{>$rb7!8@TF0@Y$Y1I`EPxfM|+j+Xa)+ZIaz$pM?9FkO{_({BG?8mLv%>0%GMzv@gStm=Dhs!NT7tg?XI`(|C|xRRU7s1f^F(x(qt4_ss# z{5D{Uv(3iI!x!tH5u~%nXxpxD>y(#hpgYje)cC4w_q1&7Q_W{D$``aD?j*Z0EfhZ^ zF(YTm;$_gn5Y5X`Hh4B+HouEQ@5`Q41MWRef=S^(nrg*!u2V(#kttl&$t`f-aIv-O zdc4Hn`6b^aOI9h_#wKZ@C|6j1q@~vDltQW3k!Yy$c4Z7AU#ylZ#-*)-0UicxY#0To zr&QNI`qt*2TE5yagS&=J)a343bA1kP><@GEnL5~k#3q*d6%~Y{STwcBec+otLpZDP zQk#&s`GB_&Wv&0fZPR3FckI37qU991iofJ%Z z#ey&EjCEb4*C_(|hDr$gO7+$$P*$XX;g0wG-$8fpZtURTL=~key7e#ysB%cAlo73PW5SB5WF09+cDZoOsD#yZJMIEWbbxc|k}Lyi*=;SYMJavkwh=Awb2SNxw(( z&(+`dl!uU$1G+0c@XE8qf-5#W`R(rtry;u zQ1<>3?P!0f0jyPOl_EmVWL}FqeSU2Ls#E4Pf(91P+R+$J%H&ik4gB=l=Mn&k+OvFQ zIHu$|Sw^6;N$qP9Jip1UJ}7pbZ-UX+p3nW^o$h3e!~^Cb{#qIrIhTKqy(e}J>)om}H}ZQ+k5~{svHJ3#P>qGYsv`h3_#sbK7QQKz4joc` zCiqI3_Ewqm5_dv}uxKTCtw)pwwqZHPptX^bo)gC$`s-$n{h#9+r^Ru@#<5#nrivR~ zZBB}}s}{T$cgN+t-6oke8!den>*0>XDQobtHy+yg{Bno4QV)LJe;zq4?Uxxq)Z&%b zqMwz(Ri+}!i*`O#8lWk38l&nV6HQvZq5HrD%-}>M6T+O-^a3VfE&=9vHp8L& z7{;sN&Oh>^VCPg4So9>wgW8wzQKH|Y)E{2yi_*gIl`k^lb>Yd@ffE=}Ifyt_;RRXZ zC~rDVXoj!kj~G~T0zX97SYWqi6Mh3UZ5B#{jCVqAwl5lMpQ%y(sB}K`MN%=E=&KpQ z7+J=eV1pG6g=+8ewlP|k!(V)t6&FiD?t_~TC@n{2^`}Cx1C45~>hOIe)t9+B3O>-2 z1n6(ZBzUC{3ubo!u=w1M1O7P)efn}5T5q_E}H$D!6^5SuPFV=1FucLCqOx$&%Iq{Fd8L#g24h=5$(0WYE37-HA%gW!u9o6$$mjFp!&#Oj zbPzg(`IHo>8$8jdtJ#CfN!4%n(ZEp%Ubp}7=SjKiDgQwlsiFs4A4dmhiCZN0LuYH? z{D6|$sjc^ob&!sRFM<`6>GH00IWr@?faNr5H-7kVcdg=%^S__W%sxYQdVy592F_n& zdA;iTYM*OE`lU~Dsk5&}36OAtvg2sQ(_yC6eG%OpA%CAn#Z5q$7L%<3XL4WSS z;{r}0#bE5LvQGN^TL)NnfKW|96e^kNMY?9y(jUK72-0SyP`~ zHeYZJSxK=p2}l7XbZ>Tz^zr4{@a)r(v)Ws4LGNlvye5K~N<>Hdoc)s!SD{+G5q!=##TFBUp+Ps-KzO$zvm{0bu= z`Sc?c&%VfDTn<>LMcG&H^>?M88SjN9KdT&VspRZT{^WDp7KB&YRsIxMaQ5|#d0RUP z63wieb4xrzXSjwO9YU=NygKjd30k(gI;OY*{hxvqm34<@NQW{}ZdXx%c46FAE_u&W zCMx12?)Sb^gluwL$@iw6d_&wL?&anG7E?A%0ulq-`7ic4IPhpkH~=^#eOgzTw`C=$ zirv-)wp{$jfxntmw@?6AThByqTD6^3YrF9~?sWD~9pQXTp}<&VpBqhzNJ<+kCy>V@ zYbkQTn-IR5;2Q4uw%pQ9iCdG;V<{%-{Pg{mFqn{ct!t&$OX{RY)0W(!4qyNFq)}T! zQc-iCr|za+*FT9{^L<*`j%vEKk;fs=LE>%F66+B~FYlVYW(3KZSRR5zVOAI!3D5WS z8meiV*KOQcYyy&(pJ%bqa$3&t{=KR6OSVU9Hdnoy3s7K{Rnt%VsNCKM=GIjz{o|)q z#}8&&tEz^#e#%AA`>J?UHd>i<3R^)&AQ3v?A(D!2*~>XA-#9uE7j`Q=n>))mMONfB z14BZ#aGVSKXw#F!L9r5$@=t1HPgO7Z`E3@`r$&C`indB?=|m{;Wp*=UcA4SnEXa#CbE@lGlMsSgNMJZtlTb>#_EnuTNq zzPsGu7;$$*b34*!t}_rfBZQYmaP)<$qEqP}Gs<2*=s8wp5?N7J_iX4 z>$20jS%+A;eV&qr?kb;PZ(B<~+k6^P&hxOza!1S^%o5LXs|zlF2YAOr5>2Dp#Zk^s zv0khwmKiWSz_=T#hkYZSzxUDZ2gBv$nV0I3ms$3{Vs^rICYgcty$(~Qrle6y^>bj` zP@N-fzW)x>$ITCtq}ePp7&iltfzL-L=h^!nu{fy{${u4LIBjaPh3ESUxCf0eS|GGx zZIiM+F_3fsQ z{Mt@8vZ<|goA4LYv0zE<*3gD&D+@(9{Uua1<30l1#fEzGnwb2~T0GIeNK}da#V+IsfQ8o`!?n*BfcuU$~Be z%&h(N%FZ_qKR;*16hNv^=`@FH3U_iuI+tR2$aD})i&Qk_%o1Dl*$4dTcYKeQY`qb6 zTFr_0-rp(z!iNA(df!K<;xT0+m75kT%e|zpo&AEBiBZQHHF%@lRB5)iVUu@YnUMvX zaKia08GU=imEzBBar9p4zllCvuyled#cQB5oTnXx_Gl_J{T2$v8spg--J5u5xfgE+ z40I-qk8NF>mcS@pzm4^l#Rc}N6wsPWZ}f3MEygRMT39ij3H)L3=KbsJZP=3bk7+I5 z1Ao77g^jj6awr(O3tvi1{-->WrAbrf+3^$j7EnO*7$nA_e4kT#? zdHd}5$(J8roHbvaZH$%&9()f4h&3A1Ojcb|=yfmW?kc?qn)aHCedbXb%6v08*>lt* zrkwfx#fBo`?(_%^xzOzIOsem?DC4kO_*Eb2<^zTz5@uKJr($}BH_<7&R-FlI9530* zOPW^Zp?%J$av$E$hB2r$U#rBkDQKC1Xc=tZzM^?A(K;ku`KC^AF_G0UO6~jf0XnJur*8D|*(1&wnFDX+1^>!QZZgAr z`LVX|tF*gusJ!-DLDUWCgbXE3>VaX_o1rSkbAd!77{_?gK;3O7xG+9fKNSCbNcr>~ zpqKG<#L_3ADgTV5EnSLvhEUcD&9TRHI+NdO(Z5UMSi)Y)+I9Vk?DPu3AWgo{=*T-R z`r7p!NTWkhj7V`}S0L(HNN7MB86prRfs#}IMYkn|zC4b(I>szFUv4%#dLkO~dk}ff zaIg*b_6WClW%F}Al2URd#RRb4f!&sOAqiK%F(7RX9UYoJ-8gtPL3-U7vw?sY*OU?+ zIUt%2UVMtyG|`$TmP-5U(i24817XDjr=YAEHezL>B??2CHeUu#RcUHGc*MPq2ML}3 zc@o?%{H@RO?9pC5!RSL=35cqd%*Z|^LavDH7^Dlx@P~Gvjn$fRi424ir)6!wF|a6S z=2{fl{zEsBRRAcu(X;;SQECLKeLijYvuM>lIdZyqM@qVw#{Ms54J3gDydPncj+`>) zktn)hp|bHMz_PNxmm*{81+*XeWxSUhZdO#4tpSMbZ@0E(Bwl{~z?Rf-{k7-fb7HC> z%hL8v%{XTKsg>b-wO_f<9X)Jy2tQXh+; z6j_Tvu7dawYnrC@VuqbkkK|L0aB0JAuBH2{FM$jK8qnqr#lYeEh#ntkg)W~e^oX6! ztenAJfFq_Gf_z`V-oMQdC2#iG%upDMRU`_`xljEoJeHnwSV)XDXfh5uJ?DomEiwc{ z2P~`!Z@2AySUx+A7uJ_BqqclE&?C_~U@TwOCY8AnxXbeL$%iAEfE4+@ijm*fG8(ma z+I@OLqDSIFRS97~*k1esB#wzQ90CR+Ba@X~@)DBIyJ>{=h%-DzCz;oW@mW{3x>}9} zxt0pGF_9n*)z7`{2V&NUcp6S+TX#;sU|W*$PCtX*-|V%YZndrY>f3s5tppVYmL0z; zs#Zb+?Th`Jx-2YYGW5}M$p_VoVO1so#XR_809@K=hP9M--Z($UU!7x?Rj>9{S6yiM zw3e#gUm2XY8$6Z(@0MS6ly|AV+z-n;R?ut~d+|wE9h^ixhbAYpG}Duj@2ZaB-Bo3xxS|I@E}5twuN2 zMfz4#&b!j}qIzrQ@quIKb!2dxQ(Ds>qVxxcBXN{s4uivwNRr4<19;1KwJtxf;Qf}0 zj~0T9F!;?gm>EuclYw^kyUllGGctLJL1>W9mQ6{rE~eLKxh~pl!m@%ut@76@S?%pI z1LjE>zTKqBKt=LE(ltzGnZn^BEu7{hy}ZHd)`OP447zB8>}XYSNjeMb z0D5$RiRIBZxk$9%HgCu0T%%tliWXr)T}pu8!RRs?YxLp|UfaKxp}Czg!EzSO`wyF| zPXG6O`|o^6c4kixf5S<-MtBpro*d|mC6eRNyC9s+#i$LFWW;_hIN zaGGG|!{&}qq1_>alZ`Q(YmE}-`kMxqO9rnf3nu^`EzvME;}-aG4or**G%0y#`W%dSZPJ3vff7d&Vrupqo>C+Gb0(x2$ zhbkVGY2PpL)t=iFiY`Ww7FAvZAwTa4xCo$>E(z5E9ZM;hUY94U*~+LdF`0k&FU9)% z4pD62&h6@9{hI-42X6z3!6=KUc#y8?^VN>CQly^g)!)bGHw(XJH|gSnTy+Qhx39U~ zNV{C;IwQUOm;WjF+V}cgZ(47`&$sC18?Y`bfs9P!ByJCy?pWiwzF!oUb{rG}Ngihl>uxc}MM`e9*ppa4+Iw4B=p(K?4EnH~#1bVOe8n ze6bV;Z+y2Kp9JNY%~_0n@aaC_9R7h?8mqLVX&)6dq!#>&$u{`=ody@G8~s6PCR)kD z>}_A$1@?!)ebK&Ih1Nl6$4};?PfixJi*?1v0hX*YG)MGY{~K+jE1_XZ4_;j`v!z$+jG4~lSaP7zSOaeF3ne9QaC0(pelH^U3?6;@nJ z8G#&8*m{CJ-eou&4>X|uH8~D#URinCp9Y*#cHI<4?AxK!D#FzqRZ0&}GBaW)X(Sh4 z!sX;Ui+PlFG%5#jef8zw(QJjNO@Bm);G-4KJV4^^vDdV8x$`J$lL8X&FhGc9C6Z zTOF&F+Y1kD1uzDJPFd5<7n98e6YqKKiP+637IVfV4(cm>CPi>a=#kJgmru+VTQ|e^ zxhy}+qZf^gNu_>ci&=?MXq(7gnO2q0rVP3^X;Y9@0V6y{h8#r4<;jSP(TuxpEchG@ zy6>s*FHY!zR!62 z!l9kxKzMmtS(fUDvESbVas0v8bplDVlz)@=ZwoP9qypF#o9q!B*nF@|8DY69UbdUU zQP1cqJ$&lZ)lf>>+)--U9RF}zzJ-25Mk_OHL2A_0j(#9*Tt3bJdV{`F<6|b>TFca) z2#@F4DIVb-zevjb`@nDCd6-CRpO^Y{xRc6W5yJUr##JvDRUNZuZO;GLEZvV5X|)AA z+Z>&a-{Exu4e5^Ka!-1L6b`oCm-0UaI`sn1C_PB0HTNe)sR zU$ZF?XLJOpHq915m%x$TyEQ>)HD*DVt3getUAuuoEJc$Th4WQ<$@4iHRZfGW^2?2K z=>xh(9z$EgCuyTV=mztB8?6~*#;?tc#z!K-`93=rOHiLz&_lgV28t8D1Ybn_emsW| z`X$m@F8RYPV-I4c?*rET&R6myuaDko8oT{1` zg>j*78D=-JbfuRkes$64Zd9dI)`fHC=avYBsyy(>Jo~V{Xk9o3pk2w=_`;?dy06s5;s2mSJgdSmGgV(qAH zRE|IMXS5hOu)#0@TSpTwX&wPOE6_

OGghe%rl5o@N3=bF8o;geo#Z!TVuO)v!*= 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 Date: Wed, 11 Dec 2024 17:39:33 +0200 Subject: [PATCH 03/33] Added 4 LNS integrations for EM400-UDL --- .../ChirpStack/uplink/converter.json | 39 +++++++++ .../EM400-UDL/ChirpStack/uplink/metadata.json | 4 + .../EM400-UDL/ChirpStack/uplink/payload.json | 48 +++++++++++ .../ChirpStack/uplink/payload_1.json | 48 +++++++++++ .../EM400-UDL/ChirpStack/uplink/result.json | 28 +++++++ .../EM400-UDL/ChirpStack/uplink/result_1.json | 28 +++++++ .../EM400-UDL/LORIOT/uplink/converter.json | 29 +++++++ .../EM400-UDL/LORIOT/uplink/metadata.json | 4 + .../EM400-UDL/LORIOT/uplink/payload.json | 17 ++++ .../EM400-UDL/LORIOT/uplink/payload_1.json | 17 ++++ .../EM400-UDL/LORIOT/uplink/result.json | 18 ++++ .../EM400-UDL/LORIOT/uplink/result_1.json | 18 ++++ .../uplink/converter.json | 39 +++++++++ .../ThingsStackCommunity/uplink/metadata.json | 4 + .../ThingsStackCommunity/uplink/payload.json | 54 ++++++++++++ .../uplink/payload_1.json | 54 ++++++++++++ .../ThingsStackCommunity/uplink/result.json | 29 +++++++ .../ThingsStackCommunity/uplink/result_1.json | 29 +++++++ .../uplink/converter.json | 40 +++++++++ .../uplink/metadata.json | 4 + .../ThingsStackIndustries/uplink/payload.json | 77 ++++++++++++++++++ .../uplink/payload_1.json | 77 ++++++++++++++++++ .../ThingsStackIndustries/uplink/result.json | 29 +++++++ .../uplink/result_1.json | 29 +++++++ VENDORS/Milesight/EM400-UDL/guide.md | 21 +++++ VENDORS/Milesight/EM400-UDL/info.json | 6 ++ VENDORS/Milesight/EM400-UDL/photo.png | Bin 0 -> 50218 bytes 27 files changed, 790 insertions(+) create mode 100644 VENDORS/Milesight/EM400-UDL/ChirpStack/uplink/converter.json create mode 100644 VENDORS/Milesight/EM400-UDL/ChirpStack/uplink/metadata.json create mode 100644 VENDORS/Milesight/EM400-UDL/ChirpStack/uplink/payload.json create mode 100644 VENDORS/Milesight/EM400-UDL/ChirpStack/uplink/payload_1.json create mode 100644 VENDORS/Milesight/EM400-UDL/ChirpStack/uplink/result.json create mode 100644 VENDORS/Milesight/EM400-UDL/ChirpStack/uplink/result_1.json create mode 100644 VENDORS/Milesight/EM400-UDL/LORIOT/uplink/converter.json create mode 100644 VENDORS/Milesight/EM400-UDL/LORIOT/uplink/metadata.json create mode 100644 VENDORS/Milesight/EM400-UDL/LORIOT/uplink/payload.json create mode 100644 VENDORS/Milesight/EM400-UDL/LORIOT/uplink/payload_1.json create mode 100644 VENDORS/Milesight/EM400-UDL/LORIOT/uplink/result.json create mode 100644 VENDORS/Milesight/EM400-UDL/LORIOT/uplink/result_1.json create mode 100644 VENDORS/Milesight/EM400-UDL/ThingsStackCommunity/uplink/converter.json create mode 100644 VENDORS/Milesight/EM400-UDL/ThingsStackCommunity/uplink/metadata.json create mode 100644 VENDORS/Milesight/EM400-UDL/ThingsStackCommunity/uplink/payload.json create mode 100644 VENDORS/Milesight/EM400-UDL/ThingsStackCommunity/uplink/payload_1.json create mode 100644 VENDORS/Milesight/EM400-UDL/ThingsStackCommunity/uplink/result.json create mode 100644 VENDORS/Milesight/EM400-UDL/ThingsStackCommunity/uplink/result_1.json create mode 100644 VENDORS/Milesight/EM400-UDL/ThingsStackIndustries/uplink/converter.json create mode 100644 VENDORS/Milesight/EM400-UDL/ThingsStackIndustries/uplink/metadata.json create mode 100644 VENDORS/Milesight/EM400-UDL/ThingsStackIndustries/uplink/payload.json create mode 100644 VENDORS/Milesight/EM400-UDL/ThingsStackIndustries/uplink/payload_1.json create mode 100644 VENDORS/Milesight/EM400-UDL/ThingsStackIndustries/uplink/result.json create mode 100644 VENDORS/Milesight/EM400-UDL/ThingsStackIndustries/uplink/result_1.json create mode 100644 VENDORS/Milesight/EM400-UDL/guide.md create mode 100644 VENDORS/Milesight/EM400-UDL/info.json create mode 100644 VENDORS/Milesight/EM400-UDL/photo.png diff --git a/VENDORS/Milesight/EM400-UDL/ChirpStack/uplink/converter.json b/VENDORS/Milesight/EM400-UDL/ChirpStack/uplink/converter.json new file mode 100644 index 00000000..b6815aff --- /dev/null +++ b/VENDORS/Milesight/EM400-UDL/ChirpStack/uplink/converter.json @@ -0,0 +1,39 @@ +{ + "name": "ChirpStack Uplink Decoder for EM400-UDL", + "type": "UPLINK", + "debugMode": false, + "debugSettings": { + "failuresEnabled": true, + "allEnabled": false, + "allEnabledUntil": 1733331880270 + }, + "configuration": { + "scriptLang": "TBEL", + "decoder": null, + "tbelDecoder": "var data = decodeToJson(payload);\nvar deviceName = data.deviceInfo.deviceName + \" \" + data.deviceInfo.devEui;\nvar deviceType = \"EM400-UDL\";\nvar groupName = null; // If groupName is not null - created device will be added to the entity group with such name.\nvar customerName = null; // If customerName is not null - created devices will be assigned to customer with such name. \n\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// If you want to parse incoming data somehow, you can add your code to this function.\n// input: bytes\n// expected output:\n// {\n// \"attributes\": {\"attributeKey\": \"attributeValue\"},\n// \"telemetry\": [{\"ts\": 1...1, \"values\": {\"telemetryKey\":\"telemetryValue\"}, {\"ts\": 1...2, \"values\": {\"telemetryKey\":\"telemetryValue\"}}]\n// }\n\nfunction decodePayload(input) {\n var output = {\n attributes: {},\n telemetry: []\n };\n \n // --- Decoding code --- //\n var decoded = {};\n for (var i = 0; i < input.length - 2 ; ) {\n var channel_id = input[i++] & 0xff;\n var channel_type = input[i++] & 0xff;\n \n // BATTERY\n if (channel_id === 0x01 && channel_type === 0x75) {\n decoded.battery = input[i];\n i += 1;\n }\n // TEMPERATURE\n else if (channel_id === 0x03 && channel_type === 0x67) {\n decoded.temperature = parseBytesToInt(input, i, 2, false) / 10;\n i += 2;\n }\n // DISTANCE\n else if (channel_id === 0x04 && channel_type === 0x82) {\n decoded.distance = parseBytesToInt(input, i, 2, false);\n i += 2;\n }\n // POSITION\n else if (channel_id === 0x05 && channel_type === 0x00) {\n decoded.position = input[i] === 0 ? \"normal\" : \"tilt\";\n i += 1;\n }\n // TEMPERATURE WITH ABNORMAL\n else if (channel_id === 0x83 && channel_type === 0x67) {\n decoded.temperature = parseBytesToInt(input, i, 2, false) / 10;\n decoded.temperature_abnormal = input[i + 2] == 0 ? false : true;\n i += 3;\n }\n // DISTANCE WITH ALARMING\n else if (channel_id === 0x84 && channel_type === 0x82) {\n decoded.distance = parseBytesToInt(input, i, 2, false);\n decoded.distance_alarming = input[i + 2] == 0 ? false : true;\n i += 3;\n }\n }\n\n output.telemetry = [{\n ts: timestamp,\n values: decoded\n }];\n \n // --- Decoding code --- //\n return output;\n}\n\n// --- attributes and telemetry objects ---\nvar telemetry = [];\nvar attributes = {};\n// --- attributes and telemetry objects ---\n\n// --- Timestamp parsing\nvar dateString = data.time;\ntimestamp = parseDateToTimestamp(dateString);\n// --- Timestamp parsing\n\n// Passing incoming bytes to decodePayload function, to get custom decoding\nvar customDecoding = decodePayload(base64ToBytes(data.data));\n\n\nattributes.eui = data.deviceInfo.devEui;\n\n// Collecting data to result\nif (customDecoding.?telemetry.size() > 0) {\n if (customDecoding.telemetry instanceof java.util.ArrayList) {\n foreach(telemetryObj: customDecoding.telemetry) {\n if (telemetryObj.ts != null && telemetryObj.values != null) {\n telemetry.add(telemetryObj);\n }\n }\n } else {\n telemetry.putAll(customDecoding.telemetry);\n }\n}\n\nif (customDecoding.?attributes.size() > 0) {\n attributes.putAll(customDecoding.attributes);\n}\n\n// You can add some keys manually to attributes or telemetry\nattributes.eui = data.deviceInfo.?devEui;\nattributes.devAddr = data.devAddr;\nattributes.fPort = data.fPort;\nattributes.applicationId = data.deviceInfo.?applicationId;\nattributes.applicationName = data.deviceInfo.?applicationName;\nattributes.tenantId = data.deviceInfo.?tenantId;\nattributes.tenantName = data.deviceInfo.?tenantName;\nattributes.deviceProfileId = data.deviceInfo.?deviceProfileId;\nattributes.deviceProfileName = data.deviceInfo.?deviceProfileName;\nattributes.frequency = data.txInfo.?frequency;\nattributes.bandwidth = data.txInfo.?modulation.?lora.?bandwidth;\nattributes.spreadingFactor = data.txInfo.?modulation.?lora.?spreadingFactor;\nattributes.codeRate = data.txInfo.?modulation.?lora.?codeRate;\n\nif(Boolean.parseBoolean(metadata[\"includeGatewayInfo\"])) {\n var gatewayInfo = getGatewayInfo();\n var addDataToTelemetry = {};\n addDataToTelemetry.snr = gatewayInfo.snr;\n addDataToTelemetry.rssi = gatewayInfo.rssi;\n addDataToTelemetry.channel = gatewayInfo.channel;\n addDataToTelemetry.rfChain = gatewayInfo.rfChain;\n addDataToTelemetry.fCnt = data.fCnt;\n \n telemetry = processTelemetryData(telemetry, addDataToTelemetry);\n}\n\nvar result = {\n deviceName: deviceName,\n deviceType: deviceType,\n // assetName: assetName,\n // assetType: assetType,\n attributes: attributes,\n telemetry: telemetry\n};\n\naddAdditionalInfoForDeviceMsg(result, customerName, groupName);\n\nreturn result;\n\nfunction addAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName) {\n if (customerName != null) {\n deviceInfo.customerName = customerName;\n }\n if (groupName != null) {\n deviceInfo.groupName = groupName;\n }\n}\n\nfunction parseDateToTimestamp(dateString) {\n var date = new Date(dateString);\n var timestamp = date.getTime();\n \n // If we cannot parse timestamp - we will use the current timestamp\n if (timestamp == -1) {\n timestamp = Date.now();\n }\n \n return timestamp;\n}\n\nfunction getGatewayInfo() {\n var gatewayList = data.rxInfo;\n var maxRssi = Integer.MIN_VALUE;\n var gatewayInfo = {};\n \n foreach (gateway : gatewayList) {\n if(gateway.rssi > maxRssi) {\n maxRssi = gateway.rssi;\n gatewayInfo = gateway;\n }\n }\n \n return gatewayInfo;\n}\n\nfunction processTelemetryData(telemetry, addDataToTelemetry) {\n if (telemetry.size >= 1) {\n telemetry = addDataToTelemetries(telemetry, addDataToTelemetry);\n }\n else {\n telemetry.add(addDataToTelemetry);\n }\n \n return telemetry;\n}\n\nfunction addDataToTelemetries(telemetries, addDataToTelemetry) {\n foreach(telemetry : telemetries) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[\"values\"].keys.contains(element.key)) {\n telemetry[\"values\"][element.key] = element.value;\n }\n } \n }\n \n return telemetries;\n}", + "encoder": null, + "tbelEncoder": null, + "updateOnlyKeys": [ + "tenantId", + "tenantName", + "applicationId", + "applicationName", + "deviceProfileId", + "deviceProfileName", + "devAddr", + "fPort", + "frequency", + "bandwidth", + "spreadingFactor", + "codeRate", + "channel", + "rfChain", + "eui", + "battery" + ] + }, + "additionalInfo": { + "description": "" + }, + "edgeTemplate": false +} \ No newline at end of file diff --git a/VENDORS/Milesight/EM400-UDL/ChirpStack/uplink/metadata.json b/VENDORS/Milesight/EM400-UDL/ChirpStack/uplink/metadata.json new file mode 100644 index 00000000..23f54b34 --- /dev/null +++ b/VENDORS/Milesight/EM400-UDL/ChirpStack/uplink/metadata.json @@ -0,0 +1,4 @@ +{ + "integrationName": "ChirpStack integration", + "includeGatewayInfo": "false" +} \ No newline at end of file diff --git a/VENDORS/Milesight/EM400-UDL/ChirpStack/uplink/payload.json b/VENDORS/Milesight/EM400-UDL/ChirpStack/uplink/payload.json new file mode 100644 index 00000000..3e3584b0 --- /dev/null +++ b/VENDORS/Milesight/EM400-UDL/ChirpStack/uplink/payload.json @@ -0,0 +1,48 @@ +{ + "deduplicationId": "57433366-50a6-4dc2-8145-2df1bbc70d9e", + "time": "2023-05-22T07:47:05.404859+00:00", + "deviceInfo": { + "tenantId": "52f14cd4-c6f1-4fbd-8f87-4025e1d49242", + "tenantName": "ChirpStack", + "applicationId": "ca739e26-7b67-4f14-b69e-d568c22a5a75", + "applicationName": "Chirpstack application", + "deviceProfileId": "605d08d4-65f5-4d2c-8a5a-3d2457662f79", + "deviceProfileName": "Chirpstack default device profile", + "deviceName": "Device name", + "devEui": "1000000000000001", + "tags": {} + }, + "devAddr": "20000001", + "adr": true, + "dr": 5, + "fCnt": 4, + "fPort": 85, + "confirmed": false, + "data": "g2foAAGEgkEGAQ==", + "rxInfo": [{ + "gatewayId": "6a7e111a10000000", + "uplinkId": 24022, + "time": "2023-05-22T07:47:05.404859+00:00", + "rssi": -35, + "snr": 11.5, + "channel": 2, + "rfChain": 1, + "location": {}, + "context": "EFwMtA==", + "metadata": { + "region_common_name": "EU868", + "region_config_id": "eu868" + }, + "crcStatus": "CRC_OK" + }], + "txInfo": { + "frequency": 868500000, + "modulation": { + "lora": { + "bandwidth": 125000, + "spreadingFactor": 7, + "codeRate": "CR_4_5" + } + } + } +} \ No newline at end of file diff --git a/VENDORS/Milesight/EM400-UDL/ChirpStack/uplink/payload_1.json b/VENDORS/Milesight/EM400-UDL/ChirpStack/uplink/payload_1.json new file mode 100644 index 00000000..154ca2e8 --- /dev/null +++ b/VENDORS/Milesight/EM400-UDL/ChirpStack/uplink/payload_1.json @@ -0,0 +1,48 @@ +{ + "deduplicationId": "57433366-50a6-4dc2-8145-2df1bbc70d9e", + "time": "2023-05-22T07:47:05.404859+00:00", + "deviceInfo": { + "tenantId": "52f14cd4-c6f1-4fbd-8f87-4025e1d49242", + "tenantName": "ChirpStack", + "applicationId": "ca739e26-7b67-4f14-b69e-d568c22a5a75", + "applicationName": "Chirpstack application", + "deviceProfileId": "605d08d4-65f5-4d2c-8a5a-3d2457662f79", + "deviceProfileName": "Chirpstack default device profile", + "deviceName": "Device name", + "devEui": "1000000000000001", + "tags": {} + }, + "devAddr": "20000001", + "adr": true, + "dr": 5, + "fCnt": 4, + "fPort": 85, + "confirmed": false, + "data": "AXVcA2cBAQSCRAgFAAE=", + "rxInfo": [{ + "gatewayId": "6a7e111a10000000", + "uplinkId": 24022, + "time": "2023-05-22T07:47:05.404859+00:00", + "rssi": -35, + "snr": 11.5, + "channel": 2, + "rfChain": 1, + "location": {}, + "context": "EFwMtA==", + "metadata": { + "region_common_name": "EU868", + "region_config_id": "eu868" + }, + "crcStatus": "CRC_OK" + }], + "txInfo": { + "frequency": 868500000, + "modulation": { + "lora": { + "bandwidth": 125000, + "spreadingFactor": 7, + "codeRate": "CR_4_5" + } + } + } +} \ No newline at end of file diff --git a/VENDORS/Milesight/EM400-UDL/ChirpStack/uplink/result.json b/VENDORS/Milesight/EM400-UDL/ChirpStack/uplink/result.json new file mode 100644 index 00000000..62d3cea5 --- /dev/null +++ b/VENDORS/Milesight/EM400-UDL/ChirpStack/uplink/result.json @@ -0,0 +1,28 @@ +{ + "deviceName": "Device name 1000000000000001", + "deviceType": "EM400-UDL", + "attributes": { + "eui": "1000000000000001", + "devAddr": "20000001", + "fPort": 85, + "applicationId": "ca739e26-7b67-4f14-b69e-d568c22a5a75", + "applicationName": "Chirpstack application", + "tenantId": "52f14cd4-c6f1-4fbd-8f87-4025e1d49242", + "tenantName": "ChirpStack", + "deviceProfileId": "605d08d4-65f5-4d2c-8a5a-3d2457662f79", + "deviceProfileName": "Chirpstack default device profile", + "frequency": 868500000, + "bandwidth": 125000, + "spreadingFactor": 7, + "codeRate": "CR_4_5" + }, + "telemetry": [{ + "ts": 1684741625404, + "values": { + "temperature": 23.2, + "temperature_abnormal": true, + "distance": 1601, + "distance_alarming": true + } + }] +} \ No newline at end of file diff --git a/VENDORS/Milesight/EM400-UDL/ChirpStack/uplink/result_1.json b/VENDORS/Milesight/EM400-UDL/ChirpStack/uplink/result_1.json new file mode 100644 index 00000000..a943d1bf --- /dev/null +++ b/VENDORS/Milesight/EM400-UDL/ChirpStack/uplink/result_1.json @@ -0,0 +1,28 @@ +{ + "deviceName": "Device name 1000000000000001", + "deviceType": "EM400-UDL", + "attributes": { + "eui": "1000000000000001", + "devAddr": "20000001", + "fPort": 85, + "applicationId": "ca739e26-7b67-4f14-b69e-d568c22a5a75", + "applicationName": "Chirpstack application", + "tenantId": "52f14cd4-c6f1-4fbd-8f87-4025e1d49242", + "tenantName": "ChirpStack", + "deviceProfileId": "605d08d4-65f5-4d2c-8a5a-3d2457662f79", + "deviceProfileName": "Chirpstack default device profile", + "frequency": 868500000, + "bandwidth": 125000, + "spreadingFactor": 7, + "codeRate": "CR_4_5" + }, + "telemetry": [{ + "ts": 1684741625404, + "values": { + "battery": 92, + "temperature": 25.7, + "distance": 2116, + "position": "tilt" + } + }] +} \ No newline at end of file diff --git a/VENDORS/Milesight/EM400-UDL/LORIOT/uplink/converter.json b/VENDORS/Milesight/EM400-UDL/LORIOT/uplink/converter.json new file mode 100644 index 00000000..8540d54c --- /dev/null +++ b/VENDORS/Milesight/EM400-UDL/LORIOT/uplink/converter.json @@ -0,0 +1,29 @@ +{ + "name": "Loriot Uplink Decoder for EM400-UDL", + "type": "UPLINK", + "debugMode": false, + "debugSettings": { + "failuresEnabled": true, + "allEnabled": false, + "allEnabledUntil": 1733331880270 + }, + "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);\nvar deviceName = data.EUI;\nvar deviceType = \"EM400-UDL\";\nvar groupName = null; // If groupName is not null - created device will be added to the entity group with such name.\nvar customerName = null; // If customerName is not null - created devices will be assigned to customer with such name. \n\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// If you want to parse incoming data somehow, you can add your code to this function.\n// input: bytes\n// expected output:\n// {\n// \"attributes\": {\"attributeKey\": \"attributeValue\"},\n// \"telemetry\": {\"telemetryKey\": \"telemetryValue\"}\n// }\n\nfunction decodePayload(input) {\n var output = { attributes: {}, telemetry: []};\n \n var decoded = {};\n for (var i = 0; i < input.length - 2 ; ) {\n var channel_id = input[i++] & 0xff;\n var channel_type = input[i++] & 0xff;\n \n // BATTERY\n if (channel_id === 0x01 && channel_type === 0x75) {\n decoded.battery = input[i];\n i += 1;\n }\n // TEMPERATURE\n else if (channel_id === 0x03 && channel_type === 0x67) {\n decoded.temperature = parseBytesToInt(input, i, 2, false) / 10;\n i += 2;\n }\n // DISTANCE\n else if (channel_id === 0x04 && channel_type === 0x82) {\n decoded.distance = parseBytesToInt(input, i, 2, false);\n i += 2;\n }\n // POSITION\n else if (channel_id === 0x05 && channel_type === 0x00) {\n decoded.position = input[i] === 0 ? \"normal\" : \"tilt\";\n i += 1;\n }\n // TEMPERATURE WITH ABNORMAL\n else if (channel_id === 0x83 && channel_type === 0x67) {\n decoded.temperature = parseBytesToInt(input, i, 2, false) / 10;\n decoded.temperature_abnormal = input[i + 2] == 0 ? false : true;\n i += 3;\n }\n // DISTANCE WITH ALARMING\n else if (channel_id === 0x84 && channel_type === 0x82) {\n decoded.distance = parseBytesToInt(input, i, 2, false);\n decoded.distance_alarming = input[i + 2] == 0 ? false : true;\n i += 3;\n }\n }\n \n output.telemetry = [{\n ts: timestamp,\n values: decoded\n }];\n\n // --- Decoding code --- //\n return output;\n}\n\n// --- attributes and telemetry objects ---\nvar telemetry = [];\nvar attributes = {};\n// --- attributes and telemetry objects ---\n\n// --- Timestamp parsing\ntimestamp = data.ts;\n// --- Timestamp parsing\n\n// Message parsing\n// To avoid paths in the decoded objects we passing false value to function as \"pathInKey\" argument.\n// Warning: pathInKey can cause already found fields to be overwritten with the last value found.\n\nvar uplinkDataList = [];\n\n// Passing incoming bytes to decodePayload function, to get custom decoding\nvar customDecoding = decodePayload(hexToBytes(data.data));\n\n// Collecting data to result\nif (customDecoding.?telemetry.size() > 0) {\n if (customDecoding.telemetry instanceof java.util.ArrayList) {\n foreach(telemetryObj: customDecoding.telemetry) {\n if (telemetryObj.ts != null && telemetryObj.values != null) {\n telemetry.add(telemetryObj);\n }\n }\n } else {\n telemetry.putAll(customDecoding.telemetry);\n }\n}\n\nif (customDecoding.?attributes.size() > 0) {\n attributes.putAll(customDecoding.attributes);\n}\n\n// You can add some keys manually to attributes or telemetry\nattributes.eui = data.EUI;\nattributes.fPort = data.port;\nattributes.frequency = data.freq;\n\nvar isIncludeGatewayInfo = metadata[\"includeGatewayInfo\"];\nif(isIncludeGatewayInfo == true) {\n var addDataToTelemetry = {};\n addDataToTelemetry.rssi = data.rssi;\n addDataToTelemetry.seqno = data.seqno;\n addDataToTelemetry.snr = data.snr;\n addDataToTelemetry.ack = data.ack;\n addDataToTelemetry.toa = data.toa;\n addDataToTelemetry.fCnt = data.fcnt;\n \n telemetry = processTelemetryData(telemetry, addDataToTelemetry);\n}\n\nvar deviceInfo = {\n deviceName: deviceName,\n deviceType: deviceType,\n// assetName: assetName,\n// assetType: assetType,\n attributes: attributes,\n telemetry: telemetry, \n};\n\naddAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName);\n\nuplinkDataList.add(deviceInfo);\n\nvar gatewayDeviceNamePrefix = \"Gateway \";\nvar gatewayDeviceType = \"Lora gateway\";\nvar gatewayGroupName = null; // If gatewayGroupName is not null - created device will be added to the entity group with such name.\n\nif (data.cmd == \"gw\") {\n foreach( gatewayInfo : data.gws ) {\n var addGatewayInfo = {};\n\n // You can add some keys manually telemetry\n addGatewayInfo.rssi = gatewayInfo.rssi;\n addGatewayInfo.snr = gatewayInfo.snr;\n // You can add some keys manually telemetry\n \n var gatewayInfoMsg = {\n deviceName: gatewayDeviceNamePrefix + gatewayInfo.gweui,\n deviceType: gatewayDeviceType,\n telemetry: [{\n \"ts\": gatewayInfo.ts,\n \"values\": addGatewayInfo\n }],\n attributes: {\n eui: gatewayInfo.gweui\n }\n };\n addAdditionalInfoForDeviceMsg(gatewayInfoMsg, customerName, gatewayGroupName);\n uplinkDataList.add(gatewayInfoMsg);\n }\n}\n\nreturn uplinkDataList;\n\nfunction addAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName) {\n if (customerName != null) {\n deviceInfo.customerName = customerName;\n }\n if (groupName != null) {\n deviceInfo.groupName = groupName;\n }\n}\n\nfunction processTelemetryData(telemetry, addDataToTelemetry) {\n if (telemetry.size >= 1) {\n telemetry = addDataToTelemetries(telemetry, addDataToTelemetry);\n }\n else {\n telemetry.add(addDataToTelemetry);\n }\n \n return telemetry;\n}\n\nfunction addDataToTelemetries(telemetries, addDataToTelemetry) {\n foreach(telemetry : telemetries) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[\"values\"].keys.contains(element.key)) {\n telemetry[\"values\"][element.key] = element.value;\n }\n } \n }\n \n return telemetries;\n}", + "encoder": null, + "tbelEncoder": null, + "updateOnlyKeys": [ + "fPort", + "ack", + "eui", + "frequency", + "dr", + "battery" + ] + }, + "additionalInfo": { + "description": "" + }, + "edgeTemplate": false +} \ No newline at end of file diff --git a/VENDORS/Milesight/EM400-UDL/LORIOT/uplink/metadata.json b/VENDORS/Milesight/EM400-UDL/LORIOT/uplink/metadata.json new file mode 100644 index 00000000..ae2ee743 --- /dev/null +++ b/VENDORS/Milesight/EM400-UDL/LORIOT/uplink/metadata.json @@ -0,0 +1,4 @@ +{ + "integrationName": "Loriot integration", + "includeGatewayInfo": "false" +} \ No newline at end of file diff --git a/VENDORS/Milesight/EM400-UDL/LORIOT/uplink/payload.json b/VENDORS/Milesight/EM400-UDL/LORIOT/uplink/payload.json new file mode 100644 index 00000000..95879188 --- /dev/null +++ b/VENDORS/Milesight/EM400-UDL/LORIOT/uplink/payload.json @@ -0,0 +1,17 @@ +{ + "cmd": "rx", + "seqno": 3040, + "EUI": "1000000000000001", + "ts": 1684478801936, + "fcnt": 2, + "port": 85, + "freq": 867500000, + "rssi": -21, + "snr": 10, + "toa": 206, + "dr": "SF9 BW125 4/5", + "ack": false, + "bat": 94, + "offline": false, + "data": "8367e800018482410601" +} \ No newline at end of file diff --git a/VENDORS/Milesight/EM400-UDL/LORIOT/uplink/payload_1.json b/VENDORS/Milesight/EM400-UDL/LORIOT/uplink/payload_1.json new file mode 100644 index 00000000..ef349fd0 --- /dev/null +++ b/VENDORS/Milesight/EM400-UDL/LORIOT/uplink/payload_1.json @@ -0,0 +1,17 @@ +{ + "cmd": "rx", + "seqno": 3040, + "EUI": "1000000000000001", + "ts": 1684478801936, + "fcnt": 2, + "port": 85, + "freq": 867500000, + "rssi": -21, + "snr": 10, + "toa": 206, + "dr": "SF9 BW125 4/5", + "ack": false, + "bat": 94, + "offline": false, + "data": "01755C0367010104824408050001" +} \ No newline at end of file diff --git a/VENDORS/Milesight/EM400-UDL/LORIOT/uplink/result.json b/VENDORS/Milesight/EM400-UDL/LORIOT/uplink/result.json new file mode 100644 index 00000000..84a6b87f --- /dev/null +++ b/VENDORS/Milesight/EM400-UDL/LORIOT/uplink/result.json @@ -0,0 +1,18 @@ +[{ + "deviceName": "1000000000000001", + "deviceType": "EM400-UDL", + "attributes": { + "eui": "1000000000000001", + "fPort": 85, + "frequency": 867500000 + }, + "telemetry": [{ + "ts": 1684478801936, + "values": { + "temperature": 23.2, + "temperature_abnormal": true, + "distance": 1601, + "distance_alarming": true + } + }] +}] \ No newline at end of file diff --git a/VENDORS/Milesight/EM400-UDL/LORIOT/uplink/result_1.json b/VENDORS/Milesight/EM400-UDL/LORIOT/uplink/result_1.json new file mode 100644 index 00000000..21cb2eea --- /dev/null +++ b/VENDORS/Milesight/EM400-UDL/LORIOT/uplink/result_1.json @@ -0,0 +1,18 @@ +[{ + "deviceName": "1000000000000001", + "deviceType": "EM400-UDL", + "attributes": { + "eui": "1000000000000001", + "fPort": 85, + "frequency": 867500000 + }, + "telemetry": [{ + "ts": 1684478801936, + "values": { + "battery": 92, + "temperature": 25.7, + "distance": 2116, + "position": "tilt" + } + }] +}] \ No newline at end of file diff --git a/VENDORS/Milesight/EM400-UDL/ThingsStackCommunity/uplink/converter.json b/VENDORS/Milesight/EM400-UDL/ThingsStackCommunity/uplink/converter.json new file mode 100644 index 00000000..26cc9e5b --- /dev/null +++ b/VENDORS/Milesight/EM400-UDL/ThingsStackCommunity/uplink/converter.json @@ -0,0 +1,39 @@ +{ + "name": "The Things Stack Community Uplink Decoder for EM400-UDL", + "type": "UPLINK", + "debugMode": false, + "debugSettings": { + "failuresEnabled": true, + "allEnabled": false, + "allEnabledUntil": 1733331880270 + }, + "configuration": { + "scriptLang": "TBEL", + "decoder": null, + "tbelDecoder": "var data = decodeToJson(payload);\n\nvar deviceName = data.end_device_ids.device_id;\nvar deviceType = \"EM400-UDL\";\nvar groupName = null; // If groupName is not null - created device will be added to the entity group with such name.\nvar customerName = null; // If customerName is not null - created devices will be assigned to customer with such name. \n\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// If you want to parse incoming data somehow, you can add your code to this function.\n// input: bytes\n// expected output:\n// {\n// \"attributes\": {\"attributeKey\": \"attributeValue\"},\n// \"telemetry\": [{\"ts\": 1...1, \"values\": {\"telemetryKey\":\"telemetryValue\"}, {\"ts\": 1...2, \"values\": {\"telemetryKey\":\"telemetryValue\"}}]\n// }\n\nfunction decodeFrmPayload(input) {\n var output = {\n attributes: {}, telemetry: {}\n };\n \n // --- Decoding code --- //\n var decoded = {};\n for (var i = 0; i < input.length - 2 ; ) {\n var channel_id = input[i++] & 0xff;\n var channel_type = input[i++] & 0xff;\n\n // BATTERY\n if (channel_id === 0x01 && channel_type === 0x75) {\n decoded.battery = input[i];\n i += 1;\n }\n // TEMPERATURE\n else if (channel_id === 0x03 && channel_type === 0x67) {\n decoded.temperature = parseBytesToInt(input, i, 2, false) / 10;\n i += 2;\n }\n // DISTANCE\n else if (channel_id === 0x04 && channel_type === 0x82) {\n decoded.distance = parseBytesToInt(input, i, 2, false);\n i += 2;\n }\n // POSITION\n else if (channel_id === 0x05 && channel_type === 0x00) {\n decoded.position = input[i] === 0 ? \"normal\" : \"tilt\";\n i += 1;\n }\n // TEMPERATURE WITH ABNORMAL\n else if (channel_id === 0x83 && channel_type === 0x67) {\n decoded.temperature = parseBytesToInt(input, i, 2, false) / 10;\n decoded.temperature_abnormal = input[i + 2] == 0 ? false : true;\n i += 3;\n }\n // DISTANCE WITH ALARMING\n else if (channel_id === 0x84 && channel_type === 0x82) {\n decoded.distance = parseBytesToInt(input, i, 2, false);\n decoded.distance_alarming = input[i + 2] == 0 ? false : true;\n i += 3;\n }\n }\n \n output.telemetry = [{\n ts: timestamp,\n values: decoded\n }];\n \n // --- Decoding code --- //\n return output;\n}\n\n\n// --- attributes and telemetry objects ---\nvar telemetry = [];\nvar attributes = {};\n// --- attributes and telemetry objects ---\n\n// --- Timestamp parsing\nvar dateString = data.uplink_message.received_at;\n// If data is simulated or device doesn't send his own date string - we will use date from upcoming message, set by network server\nif ((data.simulated != null && data.simulated) || dateString == null) {\n dateString = data.received_at;\n}\ntimestamp = parseDateToTimestamp(dateString);\n// --- Timestamp parsing\n\n// Message parsing\n// To avoid paths in the decoded objects we passing false value to function as \"pathInKey\" argument.\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.\n\n// Passing incoming bytes to decodeFrmPayload function, to get custom decoding\nvar customDecoding = {};\nif (data.uplink_message.get(\"frm_payload\") != null) {\n customDecoding = decodeFrmPayload(base64ToBytes(data.uplink_message.frm_payload));\n}\n\n// Collecting data to result\nif (customDecoding.?telemetry.size() > 0) {\n if (customDecoding.telemetry instanceof java.util.ArrayList) {\n foreach(telemetryObj: customDecoding.telemetry) {\n if (telemetryObj.ts != null && telemetryObj.values != null) {\n telemetry.add(telemetryObj);\n }\n }\n } else {\n telemetry.putAll(customDecoding.telemetry);\n }\n}\n\nif (customDecoding.?attributes.size() > 0) {\n attributes.putAll(customDecoding.attributes);\n}\n\n// You can add some keys manually to attributes or telemetry\nvar applicationId = data.end_device_ids.?application_ids.?application_id;\nvar devAddr = data.end_device_ids.?dev_addr;\nvar spreadingFactor = data.uplink_message.?settings.?data_rate.?lora.?spreading_factor;\nvar codeRate = data.uplink_message.?settings.?data_rate.?lora.?coding_rate;\nvar tenantId = data.uplink_message.?network_ids.?tenant_id;\nattributes.eui = data.end_device_ids.dev_eui;\nattributes.fPort = data.uplink_message.f_port;\nattributes.applicationId = applicationId;\nattributes.devAddr = devAddr;\nattributes.spreadingFactor = spreadingFactor;\nattributes.codeRate = codeRate;\nattributes.tenantId = tenantId;\nattributes.device_id = data.end_device_ids.?device_id;\nattributes.join_eui = data.end_device_ids.?join_eui;\nattributes.net_id = data.uplink_message.?network_ids.?net_id;\nattributes.cluster_id = data.uplink_message.?network_ids.?cluster_id;\nattributes.cluster_adress = data.uplink_message.?network_ids.?cluster_address;\nattributes.bandwidth = data.uplink_message.?settings.?data_rate.?lora.?bandwidth;\nattributes.frequency = data.uplink_message.?settings.?frequency;\n\n\nvar gatewayInfo = getGatewayInfo();\nvar addDataToTelemetry = {};\naddDataToTelemetry.snr = gatewayInfo.snr;\naddDataToTelemetry.rssi = gatewayInfo.rssi;\naddDataToTelemetry.channel = gatewayInfo.channel_index;\naddDataToTelemetry.consumed_airtime = data.uplink_message.?consumed_airtime;\naddDataToTelemetry.fCnt = data.uplink_message.?f_cnt;\n\nvar isIncludeGatewayInfo = metadata[\"includeGatewayInfo\"];\nif(isIncludeGatewayInfo == true) {\n telemetry = processTelemetryData(telemetry, addDataToTelemetry);\n}\n\nvar result = {\n deviceName: deviceName,\n deviceType: deviceType,\n// assetName: assetName,\n// assetType: assetType,\n attributes: attributes,\n telemetry: telemetry\n};\n\naddAdditionalInfoForDeviceMsg(result, customerName, groupName);\n\nreturn result;\n\n\nfunction addAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName) {\n if (customerName != null) {\n deviceInfo.customerName = customerName;\n }\n if (groupName != null) {\n deviceInfo.groupName = groupName;\n }\n}\n\nfunction parseDateToTimestamp(dateString) {\n var date = new Date(dateString);\n var timestamp = date.getTime();\n \n // If we cannot parse timestamp - we will use the current timestamp\n if (timestamp == -1) {\n timestamp = Date.now();\n }\n \n return timestamp;\n}\n\nfunction getGatewayInfo() {\n var gatewayList = data.uplink_message.?rx_metadata;\n var maxRssi = Integer.MIN_VALUE;\n var gatewayInfo = {};\n \n foreach (gateway : gatewayList) {\n if(gateway.rssi > maxRssi) {\n maxRssi = gateway.rssi;\n gatewayInfo = gateway;\n }\n }\n \n return gatewayInfo;\n}\n\nfunction processTelemetryData(telemetry, addDataToTelemetry) {\n if (telemetry.size >= 1) {\n telemetry = addDataToTelemetries(telemetry, addDataToTelemetry);\n }\n else {\n telemetry.add(addDataToTelemetry);\n }\n \n return telemetry;\n}\n\nfunction addDataToTelemetries(telemetries, addDataToTelemetry) {\n foreach(telemetry : telemetries) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[\"values\"].keys.contains(element.key)) {\n telemetry[\"values\"][element.key] = element.value;\n }\n } \n }\n \n return telemetries;\n}", + "encoder": null, + "tbelEncoder": null, + "updateOnlyKeys": [ + "fPort", + "bandwidth", + "frequency", + "net_id", + "cluster_id", + "cluster_address", + "device_id", + "join_eui", + "battery", + "eui", + "channel", + "applicationId", + "devAddr", + "spreadingFactor", + "codeRate", + "tenantId" + ] + }, + "additionalInfo": { + "description": "" + }, + "edgeTemplate": false +} \ No newline at end of file diff --git a/VENDORS/Milesight/EM400-UDL/ThingsStackCommunity/uplink/metadata.json b/VENDORS/Milesight/EM400-UDL/ThingsStackCommunity/uplink/metadata.json new file mode 100644 index 00000000..0d75c374 --- /dev/null +++ b/VENDORS/Milesight/EM400-UDL/ThingsStackCommunity/uplink/metadata.json @@ -0,0 +1,4 @@ +{ + "integrationName": "The Things Stack Community integration", + "includeGatewayInfo": "false" +} \ No newline at end of file diff --git a/VENDORS/Milesight/EM400-UDL/ThingsStackCommunity/uplink/payload.json b/VENDORS/Milesight/EM400-UDL/ThingsStackCommunity/uplink/payload.json new file mode 100644 index 00000000..281d8f45 --- /dev/null +++ b/VENDORS/Milesight/EM400-UDL/ThingsStackCommunity/uplink/payload.json @@ -0,0 +1,54 @@ +{ + "end_device_ids": { + "device_id": "eui-1000000000000001", + "application_ids": { + "application_id": "application-tts-name" + }, + "dev_eui": "1000000000000001", + "join_eui": "2000000000000001", + "dev_addr": "20000001" + }, + "correlation_ids": ["as:up:01H0S7ZJQ9MQPMVY49FT3SE07M", "gs:conn:01H03BQZ9342X3Y86DJ2P704E5", "gs:up:host:01H03BQZ99EGAM52KK1300GFKN", "gs:uplink:01H0S7ZJGS6D9TJSKJN8XNTMAV", "ns:uplink:01H0S7ZJGS9KKD4HTTPKFEMWCV", "rpc:/ttn.lorawan.v3.GsNs/HandleUplink:01H0S7ZJGSF3M38ZRZVTM38DEC", "rpc:/ttn.lorawan.v3.NsAs/HandleUplink:01H0S7ZJQ8R2EH5AA269AKM8DX"], + "received_at": "2023-05-19T05:33:35.848446463Z", + "uplink_message": { + "session_key_id": "AYfqmb0pc/1uRZv9xUydgQ==", + "f_port": 85, + "f_cnt": 10335, + "frm_payload": "g2foAAGEgkEGAQ==", + "rx_metadata": [{ + "gateway_ids": { + "gateway_id": "eui-6a7e111a10000000", + "eui": "6A7E111A10000000" + }, + "time": "2023-05-19T05:33:35.608982Z", + "timestamp": 3893546133, + "rssi": -35, + "channel_rssi": -35, + "snr": 13.2, + "frequency_offset": "69", + "uplink_token": "CiIKIAoUZXVpLTZhN2UxMTFhMTAwMDAwMDASCCThJP/+9k6eEJWZy8AOGgwIr5ScowYQvNbUsQIgiMy8y6jwpwE=", + "channel_index": 3, + "received_at": "2023-05-19T05:33:35.607383681Z" + }], + "settings": { + "data_rate": { + "lora": { + "bandwidth": 125000, + "spreading_factor": 7, + "coding_rate": "4/5" + } + }, + "frequency": "867100000", + "timestamp": 3893546133, + "time": "2023-05-19T05:33:35.608982Z" + }, + "received_at": "2023-05-19T05:33:35.641841782Z", + "consumed_airtime": "0.056576s", + "network_ids": { + "net_id": "000013", + "tenant_id": "ttn", + "cluster_id": "eu1", + "cluster_address": "eu1.cloud.thethings.network" + } + } +} \ No newline at end of file diff --git a/VENDORS/Milesight/EM400-UDL/ThingsStackCommunity/uplink/payload_1.json b/VENDORS/Milesight/EM400-UDL/ThingsStackCommunity/uplink/payload_1.json new file mode 100644 index 00000000..76ae9bd5 --- /dev/null +++ b/VENDORS/Milesight/EM400-UDL/ThingsStackCommunity/uplink/payload_1.json @@ -0,0 +1,54 @@ +{ + "end_device_ids": { + "device_id": "eui-1000000000000001", + "application_ids": { + "application_id": "application-tts-name" + }, + "dev_eui": "1000000000000001", + "join_eui": "2000000000000001", + "dev_addr": "20000001" + }, + "correlation_ids": ["as:up:01H0S7ZJQ9MQPMVY49FT3SE07M", "gs:conn:01H03BQZ9342X3Y86DJ2P704E5", "gs:up:host:01H03BQZ99EGAM52KK1300GFKN", "gs:uplink:01H0S7ZJGS6D9TJSKJN8XNTMAV", "ns:uplink:01H0S7ZJGS9KKD4HTTPKFEMWCV", "rpc:/ttn.lorawan.v3.GsNs/HandleUplink:01H0S7ZJGSF3M38ZRZVTM38DEC", "rpc:/ttn.lorawan.v3.NsAs/HandleUplink:01H0S7ZJQ8R2EH5AA269AKM8DX"], + "received_at": "2023-05-19T05:33:35.848446463Z", + "uplink_message": { + "session_key_id": "AYfqmb0pc/1uRZv9xUydgQ==", + "f_port": 85, + "f_cnt": 10335, + "frm_payload": "AXVcA2cBAQSCRAgFAAE=", + "rx_metadata": [{ + "gateway_ids": { + "gateway_id": "eui-6a7e111a10000000", + "eui": "6A7E111A10000000" + }, + "time": "2023-05-19T05:33:35.608982Z", + "timestamp": 3893546133, + "rssi": -35, + "channel_rssi": -35, + "snr": 13.2, + "frequency_offset": "69", + "uplink_token": "CiIKIAoUZXVpLTZhN2UxMTFhMTAwMDAwMDASCCThJP/+9k6eEJWZy8AOGgwIr5ScowYQvNbUsQIgiMy8y6jwpwE=", + "channel_index": 3, + "received_at": "2023-05-19T05:33:35.607383681Z" + }], + "settings": { + "data_rate": { + "lora": { + "bandwidth": 125000, + "spreading_factor": 7, + "coding_rate": "4/5" + } + }, + "frequency": "867100000", + "timestamp": 3893546133, + "time": "2023-05-19T05:33:35.608982Z" + }, + "received_at": "2023-05-19T05:33:35.641841782Z", + "consumed_airtime": "0.056576s", + "network_ids": { + "net_id": "000013", + "tenant_id": "ttn", + "cluster_id": "eu1", + "cluster_address": "eu1.cloud.thethings.network" + } + } +} \ No newline at end of file diff --git a/VENDORS/Milesight/EM400-UDL/ThingsStackCommunity/uplink/result.json b/VENDORS/Milesight/EM400-UDL/ThingsStackCommunity/uplink/result.json new file mode 100644 index 00000000..68147d48 --- /dev/null +++ b/VENDORS/Milesight/EM400-UDL/ThingsStackCommunity/uplink/result.json @@ -0,0 +1,29 @@ +{ + "deviceName": "eui-1000000000000001", + "deviceType": "EM400-UDL", + "attributes": { + "eui": "1000000000000001", + "fPort": 85, + "applicationId": "application-tts-name", + "devAddr": "20000001", + "spreadingFactor": 7, + "codeRate": "4/5", + "tenantId": "ttn", + "device_id": "eui-1000000000000001", + "join_eui": "2000000000000001", + "net_id": "000013", + "cluster_id": "eu1", + "cluster_adress": "eu1.cloud.thethings.network", + "bandwidth": 125000, + "frequency": "867100000" + }, + "telemetry": [{ + "ts": 1684474415641, + "values": { + "temperature": 23.2, + "temperature_abnormal": true, + "distance": 1601, + "distance_alarming": true + } + }] +} \ No newline at end of file diff --git a/VENDORS/Milesight/EM400-UDL/ThingsStackCommunity/uplink/result_1.json b/VENDORS/Milesight/EM400-UDL/ThingsStackCommunity/uplink/result_1.json new file mode 100644 index 00000000..ffeeafe0 --- /dev/null +++ b/VENDORS/Milesight/EM400-UDL/ThingsStackCommunity/uplink/result_1.json @@ -0,0 +1,29 @@ +{ + "deviceName": "eui-1000000000000001", + "deviceType": "EM400-UDL", + "attributes": { + "eui": "1000000000000001", + "fPort": 85, + "applicationId": "application-tts-name", + "devAddr": "20000001", + "spreadingFactor": 7, + "codeRate": "4/5", + "tenantId": "ttn", + "device_id": "eui-1000000000000001", + "join_eui": "2000000000000001", + "net_id": "000013", + "cluster_id": "eu1", + "cluster_adress": "eu1.cloud.thethings.network", + "bandwidth": 125000, + "frequency": "867100000" + }, + "telemetry": [{ + "ts": 1684474415641, + "values": { + "battery": 92, + "temperature": 25.7, + "distance": 2116, + "position": "tilt" + } + }] +} \ No newline at end of file diff --git a/VENDORS/Milesight/EM400-UDL/ThingsStackIndustries/uplink/converter.json b/VENDORS/Milesight/EM400-UDL/ThingsStackIndustries/uplink/converter.json new file mode 100644 index 00000000..b275fc93 --- /dev/null +++ b/VENDORS/Milesight/EM400-UDL/ThingsStackIndustries/uplink/converter.json @@ -0,0 +1,40 @@ +{ + "name": "The Things Stack Industries Uplink Decoder for EM400-UDL", + "type": "UPLINK", + "debugMode": false, + "debugSettings": { + "failuresEnabled": true, + "allEnabled": false, + "allEnabledUntil": 1733331880270 + }, + "configuration": { + "scriptLang": "TBEL", + "decoder": null, + "tbelDecoder": "var data = decodeToJson(payload);\n\nvar deviceName = data.end_device_ids.device_id;\nvar deviceType = \"EM400-UDL\";\nvar groupName = null; // If groupName is not null - created device will be added to the entity group with such name.\nvar customerName = null; // If customerName is not null - created devices will be assigned to customer with such name. \n\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// If you want to parse incoming data somehow, you can add your code to this function.\n// input: bytes\n// expected output:\n// {\n// \"attributes\": {\"attributeKey\": \"attributeValue\"},\n// \"telemetry\": [{\"ts\": 1...1, \"values\": {\"telemetryKey\":\"telemetryValue\"}, {\"ts\": 1...2, \"values\": {\"telemetryKey\":\"telemetryValue\"}}]\n// }\n\nfunction decodeFrmPayload(input) {\n var output = { attributes: {}, telemetry: []};\n \n // --- Decoding code --- //\n var decoded = {};\n for (var i = 0; i < input.length - 2 ; ) {\n var channel_id = input[i++] & 0xff;\n var channel_type = input[i++] & 0xff;\n\n // BATTERY\n if (channel_id === 0x01 && channel_type === 0x75) {\n decoded.battery = input[i];\n i += 1;\n }\n // TEMPERATURE\n else if (channel_id === 0x03 && channel_type === 0x67) {\n decoded.temperature = parseBytesToInt(input, i, 2, false) / 10;\n i += 2;\n }\n // DISTANCE\n else if (channel_id === 0x04 && channel_type === 0x82) {\n decoded.distance = parseBytesToInt(input, i, 2, false);\n i += 2;\n }\n // POSITION\n else if (channel_id === 0x05 && channel_type === 0x00) {\n decoded.position = input[i] === 0 ? \"normal\" : \"tilt\";\n i += 1;\n }\n // TEMPERATURE WITH ABNORMAL\n else if (channel_id === 0x83 && channel_type === 0x67) {\n decoded.temperature = parseBytesToInt(input, i, 2, false) / 10;\n decoded.temperature_abnormal = input[i + 2] == 0 ? false : true;\n i += 3;\n }\n // DISTANCE WITH ALARMING\n else if (channel_id === 0x84 && channel_type === 0x82) {\n decoded.distance = parseBytesToInt(input, i, 2, false);\n decoded.distance_alarming = input[i + 2] == 0 ? false : true;\n i += 3;\n }\n }\n \n output.telemetry = [{\n ts: timestamp,\n values: decoded\n }];\n\n // --- Decoding code --- //\n return output;\n}\n\n// --- attributes and telemetry objects ---\nvar telemetry = [];\nvar attributes = {};\n// --- attributes and telemetry objects ---\n\n// --- Timestamp parsing\nvar dateString = data.uplink_message.received_at;\n\nif ((data.simulated != null && data.simulated) || dateString == null) {\n dateString = data.received_at;\n}\n\ntimestamp = parseDateToTimestamp(dateString);\n// --- Timestamp parsing\n\n// Message parsing\n// To avoid paths in the decoded objects we passing false value to function as \"pathInKey\" argument.\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.\n\n// Passing incoming bytes to decodeFrmPayload function, to get custom decoding\nvar customDecoding = {};\nif (data.uplink_message.get(\"frm_payload\") != null) {\n customDecoding = decodeFrmPayload(base64ToBytes(data.uplink_message.frm_payload));\n}\n\n// Collecting data to result\nif (customDecoding.?telemetry.size() > 0) {\n if (customDecoding.telemetry instanceof java.util.ArrayList) {\n foreach(telemetryObj: customDecoding.telemetry) {\n if (telemetryObj.ts != null && telemetryObj.values != null) {\n telemetry.add(telemetryObj);\n }\n }\n } else {\n telemetry.putAll(customDecoding.telemetry);\n }\n}\n\nif (customDecoding.?attributes.size() > 0) {\n attributes.putAll(customDecoding.attributes);\n}\n\n// You can add some keys manually to attributes or telemetry\nvar applicationId = data.end_device_ids.?application_ids.?application_id;\nvar devAddr = data.end_device_ids.?dev_addr;\nvar spreadingFactor = data.uplink_message.?settings.?data_rate.?lora.?spreading_factor;\nvar codeRate = data.uplink_message.?settings.?data_rate.?lora.?coding_rate;\nvar tenantId = data.uplink_message.?network_ids.?tenant_id;\nattributes.eui = data.end_device_ids.dev_eui;\nattributes.fPort = data.uplink_message.f_port;\nattributes.applicationId = applicationId;\nattributes.devAddr = devAddr;\nattributes.spreadingFactor = spreadingFactor;\nattributes.codeRate = codeRate;\nattributes.tenantId = tenantId;\nattributes.device_id = data.end_device_ids.?device_id;\nattributes.join_eui = data.end_device_ids.?join_eui;\nattributes.net_id = data.uplink_message.?network_ids.?net_id;\nattributes.cluster_id = data.uplink_message.?network_ids.?cluster_id;\nattributes.cluster_adress = data.uplink_message.?network_ids.?cluster_address;\nattributes.bandwidth = data.uplink_message.?settings.?data_rate.?lora.?bandwidth;\nattributes.frequency = data.uplink_message.?settings.?frequency;\n\nvar isIncludeGatewayInfo = metadata[\"includeGatewayInfo\"];\nif(isIncludeGatewayInfo == true) {\n var gatewayInfo = getGatewayInfo();\n var addDataToTelemetry = {};\n addDataToTelemetry.snr = gatewayInfo.snr;\n addDataToTelemetry.rssi = gatewayInfo.rssi;\n addDataToTelemetry.channel = gatewayInfo.channel_index;\n addDataToTelemetry.consumed_airtime = data.uplink_message.?consumed_airtime;\n addDataToTelemetry.fCnt = data.uplink_message.?f_cnt;\n\n telemetry = processTelemetryData(telemetry, addDataToTelemetry);\n}\n\nvar result = {\n deviceName: deviceName,\n deviceType: deviceType,\n // assetName: assetName,\n // assetType: assetType,\n attributes: attributes,\n telemetry: telemetry\n};\n\naddAdditionalInfoForDeviceMsg(result, customerName, groupName);\n\nreturn result;\n\nfunction addAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName) {\n if (customerName != null) {\n deviceInfo.customerName = customerName;\n }\n if (groupName != null) {\n deviceInfo.groupName = groupName;\n }\n}\n\nfunction parseDateToTimestamp(dateString) {\n var date = new Date(dateString);\n var timestamp = date.getTime();\n \n // If we cannot parse timestamp - we will use the current timestamp\n if (timestamp == -1) {\n timestamp = Date.now();\n }\n \n return timestamp;\n}\n\nfunction getGatewayInfo() {\n var gatewayList = data.uplink_message.?rx_metadata;\n var maxRssi = Integer. MIN_VALUE;\n var gatewayInfo = {};\n \n foreach (gateway : gatewayList) {\n if(gateway.rssi > maxRssi) {\n maxRssi = gateway.rssi;\n gatewayInfo = gateway;\n }\n }\n \n return gatewayInfo;\n}\n\nfunction processTelemetryData(telemetry, addDataToTelemetry) {\n if (telemetry.size >= 1) {\n telemetry = addDataToTelemetries(telemetry, addDataToTelemetry);\n }\n else {\n telemetry.add(addDataToTelemetry);\n }\n \n return telemetry;\n}\n\nfunction addDataToTelemetries(telemetries, addDataToTelemetry) {\n foreach(telemetry : telemetries) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[\"values\"].keys.contains(element.key)) {\n telemetry[\"values\"][element.key] = element.value;\n }\n } \n }\n \n return telemetries;\n}", + "encoder": null, + "tbelEncoder": null, + "updateOnlyKeys": [ + "fPort", + "bandwidth", + "frequency", + "net_id", + "cluster_id", + "cluster_address", + "tenant_address", + "device_id", + "join_eui", + "eui", + "channel", + "devAddr", + "spreadingFactor", + "codeRate", + "tenantId", + "applicationId", + "battery" + ] + }, + "additionalInfo": { + "description": "" + }, + "edgeTemplate": false +} \ No newline at end of file diff --git a/VENDORS/Milesight/EM400-UDL/ThingsStackIndustries/uplink/metadata.json b/VENDORS/Milesight/EM400-UDL/ThingsStackIndustries/uplink/metadata.json new file mode 100644 index 00000000..904c0fa0 --- /dev/null +++ b/VENDORS/Milesight/EM400-UDL/ThingsStackIndustries/uplink/metadata.json @@ -0,0 +1,4 @@ +{ + "integrationName": "The Things Stack Industries integration new", + "includeGatewayInfo": "false" +} \ No newline at end of file diff --git a/VENDORS/Milesight/EM400-UDL/ThingsStackIndustries/uplink/payload.json b/VENDORS/Milesight/EM400-UDL/ThingsStackIndustries/uplink/payload.json new file mode 100644 index 00000000..1763bfd0 --- /dev/null +++ b/VENDORS/Milesight/EM400-UDL/ThingsStackIndustries/uplink/payload.json @@ -0,0 +1,77 @@ +{ + "end_device_ids": { + "device_id": "eui-1000000000000001", + "application_ids": { + "application_id": "application-tti-name" + }, + "dev_eui": "1000000000000001", + "join_eui": "2000000000000001", + "dev_addr": "20000001" + }, + "correlation_ids": ["as:up:01H0PZDGB1NW6NAPD815NGHPF6", "gs:conn:01H0FJRSXSYT7VKNYXJ89F95XT", "gs:up:host:01H0FJRSY3MZMGPPFBQ4FZV4T8", "gs:uplink:01H0PZDG4HHGFRTXRTXD4PFTH7", "ns:uplink:01H0PZDG4JZ3BM0K6J89EQK1J7", "rpc:/ttn.lorawan.v3.GsNs/HandleUplink:01H0PZDG4J02F85RYFPCNSNXCR", "rpc:/ttn.lorawan.v3.NsAs/HandleUplink:01H0PZDGB081PMP806BJHNHX1A"], + "received_at": "2023-05-18T08:25:26.112483370Z", + "uplink_message": { + "session_key_id": "AYfg8rhha5n+FWx0ZaAprA==", + "f_port": 85, + "f_cnt": 5017, + "frm_payload": "g2foAAGEgkEGAQ==", + "rx_metadata": [{ + "gateway_ids": { + "gateway_id": "eui-6A7E111A10000000", + "eui": "6A7E111A10000000" + }, + "time": "2023-05-18T08:25:25.885310Z", + "timestamp": 818273765, + "rssi": -24, + "channel_rssi": -24, + "snr": 12, + "frequency_offset": "671", + "uplink_token": "CiIKIAoUZXVpLTZBN0UxMTFBMTAwMDAwMDASCCThJP/+9k6eEOW7l4YDGgwI9cGXowYQ5KPhrwMgiI2rp+jpOA=", + "channel_index": 2, + "received_at": "2023-05-18T08:25:25.869324983Z" + }, { + "gateway_ids": { + "gateway_id": "packetbroker" + }, + "packet_broker": { + "message_id": "01H0PZDG4MF9AYSMNY44MAVTDH", + "forwarder_net_id": "000013", + "forwarder_tenant_id": "ttn", + "forwarder_cluster_id": "eu1.cloud.thethings.network", + "forwarder_gateway_eui": "6A7E111A10000000", + "forwarder_gateway_id": "eui-6a7e111a10000000", + "home_network_net_id": "000013", + "home_network_tenant_id": "tenant", + "home_network_cluster_id": "eu1.cloud.thethings.industries" + }, + "time": "2023-05-18T08:25:25.885310Z", + "rssi": -24, + "channel_rssi": -24, + "snr": 12, + "frequency_offset": "671", + "uplink_token": "eyJnIjoiWlhsS2FHSkhZMmxQYVVwQ1RWUkpORkl3VGs1VE1XTnBURU5LYkdKdFRXbFBhVXBDVFZSSk5GSXdUazVKYVhkcFlWaFphVTlwU201a01uaGhWVlJvZDFSWFVuRmlSM1JtVFcxT2RVbHBkMmxrUjBadVNXcHZhV05ZY0RKT1IyeExaREpSZVZwR1pIUmpNRXBLVlVoR2RFNVZkR3BWVTBvNUxua3paVVJTWVRaM1lXOU1kbTQwVm5sdmIyWmlPWGN1ZUhCZmVrcElaa3hIWlZadGRVUlFVeTVuYlRaVlZXRXdkakpHV0VKMGJUUjZaMjVXUkVoeGVHRjRaMlJKTlVkS1VsbERhemc1VDNCbk5rVk1iM1JDUkVZM1VWbHdZbEJDTkdOblNqWjBlbkphYUV4MFRVMHhZMVZFTTFac01XdExURUo0YURaMFExTnhhMVJsWWw4eE5FdHlVVXcyZUhsRWFFbEhlakJITXpoTE0xaFdlRzR5VUVjMk4wNUViME5WTkhoTmRrazFZVk5oWkUwd2FXVnFjR294VGtoMFduZHlZMDFxVlVGNmRsbERUazlNY2s5eFdVeFpWMk5XTG1WVFFYVkpNVkptT1U5NWRqUTNhSEoxTUZoalYxRT0iLCJhIjp7ImZuaWQiOiIwMDAwMTMiLCJmdGlkIjoidHRuIiwiZmNpZCI6ImV1MS5jbG91ZC50aGV0aGluZ3MubmV0d29yayJ9fQ==", + "received_at": "2023-05-18T08:25:25.906038642Z" + }], + "settings": { + "data_rate": { + "lora": { + "bandwidth": 125000, + "spreading_factor": 7, + "coding_rate": "4/5" + } + }, + "frequency": "868500000", + "timestamp": 818273765, + "time": "2023-05-18T08:25:25.885310Z" + }, + "received_at": "2023-05-18T08:25:25.906399073Z", + "consumed_airtime": "0.097536s", + "network_ids": { + "net_id": "000013", + "tenant_id": "tenant", + "cluster_id": "eu1", + "cluster_address": "eu1.cloud.thethings.industries", + "tenant_address": "tenant.eu1.cloud.thethings.industries" + } + } +} \ No newline at end of file diff --git a/VENDORS/Milesight/EM400-UDL/ThingsStackIndustries/uplink/payload_1.json b/VENDORS/Milesight/EM400-UDL/ThingsStackIndustries/uplink/payload_1.json new file mode 100644 index 00000000..84cc5f8f --- /dev/null +++ b/VENDORS/Milesight/EM400-UDL/ThingsStackIndustries/uplink/payload_1.json @@ -0,0 +1,77 @@ +{ + "end_device_ids": { + "device_id": "eui-1000000000000001", + "application_ids": { + "application_id": "application-tti-name" + }, + "dev_eui": "1000000000000001", + "join_eui": "2000000000000001", + "dev_addr": "20000001" + }, + "correlation_ids": ["as:up:01H0PZDGB1NW6NAPD815NGHPF6", "gs:conn:01H0FJRSXSYT7VKNYXJ89F95XT", "gs:up:host:01H0FJRSY3MZMGPPFBQ4FZV4T8", "gs:uplink:01H0PZDG4HHGFRTXRTXD4PFTH7", "ns:uplink:01H0PZDG4JZ3BM0K6J89EQK1J7", "rpc:/ttn.lorawan.v3.GsNs/HandleUplink:01H0PZDG4J02F85RYFPCNSNXCR", "rpc:/ttn.lorawan.v3.NsAs/HandleUplink:01H0PZDGB081PMP806BJHNHX1A"], + "received_at": "2023-05-18T08:25:26.112483370Z", + "uplink_message": { + "session_key_id": "AYfg8rhha5n+FWx0ZaAprA==", + "f_port": 85, + "f_cnt": 5017, + "frm_payload": "AXVcA2cBAQSCRAgFAAE=", + "rx_metadata": [{ + "gateway_ids": { + "gateway_id": "eui-6A7E111A10000000", + "eui": "6A7E111A10000000" + }, + "time": "2023-05-18T08:25:25.885310Z", + "timestamp": 818273765, + "rssi": -24, + "channel_rssi": -24, + "snr": 12, + "frequency_offset": "671", + "uplink_token": "CiIKIAoUZXVpLTZBN0UxMTFBMTAwMDAwMDASCCThJP/+9k6eEOW7l4YDGgwI9cGXowYQ5KPhrwMgiI2rp+jpOA=", + "channel_index": 2, + "received_at": "2023-05-18T08:25:25.869324983Z" + }, { + "gateway_ids": { + "gateway_id": "packetbroker" + }, + "packet_broker": { + "message_id": "01H0PZDG4MF9AYSMNY44MAVTDH", + "forwarder_net_id": "000013", + "forwarder_tenant_id": "ttn", + "forwarder_cluster_id": "eu1.cloud.thethings.network", + "forwarder_gateway_eui": "6A7E111A10000000", + "forwarder_gateway_id": "eui-6a7e111a10000000", + "home_network_net_id": "000013", + "home_network_tenant_id": "tenant", + "home_network_cluster_id": "eu1.cloud.thethings.industries" + }, + "time": "2023-05-18T08:25:25.885310Z", + "rssi": -24, + "channel_rssi": -24, + "snr": 12, + "frequency_offset": "671", + "uplink_token": "eyJnIjoiWlhsS2FHSkhZMmxQYVVwQ1RWUkpORkl3VGs1VE1XTnBURU5LYkdKdFRXbFBhVXBDVFZSSk5GSXdUazVKYVhkcFlWaFphVTlwU201a01uaGhWVlJvZDFSWFVuRmlSM1JtVFcxT2RVbHBkMmxrUjBadVNXcHZhV05ZY0RKT1IyeExaREpSZVZwR1pIUmpNRXBLVlVoR2RFNVZkR3BWVTBvNUxua3paVVJTWVRaM1lXOU1kbTQwVm5sdmIyWmlPWGN1ZUhCZmVrcElaa3hIWlZadGRVUlFVeTVuYlRaVlZXRXdkakpHV0VKMGJUUjZaMjVXUkVoeGVHRjRaMlJKTlVkS1VsbERhemc1VDNCbk5rVk1iM1JDUkVZM1VWbHdZbEJDTkdOblNqWjBlbkphYUV4MFRVMHhZMVZFTTFac01XdExURUo0YURaMFExTnhhMVJsWWw4eE5FdHlVVXcyZUhsRWFFbEhlakJITXpoTE0xaFdlRzR5VUVjMk4wNUViME5WTkhoTmRrazFZVk5oWkUwd2FXVnFjR294VGtoMFduZHlZMDFxVlVGNmRsbERUazlNY2s5eFdVeFpWMk5XTG1WVFFYVkpNVkptT1U5NWRqUTNhSEoxTUZoalYxRT0iLCJhIjp7ImZuaWQiOiIwMDAwMTMiLCJmdGlkIjoidHRuIiwiZmNpZCI6ImV1MS5jbG91ZC50aGV0aGluZ3MubmV0d29yayJ9fQ==", + "received_at": "2023-05-18T08:25:25.906038642Z" + }], + "settings": { + "data_rate": { + "lora": { + "bandwidth": 125000, + "spreading_factor": 7, + "coding_rate": "4/5" + } + }, + "frequency": "868500000", + "timestamp": 818273765, + "time": "2023-05-18T08:25:25.885310Z" + }, + "received_at": "2023-05-18T08:25:25.906399073Z", + "consumed_airtime": "0.097536s", + "network_ids": { + "net_id": "000013", + "tenant_id": "tenant", + "cluster_id": "eu1", + "cluster_address": "eu1.cloud.thethings.industries", + "tenant_address": "tenant.eu1.cloud.thethings.industries" + } + } +} \ No newline at end of file diff --git a/VENDORS/Milesight/EM400-UDL/ThingsStackIndustries/uplink/result.json b/VENDORS/Milesight/EM400-UDL/ThingsStackIndustries/uplink/result.json new file mode 100644 index 00000000..b997733c --- /dev/null +++ b/VENDORS/Milesight/EM400-UDL/ThingsStackIndustries/uplink/result.json @@ -0,0 +1,29 @@ +{ + "deviceName": "eui-1000000000000001", + "deviceType": "EM400-UDL", + "attributes": { + "eui": "1000000000000001", + "fPort": 85, + "applicationId": "application-tti-name", + "devAddr": "20000001", + "spreadingFactor": 7, + "codeRate": "4/5", + "tenantId": "tenant", + "device_id": "eui-1000000000000001", + "join_eui": "2000000000000001", + "net_id": "000013", + "cluster_id": "eu1", + "cluster_adress": "eu1.cloud.thethings.industries", + "bandwidth": 125000, + "frequency": "868500000" + }, + "telemetry": [{ + "ts": 1684398325906, + "values": { + "temperature": 23.2, + "temperature_abnormal": true, + "distance": 1601, + "distance_alarming": true + } + }] +} \ No newline at end of file diff --git a/VENDORS/Milesight/EM400-UDL/ThingsStackIndustries/uplink/result_1.json b/VENDORS/Milesight/EM400-UDL/ThingsStackIndustries/uplink/result_1.json new file mode 100644 index 00000000..75ff5e26 --- /dev/null +++ b/VENDORS/Milesight/EM400-UDL/ThingsStackIndustries/uplink/result_1.json @@ -0,0 +1,29 @@ +{ + "deviceName": "eui-1000000000000001", + "deviceType": "EM400-UDL", + "attributes": { + "eui": "1000000000000001", + "fPort": 85, + "applicationId": "application-tti-name", + "devAddr": "20000001", + "spreadingFactor": 7, + "codeRate": "4/5", + "tenantId": "tenant", + "device_id": "eui-1000000000000001", + "join_eui": "2000000000000001", + "net_id": "000013", + "cluster_id": "eu1", + "cluster_adress": "eu1.cloud.thethings.industries", + "bandwidth": 125000, + "frequency": "868500000" + }, + "telemetry": [{ + "ts": 1684398325906, + "values": { + "battery": 92, + "temperature": 25.7, + "distance": 2116, + "position": "tilt" + } + }] +} \ No newline at end of file diff --git a/VENDORS/Milesight/EM400-UDL/guide.md b/VENDORS/Milesight/EM400-UDL/guide.md new file mode 100644 index 00000000..56807e5e --- /dev/null +++ b/VENDORS/Milesight/EM400-UDL/guide.md @@ -0,0 +1,21 @@ +# Multifunctional Ultrasonic Distance/Level Sensor - Milesight IoT + +The payload decoder function is applicable to EM400-UDL. + +## Payload Definition + +| CHANNEL | ID | TYPE | LENGTH | DESCRIPTION | +| :--------------------: | :--: | :--: | :----: | ------------------------------------------------------ | +| Battery | 0x01 | 0x75 | 1 | battery(1B)
battery, unit: % | +| Temperature | 0x03 | 0x67 | 2 | temperature(2B)
temperature, unit: ℃ | +| Distance | 0x04 | 0x82 | 2 | distance(2B)
distance, unit: mm | +| Position | 0x05 | 0x00 | 1 | position(1B)
position, values(0: normal, 1: tilt) | +| Location
(NB-IoT) | 0x06 | 0x88 | 9 | longitude(4B) + latitude(4B) + motion_status(1B) | +| Temperature Abnormal | 0x83 | 0x67 | 3 | temperature(2B) + status(1B) | +| Distance Alarm | 0x84 | 0x82 | 3 | distance(2B) + status(1B) | + +### Motion Status Definition + +| BITS | 7..4 | 3..0 | +| :---------: | :-------------------------------------------------------------------- | :------------------------------------------------------------------------------ | +| DESCRIPTION | geofence_status, values: (0: inside, 1: outside, 2: unset, 3: unknown | motion_status, values: (0: unknown, 1: start moving, 2: moving, 3: stop moving) | \ No newline at end of file diff --git a/VENDORS/Milesight/EM400-UDL/info.json b/VENDORS/Milesight/EM400-UDL/info.json new file mode 100644 index 00000000..f36ad2f8 --- /dev/null +++ b/VENDORS/Milesight/EM400-UDL/info.json @@ -0,0 +1,6 @@ +{ + "url": "https://www.milesight.com/iot/product/lorawan-sensor/em400-udl", + "label": "EM400-UDL Ultrasonic Distance Sensor", + "description": "EM400-UDL is a non-contact ultrasonic distance sensor designed for outdoor applications such as monitoring water level, fill level of tanks and silos, presence of objects, or snow level." +} + diff --git a/VENDORS/Milesight/EM400-UDL/photo.png b/VENDORS/Milesight/EM400-UDL/photo.png new file mode 100644 index 0000000000000000000000000000000000000000..974c3fe8ee4ed7d233348b92ba1ba02da9e121ed GIT binary patch literal 50218 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%0AG(1Py$C_rB}%@ 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 literal 0 HcmV?d00001 From da90abf19f58b4d34e7622be7e5f6705fa948a23 Mon Sep 17 00:00:00 2001 From: thingsboard017 Date: Thu, 12 Dec 2024 11:17:52 +0200 Subject: [PATCH 04/33] Deleted unused result_1.json --- .../EM400-MUD/LORIOT/uplink/result_1.json | 18 ------------------ 1 file changed, 18 deletions(-) delete mode 100644 VENDORS/Milesight/EM400-MUD/LORIOT/uplink/result_1.json diff --git a/VENDORS/Milesight/EM400-MUD/LORIOT/uplink/result_1.json b/VENDORS/Milesight/EM400-MUD/LORIOT/uplink/result_1.json deleted file mode 100644 index fc5481c9..00000000 --- a/VENDORS/Milesight/EM400-MUD/LORIOT/uplink/result_1.json +++ /dev/null @@ -1,18 +0,0 @@ -[{ - "deviceName": "1000000000000001", - "deviceType": "EM400-MUD", - "attributes": { - "eui": "1000000000000001", - "fPort": 85, - "frequency": 867500000 - }, - "telemetry": [{ - "ts": 1684478801936, - "values": { - "battery": 92, - "temperature": 25.7, - "distance": 2116, - "position": "tilt" - } - }] -}] \ No newline at end of file From 3b064ef47669a5d7caf631b1ea54e4c3755d1deb Mon Sep 17 00:00:00 2001 From: thingsboard017 Date: Thu, 12 Dec 2024 11:18:33 +0200 Subject: [PATCH 05/33] Deleted unused result_1.json --- .../EM400-MUD/LORIOT/uplink/result_1.json | 18 ------------------ 1 file changed, 18 deletions(-) delete mode 100644 VENDORS/Milesight/EM400-MUD/LORIOT/uplink/result_1.json diff --git a/VENDORS/Milesight/EM400-MUD/LORIOT/uplink/result_1.json b/VENDORS/Milesight/EM400-MUD/LORIOT/uplink/result_1.json deleted file mode 100644 index fc5481c9..00000000 --- a/VENDORS/Milesight/EM400-MUD/LORIOT/uplink/result_1.json +++ /dev/null @@ -1,18 +0,0 @@ -[{ - "deviceName": "1000000000000001", - "deviceType": "EM400-MUD", - "attributes": { - "eui": "1000000000000001", - "fPort": 85, - "frequency": 867500000 - }, - "telemetry": [{ - "ts": 1684478801936, - "values": { - "battery": 92, - "temperature": 25.7, - "distance": 2116, - "position": "tilt" - } - }] -}] \ No newline at end of file From 2902069cdf6b57391822dbfac39c0a73fa9f1682 Mon Sep 17 00:00:00 2001 From: thingsboard017 Date: Fri, 13 Dec 2024 10:30:35 +0200 Subject: [PATCH 06/33] Added 4 LNS integrations for EM500-CO2 (cherry picked from commit 10e2241ef63d8bac1b4b6845c2645c0e06dcad09) --- .../ChirpStack/uplink/converter.json | 39 +++++++++ .../EM500-CO2/ChirpStack/uplink/metadata.json | 4 + .../EM500-CO2/ChirpStack/uplink/payload.json | 48 +++++++++++ .../EM500-CO2/ChirpStack/uplink/result.json | 29 +++++++ .../EM500-CO2/LORIOT/uplink/converter.json | 29 +++++++ .../EM500-CO2/LORIOT/uplink/metadata.json | 4 + .../EM500-CO2/LORIOT/uplink/payload.json | 17 ++++ .../EM500-CO2/LORIOT/uplink/result.json | 19 +++++ .../uplink/converter.json | 39 +++++++++ .../ThingsStackCommunity/uplink/metadata.json | 4 + .../ThingsStackCommunity/uplink/payload.json | 54 ++++++++++++ .../ThingsStackCommunity/uplink/result.json | 30 +++++++ .../uplink/converter.json | 40 +++++++++ .../uplink/metadata.json | 4 + .../ThingsStackIndustries/uplink/payload.json | 77 ++++++++++++++++++ .../ThingsStackIndustries/uplink/result.json | 30 +++++++ VENDORS/Milesight/EM500-CO2/guide.md | 15 ++++ VENDORS/Milesight/EM500-CO2/info.json | 5 ++ VENDORS/Milesight/EM500-CO2/photo.png | Bin 0 -> 115101 bytes 19 files changed, 487 insertions(+) create mode 100644 VENDORS/Milesight/EM500-CO2/ChirpStack/uplink/converter.json create mode 100644 VENDORS/Milesight/EM500-CO2/ChirpStack/uplink/metadata.json create mode 100644 VENDORS/Milesight/EM500-CO2/ChirpStack/uplink/payload.json create mode 100644 VENDORS/Milesight/EM500-CO2/ChirpStack/uplink/result.json create mode 100644 VENDORS/Milesight/EM500-CO2/LORIOT/uplink/converter.json create mode 100644 VENDORS/Milesight/EM500-CO2/LORIOT/uplink/metadata.json create mode 100644 VENDORS/Milesight/EM500-CO2/LORIOT/uplink/payload.json create mode 100644 VENDORS/Milesight/EM500-CO2/LORIOT/uplink/result.json create mode 100644 VENDORS/Milesight/EM500-CO2/ThingsStackCommunity/uplink/converter.json create mode 100644 VENDORS/Milesight/EM500-CO2/ThingsStackCommunity/uplink/metadata.json create mode 100644 VENDORS/Milesight/EM500-CO2/ThingsStackCommunity/uplink/payload.json create mode 100644 VENDORS/Milesight/EM500-CO2/ThingsStackCommunity/uplink/result.json create mode 100644 VENDORS/Milesight/EM500-CO2/ThingsStackIndustries/uplink/converter.json create mode 100644 VENDORS/Milesight/EM500-CO2/ThingsStackIndustries/uplink/metadata.json create mode 100644 VENDORS/Milesight/EM500-CO2/ThingsStackIndustries/uplink/payload.json create mode 100644 VENDORS/Milesight/EM500-CO2/ThingsStackIndustries/uplink/result.json create mode 100644 VENDORS/Milesight/EM500-CO2/guide.md create mode 100644 VENDORS/Milesight/EM500-CO2/info.json create mode 100644 VENDORS/Milesight/EM500-CO2/photo.png diff --git a/VENDORS/Milesight/EM500-CO2/ChirpStack/uplink/converter.json b/VENDORS/Milesight/EM500-CO2/ChirpStack/uplink/converter.json new file mode 100644 index 00000000..e802bdfc --- /dev/null +++ b/VENDORS/Milesight/EM500-CO2/ChirpStack/uplink/converter.json @@ -0,0 +1,39 @@ +{ + "name": "ChirpStack Uplink Decoder for EM500-C02", + "type": "UPLINK", + "debugMode": false, + "debugSettings": { + "failuresEnabled": true, + "allEnabled": false, + "allEnabledUntil": 1733331880270 + }, + "configuration": { + "scriptLang": "TBEL", + "decoder": null, + "tbelDecoder": "var data = decodeToJson(payload);\nvar deviceName = data.deviceInfo.deviceName + \" \" + data.deviceInfo.devEui;\nvar deviceType = \"EM500-C02\";\nvar groupName = null; // If groupName is not null - created device will be added to the entity group with such name.\nvar customerName = null; // If customerName is not null - created devices will be assigned to customer with such name. \n\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// If you want to parse incoming data somehow, you can add your code to this function.\n// input: bytes\n// expected output:\n// {\n// \"attributes\": {\"attributeKey\": \"attributeValue\"},\n// \"telemetry\": [{\"ts\": 1...1, \"values\": {\"telemetryKey\":\"telemetryValue\"}, {\"ts\": 1...2, \"values\": {\"telemetryKey\":\"telemetryValue\"}}]\n// }\n\nfunction decodePayload(input) {\n var output = {\n attributes: {},\n telemetry: []\n };\n \n // --- Decoding code --- //\n var decoded = {};\n var historyDataList = [];\n for (var i = 0; i < input.length - 2 ; ) {\n var channel_id = input[i++] & 0xff;\n var channel_type = input[i++] & 0xff;\n \n // BATTERY\n if (channel_id === 0x01 && channel_type === 0x75) {\n decoded.battery = input[i];\n i += 1;\n }\n // TEMPERATURE\n else if (channel_id === 0x03 && channel_type === 0x67) {\n decoded.temperature = parseBytesToInt(input, i, 2, false) / 10;\n i += 2;\n \n // ℉\n // decoded.temperature = parseBytesToInt(input, i, 2, false) / 10 * 1.8 + 32;\n // i +=2;\n }\n // HUMIDITY\n else if (channel_id === 0x04 && channel_type === 0x68) {\n decoded.humidity = parseBytesToInt(input, i, 1, false) / 2;\n i += 1;\n }\n // CO2\n else if (channel_id === 0x05 && channel_type === 0x7d) {\n decoded.co2 = parseBytesToInt(input, i, 2, false);\n i += 2;\n }\n // PRESSURE\n else if (channel_id === 0x06 && channel_type === 0x73) {\n decoded.pressure = parseBytesToInt(input, i, 2, false) / 10;\n i += 2;\n }\n // TEMPERATURE CHANGE ALARM\n else if (channel_id === 0x83 && channel_type === 0xd7) {\n decoded.temperature = parseBytesToInt(input, i, 2, false) / 10;\n decoded.temperature_change = parseBytesToInt(input, i + 2, 2, false) / 10;\n decoded.temperature_alarm = readTemperatureAlarm(input[i + 4]);\n i += 5;\n }\n // HISTROY\n else if (channel_id === 0x20 && channel_type === 0xce) {\n var historyData = {\n ts: parseBytesToInt(input, i, 4, false) * 1000,\n values: {\n co2: parseBytesToInt(input, i + 4, 2, false),\n pressure: parseBytesToInt(input, i + 6, 1, false) / 10,\n temperature: parseBytesToInt(input, i + 8, 2, false) / 10,\n humidity: parseBytesToInt(input, i + 10, 1, false, false) / 2\n }\n };\n i += 11;\n \n historyDataList.add(historyData);\n } \n }\n\n output.telemetry = [{\n ts: timestamp,\n values: decoded\n }];\n \n output.telemetry.addAll(historyDataList);\n // --- Decoding code --- //\n return output;\n}\n\n// --- attributes and telemetry objects ---\nvar telemetry = [];\nvar attributes = {};\n// --- attributes and telemetry objects ---\n\n// --- Timestamp parsing\nvar dateString = data.time;\ntimestamp = parseDateToTimestamp(dateString);\n// --- Timestamp parsing\n\n// Passing incoming bytes to decodePayload function, to get custom decoding\nvar customDecoding = decodePayload(base64ToBytes(data.data));\n\n\nattributes.eui = data.deviceInfo.devEui;\n\n// Collecting data to result\nif (customDecoding.?telemetry.size() > 0) {\n if (customDecoding.telemetry instanceof java.util.ArrayList) {\n foreach(telemetryObj: customDecoding.telemetry) {\n if (telemetryObj.ts != null && telemetryObj.values != null) {\n telemetry.add(telemetryObj);\n }\n }\n } else {\n telemetry.putAll(customDecoding.telemetry);\n }\n}\n\nif (customDecoding.?attributes.size() > 0) {\n attributes.putAll(customDecoding.attributes);\n}\n\n// You can add some keys manually to attributes or telemetry\nattributes.eui = data.deviceInfo.?devEui;\nattributes.devAddr = data.devAddr;\nattributes.fPort = data.fPort;\nattributes.applicationId = data.deviceInfo.?applicationId;\nattributes.applicationName = data.deviceInfo.?applicationName;\nattributes.tenantId = data.deviceInfo.?tenantId;\nattributes.tenantName = data.deviceInfo.?tenantName;\nattributes.deviceProfileId = data.deviceInfo.?deviceProfileId;\nattributes.deviceProfileName = data.deviceInfo.?deviceProfileName;\nattributes.frequency = data.txInfo.?frequency;\nattributes.bandwidth = data.txInfo.?modulation.?lora.?bandwidth;\nattributes.spreadingFactor = data.txInfo.?modulation.?lora.?spreadingFactor;\nattributes.codeRate = data.txInfo.?modulation.?lora.?codeRate;\n\nif(Boolean.parseBoolean(metadata[\"includeGatewayInfo\"])) {\n var gatewayInfo = getGatewayInfo();\n var addDataToTelemetry = {};\n addDataToTelemetry.snr = gatewayInfo.snr;\n addDataToTelemetry.rssi = gatewayInfo.rssi;\n addDataToTelemetry.channel = gatewayInfo.channel;\n addDataToTelemetry.rfChain = gatewayInfo.rfChain;\n addDataToTelemetry.fCnt = data.fCnt;\n \n telemetry = processTelemetryData(telemetry, addDataToTelemetry);\n}\n\nvar result = {\n deviceName: deviceName,\n deviceType: deviceType,\n // assetName: assetName,\n // assetType: assetType,\n attributes: attributes,\n telemetry: telemetry\n};\n\naddAdditionalInfoForDeviceMsg(result, customerName, groupName);\n\nreturn result;\n\nfunction addAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName) {\n if (customerName != null) {\n deviceInfo.customerName = customerName;\n }\n if (groupName != null) {\n deviceInfo.groupName = groupName;\n }\n}\n\nfunction parseDateToTimestamp(dateString) {\n var date = new Date(dateString);\n var timestamp = date.getTime();\n \n // If we cannot parse timestamp - we will use the current timestamp\n if (timestamp == -1) {\n timestamp = Date.now();\n }\n \n return timestamp;\n}\n\nfunction getGatewayInfo() {\n var gatewayList = data.rxInfo;\n var maxRssi = Integer.MIN_VALUE;\n var gatewayInfo = {};\n \n foreach (gateway : gatewayList) {\n if(gateway.rssi > maxRssi) {\n maxRssi = gateway.rssi;\n gatewayInfo = gateway;\n }\n }\n \n return gatewayInfo;\n}\n\nfunction processTelemetryData(telemetry, addDataToTelemetry) {\n if (telemetry.size >= 1) {\n telemetry = addDataToTelemetries(telemetry, addDataToTelemetry);\n }\n else {\n telemetry.add(addDataToTelemetry);\n }\n \n return telemetry;\n}\n\nfunction addDataToTelemetries(telemetries, addDataToTelemetry) {\n foreach(telemetry : telemetries) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[\"values\"].keys.contains(element.key)) {\n telemetry[\"values\"][element.key] = element.value;\n }\n } \n }\n \n return telemetries;\n}\n\nfunction readTemperatureAlarm(type) {\n switch (type) {\n case 0:\n return \"threshold alarm\";\n case 1:\n return \"threshold alarm release\";\n case 2:\n return \"mutation alarm\";\n default:\n return \"unkown\";\n }\n}", + "encoder": null, + "tbelEncoder": null, + "updateOnlyKeys": [ + "tenantId", + "tenantName", + "applicationId", + "applicationName", + "deviceProfileId", + "deviceProfileName", + "devAddr", + "fPort", + "frequency", + "bandwidth", + "spreadingFactor", + "codeRate", + "channel", + "rfChain", + "eui", + "battery" + ] + }, + "additionalInfo": { + "description": "" + }, + "edgeTemplate": false +} \ No newline at end of file diff --git a/VENDORS/Milesight/EM500-CO2/ChirpStack/uplink/metadata.json b/VENDORS/Milesight/EM500-CO2/ChirpStack/uplink/metadata.json new file mode 100644 index 00000000..23f54b34 --- /dev/null +++ b/VENDORS/Milesight/EM500-CO2/ChirpStack/uplink/metadata.json @@ -0,0 +1,4 @@ +{ + "integrationName": "ChirpStack integration", + "includeGatewayInfo": "false" +} \ No newline at end of file diff --git a/VENDORS/Milesight/EM500-CO2/ChirpStack/uplink/payload.json b/VENDORS/Milesight/EM500-CO2/ChirpStack/uplink/payload.json new file mode 100644 index 00000000..88086852 --- /dev/null +++ b/VENDORS/Milesight/EM500-CO2/ChirpStack/uplink/payload.json @@ -0,0 +1,48 @@ +{ + "deduplicationId": "57433366-50a6-4dc2-8145-2df1bbc70d9e", + "time": "2023-05-22T07:47:05.404859+00:00", + "deviceInfo": { + "tenantId": "52f14cd4-c6f1-4fbd-8f87-4025e1d49242", + "tenantName": "ChirpStack", + "applicationId": "ca739e26-7b67-4f14-b69e-d568c22a5a75", + "applicationName": "Chirpstack application", + "deviceProfileId": "605d08d4-65f5-4d2c-8a5a-3d2457662f79", + "deviceProfileName": "Chirpstack default device profile", + "deviceName": "Device name", + "devEui": "1000000000000001", + "tags": {} + }, + "devAddr": "20000001", + "adr": true, + "dr": 5, + "fCnt": 4, + "fPort": 85, + "confirmed": false, + "data": "AXVkA2cZAQRocwV9ZwQGc2gn", + "rxInfo": [{ + "gatewayId": "6a7e111a10000000", + "uplinkId": 24022, + "time": "2023-05-22T07:47:05.404859+00:00", + "rssi": -35, + "snr": 11.5, + "channel": 2, + "rfChain": 1, + "location": {}, + "context": "EFwMtA==", + "metadata": { + "region_common_name": "EU868", + "region_config_id": "eu868" + }, + "crcStatus": "CRC_OK" + }], + "txInfo": { + "frequency": 868500000, + "modulation": { + "lora": { + "bandwidth": 125000, + "spreadingFactor": 7, + "codeRate": "CR_4_5" + } + } + } +} \ No newline at end of file diff --git a/VENDORS/Milesight/EM500-CO2/ChirpStack/uplink/result.json b/VENDORS/Milesight/EM500-CO2/ChirpStack/uplink/result.json new file mode 100644 index 00000000..84dcc988 --- /dev/null +++ b/VENDORS/Milesight/EM500-CO2/ChirpStack/uplink/result.json @@ -0,0 +1,29 @@ +{ + "deviceName": "Device name 1000000000000001", + "deviceType": "EM500-C02", + "attributes": { + "eui": "1000000000000001", + "devAddr": "20000001", + "fPort": 85, + "applicationId": "ca739e26-7b67-4f14-b69e-d568c22a5a75", + "applicationName": "Chirpstack application", + "tenantId": "52f14cd4-c6f1-4fbd-8f87-4025e1d49242", + "tenantName": "ChirpStack", + "deviceProfileId": "605d08d4-65f5-4d2c-8a5a-3d2457662f79", + "deviceProfileName": "Chirpstack default device profile", + "frequency": 868500000, + "bandwidth": 125000, + "spreadingFactor": 7, + "codeRate": "CR_4_5" + }, + "telemetry": [{ + "ts": 1684741625404, + "values": { + "battery": 100, + "temperature": 28.1, + "humidity": 57.5, + "co2": 1127, + "pressure": 1008.8 + } + }] +} \ No newline at end of file diff --git a/VENDORS/Milesight/EM500-CO2/LORIOT/uplink/converter.json b/VENDORS/Milesight/EM500-CO2/LORIOT/uplink/converter.json new file mode 100644 index 00000000..593aaa31 --- /dev/null +++ b/VENDORS/Milesight/EM500-CO2/LORIOT/uplink/converter.json @@ -0,0 +1,29 @@ +{ + "name": "Loriot Uplink Decoder for EM500-C02", + "type": "UPLINK", + "debugMode": false, + "debugSettings": { + "failuresEnabled": true, + "allEnabled": false, + "allEnabledUntil": 1733331880270 + }, + "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);\nvar deviceName = data.EUI;\nvar deviceType = \"EM500-C02\";\nvar groupName = null; // If groupName is not null - created device will be added to the entity group with such name.\nvar customerName = null; // If customerName is not null - created devices will be assigned to customer with such name. \n\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// If you want to parse incoming data somehow, you can add your code to this function.\n// input: bytes\n// expected output:\n// {\n// \"attributes\": {\"attributeKey\": \"attributeValue\"},\n// \"telemetry\": {\"telemetryKey\": \"telemetryValue\"}\n// }\n\nfunction decodePayload(input) {\n var output = { attributes: {}, telemetry: []};\n \n var decoded = {};\n var historyDataList = [];\n for (var i = 0; i < input.length - 2 ; ) {\n var channel_id = input[i++] & 0xff;\n var channel_type = input[i++] & 0xff;\n \n // BATTERY\n if (channel_id === 0x01 && channel_type === 0x75) {\n decoded.battery = input[i];\n i += 1;\n }\n // TEMPERATURE\n else if (channel_id === 0x03 && channel_type === 0x67) {\n decoded.temperature = parseBytesToInt(input, i, 2, false) / 10;\n i += 2;\n \n // ℉\n // decoded.temperature = parseBytesToInt(input, i, 2, false) / 10 * 1.8 + 32;\n // i +=2;\n }\n // HUMIDITY\n else if (channel_id === 0x04 && channel_type === 0x68) {\n decoded.humidity = parseBytesToInt(input, i, 1, false) / 2;\n i += 1;\n }\n // CO2\n else if (channel_id === 0x05 && channel_type === 0x7d) {\n decoded.co2 = parseBytesToInt(input, i, 2, false);\n i += 2;\n }\n // PRESSURE\n else if (channel_id === 0x06 && channel_type === 0x73) {\n decoded.pressure = parseBytesToInt(input, i, 2, false) / 10;\n i += 2;\n }\n // TEMPERATURE CHANGE ALARM\n else if (channel_id === 0x83 && channel_type === 0xd7) {\n decoded.temperature = parseBytesToInt(input, i, 2, false) / 10;\n decoded.temperature_change = parseBytesToInt(input, i + 2, 2, false) / 10;\n decoded.temperature_alarm = readTemperatureAlarm(input[i + 4]);\n i += 5;\n }\n // HISTROY\n else if (channel_id === 0x20 && channel_type === 0xce) {\n var historyData = {\n ts: parseBytesToInt(input, i, 4, false) * 1000,\n values: {\n co2: parseBytesToInt(input, i + 4, 2, false),\n pressure: parseBytesToInt(input, i + 6, 1, false) / 10,\n temperature: parseBytesToInt(input, i + 8, 2, false) / 10,\n humidity: parseBytesToInt(input, i + 10, 1, false, false) / 2\n }\n };\n i += 11;\n \n historyDataList.add(historyData);\n } \n }\n \n output.telemetry = [{\n ts: timestamp,\n values: decoded\n }];\n\n // --- Decoding code --- //\n return output;\n}\n\n// --- attributes and telemetry objects ---\nvar telemetry = [];\nvar attributes = {};\n// --- attributes and telemetry objects ---\n\n// --- Timestamp parsing\ntimestamp = data.ts;\n// --- Timestamp parsing\n\n// Message parsing\n// To avoid paths in the decoded objects we passing false value to function as \"pathInKey\" argument.\n// Warning: pathInKey can cause already found fields to be overwritten with the last value found.\n\nvar uplinkDataList = [];\n\n// Passing incoming bytes to decodePayload function, to get custom decoding\nvar customDecoding = decodePayload(hexToBytes(data.data));\n\n// Collecting data to result\nif (customDecoding.?telemetry.size() > 0) {\n if (customDecoding.telemetry instanceof java.util.ArrayList) {\n foreach(telemetryObj: customDecoding.telemetry) {\n if (telemetryObj.ts != null && telemetryObj.values != null) {\n telemetry.add(telemetryObj);\n }\n }\n } else {\n telemetry.putAll(customDecoding.telemetry);\n }\n}\n\nif (customDecoding.?attributes.size() > 0) {\n attributes.putAll(customDecoding.attributes);\n}\n\n// You can add some keys manually to attributes or telemetry\nattributes.eui = data.EUI;\nattributes.fPort = data.port;\nattributes.frequency = data.freq;\n\nvar isIncludeGatewayInfo = metadata[\"includeGatewayInfo\"];\nif(isIncludeGatewayInfo == true) {\n var addDataToTelemetry = {};\n addDataToTelemetry.rssi = data.rssi;\n addDataToTelemetry.seqno = data.seqno;\n addDataToTelemetry.snr = data.snr;\n addDataToTelemetry.ack = data.ack;\n addDataToTelemetry.toa = data.toa;\n addDataToTelemetry.fCnt = data.fcnt;\n \n telemetry = processTelemetryData(telemetry, addDataToTelemetry);\n}\n\nvar deviceInfo = {\n deviceName: deviceName,\n deviceType: deviceType,\n// assetName: assetName,\n// assetType: assetType,\n attributes: attributes,\n telemetry: telemetry, \n};\n\naddAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName);\n\nuplinkDataList.add(deviceInfo);\n\nvar gatewayDeviceNamePrefix = \"Gateway \";\nvar gatewayDeviceType = \"Lora gateway\";\nvar gatewayGroupName = null; // If gatewayGroupName is not null - created device will be added to the entity group with such name.\n\nif (data.cmd == \"gw\") {\n foreach( gatewayInfo : data.gws ) {\n var addGatewayInfo = {};\n\n // You can add some keys manually telemetry\n addGatewayInfo.rssi = gatewayInfo.rssi;\n addGatewayInfo.snr = gatewayInfo.snr;\n // You can add some keys manually telemetry\n \n var gatewayInfoMsg = {\n deviceName: gatewayDeviceNamePrefix + gatewayInfo.gweui,\n deviceType: gatewayDeviceType,\n telemetry: [{\n \"ts\": gatewayInfo.ts,\n \"values\": addGatewayInfo\n }],\n attributes: {\n eui: gatewayInfo.gweui\n }\n };\n addAdditionalInfoForDeviceMsg(gatewayInfoMsg, customerName, gatewayGroupName);\n uplinkDataList.add(gatewayInfoMsg);\n }\n}\n\nreturn uplinkDataList;\n\nfunction addAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName) {\n if (customerName != null) {\n deviceInfo.customerName = customerName;\n }\n if (groupName != null) {\n deviceInfo.groupName = groupName;\n }\n}\n\nfunction processTelemetryData(telemetry, addDataToTelemetry) {\n if (telemetry.size >= 1) {\n telemetry = addDataToTelemetries(telemetry, addDataToTelemetry);\n }\n else {\n telemetry.add(addDataToTelemetry);\n }\n \n return telemetry;\n}\n\nfunction addDataToTelemetries(telemetries, addDataToTelemetry) {\n foreach(telemetry : telemetries) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[\"values\"].keys.contains(element.key)) {\n telemetry[\"values\"][element.key] = element.value;\n }\n } \n }\n \n return telemetries;\n}\n\nfunction readTemperatureAlarm(type) {\n switch (type) {\n case 0:\n return \"threshold alarm\";\n case 1:\n return \"threshold alarm release\";\n case 2:\n return \"mutation alarm\";\n default:\n return \"unkown\";\n }\n}", + "encoder": null, + "tbelEncoder": null, + "updateOnlyKeys": [ + "fPort", + "ack", + "eui", + "frequency", + "dr", + "battery" + ] + }, + "additionalInfo": { + "description": "" + }, + "edgeTemplate": false +} \ No newline at end of file diff --git a/VENDORS/Milesight/EM500-CO2/LORIOT/uplink/metadata.json b/VENDORS/Milesight/EM500-CO2/LORIOT/uplink/metadata.json new file mode 100644 index 00000000..ae2ee743 --- /dev/null +++ b/VENDORS/Milesight/EM500-CO2/LORIOT/uplink/metadata.json @@ -0,0 +1,4 @@ +{ + "integrationName": "Loriot integration", + "includeGatewayInfo": "false" +} \ No newline at end of file diff --git a/VENDORS/Milesight/EM500-CO2/LORIOT/uplink/payload.json b/VENDORS/Milesight/EM500-CO2/LORIOT/uplink/payload.json new file mode 100644 index 00000000..0bbb8113 --- /dev/null +++ b/VENDORS/Milesight/EM500-CO2/LORIOT/uplink/payload.json @@ -0,0 +1,17 @@ +{ + "cmd": "rx", + "seqno": 3040, + "EUI": "1000000000000001", + "ts": 1684478801936, + "fcnt": 2, + "port": 85, + "freq": 867500000, + "rssi": -21, + "snr": 10, + "toa": 206, + "dr": "SF9 BW125 4/5", + "ack": false, + "bat": 94, + "offline": false, + "data": "01756403671901046873057D670406736827" +} \ No newline at end of file diff --git a/VENDORS/Milesight/EM500-CO2/LORIOT/uplink/result.json b/VENDORS/Milesight/EM500-CO2/LORIOT/uplink/result.json new file mode 100644 index 00000000..08bd685b --- /dev/null +++ b/VENDORS/Milesight/EM500-CO2/LORIOT/uplink/result.json @@ -0,0 +1,19 @@ +[{ + "deviceName": "1000000000000001", + "deviceType": "EM500-C02", + "attributes": { + "eui": "1000000000000001", + "fPort": 85, + "frequency": 867500000 + }, + "telemetry": [{ + "ts": 1684478801936, + "values": { + "battery": 100, + "temperature": 28.1, + "humidity": 57.5, + "co2": 1127, + "pressure": 1008.8 + } + }] +}] \ No newline at end of file diff --git a/VENDORS/Milesight/EM500-CO2/ThingsStackCommunity/uplink/converter.json b/VENDORS/Milesight/EM500-CO2/ThingsStackCommunity/uplink/converter.json new file mode 100644 index 00000000..6a810945 --- /dev/null +++ b/VENDORS/Milesight/EM500-CO2/ThingsStackCommunity/uplink/converter.json @@ -0,0 +1,39 @@ +{ + "name": "The Things Stack Community Uplink Decoder for EM500-C02", + "type": "UPLINK", + "debugMode": false, + "debugSettings": { + "failuresEnabled": true, + "allEnabled": false, + "allEnabledUntil": 1733331880270 + }, + "configuration": { + "scriptLang": "TBEL", + "decoder": null, + "tbelDecoder": "var data = decodeToJson(payload);\n\nvar deviceName = data.end_device_ids.device_id;\nvar deviceType = \"EM500-C02\";\nvar groupName = null; // If groupName is not null - created device will be added to the entity group with such name.\nvar customerName = null; // If customerName is not null - created devices will be assigned to customer with such name. \n\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// If you want to parse incoming data somehow, you can add your code to this function.\n// input: bytes\n// expected output:\n// {\n// \"attributes\": {\"attributeKey\": \"attributeValue\"},\n// \"telemetry\": [{\"ts\": 1...1, \"values\": {\"telemetryKey\":\"telemetryValue\"}, {\"ts\": 1...2, \"values\": {\"telemetryKey\":\"telemetryValue\"}}]\n// }\n\nfunction decodeFrmPayload(input) {\n var output = {\n attributes: {}, telemetry: {}\n };\n \n // --- Decoding code --- //\n var decoded = {};\n var historyDataList = [];\n for (var i = 0; i < input.length - 2 ; ) {\n var channel_id = input[i++] & 0xff;\n var channel_type = input[i++] & 0xff;\n \n // BATTERY\n if (channel_id === 0x01 && channel_type === 0x75) {\n decoded.battery = input[i];\n i += 1;\n }\n // TEMPERATURE\n else if (channel_id === 0x03 && channel_type === 0x67) {\n decoded.temperature = parseBytesToInt(input, i, 2, false) / 10;\n i += 2;\n \n // ℉\n // decoded.temperature = parseBytesToInt(input, i, 2, false) / 10 * 1.8 + 32;\n // i +=2;\n }\n // HUMIDITY\n else if (channel_id === 0x04 && channel_type === 0x68) {\n decoded.humidity = parseBytesToInt(input, i, 1, false) / 2;\n i += 1;\n }\n // CO2\n else if (channel_id === 0x05 && channel_type === 0x7d) {\n decoded.co2 = parseBytesToInt(input, i, 2, false);\n i += 2;\n }\n // PRESSURE\n else if (channel_id === 0x06 && channel_type === 0x73) {\n decoded.pressure = parseBytesToInt(input, i, 2, false) / 10;\n i += 2;\n }\n // TEMPERATURE CHANGE ALARM\n else if (channel_id === 0x83 && channel_type === 0xd7) {\n decoded.temperature = parseBytesToInt(input, i, 2, false) / 10;\n decoded.temperature_change = parseBytesToInt(input, i + 2, 2, false) / 10;\n decoded.temperature_alarm = readTemperatureAlarm(input[i + 4]);\n i += 5;\n }\n // HISTROY\n else if (channel_id === 0x20 && channel_type === 0xce) {\n var historyData = {\n ts: parseBytesToInt(input, i, 4, false) * 1000,\n values: {\n co2: parseBytesToInt(input, i + 4, 2, false),\n pressure: parseBytesToInt(input, i + 6, 1, false) / 10,\n temperature: parseBytesToInt(input, i + 8, 2, false) / 10,\n humidity: parseBytesToInt(input, i + 10, 1, false, false) / 2\n }\n };\n i += 11;\n \n historyDataList.add(historyData);\n } \n }\n \n output.telemetry = [{\n ts: timestamp,\n values: decoded\n }];\n \n // --- Decoding code --- //\n return output;\n}\n\n\n// --- attributes and telemetry objects ---\nvar telemetry = [];\nvar attributes = {};\n// --- attributes and telemetry objects ---\n\n// --- Timestamp parsing\nvar dateString = data.uplink_message.received_at;\n// If data is simulated or device doesn't send his own date string - we will use date from upcoming message, set by network server\nif ((data.simulated != null && data.simulated) || dateString == null) {\n dateString = data.received_at;\n}\ntimestamp = parseDateToTimestamp(dateString);\n// --- Timestamp parsing\n\n// Message parsing\n// To avoid paths in the decoded objects we passing false value to function as \"pathInKey\" argument.\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.\n\n// Passing incoming bytes to decodeFrmPayload function, to get custom decoding\nvar customDecoding = {};\nif (data.uplink_message.get(\"frm_payload\") != null) {\n customDecoding = decodeFrmPayload(base64ToBytes(data.uplink_message.frm_payload));\n}\n\n// Collecting data to result\nif (customDecoding.?telemetry.size() > 0) {\n if (customDecoding.telemetry instanceof java.util.ArrayList) {\n foreach(telemetryObj: customDecoding.telemetry) {\n if (telemetryObj.ts != null && telemetryObj.values != null) {\n telemetry.add(telemetryObj);\n }\n }\n } else {\n telemetry.putAll(customDecoding.telemetry);\n }\n}\n\nif (customDecoding.?attributes.size() > 0) {\n attributes.putAll(customDecoding.attributes);\n}\n\n// You can add some keys manually to attributes or telemetry\nvar applicationId = data.end_device_ids.?application_ids.?application_id;\nvar devAddr = data.end_device_ids.?dev_addr;\nvar spreadingFactor = data.uplink_message.?settings.?data_rate.?lora.?spreading_factor;\nvar codeRate = data.uplink_message.?settings.?data_rate.?lora.?coding_rate;\nvar tenantId = data.uplink_message.?network_ids.?tenant_id;\nattributes.eui = data.end_device_ids.dev_eui;\nattributes.fPort = data.uplink_message.f_port;\nattributes.applicationId = applicationId;\nattributes.devAddr = devAddr;\nattributes.spreadingFactor = spreadingFactor;\nattributes.codeRate = codeRate;\nattributes.tenantId = tenantId;\nattributes.device_id = data.end_device_ids.?device_id;\nattributes.join_eui = data.end_device_ids.?join_eui;\nattributes.net_id = data.uplink_message.?network_ids.?net_id;\nattributes.cluster_id = data.uplink_message.?network_ids.?cluster_id;\nattributes.cluster_adress = data.uplink_message.?network_ids.?cluster_address;\nattributes.bandwidth = data.uplink_message.?settings.?data_rate.?lora.?bandwidth;\nattributes.frequency = data.uplink_message.?settings.?frequency;\n\n\nvar gatewayInfo = getGatewayInfo();\nvar addDataToTelemetry = {};\naddDataToTelemetry.snr = gatewayInfo.snr;\naddDataToTelemetry.rssi = gatewayInfo.rssi;\naddDataToTelemetry.channel = gatewayInfo.channel_index;\naddDataToTelemetry.consumed_airtime = data.uplink_message.?consumed_airtime;\naddDataToTelemetry.fCnt = data.uplink_message.?f_cnt;\n\nvar isIncludeGatewayInfo = metadata[\"includeGatewayInfo\"];\nif(isIncludeGatewayInfo == true) {\n telemetry = processTelemetryData(telemetry, addDataToTelemetry);\n}\n\nvar result = {\n deviceName: deviceName,\n deviceType: deviceType,\n// assetName: assetName,\n// assetType: assetType,\n attributes: attributes,\n telemetry: telemetry\n};\n\naddAdditionalInfoForDeviceMsg(result, customerName, groupName);\n\nreturn result;\n\n\nfunction addAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName) {\n if (customerName != null) {\n deviceInfo.customerName = customerName;\n }\n if (groupName != null) {\n deviceInfo.groupName = groupName;\n }\n}\n\nfunction parseDateToTimestamp(dateString) {\n var date = new Date(dateString);\n var timestamp = date.getTime();\n \n // If we cannot parse timestamp - we will use the current timestamp\n if (timestamp == -1) {\n timestamp = Date.now();\n }\n \n return timestamp;\n}\n\nfunction getGatewayInfo() {\n var gatewayList = data.uplink_message.?rx_metadata;\n var maxRssi = Integer.MIN_VALUE;\n var gatewayInfo = {};\n \n foreach (gateway : gatewayList) {\n if(gateway.rssi > maxRssi) {\n maxRssi = gateway.rssi;\n gatewayInfo = gateway;\n }\n }\n \n return gatewayInfo;\n}\n\nfunction processTelemetryData(telemetry, addDataToTelemetry) {\n if (telemetry.size >= 1) {\n telemetry = addDataToTelemetries(telemetry, addDataToTelemetry);\n }\n else {\n telemetry.add(addDataToTelemetry);\n }\n \n return telemetry;\n}\n\nfunction addDataToTelemetries(telemetries, addDataToTelemetry) {\n foreach(telemetry : telemetries) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[\"values\"].keys.contains(element.key)) {\n telemetry[\"values\"][element.key] = element.value;\n }\n } \n }\n \n return telemetries;\n}\n\nfunction readTemperatureAlarm(type) {\n switch (type) {\n case 0:\n return \"threshold alarm\";\n case 1:\n return \"threshold alarm release\";\n case 2:\n return \"mutation alarm\";\n default:\n return \"unkown\";\n }\n}", + "encoder": null, + "tbelEncoder": null, + "updateOnlyKeys": [ + "fPort", + "bandwidth", + "frequency", + "net_id", + "cluster_id", + "cluster_address", + "device_id", + "join_eui", + "battery", + "eui", + "channel", + "applicationId", + "devAddr", + "spreadingFactor", + "codeRate", + "tenantId" + ] + }, + "additionalInfo": { + "description": "" + }, + "edgeTemplate": false +} \ No newline at end of file diff --git a/VENDORS/Milesight/EM500-CO2/ThingsStackCommunity/uplink/metadata.json b/VENDORS/Milesight/EM500-CO2/ThingsStackCommunity/uplink/metadata.json new file mode 100644 index 00000000..0d75c374 --- /dev/null +++ b/VENDORS/Milesight/EM500-CO2/ThingsStackCommunity/uplink/metadata.json @@ -0,0 +1,4 @@ +{ + "integrationName": "The Things Stack Community integration", + "includeGatewayInfo": "false" +} \ No newline at end of file diff --git a/VENDORS/Milesight/EM500-CO2/ThingsStackCommunity/uplink/payload.json b/VENDORS/Milesight/EM500-CO2/ThingsStackCommunity/uplink/payload.json new file mode 100644 index 00000000..db5532f6 --- /dev/null +++ b/VENDORS/Milesight/EM500-CO2/ThingsStackCommunity/uplink/payload.json @@ -0,0 +1,54 @@ +{ + "end_device_ids": { + "device_id": "eui-1000000000000001", + "application_ids": { + "application_id": "application-tts-name" + }, + "dev_eui": "1000000000000001", + "join_eui": "2000000000000001", + "dev_addr": "20000001" + }, + "correlation_ids": ["as:up:01H0S7ZJQ9MQPMVY49FT3SE07M", "gs:conn:01H03BQZ9342X3Y86DJ2P704E5", "gs:up:host:01H03BQZ99EGAM52KK1300GFKN", "gs:uplink:01H0S7ZJGS6D9TJSKJN8XNTMAV", "ns:uplink:01H0S7ZJGS9KKD4HTTPKFEMWCV", "rpc:/ttn.lorawan.v3.GsNs/HandleUplink:01H0S7ZJGSF3M38ZRZVTM38DEC", "rpc:/ttn.lorawan.v3.NsAs/HandleUplink:01H0S7ZJQ8R2EH5AA269AKM8DX"], + "received_at": "2023-05-19T05:33:35.848446463Z", + "uplink_message": { + "session_key_id": "AYfqmb0pc/1uRZv9xUydgQ==", + "f_port": 85, + "f_cnt": 10335, + "frm_payload": "AXVkA2cZAQRocwV9ZwQGc2gn", + "rx_metadata": [{ + "gateway_ids": { + "gateway_id": "eui-6a7e111a10000000", + "eui": "6A7E111A10000000" + }, + "time": "2023-05-19T05:33:35.608982Z", + "timestamp": 3893546133, + "rssi": -35, + "channel_rssi": -35, + "snr": 13.2, + "frequency_offset": "69", + "uplink_token": "CiIKIAoUZXVpLTZhN2UxMTFhMTAwMDAwMDASCCThJP/+9k6eEJWZy8AOGgwIr5ScowYQvNbUsQIgiMy8y6jwpwE=", + "channel_index": 3, + "received_at": "2023-05-19T05:33:35.607383681Z" + }], + "settings": { + "data_rate": { + "lora": { + "bandwidth": 125000, + "spreading_factor": 7, + "coding_rate": "4/5" + } + }, + "frequency": "867100000", + "timestamp": 3893546133, + "time": "2023-05-19T05:33:35.608982Z" + }, + "received_at": "2023-05-19T05:33:35.641841782Z", + "consumed_airtime": "0.056576s", + "network_ids": { + "net_id": "000013", + "tenant_id": "ttn", + "cluster_id": "eu1", + "cluster_address": "eu1.cloud.thethings.network" + } + } +} \ No newline at end of file diff --git a/VENDORS/Milesight/EM500-CO2/ThingsStackCommunity/uplink/result.json b/VENDORS/Milesight/EM500-CO2/ThingsStackCommunity/uplink/result.json new file mode 100644 index 00000000..ac2cd036 --- /dev/null +++ b/VENDORS/Milesight/EM500-CO2/ThingsStackCommunity/uplink/result.json @@ -0,0 +1,30 @@ +{ + "deviceName": "eui-1000000000000001", + "deviceType": "EM500-C02", + "attributes": { + "eui": "1000000000000001", + "fPort": 85, + "applicationId": "application-tts-name", + "devAddr": "20000001", + "spreadingFactor": 7, + "codeRate": "4/5", + "tenantId": "ttn", + "device_id": "eui-1000000000000001", + "join_eui": "2000000000000001", + "net_id": "000013", + "cluster_id": "eu1", + "cluster_adress": "eu1.cloud.thethings.network", + "bandwidth": 125000, + "frequency": "867100000" + }, + "telemetry": [{ + "ts": 1684474415641, + "values": { + "battery": 100, + "temperature": 28.1, + "humidity": 57.5, + "co2": 1127, + "pressure": 1008.8 + } + }] +} \ No newline at end of file diff --git a/VENDORS/Milesight/EM500-CO2/ThingsStackIndustries/uplink/converter.json b/VENDORS/Milesight/EM500-CO2/ThingsStackIndustries/uplink/converter.json new file mode 100644 index 00000000..966af784 --- /dev/null +++ b/VENDORS/Milesight/EM500-CO2/ThingsStackIndustries/uplink/converter.json @@ -0,0 +1,40 @@ +{ + "name": "The Things Stack Industries Uplink Decoder for EM500-C02", + "type": "UPLINK", + "debugMode": false, + "debugSettings": { + "failuresEnabled": true, + "allEnabled": false, + "allEnabledUntil": 1733331880270 + }, + "configuration": { + "scriptLang": "TBEL", + "decoder": null, + "tbelDecoder": "var data = decodeToJson(payload);\n\nvar deviceName = data.end_device_ids.device_id;\nvar deviceType = \"EM500-C02\";\nvar groupName = null; // If groupName is not null - created device will be added to the entity group with such name.\nvar customerName = null; // If customerName is not null - created devices will be assigned to customer with such name. \n\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// If you want to parse incoming data somehow, you can add your code to this function.\n// input: bytes\n// expected output:\n// {\n// \"attributes\": {\"attributeKey\": \"attributeValue\"},\n// \"telemetry\": [{\"ts\": 1...1, \"values\": {\"telemetryKey\":\"telemetryValue\"}, {\"ts\": 1...2, \"values\": {\"telemetryKey\":\"telemetryValue\"}}]\n// }\n\nfunction decodeFrmPayload(input) {\n var output = { attributes: {}, telemetry: []};\n \n // --- Decoding code --- //\n var decoded = {};\n var historyDataList = [];\n for (var i = 0; i < input.length - 2 ; ) {\n var channel_id = input[i++] & 0xff;\n var channel_type = input[i++] & 0xff;\n \n // BATTERY\n if (channel_id === 0x01 && channel_type === 0x75) {\n decoded.battery = input[i];\n i += 1;\n }\n // TEMPERATURE\n else if (channel_id === 0x03 && channel_type === 0x67) {\n decoded.temperature = parseBytesToInt(input, i, 2, false) / 10;\n i += 2;\n \n // ℉\n // decoded.temperature = parseBytesToInt(input, i, 2, false) / 10 * 1.8 + 32;\n // i +=2;\n }\n // HUMIDITY\n else if (channel_id === 0x04 && channel_type === 0x68) {\n decoded.humidity = parseBytesToInt(input, i, 1, false) / 2;\n i += 1;\n }\n // CO2\n else if (channel_id === 0x05 && channel_type === 0x7d) {\n decoded.co2 = parseBytesToInt(input, i, 2, false);\n i += 2;\n }\n // PRESSURE\n else if (channel_id === 0x06 && channel_type === 0x73) {\n decoded.pressure = parseBytesToInt(input, i, 2, false) / 10;\n i += 2;\n }\n // TEMPERATURE CHANGE ALARM\n else if (channel_id === 0x83 && channel_type === 0xd7) {\n decoded.temperature = parseBytesToInt(input, i, 2, false) / 10;\n decoded.temperature_change = parseBytesToInt(input, i + 2, 2, false) / 10;\n decoded.temperature_alarm = readTemperatureAlarm(input[i + 4]);\n i += 5;\n }\n // HISTROY\n else if (channel_id === 0x20 && channel_type === 0xce) {\n var historyData = {\n ts: parseBytesToInt(input, i, 4, false) * 1000,\n values: {\n co2: parseBytesToInt(input, i + 4, 2, false),\n pressure: parseBytesToInt(input, i + 6, 1, false) / 10,\n temperature: parseBytesToInt(input, i + 8, 2, false) / 10,\n humidity: parseBytesToInt(input, i + 10, 1, false, false) / 2\n }\n };\n i += 11;\n \n historyDataList.add(historyData);\n } \n }\n \n output.telemetry = [{\n ts: timestamp,\n values: decoded\n }];\n\n // --- Decoding code --- //\n return output;\n}\n\n// --- attributes and telemetry objects ---\nvar telemetry = [];\nvar attributes = {};\n// --- attributes and telemetry objects ---\n\n// --- Timestamp parsing\nvar dateString = data.uplink_message.received_at;\n\nif ((data.simulated != null && data.simulated) || dateString == null) {\n dateString = data.received_at;\n}\n\ntimestamp = parseDateToTimestamp(dateString);\n// --- Timestamp parsing\n\n// Message parsing\n// To avoid paths in the decoded objects we passing false value to function as \"pathInKey\" argument.\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.\n\n// Passing incoming bytes to decodeFrmPayload function, to get custom decoding\nvar customDecoding = {};\nif (data.uplink_message.get(\"frm_payload\") != null) {\n customDecoding = decodeFrmPayload(base64ToBytes(data.uplink_message.frm_payload));\n}\n\n// Collecting data to result\nif (customDecoding.?telemetry.size() > 0) {\n if (customDecoding.telemetry instanceof java.util.ArrayList) {\n foreach(telemetryObj: customDecoding.telemetry) {\n if (telemetryObj.ts != null && telemetryObj.values != null) {\n telemetry.add(telemetryObj);\n }\n }\n } else {\n telemetry.putAll(customDecoding.telemetry);\n }\n}\n\nif (customDecoding.?attributes.size() > 0) {\n attributes.putAll(customDecoding.attributes);\n}\n\n// You can add some keys manually to attributes or telemetry\nvar applicationId = data.end_device_ids.?application_ids.?application_id;\nvar devAddr = data.end_device_ids.?dev_addr;\nvar spreadingFactor = data.uplink_message.?settings.?data_rate.?lora.?spreading_factor;\nvar codeRate = data.uplink_message.?settings.?data_rate.?lora.?coding_rate;\nvar tenantId = data.uplink_message.?network_ids.?tenant_id;\nattributes.eui = data.end_device_ids.dev_eui;\nattributes.fPort = data.uplink_message.f_port;\nattributes.applicationId = applicationId;\nattributes.devAddr = devAddr;\nattributes.spreadingFactor = spreadingFactor;\nattributes.codeRate = codeRate;\nattributes.tenantId = tenantId;\nattributes.device_id = data.end_device_ids.?device_id;\nattributes.join_eui = data.end_device_ids.?join_eui;\nattributes.net_id = data.uplink_message.?network_ids.?net_id;\nattributes.cluster_id = data.uplink_message.?network_ids.?cluster_id;\nattributes.cluster_address = data.uplink_message.?network_ids.?cluster_address;\nattributes.bandwidth = data.uplink_message.?settings.?data_rate.?lora.?bandwidth;\nattributes.frequency = data.uplink_message.?settings.?frequency;\n\nvar isIncludeGatewayInfo = metadata[\"includeGatewayInfo\"];\nif(isIncludeGatewayInfo == true) {\n var gatewayInfo = getGatewayInfo();\n var addDataToTelemetry = {};\n addDataToTelemetry.snr = gatewayInfo.snr;\n addDataToTelemetry.rssi = gatewayInfo.rssi;\n addDataToTelemetry.channel = gatewayInfo.channel_index;\n addDataToTelemetry.consumed_airtime = data.uplink_message.?consumed_airtime;\n addDataToTelemetry.fCnt = data.uplink_message.?f_cnt;\n\n telemetry = processTelemetryData(telemetry, addDataToTelemetry);\n}\n\nvar result = {\n deviceName: deviceName,\n deviceType: deviceType,\n // assetName: assetName,\n // assetType: assetType,\n attributes: attributes,\n telemetry: telemetry\n};\n\naddAdditionalInfoForDeviceMsg(result, customerName, groupName);\n\nreturn result;\n\nfunction addAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName) {\n if (customerName != null) {\n deviceInfo.customerName = customerName;\n }\n if (groupName != null) {\n deviceInfo.groupName = groupName;\n }\n}\n\nfunction parseDateToTimestamp(dateString) {\n var date = new Date(dateString);\n var timestamp = date.getTime();\n \n // If we cannot parse timestamp - we will use the current timestamp\n if (timestamp == -1) {\n timestamp = Date.now();\n }\n \n return timestamp;\n}\n\nfunction getGatewayInfo() {\n var gatewayList = data.uplink_message.?rx_metadata;\n var maxRssi = Integer. MIN_VALUE;\n var gatewayInfo = {};\n \n foreach (gateway : gatewayList) {\n if(gateway.rssi > maxRssi) {\n maxRssi = gateway.rssi;\n gatewayInfo = gateway;\n }\n }\n \n return gatewayInfo;\n}\n\nfunction processTelemetryData(telemetry, addDataToTelemetry) {\n if (telemetry.size >= 1) {\n telemetry = addDataToTelemetries(telemetry, addDataToTelemetry);\n }\n else {\n telemetry.add(addDataToTelemetry);\n }\n \n return telemetry;\n}\n\nfunction addDataToTelemetries(telemetries, addDataToTelemetry) {\n foreach(telemetry : telemetries) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[\"values\"].keys.contains(element.key)) {\n telemetry[\"values\"][element.key] = element.value;\n }\n } \n }\n \n return telemetries;\n}\n\nfunction readTemperatureAlarm(type) {\n switch (type) {\n case 0:\n return \"threshold alarm\";\n case 1:\n return \"threshold alarm release\";\n case 2:\n return \"mutation alarm\";\n default:\n return \"unkown\";\n }\n}", + "encoder": null, + "tbelEncoder": null, + "updateOnlyKeys": [ + "fPort", + "bandwidth", + "frequency", + "net_id", + "cluster_id", + "cluster_address", + "tenant_address", + "device_id", + "join_eui", + "eui", + "channel", + "devAddr", + "spreadingFactor", + "codeRate", + "tenantId", + "applicationId", + "battery" + ] + }, + "additionalInfo": { + "description": "" + }, + "edgeTemplate": false +} \ No newline at end of file diff --git a/VENDORS/Milesight/EM500-CO2/ThingsStackIndustries/uplink/metadata.json b/VENDORS/Milesight/EM500-CO2/ThingsStackIndustries/uplink/metadata.json new file mode 100644 index 00000000..904c0fa0 --- /dev/null +++ b/VENDORS/Milesight/EM500-CO2/ThingsStackIndustries/uplink/metadata.json @@ -0,0 +1,4 @@ +{ + "integrationName": "The Things Stack Industries integration new", + "includeGatewayInfo": "false" +} \ No newline at end of file diff --git a/VENDORS/Milesight/EM500-CO2/ThingsStackIndustries/uplink/payload.json b/VENDORS/Milesight/EM500-CO2/ThingsStackIndustries/uplink/payload.json new file mode 100644 index 00000000..798b317e --- /dev/null +++ b/VENDORS/Milesight/EM500-CO2/ThingsStackIndustries/uplink/payload.json @@ -0,0 +1,77 @@ +{ + "end_device_ids": { + "device_id": "eui-1000000000000001", + "application_ids": { + "application_id": "application-tti-name" + }, + "dev_eui": "1000000000000001", + "join_eui": "2000000000000001", + "dev_addr": "20000001" + }, + "correlation_ids": ["as:up:01H0PZDGB1NW6NAPD815NGHPF6", "gs:conn:01H0FJRSXSYT7VKNYXJ89F95XT", "gs:up:host:01H0FJRSY3MZMGPPFBQ4FZV4T8", "gs:uplink:01H0PZDG4HHGFRTXRTXD4PFTH7", "ns:uplink:01H0PZDG4JZ3BM0K6J89EQK1J7", "rpc:/ttn.lorawan.v3.GsNs/HandleUplink:01H0PZDG4J02F85RYFPCNSNXCR", "rpc:/ttn.lorawan.v3.NsAs/HandleUplink:01H0PZDGB081PMP806BJHNHX1A"], + "received_at": "2023-05-18T08:25:26.112483370Z", + "uplink_message": { + "session_key_id": "AYfg8rhha5n+FWx0ZaAprA==", + "f_port": 85, + "f_cnt": 5017, + "frm_payload": "AXVkA2cZAQRocwV9ZwQGc2gn", + "rx_metadata": [{ + "gateway_ids": { + "gateway_id": "eui-6A7E111A10000000", + "eui": "6A7E111A10000000" + }, + "time": "2023-05-18T08:25:25.885310Z", + "timestamp": 818273765, + "rssi": -24, + "channel_rssi": -24, + "snr": 12, + "frequency_offset": "671", + "uplink_token": "CiIKIAoUZXVpLTZBN0UxMTFBMTAwMDAwMDASCCThJP/+9k6eEOW7l4YDGgwI9cGXowYQ5KPhrwMgiI2rp+jpOA=", + "channel_index": 2, + "received_at": "2023-05-18T08:25:25.869324983Z" + }, { + "gateway_ids": { + "gateway_id": "packetbroker" + }, + "packet_broker": { + "message_id": "01H0PZDG4MF9AYSMNY44MAVTDH", + "forwarder_net_id": "000013", + "forwarder_tenant_id": "ttn", + "forwarder_cluster_id": "eu1.cloud.thethings.network", + "forwarder_gateway_eui": "6A7E111A10000000", + "forwarder_gateway_id": "eui-6a7e111a10000000", + "home_network_net_id": "000013", + "home_network_tenant_id": "tenant", + "home_network_cluster_id": "eu1.cloud.thethings.industries" + }, + "time": "2023-05-18T08:25:25.885310Z", + "rssi": -24, + "channel_rssi": -24, + "snr": 12, + "frequency_offset": "671", + "uplink_token": "eyJnIjoiWlhsS2FHSkhZMmxQYVVwQ1RWUkpORkl3VGs1VE1XTnBURU5LYkdKdFRXbFBhVXBDVFZSSk5GSXdUazVKYVhkcFlWaFphVTlwU201a01uaGhWVlJvZDFSWFVuRmlSM1JtVFcxT2RVbHBkMmxrUjBadVNXcHZhV05ZY0RKT1IyeExaREpSZVZwR1pIUmpNRXBLVlVoR2RFNVZkR3BWVTBvNUxua3paVVJTWVRaM1lXOU1kbTQwVm5sdmIyWmlPWGN1ZUhCZmVrcElaa3hIWlZadGRVUlFVeTVuYlRaVlZXRXdkakpHV0VKMGJUUjZaMjVXUkVoeGVHRjRaMlJKTlVkS1VsbERhemc1VDNCbk5rVk1iM1JDUkVZM1VWbHdZbEJDTkdOblNqWjBlbkphYUV4MFRVMHhZMVZFTTFac01XdExURUo0YURaMFExTnhhMVJsWWw4eE5FdHlVVXcyZUhsRWFFbEhlakJITXpoTE0xaFdlRzR5VUVjMk4wNUViME5WTkhoTmRrazFZVk5oWkUwd2FXVnFjR294VGtoMFduZHlZMDFxVlVGNmRsbERUazlNY2s5eFdVeFpWMk5XTG1WVFFYVkpNVkptT1U5NWRqUTNhSEoxTUZoalYxRT0iLCJhIjp7ImZuaWQiOiIwMDAwMTMiLCJmdGlkIjoidHRuIiwiZmNpZCI6ImV1MS5jbG91ZC50aGV0aGluZ3MubmV0d29yayJ9fQ==", + "received_at": "2023-05-18T08:25:25.906038642Z" + }], + "settings": { + "data_rate": { + "lora": { + "bandwidth": 125000, + "spreading_factor": 7, + "coding_rate": "4/5" + } + }, + "frequency": "868500000", + "timestamp": 818273765, + "time": "2023-05-18T08:25:25.885310Z" + }, + "received_at": "2023-05-18T08:25:25.906399073Z", + "consumed_airtime": "0.097536s", + "network_ids": { + "net_id": "000013", + "tenant_id": "tenant", + "cluster_id": "eu1", + "cluster_address": "eu1.cloud.thethings.industries", + "tenant_address": "tenant.eu1.cloud.thethings.industries" + } + } +} \ No newline at end of file diff --git a/VENDORS/Milesight/EM500-CO2/ThingsStackIndustries/uplink/result.json b/VENDORS/Milesight/EM500-CO2/ThingsStackIndustries/uplink/result.json new file mode 100644 index 00000000..2c54a417 --- /dev/null +++ b/VENDORS/Milesight/EM500-CO2/ThingsStackIndustries/uplink/result.json @@ -0,0 +1,30 @@ +{ + "deviceName": "eui-1000000000000001", + "deviceType": "EM500-C02", + "attributes": { + "eui": "1000000000000001", + "fPort": 85, + "applicationId": "application-tti-name", + "devAddr": "20000001", + "spreadingFactor": 7, + "codeRate": "4/5", + "tenantId": "tenant", + "device_id": "eui-1000000000000001", + "join_eui": "2000000000000001", + "net_id": "000013", + "cluster_id": "eu1", + "cluster_address": "eu1.cloud.thethings.industries", + "bandwidth": 125000, + "frequency": "868500000" + }, + "telemetry": [{ + "ts": 1684398325906, + "values": { + "battery": 100, + "temperature": 28.1, + "humidity": 57.5, + "co2": 1127, + "pressure": 1008.8 + } + }] +} \ No newline at end of file diff --git a/VENDORS/Milesight/EM500-CO2/guide.md b/VENDORS/Milesight/EM500-CO2/guide.md new file mode 100644 index 00000000..e84fdf21 --- /dev/null +++ b/VENDORS/Milesight/EM500-CO2/guide.md @@ -0,0 +1,15 @@ +# CO2 Sensor - Milesight IoT + +The payload decoder function is applicable to EM500-CO2. + +## Payload Definition + +| CHANNEL | ID | TYPE | LENGTH | DESCRIPTION | +| :---------------: | :--: | :--: | :----: | ----------------------------------------------------------------------------------------- | +| Battery | 0x01 | 0x75 | 1 | battery(1B)
battery, unit: % | +| Temperature | 0x03 | 0x67 | 2 | temperature(2B)
temperature,unit: ℃ | +| Humidity | 0x04 | 0x68 | 1 | humidity(1B)
humidity, unit: %RH | +| CO2 | 0x05 | 0x7D | 2 | co2(2B)
co2, unit: ppm | +| Pressure | 0x06 | 0x73 | 2 | pressure(2B)
pressure, unit: hPa | +| Temperature Alarm | 0x83 | 0xD7 | 5 | temperature(2B) + temperature_change(2B) + temperature_alarm(1B)
temperature, unit: ℃ | +| Historical Data | 0x20 | 0XCE | 11 | timestamp(4B) + co2(2B) + pressure(2B) + temperature(2B) + humidity(1B) | \ No newline at end of file diff --git a/VENDORS/Milesight/EM500-CO2/info.json b/VENDORS/Milesight/EM500-CO2/info.json new file mode 100644 index 00000000..9e9bbf75 --- /dev/null +++ b/VENDORS/Milesight/EM500-CO2/info.json @@ -0,0 +1,5 @@ +{ + "url": "https://www.milesight.com/iot/product/lorawan-sensor/em500-co2", + "label": "EM500-C02: LoRaWAN® Carbon Dioxide sensor", + "description": "EM500-CO2 is designed for measuring CO2, temperature, humidity and barometric pressure in harsh environments and transmitting data using LoRaWAN® technology." +} \ No newline at end of file diff --git a/VENDORS/Milesight/EM500-CO2/photo.png b/VENDORS/Milesight/EM500-CO2/photo.png new file mode 100644 index 0000000000000000000000000000000000000000..74ff895322f2f097c3263ce64c473af703536dba GIT binary patch literal 115101 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 z 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%0DfuPdFolS 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
@q07>x(%s!?43A%ng8-^ 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 Date: Tue, 17 Dec 2024 12:14:10 +0100 Subject: [PATCH 07/33] Fix Decentlab DL-SHT35-001 type --- VENDORS/Decentlab/DL-SHT35-001/ChirpStack/uplink/converter.json | 2 +- VENDORS/Decentlab/DL-SHT35-001/ChirpStack/uplink/result.json | 2 +- VENDORS/Decentlab/DL-SHT35-001/ChirpStack/uplink/result_01.json | 2 +- VENDORS/Decentlab/DL-SHT35-001/ChirpStack/uplink/result_02.json | 2 +- VENDORS/Decentlab/DL-SHT35-001/ChirpStack/uplink/result_03.json | 2 +- VENDORS/Decentlab/DL-SHT35-001/LORIOT/uplink/converter.json | 2 +- VENDORS/Decentlab/DL-SHT35-001/LORIOT/uplink/result.json | 2 +- VENDORS/Decentlab/DL-SHT35-001/LORIOT/uplink/result_01.json | 2 +- VENDORS/Decentlab/DL-SHT35-001/ThingPark/uplink/converter.json | 2 +- VENDORS/Decentlab/DL-SHT35-001/ThingPark/uplink/result.json | 2 +- VENDORS/Decentlab/DL-SHT35-001/ThingPark/uplink/result_01.json | 2 +- .../DL-SHT35-001/ThingParkEnterprise/uplink/converter.json | 2 +- .../DL-SHT35-001/ThingParkEnterprise/uplink/result.json | 2 +- .../DL-SHT35-001/ThingParkEnterprise/uplink/result_01.json | 2 +- .../DL-SHT35-001/ThingsStackCommunity/uplink/converter.json | 2 +- .../DL-SHT35-001/ThingsStackCommunity/uplink/result.json | 2 +- .../DL-SHT35-001/ThingsStackCommunity/uplink/result_01.json | 2 +- .../DL-SHT35-001/ThingsStackIndustries/uplink/converter.json | 2 +- .../DL-SHT35-001/ThingsStackIndustries/uplink/result.json | 2 +- .../DL-SHT35-001/ThingsStackIndustries/uplink/result_01.json | 2 +- 20 files changed, 20 insertions(+), 20 deletions(-) diff --git a/VENDORS/Decentlab/DL-SHT35-001/ChirpStack/uplink/converter.json b/VENDORS/Decentlab/DL-SHT35-001/ChirpStack/uplink/converter.json index f4d2c4ed..b5df8e83 100644 --- a/VENDORS/Decentlab/DL-SHT35-001/ChirpStack/uplink/converter.json +++ b/VENDORS/Decentlab/DL-SHT35-001/ChirpStack/uplink/converter.json @@ -14,6 +14,6 @@ "lora_dev_eui", "lora_snr" ], - "decoder": "// WARNING: This script is designed to work with a remote JS executor. Compatibility with a local JS evaluator is not guaranteed and may require rewriting.\n\nconst message = decodeToJson(payload);\nconst values = Object.assign(\n decodeDevicePayload(base64ToBytes(message.data)),\n extractNetworkTelemetry(message)\n);\n\nreturn {\n deviceName: String(values.device_id),\n deviceType: 'DL-SHT35',\n attributes: {\n lora_dev_eui: values.lora_dev_eui,\n protocol_version: values.protocol_version,\n },\n telemetry: [{\n ts: message.time,\n values: keepTelemetry(values)\n }]\n};\n\nfunction decodeDevicePayload(payload) {\n /* https://www.decentlab.com/products/air-temperature-and-humidity-sensor-with-radiation-shield-for-lorawan */\n const decentlab_decoder = {\n PROTOCOL_VERSION: 2,\n SENSORS: [\n {length: 2,\n values: [{name: 'air_temperature',\n displayName: 'Air temperature',\n convert: function (x) { return 175 * x[0] / 65535 - 45; },\n unit: '°C'},\n {name: 'air_humidity',\n displayName: 'Air humidity',\n convert: function (x) { return 100 * x[1] / 65535; },\n unit: '%'}]},\n {length: 1,\n values: [{name: 'battery_voltage',\n displayName: 'Battery voltage',\n convert: function (x) { return x[0] / 1000; },\n unit: 'V'}]}\n ],\n read_int: function (bytes, pos) {\n return (bytes[pos] << 8) + bytes[pos + 1];\n },\n decode: function (msg) {\n var bytes = msg;\n var i, j;\n if (typeof msg === 'string') {\n bytes = [];\n for (i = 0; i < msg.length; i += 2) {\n bytes.push(parseInt(msg.substring(i, i + 2), 16));\n }\n }\n var version = bytes[0];\n if (version != this.PROTOCOL_VERSION) {\n return {error: \"protocol version \" + version + \" doesn't match v2\"};\n }\n var deviceId = this.read_int(bytes, 1);\n var flags = this.read_int(bytes, 3);\n var result = {'protocol_version': version, 'device_id': deviceId};\n // decode payload\n var pos = 5;\n for (i = 0; i < this.SENSORS.length; i++, flags >>= 1) {\n if ((flags & 1) !== 1)\n continue;\n var sensor = this.SENSORS[i];\n var x = [];\n // convert data to 16-bit integer array\n for (j = 0; j < sensor.length; j++) {\n x.push(this.read_int(bytes, pos));\n pos += 2;\n }\n // decode sensor values\n for (j = 0; j < sensor.values.length; j++) {\n var value = sensor.values[j];\n if ('convert' in value) {\n result[value.name] = {displayName: value.displayName,\n value: value.convert.bind(this)(x)};\n if ('unit' in value)\n result[value.name]['unit'] = value.unit;\n }\n }\n }\n return result;\n }\n };\n\n const decoded = decentlab_decoder.decode(payload);\n const result = {};\n for (var k in decoded) {\n if (typeof decoded[k] === \"object\") {\n result[k] = decoded[k].value;\n } else if (typeof decoded[k] === \"number\") {\n result[k] = decoded[k];\n }\n }\n return result;\n}\n\nfunction extractNetworkTelemetry(payload) {\n const result = {\n lora_frame_counter: message.fCnt,\n lora_frame_port: message.fPort,\n lora_frequency: message.txInfo.frequency,\n lora_spreading_factor:\n message?.txInfo?.modulation?.lora?.spreadingFactor ||\n message.txInfo.loRaModulationInfo.spreadingFactor,\n lora_dev_eui: (\n message?.deviceInfo?.devEui ||\n base64ToBytes(message.devEUI).reduce(\n (a, x) => a + (\"0\" + x.toString(16)).slice(-2),\n \"\",\n )\n ).toUpperCase(),\n };\n const gwi = message.rxInfo\n .map((x) => ({ lora_rssi: x.rssi, lora_snr: x.snr || x.loRaSNR }))\n .reduce((a, x) => (x.lora_rssi > a.lora_rssi ? x : a), {\n lora_rssi: -Number.MAX_VALUE,\n });\n return Object.assign(result, gwi);\n}\n\n// Helper functions\n\nfunction decodeToJson(payload) {\n const s = String.fromCharCode.apply(String, payload);\n return JSON.parse(s);\n}\n\nfunction parseDateToTimestamp(dateString) {\n var timestamp = -1;\n if (dateString != null) {\n timestamp = new Date(dateString).getTime();\n if (timestamp == -1) {\n var secondsSeparatorIndex = dateString.lastIndexOf('.') + 1;\n var millisecondsEndIndex = dateString.lastIndexOf('+');\n if (millisecondsEndIndex == -1) {\n millisecondsEndIndex = dateString.lastIndexOf('Z');\n }\n if (millisecondsEndIndex == -1) {\n millisecondsEndIndex = dateString.lastIndexOf('-');\n }\n if (millisecondsEndIndex == -1) {\n if (dateString.length >= secondsSeparatorIndex + 3) {\n dateString = dateString.substring(0, secondsSeparatorIndex + 3);\n }\n } else {\n dateString = dateString.substring(0, secondsSeparatorIndex + 3) +\n dateString.substring(millisecondsEndIndex, dateString.length);\n }\n timestamp = new Date(dateString).getTime();\n }\n }\n // If we cannot parse timestamp - we will use the current timestamp\n if (timestamp == -1) {\n timestamp = Date.now();\n }\n\n return timestamp;\n}\n\nfunction base64ToBytes(base64String) {\n if (typeof base64String === 'string') {\n return Uint8Array.from(atob(base64String), c => c.charCodeAt(0));\n }\n return [];\n}\n\nfunction keepTelemetry(telemetry) {\n const unwanted = ['protocol_version', 'device_id', 'lora_dev_eui'];\n return Object.fromEntries(\n Object.entries(telemetry).filter(\n (x) => !unwanted.includes(x[0])\n )\n );\n}" + "decoder": "// WARNING: This script is designed to work with a remote JS executor. Compatibility with a local JS evaluator is not guaranteed and may require rewriting.\n\nconst message = decodeToJson(payload);\nconst values = Object.assign(\n decodeDevicePayload(base64ToBytes(message.data)),\n extractNetworkTelemetry(message)\n);\n\nreturn {\n deviceName: String(values.device_id),\n deviceType: 'DL-SHT35-001',\n attributes: {\n lora_dev_eui: values.lora_dev_eui,\n protocol_version: values.protocol_version,\n },\n telemetry: [{\n ts: message.time,\n values: keepTelemetry(values)\n }]\n};\n\nfunction decodeDevicePayload(payload) {\n /* https://www.decentlab.com/products/air-temperature-and-humidity-sensor-with-radiation-shield-for-lorawan */\n const decentlab_decoder = {\n PROTOCOL_VERSION: 2,\n SENSORS: [\n {length: 2,\n values: [{name: 'air_temperature',\n displayName: 'Air temperature',\n convert: function (x) { return 175 * x[0] / 65535 - 45; },\n unit: '°C'},\n {name: 'air_humidity',\n displayName: 'Air humidity',\n convert: function (x) { return 100 * x[1] / 65535; },\n unit: '%'}]},\n {length: 1,\n values: [{name: 'battery_voltage',\n displayName: 'Battery voltage',\n convert: function (x) { return x[0] / 1000; },\n unit: 'V'}]}\n ],\n read_int: function (bytes, pos) {\n return (bytes[pos] << 8) + bytes[pos + 1];\n },\n decode: function (msg) {\n var bytes = msg;\n var i, j;\n if (typeof msg === 'string') {\n bytes = [];\n for (i = 0; i < msg.length; i += 2) {\n bytes.push(parseInt(msg.substring(i, i + 2), 16));\n }\n }\n var version = bytes[0];\n if (version != this.PROTOCOL_VERSION) {\n return {error: \"protocol version \" + version + \" doesn't match v2\"};\n }\n var deviceId = this.read_int(bytes, 1);\n var flags = this.read_int(bytes, 3);\n var result = {'protocol_version': version, 'device_id': deviceId};\n // decode payload\n var pos = 5;\n for (i = 0; i < this.SENSORS.length; i++, flags >>= 1) {\n if ((flags & 1) !== 1)\n continue;\n var sensor = this.SENSORS[i];\n var x = [];\n // convert data to 16-bit integer array\n for (j = 0; j < sensor.length; j++) {\n x.push(this.read_int(bytes, pos));\n pos += 2;\n }\n // decode sensor values\n for (j = 0; j < sensor.values.length; j++) {\n var value = sensor.values[j];\n if ('convert' in value) {\n result[value.name] = {displayName: value.displayName,\n value: value.convert.bind(this)(x)};\n if ('unit' in value)\n result[value.name]['unit'] = value.unit;\n }\n }\n }\n return result;\n }\n };\n\n const decoded = decentlab_decoder.decode(payload);\n const result = {};\n for (var k in decoded) {\n if (typeof decoded[k] === \"object\") {\n result[k] = decoded[k].value;\n } else if (typeof decoded[k] === \"number\") {\n result[k] = decoded[k];\n }\n }\n return result;\n}\n\nfunction extractNetworkTelemetry(payload) {\n const result = {\n lora_frame_counter: message.fCnt,\n lora_frame_port: message.fPort,\n lora_frequency: message.txInfo.frequency,\n lora_spreading_factor:\n message?.txInfo?.modulation?.lora?.spreadingFactor ||\n message.txInfo.loRaModulationInfo.spreadingFactor,\n lora_dev_eui: (\n message?.deviceInfo?.devEui ||\n base64ToBytes(message.devEUI).reduce(\n (a, x) => a + (\"0\" + x.toString(16)).slice(-2),\n \"\",\n )\n ).toUpperCase(),\n };\n const gwi = message.rxInfo\n .map((x) => ({ lora_rssi: x.rssi, lora_snr: x.snr || x.loRaSNR }))\n .reduce((a, x) => (x.lora_rssi > a.lora_rssi ? x : a), {\n lora_rssi: -Number.MAX_VALUE,\n });\n return Object.assign(result, gwi);\n}\n\n// Helper functions\n\nfunction decodeToJson(payload) {\n const s = String.fromCharCode.apply(String, payload);\n return JSON.parse(s);\n}\n\nfunction parseDateToTimestamp(dateString) {\n var timestamp = -1;\n if (dateString != null) {\n timestamp = new Date(dateString).getTime();\n if (timestamp == -1) {\n var secondsSeparatorIndex = dateString.lastIndexOf('.') + 1;\n var millisecondsEndIndex = dateString.lastIndexOf('+');\n if (millisecondsEndIndex == -1) {\n millisecondsEndIndex = dateString.lastIndexOf('Z');\n }\n if (millisecondsEndIndex == -1) {\n millisecondsEndIndex = dateString.lastIndexOf('-');\n }\n if (millisecondsEndIndex == -1) {\n if (dateString.length >= secondsSeparatorIndex + 3) {\n dateString = dateString.substring(0, secondsSeparatorIndex + 3);\n }\n } else {\n dateString = dateString.substring(0, secondsSeparatorIndex + 3) +\n dateString.substring(millisecondsEndIndex, dateString.length);\n }\n timestamp = new Date(dateString).getTime();\n }\n }\n // If we cannot parse timestamp - we will use the current timestamp\n if (timestamp == -1) {\n timestamp = Date.now();\n }\n\n return timestamp;\n}\n\nfunction base64ToBytes(base64String) {\n if (typeof base64String === 'string') {\n return Uint8Array.from(atob(base64String), c => c.charCodeAt(0));\n }\n return [];\n}\n\nfunction keepTelemetry(telemetry) {\n const unwanted = ['protocol_version', 'device_id', 'lora_dev_eui'];\n return Object.fromEntries(\n Object.entries(telemetry).filter(\n (x) => !unwanted.includes(x[0])\n )\n );\n}" } } \ No newline at end of file diff --git a/VENDORS/Decentlab/DL-SHT35-001/ChirpStack/uplink/result.json b/VENDORS/Decentlab/DL-SHT35-001/ChirpStack/uplink/result.json index 4fba4c87..a1f6ddd0 100644 --- a/VENDORS/Decentlab/DL-SHT35-001/ChirpStack/uplink/result.json +++ b/VENDORS/Decentlab/DL-SHT35-001/ChirpStack/uplink/result.json @@ -1,6 +1,6 @@ { "deviceName": "782", - "deviceType": "DL-SHT35", + "deviceType": "DL-SHT35-001", "attributes": { "lora_dev_eui": "70B3D57BA0003BB8", "protocol_version": 2 diff --git a/VENDORS/Decentlab/DL-SHT35-001/ChirpStack/uplink/result_01.json b/VENDORS/Decentlab/DL-SHT35-001/ChirpStack/uplink/result_01.json index 3fa3482f..911cb1f3 100644 --- a/VENDORS/Decentlab/DL-SHT35-001/ChirpStack/uplink/result_01.json +++ b/VENDORS/Decentlab/DL-SHT35-001/ChirpStack/uplink/result_01.json @@ -1,6 +1,6 @@ { "deviceName": "782", - "deviceType": "DL-SHT35", + "deviceType": "DL-SHT35-001", "attributes": { "lora_dev_eui": "70B3D57BA0003BB8", "protocol_version": 2 diff --git a/VENDORS/Decentlab/DL-SHT35-001/ChirpStack/uplink/result_02.json b/VENDORS/Decentlab/DL-SHT35-001/ChirpStack/uplink/result_02.json index 32566044..46072cb4 100644 --- a/VENDORS/Decentlab/DL-SHT35-001/ChirpStack/uplink/result_02.json +++ b/VENDORS/Decentlab/DL-SHT35-001/ChirpStack/uplink/result_02.json @@ -1,6 +1,6 @@ { "deviceName": "782", - "deviceType": "DL-SHT35", + "deviceType": "DL-SHT35-001", "attributes": { "lora_dev_eui": "0202020202020202", "protocol_version": 2 diff --git a/VENDORS/Decentlab/DL-SHT35-001/ChirpStack/uplink/result_03.json b/VENDORS/Decentlab/DL-SHT35-001/ChirpStack/uplink/result_03.json index 1d189d1f..69ad5abe 100644 --- a/VENDORS/Decentlab/DL-SHT35-001/ChirpStack/uplink/result_03.json +++ b/VENDORS/Decentlab/DL-SHT35-001/ChirpStack/uplink/result_03.json @@ -1,6 +1,6 @@ { "deviceName": "782", - "deviceType": "DL-SHT35", + "deviceType": "DL-SHT35-001", "attributes": { "lora_dev_eui": "0202020202020202", "protocol_version": 2 diff --git a/VENDORS/Decentlab/DL-SHT35-001/LORIOT/uplink/converter.json b/VENDORS/Decentlab/DL-SHT35-001/LORIOT/uplink/converter.json index be781ef1..4b7c01d4 100644 --- a/VENDORS/Decentlab/DL-SHT35-001/LORIOT/uplink/converter.json +++ b/VENDORS/Decentlab/DL-SHT35-001/LORIOT/uplink/converter.json @@ -14,6 +14,6 @@ "lora_dev_eui", "lora_snr" ], - "decoder": "// WARNING: This script is designed to work with a remote JS executor. Compatibility with a local JS evaluator is not guaranteed and may require rewriting.\n\nconst message = decodeToJson(payload);\nconst values = Object.assign(\n decodeDevicePayload(message.data),\n extractNetworkTelemetry(message)\n);\n\nreturn {\n deviceName: String(values.device_id),\n deviceType: 'DL-SHT35',\n attributes: {\n lora_dev_eui: values.lora_dev_eui,\n protocol_version: values.protocol_version,\n },\n telemetry: [{\n ts: message.ts,\n values: keepTelemetry(values)\n }]\n};\n\nfunction decodeDevicePayload(payload) {\n /* https://www.decentlab.com/products/air-temperature-and-humidity-sensor-with-radiation-shield-for-lorawan */\n const decentlab_decoder = {\n PROTOCOL_VERSION: 2,\n SENSORS: [\n {length: 2,\n values: [{name: 'air_temperature',\n displayName: 'Air temperature',\n convert: function (x) { return 175 * x[0] / 65535 - 45; },\n unit: '°C'},\n {name: 'air_humidity',\n displayName: 'Air humidity',\n convert: function (x) { return 100 * x[1] / 65535; },\n unit: '%'}]},\n {length: 1,\n values: [{name: 'battery_voltage',\n displayName: 'Battery voltage',\n convert: function (x) { return x[0] / 1000; },\n unit: 'V'}]}\n ],\n read_int: function (bytes, pos) {\n return (bytes[pos] << 8) + bytes[pos + 1];\n },\n decode: function (msg) {\n var bytes = msg;\n var i, j;\n if (typeof msg === 'string') {\n bytes = [];\n for (i = 0; i < msg.length; i += 2) {\n bytes.push(parseInt(msg.substring(i, i + 2), 16));\n }\n }\n var version = bytes[0];\n if (version != this.PROTOCOL_VERSION) {\n return {error: \"protocol version \" + version + \" doesn't match v2\"};\n }\n var deviceId = this.read_int(bytes, 1);\n var flags = this.read_int(bytes, 3);\n var result = {'protocol_version': version, 'device_id': deviceId};\n // decode payload\n var pos = 5;\n for (i = 0; i < this.SENSORS.length; i++, flags >>= 1) {\n if ((flags & 1) !== 1)\n continue;\n var sensor = this.SENSORS[i];\n var x = [];\n // convert data to 16-bit integer array\n for (j = 0; j < sensor.length; j++) {\n x.push(this.read_int(bytes, pos));\n pos += 2;\n }\n // decode sensor values\n for (j = 0; j < sensor.values.length; j++) {\n var value = sensor.values[j];\n if ('convert' in value) {\n result[value.name] = {displayName: value.displayName,\n value: value.convert.bind(this)(x)};\n if ('unit' in value)\n result[value.name]['unit'] = value.unit;\n }\n }\n }\n return result;\n }\n };\n\n const decoded = decentlab_decoder.decode(payload);\n const result = {};\n for (var k in decoded) {\n if (typeof decoded[k] === \"object\") {\n result[k] = decoded[k].value;\n } else if (typeof decoded[k] === \"number\") {\n result[k] = decoded[k];\n }\n }\n return result;\n}\n\nfunction extractNetworkTelemetry(payload) {\n const result = {\n lora_frame_counter: message.fcnt,\n lora_frame_port: message.port,\n lora_frequency: message.freq,\n lora_snr: message.snr,\n lora_rssi: message.rssi,\n lora_dev_eui: message.EUI,\n lora_spreading_factor: parseInt(message.dr.replace(/.*SF(\\d+).*/, '$1')),\n };\n if (message.cmd === 'gw') {\n const gwi = message.gws\n .map((x) => ({ lora_rssi: x.rssi, lora_snr: x.snr }))\n .reduce((a, x) => (x.lora_rssi > a.lora_rssi ? x : a), {\n lora_rssi: -Number.MAX_VALUE,\n });\n result.rssi = gwi.rssi;\n result.snr = gwi.snr;\n }\n return result;\n}\n\n// Helper functions\n\nfunction decodeToJson(payload) {\n const s = String.fromCharCode.apply(String, payload);\n return JSON.parse(s);\n}\n\nfunction parseDateToTimestamp(dateString) {\n var timestamp = -1;\n if (dateString != null) {\n timestamp = new Date(dateString).getTime();\n if (timestamp == -1) {\n var secondsSeparatorIndex = dateString.lastIndexOf('.') + 1;\n var millisecondsEndIndex = dateString.lastIndexOf('+');\n if (millisecondsEndIndex == -1) {\n millisecondsEndIndex = dateString.lastIndexOf('Z');\n }\n if (millisecondsEndIndex == -1) {\n millisecondsEndIndex = dateString.lastIndexOf('-');\n }\n if (millisecondsEndIndex == -1) {\n if (dateString.length >= secondsSeparatorIndex + 3) {\n dateString = dateString.substring(0, secondsSeparatorIndex + 3);\n }\n } else {\n dateString = dateString.substring(0, secondsSeparatorIndex + 3) +\n dateString.substring(millisecondsEndIndex, dateString.length);\n }\n timestamp = new Date(dateString).getTime();\n }\n }\n // If we cannot parse timestamp - we will use the current timestamp\n if (timestamp == -1) {\n timestamp = Date.now();\n }\n\n return timestamp;\n}\n\nfunction base64ToBytes(base64String) {\n if (typeof base64String === 'string') {\n return Uint8Array.from(atob(base64String), c => c.charCodeAt(0));\n }\n return [];\n}\n\nfunction keepTelemetry(telemetry) {\n const unwanted = ['protocol_version', 'device_id', 'lora_dev_eui'];\n return Object.fromEntries(\n Object.entries(telemetry).filter(\n (x) => !unwanted.includes(x[0])\n )\n );\n}" + "decoder": "// WARNING: This script is designed to work with a remote JS executor. Compatibility with a local JS evaluator is not guaranteed and may require rewriting.\n\nconst message = decodeToJson(payload);\nconst values = Object.assign(\n decodeDevicePayload(message.data),\n extractNetworkTelemetry(message)\n);\n\nreturn {\n deviceName: String(values.device_id),\n deviceType: 'DL-SHT35-001',\n attributes: {\n lora_dev_eui: values.lora_dev_eui,\n protocol_version: values.protocol_version,\n },\n telemetry: [{\n ts: message.ts,\n values: keepTelemetry(values)\n }]\n};\n\nfunction decodeDevicePayload(payload) {\n /* https://www.decentlab.com/products/air-temperature-and-humidity-sensor-with-radiation-shield-for-lorawan */\n const decentlab_decoder = {\n PROTOCOL_VERSION: 2,\n SENSORS: [\n {length: 2,\n values: [{name: 'air_temperature',\n displayName: 'Air temperature',\n convert: function (x) { return 175 * x[0] / 65535 - 45; },\n unit: '°C'},\n {name: 'air_humidity',\n displayName: 'Air humidity',\n convert: function (x) { return 100 * x[1] / 65535; },\n unit: '%'}]},\n {length: 1,\n values: [{name: 'battery_voltage',\n displayName: 'Battery voltage',\n convert: function (x) { return x[0] / 1000; },\n unit: 'V'}]}\n ],\n read_int: function (bytes, pos) {\n return (bytes[pos] << 8) + bytes[pos + 1];\n },\n decode: function (msg) {\n var bytes = msg;\n var i, j;\n if (typeof msg === 'string') {\n bytes = [];\n for (i = 0; i < msg.length; i += 2) {\n bytes.push(parseInt(msg.substring(i, i + 2), 16));\n }\n }\n var version = bytes[0];\n if (version != this.PROTOCOL_VERSION) {\n return {error: \"protocol version \" + version + \" doesn't match v2\"};\n }\n var deviceId = this.read_int(bytes, 1);\n var flags = this.read_int(bytes, 3);\n var result = {'protocol_version': version, 'device_id': deviceId};\n // decode payload\n var pos = 5;\n for (i = 0; i < this.SENSORS.length; i++, flags >>= 1) {\n if ((flags & 1) !== 1)\n continue;\n var sensor = this.SENSORS[i];\n var x = [];\n // convert data to 16-bit integer array\n for (j = 0; j < sensor.length; j++) {\n x.push(this.read_int(bytes, pos));\n pos += 2;\n }\n // decode sensor values\n for (j = 0; j < sensor.values.length; j++) {\n var value = sensor.values[j];\n if ('convert' in value) {\n result[value.name] = {displayName: value.displayName,\n value: value.convert.bind(this)(x)};\n if ('unit' in value)\n result[value.name]['unit'] = value.unit;\n }\n }\n }\n return result;\n }\n };\n\n const decoded = decentlab_decoder.decode(payload);\n const result = {};\n for (var k in decoded) {\n if (typeof decoded[k] === \"object\") {\n result[k] = decoded[k].value;\n } else if (typeof decoded[k] === \"number\") {\n result[k] = decoded[k];\n }\n }\n return result;\n}\n\nfunction extractNetworkTelemetry(payload) {\n const result = {\n lora_frame_counter: message.fcnt,\n lora_frame_port: message.port,\n lora_frequency: message.freq,\n lora_snr: message.snr,\n lora_rssi: message.rssi,\n lora_dev_eui: message.EUI,\n lora_spreading_factor: parseInt(message.dr.replace(/.*SF(\\d+).*/, '$1')),\n };\n if (message.cmd === 'gw') {\n const gwi = message.gws\n .map((x) => ({ lora_rssi: x.rssi, lora_snr: x.snr }))\n .reduce((a, x) => (x.lora_rssi > a.lora_rssi ? x : a), {\n lora_rssi: -Number.MAX_VALUE,\n });\n result.rssi = gwi.rssi;\n result.snr = gwi.snr;\n }\n return result;\n}\n\n// Helper functions\n\nfunction decodeToJson(payload) {\n const s = String.fromCharCode.apply(String, payload);\n return JSON.parse(s);\n}\n\nfunction parseDateToTimestamp(dateString) {\n var timestamp = -1;\n if (dateString != null) {\n timestamp = new Date(dateString).getTime();\n if (timestamp == -1) {\n var secondsSeparatorIndex = dateString.lastIndexOf('.') + 1;\n var millisecondsEndIndex = dateString.lastIndexOf('+');\n if (millisecondsEndIndex == -1) {\n millisecondsEndIndex = dateString.lastIndexOf('Z');\n }\n if (millisecondsEndIndex == -1) {\n millisecondsEndIndex = dateString.lastIndexOf('-');\n }\n if (millisecondsEndIndex == -1) {\n if (dateString.length >= secondsSeparatorIndex + 3) {\n dateString = dateString.substring(0, secondsSeparatorIndex + 3);\n }\n } else {\n dateString = dateString.substring(0, secondsSeparatorIndex + 3) +\n dateString.substring(millisecondsEndIndex, dateString.length);\n }\n timestamp = new Date(dateString).getTime();\n }\n }\n // If we cannot parse timestamp - we will use the current timestamp\n if (timestamp == -1) {\n timestamp = Date.now();\n }\n\n return timestamp;\n}\n\nfunction base64ToBytes(base64String) {\n if (typeof base64String === 'string') {\n return Uint8Array.from(atob(base64String), c => c.charCodeAt(0));\n }\n return [];\n}\n\nfunction keepTelemetry(telemetry) {\n const unwanted = ['protocol_version', 'device_id', 'lora_dev_eui'];\n return Object.fromEntries(\n Object.entries(telemetry).filter(\n (x) => !unwanted.includes(x[0])\n )\n );\n}" } } \ No newline at end of file diff --git a/VENDORS/Decentlab/DL-SHT35-001/LORIOT/uplink/result.json b/VENDORS/Decentlab/DL-SHT35-001/LORIOT/uplink/result.json index 178e03a5..cffecb65 100644 --- a/VENDORS/Decentlab/DL-SHT35-001/LORIOT/uplink/result.json +++ b/VENDORS/Decentlab/DL-SHT35-001/LORIOT/uplink/result.json @@ -1,6 +1,6 @@ { "deviceName": "782", - "deviceType": "DL-SHT35", + "deviceType": "DL-SHT35-001", "attributes": { "lora_dev_eui": "0004A30B001ADCB5", "protocol_version": 2 diff --git a/VENDORS/Decentlab/DL-SHT35-001/LORIOT/uplink/result_01.json b/VENDORS/Decentlab/DL-SHT35-001/LORIOT/uplink/result_01.json index f531f446..ba31c58b 100644 --- a/VENDORS/Decentlab/DL-SHT35-001/LORIOT/uplink/result_01.json +++ b/VENDORS/Decentlab/DL-SHT35-001/LORIOT/uplink/result_01.json @@ -1,6 +1,6 @@ { "deviceName": "782", - "deviceType": "DL-SHT35", + "deviceType": "DL-SHT35-001", "attributes": { "lora_dev_eui": "0004A30B001ADCB5", "protocol_version": 2 diff --git a/VENDORS/Decentlab/DL-SHT35-001/ThingPark/uplink/converter.json b/VENDORS/Decentlab/DL-SHT35-001/ThingPark/uplink/converter.json index 2feb45d4..d03547dd 100644 --- a/VENDORS/Decentlab/DL-SHT35-001/ThingPark/uplink/converter.json +++ b/VENDORS/Decentlab/DL-SHT35-001/ThingPark/uplink/converter.json @@ -14,6 +14,6 @@ "lora_dev_eui", "lora_snr" ], - "decoder": "// WARNING: This script is designed to work with a remote JS executor. Compatibility with a local JS evaluator is not guaranteed and may require rewriting.\n\nconst message = decodeToJson(payload);\nconst values = Object.assign(\n decodeDevicePayload(message.DevEUI_uplink.payload_hex),\n extractNetworkTelemetry(message)\n);\n\nreturn {\n deviceName: String(values.device_id),\n deviceType: 'DL-SHT35',\n attributes: {\n lora_dev_eui: values.lora_dev_eui,\n protocol_version: values.protocol_version,\n },\n telemetry: [{\n ts: parseDateToTimestamp(message.DevEUI_uplink.Time),\n values: keepTelemetry(values)\n }]\n};\n\nfunction decodeDevicePayload(payload) {\n /* https://www.decentlab.com/products/air-temperature-and-humidity-sensor-with-radiation-shield-for-lorawan */\n const decentlab_decoder = {\n PROTOCOL_VERSION: 2,\n SENSORS: [\n {length: 2,\n values: [{name: 'air_temperature',\n displayName: 'Air temperature',\n convert: function (x) { return 175 * x[0] / 65535 - 45; },\n unit: '°C'},\n {name: 'air_humidity',\n displayName: 'Air humidity',\n convert: function (x) { return 100 * x[1] / 65535; },\n unit: '%'}]},\n {length: 1,\n values: [{name: 'battery_voltage',\n displayName: 'Battery voltage',\n convert: function (x) { return x[0] / 1000; },\n unit: 'V'}]}\n ],\n read_int: function (bytes, pos) {\n return (bytes[pos] << 8) + bytes[pos + 1];\n },\n decode: function (msg) {\n var bytes = msg;\n var i, j;\n if (typeof msg === 'string') {\n bytes = [];\n for (i = 0; i < msg.length; i += 2) {\n bytes.push(parseInt(msg.substring(i, i + 2), 16));\n }\n }\n var version = bytes[0];\n if (version != this.PROTOCOL_VERSION) {\n return {error: \"protocol version \" + version + \" doesn't match v2\"};\n }\n var deviceId = this.read_int(bytes, 1);\n var flags = this.read_int(bytes, 3);\n var result = {'protocol_version': version, 'device_id': deviceId};\n // decode payload\n var pos = 5;\n for (i = 0; i < this.SENSORS.length; i++, flags >>= 1) {\n if ((flags & 1) !== 1)\n continue;\n var sensor = this.SENSORS[i];\n var x = [];\n // convert data to 16-bit integer array\n for (j = 0; j < sensor.length; j++) {\n x.push(this.read_int(bytes, pos));\n pos += 2;\n }\n // decode sensor values\n for (j = 0; j < sensor.values.length; j++) {\n var value = sensor.values[j];\n if ('convert' in value) {\n result[value.name] = {displayName: value.displayName,\n value: value.convert.bind(this)(x)};\n if ('unit' in value)\n result[value.name]['unit'] = value.unit;\n }\n }\n }\n return result;\n }\n };\n\n const decoded = decentlab_decoder.decode(payload);\n const result = {};\n for (var k in decoded) {\n if (typeof decoded[k] === \"object\") {\n result[k] = decoded[k].value;\n } else if (typeof decoded[k] === \"number\") {\n result[k] = decoded[k];\n }\n }\n return result;\n}\n\nfunction extractNetworkTelemetry(payload) {\n return {\n lora_frame_counter: message.DevEUI_uplink.FCntUp,\n lora_frame_port: message.DevEUI_uplink.FPort,\n lora_frequency: message.DevEUI_uplink?.Frequency * 1000000,\n lora_spreading_factor: message.DevEUI_uplink.SpFact,\n lora_dev_eui: message.DevEUI_uplink.DevEUI,\n lora_rssi: message.DevEUI_uplink.LrrRSSI,\n lora_snr: message.DevEUI_uplink.LrrSNR,\n };\n}\n\n// Helper functions\n\nfunction decodeToJson(payload) {\n const s = String.fromCharCode.apply(String, payload);\n return JSON.parse(s);\n}\n\nfunction parseDateToTimestamp(dateString) {\n var timestamp = -1;\n if (dateString != null) {\n timestamp = new Date(dateString).getTime();\n if (timestamp == -1) {\n var secondsSeparatorIndex = dateString.lastIndexOf('.') + 1;\n var millisecondsEndIndex = dateString.lastIndexOf('+');\n if (millisecondsEndIndex == -1) {\n millisecondsEndIndex = dateString.lastIndexOf('Z');\n }\n if (millisecondsEndIndex == -1) {\n millisecondsEndIndex = dateString.lastIndexOf('-');\n }\n if (millisecondsEndIndex == -1) {\n if (dateString.length >= secondsSeparatorIndex + 3) {\n dateString = dateString.substring(0, secondsSeparatorIndex + 3);\n }\n } else {\n dateString = dateString.substring(0, secondsSeparatorIndex + 3) +\n dateString.substring(millisecondsEndIndex, dateString.length);\n }\n timestamp = new Date(dateString).getTime();\n }\n }\n // If we cannot parse timestamp - we will use the current timestamp\n if (timestamp == -1) {\n timestamp = Date.now();\n }\n\n return timestamp;\n}\n\nfunction base64ToBytes(base64String) {\n if (typeof base64String === 'string') {\n return Uint8Array.from(atob(base64String), c => c.charCodeAt(0));\n }\n return [];\n}\n\nfunction keepTelemetry(telemetry) {\n const unwanted = ['protocol_version', 'device_id', 'lora_dev_eui'];\n return Object.fromEntries(\n Object.entries(telemetry).filter(\n (x) => !unwanted.includes(x[0])\n )\n );\n}" + "decoder": "// WARNING: This script is designed to work with a remote JS executor. Compatibility with a local JS evaluator is not guaranteed and may require rewriting.\n\nconst message = decodeToJson(payload);\nconst values = Object.assign(\n decodeDevicePayload(message.DevEUI_uplink.payload_hex),\n extractNetworkTelemetry(message)\n);\n\nreturn {\n deviceName: String(values.device_id),\n deviceType: 'DL-SHT35-001',\n attributes: {\n lora_dev_eui: values.lora_dev_eui,\n protocol_version: values.protocol_version,\n },\n telemetry: [{\n ts: parseDateToTimestamp(message.DevEUI_uplink.Time),\n values: keepTelemetry(values)\n }]\n};\n\nfunction decodeDevicePayload(payload) {\n /* https://www.decentlab.com/products/air-temperature-and-humidity-sensor-with-radiation-shield-for-lorawan */\n const decentlab_decoder = {\n PROTOCOL_VERSION: 2,\n SENSORS: [\n {length: 2,\n values: [{name: 'air_temperature',\n displayName: 'Air temperature',\n convert: function (x) { return 175 * x[0] / 65535 - 45; },\n unit: '°C'},\n {name: 'air_humidity',\n displayName: 'Air humidity',\n convert: function (x) { return 100 * x[1] / 65535; },\n unit: '%'}]},\n {length: 1,\n values: [{name: 'battery_voltage',\n displayName: 'Battery voltage',\n convert: function (x) { return x[0] / 1000; },\n unit: 'V'}]}\n ],\n read_int: function (bytes, pos) {\n return (bytes[pos] << 8) + bytes[pos + 1];\n },\n decode: function (msg) {\n var bytes = msg;\n var i, j;\n if (typeof msg === 'string') {\n bytes = [];\n for (i = 0; i < msg.length; i += 2) {\n bytes.push(parseInt(msg.substring(i, i + 2), 16));\n }\n }\n var version = bytes[0];\n if (version != this.PROTOCOL_VERSION) {\n return {error: \"protocol version \" + version + \" doesn't match v2\"};\n }\n var deviceId = this.read_int(bytes, 1);\n var flags = this.read_int(bytes, 3);\n var result = {'protocol_version': version, 'device_id': deviceId};\n // decode payload\n var pos = 5;\n for (i = 0; i < this.SENSORS.length; i++, flags >>= 1) {\n if ((flags & 1) !== 1)\n continue;\n var sensor = this.SENSORS[i];\n var x = [];\n // convert data to 16-bit integer array\n for (j = 0; j < sensor.length; j++) {\n x.push(this.read_int(bytes, pos));\n pos += 2;\n }\n // decode sensor values\n for (j = 0; j < sensor.values.length; j++) {\n var value = sensor.values[j];\n if ('convert' in value) {\n result[value.name] = {displayName: value.displayName,\n value: value.convert.bind(this)(x)};\n if ('unit' in value)\n result[value.name]['unit'] = value.unit;\n }\n }\n }\n return result;\n }\n };\n\n const decoded = decentlab_decoder.decode(payload);\n const result = {};\n for (var k in decoded) {\n if (typeof decoded[k] === \"object\") {\n result[k] = decoded[k].value;\n } else if (typeof decoded[k] === \"number\") {\n result[k] = decoded[k];\n }\n }\n return result;\n}\n\nfunction extractNetworkTelemetry(payload) {\n return {\n lora_frame_counter: message.DevEUI_uplink.FCntUp,\n lora_frame_port: message.DevEUI_uplink.FPort,\n lora_frequency: message.DevEUI_uplink?.Frequency * 1000000,\n lora_spreading_factor: message.DevEUI_uplink.SpFact,\n lora_dev_eui: message.DevEUI_uplink.DevEUI,\n lora_rssi: message.DevEUI_uplink.LrrRSSI,\n lora_snr: message.DevEUI_uplink.LrrSNR,\n };\n}\n\n// Helper functions\n\nfunction decodeToJson(payload) {\n const s = String.fromCharCode.apply(String, payload);\n return JSON.parse(s);\n}\n\nfunction parseDateToTimestamp(dateString) {\n var timestamp = -1;\n if (dateString != null) {\n timestamp = new Date(dateString).getTime();\n if (timestamp == -1) {\n var secondsSeparatorIndex = dateString.lastIndexOf('.') + 1;\n var millisecondsEndIndex = dateString.lastIndexOf('+');\n if (millisecondsEndIndex == -1) {\n millisecondsEndIndex = dateString.lastIndexOf('Z');\n }\n if (millisecondsEndIndex == -1) {\n millisecondsEndIndex = dateString.lastIndexOf('-');\n }\n if (millisecondsEndIndex == -1) {\n if (dateString.length >= secondsSeparatorIndex + 3) {\n dateString = dateString.substring(0, secondsSeparatorIndex + 3);\n }\n } else {\n dateString = dateString.substring(0, secondsSeparatorIndex + 3) +\n dateString.substring(millisecondsEndIndex, dateString.length);\n }\n timestamp = new Date(dateString).getTime();\n }\n }\n // If we cannot parse timestamp - we will use the current timestamp\n if (timestamp == -1) {\n timestamp = Date.now();\n }\n\n return timestamp;\n}\n\nfunction base64ToBytes(base64String) {\n if (typeof base64String === 'string') {\n return Uint8Array.from(atob(base64String), c => c.charCodeAt(0));\n }\n return [];\n}\n\nfunction keepTelemetry(telemetry) {\n const unwanted = ['protocol_version', 'device_id', 'lora_dev_eui'];\n return Object.fromEntries(\n Object.entries(telemetry).filter(\n (x) => !unwanted.includes(x[0])\n )\n );\n}" } } \ No newline at end of file diff --git a/VENDORS/Decentlab/DL-SHT35-001/ThingPark/uplink/result.json b/VENDORS/Decentlab/DL-SHT35-001/ThingPark/uplink/result.json index 196a5cdf..3e9504d7 100644 --- a/VENDORS/Decentlab/DL-SHT35-001/ThingPark/uplink/result.json +++ b/VENDORS/Decentlab/DL-SHT35-001/ThingPark/uplink/result.json @@ -1,6 +1,6 @@ { "deviceName": "782", - "deviceType": "DL-SHT35", + "deviceType": "DL-SHT35-001", "attributes": { "lora_dev_eui": "70B3D57BA000156B", "protocol_version": 2 diff --git a/VENDORS/Decentlab/DL-SHT35-001/ThingPark/uplink/result_01.json b/VENDORS/Decentlab/DL-SHT35-001/ThingPark/uplink/result_01.json index e83504f1..ea5af45d 100644 --- a/VENDORS/Decentlab/DL-SHT35-001/ThingPark/uplink/result_01.json +++ b/VENDORS/Decentlab/DL-SHT35-001/ThingPark/uplink/result_01.json @@ -1,6 +1,6 @@ { "deviceName": "782", - "deviceType": "DL-SHT35", + "deviceType": "DL-SHT35-001", "attributes": { "lora_dev_eui": "70B3D57BA000156B", "protocol_version": 2 diff --git a/VENDORS/Decentlab/DL-SHT35-001/ThingParkEnterprise/uplink/converter.json b/VENDORS/Decentlab/DL-SHT35-001/ThingParkEnterprise/uplink/converter.json index 533f0957..86f7f62b 100644 --- a/VENDORS/Decentlab/DL-SHT35-001/ThingParkEnterprise/uplink/converter.json +++ b/VENDORS/Decentlab/DL-SHT35-001/ThingParkEnterprise/uplink/converter.json @@ -14,6 +14,6 @@ "lora_dev_eui", "lora_snr" ], - "decoder": "// WARNING: This script is designed to work with a remote JS executor. Compatibility with a local JS evaluator is not guaranteed and may require rewriting.\n\nconst message = decodeToJson(payload);\nconst values = Object.assign(\n decodeDevicePayload(message.DevEUI_uplink.payload_hex),\n extractNetworkTelemetry(message)\n);\n\nreturn {\n deviceName: String(values.device_id),\n deviceType: 'DL-SHT35',\n attributes: {\n lora_dev_eui: values.lora_dev_eui,\n protocol_version: values.protocol_version,\n },\n telemetry: [{\n ts: parseDateToTimestamp(message.DevEUI_uplink.Time),\n values: keepTelemetry(values)\n }]\n};\n\nfunction decodeDevicePayload(payload) {\n /* https://www.decentlab.com/products/air-temperature-and-humidity-sensor-with-radiation-shield-for-lorawan */\n const decentlab_decoder = {\n PROTOCOL_VERSION: 2,\n SENSORS: [\n {length: 2,\n values: [{name: 'air_temperature',\n displayName: 'Air temperature',\n convert: function (x) { return 175 * x[0] / 65535 - 45; },\n unit: '°C'},\n {name: 'air_humidity',\n displayName: 'Air humidity',\n convert: function (x) { return 100 * x[1] / 65535; },\n unit: '%'}]},\n {length: 1,\n values: [{name: 'battery_voltage',\n displayName: 'Battery voltage',\n convert: function (x) { return x[0] / 1000; },\n unit: 'V'}]}\n ],\n read_int: function (bytes, pos) {\n return (bytes[pos] << 8) + bytes[pos + 1];\n },\n decode: function (msg) {\n var bytes = msg;\n var i, j;\n if (typeof msg === 'string') {\n bytes = [];\n for (i = 0; i < msg.length; i += 2) {\n bytes.push(parseInt(msg.substring(i, i + 2), 16));\n }\n }\n var version = bytes[0];\n if (version != this.PROTOCOL_VERSION) {\n return {error: \"protocol version \" + version + \" doesn't match v2\"};\n }\n var deviceId = this.read_int(bytes, 1);\n var flags = this.read_int(bytes, 3);\n var result = {'protocol_version': version, 'device_id': deviceId};\n // decode payload\n var pos = 5;\n for (i = 0; i < this.SENSORS.length; i++, flags >>= 1) {\n if ((flags & 1) !== 1)\n continue;\n var sensor = this.SENSORS[i];\n var x = [];\n // convert data to 16-bit integer array\n for (j = 0; j < sensor.length; j++) {\n x.push(this.read_int(bytes, pos));\n pos += 2;\n }\n // decode sensor values\n for (j = 0; j < sensor.values.length; j++) {\n var value = sensor.values[j];\n if ('convert' in value) {\n result[value.name] = {displayName: value.displayName,\n value: value.convert.bind(this)(x)};\n if ('unit' in value)\n result[value.name]['unit'] = value.unit;\n }\n }\n }\n return result;\n }\n };\n\n const decoded = decentlab_decoder.decode(payload);\n const result = {};\n for (var k in decoded) {\n if (typeof decoded[k] === \"object\") {\n result[k] = decoded[k].value;\n } else if (typeof decoded[k] === \"number\") {\n result[k] = decoded[k];\n }\n }\n return result;\n}\n\nfunction extractNetworkTelemetry(payload) {\n return {\n lora_frame_counter: message.DevEUI_uplink.FCntUp,\n lora_frame_port: message.DevEUI_uplink.FPort,\n lora_frequency: message.DevEUI_uplink?.Frequency * 1000000,\n lora_spreading_factor: message.DevEUI_uplink.SpFact,\n lora_dev_eui: message.DevEUI_uplink.DevEUI,\n lora_rssi: message.DevEUI_uplink.LrrRSSI,\n lora_snr: message.DevEUI_uplink.LrrSNR,\n };\n}\n\n// Helper functions\n\nfunction decodeToJson(payload) {\n const s = String.fromCharCode.apply(String, payload);\n return JSON.parse(s);\n}\n\nfunction parseDateToTimestamp(dateString) {\n var timestamp = -1;\n if (dateString != null) {\n timestamp = new Date(dateString).getTime();\n if (timestamp == -1) {\n var secondsSeparatorIndex = dateString.lastIndexOf('.') + 1;\n var millisecondsEndIndex = dateString.lastIndexOf('+');\n if (millisecondsEndIndex == -1) {\n millisecondsEndIndex = dateString.lastIndexOf('Z');\n }\n if (millisecondsEndIndex == -1) {\n millisecondsEndIndex = dateString.lastIndexOf('-');\n }\n if (millisecondsEndIndex == -1) {\n if (dateString.length >= secondsSeparatorIndex + 3) {\n dateString = dateString.substring(0, secondsSeparatorIndex + 3);\n }\n } else {\n dateString = dateString.substring(0, secondsSeparatorIndex + 3) +\n dateString.substring(millisecondsEndIndex, dateString.length);\n }\n timestamp = new Date(dateString).getTime();\n }\n }\n // If we cannot parse timestamp - we will use the current timestamp\n if (timestamp == -1) {\n timestamp = Date.now();\n }\n\n return timestamp;\n}\n\nfunction base64ToBytes(base64String) {\n if (typeof base64String === 'string') {\n return Uint8Array.from(atob(base64String), c => c.charCodeAt(0));\n }\n return [];\n}\n\nfunction keepTelemetry(telemetry) {\n const unwanted = ['protocol_version', 'device_id', 'lora_dev_eui'];\n return Object.fromEntries(\n Object.entries(telemetry).filter(\n (x) => !unwanted.includes(x[0])\n )\n );\n}" + "decoder": "// WARNING: This script is designed to work with a remote JS executor. Compatibility with a local JS evaluator is not guaranteed and may require rewriting.\n\nconst message = decodeToJson(payload);\nconst values = Object.assign(\n decodeDevicePayload(message.DevEUI_uplink.payload_hex),\n extractNetworkTelemetry(message)\n);\n\nreturn {\n deviceName: String(values.device_id),\n deviceType: 'DL-SHT35-001',\n attributes: {\n lora_dev_eui: values.lora_dev_eui,\n protocol_version: values.protocol_version,\n },\n telemetry: [{\n ts: parseDateToTimestamp(message.DevEUI_uplink.Time),\n values: keepTelemetry(values)\n }]\n};\n\nfunction decodeDevicePayload(payload) {\n /* https://www.decentlab.com/products/air-temperature-and-humidity-sensor-with-radiation-shield-for-lorawan */\n const decentlab_decoder = {\n PROTOCOL_VERSION: 2,\n SENSORS: [\n {length: 2,\n values: [{name: 'air_temperature',\n displayName: 'Air temperature',\n convert: function (x) { return 175 * x[0] / 65535 - 45; },\n unit: '°C'},\n {name: 'air_humidity',\n displayName: 'Air humidity',\n convert: function (x) { return 100 * x[1] / 65535; },\n unit: '%'}]},\n {length: 1,\n values: [{name: 'battery_voltage',\n displayName: 'Battery voltage',\n convert: function (x) { return x[0] / 1000; },\n unit: 'V'}]}\n ],\n read_int: function (bytes, pos) {\n return (bytes[pos] << 8) + bytes[pos + 1];\n },\n decode: function (msg) {\n var bytes = msg;\n var i, j;\n if (typeof msg === 'string') {\n bytes = [];\n for (i = 0; i < msg.length; i += 2) {\n bytes.push(parseInt(msg.substring(i, i + 2), 16));\n }\n }\n var version = bytes[0];\n if (version != this.PROTOCOL_VERSION) {\n return {error: \"protocol version \" + version + \" doesn't match v2\"};\n }\n var deviceId = this.read_int(bytes, 1);\n var flags = this.read_int(bytes, 3);\n var result = {'protocol_version': version, 'device_id': deviceId};\n // decode payload\n var pos = 5;\n for (i = 0; i < this.SENSORS.length; i++, flags >>= 1) {\n if ((flags & 1) !== 1)\n continue;\n var sensor = this.SENSORS[i];\n var x = [];\n // convert data to 16-bit integer array\n for (j = 0; j < sensor.length; j++) {\n x.push(this.read_int(bytes, pos));\n pos += 2;\n }\n // decode sensor values\n for (j = 0; j < sensor.values.length; j++) {\n var value = sensor.values[j];\n if ('convert' in value) {\n result[value.name] = {displayName: value.displayName,\n value: value.convert.bind(this)(x)};\n if ('unit' in value)\n result[value.name]['unit'] = value.unit;\n }\n }\n }\n return result;\n }\n };\n\n const decoded = decentlab_decoder.decode(payload);\n const result = {};\n for (var k in decoded) {\n if (typeof decoded[k] === \"object\") {\n result[k] = decoded[k].value;\n } else if (typeof decoded[k] === \"number\") {\n result[k] = decoded[k];\n }\n }\n return result;\n}\n\nfunction extractNetworkTelemetry(payload) {\n return {\n lora_frame_counter: message.DevEUI_uplink.FCntUp,\n lora_frame_port: message.DevEUI_uplink.FPort,\n lora_frequency: message.DevEUI_uplink?.Frequency * 1000000,\n lora_spreading_factor: message.DevEUI_uplink.SpFact,\n lora_dev_eui: message.DevEUI_uplink.DevEUI,\n lora_rssi: message.DevEUI_uplink.LrrRSSI,\n lora_snr: message.DevEUI_uplink.LrrSNR,\n };\n}\n\n// Helper functions\n\nfunction decodeToJson(payload) {\n const s = String.fromCharCode.apply(String, payload);\n return JSON.parse(s);\n}\n\nfunction parseDateToTimestamp(dateString) {\n var timestamp = -1;\n if (dateString != null) {\n timestamp = new Date(dateString).getTime();\n if (timestamp == -1) {\n var secondsSeparatorIndex = dateString.lastIndexOf('.') + 1;\n var millisecondsEndIndex = dateString.lastIndexOf('+');\n if (millisecondsEndIndex == -1) {\n millisecondsEndIndex = dateString.lastIndexOf('Z');\n }\n if (millisecondsEndIndex == -1) {\n millisecondsEndIndex = dateString.lastIndexOf('-');\n }\n if (millisecondsEndIndex == -1) {\n if (dateString.length >= secondsSeparatorIndex + 3) {\n dateString = dateString.substring(0, secondsSeparatorIndex + 3);\n }\n } else {\n dateString = dateString.substring(0, secondsSeparatorIndex + 3) +\n dateString.substring(millisecondsEndIndex, dateString.length);\n }\n timestamp = new Date(dateString).getTime();\n }\n }\n // If we cannot parse timestamp - we will use the current timestamp\n if (timestamp == -1) {\n timestamp = Date.now();\n }\n\n return timestamp;\n}\n\nfunction base64ToBytes(base64String) {\n if (typeof base64String === 'string') {\n return Uint8Array.from(atob(base64String), c => c.charCodeAt(0));\n }\n return [];\n}\n\nfunction keepTelemetry(telemetry) {\n const unwanted = ['protocol_version', 'device_id', 'lora_dev_eui'];\n return Object.fromEntries(\n Object.entries(telemetry).filter(\n (x) => !unwanted.includes(x[0])\n )\n );\n}" } } \ No newline at end of file diff --git a/VENDORS/Decentlab/DL-SHT35-001/ThingParkEnterprise/uplink/result.json b/VENDORS/Decentlab/DL-SHT35-001/ThingParkEnterprise/uplink/result.json index 196a5cdf..3e9504d7 100644 --- a/VENDORS/Decentlab/DL-SHT35-001/ThingParkEnterprise/uplink/result.json +++ b/VENDORS/Decentlab/DL-SHT35-001/ThingParkEnterprise/uplink/result.json @@ -1,6 +1,6 @@ { "deviceName": "782", - "deviceType": "DL-SHT35", + "deviceType": "DL-SHT35-001", "attributes": { "lora_dev_eui": "70B3D57BA000156B", "protocol_version": 2 diff --git a/VENDORS/Decentlab/DL-SHT35-001/ThingParkEnterprise/uplink/result_01.json b/VENDORS/Decentlab/DL-SHT35-001/ThingParkEnterprise/uplink/result_01.json index e83504f1..ea5af45d 100644 --- a/VENDORS/Decentlab/DL-SHT35-001/ThingParkEnterprise/uplink/result_01.json +++ b/VENDORS/Decentlab/DL-SHT35-001/ThingParkEnterprise/uplink/result_01.json @@ -1,6 +1,6 @@ { "deviceName": "782", - "deviceType": "DL-SHT35", + "deviceType": "DL-SHT35-001", "attributes": { "lora_dev_eui": "70B3D57BA000156B", "protocol_version": 2 diff --git a/VENDORS/Decentlab/DL-SHT35-001/ThingsStackCommunity/uplink/converter.json b/VENDORS/Decentlab/DL-SHT35-001/ThingsStackCommunity/uplink/converter.json index 5a1a4894..8871ef4b 100644 --- a/VENDORS/Decentlab/DL-SHT35-001/ThingsStackCommunity/uplink/converter.json +++ b/VENDORS/Decentlab/DL-SHT35-001/ThingsStackCommunity/uplink/converter.json @@ -14,6 +14,6 @@ "lora_dev_eui", "lora_snr" ], - "decoder": "// WARNING: This script is designed to work with a remote JS executor. Compatibility with a local JS evaluator is not guaranteed and may require rewriting.\n\nconst message = decodeToJson(payload);\nconst values = Object.assign(\n decodeDevicePayload(base64ToBytes(message.uplink_message.frm_payload)),\n extractNetworkTelemetry(message)\n);\n\nreturn {\n deviceName: String(values.device_id),\n deviceType: 'DL-SHT35',\n attributes: {\n lora_dev_eui: values.lora_dev_eui,\n protocol_version: values.protocol_version,\n },\n telemetry: [{\n ts: parseDateToTimestamp(message.received_at),\n values: keepTelemetry(values)\n }]\n};\n\nfunction decodeDevicePayload(payload) {\n /* https://www.decentlab.com/products/air-temperature-and-humidity-sensor-with-radiation-shield-for-lorawan */\n const decentlab_decoder = {\n PROTOCOL_VERSION: 2,\n SENSORS: [\n {length: 2,\n values: [{name: 'air_temperature',\n displayName: 'Air temperature',\n convert: function (x) { return 175 * x[0] / 65535 - 45; },\n unit: '°C'},\n {name: 'air_humidity',\n displayName: 'Air humidity',\n convert: function (x) { return 100 * x[1] / 65535; },\n unit: '%'}]},\n {length: 1,\n values: [{name: 'battery_voltage',\n displayName: 'Battery voltage',\n convert: function (x) { return x[0] / 1000; },\n unit: 'V'}]}\n ],\n read_int: function (bytes, pos) {\n return (bytes[pos] << 8) + bytes[pos + 1];\n },\n decode: function (msg) {\n var bytes = msg;\n var i, j;\n if (typeof msg === 'string') {\n bytes = [];\n for (i = 0; i < msg.length; i += 2) {\n bytes.push(parseInt(msg.substring(i, i + 2), 16));\n }\n }\n var version = bytes[0];\n if (version != this.PROTOCOL_VERSION) {\n return {error: \"protocol version \" + version + \" doesn't match v2\"};\n }\n var deviceId = this.read_int(bytes, 1);\n var flags = this.read_int(bytes, 3);\n var result = {'protocol_version': version, 'device_id': deviceId};\n // decode payload\n var pos = 5;\n for (i = 0; i < this.SENSORS.length; i++, flags >>= 1) {\n if ((flags & 1) !== 1)\n continue;\n var sensor = this.SENSORS[i];\n var x = [];\n // convert data to 16-bit integer array\n for (j = 0; j < sensor.length; j++) {\n x.push(this.read_int(bytes, pos));\n pos += 2;\n }\n // decode sensor values\n for (j = 0; j < sensor.values.length; j++) {\n var value = sensor.values[j];\n if ('convert' in value) {\n result[value.name] = {displayName: value.displayName,\n value: value.convert.bind(this)(x)};\n if ('unit' in value)\n result[value.name]['unit'] = value.unit;\n }\n }\n }\n return result;\n }\n };\n\n const decoded = decentlab_decoder.decode(payload);\n const result = {};\n for (var k in decoded) {\n if (typeof decoded[k] === \"object\") {\n result[k] = decoded[k].value;\n } else if (typeof decoded[k] === \"number\") {\n result[k] = decoded[k];\n }\n }\n return result;\n}\n\nfunction extractNetworkTelemetry(payload) {\n const result = {\n lora_frame_counter: message.uplink_message.f_cnt,\n lora_frame_port: message.uplink_message.f_port,\n lora_frequency: parseInt(message.uplink_message.settings.frequency),\n lora_dev_eui: message.end_device_ids.dev_eui,\n lora_spreading_factor:\n message.uplink_message.settings.data_rate.lora.spreading_factor,\n };\n const gwi = message.uplink_message.rx_metadata\n .map((x) => ({ lora_rssi: x.rssi, lora_snr: x.snr }))\n .reduce((a, x) => (x.lora_rssi > a.lora_rssi ? x : a), {\n lora_rssi: -Number.MAX_VALUE,\n });\n return Object.assign(result, gwi);\n}\n\n// Helper functions\n\nfunction decodeToJson(payload) {\n const s = String.fromCharCode.apply(String, payload);\n return JSON.parse(s);\n}\n\nfunction parseDateToTimestamp(dateString) {\n var timestamp = -1;\n if (dateString != null) {\n timestamp = new Date(dateString).getTime();\n if (timestamp == -1) {\n var secondsSeparatorIndex = dateString.lastIndexOf('.') + 1;\n var millisecondsEndIndex = dateString.lastIndexOf('+');\n if (millisecondsEndIndex == -1) {\n millisecondsEndIndex = dateString.lastIndexOf('Z');\n }\n if (millisecondsEndIndex == -1) {\n millisecondsEndIndex = dateString.lastIndexOf('-');\n }\n if (millisecondsEndIndex == -1) {\n if (dateString.length >= secondsSeparatorIndex + 3) {\n dateString = dateString.substring(0, secondsSeparatorIndex + 3);\n }\n } else {\n dateString = dateString.substring(0, secondsSeparatorIndex + 3) +\n dateString.substring(millisecondsEndIndex, dateString.length);\n }\n timestamp = new Date(dateString).getTime();\n }\n }\n // If we cannot parse timestamp - we will use the current timestamp\n if (timestamp == -1) {\n timestamp = Date.now();\n }\n\n return timestamp;\n}\n\nfunction base64ToBytes(base64String) {\n if (typeof base64String === 'string') {\n return Uint8Array.from(atob(base64String), c => c.charCodeAt(0));\n }\n return [];\n}\n\nfunction keepTelemetry(telemetry) {\n const unwanted = ['protocol_version', 'device_id', 'lora_dev_eui'];\n return Object.fromEntries(\n Object.entries(telemetry).filter(\n (x) => !unwanted.includes(x[0])\n )\n );\n}" + "decoder": "// WARNING: This script is designed to work with a remote JS executor. Compatibility with a local JS evaluator is not guaranteed and may require rewriting.\n\nconst message = decodeToJson(payload);\nconst values = Object.assign(\n decodeDevicePayload(base64ToBytes(message.uplink_message.frm_payload)),\n extractNetworkTelemetry(message)\n);\n\nreturn {\n deviceName: String(values.device_id),\n deviceType: 'DL-SHT35-001',\n attributes: {\n lora_dev_eui: values.lora_dev_eui,\n protocol_version: values.protocol_version,\n },\n telemetry: [{\n ts: parseDateToTimestamp(message.received_at),\n values: keepTelemetry(values)\n }]\n};\n\nfunction decodeDevicePayload(payload) {\n /* https://www.decentlab.com/products/air-temperature-and-humidity-sensor-with-radiation-shield-for-lorawan */\n const decentlab_decoder = {\n PROTOCOL_VERSION: 2,\n SENSORS: [\n {length: 2,\n values: [{name: 'air_temperature',\n displayName: 'Air temperature',\n convert: function (x) { return 175 * x[0] / 65535 - 45; },\n unit: '°C'},\n {name: 'air_humidity',\n displayName: 'Air humidity',\n convert: function (x) { return 100 * x[1] / 65535; },\n unit: '%'}]},\n {length: 1,\n values: [{name: 'battery_voltage',\n displayName: 'Battery voltage',\n convert: function (x) { return x[0] / 1000; },\n unit: 'V'}]}\n ],\n read_int: function (bytes, pos) {\n return (bytes[pos] << 8) + bytes[pos + 1];\n },\n decode: function (msg) {\n var bytes = msg;\n var i, j;\n if (typeof msg === 'string') {\n bytes = [];\n for (i = 0; i < msg.length; i += 2) {\n bytes.push(parseInt(msg.substring(i, i + 2), 16));\n }\n }\n var version = bytes[0];\n if (version != this.PROTOCOL_VERSION) {\n return {error: \"protocol version \" + version + \" doesn't match v2\"};\n }\n var deviceId = this.read_int(bytes, 1);\n var flags = this.read_int(bytes, 3);\n var result = {'protocol_version': version, 'device_id': deviceId};\n // decode payload\n var pos = 5;\n for (i = 0; i < this.SENSORS.length; i++, flags >>= 1) {\n if ((flags & 1) !== 1)\n continue;\n var sensor = this.SENSORS[i];\n var x = [];\n // convert data to 16-bit integer array\n for (j = 0; j < sensor.length; j++) {\n x.push(this.read_int(bytes, pos));\n pos += 2;\n }\n // decode sensor values\n for (j = 0; j < sensor.values.length; j++) {\n var value = sensor.values[j];\n if ('convert' in value) {\n result[value.name] = {displayName: value.displayName,\n value: value.convert.bind(this)(x)};\n if ('unit' in value)\n result[value.name]['unit'] = value.unit;\n }\n }\n }\n return result;\n }\n };\n\n const decoded = decentlab_decoder.decode(payload);\n const result = {};\n for (var k in decoded) {\n if (typeof decoded[k] === \"object\") {\n result[k] = decoded[k].value;\n } else if (typeof decoded[k] === \"number\") {\n result[k] = decoded[k];\n }\n }\n return result;\n}\n\nfunction extractNetworkTelemetry(payload) {\n const result = {\n lora_frame_counter: message.uplink_message.f_cnt,\n lora_frame_port: message.uplink_message.f_port,\n lora_frequency: parseInt(message.uplink_message.settings.frequency),\n lora_dev_eui: message.end_device_ids.dev_eui,\n lora_spreading_factor:\n message.uplink_message.settings.data_rate.lora.spreading_factor,\n };\n const gwi = message.uplink_message.rx_metadata\n .map((x) => ({ lora_rssi: x.rssi, lora_snr: x.snr }))\n .reduce((a, x) => (x.lora_rssi > a.lora_rssi ? x : a), {\n lora_rssi: -Number.MAX_VALUE,\n });\n return Object.assign(result, gwi);\n}\n\n// Helper functions\n\nfunction decodeToJson(payload) {\n const s = String.fromCharCode.apply(String, payload);\n return JSON.parse(s);\n}\n\nfunction parseDateToTimestamp(dateString) {\n var timestamp = -1;\n if (dateString != null) {\n timestamp = new Date(dateString).getTime();\n if (timestamp == -1) {\n var secondsSeparatorIndex = dateString.lastIndexOf('.') + 1;\n var millisecondsEndIndex = dateString.lastIndexOf('+');\n if (millisecondsEndIndex == -1) {\n millisecondsEndIndex = dateString.lastIndexOf('Z');\n }\n if (millisecondsEndIndex == -1) {\n millisecondsEndIndex = dateString.lastIndexOf('-');\n }\n if (millisecondsEndIndex == -1) {\n if (dateString.length >= secondsSeparatorIndex + 3) {\n dateString = dateString.substring(0, secondsSeparatorIndex + 3);\n }\n } else {\n dateString = dateString.substring(0, secondsSeparatorIndex + 3) +\n dateString.substring(millisecondsEndIndex, dateString.length);\n }\n timestamp = new Date(dateString).getTime();\n }\n }\n // If we cannot parse timestamp - we will use the current timestamp\n if (timestamp == -1) {\n timestamp = Date.now();\n }\n\n return timestamp;\n}\n\nfunction base64ToBytes(base64String) {\n if (typeof base64String === 'string') {\n return Uint8Array.from(atob(base64String), c => c.charCodeAt(0));\n }\n return [];\n}\n\nfunction keepTelemetry(telemetry) {\n const unwanted = ['protocol_version', 'device_id', 'lora_dev_eui'];\n return Object.fromEntries(\n Object.entries(telemetry).filter(\n (x) => !unwanted.includes(x[0])\n )\n );\n}" } } \ No newline at end of file diff --git a/VENDORS/Decentlab/DL-SHT35-001/ThingsStackCommunity/uplink/result.json b/VENDORS/Decentlab/DL-SHT35-001/ThingsStackCommunity/uplink/result.json index 2c54fb05..556d71b8 100644 --- a/VENDORS/Decentlab/DL-SHT35-001/ThingsStackCommunity/uplink/result.json +++ b/VENDORS/Decentlab/DL-SHT35-001/ThingsStackCommunity/uplink/result.json @@ -1,6 +1,6 @@ { "deviceName": "782", - "deviceType": "DL-SHT35", + "deviceType": "DL-SHT35-001", "attributes": { "lora_dev_eui": "70B3D57BA0000BCE", "protocol_version": 2 diff --git a/VENDORS/Decentlab/DL-SHT35-001/ThingsStackCommunity/uplink/result_01.json b/VENDORS/Decentlab/DL-SHT35-001/ThingsStackCommunity/uplink/result_01.json index 17298040..c7da9207 100644 --- a/VENDORS/Decentlab/DL-SHT35-001/ThingsStackCommunity/uplink/result_01.json +++ b/VENDORS/Decentlab/DL-SHT35-001/ThingsStackCommunity/uplink/result_01.json @@ -1,6 +1,6 @@ { "deviceName": "782", - "deviceType": "DL-SHT35", + "deviceType": "DL-SHT35-001", "attributes": { "lora_dev_eui": "70B3D57BA0000BCE", "protocol_version": 2 diff --git a/VENDORS/Decentlab/DL-SHT35-001/ThingsStackIndustries/uplink/converter.json b/VENDORS/Decentlab/DL-SHT35-001/ThingsStackIndustries/uplink/converter.json index 0f49c3d4..02223686 100644 --- a/VENDORS/Decentlab/DL-SHT35-001/ThingsStackIndustries/uplink/converter.json +++ b/VENDORS/Decentlab/DL-SHT35-001/ThingsStackIndustries/uplink/converter.json @@ -14,6 +14,6 @@ "lora_dev_eui", "lora_snr" ], - "decoder": "// WARNING: This script is designed to work with a remote JS executor. Compatibility with a local JS evaluator is not guaranteed and may require rewriting.\n\nconst message = decodeToJson(payload);\nconst values = Object.assign(\n decodeDevicePayload(base64ToBytes(message.uplink_message.frm_payload)),\n extractNetworkTelemetry(message)\n);\n\nreturn {\n deviceName: String(values.device_id),\n deviceType: 'DL-SHT35',\n attributes: {\n lora_dev_eui: values.lora_dev_eui,\n protocol_version: values.protocol_version,\n },\n telemetry: [{\n ts: parseDateToTimestamp(message.received_at),\n values: keepTelemetry(values)\n }]\n};\n\nfunction decodeDevicePayload(payload) {\n /* https://www.decentlab.com/products/air-temperature-and-humidity-sensor-with-radiation-shield-for-lorawan */\n const decentlab_decoder = {\n PROTOCOL_VERSION: 2,\n SENSORS: [\n {length: 2,\n values: [{name: 'air_temperature',\n displayName: 'Air temperature',\n convert: function (x) { return 175 * x[0] / 65535 - 45; },\n unit: '°C'},\n {name: 'air_humidity',\n displayName: 'Air humidity',\n convert: function (x) { return 100 * x[1] / 65535; },\n unit: '%'}]},\n {length: 1,\n values: [{name: 'battery_voltage',\n displayName: 'Battery voltage',\n convert: function (x) { return x[0] / 1000; },\n unit: 'V'}]}\n ],\n read_int: function (bytes, pos) {\n return (bytes[pos] << 8) + bytes[pos + 1];\n },\n decode: function (msg) {\n var bytes = msg;\n var i, j;\n if (typeof msg === 'string') {\n bytes = [];\n for (i = 0; i < msg.length; i += 2) {\n bytes.push(parseInt(msg.substring(i, i + 2), 16));\n }\n }\n var version = bytes[0];\n if (version != this.PROTOCOL_VERSION) {\n return {error: \"protocol version \" + version + \" doesn't match v2\"};\n }\n var deviceId = this.read_int(bytes, 1);\n var flags = this.read_int(bytes, 3);\n var result = {'protocol_version': version, 'device_id': deviceId};\n // decode payload\n var pos = 5;\n for (i = 0; i < this.SENSORS.length; i++, flags >>= 1) {\n if ((flags & 1) !== 1)\n continue;\n var sensor = this.SENSORS[i];\n var x = [];\n // convert data to 16-bit integer array\n for (j = 0; j < sensor.length; j++) {\n x.push(this.read_int(bytes, pos));\n pos += 2;\n }\n // decode sensor values\n for (j = 0; j < sensor.values.length; j++) {\n var value = sensor.values[j];\n if ('convert' in value) {\n result[value.name] = {displayName: value.displayName,\n value: value.convert.bind(this)(x)};\n if ('unit' in value)\n result[value.name]['unit'] = value.unit;\n }\n }\n }\n return result;\n }\n };\n\n const decoded = decentlab_decoder.decode(payload);\n const result = {};\n for (var k in decoded) {\n if (typeof decoded[k] === \"object\") {\n result[k] = decoded[k].value;\n } else if (typeof decoded[k] === \"number\") {\n result[k] = decoded[k];\n }\n }\n return result;\n}\n\nfunction extractNetworkTelemetry(payload) {\n const result = {\n lora_frame_counter: message.uplink_message.f_cnt,\n lora_frame_port: message.uplink_message.f_port,\n lora_frequency: parseInt(message.uplink_message.settings.frequency),\n lora_dev_eui: message.end_device_ids.dev_eui,\n lora_spreading_factor:\n message.uplink_message.settings.data_rate.lora.spreading_factor,\n };\n const gwi = message.uplink_message.rx_metadata\n .map((x) => ({ lora_rssi: x.rssi, lora_snr: x.snr }))\n .reduce((a, x) => (x.lora_rssi > a.lora_rssi ? x : a), {\n lora_rssi: -Number.MAX_VALUE,\n });\n return Object.assign(result, gwi);\n}\n\n// Helper functions\n\nfunction decodeToJson(payload) {\n const s = String.fromCharCode.apply(String, payload);\n return JSON.parse(s);\n}\n\nfunction parseDateToTimestamp(dateString) {\n var timestamp = -1;\n if (dateString != null) {\n timestamp = new Date(dateString).getTime();\n if (timestamp == -1) {\n var secondsSeparatorIndex = dateString.lastIndexOf('.') + 1;\n var millisecondsEndIndex = dateString.lastIndexOf('+');\n if (millisecondsEndIndex == -1) {\n millisecondsEndIndex = dateString.lastIndexOf('Z');\n }\n if (millisecondsEndIndex == -1) {\n millisecondsEndIndex = dateString.lastIndexOf('-');\n }\n if (millisecondsEndIndex == -1) {\n if (dateString.length >= secondsSeparatorIndex + 3) {\n dateString = dateString.substring(0, secondsSeparatorIndex + 3);\n }\n } else {\n dateString = dateString.substring(0, secondsSeparatorIndex + 3) +\n dateString.substring(millisecondsEndIndex, dateString.length);\n }\n timestamp = new Date(dateString).getTime();\n }\n }\n // If we cannot parse timestamp - we will use the current timestamp\n if (timestamp == -1) {\n timestamp = Date.now();\n }\n\n return timestamp;\n}\n\nfunction base64ToBytes(base64String) {\n if (typeof base64String === 'string') {\n return Uint8Array.from(atob(base64String), c => c.charCodeAt(0));\n }\n return [];\n}\n\nfunction keepTelemetry(telemetry) {\n const unwanted = ['protocol_version', 'device_id', 'lora_dev_eui'];\n return Object.fromEntries(\n Object.entries(telemetry).filter(\n (x) => !unwanted.includes(x[0])\n )\n );\n}" + "decoder": "// WARNING: This script is designed to work with a remote JS executor. Compatibility with a local JS evaluator is not guaranteed and may require rewriting.\n\nconst message = decodeToJson(payload);\nconst values = Object.assign(\n decodeDevicePayload(base64ToBytes(message.uplink_message.frm_payload)),\n extractNetworkTelemetry(message)\n);\n\nreturn {\n deviceName: String(values.device_id),\n deviceType: 'DL-SHT35-001',\n attributes: {\n lora_dev_eui: values.lora_dev_eui,\n protocol_version: values.protocol_version,\n },\n telemetry: [{\n ts: parseDateToTimestamp(message.received_at),\n values: keepTelemetry(values)\n }]\n};\n\nfunction decodeDevicePayload(payload) {\n /* https://www.decentlab.com/products/air-temperature-and-humidity-sensor-with-radiation-shield-for-lorawan */\n const decentlab_decoder = {\n PROTOCOL_VERSION: 2,\n SENSORS: [\n {length: 2,\n values: [{name: 'air_temperature',\n displayName: 'Air temperature',\n convert: function (x) { return 175 * x[0] / 65535 - 45; },\n unit: '°C'},\n {name: 'air_humidity',\n displayName: 'Air humidity',\n convert: function (x) { return 100 * x[1] / 65535; },\n unit: '%'}]},\n {length: 1,\n values: [{name: 'battery_voltage',\n displayName: 'Battery voltage',\n convert: function (x) { return x[0] / 1000; },\n unit: 'V'}]}\n ],\n read_int: function (bytes, pos) {\n return (bytes[pos] << 8) + bytes[pos + 1];\n },\n decode: function (msg) {\n var bytes = msg;\n var i, j;\n if (typeof msg === 'string') {\n bytes = [];\n for (i = 0; i < msg.length; i += 2) {\n bytes.push(parseInt(msg.substring(i, i + 2), 16));\n }\n }\n var version = bytes[0];\n if (version != this.PROTOCOL_VERSION) {\n return {error: \"protocol version \" + version + \" doesn't match v2\"};\n }\n var deviceId = this.read_int(bytes, 1);\n var flags = this.read_int(bytes, 3);\n var result = {'protocol_version': version, 'device_id': deviceId};\n // decode payload\n var pos = 5;\n for (i = 0; i < this.SENSORS.length; i++, flags >>= 1) {\n if ((flags & 1) !== 1)\n continue;\n var sensor = this.SENSORS[i];\n var x = [];\n // convert data to 16-bit integer array\n for (j = 0; j < sensor.length; j++) {\n x.push(this.read_int(bytes, pos));\n pos += 2;\n }\n // decode sensor values\n for (j = 0; j < sensor.values.length; j++) {\n var value = sensor.values[j];\n if ('convert' in value) {\n result[value.name] = {displayName: value.displayName,\n value: value.convert.bind(this)(x)};\n if ('unit' in value)\n result[value.name]['unit'] = value.unit;\n }\n }\n }\n return result;\n }\n };\n\n const decoded = decentlab_decoder.decode(payload);\n const result = {};\n for (var k in decoded) {\n if (typeof decoded[k] === \"object\") {\n result[k] = decoded[k].value;\n } else if (typeof decoded[k] === \"number\") {\n result[k] = decoded[k];\n }\n }\n return result;\n}\n\nfunction extractNetworkTelemetry(payload) {\n const result = {\n lora_frame_counter: message.uplink_message.f_cnt,\n lora_frame_port: message.uplink_message.f_port,\n lora_frequency: parseInt(message.uplink_message.settings.frequency),\n lora_dev_eui: message.end_device_ids.dev_eui,\n lora_spreading_factor:\n message.uplink_message.settings.data_rate.lora.spreading_factor,\n };\n const gwi = message.uplink_message.rx_metadata\n .map((x) => ({ lora_rssi: x.rssi, lora_snr: x.snr }))\n .reduce((a, x) => (x.lora_rssi > a.lora_rssi ? x : a), {\n lora_rssi: -Number.MAX_VALUE,\n });\n return Object.assign(result, gwi);\n}\n\n// Helper functions\n\nfunction decodeToJson(payload) {\n const s = String.fromCharCode.apply(String, payload);\n return JSON.parse(s);\n}\n\nfunction parseDateToTimestamp(dateString) {\n var timestamp = -1;\n if (dateString != null) {\n timestamp = new Date(dateString).getTime();\n if (timestamp == -1) {\n var secondsSeparatorIndex = dateString.lastIndexOf('.') + 1;\n var millisecondsEndIndex = dateString.lastIndexOf('+');\n if (millisecondsEndIndex == -1) {\n millisecondsEndIndex = dateString.lastIndexOf('Z');\n }\n if (millisecondsEndIndex == -1) {\n millisecondsEndIndex = dateString.lastIndexOf('-');\n }\n if (millisecondsEndIndex == -1) {\n if (dateString.length >= secondsSeparatorIndex + 3) {\n dateString = dateString.substring(0, secondsSeparatorIndex + 3);\n }\n } else {\n dateString = dateString.substring(0, secondsSeparatorIndex + 3) +\n dateString.substring(millisecondsEndIndex, dateString.length);\n }\n timestamp = new Date(dateString).getTime();\n }\n }\n // If we cannot parse timestamp - we will use the current timestamp\n if (timestamp == -1) {\n timestamp = Date.now();\n }\n\n return timestamp;\n}\n\nfunction base64ToBytes(base64String) {\n if (typeof base64String === 'string') {\n return Uint8Array.from(atob(base64String), c => c.charCodeAt(0));\n }\n return [];\n}\n\nfunction keepTelemetry(telemetry) {\n const unwanted = ['protocol_version', 'device_id', 'lora_dev_eui'];\n return Object.fromEntries(\n Object.entries(telemetry).filter(\n (x) => !unwanted.includes(x[0])\n )\n );\n}" } } \ No newline at end of file diff --git a/VENDORS/Decentlab/DL-SHT35-001/ThingsStackIndustries/uplink/result.json b/VENDORS/Decentlab/DL-SHT35-001/ThingsStackIndustries/uplink/result.json index 2c54fb05..556d71b8 100644 --- a/VENDORS/Decentlab/DL-SHT35-001/ThingsStackIndustries/uplink/result.json +++ b/VENDORS/Decentlab/DL-SHT35-001/ThingsStackIndustries/uplink/result.json @@ -1,6 +1,6 @@ { "deviceName": "782", - "deviceType": "DL-SHT35", + "deviceType": "DL-SHT35-001", "attributes": { "lora_dev_eui": "70B3D57BA0000BCE", "protocol_version": 2 diff --git a/VENDORS/Decentlab/DL-SHT35-001/ThingsStackIndustries/uplink/result_01.json b/VENDORS/Decentlab/DL-SHT35-001/ThingsStackIndustries/uplink/result_01.json index 17298040..c7da9207 100644 --- a/VENDORS/Decentlab/DL-SHT35-001/ThingsStackIndustries/uplink/result_01.json +++ b/VENDORS/Decentlab/DL-SHT35-001/ThingsStackIndustries/uplink/result_01.json @@ -1,6 +1,6 @@ { "deviceName": "782", - "deviceType": "DL-SHT35", + "deviceType": "DL-SHT35-001", "attributes": { "lora_dev_eui": "70B3D57BA0000BCE", "protocol_version": 2 From 48f2aa928b20d4b89f9130bb179cd457642ccc7e Mon Sep 17 00:00:00 2001 From: Decentlab <17007399+decentlab@users.noreply.github.com> Date: Tue, 17 Dec 2024 12:16:55 +0100 Subject: [PATCH 08/33] Add Decentlab DL-SHT35-002 --- .../ChirpStack/uplink/converter.json | 19 +++++ .../ChirpStack/uplink/metadata.json | 4 + .../ChirpStack/uplink/payload.json | 55 +++++++++++++ .../ChirpStack/uplink/payload_01.json | 55 +++++++++++++ .../ChirpStack/uplink/payload_02.json | 46 +++++++++++ .../ChirpStack/uplink/payload_03.json | 46 +++++++++++ .../ChirpStack/uplink/result.json | 24 ++++++ .../ChirpStack/uplink/result_01.json | 22 +++++ .../ChirpStack/uplink/result_02.json | 23 ++++++ .../ChirpStack/uplink/result_03.json | 21 +++++ .../DL-SHT35-002/LORIOT/uplink/converter.json | 19 +++++ .../DL-SHT35-002/LORIOT/uplink/metadata.json | 4 + .../DL-SHT35-002/LORIOT/uplink/payload.json | 13 +++ .../LORIOT/uplink/payload_01.json | 13 +++ .../DL-SHT35-002/LORIOT/uplink/result.json | 24 ++++++ .../DL-SHT35-002/LORIOT/uplink/result_01.json | 22 +++++ .../ThingPark/uplink/converter.json | 19 +++++ .../ThingPark/uplink/metadata.json | 4 + .../ThingPark/uplink/payload.json | 75 ++++++++++++++++++ .../ThingPark/uplink/payload_01.json | 75 ++++++++++++++++++ .../DL-SHT35-002/ThingPark/uplink/result.json | 24 ++++++ .../ThingPark/uplink/result_01.json | 22 +++++ .../ThingParkEnterprise/uplink/converter.json | 19 +++++ .../ThingParkEnterprise/uplink/metadata.json | 4 + .../ThingParkEnterprise/uplink/payload.json | 75 ++++++++++++++++++ .../uplink/payload_01.json | 75 ++++++++++++++++++ .../ThingParkEnterprise/uplink/result.json | 24 ++++++ .../ThingParkEnterprise/uplink/result_01.json | 22 +++++ .../uplink/converter.json | 19 +++++ .../ThingsStackCommunity/uplink/metadata.json | 4 + .../ThingsStackCommunity/uplink/payload.json | 60 ++++++++++++++ .../uplink/payload_01.json | 60 ++++++++++++++ .../ThingsStackCommunity/uplink/result.json | 24 ++++++ .../uplink/result_01.json | 22 +++++ .../uplink/converter.json | 19 +++++ .../uplink/metadata.json | 4 + .../ThingsStackIndustries/uplink/payload.json | 60 ++++++++++++++ .../uplink/payload_01.json | 60 ++++++++++++++ .../ThingsStackIndustries/uplink/result.json | 24 ++++++ .../uplink/result_01.json | 22 +++++ VENDORS/Decentlab/DL-SHT35-002/info.json | 5 ++ VENDORS/Decentlab/DL-SHT35-002/photo.png | Bin 0 -> 1514981 bytes 42 files changed, 1231 insertions(+) create mode 100644 VENDORS/Decentlab/DL-SHT35-002/ChirpStack/uplink/converter.json create mode 100644 VENDORS/Decentlab/DL-SHT35-002/ChirpStack/uplink/metadata.json create mode 100644 VENDORS/Decentlab/DL-SHT35-002/ChirpStack/uplink/payload.json create mode 100644 VENDORS/Decentlab/DL-SHT35-002/ChirpStack/uplink/payload_01.json create mode 100644 VENDORS/Decentlab/DL-SHT35-002/ChirpStack/uplink/payload_02.json create mode 100644 VENDORS/Decentlab/DL-SHT35-002/ChirpStack/uplink/payload_03.json create mode 100644 VENDORS/Decentlab/DL-SHT35-002/ChirpStack/uplink/result.json create mode 100644 VENDORS/Decentlab/DL-SHT35-002/ChirpStack/uplink/result_01.json create mode 100644 VENDORS/Decentlab/DL-SHT35-002/ChirpStack/uplink/result_02.json create mode 100644 VENDORS/Decentlab/DL-SHT35-002/ChirpStack/uplink/result_03.json create mode 100644 VENDORS/Decentlab/DL-SHT35-002/LORIOT/uplink/converter.json create mode 100644 VENDORS/Decentlab/DL-SHT35-002/LORIOT/uplink/metadata.json create mode 100644 VENDORS/Decentlab/DL-SHT35-002/LORIOT/uplink/payload.json create mode 100644 VENDORS/Decentlab/DL-SHT35-002/LORIOT/uplink/payload_01.json create mode 100644 VENDORS/Decentlab/DL-SHT35-002/LORIOT/uplink/result.json create mode 100644 VENDORS/Decentlab/DL-SHT35-002/LORIOT/uplink/result_01.json create mode 100644 VENDORS/Decentlab/DL-SHT35-002/ThingPark/uplink/converter.json create mode 100644 VENDORS/Decentlab/DL-SHT35-002/ThingPark/uplink/metadata.json create mode 100644 VENDORS/Decentlab/DL-SHT35-002/ThingPark/uplink/payload.json create mode 100644 VENDORS/Decentlab/DL-SHT35-002/ThingPark/uplink/payload_01.json create mode 100644 VENDORS/Decentlab/DL-SHT35-002/ThingPark/uplink/result.json create mode 100644 VENDORS/Decentlab/DL-SHT35-002/ThingPark/uplink/result_01.json create mode 100644 VENDORS/Decentlab/DL-SHT35-002/ThingParkEnterprise/uplink/converter.json create mode 100644 VENDORS/Decentlab/DL-SHT35-002/ThingParkEnterprise/uplink/metadata.json create mode 100644 VENDORS/Decentlab/DL-SHT35-002/ThingParkEnterprise/uplink/payload.json create mode 100644 VENDORS/Decentlab/DL-SHT35-002/ThingParkEnterprise/uplink/payload_01.json create mode 100644 VENDORS/Decentlab/DL-SHT35-002/ThingParkEnterprise/uplink/result.json create mode 100644 VENDORS/Decentlab/DL-SHT35-002/ThingParkEnterprise/uplink/result_01.json create mode 100644 VENDORS/Decentlab/DL-SHT35-002/ThingsStackCommunity/uplink/converter.json create mode 100644 VENDORS/Decentlab/DL-SHT35-002/ThingsStackCommunity/uplink/metadata.json create mode 100644 VENDORS/Decentlab/DL-SHT35-002/ThingsStackCommunity/uplink/payload.json create mode 100644 VENDORS/Decentlab/DL-SHT35-002/ThingsStackCommunity/uplink/payload_01.json create mode 100644 VENDORS/Decentlab/DL-SHT35-002/ThingsStackCommunity/uplink/result.json create mode 100644 VENDORS/Decentlab/DL-SHT35-002/ThingsStackCommunity/uplink/result_01.json create mode 100644 VENDORS/Decentlab/DL-SHT35-002/ThingsStackIndustries/uplink/converter.json create mode 100644 VENDORS/Decentlab/DL-SHT35-002/ThingsStackIndustries/uplink/metadata.json create mode 100644 VENDORS/Decentlab/DL-SHT35-002/ThingsStackIndustries/uplink/payload.json create mode 100644 VENDORS/Decentlab/DL-SHT35-002/ThingsStackIndustries/uplink/payload_01.json create mode 100644 VENDORS/Decentlab/DL-SHT35-002/ThingsStackIndustries/uplink/result.json create mode 100644 VENDORS/Decentlab/DL-SHT35-002/ThingsStackIndustries/uplink/result_01.json create mode 100644 VENDORS/Decentlab/DL-SHT35-002/info.json create mode 100644 VENDORS/Decentlab/DL-SHT35-002/photo.png diff --git a/VENDORS/Decentlab/DL-SHT35-002/ChirpStack/uplink/converter.json b/VENDORS/Decentlab/DL-SHT35-002/ChirpStack/uplink/converter.json new file mode 100644 index 00000000..29d5f734 --- /dev/null +++ b/VENDORS/Decentlab/DL-SHT35-002/ChirpStack/uplink/converter.json @@ -0,0 +1,19 @@ +{ + "name": "ChirpStack Uplink Decoder for Decentlab DL-SHT35-002", + "type": "UPLINK", + "debugMode": true, + "edgeTemplate": false, + "configuration": { + "scriptLang": "JS", + "updateOnlyKeys": [ + "lora_frame_counter", + "lora_frame_port", + "lora_frequency", + "lora_spreading_factor", + "lora_rssi", + "lora_dev_eui", + "lora_snr" + ], + "decoder": "// WARNING: This script is designed to work with a remote JS executor. Compatibility with a local JS evaluator is not guaranteed and may require rewriting.\n\nconst message = decodeToJson(payload);\nconst values = Object.assign(\n decodeDevicePayload(base64ToBytes(message.data)),\n extractNetworkTelemetry(message)\n);\n\nreturn {\n deviceName: String(values.device_id),\n deviceType: 'DL-SHT35-002',\n attributes: {\n lora_dev_eui: values.lora_dev_eui,\n protocol_version: values.protocol_version,\n },\n telemetry: [{\n ts: message.time,\n values: keepTelemetry(values)\n }]\n};\n\nfunction decodeDevicePayload(payload) {\n /* https://www.decentlab.com/products/air-temperature-and-humidity-sensor-with-radiation-shield-for-lorawan */\n const decentlab_decoder = {\n PROTOCOL_VERSION: 2,\n SENSORS: [\n {length: 2,\n values: [{name: 'air_temperature',\n displayName: 'Air temperature',\n convert: function (x) { return 175 * x[0] / 65535 - 45; },\n unit: '°C'},\n {name: 'air_humidity',\n displayName: 'Air humidity',\n convert: function (x) { return 100 * x[1] / 65535; },\n unit: '%'}]},\n {length: 1,\n values: [{name: 'battery_voltage',\n displayName: 'Battery voltage',\n convert: function (x) { return x[0] / 1000; },\n unit: 'V'}]}\n ],\n read_int: function (bytes, pos) {\n return (bytes[pos] << 8) + bytes[pos + 1];\n },\n decode: function (msg) {\n var bytes = msg;\n var i, j;\n if (typeof msg === 'string') {\n bytes = [];\n for (i = 0; i < msg.length; i += 2) {\n bytes.push(parseInt(msg.substring(i, i + 2), 16));\n }\n }\n var version = bytes[0];\n if (version != this.PROTOCOL_VERSION) {\n return {error: \"protocol version \" + version + \" doesn't match v2\"};\n }\n var deviceId = this.read_int(bytes, 1);\n var flags = this.read_int(bytes, 3);\n var result = {'protocol_version': version, 'device_id': deviceId};\n // decode payload\n var pos = 5;\n for (i = 0; i < this.SENSORS.length; i++, flags >>= 1) {\n if ((flags & 1) !== 1)\n continue;\n var sensor = this.SENSORS[i];\n var x = [];\n // convert data to 16-bit integer array\n for (j = 0; j < sensor.length; j++) {\n x.push(this.read_int(bytes, pos));\n pos += 2;\n }\n // decode sensor values\n for (j = 0; j < sensor.values.length; j++) {\n var value = sensor.values[j];\n if ('convert' in value) {\n result[value.name] = {displayName: value.displayName,\n value: value.convert.bind(this)(x)};\n if ('unit' in value)\n result[value.name]['unit'] = value.unit;\n }\n }\n }\n return result;\n }\n };\n\n const decoded = decentlab_decoder.decode(payload);\n const result = {};\n for (var k in decoded) {\n if (typeof decoded[k] === \"object\") {\n result[k] = decoded[k].value;\n } else if (typeof decoded[k] === \"number\") {\n result[k] = decoded[k];\n }\n }\n return result;\n}\n\nfunction extractNetworkTelemetry(payload) {\n const result = {\n lora_frame_counter: message.fCnt,\n lora_frame_port: message.fPort,\n lora_frequency: message.txInfo.frequency,\n lora_spreading_factor:\n message?.txInfo?.modulation?.lora?.spreadingFactor ||\n message.txInfo.loRaModulationInfo.spreadingFactor,\n lora_dev_eui: (\n message?.deviceInfo?.devEui ||\n base64ToBytes(message.devEUI).reduce(\n (a, x) => a + (\"0\" + x.toString(16)).slice(-2),\n \"\",\n )\n ).toUpperCase(),\n };\n const gwi = message.rxInfo\n .map((x) => ({ lora_rssi: x.rssi, lora_snr: x.snr || x.loRaSNR }))\n .reduce((a, x) => (x.lora_rssi > a.lora_rssi ? x : a), {\n lora_rssi: -Number.MAX_VALUE,\n });\n return Object.assign(result, gwi);\n}\n\n// Helper functions\n\nfunction decodeToJson(payload) {\n const s = String.fromCharCode.apply(String, payload);\n return JSON.parse(s);\n}\n\nfunction parseDateToTimestamp(dateString) {\n var timestamp = -1;\n if (dateString != null) {\n timestamp = new Date(dateString).getTime();\n if (timestamp == -1) {\n var secondsSeparatorIndex = dateString.lastIndexOf('.') + 1;\n var millisecondsEndIndex = dateString.lastIndexOf('+');\n if (millisecondsEndIndex == -1) {\n millisecondsEndIndex = dateString.lastIndexOf('Z');\n }\n if (millisecondsEndIndex == -1) {\n millisecondsEndIndex = dateString.lastIndexOf('-');\n }\n if (millisecondsEndIndex == -1) {\n if (dateString.length >= secondsSeparatorIndex + 3) {\n dateString = dateString.substring(0, secondsSeparatorIndex + 3);\n }\n } else {\n dateString = dateString.substring(0, secondsSeparatorIndex + 3) +\n dateString.substring(millisecondsEndIndex, dateString.length);\n }\n timestamp = new Date(dateString).getTime();\n }\n }\n // If we cannot parse timestamp - we will use the current timestamp\n if (timestamp == -1) {\n timestamp = Date.now();\n }\n\n return timestamp;\n}\n\nfunction base64ToBytes(base64String) {\n if (typeof base64String === 'string') {\n return Uint8Array.from(atob(base64String), c => c.charCodeAt(0));\n }\n return [];\n}\n\nfunction keepTelemetry(telemetry) {\n const unwanted = ['protocol_version', 'device_id', 'lora_dev_eui'];\n return Object.fromEntries(\n Object.entries(telemetry).filter(\n (x) => !unwanted.includes(x[0])\n )\n );\n}" + } +} diff --git a/VENDORS/Decentlab/DL-SHT35-002/ChirpStack/uplink/metadata.json b/VENDORS/Decentlab/DL-SHT35-002/ChirpStack/uplink/metadata.json new file mode 100644 index 00000000..1f9359b9 --- /dev/null +++ b/VENDORS/Decentlab/DL-SHT35-002/ChirpStack/uplink/metadata.json @@ -0,0 +1,4 @@ +{ + "integrationName": "ChirpStack integration", + "includeGatewayInfo": false +} \ No newline at end of file diff --git a/VENDORS/Decentlab/DL-SHT35-002/ChirpStack/uplink/payload.json b/VENDORS/Decentlab/DL-SHT35-002/ChirpStack/uplink/payload.json new file mode 100644 index 00000000..e524f89c --- /dev/null +++ b/VENDORS/Decentlab/DL-SHT35-002/ChirpStack/uplink/payload.json @@ -0,0 +1,55 @@ +{ + "adr": true, + "confirmed": false, + "data": "AgMOAANkoHmxDGA=", + "deduplicationId": "ede7dfc1-a1f5-418c-b009-dc57ebcf0895", + "devAddr": "017d1f70", + "deviceInfo": { + "applicationId": "32dafeb5-0865-4edd-bf1c-3f8d9b07af52", + "applicationName": "MoDus-Sain", + "devEui": "70b3d57ba0003bb8", + "deviceClassEnabled": "CLASS_A", + "deviceName": "PM-15288", + "deviceProfileId": "7ec3de3f-7b87-49ae-8f32-330249122a50", + "deviceProfileName": "dev-prof-Decentlab", + "tags": { + "lts": "true" + }, + "tenantId": "663cc43f-0bf2-48d4-afc6-ff27ba969f10", + "tenantName": "Friloranet" + }, + "dr": 5, + "fCnt": 20, + "fPort": 1, + "rxInfo": [ + { + "context": "AAAAAAAAAAAA/gADaoXb7A==", + "crcStatus": "CRC_OK", + "gatewayId": "fcc23dfffe2e72ed", + "gwTime": "2024-11-12T12:51:50+00:00", + "location": { + "latitude": 46.80179269386121, + "longitude": 7.1381521224975595 + }, + "metadata": { + "region_common_name": "EU868", + "region_config_id": "eu868" + }, + "nsTime": "2024-11-12T12:51:50.819853185+00:00", + "rssi": -106, + "snr": 3.0, + "uplinkId": 3257702911 + } + ], + "time": "2024-11-10T12:51:50+00:00", + "txInfo": { + "frequency": 868300000, + "modulation": { + "lora": { + "bandwidth": 125000, + "codeRate": "CR_4_5", + "spreadingFactor": 7 + } + } + } +} diff --git a/VENDORS/Decentlab/DL-SHT35-002/ChirpStack/uplink/payload_01.json b/VENDORS/Decentlab/DL-SHT35-002/ChirpStack/uplink/payload_01.json new file mode 100644 index 00000000..f4b6b8b6 --- /dev/null +++ b/VENDORS/Decentlab/DL-SHT35-002/ChirpStack/uplink/payload_01.json @@ -0,0 +1,55 @@ +{ + "adr": true, + "confirmed": false, + "data": "AgMOAAIMYA==", + "deduplicationId": "ede7dfc1-a1f5-418c-b009-dc57ebcf0895", + "devAddr": "017d1f70", + "deviceInfo": { + "applicationId": "32dafeb5-0865-4edd-bf1c-3f8d9b07af52", + "applicationName": "MoDus-Sain", + "devEui": "70b3d57ba0003bb8", + "deviceClassEnabled": "CLASS_A", + "deviceName": "PM-15288", + "deviceProfileId": "7ec3de3f-7b87-49ae-8f32-330249122a50", + "deviceProfileName": "dev-prof-Decentlab", + "tags": { + "lts": "true" + }, + "tenantId": "663cc43f-0bf2-48d4-afc6-ff27ba969f10", + "tenantName": "Friloranet" + }, + "dr": 5, + "fCnt": 20, + "fPort": 1, + "rxInfo": [ + { + "context": "AAAAAAAAAAAA/gADaoXb7A==", + "crcStatus": "CRC_OK", + "gatewayId": "fcc23dfffe2e72ed", + "gwTime": "2024-11-12T12:51:50+00:00", + "location": { + "latitude": 46.80179269386121, + "longitude": 7.1381521224975595 + }, + "metadata": { + "region_common_name": "EU868", + "region_config_id": "eu868" + }, + "nsTime": "2024-11-12T12:51:50.819853185+00:00", + "rssi": -106, + "snr": 3.0, + "uplinkId": 3257702911 + } + ], + "time": "2024-11-10T12:51:50+00:00", + "txInfo": { + "frequency": 868300000, + "modulation": { + "lora": { + "bandwidth": 125000, + "codeRate": "CR_4_5", + "spreadingFactor": 7 + } + } + } +} diff --git a/VENDORS/Decentlab/DL-SHT35-002/ChirpStack/uplink/payload_02.json b/VENDORS/Decentlab/DL-SHT35-002/ChirpStack/uplink/payload_02.json new file mode 100644 index 00000000..b02a35ee --- /dev/null +++ b/VENDORS/Decentlab/DL-SHT35-002/ChirpStack/uplink/payload_02.json @@ -0,0 +1,46 @@ +{ + "applicationID": "123", + "applicationName": "temperature-sensor", + "deviceName": "garden-sensor", + "devEUI": "AgICAgICAgI=", + "rxInfo": [ + { + "gatewayID": "AwMDAwMDAwM=", + "time": "2019-11-08T13:59:25.048445Z", + "timeSinceGPSEpoch": null, + "rssi": -48, + "loRaSNR": 9, + "channel": 5, + "rfChain": 0, + "board": 0, + "antenna": 0, + "location": { + "latitude": 52.3740364, + "longitude": 4.9144401, + "altitude": 10.5 + }, + "fineTimestampType": "NONE", + "context": "9u/uvA==", + "uplinkID": "jhMh8Gq6RAOChSKbi83RHQ==" + } + ], + "txInfo": { + "frequency": 868100000, + "modulation": "LORA", + "loRaModulationInfo": { + "bandwidth": 125, + "spreadingFactor": 11, + "codeRate": "4/5", + "polarizationInversion": false + } + }, + "adr": true, + "dr": 1, + "fCnt": 10, + "fPort": 5, + "data": "AgMOAANkoHmxDGA=", + "objectJSON": "{\"temperatureSensor\":25,\"humiditySensor\":32}", + "tags": { + "key": "value" + } +} diff --git a/VENDORS/Decentlab/DL-SHT35-002/ChirpStack/uplink/payload_03.json b/VENDORS/Decentlab/DL-SHT35-002/ChirpStack/uplink/payload_03.json new file mode 100644 index 00000000..75524c99 --- /dev/null +++ b/VENDORS/Decentlab/DL-SHT35-002/ChirpStack/uplink/payload_03.json @@ -0,0 +1,46 @@ +{ + "applicationID": "123", + "applicationName": "temperature-sensor", + "deviceName": "garden-sensor", + "devEUI": "AgICAgICAgI=", + "rxInfo": [ + { + "gatewayID": "AwMDAwMDAwM=", + "time": "2019-11-08T13:59:25.048445Z", + "timeSinceGPSEpoch": null, + "rssi": -48, + "loRaSNR": 9, + "channel": 5, + "rfChain": 0, + "board": 0, + "antenna": 0, + "location": { + "latitude": 52.3740364, + "longitude": 4.9144401, + "altitude": 10.5 + }, + "fineTimestampType": "NONE", + "context": "9u/uvA==", + "uplinkID": "jhMh8Gq6RAOChSKbi83RHQ==" + } + ], + "txInfo": { + "frequency": 868100000, + "modulation": "LORA", + "loRaModulationInfo": { + "bandwidth": 125, + "spreadingFactor": 11, + "codeRate": "4/5", + "polarizationInversion": false + } + }, + "adr": true, + "dr": 1, + "fCnt": 10, + "fPort": 5, + "data": "AgMOAAIMYA==", + "objectJSON": "{\"temperatureSensor\":25,\"humiditySensor\":32}", + "tags": { + "key": "value" + } +} diff --git a/VENDORS/Decentlab/DL-SHT35-002/ChirpStack/uplink/result.json b/VENDORS/Decentlab/DL-SHT35-002/ChirpStack/uplink/result.json new file mode 100644 index 00000000..becc32c5 --- /dev/null +++ b/VENDORS/Decentlab/DL-SHT35-002/ChirpStack/uplink/result.json @@ -0,0 +1,24 @@ +{ + "deviceName": "782", + "deviceType": "DL-SHT35-002", + "attributes": { + "lora_dev_eui": "70B3D57BA0003BB8", + "protocol_version": 2 + }, + "telemetry": [ + { + "ts": "2024-11-10T12:51:50+00:00", + "values": { + "air_temperature": 23.787670710307466, + "air_humidity": 47.536430914778364, + "battery_voltage": 3.168, + "lora_frame_counter": 20, + "lora_frame_port": 1, + "lora_frequency": 868300000, + "lora_spreading_factor": 7, + "lora_rssi": -106, + "lora_snr": 3 + } + } + ] +} diff --git a/VENDORS/Decentlab/DL-SHT35-002/ChirpStack/uplink/result_01.json b/VENDORS/Decentlab/DL-SHT35-002/ChirpStack/uplink/result_01.json new file mode 100644 index 00000000..ef238e28 --- /dev/null +++ b/VENDORS/Decentlab/DL-SHT35-002/ChirpStack/uplink/result_01.json @@ -0,0 +1,22 @@ +{ + "deviceName": "782", + "deviceType": "DL-SHT35-002", + "attributes": { + "lora_dev_eui": "70B3D57BA0003BB8", + "protocol_version": 2 + }, + "telemetry": [ + { + "ts": "2024-11-10T12:51:50+00:00", + "values": { + "battery_voltage": 3.168, + "lora_frame_counter": 20, + "lora_frame_port": 1, + "lora_frequency": 868300000, + "lora_spreading_factor": 7, + "lora_rssi": -106, + "lora_snr": 3 + } + } + ] +} diff --git a/VENDORS/Decentlab/DL-SHT35-002/ChirpStack/uplink/result_02.json b/VENDORS/Decentlab/DL-SHT35-002/ChirpStack/uplink/result_02.json new file mode 100644 index 00000000..5289a4a3 --- /dev/null +++ b/VENDORS/Decentlab/DL-SHT35-002/ChirpStack/uplink/result_02.json @@ -0,0 +1,23 @@ +{ + "deviceName": "782", + "deviceType": "DL-SHT35-002", + "attributes": { + "lora_dev_eui": "0202020202020202", + "protocol_version": 2 + }, + "telemetry": [ + { + "values": { + "air_temperature": 23.787670710307466, + "air_humidity": 47.536430914778364, + "battery_voltage": 3.168, + "lora_frame_counter": 10, + "lora_frame_port": 5, + "lora_frequency": 868100000, + "lora_spreading_factor": 11, + "lora_rssi": -48, + "lora_snr": 9 + } + } + ] +} diff --git a/VENDORS/Decentlab/DL-SHT35-002/ChirpStack/uplink/result_03.json b/VENDORS/Decentlab/DL-SHT35-002/ChirpStack/uplink/result_03.json new file mode 100644 index 00000000..ada74806 --- /dev/null +++ b/VENDORS/Decentlab/DL-SHT35-002/ChirpStack/uplink/result_03.json @@ -0,0 +1,21 @@ +{ + "deviceName": "782", + "deviceType": "DL-SHT35-002", + "attributes": { + "lora_dev_eui": "0202020202020202", + "protocol_version": 2 + }, + "telemetry": [ + { + "values": { + "battery_voltage": 3.168, + "lora_frame_counter": 10, + "lora_frame_port": 5, + "lora_frequency": 868100000, + "lora_spreading_factor": 11, + "lora_rssi": -48, + "lora_snr": 9 + } + } + ] +} diff --git a/VENDORS/Decentlab/DL-SHT35-002/LORIOT/uplink/converter.json b/VENDORS/Decentlab/DL-SHT35-002/LORIOT/uplink/converter.json new file mode 100644 index 00000000..9207d027 --- /dev/null +++ b/VENDORS/Decentlab/DL-SHT35-002/LORIOT/uplink/converter.json @@ -0,0 +1,19 @@ +{ + "name": "LORIOT Uplink Decoder for Decentlab DL-SHT35-002", + "type": "UPLINK", + "debugMode": true, + "edgeTemplate": false, + "configuration": { + "scriptLang": "JS", + "updateOnlyKeys": [ + "lora_frame_counter", + "lora_frame_port", + "lora_frequency", + "lora_spreading_factor", + "lora_rssi", + "lora_dev_eui", + "lora_snr" + ], + "decoder": "// WARNING: This script is designed to work with a remote JS executor. Compatibility with a local JS evaluator is not guaranteed and may require rewriting.\n\nconst message = decodeToJson(payload);\nconst values = Object.assign(\n decodeDevicePayload(message.data),\n extractNetworkTelemetry(message)\n);\n\nreturn {\n deviceName: String(values.device_id),\n deviceType: 'DL-SHT35-002',\n attributes: {\n lora_dev_eui: values.lora_dev_eui,\n protocol_version: values.protocol_version,\n },\n telemetry: [{\n ts: message.ts,\n values: keepTelemetry(values)\n }]\n};\n\nfunction decodeDevicePayload(payload) {\n /* https://www.decentlab.com/products/air-temperature-and-humidity-sensor-with-radiation-shield-for-lorawan */\n const decentlab_decoder = {\n PROTOCOL_VERSION: 2,\n SENSORS: [\n {length: 2,\n values: [{name: 'air_temperature',\n displayName: 'Air temperature',\n convert: function (x) { return 175 * x[0] / 65535 - 45; },\n unit: '°C'},\n {name: 'air_humidity',\n displayName: 'Air humidity',\n convert: function (x) { return 100 * x[1] / 65535; },\n unit: '%'}]},\n {length: 1,\n values: [{name: 'battery_voltage',\n displayName: 'Battery voltage',\n convert: function (x) { return x[0] / 1000; },\n unit: 'V'}]}\n ],\n read_int: function (bytes, pos) {\n return (bytes[pos] << 8) + bytes[pos + 1];\n },\n decode: function (msg) {\n var bytes = msg;\n var i, j;\n if (typeof msg === 'string') {\n bytes = [];\n for (i = 0; i < msg.length; i += 2) {\n bytes.push(parseInt(msg.substring(i, i + 2), 16));\n }\n }\n var version = bytes[0];\n if (version != this.PROTOCOL_VERSION) {\n return {error: \"protocol version \" + version + \" doesn't match v2\"};\n }\n var deviceId = this.read_int(bytes, 1);\n var flags = this.read_int(bytes, 3);\n var result = {'protocol_version': version, 'device_id': deviceId};\n // decode payload\n var pos = 5;\n for (i = 0; i < this.SENSORS.length; i++, flags >>= 1) {\n if ((flags & 1) !== 1)\n continue;\n var sensor = this.SENSORS[i];\n var x = [];\n // convert data to 16-bit integer array\n for (j = 0; j < sensor.length; j++) {\n x.push(this.read_int(bytes, pos));\n pos += 2;\n }\n // decode sensor values\n for (j = 0; j < sensor.values.length; j++) {\n var value = sensor.values[j];\n if ('convert' in value) {\n result[value.name] = {displayName: value.displayName,\n value: value.convert.bind(this)(x)};\n if ('unit' in value)\n result[value.name]['unit'] = value.unit;\n }\n }\n }\n return result;\n }\n };\n\n const decoded = decentlab_decoder.decode(payload);\n const result = {};\n for (var k in decoded) {\n if (typeof decoded[k] === \"object\") {\n result[k] = decoded[k].value;\n } else if (typeof decoded[k] === \"number\") {\n result[k] = decoded[k];\n }\n }\n return result;\n}\n\nfunction extractNetworkTelemetry(payload) {\n const result = {\n lora_frame_counter: message.fcnt,\n lora_frame_port: message.port,\n lora_frequency: message.freq,\n lora_snr: message.snr,\n lora_rssi: message.rssi,\n lora_dev_eui: message.EUI,\n lora_spreading_factor: parseInt(message.dr.replace(/.*SF(\\d+).*/, '$1')),\n };\n if (message.cmd === 'gw') {\n const gwi = message.gws\n .map((x) => ({ lora_rssi: x.rssi, lora_snr: x.snr }))\n .reduce((a, x) => (x.lora_rssi > a.lora_rssi ? x : a), {\n lora_rssi: -Number.MAX_VALUE,\n });\n result.rssi = gwi.rssi;\n result.snr = gwi.snr;\n }\n return result;\n}\n\n// Helper functions\n\nfunction decodeToJson(payload) {\n const s = String.fromCharCode.apply(String, payload);\n return JSON.parse(s);\n}\n\nfunction parseDateToTimestamp(dateString) {\n var timestamp = -1;\n if (dateString != null) {\n timestamp = new Date(dateString).getTime();\n if (timestamp == -1) {\n var secondsSeparatorIndex = dateString.lastIndexOf('.') + 1;\n var millisecondsEndIndex = dateString.lastIndexOf('+');\n if (millisecondsEndIndex == -1) {\n millisecondsEndIndex = dateString.lastIndexOf('Z');\n }\n if (millisecondsEndIndex == -1) {\n millisecondsEndIndex = dateString.lastIndexOf('-');\n }\n if (millisecondsEndIndex == -1) {\n if (dateString.length >= secondsSeparatorIndex + 3) {\n dateString = dateString.substring(0, secondsSeparatorIndex + 3);\n }\n } else {\n dateString = dateString.substring(0, secondsSeparatorIndex + 3) +\n dateString.substring(millisecondsEndIndex, dateString.length);\n }\n timestamp = new Date(dateString).getTime();\n }\n }\n // If we cannot parse timestamp - we will use the current timestamp\n if (timestamp == -1) {\n timestamp = Date.now();\n }\n\n return timestamp;\n}\n\nfunction base64ToBytes(base64String) {\n if (typeof base64String === 'string') {\n return Uint8Array.from(atob(base64String), c => c.charCodeAt(0));\n }\n return [];\n}\n\nfunction keepTelemetry(telemetry) {\n const unwanted = ['protocol_version', 'device_id', 'lora_dev_eui'];\n return Object.fromEntries(\n Object.entries(telemetry).filter(\n (x) => !unwanted.includes(x[0])\n )\n );\n}" + } +} diff --git a/VENDORS/Decentlab/DL-SHT35-002/LORIOT/uplink/metadata.json b/VENDORS/Decentlab/DL-SHT35-002/LORIOT/uplink/metadata.json new file mode 100644 index 00000000..5c24f9c2 --- /dev/null +++ b/VENDORS/Decentlab/DL-SHT35-002/LORIOT/uplink/metadata.json @@ -0,0 +1,4 @@ +{ + "integrationName": "LORIOT integration", + "includeGatewayInfo": false +} \ No newline at end of file diff --git a/VENDORS/Decentlab/DL-SHT35-002/LORIOT/uplink/payload.json b/VENDORS/Decentlab/DL-SHT35-002/LORIOT/uplink/payload.json new file mode 100644 index 00000000..db896a43 --- /dev/null +++ b/VENDORS/Decentlab/DL-SHT35-002/LORIOT/uplink/payload.json @@ -0,0 +1,13 @@ +{ + "cmd": "rx", + "EUI": "0004A30B001ADCB5", + "ts": 1501064048945, + "fcnt": 121, + "port": 1, + "freq": 868300000, + "rssi": -119, + "snr": -15.8, + "dr": "SF11 BW125 4/5", + "ack": false, + "data": "02030e000364a079b10c60" +} diff --git a/VENDORS/Decentlab/DL-SHT35-002/LORIOT/uplink/payload_01.json b/VENDORS/Decentlab/DL-SHT35-002/LORIOT/uplink/payload_01.json new file mode 100644 index 00000000..5a049244 --- /dev/null +++ b/VENDORS/Decentlab/DL-SHT35-002/LORIOT/uplink/payload_01.json @@ -0,0 +1,13 @@ +{ + "cmd": "rx", + "EUI": "0004A30B001ADCB5", + "ts": 1501064048945, + "fcnt": 121, + "port": 1, + "freq": 868300000, + "rssi": -119, + "snr": -15.8, + "dr": "SF11 BW125 4/5", + "ack": false, + "data": "02030e00020c60" +} diff --git a/VENDORS/Decentlab/DL-SHT35-002/LORIOT/uplink/result.json b/VENDORS/Decentlab/DL-SHT35-002/LORIOT/uplink/result.json new file mode 100644 index 00000000..fd184c33 --- /dev/null +++ b/VENDORS/Decentlab/DL-SHT35-002/LORIOT/uplink/result.json @@ -0,0 +1,24 @@ +{ + "deviceName": "782", + "deviceType": "DL-SHT35-002", + "attributes": { + "lora_dev_eui": "0004A30B001ADCB5", + "protocol_version": 2 + }, + "telemetry": [ + { + "ts": 1501064048945, + "values": { + "air_temperature": 23.787670710307466, + "air_humidity": 47.536430914778364, + "battery_voltage": 3.168, + "lora_frame_counter": 121, + "lora_frame_port": 1, + "lora_frequency": 868300000, + "lora_snr": -15.8, + "lora_rssi": -119, + "lora_spreading_factor": 11 + } + } + ] +} diff --git a/VENDORS/Decentlab/DL-SHT35-002/LORIOT/uplink/result_01.json b/VENDORS/Decentlab/DL-SHT35-002/LORIOT/uplink/result_01.json new file mode 100644 index 00000000..7d9dabcc --- /dev/null +++ b/VENDORS/Decentlab/DL-SHT35-002/LORIOT/uplink/result_01.json @@ -0,0 +1,22 @@ +{ + "deviceName": "782", + "deviceType": "DL-SHT35-002", + "attributes": { + "lora_dev_eui": "0004A30B001ADCB5", + "protocol_version": 2 + }, + "telemetry": [ + { + "ts": 1501064048945, + "values": { + "battery_voltage": 3.168, + "lora_frame_counter": 121, + "lora_frame_port": 1, + "lora_frequency": 868300000, + "lora_snr": -15.8, + "lora_rssi": -119, + "lora_spreading_factor": 11 + } + } + ] +} diff --git a/VENDORS/Decentlab/DL-SHT35-002/ThingPark/uplink/converter.json b/VENDORS/Decentlab/DL-SHT35-002/ThingPark/uplink/converter.json new file mode 100644 index 00000000..a2e25858 --- /dev/null +++ b/VENDORS/Decentlab/DL-SHT35-002/ThingPark/uplink/converter.json @@ -0,0 +1,19 @@ +{ + "name": "ThingPark Uplink Decoder for Decentlab DL-SHT35-002", + "type": "UPLINK", + "debugMode": true, + "edgeTemplate": false, + "configuration": { + "scriptLang": "JS", + "updateOnlyKeys": [ + "lora_frame_counter", + "lora_frame_port", + "lora_frequency", + "lora_spreading_factor", + "lora_rssi", + "lora_dev_eui", + "lora_snr" + ], + "decoder": "// WARNING: This script is designed to work with a remote JS executor. Compatibility with a local JS evaluator is not guaranteed and may require rewriting.\n\nconst message = decodeToJson(payload);\nconst values = Object.assign(\n decodeDevicePayload(message.DevEUI_uplink.payload_hex),\n extractNetworkTelemetry(message)\n);\n\nreturn {\n deviceName: String(values.device_id),\n deviceType: 'DL-SHT35-002',\n attributes: {\n lora_dev_eui: values.lora_dev_eui,\n protocol_version: values.protocol_version,\n },\n telemetry: [{\n ts: parseDateToTimestamp(message.DevEUI_uplink.Time),\n values: keepTelemetry(values)\n }]\n};\n\nfunction decodeDevicePayload(payload) {\n /* https://www.decentlab.com/products/air-temperature-and-humidity-sensor-with-radiation-shield-for-lorawan */\n const decentlab_decoder = {\n PROTOCOL_VERSION: 2,\n SENSORS: [\n {length: 2,\n values: [{name: 'air_temperature',\n displayName: 'Air temperature',\n convert: function (x) { return 175 * x[0] / 65535 - 45; },\n unit: '°C'},\n {name: 'air_humidity',\n displayName: 'Air humidity',\n convert: function (x) { return 100 * x[1] / 65535; },\n unit: '%'}]},\n {length: 1,\n values: [{name: 'battery_voltage',\n displayName: 'Battery voltage',\n convert: function (x) { return x[0] / 1000; },\n unit: 'V'}]}\n ],\n read_int: function (bytes, pos) {\n return (bytes[pos] << 8) + bytes[pos + 1];\n },\n decode: function (msg) {\n var bytes = msg;\n var i, j;\n if (typeof msg === 'string') {\n bytes = [];\n for (i = 0; i < msg.length; i += 2) {\n bytes.push(parseInt(msg.substring(i, i + 2), 16));\n }\n }\n var version = bytes[0];\n if (version != this.PROTOCOL_VERSION) {\n return {error: \"protocol version \" + version + \" doesn't match v2\"};\n }\n var deviceId = this.read_int(bytes, 1);\n var flags = this.read_int(bytes, 3);\n var result = {'protocol_version': version, 'device_id': deviceId};\n // decode payload\n var pos = 5;\n for (i = 0; i < this.SENSORS.length; i++, flags >>= 1) {\n if ((flags & 1) !== 1)\n continue;\n var sensor = this.SENSORS[i];\n var x = [];\n // convert data to 16-bit integer array\n for (j = 0; j < sensor.length; j++) {\n x.push(this.read_int(bytes, pos));\n pos += 2;\n }\n // decode sensor values\n for (j = 0; j < sensor.values.length; j++) {\n var value = sensor.values[j];\n if ('convert' in value) {\n result[value.name] = {displayName: value.displayName,\n value: value.convert.bind(this)(x)};\n if ('unit' in value)\n result[value.name]['unit'] = value.unit;\n }\n }\n }\n return result;\n }\n };\n\n const decoded = decentlab_decoder.decode(payload);\n const result = {};\n for (var k in decoded) {\n if (typeof decoded[k] === \"object\") {\n result[k] = decoded[k].value;\n } else if (typeof decoded[k] === \"number\") {\n result[k] = decoded[k];\n }\n }\n return result;\n}\n\nfunction extractNetworkTelemetry(payload) {\n return {\n lora_frame_counter: message.DevEUI_uplink.FCntUp,\n lora_frame_port: message.DevEUI_uplink.FPort,\n lora_frequency: message.DevEUI_uplink?.Frequency * 1000000,\n lora_spreading_factor: message.DevEUI_uplink.SpFact,\n lora_dev_eui: message.DevEUI_uplink.DevEUI,\n lora_rssi: message.DevEUI_uplink.LrrRSSI,\n lora_snr: message.DevEUI_uplink.LrrSNR,\n };\n}\n\n// Helper functions\n\nfunction decodeToJson(payload) {\n const s = String.fromCharCode.apply(String, payload);\n return JSON.parse(s);\n}\n\nfunction parseDateToTimestamp(dateString) {\n var timestamp = -1;\n if (dateString != null) {\n timestamp = new Date(dateString).getTime();\n if (timestamp == -1) {\n var secondsSeparatorIndex = dateString.lastIndexOf('.') + 1;\n var millisecondsEndIndex = dateString.lastIndexOf('+');\n if (millisecondsEndIndex == -1) {\n millisecondsEndIndex = dateString.lastIndexOf('Z');\n }\n if (millisecondsEndIndex == -1) {\n millisecondsEndIndex = dateString.lastIndexOf('-');\n }\n if (millisecondsEndIndex == -1) {\n if (dateString.length >= secondsSeparatorIndex + 3) {\n dateString = dateString.substring(0, secondsSeparatorIndex + 3);\n }\n } else {\n dateString = dateString.substring(0, secondsSeparatorIndex + 3) +\n dateString.substring(millisecondsEndIndex, dateString.length);\n }\n timestamp = new Date(dateString).getTime();\n }\n }\n // If we cannot parse timestamp - we will use the current timestamp\n if (timestamp == -1) {\n timestamp = Date.now();\n }\n\n return timestamp;\n}\n\nfunction base64ToBytes(base64String) {\n if (typeof base64String === 'string') {\n return Uint8Array.from(atob(base64String), c => c.charCodeAt(0));\n }\n return [];\n}\n\nfunction keepTelemetry(telemetry) {\n const unwanted = ['protocol_version', 'device_id', 'lora_dev_eui'];\n return Object.fromEntries(\n Object.entries(telemetry).filter(\n (x) => !unwanted.includes(x[0])\n )\n );\n}" + } +} diff --git a/VENDORS/Decentlab/DL-SHT35-002/ThingPark/uplink/metadata.json b/VENDORS/Decentlab/DL-SHT35-002/ThingPark/uplink/metadata.json new file mode 100644 index 00000000..d024aecf --- /dev/null +++ b/VENDORS/Decentlab/DL-SHT35-002/ThingPark/uplink/metadata.json @@ -0,0 +1,4 @@ +{ + "integrationName": "ThingPark integration", + "includeGatewayInfo": false +} \ No newline at end of file diff --git a/VENDORS/Decentlab/DL-SHT35-002/ThingPark/uplink/payload.json b/VENDORS/Decentlab/DL-SHT35-002/ThingPark/uplink/payload.json new file mode 100644 index 00000000..5adfd4bc --- /dev/null +++ b/VENDORS/Decentlab/DL-SHT35-002/ThingPark/uplink/payload.json @@ -0,0 +1,75 @@ +{ + "DevEUI_uplink": { + "Time": "2024-11-28T21:08:22.138+00:00", + "DevEUI": "70B3D57BA000156B", + "FPort": 1, + "FCntUp": 26, + "LostUplinksAS": 0, + "ADRbit": 1, + "MType": 2, + "FCntDn": 2, + "payload_hex": "02030e000364a079b10c60", + "mic_hex": "e7214986", + "Lrcid": "00000211", + "LrrRSSI": -114.0, + "LrrSNR": 4.75, + "LrrESP": -115.2547, + "SpFact": 9, + "SubBand": "G0", + "Channel": "LC1", + "Lrrid": "100019D4", + "Late": 0, + "LrrLAT": 32.516357, + "LrrLON": -106.824348, + "Lrrs": { + "Lrr": [ + { + "Lrrid": "100019D4", + "Chain": 0, + "LrrRSSI": -114.0, + "LrrSNR": 4.75, + "LrrESP": -115.2547 + } + ] + }, + "DevLrrCnt": 1, + "CustomerID": "100045194", + "CustomerData": { + "loc": { + "lat": "32.592782", + "lon": "-106.927742" + }, + "alr": { + "pro": "DL/TBRG", + "ver": "1" + }, + "tags": ["EnvironSens", "RainGauge", "CDRRC"], + "doms": [], + "name": "RainGauge 5483_Test" + }, + "BaseStationData": { + "doms": [], + "name": "iStation US #6_CDRRC_Summerford" + }, + "ModelCfg": "0", + "DriverCfg": { + "mod": { + "pId": "dl", + "mId": "dl-tbrg", + "ver": "1" + }, + "app": { + "pId": "dl", + "mId": "dl-tbrg", + "ver": "1" + } + }, + "InstantPER": 0.0, + "MeanPER": 0.037037, + "DevAddr": "00FDA112", + "TxPower": 18.0, + "NbTrans": 2, + "Frequency": 902.5, + "DynamicClass": "A" + } +} diff --git a/VENDORS/Decentlab/DL-SHT35-002/ThingPark/uplink/payload_01.json b/VENDORS/Decentlab/DL-SHT35-002/ThingPark/uplink/payload_01.json new file mode 100644 index 00000000..7d0a43d9 --- /dev/null +++ b/VENDORS/Decentlab/DL-SHT35-002/ThingPark/uplink/payload_01.json @@ -0,0 +1,75 @@ +{ + "DevEUI_uplink": { + "Time": "2024-11-28T21:08:22.138+00:00", + "DevEUI": "70B3D57BA000156B", + "FPort": 1, + "FCntUp": 26, + "LostUplinksAS": 0, + "ADRbit": 1, + "MType": 2, + "FCntDn": 2, + "payload_hex": "02030e00020c60", + "mic_hex": "e7214986", + "Lrcid": "00000211", + "LrrRSSI": -114.0, + "LrrSNR": 4.75, + "LrrESP": -115.2547, + "SpFact": 9, + "SubBand": "G0", + "Channel": "LC1", + "Lrrid": "100019D4", + "Late": 0, + "LrrLAT": 32.516357, + "LrrLON": -106.824348, + "Lrrs": { + "Lrr": [ + { + "Lrrid": "100019D4", + "Chain": 0, + "LrrRSSI": -114.0, + "LrrSNR": 4.75, + "LrrESP": -115.2547 + } + ] + }, + "DevLrrCnt": 1, + "CustomerID": "100045194", + "CustomerData": { + "loc": { + "lat": "32.592782", + "lon": "-106.927742" + }, + "alr": { + "pro": "DL/TBRG", + "ver": "1" + }, + "tags": ["EnvironSens", "RainGauge", "CDRRC"], + "doms": [], + "name": "RainGauge 5483_Test" + }, + "BaseStationData": { + "doms": [], + "name": "iStation US #6_CDRRC_Summerford" + }, + "ModelCfg": "0", + "DriverCfg": { + "mod": { + "pId": "dl", + "mId": "dl-tbrg", + "ver": "1" + }, + "app": { + "pId": "dl", + "mId": "dl-tbrg", + "ver": "1" + } + }, + "InstantPER": 0.0, + "MeanPER": 0.037037, + "DevAddr": "00FDA112", + "TxPower": 18.0, + "NbTrans": 2, + "Frequency": 902.5, + "DynamicClass": "A" + } +} diff --git a/VENDORS/Decentlab/DL-SHT35-002/ThingPark/uplink/result.json b/VENDORS/Decentlab/DL-SHT35-002/ThingPark/uplink/result.json new file mode 100644 index 00000000..872843f3 --- /dev/null +++ b/VENDORS/Decentlab/DL-SHT35-002/ThingPark/uplink/result.json @@ -0,0 +1,24 @@ +{ + "deviceName": "782", + "deviceType": "DL-SHT35-002", + "attributes": { + "lora_dev_eui": "70B3D57BA000156B", + "protocol_version": 2 + }, + "telemetry": [ + { + "ts": 1732828102138, + "values": { + "air_temperature": 23.787670710307466, + "air_humidity": 47.536430914778364, + "battery_voltage": 3.168, + "lora_frame_counter": 26, + "lora_frame_port": 1, + "lora_frequency": 902500000, + "lora_spreading_factor": 9, + "lora_rssi": -114, + "lora_snr": 4.75 + } + } + ] +} diff --git a/VENDORS/Decentlab/DL-SHT35-002/ThingPark/uplink/result_01.json b/VENDORS/Decentlab/DL-SHT35-002/ThingPark/uplink/result_01.json new file mode 100644 index 00000000..bcdf7769 --- /dev/null +++ b/VENDORS/Decentlab/DL-SHT35-002/ThingPark/uplink/result_01.json @@ -0,0 +1,22 @@ +{ + "deviceName": "782", + "deviceType": "DL-SHT35-002", + "attributes": { + "lora_dev_eui": "70B3D57BA000156B", + "protocol_version": 2 + }, + "telemetry": [ + { + "ts": 1732828102138, + "values": { + "battery_voltage": 3.168, + "lora_frame_counter": 26, + "lora_frame_port": 1, + "lora_frequency": 902500000, + "lora_spreading_factor": 9, + "lora_rssi": -114, + "lora_snr": 4.75 + } + } + ] +} diff --git a/VENDORS/Decentlab/DL-SHT35-002/ThingParkEnterprise/uplink/converter.json b/VENDORS/Decentlab/DL-SHT35-002/ThingParkEnterprise/uplink/converter.json new file mode 100644 index 00000000..534bf7f8 --- /dev/null +++ b/VENDORS/Decentlab/DL-SHT35-002/ThingParkEnterprise/uplink/converter.json @@ -0,0 +1,19 @@ +{ + "name": "ThingParkEnterprise Uplink Decoder for Decentlab DL-SHT35-002", + "type": "UPLINK", + "debugMode": true, + "edgeTemplate": false, + "configuration": { + "scriptLang": "JS", + "updateOnlyKeys": [ + "lora_frame_counter", + "lora_frame_port", + "lora_frequency", + "lora_spreading_factor", + "lora_rssi", + "lora_dev_eui", + "lora_snr" + ], + "decoder": "// WARNING: This script is designed to work with a remote JS executor. Compatibility with a local JS evaluator is not guaranteed and may require rewriting.\n\nconst message = decodeToJson(payload);\nconst values = Object.assign(\n decodeDevicePayload(message.DevEUI_uplink.payload_hex),\n extractNetworkTelemetry(message)\n);\n\nreturn {\n deviceName: String(values.device_id),\n deviceType: 'DL-SHT35-002',\n attributes: {\n lora_dev_eui: values.lora_dev_eui,\n protocol_version: values.protocol_version,\n },\n telemetry: [{\n ts: parseDateToTimestamp(message.DevEUI_uplink.Time),\n values: keepTelemetry(values)\n }]\n};\n\nfunction decodeDevicePayload(payload) {\n /* https://www.decentlab.com/products/air-temperature-and-humidity-sensor-with-radiation-shield-for-lorawan */\n const decentlab_decoder = {\n PROTOCOL_VERSION: 2,\n SENSORS: [\n {length: 2,\n values: [{name: 'air_temperature',\n displayName: 'Air temperature',\n convert: function (x) { return 175 * x[0] / 65535 - 45; },\n unit: '°C'},\n {name: 'air_humidity',\n displayName: 'Air humidity',\n convert: function (x) { return 100 * x[1] / 65535; },\n unit: '%'}]},\n {length: 1,\n values: [{name: 'battery_voltage',\n displayName: 'Battery voltage',\n convert: function (x) { return x[0] / 1000; },\n unit: 'V'}]}\n ],\n read_int: function (bytes, pos) {\n return (bytes[pos] << 8) + bytes[pos + 1];\n },\n decode: function (msg) {\n var bytes = msg;\n var i, j;\n if (typeof msg === 'string') {\n bytes = [];\n for (i = 0; i < msg.length; i += 2) {\n bytes.push(parseInt(msg.substring(i, i + 2), 16));\n }\n }\n var version = bytes[0];\n if (version != this.PROTOCOL_VERSION) {\n return {error: \"protocol version \" + version + \" doesn't match v2\"};\n }\n var deviceId = this.read_int(bytes, 1);\n var flags = this.read_int(bytes, 3);\n var result = {'protocol_version': version, 'device_id': deviceId};\n // decode payload\n var pos = 5;\n for (i = 0; i < this.SENSORS.length; i++, flags >>= 1) {\n if ((flags & 1) !== 1)\n continue;\n var sensor = this.SENSORS[i];\n var x = [];\n // convert data to 16-bit integer array\n for (j = 0; j < sensor.length; j++) {\n x.push(this.read_int(bytes, pos));\n pos += 2;\n }\n // decode sensor values\n for (j = 0; j < sensor.values.length; j++) {\n var value = sensor.values[j];\n if ('convert' in value) {\n result[value.name] = {displayName: value.displayName,\n value: value.convert.bind(this)(x)};\n if ('unit' in value)\n result[value.name]['unit'] = value.unit;\n }\n }\n }\n return result;\n }\n };\n\n const decoded = decentlab_decoder.decode(payload);\n const result = {};\n for (var k in decoded) {\n if (typeof decoded[k] === \"object\") {\n result[k] = decoded[k].value;\n } else if (typeof decoded[k] === \"number\") {\n result[k] = decoded[k];\n }\n }\n return result;\n}\n\nfunction extractNetworkTelemetry(payload) {\n return {\n lora_frame_counter: message.DevEUI_uplink.FCntUp,\n lora_frame_port: message.DevEUI_uplink.FPort,\n lora_frequency: message.DevEUI_uplink?.Frequency * 1000000,\n lora_spreading_factor: message.DevEUI_uplink.SpFact,\n lora_dev_eui: message.DevEUI_uplink.DevEUI,\n lora_rssi: message.DevEUI_uplink.LrrRSSI,\n lora_snr: message.DevEUI_uplink.LrrSNR,\n };\n}\n\n// Helper functions\n\nfunction decodeToJson(payload) {\n const s = String.fromCharCode.apply(String, payload);\n return JSON.parse(s);\n}\n\nfunction parseDateToTimestamp(dateString) {\n var timestamp = -1;\n if (dateString != null) {\n timestamp = new Date(dateString).getTime();\n if (timestamp == -1) {\n var secondsSeparatorIndex = dateString.lastIndexOf('.') + 1;\n var millisecondsEndIndex = dateString.lastIndexOf('+');\n if (millisecondsEndIndex == -1) {\n millisecondsEndIndex = dateString.lastIndexOf('Z');\n }\n if (millisecondsEndIndex == -1) {\n millisecondsEndIndex = dateString.lastIndexOf('-');\n }\n if (millisecondsEndIndex == -1) {\n if (dateString.length >= secondsSeparatorIndex + 3) {\n dateString = dateString.substring(0, secondsSeparatorIndex + 3);\n }\n } else {\n dateString = dateString.substring(0, secondsSeparatorIndex + 3) +\n dateString.substring(millisecondsEndIndex, dateString.length);\n }\n timestamp = new Date(dateString).getTime();\n }\n }\n // If we cannot parse timestamp - we will use the current timestamp\n if (timestamp == -1) {\n timestamp = Date.now();\n }\n\n return timestamp;\n}\n\nfunction base64ToBytes(base64String) {\n if (typeof base64String === 'string') {\n return Uint8Array.from(atob(base64String), c => c.charCodeAt(0));\n }\n return [];\n}\n\nfunction keepTelemetry(telemetry) {\n const unwanted = ['protocol_version', 'device_id', 'lora_dev_eui'];\n return Object.fromEntries(\n Object.entries(telemetry).filter(\n (x) => !unwanted.includes(x[0])\n )\n );\n}" + } +} diff --git a/VENDORS/Decentlab/DL-SHT35-002/ThingParkEnterprise/uplink/metadata.json b/VENDORS/Decentlab/DL-SHT35-002/ThingParkEnterprise/uplink/metadata.json new file mode 100644 index 00000000..47c01690 --- /dev/null +++ b/VENDORS/Decentlab/DL-SHT35-002/ThingParkEnterprise/uplink/metadata.json @@ -0,0 +1,4 @@ +{ + "integrationName": "ThingParkEnterprise integration", + "includeGatewayInfo": false +} \ No newline at end of file diff --git a/VENDORS/Decentlab/DL-SHT35-002/ThingParkEnterprise/uplink/payload.json b/VENDORS/Decentlab/DL-SHT35-002/ThingParkEnterprise/uplink/payload.json new file mode 100644 index 00000000..5adfd4bc --- /dev/null +++ b/VENDORS/Decentlab/DL-SHT35-002/ThingParkEnterprise/uplink/payload.json @@ -0,0 +1,75 @@ +{ + "DevEUI_uplink": { + "Time": "2024-11-28T21:08:22.138+00:00", + "DevEUI": "70B3D57BA000156B", + "FPort": 1, + "FCntUp": 26, + "LostUplinksAS": 0, + "ADRbit": 1, + "MType": 2, + "FCntDn": 2, + "payload_hex": "02030e000364a079b10c60", + "mic_hex": "e7214986", + "Lrcid": "00000211", + "LrrRSSI": -114.0, + "LrrSNR": 4.75, + "LrrESP": -115.2547, + "SpFact": 9, + "SubBand": "G0", + "Channel": "LC1", + "Lrrid": "100019D4", + "Late": 0, + "LrrLAT": 32.516357, + "LrrLON": -106.824348, + "Lrrs": { + "Lrr": [ + { + "Lrrid": "100019D4", + "Chain": 0, + "LrrRSSI": -114.0, + "LrrSNR": 4.75, + "LrrESP": -115.2547 + } + ] + }, + "DevLrrCnt": 1, + "CustomerID": "100045194", + "CustomerData": { + "loc": { + "lat": "32.592782", + "lon": "-106.927742" + }, + "alr": { + "pro": "DL/TBRG", + "ver": "1" + }, + "tags": ["EnvironSens", "RainGauge", "CDRRC"], + "doms": [], + "name": "RainGauge 5483_Test" + }, + "BaseStationData": { + "doms": [], + "name": "iStation US #6_CDRRC_Summerford" + }, + "ModelCfg": "0", + "DriverCfg": { + "mod": { + "pId": "dl", + "mId": "dl-tbrg", + "ver": "1" + }, + "app": { + "pId": "dl", + "mId": "dl-tbrg", + "ver": "1" + } + }, + "InstantPER": 0.0, + "MeanPER": 0.037037, + "DevAddr": "00FDA112", + "TxPower": 18.0, + "NbTrans": 2, + "Frequency": 902.5, + "DynamicClass": "A" + } +} diff --git a/VENDORS/Decentlab/DL-SHT35-002/ThingParkEnterprise/uplink/payload_01.json b/VENDORS/Decentlab/DL-SHT35-002/ThingParkEnterprise/uplink/payload_01.json new file mode 100644 index 00000000..7d0a43d9 --- /dev/null +++ b/VENDORS/Decentlab/DL-SHT35-002/ThingParkEnterprise/uplink/payload_01.json @@ -0,0 +1,75 @@ +{ + "DevEUI_uplink": { + "Time": "2024-11-28T21:08:22.138+00:00", + "DevEUI": "70B3D57BA000156B", + "FPort": 1, + "FCntUp": 26, + "LostUplinksAS": 0, + "ADRbit": 1, + "MType": 2, + "FCntDn": 2, + "payload_hex": "02030e00020c60", + "mic_hex": "e7214986", + "Lrcid": "00000211", + "LrrRSSI": -114.0, + "LrrSNR": 4.75, + "LrrESP": -115.2547, + "SpFact": 9, + "SubBand": "G0", + "Channel": "LC1", + "Lrrid": "100019D4", + "Late": 0, + "LrrLAT": 32.516357, + "LrrLON": -106.824348, + "Lrrs": { + "Lrr": [ + { + "Lrrid": "100019D4", + "Chain": 0, + "LrrRSSI": -114.0, + "LrrSNR": 4.75, + "LrrESP": -115.2547 + } + ] + }, + "DevLrrCnt": 1, + "CustomerID": "100045194", + "CustomerData": { + "loc": { + "lat": "32.592782", + "lon": "-106.927742" + }, + "alr": { + "pro": "DL/TBRG", + "ver": "1" + }, + "tags": ["EnvironSens", "RainGauge", "CDRRC"], + "doms": [], + "name": "RainGauge 5483_Test" + }, + "BaseStationData": { + "doms": [], + "name": "iStation US #6_CDRRC_Summerford" + }, + "ModelCfg": "0", + "DriverCfg": { + "mod": { + "pId": "dl", + "mId": "dl-tbrg", + "ver": "1" + }, + "app": { + "pId": "dl", + "mId": "dl-tbrg", + "ver": "1" + } + }, + "InstantPER": 0.0, + "MeanPER": 0.037037, + "DevAddr": "00FDA112", + "TxPower": 18.0, + "NbTrans": 2, + "Frequency": 902.5, + "DynamicClass": "A" + } +} diff --git a/VENDORS/Decentlab/DL-SHT35-002/ThingParkEnterprise/uplink/result.json b/VENDORS/Decentlab/DL-SHT35-002/ThingParkEnterprise/uplink/result.json new file mode 100644 index 00000000..872843f3 --- /dev/null +++ b/VENDORS/Decentlab/DL-SHT35-002/ThingParkEnterprise/uplink/result.json @@ -0,0 +1,24 @@ +{ + "deviceName": "782", + "deviceType": "DL-SHT35-002", + "attributes": { + "lora_dev_eui": "70B3D57BA000156B", + "protocol_version": 2 + }, + "telemetry": [ + { + "ts": 1732828102138, + "values": { + "air_temperature": 23.787670710307466, + "air_humidity": 47.536430914778364, + "battery_voltage": 3.168, + "lora_frame_counter": 26, + "lora_frame_port": 1, + "lora_frequency": 902500000, + "lora_spreading_factor": 9, + "lora_rssi": -114, + "lora_snr": 4.75 + } + } + ] +} diff --git a/VENDORS/Decentlab/DL-SHT35-002/ThingParkEnterprise/uplink/result_01.json b/VENDORS/Decentlab/DL-SHT35-002/ThingParkEnterprise/uplink/result_01.json new file mode 100644 index 00000000..bcdf7769 --- /dev/null +++ b/VENDORS/Decentlab/DL-SHT35-002/ThingParkEnterprise/uplink/result_01.json @@ -0,0 +1,22 @@ +{ + "deviceName": "782", + "deviceType": "DL-SHT35-002", + "attributes": { + "lora_dev_eui": "70B3D57BA000156B", + "protocol_version": 2 + }, + "telemetry": [ + { + "ts": 1732828102138, + "values": { + "battery_voltage": 3.168, + "lora_frame_counter": 26, + "lora_frame_port": 1, + "lora_frequency": 902500000, + "lora_spreading_factor": 9, + "lora_rssi": -114, + "lora_snr": 4.75 + } + } + ] +} diff --git a/VENDORS/Decentlab/DL-SHT35-002/ThingsStackCommunity/uplink/converter.json b/VENDORS/Decentlab/DL-SHT35-002/ThingsStackCommunity/uplink/converter.json new file mode 100644 index 00000000..443fb80d --- /dev/null +++ b/VENDORS/Decentlab/DL-SHT35-002/ThingsStackCommunity/uplink/converter.json @@ -0,0 +1,19 @@ +{ + "name": "ThingsStackCommunity Uplink Decoder for Decentlab DL-SHT35-002", + "type": "UPLINK", + "debugMode": true, + "edgeTemplate": false, + "configuration": { + "scriptLang": "JS", + "updateOnlyKeys": [ + "lora_frame_counter", + "lora_frame_port", + "lora_frequency", + "lora_spreading_factor", + "lora_rssi", + "lora_dev_eui", + "lora_snr" + ], + "decoder": "// WARNING: This script is designed to work with a remote JS executor. Compatibility with a local JS evaluator is not guaranteed and may require rewriting.\n\nconst message = decodeToJson(payload);\nconst values = Object.assign(\n decodeDevicePayload(base64ToBytes(message.uplink_message.frm_payload)),\n extractNetworkTelemetry(message)\n);\n\nreturn {\n deviceName: String(values.device_id),\n deviceType: 'DL-SHT35-002',\n attributes: {\n lora_dev_eui: values.lora_dev_eui,\n protocol_version: values.protocol_version,\n },\n telemetry: [{\n ts: parseDateToTimestamp(message.received_at),\n values: keepTelemetry(values)\n }]\n};\n\nfunction decodeDevicePayload(payload) {\n /* https://www.decentlab.com/products/air-temperature-and-humidity-sensor-with-radiation-shield-for-lorawan */\n const decentlab_decoder = {\n PROTOCOL_VERSION: 2,\n SENSORS: [\n {length: 2,\n values: [{name: 'air_temperature',\n displayName: 'Air temperature',\n convert: function (x) { return 175 * x[0] / 65535 - 45; },\n unit: '°C'},\n {name: 'air_humidity',\n displayName: 'Air humidity',\n convert: function (x) { return 100 * x[1] / 65535; },\n unit: '%'}]},\n {length: 1,\n values: [{name: 'battery_voltage',\n displayName: 'Battery voltage',\n convert: function (x) { return x[0] / 1000; },\n unit: 'V'}]}\n ],\n read_int: function (bytes, pos) {\n return (bytes[pos] << 8) + bytes[pos + 1];\n },\n decode: function (msg) {\n var bytes = msg;\n var i, j;\n if (typeof msg === 'string') {\n bytes = [];\n for (i = 0; i < msg.length; i += 2) {\n bytes.push(parseInt(msg.substring(i, i + 2), 16));\n }\n }\n var version = bytes[0];\n if (version != this.PROTOCOL_VERSION) {\n return {error: \"protocol version \" + version + \" doesn't match v2\"};\n }\n var deviceId = this.read_int(bytes, 1);\n var flags = this.read_int(bytes, 3);\n var result = {'protocol_version': version, 'device_id': deviceId};\n // decode payload\n var pos = 5;\n for (i = 0; i < this.SENSORS.length; i++, flags >>= 1) {\n if ((flags & 1) !== 1)\n continue;\n var sensor = this.SENSORS[i];\n var x = [];\n // convert data to 16-bit integer array\n for (j = 0; j < sensor.length; j++) {\n x.push(this.read_int(bytes, pos));\n pos += 2;\n }\n // decode sensor values\n for (j = 0; j < sensor.values.length; j++) {\n var value = sensor.values[j];\n if ('convert' in value) {\n result[value.name] = {displayName: value.displayName,\n value: value.convert.bind(this)(x)};\n if ('unit' in value)\n result[value.name]['unit'] = value.unit;\n }\n }\n }\n return result;\n }\n };\n\n const decoded = decentlab_decoder.decode(payload);\n const result = {};\n for (var k in decoded) {\n if (typeof decoded[k] === \"object\") {\n result[k] = decoded[k].value;\n } else if (typeof decoded[k] === \"number\") {\n result[k] = decoded[k];\n }\n }\n return result;\n}\n\nfunction extractNetworkTelemetry(payload) {\n const result = {\n lora_frame_counter: message.uplink_message.f_cnt,\n lora_frame_port: message.uplink_message.f_port,\n lora_frequency: parseInt(message.uplink_message.settings.frequency),\n lora_dev_eui: message.end_device_ids.dev_eui,\n lora_spreading_factor:\n message.uplink_message.settings.data_rate.lora.spreading_factor,\n };\n const gwi = message.uplink_message.rx_metadata\n .map((x) => ({ lora_rssi: x.rssi, lora_snr: x.snr }))\n .reduce((a, x) => (x.lora_rssi > a.lora_rssi ? x : a), {\n lora_rssi: -Number.MAX_VALUE,\n });\n return Object.assign(result, gwi);\n}\n\n// Helper functions\n\nfunction decodeToJson(payload) {\n const s = String.fromCharCode.apply(String, payload);\n return JSON.parse(s);\n}\n\nfunction parseDateToTimestamp(dateString) {\n var timestamp = -1;\n if (dateString != null) {\n timestamp = new Date(dateString).getTime();\n if (timestamp == -1) {\n var secondsSeparatorIndex = dateString.lastIndexOf('.') + 1;\n var millisecondsEndIndex = dateString.lastIndexOf('+');\n if (millisecondsEndIndex == -1) {\n millisecondsEndIndex = dateString.lastIndexOf('Z');\n }\n if (millisecondsEndIndex == -1) {\n millisecondsEndIndex = dateString.lastIndexOf('-');\n }\n if (millisecondsEndIndex == -1) {\n if (dateString.length >= secondsSeparatorIndex + 3) {\n dateString = dateString.substring(0, secondsSeparatorIndex + 3);\n }\n } else {\n dateString = dateString.substring(0, secondsSeparatorIndex + 3) +\n dateString.substring(millisecondsEndIndex, dateString.length);\n }\n timestamp = new Date(dateString).getTime();\n }\n }\n // If we cannot parse timestamp - we will use the current timestamp\n if (timestamp == -1) {\n timestamp = Date.now();\n }\n\n return timestamp;\n}\n\nfunction base64ToBytes(base64String) {\n if (typeof base64String === 'string') {\n return Uint8Array.from(atob(base64String), c => c.charCodeAt(0));\n }\n return [];\n}\n\nfunction keepTelemetry(telemetry) {\n const unwanted = ['protocol_version', 'device_id', 'lora_dev_eui'];\n return Object.fromEntries(\n Object.entries(telemetry).filter(\n (x) => !unwanted.includes(x[0])\n )\n );\n}" + } +} diff --git a/VENDORS/Decentlab/DL-SHT35-002/ThingsStackCommunity/uplink/metadata.json b/VENDORS/Decentlab/DL-SHT35-002/ThingsStackCommunity/uplink/metadata.json new file mode 100644 index 00000000..11a4de83 --- /dev/null +++ b/VENDORS/Decentlab/DL-SHT35-002/ThingsStackCommunity/uplink/metadata.json @@ -0,0 +1,4 @@ +{ + "integrationName": "ThingsStackCommunity integration", + "includeGatewayInfo": false +} \ No newline at end of file diff --git a/VENDORS/Decentlab/DL-SHT35-002/ThingsStackCommunity/uplink/payload.json b/VENDORS/Decentlab/DL-SHT35-002/ThingsStackCommunity/uplink/payload.json new file mode 100644 index 00000000..54f8c83f --- /dev/null +++ b/VENDORS/Decentlab/DL-SHT35-002/ThingsStackCommunity/uplink/payload.json @@ -0,0 +1,60 @@ +{ + "end_device_ids": { + "device_id": "03022", + "application_ids": { + "application_id": "test-decentlab" + }, + "dev_eui": "70B3D57BA0000BCE", + "join_eui": "70B3D57ED00006B2", + "dev_addr": "27000020" + }, + "correlation_ids": [ + "as:up:01E0CY8V864TP36Q130RSQQJBY", + "gs:conn:01E0B4GJHDRFKNEQ9GG3ZDG1JX", + "gs:uplink:01E0CY8V1FFJ0WCKXTKT0CRPDY", + "ns:uplink:01E0CY8V1JGN0R5YZTBH48YXH3", + "rpc:/ttn.lorawan.v3.GsNs/HandleUplink:01E0CY8V1JHJA8PE0P98VSDE6K" + ], + "received_at": "2020-02-06T09:46:05.447941836Z", + "uplink_message": { + "session_key_id": "AXAWYbtxgUllLtJWdZrW0Q==", + "f_port": 1, + "f_cnt": 101, + "frm_payload": "AgMOAANkoHmxDGA=", + "rx_metadata": [ + { + "gateway_ids": { + "gateway_id": "eui-b827ebfffe9f2da9", + "eui": "B827EBFFFE9F2DA9" + }, + "time": "2020-02-06T09:46:05Z", + "timestamp": 436812492, + "rssi": -16, + "channel_rssi": -16, + "snr": 8.5, + "uplink_token": "CiIKIAoUZXVpLWI4MjdlYmZmZmU5ZjJkYTkSCLgn6//+ny2pEMz1pNAB", + "location": { + "latitude": 52.71863806169478, + "longitude": -4.052632749080659, + "altitude": 5, + "source": "SOURCE_REGISTRY" + }, + "channel_index": 6 + } + ], + "settings": { + "data_rate": { + "lora": { + "bandwidth": 125000, + "spreading_factor": 11 + } + }, + "data_rate_index": 1, + "coding_rate": "4/5", + "frequency": "867700000", + "timestamp": 436812492, + "time": "2020-02-06T09:46:05Z" + }, + "received_at": "2020-02-06T09:46:05.234172599Z" + } +} diff --git a/VENDORS/Decentlab/DL-SHT35-002/ThingsStackCommunity/uplink/payload_01.json b/VENDORS/Decentlab/DL-SHT35-002/ThingsStackCommunity/uplink/payload_01.json new file mode 100644 index 00000000..09bf7a63 --- /dev/null +++ b/VENDORS/Decentlab/DL-SHT35-002/ThingsStackCommunity/uplink/payload_01.json @@ -0,0 +1,60 @@ +{ + "end_device_ids": { + "device_id": "03022", + "application_ids": { + "application_id": "test-decentlab" + }, + "dev_eui": "70B3D57BA0000BCE", + "join_eui": "70B3D57ED00006B2", + "dev_addr": "27000020" + }, + "correlation_ids": [ + "as:up:01E0CY8V864TP36Q130RSQQJBY", + "gs:conn:01E0B4GJHDRFKNEQ9GG3ZDG1JX", + "gs:uplink:01E0CY8V1FFJ0WCKXTKT0CRPDY", + "ns:uplink:01E0CY8V1JGN0R5YZTBH48YXH3", + "rpc:/ttn.lorawan.v3.GsNs/HandleUplink:01E0CY8V1JHJA8PE0P98VSDE6K" + ], + "received_at": "2020-02-06T09:46:05.447941836Z", + "uplink_message": { + "session_key_id": "AXAWYbtxgUllLtJWdZrW0Q==", + "f_port": 1, + "f_cnt": 101, + "frm_payload": "AgMOAAIMYA==", + "rx_metadata": [ + { + "gateway_ids": { + "gateway_id": "eui-b827ebfffe9f2da9", + "eui": "B827EBFFFE9F2DA9" + }, + "time": "2020-02-06T09:46:05Z", + "timestamp": 436812492, + "rssi": -16, + "channel_rssi": -16, + "snr": 8.5, + "uplink_token": "CiIKIAoUZXVpLWI4MjdlYmZmZmU5ZjJkYTkSCLgn6//+ny2pEMz1pNAB", + "location": { + "latitude": 52.71863806169478, + "longitude": -4.052632749080659, + "altitude": 5, + "source": "SOURCE_REGISTRY" + }, + "channel_index": 6 + } + ], + "settings": { + "data_rate": { + "lora": { + "bandwidth": 125000, + "spreading_factor": 11 + } + }, + "data_rate_index": 1, + "coding_rate": "4/5", + "frequency": "867700000", + "timestamp": 436812492, + "time": "2020-02-06T09:46:05Z" + }, + "received_at": "2020-02-06T09:46:05.234172599Z" + } +} diff --git a/VENDORS/Decentlab/DL-SHT35-002/ThingsStackCommunity/uplink/result.json b/VENDORS/Decentlab/DL-SHT35-002/ThingsStackCommunity/uplink/result.json new file mode 100644 index 00000000..925b1f23 --- /dev/null +++ b/VENDORS/Decentlab/DL-SHT35-002/ThingsStackCommunity/uplink/result.json @@ -0,0 +1,24 @@ +{ + "deviceName": "782", + "deviceType": "DL-SHT35-002", + "attributes": { + "lora_dev_eui": "70B3D57BA0000BCE", + "protocol_version": 2 + }, + "telemetry": [ + { + "ts": 1580982365447, + "values": { + "air_temperature": 23.787670710307466, + "air_humidity": 47.536430914778364, + "battery_voltage": 3.168, + "lora_frame_counter": 101, + "lora_frame_port": 1, + "lora_frequency": 867700000, + "lora_spreading_factor": 11, + "lora_rssi": -16, + "lora_snr": 8.5 + } + } + ] +} diff --git a/VENDORS/Decentlab/DL-SHT35-002/ThingsStackCommunity/uplink/result_01.json b/VENDORS/Decentlab/DL-SHT35-002/ThingsStackCommunity/uplink/result_01.json new file mode 100644 index 00000000..7f2fb8ca --- /dev/null +++ b/VENDORS/Decentlab/DL-SHT35-002/ThingsStackCommunity/uplink/result_01.json @@ -0,0 +1,22 @@ +{ + "deviceName": "782", + "deviceType": "DL-SHT35-002", + "attributes": { + "lora_dev_eui": "70B3D57BA0000BCE", + "protocol_version": 2 + }, + "telemetry": [ + { + "ts": 1580982365447, + "values": { + "battery_voltage": 3.168, + "lora_frame_counter": 101, + "lora_frame_port": 1, + "lora_frequency": 867700000, + "lora_spreading_factor": 11, + "lora_rssi": -16, + "lora_snr": 8.5 + } + } + ] +} diff --git a/VENDORS/Decentlab/DL-SHT35-002/ThingsStackIndustries/uplink/converter.json b/VENDORS/Decentlab/DL-SHT35-002/ThingsStackIndustries/uplink/converter.json new file mode 100644 index 00000000..0bcd4110 --- /dev/null +++ b/VENDORS/Decentlab/DL-SHT35-002/ThingsStackIndustries/uplink/converter.json @@ -0,0 +1,19 @@ +{ + "name": "ThingsStackIndustries Uplink Decoder for Decentlab DL-SHT35-002", + "type": "UPLINK", + "debugMode": true, + "edgeTemplate": false, + "configuration": { + "scriptLang": "JS", + "updateOnlyKeys": [ + "lora_frame_counter", + "lora_frame_port", + "lora_frequency", + "lora_spreading_factor", + "lora_rssi", + "lora_dev_eui", + "lora_snr" + ], + "decoder": "// WARNING: This script is designed to work with a remote JS executor. Compatibility with a local JS evaluator is not guaranteed and may require rewriting.\n\nconst message = decodeToJson(payload);\nconst values = Object.assign(\n decodeDevicePayload(base64ToBytes(message.uplink_message.frm_payload)),\n extractNetworkTelemetry(message)\n);\n\nreturn {\n deviceName: String(values.device_id),\n deviceType: 'DL-SHT35-002',\n attributes: {\n lora_dev_eui: values.lora_dev_eui,\n protocol_version: values.protocol_version,\n },\n telemetry: [{\n ts: parseDateToTimestamp(message.received_at),\n values: keepTelemetry(values)\n }]\n};\n\nfunction decodeDevicePayload(payload) {\n /* https://www.decentlab.com/products/air-temperature-and-humidity-sensor-with-radiation-shield-for-lorawan */\n const decentlab_decoder = {\n PROTOCOL_VERSION: 2,\n SENSORS: [\n {length: 2,\n values: [{name: 'air_temperature',\n displayName: 'Air temperature',\n convert: function (x) { return 175 * x[0] / 65535 - 45; },\n unit: '°C'},\n {name: 'air_humidity',\n displayName: 'Air humidity',\n convert: function (x) { return 100 * x[1] / 65535; },\n unit: '%'}]},\n {length: 1,\n values: [{name: 'battery_voltage',\n displayName: 'Battery voltage',\n convert: function (x) { return x[0] / 1000; },\n unit: 'V'}]}\n ],\n read_int: function (bytes, pos) {\n return (bytes[pos] << 8) + bytes[pos + 1];\n },\n decode: function (msg) {\n var bytes = msg;\n var i, j;\n if (typeof msg === 'string') {\n bytes = [];\n for (i = 0; i < msg.length; i += 2) {\n bytes.push(parseInt(msg.substring(i, i + 2), 16));\n }\n }\n var version = bytes[0];\n if (version != this.PROTOCOL_VERSION) {\n return {error: \"protocol version \" + version + \" doesn't match v2\"};\n }\n var deviceId = this.read_int(bytes, 1);\n var flags = this.read_int(bytes, 3);\n var result = {'protocol_version': version, 'device_id': deviceId};\n // decode payload\n var pos = 5;\n for (i = 0; i < this.SENSORS.length; i++, flags >>= 1) {\n if ((flags & 1) !== 1)\n continue;\n var sensor = this.SENSORS[i];\n var x = [];\n // convert data to 16-bit integer array\n for (j = 0; j < sensor.length; j++) {\n x.push(this.read_int(bytes, pos));\n pos += 2;\n }\n // decode sensor values\n for (j = 0; j < sensor.values.length; j++) {\n var value = sensor.values[j];\n if ('convert' in value) {\n result[value.name] = {displayName: value.displayName,\n value: value.convert.bind(this)(x)};\n if ('unit' in value)\n result[value.name]['unit'] = value.unit;\n }\n }\n }\n return result;\n }\n };\n\n const decoded = decentlab_decoder.decode(payload);\n const result = {};\n for (var k in decoded) {\n if (typeof decoded[k] === \"object\") {\n result[k] = decoded[k].value;\n } else if (typeof decoded[k] === \"number\") {\n result[k] = decoded[k];\n }\n }\n return result;\n}\n\nfunction extractNetworkTelemetry(payload) {\n const result = {\n lora_frame_counter: message.uplink_message.f_cnt,\n lora_frame_port: message.uplink_message.f_port,\n lora_frequency: parseInt(message.uplink_message.settings.frequency),\n lora_dev_eui: message.end_device_ids.dev_eui,\n lora_spreading_factor:\n message.uplink_message.settings.data_rate.lora.spreading_factor,\n };\n const gwi = message.uplink_message.rx_metadata\n .map((x) => ({ lora_rssi: x.rssi, lora_snr: x.snr }))\n .reduce((a, x) => (x.lora_rssi > a.lora_rssi ? x : a), {\n lora_rssi: -Number.MAX_VALUE,\n });\n return Object.assign(result, gwi);\n}\n\n// Helper functions\n\nfunction decodeToJson(payload) {\n const s = String.fromCharCode.apply(String, payload);\n return JSON.parse(s);\n}\n\nfunction parseDateToTimestamp(dateString) {\n var timestamp = -1;\n if (dateString != null) {\n timestamp = new Date(dateString).getTime();\n if (timestamp == -1) {\n var secondsSeparatorIndex = dateString.lastIndexOf('.') + 1;\n var millisecondsEndIndex = dateString.lastIndexOf('+');\n if (millisecondsEndIndex == -1) {\n millisecondsEndIndex = dateString.lastIndexOf('Z');\n }\n if (millisecondsEndIndex == -1) {\n millisecondsEndIndex = dateString.lastIndexOf('-');\n }\n if (millisecondsEndIndex == -1) {\n if (dateString.length >= secondsSeparatorIndex + 3) {\n dateString = dateString.substring(0, secondsSeparatorIndex + 3);\n }\n } else {\n dateString = dateString.substring(0, secondsSeparatorIndex + 3) +\n dateString.substring(millisecondsEndIndex, dateString.length);\n }\n timestamp = new Date(dateString).getTime();\n }\n }\n // If we cannot parse timestamp - we will use the current timestamp\n if (timestamp == -1) {\n timestamp = Date.now();\n }\n\n return timestamp;\n}\n\nfunction base64ToBytes(base64String) {\n if (typeof base64String === 'string') {\n return Uint8Array.from(atob(base64String), c => c.charCodeAt(0));\n }\n return [];\n}\n\nfunction keepTelemetry(telemetry) {\n const unwanted = ['protocol_version', 'device_id', 'lora_dev_eui'];\n return Object.fromEntries(\n Object.entries(telemetry).filter(\n (x) => !unwanted.includes(x[0])\n )\n );\n}" + } +} diff --git a/VENDORS/Decentlab/DL-SHT35-002/ThingsStackIndustries/uplink/metadata.json b/VENDORS/Decentlab/DL-SHT35-002/ThingsStackIndustries/uplink/metadata.json new file mode 100644 index 00000000..e304ca99 --- /dev/null +++ b/VENDORS/Decentlab/DL-SHT35-002/ThingsStackIndustries/uplink/metadata.json @@ -0,0 +1,4 @@ +{ + "integrationName": "ThingsStackIndustries integration", + "includeGatewayInfo": false +} \ No newline at end of file diff --git a/VENDORS/Decentlab/DL-SHT35-002/ThingsStackIndustries/uplink/payload.json b/VENDORS/Decentlab/DL-SHT35-002/ThingsStackIndustries/uplink/payload.json new file mode 100644 index 00000000..54f8c83f --- /dev/null +++ b/VENDORS/Decentlab/DL-SHT35-002/ThingsStackIndustries/uplink/payload.json @@ -0,0 +1,60 @@ +{ + "end_device_ids": { + "device_id": "03022", + "application_ids": { + "application_id": "test-decentlab" + }, + "dev_eui": "70B3D57BA0000BCE", + "join_eui": "70B3D57ED00006B2", + "dev_addr": "27000020" + }, + "correlation_ids": [ + "as:up:01E0CY8V864TP36Q130RSQQJBY", + "gs:conn:01E0B4GJHDRFKNEQ9GG3ZDG1JX", + "gs:uplink:01E0CY8V1FFJ0WCKXTKT0CRPDY", + "ns:uplink:01E0CY8V1JGN0R5YZTBH48YXH3", + "rpc:/ttn.lorawan.v3.GsNs/HandleUplink:01E0CY8V1JHJA8PE0P98VSDE6K" + ], + "received_at": "2020-02-06T09:46:05.447941836Z", + "uplink_message": { + "session_key_id": "AXAWYbtxgUllLtJWdZrW0Q==", + "f_port": 1, + "f_cnt": 101, + "frm_payload": "AgMOAANkoHmxDGA=", + "rx_metadata": [ + { + "gateway_ids": { + "gateway_id": "eui-b827ebfffe9f2da9", + "eui": "B827EBFFFE9F2DA9" + }, + "time": "2020-02-06T09:46:05Z", + "timestamp": 436812492, + "rssi": -16, + "channel_rssi": -16, + "snr": 8.5, + "uplink_token": "CiIKIAoUZXVpLWI4MjdlYmZmZmU5ZjJkYTkSCLgn6//+ny2pEMz1pNAB", + "location": { + "latitude": 52.71863806169478, + "longitude": -4.052632749080659, + "altitude": 5, + "source": "SOURCE_REGISTRY" + }, + "channel_index": 6 + } + ], + "settings": { + "data_rate": { + "lora": { + "bandwidth": 125000, + "spreading_factor": 11 + } + }, + "data_rate_index": 1, + "coding_rate": "4/5", + "frequency": "867700000", + "timestamp": 436812492, + "time": "2020-02-06T09:46:05Z" + }, + "received_at": "2020-02-06T09:46:05.234172599Z" + } +} diff --git a/VENDORS/Decentlab/DL-SHT35-002/ThingsStackIndustries/uplink/payload_01.json b/VENDORS/Decentlab/DL-SHT35-002/ThingsStackIndustries/uplink/payload_01.json new file mode 100644 index 00000000..09bf7a63 --- /dev/null +++ b/VENDORS/Decentlab/DL-SHT35-002/ThingsStackIndustries/uplink/payload_01.json @@ -0,0 +1,60 @@ +{ + "end_device_ids": { + "device_id": "03022", + "application_ids": { + "application_id": "test-decentlab" + }, + "dev_eui": "70B3D57BA0000BCE", + "join_eui": "70B3D57ED00006B2", + "dev_addr": "27000020" + }, + "correlation_ids": [ + "as:up:01E0CY8V864TP36Q130RSQQJBY", + "gs:conn:01E0B4GJHDRFKNEQ9GG3ZDG1JX", + "gs:uplink:01E0CY8V1FFJ0WCKXTKT0CRPDY", + "ns:uplink:01E0CY8V1JGN0R5YZTBH48YXH3", + "rpc:/ttn.lorawan.v3.GsNs/HandleUplink:01E0CY8V1JHJA8PE0P98VSDE6K" + ], + "received_at": "2020-02-06T09:46:05.447941836Z", + "uplink_message": { + "session_key_id": "AXAWYbtxgUllLtJWdZrW0Q==", + "f_port": 1, + "f_cnt": 101, + "frm_payload": "AgMOAAIMYA==", + "rx_metadata": [ + { + "gateway_ids": { + "gateway_id": "eui-b827ebfffe9f2da9", + "eui": "B827EBFFFE9F2DA9" + }, + "time": "2020-02-06T09:46:05Z", + "timestamp": 436812492, + "rssi": -16, + "channel_rssi": -16, + "snr": 8.5, + "uplink_token": "CiIKIAoUZXVpLWI4MjdlYmZmZmU5ZjJkYTkSCLgn6//+ny2pEMz1pNAB", + "location": { + "latitude": 52.71863806169478, + "longitude": -4.052632749080659, + "altitude": 5, + "source": "SOURCE_REGISTRY" + }, + "channel_index": 6 + } + ], + "settings": { + "data_rate": { + "lora": { + "bandwidth": 125000, + "spreading_factor": 11 + } + }, + "data_rate_index": 1, + "coding_rate": "4/5", + "frequency": "867700000", + "timestamp": 436812492, + "time": "2020-02-06T09:46:05Z" + }, + "received_at": "2020-02-06T09:46:05.234172599Z" + } +} diff --git a/VENDORS/Decentlab/DL-SHT35-002/ThingsStackIndustries/uplink/result.json b/VENDORS/Decentlab/DL-SHT35-002/ThingsStackIndustries/uplink/result.json new file mode 100644 index 00000000..925b1f23 --- /dev/null +++ b/VENDORS/Decentlab/DL-SHT35-002/ThingsStackIndustries/uplink/result.json @@ -0,0 +1,24 @@ +{ + "deviceName": "782", + "deviceType": "DL-SHT35-002", + "attributes": { + "lora_dev_eui": "70B3D57BA0000BCE", + "protocol_version": 2 + }, + "telemetry": [ + { + "ts": 1580982365447, + "values": { + "air_temperature": 23.787670710307466, + "air_humidity": 47.536430914778364, + "battery_voltage": 3.168, + "lora_frame_counter": 101, + "lora_frame_port": 1, + "lora_frequency": 867700000, + "lora_spreading_factor": 11, + "lora_rssi": -16, + "lora_snr": 8.5 + } + } + ] +} diff --git a/VENDORS/Decentlab/DL-SHT35-002/ThingsStackIndustries/uplink/result_01.json b/VENDORS/Decentlab/DL-SHT35-002/ThingsStackIndustries/uplink/result_01.json new file mode 100644 index 00000000..7f2fb8ca --- /dev/null +++ b/VENDORS/Decentlab/DL-SHT35-002/ThingsStackIndustries/uplink/result_01.json @@ -0,0 +1,22 @@ +{ + "deviceName": "782", + "deviceType": "DL-SHT35-002", + "attributes": { + "lora_dev_eui": "70B3D57BA0000BCE", + "protocol_version": 2 + }, + "telemetry": [ + { + "ts": 1580982365447, + "values": { + "battery_voltage": 3.168, + "lora_frame_counter": 101, + "lora_frame_port": 1, + "lora_frequency": 867700000, + "lora_spreading_factor": 11, + "lora_rssi": -16, + "lora_snr": 8.5 + } + } + ] +} diff --git a/VENDORS/Decentlab/DL-SHT35-002/info.json b/VENDORS/Decentlab/DL-SHT35-002/info.json new file mode 100644 index 00000000..609ed0b2 --- /dev/null +++ b/VENDORS/Decentlab/DL-SHT35-002/info.json @@ -0,0 +1,5 @@ +{ + "url": "https://www.decentlab.com/products/air-temperature-and-humidity-sensor-for-lorawan", + "label": "DL-SHT35-002: Air temperature and humidity sensor", + "description": "The Decentlab DL-SHT35-002 is equipped with a temperature and humidity sensors for environmental monitoring. Suitable for cold chain, storage, building automation, smart agriculture applications." +} diff --git a/VENDORS/Decentlab/DL-SHT35-002/photo.png b/VENDORS/Decentlab/DL-SHT35-002/photo.png new file mode 100644 index 0000000000000000000000000000000000000000..47e5f1ebb3250fb5dd069c4657c6ed6145fc7670 GIT binary patch literal 1514981 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%0D{?KK)l~%ViXQ@ch!Mp6%S#c_-?*u3+o< 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

-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 z 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

-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¬MT6mtABs zEfqiyF0aW9b3@{fXI}M=)h9I$Za%qto9|wWb8DWT`|V0;{v1(S=da40V(|NHrc>b+ zV(mxL$#kh^&GrOSro`c3jjNS*o0IP*uX5P;@k6`X>WRB(V&5F##lBud-r^Ivs88J^ zPT%LhNsI{8nGbd*Zm^kc$BAz=#Y6llhqtuhgWt;c*3vBI{fjs^OZM^)A&s}QDqdeb z#_(2(R_ihP-z6Nq9En|{kDa}+z+(xAEk-n9gv|Fi)eO(1!uK~~#JJ*!LF}-cPvIe| zUKP1b%TLwWza0H$w>{-_H+Ks;0{s>C*p`z|D)?9#W|COV^F$XwC&V6(^5 z^{D&<@S17_o9y&(R46Yx4Nd^VVo*bLf9(tgc4nSwS9l|%aj&qO;R$nc{qn5$)Hl_(uDtwOzzMNXqECQ-aH0_(pBb!aijtp+10LKI zQ?G)XsaPIwy=c9{GxDlhPCixFj;o8v+N&np^%iRMLj;{eScD6cfg|;C{ko^!d%PE3 zC!gJR^cRDT(MGw~?z~#bRt*fM^pW0aK76WJ(AVb*!ub!lklW23#Mz z?NOx28|gLtpy2oQ>+7Id`B+Jgjvg1Nh_}3s3@KdsgmlfO;UkPZoJQ(<^W$FXIw&If z;#;*w>AUtFf$qF+ze5)*o{JzTK1kAzKms+`o^f3!S}&&3fl>Sq*_VRxW5y@QYfIo@XU!2EZS|5WEM~i#md%(8y<4QX~Tf^(hZZ3kK zDsFd6K)6{%(VFQ-qxe523cd>G_t_MBj&bR)fn&T^RM#wg=R+hS)ju(t3#^ZH_-eps z8eH8YGql?~C*N$SZHO*Xyv$o&U8*`6wx#|CNl-AS0sQI4p_m!kY2%_;Z{WPMl6tiL zn|z(TIMo0;doqne+YQlSsE^Hwt)A8^cnNeX;xfBrt9}89sKh^s*zSkGxItZX=hH5M zZ7J&wjOf3OoySWFVBo1AcNy={w^0w^F4J4)Jip|=y=pb^^TMml|Ms&FZvgZR1j6~~ zgFC*-6^FLpS%0B~KSQ4U#V9!kFTwRfNMGWK`vy|ooYM`f!^9?4{WhS|Vr$q7lWqAQ zyd7c{qFN1kL!{QCy`>KkHG4} zHt96g9mYDS_=sxd=u(Za4)co2ChonWWtXG)h=R&9+=mE4J%tDEUw6@`A}o6!y2QE0 z+am1yd{W{LAOGfra0{}9#%P3L;h+-L?Z{5kP}6)=J1&0n7w=j*O*BY1Z`0VisC0}E z=?3iVas%kzWK%whWi)32t_{L$f?d}EL-pEvrF++G1+>;CP83V+glqjHDfz!e4-$$s zYWeTYHD>&P^ztlLs!kcYEXoWj+^dkg=dwmhABR13nWS){M^HcgY;MPtwlX-kfc}f?uEu zoHKVXp|^0i-=1l+5%ae_I}l8NK{@||#`%EH*v#sZ$TvH|oz`Uv=Kj~6XuZf{&->|C zeOrIo;k+CfEPyZB6Lw4z#oko(2i)df80dXpF&ZX7MN6y`>OGje|Kf8aV0ibZ*ENw~ z$2hoJ@2t^D$E_<#VVrd@MuKs_+(K2d&46L!VgL~z*Pz>_!G(KnBZ>N#M!kQFYC-uM zgO7O~b8Q_43Jf20+@3tJn?^%Pop4_5c=$-hog>dyn=s;ri-e?MiM?*R;`586?`l(f z^`>w2gaQYpzV3{vC4~}=jSb|L#j_{vXB15qqZzgY{aG6#6G!H&?MWYVaUV5s0o*~y z7ydo1KA`U=bIkl8P^k&JK;xMLQh-H5Mbbs}Zv8=eFx7VgC@}p^Js*Fp1rZ8gyjAs% z*&0wU_W`cpf8J2b+>j@>1~&vB*zK==8m+x~G)8vrW9%`EhM_6qEj{F=}I8%2$P_fgvOdRTwAA zhhTV^NU!Fk*!=vR#L6w`kOZxaupm0U`1*0=#*G3b92wg8hFnfBIW{*X;{V6)#WqR+8p|yZz4Oudfz7=E4daBgdT? zzmco!aw^npjGa@{D@XR~B)ZxtE`DZ(6=;@Y+Ew2kXM` zt>*H|Gy=b&B?r*PHcc{rS!9M5*axkeRH9C;u7~xhVExv6_BY5WAe{Al;e5X@+2D6I zholUsRPY?$n4z#-W%p{>-%4s)d9Zl*g0!zko{FW8t{>QK{%$A5e{l0BADJI%)yk8N z{g6oBeg<6^Q{3SpAIy|@7PfNHAJkP!znuiHnX%_Ca@c0tu+xm>^2%V#_NCA1`%;%D zXB%BuvuWa|6BKlM*;^=NtfOnD4)Q&tDUpxfI)1rpy8R^dIJ~vgu1F+Da^qhAxR`&+ zDRFGqHuvbZ*H!O>nytQ^r$;w&_kd8Ngig@NqPZoWYqi`%eV5b+6Ua_wS{Dq`|9Q`H zb2{Pn+Dn=AWVrG3Yf~C&r477^Qu$EWd0uUaQO@}2TS0HtQZnqRHE(QbB1=I8fsPI- z28tV-{C)I_z~3C$5*Bc+GYUeGS9j-QxtP6Yf$F*<_NKGyG5lD|@nsO^A|PzvigS%k zYcB%IZIN`2(-@K3R0&?`=@jx%J}m))mbQUp7b?qBBV$E=#@<{qBB8bRf0)%veS)@O zak3!kS2|zfoM&^>=Wvf{=&8uX(O_CTX|O%+ru#QX(*?I0)z($Bwr^a4?jBD$+f(yS zcnaco~Ka>ZTC&E4haeKoDNp4 z_xo+c`bti(nuWsS=MKP4#?iF!JsWe8b14d({Sa}bxtCxv zit`z^pVw}ez=40cmTqubexzezB)HSr1nfA3aWApY?I)YADBf+E$c<8O8BKiGopo?G zBEcik`npRLpEG(y@h-LJK_{<$+beJNN)5?u*CC7o98;kb* zE^j;Jvn_8_h1xARa`YjTshDFbeHR8Tg;A?AYl=0! zU=?#+LX?Y}6T4>JT_gKF5nvz6thvMOxx1XBYSS-MVst^E(r6$!6~v>`HOpY^@mP~k zolWI?{q=)HnHS9jl&Yb+TWkNPGCw{E6RSnWxbeHH1!5^7tnDE4s2~Oh3=I6ie!M?! zlqY|RPs`7|XlrgHE3H4v=v3yiOGxwK&XcolhaC=MP=nmnFk0rn>O7-sH$Zz}g?-9I z9U701>9qS(hQ0ejd#RDAgX9#?IU&ue&zRCpI$pbDA#2;WbX0ycTWeWvvfmvQQy0Q} zx8^Q{51+T|H!|Fv&HO_ld>BSHZ5r*L-cQ>$Aa>B&C<Q4eI9v)ifbN)*fa#!+Y~R zdD7qH`_sok$k$v+%c}nQhbvwdVMj!MZ~$ z7V;8LqxORvnoBFt9ehK%+{2@I?>gJvLE$s^FZ09$V)}scr`K1nWi6gIrThb_ona4_ zbu}^*5G2KO1m8`{=o5Jen7F%Ux{+Y{eX6D<;#8+A96nKd4Nsp;*B`zqbH{|sVjJxMeo-+*Ze^!5?o)q}Xi7byUrENK z+dE$hPiV~*Q>qs2#ma75dXfZ10@4CbG@F<`*AzKM6^AX>qvNL9L!^(DCSXft$l`Cr zcG`;vZ-!||pDPL`6$~u)<(gyehbi3ekmD^tv!nMKi9NZ#30Z_YpS~4pS4~yxX_FIN zHhn9-cDSCfB#yD6arvqIB8Eg}ZUe!!5GTs_YJMpr`U_ZclzUxT)*31TG^BKoI73cO?6a(|oV zt-gg$YQNQot>%Pp`q;NlaM_m4-HNf*59$^OO{yHdKpn>N!?1{ZZvZ+1v+CvrAj)Z#uc15a|TuL81} zcGB}eCuokxkhZ_1_^tpvVxu41CDxRh=>A?0>9XQMOLReIUXy_chK#>138zAB=qtaz z++tq@OmE8cS@3GJs1JMguJ2B?=RPU;mBE%-NwwIRWUjPij>PGVd}cm_7cJsx)x`eL@&VR4v@`e0dop4>=tYK8-1KkBl{Re1T~c0hV2yT%xgGK>>~r;u z4gG!kSLj)?!bZhUSs2nK>Ol2MN5h@=_@DiL?0qY((XMoF;;>;Sx?C<#j+`t@vVV3I zf2{pEGk7_&ITd~MUvqg2QGHxxwZfFF5xgPE_|N%@atc(_0xxc;`)s4 z?*<~m_RIF%S1V}8cd||t(H$X1QvX~euX*FczRFE)-GP8Z%y=AwRrozWKX2%tc=t*^ z)1pqm`riBlr0BNNr|>12c`4NgaG}pb8Rcmn`@^k!U?{%v^5z4#Bdz>b5~phouW{+W zAHs@tSm;QJU1#bcF&q4?QGcGz*o} z+?etD@xS!DMA93$OU1Dhm{!XkPh~e#gM}+hc~9n$-cN*8$Y9chujbU)gilSryt*zNS=o zi(2*g7q;rH%#w)HiKr?T>0BaU5NZkFZN^G}QMtzg*_GQqq8Wt_TfrgRI+8Sd8!S_DeArnsnLc(lvJqniJb}`j(*F=gaFa4o-((G>fx+dmGQO;%MMLIY}e{Eu9 zGdMY6NkQbipyAHRyy^hyjbHGhu_4^P( z#hRD|12*X@G?qKkA``(Xd1G~sr5y7g_kFByVOl>h8IS!HskBp+8qOJQLfQ#rSEc7M z%32{M-W#D3F+18hmo@PeB2RWg=cj{qJ0PTLq3>bVPX$MXLf*aE=+TeUxTK4?^-L279UB?Z`QjC^A1lU{?<=hW!&m)b!q+pEy&dkxBOjSa7Y`P!mKN$ zG)L3;H^?k8FSt?ILUm^Q?~*`UKAea-Yn=s7qfxgb_@3B@mRn1Q$Ya@DD ziBDQ^^JsTbw2QuF#KYphIU5}`9Opy7(|@$)_#Kt(RlCCZ<-R)(JpYUhi(amtO2_ZbC<$#$j;)LLDY>*#IgN7Xxt>i6l zb~dS1O;vOjC1O{X6cSw5uZxFY_gJE7jitU%Y9K4B;qGp>n61X!%`t%S?`nuuu2)zj zqBX)rnRA3cAS&z{so(FPTdsrDF0corfy(s%!A=flZW04pe)P|!kXm6C;q@{U32laTgM`89Rxn*xklobp0KA~>jqC^RX zThYTf!1(PuqsM;iHC_8O*75s9;qVM)Vn@4n^D*8DeVX|`BugA;f6T#@IRwxA###;) zL`SF-Ql{sS{nM;IYmb|q%PN5{cg5ctNU0Ldh>qg_-)&yzUP_0x{=xfxV2OZQ;SIJ+Y>$uQ>c>s#np>`r+zJUySX0X z>A*(P_JNP9$JLhsIY&5g0$H`$ldlIq+NE$3?_91BZ6+EIOZs_zNu!ltW4y8A+OOYh zj)yrM+fJ-Zfnghl9Q?LA8T~(A9pe%BSso3o66{0LNJfa~@U66ES$aa-b)VqNzs-3cclFL)eoLeC7 zaUv;4q;KNgQ!=(y{lYJZ!b}guI%F4bXT=v>n+`TnR-T293)mdL1NXz9xB!4x1v*RT zooX5}wye^HOG>LSnr!Gx7SfYaiLhr}uN7UVgs-FoW+vCgh_!7p)CPksiM;2;{R!pn z>|4o3cB75NGv*yXX7x}fp}oBFcoAOdw|O62=HI>!ANt(tQUJS~S^unLqZZ!;EBgFq zaG z#q7>DFBar?(C7bxBrfB*7LppLIN0C>)rc^v)(#~1x26{T!ZppqWn1oc?%U_H;=F^k zujkBam+PyW)*rTV$tMh6v_v+)<;}bjTF*?_$^G{voATdm_aXPZ!^l-iFD4hpoq8!A zneC{n__7{>;Mvoh4G1=LJv&IUojl*Z_~uX&+=hEAX>*>_5h6Am;Zy1#_(xKpwzopT zvmq9JNP5@e*jn}4Gh}~7r`8|0nB>x6j8Dclr<{qsz93Wl2ebxELTyzSpfTF*h+8?$%Gb(NLe&0IngZVxbuy3~5Zs3Wm~4q^Q^>O5JbW`qz(rDwO*i#nNN>?h!f& zdIM#5_o!EKj;gadIZ-uJ9VwaAM#%-3_@JW3HzDi6y?XqWG`ULPgR=9vmn>#*1;-3^IYdJ=y)>o`tv^?Gry6_-9f>KOV~3+uEk!_rUaxi9IC^{V)}XxDK4;MsQ}U*aW7 zNi^;tGvJK5(aN{H5h7ng*Z9;LvKTIz)y#3EQMV#&71jmI>nM`Ud^@L9XM{59N4Q(_ z*ZCHEd`_Zh;&@R!>|dqsEjA_U4IX1vn>yEtu$-NTi0pZMHB&WeU-xGQbh<&c!`^+B zUyu7_(%jGZO{ajSYn|{5NfYZ5ov9rb{rL7=ygb*1K1w^PgV->_ax1^5c(r<0wQu2! zuQaCrrwTwK`wD=Fxem#Dt3}-27eV>Bs^IMlvR%0v%b*)Mfz5c6v>@p#73zj40PWQ8 z5%6CL@ORh<5mA0oG?;sORD>2We9Vw|zOAWc@uz04Tc>!w^QJ)0ly|JB<1_y&72{^i zGcP*64(XL@j0dqa?!VvVn#8;iBJDnU+>{+CWriF#wy0~3kz44D&2znDVkJ;brk$k& zjp$dZhyOKyWbqSaK=!Xo`ZWHDMcw=A4>i7+OTY+cpvL%Pur{$}pG|qdV*cup<;L>B z^O27|_|?NMYNxPqcxK`1^b0qt-dHLJ;xba;rt7s{#pe5Y2p_=)EHHE_4!qezDJiSP zMY|yY2ZW^4>~GF)nP){b?fgS#8h}W@hB=HGqjjgLWa-aCFg}k8iasU4X9)q(>#ilJ zXbt?PS5jD7G=;#sqOp104cKbql4ejKzbfJirl(<(VV3s2m{%`LOHjLod6lH%-iL)? z=I2zFQ1+#|B1ol?9f()AHn3@-=e2?ukHw1C%;-%7Lt7-b8S|U=>`2?|*>=?jMs~*= z9sUSpL#K?hz-;bRDse^HpaXF2?A0qBNS?NHNX9?moq%~%&Qz_BjM9dmq4{{48>5u< zc`!7Xcq>~8p~ha-!TbGra4--*;AxJPy#24do;woe&Yi^h73dKY6D7u5rwhEz*Nl>`NU(GIVn(JQ^n zjn72*RkBcw*dz4(Ft64LlcyekSZ(G5H?I_b+12x#>O}et zawQ-85jXv>ki(CP)m<0Q21>VRLPez_>k|q21GMY#(uPD)S6434cf7>XKdo^a)*wS& zBN)>3{JmG5Our{4+3!2sCZD5 zjC($A+FVQ-UKPrX?{%`Gju!pSQ`+z9a3SXPStr*EuFOTjD^SAG^ZPEMW#v&0wk+pF z`#O~HJ3+sNk<)W3Xsw}DI|K<3oTEPQ_T4O}D+^~Zg!9%&3etC=$&~(TB^-%JDswKb))jR<$Xk~^ zc(fQE9^THz8VzsH^v_DD(Y@W7C;F)l>R$4g3-*Y7`JX!Q|2I>~mn74FEYv~xh)zPb zMC%1Yd4G*?*FqDApxa~x;;Q=pV(P8mn*8JUZ|RZ{1f)R)6p-$b2E0{DDUp`$?iit> zlF|qa5CxPN-E1H@N*Uo8qXvv_MhrH#-F)ujTfbb#^$%RH>wKNh^Z7Vu6G@H~+e@3` zCSF(ZqZu>Qj8>O?JLXRGvty$`Wk~ER#Nem9Y{p7Cqjm{Oy3BVtgXa|znNs=^0d)z( zk%2aZG>J;_)tZFwV%#x3!&Ey8-$Ldwn}79SNgFXK;(Si5y+?r@hUQrszJuq;-`}iD zx{K2$0jbMoe0%bV#dYHW&T;k9l$Vmk@Renk%Y?f=Te(t^*WQ^7Ok1-RLcaR1O_pHq zm)X{Rd%@yFz)9rPtkn@yIC zSAj-ckZ@2a=LY;-E6U}Y9Ef<;>3qv?v)}voUVaX7(AYia;;2CRp|x{1xj<;~l@`-I zLjPCA(B9pxIuv(PM8aOjrn&MDhKAjgJk1ThqYLF$>%E#PY#xjjC0&Sm0Uq60?~gXN zv&8Q}&-iHmY6C9_z{|lrc+7rK9`v*tstld_OKN90IkUmwxLJ`{yej$k$(*M00oOM1 zA?TujGMMQrx{fFjCRturM+RR-jSp~yJ^LEM{w0`>E}UGozYy?0@R&=bRh?qIAMoO<8K*jWb8Yl6GPKN#wL38cctD}(=*3RSXO`P_RE~@@+9YOf2iz^mCuoFB1AqX_BG+pfzi|gNj zq)XHluMZ!P_LHA@@QRo2xBj{aPhiT5#Vs3%25rjtQDAYk(H@ zOyXAU;K{WV+uDn`!~G?x0^NYRyI^UR^dRhNR?U3r{jBI5s#un9Bb@dh7%!#T5nY}K z2MaTm2EN(Y4Tt7;MzHaK?x2VK-H)0X*V)yov#T*m9U-hQ6TB>7aw&ELIF;c`t41+D z82s;r$M;sAq#~i~g3&EMPs)RLik$-#q{aXa^7(e_dQ27l+bor>rG8$8Yc53*tOqHL z+eFp9wVNo5?&T*yF<{ysf6kk~?&yYFSVJ=&tu}r_i zz-?E7T>MM8X)n<~9A~*9fHyoJ&V|vy6wT%(}%n!S~?M<{94o>h~@+g}e^WXA4DKe@HUTA8^d zPop7mtKsN(YXf$v1mPR(q55=3kgX`^d^v|c%jI-(YjEqri%C`9xmNwT$RMk_^A7f( z=ibwI3EtZ?5)*Zfx~xlYzUm6+sTg!(bgZ!q8`ky9)Wt^E{NvlI=hw7e^VQ`rB$HNN zyxm;@n+e;T;i=`t$430m=^mP&Di!N1=uVWW;ZH-ByE&gxyfV4N^7!|8pvBj&Iw^`l zCtbew^G8q}nrJcjq$=%3DK+ky#Kn15ZHo9cjz`%5uxmTE0Wgl(1Q!APs}pP57`IH6 zW8Y7N|16A8(inl(`K>wF=vWE1U$3XTi8rzTqBX@iIO`>Q^WBnL&`!0h_}GPUTic&`qpcel<@X@^xtHP*qUp{PAk8BC>>bb18FSN z%uOM)c=*TSnftkminqH`N+#HBb!(*cyJf(Q`qsVwx#8!*_BLdi$~xmiIf-iSF?DHm z_exq0uIA&u>`-%I)@-Lf!w-Ftc8i0oXsZYChbRA4@5S%2vwcp_f;Yi>g<75vjDh$m zyJKu0-Zb7bX1qPaMo{C&V7i99oUh4t)G5b*i(G$Bw2Jr-wI%yK$*&&P{C!**!ZcJ0 zec)s;a2p$SIz)hRsOAIPy@kSn^jG02eQO>`xMwYjq0XuZEF7FE$^UNe# z-2QR>x0x%NN+sHe9Htoe+FU)fRY@?ldfw_IvS*}>TvL_A1WH`zxQw-UBEE63S^&!C z1}7cVlJ@T>3JFvD?{V5tbR+VkmxE{VEv1*?FGPr3!VaqQ;!CJthr8CqvfjxF%>E1Y z!QjUxt2UnGgg?H!2ziZrE!O9JbYUQorlnYy>@F^WWmu+yRegi{x75$oV*E7ZoT>LO zDwZa0;;jm|x#qXhv_OAv$8ga0FB|Yn_B33vaQDL%Vv`DUll*@Tk=R7aA>35M87ry8hoAai7+;ZbqMVNOUk{K&=T`H1i*izM- z)hAoaHzz`M_`9DtccjLg=-Fc09oF_M_#`2u_O3i(Pw>T_N}<6O*vlh4=x^ojc&$bE zZA_}#f{MsTyPm4_*5h$8UXMZl`wRMU=SW%p;aHsIdF&~HUIu9zCKM&bm}^~53IX)D(4}uuEdGsH`8Oonx<=o1 z>;%%p5JQw!!}e@UjttC%xr2p3KL~c#QQ#IfyKq5}0R2gS=qeRbMm5sqyuYvMy|NCp z!UrZ2+{EB;qux+&vQEP3_U)R6357&qS$-pQSn%+e>J(T<=cDGS?Bf~IU?@aUi~p8h z%a&t=T{hiMzj8Wh&y(l~u}Vi5Rl0-b?ept@g9{A(ez9LL_Psgm1KFe(Lx#Ki)Qk4J zXrneOUQq1yhA6Mj&5A>Ka-5xwhsvb*^q~5A#sbdw*DlSM!*81RhcugWJqY|WZJ8Gx zkA&XSw0^I#q9W1EH&|=9=ze?7sV^(;`ZA};31Q~v$mf8TC&_pu%RfuTt#_pJ&`)^^ zEB<-{qlq&tF<-jf1AE^^hZ^Rs?ITYua+&?q>+Tm#w+#0oZ#yhi|5ScaxpLy%x#ubr z2u(#st&bQTeX4sZy|Sl~(9kcs>N$&8IPHlFqX@nZ`F~s*@`2j;t@CDNGm(JCPq&el z^Pm<>mpfM+lN|usyCvMXKXqykFxS-HAQ$yDV2Ylg7!{)I5Sm2;uzQCWn={g}V$-Da za`NKh0)A>J(fkJvm}ZFbQhw@0R%4CL+3RSFPJT|kVU@Lx@|i6wX1jO1J`{MG z&unJfCLgQmcW(z5ss;EO6~*FYYBL26Az{MMF*tj$dtt#MiZ}cmdAcO zSQHTpJ!^7MD!au)wUXN4#b+pxuM4nJm%WDBpH?FAA=NvIBNyFZYb?HSYVMgRE3Ot4SrD|U z8W%}lm!iMwGdJnLUSG#+rbfkQ<0D58`j#Zp$@zh1Yk%W2&t=g${{@iXM_ymEoYh({ zUxecOq33;TR&&FUhL_daeF*fWH59`67yNpQB(*`RPD-dj@E6s3Kd5&S{qUgP{?+i= z=GsUMhJfz5{7umAz9fOkeMN$-SoT#3dTvRrU(LFg9&Y>`lqZX#V~nbjk2IQt#%|qZ z-U<+omE;yx`_KQVW*b(i5oTKwZx!o$Z7~yWaUJXF&+9YZv*x7eFV$Opxu#~cV#*Zp zCm<|DCyx7NkYG*Pn4w_3ZCV&(;A47E%Zux|^aaPdOTyT+qb7M9wiFuO8UGI&&958o zg&!}u==#JLSpb2rdfzoHg}a{GV^_YdUX_rx*6lk+ud?m_`TA+J3z@S-iH2u=M{G~c z{j*lvIGB+jPE0vZ^aQWDtf74a^@sAjl#K!lun88k7MOjMCt zF=vq6AnI7FA!`l!tLRY98N?$fUD>?Co4@uAL(&3ud;CVx7 zESpZ^Z_2Zr#@B*201Y#QdmM$DVfpF(IQr6DIB_Dw=EG4<6~})&zUnyoEeiH#C<4Q4 zMYpz;W0IOE!)=?p5sy>RXVp0K&oBjopWQ2-G8F_qlq?#=-s4jU4eM;-pe%mTx$6*mxe6yL9sH zwS~Q25HvfyP(2N}FJVk~7*yQnba@cBlUBFfozs4j?0xi|@a?D26xXgY#SIE6>up*` zjcagE+d*;JVoPSV&wUKx{IPr-bab|(+;x&h%Co-yiTA7g@tLb!(O57*%fA{uLj@6T z7^Y=1`&Z%fu`4I}NI^F7@35b!eTSZ#aYkQQ)2j236|w5bP!q0wd5(RNm8&pvX3*)p9|5?=U$|-}bky3~ zlQf!t_Mr%{DXFz-x>XSnW=+~r5wG+_2uH#JZm>s;{$rg9s z&dGhsaEj{1-7LBG=jspJM(bRRE6+F={fnq`%F(M^CbWyY3GSv(bvaI%j(tM#s)fD` zL)F|xCpRD8GS2pAzG~8>Zv9op-`}v~M%mg295J#HWq-ckB$*2mPVuw)2PFdntKhUfuRW|Z8+U(1N52j z>#ansicv&I-0>{9aVZ$u8VE}s1FOqwjMS4}Xi*23()bj5-(*c^er^3zP*>*ijy%RD zv#754qp$-KHpA%u03+652K#B5M8Z`7+aQ8)5gX2-oduTiEO-QPDV{G#2B)U{xrFu&X8F(VlFXq$140CCEvvg`gPSe#wBh2HfQn0ogdMA0mjv>a?#m_xB6 zP5OPgQUl{t>*no+JL=rKZC#JKkK})i40COXk)nd(?e}=xgPLt;8|_S={c`DaR*MRq z-#$m#RRQxaF5t!;CK}#zx7p|7? z?FHbuu1C&!&+VUm`|GJ8+tc>@NKR)0PnQ6GHJ4$%ZiO3oQu@F$v9+E>(HGTxeD{@GHP zCFN;)x)y%3oO~7r!7Y&2N{GMhy$jET$d`W7LM_63sL)gIc{y!2OatEZV70K>=QQ>PH@GqS#)H#u}3$#!4$NW}^ogJ9|w4Hal6B`-h^obeM`{4KOB0csCCaFJa z2mWIH@qxtPvBjel4m`#ZPc*)&HJZ(XL|+U7@nD-P#va&4>tfh=y_?EWy)wl%u@a@S3}N71WBm}VnHK$jUxYoqh%Fj}`l zoe?c?)U%~lv6G+c#(A=l)unOQqA^Iy+gc0!Z#e_$X(E}r@ru!oR95SatUh5Z?AJ;P@0%i|3)%~6 z#vWrYWMW9zcW{!UzzSwG35cs6Z5t)m`o#dmofW3EF2>esRfLi@7T5fMr+sVO+W6l^ z3gDgH5}dH1>J3j!%?SxnkLa@-Q+2CWP%S!39SQFHG4xqtNR``+DpPTOse<$4u-Dvw z+&ax)fGo+`J-v_G|J=?FQ~vyB+$Ad1!#W3jZ3mG>xe3SL)wvK_i_^hj^l6408LY_? zLE!Xwg7SSN%*y;h_{fcwtjb}KWZ9jJ`M0s@0$aei?qT?x_tuG3>!K*y7&#u~CWn9v*H_a(!FRD*kvRXJ2`Brp)diHWn71>S`Ol>w)w%>M^cwmN~x6d4BQspsKrV zXI;R_unLzumlEka7JlXZk))b9?n(1gfk&ikbok4YPaC|OT0^g5z%g?G+J47tBO=Mb zM#p;V3o044;0lF9ex&Y_FWb9#eiQdtwjwvmlOy++!z1s&H+<#u45l~uH`NX|p9n0| zuaB!&r%nDoSx`H7{*l&5QxqSc=A&lK)8vR6;KvU?zUF+o`rbDL zDQz7Yi%!V7V)j%wmo?6BP4BwdEl-B+qXv47zBY81KjPKdd}bM*eY-w_nDub~T*RHl zTzKn6jOy-UGjqxll)Qc0e}diEFRz?;{x)e6OW(I%%C4PjwWBI}Wo(5|$DE+qs1rEh zfJbose0R23y-c$}t30{xQDnGjSSC0!7SZ;UzNl%+>BNeaa%eORs)7DdqIAKn@F75#A_oD>}0|DaIWyLx+QgSM6PGZKS| zV~$i;#a$TY z=I#CIx(v%Hkw_!R#M7`AH7oS65JaH3t%-_Y0AKwHv=JDz#M?)ukVfb<=cY+Krb|K) z|BSG;y?;j%wl=5u`Y3tZjQeb22{RA@#OyAk`17;Z9b;Xe@MMO2_s{g(Tcot)9&Hux!S4n^HIe6?n1S!ivdsCM1Ay>6=-Y)RNM7_)ll zMqF)xoBN%sTa@Io{ayP!<^1WET``0I#>*xO;$qA7!s23d@8>jHk8MJWk6k=TLC&#N zK&inD9Ups4gn!hGD_O*6P{f^vIQ-UUd1s9aguvQjC#oDZiVHsckh(exGM+c4FZnEeOU9UWnoAd` z2}?YQ&3eIV^2}m1?AW02>Q*)rwmwA>y_8iDIufrL@)YlVvj}8-ecM%b$=Pdmih?2T zs;lX`1QR=;LflCzt}QZxeuQpw+b{+KL5AO`<$sG1a1wp^JsEIn2yPTTQ6gy$S; z-uh%Sg55<+^{_Lhb%}qj@6oDyD*BG4$7XTy+oAB}8UcdE*{TX>DD+>t2U@^-^A(!b z7Y8eEnpqXVqM9@UGs{TZ*%HiI-mOm9A;F18&OTdh_g{O1@Xncm>LtHqd|XB0m=+*NteAUp#!`0PXRegG`wxcz#0{8L}v+~ zxGVEdC4&|dt0*L}6E*s_-KZbTKH$M!BPDBIZEb9( zM)e%zLAPU_hOxd4kBQsSxtFQ}V5*r9E=~y~YX=Y--O|t)8;)t~fr8{d;W#l>+&QPk zA($JO@63dhsK~I+xvrdR1aYmSt^Zl-`aKH#pRDlJ>-l%e4JhmbJ)pLCf3?cp7zsf;KIK*RqQRk%xiv3I7{f-z_)4#dVVx+6@ z>9W6I_c(+~9ktOjuoFnlts2%n#JzSsY-{-eF7;)%oi!k%ys7t-_xy9aG@r7eA8TDM z7L}S(=lHWiKLmJvys^a#=+|?xzZL{MPs$rihvN*;v4pHVZTx)lXxBmajSu{MYf8FH zdD?`vHAIqeI)~Cfp>EGpCk@CAo9gIVi0?#jb8m^l-3?@M+rF(95v4wF+#M5f(VlkZ zp#i`1680ZwG^FH?;kcQ&x67%;HPI{rjcbqxP3k`*IzOHIQqS%_%%ZX~5p549S%MSY zghn@lmn`0*7Q=6f-5IpV2`;W$I05)?IZ(j1gfAm>siRtXLCl-ufE#|~*H&mYn4k*h z&4X8O64T#wl_y)HJQ-s-Anta5^Asbp%UYi<>WPvo8pX%HPK8n$YB8~YL&cz3@8 zgN$ZrgQSJh?k936^89(+g;=*h?E-dQIQ0JRXph&2PdLt;YCu3e=d$<3`-}KKEb$F$ zKhS~?Y>hg<{myf-T-Ij~%l~^OrKP6dCzeGw(Sk}@2=WY&54t_9Um<=kyWCXtgCBKC zq$48eLz8)H+^>$esON#rlY!OcQ+KdKDKSRICtS7sdeuxt$)Xua!_uBZ77M>ulDB7) z#UkmKp`Pnh8=jB;p=PR+XpZ_);cE91fzDhS(T|Ud(zZVK&qy4$FxbL7{xJQ?AAh7h z{6Hip)H(LNY)e*JMq)(B2CF&tRH=)Sw07Yn+2}5QC{mS8|I8RfX=LliX^*XCkk9SJlM z)2$8m{o=T@LgzqhBp?iK#o2A(~zx=;~Qtj*hB1IcwvkF}xO5l(kO_?c`eG z1)$dkk$z*wW0!>StL9w~YgvOef5pHY+4Vi|F#a>v(ds^g3QlAqQ~1MrJ+ip zdrV1Zqplwbe_(XOJx{~udY%;S9xNBKDx1!o4dA@IJ}i028opx7FctT@`DlJ1X~<^o zhu~yPdiRjts>kR^GV-WeE4yUj%TO8V^Y`P0gk|^BZXjUyC7armWC4T!wn4PD4M6bW zcw%u;<{E;l^VNmbn+qBx0bD{@XjWC)R0vRF&7xvKI5wvUW`BXy8-BUi#NKHkJ-q*}JoOru$l}3B!c~a!I8ZUov%&r`-K{UhroMC{O@ZhZLo_+50 zotVcTC%*b4o%y1}>o{K4U5=-BHfdFaQb;$Gdo=I7qd}6X=i2?{`2|iKqAP2)L!U;c zy$BcO;0a_7?PLV)NY?2NXkTO-EqYUF^@+e=TpLV4fB)Rnnw@V1><9T~Sgss6_AeMi zu4SgbH4QS3jYR#Np1s-n?&e;1Y{Y5Sb-=j)@8#G2CYsrK8v2+`{eags-LVgM6jGec z?Ew+rUn$xy`>>maAR27*CmGa#cIRlVA>lL;%APAFol`xK)f1QON4{cA8EtrlzXnhT zWAN&~YaV~i?`>HKpl{vvJRQ#PTVdp_b`sONpKLe#-tG0)?s%(RNeSdd?xqB|VUqee zyId{vwAd){6=Xt5=kpnV#6(L@&ygMs%V@L$dzJX0X#tTwnIgg>N(7Q9lr*YLNCtX6 zpZzp=ul~3kDnQtWd)ABBn2Hn_T1tFCwrVNGnZ2_UbzU((pTWj&>I)q(YStC4RkHXJ z@A9L6z%Bj7Dc1;ud24ED>7jC0opjbk=-VHQGa{eV(%P^(x{C$oC)4}wFmC*F#nwlJ z*;|V5xD%eTL+YgNhHWYwO8?FM0&5nu6$NxpOmaBy13iK@3Kp85gERla?$2^kFMsFw zdi2Y84gC!|mLtd#@h<}EA_Gob4CA>9{X=>~!L@&1Sy)QCc(*V!${~29>?1_Y#alsrH{L)@W*EgKJS;CaMP5iLiS?#9`pM?o=7) z!hgK4uEV9X-tZ6?%yP$awqm2{+;B^$03z&1GL_=bMC&7`BrkJ+E}MGG=)L*FUpH&V zJ-S{rwXz5vVqA;}tL2^swsZp|sQL`eIOZah2Jbhteun)&>Lr#SYNAal#gWN)91x2k z|FtKrm1v&B>|5v$xPd_zF3FR@&9IxWXL>ha>O2Mf7ecw`8>VkH95_eZ*B zJl(qj3xqo*n+Iglfj#6<9~gX*rG1e#iiBVhqi$Nq1sA23uy$Q2FmXzCeRl9USyhW& z25Xb2PUp?L(juvPs)WZCD9jSVbW;)Sld;Kdf2$t6B+92>QZ=gTDoVUwAwm3z3G?p z$gSG3w!Nkn&D6|IXxt)lNzFXlO{i0E>TIAg+Y{NdFs{Qcb2Ow zQ2ercrPiUQxqZE7VC;VX#|=ZJw{v=$8$A!44&Wj-`t+{#`={?Og~f>nJ;%P*&A@eR ziwtlLtBZa^gp$!Dp**^DLk9Qi1B-zIP14T!L0g&YIXyJL?VAlRc3SD}#;bcfIVW&IuOH-(l$_|+)jMCTc%-pQN>~Sk z8aq6I)LaKHq7=#>IE|7W{PPa;_wl^!u@H*%pMFCU4~V{DjbaO^Xk>?zEwnZ&N6~%)&@(`rIU zP%^MQ>3B>TNofxb6lSdFVB3&)%QHVYH(3nbq%BEvkn8o;G{zZ(`6WB1A*`#D<#y?B4@P)vNBMZqLGng{DR;cM* zNO`%5iPol?kk5uK(j2W<={c*qN){)9vmzVKB_~ou_C7Qw+_Wej;x6Um{Uesl@!O3?;F8%M>6As{H;Ib!i58hULyM4E0}nBQgbMpcFU;@ zly0R)rP6c#C~0oYg(&|}^pWLptQ9|g6qv71^dI|}2Ej_5bG&dE%S}`e%#r~_qa+-& ztV;zS=!C|_^y(jPw^lw!1%(8LH8fq5Aza<>M>`^?A6+(T%j-YV@ETO%c}M(>NSw_l z7^-5oXo!=eU&WC*?~BeOi!Ej5eyj}ZBXUkWDbtL#opF%1Q$6I|Vr#Gh=tZ1XOm6^- zS1wyoPsD6L4d>A9&g=}Nu5zX3?A~M^EOtvW()DCQOLcpGR{ktEt@-&)EusKl>F>Ov z-wyUq+UJ6(n&NnDo2*X&%Qn{CpVC85)zp!Li{p~+^~NsEgm-7kY1eMC?sCYm78+o} z5zcp8Wk}r=Jv*`sP52g`mq6SqaWqNj{4wlUOjBvgckRGd5PdLp>$G8JR$Qz3Z{M7m zM(LKEhL{ziUKAu&#&GBEmnow{lZiX+2~Ul(?%z6EW5vw9iPBq$k=@jT(71o>Q4X5# zVY#o1SpN}~27uGlKc|u)ars;AJD818OWl-`nKKZI2SwL7AaS2z0gTx!Q0=!#UUGzl zrzg77bUS}zQVT4ax`?#~_rZl9#L2F|{lrr@pW6?@ByNys!q_xkkB2!pQUhW^KcFmq zyiN}!4^WA<%>`#Hhq8zOfA^^w{i&qwQGc3Sg=`z06qB;0|YUL*1(3 z{ne=y4#e#bQU^I{OP9%mrxOXHF8tb?hJ(8J)I^`)C@K!Wk)KRyM~pApw(;lYVZPV{ zsbYTP);b;4q|lp`p-qrVH>RJtx!+nJoiZHBxn@$qax|XSD#;wKj-SX|TC0&yf(DGF##LKjbS33d*1lhH zvBagm)lQKg(0{3$_IvkCDD3d}qq7>4F=-MtHPnaxu{;xyF|n!HMl?2dXrN+|r2*^1 z<$W(WEukCE5=^Eg7zrB?7`)w$pJ&h{sSbPp*b_dUm?1}j@A>#pspZkEuhpceul1~M zlCo!&Vk7Icm6!cu(62hk|Cbe?ta%77uwN)7I;2GsD>E7glm+uLN}kO*us*=z4ZN!X0o&7 zvDMKZEBf7JSQp4o{2RzVjLX`Z%J^c)ft^WAYy5Erwu(a$>HrP0Lh%uQl23(yY%je# z_}8{y?$b);dNI8rI&i#C`>;UZFqpY=Ti74^k#<3d_vl7yW4S`9wFCP5u-T%0T};a{ zRt*WV7sozynq=14ET@Y|?}^}jGY~faG=B4mxL0l-QS{rU`d;yFwMv%xX?H^!zL`Pm zJF1K+_Pz5%+jq~8tt#<3TW9r+w!;sfQ*ORAHJshbKF^f=gX(2S;4o*M9;?uYX9~nr z`FVk(E|2nat}ksLQSOu{Qs0K$*}JagtS^?TkFa-^oC0n{uQmq^J_C`5#wduJrs+$` zVuR*xiMoE1gfLiXu>YOoi61)9!p0Fmu4JrLt9CcIwt9D)AitGo47yfR^tweK5!D?r zI4Ru7e8AZQu@ii{lTlHd%__4XIOi{ro&;Yy;5D4}@M(=sX=#Y=np^OD=*IC0WVU)M` z0@p94aSy3+aBPY3sf$2eK=#KUZnwqKAl^a+G( zx;G#lEEX08lZY7GYntxo?&R1^ODvGx3kxoO!V^eJRny5YMC=f=Bn6W z%NVF`f8r!?VW{SynZMEhkzAG4TI?0XZuMoo*^0{AZ^aTnI zjE%tW8l<$c=QSC@@BVi+)+m9YN8f-!Abg2*tzT&C7O%pnX`yEAld(vi;{pOq)tBfCT zB+o*bp!(Y=jN%}bXqaX-Z;8KY$~NGn*2Xeb1y zhYlsy`#8NW03|MtVyo>s?bm0*F^hnn@GB9CFeaa2NpN7u#Y!c#KF^__NUL?4Un1g+bV*K#IT@Om2N1h6Kt;~* z3Ex~}?$aubVC)x}@m<4LL$(&Mzjf%}my~Wb1KggUoizLWm0T%QN$9u{$j_?=qy9rs zNs<|74Fq-bGc$jE=sR@Q&AHbeKlP2ZQJG$j$En&*^7uCO`RT_vdFSWD(58c*+6wXI z!DpU`uX`A}16r0!!6@zwP-1hG{#T}0>_`1-XYLxzz{7HlH<;BS*s>Wi6C8)_p&J${ ze0`Xie@Cyt5GO=U~one^D9w=7v5h!;Wb z66{hITl6kzle-@uy~q?0Tp_zq*(C|kJg(ell>MIG6;U%B0bsq`H}D3eqfb$^o#Dr( z?{W4L-w-#f`F=DpPhqJwh}NxpnEt#ep=jPs=EOeYQbZO_)V%09`*|eMCG5rbtqFaXKj9=j(|mE$v8m^p z4|Z&Oyn!NE#)PhNMmx{TElH z!{e={;Bl!;LopErqeJf5l(#zQmTOJPQTTTNx4h3POuLKsW&e~BDM^R?QR-N^fOp3z zm6n;_;@R&6)EoMK+5XqWrOo08W{aqRZQ;aCE5(!V87EoYcfP!@KznEMr}=(=(xzAH zwCA<=+b(;?^wN{eb(3i^mG|M@ar5|-rfVgQpV?-n>be|jj?Np;sJ_Xu8T8$*9z9^N zVOp0oEg73VB4-5byVph|65IE=~MH(~%eh1Arzaoqo?p9M;TTISn(hoZtfQnmIgR za<|M=9e1s4Lb-M$z*TBgkYb4sB=vc^9ggU%0siwNPuwJ>VwI_NWc!xk z*y>N#&L0Xc4N1QWuDxb5KQmnU_O{O0&v*Cc>9B5>m$k>9>_^WHD*(?*)3>b~LNbjg z!h{4=`C4xQdzX!^GDMB|H3yd-nKnPcW)t#j?7njuiQ%;2FU^cU+d)DYW%=ow?_nhg z2J^DCKSC|-3-6jXW4+N zk7YvfXSw{tl&ux@g16A7Fl7_?82hm1f-k%Nm0)p2htnC~)FFq4He|*+HM-9X)GS&K z4YseQ^rhLBg7YKrA6l=xe1BTwsLGg!%*9?Cw>=KTV0+G;VZsl0@*h;l1Ojx!Guz|& z1du*c@BwiS8b0zLv9Ex)$b$%DlRibY8v=*!go>R){6L!h7F&XDm_NX%M+7`M6S}wQ zFff;}@!ijh*w|z(-*MK042ws(Z2`VocYTYv{c(9%$2>1RV1!;<&0VNVqs{V`|J?(Z ztn|03%9$S6=+7jT4sC*~7pM%;#oChw!d{pSo=`rnw=otQj#8OGAr9vcdUk*4=st`2 zcbgiwbaK$&I4}5r23r3!^m)zj4~ahD+aTu%U2YP{T?f(RD8I{76-da%A`TjKfdI!M z!s{F2ahZz?7Zjk=h#uxZEZloT8AFeW!hFELxau_M0pMVIJ%DMts5S_?*EhD6?`ex& zOw8rw=gEgH#R@%6%Cs|e390?v$gy-J>aO{LH2Bz$$2g+x3R^M%u#)cLY8m{Wb>3B0 zg(**)I0X#6*tUd5UYu0MlCjg)dlm#fC&{Y166MJ}znZBabZpv4aTrM< z_u2-dB~OH&^~HC|gX?vP@Vyj)_Z#GSB6NZn@Lqaw4+u?WKb#JeS_=EzWevKT<5>&G z^S%i=+<}r11ag)ikT6F^97Jze*D90u*P{NXZD9k7pHq{Z9?J8He_O;P!{`b56JT3y z>trWx;Z{YJVT`fcfyDi=d`V))Sqr%5L{j*tVWT;Sk#eVjsAazXIbZ%i>VGzJmjCUO zbGUWJMP3VZ@2LM9Oh`=swQOD9cg!x3-Lo6DWk>fDMm@xG0SaEMDqK=&;by+(yJmer6xAB^Y5zHy#OeacUK5Y>uez7{O=Tkldy-zXfKw>;vxnU{ndRU#pb3W zaB;6Y{z}3{?$p1`5+s5HtE~S51})A4jF%eXboJP5HQ`2FHruFT2o-!;N#9>t$N2EC z2fuDztywqndQ6(3ZhNH>z9>ndf7Z}yj@&>s7}v?SPKHlY zT5$n!>HkRsO%$XQ$2pUtrV&@CJoDMty(h|WidOT^Z7*#5abst;gBtq{^|^a+$PIpe z-@l64b(ccMyR7y!QZ(;tSGg{4_*d4{7sb04+A{9bQ~r5sdDxM;tg5>Mur3zb3pPyB z6nRdEZ~G!Mej?lsl7N|7^(VDqE4915;A#C0%5~k8ueS^2am?p*W*4dkYv~ey&eXmQ z@2NH>wUZegL^q;P4U|Re7MCr6_H-tOmQ`G}L~G7nxhHD;6>e6AYlJ$S<)ePhcd$MwYPUd^lDe1Dr< zvTCXxOS9<3yXqo+I0b6{-3Wf2${JZybl?G}81oRwS1q=s&;KJm`p4qTb_Kg_OkHFk z@ma{8vSqe8OD&pxF=OL79N~O$rQ%5Oy;F)MMp%iQ*F1NJ&AHy z4;)C#RZ;CqEDW$&Wb6J9E|It%*mv7*_rse!F&Mr7ONPzEGzgwjCKArWNQz1m=P>P@ zA6@aj$M3M%@zFtQv&fcdy=PU2Rr%#Un)(ve@RSl_zemwg@86Ev*=_RjLCkLRD9o7v zCxF8Y?IIqzdBfcbV8Bf1lxSlU9ZeTAy zZrST?r6)Z4cLPsvf7z&cR+8XjUB-OxKaAwUbrn>+5X4ys9~3Od_v)89K8dway-OiS zselhqrH#m6=1JR^ElUsQwMjxuF=bnB3^&ty6DNZC(uWy?)tmDk?a_Y{sK{X#?8XrIU zcbzqBq7Jd0_vVeQOSu(L?vEy)(7xG+^A(5g+`+u!@M)ykrmptd>Z#jzNUSvvW|;cJ zN=*4hL}aW*1ZJU2jnA;k!6^g!$JeqAWp`rn4Kw~#`Ui88ZFI&RKsxTcVxbFm2Wxp2 z{fy3*_~aKhhjfqltpJ-p{)AF5MiWdW(79S4s`NpO|JSxHwOvv`cC1CAqs=$wO4ij$ z(XZlRqB%?@h^4et+|=-M`P5HYV7I@d4uJKm06 z_WHC8=3@u`EmK66+>WC*sZX@D?pjAJ_#oQ5?1+&VWdZ@9j8|!1EM!+6I}4>O&1Rwx zSyZ#SOQvNsKA|Ct!S9uFw$L!&^M%Ltt4|siD2nPvHF)9eGJ5*Vn!ajy{HQbNe^b*m1p+jAkf&#$U=y3aQRTzC0Xp~>V1P0hAj=cK@nu;QPFgu`c}t~O~H z)F!-m8ST0%`(ERFqHp<~+~@OgOF`G^7&HDqY3R$dr=^hAQ+gTlRyq)$Mec8doFe^V zFnqv>i)G_0H|G=_TMRrahnelQpJWJ?`o1W!E*S#*V9!D$Kf2idII_4Z{=Kgax;cCP z0qS#5_TKJvxD&}uF{j$Iu}F9}d&}ZWF9DR}TKTd!l{2_)@%X$>B_46B?1k0Pkl<`!$?}K2po79iX3mPQx@A;nOrxws2^+~I)IO;2hkE}O&r76Zkd zolWIp3scdu*#zmG{F6%-6mp*U(_$V(##GKhbaALpZa|u-c-4~PEXK39t%#R(V}gkO zto9tzQtH~9n)%k}%5d9epqhq>Dx0cEtL(UiFyqs**iE#M`<&g`((DpohILz(tp>F+ zUZvrb{U_CfZ8Zqd;dg!K5&B;*8g_bKPo{R(xTUn;%q~r2&^^8V)ntyGyOV{(@UE+c zVcn2RsY+4Y$=T`>!aU^q3_Gl$8)6=1f%j}jai2wyU=_teBv0PId7KMIZ*NbLZaclS z_P10J?ly5>PW%;>Anhj|m1y1^Ja?tY_#a=MeO8EZE6mD+m)Cjm9W@bj+ z-W5e~WidqcM4BC-ndgOjlr~OB2I&5lyLrf2Ik|Ij`jJD(_QBuQs#R`;OvJ+!sd>ZZ zDKfL7gTFEc#Md%`&MoE>Ha+RnpJE&&ch+|o{;YZzV*F#d26V2MJ9sqXpymeZwPO z_Y#b;7xj`c_9c0yc=Ir>duN=;QO0s$l&Ph;5@}|GHj3?|0)1wwaZrPg7C9NFz8m7IY zeZDv5`*ODxb+Tis0J&P2I!n2Hs%%R94)0tAe7N?bw`9{8z{}vJ6eT@i!2Ke4d)!g7 zrBIyG5b)RI8}edQjGM+#X`$2g#%WAC*K0v?-H3{hR zwQL)Fx2`wSTu7QcsIJnaWOKiJ*Iv*2=W3g-ipCr>%voR(3MZcoPN;njw`dtu`%d5M zJp4)i*Gh?Hx*UZ%jq6Aq{QgUh*1PL;20Fo&jA-;Q*R1JZ$CJ$iyKytJBO3VAl`t>9 z?6ER4tmUQw^T6Tb`SRgxd#~~~KZ9JN1-7igc+PESCM$c}W6r+5 zAZeEETGQY?!(a68a}?XE-n4JxD!!PqymKAkwTCcM=jqDnTRi&GSCM#6x+m;xlM1s7 z6kGTr8!@|iV*heq#@vFN}+e9`_Vy-F@IYee;N0Dq7<$GMG5$z>h5DgEv7-nt5w z3+q%uJP%2UbMf(zuJ{?U!p#&gp}F%sSf?hSvu@GfG)#RbgjO{3dxS%^;(IA1%VL8L za59GhIbRr`w^}Cd6hln@Rzu^J;JWRbqh+{gB6`Mm8oDPGNVfci{p^VspjVhNFIR}| z#=gy|?f2=+cKOPc3s4=6BHBGT^rVLrX|6*&<;N2t>*& zg?lnct3Y|F2caREBN4uUBDRVkMcE40o8NNnu5~X#`4RCDB&&HfdyQHk0Vi7$C`wao zOTx4=E8F(c1;LIur%57ZdY|&IW@d7io^Ub#yuxd#%&n0t%^9Gk;6magQt8Q?id6vZ z<1a5*;wFUuxqXZxclUa|v&UL2p>lANLbRcVZvM{juRi*iJ~d|L_?{nRJ(Bd0t4$$C zVQwcSxNnxt#F}}-QnwB)PI;(H3?mA=D(;)pZG7zhr3lkc=!?nIy%0Y6^^9$o zFqeG-s79fjLlPQ*;k#$ELDmX&JFI9Icb=UWdHR7_v%W|;f)R9)rrdDp4oNU}kpfld zzN-T$%N2Cwm^;XAsF=@li=IUaHlrQ7t%TH|EC-i(2V>9D*!&e)S1Lhd+!v(wHGf1p zaUuQm$ouHNAy=~(77m|1;+~s%`z->O8kF3&pRn`<^<`dgbG zNeFX$T@Q(AB-45=oUB|AA?=$An6@Q#$g(p`C@3`DJd|)0*04HZpFVbEY%nZIkgb`u z;HL_;=ESba0Oe|+buS3K`ucnmp9;3_{d9%etos}B^{AKSbuuFLx!Vq&{lo-5bw9`x zkYpa-Xd6&Kbt8Yu1u%P!lGMqCnI>ryWhn^OtA|?GHclxR`t^YFjw2Cz?FUiCs8##C zd+W9NHlKo-PN(2#NsHVyaabdMvT`cG`P>KP{W0bA#B@hup^&H!mNYq@*gLpI)Rds` z$ct8b=2rn_fs7peO3SmB?P|9~*C^Pof0wq`_812Obc*LGfIm(;~}b~QiN z_Q&Ia(33b^I1l71v9eRrb%xu{HLTcV{h46+TmuquURA8{LhuJmg2 zKDHj#KR-0R-gR@llqwQ@dH#>EGvq%Psk=s3PypXu=Re48rUchtt9UDQET!&%**;{# z92jj%9p8Pxx}3U~146zy=pR3N=6B?WA&l!fUb*Rdf6u<9 zwD{VaC|0H9bUJ~kSTzm19aNU07iRZC8*;R;M7eoZe3_v4fy?T&vmn0YZY`5%{vZ;<#(seA2 zBDsD1lsqNMbls^4UA+Xx8djPFPk(CDAjUgh2`F5Gk#|HvcH`C*$~52(=%*z&eFkhw zBW>q;z!XyAby&zWgR9F|IZ_S6h#)F}g>liB5>Ag-6lfFvro1DP$I`E;JAU5KDKCSI zikRistjhtdsH)CniD*01#qgyrCwHXuk9EA$LGYxxB?eXve@m9 z@0Xy_!tLB@H7`YSjP6~@mWEAP9TPDf#s5&0Nj__EZhUbfeMir-0?>vhA$-{1E{Osj zu(IBV%zn2B*+&+@%1zPZk;i}CWr^N`dsC@TRl&95paG(cp_v3>)#*fr zGrJgkw%m)7isVZZn2PUVO&7i8rz2qN()XWlkFGeM@{My{_4ahoPrE;9 z@zoTyQ2rG5c^$BOxhW3}mV9P(f7u0Txme3{GG70ssFwZ?&|;T3;KA@G`meIzt{mnm zgILk(Jn-uv!Qb?SIMx)Qw36GzxPwgJhW0IScv)hyM$^n|0!{NOph-S8Bj@z~eWoWd z#CyY~E7=6$&{_z)L2kkIJfR)r(Xqp`1eK2HcXs!5-L4Ka6o*V*j$W2L()d1HA1&dq zH(o{R-MSo)zfwt^@>i_gjYvZ-%VwX``lX`c5NWRU*!-AT*M3&Cdh&gmn5e^iK;(}? zuUnW1P4nX4J)RqoEio8xRrzE06nN0nFoX| z&K!VbHD$}o4rO}w2$u_b=xQ2r9|i+z>66-yUs1zj&~rI}lN zAgX1u0cijMDy&bGdTLD<2++scVQw2@+iZxj~dUh%{qn#nPtV6oxnTgbSy&UIW;;IoxN z-nKvOTH^;?zjMh?A{gnGPu8Y{ttv!x0K9lMRyrhdfe6GVr1y+Q}zPfTwui7Tadu#hBo?pt?AQBk6*OaN&o&$cCwounv zXH;>-%r{?#9)mJx# zOr#d<0}}O;G8PJIi`#V=6H?UtsC)r=F5ff=?m3l`-n?cdf0j8;9Uwo^ygPVnH|75( zr$#QG+V~agp&f*t$NFSA)hsss*Tl}+0&=lrEIMT1)&5WbVs!mu`SIz#QTkQDLrNDL zvT_zaa|E~$ubZBO&0aOBHT1AwVm9A0U{!8|C9Y?64-2#LO_JIlgEpNRpf9`rr#1h7 z0^D8g4@#9fmY7hMIEZe@* zBU}Cy4~$BTeK!}@PJaApo$hEyz%_;gba|G5+q%2iY#rdP&Z6$RS22uc5%Y8HW7NUs zp*YxNmH&9-X|LNaeb5o^rV2pq7#cnn0LaA-On`358D~L230nBk~X`Lg{>tU zz^ti(o;oZ2Ij?&&w7ZGY!j-*&6XYA`o=d3Lo*6-5zVl-*;2(G>qoU_tt9+Aj?u9VB zQ^&JiqgTAM%*a^tO;4#Upz!%)nJd{RH7FpgvGSgb)2fU1U25ynD^(=)dN{Q@cv~=2 z;WF9}cGFDQO2R)PfQlSh@IAt)`_-`1-wW{Wni(bL26>?;A_h`vZdO~2-5kOXkXY8g zZVK(~H>-%oBgE9O26VLx(__E7ngZ@ZBa?=+!5!EdAtyzFduMgZYQs4q39uo@MXU7y zmG=XtG?_EAhydy1WIN98y+)xAn;zMAw0ec)MEO(N3IpH&jZX4f0-2udw{R?YKWEJX zYdWDH{&2VdQ76B>64RBn$7h>szfITOI$VZtZyRan-Ct!Ov6N#PQNFyj(8EtV8+<5+>F? z=gXcF?vaTI+?w|}95H}A*1(xlL$fdrDp4-WGWG(pdgc0@78c~5kKe}$gpLLIgZ&kF z@`7Z^an1=6^$)-|s|*`ydp{5#fXss0CEv+Cw62R~f@mM^ypq`T0=hQVz*$}C9B}0a z1~%n$a)45W)J%s7FMsLdcrT%l-)bG(_q-`BT4l-~M(}lezdv%E8z`3Ukk*2D85rRu zvJR#ICj`FvD!d`0AY3ota*`g-BEP@9Z{@3#JLLndMpE+|9@4o;)_!Qu`8?twZ-Cj{{H1d| zAzD#8T1Gy*wRTq{Aj5;eY_A2!iCd=)1L=s2S>9$OtFV4H5J1^nb^LYE?#WQg+zKx_ z^zq3A8^wL!c5b%x%nPNqLnm_-?fV$Vn~P1JDTr{WPg?m47Pt_^jZe>=IdUi}{!j~{ z&y1k^Rn#o4a0c{$2xl_o^p}aLoThRb+g^R743%8}I#o}m=YP8f(V*A~zM8m6wG2J+ z;~S*cp}D#Eo2}?A+|~X45~EjMSKdrFpdgYqnfdA~Z_ho<1f!Is3A`|#QKAI(wg}ho zNxvY`#p0-TcyDJq!MOvx=7_zKe27~_z)$nCACp2GW^~cqksgXWrEk7NS(Se|LfFtsDiYfUmK!h?#D46U zen;WkD65X-{dlTufo~*ui5rtE?SE;0O&KyzHy)~)w=W@$8!L}uPz!CB<~k-$W{Lm? z^V3FI9w_?n#k;C{HD%C;ywksmywz8-avI)@xv!=MeCe`n4>NS~^fJ}Hm4NO7)Eky{ zP8ZGnra0d<`?B?xOTzM?3CG{l;Dv~$8`=C}r#8y>o=I1O9)bNTz4rt%qFF0LYMh!7 zsUq(c)@&XZs98#}ZLzL<`xV3#rO2~g+>2WLbkuO^>OZs;-<&iT^XL&08Tc9{C6%w( zQ<0qT4I;d@aInHVJKn_hhP7VFXd{&>af;wm@`9cP*3)=)Ecb=42{ZcM!rdZLt|4BJ zQbKpc&5+wy#$}fWc3j)rf{fz|dDT}V7Cnmi&4>3b0_t*!!M#n;+0WT}2Wk)&U@MO| zYSComXF+~Fgb58<@T%GE+=8Utu9>pnznI%M%+ssudcZ~W)v*&Z*ZB{y#*$&UGjAaJ zynQ{5`e#@Hc>s|8IiopZ??SeLy>#q3bZ=pLL(UvNUBIl~XM>PaL2Y61*=_ z?nLGxn377XVE^PkRV>(j5_VUz+~n9;{tMpnYcx+Q@$+sGrdyi2WsXQxoBwGXy7fma zk=h+Iz466ib1r#QxPj%Vx>LLSE1`z#5l{kqec7#17UVCKMI0urjanQ^{JRmATXo-P>kxD{5rei(-h{nD6>u=yA)g6-7(Lj=2{JV2em7DM@( zKg>Y0^K93-w>5I0j{~nD7L_NRj0!1CL75gQdpj))gfXB375t z?|PEh!>*b_snGbwnK{os4u!`St(3bI--3{|%9jTq`!+uO6=dPBY*8PSVcV{_=LX*6 zi3mG`A{a+}VuyiZAm-#Ox(WT>4AFTJU~LH!JpTW4+{1!lXsJ6|bT7@FH5Piiau?5$ zfL-lKi6~)DX+)H8*Dy(-bJp9E{qv9gn~`S(>$**UFvW-p!xeo{{_UGo=fiHkTFs{Z zihmrhPhdfzpe;=DDl(Q#uxs5FTOrrc_D{3=YJvsDimT~_ISH7xTC<@?X;qUDJt1vu zy0~4h+&0V}2Tn8WT&Xj-iXQHE8Fzkzy0$AQ7du3Iyzt#!TB%OxYDo>zNecPLb0k%L z>L=tUi(1@TCp1D5QUvU(jlUXOFUrc!cE2L_Imu~PtF+Lw|YTAur1({qTJQko%sYpH0Yp) z!^!Ob#R}KP^96c~pW7yf!q_QM7H<#42o0mM=pLH|0)f?1CeLx{x*_PZ7TF$=;61^+ z5Yl9-aPDmc)cG=P%)WfJAlhkfG2a6`qIq8>j9;N-+~DD*r;}-8_>MuA678G8fuJU4 zFE{yT_f9wZ93INAzY(}UPI-2>qzxI~#yYg6zAKSBl0pM9_3d*g6XBoQ0Cw`o_G^FY z+SHq3tG5CUA-HTQia%ZH^5|Q$JG$NXHe$v06E~LE)S3RgG}J09sBmi%f~_B-nBa({ zP8&{+urQe+QG?%~;VoJgq(h_HxUkx&TkS5v-iVfn*jBuzp3%KVnWIU% zzET-Kb@mc6lSH~lrZOG!G6v!`zjvrAq^avJ0UBcF~nbG@P@TA z1Zm3-W33a<39}&ba`1v(7-IOhb>+K1CFtq2Lp>)4Y z%{7}6bq>)mH%Sy{W9696@w~FQfZ*y+5Vs$&J!oM&x|e6{?amwEuKQ@t?{u$JI^ky% zkFvi>n<%v&AMXHKJtN#I0K0v|MdYj3FVrxXsMa-hMQQeR`0A1$UilJ=_(>o@ajy;U zU-+c6FX7^@P0jj5zp^miS|q5l^AAdaD_VwB@6Gj#RtyDT>475ipSkb^kyg@8pvup% z>}Ns!Im7sjX)4qPnvlpsb^E5p=T#yq@e8lFiFX7|KnKih;n796JJS>*M!ecK+4a^D za2KzAdCA3iZ)QbO&+gMDWh_bcCAH3{Cm!FlO0@@~mq6pC>M}x1o#|R{-u8H)dBB8S zk}yubwuMis_eGgGRxOk%s7r8*ac2r;+yl-=0&H3LJ_@4oi1PJKdm{&jyr=^T830FS z3zLu_*R3kZM(g>%E#edmf4I5pZ^Ech(wuS0oxQyFHbi>s(-6wK+wZZg1wx-7Ia^g{ zdY4*=Y~J_oc6=j!15{K)^TaPsypMc*IIzCfdQ%O{hl5~{n6`>XJ2m*wxjGl z5>v}biAh0`ACDq+D_Ea)9Ag`Sy5a>MtYQ<|H#@Ek*k78z=vXZgj(*Qtq~TA9^z8y&QHre zW@#DvbuKH@|J?MK{loF|5NE02#X@%Sp^7RJMm)zkeK)Ihdh?QP8BtXWldFhzI#Fg5 z^$_&%MEQDxh-t9fq+S5B*}>2rEz)9}FjM=5VT{*@*rVq>nsBm0dfWX;X{M8iZ01Ov zuTbyBtU`| zFj=Cs3k^5QeCR$^L&j@Z(H=)zN7%E;xc>YnNvA|O58apiGRSu__s!0UfU^p>XG%4@ z-7)$Df9;(K1`J{fj8T>?(fpw~FntMe?^np@# z#5ejq9lp1Eq%)$ehqxYzNUJ2UrNP{^kEfLrOYYap2IBsZ@e^~NDvV&(wkM?C|L&V#|*+|zBj^*=sHQD#wfU#P1Lm<=GqFS)m8+N&WH0$q$ zzl@xn_-z6Eg_)X+96}E`xcrcwG4|ARfkvweC{`V0;QfL9xzIX!BwKQ3Y+u8F`?@pn9ZOyw`Hn4J__S$6raVSbxKM&v5di}0E9L41) z$FeMzVx&;426za~PI49pmhlrYDQQji*F0`__MGnj@VG}VK)E!um0!(QBdQ`pigN_vg)d*RJRstNgdxDo7`M3hQs9#xXV zQsI5btSBgz9i_V<@gYy#-(G}mXzCqvy6zcA>;4Vdy=U)ml{l7;x*XIKXv0zeq#+;t zBv~z)GRl97%N|}zfZa`~dWAMr zF1pMKhn$R=BC0HvKy4c(nEp@69mP|_Nam}#gM$FE*hvkjjtumdUne_;d9JVC>4X(} zjP2gNYBGIs3atuogW_sF{h#~LVhoR1;yxIbmEu3)U-os+j+Zux0v9xjsWkH{wO_L1k z#78XyUC+A=ez=z-|RRK1~jJnQ#bCyL_Rq4oR`MY#Me0q2Kt!zK>bvtSRY4!7+8hE ze~hfZ$(Pv(@|=

54tZ#!nUE55;l)z3)K!^?lCfNibBp<|d0*1*rE?M|)*)8) z`D57r*P{oOz3=$gVR5<6$r5hGF`*afL=)$7pzf0p;GY92@xC`e&+;*{#i?+5Hx>WU zbe117v3>Mv>$-tI&%amt0P6-cXBIyA2X-mQohnyac}f3CowVQyMQ%^SJSnQ=rg2yGzZ?eNTq%ee3``DT^$!S?hw*5Bt{iu8gH ze;AKjJZyTzYdYba?$DD5cVW12$|NtCx^@~IVCOde!an$qGAnY-Pf*(i1>k=o+xP8~ zsFgl^PM@c!5Ft(yqvj0@6|VN}L$Tj9q3h9l9lvnXEDzb!$^|F7PkpP(N&TNnj85kJ zdf}7cX>++PK`cp8S1q!Q^a?|iIpDmmM*Up`UXaV5*ePw9M3GsbLS^;U;q0qg^4T=_SvGgJ#p3(+}6Vsi8?vO;iG%{~pjT z5b>mqd1YuUqoc1vsG-LREepkA1DTk?zZO#%jy%=Z_EdojpH8ukWy2V}hS>%$B+!M6Y;mj z*5JF`rgLhTuk+xnC@A-)1Vi@KU+sP2ZFg?txbe#$Q^WTpD%y^EA6d1l0q{Ib_1pPt*yag`g-(?m!QrF`wSnVoQmp*(H-o<6ZY~K9s)}$Ze1W2X{LP+W347R z)!q#D!ME2=pC6h@cK=Z_?x-AbbbF)Rl?lk5F)-%#XNafyx4oIh1_MaXX7s;`g0%8N)gTFJ#h zaap?<$ctR%Khz+v2P0qP3iJa@UepDO=5QmVH%kB}8JJTsGv~&-@kG>>I^UyVYf9U~ zg5yVwlM1bNnGq~-o>D`D4@vm*eC}+A7l8mC=`VSft1}9cn?fu<;yJ(~rJPfYr!f-PD#X0?Fpfhmd3yO^C>LC$_stH6l>e^%8R%uTY%cDK2()g*l zl9iVxmjKVXl{4&YqMkuN+ZyI%8cqulWRY@G%wm%(C^>)#iDq5_uGdXXzg1PyhFHV) zN7(2ns~8ymFAG55ZU5gdd1E%|h)M(yXj2~|k>;$NSqs5`YMz_6CBJ)OT(qOTZsk8i zN5>8|ICH){*&&}n%Wvv|^&*P%ruRLtW|6PC(K!nbhxz$Y*kh!d=it6=V|YO zGe3g~aGPo=!rTZi#nUfmr7P)_+kU@mkG5u#R-c69`;{r2w`9@I)yI*}d-xIz7^VMY zl_MfE+@F|HpPq6l(6vl@d13Qzyl&gRZ09hK&;kSdHPauaLV9zkFZoIN8w~MsZ%ae< zEM0l+9an<&VA_$ZIIvEKlbF<;Z9=t+%N?ukxUTupoSP!p(6vr1=h(t`K>5dqu6MA; zXbqANuUz9u6ZvjVj*Ab`N5>0NnUeXcU2<1FW-O+i9oCUnM|R#eJg5E+;`#np6P`sH z7T%u)sVZ0&mxFK%ZS^5#-k!+Yf)2Un1j=7#T^{c&=TjfW+lsR;Tgf!ozFjUGU^%GQ z-L#J!7t8(Yy#F0O{$V7aGv0uq)WMDXH25LSk^GBHTM5VCntCu&#Q#!6Pr}f1aza2f z^nbuU@H-lzRM&-JC^l}`uM5{V48t6WJd!w_0Qfej=^;LfTut4)FY~ymXL!~Qep=zT z8aUFw7+fDW;e(iCED%1=7@7NBEr|zkot8VZ&R})&m>tGE>Q@eiQU@HgvLrExisTBL zcDZ`sE2WCnp!7F&a~qa>v)4MYJEo~nOb^2HcFW1K3*)%dh?}ri3JrjF_`yQ~@!i9# z!#x9rqJ=Dia+WlxcnPrRg^X>rt$f>#ABjDJXTnQ}3wq}=+pYwqB<#QrFt8RGSTKBY zYH8DepugxpnWqzu=sTr^pqIxO;w}wCZ@O+{y3psi5kK;@(DSxCope#6)PX@4&@hfD z2=*Viuv)YRl~rcWYhxk;d4P+p*{qL!4CK9il;4sX;)p}`YZwxg&7MWZ)c#?+5s^PTVbs=N}`WzO0Qm7cvhImv#oc!|Y!dSN&E z_)?o9P6awcu;rE<0s5EOQEuir!4IL8{ftj>SY6QBnMGJ2kYDg-{QSo=*Dc0%pZyLi zisd9fU>o0Q(r%*fo`RC+PO$qgzUx4{qIBgvIguk0_8|4!33c`%bS)_=gy(6)$DjBc zKRG}zA~4{=e5x@c(`YY@rx~SihHE%kw>zc$GhF?}0L0g)TX!IfdL2L;CZZ<#OZOw; zZ-Uq1Jz&GGyKwZ$tL~oJzu`k7l^2pV(Zc0u4Y`ih?u{%0uUtw8!-(qx79%q7RHgOU zFzXK}LTYVz2Yy079d7}vd3eu+vsQd7>IL<$w!Py)pipS6Ped27vcDKzB+}9)_gl}OZ_4INJKg063c=-xN z!SxYIGVH$rSYj#pW3Yn9_KEo4ZN`RX4}RSc|N2&;JrV7HA4LNMVEaOCs@#S7Eyp2N z2PdH0eAy8f+*8)10QpjD(`4tDQ-^|!ylHR{;(E6S+p#~U{@2f$Fiybt=V9O1jXfs* zB868#d%iE$5=iHO)?;FUmlyj_&9J8AKL<2_(^b5fYaIL80`s_RnT=HS%evdh@Jtg3 zZ|w1x-xwZZ6LbvrTm!1C7zTVLejNW#Wkk_+zsk2zJpF<-Cp;KBdH#fKi;`dViRWAq z+1B;(T|DSSFk(PL1uh+gBLF-U}h?=8=y|=6} zUFTfP$n<#1^>m1Y_`aEk-PA;F`8&QQ&jpC(4UAJ2I`(OrNQmJJZiB_7l zS^~RQ`Q*}u>rXXQO+wQ`hzWWX$@gqvpLj{HBc89kbY-PUxpmaB2J{p+uBWe^pv|bq z*#8(o_`M-Ua`_77U2_)6Q3QkE#q5ly#T563#jX*HNf#Y9Kag4wn&nd#=NBUYpd+RL z@u~W|faO_yWBH2n1D%E+UEo4iK|fDqC_TkrI;P6WFNCZ}qJL}bvI!Li_S$ru8KC!4 zTl|LNPj$T)_td+rCW)SAG(xy8!2bZQVlC8W9Usa#&RgvVv*N0rQw)|NBpfgFVe68o ze||z8*o3%F8w73ORt5XaY-K@xEiT1vR0%0TbZQaT@@%)*PgsXP!u5Jq38445-@_d% zg3{lBHRLVMOd{q{q^dn#bg@d_rSl~Uh#d1$4G2diOJ-l<3EdKU(VE6uK$<7T1FIok z!y_Lwz!84@)d{K7rlpR39nLd=%-<3XhOlK}9SMh6jv8JuZWZRX#PjHU>BFXo zwGVnZD27M#i0`0@Jy1%snxZDP6YzB2{}D$|%p_#Gii~rTe}Rqvmw5iKT5Y6iXl-oW z(_GItj?=)|PMW*fx$@yZw*|aaFLeT;B#FZh?3?kvR2RafDw+Ysl44X;hoMO}zvrfD zd>eEv*YHc%fCkRgWf$Mp8fEh8Z816LTA%4b24N*kbqV^6Obl2V5MOmujI0+E|k{(~` zW?j3h?|js|I)UVXtJTMPGdoT_zcb&3fFt|aGlGBXNMEK>w|7aVaKQY#BfHM>2WX#T z5%`M)or(+fH3a*oqhdM3<kc#&6C>gO zlrQ$#^TGJuI3Qc|HJbluu%|k7$zQDb@WK4TfL4nl9oh8gEgPF^cD749YrMu$ntk|f z|8QT>z8Rtj)`ssD)cPM1^?!&*d;(!;z@1Ze2o1eG551j(p?BtP(bYKgSp?#aKNN$y zW8;*X?-Dg#Ga_?860%S%50kDMp1OK6?%G3?G`*@@Awq{kd)Z@b!*TO|}^qb!31h&AlDj zcCx%#+~&ZZ-WAu;y^JD=&L!a>mTJ=bG*Y2xO<=xKA{$m`rQ&t$uLpeoS$!5c+nhzA({VqGVX^m z)zK11$kjpULDXGc5VsMfggIq_VQ*0)FkFw{4K)OMu&ihnwOuqDb9D~aMU6oxLb3)d zCS)qSuHMr(Z7AD&O+~vak22=dJ?q@vUWnmCCE@YGbH~E_dU|SW@z6SGi(75D?A{En zxGspInya#J+SnuTp1{3n(`?BSOZRrnn2MnC`bz-&Y6$$uAoC9H_)jF{^enj=1cK{= z_TL53ZpUtudj+#{?wOQ$AGKGpEm@4K~UD!8P3E8a%SGzceVt2N& zoo=_Kj8?;WmI^MH((D^IHS9G6>=_agOGNfE$*Z4`=<3|yAHg{dkJd)-;^5q*8c8 zuVh#qP6wFB^n#S^8$S!de|f9mN)}@2H&}%#c0 z8t-k`v|<@0%a-ax{V@-SSU63+p*?Q=Ln>(S=#TsbDkCF4S1Q}J-`lhAJPgf{_wX8@;1_%>-j7Z z)RJ`cs7l+9Gg&S0=m87eayr|fs)(a_u$SHNveJOBL^H%ssiXkx84t+;#V(x_Ju;3; zU3eQXcNOUCzfeLM-j>bly7hs8;JsEs9Hz0cBm~8|2&Q|PYC}-iUXWb4nWSSXZIfJo zLAU&;>d*{= zU}%V@QT}ZiBX3WQE{}7ctcK&?&OzbEVXw=Sg~I1(eK(?$F$24q$75TI10C~asAs?> zrZBhm1>n;^_YY^p8g*a|`lEh-oYugmR~L!eQsCc~6lNr*9r3TmdD|Rx zE=`$t!xSGp;h9|OgjhJ=E}ZkNkSdu5>})r6eZ1~dh#m8~Ygd_b?_DAM z(6?N%z#c@KE&U+!^Yf)T+nQ*@Lq9O1nNOIaA!(Z(o_Av)3$UWXHI_%@;KKa)N}(K_ zZsIQK?~Tw+KZ~2QI#5DPGbok5C3BrTWxKeD?YN4pTv6N2%{rCIx*7uNJc{gBL$5r7jB6Ap7=qAr3x4uA!OTCQ%G=HEI5mE+7YLOlCA7nruS&>t^Y*TV~43JpC@Q#{;DjXDdLi?>M7MBLygL-na*u#+odmx7=9e=j)0gh@zoevxh(VH>4KWEb3I0YWg29WGal_P*)8r&z zCZJ=6;H89<-8;pSK22L&bW8|pd_O~e^8;4qjr9pwd7&Tyh#%~QRo^NUwdKbQF(u5q~)F&H16wb&nZ$ME=~co z>ZI|Kn7X9gDvh-T%!R)2J7|hLuraKLMA}JSlY+pd=3&%IL;CEB4bsa98M*x-5NAAa zyykRZ`)o(tRzc@Q1kCk4NlhQ=n}*#-7!45?B?rUZ{6Kmuoue>arR{W}y2BYTD16#E zMo|Z-MYf>nJvl*TRyv)6lM2E;xUo#!xi*L4p4W@l*BzVBtjx@$&zP?$SU(FhVq&Nl zUBzR#2iOr{;OZG;;TBO*<+R~8;xvslGE!A#_}D}6_;J{Lja3iz4@nR^vd?>TOiGyA%!78?WG&Z6Vnh=wzqzL58jLEj50oI>sW^=aa4a}#x>Uu(2+By`in7yQ$3La7P8VX)eJSII#KJg86T zh|B(EoRUaY99Xo#1{gn%%XlBh4AU|Q^04V3=Ipa%E&-8g1qTOQGchd=?Fv|X-mOAQ zCY{>EAQ!uq;*VrTHm4F(fk6-Ylhy5Q#AYXaDNhBfJetou+*JUg8!r2G4F^*x8-P=t zrs78`Ad5v)rIBdGBnbVYql7kV-gqpNXTlsgoguU9=`RblWcg&L+TF#Uwts1>J;bXf zNih`TIrlyI(ZLkNS4HM~3T9%5L`vobI_8M3}s7z~tSNu5j2#7e4* z9s4`7E_QUP z*XZMa|NYbx-3`3HS-TUz+;&_&ZbGUPiNsxUfU4axLvc5E+a>2+&3CJ4cRy#TU1nS^ zpKm!yzlj|t#Z$w*J~d~CiOr8b9VttpE!As^m{SI|X|m9}PO3gah^P4GEbaB{o&NT+ zXC_@|?MNYf906uqj1#h#4g_%8?Y;)HU?i$one9=B%tm%$TA`6+2HzwMp<1D^+I`-K z-~DeYr9>>zm9WybK!RkQSdGJ}L&3iXcL<E6||+)p0$b5R@JK7TWi;f9Rx+KBB$!kzUpYw%Rt!V!MNi$h!EUtV%+J{EVY2v zLaRit2k+j2MDW!!>TnT2#?_ON0@84m6wWc=Y3X5aTcGa=F2`bdFY-*Q?fhg=>vqSE zB_A<4(FMg03198u)+b!9&NUwV+g1sx>f7a35$pAkl-fK9T-ICUP`qGX@pw>Eb6$Qh z_%XytKxJ0yjC_ft zQF57>v)E=!mk$E67VL?jpbF`k%=cnjwUq)#yc7MQf$opkG@+LqQySOZ3TCgDicoZZ zeI=13M}~GDO?N^`4Y`&|k3WZVJF_%+TYe}>!7*YB;EA4rPubrHeell)P)5u=&uCX` zcUwG*-2q-=N7reBc2(O-q&`^K)JL})ZD#i2Wef>(J z)x;W^8E$gGdUAoRaX`rK!-Dg%Z^PSRamPt~{U@?Ec_mQfZC5W3Vt*g2vj>xFZ|F!)PHx$gI&~91snjaM%RwMEA z4x0Z|OLW4cA`)nBa{5Bt&`{y<;B{}A=Epw>l&I!Q(BF(ww(!Ixe2g+33z{4n#cC7J z(EMq9yOvFaXksLZ_0($L)&Q4AiQZKko!5z|RxNxvrxuziUaeZ`cr#b?SZ2@_?U+b0 z7A_%VjpfN}-V<#*b0IkUw7N2ctNW;u5>Rb@2CD{mQBc^mMNy($gH*&TQz^>Icd3RSrujz=$Y0eiX!XJEpj-h3Q6F*kHfI1TP&3R~v!ZBlRRK|u zb@Ge3sj!75bk-5#Kl^9N1Vp#oTOX$A98vF$?{egX15)(oc_Y>m#$7)#0M{t5ugv^0 zgq6>yZqiB~ihl%9oo9_}ON%_QIBj!iW&eEku-x7oBQBrw+RDKbyht8Y7fuBAq91R3Qx2vB@l%WEb{@1jXo5d(bWohEcxCQQsL|&PEbT`2O*IT+I zjIoS8U$LwK!oi?@g8qx7&FdU!gDO>#LI>JmS6H$TXF*?Q$$3)WA- z9UEi0z^twf_kTEngpHg(F$g?Qgd;i-QTGn8V?8O)7DE&p?mvAzwOYJ7y4yGrH!-?a zET7Nmo>;uvGtKNcP)0nbvHvhm1sCj3pGe37m==7Z;I}}OKO^|!uxuw*m_I;o&7t^I zVxpD4{rkwCsw-DqrP||{uJCISP zdGAeR)~a*z*wo2I8sf=>w}0{3sB?9oIz%5*!5!{bw$sQPEZuinlR`1aRWI3?RDoh! z#@_GTxJ;T)gqBdV@`+dskvHGMswb_SAPtl?+o zPuj)k9QUv(`P>%*W8b;T75CZc_01Tzp?bwIriT|?=l2;Je|Qg zf-i?Jz`uMMdQ5!u-&_GD@BuU;+gV6%&ZOd7o6a$)iQ8Ajb2rVv>kjJM?x2gQI|6k6 z;T<2c27Ym3HCSz;b!vshJuyL9k77?xDaEwd&Sp0mPDl7^CmKwH-on0W@bkl?!me9T zT90Rpa$VGaMYz?}ocuz0>q3R21HT616L4q!?(Q+Nx>HQWYs&>>U)?%CtD-@9{1gCBUkn$FY-; zL0Ve+iH=Civ4H?xAoC8mcNb{=pNXVG@iEodHiK4`J*;?Y|R z$4&P(eE#`CNAwQt1Wg!h3wig`ZZM!NU` zNr+s&>BCu7o=bs@*>e_$;~Kh5ovtSVDjWQ-YXuz?1&`b|bM2b(3Fik0 zIa|BCKqCiIl644TP&@$S2q$x=-LOd{2|+TT+5?kp4Qk~D?YI?%g!P(4K5%7|4V=6e zwa)yn*Omky6<0*Kv+Z{dm{=6?c;4}HPWOX|y?b=axS~LA#8V@ftYwFh{Tj_b25>Z@dnnjUoAbxO13qb;D}00e0UAD8 zmN;~y2rf(Y3oWsu=GDsDRA%WhgSga^KWfS+n@#s0NsjuV1y_^#B)3?avoI;c3)Wu# z2UNFR&ciih%zx@-#uo4?15IUQo4kzubIOZi3E#`Nu)-xPwqsP00}IxZdI$7Gx#Vpj zW#5Y&3#IVQxiUS+>J1E}>(W9q0AM@vOowE`uiaor+D&zNmTX>13$z{AX9f6osRk($ zjc0E5iAEIMLmj(&&`B4TOmP~$WfQZWE)5rw=z|Fh$sD*C2d1{h#IjQrKt>-6*okN| zJxb0Vvu(`u{urHZ-M+QUgjbARY{zk=Nl)q_=z4Xzip~ zTgJPbWz~U38MNqHoB{61J9K(_|B6hKo$Cy_VWPj9j5^Z`Am2fI|40?fJPmO*ZM$6$ zjVCv6bol_VBKLl=VAMGMv))@KJ*4F`es+DKchqpOtv2yehsWtk=3{rx9}-88W~)>U z2FmV4R`u29u-C#g3b!DaXyiM8Yc@Vvie-lgKbk)^`SE)Rd-c1uy99L4)6-VuCGay? z8g!WHKWGYmFBEsLp=&I(U$Zo^8w2kaq)t4zd=)6Wr8An&e5aU z=JGEDFEi|4owUb>XE`N|x}3UmrT=g}WjAtF`d#hP^eF!5A>lRsJGrYm_&RmmH&PX{ z+#74*=M_V8(WvivB7V5ik>FIm=ewi``^C^vwGC2c7pA&LPkhv14nfI$Dp+nw=sV^J`jPC5Rn6rsxZ5{&hIv zVLL!CZdrvZ3Vl|Yj>{MA2Pm$q33$^m;GVWc#4JCT$%*xwRpP*XTw)Lj9HOv*EdDjU z)Ux;$QpC;+YD^vN37vpU9`|y2W(E2?E1n;7R;!w@_!?%{1qolSG6rD!?Vi*}3Q2Pc zi{)CLCITuq^jWW7uOyh9I~I5UK2KWBV*kUwb**={Dm7gYYK>^NA}}#zVXVu4vA7e| zJQ#4BYiK3q{=@=aW( zExc^f^lQk^eg=tq(NN916s`-!&o+H2Eg;W>D`PabuswFNKi#iol+(X#uUzvS;}EbN zxp?t*fd)7;jnaDmOzOu>T;d;dJ?<5y;pZ3cRaCDHyw0{$NPVx~c8dJkS}&t^+oe`M zv?bpLUgg-p=d8PV&+~puq;Vilx5nuCAXeOjsJ;ayx@eUddG3k9wYr11MnQ!=TSXro zb_b-%1y*Krf)`$@BZ@OfpuWqOc<8p;FRc8LNY-vW=yz|8S(9ses{H2j_0lP5)R>{5 z9hn}SXHLK_jK?Y_Y)n6G=9QqYqK$jLyR7| zh@4-VOWqjA#Y(s5m7dj){EU`w`&yE>%?E$#KVuB6c05L9gT_rOG<`7oY^xuOM_TLH zt$cp$N_ww=E#9*n{$JZ7*Cc|u8ouQT;Kkg?%?<*0*YZEfx%wY2_8lWA=<-DK!^W-< zyd7o__eD%Hvrtg)J^@$KQi`gO&&S662F@2Y$R6w;cg8d^sE z=OFooL%jvj0CQUrU>4i$)o@;a4^$l zhm)mZAT}+FYH(-7yXG(~!;Fnj(tQ7qPca-c(As)y@8_1UvF6xVXaWc3#0Cbh&@~*+*n=OK;#hk&~4w|$Tq3D_2S1K6fXx|Ee9Qv0IzOtYqK`b;is{# z=51Kqq3QDNhCfT;JZMN^;!8D6j@6qj%*w^fk1mUSf4)EUw;{}S%cyA(-jU;li+mEj z$BZE=Bfbg4sIN|`N^)r&wRr{T=S$35H~MV??FTQsRr{cp0T-A%B7zaW0%q5%q%~bt9Y_E{o5XPBM5vmK}+1%m?hp zj7lRRyTr>gp7xD$%@O2`E~Zwa|F9RG@NY5FBrvQdmQhSbA7HVJ+aBz8t$ycU?CVw#DaAb z{wo;b|XKE6a{$^_AN0!!SstKk+#jSomHB#?P5WZ zUas1;craRumW?ojeZU&)twj>e9w_6;n=nCUX61G1b$|bjan{72GM9v3&<$pc{l@0w zkOy0m;DH%bS-TKx79K0hf%Am|qntDtAg$Hk;snt0sA|u@R?+v&?H&K*R_A!cSdg5@ z;+)^&X+TAhq9Km7gFf{#j;P^56tF2QDL=~fB+mKDqH3nPP-k&w~RCOs!CAy;|A&DOns_+brSG}{4ZcX*uiQ!FP$Q2RTjf;IEb8{w_-p*zZ*7&K18RzfFMVd{1 zH2z2q8t-xY8Gal{VVsnkakQ%qmL%Sj)I_@5q|a(=L9H+=Ls6<0l0nph1j{F$HR|-4 zi(vcX5K%zRv{M+@rDW0yF#-F>l9oVfN>5uY^nIjd`xurTH~uRJ=_8!v8s=rn+6Jhe zK$-tK&nO^urBjW|x)%z2R{`zgZP8V1mLp%T4R}`u7~2Va71LXohHL?I6&T(Z!fC$c z>=_O6UPuyr;H^C_=$1i68JTasdM>t%>~@k06xi3WwHIXRF}qx4iuv$2F@BJlMP1eqIzx0@h?k`HcbyBRL1j&peEoa!gD@u{+_=-M5jXgQj{$(-&J3wv5bM%PJ>^=2AFBE zyi0A&Fg{uCY|VC+C6-FGAYBCBoq%sev7w1K)|fs(d4TsfSG(Sy21ZXx@g=fKk_d{o+PWm5g1vN$xfC@{2D zRpcD!B&_{b=Ez!{cI{}rCqlKP7CBUp${OicZXsKZxF64Ee5bO!sQ z4RMh!7(R2E55SLJ`F_Q;X`rKFYK~#+3=w|==6tH9T)K&iX3S)ZXW`tl;DL@#JOP)B z_JGFIdrSDzwO|m!3j!RWwZHw|>G?yxdIBT-b7FVk-Jes+SNr$3tZTFqUMPuxYSQM5 zk?-Hdt>^}Vf5y4EerIBNH`1HF)?;M#yw43% z{mCLI#vAyjhgk*gDgnYaiRQI;FJIPVM@8{bxT{cYudBCeH? zFO9E*Z!A~`>`!|ekhqX*b#fn&H2FO?>k>8EnOKUu>B8Dm1%VAYO5kNfc@&Py-=D^& z#yq9dpfeEKjzXB=Sv(QdH7*dn37iWNPJ&FLS!5+Edq}lu=&=|b)@d%x`03%8X&Y|cZZgr1kJ92--&1%?}3l~cB3frNFQ5NI#xG>32 z?q^i4mbraRWIFp*Lzdv&6x|bO$yi2)J&!|8emYw5e6qIh!1acgUZ475May3y*-3&^ zd#}uF0atL!<}|B)?>je)<7rjzO2_L|)77b;5i=e;@XO7Nlo=BaSeyE@2%|!Rt>d(t z!0pZddwC-+8LxpIxV!rhylDVl9#P*G!UFdlQ(!^63n@7`jNk%Gpr4X=G`2;1xX;O@ z{=J2ee}lXN@knNe(?=AOEsj2CY=O9lZ)x9?{|samZHZ2+q>gEKWb2*P&3Qk|5pYv* z8K7?-5P3-x`aY+t(WZE=QZSd~eUNw#wit**4Y6HE!_P@le1fo9Lu^hR>9NLPmmr?b zPOQnT()FJ7BJ8L^ejii`F>r8k@R@*HA=&dFCkXSCu8sV|f}AC|&!J%R&F&%m_U87q zqG8z&w%vej&XDcRZANPi;j_m~3|k3Y1=0*X*06^P3%p+mj&75bS0P zj@x&&_)kW=-#mAB#Rvafyhp;!H(hD>fa2is#Y_9!+(%}Q_czq80Y(&WZ{2rnGT*`R zFW*c0QoNB$ZcJzpm2O#fvb;Q7xcg+BggoNgZ$XP?->s}cSik|f%;w(FF3gN%aaBhi zErAxuVY#<0U90z2@o}T7UHkr}x=7Y8|Bwph68{jM=`BlY$1oC;I~O4V3_LuJ0yqQX z;GE->fjMx9;NrY9D^$xu?vG}r+jlX^%Fy>7Jblq8A!MT9N6`HV6cNvt*GS1HwTAOlxl!2+gF;9)Vt@iS?e^aY2_N8@?R2 zAsrYHHN|6J491ZDl5sNkZhbw9pb3yM6cKhgmPH}HQ5u4k9cJ|^0gU{4Adum7@KHK) z#{OI22B~MvGHPXRsOmLIB(+rw?FyXqtK|sFJVuK|JxF~I#WbcV9(Xmw$^R`eYU>_S@MYI0#-pYcSkmK14MgHTVtS%)LD_5;Sm7v3Vt{X zcsG|%Bru`lJAlQ5jl(RYKEG?Mea-eHKREyX-q;lG&-V$p@rw3Qk1OR^yh6sHBljyp z{f|QLNLX7oBl+EjwX?RSx(2kjP+X?TqL7g8JfoqvBLj3X5BhvrveZ1+!&%Ym62BjA zqW(z&afF)3HhIk;4miIgx49i0e5%ESHqes7f8Oit<}LCool|&)#477ejXEeX@DU_e8af>VKGGkL(jq3&XhhYPmTvbMe@IqG@+zVZXhY z{Rm5ns>G=K`}h>6M9*u@P=n=pes1Ep*cYycgqRZeXmfywrOY`00e-|@Pi-RWO(=sv z#$Iw!&gTwGFBA9BV(kz94@Y<`WuC*X@M-5M*U{lF@p8D=GkK|ho8kg%VZJX=V@aS7 zn$^-O^g#P5AJg3O!nv7EIPl}v2C$6E1IN{GVxER3!NBo& zaybxf!YJztfv0s)6#2Nn9A;gz!(IRoi27zgz zt7aTY4b^4Jp!l=CO33O}uKe9#|6`S=ciEowS`tqp*98MeRi(K|Bwju)4P8N+fy-Z) zL%b~MP^}GJInYIbH_2*#^StSmK$p?|_c(6qg^TpZg6l!ekK5z=K4Dl3FfQ)Dhi z+<0w?o<3!(YK>>X-b_wwruO-B6Fi+k&iJLVELLwpXyEC}pJyX$rOW4E+9u9?`MHc% zx_=?Y0e!7AE`8HElQoyw`KzG4_7q}D^09&N&p}*P_eWdhGC3|Te*(E&I-CO{JzaC; z`-k%`+sD6sKN&NVmYU}!gYL{+l>W=^jUEuCe+19kVqdA1QNv5uta?_UJ^d*At+i>H zh7dLZUUgh)U!jiT(FOipzg%#IpRT^aJDef=I+L$5B7eK=e}2$YXfci*qu`UhFaBO~7E%m#i~BBJ|lo1;a~e*Ef1iT$eg=t+Kd#XA7K!8NwIZ zTkN*kyX1GBQ65BS!te>?-c`GJd%)Sg)_%b}9P4wZCd=|!{sXDM>ztfVYfT-to!065 zZGh?N*#O}CPB+fi0nv0pT^<3Iek85j$gT+sk5vAWPaPxm5!U0ip=AF?9OCYDF?_ZVV6yo6w_pHD zP3F_ak`JO4a^R7(pv`r>2jlFtOwkTuSN@yoDD{I~lko=BBJb}L?ITDHZUBW+A2@$N zmfr(Xk!n8gRfg}hwDnfBAXkErL%k^@EfDPSwbtXU@XoFVL`%zc?%~e{j~$z~-3S

Le;5M$R8SBk+kibb9L=BeD(I7`djE~FR=Y~wl2FnD4}aX`|rqi zQZA^O(ZVX7wG7X21L4v7sJi&<(5k_3CcAZfOU6TK&0u8w+860(a=!WR2Oiz>ZYkMJ zNv-8_s0=?811&Z7R1=-ky}B(#-Ev&tOvrP+U$*1CoS3mgN4}XT1@Lj&HnHSVqp3DG zf@p9mQ2P6Tt(2_=&CMfqVbFcefbyrdAEIO%)1mCz5TS`Njc0n^jQ@oH!Zrg{YR;-& zb3D~z^Q>YmwBW4OWo>>=^UopDE)$xmSxQL~&+>%xB*!Zx#O(NdA`xXsr#g^&@}|c( zNiu!Z-P&vqz>5)ljiNLSg~j*7Zdc*`>O%E>orHj&`L(2`Wx^u@jgBo4v!dMK4`=V|GgEWWKF>ly$^{1EuJm!; zd2KQT;3aN~iaJL+3O9@>Q_L)%drJ2uXeyxoGJ^k*uv&1j>VVc~CbWa(!KVGA1O zdiLDOYy%BnHl>vP9g?d0B@$c75CVQSB^+b!PkP~wH=iWZgj-7{rxw;mB~?BfxT#F| z)9mfX98Qzjv^3WlNEA1*7%ikSr)FVgpygg*+0>L5ZXQl3FXXC=hDc~!2_Zy5&6 z)=3*MAfGtc{8|4-y3;U{@qC_X9bhI+VPW(nVelp-u!i4JZ)M(J{77E_JnFX|X?ZwU z#`17BeN{VCJbn3zi4YTCrt0wukxCt9-^!@Ug`>&nQip?Zy?MJHNufs!Za^3K@>`*S zd_?W}{K-C#?tAsQPQ0)u_nx8mKSf-5_ufeWksHmc{lDR=9e9!s>!bFxg*Pff4J*+% zC0294N$S+D*t%lt-T%(KnO-LpO@FrHz-5r?wDjt$=DQ6M&v}pQ?1R2`443Q2<9HW! zSBz8@b^qJ(@ zepLRP#Ac}+EG9(c-LV5oCbbtYE z=l%3-84V)zLB0K_M%|ovol<^T?H|4Onk6&C87c>vZU%i;qJ=;9db9e2*Hal=zHg)R z+zr&LIF$-tHT!8%YY-x=g|G(G{q|4L4_dpqnPbSdhZp)AN)9@$ydF}w?iU|NG!llL zSYU}h>6S4shmmJz#Y1>heBT*uU!q$*H*A=%)b9eMPYOt8yyG=fCnq*j?}v732H?30 zsSW29TRglLie!GodH_8EUO&GDm6Vfo_~~CI!G^SrFO2WMWHzNRcbm`ZAL?qZ4(wBA zyb|j*iXZ)%#2y1GlY4V}L2zh2CYM&(W4a+Bmn#GM5L9XWNjT=6s8NE(h7-P)1G@iY zp9SDo+Ll7K2zr~8zpEcO(v3~Cs@a}?@yO_RtWL4laOKb?2Z)*C6JerMGnhZl3=H!ADgA5Y4T(fO=LveQ-_T4#8%XwH9=rPg zu>fqEZ29HV!`KI1zDZsswxwX$&c}M{ErD!|FL#@JzK17q0*~3uJ&3)LK zlkIBh+1?eaM>Q7@IhEvEG=xdXxtBIfl=q)VobOMe-r_ZEzv(Vl^xLhF2x^JB8yf!4 zIVKd)*K>1bfm^e?9c~CjhX!ppA})3|ZgHo;mg{Z{+(u7J4_1cqCG#2IZMi%_hL`-z z-#2zaX*hLMPt@MeHpBWjwgYkRjJOErq3|5H-rs3gaaWyJk(-PcmLv$%SC<;$psskdN`Pmjkq;zpL?Ht68~c~C`TbH95`6Z!2w zfaG##kgbpp-d*sREs$#RZP4o09Un62HtuFS?k4umXB&}n7`TN^VY|JEyTeBsm33ri zSc~<^Q%O-3OxVx#Ni^b@b+Q!s=i|*+mAUyNjK7$gKpVC3?YYxO%Wcj# zyA~In8$QdvJ}MR0)2@N2yNyV|XM&-2J|W{9!bWlmSQX2oE$@+rpz#2)9Dlc%dCDIC zA%51S@s5CS8IoRb0+MZ*7;cwbA}Up+ z#F|MYOaWGB5mMU?+EP;T+qlGI>~ek76FM09_Sviqy<}!~x3ZNZf&~J2kBGFnkqTR} zdxQ`jj+U~PyzG=P&VT}`)|cI0j#BOXX2~rKrXwK?NE0B8p6GC)+3@YgKYI}okzW

S0=Rl2H`pA0p7JoDL~4t_AHF~;@f0B_WTofVdJ7uVla z3^hPJo-$!dKk`BE=;iII!!kQ@<|>bS%CbWksMU%qs&_fOD=d4<$3sn8yOp7zso-@+ zPaDt32y>tcHj+-qcVM7A2H-eRb6)pfpADA%?GNvJx2g((M;`*1k}M0$p?&Ls2Il+j z6HzN;R*1Cl$|hMRA7Egi8pa*ebg)k1-n2O*+JK+8YCf@^Tp*yhYks*!-rwK7sPM7J@9f;ZzB9JGCZ646}10s zUTD}gG;9+AAI+@vd9mO*WXLu8XWqqfih3zu2gjXx){jS0pg(Y&-^66 z9oUv-M=ucS@w{Q+m+iFkf`3=ZIWuk>CF`O?yL)Lt)Z1@0oFcmB!z@#+Q_IzO4;|=A zPgebF_!E5(`CciWD@%Iv`wRJ-Ser7ME##R>m5eE6)$;=S%P?4V1;Y`PX5Wyc=v}1N(>9nHx?ZB#<5*}^BHS4ar@ng9#_LU3Z~6=k2oHO_C1Ig#4u8RH}ASA zXpvWOhuw6#pPSMU1yEg#@i%EcNMfK8ERD!m)V1 zhA|&_8g=$Am~H)P2|8TY(7MBf7}*ul*nZBY(FOOf`ZRYXTWi<52$Ora`E?Ror)o39 z@I)&*#rWs%^W1!0B@c>>7%- zeRvdEqVl|ilGs>*Jlnjwh^uzTd(6!?8B+y|DQj3#+wt^tQVdJlJ{4CZ`7s~HMSHYR z23KNr@9kcG8xiC@GOkr#R^EA_&4+c`aW|RFLdB>hYUWWcCx zY9qx5u*33)#{{b&NJZ6LPH~BvI34nJD-7^X%8$^**gnL#oLe$L0|=iO5n512$fT;U z!B9Uif{0V z#~*E5kkCMbJa5_?bU8EYyb58BsCgz2PsBx+(nFlgtUt_oY%^DPbl_l}OpwfgUQ6Jh z_^^&<1kGy(jDEVNhuVKLBWRu0*T<3h0c03-Ky$;F(Zt&fwmHufm>8UU@#vKjr2+g( zZ%1>*MABqF^&S0BtrxCUl$3wd2`zqIJr&;c#T&L3T>iYfs+Vq$ZhfQccsn~nVDRmP zpiLSaBC;OLHLphZ^rEiYd`7oVTo^!`D3z*W5UO(%=DA61CHsxq8tkc(4qc#r@U8%f zXXAfP8q7U}FA5s_tIu_&xi>-8!O7Sk-X?gm*4e` zJCvp(YAOAzv3cOhMt7*)a0b7qa~;<$x(KLzlJ)sVVr^WT`b}sN->A#A7DG%|{*)vL za-Z0|Mvg<6g*QaA6j_@}W#2*4(DFI0`(fopUaTqi@l>FC&^y==ZTtJ;EG61Wl&Ip6 z_gf(;FGU*qHyKaPF;y~Cn}nl&=;&K|V4wA#`xM)ir#xp3UWe*lCm6ZC*k{Ud!HJDrD7er-R>0H4nlO@5 zF*i845zD`NmC|F0&nK6zq{voKd+goZrufT%GxLIa`FfUl!ME~lG={Z4GO$mLA?`!4 zPjhRALL8~j>i>=h+e*gsU$5OsJ5_<-WAT3WwfK)LJL60Im@?NKjRl#k z^fgT3oMCrXpfxU*Y<$b-TYTW^mC|baa?M5@mSUiHq5bTCn%`LXxsL$+ycv!y8}jK` zYaTnaI>aq?R*d|;L0l0w+;n)QT%a+50b!0gi>;oW`z-L%MrMeC+sg8|DFSDZA$tq- z4#HcE|I@tewvrP}@Oj?sF8dthB=sKY4>#MmMcr*-DuCBr!0VL%!ZBW72hIh8uD0%A zKzB8&#V;}1YkZY{|qwrWx32hEgEP1{3!^o8eJt;-d0pCv#%H zg~^-Z$2W^K9oagLyeA&tUj8b3AA9roX59Ti)SDvJs(|TVM#odhH{Qd4DOP*tTGWVS zhyZj_TnFQFd)UpK#_Jx}>z@BMH2>vf1mS04BNp>z;Wgzen3E zrkP+Xi*wwdY~%R}#^qU=tH$m-S!Y{Ygo}Erw}jI`!*CyfSL%Mh7!>2PSErfK&-z_B zp-naa=Fb~QP^RC;_DChkaOPJ36^)o0ZAf7PoGMmxgnzHC8WXfRDe1s^ccumdSF*O- zx=E8PQuf+^O3&Wv`_TH1%6KoW=2A7Xtghm}9zB>$gp~1UmNNZOMJ2?6HV`BgjeKf6c=u#u zG0R?lih|La>{4qtSB?NjIdYE!?=lG7o5yUaz>+lM9~7P#8mD9zoBFz`E$J@J~Nv~-V_ek2#*aklk2hC;|q*LgzwSH_joOZ z7r}j5kb7=)W|@UMj9GsDG8X2(x}Thc9qd%b>|yG*_ksZZ+$Hej_vIBlaw<{~DRF9e zh=to@gT(H{)0ac`Z+uYv_IK4%GOeAL_Xb;#I5m=-DJHQQTd^8Ot&vZZpfRb%L7v5x z=Hd|v6ORklA>l!vT$JMGZ=eH};3UgFTSisChys~qGDPxw8MiFBgJmQlPt9%Hy?d)S z30Z*eP{+UC(IXG#8h8583gJBT160lua~;p!D>v_Jur2XFbKdva7;eiUlatT5&#oi( z(;wVbCuyi+Lz-UuZTM8rT(W~*_bN0{b>y$}#hh36dap7>Kc^2rPTWEj47Vtr{Jq<@tX zaI*iK*5Y5GG1H1lku8Hjp1_7DB+Le`k==(a2S#96@BUDBoB$wB4 zn^e3Af_m1q9}()2BQ9{rRqKY?f5zJw>^(1q<6$x zR~B2qIWMIk5vK9;>&V5ZD6Yd`o64rp^vERqreZFM!4$IF%0gZ&)nioq$S5seSavc& zBQr54UFb>*U$N@{y#IIutk zIitp|z5o?f$d#})v&Sc4KVHs=y^a^XUQhIrrmMU&wXc6DFO7A{qs0~n@Ycy^`*9Ta zh{}$vy~I=nqtxey*RzRLo}S8l^SlQg34ZH?c@7G$y@m8XVlIJP%euFa@ek?fw@he?u_Z6z1{)=ht2X`OXOkWsNRcC`1b|y0 zdFdk9r*MRmqmnmKD5_=6(PI162zn)$l`4y*GsLK1f0OpKkB)RjOcZrGx`9{nYS}0y zF0Ap}t{6=^xfku&X1@(E1v&CJsUV%*{mJBd+-M%NL1Id6&Gn}8JUysr2N`i0-NIU#{f8zaDDL2g!U{! zpfIH{01!J~ebO*OQDXJxhk|0@^_W5maVVA6SmwUrGg6ud!>hj=*VT$ZClD|M^QiQS zE3zJ~bby=Ddf}9)Ak`aATa$G4#p=huv8~!a5(uydLQX=Ha;7&h0#8@%w7<~#4{ zss#Oc9;ICnIhxjX*T?5TjxC46NmE)r(xhqPPAx&`b`q34+zQWn#<*wV7r=+!>}?FX zwdw7F&$SH0A86br(vRY1LT9Wy{u^e17F3HGxwj`9TP(G=@u1vr0|G1zx6K8-X$U;d zXMxl^M$U*9ld2Qs9C>Uzwn>2ACSu2`jgzaB|bGk@t7 zL=a9kH_ixSy*YuiM%_%?1NlS_Dv1jQcG~7TbkxC_fwN02)xMwe6Rg^E+ovYrQso-KG%;v-fp~h2 zTCkJRrc>D3=q%zgeWFBBxfE~`I2HieZ-iZ*)kn0&`p+KX^9jnd*wC60ck4(LT#tnKT429;zpi^xaOJ7_PGQhN ztyc7&)Mp~e=M7*EQ_hQ|>5AcIHouH2eL+!su3bu?tjeh^-tcB%Msm%tc z{xkcLC%KZkewbj>dkLm9io7I)U`)Epteo7dR;s>%U3$$>1vsp+J82!k`}QqUOhVe~ zN`ctN$Ge?6{+lY7YoXC_w3Fh!xsIGJoh7Bx*K%xBFCGSMbYu8PmsVI|c%^PHw3w5=1aQtw7OWFjDk8p-6U>+Q#FY~C8UQ~ITO zkCs_$T=pYVh-bFmv>RWWBl5s5k#)LFb}IRQQFWd{P5t4QS5c6TBE3XKL+?nDW&@;) z2uKG3>Ai&-IwDQ!Ql%N`y%Rb_ibQ%15PA;@B_WWo{Qk4Mv-{@G+;{gockbM0&U4P^ zgz3E&HS?x5I5+u|_DF$VcTD$5uxb~2*w0mr@ldpQ8=7Jvo#3L=Uj}n@?RiPasmrV6 zi}reLL$eU!@U0~#5~GG4*P2!%CjrT1sON%N~6!_t|%-sx(qx zBqjRHjz-iwQIdb|v{y+`aPm=jfFOHeSyr>d3-brhWNPn@T8rS(m0L%jsxm0N6x$m# z<#9zXNc|7=mF}!rwh6-rc@i}O4Wx269y059(~RI)(;s!YxfUI~5d{_b|A$cD|o2OdDOJo}DNr%kmlGfBQz1@F= zD07&EAIlCYG}*x!qB{Ntnde39TbRz-CLJ9qRy>yzaQ>#QTX~!5X(7itQ=@9s?bg%K zc5Zsf(7-jk-Mm!osj2fUvIW0E)XCLKI6V8;Nc9yufn z89}ym@4Y3xb}Z#*ubkNzno=SPA9po{|Ij!KCwE4g)a7-H&dIA)oj34GNuLD5$kMf( z>5o`r?;ZuGQo^M(Zu{+A+8+-KfKUD%%f!pk>ObUjT`pxZc;yVt9JIeKQ*X3*vR3Ew z&?7;xs&5F*omWjXZ9izDj|>}AhrDPXIh1?L^qa9Utu_w1ctNX3Nv|-Gcfb7dsSeOA z-Nsq3aR)EQacl44zrV2pFHhfaFeNnvuKDe36Lw(y23brl{Tu<5Sd1PSN>BCL8N^|0 zigu#^*gyu{QJa$WLH>JjDj?9m4S_D(QiNH(H*GupX4FsX-POkk{RmZiE3w$T6&%!I z5O1?Ri62J`riRS!vi}X@)I6eT82rfb^PW%Jga=65Mc(;S=e}0TICm)E{!Wz1ejfbu zH=F`&>bURm*n_=4UpWV@kUv{H>8-|ppcyJRbbWIw>(72|ostAZpV2!+-@58@d9>3r zBYMinM!pbK`PZI_=p_`qt$RgUA*JY`#M&Aur6tF}tPuL&4_81FmW1AR_NVI}Rbxns>6w-Xi8XP$di@}&vRFD>9B z5kFn=apkL7&mFt>*$#@vi4#HX+3am(_|S>pt7}@xbCj57%UiH@(!K3ik~PKi-v*Ab zg4B+?Doit3JdAl0QijT}BY8a~`f854H?x+gSrRAug_e}aI1jBW+>F~eQ8_=0JO6ww zuewo1=w^809Tj{+2l$X%|H`3~PZyYF{2eI@Y2+KRLK_(4_uw%&9hEHU_fSlj<0==?V>;kE`s&D;G?&kX?W*v`w{ zrcR>y#dK50)L`Q^B6%C8xU^*vuQONRJU& zb9qHi=J3uiNf?Sbx(;(T*tDysoJMc6 zI=N8%vY{8IZZne%Svzubk|gU{Bfaiz^WcaJJ05orgVxRGqQzMD*mmOzuopzL7J$SU z?A)?TR+kK@qH8bpGNbMq-rRW6#z8I%aetDN$LC=+Nt<|CKB66bc`&@CaC(+t2j0r@ zo%bX5A4s}-Pe+q(0Ra+AJ%2M^4nS8b+7{Z}Ywvn3Qmr2l9r}V(rDib*3xrQ+aQ#Tu zO?~~}*y!c9D__3VtEppf-N}_v`L zY;nElBG(qTJ-PTMHt8x)I@{s4(N`Ps9nVE7jW-zcvr)YzivY8=C=MD~7w_`2Y~Taw zXi0R7sd$`U4t+3kFg@;~`)$UX$IB6epp6Q8hVoxAQZW|;z@~{%c3oSQm(uP(U+6b4 z!DUoX<5}V*#?g_vAENG%*d&lHcjb3yD;q%A@&-dL4u$qg%eE)7YhUlcaiqI7#!92&GM3}JYtyDg zOY5PvNwvz333}yBF2f7MDxCU|0owWV0u0%iw#k9FXylPyucs$~4GnsF1tJx1+hO9* zZlVT@ic)HsF71Ik2_#ian1TxO`ZW=fXsR^>d=Ih#f3we;ZE{vOp|^Nw;|-&g=-BQh zg+LHWW1ie@?JeVFIt+bPu-QkcD7_%l$fcEBIOs{Eod601vmR=f4*M`D4EI(D$ZEnc zCwbGd-G!6Af?uP<+q0OzKGqaK=9?J9e~mhQBegs3vrXUUWnaZ=Gq-3M9p1}*;%>T~2acF4ZS?7K<_ zbW9^$RAzvFqMa`@?xgGsrV^M>B}3>htwUTt5p8n z&)L&=u2H*6pr~aY>a@&0UgyW-G&=s^gi0Zrfx+*dVD9LY;0(7?M%yG(uufO*Kkrtf zJA9S37g_sXZ;_4C){+D3zkKrMQb?v|ZQwWwpbN-#F3}iru)LW?jed`viC^N%+fzD%;l>2(Zm%83^5x;Gtp<5YzanKYJmTq*-T*=58KTz6feqs0%Mf^u*XbiQb75%L=91NHugE|7+i`sWE*N zWw6l}?*T&T3i25=Cy~#BI56R=OY;r{kwC*aw3=Y-9)WlNMIF~U1IKj7&tf^4vdRKb zTb-%gOgOQ8<@XHCB~@W|UhTXaDu@wBxiij3SXH$zeP5Hu-L#e1E&NiFGq*+JPfCm3 zF!V#%UHoB$pF$>8y!}sBUOJNoJ-oLuu5(8Hnx%OMm-6*y2^X% zR$PGQk+D40AwFXw=ZFV|XTZ%8xPpESM!O7{pA9|BLW{{i3)N<-*TXZkP$inBUG3^+}<(0kmiFFf&b+QWCfE;63iX)*TtB|8GRZ zYusA3#7UQn7olw`d8N8Iv}ACMF+D*`i8iQ*UZegei$_z(t>*Ex+P3+$!-y;dBBLU( znD3$`x5Gx%S~>%nYB5kZ6j9+{68-}I>y}p#{>|n@2#N5wy*+-;xUt)CuP4la##4F6 z*w5<9>HZ{uX1+Eo>(2PcxVPH%l3Ish*rj5tU8C!wqHf1n4FosQ0AIHqm-w4!S73Xa zQ^vSH9>%!Gkdhzl?B3-jP)PHU~}!Ux{Z zziA8&%>DHOTWIf~uSVclYq;E5Cr z-GzBQq4PriqFn*aOge)jrm~*#?5bB^)J+((9$Z=o{e34Rwkvc0RYhw;;(Q0lZGO+K z{?Aik(hj!HZdz$VOGBQGBHn#JLh07}Z_OVeY6nlq4=xxLlb&+w@oHU|&nJz3zGXrv zmOUxGjr71-TOtehXAK|v;d$qoK1_tJkq!Dl9^m{HuK#)k@Kx2dug2zDz&>s50-sH(VQfwiB@Y%~PT2%KRL2DjjX3U|#mj>W&j330;F=xhh%rx2H0gH&B}`3%(Z z!0qgN+0-)i8lO|NAOn>;LUbg)9O(v{Ba@~wr0q^N`-yekc@S}F^K-n^Omnkdk*OioODQMUS#icq53YUFH?%3zz9Yy% zyFRY5%%Fvhjk?BH0o}$`ix#`dm)IqHDQ8cNw1qi&&AH*kJ|J{re&G3F@K=KZkOGXuz#LTc}^!V?}r z9nfTvgtnv^`@nTQlFW{scKyI&^ufLwU@W`VHg}e{2~@?=Pvh{XUp;mt094(K`4H+E z*1|i&wZ$<2p){E5vce)|=883p zrp#y0Qciwj*thp);B%j5Mn79JZCqE1&&5>;S9{*n-nh$shkenKU(b<2GRk!F1)cd3 zQjti%AX2O64N^1r!y4-E+1#@5c0mpAQHXZRyY0I_Pb4nolHV2XEdsR_NQcNYKUJew zrzeU@g;WPn35?op`ve??I(qrs7_{i6cV4Jq=An_l{6MUZdfh(ja={<>n5Nvi-pUd= zA$yWsg}lF%NXCj95AV0!A!E|CC^w@PJ>fLcSpRXu>&-L2G4*b}_x0*~IX_3xEHsFP znq3x@G^0wu4|TosT_tCkE&E3MgRfrDtnkhcYrVYocg$kVS&xu4C#D8fuPCl2QMB%Y zk(WR?27&5Xpd*LJs12Zcrp|SU9b;&GjwmRX&$fC}7||-sS%LSW_#xSb7-*%epZ-CLr9w zE&F9`XM8r_-o4AmGrBCM&@wD)$5q7o?#w%c?5Vw6@V#s0W|b@uZxCh%WcF-ca94&m zxME&Cl_n&B)d7)8WNq!cA5a53EH`X2?RIm-D*e>Wrne)luoLcI#an4}tzb*anj!{} z-f)4H+FGd}s7L2#;o98W*G$G_C)ho#1xz6*J9hwbP?{ZPOra$9+hV!H0tkPy{EGTM9+P0MU$09GvD@Gg#7e=t~rz`%TTk z7tQ%ozebI=YKP^#3(LA1Zo?e@+PCsRWS}O1q$qxv7-b2XRx#DTt6S-iHu&26CVx@r z?H{L3EH@DIki?^gKbnE#si~>N6;*$xmYAm%cl76Rr9p=H0%%o1;m%v~uuC2((TZF;DnCZ8L(Vo8dJYI_rLcp_ zU`VEYj)cllpHlLIZu)pd;(-lPAovT0J<_`VIsl28vjvVvL;L|i`-7p9f2U>n4B(@Y zLk`IDVwrqZ@d7gqe3t+8Ob6@3iR)7h)UIY1d6j=dk^xGr`*(_xy2ypRuYF6G_vI$$_Kp6^}4S>DZlKlXkEWE`fz=UO@Z&p*~3lqEuw7@6S=g-~M-epbc%7pa{-dg+z5^%Ey9 zu`=yi+6p6Vc|H#CXIDE_DOGtBP2|h#gWYl+aft(Ly-!T)xh#XGz|FMXPK?ujTerjO z?uxMA5;LXHIpYkf8b8R1vX*mOGxfXksr{5e#TY(&7{Q4v|NGkf{Dk+H0SH(padcCh zBXnWxn?$7w0o_iWieN6gsH^T|VkiyX*<$Xsi{-Rgh$mMr`(9b_Zni3tUv{pj08j0c zB&aY%^6W29T4CPEz$tfdThB*oWJtSab{%wH+yD~t4R83Cxzc8; z6h%*Jou;L*+gG!NKI>1mp88lqG_UYV+{Vvq zQm$;+Bx<8`&-XIaC{Y=|&n5O=D7c!fTFn^}=CQ{}`JH0)>rD{@ePzk45^dVXc-{Tt zj&msFv@q{;^j0j~Y^!N$vl@eXP>hG;Z`Z-QLHbJu-81R_ZQ31~>Nvvk)zAhu7=^9$ zBzH~gq}O2xq>iqfNOS|^1v^`VCA1jfJ%R{Myl;4&LeI1Ki-kO|rT~L{Ih6Og>$4Uj z*x?ny;O)V|e`~+XzwR%tPXCKxDJHSwcC^9x!5OoF6D$~)47g60;n0bkL2C=k&6mxE zy6h9gr2v%kzpM?r5Sxbc9#op>S>m`eXlw3}@u+=p4+#eU^ z5(4t7Ir%XgI@rC+1H-oHykX#O1R~L--?*5zHTd-};?FIT+X7_wZ1u6%p1HP(7b2Gu zEQ@b57+U2HXLqmHew69U*P!I~z-yPb5US&1AsrsLJ7N5kGyyRt6|P%J+xxd#)cTtE zcc|#FZrxlA?O)ElM%=!}Aux!zY~NSO$iiiUpdweLiG9^fI!l*%0A^j)Bj8}6xHpRS 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

-Glqb z{Hk&04E3_&Jv%%{Tg-Ti?Vl_LiiKR5JXgbEXBNynbygdX#T0Le4A!8pW0EClp4KDo zB3}a!*S+Dkbv$TcZcBybw?Nf4y3)hRheMn$FrvEQ`sYv`-&(}i4pz_617Z{S&i{Ip z`C>}pddJkF=W!uTQaA06{+JuBWkt{<1scN8TWWVS2 z#h-RE#8SB_VBlse3-bVyV+So>>XYg9r|=5c5%OK`=-L~~v`FT+5QD8c{EmRJzEwAf z(vDHIGQ)8r)tW1FoG>REPj$!g#*ofB0n(hbnReR4C9_zTm}8UDj1;pv_7DD5oE!fu z4Pc@6))noJDlDCr;{zM%tyHYeyR}teB(C5n1(s z!1fhkut(r=-m`zNo8Nk?!Z=K>qmeraq3%h+*9HDY1`7)b9Sue>B13I(LdF4)bx^HC zL>2h)NaJ~*ZmBj@Rng_z$p7(p>1*6WE$aGpMW9Y#H&A#|jFA^H|l8%pNrOa=hbH}@f$ z9TVBI0Y;LXD>c!gd3L=(#51V()zFX!vOi+oLW>X^WFS0Uq8^8SQWzz{_ig2le2ima zJb5nPp@>N|amesZ;*G`tD?^jg%9sc^tWT{z3X*&!BqfB=v-W4o<#i|iTHw9dGjoC)HYMjl z10RO?Pt^fkueL%=YbVhv3;|eda?Bw4Z#ST@Z$M^Bd0FX=Zb6S<=vHOX?{iq;ZA@-J zTPUbMldHY*cp#WKcL!hjEDA`!xt35kqgg^1jT1{j4MPe=5W|+N+BkxOv#iU9LV>bJ zOLov(ZI0?6QOA#9Se``B5lLRbfI>M+FQ51aczky2g1of?VHECFfCRW?OW~uy$NSVp zvqw7NaXjzClFy`au0Srix%R6RBz?M2JvHkpPMDx@X(BIa>$ee}S;@iY5upbw{!iel0cB@H z6M?`f-M`KgP3K|VsSgF-r;}-@Yw2!Ul(^bvZJfND@^?i40h-Mp0dT&NrN*eYc&nH3 z7rPWBR~SZ6XPN&w70IFfjn(^TH_w`dEiFWzs-4`fxi`MR#rcNaUhhxM^xEr(^jEDv zxgDDL<1bmu4Zpy3g`@(QEscsubGS1iNGX9B#CVH8K^Q^fBGeFCyi+?1W4%aZi%>(F zpBAH|BrA)vcy01a{AktvRxmlm+?#wMW#Uywb5HgChWbhs3Yi2R+;ddP5&D^-*FsJv ziTN0CTX83W(euk0T|38eOfH(cyrzvYqn(Jr90n`PNSAmKe)=5mq zh(r%YmindWw(0B)5n>F|yiO3>3 zBg8X@^0I|4JfUySTa0iNAm@P%CvJ7 zCTG`2Rj3m-yL*%2<<-~|%j_l(%9Z!BqHz^)z{;hDhKsyd$!{lzOsE=YAzfC-jNEmo z+I7pmSS6l#TT!$1JkZB!S@AMGWeV_ zc1jiwG}Zl~U2;EE_zl*7AzBIySv$=qN!EHU;^Tojl(P3W_*Q3KMB_@Yb|JQHnDSR9 z%H231%=uRFdhy!sb!q&B#{7JI z0J00ga6S5a9p_EDr>)F^vxJs6<2Qm2LT7#sC?a`^NkQvD$5P$1e5*{(hw7YVAv$_H@INwubzU zVONDX&(IE3aa|fG858@tgRVP2+bd@%jghGFZQz7}kb1J4vxwc|yyKEkIpfNkq)god zs7JJdU^`PI3}+%cD`)75r;eq$38ftrT{1tOjdJ8#GkSg1JT>uE2QYgx04p&Z4?ff! zdZ(?&7O4W3h9CnImmlEX$506GjIw9Iu3uXZJAyX@-cxgWPLWekMii+Ne@vED6!geS z6)~xBoH%;2xiPE2N21u8&*LyGo0yZ8cWM*rX#O7yfOVc$p3?n71%`02{QFgC8cT^kB=vv}t?$7nL#6Xf( z8%o_E_B)LGCUM^p3*g4T1L)Ihh_C7#G02_2Xp*KW>9oD0w-R$5C_6xf+ZWb6T(aT@%aGi}@FOY9sLv1qt!49wae3nJ>4*GM(}-3VoS=WuCOotC{BD%Cf%Ns*|ha>iQsOmg#2!)tA-tq zr#eMe&8hB_>S=wSx9CU&R;)-y%o6S(hkr%}6Og?{5+9}Ee~|8<(l+{==jK-d(FPgp z!~5cTU#r99W*0@1EhwGZXweZ0`?jH8=BKUcb6741h@$*yQ76LnkdeN>7-F=b;Y2$CCxWKS<(8wT#sh@gt=c?8+>5)b8L9 zwXqH$4&840jCD{A*@UgAdT0e@3eheUP5bnp&Iojwt@aEhpi>_4tyn!D5#AP3Syv&d zAm~u574)o+DDS$>#@z~Hl9lHEpL9rsP^N`mT3X5z5AX*8w*AlXS@T>qUVV5g{BkD) z&h(TeReRSWTCa}Yz=&{-K|!z`Mq$B3fW*@r?U3^2+2$!>Xt>QghBWEpm1+;u;(frY zJ(Hd~xTf7sfjssSVEyH2kij5lF5*jgpB9!9MDw5kCQb&HR%C~wQ6f9sf`tTtQa$PU zJ_UYvMYXNmOa>++&zT-JVX@zaS{c&DOPOAj-<&sV*Qxisc9dU;i^to(RMKfj?{tlM zXRrTzw_BTE`NQ}M@lw#fgDdxEjKhEQP$ERWBsdn<)jKZKQ11)FcI_N0u#mzRx9A*o zqs!~Ivu3kxYpeSUJnZ$!_gJ}Q7vIVghnbpCBnwk;+TEe_H6mm{bwPyDGjOss1_e8d zvcx{SV-o8KYqXwCaP=2##eBqSkaGh?N#2INkHWtDR-zhh;1f^6Y6pG-H+VDXvf;U+ zY{mUDa30<#Rf6iXP==}(nNl#|ulyUE?1agb=KQqFzcJ~lT>IKw!4c<++9r&V zxMLbU>URX`K~l!{<|; zgfP3kzZza}L9br>x36$gx2--K{}T)Ivfyhkya&Sp1D-B(E%7G|US+--ab)`~3De=U zl^cwOcB(>`BoW;8g+KZHhoT67#uE*h^t3nsO)O0IczGIYY4`;WJy`rju?V~#r8`95 zk+GI;r%HW2C`hiz%%M~2>5j!SL zO$uJf5-X$%<59lid{W0)Qe=tLfL=)7YpfIXvNhVVd$Rr#u%380Xzvw9zJQw{__>kk@ivp# z;(e#1FX$UNrh3QH+12TaF5-sxrFkM}+9GbOkz+97GzZ_a^8*YrAgLOyI&^!Qzh3te( zfjihJc3f}zlQb16WNN`$U&W;N@a>P_K)hEO*XFWDPjS2CUqtP)TT=cs6_3~h*lMtF zoRk`yP@6jqu-KpFm13-Q;GqALhH6RPS-ADTE%Q$p$&**VA%}S4v8(mI?!L-d;ITGX zZ{v_R`u&@=I=x>gq0Q@S%Z7-bN_`A-)QzsSIbKkXY3kDt>Zz&u3X?3(65XMo%8;Mn ztjP-NQ(88E_@2F}`*xiB(_-Y!DY>`@3vKYD8@P7Z?iDFP*n{Oa^(| zf_@n3H_(`z+I8p-#R~V6j6poy3+Tr>a6?gd{l^!Ghm0cF4VrsdF3HWJBysQWcL^y% z^g7^qy}*-uWHCu`me7&`?%iqw4T|DLO7F;t zqag}7|0$fmiX--o*cK(4WQ`bwJFmDEITkbp*77;49}TkTb;#I|QOS28IUip=@IYN~`5EUwQ}jB=<`rk*-OUrPUX&TuYUY-pmb)UN$9$#P%a zreAR2mnCQTrsjW#(KJiD4a9$H zx}n7+qdF?M{T0dM^xf#GI0BuL2XryyMR14)u&r#g=^u1@pQ%2D4UD*>6Vg<|HOAS~ z6c~`tsVjDV^FrN5H5Ec>DZlJCT7f}5JsL=z$%IQ2WVr#Tn$@z;Th&9koBNersiAOmkwZ%%#C*s3nrl%D+&r?TS&BDocYfFJa(K9izG|vm;UKEN{<#kQ za`%&(U8!7h*`8gwz;!llKl#Mat1Mgjx~1^TeIg zpCr#8k9i|c1po6Rjtc|ThGu89o5fX>SO(teVNr?R4kojgx4T>}ygMTY+Wl|!Iy+mI zxRzU0coY&?oH@mv_z1MBIvaiNJ;pb~k`g`d8Fnlo97b zq#tUriU4@#l7xOrXN7aR+P@|6fQTHs>0GZCL(dDbd8dy##A!*{#qQ3X$=(`)q17fn z(|gSee?Y*tyZ@{DsbprMjxU0EFHz0FtS%Eawj0l;&fcS_rKMi3|G@t9`CAWGTW6nV zQgktRtjnSG%HpE*;~TemTZ)g z8HBfChqn5MF{}5J7cB=h2_;21Gp#NY$5U(jEe}sWvh#R1wc-g)Bj!?kkhwG82d<~g zN(icDghHNx2gT~a&HH1|>^CZxl_ZlZQ40J|DCpr)a@3Wad__DduARJsq2;Vwf(?uC z`u9KnyD zQv_Ay=aW9+oCr^f18>+@I}QpbwB?&Yhk}c98{UsLb?pD3vT{CU^z)34hHz>*cZIxS zI`L7L^&gO&2l_T%sKWO!chZf(Mcj&%F*`gv@F&K0yyC31^(`ZCJav~Z6IZi@0nCyVLeez7a9AwI)mKask#7q?!q zJ5}o>WxdoJSzf%qAvWsCm|H@u>fYlkM=@Qe|J{HaK<49~_khm`czM*{J3=EQ{|Rrre=h1gh;IZSn0k7USP zf``B3)v=zep}=4jO~c&NMj+Bx75(smtc^U{LBOI!BQ<&D=usUK#WvbGb)F7?ZJbVJ zNe*gs9(XKTnS^A?CN>2{IvEmgxH{IrkmBTy#Hq|!Kba1_M3$)i$Kpb=S5ssbD^+xCa}g{Rh@`!` z1f@uC2wq+KU)3MdUn8XTRWR+@K2xOCWCUWn!?;0lcZ(V31wsdqgZ7M_>OKH8@h%d2 zW4Ep`k|Yjsv$Yu@Fc_UE#*YwRC-mf4#e`YXQQqL900BRWPPeh9JCcu?IoZ~{*5Y&1 zF=F0JqrK2*f4c030Z33~n@q0*jyf~V?I!8j!4{XNwP@H&V3eS%OH5tZ24K0>J(&yI zkwHv*C2ucD7HBS*!7Ypk{w{|VCBb{kqVS%TEb%+S7gI2XxE(sYW4cRlSCr42O=Qhs zFG1WBj%OG=@41bg^HH_*DfHT{vBgsJaYaZ{{+X(4lv1t3Qvt70D+2e18NcyHRRX5=|@Ji`FlxK^U0Npzp0r@TR6 zsi-&zdx=;2J5ksPxAX5V*jnd0u2r<}*zw)XU$GcLa9V1lpg%6!{UmzwU0Cs7y|0W) zzxDR%h_obICP(7eikc%Xo_6;yGBHZmOsTKOvWG*EN(Eh{&qI3(?>j||&B0e`z!$86 zzy-?fcU}KI2x5#aY$On79za!sK>0?AP=+Ft2>W>)P@1~Uw`&a!eA{pw1ShukKU9Cx zEF8l5{Ldl(U%P%@0^IF}Hs(MWNY&T-b_&>v+kNBHo~m)}j*NC$M8QxVmMpbDcwu_g zws9C4iBZ*Smt<%Dt{B{-p@+*OV08h=0!uq@$PaM7PmGD0Lu_f2VX6SG! zxDR{Zi17c!%ag$Ovii5sUdi}X^COe7Rq9f8)!ZCh z&zN63JC!XKW(QIdo0U~?-xwaIs7G$O$oB;sNNr&shC=H6-wtL69ulV}c8HV>{S^m{ z-+%d|Bq+32)=Tu!RMC)z`hHIdG0K71fG2@f#%s~UyiE8tXS#93)TS_y{0Ji*!z&0e z!=-Dcqu3*M$&%9~#9=sf2}+;pp7>8}qFvkgXDRQW%~XS}_DXhtWmlD5iUeW0_~}C! zOSLIlWFP6S!&45zSy^D7}_{<1c>9?7oW= z(9pdIF3a_}`XGeC9aZpPP|gT+J>FrG`kKHS@Zc^@{yX6I4Rdsq@1O&>404nm!(`OQ zc?LoPVXqGE=kV;c!X@pMOK1^BIjaH-Z>^9sY@xD6mv@kahzOvJS*?4oV9E(iTwtH4 zJU0Jw@Eae-intCE=`bv|%7jGM^*whk|77lhhqMznQ?x7KjCUN1fOqa^VvzCy*GMp* zJ)UnMBhw4NF5dni$+}?hg4`&DqYBZ1Kh>CS z{IhIysDeWT)v8Yp?>3$93lnqpJ8hj!oqLXcn4ux*Du*L==|e$P$sYos;xWhXhj_ib zLlLk>#1JuZ6;558?ld~jV<_!tlk&@|WCF>?^0bdr_~bk|8t2b}Fk6~5W%l^(z&sP) zuDrd`u-_|Z6Qpy<5__Cd_>Z7YVO)k>=s$AGhA8=-TIgO`(J)|j`Ttrucl+@Brp?5+ zF2v!1;B6y)n8XOM#vl4bx!W!+hs*N&`CZz6?FAQ!rT0Ypkj@+%!2&%qVU9P6Q;;&i zb9`TUNx8<$mrk$Kimfx-qz}U}S`4@N=J*a4*|>4aD?z@Dv=Q@0!8Gk3Pvng$^oOK* zROC0ojU=U(%fAa}MQp;VyR7^Z$(c?9VUb+@jouhZdBd62;+F{F$$ZL~clB$GxYShr z{IgMi_X)bp(4{)e!DsmhhE6iyrRxS!#t^KhdpG+I1fqOb(j^Hyq{EKalk#fDN*GxG z1Fil#AcAP%Wsxm#Oq>3!!_2xD(IrML~GIY}@vgZ8biY zvENG#vVo&!#+86nMEdKkjx}U%faOz+9Mo$HqPY%AyB_tK(}PV+e5#n{pefDiL#44P zlTpOR!D*jgb}1~i^D&(hkd^-+3^->61tO^#6e93n@ZBJy9?G8?t9XVDe8bL4yS%a0 zqpf{QkeVx9(;a5LL6bH|!&+Nt6DC8>;ncv83S7Wsn|% z^(>x|Wh}6tZYXAvC()LA(oKcHGy!V@%FFUkz2LhMCrJz860s%DJRzeT*@I!j5KW%N zPk#_Wi|b18e_J#%nxj#7GZZcn3`wwcRfF0cP~oyx{eBX~OxgIcD5sGhPzDiZ6Bbetdr7>{dc(2Ty zjgkIl%sf%x)hy#q_M5aCTIBeY%NYye^aP%DZpY|PASdN2IOY)*Gw2S8${FS&0a<=N zMR?nwk&^;~L`c@mWey7K#q?ta}5#+@7 zbLeTp-dhN!@T$$}P=NhWESZ<6l*?RgUrS_tIn?M*H95roM3qWVdTQi&jxQji?DfZmRlW?rXmV%QtVRWlX zcQ^PFdC~?ek@jpF!$k}C#=BIAAl`qryG-*bk7u_S&{j@7z(=OHQy-dcJNwIJ_gM}{=Q-T|F$_Y^h`YUGEwdO=(=O?JK-fy@7+}A1rT;Q<4PymsO7f@ z>>PN}pjoed?njEZ`!5HH_97udWxkqLX3dU~u;^?i2}=JIIOW$L57T-ZzE=g= z|FlmHn#vxg3$^c3V0^G|zv6?OZcXMFceB{Dw?u{VbMVfq$RjZ6hb>KA8OZ*`KJP_e zl?7XoyBmflr`VCP?}IhkW9)orf@SCLaIYSlz3U|3f`kpVUj$Z0uCkxK`SSl@TDkGr zM%{K7d&So|?mSXIy~}six~=TH{$J-j9%6K&TR39p>F+f5DLpNcZ)%NWo!SZUW{=yiYVGtcGY-*>1%_Uny z{z$^_;I-U({ltFT9(0h;tU>Yi+UTz;g%*kaKx7CZudT@}&Z++P zWW@fkpdw{$N84i7p3cR>w#d#wl>0Es6!gbFApi*Xk~1J`UwO*)ZOpZO+tomOL;t>|3N!{y*2N)@2ze0wdqY0eibB0 z#j^`Z|JQ#Zfo{7x)s0hmc^r-6PEiFS=3k~9P_ixXm*;-h$g43AbkVFCndwklDvE4f zwQU%$STT&d?|D4&r>a0D7MxSc6Uf|@2D)9v1Bcq!jQmW5Mvda-{?c!Ait2=*G%LL| zYwcTY)Z?^|;Fvh$fbpoF4A7g>uA6%vcjGJOEJ!v|7*bKH%0yv^`}7U(;I5tpO16DL z=><}+Lb@hV!~|T0F_o3sSSR2gaTF6SHhC(0nVt%Z77SN$|5?<#xjU>&svH~&vJG_U@rV;X^S^Cj=uZbA!=Z?%3qREkD#!DT9UWDpvd#MZTd7a! z?=ME&xykh++4>HFkzeE-a5K-3Y46b~u{!M$gV2N%EQEG=cXQjd zJ>}aV(a)JQfmYpj`}0GR>HFS6x&0j5N9H{rNuk31=A*OMhMwz1uE$*?^DibXd>>8x zx0uF;FCquFL|Fp&t%|%V)@6LxXlEDGc1<;=~s3U!(7VS7yO60 zPR@*cqWss1(g@ZAVt`|GI_CF5*CzPeIzm0;%@V;|biGLAI?Co#wE%zAuxj6krUMM$ zyg<4C!_-@F#Sv&r+xXxPgS)%CI{^j)A-Dw(?(Xhx!94_*;O_1c+}#KFmvhg(-}?SS zuhqMI@2Yyri#HBUa5rPo5nJ~vs1a!D}(=piBg2%WyIA9i>10ez=2n`o~_z)dNZmFH_8Z0_3%#xJAQ$F4t~MlVJRt z@kCV=Vt>7^1o;TUDD(S@I_a}KAyOBHhQ?JT@Tf}HY)z$I{a6ikPcmA&`yBkuQzdvW zjdH(7E-F?-Sd%wLuJ~ryh|roBcX@F_)?5%FE5Eb2<#qSMAYblbL&Td_dUk>Iw6D1V ze+)r)thl@|N?|dg>oq5Yz6VcB)<;D(Ayf8KIXf~)#gm+;(>3*{*JQ3zgWO0E5gA;5aJ%=Ul{ch^}u^Aa*;b|uXzeheXzJs?vSxI7JwfsRsA+0?IpqIc$*Hj3EOd3EAbkj=J;HC zowO-<0&Ti;&u*M;2lbCF>*er5qNM=&83gCMuZ<^xNPK6k!G*fnzO#eU zB)85n2Q_nQ^!daPDq&|ArjL*Z(Z-9`t7I493sKqJWmYX#JP&3cT{B2Acxqo%Cc7mcngGN?O)J z%9U&nF)=Yrt?hR`fOGuk@cR#qR5XXKr!SdxkF(O20cf~MmJ5G2k8f7)L(0z}ryijN zZ}6_7HWeBX6qx-ml;B5K28znw8_xd z-+}ql@D>PlB*Y8l8>r;J>GTBNzdu&?Yt`%U?GW~Uq-(Vul&HZgJH|ZoSfLn|=_o|? zklI|~ycH@NsKVBt$^Jt<1aifxmw!e;t9C=+!_> zMvc^rocl@m7?{$kKpH4?cgYuVs-_2##32llWoV<`-?`)=4*%I@6AE`Sg1&Qbxn>= zad|fS{)8O@0=CMUppby#Uc9HXbSa~gJg+Fo47Y%0CwpI81nJ;MH%Bb;^3?+oJw2FK zXc1p;NQ@rjiZgT#2lC%Bh1-I?S?wo${80Gt0%ek7hGjwpVpoodz00rScJWl0hnHOH`{)zb?wH{4PY}vo!5wC5g zixeLmF)VMAJ{jBE_9dC#6}(hZYXu*RF@ezyvU5HA4F(#8PC)Gp;Av?+Ki`AtmB5E||>y~QYq|N!-lyotvbJ|k4B{GtpB}>V_ z@(H+^P+N6c38;8SNY*4(aqG&@9|d^^!5uYkk+SVUjvxINw`)0NZ;nFZvxXE+N>t<` z5p}HS@O_68oG3lNzst0#i^$2bZ9>5vKgTH9j>wqz32INeaGDKhomTn%OZ@@KZcN@m z2$%0W!6*hQS`TP^@;kYEN^2_<8$>R3%<4Vu@M%w<7ZL50Ee&o%i&Yijl%z2@J}Y%m zBz(vd$uddE5m4sb;F$%V284IkAS#m(HQE!l^cXOucDIA>`NucU{QAS&E#xIROju;z zv4n4W*-eH1U;DQ&?cs+ItIq6vm=mq^KB6eBsoN;e=tB`FJMcSdW_6K9rgeu@9P>K} zQtucd!4q^|$bEy#T@es7?4${Gphx~qrpqMEbTEwRw!D$V$BGB@K{Cqa?PmBcJzUY2 z&I&^PY>4PY7}XmL6rybG1p@H?5IZ>Y&mE|5OeV)cnLPR?*Q6iFG z_ei^qavARl1=d5uhoQvI7OCRZ$VYw&N}m{|qF2gd2G<$ieypIsMpepp6UVc^$ddZ} z1yj+#kA!0Z$$6YKj_sVv2fUYfNt;*g=y#128#LlA>Dl!4@&` zJ{4B*hy*%%o!MTCz*B)?u}?tK-LAuBqxfm*imrSXM_p2YGY;#HLgz)KEK(?+rs|Wd zpH(<=nCJIKL%fu#fl8@Ag9pN!)SG4eQ775pyu=W-Bk3{bc8`-Xi>Khw9ium$(*uom zi1TD+bWT}0OqPvC(*Tzz%r$^$?SiQ=7inlj4u2UM_pO#d7|XNAVI!^UvhMx}5hH?c z!m?`kN9<7a>4lElAzedJz<%Ol=V?(_jj&~fD-q{nZ}m!E`Urm!H2G@uIjxH{yvQed zv~ZgVl*TJaCag}vFzs*dp=!3_!p@{7D)54o&wQ>Tk^tzHUBn+D_A5b%;IL$}!|iyA z$lX=GStKcqS&y5~$nnJ-Q7sDWX=>~A@9|v4I~pu;P+=3UrAv2)Kd1NSDtDmroNJWx zQ+V30gHlFw;B6uLVgtCuN0v_B`q{RiWnjN#l{m#YEd9*-z?$_zUtSy}%RW zZb)&3s(w^qB|gCs(p$yLQ3IW$A!bYojy_u_i;#?|jKL^Y(a0lyr(Th;Cj|tr*ABqj z5Usms~d@u01CX~gniHq*4AA}K1F{PTI>H<{bKPxh80B?_nP&=sQg8#z3IKNY;| zYf8S?qt!2~7m_62!oHYQ5NJJ`aSZvm<}~o2fBN#3BenXhd}Py53=dyw1B#L_GM06O zJ?htwlF+3i;n`9^taIVoYJYuKpUAa}MJ%!7DO1(5QSEN_XLtA8%fm8c)0#-HUilD+ z$W9?FjT27JAi?op$@hO{w(2cn{r5lk_b&CfN8gwtVMvvu*k~=aOWU_-C&cC6YnkrD z7Ub_)=`HWfi>cksW)LhxwxJNju+SbMDhytxik=vwqUJt&9>hE#V*l5a^(l%nAm)+A z)nQzb>Uv(TclliJ4BVpEB}UuU^jK#ZpvDuL&(| zKB2Y$lL+4(VU-U<)isRW+XouNX7}nHvUa^P&~^~Tl2rJL)vbLj>Ko-s5;+fEcRVcI zof--2zM{3FHkBS8iGPi*!LF6%h)m zc{$an(*NjTT&n&%romV8Ho7o)anpEjA)Lg3s?PPDk&HNAfW6|Y2^RId+q(57yGIx% zIF=Fcg`WkKAJaShW=sdXT)F8SgoO*_uTv67S?kE2peu`}kUy=;#M8@CA&V^7448)s z#RP!=P{&m{C)Oa@AyoW(5DfZaUm2iDk6hk^P)~FU>PBR2M$Hx2(D%Adxqn`cYp6G$ zYQ!o9IcA+R?3>icdeWMFixy7`SVkR$qCLpcoI@uE3H#+T{Mr+xquUHxLT9xM#|jbX zM^o|umXtRJ=jTqk`3bx|KLlK57CnKs-U*C!#duo(_aXQqk}+n@J{#dmzfpj9o8o0@ zvyCOCDAf`~L1yHEXB%xgS}i!nP=o4j90Cc4dk?*9KSPMME!{E{+q_;#>MH*(?57Oh zcnG{Cv`scVmk60`ZC`Ny4aPDCdGpKXMo5`ojB^U&NDn>^|2SB!TOA?}3pVD7yPjGX zjv{h8r=X{{iN5U2&rM_{%c?0?>3v$Fwc}os@(r?2tJUjFPSS}~*G8*16j-`?EDeljsXg>1R>XY|Mm`W9G# zS(rCSe;laLnW$(E^?DksGHMn&?%1}f)tBVJo%P49IG`bo;w>^IWGq4kLwi>P%wdKy_t5%azip9j7rm>=p16)8WP2AO%2CB>=gxMw#$JcH?H*MC zjlOkg9`^aCv%TS$)LWpv!(K|Gyw1j25D*C0X^X@r$Y1Odf)m2ZiXhmohQe}%5(o~W zG_S&<4ElqT%P43+xRVoM9e%PGnz&JP^UcajE}&wN+4OLkt>huW_DfF-$)}5C)G*;T z%gbJJyL7V>T`zeE2Q|=|&SLAW19+O>fSn_&-`@&?HP6k)`EZZ=E2QR)2>W@)MM9IQo*}&&?GFsG3{O^P|f}z@4!gC zsll>^@JXZr9tN&f~RNPl&nD_bY=YTrMUp|G9PYU+| z?=}+Ml642iJG>6LQdf6R;x7>~!p4SD^|x9!3B}9<&WAS2@eWQ841MzHwLr}aaop-H zgF7O8v8Pw_jPjo;z#kC$vj}NeP~%Zk?P`ZkN7SatXGU5sjV?V3Hy7rF3mJ>8E<<&X znG*cQLXOHgf$SYF#>8H_U7pL1+Q61CgB;YPo%`y#`;2cZ~ zyeR23lBS9vLjUhO#dG0I#6QmZ{eV4Ncl5KKVZG>xL?Zp90^P*HGc>i1+HR@bLR*A0 zTr#1Zh-6m>uROR!m@=L~7&%gunbZl#$UjLvDvTcCRgN);`yrh=>KI0Q#IKCXyJfuA zjQRLRSSE57a3~!hX2G@qO3`gtl*jF1$2>I4>vHyX8(ElZ=%rziU2WUZui!{~Bk}5a zgge^Yk(<Zw*`r+C>kZq=tHd*Aqp}Frm~-fx zekCJ;BA-ydi7OHJh8ck*_%l5u!PLKO=t8Y7bBMXzSn zJ?O^b7e(BN_StM_Ux>hp1RM4C{?EJ_tvVG*CGD8K@vNpz#PG19tJR)5yH7mMEcnsE za)O~EVA3daQahoaOLprAu{SQR8KkyT9gh+;mwHFd!|f4E1nlyO($KN^sd8xq^K6q% zPsMR&ohOVZqQ9n`+jUZdbz+mTZpmzM^>GLR8rSu7?6Ku@74W-&PSXNE86pL%>|Nia zftJmU5`|oHw2uFuADsO2ur0gDyY#Ukc-isdb7{o&ajRozwA8$^$g`-nGEwQ`9Jdtq z&9DC{{>aAp#{u>Ut$S#%Dh(&kEYZ4M_pRz#i;PS4Ml z>(3uYXWobpPr9h6e4dHCORI}Xh@KH}JG&lAee(Nx(M$cF4g0*%ZY*{0nkV_*I)<(Z zKQ6bP<{o1_d6EhKM|Z#a_yT#D6>n{zg-XspmC){&zM%E7w*uh(cuZkjs$12CZY__z zHoxj8gA1w(>LHFjiLsZp5MbXDO&NaONDgpEII#f?j|(-gt_kAcl=x1y6=LL%%OMV3 z&1lfLgyR(S!?Q@yCXZOfGKZq7JY@MBi#3fwG$DBbUbH-r<9&KW+Xc~=rfR3imX+R(hc?grBSIrxSm7y}&0;sfgINOxNZ=)e4Z9q}>f z2~WBrhH-uMKKaH1ctd5N>J#)Gyf$xcduj_5fGV= zoH;h^u5`SdY3BUhUF&P;u5yV;gZT_QJa$H)c6Opr69OP>%^J_zJg56 z*^cvO*kYhqs-k8x9VDc-5M=N9_%V+;hOHVJ6gi zdnlK#IeS&(t%Xc7P97n3XAst-Z4EKkimCy;3SbG|($wM%uD?_S%5)QAe(ub0XyG)S zRZQ$_&A7yy)1<7xf5(Rxw7Gx9pyjSKAxU*I72_SR)xA!Zr4;nV3 zm(3rMX$>i$^^jcn~L zq`6ik#cJN!|97$|<}=jDnHJL4rd3#lowlO0$R4FlqdD&yf@b|PZo(G70G1%U9`7YM ziM5ZZXhYOE8M{B}SfC2-8b-R`vwLrWSj_gX;)B1$80+)q_Vs#(mQy9-4!%RRe*eA! z4sr>MtApe>*1W(g+2G@%zm`(3OLhY7Jm2<~M2FTuqrk2dX<$(Mv@(%g zM)=I(q=c0{>#pFxo+JV?abDAjIY)(WWZE1aI(0z%Kd_N#e7LL;)wR}L z`Mk&W>~s<(i~XGGjX8(<4tBdO!q5`yd|(;%mMH4;dfa1ByR8&&#OOhddiUYK|jOdYx6%TOzE3hS}Hi!_N4ld zRXn8*={2u+H_r;*p`PoSY&E%<@UJbC+DkRE z{!I6YycOJ6+i>&NE`_Ay-Oa1y)1<**h`#yK+)O~v918yW@L1f1LxFl{4KpU5bD)F7 zdE0LVaWv|x{=rQ@%tORkQ5b3K$%y^cpuot z!86FFUt|?7lg?JOnH0KJBj8LWY-lpea!5Jrr)+9!0ou6VV1%^S*gWfFNPWc6yt3h# zKfjS2QNUEm2cKJ3TbJH@(|R{%!rL;6+?rJ1T-}lPXi`40{!A3yHn4T<;b6+`%Fd}P zxau|2iIFi)QS^T|vuJF00s3z4`mi`6ez1?O^g|HdROUlgm)G4J(ZYobW$f{M2*Jog z)QQ&++J%@#6JO(3^EP(_FR1mXTTx)s5rAK@$xb@=pF^Rs&0VW8-rWR+aD!29=&f)rzf)_r-EUD(Ru=fkOi(qU%NUy@hM`*I&)>{#B)+1lO2B0Mt9(#U)ythZT2$43-{a2e3+Op4 zw$BMZ*GTPI?M&b!Cdb!1_J7=STMrTeiH==Bc!T~1_~Dew^>xvgo^u^h-~E-C-8BA^ zx6cwDt0s|d`^l4?HTBW0b^chqWc(rl`D{p%951g-co1L&)%#ySY{IJG#6iOS#SaI= zh8VVoBUZo{)b}QQ3t2YGW~D;($)c#BY1m}+Q8-fUG-zvVqHEWdQ%Ts8z^LEm5Cer3|~A<2H%&Tbrmlok_gAUMk-u+fIzOF<7KGR1u*W1_vSX{Fo^rH?jz?d>aCH))go?=Io;G=( z$q5R6Xt#}0MBKf^t**f#QC_T-h-d_rHha*fGlUb-VX@H#Kc4+q&?!QzWrjwcjIam9 zkz^46QeDctl8iluA*a0rj_|eBYh|(XH~bPA9_(v#rIRpVG}-9}K5NNhi|#kF1ZXF9 zO|uN$Xv=xGIENl9ucEQaK_0?Hfq`0Pz!@}AcIma^?(MddNds>Py zw)PQsgYlY>YY=W4f^Wb2Cj~e{v?>s~_il@q^<=b$X2@fhJWI9N@57?)!8y%p=JwZ5 ze+G2L@L#V7$8rS~g(ugscUTb4STk}zUJdr=Eohti{9g4azC=Hi3=O$our=&5!}U=ufo5+3mtCd+gL((E>`c8dloEo#Orhz`OLr~LhrPoQAx~+L^NvUf@24(cd%B$ve0Du*E;V5B ziyW%4r+#y5Y8(<**wa9bD6O!Zeje+BMja&p>R774C|*_9jl~_vw~-^QwwT^JV~ttV z_Uq7gh)wltL12mY>XGe(47YKu_v64)e~P+c4CSJQ8i}%SQ#jN_AX|r_wC6!S+evW! zv;<@Ud24}M$Pma}{s7`bxy>s=mkLOomLECG%b+iAc_r(JupZl@A8mBqzjkpB1!Dyk z&{?{Em9~xy&|4}<(KV8O3F?xK%(RUS8RfiP3l7X|@-}JX%63#D7)^{oTC+!a#py(@ zmwYIy4AFVkAw|-}=E~H^;hAxI^rBwg6r{{^ou}4Zp!C8UjVS*-f zdpTtBYYm(LI2@1{ylx;G`74fj~VyE>o4Fa#Gc=R0O1K}ajHf$O4- z1L-khFghfB$^gCfFe@cQP?^($5)+m^JPe|}vIqfH1UD&?v)zTgl?&awUT}ILO}jtH zu>3cL>vw9&{(%*rc4uLFWUa2|uc720}< zsqXP{a#H*@Ug(q!3Vv9kHz^#A+qagAFjFSiL`FWUdgP=e`R@Zm&JM{}(_#2w9i_$hD$y>7UC${Boe%e;oQri^E(o~vx<64*lwqtir;I4%% zHv=tRh`aBMVPm7~-@lco7qzN#j`O4cCdxkT$;U+yZ<*@Idz)UTi{NfK^S62=wh;Q3>eZS$f{(5Kdbmo+Cn#XMI7isPi3I8R@J4^jFgAKlpi zy>>;&hdw3QN6$HKQ{VXXpG@{2{jor~XVm4h!*)c^nd@LAvqG5jw6dY)^z?T^%iyFI z-)F2?dfa7)_ty;b)nyHR+v=`&&o=vap-k0S(?a5zu*W@90Ceew;Nv*JuN6h&aghJ< zw!@E5^x0GH-`m~IVbkNCxA#!4?aA3oZT>6Kh;892vDkk#<4;@~HX`4PRMY!Mwd7;R za21%;{bBUQk6X6En9J{D<<2$E%ZgOgHw&^@VgoWJ=^Pag{|^UU)Tq5}Jgbj0>clh| zU4U(kYd2r%HUT^%s)-8jDxSJ)lmEz;(!y@H)+3^`zI$t+g0#x0)NrgUXT)W!+YViY zlQqRv{3ex?zY;+TA!`O3wuUT7Dm@?DMLx{mKu_Cth(Go1Y^*vjT;JwU-zVc`GS{*~ zbyWj#1LKFc(c`zTFhh`_hZ~RSJHEk7#FDVnQbG9op}DTZ!?vov3wuw#FF&)LKj1$6 zVjZ8+9+&XBQmkJE|7$qhG~UF-jw80z!CJ&cU6am#+ve67MQLTTe`5_s zXIP^I_DC0{JIs$4-)t}f#C|YyX+U2Z1!VrXb(QcYT;C`HmGhFJ5x=yc0QzD$l&<-7?>lKvJ{+QMbe#T zD4}7YJVz-kgyBgK{Rm_CmV&a3|5JF2l|%*&8dLU&Uk?(jgL?d%)AocU{bI4HOV?56 z8s{fgz6JSTn#pK)f(3F2dRY>#T27fTw*PW+J2({i!WH)P>NC>8V zFy$^J7(2&UJdGrED>grJo%UviL+h7uUMc$J*n5l!B>x<|o@liX92268i6OWD=_bq^ zef#(7Cwpat+?F`SDyfDS{MvfE)7j{fCY3rSMljdH{G`DRCFxE^m_`5fkB!$dWyFm8 zEFOQLvX$&1`vZ$qH*^L(#3SOjn`A4Bpr>zUs~0vC88y&mdtG%hssH zn1r`ubFH9F7A6U#53V@0dsN0NgYM#{hR$`gfWgTna>Lh?BY(Wy;Ri-2Zj~`*4JuQ5 z5G;*EpJZ(Vm5Z1)38#|y zgs5%OjQNW>^%2G&1(h!TI@18n_)0Bm_C|sIUNzhhqs|hLrKn&$zpMTf3+Jk)Aws-4w%ciWqoa zd?GHkEUiS(Wl^F8Ey-_wwxeVbkL=IPoLqRo{N5fVNyf+vx13^~p=P&$;JEPp zTyO=L+{n_5kt)^g93^@QQ)JgW*E)?(ux|c~Jj+C$9@JY)qC{DDLU|W=3!{27LYGxY8v)UK4_&j%wVN?Y|l$bWzSqt+! zun=wDOaMB|rm`jtTl`JlsIwn2G>EJ}RHBqu7_TsGTOKXHJ|wv9QsEz8HR!ck^n*(# zRl8F4nyFCS9csF4mn~=;a#z+MD(Krs*20kND_E5!yUW+xUTTEhukwWTy&%>PoQl`K zf|9^F3pltuo?ulFJVZvKp5YD*hH0(hanqt zrE^88f26tBvaY+O2m!b5t=hHsq~8yY?2jSuP33~?ssE5n{-ZYwrC^JNRao2Dyv00J z>pvw#0a+WT+TUE;0`+#^SNa;+t$Uqj@}Gx%WzO)Aqz{GWTUN)JkKoP5D=P!Uo`;sN zdTQp>aO&fET32%XDSe)ys5ZoTr|JnbT*`CSsH>g@oFEx&vOGs3V1Zv&mN@-*^_+cd zNl~eZgnxR!rKP25tHC{#3Ojw?wmpU_ff`bDael7 zUZnHK>s=ezpw>{Nl#rl}DwWp6tF{*{+qajdsi4UkWHOHv0e!&k10O@~o(Dwe_1p1f zeczS*EB;V@F8SLzOtjzs#`~#DAd*aY;|+j~O-;V32!BMCHHduj&Z?qQ%t11C1%lpg zKb?JJ3)j}OgLU0#=P17Kj5t@Vw{$ICtog=^hf`vs95bG2FRxQ6aiL&c+;(I?R_gUF zh`Wg;MCfx=>P?)G`WAGP-eJx1cuMn)Du>b(IpmoHi?a~sJ}Bz`BE1A1STZfqr3Rp0 za$6oV)neJ3Y!{XDYql$PVusb6arCO}%z@qgzPl#C0$jnMmeQ5rBB#8fagB;LMpmrS zaSPAj)>dbZsjrVG1QBL=BY2^EnkKZA0q4Or*?<^zk{8pm9-)1<&d*y2@VI?RP0u2) zfjkKraiZRJ5>mM%%Z?m=!J^-I%Yy%tGXZ=;m5pmTJ%Yu}E-SoTYn!vxZ;3VX`O8dt z*r_l!(p?jM)7y~Q2ay1VV(~D6V9+j*&`mV4a zK;AT^p|v?bcYkO;k~UWpB``E*i=-y)u+~0lLuT8ufKB4TYDtx^0d-nM12G+ne6O!<=Z|R+Bm6L>4+$gXn`r74TT6{8laMBr@U;p}dnDS8#TE8nvxJ>FVGS<-_Zk4NnPll-44NS?o z!t?Q-mZkN_jF63SFT9VMK85;x@&H#^-}dr$f1JCp;=GM6i|0SL*;JyUCUu+e&_JT6 zESP(CdYrpI>^+WfHt54FlehTvK+B-&)ve(^y~2WY&zj0`QPF|u2IQ_xVCT-Mt;{ch z&3-OY%*^Tr2S?E%XEYfa3^~DM+r6m-H?e~Eio$?Ubu)#K`kVmsu^L1xaR5K9Z8bY( zWUUZ6j&lj1$s6rj9?O>@l6uWBGxY7U2tTp38WeF>F;*I3EHp;w_ajM@1p5-N(H(8V z-?SaC-y6=Zo|4%@ePle`{|f%{D$!IeP&4ra>oi6*!2dP8kh`TN5P zT%A1qmhH4aqZb`uhUnvrA~O-%qm61JMEDt6#8QIvol5we<$xQ!^vDv!VN2g2g`!2N zE95>Bg#FhZ@Yp>mk64ms=8MHGYIvA?oIp8S_lb_XV(}C1Fb;Dj!RbtIV+fB<;vop- z{)Ywq%vKV}dsW1t*Tf;E7yJc;$U4k-czVD?KK6B%TbKq!%@DPooT z1UQk_UQIdG4qhktVs^YPMd)t{y_1Euqe0o%c4WK&)xijx?8s%~UaSg_Qsp4=_D9{w zD@q|7^jBR7;|$z76(sa-6-N`J%!C2r^b5!82(4MwMvp7d#+J3nV(vHfOJ|aX2~Amt zZur9+n-&ITRm>h(C6{7?;yjk8iW|K1%+Jnf0jsh&YdLIgO9));xScUyCOa#O0FIq7L24DZo8UNOq+0AX0 zHui>8O%)UE6=QR6Q-S(y5Wsbs!7Wa6R7aK9LII@8-mpR`@KgA}s&T>KYMJ!lY_q)A z?kT@xD9^_f721zNgd4cfQ#~y?3ze_!=$oo$ttkH;G7>g(NVwhABT4M>`R3t~s8waj zj&wrtsqF2QC2W*dvCe)W#nwv+0f;%U8y{w0<#J&QJhuLh40bL*mR#9Lh78*7ejl?I!g8C$ zd!FV#`sFU<^A$>X?FQ`zyti)U946VFvO9N=UA-qM`!qq-##~K`OV&SKe$LI@K0iu` z|8s7Ce$c+DLijYdcXmE4Rq1v-6<)T#fV>W~-B!FV4Q$;ye!^tSu+sT_9lB7Qm9oqC z{KFazay2S!9k8;PubfGWec>zPd2^ufDv0tCZoqqkSKhAFkMg0tYZF*_LQ>X^6fv30 zef|dQ2;FcJI)*YEN-k;2ZL9BTaX*o9Hn1k?SEKd()<(P6`TR*lkKx_0AociU&w?K# zvhE95xZXmv9;K1!U*v_3G!3hz<9oqGgZvKxRP?(&578fLhB7dDu*lI1yo~drHFT z;uKd5sqAGJ6paNOhzMmJ*q)b1e8?UPAtb248@iBy2Rcq?`Q;Rw+ zoqda1HM%TL^BnP~tj{Xi@|M-LlsSTlHcWxve8H7Jjwc_gRHD?b;nJ^w@IUP z`)ZfpqK3a|#frJ^*f4SiE*QB5x^Q$&OghK#gHl+2sQepD_l;BUiPO~bYG-C*b-I-?JKSTn^X z6s%kEl-cQgVN&&vZ^14F+G)Nh?iT*>ti7R+V~2}n?%JZW%kMI9yNjZi7hG;%gJdYj zaCkyX_%8@OaW9KYp-?$^JmRZ|`UnpC{gBD`(gesA3uEUt1U!sC)j=i|U+_3aUm30k zP&0L|H6*TI__nF@++f=XLC@t1FY65zwFPkUxPH2_w+z)Ir!>51V1?q zhkVo|fX9T>sKg1p=!+Wxlc|&53RX>I7@###hL%`O;`&vT&$58CQw?o__q!@7UgZNU#7GqQ(_GYU47AC+Hjp}5|1o_C?lC>dg-fK z13qxZ`!?(igeXS*%Nr)++h{rkv0@0)=AH9GEEi0M9dhy(q{$UMLDZAAW;%r-yL>bM zla1C@LYfQs87pf?yAzy;u4a+NE#POUEu;m0tA&0{nldjZDYq$x^# zqF77z?#=eLuceutFB-LdWpua!eqeVvS`Bl)5RP7VlVGO{K}#hm@HLnuU+KCOUK8tChi{*o z{-^GKW)PjF^c4}zaFKpKHozre_CgS&e&RZ z=Da%*4xFgX<_zJFl#%?W(GsNxlZ^H^`jnb7k-6(`cF%9D`eD{L*zQO#?oE0?y!*3lc37IVa&lC`mhuiekn5)52WU?bgBBW_8 zYBeS{sY#T6QKF1Mm)D*l*I!@rdZ@$1U`L&bGB1?UMx|uT@-f zXV`X~oUY3b{mL}$zsQf{A3`>ocMF*>yO3R%;F!4hGUMWt=KWWJ9O)lKJeJ#-ES-=to75*V7D{KOTx-uh=BoT4qQ@VI5KBJd5~3A1DgIa?GnSFt2vq9%UqJ-~?hJA#8YfwdAALkFswx?c?MY{Of>s#)IH!1ybv10zPr}NiUKUf|~ffvpw z0?$LX*KzTEE$^mv^^Yd|p(k=424}Zv)Pznn0XDw$>?=48zCV&}`j!6gHqD;RL#Mlc zFMz~CM@vWMiJ7UnpFuc;jt|0iwVnUjp+ArN3d)eOyRmPbMW_Ks;X7x2VR61kJ8fy5 zcb^UL6*Rup`4%hZUT&*!GEOL4C$IzF#9Cw1X(MTh`gFGlPAPT0J^=xWuHVTYi8JV= zT-xv?nI?KU1|%>(JJ31cT}NT|3u(k7nic5O5RfrL$aMjR8JRA1lR$rgk>asn)<_Wd z^o;{oMLJIv^yk>ON)D_yEivl9?2j0=b1`iZei=VL^oLNRM^?edu-#7ZyPd=HZx1mp`k&!iiU$T_zT2Cn= zPa?jbMGPMP_ZZTNj4dWY@8_E}Qnz{Vwlq;k^P12xynT`EbaVDSHs1l2xNnbh&X6u~ zy)hbI&^4=YwTWlt4PX_Mq(T8y&e|f8o{Z$GT1td&zr|W%#edfX^9u-qlS+V9BK58j7hWFh7g*)zOf+KwRO9 zY})%weZY;ZtXhzCD44*Hodo4wk1|i6LB% zudHv}NJ`%IvzFKmx&%~8N?LUwar>;v;|z0GPwJTvlXyLshGx? zd{f1968wUV(kBV7{g8z{hus(WQGG`-+$hh6c&#!3Sc3rW~`jWRB+VBE54p$#cT5;f1|SYR#G#iL8J8383Fl zFXgdjzn{7QsYz2|{fr6K|3$zw(1OzYXBhpMl17T$-mJ$``kMzs@1+oZl5;WRU9E}2 zxSxU-!6_~lt4&qN55L`g^nO!!`tTmLyM?L^fs@>JN4biqSZ+6N#+hO)X2%>=DYw

Uw!fWvmO3LyW)2yI&4uFf)m|&mh)mu+02H;8)0Y_cS|&^HTyO!b=zsX z(v@qg;w|Wdx8?o!BSe^T=SN6Fx7S=QD9nH~Vys##pO|1UT?V7eEFK-9r%HPN2x-n@ zw#6w>lGIYKJ^ntxPq-(B1As#j)|64vkfTebcUH84=N?k0g*$f6iWI0Aclug1!y3}7 zoM9BGOD_{F-m1zoisD`U%!XFvlK7i*mdAbZ2fU@e2PU)kF%D*qSgjmU&G7ZxD7wVj|nzfnV&lSj&DRdClTq;IS1YnNCEovB~3xhl_e^aVSQY$1q|zFLpeS3auYA+DLI42^HsKH!?4S_fTA# z-&fgEoPhw8{o9kk+;3+r9Q^a-c01Z4A7jM{Zv8HG%L5oY$#bC)42UVIj*Oz=hpqi5 zyyE=v$yFmc(}A+0;lcbU0bI)|%FC^>4uCFp=_zUFwr+d&$bI@ZJGLkr35XiVYW>7X zxBhU(w=cK1%)toM`PmCup0J_k(keT~Vj~xj#!r|GB|>|YqS|qbJwk6^7}c_vis|RA zQWtq_Kir|5(sN%)?h%Bq53vbjPE5i@x35m_pIukAH!b3LFPn6l><$sTjEQD^!B@4e z>9CQqYxdp8A{q5$dbkXUakd`I-=TfzBu&aQ{vT0i!4_5AZha65Ns)%3k&>30p`{z7 zyBma|yF&zqE@^4$?w0QEj-g}demUnk&-H$Uz5hGzSnIa}DxO`UTM5YTIi;jn=`5Lu zcG={oCi|te<8D9%uHC`%nOb?sw&HG9+rQFsm!VMKDA)@rXb~b$)BpdM)C~D>&3?^I z_jk+XE3FSW$t?OAen({uOOHHnYUo!?l6NQLY~|lxi)&^yUREYYFHR@vfJTTy1g^zd z`~hY%x_Hfn014TgtZLpY!NlhJo2uNNeFU1&XC>;tHk0`;0OZ+E)?2);BFcPNwY}-e z4@9BU4b!RWt4a5t9;gqk&p3r{r@l08uaH75-n4loCA#s(Bb{`a&uo2ophq)M&rI^O zj?ngf&2cl?n%&3H1Gfp_?cA`j`!$zr1D40{O@mId3$#4uPGtDVv;PC4eflnp;7RW0 zGg%{YC;xH54>p#;C*-mnltxhA>Q|=M>|CtZ2Cf4`fs$oTSipC6NPd&}Tt%V~8!-!C zo^H?BGdpzyvzSmrxATIJ>t=OT2ze;B$Yw=}0I%*LSLAB4)RutmR5sDlsud{uZmhr+W8V+}w9Pc{;Tp zR2ceIb+)XTfSQS9@Dr;mnvUklDY8jr4AX6p9i=VWU{V-9%)jz87RsVMXIx06b`c3# zXA#B}9wB;lBzfbgp(VJ)hS$ZK_mY3-+{`!i<@v>?zqobRW~UE-MaQilXmHwQB3Y_w z)B8&k+eZA~TW2BSL1S~0{ZWbmjn1>e!2Kj~`)Mf6es2IL+JWb%6Bc7oIlU^?vz`XA zfL_N-Wo`Qr>d>t~#clUh6LOZ9u7)Awmu=PW0?gwb-!g^%wYx9ft^o2KKsS&`HksC z;F*;Z`i|*aB8m@xi~J2c?%%?dUFeR*c-g>JY$&0kM+MnHjSpjmi|%lLF(GHH`9ZVfDCN>t|wyR8KIEGJs z-$-{$p41&QkF&GtwEz?^Erhi5>i2?;IBb_yqKbldqgSVLX`sm<$gv>a=byg{@*FUV zRs*QWn{!nV>S_rPx6Xq9(t=IT{Q~d$bB>}s?x2`oGG-M3Cdcok4k1tA6>QcH^gbPh zc7``nO)vK8hOTkLRBr^qGRt~jtJAB3*ZGD>TA9M~pi?2eVlHE-?jfaug$JhGaoz^n z8CUr`q1{5<4IO}s&3(z~!xpZ>&0UQXjsWU7Z3zGzU3$lCnNyKFZJ~3V{!M+SCDi)9 zOf)qBJ>u^Dh#P-?Na`V_WP?sWgl{XMYKq~DX#nmyFqDvF{^w zDov+1r-E-p6XNsjS25iq)dMmjy-QRi6F(K8*?Ud&`W9Q)46L;1K+bWjl;iLdM)9)Hw)hm& z9s4_g`|Nlqe9m}a0G-E1xuv9f>DT*VH6k~CrST-J)(tf0%ieF|8F2ZLSZaeGQm6i8^{mY#7aP@>-ku1O*|+o{y zoi&^mh}1q)^Du4Gsh)+CAr6%IuuNq_a?VIkmDh6vLXJ)4$gSprWVs(M)B!dX?oHC& ziJ)|xaY$qyzq@CAW4y`Svg*x<_`{B1-y6@x`9}&Z!zCkE2IMR2DVBtrW8je=J#&+b zCEb#AB;po<*!CE}q=X)pfiGdLPeJBpnVk5H3c^E)Deo`#DV^VmrenY)S4s>R+MRg| zWajbS!EG5U#G`lo9Tr&&-Zlm{=Uo-QLne4s27iy%k@d=az=`|CV&YQ7*Iv&yEf-K% z(=zaGfZ&vyuCylp>FEesef0Dm)A^oQy9%BG2I}OQo4YL2ycoJQl~#SwT}0r%2#ZwN z;t#VJQXPzRdUvm6)r=!hjTl*p|GO=M46htd%zey zPUk>CECMxhdlf*KK)%7X-uHB@t);`^axd!OR_LK|^#SJV)u(*IdYfs6urU+}<_FPW z8uX(EDJ-r-6GX4#&^~3z?#oHWiWLI&*REA$_frL2KiqjNEI=ka{+iW&w;LkdGiP*t zA}$yIax%Qo)ntYQANfGYSJXl3)zrA+b|@U+p%!)!29D$vU(ezN|82Wp+P!&sJZrdJ z^DWGPsxbVxlO^jf`zsW9Khyt$-hL~1**O&<^wFM3a@yT~sf&mVP@8u3)P3fFERe<_ zKYp3D`%r;k@+JH~xvG(XJIN7v=uA)T#%o91ftcctvmdW%ZfEQF_JXglo2v-ccFQb3 zkCII(`|VFgWHk?&8XE3Ga*?p_?GQCadJSbtg5f_hN<;a-523-~bEZg3)6j}TR@Nib~4chz(lvd>=E zs}YX|{`pmm`XyT^G6Ed;A(j#p;;VC%t>*{yJ{gw|^W8qn#z|3)#gvjOHQqv#qXXJZ zv??sgRXRA_NhjRjsC)f#a(nFMUJtWiUl_7Zv&*#XSID$1TqthK!zSa!xhib_5r89N zVhp2U|V8k({yK$$!N96HN5?)86^Qj1`I z=gb^xu5W4UK_KYJ9%enk2`^onZj&!F==h?hf95jbVYzhLI=$%6nH~!Klv&EW^vAc{ zmw;pte7(D=+&ga^FJibgN{1dLz%^RdKxH6~cVLUj{2+70ICnI;4WGA=Tt@SrF{cZ# zTEkg}qy=R#*(6;2onaDDVT2+qm^?AlIGx|-*d@g{6VJhopDMa~V*(F)K1e$ESyU#7 zKNr%fV(E=3k|ZIxaa{7Mg50iVF5Sa-=?wVmI`a0!^9_WKIYnP_Ma4l=WGtc+csCm$ zOghBO?Rj|3`Bo@BCH$$}m291b{AD*2ge$QEbgv+jUJUeaVQhL&IZz4{;;rfTgBlDW zR*d%;x9c~%G$!sR^eBsX5(~-NC2^KX!l}(9t?(qUz^`02BK~bha9*|zO;PQS z?_7~j%S}g=(jzL24Eo3*g$SThnZL1VM}5h|iI$?dWntnHeAb)Dd2w>_W)AkR#m%H9 zVkl?KdBC1daCXR9kNSd^f;8+HpioHZ!j@3%ec*t(G!(?MH)tI(l!kH_?~2P3z;|${ zDl{bYj!%C5X(BVD0KTur`5eb{_U9GWQ_OnnxgKCnKYZfAI?a(%UHiLK7#&pxr)P@0 zN_6b#7A2r&CFF&IDFP(oDdL}bE(1FGWDW8Q_}wU0G&c#OHD@0pG3|Bo*3EL!rOXm@W_fq5e|XShboY%%sWW+ z$)J(yyW8gNrdz~~d|-2=q?y{Y`SV*)v$5$difsZbl_-@_4DF7iO_p^_vid!Xmw=I6 zn7b<|Uak40f_7ylCw1bTol-jg9(NX|t=orT1Tzix?^*e0P#;r&jwz^?{$VD;)YtdQ zwFX>26{p}dyo*Vx;D>w~>9E4wp2d*)Se442de)iVZ}`H0ySa7wSLcKBTyKkKXetOr z$s0vNa{$Nk5`6E(LZKf?x{t(g$$R-oa1p$5l>!T~SWe^rcxHVILwosXzs@Cx6QJQp z`|wFYiI0jCo0S3gKra>+fOI62$gk9AzvLmwef0Fl?VgxP$v4^hrpU247D@N`V`kOel z>aA!ymF5xygb66>_Iabks&fyGgsUL(8u+_8!84Eh?{^)4I=SiYBoIDU9jiB#GtHyc zAY?009U+FgXZz<~Zw8_ZB^LU!Cu^bCs|;6;*QJgB;X9yQW1k}1rgggW9iwxo&$PSn zxg-G7r0>=6lK`eqp(otjK-G0_tQC!Cp4&<6rNAOhFU5YzFOipjZHFts#U6Gh;B#4m zorke1@jD@kbdJvP8w%2#-UrGtkKhQ6*4F?7on}eqSDl*0L$`3Zj3Gh^%t*lhG*25O zBk<1uoGt9nZdbeXJLw1#HH&UG9kPIQY%FFb(&@UYVRwxN{-S<}KWTnaJo+$%Vv1|@# zxo0|N@Q*jblzEY=W{gt zpTfe=6i{jL$Kv&sY=8fleZBYo+@OZ|$j#T|QT_35n&f0`_0ikl#>4Byc$mSAR`I58 zOy^0RZfQf!LYI_*6a*$CC8S0U2gCpC63{V*ChO4-iHqiA!hGCJQ@X-wE{5e$YKDHb zyXZs&!1o$2DlA=LXcmy(P$ne+5bcpq{&9^B7)IOJcI=v^8g<< zfAR5p_jV~k$84FgWC%*y6Y`hGKUR|XpTSS9Y^i(5*YDANp5v?xjn+R2l3<7dG}(4q zXB3}p-+b)amGTQiF?SP3lY^j-iF6s+WI$hGKINDE97`nnfq|@36z>pZLS+;)9e%&; z3p{;(&n(xGmWuU9Cd8`WL50_!fOK=cnR8ZUH% z##4qEG}nnl$>r38DjjbEEBoW2P(A@ghp)Ix6&=CW<(d#nDl! zctqzx=2wM)LBF9wp#Y})Q@$gyCS2BQ@;p3N|IhXUq3t_!AUwOf410Ht3>c{Tz=fSa z5^AL&ARgX~;g^?YagpDl%py>~?wY9R5n#U);l3Qw?A-mQ@i++yQWeVUb28sa{rvZ2 zO+!M7U=E*N2Suu?2-pfwK23s0Ce8EuQF|Jy=?-hP)|h%TG4t-mDd_g748Sb;As5L1gg(nTL=_GEB~>4x%{6vwJkFEKai@=f{yRJwVpZ(_43o>O(%!e}Om+ zMX+RJ1`3%SJ`vCbML=%4m_LnfF)U|$)R1UDC6Z>A^+ziI%PQSEWnhD;(zz&z22cXa z{CNqa7xoIg3;J;k_Fy=_ZG#?X9wTKm=mOy*4g)G;lK`QlDGlcE?+F}&$9L3TEb^SVjkSKz73QnhxeXd5cJAY zcC-!rt8uR-0%E`+e2fI1@Bt8jbISPCS{_((TVkWra8_U~bjGt)r3=_SJ{`4PyhSnT zw)?_Yi?P}_^j5tZzL<3j{e3p(K?$5Fiygor419r#W^~f>^~GgHHt<|hyD54z!!rg; z>lj~uP-0gZV0C-rebtMXJTT*zIqO1GtE(fwfnsxTex{gAE7V`5m|G^s4Keyp`@HUe znSDlkjQgsWUhqh_fZOC&Ne5nSicrGfooipX8^aZl3J{irTYp(i-%ycYA0o;0! zGVFKn{o$ALYLa3{P84S4>mrLYX;33djM&O9BdwcEcnnbddPG?as zsfqVjP&viPr!g>>&QOGc`BU#g&;2HG*5$I{#p`ZFMcvtX)a6<0ZHDW`@x3kC0Z5s@ zm7qMgdFpXrBn&ag*QL~s?G4=g;yIvc`jbat^#_^XswDVojWejdt>?O>0DevW35Ogu zwElmk$$4}lf;Rg@B7?`$*3z}@}q6tBbn^vC7+*=i5?B_YGNT-D-t zT)1VK_B=TA!wa@acga|ig5Gvop9jWqYQpd2!Lu#@ZRhEbAV!~>mI_s!dv4}XB50!P zISa4=1vb6w1Z!L;53dQ>2^%RtDLPr^a^LX^0L1@^W$QzVG*n=kL<++19)*EgRFcb;XouhF+%{&TQGTY&5{ z&u>|G%)YNUMK4z+?F6KoKh}1ofx=uGtQSVRZ?H?j__mHf9M^I|L;v={cV)ZVz%J7; zJ$6vW$*1T|L;Osi!sl{HXB)F&OvdeWZML-YMZEw8%Ndb-TolmY>3qieP0LpY>`)|Q zQszcBnZ;~v^>eu(ym7Obm7ch=s^lH#CmP`_!~$)IeIu(EKmFB#n10r#Fx^^q?z&(H zAnMD>!h^XEsP|9cEPQso@^d9cTea)LerP6gCjfRtb3J9FnC(+(@IB9ef5?#BvqslL z%ADq_f&WBCAm-G^fROc+)S{s5l4d(lRd8q@b?JRXTa zqiXTNqgzs~hPTHHe060CzO~fA=u{}(q)o8Iy@A|5jk-lNjlUDwZ|GY&hVFQz+HY&B zyEft!dh;=Gb8oYL2|;mclF`eyLheQmI~K+v^LTnG%*~5KgJDNb7jK=aFJn{JO>8LW zsqAk|pj}$4wV&lsZ-Yz+z}a$DOgdTsDvGlPmCI-SJH^Xv?|!ubdJm3s1Xt1z@`C;T zomKSx@yH7Q!oZ3AjC3&raO)5L$x~ejMFS#1<2%&yCt~sI|FHQ3jG~1=q_j|AS1Znj#?Ca`=(HY2P8T0OEaXO)X$i&Uw{^#s!7K@hG$(_mlK?5^e=Lrw3 ze{?S3lP2%)27q{DX8(d%2 z!_s@^BVc1d?Xv)c*x+X2gf%_MjA7Q^)Y z)ncEdFheVmd?#5OgL>P$wd*i+{9v?>J8jRHuP)WSn}xoH?6KdsX_VHq$cHM>>}TXR z8ye#z3mpK39ElWyr;OKp%l>dbdqr?7k5SP)wSz#a%>%e6_;;cQ89G<5x!ZU8?Q09 zL{^U$!o864LC}uZ?G{l&z9d;d@>SX#2miMflcn8!pH;GxwGi{ea-dHt`P`?^)9RP| zga}v*2gn;HfTvom-5&7|#X?pJAqa2ia6nTAeMfba7@vQQ?KHy?OUwX^kMqiV-IK@O z`D}je2${I^L}r_L*PTCnyJIRF-{vVK18mIi34WK^kj~`sVEjC199tCiZ%oq@Y^uZr z)5c^v%Blz0@lkg)=7ov6792*NH+@Vr$PY{8+Jl)+5}pJ`O-Q`cOc&QV#LoVfctXxE zMXrU%K(LK%v3!$}^H8S!@$*A~Z12ng#Z3TAVk8*Fw2##|4bi=rHI-s@hLoY2kToX4 zUQKUe1gKbf3}r%9j9~aSsFOOa8ZOPwRuf z>PCfJ`lXUWJKW#w-Pc%xPnA9oyU>%(ZApxE$vr=a7r?|grK@2xC9iMs{y0lp-7JvB zY14U60>ZUGxNj?P*^@rd-6*^pj_IV7|LcM#-@6<+B_RPU-M77GsvBnhS->;-q51!jnHAqm@;_tGYfz$QW{2`DB7r+NDZSy#A^txSjt2ug_%9lO4+pF5JCJvgP>g^P> zZw}8sn%keGjI#3b-t(GztlRK9`3~#m6zCYAe4MNb5~O7Xy%yd*bFD=;-`KPQ$p7ck z?)t~!Ek2LX`fdk6u1DTt$DTIj956FaHRCyQy!$UihP2A^u-m;`z2sB&0ilU`IFQ(m1w7Q2+S!uN`#xm{f z+g~KoG0yZ`)>Qe)c=l)%Kj(a7YrEY$$?5mvayBytO+Oyx6v{WzmrtOTW;PVQS^1t< zmCa0F1n-YEF2C=wa$r9pbhgYsrK4;Amjz%HHUEDD^F~Mi_DK2aFrglbSE0brS8j;3 z^Ur4!SEfm!mQTD9DTML!^9s_^S?yc5o%0SP)i_>m7Ib{EnF2mjnd=?vEM)1MjhDYQ zkAdML>y|)?FWG75F;jNS(1P1O&B7{eWNr8AUauJq%Utb#TzYQv$_E;xFQ?jk zhJU!V%yRp3!D>I<~Rly(p=m-yqNAnSix@n@eQx zhmA7$MKzpFX3#u4l2CNHf#Hc@X9S@Sqa1Ax@$@!R@+&%x^Sf|zzb>;z86)>xoM+W# zkAXiT?VBEC9t#s6OHI04^Ck&(L-*B&;D7O{e^r*yPv;bE{2^{JSjpM9!9)bu*bkXt zBC`O3?ZOkWynhMfgF+39-s?kz043<#A9wz$cO~O=S78;K5Z>avABu#CSSht9T@Ro` zzRGjyk4fUFiS47}Ch46a*>+<}Si>2*csHvVV);bVO?!6-dQJwv(;CY$I z#15$QQOY#(2AVFba4_O_a%+{xT7OH1ak%1BplP}d|E)WJl_qQ7{DXqYs zVx8(RGg#pvmLN`l7@}~5s~8#S$y`yZ^y+VJGx{Ug2q-zZbIT&Vo+?AHSn&Y$(*46o zf|>RmL3=`%H$?$>oZaYmf^-l_?ud9KJjKli zZc?Ew7fa^x&CT7J7@T2_okKi=ck?(+2VE&%tgu?aKaBXQD`YVOP}1eIHmQgXOztC$ zQ3!XV+y=}J<@E>2ho-c?tm7IJaGK^|I*W0*Ll01s_R4*QzE+`Os=_zz+D}$aDAW8n z@AL+*>F`XLD1~D5r8VuT%*=kw3XgFf$gV|updD7RzpxcR;@+s9cu(LoXi!Hwo=?C+DL$_lKHwN!(l3A4hiaw@qrW^%Qquj%O&U(N7#%_TW^2T~XHuTN+Sh3FK1=P-ES$+&aC z7oEr!%_X?lYm+X{jum}bBX7jXoQF}KB*F4LX<5T(STkIIXtTv4d%*yLK#O|v>&MiR zE56eo91C=oAJ?326UKM+s^Z@%d)SeuHGLTePLUE8DCgBsAgz6jwdhBkGg(t{W#)}F z+{KKd%JQMAIdlGAXy33p%zXaS3HN3HJV~SG{5{~9dLT`)Q$&y1Js15vJ~`n{_^6or zBCkDQLaN#^ZcIB|FfxF`TOzsBY&TMmQev3BjkOh!c1SsjDp^T3#oE-_N&3p}ZIRxq zDJD&Lm+2eSdUKswOT|mzP5Jh6_D_M0|HutC-(@zNLIXltvkCU32FnK_>Hd>iP9EhS_zWg^GWDXRBW+1tzeS%iSRz< z&P6atpSi29eCuFnBv6RvdjNzd%lCK*`503OB$f8~d2#4HK!jq)uK)hf{GxRC5 zi?iT7Yx|fYMGWhn`hm-Mz6!S?HOnNUg3$r_htMd?V)l!7a>LH z(A$VN?67&7bIpq@W!xEQ+ly^1>kQ*rPtm}0xoV!Ro+9JyPN3iSRwLf(>Fa+c_2eR$ zPoaQ)=ir;bGa=unyXdDSo8brY^=>({Ltf|Iv#c`B!Mo}+c@_Ll>cX9-K%%%B{x zp6o7Z9oIwfI^UvmE&p;rvvC>^Jtl2FZp0{s1C*X6YV^SUAVm!X1Vs{Arf*$sf(}ed z!*jlgi-Kq`PBANccrtLL_g+>aB56fnijCjvC8+5NmG!5-wb#wgy1tBPrSI9-xvhB= z>a}@tt)plel;!p@iSBO9Qefyc6}kVLx7cpkx>z&VCp&FXY3sn5o8-NGIAY^#)%Rsx zb`RS9y(at{dF7RkzQADb`BDtx_n&>sImRa3^Ka5~a`WCdD6PS5hm+9Bv&9M9_h|IK z-m8nN2Kp~hOZWHRiyZOoJFX-{j^oLUR2F5e>N7#A<_fa zGzhsIoyBP1gdl{i1D=LcSec30QyFvIIEPr+zA13eErA^Nj^SXu4_x>->5IH`V{I<2 zq^+(*#NfOd6~2~)N@CWUVU4gR2z6Aq_Lp7dlbtC;JrxOhGx*=}4A!*fb?(Q?iZ#}$@8Vd7z?woPuVnZZTzfY9Q;#u(C z!VH7U$X$>~_=kA?=Iz?toxmDDQg3x`$QgUtTQjQEK z26H`46Dci%1YHpl#0LamF&4#HktMqMJU2PMZ1I9D)^H#Ly@l$7yMT+`psf4AE*+jJiYJP2> zC@snoad{9_92@i4@l$T))L3Ur7b^KLgMw`FIrk6dyP&^3`jd*ih=V1?WPc-Fo-;bC zavTndh93V2#@tmm36iem;U%L2+12uq+32F+P2>mZi0D=Fie$bD!%0VvRb<19f(GaU z^3?jwzT*QY) zRxW+rd%pzyuzHCjhpV?D1iEdAXjp^wHPM!-d7sRN>6l@)vlfg4R|N0R8Otlth?sSHaO-UDO# zVUSD`HpPKv(@tMJ=%!Qt*bz{3`QAaRn?A7~;iNm}p%(dKhb~#|3&{Cvk~ur%srV)0 z9`aP>y#_UXXNl+c(IJ=q?3jdM)|GF<*5Kpu#{od09YcEqMy`^0Kle60r-F5JK1yDyB85SH558 zhlg(jyo`)Mt@nB+0xSumlnRTIt(~8Ufve(@3AzH=>naxI**gD>AWsS|zEomcdb{0x zW-7iBY@7oYULo(@O=~&Wko8@?m&ea-f4$tJD@ixMrNFwIrNu(0KDz%jb)An>4$I9s zOeV36ru;OLm}AZA5QbFYy->cIDo}W7Fm-RsvFUWv=0b%a;|C){>YKFni81dUGpllW z;~NQMw2d)oNi4hmjDJb5N6OV>`@x4HR3tU*)c>X^`jdy~vd_OjL4GGo6iG4Fu`wfQ zjt)U|3~pfaHjhmkTLmO4a+?Kfw&+g%{Sz!s)XDRV3QcQ4SXr6cE@nWIe8<6O7sg*7 zrM=&o=;?~=bHF9oWVAYjjE2xUI`cy1gElV3=+1W{o z#qi7s>;~iavCY+`e_dy(rr;{scUf-88cL%WzPV`G@w?g=@q+DW?Wa_o@AIx}U#Hv< zL7WIWta2+?5Z;I+B*UQIMRAtnfv;C7ec(FcN!O+!&Dr|HcNC8(qHakMB|G=}_ggHL zFm$y5G}|Ci9s47VldjufzVts=VIRvncrz4!Kp;+99HIYd@4Rb({y%j3%&+*!_&x7r z4Sd0mGf^ZwzdORP$T`f-<{K|r`VpS^W%TeOt;KEl>O~0tzD`~ftrs`Wt`lu%zfQ`R zD+?_kW175&5QUy;cE@_H}~mz)LW zUSU~zJ-m$B3XH>1Se-|m5#*g8E1Te40L`j7r2+VjN)Zg^LYe|ROo$W=)L zs}7zShTW65xSXBtDhjqu{_s_nOle*5oxFj1r5+z4IjAHm{QPWQrcjxpmxu!wvc=!8 zFioWInmaMM4E}@V4)r?y0M^I4NPXI1TdW1Uog!Ka4?N0h1xj9cH!j+rf_8S(5Kuhb9XCG_*^x5dl z&CBoa$+8=9i!#w}Or1d}xhw$MUf(=bPbOrCl__YOhTNYLoc@m&3VHj*Pnn2^9Nac$ zVOihMZ z%xUEhbB?*inyj6nc7}f=ux1fHx@RL;k7hI%Kp0joc8B>!dG3zYN4^Be@MCAXx13%ZmA z%}Q>SD{CQCKX_qE`|=RQnN*I8q57uk3l_1C()l@W@a2#2Z5}awL_UK5F{pT-`QZ!2 zbL-ICU74J>D2Za2vNB_NYIvg4T_?~%aMJ=z%jl!~X4gs+Y)rJz$R zC72e$k~Hs0gd&zd=Dbq5*^wd8GjD|q{-Ve$X=msdm0|INW^>-uc%2R8xw(z@=B>)c-`}cso zDZ@PBV5EI4gB|!Y7*Swn2o}wBQ-Li*567Th6iYQ6C+2mR7DoG!UUI}t>vM@#_PSm) zirP@@{7{4B(Q*NkItwl)abk?wG{V<4-sNQes%RX$p(tG{x4DAbQ(pz0_ZlTN__4tz zA<3=TuPAO(){h@5V&-uXbd8p^Gg8r|Le`OS>C0I9!1qFfr&`f*PqmZMZ=GG#4DKH{-RqNTXQ#y2Hr*0+R_x2+Z7f3;nY!1~!0xs_=iqXDWg0R^P1dHg7o+J9z^K?ft&2 z0;_e;HT9h0Fz%Kl@kZ5g**GnyL>9;iaZe&eBi;N(tq)d_?RPcXPQH3&sf;^zgJz3Q zzVQor?K$;*{3E4=JVQk;v$J+PcKNITL{Y=T@czD5dbDr#HI1w<|M`A|@3BU^^&P(h zYFq2CF`|uyQ|ka+*6&yx&G>kX<9iLPqu=le%;{~W-Yeh^dRg47B^AQ`G_688)uQzf zg?2VVD!?yO68_W!mGCc`KL!w4)uRKjvEZ$=-)fCi`?}-GF4M9RhJrLf$<@{7+p@aWaxiL{_>f)L7F{ZEJV&S;xAvVvUc$q4!v*E`Wk# zGX#Wj@K6xz=;#Vuz07Rt&aN^}8~7#yf+$+!!&kdFH`9MWeQZImLfEqG1i*}TNWb*a z1RNfDgZ5qUtv$bInIwIPP@OLC991zZWg}o1ny52omwh(-|+jiZ))QQ3fV*1%X9-zQsIXoZ$@`#?c$!IDufh}f= zyaLtJa-B(eBzSVp?v1tkK4V5X{r;rjd>xCx4P8C_+8_DyKG%1IO2W|M!eR>`8`sbN z-l^S^d+n@-q0>-nZ#Z42Eev&8ciEC)+`w{uj|6(=cccSOFA1w7Ek=`HKVcRmc^7n7 zF6(o%Hc=sY7WFmiezqnQ^U?C*rM%9gk;_5Q6+tkgg1SCgmFIyD|Onpa)(;>IPX})+dJ?*vg zx4&^Q2ZSi^@J;p!ehj=_QxouJ;RCf9AeuWcmH>ZAnRV+%dCL`h&!uj>kKtF4;u6p@ zMn40saPbFb#VgWX3luRK8-C=Y4F-OnY>Jci&vn{4K5#n0P`A`;a?ICjamC2Ll%Vy~ zJ3#5lY9#p;`dgSxjkfQRpSL<*q1EemE?Y3pL$AG(ls-ldgL4wq(M9_a?-g%(N1*X* z+lD8;*=v^LGjJ;5hNtJh0s#zYXR%5l*>sj~+UmX^MDU{U^Za16PdVjt0qEDu0`H^# zb+9B4IbdcIN+O2@0Y~nZA>S^|MI`eYv-8`RN=l~8QS+R*xr`O7a6X{wseNzZNIg0~ zwG=v|>EFnc+I}_y$nUe1Ui{5TnGeV{$Cfnmm_-30BqtJ`+R_R!1a)(GMC1T6ByH2P z^Te-Xv3;caxFC+}Msd457A`F0EZhrC+~X|OJPKL1BqSs!Pfhb%31QL+qj?G$#lFar zZe2MZ?+HyRTDAKwjMEzt6{iHeUa0t1vh0P-Bw>(4Twf-(>>u?tbP9E9^<5?5<^amG zi)tjj8W!#%ul?J#L2^&NB{c-jBB_cW6bI8_S_vc-vw7TIoh3|jE0>4C_`;?8h~<;9 zWUQsWhZK_n+WTbvn_;UV6(R68c9Ia@#s8!t7?Y9)#-oGG2 z!W^z%|Nc#^z$v|23knU=+Y30B(V$9lhxl@{qtSjVH~Gxwx^<$N?|LhX&BA##4v(#NZd16Qq#=4>E3q%k+7qicd6Ls9K+h;{9{4D=pI9|rwnOS`P=sh z5SLpKM6Xv6SE38%SJEdn>J9j|`VSl7IAN6hNJ_WbiNr>Pw0I;Aaf5-bys<&wMdm>1 zV&7X2;ESf21H%z$-ASFHnH5Pq8}7aoaIIeav7@|H>^=}Y5Yw1s3u-UDNUtTqdf7lR z^nDLzUwelF>p0U)CeLZopY{2EozN5HP3Lz9@T5mO|Fg}L>@-t{tJ0YLkEh5}JSjX! zcP)P2&4*pFQtYR*;4a}#z$?exnK|8&e=eqWe=C{f85F7LTbvd_f~j_f#rY8FYN+U) z1z!S2AMd#anM$(Q5lZeJBdb*p(Nd7voxE)jCa$PvGQDY1y=`4SGlzP^k62gVwdBi! zB?h8A$)!Xi6)o0+Tb=F%qcgm)12~9w!{nItCz?M!Y&n8pN#4?IdXV<$OSk@UmwW{!pJ z^UjQFRbD*xb8RtU-a>lZN9m!jl{6e^t=YZ3c&g+aYR^Bdsx?I);OrbTp4-}_8ea40 z{xv(uo{ab3Hfe3pXJe=)3X0ab(9iCFWR~a zo-R5E$@wT1+M(i}KekB!Wcq^(@r!>?mX8w11py6)31X;~aUYuxtz1H8YVf8=nGg}#6f;9m27{H&=J!8e6c-&E%sr}zK>IUKMwkql3SSXR=1H?NT;+P zh5d%#KXYNV_MyTdGoTDfWgySRf&WjEyUhCXQjdoy5ix0U-7<}c5LWC}Lt_amx-8Cam_ortcbjZKrF4`~B%S{wY5d@r6Ju#^JqGOrH0DfM86 zk{lEDej(UretlJ9e$j55+WK!W%>S;hNk-xOeh>3KKE9ShE_K{ab?-KMqKUH#>~6^g zZ27#mSMF0UpZDpnE&^2&XDBV#_BYapg33qeA}1^kp-gL+L&b~|ysW<Xt@e;_X_o927Ex`DK{ z*Ud=k&0EG9EaUQaYnT^&TtW&hILVpbtEn}6DudDR3LbUcy|njVLnFgyS9i`t8lRgA zRkHeh5t%lgvD5ebV%&5D#{b(AMk64nizE~pb|zttvf8x2Ze8TQo}T%gKl@$KLYxu@ zPnH{&Wz+Y7ail>tIHVoVjT2JY*kOY4748YKQq*5V5!K|LYg8#K`l87EFyJQMp z!%~Hqu3>~k{8Vchdnyn-{&tVj3_%x&ePHWadAm!9ePMeS`w4-*&w48fh!368>rB!6 zVcb1vJha?j4%*g8=2G-p`6N)$_|P6EM;lGgyPn$D*&+aYMwfW%2>!m6xV*O1A+e$X z7w7oj5x%`3^8VxbI_V1&Qv2(#mka2L#`B{6UxV|Ioi*RtY$F$lf{saH)mYl@XRPnL zG;t<$OKr%v%g+Q@nz}C48Bo=@59_uwgH7io`Nyo&;82OK@WU}aPC&Ex>UQveVDnMH z)q%9uZmc`o3g3s4a3UFue@_)Z-~}&09vZ2_^1|ApjYBQXH@P?fhwRcO9CljWdkJp$ zBGJ`@__Nu=5B+mIF5gq7e+3kNax!3GZ zP?XxXn&EnMnh}ZTyyKqWnLe3)nrCl^*KiZzvAnV}YQ4`Dne0QURj5W>mIfI15IaNs ze@wk)S6tDetc|-vaCdhCG#)HSXb4GghY*4_+PG_Q8i&R;xVsY?_u%gCt~dAYv(Nkf zfc0UGHO88wYF0f3%-nK@j}ggCN%;NXU1Z{n3$3hWf@s|{;he%rx$l~LK6;f(Y_h%* zUQOG&U<1AklTJftk^(CK{X+U( zN({FMnMZi5#?@VzuEr;PgD$}>j)mC|JZ%wlOWk-7Q|zwiKH+F_R4IT6tDx9emugY? z-cDG7Vu#1kWF25o#w5ii5b?ZQvdJxr<(>_ekT=GG!MUoDRI?wBa=FTjkNa!FfvAma zFLhjGhy5-IX*`(S7w3lz-jzgH8|l!s;e8gY0f-HSuhg)BJk)1-&@4pS-f1$aekXSbi_9~t~$?G zUN}vJ^W__zF&g4;UD};I|BygmavbM3{&8_C0XVbGm!|S#KRmgw2P%BvjuM9WVA*(? zpIN#Wu92vC0hIcj+sp>Qv}TW0OFEI|iqr>x+Q7_8?73ueeJt_wvo4zKxl zM!#hq4<=dl^t~Lt>~N7avZKmAf2*t|jhn({&mztIxL~1fcz`y0QO5(!*4awp$M(;M zyv-!N1X=WIT}i+5{kM!Hj3&L$fy(dAAQFr+wWs-R;RXKF^K^Gf+ddwo2w&>}wE~kY z>ELbIJ06-iC9~*g*KGuf@8nCD$yU@};?{T0HBs~NK#=h;0PzH&F4SkxZ-&A>M2 zkx*?cCkp5+g|aX0vloB%amHf-*$cOuzBCbLp*G7pOsI~pdt#i6?Q_(jKWJO9(~(P- zV3XYWLE51;ThVWD#vguTc^ro0oNy-}K8uw6rJ1dL*e~6Vsi|yo=WOIm=!_?1Yzlf0 z;)@xRi>jP@_fXKO74mY7OcZB|5tH*y*JdezFJ&&Tp;v=Gc#CftkbQ#Aa?WiV{=S-J z1&-IA_|3ru9=<>kC5S{^ni!p8HOF#;fh)8od6C?TxU5TA3bDdz-b^fIaW|h>pHfk$ zP&+tzwt$NGMZ`DIx1vO|<~~OJa>&i%ZxQEdjsA}zx1ek8F{2OYil_Cm+BlB(5@`@( zJTi@t6NbpRhu6~A7PlXd&jX2gFYnLe(3*>u!=aaXJ~$x>mXtr>bgXXTybysn>)|f> zAN#v`C_n#}&7bt$9I+iC`5O2Y_tJ)yQ>emg!176dDXhj;lDbDHx0mAAcmz5Of;C6PvmQ0qM0tb`OqeS>t*q+ zwH8mqCpDX26$KSkSRjL%zubU!6kKcB+++A~u4-9yVs#juPiRP69>9+i~ zOIvDrKDHxO+$C0QcK$Zn8hk>+czZecH@B#x3y|^|w3qQkbhH}`U8<3UW?z~~@d3OR{6kGFXG-!2frxJ4zmrURPF!f6j_wcLi zT=I({B|q~ABagK$r>lCYK($Y0R#2ncHlt46)!5xN+LgC^A@!}T|8c50MR;=GWEqFKoa)r9agrO($ekgi zt3vjt6b97OhOms3qAkO^gsC{vnKZ&P*(N>_oQ1V$`LfdSNU>(gtWKX$#Dh+FH_#a6J}WQ(6=EU+po8w7U}PO(P`n zVi|swcxe)#bSBn~_a*0R&f|>lzt_RhK2=J}E77PiAn9|k<31O#`_=0+w5_<8$RrQJ zSR&LLD0&^W)19(5chN|*5S`SU^dEK!;hW0vB4TnI)ux@Gx~lLa)+B+2M>O@TQ(Klh z!{L&O;(YDpCHxRoL(Oy>W?#H^e?GUQNaIbaFC0VD3x~1xUTf*m1~Kq4Ut-yN)lhO_ z(A@dvIhEgMnB^c)IGU%a0PA9cbp&yzxOE2}xO{M5+z9w4Sa^t*Y#5^~;g?x5hUYqW z#>Zx0aPzb$#tGM!6@GDKZ#WiICuT1+KO{^=M_w%9sFgI!ip*_h7Co6#9WF+&@d4|B zL&P`fp15Z1WJY5i%5Y<#efUcgVK*}T)|IsNoXn4jc|9}(!FZy(TGd-!C>GV=oFpVv zA?gi4>++*7C(!RltiHcP|}p_=a3Wvf%muW}i0)Rqz(MS=FX zX6_jYUDsivfo@)qQHH3uL=*hoN;qY2dyoH_hWKs(}MLmd zlTA}1%4s%-+okhfNcAPP52CE@@(F2jEPtV<`n>rNI2_d-QTdQXD+L$nG6hFXFSJgG z3K?Lr99JIK7hA)rm>pENvw@MD9SxyvQq~mBt?`6kY#BKcsb$jL0~AwQP&j{4f(87^ zA~?8TxIMfBQH8=xuz@bdWO9QI-&d3xx9qXSL|3F!A@r+?9{KPK5qXq4^_&y|Y6j5j z98`~jua-$S6roa8o>f>Fd8+QphKKX6@xJ;;LTYaK4BA10Pofd)XxLTTiK?jz8Hwm? zD)rrDA>EcLTHM||oB#y+6M^UO(7N^5izH+o2j0uEn%Y3^*DicIj{pSwu7z(qk^Y{) z5lVWjFxJ+uf?oT9Dyccq@gWMQm@G$8o zBT2Dfy79Xyi`U15uY(BTJzbj*a0|}c_1?<9H_!=~*C###Vql3STZFA^(7c!|U*AQDHADV7Qgdsbt z{W=`p(`E)gElb=d>3~Mx?Rr6Vmab~#iJ3Bmk+Q@V=-GJ?b_ zvTZ%6{0~}#G;`59h)}Xzx{A)Wpx(c{Y7<^m_YziqN_}pNzb&(YpTGT)h1uChVL`bn zuOO{~y7%G!nWLFdFJprh?tvcb;OO$lplA*fptM5CG|L`2#lPm*;IiH7NQRwFD`Wc& zgP*oS2d}_k;a8Ge#S}ZwcKZzjP_t;L;^rWICS63G=RdeR2+ zUisi^JJ{AbP}u=2o)@!!Q&&J_vWBehlby7i=-}5wx#~~jc8%wA3G?C7hQO*r>Yk19 zdVdFUx=O1h$FeMiZ*eZ!BX~6!mZx)m@RyYFTnwvch*8-s*Cd{%)x>nprZ>&xRHcUw z=;n@$kmlHhmpbNaG)>BHTI+sLO3)g{Rd+LP&WBH)`Tirgwcj5cdCM^%RL6Q0##Z%U zzGf~Y?)jLoW&7Z@il7*{HE}aq@0tejoqgzdSbX#l9Yus}Pgx1%l)dZ!uy}EoGwA?! z-G^_xJ5j!4H%opk)AWHOZ2Ng9Dk7^7LeK)H#c^MZHOZtkk6+=1;yj+3H(b-y)~(Nl zHKy?W=ZyYWZU&;EPT;G|2fU`jVrX7U^cwAqHiA}eCyRs^SDx;)@5hSv&UxHS4V^z; z^O(_*_~u&Y3U6rcE+49YAa-(cY1{q&0Tnz(^>_S`jU?FKjOVlePrZ_6H~~y!SDG-; zqmof(7sqo#&XlYXU}Uhwaob_i_`pNqm&lU9oUx%`ufyq{#af3?yZ2uE-O}GuEvNVj z=VG%z68B;_6#bEG$#;?zGl^21&sFz%4hCzkq#d=Y8;@g_XVtCk+m9;xZy0B9$G9BU zkre*}?m|SZvf_N1wH(iUK^3<1c?@+(;qkp>Tf>r%+h?55tG)eL;bk_dmVu*f*+|&_ zK)rUBt(kA1Z*81K|HAsjcPN1V;UB8B9jjN3);}kD!w6u@oUT^$l~K(Q`myEn zQncaLd4^jQy$>Qtn(mCVF|yHl2J{H3PB)A+eeJIyD za$!1G**RTd)IMd{>Q+r9Hl|!YNG^yoq%gnkC`jr3jqlp>EJl*z?CeJd$fNC7!QRQi z7eL`zPSM37F!Q0KXiKkCs`m<->C+bd|7!OCJ{+#2pX8L6QcbXr?>5A-jyqD7e}1Gmza1$j40?G9B^{+;orPsp^)#Y(m6X-#o@_{iOrB<=VBPrgR*1fNHpV5K*?6{1`02! zS*&{AF_G+}yc*{G>ZILref3vQ9oK{jkA72 z$9qW>H>|UJ)pf4c6aQQ_HOYRibT5_FmA9oxl|C4>hdS`ASPnJZEZwUpgXKt`U2YZK z)eT-?neJzr(Ebo9YF@1wC)5_;NdUS}sn1C37cpUKS0g+h<94y41AZI7GJLK*_jiMK zicW=QM9Vl!hKdA_XiZQuNSqIeR@mt9@QyR)!)qAJreads;uRFaL%xe7-jzsJhzs9ecw6Zr)YO9%cA|)*%0%3Q* zzheK`chWOR#sP1REr&#LhV`q`rgJ1Zm$Vt-DcXb3acyObX$hz!3>G5 zmClAdR|^4{3I-Td!YmdMlwo(`vihxxfpC^s?l^LhOetPybLI!!`~IW`-OfkY^Y3N{ zP0t14!q3g_7m3>eTIa%z3feg5FPfa!Pq+LKO^i9@Mb?@cv8lPmLe1d={=y-5Fg3IK zF}UaSKC*?jdz0%E0Dty%48;0m`oMsS+5r(f`V&a4J3kHw(v5+sNqG=M@9*@TDr1Mt zpaw7632x{9!kaEBkDr@=R2v1X0g8k zE=j42IH9XEw);$3RE>FIzl(&l;Vk1e5-HCN9Z?yiv%Xx5ZWgo+kkwK==ZC*UIL6&t zF(PXNQ9TlxwFn1r$xioV;Ch_?23Oe#JQo4slW=d@l#&`}XkHSV2TQrXu5H(mw{Sc; zdlEbm9nIX*tzmln7RspaEWKrv@`B1`d`Hc^Em}8cJAlNh0IeO&84bAg<0^+dhTq8~B~aala=Q|(VDdU3G@l`rrmmv_q`7nT-=h%P@g}-zZ)k+TwnqM_&mVs{ zv1-lAbvjA7oR;I-a>ZeIo{E6F6A|ij!&GJOg-$(`?(d(gx{L&$S&ZB*37*1dILOLX zc7~z5Aqk^@-`h(iU}G&u_!!P$XR20Jpx3h_jOO5ya4>zTAi)7Ju zS*jByv{sp%=SdzP=5k~v9I6}&{ds*~45^N;CTV?M+UH)6tR8ExQyTj5l)$0L`BKAY z_VEe?{r?Z8Ip9xYjiV}ge-q<#xN9lwbJ!mhv-A=gvvfrjt$Q;+nR7MWRaPx)=2yDi z>d-}2-AZBFCcD8YV6Ar!#S>F!sk69uU`m4UGBp^<$-2S8tmS42Cf4B$Ga)5i_`i_uy>oIl=7Oy9U&rHv^q&rPQ{ za3uLi{QIl>O1Rlmn{4u)O$s+XXoXWi_n-{_Em^<8;Y^IbxqqX1bGk0_{YqHq!J_C| z3PL+1^!0QD-&3Q2Ln%-E|J98e3DX`nbRVw|oD15$ZZqtCIwQM5whwMtwGeG|QED>e z#y%k7?=dql*(Xp<>C%jQ8rM;i)sU8!yN!r~(HC>Q%!NA$SSU4V+m9Nm60+>qP?to>!BgjV`8lD)oIW5!^w-csQ&_4MU*>ZSLXdV>{NA6BF}>nX-UC3z!e^8DxuAF zzQJfu@!h##;sgajkysFo=wx_xKjZs|dpM#!*0qG>{^Ywxht1lhp&I_LA#>4zvGC1h zkom`PdO7Uj&&W##r0@jKfBBBL7tU%S$v?96vo}(@!mH_AwqPT1I$%2P-f@u(df_Db zhY2AI%L27V$;>LGEN?cOh#f8ho)^{g738tjV_L=6DML<#1;PEQd4C@(SFckro-{X1SzqsxdI* ziX{Q~PFZL{snF3vAVZyA>=FyaiVa;v=O!2Zi3%WMaHOkIjQrpe zvm8w*h%FcSfbKHxCgN7x(4F)tNd>&<#5)_zge{S8Y0e!O1MgX}cW#j*alhsIyB;jU zm3pF6KZes=Xg`44DpbS$qCd(KyGfTS#;KS^6Be$Wo3nuHf$J2EOJO4@lDi*p%!#$I z<$bOeCigOeruIxxp_7;I#Y8vqZj2whHpc*U-~OlVs5+KRsfsg~AferBqBwXKlSmOybXo`NMaRP*)Wbe{7D= zT0;G(0hh%7wdLXPPQ||oPD@DqFNgUC>bz-Q8l22Y%vV+nqP5h>WI}8fPkV7zyMnQ| zg`)VG<;tDpKEL5xxzXd4xb8Q!Ka5&YtxzLYEinCg8=FmnOM8Fcw zRV#7q6@8L%kK?xj55ZZalmbl7y&xg!X=_YSbpLk2XHq5ChVfBFa zP_Gp3@x{}b*UxtI(I-VG-I!7qU;f1jU$P?-6BOOKIERTm)R|HR!@G$jm%fwH=by?6 zIjIonvh>s%x^t}0#ITIb8(sWr$s1#pGjQwbqGRFGmOKl{5>DVDoDs^F7mptq6a!SA zScB)$d7y+#a8{0h(3|`=T~22Ut>*FNQVFa{>+QRJjn4(#j)#a%+~I;ZC9B^^6qw^N zeZr7HRBQ{k$Ak$EPith1=?&NE1CTEslb(}K<}McteGXw>?}XRGJ24NHl)b;c;NfR% z2i7F=;i1R# z3GAXf4CjM*V2UVL^1FvE?`JpI%}!7)24}8%FH%c-#~bXGMuv`MwNFIX9vDN$cWmr< z-xqeiml{A)yistLv}nTn<1Kg1IwHu+-av7e4CXx$rp}Dn zS#nDo_!1$>Pxm-A?NtAcw9;-^gz{zozGr1C)b6A4b~ZD3B=?oSvn%gyuyJ@(85Ym| z-sw7>58+Y6sB1x>XmLravfjS)4(he_e0@-x(bA~f5?}4N#dGt$o5;xcs`QUzbSkL^ z))qP(OR*=FJ*mCNShr(u@Z2t$_PgVTC`W$xL{{^0+{v28?oA259{T15-J ztu4hu2#fqI@=bb%esXBZPcjsm0bw8aj9{rVNLIK^>y1)^2rcyUO4Vx^)ezUQvg#2f z$BaYLkv-Lkd6rQ4kmzsP&gXo({ARL)$RUKwOj_Hu0@gYO`3U6S(qVXh)3j7VO^@YY z6Ejg`9X=cS09Pn{-(e&cnP(NV`XmYYKva4mX_+f74$k=U4Y7=+>s2dz&zIq) zII`#9V*Ec|{_C2PpZ|-I?A-JF$C=JkaaJ7UM_cF&d6lQStX1)nNl^xhBThkNoSS7$ z1RtJlZ`>hIW5XgMapq`4gW1PrZJps$4(Q5h(v)bP{})ALsvW&YnQ4&gpnB#Qd{i`f zgHW28ZIsNHza>xllu0fX{HdBnNrc7cGw8(~5$~29GbS!@JEMRWVG51eCY<;T)e5$& zdo=wf&X|0u&s4@{Gsa|@#cLU=rc`sh<*$5AkQ!9pkV5y?i-joHz10)1C9g5Y>AFk1 zH8W3#DNFDhrQ-YkaVp>apWq?g3Wd)wRC3r~|Eb?M?<3|vnv{Gv5>wxaX>h@Sw{+>a zQzgoK3tgn3r0W>kCKi7$>ag1rjCrz9%cA4pb2zfl;EJUPFhc|`9zf)<7Z1&k`f2MA zjUs+&K;720i>-^zOeVw_B~LMdUmxZ8pK zPsd1g`oHFyxuYrq<{nF@r?UqQMt%xYQ1WrPY}^n3yhH<06-U#Q0jbKp^&xp6RFRH3 z^@>38E#fH)N(4cA{t!oT7}pINrJrTnpLtFe;`6d)fREE2sGmQ7$M>%Vs6L59t|5oz zM!e6(;q&)It&&xXfSUMFep% zbG0FQxg`Utu>a^FWX1i-cw}5Tk0yp+&XrjJ!$+@qORmeI8<0LLt**wfYyKNNsZDq~ z9l%^0;4m1HUZtC_n#Ib=8#dXmU0rvf2%S%twy!oyZ14w8kZ{6HlK~gwv$R zo!~#9a?c^4go%9%b4Wsz%{W$^LiKO_WBtX2LTJ|n)<6;eQb;qpR1g(Fe(-LCTw~}fsouRscVI*dp6b!??RJx5 zYnQs!b{!Y-c>Nb(72my$70QABJDSsJYE5ST4VA89dn(NvdA-|`p^ldKe}@E!WX&%4 zvVv>N8HNirlZR=5u&~V9Rn0pW^ep-PkGw_`u`J74##v( zLGlof9^~}R?Es~J`zZf5t8(@;%xvvfJSPk#eP!@TPv^cZ{f$VjE-BkHFZ_D0W%xAD z;*A5U=|V^KkKne+;|@D;gr4Q#iqA}(dZIz=`k{&9WTi9JMYRTAXZNO; z%h|tO$|d{PG5dcQh#O+eg|VIa2XYEH#GM6L(<0BKw=a!^mmIOz=@}<%BFj@Z>u1hYKX|QVO~y=3w0b78Pcr;i#Xmd zebufH^(rSX)^jyW&-Ac5&me0pBq+Da)haDb3jrTAr}JuY>oP#9Q21KVeH|Ecb~a*} zhSOVWm0!sr?(lw$#=$qWO$yj@=0Bcg`Dfvb-lwsbrt*K?3yM8Bh1R#g!M{>US?fsriFmP}EXZ1IGgkSHWzteHXY7fO%Dvk6&w8M8a7-ByaY; z8<>pK|FaT**jh`3jHCAcZ>q!ZSU@XxNwSs)*=ow#fv0)61=kH3NI)cfE75IwCd>QT8Ct&u=-_UAT z>fl9m76B7$e-rm>i5bW|S zjl!Lh5V#{t5?$w0z^d5d7$7F<=&m`QM{5bwO%A30p0JXkuVwCHvtpjw!w0O+-m0!_ zsH1MtA}}S`fCC1)jt9PcGysFyneER5$dD9UoEE=rB8wvF<;k!N zs;BZ*wdHEO{vzr8X}_suW_XU=GM zw3_V%s#w%yBlsMB;g`z{ptujuerx{zO0Tv}n7Fu;fdCofPlSt!H<|!bdHf9RTR*;f z8XAfbli4{_MFU@h!w4T5v+`wyABPM#qqUsTF%fF+NbC%X{_OvjCAJ|p`@OFT% z6)Y^iAI)ggMX(YE^f%zM^rhuP2M|FH)e-+B;_M867L0PU+KPCV_aw?{vqI-Z2?{tk3Z;V_tyVPdL(ro{yllk~ZRPO05#qlx}i z6E+d6_5~c5!9(xu9eZJL1CZE0&DHR{7h~K%)H`u4MN)N8_VG(|TtJ`iFOYVJckzw3 z*yc$Lrt%~<(4ARv>W5upRO#JzaGC)f;U}Pb)k|tea@HSKzuHcriLJhKLo?yx+?8e# z9zf9DE$Wc6u{P=f>qnMMxl3>{uEp=gwm3n=!(PUoT59>8Qj2(3KZ`o$j;u0V!*4+IAOhK?KD7@S*@F4+K@;ARl@ zfZO6I(jiEYHH(M6Q?5fJ`nBAhWb0=_nT|o5l;U3V4=rff>rxRGu-j=YBML22ysou) zoRUzaa`YafsNL+I%}V0HE|mYJFM7+L)22uqcH85k@oFXM2|g+3IBCCIwLa7LrAY6$ zUI?caL)lT_34pvtB*=GAd+hd2obts~ff$n^(=8>_`yt$^7 zib1DHj$j>k7GyjFH;bTMaSf1*yC3CXsSwTNqH_PFf6%SLu7=^?E2R|_h)2a=FO}~#KAH7hk`+hm`%lNd(O*3oDMJQ&p|RY=MJQiEfL#g$P&6i?aHw{i?4S7{$b$Q~=A| zhDh!kG?h&J6zj%(l zx-E!(xpRJby_73th`-^WZK6y9T%E``pufr|+f>Y&1s%C_!`Z4n&fXaj`PjSLf9Z}t z)R)dx)Yd-zgPUK=X9%NeAJpbym4U$|C)?!n!8)>m)=p${bv*2q0bBKe^GJ1KbXCcQF!Yr7z3cH@U2=sH}&0Rlfd-*gM&Iwh(g# zVP(#hAo%=7VOH;G!%OqcPKY3!my|Rnf;etBtA%*~SX?t{ll!TaZv8xqatxl7c=Z4* zb@_K>*;kE=aJeb`yF~@}ZILn(s%JhcvUR!YV%z)M8&K6O)wwSA#!lB?emwX>5^7Dthi>_)(cPK42u?DW3UWY~KWe?0T-oLahwx3oO9&qe(PrBSq&VqFj zhpZW3e;Oz(&b*Sq@MFiegHO#%6@CiVN-7Xpbt-GT!NRqHS&8K@*5@u*;nKxV651VC zZCH4Hz+F}Exm};%r^7?lrkSZJ)1U$3^S7OWhQE<`o{?KyO|9JgU9~*(=Jsv@f`Q<1 zv1ti!XnIuHIUW8bD&_^Ux?Eo<96kDH&e)HVc&M2Ecmx4(zmyE=!gA3ttMHWr2qW>< z@aW;`66WWL!%B@jxg{j#z^l#IFUz+Jd)s$Ul|>#nfgn!lhGU<@>(f2=!} z{rfwDKlV4rU6D@=d<3GcoxaqiTHEB4sv8Rj`gTq1f+sQ#}GThW4W*~g!#%R(fNyx!915Z5 zT_j$5g*mvd2IQ}FB$r>Gr}~vRXm(FDwQ!eM3^vk_XuC?2X)1%$FCIYRtQ9@`H#4qA zYI5`&PXEwE5vBtg>wRC-oTa1vE=RYmM9&lM`h&H4h_9xK2109O`gFc(=XME!K%3JH ze`@20qLJcktb&(IV9+UXdh^m+? zrhHWas~3x7$13;@9!#)Ow%>;bvPd??!Y zjq!$$=gL~hK9;|2AM}h9Ra}l|xi^8F6rci`Qo>@}N^6YXZ1K!k#toXU&tm~`UDPSr z$F4qvsLa9NOc>kGi>9Uicvt!+o$-jp^zZ%0T2#OhH=>lzYQHtV8#L+$y|z>TeVr9M zYZw>({j%=&Ko)H^_vwJgtSp-+5Cz(b_ijtLMZLHFC5O$sZ+Em>badeLw=Vt)dAp9- zXmH*?N{UBIPvM(%9qY&I_0QhQYm#$W*jo%PEdbxco-dCigrJLSGFaT<0NIOpjHmD% zXIOffnPO_a6Q_Rb#Sq6y{oHAvn@>35^_UI6um9^8+`~tK7r;~GzRSxL%rujk1r_%q z_wGa(s{*F7h9{L(7*oNVx$$C2;L^5cfcvz42TR4hKSPP#GW!ory7RYampCeR9(Dtw zEBQ;AM~%NCp?R!Nn14q9T8_q-LEdZ#huZG;DegN$5GC68*x{$zclXN?KLy&){BVO! zWJ@)cW#~U~pRr=Bi*1IqIZTpXX8I-Czr@+UjA3KE{*}W9gC_b5Jlc~H~?s) zUNqUtt^e=ZpYOdT| z3LnsmaAoCCC&;}lBkFJe1U}h%Th|&iH?dh2l;#M$q{6Fpmn!{85cG@a{C=FRE33@h zp2|6^?$P7t?k}^lwICNB$HPM4=F1A1<)pukwrj{%BuME4g$y~f5aI)^v6dPMIA~?n>>wtpV-M`F z`?m^``9Lw}B^&4$B#}Q!zHK)>JysJddpbmD38uGH%&`JJGBG^0_l3(Kr)*YMkDsCU zlVWGhs(h+fg8Qt~M?m|m_%d8CzbWh9%J4PX6QH?22~=$BD*%zNQ{rx&d+I8m*)A0AV*ck6OFD5B3m^a2JfsZ%1X0rotJtfQ8zKg)MD}3> zxNr_`?&5mxR3p$9nGfQcTa5^;^NH#;jmN4-(*ntg6&&V zn0$~y{v#X~3^Zn-%A%0R` z5=4Q|BzE?a{u^TlB8g<@KzYxH<;d|^vlv2QP3*1)ipyVC!uLFs8%!xAdWzZcI@r|%w=Wngv&sP!Ztw6AZfxd5L(!wK?M21SXp8d-13PdE?< z;UmAMqc4O=4RLngr~xWz@h?8=o3o}6_I`Xfepyd_>$<{T4zJ-c6vQR9&f%kZKfvLZ zC|**)505cjFdvL0FM6?UZ=UUJI23a>Kk9eIJ{Y1@b1e_aVe;n|xEfW%u0N%Q79N zLyG%D$pB0vi%NYcwB6O4bN?+k;CjU;^^kosug~?sSwXWI;cv^cKqO8;ZqH^aa&gDQ z2+wiC=HvE9M`}a`&*P!?TIF`|lkp=t&P%9AklnseT#nUtSf2PpDbZjnoVK2y65yxD z!Rsbg69sc76J*M8N~>zRKRpD_>b&45hB#e8#DhK&oZkeGFK5KB(ySYwF7)R=d94ZQ zN;g%bs^0LVykH%1(vf1!crs{kq`3Pf<4f*~_oL1A(O5P5#%Xa{*7lcEv6E?_ zlSs~=Fk|L$7XJ1g*(DwsxwEO@aO{laN!Z}IO@WgUgEUA>sFef<$nd(ZYu zzd&!Z$ih7;(D>=3s|Dq|sxh9c?t}LA%aUbGk#7R^LGa{S)Uc4N2?1xy_Y&7As)BLzDI0VZ3v_Vq>Dnb_xY%NOI@w5$St8zp*%>W5n8$ag){c^^3My3O zy(JxLu-H6^f*kJ?zfSHqE|^Mqgh%G>^@PZb-;ZhYJjx>~9ngtuWReY+82y#Pf+M5P zT|XaB0ZJ5E5(zkDAVJOG)?42B6NGbiA>6M|p#D;u?4MT&1Fif$U~I8dTkC#mz}TP&TVvB$k&jPsj(=D2lWC-ZMGy z5A^guFpnoh=@LncV}mZn^ImJ;$1gt!4jANJo#zVJ{JgY^-P{eI6WYh*Le2W5ImZx%w+9^VgOJILZbgec-OUU8=q;D&$f{Hyg?QIbAEu{DHO zd4{J-<+Q=Fk^f6W7mwap6dV}oHCzF|xxcp^Nhmh-I)jmJ1DWWHt4@$OQyX!1zY8jU z2ebFAv^S^r(q4r4h%%DAAgl7SW&LjL37Q*(`MAp9uF#fEsx(-gbGT2euU=&bw6tq|J~2t^3Ko{(ISSbB(@t-gK^ zVn3U{ovdIt@`ryjYvPCUy)zE~gAVgh`^(Sp!OGg^smyHZBWW*ohAkyrEH?Q8sf7@c z?%Fq5iHUQug7Ue0I~BJ`4a4Q#{EM;g?4Y6kOGk&G<^q2F##Q)Fx|ITR*jy^B!)`$p z#?KIbhE+ZocC6T?1%;YT&`$-4lFQGVu>xqAw$d8bO}x30WBX+8MOee;W_##3yD5+C zioph#wq8sNp4ET4J%2v*%n&(sdu4XT?Qdq6re@MEwq7pRGI?< z5B@-od5e`%qw6k5TkKN9loqenb=-6m_{1TVV-95*F4c$&9FF*`G*$Q=Y%%1`DywCl zAKsfSoty_hZ+~Li^(CLH!@k$}+!rV8vfD-Hqr-?(AxZ}?GHWYYYFMPEr|E}glz=TA z`}+rpmO1)kg{RVG+H*=cJqf7mzoqU29V^_b znrbJM9xrOeZGb(@n?v^QWudU!P^b^0gl!f6Gr74;Q-jM;!U3n}FwwUEQ6TR>nO*dX zg4x&Pm7<`ZAh5%3LC_ZG?f18YIVe3gj9X#Y^qpI|iXNO~52g{mkV646qYp8c`r9-N zfz5&7TV~)gQs}@B-S2p^)Y*eP77P|Lg^bv51=T|`qIuY~Z$C|oW9UD$tZEJQ$n963 z;Ast_IeBdcC?XeTIBo`sLJE%(_fflWN+8^@b{No5FSG+A(P!h3=baq@&;5dDRejIo zLv-RF`#~%J7!lEZI#`{Q&vl)F*M`?FaQ7%8gGf+?1}P(ZTArxJFvF1x*WJ8B)v>sFC^5F&DZrI#%4)$64+WR!zpvmT%9SU_EIy&2h{W7C0jY>(P?zxKc9 zVI!sVoB<5;Nd=>G2I^iE>=!P=Zx%m_(M0__YOb! zF7gxG>}rdi!dbpNYEnL*zQDOycjl@|K_Ae1-8zmU=X!xfH!HjwPsdf&TF*u6kHYb8 z&-VWji{oUd-}m2wn4#7QwLvVKs z?lKI6`!Kj)zGt6v_U+%$Pp_`Es@~F^Qn6Q=R!9**KRssCP0!q6O`O-f!Y%#&4Waf<4tOH)IA!5=O?< zlE`QZcv$vxN%Fhr@ecO~UTERP1%9kI!xWpx*N&rS@U3!gef zXN3zT0HBB)aQ|N8<2AefOq@ynJU9zhSu==#VK-?v@+on%=tV?)*+ole&;yo>_xjV- zg;Ku=p+$52_7t*iWm5>toIFp}j`tzrNJfvIrjg;xj_-DTHF^TSW}!CU8JPX7*LzLP zd~@F-tYfhiJ!6kR2kh1;?aYnAk-g%zu3++aO!Ag7DoBgV8O?2ls7)w;dKOe*AL+n> zg?FK*@0NrB!R?|wbk&L<^Sdl^P^c-S$MM|w?fGK|7%#kCxIw7C| ztp=N-t?l4eNRUT-dBA^p=jDI>re91>NS4!Ljb6y2XKdB0=no$0g$G9I(}($61l|+^ z?wUx&U;3}e{$ZR%V?7&)0mfeTVKk%?K-_fjGEmohc%{-_7^m#_8pmGAVD0%SIvCBNo8H=v;+#q8X}>l>g? zIwY1v_iV@9gn2><*k6g)kSWu$a7?)Se{nXY$P}T`GIjEMTs5flW$ci@a0d+U&5>p0 z=R>d)dxTZ0NXJG2y-fwO!{OwR@DLHLisG1dfDFyVlrUlSRr7%w93qjsItrFSt#_G33ApcPJ5fGstIeO1%3pjCm{&3MK}aOtnvoQVk5ZKIG%K{MmH3Tk5s z(-7!%1-dc>jDJW+NJS>`hDs6R28ilJUC%MRg~7cs4g@j#sZ|K2FdL@pFpL$tKtGr4 zT3Aub$3~9?&`XE=@+-f_VHpdCATgep<>JvcB)jv(KmTT#OdA{xeLx=Ayy>*ESZSx- zro8_V<qyovv2Pq6Br|ZEb`Q;vQA>$HKN(4@6Td$VS`UQ&Bt3tJb9A4a_&D2w zgNCR0dyGLpgR)BoDi;cI=uVv6HYSr#@g_qz*u+ z|7vGfn8XnbqWhhK(XY*ROAaH60tlf5BYh-JI2f9}eESdQSR{)?qS9n@bMs}}pS<(V z5EytTn)uCUOp=GhpOz zR?|sij8_X6Csy#NoBsphygQBWMeU~BFBzf5Dg?;aqPT9!Hu75BJ}c`mKbf^sxtwCM z@zH1Fkdb{oZ_Vdy&!tJ&=e%jzH281e&bV@3)r4Yn1ya`afx<8JMF8*#FXxJ~^N|~O z`aURl6X3jdEetq*KCcVBvklr@#h-bgIVD&hrsY#$sc#WEa{J%qZ~;I1WM{5OxENC1 zG2!c%PrSW<`m(=E?3w=z&u2iR-?6vTl;;^%Ynat9_08Mm%=mM#neW*@7z*!+`-76H z8g)2!_dIT+SU~_bLMVpH&1^Yj#zw@WkbtNH^|X09--X@Ow|+BV?`wzei?08}p2OLD zzJ-&IMIUXy%v6sHeTHl7+>YP?pk7&XDo!P?t;UpFlgwm;wjWU$ruY?nUz2(?{u_hD zzxDet$If9?Ym)DaBrrG%mOi&wcMEO91@1&XMx1DR;MZl(|MU$(T|=6)ALi4xLa81H z>`LE&-s{Nj3Gg)nCUu5Sn4)EyMgwzU#s}wLlHAaZTgtHlk-D<_=G^?hyWJv3?Rq#I zSd{%^6PzMn)EAbOC*e>$o?5E8Ky!QW2anu*I3^Alz8+dUQ8G{kUzyz-bdzl?czBO>Hv^8uwcju-=tOFGc1}l;~8_S z@QnT~>vhuk2V0~+(YO5fxjQa(@?r0%K7zwb^+qaA)THlhLa5YyuS9czDBGC~=Sjs5 zz%88hRa4*tMAAFDu++5p>I)3^o@ghv7akc%Iu;esZaW8nz){;2UMI}b2U5^QQ!@C8 zL+95XhHTbthwigFk^}-njPE-ut6HgprlcaMF-t#ci)H?mBWXo^?iVG+>%3Y?JgSPoFNR_9eQ_|G^W9YQZq%!w z(C(}^-AftgRMNL)QMcEKIbAkzt*9qCEkaX!J?;4AR^%_@bO}#_4j*x7(Anq3b8A{TR`S0sLCW7+jyQVvj1QeuHsfCd z`fa)NlDw$99$F!N{%ebTY&H#__kOEU6B<#Po}{)KqVFed=npf(8|s25w8@sr7Z9vT zFxKs@XXNx|_1G3jp?%1szvPRKhKz89jHKs8h9O*fr)K4MggcWF!Y7W@g$YevD zZuOJt{<+E{gUx;R7ww@~eHr3J3wszjGA30?nJMSl5{=>4>9~Srrw6?{a>g36G>~Q% zMQV>-J()DK_D*(-U|HK}7Lb z#t{~}oIkH>#F~O)3+@%P*D8x4gQ9^j;L%_v?c#~I{Xfri)eV!=w~ABk`gB|@-4JEc zdaPG^-*E#2OcT6e7(V)Jm|CN4^ENEFj^8zebVlpCS^8zcJP=Bhp^vpstxgWCw#Wl$ zuJH2u07hgb+RqXwwn9I5tkeLo5iFKs8%-5<++?~rd0F19J}{i(FqRO=(XzcV3 z-;;0pv?MIPF7~>seJ)_?E}I*e$weT%T+%&e-+q0gyo|czeN*j+XDdGK5KVF+V_MR| zT`Se&HEa}hmwm86b;B6=@eKdA_zbQA@Mkug7w zE_vyrz+7&(n1IN9U+>|Onz-<30no*`#qtAQAUiZDdg~77B4~)12hpUOu)$hXN zPNPYh6!JW`iIk3jZ#1IDbUy4Pd{#{=?cQgBVBqX8-)Km&7)u|KuB{n zx2aRzU1Qz$tb`9n3f%osz1ubyoqUIeE3)gBW5Ymc26gk7`C=*3{onkXy_eC=4(95!RY z37&-bvQ*=oZ`#Lb)~oCTG5zPf?XLJ|;Qdv^oXs?Xu0iJKnVvpb@Ypx$e32Wtf4XHx zhGs?qQ;HK_bV{plX=AU{=QDGMMU>l^fi&M{4N+}8XB|UBFF%MMIF(M!{`tm^U->H- zJ!f8LS+Gs$;OXPb?_%=-W7+%aR*b-!SIc&t{L`Xo#%%(!yjEJ4YwqN$^drV+*ZW_g z^T_Xgv|Z3hNh>hnC;ZSnNh3O$BLjiZ+zyNUn12yD1GBpAUvOPWG;l(@6NIJCTBz278rYYU4D zIj1kH@oI%j;Iv8A3TdsW)Kgn%omOGLMPx1J|rK8Oyc`Is2OJf+Czplzm$8c27gZIQvS zI=USovt|xi^sA{rmy^pl<Qr&&+tVw>)MqpnlZ4;}Iy-*BkvNM@XV=!v;q|45Ra$?7oL^At3tUg};aR{kBG;my_A5L})%;@#PBhwZjiwUj~p|<5^J1 zE5#HIk+AT{ha9jX_>Q0l7CaA5>-%9W37KpGb?5liEH*IsdxPyK{Y-bApJdysHJR-{ z0Mv*nWc1yW-vH4xXf>T<+7A?d#yxn<*V+{ywD+tG$|tK8j{yO)i_>xja5V9D;LWef1jz@X_dp!i-7K>yU9## z8G^^eA@X-P{{@Gj#R@hnu7V=K64a}8KOGzPy*0WosCMo`TPoX<;E2R~>Tj3)iAhK&^lMLTEJ_c2vxM4nGW?9*C3C znclNW?|(K1bYAy|Hj$o@n+Y7mtmL+=FY#4gOzIOH!YPiMMPjmxP$B`?*j(w`L?B;^ za{Ty%a0}X%R{`UxZt3;|L(|a#^IIii2P-vRoXfCx8Ja(?-f_&MJU?RnRg!K|uI?fxPC!RZM5d&J$)rrX-7|F4GeUfyPQLGXt{w*qb#HCnaP%bXs7KCk z6BNK6{pu8|a^?_6oA5LyM4Rpz+hpSJ(+^SO4Mt%u6ABZO? z(%)YXzjmvQP57*!jMyJrjOr2)Mbazv?!OOTq6|JK5#tfP54Q)9wS`9eU;88qj`xUu zU`L#HP=Oda1KkR=eHobR`Kw>p#m30QU8h=c38HElron;@lv{)%Y2%o4mlVNQo>ZIK z*mZI=-NPhLrkS4%zKA1BZ3;RI+8^>=1XblP-!phVt~WQ~VwTshDMd z_m|s0|HGYS%NTL{KhM8|?%61B)rG6l^{kY~l6kfj*>UKeRpx_J24K6724f_&^anWN zM_VX2+KQOw-RxYduKKBTkE5TyOp4poq&sEQ1o%*~Tx0qx z8t1t&AyqVP$~`{a`Dz@qeyV1~nWaR7KC@ z^7+=_F@(WH6($E|Xa>!9qDm428^2zU{vjD4I`{)^vqLlI-}zN9G9-wK*lyWpFU-qI z7%$2wXstvirfZo0%y)@rjr23$`6V02Fd|QY#FmfQS!BVtA1rza=n%({jEciF6 zM0b_;`w>`7u@Y7XKb+NfO*bYw&Tr$4&15*?r_?+w&w?}E`Zq*iKnL|0j!FFP?jMx& zx&7p?#sbA5iM)v6YTh#8V5xkpf>8KplmM(UwAy+6k6zDf>z?B%m;JEOJ$W`*0g)); zAN5T2>9pR*7~WU{3m0g}lV}1*QlV@|{Ocx@IQ~&goEo|BDV5;-U^1)O9D_>^Qr+mK zyK{R{T>h|`Ra-Jz@BjvY2G)K;l~z60Dc{FLvYh68ys=t+FhL+w?>uE>+R^b~uoAC1 z8NJ=31cpP44dNnQMj9V7S%vaY@}~5nqs|QTDDda z)4^pZWvA>>G07r=*zn=Ji%-=RbCx$(e1ymYP@bbG$s^MpkvDM|ECx=1%8?v zX+{=*)$LUr*x_?`xA6pe@xD9Xyxoo_Z;n>?S%-aGO|ifu9w=j6K3jEJG|Q)5I@Eb; zDmc!<$yj({P#@`JnicXL7yEKU-W0e1r`B}ShgFI8+kVsdT*~`-CgaFqr4~ewIbwLM zeB&n+JLu78c1nILyAT**ZB)@*Sqf$hEHD8)953D;p9!D+k`XUY|eb=QqHzP?0&WMzur+17n|7}!UpPH(nMkRa^l zGdVv7T*C@=>ys=&gxeNQkyv8lz+If0YP+3_W0(K6(dO~Txa(1=!*yHg9Jl4t2WBH9 zG$A+`f4YX@u`$}K9IG?WQDD!{s8DE!z_haPf>e#}YE(P;>U`^^tCIRv9rCKG>+&KB z7W-KDzkAa6LVDaj*tIhZyOG)k;+Mh@2y067=7su}(_6>HZbe#sCD@VUP$+J8@7~ zbIPV9G6B#ZEGw~?{3iRqtBx->spMH6N-%_VM{%7Aw4vyc19|uL;coK-CfKxGXU`9; z+B%z2_kQg;i^NSf+|jx#>8qhoRmH=|d5;_aYS>tbje$Lu5AcNCK4Uf8CMp_ z;XXaj~8K{ zPGW(%;P|7RcXF}Nby$RyyYuckjnC0HO0^{oWX28_c2E!4Y&FC9?y*@ z1y{w!A?Ch@K0GGve{#R{!g=5*r!;C#*7Qnd1Ida-MF6G`n*zgno^D^d%Oqx>yy334f$wX3E?hq%;nXpFg$Td#A z8Md~85>Up1vih=&QjW{)oevb3g$gV%2e==6p^?vxz_IN1-*LCf zg8Zg-9+b^s3&HXt7KiQ(>Gg?SnGG(RM-dB2gKdpR={BrPD7}zEbkjf*E!14BnDBla z(9c_t=96VF=n|-6D6zU`vipb#Vsr|Cl+sYwnaLTguVPAM$IXs1RJr%XP`MCSJL)SH zlvGfPnn8F!e9_l{WCZC1Wl@xC@+_MZz-GD231XAv8Pk;1NS5f^?ZM#!6jt@UKP6WF zssl!9!X>HgTM+J!N!ZM8 z6b`(@%9%Wx#eIbi0Vc!oY-q)6J=+JY=kNS;;nXTq%*-+%`e~U^5ms{W!Fti7O16{! zA#LJ?fy@WBaUJYSXQw$#*2EkM{;mY=Ij)P;Aoz}3QPBu4p~0;oERWqavA6*276hj$ zH@x%Y^t%X3m$|PfpBXGKBhAnbjte#`)z^{UE44`9t2_AxgU^jRT)pY(AAEf}L@@dD zFR<*^^+78%F}7LZgShe_8(0FjYvvSa*W<@y%DSJ|Gn!^7blr-ULEBDH-iyC)xzLxu zt0C|KB+K`|W8feg{_sbBczC#YWc~BqX4jpG|H1oQd!;9@r#R)z?I2C7!_+ua5FdQi z^fNl7eX2Z`Iv`p|Q|7x8tZ@zf@iO#vcNBn{zo$Rs7U@BO^Qh%)1Yt@Q+KdXSeNo1? zQ47CD>TNJp#ukOnUcWACv+L z;R5n}$^8b2Le)e{Lpuso{RG&KOT!nZy&PNKclfz zXq^Q5{FV&27b_9gw<-Yo93D6x`;%ZJOB;>5EcA|ThNt$lIT}ARC&~6h?+RD5|= zB+9JX+{D%=dITOQ#)_8X`JBaD{bMk=$i4J~*vLCY~pg*FFN542cc^@r<_GP4~f%VXMmBM>J7{!5(j<<%jv; z@eHXWgU2!%bxDn37uyy*`ZJ6oclr?96X*hWjV+(QM~(Wz+ptd%$Vj+| z$oVWb7^lq*OKOcbY%kh=w{hds6lfd!!$U5^$Cd`C&fhpQvLwD$+s+lRuE~sO4J^e< zT?>i23OS9{tZHF?Z<%ut=xTb?*U z7UhSPqw()BFhVud)g2xuMFGB_3 zqf5p^{*oDAU1+H!)@QJm!Z5eO_EWfg%vk2p8VmdK`n`_`&(Z8-(hz-3A~)NA6lsXqICK&pA^N6QrE=HWO0V#-PnL=X#OoQ?GfLtY&tsf`4zd z*SEliE+9qb?gtwe&l5&Ytucc7Q<~Yn-0l1OYy2TV1;tUXjU3LUzyB|8e{Mc#hGYj| zjsL7#>mkA#WIyov3x_M00LqG4;vTr4>SaLhgv+!B!qNU52bj|ZytR#hQP}S#YXg)* zp*;apQ@)4Hz)=?g_0QIo<0UOReqlP58J+#~+xp$(h9XMc<@0GA3ymWnI#D;tO+`1Q zv4&pZD*74kVZdt6R0|i2kkI<7k`l8N(b#W7j5Qk(E=@M|D6S@S{iyA+-t}Hdp%SD} zC;u{oe)R6A|Sc3qj>Ofr>TTI_GcqmQ~&wJP+Ee8=!nFF4uh+q?rw-Lfm_RSHNU3%J<7O+E2p`5hIv9{p#2Vm`nuP{-h63;z^97w6s!oco(5?Ws3s!&u;pH3fx=Fi8-Z&`7z_PMDd z3T^-9a?^+-(j>*TL)vE|O=7hIM61VCc@8W(>C#Z`!Dxw zsoL;tIDxqBWP^IRpc=@>K6mVR>SZkH8QkMV)b!M0{$i`IzW(xj9u#$gs-5FG(6%-F zPEFf;>0r*M+`Mx?9TTSk_9llAzx`kO&$N%ENY&P3X3PcTm-2?odR1txM}l*6{2^Ek z`{@h0BNydSm;OVsRLg9zvRY4`E4yB9o;?P+_&4yKU(V|X4?27M=+qSJC*3AvBI1=g_#+D7u63&iJdZ&xGRF%oPUh!KJGRn8dXec~@W<>csR9V+uX;CquNcXP`>`(o7u&lFEceeWFI z0w7$F&|`E@KN<{@hovQPKKTIP-ogo9_wC8%-c6lG*~oD*^z4=}#q8e#`*PHMDkf@F zL?X^wrhIk~ob6sdAr&8P+53B2_k&y>PmP*76(`>A_2p6^>9!+%0l(2x>1U-dZba0_ zmwbt}Z1jGMq@}TOz`zcwM_~xF?1qP0Sc^>LihEcIetK0vv;Q_0ig{EIKf^cG-EIA2 zXLJwuX8CsbeoQKy__FG%nQ&>Ape9d)OPl2jQOM-Pb2!Y(LpKOE zdt(#5G0cB03RBZ5qmI?xg89G*83V=+i+s)wGiesUV0sd_tSno=5PSqZ4uxPb0EL0; zdJ?E=MJmIRNjejL)sFbx1U%*ue026DDbpDQY+RYmd8jZLr119H|9+8$(z#my6S)E9 zNNMq6W$0w=zVzzR8H(=s!v>1vr*c zz}=ITn4HC1|1gS%Dzt`uXC9y%yZ>?vlf8LH&^O0MNFQZJ@x?a{akQWYG-ZC3N5MW` zAs0Bv4P{F}v@yr#FqSC~=-d9?lCF6#pB=!sim6U16pH);F@9WR1b)|Pkb==16h_o6 z%`NERGE2qSVoq8^BoD7fi%P@RhkTNNMn%E=DE}_*OGg4}aKcGS$9Lnc*#G<^YX zlXj05xlA_(fBTKD_K7XZGq9SVS#jU&y%u?|pRbo|3=Cr>(P@lHtK14Dhr+QP}Ma>s%UJH@fL<+2aC47dBG{$=Bxarx@o^sWBqCri3)5+>iO& z<5!69(NuCWAO+ATsHa_iR#TeoWR-utp8iWb`V0C=i_zzRC4F9o!dMh(Y}k}twDG>s zMFF;Zi}tM(`}e7?5&lm?#xq1~hBxZy1>`;X5S(#_IE>`I-x(me23+e?Dv6V*z;+Pg z>B~TPbHi5e#&{aN`dZdqPnttG-ie{p)9HivCD>POWpx`9gC?!vGM$=HW6PE-O2moU zSOllQy{bw*$>pYr+_%G~2Pw{l0xHkId^9<6gwbIPsZZUTf6tswbP z-X<>LEz;+FlJLKQzW3S1Ua&n15s%q^PU^au5 zBJ}ue31Kh1Y_I& z1IE(waxnAjU7G9vrWf8%QIhC&r-bFHi(i<~h=NA`@U0A#CHRz*az41gi(lRMs-WXA zN^_F&4Ocd})>-Z1*rYgCEoUp}r2rO+N+BxaoJGPtZHqNV?F-Jp&Q<5l_C=F6KUU!x zgO~JSNTx(vvJSJ2lC*^wx~# zoYBUR74Q3+fO_sc8O96MaS`Ucs9|X$eT;QM`cbxOYd6Nj@GVDC9c*nuPEt7nBp+_^ zTe3Rjjjnj5h|0I!{Y5##(a8h1$AkwGF8&?L+0i?h;=}7mx5nEZk{q=(uorX>o;@^< zhIX>x@folPCGK?@fAp!1|* zl%tO(M2s8uf3N&rNTM6exhCJtOxoTgB zj7y8|u>2Q{&I8~j{dKk@p@@H>OnV>2=p7ABcY^jIL_*p$A)i#C$Ru78mi;7x6eV;K zb(qXKMU!iQarsvk0+Ab^IVoldRB69nZEMCT!Cl?bSUJiGst)B)keb{eXWg!gT_z$B zUQZmVg~-!xok~V#B~SPI-F$cc6p$rg9w8qfhxpO8VX!AX|5f_!UjzOSIPF5~LMHke zy@99qO1MGpxmNhaYblzbi3S^gqey*TO3k2QV|4x1##>~k5CK&>fCFCsvW`Wm=AYi% zJKNLYcR_1}`ZM`{<2vR*tp220Iytno=UltetwJjki<(P<_M^!@8oB3^pg3a&V2I(Q zr9aG+Kg#ytH`GE@Vycn|e~l6#W%m5ezECKqK7BctfWu*F{dbPkyB(l_ybmo zg`Jk1Xn|pAhjn{@5m6geK1upCn>Sa`56{alx~MeW!JIPv(;H_h68XEZyx|~ud_YD- z49>Y|GIZDle^kZ1;w%m2mzJ#zUV4K>SY8JHMLN$!FJE?Nmi_u3ElzsM9@oYa*4sE7 zdN4gpUh7GHZh9}1GS!@tHu`}G(;4_;aXj_Wig0{O3oUozL z(JmJd%g{TR)JIm-R%#RrTj9BFS@Rsy4}bmnFkSL~=#I#}-U=&%>jIqGgre9N9P!8B z{a@5`R?DtS+wMm{sxq`>@B5wp@C_{Ioa7~Kl;?TIxL*#8X<+FY`mK@}z!JN!l98mY zzw@`N40(98GS_p7o>aP04aBnFn`dBSS}dDzYmMt*eK0aBUPPNdSv!lFbkM??aW^&v zWz-XVkHQD?)qjb#4QBe+Y3xGx*+IC9yd)isTYUE4UX%}zYGS04Tnyw9%TgL}*vv!- z<({c*BPIs^ZhwcRCg9J(;lDvMa#}~vX3ptIj%@h5ISy9@S$fSzrLT|M08HwscuQZx z!gapcWl^scHq)z<|D{EtW;iL)b|&kkRkFa`*Dm2*yxolL z^7_gB_bYmk4}Vypih3XpIa3#VoWBDG_qM_OhT@Lr=M8U|{zun<=1vv-3siT%gDI%DZFq$iw5h z{&KNA(I7y{6i@XN5}^H>@{}DkIbrJavMF%O>1VY4=+w#)xJ(%IXrC>`@PZNy7hKc8Qk2*X&MYmf?BCufqz zslceW5JU-LO@1@gdj=k4|EnZv@x6y&rIj%Al@vNTpw`^_itnReiy|hSbP5Lx+tL}n zvzkUw`7oBg(a&4OcI*0Fby)#g zNrqL4nD9}lNI7i2kv)=p7JAkS{xcW6m(l;8VuJ5reJ zJ?FgHifr_R2c*^w=a>6Ucs~sD!7*RZL1T`C7{c*&0HJf58|QY=qtg*v(463HZ<8z> z-VkXW?5II^%ZR^obZ}Wh6w0Hvvb?HaI1&?dx7o5DjzqH8?a}S_hM#+%53Yn^;7=`o zhBGaqpa*W=OSAOWQzuu-#Zm(%s`*$rB-lpbHO*4}6$LLiAO|2=Jio#^4!6JZtFC!H zoq~NtW=1~g*79_9ll+KQsF-byg2O~l=6GCgT_H$f>UBR`O9k}KAVFX-GB$ad8ruVU z8RX-x?;TDy2n5EE{x?Z#KR4)kuTe43FC%`bO~k{LYEGE9TiT%LJMyz=Q5JGvZSM;< z_DzYJRA1SmA$JNuDa9J<&|+N+H1QGn#}$FE@($fx>r48O)W9nj8-gMuEM^3Mergj!TiWg+dLI~N4 z#ji%ZRhvo97)G!I7jb8G8>27rw~4sIhCN>WhDAHZ;2k1Y1wd8yu4TZn=AjP5oB;K6!BOTm~HvTTHffl07FQKuPxNsIj zk25xJfW1zlBC))XZ+)0gAEwEKPf~DZ8lx%XIz~C+s%<>9L17}i=aGr66(-k(|JqI= z1HpaXx0A(&BV#wkHW93gmxiuRg)&e5ad5s=#A{r7O#@hNYquI=@VqpAOKojsgsop{ z$sjwdnE)!9#O2`B8-BnST4bF*#+2xdCl{c$ZJRfNfbF2$jE+4?BK4tw?`0@1Qo=m% zzAMqJ(s3WWYe+tkQvgs?r!3>5?5`8TZ7398%&V*?^(zn4)*L43525}n$V?YeG_^-( z8cdGuYI@iVDMv9uAg{guup4YtgRDTc%Mg(jlEg#B_lePTolBh!FDR`_V%0ib1xZ8ptPxof+DE>Oy>4RdzP{Y4u? zW?mfphd-00B)!55&#)w=ILjMLXnA8Ov)x*4f&CE;3CW*eTJP*KJlZMvE(FID?;okt ziKBvmhfSAL!K#f`r>la$-DXMOrM`Z4^rg`T2sWUh+8u7wH+c{NsrEJnh|n6L=DK*( zhHcG#6uPIKr7aAn*KQQAA(T?yej{e5lERsO|u zo6mXoI?(T~`gY8A%l@6XJ>bs<7kK*B z{b@uj%0rmlD5!X|+xJi4GV#`?^F}~6ZAV+z-lVwO-=;w|_r7|%%2(~CB2gp=lm=@U?a*y3dGAcpqw}fzq`ibgmHczT z?TH)e$!nnNN{{LZr_IZH>oc(b?M>qHS$*v1-?udl8)0V=^r`rBqU6L^?>MmD^D(p*roW zI_qk`OA8aiYYMSUNiPE1iM}EH2F6M93Uwpes;zW1CIDdsv6VL`w5dbo+Hu3zcEZDN zJ?}W~y0&`W>dxF34)=%hy^-^S!-{3XYkdVTzq8h$ezszC@aU{|?OR3mPh#~d$_cKZ zRJn6RGK*SK8GMg;UEn}){SLz;^mcJ~@HEuxR_rKZF4cY%AG}lB)}s%f)x}?Ugl7(j zPqxj^&Og9IMr*u|T54gHZnHdZanfO5HbZM*E$df$Lwsh`1el$NH9el#pgVSpdq8JH z64EA=b>cJ5v~41)`HR%Js>JBMBfU0%-W-ndb1C>8MY5mJskn>r5c(Ipb}7D(S|Z)< zYF6{X7DC;w!z*TQN+MU4+lcL*_=eft2SPBrlvOmD(6i7%UmWkSaR@9kRoZ^eH%j&~ zhYEWml30?~`?x=QhkCyi85#A(}j8!f7Ck={I?UEJb3Lr$NDh=r6s zpq@6{2Bnj6@-VQ)Ba9XuAXI`d%q`v@N$C#$jZ)|vWtu6-=Js9%K`+^0IU@yIJZR}P zsFb6P9-$~ggJ{4a$iu`Szi*jG$9~B(GU|EE&C}aMi!0XQt+>+?)wsdV7M!eurghF% z-R@!%PSQ|BcaKXLzLCkPSzu5}$>mlxL1dJqWdi#6|1otITyaHRn#SE7g1ft0;S!{9 zcP9jQcXx;29s&VStLLX)UUmZ*Ovy4HFmr0Wp=^nglm*gPbtZSdW66ZD27etGLn ze;|l6?S75JWMzTwEW+T~(;M2x^=1%SWl-E)-5|=f0WpIq-f}(BY@!tJU?DPUY_vt- zj32QiX@ymYt1WReVa4+QVG?tELlsW=enWbVFfU+q-DQjFv04D6wezb@Q}RA!rl{jq zsVU8LJH3{)m`K*d<5*HB8jF{WIaRxiq8_FMcJ&6XPmDq(sO#?Ge29noRizXzM#{V= zRmD|R4|V2%#@b;8i!HoI;7@xo`E}nbjir~g?;>7*TVDLs;u%DU2jaY>@Ht&xJgwSLquhqLYcsEE{xBHLB0fuuZXVR@7bvn1ao zX(^qax*DR=BAvDoj_sMjC+f<~B{mM8raNvyNa7^{O^V+z`%DFieZK3C`%&#mP|lN; zOywTiNWy9bm?UIJ=~HI(GYtABg4y>+g_L)y=`x$UkLfes^ z>Uz+tTpJXvendU-(~4~f10HEBEGhLHJ(;U`e$vO;5S&QcLEpy_?bf$yAn_L{123t~ zWZAC4K28qMB4lNeV;(PqOKA01`LzOdTjpiLRz+P6zAwtrNfp5?qI=$QdUtziAe~ zKcUKbCZ(&2CpRK-mq8@%Z?`zBR*nMug7XjUfoF7c)7!k*C1gurzw>l+dZM1L2^1oG)dIu{rz^sDSc>pw^HNw)XArP9`tO>zl{3zm|^+@4v;{aV{$_9|F?NfC>GJl zNJvT82VYAjBsNNvx?o6DP8C=JK;PwHN0XS-n;$GxZB|K=5>D(0;OYwkSyi|Ev0g7I2GN&=C@ZfGm~ zP1{->Y*C99V05@O0iEC|kQu6UwsL*$yi4KoPZz9n*ky~nE?$-!2UHIbHHm1>a5Z4N zFZ_OK!*l%w^!}5jxrKA~Y>U`Q9vS03x`FrjyQF(2OIj>Nwxoy7c={WwfUa1a7Z?iR_Jyb${# z>@c-4X6aRrFPp`0!x@}htoKSzwq=)v8yxW3O_OREQ~C$RMT&#Jwuem(d73u65kmJG z@uF*MN#`#AAGrylva6SHBw7QcHVUl{m$1ilKqi0BQzsKLkq`IKsI{fWGf&UA&ahxH zw(JqQV^fQ{6JSaYHas~7EP>RqdoL6Rz#B`KMv+RtZVBYJw;B&Kr1{>xnR)wVI<0Mp za=z7sGL_K+B?7E&Ga|!2+XFj!ZAe^}bP!jOuA7lu^s^-av3Q+74cInib; zLx}32!MF>971kux1ps+z1nMrv6%J7!m3_Y4f$kJ+$P%>J$cTtel^%f$F2@|AXdN_> z-LxDDFNf3?3*!YUvnTrjH!^^qyYNtCd9Sm!-<$kh9;&(Ja#&qVR&PiNw>Q*cI6JoB8d!!vf1rAR+WKP={#++P*Y3q|jW3@tR4^H8Ei z05wtO9Qs7334xs4{Hdm0K8H3mgo;Bh)lRdI=PlNFERfJOy_Le)#48;cD^>a%k$-3; z7|y%iAN=T`mQ>IY!DzgWWEWze^~xusT-8$$_$nvcCKP?PlSc6Lgl02GFLDYVn1|%o zpm4L>n)q8dygOp7xM${dq|1fVq$EdIF07$!0?wUy}2Q3UvRunzn4rQ5>2Kijd4-iDcs}-x;mg z&YL+xc^U$~FNCE00(xzC-v`bOycZ1~JikbM`QH;Xj#vyZx#9*E0(@M@lD&c7&<{R# z4!b@9zOSYoA7F8ze*n3U_4&>@cS-aj+*w1O5Ve;53J1*(usy&|0<<`9h%%1IcC>JN zG!Np4H-vF#7fkaUp1CrI{M#;Cfe0xZsNv-<46c<9fL*>C8Fi_3qi4?=lYf^bI_;fn z%grM}Ib7lGdWq*-x2xTpvi0~!m;c^(EP(UEyCINp+>GkZq5&!VfhGMHHMv*hjq+-L z{XJredk$A5?`K(Nd`WBq9xEsqko}69ABgz(10C#}BDWj(ze;q+$>8iz+eeuTpvEk><=WrlA|QMc89uoWepq&-J3I>6D8z8hG+-yR3UC)-mzN+uI$IfaXg4l6!lBm@E>l&A_A*_ zwH=UC!@`01!!@t|JKE*OiTnYH|3&2dzv{kE3Ax#QCLzu*+z+)44n1gm!ksC0ctz6d z9N)3o^iA&*sj}u_2FxsE`x{uH$Yyr9!qCf0fGK58m2!fB=<5*_v=CgFjG0B5vMUzo z*qly6Kqg<_oz`*Dl$cM@StyGmduy_OKymFG%BVY&;#AduGIwY3CD)LP1c8n#ZT^M; zqhH_`(v8uc+brDW3n?gXSBsuep<90PMJGkdkX$+KhnD-n5_tQ}7yiTt4pT1xm#XlX z-&EdC$615V093FnoA5V%ZKF8law_|(1JG+bGvtp}WXBU{* z>xoC!=k@(=^(OE{4cl!O`u3sMxz^&v+^u4MWYA%$u&iosk-1N!C1ai5a(t2-`XGekNh4JGr+5hmI1&_}E8UBZi>xud1bFt$iaqIj`x~NF_8@ z0YsiKj-*g&!avAB)^Io{iLQaKy7E&=_~r;8qA%%wZ&ZH{dTW6aS<}b6 z7YMj6dx-4bC-~O1;Usm;bi{SS&&#lAmL{o=u=6H{7L^a0z3^B&bAddppdEew_MGk$ znL9^$pjZX4b5h7XvQYsmv)-%luUKRto~uQ{SMu5z<)2h}Q`TE!=5Je$7e`!0a>=x} zs{@&)5REY%X~yNi6&M4V&cgGPlrcg!oNf!i{BzD!p#HVmnL_ zl2z=sp5KzA1=!`oAvHp6N}W$2->GTM6U}i7Mn;2jxW7i+jfT@(B;B)hCea?b%}tHwN1=n}LlCr+2IK-FxPEZ}oUj5>x3)RAuUkF3@a$K6nGn_i zUQ}d#fN>>VJ{10DQ_^}zU(0%(jLzW9?E}YkONfsN$-w;WZn9FI8s$L#y)Q{j-CzYj zasJA1GP5fxs~SXtxjDZS9Ky0ZIRh{1seofavR`@Z_A42 z`J*qz-D}^5lgG;3o+BAppGbP+2uS3q99f2Q5ulppN;%wcVNDP-45C8e*4fo8a1f7a z1M#6tQE@0XsX%G58Y>5_PJR5ny2QaWHLNT36Hl4un5{0VhE zKP^L~DX3mu?dPOfKXTL+aL{X+g5+Q1=x?eR0S9ajV^PkCnqVFqU%lagAhcHfrE8aw z@x~>`@p%pb>95^=Fu`i>K*dU!e23kuTh^5sIc4(8F=3YQ@QoocLjT&!if&_jTNWDvt{ePaW+N;a9Echfc*ktMlkJXtQkE(2 z20aqil=Yr8`1J}h4dfx0evX{|fG$Q}=@hjbgCa_d*#JusZI!V`!5gq&Qa!^s=;^G1 ziaRrJ^UzxR4x>a-#yfEN%dxaWDa|SpRGlIElW$r3@dheJC4g+m? z_5HBB{s9O6-{{EeLLf*~&)jIcrD69q@MS9$oj33zuVwu&`lcQF1!#KIjS(9^p;ET< zT9YKqr9UwMA!b|vk;mW}gOS87$)B`IFTRCaifc-`;yJEH{R4BjCcNg^F04dHe|Bz8~E-~5!) zeCFVC=U3?q-frhRJ>R!QzJ}A+>sakIwBfi)7!CRjh|TmMcKgSU9Sp6&>8qBoJS~(@ z4#?bYc6tBN_Q7EXd;870-=~|(Lw=Gvd$;5oD7c`iQ6_von@?2sKhI*k3*mDqt2Mp| zD`NuEXtC(ame$;8IywS7eC|Nf`N?DBK zNnX&y8Ms&r;p#cdHQYLfxMgl4_~$p87Tp(f!77pqG#L`9jH0k$^2=->?FOQ=Av52$ zvhmFL)?(E_rvlz@;#^lZ&d^ojW5lUGtwfI>+yTr2C9fuq-6Upi_nUQ+iGu3OX2POd z{0|IT#Mm;Ju>hZ9;t;}<^s5bWd<+9;$`VXZU>=KO;VXU{Et+>(WSTs>4Xpzn4-CEu`0#@$ zzTtGEv6wEP92MsThAktT{D|8a<`E0tMhUj$%|ZPoRJ{Z7u5kv-)?+L{&)XN6lL7e&RQh>85+4&BrV3>ZND zzLl!5pD9C? z$cLgghV622)$7x`LfMIFXPX!l1o?EG*f@ZVKBhQkk6oRrEckmF*>Q(l2b@ts9Zi90 zF>h6mF@TM{lw@}*exaQiaI_$IG_^B>+beA~v4Y5C@>P3G?t3p)E0}+*M%StIw-O0V z1#@dqJ^@`cnwoXUz}i#+%B`wzcIqTQN1f|0h4e7@sMYof+}b0y+%ugp&m$x*9wWyP(irBojob2N9l{o;kg7hZ)lKW zuqK?Xk#ul(Fz$A=1&wenMaW}6IyFMzjViEcIS3XPF%WM0x|i+-Ni>qo;PCHZ2%YkK zmgxESu(BQa!L(X0J@jLARmes8F^t1!4AuM?5tSs8ae2b@d*<6BVuKZnHj7!^O4D_z8n|hu46gA%gs2)Zq6mOWn2ikmdSwM9UxvNA>0r zk~zNBeII_``C^|b9MDA^t{Xn{lzo;hp7NdP}WLY(}AGm!F zSf>Bq)XEpFkV;_W{)jKYbNcpHN^;+T|+k|)vxcznVuWH+X`(%{u-to*%vpYV3?`mO@ z=}@E&d4&zkSi$h7KYYx3*3^>B!Qs8a5~B>8PdAc_G5lUmw~%lCzH_3$*21^x73w<$ zveB+Fu+7P>sn`&w^8@AC9qk6!@Nogfa%;5bGYOt?hB%a#Tlxe^K#u*2RDOXGr`Btv zQ#T)w)1asi2jSt5|Cg17;H{X5UUs=}6)S$O5I6{qno26WPIin%^rm+tIfaEM|k^bLZ!?USEHi*;tAM& zy6Jei^I}ZB2wbZj=Idl4+_O^12Z-E&}bb`1SQ%J zvQLY$U&qb+o+77ztMwOu`JS(3{+X`v7kX*L3jIkCACim^6QAU#Du+N&uRj|U+$bmd zQw{+YQ}Ii(GCW{~J4Guxz-A_h4C-k{3e`xkV)}T~{rp z>-XjcSz4(`X8xZO!|9ue@htNMfdgXK1P->2vjN{2eqP#-w0TBh)z_MAn{Q&PS{INn zaU=>q9XQtN^!5As)n#x&%5s`J?OgsceyHL^GE-T$tWhnwtScl<_|U6Jy64W@M%_DT zOd(g=$NESMX=Ta%PCK>SKmPcxhuh$*!T`R@&{>?FZ55kDjN{ju{4_#G?`jA5IbX(_ z<``}$ODTaam{J{-AAy9kXN7dQoAx4(JA_5M$T*8P7wJh@ai^DfN{tW%~e@_*0(Z4ktijs&2x zMw>jVj%7G8r)1Nhwh-UAgKWl=@6l=x=pSkgJGrY5W4Eug&n5t(2l;N7jpYII%$a)$ zRwtBj#3|u9iiteb5z1cM%rZ2ttYf+v*5>5V13M5m=|GJbYy7{hqwtgr%=2)j&Ujh^ z>65)FEFJ($`2ai)*?x6{?dy0~0 z8;P1}YQLg_q>VMa7h)45=-lc=L|%B&9IA`9c3bWohzqYQ<5y!)Y;2!s)x2aJcX(kV zE_YNIlkq?Uou5q4InS}fgeiesMfdGrhLHz*y98X8-gOG^?424BJ_$ADj48Sq^ zkPyn;id(9r)}3jgd?G&X_O>leXx0A3e|xTh`4HRc`D2KLJC!LBkIj5SX!D=kbz z+El`|z*XFpy^7v%aMd$0QupQy%mCz2{}B)Te|tug9AHE@PUW>iTM_AE!kmA{y&bV; zdlH4EaZMPZj$86yaBVY;h2u3k#rgT?#Wg(WR&M`!)$z?8{qSGz9PO-cW(o|>TCnI=5|^R~e6xF2S!@vC(Yp-w{7 zPg;Shb3gg8I+lPkn4(rUY_#EslGskURWvUaY2~~53;9^dh=qSUZuVp{o9}yMUnlQjEq!Cs$C;i=inUz`& zHaIkvyF5*wXpE@|Auek`f9o&=$(FO;_)v&01f#s6)dKZST*o5W|99g~f#rDLmn?fY zzm%26-_Nb;??X0rh;yRgLg67p1nACD3h-HrlmIM8UK2Fu{-AM?bqup1LMGj-<7r|s zVb)wcj|makXr{a(P1uZz3Hu zl=eJXXv~QAD?j1sq3{c1h9j~v^S66{qX+M|MJ@9a~lN9ANdOY4-4Rqc=7W;Y};?u&2A6}1Nq}m;wmEC_mh#o zU<&eFh>tMZ=E-Jh?Kb+L-jR+8;UASWiorq8UqJ(hr>AuD_y_>56ebypbRoOk7Ww9Q z!zyD!@sDFF!)Whr0YVurR6$>0YK=N3M%&p?9sdRRdmWy)m`izbiMd7t#!PP-{mu^` zya6EhNm@+3sE;=8J}#qJbHDy|u1CRx@fGq=^w4*tFL>`FJDPCO8y{{+{~fQPlwNL;d`$`unl8pYpU7v-FT9&GZPerw$8X;&pV^V1 zfzQQY(R?!7NKJvhISWBGI2->BgZ}B1TD`1JXd}Jy;GFd$8&2o_2}ISO+$qIGSlv6| zYeMGQ`7@$a(W{=(V6!{QG?aaO(o86Qobgx1p0nGdSL@4O)%NpF_%>FmDBUkbCKkOR zTr)*CzemzQeLcEd#n7;^15Pxt+Cnsou}qTYeMsg>&os@FL~gm&JcL;3ZPHMfY&|~4 z9}Fa4&*tNRHJh!X22a;x;HSd^=eU>9ZKQ`{p|+`3NZ7wT`vdyVLnaY@`hqbztqOpC zv#7zK3A>X(D0_{boQD|sZlRHTk&Af5R|;-7ss}4s^CE89WU;5xPw}C=uFY6~!(dcz z1^Zw`6dquR=wMPUXeX77`zGgBw;pJ44!;^LA2JhM!HpZl?$$TYRR*i#p{tfK#K!Rt zG4|0et{6K$rgOZYeE}PISv=)GKxCW04X-T$?@6H$dd5$lJv8I8m-o;Y+kJ(m%s?l4 zO}@FUIo{u~%_zql1IT-4G?D=P#HQZS_A?>YpiR&49M0=&uBqyZj$?Y(gR_AHKN3yX zb2g@jW@r==A585Ikh>=KMY6y^ocXK;ObI#1QD{MJm&&95Edtojti@px`siL>8^uNL zoCqBsDX|l$7<+ifBz8V_vdVoGTo+A%N(=eB0;wwW zTWCt%VGD{}rpxB&m76WOC6S7G;AS-NCey2k%XwhcCq*tj(%qCyEk-Cla*i`%VgMVi zkeLtoBCT$%8mt@V?6S4bMD_k5ofH z5;q1#!29ox6>~vct}QjkC2a0!XhPgNxrQ{VShUzYVZw6%I8;u|VcTPKtrM#8w{+`+Y4d)rf1>-x{_jgs}a%?({RBSzzto7bh> z_WL!>6iV)Mvke3n6$=eAWei{?JE@b!hSKi?3U8P)6!O*`Sa^*C3Y(m@|Cku_{laz=#G2hz*@+wnc3N=TbbN|t;=Ywq=z7Sd1h*?x2w z!#qpc$`YCs`Sn)i`v9MyhboW8YDDT_*v&C<@98?-CI!PCR>~5je*Oa*{S+#|HsXr# z&1l|L=M(zX?T?-y`ZPQoAFV%T zd`NI%s9F z3Gw<>fDG8p@ycel_pzFqn))T|qojKC`3p-xpvV7YIya=(z%q!2DA<{tK+7iKH{%j= zkG`LNlE)&Fh=krp)X1?jMCZ0?`_;KdrXvXyA<@Yl4F#h9KirgMwa?1U{_>(UuFXp2$+hZ6Ean#<(4N;e zBu>|o2FE4~A>g2ao{Qao_P7A@WDRrFE?g{ zxj8RYjrr_UNhI!ybbRy(4!8F+aeRj=C|pREJ(bKNkRTS)TY5^{1*=BcKxDLPGD-b0 ziuOGrP!D{RfsTM%Y;XCCN1N5+o}<{Ki$J9JNEVR3sj_Yp)WSQ~boiKkRs0lWe*ztc z4N7CEak4d^JyStDhq~4uK}x8Uyy}sD;!GL5OhWf*yCE)(g2=eeK1*uHKjo3d&~v?; zK4S^9XEoRLmXykG8=H5*hLM{iL@}x!g!sYkj8(u~R_3X(+!tKj@U4>AQ%RID?H}$B zq4VBZD_RuP%6rs{m6aZIN_!En&UWbq_VS|gxNG_!d)9v@$qKB-;KA(cQD2WtyLT~% z^o?G`0WL5#!qSWNZ1p=&jE*)RAx|)m| z-@-YeFe09=SOH@SON&-^i1_U|3StC`qmnCD%tlMkcuNMSEBkO6)4YWopn0H4%9e`I z{T06BRtS`CToYD5m2)UGdQXm_pa>~7g2TaSG2Ij6kl&8%{fY?!b|lxc>Sb}J_M79J z1|rGNWyXm~I~cNOmB6WuUm2YpbL|uq?lg{UQW4y&S=UlXI#Z*B;=V=}rc_?acI6s%$PJaEEh02wy zlzK?apPp3{MBfm+UfZW4U#&?gi9$K|QR4HAQv;iv*NLB0tK+}@(dDpAYqasXIBv)74i+k=b|Webc!)xJ4``Cde^M9OvAL_V7y9|8YcKYbm?jId3KFHC{3P(|Ar!rW{&&1YE zV;>{f_#u5VuI}OEt49W9*JRa}z3XAYUySQr;iP56usfr~Y(NlY6?z%hi=k9PkRVFs zifmRhBXX3>M=wj_Yw;R<=DLtlvgewFl$|AgP-l7CI>O-0=eQZS{g33Zw(B~6MUc{1 zo<-R5=hOqOZ1=@-ABv+n1nADuR8+qmZrJ*Tux8?+WAMu`L|}AX_Ym3>eAos$=Nqs> z?7yPtQUG=#GUIxHN->w6vQe*MQ!A3h$?-Ur&zNA->+Np)oNsfl^?o_RZn>t2UfLNA zVz-66cSV`hyEJ7Kt-B3R_OrffdihNo9&idW$xpP-3aO$6O=+v*Cbc-PS@ICL8WuPzR^ymNjwg1)0&I@Rw>nPi6|on)s#?WkO1ou-YX9 zotm6eV^AQ3#Jk3H=}}p8lo4qgw?~t*>UE#SDL24pz#dEshzBrk9hN3yWse*s2U7~t z=(8-t);L8^4B7meTTQWD$ftoQ#E>mSm0JF7VSKo zIXX<12xof7{qFg0JC?1B;G$mWd%=rr#mqb`6w${&8owAMkni!IEio#X<3Y~5!2wZY zqLiQ5sG=9GTJ@jythu@x;(AqcC8x~~9+9c@^MXhP&!8oUkUlYbcPUPD%FRKR7=N28 z)^&bHg6fVm@tsuTy82>8b>m(kP#RT)e2N^|cy)szl_Gtxv4H7~@oA7uuyd#7Yo+WT z>{Y|gw!kT8DpDc{rAFCR?sr@Mw3a^#x}>ni@uD2$(6V~bp-++br4erIgg8{dcq@SmqwQLjQ){l*<0j~1E zGGiO5fYAk;p5M=S0j4@kdOu^g;8^NcaCpMD0Bd++&0A=M0e(stBh2)l!cZxqB4$^UkU8N1cxG}%LUoGEn}ynr6yHCS3Ss}JE%_a}!bI*EoR%nl}% zS5v+;Gk>57woF+G4ZY$RVG5s-15W=a!;UKIcW*}<&;GbA$z!Y`UfK$2Dbs$;RkEjd z@Yznx)LdVC5K^P5b1g~1QX7wiP*J}tMF_|K#!w3sR?`T+&GehPZDdC8pe{sVS1_8x zL3%p{DhD!T-=6HH?Gn9p2M_)SB3JBB@0P@R|0BobKVJYdkK}AG#$Vbj6Z%rUHuY_F z#X=s#?0TA+4;iV1R)KS?yyty{@z=@n2TBE~Pbq<!;>(UCHbOsA$I2^Dv;QDNs~|v1NJwx=0rl>`ZJ(5l_xBFI znKpM|>$RCr+4;G-q8z0xby2iqnT%S`=~`EVN#38D*_=$NTje8Z&8h!#ih35#!@2jR zZw}25$|duiSa3d7(Z${c`d#e|PVX-MZzswPDGo<$sPh)Q-EZvmFy#w)+LR?jxeWMt z+ujU)$*t~day@xZX8Sreir0=bBs9kJmL!aHGE#HIos^S5wwq(G>qoQLQ--J&*p;x}~SA%{unt`N^MU@z9f!PwY75g8t9 z0yHOHUG+||9Xsa%PJwCyozts%F5LVB<`Cv?u;=~513-YRrQ7pAhyRCUaQ0W1=RJgA zdW$Tz%CODNd{k{T2eg)zc=sIhHIUaiFH>C?q4Fgz*Y&UJA-w!JsVL&MOMWD-0KyQB|@w;Q#<+O6} ze@8bP61nk|Rz>Vb!eN2N{Qw0Fj~Y3R>WOHkKO^ggt;ScA3pmM5`w}t#>%A;_+N)-s z8XE&OTNLJeA$n0w|C7U^a+)y^@ov1062d3$OM*6!F`s9mI(x)NIu_0uO2PK4kuvQc z-!GD3vV(`MjE@J*va|kEPEFaZ6O9_LcI8=lb()Q;x%mgc2YKAylqf|;RQ7;62!C=ge8M1mE zu+z$4c1!1eNOyVuk%^5_I4q(bvrGgF+w z#TrP^)RTqZt3tm|6=R|a=W4;kdbP8}J=SfrB*!O`teOhynj76yGX&PM{NF;lOd|n3 zIMX_$z>Vey9A7*cQJ*BrTvVE$c*cTvdiVsxmm!F`SgN++x-L@+nS`#gghq8leb|9Y zFKkEJZY5@0)`PufQZdj2G5rUkwxP_WhYGB_jlbyH@~-J>S<>&yus@E|Or z6yTJa$d5C#Z((oRJ&qJGl+hzESN~SOW-I}i>+E!h^*VVfe`~z{d+s;&^7xzLU%hLb z_5$K&gXK=S(htb|>#UDzu0seS6~jk0PnCIi6^e2imusv83j_M%qJJsv2-Gsl<7l}w z?A}%Fg*dD=az2Sy*Rrs*>kcq@;Mg+E~&L|r!j(4 z^_gk&VmClTf=oy60iSx(f9~s#TtM-ae`m{L6ZekKO%qn>#gM>6K`>oN8^ zk2_!1e#CU1KkVVv{$yuYTI3vID;-^ADi7BhbILo1AaD5kIBOv64lz@d4wlDw{mpc^ z;3`C6KzI^u7idc4)Yy4VPc9G7yVU{17rldK@eN@UuG|8OfnLtXhVlCqr8)j61{ME$ zFyi!e*b7Q%4J-Xm--9B7Bj#!TFQJ*azxqN*Mrrj+{XVIV$gvG7Of%9d#A@c=#`1LQ zvC%XTQ}0sN0(*Zawo|(vW%HA2GLqD&fiE0IM4*7uxHnj;x~MZ{JJSPrV{QEuYfGD} zFe9j@g{@LyiiZWZaHyI9O8IDi#Qc&6@?1 zH<8(*tsB_YCxw8eirtoy`BX4ybQ`l{imbmmE>wrzGq%bMP3Pxfx~K2ISkY}9qJ4$6 zup#F}>k5>6XA@de^H*iiRI9un1;G60+JKnHzO3L)QyeRvoT_AZaqY1;@?Td8lgBWh z0Z=M3#5GwR|4lc{JGQCEGQ-S&f<6eP>+10c%=Yp8(Dg#s<$A~$33~pG9@$~MSzBeC z&NHT9Nv}5JTx4zrG*_h+%pVWoeO=)68eArnbj1I8$OLpEkkZm*APC znjlL;$JjBQ#pIhXn|*_9!M-EpYI);Xy{|$|=fuJ@2A%qWmO_hyHbnqvHx<`yQxdgu zi&nof+RD#)>Gf1MiUXN7^PR{R|0B*5IuZJge#Ij8x<@eRLWJB1P~nYfI^G_ zHXA+tNF~+b2oYV4aXY7hXlt6#Co#!AOw>1r69C{K$~-vSt^STsUP#m{%dO z8X6MpNmu1&Wa)A_yP{mfq0x|Kl28taP;tUW*VrOdmtQ}2qqFoF>;m)5S@Y$|wn`v> zdS*LYw|gDnkh9S56<) z`bl?*p`+c|95IbU*JG}~&i^tt3HtGBQf8@0WJDnYmmhBKAp!;Hv@CKSOzqK_}YkL@kFL%tRLWu}#yM%GwBzn#DnmnCVvjz~7gVpcu2nX>zltY2MgmF=a|< z3k`E~SHMFZs5dl8I83O@qAQJpb zdro~Q*Fpj-K8xtQ;SWKv7o(U-5{QBSt27W3()5*qtW}pz3|9L+L6`xBJkm<&R%r9% z;_B`|AXMCd+-y-GJq4d7_N@}c^jmd$|BIFi%Rq0x-xUw^%}5CLw?aITN`^AD zxkv&{K>}ntrN^3%mfm15DP%xYKbE(Nh#rXO>U7HMR7RNP&omO1*|w=AB=wtglsNIY zc&m*4_*Ng{vF?yb&`SQOWPf8v>$!Rm5ouHrURE*l39A@AG_$h}_8v}lj$orsn!EtE z_x8WV>mzjUGZ0Mab|*=?Ly!F0td4eCZ0tlw}9@G5kTqNUHFo)0!<%`X6mLNC6Arz#yt~EM- z`yolL9Q<>5?OmDb4 z(q<#|0pUbHR~56^I?C`Ij-O$jh1cnL7|Z58k**j7%c&1mRjia0ZyYh_Qi`lQP{95$ zsbo!8Lzgr4)v@zYf|ug#;#`yZUD<;`UuEmIb|jT0ev2E~TS_?X<%D!p`w}no`aWhBx2@*a^Mg1HN)3qNV)&*3b`Q(mq1(} zjBRgkPrv`Yd>aCS+FY$4!TsowY?m7(qyYbvdW;lUfzUW>=A+I&f!f`jk?)pOE;u%) zBVL@`JB77@!KR9e1SKUEs^UWKl@g{CzqN9Z0kI* z;@-dBhevF!qG+{%JH0FK5Bp3%!F%!UF5FC@J8k2nHpEW>W3U(=8nGI$z@|QBfqP`?V+Yq#6Q@}JmyWH-~EpKEsjDT zwB&j^FTDQPqUWn7Us`%?Ob^53B=%lgoRv-;yxzP&q{UttrvYN3-7%mFmXG(d|Cyd0 z;XM8=hqykZqDxer;q16Rj+?GPQnA!ba3!Ntu(QaDdHQ|KiY-PP(m|}G;By#@Ol!A( zrdDv3M>Q;0q8bW>Fqa~6H4J7vBHoSY2ns{0ijG-fQZlBHMtiuQh(k!YXVyAe!Wp`-e|5R*FSAjgV@N!$^#T$2r6MB=0_6HTX*RHMEC@Y6BR=v5&<>cqGZ3k z=muP8{2!*?Iw+24i~7Y~g1gJ$?hNk1EkJOG;I2V}ySs(p4#C~s-DPlRu;B3c-h20c zx4NqT?3$|SKIiPc*7|K)Ld9veUmqX>A9~DnnjlayTIed@9AM%n#MwKHSuLhAc8s=V?OfK%iyuhB=2n9)jT}K11 zVC6Ro#R$F)j+0!@^!b8_&W6_Pq$NF`h-B8znu@c56x;{gz;QPCCezK<8FE+JNzN^* ziGMVtC&Sbjm#!UGvxEF|^IZbB)YvJc{$vFm)WOP>9^o#bPTw~4d(3qV3*ouN=DIxS*tfd-zz-DeDacS z1VInRg;q_ic08l)hSTK=6Mzytfg>0=t^LC%ZiA`fuJDjb#*XzfA7#qAo@YLq^qS=? z)F|&Ifk&^aShh=$muH+h*f1A=-7j-K@v&@Kzu7IN-Ij#?_rIdeF?Imd$RTt!@e_LY z$GeX|+TIhGfgX<6MlJ5QL*R?%?hw%HBq(dUBWE&b4VyTwfnClA?u&o0u5**G zuY=R~l_$sku2n}7nZk7MbqHxW-sr>^E_Hqv0MN1ySqEXzG;wx$A1iY zBIHODpAL*vlEY?)ZPKldw`Xu4GAl~j7ba4IKQ@As=U`pS8uD6~kG5K?_fT%**|7r; zc|)WJOxwPh?wj&akQd)!g&?{*q^Usv5ZIr{*IyXpCGS6*lu{rW4D3`f9Zg0H{Z{%e zUGr;Bl4e58b8D2>FUTU4xDgGFbeoh@8t)7$j{LbD-2QBatIY5+vxgFAlDC=+GpJF$ zzeWkoNOM+_8MbZ6bM2L??eJ+F)W#!ye8rxV7)?ExGV`s_27BcX5&Wz7XdL|;^ljtz z^tX#GzbOnPnjX?x&opS7rP0R^Rc8pxdGI~Cd+>{Ujo@2HKR^Xoy-O*Y|sM$*#I#ZE{C%mbg zy9n>Wqc#`lsML%-Wt-0Of@x0>3GVY%=bPxWnW3=rJLRkt?clC_EU(BJ#@TPKczg2Z znc~buO2BsyJQ0tI-thF`B?^)I*(xe&uW6i5@h9e5A+s|4BRcIKnM@4pj9cV&2av+n z8idP7C{PquJ(SA8zJuYpn3H1Yq4{kd0>jsJG^+$yJSR=uR}m`eaUzCff}lH(vF&#Q z7(Arc%Q2r<{%*zZ3K`mEJ^@=@72_Dgk-BX~*twxkDDb2RBOYln@SvZ$cBxOS8tdx` zi6X*?)`5U|CGf3%E_)b8$V{i_pb(4kKzBUvYIPX4XAR5OkNPqZRQRSPCb5&y}kOOqvl~v+HX!mJj%TROvHU;BZ%I#hlV&ACvehL4jsNlK(le!<`NOT;ufxU1_}=v25~SHDR}5mj4PA>@J- z4H^yCOS1Z&;#Ueg7@!dGMC8l`-VQ>*Bae2S6}7HM&ftM<+LK+P7w*0Fyfp@zl;Ofg#LDG`Z7UVKyJQbWKTv|OrUAKNWO7?f z0^Ww(QjsU!@_CTUFUY$l1J~ZDyY(5lDV+$a048}QG780NoNz-L4y8eWVTZ{bKx93A z@q8Brujlv^y5~#Y*^if8b)RIWWj|0fSWgySUyAb0mLgYyYFz3a+E5s$_^pR?c`i`W zT!d0g@8xy(sN8g3!*2)q(ij>ZUahypD?xepI=4%HEr?LS?Kt9yeUP$LI# zdwWU#A5%FG?*)Ryi|@TMWN3Lm{}C)FGC6Ct4&4eY7MpoitEv0a`@|a}_oWDO(~_g@ z5eyeU$$0WWfOEVc|4y?vWnrw#sNJ;%<@xTiF zzn32ycKX|_$c;?cvZ4Ra7Pnhi?0z?eb`sCeEV+WP=Bw~6W1xxUM?3%9^so@CN@lm8 zz+SGuL(-+1D-h3U$c``FV&a9U`p|-V2{!kNu%!Kewg`OKSh7vAcxh?+5-vYJiqBQg zxJYa-<9uCOED~)#B0p3ORWRv|B)WP)%&TI>EewDtJHhIVf6xf>94;N4nDL(yJu@T# zY}{wQsLB=8NflKf>FKL42$bcROelT-)kA%=jp`xQY=S&J~96uPNB zTK`ZoU=@5^0pFkfa-u^hY+LVRV46P6XUTwEy|rEmsRAoH1@JJ2sm&g7Ky6=OmbsSa z9y=1Muw00G$XLd3(+sn*Y8IF1Zbl_h@y!$c;C~o*Xh(u1lnurAqt82tWDjsI)$q_O z+7$~*_oxt|3Owi`Fp%au&FRzi#X)@LHLbiJ`z^&cs_}!#i@j!`sJ73MB6Of4C$UdO zmDLX}5nb5>rzOf2+F#ZqrgSvr_0K|>$Q+Ajo0T{hqMRNcetNgac>5qCih!3aelNc; zp>?I#iIQ$l95rH%(a-QJ!yU;C5LVs*r-Jvj-ofz)$J#dtsi+ zmGlZEVmva@#vZ`;+*C3An_ql|q)@AlXZALHb@l@hBTZg0J908>3lIFzRgNJPYE9~l z4wFv7eR$~dGCXDoz(+SYChE()UeIZ-*Z8U(hOQq~#@Ba5Hn- zAuUq&1L|9FiB-5Z!L%0++1VIL8w{+}u@U5kP}Q~8&14V+=um=CQNw_M!csO0HL{I< zNC79{QhRcj#7n#D9udX5AWBW;cTb&S_O`0cNBmlm0UmWGe11Z8Dw%d*FIgEmSv#_f zuX8p{*+oV`E{80@nl(?`Az$dAkpkZ`>b=i(>E~jFm31^c59tD%v2b&!dSWZIuBq86 zR$IlT?FY<^(s?PY%2EaUxED$ba*a4q$6wBo$f0SZX>NkYsDg&NZTl&b$gSTgF*hH%q#nQvi|eEWeRb4|VT8^aN${zr5chuc#D^Xs!E{2*_ydp-0#bAkUS?Io>$Mz+!l|0zhgf)8Xuji!0It(o4Y_g!2 z$}l%BC7zM3&m`I&{(AR?3c<(Ybr1;DFVjDIV(lKM-{s8>cl-7h)gSwiHBTl57vF6f zT)a)*%x2mbNMrali>Z=2#yl~t$@2XBkN+w5Bu3~@V=PuxDJPkrXvq!sh1p10kQRGlg*WYHd;++bjxn0+O?hs-D zW1fRpMLfifU0`}X8KcU1*Gk-{2~JZ_H;lt+ME6*KoJ)djHaOh`0}c210^VvvvaZjX z0kHMt{)y@K^#bCAA`m16#Bpe>jOiUM`Vk#^B-MoSYB{%ceFt`L9GBQQ)$;{h&1C_n zWzwHxtVNDq@`j7AH>pWK;=_Vp?r;6xI{%Y0ftLwfC3`P9nKxUmK?A);ieh-_Y731PuhB zG9!jKP1L3`M)b!acu(PZj13_e5fj06mx@w#k>=B$p{26lwh8&i2j=AT_L)u)DY8wK zg{pI4lnfw8V48~CL#-XJJ#Q3l*eHi(VZ`lBbl?a}$`5&Ck$dFLUo$WK)ltky{o6Ru zzs#xtLE#Jf@2!GoqocEq5AU6z!+Rq9ii~W*TnNA9w~i8Ws2Vj~pO{QXDAUQn0!cR?;(h4XHfw$(=$Eju=N9`G-P&-)QSy{lIjU6l0GWj zC_ZW4PByuzTmH@0scB##s*{Om?@In3amy~+f4VEoUGK%$_*QW=huoj@`fL!x2@LKw zHx4`)*1OA)HDL&GB2sRKRX*9R*j!&Sssy1zQhBKJtVL-D^-OV{rmvWk`!S4-A{8D3 zeGi!To@ZoD^=0ZLbT;bFB9IAhw7xVr(wOQ+Yj`Clnpp!1F}fP?x>_FXNmI4^+ht;G zv>TPU8%{9ew7e9llyQk67-Wp(5jjA)fGP7MU!j@FcYD@GlhVB3bAv~Dw$mU8c>p!y`GT)JjMNlsp{zj+y4RuH&S!PtO zpDVz2&TQ>|X+Dl4yNasrJb-udct?yH92ENv^4g3Q^vn^wo~?<+U@toAn!gHIE?yE|l~LB;uB1 zhqD=td*9m)8rcfVkdbe#V}ki9;x321xwHm$8~-l-8I#GJJN}9%CNHBg5`|hB7B$>*IW+ z;Q?CwT-{z7L=??jc^P0+H1m=)bdndEnfY6h<~l|$QL#~$L(DvIJuWQ_+; zxse_Ai=>PVx%TQkZzl(g6i%agVOmx4xJ)jFL2NPWMEg1lMWEJbqO^9L$nCn zqOHY9nIGUj&ZVmm4#x!uRQ)| zY$?6%*}p3(C>`E8V?&*uF#LWqH6i!EW%y<7=2*9cS^|a4CG$ls2($BB)-xu^3Z{^N>b9=>{a+d8cc3zQmSp;;%9d1Or#jQR&`6T)>jYmT}nQD4-w zgcx$@lyvCfW8JeHY}>PaEhg?IWsj?LeOF2b>T8@m%4aJaNeBK^@@)5Zbo0E8;SKeF zTo+;QaC(`{_U0WHxmjL;P)|Meea^Y2IeD`;W;Tf0<1}@;;jm3^^+IQRKep^B_OZVH zzF`5h)C1q*Z*IC>HWdH&Tu)|#G@*fchK;Mp$K^YX9C7IJZtdy9T)nOM`*XrC*h_eW z&kob;eUneI^q35CMAF&!9V2*rd#?MxPxx#e@gR}+e<{cknRr|A&w0pmtuCG8t@tBj zrdcY`tg%#vJ*m1iW|;ii4s(8Wj`p&Ct|z?vXo5M+Cl3VVPGDu+Ee0#YUa13egRM&= zXQ4uFlI1Fp-XF1YpUOG6RJ$VMLaBvK6~LZzlYe4`uz26N(_v|E))nqKyI~z&&K(-o z6;xEa+M}vT=2?l&ttI{qzPhn(v5_22{gPEfzyw)rTu#TyocWq5Z~ zu{>Bv)NJ&h@+MiJ%1az(ssuYYPc5uI#+r|0J9Z=dL-d{9nkyab#sPB&n3l1@wJb_5 z<6N;9*8A9g7>O|MD5EQfbw=TL#;qz=|M6Ll5KQvH-qsoE;qalul4wPORAi8MFINn& zhw_V-Acn8iX3<7uW!bk9o>8V+i8ehbuBRD$Ofo*A^ytfipFLbC8r&E0ERR#kP`R%% zp3kXYEkd^2L}gJP3<%uy+hck9iYR;&1czDQgjR&A5$_Mawan3pOb!cARE7=mBTOyI zaLXtia2u|4ZHnc#8g+0f{`|5omM4#r#e93J+z(St`o21bwbLDIWP0vbpXihSwx%A2 z{I%|Gg#`CVRE^OnG&tzps5EFlz}7+bkGd=U*a0yl%N<{PM_vF`km?&`qR3^=L)`6n`g%6Gwb@dVrVDTu)BuN{E;mJwE%yYmoz_atVTh^Z- zZOljM4byBsI=eJSDk-!mF3_ecX~h1%o7cW|Jt7YI%G?#|vv43H6EH5Yoi-ojzY=q6jlELqsKW`*|YGe%wE!kN?VfcO37Obk$@KZ z7w*FP))zEU5Ki0x6y?ZAuN8H*k(=C$n8M329Ua(|dT7-$e_|($}SYTDo1xl1b zng+aNFV1l*enVOLi2PVA28ZQ;z!T4V>wcqci4G{-B$|mlxx&b8Z4iB>ZRaes{n<X z#IlyfJ=OM4H_=y}^wZ#iPRRCg>I#8=<2k9aA&hfKzExCslF@Eo1)fBPe8;DoJ&JYV z509q&FcS^ZA-U#64}0Vd=C;va#E!|gzwVu<13Edzu>>mzTKQlApw+pr-&Sc8(Q6}l zcOV}}^=D10kNLBfBA75I_$(MZ&*2M${MM;Hu`EGZQOr#03=5I8(+kXegJ9M#))1W= zPxe_$t2evhcn0!*Ggx14V(z{K?bD)k%p}!M7$%69ct0)j6)dhjOu}RAL17e2u;1?WMHpQL+TTx3HGPG zLlcRB?kX-0xBsmjJyhb7mv{2t)}`awfmY~QTD4S3orf{67k=t>5|AAISDbwodx&up zrx%qeV%L5B&k&iBsfJvFt7cPv<->?6Nk8%&XKriHD&4FlYcc| z;)HzuN6UV7MnHQS%c#^Hf^MQ-o;h)wr)Voyklc<>3!TZaWf5dAGk-aD0%aFhH z24ylv``Lf8nfXOM3dXYn9wx( zslx2LMiqlvOT;{}5gK|6#)aUn)xrB_$yPhjr)7!GWOLks*}qpq59xG$zhbM23p6!K{1$A(_r>lB zFoS@yDqDhlf+$xA#?0Lvbg-b{Zos4;Qkj>uzUdHVr&6JP)X~ciQjURRA1DYPy@5<- zJJLT*^b~kf(dtm@0;h1JkIdrOK2b`4`>BW&Gst*yN69KSM#kP@4U8a?mrqBcOp1jm zm2spNv6du?AG(~vb#E_NcDDYS*uBBd%xsFXkoft_STfmTWUwPk8jZzxu(l$KXNTJm zx?om$=BGwfF|7)DB0}>xfLg?Fwf2L@thm2%@v+=de8TQCP0x6V`{|NAEo-8_?x*ns z3|d+!J1C|htx&1PU|%C96~_<^`rBCG>`trsM)?Ty=;1OV+dETJ4Pzp2R#H2}+7im~ zSC<>0F>8x}C6=NNFhSh*=1k zD|_M#uMAp_Ku=xlN^uZk7I8Yy9k8S5%%3LAINQa4S`zMo#h4ou7!&83`-*Hlna{`` zAZ6DJZ!Cn-H(EZJH-M<7skKzRT2gZ_wSky7BW!0g$A{?Ej0$hzIVZrn@|>Ya;=&N^ z40pzA7oCx_bSUj}v(7`WI3-Azq3q>hx=wqsHdZ(#=FAji{!otjY+`kpb6->$S}dt} z9k7Yp9wBoKaNA*3{zeY_Bx_B)y*r2dbroc>R=!s|z!H9E?{ZRYsAO0B zO4WVFy7;#T=DUDW@}W)(d*5FnvulzsMLAAqt@j?KFaDOo+b<%IxG9(aUsL}7-2I4P z<2mb-26qkLUgxLZD?GaWEss9l@2^nu{GOizE`K?Zo7$SyIBTvRXfWLfncfmo@$;;D z{v}r7d{Lw2e2>~NDJn3Ps}WHhI!ku*V+7|=StC4@b9m$n+Iyt`?FqMUn@c0#CP-WG zMe_afE7qnYR)`=*Cz&5hi%ju$PR@!=?Mab;oBin+B{1g_RUpBM*#9IVze^eu;;BEz@PIt#RzSg(5 zw|@YxXuNd){I7+Hq8Q?@olT?m`|?HCHSKz`KYKZM*^rq=LMf*Aue$yhE=?xWW|D6{ z_zMkxIWnUAgt4?}&BJwY`U#cXoA}>_#x&>ZX&mK?8onv-mYcc5|AFJXjUzg6R0PVG z{;=^VJU2>3S$k*IUU2NpP$z= z;m$(ET*U$>hC1kBKQvl`!g7_~BhutND;Wm}PIk<;BUMB|! ztW(HejdXShiR=^)<E@-^Ln3u8pO?J2g&y|Nf*Ud|m2a!v-!j_8L#r4x2=%iW5Am z($T*#pyOM0gP+$4k;+6O457Pe7U0KOgyq!WxREUzo|Nsi}32%>bQHs*rm8-B0wy87FGa% zmRvzpdp$+<4nRSuNaPwj|BPj4DZJUd!Mdk;Qr6j^5NPDYR<_!^9BPe`I!J4PioI6v z-nV(FA?ZnuP(c-7XA4X*uah6C-mi;=If%8zb35KA8aJgc{;oLuxAjbOMFWlkjJITR zO%|2X)%Ry4XxBQuN*89s>&I3T;`_iCwA7x8$5dSzCmIr<38|DwoIs7hmtukumt@_x zaQJQuV3Xd(S}+7et+e)2WAwU(5z0 z6H^73>^e?U8Iv2qMNzlk(0Yp_lJDK#%=PQ7B;=Wv&TmygT-oG!QV-UQ6IfXZnCz!{ zodY39@H7V`gFhUaWfMS9DmgVYiR> z&~x@JtTK~G6J-_~Pt?*1N9^spU};IJ*jCjAw1+R~>4R&Kx9*?M9d=Y%spY*2qb}C| zt<2Fdx7ax1hLyRY8^x?Nxw(Mt)$mSr-0{#0$>2QJb!_@iq9hlwQ*~+g+E1VhbEmEYgF&$iQZp zUC%JaCg(=XJY8E96+iwV$G;bDdMvaq8h_F&8MA$zqI;oN#%`l4M%F_v#@aY>>uj`H ze~QNVGZ);Z+oaW?G#h%kdA?NfhBj|`+q7KwP3oyu_`*6LzVyum=BVKjqe8L8Jxu3h= zOmZ843FLmx^LG$0L?r8fPDGL`}%zJ9h5OS;jIHNJk&+UCZ7vpS=A>W9d7#)%hh zesZ9*26TtX_nf*=ESw&DS2yodvs$w%^~G81baJJWu~lmv^J*lWl=l%^K#i{zidyfv z*{$uUP;(D-kb>vtU|TFka0^4oHJ&i7MDie^qYCj}4aJJbhq;?TXx{vRI`%zx{>Jv^ zctU9yIvFZ_vpvl;f4FtLyCeoQ;WXWdl#1n3uOgN7QqOHQq{{i-Fp;-7{EbR}P6))n z0={W$cE645n7wTb^rKgDBcGfPD%HBuiYkO&%h1#<{6nZrm~!Y_1zy-5Y9s{qVf|`# zc>FSop7L*4aG_viAa~>gY6-%??{Gp<%EOstH-(-{-*bVp6 zb|Iu%Q2GO^Q+>Nef4O<6AECOY%0RkU2SeCXAgnbvmZyT>qbT2QMBXs75B1;V_|Q3% zpnIP7ExF3N<>yBG%I@Hx5+p<$EV5S(v4u2$B9W-1&=+D<#ptz7#N-_rVFs1QFgX@D z7CRk~2R5K@M3IbHLYlrC0)fB zp6S8mn)o>W=(=SA1*>1-TV2)X?A|V}eEpWh!It*~rNfFqO~(8ayQ9lLi#>_B@xGeE z3Ce32Zozrs&J=cZ0;*or)R;a@9bTiOb6$42b1B|`ni6FSfO5aYa%XxsyBIR`#xON{ z0bXlOgOg-jE(uV?DJ1wdxOP^-bto*^b?=%1A=Tj8gYoO}8CB?1*k;tFt*sa{}7Bv=ML71U#w5q(M~?r#+*hj??)l!S>+6` z)_7&gM7!^#6&zkq$No4@Yx~-b5IEX+I%V>e)py_FHdtnI;x$k3WCuNZ0{XlBc=0D{ z%wL>4r}oW~_4p;ZZGO4SvykrRjVu7TZ+gafkK!=G3&KBRcHE?>nwx8)Vh;F9cr{<_ zQ=F3|^Q^aBCea;{X4=h+TRWO_cYX=qHSCG3b-dNw;rh||hVxl?Y7hQa8qDCj{4zJw zAptyFdnOO>UqenjaaQ|vKiD36l)U&kq-WSnsvZ6lBd3P8D_652ESJIctDd;xF`BEI zzqZRx{?Hr>HBQ5Fc6=(fZ*`c!7*bJG<7;nTa*XRu&_c65KEU-**OEYwxL9Fs49Ibm}VBvG3b-cd3&8Si?OW4KG1w<5jtEf&uIhOJEd ztLZRaF9D?{nM3yMtnh)w%M2or6Ki@$AxB3w*qoOSyzjN1_o~5B?kQv!15N}TA_+g~ zIt7)iMrf$I?Q@>!n;SU>8x}R@xz5H6%C%#YUIjwiA12v2^eFR}jdzv}WK7!)GihLu zJ#RA&{Z*_xzEB7OUW_v8Zv;Nvoy>ycufspVR~|*>;oZNkUvGL-jKeA{XEY_h=@|CS zhF1d@PXIQf(CTrvc!oy9d3@#&09#w1fxg$Im-%2ugpt3c&B$&W?bO;tZ+9nQqpk(4sg$+QL;qgzCtJLvHR2z1>dU-w- zrG+|lK2?Eon!C9>9QSBT2F_)cc%Yk0Eh_iMk6*v#o=y#8Dfj!HUe!FM__7deysk@& z?r}XaDRd7X8SXvR_vqDof|5g?@&Ld8>)w4#DC{}!fT)8}GV4j2wB z@fZ}om@J~LoQ*Oot*1&CN_mJMy0j(VGo4!1(?@fqS!=_|#DP!cBa=$Xizg!#G7;VT(Vp=ji7zB~c*oV>p$X za-bM7*9;-iC_9!lMxO==?{OdGcyagrvP7#Dj9u`A8wHtKf}hFeZByxC95h6E zrd|*dT1B&$zp*}4{>pipGVkV`#uA|xw{_2Gus-87b(Q>bEVRE#(smi%V6P!Nz-C19 zohN48)839R742pm-Q296wvv6=WFbsbf}h~{T0Hz-NiU}Rl5(mK{xy=QlFTb~O(Nf6 zg8%?Ezz4&0#zw6+3OQN&16l82qj`KC3_MT3$v91J3qJD;Qf3~v;Tjzm$5Oo#2xMUNbwC?6;v&{Ug0 z^5~vP%u#o?s5eQ5q(6gFc(VUZw;RvFgnoVRB4mZbqsqcVu!$6usH2H}4Fu>(s=b1g zb~w(}rL6$dp~6t1a7!T>D_8jOB!A#ArhS+2|Jw2T*#y_9Lq9h8lSd#2p7;B%`M1<- z`rFL{25lZk;n5ZW$X$b^WXi0@zG*( zisdKccaw=J>w`G=%OoyNrbPCact7l8bF-|1sa9e4QB>ojn>e~zycyYrcUSVYzkNL3m?Q6f8XsSWcOqZ=&C{ze?65=R1 zkVwat^$HH_{#kNS@Kr3_6&2&R8Pd0(zqr(hgO`%+1eRo;!`YB8$cQU%=q~I8ecQE} zoZ)&vpZ3YxbLtO;4qcpRrq*1`XibZA0~er$^;AoqW=O|FqDw7`^TUbb0N*~S^96sJ z3=L1EXWJ8Gt`yap?i49~dvT#(o+t3Hf!wM-3e+)*e1g~Ydw^g$qv|JgxX5xKzD)N5 z_SJ8A7CAswujXpvRl=}(+<=3!(X1=2$YAxq54di>?pEsa|15Po9x4G&4Dz>HAALb# z9v{y+pIxMoy|plO;l}_*Ia1n7g1rt{xJy*;uo0jADWs>e6)gq+T&L{9SEu(Kx}G`* z;ynnO2l0%kFL~ubj$(uyYf`UcmIpa|*G1B{ecWq zqL7D`pZ!vZiE0z4v=2~#FoHW;Hb zzngbS2g1H*5{2whYxL_yYn59dM*Y>(i$)`LQm``B7R$)iKPm7>vG{Q>rkKNjyGqR3 zZIM_3VwBdNvslivmg;l3U7qUsCmu7xJ{0f&Zkj*)rD>?Nd%V)8pZ%}|M!`#1Kl@LQ z@F)ylx;R40!Zd9qQ~+r!URw-fdOCnOo2auwC06b?tCttB{m$_y--oP-9(EB8Q(z$e zxUfZKpU!+(KqbL3W)I#cji2!H5d36Gh6;#73oBTiV%uJwoKlz+jG_s3HL_7KP<1c| zbFiW!B&V>I_FVELU(A>erS9#OgjL25@Av7qU+zp^YW%Q_ZW)4RdJf3iB>K8fE}r$R&wq{E`qBK^S7&m5x=rvc|^TltQ<4j^-dbgu^g0p3eM z8f>CXV=bag)RC-V0j6Q*Z5o*%wuHk|YQqgbpUuFnw(WM2NC?``qJ);hoJ8-hfv_oj z18H~%o%nfHSq$ZgI0$Pj2q@XnB_!hN0bjFlDFPPEPbd0TXG$yXnCBqCOESl>UArdw z`1W~}OmSq>DX1$N9N#r?XzNs-l}8t}T3oG{&<-*uwX;IxrHVb9t!imByuW}P#0+&1BY1O{f5jS=lk1DJ}f zN_f57%#B_3Jbh-p1NbCrniXo}qp2%K@tv>5Q)z zI6^G+@{YX>Ai0ynQ8;} z22FpyZ1o$SbT^%K7^zNRBA=yrVf^W|r_VY?jVVf+O0cCkdLE8$??>a+FE2E{A z3e4uUmR2>7o7Hq4H<`dewZR(XufZpXXg7K(Sjy{J!36UMuxpV{d(1zG@MlI}MX;XpF*rMrLpFp?NQ9Fm{mYo(F2o&xGHs$ zAj2pswOd;GcJ%B8qI-xKDm-TNk6_9UCX(P1m!CoWNUrBp9TwDH+K!G|Ea6(X9U~@> z$n&!QU|GzZj8meBDTmEiZi{d!xM#ylnCi&(eO~%59lie&c6r~pdfpw+){4`TIYnRa z0QxuDo;ZdZ$xvSKSX?yG+OG&|MznI{IV^kA?21o#zGvO>Pnxiq!9H@6gv(4nvs~Uo zGv7=LV$`QgO*IuHatz65k z{P6GU>P>@jO!bFhZ4S{JA5%7uqY-sjV)9(jT!}|)@#1`b zXyR`8h)01luy!x#DEvDn7ejoNB8Ux195E-NSp7{OBbv9zR4{;vemx4qqkf5NSic%Ey6T$;3*#2RwLl<^OMufX2)$Mo2gl#eugMm()`#YdYeJS+2?}=*vAIUGZm`La%aEIu zpbITq9H`(2d!@nmU?f*PAz%JjRd`w;?=`uuD#yK0iyBaca)Yrh*>OI?toSc(n_U}JwXU)!8#BM*Q-1{|# zW|;#8c4M!T_CRw*QS>jw2Tmx?sqmo7~;-JU=;Va%-)roJnQCg$=B{skk=`y4Ja|qHQ8g!h8%@+DVyi<~ZLO@Fl#&NzybHDZ_g0+qHg+)*ltEDutz($LHj{K`ntFA&Jrq zF4RE)?g2jPHW+BiP~eG~w=(S)Rj1kw%kw?3sUXBt!Ou`|3;?-sVuzYpJ&m^SniLuz z+@xJbab=-Z?kNZFr$IBz75pt@@Hk$ADN!D)YDM`2dGSD-D65rCq_mmZ5q4 zjI`u5;3JCPLIN^fa28+BhzYD?!=yzW^b;+*(TZVu7Mw!N<=j`bb=nD0DsB(aqRwMe ze;QJHPPR>M0n;=QdJP=-~C|pfnuN0sW3|p@Dut4hyl|#IW zDoQCY19Vi0akyC|OM@i@CZ#6c(Z3f!LvOfW#6bI`30NzFfFZUsSJe-N0YfO9)C zY<|QIXm3R!c3Yl|r$ex;45Ioorriv7e?6mMIVfp}*KH#qrcwdJtw{zwx;?x(Q8*LB znHUy)qb3>DD)#e6?*5QJe*5&8O5@Z2YChnQIUrKOV!RNGl%tGd z0sLw}Mk}m1Sb)VlRa=>x=Q;fo%LB);0V_Ev#SmQli^U7{>vNE+)npm#dUm<9cN;OO zP=_EfX%31Z(6grzW*#*7_USd3XLV5=kD=@Hu!3h47|VD_>qj@qt#BD}nfilqHtSw! zJ16HdtaK`PceB|jc#kS|pumD5X`ZD`C9N#_dR zCAM<>kEBO=Q0!me2{C*8gj0wq?vdP-ZgTrrFM%j9^=&cDkYvky?*f$L(8=BLILFAI zz5I4e9*i|TVz9+2yi=CFC}O^&Z<+q|Yi?nYEu-QHn{8oSg1fs6?gY2sK_*ym zXVBm>5Zv8@%ix3%T!IH@a3@G`hXff0g3HG__q^xcZ`E4ezq@;NRXw}*-X+Cj9NEK~ zizB!|-aM*{TIZ1e2t_Djs2UAE4A`v&WvoIu!%2wdLTr)ZWumi@lD)`7_0<~>$@{vh zzG04cs+kWr zW(B<-C`l6wN+-DK_tRZ8>%%3?DEBGsZK~xK5)^&+Dz&swgU--~VKU_jq`yo*@e_WS zIdM}obot>s?BwG&98>WKN&}fr_zsT~T*yb;PI_F8>|4$QwKuI4keX8^}pfu;5t2ZtIK@ zQ;uJj<@uSYaRs64t*|h{(^PX)xj9D-_?PF?VoO?Yn2NyU+ zBYavn&vF6;j~F9KtF$kUVynB2rrUBJ|FE4-LfLMu=V9Oid1T^Fi^{;|ug*p2c@OB0 zr9@4R;-Yd+7oS52drLky??Zc^3Y4xPGi%INpiD8w{-7ir7n*J>uu&t8c({i})3y8i zhFV^udrlaPzpKyJ%kL({s9n1d7{K-Eb_O2T*xje|$Q@Vs~fl`rR93b26*haRn+S=v1fU~dZgya@i#=TZLoEgotIYBL0v-*4Q#?(@vF z4c;OJZtICtmFEAWK^7$_e{ZjhLZ(pOr6ef5pU|+;Lb6ugAVkH4k?uN<)X_INgu!}k zjuHE!zA?-J=~}C~e5t>&7F6MtWd_R zpk+UZ6C2T?h(!=)UyM&l%o?epB3pvbP=bMvG??y&NOr8So^j@wHD22ocw+r9F)z|} ze$!3Yvl%QkebKO5epc4$I_6(^88m%)VtM*w(ahh-32&lwLRHeX`G+ytGm20>yF6IV z|C9Ji35;1P6s}Y1Y7^}RH&mVNWlv=BmEKC7VJVbZR0AEQN8+vuk6>hpleCAP!`+d& z>Js>X4;aAglw`P%#?M^@pvMOn%Ro_=KP>8J5KO z;xgrKPFK*$zUqt4fs?=zqR3Pb`=;J>jqwTv9yS?v84g|_tJdN%yr`d(eQTl0drl_IQ$cz&ii35FHL*-}m1y$|=$)!|n{0nb@G?=3J9>^^DtY7gHAN-r^w#Ex zu6VV5IkBzeDP>ov$IjYZ{DHMKBh(ah?HU$;JSYtQMuBC z*}i%vI5iR`RcqEhM#4R9^7Hpp1JiovL~Fv2Mkd_*F75Jrr!p!N-32w(J)-WsY2u!( z_fjqEJfLp(5iK#6q{e@@$G0)b%^DVZ5;Ij(qjW=kd?38B=chZX!_DnZS5da@<6sGN z@&AtQLB#tj%)I&MSpS=|$A8JS=Kja0t(z{cJr8CNd(cUf#DjOf|B!e}yu0@u9IkhH z1U5Zz^O>GHlA?o#BO|Yj+rK8xJ3#Wpd>WdjkhIWr3)+18!J4xSaGt0A!Fgvt8DJLXa)Xwcs1wB;x%Q%4}pmKbW5*bkxEXz_C|*w#Ot-z2!WxO|zxrLPu& z#;30~e$LY}H;F!}k=Ht!993c*BRkYf7}FIl)L2QI_Y^OHyX50Uk$(QOW%Eu1*^*|zNA|VOS*2?gR z;zuk9E=)7#2K`w5S@T@IV9zD^ocid$lNt4ZSr@gj%*Dd$sVI&H8z0Ufaa zME|D}D0WUa^1Bk-zjKZqDbmR^Lz4O^%8bYBo)wyr*28KC=*Snhey`Ew1UQH~|IPXu zdqS9@z1N;nHMmGK2Zp8$DCT(bI}mkYg*x`=4cY;CH>X^eD3L$lpEs768dOmCNFTCY zQ$z_5tdE}JUj8n|KoA

3Wk8AWZEjn(J0}cQO{~Gf3kAULo+=-f`$0BXH(8able2 zLk$?=Ch}{;AL=^Fl6(I-&K7WzgFJ?&w>MI zkw}27jbq%EYE9LhT>tRBeQ!whJ-6g2F@NjaWK%TCcEXN=$_^t9uRrZ(EEjp0px~fb zhnR;CQHE3xpJ|Mg%qFBYit3bh447axIPIbj!rfJZrYWQ-XSSDA_6;;rVHqi^`ADlE zZ)6fh=6qu^qpS@J4=x@OJpfGQ`Y5e@?JYtziK&xQyx?hP7bE=syi*;jQJNGLywuvJ z(sz46AsL~dWVm2O{Xujf#o^g-ka083VrxGn+FPxllL&cYB>uL4h^;L6^@!nZ7jU5& zG>EU#29yn<`j=2q4sl}OG8!L~{hh)gvZZyi7acX;Oa7-83oPU_4xU#SiVWC43R-3C z#WXI@i6`GHmTcId(tq1#th*-p)UQZLIb}T~@Zt9e=RPhjZR}~%U3#H|A45B~1_c3O zX*~<`TC)?1azTjovlYu`09kYx=)K?0rpGpux6ZxS91o;XMZa2KT1BnHy`njuVUQh- zYyQC40{D~9cB0Sag)boc9 z3Cv$po{mrOy!&Fa7fGyFL@@t0bX~dx>2{Aq2t@@Iz-`jk!-RX&Gv-VRRPB6t48A`n z2`~q8e+bVEy&22*i;W%b{F~01+z()PV8o2=nZ*m@f_(uvq($tO5cV*QZ;cTx?80!L zTE1V?=}-oXIXv3}c(KSle)0BmeMd%^$KlsO;|aRxK!4h52iD=KRHm>prx0_+=)>OE zjyiNQV_oh>2aKtMb0(Rp^l&Tr7M&O_hfy*5iMh$DM(egnul6)DT%i1L5lG(tu*?qm zXUAgHRwL|G9g$v~k1a$Jt0DCte-{?E&_F-H*XN1X{;>k1ekU>(IO&M4A1vCn{=OJM zUm5k;UK_eTdDiT7JCn2~x3}TXlNjelCQEF?0^ZFsEmhO!!PkZYixpqUC;KSMB(;=2 zE9LHmgLJ?JOyQYK+fbT)w)l`3YhxX6qDK2PhwvbWZqY~2w9yQI+2dNzqW_645%-X8 z`>?6)8%xm_SDB9I3#Xpv>$=v~VAz1q<-w^>o3vy6zRT)rPj98|5y7kSVpL;56vARk z1?&(dv-+*?@6|E&*ZZy6-?)mvbqYW{$nxzm&5|vDmptC~a-o>ZR-J=DtLMZ(nEEg~ zMHT)uzbt7f|Ki$mtKHg=gr8V#3-7vp8<`*)Vv^l-_>CTEYv7^8rh{wOwXOeMB$?+B zRYd~=MSeCoc;%V?xwP|8;{ULkOxQB#dv>u-l~BRvXgCOw)+eW| z5VGh0S#Dk%d$?>aam>OBgH#iSyMDgdvn#A2yo;^0PKbKPvEP<<_~*ed{>zH0Gi+$n zTCKIH^yfO0*)SwhRZR#mw-G*0c~N!&b@_FjXgat;kUQGyG%GB`$Brt0I7z9WU&Q)$ zr=F)bbVtY5CPkN=F*N7W`L&rlu$934PV zB-IS9?i^8OvOn3fOhZF_LiU5~_lE@d1QQW#-&HyrO44hthyjZ_%Nr_&lQBq10*doJ zs3oHCd@K09lc;@-LWUZKFqqzNL{|L^h_7xhH3<+>8qr|TGW}BJt6EVntQ{NMGMZ9O zCv6yl^r&@OoN8Qrb-_#*LG3%p!r5!}A-rxZ`d@#*1XHI+Bv-OKB@!rWDq5)rQ5zO3 ziqlB-tb-Ymqr(7Shyc;_<2yqDaz44psHChi>}q-VGB)HdW7>~pg~6E+V+!|zFZAc- z!Dm)@Yf7jYV*r?%7y+s197@fizK+3*P15Nk+PvsOv`!AXptm27O*A3K^rf9HvvaP1KEpJs1tuA zT&b;^nOALkKbG&(2e!c@Um4=zf)!P6SsJ^F!OrI2#@yFN&o06h+YbwK*k$&lVFhih z%-_aH71{hQD2xJXi{{p)GqW7lxrtZku^C6v?RO%>bUQRA$Us&!7nn3C-`H>pLo1&2 zHZ%-j%)n_;Ma7^3BcQ7J@E0sI^;oRxW`@2}cnYmwmPh?*a~lRaF{mHil8W;!h`W%x zX-icoah6A+K5>z^QT`de_98YUcgOtG5E{b+4Op1+WQ;WE3M&R~ZA*!}r&SnYqwXOz zYOeZ$8E{5zr>pxm0*~!i*jo4jWxb#V&;Ji@rn+12DN>V*ik*{z4=y=46k4YM#prexbhT*p|#c4gNnpy*PUJ1R@lRa_Xf4 zJ^AeA2Ty zN9U|u+AW^z_1eqxrc>D>OXOcYuI>LF@f^`NZG91K{~GVIm{xT%Y@z~j>Vrv0AH?{G z3n|l2xeC~p$V^u1CMD(omtR&lSEu13myTq1v~G|wPyIq?*RE$$9$$3)Qghccn0;C+$LRx0dMI^@}+{gTHl>YNJwPZS2>=1Z!U#C-y|{K&BIWb}+O)65n#hO4cD<#LrW`uldw~NbT|7+5P%QoR(%z_OewF^$rSe@}Mx)%A4 zCk%ASV5vx6*z-hIDEMLHnas@yJ|w!=7W|oub_OcU9DmBQqFfh0wSJ^b4Jjkvm{t zjev1b*NdJnh*)gE9v!dV%CUN9qGXV)|D$zw9N~^*TPk7_%fB=cxTX9b_tuJd)Gs~m zeJa-JjCdUUlE->bI=5&998e5}uNoc({IqtOe3XeOv(iERb(c-7{i53CU884o$5=tg z8<{QKR4MKdtMY0^#oUNKy0sDB&6?7)<;j280?UuSaf&vS?IxVXFh8ZAtoXhpc7vO3 z1v?fj*R_tOK3zytkc}}TN22YDu~e--Lliyp(ZB4cG4UjW!>CLf`fNY=f2Y|hQj1XX zvd5ojVsgU>4Tj|@A}%OTWJ7n}`_uDKUT_WnDCkY)$>TACzzjZI2nJvDb1O4--*S=- zHc;2Ja^5nz#E&SBMmZNZrbQBI%Smo`U?|;Bjr5*mm~N+YeTfoHBQHc``{0*B_b&m6 z^>Gb5-E|w&e22gsriYdh?xx-mLKp4@d&>*bH3YbBWiY0AB+f2#MZ9t8eY5$=#+_0_ zINo^2QY1(hajvG4Ux|JKMf6G0bAXZPSjX(C<+Mf+DFB^}DL%X>B5T6N9TJ{ctbr#@bea?zEMA{|JURGzfAFh4n=Y+h0k|#w8*&qs!yb(iggzoEsAYt zXPMJldvMbwpj#wrtVvlv2{?x#f8OmU zdYag5_Mm#S_LM1V9K7=DLPsm81eGy~f4H-w zDaY0^4*-Nv`0uC{YZ`gL-^s?82JqwZqohwH>~i|*_^`{o$^8DFXaA~cBD~In=)0~L za{#H%=H2M@QwPE&1p)Ko_7&t|4U8aHB0?_$n`|YGs#Ml9O z`^sIR=LS}`-tAu{)pk=4SzUDnn)`h>?eI-q_kA$TKXgC6uKWlFDNK!fJ`D+DQNwOx z0zm4JVchsv+aMKMb(;8I8Bp1ML!XSZ{!d`a&^NjCS%!k?vMl!6cgU`f&qx(FZT>Z{ zz>e0R{~xf!_PP985RXp!(W%uX7@pj9IRIY0>3#{n-guyM}>xp^& z)x5f{mF_2K-YJVuzIm5#jAY$#m@1wBg)LUwaGWx~6{;GMg{9X9%egRK`vN?d&$LK%!mpJ+!!V?{!xJE2+dujbZWR?i1y9QGdsxhEcM^Ay_X&I0<1?(UnHC+y7E_?) zs5I768&pI`=PdHvTxTzfC);XQhZ!PAIa|k=%Kl>E<2E?fh$TO{H&gJtX zC;f$)ljY8u%Fp$>-i@B?lZI?2O#neZn>FmMKvWN|i>@5ZY&eXF%*{B$sI(M~bf3NR zIx^2AN{2OahywBQ{y7P+wPwm7q6%@t@x32F`( zUC>J)ap`2l>^ZIFuUXLcR=y=nt85H=Y|jyPD`LRPDl#^rqw0+X0NCg)Qk7uzE)SCO znfqYs3*AAj0ec+{*Qdo1)?le_!l_)k{Tk=Vwp5gmP6L+Ph_&O1B=waa$z#?S$x=0NVWL6XK(}{qHR8KClHJGRjupw#RX^zPxZ!gEsqiao6uO!-`UV5g zyVzPOtdqAijhmZ#_AtPAsJvazsIWuulzZd^#c*?Bb7|=-{L(~qDlIX6Gey%(W**RO zy5sk}7IexCTt7StOhEHYsvxt&^ooAQ4HHm9{M}KSeJ@flX zpDo^})jzTW{&An)UoOGw`}xLG4p*+oUR7J?1dHdQcp?vl|7m-9Jwy0Ie-5|e;o-gf znanGE+CA^O)O<*6?OCb~4rp5Ub6eKL_D&dSbKGZlt8U)U82Tn`>#^+$9lt6g($w+{ z_~1!U%Ov6c_P+g+BaI#HJfV>-Fb+rTQQBF1P{E>6uclq#$Q$>GV1b zkwGKhrol;b%9!_GQ_fvC-viXnwOj6dM-06*>Lc34;uC^~5J!oS+;S}LW4o8e9RA|X z_{)K}Ws^`(J|f4kOO1e^hDXgR%?hQ)Oqeqfp-kTMPomG{S)&+>U`e}+KWwjhnzcLK z+he||KI@IwY1yJ{ppt?9DMFHw6U!T4{w;AC@OLZ9gLZ?~ZRt^-n4lQXX_$Do?F|m7 zoKy~<235%|6qkgal88^9^c*p((Vf!O(2;*z@v{c+o0S?iI>BGOyBHf##-xQbI`?&) ze44^9m^G9i)}6`N8P_0Z$r+@*Is_%UW9QU=sY){(u<-oqt4u~kQ2gTZk4hf#`M)gk zj1e=;88jmMg~-Z%X-vH-XO49@L{LJ=#1aoMR}pj{m(4gqUlAs9Ykmw><_gNZ*$M*? zBgl)RT65P+<4!R0?AwWN`D3@D5rIW=m3FVADl99d`qR)}wv`9tl&L|@7D&M(-DBBp zpNl|o)JB^sYTg8ff2Ih-h2sDNdS*k*%2#_b2yi*bC_Casi3UHnms2%qg?7+NroD|Y z)+)jHyXszZ>a|~(CR$`*3^f$c7^IGqai83k(YIgWH=jF8?yjw&I z_nOQkw+ULuKJCL+e1I~QR>6s45u)QgfN#F%>YTla7^GasFxcKt`{}e}SI;cmv zO%;pF^M~ew)}L?JgNCCUMw-HtLa_6yu7g~yw&ca6ge;(id{zAI$#kDh z7Alwu`|#$R+Fkv@?sVg)e>#@?c5LTTfgJmEhIjya`PSPVk<3&mQs^ov*U`Dx84p;$ z%R~6$$lqR|`>7SnP!a+-*=um)XRs`tmGtJ3ERvRwcVJ@j`?w-MRygGLOoxA6&-eF# z8~s# z%?XPHdg6dh7G{OA_OP3JzBlo`v5!XaP@+-ZD1)ao4!-7-?$sgNHopuYZjk7s2HTUB zN8X(u`)D8yAdjQr^yR1VLgJ~AO#hU}SfAI*WPZVI;;fDWdWk9nIO2Gw zQBx6gCHyF%r}xoX)Fdptwz?5v@7jobcAc7M@5pKg-HK*|D=lM!u?jM8 z+K7HL`6ml2HH<&`wu3;=K?y(vY;5r5m>$lbos8Wb%+b`dkpT)UZXuJ>3k+PScLig^ z0CG8y`p{9vD#y0E%6^1lM2wtZnHG)F)~ecwK9 zXcbScwOhnyru!L$EcmYo499#Rhy69Tkx2_!tk0&{w}B|g#E|{{aHME0om1+C557;t zU+88(-xhqRowLb_%aRcNk^Y;st#h^6uub;yBt`XMIJ(Vf_}jNsc0M{w;zLd>5QzgF zY!I)jGDRq%)GF8r8HCx zAvU;K;9*n?H;CaUY<0P#7vYR8e9l5DDIq@ZpT|U2V}o;Zpm)RKGS3^P&XYg_p1VS4 z1KiY(WTY$;4~5PM?6wLGK3WHl_X-KUJIp+fXm=4ETiisF8Z7ZFLP}w!e2<)f$3w=1 zfK+8tdPHNf+H28~$d)bwfGBLFpJAR2c2Jg z!RAxE3AXmgdqES{#Ib|>iZw(G*T0Bshsb#Mm(9*w`&Kmd4WcmsWi0(Ph&xWqQ=|R; z2p!JMUCa3{$%Y?J{PrAk_U!%@zRVZ$W#m8}NRFF_(ij~zw1WdEpErUra)Dk?_aLu7 zO6i=my|5~}os_UI^)JG8m;@^Fo&3N-((L_5z1{f@95?JQ@{6meRiYn<^L!5P?M`RI zcdw7_M3}Pl3%kFpf6A(pp67w|pu{N-qjjT*tcv^zb#4osAlwa~`o8T86}RYmZ7jxr zJ$p_ey(%AOcG9G+>9I6B+=@fN4^|h8OGU9!-eypkWW{`;UFbsa#DgW_t4;NPqt^d* zHSa^bUtKzTg=gwq);pen-8UQlr$1l0S+%B}i)WiZhhsT8Nwc|+uuOxF`W-%NiE}?x zG`35S6&3ccxJtOVcR6m_(RG!Zdnecw+P#=qSAA|pZo*p%Ic;;zH(%+@*-IaK5(HjZ z25i0S{Zk?qn1DEnxfBOd8l`6kJkOX{$N+*b^F1_HapNO?YVRlNZ`!+dKP&nF+t2!~ zqhC9-^cimQuWDD%HOOuaF-iItr>M_2ek9SblxJ)4O&qFul^0Q&oAs-&7h>Y`Niy@t zk7!fD@77*0!k?3Gqu^)%8AXVrmkhYQH-bb?H|R7BP>6r)dG$)bI+?jo!7ckt%JjeK z{lAhtOpp3jSZY``hZ3f3TN(li`--SrTDcVM+~hf>TF9P#bzdT&Z!Jh>xZ_X|SScfPk;Zqzi8vi6`teJ=wwDP$>| z+1wUp9o@M_cjkG++a<+t+8vLqD~+$LuIm+(^=bWJ8BA&j(@3R%OPM4jz(gnb$N;#| zJ2Q@A6BQD5C}Oa>r5zwSE^$M+u8fil;-AA(yW{80;3cQ=I^a(B=Ffz2aAyXd`JdSk1( zFfH0exZVou6eaM^EL(;1JX5Svm|n&#h2D+Aj$(^-mBbnSu0Oi{rX1OPSBe`4v=7Ja zuB_ni%@k#Yh#IuC(^`cHQz{M_%(u*CGG&FUQOHz1r6uoVk#aT)E57|3qoxqXM<1R2 z0b#vZ?Oq*Va+I>cm8A9c)=bCjY(zB{e&$W80DN2!AykgKNWc!W9+Ubvgv7lu?o8H9 zk7^-DIo9U^=dpK418*o&v?u5H`onpVtLbBTrzCZj!kXPjmP~G$0x54Yz_}_-nx^$# zR>XiB0eYvjsI1e>mRJusAX?aqD%h&s zsm43|>HLYoTY1UL6f);yoKJ2x2tBFOE$xejAgA|qJlq+Lu;$l~i-qu8F)d~5TTka7 zXMoUkK}Y=<{+HEKyZq`cG>eAv5K09#Cuq*V-M3t1xT;xNpr;s_B5De zUhTs*WC~Z@rwqp6uO4mnA1u1x>!;d?F+&oB&OS_EGHY((1a;$W>Q)T(yfsyS5!f6? zTzvTtf5Zzn02MtcDXCl0{GWNy?dXr-gETyuoutdxblP(n?(>q0wU8yot|;%dI!E_8 zAkCBDo*!rjzx5%zvHhe-x0mFZc#wo6Tq4okSm#|Z5L14D#5^tOnk`ah$7*^XD4h>X z@;nf}sV?-u$lpD(MoYOaGYlDz)7Z63Ky+NG)Wqc(1XXrXw5+d#{0}NCR>ygJ*18|= z^G-9C%v|;P@+A&`;0Zt7`osNgQiE~^W|YxIkOF>BKQr4cw;ky`L|p_Xxj~zyqhU<& zyDY=4m(A^^hrfk`%V(Sar|T9zkey;}(1BMp5nZeUXeL_QZZ4nd_=Cld|8FIGk)<|J zuQ+#*bT2WA+t&V?MAX)h>}{3D)MlOF#yEyT9C@BzbKqoKNh_Goq-5PTV^I>;#hPHK zhx14tlszaQ$ORIPyI>p7A?`FbmbXZt*34Hm?=Zjj%~**NtV}X0lr|?z3weJ}p4(?k zJv8o)w5=&A%y^dv6!U?YZgw#FX!zg2j?>rY)xRFHJ(7{TOZ5lzqinXf@5Y@-+PzEU zq1^bk02T7-FDpFJs~_h(&z@9}`3}YjRnK1noZdb cm6o8KVDROgqs?)rQscA{O1q%g;GjRcYt^RFEe&mJJkXt(dcR9-=%}J^gy!;~Vva^s@9n+_6W#3gGZm>^h=@{!4))fo zZ(gw!G+>UKujKsnq$REN;dG>QH_M;iG)nO9FT{htD`a}{v}#XO{=ri0SCUQ!0G1&z zQfub$N{bCUdWVIdK1~F}mwA&W3HHp6MYd$J zYP0~@UB#3s1deK!Cpi|Mz?(|6jj!7Nu0v%?WF+G%*Lp}M5&(aTX7`u)I1H-`|FA#4 ztwf}ZLHp+}AQ~$A*)|%josA+dl&=5AO*;8#l7A(W#6b`5PT-d)t9mSblA&KubFT*H znI2&m;j4AS;1Efr(7}+*C-G2AiV!JpRlnUN|MBTJh#%i&LAfGSeD>+?=ri8e!zMmM zhC~kZ9$(*%pg3}G_s6Tw-PUHqv5lnqA?wb+f7-L@B zrEaRCB6oP*#Zn&Cv#bn_wX@l++%kqI$YB@Rp1WuyrgdBx#gIR#WTCPT^4C?jg-m~K zIL-H%i?sii9#6l^%R6aYTIj8YUZKN-wewogyWR)&nixp)q=zacdTu11{zko<6eybc z&MySQ;TnH80NU$=-`qsZr)co8E;_1l>yvF|^JpVL;6#Nd^;tKb0tuf~(BmV^qyUNt zs~r&Q%^y~~yf1-oI2&0FdO~-@&_I2Um*{5fnXw4YJMgydBPmgb2Hu=pejdLW*-l%l zadfeA^OOr7#_U;5CCu31F~dIk37X>-ew=*r+elT%?bSg?gefa*K}3EdY8#^4Ii)af{*y^M76`onfa3%K+5qAiQT5&u$u)bN$$Ee7Ca5gP;U+|c|5-A zfgQG|A>OcFClfwPNh_@d5}x+%igj#0LZUKM{dImw@frF9FS7xi3>EQUvDxP%T&uQrY~nH^h*R@c$qf5NhhwI+GC}l-6)lnOx zN`pWTLSq96(ehrJFC;#{oR#VxEk-f9e>W_{=}oLZ)OjE_2QgZ#Ka3NmjftnU zAV4v+tY3Sa6N>(9VNS|F(u`Q+*SDtf(z0&+g^KM;tM?ay); zkAm)rzixe}tVUX_y+%)tu0S!WUB+KZ{)8?0Y%SU<*=xG`Qe)d4e<)ABNR||0L zu4zS~?<-j&(b`)*=Y)aK@&-;a{1c>1d5ZyL(#Fo%xYNwVLEGW3I(c9Gs&-!1iFpzW_tRK}~myEnIvPvt~6&#kN6p)y5WKbj*$ED!br{YTCRHmg@LT&Kzs~)MY=#d4W z_7N5T#fF`hUk3+NiCDacyRPY5WXY!N6<+$q;kC`;JJ3>M^fPZvVY>A^3EXF*ePinL z8>z_#&tL?Jfn{2Ck`7WJiem+hwdCLvT76w6)97vILea0=T{fs%cCXxlPCtnLFjMT7 zAxF%X$pE6q5$mQzHu;15{668CnfejMxKZiD(G3NlM^)lx0j-`$=Dmd6J+T#=uh4U7 znuWDJYgCkfqSo`G&DZT&({{>luVxmXQpzLa#jeyCz97SyTYsX-8R<;TSW$4t9P;lG z{mvIgZDSmu)=TVh6XO<#TL#YkYB)>tc{fCf^J#Hu0W?6QO6y>7kX%jzEW=q&cN?Qu z)~8awZB`~NxWwPD9xK#N=T3E^cVHP@nNlESQQ1h_xaC*TK2H~=SInuuAaR5r%J=qhrJ4p^eKF-V49N zzksA!Fg766PgH}yl659R%{<^0YfB|Wg5Mt-RnVxVROyd!8=7Q8z~H9}7X-6_rWvFc zE>?O|8y)*D^guUk`sc5;UpAh8e8601G0(3rh(vs4!x!}<<7A9=DBa-voR5Gi4hUCS z!c4d1H)cHIy14m+KK}@Dj`YS#VjU+>Mf7+BSyUwH65o`%o*!ate-&t6r25D+HJ%=_ zJ?xYqE;f2;DKA@v9vvcQU$d}tTB?!3&t~`U$AO^vdn?+VtRa>lH7bjK!N>gtGU|&$ zugn^EPnoyCeW(*gI<=avb>lY3#IBD7#$8VSPtFZFI6%ZnjR7kSLpg;FfdRjh<8xmF z4L9Sc{8)-9m6^#0Dti%y7d*ET=wAKTJROvH0k}$puXgSC-Ls4l=i5(azO z0VOvGcnuneDd9n}GPkJG&XK3l7mcEfv&Ez`ei<~uuy7rLq$B?q6hQCe&E+WWE4}ak zwyoxqp-oN7({!{gFOTy;nWurm0H2?MFQ?$&c)_=?>ZirT1S&EvYRK8^Ad#+_=_}b} zHX#1wD6J~Fq7`U9cpKKBPdXJ$*gDfGt zM03BqNoMZ2dGPIe$;>~odo{>k z=Gam4BU4mD&WTRwY3G#Wa7B>$vnG9T*f<}WTCfaC!fs>3=8f?{`zElrG5MM4_66rL zu9v_q*yn$F?XRbjBf$@6GqdHF;t~&qudjELeq*zOsgm}DlhC{FKV#DWy4M{b#BBhN z)C5(>Ba&kC9Bpw}G}rRs-)9!dO9<$}fp|m;14Nml>`>SA8QPVzxHB4T6OyDqbo4n0 zrD$ke=Z_4|>AStH$Y8Jpdc2)LP3rdOXt@NPRJX+UbM*;`=)+`$P?~)Ly@8NNGhf{4 zEZ@|cpl==j&Y^)bqm#{mO*A1LQ5+gRVE)$Eqyr17S*tT#VmE;tsR;eAUVNA;{3^-#s4r4t2Z#LYb{wVxaeun2FilAIYm>;Qb+ee(z!UiEloM4Iop z{5lr)>GB*DmpJ@ouKr7$oK9Rge_VzHAH|a1pwYkkYz8+Nb9I;JANueK+ssHiit>4G znoRm|&LiR?(w$+dOW3SMvd1zB7^Xs?RqJ{B#|Hli{gJ5UhL%%82YZj-%f5a$4=L7t zJrbjy#oIHyV(TATJmp$Ji|Df{3*sqn$6dDoo9Q z9XV{b-}O!@C+ByEMqq02HVM3E2%lM#636pIq+XJ}|K5rp0ikY}mI;$Zp}4 zC8f(pqy28do_L$YsKJPc!cH2T!Lr$x5kdQd$F)f?$IjCO76>pFpcyBZfR%-Ql(-|P>`k?_lQQE6@`?99 zria(>>!-UH0bJF`3BS!Sq5b;kq%;Ua=fY{>Ax4z7QC2LC_x89)cJRY|LTaiu#n&N; zr>DS%9Egeg)l7sq`-PS&8~jb@;rv|tb?cW`@;nkJ7t48i{I;+CLNa0c6~C{Ja)cy{ zS;E2r9rXkOIm`(aVL)hWI;wPS{|~O8Z}q)N=jVJDB%#OS&tt>j9o;l^YK$+e0t~ig z+2H;=0W)qmB2b>m0@`{SUeU|(9jBr$9BfI~Ese?j#m75g#OOX7OLS^B(1Kta$tE5-A1%zvEr)=p>> z0)mV;&7wY8!M-U^SiF73T6Cj2q(%MCP|I-u0^<7FJd_@9nTa6v$wJf4uGPWr<<_cw z6k|BDUxzCk-*a{~-=>r0)GSza>c4O$1I0ppIXOolndogWM%Bt?-(6FPQn?8Mp5~ zPA-`{>l?ya1{|F1u2v~}QlhO%UedgS`bXAMDgt4mE-EsgsNq*PdY1Rc1qn`cbyUvO z)-SHq+io0_=0oQ|_-5o%rviB0S?v5Nn=Slqkl3Y3^D}MjJUcM^YTv-i_B((rzo{wB@Pgva!SN@+ zo1NI=f(Pb00KH6w@MUnxiX+^?JNH> zRog7p)iKAC-Vs%*gG(U0`Z+~1Msz>0X!p+sKkuiGe9MUa|CoBKu(+aaTeols8X&k6 zDBKAS!Gi}#kl?Ptq42_;BDlK~EV#S7yAoj z%3b`f>o!Vrd3u6T)=%Yee&+~S{{vW9F2g~D^yWK3$O_*DMqh>2oo%h&!>pbS=yYwv z_140r>f|KT3ZF&Wd{_ulu`Fa>eTBbVrc_?vj7eUL56ugE_@(c|;e*mv6RbSRv<=t3 zv_bbiQ=RvTzl3dv!lV=7tQrU#s5cCSHlkAdfFn9z@Aqrc1S zI+=grbV<>`w%iFDNs2v0yP8OlbeVmk+y499_@u$vp$XXvv}xzY@HHpQ9{lWCbe-}u z;N(ez=(-VaBHtKVFV!7~ZbH#Q(Jk(uc-@Ein{>xa zyV#+gZG<)s$?l#QY~kF0sever9*^J07TB!&Qg2V*Y9d4d)Qu*&_iex-hD$E?YZ&Po z=Y2N(jH}xtnxV$)C*gTdIZ8B;msxn74zR*_OAJ_EGk$NwD2jt{`-$y%!6H|9CH6Zq zmk9W=`?igYV4~OG>PkgP2`}>9FF`3IgegPl!{Jk7?ifCID_T+cdQ9+!eDthj?SwQr z*9GNKm$s|EdKTo{IoI9rQw1jlUJPk;P*<#ex-yEi-!)Wj_9^*`lV7{cp|}AXss*8wZWH<4)I_kKj50?#xnM;5w8XhS(g}A)dth z)?^4Cl_(U5UVPeEW!(xtbyrR7HEaiiMi>DTjKfeSQJ<}(RHOjHYn{P z8~7Xc>^>hoi)mG~j4AkAeh8a=k}^=ihyz^gulD61d`JVLl;^Wi=I_BSoT)-#*k$e3 z3a=n`if{{(=KbQ_m`n%w(uW3*XPB2e(o>%K5brKUe$cwm+p*lqbN+C)Jt&h=A&=iV z&V47IhhgX=0Xk~eN2H22nfCGeKBx5ggoU}{Z;5&r)l78Yqui=vRem_>kwBj3pz#4w zMNd1pF5^o|qkNGsdLwUm^Wqu^%}4*wX}?c$FN-nJuDz3S^>%*xA^_fAy0JQWyg54N zeKVL2@!qtsK^xN6Kkb_2e3Wu$eB|BJ&~-Kykra_u;w;2*u73#VG*gVQ|Hta}iR}9C zAu<7QGPqe|;bZt#eV`Hia~f-7kxxe0 zBU^9#YqQw`x{@z|tK{ZSV$E(YoA{8JTVZ6O z>U!VRL*|VBGiPzacy{6K$U8Q!7H$pSe2TevP~-r5a6hQJoqbLiB*B>}J=ql+(n4pW z0|S3`vdR8Qd86}K^lcOqEz5S?#4!4FD_>SE{_|d(Y!Ri9YT1G^#d$AS(dH+~(T;JA zH}{1zQljbrU#xNU(w`_CLv*=D>XgCSK5AeaI|rNZI)_Cj2Ypm_$dim)IQz_&mke47 z(WeoG^qLPIv|Gna-C-R?gy ziNUB%-`PjbDGN}MPS~-E2`Jt3`$m?pDGK#Ys4V6vCd0RFt;nzZ zQgSM>-7W_Tg!~gR`Sr%DFZ=DH{+y)S@LIKzhR!w7JvS!wGdombjG?Snnn`syqNBbl zD~HK>jz5aYwX{Jn_KeR#lMG8MLz5yyg)*`Ur}h4FYw=a>h}t@Z7U-55f;k{UbDsN62kN}l;EJ_AA3Tm$^#%p-3``< z{)xeQb$&V!(NOF+07aqlYSZ4o&4Q{H=gp#(SrN^X9O6-E8n&oV-M zld$h&0|J88WRK*ZS9w3_V(!@b{0qpG{OYZG+iOvrqkRdJSEJ;eWHx9h`5CQYi6JnZ zdUJ5ZXu|QAZ|gw^>QRNgB@D**fs|upBt7%mvm2d2hpIr+qpJvqN(oxL1dQk3&4K*5;c5pr(ff4$0F zdAwHgd_1_heSJFq0)BTOO#;blySt?|LmE6bNUpjS-q*GEq*z8Uk8K1+2Y1KA#}!pc zbM^@7*=J+Pq?mkoAcOt1e;pTLN9##S{Cak-VudMzku1W(z1{YMX%9KMGB-~6~~ku%20E|9j~WZ!Lb5k>#nV>4~JGKi)NX>pPD_A z`$a6E38WCrYdJm3wZ}=@r;`=uMqa}89V&XQK^2~^X zr~i6R@;Erlr2o3c-Y+tpcW6xc8+Pn)rekpGkR>oM*Fe>1fHqc_Hj4d6R%O&wTio@Q zMCF8i%yG?aX@v26DhW@y{ny;!TYzbJe%@FQZfsDj4DDdwz!<})V^5PpK6`Fq_e__# zCAu*jsfHn2gV|Guv+qbj7o$p6Ol&-*67vTY2Cn@cHld)dp2svChi5MH5*9O}@jQ)b zta~=AIVI`~iSDF1K>VxxBe%49&GfghRT6PhUf=l`E-N)C_`I|BcK@89g{%e@754+t z)*$$A^oNBzoA)I$DDeba_HL8A)`d?-L$BU(|d4zL<>n8BZLGvSqq1M_CH4 z7RUVzS-4jp%cKj#wF}45a^<2;5+)|Sk_a=Pvv*I+*Ken~x?#2=l|+f=fYD2Jzyh z*C%jt*0WcuR(1#r6ND4Y`Y771-B?qKoEi$}Hau>hXagnWd5BKDj#%%mK98f3Ox5@+ z5fdwe=?PEmWXF};=8J#WLr9LkHB|J_q|w12U*mbS*Lx`oY?NUw9as zezZ!>|2I{q3QFh|=qhr+;-L#T%|;uj|1vjm`;m&wI9*VO&G5m)^P2ER2CfG6=M4T> zQ8@pysS?1>;N!=v(TD(5LHoi+X8nj<*e|wAiN|<;j~tfxk*7tqI_G-Z5J`G{aiVho z{@I2w%rE)GZE?kDM-YXH^v9lj9e7MP>Rx(cyD#MdZYl$Wc$;YszJRajp-hFF_S=gM z4a)!aJ)ZM%+~SkJlTy15#hll`bpa~kXn601`Cm#m9hcs>(Sq?__SkyHD-0Cd1Ep2b z{AgrdBmf!~{XK$xAzG1uiwRf8LN4#|V{yQ){arOv3;nAFAd&pFMUfKqlPhQvb(BI7 zsT_b*V|MSs0D~!`*l4;j8 z4)4AE-4#YjJ@I<{zu(@jesG|(wN^nbdGCwILh`rc^ryR}TC4e`=CihG;bym7p$0GV ztp@`wwnAe<0b4*I9cXothW=7d$Uxl9wxbZ^EsK`Nkr) zaD$V*{p$ML_UqYOi!Ol;OWeH@mKDd+Iuo0-v^imRROw*VYbg~Hf7XyRcJzz%x6Cce z_`M8|^8X6~tL4%C&DwfyC=k3MXiv7K^HSmcnsE$znG2mJFctO|Imp=dKakewyYg_l zz33x-dZR>h7+dQ)i?Rq=@xl#($7FS&sh)inFEjI(6vu;<(i_ zfwIm^Kl637M^Ri8jZ7ZaNYH2#pN4CKOHs-#V%IzEnuVK<({auHM{1Z=W&;W9Y0pe! z5sqvIk@*mEw!`wM3 zd`ZUf{Pb{qy=ITkJ!Flp8%)<;Xm!SJq9NMw!6Q<@a%6P!`m{Fy6{4VZmBGRi#6`-Yp;;06)meE%w=npf z0cMM3d&*vAq!sL?Mt|mK?CYeWqc#owOziv(SOpjc=>)oDD*6c#;XzahUGT3DGVhiZ5B^XBVf>1`{G#)T1vv@#^P8s6e0tstF0J&Qvr$;bp%GLqclH%HAJj*$*vu06DJq$q z!omv}=Fgk_PL0z;lM#*y_}FG5%_sOXtCV`E@kVxu>sK(H%aUw`iH!yW;Uw4Thh79+ zNz5HFQfJYKes1@gTo9a=+1$2;X2p+R(Rz3h-&i{!oj4txgLPdF>>{A1?F_s25YAYP zVKPBOl23YT+_3ZfA2y>A$C()D2LWc&F&K&$ETuWKx5_jrZp_hxHSq}*zsc;48i=Qc zh%KcqlM(tlCKtr^6diONr+md)3e`N2Ul^zFL zFI7HoVu~189U^lWH?T+Qoqd{o%x3!KUHA65bUJeY!{q0yG*tIGTlYijea#}Rafw4v zyESl4(=9iZ-{z;bjlIk8#4emLQ{c@|999%h5nj^sGfBLy7!FYNrs~Pv5Q93&d^RM0 z0G!`W^w`?Sc3`O33XtS@@U?xcsR?$78ZmeeRe3mgL_QKHC_3&G@eMKZ!6GzUnWR_Z z`ve;W{oT^9=mso)^YbU~2qwcv3;^C2>QLm2)&X&U5ZT4sa9p_u^A07)z-!&bsbRJ93sA;J6o7)qWum>#f9Y?z|YM1tn`|f zj-Zwn!7lV$=EIjoxu=BJ`6knoveiAl*H3A8qd1-r^}-X%mpyKmjn(#kdXA2ku*v7- zzvDXriLF9?9|;!z9v83I{KR<_bE`--WIIQ`Eg>EfaOiFjCkZ^O=<>uSf4x7M&TK#! zJ0FEpw`;>n7PgzlQ~|Nc&MN@7d#-UgyxY%(jbzliSID@_GA{ zGkw9gW6no*DO_!E-GU>=;0-r00`4IAqlnBi+8`C1JI$ zkiYD}Dn0jcyf+S#eK>@x&z5~X#1o8p>s3%+for;J+vEJav-u;K9Dnnz6L#98S_kIwBu|(Piw0_iGO`O`cEf@f_i*yzP^$Es{o$ly9DQPf`Y3erWzLis0-GW!yY3yT&;&-k}A)N!<=-_+6*;^tNAR+*#2>uR;cWAuWV$|dvEB{&RRnQzZ0(z0QkTbSeMb^fFU7o%nemvcZpMXf9`=C4 zKI%}nwsQ|X8;fd3PM*RF!DJqI)(dH;*DMl={LxF#iZBB{VjJCd2L}^mf9q$Fj9m0U z!e6~3%l(6jmBR$MjYyAaWQ-@_(sxU%8e84p%#OXvP8IC@9u&w*RP#^QpVQu_vA%x3 z0Ay3Emo#%5Y+^7=%Ox+ixtZ;bzcOF7?y)2>K@0a z&mh1cLlp(hGY}R)o`m+?)1!aHxg`H>SKz3m8{v$oC1hrgD{eJDvL8e2=_vjKF>fkL(+6dC#HmCGhL9GJ+fMp>ub?YaaZwS zf-l9_hu*Q=2&zOP`9NwGcE}Jav{w@!h5YCbD$wV=K^U<@0=|$k)L9BvAyyS15qy9p z@}l}y6dv~Hp)U)cy3D?WiRr9GYhFebG?4o}w%>Kf{1#qWs%Jz|w@xe=v_bCMFzPBR z@w|zkv@p8K_#9`I(~ze<%rLix#+v(m%|LvT~DK4>8Jaq3Xdc{5f#qTS3a+vSb#bGA544z zmTyj-&dm>mW#ZU#A~$@U^qVdf*^{8t0T)WOkJoHd&~0(N-VRQD3=NlPod>EhDH^3e za^CP)PH(Ymrn}=L7V4#UeL$NpYksL9V(KpvMd;!ODo*0LU4}S8o@SP);KVyOnfcum++C&mq|lQo*70$pB%A zy#r*QcN)3q9SuvbhLG^H2lS78S!4ne<9S%pruzjMwX5pY0I$omO<5FS&UU&}Z#gbe zo1UTV_lv+}j+<#0u~%j3c;V$~rWH0spLoKf?5f{dc#lP>3HdvP$kK=%qNSfD!QG$% zTcM2_?8`d_jDDOs^`|QwytLI8kH4#C_-p>T;^ta4dn~#Zd*hk5_!&(EJI!8F8?ewo zlapeuIT3RoX&R;LjT)u4;VXjC-_t$4Er@WB1U%})1c+6ii=Dn_NV2#xc+^fr3Wn(G zzQ%a-zXU#bK4e~cu@YYYm(@qa7w%eSFG>;Oy)jLk`Mh$nT)*6(>9w@heoF~T1J97H zf+xrXU3(0_;|2WtHbT1PWWbB(&CWZ(i;Ve1j{mh8OR$xFi>KcU!g}95E?kdg_mU5a zC05eVQlwBtf);D>OFKalk3~rF`4lUooJL~!aJ_FcSoA^j?szFqN2;J$?oTO2h3bnM)>ga7pGbbG+8#(zm{(&5^dN%Y^f z6vkqAW@$5g22R*T#6S-shGbbO&9gDCE#9keU*EysWnaxy21KSC{;o6!CeN8}TDhNa zC6lHEBQlxJDkpfr&>^Bn0=R2QaQk;RKBu@61^0C1E+i?K>7GumDfYaOOAB79MU#q4 zuu0UH`9?B9l1ouD1=g1rW8w(5esqjicmM2exQ0bT;5h;yGx|@bJ&%0P;OzurBXX17 zdmyEH4qj|e+#EZuo1e8_*=UhhEMHRnz1i^vSv#t)T-yawrhBL)_dIDic&?14iKjTu zJlC8UezNDu1wo>SkYtAG0p{pGF0HCVl<~v_9qQ1KFLg|WaXddxcfiQYKb}mzuM=`H zD@@Fu-(B|lq!-8;c1$&gABIJ{yRm6PJ=5%g&Har=nEE_S7fkvQNGHbz7yb>zbsm-~ z%UJYC$Suc6syrms?Vg)`$Ji|%-pM;G&G$iD|ATEF_eCfU9Lp=w(5gM-SRcI|UD9`6i?}g}`F)Z7c#ZPr zA4S1#aFvpG9(iO!trcE3m@=)sYYuQUrWX?eBX}A4XiT8Aqn4l8%S&|Bk>LqVcEeFJ zN!|gH5gl5y2JEy>iOpqk*>8M!cE*NY95_x{>MQ(=mpcDOgn#yDu}eu`{|SBFxLRuZ z-zxSUhaYxl5|NM>Lb;RyzENH)%qcBAMQY368Y5!HdoA^M#;h58T(X+`L*#wO7E{(A zMRS4pJt$MSV3>Ap;al7vdRHax3F^#HpG?osY8Q%IZiY)3MAENKSK5-hF-ey>OD*3& zvu_&gs3u58c`~0>7JM&Ev$pLeZoG~xvbqSoTT@7uinT?*n?pGOei87G#_Eh=dy%Zd zG9!T*Vt_JO4N*G>*5I! zJAGA~)BYT*mim};AqZ+J)cK-hgeuDAiF5|t;Bg=l>=GVAah;>tO35H_JR)7c>~s=4 zA8_9p+uAhp=~qhm(Q(w%I}JC&KMx4NrvWFJK;i@O(ovgfuYa?A`4?&5nJQZMJFJQL z(3)qil+D8~DtGB@#UgXHVUk5haGgb`u}g*p-(j8)(Xy%Aqz~5dFk{C|bAg;*pqdcX zdEbZ`U#aY$jtl!rOdzvEKgX?E8m~!0=8mcf1GA)_mloM&{iXfn(u}ZnBjXZTCES_P zsOfOKZ>EmRe|0gDXt?WtNd14i!7sZf#BX^0b&mB9H@6$XD~_*|H!fSJCoZ0zX>E&* z=Va;-6H4IA0{x3~6R@d>WH^I8&j{g3tKa_mR-SBJBW|GBh0th9`5(cm?wW8qJED>6 zlNf$TQv>VOFHa7eyozapvz9sD+uYgCX|O|As*&`b-)$|#*6}yCa$2z2F(PDd?4;gS z@JZWaE8e!&)<_V1@PNO>0&L?`x{=7{zEXSo-A~5fZv|Nme&yPVf)~6nI}VRULOZv3 zj`(^1#S@J56Q!u`BoY`iYI=-p+1L?kLWN6762kzXrUI}U`P(BoJiTn|{Dsj$EfC`rP^Iz=|f zp=}b8adjmal%rweKxn~7`H4$~tZfk-oBnl3WjLpd8TM$$MAVB2xF6NawJnhZ_ISHq z1VMua9l@qwO_8+FtTl{g3D5DzH#zy(9}v~zZu~_WiUtQDs&>jKwvU|nCqx zL@g_nWqo(SE#zdRwY{BWA0q-L$E$*D*+2W0n`9Z#3w#}v6cj8c@m(Pz-%Y{8;AXf2+j5!5@vX2*!hN-vsdPetkUsV_37vl` z<$g0ECS*k`VUteqLj6F63)i}3OGVnX-WYA3PH4&se*NA3HsosyVx{g4lFAqXUIwe< ziuK%hz?={zL<|zaMeLXu*RBzc^XE}po~JcYQ11kz!N8TeVfVi=8PcKBS#(aPFR(Yz zS9dBumd>&?iP8=(bZ0Rqs=jPI5pvIxCdL=`op(Z|bT77wFKr~{l^Fi44e1HyC$;pT zHvTx=e)olpTcKQ6Ecs}k3*`$r0-XpEi;+wq%wz~ban+n8V68%q0daC(`1R;74GUTMT7_ z7O9@3&6-P<)fT5JOD{B(dD?h5GGi7%^QbsJO9!mn)uFO^*bnKV=rs=G@Szk6y0{c(|3*y)xX zg%q^ppeU9g^^646xPRX$f53FPR2cv6HbkBtMWSw&ojC_QDC;^r0(g@PZx#zra>6Yl z%WE%nUh7 zEW{25Z%AgR>7EI2#H5$KPW_}g7I&L=^{a~~H2Uds;<_|+pgD_K;HV2028Dbh{3XgW zFBXAsIP+eLHlszB?x8>;kT6)JS4&;?kMw(_G{E=cTA=)twe?@WlSKRYS|-y!?WV?K zP<`)*nSOpn8}{vKeDflV=YF?XC4G;4l$(GS(-l==$$~EvZ0f#>85v}hBhB?^HCjAp zH6EDcS>~CwSNOL}sH{R!FfUYy0dOTvF(~-#8N-8oyHId`nIl(B05=7eM#Xalmxy^ z6erqs76}!o2Os<3N!1cOBc##Vp7{`O{VyEkkefaQHM{#etFU+`kD_(1g* zA<}kDa&>bs{^}aRvny~rpKGA4U9w*8y?VbZ(C4xFB>oJ(z1$fFDNO79hiY<0gVgjc z&53Cyb@_jX9rFor3^MmAXoT4sBaU~v+KZ(9o$;lfT#2p_i z(~v#7PbKE)^0Eu#w3)oaqfGra77r?dXrsi{lgp>E^5lqU2a?aR*HP-GRbFa;6|Kzw z$~F+C4jyd9p9hE9e86&1ArEYk1*b`gnjKH=JZt4<@u8|w&+R)@vf3ME==Y}x*tW*< z5qVyXH}(ePKJWTmbxip{jUS0w+ZWoNqS|^}p(HR*gN4Zwv9E|AY#lDf;D@9+&j%Q1arf0~gW+N%N z8_un5qv1i^g|U?TGE0!JtB8kBcq^%86{$R}6K3ZwAv8nl*prSuCf zXry#?;TL&uqYarQXiFV>f_?)1kYyXH0UrL3;Fkvl~&~O z-FxBo>yU`7d{Zv}c<+3Bm_RPQ&>r%mb`2}BbFTGBvwdysHbKE)d@!KS#zrq_b}clg zARi{@SM7&~x4x)Z8`&0UnWZ}&#E({v*x-c5QKF`-n#eXVNd62kPBaz!o;%F)1AiGg zoLsZ(GdR$3i0oPA%jcPe6UBRGR6z&9MhDSrgzGf7Sy*QSt7Yjf>ZLE!vo;O}R!OBR z4>9bW%kEie1Kr!1$5!g?CyVS?W;c!XbLvv|lcw6)v{G6#h6K zDY0fg*t?K_Gt5-^Z?mW9m@UoP85(SLBAVM@2_3#M=J>@By&YCWGj2A83^bV$q0eQw zWB2l$(Q9$ktS1zl_k)fbH!v3gu&<)Ow|~C7v{XqWyMcD}n1j?4U+lyU256Q|mtQ46 z{1U0gYNO91x1nI{ng~r)Z0axkaCS3fq~B@e6~lW=)5j;wXLEP9W*Zy@Sx)x=EmOC# z8nQ_@u8xtC)V!px&TxauBb#SUkH02jvWO?M==g~1(Ry{nW~3!`KCy%!ub9~Ae9}9D z%qtIYF8g1TPJ}Ai+4~yy5)UaD?qF6@ab}9Fo1xvZj_p0YksIU^1g`xro%MayHcXOb zyClTN_o!~W-u8fhy4pN1{BXT>%YK*E{1;)taXR9hn9uUT)1We5aY514IoDUYJG8kx&BC;h|KnH# z(a2Uz^3-NUOgc*CtK!nA-WK*-&%DN>rlmJDuW9vZM7^aUOqWDx%nJf5h~w7f6($`4 z?)rYApt~4PN9My}=Hk_>R11bgb}QlMl4vopYB#>)0-nHn&G*loCr{uzkCVB`<&%v` zafk}IMCfJ2@uXJ0Z7|w_Rg$kldD&mb4C|jEQpMezWs6Il$R7z^Koo3-k&zqoaK2xpGs`osa<8%Id%8l_&B2Sz;QsM&^0*nO! zJ?9*Y!q*T48yfeGfiEi{M_AUw7eEZ+?tv~l_^~}y3 z$6nVSUS5sLbW$0&j=0Xt`nC5wJ<7P}(~KbOyGi43o*{L)U?jE~--77)em~jgD>s6D zsAJvcbcG%YZTx~y6zn1P!im}n>{~#&Kb2n~jwtF$5Z5OzS*k70zrd`$_>)T`Ws^)e zD2qA&yyIaQ*_Sv2j)IZL}ICV2nr9{tcP>w@b};AaPNkubcPQGFb5c&XKoqLqyP zKLW;wWVeVnZ&)f;D)hQR(-4VBrsNv2C4_~kB9vT_@er54hjy~hyJx@37%SnDfS6KU z<3HCz{N#rsV#Q!S^L2L4rXhELridDcq<6rv)Nra2atyN)n4+{@$lof`0bM!|f+Boo z3{N9yA2q1#1TVARVnknfQN99JNIW{CRQEk7y!`{kw)c>Ud6KufBtkx9&`c1BYXGggD6kOkI`{P(1&M^$^gYa{4*;(NF zKj*eaM*pl^B7GZ7{fdZaI32=@@Rw1gUB_w&oX;s1J9YWKUe`G@zH95$&z!(h0N0R5 zUE{n!bZR&n=FjUNf^+M#{R6(4+!oY6@A`-9$9#;E7LHLUG3;v$Vx08kAO4Hfoj*Zd zFMj0~f0Xh7jk3GdyFOO-lVDpQqct`AI+=H{Y4 z>dl4PhMQAFm|ZoTLk9J)!0-2yw9M1;krFWW2Svorl;resZi)}0Y(S~c3Pv*ns3*^P zl$yGh4zYZn_$$vakPq8w1SQK`sP43z4Y+eI-a3!91yFVC_ zyB#=b4~~;q(a(E0HSUUFA(LgWW)Z0$Ol%`bK@?6F{)hV8or{0(1+!}N zIrGYT?zj5%*Z)@??dotdZs9u)4`v$nuQ<}u(yQ$H5B=m|Amf-w_G`22MOfo1V01>5 z81f~xpiERN9K^_Sqz}scSFtt5ta$8Xn5250CYV6l^1ccuS?rMxyIKLE@$40jG zByT&IxAlL*n)B$xlFDsw)?j)iIr|c^H2ba;`Ty%&tHc*E>n)+AS#s`wj%cPkSeGv3 z_WocL`p@}cHJJo5qz@5lZ8Ygr>l3z46`5_XwNSBPI85`cDgn9(Hl3yK`Kmievw~#- z_%OasOc(feK8l=$Z?GM6F0IL*6g?537nEM6Vs|aPO=%FevrEDbz%Q6&fL=GF!L|$& z5E;>vA77W(c)YH}j}`Wi`m5+T()clXf}A$w zwJ4`Pd#2~$zK)hA^aZpF=-`BNkM^I~ZF15K~)nbXkgcl8mU;YXy=b7bHgwi$nk*o7cnZx*N zA+0_>44)b{9-gl1vNde@L@aN0bH?HdO6#Eh0iuh0D@3CU&m7sv@&lg#D%_Z-(2}B@ ztunVFBwOx~b%`$flIT2i$H$@D5;{;N6@o z;4)H4+AQJTM%hHOUIv?k+WisdY(z!0B7scNC&b;b8us5L&mAeC0cvO*$Pyp}-hu|( zXm=il{T?RH5BbuCskCcQA0E(Vrq#U43IDWE$v;4!>yzX2_kv%uLoRFW$3JUP|3Su~ zI2loQ)pa^fXyaon&-<^=ZEBsA28^7n%yo}3K&Mi~ZR`SzfG#r{uB}0d4vQ(a2Cml1 zJ3_!0kCev32F?VadHev(V=%>!0M0pX&Q5&C~b~+O>z< z-S~IdPbIsrgYkzkP}Qf*N=rStW=XDB&f6psWqx*RvSmw8FY912AUb8OY7gs8&DxZ# zlskQ2-;G}B#`I^|vF;oDmMXfQU|>1(d$szTmb19&a8F5ka8$RM3c?a~*9mif zUZjX*%oy%n=;Mz6Bah;z?{K~Q3ba!gy<$dp&!B9thLa^QqWVJq^g?{2^y z+Ydog?K{nTVMb#cj+OXV#*o<#Q#4lVQsHWGq-P7xsUM0rN36xU3f+k~&e|8YUgRug z(=s@I0qgP(D0=72=+E?l58YSGi}4~4p5bV!5!GsUK-o3?Rg~o#aALXv3oA=C)pI1z z+Sr$h;9yj>Qe}{GLWG5Y^+auRg+6`uk<0PY$^yq!SSm@lc8EcXl zYtTh}s|tX5&L)pFZ_mk&F}naus<*;_(|Kxm#;x(lZOcecP{p`F3~S zinL1VR`oq=WBR3-#o9WJ4>Om2KFqeW8 zI(K0^)8wmBMH-zoCvQ?dyZ|CjJ3;3vZliXL4AfYT6ef%W7<=^}eD|lfmA64U|M1!H z&;^dX_S4ib*Ay#8c>h=@9c~9JJ4 zEO79C_~$(i9A85Z1*f%w$y!hteC3hlQDH+WLcC{7`1XhV4gSb?Xs&_&nwYcl8aa>1 z)}?~hIy1imHf5uVXtT(NTBvQ17I-G&g4FBqXoV#)=sLZ}Jj@=e8!PmGsyS2nbWD7* zlQRc4$XWGRo}Zv)!EYd-tr~j647?cDp6ZstoRDrOD(wV8{*uC3e${F<3D>^=vu+RG zb+5}(1Le(!z~I89`Jn9omL)*~d^mLMVS&MrAA!xfGs|iwrO2fyj~V5wBEVajSL;2e zq!0?qvY?48wAo=jpce5rort!GmciFh+nyaU#W&<}Bn0tCHcHxTq(O5iReAgv9 z>Lt9Slq`G>Sdr^}G<2128QlAbbjHfRYn%o!LdLbM7n{UO1Nk2v3CDTe2vS}Eai_AU z9V%Q|lbhpc7EO$m2b_3Weo;PCr4lITc^+BDU07iDHw$4sLutjJ5XJZ8*g@)FZTh;G zO_LWaSs}6;nolvf{U17(Rq$pAQCQzFCSVk(an8`n371+bM5X2fsCmcZ;M}_IC&7y; z&znRkK5H;3kx78(NyIA2dZ|9Q!4ie6@sr~XiYnf8v6nHIQ+Qv&)Imd-~D{ZDG z;#Z_!1^$fvUZX=4>Zi9ZK=hLVwxw)~V)ZvVRz0t+*y5BlErBv zjbYK)+wS0guzoKu0P`eY@Nw`qRb=}r^)^4Rmxmnr6kxw{U%(uwcr1?xlWSl9YM&Dm zm{1qQF9+I2c(F?KJ588Wtfc#1cL|B*6%^1eFp6(Q|I2vbN?$l)F2ip@ZaQwg$a<2; zT2;KId!}w7MR*7S(kG$-rGF(fB^12fuwOb{ zt4hD;X)rVSLSDwXEresY*=~$sa)fqS8e29*t4XN%vSlnZ4CGph+%4Tg!V=*VI?52@ z6C1Mtd3qjdr=E`T=pLO`E;WZmUq26bpo0|d-! zEt(xKb@F*E^qaE20MqIJQuxl}wl{gubAq42&K8V^Bd(XEI?&rU6^d7bC8IYYp3!C< z1-SpI_H0CR$C0_CVG)a92vZDRQ^bXqTe;N$F4{p9& z2e&ta?{s|}yWP+M4fcEq8#;VJI>STiv$g)~HAm+C`{V0(O~g_{=prvi<4<4L*@RqQ z{cPXRPep>kpQg$SeE+A&lMsn~Ug1=|!W%5I{%=9U%VGFES^3DH5*yz739$4V$qnwGTUF#>1A z;ovcA;q!jQzi>~wZhhoN^Rvm^ACO9)h6~ToS$Ver-V|`rENiGxF5M0~#6eOnf`6AY zqIONo+;XcwZ+gPw znCLg7GZ3b2j@7j1pjsW;)St0Q!m3dxB)Z5Yjj^M{&VhhtJ8YF)GPTPK7G%mw3w{LL zz;6~X`clTYno`FXazh)^=b{thf3ycbzxO(vnb})yud#ECbp)qxN-_hf@2nG_f=XB) zPu2Q-;4`O&@uS&n1^Hz3Uob+Bv)tphsqVRBet&#fSCl=y9xcT=i~d1A`HNL1N^rZ+ zNlVmXW2X)_1M_(>aC*vVDhNKPH7pUKHbes8$AJp%sCC68C`{DSv^cpM% zMNhVh&ddkBMI9MJIZn#iPZ#VaeHE+PUn4+3E4t>EzkRUt6rEu3xU7MAAY>7xV>{Y zCBIis#2P8ZHJy!;GJ#BACb)=SZh~9`RqB`PWhDr zqFCQmd(rv)sUArc2$0k_{mSQup8Iqv?Gy>*{29Hkm~u@L6SynII3!gk+h66>HfeR8 z$;xu|t|oCq(@1jKB7rVZQ9ivwm{sv8*l}L9v#sv4IbjA@#n9F>#i2icuHkKFjcD(R zq&LG6Hj+>vW>sC8T3Zl$(tp}c7~4E+C5^_Edl#cSN?&^?q$cT1;q zN=b?W(jeW<&lahI%%8 znlt?*d+aG#wza8@R%xK!BvN0z#kF987aJwgd-bSkjydfX?Td&wQ{O5vjrIU6)B7my z0H|fjA_>ayYK@v?Gh>IO2ojE|M!Xr#=M$-_8Z14(DfB|z8a&~lRi4$n$FDV+tXO%S zT;;fNi6p0=+y0)iaqmU{WXOjb1G0HGw=Z)WCNwA8XBw{H*SQv-oYxQGYu$6O zcCVNk(=*Svp99Od9P{MlJJCWHUY|H01M?HZZ#i{Xg<~sJt@j+3QZT@M94&y5u6HU9mj8Vl9@EFY9(G!gR6MU>a|vlg4uXR?26|iee@9QD-NwQKz-!{# z-RoWnF!^$~-LU-?e9xLd>(z71(X%Z1giyJ=ywo`=BKIotI*Ruj@mpn4S?;$B)&?2U zZl_a&Y(H-_9N9d8;S&4Bd?3?bPpxH)s&)EMVHHScRj}yyf*fy*CpkmBW~5S$;)vUH zu9de>_SaRnSRX#mJvist8Ddm6>N_fFD;NZ8YYsRip>mL}1| z3BR}WmS3B3dRjl!`Qd>P=jv|@>P)9E_;c5BiwqxFBr&DK$(Q{eZl?2ukv-^!f|Gfr z`#aPtyoK-t|L^q(5i)yP{+}^i8uB7TQMirBIK+I;HLP3W^Q03ow2%2TWja1z>G((E zMLS@4jWO&u;Qci@?AxNpAPC^%AZyX_Cl;k6)B*Lt5+v*s8-CCxE(2#iCsD&RkT09n zIC90~V4yB;wm8<2zY;2}TmPQoh^W%weMXH#WkdBq<3`0n^An+?YFm|C#oMVW>U=G@ zKbqAR+W1ZgeOBmwz%c*T4}2tuXFg6Y*gf?Zl7z>=Ryy!)NAk*z4W-w0@3?O$h*H-j zVIQ}VIPhGs4=aMZj}+d)>^8pFE`Ha08k=Xh=LuD$R!k zwv2f(7eESz_te3m0y5#$Ra30UNdd&?#6T48M4|i(e36a$7M4^LI%F?reFxks$J5xz^PopTP_a5W(@^!A~Bn%SKn6@2He?`^!%pCDvQ_Wm6#D96E61z zBZ?iTlM#Os%%a1joJS~UWNx$en$72dy7CQJ$1;sHMs^&yIdQdvI#9^c< zRMU5YS=|VgkesJvX+uptAXcB|XLL^6EmS278Ni(SGdkprK}e=qBo5>0E3FNtZB%k# zPqLjseTx|r_phc>?&QKJqdnQ-gFn-Jrj_-!Tth?It;+M?Bj$T33}-0yrb8e@R=;=(NGlQX^SDN6wsosENMU0S8XKyF`#(i_WNg0u7x zm6une+G+Xq3odFtB*nT|qm15~nYa=xm)%A(&8?eI!8>i1{_L|n!7tDAd!;O7zf;}N z@y_C@j--t!xs6h3kR;a7o6e7 zfqAy%OjR}<3D)3D(Q-OHo#aCFPe?GIVmsUSD=BXb8XNP6vD}(*-)+y!9x<^ze{U;; zkLKBcSb2dnth-vpk?0wof&6D;`tpXlcT3My*-Ln6l=sw4SsoA|zflq@f@v`@}XQ}IcPY<=~BdGF~A%^^fy)gyFzp@M&$&>pT$n5@$M9A5J1v-Ly zYoML~eEJ%!X&Ihm#_B8#LzL8dNu*LbE#g(S|Lri%iBd}s9K-3e4+H-7SIIwcsw)7%J|s) z8}5Tto#IyZtG!*T=5SDWf5_`4Z)V6nywkATZ;4vNg?JDP3n&H22U!z~kkx-Ndv}Y> zMuru8HWeALK)!m^u4|h8=@+5Tt?7o9<sjAYU0LOHM@@7GM^DDpSA=6%F(sBz+HgTaz3Cv*liS$?u%D;-ZzU& zGn*Xt32pN3!>|VWNUj8fcx@}xjNoka6*$SKt1%FxZ|sxjHLhm55&r@&`kJvh6C!@SF88YxwM#nDB5(J>@;2pk$N|D(EbVtz&Ym&8U# zib`?$X}s@Rg%9^tLOoXUs44ovb&>OU@Hr!9G(*Z@Q|PDQqkQ+>Z>Enjw&)w_c|ael z7&OG7`qGBHF(L6GoAG5&ea8xl9dXbg)v=7C8~+EEL=hx_bZHs8BFg|zmF|Vba%&~4 z-GNNWBT<5(sUKE5e<0S9Rru^i&LQC`pWDctTKI>tHw!rO%LFYFqg97hS@tWIik|Nt z(;jc~L>i-0K}Wj2UwYI&)4`b~+WD7G+fdNuG^ukk>gt*Y`0gP_JX~W7*|ypNcy=6B z>FOi$=$F$ypxtc-7G3s_>6@4x_IR+w1>XdGL{~jKNdkU983>`&68c-?f^P!XQUt@7 z%f$noh2L*nF&&@qEWSbNgY<5k_eU|d99FuFdN#d+56AlLA|r-d@h2j>*6|&_P^am% zDfdB3utfV0_-2_TW@Q3Hd9zvdvT7+d8`3%^9U8+*R?uS%mzrgj$lZr!X5!7zMQb=wY~U1zn@%mnxdA?H3StB11OR?m^Tfl|9FPf9$IlOcc2{A{tUiw$FdFjBPk^Y z*WfYnY;mFXG!2Y&T6S4OlgRYKn01?JZ;&1>~4^Y#E0B zCJZEcBhh!|*ePS;GqmKir7j;`)UxL@PPYsS0K=FxclAHGhB_Q~Mx52$A*Pr!URd#y<2#Kj=E z+g*wMA?dj&q?gKl`K>T&d8F^$G*$<>PYPqbd@wJkKz3L4JQK?mr}8^8P3`EE0k z)|Vi?yxGde!$xe8U${=FT3lv?Mi?*G#WPux8{(c+ z5-k=S=>pZ5UXXQ<_R~t7d9pQ^!_=7z@3C`avPwoLAOFWoHm&1P;SWe5mMumTvw$^f z*MgrE>RG5IRFB@dK`AAh$O3~9urvztl4342i^^wa za2;Gf;#@4cxCMal7BVJN>n@$YE(!WLVPgpC7M&%eg_>iJ+Exo+)pw&Hj1ZYmgPS0i zw2`>jGc9C;u1NOo@%a)=3af9vpTkc%@*jBn1K7;k|bOu#QCBCC;!pj(qFHf!x&vB z5ooh+r8*D~;5EJ>knR-6Y@lqIkwx%vZG7nVfqtzW$XjjB(?r5T!!_195+dT8MgQvR zdPlYK^e&IA^bxc1Je*lx^2uX6fIXe8@;9 zSh2H<$eUO{Jz|24FXJgUhkIe!)HrJE)rks`&b{So)320|=fXR-{j@edUck*-h@`XbLRu|$3Vjnf-vK$ns(E0HR|Q$vJi~K~ zKCCN1Adt8~ECg%afggofc-RodR7Xix^(Gweddy>V<;$DhAV(C?y@^8_>NqOVj8WHh z5OGE`QfmyxW7g~Y_hwA#pnC;tFT())-rb>d6MIqcTj)~doOsV{++v#Gd%ayUZ z@=Ei}Bau7USHw5=qb^&y^1*wS=~8&JdD1OkT7G69^(@4tP>&YSg;pVaB45-L!8RoJ zpI7j)7H0ZRNsb==ES+qW`E<`Z{C~st-?(MO(`re`$k{zZ5_vhCX_)b6WmU@C&y{}I zNr4|WY{R#p=1#{u>di{lf_%uj3|Nl2<%h4bH3_#gHaW(%PzC2)bmcL7;=7G1g z>ibE(_94lhET`9(IJ`Kn?_Sa-o2Wg-m%J?xU8n5|rYKwFo%fA+wI2s${n-DI4oR9G z{N|_AuvxBgLgSvs(j@CxxZweRb-RUo&+S?r09dIm@b%C!J`dzNEu&E&M9p}l4(Eq! zbHilvdR6IUiNv>RKi!TlPF( zKTShpShaV-$4uNwB#{a0&uJk}sKPA{ggE;3)>e~+cRQFItL^_NYH#q8C1R40ZtHz`mEb}dMP5q{7f9=8@Y#%grBp8-oVVdrJ)<-fVM= zh;Z!S?BC(IYVq@8(BfX5>z(tb;;L$7nWk2;pwwT3%g{dzs%LG*=S8qcklkT6)_QwD zGWsfruU$m#Vv*;YW{?QCxe?=B_d!$Ur^il9j7*a4Rd!R0U zkyqz80;v=JNv=Ow;c~^$M#yuS+-vM9Am82e^@p9B7OOB;A_WT#^WNN8b^RNcO>*gZ zE&)fjbTf%*-n{-UyA((?DbcyJpn^Q5D-M_|i!P-aLDsePXT-*tm`1+@eWq_Hkl=@6 z%Z{m?Wk%TVn#tLa3#P5}qXvm8X(ypDSaP4!#8D$I%{HsuLRk(AO-@+us|G8M(U{_S zi}tck&JHcpEZ(BikHCqjagn)>+?37=fs%9yypZWEIxhp#KXHD#tn8!JpeT!PHI9pN z-W?{{PaRjJq`6MdogJN)abg#%?OsKOtNGq7F6(=pSN`E2K*g+H>4y@psaRn~H`1&V zc_PBqY+?F{je=9sW6kM7mnP({>1}&0>e6H>d~mE{bLE>y zrS09`@Rol2(4q}pQToBP8$M9+B)+n8Oc5XI@`9~YyDHK7;WQYL+`L(`+u($~9y#{l1z7O9`s<2s8qgDTm$Qix z3>OpV#P{@SFg}9Ch}dQ)JfoREpP}a~F`sJwM^a~Fgc6u=Eih?iQTJca`l>p__s&IT zKnk7SSE&#}l7ReCUqv}Gqt?dj8{m@p(n^< zUtSU5;BsLq-nELIdyYmguCTUXCyEj1Qx7EhOw=juC#?VZTj>ol*v6)l2krdGtM(kMSU zEXBR_I(IkUun+B3A}ji9vJdMKS5*SWOb9`ncXY)uxFN1BI_D5};I zEh11uqxjsi;41!}^k&O}^nxpQNRxzRVv zwO8>RpQvH-L65S=9+?V!b!b-WJrsT9K(nB9n~&2HRWMA4rKadm%&*RWoGp3r8g2Bl zC}mkxTuYCL`aK!4-0q!Z#cE8Ay`lM%<{jP<*9#dHGkXnT@Keyb`N~4h_qRDzpG
@LBVd$JBr!cOSsyy5Qnq<-j8v$!0nV4Uks;I)~$&hO;3JQV)*3nJ_Gl>PX( z&~v1Bt`p0O#%){fu#e%!<8igf3%F)k8d3OnRBs&)#K*^pDx1jErMsKm9!?ZaIE`y0 zt$ZqUTt9~2ZT+fTIbOe!4rq{;k~oI@9|iXL|5Er%)bfI6{P=2U<>^h(AG7~i*rjMG zYyl7ZjCm9p{}E;sSl~^mtO{H`YVtvz6Ha~n@V2|1TRNKiCwjhbSI~;*A=d-LaWq7c zxeA*M+H@LLTKRcTW4)B}pMd&*%R^A91oss-#_Oh4JAr1b&SL%TS6B66E|IGR)QC-Y zGs7vS4Ro`3!RRTz`za0RLaz%7rr#cIy$mK?UUO;*DXh9ZU7Yc&bt1NWUy3ubwl(Z>E5_BuR|wfaHImC&R}5N8hPAfJ)30lB31a2+qRK{7 z7!hdcCDlIQN`AEv+N1$|85+NrG>ZzOCDtY4^lkwN7A64Gk!PoErWDw;MTS*SHYXaf zA%C{1ir2#%XEON7I1RrEEEYa;Y#FR}FTp;qzH>o7`ArBRx2{*<_j^ZJiwvCNSyT+j z=im?_A)h4+r!F{`Y@frs$ORV$GgS-jRz(-)FZ>8@|LgJ-ZEMsS5J0$r1K~74UoVX{ z^K(Qq-aGNK^bo%SFCP)-tFO7ww?fNR*{QPrVidw=Y96yC}?JfRZj+0@qN?EOnu6H~vUpsOKcJS&7qD z`gfW>2XT}7gXZW6EX_S6JNHdW{m}@cq#x{qlFs3C&in^D&8HML)%2GK(1R2rqIYYF zUwfmLhg@=xJ_(5qzje%W78|W2=4$?()Tp=Lrlx-_vvyg*t^3!$B{2KlYpF~d)G{<% zF_lVwZYhN46@^!M4A(E_4q_@#Cb$1NZi*|;%LmpX+raS54=RHoOL*P-W0pF6%y zr^(_$cuYL50p9efx*VN(tD*QLNHyU6;(<4^i6#niO8ROx9ylLlI;OdHaopNkn?>kp z9C>#c1m#|vph*kp%l#zlVok%^sQfY}Dn+V}Yyt}Tq%BqSzJ5jY=zFA@y$_;o*P2G ztr@g?MJ=7sKRQ@MY36%HWzDVe%ZPXx8?Lcp3Npxa z?eP2}n0jF6Bm=gWHeHqlFv8nWJ9kIv_9(o-PscKyYgj~5fv$b(S%tem_p92q9lDg% zWX)L0j7@#mrDWA`xsv6ZQfBk5YhCZSHF`KCfIGTUYF7(mxvKNaTOv=AE=qGtI#UI6 z+b*VAo?=RkvbxER?Xn@5pYP#5JnrvZ`v8)esM4?1z42L5a(4@ZY-F|BY_9RUgD4%} zLzs#s5ObSMYJXEteQoN7YV#2kdD+H_}c_w7>WG6ti1*$Cx7N)c^VYjhzfj z!J{VlEEwaCc-#KJSR~|b25@s8)%@p7szc-{QZpgH+kZ4`FCky*kVZOaS@M2o8y=-% z`LAoFm^<71?b+&)?wB!XHy$dhb{V|1cmLbDy_{B3y=vy%ufTU_&FjOz#P#I#vE0lnj(zNnKKKXn5ZevCXr-llE)Wri-`=twlykarD7`HGou;WEr*(76r~5AX)^#BG z1>VrJNwIcQN3|Bmc&f7Ib+uozzM1v+rT;H2hRh2yeD?8wnXpH@fAZUc9zh4HxBpj; z5C9Z{ytaBto!k?po>-}O*`J;)GyBC+iY9hacnpUE1vPH}kkgXB`LR6_fLCod--P^&g>B_TzY!3clMh|hBfA?U~Az*ba-BJQcO z;{$M_1SsHBVkqdbKjgVKSk`g*|9a*K7b!pHyErKsX2nTXk?um{Ma~9AzwEXH^pOg{ z+*2ucByMd&PuR}8%r-lt#O4tNc{hIOoMUDfG-N+PCuY_X=jP+04!KA{Asl);bAYZ5 z93l*_M9OW?jqujOUExNDS4>8XbRf3HCL>u=(zOB71tgCRY65xb>6kS%V3ht(I_D|Z z@?CH*MTmvYAt2IE7VJFo?Vdl0E|jRY+XKr+M)47csNLOD#N};aDTCs|Fy7N9 zQ8?ZE7se{^S22BsgwpSaF3Xs2_P6{WJ#d0I@$$WNv(69S_#bBL)=GW4YufrXt?Rlt zLXYgGoF;gF(o^3*o#8G@mpU8i-OOrj_8xW&uhi_N$B5man!|id*D&_w*sbPfG3K{J zq2Uh!lQ3=c2a-M7>YY>aw+>EXGMfI9@1bj7kK-S==jkS%93jzLA>VSe$4(rW-yt?Q zs%5I-T{dR*%+_M4)7129EgTJ6=EG~EhyPboYuaI4 zN%QR1kOb{KDiF``&&q~gf<`!RJf2@|B36FXZdhb-RdYei^+yavxDD5D70JIlDJC|f zY(3w3&}6<$(~@3txL5d}8i|Ll;VS-nU$*2@6`Vf~C%L@o!Z}!B$pJPgO69EcKP~Kp z-1wtY6l3va{vc_5eUq+^Gqb{5$|p?|I5zn@z=KSHn60qHq-Ce3ek@tCo?_Z%vE9(u zkRY>r&nx$y7)4c->s$Hy7nGo+8Nt~CgZbBKD$;C3!AJPwdUcy>B!}pEQCmm83hx1I zT6@N6PHFf}A7;cln3S7)#tV=RdCI!SzVS(_o`#S$?l=LqHJR!(OIU z8gGAl)-w-lbt}rDoxGAl5x?jKbjvbVCv+8j}n>Y0IkuIR%7JL0% z9Cstt06g z$M&TI-Mw$|ph7Q*!)yT(E=W0hDWXX79T*BV9`U zcl?;

&PeuY0L}SILNmuva%hgUIL3FgA1-+BFxCBe=L)W6<&QvA)}Lf3C;#TwPF8 zhsUw^7JvTc@2U(J zFMqk~zvq09;(tD~;CP~{U(5gTncdF;@`g^`+a5o9^1o<`m((74pLgrB^4mHqc}>y@ zZ4~TB_yg;xb)YyNm}bz|v!N=H)wk{}9VifuAn-p|IVpA}% zwoNtWdx&#)i9j4}$SRnxy<;o(FTfM+72pqn=S=|sYz8dCH0ty~n~en7`J!JjhXDrP zTI7IaVM!c&EXX=SB2w3dr=LluLShV82sJ&wb7(jl*U^gaD(*KoqQzkH7K%&qZA$|p zE;n5cPH;Y#Cxf|htud7`?OVk@POa8tD=ne^P;CWJ0pBR22;t@EmiSv1t+B3}YU=YexN) z;CS`)m@G@}=@V(@VWme)#Du4Xy{u${;nv5z8O_K6Qqe;?eK%>E2<#-zS60De-|-#a zh{^EtbhQO!&ss!?PGy)s+K6SnHgVoPB_Sa3<+c2>_LG`7{&znqvc14ybS?eslvj|8 z4tTf+;M=FfS7Mu@8%fV@TGHoExzQPdWA_~amy5`BR6duq8I9xOLH(`AtM)#7+q@dJzXm-Hi`LKr)%1|wEPyzqAL35JQS`B=tdLoMm_&9S zE9DEHSZ@@jxDA-7=M>lYcKfh_>@rP?0iBteD0}Rr;bt+tqSvwUD48AMpMpLcS864F z^_jEK{e3aZrbbbeX6YccXB?Tp}WU^S zo%^A43!kQO860*^f)XFOp?vYP4v8!!^}FR7BgxO|WKBJF1Qj`P~T(uSgO zMrBhm;SX~hVj+eH6&?r4GVw5HV?s5p8eQ&`AHRE*m{mI0=K4`-JYKU1@1au2Gn-yI zw=whP^XvPn>)o&@bQ;(&y~YsyUcj{)ZNUJY($$5H07dp2xSQCE0nvz?L@n=~SEFNNFoUFPU?>&J11gnB?-Q$46SU2~Q}$+r|hvTK9e4 z+A7o3Oz64UInbXJ3cemmfv@yDIKZ}xw&R~gyhv|oi2vlF+WqZ|h`YJTjb5Esa${_E zTmIX4hOq7!m@f?^d3w({6rjJ4mHx5EqgyP{HRXb{yR>u{*P@p z*yLmF1?)fLv~30wAoZdzW2En`#F_cT-9**m6p6!;GEu;k(=-N`m z^Vw>_)Yh_~CYKsO5MKpsqV{G59N4h<1DQlzfted-y^}Sk8z0O@Lhbw`4g69$*IXGoUi!MoaGYkm>{P=KB-OPX917=vJ z7o*zA=^1UK*UqCl(dz~bOs!Q@g@f@Sgqutv$J{)o-jurEdC0C4b(>#Ueu@$ATvIJl zgG-adwR9yv<7JK!em*<)}yUdCmjJ0rhLhQzEOsj`B!w8WfN`kDS5^ zDE-j`qCQL+IQE`yz=8|_A2zi7$q9AMCUlO(_1>U={h*EDHI6_coR+XF!6w!tlE=pj|1ic#3uQnBgl?RBQ1 zh4zdFnLE=pQ%L`i=`Dnon^mZK!$hkQu52K`f*2k2y-owYg0CALu|A5~Dga zMTO9ML!fUvS)bGcpKv}ME}WJ6Zha}N(ltvrJ^du3``pPN6+S`E4JNLSSP!uBVtph} zIK;ir=ef}}Cyw+EKS4YCRv?Q~GJ7;z&kE(eHS$loGpGqY1(zyS7K84`=!~}bJc!VR zM|2Jpa?+dO=c>w1ENUY?4BMp=my~ogN>>ryOrNPJ5JXYlkx2bY&NpB4u$=LSkWo+f zU^=2q>~{FU|H@vw?C@*9>7AJ%PZ6KU@c&aIK<)jfKfJzymPz!}X?D^JC>h<>e}-IO zCIn5qUjDuRW^0<|9>B#Gz3aq%T~&?ja~yy(_l|*N?A^^zmWH+>G%3PgeeD8Z@7z4X z^D-05LUi5DxogOT3c(=#T3%x~&Xqn(8-Ye;?LV8w#M$d;6Ae0T{LAC4OE$L6i8GCN zu5aQv^84t5)T?lBBgVdcq?iotSx_)Lo|kV1(3)3H9JOA7Q^rnM82OTCJwP-8=rllk)(s&aF^nW469J2>N_q&E^##;y*U3g?}?mh`-WA9&zEUQ zGW`z|48|MA2I*b?qeLqN&IL5qB1cvlYkon^TcFvR%*0)$;*Q9-9rDfIU02Ip)n-NN zauQQbPDwgPg9>eqPa2PFX*TFu@L~!LnnH0`n@%i?x z5qp^LLiU@9#`S-FtT!ns6Ss95E-*g{gv;H3$?&r>q~+H|b4LR%!53SPW$_yE!9xxI z$2_;s3fnGYg$>b4ALa9foXqXUG)iV=Yjml=RJ^SGStiuq2>&&o4XyC6*{^nqY+pju zG&IjH%r4u7og6xp7%SYA1^-PF7Z)^|KekvASi`dr5A_RBD2St=0m=V-$ko#Q-Q4i6 zobQ6`l&`Oroc|{`j5qojxH8srGj9mPIFmdva(iy73#{qzI@Ue9Z2aYTwkQmaKjl8Q zIW{TiIv#RS$Ptcy?%Ah+TyEBy9{S+9DLWvfT91d$o}LN__t!0Latbsd|Ldi|DGWK< z3_?P+WB8BnKoBorUPxx&z008H83XZ1d6_+FExim+^qj0LB{tYs-VW(?2uV5R9ZoQn zB@u^v+oKT)CfY)bDK!&?;w^BI-OAmtn=?eIQ;(~@LuvkFT<+%|SOkVx()T?i!C5yfT zmBnO58Q=W4VPrPF^fI^2ounyjQp@DSKfWP%}?Nr?11+>7oVgnefm zH@46>{6o<)?uJsH7tp*JOdBWCD@I4vr=&X&+D(V&9#1%|LXNDEZ!^v++Q)IrB8i}g zCv?T}pC$0uR*2nBES=s~fVrk%Z1Vx3(s$n+9|R`Qe78=pu>mRXl(Rh+matyyf6sLV zo^K2`6qeKN$QS~&%_aq3M_r__eDY*K-F)-ZFu)J}O(TxiMlb+G?7x{dnhp)NLwt1M zuTrPLH+ub)c!wV(^zP)3s`$)0?{G0S8H6A8-%*)@&kTD2@Juas>%NpvOeeC4Lk31!InxCGQ(tfq>O-rQe^h%h;a zh>^gtZ=}3N^T#{h$AV<%tEVGexW0$YMdTAx8wGZSnX~GM zWF9h`%6*UhXPAFiMDxD?8v~Cbm--_I%4S~icd1C6=6~jb>7wUG%^QnV6;M75yMSIb zXcW27-Zz9*YWJI3r{z|h+j&e}@?PmMFIzi#!xrW}r^^OsiVBmKjr*OIo5*kA9BX@$ z3){Zw>y5E8^!PEIcDXTQPE_Nx{*ZAAfeiy<%Ab1u6&9hjzsAh{wS2SAH7pv zd#cGyd?pRrg}U6-b_4)j2C5!X6!vwpj5$qqdIvL&R+p|(J%@{`DWmm%U`je@P!$g+&!%{>nM9>iD}BY zp5|pij<<^yDuTqe->md@R90l}9j;p51`n}cl;-_hSmmgIX|bKyteN|t2$@lznUYSC z4`HOE^pP_uFZYRQmrUUusg9PZHc;gRUoyfA1B}c_W~-oKAmNlL|K`!|ZWVlY07o|; zB)Tvca@S881Bd6;c}6;_irbXsgoRNqD(w=4JW5(+^(5DNvYjDs{}Ci?yXto|k6mOW zpY<4T>iNDJ6DZ5r;Vol$hwVVtpOMoMg{Ynw11*!Jz=QKOc!ItN`dvx<|I|h6;pqQD zIVSbi#l*$$F-S>CdyWwYc0>C6u!|A)e*!8vjkMTdd_sJt+29{WL5f_2Log?=u-D?Z zZe4YPMhz=c-iMD45BBp$OK!H~aE{xd^1r!0HpW@Pf*KjeW7ozt3pFS+Ex6(@#coy2mRN)67AzM?CP`Nxg-Q;PRd{m-3>U;*KC~y({jx%~2oZ^)Al^ z{2mLF;8>VrQ2KsMfMf7~M7i1M-7*yANj*G?GU}=S{e3{|(GQHCX+5uBB2Z4ewN8DO z-Kg^;C#z*b>DGZvR^#pyTt)l(y9$w#u+L&I`B{n!pS6){aF4N7TYQLHxynPirK$ho zS`q6ZQOvQwEmVHUzarKVBLgl`cgV zxuBjXSr&{da&B&eu`+o#MITwpF}eCDF41NODCa_0hlk6xb;TeS66dwcPtGLnZ-ftuxVv4 z`&&SmtRq-c6*^<#@6>DuI#<{jMxxQX!Tvo5#+BpCW?b<$x#EY*j z$1PM?{Zr-L$IQD;k{uyL!{Sj+`pgPz{D|Zn0#$3}1zb#CR7t21W5i%?EM1wv!#8A7 z4$W6Re8zA015#+%^8{W02GjxGuTp>Em&{ExqnNV?I`VdZ)1*x!8M)UpO-^0kRw`7R zQlq(feV*j%RqBH$#tvc;QpV~LjiKqOwXbceKPT3=FSJiIO-?do{wnbxt8t&qA#3`C zIvbzxka89t?YMfALQR0VPqzX|7zKS%hsaG2bLFAsapActsJbf6?y=Vu)0VQ6IZ4q7 zAV{B-huo2cY(SWOmH1Dh!j<*sNX7LgQV-cEUvjY-GxT{W;jTye=4e?2zfz9k%xKnZYQ1p8nazk4$66^=5#U4@bKMU&8Y!Lr{`$FwADE-wH9V!RR)`xB#F~sySk77dByL@A$J07-p@zzTT;?ov!gp>t*Cew|bxH zA9$DS!q0h@b|#Pn;jh#b*qx8r#1$xU<^2cb=HZ8SIeWc9yV}9rQ@3bi^G|kY+Yo=j zEi;iT5WFz;(Q1jnK-TQS`HB^`JHqJLaP-Cr$CDNHuvwLUPN{F=)u;ydV((~Y0>Xp* zHd%U&OEo!?1dRBh4nwfMyf??DgisrheS1sr&!SZ@R#l<6M)wk)?z}8SUs5=}!|APP z9!YehIQDUDdS+$@j<^m#wbT2pt<=5R7F^ZgcE!DMFY7qC8s;-qG??v|F6xK!nHTyX zQNUTgZxqKP5+C3QVg`q0r~&`}_N|An);SR}Crfk)k0aD0FgC-}l+=?s3aX zox*~Z1iEdobf7M&^J5m-(48c;T*7;gE!)21h!?}iNZ2t5?)6X8 z9|XR_zz0matgGa?1imqSsB5RxkL~}K>AmSSC2{JOi?_Y&zx+C!c952cXZ^+l)^iq? zV}894ZS|+<8U7orB)((1Sw|5bUGnrlUaBwuhgLGJzIL4c&$bybC?tb%g$j7eI1GFN zVjxbBb<0}B&O=F@?~V(vD8Tg8pZqpEkt>n4r|b#{CqEn*1djTtprd$ms$8vJiLO** zi-|^^omDc96WxGOfaf!A_;l8+l<27H{pe6+Kn@sx>Ml>C3-XK3T362Fu5-P_rrix> z2#d?Jf08MKEX5*+m(rPo6~s?2-{m^zPzIlG(uJ-B#$305TW+WT0oPD2v4B{BCEtRd zM9$ID{n!-Z=X7NB2}jCWOkt0!)Yq=O;hJ+J3;57b&)QXwF-xr>+)!LP;Wd=SwyjTv zp9ac1svX}=PBZfTNEn;r58&E-Vir6jcwq@bwVF%uD~e_Y=gFea$lAt>uhuM@fJTlY z`ui2oO{ii=!0&WR`&(89w$raJKH*7lY)82|92mQoK88GOhCv!G{VuS2hT(JsoxMb7 zt%cIi%dc{ehtijq6Bn;%)X#C`T8Y^X@nNk>3ZpsY4ZmfCKnt%qfWkQu(v*MrRr+l3&wpXrfEwVd$`uIw(XBt z&y|zqRE&Kp#DRA*2YrFmUE1-K`m#4UqVT*TxLA3);rR0dqeRe2r={~e9*%<8vW~s1 z?ohEof6JUFL(ik(mzbVe2dOo)q88nJ?hhm9XikZgF}|F-UdgSqZmo&1Qe zb}3ov*RD`-aZT)UDiryC&^J&CTZM^YXGSv!D-YaxXC~Y@7u~@a&JvK#|GrgGGZisQ z81NC;U2&?7XBD~5#q%cxnoc~(*d?nG!*WmMJkk)+J0VesXRDM+@eGcmHzEGvgJy7x z`6@*@=i&gji9)IgV@unZ{rT1Fgsg*|hJefaw#oGx`>KV}0rF>(P zlejf=;GO!72RRjXuBX`vlMK^6AuYxw= zZG9?B-_BC|QF}k}InRcC^SAIZ-|<>1(nF+OFfy>c1g=F8>>dT&o_zZ>_tm+0fXDfb zz4Sxd{o{GU#hPyAje&j3e|D_(Ty&Ezznesh#OJj?BMmPnhcjilZb7ru1#{o7OrH?q zu!gd-ikR0i3Lu{sjpcGx<+DW?hdAj6$)%kJc*~iJg8!Ui{gc(pjJLNvAKZ?nbW@?r zN!m+oqM$kcROg|x(YPX@g1AP%;{RdlESTcjnzlW-dw}2?+zIXyB)Gc;2=4BKySqd1 z;1Jv$1`Q%_4gda%-UA;n*K$Bx0?ho$rPd6$&)erZMW_2<^c`9DKU zN^m9?7#{&Iv3Z?Jt^fS~?03Xhf|tX;tYoeNrMsut!s}bl-qS$$+Gm1F=7zej-Qa;y zvCzY}K~<~51fsoy(=eK&k8sWjvcWM&NmAL$JR(pa+*VDdJrxja9Nt+usWU=u}VqUY48DA9IrsNL;?B9zEq8ZH97JbeouNT$X&n~62!SE5`Rs1ESq%K61P-Jb#`0Wg85 z_hvvNguW^+-E3uF&Lo&t5rvA7pqpa(o1~=^rp)d zXdlCCZF4u9Dqw9}3_OUVm|T$ea+R-}&A~%vb4X6|nac>9d+dKrCzm7Ssr0rnkRB6^ z;kyIw<$|?NKQVv505QuU1{;EYYCuGYqr0|y;C0BnG!kL*QU2h{xq@ax-E^bbDsTBiOBlWp(L2N&27WZ_;Tfzq!_A-8L=FN@AMUIqa{6$ zjBUZ+c@l!X?F8jBnj&_My<9b<@ViztHMICxS4-K;^&O4=30ubQip7R8>!6iXU@P>e zw5OgF9WKsO6OfECs=Ja~vNJW5vT>%o^L*mMU(?fJwL7bMVj}TLA#k8@DML~w%D5L- zTd=rZaU|B0aoI8M>8cQ2KsZ}{p<&-)!?pq-mP;|maAn{LDj{&;F$3Tlh|A9|&2)e- zzrARBGcb~7dYXw28eAb^H9C@hMuMmTcx7$+3$0XC#)UHgFkqrQ5nz#C<8`d7_zxuG zNbZh!m6qG@SLtYxuUymSUD8#KB^RY8kc%)L)?bmU5>C&F=$+7%Xrjw6zTfeVuwv73 z6B=yQk3n@}5cihA0>;>Mez++V=IC#%Z;n>MlmXzFezYiLBq^#q!-=yCHHwdFi~FPJ7rvLa}bJ7HdVA zYFkZg&23n;+$U-0!KyBSYG{j;R09tGT(NUXoT&h@pSiX_t8p#;xBFfKb3Ex~(%la2 znoS^o*=WAu_B0eYOGrpq`Tk<_aOFkeFJHZ~V(I549w01{ z_ zltM#k(QgUq2@a9B6wtZQ)!&%seJe9di8?#e8ZSSCR>}Pze2T0#C)O?NA{C5`U&VGF z#{k!VabEKi=l=7z?D78tR+Y&g(^>yJlm7`0D6u(VtBzEJAl=@Dn!)B6==pROW_7|R z1jhU|DNGqs1j_2Mf9oI_bejW(03Y)=U=_#?$MOe)gof*=-2etjpOOp!)C?FuAuQ^L z=r67k<=ePxo?p9_w-sNVtF>~rw)|Z@icG8F&@mO!L*Z6t5`ZB(R1*O*QQzR<2l{)! zW5=_>NHEMWH+lIn^({qM)wQx+ljl%qdzW|MMt)EC;ePDUImsrpL1>FqryfO9#A{6p zB+O~?wzvZI?k5(}aAD`y($EVtoB}AO`B3Zl&Srto0sb9F162dH$PvHGfYuad10~~g z^T^pLL7=kghjZNBTtT%_p0wXRf8p_(u3I?ZXMTelVP9~Qp0&J!JP8GeoVVM?5Ruc| z9_~5z`iQRJr)bI8mJgl*MzckH=HgKr^FK3zG938x5*+I5)Fsc@ZL~L8d=_Xyy<3U+ z@fzY-62xUwwnp>)>9YfX7J<}vZ3w9dt>~hRT?Z{rmn8+UyvzjgI?W;O{RHmC(*g|| z;w7P)Ou$>jECT1L`%A8iEsRalNY|v%kKgf08yLy#Y3^;Ed(mh<>wrlRz2mfFHTTh3 zBnpf0>)KJpP%S#gtHcYhFnQUN3;`@KkVvVvmkd%$)&h~gt2FqA@%5*+GiZz7n(aB+ zeAsMc+ah8esJLC=OJz)y=dk-HfuvKY()7e7V|}+b7+rX0lj4M^8A0^fx1fUv7R0cK zXJSmes%WfIs)@+DSl#PjvOsZ`~1B7Pe%lrF^-CO-(D|^2%jS>68C3;4%rlsIvzZwy>Je5 zhr|QG++3A}_%7RHvjMEAvpJ~;x_gVl4WIl-dwbKAG(9eDT`gsCO?W~iGA-@ z6?~+|fRL=h-hCFa&%WTjPr+-ymqdHsjR{o5Qb0CDW}!{o>SU_L z%8{3?GyYsKkigsZAvKXng;q?Q0j?!uvK+-?O%1O36Z%S}GL_1*?;y#d*KSyW!R?Yo`WF{P!7T0LrL^YL)VuFX?!UjHpqMarP53=k z?cz;Y?lI$!r9vc>@|YV;&|C-e@JiTbjh#myZ|s*G-!` zE%#oFif|Mt!(ag{u)6&kkJCEJz^m(?l;+VT1hlboogyb+qlzl}dDU|E?C21!JxY67 z#E{qK;V-+ew>u)4)p>C%~Huc|(DU~^RM)1x@+)KO$}3u*Ugtt~ta<2{(}%=!F% zwa&j(6g}y@blaTU{*}a)-O~wUO znR}EM<9yW0$QBN4)KeoRlKXQ0;Fd01g#S5?#HYDqKLbn*y2GT$@$avBZ}i+gz87|aGUYczW|s^ z$O5n={y+1f*2GZOU;U@1_bP{RGrB&{H|~Z(_5H1Yg8b#+hVmayQ|{zXHEtAVUaz9W77#`>LP2 zg=cx;&<^|G+(xjzdwQFqu?&L!J293>((pD9da$)D&Y@Q>1revM^d9Vx@#1AJGy) z_J`dt^GOkh>iuc?nA;Kz6zd~}f;1RJS;TJGH^e)ZvW{AZsJf^4olhv^()z>-t*n{^ zXQ%-vAB9@eb@GOJdkj4odten?0+4dj@Qk;T*^4W3#XS*=uUil!zqEDx(PzW8KAn0F z8N;!9$;ow+nCy&l^QJqupY0Y(a7oAwCK{%olEB)9R3ezt>kT?Vi#enWf5IBuc|i(=V_r1!4yHd zh4=eSE#*IKXfw*}(jP(5ptitBDWIYj-Sj8E@aGZ^3Tj2v`v{+0f4GXUB_5R&F4w@( z$z)sSmbuDqI>YN_s46`rKdXWfhI3^{=*`Cz39i4xFL#yeJM;a1mc&VQe z{oU87YkG8yC4qMZS}nu131oXe6!XRFQ!oPuWhN{>L+1IT*)6|6O>KRIv`Gb1rk`WOFE&ZCia z;quu%18uo%K6J}0RSq(#`oSY`lL@ghTN0laHL}u%h^JJSE7;i!oyff+J=ar!&nRgA zAaXV7T^ASWQJU8C@I@CMtMdmXGISZbwKT;6z%Zy(W3W&F8+Sj z?i{}<8rZk=DI9D*&*`ck7Zx<6VT)VAOF`tKLfK6sU1TT*`tl3hq1F0P?7}%t(c{EV`G>=w z&F80kY3rQ?qL86?)25K5oUV-nSsj{Myr7 zzS)t@k(~H_&SA}nv7qn_;k!S5e1(J0k+Ch0-YTyeos))@{=tQP&>a1&g^cu%b<^Cz z(FC6EGYYUf+EZZtdIz}Y;d}{Zrf($xx*fT0SKl*=$a+)#gkL{GpIjj#V`#iM+lmwE z%l`u2SigYN74=u?o4JS4X%VtsFf8F|e-!bh>it3Qec*qC{_VKj6(*DY4tPFYEw3^xZ({jdcK{84ftTTu^J3VlJYUYjW);{wQeB z3|C~I0ox5^70Ay0y}{jPl#WTZ9VV+OI0T!CnRc=y5gMaWlmb1xiL+ zi9j_a>f6SP5HddbV%Xi!GbBES*%5kxS&oN9CFQ3www}J`$jQRdY1~w`am{rQ+=VM* zHPOWLF!i&?;rN;vY;G>!c@ZokVD>WWw4f{BL^kiSt+=?GmKLQ?w~qBBv16h8v?IT=VF^r z07}%UaCD;-wMoW6!jLr|K33H%fKtE2Ok3CHI&E|mNtp^vVGNdaYO9_aJH@!^Y7O$~ z;@KNbB3;ZGa1+Uz#;mr4)x8fy5o__>3{Ko#0cI6t}9B73fT&C(pQ zu#2I`rc(SL;{4?)=4%dkD1~fjlZb(6g)@B|^tM5^L;Wx>-tGl*+R7y4#=jyu=QjKO z=Hb11rI)Uc`FzOs;)2%FmGhxuh>q^h@Uu`-(Ey!`n73klFioPrdG+_13GvlBbf5CO zm}h%_&D81?gmpZV3u&%wl`VL|2_4*>Ab`1?<%gc551I2BFdD>y!P+ zarJIFg(9st6UOAHGs%@EA<0I<7k&wOvhmCi{w-qFriWeDudu90A0F%$Riq4x)G<0v zq979a3hZ6S{p(~~?;$>E{U3Z7Ept$}Kl?cPn3Zqgj?dt2r+kOTo)(w6rnvqrex95g zhuxfxAHOKeg^j+_l%=&gN5cRU%}b$;zgOZ08EMbB1p7 zg&u}!)PG3rzQzbZON&%O2+R49!}VK?UiIj^h~1=fJ=-M;5)S-zcG3^dK%Lrw)J!40 z_m5F4*veC`ZP|@JCdZe-7sK1)VsRb^CzIz_C1dLdspI>1jNm7o*&V{=cVt2nnd z>%TMfiJcWH3ClgP(Z7Cx&({NJy0YFj=Tvd6)UAK6T6I+JHn>#ItU5Mpb#0{cBK(o> z!P}<@TWVz5WvOD+?TX0nL0nqZ=1@4dn8dc(W?$@>D;QvQtOQ0r&)CyGKR<+*b!omx z^Zk8~&`jsx7GG83P&ZxWcd_0B4%oH3@YsCb3Oy%z)1VvvH`BisTCr+P7G5RHhK$ya zMAtmp9PiIBe6!x*7#-xJ2ip~eCm-D@0B(gE7l|_Um-i*ze3ypd|MteV6l#Ny&jPEo z=EDB72VuZ^>kYV?d2;vkupsbq;5pNb;DE)l9DL`hYN%4w%$GFude(WGJm8asd)*&7?g}*Y#o1S)COr)0+#xq?-JmM-tU*twnQE# z2&CQ|QD1Z9eKGA9#=UtsD~;Wdaq_L7W~pz8<|jXtmZJs-LD8cEe(*5x^ON9~wJs9w@8Cd1 z4~Gk;1c|oxNxz-`K1j?g=;Hmi=zTBxB3g>p=(dvJdwJ%mZhrm(?rak-nXcgY~R;BZ`i$8x3SNgsLL z=(dQF=}+spK(u-ezh(5a8f6eRS@Kh^9`Fz|mKD$U8ebj6D`qK)^0Ap2X%l|pu1&@& z$Igh%T4aNFB+oLAoysEK}&KG*U z=b+ObgD402oK3=xi)^1d524?g$DME80zOF@Q*(|%Qx*Gj@lI5crIedm?DD9-=dzLVfAGMK0Dqc%v)yI1iso4j64x4R(eL*!I z$JXVt=ihVA>msA3dLHx}se7S2u~GOqn_|7lp-k16boHf9dbR;hBxx#Q5%G%Ygf8hC z7u~IzH7at|exvx0(js}DB1PyLfvzw{f8*#`^DknD4@6Fkp3nm|RxjzRonf55rr1Hg z>POsOAItSt~RuYY+@iWS>C0LPK7P z?)aK$oV0RU9C6oGFNZ#9qbv&5%xaIu2QQr z*eIX;qn+8T$*5bqS(E8etieh`=r8@YO;^LJ{UQh=zmg3ee`8?HDzB*Mw|*D9K0KWW zx|vsCH_Fm>Q-b{`3O~W#nt2h%R*OAMTnz=Cyd^ToHp)RxVPVF}$%(70zj5!M^@qu$ z#}5INBEq3-w{E*WXZ2@#M9=)b&50FlAW64bshx_Zn>T$CTHAvY zX~t3mf6&937huMO{o#C_8R_qKc5${zqiPwHl;5ec3-{@NV2zl*{J z@RVt=<$DGlRy>7jxLrD`K)wE7#o?1MBkJGZHR8KXfu^z^Auz(DFocz+0Dskv2BadE zuttQ^ZJ`|h0#gYr_u@~61JtC5KaPK=sMv|uo;S6y0tdbMm_r%A!tGt{Ju`qJdB8i< z<*(an?Ebn`IB zMGsO)<77))Zj8UN4aDG}F6w5^)KLM6g0H(yfTnZk}U6xAxhAQJX9S>mKvyg`{DJDHp`*&P{MUAIQiQnT$l-iL)=_B?fw z@tdE?eoXVN8o(~X@|*R7bMU&y9&>$EsdZ-gEG1oKv?b!tUYbQZmc)xW=TM??#qR(Dxl}U$&_x z(lYvb#M5TUCHFv5Ke-F z3V%^SUsduTe|0ux_H5Wj8p7C_!}Q6R$2#*30g*(zG(XwGVGUpXeX66Sqra#3o?%3D zSY4BPzE_Th$1Ym;UI`!a{=~iiQ?rf`U$A(-!C7bC8#r~k%xz9}kS{#x9n~wiTNQ_N z==P{IrWnM6)y8iNNzd%l?|qzh%4j>^WPdRBXAJO#PU=o_ru&a)uY1R5lJwqUP0tM3 zi4pl_6U_Xv8oHYeDDN}#yL^r`@_G)E%qpb!hnvMW{Li(J4_`oJ`!W0f66i;i=h6@T zwCN@D+M9@%uYTocv`f*Qi&6UdD8Bc2>x%PT9I&X$VdlkkkS0`^ch?0M=)ph)0Tq(D zmI4K){$Q?60YN-BP6acz0lkmMYE5X8S#<_zyF~Acb0_gK=7cqfF3eePX+YOUc*>t9RNu#U8j5eXQwLi|0x{q{AQL{gBGow&;L+p7+*90*J0-8axXG9x#Yv`hg<9z0t<$MGi8%Hm=#=_`>!05mJGDn~4 z^vcIe+R^UFv5@o(Y)uU`0|wV1Mcd_n=tRSGADtx%U+*zn`?k3`tcFd{d5dBmpxDE! zG!)UtMB|g``JO&!JG~LYu=*J-oHuNX(_;ah`ovbmNqPsUtvw@&LIDPBJ7=_0YR_nl z2IY^?WmJk=Xkij7o2u&}C*^AQ8HD#|R;HI^ZGnNcrZHPx(KQ0Q| zv{G9^HT0Wo3Owc~BK=q+Fb+~J!r2x0sZi*TPyFaI<;Q{h;{AnVEYyv4ma&duM}wH@ zxl)AVNhshzfO?rqD&9Lq3~DUotRS8;p17?qtsrHHy5~0a^F;lbd?p!lO?^n!Rq}@$ zJ+M*wr+B9g+%a@_Wqo}?1F${TJTSCdLrKzE)RcW`B_4nq(%kqpB&g5|2hhaZJKuCp zlrdGRyzJ>Orj@NvjANiXiDA-Gr`?NdEOt2ZjhHC)ljkg@L*3Fj`he4h$NaZhPNY$7 z$B0@1wQ)ltUg3V6rCu>8XSnc9Kp2*pyjsVw8-Z^9QZ07|64{q zf~^(lyZ;$rSKyJ|F4%0FEyMdbA}i1U{h$DxqW!^JdcbU?sTAvK-d1os zzy3XM_k+%`nD1bAT^{6^sAjRg%j+V|pzR`U;`JlfJ8X)?uSZL3iyQgY(ilyu6O#Q- zD%HZ)ow<^$6tCxjJ6*qA5H`A1{E>#}12O{&GI>~risY5Uuc_P_YNj8O`W)I~ox}{Se_)hN!$7wRr zl^6X_@yJ3k4AW-d#vu1E?w&_oI>T3$9}bK>NI_6Z(|pPVpNwChNn+=G%U=M`p{QzlE**Z9!)T4+%6L_ibWRkKGAX#}~~@0nk82)dSZS zm5ai=fbNGESYfumY&Q#q2M?JBL3I{6cDUC6KcIKG&Zj>OQ^o&{eib!X#V>yo6?3%C zg^n)LmYZm?>7#a~mpERuYn1Ddrl5Beo&JG^kAhYjXyeF~$f`C!iK;!)9@U61&j?&s zHi(!nk0)vK9y?8=f?%mV@B@EGPsSDkHE3zb3U_e`KXvO+!Zs$**E~g#Q=Scc2SyHS zznS&Yn|JmZh!OQ|;5?DVtvhPUN(oj%ui)*3-w`a?J1O^;FW9iyWa?shf2{!~ZAn~L z_ZA=EZ6NAz1Ye_0TkBQeTGWUgp->~cv;UyeVH19+arMAYPR^JMF%5~f7W)yxQ!NyC zBCO*(OmMT5Na5!BhYNg;!mrQPb3NpW6NTeMRJ@k$MpsDr^Sy%Wq-W0>vyNLo0qAYn zfi`$AD8co>KM-LHgB?goi-#~Z&JmN=G^O1Kii73u85ggc?yJO_kN-j+E~&o0P1GMKgyHC!X^h`^9ynNouh)Srfvs%H z2%_YXUDH&piLF-!q{(%Fa=cyFyAtBl%jgTAq&BG`$E1k?Y!*Lt~#Kr_gr+x_JE(~2RR+LKE zK*irgJXaI9?;_Wb&XQQlQ<;cH7W@)XqRq?FeJz*r#`bKj5{c)5VyphSoSAlwJX>{I z7mh33dRl%EwRG70a41q-fZjltSx*J--OYZTqWR3yrCT_Z>d=VPSE5<5sg#W?=2KL| zAZH=hw={wI)5VGEvH;Itr=WG<=~-udx=)}W?yt%@zQ%u4RG~cVZ7$Ny<8KNP!N5y; z3K1Co3JPHnA9U+L{e;BCNqVeA(8%u(vOY$fK|8v*qUWxA-UG(1Y$P;dMthq-^?Js@smbUM7-mK!q|EESLhy0H zXVYXXw4NMrF?7FuJ1ZP(vU~f|Jlk_&LnM>gNYs}+D@OL3;&a%i2n|XDo>j{i{To|+ zY2t8mK~g_|ApKKQP=XaBLgDa1U^af~Q#|a$S1_*ltEHD8-C)R1bxuDuv)BAv5YKW8z91k$t#Uf;r#cK_f z=1HY8Tz?Ld5hbexbC3^VX@})`(OVQxy}|7W?XKI5XWpxm zSW+>bF^VDiz!b`MaI2j|U0GiS+5W5%>OKEw@vR)DG_K4tU{-0xVD%z5gn7KQyI6@F z_6J@oY6DY1TIQ8UOWh}6i*P4WBldaSv_VS~kIfLsrSKpD%UcsOIItbrD2DwEBPfW~ zi_lj(n?TT2)u(|>q@_Q-9Wtr%PLn`1>`gd!v*@adE~2?9_(rjAD@lDSIu`X}ZKy+Z z&LCJKnXlSwYgE>n(f{1l(>620Bs6Q5Q~)#0?4d!Gak$}C6I-qJDqu8A#3pYeImzuks&ACz3N4n%E6N;S5*|rTNB7#@(sj*jFg88M<1HCUVxz0YlM{?^i>b@C5>HwD5zzEZl={5JD zvr&rM)wj~N59q<=6=K;cM4-PO8ADLrm(uA=XMHWlVrP>HfyXpP&P1T=MVj*1lVR~L zaYkM!b8=?iHgPI3@FY()TV_Gr_JJx1dsEf^vML<%=o<==zkQb1E`Ur5+IV|C&CNpD z=2pl38OE{9sEYEM7U0ajYwc7?Ad#|o%<(YqV$uS}^_1>pXfH~SE z(^yFa%Yrl6j#@_Dz1d{Qh1~X6W)Nm>f1dm9=??Qa3lTV5wfFPS?Uor%^}HDt`x`}W z3NeI+?Ga;HfaINTZ5VZ-<)(TuVSWaa7bb(2zB^@~gI5yBhK?~?r2S^Wdi$ZunH$Cl zwA$-B^UD0dtgpK8mMg>bw5V{#ufFi*?B(Tb=<&~xXaYqiN8k9}1;p2}`#(j49QfB2 z+_x6Hn1Se-&3|;G3@rF;Q@ZelwR}YFlw0U)%5<2Kkq4iIm*m;7&Pbbqn_VpfzmSxg zsI1b~vwe}6u zOC$eM3=#3Z*YILz!F^2&Wfit}7I#0K3^0yXZz~4KKKBj)M8Tu}@fr6JTee!9H3@+q z{=kh5ifFAYPHPr`*#?irFJ<4Rl*rJY@S*lpQU&1M&$|q9Rr@-e-PGg1(vU8^q<>Ne zlc7^u@#&9axELsZLLbfbe5G7R!+AwGYX-1Du$PG|(d)?Cr)x-q)z5X!rd!K1ly)gZ zfE6cimDt_B1)!0^N#~*|0RK#79oL_+H_HlHlqyTH%uz35fmcrwaYwjm1<5l9$e~7Ys)~Yp^1?9mJ#`z+_KdkmZsDCnXVpYZoFc#8lq^e<{unz76yi^epQ2dg4x_I~0MnI= z3a})7uU#BK_e;V!H=kj|Y;X3<^40ipI=uyYrH&sP*_J%^SIMOA@f8wZ0Rgg0PYZPF z^~fEHv@EiZ82mH!w|fR7`9ZDBC#8;ZhV=+gi_pJ0m>A=}pIxvE*cbL@Z}~z@hjI39 zXC3lt+hh{_=Vg!+Gc7j`M)Kg3_#Afej0Ia*Oh0G3UUJ^e*hTLY1km4gpE&t4ao1*E zmuu9)h)#5vDQN)pI7Gy`A3{L**4odDKF4|PiZ~o=t`{%{!S+$uO9;s2M_m&m(!bnp zl!;-iC%jm|9rUnEzX-!v&tAJdz%tY7V>$2 zB8Bx#`8AvGL{=eUX!w8vNVuvCNW83$=#l}!OQbgU^Xm5_NkyZml z!dS`o=KIv3Q_jp5G>vBY+ZkecP)W6cQmWcO|XKD zT10#*@8=I>LX@NTp^V=e3vqy*wKaIFQu^aqh@W8-!!%x|I>BHx5|q&x?{G`x*hT|| zr`kaHz?VD)w0^4DWS*w?W~`MpbYF1m5P|2Y9qbbi)<|+QysN34N7d~TFeQMn2fFdg zwI3_KUKoYdBc#CaW)~E$vNyZTlz4f$pN8Z&a%wSHS=jg*i+`^t?ENY!`+^}9^XL@!l`zUyF&HVn$z!6M?oEYH2>W0uV+;= z7S`slQ{nOXdIRAa8AgtZzHO&`dY~Cib}BTM!yCTut9ltFL{fN#r}O$jvSHbsvG#I+ zEG^1OaxOFC0&(a){YEKG61uD!W{eM`-L8`LLzM{p577@Id#ry2k7x_4*x#6oUNG$w zA@G&U#{O7$pbqR4>s!tib>3J}g@Sjz3GOTxr&9ovI))?)CKRIU0Q24{jSS99jJ`{Y z{AT;KjRJAg>vO*-=(}%*o$p6@3;805Cecv0$maK17w>*y`K0g=a%)z3^TVVSi(R%O zS`%x_YoFWoyi3X;q_Nwz(EoUqmVU-)-{rPNt=fXZAK05RR5s)N>5Wc48%3#I@Cl<8sbDX} zlRom0R?rp>M^o^mi-_&8=t`|E=K89rGXP~Y3LO&;n`&PMuRha z6c+7cAxtbxtDaP_ovvIP1wC(Fe$Af7#GQF4xqvXr1~6#YMRk?`@?t@eV-Aoi7ORIG z5S-ftwUP|ofC~fIdTvcPPGO_RNje2OsojetUQ11E-j{>=^C>Q$!w0-yC{EAF0!erN zD>}J914W&ibXj^|4sZAR{N3-ZFAs0q^Mpm2$FLGWD^jiY2XQy_xpFg4ooIfZYf(b5cV76h5DWUqo;NNb>006?;h~qPjlSF%3;Isl^wc-}yw3{swJkKLKIeGlHoImXG8e!o0>nAAM8^tawZ4 zf``tv5Z^5CJk%zi;gZ?^aL*7ZZ>rHQt|0b!S)x98R*Jx-#bRA!^<+!-gP1UcFbweS?Wv`KX%eQtO@Csi88{?6Y8DhDVhr>2iOtK?}fML-16eK*lllw!5NedgKssVs* znmQz%f#SmpwPTsSY(-r%;D(@$=b<9rgu+G~Fp(L$70pXHPyFx*QE$AK-K5Uq2u6fe zqqcMjObCZJ<Z`aodbg{K!3%(cOvh2NfX^4UgK*Ql^unAH&%hgx`-a zU<6kbi>a(j$?@e+-x<6B#^a|)oN9du3teXt&kk;krex^8j;Smf6m?W02Ho5W1t?jS z?UODyK6-uCtQDBn+yxs(V3rms)2=V5f8JQ|A*VkdQdLNC^ED4Rby?p`j#5{xtKNa% zFefOvj?VE}PwQm<^ALaO3}4f@ByuaN3|)vvqa2+Pj1!@xcR`V9c}5m&Yc!ez#BP0V zN8?kLrEJV4f~9xEYkMfW zb0QMM9Kklyr4O^(+Rrbk6th9v1Bcv%?eFQ`?dgjhiRl~yZeqgHDKqy6SPS3AHCZ)$ z_NsNDIM5{lm}`6p&o}$EjsY)C1f75b@yYjdNxj$Z!K$kiOFk71s^3CdFC8I~UEK=E z6_elIU#q?C(`<1cWL|ISP0_u76_YbNjbSQ zW8|MTW{CUP|HfKjvkaJ?I!gV8c%*PexorD-sbditySMR%2%xB5iv`H5!O{W z_M2!u6l!XfSeT-bq-_0#<;5q@K7z(^26$4?0jmOqK);}i7BJqdp!AnLplEnHaxCQA zRDHd`&|T*g3}OZga&w+ZVDg!vT08in({0>>fROj|HC+3`YtxWN1HO=8t~LE?jh0 zx{iBq7`0@?rE)tqUo^8v0?oIN-w&-s+iS5aSc?`?l>Puj>;6*XjQXNPlIN%4moG)7Nk5Q-K=hO-fQ(4Fu$7`)T1K zFT3L%2vXHmujbQMTVSsd2;2!~%-Dz5X5qOl z;gp3U$Hw@lp&pYb{8A$c^I8u_Xb9cm3xV_F@y@qA^B%81cH#uw3@{w+MxEN} zB1snWAV#oG^<`2Z5FVd{%zAt zw}4KWKR_Bh7F;Xq*amwZsVL<+3u={P(=8J;mq&0^ouleY|Io)r+#(Vy7nnWCg>GG> zJ&m#y)be7>@qpHeh=it@!agXCwm-r~m|q&w0~GBYivNTTfrxl!HSh#hTg^g(hM<0a zjK+Y~PG9L(7ang2RfAQu%r0BYa*i0-z|?oC*m)hXgVsNlc8lRGQ<{d;1uM7Ae=W0x z{f?pa)b~TqmfxV)=L%r>Fh{*$AHt^e``yqW0t)1B$$j|GPwh-Ko&2DP(PFKbE>wH# z5)`;vh9$X81elOe&}2A$MzHqbd3i&V84jQJv9ONxJG;RT`D`L!qkheT+`@`GG{Mn< z(0by{gA6h?DWQI%v$5+;Bm*GzXCn0r^I&DtBLig>2*TM3KU24b;%n4kE^$gYJ*?Cwu3{1YoR!$ zxR>JEQna|cySrPl;x5IV;_eb0f&?j0+%?65`@?zH`k(tg@5+aK&sv$^%$_~h27~2p zC#jC>#`~jumz6JKxiEGemXn>HwSFev6h|>4+EfwE1;1M>Lb0Rv3|hHMM{G>Wxucv4 ztUu2l%uhpe&}k69nyiHhhcyduwVI1X9mrs$GGjfVror-~Q{vqE-fY#l^&%k|5o)h# zU=uUKjGTuylRS#8v>kbgn6=bXtGqaLX4V~%+m}0mCs@g{0F@j(h{qA?omt08lMe`&F)@I;iYlKo)=qk}Lz-IYO` zBbJ>n?4(X1$~UiNo6LG`JgNRl&zfxX-4bj&sReGlJx{`{<8BFO=)Oz7?I*>B?AxTK zACx{SjjXuImv$OqPMa7YH{+!4QwOi@LfJ>%i}Cuw7@@H&{sal_9Tmy|2@1~5)z~j% zkBO^a0JCfd4XluwdSHm(6cDSbozxG~@w7)tj!o(0ly66^j%6 zynxljE|_^I)#*30G!8hY*2uG~@R+L}ihb$~B##&gXI zTlCyNTVIex3gGD`B6Oo?f4VTd$I;oJUx-hDg$}S^8b_W|7#FwL{`BgDnjGUBRzE&g z05m~4KE=k7%`TquJx?!+@JWsy{CHkI?*tCGhSiN-E_hYApgrghW5+I&a+g3%{F{qj zCgqZXGW@!!1W86XLOw^4ce;yl#-a978xNJt5GO^LFnmZe8=IQqTk7&*OMR_{GIx8+ zr^yQjek`E2j-+C&G&fI2(n4r}%f)!wlWVR>R~L^h#hL{~-{+Lh&tJ0i20Ge4CEBy* z^iqoYQhH8<@V_My2kk$!52>0#yMI>S-%7d zlVaVT&5z(dt^p*{X1KgfED@GpP3;0-_}IT!2POs#L# zdA(k&HNv&zBWZ!9ll26DH1f^mJibXygkhz>@+g%g-UZCeOVa>Ydv_#-tKt|3y$#1d zr3y+%M$F5W8=HQxfEz2e6jWXl6hQJJxrz<%h`T=J!f%!KR5Y z24Y0^7F{Y^z4*uuPDL*9n&9nu1{?VammHFK%G7stKcKVV?^o2oA3GU-a~d;YTo)Bw zWV?)_Kf?H8%&3tCu-dG0jw)VJf~yBB zDkt@^RTj$FJTBdL$z%#UvKi3_OfwL%i#SPGN!e{#sqNNq0SL~d&Zeb3lCqU`De9W}1` zst5QsyyXK%3pSTdr*CGs7Q+`$mo$$4Iy7u!ED-ne`RB8(&74}~zke#)7Ht1)E`FI7 ze8^1d;lUYn)^36$&{$`3m`z>g zfBm5Tv$UY1+ZzssXH1ocM>E`s6w%~r`D(Rt1bmJ=qI4YNYi51Ok@~qmZcz~0EXUv-MR}HT=UEm; z*{pF6+(B4Qs??zRp9G>QB*K3*XFNJwn|Bc!mF-OqMsJX5!2qaiab7je^f%P|E-ozb zXO}}7C||um#~vzQC4$2mKCgz_=X-jyFwNtkd*#D~Si>pj7Ey9~o|2I7A(SzMQE6G{ ztn5eXmy9ASVP0_;bHgeC&*%W8PU8%Wn&3aRnk-IL094JIK;x0=<0d`RT2(Yew(n@4 z1!mOIXzi*bHraus@VFTs7yYSWso^uYyiu_7r0ho^woh0)1mRPKG%U7NiBW9$elL97 z}(IcU)7dl9pN?X*0}(L@LWg00pDGIzHd23-&Tn2O`t(ta>pFY7ZC+u5EA z#DSbD0NM`9x{|eMjc-KH$){U~(N1Nu{KY`W3I_8jWS<2GmHZU!%Yi9>Rj|4rv7DNQ z=My#ceXpKv6jMuMqMX$2I}Ue)2uW0L(F{Zhq4Ff+S%&yjq3qhWX`#5y=L){QB>9z< zpAn8!0wtG!07XZ_fmX_dUzEGGsX7|Ju+Kj_C^B2`T3fxX)<(oz`1<)4RP$Iu`<7_Q ze`XTZ(7#jt6O1V1NP+ZuyYWqP)@lZ|A?;sUrn9`|LLr&Y+6p4`8CtGaqiO}?V4yJ%VlhGeGE2cEk*Gdz_i5-o5c;9v0D z{AS2Ozf+drlP#($<|(Q!9t5KlO{P+uYk(Qd7_+E6DLM6xU89|`>nr>9du_<2a#GS` zTrDvzYszM@6V98?_(;~C~PJr-EIil8T$&7_oIKKV2QA5XlR%rV>_~E zr|4ukvDW$>z%wN;52=l2`^S7_=6TX<{9^75**gVn(h!y^%8&N=5m}ABMdBzJ7w@kh z7`U_O=E)A3W}Zz`Mzveay|*1#dCifvifIa+-Q&q?DnhuWBc5c zG@I1peSLd5dAR7rC+w~H3O52X0Pd&zx1BE!-un>&n`hR&I%A@WhiRG}ELfXe&fh(y zc8s(_Q@8Pl(VyfcuM@64PRjOl`*0%t4kKH&T*ux{Zs&2XnN8Ol@n{x8GG3O>JN|HW za3o9;=5@-mb(|Af9g(7R&}4k%ln)l!o=o@YKI;SSzOvxxPuBt}IzS$dXPLBcO&0&#EB<&7DnEY-uR3`4yTlF9-;iY=B(4Jo(9OyJeN++=p` z{ThT(Wg6c9CLU`lCJwEp$=WbbUYgSLuewXHARJ(NFi!FQojDWr#*UzW+4?kkrJ^9} zYcS9OpuU`aWIz}UAb>A|yCpPK3KhA@VWZPz#Rv{{U@2dcH;$Y=-G&wJ_@aS3 z!3?kg;(B^}(*jwMk8o^tKd}e;f0Kt|f(xJo>VK0stM-BskuB+tt2Vj;bO$X0@S6A3 zWQk(%i}wpvl_sIAHRfo=N}@b{s5KdLnpqxKOZDo|3@Nw%K9>4D%*!X>) zB!3LyRVYlvH6(D{$=|5Qo*-$n8f6isFUz_gWSjo{-PFa7Zy>UZ$puy7gwteEGdFsd zZum_)L)N4Adc~DRCv4a2tQl!+(ihy}Du=a~2bM^-p67-t=W!p=K5C1h(!?RxcyU6C zuqI9YK4w{$#VWrBDSpw$juv#$voe+SI3$jXkTy7)((O%~?}O35vPUvQ;U2-6pk}L4 z6{Khz;mW>q9>GRx|7xTl6ejAoN&FLE3!tZD6d zi3$eFb;);ls^^os?bQ9UV9Fo%CTuexM;7>Z<1SC0A1HR@2=VBS!MDD)KCFM)yMBgg zC0O6ovHtNd(^0cd33L1HTJQPAQDtc)1s(ghk8@~`Z(Et@)QZaxpET8#6pjx0Ji|@V z$oq(W*!!Dy?NVk2C_kjH^l*6%U7FuihH~!uEBz7SM;4E#JoASOH)GkxFS>HLZ3)#@ zr8tPH5nuf6xQJ zt@XV+X{&k(D=eJ3et(wy+SuvgqhgR(hf5<;i_iCNpsJt6BxQYXng7?LpF-Tun8nbr z+4R?=AS3IC`E~b$MJVeQD#TZ-x&%+S3l#U0I73ThS2BLpJ8Ae#kdDxyv`C8xQ8cO9 zQ1D@t5f4hg6Vd1*iM6Fg-87kjQ0?bn4L6w`X-m|4=KcZwPIT?iM>QG`WcRzJv4dOP zj_~Xa=yB&<8gPZ-w=bM($+pt1V=olIv)s+7dhdMDSBgPJ&r@G;+kk-j3mFhTO5Z2_ zMa%1?O~4N1Xv&PL@4zAgp3IgxW3ME>~m>KW*b1<(3GkK6855Nn2UjLqNP%=qe z+4dpm|2_~}xcli|@2*>o$(*d`CX`_;0}zZf>H@FXCP0<^aib7+wyCuGYtRYR?;^e} z)`Wuv)FMDgI_tDdq>ye=NsQIn$}9O3^lhljRpr_yR_>UB>pGvyEg5Mv@R;d-D**v; ze=x3gD4=mUc=Ff;P+YH9^c;~{Yq~JHKCCz3IZ5sI?K9rS5NK-q^M@m*BgKqauDyh( zM5M>(#@-A1oVojLk}u%t)!8#B0CCclC0hmiyymeDdtG}426UK(bLjQhwyuw$wL{UD zXD^m6b7Ni_d+2NfR-gQ%9D5AgHM0W@wEw5{J$k;!UY(8$cP(7{ca8L-1(`mwF%w3; zpvm^0qOMpps|f&D!H61vw%JfOum5fw!6ALkBJP&3+5F_1-#f74 zGOk953L6k-i3DtIQU&g(9*Waye`!am1y~j9^~N%6ROL~0tiz!L;LAiJ>H%h`t_|Fu z)De|XMN8!`^A)_0NZ^ag2@mnnL62S_yH%2(Ko+=0kBJs?_BNo?Y&KUsU;$5ZABI69R#;ANpd>6#KJO*8GBeA6_nJd_Y@ zh3HzyOjTR}bl%By-lj={y{%AynlYQOa8ZbdJFBd%8AnNHSGt)}D$dQdVfb1K+5E8` z!}|7zQoq=4akwCdvqrs^Y9h@H>hVp|##>EohNJlnzgdZ{uADJhiov1wzMjAaCY*N7 ztBxvt@tw4jsK?z&>akMS(_F`lHHqelp68-2TpUubW@RBjRuK43aRL1h2X1pz$CLW4 z?}OUd>&*t}I7l5@c$mq3QFYa1wgpevYYeSFM=B%uonxV!L_wq}r6Otv4Ngkdh+zVy zhrt^`GdHUK{=SwL&7g!=4nj2Bq|ncyvPwUj3EijLwbDE^W%B47v4}-f9FIqzVj#0G zGD3P|X{DLdQS5K&WB{=o7U?ZRY1{<#D=N*y8r;Ot>=r`_no)H4WDOWGs4)|wuKGjK z!M>9jcn_WL{R(Zv`pSQM>{`)^2^an*vc%PpwTIJ%$Iit!3-Qj85J4{W^=+|M`ddKg zvF+H4mUW>@JR0t+&VY$#lk*L7&xGwDz!{s@c)WVgNO|(W$vGJn-9mArRrFanB@Ot# zk~M5J%sZ0%|5yOOE*|golbZ)SQv(>kUy1A6HX@vQ^&CFRXLD?Sw1%_UR+QZc6Y*?d zERCHZ*Da#O&NhMbzGK95Nprpc-(>HG84Lr_z@{)Jy7L7rVHZe^{27morKP2`g6OkV z^gQ07b4TD!{_aG~aqmq~k*;Gr{}-uU%j}zlPy*$|d4O3v-)xT$jp$Dv!banKWT9nk z_iIh(=Fa0ZpE%$&=VZ1lD{F2tUsUcqb2Z6qEFIv?!=P2=T4>$(lNpcpz3D*}U*_5; zcJuQTm`jCw_J(Kd5eV|EVb+!lcdBooy+{TKSPkLd?O6Ys>m8W>m#9G#>_J$)?l!m& z2f2&+eC<;>olCR&l5P=KZt-CMkILqYo5%KUeE%W<4GMcX|ND2x48kiSEW}FjO0$5i zg;S(9%+fJ`G%+H1nkA=fdb&(@Dg)g84E^)@-i3&N#)YHV5L1@NJZ;x^)M+@(Uq^KL zd7L9P{*EwjC3I_%D#j_{={%7y>0(K!dEn4P+bM|iB?E>3@lV@SYEF(A`H$Lz*zU!_ zvFjH8VGUN>NzGW{g~54NL!ZsbRoIeEO^U~wcSC3IX%wUf#PNDA)&G4PW%vt!fJ@Aa z3Onh~u(7NR#J>*{V^}U>=U#ghdVwP`XF^@i`Xms2mjJ#Dxo3{^7m0#ySpNY}&;LCe z|M^}QL}OQR_@|+M-NB5}!+BgFqr%&nd2o^`rY!n2hwkw#+jqPncXfcI z2Q!2oEraf;Z$&?nVil?4#Cxebk(W6y;QHgqDgLze~TjTyGd2R51CS37`=TbQzJI zA^8A*{|5_Tcz_5&qL1!?8~J1<7T|@iI=)y3zqA)3;iixStKppjKhV1g z)_DBbG7mzZCN<)Y<_uLs2{yz_=BRt!vb$Y;qOCr(9xZQb%O!aAh{qNSTOrcJ4dD8? zaReP&S9MGBbx?}NqtyV!7|p0@WR=)s>*M{iMAN-?3e~~^$?_SkWWFG}6lpkaKhc%s zDrxxVw;F9){*LW~GyO76&>)9S4f?P~*QOOU87fm#EW6u84b`u{@vzOWJIaP*M8R%{&@zZFMZQxShk5$4Zwn+V}DDI2&Mb~{0reL$5lu0y6(W=Ye4xWr? z;JKAIUm!WZtLHW63Vq{d(O9qw+nR=HYGK*cB+tIhkAKtM}-mx@;r z!mRP0fX{Rv2xhpN5gEA{3P6!S+mZ#V^#hz&-b{oj$Aj~L38R7ml`oXV&h5q z?HRENT1SwLF7SLbi8MtWTc2zL6|9^Ik9Sxb77PjAMZlQ59O?g=>+LXBM>c)!X7#=M zp^QCWnwXKHCDrfowozBtY4Yx;$F=!52RYAJwog`&Ob>n@DNta$;V5&z;;hZlyE(7=NvPjj*8R1i1{;Ve*jrun=3=9}g?us?pS9qp&fsKg^V@g#dYaQ1>p1P!(f2uSg1vG#)HYUJZ>RESr@fWPXyjm9 zk24bPs|9dF!Z4Hdng+=ATHI69q=o*2jqX0DA8#&n;rpXL6n*{f2_6Xd44lmLsH!(2 zE9l&J`(HDpFq-PO%eXlI!j*sbo_w^Rwm&cFWhnG4{sJ!hFM9Enxe+LchQ`N{zP)eG z!`}pZA@c)JBY(6vv4ed@6KuuCk6wxm=^(0{WmDLd%gl&2=^G8@>(cFt9iY}EpCCB` zeC?1oo|fmWL&4KO1bHR4uo?J1W{CoED(V5i<94?yLwqAdcHWNy%NvO&h}y;i7r@H4 zA3i1lJ;4Pks zif2id_sFr9{(v#Ri;z<_ZIeEaU4?W1)7j05Oi?}qtprl?pagC`6T?<@R9-xkQ_zyT zt;k9s1a)Y}6K=wlU~4CHnaaj9sE;Ih;Cn?O-UHT zgM{(E#0>IzMXI5}Pp#k6#kW%B0Su95ky6W^it@Qz9!s){ldzoVeelW;9fLS4H3Y@@ z+!nlR9xIbJ<6gsReNV1m%rTweE)ZwX(6O4)%*L9qoKojd4ci=|SXDol^Ggc}^SE}*_B~xkeOZA!NGAE_MU{HbG!rxbG@j)_LPlVw+jIv@HIAs z#Ctw`Dm3{9_f0xFuPzZ*yhaufOKx(iq_}~FHuG#Im*sGNCpdxW031#_md$zIoz?(5 z7{l%rTc|4g1(_E!*2=M8)e}=+B6Jcu)uJum-5|{BE-i4CDCt&jr03~M&Nf4IL0JC8 z>GbX|;JI0cT#WH!%EViKn!a|=5Ii;l#KujeZVT8qZ&pj3#*b`jm-Bae8B3F`xCPhx zUi1`V=K~GXXUt~D1a}c;-AhKMGVaAv-g<2kJwGTm6R~y?u~_+0c^TQ_-+zpQTT3A{ znrOR8b&9S#_c%|WKt*JRP@@xeY3?;=woeBCR-x;F1xb4RX7?jf9KiXcuA!HGj#Nml zPOc0|l9)NyZ{A#dY;6c?vW***vj4^w(5>?H>q_H?bhyPpl3I>9DDz&Rk?ow!ocsMY ztABlV@x1mL4D;zrDndlj5TlONS&4L;Bv??EPc)h|be>S6c{frMFD*G=Z@D$_GBz7! zd^Yy0K2dG$fsv92e#XgH=HE-D=zeS%W858~%zGEkUQSA^ljIlA!%L6I%dPOK6pr0( zm)8dZC3-rPzZ&0(!GsKUREra$UIAdI0S{K|CVOIMg2395?_QTCZ>vUF3^?($O!qNz zr4deVGy5&J+!iRNN?t&g$rlqeoOl0LDKDe~p9wY|k8*vS&u?o)_sC^oGJug}BX{%G|msDJ+4_C z#1k_uESkE1Z&`FIW}WuRD(@1JMxyCTl`Ag{9`5+^x^$Yk{*F_ttdZFE7cwv=06YuzmdE;*Vo_n-$`QHs?ZXn_-d>s$l zS+?LGPg9hXVI#57ALF{C0X?&j$sa9A)8M2Vok;2 z0E&z>ba)Ik>I_l@D~EU+`l?nH&L% zaE8Rx^sjO7?yVx$3cqDkm{EfL>sS zD30KRpcmn7&})xNz#8lryi}AUh?Y12udIKrvAHGmR!F^S1ba8Se(sGSlAi=K2(F(` z;q>n%hbXvU+?@Tp+9Rn=1e)RbX4TW#u6wWmrn$ic5kXOScV6o<0c%8yo)Nv_{ANHi zHJ*Tz>Sa`=S&* zMebk$4}LPv<@u~c*j{$64CnB+wmrPF@G0oa;vp?du69aCb|-9d{%R^pg1t^o?M}T` zmXY-hyFp|wTegULUa7yg>L9M|24dXNMUiA@yI)&9Rk@k9*iX!rj^n1?6z2i9_qPP; zm0lr0IF>BmHc(!G`I^t2IvOtBM$TZ6oF^&mTPIftnAOmcsE0K~YE&W?eu~^;O2A5! z%`MnSn{%N)O%gAphZQ4e?F>J)SPZF;c(_@kSN?RA!Jyf}_}_?u0f zk??EY;*JkLNk09;&NbMA{6gVMu*-4_EmQ$a)PPL_gU4i+C4hBxDUaCu3ExqDgI87--NR z@kz0}+Q)g`%Z}TWtLrGGxC{UNS0uvtDebHR$=dwiBnDF4yqcAM@SP4(n#If0;o_o$ z7r^p)S~55JCg9A7&)ZX*T*y1Qd&b{J&_%}`&&YQmG&|mprHk+>H){UKZ!hZF?J!fX zNXkGyH$A&{MLWvhKZS#8f%%P_?S6sDgJ3B&-VAZA$<$KaJ0~s+n&^#A7lPp);xRtL ziVDnr$=Jtwy0BO$(j-sa2^YvJOHJpswHGwzVRvFdpN*~S%(zYB_0JO+Ka!r!yEphe z?=uYleC>}o*6_S$;rE9T;q&iD9|vDAb~&=r-yG35Pm(Xfe_i?g5)S15)OhMIP)XJP zOIiI8lw0=y)iVMQ*~)+FnTwR6w!c}+$`i(iIT5B-P^G|^EJI)pCp30T2*jZtwD^Hf zly8bsCfKPUZxve;<;yzYuXkiED;S`$iSWU5-k~xhlq0>`q3K8+B^cVWX%42Kl?0$a zs_j;cVE=W3v4OU@PFLME2}V(iQRDKETuY4s8;1ObKo^iD1A46#zU5_B2WKm?XQ1Tk znC*wvqt})#0k0&7S`P9SRY<|nCWw!0quMR9^R8#Xf^UAjFwzlw_Qe&3b%rg7_g1xG zlnIW9+c*75z9Y~XNXmcLf;l$DlI!JvVTc@O5{S)E-vqnG#PLu%jbH~`LQYMmjbJg`0_0tt= z9<7la6Nv1wYBci=XHXY?x@imyZNA7QQW`zL(=pDkF95YEc-Dv z%B)d8S`iyYd;7pm?($*qOFHO2x*2Vx8?oQsB zh`So=yoSJJy{@AW63cf(qL^Ls|MI2iT#vtF2*L0BsBwRAfp2G3R78 zn>T;sd>o??qMPmA_Likua{;Ony8!lgI-B8!e7IL`1HH=?uh-Ca@^E!d?~*}6UhpmG%qG=cYC1Dw%On-BimfDx4o|0>BKH?W!<-#EFN7E`knN?pWA4P zcoxZHAouXbb3V-Z;@q8?4(4DJ`|aw_XyTgL z!128(=#(?-hxjfd+hiOX*P~e3>vgwB7VP8B(Qa3CybAkqamY`Jde|q!^Za?}yDhB4 zhhv4)6+Y&gPMEdV#RSh?r{2kGhX$tB3Ul_~uShC~x%o-ws68dW46yvSQ!JibPVsuS zSzK(YcY9kmLvO=8rhOEc?gk(}BK-X@Bk!K4mOG(XiwEofDxa3Px4&dwgBeBC&RYil zvDiGn(1H+u^4*+xIHW>*daq9LbtB>76)Bf%3wg`H$Z9u&2u&mfo^PZ7*pp7dH^Jk% zJi>i-M*z8izK7;9js&IJ!&}O&BdG8E)#wa4TX~i*mJB5Mvy*D`nEn^Ib%;p(^u4B3 zCip$*LNh3Qp&a{w01@xN0VN5*oYQtpJjy3P^2G*yV>h*FX)^9lqz8YO(ohnDa4?xo zGs=6i6!c(@5}?Rt$R(1rDD_5X`x#nI*hRyfa}pC|`D*d!@kWy{Q4x+SS{b5V%eH>S zcsjg4B^_lu=idGN@jGT=knP`;}4wDC%{9XlsC#wH8 z3sZ?#Y?9ECFo~flx8c5SpDPHzfpgI4nq0hm3OxFX znd+N{BE|p>H!EmrTBZUGT@134(#Rw>7zBw%u(~HN%g%^c6L5p!IQ{1 z6#PNU3$@1=En*wl_W%!-mJpNpZXyO+lcZv3Z0b#6RD3%?L$`=>qDCSKcE=duNz>`2 zRUV0t0i3Fs^fJfHqKS**0vbJyZhH_D*k*cpHxu<_1|0o2e+LhEtsXcQU?4=b2imaU_&2(kl{IB3)~Tcnq7B)(Wq?C>-@kCZXa@aP0NMN zl5d!?*^RcV(CA#Rnt|+kC9Be?^^T$~)GU;Oyb>Lt#CB}H9)~*MUp1*{FMIYYyDfOS zFwqlfV7I5eB2n(huSwU6=x+u0nUdQh0nx>sgU7wHX4r%5g6;8N$eYi~SLA5iVrskD zlzS$M0^841%x*=m8S|^MSMRcdTUbdBQhHgj*=xEBXWTayMR?L70(D7ZV2o#KFaL)0 z5+C(hHvvO)!&l40f_D}7sE=+$@d~5(l zIybT2$!3$fJ|*5=yu~HTFA|JSM#8P=?78_&7F$dlG`oBCr{_PRq z3xF+)JntmIx=y<^)*jBjJNx?fRWnyOcWKter)#DAwV6=zUq#y;%!UyUpFzWzW3diz z5HpXNkmfzexlLXqdMbOK0-m^d{YW9C569m$^$%K6dfFZ5Sf|cWE%FdTmaojC2VC}j z4`tC#MSE%ch=IJ8?4(coVZ5ATH@cXw+}WCd-HP38k2MB|t}At~yJDZqbDqRzquF(m zrE?@f=uQO%+f|S7D{B#RuQf>1! zdgULhq-YXILG3@T!C#R*v}^yB>COtJ1AlxR`rQ#gHgzLnRPYoordPg|Egb+*_vbeL zOZQB0fEmMpa5HwHC67~3y>#_EHu6K?o0M9BPoD_lnOu|g;_?A zo%>@hyJxC0GO9eUOi^+o{1B>YS_!Z()CDQjYK~d4h#(P_*i%&o!$$?44{)7EpqvS+ zE{MIV2SnQ9@Qn)Q!IWx72^XDk;)tb)v5g|wA?$iyM6NgoG_HXdZ9klc*fk@P6!Ceq zlgdHF!C>ZEd5;PcJGBNs!<@Fi0QRgw)P=0+(gKriRbkCy2X@H*$}O#~QI!5<8j+b> z6LZwA;GNo`i%X}$hlhsb7>iF8Jp6!&3=d2FK&Ipmun)K8Wl9o*@O+?mk3%G?WSDn2 zsHq0$LM{G8u3YA;B-uU(XDQC$)T^n6m4bL>Z*W>;f+)sV4M3lnoB($c79YFc#`HOR z0~;+gbpdYwOmRkQB%gEKXY^gFv&vT=z$RleC{g(Z@wZ`rrBro$sh~=l#KP^(ilg!Q zqY8O}Bh*;J7nUC!Yp6we#vn0M;_o%Y5#ZOAqVs*AAj?LK&uaehcl)=2mC_TbOpz*a z8jV|A{AkX2&zUN(OOp0af~>7OrHo+oB$j;^Pdz%F*=f3~6jU@67d|N2o4JClOWoEW z=0r?LTZkEc)T1_xHBzcuE-k#o`rc^7V7Zx_zf-9p8Q3?wq#IB%q+~^l@=JX_5H|P}=zfZ;z6kRgbr`Z9uzmLB+U%n&`Y|mPr2h@%aYdMs{^8QE( zD9nsM6|HtZqwS|7-35w`ef6@^BJ;Y-_Ar-$uh&~lT)^3_YOovNaRc8LnZfo}0r9c) z6Ywc=867M=`!$)!?*cCD*_n@-Z9RAE36g6(rM@q1X!K>K0_=pK-QG9H+O*9;HfLtI zQ-gILfy&BaDD_(vME$RP7~ca2%3^GCY}r;0SM>Vs;{}yk+On>Lw}qZ~u;1 z&s+0o^YvrN_Tb^z388|o7B6Z3IVbE+(iVdWjQNtD`*k$9MsE|kf7dk?hM~g|JG5%r zjp3NZinN^V>Rt|Q8r{87-wWOox!@8}(eJ*QbG{ggxg3L0+Uf26I-Bh{>vPF|^sWK2 zt=#mS|LwkK5AzV5`M!VuaCrE(g@Qu$&RqWSruO7T!)s5p>%YbPKcX930^(8Sv+RJP zN%4P&)7K4dxNM*_wRBaM36~rDmz{h|WE4g5fpGHv+$`3VmD5f{C z=0}96x!Irf-VzAPH55OHz*Z11X%6A6^r) zq9o6hy{GbQdAa;pHfFTIvPyyLGlttfFe$+;;N)qOCa@$4B^!`sc#e+rvwq%8EaVU^wHP3!qFCvZ z!~gXOFS-hixPoyK{-VRfPg8O8{aH^Psr;g*M?VoHB3LCzoZWJz*Xo$2S8vEmLU#S= z7Umdx_dLQF!6NPufA=v-Zt6|9^{b=t{q7`Qcdy|33KFKXgmM0HM*}!i6+Q=VtrPow zATRNWamY=~sUf*JRd|qNg0!hcIsfhMn)kj=@Owi|iFTZJ4@|*g{Y;0M?QlVD8o*K8 zrxL#))=gBlEB)y#ByntYtM21>5k@L(qotP@tc7z)m2UPJSd1kamjUlpzXJB*)>jV^ z^ValOClw%(qCqETLq(mQ+vXWU9*Q4k{VGTO#^CE4zE$M~CXRaT(ZeJ=lde1-Zs33g z%yc%Mrh@`LU)Hg0I3LG9gVR5H16`q^hVAtYQ=K<04g${~#!Js@Jo z(7R1Bns2fslZzkH_|C(qe*5Y&>eB8yitp=~)4NGNt9z?^g<<_kq43MiNd)BB9ze~4 zW*ZwZ{-1z(4vMH>L{ZU1_ji?6yh8~@-m6pYz8b?>vFlu0jNvFru&cBl<+b(~_h##t z``6Gbhk2Ub=pEiwVIC7sFWhmDcvxlsdR^q^&hYx$mH$&$&(MN_cG!Z~>M)l9M0opL z#8B?MG@@ne<`l2`9S*Ja{|=dnQm;d%L1M6_?LUy~M|xaC=Ltcd8;gapwuVO$8cpRC zLV8M7O?EFL!HBIOo0JEpWIPjqe$f1?jG53)FjR3$kvqw^vH_36EU5iS?m-FOl7)VN znG8;H8iU1TS``sL-a_pyqnu!z9!Sbj`qmWjoF0Qxt4bY@W$_ZKA7%($W7J`94N~30lR4QwOjKy&Y;&kTs%V9sVcCX z2oCH;H%kKJf{eWqP|QjRtdiNlv95x%n(w~jIJv(@%;lh^{Bk78pnG9KI535J!@1$h z(^Mu&i*st;B?%ig0C5l-5t1v;#0*orQ#0paB-&G@h@*s*1cyN5b~krXMoT6lxXto| zUto&ugXq#8*z6I}yi3p5Lt03E#}-#S!=02UyeyuXW-&aZ=v5%-kQDz==}re8`(2gH z+Q?oNm>lo8`#n)r>w~5P**XmwRC^MA*a6Rs#E6Q-kb)#tx(}?JSf8Wa69K*6^?dVq znt zSUS>RnYIi)(_fq#V`bc&>YN{Cj|eHb2N*5p^}NobJP51~i;|ji1Y81b>18FV(Z}Hn z;z*&v7)!u&y^#&5>Qv^-h*@;_)gMp&n@M*ZBrYokiHi+;DyFr4a2$1HG-axVYE!3! z?RKXSDz^Dd&L_sM2?RIm&!)0!06i@;B6P3#55yxBUUlYL!}o*ltR6U7v~JyaLcC4v zw%=kZgEPZ|uQbuO9Z$uBZMhwvcS4?RH0%rIdPdccO?Hgm z5dhY={V;vyAMb^+RUuoA97t^tm*#Y}t?QU;s&=x|Ftn%zM3N&`ROUh$3E$G%g!B^m zlOy43e5#w!DId((&ne+^u10m-511V&>Lr8yP3ylJmDjm*^<--|3c4EL@9cW-Bg}W- z+WE2;zUy<^qakdx>>gLB%{4_x*mAFqO9qDGw@-NJu`uh>9p21>Ldr|{Vy^A5jza?h0(!uF{ zb;%vGyfR0_Ki#4cDIptnxpsR7zUTU056?EcdanZB&_cJENI;Ts?sWEHy`!%G>qGS9 zmbD;|d&rsN+BxV)STrjM^<5iop;(aqEV3VYdw`KoelU7HHi8D z>1oQc|0#7xTUO)$@D3im(bzZ5<+~r^)GG#o^a#(j8##EF{`EC|`RgS1q1+8JeqvNk zvGg}}Ci?8~e`?X%z|l<+XgbT)zY+4v9D%l0Z%TfISHtOK-NuP3HQO3=m!=4u7ZFcH zL?RF{J)%h+BZk5$tjrL)k`&Cq7-Zsw@ZS`Ty9coc&J-bFG;+=*s+h&x|0LThCrB4x zgge`!hQpO7*Pz@jrvgdUelP{P!#U0nm8I;dLmjnD>H@v~i~tYf4bz#;bd36J{Cu4J zQtZ5Lco%&8)sLZb)G|3}`)R;DG(+nqUQuDZ<|K-^+DINFd=6Ptjv)oJ2%X*2iLU_e zS$etTjE$wYQ}Wz6NFi!nzWJ&@b`pNUmKd;1nK!WV@WLN=)Q;yw4e3A(Ud>rjJUU}Z z6wWfb0ijn?al9Rr!DpQ~@J-Rur8G>M7QSkqhtLiXPw($+Ln@_k_z^|r_iQlk!xaMg zx?#{LiQCTIIJ!5n|tP>J_O%)4I+0THFqI724u>ctbEzPw0 zIiXASc|1-_`^rK_Xc1o?x?04K$RXHVV^#kMTNF-Saq*c9rFzC$WpMK*sRU)Jps5nB zc+w1belrX!Gr5R5Z_-ZlH#SPlS+KGSBYdOJZ=znl8`1cHD0fpo30C-HFq_@m0JE+j zWLko>Rg6B9u9hsj0LHI+zKN>wk~0P5CU8-{DN1kUv?R=|kv1}-NQx2?8|`2-9!HVP~bE53L1j9*<1ZuQxgpTK)&O3H+z@gkV1 zBLeU5V(~{A>J<+w8yUZuiV^#;BBG2Ggx~&9f}~G2$JLL`@EU zOeFM8lUT2sM+tIT{xb1~yy!y@IYo68K{MF2{wp4OYmd0F&g05N;7Ee(5&X@y$UG4d zMdjTpmFK!|bAGXzWg8gL46he20Nk-i!>5aVb+A>R^_mr(eA9l{?gzbdcI0Jxc(9d~ z?TUXU4{upo_xgWSeT7@p|F*RvB1o5X4~y`_fq<~YTE|-YTNEhfas9PcUahgEU~t- zK^tIjJ4(ZnmUUMTydxiLdA%gqkk-JGJaBrBasRJ!eu^Yj`ttwZF=v1fCuQv8=6go~ zdEUOdC8H2wJPkO5Uob(QUk+0{x3)JAcPq~2PW~2>bt_YXfC;;0THqC;c^oIg8uXuz zsG)j%yFQ*t2(+nnJd+1>e)tBB7lyY%N3#(FF(x{Bf6R?#KnI ze!WTeyrmkT>fO=XH8d2G#a{7R@nm0qIaKnsxb?E1L^roX&p6=40uZ}u`Kn|{i4TLu znKkA3!F3?)#oW;d*VPH?**|FfF?HrkA=c`8>J9|w20gSs&$PF%`Ke@!y;BRyf|e&H z&MfKtw^cRM1i@4KYzJEFy714w?IpHm59pK*sL~&M{-78GQP+Xyr+m4nkfb!&`5C8+ z@Tg7ut}}EP<1dXm?~fm6hF3c{_HSlrb%F=(h0eWaTeZCq-XZ)!=wxIH0byA)*pwi= zPHJJqFEJB;B^UlJ_)qZk0=ur=;r5WDgU)x?_f(aXH);!h^Pg60cslIc=RKGG=GU}} z4rZEWi~WGptHz(CfBm_exJ$vj!@-hqz$u_Irk2P0sX}i40-XU~GTF!6;SyqjPRB>%8c3a52 zw)DOTM!XUbRQqUv#v&CTfbm+2)72Q17kw6u@u2^H!-l78b^w?4f}vhC5}z z8_lLeqv)pZ)zF^#c~UI}eA#mw?Tyr4JH+W4S4t)Skd*q~ifepqhorKs+XW|7Ha!d0 zL#HLmBaNE36a|wX-RqSQQKr~JZ|K*2hpstCLYF&}%(R%(nq;$=sWnS={|oC{5{?bV z&r7*_D6`3o8ZUTzE!*B-QAT{NpHFxniA6g$H@jYtI4KW@*{tKteEx{U>-pm?7SdCJ z*7I8mXQLs`w@gDa^x}kk%ZW5n*~-?*V>HX1Gzt+l!^%%EzDzG^1J`g??G_&c-sSp= zGiuVJD|bfgjK@h#(i)A$nxt@WxTm!rhck-o>O-Sd!U4~ zWslU1!gqL9{yTqgQoXdIH%=5s@U1ox5`?UaYMatPA zxVucMwn2u6Q-xXE94@=pHKqrAPD)0NBO!p&aZMzL$zqEuw<)EW9iXkA2LYsb#AmUj z@yvG%byBs=m0FrzhT?GOmFEV^`wzpmgdgAb(kw%%PRX}(0z;VV#?)~|^XnzLJw%`T zF+YNIXE5EsxyX1pSzc1DD7b$RFy`Cs8(MMG$gJ=8%pOX36+_;WJQF+V>JvMv_tdAD zb3@^~m%AU>EjWKoL-oaGCT!$9uJvR5pzR|fHPHPI&L$`l`Vv3LlZ)6e! z-I@I$K?JgI3F2};XwLj(g99(lr>Cc%k5V7JgU(km*C+yEH;IwnYrf8~bvmZ;M2dnI zaE!}+T^#FPB-!nv+9IDIk3-LC@s+{N^c7TSU?$-iMrK2CirB;w%J?Au@W8vPZ99N{ zGiJXzcUq#K)n*RmvRpn*r8GwfYA6@j9pM0_-dvERz7Fxdj1=v-*P|CE*|n%63V`9N z33IfZBxCbA&Z+JFNly$MnTMF z$^z?5L{>$SY+8}nc4LQ8y;6L0`9ykS!<83JusQ0p4UKuLqoJ6f)G-^QjYa^FdlQEe zCLXqD7+=wbB#14A5>`}tMd`+y^kkVviQz`869>&&uTVW(X-(=(ljvsiNb5)69@%kN zbTcx;V>fGb5$f2A^ybRyL_y3ex*aMP>H#i;25r!+OW~%zKE0fs`pLpSSEzQsj9BfJ zvQ`LtDy<73wpi~eK1Bdh91t(u(L|srf5L#F*j}kvYN}#CuF`m>-w#&C@uqm0J}@MD z(us0ts$*PEE94(hhH!KsE<5l!!EwGAWd~{7Nk?)%S&(?2aqt1Zb5GF$(tFD+IWW=H zLy9)u!&jD89d8?wpmRyL2Z!%X-84xNe|`6hx3CnSijLh$by020q6fJ+?Gc4UH9B28 z1bj8==MjH@SC~NvUEz2&MqkrlOl5o_YA0>v`O}el8gGoJwRN5k>Z%E6{GyA>XF_Wb zNZZ)cd9#87*tUElWqma9sAVaC2BmjB?3 zNKOY*FU!VUQB^kRE~tbPZ-J0jUj~?Wqukq@V}J6H>Qx2~jh- zDDoYWYKc5Hgi+2lKUPFB+^cr9@}28m|FR0_N(QJpBG%*L#hEUUz2>cFA=aSFKl^k} zN1L}0cT9P&p16&Tou4Q0^>u*1vH$#!&uee<0*teBOzO-Lu#1GnW|0EOFUV`iqZ-0t z4Ys{m39)JV@TmOH&&S^Z>%=hpw?hfkzwrW}YR47BO2pRGZ>h34raOCRQuDvOlcFLK>e2AYoj=z=Nd z8PDKOLgQhS+l!*K&{-x&Tm&jp*vpLiH7F^Aefqw)-^Ph?b1zfvfK?n(&i`4h=CRMT z`WES2e=OY$?)(B;|MU3xt{+`lGBSV5vFj%tvFCMYsz5k>N;&ZbdB=S*yA9cFD4Pe+zI<7pMM$}S zTB6s0`1c2KKs^jtoo(7<7rxbU8}Sa49Ic2x&plA^$n=jZPh063SRv?m{XJ5mFESx~ z)$5anQqAb`p*dEUnylO}RcL)s3RAYh%z#^^VHu&J)V6_c= z5f=8>_zxdEEDn6Td-z@C4P|ENJqzcAg(CGZadTU znHKd1rw6|PXM5&7!gy^^QCCuHA1PT}arFqZIMXeMhbxQd9F6K=-6FE5cYb96e!}3aCLb*GoF|pW{BKEt7b>sEScE!L+HHnNa-Vy{{ zw6HpTk^pvcyT2=E<$HIezmmGYb0hvO!4@lZ#>!6Lw~`^PVU(ifEce7_2WA)L!W<+k zmezVr%4Ovc(Lr;eVf8$e5!mHehFqj}jobl3ep7R4^>Ju9psz4`OJX>lp<@q!hF&x+ zvbz`X7iz zrt;LgkIx;QPh3n%#twKaEUDi;sgk;y1)t6-Ur9vx#y}&6)SV_l$B&tw*LsG32Q%K>x}6A9TM+q8`nvU^{|*CsaXa8MTV<-je*4aCXq!TTSm5@kV% z6R02u0UtS~?>e40>KP1}FE&U4J8 z;(p7@Om(pA;qB+_OXGT-oEttNnO3!W{9@Zeq~GPxN__&VCR7J+H%={Otrz~5+Pe<3qKsA@#Cq1_ma8qjARrCMg*T_Df;OWjxldDdvFuQ1X^MK*if+8gJG2Wwa2V) z|J&`Y1*M{(mZ$xPIB?WU0oarfygr}-v1vbOiO7n$M>#*x(QNfQq*6TN`Q>U;SmW;X#rh&$d?HxVa0hy1ipFw)|0ceGK&e6pry)f?KeoZweG>TUfJiKX4X?_>{zg-6+t46=dPkoVZ!+Zpqq2jb?v{~A9Ah#B4(`w5$Js+ z&j+>jy*{7MeeiyN-X5YHDQ|d!DJO>oO=6x>$fIao$o$-$D=o2rMv=wAvZMSZnnFjx zL9bYJ(ZE77cn4AwVyvOT>HbEu;8=Ro^;@#tdso&)JZ5fL8EVf03fFS%p_Px))8qFv z2?bmzG-{7Oe^E>QQZ!Gg2X<@wr^|50iP}#AoIU1#SQyzYM6(RkF7iAj^$|+7<1>QdzF=GCGGD@edV%lMs|wyCR{JF`_93g@`m@jQJ)FGAiUR zJ0H&hgI?RtZ7qyEzf&!!pVGP)$!q;yH>R*(|6s*2>5A|$^IHrr80f(pmdWypL_C>X zI+^v|WDY`+iVvD(=}%$FFs%oIaJMxj zhvh(zjLFiZnlObqx&*V=V#nI6ljc2kWp>~_8gg}G1bm_uMupj4f#u|vtO#Y{?)(fd zWOvkLiZ@lqM%gzZig5D4PC5@4A~aXNL+$CgB*K4SshQj9g@ zwKDD3Q}^AMk_9%Qpa0thkilMeJQ&TC)_)`AvqrLKwHTnxHQCENt10G6Ejp`Q(c1&@ zFE>A&9+!#tXc2JiVy^&umkCHE&TuIT2)wd|r5meiyXwTIk!!8&^d4KR-cg^!?9JT~ zlAu}UX}fvRihq-N0;ccy7Z1ALjJsI=N-G`3tYEHDdFXn=-q{*_+kn?uJP_t>D39PO zxB3zIL z?qK@AAGRne;$C9nLJ3@~@h&wn@NTvth`klwLxFi3barxfE+=Lxd4b#7UT?(f9CNn`p_?>>Tu(o*nw@ovi071py_BjoRa>j zT;M~$=+ahgJ%+GL0>0bmd)#cD2q96*@r;)w(3udgZ{@{uyz3iZq7&!vIOoQdE$=S$ zdb^uUX;Tk*bs`EM3kOyK%rYuyGW zrw#k8K>+aGV`?v4C~XHsb>v+4c>iD2eu1zcM8R)Qca=THA^*&cFsWy?^PcBQ)Nru_ z_%{gJD<>wyrzsXf9zgg){c3F~ZGL?PdFLPM-_*&1p^v%_RG+C#xeMiEGEbX|35K4Ccch!ClSFm!T7(sZF3y+>oEq2&@%(*hIszttP=3e5R89 zHM?({4*XswAZ-#SL+B#q9)E)q#w(Y_Ted%YvVUH_+O)lhs-UM-jAE+X^38o3T(n+CFDgc z3fudeH8T*?p#4Sd7E)9h^(kY$0!3)4WrW4|8H*za77C=_xhrcGwL-BJVn=ZVs`*$b zDnw5Ctow205d6Uc2BsA*i{ zmTpN;T+RbYNVe?GddTFZ`*%+camClZCy37A31=@#Dq`T7i*`-zK;!-zi6wx6J7w`|KI zoMOqMt}*pp0Y^Fdv!bLT)>kji!jYtAhHts=bv~#w#9C7332ve39P}$Xv0g`Zpj^?7 zrZk2KH}umaG|B_&tv^N2nb4udU1)-aFUjGKa!X&*KYp{*OUM1S?O;#ih?ABQUybwz7;f-*4yiBEzi*@do4^l`B%`l zLiORLi3v8dND~s&Mg_C0yq0>KQuopTRd$VA)X4V!x+m9Sf+^cG-Ym!EUq4hlszes( zxb7mtWNtJyJjUrQP5H1r6It`eS4!PP{DiR>gob)iztw$kaNOQdLb49bkWyiBKj04U z9~dItG;67Xy4Ixm7Kfg*6rJ*r9rp{1^miW;oys?OXgx-F`STJliX_lnEBUJJ)10g{ zkGMmH(B6n4IW#!8b(dViX>nWjrdJetdH+m{gX+TqH>qOGwk?Pu0fo1sj@hRoYqy(* z13#itUStfspV-jCOY`O0HbGZq-{JFS5ei{QkZE(nBkhS;0w-MU9~vV1264|1Q&p$v zc}j?MKDcxb+Hz^lgbU{vsLR5& zIV)LOfC4whXP&I4-~rc=m*&sNICFWe(sg@fiO#BqT+Bq1HbLQsQLY~Ej)&EaJ8RHL z7F0E3y6#;2-oS#VNciC(PGv9E({aRei`P2HF}Hr!FBRIbg|Gut=nx&|aBSftJ0B-9 z_fI4n6ZBmRK8E~5!(a&iniAPQS>F8eK>YWPuQQY2bztjr;qsq{P?Mfu**8ND{3xS@ zGBfgMO=A_c&qm8Fa>7GZ_+E$#&fwDYAIr>o>hJBdFGp5ua`ES!Sjtz|gB{&hB?CZ? z)9C@D?@!-Z)AwA>IV^~Ee}Db4+p1|h5jz~2*vN~O_Y)dYlmou-x541>?=@P&!xwsC z!hjDJYwRmqk4s#`oR&H5On$W+#6%RVyFFUytb``QsR2k`0ad#FjT`UpSe}Hmd6ip@ zfie|W{YzV zd+TU3lrOew9p>aAP5P3BDxJMGcGAf|n4aWQqBwCN4{xPa(-Vi@DN9bAO~uL9?Fcj~ zG9-(ZYEqSN{~3j-Y5#fgsl}9PgS3s5>=aHKL&PkKOIea>oYRhvQr~xMM=PhH{d_B` zm=;B#GeTRvXJ>XOvxJk*@GU!&6~~%tQkJ^%N(PhqPbjDiz=!!5%wj8oBQ80wLIl+1 zuns}O52t{rs}y|xE*%!@>mr}SP3BhIKxV)n15}+V**TSd#iMP2a`#1c9H(7o#!eg% zsG;A=NTcPfPQwIs!8O5mpb=OmV{WU%kV?rCMUp*vE!&p1^Zt3}O>?pJ!G|V9+~O;B zf@}QbvYCw%y6n#+`Pg(u8|4y-+k+SiG5*m4BDBOqaW~X1VVd50U9l-Lt=dn#!PGY; zD+ZjHZVco#eD{>NM9abu^!cyklH#~U*o!!a8FCIR5zQ)-BM;d>s5D>?aX7n%XxJ(2 z^<(;SuDtIb`!K?}ev0EjYW8tP+z52fITAUhw_ob09$NdbPughZSKooAuq{(&&X%0W z7Vm#plXI>y?SfXZV7x(xksZEBjeox8uk}eoEy8|3^utEOnNqzkNFy8gO@_q>iMow?%TYcH+p}9uh0?v;Vd7Hz8mzpA zt*AsM#phP#x&^kN%(K3}HOh*{Rt>&rlhTXE$m8+tvR}^l^X?6#4`)SiE5$hTYxlB| zaLKs;^CU)XMILf}TW=gJJ6KA8WQPOOU`?#T#eFk@MY>f#gy?v63!r)eAvqz1jM-fg zwG@!L6b!x&0F$>Q8;X?SLsf+@0<3`x35MTT`*+QCef-+p6Tht}NaO6RrBd(j-elU4 z3vBKU@b7&FG)Wv(R3x27gaS`@2i2cEE}%uRZDM2a3=p`FT{iR_5A`owKg^A zVV9obx#@N-$lB-lp+lhc>He^12*^cu%UNiB;p(Mj=3SmWAq&~zPY|uXw;p)!e{@NN zd9>#Tebjap@(uzQ=vcR|CurZ?Fa>5db^FOY{)Us7o*2p`W}SZvFuAwy7gX)UI9FbJ z%&^G)p*#@!h-mTHcS;*XU_scmKz+Nlu*mT$;5Zjz9eE^pv+2%;A$AMYiLj=e06h-t zTt3v^drc*7Q9l?0A-kpaOvCOy6!09-`Q!Jsp~_)y^JoUY zoMj>=ed=lzCyaPMxQ{N)<&~B+trU&ZO+d(95FkS1e0(#iE4yN>7BUk*#*@?ttmy4p zeHiF@6UP);h9wN7#zok12{N2~_pxTRN=uNbo%YZwuOk7&Uc0j;hHRgZY7nbN{uc}x z0aCssGNP)X#py}G88EE)9)%2@++7=2l}cu=EX<@_ErMtJjumZ!{fL6JN`xvEMK>aw zWjeX$7xQ%S@|d}}fGN`#?Q)QV+7R@BeL3_Kb>$m*uQ>HGGqHp~V!1(#=Qn3HXoQ&n zg<+eJ*T`^=!Q9$=GGjhOyx*wm^`3n~FaI26Y=NoDx2u=ocThT*yLbj(O43hx{lNF{ z4wTGhXRE1(WO3pNsfKtg!;xpS-@eYGP1Y|rvDVltHux+mE-7t8!P?)rEJBHv8g`xCF5^tgu%l{{`)GfKcsi8Wvol9GFsS zjE$zSohcKp!1AcQt_ISk3XGCb4oNLq_KsYBA)zh5E@LDfpHcEJlkFTaSOEZvoS4cRBg*$D95Iq0HmDnpK;3PfIYb~Jv zb@>m|NE>(?(V~f%4AWGF-0ZtXsr^*UD_e#froqJ@+~B6GCg~ReH1hCTnPMsi<68`+%n4ITa#()*Lt?6NG$<6~&#dEXWgUQeb;WCe*huxBn z0xzb^Pidu$HGlPfbV+%|Q`*1p9mVFiHn6arrCZES_3n4l9ceT`9N4(dF=QfKcybO1 zP$am{$NxzaM7>zQu8M9zr|;PJnyh!Jw%xJPeaXTrbiK@TFLa2zqn2p2u{cEwKE!)HPeiDAxFu7E+8FX4M^ONi7DH zJwNIXHjECK_3+cD=eD57*o+=Z;mzWWI>9-R$U%=;L-8cuDUHwjFLK-e@Dc0aSMYQ40WUZ;)A;jc1LW@fYK#v;8aPMfYsweZG%C{ya+%N1eI`wMhpp6Gy5Xl({ z)V~}ih2KY*cg$U_CbR*qRRG~v7t;BRKhI;rP4$2HryzofG$JcH zM|)J?q2<9pze47_Z`X_WYG!dTuBQob*1W&H#RTjpMg2E_>)(R@5v3t&Mn5|nBHo}= zR4|6o1q(A!TeOMNs9>8^h$1f*zokR8GPTzSx2E!^F{3vD?kGQY-PKf-%tYl=ZSCzb z$VTN_`{|bw0V=phZH|&B7R0|c6Q|*E{P7|G>-6nh@=ZVER}jXs<}mHuaKN}8{n*Yd z!ZNyGpJyX|-F38P|*B?QhM%^bqJw7t`r=N!h zdu~nK6IxGNX_2*VY#|mil|GdjAfYv42Sp;^Fj@?SSVsflOPo%I8ue(iydF9=FoHIo zgMi72_G_mwBIXluHo%>mnTmR!meM_57+o>LoqNya=Xpug=jgn>e08*~G(>ZGMvw0r z31u-m`YD66SHn0YBcR7gweE=rJDRkS$1_bQQrFfO8_lN5Q*+u#a~)~4rbX_#2OiIk zo4NZ=Y`mprkZ0x}9!GbSBGSVlyYB)<(jf^$m;iC_=Zk8xl(m}`?UPi$?d@FOsd9LW^bfHTLX zR#g$rFqsLJgVw&>uwN6Tn2q+Y#(WApaWJxe!02uvpm;skQoT3YArwOE?PJEk_h zN-ILkQ7!m$V_-Wgv>)J=M$#AkZPbB@oUGGfwC8@Zi7TYps{6HLcm0G1-wH3Y0@G1N zr-oQxCh78!kE2i|0MaCcq?+qdOu(vA)L&js{6Xwu<|8;-35utIla;cy_*Xg24$~s9 zUI}f4ZP8ii(x~j)QjIKM3PXpN`j6Zp(BEC2InyPf2%F^`$1#sN;Dw}dYQI-bG+Ut@ z1-${kubefo^yl68z?ev(6y}-Nohv14RVXbfE<}r{2lSqOZQrfT5PgZkiKPo^2bZyu z9!M*CnSwQ*;W?#yEQyxh-eK;$LDAu!9>XwPXm*D33jb9fA z^`*>2tm=U%{b~rA1g|i-y#uf@+v6RRijx~xgN3>l;53$)H8t?U6YYtsn^NozW(%=~bW7gZaR&*X_+6(eQ+CctPRwZo|(2Pxl0={nyh2^ysDu zA2S?4?S*1SuFxRzl5 zsM54yZgOa`W2rH5@>T*tk8!f<7}s#3nob`!Wy2b{H~y^ZtLS7TGs81cb-+ z=V7b5r)aT9He~EL0%C@%)b*Lhq}s80oLwPpv)Vp^jq^-?+TYui=N!0a=;u5UN+)3q z5f*&y01%|V?^lvAtt7x%o8}v%0*%0L4mq5G^%yQAVurw%#0xTm6KM+tQSPU*D1C*n-~gqL02 z1twAC@w#S+?KtxXWZCE)5pvqDW;|x`KI!PDlLnmWMsGZ1s`Q=QB@yoAaTKtucQ~Ks z@;#})Wpnw_M7nUOl8JSXqaanlW?mJML!G8aJ&}!u0@1Y5h2X6j!oweqXHsp26ZtJQ z#n8Q7w=E2#ct*0h#?#e4pGswufF9$Z?MO0t`6Mm)3v?d+gAgN`1!^B$&sa=3@}{`sR>Z4WRxADv|O4huuuNu{!jo-Cs2A* zgW~)`U?l6TpjyO^dvrPy!_jRJjoDMRpZzo0F!nQ!fc^cRj8u)V)1o8EXo+(w)_kkf zr%N;#^L$gc9!=6T$0pUc=kr28TeyMaP`a`K`FwPieLLMc-!KmTy>vJgbag zq!z=z=R!@>Gw*fa(Lp)ulxvf|4$z@Yw`EnE3}2IaYjKA@s;`<} z(}l!?JhZ*>+otsH%8kl#u1f_op$x zi^c!U`(2WMW2l#Drq_b$qvLrfjSRvCsU9juADA`8{dDq08kHg&3klLzdTg?hJ!3ij zM3r-a!P5q=#!W5hSVS98wrLIu;wcjt4-K%1g!lBh{Ppf_@e@OAlK!UBD@rT$2amcn zNJO+?DPh}ZO^1^5xD*DW-;3^|7Az} zxI?*FHMi*ZKN9_!9;G;>S=YJYdAMAt;dxW&w5`Qw>zy;2bNkJ`%VitpG(q{EuKQp7 zfaM{6ZR71Eq6dZnH=Yk(*7y$wKy&edq_yRaJHH;+?hHso0+@^AJO4`}91>)$%u7qFO>3Glf97%An)fiSqrH~O6+ zNxN#4i5n_nDLb4M@aF%HXGn;{_xF|zwruAAY}VS>kPvr<2{HMj+WU{+RgnL zY4F;Pb;Bh4zmZM`^lC0g!zLN`UVL;(9_7{+4-c{q%LIk zj=wkWo>i+&=r3VGba(uTj#P$_z>DLR#^EX1OXzLrxjM+hnN{O)g`gn z$9}%)Gmf%Gx~T$Te8>zj$N{wweWTKU_~%hpda1BQSQK6Paz0-GcHEOXt1kl+#gtE4 zFq5UXveSZk;z3evPAQM{%WV*<&(wGMk-tB1dH&q6`1P9Oqr_Ep1vk=H?Z0<>%=EwV z^Es{ZPv(9vufNewu93&)I_J!bzVPqu_%u_sSHE5n^&!#WjcUwHN7lx`^U6DCdDTM^ zPkZ20hNE1paM)l9_gk1So4D=Cq9`euHP)`EAI^*@CSIe*mg%{&;(I#bMq!b#*!ZSU zme&=G+V2v@s^XXB%jC>k-~m*>gB7RGxZ>t3cEL%;3N(khjm;pe^GTBn<0^GDc?#-noDs!*>%0U}}0#`yLJe@|hSWE1{4 zM}eVI|8q6rJ{nY@|2vJ~6(Q5!eB#2HwvFr2rjq9pU`ZK*yPd1F;a>x%6ja_v|!Jfyo@ zfH}4+|8%ez)LBoxI`$vhI4mNiy*LLZM!F|#FW>|PHSv)eE>a}udIrAob-H_5WDoe` zg@``S;GasL9{Xi?1w?GTC{#w6;NLtc&6jO^Epy%(VC^-vLEbjc(^2N@aYc`-v0jp8 z#K6F?5GMF@&Z671+Pe1$bMxUpQ-<}oSMVEBjeE>mra6=QbD`6twwwOL(Cs^*kaxuF zzEu5A4QR(Zb-;)N!_%^{qxz^@7{g{@oSXbqQjI48mz0V9$rNqwo@2l>fsM3CfZUCF zLw+#uG51h8q7ZWwwx|#YRko`Iac7v*zCZ9fH5e!v1m3GO!b`W_D7XR55vBVpjr@kBj;oM`lYjKAN#BXdQsH2XgTR=Yp)%%80hofG5D|I#@s>~*;( zPwk(OxmUl`#ifEF$4gp>DMLPSrcNrW6|})jPD)!@P^xLmMUL-Zh9*ihIL$34JJnq! zze+aG9GJ*+%STmR7Q~Rp2?Dr178yhVnof6`vM-K-LU+{dGC?Z?lV}bw)Y!aWF}`$$ zq^r^pOfqj9H>5p|!=2}yFj_A;$%1Sops+pCOH@EVz{uzD=*;5X_CVoS( z@j%$bebzfDMFep3B>oL>am!wa44UKm^Jqni>pd#EB~y&f9EO5C%J z#)<(!c1-{*Rc|R2*rvmLmEw9g)sh=Bt~tLs*=Pe(Bg2fBDyrq^c$(D}=45ETlykjL zc4O`nPQ|u+7doiq`-kc3@1vQsBc2s8Qf#hT0F^@%ls93^E~lU_Osky^{2}AzWMUeR zB-YBPT<%QiKI7M7v}t54)r%+W4@na^i-M1i5W(f}=B!?SX6Hd^kCZQbn9G|;-CB~X zUiM#sVBI{O5tW}8D_f^^xI!y8EBC-N<3oz$s5)=gE{3NQEoqC^t1p-E=y%-u!`MfpCy>Qh3vK1WhTLOiN^F+;us~l+Op(ox# zAX``YhY}qg!Dt%GS6`NYpML5o7u&MB4jPsbUQ*VsFzKc$T^w-B%5TvZHvCBefTb8w z#+`EAOb#?eEPFd!dctP&nFIuTju&n--dVgu8TTCbYVhBN`mq^Q3892QA?1sXYN9zA zB1ryDxh~sn$LjD_rwyDf)wwghx*!*Nv>sS~iEv>$tD}=L^dU>PLv(rhc|Q6tP*Z==RdqXMk&FL^p5AIqf;!AxS-Xj$syrQqw4 z0&_FLyXk82e*7|hZ^I2(nBFLl_77C8!hjajERRFPPbbH*6fJI^uzMX4xpCl0(}rc# zrE|bmj&hn%nZn#~cNWMtHScgY6ZL7YvW!>O`6+X{j{BZxe#+>k^!y;-wc_?mUEtYz zmnNUnO5^m@&FMdY@iHalB46R}nT&ru{eAKu{A6Q5AVfT2?|Finl0MB_kxqPZTSWfZ z0SK0jToNStr7VS*kwjJsIxKTgkkbALNRZYX8`r@|Gm4|qD}F`Am5SK4kfa5|;U;th zBuo7<;Q8w`f zw_9qn#}S1Oi+02TYTxt$Ybo#iSg)a?eIXM&^RcU)#4-oZ zFPB><@({-sYnRGy$eW1@CAqejfz~MX`W{DNcussv5vwBf?FFruA4!-b?sFd%OS#Y-Du1qe46%d3j_ag7=zc`0ynQ#2B3J?cw_R22J=m<%dH*%K6^`*KJ$(ka<6fIre$wED;!36iN^e zxBYHhcrPkgT(HB=2(FvFs7#T;?ACC*GTUo-S$X=91u{@bMrVV%Gw`bNdG z<&#fSD3m`k@J&PsL={sx0(m5DOgN*+{ne&mGugs%afr*`nqi|V7f#|-*Ovid%F9J; z>X1_7rJ6Ea#i95eUd;+kq|?bUmj(wY$k*8iOr&B2)~4@)3wcLQN763}-rR3&xEv3g zJ1hov0_e2E$tF*+vWn4Ky$462uiLCz*=liCZzN#3!qC6!l?43~9Ym*&L%!$LqG$bm z40+a;5v&KPyvG@5$y%=QkSU|5-R!&f(?PEFx{r|FYMWKh|5+7_%dKnDhzD_R>6VMZ zhRPG4TfEl-pa-`mL5{F417~#5O0x{b@TAt`xGioEsaT`?TrRjcfCmopt7tUyA0L1? z?B7O1E##X8Ndw69V?TBXJQ}62stY7gMY)WBXEFDaOao0Oq@K$Q4Pl#DnBR(8wr-uP zZd;3;eCO|AIvaKdxiXst-uxc+lJ2dn*+^=K8<;%HYUcz&!!skS8{6G>6gL}NG_}jP zc0Uz822zQ6|F%=r6WrllT;qH8TJ2^Xu;01ji+dWYgM2ny-n@j9tUUYEgGm(OE&m;? zoc^VI?NmG)-~X@fg+Se@cw`bO{R}6hc#`E}G$ee>{;~%xqg{c`iElLYMp;D@vJ^-) zX0ET8Yc&`M*n3RoZpMU>ZS&8?5SrE#YW=kyW#4QxzsRV)ww))T;WZq zXZAy$e|zyQcI!w9608aKQ>Bdi02e3IBPDmrlVk47?E-64s9_4g8-JHna`||P)-MgU zD>)rap!EC2F~H@MOT>w06uyFVujFnL!Kgo)+#UnUj&>l<*NQYl=9`EfCL!d!NSWLU zU0_#9d|O+a>6k#I+|XIbh) z>0k1Av|Y8`AG%FA6Y=)O2~4q3V7NQbb~L5zDrTC#*J4V&fLAHmPb-q2Jl_>6 zGJh%>4YFMS>7^T6d0`L)1Y4xGt$fd zJ=SVOe_cb2c5+aE$1t69HuW@SL^_`jb15N2Z+r|&vQfvTyp91)wl%uotcXheH9?f; zXMFP|m5iFHIYO!8GYzg{60_58&IR@SslbkkNPg%kqNiL6a!6uU?Q%$}t3NN5&=8*Q z>`jS&BX7LA=ZxOAJJA${2s)k;NuG{jcz2z1%X2kdHmm{$=j3IF0C7qMGh;>6|iVYYHqsVb{OD zz0x7U z@BBzmnMU=SUDAI7qJYzc>pr52)_pl{+x^ENd_VKTg)iSJItH)$5*~ulTRHSGY;yMl zVNog@cH$`+X3p%#(*1ECkW<9Y)0)f9{p<##K^;Yn7YR&DZZwV1I_5=hXbI~ElEYEHbcl;M!iL?gLm%C zq0gEyAi(r_`rk>ge@Rnn(XRq_JZc3V-ZVG`Tv;xV&dKf50KdH8 z9}6AE@~LkD-et~l`hrAk;5bK20A)ahIajm%J?r3=MH zirshV-EOQDyPMtUBhYny>K^H7=(rwrxjvYERJGqydMCZOfi(H_RP!9boj^Ds4HIBZ z3__)VAJtwvvzjBm8*P+LAjyj!Szp{HIl-`6qj@mjejMq2CRq`~u_`$Ew-)!W{NGEm zWQzJXk@Hc37oNKxR>u;@F9; zWJwSUqI(I*37w*laB;hU`O`qkmeRu`?N! z=cUK=1c#(sQ)N*_hmcvk#b%`y1|6FN7()j{p^f&`OYsFU?@s~h+=ULSURZjA>9{QO zdaFD*PsVink^3$=ic?<)`wJs`-D*iuSFzZ(+F|1nPv*0c&u*v0jc`bEsU(Lti zAq475>UNT##yBAZqmfcmOOeRZT>*!gr1` z=R-FrYr6`aVdwW}JW()RvBt2OPuOnq(MRd9C%-AbGpN&R?uYJI9J>iRkk0DZL1qnMB@ zTf7VQB7e*Z{;9gnX<39DzrLp6^5D?CWXRtq7qW_?rJADXfA~ghxeSE5at`u|dp%z7 zm_-xnytD65(7>H`*pbV6^8~nUz+HI$k4pY8>O^J>%o@0? z$H2Lb$KU0$N14%!^K|VgFpy%QLDkxCzj_X9|HjwRZ7qf4r<}T_Bo%~YfaIp>K(3YL zjoLt*mvaJ2Ymv9In4O%nNhF^RkJm_nJhgSJnn{Q0qXUJboL+}{lv1{`u)FZc_wK+M zklsnkcET6?`%m6hZhd#tYN9-iOON3M#=-p0bN`R4ul$R$?b;PYLQ)W=JEXgY?gjy+ zJEglz>7hHMrE3rnhDMlS=%Ks2yLcz)wj=^;}{SiyX`DwaU=aK5>|gNla(oB1#q^Xh7qr~tIn{o3)}^63y#pL z|7-5P>^-lL`h7<7|6|GhpSiSx9{LLTM+uGX!#DO3vAhJz>l18HBNPd5O;NP!4d~^{ zay|Y=5=jnY{766hyBczP5I-*Z2sL^%ca|CP+B;1Syi3|R_DDJC!4$PlBxx7^A0m#y zK;VI$nw?NIE0<=hqGpY$h_|)IDkAQiV9Z;Suk!6y8}43Cp*_E zn->u21*)HL1#r`FJz&l+=yUp0VW(xV$QT_16O8O!|64Btc8nZu7VcrHLBV(yeuCiu zp|U4BhF%FI*!Matc=lbz2T(UbeeCI53U-2BOWaDsc$KctV>Yl4=Q;>j2~8(20uNlO zB@VlU4%Sh$^mX|!PR3(D!s;@TFh3PA^NlUu>AjwwIySeoL1%x<;iy^O_=Ps47@4(z z-Q5`cb(#uzp%$BL6Q7**r;37}AU*A;3;EdcjUV^-B4Ow3K6F1tm*HFU3`NtgdgC)6 zy50#_5%0foYFgDzB*sX#Xd4`1v7jDou*})A;!lC$-;RlV`CMQCKhbo!K%m}73*1#6 zDP%?CN^$;ME$6J-$hw9r{vatjmk?kX?6%?b{gn(P(ea-CgLi}pyQ)AFWs2;Fm+kY7 z09p8V&$+BL+{KSFV*R;cVX1r6KlTL1G=J&+#N#=fV~WhV5>r;UEcVmR)2vXVp)-f`-D6w={=C7!;XLtYp>^>WAdTSmo9Dw;4DMD}8`aen4_2+g@ZhQ{16dpS zXUt=ifuxC4jgYF>%hPg&SoD9=hG6mlXqU|qO)$f;CFV`4Uj6Atn>4|756<>}()jA? zBMQTIz3p^Z-{|OX&)?9$@TL+G(PZ7Wk4j1|W3hr^+CUZ5UUP=I1b81oyQ&|rKa&5E zQ0;nxq|wDVg`>6;SN3qWy(-n;?N}<{uzE#cSNC*tT|iapZuNqwz+>HXwb3!u8)xtT zB?hdFQ;Fp=IzJ5ux;#%AJ)Q((cRX!nR%2Ip+`>+t?vJspE;@EAdZEkGxZ4;i8Se*Z zbnkg!-?tyyUGz1!e;#wz@H2rA%XZ;YPax+7Nzq;HS&^ogdlFYx{#xjh_fR2k4|?p& z7DEc*znxv0>HAAe|5%*snMT{ge=!zKOhOHq9X&0t7_%L7EgHUgB@ljbtSWptanfJM zhOz9wTC_Ur80g#R;uf>4F&Q_$TasI!>k*y6(SMWedoh+Tf9KNk?yf{Bt({bB->Snt z%VTkEZ+T5$sZ<(t3cK%+Ul2tudm_F;ll1&YQ~jT@6z~yoePqM))-CnJ#_)U2#5 zp7aVWvIj{U(1{p9I- zkq)3l>{7^*cuyG^%3obHGs^5i`4|xy)MYW~NJ%oxv(O7&HL9z?55v)F=wkzzzZVOC^)-Yf&GGK zQ*HP42F&gaNGY$ErlW!(CUFLmaLWB_>vRtNo`_Z)fvqnHw z=%U=AKJ?B=;n$(L$I7`Ja|AO*OO4lyMO@@hg_VXVMv#q&5<)a5L4opaFjsy&{PH{gd7S7e^knRu z4MX&Lj0pm6KOI^VIHY3+3m6)DFFG*T?_bdt9Ub?(Xg~Rbu(Ez)*UH zFmVEC8dy;;6O^Vq2q|!5J0*ftT_n@~5a{STukiM=1Vng2I7%zE1!@)*<`g1A%6sc+ zT96uL^2?Y};2j_g>>u)mOSTK2K`;WX_X>mG-v5+r{-m+S@D_mM<{3-2*{9L*DVz%}HnVph zUXRlXahxi`7AUwjs_lqWy0qH3_biGyma0_neu!2H&s@=r56PzaeNwv+cVMc>@IDk6 zPd)VHU*k!0Gh6I-#Hbr8D_Mr2J!~*M?U@p0#+n|txj#K`Cno?uq^La=D}ScTwg8TP z^{?EnwE9@uI0VS}n|!p0-TG zmp9qW+x_nTw27NdLzy4EU?r;0uTvy+bDyJdiL>mPM^IN))?|U3=w2k!{xK~XBBa^B zN@jN9xkTX?A7?K3#1l|K7XX;LRe&_cB>o^Y=u5SIx(a{WF!<>+~9{w+IDvdz@>;K2ot!ozUkbQCyvWtN%fGn4 zkdGzKG9TPwc+BXaCBUt5@y)2&`-#7LmG(p@V0E%K`st|jmn&7Ce>wEdLto&iMmnQX zDQ%b4EY=r%V7bA&brlHGyypA4j)H{6977H#p>~Plh7rVqNt)BAIKl+m**SkERtICk zP+*Hj2iViqq9UyiX9EyLHX+g0m(FAe9v|6o;chg`rzH6P0+*NdI^N4A`M@1!z2PjN z|C|c)=Mx>jvp#KW&x%_|4m7^|_oZeB_2H4i$-ASaBlkvFL4f?&-Y_nb^NP-%R4qG$RN5r8jG5K$w2V6#i9_-4eN^83jKQh{seU-Cn z=L<^uBOVHs$B0(4U?&{NUuAH?ZPUD7D{<`(MW)H#s7J!h{7ElDIVRDIf_Ii>5zm!3vkb0qiVhNj@LZQ%zuH(WBXE{Zk=uIz>6Mw9`ngE4Lho2 zW!Q5{s9bAJhfQx8G^WjEOVmb+BL0nOzgDeAF*5afiY#Zhl zuHv5>9wv+uM<#a?*hcsvEG655dglsb_;jJ6NeXjKNw74<==@PP=p|sSz_WtbWrK6R z2e0pg+6LqF!uF~9M>dL-?!~$i_q2gUIzt*vY{}jssHqjgi3&Qs(YQ9^yo{XeF$>nV zr6Iq(dJf6vkH+2_5#F3iN(6{$)M^ThSgkoq{z{@?|1QW+IfMS@{Py11ACIT zHObvzy_A+(KLxXQTHx;C`<^qrQId?iS0Yy2j!SGuV`8mBqNAbO8^`_T=czk;qF%EnvxhZCuRBTO+KT2PGsngCmG z1Z7aIleLjwX0U49F*JT?MbADeexgE9oV~NtZ-~5d&+An`7B67nNLGoBE-v1GX>lj4 zDLwEdU>eNhIA7k!Dso<2AfkctmCrPGV#ATR_?4N?(1477fQHf8#x7U33&Y33tdRJ# zhz!DD2pP0qR$aTnKlZ`PtAWhH|3-~Yv5B}Z^~(Kn&kT~%_PW8s5!tR6L9;ZaF5pwo z6Q_2?a{ICOm~`O8S0!XgGC~CaMBD%{hsq zID778pTFN<0Jj}b7yN4*ImSo0Gu6s^#=AaVeq_qBeOjER91>n9!4;O`HON#P9G4|k z^l`P#b%$fAU9HEuA6y<*Pg^nFIo?^`@%QAtR7!z>9VTbFP{d3Fvj3L_&}0pUDjN0t z?L3VQ&;UuY#+e!1_u&i9+Y#acunK(X*|d_TA448UqZ-W84l+v~oD}re%rOSREu$nO z9ir~*z*T{UZ-JXHUWM%(Ux!BLbs4&&a@l@ypEy(N4i1)-r@azZd#d_VcfyjGRr%q1 z_tZ@I-YTRjR6>TGSZHZjVC728N;*KL zB{^1a{fdsTA{^Jk$-MEbTW@m6yCrF|d=%v3UW#APHmlcqbZ8cRf?Cdw#txf3mbmg9 zf8#{}K7wY6uTD8MIq|8FF2QJ`#BA%LIX# zFf<0#KDDdq9k}VdF%3x8Tcdvi6Q#)y1oE3jnH{qz9@r-883xyw(k$txr~ozSP0K=X zU|!++-97fxFa5d2WGc*JkPYj%E2!-O_oH!$)>_oBASpg)2?v^i78@A07Y_D^wVi_- z3>vI*E5hU)3iszZ%_Gue(_uPkRXKRWezbGyjs&O7d;z$FiT#xCX>lf_{#c{*)9|&f zO}I-x#2h9xk2W>S^lE5wNH_JWd`n@Qp^^#`w2wuCQD^!+jQ1BTs|s3Vg5mpwKw4E= z4Pgz=7)+Krt5?^F*_c-Q9Cvw{^R7v?hza;z_=KgQ9rg&bR3@Y?j0WqBmv-rg6wZE2 za{G)2u1+V-grpVhe`JN7KhQP@JEnkhXcVyFxLHy(%s*fa%zKa`cREdE#WOmrVXX+W z`L`Cc@=DZR=;6DmyX{Pxlg*>(-3jZ3uQPLoa|n76R3hvh)~tliN$JICKHMq8(1eiG zu{={>34gh0zo@Vut9s7PtMIzO%<~H3d&*&IM&{d`L$;M}59%)heX5q_mNTBeDrK$h z+)-*bm7AjWjuk@8Ff^yF2}XHfsnf>M+Z~}j*8g48xaP1%QH=<|Tx{h*RTh+INmR|j zJL9ePA)mYI)F&(>Uh3eEay3uFgmdbk$dw#eh;A>6Zmr+L>PDyk;L-DWyLAcNIZ*Tq zmmAmrk~WPV_6=+jCHXzJP@4|ct7Fr7U0^_H$8B)hb+o?yq{~d*eQnfd3Nel zAIX?zm*(2&fhOL$YY5tYF*4EJ+@l%RyJc#>G-|QFsVc~RMn2qH7VBMx4O>qBD>s7& zF}-xRlJPOwaZd?au2d&C)j;{}J+H3w z;lp9l_Xh+I#3+3k+`=aGH5YwPAV@W7(K>2$zWIem_bpzW0eO!9mL5d($yGGX5p3fL zCOUVnOjw1?Y~SgLm54sCvp$P_^LK?g7IIYH-Yz~odSuPXT}N>+;gX^dfc+;zy_Ttm zI%H0wqS>BG`kS5)|BGT?QYEp&#E3f{f{XTQ{z)r)VVd+QzOSx)$H&3u0ep)e*;(;y zakvf``0Um06p_j^UVaj0}@1d!e3f_zDx^Ln5Gn8vGkmMTzT#3&HrgnJGnjfdcCuKEx zlHjfGQwgjvrhORi_maZh&1UxJ0c4JGFUKtYu9SpBNYhkNEX)mtA4NAl-phl9Ea^s1 zG0kf*|HZYT%8p)zWHZHV-(em{W!>D3!i1|;ps&*vkI^mcV*$G8 zai403CM-F(QDyFTWKtM^Rok`~5>h(+p;n?@3Kx7**E*!5xnEu%yu&18roZ_Ih=4mh zRcmDn#&1?;+hmY5Gk4oq+Wt%WCYkb`ei6%}oiMCqQ>NJ2MoqO|Pts1Hfni{)t}565 z%VQE70eBJ3P9t&aKv4GTiXX*LSQ~3dmKfygX@0?Vx%^ zwDn?*XhY10)+PLQIODbPXqRRNaK5~%O~`P{)^kK zMKycW+16lv@7&sWhZYMS;#1RzEq_lJAI)QWm%v65;+M)tzQLI<>&c$WxMr7~leTs| z1A^GN!g|nhTKj$$BYHn|^4^rsY0O%D_}RbPTFjeNB>aJ7Tzg%{uZrw;R8P1ssjWW` zm%Eb_N}-=(Uo{-Yzdci&n@S*Av0)%%z4`^AjJiWsMeXIz{Yl4wlC)IXA!kWa|W%_}G0ofqsZ-QVNpRrj{O zSID8p$vB-oJLDsSl9j&F2U^7-j5B%2@L$3OPGNxxonYkC!cjQK3Unn{fymC3g7a0_ zM%G1+ywF$HX&Obt5D8xVKH7|`BjOEJ{$;jUU&U{$6VfgW;0=OA4$o9oZ};&CIScz5 z6>GV32)hy;!5=7OFs=&E5HsBirogE*8Vta!6(y6>+dob)|vi#8QiFzP4^yu6>pr zm0v~51YhfU zb{?9FTw4U^6#C0=eGy4kSXp*0^@t09EQj$-GyGLN%g)>=u&tiXvEhk6SxLwf@bsC3``{s=|zl< zk#V#~)!Rc{hZfb$MT}hh-#P~bHhQ`Y!ig$bdz=Eyj!#XRhKav7`X2PxY(%`B2Sb|( zd;%(zeFu>8Ze0?ZGi%Q!@5q-{k47k;!VV5^`BbIH(wEG*p?0tYvPrASScGK6Z{ISe zfXgeJNZ(uW?6r2*3n|+J-2r+J)?F=>q=Wwm|A(;+gc`5Y9F|&d?*mSzh#}X3 z`}H{6Jxb-6)<-tq?mg~m@JX9G-075vk`@|rU4-%q=nHb|*qDOSS^3u)1l7Zd$hd#K zBo3rH>jvmKDNFS{Jhjd>K~#@YIkI|tfyYs_o#;5Vp=0O4|Tw54k97iziwO5m1AZ(XE0)+&*bvYickT{2a!`p zdh!3wBClvrya-uT5e!x5{t@*IBOsEykR486U0I3-<8MqyrT&$o#tRt~lw9HkgnzvsNrcip zImSqH{w#(ENe|B)?UpfWWy5R26g=PI0NuagpK4d&j)yy4V}S5B3D{9u<4Pdqm{)Qr$qJQ^J4gVc}i zxZh9pK(g;W!yuO~+I6N$uY0R znKf~roWJ>r8-4^vIFz=evQz)oq^}UX^B$I!w3uti0nI4uF^X=^bMlPokW&_vd7|&U zB?QBj^v;)D;#6jDHsFqz%EdS7T65|7ciW2G1NBzjElS8MI^*AemJ)oL{4q#v@N1b# zDHbZjYBW{1+0P~Ioi$a{R+x1=^NTjheppbGGUGEEU_Y>eBBT*_8jbqP*STywQ;DNm z#6AN`Za14JjIiE|+q6nv!QmAlt+2!Q&&IEE0#MA(*YKJry57C42311W84cMO+j19# zbSn6eFQ$&b%T&1r|2usbwpaamjuCtpp zEUD(M=msNa70l_2bl-1rJ$O!OxSXL;vRK=->=_f+8VYk6f;H4g68j1s^h3Yqw2M}t zuI=fZ0WuAWc|SL7hPh3Ja(a7eW|m!7&cK$Pcxba#qc*@jue>(G`oBJ+uuI_Kjp4KfzLy0ATq341vddUvkl|t9T*47J4%T}Awp0ga#+decX;K{d=NOaDu#RFpp zB$6aIO>jJQ_})0Z2G^j#Pcz#jMOGtdp*Z`+3$$PjJ=afL|4_d*)qmL1CB$4OS0r){ zlFGsF30y|Vp92=;B)-qsF+1&)B3yXJEqo6Ak#*mH{9g-kE-nFxe=rBe5-{q(3;JxVH6ZmnDVVLCQSV_Ym|q&;|U z&tzI=qU3iu&c{>EQZl}JcYCyt0xjPXj^@m8wvC?WP8PNPBb7skXyy7bJ_f|7F@N+H zz*7702wD%_YQ4UWNn+IV>)`UBNt_<)h+)VU+Npoq?dfscZ1CMAR#`A>e-;o~rat&c zAo&2s*``?hFL?XU?(#BLW##`XPJTf-Z)9JYLG9`RLn{4=908`4opSkVUH4qk?36O6 z1O2Me?4XGWx%>+Ibe;ww7Y-NWM2=V}4sUYfr5uSjQ`&n|Xi7zIs`2H0m-F$SqrBoe zohVRy{Tn6G`amW@F$knG?Oi2vr#Pzb0Su2O&`0fkdkp0RA|>uB7JEk3nBPUkxvuREiY}evbzi5A-^A*vP7rkf=R_#q^9MoF`E(#Zkm; zna8{6@`^ZAuy_zvUBn?Mv2%O8slbHNhtKC0h*&1m!e+uQS$^hloS%|X=5tr59c~)>!C<*X=R1QFv-06Oj_H8eA~|snk-oQ zYSqu8pPg>v|Hq{)4Ugi_G2t?=c_Y7($DZk2qO~A3ZAK#t&x>z>%l>fq&zf$C=xOk( z_Oz)?E&7A3Fwd*Vw2&5B`5d!(4MVs3oQUe!1_aRrvw$_HzKkB#`wUILqQ97W8s|fV z%R)3Y?gDHJSJidQ#w%8k1Oyh<(}paSRyjbI`*ur;s`PHOQ4SkN}55G0z8=ZdHHg`ppZSc}_j*!aZ%W^-VvQIn@RU zt@coAgAH9U&R>P07SxPMkKScZ39=;n za4XgNYj5Na##Qa6X`K0KVGieGz-sNX;Ii7Eq#a7gHisczt``>vKFiZvR+;c~`^M+eCjHg=dl z+&NoA3q%3d=Nblp?d7mm78Dj2ktYPC1ZDuUR^lX{_&9v4)0MgW6U6v9kTw~&WmUj3 zLudMR&`X9$JlumkiyBE^PIX>bW{*6RCGGjOvn}?#+`ro;cHiZ7++St4cs_TbkS{*G zc6`2(g*=}>E|V-hp9HUVo;u$#-b>y~w-irC%3EC|U9Ijq9{TnK2>--M1s3hr?Sgk3 z33X_CN0ZDD`|Nsj0Qb^8Y*x{4tW=)P!I@@n?lqckl|szV@=r;t&9fA8ZI^dH95cbP zW7#h0>v~;;R=hf$lg(T_-!un2&YcWSw{x_fjVb=8Uc%bztgl)ki@ZqbswZ_cPPnm_ zP@vQhG_YJFMSLE&UL-|6Afr3}bAm^SOaUXuoD-VQ@kxs(?qnZ*KyzMrv^%jm%5z{Fw;UrR=!&{qV2{$t3k zg(|MBLMNd!5=$#YF4kH`BWIWUy}dB~JB!*eg4fy&ksm~#_^8L-8cII9A)=flEO_EK zrUSEfX;*5MdA!YS&AQI9bwIpWm-4Mt{kJkb69NGsIhmW^E-8#0I*zJ8=Ty|6cf?7+ zR&*3hHZHMLcY~*C+U_ntbZJ1|wm2jmV5LGFHgpSvaOjZm>F9LhlwO02)^dD_S2Qaf zpil3~ss!;dp(-kUL7`1EM?wX3C9}@T=4bk-KxzZL*K*JeA5?j0I0Sp5AZo;sAS;uhspC2y=Dt zMWSeMkv#%!ZKQFs2@Lv^|H&QYjdO3g<55ZPNPLu5R;Pf?ch1@3hejVDlAQQ9$Fon4 ztih>jwrL@L@O!bv&rn_gN`K*!9hxNqKiT>+fS&Q{p6fS3T+wCu39l`7JMRDk<0R>fX0T z*aE=(;L2^BAr)5kL3s&$%gj=b6+!p~WhpQzWvdf6W2c-ElrU{HI8i+z=}Aui^hRUt zChG>oxzMaUFImj9R+r#O1fCt{e%YUL+kf*9=dUg@=dFO1L9(9NpU}=+7q~LaM&X z7I?IKinIVB*V0!sI#hxFATCN?Q_Z-_!@5uemQ5-QHTTfvpWYAl*q`_L> z_;u44)@AvqVa;nMV3gE`LIBv%uUu3#1?`$4_ zLSZJcf_{I7nQ4Vr3tvvITD6}qt_rfXC*yBlJzll+b32%i^G&xEyuaTCgu!ZlsQ6br z%XqlzYZCSF&{i)JON)*(K;otW9Co$Qkl8JxO}lfHn;Kb>CeJf{f`3rl3jwo2j*FNr z_8g96_i_FoNE0}L^LOWW*n7Q33vfuN2M#7K5j6=;W0$z8e1UX?()!781nwU|42S#< zkM$$eNWhFl0_Rs5D!qJ9l~jBfMR0?DqmTO70DrodLaL54o7z}|NIQFFJp6*C12wVq zi)5GEM`w;NyHuI%O3G4cQ)}pu)WOJ*!rOGC(2DXi3=M4c0<%adLYfM_z9o)f{=L;`H0cK! zfIjas@BSda;XJtJ@h7^B9U7E;+4~txqTOoq#`x&6IG2;z!CIeB8fG;r2AfYV{O_&8TC+myhMkTUs=%%)p4->Hdll`%ulwQ|B7Y8) zHD6~P-`jZaSC#Aueti_Fk8ti+Nw;UHZR67t!az@md%|OKaRTY9kj`R7OV6XCe>!S# z7ctcVFVK?&Ubf z^LPtNh?{}noVpG%P~7q+KC-GMnvH7?e!yX;|a zdOa+d=Zn06O)h#Za(a|@X)Xk8R81U0XCv8qxItmcvG*2Qeg#J6qaKqSEGC}<8&b7C z?x)`9yn_o`J|+q5`a5b%!|K+4{F=f8Y-Dc>6Bmq&(A-G0B?!u>*_taAocYhr{}gZF zS`9Z~dl2^E3%TW$y0eRtCk%N};6^jS7k>G3T4s94osA-Key@!-P=>$zkhn^;#^WR_ z9PnG;;^^uCB&M~DPlvfXu^i_gJ#*8}0^x3q6b6j7V|eQMgX{4tNp?93d9dEy8k}5~ zYU6CK7i^x!CHHM4g=CigH;2h@7ALQx`SEUQ%gA@FjK1S~%_^5s)&I!U`|)ymU~7x+ zJeV+WGadI%_f8P)!T_-ONLcVa+Izndrk3{DNmGU3d<#Rk|*C?@sRy zH-Q|ot?y)l33F$jM-@4zEX+4%fM0hMqZzVEw!Lg}sZB=0+PSG2T`Z%&W881WAMVtP z9$-l#-fe8w23%-2o#f2(uRpB1h*rRl8`ooNVH_+uJcjqS<_#U_a%O>*OMQ+b!|iQN znsktHPrN)5QI^W?Nwz>=s__S1zx7)azf=As>1PDzBbuY|SW>|&UB&t8|0SG#`u%PP z>5iPY%OK#Nb!h3Ok3iuT5f<)S6KH%A|GP9KIt*QuBh0vU1eMG4l7V%e)fS4@LhYF^ zj?Ae@jRVS1Scsfq#}rj3h=Ij_8)FbPrx}h+B_QyJH z%_a3C=*Nbd7MQWE-_fGCp)(nwPLXE@)bU%cgf*e-!Siy;1tlRBmlTI-Tv* z*}c5ms0Yele-ci`NPtve<7(5Z89{IH)oYGdq&j-Tny~8D3!5h7ga9{pT}y&lOM+(2 zMlGWsKgG&zM2nKcYgitO&Z)^Is!ZYcGssyZs!7_OoOxHji$Ara(y~G}ouo zy)tLWKSF5YcpO1fW~gTFKxS4=-Wj*CAk?VtPY z8|g@Fjlcp<8qHuf`Hj}W@n7;Fg)>^JTc-R;CNPSMK@hnJB_YcMWtz`s(@(6X{I0d| z06>&2F~*CGZjy)$uQ+yve4U1@%Y@$sSukq0R&fca;Xf!zUF4jpFHRZFU`0F?U!jQ8o!F5&{otO#Y(iw- z(l5+Ze!@q-Y){{$?b@&jU4}0f62D#eyFJzVm`rNb@k^{XMdXdN zW37_!icMxoay{nhfp2^*wP9e5e0?6Ds?eQ*!CaXa4N?XazeOpMV2thyAxs@*qr6(% zs}M2+sC}@$Hhs}g+^c9b_i9+Oygp;-*iNO#JkIt~`YTZn>kXe$nf3G@PLyfd$iE7s zR!gxF=^{ShSgFhG9?JqJEH`#zS!EeDCE6QJPsgT?CQoj~ujM$i3gq(fg#1f-+hpXc_uoXQho!d-x69p~#~KX- zspH>-O37i21?Kt&_ z`drsv(6Q77{BL3yU+hI-VuTRy`{AEC;YCmJw|pTGws+i7nBT>9 zBw_7)k^`+M{Jnu$LB!!7(i=ZG^0)Rlb^d)`qV(VXgw8x;5Ra;T*i@PVB|ps;#q!swGHRwbX;;RX)N6hmQ6L><#{Mk} zxjnZ})H8+tn7b*I&ij$Z20RQ?9wxry@Q7~VFmX)sf`Jt=eLuG& zMMc@H*WK5`y-yuDbpGDq(w`4TGB}lG)cNy2Ip~q6$v}=@-R>q`#o;FQ`Tlt^%q+HL z@L&~B1^Qbpbmpz850r9fDVP4*vDpn0ZBNOi&AEml?gQjQe9t%yFH0(u2XOVm0T5`< za#Q7!OIqZrL8^;KX!<4GVC{as5Vy=0&Dk$oe^v0aC-SNP<_|w%Mw5?cdV*k!gshJ( z7MioepUx3mlSEgo$)TipTji&3wCx-R`-}M4G?wia`)!;9%_L*ZpgAt^rfWPA@8^VS zaXn$JQ{uS%!@l7=xY}Fp=o%=%s!%T^tlpYg6*6|mCp2H1$y-FHB6PcWx}Y6EFuokY zl&iEs`kD4DToTr)Veb|I_%-{ps$O*PpAa6$ zeHk4cpgwD}R~9-S=(nVc&1fEe+IrtAWpyxltIQF1=|TVhu_5vIRO7!hatE~)9cN{* zvARe5w2wf5y;bgKW01r>ratcQq*y@*O}Y6mXEO@Q&k~ZsF`%Eu?C(v+*;O>->03b& z?w8*h5a~fk`WW;?zWU1F9^}f5a7AA@)TD$l_e6oo3peT<>lj-i3*PmZg(xJouA13s zl(k-~7e4!YdCRFm!Xe|3C6aoqx$YY8W3O>s-y7<+mZ0F^5y)|=yyiUQE<>gU_q(fR z%0Bn06dRmmA*%(SQ;NRtW93<^i+_QgVVgQHm~V#h^qYX|JWIr6Ja@st4#TbVU3{1y z8(W$1zc!K^8 z9cB(`Ar7+FRB@B75k3(0WRfNWbtw!V#EDr|9;26k$K?(;$Yx6k!c=l;iQB+e_SkFbF6x@Yu~ToT&+K*! z(oE$X@8yZRX143RiI)N2K;3b0$>u*p;-ugaxPlFiYpoQW7y+Gi$h-obDw!L;M3lAB9Et=p`j;7V4^i~p4P&+*mRc+XL%zc&%~aqv$d_|p)V@FPMCu(WRPM|A zqcH*aY8R;~vtDg_+;gnEL`mvuDb`;AuH9NMjs7?YFq>&fxzM=33JQ4<4rHsB!dWfjoUdFmG z*$r%R?;*WE2Ec#C(fY&apz@-k(c=0saO276n{oQFV*u|=y1mvd)bp%x{pJBvRvV^e z*jEz6FgdiILc-vc+hOq8*x$c?!RLykVu<_`w(yBq)4A}rWLDhh{1d-Rcum^om_?TC z_QB-Ka~0}c{S;FhoUt*ioQGXNNabV!~Y@gpww)tzSef#1}8WbWOK^ZN0CeF^Mu1sAi zM7bV8&+&2KEi8sW;-o@FeUSSB+f{qqSY^yK@za>!?MJi7!k7LHe)U+DV4%66z{;1r zFzavXKB&qMc^2%S@-xii*P2A*#TP0UXxb}E>xck}G-eaZiD7JGTdiW}TcfS+lwE!x z#^U?K`B!1WQ7&x8szdy-MDV_VEo(4Itf>m_a5%yS&Izg_4pAb>lW8h z=PsN5^~tvzeMuHEhj{hnhX-(q$Z{-7j8o!*R)G8m%OC_RqRfgY9*@z*uTXp|H14rq zneVQ+LGMyoU@Tk!T}@20Jw^vy|ACEsq3LbQX2cJ|#r#n1?c4o+az)F8Def}7aVk6w zq6$BI28!>A=os!e27O6|Ku02%53PRc*daym6f;6EkeUlc}PU4TkE-D@|N`OCk&TJYYF9dHL3pf4%2xBAxr*e-o{tD%`l=}G>-Zd(J zsi(B9oYK_SD&xDW*rD zQq@e#bgk^Z#86w0ebt+?`=rUAL9?BcNi^t3-&0<$Z(i=YWO7P7$T>@Qvt_2Y0Z!QV zH>#ZY!IGUC;|G?hk4!eR1KQVsZrAc1!tjRw=p15GSQ}c3KhRoH-_(`Aa^L~@5-X{3 zGmVdqQorY3u=ea}UJ7N{3Q+3ZrOkf_{evRPH{|CH%bKtZk|{ zSbB-(_u$|5LwR=B%(LdsRnbv{KjJd=zEh_YSbHt7V<&jRC)TEayH(CHpHT>otoEV< z@XKfMy%umf8+43`5%Z7ktLnihR9-8o?l9~B+TQUMu;22ubrZ|#@9f?B02wGqd5-dO zPgOU)tp4W*^7F>YGXgZ#*I$lzoC~Tx>}aS8tK~d(xo(DP8CeovdDCfuK;xp8xTL~t zc;<(l3k=UF1paMxMpgMz2;l7Vb(^+SJ zA_rPM6+G>y7~|Mu54=Z4_SX0H|AZ{PAdSD|JpZ|*7Jz=_1pae~Xs<;bG}9ja8(c57 zreX^WBLSv2rP%sK=u}c@W6*`F_prb zR=W<9vrLKU9icyM}0vu@1rv< z_zHsS3OE`kZMZ;k`L8z(U~*}jnZ}1l2*84$fc^;)6$%^z=diOiSRd}pT<<3-Zs-!3 zTXluDggJ2fce4@Un#Mk;zcVD9WV&8A?WRmou1oi08Pk5Q8_|qzTZJZ1mvix%u|5~` zHZPSOcF^#Qb#;P66s$ z^NXzmiYJsgs?Ow+QWfK>f>708YmJR(Wi3HGrg)O6MDQOxge8>Mf(% zYPfFg3N6rLg%)>rcL`A33lz7a!9#Ee(iTdgxH}YgDDDoyp|}$Y1efBH1U{bcy!Z3o z=ltDcO<>O&*I-WzG z*h&~|7ob{tjLV^QG)!rVqUq9%xzt3MeSBDpHisZwqRDV{>uO{@c@o>wn@Vyd=7c&S z@;K}y#Z^9nr%Cggv@!~Rbgl%1{-v*qfU;>4c6M4tl96cXS9>Nj1jFvld>dzG6zV#5 zp!>z=Hk~dYY0|;G@%5GS#0iYGY`97$1!N3~_a#oQI547l&N!Xux)5y5$Y4)aMRZ)RzkNVZqLmddnL+R-zX2PS2yI zzyZM{$@^5MELIIkl)KL#IMIT%@|5rH^wjlP7jYj&8hKvS?!)dPuVCJ$awlB28LuB} zWTi9{rGK~)R>kf$mgAty8gGp<0{-EAkMytk)HQn-Xzubp1NAe2Z{toV#iTIM|Bx?> zv^Ec?-PPoUM#^U1ZLTv1DBJKlw#rgM0ox(s`FN&?(Q)Us^JDm9aYm<$o(T9%KUH1# zH$f_n+~EAFHe+p^7ZjKjQ{!_o+o|D-h5ZL0l!-fF2d1DRJ}!E5k)#G(RGkKR`%|t2 zynEQp55#{^&q6P`pZ)K$C8|s8#TWITo!a)f2b2GOT7~uOjFXs?yD~WGH}|tYJjAN> zBWZtZsPbY9$uSv~EQUxTrSWC(eGOJsv7F4cD&rVce$COO*F)*C77eNmBN?{j*&n+P zt*C3#1Q&dl%D1yAbc-Z;Sl6T;FTt}DZMU*OZ8xr`gi1Oew@Mr~K3#;dZ-ijwN6;Z_ zh-K;U?nyJRer5`2DFyflHybrsqLd6V*=jNE7|i?U4(+pRx9Uy56iq-dR=rx~UNwq; zzh^MTGK}|7q}N@rP)x5pN#5-1d=?h4r`DjE#WC#HU^F)`p6-nqL;@_*-meCl#_y3^ zroLUmH`36%7{qzLN;xdLC#9uX6mYAh0l@z*szatXD=bn_`e@LjO_eVD` z_0*lT+da!^ZA#I$L8lmlQ+tHdYPXc&eBCaInBtvv$`QxaG_&Jq%WW&Yt74$LfyFK4 zSf_!JUMfzRrQtzBPm==r6|S^V|7e=jLU$8Sf>`v8Q^K&s|}o; zWR4L6-N}fbq#V8my3^_Mxzz>rSRNK3x4ON>1r*YgCoPSVpGyK)8`^9R>7SiU*|_bQ4|_d{fr zhPDf=#_&%Aui zc0$aHyRo}-NafZL)h%|EP$M#FCI9=L{CQg>NzHPa8<`i(JPg%bHjZJKs!lWBI6TWn zR<3&9riq-3PS`9Lq^eNm$?7#*z!{vN<8bVB?p}*ntrVP}xH=s6)GI|mNKvz~TJa2e z#|9`y`P9&@Ewol(!ISobV(0dL{ijFr;=xT3n$qMo2u@h#U{ z8yYGf6gpAM(f3>Fpbnqldz;OT{%}dp$4lP(D&!g{@bUivC@hwuI(_y_iURhhv+vz~ zu9|m5Hj%S6_4U1+oLQz>l=dlD_JJ?nIBHD5UPRgK$4W+&JbEi?4>%PH<1Rdfs2P9r z#(9NblKb>;b9yeOUMQBou%uCo_tG!egTTIUDIs*_oo!g)kssStm&53pbj8bx_`-&LO-=z&o^(x5;N$yPbhw59e z`Ttgo|15Jee@Ib~bZFNf`2JVIdGwH3%RQlk^1dX$X|X3BY8Z+$2;jch5*4@nj>)rg zyK1oU^AepYbzATosqK4Hwo2)E(iulk0E=++; zyJa0q)mGe7>lpSZdNSXGeft42d74zwyn4R;Re2tR*vd+@_E?~M9{D7u34O1tX%0YK zNV$mcA;h$@%kgFI-$3y^JS)PNjD2>-XL(WQ6yxFwbBx}d7gH+4hl0aPONJsohs;2{ zDxI2Fw4gxY2V+6w9syalv{qNcO!xg-`pKww?52a4ZSF%Hr=AQg*2F@(Dg2e3Yj6X9 zGN?MCiyYR4fo|(e#XikUf-EH;Z_S#7nP@Pl^(&H4aZI`S?C*+nrpwh*sM7e475XLd zmG$oq#(6_kxa&E=BfqM)^}J+@eTuMkcx1bxT~p@VhhM);kVeH6zm@A3z;6ZYQHeIr zEykFVB>i!LXrpHaSdfkm*1eeyDU)GKZt2s+RjcaW`8hhfU~nlYIo&YC0+kqa>*^7G zOrQrD5B~OqSvC4aGTBvO9rU*djo$D>cS(adtjb+4HBxR#C%7``8$FVIyM^tItvO_7 zmMHhr<(o^;r`^J$hSGNwr9;MV8R}IN2!EApW5Svxx!WeX@d7>c8ax;}IsRyDLO(=RxyukXVfWC9D*`)feCsbjBKg6~4=aU4ErknUb!Q`w3+7o%u!!hB`A&%O& z5Y~neu|M+ux_TMt5;MX1BIaYC0YIH)=*z9!*|Np2SAD12j?(~+vY4H?trp{M^APr^ z>p|sn`@_nGxuYeY?7kpTBLf4qdnidOs*QnG!$f8N*ojEj>@wL_K`8EqkOB4i=k++= zr%NP^OpWm2a%w6zneNv=@?@7<^b^#;-u&Z1{__dI`NhM{ByQl=R*~eTx6kn{(W@;F zl4^os38G{6zG~nU3x9p9&z*{(+PK$8+p7* ztKz}UC=fBt+{9RqSd~@!whOQOrPM z93CF}aj@x8h5T8B#+<7}61&#d<*P@Cnl9qEk$Q3;uk*(=wNyg~c6-me8qIBEtxDwI z_L}%F4N6Zd{eqgWpDqfMn$V}G{dp0E@j5aj-QJHkfDXW*;4#J=^f|^KAhfAwHM~XP zDuByiK|R&MAFNbPl7x3L$z9kn)~u{Ac{$Bo5GAU2233Tk*7Yzg-Q};hx@VDnrE%M{ zcuB67Xwx97pcJe5`UAb;^!du9$fL*%YwwJAxj>C<7PbNEGHR&A^aqInx^baC?qs*O z1`?&UZFGvB9!^%p;MrcF-n1_AcdA=t&^e8FpV-|76HQicJ_rCEoZ1D3H`A}exHWF zC4B__h1|<8TLwZOm2a72;-4mE%6^Xcq~4=kihC&~vhu2y!f(-lcL#s&~IPu=EW6Ykb)i#eEt{%wJ34 z6ZlzUO%E2H^MY0gxNLNipN?+ju7KVMZseGm3*X33EKho(hwD+3(IO?YR)M@TC`?F~ z@)+zRoVpRSX9e@L?y9Zy#;e4s%QBmJmbzGA-LZ2+HHO*~6(k5V3hYA}l*Qp10*R(f1*#w!@8YqpmwUktHX0xRnxryHF=)Mq*dycX3On0jV)kMfDD3WDmD0T~D!s+={6TDA|}v;;(P|-M{ivB``LyqQK4-%fSqM~w-P#OaB+`Twp; z>|H4AQPqZ>p4>@w>!s616%rZ2E*5MgAoQEIdSxwqi+mZL<=LCa&C7@IIO!mJd?^3{K- z_gpW7{tH`(+c5j7SdLc3eB(zezL#l3>#EsTU(D4qImifmi1}nLQpG~vp9+kM>Qw40 zTa-3>9Mr0xO*k4EO>6Ypx)mm)eSF9`J>u(*8`(F9I4)PIPzyG5NK|XvWDEQ(jF4G3 z*9N)EHozSg8m@b4nDqkBom-$FZ{1`PkF}{n9HmViiVBrXyWHn!#b?+cG+#(`nqTAP zD8hzZx<>#N)2E%7`dP+o+dN&6lcbjIJ$62tfJ6X<=V}TEkA1HN_cW6Bo#ZP!lfq-g zG*@i^s{rRt%rxLqk~*)sk#luv^-hC?+00EPK`zcHkg2EGGNQSG;NV**ArG+lacN}? zm&-Lgxe;l8Pr)HjFbtX5|Co@OU_q|MXaqy-Dy~&<5=gBSn*CKMzik*IgDSPkMl{XC zUWq^Db>-z5y!wPDxei5CjMm}qL#apf4nFfD5apjXAQwUAVn%$5VQLYlV%CD`iF5}8 z!*4w6en~_dm{dBjb!KF)i3I>10puirpN??&&4~h(nEs zZIHj?t=>cb_u=!2P7J$yo5i)YQ5r3;4EZ=DkR_6~PlB(273^Lisf{=Gs;C%0=S zTn~@B;khKh>ux2xAaDU0MEg~}Eaoge;7V^#*FC4nk>OKr1j2zi$@kquoIe>hUO-d|t z`3%re5j}*=Blc(WANmw$Vt?lwhrw{2?^7U4~gt}dpRN^01zGsN} z74k(?k=9^4rY&SoLDagDm-u_I(AHUgc+TsSPcNe4z7(G3nPGXwnBW_yD!K&<&@@jz>fX3tfv~Z?5oO9KY9l8HAMS;81r}T%?YA#5WGk zMXFC?gC$3Y^1ipzzihtJ;=-z(SW3WBg zzsKCNcMz+W_>h!iLIp+JLsr3^eSCH9zts8{sFB}n74~0uBj4p^%NtYyiXy}n(8CNb zw=J8j)%}iT+_i`r@?vWHGzMGiF`B6WTJGmhQnXXfF#hqqBDX(pZ`G z%4Zw_g}(J6YU(2~L*o}jP|D#>@K8$zytOCqsC^}V`nSlLqY7TTHf!JmctLhy)H9tO z&3>#9K|pae+3U2LM+eTx*l68?m}iE^J3p?WP4RcKykMTV+$J1Fr~9BT=@wO1%{Ry) zu^YY|x+C2Jmmwjq%ll7>!~sb%;v9{3VaAp?*K?739AyMg%Hw%nd?e6Llk;5qX}q1< zqQhyeoX&Ji&2wbTE?5OhE}LIy|GFwuI9;FM)W_OjsgU8jyr^3Eb8$DvO_3 za8%%+qeJ$9eSI^q>9YL8|4CmF;(3PL<^nl82Rz?Ne?S7Wy!T=EW6=S1en?Hdj6j-! z(1qEdp2uoF2X`JcQin9qcl zOWR~s0L$N>^9fEHfy5igDpS9^J$MnotGaFQ$NAWSk!Sl}*~(%+IILB=z9XFS?kDa{ zG^KDn8U@ip(PDCo#`v5C6THNqOo51IWGLj|B7F@s2CT0tn)eh>9ZFAtfum8)mUq^k z5T15a0ER2#4i6rIeV8{n1`dS!miAD0pFaPYLl=mSw=;Sg?>HII(RR}PefSY$;gv-%&2+jlh_#!d1mg^yJ2`YMAsQ7dRJIeXjvXjuIM$IUyn+U;R9Hajs-)wm1KfV0{VnC(v$ zogu6>o*}L|H$OjO>%jmtvwS9I^(0S~^wM~iR#ODe&}p`wyEIXr-GZDLs#<%%>oaV- z$beeGF)3eRT|R4K9pG3`6wm_cV%aehKvdXqdTfoszwOE$oERwmNECqN)y?4SW#vAa zvW*{B_)T#lMmi2i0=Ks#iQeGRmo7_EzZo44bXq3e;FoUMh=TT(#I5(wEAE;t29e)= z>kc=no=zd@xx@6~@fr=++lyD$BsD*l^n>e7FdWNT2CEubzPCQtr|Pzi*=tvi@ED$m z!X;KTIbuJ}IERM;1Mtg4^?DF%1(^iV^IJdHa7I9`ay_E9>IRpn;_wsDXO}gUyt@~S1_DvPS#o4F0XN?t0o@4-e-6Y<1 zuM$eSdBMH**D&nt^V3mqfPdUv&0g@x-@*y}Ceo>WW^-oq)t@wW4*oOm5IPD{U1oka z6c*2P$1x&4anF%vy*Bvki3(p70#Pca`V&!}HK#rNIJT(^!uyP#b=_<< zwAMY;va!`>8yJe-7ViDG4^Ag~dRHgF7!Uw^{n-A`Qw1Js4*;&JqZ2j!_qE|uM6jPK z`oF|p8P!b-HPQX>U$E*SPP%W2RM>Zxj|$iq?gF^tPWkl7R&6qkCxC9|J35f-xc8rK zh3+pwcXEuzDC@gK*t{of&|q<;?Fwk-y9a-OZ%j|HOJ3fF!wcq3x#k5cYxh^xlX1d2 zetfa+@?u|4>8eiJyt=Tv=wGbK9OsT-+I6G&VAVr%n!zk;toK92@8smh5Zg_^0W$I0c>Pl?zq_Z&pG)lSa~OBF=>G$E}?! zfe$E=&6Un~?u9B#;;~TVsdi&Xr!>g{*a_7p`WScBSa-B2ye8zj0-SD)o_Hks@NA&$ zkQ&@`H}uy=YMz~*|6tbt6aUb(i1&$j?%$WLCpKu@-Wdy-Tv-DjTvaW@f)(g~pGQc` z20gAT65Gz+J&%UQ-5GC&=DjR={HXyJUyD^5m_bJ1nG%i&Mu}0F-q(_}+S1d3CXg5Y z(Irv}lT|ysx-wu@}!#I)poo zP;M~s8^v*NEO}O?ithew$a(C?w+iP*zvQeVz8CgNZ8yvpE*Xx-RhchmfOivh_~83+ zHtUXh6Gl8MCiQIQB4-g3T^^~gyjz|UYzEW}y?WHYRhe#I{?0JKxn+=!Dl^K|o07?X!0}SRv(c0I*p;q0}=xnaYR%sqlYW+6D032oH9CL*o#jIeh(ukAuy`& zuuP3%0wh6r9O)`mFGF!GWQ~`3@wIod%A6J%W*CG5g_x8aTGiKNWAX)XSARdgB*6to zZ-Fbqr+;PCoxLjf0uM6Mw;J#;Gz&69ntg`_i#p~KJ<71EoyG-;EsMYbM2QE8PpKhN z9>iz$<1)v%)*e0ITXyYR>=WK;MD~b!2oL%*r>E={8EenyJug>4m97n!(c0>LDxPlZ zKvNG@4KUD*3=A-9dMS1xG5F@4F{(|iBW{fHlw10^L#5Z{U3yLi{*6pOaoQQ42C7yW zM{*gROK;Z5vIYKO;%RhdBh5ow0g!ikYTV})n;F~TBr#$ z`+^8^_;YJ<&B?WRIaBOqb+XICruS@^sk=i&?B2-=$s=WOv7u77 zLzphUM`iDVrg`SGRsxm+QrC{CDTAIz@tyTC=t151-=Nm|ct0djU^oqU)d%Kx(ut#J zT(`+5>(HBzYfbWM_+pa|tTq<>dGK!6>w1G1@U{~9J9%)>nLK(}6xztAMfQ#sstMq0 zVq6IbD!-pAUNC?7oLl4DiCCf04g(VjT{%=57K$LmtQBOwos+HJN$8w4m+E@q02lLf z+B0l27p*!pbz{3ng(gu?{adwcT6|NSSCHQR*5u(|n&rI|#wTHspg(Y0`S|#__oNQ= z5dK_#nedRel04fn>CkE$ms4M1%4Zhtu`3_5LRd^%<5Q*;o{j$M?aK;I1Cn*F+NIf{ zwU`ePY_mesXH`S&}Ey;$ob5JbZZBQZUd(o;}NZV>*b~b zt0rUFc53gGll~6<4O8kfsVqDo{vg|p(6cGuUzEM`f^o}8ws{iQvG<`qgSLGtU(?5D zcP*%IiyS6oqYg zU#8ubkAu9RmnPMf4nFo|`Zgn4dMpLAu~nRZW|Hmbb7hiLinX|C3KN5bbzBo$`-<#J zaWJ^KmMiEBPua`ZDtHEMiZCw1DT7mWnHcvu8jc0={J(qtj7SiGSDe{X=-=CBHKcPK z2fcur7rc=?lJk#oLaYLNUg`t~x@!IXa`@x*Ua4}o%Bq%bC8k1$+w=D>;Xgqa&OyU(n-7LGq6)0@yVH(NF3LvvH3uA#u8#jQ z5i;4w3BIi7V0O3@W%3f8^B_;+AwCsH7{B-N@W?a`JLOr8nmSUra?SGgrMxq3cwdAo z>3^kq8+C%LJiC9?F#T40qme)dhv`mrW8bm;-%f4S?WiC#zoYO##NJL;rfHjZbsKX3 zHJn$h&M`K5(;DHX7reZ~5o?gCu|sT~LawlOYt(>8%^chGl0qg}H^yVcyvBus9NQ>Y`>c-tXWfU-DO= z({wY4uIX%nat-IvIgHX-bbw$?ddqBmEpdA}zjF=w|5&faqCV%<{ofp8TYZs+6fQu| z7@ffv97a+_{w#9Ful~+2iB1GCtXpL^pld-?qp!2=H+kFo=NG1}Uin}FgW3nY$6U1G zqDPan0N+)U z{`MHiU(UwN3{N)reM}}!4v9^?O9$+66Z%%cIFs7S<-1*q#j(R#*sjIO$%k}L+^}4T z|M1I>3*(}e63hCs664DSO@Kz%vxx!?&Bkh?krCY=R#{?RN{e__|G3{)*)M07OI`n7 znNvpd#Ka?>ZyM9#j&xvFWCSu8LoZ8|{3?>AQGMa7guFy4?Ox5W7jvycEpD=8*iDT< zop_&5(yN$54;|dwH!{u8gwg4RMPnq7Eh%eh1qbmlD^0Jqkd*~xTp8ei-}y&;v^qDp zkr&@zLmt}4d>{RfnndoTvqQK%W?$n^$BGiWuSmZi4^M}cZ8dtSF=e~|BnhY){_Orz zTTkzxPd?CO8bM8kRh3FE1#q5s$|RZBS%@1JJ=LN*x3w;PBt@MC#CWnxDjPTM>?A7r z9(c&3(xx7b{V6FJjg*PC`-E%xZUq5#a^H0a76RQ)YK=l1LY>hd8!@>ZWS7@nExI<0 zc>1`{J!Q*q7$TanVveP#DJ$C=E1HLWeTHf!yXiyhHevwrSbacmJqDD2r@LCGs5y

gQIO6GMCVnH-@|^da(pk}BzW6NPWp}Np-REneL70}3 z*LhX|u&otJm$Jrng_^9f)&HyUD{L)8ZbX0FF@M@Z4HdNBzN3NFzrcUfRyEM`fB&taMZUR5g6HhX}c zbAV>i{QJ04Wb2y=O?K=bbHn1tw<4Z*C!J@VbT9=8pfU9PEl|bwByCKa=JMIdA;+Aw*^PzA zEhvj_=m5%VLp~dQmlAV3NOg5b5#L%QZRO>tX{m`!TaU}i zm-*|SVdMZa9X`gljj-~;wYU**%pBC4><`Ln3rlpPVhpm^_pFc3{eF;4@Tz(hw z;ou_?Z#3R(U^{VVT<+XE(m9)yrr{{@tkFERm|~}|XSxvcNU@9(=aeSa<%2I|OTH@f zIjbAKPS$@-X^ntuN9`Xt4!T@0RSp{7ltb-|MpcIGR~TqdsYR4h!U*!SzbGvgxW-y% ziBx3*4+6hte8St9Y2&v#cV>jyV+aI#czt~zh4z7H>2s4S>wBxTBF>gMqhp5vKpMy@ zC>m^0*KmehFE4A0o+BWIXKj!-eSyppSLD5$;l+K2@0w11{vqI(TvD~f_Z1-a-;k2V zf~3BN@s-LIuU~53+~XfI^7$mycGQPm5|=Pc@ZQn+VR%Q&|3od`(PQ;ZV2X6pgPkmI zG?|AE+qgbWIM>A{kjnI)20q*%OIvH&{U7&_5Y@8_%p$=mr~7`G&skXZqmC)rf{ayIEX?GX ztTJiUn$u&n9;P2Bu{r~YF;9N8#wW^DTeR-K&Zt;kHSDiGcEO)f~?RW+3tPQyp zHJApXX6Ys*5yrPYL>(X2nvn8G8euz?9F>1Pf$tC?h)-2(c;;>meX4rZww1tu8p-nX z(BAhR5|y1342bV5TeBmQ?Wp=BzNBAFF!M8(O%bif08UN<%)x^FE<)j`KOP>r*(iI8 zWw8!7shrN$GBM5ij#-}SO&Y{L-66NzebjXVI;A(WQN2nAl?f0_DmTQAcYP$FN#q0@ z6mYcoH>vWQK$c_N5i)G#AtbU7W z;lE~)4tg~17Q)9^`0=*XsCP@>KbWpiHzKJ-yLV{uiYEgwhZ7mSBn&#;BKE z#-V}70$9q_sSXipjQw0Kx;*mH$dK3xdqyQT%`BZ=86W$M7PVWyg*kt+XMVvbr|Mp1 z(ulaq-R3)JqN{(kj%rr^J*s1^{@}@nCSRo=#@@b8&8=$?!^Z^B`qEjc|TGN zwnY)Quhk6Ds413oWe0Y6=sYpgIZoShyt77t}s+w?< zpevwrUHwLgyI!$t~(Tc^hbio{reRTGI=VT;k#?5EGF#f_B$K(21 z(XEbZ=qLz@A1%cy#&$ogD@-&^O0U5)Uw?y*yKL^@R$0^7c4Q(+4uc3NLFl4f6H3T2 zcSWmZRQFp;pBkb3qH!2;$ag_LQ=*|Dve*4iggO9ThK=+}%=M8(uqX^u&-K9GWVXh9 zqv(EAdq>Rd;Qh3>XW(b44@@3!=`!Of*txR0)g{k)C?j8k2AwdTW4aBY-(-a!kqAx`b>@2^B}P-VEoveJjV?PY;7dLYSYT!u%(%TUn`*OkDiW~| zG7cob**GOfj!{ux=ym7sEG;FR5E#`zG-l)-d$uGePX8mQtz=;Q7Fwc!Jxn=N-5)Yh zA&yS&Z}PI4qwlx#;M&m=FKPVS$;E06bq%ncK)d-B&1k0`{#Ztte9k7hRj+7pVvUJA z8-@~c%{$jTok;oQtE)Vbay2n4SA5Rky&uD!)cmk+G04yhQzJ=&E<^3?()$C^eK^l%_c6> zSj%!a8iZSm(Z5VoX_rc*=g0XnhzoZGVm5gG`b5Gkic-Q5VbR@J5G{yZ8ELm9kkzZV zMcD!ZUo@6iz^>Q0B|{84j{ufWtm>MAL2s@+4nLpsUwhcP3r`2Y{&%1G=$|aZ`yzUF z$I7nHrS-4PMxYBCwev~0;+Y6Nhr@?SDffki-0a}I{G@RQ1{sssFOy+^_gUW*fC~$* z0ed`a-Y_hIyL$IKA5hac1inutsl^KMr9VA8092odVSX-D5f6z2;dwX#&*o_0r}_SszGwkRfu!)JfP>KTP+ zt2k4oht#5dGxu>dat^W0-XZExTuyuNiu80ODM5B6aVGB(WEvU%a4u9utgJA)(8oiKC}+kRT`T=SXDRvhUUxUEQT8H z>89ys)A0xGznBzjOAVPHX+0~6wM)+uxUTM~609)@^dd(@r+<&iEHv=iDy}IEUA5-s zNbo)eX|i1MUgl>U`o(IMkchHPo4msLRe4$JxU7odV}&pdH$K(rP|u7fij#NLJfM$8 zB_#h!6Zx~HwPP(SKW?MpGn0Ou;w`V{9_V!w`HHZ?y1P#U)waD5LgMWrx!E{#G^4kW z>(TS0gGC;q7YAgZaC)^Z(W?4;bSi3A&%|k(w4H&a{2U2wzKh}xtX-k%@zUQp=RL7^ zOQ^Z~Q&qKKX{bS`WDE~yb9$Ot1r9lkj?mS;$33$yG5_Z{*`=0NN>bRA-SfVEr{gaY zc5@jWa5El_ngb<92Oe`hFe%In<@Vx_(R=PoK2Kso4Uyb2a z(FG$8i!hb(4n4P*oRV1t){r%V8NsfX0gRyWiL9j>?o&&-Y-hmmJ_9EcF_rGE?63F% z@zz^Isd&Cz93C|$L5^D*S3K_9;iIYAySl@d2lJ`|I>7F5h!IcW$86L?tj#`Xscr^% z5xq)*@EDNvXsgCDZH?MNeum}N9AJ?tz?u7QA^`&>`=+~Ln1MTaC(b!BG|VU$|;SC#f(*J=Oh{7>-F zob@%<7+xIrAO3H`z`7asQ;b#IPx^P?3#b0(#wuA9XU4B#DTLJHUgZ({&`(}$vZO*k z^}1nHn_uo?TYeBg&V1t*@aMY^4kbO)`*1#wQQ&avTUE_UZ*VqS1eH|GLw{L*#U8fp zADlt*nn`?uaYWQ8T5a7yVJRuLR)IGnzwHjHe0IDEQlyOTX{Z3B09CERLOSN%%SNGyKn7 z*ptc|q4t-CCh^ufY02uSTt40mMJXvHw#L1T;d0Of&u2!cQD?bPer$$UpLdYk$nULi zGl!FxERxwY_Ps*DPYvRBOdQUMEK16Y-Hm^o-u9L&B!sITOk_Ukn-j132Jmfu7Lj0u z6GiN9L}G$na2ys*d^w{d+?O}!57F(|`6(ah&T}G|+T%Xy#OyV^_DfbHa;LJVW_;#3 zjbfP(Bj*|8?oUVTy|hgSvK*)q$XVAD@H;X#Gk(qb(hr~&%(qB6#o}7kv z^anHZ?|_veZk=~^m>c1-MveB|upshz*i}RFv)s;0YTX2xxWx+NS$YDkh34)a|Fp%CWxHJIE_WzfL$4?G{1{pDi#gEtyOaeSYWfxgV9QzTxPQI z7M!u4G8xb}HoR&L&2yE%2;xKdAZQgW3xg9G7=4zg)TulFV}+ddYEkx!P*t*$r@S)U zGdkJ{i|OFCRJS_hbuRNK@@L$uOw;V^*edrRY9;y3Jb`ip@h z&2I2+#4!i1q)XrI;lS#cmQX^1}_f*8s?6efc*Nr)?(dNz}j_a2?*ZG>9jy$O# z+YSqq{Yjmo@g`yKq44;Dce$?fN3qj}wc@nZwZp$Y`Hx=6=g&M0hFWv-+avyqk$D^o zlrSPZy{KTlT~o$boGBm3Wo;u)9eZu8;$ONY778XwAO&`s-n&!fX&R+=L`&O|2dO0% zgUd+$UYdrK*R%_k^lD|j2 zU_s|~SJ6MY(m&;0>~X==1oVI2{jrDXI>$5Ke%dc2@uk|)5iEEo5RtGe5aMU#`b{NN zXiyZn!YB%l{>UTMAg>webrUu~c`BeDvNHc$sU%eH4Suiw0*am#jAnPEs^+5UZ;2SX zh3VL?mQwh=)tqQ9-_~j*tE!`xS2=Gu4&50Lw0icCgV*vUIz;!|plZBm8Y-W+#&lVoc+_L~lsRjjC!4NSb7tYp?c&MIqFWX37ZihgNBR?mA8Q+yqO8|2@n zX!$H`Z9P)FF~E8b%}b??j2Pz6qR5XM6m^v2_p3S9a+5GWkZM zcwR+ll6w`Glx;-r zP>1sXp`S0VJ%?4wdy3H24X(GZ=F8KVn1kE*%Opj^zv+t2on-ZDZnziovU8nKP%KMKwNUqjZf#PoGe$%x~Rlkz7!X0iD2m1|rp z0kh0Oi=jX@Z9hLsEJ-#}=TL$?{AvrS=^IO5;|Sm-q4wJe;+6NhJ{oOrTve-7)_Qd| z6W9WlujZfzl!~gGX>&J`elwtm9L4$J7)XSnz}io|EQ2Ha4&g?odAm<>KkY>+)ajH! zJ}YOb`eAg8%D;sfC<~{BU+Aap<~IJevVIL!N?>DyWS|E3XHf5YXpHoD2A#s0%D&2e z%09~E>IAa@nL2N$%B&lP7I#mY1#VOgZlBQ;pVp`wJh2y<9io-uFQrP-9PUvj0I`TQ zynik93IDQuXqQu@c%*jOGN|f$E^Hvr2!J`dD<6QLx|kKWkus}TqxqCaZl6WE3@w*5 zm%K7-Crfl*v6TP*yWe#?ojDi;f8C{#=^1!htnY7XNI^1Qb#`+fwKu8 z6B6=pcrOR#+}7t7~DHx}`hXn}u%v=F68BbpI`L+DbTGGkjc@ zs0S4!Mb`}OXJ5`G%f9-s93ebEt32Mr4LMkA8x_)@c}7b>$G&ga8F$s4(sZ^6y{>gw z#Vgqe=G>b0taGXNQnZ7Sg{z6`HOnzwZh3WkwRczsw??uIj2tyx&x&|i>STwK}~`kAHCvC%r(3Xs>;?W74%1+b|6|q^C+nMqz|xT+*b{dYe#Hb#csz^iR9(8r zt*ND@a~<3Nu~1TcNq_V7ZiQ!n$A83aLIU+V+xIa3`u>dT!PVyxDVH#B2KhESRa;~K z;JRh28?mg{w6tNKEugLWDs0=^MV@5D$=%H5 zK78YRB3W%?H4tV3KP;KHj=aAdjJ>RBpRhm2MtDP4$-nR}rA_kzXNY+HLZToSkdcT+ zV7Y9zSOW!*9j9LSK~t=wQq5=X2^@_>Jot^d+li>Jb)DwOsPJr4loa{HZ`8}@15_`Y zo{y1QKDYtLt;((xD1GuXBm+A#L_L0p*gK+g(L~qcq}77vD6SmLEtdYyRY^4Rk5%B2iy6kWd%5rZ=-v zwwm?6O#A+)3=X%PP36^AKfgA>dNhw zcNQZ_@q|PUPKOiOtQ{w{0_TR9`_uS zpXy;Q-%Fskfkdg!I%ckEk5)aUmkKTY|39w2IxNbs-C89TB~`jhBqXGUQba;ZL_xZxha5Tt zln@xYOIoBmhwd1<2Zo-ZW{6>E_&D!*f9JgC`|G)`=g;Tad*AC`d);eUhAOwzjNTWG z+j-3R)`q|+b42;*>YnCdvH1Jb4ONe|G|{Z&JmI|D<(x0Ss|YpQjI-6gg%*41-Wo4; z+LBt(?#y~{w1;Md;XHWw9I*Rmknn-h`XIVSeXu%;%(piV|G*9|P2e7})bZ*(1$=>_ zcUyFGHS(D1B$iO(`DS5h8U8WUMLV^;ERl<`-uo`Hb+-GI{Ig`D3H2UFiEEllGGP#r zIO;M&x|Ia=+JrW<;+I;|VE7h7fAE;z=#|u|3ab4nDHy%-+%H1%AnSGTO)LHFP z%H7}viOiK_qvNWqIL`Phk{?2j zykPm-1flD?6;g2d!9?UH@uzB_9%`hp;5^6(@EjEAHf4U z{EH{bJvcJ8KRP}i@fQdx9>@!N`Z%K@>gVe{wkp=*L<3kMl_+IqhrNX!$H``0>7PVW zg&3s8&0YGsTF_s_=UEXOoe0C-DM#&&T^{%0!hS_V0{aF2g`gNhp-jHbp0>@&vS)?N zXk@;srtGv5U=do$y= zOps|$5}dESSkW0l#D zICiL`{9lNg(uMMcET9)kOs`5E`R+O9XKA@(gbkptmf%`oV6t>#UTj-g zR@ahoBUy0$?ZxZ92&^Yo$~$^OjU9x@m89Ts+9!Sm-b8A}S<>h3Czgs!)Kv)j+P8d= zQC{8bQ%wZ$9YvSmUh2@cL?=0#5JDD`4 zKj1>TcLz?3=g-_?#9g-Z8+SXGHf$(7rKsddP!)eKZz$5daCCg?km0=G zD@lA#Pi%Y2>l>HvU);B4NhdQXtk05hSx9=#D5$Y2aAmW_+x7n+0Sdo$HJ3M;Fl+Ar zp-{+YZhsUonH>!YNYq6}P?0CHcsm*&WK!7u z*dcsoWkRAj7;o`H)3sA9*;yGD`$lGnUO87RCMj8*jOpYlldb-)pi@`~6-r6@yfJbz z+6xE$tMvZb>Pz#;f|&sGN(&__@^jmy(GCf-ecO zY<|~LO@&Vhg?apeP9N$dpg-{rBA*ukB3A$dn>*e5OWpJCB=a!NI>AmpO}>(zHBty! z$_15qXkFP%n1xwBjo?(#4DV*PlrEy<-gXg?Uri^J+q0A*MI}2MvTdE&4+OmnL?*FY z1>KtDmN$vMYXj6?9Nh4#l|)V5=jONfeWQfsBpUi@|&Q#I)MoI}5FB}mn2z1XUE$hgysiG2#- zyqkFY4uI)0MBYfYJ-H2aB)0gUkS?G+E)w2LORL?wnJ^1K`#I`!G2ktO$tFpNlDV+* zj6Ci@kdE6=m|on!cdHgpMj|{7uy%_yxTT z-Cq29a=c)vYX%kc%J*btnDPNl>SU>iO6oYp`#ctEZp8oyE2JF!O z`N{$RAw2M7B&@JFlL>r%LAChsmSz0*Y?W=qn6-A2j)UQ`h%V%A7(xsXX`2d!y_`Qw zU93_6B1;++|LtYOXFk6u{aEWML5lj}}b6=r>3Z$Qy8(2p<32D}&qI6pYlFZ=%GO$9g~Iyl6OjZK+;J6^lym z>3_My-e24Fx0Z(blx;XR_)F{Jitr{(?sZCF&%?6W`59lR_zBfS>Z}IY*^xQ#joQ5kXuEr8q-$bSkov+Mw|7)}iTD)Us?h+LG*N zg`x$hZ+fFP34_V zcss|}$sIQO%yT@;gFN6 zuz_c*@@s81@63jr*DBm%_;b zR`nfxVcP&)9H1>QWMh%0yg4k$(>IlICwQBwF`WJq>ykoB-Wf1r|@19OCb1UORrlN@t z{MIi_dv=Yl1c1k)s3+P_)OdL+`FRFve;PNF2~@?;rgv+)T-3Mdrn?D4JFY*Sv-h{% zYSJ=Y_|ezZko-QO4-0Zq4NAOF%Bgp@P*$N>LD$7JJuk>sJJQkD{}T5MNhQo~bvobs z$$vniz6LWaAL$d$tCjCkw~htXf#3~VBK!!xrfAmIjXr7fC@zhfZ3j;og z=qk+Q9~Q5wKRy;9l=4t)GS~@!I{r>jqWA4a)5$ls$MWwdwK8IYG&HNeY`Ywlv#~Jz zF znw`87xB5!#4=%VS<9o?iwH3n#s2=wu{{4_V^!KNx6sYc}?(FyYs<-EH8FAzhqMb84 z*gNgU#7sIU^9*Ev|2>uLAfYIpC;Cfa^aB+L3JKX7d@ z$aG^ifVXC}IftvAK3Z=hy}P^1JX}~Jxk#(!G5rNOMl_XRnaDjkAUL7}F2P^7(MySL z+Z<7t=xBIHd$6otA=|#n&+sN*gs#M<<;Uc*F3p6L!a){wl(v6{_xIg@B0Yg3cb5%& z(rE9^1a0ZF`BB5GWux1J^29y{?-KpHi3Fd+@bdBeR|#J@oaW&pmJ!rQZ^7?O8mwCM z6my%4wBq3({IimfK|6V6pWMEIB@8qSF4YLsK^W$T@I*T4%QbMwb0UgSTF zPYIu1EcU=Meo~2|Dt|Eq`n-k@Hke52@KT~6&9K|{cNU(Y+C84S!tz^%BL6fTllj z0=i!A$D1@bB<~;~t0CnD0ws|;KES4$3hdr=Ln$y}TAH_P)PcxfWC2@R4q13`8zg;$P#bXt-Mqhs8W98X=5-jBiNb zLb^(`%>R;|xR>+sS0F3zVbZguv)Snen#{k4N;-oay#a3rE551xddo*mZN_vmY{nnU z9+g)f^S8w2>Jyx*9Xq5vxBrb~$Q%g{r|4v1VczS{NDgs*p9kU(_8YpMfDT3-jt%>AW$rpZ_S zhbL8ykS{ZLDJYtS>hVGds7b$`W%22*m2(%r=(yOUt#KTK=Txf|u7NeuVoy?Gih{qq zdy1SL60$&_Pks2Kzcsr#t(mEQsKYLxdbOgZ>iRu2yIN+vf_W7_4AimeBu;vJ-Glrzi@olO2GLE>7Q$E~oYFxfvjQ5gBc(%R_JT*nY8C>&(320&?g5+@0YX!&lUwz0T$P z#AzSXO&syujf1mPqsH1cPc^OcAx$429jiT{-Ac2D%kJqzyFzjc)rc1w6a+D;@56H5 zE3u&uo}giH^gKe}kVuI~qfX_+u6`@r8!GMn^->&hIkQ%c)lCC86iyoH`(kH~s8RRb zR5Ezf`WHLBU&`-mkaWGJTUYrFA<`r_P{0q6(y+nC^pLk8h_js9V>d`vCN@TdI0b>D zrr}p=nXj6;lgfWah+H?dB}u%I6l)!$C+(P}+Z-7H-oC^2T9ye8?J{-*b2EcnYrKsR z_p7V;!JtFyK%EJ~GY%n;ynI%;dzAR~nPj(v$W}f6oaCR|eh=vziYt!u`a$UK3*1Km zvcE|^!kE8jX7VO+`X5wh`5rk)T_IUdTW$kRL1<3ZOH1j~hjwk%z}^p{(+yY?1zcg9 z$e#`i5)03FqL=SOPoiUb1oy2<+n@bf`l(Mquwjs0UOoB64##9d#QLIS{^0`t&Zm+Zh`u~GG-=KdNKR(jl|&RuSFr!GnwXQ zPchOn9L`?wr@ITKgU;Y%?}5&`O0$dXk@%pEw0A~OIo>U&GaBfk0jzi2+Z8H0Ld+6FyFbV>D5?=8>{Nuo2hly8hSNe(?_ z!f$}9mkGz`R~@dOW&ZUU|NS*z;QHy|(ga@acnpJ+7ck_mpaW7cMfD zqI%zAy~_L3hQ+ls=4JV{=&{3AByCJeApuclZTQu1n`fokpZ%?KtKQ z{I=#%+l7(xJ53Tme@}OxLsQW<*9alkh;?6TI}$}5`;8j#hbS>FCw#Ajo`+6b>sBpl z-NJ#BhuzjTFYPz;enMSIGV&SLNGfIzf$lEcw-SHPP>^kWVlc+j%wJ{pZkmeed zC8Iz2Tsu6q$z0ZW%0KSnDWEt-QoSL7hST z*AS@5ZCI&UmxmB#^r3riQn&-0WY-J%g0fH~346J9x#~g>Ud=oSc2}ZacP$+5I(5Y* zL+AT0w2fwhgKg4wP2j*%#Uq8>smyy;ijPgBlDg6w>SwhU!& zrXafeqwjI90Egl-@Pq91P-!U&$|w>gCGXIzz|-$dybCRnxq2OUtWdp%<0^j0xLZt$ zgXXj@{N2<<;;K&pbbQ8B9###p*w@+a{;kq@X}NYhS+ufx>=?1~dS_XAh;e`GIO@|( zZmP{mF6qBk=n8w_y{6s7p`=&0Az5croVU9K3_iwJHw27((%3VF=EByqG^DsIjhCmS zrf2l#k7IVCo*c%C4lF95i!392Ih=3aSlcY5p|CM#Be94RM5?f!^KME)W4p3^ED1?_ z0$MPmXfU44?3457d>0{-RQJeBWIntiWU9+82j#LG`U1mw z!64RqY~Lo`W}=_I2_HBwbgB0H_m=+m!)J-`HTUi=Q0vKmo&z2xgl{%hAp4nnGNs@=O~g9!)k^VkiH#s zZoEPbc-)?HH7GmeXw*Ah9hSbMD&QmTDD6%)XE5K0cggT0H--JQqNB_Ai<2gocNvsq z1602{Pmgi+8ns;dnZ~z@&;xODa_)tA;+Y<_G+!Iz=O~ayRg0yvBOTj9_-p)SP^w&v zg_EE9$-W>`X7eUL`J;~UPH$~yqi#GFpv{x{p#ey^44lR|?mrzk+?Uyt~Dl_*a z9#Y#p-|Y{Ram5d2cG@;pO(4swzS$S6U(DHjUL(sgeX9zCKDDC zlX~6;1;DwEufO?Jy69&W&3R5<7Nm(@EZ)WIwEn)wJ#J63>%G zn>ERdBDxlCg<_)LpFIy~D`T6-~90!bzSf>hI)_}kSQ^_}~D1fZ)37@vVo${MbfsgEREliz*9 z)?jf{bf6Qiz=EH!>|V+kG&JS(V+Lv~b5(FrpIhDs^G{%ZE#p)nb{22H^A8TNX8sQS zm;k%P2pQe%IzZ6&aQ|BgG+G)nrqC26bvS_9+i3jOwbGrDGg~vF;)2qx$WXJz#Ji;e zjGDuAD=l+`1SY10`J#n}hQYS1wUJfJw!3qRUEtLv7Z}^8N}m@KJtYJDJt8U9@CE?6 zsLP}ijnRS$^8BHf?N03iEd-GxPw8*NXcJge9{t)&cTs?d#k$Zit9p*NDTRB}ISPbs zein`0NN!yWRM@9op!pUxtc<~U^a>m%(m7w??ScB zNa%z(w|eOe8mKbVeMv?gB&Vjkd`EkXEAWDw3@;lG0Yp^W{YSfQc>DWZQGH{97!&LtR1|9`a2EP#>Gok`c|NY;$ew3u&kulbRRf7l`xY31INWkk@B^$d> zm#v2_mQ@9Qh{>q)6XIjgtP#(166Qtsy_sDZ9MLmTwq6!4DW$1x$uCSwP1KB&^)6(b zCEI!IPblM+J!p!WH$#G9GgHZVWv>^$Rk>ts>R@9f+lxf~=1Z5JT3+BQTs#+ykrHa2 z&QBv37t$Hi{S@=IUMx+Uv_gI-)meAmb-|h3dFBO2*r%}8$UN@Qo#>~X57pL#3wZL? z0E8EX6WNmyh`II({2_xNlnFL#yd(jInl&9lL z)7zQnAK7*ur!Po0C|$xVQ%xms8zmmRXa0RYD0!8rp>_)%@;~U0(d@I2)BH$93xiSk zSZ0Cmi#Q2}b1&(uuYyZh1nq=Yc!K>SInbPG9n_?a!ItgFS>=o%HtFh-=B>*+=Oglw zUityd-Ecch-HWoXX(_M<%^43l5(jJOK!wN8T8g>hyjw+G%-7$bH?3SD;|R+uL$aQF z$skFYkb}N#wbU6_KhangN=M4$b)Ynbp24G)b~H^J9wD6N;yH|#5ZGo?>rzT*n5Oi` zu16*0O&pGOLY(-ng%ucsmDcftfUB!yGC0LVyE~JT-4BxPl5Deb?#}-yjsJ$22juVW z`O5SOT;uFn-VmX^4+8EehE)>Ke|aIEb{9IPSO2#CdDFoj5$8dc(Por0ImSx!R8O;T zbX?mzW9%>99x>V^+*+`x#4Q(31BQG5Qdal&}41@GN|B z3Dj5Iw7za8r>V{=<3g77ZS?dw7hNtbh;H?{OEU97-aBomgt_bo-(^W5U!9%S1t4mK zzg#lDUzXCbzcCuT3zYo7JJ{iAfb(zvTtcnO|9$VF!FSEy%X* zZHzL+v!@Omd$BF14f=HCpcsW>lWo}kEM$r=s2XcOEDe<(MNUl>Nd)@9RtFfWNse(X zFNAY~dRnQM8lzC}9H~Jmt0xJU zSTKKr+%pwcUpGJ$=xqBS*yJ-`R6nn0=&?S_XjdQqL`Pq(^~Cx{VyK1WfV!TSgMtKL zMP`Vd7!)Y7{3}{30e`y38OOqFa z-{U_(9l`d(MdXu}VKf<~LSI|(RYKz7Pr5Hua_F4u;kkgh9uZ@x2)rbst@mcN{(ZtWGP-+qzP zB^PxGB)QDEw4)n36zU^fIa_Oo`PNfUwEpS1EQrg5<5-Z&^ukg=?ai3UDk_gnA;FV2 zsu#+vX_Ex@zLr-Rm67W;*V^?<*=i0CT~k%hmzdw-axJKzy-BWS>Z#eO-Zse@FKl@g zJ1Yctpqsrp&PZ{TnPcswqmFEG(WPLyxBemogB2GFP_&j&Qm4IIRPl^Y$wC(%sfKl( z_Sd3$M?cTo)293MQT6Q;?FH-;`h9EqdQ~5BY)3N__3w3*^z^}1iNQ zi@CW(TRI#QG=(sDH+Z84H&GG3jT$6*?3R}#pJzT(Hp$~Q*><@}$*1?Ba#c!KvcGI& zxp$Ou`$t%EQ5nYJJzQ!bN(NBpFO+;X;lDGi5Hl>cs7fXZ%Vw{qCzBWN6HM}jIV&xY zIZ_#@$|q)&IlCgC!KH=k^o{WXFQYH+dipMN{ZD=;O*>>#cSZ$ZCs2mc6z5+2R64>+ zZ{d%6QR-7vm~6ewLW-yLnyDsAx34EpaZD9dKtz*bq95()=l7xeD%GiXY1Q?9AZ)fm z=!>M=n;O6oRW08f-@Q3w3M&Gb>#FJLFYTpq$m$aZME8g-LyY4iNE;P$C^pB z{37?6$N{Lak49h;WQjcMf{cm69v=2e(f6YUd=v?)dwv2RJpA*{H6YFr$J%;fL^J(I z@z5wJiO=8zBkj>=L#87_o2RkhOpr}*@Ko5tz88%jT)knC{-k84hW5k-{iX>fCX2df zC)5foUz{f}NWdEC&7=Tb{B)z9KK9U+z)~380FUP7p;FKhAoT#TxUM8 zlZtmD;etdRr#P2UJcHH?M|@Ss6^58cc>y%MEYgck_+Fg|D?1?lihnLJ1M*FFD{fFh+WgEXC-HrVPZ)Xd$ zjttSiXt4pNcKE44O3CI=35}A*tl%sa${fqNJA2_7{Nh+a`|t5! z82Bbpj;?Qlvn`&h+o8IO>yT^*gKQaw9Ui6@S3R`QWj~p&_ie!nM>U2 z;WM{%I4IF93fWd&a)+QKnzbo>{U%jK-HTuv z>N5B{dbHkX6>TmQg3ZiYJ)ooZOZA1`axWlwsZrDJ|4WG7ZPs@5;|Ixwp#R%WUl}r2 z7@^v{CGNP7Lx;H6i!oY0OcSmRNM$>r?E zzHZW5a|E^SsX0E)bn>m!bE|LLt3%c4IdD{IO?(vmLLSd};Ak7FnlUfffMYV7UeS;Y za+Mb$l(J#l7X@jmo5o79S-d?A@6AtcVg}MGS!Id;+09Jr@(Ceir;kWff_(E4>(A@o z_#m3klYLyJmfq2Cn&ONI*MKD9&;?ro&-GaIL9r6`@`?*3CvkPxbJSUNT(lQEn`(d6 z`}PF*AMnIL6?wRLh+SEC(;fPpBrji2NZ&Y>`O0(cT4?Y^W&2$y4lorLsTr^_zXkeB z6RBVL#cLBl)G)@K&7DP~swsQg=VfMbt?b603jn9L-wMrO1eWz{Lw#=6$~ygq%?PPV z9?)LW%`x#-3ioH*EDA?Wuw=Cxw;6643WV2|@|zi1y-k&SgmLblb~6-KbBK2iQ=k&oH^YK~1+W zBa$+#I=Z7p`Ogn;`9ZpZz8W7Gn3g%hOse0)LKwZy*7VTL<(K^gj3~e3BF_0=2p(*z z*IPu97f11*soi0X5X_xDMU{l7DVR&^W{U{+~$SO`WdaI zQt2;kf3s@tAj3OXK*kBtVjX6Ep|nG7;JMfum}eoXF5EZU{*3`ipH&lo(s*@skEGx> zp|*%UiN!H2=xTi+HfWmk5`Q|CS3Bo2@vC8LWpk0)g}1i+ zsdPq2!`meX)D~qZOhyN!U{?3indv!rfzwfB5pQu(oSvS}wI1&0eQE$dF<44NUHdK> zxGzl`Gs6U>^z3w%@+%-Sk6Z>qF%+U z8%Y2FUg|IZ2R!^6L%^TmzI<@)jyJPY^S}M&qk!@!0pq3{%gAzAnU?=k**!$|Wq;!` zp;WH#lBl4Zb<6igmkgh{KSR<>UtO7z2Mw_k;-^cyo)Maka=HU4m%7kUSC9Axxfid&~}Huecay&#pwP@qx8Bh|OFj7ZF#m;Iy9=RV2m!xLN`5Q@pSU zJU5)-{UpXG0MEN*{UgW-M6x^Q4n4O4BIKRxem+_jxCnXGn@};ut9%;vCsxiato;Ns ztT}$TU(HK8cE0>lnNNbwKK(AW{8&qv7kikloVQ@+Boo3woqI{UwWOM zVLiB+{xGbh&VE0|TG1gZ<&&f^o=ImKG1S>T=+FsPm-Td6{$P zMUoDVkGq}sHMN&o2$z|hpLz*h3Hw}}nwD%P0x6wGemiqAe=bX{gOVkyh8Q-wH8#uQ zV`yFsZxWpaleL zeOtWAN~*Z4$8aP`wen-Mt1z%@9x8p|WoSv9i}Jgpnj*8{e3;}b0X|iD^(v)%=RB#3|*75ZTsE|puAqp zqc)8Ps2jE~IaWVTfsD7a&sqCorqQ>rvw(daMz3955XD1dexJeM(-$IDUlq8Jz1pCu z%NXO|?F&Bygm_5gRXiu{6MVJSFD6Ld-R9r?b@vMgNpU_!s`c%R(_14(3WAFMc8|2? zuMzu}FbKO0GaxXjd;EOQT{HRaeJmI`7bkirI#*>LmaRHWNxwChsG?vsmg_UNTaAae zpkkhyBGkuvvG5zNYE~_9#Gv=~^3CO^q0LY!s6*4{r_+q`YcOir8@-RZyM{&;geT>c zr}TjIdOVwwq3_)@y?svHA6*`GXh{2zfE?@!Gjdz&p`;)nB)d$c%W>KNR@nUPRj8y4 zZSP<7|Mr6aMfSkyaZ`IvnA(PFC%!OQT`^mb@HRGQimAnwzAt-makRQRe3M+t3avmni=akUuC!`zE4kKX0b-p zd+20(UsG{$P9s7IH{HtfM>pKkQ&_j=Sq7P79hej?g5TbUK6^0N_%ggzCB?3Hq*l(2 z(82aoVIL<#wEyqpE&)kxC8ME9b$_@^RQAn5x@wP&ms@#hoQT#Je&WetZiP=fi1}4X z`OlS@%y4Ew0&dNyGDk;cj#I&QJ8vUrz-YS{oxY&uMer5$EuKX+I7F@qWW}qH;r?;H zg^{|*)|1Mn;iB}%8ilPx1NFc z#T{6uNB?Q>9zD1k$;xzq-nMJEUcp{T-psvo@VNAK*j+v@J9W*vy+W9=S}VVo`7K#z zrz#}Dw)>DHR3r);N1)3JswvNbzX)H(FaUbY#zFZXElx~fpzsZOsgyRZ$;nKE><+N>N<+}FfuI zba8AEGAE|&Dy=UDs%WKn8@jl=`yAuZZ7WntoTBK}Au9y9?yYMHOYSfi?bD{&w$^3@ zN}Kb`F(cJXEQ-F0@^tY@#W)LgtF$u-I7nC+-NVzqwM(nH?IKcz}W z7UF(1g7f#^S5^O}QCHFe-VlYKeT(>P_WvQpI>I**+dSU1atmo;O`bTf*KZ%FpG(DB z$v7nbh^(OhtZ0VL@5qA7Q}4Jr0ud zwlJ^`{ZByW5}JCx>#JbvlDBnyEco3+P5r{>-OL|CW^z=(q_Q!8+!5P>0cX_g!4x~) z20I*rDHqv+4or;p5_ENKeiaH^(jK2!doZ@m(OnVibWftz4%|>Z0gvYQ=j>LtO~2oK zyIh-K;mm@xTpq?Z(vQTX`j$j8nW1JFGmFhE8TzM*@I*=@$3DiDSp?7bW!j!nJY%Nh zV@r5B+RF-d$_&yll?QHPKv^G^4(aqcbFwVseCye(GkzUmzmRkFUePnV)Ei0v63EHW zI99r~33<8`T}Luxk0&dZnSFcNSm=P#U{^@<_9oH0?~d%Fo}+w4bvO9o1g3zUIt95f z6F`p-Bi=s~n>jXA`qP!H9>k@Z0=Ig5$zJtlFMLyI)L<7{CY|KIzj7e90U1Y5_LyvO zI_;x_i0=6?K$*#mj8|&MpiDd4OtT}NYRqxaHFCUadPW3N0X9KtffMY9cz0`Bj<}6dYRc$0k{G<>fWI(b`y}) z+&S)wbMW9r3kLdW*iE3+4cI$iN&9Nmja)mz4#5y>Xkp&i%(jY{4@OzH}$VGtksk7we4k^ zsA1&i|6A3BneJ(D2%S@P&!5IZk9pUxQE1JB5A=%#_DM957(1d>4iJ)Ihd-S>Avg0Z zPI5~0*J2XVgbpFrT-f|xwDq;x;7*+8glT4_%*ECtGHE#kLxnku;tB`yt%9ct4xBQV{?e(7FhU+Gr0LY)oGTA%uM;l4cB9K50!^xs6VC z2iH``Y?S@@Q}g1upZ-ud6-|Ao4Y38u)|N3?5pg-M8O}7>4XE z+kZW_i!mao>H=i#`U3E0{Up;j4_d#$-Ev2fu#47B`Q#8EM8;rp{AQ1`3@H?K_)Bx? zMSW?J?z7OhvtrXA!U(6}OGSin^dDiAkx6*q=7ny(Bqt6IG!O?HD<#SHp6^Gaxo;Kc zo8PaVR|COaQf;&mloJbhjF{w+OxZJBj4M z4eBsTdPeGWxEjffg-c5#!9d8fC1E+6T<p?42oy2C~yzZPZ??P_5I zRDXkwthtZX7rS`%F;`ht{q6l2?UuD?cYADk9I};(UUAWOA5sf}mGo@DpQ_*SC#nN$s9YlvXq$yKj94QT07aq`CD<4yieQ|o`Sk}q&u z2MFVFuG1cSJkkD-E!I98bgw(*@iGC^ks)M}=T>sO(Vv%CpYYv)2+2SLsrwmH-lNL> zt4BDPkR|MM800)%ij|qgiLK0vRi~c*?O@qrBW9C}Ef+d9y{*L3>A;fT3|^hAwvC2- zEMaz8QlC_0OZNl3?c)7Fwexv@KwjLOa6t^hZri9eOxi35^fnPV-0qKm!aXQk40Q9nu~1IJ7?{acio_ zqn5Pw5&rl#*X9Cm;aQowu$Jw(9Lb>Q%zkcvAm*I7B!2%q=)!e#j=bq;c7Fvo#W!u<=9b0$qfhl`N(gx9^c8BTZADn_pC+K#39)I+x4(E#`2)AwLXu%6=9@a&_( z1!dOz5Y|Ea2iZ#pR%$>?mM58bq}Sevr?6K`wRnJrj4X7}z7HeWy|reOXvDx(2_JJ- z-xSGC4k7DuAoHng0fqVIr?41?ZwD1d^e1VxXcP5dWuVahGZ({yPV4c}Jp5skOO_zNFyE}I3T7enD& z!7WpHWWG9g^HDBeKD52RJrql}V;yj!IcUL@Yp&hn%F-Cyl5Bc3e~Tt1cKGYY{15W^ zFOd!a9eO=-TRQ583Tsp9J}*6m-$GG0r!9rvM+2kog$PTYUz2qmjgoM8ZMPv{V3a#T zgbj(~w$saytntR0Nj_Czdiwk*Z9`kl!{2i_BXyOYVT}_4u zo$K*h%RJw6TbqnBXy|DqdI5kT5M6O(WBJWKF;X)_8SY9i)$hAcONqmiWZVsFF)X(t z;hRZ;R({suDZCcqe6*y$SBOL=UDT-!hNk{MDHGY1UD)yQ_Q&886|FET#T85duj;szqc_IRIa&1a#@Yeryk84nPgTu(F zd+kV$G&d;U>D}hgKQIk(y#78BU&%Yzw-0-&N4(+A+;xI@66i9ygV3oFZ+z2v zBlLW87J<7p&v}UFe8c%d@~?cq^48HI6>@R+_+HZfJ)YA^Z6j@T z!#-Pe#w9;|*W*1dOHU{+Yw-j9+IWfeF{mG1m!fzzWw+CcZGtgCs;2pB&!uH@XwL!Fa0kJ6IHFMma+$9bPf{&czfLi}ZI9BilRcnWr_uqhe?L{4 zqhvKbaMe8^yRX@P5#bwRw=P{Oot5~vPFyV5lOqs*F66#DSASadrqf|i|M%*#F^#`h z-PbFY)ARR5{|Mpozu)t+`H_1nF$#s=Ojt@Er^uXlkof=cKIkB54!JY5xE!1`LaM2$ zoza$q#|--ULKZA^TDUh}!H z_3d6`P^U`UJcq(%j;PTvM_j47+C`;~F; zPpJFRt?d)1ucLp$nzfHcSmiR#``T~Y!vlc63K+vKxMU&bUFrO53S@D0T@m>RvG51_ z{z=CuvA0Fd<78Z`gL5@GWNbW!x?!eEU0zQtN&8*;HFrZ4*-GXWEeGCv70OFQe8NU6 zVq1Td6RZ9|uD<#&%D(Fs6OaxG=@z9ym>E(UDFLNJq&tS88ziJdLP{E>q`RbRhK_-u zVPI&6&cl1obHAVaJU?B3!1uGSz4uycuVtx_o)*bCra;x_{CeI?zTi#$d2jz46%cqO zs2M0-x>gQZAGhdL%_EOumN)(cSx4!f>Pfm~6}ih=AuKrTK@#u-M|A>|K86z9)?J3Q zd4bn^1mvW%>0-aWCD62=_EGe|>D-|`1I4nq7jkjMQXN!AYs@xIi0vC*1&-TAP*Dhh zbB6acwqNkI0asY6%8>0DZ@H+yS4cND())v*#wu;;e4q0Htv+3Q1SgUoQf+SB$ej$7 zB>JLpowMG17Yv(y$gYRbyKf1cA1YIlY@1(c*3-`(iM^IP3zd65(F}EDw(VHnP5ef~ z@z~?c8~dnjxVp{7y;2zT)lXv+6FbAA3=N8rU(Hww&l`MJHlQ!p811>)*Bqcn!zM%L zgnzc0<#E1b_kwd({6H;F#(ZB9g=~CsOnT^=XeQR8x~Td_Kb_b^Her9JcVdDrGt#~_ z{louCPi0~-{MHDxN~#a;cadUfbd31ffR@j4(1XV8Fo3`%M)XYE?G#n5`@%`P#BXvQ z{)X%CkR-254AGP@ZalW&D6N!rRIZo6bh)KqT(ortlxud}kvCU4eflKm<*%Gw-c@R! zK)9q|qc9K@Dkk9NilQVBmq`}%>h?mt-dK~f#iv2OdIoXqLPu zZzGn@MG@z>=%opS>%3ifx0@lfa?YB|wM%x(PG~69D|*RsO4lm%T*SUqXp%r>*deyL z*4;NQ<2 zRDoyWp$pgCQjaB_B^6iwzj<{jh_cp9TY?ALDZHgO`&B~xraazwux%@}xn->CVf7DO zypC&%2x3|1j*|eeHJ9v2UqBf+Aqn%cbXDw#dVu6SZSu*`mMo72for&0ZkBp4z%d47 zDmp9+tYh?%uNn+T>Eo7RU0SE&`yq;0YGJ-uFZozOe>^xO&cnfpROQzx_%I1*)v7f18!{R=CnJ_#xMzCpq7T|ZB9dhuw z*$cAtCU{3Sp_cwLU<4*}L{Exux4lI$s6HH#Bk0Udg^o#}3K8?lhjW8TQk@JLV_hFm zX9|2cp4Qh72QG5fVBSc5GCo7U{d7lO9^#E+7&)Z6LlTC8nG4}xN2D2dxZ%rPPN8iO z*j~MvS?P7>X&$sRf7*f3=qHRr210x*G;Vj4-%n5&ef(^H2|~|;dzj8dqQDR9S+h*W zwHVSZ$YGChUho;l$lSv=c`W%lj?-|1R9!!ImgznP)0=#5q-@XUoFxY3RApIZ$ zx+nauN&ozPTPTPmFk{)gZy)sCs(z>^bQhxpqE}-vu5@?(m}`Isz%i@iQA>CEG7Ok% zu&^(KK>g*iqrboF6I|}|%(v$uc@b?@Zcv&ZtzUBY@l!Rhc%-;J=N1m4MtSaN?-QQ2 zTToZ84BM(UMzBmJydkX~-8CSUrMecPj6QxXHPIaTt*V}2sFq|;*fY%mlH|#Gy6rIP z_kowXH~XOWc63a3yl*9DFMA{}XwhRQoi6*W!5?!nW=?+cm$UajOL>z#W?^I)E(NMi zS7}6{E4j@EWXrxAa0(N$@zh@5?oDY>v%#!Tws*By%wq?=XJe{Mi!zuRNA+A0_(tG! z1H@Y+r)!>X!$UZbCh!Tr{TvHFZUh zHvx%S4>M?*l~9V`On+eXb`JC?(Gp?4S=@|mim%EEln9wSP4rvq9J#A2YaR49@)lG5Rp^%56iGrnTVY69-Mo2{F(Co3;`)XQK$zAM@`Kv#k57lbUP)o9)IL0yz5jBMM%C7a(`&hAr89qQJSigeM_?b` z@!KH@=Xs79rx35suNZ$OEJU9tbFwRt@Ty#Mi1bTL=AwyKPMr4ZRT>J6;Ott5C&4Ck zIX|!BG(4&|8MT!ua*dzn0MZ}vYZF6ziowqbs-KRsUeEA9FJhoxuWK_)TW7sEKJ1G> znXKm^y6InD+<^A%5al(5@eB-u^ECW@M(V*d&p|EW%qFGPHiZfYO$>-VRB#wry@M_m zJ~g?EqyG12ufZxDtTBsPpp#mJx&M((S2Tn%OpuFNm^yKR;F#*dOCUIq4@Twdz`Wv9 z=xy)h>6jVze#zv@<{(D}$6QkQxl-!JuG#%i+Q=PD)jWc&fh-mDpUvDb80**dr!YD1 zedz}~H{=dF%l&wOt^K@GjxMI_W=xK5N9=Y^6{0GB>yo~{v&Zgt3VD@_>6yW+&i)H2 zIEz<+?Z)kNswq&m=uEmnmd1i_d6JdtHO=9zR0_m-l^~d5m|!f2==v^mt-14CB4>WG z3&l)+QoKF|+)~VUuxZ!lG{{T#`*W$LXnQ6q)p3N^Bb2;36E|1RdfR>fOt=J%=Sjl`==&)) zRa*^AHL*15zH;BBSWan$W*jhjYT`ng9K!XNNIJzcIsVvaKMh5!i){@$xZIEl8;9;y zF)Bt;KB^%~baV8+F3WUX>>4}qXnr*qDriV>8tN&PIwR$G-vH`*{20Xnynip|kiUq2 zLhyL4Is%+6P~8qDS#5$`kVZ_X&Yq%s_IkUmF#Ybvh! z`{Ae@lF(PzCgiQ?o`%1q$x0Na-=akVKEnBGy0-oJV@M7RG5d^aIZ-820_-i$DLH(u zF?X9qoPqatab)ECH|kwT`Gg;Kr|&6BLG052^(Ntlob6l3{y==1E$3a(v-Co>4JMH_ z1%jRDNZ^@WyE|FeTlKxu@kD0 zc!!7zx{j*3T(l`k-()By%_rAEK)1beR?(!^~%RjqOjsY?l^{P-#1CyljT9S}w)2$zF@(z|BPh`eob ztIyd97NlwR>^a$>RmhFb=KEZ6oFS&xPnEH)l6+r-QN#aLPPz|d8JV_)s@b;7*y8Ae zQH<>m6Jb|w)a1zmewF2BMt^%Rt`i%|fdXY*fYwa-mph<;KcLJ57$B2-W06YUK6M{X zu7N~XZ^>RZ#D3|%adEb>R5IA@{rWg}wvZzhe3t@L`niKmbfvgg^x1KupJL6{Z3!$V zFCgst4O0y+xzj6E&fi~isMPEK$2YiN{Ld(uaIY-zC2n&^a$3+9KQEp` z#UE=}`0WS#=3_r)=2KLl!k$WqKKW+)(B<6aUx44}Z12_&J3V>NIfqhWkysmDhl6*< zj0ar`x^A4iF2^y!bg1C1e5s1m7gHAujka{88~%T$F86K{5p7YX1pLri=;xR+2w?Z^ z?YtrJOIzkY>`#pp4zf*pgHDnh*f#3lZ7l&6CEs$h-8Qt6XK_`Dbp8e=s_7gnV28=z zXSTso{ba*{qDw(m+$PT}#WwVi)MGy)$@F*VXCLi<-#Qc>GZzaD`zuA*TMQHMdH;RF zLp^1l(#(VPWQI&-w$hGDcCeXgkE0a?GC6!Ii?&xzysS;Awr@0b_>_*qp;^eY%37h$ z;&KdBCGUqefXHJz&*6z>@kb&bsSop_3)`h5nIslT_Lc1lF}s{dJI|FV8$TvZu7M7U z%}&177?1^hT#}c_%k#DAli82*LW-Q6$!9P01fs{qA?~+aF{g=TRY=MleU>gQ@E+!i)pq zm&atHA&=G9mW>NClCbb~n3@e5LP)eNO6TVRnmPS(`Ez6fg;BR#j+*zcdc-t@uERzB zMTQd7xCU{M_DJu#;DKZE{=5a|6|f#1SI1=)^7S|Q2!51;{BE$!`SUb z_W6_My(_khJ0Me(RE^{p)E}jFfGL|3FT)x0BN#(u{$mz<7NHG=s6_bRU@m%IasUk* zVZ2tk!G2O9+n)%+#)r5}ve5lt?6?;?4T6ucB(?v3WHZ0YF=QfjYVlM()&w@By*6*q znW&#0zcoMjT;(ghK!4n}OZCRo1FmsOF z%qX&4`t>R%=G8a1sMiJY_X=ST39zEj`p)v?XC6Ysklex_gTxDG7J4kByfJ#GphqQO z#9c_3gP9B0+(b2<;@5>IWAh@duyzgx!n8XcPXjJZ+l(~)g<)dbvYkfQ)NNPU58~@p z;H(Kxj(DRdS8?=Y|7KhcpaYn@v;(fsFs()hb}y}Q#^T$vn-;$S+o#gV=e*S;6Aiw}8z`UcGjT5ZQAqqlM6(~(S-WeM}=pBArPjcpS!dtjO18_k+6Xng#!riIhVZsxQoYGDbm3}(U7_SM_Go*5dP!RZ zTH%vn7xj_!WLUcOsyQ@$!`Tb&#&S7lbh|@Iwj)tyeIJpzYX(JsTpe8dB=IwDxtPQ5 zKAQx^#jSud4yh9cjLCNP8VyZ&tQd>^5W+r!Y{VJIrYYI>bu>A8yp=JORgs-d~d$E*mG3+e0GXLb3shoZB~m*B6A4E9q1M-RRvOL9Mk^zX4weSdh0 z#s2dc{|xb8u}-Fs6qQiK{{`~XMPM*zC~d(=YELn|f|dv%VSce$g#PjQ`{=R+{m1Hk zI}2efKLx5{Ym)0&e+_QYUC~#0DG%=WxWx&|T9*k9?W2Amn{b+O5S`yl&Z(EzWj(KFC}xmhc!-@$W8jSIvot3N zAC#8czR8zY%eQq9F^?SvrE#iystGUadQw@x98Yep%dZe!FAUx8{-HY~&f%E8`KP?N zuxnnI!LQ6#Kv1BlDiQ)hXCX1LDtBH-+ELP3ZA38(_2>tp@v2ZKg>-tspEr`~Y2#<$obELG$C?8>HAK7x&mNIst+}liEc)k5 zeLzGQ96Ijy%QTBfO=Q8Ca;003Iowsf-Aa*Y`|1MGXHL2k>|sFc^)<{a-h&Y6i!5|t zt0DxIwF(e#bPZWs4X&i1d45;0mb<_DXnt%JcjkS0SNH9_*%4A8z9mWETyLSEz}CXq zLvYzF&xq{f>(9M{>IUZbmsq^m_m41-U~N?*azna6Nb3s3C{w2neQkk0ZCChtR-vu= zzdcXRzkRL3d_KDUb`B|qOM7H6@Z^C?CAe!})fMU7_o zE=sPaGPzC#LQ{FuD(6=ucSEJ}^K2*j(@t|riA;!)T+5YIp=(a!7@jT;)k%hq(xe@# zkvAF*rf%?3FQLmuvu;t=f1V>QYm?GZtquCwN#gbB+k2YyHfhq5Qq^$O0Sqi1@z zPUrFE>O$SaBF-DP%xkKbY>iCRbmv12vbE4K9H!-Y#&=QiqD1RlztVqMAl$r_Lb(bi z?zUzN_4Rgcc1u_KZlEfiP`&;<^uo6%BqyhlSm2{`%IMd_f1k=~x!G`MREE7r?4hTl zf#N!BfAw)$x15iNiR_-(DP|y{ax@2RXs6#A`+?0Inx@`nX!+K3(fi!(8`r(Y3j(ug zxTElPMjp$z};u1 zSFcdOv5!c=SVe|;#dg<`v752$tO3*VoAsinEO}^sb-h08-U&(tI+q;&cT4dwc@w;1 z(->(UN~fnD90X~6Lsn}<&dIK4ie@_NHCAQw-n$x)J)SAN&88$q)M3#(y$!dCDpTvH zJz+XZKRH}*F%C$;dyfhuZa$fbmd_F#`~tt|Y%C8}s6gFND&F8e7aCl|vbY96cYSwa zo)wOf8-=#BRFl;^ny$1J7C+kve6oWXda~h>7HY>5Qhyc7FfXHtY&N;VB6&BWU&SpP zK{IZ_ojkk#Br}emZ^sdnd$U0efRt$`zBP={y86=cZo`R-|ECVd@dCpxHW^r*um8i) z-6jCA<@FdS)=AXP_~uX%=AA!Z1-nf0v4AweW;4$o7sJm1BLuTcF8Bi~v26kB(ja;BkOd zmdS%O#blw_snmhj!4rhu($)07NsK7m zpjp-$LXFg8Y=R^mBSB53tsuGN+HV@#%&$MBH!q|OD<8B*X?RBZ9y%UKXLf>@>wIy27cU$uVXDnV3B@ifzur`*u4AIk882{XVKv8fG^p2Oe** zm?uV+Xb3R5TvV+_B`m6R#KrLC(KLk#M#nI+fL>)3pmhqlWl#>Kg|pa}O{Si}Jg#~4 zulB@WGhVIb{9UTv=cwCCoCU{^ea6w5vVLB#WAIJQ(sKDTVu(=Y9%IqtjTQK?Zp?Z4 zOF)6CPd4jX6$Z&d!GOqC0PUM%xk=-=PIUTj}UTPJeyr z!monguI1$}zFWNJiVlwYGfxL$%02FR@1f7#@gw5-UP8EfM{6n5mrVWZg|wCYyggA$ z+qj@-NfF#(ux_t@hUc^%b+`JW?MLu44^{7@t0rIJ%&cttYI0elj(uN}Q*OOb2e!}u zO{G!)51i6X_a)ruU-j1^j{WG|IApoms}(NZd7jOjRkLd;2eJ(}rP&}1265Fp`ZU$! zts=@8*p6oLy%bP?616jlJs={Dvz$&6nM4LIm#IUD&6HMl0)i$WzG}E^Zi6P_UyZAz z^~pGqZ(B+3`Ch2Qu6ue(mLfUnI5j-$NrA;d2Fecxd1_qPAFNbwqAMFRuhAr>(evwEpy~31XR^NytVu*>AC9 zV$CbDs`jBOU>;08a_lX~dV@0!WJ`W_J}z*`iFu@a||F7k`@!(v{1pv(~byk zT>F+qc{{?p;o~Uo62330a>VXa;W&u=^?Tb4`>E8&L-bI&(@#1L*!dTiCR8Si^7X)v zk{ZlQ%IKrCXtejHblwOXdOvpexrZ3zU%)EoWyRX{s63$DhizUs3iiZ#!IIw$T5T4s z0r%K%?s&V+skYK;ahDkGBK6&4OX5&R-F%(CFtRT#V7P^I&qJf%PZe!=DRzUV%Uzl^oU*S{r6DsA0I2B5{roC9zRsmVA4V4&; zbJZEqHpz#=&PixX>V~B-}~*vq4zie zN$qg18Nl+KGXlXtcpKO6p2@j!Zp?j;0fB~kof`bBz#bZ0S%5^fY5TiP_3D3lJUkEu z7jK@@pR~2;W_Z(8iV^HHh^>8^^58-bGB8+vLc2d@fD4Bc(8or-p`~usQ%_|T1+I*s zUwWz2NzsqXvR(a1ut7X!yc*9}L@=1X^JrpttHqFFT)gsmdkFYhZ7A%U z`;A3hN?Lu91R4*$le>;W-d2YCpIMSxyglLSavD{|`r^sEI$Olet`V*dWpmJ-}Lb)HqXsOT<*PUl(vF#SPTU?A`JGwpavo(mcn zq_v#{y|I@*KnL&hgp|A&Q=UdzR{Xv#60VI$`SCLCer zwbldvWj#5seVvX@p1n3_V7q@5lVoFYb>YZq*okj?wjnB7HYV0!g^g{Zr@28)vG9K> z=w}T6Tn#^Pf#T>{lbGAB2Q8z-`A+*?38GK@&i#D%$IzB(#>9R`nY}t)ZrUh;-rZ(N z-vZ3DUPJ2(?4w1_1ZC^mnSe>g`W+rJH>#==xZ}!nlU8dn2xcG`xJH|{l4fQ4f8}};^?6pvP3Z{qf8{gNGVJ>-Xv(`fZ|QE| z%^NWU#KB8oU^P56Z{8iPfPaOPauHkNU_)*NubC4scfuiZz$u}=M2|GVtU33!c}E&nlU$h zlq~5u5=fW6zDOljDFi>ANWWJ=HTE^CPyNTT;y>nShn)Xok<#8nYpGoLZ$Vat>=!{{ zPnT+4KhnShLu?5JmG=3u2azMmhWDC$;^?|(&*IO08J`wF|6=a^Y4ERH9k;=@L?MHR z5DruUSZL(>a;nvY1SKXIyX|TPVw_ zv*gJaFRQfEouPmQb}v-R7K;BhIf+($xlnOgXTQ1KEwaT_j9LL^8>Eq>RXqw1d9?l; z|89AGtETe#x-;VtN1y_JsvX@V|ErP9IxL6ume}@YWu}C}RV5#V6};mp<~+^_j`*ot zYR^kPexyDBzRtTYFV5`Y%1{WjA-(UBefF;4Ua9dXF;0!XyPi0KyBtYM=6B#f(dbiy z6h@78avW6JRSP0l90esDyaqvEns@0Z+Jp%#y-(q$FR`Ls^&J2w_KRC&p*gpWlJl(F zy-#)BzI|%hU-2dK=B6>~@bFJq^|wTKb$zi-Y=Syx#XW^EE^Z6OT}vYrtYheBkrOg- zMy1~Ba`t&q?{Zqa=1g3eVTM2sng}A4+L6n$SYRHc#?pqwnK-Oi04x=C?}>wp_?Jv)yP_*34B52 zdhuWQuKg)a#bTO$*)a>MKFasPF4MujQ$uOD@ke2QGuLe8kf0W*9>kn%uLoa^R=Tm= zLV+X(ANu#5%g?i@GynNmC7qN8)^C@~Hw8kv@XXY=ChHC_hD3X5R4-FKPK;b$@(Cw} z&d>(o$1u^*JF;mMRO{}#aHVC0l&M%I@$#Af6ugdfnks2p-0PY=9(XLV^A2YvMCM0n z)>C{tTr(NgoW-b?nL3_oHQQ$oH;3l$oU_warFP?4o?k0ll2aj z9_UZPZ7vm(%>(}F&AAhk=9a%bF|-9?Le+R0`@P^@9NSsx)`UlF^UL&!;Az)Gua4n5 zxOJs?>=bw}y3>%Rtqg{4&p6`6um#=o0^8f0I@M7uC| z4TgNNI~0hYdY{NZv}33p_2ESB;EO%$^O zK4F4|f5}x7xXXXs@pg>db$~S<1V>{qT|;WFUnlx0EbW`T0k)ZsBB$B%T(exXX4h^| z;N<3)2Yugi*X%ocw{WOQ`p9F(Gcjpz7@ycV9jpmB-X9Ah^E}?I;(8E}^$%V1hNhD< zY^c*#VvD`N%LMiJi10XaM|+~oJ@x0^O5nW|@N2wHi~bW5>Gper^0#mi`TrbY7y=$| z)km0?UT#0cYprv)+&?+kS-d-|e-LuGyImevZxNgk3Tfa)f2=W+N3O0;G&lP!gnB1^VO#c{-5MF3c-qPRRBs z#(~3C)Y-4q&NZ~ainp(><*9;!p4yv%!q+f1uw~A!rNbMyjLx_Yuf~dzwF@p>6ACds zva;g0oN3Y)Hc`B^O%suP0zGk19sHEe!L-ZPv-OIUD>~D%U&9zir_`l zb@lZWDtVUR%8nx!o(;j43AA+t$n<2a~$_q|EmV z(!|Cu8uvFZ%NXeE6=_ySGapRZe^^>z!8q5~;R0Er@0+G5=Sjwh{~pB)iybRu_J-qx zq81m~zw!LghuP^0@+Cetdr%yLK>|RZOH~W&`61G(m%yitK6WQccomZxl;_^I_uVp0a&TLIZ=89=nl84hcz&2#?hU8MX(z^+fc5r{s*aIn#lG z#Awwt4<^-k$&&8V%-7+CoIOo4i?(M0Dz@a+z%_u!SjOs4dAq^%_OlRYVS=5MDH*T7 zPtR@k@KFFEi0ynAjgOM4w|cIIYTDsp?6KB}(t=adI_!Gh(2lxH0j z-g8$n3%3`MwLwW-f)t!iu_Ve|nIhtLjJz%Z)C14P4TU@0q)Ax;YZ(;>-O(1i;Q22W zN>*uXBlQtXGp5Xrr9hLk-v)i>-oB$WbkxWN3*lM(xX?zuK0zTsf5nXPVQ25fK^Wj( zhs%$oG`94=I~4ix*e;Xoz406cbU zYbEzV>iFN|Jtn!K^dBvx6&3VVk2=zxL!QhPC(mO2o|~Thxf|i@EZKcjtuSQweFCrB zTK)^AYX9WRU`z1meDYI1@i4+bw-5jlGfP^S=~4M7ZYg62X888k(1fWF;+nAUF0#*@ zm@Gz1GS5OM4oSW~oRbe3q8L^h$*ZWgEyZ1lxBCRgPd^pN>)$Y+g3g)1y?;W2|HRD` zk8_T*7o)=aofljMoOS<-P)t-OY*>U@WAfrPcmG*aTt~&arYpr?1BF^Sn9+YMiq#oE z8O2bBq!%j3z$lI%3<+P?L)aBwXl3d!!7nwF?gA7Wu3I8!881PrJhYL`UfptJn|7cx zY}0n>Yis4N23I}JG+!T9;@$G}3_`o;gbaB!a1Y<*`;zwp4JX&JJrKDWnG$aZ!QU1? zo9*WoXsvY8lC06l}&K}lyqCeVKymPMrLir%_F;0}X80yPu=|}@*J^S0t)lr$ghC;#GhC+Nx(qy6? z%d{=PDfxU7e_pinsbH;BU~`Rix=awjOJS^yh3+!2-zM3GXhMk}b8<18CT?oCBdV-} zLYs|?mA}cGPtNF?`}?a_t1Cy-b9l`roNI9NamOt_kRLOrp7%>lDH>4`YzN-C1gEXHMr|LcG=2rWbq&<3v8B+sZ8711h6xnXz+i29rVVEaf+5g{BM;97 zi_!$6%1cY5hS4&x@uS;{_j9F>&V*OyEJ?6>$qJk8&ai5G4d;#505iN1Plfa{fjAdu z-U;Vnh1Cr6QBA(%h~YbAAK+f}=OD~#vm~9?mtf8oZm@%zT)OAOk?>tl(zExle_e6# z?+)}Lz=8Y!7S(BsP2InX%B8|%#0DC$qDshc6ERxouvYz`p1J!OUq{@0*al3_duMGO zO)}ljjBOLHyrm=msekC3DW8=VTiU**>Iu2oTlL?WanB*HJDi9y@AnUES!|Jo-gw@s zWm3^;zu{tR;_*81Ja9!=#j-a6a85y8A>a3swCZUo^2Ey8;nnyjHd}X7Q!U1UgEj{R zi~U03Fr7v?wXud&d`SNYZQjBxA(6vv-p5*%uuoQAeP+1lgr|=+;SJp6lswd?+*M#H zF}>q=;2haA_Cjw8O*q9XD#;Yrnxnx+^A&$ICR0pobChbk@7}O3bDO-Q1fjS%gH!PE zez>!PP~X$_y2t1x^AwT1CY$FE6jyI@b6*pYwGEVsf&A^CUy7#LPj!NLVJU?%37w?n z%jAGW;nZM$s zw(={t%m5}OD-oh`o6y_k)O z?UDU;{hau^Y`nvaEHOBoE5`7cK;-+2IuC2O`+uO-Z{=J%5jU%fhV z_lC2wAPpZsVklGa zK{=6h=Rqe=ou@Ly-14bt5V>K`$vps{YH{Fw?M;z_qd90uj3aLrtp4)v4a z03`7}#_6dl+bY4O%OilexGX00BFVqq`SgQaqA_Dv!dcS7etnf?U_Ap&l31j>Hc!;K zfxOY{yC*e;-ScH9X8NJo*TBB@tT-D5-k}E!5IK*zBJu;~aISK0Y2vikC<*Qk@33V{ z)#}1|6z`cy+Hg-mayu|~vmE}Z{GX>5>B znyb+^0Dco`fkNvFf`s20Uuk~dy`0Go*Oczl7Q!C}Sl#NC`z$~HW0zQaoxbLuuaDUn zF){igJZ!Q0kB!`&L&g*eQ3tC7slHUEaY;H0d9*(!P#{)FS5K&B#72TMrBImr^}E<7 z7@T#cfP!sL*!qW5Ycy0wONP!$^kXLJo_t=}9~r^Z=ChDBb~hJ(n<3Zvm&ifb1+Iky zm5P3Mik&Wp7A(6f*57HHRwqR2cIS4>b`vyfEn5R-YQXvhNldnYiS>)p{7~&&T?ZbLEC${(jIFgi>&}snToFPLa0XA z=dE4YO?7k6X#k=Xc5y=vbjj;VlC7)xp%geL9gF&%hH@dgF_+B-05-O z_TcTu{^O=6^~3bgr7oaqm@PV%z?Bz6gew%^smNl7FE{ZuwH*8dS7F4oADHZ;gt6%n zX=s3o|1N*@Zf06t4b5`U^-pMnZ8Y-kxpNIj;T+nS45E}&2k!@B5?fDb8R;BL%)N9tFUcVw3!2*+{V5>o_A=> zPm@yD12ba7_^C$l9~Z&2yb(wUnI?7ot9S!o6%rMB&w@R+NM;#kV6!$!HOCqKRdCEn z1#xEUy$Bj+pHTebR}h}RmUr}0i?wv(@zou&7v0sa)XZ%W{lC~Zl_Um2NG~hv-iaF7 zez@<}YI7E|c$>LD79+aov#n_K-Pa87GvA0Q!%IUbUfeL~_f&Gh)wENIk%-Fbox^RU z_?da9nhs?^`Y>R(uWY|6ALrmg5w_%gE`tngN1GbO7%s#7PS9L9dquF{9G?U*oBU)%u$GgILBEn96{_#{W= zD*OW;OKBMDQxAV(1lUp&V{b1A=kzp1;21b+OhU%=rgOM;3ZdCoT-zKci`IZwoeYq=g?yT=Ft(rQIRGKm+F#^}cz1giL zrKq_Ypk_`i982j$(CDtRf6!*OK%p-pUhidfFi85T(k9U_QVITY)q)fR^Dcan30wIV zfuN~qOYj*Tv1d}MbC9cAKS7?Lu?qcOh-868M7(pj%Pao>F-{Vrr1rnpC7Y-8pbgS{ zF4GGKmlE{#3jaZXH7+ZI5&NhbhYq{3jmw{N$n=MleT8Ho#K=~tBXPKnU2}8AlGdWp z%d#9Q|D+wT%cVjN&~^I59c6=$M|=G4R#AjM#7UR7KojEKS7UG5>0x~?Pa6MYei6Gf zy(zYaHtO|Mqn&WrtfuW$?0zaQIxtY#2Y3dsWHEIj6eq3{#h}#;hII-B@ zzNf>EQ|@bmgx)RG3#&Nu1{30AF9zdN9st65gic>0`9&T*wLl&k_WQ|OF!j8O$pRc} zX5XiJM(&Z4bXt5$S22I#Oc35Z3X`buQjP5W!e8A+%#_&}g)W&1z zSX$h+ZoXYn^?vY{*`_&f^*M^JznA@=W037x?pMf-BH?bL5)#j{HTTK8>54hH%-%*k zYxS=p{`n>MJ9{SOh_hZniTAcnA-}J2pU()+uH2qFG#??oT8_gfp?qR{826h(^9%)% zgNwb19s;ccZblUzCX{-LQhgVL%9s_QuCZR} z&1~mM&Ke!fl>?d2{86mWCX7pMqls=y(ud7LCwxX21>aRfOu4+aQLObC;Ee8p~;h&C~c&6F2oKl+wV@3peCo>pV80E=1ohQ^LVtmX9oROh-?{Y`4 z-asEFaPyIc#!$yL4qZ5j} z$!2=g!-r+PCw$hYrj3<0MKQBPqdl|2?;DGpx`iK&GjRLZQ?b>%5qN#*3tf2Mk3F;8 zDkH`+YIT?4hL~tYy{!1l3jF1_E3vLcW`|davWvct3PaO9^BSrDFR9;y`&yuXo!LJ_ z^*@`B|N5Rr?DwTw18%=eK>oeN_{%zw$|PYkVTGRdB#qiad{x2p2}R{So3Jdas zW5v~rmPbT!TKrc6qJ{Vt2SZ1%l+9^!)5htu#kN&P<( zRT|BP|2hegf5&LDtkSjf+X`pPyf9kwT)KC=$nSl;yVgijvD(n~yk8WtW)p%G2mJe;^!#Fsc&{E1o5tfz9=Sv~q~dC}L) znC?pb?e=0&h=so^u3``~@xquNeGdj;b>jw7EYd)0RNEX*7Y__3h%kuU zpS~>j1-PjqO0@3JR&+*AcWQrz2MD?pvoDVY_vjUP#oP{8a+ajnj0P7uBe7JNL3Wa= zUTVk`^si*1IpPu9d0J;04U)LAAGp1f0sa`X+{fBPg`(4SFlCwY>ERMx+~f${3q4j9 zks^|vj;D|R!h`rDr|Y&z$M&SdBTCS5gi%UkrlbOFr$9cFMTQ0}o?K;Vi;0M*b%Y-6 zlnLK6&mZYRjwnB*>6pv6qvs3*#F2n%>*0a)EP)o%rLtQ*1ut>QiV#x4_^Y?MJ@2|t zgt$oBa3J|Ni%4&Trs(I?WvSza+}!CY^t2O=DC=gBaIl%rCn753dfGVL?*oV-xp z3k~IEg~#?!<6CJ_$rEpNMe#ze4oO=bz2)>`Wd?p1s78~U;X8i8^jJKd5Qpd!Z&&j9 zi$w{}nkGVw2Xt>DUIsIi)|_Z@4qg89GI zHl9!~`O-}TDt+WYt&j`F$er40E6!BtUdNsKYcfF^MPcD|5~r2%&p?^&!ZX~DOnm^!a4iRkD!Yl2H51_I;)kXh=yx%v<>m%vF)OmZwonx}#@+FgHi zpm<7pus@(QOgtLp+WTR;lGI=8 zh6m)`xZ+B;HDdmRPmU3PXzug=8=cxdTX>p|*KjfR&E;$F&&I0yp~sJQ-$lBdAm^>4 z&N7K1(7&MYlUYqnXRqys9%+sgoCb=ort4y!a#?M{sD_W~`iQSRle?U^I{KC$3vI=M zi3`V%zNHS6r|?GxQCO(4tnud(0N04D1b|>r6{7Uf-+F$A7e>T>e{Z@f^}XWHY|Jz7F;9?l^DsfdTdIOM}(4!Gl6UeEn^3HfRhQN##| z)f%?DnATD(h4dYZWW=m2upaA)*X|qZrvieHVpiY06CAi@3wqsiRKiaqZl-g11o$~+ zxt@P*N&J7<`pUSb8~$q$B&0*S2ck#_C>34zpnea@B4aQ?Zsa0_u20o=bZ03>C2=Y?yDG0KjGM~at61pd0nF1N@SDq zo}lU1314*%0+;e`t-UqU7rc!?dGhSEXYSRhZW0oe1^^lb{&R;&c%tkiepoH2>(v2E zLddGfDFm@wjLI;7`9o}X6)(wCxU)3AUBp)ss>DEMBmpE*RoZa5UI@6(C5PEF9uMLb zPP8mH)L=gC?W+273$#piaVx^8eC{_YUfpt8Mjb)mofUnxM>P}7cm-7hV|ky$HPND z!h%$01(=g2O!}|FR7Q*GU|nSZyG<|iJJ@Rj!4XcPmscZ3+DzUXLC2j0BR#b|dXK5i zmDbI)Iz#*RfAH$lmp^g$d1ksR>rlGWYB@SH`v5dcxg(h4+mMP=~QUg zTCdO_gU?j?l;R4RDsqchhG^3O7(Jb$*Fg)yv?_RGi$Su6dOr7I%MVSXy$!a~-s}Ao zWs#$DnJF%y@_3@&{D7#REniJld_9@^$W8g%+42-~chG2PFX>tAu#RtUrxXGL^@2o> z_HIX~WeX)kw72(XX_ck`TN;Vj9{aEoGyLxa#EQWyy>DJ8SVzU#_BPPI@6nW841CKa zMYa6BbLp*U`x3Wr8uI6j=IDY@P@ zl)dyjAGaqM08w2rL(_cW_FSP7#KD(lW1!_cn?UK})-z2oX)wJVUp~*zh`w+QP((dI zfUTI0Z4m>PeuZKE(ro|M-r=6Jg9C2nGm$i(ygq% zeDzjMY<(wfLtq8WfAkk=@}QK#+c>oonSbvu5$z5PWQeyIvQGS%X~UcR!}D zi-}))uKdb*h}L?C@^-F$F`j0Bh<1<{`@neMbE3Oncwm%FUPz9J{{_e2S$55b;ROl2 zlkC$qNEJ)za)lMY%4v2Dg}GeJtI6q&$rsc+eK^B&E++n%u_rP`dx%Jp_#F$Xp8jbW zTgL!;tw5Rxn|2Bp9g~gJ9eD;g^0S zW;;ejt$>N2dfh%?a9y!G>;&Qva6H{1usq6GQr67Wvlv3MD`v{)W5iUiDE9(~KVBu~ zyaQ-~HtMNvqXyiY5vf~d>i=FgtY#tFm}bm8zj>-po8cpk7n1Lnfb1H9$WQDw7#oLo zR{m9}nx9~oD-Yl2D0CELdLP$0-CPeVNZs_SCEmx~DqE%wvCE6`l_R4)Mi;jjc7?cZ zoy=nz5Y9C{;oG7py(S7;Jw-+*_nJ01jHsG6sr+b`U77u8+Qo*T++^M>Vq}?Dx!q0} z0FQEvn?CD(DD>F_m35$*BZwX8*cs}QNoqr7aWp9=FFWzXfhUoA_Whi@V6I$Jg3TVA z476P^{DuWYo15prtyA@WJG`eS^mmotv#udt`+a{o<1pe~<&|o62(5vGy?CT!&Cay( zy*ZMjJfOBG8?t~nojqoOyS1`{oA8CO!1i9^v#toyt{Q=uPM4ALU2Br-bb4*6RKq|T@p~OZ^7n`LKAM+De zeh?1ouXxK}o&>C|@JL@$1mrV_xj!-wl(1H@>fzrbn;AK2@gWe|`rPCxc**(i6PMiT zCh2yw51%$iCda>Zmsq^(a<;&4WNKEIUZ@v$+H#aP(qhi3fJEsIp>CRKoT8n2?JG zVO?LE+v29r2s=G!y$@M0;y3gJDK9(#zkD1lG81ti?fh{vAY?{Ib>ZX?RbjpSfmvDN zB*y&M7=bs<<1jGQTJoh5vh6~50-mDSN8N81Iq-#Fyo|j7(&(oyE`)A0)@QL|yrktb zG)f{f4X1rF)|IeZJ$J>47&_7$OER!@@9&x^*@dCMy#RO(T%yEk&7-Erz8gWauJIaE zc|J=Rk8n`@5J-2BpG>x$Un=tdBBbxlB$}T3uqwj8hy*@{Igym49CE(tkq?l96a>Fqb{GrFnc8bHQM(M|s zJ%MjB{CGASA}oT9^&i@^byQN930v}=d&weKK2ORA(t3&sEVwGrZz#UtqvvVe+1*J# zdbS+y`P;P&7M;Mn)GLbyV}B}3l5E4$m{)`>j6U@QxjTbWMQ|gBwrBk#w&go%a#A%C zAqfbci}`^Dm0&^*r1IhOfg_FR&ma3}WLNFMxV+)v_>dDZ#fuN){s##++maV8t1+{@ zX?uT))dI>C@%<}m8h~HKuvb|8G&t}CGmhPyJmnd7^So!zS ziabdBb^DI{-;?s+U#&hSYwx(+x^y^aTFh`BW2GZjV@MV=?~<{r)--@uZe+yGGetY> z0ty@eUQDWLX_-DE(g@$vU#X++C+%9abk9Pd6MbxqJLD5&M4@o4N`DAYYv#Grj!WmB zO493@v&PTtNm@ipDLcExpX##o;%G9vatmW&24(QEOZxy+nebd|=o;S4uzsWf`=hAlM{S^|Wnn*j?5yOH zKsid;*{`S%6z;@RYhDmA<1)( zP}t7?-DH;fo~*+k5)l47-;@>RpWav2sOX;4%|a=v|#3?X2V`- z)4;uKhrz%~e{1&7Y|P?{gUVR z{T6ob*yAroxSJ3{1ZGi^S119j8d}+yX74jh$=oeo`zx;ct!3_n{=CR97$N_;$!*64 zVdKmxZ$;QHgGYR8jqNTq5Pze)8IQI$=0p|wO9A~sdjThu$9$BxSCr-{VC!|-1X<)` zhxRa|>i%qGtM~5DXd^eXMmGSIGfx+soqE$>%tupnCCd41_I4_M@_6am5&w2qG`fM> zPi5P#-d5Q`&~B`t8-?+`b!K)Z1O7wQI8S?~wu%6G2Dy~=} zx;poqgZU)QzQZw8k%@USY0A`nMwjn*z(zb@<~K5g=yk7t@^e(wS+c%n&;OCPG zMS#Mc42`Qb1gO(C; z6Ur#k=JI8UdZvQVhXIHFJNKDS@w8?FIjT{Zm+NHeX06)Z)J?42O^DY9k+Z8d=Y?ZO z?xe_^7$NO^b+5+(FkE&k#~;Ssmp5wnhJBnIB!4d*SP!nJ-=!I&W+`IsP=4pjUL9vM z#>Py(e}azpzo}K!+wt{{v}`gFwAGelIjwvKeO56%7I(DzPKJ&UFFTJm{>arj3jXtNok(2rJ6re{-y z_L`MDAFJOExbe!w9JvPRRC$omobBkZMNS!=idhiGslUCss2hh-d@pv&7XkZsVt;vt zXWlU_v`yjhK{>P;^8}-WTZ^lgnu?k{oz=XK#l~xWHW-w&ogc8C+l51n(RCRbIgvIZ z662z7$StSA+;7qt+2>w*uXJm8VDAIs1w3okQ;HRonxFBC_WR5QEaV41M-a)^*ekp* zk_wb_vaPeKNIM7{s-YUHQkiJ=fNfZGK7M$5&}>i0D!G_~6Kc=amcAfr{YbPLBt;r| zJ2@60be7(oBf6Z;Cs^8`z)Xd}hb(+elt7fcg)YMTRM`GR`3>}h<5UdCq>MZ93pb{d z!0DByfoj*p%u+hbmoS2X%-bVoKBV6W$7Y{x0W)AY8U-FxXx6S+ok-+?EZn?hqWCY6 zD_J(M(D5H_WD1Zq;rA-@j$?6$c>1W|qog^X6Wb4$IV!-UmE23(rB_>36>CN*a;ZG74Dc*a<`D<6W^M<2I>Og|y!2>N zxNjVjo>*g^W~vxGyC=oA)b}L9JD~_-Xn>RlJ&Y(4Oh%Ips~Y=NC&wA{lH&fLY65QzlE?`?l-H9rOvE(S(>@8KQh zPQL%Pn~^V{sO^*`wogBw5^DIM3!UE!Y9=U~1H0qbij!{VdohM1EItx5OHdNq?mfgT z4NfKNW_##v%Odau6>VTRV$N`MPyhTv_7-v&fB3FN0L|P!|S9Q*hGXws5-bR22*IOigQpbnZnSQ7`rslh#Nay;U zD>uXvIDs?MGw0>J`Mz}*@`mAo2c(eU%{;{P9b!;-Hn2uc^o#SX#s%EN(HqtHGwcXH zPpP8tUAf9Um7DihrEX-9K(tSu`H|FgkE3ZdX%|@%P6LsO(-33qj_Xq|#{J49MS50K z{W`h0=Ba!;-d8&^C}-vPdk4=S4hA zhaN987MdClX~|Z;OHr>xSNEsyhof+$n?|+h=ZGmO0S$Ww99vHZPD?i$QVNC79Gnw` zCs;zUFqe0zg=zL|1b!w0lfEXyyNm=nSdR4$z9_vgsK@ZPi~$e$4(v<99H&RGc=Y#Q zwhHaf@ZGdq{}#ehw>zzPj+`xujdhO$l*zeot|i*IDr&7fQzjN0)OQ;;K+jG2_sTZ0nQ7eT2qTE&{aG*xqX-S~Ys+PEn(uM{W{Gvi zC*GFpO1G&`+6e?O@fd{ukwFU<^=6K~1$1q8M7#c$GH!=?op#$w>Hi_X|F@YKF$Fmd z+#M$#+y2Lzeh+#r;l+NvIT+4rv7RDUCFbOL9OV*EnfxNAWvr?Cr#deE zI2Iv@;(VoNn4_&w<`c!7?zqQBoLm)WHWBSA>ZPKm&QLKBHzefdYo({gFjhe#1~Y-z z;K;|)R)xSd!z$I6DyZw!En_j0jI8mkB}!b?5I!Oqp!#*2(n1q{J4z zS>Fs4?rTK}v1j_tKn!|qt&aGHtx9Ze%-Bo@S5)1dEIL$B%%vmfpf!)(2obE2CiSE* zk5iFIJ`Bh(Uy@>ngM9b6jp86vJ&(lFXXNT5s{9l-+I)s6M4h@XvB~|WYKq8i zTXjUVzUGC%Q19#}5w2~YdoMgE z&w9|8$Z(-M=ACohJ&V7dvgZwHyOgQc7PZvn0YVDZj&cB-kf3&_Qc#-T>Qz=9@4+2N-o2k zq9#}GHL@YBQG0yeRJk0>++p0iMO#Rb*~vAMtS)dY-_Cw|);WwNuB7Bu&1H%d`zgQI zsluta&?|?sIlXer4Cp;7naf`N-Ptao>I9Dp*M$*Caf(0ph1v1ax1#R6z7|%Q=H}rWDf{nJu#3mkR#pvj7YFHFqao zoPU7<3;uT`IJhAKC}Lk*Oy}OZ{$@}^RkYB+d*|oojkLF;*T~Q0gb7t~o-HZX57jnh zQdCec2Y;EBAo}wQ)fQxX5Z3v$(53KyO@k=JroS5V)_Mmx)s#t z-VG)(hf4w+50t|SVS6oxeHILz3mQ2vmp)a(xb?P&Obg+ZoO%u%9np&{eH;bRpX0e_ zbfaabUgmdk*h;zvruI&et2(QBN(sHAgC3GUjJ|Ml)?BI+vpCS~T&`^_?~+lbpP1WC zs5L@XPl=W-lOKvXb1Zau4b^jJ1J1GwWfgoP{p8eXX*%&+AMhDY5z@V%ZA-X~-X$l< zt?J#bw?Xv%k`o@ny*;-49)u|E78N^SSUUTZz%!l(QR#n&y-LZ6cF{{8Xa(fL*ogT2 zL~qG#9fDsZr-bFhIM}8etly!(mW93hJqr$=X+DY57S$9i;SONQ zb4U?!n;8S8zoYky6%$*C1WS33NP^q$^6AU?NEUt6F1w&iJWY{H zIu@JGlHzey4g^hwj$Iy1i)=ZxR-fXvI%}d8og(`1J@E8H90gkHx@(I%*t?hPEW?Qi zeYSlAQE_4hsc(2nR#PMkale)Skg0vgWN*m+enu`cl}aMq;im zU)+owcs|g8$e{loA#YgA_**^#xzu`sY(R%XoV#p@eL9jU+F<;$1WN<2X1Ty|1BHoOZ8FXO>v^UDz`Rs2#Rlbjox`HRJt0QVv z15zGxt*TlT=le$Exk=3L!UEzxwglTLefjZD$#gE<_u8{v>|&H`r7iiqKwl*Xl?Hir`BdfI&&;#bIbg1VO)fI&2P3zD zuY*A9r=u|NhGgUjhY>^J*sXf=OgegzBw*brV0g)zc4|bWKtFRMqayfUD3vv~2N*oE zw7h(KhCXaKhu%l(ZMi`W>yn_%K2h6FfN!k2{1O)5Sa*{tm#P}Sgrs73#-bTe*`JZos96vciwi+ za)IBX9@h~Z`PR)9K)jc>8Mu{-YPF0 zN+rOE#YXn#E9f{xUz&nhYvy~DzZfV7vGCKipzBkeC)`Fl?-H;I z2zJd_(~$ZhDZx73c5hKYgcc0vO0w6m-bB3OEApMiBe%7l_)EHz$5bCLZhoyi?wvGk zY~be-Y&CvPCEWP>vnt$2XK(rvy7rAEfq<{M+`#9cX7lTFUOs2Hn#2>e{~nXm|D3}K8bY+wiAl|qk)`mXbSuLcn zm5un-scZl`Osn(^0vHxS>=!<=qO7!y@)BxlujWW#XRL+JjL94fO=8W7F@t)QS(Z^^ zu{}Sp@;Po?-vNB^f}GOCgGr!`wi=*DdRj$f&ApF&IA_fP@z@p?D#3V-d*;Y@ckNs7 z(@auVr?0x{P_bx`6SM*5bw$(g3uDQh3#~3J{o&DC`;04c`Il6coFvYk|MB!hKe9rs zkOR+7@^0j9-oQDHK#`z6typ)%Iq3TMuHUBG^*MrA@?UKtsvQP{El?dCXD$KHB?C~Q z_w=7sz+L+0LX4!Yk@r!Ej*3t>uL@pg_4?^K41xojW{fp}RhI zO#N$^{Bl>83`D*A51*^#C2 z(=Lk^U>*mI*s|9{3hQ4AZ-wGt4$-f^6PpC=WrR z72{v@E;R-Tg5KKAPAfiFT(znsBOVcbrlK$@DL3z$S?0o0N7|Fmvy{#=pe)C8aCo@J zC(o<8a&WNZ7V9@&#}Wf&0KBt*Z$Tkf3)4-Xl>bD;vA2U8(rH@K)x!EtWnFwcd;N*g zYI6@%C6>-Y2$3H=gD>7m#-p^_*F0^=peaslmD@zxJyv~?4ovn}d8qa&Z7_Cr05mDG zmn`-Zo;jitV(-obyWC_tPS1yDWjMI99~^vkB~2^~_6(ZvY9KJ$#qerXdbx7?N9k13 zWIwe!NVC1dk)7H4G;rDEtDVTooN`78Zj0<(2!T}i>Dkkr8*_`0FAp3O>Cd*+XXzLZ z)m`!@miv5H9QnRk9YI=pLBqg^^A4=2TWc1aL&UA?2$=KPzpyJtO#jFc&$STh+Z{*n z;w`oG$#=EHCS+r-#O3L?&5)M#ck_1V+g75fxN*+SNGEX7P_9O5}u5<8MFN zJ9IztdG+GzJ1Q=OWB&=&=am5eqg*FBou-@c$krUDY1o1On^Ja(Gg0T@F93 zfX3#Rz^J@e4Fl?!C zxcOFUyQ*?ArlpjHPci@OhvZus0@^9meCDiI6lNC5T~7-cFuyU;-}Hj;cTWss)=Ey7$(O7mS-&chk6oO)Gw6KACrlb1AVone&jDw>Xd~Hm#fMTxe+*POiU%Ay!EP?k|_`Jz&D(+(|lcqb+79kKjeF&xcvdF7w zsYjgr0uB1PDh93S8;B@Y`BR1_zQ+> z*M5*(4#m%(vZB3NfbW$XbR>c!W6^(#_=ok=M&9w$Nv7TQJ(6@0fO@{~__|64vtUEh z=4L+h$(B`wCu9(+*b;>L5;KXA`pwU{e+4o~Zq`qAg+E8*#JX&y=1gyUq6HcqyAlqY zBc`gWauPsQ+&@%^&wS?$7H zKB@oLH89$C6j)$)N6AcA#{sAPBfgD`eu$FI)Rl|izU>@IyYg>>{^x+>v=ffP2}7I5 z9&yH2mwG%&3-R^gT>CV&^5O@`mg)i(r)!isHLk=7Sek9%{lgKj_f5lod$toc1qaS7 z?KQGkeJkbkr@03)_i>|5^4hr*DLC@l`cOxG_TectT_UtQiLG;^Ge~=FJJ_1Ml5C6- zkcG5MXvkrdpMGmpER?JL%hBDehJkGAF!}Hq`-L}CWewPEXa27IgqJN=^NF{3pI&LY zew0p{kb=DOw&-r$78Ap~tFFm+fakI?Ybo`)A(L=_0=1eZ8j8D zl_~yPew**fl2^c~;bp~z;vIGT1Wae!Z%Z?0|~wp;RVS?lOpF zPqWsUu}v8tfAT}XS>>d4VhT!+)0?3y=sCX3l85Zkb|~P7A8aXdGQ1kcODvwTY|Qy4 znQ2)y z=-Mjm;B^&?bA&3S&*6aXtcGFUIn%bNn#lC5{5!8*8J;mNT4wfh8@glusPy+e9yYQL!A`q)_Vl`+s#CG3x`wOKE^G5X2TAPJJFU?! zN!vnhV*9D;Q>WGO{Lm-1#x*em?nBcRH-W8G@%z;)Ce7r#Nhx8TRrY`m#uFkc0>VTY zVrSb5asN8dHl@U|nBQYe>>lTiy!|Nn6ldfV6Cu zmN&&*;4PxhH>O3%=XQVj8H?cNNKgDx@WTyE2M<0zkB(_&d~WVC1mVv?+csI48tp5n z$>z?hCy^kXM=1Xc$XNI8=SXT(ccXZl)wn`#{k8K((+L#6M8=&YM-$~Nc!lPTPE-)3 zG^G$d-Qpb5_CPebI-d4XeD@X zK>;xX;N-5922>Xk+oi45YKPrYhza;-U=wFEpS2*rV(e*uyuPTH#m!WQ{;K??Os~8s zn;nT|K(9Uw$&pOaZvP^r&2xO{&9QvN%Fw2GImYvT(~T+}A-0ZRdE+KnNJPk{`e zrB=Nk3&jxg)TubU=jxVdp-)nM!4`R6C`i4IW34t^Yds}|N49&QQPnn zY->@J>FlpB-65`OU)VL9~V3^nsUK`yAUA?sO2TR7+v9O7lgP{5UZud=}5{n zk(6lfiEQysRyt5P%gLox)u$)%SiV#uylu*ll zt1cUG0CO@_X`nvL1QliK)A~p0kytwv5J#V0aBCoj{f&7kn8EefNu=T!p*knR|DlE@6Z7Ik$=T!U@n!e@e6vXU!#VWEYDMU_4o} z?0uUPp-Y{M~b_j*?$Ia3G!6;ARW=3iBA6!@iL{#(D@}*W3Ky&#yB& zEr!}{$@o)xVS{C;Sl0T^}!Z$yP~LyJ`dw$qJPnkH((!6O>M z7gfnW(JGSj9#^^%SSRd}JL>>8#_LZ#JWipp=dxU4Gj2?)W+6$p2B$AL#+O7N=elby zYFoR*EeQ(+PbIU0b-$?09iGdp^fViewCA)2?^tL;7`!wZF4oTz&W(K>8@3IRT%1)i z4Zz0>;=Qfi%^?H`j~l@ls=c$3HndT|3Si|-AwnvEm2UIzZv6M$em}6sVqXoOEH+81QOXz1d_`ZG+;~It$y!?8vQRruekLfA+cFd`!M-C==0_qbPw$=~i?^KuN#RXfHc#6< zMDNyv*!Mo7zK^-eFV69@A!8c|KQFf|MzC2#iRBa-T&;~Kl*!*d>q4yO<}#DH@{W!8 zZzy(lFb3&Qbug1{iZt_(&6S=Q^VK_JTl=1pAr$3t?&h$dTNxcLH)~@yC#r|w1|zT7 zzdGM4NCAW1-NnZmft2_Yg1*}uS#i^7SeuwhEc4xbZkc*h1~t!Zt&p7+uGiOfh{+5Ir-fR5EMkwd*FK7TRh<@P+;ez&)wV+Ja3UgzMUM@RTs%>u**Pw}RN zP}S>qV!MOQEW1wx>DJr>`timYp|hFzX1Ox$jK=~R;v~ASJYn-#g4~0Hl33<<0G-Qh3^gejC8wMGWNkJK04lq=jsOnoQ%p+o> zQ59i6eR+Jlw#e#}`PcoXcXNO&nI{u`*j1g;8!?^hSUiO^Wh}`xT?5^nCnU6=dq9lj z@Z)$eyVnvMCsS~k=eQ#_TtT?GsRBssf*1ee(XPX3GbmZgnzzC=@TTYSfPy4@Cw!^G z#%#D#;_SChPE`sigeh)2_Sj#IAq1GJ-E=v(mFy~dE^b|!lpRlc8R}S(%x6bg=npOl=f@7oxcPiPx#y@^ZqfH7rkM@Kh=Jyq4n-R@E=be zyw&dRn8w@GNDma=?UZqJ^-mE?S8(VzJx&B&jAL+>rh>%nsLQfmms)*@a!~T64rU@b zsGK$=|EXccuD+Y2fUK%Fj@hS1Icu-AxBvdg0=6#FZoA0Ur9L{7Vyz*yYu23%uej2* zmVoV5(8zhCcJWZzJ_BMIMB#XrVS>i%K}?KQ=j@|^L>~m5ke_W&HSmRg!Njv&pdsV< zVnOuCdalNz{aJRsVxSXBlKJ|?a^ZG-dTZKTo%Qao7e4I;_C@;g{M_87zVY=s_1)n? z-HKjm+gjD;UcevR&7NF76N2(*r1$0uqWYhQ*7OxDt1BKhyi4FiIWHD$=NrZ5#X>6! zbj1B9YB2NJ5V%a0j|n2)Zz%19cyyz@I<0Iu*{15{oL^a*7Vz(w22?A|3vrVXm4EMZ z_RRM)FdNaDO(OI7YB&4Ffr$hs@11iYK}qz@*z5vjJdM7@T;TrZ{6k|s|AQ94v4`5R zE5Y~zQxj+yJ!KT{{0W&5&6@^0fT?m@Mf-5$E|e2>VFg*!=~J8_SAy+|hMQ51*?tOE zDs}5x=F&G5qqi;n!7|Hws~y#Ii?dXp_E65kYv^%#>O45yPT;%7h-j!WMG|%SMIZ-u zRI~%;s`R?~Myt68W~TZwk&x%peznL@f8RssQEBp`wagd9uE1hceb^OVSflz{zUM)t`C)qRvfw9sx!whZs1_z4$p^Wkqv&+X3XQPV z=ndQ(ow|IdnIofHm`&x8{o-KDu+N{9l>hm)?f7pne5ynDdQ6cbP&%=wg%SUlHmp$ zbMC4GhYt~l>5?gL8s8Mt1vOj6I35(_k2$<_$D12W*%toTqF|42Bt?D{KfGO@(4MH% zGi{n}zLpXy&}TW7+geM(Va~wMi*ISGoLCzVTI35S0?q6^sTZ@~ zacjBAtUc0?iYp+B#P#JAw9pSjo1;k11yfAUX_*tpf+cq^_nO?Z-vq0Sz~7EV!^d)P zH&!M0d$-@cUoRQCOnNnrbH5|56G(&?_P%)c~Uh1*OjqV2XJTFoO^J=F2SFPJ}aEaZZY#neBmDv$oLl=FUDV#sQ2-w%7;CRQjGv(p4mp zGbl^(1##((xfoaEiQ&XQDBd!<`&&`tSDL!~|DlywJ$r2;vUm~QVdtg3Q0$KheTF&L za$*$52{TF`7Lh^71!*gYz^+`X!7xpRN||49;MAofJ}1`<*?S0l(tXQ9vJ9r3)}1dX z+}R>F;VQ6q20bdFSemRMpMWdgIDJVac1T;RT%zm;rdQRb$NiW@pkjWkg`@O-cL?;F zI%0pv_C{WuiBiWhpn`eH9zrF*j@ed}zFtrDd&^jGb~Eb};IES8e+uhx@X1W2n?kG= z%d0ZlC&F8viYx*gOB{7DJ`nKU9X83yF)tTWd(T!Z*kgt-%Iw==8r7SM z;sr*{6Da{os~T$YEh7#l)mNUopWm!V*YgvTF$6Zv@VBj^SIxQwVG>max69{A=f-}Y z8vdjsxp9e^O4Sh_DqzJ zT|yzwQ|n&)e`tQ_>Efv@xBbVkCV#re))^#$j9*eDkPIbd?ez*#XnB1D2pqba}?gs3=z|oD4Sjjy8XV3dg9d}$56KV=(qwNC1-y`b$!=u}Gv02L)j~cp# zaaduD1!;D2V&*TZb=9|pYq>kDutBQd@EPr-lI5L&ITD^WU*&)`oB3RvE5ceYzT^nj z;w*7EM_Yj<U`)L zCA=GGBiC;Zjm{E2mafE7RERV#Hp95%;F%w;T17(x?d6=3DNqQrRxDmg%lq8!n6>e1=j}C|;NHUBHS9?em(;Izn(@jwzrQ zzv1RU*WjNk53Fq6B`TlzVm`oad$x`|53V&=a=$u2Sd&lsbFTYPe)r!64{jy5iQrSb9vi<=)R!wjiiG zB*(=g%$H$&O(JPqA?a+iRxDI}PRNkQ?zj3mM_qa*%T63e5U+antt6|-#`m%HwLdXp z@yGS&u6^eaGxUkkwk-3F-{zT!=Loq%*Wy#DNC4zg1b1&<2nThM7Zs4NqL8_1boN`} z;BPv>g^jeGDT)<#2QLdap}!kE053_kp45sD${IJeN!(onO`k8W_)6)M>cX5w3mZ9l zXAEAF{*3RJd6S#M?h4Q0*;irmDA|vc;g&9RC-S^^SHbWN1d7Ej$^kk-cThy&~>DG zd^Sl{8yCM+4JRFsd>dPoIxk(>A~L<*QDS6(X9b-9av%%EG)RWpo-^Y& zk2A2(du7Hxg6_K_v)vk_GtGApCiKCYgFXBeECHpxDc32X!ZSo6r?u#6RAm+Y|772M z^_X|!k38L%cw7gv|Lipn7&-4&ngp-C)_p$^)k8Ga%f(GY)64dnce1}&U=_K%(~Q3h ze0eOnF*IP&s7uVuE{S%b({HQSX&3Ec0!BYHuPu9wZi3S2Bq7qELn0M_-bmgM2j%89 zAjgosKhUjeXQaj^8jmU=)C<{Kr=N1CDQ1=dy!9}|<(CPC;KE*OUv z-z_YbJ;(vw{zI26`2d7-wYz6M{5OX3mwUzP7nVS*({{U8cORPUq}LmW$8MO@cf{VF zQ!E>yE4EK-T44tLh*l@0J5f9%!bxQ9`$K*0&L$*WM=~4(x$~6x5-nepOB>?@+Hl*C zJOkxC2Yjqo#??t)Z(%7C1xu?(cn;E;nQ_Nuod|CS>z&tgGmc9rSodSaWSc9j`YZ={ zUrP2f2{iiWzCV2`A5Z_^e z1=KBj@16FhI&&F&Zexa@ATF0U-->rPy#45fiAks4JCAul^77})Qudm*GxB-zAIrjD z7ksYgPYNx5+13TmZ7s*X+*byIapNK+ElV`>ED;bb`63(q$XrRFE1etQ5p6?D`k6oX zaSn01_E9a|z)Y9%$C;Le_ZSSqetsz@cZMzg(q5PHwehS7;3rt6sCCvnWx@@Emi!u! zv&SI|cq@6+p!51N(YGvei*0_v3uB{Vqfpl%hj`=oL2**`HxnW9RFTW_o%r#tq!JZ_ z7Wp_4Ar*a}vS_MQkz{J&MtU-ccEkK`c@OEll|w~wyI}A8g?4;J@8h;iKE)jR?87F; z5>C0SZ|Z@!({focy3M3M(O?2ftvoAX`zNvc+k4_ICjVG7nFYagI=xQ^8rVZ zS*q!`8LzXb-c-x5Ef9)?kuY&n8@ZGDq#GM91N-mqM^e@J=)Vn*LXjbE+&2v~19Qe) z8PNWd)>6SpZR$yLQq9CpXMak&DYr~dKZ^vp#D=`X<cGHZ9OO26mxF0r&Cu}Mxj$_81@@7RloAniAZ$li;q_eU|LKp zB=}`kwEu?am}V`wOgDFGI`88_dNs;9wZ3I!k_C*0gACq5TP zj0JF1!N03b4x?Luvnao|o14WGgr@ghJfA7%v2j}w(hs2`B za-R5~e}2SPkS39Z*i(XPWXEIe`!ovG@O2J8t53xj&okJ$c59h{v)U_&e8XX-9#ORt z#N?v;j@Ez%>r+|36H~x8NF=9bLVO%cwa`^IIuMVIv4sjhybk>~n29|Hb_NOG58RWitQm4~SIV3d6xtqwW%wL2)#5mkzYE%>hETZEN z;_fX@x-09TSa=q}2hpowlJg2j8;9x|vfaej$uGjHslZHhKbIEZy*-#?!bnRDe6>AH zi~5n8v$5oALG!|^%iHSh?f*m9RYpa zosyvxz3cwT+*9QK!{MU=whXS+H=y-??-bOM)7F}z#R*J_TcrZ=773cR00ynqBy3hm z`vmKV76lH)>&=Hm0mnvHkgQ$Ndp!nA?nuyaeM92|#io!D5ljHsAe-zge%05EaCO1z z;ndt5x1(3T{#|Fqz_6@gC(Wf5n>zl(ja=ra8%;wG-$ItBILRmI72^!t86+i}&vmvp zx_g7(81`W-wSCQ)#pjF~9o;@9a2EViZu(1RE(ZoljQSE`{QUcV#~+zgx1nBVz#n__ z79QR%d@eH1X_z@JE$*bY3XLdKfRc*?Qsp$L3uatR7 z$9bkPl+s&Ww-@b3OW$Ieh1;Er&150&g0^e}JHL2sK@Hx!wm)7!C!C+?&VZ8ANo=`W z`cyAEJw`+c#O*#7far6u{@#6J>*I!m65ER>U(0Kgech_MNZgFr`~Wq62YuSw8#GdS3$GL*-}#)UQgm)v zK^Ux;EN!hxL|KDZ8DBR35?@`|Udi3(ZLbD;xJIWsE8pK(QKpu(#r~UZLH7~P_1Gqx z-Oo+(arsY*7Y%Wuy5ow2bP68)`s98NKfE|SWQhIZJQ(J2{bDiXH-bYv{Q4kE$y00@ z)dw>Jz;E6I1P|<9Yq-p+plH&_R-@t1fR;i0kM)lY28uHiQ}0g1*wA2kf3qow!>Q4) z7hYMk*R5_of4ivh`#4u>r{anH<5{o}R^IpRmDX=TLn6uzh^L0S5-`YWaLhFl;s8CwXkO{HC5$#%j;t|G65l?a#jZ-MUjzxz1in>#>_x41 zcfj(?JT|b&v1`|-qA=w34%bh{I;O@GiZiO>1OZQnSz-4F*LhzrI(^Dl#rAvB`<_u7 zt2KD!4)Q@CoJ%mB_<8t`2goYKuCA^&GgkfRY`Kx%nY}2Ht@W1$A44`@Srt+J=>?GN z=K?pCU&{NxFpG(CcDvm~9Q@|#f2e43taqTDnxB_WA1KeV)^0Bj!J4FCSQn!$GrLR` zq~a)MAIbA@kJ0*6$hosUKy2lrjhGT-_$guG&bzzTWf7y9_K24Ov0S(Q^;)Ot;JKUT z-pV_fjgFWeNvVP6QEiL|Be2|%r*Z+tpkNxR#*aA%jL`iLbWM*JKZTlYS-s?qgn);R)x+%oM#zd;zbj$CStVO?vF7?(*hk=>zB7$x7D%A;E^-FLTZg=(|vr575S87NKH#{c3mcamI; zAHPC@)nr#_6Lunu!+CIxg`D9Ro?$P!a?f(ERxg)JF`s5vnFJzpAeFCLt-Vo3 z9SJ4kzU2?f!W~H3uW9HTB0lc>u1~~aW1Ez}B;T>6dRW-+CiNcc@mRv5udF9U_a^%i zWjV-CR79k2+A34GtbQZSrE^?6$#qbo@y@B^(HfS2biM4StW7B5A{GqC5Ut!PE6uyP zzWVOSv`8`I-E5q^DTO9_Q*%oR8Ryd(>-p1x=ucSyW~-PzC}o@;ZI}7K6y86WSH>$W zrxIePG~*Xom$xsKsY6wbt%R5~f9XkeuNt#`U(uBvFI}s5Z_1;1x49SG;|!`4Uf-4B zC?~eGSQa|hkrnf^FFk2=Jyil7Jmwp;vBFCKu2ElXHbtJGU#+Qx@QlU18MZM>cSjX! zjyLbrBIa0DvXQZVGhpLMSJi;uN3W}I`HVf6w-6w4mo;mtfj|E_2LsSQi+xb`Vr}$p z+y9^uA+zr~=~p9l^*y}ri-zoL4@bo*VU!Cihsb)D&ruyX1DVv3{krpDBS{5VB_a$k(wl-?IrV4rj_+*N(4sWmJ(; zMa9vSv$O7d;nXssGs~5?Y6%{aPHFa-_L@Ckvd|7_*0MPmh6nl$;zkF^`?%Z0H(Gwz z+3QsQMU&SdwyO7=Ynw3&Bbv4QAbCm8Fe8w6X;TL`KRqRt%3=4AAH$&0)|o%3Xnfqb zt(g~}^!*}(&hg?afi#h>tZ?avkB!J>7I+di^M4_I+x)2Mbil2WL?apg`Gf3R6@APY zps!LE247s3U_qa__UYWdT!;kw*9Qy5A>{pP6Al(G438i0{kl}^rZLV$27Iy=KR5?nZ)K<1{kHcSvex4vQr<#m^ zRH+m}fLP7QQ{-~tt=PcGG>)Sh)&0yIzx~cKXU(?-U(%aA!<7=<76(^zO-C_N>?hwr`ejGrULG*C*;|O7;n(YEJeRraxlMuy zR~3`zZjkJg$M?KEP{dwld5FqLuJc19`6-QQ(fLAD#dao$5v!_{NO|=r5gsbtGM$n! zsKl0g%u>*4UjfPay7to*bH6-92|{bhP4ip0cXYg2m$rx}*1eyq*PiQHPp7@(XpF&gbi}A6` z)>P+Oix>13B$Y@mRMydZbwzQTT_RQ@W95*zruE4jVD!03!g8;8ydx6{^PUHFrsBP6r48riQm)5q`R277H7B)&i1b( z8b3D=mOr*?+2=l$p!te>^->Q*dyT7{Pnz-iSNEs)nFRZ?)U`0#CuIU?uY|L%)g#_+ zWaZ>#J9>TH>u-ts(3|z{v}1WeM`F_7gQf|VQ^rrSoh#`Rk26_{`Rf~}*j22FNrzcaJr)Rfzl7A@D|azYNHmb4Af8%RG06GZGD28s>E#pEi1_XGW*IV@s?^9P`P2mm%cCfm! zXMM<0N+1R~Xq!^AzSUoCS=RYH*Ryi(qf$Wba3yW&O5rPxBHnt&8l_xn zT6tDmWzUUY=KJ@lbiDm|k3Ol77;!4DOp%-O7kq|MMVjuuJ#MP9B?f#QT7DnSde+dO z+NK~jYbljc@k)-~?tb&|W^@Fct~niVmDxKL_c0w({R9f^wZjLGR*5>DbDbYq3ImFE z!bwLci-#g-4>TNJpGQcK@+kE*-g|E)Q!Mt;E}65CYj|_VQj+a@f5vo7m^=b2t3zkZ znOR?rpB4JOlz^m(?_m&U410=tz)KhJHJfxB(i7|%;REYIF?$Z)gc?TiL2>3H<*}@v z!qMpRC@?p|HNYd%s;y~Xn_IoWL3YKM?OfU7i{CH_1H^?yfZvz#PTiNDx(TJdU%0$c<+e{$9%{)BLWzx8+RqqZ9 zWI<3}MYDsacOKMqT%A**5@b3_H9he*pVO8z&SjM;x_k6C{iNG7`CEPAe|M9Y&=CL+ zg_W!0Zl-{hTIk_NT)w*HF#5h`b01BzP=g>a~b{pd)E(a zO7rY<9lMJn1uP^_`N_7U%ji?gk$T58^@<9Gx~G&rP_y8E-nH|JXAd8sgR4(mWjgHH z>OSvay4_D#(PSh5Ft;cxdC_kZcSYzWEcoF}?2y|mMq*{XWGU5+9^y+A#FwRNlYdpU zL^z)=@GyAx8TKGi^h7O_b7Fc*Q?eVlgy*R+?S^n|Lmz$ zDBt$%{Hg&ft&7%m@CD?zS-_cfgk9ctr?nJ_Y+h>ra5uv5G%mtsEyiMJJ}$F_n?PmB zkQ!%b0?kYMfRC;wa3{a%GHpEKncI#Z^2P%g z{CYD117xa~evm5~&VWu7T(DGOsIwXM%Hpw{eMX$1Anl|;(jv06#kk;0+s~V$u4L%?cVjqQXRt_^SDF{$MN)UAx-Y%Mb<~T1*X!m> z(&I|QLjuIS1DC9{Sj$Q{wYj*k{#O+I`i;omOO-YTA{X zwIaZuB0H*O9~vVRENk5nBR$rKFTx(bS3dD9fLmyG@S;dnnHIcCS&K2R2LaV~7DnRhY z&(Yms$^QUKe?&)Wh&W*}2M>Tewcjdr&h+?AsztYUNq0}SlS#nqam9JP2!9-8$^;Tp ze_>y%(^2o%w-A`;ZjZ@VQ^{LU3%4+{t*Vx+43RL5e{14XUNS~TdqRu&XniGYUf-_3 zxhC)mRr)2OVT%Q7HAjCb&95%uu4qx=;As<1%=Bmz;wppAFxD)qJMMGY&|jb`n)BI9 zDj|$QN+G9YsS!820dU)0@r9eI+DhnJJ^V_i?uP4WMnI^de${oi%HW7wF6kZHBk2J_9MZ6t>5!mZ0igre|42@AApOOMOTK4 zOx)h6wT6BnHai;lS8p6f9|vfeyeTn0JRQ{tIBi8U)uGNM9l2`fJ@hZTL~of#tkFKu zKoi4X@vT=Isu|r2i!&ttw|K;1u(6uDayOlb3VBtCYL@D0*@H>5tb>`Z!tGyA^UgbO zujKG496%yJmg}o)9_AB9aECP|h9;5{xsLTF_b9WH4eLFcO+_(~L&nx`G;3^{xFTOZ zK4Df&h@4}8J)SR+GDV!;DHwHM;`jX+2I6Wk{G54$B@^Vdx&rJmpE8&MduXsSd>(sr zjJrNr(-*skj0Jw-=u*MxDg(LG->)=oQ|6%8a%-aj> zZaHV`{ajv1wkTB8H{^7$a|J)bFZT)*K+ne@?fGqP0)hSFm(q@_^aI1jMIfI-^#@Jx z?oyCTUtES3Z{yyG%h_Amcf3u9Z7zMB1y2Sg-u>uEl|JBuPWB`N7^Q&+sp$ITO*8@# zF!5z$;w^DEHd5xEm;dgK%(2vej4UyeUHIQIk)=gAV^#UzJBvhe0IPkRd1z#H;pWOf z%RS|z?-#C%;bv&^0}b~LJ+~#Cdf4#Fy#L7DWF+o9({A^*34cj+RmRDSL?lmt`&dJY zbu%t*@tGp&ePg!7J?V@>f?uMNfG8pF2C?yXIB0>+`s4ozL#SCAMK4o|$>$7Ugzwu4=ft6?4HD+=wZ9=FJ3R zO2t*G&Z`@cV^Ee4ZmgB?mgAN5?=Fs&zhG7UX*4@e_v2+GHf9e#_k;D;zU!|2`FND4 ztj+;h)C!GOwY<2)1+fCa%*mH@)nv6%2o2kyQD7MH1;_ICnZ|j$n)(r_IPzQc3(+}fvCxcF__{+BqpT|_s>Nncf5A37@{z|_shC23`piNn9)GMS z+~9-}RIr*B9eITl5)w|51kMPMuix3>>a*Ab-%JP&K2A?hKZ3GRHnFXsDHk;dJ6lHr z3RZK`Y-9(1XGOQ^g>_!#j+?`AxAZ@qWI}{)i$+^TaIOyJTkk9A*}|hz)6Ro0kO0Lx0<^QaV1YnhxeM6wUW^SB~n$fSL|W ztaX4(@qpZHO{)aKEhbnduOotIJL{VjeH2IuymZeFR~=I@hHNwcq_7%<7>$jMR*sH{ zs}p+1rb`aThHadPlg7Tu7F3deeuY&n=NO9t`W>6vuByIt*-sXTLF8PmfsWF~a6uV1$WhW__bwaeHW#cnxVQ;FQz)%d3#Ew01S{)Ss} zzlb8-sF}De37!OPhuIlBC}ty$nrSH1;nikOjnB|)LctK5!X`Wd42BU?V#fTXf^t~I z%>+*!T(?9nv#S%Ea3SI%SqMn@?1^GN0hyBR`8!-(wmH#!{q>#%w)GL!NQoBI^?Gg; zFLyWz(}r~YL3~(rF~=aN_@kFP16tMyxmKs#0;Zb9KA)?4dF#wgwR`?k{Kl;3bTJ0^ zA8f%hgiHnFn#dnG?e`x<_m6BwJnzJl7dgE2dFfAR`rji99P-%}giE904lUQ`vfy2H z(G>JSV}bALuw&x>JSbVsKIQVWux5NPc?$U?riyA_3%eRF>A-$pp^=JGPcQ$2_oR^m zwd4_V9s#EipF~gNSt{P2%kRG_kbEAlb4)u_u78z7dir^gw7TbgBgvz;J+C9p2Hx#~ zc!%*?n}RzWifW%iIy@DL&zX;l^w`41w|kINTMQU)N2JcF!@t(RnZ^B(J$SS`-;{cU z*6YZ1wUi9=!grzTv5r6yt{p=5^ldZ3@EKm_%9IlUlc3g6xSkqAM&*8Wt_Q!FP_~TXOdD_ zh*i>52)u7gW#8=nf@x7-AQO+6qgK?ME@zoYzRiq$L(jm1nCRjv0#lRxzA7@dPg0 zV&M8)c)gFS?2%Q|`hZ!&!OG@EDaWvVB%%wtdt;;#>a(}|Gz5V%tFFIIuYhd&2}!P9 zs#c>rz;EIG|HyEPcUu{vgs45Szh%Y02H5>cN$&u1;tH3()o_4bp2)h75>4I#q@hvj zJUlLWe%`)EEiZ=sD~k?`TFSSc!CLko!vO8fKcvCc zS`jqndEZzh*`ueU8Z|7WLk)=VwQ%13WPryYx8g08yiORVM@rZZ?)niduUTN>WDp|f z7n0BWghRK7tnF@}FA0V9^N23N%U-SI6)wyl`AjISpne0R%OzI6^0 zP1x=@RRpDa@CVh+I!aZ=4*aCc)#?bvOkQ(V2bjrz-s}-JWytliKc<<{cu?z>G)e~3(>Y_OvdCh^)w8;leX0HZS;U@f`{b@{WZhUAN2K{~WyHqkaU&3@)k!@@J(5WX2E6KBezq65(Q9?YrQVEa3k7}OQ6>I*!w=@|J7Mx#03-K0Y-Q>IUvZo{>TNVpXqL@cXu!k9= z8pVLUZ4L7q9t@J4D~%F*4JwIrteI25tZU_Ip@9(nRVb?M77I4Sn;JkcG5bx zj88ufkk3v__91{KUstdjL}nP(R^-Nimj6uA+7wDkVydS=fv@F~da=Qr$v(_p7h{^w ze#UIROdHZJEFjtAq4yeoI!{K)yZu|1p!MK1QV2O#Q<^YvDjg=|VBP3+>x4HQb~^W@ z`19mv=nmfz_plwEC*DeS^R%(P!1N6z==ebadry(sk7Hr161M3;n2}4s^TbQj!NPbR z{$hxvq~x&i-tfF!mn+;^b&5p&y^*-B1G7GBM&T(lge8?8MX#ckCrA3TM;Ik>uBlDX zvqVM$`pTrd47n5Pb*XXcY8%iUU!J!RGH1SB#KtRT_G6g{A;6`W>2!E}&R*0HJ(izx z1$_v*XEm1V)Gl<&`!F7hDY$a18R6Vfum1^s(_eP=AGxBhR=^YQ|3~nkWFlTdGqGvWF2TIEaS2pD$Q>E=tC)Jc_)}{^FZ>#1|FK z{JoyC{SNm}RQ4kzN>TUkMdu2C`u1#yt4r{4Y2_wCPDaa8E~%R(Q&)9b9vWd6vm z`k-^!g_I}qGpBCuQ+*2I&tTt0!M!SQK#NtD`p73+m9y^y%hTGM5WjPy_Np6OL)eDn zbygDoH;f{=$A_j|fU(A{wO+xN3mAvYQ5AB|FTiVU7`H#=cI#yQ^sDBQX~e_9+4YSl z8I$xGeV9X;ZF%nN7%9%mit6q4bC^wD3Nxo?gDf$sv=N-#RHyiPl{6{-4To3`7eb`> z52i+97uzfER*b<*&a54$+%C}4GS%toNvG++k=cdn#ZVPT=~K!F1dnj=F=h1qH68}O zef)9?z|0Uw<#r!2*RyDYc+nHHMMu#A=h1X22-P^O;NO z4hm*H6=LhSV;t21;0l|>Ql*vi3C&#T4+B7e;qTaCD(tO}N9Jc42%dQDx&_j@O>lT| znqDPs5Wly7W9-Fy(N^xCfLH0M!&uUDuZ9GbS3KZ2qLjXhAaq%+;D+MG-otQl_j}Qr z`gWt7X;0t~^+iCg548EpgCGRo%fn|g3>#;xOtfw|GK&{|8J)QGP2YI0I}9lLR?OJk znom{pr(jn*5k0?CmT0i$L5kSmxV?maqF<1JUU~eioVp?6HGuM3*HT29Zt+9;sA0Av z3{tjGRU9M@us*ojZbcUDjvVC#AD#FTtYr-^>>A&qj?ZgbGOGpy3Jt*X?!Zy5iS2ml zz@30T;Wp>Z9`un9w}iqmHHJsl<$Fs-(_v`=h;d_ov zp51a68A4uQzX{S}rd0XI=cE*Hh-lL+czLT4CxhAwI7%Q{G-UMJT0ZVJM&-Gn#;VLu zjlvpzN}FkPcEwjr7n-m0EPk!gZg+j0Y4{=CJ%h%fM&dl-5u$qJgHyjf>rS@&$T43q zdl}HCKFNy~p0DS%fzNMzk6R&E^PY~K1TcD$7*O`$huQ+bfm%CsnHC&!hr(Av%vDFU zEik=0RYTpDqJCR5?5!Cpx1{4Sz&ir7k4;_Vo@rCp6vSReC#g7B&twzzeNt*zxb$t+ZR9u#ZJp3nw9qd*QAr*Fw=7^4)Z^K9a=~vz)S)(e z9D$~YeV;d&KgNMP%PW=Bt;-dDfYLB$+*jIWeOqfaB`>}j8Holw`*9}k0e#Nn`1lO( zM8A?#p;lb5-}2t66+?ckqf=N^;ilk5ssKf{8$3hHwMJ=R%0%9Hm(nV|Dk!%gZa>U@ znf7qt%S;_GM3)U~^F)uH6g8^9@7d6U4K`o=B;aE)wP z3*stPxQ0s<>blWoYuD~5>wrZ&d8lKFyapg{c(X_}c`a`x7dGL4d;cZ&JUNWhlmRVs z=Kn;^|NJ^MeFV6W^gmwfy}hZ7lQ{-6UiA2_-=JmRK<*rvUCs{y9?_~(T6cb5fewua zCOIZAa&nxgVfQ$a)Nx=!(8w~wSM~(;L@Lq!;HoxpDeNYUH`q0l#D^x|A+^7Wx;6ph z`lDe4fnFLS2Z0%&S6=u_#MI)jcTLu`FNQgszMu^2IFiyT?Mozk&y>Uoi-4i!aWr?~&&J9W}I;e6#@B z;M0Mxg0i>6asH<*eoHrTi9UCfO6qKFQ@j>!P~=SH*vrb}J0?vi&(T~H_{D7xW-{NU z0Gn{lXGzk$_wee8iDQQH@5aHgy+GBV^=P-baY7mb4g&()bgyrQ)I%YUgQ76BVQleU z)+7*>`O;YDphAbWAXS`*xh1VdjNkN9-I&o2p8EU5qOg`qIT-NO(zPhC!bLEBDVKIV z%RLNZ%TY4hajhzhB2mWuJ4>yC@1-9s~X9x77#uV}b$IY*4~S;SVU(CiDw?9UUP*hu*Rf7Goot&gyx)XrRbt8ds+GsqkgSVUhhuW0jN9e)}n- zo`nIbC?@lrnq%4Q^abYBh>{rOvJ6Zy-1RR-(>t%90XZa471g3gn%6S5zAzep^zgM4TI)zu&b~{EB0?3)yy<6vaU}Cv#p;P?eE$ARxWRB zvRVysW!*y_b!B58#nMWTsZ7}~?%4EQ19kw*{$2G)ZT5X|H&e|C3CN_w3y=A2VAnM1 z6SmIAo#~|O-XN>bZa~Qtn{kpmSCVr=GxkdL3A+e7LVO)~8w;{wr{UUukl`;wv-$-VNO; zqub$Y>t-$vYo=YD!9@d(%bWN90liHBtU);bs6jF;xy;o6QGEOxSGOA2fu24EgBhsV zIKMq)z;c2z<6{yTC*#Yp)hzD*brw(ZE!>Pb3}H#ReM^G5B?qgN$1Z_TdeXVx9+KLrPNT z?4Hr*%U>HRujlFF0swXTK=D=rU$%Ae&=iW+OH8bF(Cut9Jxahs-jR*DfbjKDnN72e zreH!nt?B-QPgN7NleaZc4sAp0|`w;`@25oulhm-FFvBHBSuq2eqSOx9-XVE%m zY@HV#%?xhlQVAQGI#TpT-9q4;p!Z^YN1>Yzq)Y1G%u*sJ2Y@=_88g7!Qcm-S#OR3x zCKOp*i+pRKpUAFqZi z7%kVLOO82B;M7{KVuP5`E7xxKt=k52G*oRW1#v!^J@PWDht*daqTb}wxR>yEn{zjr zQ3pA9P!S1|x~UEZW+nM~$EnjXlEJP(fbp-P5%ZgsT`FX<@7X%psf`UBT2^b0^JK49 z*HKJ$#2hH>oEYgJ!xalx!q!Jt(kGcrW=#El9Ck?L#dMPKaCg8b`fI-{5eol*rk0m~ zq?Sg`{=ok?wS2?}>}`k*1{|zrU92t29`&@h({5(n+KHd-J35PqTd5Fq_AbvW=Bm5T zW7bGAG*ddc;9gtDTFJo~8)z+UVDFVt`wJv6Dg=KvCBtKL>^D9*-rq0_7EGbAvqs~= zcsi&(b|Fk3PcZP;{L%{?@4+4EX;&B+v|)%jGjX6+pfJqK`~>dzK#p2yRZT=@`I<^> zN6PRiNn(VPE zXGh8mYBs5vO^bzyJrQ1weBV&+)@G)DP!F`Ql~Aan2!O5#zB2E=y!IcM3a06I8O9T;FVN6*CU8V z;#9D_RP)w_@v<+q!DNSRez2KO)o}yY;w%5deQ;vSsiN$gvWAtupS1yrNA<~jR`(H? zKD#Z4;va82)*FwS7n6~6LG{Rd`^9F>f!pY@eS|!?>R|KVZ1peN(qu=e5_t17vw=|R z|KKZkA;Z(13s9GyDJ_PsiVN8JavSeDSRBsio9$!_^*h!b6vX|35%94v-#T0Z!!9UK z&L|T~RA#5vBv#&*U)?H+~$g12T?P^$fKs$a!&)l-F-LzKeC#Q)$JoBadbVDbD4ZCh>y#L%igya=P zA>H=!QPe6bIY4>N?*0=Gap!Le9Opn?K@VbbrqObOST+l3wgKIA%+f+rd|50b(pItK5tjp0$}V zk3N$x&!`WcQbdrp~xao=u~6C?bn(jQA< zE;ti%4itPdUKH2}T#Jn?L}6RyR8h4B6O$r+eZbkXpDns-Nxz%Cn?nd_gUcw^KF_-{`)y?vI~QC`d4U^X?T ziR2l;Mr3D04cj9ozO0xh(i1L*x5S8BvjcdH#j)hyAmAy^b$E4qhIV0m)&=<=qWhm^ zNI4yLpzr9q%cbbeQY8FpRhiMt+qYuKjm~!>1I;Qu zhCF`9amLT-#VjpAtzS3_C#{qqoshEyo8K`@eHb=9CP%c@4GP;Og9+kyJ#B(p+$QyT z7e)&Pz4jLxs?_5g%Qa`7%-?8<)&x0sULI~ub~ZgB?yCw23foYTM;F?ZH{9GEGb_h} zfn0@cJaLiv`U(nc+1`qlfobZvBoV0Y)-8Lq=6YV{ym#}ym(}e5daR%VUE)Je=9iCgsh5+$D=HxTu>M79&ssYO6-cCJwv@r4z zx(4{1PqArJ_YKnsv!E9Z0?bq|dDt1Y6Q!;Kn>fGD$TD?vSTl$)xN3E3(H6*nSAj;Npk~&2MP|-2KA>Tpwvp5v4BR9P$ z?kV|omH1cp$3fJAq2%cV40xXosROCS3{F7w__-~#RsopVoVHC44PNwI^@IAQGtC z{J5A$nOxI^DL~%$c18wZ`rG{Y>qR z)*@c`$Jpv&ppqZ=6Jg#9aJAv{ACbl|V_+zDH3h8r<&j*e)X=g+4~ABdtK91yA1ZK6 zo-{ym(^dJ)*on`NDx*LGyK^a*lA*CPqeNQ{Us{4yqNx`dg5A50Z}Px`GdZ&JN5T7r z7KSt06nO+zjfj{;*A0u-(uS{)jC0nP5}#0w&PSAnxMEbX6kj;EimgX`omNBA?^!EO zO23jtJy>AzF#U$@{vo0u@8BWBcx*!WJ7>1Q_zdUWiGv!S>fZbaad+oe8u_kE^(Xxd z_0D%op=t}Q+pY}8aIr0LJMDS?`r;GboElPHQSp!sNY(x&pRJ{Yb@qy_=yMt_{;r3y zsn()+b!BvYOEV9JL}fa{fcRY~X9mI!BK#X0o6!UH=0);N+L2#O-`OTllCO?k@eQ0# zJ?n4MY7?_iy;qgBZOAB3c+ZnQlrod_pG z{M8Np1i6pEL+Uv9lYgX`?|**IdQJy&jy zFIJhj7Ev3MY)Kw~XMi)po5^C}RlF+mk0nwuu9Dc3rVw!q zDsgMQrBeF&$%g87CZY_YO`)MNB#60^l9`|u`}bIu3yxRaAh4@#JOF4Q`(c?LN zAfd^W;jGFrB%BW1me+4Bakv2d-jVaw7bQCM4V#rLqY;rl;eJ!AobnXL&`^{^f^5b# zPQ%`H-pt(tK)>^*Gh25TkJBzL4?M)V^nls?5UbI_B%bovb^i)K@Ar+>OjpN8 z`zSl7miK?~6OoZV^!0MmnOXmIlzPJy&$t_L1gNBr_LEqb{XQLus(`ZEOId^>hs$Y6 z_EIj|)L%;GTa|we&^)aDh6bO6#RkMnTMPy2v^Nb(6}yXFUoITB%g`O)fc>XX%dtV; z0e5}nGy49xo3*$kdWWX(1J9*pqy2h5JsE6V{IDnN?}IoYi%0KEx}V8x{8liKv}Qym ziifaW6OBnzlKfK!p)9$RL9`FoHirHmaXlpu1J>|qY&zhwr~rbB31{*?%=JMui!y93 zUTug1GjQdU;Q1Te)~)=f&ds#)0$b$a{B>!LWE_X_ObvZ3`HAbYcfM^jJWuyRQ%s(- zZ$L>Mh1!ZbxpPc|n4b6lmkc>KHL{%Xf$l?|+V`+Qs3 z*;cq3+sg1?fIf(Wa zkw8 zI;yFs71@jLrW{#}_`}|nUNm=ZFOd3_5cSpC&a9T8%>wtsYHAZRF-G{ryx-rgX4R(X zm$wLy)D#yJOo@|vhu@UYw{-V|D~UZwx)%L?Vh~sMk9`7sWHH=l8Zxc$;9%6c_J5Qa zFfRQ&np?hi`Fr^9J(+)(Abj-L0FUvXhR~A}4ZmeSCZD~$^5(mdlzyw5!^q>af|hs0 z$>Bg*cPwz}DVZl8A(i?|pnn^bPKVPM0;s?)I#vX&QU<hW-g7@l0&D%WD9fpa^OzGn7ShLdpS;b z?KQU3e2~d=+fK|;xZ`s&-X$t;;-U$6X+fnGk3SAqLPf3x| z_xj9UUD-JY`Anb^gLv=us%_syk!)I~mn{gk#c;_CW|_UYj|g4IuCPl(MPv&0deu6E z0YN31iYpXfC11ipwW%$uQmCIm8IoN&cK5H@v@%Z&22{Lq*5%`OZ?a(to4Q$w8}F{;BT=hp_G`YqNTg8JSsVX>RyWo(}H&@ z)y@>y0d7}eyfNt%D`H>ioIzJW8n2`)J)=~Xp$t!~<%nC+W& zXlZ7UbYVzArJYek$eIeC1Ur+^(%6LuunZ)?yU_2|zrI^|mu1Yye`8oLMgjphS_Sxt zq)XF&Jo$&B`t}b+RlD`UCh7kpi=_O-kZZuRQg6AAGQK>Pl{{Jsal9G|m(hWEu0$RW z)V9zvYc6f-uBDeQQNwxye#gu2bW!FUKZF(lcGKK;AolY>Cv7eRIIJCl4@?DSWvj!A z1= zj|mudW&j)lbht=;_yE44MM*Vj_N?pBdT*O~NL^tR+PWRb8{qbCum?k>Wnoi1w;ToHj?F|T3~n`sU3S93>py8-Y2ie<-HE-A*)iT~ufOv|iXe5@amItYMls}y1SzIB!&D_K zq?$QXA4x=3BRG&?&n8mldMij>$+F^B^9U{0#r38PZfOn#2!X{$^fL~3Lp0Y9=YDcK zgBw>(f1fxN3BD7hiCCb|M!U(ZB8R~34{<;JbZ*miH3K>yPsBYI%g5I#UwYkMZ#uUV z(-duA7x%rRA-(RQXMQnMK)S`E__{}7N%8a9DC=@1WIwNb_U9yb->=CVx%!hbaN=as zhOk{e>2VeB6t=*hUI6c=bW8?}FntUBOL8__y1}a``hYmw&P@f^fVe{jYybV$)>iR1 z3$pf?O@B`>+EEyIL&iLUnX795x29@jijO76m#*J((JAY_Xm+QnHr&OQa^K^lMLy%} z9qpiX$T(3V_8uNNrko3+ckK%Qkh^-!W>0*~NI%e&eGU5pM{E9lCsit=$uMTVGg$~5 zrbAkrl);`Bi3w4}eZnYKdWLR~ISdzRGsC(CKwk{OCw2Toyd}z7zQ8J+Tt{MO0XU#r z?u1x{OLP1?F9}ud2%SAzbm^s zYNG@PNK5x*@_v7^l-Podf(9f_tR9`Rhero_ z*Hx@>`U96n#TKe@HG7nYBTBE*Bdt(JXj`jWT?h9Evtlq%<4F(RDBiCAbXU6-A3jqKtK{cf>nOL>*2VAL#+>d}N(^j7<9 zfRUqsok@Go0e|cTZA0q5%3mmJuEsy(r<}QO2mLRSfd3jlfsN#Vr8{c}r#_ey-zywl zst-1jj<<75;oRwDRqS>6?*i5E0P3VuS*|d_T|cMEQM7)1xeG*g|49K0>XYlQu_i;z zPcAyHyX9f`h>hvd(pRUGGe!Qc;9i<*U@IGYis^j?BGD}N`A20yy$m&T6St2N#Gh(Eeojb)YPx1^ z$jw_#e@dAVe=)Lm03W@7lKoS~B*38~-t$;<9 z&AO$dPV*S~7n-SlRPq|$zPe1Z|sX}Im zaYUcMPmQKKYw12|0@B$V!ao{uE_@AondJuDkjq%MvC>Ni?Po zr#vQ7R$&wZg4nWsUM|SCqr|6IGpzc@e}FknlVn0$zu9p2%toF&)JS(lf0fAEpYxsu z^}>g0jvgKu9(Sh-x@){D^!3+JsBQ@_oh1TAly%c<7lb*AV3alXQex!rpSNFZueSkf zXDNpQ)P-S_z9y5U63|5+>5DmA>%7%xQa49hH+cfv!@}S#%8mD-aW>3-K%BoEsoJ3f8p^pIJdeSQ0<dH(NIuG0%I5)gRk1Z}-%s;4nQ5 zbWd~ag4?P=SA75GBN7A4k?(9@e#xTdqbgDlWWhLc)HTZ{Xms=NT=|=*ZzA!t>CJRclp0Ciln&zz>zegxrAp?TW3u}kP`V}7+6%89Vj^G8^xT7CxY*^3kk&= zpH}}eSZ|-=d1ZWwUAFFmDVQq90U`I>;CN>Rkn0#Cexd5h7+bCoM(y3}o&6>7U+GzPz92N@dnEK_NnP z8~iXR{hYDGqq0GC74#Ug+GNfrQeZv!YRz#Gh-2nL(7g&QRGe}xr~oNt=iMj<%XgBw z^CQvz!MVoOtKQ3>O{Wh}lz9|aJQTn0W7qzKrj>uQvZLAA&$QW!q^V^FRNmew=h#TH za?*W!XU4M2!1}WmRjC6bA*}DUFI7l;vCuFIoQoZ)8U!yL7*;^j_}{Jtoo!5(l)BR? z&^!!H{j#Pi#@Vf_FDk;Uf5K?+`qUd^+CKe4>=ZaT7%t*Vx1H*Ch&qx>-Fker)^j~M zJBF1*SjHj}37cMdi06)$He;d+xsu+f;?{w%YliEW%h@LDi9_G+upbDpabIt48E(z!q0b@WeTKpS*u_<3;Gspv|QCyY*05>c52$fw5f ze5||CoM@HG7aktIEMisCR4owHJGv)(8f~+=qIGmxswB3_Y?8+yu(sTVrmD{AV8eOg z)xF-j_tp|kBgAxikjVfulY4B3L`?7`ug{+hri;>>*|z(AgNN4FK&h`{ z#&2Rlf?5MH`Al<~G2$xTx;S5Z_?mr{tiV}2Bf$kCOofAm0Y9`@Tm=k!M~yLEW4ahO zZ4pOUFa`Hj&QL%Ju>dE2pjQ>4g7#NbVoxwl|AVK@=$gr~FqGxbr2B zMZdk6Ip|drQ@u7dO)tPcD6}$4hRfkN0T_W(r>dY;Y2^F!nYRe%#6!U;*IomX4-@m3 z2GfGGfbnStoonl1{+p|0LP{TMIWbvQj*@e3#4cDSoPh*i<_M3#c$8R&{|)Ui3HP)$ zvqf$%XD8b;K_@Ch7MusgvBXCCN<}pG!KQh&o2rC4?J@GysPI=utU=_P=#QoV_RrQC z=-1fDz0M6~>+SH$#{i33Mna+EJ*YGQA$H%%O z$W`OYXC*s=lrhh%CxUimsisFn7E!&tl^7ZBvg8`(_nzpQcweo=3O;lD6`rY6!b=6h z7C_lq?2uA#0?n8O)%xqXTG&SOPMRng6>hKPDYkmuj%|G^ovH6QCGBf;6_s)t`^Fj8 zy=AIWzUju6mTki5jCWF6nb5_Y3vnXrVpN5(<1MF)B8i--qHE2GQ{RnjFeP{}3{UFHdL!kBN%0j;q*%2J>1U0kDu>rs@iO!5M> zf~plK+!m>hzKnBtRvd|&Ro~zV@d|dWmC!s*oiqdxE?4ZY7KmJ~lgeH}%4b6pNlDl- z!wyW9n;N@t@xqd=sN`ljpy~^(GmN-%0bkt{jQKY&?i%*rpR> zab!+~*EVT1ptnBskkMfyK~Y-%C#eGCvBz9*Nm$MIxSu#qTI8V|VydTHIb<%d1aWd- z)RF8NbHNGUkuSi_WS^=i!1pvw*7wxyjS;{l!2}~kq!^wS_Ut3w)IyX7ttq!x^c@!; zZ80R!YxBIVcCCfvGoI^cw@O4tr;B9U(m{J{{y`@n5IyLLvR&GwYBL+Aj&ZTnPXPT2 z*76;d-OV52?|oh&fCNufajo5%A;%Q16QG+5qU928B>lmj)b_df&Ia?=&Q?hI`m6>M z+R}5AXpu*N3DvM&u~p}>b#=#mhW&2@my6+8@*kcMruv2EUvKRHZZtUGmjE-#tI>*- z6C=*k{^^E&4ETt^1eq^SFBRo#F>{P%VxDzF_JUD-=8U^jupctU#Kr(+a`#+vwXL^(hxu+qH7FLu!vjRLM*KAhm4ZP?-b9gQ8;H}~G zKr3WWw&DU5me0qf$5eDQT&9&?Y34=EJaRGPP6D(H{mS0EOXf5+Jb!(X+(~-r?2}lf zucFPf)eQ!BmfjN6Z5yd@Y!BdN+Vi$Yfkw%_Z!IP>lqQ)mRxKUK@f(V_jMB>7$HJqY zd#rk~z>E?vnKS8cpO^|t z2^0zV^ZI|tdwJaVMCACV_eLPeW_pvi zI4Fp(h`hci7<1*g>StHo(InU*4r=}NwO`K#)DYj0EamI|l6(g1t~3^u(;qW?1wXY3%4&RV8prMl6jmms{~HnQ3Fo=?$G-vtHMiYAvV zm-f-Cc6|3<(X;o`bbz;alcT+wuO(~beKBcCWOB)X1|#)P$glY{4^5(DB7FYV&D-+L zRMxq2Ecxsum^g0j7hDP$!#>1O?6FXq(B4wQjgLz$!N~MK))7NKmZ|C^PgJ|>#-c7E zBceWwjr98|kgXqIjpRNh2oOhEd1LOp4>r&r>3pzNYBfHbI}){1mHzf87A0@ji)ON2 zGtJ7mYnS9r+>^w1`rJwk>^Af!fRDvpx^3-;o$+(Gk+IU-fUSOPG$Z?i0G&j{>=oHe zeluGM`ocbO$!R46*){C85mhM=(f44Bb@i<9Eo&l#pm@;8E&N!A&-2A9xDZImUBe!B)P&vo(IocN^_-s~C<+&W6i zptKd{asYoS)2lF9$&KSSA4U6@?oK(2rOFVn$d;jEHO$HQWa2z+yywrm36F!0p(GuR zV$)|&KpkjNlVeB9qU02*l?g5pNL0nDC4cE0^8)`ObtA!Q4;>iT{dyPndcU#eHs5kz zem~JsRnD3F6>LBiYC3{)(6k3eM`FeLAiGcSPsr!0@gBwq#h2!&%ZHDau)}-w5fW3l zH})xNn_BpE?=rHxjaH1<1nf~Mdhi6{N*3!yM{gr63si4Yt24S(EaOSX_+OeuRgW>p zXzl@WK&Fz^BAR`mERV_ovTJ4vG|<{;iIC&UGRQEO3E3~RK)_5;oK4)*+T`!w$X`Bu z1r%$TIyURvJB|!+ST0@*mQViZ5EbdWYWEyww}e{qjor(G&C_|va5~1(n(DW>y$gJP zXtnptSZHACb_t)|Xjh!Xj{zeIGy9YL;0ANVh1Zj+L^6WTzcpg|d5FiLHBrB_>9d;X zLyoDoxh1?D{OFC!So3%xo_7%35E zDjCJnS@D%dNZt#ypqYJmNoqN73OfvFdLsW~PI$|%%{<9%<2Z#vK|O>e#LfDdOpDCj zFxxLHA1?hEkv#B?7CS#(tfD~jv~(YD6k(;@YpZU1gLqNQkxhAbHZFK59C|cnQ6@!t z!@ zjFZq@R4BLUhYt1JA?q^yJl1V|_aW#-kmv9Ov;7rpsU185_WbL(nz^+PQY3ikr7$9$d7{djfoyBBk+VHDmsl z!^Z**e?iB%8hx(ItK_YEuekp}Q0WBeBSE}cDYd61slKaqM>BhKo+#*!BD6O?^VZm# z8e4sU_TVqqusxq=wl3*XidtD-H2wKRKbqD7Kby=u%;74)J64~;L>fn?Kwo#nSARd% znw}#ZeY+gnN-fE;-KwL~O{#BFv|scdfboV|F9GXehok$#c*+|B!VCDi19cK%`pw9( zE_z&wTs`_S&79ub)=L!QlTQmyQu-5?bSdoc0?v7Z?^pOfK|$%2Hu%tCL{Dy8 zXaS^N4x^;8jCE|C7z0iJM9KSNOyMu3ssU(F5Ls-yz2f${2YHPsTr;S)v^`DQ;cS>f zQ84QEou0APw}GIA3HAPUOF$XZy9{A&QaxqZTHIaCpfm8|7s>Lz`@LV+30mni zhkzS(f;+65T;TaO#f`{P$;xcsk27JRTjm zX}t5Z-(tLb^_$6CX&~KpctD%6-IC3e- z$IEy*OU?I!;njO~wm$9-@!@$H%~1UL6f>7k=3P%Q2v9p<^-dJTEJ0xh>;CYA>-6Cx zk^SJqCfB7$5&0=mPB-XS0e58qR=m!&55Y@cs<<)ZH?BFM4uXuPTCepR%CXT^|LT7F zY!Pli6Z`TRd5!A#!ZxcYt&27)3cJzdXU)UMMniRHy_K(;sftfvKg`9zxy5X99(l%B zqXe1ORZGk_&gzRpmx%g}bi4(If5HVGJ3L9t;q5DFv3$X%ym3(9{5b)Tay}tTaIQ=h=}Oo-k+hs zxT;rk&nGoV?e;$NxGy_h*7eLY~++7?DlIz9IuO}lmMpsx9$`2I_(Kq*G%S(pEHy`T4r<>8)c7l+Rv zLv`eS=#;I^(@-gf(ag=Q{?0mjxt;ModMcAyx#F#jjc){_^v@~3HNk~~n$3G-CTHM< z?-VgKYmpwtX8}*VILu~6X+QOyTPiowo!77sx7Yj)JL9fWL6=wLe{D+tbNzF9p#tW0 zQ;(}uIKBUH${u5Q7R0p9-$?l`zQU}2iJg7X%s%m6`%ERWT2?-gm+4=CyiRNghzlJx&A5 z4*Mf=6AvrkPcJHpo^}FsJv9#oz7q2CB@Q09L!zi?*XcNz!6{1$qSWmVpevE_yA0;! z37pY7HYDw>CDI@2G82+%6Jo636!BT`Kg>CkSz-Vvl4dlMpJ|solQ*i}ZLz#~%8LUE zM+Q7>j<~^DYO8AZ<~UC!Y-2j#0>ZLua(Kkf-5y!8cM%pTw-tJgF}7HAckcDUE_o zSsbeI^->?Pq6RZkzvS?@@1$RdaDtpxMe?X|)2v_pMLa1HyUkt|0E?kIR^bSRQqSN< z`ULr8X)Wug1AGU@!mPM@zBTluUcYD%FQw zroP@)n{BKh)T|%A=O6zHbzM|znWP`hRmwW=D3M^cN{bq>^MbtLihoAtuMRHlc$zr2u9%P43;E za?KX9H0^eZnkHpBeS)+@!y{CgZWM0&dA5xeEA8&nNlnJJR?>DXVQRbzUf6{ipOF)ERJ@1|z~-J; z@=%KMrkHS%sQ=|}7oKcNQW~>^{G8tx8|cQqq4^)&U+|+UW4O=BQP3&%0trl%nKba( zEZ+b*YzXVj>MFGLSIq$;3dd5Ej-&d+Jj+B(E2`JMouD=8iu%6Rf(MMTdora&XbP-D zvrB-C63}A6o9{|qwe*xk?6#401n+VY61*l!1p=z#4L|Dqjh7_r5Aqj!D+n*9`Vjh0G^|z{wJfABRk<;Fb;HV91DS!J634fm zr9x7!IQ?>6{#C<6$ZuJCfjhbC!}U#Q>uLS_B}gYIJ{|<9{*8}OxGay6KP;a0S#AuU z-CpTCSCVo+WnFOcCimhUp8>o)3M%jo1{=|m%2HQ;7}8&6>83W20zOSb80rh%VCt4? zeb@79K&E37?B)KQLLH2opF~ub(pmi^`9mBDeiFK`T%+g=$X=<1WC&{7P1NL*$d4V^ z(;7c))2J*5Hp(8=IgH0UF2d26J|{yNV#A$eO&4ZSL8_zkqJpiE0@L^E!e_LmZI%H1 z5B9E5u-wySz|vBIeWqkqesR6?+Ef9sb0d$>w{k!(%y=7CBR#AvwK<|qYH#bJiwwsa z_tz5zXIL~$wz#$vwow(S<1?wHYWLKSAH{0qW^2sl6K`rPS~`1b5fx4JfR~l9=+}kt znkH-a#OFoMc%mKVicOe1MG^H4$&q?! zIp;-!T=B%DSi5nCLC21}m?TemV@5~Dh#pAy<5nTMrHY(Mm$^_TP}i&h!4Wm;a+a)M zFtd-&?fjh4{t9eKG)|S0P^&+?lW5oDKEEKgb#hL$eZJ|H@E7r(gYkY&sH5ET+6VE` z{}B@EQVJp@599R-M;Hb+6?k>A<+qxX)tOk5)l_UJ?cSH}2u%7`@OHZEp)9~=mJ>j% zrbPus46jP3+z!3DjIe+{~?6y^+jY8QmgX>G;25EMARp+P;=J|Cv z;D4fe>P<#S-?$QH>2Ke_pUbvHY#h)sGLQ`!-iTsOO(uyfHyKY+hrLv>2fVyhN@XJdbh?Y zl@gPNmlO*T>}&grt|@o0k~j^UkZouE4dS)Jr$-MWa5V5XQDhP9ttf%;Z@$ZXc3K z{%Ya<*L|I>`f7%PmOt&6{a8tr|C~3rekjtIIn~mn%{-C(X|AiE z>a-lRb}S`JgHjy$DO-M$*S3>28_Xe$L2pQLoX$B!H51Hry8SVjF_<~iAM&I2z3I^G zc~417RfOD;EKUKR56`9Rv)~Pht9~}v&sx3GFR5slM8oSAP0TJj-p;5hvtT60EC7Gy zso=c)7ERH&fjIVx3A~WPu(1N+{ZvI$_CWfm(iMhc3F+S&xrp3qW#O~P7mNEN<^u(C zL?{h%29b%bl2H>$klT`ZISzRfVP_#rg7X{f5mu8dd}1^|J2)HSy+%m(Z*4$qCKZeM zR(9rerG7XV8*+p@O^%cm_!K)6(qwu(Yx9N?<;JNGa;t@?L3pX1vi%iGnJo4N+tG&` zizJg{C7eaF`*ZBK@h%&$u3-XSJ12~Yw`_AJuL zUXfuR570R7aysEGrrtE`t3=$V#@r8}sO016j*onDHh}2euIl*?*iI6K-UsGxk7|Gg zmn>le^}1ly(w&I}B=AW+i~Xzy^>9oyaqLUj0XN&NCr0nmxiMlsd$Q8e33Z%8K95p> ztgPnI!G3gRsiVt}M$WPFwt_q7qpcj3@u|{lBf9NXpL`hS-7qdX-NMeOwO&geMeC*( zM>X&IJ7_`hjuu!}Qm&4bPrCQM{*hrv5BYOu->uMNU}dszGQP9>4vm{bf^vK;{>3dx zO|Q`lu0)9c=s19v2rf<3KERQPK}U-Rmu9CDVHw6h4PANoq~WN_l5Cd^XC$2QqJvnBKoB{ z+LNAF^dnR<&dwoLDQBCWUY9fJPcD=Hy3Ch!ftRx(|9M&dmIo-8Br;f7coPr}AAaWP0U%R&w)LgL54mF+vk&`jl7 zV4F0&2N;EvmL2Q_OOU9A?Z%})xS)7@^3mW4PA$~Bd2v|dSuNaCL+O4G%{J=n)0YbA zA&n6s=z;`SzLhJ**U&mgk!9e}!)2;oM{ygd)l^A$O^?XsH~?b+sjkauiR=~iiL2V$ z_Q2{!y-ZkV-UH1;YS?`GHp@9pWr)w%-!3UBzVl>OcS5+9``4vWYO{81guNg9I+?5v z%yqTGN4e@S7ikhZ+Tcn_fUR!?5rWKJ;(YE&7Pr%)|!*{BoC%YaV#mnHi^~}qvm?pZgKIU0_UZRzE|8iBqj{z{DDK3FSt3&-!IS-C?zhsL=kk z4_N(ue&@>}aN`1R$&>&rfc?VwryEKUC!fkR6aujU8GbZ(rEzLcdUU~va}<_9vS zXVC<#&C!xvFQ-**L=8$lLSY5_LIUgPYeBr(6v+8+yz6oPxuDJDbZYLbr* z?c|-W{R(t&zJ~>oA}yUB(y=O0bDr)@ZE>^9(8{zm!mvQ1aE_2W`!oh@HsipYmep5( z%9*vP0^Rh$7Y@;FwwPafYtUfi z@rW|J`{>66UXbHF{V&bP=Ge`qZR?m~b+>4l7)6_xwjD7u2G=a|^yiixi>I3#90b#f zmJ;-bi@VF6<<K7`-d;(z|%0SN~LPVrlAw#!@yMCnKF!d+i%K@T!$RaWLjZXa<{KW zLYL5k;3omORIM3x1|+3(D9sa3Gw(C!&FHa1X$g0zW|_y=pr@-5o&i~TCQG#s~dS$i*Bxjs-tIl`3y6nqwa#sORv1tRhZW#r1M9k%l&cp?jXtPna^lX?9oM!=(l?_Nk7Bg7781fKPx|sQCB`96IDE5l@e%u(eXuR29bQ zCTQXnwSkrX$C0k%-Zayc29q}c2>Utt=D0Xw)oADEePYcTFb)Uk(>7(To%Ua7mMqcg zYvqHZ^e>%1Xh|Jmb9th@*f(S>=XuajRSF zrdijm$E7Z@b&(`MEXYR?5!O_ti96JYy_Ia4Omo(-JtfdEjlUt72y^B!<7T!2E^{+F zKtp&monJ=2&9bs*+bhx8Wc)4pH?=v7BNl6hZ3K?c z^o%*VN6j^KjfX>^b;}ND&xW-@!Q!N~Mk+>dZjt6*$fYaWIn!%D8}B`2fl$TlW$;3| zk)xn~?OdnJpAL?V@8Pb+Mls6vhZwd>vG-gfRv}9>GJydx@pfH4rt(XdC-LU#=YR7Q zd*2Bt^xjQ#i7)@LFB#aTRS0*-2Og#%Zf-Pgw8K~AJCJR2TNX4e2KsbpM+ z%hwf?DP+qnx-HZp8G5&dJKqg%mkOSfQF`ELHe?qb%#6u0@~6H&%8-XY zq%~WWTF%$NnH|;~aMa7%+ zfKu)<{MX_wq$Q=b$0#m^m3hC(?Ch#mR9zEarCvX%bq=G9VtksLt7*Fk0!^7CH*L~X zRE9d%KEw~bPy6hy3ZCs=nloV9&^#KZEUL5bLJe>1@#QB=aRp3Gbx(Af1LoJgJBy^u zl-19&U*R8Yp{bLc`^)hk+#hLCt7TOfYI?Ggq9or`v69ugRgeJmVJTG}(}af$fQ7sd zo!i#K$k-1^d#vKQ;j_I+hkmjj+2Z4)<_$-Rpx|AJIKCb1%I965ktimW=mmTvIz zq;1+;fXvKXOqq}3V&mg(|I8A`esVweL(pS8ow~iOFSKBe{HpZ#)b>HJo{0%vwh8~% z-@^dYUS}br(6T=bdEu3cI(U^QJZ+5@Uwy-gP}oCXcq^0?0c@>eg+mk)Wu# z)KY;J-a_MymLGH<$9`r>t`8}#{uDZxk|m$6u{IeFfvojGf(??!PmFPhce;T4QhKrn!;>{dW_I4ejc)w;XCB=+amrO(y^+l z_M+GGQ@KBMX)4fl4xvIwV2JA7WvcF=`rRdtw-OMOcU?F4ZixOZUM53h!u^+bM<<9$ zjUXu#{!%ny{~v1SLeFeMxbOl;BEMhk*>E=2HS{{LS|CY^uN*iJ(qDFpF_&g52I%$) zGZ{QQo%gfslQ^n{DJ4gZ>ZeFLPVT2C7|@aOaYF>Dj{v4C_ZQ|On*HBM2R$)~ekani|PF1o10>~BH+{}REtc=iyW_!1*t-y!x^ispR zETe;2j$f}tplbkVVj*&IqBd@esJ#xdiEQ^_Ych?W5OT8*#j3Zw9?pR;)ZnN0ODI?P+xE9&wMC7YqBb?nJrAavKq&5jet=p}?jq zQKAdZHTg^sq&^g|geL1MTI9hibw_@ha!*6m>dPzz?H{Ft%a=Aji-Br)CyW&kvU5aR zAwt^?+sBZFu(d*ASPg+cUCXbC8>`#=@XJ8pdqJ@ev+}twwv|EDc?%VTnX)Rrb9d`# zdn;yQW*XaTFzOkX#R=~E*VG(Ui0Q3=f*e(wEKC07(*G}U8RkegC^$Hnf2-zfv+sOT z;Y4M@X0ZIV)4r+{;NcN`z^U0s;?NTQCqcfNkbY_E&iQon9 z1~KY5wCzOAv4MBbMBPsdRyUucJ;U)Gp1r1B=m89E03Bjo_WW8}a~ zYv0&l-XHCNy>#ZdY1*RQm#Cc-=9Yr|Vys%bAS|gxgo2P$#Av*7e0t{8{k2O@LhBQd zt4%$RpZlnqpM<2#rGt4X+VGR@j96bNKEZ#sUi4T5!MLo}X5X#ixLx}7@X$`u_nKiA{ini`OLFv+MfcJXA4af!UFoH zJJl{&?2MlJSis0j{ck+JD!_fPSB$s@dwRv#^35apwm*ihRNu2K+Fa^6*G}bZaTWbD z2g`RzrQ|u2tykukt8ovM;yCrK4;{ z&{z_bgM<^Sj~1?9#L>?jXY(mdHEFVSjv`_=q8gi2AHTXxA`cDCDeaJDb_o9OEC4N| zq2jy@?|DF^vH?FE}7Ts>@qdtLY;O zC>{U@Pi-O{+%bz3ZZZar<90!NuR%SY*g^x9;Uz!c*8T~(Hzki-lbq$H&Ca8SSJCT* z{T=QD*W(puXPdOHPpGpYD3Yqdj#tmd21Y5Qd-1X6n&M<|T3#i@=v5 z>||HBH<%CVn3)Xd^JJfjXb$dt#FC}Rt5s;0Ig(uYO6Uzor81LtY%GQ(iF<~)_Rcyj zd|Ozon7NMFvn#BNi{^+Yn$qJD<rud~+Hyb}@Co_TW@XCE;1}W8sok<|r~wYQ6um3E*8GFIHe{OY@Cn!5 zScaK$42Gp&AR=rKBppEd0ElJX_LPtL+1zpMEPn}|RO$-u3{d8DWC5t=ZJwtRK%?VnLt3J+%Z3o{lg zG+1Vu*6eHT9J1}ZfWywM-fDDx!SY?Asl4>6V5Zc8O~ta+erAUi(lI{47ICWDzI3gRgymP^|R++O@3^sm47{zHMJzh3j>*II)Fk5g>Vt1{0NYsyx9`I(IxK z1xq?~RE8-oyx{?vf0zR%OyJBsfaa`jEcF@_gft$OSY@hm=^j3;Bp_gMD3MID+w&s_ zLP5e>yS*}RtH0KBlSi(O)>JT}Ybk_dLI@vYM43M>FlLPHw*u zb|Z2^#3P<|s;fTiL`)vfEhfZ)iC^&B`f=trMjcbbTB*P!{Fhsv5Is8Z zk6q}y8j|WS&C&mxg2MHnf1;hPW?)x`4Ss9jBe@&BJ5J9?o)LA<4$B5VYrdIpE3I>}l;O{pPSc7KF2l<;4ACFc z>e}cYEBa|AyPD_?lDLTaKS&^U0L;N!w`$B`xZz1{0}$VM@ZRI#k3Nm!=noE?eeb1l zS(#*38FPC-uYyB%%*3zqRZhNq2hw~&tCIvC_Wlsz7KVC5OL=5*&Km|+7TaF&EuZAk zQHH~@yih7<(We205^KL+aS%_L783Bl*n|EopThF+hSc;A*$aUCi(|v@Fmvii+rc2=m=}rf>?n4o+sPeWUejNC)R@$579KJ25vGw~jedqpb#vMiNq3GiW^G`|P^{vrI*a z1HikmKbOyH-k$tTstJE5w4&FKoJ&^z+gSEr8j$~%g0#K>-0*LQU5sv>ZvF6nkvPs9fcoCSPERyX z=I{PpKeK+6D$jSE4c9buw&oGj5jxn0rb-I zh`vhP$$TE}TQLO#R^^Hzz}1!N=FRXpq$rh&#@W;}l2h6e^I#~6@y5Kdo#HJC zYm-)lu88BLd(R^FcbGG%JgDH8-T$HMJHwjXx@{9e4^^aBMFo^9E%c^hqX=w3dXXx< zLnuK-P^wCk-UJcpE%aVCEmY|>LTE{V00Ba|+2@>lpXVO;_w#+;ziZ7k<``p+Y5rUO zFd}8uEUqn3RL#Lf4Y~1X8s^%2y7>NY=r*2LjX2K6K8;R(Z*d71T4Q^S z-!3U9Pg^!4u4Sk@*eEF%f@&TM+5Jqu&En&&H0yqdQVKa^FE`d9<&oH18pMm8y9!&> zp>UP4qhqHx#h11euUxJV{R_|i(1@t0MT>g+{r_U@|NF`aBZD~)|KkM-Up^0;h1TmX zj!U=gT=cFg49QIw|2Y29^#fPtJtc4GTP;Syp+*z+G2GBejsH{YC@C4E`}JD2wb&@f z`MZwdkFS5pVaU(>aLtkSZtjycnNJ~~+!hxJy3lFsQfbt=wk-{D15t3kvmQpOsR_SS z`(vB^^{|{ab~W${`#svE4S&@fc8o~m4ZVUE1X(006_4HS-0OXuB$^2NLc(`JD^9a1 zCm+}qcu#5Ldyrl$SPb}gk`?3QXH~8MAz4UdtqqvomkG?!)7rW4G*VVKuq$-!GnzS} z;oC4SvS@u5NwNNxKtJ%_=b)N*StO4vcKjHTizGV)tF#s4>1a&Oy9q;BZ&n zGka`0ZID?tl-@(S4iMXYtD6}i|EpDnSFHg0e*TtRH(7V57yXOl3L~mPkO95oultQ@ z1ZzfHrkMAj)ZU0RmIbd^|LioFt&P`W2Thc#O7AAyO*>_L%Sy7c7TWFQ6c;$?5oo2# zD$hqdnIU3%KXqipaJLeQuuHWZohqgSb4C_YP4uWF}Vc5=*4q`?1as=`1( z)|W=}hZ%ZBm8;WkGs(E4x{OakR((p=n$x|8^^jj*CtlJT-!Tsyer6wqeaSiHAh49 z5U{d_nvD~e{-p0aQH)jDi5ta(C@D;6FM#k>G(h@hFN;wtGD>OQwaI$5?_0hXvR8lo zSE=dxQVV`y+A_4%tmzoC+{u-hS^vTonMF6RTON%FX0=sl_b%_ldUKUbPaq8Zeqd*1 z=uyP+{Y&}jE9|6Y)*pzTxHFPSh-SC;&T9MzJjP_S(nYUwu6a4%wuj;+m|jg^z0^(y zd)(Hxk(vHARZ?wIC7iPerXvf4yGArXxqp+GtV;Fq$kvHp@4gGAub^1s87mt(v;01_ghdzX)nR|l^J5qd z4i*B)w$ya#L-Z`zuxj8>%8JL6epoNtO4nQ=RYUlW1ya&Sf7n9@bn0qZf7!mG5novu zfYIew&e*Rl-gq&4G3pRA+(WHoE4{0f_A!16_R(;S&AP;ul*{4r-S}8j@q{@gfXzJ| zWoYa1LQ^DSm^laf!FJgNSZG22Ej8M_UT7W{=^`YiTgbZco|(ZQ$JM&RwE^q*Ole_O ziMNN2IBm-ZU~S~%`YR7%C@vZ!&;s>w7CS_(k@#}9iK|P~D%Kjze%XKY9wa(B6hT2} zgVMDL;rc(bI*T6&Jlx!{dbVkIDzN zuID?mA{WG1G}q6VEW!1sEl_Oov_(k1;(qrLNpm63Fq}7J632PeCc()Yf0ETevlxg8 zf#B)w3h~IWdyXWN_^)88LI)=C`koW_j=;^vWed?1tnNlvWzqScLb1v{A`@}-GjSyJ z4=wP&U(@UaVid&L^yR_TA@9YUUxm7uXJLwSY;ek8&+tD@u>olW77XUL>m>B7n2w%pWBqs~q98cV-*ep z8?*=q`1?rO97dxm!148>Y7g_hnd(*f-7lBGOE=wFCYhil(OMvw3ixWy0{UTr zgs&0Y+>75=LRZy~I5b;)U8_qTs~{Lm7FG$H(}&vyDJV|9j*wRX)%$vJVjAxJ6XtEu z0CKLP%l9?tqMfS6EJ-7PgB6Y>H>q-#9n8F+t{Io3qwpQ=!WKM&W%ckj{(81d zZdM<1l$UFK*pU!e9&L6cf`GQMwpp_nLHt;SA#WM)nR3BX-?_cCYWE^nUN4DPd9f6P zMjv=%Ta1>1aG3{(6SCAR@`o~XVM8zm-%Wp#H7PbbMZ$%)s1M5NF0xjo&YGPbdl4#v zokb}#{e&K`oQ1tY;KE=~L)qV-{*Yl*UjNrgVn$s4hm*8iM1sdIx8awsBCb|XF5Itj zYH+uUYo_hENx9)d&jpfBX*Su!Sp^*$-OcMwk2P60w>P=z+xdq^9MrY@W#ez;sP@AO zI{o>AU~Z}#L$PHdYUytYb|9b=jTKe5gNp0p`;|ijLFktCV&eOxb<7i>^5y|YPC2ai zy_%_MPGO-lN6xZd-Atr!4*w8~5l z(dXHqQA6q3tBgs^Ux#(Ij09V4Wbo?#?C7>$E(9)Xp7{(+g{91~lo89tt5idV*tDO=rRfSAD4aZ!(*02#1yae_L*CY4v1|#1!t~hDtuO7=-MJLarg-V>%5Cz@NR1hD( zFRs5*Xf--HzN?_!xb4wJVz>VTnMl^Hr;~ET#Ye?TpZc9R8+3eKR$3v4MY2xS7t!Me zj*1K;=PgS8y09oPf588?rtK3w^=E;V&06=HesgnF$7uRwNCL{tp)z6lgr%GHRvO&3 zE(C>2RG=F-Znfm+&CRf9F^B$PTd{o_{ z>_(3y6&x|s`DKcbFg#zaWVS$LlXGN>|i>&30MUgFSa5mtw1mKl=rxd%a9q@w@22~ z4$oHm?_fmgJh>N{S3>$I-W0?j)&VhqkU8g`lh}kFkTYw$nfUW_MOJ@81l5r5u)>vc zH7sGFl!Qw|gBQwjErDy5LHg*?2mVX8XEEtN6zTsmKDXW=#Vep}t;~)ez?%KldOwrh zVEoi5$y|6rPl_EO2|XNgp?aK;g>|F6#5Ri02d-)b&rikMn;y} z{LpinFK+ycHy2e%ghU7};&S3Yj@W;dq?5&ad-H7<^TY|alD31$){6@)C@|a|-l7%G z&Bx*hp9fL{>l8_nNwBbwg?FaETJRpnFM(~tJ>-jUn&n*(j=3^o@m5uWxN%$BRz| z@0N2T0{I}U#EjVR7Rk~RE^aVMz;%^gEB8z0!brm<-Fo2Jn-TW69D;eUlmm5#8w%Ka z^T&}Nw>J?2TkS%Fj(LjtR%1Zl=MvgXN@v4d-$h-v4FH(OmT`2LXJwp0OP~ESQ_oIy zS?-P3f@kZ8l-3alp5#zag~QVG($?kD!S}}gGTPOmjmA@&-)viR>s8&5R*dTHp*&Ot z>_%X-X;$~Up{%-agN|cCE@Xm*LN=%pJg~?c@}^$~efe9ok>N8qjs6SrJ97SG4|Pn3 z&+&+zn3Rz$^=4sw1k;1p5svdObnBK&YJ)Lj22@ko8m`rv@}*Ka?#~ULn*W4F#P=$`y8a(3QT(@d z`|8uvwtd+v!&xbKystG#04l>%?kVnHu%7iW?X_UB2ct(nWXeK04cn zEwRLMIn;Djyodw>o;&Gl)-ss2x?Du*!q9L?q+1p`oemTi z9U-!l@SV37fGV{1U-pTo=Dw*63!t~kR{e2}^m#oS*`zd|a6Mz$=t~E=uy=FGm{Hl0 z$(JMZRmLN>W1Y#WcmlEK^FSpcUc|^``9Xw z&q*5Y1Y(>#9-!j(0l6Z@zYc|F>NCJ%Tm-8hfi+zEi`9?cx!WweN7=<`Z^weO>(LpF z@DUwDO-0Uusb?vJugjZFLN8HmFP1_H_JPDu1`Q3BYxC1B%Mw>39i**W;&D_zp_0Rv zG2xyTilpey!>y=ODZe%a6$qU#Zmx==|8i&HYQR7M@yB`CbNnY7Vk|W>=H`E>HkH>; zHe}mQ`&3Sr{0F}^tguguK(l4R?b(~UGXumkOg0JJg%#Z#Am3vnyaUNaq^kRA>pcep zA8IX>64FqBaVlX9Y_jmO?2S8ikhn%G)gbYdaZafy8x4$b2+@4C{F=&$0Q74PN? zyT@lxQ49^*HD-IR0{QXn7rzzhcMR9tTLv@K8AXwD5_OOY?i&rw;k6`$G8dU$Tq{UI z%-&9!cOs2m)hfJL`!xKb#c4s!OON8vhEWwVMI1#oIeuKO9VWldZ`YK-bBz<)%+v<$ ze`}2F^I7{*P{y6+`^G0t_GaHJ)5s-wZP;?WcpBekm!$P&rgWk-_ai&aGTq|3F!+=9ZM0_uuwUt+k*w@~S$oZn8C znx|iukI-T;a?y%)!TF&josM?m>n&%dGF4OoIs?$QsgLfjD2D22Yw5J2yqy#<%i0=B zDkZk42|>Z>DgpVxU5YtlKo<(&gZF9+s=6ztNKg;Njv!Lfv5TUzS)qj)85!O94K7AT zoGa8;g`W+7N{PD=)yxrPll2-r4OP73-)QHPL_lWnt^^z+Ykge?g=uY}ww#k!(*ajb zZ}q!~3o`#VHb(qKtT@>v=d*$Tp^Zo014O;P>~1?93_Hn>4>e|iBu1=uTIZT+avZLp z6t7VRzur|BOQByqioA6^FAjZodyI`Smd~(%w}XVl ze7+lV;&i(g)%4?0(bIU@vFd=FUfR}9^QBK8oBQk#Qr*U=f}57Yb6z!RDO1RlK?-b` zt_=OifM1A3okJ62sw5k}h_!6`kXiCsn0;aSurMDDk4LH43ra1s2f5abOr7zAx7hAg zR=RX#XBq3hxrZ5>4jFNZQ)LIw)sIAkd&fkRsc*0;+_vd}akv>juaq5@Tfcdy#s}*s zJzl$Xzb!=A&&n`j`%vhC1J2KR&n}Il4F$c`8)Tg5+7<^H7Op6`c-)~ZaHK-$ieFYA zRz_(8N8A^i%`r{zfe zWwb-Kx?h_}@8jn@Uj`N3PHvm2OkT7#T=<7?g?ZP{XKG<_8Gm$N@o_{>oHw(f|MCAm zVgJLCFTV)KhFuZFg0WEIa-4?w_w~DPMOGrVfRDqW7>crdc9`6R1oxrw2o+n31`mwa z9rRc>!C*Cat4b4J=jOp685_Ct)lb37eoEAnePV!TIq>iXjM@0}{dA@2)fUf9CRuXs zgX>(H}LgNE$;Rt&reND zsahW_B;%&m?H<6peapI*l!l2hm%N$Ro*D6wjGAsJ>y;p-{CU2vGj`+5;cbdfs5@ho zHmk}!0_KatC6u{WMgl33OZzcOEK=PwiCjj?;-&(DuQ+nPTPZ3t2z z?tSyL-bVWt9+%g*X5E*X*;meMr!DTqtL#5G_g@K)#hq^jo{#jx={yt$W?F4=vp!1U z`vD%S(*jpoFP82z>DKrA=qMD`;1QWwS(gp3r^`Zoa)T`XFy6NFeLIRi%m?$0hT5Ugdj!RH*g|?km zb%SN&NfP5;BfdeXZn3rz#0I|OugsK1eHWOi#K1QBgnOlkkPmX?)Qjj_nw7e}$-J`d zCBsv9w_b{3)R1x{^Sdd9R4(v~^$uX#YTK5vPo`Wfiu` z_n0_VT5|j1v&n^cvd2Tt+ja`DLmFru%sjyLqcOFy=Ezg2b!>UvSB2PtzsD5WUsLB5y9ar{i}$ZnCJu*j9bldyR(w_U9Ujh; zOvgQ>7U(k?7?VIs*l*<7YV7k=Dxb0So%%f=YYm0VeAoNZnmudB__kD%eh8iS@||Bl z%ba^ZrIpEHTEjIj1)jlczQTf=vqolc%)>EZdus8_bJZdH`;KfwF_lw=jz#Lh z-u)<^9b8Yd;^oZrz&!x2$$v=%+w5Ip))v|#oHCf2@7Zq~+$+=JiC{&_Am7-2xGJP` zC>P_=4;&19zAl!$Kf8(ojkHA(&c*Z)S8V?RfyH3NLed8Kl6d2f)AQf5?A^UZ_b^m; z%T-4o%z?WH@FWMrppD5LnwKNwf)zbqcJazK(dLBkw7;MfhD?1BsUWQ<(TwQgH`pZ| zsF~6?s#yeiLjm4mIPeCQ_R&y_E{hxOyX1?sH_iNLh_BCMp7PBx&mhZWekfTPnq*s zZD`IZ45_}zm`uG5V$D~x4dfwxylydCvXkzZ_Z%{98}IR27ZI`wTyM+~V(=nnzwpB9 zgEPrb*HfLy7B72DDw;zrd#S_XHW#)F{3=rchK=Vk?=uKtZpqcL}8{}!-qgqWNE}hOBLo7VC?I-Yje8y0`QfXwEfl=xzfy(vIBhxA-^4BCcya zG?jj^@^F5>dVc#`n;ct&Vg)8X?=UuI*ElKhs+bqC;<+G$Ue76yb3gr)`19&?;1*lj~tsf-4hT&ufOBLz| zOx;_|-4t114{$CPqKs%*^-AC@%g$66CDcJ8kF z9=JEkD=n}oi6q51XFQooyVgW$AJhhaVRmvip@<$&&)UL~z+jH|ffSc&giOqsHWj)~ zB=teFwmk52o(&$bQ4+&+y>kZbn&`C3JynV@&AUN(YyTVSFh@e3NLm#9cg34MZ6*F! zz*e(4&wMda4>{;tZS^a@nO+_`XT7qCP-NF)xF z+1%T4U>pBu0P@Ewp?8pGr++=qX^>Y9&b!+4rEJ8)*iM>&!3i`WB$;LB~i zVh4ZP(1KV0@pVL`SJC_{4YN}6y*;QU^sFmhh0=qgxG-W3X0HDpYzoa7esjb~O2Qr< zpFT|Y9Slf`r2bwjr6KH#rv`$u^p|~h6e$V!xsq_3-)VK7>Dx`zR)smPv7P1T6I1>n zIV=@FzBFv7S8Xs~nsRk2I(Q%6<-4Vtf-ek+EYss;81Ox3{4vkbZtz_zIx$zw_8WZf zm%*Mqf-Jwq&1NDHWJ57P-|be-Q%NBk8&R#?e#b7rVK?>&SX`K5Bxb&fF&CxudjXS} z5fBL@iPUWAZj{Lj^&;$N>$!CGfc;#-jW`i;Z^k!daujBER>15V6XG@-Jv;%}PSEP< zN1q)?&kh-S?U7}6DR5)gNc)QeJz}tH!nbDP{&eqYg+e|(->J2AcxP^8(<}bjF1p0i@Va3Vy|nJFSvQ zmE6)ty8#05-K>q(Vt#|e26V1+O_}D zP5-02TRtQM`1tcGL!zb7f3@p!EvuSlE{^L>q(x_Ig^8ZeyTN)~zE~g)vxZ^gjT4cv zUt55m-l(nQirNz=&T8^R!UdDQ74J&ZDUxLbiI_3BKWm7n9QT+=qe!F}cw_i?s}@ak z-A_7#FJfUQ1McTDGwxU5DX<9j36C~C;URc|Od>w1U&Q(R<|jp^9qx55q{&de;Vtu> z0{>$F0&5g_w7AM-7Ws+k3pSrMN2HxC_3p-E`cobVrz%{XzLx>xvQ23OqLWPihysom zzorTutCpv-Dkh3tR9P4eR@?k%mk|#aeu|!y3O#E&M8EVu`LvQ*r-c`J=bHW(d|xAM zZuyf*Sd(cAZbI_R0})tNUA^28&Go)NC4S@`|1DM*S$GvU;j<_6!d4Q}md=JZaLK zwTSRl&k&Ck%|H~Qk|(RBDc_tAn7xk~8RIG^vGJ181o^60! zQ#4)GBc~%FU-ae-q7uKJ0hR+6D<0fm5!>o=5FtF>8OQ{>hR;CFS294|AgX6=EX*L% z@T&G#6A9H&`QlDs{$%d5KlDK*vNdtK2##3;piQ>vU*GEuB{y1n_bRC#CqS zG1XQ=^|7|;^#j&DRv%(&9e;yAhB@wOH&Nc|`Q@c-X$~zYBPa8d4_N_00^hS-Xy9+C!d@@vr#X%es;kkqvbLhOi;_X{PCH;qvA) z=RoWtv=VWuuhXKN3_E7vH(<$9sIR*}(nH!4JKP07-%mALw=f;yrSEh88qF8tj9Mdf z9Z}SHrx>8G;_-ohq-wOMXc8$B%dCc>Pk;RT2ayJUV4iVrvh<<%aJ;+8_<)-ACo%ph zhcTE<8%=$U7PTS5z$z$c_UjbgI$ou*xN?UZAFm1U7zEOhMHtXN-fo?i?00jgKJLm| zmjt|~kKuX;uen`V^CEl4<$WcRoZJOun(wOT=I*KMFW=}&KkAg`w=B~wq>gszG#K{= zX}fCT@mYy$l2(-((#qC_P%p%+Lr5=V4z^E%^t>gZ-Al~KJUX@WP?S6WLcu}l(zVF7 zXN0eQkuywc{zS=rz_a9gEcxzCaXP+NIL?oBH3**;8f5dzRn2L1k}wz2Y)-ktrRx`G z+Um*z3+1W$uF8Gy7?O>6odxUxj??oh3*y5!N>1~3{WRpD6}dFg3~bROdkk|+fxmv; zo9oglt>#_4i36bJ@r{_w@{!YDf43FU=P|T4joXk{ELT_t3%?Slvzhd5Lx-b;rF5Sy z{^pTfIR{X-12^v)uMhLXjA`hVM;ey3<%^ zkUW92?4rzgu-(`*w7$g43;n(M{D^h135GM3#U`V&pk-X#+#v_%5P^~0bbdaWdJ-GC-{= zQrr!KW8ofkz&uQNZcq|g1c@Jmz+-mDXCeCU!$`Eq@>`j%r}v)g+LKNl(yEniHBoGA zAC;o2y_(I&!-S$kOl68p^}eLbXBonpDlKKMI3#SdkL*iII0A;7LR1Y^E3M3v4P76oEE+=4`1%|V6Ia_71H%x zQXcG7#rT{k5{KKeLbrEMwV!WcLf2Ygydmcn%|}ch&7}= zMJK$^Hw-J=?hV`Y^Czz$XZd{1OgyHZtMkcyw}}$4FL9AGLW^H{`p)ob-73lQ`@GMy zj|3`Q_d@9pnQuN#&-a1Hwor(Jc%Xa@gbzDhSixmblc~jg4b;`B{iXR@CM?-cHR-{v zyBpLiP3^bc&oH#+>0hDm2b-^Dsb_$aCv;&ZJD)qDz~{_GbixEiPYfOj0SVs zP+#AW2$R?A+fkpM=CYmnu+-PJzkki+?)+3eqEroxK(eV->i%l!l78Go(d6cPcQlJH zQ`||{>RH_Z#3d|BYP-{BfYLYQ@3yKMVZKr8RzO;LGRfK4(K2J7eV9p|1B_^mQv`T4 z^)(dtYdN%8WRtJlPVlq_pjfz%h0SIZQo5_G!n@nwL;^F{rtuV*1P}0=X*?}d>im{Y&5~R#se^u3-WAmfNF(Z z|IG>LoQQzVO=|;?aV^Lf>gJ#d9J;pKH4Fq+vJZY9s?pcix86IUlQduNo&xp9B&Ape zeKTu0V_QBanTbQH6uyobOP##X5*M#~`^(B1wT8p#dD2twC>>7pAx zel_&UcS*AGUy$eEKih@HaJw5bf1uKTTu!amsdw=NBho03UlI=$V0GjLJ7a$I&Y3Oa zhR?xK+GUFMOKA7H&euG+)*_`)|f7{SkTbjNI+5RZCQGjIG9yy)|jNg1*6{Alv zUDwV*M=d}%v%rK??K=v#U@6$K?_a-8L8vgTCT=w{=jR)*>)Y~Y z-+sTbzk&UH$=Oj0`m2I6zSZVUCZkDb2nKdxEAQ)ObK@JPL2`j9}%T5islBw4s}*=S0Rl z`S}vEvIc0pZQJof@#y!_!P!oE3Naj@ym`NubA4_~p!X*TxH%kZ<&I?J<5h}SlIhi6$&CyoY5sBlgUSA>4a}*(xorOU_fKtL zwFr0Ly)k0CviXRCk}~^iAvC&Z-jukA{)O&Grr`3a`guJXHtj8!$q1l}vux?*$TtuiCOaMdOF8r=GRL2sNt}LZBOZkDlJYj|{qQHAZ zT`%|e{X;UF1z7*Yb&#{aYH;QVW`NFgf_QKxu>#kZc5*KrrPF&h}U6(d^fVIr#NmJ1wg{;EK;f?3(5sL<9xP?7W@;x zQHSKoXdgUIa<6X3$yJzT#y-=c5>ze6;0Bb&8hE4n9)jO^^;ti?=(w2v(2VWbYt{gn zJPPv>*kIqHcyIko=}lp2R%q>8!s1LKAwKyX0+i(6xPp< zcI;Y>A6gzGmv-&RbY+oWL+|J+cZ6mWT+Tj_(bKqbOc)>t#c_6|Tdg=nZe^7k+?rRz z`S4cYzj$a%a*1W3yjKw=_y^JTUuB`4dL`>ZBc$Hi^0k$)Ze`DyIqVy^u9V(SgohvK z-XfxL4tYT4yv@aWVAxo}*-;Ol)+DCgqFGLe!Pybjz#^f@lKGGkvZ!09bdR-vxvL5Z zbrx5LCsS*y6)oU06wC(?Y1qh&!NK&8%tvpFx^mB}2Cp&JO$djOID;O5MI+{GhO0Tg z->s2$Q7hLzzM!jD@c8m`6W&^^iMXYVN^9M${T8>5R-M_FcqAZBzNu%_snE)J7G(FK zizv0Vsr!aI!Q2MmEH^yv#^PgM>+0G})w(x`$cq?0Q-u`wduGuK>rxKG2IVuG7F#ni z-60bDX~WiwsDz~eYU}(EDR&@ zNE{XaP2))SwQ%;JH2KUIJzTL!{5*p)lgc{j`1Up#6HhsvG20{uy3|% z@5uO2Usx{MgT=$@=9x;EIz@z5V`s(Qx--BqJUAsQbJQ6lv{5B=-8t}R%4o0&+X_}} z)6WXnm{tGibCzktH=+^aC$!SawoKX(;$NA8Z*8I+X~~YGN`<;Bg%#qN9u#GJTU>PPlhuvP#`g65ZIfv2>%RUy^*B|1W*jI7*jh1(!G#A4Fuid^~jsg zC?1M+c&~3d9Z2@reEc)CY~JB71Skzmhz%w^m7fmOQHYaJy^98`lYQT298J2PM2O^! zpN8c2HSZrjh5EU0oXkP^KQgM$FY);M4O-ydrrnoms_rKVXdRcvfPhtv*GdTC*;&e@ zIXmP<#DV2F;4Y%-{r&lz>a#BcW`H)zX}P@xcvP-LM9Xa_u~&~MvZL^1zeNpnuQplO zT>D)?aC&1cUV!V3!{LlOK0iu0H)sC-FZ#RQz`mSc_kaMg5eEMO?gSrI^$nI|R}gS}O(S&=iNP zJk4IkB++;AcpB~0kl$K+N}f)R!NAh_kbu6zm0!~|`ZNMn4*tV_Vy|CQCW1bJoY7q^ z4HQ;C%l!7`Zt=*jATFwxm>$|nviXSGCx}B$JfG3 z3fa0FdHRT}ag-Z*bEVvArQzGvvv#x7y*S>*?Sex(!NJy<>wM&Eqe{yY8(Xu14Pj?F z8R_?Vhx1$)wh6;o1}CDHeCrCu==rJUjHXnW4e@@vOTp>3)7i7Y>_1vUORay}MQN0h=AZWWf7->K7b_3;1Xh~8);Y>h%+OpUg#0Fj z)OB*O&}!T&IVxy2?y9McHIamvGWz?K3U0(~8KC(oKk6?{xNKhk$PVBqf7D^iiUc)S zI{ZiP3t){eW#kt#^$|(vemU0n$>6B1ith-zf-8FhJYT>>p|u|^9^Q7#Hd32Hwbr#$ zQd_c+GjShj8z;42C&J}#=?(O>&TWTZ)x)RW$37|Yi`6r*S7bg#Y2h$=Ff~m@go_C) z^c{_AtY2WSh9-^fHyvP!wntxAcJjpx>);nX+rhqEE@%?ix<36!@Zn16Y-U!9^;qJO zo7NA%vKPVi*5&^4FBu%l7kPe(!pd3yg3obBk7eZT3Dm9eWksk#95xdds~JJG1#IqPr}G;W*anD;o?uf6rDD zCfMu{igq{CQJtUM>AyDmH?{g;8b(^AtRMx&ihV zs{Z796ptXs_~1)e$&raMcbqNvTKmh)(ZVa1Zu0#?74s#v0AL|EgOpzfSgR@&V_VY?&V+Z`3C6U3FTR`k2HB@Tn*& z-B<2nGc@pIrK@UorE?jOU=9~IU1{cBbq58wZ8^}Hy_e}DgkNm>zCkSdb6JU0U^ly3 zep69vJ;rJC(hUaQmu?Dw&+|0yJyIRe`!>$`+ln)0#>N_C^u{*Ob2n+^+3H1VkdjFr z@AivUP>pQv7o2aZz><`w(#O}mfwiv-h_yoP5lXfT% zke5a6oH_K;4b!JckV*U#-4~Eh@LoCE{NF49;>AZ5{lA&M|DQfo?4$+&ENS*MV{mmM zgFRdnhxfVqq(=jqtefmr(VI(T?@8V%xU6(q0pWc-kq4yLB9?6sH@p(Np0|*{cPl2g zKKkv0hFXL&LKD^Nrdxi@t{qxHPLA}7jvgY6*u*bjPVG(oA>5reu1q3$_U(mI`oaa?AP*HK`h-Hh^2&J#5vpij)%EBP$eIn7Y-^qr5REOX+|?#BvyISw#Q zw;C=5AZxvd+|NPpynB*^TQkE~rro}aUrI3uDPr`80t z8uWa+&bCQkMZZPkG%OrXh0rKH|8q1r`!C{Hrvvlfgg-FAf0=z(81(>vlX1$gJt^ud zg+Jq1fISEV2E-89-#XLyPJw$(bvv9e(>8Z~eqpD;4UX|mq{xxFAW+`)HFeJ&D;%y9 zPLy5hxDy`Vu08PZscQg|$4HKnwg2w+I&-^OOv${$@f=+$O@AG|?*7o>QkK*7{hOXb zB_lf*3+A&Oh{iEbYl_3zpqxcP@Hq|q>43MXb-Axe-Uu9GWmWEBE!VZi@Lf`ddxKO4 zkZ+sqi=hY?m!`mzP>jpeltPtz5vgQw^qU@F%+!vOt-@E{l))6yBsoCHaw)LC>0oTD z?;GmpttKTNpPU1~Qsqfo8nDkT8`b-0CU*^95r!7f8rE|TF}rLg3x5eD;R1~;N;a>3 zC49@biD?3PDNIPr57|2Y{R-X}^iYAuBzdHR?WXS;Ws}p$i}!IO`#u3mBd3&8e>*a; zQ`>+6L0^~tF1Ni0Fh_GaH?Z~+hDYmOQkuoD2#i;#wnuTJGCUP%rK35s0(L782A-8C z5{)YN+*@&efyceL_08@G*0@-)n;YKm=8kuQpIZ?oAdm2&-5%Cl`Y-3q{PKnhJY%<7Ycpmq?DTG0oU@T^`k-`2<77g+|qB*g!JlN@IM0ro5;1 z9X=Ve{x^mTYrx7EK-dq0shK>|=J}{HJ<1ngWJ2jUoc^?t#tiNA0W{E20@%`jbM5Yg z5z(vUDKwEHfs@3XisW*46yGKrkOEy_XV+j%>uW_->Cf@-HFVl^1c2E5m%Yc7WewKo z{OiD=ykWLTsBe6`Vag#%Dq0yu>$YXFQ&X8p3-$hTEiCkdr$M4;b4>U{D(S}T$p^iKc$+CX(t!HLGFhIKyygnamwDlY4qttW6T5}(vu9NU4AMl@MwH$qBqM2R~Xh7?A6e`cm9kx@ajJ} zoL)azjZk7GWGK{&4n&<6aiCp_@&CzSxaO~{_ww9O^9Ab(#^Jf#nb!$_M#IzxL{^LK`WEhi%qK7%)biAEe-8j zB-UlyKZW!z+9<#TX(kUBVue})YbH)<1Gt_~(I(b%&(fz3eAq@`LMnKaB$z2z8*b7s^>mgayg<4Tbtas0u#z;2bAL4&jw7mK3A8)!W6! zRqqOAdmWsT5wVi(8?R%hsFSm}L-kX~H^e?9n=sT>jX&q>+lwAtKR^Ul%zFeqIwL`;*=MuR4Aqtb* zV%O$oK8)xg+ZY|9GvJ<9N`}6W8Be3wW5H2d14qqUz9~)#-J@h#daDwSHAD8ZaNrL)MV+lm zDq01!^$RAv&vzUA+fTBW732 z1hhLYGM)oJrDcW8iKslD3%Oz7f8z~>XI$}S@hb&qt%h)~&SSE6%f5QuWn=lAMwftH zUNk!8&J;hNv{sz166`*1XyN_`g*0wf9^))(XKpYkCiBcsr|kgqs9t$J1>CN%9NTDS zGCb&wXwkKRB1^pp$C(EQCFM!wN|)V~%OAw(&hD4>>$Q`B2wzoCjbWjqf@dm7_r1?Gfpc&%q`z~epd@>bU$?r(X{0-zM3z1P>|zl4954+~!{UD1OJ^ON20 z^yrvsf4t-m&<^J>?|NchSzfp23DAvRyoaZwV3>F?`}u6XWgtYfhUM{&SzUbGxnXBq&kH2xxZ?^qUg!Gz{}q8>W~e zGRI633FS_0rSL%*OIhud>M~o+(-#;D=zi&?SfAb*R^F6it1z2UEdTWxkDpE3=jH=g) zutC9B@%W)-?gu(A^JVV+UTAMY{Jg`b&smKlr8!G}rJ^~SCS2R1wt(Mw_|ymMyG+nN z{h>g8LDaLHpW}_VK#A=>Nqd)b(f(LVCQH@JQr&FX80(y}h}c+5Gvsn#Qkzxiak{kr zs`326d9_Y*y8EIieu>aTy>*KzB!u}^8lNL-_D9eD)bojV7y5#T(y$L}fBvg}n?QZ;a=qO^ z@l79xVBq?=omqQzm4XV02Rk@6mUq6_p$SYV(YTAJi)xt#a1`5{oA*IS(AojQ?W9>B zjZeXkcy9<)$Q;v9tOQZEkqsncJ-;BF((MP!mR4ar+*@y!$+tx-rZtz0OsT<1zK#0i zDgG1DQDjT7ux&iyVLP5&+%3p^6%I}JH=bs8fJ) z|IqcGVNI^h+AtjfDT<1S6qf}HMMb3(tf;7{Aib!FQ4vB90TPN`DJlxm5|Ab$AW{OP zfS^Pv3B9EOA%vC$2oRDG@@4J)?)^RPXFY#7!kvR3+;hz}Gv}OhjxI%?Z0#$vgvbee z{$V|=O1(-@Xxf)!D1!}SsqQ5iV{@tyD11Oqn{k&tuJ6Rkm4M_lHj*IqgDk>_CGc_9O!@P#unzL z3|#c@@%^>T}+3`xc;>|&)CW7#S#CCC$u&3 z){6s!6@VMgrSESYO+MmXk#ud4C)4(16!uKau{6@bhVH~Ry0*?Lq(ujq?`i#?AacMC|DU^IDAyTAjTP0B!9Jb%a6I0lcWK zipp&EwArpaLHe9f!}w3IM${B5We{K zbu{zcM9~i8Iawo(pETwBve}Nn{dN*O?ehEc=D{1@0IQDI?YJY}swz#Ceh|{A8%M9p zS%5n}jdl zU}|9XCal!A;KEctQs&voz#aUpan_>-$A)1eG{1~Du(dnk9fF3n(Uz1p9P#pSYFf-w zcn&_soutlCDU-Kd{AP1Iujz|H_~5JW-Gkv$b2ss3VU5z2ZW3R`nq3r7677NKCXXiX zH|1UKb)9a5)qraq{Swb@$tv~(q z_)lmllK9y7A^Eu)-V=WR5UCqoWLrh21(*SR)IaCu;@iN{arCE#&%^U$I<}kP&#Ph_ zPdvOyHj3|6)ord37h|aO?c!bAfiL}Y{Y;CH@L+3c_e^guD-5omX@c(GRF(Xox6H+G zzFzVXvdKB8t?qUBF?Pi6uNB*x{b6x+2`kPTCzfTZa=zx&%2rArXgy1&3?_hBE7}Xv zMHh@z`gG&LbFY+d2JWxiEo|uOi#X8iV+&wDOLdpfs#KifeZNSSxzp;#-f-T;=goDD ztV-5(8x>o0(}=K%2>A({H~Zzb<>u$eu~Grnq+_w$4q(6*4S@1ggC(1gZ)~&=CwpsK zjJUiq3MGEK(0coGR4+sQxJvYOEGJAM>;%k<`{oq+tn3fHi(mtmPkFEPxu+&M&1+}v zmuNHU8_LhU7bMdxQf{x0KmWP$8u^LTsYsngqb)%lZ#KnM^Y=fzWAsjK$&wwc=HTZZ ze*CUC&z`!W3|`G}TB*A1R--gt?A4=Ey`>?9ei6d^nJ&)8#k_DLJ59?JZltfDzMG{G zL&Ux&R(d|B`Qln_62jQ|v2Et^16;;V&CJYX}v7LH3Eah%3i0=BF1zhmp? zWnpi{x|5;{pECjq|L^k1|DG5CxXDgBh86_@+_Zl`jYnHNORsw(2!UNG4~)CNchA1F z$eo~!{Y}f zXulGbhdkY%as78Ps~((g0Oi&P59!a>Y(Axa8D&;$VZ_p|l%l=p^gZUN+x9Yg`mRIV z8x{EC_JNjVn_>sdXimUpM9{Dtqlx|!(+M_fm)8qvxh*lankcYVSsRMZ%2a|Qt8dL2 z$-OoQ4GnsJXmpD`Z^6m4id?-m37hBx5_FYrXXPD|gz!761{NFQj7Vvg zy*{s`NqzIJzoMk8ZvrBE`fzV0E%Nu+YX8uUi+U`?Op{CUC(me)qQMDfBr3L*r_I@w zSTxs!l4yO$g6y+mY|$Hm;e^vrl_L3%(LYS$E!a=!Mp5(9T}OP5#44+gO1&~y`b*LB zE6TO$NUed~r|ziV+pieuz6Umz)7GxkFXKBG|56jKPCVX@1D#RR8Qx&#&_u)qA(@Y5xSN0fPU|(SGdhl>5gv>GgQT z2Pvhzu??F_&*xxd65#=HleXOw#Go_W?Gwr&u(F(dklvdgxFj@bPe(P;>%XR-3{6q(?*hz8d%h zW;mKiKCa4kf3VH>q_G#@V)Vi(2S8j%^~0_KCzhda`Msu}ntzjH=nRCI6Ahwbyu71$ z??a|nk1`L}wruhZQQNt~#=Q1eWga0%TU%$1FAaxX`UfF#+H4xA)%vlo{|J=6wK?vge0k26qy}2F+gi$JO4f{t5(3+|Z**eHf9f zM`jI~TV>-cNdsb8<@lDgmS8W*=&~KraCukRuJQfp7Fh$(Myk}Ulht)2K(&Ra8+Pts z$80vxjG#$SxtbDO@9Az}FJDb&Ny4l1lq_!E!|6;D!wWJs+VK1HO{2bhk0jq}IzVai z>9jKX85my|eZ5peo4KNVY1>m2n19$KQB8|c6Bo756L*Btscq-CT@sPrFnYnz_+jB0 zTaspGHsYHd8hSkzWp2m-W(7rLjd*owl@Po8s=BbUKT7Yb?$He^b4-boXfW73uc{0rI=1bODf1hYtoDzN;60=SQIQULCV8?I%w2vL%v@J>JhjgAXS@W6KW zR-lp2hvdqN%B1NGX7C#0onUw0@D;*8jDwamIXH?j62Rr~D&~JEthjj+UA&k5vdI>2 zT;gVH-I|@lFDvCsHla(!tJqY)$JCH=I&3YygQQ+e+hskYjVHVs^s1#AW*)MJ0ba3@ zqt|xTHCcZu7v$24DDzKOA}soXLkJoTRhBndM{_Y7YoFc6$A7c<1nh#Cl(B1X43m6X zBBr05+P%HdaAm8;##twJ?v%hVXkfb}we_S*6f4+Qy8TF(`tGYkTjo5Ks41EGJ+o%T zsm@>vVShDEhb28L!B;N38ll_-pgwGmN+M`xT}uV-o{@^Ipn_7mwsU zm1gZ$t#kC}nNo7M8n}+;zL-crQYQnC@Lie1%-@z( z&!|fM50(X2NL*c*9oTFzv(rcFbxQmc;KvJc6|Yv{sgz>5VyRI(UZdgyQQEHa^n@O7 zLtJpUblyp(ys5>_ZKDnH$s@^EN1#oIvgfvH-DTge))xvinSrvO=CZIqhtVI(h9AYa z3`h)pX0^S=^j3aM|G9wvlAKZ8G{Iml~en_H8 zYm2MkvKi6TmJ{zZ%h^$kJd>&CzH_BA>BQCHvyv7y%cozV6wWm(`R{XWn7-7j!czsC z3zGuovu`M9%_PbPWjrVf9t0bUcN%D=cEuD)B!rSD7VqO&GZM-Bai?TY9^ET3)>=x) z7Myn5t#s2tvposVS+E$b4UC>~x}*KU#8~^PP1qd+-_H?`X4@BLK9M3Y!pl3S2xp?e`Zu=)Q48ga_H3tV2`uiMdj1@@s;aUOIsVtP=ZHAfc|mFwp_n_M ziL)_UpU(+pf6wSni+z5S(IF7wQSu9a{UfAp;v_DS30LRl4*rLNiM(Ip`P!rA^C_BN z!zF*&STw&-erHX7IE2ueCuP42jP|ZAkf2Il^`J~I4nQATEUMVvZvgdHD|N|EJaP^m z$&vgX;N?1k3&mS}JRsIpybh9N1huYDy{dgkxTI_3sPo+KMudGfbA6Yg`SfIbW87WG zJn0LvOYL{Js=fcU+q!`^Bt7?Je2CVv)!2&M1FOS4DJg&;Bxj#YcAWb16R#2C`=@%$q}tWvP1hwM=KrL8HCcCsx8 z>po69Y+%^}%>*qMDx9ki6Q!f32>`tP6FLg~rLXkE7AWP-w;W*W$GtJCQx(L$HIlS7 zGpU^QyYgQFl8}eZfnI{b04|LEykwlRuw-y%!v@tm6>-8-kkaWuHiYd;Mo}Pr-MR-@ zZeP0I=uoX^FMGsRe`){y`~BiT7W*A2hNeYd7EfP00K#|QjP5vMsPe-R#J^{dwk`$U;pfrhJPLZ~F8qi<~dwt}JXltujKx>vysgK6|(xh-h@r=3w@mTY`2 z{ZR@_9=-K>!n<~bE5M2*R3Us$JZ;aM(&dV-{N<&ou*EkLvO%l@$1 z)@%4G>(?W?dHgtmU~cZAOl90XqM}~l%&NAYPAIx$NNYqtB&@Q-)x`y?g;A9Vv3MFv zyCQF|4qX}kHVTOgPFS$aZHr`Q2d&~i zSdXLTiR0v-;_b&cc(H$Dio!>S*D+DXX2|s=Qpl#3!w>g!D)JeKWR-u!rxAb4p#$s| zs%HO#IoSmg$t)kK!?#m(R3#Y;i)OioeaEjCRS;0$EP;)|JAWCnzqd%dB|-SH$RNhjxTLi9^LPrhnxlSwQg#Q&TldP&!lkumzYdu?ttB+qHaHMExaXl9|( zr5m`f=@86K5EwTJAGM9iMF~5mvPLB6-IC?CDi5{=GlMdv-&|`5$&*O^>%9Kq*4qIB zjyyBw3e~%`<;(6Q>sMM%frNF=`JF1E2jyenc$1y07iSXUGtK)7DVd)UbwByLUBS1c zmDKMQtZe*ncUdan;}hjx?q=?KKTh{h1$yaXJ(ofd>u96_;gEetw@=+g*wzK|H#{|8 z*pO2Kh-XQU+Wgplc6?9fVSEI)8&A*}b4 zcc>|`k9$NKoB2^gAQkt~C8GnAA3=DJ!)5oYB|DoO$$dA&dQy~vgALOChHoFy2m)Ij zYp?%m^1A5t_AW{#n}0fclC$?W-bHCIC=^wY+QDZjaRef{begv~PRI|9KWSpLb zWWUQYm1Gbo`}Nbye-8Bn=RlW!;?-Wf@VPe@nxgPL+FCNCLc2v~z|aySR`4=Ctx4tO z>tH!*pQ5b`LjX$)cJYi@L&blXDLgN$vq@}Jz+dWbZv9F7_}||UHzYRjybuanvc+n> zA>hjd}cQ&CV2qV=QabCJfZ9n z?m>ywetOyNm@AF7w-Wi^pVa6ykmYgq#WQ{fm*Tf9RvKHC5aq*C9SF^DbS*RNlYNiG zEmto*lQS^-YV6plu6WksozmXtsd9Da-kKTczR?}m>~i-SKOp>ZQU2o=Zz3F^)5_ki zrLk3}U?2&Ae`a#rN9_=_zpm#rXtchn>mzk}c2L~K1-MWe!mCL2!od1qT7Ag$V<(Z! zS=Dau$Myhxc;fF!)j>y*#>qP9CA%NNbx77y;6e5s8l@UXcYiOuTHpKtwmjoYzf=Ew%WOk|Y`ux+ zudU@Qim)agjS={BTt2Yi6pNnAk}6TMr&9SlB`lZBvV#o<`-V~9&F_;Lt~JBKIp3;x zRsS?sUMV!ZX)=$Mo58DSeeri67{lt92L(xA(VFRSDV6wC6SpI`0k^eLVsR!O?7+HW z#&)}S303Laun@90sBG78Lg40l&iU=L>+Dk@w%qK64Y()$*!;vb7Z(gZ;xswy86115 z*jqBAu-iJwJstg8%hT&{gY+lnBcD$nd#(6gyL1Q;gFCooP-dibpwwN?haqx4I^~Iy zZA3zUC+IBA)P`$=jMcCnLQK<6veNWyvY8F-3XV|Ei%s98TNxg>e3X}D7aTgH5a7B0 zCMvNqpu1U_Qg*g->lJ~0`js|L)8gMlHAF7OkYL00tdHRxq-$yc^3KKaH)Yy2cD%=} z29$iH?Z~TRC?wbkPY)B)7GMc9M+jkHfwwf*MTz~DkQnP*;||SYBp&=H@K5J&awQ;> z^Y+?5f`2hTw@O%?Cwg-S_Px;ORW4DY4m7v~7 z(uGJ{U$7dePW7B&?H2q~sC!+z?kCu-_`}XKc%q#8K)}xdRj0-=qY8%u%ep0@^$>p_H zfD)47NA1}c7!toq2{D@n&mFK)Ll}i#HLR4PUIsXL3gZrCagFwU8aE%!T&M>?9CVE~ zK97{`SkJ=*#_Hs{4;ikK^Iu&*;-qrDv??g~uX1f#$-Vp|S8~@AE0vb~aqX+yH{5uh zKD0CSFbUdW*+VRSG))}7s*@BJp`{xh)+Aq03nJdlCZC9lXm6HHvptig#0`<3S1M-o zp<<@%thjUbbY>Rly$73OL;!Ga$8ml`*hrd%EKaX)+mx71&xVSIXCs@8#iC=M#bee* zQR-$~3}I~nL$F3~!>hL=e%@cVC&h06CwT_3r`7%KX$uN%^Z)2+*l&uS;0cLe+IX+? zWjDVa8icR9i-`!b`woU}t&@5ae35-nV&1&#{q231z>T2!`w|pw@nTx@DcH91EWCEI zg)|8t)nwMC{@9>L<=*GhR@q~xu4eUbk&C&1_QX|;9Pm}e-Gbzl7WCR1Pd z@w%4yU#Eh*qMDfT+rvU;(wYM%9-MzOR85_nxu?4paXFYM|fTiB9slxtX$TVG}EenKo3lz&~c(3xs zyoTRfS55*F<9i-#f2}oIK_Fj}ITff%^|DfGFs4LXoA;hpXB9Vy+i4G}x(J@H=Iq(V zB}p^UGagLj-#+>8+REawq_g6p-{)OMo7q2Nu-FHRXw|rw$+4Da+BX-Y^*SZq>Fetk z1UD)k(>LUM51x?NW(IZAO-+D$UvY3y!Y@12C^mTq6{kqJM7m2RKKU_E4uUH^zPzBq zdjF_bRZZ{}ST~;?L$|%vn?gG;HE?fedo^iXPHNU-X4m&=C z%?CW{c@vo0Jf3VlKrYUyru-;q$%%~gR=Q(&Y1q1CI=n*ZQ)kbW4WoWm!`%wuiMZOJ zFNE8>B#iFyOk!Kl%4d7-lyFVK;Dh6`CNW2qEr9Xhf(BFA(y`0fBeT0xekxdjH^uvg z?QcL?<^tX%R0HXWM?T$mpjvQ~Qt;1#*~VTor#R=^jSO%Z6v=jnK}O=OHK1lMHo7CM zEYxrwQQ>(hSIY}1%uLpxPfdMrViM8^ePVOOuv>d+1=hXXv;MD7$(4#aP5WREM{p1tGlesx}71WjQI5 zv`c#BGhW22V$DdUCYgv-3$MC^DmoJ1Eh^)`H2jbstp=*@`c%^XWCU&*$KQDGi;342 zGN+?&{53U>RLL-FLP>v9HEZ#B9^R-+tBR2rxaXqQ8LAf~ac5*OC%{TM!0uuwd8SV@ zZb>rtMf=c9+A}fIQoY2=@}8Bz1sko4g+II|A8rcU^i641R#X#gsR9XX@?sS(BrLvJ zm^qmOmRfSZeAf(F8b0R}XkPW%16b?`2)nhhJ3G*SWMA5m6Wr^j7}WO-{mV!#6Hxb| zi<13ZVcHXEi75B!7oA+|P-o-)Ej1#u({Clli=Vm&KM0?zs%z>Z@)Xl~_VfWuE(67{BN(_1QB*5$CL39osihh0P>z5wepuNRkt!wy0Jg3<(ooirVmH z2~KSGtmrL}_A;*I>c0HE_m~(?DtNixNV2U!y|Xwp9CP*2$ z^6rY~jjh1C?6wneG;40s^q@H^B^ud#5?hog5p_vfr~F~yneXv$43*eo+Td8VEf_SP z5UqC1`h6>Gw~>Nb<&U}prw`A#ywSnpLTr3@zFiB#NKcVVp*#24W`OsDBXPO+iqENP zsBLub%0EcEsueg!Dx_PZaQTfYQFfPi-Lpn66`v+QQIrQ_EUtAwlx%%yAl^;^i4*g$ zWf@xm`et|#DY6#LYbDYrnc%kB3hc?1c$`$VQkklC_e$hrxLoiU1*pEZQpsJv^h&=7 z2rmv%x8-J(hc=c@4?D$LaMoh;DUHiH>=*{2ajD1NmHrPhWKN^6%Ko0&U0L&6`Zxdj zFSVH4vT^TX=hcH0HfY>dx`K#VoL>A(jm+u8hmf%4bXIf?%9)lF^@ItQrX4VG6Z(=d4tJDw&U zd^Of=RXT_ksM^eYVG%KbWfqkeAMEnJ7T>cu(nTvW1^#Yl{4wnYgC;XFkixasgY2%B zFV_OMz!nUJnJ=jV8f|wIPnk4n+D-(K|GFWVrH|D3OIB$gO8Sw)Q4`eUcgxg6HZ?@U zfMEmD+NSJl`Yz z4(9p2PNU~X5BwrAk>WM8naxglGa#sdNY7UVJbot?bAgPdCd!TSZcAGENFZfr zCJN=duH@Fxc`Ao5D?C5+Nz>IP!A-l(^J3J!c=~-jitDqI|Xbp6=}}C*wcHdF0y) zx~gpxWX^i+o9`GWX1A7w=l@KG!U8{>^=OdTeLJgksWH>s>K8P2#5w z?Ck4>u%UzV>)&n9wOL2>fU4RFx`h|59EYr`_>Ug>i}{&T_>k9(A?9XwJ*a|8x{QV& z#ztHgYMtSNd+1Y^-*p(*LJo2|gKdu{bsXBdetCrmvSj;EDHp!LgCiEjTQ37o37jSn zmf&0U0!nmRF+A!4gimuYR)tNB(c9iz;@Girl(L=d@X%RKilE>YD>|@lg4+WHR0XU| zN19whFb1f>Hb%cvR>bXz%$*_t4>Zg82KWG-Q&7{hjgyd+lG&i9H-B=oT5jxXSQh-r z|9kS^U)fxhD!IDey78V%JTRZ(v>$=_YPI-lcRLU!FjX(wX9alBg;vbbN?^^we_Q_G zIIKS{Rk)^=5K+H)tl$8%Oy8Gbb(?*34rkhFNrKdlAr&nZ} zbL^Gc?Ve}v?M`vLOy<5!5oAB5D0{g`2JD_U3WZNuou2Heqz5HZg}0>U%@oy(H zyw}->a&A{Ly@76Axfyb%Hg`Jo z)`nWHVhsARRaJx6aIV^oSZFcya#VJ)KW7!%Q5#In_Q=sKrt-RL;p`IvZe46{_X;GC z#i;MSxby|xxS)Gyn%9^P1qJT@U;Eg`HOXJMja!djtBKnGUl#kHuU7Ro?5SJxe1vz_ z)<3F!5}0C&bVw7U#79}W*l6C!D`P|Pv2F|bpg37p1ysLY(cGKw6a#)S{{yw#z}m(P z|BY3W5Ew_wHB)-8tIaZ9zI+9KaN0Qm`N?7oBHbtVOWXHx$!|}T6Ym^l7dG|a3|0)) z@8aC0Fv(XVP+Lb7o^n;ytx^us6Nhh_bMJ4UY+lHhqn3n$x+rTk>~)(N)K5;V;ite~ z&}_dk0c`$mpQS<_^7?U#B6m|RBh$GPF|lb!ktr)M0h-M%Hho9Ew4K~PV9K#t9{%O| zmRammZvPXkjqHWJ{qC?BQx*Z3(cN5tyUQ4|6}nR{z(qm$BybUMtuA{)d%B;!(f{b@ z2|>C<{cr?7fL?Fs3VjQ%8$96~Sm3@+syBha^TmmX|8#njP3+L&TBCF-kDh0o?eLTL zjO`BRmpB+8)+Tz}?R27o>SM%*a~_EMP@3J~T?)7|WfC?kJVAA)UiK|7a6NmFtS?j z@0N)<2}H_`@BVT*E@pa>PA^G`4TG%I8yiv~wB-c~%YV@Qca9>%K$Y^DMJo@W%$tfD zGr$i`HwOGdWxQk#1S9zne^mQR!r>Y(M_~?ZdZ2aRCxt?-UHa95(U}clg5aKMx$d$V zn=7=18o7=#@kSPdBNR?XsPt?$;Gzz3UHOYv=iN_<8P|GCz?Q=^i!)wP*1ol%W}Y|d zjrme6dMfAKR#*$w(^87-6ph$(J}?qqV0IF$TTU1pvIbu~k9`j?n2J-*=WO3iV&(gN zV~$+dy9Kle{Q%hb+>RAWI>?sc+;?AD#4gfk@OF|q3}kxG;XHK-yLD1te(>B-b_QDg zA#xne&eLryUApf|X%;!>*gY^8<$0vZ>%xK{<1h5Dhp#)fi#KASJ+YA<2Ya|j3H{Ny z**d=0;6dL44EqAeBf!0a3fMhmQjX_>tp(-DL~iR>G?WqRU}DP-XAU}4+!x$O_*@KH zAM9BV5e$hhzW;F}y&#hfOVr#Gf0#$lb`*19eq`e{2KM{i(_PL70P91J?PM_YE@VN= z*sp)_(Y4>uccbCE*#N5bh_+b8s!`}HHC2857v7|{&5BNLzwo(?3Q3Px97v{e^c7xe z-8W6>y!v9;Q4(Qd=e7^#Z#gy_;jXenh7o&xd;hFLOx2yJmWiT4?PB}Sru*2zx99Kl zDNj4Jh#vpO?e4;lDl~ZPrC5RrFQQE6EC+Gn!=|GD*jO>M(5yf>mc1F{O)1^$0%hZD`a*jbULOA?* zEjfB@&jn8TQ zceMJShkEng;<+KnJH;jA;>EQwIk>P|5vt=;AL7TGvI8`TRS`|vZ+-64+URrnC%*>C zt$N72lBNN`>>Hc)mZG(mLrtR&wFt_W{Jlb~B_F2m1)R4azMPY*gEp=@AF5Ti0cR{5 z1yeqAfsB*ULvdDIwy*~}=MV*z z;@6`ggz(ui_cC&H#Fc=6EmrF?dNgnbmjae+(swgj-_za+x;wp8z5x3+p-rUKQGEy`mLWL1;SMw9eg=64Q#9=!qe#KTp5L@|B*XvK{X2QSt~;o-QA>_J!KYoTrR-oC4Z?#%$Q$5VZTl_+E{9X?VLjld#h(Rc@e!$P zxf-u1w0&_3_?iAyfX=R%9j#@d>^m*HM?gbFOR#vGbOXkqkkU3QH&FF5YR|OtLT{QD z!@qf~1Eg;&i%DC|rPZm{@<|kG#a_fVbl80RTuj$iR8Ma%Yo`paT|2oiIJ=O-VBfZKVe#;x$(mm_0@Wx*D;2Xz9z43Z6{mq3*O~Mg4eW=nW(*HE4B~K%fhqj3#rtl7@=p)@ zoF?w2UZx!3a<2NSPOTzp46>5cocboE3Dcem-o(WsQIfpK;>g=eVhjom#7GA8Ov*6o zfr81ZH^C#MI{qHN>9P-0(mgeJXg$@Lk#@u`da^NfhK(geM@JuePt2fw`U-jn|7zj? zIc3LEaz+!x*I)|vS`cRRg4xU5!#-Gni+D60;q|Zqd72ERwCDrLVhB7K%_OrZWK<|!x4FrDT6JXS}?kP*>hwilu4kkx_mQkNcvZ&FvY}4 z2#Z7x694*8W&=81cJl{ViR5(D`4Qd;wScau$&UKJsYssdNiOTl2DJ5oMUoQ1SY99x zi3OjYI5!CefLq4oXr)d333n-yOwVuc(4y|hsKRQCg^=dajqnvL5Zyn8b4x~#g{S+2 zf~*tBiK#_&z5YqN5;baDz1*+e*I1ipmD5cY&)*5{Jh(fsKeU-;P>5A*GO?xjVhfrv zc~OYs(5X;(qK&4>@3m{KJ8n#wdv}&??N91Axe_@1ng4X!>nY|If71DLxk<495%daD*Kq2g9V}E!mzr(77@3JAk{xBNr>_lxUViE^L>x!l()FDcxiq zJ{H-D6Cvcrlz;hOO<7@{xD;Yl!Q^Td5JV~s>|(}U5ezYikeg&DX0RKV+YVK%d4Ng5 zIIa9t-G7ZMdWU6Xrq)mYZ=Ct>5A0j<=v00dM3w(xY@@x_YdkoQ`{Rj{t~-oh47*z& zwLBBTOpk>?4!xfuS_0FNoIqASvLZ=uZNi<>o}&hKaxoR+2ZG;zN}gfTWT=-@wK8>U zq)<18&8Zg`?@XH?|7-RRrnC@Wf<=x*Cs(;MUR3aO?p{nJ^z-Eohchmm&W=56SPcj6=g-)R5SbRP7T zs)pfcFONaLln=uRcWuf-K+C+l2PXwK%Q+?}x6i`n5MCRzJwL^!A!b}1;i?n8wm@g0 z*xq;q0I+thaIGYiO)krWs6LCuv32*~nR_}8UD14;g7uF$)VKt|L_B3G;|5!nSG0VK zeID_3z#ZlhnJK;N#p>{i^_H2qKeMjwQc_`}UH>oi8`yPc{ErsE|Fc^>x3hDP1S*KOhqKj(9A< z7g{r?^zB6wqxU@K24{maK-qIkvqKiM zN0zM|OMjvsMoUk%_V~WbCe7^(fzejy?iWV1UY^IiF`sZy-25JlRrpawZOd-m%);38 z&tb|>3a&`;!`x~YpUFU3j~>t8zxW)^Ex;`{KjE}{aY-1fwJG)XRNd$YkhwQEg0M)W zDLk(+pEqq*6UpEX)GH$=mTT~Hf-gerh^)co$l7o!6^zt;PN0g`D4`s1-?}iHQXJ0{ zeFzo}dUBGga|m{k-iQCls{+-g8oM9<;UwY;CfZ3ak8v)61Jb{Vi3tiiEYF~K4`6>|F&lH#(BFd@;Gnup zU^<9;QIX6cU-v@LoSqT5@nQxhZ-KIyt;@X(;RmzGpE)fZ)BEG2&bcb32{x80&K(In zz4&xl;ky98kX(~M>#ndpl3)5=LUoIpQ2iVpu zU9+%qA!fx}EUS%VF}Rw^NGN6|#@axa+jiU%T zle%}%Ax$Xs-z`HKCTdE~-{LQ0CUe?vHP4he2k1AkVmube!MI3mGml4O$%895wnC&B zqylDXml*?hbguY&*rYjsWu#U=lJcO2|H+I{mBht@Kl1k2vIoQn=NQEMjZHJ(8LO*% zH~ZQ%IAHtv1Q@B1Wm23YGpUW-1xrtK(1xZpQ$6u4rjdrRx2I0zXgu9lS1=UGShKTP z>|k7{9UL56R9@sE@KH}Ivi?fi!*^IiOQBOsF*F`@x6y^tDk20mJME8<{_dJs|%Jq#|*vxJqF0}EHz*ZYqI9-Zm4 z2Oe0a8O6b0vYe8A$g!4Ok2I5L#@kr^{W_vUr=?fr7E6OLl6>bh2X;&p0+0L-V)xFY zLjynM>{uLlpJJo^iEXNzC-_EnDPh1By6wJV6hCOiAPGa8W5AZ%?ek4nsX8>!MBdTV z$E#(oKA4}Z{k~urdB>W;$I{{}R;=54T2nHVAtbhkR2EbfGh}VL&ZO z3{Vhs~^T(i-=ZcSL}muc{-VJ(VR@c(BbGqr7fVdIDMxSU>fb~r# z7fFRhL&lzHq*2%BfZ`wejWyzOfNfY2%dPPf&EE`%o|+4^gQ!B%4^T%&w3q>?v^b3Y z7q0c#0ZaCD(NEqR#g)hXUd@>I)4RnxDq8GvvtP1{7KTqaZo+o&?eaJPzsSXxA@C3# zBsHRW1_t_S4c8xw{A-+qT%NE0e(v)GY9J~t1T=?<8t6wOPxMkK2Z{ms<+AP6D{7R5 zh9p5Er{-cEydJ#ndtlkh{?HIH+*feez71pyTvXw`LV9`zHVRkh-FD*a9mb!gf49@| zWT9#0^yX)QngokZ6uWqvFJz^ck;x2I$zgBAM3*zk6(G*qoFxG)va6|Svmv_lvI%tU zInhI?C+?4TH!oB`3w->k)S4*u|C5yf_QgA8i9A0eMJLmPK)DuxvQwa6BMy&-Yr$FH z{kdds7`=x6q+)%2aTc+@v}oD5?2uMrB@(oIl<2V==5Wsx5RQ0EH+|TnD(B$Bn|Q9* z=*kpHC0L1;S$bxi1*hLwyNah8m_y^77Z9y}hzj$o07|Aw;D1T5%Hr%V8E!qNA)7zc06 z=4KT)uUF4R^H(y(Li;=nV^B~HT~`^gi8T&jpJ)Vsab_Stq8o8A1Px5Bbqm14jF_Us zR8f_|@VbM^fTG{=YQ&#!S9-&j^{ql_&#BG-7wN(2zn)({l@=@tWDlufJX$#QW%5W< zxmuF~sO7F@e<}sv86*3MAjh0h}? zI4&NvHJeMGCMqm~H@^k>UB^McMW( zD^m;jN)B}7grK@?FbqM6&FWff{8dxYIr~Q^!FJTaNY7T3sFNMhqXyzozHP*-CW_swpFSy%+O-U4dz0BA%g?iJ)@+Hr= z64vdXkq_2Jrgu6*ZCYqg+1kY(M;HB&?4u4f(Sf~-tWDcM)o)`=ZmowDnZrg@S}nVg z-yZVL4ZH&tu3dOEl}*0%9+LiweH` zmSXH+z0emzkmeeLDG=bnZez4#4(0QT+ZfdxAAqkXRI)}mLM#?Ug^hR%)?ot`AP>gz zidmk~Z;FjI63ea=!bjH@=3+slU#fo`%+)-_FYE95r?q=-{&A4S8Cl9Hz3*Hfhaf)n zcwa!*NLRSCEttwyb_Jd%(gMj`&qLL!S!T%FR@4e_Oaq#~h)g$z@`mYE2mzU1FEis4 zZF4f}bDyAmId#dh?fNvdn0Kycsbyb}LY>`niXRcRC#u!v(i868v@pQT(fQ7%-s1K` zV-H{`r^P8(f2nh@AHBI6$l|C<+&!P|&b$)V0k(2!y*QCmBtuZ>Gz}GDcSA#?!R8&= zBS8OX-}+kW%M}?~y`P4^k9BBk8!1KW6N6vo*^7l%@GxL%Rm=odkgku2j1gzHxHQz} zk3MFiJbFhxC!f89X4Pgo>fGxn1KdU6^Ehl+U{x74+KLH`7E~a#d=~SC&Y?axvbj3` zC;7(vj){zWnR<=sN|aD>PW`Wl$b5^&2a)31SjxjQf4pUJru9tBB3RNl8D(hMa(e@G z2=n3A9Za6)=)P+@w?Ou_9_BWWNcs6rVa1uk{y}V24AbA(fFMQ~7k|cJ7vCEjQ&(F} z(@m*s_>dmK-VT;O&T{?QBbv;JHp;%b7#1Tlj`L6`Mb$;8IZ)@`&Jh{v4;bFC#CKToN>p2KkA zw(p5*1ShtBaVCtQQN`|tjo8kh7>pP+XGg=HGIBUElMoWNN@Qh4h6LUM6ha86N^8xD{&_ENNLY=>#T!INatIe88S&3IC$uz07Km9H^?3+Y$hV1 zfmYPG)x+&b>iuZ9=H76 z=fb%xGEk2Fa8=;m!dW8!zRvMb#;cEm*erwSXv_984UiiP!==#6QEZ)Cywj@I)udRq zwD0gr6_602u!NuR^6+X{wh09w?jQRi`~V#}X2_U^bUwfi9_kyc$cROEVXaxk3529a9|0=`&w zE-+EBsfSZ;rBQQ2luDJ>-*GT5ZaIH;=K;lF8+GOx)3bqu@{k^#Gcl~M6%mKv+ z{r}cRsEaXSUyNNS1Q{DQuFWjAiVIfn_M`KHlIzs-{k(;RnoTOkZZHh{Osr+z+Q9FF z$Jj!xTwUFQ>rk0)V*U=OukW(=a%y*4T=WDktDQAaFSAG#gSBM(X}2ihA`@wd^lmWR zN>5KC1~wj(TCyyUiIka2H}Z1F=UAr4S@^=``k}2_2!DPxA!!@a(yR3euQIU5AJr+G z(d0jqF9m<)MyD{|&V{bA7z@*jbH3SYk;nQc33%f_uy(!qRCTpn(Zn1%4Qm)oPlT}^f z#R~0>STuj8w7t~0@f&*moK1ySCj*slAxuJB3TJ9eUEa@uv<(C<)Q-&y@-)7iIaLs5 z&VBmZ%URfwL7wA&+b9^m<_23K;X~F*h9!SB2GobyQ`}(fVmSMWlG{h&c*w#yJ;o@R zO~Wu0IxNpIERcApO>azVzjcL3@+6UAQtm^9RYBduzTj&Fw?d+re6F_(I}lS&+*!=T zz$nGc`-096fulM0goWVbALjyaO;VEY@Q&K~uXnsSGIEVyORW4hs9fjCjVSv9<1D#V zo1>r;Pix2nEyQJZ00=P*f_tb^qs!UH+0g{t0-C#UYnwk6|8{XO4V@2#(2`7B7um|I zg8By0fa^<)7@2VZgeF@Dej3+wgyC=JYI!?j@YpKY4tUr3g!t00QbSSmawr4I7O+|0o#ihy|6Yzrv{!apMK@8%@USDL{|M9QOz-;4XD$>=Re9qfOdn7Co{=fFlHL8g-5926q zl`3kl%0+>esz=WXE-sit2-z83zk)^4T+RvW?_;HY-&af$%r8dAxvhc`>A2i*-v}AUnZY&GC4W#<@r5%-uL}y zlB(t>BgZ@MTOtn!&gHqvCesmnGgk-Vg@M%dE|b=Q{_y~)2m2(wUppG|iV&=%e!E1@ z%P21{lK3a1b{JK~x=!qo_Ah69lZ9#*0G>d_(9~%eVEF`zbx+0aeR1FmTN7(wYCM)_ zXb6Zwf-PhVo7k|;doEAh;|3uiB>54?^Yvs|K>@yo;hP(`f7^F64DqGeFnKWWoJu2m zcIM)S`d`zbPv(r`pTCio1y$fp-v~~n_gLhzkpi4y>^uBe+~Q0VG-segIUoMrf$fpR zycH+kvrl2YrB$iYJ1^8Xt=3}yaKPRU*k_&sHO3>*#j>;IxaqXi3b0vF8-|!Lf{m!J z22}6qV9z7B+|fbwoOt)0OvHZ7tzFg#fw-pYa=B0C>N`!uIbE(G#2~$DLuePQ0M&)R zO2;SDZ0pD-+@{Qs^iG%qk#f49;;+6;BL~CF@qq$50mMm-> zw-Om{wy>Jo_#pP~<&X>n%dx<%v;0l#3viE{>8ck7S%x5P4~%%8Sr*d3ZeaKDlnz82 zQ`RTV3_rlri5r3+M;ww~+bB@3O~^#sEO_LZT&6`*IV^6Og&*PR1WXpI@r>x?-8O0E z$ZqnI=r92lR}2)*-3N z0au5sy4%vW?aseo{!3+Xod`fUzvV6;97*yeL<^PbB{0(5f3? z?+^Yk!DPMj+%I4L*#x!9tkwPG{Szu(f0n39*EXaML``^0tGXk_T+~x5_VQPmZBgru znGO^y3>-5vz<{-sA1KkwbK`hyM51Km2PQfKjI)EOuh{D}B?Ra=Ffrue6PZpWXsO=| z9klW!P3>vh@wiut&C88k!-k{>0nXhWQ^udnAEs~(<%NW{I>dp7HA(SVQk<;T*M{2k zbnBdFCo|7H_RfzGrE!zZM?0XXm(nKr$r(K(E^dxl)^zfFM=ujzhe#!kj>y_B=zswi zE_9oH(U+WU##kxA<~tfBCZ+dKE)LsN$E-q`Q>bS2ib0B4FCWQ}`|2?)BOh>fULmB} zyQetYbi7M9LoKD0^YlIveh?^{TCp|MROU6!PrReSoJur!H49=ENoZXt#*0pS& zX%*7Xvo_hCyS^m1%(e(4?n+ezx7HfgIU=qccEv0Z>6Ygh$B|S7?iqbbZ^?gXwu!X_ z0J75p2Hc4_Z+pd-M`K;mc05)nsTXhcxr0LV8B?G|X|##KDx2o2?;OTGWd)rB7(Z9n zFf?tLkX(a9ibb-9D_^D-xx>?InGvBecrtvpIBiP#V<`|mA&8U)&h19{vR-Pl!e@IM zY&r=ugFWq@WJ%S%NPAZw&)y+aiv{g9h6VyjRmhxe=zrn&=+@XG_pppis{b|BJ5vHDz&nsWPLEIESpS@|u#F|&t?w{nmy=q#T zxC*?E<$vpM>Xf4~vBp|e9#F%*kr9r81z{Fr1}mV)Q%<>-E)%lTdt5F|lb?&-Zx>Lq zvmKMcHA((;IE*`B{W`AB(~6nxzjqH}%zU8t;ju_P(9$~^xKbW0vlkW&$srpOvV+w< zcjxdTvTb~ky{&9@r~@4xcsg-`U=xAciHB0%yp)I9@zOol)3yjYv|3$jfzG(NGta%? z0+OjSx;30iM@;y*hsxik%#_6(2zxZ<0ZPUg)=%6=P{YOC@NtGAR*6lG)(@Gom8bod z2{N~^qgKKBeutCH9jfl#%nIFl52t7)yUCB3@u72>6Oou~z0=jtF$T}HHzl=ZhCgWU zy9ZQ_Ix0$xeb+tJ{lj85f?I|f_^6|_n$^qK4N8gg3~$++R*(KI?vDY%I9C(%TfeW*A=a!kfwEe?30= z>4`gwE`L2`opYP~Dz7N~C)I=LNo%{Y4pNC{QJLPsHz54DR< zvthnQBAFJW3^sL*!Xy2S8UO@eEotn>e9Iv#j@L7U_CIe4Htc&jBS{{5YJIKSBTYar zhb@9hzS|F_>hZbVq&}^Q!WRIsoFP8(kNLjcQma$GLKdz`&}9nya>N zIliCMP%}JX&OmVuS4pimE%pvdPPRc&vAzZ@*lsPP>L3eswFG)Mhg^kO&lAp2Z?(U; z_zTpmlV)d!O1vs-lUtfJ%ME&^D=VISMmf+$cUh^m9qjBQ7JStOZ4?>%yn_n3c+4}b z#-fXifZpvyZcHzVIUuR`LMZHWcMfzDDgGeq@^z{}3{%B&mMxhvJ9A9baWQY{!jL8% z@9tY$n+&8UOtIdqBe=Z&qn)!v;kak98s*-zc%$}Y>jsqpFK>f2lPH!s9eDu4U8=Qm z+3-3$6EWFb>3djh90fDds;h6;oj)2J7}QxxW}H+^o~3didGJ+3$d`Ipg=~9#-h};I z9xT_V-{kxdESeYGG<%fHxH+|rk^jC$68;!0%TP|ljFi0QjQYlS9C&J2SnuU~{9~|} zYLy^m7v$8yYLQPvZT3MuWV%zD?j$z^97*gr&Gd|fgXU5ZLZB1HaYG2AYD#4L;zx?t z43N$-X~Of1R@MdE7(w687lLs9Dr+*p+*0s`<@&gQ2^*(UUvqmMCMv1~iw8a98Z7@* zrtzSeioiH`v)6dAJ_&Ps<^<6#Fg$=+l6ZJn=n^shaqr?%pKc$ybjid2Fgf$=h!*8@ zJL2{v^a9s*NE0i3*(>*xI}ee&GP4cwnu=1^Az&^aEPw=-mGj~PU;*mid^Cu1&1-K3 z2N)jA%|J6Fe!$;CK4!Mh80WY%6a$*zjW^aW40Vb4qdVs(#^a>*#yO)&sr58l*6eK= zQ~T{Q;N2a>wAE_8va1F?Yc#GXCf7t5ab6A>eVsfv;lCXW1}`yuZHLGmTGHsK8&#gg zBl~xsSM+RH@r&paO5DGX#VdS@tV(ZXWu@*yGI4)bD|z3Ce^$qs(XRjg8T6a!@tFZJ zEeTo@v?OQ>XbNZwXbNZwXbNZwXbNZwXbNZwXbNZwXbNZwXbNZwXbNZwXbNZwXbNZw zXbNZwXbNZwehmt8x<4Yq!j@ETetqMv(E2f2fwTgD4F%Gw3$3}MRY$9i_TK*&1&>MP zYrV6>s7K{=b3^N;#lPF%eSB8h($ literal 0 HcmV?d00001 From 08a49272f7b1f5e71b22e890e574252267e815f5 Mon Sep 17 00:00:00 2001 From: thingsboard017 Date: Tue, 17 Dec 2024 16:49:50 +0200 Subject: [PATCH 09/33] Updated company logos --- VENDORS/Bosch/logo.svg | 10 +++++----- VENDORS/Decentlab/logo.svg | 4 ++-- VENDORS/Elsys/logo.svg | 10 +++++----- VENDORS/Milesight/logo.svg | 10 +++++----- VENDORS/Netvox/logo.svg | 10 +++++----- VENDORS/Nwave/logo.svg | 10 +++++----- VENDORS/SensiEDGE/logo.svg | 10 +++++----- VENDORS/Yobiiq/logo.svg | 10 +++++----- 8 files changed, 37 insertions(+), 37 deletions(-) diff --git a/VENDORS/Bosch/logo.svg b/VENDORS/Bosch/logo.svg index 3ff8dbb7..33b82f41 100644 --- a/VENDORS/Bosch/logo.svg +++ b/VENDORS/Bosch/logo.svg @@ -1,9 +1,9 @@ - - + + - - + + - + diff --git a/VENDORS/Decentlab/logo.svg b/VENDORS/Decentlab/logo.svg index e70014a4..aea4f022 100644 --- a/VENDORS/Decentlab/logo.svg +++ b/VENDORS/Decentlab/logo.svg @@ -1,5 +1,5 @@ - - + + diff --git a/VENDORS/Elsys/logo.svg b/VENDORS/Elsys/logo.svg index 0c865b13..11e2c6a8 100644 --- a/VENDORS/Elsys/logo.svg +++ b/VENDORS/Elsys/logo.svg @@ -1,9 +1,9 @@ - - + + - - + + - + diff --git a/VENDORS/Milesight/logo.svg b/VENDORS/Milesight/logo.svg index 07ce8092..c0abf479 100644 --- a/VENDORS/Milesight/logo.svg +++ b/VENDORS/Milesight/logo.svg @@ -1,9 +1,9 @@ - - + + - - + + - + diff --git a/VENDORS/Netvox/logo.svg b/VENDORS/Netvox/logo.svg index 5a0c17cd..7efc7d79 100644 --- a/VENDORS/Netvox/logo.svg +++ b/VENDORS/Netvox/logo.svg @@ -1,9 +1,9 @@ - - + + - - + + - + diff --git a/VENDORS/Nwave/logo.svg b/VENDORS/Nwave/logo.svg index 4a0764b7..7b5b3689 100644 --- a/VENDORS/Nwave/logo.svg +++ b/VENDORS/Nwave/logo.svg @@ -1,9 +1,9 @@ - - + + - - + + - + diff --git a/VENDORS/SensiEDGE/logo.svg b/VENDORS/SensiEDGE/logo.svg index 39479f1d..22c4acbc 100644 --- a/VENDORS/SensiEDGE/logo.svg +++ b/VENDORS/SensiEDGE/logo.svg @@ -1,9 +1,9 @@ - - + + - - + + - + diff --git a/VENDORS/Yobiiq/logo.svg b/VENDORS/Yobiiq/logo.svg index b53db240..6ff5ef95 100644 --- a/VENDORS/Yobiiq/logo.svg +++ b/VENDORS/Yobiiq/logo.svg @@ -1,9 +1,9 @@ - - + + - - + + - + From 1df7d2f61d8939968dae0862bacff5e196adb954 Mon Sep 17 00:00:00 2001 From: thingsboard017 Date: Thu, 19 Dec 2024 12:44:55 +0200 Subject: [PATCH 10/33] Added 4 LNS integrations for Clover --- .../Clover/ChirpStack/uplink/converter.json | 39 +++++++++ .../Clover/ChirpStack/uplink/metadata.json | 4 + .../Clover/ChirpStack/uplink/payload.json | 48 +++++++++++ .../Clover/ChirpStack/uplink/payload_1.json | 48 +++++++++++ .../Clover/ChirpStack/uplink/result.json | 26 ++++++ .../Clover/ChirpStack/uplink/result_1.json | 28 +++++++ .../Clover/LORIOT/uplink/converter.json | 29 +++++++ .../Clover/LORIOT/uplink/metadata.json | 4 + .../Clover/LORIOT/uplink/payload.json | 17 ++++ .../Clover/LORIOT/uplink/payload_1.json | 17 ++++ .../Tektelic/Clover/LORIOT/uplink/result.json | 16 ++++ .../Clover/LORIOT/uplink/result_1.json | 18 ++++ .../uplink/converter.json | 39 +++++++++ .../ThingsStackCommunity/uplink/metadata.json | 4 + .../ThingsStackCommunity/uplink/payload.json | 54 ++++++++++++ .../uplink/payload_1.json | 54 ++++++++++++ .../ThingsStackCommunity/uplink/result.json | 27 ++++++ .../ThingsStackCommunity/uplink/result_1.json | 29 +++++++ .../uplink/converter.json | 40 +++++++++ .../uplink/metadata.json | 4 + .../ThingsStackIndustries/uplink/payload.json | 77 ++++++++++++++++++ .../uplink/payload_1.json | 77 ++++++++++++++++++ .../ThingsStackIndustries/uplink/result.json | 27 ++++++ .../uplink/result_1.json | 29 +++++++ VENDORS/Tektelic/Clover/info.json | 5 ++ VENDORS/Tektelic/Clover/photo.png | Bin 0 -> 104798 bytes VENDORS/Tektelic/info.json | 4 + VENDORS/Tektelic/logo.svg | 9 ++ 28 files changed, 773 insertions(+) create mode 100644 VENDORS/Tektelic/Clover/ChirpStack/uplink/converter.json create mode 100644 VENDORS/Tektelic/Clover/ChirpStack/uplink/metadata.json create mode 100644 VENDORS/Tektelic/Clover/ChirpStack/uplink/payload.json create mode 100644 VENDORS/Tektelic/Clover/ChirpStack/uplink/payload_1.json create mode 100644 VENDORS/Tektelic/Clover/ChirpStack/uplink/result.json create mode 100644 VENDORS/Tektelic/Clover/ChirpStack/uplink/result_1.json create mode 100644 VENDORS/Tektelic/Clover/LORIOT/uplink/converter.json create mode 100644 VENDORS/Tektelic/Clover/LORIOT/uplink/metadata.json create mode 100644 VENDORS/Tektelic/Clover/LORIOT/uplink/payload.json create mode 100644 VENDORS/Tektelic/Clover/LORIOT/uplink/payload_1.json create mode 100644 VENDORS/Tektelic/Clover/LORIOT/uplink/result.json create mode 100644 VENDORS/Tektelic/Clover/LORIOT/uplink/result_1.json create mode 100644 VENDORS/Tektelic/Clover/ThingsStackCommunity/uplink/converter.json create mode 100644 VENDORS/Tektelic/Clover/ThingsStackCommunity/uplink/metadata.json create mode 100644 VENDORS/Tektelic/Clover/ThingsStackCommunity/uplink/payload.json create mode 100644 VENDORS/Tektelic/Clover/ThingsStackCommunity/uplink/payload_1.json create mode 100644 VENDORS/Tektelic/Clover/ThingsStackCommunity/uplink/result.json create mode 100644 VENDORS/Tektelic/Clover/ThingsStackCommunity/uplink/result_1.json create mode 100644 VENDORS/Tektelic/Clover/ThingsStackIndustries/uplink/converter.json create mode 100644 VENDORS/Tektelic/Clover/ThingsStackIndustries/uplink/metadata.json create mode 100644 VENDORS/Tektelic/Clover/ThingsStackIndustries/uplink/payload.json create mode 100644 VENDORS/Tektelic/Clover/ThingsStackIndustries/uplink/payload_1.json create mode 100644 VENDORS/Tektelic/Clover/ThingsStackIndustries/uplink/result.json create mode 100644 VENDORS/Tektelic/Clover/ThingsStackIndustries/uplink/result_1.json create mode 100644 VENDORS/Tektelic/Clover/info.json create mode 100644 VENDORS/Tektelic/Clover/photo.png create mode 100644 VENDORS/Tektelic/info.json create mode 100644 VENDORS/Tektelic/logo.svg diff --git a/VENDORS/Tektelic/Clover/ChirpStack/uplink/converter.json b/VENDORS/Tektelic/Clover/ChirpStack/uplink/converter.json new file mode 100644 index 00000000..a228a916 --- /dev/null +++ b/VENDORS/Tektelic/Clover/ChirpStack/uplink/converter.json @@ -0,0 +1,39 @@ +{ + "name": "ChirpStack Uplink Decoder for Clover", + "type": "UPLINK", + "debugMode": false, + "debugSettings": { + "failuresEnabled": true, + "allEnabled": false, + "allEnabledUntil": 1733331880270 + }, + "configuration": { + "scriptLang": "TBEL", + "decoder": null, + "tbelDecoder": "var data = decodeToJson(payload);\nvar deviceName = data.deviceInfo.deviceName + \" \" + data.deviceInfo.devEui;\nvar deviceType = \"Clover\";\nvar groupName = null; // If groupName is not null - created device will be added to the entity group with such name.\nvar customerName = null; // If customerName is not null - created devices will be assigned to customer with such name. \n\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// If you want to parse incoming data somehow, you can add your code to this function.\n// input: bytes\n// expected output:\n// {\n// \"attributes\": {\"attributeKey\": \"attributeValue\"},\n// \"telemetry\": [{\"ts\": 1...1, \"values\": {\"telemetryKey\":\"telemetryValue\"}, {\"ts\": 1...2, \"values\": {\"telemetryKey\":\"telemetryValue\"}}]\n// }\n\nfunction decodePayload(input) {\n var output = {\n attributes: {},\n telemetry: []\n };\n \n // --- Decoding code --- //\n var decoded = {};\n var fPort = data.fPort;\n if(fPort == 10) {\n for(var i = 0; i < input.length - 2; ) {\n var key_1 = input[i++] & 0xff;\n var key_2 = input[i++] & 0xff;\n \n if(key_1 == 0x00 && key_2 == 0xBA) {\n var val = (input[i] >> 7) & 1; \n\n decoded.eos_alert = getAlarmStatus(val);\n var battery_bits = input[i] & 0x7F;\n decoded.battery_voltage = roundUsingMathRound(battery_bits * 0.01 + 2.5, 2);\n i += 1;\n }\n else if(key_1 == 0x00 && key_2 == 0xD3) {\n decoded.rem_batt_capacity = parseBytesToInt(input, i, 1);\n i += 1;\n }\n else if(key_1 == 0x00 && key_2 == 0xBD) {\n decoded.rem_batt_days = parseBytesToInt(input, i, 2);\n\t\t\t\ti += 2;\n }\n else if(key_1 == 0x01 && key_2 == 0x04) {\n var value = parseBytesToInt(input, i, 2);\n var frequencyMoisture = 0;\n\t\t\t\tif (value > 1399){\n\t\t\t\t\tfrequencyMoisture = \"Dry\";\n\t\t\t\t} else if (value > 1396 && value <= 1399){\n\t\t\t\t\tfrequencyMoisture = 0.1;\n\t\t\t\t} else if (value > 1391 && value <= 1396){\n\t\t\t\t\tfrequencyMoisture = 0.2;\n\t\t\t\t} else if (value > 1386 && value <= 1391){\n\t\t\t\t\tfrequencyMoisture = 0.3;\n\t\t\t\t} else if (value > 1381 && value <= 1386){\n\t\t\t\t\tfrequencyMoisture = 0.4;\n\t\t\t\t} else if (value > 1376 && value <= 1381){\n\t\t\t\t\tfrequencyMoisture = 0.5;\n\t\t\t\t} else if (value > 1371 && value <= 1376){\n\t\t\t\t\tfrequencyMoisture = 0.6;\n\t\t\t\t} else if (value > 1366 && value <= 1371){\n\t\t\t\t\tfrequencyMoisture = 0.7;\n\t\t\t\t} else if (value > 1361 && value <= 1366){\n\t\t\t\t\tfrequencyMoisture = 0.8;\n\t\t\t\t} else if (value > 1356 && value <= 1361){\n\t\t\t\t\tfrequencyMoisture = 0.9;\n\t\t\t\t} else if (value > 1351 && value <= 1356){\n\t\t\t\t\tfrequencyMoisture = 1.0;\n\t\t\t\t} else if (value > 1346 && value <= 1351){\n\t\t\t\t\tfrequencyMoisture = 1.1;\n\t\t\t\t} else if (value > 1341 && value <= 1346){\n\t\t\t\t\tfrequencyMoisture = 1.2;\n\t\t\t\t} else {\n\t\t\t\t\tfrequencyMoisture = \"Wet\";\n\t\t\t\t}\n\t\t\t\tdecoded.input1_frequency_to_moisture = frequencyMoisture;\n\t\t\t\tdecoded.input1_frequency = value;\n\t\t\t\ti += 2;\n }\n else if (key_1 == 0x02 && key_2 == 0x02) {\n var voltageValue = parseBytesToInt(input, i, 2) * 0.001;\n\t\t\t\tvar voltageTempOutput = -32.46 * Math.log(voltageValue * 1000) + 236.36;\n\t\t\t\tdecoded.input2_voltage_to_temp = roundUsingMathRound(voltageTempOutput, 1);\n\t\t\t\tdecoded.input2_voltage = voltageValue;\n\t\t\t\ti += 2;\n }\n else if (key1 == 0x03 && key2 == 0x02) {\n var input3Voltage = parseBytesToInt(input, i, 2) * 0.001;\n \n decoded.input3_voltage = input3Voltage;\n\t\t\t\tdecoded.input3_voltage_to_temp = roundUsingMathRound((-33.01 * Math.pow(input3Voltage, 5)) + (217.4 * Math.pow(input3Voltage, 4)) + (-538.6 * Math.pow(input3Voltage, 3)) + (628.1 * Math.pow(input3Voltage, 2)) + (-378.9 * input3Voltage) + 102.9, 1);\n \n i += 2;\n }\n else if (key1 == 0x03 && key2 == 0x67) {\n decoded.input3_temperature = parseBytesToInt(input, i, 2) * 0.1;\n\t\t\t\ti += 2;\n }\n else if (key1 == 0x04 && key2 == 0x02) {\n var input4Voltage = parseBytesToInt(input, i, 2) * 0.001;\n \n decoded.input4_voltage = input4Voltage;\n\t\t\t\tdecodedinput4_voltage_to_temp = roundUsingMathRound((-33.01 * Math.pow(input4Voltage, 5)) + (217.4 * Math.pow(input4Voltage, 4)) + (-538.6 * Math.pow(input4Voltage, 3)) + (628.1 * Math.pow(input4Voltage, 2)) + (-378.9 * input4Voltage) + 102.9, 1);\n \n i += 2;\n }\n else if (key1 == 0x04 && key2 == 0x67) {\n decoded.input4_temperature = parseBytesToInt(input, i, 2) * 0.1;\n\t\t\t\ti += 2;\n }\n else if (key1 == 0x05 && key2 == 0x04) {\n var watermark1Frequency = parseBytesToInt(input, i, 2);\n\t\t\t\t\n\t\t\t\tvar decodedWatermarkData1 = getWatermarkData(watermark1Frequency);\t\n\t\t\t\tdecoded.watermark1_tension = decodedWatermarkData1.watermarkTension;\n\t\t\t\tdecoded.watermark1_frequency = decodedWatermarkData1.watermarkFrequency;\n\t\t\t\t\n\t\t\t\ti += 2;\n }\n else if (key1 == 0x06 && key2 == 0x04) {\n var watermark2Frequency = parseBytesToInt(input, i, 2);\n\t\t\t\t\n\t\t\t\tvar decodedWatermarkData2 = getWatermarkData(watermark2Frequency);\t\n\t\t\t\tdecoded.watermark2_tension = decodedWatermarkData2.watermarkTension;\n\t\t\t\tdecoded.watermark2_frequency = decodedWatermarkData2.watermarkFrequency;\n\t\t\t\t\n\t\t\t\ti += 2;\n }\n else if (key1 == 0x09 && key2 == 0x65) {\n var lightIntensity = parseBytesToInt(input, i, 2);\n\t\t\t\t\n\t\t\t\tdecoded.light_intensity = lightIntensity; \n\t\t\t\ti += 2;\n }\n else if (key1 == 0x09 && key2 == 0x00) {\n var lightDetected = parseBytesToInt(input, i, 1);\n\t\t\t\tdecoded.light_detected = getAlarmStatus(lightDetected);\n\t\t\t\t\n\t\t\t\ti += 1;\n }\n else if (key1 == 0x0A && key2 == 0x71) {\n decoded.accelerationX = parseBytesToInt(input, i, 2);\n decoded.accelerationY = parseBytesToInt(input, i + 2, 2);\n decoded.accelerationZ = parseBytesToInt(input, i + 4, 2);\n }\n else if (key1 == 0x0A && key2 == 0x00) {\n var orientationAlarm = parseBytesToInt(input, i, 1);\n decoded.orientation_alarm = getAlarmStatus(orientationAlarm);\n\t\t\t\t\n\t\t\t\ti += 1;\n }\n else if (key1 == 0x0B && key2 == 0x67) {\n decoded.ambient_temperature = parseBytesToInt(input, i, 2) * 0.1;\n i += 2;\n }\n else if (key1 == 0x0B && key2 == 0x68) {\n decoded.relative_humidity = parseBytesToInt(input, i, 1) * 0.5;\n i += 1;\n }\n else if (key1 == 0x0C && key2 == 0x67) {\n decoded.mcu_temperature = parseBytesToInt(input, i, 2) * 0.1;\n i += 2;\n }\n else if (key1 == 0x0D && key2 == 0x73) {\n decoded.RFU_2 = parseBytesToInt(input, i, 1) * 0.1;\n i += 1;\n }\n }\n }\n else if (fPort == 100) {\n for(var i = 0; i < input.length -1; ) {\n var key = input[i++] & 0xff;\n \n if(key == 0x10) {\n var val = (((input[i] << 8) | input[i + 1]) >> 15) & 1;\n switch (val){\n\t\t\t\t\tcase 0:\n\t\t\t\t\t\toutput.attributes.loramac_join_mode = \"ABP\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 1:\n\t\t\t\t\t\toutput.attributes.loramac_join_mode = \"OTAA\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\toutput.attributes.loramac_join_mode = \"Invalid\";\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\ti += 1;\n }\n else if (key == 0x11) {\n var val = (((input[i] << 8) | input[i + 1]) >> 12) & 0xF;\n switch (val) {\n\t\t\t\t\tcase 0:\n\t\t\t\t\t\toutput.attributes.deviceClassEnabled = \"Class A\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 12:\n\t\t\t\t\t\toutput.attributes.deviceClassEnabled = \"Class C\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\toutput.attributes.deviceClassEnabled = \"Invalid\";\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tvar val = (((input[i] << 8) | input[i + 1]) >> 3) & 1;\n\t\t\t\toutput.attributes.adr = getEnableStatus(val);\n\t\t\t\t\n\t\t\t\tvar val = (((input[i] << 8) | input[i + 1]) >> 2) & 1;\n\t\t\t\toutput.attributes.duty_cycle = getEnableStatus(val);\n\t\t\t\t\n\t\t\t\tvar val = (((input[i] << 8) | input[i + 1]) >> 1) & 1;\n\t\t\t\t\n\t\t\t\tswitch (val) {\n\t\t\t\t\tcase 0:\n\t\t\t\t\t\toutput.attributes.sync_word = \"Private\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 1:\n\t\t\t\t\t\toutput.attributes.sync_word = \"Public\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\toutput.attributes.sync_word = \"Invalid\";\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tvar val = ((input[i] << 8) | input[i + 1]) & 1;\n\t\t\t\t\n\t\t\t\tswitch (val){\n\t\t\t\t\tcase 0:\n\t\t\t\t\t\toutput.attributes.confirm_mode = \"Unconfirmed\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 1:\n\t\t\t\t\t\toutput.attributes.confirm_mode = \"Confirmed\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t output.attributes.confirm_mode = \"Invalid\";\n\t\t\t\t}\n\t\t\t\ti += 2;\n }\n else if (key == 0x12) {\n output.attributes.dr_number = (((input[i] << 8) | input[i + 1]) >> 8) & 0xF;\n output.attributes.tx_power_number = ((input[i] << 8) | input[i + 1]) & 0xF;\n \n i +=2;\n }\n else if (key == 0x13) {\n output.attributes.frequency = (((input[i] << 32) | (input[i + 1] << 24) | (input[i + 2] << 16) | (input[i + 3] << 8) | input[i + 4]) >> 8) & 0xFFFFFFFF;\n output.attributes.dr_number_rx2 = input[i + 4] & 0xFF;\n \n i += 5;\n }\n else if (key == 0x20) {\n output.attributes.seconds_per_core_tick = parseBytesToInt(input, i, 4);\n i += 4;\n }\n else if(key == 0x21) {\n output.attributes.tick_per_battery = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x22) {\n output.attributes.tick_per_ambient_temperature = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x23) {\n output.attributes.tick_per_relative_humidity = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x24) {\n output.attributes.tick_per_light = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x25) {\n output.attributes.tick_per_input1 = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x26) {\n output.attributes.tick_per_input2 = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x27) {\n output.attributes.tick_per_input3 = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x28) {\n output.attributes.tick_per_input4 = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x29) {\n output.attributes.tick_per_watermark1 = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x2A) {\n output.attributes.tick_per_watermark2 = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x2C) {\n output.attributes.tick_per_accelerometer = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x2D) {\n output.attributes.tick_per_orientation_alarm = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x2E) {\n output.attributes.tick_per_mcu_temperature = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x2F) {\n output.attributes.RFU_1 = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x30) {\n output.attributes.temperature_relative_humidity_idle = parseBytesToInt(input, i, 4);\n i += 4;\n }\n else if(key == 0x31) {\n output.attributes.temperature_relative_humidity_active = parseBytesToInt(input, i, 4);\n i += 4;\n }\n else if(key == 0x32) {\n output.attributes.high_ambient_temp_raw = (((input[i] << 8) | input[i + 1]) >> 8) & 0xFF;\n output.attributes.low_ambient_temp_raw = ((input[i] << 8) | input[i + 1]) & 0xFF;\n \n i += 2;\n }\n else if(key == 0x33) {\n var val = input[i] & 1;\n output.attributes.ambient_temperature_threshold_enabled = getEnableStatus(val);\n\t\t\t\t\n\t\t\t\ti += 1;\n }\n else if (key == 0x34) {\n output.attributes.high_rh = input[i];\n\t\t\t\toutput.attributes.low_rh = input[i + 1];\n\t\t\t\t\n\t\t\t\ti += 2;\n }\n else if (key == 0x35) {\n var val = input[i] & 1;\n output.attributes.relative_humidity_threshold_enabled = getEnableStatus(val);\n\t\t\t\t\n\t\t\t\ti += 1;\n }\n else if (key == 0x36) {\n output.attributes.input_sample_period_idle = parseBytesToInt(input, i, 4);\n i += 4;\n }\n else if (key == 0x37) {\n output.attributes.input_sample_period_active = parseBytesToInt(input, i, 4);\n i += 4;\n }\n else if (key == 0x38) {\n output.attributes.low_input1 = parseBytesToInt(input, i, 2);\n output.attributes.high_input1 = parseBytesToInt(input, i + 2, 2);\n \n i += 4;\n }\n else if (key == 0x39) {\n output.attributes.low_input2 = parseBytesToInt(input, i, 2);\n output.attributes.high_input2 = parseBytesToInt(input, i + 2, 2);\n \n i += 4;\n }\n else if (key == 0x3A) {\n output.attributes.low_input3 = parseBytesToInt(input, i, 2);\n output.attributes.high_input3 = parseBytesToInt(input, i + 2, 2);\n \n i += 4;\n }\n else if (key == 0x3B) {\n output.attributes.low_input4 = parseBytesToInt(input, i, 2);\n output.attributes.high_input4 = parseBytesToInt(input, i + 2, 2);\n \n i += 4;\n }\n else if (key == 0x3C) {\n output.attributes.low_watermark1 = parseBytesToInt(input, i, 2);\n output.attributes.high_watermark1 = parseBytesToInt(input, i + 2, 2);\n \n i += 4;\n }\n else if (key == 0x3D) {\n output.attributes.low_watermark2 = parseBytesToInt(input, i, 2);\n output.attributes.high_watermark2 = parseBytesToInt(input, i + 2, 2);\n \n i += 4;\n }\n else if (key == 0x3F) {\n var input_status = input[i] & 0x3F;\n \n var bit0 = (input_status >> 0) & 1;\n output.attributes.input_enable_input1 = getEnableStatus(bit0);\n \n var bit1 = (input_status >> 1) & 1;\n output.attributes.input_enable_input2 = getEnableStatus(bit1);\n \n var bit2 = (input_status >> 2) & 1;\n output.attributes.input_enable_input3 = getEnableStatus(bit2);\n \n var bit3 = (input_status >> 3) & 1;\n output.attributes.input_enable_input4 = getEnableStatus(bit3);\n \n var bit4 = (input_status >> 4) & 1;\n output.attributes.input_enable_watermark1_enable = getEnableStatus(bit4);\n \n var bit5 = (input_status >> 5) & 1;\n output.attributes.input_enable_watermark2_enable = getEnableStatus(bit5);\n \n i += 1;\n }\n else if (key == 0x40) {\n output.attributes.mcu_temperature_sample_period_idle = parseBytesToInt(input, i, 4);\n i += 4;\n }\n else if (key == 0x41) {\n output.attributes.mcu_temperature_sample_period_active = parseBytesToInt(input, i, 4);\n i += 4;\n }\n else if (key == 0x42) {\n output.attributes.high_mcu_temp = input[i + 1];\n output.attributes.low_mcu_temp = input[i];\n i += 4;\n }\n else if (key == 0x43) {\n var val = input[i] & 1;\n output.attributes.mcu_temperature_enable = getEnableStatus(val);\n\n\t\t\t\ti += 2;\n }\n else if (key == 0x44) {\n output.attributes.low_input3_onewire = parseBytesToInt(input, i, 2);\n output.attributes.high_input3_onewire = parseBytesToInt(input, i + 2, 2);\n i += 2;\n }\n else if (key == 0x45) {\n output.attributes.low_input4_onewire = parseBytesToInt(input, i, 2);\n output.attributes.high_input4_onewire = parseBytesToInt(input, i + 2, 2);\n i += 2;\n }\n else if (key == 0x48 ) {\n var val = input[i] & 1;\n output.attributes.ALS_interrupt_enabled = getEnableStatus(val);\n \n i += 1;\n }\n else if (key == 0x49) {\n output.attributes.ALS_upper_threshold = parseBytesToInt(input, i, 2);\n i +=2;\n }\n else if (key == 0x4A) {\n output.attributes.ALS_lower_threshold = parseBytesToInt(input, i, 2);\n i +=2;\n }\n else if (key == 0x4B) {\n output.attributes.light_sample_period_idle = parseBytesToInt(input, i, 4);\n i +=4;\n }\n else if (key == 0x4C) {\n output.attributes.light_sample_period_active = parseBytesToInt(input, i, 4);\n i +=4;\n }\n else if (key == 0x4D) {\n var status = input[i] & 0x03;\n \n var bit1 = status & 1;\n output.attributes.light_alarm_reported = getReportStatus(bit1);\n \n var bit2 = (status >> 1) & 1;\n output.attributes.light_intensity_reported = getReportStatus(bit2);\n \n i += 1;\n }\n else if (key == 0x50) {\n output.attributes.orientation_alarm_threshold = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x51) {\n var status = input[i];\n\n var bit5 = (status >> 5) & 1;\n output.attributes.orientation_vector_report = getReportStatus(bit5);\n \n var bit0 = status & 1; \n output.attributes.orientation_alarm_report = getReportStatus(bit0);\n \n i += 1;\n }\n else if (key == 0x52) {\n var status = input[i]; \n \n var bit7 = (status >> 7) & 1; \n var bit0 = status & 1; \n \n switch (bit7) {\n case 0:\n output.attributes.accelerometer_power_on = \"Off\";\n break;\n case 1:\n output.attributes.accelerometer_power_on = \"On\";\n break;\n default:\n output.attributes.accelerometer_power_on = \"Invalid\";\n }\n \n output.attributes.orientation_alarm_mode = getEnableStatus(bit0);\n \n i += 1;\n }\n else if (key == 0x61) {\n var status = input[i]; \n \n var bit1 = (status >> 1) & 1;\n output.attributes.report_capacity_enabled = getEnableStatus(bit1);\n \n var bit2 = (status >> 2) & 1;\n output.attributes.report_lifetime_enabled = getEnableStatus(bit2);\n \n i += 1;\n }\n else if (key == 0x62) {\n output.attributes.avg_current_window = parseBytesToInt(input, i, 1);\n i += 1;\n }\n else if (key == 0x71) {\n output.attributes.app_major_version = input[i + 6];\n\t\t\t\toutput.attributes.app_minor_version = input[i + 5];\n\t\t\t\toutput.attributes.app_revision = input[i + 4];\n\t\t\t\toutput.attributes.loramac_major_version = input[i + 3];\n\t\t\t\toutput.attributes.loramac_minor_version = input[i + 2];\n\t\t\t\toutput.attributes.loramac_revision = input[i + 1];\n\t\t\t\tvar val = input[i];\n\t\t\t\tswitch (val){\n\t\t\t\t\tcase 0:\n\t\t\t\t\t\toutput.attributes.region = \"EU868\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 1:\n\t\t\t\t\t\toutput.attributes.region = \"US915\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 2:\n\t\t\t\t\t\toutput.attributes.region = \"AS923\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 3:\n\t\t\t\t\t\toutput.attributes.region = \"AU915\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 4:\n\t\t\t\t\t\toutput.attributes.region = \"IN865\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 6:\n\t\t\t\t\t\toutput.attributes.region = \"KR920\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 7:\n\t\t\t\t\t\toutput.attributes.region = \"RU864\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\toutput.attributes.region = \"Invalid\";\n\t\t\t\t}\n\t\t\t\ti += 7;\n }\n }\n }\n else if (fPort == 101) {\n var size = input.length;\n var responses = [];\n \n var index = 0;\n while (index < size) {\n var downlinkFcnt = input[index++] & 0xFF; \n var numInvalidWrites = input[index++] & 0xFF; \n \n if (numInvalidWrites > 0) {\n var invalidRegisters = [];\n for (var i = 0; i < numInvalidWrites; i++) {\n invalidRegisters.add(String.format(\"0x%02X\", input[index + i]));\n }\n index += numInvalidWrites;\n \n responses.add(String.format(\n \"%d Invalid write command(s) from DL:%d for register(s): %s\",\n numInvalidWrites, downlinkFcnt, String.join(\", \", invalidRegisters)\n ));\n } else {\n responses.add(String.format(\"All write commands from DL:%d were successful\", downlinkFcnt));\n }\n }\n \n decoded.response = responses;\n }\n\n output.telemetry = [{\n ts: timestamp,\n values: decoded\n }];\n // --- Decoding code --- //\n return output;\n}\n\n// --- attributes and telemetry objects ---\nvar telemetry = [];\nvar attributes = {};\n// --- attributes and telemetry objects ---\n\n// --- Timestamp parsing\nvar dateString = data.time;\ntimestamp = parseDateToTimestamp(dateString);\n// --- Timestamp parsing\n\n// Passing incoming bytes to decodePayload function, to get custom decoding\nvar customDecoding = decodePayload(base64ToBytes(data.data));\n\n\nattributes.eui = data.deviceInfo.devEui;\n\n// Collecting data to result\nif (customDecoding.?telemetry.size() > 0) {\n if (customDecoding.telemetry instanceof java.util.ArrayList) {\n foreach(telemetryObj: customDecoding.telemetry) {\n if (telemetryObj.ts != null && telemetryObj.values != null) {\n telemetry.add(telemetryObj);\n }\n }\n } else {\n telemetry.putAll(customDecoding.telemetry);\n }\n}\n\nif (customDecoding.?attributes.size() > 0) {\n attributes.putAll(customDecoding.attributes);\n}\n\n// You can add some keys manually to attributes or telemetry\nattributes.eui = data.deviceInfo.?devEui;\nattributes.devAddr = data.devAddr;\nattributes.fPort = data.fPort;\nattributes.applicationId = data.deviceInfo.?applicationId;\nattributes.applicationName = data.deviceInfo.?applicationName;\nattributes.tenantId = data.deviceInfo.?tenantId;\nattributes.tenantName = data.deviceInfo.?tenantName;\nattributes.deviceProfileId = data.deviceInfo.?deviceProfileId;\nattributes.deviceProfileName = data.deviceInfo.?deviceProfileName;\nattributes.frequency = data.txInfo.?frequency;\nattributes.bandwidth = data.txInfo.?modulation.?lora.?bandwidth;\nattributes.spreadingFactor = data.txInfo.?modulation.?lora.?spreadingFactor;\nattributes.codeRate = data.txInfo.?modulation.?lora.?codeRate;\n\nif(Boolean.parseBoolean(metadata[\"includeGatewayInfo\"])) {\n var gatewayInfo = getGatewayInfo();\n var addDataToTelemetry = {};\n addDataToTelemetry.snr = gatewayInfo.snr;\n addDataToTelemetry.rssi = gatewayInfo.rssi;\n addDataToTelemetry.channel = gatewayInfo.channel;\n addDataToTelemetry.rfChain = gatewayInfo.rfChain;\n addDataToTelemetry.fCnt = data.fCnt;\n \n telemetry = processTelemetryData(telemetry, addDataToTelemetry);\n}\n\nvar result = {\n deviceName: deviceName,\n deviceType: deviceType,\n // assetName: assetName,\n // assetType: assetType,\n attributes: attributes,\n telemetry: telemetry\n};\n\naddAdditionalInfoForDeviceMsg(result, customerName, groupName);\n\nreturn result;\n\nfunction addAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName) {\n if (customerName != null) {\n deviceInfo.customerName = customerName;\n }\n if (groupName != null) {\n deviceInfo.groupName = groupName;\n }\n}\n\nfunction parseDateToTimestamp(dateString) {\n var date = new Date(dateString);\n var timestamp = date.getTime();\n \n // If we cannot parse timestamp - we will use the current timestamp\n if (timestamp == -1) {\n timestamp = Date.now();\n }\n \n return timestamp;\n}\n\nfunction getGatewayInfo() {\n var gatewayList = data.rxInfo;\n var maxRssi = Integer.MIN_VALUE;\n var gatewayInfo = {};\n \n foreach (gateway : gatewayList) {\n if(gateway.rssi > maxRssi) {\n maxRssi = gateway.rssi;\n gatewayInfo = gateway;\n }\n }\n \n return gatewayInfo;\n}\n\nfunction processTelemetryData(telemetry, addDataToTelemetry) {\n if (telemetry.size >= 1) {\n telemetry = addDataToTelemetries(telemetry, addDataToTelemetry);\n }\n else {\n telemetry.add(addDataToTelemetry);\n }\n \n return telemetry;\n}\n\nfunction addDataToTelemetries(telemetries, addDataToTelemetry) {\n foreach(telemetry : telemetries) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[\"values\"].keys.contains(element.key)) {\n telemetry[\"values\"][element.key] = element.value;\n }\n } \n }\n \n return telemetries;\n}\n\nfunction getWatermarkData(watermarkFrequency) {\n var decodedWatermark = {};\n \n var watermarkTension = 0;\n if (watermarkFrequency > 6430){\n\t\twatermarkTension = 0;\n\t} else if (watermarkFrequency >= 4330 && watermarkFrequency <= 6430){\n\t watermarkTension = 9.000 - (watermarkFrequency - 4330.000) * 0.004286;\n\t} else if (watermarkFrequency >= 2820 && watermarkFrequency < 4330){\n\t\twatermarkTension = 15.000 - (watermarkFrequency - 2820.000) * 0.003974;\n\t} else if (watermarkFrequency >= 1110 && watermarkFrequency < 2820){\n\t\twatermarkTension = 35.000 - (watermarkFrequency - 1110.000) * 0.01170;\n\t} else if (watermarkFrequency >= 770 && watermarkFrequency < 1110){\n\t\twatermarkTension = 55.000 - (watermarkFrequency - 770.000) * 0.05884;\n\t} else if (watermarkFrequency >= 600 && watermarkFrequency < 770){\n\t\twatermarkTension = 75.000 - (watermarkFrequency - 600.000) * 0.1176;\n\t} else if (watermarkFrequency >= 485 && watermarkFrequency < 600){\n\t\twatermarkTension = 100.000 - (watermarkFrequency - 485.000) * 0.2174;\n } else if (watermarkFrequency >= 293 && watermarkFrequency < 485){\n\t\twatermarkTension = 200.000 - (watermarkFrequency - 293.000) * 0.5208;\n\t} else {\n\t watermarkTension = 200;\n\t}\t\t\t\t\t\n\tdecodedWatermark.watermarkTension = roundUsingMathRound(watermarkTension, 0);\n\tdecodedWatermark.watermarkFrequency = watermarkFrequency;\n\t\t\t\t\n return decodedWatermark;\n}\n\nfunction roundUsingMathRound(value, places) {\n if (places >= 0) {\n var factor = Math.pow(10, places);\n return Math.round(value * factor) / factor; \n }\n \n return value;\n}\n\nfunction getAlarmStatus(bit) {\n var alarmResult = \"Invalid\";\n \n if (bit === 0) {\n alarmResult = \"No Alarm\";\n } else if (bit === 1 || bit === 255) {\n alarmResult = \"Alarm\";\n } else {\n alarmResult = \"Invalid\";\n }\n \n return alarmResult;\n}\n\nfunction getEnableStatus(bit) {\n var enableResult = \"Invalid\";\n \n switch (bit) {\n\t\tcase 0:\n\t\t enableResult = \"Disable\";\n\t\t\tbreak;\n\t\tcase 1:\n\t\t\tenableResult = \"Enable\";\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tenableResult = \"Invalid\";\n\t}\n \n return enableResult;\n}\n\nfunction getReportStatus(bit) {\n var reportResult = \"Invalid\";\n \n switch (bit5) {\n case 0:\n reportResult = \"Ignore\";\n break;\n case 1:\n reportResult = \"Report\";\n break;\n default:\n reportResult = \"Invalid\";\n }\n \n return reportResult;\n}", + "encoder": null, + "tbelEncoder": null, + "updateOnlyKeys": [ + "tenantId", + "tenantName", + "applicationId", + "applicationName", + "deviceProfileId", + "deviceProfileName", + "devAddr", + "fPort", + "frequency", + "bandwidth", + "spreadingFactor", + "codeRate", + "channel", + "rfChain", + "eui", + "battery" + ] + }, + "additionalInfo": { + "description": "" + }, + "edgeTemplate": false +} \ No newline at end of file diff --git a/VENDORS/Tektelic/Clover/ChirpStack/uplink/metadata.json b/VENDORS/Tektelic/Clover/ChirpStack/uplink/metadata.json new file mode 100644 index 00000000..23f54b34 --- /dev/null +++ b/VENDORS/Tektelic/Clover/ChirpStack/uplink/metadata.json @@ -0,0 +1,4 @@ +{ + "integrationName": "ChirpStack integration", + "includeGatewayInfo": "false" +} \ No newline at end of file diff --git a/VENDORS/Tektelic/Clover/ChirpStack/uplink/payload.json b/VENDORS/Tektelic/Clover/ChirpStack/uplink/payload.json new file mode 100644 index 00000000..9663c8dd --- /dev/null +++ b/VENDORS/Tektelic/Clover/ChirpStack/uplink/payload.json @@ -0,0 +1,48 @@ +{ + "deduplicationId": "57433366-50a6-4dc2-8145-2df1bbc70d9e", + "time": "2023-05-22T07:47:05.404859+00:00", + "deviceInfo": { + "tenantId": "52f14cd4-c6f1-4fbd-8f87-4025e1d49242", + "tenantName": "ChirpStack", + "applicationId": "ca739e26-7b67-4f14-b69e-d568c22a5a75", + "applicationName": "Chirpstack application", + "deviceProfileId": "605d08d4-65f5-4d2c-8a5a-3d2457662f79", + "deviceProfileName": "Chirpstack default device profile", + "deviceName": "Device name", + "devEui": "1000000000000001", + "tags": {} + }, + "devAddr": "20000001", + "adr": true, + "dr": 5, + "fCnt": 4, + "fPort": 10, + "confirmed": false, + "data": "ANNaAL0KCg==", + "rxInfo": [{ + "gatewayId": "6a7e111a10000000", + "uplinkId": 24022, + "time": "2023-05-22T07:47:05.404859+00:00", + "rssi": -35, + "snr": 11.5, + "channel": 2, + "rfChain": 1, + "location": {}, + "context": "EFwMtA==", + "metadata": { + "region_common_name": "EU868", + "region_config_id": "eu868" + }, + "crcStatus": "CRC_OK" + }], + "txInfo": { + "frequency": 868500000, + "modulation": { + "lora": { + "bandwidth": 125000, + "spreadingFactor": 7, + "codeRate": "CR_4_5" + } + } + } +} \ No newline at end of file diff --git a/VENDORS/Tektelic/Clover/ChirpStack/uplink/payload_1.json b/VENDORS/Tektelic/Clover/ChirpStack/uplink/payload_1.json new file mode 100644 index 00000000..384793b8 --- /dev/null +++ b/VENDORS/Tektelic/Clover/ChirpStack/uplink/payload_1.json @@ -0,0 +1,48 @@ +{ + "deduplicationId": "57433366-50a6-4dc2-8145-2df1bbc70d9e", + "time": "2023-05-22T07:47:05.404859+00:00", + "deviceInfo": { + "tenantId": "52f14cd4-c6f1-4fbd-8f87-4025e1d49242", + "tenantName": "ChirpStack", + "applicationId": "ca739e26-7b67-4f14-b69e-d568c22a5a75", + "applicationName": "Chirpstack application", + "deviceProfileId": "605d08d4-65f5-4d2c-8a5a-3d2457662f79", + "deviceProfileName": "Chirpstack default device profile", + "deviceName": "Device name", + "devEui": "1000000000000001", + "tags": {} + }, + "devAddr": "20000001", + "adr": true, + "dr": 5, + "fCnt": 4, + "fPort": 10, + "confirmed": false, + "data": "AQQFeQICAtU=", + "rxInfo": [{ + "gatewayId": "6a7e111a10000000", + "uplinkId": 24022, + "time": "2023-05-22T07:47:05.404859+00:00", + "rssi": -35, + "snr": 11.5, + "channel": 2, + "rfChain": 1, + "location": {}, + "context": "EFwMtA==", + "metadata": { + "region_common_name": "EU868", + "region_config_id": "eu868" + }, + "crcStatus": "CRC_OK" + }], + "txInfo": { + "frequency": 868500000, + "modulation": { + "lora": { + "bandwidth": 125000, + "spreadingFactor": 7, + "codeRate": "CR_4_5" + } + } + } +} \ No newline at end of file diff --git a/VENDORS/Tektelic/Clover/ChirpStack/uplink/result.json b/VENDORS/Tektelic/Clover/ChirpStack/uplink/result.json new file mode 100644 index 00000000..293d7f0f --- /dev/null +++ b/VENDORS/Tektelic/Clover/ChirpStack/uplink/result.json @@ -0,0 +1,26 @@ +{ + "deviceName": "Device name 1000000000000001", + "deviceType": "Clover", + "attributes": { + "eui": "1000000000000001", + "devAddr": "20000001", + "fPort": 10, + "applicationId": "ca739e26-7b67-4f14-b69e-d568c22a5a75", + "applicationName": "Chirpstack application", + "tenantId": "52f14cd4-c6f1-4fbd-8f87-4025e1d49242", + "tenantName": "ChirpStack", + "deviceProfileId": "605d08d4-65f5-4d2c-8a5a-3d2457662f79", + "deviceProfileName": "Chirpstack default device profile", + "frequency": 868500000, + "bandwidth": 125000, + "spreadingFactor": 7, + "codeRate": "CR_4_5" + }, + "telemetry": [{ + "ts": 1684741625404, + "values": { + "rem_batt_capacity": 90, + "rem_batt_days": 2570 + } + }] +} \ No newline at end of file diff --git a/VENDORS/Tektelic/Clover/ChirpStack/uplink/result_1.json b/VENDORS/Tektelic/Clover/ChirpStack/uplink/result_1.json new file mode 100644 index 00000000..252d0cbd --- /dev/null +++ b/VENDORS/Tektelic/Clover/ChirpStack/uplink/result_1.json @@ -0,0 +1,28 @@ +{ + "deviceName": "Device name 1000000000000001", + "deviceType": "Clover", + "attributes": { + "eui": "1000000000000001", + "devAddr": "20000001", + "fPort": 10, + "applicationId": "ca739e26-7b67-4f14-b69e-d568c22a5a75", + "applicationName": "Chirpstack application", + "tenantId": "52f14cd4-c6f1-4fbd-8f87-4025e1d49242", + "tenantName": "ChirpStack", + "deviceProfileId": "605d08d4-65f5-4d2c-8a5a-3d2457662f79", + "deviceProfileName": "Chirpstack default device profile", + "frequency": 868500000, + "bandwidth": 125000, + "spreadingFactor": 7, + "codeRate": "CR_4_5" + }, + "telemetry": [{ + "ts": 1684741625404, + "values": { + "input1_frequency_to_moisture": "Dry", + "input1_frequency": 1401, + "input2_voltage_to_temp": 22.6, + "input2_voltage": 0.725 + } + }] +} \ No newline at end of file diff --git a/VENDORS/Tektelic/Clover/LORIOT/uplink/converter.json b/VENDORS/Tektelic/Clover/LORIOT/uplink/converter.json new file mode 100644 index 00000000..45129d37 --- /dev/null +++ b/VENDORS/Tektelic/Clover/LORIOT/uplink/converter.json @@ -0,0 +1,29 @@ +{ + "name": "Loriot Uplink Decoder for Clover", + "type": "UPLINK", + "debugMode": false, + "debugSettings": { + "failuresEnabled": true, + "allEnabled": false, + "allEnabledUntil": 1733331880270 + }, + "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);\nvar deviceName = data.EUI;\nvar deviceType = \"Clover\";\nvar groupName = null; // If groupName is not null - created device will be added to the entity group with such name.\nvar customerName = null; // If customerName is not null - created devices will be assigned to customer with such name. \n\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// If you want to parse incoming data somehow, you can add your code to this function.\n// input: bytes\n// expected output:\n// {\n// \"attributes\": {\"attributeKey\": \"attributeValue\"},\n// \"telemetry\": {\"telemetryKey\": \"telemetryValue\"}\n// }\n\nfunction decodePayload(input) {\n var output = { attributes: {}, telemetry: []};\n \n var decoded = {};\n var fPort = data.port;\n if(fPort == 10) {\n for(var i = 0; i < input.length - 2; ) {\n var key_1 = input[i++] & 0xff;\n var key_2 = input[i++] & 0xff;\n \n if(key_1 == 0x00 && key_2 == 0xBA) {\n var val = (input[i] >> 7) & 1; \n\n decoded.eos_alert = getAlarmStatus(val);\n var battery_bits = input[i] & 0x7F;\n decoded.battery_voltage = roundUsingMathRound(battery_bits * 0.01 + 2.5, 2);\n i += 1;\n }\n else if(key_1 == 0x00 && key_2 == 0xD3) {\n decoded.rem_batt_capacity = parseBytesToInt(input, i, 1);\n i += 1;\n }\n else if(key_1 == 0x00 && key_2 == 0xBD) {\n decoded.rem_batt_days = parseBytesToInt(input, i, 2);\n\t\t\t\ti += 2;\n }\n else if(key_1 == 0x01 && key_2 == 0x04) {\n var value = parseBytesToInt(input, i, 2);\n var frequencyMoisture = 0;\n\t\t\t\tif (value > 1399){\n\t\t\t\t\tfrequencyMoisture = \"Dry\";\n\t\t\t\t} else if (value > 1396 && value <= 1399){\n\t\t\t\t\tfrequencyMoisture = 0.1;\n\t\t\t\t} else if (value > 1391 && value <= 1396){\n\t\t\t\t\tfrequencyMoisture = 0.2;\n\t\t\t\t} else if (value > 1386 && value <= 1391){\n\t\t\t\t\tfrequencyMoisture = 0.3;\n\t\t\t\t} else if (value > 1381 && value <= 1386){\n\t\t\t\t\tfrequencyMoisture = 0.4;\n\t\t\t\t} else if (value > 1376 && value <= 1381){\n\t\t\t\t\tfrequencyMoisture = 0.5;\n\t\t\t\t} else if (value > 1371 && value <= 1376){\n\t\t\t\t\tfrequencyMoisture = 0.6;\n\t\t\t\t} else if (value > 1366 && value <= 1371){\n\t\t\t\t\tfrequencyMoisture = 0.7;\n\t\t\t\t} else if (value > 1361 && value <= 1366){\n\t\t\t\t\tfrequencyMoisture = 0.8;\n\t\t\t\t} else if (value > 1356 && value <= 1361){\n\t\t\t\t\tfrequencyMoisture = 0.9;\n\t\t\t\t} else if (value > 1351 && value <= 1356){\n\t\t\t\t\tfrequencyMoisture = 1.0;\n\t\t\t\t} else if (value > 1346 && value <= 1351){\n\t\t\t\t\tfrequencyMoisture = 1.1;\n\t\t\t\t} else if (value > 1341 && value <= 1346){\n\t\t\t\t\tfrequencyMoisture = 1.2;\n\t\t\t\t} else {\n\t\t\t\t\tfrequencyMoisture = \"Wet\";\n\t\t\t\t}\n\t\t\t\tdecoded.input1_frequency_to_moisture = frequencyMoisture;\n\t\t\t\tdecoded.input1_frequency = value;\n\t\t\t\ti += 2;\n }\n else if (key_1 == 0x02 && key_2 == 0x02) {\n var voltageValue = parseBytesToInt(input, i, 2) * 0.001;\n\t\t\t\tvar voltageTempOutput = -32.46 * Math.log(voltageValue * 1000) + 236.36;\n\t\t\t\tdecoded.input2_voltage_to_temp = roundUsingMathRound(voltageTempOutput, 1);\n\t\t\t\tdecoded.input2_voltage = voltageValue;\n\t\t\t\ti += 2;\n }\n else if (key1 == 0x03 && key2 == 0x02) {\n var input3Voltage = parseBytesToInt(input, i, 2) * 0.001;\n \n decoded.input3_voltage = input3Voltage;\n\t\t\t\tdecoded.input3_voltage_to_temp = roundUsingMathRound((-33.01 * Math.pow(input3Voltage, 5)) + (217.4 * Math.pow(input3Voltage, 4)) + (-538.6 * Math.pow(input3Voltage, 3)) + (628.1 * Math.pow(input3Voltage, 2)) + (-378.9 * input3Voltage) + 102.9, 1);\n \n i += 2;\n }\n else if (key1 == 0x03 && key2 == 0x67) {\n decoded.input3_temperature = parseBytesToInt(input, i, 2) * 0.1;\n\t\t\t\ti += 2;\n }\n else if (key1 == 0x04 && key2 == 0x02) {\n var input4Voltage = parseBytesToInt(input, i, 2) * 0.001;\n \n decoded.input4_voltage = input4Voltage;\n\t\t\t\tdecodedinput4_voltage_to_temp = roundUsingMathRound((-33.01 * Math.pow(input4Voltage, 5)) + (217.4 * Math.pow(input4Voltage, 4)) + (-538.6 * Math.pow(input4Voltage, 3)) + (628.1 * Math.pow(input4Voltage, 2)) + (-378.9 * input4Voltage) + 102.9, 1);\n \n i += 2;\n }\n else if (key1 == 0x04 && key2 == 0x67) {\n decoded.input4_temperature = parseBytesToInt(input, i, 2) * 0.1;\n\t\t\t\ti += 2;\n }\n else if (key1 == 0x05 && key2 == 0x04) {\n var watermark1Frequency = parseBytesToInt(input, i, 2);\n\t\t\t\t\n\t\t\t\tvar decodedWatermarkData1 = getWatermarkData(watermark1Frequency);\t\n\t\t\t\tdecoded.watermark1_tension = decodedWatermarkData1.watermarkTension;\n\t\t\t\tdecoded.watermark1_frequency = decodedWatermarkData1.watermarkFrequency;\n\t\t\t\t\n\t\t\t\ti += 2;\n }\n else if (key1 == 0x06 && key2 == 0x04) {\n var watermark2Frequency = parseBytesToInt(input, i, 2);\n\t\t\t\t\n\t\t\t\tvar decodedWatermarkData2 = getWatermarkData(watermark2Frequency);\t\n\t\t\t\tdecoded.watermark2_tension = decodedWatermarkData2.watermarkTension;\n\t\t\t\tdecoded.watermark2_frequency = decodedWatermarkData2.watermarkFrequency;\n\t\t\t\t\n\t\t\t\ti += 2;\n }\n else if (key1 == 0x09 && key2 == 0x65) {\n var lightIntensity = parseBytesToInt(input, i, 2);\n\t\t\t\t\n\t\t\t\tdecoded.light_intensity = lightIntensity; \n\t\t\t\ti += 2;\n }\n else if (key1 == 0x09 && key2 == 0x00) {\n var lightDetected = parseBytesToInt(input, i, 1);\n\t\t\t\tdecoded.light_detected = getAlarmStatus(lightDetected);\n\t\t\t\t\n\t\t\t\ti += 1;\n }\n else if (key1 == 0x0A && key2 == 0x71) {\n decoded.accelerationX = parseBytesToInt(input, i, 2);\n decoded.accelerationY = parseBytesToInt(input, i + 2, 2);\n decoded.accelerationZ = parseBytesToInt(input, i + 4, 2);\n }\n else if (key1 == 0x0A && key2 == 0x00) {\n var orientationAlarm = parseBytesToInt(input, i, 1);\n decoded.orientation_alarm = getAlarmStatus(orientationAlarm);\n\t\t\t\t\n\t\t\t\ti += 1;\n }\n else if (key1 == 0x0B && key2 == 0x67) {\n decoded.ambient_temperature = parseBytesToInt(input, i, 2) * 0.1;\n i += 2;\n }\n else if (key1 == 0x0B && key2 == 0x68) {\n decoded.relative_humidity = parseBytesToInt(input, i, 1) * 0.5;\n i += 1;\n }\n else if (key1 == 0x0C && key2 == 0x67) {\n decoded.mcu_temperature = parseBytesToInt(input, i, 2) * 0.1;\n i += 2;\n }\n else if (key1 == 0x0D && key2 == 0x73) {\n decoded.RFU_2 = parseBytesToInt(input, i, 1) * 0.1;\n i += 1;\n }\n }\n }\n else if (fPort == 100) {\n for(var i = 0; i < input.length -1; ) {\n var key = input[i++] & 0xff;\n \n if(key == 0x10) {\n var val = (((input[i] << 8) | input[i + 1]) >> 15) & 1;\n switch (val){\n\t\t\t\t\tcase 0:\n\t\t\t\t\t\toutput.attributes.loramac_join_mode = \"ABP\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 1:\n\t\t\t\t\t\toutput.attributes.loramac_join_mode = \"OTAA\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\toutput.attributes.loramac_join_mode = \"Invalid\";\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\ti += 1;\n }\n else if (key == 0x11) {\n var val = (((input[i] << 8) | input[i + 1]) >> 12) & 0xF;\n switch (val) {\n\t\t\t\t\tcase 0:\n\t\t\t\t\t\toutput.attributes.deviceClassEnabled = \"Class A\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 12:\n\t\t\t\t\t\toutput.attributes.deviceClassEnabled = \"Class C\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\toutput.attributes.deviceClassEnabled = \"Invalid\";\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tvar val = (((input[i] << 8) | input[i + 1]) >> 3) & 1;\n\t\t\t\toutput.attributes.adr = getEnableStatus(val);\n\t\t\t\t\n\t\t\t\tvar val = (((input[i] << 8) | input[i + 1]) >> 2) & 1;\n\t\t\t\toutput.attributes.duty_cycle = getEnableStatus(val);\n\t\t\t\t\n\t\t\t\tvar val = (((input[i] << 8) | input[i + 1]) >> 1) & 1;\n\t\t\t\t\n\t\t\t\tswitch (val) {\n\t\t\t\t\tcase 0:\n\t\t\t\t\t\toutput.attributes.sync_word = \"Private\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 1:\n\t\t\t\t\t\toutput.attributes.sync_word = \"Public\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\toutput.attributes.sync_word = \"Invalid\";\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tvar val = ((input[i] << 8) | input[i + 1]) & 1;\n\t\t\t\t\n\t\t\t\tswitch (val){\n\t\t\t\t\tcase 0:\n\t\t\t\t\t\toutput.attributes.confirm_mode = \"Unconfirmed\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 1:\n\t\t\t\t\t\toutput.attributes.confirm_mode = \"Confirmed\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t output.attributes.confirm_mode = \"Invalid\";\n\t\t\t\t}\n\t\t\t\ti += 2;\n }\n else if (key == 0x12) {\n output.attributes.dr_number = (((input[i] << 8) | input[i + 1]) >> 8) & 0xF;\n output.attributes.tx_power_number = ((input[i] << 8) | input[i + 1]) & 0xF;\n \n i +=2;\n }\n else if (key == 0x13) {\n output.attributes.frequency = (((input[i] << 32) | (input[i + 1] << 24) | (input[i + 2] << 16) | (input[i + 3] << 8) | input[i + 4]) >> 8) & 0xFFFFFFFF;\n output.attributes.dr_number_rx2 = input[i + 4] & 0xFF;\n \n i += 5;\n }\n else if (key == 0x20) {\n output.attributes.seconds_per_core_tick = parseBytesToInt(input, i, 4);\n i += 4;\n }\n else if(key == 0x21) {\n output.attributes.tick_per_battery = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x22) {\n output.attributes.tick_per_ambient_temperature = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x23) {\n output.attributes.tick_per_relative_humidity = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x24) {\n output.attributes.tick_per_light = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x25) {\n output.attributes.tick_per_input1 = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x26) {\n output.attributes.tick_per_input2 = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x27) {\n output.attributes.tick_per_input3 = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x28) {\n output.attributes.tick_per_input4 = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x29) {\n output.attributes.tick_per_watermark1 = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x2A) {\n output.attributes.tick_per_watermark2 = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x2C) {\n output.attributes.tick_per_accelerometer = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x2D) {\n output.attributes.tick_per_orientation_alarm = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x2E) {\n output.attributes.tick_per_mcu_temperature = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x2F) {\n output.attributes.RFU_1 = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x30) {\n output.attributes.temperature_relative_humidity_idle = parseBytesToInt(input, i, 4);\n i += 4;\n }\n else if(key == 0x31) {\n output.attributes.temperature_relative_humidity_active = parseBytesToInt(input, i, 4);\n i += 4;\n }\n else if(key == 0x32) {\n output.attributes.high_ambient_temp_raw = (((input[i] << 8) | input[i + 1]) >> 8) & 0xFF;\n output.attributes.low_ambient_temp_raw = ((input[i] << 8) | input[i + 1]) & 0xFF;\n \n i += 2;\n }\n else if(key == 0x33) {\n var val = input[i] & 1;\n output.attributes.ambient_temperature_threshold_enabled = getEnableStatus(val);\n\t\t\t\t\n\t\t\t\ti += 1;\n }\n else if (key == 0x34) {\n output.attributes.high_rh = input[i];\n\t\t\t\toutput.attributes.low_rh = input[i + 1];\n\t\t\t\t\n\t\t\t\ti += 2;\n }\n else if (key == 0x35) {\n var val = input[i] & 1;\n output.attributes.relative_humidity_threshold_enabled = getEnableStatus(val);\n\t\t\t\t\n\t\t\t\ti += 1;\n }\n else if (key == 0x36) {\n output.attributes.input_sample_period_idle = parseBytesToInt(input, i, 4);\n i += 4;\n }\n else if (key == 0x37) {\n output.attributes.input_sample_period_active = parseBytesToInt(input, i, 4);\n i += 4;\n }\n else if (key == 0x38) {\n output.attributes.low_input1 = parseBytesToInt(input, i, 2);\n output.attributes.high_input1 = parseBytesToInt(input, i + 2, 2);\n \n i += 4;\n }\n else if (key == 0x39) {\n output.attributes.low_input2 = parseBytesToInt(input, i, 2);\n output.attributes.high_input2 = parseBytesToInt(input, i + 2, 2);\n \n i += 4;\n }\n else if (key == 0x3A) {\n output.attributes.low_input3 = parseBytesToInt(input, i, 2);\n output.attributes.high_input3 = parseBytesToInt(input, i + 2, 2);\n \n i += 4;\n }\n else if (key == 0x3B) {\n output.attributes.low_input4 = parseBytesToInt(input, i, 2);\n output.attributes.high_input4 = parseBytesToInt(input, i + 2, 2);\n \n i += 4;\n }\n else if (key == 0x3C) {\n output.attributes.low_watermark1 = parseBytesToInt(input, i, 2);\n output.attributes.high_watermark1 = parseBytesToInt(input, i + 2, 2);\n \n i += 4;\n }\n else if (key == 0x3D) {\n output.attributes.low_watermark2 = parseBytesToInt(input, i, 2);\n output.attributes.high_watermark2 = parseBytesToInt(input, i + 2, 2);\n \n i += 4;\n }\n else if (key == 0x3F) {\n var input_status = input[i] & 0x3F;\n \n var bit0 = (input_status >> 0) & 1;\n output.attributes.input_enable_input1 = getEnableStatus(bit0);\n \n var bit1 = (input_status >> 1) & 1;\n output.attributes.input_enable_input2 = getEnableStatus(bit1);\n \n var bit2 = (input_status >> 2) & 1;\n output.attributes.input_enable_input3 = getEnableStatus(bit2);\n \n var bit3 = (input_status >> 3) & 1;\n output.attributes.input_enable_input4 = getEnableStatus(bit3);\n \n var bit4 = (input_status >> 4) & 1;\n output.attributes.input_enable_watermark1_enable = getEnableStatus(bit4);\n \n var bit5 = (input_status >> 5) & 1;\n output.attributes.input_enable_watermark2_enable = getEnableStatus(bit5);\n \n i += 1;\n }\n else if (key == 0x40) {\n output.attributes.mcu_temperature_sample_period_idle = parseBytesToInt(input, i, 4);\n i += 4;\n }\n else if (key == 0x41) {\n output.attributes.mcu_temperature_sample_period_active = parseBytesToInt(input, i, 4);\n i += 4;\n }\n else if (key == 0x42) {\n output.attributes.high_mcu_temp = input[i + 1];\n output.attributes.low_mcu_temp = input[i];\n i += 4;\n }\n else if (key == 0x43) {\n var val = input[i] & 1;\n output.attributes.mcu_temperature_enable = getEnableStatus(val);\n\n\t\t\t\ti += 2;\n }\n else if (key == 0x44) {\n output.attributes.low_input3_onewire = parseBytesToInt(input, i, 2);\n output.attributes.high_input3_onewire = parseBytesToInt(input, i + 2, 2);\n i += 2;\n }\n else if (key == 0x45) {\n output.attributes.low_input4_onewire = parseBytesToInt(input, i, 2);\n output.attributes.high_input4_onewire = parseBytesToInt(input, i + 2, 2);\n i += 2;\n }\n else if (key == 0x48 ) {\n var val = input[i] & 1;\n output.attributes.ALS_interrupt_enabled = getEnableStatus(val);\n \n i += 1;\n }\n else if (key == 0x49) {\n output.attributes.ALS_upper_threshold = parseBytesToInt(input, i, 2);\n i +=2;\n }\n else if (key == 0x4A) {\n output.attributes.ALS_lower_threshold = parseBytesToInt(input, i, 2);\n i +=2;\n }\n else if (key == 0x4B) {\n output.attributes.light_sample_period_idle = parseBytesToInt(input, i, 4);\n i +=4;\n }\n else if (key == 0x4C) {\n output.attributes.light_sample_period_active = parseBytesToInt(input, i, 4);\n i +=4;\n }\n else if (key == 0x4D) {\n var status = input[i] & 0x03;\n \n var bit1 = status & 1;\n output.attributes.light_alarm_reported = getReportStatus(bit1);\n \n var bit2 = (status >> 1) & 1;\n output.attributes.light_intensity_reported = getReportStatus(bit2);\n \n i += 1;\n }\n else if (key == 0x50) {\n output.attributes.orientation_alarm_threshold = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x51) {\n var status = input[i];\n\n var bit5 = (status >> 5) & 1;\n output.attributes.orientation_vector_report = getReportStatus(bit5);\n \n var bit0 = status & 1; \n output.attributes.orientation_alarm_report = getReportStatus(bit0);\n \n i += 1;\n }\n else if (key == 0x52) {\n var status = input[i]; \n \n var bit7 = (status >> 7) & 1; \n var bit0 = status & 1; \n \n switch (bit7) {\n case 0:\n output.attributes.accelerometer_power_on = \"Off\";\n break;\n case 1:\n output.attributes.accelerometer_power_on = \"On\";\n break;\n default:\n output.attributes.accelerometer_power_on = \"Invalid\";\n }\n \n output.attributes.orientation_alarm_mode = getEnableStatus(bit0);\n \n i += 1;\n }\n else if (key == 0x61) {\n var status = input[i]; \n \n var bit1 = (status >> 1) & 1;\n output.attributes.report_capacity_enabled = getEnableStatus(bit1);\n \n var bit2 = (status >> 2) & 1;\n output.attributes.report_lifetime_enabled = getEnableStatus(bit2);\n \n i += 1;\n }\n else if (key == 0x62) {\n output.attributes.avg_current_window = parseBytesToInt(input, i, 1);\n i += 1;\n }\n else if (key == 0x71) {\n output.attributes.app_major_version = input[i + 6];\n\t\t\t\toutput.attributes.app_minor_version = input[i + 5];\n\t\t\t\toutput.attributes.app_revision = input[i + 4];\n\t\t\t\toutput.attributes.loramac_major_version = input[i + 3];\n\t\t\t\toutput.attributes.loramac_minor_version = input[i + 2];\n\t\t\t\toutput.attributes.loramac_revision = input[i + 1];\n\t\t\t\tvar val = input[i];\n\t\t\t\tswitch (val){\n\t\t\t\t\tcase 0:\n\t\t\t\t\t\toutput.attributes.region = \"EU868\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 1:\n\t\t\t\t\t\toutput.attributes.region = \"US915\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 2:\n\t\t\t\t\t\toutput.attributes.region = \"AS923\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 3:\n\t\t\t\t\t\toutput.attributes.region = \"AU915\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 4:\n\t\t\t\t\t\toutput.attributes.region = \"IN865\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 6:\n\t\t\t\t\t\toutput.attributes.region = \"KR920\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 7:\n\t\t\t\t\t\toutput.attributes.region = \"RU864\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\toutput.attributes.region = \"Invalid\";\n\t\t\t\t}\n\t\t\t\ti += 7;\n }\n }\n }\n else if (fPort == 101) {\n var size = input.length;\n var responses = [];\n \n var index = 0;\n while (index < size) {\n var downlinkFcnt = input[index++] & 0xFF; \n var numInvalidWrites = input[index++] & 0xFF; \n \n if (numInvalidWrites > 0) {\n var invalidRegisters = [];\n for (var i = 0; i < numInvalidWrites; i++) {\n invalidRegisters.add(String.format(\"0x%02X\", input[index + i]));\n }\n index += numInvalidWrites;\n \n responses.add(String.format(\n \"%d Invalid write command(s) from DL:%d for register(s): %s\",\n numInvalidWrites, downlinkFcnt, String.join(\", \", invalidRegisters)\n ));\n } else {\n responses.add(String.format(\"All write commands from DL:%d were successful\", downlinkFcnt));\n }\n }\n \n decoded.response = responses;\n }\n \n output.telemetry = [{\n ts: timestamp,\n values: decoded\n }];\n\n // --- Decoding code --- //\n return output;\n}\n\n// --- attributes and telemetry objects ---\nvar telemetry = [];\nvar attributes = {};\n// --- attributes and telemetry objects ---\n\n// --- Timestamp parsing\ntimestamp = data.ts;\n// --- Timestamp parsing\n\n// Message parsing\n// To avoid paths in the decoded objects we passing false value to function as \"pathInKey\" argument.\n// Warning: pathInKey can cause already found fields to be overwritten with the last value found.\n\nvar uplinkDataList = [];\n\n// Passing incoming bytes to decodePayload function, to get custom decoding\nvar customDecoding = decodePayload(hexToBytes(data.data));\n\n// Collecting data to result\nif (customDecoding.?telemetry.size() > 0) {\n if (customDecoding.telemetry instanceof java.util.ArrayList) {\n foreach(telemetryObj: customDecoding.telemetry) {\n if (telemetryObj.ts != null && telemetryObj.values != null) {\n telemetry.add(telemetryObj);\n }\n }\n } else {\n telemetry.putAll(customDecoding.telemetry);\n }\n}\n\nif (customDecoding.?attributes.size() > 0) {\n attributes.putAll(customDecoding.attributes);\n}\n\n// You can add some keys manually to attributes or telemetry\nattributes.eui = data.EUI;\nattributes.fPort = data.port;\nattributes.frequency = data.freq;\n\nvar isIncludeGatewayInfo = metadata[\"includeGatewayInfo\"];\nif(isIncludeGatewayInfo == true) {\n var addDataToTelemetry = {};\n addDataToTelemetry.rssi = data.rssi;\n addDataToTelemetry.seqno = data.seqno;\n addDataToTelemetry.snr = data.snr;\n addDataToTelemetry.ack = data.ack;\n addDataToTelemetry.toa = data.toa;\n addDataToTelemetry.fCnt = data.fcnt;\n \n telemetry = processTelemetryData(telemetry, addDataToTelemetry);\n}\n\nvar deviceInfo = {\n deviceName: deviceName,\n deviceType: deviceType,\n// assetName: assetName,\n// assetType: assetType,\n attributes: attributes,\n telemetry: telemetry, \n};\n\naddAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName);\n\nuplinkDataList.add(deviceInfo);\n\nvar gatewayDeviceNamePrefix = \"Gateway \";\nvar gatewayDeviceType = \"Lora gateway\";\nvar gatewayGroupName = null; // If gatewayGroupName is not null - created device will be added to the entity group with such name.\n\nif (data.cmd == \"gw\") {\n foreach( gatewayInfo : data.gws ) {\n var addGatewayInfo = {};\n\n // You can add some keys manually telemetry\n addGatewayInfo.rssi = gatewayInfo.rssi;\n addGatewayInfo.snr = gatewayInfo.snr;\n // You can add some keys manually telemetry\n \n var gatewayInfoMsg = {\n deviceName: gatewayDeviceNamePrefix + gatewayInfo.gweui,\n deviceType: gatewayDeviceType,\n telemetry: [{\n \"ts\": gatewayInfo.ts,\n \"values\": addGatewayInfo\n }],\n attributes: {\n eui: gatewayInfo.gweui\n }\n };\n addAdditionalInfoForDeviceMsg(gatewayInfoMsg, customerName, gatewayGroupName);\n uplinkDataList.add(gatewayInfoMsg);\n }\n}\n\nreturn uplinkDataList;\n\nfunction addAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName) {\n if (customerName != null) {\n deviceInfo.customerName = customerName;\n }\n if (groupName != null) {\n deviceInfo.groupName = groupName;\n }\n}\n\nfunction processTelemetryData(telemetry, addDataToTelemetry) {\n if (telemetry.size >= 1) {\n telemetry = addDataToTelemetries(telemetry, addDataToTelemetry);\n }\n else {\n telemetry.add(addDataToTelemetry);\n }\n \n return telemetry;\n}\n\nfunction addDataToTelemetries(telemetries, addDataToTelemetry) {\n foreach(telemetry : telemetries) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[\"values\"].keys.contains(element.key)) {\n telemetry[\"values\"][element.key] = element.value;\n }\n } \n }\n \n return telemetries;\n}\n\nfunction getWatermarkData(watermarkFrequency) {\n var decodedWatermark = {};\n \n var watermarkTension = 0;\n if (watermarkFrequency > 6430){\n\t\twatermarkTension = 0;\n\t} else if (watermarkFrequency >= 4330 && watermarkFrequency <= 6430){\n\t watermarkTension = 9.000 - (watermarkFrequency - 4330.000) * 0.004286;\n\t} else if (watermarkFrequency >= 2820 && watermarkFrequency < 4330){\n\t\twatermarkTension = 15.000 - (watermarkFrequency - 2820.000) * 0.003974;\n\t} else if (watermarkFrequency >= 1110 && watermarkFrequency < 2820){\n\t\twatermarkTension = 35.000 - (watermarkFrequency - 1110.000) * 0.01170;\n\t} else if (watermarkFrequency >= 770 && watermarkFrequency < 1110){\n\t\twatermarkTension = 55.000 - (watermarkFrequency - 770.000) * 0.05884;\n\t} else if (watermarkFrequency >= 600 && watermarkFrequency < 770){\n\t\twatermarkTension = 75.000 - (watermarkFrequency - 600.000) * 0.1176;\n\t} else if (watermarkFrequency >= 485 && watermarkFrequency < 600){\n\t\twatermarkTension = 100.000 - (watermarkFrequency - 485.000) * 0.2174;\n } else if (watermarkFrequency >= 293 && watermarkFrequency < 485){\n\t\twatermarkTension = 200.000 - (watermarkFrequency - 293.000) * 0.5208;\n\t} else {\n\t watermarkTension = 200;\n\t}\t\t\t\t\t\n\tdecodedWatermark.watermarkTension = roundUsingMathRound(watermarkTension, 0);\n\tdecodedWatermark.watermarkFrequency = watermarkFrequency;\n\t\t\t\t\n return decodedWatermark;\n}\n\nfunction roundUsingMathRound(value, places) {\n if (places >= 0) {\n var factor = Math.pow(10, places);\n return Math.round(value * factor) / factor; \n }\n \n return value;\n}\n\nfunction getAlarmStatus(bit) {\n var alarmResult = \"Invalid\";\n \n if (bit === 0) {\n alarmResult = \"No Alarm\";\n } else if (bit === 1 || bit === 255) {\n alarmResult = \"Alarm\";\n } else {\n alarmResult = \"Invalid\";\n }\n \n return alarmResult;\n}\n\nfunction getEnableStatus(bit) {\n var enableResult = \"Invalid\";\n \n switch (bit) {\n\t\tcase 0:\n\t\t enableResult = \"Disable\";\n\t\t\tbreak;\n\t\tcase 1:\n\t\t\tenableResult = \"Enable\";\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tenableResult = \"Invalid\";\n\t}\n \n return enableResult;\n}\n\nfunction getReportStatus(bit) {\n var reportResult = \"Invalid\";\n \n switch (bit5) {\n case 0:\n reportResult = \"Ignore\";\n break;\n case 1:\n reportResult = \"Report\";\n break;\n default:\n reportResult = \"Invalid\";\n }\n \n return reportResult;\n}", + "encoder": null, + "tbelEncoder": null, + "updateOnlyKeys": [ + "fPort", + "ack", + "eui", + "frequency", + "dr", + "battery" + ] + }, + "additionalInfo": { + "description": "" + }, + "edgeTemplate": false +} \ No newline at end of file diff --git a/VENDORS/Tektelic/Clover/LORIOT/uplink/metadata.json b/VENDORS/Tektelic/Clover/LORIOT/uplink/metadata.json new file mode 100644 index 00000000..ae2ee743 --- /dev/null +++ b/VENDORS/Tektelic/Clover/LORIOT/uplink/metadata.json @@ -0,0 +1,4 @@ +{ + "integrationName": "Loriot integration", + "includeGatewayInfo": "false" +} \ No newline at end of file diff --git a/VENDORS/Tektelic/Clover/LORIOT/uplink/payload.json b/VENDORS/Tektelic/Clover/LORIOT/uplink/payload.json new file mode 100644 index 00000000..9840ad99 --- /dev/null +++ b/VENDORS/Tektelic/Clover/LORIOT/uplink/payload.json @@ -0,0 +1,17 @@ +{ + "cmd": "rx", + "seqno": 3040, + "EUI": "1000000000000001", + "ts": 1684478801936, + "fcnt": 2, + "port": 10, + "freq": 867500000, + "rssi": -21, + "snr": 10, + "toa": 206, + "dr": "SF9 BW125 4/5", + "ack": false, + "bat": 94, + "offline": false, + "data": "00d35a00bd0a0a" +} \ No newline at end of file diff --git a/VENDORS/Tektelic/Clover/LORIOT/uplink/payload_1.json b/VENDORS/Tektelic/Clover/LORIOT/uplink/payload_1.json new file mode 100644 index 00000000..c93999c7 --- /dev/null +++ b/VENDORS/Tektelic/Clover/LORIOT/uplink/payload_1.json @@ -0,0 +1,17 @@ +{ + "cmd": "rx", + "seqno": 3040, + "EUI": "1000000000000001", + "ts": 1684478801936, + "fcnt": 2, + "port": 10, + "freq": 867500000, + "rssi": -21, + "snr": 10, + "toa": 206, + "dr": "SF9 BW125 4/5", + "ack": false, + "bat": 94, + "offline": false, + "data": "01040579020202d5" +} \ No newline at end of file diff --git a/VENDORS/Tektelic/Clover/LORIOT/uplink/result.json b/VENDORS/Tektelic/Clover/LORIOT/uplink/result.json new file mode 100644 index 00000000..81ed555c --- /dev/null +++ b/VENDORS/Tektelic/Clover/LORIOT/uplink/result.json @@ -0,0 +1,16 @@ +[{ + "deviceName": "1000000000000001", + "deviceType": "Clover", + "attributes": { + "eui": "1000000000000001", + "fPort": 10, + "frequency": 867500000 + }, + "telemetry": [{ + "ts": 1684478801936, + "values": { + "rem_batt_capacity": 90, + "rem_batt_days": 2570 + } + }] +}] \ No newline at end of file diff --git a/VENDORS/Tektelic/Clover/LORIOT/uplink/result_1.json b/VENDORS/Tektelic/Clover/LORIOT/uplink/result_1.json new file mode 100644 index 00000000..fa770668 --- /dev/null +++ b/VENDORS/Tektelic/Clover/LORIOT/uplink/result_1.json @@ -0,0 +1,18 @@ +[{ + "deviceName": "1000000000000001", + "deviceType": "Clover", + "attributes": { + "eui": "1000000000000001", + "fPort": 10, + "frequency": 867500000 + }, + "telemetry": [{ + "ts": 1684478801936, + "values": { + "input1_frequency_to_moisture": "Dry", + "input1_frequency": 1401, + "input2_voltage_to_temp": 22.6, + "input2_voltage": 0.725 + } + }] +}] \ No newline at end of file diff --git a/VENDORS/Tektelic/Clover/ThingsStackCommunity/uplink/converter.json b/VENDORS/Tektelic/Clover/ThingsStackCommunity/uplink/converter.json new file mode 100644 index 00000000..630ede7b --- /dev/null +++ b/VENDORS/Tektelic/Clover/ThingsStackCommunity/uplink/converter.json @@ -0,0 +1,39 @@ +{ + "name": "The Things Stack Community Uplink Decoder for Clover", + "type": "UPLINK", + "debugMode": false, + "debugSettings": { + "failuresEnabled": true, + "allEnabled": false, + "allEnabledUntil": 1733331880270 + }, + "configuration": { + "scriptLang": "TBEL", + "decoder": null, + "tbelDecoder": "var data = decodeToJson(payload);\n\nvar deviceName = data.end_device_ids.device_id;\nvar deviceType = \"Clover\";\nvar groupName = null; // If groupName is not null - created device will be added to the entity group with such name.\nvar customerName = null; // If customerName is not null - created devices will be assigned to customer with such name. \n\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// If you want to parse incoming data somehow, you can add your code to this function.\n// input: bytes\n// expected output:\n// {\n// \"attributes\": {\"attributeKey\": \"attributeValue\"},\n// \"telemetry\": [{\"ts\": 1...1, \"values\": {\"telemetryKey\":\"telemetryValue\"}, {\"ts\": 1...2, \"values\": {\"telemetryKey\":\"telemetryValue\"}}]\n// }\n\nfunction decodeFrmPayload(input) {\n var output = {\n attributes: {}, telemetry: {}\n };\n \n // --- Decoding code --- //\n var decoded = {};\n var fPort = data.uplink_message.f_port;\n if(fPort == 10) {\n for(var i = 0; i < input.length - 2; ) {\n var key_1 = input[i++] & 0xff;\n var key_2 = input[i++] & 0xff;\n \n if(key_1 == 0x00 && key_2 == 0xBA) {\n var val = (input[i] >> 7) & 1; \n\n decoded.eos_alert = getAlarmStatus(val);\n var battery_bits = input[i] & 0x7F;\n decoded.battery_voltage = roundUsingMathRound(battery_bits * 0.01 + 2.5, 2);\n i += 1;\n }\n else if(key_1 == 0x00 && key_2 == 0xD3) {\n decoded.rem_batt_capacity = parseBytesToInt(input, i, 1);\n i += 1;\n }\n else if(key_1 == 0x00 && key_2 == 0xBD) {\n decoded.rem_batt_days = parseBytesToInt(input, i, 2);\n\t\t\t\ti += 2;\n }\n else if(key_1 == 0x01 && key_2 == 0x04) {\n var value = parseBytesToInt(input, i, 2);\n var frequencyMoisture = 0;\n\t\t\t\tif (value > 1399){\n\t\t\t\t\tfrequencyMoisture = \"Dry\";\n\t\t\t\t} else if (value > 1396 && value <= 1399){\n\t\t\t\t\tfrequencyMoisture = 0.1;\n\t\t\t\t} else if (value > 1391 && value <= 1396){\n\t\t\t\t\tfrequencyMoisture = 0.2;\n\t\t\t\t} else if (value > 1386 && value <= 1391){\n\t\t\t\t\tfrequencyMoisture = 0.3;\n\t\t\t\t} else if (value > 1381 && value <= 1386){\n\t\t\t\t\tfrequencyMoisture = 0.4;\n\t\t\t\t} else if (value > 1376 && value <= 1381){\n\t\t\t\t\tfrequencyMoisture = 0.5;\n\t\t\t\t} else if (value > 1371 && value <= 1376){\n\t\t\t\t\tfrequencyMoisture = 0.6;\n\t\t\t\t} else if (value > 1366 && value <= 1371){\n\t\t\t\t\tfrequencyMoisture = 0.7;\n\t\t\t\t} else if (value > 1361 && value <= 1366){\n\t\t\t\t\tfrequencyMoisture = 0.8;\n\t\t\t\t} else if (value > 1356 && value <= 1361){\n\t\t\t\t\tfrequencyMoisture = 0.9;\n\t\t\t\t} else if (value > 1351 && value <= 1356){\n\t\t\t\t\tfrequencyMoisture = 1.0;\n\t\t\t\t} else if (value > 1346 && value <= 1351){\n\t\t\t\t\tfrequencyMoisture = 1.1;\n\t\t\t\t} else if (value > 1341 && value <= 1346){\n\t\t\t\t\tfrequencyMoisture = 1.2;\n\t\t\t\t} else {\n\t\t\t\t\tfrequencyMoisture = \"Wet\";\n\t\t\t\t}\n\t\t\t\tdecoded.input1_frequency_to_moisture = frequencyMoisture;\n\t\t\t\tdecoded.input1_frequency = value;\n\t\t\t\ti += 2;\n }\n else if (key_1 == 0x02 && key_2 == 0x02) {\n var voltageValue = parseBytesToInt(input, i, 2) * 0.001;\n\t\t\t\tvar voltageTempOutput = -32.46 * Math.log(voltageValue * 1000) + 236.36;\n\t\t\t\tdecoded.input2_voltage_to_temp = roundUsingMathRound(voltageTempOutput, 1);\n\t\t\t\tdecoded.input2_voltage = voltageValue;\n\t\t\t\ti += 2;\n }\n else if (key1 == 0x03 && key2 == 0x02) {\n var input3Voltage = parseBytesToInt(input, i, 2) * 0.001;\n \n decoded.input3_voltage = input3Voltage;\n\t\t\t\tdecoded.input3_voltage_to_temp = roundUsingMathRound((-33.01 * Math.pow(input3Voltage, 5)) + (217.4 * Math.pow(input3Voltage, 4)) + (-538.6 * Math.pow(input3Voltage, 3)) + (628.1 * Math.pow(input3Voltage, 2)) + (-378.9 * input3Voltage) + 102.9, 1);\n \n i += 2;\n }\n else if (key1 == 0x03 && key2 == 0x67) {\n decoded.input3_temperature = parseBytesToInt(input, i, 2) * 0.1;\n\t\t\t\ti += 2;\n }\n else if (key1 == 0x04 && key2 == 0x02) {\n var input4Voltage = parseBytesToInt(input, i, 2) * 0.001;\n \n decoded.input4_voltage = input4Voltage;\n\t\t\t\tdecodedinput4_voltage_to_temp = roundUsingMathRound((-33.01 * Math.pow(input4Voltage, 5)) + (217.4 * Math.pow(input4Voltage, 4)) + (-538.6 * Math.pow(input4Voltage, 3)) + (628.1 * Math.pow(input4Voltage, 2)) + (-378.9 * input4Voltage) + 102.9, 1);\n \n i += 2;\n }\n else if (key1 == 0x04 && key2 == 0x67) {\n decoded.input4_temperature = parseBytesToInt(input, i, 2) * 0.1;\n\t\t\t\ti += 2;\n }\n else if (key1 == 0x05 && key2 == 0x04) {\n var watermark1Frequency = parseBytesToInt(input, i, 2);\n\t\t\t\t\n\t\t\t\tvar decodedWatermarkData1 = getWatermarkData(watermark1Frequency);\t\n\t\t\t\tdecoded.watermark1_tension = decodedWatermarkData1.watermarkTension;\n\t\t\t\tdecoded.watermark1_frequency = decodedWatermarkData1.watermarkFrequency;\n\t\t\t\t\n\t\t\t\ti += 2;\n }\n else if (key1 == 0x06 && key2 == 0x04) {\n var watermark2Frequency = parseBytesToInt(input, i, 2);\n\t\t\t\t\n\t\t\t\tvar decodedWatermarkData2 = getWatermarkData(watermark2Frequency);\t\n\t\t\t\tdecoded.watermark2_tension = decodedWatermarkData2.watermarkTension;\n\t\t\t\tdecoded.watermark2_frequency = decodedWatermarkData2.watermarkFrequency;\n\t\t\t\t\n\t\t\t\ti += 2;\n }\n else if (key1 == 0x09 && key2 == 0x65) {\n var lightIntensity = parseBytesToInt(input, i, 2);\n\t\t\t\t\n\t\t\t\tdecoded.light_intensity = lightIntensity; \n\t\t\t\ti += 2;\n }\n else if (key1 == 0x09 && key2 == 0x00) {\n var lightDetected = parseBytesToInt(input, i, 1);\n\t\t\t\tdecoded.light_detected = getAlarmStatus(lightDetected);\n\t\t\t\t\n\t\t\t\ti += 1;\n }\n else if (key1 == 0x0A && key2 == 0x71) {\n decoded.accelerationX = parseBytesToInt(input, i, 2);\n decoded.accelerationY = parseBytesToInt(input, i + 2, 2);\n decoded.accelerationZ = parseBytesToInt(input, i + 4, 2);\n }\n else if (key1 == 0x0A && key2 == 0x00) {\n var orientationAlarm = parseBytesToInt(input, i, 1);\n decoded.orientation_alarm = getAlarmStatus(orientationAlarm);\n\t\t\t\t\n\t\t\t\ti += 1;\n }\n else if (key1 == 0x0B && key2 == 0x67) {\n decoded.ambient_temperature = parseBytesToInt(input, i, 2) * 0.1;\n i += 2;\n }\n else if (key1 == 0x0B && key2 == 0x68) {\n decoded.relative_humidity = parseBytesToInt(input, i, 1) * 0.5;\n i += 1;\n }\n else if (key1 == 0x0C && key2 == 0x67) {\n decoded.mcu_temperature = parseBytesToInt(input, i, 2) * 0.1;\n i += 2;\n }\n else if (key1 == 0x0D && key2 == 0x73) {\n decoded.RFU_2 = parseBytesToInt(input, i, 1) * 0.1;\n i += 1;\n }\n }\n }\n else if (fPort == 100) {\n for(var i = 0; i < input.length -1; ) {\n var key = input[i++] & 0xff;\n \n if(key == 0x10) {\n var val = (((input[i] << 8) | input[i + 1]) >> 15) & 1;\n switch (val){\n\t\t\t\t\tcase 0:\n\t\t\t\t\t\toutput.attributes.loramac_join_mode = \"ABP\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 1:\n\t\t\t\t\t\toutput.attributes.loramac_join_mode = \"OTAA\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\toutput.attributes.loramac_join_mode = \"Invalid\";\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\ti += 1;\n }\n else if (key == 0x11) {\n var val = (((input[i] << 8) | input[i + 1]) >> 12) & 0xF;\n switch (val) {\n\t\t\t\t\tcase 0:\n\t\t\t\t\t\toutput.attributes.deviceClassEnabled = \"Class A\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 12:\n\t\t\t\t\t\toutput.attributes.deviceClassEnabled = \"Class C\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\toutput.attributes.deviceClassEnabled = \"Invalid\";\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tvar val = (((input[i] << 8) | input[i + 1]) >> 3) & 1;\n\t\t\t\toutput.attributes.adr = getEnableStatus(val);\n\t\t\t\t\n\t\t\t\tvar val = (((input[i] << 8) | input[i + 1]) >> 2) & 1;\n\t\t\t\toutput.attributes.duty_cycle = getEnableStatus(val);\n\t\t\t\t\n\t\t\t\tvar val = (((input[i] << 8) | input[i + 1]) >> 1) & 1;\n\t\t\t\t\n\t\t\t\tswitch (val) {\n\t\t\t\t\tcase 0:\n\t\t\t\t\t\toutput.attributes.sync_word = \"Private\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 1:\n\t\t\t\t\t\toutput.attributes.sync_word = \"Public\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\toutput.attributes.sync_word = \"Invalid\";\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tvar val = ((input[i] << 8) | input[i + 1]) & 1;\n\t\t\t\t\n\t\t\t\tswitch (val){\n\t\t\t\t\tcase 0:\n\t\t\t\t\t\toutput.attributes.confirm_mode = \"Unconfirmed\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 1:\n\t\t\t\t\t\toutput.attributes.confirm_mode = \"Confirmed\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t output.attributes.confirm_mode = \"Invalid\";\n\t\t\t\t}\n\t\t\t\ti += 2;\n }\n else if (key == 0x12) {\n output.attributes.dr_number = (((input[i] << 8) | input[i + 1]) >> 8) & 0xF;\n output.attributes.tx_power_number = ((input[i] << 8) | input[i + 1]) & 0xF;\n \n i +=2;\n }\n else if (key == 0x13) {\n output.attributes.frequency = (((input[i] << 32) | (input[i + 1] << 24) | (input[i + 2] << 16) | (input[i + 3] << 8) | input[i + 4]) >> 8) & 0xFFFFFFFF;\n output.attributes.dr_number_rx2 = input[i + 4] & 0xFF;\n \n i += 5;\n }\n else if (key == 0x20) {\n output.attributes.seconds_per_core_tick = parseBytesToInt(input, i, 4);\n i += 4;\n }\n else if(key == 0x21) {\n output.attributes.tick_per_battery = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x22) {\n output.attributes.tick_per_ambient_temperature = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x23) {\n output.attributes.tick_per_relative_humidity = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x24) {\n output.attributes.tick_per_light = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x25) {\n output.attributes.tick_per_input1 = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x26) {\n output.attributes.tick_per_input2 = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x27) {\n output.attributes.tick_per_input3 = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x28) {\n output.attributes.tick_per_input4 = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x29) {\n output.attributes.tick_per_watermark1 = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x2A) {\n output.attributes.tick_per_watermark2 = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x2C) {\n output.attributes.tick_per_accelerometer = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x2D) {\n output.attributes.tick_per_orientation_alarm = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x2E) {\n output.attributes.tick_per_mcu_temperature = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x2F) {\n output.attributes.RFU_1 = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x30) {\n output.attributes.temperature_relative_humidity_idle = parseBytesToInt(input, i, 4);\n i += 4;\n }\n else if(key == 0x31) {\n output.attributes.temperature_relative_humidity_active = parseBytesToInt(input, i, 4);\n i += 4;\n }\n else if(key == 0x32) {\n output.attributes.high_ambient_temp_raw = (((input[i] << 8) | input[i + 1]) >> 8) & 0xFF;\n output.attributes.low_ambient_temp_raw = ((input[i] << 8) | input[i + 1]) & 0xFF;\n \n i += 2;\n }\n else if(key == 0x33) {\n var val = input[i] & 1;\n output.attributes.ambient_temperature_threshold_enabled = getEnableStatus(val);\n\t\t\t\t\n\t\t\t\ti += 1;\n }\n else if (key == 0x34) {\n output.attributes.high_rh = input[i];\n\t\t\t\toutput.attributes.low_rh = input[i + 1];\n\t\t\t\t\n\t\t\t\ti += 2;\n }\n else if (key == 0x35) {\n var val = input[i] & 1;\n output.attributes.relative_humidity_threshold_enabled = getEnableStatus(val);\n\t\t\t\t\n\t\t\t\ti += 1;\n }\n else if (key == 0x36) {\n output.attributes.input_sample_period_idle = parseBytesToInt(input, i, 4);\n i += 4;\n }\n else if (key == 0x37) {\n output.attributes.input_sample_period_active = parseBytesToInt(input, i, 4);\n i += 4;\n }\n else if (key == 0x38) {\n output.attributes.low_input1 = parseBytesToInt(input, i, 2);\n output.attributes.high_input1 = parseBytesToInt(input, i + 2, 2);\n \n i += 4;\n }\n else if (key == 0x39) {\n output.attributes.low_input2 = parseBytesToInt(input, i, 2);\n output.attributes.high_input2 = parseBytesToInt(input, i + 2, 2);\n \n i += 4;\n }\n else if (key == 0x3A) {\n output.attributes.low_input3 = parseBytesToInt(input, i, 2);\n output.attributes.high_input3 = parseBytesToInt(input, i + 2, 2);\n \n i += 4;\n }\n else if (key == 0x3B) {\n output.attributes.low_input4 = parseBytesToInt(input, i, 2);\n output.attributes.high_input4 = parseBytesToInt(input, i + 2, 2);\n \n i += 4;\n }\n else if (key == 0x3C) {\n output.attributes.low_watermark1 = parseBytesToInt(input, i, 2);\n output.attributes.high_watermark1 = parseBytesToInt(input, i + 2, 2);\n \n i += 4;\n }\n else if (key == 0x3D) {\n output.attributes.low_watermark2 = parseBytesToInt(input, i, 2);\n output.attributes.high_watermark2 = parseBytesToInt(input, i + 2, 2);\n \n i += 4;\n }\n else if (key == 0x3F) {\n var input_status = input[i] & 0x3F;\n \n var bit0 = (input_status >> 0) & 1;\n output.attributes.input_enable_input1 = getEnableStatus(bit0);\n \n var bit1 = (input_status >> 1) & 1;\n output.attributes.input_enable_input2 = getEnableStatus(bit1);\n \n var bit2 = (input_status >> 2) & 1;\n output.attributes.input_enable_input3 = getEnableStatus(bit2);\n \n var bit3 = (input_status >> 3) & 1;\n output.attributes.input_enable_input4 = getEnableStatus(bit3);\n \n var bit4 = (input_status >> 4) & 1;\n output.attributes.input_enable_watermark1_enable = getEnableStatus(bit4);\n \n var bit5 = (input_status >> 5) & 1;\n output.attributes.input_enable_watermark2_enable = getEnableStatus(bit5);\n \n i += 1;\n }\n else if (key == 0x40) {\n output.attributes.mcu_temperature_sample_period_idle = parseBytesToInt(input, i, 4);\n i += 4;\n }\n else if (key == 0x41) {\n output.attributes.mcu_temperature_sample_period_active = parseBytesToInt(input, i, 4);\n i += 4;\n }\n else if (key == 0x42) {\n output.attributes.high_mcu_temp = input[i + 1];\n output.attributes.low_mcu_temp = input[i];\n i += 4;\n }\n else if (key == 0x43) {\n var val = input[i] & 1;\n output.attributes.mcu_temperature_enable = getEnableStatus(val);\n\n\t\t\t\ti += 2;\n }\n else if (key == 0x44) {\n output.attributes.low_input3_onewire = parseBytesToInt(input, i, 2);\n output.attributes.high_input3_onewire = parseBytesToInt(input, i + 2, 2);\n i += 2;\n }\n else if (key == 0x45) {\n output.attributes.low_input4_onewire = parseBytesToInt(input, i, 2);\n output.attributes.high_input4_onewire = parseBytesToInt(input, i + 2, 2);\n i += 2;\n }\n else if (key == 0x48 ) {\n var val = input[i] & 1;\n output.attributes.ALS_interrupt_enabled = getEnableStatus(val);\n \n i += 1;\n }\n else if (key == 0x49) {\n output.attributes.ALS_upper_threshold = parseBytesToInt(input, i, 2);\n i +=2;\n }\n else if (key == 0x4A) {\n output.attributes.ALS_lower_threshold = parseBytesToInt(input, i, 2);\n i +=2;\n }\n else if (key == 0x4B) {\n output.attributes.light_sample_period_idle = parseBytesToInt(input, i, 4);\n i +=4;\n }\n else if (key == 0x4C) {\n output.attributes.light_sample_period_active = parseBytesToInt(input, i, 4);\n i +=4;\n }\n else if (key == 0x4D) {\n var status = input[i] & 0x03;\n \n var bit1 = status & 1;\n output.attributes.light_alarm_reported = getReportStatus(bit1);\n \n var bit2 = (status >> 1) & 1;\n output.attributes.light_intensity_reported = getReportStatus(bit2);\n \n i += 1;\n }\n else if (key == 0x50) {\n output.attributes.orientation_alarm_threshold = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x51) {\n var status = input[i];\n\n var bit5 = (status >> 5) & 1;\n output.attributes.orientation_vector_report = getReportStatus(bit5);\n \n var bit0 = status & 1; \n output.attributes.orientation_alarm_report = getReportStatus(bit0);\n \n i += 1;\n }\n else if (key == 0x52) {\n var status = input[i]; \n \n var bit7 = (status >> 7) & 1; \n var bit0 = status & 1; \n \n switch (bit7) {\n case 0:\n output.attributes.accelerometer_power_on = \"Off\";\n break;\n case 1:\n output.attributes.accelerometer_power_on = \"On\";\n break;\n default:\n output.attributes.accelerometer_power_on = \"Invalid\";\n }\n \n output.attributes.orientation_alarm_mode = getEnableStatus(bit0);\n \n i += 1;\n }\n else if (key == 0x61) {\n var status = input[i]; \n \n var bit1 = (status >> 1) & 1;\n output.attributes.report_capacity_enabled = getEnableStatus(bit1);\n \n var bit2 = (status >> 2) & 1;\n output.attributes.report_lifetime_enabled = getEnableStatus(bit2);\n \n i += 1;\n }\n else if (key == 0x62) {\n output.attributes.avg_current_window = parseBytesToInt(input, i, 1);\n i += 1;\n }\n else if (key == 0x71) {\n output.attributes.app_major_version = input[i + 6];\n\t\t\t\toutput.attributes.app_minor_version = input[i + 5];\n\t\t\t\toutput.attributes.app_revision = input[i + 4];\n\t\t\t\toutput.attributes.loramac_major_version = input[i + 3];\n\t\t\t\toutput.attributes.loramac_minor_version = input[i + 2];\n\t\t\t\toutput.attributes.loramac_revision = input[i + 1];\n\t\t\t\tvar val = input[i];\n\t\t\t\tswitch (val){\n\t\t\t\t\tcase 0:\n\t\t\t\t\t\toutput.attributes.region = \"EU868\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 1:\n\t\t\t\t\t\toutput.attributes.region = \"US915\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 2:\n\t\t\t\t\t\toutput.attributes.region = \"AS923\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 3:\n\t\t\t\t\t\toutput.attributes.region = \"AU915\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 4:\n\t\t\t\t\t\toutput.attributes.region = \"IN865\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 6:\n\t\t\t\t\t\toutput.attributes.region = \"KR920\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 7:\n\t\t\t\t\t\toutput.attributes.region = \"RU864\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\toutput.attributes.region = \"Invalid\";\n\t\t\t\t}\n\t\t\t\ti += 7;\n }\n }\n }\n else if (fPort == 101) {\n var size = input.length;\n var responses = [];\n \n var index = 0;\n while (index < size) {\n var downlinkFcnt = input[index++] & 0xFF; \n var numInvalidWrites = input[index++] & 0xFF; \n \n if (numInvalidWrites > 0) {\n var invalidRegisters = [];\n for (var i = 0; i < numInvalidWrites; i++) {\n invalidRegisters.add(String.format(\"0x%02X\", input[index + i]));\n }\n index += numInvalidWrites;\n \n responses.add(String.format(\n \"%d Invalid write command(s) from DL:%d for register(s): %s\",\n numInvalidWrites, downlinkFcnt, String.join(\", \", invalidRegisters)\n ));\n } else {\n responses.add(String.format(\"All write commands from DL:%d were successful\", downlinkFcnt));\n }\n }\n \n decoded.response = responses;\n }\n \n output.telemetry = [{\n ts: timestamp,\n values: decoded\n }];\n \n // --- Decoding code --- //\n return output;\n}\n\n\n// --- attributes and telemetry objects ---\nvar telemetry = [];\nvar attributes = {};\n// --- attributes and telemetry objects ---\n\n// --- Timestamp parsing\nvar dateString = data.uplink_message.received_at;\n// If data is simulated or device doesn't send his own date string - we will use date from upcoming message, set by network server\nif ((data.simulated != null && data.simulated) || dateString == null) {\n dateString = data.received_at;\n}\ntimestamp = parseDateToTimestamp(dateString);\n// --- Timestamp parsing\n\n// Message parsing\n// To avoid paths in the decoded objects we passing false value to function as \"pathInKey\" argument.\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.\n\n// Passing incoming bytes to decodeFrmPayload function, to get custom decoding\nvar customDecoding = {};\nif (data.uplink_message.get(\"frm_payload\") != null) {\n customDecoding = decodeFrmPayload(base64ToBytes(data.uplink_message.frm_payload));\n}\n\n// Collecting data to result\nif (customDecoding.?telemetry.size() > 0) {\n if (customDecoding.telemetry instanceof java.util.ArrayList) {\n foreach(telemetryObj: customDecoding.telemetry) {\n if (telemetryObj.ts != null && telemetryObj.values != null) {\n telemetry.add(telemetryObj);\n }\n }\n } else {\n telemetry.putAll(customDecoding.telemetry);\n }\n}\n\nif (customDecoding.?attributes.size() > 0) {\n attributes.putAll(customDecoding.attributes);\n}\n\n// You can add some keys manually to attributes or telemetry\nvar applicationId = data.end_device_ids.?application_ids.?application_id;\nvar devAddr = data.end_device_ids.?dev_addr;\nvar spreadingFactor = data.uplink_message.?settings.?data_rate.?lora.?spreading_factor;\nvar codeRate = data.uplink_message.?settings.?data_rate.?lora.?coding_rate;\nvar tenantId = data.uplink_message.?network_ids.?tenant_id;\nattributes.eui = data.end_device_ids.dev_eui;\nattributes.fPort = data.uplink_message.f_port;\nattributes.applicationId = applicationId;\nattributes.devAddr = devAddr;\nattributes.spreadingFactor = spreadingFactor;\nattributes.codeRate = codeRate;\nattributes.tenantId = tenantId;\nattributes.device_id = data.end_device_ids.?device_id;\nattributes.join_eui = data.end_device_ids.?join_eui;\nattributes.net_id = data.uplink_message.?network_ids.?net_id;\nattributes.cluster_id = data.uplink_message.?network_ids.?cluster_id;\nattributes.cluster_adress = data.uplink_message.?network_ids.?cluster_address;\nattributes.bandwidth = data.uplink_message.?settings.?data_rate.?lora.?bandwidth;\nattributes.frequency = data.uplink_message.?settings.?frequency;\n\n\nvar gatewayInfo = getGatewayInfo();\nvar addDataToTelemetry = {};\naddDataToTelemetry.snr = gatewayInfo.snr;\naddDataToTelemetry.rssi = gatewayInfo.rssi;\naddDataToTelemetry.channel = gatewayInfo.channel_index;\naddDataToTelemetry.consumed_airtime = data.uplink_message.?consumed_airtime;\naddDataToTelemetry.fCnt = data.uplink_message.?f_cnt;\n\nvar isIncludeGatewayInfo = metadata[\"includeGatewayInfo\"];\nif(isIncludeGatewayInfo == true) {\n telemetry = processTelemetryData(telemetry, addDataToTelemetry);\n}\n\nvar result = {\n deviceName: deviceName,\n deviceType: deviceType,\n// assetName: assetName,\n// assetType: assetType,\n attributes: attributes,\n telemetry: telemetry\n};\n\naddAdditionalInfoForDeviceMsg(result, customerName, groupName);\n\nreturn result;\n\n\nfunction addAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName) {\n if (customerName != null) {\n deviceInfo.customerName = customerName;\n }\n if (groupName != null) {\n deviceInfo.groupName = groupName;\n }\n}\n\nfunction parseDateToTimestamp(dateString) {\n var date = new Date(dateString);\n var timestamp = date.getTime();\n \n // If we cannot parse timestamp - we will use the current timestamp\n if (timestamp == -1) {\n timestamp = Date.now();\n }\n \n return timestamp;\n}\n\nfunction getGatewayInfo() {\n var gatewayList = data.uplink_message.?rx_metadata;\n var maxRssi = Integer.MIN_VALUE;\n var gatewayInfo = {};\n \n foreach (gateway : gatewayList) {\n if(gateway.rssi > maxRssi) {\n maxRssi = gateway.rssi;\n gatewayInfo = gateway;\n }\n }\n \n return gatewayInfo;\n}\n\nfunction processTelemetryData(telemetry, addDataToTelemetry) {\n if (telemetry.size >= 1) {\n telemetry = addDataToTelemetries(telemetry, addDataToTelemetry);\n }\n else {\n telemetry.add(addDataToTelemetry);\n }\n \n return telemetry;\n}\n\nfunction addDataToTelemetries(telemetries, addDataToTelemetry) {\n foreach(telemetry : telemetries) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[\"values\"].keys.contains(element.key)) {\n telemetry[\"values\"][element.key] = element.value;\n }\n } \n }\n \n return telemetries;\n}\n\nfunction getWatermarkData(watermarkFrequency) {\n var decodedWatermark = {};\n \n var watermarkTension = 0;\n if (watermarkFrequency > 6430){\n\t\twatermarkTension = 0;\n\t} else if (watermarkFrequency >= 4330 && watermarkFrequency <= 6430){\n\t watermarkTension = 9.000 - (watermarkFrequency - 4330.000) * 0.004286;\n\t} else if (watermarkFrequency >= 2820 && watermarkFrequency < 4330){\n\t\twatermarkTension = 15.000 - (watermarkFrequency - 2820.000) * 0.003974;\n\t} else if (watermarkFrequency >= 1110 && watermarkFrequency < 2820){\n\t\twatermarkTension = 35.000 - (watermarkFrequency - 1110.000) * 0.01170;\n\t} else if (watermarkFrequency >= 770 && watermarkFrequency < 1110){\n\t\twatermarkTension = 55.000 - (watermarkFrequency - 770.000) * 0.05884;\n\t} else if (watermarkFrequency >= 600 && watermarkFrequency < 770){\n\t\twatermarkTension = 75.000 - (watermarkFrequency - 600.000) * 0.1176;\n\t} else if (watermarkFrequency >= 485 && watermarkFrequency < 600){\n\t\twatermarkTension = 100.000 - (watermarkFrequency - 485.000) * 0.2174;\n } else if (watermarkFrequency >= 293 && watermarkFrequency < 485){\n\t\twatermarkTension = 200.000 - (watermarkFrequency - 293.000) * 0.5208;\n\t} else {\n\t watermarkTension = 200;\n\t}\t\t\t\t\t\n\tdecodedWatermark.watermarkTension = roundUsingMathRound(watermarkTension, 0);\n\tdecodedWatermark.watermarkFrequency = watermarkFrequency;\n\t\t\t\t\n return decodedWatermark;\n}\n\nfunction roundUsingMathRound(value, places) {\n if (places >= 0) {\n var factor = Math.pow(10, places);\n return Math.round(value * factor) / factor; \n }\n \n return value;\n}\n\nfunction getAlarmStatus(bit) {\n var alarmResult = \"Invalid\";\n \n if (bit === 0) {\n alarmResult = \"No Alarm\";\n } else if (bit === 1 || bit === 255) {\n alarmResult = \"Alarm\";\n } else {\n alarmResult = \"Invalid\";\n }\n \n return alarmResult;\n}\n\nfunction getEnableStatus(bit) {\n var enableResult = \"Invalid\";\n \n switch (bit) {\n\t\tcase 0:\n\t\t enableResult = \"Disable\";\n\t\t\tbreak;\n\t\tcase 1:\n\t\t\tenableResult = \"Enable\";\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tenableResult = \"Invalid\";\n\t}\n \n return enableResult;\n}\n\nfunction getReportStatus(bit) {\n var reportResult = \"Invalid\";\n \n switch (bit5) {\n case 0:\n reportResult = \"Ignore\";\n break;\n case 1:\n reportResult = \"Report\";\n break;\n default:\n reportResult = \"Invalid\";\n }\n \n return reportResult;\n}", + "encoder": null, + "tbelEncoder": null, + "updateOnlyKeys": [ + "fPort", + "bandwidth", + "frequency", + "net_id", + "cluster_id", + "cluster_address", + "device_id", + "join_eui", + "battery", + "eui", + "channel", + "applicationId", + "devAddr", + "spreadingFactor", + "codeRate", + "tenantId" + ] + }, + "additionalInfo": { + "description": "" + }, + "edgeTemplate": false +} \ No newline at end of file diff --git a/VENDORS/Tektelic/Clover/ThingsStackCommunity/uplink/metadata.json b/VENDORS/Tektelic/Clover/ThingsStackCommunity/uplink/metadata.json new file mode 100644 index 00000000..0d75c374 --- /dev/null +++ b/VENDORS/Tektelic/Clover/ThingsStackCommunity/uplink/metadata.json @@ -0,0 +1,4 @@ +{ + "integrationName": "The Things Stack Community integration", + "includeGatewayInfo": "false" +} \ No newline at end of file diff --git a/VENDORS/Tektelic/Clover/ThingsStackCommunity/uplink/payload.json b/VENDORS/Tektelic/Clover/ThingsStackCommunity/uplink/payload.json new file mode 100644 index 00000000..be420fea --- /dev/null +++ b/VENDORS/Tektelic/Clover/ThingsStackCommunity/uplink/payload.json @@ -0,0 +1,54 @@ +{ + "end_device_ids": { + "device_id": "eui-1000000000000001", + "application_ids": { + "application_id": "application-tts-name" + }, + "dev_eui": "1000000000000001", + "join_eui": "2000000000000001", + "dev_addr": "20000001" + }, + "correlation_ids": ["as:up:01H0S7ZJQ9MQPMVY49FT3SE07M", "gs:conn:01H03BQZ9342X3Y86DJ2P704E5", "gs:up:host:01H03BQZ99EGAM52KK1300GFKN", "gs:uplink:01H0S7ZJGS6D9TJSKJN8XNTMAV", "ns:uplink:01H0S7ZJGS9KKD4HTTPKFEMWCV", "rpc:/ttn.lorawan.v3.GsNs/HandleUplink:01H0S7ZJGSF3M38ZRZVTM38DEC", "rpc:/ttn.lorawan.v3.NsAs/HandleUplink:01H0S7ZJQ8R2EH5AA269AKM8DX"], + "received_at": "2023-05-19T05:33:35.848446463Z", + "uplink_message": { + "session_key_id": "AYfqmb0pc/1uRZv9xUydgQ==", + "f_port": 10, + "f_cnt": 10335, + "frm_payload": "ANNaAL0KCg==", + "rx_metadata": [{ + "gateway_ids": { + "gateway_id": "eui-6a7e111a10000000", + "eui": "6A7E111A10000000" + }, + "time": "2023-05-19T05:33:35.608982Z", + "timestamp": 3893546133, + "rssi": -35, + "channel_rssi": -35, + "snr": 13.2, + "frequency_offset": "69", + "uplink_token": "CiIKIAoUZXVpLTZhN2UxMTFhMTAwMDAwMDASCCThJP/+9k6eEJWZy8AOGgwIr5ScowYQvNbUsQIgiMy8y6jwpwE=", + "channel_index": 3, + "received_at": "2023-05-19T05:33:35.607383681Z" + }], + "settings": { + "data_rate": { + "lora": { + "bandwidth": 125000, + "spreading_factor": 7, + "coding_rate": "4/5" + } + }, + "frequency": "867100000", + "timestamp": 3893546133, + "time": "2023-05-19T05:33:35.608982Z" + }, + "received_at": "2023-05-19T05:33:35.641841782Z", + "consumed_airtime": "0.056576s", + "network_ids": { + "net_id": "000013", + "tenant_id": "ttn", + "cluster_id": "eu1", + "cluster_address": "eu1.cloud.thethings.network" + } + } +} \ No newline at end of file diff --git a/VENDORS/Tektelic/Clover/ThingsStackCommunity/uplink/payload_1.json b/VENDORS/Tektelic/Clover/ThingsStackCommunity/uplink/payload_1.json new file mode 100644 index 00000000..d7467513 --- /dev/null +++ b/VENDORS/Tektelic/Clover/ThingsStackCommunity/uplink/payload_1.json @@ -0,0 +1,54 @@ +{ + "end_device_ids": { + "device_id": "eui-1000000000000001", + "application_ids": { + "application_id": "application-tts-name" + }, + "dev_eui": "1000000000000001", + "join_eui": "2000000000000001", + "dev_addr": "20000001" + }, + "correlation_ids": ["as:up:01H0S7ZJQ9MQPMVY49FT3SE07M", "gs:conn:01H03BQZ9342X3Y86DJ2P704E5", "gs:up:host:01H03BQZ99EGAM52KK1300GFKN", "gs:uplink:01H0S7ZJGS6D9TJSKJN8XNTMAV", "ns:uplink:01H0S7ZJGS9KKD4HTTPKFEMWCV", "rpc:/ttn.lorawan.v3.GsNs/HandleUplink:01H0S7ZJGSF3M38ZRZVTM38DEC", "rpc:/ttn.lorawan.v3.NsAs/HandleUplink:01H0S7ZJQ8R2EH5AA269AKM8DX"], + "received_at": "2023-05-19T05:33:35.848446463Z", + "uplink_message": { + "session_key_id": "AYfqmb0pc/1uRZv9xUydgQ==", + "f_port": 10, + "f_cnt": 10335, + "frm_payload": "AQQFeQICAtU=", + "rx_metadata": [{ + "gateway_ids": { + "gateway_id": "eui-6a7e111a10000000", + "eui": "6A7E111A10000000" + }, + "time": "2023-05-19T05:33:35.608982Z", + "timestamp": 3893546133, + "rssi": -35, + "channel_rssi": -35, + "snr": 13.2, + "frequency_offset": "69", + "uplink_token": "CiIKIAoUZXVpLTZhN2UxMTFhMTAwMDAwMDASCCThJP/+9k6eEJWZy8AOGgwIr5ScowYQvNbUsQIgiMy8y6jwpwE=", + "channel_index": 3, + "received_at": "2023-05-19T05:33:35.607383681Z" + }], + "settings": { + "data_rate": { + "lora": { + "bandwidth": 125000, + "spreading_factor": 7, + "coding_rate": "4/5" + } + }, + "frequency": "867100000", + "timestamp": 3893546133, + "time": "2023-05-19T05:33:35.608982Z" + }, + "received_at": "2023-05-19T05:33:35.641841782Z", + "consumed_airtime": "0.056576s", + "network_ids": { + "net_id": "000013", + "tenant_id": "ttn", + "cluster_id": "eu1", + "cluster_address": "eu1.cloud.thethings.network" + } + } +} \ No newline at end of file diff --git a/VENDORS/Tektelic/Clover/ThingsStackCommunity/uplink/result.json b/VENDORS/Tektelic/Clover/ThingsStackCommunity/uplink/result.json new file mode 100644 index 00000000..b909f054 --- /dev/null +++ b/VENDORS/Tektelic/Clover/ThingsStackCommunity/uplink/result.json @@ -0,0 +1,27 @@ +{ + "deviceName": "eui-1000000000000001", + "deviceType": "Clover", + "attributes": { + "eui": "1000000000000001", + "fPort": 10, + "applicationId": "application-tts-name", + "devAddr": "20000001", + "spreadingFactor": 7, + "codeRate": "4/5", + "tenantId": "ttn", + "device_id": "eui-1000000000000001", + "join_eui": "2000000000000001", + "net_id": "000013", + "cluster_id": "eu1", + "cluster_adress": "eu1.cloud.thethings.network", + "bandwidth": 125000, + "frequency": "867100000" + }, + "telemetry": [{ + "ts": 1684474415641, + "values": { + "rem_batt_capacity": 90, + "rem_batt_days": 2570 + } + }] +} \ No newline at end of file diff --git a/VENDORS/Tektelic/Clover/ThingsStackCommunity/uplink/result_1.json b/VENDORS/Tektelic/Clover/ThingsStackCommunity/uplink/result_1.json new file mode 100644 index 00000000..2c720da6 --- /dev/null +++ b/VENDORS/Tektelic/Clover/ThingsStackCommunity/uplink/result_1.json @@ -0,0 +1,29 @@ +{ + "deviceName": "eui-1000000000000001", + "deviceType": "Clover", + "attributes": { + "eui": "1000000000000001", + "fPort": 10, + "applicationId": "application-tts-name", + "devAddr": "20000001", + "spreadingFactor": 7, + "codeRate": "4/5", + "tenantId": "ttn", + "device_id": "eui-1000000000000001", + "join_eui": "2000000000000001", + "net_id": "000013", + "cluster_id": "eu1", + "cluster_adress": "eu1.cloud.thethings.network", + "bandwidth": 125000, + "frequency": "867100000" + }, + "telemetry": [{ + "ts": 1684474415641, + "values": { + "input1_frequency_to_moisture": "Dry", + "input1_frequency": 1401, + "input2_voltage_to_temp": 22.6, + "input2_voltage": 0.725 + } + }] +} \ No newline at end of file diff --git a/VENDORS/Tektelic/Clover/ThingsStackIndustries/uplink/converter.json b/VENDORS/Tektelic/Clover/ThingsStackIndustries/uplink/converter.json new file mode 100644 index 00000000..cb3c3c01 --- /dev/null +++ b/VENDORS/Tektelic/Clover/ThingsStackIndustries/uplink/converter.json @@ -0,0 +1,40 @@ +{ + "name": "The Things Stack Industries Uplink Decoder for Clover", + "type": "UPLINK", + "debugMode": false, + "debugSettings": { + "failuresEnabled": true, + "allEnabled": false, + "allEnabledUntil": 1733331880270 + }, + "configuration": { + "scriptLang": "TBEL", + "decoder": null, + "tbelDecoder": "var data = decodeToJson(payload);\n\nvar deviceName = data.end_device_ids.device_id;\nvar deviceType = \"Clover\";\nvar groupName = null; // If groupName is not null - created device will be added to the entity group with such name.\nvar customerName = null; // If customerName is not null - created devices will be assigned to customer with such name. \n\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// If you want to parse incoming data somehow, you can add your code to this function.\n// input: bytes\n// expected output:\n// {\n// \"attributes\": {\"attributeKey\": \"attributeValue\"},\n// \"telemetry\": [{\"ts\": 1...1, \"values\": {\"telemetryKey\":\"telemetryValue\"}, {\"ts\": 1...2, \"values\": {\"telemetryKey\":\"telemetryValue\"}}]\n// }\n\nfunction decodeFrmPayload(input) {\n var output = { attributes: {}, telemetry: []};\n \n // --- Decoding code --- //\n var decoded = {};\n var fPort = data.uplink_message.f_port;\n if(fPort == 10) {\n for(var i = 0; i < input.length - 2; ) {\n var key_1 = input[i++] & 0xff;\n var key_2 = input[i++] & 0xff;\n \n if(key_1 == 0x00 && key_2 == 0xBA) {\n var val = (input[i] >> 7) & 1; \n\n decoded.eos_alert = getAlarmStatus(val);\n var battery_bits = input[i] & 0x7F;\n decoded.battery_voltage = roundUsingMathRound(battery_bits * 0.01 + 2.5, 2);\n i += 1;\n }\n else if(key_1 == 0x00 && key_2 == 0xD3) {\n decoded.rem_batt_capacity = parseBytesToInt(input, i, 1);\n i += 1;\n }\n else if(key_1 == 0x00 && key_2 == 0xBD) {\n decoded.rem_batt_days = parseBytesToInt(input, i, 2);\n\t\t\t\ti += 2;\n }\n else if(key_1 == 0x01 && key_2 == 0x04) {\n var value = parseBytesToInt(input, i, 2);\n var frequencyMoisture = 0;\n\t\t\t\tif (value > 1399){\n\t\t\t\t\tfrequencyMoisture = \"Dry\";\n\t\t\t\t} else if (value > 1396 && value <= 1399){\n\t\t\t\t\tfrequencyMoisture = 0.1;\n\t\t\t\t} else if (value > 1391 && value <= 1396){\n\t\t\t\t\tfrequencyMoisture = 0.2;\n\t\t\t\t} else if (value > 1386 && value <= 1391){\n\t\t\t\t\tfrequencyMoisture = 0.3;\n\t\t\t\t} else if (value > 1381 && value <= 1386){\n\t\t\t\t\tfrequencyMoisture = 0.4;\n\t\t\t\t} else if (value > 1376 && value <= 1381){\n\t\t\t\t\tfrequencyMoisture = 0.5;\n\t\t\t\t} else if (value > 1371 && value <= 1376){\n\t\t\t\t\tfrequencyMoisture = 0.6;\n\t\t\t\t} else if (value > 1366 && value <= 1371){\n\t\t\t\t\tfrequencyMoisture = 0.7;\n\t\t\t\t} else if (value > 1361 && value <= 1366){\n\t\t\t\t\tfrequencyMoisture = 0.8;\n\t\t\t\t} else if (value > 1356 && value <= 1361){\n\t\t\t\t\tfrequencyMoisture = 0.9;\n\t\t\t\t} else if (value > 1351 && value <= 1356){\n\t\t\t\t\tfrequencyMoisture = 1.0;\n\t\t\t\t} else if (value > 1346 && value <= 1351){\n\t\t\t\t\tfrequencyMoisture = 1.1;\n\t\t\t\t} else if (value > 1341 && value <= 1346){\n\t\t\t\t\tfrequencyMoisture = 1.2;\n\t\t\t\t} else {\n\t\t\t\t\tfrequencyMoisture = \"Wet\";\n\t\t\t\t}\n\t\t\t\tdecoded.input1_frequency_to_moisture = frequencyMoisture;\n\t\t\t\tdecoded.input1_frequency = value;\n\t\t\t\ti += 2;\n }\n else if (key_1 == 0x02 && key_2 == 0x02) {\n var voltageValue = parseBytesToInt(input, i, 2) * 0.001;\n\t\t\t\tvar voltageTempOutput = -32.46 * Math.log(voltageValue * 1000) + 236.36;\n\t\t\t\tdecoded.input2_voltage_to_temp = roundUsingMathRound(voltageTempOutput, 1);\n\t\t\t\tdecoded.input2_voltage = voltageValue;\n\t\t\t\ti += 2;\n }\n else if (key1 == 0x03 && key2 == 0x02) {\n var input3Voltage = parseBytesToInt(input, i, 2) * 0.001;\n \n decoded.input3_voltage = input3Voltage;\n\t\t\t\tdecoded.input3_voltage_to_temp = roundUsingMathRound((-33.01 * Math.pow(input3Voltage, 5)) + (217.4 * Math.pow(input3Voltage, 4)) + (-538.6 * Math.pow(input3Voltage, 3)) + (628.1 * Math.pow(input3Voltage, 2)) + (-378.9 * input3Voltage) + 102.9, 1);\n \n i += 2;\n }\n else if (key1 == 0x03 && key2 == 0x67) {\n decoded.input3_temperature = parseBytesToInt(input, i, 2) * 0.1;\n\t\t\t\ti += 2;\n }\n else if (key1 == 0x04 && key2 == 0x02) {\n var input4Voltage = parseBytesToInt(input, i, 2) * 0.001;\n \n decoded.input4_voltage = input4Voltage;\n\t\t\t\tdecodedinput4_voltage_to_temp = roundUsingMathRound((-33.01 * Math.pow(input4Voltage, 5)) + (217.4 * Math.pow(input4Voltage, 4)) + (-538.6 * Math.pow(input4Voltage, 3)) + (628.1 * Math.pow(input4Voltage, 2)) + (-378.9 * input4Voltage) + 102.9, 1);\n \n i += 2;\n }\n else if (key1 == 0x04 && key2 == 0x67) {\n decoded.input4_temperature = parseBytesToInt(input, i, 2) * 0.1;\n\t\t\t\ti += 2;\n }\n else if (key1 == 0x05 && key2 == 0x04) {\n var watermark1Frequency = parseBytesToInt(input, i, 2);\n\t\t\t\t\n\t\t\t\tvar decodedWatermarkData1 = getWatermarkData(watermark1Frequency);\t\n\t\t\t\tdecoded.watermark1_tension = decodedWatermarkData1.watermarkTension;\n\t\t\t\tdecoded.watermark1_frequency = decodedWatermarkData1.watermarkFrequency;\n\t\t\t\t\n\t\t\t\ti += 2;\n }\n else if (key1 == 0x06 && key2 == 0x04) {\n var watermark2Frequency = parseBytesToInt(input, i, 2);\n\t\t\t\t\n\t\t\t\tvar decodedWatermarkData2 = getWatermarkData(watermark2Frequency);\t\n\t\t\t\tdecoded.watermark2_tension = decodedWatermarkData2.watermarkTension;\n\t\t\t\tdecoded.watermark2_frequency = decodedWatermarkData2.watermarkFrequency;\n\t\t\t\t\n\t\t\t\ti += 2;\n }\n else if (key1 == 0x09 && key2 == 0x65) {\n var lightIntensity = parseBytesToInt(input, i, 2);\n\t\t\t\t\n\t\t\t\tdecoded.light_intensity = lightIntensity; \n\t\t\t\ti += 2;\n }\n else if (key1 == 0x09 && key2 == 0x00) {\n var lightDetected = parseBytesToInt(input, i, 1);\n\t\t\t\tdecoded.light_detected = getAlarmStatus(lightDetected);\n\t\t\t\t\n\t\t\t\ti += 1;\n }\n else if (key1 == 0x0A && key2 == 0x71) {\n decoded.accelerationX = parseBytesToInt(input, i, 2);\n decoded.accelerationY = parseBytesToInt(input, i + 2, 2);\n decoded.accelerationZ = parseBytesToInt(input, i + 4, 2);\n }\n else if (key1 == 0x0A && key2 == 0x00) {\n var orientationAlarm = parseBytesToInt(input, i, 1);\n decoded.orientation_alarm = getAlarmStatus(orientationAlarm);\n\t\t\t\t\n\t\t\t\ti += 1;\n }\n else if (key1 == 0x0B && key2 == 0x67) {\n decoded.ambient_temperature = parseBytesToInt(input, i, 2) * 0.1;\n i += 2;\n }\n else if (key1 == 0x0B && key2 == 0x68) {\n decoded.relative_humidity = parseBytesToInt(input, i, 1) * 0.5;\n i += 1;\n }\n else if (key1 == 0x0C && key2 == 0x67) {\n decoded.mcu_temperature = parseBytesToInt(input, i, 2) * 0.1;\n i += 2;\n }\n else if (key1 == 0x0D && key2 == 0x73) {\n decoded.RFU_2 = parseBytesToInt(input, i, 1) * 0.1;\n i += 1;\n }\n }\n }\n else if (fPort == 100) {\n for(var i = 0; i < input.length -1; ) {\n var key = input[i++] & 0xff;\n \n if(key == 0x10) {\n var val = (((input[i] << 8) | input[i + 1]) >> 15) & 1;\n switch (val){\n\t\t\t\t\tcase 0:\n\t\t\t\t\t\toutput.attributes.loramac_join_mode = \"ABP\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 1:\n\t\t\t\t\t\toutput.attributes.loramac_join_mode = \"OTAA\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\toutput.attributes.loramac_join_mode = \"Invalid\";\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\ti += 1;\n }\n else if (key == 0x11) {\n var val = (((input[i] << 8) | input[i + 1]) >> 12) & 0xF;\n switch (val) {\n\t\t\t\t\tcase 0:\n\t\t\t\t\t\toutput.attributes.deviceClassEnabled = \"Class A\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 12:\n\t\t\t\t\t\toutput.attributes.deviceClassEnabled = \"Class C\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\toutput.attributes.deviceClassEnabled = \"Invalid\";\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tvar val = (((input[i] << 8) | input[i + 1]) >> 3) & 1;\n\t\t\t\toutput.attributes.adr = getEnableStatus(val);\n\t\t\t\t\n\t\t\t\tvar val = (((input[i] << 8) | input[i + 1]) >> 2) & 1;\n\t\t\t\toutput.attributes.duty_cycle = getEnableStatus(val);\n\t\t\t\t\n\t\t\t\tvar val = (((input[i] << 8) | input[i + 1]) >> 1) & 1;\n\t\t\t\t\n\t\t\t\tswitch (val) {\n\t\t\t\t\tcase 0:\n\t\t\t\t\t\toutput.attributes.sync_word = \"Private\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 1:\n\t\t\t\t\t\toutput.attributes.sync_word = \"Public\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\toutput.attributes.sync_word = \"Invalid\";\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tvar val = ((input[i] << 8) | input[i + 1]) & 1;\n\t\t\t\t\n\t\t\t\tswitch (val){\n\t\t\t\t\tcase 0:\n\t\t\t\t\t\toutput.attributes.confirm_mode = \"Unconfirmed\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 1:\n\t\t\t\t\t\toutput.attributes.confirm_mode = \"Confirmed\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t output.attributes.confirm_mode = \"Invalid\";\n\t\t\t\t}\n\t\t\t\ti += 2;\n }\n else if (key == 0x12) {\n output.attributes.dr_number = (((input[i] << 8) | input[i + 1]) >> 8) & 0xF;\n output.attributes.tx_power_number = ((input[i] << 8) | input[i + 1]) & 0xF;\n \n i +=2;\n }\n else if (key == 0x13) {\n output.attributes.frequency = (((input[i] << 32) | (input[i + 1] << 24) | (input[i + 2] << 16) | (input[i + 3] << 8) | input[i + 4]) >> 8) & 0xFFFFFFFF;\n output.attributes.dr_number_rx2 = input[i + 4] & 0xFF;\n \n i += 5;\n }\n else if (key == 0x20) {\n output.attributes.seconds_per_core_tick = parseBytesToInt(input, i, 4);\n i += 4;\n }\n else if(key == 0x21) {\n output.attributes.tick_per_battery = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x22) {\n output.attributes.tick_per_ambient_temperature = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x23) {\n output.attributes.tick_per_relative_humidity = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x24) {\n output.attributes.tick_per_light = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x25) {\n output.attributes.tick_per_input1 = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x26) {\n output.attributes.tick_per_input2 = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x27) {\n output.attributes.tick_per_input3 = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x28) {\n output.attributes.tick_per_input4 = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x29) {\n output.attributes.tick_per_watermark1 = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x2A) {\n output.attributes.tick_per_watermark2 = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x2C) {\n output.attributes.tick_per_accelerometer = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x2D) {\n output.attributes.tick_per_orientation_alarm = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x2E) {\n output.attributes.tick_per_mcu_temperature = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x2F) {\n output.attributes.RFU_1 = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x30) {\n output.attributes.temperature_relative_humidity_idle = parseBytesToInt(input, i, 4);\n i += 4;\n }\n else if(key == 0x31) {\n output.attributes.temperature_relative_humidity_active = parseBytesToInt(input, i, 4);\n i += 4;\n }\n else if(key == 0x32) {\n output.attributes.high_ambient_temp_raw = (((input[i] << 8) | input[i + 1]) >> 8) & 0xFF;\n output.attributes.low_ambient_temp_raw = ((input[i] << 8) | input[i + 1]) & 0xFF;\n \n i += 2;\n }\n else if(key == 0x33) {\n var val = input[i] & 1;\n output.attributes.ambient_temperature_threshold_enabled = getEnableStatus(val);\n\t\t\t\t\n\t\t\t\ti += 1;\n }\n else if (key == 0x34) {\n output.attributes.high_rh = input[i];\n\t\t\t\toutput.attributes.low_rh = input[i + 1];\n\t\t\t\t\n\t\t\t\ti += 2;\n }\n else if (key == 0x35) {\n var val = input[i] & 1;\n output.attributes.relative_humidity_threshold_enabled = getEnableStatus(val);\n\t\t\t\t\n\t\t\t\ti += 1;\n }\n else if (key == 0x36) {\n output.attributes.input_sample_period_idle = parseBytesToInt(input, i, 4);\n i += 4;\n }\n else if (key == 0x37) {\n output.attributes.input_sample_period_active = parseBytesToInt(input, i, 4);\n i += 4;\n }\n else if (key == 0x38) {\n output.attributes.low_input1 = parseBytesToInt(input, i, 2);\n output.attributes.high_input1 = parseBytesToInt(input, i + 2, 2);\n \n i += 4;\n }\n else if (key == 0x39) {\n output.attributes.low_input2 = parseBytesToInt(input, i, 2);\n output.attributes.high_input2 = parseBytesToInt(input, i + 2, 2);\n \n i += 4;\n }\n else if (key == 0x3A) {\n output.attributes.low_input3 = parseBytesToInt(input, i, 2);\n output.attributes.high_input3 = parseBytesToInt(input, i + 2, 2);\n \n i += 4;\n }\n else if (key == 0x3B) {\n output.attributes.low_input4 = parseBytesToInt(input, i, 2);\n output.attributes.high_input4 = parseBytesToInt(input, i + 2, 2);\n \n i += 4;\n }\n else if (key == 0x3C) {\n output.attributes.low_watermark1 = parseBytesToInt(input, i, 2);\n output.attributes.high_watermark1 = parseBytesToInt(input, i + 2, 2);\n \n i += 4;\n }\n else if (key == 0x3D) {\n output.attributes.low_watermark2 = parseBytesToInt(input, i, 2);\n output.attributes.high_watermark2 = parseBytesToInt(input, i + 2, 2);\n \n i += 4;\n }\n else if (key == 0x3F) {\n var input_status = input[i] & 0x3F;\n \n var bit0 = (input_status >> 0) & 1;\n output.attributes.input_enable_input1 = getEnableStatus(bit0);\n \n var bit1 = (input_status >> 1) & 1;\n output.attributes.input_enable_input2 = getEnableStatus(bit1);\n \n var bit2 = (input_status >> 2) & 1;\n output.attributes.input_enable_input3 = getEnableStatus(bit2);\n \n var bit3 = (input_status >> 3) & 1;\n output.attributes.input_enable_input4 = getEnableStatus(bit3);\n \n var bit4 = (input_status >> 4) & 1;\n output.attributes.input_enable_watermark1_enable = getEnableStatus(bit4);\n \n var bit5 = (input_status >> 5) & 1;\n output.attributes.input_enable_watermark2_enable = getEnableStatus(bit5);\n \n i += 1;\n }\n else if (key == 0x40) {\n output.attributes.mcu_temperature_sample_period_idle = parseBytesToInt(input, i, 4);\n i += 4;\n }\n else if (key == 0x41) {\n output.attributes.mcu_temperature_sample_period_active = parseBytesToInt(input, i, 4);\n i += 4;\n }\n else if (key == 0x42) {\n output.attributes.high_mcu_temp = input[i + 1];\n output.attributes.low_mcu_temp = input[i];\n i += 4;\n }\n else if (key == 0x43) {\n var val = input[i] & 1;\n output.attributes.mcu_temperature_enable = getEnableStatus(val);\n\n\t\t\t\ti += 2;\n }\n else if (key == 0x44) {\n output.attributes.low_input3_onewire = parseBytesToInt(input, i, 2);\n output.attributes.high_input3_onewire = parseBytesToInt(input, i + 2, 2);\n i += 2;\n }\n else if (key == 0x45) {\n output.attributes.low_input4_onewire = parseBytesToInt(input, i, 2);\n output.attributes.high_input4_onewire = parseBytesToInt(input, i + 2, 2);\n i += 2;\n }\n else if (key == 0x48 ) {\n var val = input[i] & 1;\n output.attributes.ALS_interrupt_enabled = getEnableStatus(val);\n \n i += 1;\n }\n else if (key == 0x49) {\n output.attributes.ALS_upper_threshold = parseBytesToInt(input, i, 2);\n i +=2;\n }\n else if (key == 0x4A) {\n output.attributes.ALS_lower_threshold = parseBytesToInt(input, i, 2);\n i +=2;\n }\n else if (key == 0x4B) {\n output.attributes.light_sample_period_idle = parseBytesToInt(input, i, 4);\n i +=4;\n }\n else if (key == 0x4C) {\n output.attributes.light_sample_period_active = parseBytesToInt(input, i, 4);\n i +=4;\n }\n else if (key == 0x4D) {\n var status = input[i] & 0x03;\n \n var bit1 = status & 1;\n output.attributes.light_alarm_reported = getReportStatus(bit1);\n \n var bit2 = (status >> 1) & 1;\n output.attributes.light_intensity_reported = getReportStatus(bit2);\n \n i += 1;\n }\n else if (key == 0x50) {\n output.attributes.orientation_alarm_threshold = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x51) {\n var status = input[i];\n\n var bit5 = (status >> 5) & 1;\n output.attributes.orientation_vector_report = getReportStatus(bit5);\n \n var bit0 = status & 1; \n output.attributes.orientation_alarm_report = getReportStatus(bit0);\n \n i += 1;\n }\n else if (key == 0x52) {\n var status = input[i]; \n \n var bit7 = (status >> 7) & 1; \n var bit0 = status & 1; \n \n switch (bit7) {\n case 0:\n output.attributes.accelerometer_power_on = \"Off\";\n break;\n case 1:\n output.attributes.accelerometer_power_on = \"On\";\n break;\n default:\n output.attributes.accelerometer_power_on = \"Invalid\";\n }\n \n output.attributes.orientation_alarm_mode = getEnableStatus(bit0);\n \n i += 1;\n }\n else if (key == 0x61) {\n var status = input[i]; \n \n var bit1 = (status >> 1) & 1;\n output.attributes.report_capacity_enabled = getEnableStatus(bit1);\n \n var bit2 = (status >> 2) & 1;\n output.attributes.report_lifetime_enabled = getEnableStatus(bit2);\n \n i += 1;\n }\n else if (key == 0x62) {\n output.attributes.avg_current_window = parseBytesToInt(input, i, 1);\n i += 1;\n }\n else if (key == 0x71) {\n output.attributes.app_major_version = input[i + 6];\n\t\t\t\toutput.attributes.app_minor_version = input[i + 5];\n\t\t\t\toutput.attributes.app_revision = input[i + 4];\n\t\t\t\toutput.attributes.loramac_major_version = input[i + 3];\n\t\t\t\toutput.attributes.loramac_minor_version = input[i + 2];\n\t\t\t\toutput.attributes.loramac_revision = input[i + 1];\n\t\t\t\tvar val = input[i];\n\t\t\t\tswitch (val){\n\t\t\t\t\tcase 0:\n\t\t\t\t\t\toutput.attributes.region = \"EU868\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 1:\n\t\t\t\t\t\toutput.attributes.region = \"US915\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 2:\n\t\t\t\t\t\toutput.attributes.region = \"AS923\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 3:\n\t\t\t\t\t\toutput.attributes.region = \"AU915\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 4:\n\t\t\t\t\t\toutput.attributes.region = \"IN865\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 6:\n\t\t\t\t\t\toutput.attributes.region = \"KR920\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 7:\n\t\t\t\t\t\toutput.attributes.region = \"RU864\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\toutput.attributes.region = \"Invalid\";\n\t\t\t\t}\n\t\t\t\ti += 7;\n }\n }\n }\n else if (fPort == 101) {\n var size = input.length;\n var responses = [];\n \n var index = 0;\n while (index < size) {\n var downlinkFcnt = input[index++] & 0xFF; \n var numInvalidWrites = input[index++] & 0xFF; \n \n if (numInvalidWrites > 0) {\n var invalidRegisters = [];\n for (var i = 0; i < numInvalidWrites; i++) {\n invalidRegisters.add(String.format(\"0x%02X\", input[index + i]));\n }\n index += numInvalidWrites;\n \n responses.add(String.format(\n \"%d Invalid write command(s) from DL:%d for register(s): %s\",\n numInvalidWrites, downlinkFcnt, String.join(\", \", invalidRegisters)\n ));\n } else {\n responses.add(String.format(\"All write commands from DL:%d were successful\", downlinkFcnt));\n }\n }\n \n decoded.response = responses;\n }\n \n output.telemetry = [{\n ts: timestamp,\n values: decoded\n }];\n\n // --- Decoding code --- //\n return output;\n}\n\n// --- attributes and telemetry objects ---\nvar telemetry = [];\nvar attributes = {};\n// --- attributes and telemetry objects ---\n\n// --- Timestamp parsing\nvar dateString = data.uplink_message.received_at;\n\nif ((data.simulated != null && data.simulated) || dateString == null) {\n dateString = data.received_at;\n}\n\ntimestamp = parseDateToTimestamp(dateString);\n// --- Timestamp parsing\n\n// Message parsing\n// To avoid paths in the decoded objects we passing false value to function as \"pathInKey\" argument.\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.\n\n// Passing incoming bytes to decodeFrmPayload function, to get custom decoding\nvar customDecoding = {};\nif (data.uplink_message.get(\"frm_payload\") != null) {\n customDecoding = decodeFrmPayload(base64ToBytes(data.uplink_message.frm_payload));\n}\n\n// Collecting data to result\nif (customDecoding.?telemetry.size() > 0) {\n if (customDecoding.telemetry instanceof java.util.ArrayList) {\n foreach(telemetryObj: customDecoding.telemetry) {\n if (telemetryObj.ts != null && telemetryObj.values != null) {\n telemetry.add(telemetryObj);\n }\n }\n } else {\n telemetry.putAll(customDecoding.telemetry);\n }\n}\n\nif (customDecoding.?attributes.size() > 0) {\n attributes.putAll(customDecoding.attributes);\n}\n\n// You can add some keys manually to attributes or telemetry\nvar applicationId = data.end_device_ids.?application_ids.?application_id;\nvar devAddr = data.end_device_ids.?dev_addr;\nvar spreadingFactor = data.uplink_message.?settings.?data_rate.?lora.?spreading_factor;\nvar codeRate = data.uplink_message.?settings.?data_rate.?lora.?coding_rate;\nvar tenantId = data.uplink_message.?network_ids.?tenant_id;\nattributes.eui = data.end_device_ids.dev_eui;\nattributes.fPort = data.uplink_message.f_port;\nattributes.applicationId = applicationId;\nattributes.devAddr = devAddr;\nattributes.spreadingFactor = spreadingFactor;\nattributes.codeRate = codeRate;\nattributes.tenantId = tenantId;\nattributes.device_id = data.end_device_ids.?device_id;\nattributes.join_eui = data.end_device_ids.?join_eui;\nattributes.net_id = data.uplink_message.?network_ids.?net_id;\nattributes.cluster_id = data.uplink_message.?network_ids.?cluster_id;\nattributes.cluster_address = data.uplink_message.?network_ids.?cluster_address;\nattributes.bandwidth = data.uplink_message.?settings.?data_rate.?lora.?bandwidth;\nattributes.frequency = data.uplink_message.?settings.?frequency;\n\nvar isIncludeGatewayInfo = metadata[\"includeGatewayInfo\"];\nif(isIncludeGatewayInfo == true) {\n var gatewayInfo = getGatewayInfo();\n var addDataToTelemetry = {};\n addDataToTelemetry.snr = gatewayInfo.snr;\n addDataToTelemetry.rssi = gatewayInfo.rssi;\n addDataToTelemetry.channel = gatewayInfo.channel_index;\n addDataToTelemetry.consumed_airtime = data.uplink_message.?consumed_airtime;\n addDataToTelemetry.fCnt = data.uplink_message.?f_cnt;\n\n telemetry = processTelemetryData(telemetry, addDataToTelemetry);\n}\n\nvar result = {\n deviceName: deviceName,\n deviceType: deviceType,\n // assetName: assetName,\n // assetType: assetType,\n attributes: attributes,\n telemetry: telemetry\n};\n\naddAdditionalInfoForDeviceMsg(result, customerName, groupName);\n\nreturn result;\n\nfunction addAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName) {\n if (customerName != null) {\n deviceInfo.customerName = customerName;\n }\n if (groupName != null) {\n deviceInfo.groupName = groupName;\n }\n}\n\nfunction parseDateToTimestamp(dateString) {\n var date = new Date(dateString);\n var timestamp = date.getTime();\n \n // If we cannot parse timestamp - we will use the current timestamp\n if (timestamp == -1) {\n timestamp = Date.now();\n }\n \n return timestamp;\n}\n\nfunction getGatewayInfo() {\n var gatewayList = data.uplink_message.?rx_metadata;\n var maxRssi = Integer. MIN_VALUE;\n var gatewayInfo = {};\n \n foreach (gateway : gatewayList) {\n if(gateway.rssi > maxRssi) {\n maxRssi = gateway.rssi;\n gatewayInfo = gateway;\n }\n }\n \n return gatewayInfo;\n}\n\nfunction processTelemetryData(telemetry, addDataToTelemetry) {\n if (telemetry.size >= 1) {\n telemetry = addDataToTelemetries(telemetry, addDataToTelemetry);\n }\n else {\n telemetry.add(addDataToTelemetry);\n }\n \n return telemetry;\n}\n\nfunction addDataToTelemetries(telemetries, addDataToTelemetry) {\n foreach(telemetry : telemetries) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[\"values\"].keys.contains(element.key)) {\n telemetry[\"values\"][element.key] = element.value;\n }\n } \n }\n \n return telemetries;\n}\n\nfunction getWatermarkData(watermarkFrequency) {\n var decodedWatermark = {};\n \n var watermarkTension = 0;\n if (watermarkFrequency > 6430){\n\t\twatermarkTension = 0;\n\t} else if (watermarkFrequency >= 4330 && watermarkFrequency <= 6430){\n\t watermarkTension = 9.000 - (watermarkFrequency - 4330.000) * 0.004286;\n\t} else if (watermarkFrequency >= 2820 && watermarkFrequency < 4330){\n\t\twatermarkTension = 15.000 - (watermarkFrequency - 2820.000) * 0.003974;\n\t} else if (watermarkFrequency >= 1110 && watermarkFrequency < 2820){\n\t\twatermarkTension = 35.000 - (watermarkFrequency - 1110.000) * 0.01170;\n\t} else if (watermarkFrequency >= 770 && watermarkFrequency < 1110){\n\t\twatermarkTension = 55.000 - (watermarkFrequency - 770.000) * 0.05884;\n\t} else if (watermarkFrequency >= 600 && watermarkFrequency < 770){\n\t\twatermarkTension = 75.000 - (watermarkFrequency - 600.000) * 0.1176;\n\t} else if (watermarkFrequency >= 485 && watermarkFrequency < 600){\n\t\twatermarkTension = 100.000 - (watermarkFrequency - 485.000) * 0.2174;\n } else if (watermarkFrequency >= 293 && watermarkFrequency < 485){\n\t\twatermarkTension = 200.000 - (watermarkFrequency - 293.000) * 0.5208;\n\t} else {\n\t watermarkTension = 200;\n\t}\t\t\t\t\t\n\tdecodedWatermark.watermarkTension = roundUsingMathRound(watermarkTension, 0);\n\tdecodedWatermark.watermarkFrequency = watermarkFrequency;\n\t\t\t\t\n return decodedWatermark;\n}\n\nfunction roundUsingMathRound(value, places) {\n if (places >= 0) {\n var factor = Math.pow(10, places);\n return Math.round(value * factor) / factor; \n }\n \n return value;\n}\n\nfunction getAlarmStatus(bit) {\n var alarmResult = \"Invalid\";\n \n if (bit === 0) {\n alarmResult = \"No Alarm\";\n } else if (bit === 1 || bit === 255) {\n alarmResult = \"Alarm\";\n } else {\n alarmResult = \"Invalid\";\n }\n \n return alarmResult;\n}\n\nfunction getEnableStatus(bit) {\n var enableResult = \"Invalid\";\n \n switch (bit) {\n\t\tcase 0:\n\t\t enableResult = \"Disable\";\n\t\t\tbreak;\n\t\tcase 1:\n\t\t\tenableResult = \"Enable\";\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tenableResult = \"Invalid\";\n\t}\n \n return enableResult;\n}\n\nfunction getReportStatus(bit) {\n var reportResult = \"Invalid\";\n \n switch (bit5) {\n case 0:\n reportResult = \"Ignore\";\n break;\n case 1:\n reportResult = \"Report\";\n break;\n default:\n reportResult = \"Invalid\";\n }\n \n return reportResult;\n}", + "encoder": null, + "tbelEncoder": null, + "updateOnlyKeys": [ + "fPort", + "bandwidth", + "frequency", + "net_id", + "cluster_id", + "cluster_address", + "tenant_address", + "device_id", + "join_eui", + "eui", + "channel", + "devAddr", + "spreadingFactor", + "codeRate", + "tenantId", + "applicationId", + "battery" + ] + }, + "additionalInfo": { + "description": "" + }, + "edgeTemplate": false +} \ No newline at end of file diff --git a/VENDORS/Tektelic/Clover/ThingsStackIndustries/uplink/metadata.json b/VENDORS/Tektelic/Clover/ThingsStackIndustries/uplink/metadata.json new file mode 100644 index 00000000..23f54b34 --- /dev/null +++ b/VENDORS/Tektelic/Clover/ThingsStackIndustries/uplink/metadata.json @@ -0,0 +1,4 @@ +{ + "integrationName": "ChirpStack integration", + "includeGatewayInfo": "false" +} \ No newline at end of file diff --git a/VENDORS/Tektelic/Clover/ThingsStackIndustries/uplink/payload.json b/VENDORS/Tektelic/Clover/ThingsStackIndustries/uplink/payload.json new file mode 100644 index 00000000..7f8b5359 --- /dev/null +++ b/VENDORS/Tektelic/Clover/ThingsStackIndustries/uplink/payload.json @@ -0,0 +1,77 @@ +{ + "end_device_ids": { + "device_id": "eui-1000000000000001", + "application_ids": { + "application_id": "application-tti-name" + }, + "dev_eui": "1000000000000001", + "join_eui": "2000000000000001", + "dev_addr": "20000001" + }, + "correlation_ids": ["as:up:01H0PZDGB1NW6NAPD815NGHPF6", "gs:conn:01H0FJRSXSYT7VKNYXJ89F95XT", "gs:up:host:01H0FJRSY3MZMGPPFBQ4FZV4T8", "gs:uplink:01H0PZDG4HHGFRTXRTXD4PFTH7", "ns:uplink:01H0PZDG4JZ3BM0K6J89EQK1J7", "rpc:/ttn.lorawan.v3.GsNs/HandleUplink:01H0PZDG4J02F85RYFPCNSNXCR", "rpc:/ttn.lorawan.v3.NsAs/HandleUplink:01H0PZDGB081PMP806BJHNHX1A"], + "received_at": "2023-05-18T08:25:26.112483370Z", + "uplink_message": { + "session_key_id": "AYfg8rhha5n+FWx0ZaAprA==", + "f_port": 10, + "f_cnt": 5017, + "frm_payload": "ANNaAL0KCg==", + "rx_metadata": [{ + "gateway_ids": { + "gateway_id": "eui-6A7E111A10000000", + "eui": "6A7E111A10000000" + }, + "time": "2023-05-18T08:25:25.885310Z", + "timestamp": 818273765, + "rssi": -24, + "channel_rssi": -24, + "snr": 12, + "frequency_offset": "671", + "uplink_token": "CiIKIAoUZXVpLTZBN0UxMTFBMTAwMDAwMDASCCThJP/+9k6eEOW7l4YDGgwI9cGXowYQ5KPhrwMgiI2rp+jpOA=", + "channel_index": 2, + "received_at": "2023-05-18T08:25:25.869324983Z" + }, { + "gateway_ids": { + "gateway_id": "packetbroker" + }, + "packet_broker": { + "message_id": "01H0PZDG4MF9AYSMNY44MAVTDH", + "forwarder_net_id": "000013", + "forwarder_tenant_id": "ttn", + "forwarder_cluster_id": "eu1.cloud.thethings.network", + "forwarder_gateway_eui": "6A7E111A10000000", + "forwarder_gateway_id": "eui-6a7e111a10000000", + "home_network_net_id": "000013", + "home_network_tenant_id": "tenant", + "home_network_cluster_id": "eu1.cloud.thethings.industries" + }, + "time": "2023-05-18T08:25:25.885310Z", + "rssi": -24, + "channel_rssi": -24, + "snr": 12, + "frequency_offset": "671", + "uplink_token": "eyJnIjoiWlhsS2FHSkhZMmxQYVVwQ1RWUkpORkl3VGs1VE1XTnBURU5LYkdKdFRXbFBhVXBDVFZSSk5GSXdUazVKYVhkcFlWaFphVTlwU201a01uaGhWVlJvZDFSWFVuRmlSM1JtVFcxT2RVbHBkMmxrUjBadVNXcHZhV05ZY0RKT1IyeExaREpSZVZwR1pIUmpNRXBLVlVoR2RFNVZkR3BWVTBvNUxua3paVVJTWVRaM1lXOU1kbTQwVm5sdmIyWmlPWGN1ZUhCZmVrcElaa3hIWlZadGRVUlFVeTVuYlRaVlZXRXdkakpHV0VKMGJUUjZaMjVXUkVoeGVHRjRaMlJKTlVkS1VsbERhemc1VDNCbk5rVk1iM1JDUkVZM1VWbHdZbEJDTkdOblNqWjBlbkphYUV4MFRVMHhZMVZFTTFac01XdExURUo0YURaMFExTnhhMVJsWWw4eE5FdHlVVXcyZUhsRWFFbEhlakJITXpoTE0xaFdlRzR5VUVjMk4wNUViME5WTkhoTmRrazFZVk5oWkUwd2FXVnFjR294VGtoMFduZHlZMDFxVlVGNmRsbERUazlNY2s5eFdVeFpWMk5XTG1WVFFYVkpNVkptT1U5NWRqUTNhSEoxTUZoalYxRT0iLCJhIjp7ImZuaWQiOiIwMDAwMTMiLCJmdGlkIjoidHRuIiwiZmNpZCI6ImV1MS5jbG91ZC50aGV0aGluZ3MubmV0d29yayJ9fQ==", + "received_at": "2023-05-18T08:25:25.906038642Z" + }], + "settings": { + "data_rate": { + "lora": { + "bandwidth": 125000, + "spreading_factor": 7, + "coding_rate": "4/5" + } + }, + "frequency": "868500000", + "timestamp": 818273765, + "time": "2023-05-18T08:25:25.885310Z" + }, + "received_at": "2023-05-18T08:25:25.906399073Z", + "consumed_airtime": "0.097536s", + "network_ids": { + "net_id": "000013", + "tenant_id": "tenant", + "cluster_id": "eu1", + "cluster_address": "eu1.cloud.thethings.industries", + "tenant_address": "tenant.eu1.cloud.thethings.industries" + } + } +} \ No newline at end of file diff --git a/VENDORS/Tektelic/Clover/ThingsStackIndustries/uplink/payload_1.json b/VENDORS/Tektelic/Clover/ThingsStackIndustries/uplink/payload_1.json new file mode 100644 index 00000000..1e860e20 --- /dev/null +++ b/VENDORS/Tektelic/Clover/ThingsStackIndustries/uplink/payload_1.json @@ -0,0 +1,77 @@ +{ + "end_device_ids": { + "device_id": "eui-1000000000000001", + "application_ids": { + "application_id": "application-tti-name" + }, + "dev_eui": "1000000000000001", + "join_eui": "2000000000000001", + "dev_addr": "20000001" + }, + "correlation_ids": ["as:up:01H0PZDGB1NW6NAPD815NGHPF6", "gs:conn:01H0FJRSXSYT7VKNYXJ89F95XT", "gs:up:host:01H0FJRSY3MZMGPPFBQ4FZV4T8", "gs:uplink:01H0PZDG4HHGFRTXRTXD4PFTH7", "ns:uplink:01H0PZDG4JZ3BM0K6J89EQK1J7", "rpc:/ttn.lorawan.v3.GsNs/HandleUplink:01H0PZDG4J02F85RYFPCNSNXCR", "rpc:/ttn.lorawan.v3.NsAs/HandleUplink:01H0PZDGB081PMP806BJHNHX1A"], + "received_at": "2023-05-18T08:25:26.112483370Z", + "uplink_message": { + "session_key_id": "AYfg8rhha5n+FWx0ZaAprA==", + "f_port": 10, + "f_cnt": 5017, + "frm_payload": "AQQFeQICAtU=", + "rx_metadata": [{ + "gateway_ids": { + "gateway_id": "eui-6A7E111A10000000", + "eui": "6A7E111A10000000" + }, + "time": "2023-05-18T08:25:25.885310Z", + "timestamp": 818273765, + "rssi": -24, + "channel_rssi": -24, + "snr": 12, + "frequency_offset": "671", + "uplink_token": "CiIKIAoUZXVpLTZBN0UxMTFBMTAwMDAwMDASCCThJP/+9k6eEOW7l4YDGgwI9cGXowYQ5KPhrwMgiI2rp+jpOA=", + "channel_index": 2, + "received_at": "2023-05-18T08:25:25.869324983Z" + }, { + "gateway_ids": { + "gateway_id": "packetbroker" + }, + "packet_broker": { + "message_id": "01H0PZDG4MF9AYSMNY44MAVTDH", + "forwarder_net_id": "000013", + "forwarder_tenant_id": "ttn", + "forwarder_cluster_id": "eu1.cloud.thethings.network", + "forwarder_gateway_eui": "6A7E111A10000000", + "forwarder_gateway_id": "eui-6a7e111a10000000", + "home_network_net_id": "000013", + "home_network_tenant_id": "tenant", + "home_network_cluster_id": "eu1.cloud.thethings.industries" + }, + "time": "2023-05-18T08:25:25.885310Z", + "rssi": -24, + "channel_rssi": -24, + "snr": 12, + "frequency_offset": "671", + "uplink_token": "eyJnIjoiWlhsS2FHSkhZMmxQYVVwQ1RWUkpORkl3VGs1VE1XTnBURU5LYkdKdFRXbFBhVXBDVFZSSk5GSXdUazVKYVhkcFlWaFphVTlwU201a01uaGhWVlJvZDFSWFVuRmlSM1JtVFcxT2RVbHBkMmxrUjBadVNXcHZhV05ZY0RKT1IyeExaREpSZVZwR1pIUmpNRXBLVlVoR2RFNVZkR3BWVTBvNUxua3paVVJTWVRaM1lXOU1kbTQwVm5sdmIyWmlPWGN1ZUhCZmVrcElaa3hIWlZadGRVUlFVeTVuYlRaVlZXRXdkakpHV0VKMGJUUjZaMjVXUkVoeGVHRjRaMlJKTlVkS1VsbERhemc1VDNCbk5rVk1iM1JDUkVZM1VWbHdZbEJDTkdOblNqWjBlbkphYUV4MFRVMHhZMVZFTTFac01XdExURUo0YURaMFExTnhhMVJsWWw4eE5FdHlVVXcyZUhsRWFFbEhlakJITXpoTE0xaFdlRzR5VUVjMk4wNUViME5WTkhoTmRrazFZVk5oWkUwd2FXVnFjR294VGtoMFduZHlZMDFxVlVGNmRsbERUazlNY2s5eFdVeFpWMk5XTG1WVFFYVkpNVkptT1U5NWRqUTNhSEoxTUZoalYxRT0iLCJhIjp7ImZuaWQiOiIwMDAwMTMiLCJmdGlkIjoidHRuIiwiZmNpZCI6ImV1MS5jbG91ZC50aGV0aGluZ3MubmV0d29yayJ9fQ==", + "received_at": "2023-05-18T08:25:25.906038642Z" + }], + "settings": { + "data_rate": { + "lora": { + "bandwidth": 125000, + "spreading_factor": 7, + "coding_rate": "4/5" + } + }, + "frequency": "868500000", + "timestamp": 818273765, + "time": "2023-05-18T08:25:25.885310Z" + }, + "received_at": "2023-05-18T08:25:25.906399073Z", + "consumed_airtime": "0.097536s", + "network_ids": { + "net_id": "000013", + "tenant_id": "tenant", + "cluster_id": "eu1", + "cluster_address": "eu1.cloud.thethings.industries", + "tenant_address": "tenant.eu1.cloud.thethings.industries" + } + } +} \ No newline at end of file diff --git a/VENDORS/Tektelic/Clover/ThingsStackIndustries/uplink/result.json b/VENDORS/Tektelic/Clover/ThingsStackIndustries/uplink/result.json new file mode 100644 index 00000000..a37143c7 --- /dev/null +++ b/VENDORS/Tektelic/Clover/ThingsStackIndustries/uplink/result.json @@ -0,0 +1,27 @@ +{ + "deviceName": "eui-1000000000000001", + "deviceType": "Clover", + "attributes": { + "eui": "1000000000000001", + "fPort": 10, + "applicationId": "application-tti-name", + "devAddr": "20000001", + "spreadingFactor": 7, + "codeRate": "4/5", + "tenantId": "tenant", + "device_id": "eui-1000000000000001", + "join_eui": "2000000000000001", + "net_id": "000013", + "cluster_id": "eu1", + "cluster_address": "eu1.cloud.thethings.industries", + "bandwidth": 125000, + "frequency": "868500000" + }, + "telemetry": [{ + "ts": 1684398325906, + "values": { + "rem_batt_capacity": 90, + "rem_batt_days": 2570 + } + }] +} \ No newline at end of file diff --git a/VENDORS/Tektelic/Clover/ThingsStackIndustries/uplink/result_1.json b/VENDORS/Tektelic/Clover/ThingsStackIndustries/uplink/result_1.json new file mode 100644 index 00000000..413045ea --- /dev/null +++ b/VENDORS/Tektelic/Clover/ThingsStackIndustries/uplink/result_1.json @@ -0,0 +1,29 @@ +{ + "deviceName": "eui-1000000000000001", + "deviceType": "Clover", + "attributes": { + "eui": "1000000000000001", + "fPort": 10, + "applicationId": "application-tti-name", + "devAddr": "20000001", + "spreadingFactor": 7, + "codeRate": "4/5", + "tenantId": "tenant", + "device_id": "eui-1000000000000001", + "join_eui": "2000000000000001", + "net_id": "000013", + "cluster_id": "eu1", + "cluster_address": "eu1.cloud.thethings.industries", + "bandwidth": 125000, + "frequency": "868500000" + }, + "telemetry": [{ + "ts": 1684398325906, + "values": { + "input1_frequency_to_moisture": "Dry", + "input1_frequency": 1401, + "input2_voltage_to_temp": 22.6, + "input2_voltage": 0.725 + } + }] +} \ No newline at end of file diff --git a/VENDORS/Tektelic/Clover/info.json b/VENDORS/Tektelic/Clover/info.json new file mode 100644 index 00000000..c2d80a47 --- /dev/null +++ b/VENDORS/Tektelic/Clover/info.json @@ -0,0 +1,5 @@ +{ + "url": "https://tektelic.com/products/sensors/clover-agriculture-sensor/", + "label": "Clover: Agriculture sensor integrated soil and ambient environment sensor for smart agriculture deployments", + "description": "TEKTELIC CLOVER transforms precision agriculture by providing farmers real-time data on soil moisture, temperature, and ambient conditions. This allows for precise decision-making, optimizing crop treatments, and ensuring optimal growth conditions, ultimately boosting yields and minimizing resource wastage." +} \ No newline at end of file diff --git a/VENDORS/Tektelic/Clover/photo.png b/VENDORS/Tektelic/Clover/photo.png new file mode 100644 index 0000000000000000000000000000000000000000..2db227a3850cc5d72f6c52c4eb029aa2501edbd2 GIT binary patch literal 104798 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 z
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∈rlPtv*DI$r7v-P; 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 + + + + + + + + From 460af4e1ddf250735c2df0be211187871bf059b2 Mon Sep 17 00:00:00 2001 From: thingsboard017 Date: Thu, 19 Dec 2024 12:54:15 +0200 Subject: [PATCH 11/33] Added 4 LNS integrations for Kiwi --- .../Kiwi/ChirpStack/uplink/converter.json | 39 +++++++++ .../Kiwi/ChirpStack/uplink/metadata.json | 4 + .../Kiwi/ChirpStack/uplink/payload.json | 48 +++++++++++ .../Kiwi/ChirpStack/uplink/payload_1.json | 48 +++++++++++ .../Kiwi/ChirpStack/uplink/result.json | 26 ++++++ .../Kiwi/ChirpStack/uplink/result_1.json | 28 +++++++ .../Kiwi/LORIOT/uplink/converter.json | 29 +++++++ .../Tektelic/Kiwi/LORIOT/uplink/metadata.json | 4 + .../Tektelic/Kiwi/LORIOT/uplink/payload.json | 17 ++++ .../Kiwi/LORIOT/uplink/payload_1.json | 17 ++++ .../Tektelic/Kiwi/LORIOT/uplink/result.json | 16 ++++ .../Tektelic/Kiwi/LORIOT/uplink/result_1.json | 18 ++++ .../uplink/converter.json | 39 +++++++++ .../ThingsStackCommunity/uplink/metadata.json | 4 + .../ThingsStackCommunity/uplink/payload.json | 54 ++++++++++++ .../uplink/payload_1.json | 54 ++++++++++++ .../ThingsStackCommunity/uplink/result.json | 27 ++++++ .../ThingsStackCommunity/uplink/result_1.json | 29 +++++++ .../uplink/converter.json | 40 +++++++++ .../uplink/metadata.json | 4 + .../ThingsStackIndustries/uplink/payload.json | 77 ++++++++++++++++++ .../uplink/payload_1.json | 77 ++++++++++++++++++ .../ThingsStackIndustries/uplink/result.json | 27 ++++++ .../uplink/result_1.json | 29 +++++++ VENDORS/Tektelic/Kiwi/info.json | 5 ++ VENDORS/Tektelic/Kiwi/photo.png | Bin 0 -> 126813 bytes 26 files changed, 760 insertions(+) create mode 100644 VENDORS/Tektelic/Kiwi/ChirpStack/uplink/converter.json create mode 100644 VENDORS/Tektelic/Kiwi/ChirpStack/uplink/metadata.json create mode 100644 VENDORS/Tektelic/Kiwi/ChirpStack/uplink/payload.json create mode 100644 VENDORS/Tektelic/Kiwi/ChirpStack/uplink/payload_1.json create mode 100644 VENDORS/Tektelic/Kiwi/ChirpStack/uplink/result.json create mode 100644 VENDORS/Tektelic/Kiwi/ChirpStack/uplink/result_1.json create mode 100644 VENDORS/Tektelic/Kiwi/LORIOT/uplink/converter.json create mode 100644 VENDORS/Tektelic/Kiwi/LORIOT/uplink/metadata.json create mode 100644 VENDORS/Tektelic/Kiwi/LORIOT/uplink/payload.json create mode 100644 VENDORS/Tektelic/Kiwi/LORIOT/uplink/payload_1.json create mode 100644 VENDORS/Tektelic/Kiwi/LORIOT/uplink/result.json create mode 100644 VENDORS/Tektelic/Kiwi/LORIOT/uplink/result_1.json create mode 100644 VENDORS/Tektelic/Kiwi/ThingsStackCommunity/uplink/converter.json create mode 100644 VENDORS/Tektelic/Kiwi/ThingsStackCommunity/uplink/metadata.json create mode 100644 VENDORS/Tektelic/Kiwi/ThingsStackCommunity/uplink/payload.json create mode 100644 VENDORS/Tektelic/Kiwi/ThingsStackCommunity/uplink/payload_1.json create mode 100644 VENDORS/Tektelic/Kiwi/ThingsStackCommunity/uplink/result.json create mode 100644 VENDORS/Tektelic/Kiwi/ThingsStackCommunity/uplink/result_1.json create mode 100644 VENDORS/Tektelic/Kiwi/ThingsStackIndustries/uplink/converter.json create mode 100644 VENDORS/Tektelic/Kiwi/ThingsStackIndustries/uplink/metadata.json create mode 100644 VENDORS/Tektelic/Kiwi/ThingsStackIndustries/uplink/payload.json create mode 100644 VENDORS/Tektelic/Kiwi/ThingsStackIndustries/uplink/payload_1.json create mode 100644 VENDORS/Tektelic/Kiwi/ThingsStackIndustries/uplink/result.json create mode 100644 VENDORS/Tektelic/Kiwi/ThingsStackIndustries/uplink/result_1.json create mode 100644 VENDORS/Tektelic/Kiwi/info.json create mode 100644 VENDORS/Tektelic/Kiwi/photo.png diff --git a/VENDORS/Tektelic/Kiwi/ChirpStack/uplink/converter.json b/VENDORS/Tektelic/Kiwi/ChirpStack/uplink/converter.json new file mode 100644 index 00000000..b2e7d65b --- /dev/null +++ b/VENDORS/Tektelic/Kiwi/ChirpStack/uplink/converter.json @@ -0,0 +1,39 @@ +{ + "name": "ChirpStack Uplink Decoder for Kiwi", + "type": "UPLINK", + "debugMode": false, + "debugSettings": { + "failuresEnabled": true, + "allEnabled": false, + "allEnabledUntil": 1733331880270 + }, + "configuration": { + "scriptLang": "TBEL", + "decoder": null, + "tbelDecoder": "var data = decodeToJson(payload);\nvar deviceName = data.deviceInfo.deviceName + \" \" + data.deviceInfo.devEui;\nvar deviceType = \"Kiwi\";\nvar groupName = null; // If groupName is not null - created device will be added to the entity group with such name.\nvar customerName = null; // If customerName is not null - created devices will be assigned to customer with such name. \n\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// If you want to parse incoming data somehow, you can add your code to this function.\n// input: bytes\n// expected output:\n// {\n// \"attributes\": {\"attributeKey\": \"attributeValue\"},\n// \"telemetry\": [{\"ts\": 1...1, \"values\": {\"telemetryKey\":\"telemetryValue\"}, {\"ts\": 1...2, \"values\": {\"telemetryKey\":\"telemetryValue\"}}]\n// }\n\nfunction decodePayload(input) {\n var output = {\n attributes: {},\n telemetry: []\n };\n \n // --- Decoding code --- //\n var decoded = {};\n var fPort = data.fPort;\n if(fPort == 10) {\n for(var i = 0; i < input.length - 2; ) {\n var key_1 = input[i++] & 0xff;\n var key_2 = input[i++] & 0xff;\n \n if(key_1 == 0x00 && key_2 == 0xBA) {\n var val = (input[i] >> 7) & 1; \n\n decoded.eos_alert = getAlarmStatus(val);\n var battery_bits = input[i] & 0x7F;\n decoded.battery_voltage = roundUsingMathRound(battery_bits * 0.01 + 2.5, 2);\n i += 1;\n }\n else if(key_1 == 0x00 && key_2 == 0xD3) {\n decoded.rem_batt_capacity = parseBytesToInt(input, i, 1);\n i += 1;\n }\n else if(key_1 == 0x00 && key_2 == 0xBD) {\n decoded.rem_batt_days = parseBytesToInt(input, i, 2);\n\t\t\t\ti += 2;\n }\n else if(key_1 == 0x01 && key_2 == 0x04) {\n var value = parseBytesToInt(input, i, 2);\n var frequencyMoisture = 0;\n\t\t\t\tif (value > 1399){\n\t\t\t\t\tfrequencyMoisture = \"Dry\";\n\t\t\t\t} else if (value > 1396 && value <= 1399){\n\t\t\t\t\tfrequencyMoisture = 0.1;\n\t\t\t\t} else if (value > 1391 && value <= 1396){\n\t\t\t\t\tfrequencyMoisture = 0.2;\n\t\t\t\t} else if (value > 1386 && value <= 1391){\n\t\t\t\t\tfrequencyMoisture = 0.3;\n\t\t\t\t} else if (value > 1381 && value <= 1386){\n\t\t\t\t\tfrequencyMoisture = 0.4;\n\t\t\t\t} else if (value > 1376 && value <= 1381){\n\t\t\t\t\tfrequencyMoisture = 0.5;\n\t\t\t\t} else if (value > 1371 && value <= 1376){\n\t\t\t\t\tfrequencyMoisture = 0.6;\n\t\t\t\t} else if (value > 1366 && value <= 1371){\n\t\t\t\t\tfrequencyMoisture = 0.7;\n\t\t\t\t} else if (value > 1361 && value <= 1366){\n\t\t\t\t\tfrequencyMoisture = 0.8;\n\t\t\t\t} else if (value > 1356 && value <= 1361){\n\t\t\t\t\tfrequencyMoisture = 0.9;\n\t\t\t\t} else if (value > 1351 && value <= 1356){\n\t\t\t\t\tfrequencyMoisture = 1.0;\n\t\t\t\t} else if (value > 1346 && value <= 1351){\n\t\t\t\t\tfrequencyMoisture = 1.1;\n\t\t\t\t} else if (value > 1341 && value <= 1346){\n\t\t\t\t\tfrequencyMoisture = 1.2;\n\t\t\t\t} else {\n\t\t\t\t\tfrequencyMoisture = \"Wet\";\n\t\t\t\t}\n\t\t\t\tdecoded.input1_frequency_to_moisture = frequencyMoisture;\n\t\t\t\tdecoded.input1_frequency = value;\n\t\t\t\ti += 2;\n }\n else if (key_1 == 0x02 && key_2 == 0x02) {\n var voltageValue = parseBytesToInt(input, i, 2) * 0.001;\n\t\t\t\tvar voltageTempOutput = -32.46 * Math.log(voltageValue * 1000) + 236.36;\n\t\t\t\tdecoded.input2_voltage_to_temp = roundUsingMathRound(voltageTempOutput, 1);\n\t\t\t\tdecoded.input2_voltage = voltageValue;\n\t\t\t\ti += 2;\n }\n else if (key1 == 0x03 && key2 == 0x02) {\n var input3Voltage = parseBytesToInt(input, i, 2) * 0.001;\n \n decoded.input3_voltage = input3Voltage;\n\t\t\t\tdecoded.input3_voltage_to_temp = roundUsingMathRound((-33.01 * Math.pow(input3Voltage, 5)) + (217.4 * Math.pow(input3Voltage, 4)) + (-538.6 * Math.pow(input3Voltage, 3)) + (628.1 * Math.pow(input3Voltage, 2)) + (-378.9 * input3Voltage) + 102.9, 1);\n \n i += 2;\n }\n else if (key1 == 0x03 && key2 == 0x67) {\n decoded.input3_temperature = parseBytesToInt(input, i, 2) * 0.1;\n\t\t\t\ti += 2;\n }\n else if (key1 == 0x04 && key2 == 0x02) {\n var input4Voltage = parseBytesToInt(input, i, 2) * 0.001;\n \n decoded.input4_voltage = input4Voltage;\n\t\t\t\tdecodedinput4_voltage_to_temp = roundUsingMathRound((-33.01 * Math.pow(input4Voltage, 5)) + (217.4 * Math.pow(input4Voltage, 4)) + (-538.6 * Math.pow(input4Voltage, 3)) + (628.1 * Math.pow(input4Voltage, 2)) + (-378.9 * input4Voltage) + 102.9, 1);\n \n i += 2;\n }\n else if (key1 == 0x04 && key2 == 0x67) {\n decoded.input4_temperature = parseBytesToInt(input, i, 2) * 0.1;\n\t\t\t\ti += 2;\n }\n else if (key1 == 0x05 && key2 == 0x04) {\n var watermark1Frequency = parseBytesToInt(input, i, 2);\n\t\t\t\t\n\t\t\t\tvar decodedWatermarkData1 = getWatermarkData(watermark1Frequency);\t\n\t\t\t\tdecoded.watermark1_tension = decodedWatermarkData1.watermarkTension;\n\t\t\t\tdecoded.watermark1_frequency = decodedWatermarkData1.watermarkFrequency;\n\t\t\t\t\n\t\t\t\ti += 2;\n }\n else if (key1 == 0x06 && key2 == 0x04) {\n var watermark2Frequency = parseBytesToInt(input, i, 2);\n\t\t\t\t\n\t\t\t\tvar decodedWatermarkData2 = getWatermarkData(watermark2Frequency);\t\n\t\t\t\tdecoded.watermark2_tension = decodedWatermarkData2.watermarkTension;\n\t\t\t\tdecoded.watermark2_frequency = decodedWatermarkData2.watermarkFrequency;\n\t\t\t\t\n\t\t\t\ti += 2;\n }\n else if (key1 == 0x09 && key2 == 0x65) {\n var lightIntensity = parseBytesToInt(input, i, 2);\n\t\t\t\t\n\t\t\t\tdecoded.light_intensity = lightIntensity; \n\t\t\t\ti += 2;\n }\n else if (key1 == 0x09 && key2 == 0x00) {\n var lightDetected = parseBytesToInt(input, i, 1);\n\t\t\t\tdecoded.light_detected = getAlarmStatus(lightDetected);\n\t\t\t\t\n\t\t\t\ti += 1;\n }\n else if (key1 == 0x0A && key2 == 0x71) {\n decoded.accelerationX = parseBytesToInt(input, i, 2);\n decoded.accelerationY = parseBytesToInt(input, i + 2, 2);\n decoded.accelerationZ = parseBytesToInt(input, i + 4, 2);\n }\n else if (key1 == 0x0A && key2 == 0x00) {\n var orientationAlarm = parseBytesToInt(input, i, 1);\n decoded.orientation_alarm = getAlarmStatus(orientationAlarm);\n\t\t\t\t\n\t\t\t\ti += 1;\n }\n else if (key1 == 0x0B && key2 == 0x67) {\n decoded.ambient_temperature = parseBytesToInt(input, i, 2) * 0.1;\n i += 2;\n }\n else if (key1 == 0x0B && key2 == 0x68) {\n decoded.relative_humidity = parseBytesToInt(input, i, 1) * 0.5;\n i += 1;\n }\n else if (key1 == 0x0C && key2 == 0x67) {\n decoded.mcu_temperature = parseBytesToInt(input, i, 2) * 0.1;\n i += 2;\n }\n else if (key1 == 0x0D && key2 == 0x73) {\n decoded.RFU_2 = parseBytesToInt(input, i, 1) * 0.1;\n i += 1;\n }\n }\n }\n else if (fPort == 100) {\n for(var i = 0; i < input.length -1; ) {\n var key = input[i++] & 0xff;\n \n if(key == 0x10) {\n var val = (((input[i] << 8) | input[i + 1]) >> 15) & 1;\n switch (val){\n\t\t\t\t\tcase 0:\n\t\t\t\t\t\toutput.attributes.loramac_join_mode = \"ABP\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 1:\n\t\t\t\t\t\toutput.attributes.loramac_join_mode = \"OTAA\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\toutput.attributes.loramac_join_mode = \"Invalid\";\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\ti += 1;\n }\n else if (key == 0x11) {\n var val = (((input[i] << 8) | input[i + 1]) >> 12) & 0xF;\n switch (val) {\n\t\t\t\t\tcase 0:\n\t\t\t\t\t\toutput.attributes.deviceClassEnabled = \"Class A\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 12:\n\t\t\t\t\t\toutput.attributes.deviceClassEnabled = \"Class C\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\toutput.attributes.deviceClassEnabled = \"Invalid\";\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tvar val = (((input[i] << 8) | input[i + 1]) >> 3) & 1;\n\t\t\t\toutput.attributes.adr = getEnableStatus(val);\n\t\t\t\t\n\t\t\t\tvar val = (((input[i] << 8) | input[i + 1]) >> 2) & 1;\n\t\t\t\toutput.attributes.duty_cycle = getEnableStatus(val);\n\t\t\t\t\n\t\t\t\tvar val = (((input[i] << 8) | input[i + 1]) >> 1) & 1;\n\t\t\t\t\n\t\t\t\tswitch (val) {\n\t\t\t\t\tcase 0:\n\t\t\t\t\t\toutput.attributes.sync_word = \"Private\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 1:\n\t\t\t\t\t\toutput.attributes.sync_word = \"Public\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\toutput.attributes.sync_word = \"Invalid\";\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tvar val = ((input[i] << 8) | input[i + 1]) & 1;\n\t\t\t\t\n\t\t\t\tswitch (val){\n\t\t\t\t\tcase 0:\n\t\t\t\t\t\toutput.attributes.confirm_mode = \"Unconfirmed\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 1:\n\t\t\t\t\t\toutput.attributes.confirm_mode = \"Confirmed\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t output.attributes.confirm_mode = \"Invalid\";\n\t\t\t\t}\n\t\t\t\ti += 2;\n }\n else if (key == 0x12) {\n output.attributes.dr_number = (((input[i] << 8) | input[i + 1]) >> 8) & 0xF;\n output.attributes.tx_power_number = ((input[i] << 8) | input[i + 1]) & 0xF;\n \n i +=2;\n }\n else if (key == 0x13) {\n output.attributes.frequency = (((input[i] << 32) | (input[i + 1] << 24) | (input[i + 2] << 16) | (input[i + 3] << 8) | input[i + 4]) >> 8) & 0xFFFFFFFF;\n output.attributes.dr_number_rx2 = input[i + 4] & 0xFF;\n \n i += 5;\n }\n else if (key == 0x20) {\n output.attributes.seconds_per_core_tick = parseBytesToInt(input, i, 4);\n i += 4;\n }\n else if(key == 0x21) {\n output.attributes.tick_per_battery = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x22) {\n output.attributes.tick_per_ambient_temperature = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x23) {\n output.attributes.tick_per_relative_humidity = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x24) {\n output.attributes.tick_per_light = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x25) {\n output.attributes.tick_per_input1 = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x26) {\n output.attributes.tick_per_input2 = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x27) {\n output.attributes.tick_per_input3 = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x28) {\n output.attributes.tick_per_input4 = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x29) {\n output.attributes.tick_per_watermark1 = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x2A) {\n output.attributes.tick_per_watermark2 = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x2C) {\n output.attributes.tick_per_accelerometer = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x2D) {\n output.attributes.tick_per_orientation_alarm = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x2E) {\n output.attributes.tick_per_mcu_temperature = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x2F) {\n output.attributes.RFU_1 = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x30) {\n output.attributes.temperature_relative_humidity_idle = parseBytesToInt(input, i, 4);\n i += 4;\n }\n else if(key == 0x31) {\n output.attributes.temperature_relative_humidity_active = parseBytesToInt(input, i, 4);\n i += 4;\n }\n else if(key == 0x32) {\n output.attributes.high_ambient_temp_raw = (((input[i] << 8) | input[i + 1]) >> 8) & 0xFF;\n output.attributes.low_ambient_temp_raw = ((input[i] << 8) | input[i + 1]) & 0xFF;\n \n i += 2;\n }\n else if(key == 0x33) {\n var val = input[i] & 1;\n output.attributes.ambient_temperature_threshold_enabled = getEnableStatus(val);\n\t\t\t\t\n\t\t\t\ti += 1;\n }\n else if (key == 0x34) {\n output.attributes.high_rh = input[i];\n\t\t\t\toutput.attributes.low_rh = input[i + 1];\n\t\t\t\t\n\t\t\t\ti += 2;\n }\n else if (key == 0x35) {\n var val = input[i] & 1;\n output.attributes.relative_humidity_threshold_enabled = getEnableStatus(val);\n\t\t\t\t\n\t\t\t\ti += 1;\n }\n else if (key == 0x36) {\n output.attributes.input_sample_period_idle = parseBytesToInt(input, i, 4);\n i += 4;\n }\n else if (key == 0x37) {\n output.attributes.input_sample_period_active = parseBytesToInt(input, i, 4);\n i += 4;\n }\n else if (key == 0x38) {\n output.attributes.low_input1 = parseBytesToInt(input, i, 2);\n output.attributes.high_input1 = parseBytesToInt(input, i + 2, 2);\n \n i += 4;\n }\n else if (key == 0x39) {\n output.attributes.low_input2 = parseBytesToInt(input, i, 2);\n output.attributes.high_input2 = parseBytesToInt(input, i + 2, 2);\n \n i += 4;\n }\n else if (key == 0x3A) {\n output.attributes.low_input3 = parseBytesToInt(input, i, 2);\n output.attributes.high_input3 = parseBytesToInt(input, i + 2, 2);\n \n i += 4;\n }\n else if (key == 0x3B) {\n output.attributes.low_input4 = parseBytesToInt(input, i, 2);\n output.attributes.high_input4 = parseBytesToInt(input, i + 2, 2);\n \n i += 4;\n }\n else if (key == 0x3C) {\n output.attributes.low_watermark1 = parseBytesToInt(input, i, 2);\n output.attributes.high_watermark1 = parseBytesToInt(input, i + 2, 2);\n \n i += 4;\n }\n else if (key == 0x3D) {\n output.attributes.low_watermark2 = parseBytesToInt(input, i, 2);\n output.attributes.high_watermark2 = parseBytesToInt(input, i + 2, 2);\n \n i += 4;\n }\n else if (key == 0x3F) {\n var input_status = input[i] & 0x3F;\n \n var bit0 = (input_status >> 0) & 1;\n output.attributes.input_enable_input1 = getEnableStatus(bit0);\n \n var bit1 = (input_status >> 1) & 1;\n output.attributes.input_enable_input2 = getEnableStatus(bit1);\n \n var bit2 = (input_status >> 2) & 1;\n output.attributes.input_enable_input3 = getEnableStatus(bit2);\n \n var bit3 = (input_status >> 3) & 1;\n output.attributes.input_enable_input4 = getEnableStatus(bit3);\n \n var bit4 = (input_status >> 4) & 1;\n output.attributes.input_enable_watermark1_enable = getEnableStatus(bit4);\n \n var bit5 = (input_status >> 5) & 1;\n output.attributes.input_enable_watermark2_enable = getEnableStatus(bit5);\n \n i += 1;\n }\n else if (key == 0x40) {\n output.attributes.mcu_temperature_sample_period_idle = parseBytesToInt(input, i, 4);\n i += 4;\n }\n else if (key == 0x41) {\n output.attributes.mcu_temperature_sample_period_active = parseBytesToInt(input, i, 4);\n i += 4;\n }\n else if (key == 0x42) {\n output.attributes.high_mcu_temp = input[i + 1];\n output.attributes.low_mcu_temp = input[i];\n i += 4;\n }\n else if (key == 0x43) {\n var val = input[i] & 1;\n output.attributes.mcu_temperature_enable = getEnableStatus(val);\n\n\t\t\t\ti += 2;\n }\n else if (key == 0x44) {\n output.attributes.low_input3_onewire = parseBytesToInt(input, i, 2);\n output.attributes.high_input3_onewire = parseBytesToInt(input, i + 2, 2);\n i += 2;\n }\n else if (key == 0x45) {\n output.attributes.low_input4_onewire = parseBytesToInt(input, i, 2);\n output.attributes.high_input4_onewire = parseBytesToInt(input, i + 2, 2);\n i += 2;\n }\n else if (key == 0x48 ) {\n var val = input[i] & 1;\n output.attributes.ALS_interrupt_enabled = getEnableStatus(val);\n \n i += 1;\n }\n else if (key == 0x49) {\n output.attributes.ALS_upper_threshold = parseBytesToInt(input, i, 2);\n i +=2;\n }\n else if (key == 0x4A) {\n output.attributes.ALS_lower_threshold = parseBytesToInt(input, i, 2);\n i +=2;\n }\n else if (key == 0x4B) {\n output.attributes.light_sample_period_idle = parseBytesToInt(input, i, 4);\n i +=4;\n }\n else if (key == 0x4C) {\n output.attributes.light_sample_period_active = parseBytesToInt(input, i, 4);\n i +=4;\n }\n else if (key == 0x4D) {\n var status = input[i] & 0x03;\n \n var bit1 = status & 1;\n output.attributes.light_alarm_reported = getReportStatus(bit1);\n \n var bit2 = (status >> 1) & 1;\n output.attributes.light_intensity_reported = getReportStatus(bit2);\n \n i += 1;\n }\n else if (key == 0x50) {\n output.attributes.orientation_alarm_threshold = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x51) {\n var status = input[i];\n\n var bit5 = (status >> 5) & 1;\n output.attributes.orientation_vector_report = getReportStatus(bit5);\n \n var bit0 = status & 1; \n output.attributes.orientation_alarm_report = getReportStatus(bit0);\n \n i += 1;\n }\n else if (key == 0x52) {\n var status = input[i]; \n \n var bit7 = (status >> 7) & 1; \n var bit0 = status & 1; \n \n switch (bit7) {\n case 0:\n output.attributes.accelerometer_power_on = \"Off\";\n break;\n case 1:\n output.attributes.accelerometer_power_on = \"On\";\n break;\n default:\n output.attributes.accelerometer_power_on = \"Invalid\";\n }\n \n output.attributes.orientation_alarm_mode = getEnableStatus(bit0);\n \n i += 1;\n }\n else if (key == 0x61) {\n var status = input[i]; \n \n var bit1 = (status >> 1) & 1;\n output.attributes.report_capacity_enabled = getEnableStatus(bit1);\n \n var bit2 = (status >> 2) & 1;\n output.attributes.report_lifetime_enabled = getEnableStatus(bit2);\n \n i += 1;\n }\n else if (key == 0x62) {\n output.attributes.avg_current_window = parseBytesToInt(input, i, 1);\n i += 1;\n }\n else if (key == 0x71) {\n output.attributes.app_major_version = input[i + 6];\n\t\t\t\toutput.attributes.app_minor_version = input[i + 5];\n\t\t\t\toutput.attributes.app_revision = input[i + 4];\n\t\t\t\toutput.attributes.loramac_major_version = input[i + 3];\n\t\t\t\toutput.attributes.loramac_minor_version = input[i + 2];\n\t\t\t\toutput.attributes.loramac_revision = input[i + 1];\n\t\t\t\tvar val = input[i];\n\t\t\t\tswitch (val){\n\t\t\t\t\tcase 0:\n\t\t\t\t\t\toutput.attributes.region = \"EU868\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 1:\n\t\t\t\t\t\toutput.attributes.region = \"US915\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 2:\n\t\t\t\t\t\toutput.attributes.region = \"AS923\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 3:\n\t\t\t\t\t\toutput.attributes.region = \"AU915\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 4:\n\t\t\t\t\t\toutput.attributes.region = \"IN865\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 6:\n\t\t\t\t\t\toutput.attributes.region = \"KR920\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 7:\n\t\t\t\t\t\toutput.attributes.region = \"RU864\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\toutput.attributes.region = \"Invalid\";\n\t\t\t\t}\n\t\t\t\ti += 7;\n }\n }\n }\n else if (fPort == 101) {\n var size = input.length;\n var responses = [];\n \n var index = 0;\n while (index < size) {\n var downlinkFcnt = input[index++] & 0xFF; \n var numInvalidWrites = input[index++] & 0xFF; \n \n if (numInvalidWrites > 0) {\n var invalidRegisters = [];\n for (var i = 0; i < numInvalidWrites; i++) {\n invalidRegisters.add(String.format(\"0x%02X\", input[index + i]));\n }\n index += numInvalidWrites;\n \n responses.add(String.format(\n \"%d Invalid write command(s) from DL:%d for register(s): %s\",\n numInvalidWrites, downlinkFcnt, String.join(\", \", invalidRegisters)\n ));\n } else {\n responses.add(String.format(\"All write commands from DL:%d were successful\", downlinkFcnt));\n }\n }\n \n decoded.response = responses;\n }\n\n output.telemetry = [{\n ts: timestamp,\n values: decoded\n }];\n // --- Decoding code --- //\n return output;\n}\n\n// --- attributes and telemetry objects ---\nvar telemetry = [];\nvar attributes = {};\n// --- attributes and telemetry objects ---\n\n// --- Timestamp parsing\nvar dateString = data.time;\ntimestamp = parseDateToTimestamp(dateString);\n// --- Timestamp parsing\n\n// Passing incoming bytes to decodePayload function, to get custom decoding\nvar customDecoding = decodePayload(base64ToBytes(data.data));\n\n\nattributes.eui = data.deviceInfo.devEui;\n\n// Collecting data to result\nif (customDecoding.?telemetry.size() > 0) {\n if (customDecoding.telemetry instanceof java.util.ArrayList) {\n foreach(telemetryObj: customDecoding.telemetry) {\n if (telemetryObj.ts != null && telemetryObj.values != null) {\n telemetry.add(telemetryObj);\n }\n }\n } else {\n telemetry.putAll(customDecoding.telemetry);\n }\n}\n\nif (customDecoding.?attributes.size() > 0) {\n attributes.putAll(customDecoding.attributes);\n}\n\n// You can add some keys manually to attributes or telemetry\nattributes.eui = data.deviceInfo.?devEui;\nattributes.devAddr = data.devAddr;\nattributes.fPort = data.fPort;\nattributes.applicationId = data.deviceInfo.?applicationId;\nattributes.applicationName = data.deviceInfo.?applicationName;\nattributes.tenantId = data.deviceInfo.?tenantId;\nattributes.tenantName = data.deviceInfo.?tenantName;\nattributes.deviceProfileId = data.deviceInfo.?deviceProfileId;\nattributes.deviceProfileName = data.deviceInfo.?deviceProfileName;\nattributes.frequency = data.txInfo.?frequency;\nattributes.bandwidth = data.txInfo.?modulation.?lora.?bandwidth;\nattributes.spreadingFactor = data.txInfo.?modulation.?lora.?spreadingFactor;\nattributes.codeRate = data.txInfo.?modulation.?lora.?codeRate;\n\nif(Boolean.parseBoolean(metadata[\"includeGatewayInfo\"])) {\n var gatewayInfo = getGatewayInfo();\n var addDataToTelemetry = {};\n addDataToTelemetry.snr = gatewayInfo.snr;\n addDataToTelemetry.rssi = gatewayInfo.rssi;\n addDataToTelemetry.channel = gatewayInfo.channel;\n addDataToTelemetry.rfChain = gatewayInfo.rfChain;\n addDataToTelemetry.fCnt = data.fCnt;\n \n telemetry = processTelemetryData(telemetry, addDataToTelemetry);\n}\n\nvar result = {\n deviceName: deviceName,\n deviceType: deviceType,\n // assetName: assetName,\n // assetType: assetType,\n attributes: attributes,\n telemetry: telemetry\n};\n\naddAdditionalInfoForDeviceMsg(result, customerName, groupName);\n\nreturn result;\n\nfunction addAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName) {\n if (customerName != null) {\n deviceInfo.customerName = customerName;\n }\n if (groupName != null) {\n deviceInfo.groupName = groupName;\n }\n}\n\nfunction parseDateToTimestamp(dateString) {\n var date = new Date(dateString);\n var timestamp = date.getTime();\n \n // If we cannot parse timestamp - we will use the current timestamp\n if (timestamp == -1) {\n timestamp = Date.now();\n }\n \n return timestamp;\n}\n\nfunction getGatewayInfo() {\n var gatewayList = data.rxInfo;\n var maxRssi = Integer.MIN_VALUE;\n var gatewayInfo = {};\n \n foreach (gateway : gatewayList) {\n if(gateway.rssi > maxRssi) {\n maxRssi = gateway.rssi;\n gatewayInfo = gateway;\n }\n }\n \n return gatewayInfo;\n}\n\nfunction processTelemetryData(telemetry, addDataToTelemetry) {\n if (telemetry.size >= 1) {\n telemetry = addDataToTelemetries(telemetry, addDataToTelemetry);\n }\n else {\n telemetry.add(addDataToTelemetry);\n }\n \n return telemetry;\n}\n\nfunction addDataToTelemetries(telemetries, addDataToTelemetry) {\n foreach(telemetry : telemetries) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[\"values\"].keys.contains(element.key)) {\n telemetry[\"values\"][element.key] = element.value;\n }\n } \n }\n \n return telemetries;\n}\n\nfunction getWatermarkData(watermarkFrequency) {\n var decodedWatermark = {};\n \n var watermarkTension = 0;\n if (watermarkFrequency > 6430){\n\t\twatermarkTension = 0;\n\t} else if (watermarkFrequency >= 4330 && watermarkFrequency <= 6430){\n\t watermarkTension = 9.000 - (watermarkFrequency - 4330.000) * 0.004286;\n\t} else if (watermarkFrequency >= 2820 && watermarkFrequency < 4330){\n\t\twatermarkTension = 15.000 - (watermarkFrequency - 2820.000) * 0.003974;\n\t} else if (watermarkFrequency >= 1110 && watermarkFrequency < 2820){\n\t\twatermarkTension = 35.000 - (watermarkFrequency - 1110.000) * 0.01170;\n\t} else if (watermarkFrequency >= 770 && watermarkFrequency < 1110){\n\t\twatermarkTension = 55.000 - (watermarkFrequency - 770.000) * 0.05884;\n\t} else if (watermarkFrequency >= 600 && watermarkFrequency < 770){\n\t\twatermarkTension = 75.000 - (watermarkFrequency - 600.000) * 0.1176;\n\t} else if (watermarkFrequency >= 485 && watermarkFrequency < 600){\n\t\twatermarkTension = 100.000 - (watermarkFrequency - 485.000) * 0.2174;\n } else if (watermarkFrequency >= 293 && watermarkFrequency < 485){\n\t\twatermarkTension = 200.000 - (watermarkFrequency - 293.000) * 0.5208;\n\t} else {\n\t watermarkTension = 200;\n\t}\t\t\t\t\t\n\tdecodedWatermark.watermarkTension = roundUsingMathRound(watermarkTension, 0);\n\tdecodedWatermark.watermarkFrequency = watermarkFrequency;\n\t\t\t\t\n return decodedWatermark;\n}\n\nfunction roundUsingMathRound(value, places) {\n if (places >= 0) {\n var factor = Math.pow(10, places);\n return Math.round(value * factor) / factor; \n }\n \n return value;\n}\n\nfunction getAlarmStatus(bit) {\n var alarmResult = \"Invalid\";\n \n if (bit === 0) {\n alarmResult = \"No Alarm\";\n } else if (bit === 1 || bit === 255) {\n alarmResult = \"Alarm\";\n } else {\n alarmResult = \"Invalid\";\n }\n \n return alarmResult;\n}\n\nfunction getEnableStatus(bit) {\n var enableResult = \"Invalid\";\n \n switch (bit) {\n\t\tcase 0:\n\t\t enableResult = \"Disable\";\n\t\t\tbreak;\n\t\tcase 1:\n\t\t\tenableResult = \"Enable\";\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tenableResult = \"Invalid\";\n\t}\n \n return enableResult;\n}\n\nfunction getReportStatus(bit) {\n var reportResult = \"Invalid\";\n \n switch (bit5) {\n case 0:\n reportResult = \"Ignore\";\n break;\n case 1:\n reportResult = \"Report\";\n break;\n default:\n reportResult = \"Invalid\";\n }\n \n return reportResult;\n}", + "encoder": null, + "tbelEncoder": null, + "updateOnlyKeys": [ + "tenantId", + "tenantName", + "applicationId", + "applicationName", + "deviceProfileId", + "deviceProfileName", + "devAddr", + "fPort", + "frequency", + "bandwidth", + "spreadingFactor", + "codeRate", + "channel", + "rfChain", + "eui", + "battery" + ] + }, + "additionalInfo": { + "description": "" + }, + "edgeTemplate": false +} \ No newline at end of file diff --git a/VENDORS/Tektelic/Kiwi/ChirpStack/uplink/metadata.json b/VENDORS/Tektelic/Kiwi/ChirpStack/uplink/metadata.json new file mode 100644 index 00000000..23f54b34 --- /dev/null +++ b/VENDORS/Tektelic/Kiwi/ChirpStack/uplink/metadata.json @@ -0,0 +1,4 @@ +{ + "integrationName": "ChirpStack integration", + "includeGatewayInfo": "false" +} \ No newline at end of file diff --git a/VENDORS/Tektelic/Kiwi/ChirpStack/uplink/payload.json b/VENDORS/Tektelic/Kiwi/ChirpStack/uplink/payload.json new file mode 100644 index 00000000..9663c8dd --- /dev/null +++ b/VENDORS/Tektelic/Kiwi/ChirpStack/uplink/payload.json @@ -0,0 +1,48 @@ +{ + "deduplicationId": "57433366-50a6-4dc2-8145-2df1bbc70d9e", + "time": "2023-05-22T07:47:05.404859+00:00", + "deviceInfo": { + "tenantId": "52f14cd4-c6f1-4fbd-8f87-4025e1d49242", + "tenantName": "ChirpStack", + "applicationId": "ca739e26-7b67-4f14-b69e-d568c22a5a75", + "applicationName": "Chirpstack application", + "deviceProfileId": "605d08d4-65f5-4d2c-8a5a-3d2457662f79", + "deviceProfileName": "Chirpstack default device profile", + "deviceName": "Device name", + "devEui": "1000000000000001", + "tags": {} + }, + "devAddr": "20000001", + "adr": true, + "dr": 5, + "fCnt": 4, + "fPort": 10, + "confirmed": false, + "data": "ANNaAL0KCg==", + "rxInfo": [{ + "gatewayId": "6a7e111a10000000", + "uplinkId": 24022, + "time": "2023-05-22T07:47:05.404859+00:00", + "rssi": -35, + "snr": 11.5, + "channel": 2, + "rfChain": 1, + "location": {}, + "context": "EFwMtA==", + "metadata": { + "region_common_name": "EU868", + "region_config_id": "eu868" + }, + "crcStatus": "CRC_OK" + }], + "txInfo": { + "frequency": 868500000, + "modulation": { + "lora": { + "bandwidth": 125000, + "spreadingFactor": 7, + "codeRate": "CR_4_5" + } + } + } +} \ No newline at end of file diff --git a/VENDORS/Tektelic/Kiwi/ChirpStack/uplink/payload_1.json b/VENDORS/Tektelic/Kiwi/ChirpStack/uplink/payload_1.json new file mode 100644 index 00000000..384793b8 --- /dev/null +++ b/VENDORS/Tektelic/Kiwi/ChirpStack/uplink/payload_1.json @@ -0,0 +1,48 @@ +{ + "deduplicationId": "57433366-50a6-4dc2-8145-2df1bbc70d9e", + "time": "2023-05-22T07:47:05.404859+00:00", + "deviceInfo": { + "tenantId": "52f14cd4-c6f1-4fbd-8f87-4025e1d49242", + "tenantName": "ChirpStack", + "applicationId": "ca739e26-7b67-4f14-b69e-d568c22a5a75", + "applicationName": "Chirpstack application", + "deviceProfileId": "605d08d4-65f5-4d2c-8a5a-3d2457662f79", + "deviceProfileName": "Chirpstack default device profile", + "deviceName": "Device name", + "devEui": "1000000000000001", + "tags": {} + }, + "devAddr": "20000001", + "adr": true, + "dr": 5, + "fCnt": 4, + "fPort": 10, + "confirmed": false, + "data": "AQQFeQICAtU=", + "rxInfo": [{ + "gatewayId": "6a7e111a10000000", + "uplinkId": 24022, + "time": "2023-05-22T07:47:05.404859+00:00", + "rssi": -35, + "snr": 11.5, + "channel": 2, + "rfChain": 1, + "location": {}, + "context": "EFwMtA==", + "metadata": { + "region_common_name": "EU868", + "region_config_id": "eu868" + }, + "crcStatus": "CRC_OK" + }], + "txInfo": { + "frequency": 868500000, + "modulation": { + "lora": { + "bandwidth": 125000, + "spreadingFactor": 7, + "codeRate": "CR_4_5" + } + } + } +} \ No newline at end of file diff --git a/VENDORS/Tektelic/Kiwi/ChirpStack/uplink/result.json b/VENDORS/Tektelic/Kiwi/ChirpStack/uplink/result.json new file mode 100644 index 00000000..fe5d836f --- /dev/null +++ b/VENDORS/Tektelic/Kiwi/ChirpStack/uplink/result.json @@ -0,0 +1,26 @@ +{ + "deviceName": "Device name 1000000000000001", + "deviceType": "Kiwi", + "attributes": { + "eui": "1000000000000001", + "devAddr": "20000001", + "fPort": 10, + "applicationId": "ca739e26-7b67-4f14-b69e-d568c22a5a75", + "applicationName": "Chirpstack application", + "tenantId": "52f14cd4-c6f1-4fbd-8f87-4025e1d49242", + "tenantName": "ChirpStack", + "deviceProfileId": "605d08d4-65f5-4d2c-8a5a-3d2457662f79", + "deviceProfileName": "Chirpstack default device profile", + "frequency": 868500000, + "bandwidth": 125000, + "spreadingFactor": 7, + "codeRate": "CR_4_5" + }, + "telemetry": [{ + "ts": 1684741625404, + "values": { + "rem_batt_capacity": 90, + "rem_batt_days": 2570 + } + }] +} \ No newline at end of file diff --git a/VENDORS/Tektelic/Kiwi/ChirpStack/uplink/result_1.json b/VENDORS/Tektelic/Kiwi/ChirpStack/uplink/result_1.json new file mode 100644 index 00000000..aa5fb3d1 --- /dev/null +++ b/VENDORS/Tektelic/Kiwi/ChirpStack/uplink/result_1.json @@ -0,0 +1,28 @@ +{ + "deviceName": "Device name 1000000000000001", + "deviceType": "Kiwi", + "attributes": { + "eui": "1000000000000001", + "devAddr": "20000001", + "fPort": 10, + "applicationId": "ca739e26-7b67-4f14-b69e-d568c22a5a75", + "applicationName": "Chirpstack application", + "tenantId": "52f14cd4-c6f1-4fbd-8f87-4025e1d49242", + "tenantName": "ChirpStack", + "deviceProfileId": "605d08d4-65f5-4d2c-8a5a-3d2457662f79", + "deviceProfileName": "Chirpstack default device profile", + "frequency": 868500000, + "bandwidth": 125000, + "spreadingFactor": 7, + "codeRate": "CR_4_5" + }, + "telemetry": [{ + "ts": 1684741625404, + "values": { + "input1_frequency_to_moisture": "Dry", + "input1_frequency": 1401, + "input2_voltage_to_temp": 22.6, + "input2_voltage": 0.725 + } + }] +} \ No newline at end of file diff --git a/VENDORS/Tektelic/Kiwi/LORIOT/uplink/converter.json b/VENDORS/Tektelic/Kiwi/LORIOT/uplink/converter.json new file mode 100644 index 00000000..8cc2c484 --- /dev/null +++ b/VENDORS/Tektelic/Kiwi/LORIOT/uplink/converter.json @@ -0,0 +1,29 @@ +{ + "name": "Loriot Uplink Decoder for Kiwi", + "type": "UPLINK", + "debugMode": false, + "debugSettings": { + "failuresEnabled": true, + "allEnabled": false, + "allEnabledUntil": 1733331880270 + }, + "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);\nvar deviceName = data.EUI;\nvar deviceType = \"Kiwi\";\nvar groupName = null; // If groupName is not null - created device will be added to the entity group with such name.\nvar customerName = null; // If customerName is not null - created devices will be assigned to customer with such name. \n\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// If you want to parse incoming data somehow, you can add your code to this function.\n// input: bytes\n// expected output:\n// {\n// \"attributes\": {\"attributeKey\": \"attributeValue\"},\n// \"telemetry\": {\"telemetryKey\": \"telemetryValue\"}\n// }\n\nfunction decodePayload(input) {\n var output = { attributes: {}, telemetry: []};\n \n var decoded = {};\n var fPort = data.port;\n if(fPort == 10) {\n for(var i = 0; i < input.length - 2; ) {\n var key_1 = input[i++] & 0xff;\n var key_2 = input[i++] & 0xff;\n \n if(key_1 == 0x00 && key_2 == 0xBA) {\n var val = (input[i] >> 7) & 1; \n\n decoded.eos_alert = getAlarmStatus(val);\n var battery_bits = input[i] & 0x7F;\n decoded.battery_voltage = roundUsingMathRound(battery_bits * 0.01 + 2.5, 2);\n i += 1;\n }\n else if(key_1 == 0x00 && key_2 == 0xD3) {\n decoded.rem_batt_capacity = parseBytesToInt(input, i, 1);\n i += 1;\n }\n else if(key_1 == 0x00 && key_2 == 0xBD) {\n decoded.rem_batt_days = parseBytesToInt(input, i, 2);\n\t\t\t\ti += 2;\n }\n else if(key_1 == 0x01 && key_2 == 0x04) {\n var value = parseBytesToInt(input, i, 2);\n var frequencyMoisture = 0;\n\t\t\t\tif (value > 1399){\n\t\t\t\t\tfrequencyMoisture = \"Dry\";\n\t\t\t\t} else if (value > 1396 && value <= 1399){\n\t\t\t\t\tfrequencyMoisture = 0.1;\n\t\t\t\t} else if (value > 1391 && value <= 1396){\n\t\t\t\t\tfrequencyMoisture = 0.2;\n\t\t\t\t} else if (value > 1386 && value <= 1391){\n\t\t\t\t\tfrequencyMoisture = 0.3;\n\t\t\t\t} else if (value > 1381 && value <= 1386){\n\t\t\t\t\tfrequencyMoisture = 0.4;\n\t\t\t\t} else if (value > 1376 && value <= 1381){\n\t\t\t\t\tfrequencyMoisture = 0.5;\n\t\t\t\t} else if (value > 1371 && value <= 1376){\n\t\t\t\t\tfrequencyMoisture = 0.6;\n\t\t\t\t} else if (value > 1366 && value <= 1371){\n\t\t\t\t\tfrequencyMoisture = 0.7;\n\t\t\t\t} else if (value > 1361 && value <= 1366){\n\t\t\t\t\tfrequencyMoisture = 0.8;\n\t\t\t\t} else if (value > 1356 && value <= 1361){\n\t\t\t\t\tfrequencyMoisture = 0.9;\n\t\t\t\t} else if (value > 1351 && value <= 1356){\n\t\t\t\t\tfrequencyMoisture = 1.0;\n\t\t\t\t} else if (value > 1346 && value <= 1351){\n\t\t\t\t\tfrequencyMoisture = 1.1;\n\t\t\t\t} else if (value > 1341 && value <= 1346){\n\t\t\t\t\tfrequencyMoisture = 1.2;\n\t\t\t\t} else {\n\t\t\t\t\tfrequencyMoisture = \"Wet\";\n\t\t\t\t}\n\t\t\t\tdecoded.input1_frequency_to_moisture = frequencyMoisture;\n\t\t\t\tdecoded.input1_frequency = value;\n\t\t\t\ti += 2;\n }\n else if (key_1 == 0x02 && key_2 == 0x02) {\n var voltageValue = parseBytesToInt(input, i, 2) * 0.001;\n\t\t\t\tvar voltageTempOutput = -32.46 * Math.log(voltageValue * 1000) + 236.36;\n\t\t\t\tdecoded.input2_voltage_to_temp = roundUsingMathRound(voltageTempOutput, 1);\n\t\t\t\tdecoded.input2_voltage = voltageValue;\n\t\t\t\ti += 2;\n }\n else if (key1 == 0x03 && key2 == 0x02) {\n var input3Voltage = parseBytesToInt(input, i, 2) * 0.001;\n \n decoded.input3_voltage = input3Voltage;\n\t\t\t\tdecoded.input3_voltage_to_temp = roundUsingMathRound((-33.01 * Math.pow(input3Voltage, 5)) + (217.4 * Math.pow(input3Voltage, 4)) + (-538.6 * Math.pow(input3Voltage, 3)) + (628.1 * Math.pow(input3Voltage, 2)) + (-378.9 * input3Voltage) + 102.9, 1);\n \n i += 2;\n }\n else if (key1 == 0x03 && key2 == 0x67) {\n decoded.input3_temperature = parseBytesToInt(input, i, 2) * 0.1;\n\t\t\t\ti += 2;\n }\n else if (key1 == 0x04 && key2 == 0x02) {\n var input4Voltage = parseBytesToInt(input, i, 2) * 0.001;\n \n decoded.input4_voltage = input4Voltage;\n\t\t\t\tdecodedinput4_voltage_to_temp = roundUsingMathRound((-33.01 * Math.pow(input4Voltage, 5)) + (217.4 * Math.pow(input4Voltage, 4)) + (-538.6 * Math.pow(input4Voltage, 3)) + (628.1 * Math.pow(input4Voltage, 2)) + (-378.9 * input4Voltage) + 102.9, 1);\n \n i += 2;\n }\n else if (key1 == 0x04 && key2 == 0x67) {\n decoded.input4_temperature = parseBytesToInt(input, i, 2) * 0.1;\n\t\t\t\ti += 2;\n }\n else if (key1 == 0x05 && key2 == 0x04) {\n var watermark1Frequency = parseBytesToInt(input, i, 2);\n\t\t\t\t\n\t\t\t\tvar decodedWatermarkData1 = getWatermarkData(watermark1Frequency);\t\n\t\t\t\tdecoded.watermark1_tension = decodedWatermarkData1.watermarkTension;\n\t\t\t\tdecoded.watermark1_frequency = decodedWatermarkData1.watermarkFrequency;\n\t\t\t\t\n\t\t\t\ti += 2;\n }\n else if (key1 == 0x06 && key2 == 0x04) {\n var watermark2Frequency = parseBytesToInt(input, i, 2);\n\t\t\t\t\n\t\t\t\tvar decodedWatermarkData2 = getWatermarkData(watermark2Frequency);\t\n\t\t\t\tdecoded.watermark2_tension = decodedWatermarkData2.watermarkTension;\n\t\t\t\tdecoded.watermark2_frequency = decodedWatermarkData2.watermarkFrequency;\n\t\t\t\t\n\t\t\t\ti += 2;\n }\n else if (key1 == 0x09 && key2 == 0x65) {\n var lightIntensity = parseBytesToInt(input, i, 2);\n\t\t\t\t\n\t\t\t\tdecoded.light_intensity = lightIntensity; \n\t\t\t\ti += 2;\n }\n else if (key1 == 0x09 && key2 == 0x00) {\n var lightDetected = parseBytesToInt(input, i, 1);\n\t\t\t\tdecoded.light_detected = getAlarmStatus(lightDetected);\n\t\t\t\t\n\t\t\t\ti += 1;\n }\n else if (key1 == 0x0A && key2 == 0x71) {\n decoded.accelerationX = parseBytesToInt(input, i, 2);\n decoded.accelerationY = parseBytesToInt(input, i + 2, 2);\n decoded.accelerationZ = parseBytesToInt(input, i + 4, 2);\n }\n else if (key1 == 0x0A && key2 == 0x00) {\n var orientationAlarm = parseBytesToInt(input, i, 1);\n decoded.orientation_alarm = getAlarmStatus(orientationAlarm);\n\t\t\t\t\n\t\t\t\ti += 1;\n }\n else if (key1 == 0x0B && key2 == 0x67) {\n decoded.ambient_temperature = parseBytesToInt(input, i, 2) * 0.1;\n i += 2;\n }\n else if (key1 == 0x0B && key2 == 0x68) {\n decoded.relative_humidity = parseBytesToInt(input, i, 1) * 0.5;\n i += 1;\n }\n else if (key1 == 0x0C && key2 == 0x67) {\n decoded.mcu_temperature = parseBytesToInt(input, i, 2) * 0.1;\n i += 2;\n }\n else if (key1 == 0x0D && key2 == 0x73) {\n decoded.RFU_2 = parseBytesToInt(input, i, 1) * 0.1;\n i += 1;\n }\n }\n }\n else if (fPort == 100) {\n for(var i = 0; i < input.length -1; ) {\n var key = input[i++] & 0xff;\n \n if(key == 0x10) {\n var val = (((input[i] << 8) | input[i + 1]) >> 15) & 1;\n switch (val){\n\t\t\t\t\tcase 0:\n\t\t\t\t\t\toutput.attributes.loramac_join_mode = \"ABP\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 1:\n\t\t\t\t\t\toutput.attributes.loramac_join_mode = \"OTAA\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\toutput.attributes.loramac_join_mode = \"Invalid\";\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\ti += 1;\n }\n else if (key == 0x11) {\n var val = (((input[i] << 8) | input[i + 1]) >> 12) & 0xF;\n switch (val) {\n\t\t\t\t\tcase 0:\n\t\t\t\t\t\toutput.attributes.deviceClassEnabled = \"Class A\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 12:\n\t\t\t\t\t\toutput.attributes.deviceClassEnabled = \"Class C\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\toutput.attributes.deviceClassEnabled = \"Invalid\";\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tvar val = (((input[i] << 8) | input[i + 1]) >> 3) & 1;\n\t\t\t\toutput.attributes.adr = getEnableStatus(val);\n\t\t\t\t\n\t\t\t\tvar val = (((input[i] << 8) | input[i + 1]) >> 2) & 1;\n\t\t\t\toutput.attributes.duty_cycle = getEnableStatus(val);\n\t\t\t\t\n\t\t\t\tvar val = (((input[i] << 8) | input[i + 1]) >> 1) & 1;\n\t\t\t\t\n\t\t\t\tswitch (val) {\n\t\t\t\t\tcase 0:\n\t\t\t\t\t\toutput.attributes.sync_word = \"Private\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 1:\n\t\t\t\t\t\toutput.attributes.sync_word = \"Public\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\toutput.attributes.sync_word = \"Invalid\";\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tvar val = ((input[i] << 8) | input[i + 1]) & 1;\n\t\t\t\t\n\t\t\t\tswitch (val){\n\t\t\t\t\tcase 0:\n\t\t\t\t\t\toutput.attributes.confirm_mode = \"Unconfirmed\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 1:\n\t\t\t\t\t\toutput.attributes.confirm_mode = \"Confirmed\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t output.attributes.confirm_mode = \"Invalid\";\n\t\t\t\t}\n\t\t\t\ti += 2;\n }\n else if (key == 0x12) {\n output.attributes.dr_number = (((input[i] << 8) | input[i + 1]) >> 8) & 0xF;\n output.attributes.tx_power_number = ((input[i] << 8) | input[i + 1]) & 0xF;\n \n i +=2;\n }\n else if (key == 0x13) {\n output.attributes.frequency = (((input[i] << 32) | (input[i + 1] << 24) | (input[i + 2] << 16) | (input[i + 3] << 8) | input[i + 4]) >> 8) & 0xFFFFFFFF;\n output.attributes.dr_number_rx2 = input[i + 4] & 0xFF;\n \n i += 5;\n }\n else if (key == 0x20) {\n output.attributes.seconds_per_core_tick = parseBytesToInt(input, i, 4);\n i += 4;\n }\n else if(key == 0x21) {\n output.attributes.tick_per_battery = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x22) {\n output.attributes.tick_per_ambient_temperature = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x23) {\n output.attributes.tick_per_relative_humidity = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x24) {\n output.attributes.tick_per_light = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x25) {\n output.attributes.tick_per_input1 = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x26) {\n output.attributes.tick_per_input2 = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x27) {\n output.attributes.tick_per_input3 = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x28) {\n output.attributes.tick_per_input4 = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x29) {\n output.attributes.tick_per_watermark1 = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x2A) {\n output.attributes.tick_per_watermark2 = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x2C) {\n output.attributes.tick_per_accelerometer = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x2D) {\n output.attributes.tick_per_orientation_alarm = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x2E) {\n output.attributes.tick_per_mcu_temperature = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x2F) {\n output.attributes.RFU_1 = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x30) {\n output.attributes.temperature_relative_humidity_idle = parseBytesToInt(input, i, 4);\n i += 4;\n }\n else if(key == 0x31) {\n output.attributes.temperature_relative_humidity_active = parseBytesToInt(input, i, 4);\n i += 4;\n }\n else if(key == 0x32) {\n output.attributes.high_ambient_temp_raw = (((input[i] << 8) | input[i + 1]) >> 8) & 0xFF;\n output.attributes.low_ambient_temp_raw = ((input[i] << 8) | input[i + 1]) & 0xFF;\n \n i += 2;\n }\n else if(key == 0x33) {\n var val = input[i] & 1;\n output.attributes.ambient_temperature_threshold_enabled = getEnableStatus(val);\n\t\t\t\t\n\t\t\t\ti += 1;\n }\n else if (key == 0x34) {\n output.attributes.high_rh = input[i];\n\t\t\t\toutput.attributes.low_rh = input[i + 1];\n\t\t\t\t\n\t\t\t\ti += 2;\n }\n else if (key == 0x35) {\n var val = input[i] & 1;\n output.attributes.relative_humidity_threshold_enabled = getEnableStatus(val);\n\t\t\t\t\n\t\t\t\ti += 1;\n }\n else if (key == 0x36) {\n output.attributes.input_sample_period_idle = parseBytesToInt(input, i, 4);\n i += 4;\n }\n else if (key == 0x37) {\n output.attributes.input_sample_period_active = parseBytesToInt(input, i, 4);\n i += 4;\n }\n else if (key == 0x38) {\n output.attributes.low_input1 = parseBytesToInt(input, i, 2);\n output.attributes.high_input1 = parseBytesToInt(input, i + 2, 2);\n \n i += 4;\n }\n else if (key == 0x39) {\n output.attributes.low_input2 = parseBytesToInt(input, i, 2);\n output.attributes.high_input2 = parseBytesToInt(input, i + 2, 2);\n \n i += 4;\n }\n else if (key == 0x3A) {\n output.attributes.low_input3 = parseBytesToInt(input, i, 2);\n output.attributes.high_input3 = parseBytesToInt(input, i + 2, 2);\n \n i += 4;\n }\n else if (key == 0x3B) {\n output.attributes.low_input4 = parseBytesToInt(input, i, 2);\n output.attributes.high_input4 = parseBytesToInt(input, i + 2, 2);\n \n i += 4;\n }\n else if (key == 0x3C) {\n output.attributes.low_watermark1 = parseBytesToInt(input, i, 2);\n output.attributes.high_watermark1 = parseBytesToInt(input, i + 2, 2);\n \n i += 4;\n }\n else if (key == 0x3D) {\n output.attributes.low_watermark2 = parseBytesToInt(input, i, 2);\n output.attributes.high_watermark2 = parseBytesToInt(input, i + 2, 2);\n \n i += 4;\n }\n else if (key == 0x3F) {\n var input_status = input[i] & 0x3F;\n \n var bit0 = (input_status >> 0) & 1;\n output.attributes.input_enable_input1 = getEnableStatus(bit0);\n \n var bit1 = (input_status >> 1) & 1;\n output.attributes.input_enable_input2 = getEnableStatus(bit1);\n \n var bit2 = (input_status >> 2) & 1;\n output.attributes.input_enable_input3 = getEnableStatus(bit2);\n \n var bit3 = (input_status >> 3) & 1;\n output.attributes.input_enable_input4 = getEnableStatus(bit3);\n \n var bit4 = (input_status >> 4) & 1;\n output.attributes.input_enable_watermark1_enable = getEnableStatus(bit4);\n \n var bit5 = (input_status >> 5) & 1;\n output.attributes.input_enable_watermark2_enable = getEnableStatus(bit5);\n \n i += 1;\n }\n else if (key == 0x40) {\n output.attributes.mcu_temperature_sample_period_idle = parseBytesToInt(input, i, 4);\n i += 4;\n }\n else if (key == 0x41) {\n output.attributes.mcu_temperature_sample_period_active = parseBytesToInt(input, i, 4);\n i += 4;\n }\n else if (key == 0x42) {\n output.attributes.high_mcu_temp = input[i + 1];\n output.attributes.low_mcu_temp = input[i];\n i += 4;\n }\n else if (key == 0x43) {\n var val = input[i] & 1;\n output.attributes.mcu_temperature_enable = getEnableStatus(val);\n\n\t\t\t\ti += 2;\n }\n else if (key == 0x44) {\n output.attributes.low_input3_onewire = parseBytesToInt(input, i, 2);\n output.attributes.high_input3_onewire = parseBytesToInt(input, i + 2, 2);\n i += 2;\n }\n else if (key == 0x45) {\n output.attributes.low_input4_onewire = parseBytesToInt(input, i, 2);\n output.attributes.high_input4_onewire = parseBytesToInt(input, i + 2, 2);\n i += 2;\n }\n else if (key == 0x48 ) {\n var val = input[i] & 1;\n output.attributes.ALS_interrupt_enabled = getEnableStatus(val);\n \n i += 1;\n }\n else if (key == 0x49) {\n output.attributes.ALS_upper_threshold = parseBytesToInt(input, i, 2);\n i +=2;\n }\n else if (key == 0x4A) {\n output.attributes.ALS_lower_threshold = parseBytesToInt(input, i, 2);\n i +=2;\n }\n else if (key == 0x4B) {\n output.attributes.light_sample_period_idle = parseBytesToInt(input, i, 4);\n i +=4;\n }\n else if (key == 0x4C) {\n output.attributes.light_sample_period_active = parseBytesToInt(input, i, 4);\n i +=4;\n }\n else if (key == 0x4D) {\n var status = input[i] & 0x03;\n \n var bit1 = status & 1;\n output.attributes.light_alarm_reported = getReportStatus(bit1);\n \n var bit2 = (status >> 1) & 1;\n output.attributes.light_intensity_reported = getReportStatus(bit2);\n \n i += 1;\n }\n else if (key == 0x50) {\n output.attributes.orientation_alarm_threshold = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x51) {\n var status = input[i];\n\n var bit5 = (status >> 5) & 1;\n output.attributes.orientation_vector_report = getReportStatus(bit5);\n \n var bit0 = status & 1; \n output.attributes.orientation_alarm_report = getReportStatus(bit0);\n \n i += 1;\n }\n else if (key == 0x52) {\n var status = input[i]; \n \n var bit7 = (status >> 7) & 1; \n var bit0 = status & 1; \n \n switch (bit7) {\n case 0:\n output.attributes.accelerometer_power_on = \"Off\";\n break;\n case 1:\n output.attributes.accelerometer_power_on = \"On\";\n break;\n default:\n output.attributes.accelerometer_power_on = \"Invalid\";\n }\n \n output.attributes.orientation_alarm_mode = getEnableStatus(bit0);\n \n i += 1;\n }\n else if (key == 0x61) {\n var status = input[i]; \n \n var bit1 = (status >> 1) & 1;\n output.attributes.report_capacity_enabled = getEnableStatus(bit1);\n \n var bit2 = (status >> 2) & 1;\n output.attributes.report_lifetime_enabled = getEnableStatus(bit2);\n \n i += 1;\n }\n else if (key == 0x62) {\n output.attributes.avg_current_window = parseBytesToInt(input, i, 1);\n i += 1;\n }\n else if (key == 0x71) {\n output.attributes.app_major_version = input[i + 6];\n\t\t\t\toutput.attributes.app_minor_version = input[i + 5];\n\t\t\t\toutput.attributes.app_revision = input[i + 4];\n\t\t\t\toutput.attributes.loramac_major_version = input[i + 3];\n\t\t\t\toutput.attributes.loramac_minor_version = input[i + 2];\n\t\t\t\toutput.attributes.loramac_revision = input[i + 1];\n\t\t\t\tvar val = input[i];\n\t\t\t\tswitch (val){\n\t\t\t\t\tcase 0:\n\t\t\t\t\t\toutput.attributes.region = \"EU868\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 1:\n\t\t\t\t\t\toutput.attributes.region = \"US915\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 2:\n\t\t\t\t\t\toutput.attributes.region = \"AS923\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 3:\n\t\t\t\t\t\toutput.attributes.region = \"AU915\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 4:\n\t\t\t\t\t\toutput.attributes.region = \"IN865\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 6:\n\t\t\t\t\t\toutput.attributes.region = \"KR920\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 7:\n\t\t\t\t\t\toutput.attributes.region = \"RU864\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\toutput.attributes.region = \"Invalid\";\n\t\t\t\t}\n\t\t\t\ti += 7;\n }\n }\n }\n else if (fPort == 101) {\n var size = input.length;\n var responses = [];\n \n var index = 0;\n while (index < size) {\n var downlinkFcnt = input[index++] & 0xFF; \n var numInvalidWrites = input[index++] & 0xFF; \n \n if (numInvalidWrites > 0) {\n var invalidRegisters = [];\n for (var i = 0; i < numInvalidWrites; i++) {\n invalidRegisters.add(String.format(\"0x%02X\", input[index + i]));\n }\n index += numInvalidWrites;\n \n responses.add(String.format(\n \"%d Invalid write command(s) from DL:%d for register(s): %s\",\n numInvalidWrites, downlinkFcnt, String.join(\", \", invalidRegisters)\n ));\n } else {\n responses.add(String.format(\"All write commands from DL:%d were successful\", downlinkFcnt));\n }\n }\n \n decoded.response = responses;\n }\n \n output.telemetry = [{\n ts: timestamp,\n values: decoded\n }];\n\n // --- Decoding code --- //\n return output;\n}\n\n// --- attributes and telemetry objects ---\nvar telemetry = [];\nvar attributes = {};\n// --- attributes and telemetry objects ---\n\n// --- Timestamp parsing\ntimestamp = data.ts;\n// --- Timestamp parsing\n\n// Message parsing\n// To avoid paths in the decoded objects we passing false value to function as \"pathInKey\" argument.\n// Warning: pathInKey can cause already found fields to be overwritten with the last value found.\n\nvar uplinkDataList = [];\n\n// Passing incoming bytes to decodePayload function, to get custom decoding\nvar customDecoding = decodePayload(hexToBytes(data.data));\n\n// Collecting data to result\nif (customDecoding.?telemetry.size() > 0) {\n if (customDecoding.telemetry instanceof java.util.ArrayList) {\n foreach(telemetryObj: customDecoding.telemetry) {\n if (telemetryObj.ts != null && telemetryObj.values != null) {\n telemetry.add(telemetryObj);\n }\n }\n } else {\n telemetry.putAll(customDecoding.telemetry);\n }\n}\n\nif (customDecoding.?attributes.size() > 0) {\n attributes.putAll(customDecoding.attributes);\n}\n\n// You can add some keys manually to attributes or telemetry\nattributes.eui = data.EUI;\nattributes.fPort = data.port;\nattributes.frequency = data.freq;\n\nvar isIncludeGatewayInfo = metadata[\"includeGatewayInfo\"];\nif(isIncludeGatewayInfo == true) {\n var addDataToTelemetry = {};\n addDataToTelemetry.rssi = data.rssi;\n addDataToTelemetry.seqno = data.seqno;\n addDataToTelemetry.snr = data.snr;\n addDataToTelemetry.ack = data.ack;\n addDataToTelemetry.toa = data.toa;\n addDataToTelemetry.fCnt = data.fcnt;\n \n telemetry = processTelemetryData(telemetry, addDataToTelemetry);\n}\n\nvar deviceInfo = {\n deviceName: deviceName,\n deviceType: deviceType,\n// assetName: assetName,\n// assetType: assetType,\n attributes: attributes,\n telemetry: telemetry, \n};\n\naddAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName);\n\nuplinkDataList.add(deviceInfo);\n\nvar gatewayDeviceNamePrefix = \"Gateway \";\nvar gatewayDeviceType = \"Lora gateway\";\nvar gatewayGroupName = null; // If gatewayGroupName is not null - created device will be added to the entity group with such name.\n\nif (data.cmd == \"gw\") {\n foreach( gatewayInfo : data.gws ) {\n var addGatewayInfo = {};\n\n // You can add some keys manually telemetry\n addGatewayInfo.rssi = gatewayInfo.rssi;\n addGatewayInfo.snr = gatewayInfo.snr;\n // You can add some keys manually telemetry\n \n var gatewayInfoMsg = {\n deviceName: gatewayDeviceNamePrefix + gatewayInfo.gweui,\n deviceType: gatewayDeviceType,\n telemetry: [{\n \"ts\": gatewayInfo.ts,\n \"values\": addGatewayInfo\n }],\n attributes: {\n eui: gatewayInfo.gweui\n }\n };\n addAdditionalInfoForDeviceMsg(gatewayInfoMsg, customerName, gatewayGroupName);\n uplinkDataList.add(gatewayInfoMsg);\n }\n}\n\nreturn uplinkDataList;\n\nfunction addAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName) {\n if (customerName != null) {\n deviceInfo.customerName = customerName;\n }\n if (groupName != null) {\n deviceInfo.groupName = groupName;\n }\n}\n\nfunction processTelemetryData(telemetry, addDataToTelemetry) {\n if (telemetry.size >= 1) {\n telemetry = addDataToTelemetries(telemetry, addDataToTelemetry);\n }\n else {\n telemetry.add(addDataToTelemetry);\n }\n \n return telemetry;\n}\n\nfunction addDataToTelemetries(telemetries, addDataToTelemetry) {\n foreach(telemetry : telemetries) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[\"values\"].keys.contains(element.key)) {\n telemetry[\"values\"][element.key] = element.value;\n }\n } \n }\n \n return telemetries;\n}\n\nfunction getWatermarkData(watermarkFrequency) {\n var decodedWatermark = {};\n \n var watermarkTension = 0;\n if (watermarkFrequency > 6430){\n\t\twatermarkTension = 0;\n\t} else if (watermarkFrequency >= 4330 && watermarkFrequency <= 6430){\n\t watermarkTension = 9.000 - (watermarkFrequency - 4330.000) * 0.004286;\n\t} else if (watermarkFrequency >= 2820 && watermarkFrequency < 4330){\n\t\twatermarkTension = 15.000 - (watermarkFrequency - 2820.000) * 0.003974;\n\t} else if (watermarkFrequency >= 1110 && watermarkFrequency < 2820){\n\t\twatermarkTension = 35.000 - (watermarkFrequency - 1110.000) * 0.01170;\n\t} else if (watermarkFrequency >= 770 && watermarkFrequency < 1110){\n\t\twatermarkTension = 55.000 - (watermarkFrequency - 770.000) * 0.05884;\n\t} else if (watermarkFrequency >= 600 && watermarkFrequency < 770){\n\t\twatermarkTension = 75.000 - (watermarkFrequency - 600.000) * 0.1176;\n\t} else if (watermarkFrequency >= 485 && watermarkFrequency < 600){\n\t\twatermarkTension = 100.000 - (watermarkFrequency - 485.000) * 0.2174;\n } else if (watermarkFrequency >= 293 && watermarkFrequency < 485){\n\t\twatermarkTension = 200.000 - (watermarkFrequency - 293.000) * 0.5208;\n\t} else {\n\t watermarkTension = 200;\n\t}\t\t\t\t\t\n\tdecodedWatermark.watermarkTension = roundUsingMathRound(watermarkTension, 0);\n\tdecodedWatermark.watermarkFrequency = watermarkFrequency;\n\t\t\t\t\n return decodedWatermark;\n}\n\nfunction roundUsingMathRound(value, places) {\n if (places >= 0) {\n var factor = Math.pow(10, places);\n return Math.round(value * factor) / factor; \n }\n \n return value;\n}\n\nfunction getAlarmStatus(bit) {\n var alarmResult = \"Invalid\";\n \n if (bit === 0) {\n alarmResult = \"No Alarm\";\n } else if (bit === 1 || bit === 255) {\n alarmResult = \"Alarm\";\n } else {\n alarmResult = \"Invalid\";\n }\n \n return alarmResult;\n}\n\nfunction getEnableStatus(bit) {\n var enableResult = \"Invalid\";\n \n switch (bit) {\n\t\tcase 0:\n\t\t enableResult = \"Disable\";\n\t\t\tbreak;\n\t\tcase 1:\n\t\t\tenableResult = \"Enable\";\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tenableResult = \"Invalid\";\n\t}\n \n return enableResult;\n}\n\nfunction getReportStatus(bit) {\n var reportResult = \"Invalid\";\n \n switch (bit5) {\n case 0:\n reportResult = \"Ignore\";\n break;\n case 1:\n reportResult = \"Report\";\n break;\n default:\n reportResult = \"Invalid\";\n }\n \n return reportResult;\n}", + "encoder": null, + "tbelEncoder": null, + "updateOnlyKeys": [ + "fPort", + "ack", + "eui", + "frequency", + "dr", + "battery" + ] + }, + "additionalInfo": { + "description": "" + }, + "edgeTemplate": false +} \ No newline at end of file diff --git a/VENDORS/Tektelic/Kiwi/LORIOT/uplink/metadata.json b/VENDORS/Tektelic/Kiwi/LORIOT/uplink/metadata.json new file mode 100644 index 00000000..ae2ee743 --- /dev/null +++ b/VENDORS/Tektelic/Kiwi/LORIOT/uplink/metadata.json @@ -0,0 +1,4 @@ +{ + "integrationName": "Loriot integration", + "includeGatewayInfo": "false" +} \ No newline at end of file diff --git a/VENDORS/Tektelic/Kiwi/LORIOT/uplink/payload.json b/VENDORS/Tektelic/Kiwi/LORIOT/uplink/payload.json new file mode 100644 index 00000000..9840ad99 --- /dev/null +++ b/VENDORS/Tektelic/Kiwi/LORIOT/uplink/payload.json @@ -0,0 +1,17 @@ +{ + "cmd": "rx", + "seqno": 3040, + "EUI": "1000000000000001", + "ts": 1684478801936, + "fcnt": 2, + "port": 10, + "freq": 867500000, + "rssi": -21, + "snr": 10, + "toa": 206, + "dr": "SF9 BW125 4/5", + "ack": false, + "bat": 94, + "offline": false, + "data": "00d35a00bd0a0a" +} \ No newline at end of file diff --git a/VENDORS/Tektelic/Kiwi/LORIOT/uplink/payload_1.json b/VENDORS/Tektelic/Kiwi/LORIOT/uplink/payload_1.json new file mode 100644 index 00000000..c93999c7 --- /dev/null +++ b/VENDORS/Tektelic/Kiwi/LORIOT/uplink/payload_1.json @@ -0,0 +1,17 @@ +{ + "cmd": "rx", + "seqno": 3040, + "EUI": "1000000000000001", + "ts": 1684478801936, + "fcnt": 2, + "port": 10, + "freq": 867500000, + "rssi": -21, + "snr": 10, + "toa": 206, + "dr": "SF9 BW125 4/5", + "ack": false, + "bat": 94, + "offline": false, + "data": "01040579020202d5" +} \ No newline at end of file diff --git a/VENDORS/Tektelic/Kiwi/LORIOT/uplink/result.json b/VENDORS/Tektelic/Kiwi/LORIOT/uplink/result.json new file mode 100644 index 00000000..056eefaf --- /dev/null +++ b/VENDORS/Tektelic/Kiwi/LORIOT/uplink/result.json @@ -0,0 +1,16 @@ +[{ + "deviceName": "1000000000000001", + "deviceType": "Kiwi", + "attributes": { + "eui": "1000000000000001", + "fPort": 10, + "frequency": 867500000 + }, + "telemetry": [{ + "ts": 1684478801936, + "values": { + "rem_batt_capacity": 90, + "rem_batt_days": 2570 + } + }] +}] \ No newline at end of file diff --git a/VENDORS/Tektelic/Kiwi/LORIOT/uplink/result_1.json b/VENDORS/Tektelic/Kiwi/LORIOT/uplink/result_1.json new file mode 100644 index 00000000..9f966858 --- /dev/null +++ b/VENDORS/Tektelic/Kiwi/LORIOT/uplink/result_1.json @@ -0,0 +1,18 @@ +[{ + "deviceName": "1000000000000001", + "deviceType": "Kiwi", + "attributes": { + "eui": "1000000000000001", + "fPort": 10, + "frequency": 867500000 + }, + "telemetry": [{ + "ts": 1684478801936, + "values": { + "input1_frequency_to_moisture": "Dry", + "input1_frequency": 1401, + "input2_voltage_to_temp": 22.6, + "input2_voltage": 0.725 + } + }] +}] \ No newline at end of file diff --git a/VENDORS/Tektelic/Kiwi/ThingsStackCommunity/uplink/converter.json b/VENDORS/Tektelic/Kiwi/ThingsStackCommunity/uplink/converter.json new file mode 100644 index 00000000..7a47c75e --- /dev/null +++ b/VENDORS/Tektelic/Kiwi/ThingsStackCommunity/uplink/converter.json @@ -0,0 +1,39 @@ +{ + "name": "The Things Stack Community Uplink Decoder for Kiwi", + "type": "UPLINK", + "debugMode": false, + "debugSettings": { + "failuresEnabled": true, + "allEnabled": false, + "allEnabledUntil": 1733331880270 + }, + "configuration": { + "scriptLang": "TBEL", + "decoder": null, + "tbelDecoder": "var data = decodeToJson(payload);\n\nvar deviceName = data.end_device_ids.device_id;\nvar deviceType = \"Kiwi\";\nvar groupName = null; // If groupName is not null - created device will be added to the entity group with such name.\nvar customerName = null; // If customerName is not null - created devices will be assigned to customer with such name. \n\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// If you want to parse incoming data somehow, you can add your code to this function.\n// input: bytes\n// expected output:\n// {\n// \"attributes\": {\"attributeKey\": \"attributeValue\"},\n// \"telemetry\": [{\"ts\": 1...1, \"values\": {\"telemetryKey\":\"telemetryValue\"}, {\"ts\": 1...2, \"values\": {\"telemetryKey\":\"telemetryValue\"}}]\n// }\n\nfunction decodeFrmPayload(input) {\n var output = {\n attributes: {}, telemetry: {}\n };\n \n // --- Decoding code --- //\n var decoded = {};\n var fPort = data.uplink_message.f_port;\n if(fPort == 10) {\n for(var i = 0; i < input.length - 2; ) {\n var key_1 = input[i++] & 0xff;\n var key_2 = input[i++] & 0xff;\n \n if(key_1 == 0x00 && key_2 == 0xBA) {\n var val = (input[i] >> 7) & 1; \n\n decoded.eos_alert = getAlarmStatus(val);\n var battery_bits = input[i] & 0x7F;\n decoded.battery_voltage = roundUsingMathRound(battery_bits * 0.01 + 2.5, 2);\n i += 1;\n }\n else if(key_1 == 0x00 && key_2 == 0xD3) {\n decoded.rem_batt_capacity = parseBytesToInt(input, i, 1);\n i += 1;\n }\n else if(key_1 == 0x00 && key_2 == 0xBD) {\n decoded.rem_batt_days = parseBytesToInt(input, i, 2);\n\t\t\t\ti += 2;\n }\n else if(key_1 == 0x01 && key_2 == 0x04) {\n var value = parseBytesToInt(input, i, 2);\n var frequencyMoisture = 0;\n\t\t\t\tif (value > 1399){\n\t\t\t\t\tfrequencyMoisture = \"Dry\";\n\t\t\t\t} else if (value > 1396 && value <= 1399){\n\t\t\t\t\tfrequencyMoisture = 0.1;\n\t\t\t\t} else if (value > 1391 && value <= 1396){\n\t\t\t\t\tfrequencyMoisture = 0.2;\n\t\t\t\t} else if (value > 1386 && value <= 1391){\n\t\t\t\t\tfrequencyMoisture = 0.3;\n\t\t\t\t} else if (value > 1381 && value <= 1386){\n\t\t\t\t\tfrequencyMoisture = 0.4;\n\t\t\t\t} else if (value > 1376 && value <= 1381){\n\t\t\t\t\tfrequencyMoisture = 0.5;\n\t\t\t\t} else if (value > 1371 && value <= 1376){\n\t\t\t\t\tfrequencyMoisture = 0.6;\n\t\t\t\t} else if (value > 1366 && value <= 1371){\n\t\t\t\t\tfrequencyMoisture = 0.7;\n\t\t\t\t} else if (value > 1361 && value <= 1366){\n\t\t\t\t\tfrequencyMoisture = 0.8;\n\t\t\t\t} else if (value > 1356 && value <= 1361){\n\t\t\t\t\tfrequencyMoisture = 0.9;\n\t\t\t\t} else if (value > 1351 && value <= 1356){\n\t\t\t\t\tfrequencyMoisture = 1.0;\n\t\t\t\t} else if (value > 1346 && value <= 1351){\n\t\t\t\t\tfrequencyMoisture = 1.1;\n\t\t\t\t} else if (value > 1341 && value <= 1346){\n\t\t\t\t\tfrequencyMoisture = 1.2;\n\t\t\t\t} else {\n\t\t\t\t\tfrequencyMoisture = \"Wet\";\n\t\t\t\t}\n\t\t\t\tdecoded.input1_frequency_to_moisture = frequencyMoisture;\n\t\t\t\tdecoded.input1_frequency = value;\n\t\t\t\ti += 2;\n }\n else if (key_1 == 0x02 && key_2 == 0x02) {\n var voltageValue = parseBytesToInt(input, i, 2) * 0.001;\n\t\t\t\tvar voltageTempOutput = -32.46 * Math.log(voltageValue * 1000) + 236.36;\n\t\t\t\tdecoded.input2_voltage_to_temp = roundUsingMathRound(voltageTempOutput, 1);\n\t\t\t\tdecoded.input2_voltage = voltageValue;\n\t\t\t\ti += 2;\n }\n else if (key1 == 0x03 && key2 == 0x02) {\n var input3Voltage = parseBytesToInt(input, i, 2) * 0.001;\n \n decoded.input3_voltage = input3Voltage;\n\t\t\t\tdecoded.input3_voltage_to_temp = roundUsingMathRound((-33.01 * Math.pow(input3Voltage, 5)) + (217.4 * Math.pow(input3Voltage, 4)) + (-538.6 * Math.pow(input3Voltage, 3)) + (628.1 * Math.pow(input3Voltage, 2)) + (-378.9 * input3Voltage) + 102.9, 1);\n \n i += 2;\n }\n else if (key1 == 0x03 && key2 == 0x67) {\n decoded.input3_temperature = parseBytesToInt(input, i, 2) * 0.1;\n\t\t\t\ti += 2;\n }\n else if (key1 == 0x04 && key2 == 0x02) {\n var input4Voltage = parseBytesToInt(input, i, 2) * 0.001;\n \n decoded.input4_voltage = input4Voltage;\n\t\t\t\tdecodedinput4_voltage_to_temp = roundUsingMathRound((-33.01 * Math.pow(input4Voltage, 5)) + (217.4 * Math.pow(input4Voltage, 4)) + (-538.6 * Math.pow(input4Voltage, 3)) + (628.1 * Math.pow(input4Voltage, 2)) + (-378.9 * input4Voltage) + 102.9, 1);\n \n i += 2;\n }\n else if (key1 == 0x04 && key2 == 0x67) {\n decoded.input4_temperature = parseBytesToInt(input, i, 2) * 0.1;\n\t\t\t\ti += 2;\n }\n else if (key1 == 0x05 && key2 == 0x04) {\n var watermark1Frequency = parseBytesToInt(input, i, 2);\n\t\t\t\t\n\t\t\t\tvar decodedWatermarkData1 = getWatermarkData(watermark1Frequency);\t\n\t\t\t\tdecoded.watermark1_tension = decodedWatermarkData1.watermarkTension;\n\t\t\t\tdecoded.watermark1_frequency = decodedWatermarkData1.watermarkFrequency;\n\t\t\t\t\n\t\t\t\ti += 2;\n }\n else if (key1 == 0x06 && key2 == 0x04) {\n var watermark2Frequency = parseBytesToInt(input, i, 2);\n\t\t\t\t\n\t\t\t\tvar decodedWatermarkData2 = getWatermarkData(watermark2Frequency);\t\n\t\t\t\tdecoded.watermark2_tension = decodedWatermarkData2.watermarkTension;\n\t\t\t\tdecoded.watermark2_frequency = decodedWatermarkData2.watermarkFrequency;\n\t\t\t\t\n\t\t\t\ti += 2;\n }\n else if (key1 == 0x09 && key2 == 0x65) {\n var lightIntensity = parseBytesToInt(input, i, 2);\n\t\t\t\t\n\t\t\t\tdecoded.light_intensity = lightIntensity; \n\t\t\t\ti += 2;\n }\n else if (key1 == 0x09 && key2 == 0x00) {\n var lightDetected = parseBytesToInt(input, i, 1);\n\t\t\t\tdecoded.light_detected = getAlarmStatus(lightDetected);\n\t\t\t\t\n\t\t\t\ti += 1;\n }\n else if (key1 == 0x0A && key2 == 0x71) {\n decoded.accelerationX = parseBytesToInt(input, i, 2);\n decoded.accelerationY = parseBytesToInt(input, i + 2, 2);\n decoded.accelerationZ = parseBytesToInt(input, i + 4, 2);\n }\n else if (key1 == 0x0A && key2 == 0x00) {\n var orientationAlarm = parseBytesToInt(input, i, 1);\n decoded.orientation_alarm = getAlarmStatus(orientationAlarm);\n\t\t\t\t\n\t\t\t\ti += 1;\n }\n else if (key1 == 0x0B && key2 == 0x67) {\n decoded.ambient_temperature = parseBytesToInt(input, i, 2) * 0.1;\n i += 2;\n }\n else if (key1 == 0x0B && key2 == 0x68) {\n decoded.relative_humidity = parseBytesToInt(input, i, 1) * 0.5;\n i += 1;\n }\n else if (key1 == 0x0C && key2 == 0x67) {\n decoded.mcu_temperature = parseBytesToInt(input, i, 2) * 0.1;\n i += 2;\n }\n else if (key1 == 0x0D && key2 == 0x73) {\n decoded.RFU_2 = parseBytesToInt(input, i, 1) * 0.1;\n i += 1;\n }\n }\n }\n else if (fPort == 100) {\n for(var i = 0; i < input.length -1; ) {\n var key = input[i++] & 0xff;\n \n if(key == 0x10) {\n var val = (((input[i] << 8) | input[i + 1]) >> 15) & 1;\n switch (val){\n\t\t\t\t\tcase 0:\n\t\t\t\t\t\toutput.attributes.loramac_join_mode = \"ABP\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 1:\n\t\t\t\t\t\toutput.attributes.loramac_join_mode = \"OTAA\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\toutput.attributes.loramac_join_mode = \"Invalid\";\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\ti += 1;\n }\n else if (key == 0x11) {\n var val = (((input[i] << 8) | input[i + 1]) >> 12) & 0xF;\n switch (val) {\n\t\t\t\t\tcase 0:\n\t\t\t\t\t\toutput.attributes.deviceClassEnabled = \"Class A\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 12:\n\t\t\t\t\t\toutput.attributes.deviceClassEnabled = \"Class C\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\toutput.attributes.deviceClassEnabled = \"Invalid\";\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tvar val = (((input[i] << 8) | input[i + 1]) >> 3) & 1;\n\t\t\t\toutput.attributes.adr = getEnableStatus(val);\n\t\t\t\t\n\t\t\t\tvar val = (((input[i] << 8) | input[i + 1]) >> 2) & 1;\n\t\t\t\toutput.attributes.duty_cycle = getEnableStatus(val);\n\t\t\t\t\n\t\t\t\tvar val = (((input[i] << 8) | input[i + 1]) >> 1) & 1;\n\t\t\t\t\n\t\t\t\tswitch (val) {\n\t\t\t\t\tcase 0:\n\t\t\t\t\t\toutput.attributes.sync_word = \"Private\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 1:\n\t\t\t\t\t\toutput.attributes.sync_word = \"Public\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\toutput.attributes.sync_word = \"Invalid\";\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tvar val = ((input[i] << 8) | input[i + 1]) & 1;\n\t\t\t\t\n\t\t\t\tswitch (val){\n\t\t\t\t\tcase 0:\n\t\t\t\t\t\toutput.attributes.confirm_mode = \"Unconfirmed\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 1:\n\t\t\t\t\t\toutput.attributes.confirm_mode = \"Confirmed\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t output.attributes.confirm_mode = \"Invalid\";\n\t\t\t\t}\n\t\t\t\ti += 2;\n }\n else if (key == 0x12) {\n output.attributes.dr_number = (((input[i] << 8) | input[i + 1]) >> 8) & 0xF;\n output.attributes.tx_power_number = ((input[i] << 8) | input[i + 1]) & 0xF;\n \n i +=2;\n }\n else if (key == 0x13) {\n output.attributes.frequency = (((input[i] << 32) | (input[i + 1] << 24) | (input[i + 2] << 16) | (input[i + 3] << 8) | input[i + 4]) >> 8) & 0xFFFFFFFF;\n output.attributes.dr_number_rx2 = input[i + 4] & 0xFF;\n \n i += 5;\n }\n else if (key == 0x20) {\n output.attributes.seconds_per_core_tick = parseBytesToInt(input, i, 4);\n i += 4;\n }\n else if(key == 0x21) {\n output.attributes.tick_per_battery = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x22) {\n output.attributes.tick_per_ambient_temperature = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x23) {\n output.attributes.tick_per_relative_humidity = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x24) {\n output.attributes.tick_per_light = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x25) {\n output.attributes.tick_per_input1 = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x26) {\n output.attributes.tick_per_input2 = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x27) {\n output.attributes.tick_per_input3 = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x28) {\n output.attributes.tick_per_input4 = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x29) {\n output.attributes.tick_per_watermark1 = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x2A) {\n output.attributes.tick_per_watermark2 = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x2C) {\n output.attributes.tick_per_accelerometer = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x2D) {\n output.attributes.tick_per_orientation_alarm = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x2E) {\n output.attributes.tick_per_mcu_temperature = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x2F) {\n output.attributes.RFU_1 = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x30) {\n output.attributes.temperature_relative_humidity_idle = parseBytesToInt(input, i, 4);\n i += 4;\n }\n else if(key == 0x31) {\n output.attributes.temperature_relative_humidity_active = parseBytesToInt(input, i, 4);\n i += 4;\n }\n else if(key == 0x32) {\n output.attributes.high_ambient_temp_raw = (((input[i] << 8) | input[i + 1]) >> 8) & 0xFF;\n output.attributes.low_ambient_temp_raw = ((input[i] << 8) | input[i + 1]) & 0xFF;\n \n i += 2;\n }\n else if(key == 0x33) {\n var val = input[i] & 1;\n output.attributes.ambient_temperature_threshold_enabled = getEnableStatus(val);\n\t\t\t\t\n\t\t\t\ti += 1;\n }\n else if (key == 0x34) {\n output.attributes.high_rh = input[i];\n\t\t\t\toutput.attributes.low_rh = input[i + 1];\n\t\t\t\t\n\t\t\t\ti += 2;\n }\n else if (key == 0x35) {\n var val = input[i] & 1;\n output.attributes.relative_humidity_threshold_enabled = getEnableStatus(val);\n\t\t\t\t\n\t\t\t\ti += 1;\n }\n else if (key == 0x36) {\n output.attributes.input_sample_period_idle = parseBytesToInt(input, i, 4);\n i += 4;\n }\n else if (key == 0x37) {\n output.attributes.input_sample_period_active = parseBytesToInt(input, i, 4);\n i += 4;\n }\n else if (key == 0x38) {\n output.attributes.low_input1 = parseBytesToInt(input, i, 2);\n output.attributes.high_input1 = parseBytesToInt(input, i + 2, 2);\n \n i += 4;\n }\n else if (key == 0x39) {\n output.attributes.low_input2 = parseBytesToInt(input, i, 2);\n output.attributes.high_input2 = parseBytesToInt(input, i + 2, 2);\n \n i += 4;\n }\n else if (key == 0x3A) {\n output.attributes.low_input3 = parseBytesToInt(input, i, 2);\n output.attributes.high_input3 = parseBytesToInt(input, i + 2, 2);\n \n i += 4;\n }\n else if (key == 0x3B) {\n output.attributes.low_input4 = parseBytesToInt(input, i, 2);\n output.attributes.high_input4 = parseBytesToInt(input, i + 2, 2);\n \n i += 4;\n }\n else if (key == 0x3C) {\n output.attributes.low_watermark1 = parseBytesToInt(input, i, 2);\n output.attributes.high_watermark1 = parseBytesToInt(input, i + 2, 2);\n \n i += 4;\n }\n else if (key == 0x3D) {\n output.attributes.low_watermark2 = parseBytesToInt(input, i, 2);\n output.attributes.high_watermark2 = parseBytesToInt(input, i + 2, 2);\n \n i += 4;\n }\n else if (key == 0x3F) {\n var input_status = input[i] & 0x3F;\n \n var bit0 = (input_status >> 0) & 1;\n output.attributes.input_enable_input1 = getEnableStatus(bit0);\n \n var bit1 = (input_status >> 1) & 1;\n output.attributes.input_enable_input2 = getEnableStatus(bit1);\n \n var bit2 = (input_status >> 2) & 1;\n output.attributes.input_enable_input3 = getEnableStatus(bit2);\n \n var bit3 = (input_status >> 3) & 1;\n output.attributes.input_enable_input4 = getEnableStatus(bit3);\n \n var bit4 = (input_status >> 4) & 1;\n output.attributes.input_enable_watermark1_enable = getEnableStatus(bit4);\n \n var bit5 = (input_status >> 5) & 1;\n output.attributes.input_enable_watermark2_enable = getEnableStatus(bit5);\n \n i += 1;\n }\n else if (key == 0x40) {\n output.attributes.mcu_temperature_sample_period_idle = parseBytesToInt(input, i, 4);\n i += 4;\n }\n else if (key == 0x41) {\n output.attributes.mcu_temperature_sample_period_active = parseBytesToInt(input, i, 4);\n i += 4;\n }\n else if (key == 0x42) {\n output.attributes.high_mcu_temp = input[i + 1];\n output.attributes.low_mcu_temp = input[i];\n i += 4;\n }\n else if (key == 0x43) {\n var val = input[i] & 1;\n output.attributes.mcu_temperature_enable = getEnableStatus(val);\n\n\t\t\t\ti += 2;\n }\n else if (key == 0x44) {\n output.attributes.low_input3_onewire = parseBytesToInt(input, i, 2);\n output.attributes.high_input3_onewire = parseBytesToInt(input, i + 2, 2);\n i += 2;\n }\n else if (key == 0x45) {\n output.attributes.low_input4_onewire = parseBytesToInt(input, i, 2);\n output.attributes.high_input4_onewire = parseBytesToInt(input, i + 2, 2);\n i += 2;\n }\n else if (key == 0x48 ) {\n var val = input[i] & 1;\n output.attributes.ALS_interrupt_enabled = getEnableStatus(val);\n \n i += 1;\n }\n else if (key == 0x49) {\n output.attributes.ALS_upper_threshold = parseBytesToInt(input, i, 2);\n i +=2;\n }\n else if (key == 0x4A) {\n output.attributes.ALS_lower_threshold = parseBytesToInt(input, i, 2);\n i +=2;\n }\n else if (key == 0x4B) {\n output.attributes.light_sample_period_idle = parseBytesToInt(input, i, 4);\n i +=4;\n }\n else if (key == 0x4C) {\n output.attributes.light_sample_period_active = parseBytesToInt(input, i, 4);\n i +=4;\n }\n else if (key == 0x4D) {\n var status = input[i] & 0x03;\n \n var bit1 = status & 1;\n output.attributes.light_alarm_reported = getReportStatus(bit1);\n \n var bit2 = (status >> 1) & 1;\n output.attributes.light_intensity_reported = getReportStatus(bit2);\n \n i += 1;\n }\n else if (key == 0x50) {\n output.attributes.orientation_alarm_threshold = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x51) {\n var status = input[i];\n\n var bit5 = (status >> 5) & 1;\n output.attributes.orientation_vector_report = getReportStatus(bit5);\n \n var bit0 = status & 1; \n output.attributes.orientation_alarm_report = getReportStatus(bit0);\n \n i += 1;\n }\n else if (key == 0x52) {\n var status = input[i]; \n \n var bit7 = (status >> 7) & 1; \n var bit0 = status & 1; \n \n switch (bit7) {\n case 0:\n output.attributes.accelerometer_power_on = \"Off\";\n break;\n case 1:\n output.attributes.accelerometer_power_on = \"On\";\n break;\n default:\n output.attributes.accelerometer_power_on = \"Invalid\";\n }\n \n output.attributes.orientation_alarm_mode = getEnableStatus(bit0);\n \n i += 1;\n }\n else if (key == 0x61) {\n var status = input[i]; \n \n var bit1 = (status >> 1) & 1;\n output.attributes.report_capacity_enabled = getEnableStatus(bit1);\n \n var bit2 = (status >> 2) & 1;\n output.attributes.report_lifetime_enabled = getEnableStatus(bit2);\n \n i += 1;\n }\n else if (key == 0x62) {\n output.attributes.avg_current_window = parseBytesToInt(input, i, 1);\n i += 1;\n }\n else if (key == 0x71) {\n output.attributes.app_major_version = input[i + 6];\n\t\t\t\toutput.attributes.app_minor_version = input[i + 5];\n\t\t\t\toutput.attributes.app_revision = input[i + 4];\n\t\t\t\toutput.attributes.loramac_major_version = input[i + 3];\n\t\t\t\toutput.attributes.loramac_minor_version = input[i + 2];\n\t\t\t\toutput.attributes.loramac_revision = input[i + 1];\n\t\t\t\tvar val = input[i];\n\t\t\t\tswitch (val){\n\t\t\t\t\tcase 0:\n\t\t\t\t\t\toutput.attributes.region = \"EU868\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 1:\n\t\t\t\t\t\toutput.attributes.region = \"US915\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 2:\n\t\t\t\t\t\toutput.attributes.region = \"AS923\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 3:\n\t\t\t\t\t\toutput.attributes.region = \"AU915\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 4:\n\t\t\t\t\t\toutput.attributes.region = \"IN865\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 6:\n\t\t\t\t\t\toutput.attributes.region = \"KR920\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 7:\n\t\t\t\t\t\toutput.attributes.region = \"RU864\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\toutput.attributes.region = \"Invalid\";\n\t\t\t\t}\n\t\t\t\ti += 7;\n }\n }\n }\n else if (fPort == 101) {\n var size = input.length;\n var responses = [];\n \n var index = 0;\n while (index < size) {\n var downlinkFcnt = input[index++] & 0xFF; \n var numInvalidWrites = input[index++] & 0xFF; \n \n if (numInvalidWrites > 0) {\n var invalidRegisters = [];\n for (var i = 0; i < numInvalidWrites; i++) {\n invalidRegisters.add(String.format(\"0x%02X\", input[index + i]));\n }\n index += numInvalidWrites;\n \n responses.add(String.format(\n \"%d Invalid write command(s) from DL:%d for register(s): %s\",\n numInvalidWrites, downlinkFcnt, String.join(\", \", invalidRegisters)\n ));\n } else {\n responses.add(String.format(\"All write commands from DL:%d were successful\", downlinkFcnt));\n }\n }\n \n decoded.response = responses;\n }\n \n output.telemetry = [{\n ts: timestamp,\n values: decoded\n }];\n \n // --- Decoding code --- //\n return output;\n}\n\n\n// --- attributes and telemetry objects ---\nvar telemetry = [];\nvar attributes = {};\n// --- attributes and telemetry objects ---\n\n// --- Timestamp parsing\nvar dateString = data.uplink_message.received_at;\n// If data is simulated or device doesn't send his own date string - we will use date from upcoming message, set by network server\nif ((data.simulated != null && data.simulated) || dateString == null) {\n dateString = data.received_at;\n}\ntimestamp = parseDateToTimestamp(dateString);\n// --- Timestamp parsing\n\n// Message parsing\n// To avoid paths in the decoded objects we passing false value to function as \"pathInKey\" argument.\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.\n\n// Passing incoming bytes to decodeFrmPayload function, to get custom decoding\nvar customDecoding = {};\nif (data.uplink_message.get(\"frm_payload\") != null) {\n customDecoding = decodeFrmPayload(base64ToBytes(data.uplink_message.frm_payload));\n}\n\n// Collecting data to result\nif (customDecoding.?telemetry.size() > 0) {\n if (customDecoding.telemetry instanceof java.util.ArrayList) {\n foreach(telemetryObj: customDecoding.telemetry) {\n if (telemetryObj.ts != null && telemetryObj.values != null) {\n telemetry.add(telemetryObj);\n }\n }\n } else {\n telemetry.putAll(customDecoding.telemetry);\n }\n}\n\nif (customDecoding.?attributes.size() > 0) {\n attributes.putAll(customDecoding.attributes);\n}\n\n// You can add some keys manually to attributes or telemetry\nvar applicationId = data.end_device_ids.?application_ids.?application_id;\nvar devAddr = data.end_device_ids.?dev_addr;\nvar spreadingFactor = data.uplink_message.?settings.?data_rate.?lora.?spreading_factor;\nvar codeRate = data.uplink_message.?settings.?data_rate.?lora.?coding_rate;\nvar tenantId = data.uplink_message.?network_ids.?tenant_id;\nattributes.eui = data.end_device_ids.dev_eui;\nattributes.fPort = data.uplink_message.f_port;\nattributes.applicationId = applicationId;\nattributes.devAddr = devAddr;\nattributes.spreadingFactor = spreadingFactor;\nattributes.codeRate = codeRate;\nattributes.tenantId = tenantId;\nattributes.device_id = data.end_device_ids.?device_id;\nattributes.join_eui = data.end_device_ids.?join_eui;\nattributes.net_id = data.uplink_message.?network_ids.?net_id;\nattributes.cluster_id = data.uplink_message.?network_ids.?cluster_id;\nattributes.cluster_adress = data.uplink_message.?network_ids.?cluster_address;\nattributes.bandwidth = data.uplink_message.?settings.?data_rate.?lora.?bandwidth;\nattributes.frequency = data.uplink_message.?settings.?frequency;\n\n\nvar gatewayInfo = getGatewayInfo();\nvar addDataToTelemetry = {};\naddDataToTelemetry.snr = gatewayInfo.snr;\naddDataToTelemetry.rssi = gatewayInfo.rssi;\naddDataToTelemetry.channel = gatewayInfo.channel_index;\naddDataToTelemetry.consumed_airtime = data.uplink_message.?consumed_airtime;\naddDataToTelemetry.fCnt = data.uplink_message.?f_cnt;\n\nvar isIncludeGatewayInfo = metadata[\"includeGatewayInfo\"];\nif(isIncludeGatewayInfo == true) {\n telemetry = processTelemetryData(telemetry, addDataToTelemetry);\n}\n\nvar result = {\n deviceName: deviceName,\n deviceType: deviceType,\n// assetName: assetName,\n// assetType: assetType,\n attributes: attributes,\n telemetry: telemetry\n};\n\naddAdditionalInfoForDeviceMsg(result, customerName, groupName);\n\nreturn result;\n\n\nfunction addAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName) {\n if (customerName != null) {\n deviceInfo.customerName = customerName;\n }\n if (groupName != null) {\n deviceInfo.groupName = groupName;\n }\n}\n\nfunction parseDateToTimestamp(dateString) {\n var date = new Date(dateString);\n var timestamp = date.getTime();\n \n // If we cannot parse timestamp - we will use the current timestamp\n if (timestamp == -1) {\n timestamp = Date.now();\n }\n \n return timestamp;\n}\n\nfunction getGatewayInfo() {\n var gatewayList = data.uplink_message.?rx_metadata;\n var maxRssi = Integer.MIN_VALUE;\n var gatewayInfo = {};\n \n foreach (gateway : gatewayList) {\n if(gateway.rssi > maxRssi) {\n maxRssi = gateway.rssi;\n gatewayInfo = gateway;\n }\n }\n \n return gatewayInfo;\n}\n\nfunction processTelemetryData(telemetry, addDataToTelemetry) {\n if (telemetry.size >= 1) {\n telemetry = addDataToTelemetries(telemetry, addDataToTelemetry);\n }\n else {\n telemetry.add(addDataToTelemetry);\n }\n \n return telemetry;\n}\n\nfunction addDataToTelemetries(telemetries, addDataToTelemetry) {\n foreach(telemetry : telemetries) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[\"values\"].keys.contains(element.key)) {\n telemetry[\"values\"][element.key] = element.value;\n }\n } \n }\n \n return telemetries;\n}\n\nfunction getWatermarkData(watermarkFrequency) {\n var decodedWatermark = {};\n \n var watermarkTension = 0;\n if (watermarkFrequency > 6430){\n\t\twatermarkTension = 0;\n\t} else if (watermarkFrequency >= 4330 && watermarkFrequency <= 6430){\n\t watermarkTension = 9.000 - (watermarkFrequency - 4330.000) * 0.004286;\n\t} else if (watermarkFrequency >= 2820 && watermarkFrequency < 4330){\n\t\twatermarkTension = 15.000 - (watermarkFrequency - 2820.000) * 0.003974;\n\t} else if (watermarkFrequency >= 1110 && watermarkFrequency < 2820){\n\t\twatermarkTension = 35.000 - (watermarkFrequency - 1110.000) * 0.01170;\n\t} else if (watermarkFrequency >= 770 && watermarkFrequency < 1110){\n\t\twatermarkTension = 55.000 - (watermarkFrequency - 770.000) * 0.05884;\n\t} else if (watermarkFrequency >= 600 && watermarkFrequency < 770){\n\t\twatermarkTension = 75.000 - (watermarkFrequency - 600.000) * 0.1176;\n\t} else if (watermarkFrequency >= 485 && watermarkFrequency < 600){\n\t\twatermarkTension = 100.000 - (watermarkFrequency - 485.000) * 0.2174;\n } else if (watermarkFrequency >= 293 && watermarkFrequency < 485){\n\t\twatermarkTension = 200.000 - (watermarkFrequency - 293.000) * 0.5208;\n\t} else {\n\t watermarkTension = 200;\n\t}\t\t\t\t\t\n\tdecodedWatermark.watermarkTension = roundUsingMathRound(watermarkTension, 0);\n\tdecodedWatermark.watermarkFrequency = watermarkFrequency;\n\t\t\t\t\n return decodedWatermark;\n}\n\nfunction roundUsingMathRound(value, places) {\n if (places >= 0) {\n var factor = Math.pow(10, places);\n return Math.round(value * factor) / factor; \n }\n \n return value;\n}\n\nfunction getAlarmStatus(bit) {\n var alarmResult = \"Invalid\";\n \n if (bit === 0) {\n alarmResult = \"No Alarm\";\n } else if (bit === 1 || bit === 255) {\n alarmResult = \"Alarm\";\n } else {\n alarmResult = \"Invalid\";\n }\n \n return alarmResult;\n}\n\nfunction getEnableStatus(bit) {\n var enableResult = \"Invalid\";\n \n switch (bit) {\n\t\tcase 0:\n\t\t enableResult = \"Disable\";\n\t\t\tbreak;\n\t\tcase 1:\n\t\t\tenableResult = \"Enable\";\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tenableResult = \"Invalid\";\n\t}\n \n return enableResult;\n}\n\nfunction getReportStatus(bit) {\n var reportResult = \"Invalid\";\n \n switch (bit5) {\n case 0:\n reportResult = \"Ignore\";\n break;\n case 1:\n reportResult = \"Report\";\n break;\n default:\n reportResult = \"Invalid\";\n }\n \n return reportResult;\n}", + "encoder": null, + "tbelEncoder": null, + "updateOnlyKeys": [ + "fPort", + "bandwidth", + "frequency", + "net_id", + "cluster_id", + "cluster_address", + "device_id", + "join_eui", + "battery", + "eui", + "channel", + "applicationId", + "devAddr", + "spreadingFactor", + "codeRate", + "tenantId" + ] + }, + "additionalInfo": { + "description": "" + }, + "edgeTemplate": false +} \ No newline at end of file diff --git a/VENDORS/Tektelic/Kiwi/ThingsStackCommunity/uplink/metadata.json b/VENDORS/Tektelic/Kiwi/ThingsStackCommunity/uplink/metadata.json new file mode 100644 index 00000000..0d75c374 --- /dev/null +++ b/VENDORS/Tektelic/Kiwi/ThingsStackCommunity/uplink/metadata.json @@ -0,0 +1,4 @@ +{ + "integrationName": "The Things Stack Community integration", + "includeGatewayInfo": "false" +} \ No newline at end of file diff --git a/VENDORS/Tektelic/Kiwi/ThingsStackCommunity/uplink/payload.json b/VENDORS/Tektelic/Kiwi/ThingsStackCommunity/uplink/payload.json new file mode 100644 index 00000000..be420fea --- /dev/null +++ b/VENDORS/Tektelic/Kiwi/ThingsStackCommunity/uplink/payload.json @@ -0,0 +1,54 @@ +{ + "end_device_ids": { + "device_id": "eui-1000000000000001", + "application_ids": { + "application_id": "application-tts-name" + }, + "dev_eui": "1000000000000001", + "join_eui": "2000000000000001", + "dev_addr": "20000001" + }, + "correlation_ids": ["as:up:01H0S7ZJQ9MQPMVY49FT3SE07M", "gs:conn:01H03BQZ9342X3Y86DJ2P704E5", "gs:up:host:01H03BQZ99EGAM52KK1300GFKN", "gs:uplink:01H0S7ZJGS6D9TJSKJN8XNTMAV", "ns:uplink:01H0S7ZJGS9KKD4HTTPKFEMWCV", "rpc:/ttn.lorawan.v3.GsNs/HandleUplink:01H0S7ZJGSF3M38ZRZVTM38DEC", "rpc:/ttn.lorawan.v3.NsAs/HandleUplink:01H0S7ZJQ8R2EH5AA269AKM8DX"], + "received_at": "2023-05-19T05:33:35.848446463Z", + "uplink_message": { + "session_key_id": "AYfqmb0pc/1uRZv9xUydgQ==", + "f_port": 10, + "f_cnt": 10335, + "frm_payload": "ANNaAL0KCg==", + "rx_metadata": [{ + "gateway_ids": { + "gateway_id": "eui-6a7e111a10000000", + "eui": "6A7E111A10000000" + }, + "time": "2023-05-19T05:33:35.608982Z", + "timestamp": 3893546133, + "rssi": -35, + "channel_rssi": -35, + "snr": 13.2, + "frequency_offset": "69", + "uplink_token": "CiIKIAoUZXVpLTZhN2UxMTFhMTAwMDAwMDASCCThJP/+9k6eEJWZy8AOGgwIr5ScowYQvNbUsQIgiMy8y6jwpwE=", + "channel_index": 3, + "received_at": "2023-05-19T05:33:35.607383681Z" + }], + "settings": { + "data_rate": { + "lora": { + "bandwidth": 125000, + "spreading_factor": 7, + "coding_rate": "4/5" + } + }, + "frequency": "867100000", + "timestamp": 3893546133, + "time": "2023-05-19T05:33:35.608982Z" + }, + "received_at": "2023-05-19T05:33:35.641841782Z", + "consumed_airtime": "0.056576s", + "network_ids": { + "net_id": "000013", + "tenant_id": "ttn", + "cluster_id": "eu1", + "cluster_address": "eu1.cloud.thethings.network" + } + } +} \ No newline at end of file diff --git a/VENDORS/Tektelic/Kiwi/ThingsStackCommunity/uplink/payload_1.json b/VENDORS/Tektelic/Kiwi/ThingsStackCommunity/uplink/payload_1.json new file mode 100644 index 00000000..d7467513 --- /dev/null +++ b/VENDORS/Tektelic/Kiwi/ThingsStackCommunity/uplink/payload_1.json @@ -0,0 +1,54 @@ +{ + "end_device_ids": { + "device_id": "eui-1000000000000001", + "application_ids": { + "application_id": "application-tts-name" + }, + "dev_eui": "1000000000000001", + "join_eui": "2000000000000001", + "dev_addr": "20000001" + }, + "correlation_ids": ["as:up:01H0S7ZJQ9MQPMVY49FT3SE07M", "gs:conn:01H03BQZ9342X3Y86DJ2P704E5", "gs:up:host:01H03BQZ99EGAM52KK1300GFKN", "gs:uplink:01H0S7ZJGS6D9TJSKJN8XNTMAV", "ns:uplink:01H0S7ZJGS9KKD4HTTPKFEMWCV", "rpc:/ttn.lorawan.v3.GsNs/HandleUplink:01H0S7ZJGSF3M38ZRZVTM38DEC", "rpc:/ttn.lorawan.v3.NsAs/HandleUplink:01H0S7ZJQ8R2EH5AA269AKM8DX"], + "received_at": "2023-05-19T05:33:35.848446463Z", + "uplink_message": { + "session_key_id": "AYfqmb0pc/1uRZv9xUydgQ==", + "f_port": 10, + "f_cnt": 10335, + "frm_payload": "AQQFeQICAtU=", + "rx_metadata": [{ + "gateway_ids": { + "gateway_id": "eui-6a7e111a10000000", + "eui": "6A7E111A10000000" + }, + "time": "2023-05-19T05:33:35.608982Z", + "timestamp": 3893546133, + "rssi": -35, + "channel_rssi": -35, + "snr": 13.2, + "frequency_offset": "69", + "uplink_token": "CiIKIAoUZXVpLTZhN2UxMTFhMTAwMDAwMDASCCThJP/+9k6eEJWZy8AOGgwIr5ScowYQvNbUsQIgiMy8y6jwpwE=", + "channel_index": 3, + "received_at": "2023-05-19T05:33:35.607383681Z" + }], + "settings": { + "data_rate": { + "lora": { + "bandwidth": 125000, + "spreading_factor": 7, + "coding_rate": "4/5" + } + }, + "frequency": "867100000", + "timestamp": 3893546133, + "time": "2023-05-19T05:33:35.608982Z" + }, + "received_at": "2023-05-19T05:33:35.641841782Z", + "consumed_airtime": "0.056576s", + "network_ids": { + "net_id": "000013", + "tenant_id": "ttn", + "cluster_id": "eu1", + "cluster_address": "eu1.cloud.thethings.network" + } + } +} \ No newline at end of file diff --git a/VENDORS/Tektelic/Kiwi/ThingsStackCommunity/uplink/result.json b/VENDORS/Tektelic/Kiwi/ThingsStackCommunity/uplink/result.json new file mode 100644 index 00000000..afaeebe3 --- /dev/null +++ b/VENDORS/Tektelic/Kiwi/ThingsStackCommunity/uplink/result.json @@ -0,0 +1,27 @@ +{ + "deviceName": "eui-1000000000000001", + "deviceType": "Kiwi", + "attributes": { + "eui": "1000000000000001", + "fPort": 10, + "applicationId": "application-tts-name", + "devAddr": "20000001", + "spreadingFactor": 7, + "codeRate": "4/5", + "tenantId": "ttn", + "device_id": "eui-1000000000000001", + "join_eui": "2000000000000001", + "net_id": "000013", + "cluster_id": "eu1", + "cluster_adress": "eu1.cloud.thethings.network", + "bandwidth": 125000, + "frequency": "867100000" + }, + "telemetry": [{ + "ts": 1684474415641, + "values": { + "rem_batt_capacity": 90, + "rem_batt_days": 2570 + } + }] +} \ No newline at end of file diff --git a/VENDORS/Tektelic/Kiwi/ThingsStackCommunity/uplink/result_1.json b/VENDORS/Tektelic/Kiwi/ThingsStackCommunity/uplink/result_1.json new file mode 100644 index 00000000..e99a2a6f --- /dev/null +++ b/VENDORS/Tektelic/Kiwi/ThingsStackCommunity/uplink/result_1.json @@ -0,0 +1,29 @@ +{ + "deviceName": "eui-1000000000000001", + "deviceType": "Kiwi", + "attributes": { + "eui": "1000000000000001", + "fPort": 10, + "applicationId": "application-tts-name", + "devAddr": "20000001", + "spreadingFactor": 7, + "codeRate": "4/5", + "tenantId": "ttn", + "device_id": "eui-1000000000000001", + "join_eui": "2000000000000001", + "net_id": "000013", + "cluster_id": "eu1", + "cluster_adress": "eu1.cloud.thethings.network", + "bandwidth": 125000, + "frequency": "867100000" + }, + "telemetry": [{ + "ts": 1684474415641, + "values": { + "input1_frequency_to_moisture": "Dry", + "input1_frequency": 1401, + "input2_voltage_to_temp": 22.6, + "input2_voltage": 0.725 + } + }] +} \ No newline at end of file diff --git a/VENDORS/Tektelic/Kiwi/ThingsStackIndustries/uplink/converter.json b/VENDORS/Tektelic/Kiwi/ThingsStackIndustries/uplink/converter.json new file mode 100644 index 00000000..8fc769cd --- /dev/null +++ b/VENDORS/Tektelic/Kiwi/ThingsStackIndustries/uplink/converter.json @@ -0,0 +1,40 @@ +{ + "name": "The Things Stack Industries Uplink Decoder for Kiwi", + "type": "UPLINK", + "debugMode": false, + "debugSettings": { + "failuresEnabled": true, + "allEnabled": false, + "allEnabledUntil": 1733331880270 + }, + "configuration": { + "scriptLang": "TBEL", + "decoder": null, + "tbelDecoder": "var data = decodeToJson(payload);\n\nvar deviceName = data.end_device_ids.device_id;\nvar deviceType = \"Kiwi\";\nvar groupName = null; // If groupName is not null - created device will be added to the entity group with such name.\nvar customerName = null; // If customerName is not null - created devices will be assigned to customer with such name. \n\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// If you want to parse incoming data somehow, you can add your code to this function.\n// input: bytes\n// expected output:\n// {\n// \"attributes\": {\"attributeKey\": \"attributeValue\"},\n// \"telemetry\": [{\"ts\": 1...1, \"values\": {\"telemetryKey\":\"telemetryValue\"}, {\"ts\": 1...2, \"values\": {\"telemetryKey\":\"telemetryValue\"}}]\n// }\n\nfunction decodeFrmPayload(input) {\n var output = { attributes: {}, telemetry: []};\n \n // --- Decoding code --- //\n var decoded = {};\n var fPort = data.uplink_message.f_port;\n if(fPort == 10) {\n for(var i = 0; i < input.length - 2; ) {\n var key_1 = input[i++] & 0xff;\n var key_2 = input[i++] & 0xff;\n \n if(key_1 == 0x00 && key_2 == 0xBA) {\n var val = (input[i] >> 7) & 1; \n\n decoded.eos_alert = getAlarmStatus(val);\n var battery_bits = input[i] & 0x7F;\n decoded.battery_voltage = roundUsingMathRound(battery_bits * 0.01 + 2.5, 2);\n i += 1;\n }\n else if(key_1 == 0x00 && key_2 == 0xD3) {\n decoded.rem_batt_capacity = parseBytesToInt(input, i, 1);\n i += 1;\n }\n else if(key_1 == 0x00 && key_2 == 0xBD) {\n decoded.rem_batt_days = parseBytesToInt(input, i, 2);\n\t\t\t\ti += 2;\n }\n else if(key_1 == 0x01 && key_2 == 0x04) {\n var value = parseBytesToInt(input, i, 2);\n var frequencyMoisture = 0;\n\t\t\t\tif (value > 1399){\n\t\t\t\t\tfrequencyMoisture = \"Dry\";\n\t\t\t\t} else if (value > 1396 && value <= 1399){\n\t\t\t\t\tfrequencyMoisture = 0.1;\n\t\t\t\t} else if (value > 1391 && value <= 1396){\n\t\t\t\t\tfrequencyMoisture = 0.2;\n\t\t\t\t} else if (value > 1386 && value <= 1391){\n\t\t\t\t\tfrequencyMoisture = 0.3;\n\t\t\t\t} else if (value > 1381 && value <= 1386){\n\t\t\t\t\tfrequencyMoisture = 0.4;\n\t\t\t\t} else if (value > 1376 && value <= 1381){\n\t\t\t\t\tfrequencyMoisture = 0.5;\n\t\t\t\t} else if (value > 1371 && value <= 1376){\n\t\t\t\t\tfrequencyMoisture = 0.6;\n\t\t\t\t} else if (value > 1366 && value <= 1371){\n\t\t\t\t\tfrequencyMoisture = 0.7;\n\t\t\t\t} else if (value > 1361 && value <= 1366){\n\t\t\t\t\tfrequencyMoisture = 0.8;\n\t\t\t\t} else if (value > 1356 && value <= 1361){\n\t\t\t\t\tfrequencyMoisture = 0.9;\n\t\t\t\t} else if (value > 1351 && value <= 1356){\n\t\t\t\t\tfrequencyMoisture = 1.0;\n\t\t\t\t} else if (value > 1346 && value <= 1351){\n\t\t\t\t\tfrequencyMoisture = 1.1;\n\t\t\t\t} else if (value > 1341 && value <= 1346){\n\t\t\t\t\tfrequencyMoisture = 1.2;\n\t\t\t\t} else {\n\t\t\t\t\tfrequencyMoisture = \"Wet\";\n\t\t\t\t}\n\t\t\t\tdecoded.input1_frequency_to_moisture = frequencyMoisture;\n\t\t\t\tdecoded.input1_frequency = value;\n\t\t\t\ti += 2;\n }\n else if (key_1 == 0x02 && key_2 == 0x02) {\n var voltageValue = parseBytesToInt(input, i, 2) * 0.001;\n\t\t\t\tvar voltageTempOutput = -32.46 * Math.log(voltageValue * 1000) + 236.36;\n\t\t\t\tdecoded.input2_voltage_to_temp = roundUsingMathRound(voltageTempOutput, 1);\n\t\t\t\tdecoded.input2_voltage = voltageValue;\n\t\t\t\ti += 2;\n }\n else if (key1 == 0x03 && key2 == 0x02) {\n var input3Voltage = parseBytesToInt(input, i, 2) * 0.001;\n \n decoded.input3_voltage = input3Voltage;\n\t\t\t\tdecoded.input3_voltage_to_temp = roundUsingMathRound((-33.01 * Math.pow(input3Voltage, 5)) + (217.4 * Math.pow(input3Voltage, 4)) + (-538.6 * Math.pow(input3Voltage, 3)) + (628.1 * Math.pow(input3Voltage, 2)) + (-378.9 * input3Voltage) + 102.9, 1);\n \n i += 2;\n }\n else if (key1 == 0x03 && key2 == 0x67) {\n decoded.input3_temperature = parseBytesToInt(input, i, 2) * 0.1;\n\t\t\t\ti += 2;\n }\n else if (key1 == 0x04 && key2 == 0x02) {\n var input4Voltage = parseBytesToInt(input, i, 2) * 0.001;\n \n decoded.input4_voltage = input4Voltage;\n\t\t\t\tdecodedinput4_voltage_to_temp = roundUsingMathRound((-33.01 * Math.pow(input4Voltage, 5)) + (217.4 * Math.pow(input4Voltage, 4)) + (-538.6 * Math.pow(input4Voltage, 3)) + (628.1 * Math.pow(input4Voltage, 2)) + (-378.9 * input4Voltage) + 102.9, 1);\n \n i += 2;\n }\n else if (key1 == 0x04 && key2 == 0x67) {\n decoded.input4_temperature = parseBytesToInt(input, i, 2) * 0.1;\n\t\t\t\ti += 2;\n }\n else if (key1 == 0x05 && key2 == 0x04) {\n var watermark1Frequency = parseBytesToInt(input, i, 2);\n\t\t\t\t\n\t\t\t\tvar decodedWatermarkData1 = getWatermarkData(watermark1Frequency);\t\n\t\t\t\tdecoded.watermark1_tension = decodedWatermarkData1.watermarkTension;\n\t\t\t\tdecoded.watermark1_frequency = decodedWatermarkData1.watermarkFrequency;\n\t\t\t\t\n\t\t\t\ti += 2;\n }\n else if (key1 == 0x06 && key2 == 0x04) {\n var watermark2Frequency = parseBytesToInt(input, i, 2);\n\t\t\t\t\n\t\t\t\tvar decodedWatermarkData2 = getWatermarkData(watermark2Frequency);\t\n\t\t\t\tdecoded.watermark2_tension = decodedWatermarkData2.watermarkTension;\n\t\t\t\tdecoded.watermark2_frequency = decodedWatermarkData2.watermarkFrequency;\n\t\t\t\t\n\t\t\t\ti += 2;\n }\n else if (key1 == 0x09 && key2 == 0x65) {\n var lightIntensity = parseBytesToInt(input, i, 2);\n\t\t\t\t\n\t\t\t\tdecoded.light_intensity = lightIntensity; \n\t\t\t\ti += 2;\n }\n else if (key1 == 0x09 && key2 == 0x00) {\n var lightDetected = parseBytesToInt(input, i, 1);\n\t\t\t\tdecoded.light_detected = getAlarmStatus(lightDetected);\n\t\t\t\t\n\t\t\t\ti += 1;\n }\n else if (key1 == 0x0A && key2 == 0x71) {\n decoded.accelerationX = parseBytesToInt(input, i, 2);\n decoded.accelerationY = parseBytesToInt(input, i + 2, 2);\n decoded.accelerationZ = parseBytesToInt(input, i + 4, 2);\n }\n else if (key1 == 0x0A && key2 == 0x00) {\n var orientationAlarm = parseBytesToInt(input, i, 1);\n decoded.orientation_alarm = getAlarmStatus(orientationAlarm);\n\t\t\t\t\n\t\t\t\ti += 1;\n }\n else if (key1 == 0x0B && key2 == 0x67) {\n decoded.ambient_temperature = parseBytesToInt(input, i, 2) * 0.1;\n i += 2;\n }\n else if (key1 == 0x0B && key2 == 0x68) {\n decoded.relative_humidity = parseBytesToInt(input, i, 1) * 0.5;\n i += 1;\n }\n else if (key1 == 0x0C && key2 == 0x67) {\n decoded.mcu_temperature = parseBytesToInt(input, i, 2) * 0.1;\n i += 2;\n }\n else if (key1 == 0x0D && key2 == 0x73) {\n decoded.RFU_2 = parseBytesToInt(input, i, 1) * 0.1;\n i += 1;\n }\n }\n }\n else if (fPort == 100) {\n for(var i = 0; i < input.length -1; ) {\n var key = input[i++] & 0xff;\n \n if(key == 0x10) {\n var val = (((input[i] << 8) | input[i + 1]) >> 15) & 1;\n switch (val){\n\t\t\t\t\tcase 0:\n\t\t\t\t\t\toutput.attributes.loramac_join_mode = \"ABP\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 1:\n\t\t\t\t\t\toutput.attributes.loramac_join_mode = \"OTAA\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\toutput.attributes.loramac_join_mode = \"Invalid\";\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\ti += 1;\n }\n else if (key == 0x11) {\n var val = (((input[i] << 8) | input[i + 1]) >> 12) & 0xF;\n switch (val) {\n\t\t\t\t\tcase 0:\n\t\t\t\t\t\toutput.attributes.deviceClassEnabled = \"Class A\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 12:\n\t\t\t\t\t\toutput.attributes.deviceClassEnabled = \"Class C\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\toutput.attributes.deviceClassEnabled = \"Invalid\";\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tvar val = (((input[i] << 8) | input[i + 1]) >> 3) & 1;\n\t\t\t\toutput.attributes.adr = getEnableStatus(val);\n\t\t\t\t\n\t\t\t\tvar val = (((input[i] << 8) | input[i + 1]) >> 2) & 1;\n\t\t\t\toutput.attributes.duty_cycle = getEnableStatus(val);\n\t\t\t\t\n\t\t\t\tvar val = (((input[i] << 8) | input[i + 1]) >> 1) & 1;\n\t\t\t\t\n\t\t\t\tswitch (val) {\n\t\t\t\t\tcase 0:\n\t\t\t\t\t\toutput.attributes.sync_word = \"Private\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 1:\n\t\t\t\t\t\toutput.attributes.sync_word = \"Public\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\toutput.attributes.sync_word = \"Invalid\";\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tvar val = ((input[i] << 8) | input[i + 1]) & 1;\n\t\t\t\t\n\t\t\t\tswitch (val){\n\t\t\t\t\tcase 0:\n\t\t\t\t\t\toutput.attributes.confirm_mode = \"Unconfirmed\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 1:\n\t\t\t\t\t\toutput.attributes.confirm_mode = \"Confirmed\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t output.attributes.confirm_mode = \"Invalid\";\n\t\t\t\t}\n\t\t\t\ti += 2;\n }\n else if (key == 0x12) {\n output.attributes.dr_number = (((input[i] << 8) | input[i + 1]) >> 8) & 0xF;\n output.attributes.tx_power_number = ((input[i] << 8) | input[i + 1]) & 0xF;\n \n i +=2;\n }\n else if (key == 0x13) {\n output.attributes.frequency = (((input[i] << 32) | (input[i + 1] << 24) | (input[i + 2] << 16) | (input[i + 3] << 8) | input[i + 4]) >> 8) & 0xFFFFFFFF;\n output.attributes.dr_number_rx2 = input[i + 4] & 0xFF;\n \n i += 5;\n }\n else if (key == 0x20) {\n output.attributes.seconds_per_core_tick = parseBytesToInt(input, i, 4);\n i += 4;\n }\n else if(key == 0x21) {\n output.attributes.tick_per_battery = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x22) {\n output.attributes.tick_per_ambient_temperature = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x23) {\n output.attributes.tick_per_relative_humidity = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x24) {\n output.attributes.tick_per_light = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x25) {\n output.attributes.tick_per_input1 = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x26) {\n output.attributes.tick_per_input2 = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x27) {\n output.attributes.tick_per_input3 = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x28) {\n output.attributes.tick_per_input4 = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x29) {\n output.attributes.tick_per_watermark1 = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x2A) {\n output.attributes.tick_per_watermark2 = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x2C) {\n output.attributes.tick_per_accelerometer = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x2D) {\n output.attributes.tick_per_orientation_alarm = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x2E) {\n output.attributes.tick_per_mcu_temperature = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x2F) {\n output.attributes.RFU_1 = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x30) {\n output.attributes.temperature_relative_humidity_idle = parseBytesToInt(input, i, 4);\n i += 4;\n }\n else if(key == 0x31) {\n output.attributes.temperature_relative_humidity_active = parseBytesToInt(input, i, 4);\n i += 4;\n }\n else if(key == 0x32) {\n output.attributes.high_ambient_temp_raw = (((input[i] << 8) | input[i + 1]) >> 8) & 0xFF;\n output.attributes.low_ambient_temp_raw = ((input[i] << 8) | input[i + 1]) & 0xFF;\n \n i += 2;\n }\n else if(key == 0x33) {\n var val = input[i] & 1;\n output.attributes.ambient_temperature_threshold_enabled = getEnableStatus(val);\n\t\t\t\t\n\t\t\t\ti += 1;\n }\n else if (key == 0x34) {\n output.attributes.high_rh = input[i];\n\t\t\t\toutput.attributes.low_rh = input[i + 1];\n\t\t\t\t\n\t\t\t\ti += 2;\n }\n else if (key == 0x35) {\n var val = input[i] & 1;\n output.attributes.relative_humidity_threshold_enabled = getEnableStatus(val);\n\t\t\t\t\n\t\t\t\ti += 1;\n }\n else if (key == 0x36) {\n output.attributes.input_sample_period_idle = parseBytesToInt(input, i, 4);\n i += 4;\n }\n else if (key == 0x37) {\n output.attributes.input_sample_period_active = parseBytesToInt(input, i, 4);\n i += 4;\n }\n else if (key == 0x38) {\n output.attributes.low_input1 = parseBytesToInt(input, i, 2);\n output.attributes.high_input1 = parseBytesToInt(input, i + 2, 2);\n \n i += 4;\n }\n else if (key == 0x39) {\n output.attributes.low_input2 = parseBytesToInt(input, i, 2);\n output.attributes.high_input2 = parseBytesToInt(input, i + 2, 2);\n \n i += 4;\n }\n else if (key == 0x3A) {\n output.attributes.low_input3 = parseBytesToInt(input, i, 2);\n output.attributes.high_input3 = parseBytesToInt(input, i + 2, 2);\n \n i += 4;\n }\n else if (key == 0x3B) {\n output.attributes.low_input4 = parseBytesToInt(input, i, 2);\n output.attributes.high_input4 = parseBytesToInt(input, i + 2, 2);\n \n i += 4;\n }\n else if (key == 0x3C) {\n output.attributes.low_watermark1 = parseBytesToInt(input, i, 2);\n output.attributes.high_watermark1 = parseBytesToInt(input, i + 2, 2);\n \n i += 4;\n }\n else if (key == 0x3D) {\n output.attributes.low_watermark2 = parseBytesToInt(input, i, 2);\n output.attributes.high_watermark2 = parseBytesToInt(input, i + 2, 2);\n \n i += 4;\n }\n else if (key == 0x3F) {\n var input_status = input[i] & 0x3F;\n \n var bit0 = (input_status >> 0) & 1;\n output.attributes.input_enable_input1 = getEnableStatus(bit0);\n \n var bit1 = (input_status >> 1) & 1;\n output.attributes.input_enable_input2 = getEnableStatus(bit1);\n \n var bit2 = (input_status >> 2) & 1;\n output.attributes.input_enable_input3 = getEnableStatus(bit2);\n \n var bit3 = (input_status >> 3) & 1;\n output.attributes.input_enable_input4 = getEnableStatus(bit3);\n \n var bit4 = (input_status >> 4) & 1;\n output.attributes.input_enable_watermark1_enable = getEnableStatus(bit4);\n \n var bit5 = (input_status >> 5) & 1;\n output.attributes.input_enable_watermark2_enable = getEnableStatus(bit5);\n \n i += 1;\n }\n else if (key == 0x40) {\n output.attributes.mcu_temperature_sample_period_idle = parseBytesToInt(input, i, 4);\n i += 4;\n }\n else if (key == 0x41) {\n output.attributes.mcu_temperature_sample_period_active = parseBytesToInt(input, i, 4);\n i += 4;\n }\n else if (key == 0x42) {\n output.attributes.high_mcu_temp = input[i + 1];\n output.attributes.low_mcu_temp = input[i];\n i += 4;\n }\n else if (key == 0x43) {\n var val = input[i] & 1;\n output.attributes.mcu_temperature_enable = getEnableStatus(val);\n\n\t\t\t\ti += 2;\n }\n else if (key == 0x44) {\n output.attributes.low_input3_onewire = parseBytesToInt(input, i, 2);\n output.attributes.high_input3_onewire = parseBytesToInt(input, i + 2, 2);\n i += 2;\n }\n else if (key == 0x45) {\n output.attributes.low_input4_onewire = parseBytesToInt(input, i, 2);\n output.attributes.high_input4_onewire = parseBytesToInt(input, i + 2, 2);\n i += 2;\n }\n else if (key == 0x48 ) {\n var val = input[i] & 1;\n output.attributes.ALS_interrupt_enabled = getEnableStatus(val);\n \n i += 1;\n }\n else if (key == 0x49) {\n output.attributes.ALS_upper_threshold = parseBytesToInt(input, i, 2);\n i +=2;\n }\n else if (key == 0x4A) {\n output.attributes.ALS_lower_threshold = parseBytesToInt(input, i, 2);\n i +=2;\n }\n else if (key == 0x4B) {\n output.attributes.light_sample_period_idle = parseBytesToInt(input, i, 4);\n i +=4;\n }\n else if (key == 0x4C) {\n output.attributes.light_sample_period_active = parseBytesToInt(input, i, 4);\n i +=4;\n }\n else if (key == 0x4D) {\n var status = input[i] & 0x03;\n \n var bit1 = status & 1;\n output.attributes.light_alarm_reported = getReportStatus(bit1);\n \n var bit2 = (status >> 1) & 1;\n output.attributes.light_intensity_reported = getReportStatus(bit2);\n \n i += 1;\n }\n else if (key == 0x50) {\n output.attributes.orientation_alarm_threshold = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x51) {\n var status = input[i];\n\n var bit5 = (status >> 5) & 1;\n output.attributes.orientation_vector_report = getReportStatus(bit5);\n \n var bit0 = status & 1; \n output.attributes.orientation_alarm_report = getReportStatus(bit0);\n \n i += 1;\n }\n else if (key == 0x52) {\n var status = input[i]; \n \n var bit7 = (status >> 7) & 1; \n var bit0 = status & 1; \n \n switch (bit7) {\n case 0:\n output.attributes.accelerometer_power_on = \"Off\";\n break;\n case 1:\n output.attributes.accelerometer_power_on = \"On\";\n break;\n default:\n output.attributes.accelerometer_power_on = \"Invalid\";\n }\n \n output.attributes.orientation_alarm_mode = getEnableStatus(bit0);\n \n i += 1;\n }\n else if (key == 0x61) {\n var status = input[i]; \n \n var bit1 = (status >> 1) & 1;\n output.attributes.report_capacity_enabled = getEnableStatus(bit1);\n \n var bit2 = (status >> 2) & 1;\n output.attributes.report_lifetime_enabled = getEnableStatus(bit2);\n \n i += 1;\n }\n else if (key == 0x62) {\n output.attributes.avg_current_window = parseBytesToInt(input, i, 1);\n i += 1;\n }\n else if (key == 0x71) {\n output.attributes.app_major_version = input[i + 6];\n\t\t\t\toutput.attributes.app_minor_version = input[i + 5];\n\t\t\t\toutput.attributes.app_revision = input[i + 4];\n\t\t\t\toutput.attributes.loramac_major_version = input[i + 3];\n\t\t\t\toutput.attributes.loramac_minor_version = input[i + 2];\n\t\t\t\toutput.attributes.loramac_revision = input[i + 1];\n\t\t\t\tvar val = input[i];\n\t\t\t\tswitch (val){\n\t\t\t\t\tcase 0:\n\t\t\t\t\t\toutput.attributes.region = \"EU868\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 1:\n\t\t\t\t\t\toutput.attributes.region = \"US915\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 2:\n\t\t\t\t\t\toutput.attributes.region = \"AS923\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 3:\n\t\t\t\t\t\toutput.attributes.region = \"AU915\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 4:\n\t\t\t\t\t\toutput.attributes.region = \"IN865\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 6:\n\t\t\t\t\t\toutput.attributes.region = \"KR920\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 7:\n\t\t\t\t\t\toutput.attributes.region = \"RU864\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\toutput.attributes.region = \"Invalid\";\n\t\t\t\t}\n\t\t\t\ti += 7;\n }\n }\n }\n else if (fPort == 101) {\n var size = input.length;\n var responses = [];\n \n var index = 0;\n while (index < size) {\n var downlinkFcnt = input[index++] & 0xFF; \n var numInvalidWrites = input[index++] & 0xFF; \n \n if (numInvalidWrites > 0) {\n var invalidRegisters = [];\n for (var i = 0; i < numInvalidWrites; i++) {\n invalidRegisters.add(String.format(\"0x%02X\", input[index + i]));\n }\n index += numInvalidWrites;\n \n responses.add(String.format(\n \"%d Invalid write command(s) from DL:%d for register(s): %s\",\n numInvalidWrites, downlinkFcnt, String.join(\", \", invalidRegisters)\n ));\n } else {\n responses.add(String.format(\"All write commands from DL:%d were successful\", downlinkFcnt));\n }\n }\n \n decoded.response = responses;\n }\n \n output.telemetry = [{\n ts: timestamp,\n values: decoded\n }];\n\n // --- Decoding code --- //\n return output;\n}\n\n// --- attributes and telemetry objects ---\nvar telemetry = [];\nvar attributes = {};\n// --- attributes and telemetry objects ---\n\n// --- Timestamp parsing\nvar dateString = data.uplink_message.received_at;\n\nif ((data.simulated != null && data.simulated) || dateString == null) {\n dateString = data.received_at;\n}\n\ntimestamp = parseDateToTimestamp(dateString);\n// --- Timestamp parsing\n\n// Message parsing\n// To avoid paths in the decoded objects we passing false value to function as \"pathInKey\" argument.\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.\n\n// Passing incoming bytes to decodeFrmPayload function, to get custom decoding\nvar customDecoding = {};\nif (data.uplink_message.get(\"frm_payload\") != null) {\n customDecoding = decodeFrmPayload(base64ToBytes(data.uplink_message.frm_payload));\n}\n\n// Collecting data to result\nif (customDecoding.?telemetry.size() > 0) {\n if (customDecoding.telemetry instanceof java.util.ArrayList) {\n foreach(telemetryObj: customDecoding.telemetry) {\n if (telemetryObj.ts != null && telemetryObj.values != null) {\n telemetry.add(telemetryObj);\n }\n }\n } else {\n telemetry.putAll(customDecoding.telemetry);\n }\n}\n\nif (customDecoding.?attributes.size() > 0) {\n attributes.putAll(customDecoding.attributes);\n}\n\n// You can add some keys manually to attributes or telemetry\nvar applicationId = data.end_device_ids.?application_ids.?application_id;\nvar devAddr = data.end_device_ids.?dev_addr;\nvar spreadingFactor = data.uplink_message.?settings.?data_rate.?lora.?spreading_factor;\nvar codeRate = data.uplink_message.?settings.?data_rate.?lora.?coding_rate;\nvar tenantId = data.uplink_message.?network_ids.?tenant_id;\nattributes.eui = data.end_device_ids.dev_eui;\nattributes.fPort = data.uplink_message.f_port;\nattributes.applicationId = applicationId;\nattributes.devAddr = devAddr;\nattributes.spreadingFactor = spreadingFactor;\nattributes.codeRate = codeRate;\nattributes.tenantId = tenantId;\nattributes.device_id = data.end_device_ids.?device_id;\nattributes.join_eui = data.end_device_ids.?join_eui;\nattributes.net_id = data.uplink_message.?network_ids.?net_id;\nattributes.cluster_id = data.uplink_message.?network_ids.?cluster_id;\nattributes.cluster_address = data.uplink_message.?network_ids.?cluster_address;\nattributes.bandwidth = data.uplink_message.?settings.?data_rate.?lora.?bandwidth;\nattributes.frequency = data.uplink_message.?settings.?frequency;\n\nvar isIncludeGatewayInfo = metadata[\"includeGatewayInfo\"];\nif(isIncludeGatewayInfo == true) {\n var gatewayInfo = getGatewayInfo();\n var addDataToTelemetry = {};\n addDataToTelemetry.snr = gatewayInfo.snr;\n addDataToTelemetry.rssi = gatewayInfo.rssi;\n addDataToTelemetry.channel = gatewayInfo.channel_index;\n addDataToTelemetry.consumed_airtime = data.uplink_message.?consumed_airtime;\n addDataToTelemetry.fCnt = data.uplink_message.?f_cnt;\n\n telemetry = processTelemetryData(telemetry, addDataToTelemetry);\n}\n\nvar result = {\n deviceName: deviceName,\n deviceType: deviceType,\n // assetName: assetName,\n // assetType: assetType,\n attributes: attributes,\n telemetry: telemetry\n};\n\naddAdditionalInfoForDeviceMsg(result, customerName, groupName);\n\nreturn result;\n\nfunction addAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName) {\n if (customerName != null) {\n deviceInfo.customerName = customerName;\n }\n if (groupName != null) {\n deviceInfo.groupName = groupName;\n }\n}\n\nfunction parseDateToTimestamp(dateString) {\n var date = new Date(dateString);\n var timestamp = date.getTime();\n \n // If we cannot parse timestamp - we will use the current timestamp\n if (timestamp == -1) {\n timestamp = Date.now();\n }\n \n return timestamp;\n}\n\nfunction getGatewayInfo() {\n var gatewayList = data.uplink_message.?rx_metadata;\n var maxRssi = Integer. MIN_VALUE;\n var gatewayInfo = {};\n \n foreach (gateway : gatewayList) {\n if(gateway.rssi > maxRssi) {\n maxRssi = gateway.rssi;\n gatewayInfo = gateway;\n }\n }\n \n return gatewayInfo;\n}\n\nfunction processTelemetryData(telemetry, addDataToTelemetry) {\n if (telemetry.size >= 1) {\n telemetry = addDataToTelemetries(telemetry, addDataToTelemetry);\n }\n else {\n telemetry.add(addDataToTelemetry);\n }\n \n return telemetry;\n}\n\nfunction addDataToTelemetries(telemetries, addDataToTelemetry) {\n foreach(telemetry : telemetries) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[\"values\"].keys.contains(element.key)) {\n telemetry[\"values\"][element.key] = element.value;\n }\n } \n }\n \n return telemetries;\n}\n\nfunction getWatermarkData(watermarkFrequency) {\n var decodedWatermark = {};\n \n var watermarkTension = 0;\n if (watermarkFrequency > 6430){\n\t\twatermarkTension = 0;\n\t} else if (watermarkFrequency >= 4330 && watermarkFrequency <= 6430){\n\t watermarkTension = 9.000 - (watermarkFrequency - 4330.000) * 0.004286;\n\t} else if (watermarkFrequency >= 2820 && watermarkFrequency < 4330){\n\t\twatermarkTension = 15.000 - (watermarkFrequency - 2820.000) * 0.003974;\n\t} else if (watermarkFrequency >= 1110 && watermarkFrequency < 2820){\n\t\twatermarkTension = 35.000 - (watermarkFrequency - 1110.000) * 0.01170;\n\t} else if (watermarkFrequency >= 770 && watermarkFrequency < 1110){\n\t\twatermarkTension = 55.000 - (watermarkFrequency - 770.000) * 0.05884;\n\t} else if (watermarkFrequency >= 600 && watermarkFrequency < 770){\n\t\twatermarkTension = 75.000 - (watermarkFrequency - 600.000) * 0.1176;\n\t} else if (watermarkFrequency >= 485 && watermarkFrequency < 600){\n\t\twatermarkTension = 100.000 - (watermarkFrequency - 485.000) * 0.2174;\n } else if (watermarkFrequency >= 293 && watermarkFrequency < 485){\n\t\twatermarkTension = 200.000 - (watermarkFrequency - 293.000) * 0.5208;\n\t} else {\n\t watermarkTension = 200;\n\t}\t\t\t\t\t\n\tdecodedWatermark.watermarkTension = roundUsingMathRound(watermarkTension, 0);\n\tdecodedWatermark.watermarkFrequency = watermarkFrequency;\n\t\t\t\t\n return decodedWatermark;\n}\n\nfunction roundUsingMathRound(value, places) {\n if (places >= 0) {\n var factor = Math.pow(10, places);\n return Math.round(value * factor) / factor; \n }\n \n return value;\n}\n\nfunction getAlarmStatus(bit) {\n var alarmResult = \"Invalid\";\n \n if (bit === 0) {\n alarmResult = \"No Alarm\";\n } else if (bit === 1 || bit === 255) {\n alarmResult = \"Alarm\";\n } else {\n alarmResult = \"Invalid\";\n }\n \n return alarmResult;\n}\n\nfunction getEnableStatus(bit) {\n var enableResult = \"Invalid\";\n \n switch (bit) {\n\t\tcase 0:\n\t\t enableResult = \"Disable\";\n\t\t\tbreak;\n\t\tcase 1:\n\t\t\tenableResult = \"Enable\";\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tenableResult = \"Invalid\";\n\t}\n \n return enableResult;\n}\n\nfunction getReportStatus(bit) {\n var reportResult = \"Invalid\";\n \n switch (bit5) {\n case 0:\n reportResult = \"Ignore\";\n break;\n case 1:\n reportResult = \"Report\";\n break;\n default:\n reportResult = \"Invalid\";\n }\n \n return reportResult;\n}", + "encoder": null, + "tbelEncoder": null, + "updateOnlyKeys": [ + "fPort", + "bandwidth", + "frequency", + "net_id", + "cluster_id", + "cluster_address", + "tenant_address", + "device_id", + "join_eui", + "eui", + "channel", + "devAddr", + "spreadingFactor", + "codeRate", + "tenantId", + "applicationId", + "battery" + ] + }, + "additionalInfo": { + "description": "" + }, + "edgeTemplate": false +} \ No newline at end of file diff --git a/VENDORS/Tektelic/Kiwi/ThingsStackIndustries/uplink/metadata.json b/VENDORS/Tektelic/Kiwi/ThingsStackIndustries/uplink/metadata.json new file mode 100644 index 00000000..23f54b34 --- /dev/null +++ b/VENDORS/Tektelic/Kiwi/ThingsStackIndustries/uplink/metadata.json @@ -0,0 +1,4 @@ +{ + "integrationName": "ChirpStack integration", + "includeGatewayInfo": "false" +} \ No newline at end of file diff --git a/VENDORS/Tektelic/Kiwi/ThingsStackIndustries/uplink/payload.json b/VENDORS/Tektelic/Kiwi/ThingsStackIndustries/uplink/payload.json new file mode 100644 index 00000000..7f8b5359 --- /dev/null +++ b/VENDORS/Tektelic/Kiwi/ThingsStackIndustries/uplink/payload.json @@ -0,0 +1,77 @@ +{ + "end_device_ids": { + "device_id": "eui-1000000000000001", + "application_ids": { + "application_id": "application-tti-name" + }, + "dev_eui": "1000000000000001", + "join_eui": "2000000000000001", + "dev_addr": "20000001" + }, + "correlation_ids": ["as:up:01H0PZDGB1NW6NAPD815NGHPF6", "gs:conn:01H0FJRSXSYT7VKNYXJ89F95XT", "gs:up:host:01H0FJRSY3MZMGPPFBQ4FZV4T8", "gs:uplink:01H0PZDG4HHGFRTXRTXD4PFTH7", "ns:uplink:01H0PZDG4JZ3BM0K6J89EQK1J7", "rpc:/ttn.lorawan.v3.GsNs/HandleUplink:01H0PZDG4J02F85RYFPCNSNXCR", "rpc:/ttn.lorawan.v3.NsAs/HandleUplink:01H0PZDGB081PMP806BJHNHX1A"], + "received_at": "2023-05-18T08:25:26.112483370Z", + "uplink_message": { + "session_key_id": "AYfg8rhha5n+FWx0ZaAprA==", + "f_port": 10, + "f_cnt": 5017, + "frm_payload": "ANNaAL0KCg==", + "rx_metadata": [{ + "gateway_ids": { + "gateway_id": "eui-6A7E111A10000000", + "eui": "6A7E111A10000000" + }, + "time": "2023-05-18T08:25:25.885310Z", + "timestamp": 818273765, + "rssi": -24, + "channel_rssi": -24, + "snr": 12, + "frequency_offset": "671", + "uplink_token": "CiIKIAoUZXVpLTZBN0UxMTFBMTAwMDAwMDASCCThJP/+9k6eEOW7l4YDGgwI9cGXowYQ5KPhrwMgiI2rp+jpOA=", + "channel_index": 2, + "received_at": "2023-05-18T08:25:25.869324983Z" + }, { + "gateway_ids": { + "gateway_id": "packetbroker" + }, + "packet_broker": { + "message_id": "01H0PZDG4MF9AYSMNY44MAVTDH", + "forwarder_net_id": "000013", + "forwarder_tenant_id": "ttn", + "forwarder_cluster_id": "eu1.cloud.thethings.network", + "forwarder_gateway_eui": "6A7E111A10000000", + "forwarder_gateway_id": "eui-6a7e111a10000000", + "home_network_net_id": "000013", + "home_network_tenant_id": "tenant", + "home_network_cluster_id": "eu1.cloud.thethings.industries" + }, + "time": "2023-05-18T08:25:25.885310Z", + "rssi": -24, + "channel_rssi": -24, + "snr": 12, + "frequency_offset": "671", + "uplink_token": "eyJnIjoiWlhsS2FHSkhZMmxQYVVwQ1RWUkpORkl3VGs1VE1XTnBURU5LYkdKdFRXbFBhVXBDVFZSSk5GSXdUazVKYVhkcFlWaFphVTlwU201a01uaGhWVlJvZDFSWFVuRmlSM1JtVFcxT2RVbHBkMmxrUjBadVNXcHZhV05ZY0RKT1IyeExaREpSZVZwR1pIUmpNRXBLVlVoR2RFNVZkR3BWVTBvNUxua3paVVJTWVRaM1lXOU1kbTQwVm5sdmIyWmlPWGN1ZUhCZmVrcElaa3hIWlZadGRVUlFVeTVuYlRaVlZXRXdkakpHV0VKMGJUUjZaMjVXUkVoeGVHRjRaMlJKTlVkS1VsbERhemc1VDNCbk5rVk1iM1JDUkVZM1VWbHdZbEJDTkdOblNqWjBlbkphYUV4MFRVMHhZMVZFTTFac01XdExURUo0YURaMFExTnhhMVJsWWw4eE5FdHlVVXcyZUhsRWFFbEhlakJITXpoTE0xaFdlRzR5VUVjMk4wNUViME5WTkhoTmRrazFZVk5oWkUwd2FXVnFjR294VGtoMFduZHlZMDFxVlVGNmRsbERUazlNY2s5eFdVeFpWMk5XTG1WVFFYVkpNVkptT1U5NWRqUTNhSEoxTUZoalYxRT0iLCJhIjp7ImZuaWQiOiIwMDAwMTMiLCJmdGlkIjoidHRuIiwiZmNpZCI6ImV1MS5jbG91ZC50aGV0aGluZ3MubmV0d29yayJ9fQ==", + "received_at": "2023-05-18T08:25:25.906038642Z" + }], + "settings": { + "data_rate": { + "lora": { + "bandwidth": 125000, + "spreading_factor": 7, + "coding_rate": "4/5" + } + }, + "frequency": "868500000", + "timestamp": 818273765, + "time": "2023-05-18T08:25:25.885310Z" + }, + "received_at": "2023-05-18T08:25:25.906399073Z", + "consumed_airtime": "0.097536s", + "network_ids": { + "net_id": "000013", + "tenant_id": "tenant", + "cluster_id": "eu1", + "cluster_address": "eu1.cloud.thethings.industries", + "tenant_address": "tenant.eu1.cloud.thethings.industries" + } + } +} \ No newline at end of file diff --git a/VENDORS/Tektelic/Kiwi/ThingsStackIndustries/uplink/payload_1.json b/VENDORS/Tektelic/Kiwi/ThingsStackIndustries/uplink/payload_1.json new file mode 100644 index 00000000..1e860e20 --- /dev/null +++ b/VENDORS/Tektelic/Kiwi/ThingsStackIndustries/uplink/payload_1.json @@ -0,0 +1,77 @@ +{ + "end_device_ids": { + "device_id": "eui-1000000000000001", + "application_ids": { + "application_id": "application-tti-name" + }, + "dev_eui": "1000000000000001", + "join_eui": "2000000000000001", + "dev_addr": "20000001" + }, + "correlation_ids": ["as:up:01H0PZDGB1NW6NAPD815NGHPF6", "gs:conn:01H0FJRSXSYT7VKNYXJ89F95XT", "gs:up:host:01H0FJRSY3MZMGPPFBQ4FZV4T8", "gs:uplink:01H0PZDG4HHGFRTXRTXD4PFTH7", "ns:uplink:01H0PZDG4JZ3BM0K6J89EQK1J7", "rpc:/ttn.lorawan.v3.GsNs/HandleUplink:01H0PZDG4J02F85RYFPCNSNXCR", "rpc:/ttn.lorawan.v3.NsAs/HandleUplink:01H0PZDGB081PMP806BJHNHX1A"], + "received_at": "2023-05-18T08:25:26.112483370Z", + "uplink_message": { + "session_key_id": "AYfg8rhha5n+FWx0ZaAprA==", + "f_port": 10, + "f_cnt": 5017, + "frm_payload": "AQQFeQICAtU=", + "rx_metadata": [{ + "gateway_ids": { + "gateway_id": "eui-6A7E111A10000000", + "eui": "6A7E111A10000000" + }, + "time": "2023-05-18T08:25:25.885310Z", + "timestamp": 818273765, + "rssi": -24, + "channel_rssi": -24, + "snr": 12, + "frequency_offset": "671", + "uplink_token": "CiIKIAoUZXVpLTZBN0UxMTFBMTAwMDAwMDASCCThJP/+9k6eEOW7l4YDGgwI9cGXowYQ5KPhrwMgiI2rp+jpOA=", + "channel_index": 2, + "received_at": "2023-05-18T08:25:25.869324983Z" + }, { + "gateway_ids": { + "gateway_id": "packetbroker" + }, + "packet_broker": { + "message_id": "01H0PZDG4MF9AYSMNY44MAVTDH", + "forwarder_net_id": "000013", + "forwarder_tenant_id": "ttn", + "forwarder_cluster_id": "eu1.cloud.thethings.network", + "forwarder_gateway_eui": "6A7E111A10000000", + "forwarder_gateway_id": "eui-6a7e111a10000000", + "home_network_net_id": "000013", + "home_network_tenant_id": "tenant", + "home_network_cluster_id": "eu1.cloud.thethings.industries" + }, + "time": "2023-05-18T08:25:25.885310Z", + "rssi": -24, + "channel_rssi": -24, + "snr": 12, + "frequency_offset": "671", + "uplink_token": "eyJnIjoiWlhsS2FHSkhZMmxQYVVwQ1RWUkpORkl3VGs1VE1XTnBURU5LYkdKdFRXbFBhVXBDVFZSSk5GSXdUazVKYVhkcFlWaFphVTlwU201a01uaGhWVlJvZDFSWFVuRmlSM1JtVFcxT2RVbHBkMmxrUjBadVNXcHZhV05ZY0RKT1IyeExaREpSZVZwR1pIUmpNRXBLVlVoR2RFNVZkR3BWVTBvNUxua3paVVJTWVRaM1lXOU1kbTQwVm5sdmIyWmlPWGN1ZUhCZmVrcElaa3hIWlZadGRVUlFVeTVuYlRaVlZXRXdkakpHV0VKMGJUUjZaMjVXUkVoeGVHRjRaMlJKTlVkS1VsbERhemc1VDNCbk5rVk1iM1JDUkVZM1VWbHdZbEJDTkdOblNqWjBlbkphYUV4MFRVMHhZMVZFTTFac01XdExURUo0YURaMFExTnhhMVJsWWw4eE5FdHlVVXcyZUhsRWFFbEhlakJITXpoTE0xaFdlRzR5VUVjMk4wNUViME5WTkhoTmRrazFZVk5oWkUwd2FXVnFjR294VGtoMFduZHlZMDFxVlVGNmRsbERUazlNY2s5eFdVeFpWMk5XTG1WVFFYVkpNVkptT1U5NWRqUTNhSEoxTUZoalYxRT0iLCJhIjp7ImZuaWQiOiIwMDAwMTMiLCJmdGlkIjoidHRuIiwiZmNpZCI6ImV1MS5jbG91ZC50aGV0aGluZ3MubmV0d29yayJ9fQ==", + "received_at": "2023-05-18T08:25:25.906038642Z" + }], + "settings": { + "data_rate": { + "lora": { + "bandwidth": 125000, + "spreading_factor": 7, + "coding_rate": "4/5" + } + }, + "frequency": "868500000", + "timestamp": 818273765, + "time": "2023-05-18T08:25:25.885310Z" + }, + "received_at": "2023-05-18T08:25:25.906399073Z", + "consumed_airtime": "0.097536s", + "network_ids": { + "net_id": "000013", + "tenant_id": "tenant", + "cluster_id": "eu1", + "cluster_address": "eu1.cloud.thethings.industries", + "tenant_address": "tenant.eu1.cloud.thethings.industries" + } + } +} \ No newline at end of file diff --git a/VENDORS/Tektelic/Kiwi/ThingsStackIndustries/uplink/result.json b/VENDORS/Tektelic/Kiwi/ThingsStackIndustries/uplink/result.json new file mode 100644 index 00000000..958d1f70 --- /dev/null +++ b/VENDORS/Tektelic/Kiwi/ThingsStackIndustries/uplink/result.json @@ -0,0 +1,27 @@ +{ + "deviceName": "eui-1000000000000001", + "deviceType": "Kiwi", + "attributes": { + "eui": "1000000000000001", + "fPort": 10, + "applicationId": "application-tti-name", + "devAddr": "20000001", + "spreadingFactor": 7, + "codeRate": "4/5", + "tenantId": "tenant", + "device_id": "eui-1000000000000001", + "join_eui": "2000000000000001", + "net_id": "000013", + "cluster_id": "eu1", + "cluster_address": "eu1.cloud.thethings.industries", + "bandwidth": 125000, + "frequency": "868500000" + }, + "telemetry": [{ + "ts": 1684398325906, + "values": { + "rem_batt_capacity": 90, + "rem_batt_days": 2570 + } + }] +} \ No newline at end of file diff --git a/VENDORS/Tektelic/Kiwi/ThingsStackIndustries/uplink/result_1.json b/VENDORS/Tektelic/Kiwi/ThingsStackIndustries/uplink/result_1.json new file mode 100644 index 00000000..dd6e8fb6 --- /dev/null +++ b/VENDORS/Tektelic/Kiwi/ThingsStackIndustries/uplink/result_1.json @@ -0,0 +1,29 @@ +{ + "deviceName": "eui-1000000000000001", + "deviceType": "Kiwi", + "attributes": { + "eui": "1000000000000001", + "fPort": 10, + "applicationId": "application-tti-name", + "devAddr": "20000001", + "spreadingFactor": 7, + "codeRate": "4/5", + "tenantId": "tenant", + "device_id": "eui-1000000000000001", + "join_eui": "2000000000000001", + "net_id": "000013", + "cluster_id": "eu1", + "cluster_address": "eu1.cloud.thethings.industries", + "bandwidth": 125000, + "frequency": "868500000" + }, + "telemetry": [{ + "ts": 1684398325906, + "values": { + "input1_frequency_to_moisture": "Dry", + "input1_frequency": 1401, + "input2_voltage_to_temp": 22.6, + "input2_voltage": 0.725 + } + }] +} \ No newline at end of file diff --git a/VENDORS/Tektelic/Kiwi/info.json b/VENDORS/Tektelic/Kiwi/info.json new file mode 100644 index 00000000..7396f7f4 --- /dev/null +++ b/VENDORS/Tektelic/Kiwi/info.json @@ -0,0 +1,5 @@ +{ + "url": "https://tektelic.com/products/sensors/kiwi-iot-agriculture-sensor/", + "label": "KIWI: Versatile soil and ambient environment sensor for smart agriculture deployments", + "description": "The KIWI model of the Agricultural Sensor is a multi-purpose LoRaWAN IoT device designed for agricultural use. It supports the connection of up to four analog and two digital probe inputs, enabling remote data capture." +} \ No newline at end of file diff --git a/VENDORS/Tektelic/Kiwi/photo.png b/VENDORS/Tektelic/Kiwi/photo.png new file mode 100644 index 0000000000000000000000000000000000000000..176826ee74f99bcccd04ab312312516f503ec740 GIT binary patch literal 126813 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

ES7C!He9Q@u|Sn@hzLshN57R{uC@#z7%9 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 z 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 MPgg&ebxsLQ08uZ&#sB~S literal 0 HcmV?d00001 From 230ed70d00f68985c24eb6ad04398402434b8651 Mon Sep 17 00:00:00 2001 From: thingsboard017 Date: Thu, 19 Dec 2024 17:26:27 +0200 Subject: [PATCH 12/33] Added 4 LNS integrations for Aura --- .../Aura/ChirpStack/uplink/converter.json | 39 +++++++++ .../Aura/ChirpStack/uplink/metadata.json | 4 + .../Aura/ChirpStack/uplink/payload.json | 48 +++++++++++ .../Aura/ChirpStack/uplink/result.json | 27 ++++++ .../Aura/LORIOT/uplink/converter.json | 29 +++++++ .../Tektelic/Aura/LORIOT/uplink/metadata.json | 4 + .../Tektelic/Aura/LORIOT/uplink/payload.json | 17 ++++ .../Tektelic/Aura/LORIOT/uplink/result.json | 17 ++++ .../uplink/converter.json | 39 +++++++++ .../ThingsStackCommunity/uplink/metadata.json | 4 + .../ThingsStackCommunity/uplink/payload.json | 54 ++++++++++++ .../ThingsStackCommunity/uplink/result.json | 28 +++++++ .../uplink/converter.json | 40 +++++++++ .../uplink/metadata.json | 4 + .../ThingsStackIndustries/uplink/payload.json | 77 ++++++++++++++++++ .../ThingsStackIndustries/uplink/result.json | 28 +++++++ VENDORS/Tektelic/Aura/info.json | 5 ++ VENDORS/Tektelic/Aura/photo.png | Bin 0 -> 113371 bytes 18 files changed, 464 insertions(+) create mode 100644 VENDORS/Tektelic/Aura/ChirpStack/uplink/converter.json create mode 100644 VENDORS/Tektelic/Aura/ChirpStack/uplink/metadata.json create mode 100644 VENDORS/Tektelic/Aura/ChirpStack/uplink/payload.json create mode 100644 VENDORS/Tektelic/Aura/ChirpStack/uplink/result.json create mode 100644 VENDORS/Tektelic/Aura/LORIOT/uplink/converter.json create mode 100644 VENDORS/Tektelic/Aura/LORIOT/uplink/metadata.json create mode 100644 VENDORS/Tektelic/Aura/LORIOT/uplink/payload.json create mode 100644 VENDORS/Tektelic/Aura/LORIOT/uplink/result.json create mode 100644 VENDORS/Tektelic/Aura/ThingsStackCommunity/uplink/converter.json create mode 100644 VENDORS/Tektelic/Aura/ThingsStackCommunity/uplink/metadata.json create mode 100644 VENDORS/Tektelic/Aura/ThingsStackCommunity/uplink/payload.json create mode 100644 VENDORS/Tektelic/Aura/ThingsStackCommunity/uplink/result.json create mode 100644 VENDORS/Tektelic/Aura/ThingsStackIndustries/uplink/converter.json create mode 100644 VENDORS/Tektelic/Aura/ThingsStackIndustries/uplink/metadata.json create mode 100644 VENDORS/Tektelic/Aura/ThingsStackIndustries/uplink/payload.json create mode 100644 VENDORS/Tektelic/Aura/ThingsStackIndustries/uplink/result.json create mode 100644 VENDORS/Tektelic/Aura/info.json create mode 100644 VENDORS/Tektelic/Aura/photo.png diff --git a/VENDORS/Tektelic/Aura/ChirpStack/uplink/converter.json b/VENDORS/Tektelic/Aura/ChirpStack/uplink/converter.json new file mode 100644 index 00000000..3601cc1d --- /dev/null +++ b/VENDORS/Tektelic/Aura/ChirpStack/uplink/converter.json @@ -0,0 +1,39 @@ +{ + "name": "ChirpStack Uplink Decoder for Aura", + "type": "UPLINK", + "debugMode": false, + "debugSettings": { + "failuresEnabled": true, + "allEnabled": false, + "allEnabledUntil": 1733331880270 + }, + "configuration": { + "scriptLang": "TBEL", + "decoder": null, + "tbelDecoder": "var data = decodeToJson(payload);\nvar deviceName = data.deviceInfo.deviceName + \" \" + data.deviceInfo.devEui;\nvar deviceType = \"Aura\";\nvar groupName = null; // If groupName is not null - created device will be added to the entity group with such name.\nvar customerName = null; // If customerName is not null - created devices will be assigned to customer with such name. \n\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// If you want to parse incoming data somehow, you can add your code to this function.\n// input: bytes\n// expected output:\n// {\n// \"attributes\": {\"attributeKey\": \"attributeValue\"},\n// \"telemetry\": [{\"ts\": 1...1, \"values\": {\"telemetryKey\":\"telemetryValue\"}, {\"ts\": 1...2, \"values\": {\"telemetryKey\":\"telemetryValue\"}}]\n// }\n\nfunction decodePayload(input) {\n var output = {\n attributes: {},\n telemetry: []\n };\n \n // --- Decoding code --- //\n var decoded = {};\n var fPort = data.fPort;\n if(fPort == 10) {\n for(var i = 0; i < input.length - 2; ) {\n var key_1 = input[i++] & 0xff;\n var key_2 = input[i++] & 0xff;\n \n if(key_1 == 0x00 && key_2 == 0xFE) {\n decoded.energy_consumption_meter_elapsed = parseBytesToInt(input, i, 4);\n decoded.energy_consumption_meter_consumed = parseBytesToInt(input, i + 4, 4);\n i += 8;\n }\n else if(key_1 == 0x00 && key_2 == 0x00) {\n decoded.energy_consumption_meter_status = parseBytesToInt(input, i, 1);\n if(decoded.energy_consumption_meter_status != 0) {\n decoded.energy_consumption_meter_status != 1;\n }\n }\n else if(key_1 == 0x00 && key_2 == 0x74) {\n decoded.voltmeter = (input[i] << 8) | (input[i + 1] & 0xFF);\n if (decoded.voltmeter != 65535) {\n decoded.voltmeter = decoded.voltmeter * 10;\n }\n \n i += 2;\n }\n else if(key_1 == 0x00 && key_2 == 0x75) {\n decoded.voltmeter = (input[i] << 8) | (input[i + 1] & 0xFF);\n if (decoded.ammeter != 65535) {\n decoded.ammeter = decoded.ammeter * 10;\n }\n \n i += 2;\n }\n else if(key_1 == 0x00 && key_2 == 0x80) {\n decoded.real_power = (input[i] << 8) | (input[i + 1] & 0xFF);\n if (decoded.real_power != 65535) {\n decoded.real_power = decoded.real_power * 10;\n }\n \n i += 2;\n }\n else if(key_1 == 0x01 && key_2 == 0x80) {\n decoded.apparent_power = (input[i] << 8) | (input[i + 1] & 0xFF);\n if (decoded.apparent_power != 65535) {\n decoded.apparent_power = decoded.apparent_power * 10;\n }\n \n i += 2;\n }\n else if(key_1 == 0x00 && key_2 == 0x81) {\n decoded.power_factor_meter = input[i] & 0xFF;\n if (decoded.power_factor_meter != 65535) {\n decoded.power_factor_meter = decoded.power_factor_meter * 100;\n }\n \n i += 1;\n }\n else if(key_1 == 0x00 && key_2 == 0x01) {\n decoded.relay_status = input[i] & 0xFF;\n \n if (decoded.relay_status != 0) {\n decoded.relay_status = 1;\n }\n \n i += 1;\n }\n }\n }\n else if (fPort == 100) {\n for(var i = 0; i < input.length -1; ) {\n var key = input[i++] & 0xff;\n \n if(key == 0x00) {\n output.attributes.eui = bytesToHex(java.util.Arrays.copyRange(input, i, i + 8));\n i += 8;\n }\n else if(key == 0x01) {\n output.attributes.app_eui = bytesToHex(java.util.Arrays.copyRange(input, i, i + 8));\n\t\t\t\ti += 8;\n }\n else if (key == 0x02) {\n output.attributes.app_key = bytesToHex(java.util.Arrays.copyRange(input, i, i + 16));\n i += 16;\n }\n else if (key == 0x03) {\n output.attributes.devAddr = bytesToHex(java.util.Arrays.copyRange(input, i, i + 4));\n i += 4;\n }\n else if(key == 0x04) {\n output.attributes.network_session_key = bytesToHex(java.util.Arrays.copyRange(input, i, i + 16));\n i += 16;\n }\n else if(key == 0x05) {\n output.attributes.app_session_key = bytesToHex(java.util.Arrays.copyRange(input, i, i + 16));\n i += 16;\n }\n else if(key == 0x10) {\n output.attributes.loramac_join_mode = (input[i] >> 7) & 1;\n i += 2;\n }\n else if (key == 0x11) {\n var val = (input[i] >> 4) & 0x0F;\n \n if(val == 0x0C) {\n output.attributes.lora_class = \"Class C\";\n }\n else if(val == 0x0B) {\n output.attributes.lora_class = \"Class B\";\n }\n else if(val == 0x0A) {\n output.attributes.lora_class = \"Class F\";\n }\n else {\n output.attributes.lora_class = \"Invalid\";\n }\n\t\t\t\t\n\t\t\t\toutput.attributes.confirm_mode = (input[i] >> 8) & 1; \n\t\t\t\toutput.attributes.sync_word = (input[i] >> 9) & 1;\n\t\t\t\toutput.attributes.duty_cycle = (input[i] >> 10) & 1;\n\t\t\t\toutput.attributes.adr = (input[i] >> 11) & 1; \n\t\t\t\t\n\t\t\t\ti += 2;\n }\n else if (key == 0x12) {\n output.attributes.dr_number = (((input[i] << 8) | input[i + 1]) >> 8) & 0xF;\n output.attributes.tx_power_number = ((input[i] << 8) | input[i + 1]) & 0xF;\n \n i +=2;\n }\n else if (key == 0x13) {\n output.attributes.frequency = (((input[i] << 32) | (input[i + 1] << 24) | (input[i + 2] << 16) | (input[i + 3] << 8) | input[i + 4]) >> 8) & 0xFFFFFFFF;\n output.attributes.dr_number_rx2 = input[i + 4] & 0xFF;\n \n i += 5;\n }\n else if(key == 0x19) {\n output.attributes.netid_msb = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if (key == 0x20) {\n output.attributes.seconds_per_core_tick = parseBytesToInt(input, i, 4);\n i += 4;\n }\n else if(key == 0x21) {\n output.attributes.tick_per_battery = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x71) {\n output.attributes.app_major_version = input[i];\n\t\t\t\toutput.attributes.app_minor_version = input[i + 1];\n\t\t\t\toutput.attributes.app_revision = input[i + 2];\n\t\t\t\toutput.attributes.loramac_major_version = input[i + 3];\n\t\t\t\toutput.attributes.loramac_minor_version = input[i + 4];\n\t\t\t\toutput.attributes.loramac_revision = input[i + 5];\n\t\t\t\toutput.attributes.region = input[i + 7];\n\t\t\t\ti += 7;\n }\n }\n }\n\n output.telemetry = [{\n ts: timestamp,\n values: decoded\n }];\n // --- Decoding code --- //\n return output;\n}\n\n// --- attributes and telemetry objects ---\nvar telemetry = [];\nvar attributes = {};\n// --- attributes and telemetry objects ---\n\n// --- Timestamp parsing\nvar dateString = data.time;\ntimestamp = parseDateToTimestamp(dateString);\n// --- Timestamp parsing\n\n// Passing incoming bytes to decodePayload function, to get custom decoding\nvar customDecoding = decodePayload(base64ToBytes(data.data));\n\n\nattributes.eui = data.deviceInfo.devEui;\n\n// Collecting data to result\nif (customDecoding.?telemetry.size() > 0) {\n if (customDecoding.telemetry instanceof java.util.ArrayList) {\n foreach(telemetryObj: customDecoding.telemetry) {\n if (telemetryObj.ts != null && telemetryObj.values != null) {\n telemetry.add(telemetryObj);\n }\n }\n } else {\n telemetry.putAll(customDecoding.telemetry);\n }\n}\n\nif (customDecoding.?attributes.size() > 0) {\n attributes.putAll(customDecoding.attributes);\n}\n\n// You can add some keys manually to attributes or telemetry\nattributes.eui = data.deviceInfo.?devEui;\nattributes.devAddr = data.devAddr;\nattributes.fPort = data.fPort;\nattributes.applicationId = data.deviceInfo.?applicationId;\nattributes.applicationName = data.deviceInfo.?applicationName;\nattributes.tenantId = data.deviceInfo.?tenantId;\nattributes.tenantName = data.deviceInfo.?tenantName;\nattributes.deviceProfileId = data.deviceInfo.?deviceProfileId;\nattributes.deviceProfileName = data.deviceInfo.?deviceProfileName;\nattributes.frequency = data.txInfo.?frequency;\nattributes.bandwidth = data.txInfo.?modulation.?lora.?bandwidth;\nattributes.spreadingFactor = data.txInfo.?modulation.?lora.?spreadingFactor;\nattributes.codeRate = data.txInfo.?modulation.?lora.?codeRate;\n\nif(Boolean.parseBoolean(metadata[\"includeGatewayInfo\"])) {\n var gatewayInfo = getGatewayInfo();\n var addDataToTelemetry = {};\n addDataToTelemetry.snr = gatewayInfo.snr;\n addDataToTelemetry.rssi = gatewayInfo.rssi;\n addDataToTelemetry.channel = gatewayInfo.channel;\n addDataToTelemetry.rfChain = gatewayInfo.rfChain;\n addDataToTelemetry.fCnt = data.fCnt;\n \n telemetry = processTelemetryData(telemetry, addDataToTelemetry);\n}\n\nvar result = {\n deviceName: deviceName,\n deviceType: deviceType,\n // assetName: assetName,\n // assetType: assetType,\n attributes: attributes,\n telemetry: telemetry\n};\n\naddAdditionalInfoForDeviceMsg(result, customerName, groupName);\n\nreturn result;\n\nfunction addAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName) {\n if (customerName != null) {\n deviceInfo.customerName = customerName;\n }\n if (groupName != null) {\n deviceInfo.groupName = groupName;\n }\n}\n\nfunction parseDateToTimestamp(dateString) {\n var date = new Date(dateString);\n var timestamp = date.getTime();\n \n // If we cannot parse timestamp - we will use the current timestamp\n if (timestamp == -1) {\n timestamp = Date.now();\n }\n \n return timestamp;\n}\n\nfunction getGatewayInfo() {\n var gatewayList = data.rxInfo;\n var maxRssi = Integer.MIN_VALUE;\n var gatewayInfo = {};\n \n foreach (gateway : gatewayList) {\n if(gateway.rssi > maxRssi) {\n maxRssi = gateway.rssi;\n gatewayInfo = gateway;\n }\n }\n \n return gatewayInfo;\n}\n\nfunction processTelemetryData(telemetry, addDataToTelemetry) {\n if (telemetry.size >= 1) {\n telemetry = addDataToTelemetries(telemetry, addDataToTelemetry);\n }\n else {\n telemetry.add(addDataToTelemetry);\n }\n \n return telemetry;\n}\n\nfunction addDataToTelemetries(telemetries, addDataToTelemetry) {\n foreach(telemetry : telemetries) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[\"values\"].keys.contains(element.key)) {\n telemetry[\"values\"][element.key] = element.value;\n }\n } \n }\n \n return telemetries;\n}", + "encoder": null, + "tbelEncoder": null, + "updateOnlyKeys": [ + "tenantId", + "tenantName", + "applicationId", + "applicationName", + "deviceProfileId", + "deviceProfileName", + "devAddr", + "fPort", + "frequency", + "bandwidth", + "spreadingFactor", + "codeRate", + "channel", + "rfChain", + "eui", + "battery" + ] + }, + "additionalInfo": { + "description": "" + }, + "edgeTemplate": false +} \ No newline at end of file diff --git a/VENDORS/Tektelic/Aura/ChirpStack/uplink/metadata.json b/VENDORS/Tektelic/Aura/ChirpStack/uplink/metadata.json new file mode 100644 index 00000000..23f54b34 --- /dev/null +++ b/VENDORS/Tektelic/Aura/ChirpStack/uplink/metadata.json @@ -0,0 +1,4 @@ +{ + "integrationName": "ChirpStack integration", + "includeGatewayInfo": "false" +} \ No newline at end of file diff --git a/VENDORS/Tektelic/Aura/ChirpStack/uplink/payload.json b/VENDORS/Tektelic/Aura/ChirpStack/uplink/payload.json new file mode 100644 index 00000000..1ac72155 --- /dev/null +++ b/VENDORS/Tektelic/Aura/ChirpStack/uplink/payload.json @@ -0,0 +1,48 @@ +{ + "deduplicationId": "57433366-50a6-4dc2-8145-2df1bbc70d9e", + "time": "2023-05-22T07:47:05.404859+00:00", + "deviceInfo": { + "tenantId": "52f14cd4-c6f1-4fbd-8f87-4025e1d49242", + "tenantName": "ChirpStack", + "applicationId": "ca739e26-7b67-4f14-b69e-d568c22a5a75", + "applicationName": "Chirpstack application", + "deviceProfileId": "605d08d4-65f5-4d2c-8a5a-3d2457662f79", + "deviceProfileName": "Chirpstack default device profile", + "deviceName": "Device name", + "devEui": "1000000000000001", + "tags": {} + }, + "devAddr": "20000001", + "adr": true, + "dr": 5, + "fCnt": 4, + "fPort": 10, + "confirmed": false, + "data": "AP4AAVGAAABqUAAAAA==", + "rxInfo": [{ + "gatewayId": "6a7e111a10000000", + "uplinkId": 24022, + "time": "2023-05-22T07:47:05.404859+00:00", + "rssi": -35, + "snr": 11.5, + "channel": 2, + "rfChain": 1, + "location": {}, + "context": "EFwMtA==", + "metadata": { + "region_common_name": "EU868", + "region_config_id": "eu868" + }, + "crcStatus": "CRC_OK" + }], + "txInfo": { + "frequency": 868500000, + "modulation": { + "lora": { + "bandwidth": 125000, + "spreadingFactor": 7, + "codeRate": "CR_4_5" + } + } + } +} \ No newline at end of file diff --git a/VENDORS/Tektelic/Aura/ChirpStack/uplink/result.json b/VENDORS/Tektelic/Aura/ChirpStack/uplink/result.json new file mode 100644 index 00000000..d723b7d5 --- /dev/null +++ b/VENDORS/Tektelic/Aura/ChirpStack/uplink/result.json @@ -0,0 +1,27 @@ +{ + "deviceName": "Device name 1000000000000001", + "deviceType": "Aura", + "attributes": { + "eui": "1000000000000001", + "devAddr": "20000001", + "fPort": 10, + "applicationId": "ca739e26-7b67-4f14-b69e-d568c22a5a75", + "applicationName": "Chirpstack application", + "tenantId": "52f14cd4-c6f1-4fbd-8f87-4025e1d49242", + "tenantName": "ChirpStack", + "deviceProfileId": "605d08d4-65f5-4d2c-8a5a-3d2457662f79", + "deviceProfileName": "Chirpstack default device profile", + "frequency": 868500000, + "bandwidth": 125000, + "spreadingFactor": 7, + "codeRate": "CR_4_5" + }, + "telemetry": [{ + "ts": 1684741625404, + "values": { + "energy_consumption_meter_elapsed": 86400, + "energy_consumption_meter_consumed": 27216, + "energy_consumption_meter_status": 0 + } + }] +} \ No newline at end of file diff --git a/VENDORS/Tektelic/Aura/LORIOT/uplink/converter.json b/VENDORS/Tektelic/Aura/LORIOT/uplink/converter.json new file mode 100644 index 00000000..7de9b7ad --- /dev/null +++ b/VENDORS/Tektelic/Aura/LORIOT/uplink/converter.json @@ -0,0 +1,29 @@ +{ + "name": "Loriot Uplink Decoder for Aura", + "type": "UPLINK", + "debugMode": false, + "debugSettings": { + "failuresEnabled": true, + "allEnabled": false, + "allEnabledUntil": 1733331880270 + }, + "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);\nvar deviceName = data.EUI;\nvar deviceType = \"Aura\";\nvar groupName = null; // If groupName is not null - created device will be added to the entity group with such name.\nvar customerName = null; // If customerName is not null - created devices will be assigned to customer with such name. \n\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// If you want to parse incoming data somehow, you can add your code to this function.\n// input: bytes\n// expected output:\n// {\n// \"attributes\": {\"attributeKey\": \"attributeValue\"},\n// \"telemetry\": {\"telemetryKey\": \"telemetryValue\"}\n// }\n\nfunction decodePayload(input) {\n var output = { attributes: {}, telemetry: []};\n \n var decoded = {};\n var fPort = data.port;\n if(fPort == 10) {\n for(var i = 0; i < input.length - 2; ) {\n var key_1 = input[i++] & 0xff;\n var key_2 = input[i++] & 0xff;\n \n if(key_1 == 0x00 && key_2 == 0xFE) {\n decoded.energy_consumption_meter_elapsed = parseBytesToInt(input, i, 4);\n decoded.energy_consumption_meter_consumed = parseBytesToInt(input, i + 4, 4);\n i += 8;\n }\n else if(key_1 == 0x00 && key_2 == 0x00) {\n decoded.energy_consumption_meter_status = parseBytesToInt(input, i, 1);\n if(decoded.energy_consumption_meter_status != 0) {\n decoded.energy_consumption_meter_status != 1;\n }\n }\n else if(key_1 == 0x00 && key_2 == 0x74) {\n decoded.voltmeter = (input[i] << 8) | (input[i + 1] & 0xFF);\n if (decoded.voltmeter != 65535) {\n decoded.voltmeter = decoded.voltmeter * 10;\n }\n \n i += 2;\n }\n else if(key_1 == 0x00 && key_2 == 0x75) {\n decoded.voltmeter = (input[i] << 8) | (input[i + 1] & 0xFF);\n if (decoded.ammeter != 65535) {\n decoded.ammeter = decoded.ammeter * 10;\n }\n \n i += 2;\n }\n else if(key_1 == 0x00 && key_2 == 0x80) {\n decoded.real_power = (input[i] << 8) | (input[i + 1] & 0xFF);\n if (decoded.real_power != 65535) {\n decoded.real_power = decoded.real_power * 10;\n }\n \n i += 2;\n }\n else if(key_1 == 0x01 && key_2 == 0x80) {\n decoded.apparent_power = (input[i] << 8) | (input[i + 1] & 0xFF);\n if (decoded.apparent_power != 65535) {\n decoded.apparent_power = decoded.apparent_power * 10;\n }\n \n i += 2;\n }\n else if(key_1 == 0x00 && key_2 == 0x81) {\n decoded.power_factor_meter = input[i] & 0xFF;\n if (decoded.power_factor_meter != 65535) {\n decoded.power_factor_meter = decoded.power_factor_meter * 100;\n }\n \n i += 1;\n }\n else if(key_1 == 0x00 && key_2 == 0x01) {\n decoded.relay_status = input[i] & 0xFF;\n \n if (decoded.relay_status != 0) {\n decoded.relay_status = 1;\n }\n \n i += 1;\n }\n }\n }\n else if (fPort == 100) {\n for(var i = 0; i < input.length -1; ) {\n var key = input[i++] & 0xff;\n \n if(key == 0x00) {\n output.attributes.eui = bytesToHex(java.util.Arrays.copyRange(input, i, i + 8));\n i += 8;\n }\n else if(key == 0x01) {\n output.attributes.app_eui = bytesToHex(java.util.Arrays.copyRange(input, i, i + 8));\n\t\t\t\ti += 8;\n }\n else if (key == 0x02) {\n output.attributes.app_key = bytesToHex(java.util.Arrays.copyRange(input, i, i + 16));\n i += 16;\n }\n else if (key == 0x03) {\n output.attributes.devAddr = bytesToHex(java.util.Arrays.copyRange(input, i, i + 4));\n i += 4;\n }\n else if(key == 0x04) {\n output.attributes.network_session_key = bytesToHex(java.util.Arrays.copyRange(input, i, i + 16));\n i += 16;\n }\n else if(key == 0x05) {\n output.attributes.app_session_key = bytesToHex(java.util.Arrays.copyRange(input, i, i + 16));\n i += 16;\n }\n else if(key == 0x10) {\n output.attributes.loramac_join_mode = (input[i] >> 7) & 1;\n i += 2;\n }\n else if (key == 0x11) {\n var val = (input[i] >> 4) & 0x0F;\n \n if(val == 0x0C) {\n output.attributes.lora_class = \"Class C\";\n }\n else if(val == 0x0B) {\n output.attributes.lora_class = \"Class B\";\n }\n else if(val == 0x0A) {\n output.attributes.lora_class = \"Class F\";\n }\n else {\n output.attributes.lora_class = \"Invalid\";\n }\n\t\t\t\t\n\t\t\t\toutput.attributes.confirm_mode = (input[i] >> 8) & 1; \n\t\t\t\toutput.attributes.sync_word = (input[i] >> 9) & 1;\n\t\t\t\toutput.attributes.duty_cycle = (input[i] >> 10) & 1;\n\t\t\t\toutput.attributes.adr = (input[i] >> 11) & 1; \n\t\t\t\t\n\t\t\t\ti += 2;\n }\n else if (key == 0x12) {\n output.attributes.dr_number = (((input[i] << 8) | input[i + 1]) >> 8) & 0xF;\n output.attributes.tx_power_number = ((input[i] << 8) | input[i + 1]) & 0xF;\n \n i +=2;\n }\n else if (key == 0x13) {\n output.attributes.frequency = (((input[i] << 32) | (input[i + 1] << 24) | (input[i + 2] << 16) | (input[i + 3] << 8) | input[i + 4]) >> 8) & 0xFFFFFFFF;\n output.attributes.dr_number_rx2 = input[i + 4] & 0xFF;\n \n i += 5;\n }\n else if(key == 0x19) {\n output.attributes.netid_msb = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if (key == 0x20) {\n output.attributes.seconds_per_core_tick = parseBytesToInt(input, i, 4);\n i += 4;\n }\n else if(key == 0x21) {\n output.attributes.tick_per_battery = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x71) {\n output.attributes.app_major_version = input[i];\n\t\t\t\toutput.attributes.app_minor_version = input[i + 1];\n\t\t\t\toutput.attributes.app_revision = input[i + 2];\n\t\t\t\toutput.attributes.loramac_major_version = input[i + 3];\n\t\t\t\toutput.attributes.loramac_minor_version = input[i + 4];\n\t\t\t\toutput.attributes.loramac_revision = input[i + 5];\n\t\t\t\toutput.attributes.region = input[i + 7];\n\t\t\t\ti += 7;\n }\n }\n }\n \n output.telemetry = [{\n ts: timestamp,\n values: decoded\n }];\n\n // --- Decoding code --- //\n return output;\n}\n\n// --- attributes and telemetry objects ---\nvar telemetry = [];\nvar attributes = {};\n// --- attributes and telemetry objects ---\n\n// --- Timestamp parsing\ntimestamp = data.ts;\n// --- Timestamp parsing\n\n// Message parsing\n// To avoid paths in the decoded objects we passing false value to function as \"pathInKey\" argument.\n// Warning: pathInKey can cause already found fields to be overwritten with the last value found.\n\nvar uplinkDataList = [];\n\n// Passing incoming bytes to decodePayload function, to get custom decoding\nvar customDecoding = decodePayload(hexToBytes(data.data));\n\n// Collecting data to result\nif (customDecoding.?telemetry.size() > 0) {\n if (customDecoding.telemetry instanceof java.util.ArrayList) {\n foreach(telemetryObj: customDecoding.telemetry) {\n if (telemetryObj.ts != null && telemetryObj.values != null) {\n telemetry.add(telemetryObj);\n }\n }\n } else {\n telemetry.putAll(customDecoding.telemetry);\n }\n}\n\nif (customDecoding.?attributes.size() > 0) {\n attributes.putAll(customDecoding.attributes);\n}\n\n// You can add some keys manually to attributes or telemetry\nattributes.eui = data.EUI;\nattributes.fPort = data.port;\nattributes.frequency = data.freq;\n\nvar isIncludeGatewayInfo = metadata[\"includeGatewayInfo\"];\nif(isIncludeGatewayInfo == true) {\n var addDataToTelemetry = {};\n addDataToTelemetry.rssi = data.rssi;\n addDataToTelemetry.seqno = data.seqno;\n addDataToTelemetry.snr = data.snr;\n addDataToTelemetry.ack = data.ack;\n addDataToTelemetry.toa = data.toa;\n addDataToTelemetry.fCnt = data.fcnt;\n \n telemetry = processTelemetryData(telemetry, addDataToTelemetry);\n}\n\nvar deviceInfo = {\n deviceName: deviceName,\n deviceType: deviceType,\n// assetName: assetName,\n// assetType: assetType,\n attributes: attributes,\n telemetry: telemetry, \n};\n\naddAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName);\n\nuplinkDataList.add(deviceInfo);\n\nvar gatewayDeviceNamePrefix = \"Gateway \";\nvar gatewayDeviceType = \"Lora gateway\";\nvar gatewayGroupName = null; // If gatewayGroupName is not null - created device will be added to the entity group with such name.\n\nif (data.cmd == \"gw\") {\n foreach( gatewayInfo : data.gws ) {\n var addGatewayInfo = {};\n\n // You can add some keys manually telemetry\n addGatewayInfo.rssi = gatewayInfo.rssi;\n addGatewayInfo.snr = gatewayInfo.snr;\n // You can add some keys manually telemetry\n \n var gatewayInfoMsg = {\n deviceName: gatewayDeviceNamePrefix + gatewayInfo.gweui,\n deviceType: gatewayDeviceType,\n telemetry: [{\n \"ts\": gatewayInfo.ts,\n \"values\": addGatewayInfo\n }],\n attributes: {\n eui: gatewayInfo.gweui\n }\n };\n addAdditionalInfoForDeviceMsg(gatewayInfoMsg, customerName, gatewayGroupName);\n uplinkDataList.add(gatewayInfoMsg);\n }\n}\n\nreturn uplinkDataList;\n\nfunction addAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName) {\n if (customerName != null) {\n deviceInfo.customerName = customerName;\n }\n if (groupName != null) {\n deviceInfo.groupName = groupName;\n }\n}\n\nfunction processTelemetryData(telemetry, addDataToTelemetry) {\n if (telemetry.size >= 1) {\n telemetry = addDataToTelemetries(telemetry, addDataToTelemetry);\n }\n else {\n telemetry.add(addDataToTelemetry);\n }\n \n return telemetry;\n}\n\nfunction addDataToTelemetries(telemetries, addDataToTelemetry) {\n foreach(telemetry : telemetries) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[\"values\"].keys.contains(element.key)) {\n telemetry[\"values\"][element.key] = element.value;\n }\n } \n }\n \n return telemetries;\n}", + "encoder": null, + "tbelEncoder": null, + "updateOnlyKeys": [ + "fPort", + "ack", + "eui", + "frequency", + "dr", + "battery" + ] + }, + "additionalInfo": { + "description": "" + }, + "edgeTemplate": false +} \ No newline at end of file diff --git a/VENDORS/Tektelic/Aura/LORIOT/uplink/metadata.json b/VENDORS/Tektelic/Aura/LORIOT/uplink/metadata.json new file mode 100644 index 00000000..ae2ee743 --- /dev/null +++ b/VENDORS/Tektelic/Aura/LORIOT/uplink/metadata.json @@ -0,0 +1,4 @@ +{ + "integrationName": "Loriot integration", + "includeGatewayInfo": "false" +} \ No newline at end of file diff --git a/VENDORS/Tektelic/Aura/LORIOT/uplink/payload.json b/VENDORS/Tektelic/Aura/LORIOT/uplink/payload.json new file mode 100644 index 00000000..0b10cef0 --- /dev/null +++ b/VENDORS/Tektelic/Aura/LORIOT/uplink/payload.json @@ -0,0 +1,17 @@ +{ + "cmd": "rx", + "seqno": 3040, + "EUI": "1000000000000001", + "ts": 1684478801936, + "fcnt": 2, + "port": 10, + "freq": 867500000, + "rssi": -21, + "snr": 10, + "toa": 206, + "dr": "SF9 BW125 4/5", + "ack": false, + "bat": 94, + "offline": false, + "data": "00FE0001518000006A50000000" +} \ No newline at end of file diff --git a/VENDORS/Tektelic/Aura/LORIOT/uplink/result.json b/VENDORS/Tektelic/Aura/LORIOT/uplink/result.json new file mode 100644 index 00000000..c0fbf70e --- /dev/null +++ b/VENDORS/Tektelic/Aura/LORIOT/uplink/result.json @@ -0,0 +1,17 @@ +[{ + "deviceName": "1000000000000001", + "deviceType": "Aura", + "attributes": { + "eui": "1000000000000001", + "fPort": 10, + "frequency": 867500000 + }, + "telemetry": [{ + "ts": 1684478801936, + "values": { + "energy_consumption_meter_elapsed": 86400, + "energy_consumption_meter_consumed": 27216, + "energy_consumption_meter_status": 0 + } + }] +}] \ No newline at end of file diff --git a/VENDORS/Tektelic/Aura/ThingsStackCommunity/uplink/converter.json b/VENDORS/Tektelic/Aura/ThingsStackCommunity/uplink/converter.json new file mode 100644 index 00000000..c5ea9ae3 --- /dev/null +++ b/VENDORS/Tektelic/Aura/ThingsStackCommunity/uplink/converter.json @@ -0,0 +1,39 @@ +{ + "name": "The Things Stack Community Uplink Decoder for Aura", + "type": "UPLINK", + "debugMode": false, + "debugSettings": { + "failuresEnabled": true, + "allEnabled": false, + "allEnabledUntil": 1733331880270 + }, + "configuration": { + "scriptLang": "TBEL", + "decoder": null, + "tbelDecoder": "var data = decodeToJson(payload);\n\nvar deviceName = data.end_device_ids.device_id;\nvar deviceType = \"Aura\";\nvar groupName = null; // If groupName is not null - created device will be added to the entity group with such name.\nvar customerName = null; // If customerName is not null - created devices will be assigned to customer with such name. \n\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// If you want to parse incoming data somehow, you can add your code to this function.\n// input: bytes\n// expected output:\n// {\n// \"attributes\": {\"attributeKey\": \"attributeValue\"},\n// \"telemetry\": [{\"ts\": 1...1, \"values\": {\"telemetryKey\":\"telemetryValue\"}, {\"ts\": 1...2, \"values\": {\"telemetryKey\":\"telemetryValue\"}}]\n// }\n\nfunction decodeFrmPayload(input) {\n var output = {\n attributes: {}, telemetry: {}\n };\n \n // --- Decoding code --- //\n var decoded = {};\n var fPort = data.uplink_message.f_port;\n if(fPort == 10) {\n for(var i = 0; i < input.length - 2; ) {\n var key_1 = input[i++] & 0xff;\n var key_2 = input[i++] & 0xff;\n \n if(key_1 == 0x00 && key_2 == 0xFE) {\n decoded.energy_consumption_meter_elapsed = parseBytesToInt(input, i, 4);\n decoded.energy_consumption_meter_consumed = parseBytesToInt(input, i + 4, 4);\n i += 8;\n }\n else if(key_1 == 0x00 && key_2 == 0x00) {\n decoded.energy_consumption_meter_status = parseBytesToInt(input, i, 1);\n if(decoded.energy_consumption_meter_status != 0) {\n decoded.energy_consumption_meter_status != 1;\n }\n }\n else if(key_1 == 0x00 && key_2 == 0x74) {\n decoded.voltmeter = (input[i] << 8) | (input[i + 1] & 0xFF);\n if (decoded.voltmeter != 65535) {\n decoded.voltmeter = decoded.voltmeter * 10;\n }\n \n i += 2;\n }\n else if(key_1 == 0x00 && key_2 == 0x75) {\n decoded.voltmeter = (input[i] << 8) | (input[i + 1] & 0xFF);\n if (decoded.ammeter != 65535) {\n decoded.ammeter = decoded.ammeter * 10;\n }\n \n i += 2;\n }\n else if(key_1 == 0x00 && key_2 == 0x80) {\n decoded.real_power = (input[i] << 8) | (input[i + 1] & 0xFF);\n if (decoded.real_power != 65535) {\n decoded.real_power = decoded.real_power * 10;\n }\n \n i += 2;\n }\n else if(key_1 == 0x01 && key_2 == 0x80) {\n decoded.apparent_power = (input[i] << 8) | (input[i + 1] & 0xFF);\n if (decoded.apparent_power != 65535) {\n decoded.apparent_power = decoded.apparent_power * 10;\n }\n \n i += 2;\n }\n else if(key_1 == 0x00 && key_2 == 0x81) {\n decoded.power_factor_meter = input[i] & 0xFF;\n if (decoded.power_factor_meter != 65535) {\n decoded.power_factor_meter = decoded.power_factor_meter * 100;\n }\n \n i += 1;\n }\n else if(key_1 == 0x00 && key_2 == 0x01) {\n decoded.relay_status = input[i] & 0xFF;\n \n if (decoded.relay_status != 0) {\n decoded.relay_status = 1;\n }\n \n i += 1;\n }\n }\n }\n else if (fPort == 100) {\n for(var i = 0; i < input.length -1; ) {\n var key = input[i++] & 0xff;\n \n if(key == 0x00) {\n output.attributes.eui = bytesToHex(java.util.Arrays.copyRange(input, i, i + 8));\n i += 8;\n }\n else if(key == 0x01) {\n output.attributes.app_eui = bytesToHex(java.util.Arrays.copyRange(input, i, i + 8));\n\t\t\t\ti += 8;\n }\n else if (key == 0x02) {\n output.attributes.app_key = bytesToHex(java.util.Arrays.copyRange(input, i, i + 16));\n i += 16;\n }\n else if (key == 0x03) {\n output.attributes.devAddr = bytesToHex(java.util.Arrays.copyRange(input, i, i + 4));\n i += 4;\n }\n else if(key == 0x04) {\n output.attributes.network_session_key = bytesToHex(java.util.Arrays.copyRange(input, i, i + 16));\n i += 16;\n }\n else if(key == 0x05) {\n output.attributes.app_session_key = bytesToHex(java.util.Arrays.copyRange(input, i, i + 16));\n i += 16;\n }\n else if(key == 0x10) {\n output.attributes.loramac_join_mode = (input[i] >> 7) & 1;\n i += 2;\n }\n else if (key == 0x11) {\n var val = (input[i] >> 4) & 0x0F;\n \n if(val == 0x0C) {\n output.attributes.lora_class = \"Class C\";\n }\n else if(val == 0x0B) {\n output.attributes.lora_class = \"Class B\";\n }\n else if(val == 0x0A) {\n output.attributes.lora_class = \"Class F\";\n }\n else {\n output.attributes.lora_class = \"Invalid\";\n }\n\t\t\t\t\n\t\t\t\toutput.attributes.confirm_mode = (input[i] >> 8) & 1; \n\t\t\t\toutput.attributes.sync_word = (input[i] >> 9) & 1;\n\t\t\t\toutput.attributes.duty_cycle = (input[i] >> 10) & 1;\n\t\t\t\toutput.attributes.adr = (input[i] >> 11) & 1; \n\t\t\t\t\n\t\t\t\ti += 2;\n }\n else if (key == 0x12) {\n output.attributes.dr_number = (((input[i] << 8) | input[i + 1]) >> 8) & 0xF;\n output.attributes.tx_power_number = ((input[i] << 8) | input[i + 1]) & 0xF;\n \n i +=2;\n }\n else if (key == 0x13) {\n output.attributes.frequency = (((input[i] << 32) | (input[i + 1] << 24) | (input[i + 2] << 16) | (input[i + 3] << 8) | input[i + 4]) >> 8) & 0xFFFFFFFF;\n output.attributes.dr_number_rx2 = input[i + 4] & 0xFF;\n \n i += 5;\n }\n else if(key == 0x19) {\n output.attributes.netid_msb = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if (key == 0x20) {\n output.attributes.seconds_per_core_tick = parseBytesToInt(input, i, 4);\n i += 4;\n }\n else if(key == 0x21) {\n output.attributes.tick_per_battery = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x71) {\n output.attributes.app_major_version = input[i];\n\t\t\t\toutput.attributes.app_minor_version = input[i + 1];\n\t\t\t\toutput.attributes.app_revision = input[i + 2];\n\t\t\t\toutput.attributes.loramac_major_version = input[i + 3];\n\t\t\t\toutput.attributes.loramac_minor_version = input[i + 4];\n\t\t\t\toutput.attributes.loramac_revision = input[i + 5];\n\t\t\t\toutput.attributes.region = input[i + 7];\n\t\t\t\ti += 7;\n }\n }\n }\n \n output.telemetry = [{\n ts: timestamp,\n values: decoded\n }];\n \n // --- Decoding code --- //\n return output;\n}\n\n\n// --- attributes and telemetry objects ---\nvar telemetry = [];\nvar attributes = {};\n// --- attributes and telemetry objects ---\n\n// --- Timestamp parsing\nvar dateString = data.uplink_message.received_at;\n// If data is simulated or device doesn't send his own date string - we will use date from upcoming message, set by network server\nif ((data.simulated != null && data.simulated) || dateString == null) {\n dateString = data.received_at;\n}\ntimestamp = parseDateToTimestamp(dateString);\n// --- Timestamp parsing\n\n// Message parsing\n// To avoid paths in the decoded objects we passing false value to function as \"pathInKey\" argument.\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.\n\n// Passing incoming bytes to decodeFrmPayload function, to get custom decoding\nvar customDecoding = {};\nif (data.uplink_message.get(\"frm_payload\") != null) {\n customDecoding = decodeFrmPayload(base64ToBytes(data.uplink_message.frm_payload));\n}\n\n// Collecting data to result\nif (customDecoding.?telemetry.size() > 0) {\n if (customDecoding.telemetry instanceof java.util.ArrayList) {\n foreach(telemetryObj: customDecoding.telemetry) {\n if (telemetryObj.ts != null && telemetryObj.values != null) {\n telemetry.add(telemetryObj);\n }\n }\n } else {\n telemetry.putAll(customDecoding.telemetry);\n }\n}\n\nif (customDecoding.?attributes.size() > 0) {\n attributes.putAll(customDecoding.attributes);\n}\n\n// You can add some keys manually to attributes or telemetry\nvar applicationId = data.end_device_ids.?application_ids.?application_id;\nvar devAddr = data.end_device_ids.?dev_addr;\nvar spreadingFactor = data.uplink_message.?settings.?data_rate.?lora.?spreading_factor;\nvar codeRate = data.uplink_message.?settings.?data_rate.?lora.?coding_rate;\nvar tenantId = data.uplink_message.?network_ids.?tenant_id;\nattributes.eui = data.end_device_ids.dev_eui;\nattributes.fPort = data.uplink_message.f_port;\nattributes.applicationId = applicationId;\nattributes.devAddr = devAddr;\nattributes.spreadingFactor = spreadingFactor;\nattributes.codeRate = codeRate;\nattributes.tenantId = tenantId;\nattributes.device_id = data.end_device_ids.?device_id;\nattributes.join_eui = data.end_device_ids.?join_eui;\nattributes.net_id = data.uplink_message.?network_ids.?net_id;\nattributes.cluster_id = data.uplink_message.?network_ids.?cluster_id;\nattributes.cluster_adress = data.uplink_message.?network_ids.?cluster_address;\nattributes.bandwidth = data.uplink_message.?settings.?data_rate.?lora.?bandwidth;\nattributes.frequency = data.uplink_message.?settings.?frequency;\n\n\nvar gatewayInfo = getGatewayInfo();\nvar addDataToTelemetry = {};\naddDataToTelemetry.snr = gatewayInfo.snr;\naddDataToTelemetry.rssi = gatewayInfo.rssi;\naddDataToTelemetry.channel = gatewayInfo.channel_index;\naddDataToTelemetry.consumed_airtime = data.uplink_message.?consumed_airtime;\naddDataToTelemetry.fCnt = data.uplink_message.?f_cnt;\n\nvar isIncludeGatewayInfo = metadata[\"includeGatewayInfo\"];\nif(isIncludeGatewayInfo == true) {\n telemetry = processTelemetryData(telemetry, addDataToTelemetry);\n}\n\nvar result = {\n deviceName: deviceName,\n deviceType: deviceType,\n// assetName: assetName,\n// assetType: assetType,\n attributes: attributes,\n telemetry: telemetry\n};\n\naddAdditionalInfoForDeviceMsg(result, customerName, groupName);\n\nreturn result;\n\n\nfunction addAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName) {\n if (customerName != null) {\n deviceInfo.customerName = customerName;\n }\n if (groupName != null) {\n deviceInfo.groupName = groupName;\n }\n}\n\nfunction parseDateToTimestamp(dateString) {\n var date = new Date(dateString);\n var timestamp = date.getTime();\n \n // If we cannot parse timestamp - we will use the current timestamp\n if (timestamp == -1) {\n timestamp = Date.now();\n }\n \n return timestamp;\n}\n\nfunction getGatewayInfo() {\n var gatewayList = data.uplink_message.?rx_metadata;\n var maxRssi = Integer.MIN_VALUE;\n var gatewayInfo = {};\n \n foreach (gateway : gatewayList) {\n if(gateway.rssi > maxRssi) {\n maxRssi = gateway.rssi;\n gatewayInfo = gateway;\n }\n }\n \n return gatewayInfo;\n}\n\nfunction processTelemetryData(telemetry, addDataToTelemetry) {\n if (telemetry.size >= 1) {\n telemetry = addDataToTelemetries(telemetry, addDataToTelemetry);\n }\n else {\n telemetry.add(addDataToTelemetry);\n }\n \n return telemetry;\n}\n\nfunction addDataToTelemetries(telemetries, addDataToTelemetry) {\n foreach(telemetry : telemetries) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[\"values\"].keys.contains(element.key)) {\n telemetry[\"values\"][element.key] = element.value;\n }\n } \n }\n \n return telemetries;\n}", + "encoder": null, + "tbelEncoder": null, + "updateOnlyKeys": [ + "fPort", + "bandwidth", + "frequency", + "net_id", + "cluster_id", + "cluster_address", + "device_id", + "join_eui", + "battery", + "eui", + "channel", + "applicationId", + "devAddr", + "spreadingFactor", + "codeRate", + "tenantId" + ] + }, + "additionalInfo": { + "description": "" + }, + "edgeTemplate": false +} \ No newline at end of file diff --git a/VENDORS/Tektelic/Aura/ThingsStackCommunity/uplink/metadata.json b/VENDORS/Tektelic/Aura/ThingsStackCommunity/uplink/metadata.json new file mode 100644 index 00000000..0d75c374 --- /dev/null +++ b/VENDORS/Tektelic/Aura/ThingsStackCommunity/uplink/metadata.json @@ -0,0 +1,4 @@ +{ + "integrationName": "The Things Stack Community integration", + "includeGatewayInfo": "false" +} \ No newline at end of file diff --git a/VENDORS/Tektelic/Aura/ThingsStackCommunity/uplink/payload.json b/VENDORS/Tektelic/Aura/ThingsStackCommunity/uplink/payload.json new file mode 100644 index 00000000..9d86cc7d --- /dev/null +++ b/VENDORS/Tektelic/Aura/ThingsStackCommunity/uplink/payload.json @@ -0,0 +1,54 @@ +{ + "end_device_ids": { + "device_id": "eui-1000000000000001", + "application_ids": { + "application_id": "application-tts-name" + }, + "dev_eui": "1000000000000001", + "join_eui": "2000000000000001", + "dev_addr": "20000001" + }, + "correlation_ids": ["as:up:01H0S7ZJQ9MQPMVY49FT3SE07M", "gs:conn:01H03BQZ9342X3Y86DJ2P704E5", "gs:up:host:01H03BQZ99EGAM52KK1300GFKN", "gs:uplink:01H0S7ZJGS6D9TJSKJN8XNTMAV", "ns:uplink:01H0S7ZJGS9KKD4HTTPKFEMWCV", "rpc:/ttn.lorawan.v3.GsNs/HandleUplink:01H0S7ZJGSF3M38ZRZVTM38DEC", "rpc:/ttn.lorawan.v3.NsAs/HandleUplink:01H0S7ZJQ8R2EH5AA269AKM8DX"], + "received_at": "2023-05-19T05:33:35.848446463Z", + "uplink_message": { + "session_key_id": "AYfqmb0pc/1uRZv9xUydgQ==", + "f_port": 10, + "f_cnt": 10335, + "frm_payload": "AP4AAVGAAABqUAAAAA==", + "rx_metadata": [{ + "gateway_ids": { + "gateway_id": "eui-6a7e111a10000000", + "eui": "6A7E111A10000000" + }, + "time": "2023-05-19T05:33:35.608982Z", + "timestamp": 3893546133, + "rssi": -35, + "channel_rssi": -35, + "snr": 13.2, + "frequency_offset": "69", + "uplink_token": "CiIKIAoUZXVpLTZhN2UxMTFhMTAwMDAwMDASCCThJP/+9k6eEJWZy8AOGgwIr5ScowYQvNbUsQIgiMy8y6jwpwE=", + "channel_index": 3, + "received_at": "2023-05-19T05:33:35.607383681Z" + }], + "settings": { + "data_rate": { + "lora": { + "bandwidth": 125000, + "spreading_factor": 7, + "coding_rate": "4/5" + } + }, + "frequency": "867100000", + "timestamp": 3893546133, + "time": "2023-05-19T05:33:35.608982Z" + }, + "received_at": "2023-05-19T05:33:35.641841782Z", + "consumed_airtime": "0.056576s", + "network_ids": { + "net_id": "000013", + "tenant_id": "ttn", + "cluster_id": "eu1", + "cluster_address": "eu1.cloud.thethings.network" + } + } +} \ No newline at end of file diff --git a/VENDORS/Tektelic/Aura/ThingsStackCommunity/uplink/result.json b/VENDORS/Tektelic/Aura/ThingsStackCommunity/uplink/result.json new file mode 100644 index 00000000..c03cf49a --- /dev/null +++ b/VENDORS/Tektelic/Aura/ThingsStackCommunity/uplink/result.json @@ -0,0 +1,28 @@ +{ + "deviceName": "eui-1000000000000001", + "deviceType": "Aura", + "attributes": { + "eui": "1000000000000001", + "fPort": 10, + "applicationId": "application-tts-name", + "devAddr": "20000001", + "spreadingFactor": 7, + "codeRate": "4/5", + "tenantId": "ttn", + "device_id": "eui-1000000000000001", + "join_eui": "2000000000000001", + "net_id": "000013", + "cluster_id": "eu1", + "cluster_adress": "eu1.cloud.thethings.network", + "bandwidth": 125000, + "frequency": "867100000" + }, + "telemetry": [{ + "ts": 1684474415641, + "values": { + "energy_consumption_meter_elapsed": 86400, + "energy_consumption_meter_consumed": 27216, + "energy_consumption_meter_status": 0 + } + }] +} \ No newline at end of file diff --git a/VENDORS/Tektelic/Aura/ThingsStackIndustries/uplink/converter.json b/VENDORS/Tektelic/Aura/ThingsStackIndustries/uplink/converter.json new file mode 100644 index 00000000..48f16f1e --- /dev/null +++ b/VENDORS/Tektelic/Aura/ThingsStackIndustries/uplink/converter.json @@ -0,0 +1,40 @@ +{ + "name": "The Things Stack Industries Uplink Decoder for Aura", + "type": "UPLINK", + "debugMode": false, + "debugSettings": { + "failuresEnabled": true, + "allEnabled": false, + "allEnabledUntil": 1733331880270 + }, + "configuration": { + "scriptLang": "TBEL", + "decoder": null, + "tbelDecoder": "var data = decodeToJson(payload);\n\nvar deviceName = data.end_device_ids.device_id;\nvar deviceType = \"Aura\";\nvar groupName = null; // If groupName is not null - created device will be added to the entity group with such name.\nvar customerName = null; // If customerName is not null - created devices will be assigned to customer with such name. \n\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// If you want to parse incoming data somehow, you can add your code to this function.\n// input: bytes\n// expected output:\n// {\n// \"attributes\": {\"attributeKey\": \"attributeValue\"},\n// \"telemetry\": [{\"ts\": 1...1, \"values\": {\"telemetryKey\":\"telemetryValue\"}, {\"ts\": 1...2, \"values\": {\"telemetryKey\":\"telemetryValue\"}}]\n// }\n\nfunction decodeFrmPayload(input) {\n var output = { attributes: {}, telemetry: []};\n \n // --- Decoding code --- //\n var decoded = {};\n var fPort = data.uplink_message.f_port;\n if(fPort == 10) {\n for(var i = 0; i < input.length - 2; ) {\n var key_1 = input[i++] & 0xff;\n var key_2 = input[i++] & 0xff;\n \n if(key_1 == 0x00 && key_2 == 0xFE) {\n decoded.energy_consumption_meter_elapsed = parseBytesToInt(input, i, 4);\n decoded.energy_consumption_meter_consumed = parseBytesToInt(input, i + 4, 4);\n i += 8;\n }\n else if(key_1 == 0x00 && key_2 == 0x00) {\n decoded.energy_consumption_meter_status = parseBytesToInt(input, i, 1);\n if(decoded.energy_consumption_meter_status != 0) {\n decoded.energy_consumption_meter_status != 1;\n }\n }\n else if(key_1 == 0x00 && key_2 == 0x74) {\n decoded.voltmeter = (input[i] << 8) | (input[i + 1] & 0xFF);\n if (decoded.voltmeter != 65535) {\n decoded.voltmeter = decoded.voltmeter * 10;\n }\n \n i += 2;\n }\n else if(key_1 == 0x00 && key_2 == 0x75) {\n decoded.voltmeter = (input[i] << 8) | (input[i + 1] & 0xFF);\n if (decoded.ammeter != 65535) {\n decoded.ammeter = decoded.ammeter * 10;\n }\n \n i += 2;\n }\n else if(key_1 == 0x00 && key_2 == 0x80) {\n decoded.real_power = (input[i] << 8) | (input[i + 1] & 0xFF);\n if (decoded.real_power != 65535) {\n decoded.real_power = decoded.real_power * 10;\n }\n \n i += 2;\n }\n else if(key_1 == 0x01 && key_2 == 0x80) {\n decoded.apparent_power = (input[i] << 8) | (input[i + 1] & 0xFF);\n if (decoded.apparent_power != 65535) {\n decoded.apparent_power = decoded.apparent_power * 10;\n }\n \n i += 2;\n }\n else if(key_1 == 0x00 && key_2 == 0x81) {\n decoded.power_factor_meter = input[i] & 0xFF;\n if (decoded.power_factor_meter != 65535) {\n decoded.power_factor_meter = decoded.power_factor_meter * 100;\n }\n \n i += 1;\n }\n else if(key_1 == 0x00 && key_2 == 0x01) {\n decoded.relay_status = input[i] & 0xFF;\n \n if (decoded.relay_status != 0) {\n decoded.relay_status = 1;\n }\n \n i += 1;\n }\n }\n }\n else if (fPort == 100) {\n for(var i = 0; i < input.length -1; ) {\n var key = input[i++] & 0xff;\n \n if(key == 0x00) {\n output.attributes.eui = bytesToHex(java.util.Arrays.copyRange(input, i, i + 8));\n i += 8;\n }\n else if(key == 0x01) {\n output.attributes.app_eui = bytesToHex(java.util.Arrays.copyRange(input, i, i + 8));\n\t\t\t\ti += 8;\n }\n else if (key == 0x02) {\n output.attributes.app_key = bytesToHex(java.util.Arrays.copyRange(input, i, i + 16));\n i += 16;\n }\n else if (key == 0x03) {\n output.attributes.devAddr = bytesToHex(java.util.Arrays.copyRange(input, i, i + 4));\n i += 4;\n }\n else if(key == 0x04) {\n output.attributes.network_session_key = bytesToHex(java.util.Arrays.copyRange(input, i, i + 16));\n i += 16;\n }\n else if(key == 0x05) {\n output.attributes.app_session_key = bytesToHex(java.util.Arrays.copyRange(input, i, i + 16));\n i += 16;\n }\n else if(key == 0x10) {\n output.attributes.loramac_join_mode = (input[i] >> 7) & 1;\n i += 2;\n }\n else if (key == 0x11) {\n var val = (input[i] >> 4) & 0x0F;\n \n if(val == 0x0C) {\n output.attributes.lora_class = \"Class C\";\n }\n else if(val == 0x0B) {\n output.attributes.lora_class = \"Class B\";\n }\n else if(val == 0x0A) {\n output.attributes.lora_class = \"Class F\";\n }\n else {\n output.attributes.lora_class = \"Invalid\";\n }\n\t\t\t\t\n\t\t\t\toutput.attributes.confirm_mode = (input[i] >> 8) & 1; \n\t\t\t\toutput.attributes.sync_word = (input[i] >> 9) & 1;\n\t\t\t\toutput.attributes.duty_cycle = (input[i] >> 10) & 1;\n\t\t\t\toutput.attributes.adr = (input[i] >> 11) & 1; \n\t\t\t\t\n\t\t\t\ti += 2;\n }\n else if (key == 0x12) {\n output.attributes.dr_number = (((input[i] << 8) | input[i + 1]) >> 8) & 0xF;\n output.attributes.tx_power_number = ((input[i] << 8) | input[i + 1]) & 0xF;\n \n i +=2;\n }\n else if (key == 0x13) {\n output.attributes.frequency = (((input[i] << 32) | (input[i + 1] << 24) | (input[i + 2] << 16) | (input[i + 3] << 8) | input[i + 4]) >> 8) & 0xFFFFFFFF;\n output.attributes.dr_number_rx2 = input[i + 4] & 0xFF;\n \n i += 5;\n }\n else if(key == 0x19) {\n output.attributes.netid_msb = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if (key == 0x20) {\n output.attributes.seconds_per_core_tick = parseBytesToInt(input, i, 4);\n i += 4;\n }\n else if(key == 0x21) {\n output.attributes.tick_per_battery = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x71) {\n output.attributes.app_major_version = input[i];\n\t\t\t\toutput.attributes.app_minor_version = input[i + 1];\n\t\t\t\toutput.attributes.app_revision = input[i + 2];\n\t\t\t\toutput.attributes.loramac_major_version = input[i + 3];\n\t\t\t\toutput.attributes.loramac_minor_version = input[i + 4];\n\t\t\t\toutput.attributes.loramac_revision = input[i + 5];\n\t\t\t\toutput.attributes.region = input[i + 7];\n\t\t\t\ti += 7;\n }\n }\n }\n \n output.telemetry = [{\n ts: timestamp,\n values: decoded\n }];\n\n // --- Decoding code --- //\n return output;\n}\n\n// --- attributes and telemetry objects ---\nvar telemetry = [];\nvar attributes = {};\n// --- attributes and telemetry objects ---\n\n// --- Timestamp parsing\nvar dateString = data.uplink_message.received_at;\n\nif ((data.simulated != null && data.simulated) || dateString == null) {\n dateString = data.received_at;\n}\n\ntimestamp = parseDateToTimestamp(dateString);\n// --- Timestamp parsing\n\n// Message parsing\n// To avoid paths in the decoded objects we passing false value to function as \"pathInKey\" argument.\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.\n\n// Passing incoming bytes to decodeFrmPayload function, to get custom decoding\nvar customDecoding = {};\nif (data.uplink_message.get(\"frm_payload\") != null) {\n customDecoding = decodeFrmPayload(base64ToBytes(data.uplink_message.frm_payload));\n}\n\n// Collecting data to result\nif (customDecoding.?telemetry.size() > 0) {\n if (customDecoding.telemetry instanceof java.util.ArrayList) {\n foreach(telemetryObj: customDecoding.telemetry) {\n if (telemetryObj.ts != null && telemetryObj.values != null) {\n telemetry.add(telemetryObj);\n }\n }\n } else {\n telemetry.putAll(customDecoding.telemetry);\n }\n}\n\nif (customDecoding.?attributes.size() > 0) {\n attributes.putAll(customDecoding.attributes);\n}\n\n// You can add some keys manually to attributes or telemetry\nvar applicationId = data.end_device_ids.?application_ids.?application_id;\nvar devAddr = data.end_device_ids.?dev_addr;\nvar spreadingFactor = data.uplink_message.?settings.?data_rate.?lora.?spreading_factor;\nvar codeRate = data.uplink_message.?settings.?data_rate.?lora.?coding_rate;\nvar tenantId = data.uplink_message.?network_ids.?tenant_id;\nattributes.eui = data.end_device_ids.dev_eui;\nattributes.fPort = data.uplink_message.f_port;\nattributes.applicationId = applicationId;\nattributes.devAddr = devAddr;\nattributes.spreadingFactor = spreadingFactor;\nattributes.codeRate = codeRate;\nattributes.tenantId = tenantId;\nattributes.device_id = data.end_device_ids.?device_id;\nattributes.join_eui = data.end_device_ids.?join_eui;\nattributes.net_id = data.uplink_message.?network_ids.?net_id;\nattributes.cluster_id = data.uplink_message.?network_ids.?cluster_id;\nattributes.cluster_address = data.uplink_message.?network_ids.?cluster_address;\nattributes.bandwidth = data.uplink_message.?settings.?data_rate.?lora.?bandwidth;\nattributes.frequency = data.uplink_message.?settings.?frequency;\n\nvar isIncludeGatewayInfo = metadata[\"includeGatewayInfo\"];\nif(isIncludeGatewayInfo == true) {\n var gatewayInfo = getGatewayInfo();\n var addDataToTelemetry = {};\n addDataToTelemetry.snr = gatewayInfo.snr;\n addDataToTelemetry.rssi = gatewayInfo.rssi;\n addDataToTelemetry.channel = gatewayInfo.channel_index;\n addDataToTelemetry.consumed_airtime = data.uplink_message.?consumed_airtime;\n addDataToTelemetry.fCnt = data.uplink_message.?f_cnt;\n\n telemetry = processTelemetryData(telemetry, addDataToTelemetry);\n}\n\nvar result = {\n deviceName: deviceName,\n deviceType: deviceType,\n // assetName: assetName,\n // assetType: assetType,\n attributes: attributes,\n telemetry: telemetry\n};\n\naddAdditionalInfoForDeviceMsg(result, customerName, groupName);\n\nreturn result;\n\nfunction addAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName) {\n if (customerName != null) {\n deviceInfo.customerName = customerName;\n }\n if (groupName != null) {\n deviceInfo.groupName = groupName;\n }\n}\n\nfunction parseDateToTimestamp(dateString) {\n var date = new Date(dateString);\n var timestamp = date.getTime();\n \n // If we cannot parse timestamp - we will use the current timestamp\n if (timestamp == -1) {\n timestamp = Date.now();\n }\n \n return timestamp;\n}\n\nfunction getGatewayInfo() {\n var gatewayList = data.uplink_message.?rx_metadata;\n var maxRssi = Integer. MIN_VALUE;\n var gatewayInfo = {};\n \n foreach (gateway : gatewayList) {\n if(gateway.rssi > maxRssi) {\n maxRssi = gateway.rssi;\n gatewayInfo = gateway;\n }\n }\n \n return gatewayInfo;\n}\n\nfunction processTelemetryData(telemetry, addDataToTelemetry) {\n if (telemetry.size >= 1) {\n telemetry = addDataToTelemetries(telemetry, addDataToTelemetry);\n }\n else {\n telemetry.add(addDataToTelemetry);\n }\n \n return telemetry;\n}\n\nfunction addDataToTelemetries(telemetries, addDataToTelemetry) {\n foreach(telemetry : telemetries) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[\"values\"].keys.contains(element.key)) {\n telemetry[\"values\"][element.key] = element.value;\n }\n } \n }\n \n return telemetries;\n}", + "encoder": null, + "tbelEncoder": null, + "updateOnlyKeys": [ + "fPort", + "bandwidth", + "frequency", + "net_id", + "cluster_id", + "cluster_address", + "tenant_address", + "device_id", + "join_eui", + "eui", + "channel", + "devAddr", + "spreadingFactor", + "codeRate", + "tenantId", + "applicationId", + "battery" + ] + }, + "additionalInfo": { + "description": "" + }, + "edgeTemplate": false +} \ No newline at end of file diff --git a/VENDORS/Tektelic/Aura/ThingsStackIndustries/uplink/metadata.json b/VENDORS/Tektelic/Aura/ThingsStackIndustries/uplink/metadata.json new file mode 100644 index 00000000..23f54b34 --- /dev/null +++ b/VENDORS/Tektelic/Aura/ThingsStackIndustries/uplink/metadata.json @@ -0,0 +1,4 @@ +{ + "integrationName": "ChirpStack integration", + "includeGatewayInfo": "false" +} \ No newline at end of file diff --git a/VENDORS/Tektelic/Aura/ThingsStackIndustries/uplink/payload.json b/VENDORS/Tektelic/Aura/ThingsStackIndustries/uplink/payload.json new file mode 100644 index 00000000..31db41d3 --- /dev/null +++ b/VENDORS/Tektelic/Aura/ThingsStackIndustries/uplink/payload.json @@ -0,0 +1,77 @@ +{ + "end_device_ids": { + "device_id": "eui-1000000000000001", + "application_ids": { + "application_id": "application-tti-name" + }, + "dev_eui": "1000000000000001", + "join_eui": "2000000000000001", + "dev_addr": "20000001" + }, + "correlation_ids": ["as:up:01H0PZDGB1NW6NAPD815NGHPF6", "gs:conn:01H0FJRSXSYT7VKNYXJ89F95XT", "gs:up:host:01H0FJRSY3MZMGPPFBQ4FZV4T8", "gs:uplink:01H0PZDG4HHGFRTXRTXD4PFTH7", "ns:uplink:01H0PZDG4JZ3BM0K6J89EQK1J7", "rpc:/ttn.lorawan.v3.GsNs/HandleUplink:01H0PZDG4J02F85RYFPCNSNXCR", "rpc:/ttn.lorawan.v3.NsAs/HandleUplink:01H0PZDGB081PMP806BJHNHX1A"], + "received_at": "2023-05-18T08:25:26.112483370Z", + "uplink_message": { + "session_key_id": "AYfg8rhha5n+FWx0ZaAprA==", + "f_port": 10, + "f_cnt": 5017, + "frm_payload": "AP4AAVGAAABqUAAAAA==", + "rx_metadata": [{ + "gateway_ids": { + "gateway_id": "eui-6A7E111A10000000", + "eui": "6A7E111A10000000" + }, + "time": "2023-05-18T08:25:25.885310Z", + "timestamp": 818273765, + "rssi": -24, + "channel_rssi": -24, + "snr": 12, + "frequency_offset": "671", + "uplink_token": "CiIKIAoUZXVpLTZBN0UxMTFBMTAwMDAwMDASCCThJP/+9k6eEOW7l4YDGgwI9cGXowYQ5KPhrwMgiI2rp+jpOA=", + "channel_index": 2, + "received_at": "2023-05-18T08:25:25.869324983Z" + }, { + "gateway_ids": { + "gateway_id": "packetbroker" + }, + "packet_broker": { + "message_id": "01H0PZDG4MF9AYSMNY44MAVTDH", + "forwarder_net_id": "000013", + "forwarder_tenant_id": "ttn", + "forwarder_cluster_id": "eu1.cloud.thethings.network", + "forwarder_gateway_eui": "6A7E111A10000000", + "forwarder_gateway_id": "eui-6a7e111a10000000", + "home_network_net_id": "000013", + "home_network_tenant_id": "tenant", + "home_network_cluster_id": "eu1.cloud.thethings.industries" + }, + "time": "2023-05-18T08:25:25.885310Z", + "rssi": -24, + "channel_rssi": -24, + "snr": 12, + "frequency_offset": "671", + "uplink_token": "eyJnIjoiWlhsS2FHSkhZMmxQYVVwQ1RWUkpORkl3VGs1VE1XTnBURU5LYkdKdFRXbFBhVXBDVFZSSk5GSXdUazVKYVhkcFlWaFphVTlwU201a01uaGhWVlJvZDFSWFVuRmlSM1JtVFcxT2RVbHBkMmxrUjBadVNXcHZhV05ZY0RKT1IyeExaREpSZVZwR1pIUmpNRXBLVlVoR2RFNVZkR3BWVTBvNUxua3paVVJTWVRaM1lXOU1kbTQwVm5sdmIyWmlPWGN1ZUhCZmVrcElaa3hIWlZadGRVUlFVeTVuYlRaVlZXRXdkakpHV0VKMGJUUjZaMjVXUkVoeGVHRjRaMlJKTlVkS1VsbERhemc1VDNCbk5rVk1iM1JDUkVZM1VWbHdZbEJDTkdOblNqWjBlbkphYUV4MFRVMHhZMVZFTTFac01XdExURUo0YURaMFExTnhhMVJsWWw4eE5FdHlVVXcyZUhsRWFFbEhlakJITXpoTE0xaFdlRzR5VUVjMk4wNUViME5WTkhoTmRrazFZVk5oWkUwd2FXVnFjR294VGtoMFduZHlZMDFxVlVGNmRsbERUazlNY2s5eFdVeFpWMk5XTG1WVFFYVkpNVkptT1U5NWRqUTNhSEoxTUZoalYxRT0iLCJhIjp7ImZuaWQiOiIwMDAwMTMiLCJmdGlkIjoidHRuIiwiZmNpZCI6ImV1MS5jbG91ZC50aGV0aGluZ3MubmV0d29yayJ9fQ==", + "received_at": "2023-05-18T08:25:25.906038642Z" + }], + "settings": { + "data_rate": { + "lora": { + "bandwidth": 125000, + "spreading_factor": 7, + "coding_rate": "4/5" + } + }, + "frequency": "868500000", + "timestamp": 818273765, + "time": "2023-05-18T08:25:25.885310Z" + }, + "received_at": "2023-05-18T08:25:25.906399073Z", + "consumed_airtime": "0.097536s", + "network_ids": { + "net_id": "000013", + "tenant_id": "tenant", + "cluster_id": "eu1", + "cluster_address": "eu1.cloud.thethings.industries", + "tenant_address": "tenant.eu1.cloud.thethings.industries" + } + } +} \ No newline at end of file diff --git a/VENDORS/Tektelic/Aura/ThingsStackIndustries/uplink/result.json b/VENDORS/Tektelic/Aura/ThingsStackIndustries/uplink/result.json new file mode 100644 index 00000000..6c5224e2 --- /dev/null +++ b/VENDORS/Tektelic/Aura/ThingsStackIndustries/uplink/result.json @@ -0,0 +1,28 @@ +{ + "deviceName": "eui-1000000000000001", + "deviceType": "Aura", + "attributes": { + "eui": "1000000000000001", + "fPort": 10, + "applicationId": "application-tti-name", + "devAddr": "20000001", + "spreadingFactor": 7, + "codeRate": "4/5", + "tenantId": "tenant", + "device_id": "eui-1000000000000001", + "join_eui": "2000000000000001", + "net_id": "000013", + "cluster_id": "eu1", + "cluster_address": "eu1.cloud.thethings.industries", + "bandwidth": 125000, + "frequency": "868500000" + }, + "telemetry": [{ + "ts": 1684398325906, + "values": { + "energy_consumption_meter_elapsed": 86400, + "energy_consumption_meter_consumed": 27216, + "energy_consumption_meter_status": 0 + } + }] +} \ No newline at end of file diff --git a/VENDORS/Tektelic/Aura/info.json b/VENDORS/Tektelic/Aura/info.json new file mode 100644 index 00000000..94656046 --- /dev/null +++ b/VENDORS/Tektelic/Aura/info.json @@ -0,0 +1,5 @@ +{ + "url": "https://tektelic.com/products/sensors/aura-smart-ac-switch/", + "label": "Aura: Enhanced energy monitoring and remote control for smart homes, offices and facilities", + "description": "AURA is a 120V Smart Switch with the form factor of a standard AC Decorator-style rocker switch, incorporating a LoRa radio with power control and monitoring circuitry. It provides features such as power on-off control and status, as well as precise measurement of consumed energy (kWh), line voltage (Vrms), load current (Arms), load power (real, reactive, and apparent, W), and load power factor. AURA is a Class C device that enables real-time control and telemetry inquiry." +} \ No newline at end of file diff --git a/VENDORS/Tektelic/Aura/photo.png b/VENDORS/Tektelic/Aura/photo.png new file mode 100644 index 0000000000000000000000000000000000000000..e43d3a0c0dd970c4fa497feee3ee9aaccc5739f9 GIT binary patch literal 113371 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�{ z*(+vP{CHY5tKf=#g1rOA_Ir!lUbn65e(mXWIdP%wA?*i0uNovE_L)Ez2sCMabD=%X z(Y};-C*q^Yu%L&BwX?b) z;&Zt}XkR&PC11%s1)u{Dv}7)<(<-8O-TFP^kt(8d4Ue>1Jc0K8j+e7)=wDn4yRFgb>1^~2)^NA@qIF&fS;&Quq&~-q&C|86 z1464XXb&(yq6gPlW)C{@YrBniH*+i#z~RX4O0472u$D|BS%=;)pO+`Y(sIfvFqqZ) z*3?q(&b%16Qh*<^R)KcPT#M+u;z{~pMY$iY?H!fOeH=&b?r~brnD&wAv`}O7$4O%Y z<)U0VlbCZUQuJBUaPz=xH^JRN(R4UM4V_RJ(3C2};_kA@_sgg5> zT1&GKDfpjliLZVSFi9S9z+z!ygp2fI=6Ru6VI3;cXIvv3D}D5v^OZbDatb-Q}VSl6IW1a#D6% z>CEum@^&Nk@dqlp9`oka~7FDORDq7TOy=^?`TnS69Gir>25Bm>+R#hU8}kai^+|M1DE8{!dy7 zaf~S^QPN5;HTw=BEgk>NuZ|HcX4DFer4bEbtB;##ibW+M`LX7a&?B@_mb4GBy=@*sO ziRg^5K}pNx+eEVZB#cplh*VjwvD4#)g7+>L2CEJuqcqy6?!Gi%6FWZe{4_xusoY6m z7Om>{TjQ>~>I?h`{T&X7^2Wcg=v`F9HVf7`k;k(a&t?&9R{{xa>xi4on(7^n?+b%lW0Z^42S~XIGqjcxO6p}b?M=Jd{oq|uC5LWk*JdGq% z41c3Mm5U=m=LyU0$(foC6m>Sq;rAlNuLfv~3)t^A?5lpSi2JNTA3}4R1hYV)d_ldi z(L13`0s=CA0pSZXZxS8E%}Zv7g=zVC-I}IlItkbdW4CNI!=fXPn()M~8DjA9gjhgd zSYU?$9N#sAHVta*>d?CbZYcB)ksU9skC@n#0#g^3){LB_W1sEj^|iHK_Qcik7ajIy z5S9ElMsekJl33z9<&!>Q5pjEtSmHk7rXv_%TgS`dGZ2QA>~Kj5?L;s=AV{`SW3C#V zyQYqK)6Z>RTe3AHl0uTU!@bkSsQ7pUZeW`mpw5W8%N#F^N_x^v=%OcjnM%KmuO5BM zGbf!eQdH}YDXc!}8_CZQIH<7!D;%8m|8^!RM<)#3TC1tdYchaGvf=+^#WRrJNBQ$7 zW2j1ilyq>?Dil5+E9N?T%C^8>VnM)|-|G7Cidgw=E5<@s38t3(AMfk_Os!jz^Yl%eiWxc0 zxZ;1kVsxifI-2E9m3{GBnX?*Kt32wvG1~f{UxY9Y3=oIbBx~4ZmdKtI!49t1y=INf zk`56ztZ89A^CSbg5KICS^J_OIl@SOjzw$hlF78?BtwWFJ|4jVgyYqFf6-OR47hX6L zj6Ky{*E4QC+g4mZ%YvOJIHl40s;{)zTn*v>Rnrsl#FPj2>x<7pPi%(WN(7{ zqE7-gFqLs~453v){r_egW;=nK8RP5ApOAu)K#~XTL7Y2xJb$Fq@W#T%n)6DN=V98mDD7RN; zh7UU45HJ&eZ{iy7AUa&~;-|xO@dQcSw|~8Ukvh_8Vt05moJPrGQ*Z7{vW2k!YvAJ`})j~(hbszvlwiT+r^bJHa*NuEcvVb)GdfWfpSv8Y@qUOw7e1IAA!ng{ zvl($->ip^>$E%3V$@+k}1$K&75><0a{}p>X;AwA#RoIv*^S*z%W$;u|Z3bfz4Xa!PE1O$;;}U{GlM9utW0>LCnI}%C>72%m+bvJw*ZpGjt-yMR*vWN{7-yh3jC@we$B}!Xx7Ya-eApC!raA> zrbvWz*|1`FV78y7D<;`Fz(peeCuCGi=CyIS$f(c4`Bs_|f!3>qrhw7bUuS=Z{^sqcSL8OIIPKRkRTeax|+yZWiMhsu|-{F zWl?#{DywkD8RkNf8OJt(^(el;~rW z>OU}ZTJaEg_;`IfrEr!ITmJAG^x^+ISZ*Z1!uO77;VrEGat+o}y%1-@VLARL4I^w! z80CNVa=t~(K`6BRr(T9Z49~SrCN3dI3lByf$gi{P5Z&E{6~Fjp0-QOCjw0BB66s3m zEl?WfiZBLo2XDLkqr3ycDG(h$u${V4M&$EbU+g^36}r;5=@;xu>Q)VfF?+yuzF0zy z@NDlJ9u=+-mTHnA0ud_~(CrD+Wp{8rvU|Wrs4Vn%O2uk<%K+sbW1N=mG!ajq^2@69 z=3-s{oZFze-RV!9wN_c5l;Rqs@Mr1V>>|Pn=*nzO(n53=@;1Zw2z-qIquiGa)t$-b zflf2U=Ms_bhJ()NMH?_gfrSxuymx#k_BKD-sNLsP!G$spCscVnA3Kh5`7{{mT{82B zRxy{&tSi*TMNONKxY>=ZGIY0kFl=3sAoK6ihr1=6w#+stIYI+p^G1T#RPoZdZ#QdN zdW-I{V&kpq%D=JaACl}VEM+fk;}v1GY{Vzh8 z*ekA)3Oyg(=$xhdZ36mmTLWz%g8EkdB65Q20#Rkj#*LVX=MgvV{6R5PbmcWQ%^qvK z6iqqZyB`q4N`s|9w7AV0ipYq)_#-?245dT%I=b@5gQvVwi_g{J*cq3x2;v0VJGt7! zWlN#@K4VpU-zwWw|po2&xx8)%6Bk$Y+$1lG|-T(jOMXKiOvC08_DOZD;qTI8W zEx1+3oYUZgsewQi#%ot+B`j0R#})@clvOR{!wA*>L#bwZ^aVTkYb61yum5`8Uxi8G zWSECEaTOL0L4ma&!h7}#|o=)q8GdGsMw1jt#`34L?Z-X z1vmdGygwKN2DdNnMfURD)C(eQ9~f=N&a)o!$lkY-QX$Yl=ID&V9@ybaxKN!$J)>!| zjDk%-&)RO?+>AIVm5=O;Ixre7?X=A9#L(XWjL;wWAktZ9E9|2;gY&h_S+LuJb3z>%yri7U)$&hW2PH zXbFLznAg2j7%0jwkl5Z%u7G4@xkyg5cx`hxVc7m5&fj8_q5z>R`AG5V@Jltvt+a@n z5$B1<0LwDm#RxL~)7G27?@~P4)@WqKc21$s$q{*ant$){yQjbjf6Du$b=+;;`t+v) ziU?q7#o~_~7(xh7|Iaq#%BzRG6rq3)NZ+!`%)-)@>T%|)9pjD5xm462cpp9b@$=8~ zB0TMtyQ#qsS-8HGE7xYt2j_fv5ru2ZBCljR6pW%X*3w?k7ROTPOv7x}6KKeku5$U)Xa+0egQqZz@ z&Gt_tOn9zM`R<{d37bPhc6m3*{c`fU*Nyzp)`t@gMZ#|>CqAOGWu%EWJcYV+77~~uHaV{^))L{ zIiRDk?zN{2#9+eHE{4ImtJAFTM_4JX_f+^$j9!mb(XD})n9?rAY32$^pDI#N`1kEJ z_~JvjDudO%M>UOJ!r#@oy=$P&tKddp>yjU=@@%D?3JgsVR%_NHpV(N=C$TN-ckRjol3PnV>^|h^#gz*zX|gq=#kCV47bg4^kE||HuZh+HBe{ z5C;cm)2FM%>NJLvEtMrj_p!ndeED!$VD)1NN|RM0sW?TW9#ch{^S$}W>-BD4o&@u7 z>*L<-pq!!-UjEl%-yC-cv^i|CH@5yooR7-W(lHvv86p~U7v@pR4`MxqM8ppnNPXhC z&3#1)pI32lGeL#Em1OOXSa;z=SXPa!|FX3$-jZP*0U3iK!vVOEsJ~gJ6rl)KN?f5C zOMN|oHw@``OmVmR@_sx?GM$dbdL3p8VzYNI(Zt|Lpn{d{i%gEesMh52`;;gx1UBRx zGR8qR?+s$V4mZLFUtVQzUgbB_LZ$iL7$J0h22%wwBfcjaxFQw7VPu~Zf$U|lJ3n*g z=|CPd;UgM*94j(&(CSb0j`EYMU0wV=j|Wegj+p*?TyU?9S2t%Ge2_@wbj5n?Kgw@O zspP1rsK9UVmph-YuWizq8I#Y>#>U2wnx^e8$jgtJyR-1pfaia;{+OG?Cn(L|J>dK8rBsOooFBc-w+`;2xtBZf%$oEGKXhpT@Hb-xJ#A)o?F z|5|0|;TU$O^jUjpr{066xMZ(*+i#5p?!y;bL^{D5@mcj-QI7UERz>;7Fg7)o3_8$)!TA1i=wefX>os zu0lpDx>;YBNPkq6AN;;R^c5*6c+DqmO$;5`YM{$(-HJzw@Fz`~5DTi_U%XiZJDAM*EaqZ#Rd=6RYZ z{Gyw%r`pDsTUato4^~TIRqHr=TNgdbto2?SJ^Cyb?a-!QgWItrfy<$brhdz*5!u9I zD}PdKUDx!0`Sa{B7nKvGl8)g4yKYJD}lN-!T> zNrIoQ)|*m!)oo5DCh}*mh<~UGFI(<1IAz!V>6Qj+&hNu6KxJ#rRZp=)qe(`=Red1dh;4+CfyQc{|Yw)IOTlBns>wR-%Hhb5e zOWs#0f@syA=ZO*p&(9eurhEV4#HRwp&9GzIEFMmf)-&RH6e zXUAjJ=IM+KY#7DCv$MqdF0Ph2mvL!1bbRx>ccqHgpFdl&eqqFnY@oVZ=HP>}n52sT zczd14Ba&AI0#H}i)#eTE7x)peC*;vGqY{!AW-2~NkDpKf)OAi&uU}=N)=h5jYTXIA z;O?w`>5@LvRO9x%Hzr7y!)EaHXY;{He8tiP(X)l$rA0vmPGIg0n>ph6J`|#?VU4z~ zy?Ph-?iiJF*81b!33;-sRyxnfcnT@Bc5YaN-4R)-T*@JkvnY(-piKXysjz4M%&ta=NhlR;A({^(yBhSX+ zu|F#J&70M{5xUHoQ8xJGWo^K976x{YgMpo*wjCNnh`YcNdUBfC63xZLTE?0^^G2ml znRa}dLR*>|96AMZmDaz=k=8cIGE)HvM#Wth0zGrsF6+&p7w+qOdI4mtK`4}xkE}?! zU$2P3!C6JKLl>{5Xp&A>ehz9X|IOoLeW7{30;iWd`inW;(eo=Sy3u9;_X|7@lQF>-i4fj;e@}k68SW4JMWsZzcxkuu{JP&gXiMdU0wuZX24VF}$ex7b_zoTkZ4ybFH)ZTMc}85&b%K{q(n!;-Ip-(v zVSwn^{`oxjrIj5HV%l%rx?&|J%)O~6))=pa*D?9yfRI%u1cMWl!o~WSG`jNTO!Y2i zW-SgXjQgJe7-s$Q<<25$G-*(Qy|3hm?ES!=MOMF2wn#hr7hB)dD=qF8yZBDxhe~|L zQF3{?7_el|RD%qZmTlCLLRk&(UA%WR{<|%PmfW%(LnmJ1=otF+Oz_ao~WI?Fuh*%_r27P?ant4wcn`pc#azt_H=cGGn-#pY)o zqpew|vrv~1T9RA9&7R%@F7s*kXQ^Y%>qn@oZpsRP9J zdqM1TOtqT>O&8|%VP6^jgQ7|xu7jvPPNWphjSy_<+^24>AO%Id23ouyRKu_kcUD|Q zrYC8O0rnJMOunk1l-$zXAbu|dj)&Gwax z_D{vk@4cwNaM|S)<^;R+?P$8B92zIZ$0x-v1Y|dEG;wb{p~wg!cuaAe_HBdr<896! z9bP1-?t-16*NNw3-%A%CWa)Htcg12rD{=4{kb0+YXP7GShZMmMLfIJ(Yd2ER3@5f3q{YyOFAbh{t!R-aY(Ast1Q-T3&7L_2nTQU|YzYGo)SO3V&Sv^Z59K zJM^NS&kUuKp9|Zw6%IVLUi5jMfKpd?ldP!?lxgB-@N9#~v!Tav*>MGm&^F_=h3Nni zcfBMp6xjdDag~aFYILOJx=)h~O?a7iX|y8mc4Iq5Iof)`AM>-y58TXKa1iXJWSb+2sMkFKB>b3RZ*Y9eBHVukmn8@m z<~9?(Mf?;ODj%Mzf8#^JN$i??qU?yTz`Zz9Kc&$it3X351UBaaybBiSF=Rs}v~7c> z6`73*qUqb{EjyNG_Gj1C{*Jk(VZI4@j6rWk8^BAhjYjkNoZ5hu@G${7k)AAY{1ne; zfOR6#&^W?G;QtN`Fspv&ZA<&Z$4*dEB;EV@Uk40R$CZab^95$vdAol6fuu=ufajt| zMMcF3F+28zZ+~>K8Edv5^tp0&z6V$75-W1&xT2qU>i0cMYMj=Fg>s>+&9VTG6PE?| zYxBX4d(#TjxSj*-{G@DvI(d>l-13W^>ULWt)3}x_oq^=D{O}jfc?`} zCw+V9M()l07R%>hs6Vd=nmbRUk%^Q%WA=)&Mh^FB46o@Iw4MgB_{Vw`q6yJkBw&tA zyETT6y*kM1OBm)XGi$8Hrv-&6GrinN)D5(78>-9Rd3{Bd8ksk?$r+$GyI6fphVnXz z4ZLfA<1O~2AK#e~f&j*unYreKwFgD6Hc<7n4rU@u4>IiQ#^Ar;L1`{ zctd`JzV(Zi*;aHaZf$F5D}80X#yod!Uta`#IS|<5sx+0^WY*N1vwawU=^ONPOsi*@ z;K^rBNhy&+8XNh@^Lj=~qQZRHEyTSjq`t`I_*`()xUZJjA3Y6xldk~Rmymp4NKp*g zb2lpES3u0^*x4ncb09p*&<2)x-#g5zs;$%_g718}y{Yn)>Qu)b!b3>dv=-j=NA8Rj z04oI5t+-wATanWq@j86b{Mz{#&QVoRx=1Os2Nb-V zh2xqUkPnU*80#Yg3}3!lU=6CY%jSy}9`?F01zeDOqoQ{h85u8>RxkzsdHuJC>+{MQ zE*qM2xJpNn=|+W^FP8(Emc-e&n1I#szRuP>6D}ANT6fIk&1wwQja1{U%X|HaC{l6R z5`vh)leaR+QXCdy_7s*jaW$9}PG^gaw7a%(g?TN-qrqLV6*j{`7UvGLc{+URY~R34 zlo?)NepKmsb$CYU02FcJaeZ=hJst&@Wq1fxxG8lVx zX^9&jjKPN%9MC78rJ=oeD25{7UYZ~S(uA{tC*NL@d=Puc|JonVvf!nfWpXx*UVi+# za5lPg*SDD)g7~T`kKn@yAK9}c`WY~OpP1<$j^bLEb7W)8MqiI!VTNm5D8Z*g)o&&c z`4D_cI+vvyFXtu#6RA@|@b8V1gn&6x(vxx4LDIO&ebpMevDzIK0`RnH5~uZdALZ7~ z#Tq^^bPC`X>MkQ{WbPlh4;- zZ}E}v+9`J0ou8Py%PIfQJE3|f{x~{1deLiQ{JfuRU1RJk2Z{9wQzjLM^eA0XkB<;1 zUVpt3fnAf^L&mjYo3;VIUbrVDXMI0Sud_j=WeV({)=JC46ODMUO1i@y?U z1yqQ?GY8Y}eb)Km3tyS!_UJQTT)*zR0Z!Sge?u&HFl z|5l9NZikBkc?=#2Vc7Vjn!okBRa24oqi?%kS}*Ri(V|X%T9N|<-q`huwvgCO!k^~h zK3=|wCMR7)EsUE5YnZ}=bmsv4DMy(+w6_>5P3$8N@#KQ>%$Eh~kSnD9A3PzwF0a~9Pes*Z1$#|4C{S=F4dWct&HQ=PCi>Z$Tg1>flzPfNX>0RXvQ)S1t$Y1b&* zv=5&Z$cq%kcg6gXiZb!N7cs050)?FT#%;)8{gT+2#(Ve3Hrk%kz{mgywW?CYXb^xZ zjvq82FBPW>2QdRz$7?$WQ+Pw^=tzU$Ycf!>-G$g1^wnO77W%@9N=#4F$Nm?N|SLO3=VsUYnzK3DiM@Jf|av2zF`2{Mq7GjS~H zebE^Y4?3sFfk2?z_`fEit;JASL&@a6@9FcU{!luV>U)f~N?UUTY1gGe%|hAv6YJSh zq<6MvXU{zFSDbbvm;CfAel*`q;-(UaA~0Y_?8mC9+qCHy&b-O7g|ycGalr)(5LbV= z(~$&=r)Xto-@pKx{{e~me}3-po4k^ey+xx3sibx(*M_11F;0eH1^!$pz3qLT^ZEe8 zIf(qZ_S3UTsE8q|j4E;{R%l|OC8a(hA`c!Ih0lc=PHPG{mud`n8E4{iDonC;$1FIt z-W+ld@}6!c9e~>}i;^Tj$iexsg#h3od`bjrU7lsG!EWy}v2gxUAwKNs4YC~XiD*Mp zL$NVan*uPA-&Z;_JUOo|fpN&gGM@w$v)w4TCw!AIla&HwJe=xUf9dKTs+@y5;*@EG zf5Jy;xKC4f)BjijQ-CDz;2RM*ZUEa@-P%1Qyx7@6Ztbv!tG}=BDxVpj>;L{?rN8cC zfu%jmgmL3D41i*d0@ol*AP3dzu=S``;zh{s(cwqt0jD~>LqdMi4f%b$%k5DVZy6XU z&f+8APw`njdv2#w6~DeJ;Z>!#xX(@+73=z2WuHw}=*f!6XeDw@Rv)XKM$U zd$DFWVj+kmvYL?Vw0jm4>^*%*VPzIS$jkeDJ%JXlN$9=aG{c{0GQ6YkMYRy9MZ|Dm z!@)XzI1@#dBCM6G^rah3UNCcBIZ@Zs)EMzaHe3DSs1`TT!mdqniqQzCs{18|9Ve#- zr;~~OJXYGSWiA4dCjDMnmb}j^H zUTg62*mKh<`)J0ap{aoLc zCf3jKL*?Bq$Y>zv99R-Jf#>Y$Z5sQ%6<3uyJ9-^+crt2@1R zqN``mO}aa)f@5PdHZs|3%i@TVQxsoP?B9axf~Vb`v>vpmgQMuR3Mif36@Q9qdvt4o zBFtN52q&bqgbY{D+N?OPa2nM~?XE0_mn9&rRRF*N3`+cXg(jH&x@gwR)36T+@fCE?=fre+X#NgnOf*@4>$Soj4 z>=BUv_vv*T8l57Gy#qJ^2pJ^=e7|vkHqm#GVdEM22rM0@;{o|iaz*{(7ENNi-7%QB zI;pdO2`J1^*AsV+j?L5%p50v8HQi`;PTBapn?7tWU31r$$(Hu7UUt(P9{`|)-aPBB zV)(uUh+coXHt~DoJpm53ax_+$pi&V(DCtuDuo5Cr*+Nbkea2Xlm1e8)Jy zC@#uEqtS$9hbDxN*o`W74T2hy!(uZEYV3b5tR)CtnwVsnL{C4=a;~&96-yBKT3;@_&*U7~h_yQ%aD%l{$Y%v(C^vF5p= zdSo3roO&-+se;O#iJ2yAxVc;((Cvl2Qz#C)uCzzulB)0J%2I#6T3E5q*U2rwB}_cq zF`AT+p#;xOokYR@)nxKTXI4q)#P{iGV+i<9;(o})Q8RmO9tV<~LIHx-fdk}G2hoDs z8RFu2IJevU5s)|k;BH0cai21HyyrAgs z?@tLEYx^$4ip|-dQoiU^<0cxn7puDI?+X@|={zbPSI+M9baU$ z#6^cJI@oMTFv4*x&QC9RG8A~*FvmOVS2q<_Ty! zqCf=)h~~LZf4E@_`?()WYd!YN=Y@57fGq2vr)#Ub-%jdzf9@wGmfg+_vTz zyEzr}SZ~Y51lC;<$cooR)nGXP(64OCcryEkf>3X1AW>cKzpxDUc{YZbkT|ahXm}-c z5ziZ8X#_}Wi^ad095h1~N>#m&UewhcFRy8B_LDDUuUnpT%AWSFR}D^89JlccjzpF= zKV)-3M^$(2d`mqji~ESRO*2-ovG3eF8veDcM4~7O2i&ZQQ@hsDtqgb<-@%7)yJxxU zHH?7SQ{3m5rbYcRHx&F^$Uanq$ZNXof42bgifQlui17p0>Z(#A@X1|6<`zL=`IkQx zr$Z!S-jyFabkyFx;5{B*i`@*1g=M6cNpB{)G-CajF?tunBCw2fxl0cJJ^I06K~Wyx z)vCnJdGdu!7B^`ztH)!CbF-D4cGAw#^N;SqSPnbw9~rRP=S5`vD3_U1`(aho z%zxzA=*<)g>v>;bPPV7^bb{egenm4n)oGn{(Q-iMP@gzK2+GGUAO6e>4Qaavz%rXP z{JAP|{3wC1tts*#EW*&X=(*tf4FRET=d0%7&dWblfa*8{VUBOFWTTIL?qEsxjFS4Z>Iy=AP4{u zSsL5~tY+qCXhl5N`q+9IwEvAlx9?$nOL%7$0`LBdFdZhqd_L+NML!-AHVc-O0^81f5p%qD#F9ws!+ zZ;$(U;L=6c#E!_=kw3rFKqY=pRMz;Dhi*w?6#b`hAfNz;sRAD)HX0$ zCo2ypLYS<)Is0P(g-N}1UQ=m=4`qUn<(HFHK{F|vGqk%h63WF`b^2m(bUeE$M%+R` z<>?z1G??7Z5+(S_mVH+wJ^edQm)7g3**4jRqLbL@wIu5Fi1XI_@8j|Q{mBFve zgNzps%Z0qfxg(sebWk|H4_{0VTAtV8r@(B$nd_*E{%&68yRgd_TSKDJ8Zn4p5{ z0se!2P&t2L0A?}r*|LPd0ZJBAOR@(tVqg};hi-M}bA(@w3^Y&)hOeL#IAANIjIqEU z=pGVJ^Tcj0O8gYNWaxTJ#VU%*dHy1^c}88_o-{ro$zi>u|G2GpaAXk6-@2T(yn4M5 zj3m8S`h4nOKj(cveoX}TsWTm49?y64CuJm{BjG+{(n2BLka4oi{r1FkOUYh2?>$i# z*?{*kUmqw$Xr+Ev;to@w5Aj|*6P5}*lw^SgBx_p8sBqsaUW%k|3%nZ17Gi2?`J`nr zl(w>CEak6DJlMs7gZemXUwLW%jd;>!Xk6N7bEF@;;YJPyPaWv*ADu4rh-~(b4|=sX zLzQMZvA(|E);O|qz!-Osd~c!EDaF39E4|TE=TcVl;Iav`Q6^-QjUMXO^W53-+ja3s zM*8f`8I$dAxrBE?cu;Jz->#iw4`1Qjvp$j0>jKObS82h)%Q7%l>-ovCUn>S4YD9G| zxDCo15`NoRH5*kmmf4eweqrsHH5OBz8lhNK{@%R&rX>8XH+f~n?|dNMzdBrTq;hcG zZ1&UUMJ2_aKu8(-S;<$8?~-6e17<**f*t%HPPmcZU4R4PQms1Vd}|GU5CDMKCns!u z1wcl1SyFu`N_V@J!f&=AZ*DUN02#7Lrz=SEgP>$12Vv{gB>J@6$%TN=pF}?AO<3RZ zuob4Iw;fIpU>oX6Z`NQ7KIXd2(pvZyD;FG5y*u|1*@%(Kw!5Qk>vhxXq((2ugQbJ3 z>vR5h#13l&9ZBxS)f{KNyHiZbe1n3~E2qr!1aH41F7tZY<8jlPsmWK1WPW=CEcNG0 zka_>J53l6vwQ8DuDegBnqxV^*&ze*`FM9qyx5x`0!q&dEtOhsDc3YR!%3`^3%82f;p@GxO4cb*yPEvFUXVE2q)Tne!?)k<0xm zGuuIDh-jo`ON01|OIh6bq8jG3eb@J^Kk3%Rxzpsv(0cmO7vp0enz+PI(o0!8p=K8^ zFYPWox3Td=1v#XW-mE2jAYD0VK*gEMxxX%4BNSoMVETL0L&sl}uIY3*f~07JRsnv) z`?IngN>9&)Jl!J7ot@boALJeT=a&>l&O}6n0oSuUd~kV_s5Vxa05XhVR|_b)oruK- z@c&nu@dJc0w&f)SKTO!Z0)1vF9MIn){J@VUF|{jGZc_KrcnB93F`~zQZdm7Y8X4tO zG%@=RyyVS|x=1tfn1e)^ANqm+!8rX!w2wt*`5}}~U^Gp_kDK$COU`knxxQKQqt!K; z`=&%y+Yj{3(o_z*r5ytL?5byx8APPGM7_lM*%k51+?^YTSF{4`i`Ij%At;tJFf^%n zpI|jy=mkj{pUeP^kTJy4JiP%f?P-o@L+ei2(_Zw-vW@vuVi~%Q0%dJxl(|Sq*eU;t zWM7#H>2hp>#8hG}1EOj2c&*wdFD5~T|5?i7{waV+ZV(gnPX}ri98B>FNT+&tB1h!e zQ+z&adm9=X{Ot6K%j&qZ`>pSaWTxDy0{;ebII^^{FS?z_SV`+$%>(&%0xpEGwanpa zD*!O;;S(GNt&K$B?cT3%8MNT(6{%ixOiAkh$|Usy+`K-!mTYFYT0K}p8U_dyWvo*GWyVXOr7BctT#-hxXBVaLOCQe@luR@m19$G?lg$S&;u2C-OZ=t1j;nPu zrd5Ihq+WO~vXjQ1co-Y|(JGI2j@nC$AH3BTy|JSH-e|!um8x9#_g3|AYw)f|OK##0 zsRH_QF*%QzfYCckUzgZ@n^gB`jsQQ2c}nrkzyg2pe6X>X>+Ys z*C2E5Kr@-6!-+=_X6i4`2^mUT#fM+4`Yb;?>s@`-psrp3hmvieDl<;2pd~yB-EMiM za)H(gZjBh-RezVOYA;5rxwl%u%~&s;pEuLPt-bO?LLDD_VejF9kE^g@RRj(AXW!dL z@ZTBd$MMw*i|o;brzTDf@h&BQL2Nl2Ga3)sGmyKBbwTD3NcmH)5vOC=4TdTM9E^cH zdB~%NraBjL78$=cD&oP_HUzSlZAZuL>4E8Kekg+DD`HrV7R>MS{Sj~NFuMH)sjd9F zZY4uC%A~{5{0#OmK0e~#%SCt8G-bBA(v+1zgorF{&(cU^b7YF_WY@}5q&Gy=$r z0e*f!=r7ktzqS@?@x{txxw9%G@xuQGKkzkUg0vDsKZ?IOOX;1d<*=?iKyL+^d7j1K zwbd*rTMZHTRxhKKx2>&(k1fe>E@L5be+tBbWGhY^W?qF{baB*bDFi<#(E)iZNg6{w zG_;_QELE9)5#gg}j93jpq^nizyGW{XzS%zP@=76Nmix9GnBZ)aw5>RTQWy zINqjdj$rh^$ghKcnJZ2u0X*kF$JofEXI5N^T*KQnim$^wcdj_)hP~|-q1RX0^cw`Q z&MnNKFTv91*u{*>%H8LM_im-nsv1mCsj5Y1)=u@uePmTR=fb8r5#Cavus@%wbpp3E z3%pGn{w%$wqbe1~W&i7TW(fiJ`phj!u9O97&!Q~_t!*+a3k4TyJH$ifpYPLyA?agg zVwk-f{n9H}dU>3OJJ7zqfgyC#6Ra~h;h0oGUQzjLzPs6fU1#&k1mqX+$!(MF`#luk z!pD-_m*HYqDJ8osi0Wg`Txg=!pB!(O|LVYJ#{^-|uZ=1O83nh5cAa)9{*4NiZbVRo z(-Z8YgEND-y?xoA9HpzsNj#`sGqNK8=<02*3${FjU$3;}Bw7TeEd*|JUhKC|I;;X8GMuUMpk95>tz+#*rzG$0k9CJWptSwV`MGqsKZFds*e0Fd1nU}q z(?(tgeIyB58z95bmV<51mn6qdRiJeRBJV&i-vB?m*D8AtQjaMNAbG2z#cJ)qoXU_{ zugqpJeU}+sTowPf*vI1?#jCD3c7}CmV7(VL7Kt!D?u#6TWK>qaDOZiWA#J}5gsvF? z!UHe>RKU!v&;N#G*s*J$_YN3a7~rqD3zgTrC9O<+NQjvoDR;>AmM#7s$`?e6g+|r= z>6XvGMhnd0&drUggwxUsSRR-&F-=eK~{~J)kIJ9p_r6RKqwh& zQZ|lC%+UTqkf>;LVh$P0_iF|6Dua!!4B+R^1h0g{Hdea}h7ZV z+Mh?eE&=Z}EhSaxOU*N9Pm#i+0Q|to0H9M7bpHB-C=D4_K<{LX<$kLV<%TX(SxQu& zcQ5`K1tRf>YKOIK8S}6BfeO@k%wq0Zb7XXk>g*npA-k z^4Ze7h;TNfRhSf@K9?2>(x8`Lhh|U{_wwfFg{EqoDNK)7{S?kXx8A{N9s2O!*cbhg z66k7}AO?fn!PLi31GzV(q5YnyEw35b`^xd+OcD?qk_{)9ria;f)CQ9Y+GcHbGv%wY z?<40QK6xk2BW%sou`{D+oYWncOs8d99jtEZ6R7$wzidoos9$WpYw+vRe(aJx3Fha> zhX!W!WrT8mMNN7m8sFVN=x@nnsEG~EIU{t&tHnD&c9wd-qG{&TaJ^F~02*R2eJ1(! zDeS`T5Q)#gpA8jWi`YNweZ56FjRPd=zz~ao@c#ZUP8P-k@ z-j(fy7|mvV3W%|G6vc4oX=0Ee((AmIcP@~ zhcfl`7OLiD7bYPqWUc9&t`7nN>3}A#GPUdAZz1D3R(ynF+@8J>OdPOZ2|^L{(tvue zx_bA2p-%l4$SbIe?v~{}50Cru8M`6JR9D20QQOh&K~hujp%2myxK?>;*Nv(@prvDl zymu$qVc${jxB9|U>@{?}^CVf)_lwl!dUaBOZ#1=e0IWWL)} z(qEiXG!W;GH!#WT+yVMwGoWB*jN%Iu4r++=M zNCRVI(T8kI1ej0BCVUms`8}puCoJ_ssvu3B2JvsD7=_&>fe^^_+6## zY{YRsJ^```%gjLUD5;J?O}#bw>Vm`>88+9I2R1qMNWkQ)fp7rCmToOJKJsA=RL~Pq z`E5?0K}D)rQ2F7_hne}<_|;c4A~J2P3@l{+fv;t2eLUkAnASqd$_xTde-oaNlItOd zw11ynY>Qfq>KY=)-B}rKl6qh^W@Pf31ceMwbqd7lT|zs#xLyRh!vc_FH0^lkm{mi5 zB_?mkevMHOjz4I{y3V!sU)J0NZ%|}T3N2rpop!~r_yBnFP(fcM@LA7b$*pBL-sLD%gM5I+^5th@hC>e9fzz76kWlIU;dN{)@uZTAjnsv*I{bNFa$zJ6iWUk$E5;ZV_;4 ziv^E-d@FN%%^zjk`k7rE{k(J;O2MMAE{!O)3wdHIY>-iPJCNq(mq_KV8LNF+Y5yEs zs`R%M80$xe{r&i%200upeOkr-pj#UB@0v5;)=HHgJZ%#7i8qQlY4!}lW9p1xbbiSv zelb!-%e?v^J?Dh9`-fvaso3Ix%ISEWAIesSAkAs{R2YrsH_B~<5hLNNJ%jP!A zLOaW2=<&{UyEK`GbFpZU?;ETUm8BR3c6|&kyL@YOgT&_FIz2{7O&v9RegkPoo(A?r zay+Fol@0iIn8fD1*5c@u!f%I*j@5t^xwUcljxNyGuC_h$@7CApz6Zs15QielaCzhe zHzf6LNdMF?Q9vY7z2~pPeVc+vW!;0gic1`kAr9aM|IX^oe@TO?80^5B;)=RleTU^m z-7PSc9r6=(Y{us`;da(#3>*pA3yVJK5~-g5_%Rh_Hk0&qU?KjK!cDxq{JqR~NjDjj z=2RAP{8iPpGEU|EQWnma3|Nsj6Mw|Z%^u%tI=F~DzHky8A|Av(a+{w*D( zDgVWCdGq7eDz#O@ysMnRem_O_4Pwp&P!wvjE_;TUqiu7aKyqjD|gW^INm-X4OHP=E*7fc&>4 zJ1+h(zKbrYo7faAD5$%+1L0Yth*fH_!ULwFE^57*{oTg;+AC|Uh|XpOIl{i3l64k< z2ZT2t+yaO)Vr^Xmjec2K&*QQ6G1;MBjfA{9bcY~Z6?V00IieMe3c@-eV%{`k+FLSO zt_m@a;nxyy1=!WHXNLOO>`3PaA89i(Zi#N7`In z8Q?m7k@-8t_YUcxgy$=|*42ky$zI4ZwioAEp+peTwODX(rhPU!~y5CJi&b zCoR9sRFnLSNisI@d@-L-|G_b_p&)TFC`=2}U&@m`F)w>H?Yy%!CfD`!fE*vL4o0*f zhdwCn$$bXWJs1TZAewf|`Nj@taC;H@)IYE*pCDdUmB0Tt9>~S|WHxcBodg;h<8g8n z-31^W@*!Et^mDm`-ZQD7ggAwCuJ1Z&1f6tR?=S%v<+B-_TSk zs6A|KY`h0(JMw<(mxf_+*5IVzgONc|SXVH*!+!c7^UeDHmFZot5R+PP6xQzuhe^#i!Tn)(?66K+fPgr< zv1;Zl@Z!_g)gp_Q1E-av(&sCeA@j`g0R0Mq9fCx)#Iu5ZFNzK9#I=>2a3~R^HoLy@ zC%F7QyOib5p95A!aPNHQIt;Ny23^T%T?|X#;t%Izsru`Xw^E1kDlY!(Nb;fEOrgV2 zjpqs*OY$dscfqe!x*s-2#M216Ro*hljc1}8ByI7|x%DZ$dSC>~? zFbsBzKVVrWpG9rMypc<$abzza4#xvRZ7>oBNsoiOyQwoO<_!(qYwn+JgDhz z{u$MC2vEHH&m3;HQcY5`p?}N!LrYft%w?D!oH+!a&u2<8x+|qN%kdZkuOiMP312mcNR>GMM=fHvz(dbeOM23Mu#a_(y_OIp zDuN7e$OI9fUn_kht@@a>h6t?y+asz!^e5OlsXjP)G_`+OI^KC|Gu(@f8HMzI%tfqF zD>*!02pF)C(~5{?vv&P85Hi2=E%Z>ghnFv-at>?k)W`n0E~>||(07~-B`W4RP2L7G zL{p+83&NJ!C=l^*S)gAlGlNm2uOcNI-Fugh?dQ6M%U0Zvriq|bL>fDukx4`^t1#Ne z>q)NS1l1A}5*WcwjM4v10Kak5;UIcXnxK&#DaO`mTD$@)<+uQ}5p@Qa;DY8D3w*@Y z`z~(1JOo0BG5!3>!9$Tbz}|$a!#+n>)#434X}HNgU*>J6o3X~P1x(ID3wOp} zjybmjL=MVMuHS3%7&js~4!eYf)$F>3;jrv;x)T_}_CT-DX;|`w0N8&nj>cZ7gX^cB z`^cl!#q0M>0hDK5Tqby= zys(r20dHx82h9509v*eE#RDo>w%ho{_V4kzJo5{`KKmycVzd)a^D_$GAKsqBED@4@%>3@2=jr);e}C1hS1)GX@B2RII@h_*b;>7riDu@KIs{k> z6@{;;XehhQInn;#m9-WHx?xHCa^>wyoW6UHzK%G(e{-i?{Z|$nrDQyqF%QZTvxE4i zfEp!yE&3xb1xMM+aq-tt2c>ZDL*kSB4t!;8*l}1W`Y%fQKWvz=1c0eR^o?cF>t=GiJ`iAg{@>tSg@@o;6Di>(5P|dhx}# z1F*QWdC^suyu9oIf?z(FS>sxKcAfD`{a6V^7TxMElOWFWGhY|So6E{M;1*s z(^_}L>Qn139=+ACK9k%T1P43A{XIh`)E-4EGWUC)jA2p*yB@GmYAlUJ#|Y=csY44{w}i#TG*F^tAbr`3^Nr92C0eh|P>D(7>~ zpZf0zm;nVR0i)lU!7g7_fy9|4393H@fl>-L@sz@gH9s@kaYVc0>aOc=DHJ_c;D$?E z*R27+pA%ZF5Hr#a6#WS zhaQ*-Uid5b03PDvA2l@fPFzST)!Qm#wT#}|By)cER=RwBz;yqOTf~yFi))jkE)w5P zyqe%PX$R@jH@mfDV_mke0F_>ECM(31deAK^cDt{$%p5nb*9ImoZ{Y0m7gz1b`I9Mp z;yNZgr%v^L<J?@UvMGOr5~Aci@ar^O8s zqQ$(>X0l~h6kD9sApgDFoTf7yZ<2MtB;AR6OJ-LBI_ttG8 zrPYg^@E#dy?eaThE|rZ8(kN-9!+9B}!LVsJc-%|e&suhMBpPYac`&y+3^6j9S019F9APMu2(57?P7&R-y3H# z1j`uDH~kkKb2uwj`+qNuJ7(>#RY|?f_p|55tx9gVhyKmP)rT*%j5ahjddI|3PwK+; zliLrTbo+K<(m<3lG~{7lyNi!_sCcQf3oe_ofM?F_*khE9?-UiYYfaQ{SYhCI;z4}G zfvq1kcD&1ys+sL=*U}Ch6p%0o&~M~~TRTBBlJT95;+r93L>~$%nb8uSn46kCUF9*I zj}43ulTs3aQW3a1FM&1@p~Z2OAG#s?f~EBDc$fQngWvf&UNdimW1;oqrFK>pC+2KT++Brq$42L%k9P;&%zj6Vx{$Pw0HGN1mwF%WA0;%u{_iW-& zKe9a@vv@wg6obl$6Lb{-R^H|qpndLaRKl6ID+5sw%>)m&ab$_3OXN&(k#AD!$bZ9UtKB6c&mPN&xau0R(+JW#Sw=s^tX)>piv26zq!xgu<^cvF?j{@U z`LK817`nWr$wmH4e4^(Ljv$tEHI6S124219a;mxJ-OK_VuYZ3IY7ijd&0i0)6N2u! zE5|UXGjmsd1)hgrut{j`c67yVGt0A^$p^zF#?E~BKz5-!uKW9*ZL&iS=9iRq4tLA0 z8#(-ws|+$x>8s{py763u^)$a~Qwn2tf5i4v=4Lq`YXve^6IqRS=v%MQt?pw)FGIuo zY@{?HM!7tz%2HT_?xfj1YRXra`G+6ZB4NpLW?csYjcgR-sGIA(!O~o|{RRRIFRPUu zo|)vTI8YCdG^>acp0Hy`{C>519b42~o9ATJa&exh#hkN(4E|^N=c`Uczxaa zcpgSs$yA!-v3VgOaTJX^GA~_V$PY0e{98Z?nqow2|D~m`x|f-aIa}?z>fcsVC@p`T zL#hK~|NW0QZ@74f^U^M`>@NueN-*+-K^cWW^JW18Gv21?eYa^cT0$pF6jW2&0Ga_y zkATLiv$3_Pz1j$kxRA`Sad8QG;{e6P*GICX>N>~OZ$D2@a(o4rUw_d9ju?@eJ3DUZ z{8lV-{ioQ+fK%zoPCW23x8sOmPHSGfy1u`1-HMm_oeSEnhJp^AHIqKcYoX zua4Ls9W~vK>QM#EYwG*m0GlG^^UO4j(cXl8psKyylKe?rq)nr3O;ltdqmm853*s50 zAzdK-Y|A!4qVRv>?FPH8KxHsrcI{@RxEyw3hls*-tKq_2)Yb`xs?AV5HBi&4h3b5< zsS7Ay6$!$?>778!1@FQB&JL4@-}dJ75Z-*5z1lrA7yxU5TJEX`#Hmx8#|~oD)*q|M znmrH#@!2oG*3D zR&L-(J^ENtHX&%!?|`vkv4|Z+#;)J5G4eXD?CQ}{x)B_z-tc5S)%D--f^Livsg>z= z&!1Pxf#qOV$jXP)F8lZv4n!yPJElvOb95mgy2E>hepnF;6mwBwV7$5$mib22leKecixX}9v2bG>CmeXL3b!|I`OBJF*V9-{QKKGv5TC!*WR6+ zKZAUauM`GrqNz!{qh+jc2JNyxzVPHs+W*4bof|Ng3mE8Mv>0w@E(F)T&z-rrHuIWP z2|fu43nVD73T~se2?wzlM;Scq%cQ3#=6HRHcFR9j| zk-64Pg7_)URuf3Fv)jWG)L(7Yu7T=f&s*u~|Kfb>P zpbHBT0NOay>v!)gYTlZaQfi}IV&PcJZi!L$8K0l?V={pD{+hg}i%73y46TTC*={p!NLu&A z?vbX%*C~(O&(3#sdjzxfp6EJgdQx&MZd1;V>@>!QQCxk^f*RAl-di4B1rH)%to72V9KqMy2Vfh!aP<7lLer;eG%}vVp*(T2snR z9K|Fq9hWYFgMOkIzVi1V$qObzPJ`F#JwurKS_qm!|W&^!X9kAQe?n=0ds@45v=@!_0a8RrXEFqN`x|-S=T3N|V6OuOXlP0g z5;4dZvE7M7^JTm)XP$**=vXsYph`=fHOzTHqbGzphd2f%YB8>T4~{`Q8&w+40%{NSF2=8+df@c^^#vfujrXAQ_l=-XBn3(% zZz%K%A7`otYvey+YDQXh$9%2(&S|lJ1H!h(C3e?DT*_4MO( z-qm^t22Og9P>aqnzdfdw-}7e5vw}jw%&HoK7#Qtqwki3X+}ZyF+8W$S&*r{55#W}5 zt7uT1lCl$^8N2U2WqX2c;4KghDO>P3!hm)d)=Inh4Bf6f2e9QZ46bm$t#0_=!^XiX zL0Y(9C*+svWXF&Gw$E#NFxq(aVJ@Z@u2q8t@*|o8fTHH!OfUJ9Qg{$n=(YR)PO&J( z^sUNAAaXJDL?$FQ+u82l$CFMdV54kLQzM|PbzuSv*$&7AL3(lMk=2S;$|S+iUKO^?i6b5%z)4dRXFLpKV^mW- zRP(|kl(?ofa751VF}VS59(bf6%QjdoeS(w!7I_(-(eo+a;DFZqAz@Xrqm) zp7|Act@>H&i-d%)93K3ZHpbS8X?9Ts2l8M{kV~_5Vs~8JhL_ffTUf71ag`-@}TNNM2 z(A7a65%L%Z=pHjBEGuL&J%PfIMotsr8G3u2udUp#sGbtTLFi+(3Q7Y7aXJwPW~=I+ z&{I>N8TUhN%>c#s{Q$hsEGVAA{XAb6uk@9U|l!Pdja`iZd}q9(70 z)YLq^4+)&wzt7G0ibbokVA&^uE}cVvb)$zfmbc-18YSTa8A)r7^JxH^wvI<&*d;zp zCwy{?6#MyT+AkeQ;SU_>I{1)joUS2l7|ZY&B%cN8?Q5CJOKrNlR@&5A>2m?o(#4+~ zbxE0(VNrFt3kR89(h>&2e<>fU-qrcTfzOZ<$%ZIgB%s+LExxfsuQ*LqM_ZV8W{I|+ z)=MbBhl2;xlUVfi}XY(9w-PTjdlwNwi>|t*wbjtiK zJ35?pyr-JpWKVYQd8}3xgVC&pme!-9>e&HvoX|fdpFbzs`@NjN0^*EVR&<@6*>aW$ z=udg&^U1&g1=T3`jlLPEIvyDTG-cFDY-LB7Ns?uGCyw@{0M~O>ObO$}h^F>G8pWsJ zPYkdlk73fK#n%NM&3YsYS)#bV2K0N^)W@BBJ+k(<>ur3VrhO#vA~cTn+P;F9kWNNDp7opm1Gub zcoE&LYuyM%UE%)meRvd9RrPmgW*TIlof2*O%%hIsah5m&yQL0LqH;0FR@O+QpOlcy zW{lyvVfC=u*U1Sq=TOX*WM#EKXUl?ty>7zn!<;9*Z})5cfw8O?F>1%R%>@N+u&7I%f|z+by@M6V!zXq)x4KYww9G%|&ti37=F-!00XzX9f{qynFX;HI)5U;k`Z z{aj>Z^JsRn^41X1Vup0FEJiI&^r9c&29Z5A5(HhJJOS#d%`+1cc^4n6ZQYNjSY2x1 zy~*4(>@vH71h4}XLG{xqmxZOSsQI9t;Av?K#(N7)JCY&3()Fw~&$)*fCu~?926xs zDzCqxEiMXO2>s5RNwxWW&-txY*V2lwl$A}Z+`2RI33~XPp2j&oY$Oa^IFtS+UXY>J z4!F>Xi~rrNi($+WD24m|Bl19cgM73N6ZIX_IvadEyzf?`LpiNtwtxYuwYUZyf#iG= zVSQuPg}I;O02>@dhKWd4c`fU_yj%t+aEog;20i(*3H_#jKv=&t21-G><*!bpw`^6; zzAi2(>++4Yfx->b?;nORv^SKi;=sgP;`&jCy%)8fiR#|-m+>nW(cEUm5In_(kom=D zsp3eudE4h5Upl-HhtXj4s@41Aoebz_t^PiE^=Psh3>MpyBQAcL4%N~WBT%mBt@fIp zYheRgUoq-SNq{B+xMYb)iHU@1H_;f391meJ1Aj$iVIDpagk3fYr2(5ZF4BKmG3OaDv|z3Jz{>EMx2o^W7`%A02T zo1G{|!mq1{^3JOrMi-47tkTX3pw0s(H!+H)`nhTx<=EI;Zg60I+=@pO*JZ4!{oIZH zTt{DPy6oq2Znx7s3>0l2pNaN!8t*88;(Pn2F2YIfg5-xyv0B>^HFh;?>644|{={w5 z#;mis!|fP&G1oAT$V{iR@$H1gou4CrUC3nP`6A4tqgs-PQL`STMVy-a>gCmeT!@4w zOOIsXVbzed7jXsk@5o*U*NDZ%?7`8Ts$O}tp7P}4p*ca)YXr$<5`)~n#bK1VG)mlm z&-yY7<;~fM+#rX-XyituB-rPK+==qJ6^yy8L+##dX**{VdS>U*iJ(3f+DT?jWq5Sy z>If3l_{pO_{uORUzYjb;DjsZOKS(7KUB`2S;@PXb94KpOPe={B_7}{r2Cp*2v>qP%1SQm3JNN@0`aj4 z=@4v$pX2308KzVwnprOPyMmCy!GzF(yI2TwQyI^%*>R=@9=5Ls>12Te+1${cLEC9V zMe_;&k_&HhFk)HL;I_`LZ}EzS5&X6%z2r_EFw1H}{Nq$>xIS;qvL{ybNu|Pn@Hlg90PW4pzIweIEO=QIYwF!$rOyRoKa(# z0Wp*d4eh_sYK;r+-Ryv34*iC>NPhK!-)BG{Nl1~Jj3Tx$H9O*@Vsg5!F7H`xBHhli z$a`v|g{h8~nEm~nhf!N9kMnq?Tb(FZgS8!2*WP-e5_p$>Eg5x}vTxihz7`+fwWv?& z`p~g|(&+AE_i;!-BO8&3J~w@W%rcUa9Cz(0`$5jn^M3Jd`ag!4=)^|BXx~y4ORQMF zGY>wvoz&=rPJu#sh30N2S+qsU_Q;+*JCDSs#;-l(Gq`DY{}Mzfq%JLSV+#0P)Ah2K z1*9i{T7bt60_m){2)+8*?;hAI#9gyRZQX%6J`25u_=wz^i>n{CRQDwu`^*hh9pGeoPE4WYM3y+>n!E-PrX(%AT08YuAt#)U-+3X3ak#LB+%(Ab2Nd*Z zqANZTRQ~!$iegbdPX|*zcXr(1cORz)`u`A21s**sIG4x~b@BXmEj# z-isFS`}T9`K9I!mm!|oKeAS+l$sThCt?&1oDV+T3E-zOIUex_r0dv*#Rnx+_Ft&~s6*I|QRe(zrkUSxw5sS88v^YtrF zL%q0nUMIzK`18FmKtNVS0d;QmfD=cG;88_06z`mO4Ic9xTYD{|MjZ#DQT~z??R5xF z9f#!pmctY)g=42Ul1exwIZ0npid0#oYe@Cp z^$zxF8#8qm0oDcH4;Q&|$KDlcJ&&A{`^`^I#hLc_mpI}~Y3wFc6}olG2#pRw*Y-Pp=~c_sC;KJSXeOXnS$ zXOrsqJV8~z#uAagIfgsYd~<}v-PO!jZte#i%z0nCdeiJr$&;__@{d32Yze=-Gy(%Nyc48GYq4EjV&?S}*uWaSeJ zl=;f$=ML9rU|aX?Jaq8LEyTJ#Ywrv{gY1A&_3o=#M>>s@OiRVL&a{t_YqU z_ip2L=JNJYXnhA_CD>|}Q4gJB3dHQ(E8kajjO#r|Y21@~5lRH8*#1a!5h+$syRRUY zIq_)wmSS5G>Dvi~*CQ=-1z|<5yfA^T@wqyfasYb}$OctC{V~IURjO?-7GA zu{5S*{O6@3$M<*J>=!xeIB8bbEc3LX+k6rbs5WV8V7@y(#mx8i8-0*5 z_`b*?DhD+}Vwku8I&pkerC`Ub7HIN3%_>a5OVn<7N9O;5fhHI5Q;9?%onf2>3WAb( z?j+4E(DfZ>HT+Pfv|$}0nOF`rp=KUsa7?5p*hSqI_fY`t)CO>8Pua57YS1szbwOh_ zak=@&r^2)NjvqDe9e>-lwfvv&vu4d|P1V^IM(4w-D)*l7uoFGcpU*!I3YJp0>ArHq z%2r=vU2=Nk76t8VS8e>1KUjsBS41k8-~V;}L%-%Hy&Vycom*&o+^I8C4f&HyM>nU< ziECc3-7q0a`iuYachzPgV)Qn15p;or#Q%B}us@oM2hL?1gdtBnyZdcUxy$qFqUjlT z6w7_zFD+?lqpCC=c}N6- zE}ckvb@QWP;ccS_AG)0TuPi(a3z|IBQsBP)Y+)%%h46yFVY#uLv!#689ynMJLVi`| z!U6#~pt8pBQ(RAWHJqzEq*>b1LZV8-g{PgHM8zonn}svhrr-CI4w zZPut_7^um0R#fl85xXQWo`R3Yo&o3d#91wLv8={77ONWB=FeY5T22ghSa zk1nxnVQ%>QWIoQ_#s0?3oZ+RMyi#eVP9_EJ=p3782~!FRE@~RPasSu1$jWZ*H-=G- zq<}Y#$`+YAqEq`X4_CxJ(kfIGPi?b1rt!+8$+3JtYvkfnpk(jSi{9RG;qstV1DW-V zw&ktMjk;i#X&ciJJVo21JiP{`xJ-0GHIefjLQ z6e$52R%YxE@){TG>uP;a@@uqnsCz;xfH-X|ev&yj(biUd+*WV3 z$fh}ync1o0u=q}A>cwn8`;^|_)abr@D!aviW<)Ggv{6t?ZESh|a73skHEp;5}U@Mk^ec86t^?mF5*fGs^&IOjQIquSGS}ajkw%)r-OGrE7`^ijN#gz9^accZ&n?;owkw?k@u_JR&LfppnJksF5p?w zSCj0b%jV{h&mO;^dpC?Uul6i24>QN>62xqO9**+*_xrgYugT8NELn;u+MJNH?W!3g zxv(>Q<{edb{!RvGgsmV-5jYK zD<{`ItrqrOoyy~b>?M(q@0I0)@0uR?t(uEKtHzJM^Ey)o6h8gsq@{OF-~E1m+;Z6> znY1Z6F6-)59=H%CFI1Rfz(RX#-M#sTcWzEive_d+n80YXmSy199)0hfW%|J7X388j zu$%nVOin+L`?d4iw{QFNaU(fO5eEMxi;a4-wO3=!$)oF{U+!!xdLOxdfq;BTNgS4$ z)=lOZI|OyMC_-=KA|-T^E|PLgoA+?NsUM@(9x2w=Jq=q~z5>#>%#BFwrsOXZLJ2GA ze0{llbl*sP0pX1hXNe?b6769*0kQQnGW~C+je^lu71!;|-HQzAe|~@1UEv^N`9ymihAXo5$Fo_34^*7#MH-8Gpm?@txhd-_9lTx(LZAOj@(z z!pa5Djjc6P-uh@W5k2@3mE)VhqjneYv(Bizs~s76?_5EE?9IY&6Kh&WRbQPy%r9wf zv_q{?T&yOc!*y25d5P}|%WDn;`bO0a5cu6nx=hq?IAHZn#-)CaE3UeEhZqlP7ufz$ z@w9Qt6Tn83ekQ(C?C`D2u+im%QU!$hZs*-s;dZyd+&DwyZ#w)~=c(l67d0Hwph0^$yuqi(D!sRdR%uQ(@ z5`i{_@tb4g){0c)yD^ca*hk3`zQ#eKy4F?Z-NuvOl4Ga%{=GBn&DnvGm1R)EvYJ)T z0=g{3*<3(wks)*Bxrw7V3XdRsL~8N^Avhn;BAk9JW=(V63~sj;k=B`_CQx{kP-npy z%w-1Vf91yAlheC@Y`*2PVYSK;B}U{4r@@i`{}d27XgD(dU73hJg%$ zMO3zf@YVx{VRzVPN|f-xAW&2=F9PHg_ou%ZjzsFeza6*QOgAtHv^Cu7XK^$<%mY76 zRK?b00yPxwD`Pzz@T#t~8Ueh&>7lV~w4h5mm3}x}RoMELQvcXryjDOJVCaOUEbT$U zI*&mP=;v<46RQvMoqoWvBS~ZV6dZmwEa6n&;KXt0oW(>1+u#YC{^7ieE*~!j@ z|Mm@-_xi+ZGjn1M9fcQT$p%sdQlS9~ zZN2aDD6wGQN7Te`X_Rer8x3r|TMkLnfOSU6oUy;8^B^vb{H!%IJ=LvlyR;+}Wbxah zDxUHw(trC6+rx;k;zia*Agl#`Z5;6TO}UqBstcO9EOs2x*pYk;LLRd$t^tx1@PR~h zGyxJlouPVv8aO$XgAH_?adQIZovjg(l6vzYFg<-OabPvE0g3}};VFkM zHqq;c9lQ2j8O+RF95R)Y*4$nz{>FutW_C_X*yZ=bDw%FE1mE5xQBC8EDQ#}6jgnkT z(RphVFxkJO@UIh`5P9OI!Nq2m4syqrxgTO5#ZFHOj5$hpO;I}SO9=P5VHZ0QWtWE> zfW`$Fh3v4Dx*Z0-$FV`=x9VU8-sVM_Pj?ThE=Ev`k9KpwdGZFB=BJe7_YS#x_{75b*67vMP=QpXcIGELx(|Ie~~`B==Y=C#>R%cT3FtbIp3>(($vYhWy{BJ=9v*{*=O$|W zycxB+t#Y{K6HvtXrnVK`HsJYS+5|NDX@;>>DOpiDw!z$@9M_XfN^L55TdqwH_H1uGx{i^0T7d948>-2mks-7 zY6i@IavoAEsyKI5J+@EDxPeDbWGb@EI%mhxO>RZyp9C+Ky(;ZCKy@C&T~Sf7nlfcP z7=HcFlZ&xoPW4wa}u;O< zMZxOwCr{>07pvA*+3f$PPzl9U-|Zh4N!^(*RnmzyLge4uoxG2R7Q0kdvnrS{d={2 zt`j={6kcBFxseD&H;sUP!Si2t57vKpAa9VV8!B*VmWyB5WIL(u{Zn1DyNSOpbp7B` z-}AC0=^nEAgEJOTdscJpSor&ZO|W{bWU<(WyZT@rinVNT}7iEg=@ zG{iXx(H*rqSRD<1vCeAnin}@Mo~mKrZ5+@z-`b1;-ZFmop;Shx4MOp8-6LWwZi7QQ z<*L-FGH-JA^pxk?X)(RNH%NF8BM(h;u!9dgmFavI7Di!SoPP}s@efw_R*5;g*FRt>_inG0H zm{yXBgmCk4WLg;ZkDPikl{2=MoZj@Uy~c9lShD=|vt}2Ti)K8&ftR{ANpUmDLHE{G zMJ@_QtPUJp6bi1+wqW&&OXf0RakJOtJRQ%|!>S1bwR-2p`c`zFr^Fth?Sj!h)ePMW zE~oheKzjIG2i2U-E;- zazF1_&Fu*}L`tj|CX%KzZSCCV}zj};rVrseWvQ4 z?A!58%7poLd3o7_tN+12uXSI=of9RC-_a{qc9f3zJpPOFjue}Lu~dXHMb|T`&pxgc zXJ|1$8Kq&;+UmUXZ(1K>@LUo+Ce@1 z@A)d6AtZn2_&=X7Ps3fU;HG z9a^_36kXT&h*Tz%K`tk>Cq?r@i; z6cI5Z#5z~`XnNu1R(kmH9SH7BV|dC9jTYKRx&y*J)69XFiCs({0~QY*5Kc|a10drl zvcza>t~5dnVzZYIdu#x+twr0wPxh~Zk8x}iji;@Slg3CJ2-4GM!#4%BU)vYY0e?;( zD)5Xv6Pt!BAF3avTI9vvlzdy)&OANF=ZM=xppfLs6@gMW-6Gb2Heyjr>}tLSl^p#+ zfVAHq&jnI+^(($ZQhK`U??841e>MVa^D&69*nxw*_lR$udGI47Klu-)&e;44BT9=e z*dAkunN+fb4SQ*}wR06oOy0lFl!l0*1fd{iT76Gewj=MB-1Rsaaab!?BYr8W@no!d z>bY16ZhFL`L2LJ6=PC{X402%uf$DFdIV;S1quRUX z?9;F*Wv+|D#8{xDQT*2k&!cL%HAmWBez!qttl?RAA?2T8Uz;}E4t375d0kr{{I-_b zVlUjK(pNh&xc`NoW$)4e{^{HRrc{*a29_zeDRbq`HQC>72A3!8*U3O{C=;{C%@5q= z8~D=XeR55TA0LRWj~d)n{A>4Bw6e$o`x1-Pi_tChQH8Nv@h`VgcLLQ)Em-km>)nr( zS}!*D2=+sQhb?ve1#)bfX|FCG@vA%Jci$ctxBF~kTzGcbP44ZcmxEeEjWX?=jcj_2 z{tJSZ>`>*`>wad%=O<8XMp4ic26}3V1gcipss39ycOeWCRW^S~gfI=Q^|1wBKoq;p zyKntZ0*odLgWNZh3SMvy2tYL3z*_2O93}eLm*?PT+4#&i>FCMgs16%ekWc>?_V$>D zI+v(~%WSK@h=*7wZ*+?W?6*p^YEwxtAlAI=h2{}F*iOBW0IN(OO^;ZB--Lpwd(OhU zhC#;=T(Jba2wv6pCe#%tCeRQG?(C$>yaNM2;-t1CqTP+B&OJAn0E>D{sclanDJ`=I zh)S96sI+D+Xh+Dj;jG_;dnpWDkn;vgEW^tNXoi0(i!pYLCU}Klrrf`k0PlH`!bS44 z5afqL$k6WV)?)*81>|+V{0B`6w)h&qp6)MtzukG-Sn=}tTY{j3-8yzu4nmOiXt=N! zP=5Bun!vJ^6LA6Y1`*QMC$H~Fjq-oSYu zlvCEhXqz2znD?v~r~Jb%BYzzHQzeHZjv>xKc)RwCa@R1mz=j=uPY-h!Jqg^-zE~%A zYP#uex;Q*8UFp~Ec#Tmwuk-Rfy(VIfbK%@;==R7c+2N(A#J1@d9UUbcxM{{gf2j)} z?UFXGe-~G z6ar~(hJ^?OsZ4VnTM3Uj(70f*$nWFK(K_})RsYzzjq4w`WRSTYI#lp#_0L*s#!W#UAB-}<$GO1&Pn(8>}Od)+Ek9F3aA z4YsA1Q7jxt%*u?T*w|HMowBUt0M^E!QA-cofT8c2dprc;alpbSP2exR<+TA&jsK%c z5Ec7xn)V9s7Lrqw$2G0i9%c8T@AE=boc)c*dwQk;NAvDmc-W6bMgdvXJ;DsfrRQh4ph0C1hFtZ@f6tsJYrPra?>#ia*Ne3y!Ck_VPY-BgromU;k&k2wpgMX zGu2p2>Mw{j$en0H?8ty84yrkX8_4HmWGqnlFh^WVn!O7YSKA}9o3z-^4Uzx%c0_-Y z=&+p#UTzN?P1-U*GFF+;vE~9@LPSL+TaW84G~e=3VH4+J63=U42;5S3^4S_3?LpzB zn2&1>bFM?ZtFw*MI6NHH*HMip2(eAvqUCrqhsE+(95*gdnXTfBinU@YTDc*IXXCPF zWf$(rG4H^^Eb=@due8Yqy=E@{+#Vvc#*Y1H^wD^M%kriuDUWH!6 zqu3f-VY<|MP+#pmAjJBsGH7xNc|OuuNvMM@r60prHOn#Eu2W8$o6yEn0-d<;bg$`P zzg)Lsw1i^=!6Wj3XiAB20?2V)c&t5Y?P=TPd-zSt1F>^!cwNLBwd4Luy8VT5NJQB(R%$eP&1ELyy`r-|yCOz`WdbH_11ZYJ@(){PA?YN@pLw1V+-|dCz9FU<5 z)A6*nYqA$y0xEEjIyS@&^JjkT-~b<9sQoX?SnGnq)+ah=Z~f#zvux*?opudbQVo&g zIAXgb#W3DE96Y?8l<^eYS8M!&ni6%kt47#QjlDJWcJIgm>5hD=aW<*^Q1q1=9F9^m zbRz3iSZJObx5BMhJLP>t+f|kD`E1bnqtBJG3mf=W_DBPxsNU;jqi{KN8FOL8#WQK- zzIY52-8-C4xVhD%F1JAiatDd0J;71T%UFMx6x3szi=JM?!?Vx455Mx?GyR}i^`iD2 z<$SK2@Y;#*6J9vj@#ouQTzP`0gvmqE6TK~1ejmYs2MXe-9AH^dKwZ$L4FvelQ+hn( zuxr?EFIOHI7`bk(<}Gj~(Uk*Y2AQ%zK@@%g(7sMMAi2hRtHNbc;;`oAAlf(Ab@yY@n4en=>1*jVf= zO5JIG3rk#ScHC#QL8HXJWLEy)#>}fx74lzhpdRp?Vfk$XHPZ zSx`>s8|i6^Gh7^$N~6pO8JG*bi>IBgUoQd#<3|G`CQ&tF_knmA%dG$u3aUYWQ8D-0#Cn6F@1EcIe`$?O+KIJqz zipB3sSWgN%!{VbKVY?Z>i`|12GA89nPW$BH{(Mu#LQ1e8v_^=uzG~aPRw#K3ka+eG zCj+Bjkxu;Pd8#IIB|$SzAnEq4a~l_WUS`Gti92SX*cQhYw({=gz6K#a)jtU)Y&>5Q zZ^s8!p-=T;p#8l(1_cZCKc&1if4?#dtXTJc*cwDO$)G+2E9HB6FfT+|J>rBqYRH$} z**;Pj?G;OKb`!^m%BZHLei2aW#1U0|;31BZF#RW&j&U8FlmzE&j*$KmA2*?84H9gC z_2FmUt>uOHaQG{%B+bf9{QNnauBnd^7VkkRN zsU*utp=_gUS!RBhI-Sq^`#XP}$2pHqNB4cdmg{S*#GdX*6i)?iIqaaA;AtB){qCP&JjCz#-|bPj(cULW9H z-uCH`Ysm5Qk()%&2_-LCJ8GJXIfeOfjTfQH7@lbCn^1F(wOQuY+J@LLj+NFFl2a8=1PEehO>l80-DiOcLQ;)HyOhyl^Ba!)p8AilgZzVt(sJ%t9qN+H2uM z#CMcOl&MSYr{dj;nX{~2VUDvKQC?DXIrl3O&-%3q;mh?v!BTqQJ^{QS=eIG%2tMK| ztCKKajc2NeA$S?11y%wLO*VfZM+kTN@6x*iT%Tvds}hjP-&|dTP(AK1fcD4pN=XaK zOm#T2CpCM{aldDCXU8(Y>B_tQ_W>EA$B!`|^_e4|o>%*NFCDUc@ny8ffEWK<;WeK! z;R+@yFH+S*##oC~Bnq+UAyGLb+C80caw`5LG2wv-XFY=Q%f;h_fWWrpI$#$mHSL{S zkQ~WXMhwZn#j5%yjj08Z^-zksRYOL!B2kinH+UV~vo&Fhk0`C_3Y1A|y@VvWFUnf| z*H^8Y3QigQZesbX{P&-A2+>-J*20J~0XNI)k+n#wcUz*`c?gjiBr>Vrk(3mx zb^l1BhJ@-6@b7PN)9j-k5R;X;(dA!M$J#xiPv@LvzTz$UL%1kF5LV z)wSRf-UTi{NL2l6k+#PryvjGhAE$i}WH?R+_?5d}ND1Ay77DH~|G0yuk-SQLNT1T| zNvqO#{7k2J)}yuxe{GuoMqIjqGJ8ZFDM7Ym-5Rf$Aigx-bWA1!e&-X(5IEQ@8# zhUe~n$8=P@b|=aS4Zak(QMf63;XOSu>y~nVz z9*d*S^CFKVr~yxfun>MoA^gK=$yf?wta$&a_xTTid1!mjGqh$ws<%R;745zTf3G!c z=nzq~p7s%bEUUR{Sn>O}h{xE9BNLTbCbP5fmgTXtpwg(ghtUqNfzsPmQlpDiAAJ01 zJR~XMg}!|hWXpHTmFa!Jl^Xi`nopUBH$N(Rpw;!1UKB#`@szE4qT!sP!c6UZ-~Hy@ zHlOi{lf@@~>N|c-=QHF1yr*0l)mWMka68w_JYhl{PPf$5CS6KRJneppThXfQLo z$L&xX?bpCh2OI6yA?zWd_2KQqOVJ+^ek`Pa3rI;!)>_RAeiPn&q+=05_ZRX}_dTVX|e~eo0tnyE{WJA(m`_(r=y(%q>Gpr829bWY7<5 zj6ZUaT`5au<%R@&Dp28{XicBnpA87eP}W-C@xNszx{FB5xFdvS4Av2u zMfUov)ap9ath^^&Q!G62xIo2|;~G3SHC*!7$FAr1-aO43e-MP42{Q(tSf`6)iMT06 z+fxtah1d4&KSlyhjY*_wEl0%~0)Q+?^+N`S%rR&^M(7{g$!OT{8DG(G*QyNEAO)ve zQtFijzmTBwff;vS{;@4+nBhi`0?Jsl>W( zynEL0eETL#adrwHy>uk;>Qz276@l1gbN@ZhBJk?waK&N4yx|8>RvMLdI2mJsA*lZz z!aI-hJ?d&~SdG1yrsv!9&&iz>MlO;X`ul3U<%n%U5dEM*zz=?97T*q8xi#nTlBB=Xdv-{Ug$!I38}BNyvFCz?*RM1OaMQJGrQN zA`Q1-295(9U->pu4vMNUHE#J9TK1tP31rvT7&O&)D;*#2G{a~m=tFq2jyu~mfn zB<01m(IM?TIKsc0co_1Z?tOTlL-)8>V@eY@{H9Hb#1fC^ZYrJSgI0Y0;)k87hI#U$ z$3HZ0hyMltz(C^OSIitQY~ULvFIxYce7sD{O>lIe*B5;&;>P4lrg^z2Pr<2f<5eF<6r%Tocg;bHV0 zxXI~aXd>Wo-cEeo;nib@lc-wXXouH6%;r)!`9i1p@b5bjycQn0x_C__b{<>s=kr<%Y|FxyfyUEE!-#1le)4i&A0b-;zW-9B?1_2Qr1 zb6ff0yIrU^DE0n}4TYy;q1#t9YwV3eE3b9y&$RQr#S!)r<1RQR7#@L z2=YTi5wFUP{Uw^SFD5Odk3ZcisS!iZn%<$s?m@_DPV{9D30VaCQt55bLt3U82|tSS z)zEW@@Ev*9c!#SE$l;U2o2Bcac7nI{P;;|nKxh}`tn=FFCI5X7P@e>4s;(-s8#!Y;Er48D)h86eMZ$;9m1?MR z`4f7}<<5p*C*lgXMeL^!0Gw(g%X2oBE=~wUx~*?TVuKB!-HyGVu$DA=_u&0enMjkT z)5ZjBScs`!9;mNjTT^~U=YviX;wLU8&~&dxdFaEn6O1&hf8bQ1v3NC-&V?aJ7w511+u;nQ)gjiI`bK{!>3QJ5(3tXuRHSkGa^#a& zaw&;hAaZ&yJGuWdb*%@Z>(;@=ireT@7EB6fbmBOMinvu;vYXu><#Apa%-^cf+>G@< zQC?N_uaCERc(J}!rS+D4*D$;yBnyl%gJeN&=>fRtD33Vc`K$UsNl=DJz?5%g@;1=G|jTVCAf zv%ud%!f2N)x-O6G;BgiY=VC~RJ5RnL$UFc^W`}^f{3W4^@&_kGnFB*vp|S^xC;Ds(v+AC<)0Sb29-1#Pxk zx9TFF)|7Xa!OK`~t<}x*H7u#S78#$v6k*c?Mn308a}`+Y@q#^dPl*~1P~+!bT- zGn3u#Bl&!$XHSWsD=slVf7K_Wj3Xh!wnS!{Xy>72G!HL=li?%#6MdFGimq1V6B_HKmD|T4h4N>2v(*CIgZ40q^H-=v%BA${;$p{FdT8^e& zZUGciWpt3NOTA)R(nj*Mx{TpQ;1&NZQ93MIn2MU0ePHewo)Pt%c*y43JMal|b00r` zXu!6Qe>R>W1d*&HNj|6EFEy)YClVQ16E;suoN;juHvqu*w<3#}4oluI|v_S+C*p zFpr&3#V(UX6odSRYxv1A5!9xzhqIe6!F zc?+KM+qpjm6XX}fNO;Hf=J``LjRT@bfV;hwFY)Si`0+93<|(6`l0CaWfawR!N z9JSa}YKpXF9uL@0oir$5b0sq}J-foD5@jon))E;BL{gWyM0s^}l*2Hx1EF{^m+AuV8KVhOx(cVaTY-F}_cPbC}`_ zV-x=Q(sntQB}D~qlVmv9)QdC{z2_xpu#%xX>^|igrT{oq_h98@>rW?9l*dtA3%C|>Mu0C8(K8t`my`PFJ=U#AVRSzpAAZbB9B+~q( z!)0uyeDLQQGIJ;B$=FL-TM%`fVZ%Ditz#0>5cXjkKE4AtI=KD z20O}F5&K=qWJbeDj#YMOU!*7nT{rZVQ||3`32~1}8)Qio{rEt(1W--a`B~^9Y0I3v zjV>=Lp)m%x`GpHRHd}4iKq*f9q6Y_$?1%VidUj1OLqUvlYN=%s)*$ zP;1O>nULOj8Z_RE54C4h?gTWjaMNJ!``g_GM=QcY08 zXqP&rCcKZ@A=K`>!)?BiE9WjZ-t(>(bD3}Qxa}=c!RJ#kw2s#g8cv0ISkZI8fT7t6 zUhp13pQ6Ku_FY?p3bNic-?LfM6MCVRBcD!>i)ci3p~i{CSq= z$x4*jv*p8Q1u)k5<7ys!_zp;Asx%p2=Sj-XxtyLPuG8%Z(|O^!+pH8Ldgl?aMb?L{ zKSKh!0|8$?>I;t|h~_%uvxTi-b@&jPYZ`=Jp7^TH)GsRPCEWsah9u2eG?+sCM-DZtlowWm?Y-e@q zdODv(oVjl~jBlm(^EVVq@}TD%#uvOP--ED+`78sT7BOAEgo7I3~~?-959BESac%3}nVk^$Q& zSO7oX6p_z;p&+|rW{Vnfxy1HI)ZJM{B$U&^TO0BKl&PK7l2BTN2VPGib{9|xcr_b7 zcDyC>A*q<~7APR{Hr#(9t7;kn*tkzX zZ?kZW9BS6vN7cD{V^3C_1jzk@cOrIY<3gb3za~R(_Je1$ugU5iYP+}MrDVj=WcM?OyUIF7hy1%)ad_)@WsmQ1X)J zi@RAjvX8u7lDEg<)5pGfNz@x1CYAQjyN6E5i+n}a;ywp}^DKKFqP=j9E@)g5j1X@o zG3JEZeSSOW%3Kv*lmY^Fe7?M5m03|}0fYLBInjCSk!QX~UPLsFXrlHxw%KDo+Psj) zfTQ=aPsSB1Q;5g&0;i><`g*Brom?!K;oGkT4_#SQbAWoK$;@*<;i5cggWxG2k!7@j z@$eRp2j{r$owA9JxmR>aT8PB9F z!fLYy8Iq`Y^7W<$I}!iS4d0$3mW6V;iD82$S93N&eO2BkWj-m$7G$6XCrO znu^)vQmifbt8y7Hs?FNFZq=kuuAd~7-6l)F#}b#Q@&CPN$E2cR2D1H4*b0*K8lH8@ zX#6;8ex!~Hw({*|_XS|A^&0UVm_Qs4?-(yHHg1U;6hw(gC>*%AV{_0$E3V8gy8@F4 z1i7#JAZ?dY?GCteZxIRKAtF|lY_;A$Od;aqYY@d;5n7B6xC1!%MJCzR5f_y3%v;Wvn1$ZBHWprinn0OaqR0FL>u;A3M_wh^NfkN_GWv{ak5H3o- zkCG&DEN;O|`NSWnIp>W}?(wz64*w?+vL@!6n**P<&$wQm;q+MB0S-WQy1suTUgzap zDn?uS3Gh<4GjdN0)`_5hewY2ye~*da6_2WaE;NtTib2hpA=B2#z79eF_-WO0<1|;`@42`Jx_`b56hIEebzxjgR-*f766Oyk(pm>ktSD=t0-=e zbYPhg@Ee7nUWA)TnJ%|<+Y|%YsrEQ7U#G0u!o2-D|KGEokmjG&er)(Xx z9$?GdR)AOjawYK?BbA6hSc&=%G$!!U#Uegx?w)WFh%P!xFfZ%uEX^n1hhH~M+TX!e7 zse^3iww+|Co!VhCO8XIRfmr9F$|cxCa!Bp|gNPR+heFZ2g>J7&$jYUgE9w1b>*R`~ z?FuGN7~)8wvXLzq8sIKEqdS1L@}vHcQj2-uJCDCu7J2NV(7Gpl=c|3a|7-kq38N56 zpHSq{hZskR=nLS(dtEBdthi&Hr-}RuDmbqm!x+00-CG4clanHm3?F6;?}(34a1BIK zd}9CsQYkKHtgj31{dvf;JbqG!-E#^p}I|w(tMyQ;kL3-uu0UDj7X%B z|FCK+?jue~NAgK^as-+nUl$p@-|*wC!N&jE*sodF2uqgE>uW61BZi8R11?<=UR z#Jj{c-et|1d&1uw<4vm;xxH}|GaHNxrP3_5bM(rtW76Tnk)f+ zZK6=VC(KDue)xOTd2EI1$m`ali~xgj*71Cwgh|bQH+Ek=9ppJ$>rvP~Z39BJRqigt z(4W28^*l_tGi0RV3SxQ_%}r#Hp_tv&ROi%>v}sU8?JUx0_CDBMq0wo@kHn}ilwOF* zy`oW*VqAhK5>E_2@!(=&^0HV{vlu1RH1TSV*S12tovW~wI#}`x`bo(=yM$m(AEAEo z!sT@dSPn0KGxY3PRk3CR#8*l5iHZbL=Z}ET%A%Ox&bu&K2OHSlykcj0_^VDM44)gy zVVeiY_=!wBO3XdkraDji7dF-rOz7ifdl8cn8#dFnOV_u19|6xi>e@UntLC0VwE2>w zr^joFSh~<43Dxby+Xu&}S_UuHVgKm?+$+J_d>Vj{p6jSZ75faeCF3S^9MW4>pO!iy zJ$woT+=^bvT#4kONIN;TNpKquDuo)k@Lv)PPoz8d$^aUSNaGl@un-lDxyk{$$%h(K zBa0Dh(q#+yHjcrOM7_L%k4{1)jD*kA#kieuQ(Z(uxkiopWA%A=PA^6q^3UglcVCrQ z$g`4!TP&kF{<*iG&#}!jKj1&8J~92AtEYIl2wZ8K*(Hac1NF zS-$17E{qRP zpGGAUR3bU=6n3ZN1l(#{i9BR9e{A27~la+C5#7n{SsJ%;JcH4`vM{RI-}g5HBGwbZ6>@QNuc$KqPY=rJF1c7ydOrQB1vB?# z!6OvqCVB)h4@5i;$8=jFg_&PLWsk8o?-7+BkTxyZAOLX)Vyd>(T}N7vmYEBBicrM_ z4g^*@gV!Khz>?1?bY*D}UlcZ0t1 zCL>?pwb_ODj6I*xR$;$d(D0>poSIi#x%);KTy?!c_d9msl*d0Lpud%8VcC_!efLnA zb?l%lm_%PL82OJpH?lQCx^)Z|j-t;Jm6mwAs zX^iO*@MF<(`UeH1IoWduAn5LIr!#hNqN>zuG_b-xd+z*pZ{7=z!qq`Dx~PAD=ZBA# z(HzUb!kkD`WI0u?4p~wMLejpRTMWTdx(#(5$o?CI8A9{eIBdq zbvZ(HJWPn zLJOUCkC8=zAQxATX{A^T%@q@=FL)-v6=&ow5JhthC83ZZdg}I4@!2EE;ZPczEfJd8 zuY0b@=($(RD!G}XZPN>=ujNeZEs;br@xLnA=7#n32jY#>UEhQ|wOiBfYs%!-DGv8% zh2zkhcnMTBbssL@kzY(eiynp%a9(L%I=owmf;QqYd!k7e&HOmb57?|H*SgeN52GPw zlM>3aVCoZ(AQ1lO)JMc?GD*Jo6bgZ_S6E3^F9uUA*c#>|y( z9=!9e2fJO4I^KkDeX%O$q;#u}dGLOZ>Iyf38cbCOJ+10{lL==F?7Z;yXWg{ZhxigY4KxO%_Z{d#L)2V?MN=n21*599g zQbh6Pfh>o*fxd=L-tUU%#^KHOtBI$-B)XQt+7Becm5-AxaK(O{vIQ zIUER5y=oR!Uiyq36C~ABVA@b6+gL(Z)x1GJJ%rA zB;|#qFbUV`3Z0C`@V?I9&m@5WAk3Oq_U5giEquU>FX4-)v^{U{6XsBf=)&&mYaypl zV9Tt7Aex%49x=n2Y!m+wUYkoB^J0h#QS*z2WTxxXCQARsIv147G4Rpy{~UawrKYyU zV-)JEKShzz+b?ZxtCP0+b~P-BldSdY-C6X3OH4B7-gG)_vbmVHT8@J6UR7M+b7N6Q z6_3B;`-7rWd$;hc+dchRa}~qH7+tQ%mo|_IfdZh{gQs$cfI;%}^qfnO>kZI8SuaI_ zypGG;b=<&620hg&r%^os$dw%PHrf6DRxbfeL8oG3092%bTMkNxOGJDFX;V<}$8}!o zM$h_|_$4NBSi{0M-wKveCZD@iiazSuSz7UB)Wp%*nR~c9IO$*K!Ja5nx37aAyHc*F zU+6pABO{sBJ=sypbWRyOZ>28M*LAP4w`|~2J@-LLZo*z|U3P$6>d?sSnW;lp_jfv0z+C2$=D*oWYJk9u zUijf^SE>I3%d(%AJP6F(*Mmol{;tXg;KQqZWeG*HWj+f?TuNI$ssA`)IOIqWm7=7vO7Ha6k`LuqQrgnPBIxrGo9YuGvZyz6_YD}ufU~m9*`q> zosPb2&Mz(H)WcuggITuI_9p_T=vD~_63lI~oFXgV9Lf81b=*HV-ISN-DLe=W0|j~_8?1l8MA;`%RXfPh$gmE;Te{nxcy zGOMTQl7f4{^bAtuPc1>SEr*N!xtQQ(8SnOp$p>9uLehSvsqSfQQM@l+RP2}}LA@_o z%}!YSP>#?%SgLXNVnFrDiV&lp8oP-Hca_eu7YBDr@7}YxI@$|P{!=-|7_*9<+WtWR z11fMeRF`s0M#r`@@$!QR5|g3+eKg>5Ef&t`|l$BQ_4g~`87jj{qs zmn$W+zEoRJ@0ag4ziAoCOP9(HSS<~!Jy!HV_fqZb33vaAkTf9pn_b%piF8-t$T6nFZCfG1sK(Hf$|*CeHOIZZ!m12>-G>&w zt*biN-a9TI!i|g-Rpbao)Bmi^re_jo zUM7!;_vMPn#sBlb^y7)R4L?S}oW1fOtpsK!95{y(SDydCgA0Cmpjj6BO~L`>(d=`@ zmaVyc=JOd9i_tj?%VYW&Ya8rID7){?%kNdrKdh9*2M5)@$VfxV%{Vj_xN+KW_14s{ zC9gL4oha5GrJq+{&29T)Ff!Y|bUR0?bdyTUr9Z(N-BLolbaU5rir;tLb8ovnH?N>& zo!+pRG~aoaRqS^y;bVKMV@%&K`mSZ^sXX|vqy;r6T+>Z377)N`2!eW^^HV@NqRX$c zLoGt}0!sTNXmj()3Y6$kXkw#xRA(^%bfcF1FX8T)$Ug_vx9FWdhrbm2_{Y{)9$?uZ?NM!y+DgI|Jr+H_uBz~>$HSPb`v0aG1uUJqR{K?M;KLE_!+mWZ zq!8H(drU;P`E_mwQ7<$?ewx(-$%%m{;;4P5UumL!k+W0G_8Zo+#IvD_@8XyMlv<)6 zFaJ^dq6B|17iaz$?r8Kze>osDGhQ`Ifx_M|BWvhAgYMB!uXBG?Mh&6=o3-)Wry}Qe z`sV%xaa}qqizwWOzIlpvN^B7f&*hF>uBF|#@z%#Qf1IbcD4eXTB8f>=LG7NG-~nIJ5bJ+lUpg%7zL z@RU=Qwqmx_UK%t`7t$64*Rk?iIj&`2fk8;^7kWbD&;R$`98wuO`*C2=j=kz#Ll=b& z*CEy_OlbEw0tDdV69UHk`FqVQ1V0Zf6MPvhkl@4lyiuAnD#dusPg4R$-6{NP(k@Ec zs{CG-Il>dqN@u+@QP8-`x%uAp5npUi+26K#J_-mo5}R5_z$^AoAFIX-YzVdi{C11P zSlj3tw)syz3weRcNK9?;BHeA<&lCBU=Ud2yB($$2Sn)yo(|R!T7cNwrEejt1u8f#@ zlfA(SFmY?9ebT77h#zE)Pxka!m|l5i0BzrZZ2iM~jgyGI6BHQiC+2p6^2jIpChJVq z;_I)N{a>_8rV|ioKK8pXP8Pe;4gu)U6dj`O2iD_dtBJJK?XONHmaL9ch@alH=FzX6 z&+AgRjYg>XQ<}yzP2S6hrFSwd&$$T@ z6$N75YQl>&QLqHIo4^>Q?c4Ju7`2ky?kfWS)HepU_nb(g5MhITqv(R&17$sknW7@a z0m<;6!)A3f91*?h5hl>yLxkbH$dtmVloK91TnJ|A{5Dy1psGHO3EZX3u`V?}t}rSN z;jVK0Oi+>=0l0tJ?}KmwQhShN8Wwa7bo^aYt(JgB%xlM|uGJkk5nYVx!+rEpI=>!7 z_(9qyV1F%V%%VFcK!w|27F{v&pGRrMm>~#=V<)?R%#e_C%KW12JUZX$f^WcZSA`}+ zmq*3nT6j&3iXG9_I_0Pkz(_8tNbK-h?q1hNb7l6)FRsZca`*k;qbXqcawVOV(od@{ zyuXY_57OS1E1H>jdl5QUAV+8h-wc%i@#?@H7D2crO5Xu!o$YFZ;K4VnMQ0;b<*)$5 zI%CUt833{gs8jjGDYmlBeIarH277cW_Z!yQzvqHSVTP*Om9iZrUK7v_SYUr5%g0WD zG5WLcGf$u5heZ1h=f@Lg>$}VNfj+cCGZcp?%5p#$ zMvgQo<4IA(+SHI^2^Z%Xk1IO%B6^|DUdo0Zj~dX(!~LZ*0%GdWp_L5})b?1S3Z)ln zV?U|*`E%~A1PzebJA~)+F+Yof&CQDdW!aQ{2MA6yvO%@sry!a(QE*K4(Z^)SwU;U17y)~=#SAWVB39@@%<8V)Iv^;wq)gk7^>{b>ZHK?QJ~BKymG&985CeSNK;UG6`A(P7@w^rD=`8;L5r4xJxA%QX?=<`#XH&{#Da zFrlG1D50q+edcPy*wz%FWK%xfo&(?XJ*R`GNFE^WSfWu-HSDs-qwl?CJ|p(VNJad> z{RU!Wr^BAr)G?4VlDWnLzlri+uD6&O3H?By7?OYa+TU8A4 z65;A;`aID#XNE8)Dm-}T@ayf^pvv!=W#R=I0-=Kt_E=w={dRL#k zntmoALTjRiAqgc-l+%0*GMt|Qv!mvs*r8kgY?gxMkbP26%1NsI_>q1gBYk4&rcKM; zUMOwjv^HOSq3F0q*KwO%+|exO?1S&^?$>i{J=gA4d2r{fWcF)r#`8&`^IG+9#`YJQ zERB}BVPX@dtz~f2M4<8IOHcoRpgWlsCj(CI(y3o4ZNx7|a(zqqrY=#lA;>#%bKnR$ zg7jQ9$SR`L?)^zz~8EQ-6Y=lycw)y;yJP6uWL zH|Yhqux&4`W?LUAobyhS8{*DrLzcpF#hta)<1>?6!DYb7|9Oal(zS9IAjfAX7fmcO z5t<9G-UjSIS;2I|m0V6ehD7hG@}h701e{G@6Ktfo>FEhcqu@!qDp5sSs0X9=yPUAO zFg(0F>XXeq7l(yCxP{N8C$7L^bKS z%KiE8&5Ng1X1go~J7#)ozT8s%(8aCyvf`QqzS!Y&%FM+_JF?0Pdrtnk_4$Q!A4Uso zuP2{hp82^&>i*jgc1NwVUg@A*7y=dmhEy$NSmq>%nA_ULuj%`r_D5~JLDY^98?Qu^ zm8mbQpvzyoxx*)FeZjQ%SYV9}zgWy{B|_etg0*V7t$Lc%Be5cb!Mb_gKVEgZZSoei z9Dcs2-oO3$ROF;r`Lm&N)*`>+n?07g$tCI`j*bbUmX;3`jS4246pez$GPadqLfF60 zvth|B_XETbt&ShgI5x0w(Tw)>?cA<(mqEpMLE?c0?ssjzxg@WTnv~9%(KVrwVz2y9`zYKo-y$?gnZ3D={9d&lZ-}t$lU$FXhe;(P_Gu;-b0O{K!~N z?kN0CV~+F95rz2l~nl96+hU#Y0UsQM~ zwLRKMcgd9R7P0xSYjXpNEh0>t|1b-Qrk)@_Ub@+TgkRDLyS-xa05PmHJ8dIx<{QIb+?Bt-ncDk%cQ+wg6LYh6(!jHYrnyuA`rd7kE7U zU^Pg;rgI9%L6x`pK0v6P=7)$DCXq)X21@v7qRnD>3CP&rtfGBj_ZuSSj|@Q_??hRY zZk4+Z8BUMqZiNBpUV)~_~Y*?3S7-eGI*cKzy1ez*YDHC z?*6VFR!yynC;de?hFFv?J3n!!Ko{Lo4he5*g`i&*1*IlPz zQj|G%X6F*AFhY?6Yq2#D`i);<-h*FYYloHbZFbZAUfhAi!WE48P&E(Q4&yc>js$q0 zol$^)T7j6)t=P?ZR^5-fLQE4(jt>isofk5#wl+BsR6^~1Cvw9}AS8=aQ04Y(nrn>) zO-=0Patfw%kNR6rRllPkBb1MEpP-zmM*U z*#R$+&Hn!7Ew9~tMtZDVdpUeQ2SeB8KnX1YKK{d)j!9~vUkuX_$`onCT=kBr9k-ww89fZ`$Qs=k8)x=4&nTqLW6 zG=9x8#IVq!PO`yTVL^mPY)6bNAm>Yj++f9 zI>mb1v_ki@2!f{=S%$G>GRVMG2qHJQcaDzgJYSAj#K5Uv)$G@+O(J1>3A0?Xn)>OI zD0i_q=XtHlUIN6NaQDL0o*xN$B=k;N()Mb+-xleNjea@rwsJ+|K$DW;wddZA_1UXO zE#uEW6GJaS?fK`>xlKlI(hggxa4-vCq^+|&)cCpmjcd;ul1^(R+~A9}IL;4~9K}Xl3@hivcZP z_aP)cctqXbC#pwmNEUBlf{YwS+uibd;N8fU+gFdDgJ(XQd)bNd?;{JpO9k}G7)yyw9lnCfE0qK)a z`vDYK^?WI6P{l5Sq=Ueeaps7;a(Y5i3ZBGuB%(G1FWjKDA_DnoBt_BIU<%^xY2k)w zvjLdS$P5Y6=J+x@!qOyc!3VC=l>SZ4h;A5gb_%5!gZviae^bB>O+YTxN= zTLk@k-ANH>+E;4}rj$f;)SY0^NnsceWcME|C$~E0MtDAoN7Og(_-e!2F*`7M(5PjS z@X6|U*S1jn7cuwnmvGeq;Q>NbgZ8%DJPp8qXU2z9N=C7~GQP08@Nv0_8tv{%CY zvIQ4VSz!2;fDS^^Z1xlTp{;3^;+FJo(jclsSY!$x{ax4+p)RZ25#*A-8 z`^Ha?S|F*BW2BFSM2RozuZk)X6qd$R4g8?hh1G$f<{5>|sx5784etMPoYJNx5-hri z!Ah{km1uELIXn>~FyDRB@)H3rEyQqw=qD=NY)QM5E%?t>2x-#@vWM&G*3P^6Bw>su zH@EkwcH*|`@M|7LsHswg7cY<8v{+}|7REEPcc?^eJI@}E_(x(IA4vB-{UcY%aqH5K z${?oE-xJlk-1bApRJtkfbP!7{&q2|2y1sDtcIgQPy*k7``cnYW1jZ7GxHI=t*UkiH z?axDsg6M|=`uh>Pf;N6?<3uCeQ4`tT^IL}UZtsRY$uf0;*5VX9x7nj+*HiPmI$w`) zZ@*yXVUz*x9wItsSPb{3S};GF8jEulLo7#b_^5b_{)xo(CY}BRku%GnJX~Lis6&)< z!>PAUFdXSk4*{lYUW%B_P5&N40}eMlY!OZOg6}US#ahf|({s7U@90{P;Q~?(rYza` zIKLQ?sWl9#E?uqc`QMJGFGqQ6P~PujH%P9INDEOwmsf1XT(%XSJttf)a7j|Wobs}S zj|%x88KB6A)h~!Nn3lVGLQu-u3e$X5ZQ(E9tIVw_763@mjy!t%txT7zh%r`B{^{)k zHnt`ePc|kG8b@>YBbA9~@V%eH7780z6`xS#N4i+(&6^r0r!*Sc%dCnzB*bFHtc6h7 zREIaKE+^IJ`)55$`gO*g?$Np6Eb(GrhRnsZMPky36<_TkAePSK^0P1^>$a?)g@~td zwS;!mj_8luear6*RCU%&f-Hu!14LkhNcqY5x1d z>~}6k1?KyQn!qx`i1Gb2ik7R5JXsx~81pMTU<4A)o-9RDxg42fjs`MRass4mc2J9e zhv(;4gLPX-W(2u>6D2TTj!BJ+vaX^NAlRYCcJaAe3HI;%HTtL$S>s6SJW4Z=5{mCx zFZ=K1Xru$YtGBlO8lJlpbW54#O+->3I6p<0TD{8)gC~ae6$C~VvV&6zhI2@`}BD{V1ys?5O_)bxE39qQxe;pYmEAN zP>Q3v%g^E)dK47`UX1X=o}6b;&1iq)*=DqxfCNuDQ4gBzTTMj9v$MXf^e;8Au9~n! z1f5I%EZ?^9Jbp?we&^{^GGc3u>msI4Lb$WOkQcne*d>Ybl&H?EISn5ci@+ED)vQcv zHsGFx^@BAPA}2e)ODneiQ=9wjY~~Ax%YT@}(nBB99~_c^IYcM~;K+XqCh$$P64`@9+J>mYel;|hDvGo| z)bu@Y4!18*_Hp@il=N!`Kal>(-n%LZ;`dPM#LL0WitHq=I{eT zRU+FPiTF>Q2N%VWF;dH7WL+CYU8Z+H)e<%@-d{4 z{om>+)PM(Zy&jW5!vnDneHhKO(<%EOMush~~+zEju^L@vb+pbWvnYuJy zAg@hzcv zH!WENLppjEU^v-O0+HHIWE0TIATw7P+K~(Xn4^pLc%nE-48>$lSnph|FdQw3=M5`H zmK}g9p&8N*ba}`atN+`jmZ`XdG%}$TT_3Djzw{Gt_<<$PTt&7Ccqz^;E&EXfV=%P- z?%{=7Ao3&r5y9YVQ<^O+dy>~p-ZTvreoni0DUXi`a%E&>tio{)_>{5{tm2u2->`F!nCF4j& z$%yQAkd@4`_b8iV%R0ZS&*#(q{pa_O{L$m!{l3QQ^<1xQt(11m1;4O@11c>6C{$24 z_`AH1E@lJp{CW*Kd(aHP*FHe1gzXIMY90aOEWA%Fh2?Y3lRkTCE^e=Uz_;A96?`cF z@+-R0x^3E+F|;%l)b53zA`GJHU^)sl>Uzbe)q(C~fT)m)Miia(|4B=64ku07YRM=& z_R0q7z7u?9R(FPVw=O(-tBTkrTfDR?Ooh-uffKf?X}XG(?yG4ix9KB3ENT9{{Kkar z?>;K8$(3fNiFBI)NiflmgdD*{2sPO%W`2Rtlj>&il)LpkLN%UHC;*>P)j1$vS`t)~ zLE)aq-ldvI7;|Ku9M{iNve3816b{Y5@?ySDKGKchdkrk)X@}7luFlDo0O0<*34NS_ z-B`(+$a2~5XXoetUbOl}Fu@@9@G@@Z2~-nr<#PkVPe3TLGr}h)s_dky9$g1m^129I zO6^cIR;tYi%vMLBKw@?AT~8`j8I^V^NFNvUUh%WuG~3>%6&prSwwGV1Mmw4M_g$9i zP=Lo-P$+z3c^W~u5t7wAfQb1DNvNj{T879%bxi+{bIPh4hv0h8Y5(;vRT3C_&{^J3 z4Wd#t|A8TT;K{b~5P~}M1sXKM6yqblBfzQ2j|7&7X6EZKFXNz}8@yyxLH(_}6BH?b z@EFZB;{y!;%zuKNCfrwMM_aNSTv>>;)76>=NMdUQ$N#LLQ{Z4~wH6Qi@cJhkt59Gc zcoN<$!w7K%{w`DQk<_Y|0a&K+1f;Tq3t|Y41hO&7 z^+9a=eWvnU9N13Ppzz|?40Gz>o4l1!>_Lu?D2K?Y)Zd-(WZpk6!N z9V^33XT{g5@U<^Fs1NCZ6p8iE2$2zJk}(EEds4*sA!XipC4*RJDult34pRlluVEAR zn-Sk2CR>fzd3yA)=lJqlo;hsVj`pou}WOzLdfH zU|lBd6MyM~x$yZNqx$Mj{b>1Tx*?%gAq3z&;I5>HNR4rBny{aV^W&ZJy!}NA?g4XEtm#4qY2;&%QE8vXZPEoa{()gP606EyYRmY z@#x+~K*V`2{CH0mRgouYvV_Pg{jMilyLtuIJG2SRhy>woSizy`j+A--zF?sz2^Rcv zL%y&=b@gc>1Kp#V@Issu7mVn)*Z)-OO~mN2GmB5d^agsfgSmqP>uY-)5yhj7k*dF` z5X41Fh;nQb1e_59GhzFa#CcY?)oyq&OrpyC>?vi(swg?~Y{EDC^PUjBC@v?dQ|&YH zh1n`n&TsQtS`%ol-=|+wiO`UP@k;r(9Rgv|TY$`m&NdQhl|(A)oLi%VJvH?t;sI(} zIA(E?6?Dk}K{GUfo|j1-0TBQCCTl_7;5AN^xoaa0=2sBBUHgmkMBSct4mkq6+;`82 zzmGWa0{R)QX13)yxh5Sq=Yaq=s)v*0cSTAvJisz-SA`bp7k)F}KU-y#Rc&4NAg-Pq z3os9M?ZGZ(6>Jga`fG(?*m4?`SQA_&X&8v|l+tK| zqJYQtPVMo_cLG*7LkV>Y=#18ylfd@Tj3YE1lJ%1jj+gXkEodtv^(DCzt!y2(@U5$e zM}*@`C-MQlPXi>KfybWZ3A@(jCy(se;ShGd3J5*c+=LY?=aC5DOnQZ%w>v-o0E*9H z4USKZoNT3GPJPs}z1el<81@yf4!Deh`UY6m+@lxQ!Qb)Z5X5o5iai@09gJ@T1lMux zKVTT;aNN)x6h`oSfK=;W)I;VZ0%Hm=;;#cfz-br>c1%QAQT6e_e#jJFc$@OTkEfa* zlJ#UoV0)i~@Z@ZS4He9%VZ_|U`VGRO$f>D0;HPU_$H_`>dh!3o5|o$`#DP-)lSp|I z1?xFHb_d+1)FY<01{Nz_=*;cmUhlL)gLl8+mrWf&xcBf1pE9KaR3YwtXIl?EJr^4F z9HEN+bvun}VqtlZAFyn;n8`Nm&vw>tJ{M+w+IZr7H^S`xm^8X|Sm0+nROWbd!PDX_ zmN*R2dbf$)wfbc*tvzwF3QK3@&RR2RO%6wsdiYC4{t@{sA5x{zOU|91QKuxI&~Za2bCJLD)Bl!M?$dG{=G=7LdSvvLJ%QFM+`4wI0Us^NIj*GZk4HP&|eE%KexQ%-Q~5onNf{6-9)QFgpUz zeqP`ybM4jM3zM}~)>8HA@f+FjMFo~zF2Evf=-^MR9g3055{Khu>YC)ka>!A}wvC`* zbplEsEtAU|q0|;Or$l48swnsV+%)u;9Fa}@_)s|16oFBI(iligsflG$1K!Cp>Vpaq z1l|(_(fsX-ow8=R03+-YG8uW%wbXauvGgR>4rFtr-uTT(j71Q^-&?I0A{*snfu+H% zB^uy5FG1eiHbHXyON2Hb0yJ~#hX=uHoHRsOmDq4k|qdvC#`th)%Um*RiGs@A&bXUGkeo0{ArD^8`CTxp!zd(-`y9QS$~P+=yQD&c8(`Zh#Bx z|G{Q4XmD=?fu)CGTd}h&V4GJJjJdr+On84<+JSw<-(40L3c7?*AaYO-0-^WC(Vj`R zLCgh-Ag0vE5Mg`ErvkvB;E~rH@;?#&xiUDicRbY;&N2S*tSN*QMk=XhT`g_keD}i| zop~l75kPo&<{tfAES$SNhKwoz_)GhjKE^iV3;(yjLR|!yt9TfSq8UI-_V8hCUx4|B z1(j)t4_iLjO5C#ueD5M6T;M#u0~U)uoO@83bB&tZ2;^&A1+Y3NVDZ#gINl5uNn4d( zlOtPB@LdK5v}|r;s&Y_5< zsFl=CE6LmodZ9$DZ=+Hq~WOZQTyGJCRLI$?#$R9k<2!+=nAfcPyK$97Nx1iLAIKQF&NFH+^mij>rS>st<;UfHH zd$`Fx5BO`3!e2WUNt~@clv!p>u6anIw{0jx`=_IU_exOq*PC)ll$X*m_Syta${+2& zgNZ5h0KF7;<-c0#@fX@bB6fivJ$0<6Mu*QZW|2GAg38FsZTKp+PJ z%G5WZ-~tVn5B+0S=EJVr=NTVO8;B4@xHCsHZh;t6vQpH+0&a~>@bC8N%zbx^VClL# zTxS9SOQ9-ZVB)wL%3R9{Y$u-VY+s#QyYt9)D-@QVV~?h_6b?AT16n_$Y=1zk22wjZ z>ECM>fHAKqWTdoVFEO#w_1=Jk1LCoaAbU9@=MS*Wi;{$Yr{dpT=xRv~P`=v-4=O5G zlQBXYzD2`y*Ub4Sc4>?68zKm*2arI2cG)mcoipUN?D-5qxSz`)r0~5ts%QES5Kv*W z$Cu9rNc8Z4z<BhT^|K&zB>5&X6gSOSucR# z_rZ<(PC|#iSBs+SE72hImkpfAWpW#h_sL;Mymj%yCWH1}EN@UbbR;@6Ht~hr!i$H2 z_wyVmoJV@e7Y`pk@piqg$1%ms;4>PH-aYKnR79U2x8VlzCxyVtq2c#zXtO6GI96ss zrm_ubrY{CJjt;V1e(!9&i?2Sq0t(12EPK^w50;8v%ucvx-vX-sYeIDdMGEoWUW)E* z4S!wj5dn{|noWbVr=m*U5MzFik^);}-x?QRhM7IO>{NGdR@p#1 z24Nc~Lk>v!QP^(-KjPRM;+pdOP9<#SL~Tb9|MR8bN$2aqWeLomCKrKuK!T6>)!~V~ z+UEeX?ird=W%xeJ3a{ow_saiCzDDcz>kB-87l)Fu0{Hv|PWM!-e`J9UqW<7uN4rH@z3Q z_|jN|9%zWCFyNa|a|Ij}`&SASl06ZZGLKD9dN_1ux8BSYS2m=;txwQ_WZ;g z#|jU3$Vya|jo^=M)H6Aky|HK4z)BoQK_l7TA zZbx6B_DY)#4t`%7@)O{t_EguX%#I#>S*&9fbEt^jEPV;U;l%f72*mo!g30)@)xh0L zmVwh*Ms?3)n zQww`4_w6krahLiMpC54BJMtt zFIK@zB>v_H z8fNHnP{8*I3To$vQl|5}-(|IOWKbi82Aj}^rDM?n1IyisZhOk}-EW1Lq>7t~FC z{nP#N@5nJ@pz~hUked6|$W;)yrc0G(;}>a9IUx%VU<_;E-8S4`fLGJ(?IXy^QjWQ# z@Szf!R`mwn_cUD2_&3C}+D&*V`+NPiIRYr@JN~*hoHX$i;`J(EFzsJzFLy+WFo78u zkJ<)F<{~`ls9V%+j?$H1-zzklC4ti?ReL_8O;ut2Dhv^;J*Ffm?}S zB1Ndkqm}eDW2WYGVK=YlOHB-U=eSj+6jsCpY?bOFQfi71^84gdLWV`CLBUoJ0u-*jny(O+)UZ! z@7eentv!9Xt2q_bG6aYyl|auPooAJ-AI@J|;;3+(zYBM7pO-?7H<%!NWX7psD0h z68Ynguw0w5Ltw0tCV8h`d^!mKi-BG3c0^)6=41ijp+;9;hHeos(jDJLUrN=`&Z*YR z`X_{JNE%XKJXe4V^aLgGF6i`PmSgjr2n^X+>)aGe*TUz5TxXuD(tE;H+kJ1)kb~S* zg`u=RY2#WqBcpnjysBP4vnk!#?zz)HVOuvJ#W+NPwcogl{kdE^87^0imaE?8t}4HY zavu2m}~^T_eKS|;n}+Bo>@&dQBbV0QQ4>Y0?;Ik<6KmR`% z_i6$!*lZ6#fIb}>=6EvH6n>KlK;nI><2=C!6SeH#L_*zEkR@5(ohizgujWcWaCNn2 zS{yq#^U-%Xi}XE}3<5U4*9Na!S&moBvqW3r!e)68Lb+x8$ zinm+oZ4Mv?{5RV=Cn9ReN|x0ge3{WJ9AJhb*P6jJoMvR~E{ReTdCI)CZ1MAhebMVX z3!Rha<&GYEz8M=XeBz0=tT9!4a|_)Z%Ks`e0A%!{@8(y&3P z6DJTrnqDQ2A5Gu_R}V&Q>Z8^fY>Rk^w)a5nMJmQOG{-(Mql0n@CcX82d=`^&{r%mN zD-#3EaAZsAU3N5niXhIk7r`YE5m|QqR7e`HK@f>PFlF*4Cnrz(MIEDCBOWo&;1DBL zET4g;Th_$BT+Ic;HZ1nW1JuVKoDms@svR%=e(qJl1l-~7+5C z8n1umtIRHXkC*A!U^i&F7I(U@#5BJ?bVwQsj?dIcTl-?8cp34+Z~7>?9wG{i5ZbBT z8|85O`KuSYxD6R>KhLGLF5@u+QYbtFX}uz0a$n9b8Z%L>ViR0CW?`g`phj2)AIb-i zfHq#34dm3uH3jMaPi&M}ri&XV<&FUUdGL9HeP=)m{WE+kPY6`$-9g|bm=C}Hr;f{2 z6aZDmPEd>Ew+n^I=C>}wDVQ|ZhY&>AGb8g{KjZsG(03D<_QWy;UoXCkBlY*yGHBtZ z?S-5V84i|r$j1-f)E?69=Byrc7Tg)O=$iVZBR_(CUBWpt#43Nbk7-o%MuGabg33(f zn9q&}5_}woUdtWxBjnrp1$=t& zfuTk@O04k(`x4LYd`^DPWz@>c30b{Q3Y*g+N6$95Xb~9xfz&S?_d8x%_H23A;XI(k z!B>2HB)f}>u8%AS%YaH2ZU*jxGwsY5Lj*b3V%N4^ep*b}=hvXe59`LM3dN_?o5Ez?^vm8;ivfzUDakGO5BPa7pIP%NdP`~x9 zsOyWGRvF9+St#99;QbzCHtrps$vhbqym^?OVa3q8>ocwhF39?6%I)Su*+Oc%yq7X& z{wo>EDclAz-?Ndi?V$A%ujo!>ta`=p{8?$u;j%lL&Vw~H%C5t}H4jHuvOK~Vx22>g z#P%kLYG*mLqx+^qR45IAs=TC0@!OPP1l+hHy?`pcm7VX2L3K1`w1BcnZ#xQnJWR0c zi-EH_Su=#4Id7;!+npZg>c%DqbZvLil*7*;Mq>C`dqBw5nQA%{@b zHr}8?*)A1thb;jZu{>#`#Ql-%il`L3AcFCE6P#$L;ykV+!r}2j61&x&N{qJNW2~y2 zwO*w}349=1p=)MOdy7Wk%M`-=edDnxH=%O?&p>SS2aS^u#*3#za;`tf z;NJ&sA=$j5Pi-vtTg)8i_v;q-qj^sN;{|t8UsI$aC7VGoyHEZtLQK%nt#~joQe2fm z3h-oU(>Nh0+k!M@r-r4%cswQw@nt#XOHRY0dJwR!ca6Y^NoKMzUAhL@gu= zb@2!If>8WKL#IHUeJ#|hHMGh5&w$9I&0X`Bx@?Y~O6{`NJ7kR)Wmy|Ei1UXz)I7j6vqpmjtMKx<;1im4t2xo_}Hnt+OEIZg`glbRAt{ zaW1b z+uC(UTD0DrNb}r5>a*9E6NBs-zYNj%!0x&ieE437$bKl})>6|-?0Z{>`8yJkwXPadaCZUnsxYQ{V~M4o6&W@&^c0+LBEU4?uMsOqo`u`IqBGKwUYKi6bl z2E{I4fLR-`SiKm}41InGH-``DEiIiR% z5TQYB>G3SxCn^vaU{d8U0+J>Y2X?O;;FGs~RL8T}-;i0jEOdRIkflW>T1n~nQk`(Q z2=$gGi<&IK$>kb+Ziu0dz*m2hm8ZIME>2A z8X81~JWjGh_S(THOLr_rYLSW)vih@eHsD7*3B3flriJQ8`$HsE5)itRpIh!ih z-@PUQ=5)LPwfleY3rdC>h_=DB;^ME=YB_K8@oH3J#5sq|-+QiAJB&(Zw_f$nEfD;6 ze2qi&6 z%dduPsQf`bJM@%#30$_WLTd`!x%c7qT|>UAiDWZ~s)aba`Mt>GU`cB4JDC28TU)5r z*oFUH<6x6j_2IhsZM7j=FRSCdzrD79*^<*PBJplt7_3uSmo96*`o`V05XW|~ra@b^ zLQ^(hP$79uCY#>8ptQu8tE=lsqJ@D05|2pf%U)L2pqq3hY`*CUc_Y6GqM|LAshUeu$8fY587p zwmx!LTODHo4>+Lvbm#gw)~)u73I&>A4<{^6-IB-daw#Lo zl$nf|bQO;WGgzoxVY;Zw{*EMY5lv{lgT!_HbKld#;lTNyUdF;JS9OJT9#FwZf3`?R zB-EK>>=6@zwvmitKNdD`hakL}0F=f<;U3=WtK`jw`xI4X83Ze^skcTBWrpzo8Y4&m z|7-a&XZ;C7oDc6+xVqUnojT0uUbbNYyM@Uy+?*$PQ;c`JtRzYYvN6G33L5AmcjzF%QrW_g41K(EU-o(mw1iVY z3Ez7v{2Tm@|8=pv-d+mCojs+rW$%J&cvJnJ9)Z6Svgw%2CHdpG1cojdWgImNTHxo< zGDm??5go&Stc0^8FUu==pBPq`uJ;F?CZ-KuHdsVJ#fnJcJUKR@mP%`Ptv0as_mNG# zLB1b{0E2x-~qb)dt7VEGk zh>qO?*TqR~HXNw(84czmaKoK*J{yYeJYc5N!Uak|5}u`zA@CVGD{Z<^)U{8D@B)3uzSNfK^1!Wq5We4$-nlclsqOJO7In*to`zo z>*HNkF+W#a2&X0Pp~ZE6S*+I3%GDg`?)e=pZ6(|c#_}s8N}K9qmKVdYW>oMVJ)Gb) z{@mpFh6?mB0tB(c5#|9yDmgO!zk+Q@vKHkw(>X-hga$Lzz@$%Iatey|*>UJ?81ijahUIvn>f`M8q;88wgj^OEEvC!OJHFSKq^+Q}xg2X=cOOIeB?B zKEWDC5wJT&M;hg*LE$!naTK_%QXHd})sB@K>qPFBTwPm!fX!~Wv32?DJ+!imFAog9 zRod;?AuClKbvQvhH?1f?JQ1h0KV^nSmYywRI?W_+JKLQ`nw!B#x&HNu%h#lecRU4)4)xUIPt5!#=@<;XwUwW2b z$c>hhi={PjEBlE>Xo^h_$S^5R$gyv(mCx}okz7yDz7g=dkWz{wb%(ndg#;|AVC2<( ze;ymqY%j3exs3Ilt|YBwdJ*3Gh^cBScX3}MjrDm=j7GZF|8iNpx87N@ZV2~k|3sEn zXRt(yY4yEkQAxzZ&lQ5B-)Tmt8zu}yi2R$uL-)hYg;UVZl*R35@@Z6=KttESQn;6t zqiqqmwV7!yZV{OO0ADKf zvwHS@NYk?;oFW*%We8fMf4Q8O)SaR*RXR=UKb49xQ0lmU(Ly*|UFB|83_Q}-}wHDFzWt0CYM{8vF^_W+tFBBnOvKiel=Uh{W3d{eNp4ArwG zt3#A`vk=^u90#shFskQxJsvKJ`Bb&ERoc%24rVe0jA@J`3llp4saf~)-nhak&~brz zQ$}VA*QkB9s0%yFPYsiGQ_xlU04#d-!g7W-i|1S2u2~8j60H8!i9=;f3=jXXAOb)1 zE6Ass&od|TPg?MnH*{fRRvmw6>pp^`Lx>VO*qB#n$az2Dur>2XWz#FWQN3k$T@1-I z72u=XPEQD+*E*Qr`E$5nm`PuGY&NYkl@ z7edGnjTaRsqC;+W9!aQrY}4~<`O`vB8uRGagOHOe=nG1dZN+RCGJM><=bw&5qrkn; z8r8YB+LYNBy@zKEN)4o@dOqwO@P%A4$d}69wW%f-d|BrU%#a>eh^fSe-@4gpvt{G( z6L()MlMO#3XaYiS2%|L)8fV>~d=K*pqq>v zP!QM7HNzxlCSrgW(%N@%mef-rz)C$~XUHgA=6C;(a{4NMn9_&1_)-w>Lfn02i}=hyr`1=r7w zM&*GDyVK$(TeqvCq{>`B;`q2PnNv5B6en(S^6~_xt-)*SGy*C|&VWd}~JJ&eTn5oVJ=GTJttQMsf&7>b%XaOvOZyzvFA zwKwx|yw)cj9wBX8PYlcioaXl}M-tdK=cRUwF4pLY(Q)wbJc*D=)^(fw6?sfp!*;ip zJjZev*|f8aifFr739dIo4<6^jg9@g2@S4|0et`R)3OHeV7!Om9pbFa{bfMT|f^PrB z%csydy6L6+@iY~8ID=!Pp7E<(3OV$j6C4Sm;4l;L(vZI(%+AJp82k4&#cNVcl{&% z7KA9b7DMwhhDqxKgHmpDKfGU^4Pf7E5xjqg!!=A2|*`wVoU3u0E#T@@>jq zGwYwhL;19H?h%J4&{0Ty+*`UTNYAf9%QuY#dwRqHZb<}QM#+4=&)jOP2oNMGVS@SH z|8=&q!@AVY%}*GKr^o_a$&d>Uw9?l!5qB4AQOV;3o*#;hO%s?78}mLk#F_HVNqahM zQ=DLn(2dOs<@Ry9=238S@h z_d|8$2=``i_g%!DV0IH9O^0WC4xg`MT#Jr77Yx_Ux#0)r(U6hs`*pV>s&vxd!RKQG zFMur!M zIO&?q!R2K8*xkz6Wl^3t7W&eo_dR{TIDHQ4U9{?2U$yXYwHMS_6fBqE6soMRJ65VU z9ka9)w1x_IFlUKpnUwev%xcH{_cCABYu5D2;QAaUiE+jVWbp6?5JZxxt; zBg?m!YRP4WQntFfdH?35nP(i+ioH@*`quV<+bYAfyI+0Lv2n-Ttjx$x`S?d=uF!VE zsVR>~V|r3I>`I;&vs0DVEl7Xr=sO438HLI~;`}k(xT;#QzLWStfM;K?uD1)H)my2B zIQJ*D-}#E42CXeNb9vo-YL)im<@EsEnXzro>2Z$}20Lcr*Jd7uKD-%GTW2S;f7a{$ z=b6z&y@wg524kaLm^^me#x1EY&!n`wKVUsg)20t1e95r1V@H&upXWR)CTi`fh zP4nifN`u9lv9Naa(#PZK%6pDqW?QKlZCH0>Z&Kg66~nU>=8O}=PP23kwTF_Te`+aB zZ5Z1r#yYjL8xQbKP&dP@2u9TRaHzz4FgNrFyg-sJjmbOb)lvE=c{?TRp~+!qI+6IH z-lzF%akVn)tkcH?|JRo7ly(Mi9*2OWNM6N6k&7{DDEv&VUx7N9Cz; zK6C#2cVV{Qhn?u#$|#uD)irCg7*NuVm#vssU z;S=ps9raAAoHiEwvGH6}eh#;y&^M=li2e9pnHn1ekFt?ewOHO>|Dya-8$!^vDt}-X zyY5UfOZ<5IfNx?IY2RcwEq)X=TVD~TbBf!nyKP|>LIm&S4?4MgrQgX%CG_Z5vAtT` zdTREa1BLQSZsuyPX6LD6id4tUc>{uz^aBsOF)W|ilETa?TbEg0t3^$$V6`hkL(!-3 z!2d&}w;glyJq_BT*Rr!j;sxch(FywS6NCMz;Qj4m=w|{c?EO0!&jJpe!I#v(A4Pe+ zlQ;-JMWeRWzu*anUr}=BQ18YcIO(U=e!U&$h-iDU*l6$14=$}_y$~$YIteiFU?_P) zmMARz_tk%RJTs<-ir|HH);$?J{znyTd%?-A0=h1GMjk2F14>K!qg~6;?km(sS6o#3 zitR4a=e?LU>*TRF>nkprtPHfw?a0rY{!sDxYYLg$Y-+3M#4u2+jI6KtKATrVF0q3arw78$0b@4eqE6Lc+?q2 zre%m{$(02^Xx(03lG>=Rq*zK*D44!!Md@|AePt)(R?N~op`oe^n>;f5CtvIRpu}0K zsa0pC?ytCNuEj$`kx9r0VhqRf&Qbr>FmJKJh@wxQ7`jVF5*Ts#uVV7IZ_zYWsXbUL zhR|2q_k{bwx5ok3O`R~4=N}A3XTncDj@8%LZKLY@}pCX5S4mnW5@cwckzTg zb;K;yDGBP#o{4C&_vLKkbfdh~GV}4w$S+B6gjr6lyqH*RO}>CP@QV~{{>3LW?6=`5g(-IhOr~5(8}L4yh9L)N879F|1^UkM^WG?*_0Nn6QgCnca&R( z1hhWn#6bDq5JLRpk&{v=$*AclP)Lpflr0umxV|IR4xhZwI$1SzOY%Ar&@lhPXv<-U zw0RC7(N3GC(BGEHd%lNjjg@y|e0*RkgfcwTGyG}fWGV=*uZ^o3c7|&HP#B5tfIOAX z`U7bA%%C@yl3@hshEhqNIGy3e1%Y7q^ZlNAI((C3 z`ZWj3Kv_m|qhSU$RiqGU_XXF5twcUk!?wMTH+I04=h?soOSK8B` z@ja6D)i)AsCRGx`0t&m&b)fJW%ts=S3Amt+z*dy(S_B-wzxe8+*Y;n5ggF$O@*V^7 zCH9?R+bJn>4>EY1mg9tO-~4@XjTd(>UaNh>Oy$Zwx{ePn8cMyXQEV&r_AS1w7oqx=Yg0ACx=`cQH1!4d4>|VRYGVmf zWg<^k`A}MYelTN5^k3;iB2l3Aj>Lg5+I9j~;;>4Nx%6*WR{!E$+Uo=ClgpFOeAbHW zeJERYH3g|B9=VBO_5x@htu*c&UtI~t8ZmL*#E%TWsm-M`_}6D{Uw>x{OiX228pq-h%gOieE)oHf z7(cWZR4Vb(J)1Yr&&+|sP1#l}IPmiG_)D?RyNUp2(nd=?@Vx1faBi2}?fE0MoadIV zr=Q1}vi5GLi%`exQ8|3es=Jhz(f^5E8iC1eH7zhd&{BL-d*1UlBk&Q+Isv;cHkBV7 z5FGDD8$NF_>yGMpZ8;A9(*C_1NMd*TdGhVfA3rLqbsK68eyNeWS)W`vRO=g>J@4tL zujl<%1dy7pumyDoo(t1=FW44{Y_EmgWMd7MLO_m%y{j>2uWUhX8SKitN7zPF=}sc9 z9HW=!0A0VY?fKncjz_0``W7rGm<+iA`a{l51=93WUj;BBsS(dHDT|6ncIyX7($(Fz zsO#yJeU@(dCTSo#OxV|_`=&Vo&G0e(x2*J>#F zPuPajPNpm1f-o_db2KM_!ChvgyoTMOU(F?P8~&5p zC`xz5u=|RX9ugm?MdG`5S=WL-HH}a11WIuS#bawYKp^4FF(D2VKn9wSR~gS|$Je%| zs_^%P-lx&4<9iw?#w%t}H$GD@p(7K@4@L%wsdTz(d3_dD*3bjrVV%0~vqJcIu=6Cc zy}b@INsyu^>*s`;?y(>XIDieS7sC07IakmC6r=~_-Ok}eo@6E(c(dMrFwl&b-O+*k z2_^KC50E0hKg)jY%})DnUi-y^UI8;Wr!w8^gZ>HI6ChjpTihO82l3UY0$PAKB+ls{%0oi_4ld!1Pd3sdo37_xOsn;hjpSt||W4TJK@1sXo z?(Fo+Z)#@Ea-nY!jP$89UyUHeFp6Pt?W$%bf zYy21gosHBDzWdHWY$EEfZ`AL9+{&%)JiEVCw1X(`+dm@j-~=)-EE|t~%)UNs&`Wr9 z`6t)IuJbef*fAdSdgYeCUSg@J zW+QoYcR5{@cqB?k59YOa?kfWJ)!QIZNH>BTu#z=~g`JLB3aherZmgay{jlKZf8Gpd ze|utOx;Yvre}FTkJ`ut^6;8=2ucWl~XgEBq@0^~V=zdt3b*{7X!QE@R-%EQ6H)`S% z<2L&AY;5mexV+XUBI29Fk`&;4x$|+>_^X>3dOJ4p@h9SXbFs8+9~XkL_RrI=x_|MlVc$+>$MS`B}oZFU-aakDq&V41N*!aYiTGrkWq2U40EwYcIhe>$hs`9aa~cPjsGwXmym^r}?kbsy(Tw!Uwe z?8M(}PI*^uPRNk8+*U+z(S!J)e&K+s4R3C|{e6$Yjj>j4M_Ufuy*@`p6k2d#tK<@t zRB-8Nk2EtgFI5^!ulsqhACzP}eyi?dkU-nLU+fXRt@mU_A~Lbdx((L-EoJ>ZDiiE2 zcKFqR83mQoVO?2Hia*^HB40LTj8l+1zP?Eu|FF7nc3esEWue_{2f3c!YL}eDtV4a` zOLRzg_q5g-MYX+D%JWTyVP2QNK}BxL;^T9&>}IAmA3r+nHuZg5TD50qJG8a1u4D4k zoe--1I7QXl?&4~ys9YO~z(@-_yy7EtXx#;Ct`UJQ?0EmE(^JtcN}rtfsqcQ#pu{&4 zsr{k`z3U3ozR|~6>k96|CcE3v3a5Wh^zJ)#Rw8@15wyI%VkQ4BU*VFL2jAplzBXi^ zy_NdQ+F9ls`g#S^&L!^H*UT%)cF+$=E>AjhVpJ^FBvo2v!Rfux-Mb$pk99^U&_4A& zcWBiXUruCu)m1w2icjUcn-q%Kk37l^I&SLKU-9dE_fAzi*_FtRn<4Qj&d}mbayrn;gW;`8adj@unDI&Dj1Qdb0hjr0!Jyh4(f`*)p)C9*H zcYW^B+fSu(NmW?R#=rFb=lHe$#7du<@BCb^qUfW^Kj&6PYv*|I0(4}X^{eL zy?XU(cXwuKDStKT^>4Z5=PjwfDJSH7OPLP)qiO-;v?84%7=(ZbqX$R`3?@j|=!VfF#`ezVdH(O$`{VCEd0p2zCmXZy z*P@KRDQTiuCO%~+=DU!juQ*_bTb6mQK|2|$SOBZjkh=dGsRO(fVNMgRU|F&rw>VN`i3Bd0#?&*=Z2@j_dEcQ0FA&Co)ZIC9xm?l}Z2IaFt$O>#H<(+-HPJgmCZ#`m6fap> zksGvoq9)~ZQ3Hi^;!TP{5d|J<*{SRHI^YVm6<5vcR^=-6Z%X%B;%(OWGwRzz4D>oG zU5?s@J@lkY&p#TllrDN+Z(@cIDseiQuFP&07^Z*SfrQ?;zFpGX*%|jSONGFnlX3Ej znfr<)#pYj(q>vI=BY3yw!XXLLkG}``*#{iNFC7S0S2RfM-1qb){5m6G6@T5wOKweo z&svaI&}w*Wc=(|;-d(gIck7#Xr-e|NE9XC3(VI3|r(1mLpf5w@1tTy4%!JR8?uNRKQNYQIfR!LcF3pY!m z{k7I}*rxb?AOZ2DJQY;!d*tB=uush&s=O3{6mpi|=hci)xTOuN z#YB0eknz0DxOEh7=-8&UBj4eLPg`gQAWRqaQ%oNscFe=Bd%|)0!LaRI!p>ZtB%Th* z5Tj+L7YzeXyy-EwrFFLRo}dZ@0Oz_zN=C@1+LGO*gU}g?z}Fr3h_M^0lZsbEYHK7s zYQNTQdg(kIUrAq#`)eT3@WrB5?90im_Im^#y#EXPfW_tBG&Rq^o`ESFnQB|eJ0#|R z>B}ZFmBSrjJN$i)g0Q#8OYkJcXp3V0$V0aXk=fZZhH;x?`_hx);gp*4hBeQ$BOU&r zK8(}RSgegrjmU}t*YEcS;nVRcM=U%5I+pP%GYrra(=hFrn!a5VTWlfxodY+}SL*!S zJCFYz4uY}x!(T`L>9jd_V$q(y>6me(-1gf8eGrVM?^Ux!7Ki)Fg^wqTAyVlUmSu!i zWYa`yntU@(9s#-SDB89%qu`WTM)`t+Pfxz2EH$VI1>CrDXh0e-&*gydqukT)k3dY7 z*`MojHJ|&~HpF1dbekeFEVvz?s{2f==?G!46__NuuuTw^S+4-TYH`Llfmeqwp}zuCp-uRB*5CS10$^ zw455XXTRMkW-i-@40FG{^(%dfW6h|4>fS{1sn$K6K|ei0)7;HE1R*l!UP$_uL6gAb zO)+0DV*Es3AKdE}wTk%LN)329f*IMTb)74tn1eZ-#L{Aj_bN6mehVo_LK^+2xlmJyr*os_es0yE`J~+`Wk+^w(>OWTx3NUV8==I z#z$gg4sss{1uXHEWB&WQWJY9n23sW3W9hN$-TfiwJ479y*C`*8mUJiYFlYtAIGZYO z%Q7(|nTxVp{ULs>@aJkV$6~8Jk?vQRBa{?*cpy_~ofa9>MQX=|z3nbEzYpV|DFjcp z0L7D3Q|lS`Sp4h3{8x{EEX2v(eRT=i%N72R*@pAvVB@3}`%VmAfuxX;DsVVuyQZdw zErJryNHudUlANBoUiX_}w|oAF+ur;gk6my3r48`V%C{sxcquUw+~?*5OemvFH!-hD z7@;CAIS%ix32-&!3$VBfNwj@T8DGU+0|WM*x0xDi^+PQGCW5K zZ1_}NzWwDF1x|fFh{)7qDD}kr?b`;y&z@?vZ0+pxTjzPiCGBeehV}Qv0LGzT!SgSU zI|}zxfyK%VvAm;9y|>$Kq;%N~noF=zYq^hiDldHJRA79>GB*EWrJ`Ugo)=U_J6zG9 zvtDZOvE`4r#BvS6R+d^{U(LIub?2m+z3kF{MIk03ybo75m$Rc(;_U&J6|>DHhacCnRrcnZJB#V)A^&ZE$e# z^vNM5@;}ApNgNj*$bYh+S|+dH;%;E{gL>=Ix>asPjtA(n7ELIPwtcbqrJCNp&*hP} z13=y83$Xv4Z!Oio>&|hWGEC&yGU?^Ci#IEq6F+8@K7GsUp5?Qf=KtHL0W?v0Hj#^V zHhW299VTYm)1JyJOvstzp=E|aRVAoLeAQ#f3}-Y(Xk{$W>e=6Key6~ve37bOgl1xu za_{iGeuIC5+vPpEAdcFVXXWAn>rralj;?ZVzoR7e`TgNOZLW5u&D)-iGQQ#pr7L=@ zvTdLs#x-VSAtYkpenGP*QaLaEoQTI(C))9xz;+C%>4J>uG{41s^jqOzhHYG=y8kIw z##GAi58!UlAAckMuKENU{yd>#njf^r*rZUbDw(sSrVn%+sb_}|2t~lx*i7HpHZVgk zez=f>2L+X@xs)pUz(ktt?C6;MnEFHr59eJe5m+~;baeNC`?SK=B9onAw9@jEAHISb{ zfe`0f@|+##m+Vfg~&dCZPg|DTAU>O)6&d`+-KUi=4-A$RpB_mLZOB6 zmzotCD0a3m4VgTl77oLpsMKJMSywbmDjhgSh9 zvY&P%kB-tZU{?fDy?oDGu{#Ty87_Z z7I(#eIJL9pYvW!;1f4K@bC=ona^c0tvJOIVW3 zJLtHFPY*1|#Q@R4F5)89w^N<2x!^Yy4)$w2Yi#rxiEZneH{D95X`)8Hc&!{?E2KHE zGUIkxGZk!vk_oPN z@gt6yk6*f-R@b)8MT1>2c?F$TDNOM5u~ao~hWSLYlm;XO3s}%%jOm$@S-jO~>_ZPr zU%2dIDke9?4oXzq-F<##b8{F5u+3(1AR|<9R>PwU>Nl+^HsoJlvO=eC3|~3Gz={UDP>EW`e7PqH0@sC&KI7cXyB}x@>vIVC}%Q# zYoO&PZ}&fId;;E|!PEjzm+~CkPBeA2Z-r~+e17^!yaljjHDz%wF!0C6l2vFD$omoN z#Sd2&bmBk!{7HIr@$Av|7KQC!Vvi&W^a3Aj0j87w9VTn9qn&aRlD`?<7tFaYzMfT0 zq?0Wz5o}D_``KvAx#FI~K>de5s zGrrA|!oTkb{TR5s_NuADEL{Fz4kjp2()e;ary&22UQf@?kjvdYlVXcGwS(5X-0{WM zmBL~4s4~LM39(hDy1KcZ%G)1j6r1MllugIki&wRUNogQkD#2R?qLRpZFH#Z2C$T{d2b7b%??~Da}CA`?AKS>G_Bl7*iFi@EDtLK*U9?= zbzgG$(U))Wcj~Ix)-q>N!&9eh(*eL%UB;lZ zkRtr~PJyOIh0t|?C(%|omG|APJy=Wpp|0OJADEMp%B&~fVj6J<7-r=I$oK4MG!j@_ zD{F2cq#+j2nDXiDBSC$}=eKwOTKHuRYV~_Tk*2Alm8D4<0qi^h{uN2(kKE~Vi`O^T z``>T6(7k%x1B^(j&kDYL_Gz%WmXcp0>|^j`{I*ISeC&_(*v05adC!jSc}$`GEj+%} zV0!er@_#!1RBW=>d?nl>yBC{8`I!wGa%f6o>WLiMLO0S*q)bW>orztZBVmZZc%0~R zNh5qPAg|yKTFEZnPq!)YCQecrfg(CTkQ=^fX~B4(i_W6$BJH6Yxml=Mr{%(&uMWgh zFgipY6w~WjnyfsaqP)1F?y(mO!>R7>abu2W*9(@i*Mg2~9P8wQRy^j{VTL`K4M8h= zgP64f(Y@V~cwwQ=E-={IM9gK7g2hH|RWE?S$_F*s176k=GNuBwzN4p!Oj; z(*j`_fMrbu2|L1_f$E_R9>6HHn(Grq{CLzu4GVOn1#7f=3eBI09deK%rv{@nn+mh| zW6+4GZ3_K47{I7xR+^vG1^mnS_HRQ$zvbjG(qD@6IcYTZFYxbI?PNz@qlJnMZPOKo zYVdfnE{T5S7;!#QC5+k+E$|Q5S{_Ke=WH0v;H>Z996D<8vYI~K-=t!4lVgXC4Me{d z`e6xFe~$CU4PsO^OY+)9_Q^4NG3gzp4D#IDN7m`cVom4{A2yli`L18@yilD zkQwJelqAiuVot+fUXUKc>;#2~BTocp6RuWl4d)yc6N$u$xi|;#jTC&08DPVMsR<-6 zGpFQW(og&O@kh~1*1`MSHhvqGHjO*8(U{{F=~B}1ZfV2b8=KRiVG4OKk()`v(RbsU zo6D)Lx%K8a0t}^|W`Y3-u;1rgknP1BRZ1ImIlLn@6;#%rK{dk|^0=1$l;g~muq?t) zeB_#3GPu<@;xCH*7%S?IOg{Lfu8RtETnxP?@(+pZf)j>-i;GV%tNf@>ji5sV<$zr(WIWv{1wAk61dIJ`WkI>UKUDqv=A;FZ;9)#Dv0ABfJPCGA zFW=5SEg4-B{F*wT4&^a;yMsP6sb(Gg7!70NVX%nkS&!ufA~3wb5Unk6n=Ma@Js2qF zEZbMR-PP%@P*Aq@Ojl==dsXxuQtbc7-`wiF<4w{IQwsQJh+Y)hxo3?-&Kjtgk~v4u_9XUMl0^IBs$w1|*KcO&+mZg$lW2 zHWo9Boq|7!m2SX&@(+I3cp}3=5K2!IoIKNwgP*+la>WW;>g;kdTQxiDG-M%6%6Lhc z__7aZ=!@mKSTWew{U{jZ1+~^0KeQK7=&)3L*8i1>$?^s3ikb|zvJtcn8;fTYKD=O` zNS_EzSOIHn^F=}FgOx8 zzn%CAm+X<;_dYquClN+JET-&WD>l-+mpD!A5WAiyBs3bI#R*s33xQ&3>-lM#j_Th$ z(_VMYN%zo78TOU6@CgS^S1#09>|c~(F4vj<0ZBCjdJ6)#sGU_QWwb7nahg~{SU=qS z)7u%|fy=?~xZqA`?Q<|mnA69hhud<&r>hvu;d({R=2*FdhDiG049bONK%sChKiaZ&iE3q3%ismyv=eSUE_kbQ{6>=5yB+W$xf z6MkxirTvrf@q5GH9@;+%JqSU_0ml(_2v^5Jyjsy>$u7D<>2;d>n#7B>EYL`1B7p_4 z_{Vdl(i{V(Vio)>8V^3gfGp0tptICxY(3jd{h(v)Yx1&lP}XeJ+5?f?alQKXb#qpj z)N+Y@viF~-twY-R#)EI;_#A6>>Sx*-5D+NM_nYob8m5hn#^dFL#cE#GBDmY&^Dz3B zg%2m6XAzpmhJNBrSU?o6x?{K{5XAk75;;jd`^V3?bmN=m{OKDLn%J7lDUCI8 zD^l<6jPK3V3e(hAO~o|TYcp>$8EwT;Ub#Q(ClnbZB(hZk$j)oKrS&^Pr9r1_@HV{E z6Cg4^csEut#KjqxT{v``(w6yShhWNdAL>URc#jLWqo|czk-!_;i%-RfRDdHrbQhne zCMRbQLXaVzSRRa$IO+jXm&9>u^0A{okDUPVUGufo?ZxsFZ@ob@GH_~$U5^Qqm2njE zv|mv-QF^=7By5^y7PspbhYaUI)vwml(W5@(=7LNsm7YGJ(O~*hwey}K{q>tl>Y;;w zy=wT*&RgnXTjR-x_f19M7nL@i~H2RD)35P zQ1dwA?L*uC%s81xk8EbV$~s}Imi;C}GD#KFE|FzfRBUFK=MNLe7bG0q&7y&LI=b|~4ELl7IQQsL^|{>4_fbV5e%dDTvvn=6 zyfFm_jf2ZyTrq<)=m%!H2^ojLi!mv(qg#m>hecoUzu znWxNmHvzwr^^4#SAGq{yLT|Vd#7x3xk!JQS24?`V1!9TmjOa5!(6pi5JFR4G#d8*e ze9_)5S>$fN)B7f+=9-}Hj+vwZt9sZ-0NqdRs=%9n>n3DS#;mhuse>BDw;Uf{&DxSs zh~iD2_|cC>$H#`ak=IvNx^Zg6jubf?a={k9r-{YVZ!xW|1A)ls-(j}akbH9nRdBr= z#}a9L;m0+BR>j$zpK=mI!5;&9HsnMY8VYP-2U9jv z)!lRZDZQl$2+r#OEj=JMjR27dUSdn-ah?7P=kF!JuHqz5qbm7l>4Ar~PEcnNg}j`! z^WPVYo?pE>iSO{B91-WfpVvE;pK)^nRU_QF0MCdA_AjpzTQQe5`wGFMEr_b1si9oc zE#F*b=r{Fw@-AA0?l%`D9aILTNl2vVG30STX>`Nyh? zuk)6mUF&&(e$?%ma&e2~T8H!I5cTLkrLJ!KtI8^wpl9nFJ}vkd(5LqKAd4-&ch2-w zghT0`tY6rKr&OQmJ|D9_=xEs)eN6PCo~NZUyi^{*qL)PjcbKnO>xkjETO2u+&U>mK z-n^_%ynA%FC?foR+c`V%SJz)|Iswe!luGt|N-;itwm-CspDzEfY^cWp8aW>Gau` zNwAxz$sW&=Etm%+vB3b-uod;|Nq+E*S+PaP;ugvj;f2@5l?0q2R9w<0Ih=*)NoajA zA_~&5+mQIL0`blh?6D(YGg=R?8M$$Z%xVcitDNbb?jn`ihTroa6dNhI!^+jaN@$vB zRU6;w+Ba@lS2S}EJ6V~t*(V2_Ot6V2SpzZ0yB6-4AuFX?YHGcblm_SBmD7A{XjAh&#kt#hVd{ zRX53M^d}YaegL2xaz|V9k-Icf#YQ!eOWRn|=%r<1*~qNZX2!V-*`Q{eIaqOrKv`53 zD|j-uq79l6Vrk5A+9ABkq-4K)fWDs|93n>E*peA)#e%ovzu9s%amB#;alfh0u0fJO zAnMXW%MRK2P(2T5+)e2<{*&F9STw%70Y9Rm1N)hnO53@|=()ySdm9ArjP`Y@$_Q4L zy?y|>OFY6}pqTp9hb6RqE@q)*UQp~ZSWTeQ{RMWI+363S>D|X_)8cP>(f^9GxFo8_ zc$LOB7Skd|L4d=aU+p`a%Y3Hkrqhs;rrFfkrgyx7Um^pml30^ds|2oAU18E9>t`D; zC_NpKYV6;$s`tYTO9J2LdWry%u*CC`)bJ zHYDvs0)68l<Zm_Q(2irr7-b@k$7yHQQm?Q+Vy4m71=h6oW{ZNGTEMu@ksYF zuP;TMLNM01<3C8lX|DMry_e|dKkAt_s^p~*e*DNmh(iuGDw^l)9&%h4i%4U*Yi)F9 z*@v10Iumv{uK~1Tr}@c0+0Fz$d=pn~2K0x1z4p-bA%Q>M!;yCA;+I+uB5U&=l=L~I_z+TipYjQWFw|Ingl;^RGek3{sPFQUtif$bVgd=cL+VX+TYW4iv zm{id36wrSd6{Fc&kmT~{`^4a+Yv;P}*d*z5Us@|E=V)#EA+}UlL zHj#iRwJSMukn`(o!PV-eR&uD+w`Ct#TM9B;`NHi4!zfgW%Sc4JrBC+0A(vV*%c*4kXN9Hu@2)BQbk zbL3RCR@N#i(7^;n*LwXJ2VTp5XXl1{cQi~CR0;5+rtN`YRl;2U(Fk7JgnqB%ie>dy zU*BjJW)d!6rK+Gp(6$d~w@BusxUvA6UA>?8SRS8=97Xk~E0>OOQ_f^femB7s9F}d3 z4Ov39;-MW_+BPI~iQ>ZoG~==9DEYc3XOt`$U1($?(uEL!=y3!p&f5IXKLuGdsH{{& zBWPK#vnR0cuBozJ&bt{=`RFTUY1Vh`vQtbh7<6bJij0I^hR2Y`xkRwZl|ZtV)-fB5 zC6#6PzKqypL)AIa?`;aBXkLJGZ`}fI3S&g554F7*s$;rd4q-BE#jJrdd15nqsK;Ou z3IMYS;-M6p74_mp% z#ilFSNoJr3Wg^baK;e=u8EqIxt%n{?tS1q)%P7Bc;e5KOr_C?E_U z<&h%;e3sA%2nn?~r*F=_2A;iS>cDX=q}N%b_!OUs0YwKg#+fDX>68g8UVwOXFDX8B zjP9JQeTSMx?+YO`ZoE;Tee^7kiM`?)4{FOd;#Y~oZA0SqrNzcf^ZV|Sr9XDm|1Wh< z@Bw(>3D^1k_&K?=CoOYy2Isb+d5t3`@ z{X-;Znx6T)bGW<9QqMXRdxI0{AI6XfYX0pieh2l6f$I^9KLX>2mCmIyO2+sMRz7$U zAuD!Di$Er4`pl%-atGKn)aP;>}NEzj@T&_1qY0{I_@(Pz(?LJd_ zAfR^K;o#|sl>gy0?09nP*5hkGtFA95r3l{b=?&@Oo^rcl!(H;8lbb@Y1@uXEd?!xB zDj=NO8^4bGTuSqj)qxV1KW=;V=GV(BVHG6L8 zYCJfY%k$*}LenaXlT5d-V14Hyb>R$G4@mK4bV5&QvA5=xpa(ADkB#v2NeT%PQ;Wux zKGpTEVf40-0MWr$vQIS_Ia~6B+1EXTH$|LTCxYqjhA4Z^2syN-Tlze1@8{0fE(;yB zr=La`qu5FLAhQTZ(Crh(UNBZbZN@-IbvA~2PBLHG>5dM+6S)mS%wkhp594snj_qyw z1*>c5t5I@0{sSWX8T~ue$Gp_gAQ9)!V3=KhT}hGH9%uCzM+LQDs=kNrYkN}-=NnXf zt_@V7W6@r|IhTvS9*(sSd_bExn-Y|^F^d5&3{~~FI$G}fz3zTN?+8GQ!mz+rhOYE^ zos5v0`qR|ICBE;XhW787BamBsTzy_;CHL~*(DcPE+dx0D>n%iGztiobg>MPCSLQv7 zT=Sk0x^})9lEJ!mE-N!d;=iR-!5d>xSE(f7;MIXK=g7UFli3{e6TrMugTydQGa{oAOL1;CL)~=j4cuM25^xJ= zvvVK_Ux+^Bydr+E=}AR05C7?Z!uCNVpTv`cz=~UO0VjqYWO)g455Quuu@~^>P3d4I z8uMUu;;^#t^XHV^yLvYIoxMTN^$_jDoPYZp>q7K)G8zvtRn9$}Q=bfrU)qTsQ`K0O z4y9D2dgBch12j53gFb(*{UOSf$N7kO&14QAK}A|n;JM!OhYAIMbX z6cF^lSHbkLQ28yi6%3pYE@y4J8|Et8<@;Rg`yEs44dEeqVBf0Y-l5nCJLNjFtpUba zsPFOk&}y`<&4i+2A8ogencDt}lhsyj-nYI6!$;_AfsHo~(rfGLhZ@y=1sZcW>}f?r z$3-nc%QLMBhip_i1TA)Ug5hyVTnD#_`pj&zu~Yqd#*F&R9jQ`Zua*p@paB)X<4j+2 zSH;w*W8-{QZP2KS&-NX(8hQQ_)pSK10iI6sdN^AE#See#Dhqsj=y@x?#xvf!dRai- zyL}uvp?HQ|uC{xtq4Ax(#OH6=a305tg711EDq^eo>$Lp#B8%Z+Q`r(Sq`Byi4kyxz zZa!igG5Lv0ZtYR8Fa}m?-^DSfC1J5+%Wi+gGJ*!qEQ3(mBUe z^;p8U?N{8!h{D<#1Hu9Q7X&HQXZS)|)_yy2-P;18Clhe1V?xbr|6?wwI%#W3RdKG# zem90iu0|NHOmqMLAl3*NkfcC763@kPhsuc-vhT$hi5+_ueXFqEe6d;q@bnofEYz=Eq^$du#E_!460U;ol2m8_&NlHZT-jeF*elcaL;MCp?f`oy(shw+qy1#m>)Cyc8CuEE+EQCz* zmmrVg)sU?P#|c9%%M|K%Ab7PbF|v#rf2(2OUB_OkBV-W~Y(m?|!JwY6D#rf5yB)>D z_tI@c8W~T^KxIF(seN3kC<}13MN(rQR3Qp&8T8bnPyW=yL??tQ&Z#n3ggIc%FWm4R zb79L?pVMc-1^-6I{aWfh!g=)3Rfsm*zMdax`$EDmJtwplbWe4DXUBE!M6ijX zymmIU40xfr6+9u0^c{l8h?Cuhfqbt2)w5J;Mwm{tsQO9Z3u|)pyuF12SL??Dy^9D$ z?Olydf2HmB)SDsW?{oNV68Pg=&OSa1o8pm)Uey?0BU-2-*Z31M(`H0p1-ZeEJUuP* z7Z#{nAR1)N(xw(;TsDKIaFQ`5muBmJi%1|dGXo!M4RBWz1_3CuyV}r|RJz@^T;91$1!?P8~=eAlZLH<-sZ zKFwVTe*FqPzW}fIsO%;<;$x_ap%Zbk%L7-{N(pF}P>lPLL6_YQu}xJz0C(z6!D>Ur zns*brB9_rV#kDc78WvTn5Ui}(s%x`N-(EF4-+|uF`Vp+JF(K26jR=+)UP`6=jKU|U zT_USZ7Vj9E9*)=2+(qpW{Pi9*cYo8-Vel-H-gL=HKZYzA|9_R0?+u#!CjR)Uu$B$R z=PPoenH+tzU=9u!tv=n;5;>q$o^FV4i4)#Zi>!Et~aUF25^~W6)uFh~5vh z$SbC6jT(A}o?7_U#SPD4Oyq+m{#rvmYEP1ckd4rkMA^Z|I1x9<1>4dSe#sKT)Uz z*L51yx5><$|I17a^trjkvzzNJd7FC^c|~uZr!_|E@3mdp-+i8cUf`vV77Wx^(`%s{ z&}rUpH&p9jQq#s~Jt|pWFq`V9AmUUy7dC`hbohQ@!8~54qzco|y;O8o(lG6uA_Q^P z8ENG)U^(&?^NN>8kA~?Ab)SUXA|Uengo;X7)7aWADE#u?<9#LW-L*3#PxFw0tyTe8 zPh5;p%43nlh^-hEpAkOu6}j|*fB)8D1v~LI-*Nc^3bi1hYsK*9j4J?|4jr{;c8)j( zuSeV2*ZHFqsys&BFenf(XZe5zH-n(m>$Kh+t&k*mD#QTEfkGfuH~L+UL_O8qeDrjtb5JU(mO@}f1PI#yRpmHqVl&jN~?vwzP^7>KK0 ze8SNl&mA+(hbjYUEL+I>RYlr~hJ@H&Q{!oN8m}mhgNpsIt}@hYjog2744wJ^suDEW%W&G#^%fohnItSnp7ZR0|sr;BRo8SC?Ftr6!c) z@ns~`F9$cejIqM;-KP8H&2i9HQXp?8#U2Xik|d6_k~fk`LEN4Gk8VVHE5?;rK)xH7 zK|afETMe~#Nv%RXdT!rn5$bbR<1GHJRzVk&?7(D-(O5CUK5+ls%5_>B8EhEjqTBSO z2Err2Op82BrCS;Y+affp;riV@EWjsny?uj7(=Ob+^hA-{qXv!I1P=)s__U=Mvtnb$0~0T9{smVnYGdoD{I-= z3Eb)K4rG=pvSzs+BFf%q_ViL?q^wU^Mp*!fcK@X0r$o(WzG?o_1F7 zUHpig)AMbq@i9wx!a$Paql|a1{dRt_92x@*NH%6|c+0u+t{M_Of|mUt(x(+FHVbjg z;3yvj>jT7CRKW~ad$g`)KDbR~r9CF4C%?@7e6y?QR7-zK7*+TEkewXU6X(vRssbM8 zBGZTCTeD-|9n}f>52(TNGD*lnh`h@7KW#+8#@4t)*NvQ2t(YwsvxXZ4L4RA`A-3~) zz>DJcXo>51M=f7(JJ8Vj$hSlxf%eO^B5Sykk9;tpMKF2`dkk{V_k!NU>D?qwCo zpV83unQM5Oc^lt9K3C}y?`IW0-mocfYW>9T_nN>eQ5jA2mu$C*Vh6MYmG1=GH*GCr(q7qFv48HTsELK=bOOhr< zAKQ%l5ON9NQeanA!M_!*G%AFcaxucv4PKlR74)3e#vrfcxU6o}4RNhthDHWG&-~TC zB%F@yJM1nnY(t#Ql)N`ytFca@&KZTBh!}TDtw$7X-YOsa;PiipL+Y%s=Q$=GE3vRy@h~aW#r%FdC zLIt46Uf|K>Cn*go%Nt>O)fR{frnztWpzopS0zc62vihQa_Sl^J(i!gu+xW3{-Q94l zNrjo6IRrgw_tPh$fa^TQC9rgO3P0z4qD!4{s{p(OO0KM`jFZ+XJKEr4WM_F=%QtKC zV(iy|nx_T#Bn2Fg)T&ANg>cKPZFWx#-aaAikFA>Vw_odT$)HC+$jlTHtzi(I@dw3S$^%8=<$zzlEqeP{&Gr&Fz3C@nkzru$H zTcD|eJ=PPe8wX8MNxd>#zFG0nVzc4QUucfh~pd>n5Rw6g-k1wAJZB&Hl-bCl3XAM)>&mEe;c-i*=Hp3mR2 zh3@lxc!h56L$*?=(@R_FC%O@0WhKRqP)ireh(3UOP9?XRUQ+oZBE+NLU(&5>A1W8= z-yaHvty>i2sccf}GvupxKfakHU&xnmIDT$5RjM_O2 zn;=EqecX{PoHBVZxAcK4u;!AEwXWuOw1UcC9rJt1fmzuZ8}=3<_f(fRyUl67_xRFr z(~WD{ws5hGYgt(oN2A!TXjkbpG|yGpayJXEKfyW;aR}G{veUXgGU!*{+pbB&E*ot& z9U&z~sbj+--3XnDIDs1XkGsoldgHz7yI8f9#=Qbe-QI#6`|xujUG3=8q^T@6^;Kozza!DB zYU>Yo5;vv?VpN6(>Lv>g6V`B!cULnky@jQKa(Wb#2DP82nSuwCHHk#A4W@UviXWRG zF_co%#WMC(jO^g+;_j=@HF(abC#K%j*_JHh@}f&aMmU0cAE z=Kdq&!B~)F$+wr2-X#O#Cl)`hTJhp~R#vQaLk3v#54BRK8|JYx!>v-)m;B;AjVh}A zJ9(d5_Ya+ObLc{Fzx~#^sW8qjIz*RBxP!xa(nrYJwMRJ2QylK={~0$2I1jk0vYUsxwyx&Lp3!EW4KM{U=62fo5QQs}^ag*2IH zL*5}+osJEMEa=HK?Ct)CPEg<7@x&a=CrKkcj%V9igLikS=?zx;!zb*-=hIwy02zLl zrb*$eQ7d(xV1I}t>sMqdHabX!`SHB~YC}3r`CC2M+OtoTt8Q@9%lyLy%-cS*z@h zRm%It!75)BhbD8>R39Tz`Lfvfr zfJc5@LGfnf7iapq0FkZh>nYSBtFO6L$JYOc=u)Zeyu7;n+A&^$_PS`Mtp^>Ti{Y;SmyGV00Vb^1#q7y?}p<5((~BF?V))g^MO2_^Dn!coAZvxTEX%(P3jd? zVFv#`nj?g^gcl5c_iW|PKan2ZYfUK&CWdG+m`nX(U+26ak!STzapKSA zk?#%yFM9xJo?0cPX^p`!OUZ}y?aTY@dXI(2!5=A_AxPv&sf>LoyeX!sGn$)_qZU-{ z`z&CUAxp)lzQ^-l4MdT10dDV$h#v^Ld!KOZ$IOe(v*k2QBfwP9vzL|~OAme6RCA3y z>zU8-a&ucECyq#)Ye+p_%1UgASxpS{n(cqM9qd8=rmoF+zgP1xF>g=o8i3zA(=IKysS9i_HGcICW=J=;ECbSpxfFN+ zis|LW+}fcMv)o1X*s5ps-ZvdeG-!J?se^c_^gm6d*jKdjh2P;fqetB~)Lz2PE{$BDIQr}9=_yoAhTr_hR?h}UInkOJg&4ln z(P5*{?dP8SFv+4zQ@N9oo@t7clin@l8y7act3U<0Emvwzrvp}NRH z=8XmYrte1%Q`mQjWT&_s;z3U1G_5i-@(!nc$v+T?%dS}{Zn}mm70^}>omNb=CA?($ z+br`dPyx6zI*K1RG1@tg2a4b7YpcH`9llhQ7W=Ogwif_N$x{}O%%?2OtxoeecSG-C zzJGAk9}$~pOc9?KVvd_1f2K|trz%G6%1&FNjJOdjP`b?cCUlhgOj*=TyBW6?jlOHb z2)4WmK>Uzetdzu(#mML%m`C4tHus_qG=t_cYqp*Jz|G+PG)&Eawcm6xIf zsx2X3gCKDvhBmk@(0JG;N1h<1!E(j}*Oy0sw=Neo^P+sENq2~huX%x~Ix8Bg@(((L zA_G8t-dX@na3{8{Ox(7BUnoj-tcZ)b?wr=NS$ zI%m9{L^=K!xjCSK|D{XB`IHX_$pZtHPqpD+ZlpUH-hZFi1-i7dQ zpr_S(?P9@V6n-P4tSvND6Jt8j1yE-P!!`GX3mMCYay_4QRIc27V?7x-tKCVe@uckk zSPEW7%nF$@xKpJFHp&6312iXbg29DI=e;!^RL>~I^9&&GOY(ZOmvduHzo{9gI-BtQ9~rgqiFfp+iy883FFoEx)0<`TrFGRP@l4N{HFLH1x5X87!_3lI!IDPHT*m zSx?p3sdBm3Dz+#O(KgWxWri_v$z0G~eyIDw$z@OH+1A(x(nU#y)vnm%lkWldi)Z5- z(9bObNNRT@?75(lUOft&sA*~q|43-f5VeIjxxb9OGOVXRzUZPqxw=Cc-AR9;@nKZE zn&H+#I5=m+-Z;dSD~4=Av?&~o*%;mJNleM!R3;Y41s|Npos8JG;G2Xq>%3Ob)Z??+ zKZ#p2!?pAbQ?{=!%7+I|c->rmV7k>oM=+os&TdHA%&1r-hq$e7iMUayd+I{>VJ%31~rHihNDHt{+Fi$M>e!CR?lPfC6CH=0`$YgB-!Ve}|* zGgu{lxQ;C+@{R0O@z~!+Zz0&$9`Kxo4Y&~EavSG$StIg-=v6dS}`Q71h1jD<`$mds(V6{h{f+w(6{4bDSv~vyc5lbMtzs`!}F; zTs$y&as}ooQTK4P}qqC^GopSSgC9I+Ou9tAm zkoj%)+DMWlFx_A798eFcsO?Z;V>X#NyEf(=>qD3CT4t8<-px(yll6V+a0 z25Zr?2-4JtvB%HoYNH1UGgoeNb^iIyc+Hi_e0^_nXyrig(^xhq_fXS9Lj!Hz!b0C> zWa!<$bNJYdMbwS1`lK6OCD07yV4$tcb2P8m*3-~KPuk)iWCwc%fC9}Ff4MWlk9ulV zjR%PkAA`IWNSU?-G0c*hcK|?jR?yK@Zi%L_@OEu3zlS#rdwKigG6yh^*=okZp93Hn zhg&Za{T?C=v&?RI@rV6l^_+xOh7i4anxILb@WS;;FY$c&Xt~Eiv9n}e`2L*vZ4-mt zd3BXzAoHLPBzo-C>n<*E=-@s9XxU*++P@m9romiAd%bwuPU;13ItYc$!DfL&P9Bk|K$cT=!N<+)xerq$h*c~fh7pnj%0~C9=H|nz-xU40 zc{Dlswtoti^XXrDJ?|YJGvA==h8EQd_imo~__~7xDFaWwDL9E|!0dWRa8o{oBA(h` zuBi10Lk}n5-q()gpoQZ`KA+0mIqs(8bdgPrw?A7+f^V#_5}^D_PeIVi1I%}yZDIoZC z9yUSxg=+90$7Cle7T0r_dlkl9 z4vl(LRjqS!(570u<>swE-z&4~yce%%X+*PCKwCt;)8E@VTYp6xUj0mGwD*veeAAPT zs&=@VAU}lmNj#Yf-P5m1#;#EDTvk0a(AlP^_9C_8?^6V`NvrDaU9P8yA%TBLbTmw- zin75UmUkk8d|g~#N<$ErEF#4=)FvkE{K&g^-;|8Ind9yaj?RSgnkj#&Eevy{M)hKY zDIT$(ERLSja!88zsybd%CYh?BDkP&S(wX5=-dFo>*K8y~ZP@^nlrt*5@Yk2u0+pj8 zA;fcU*Cbq$O-jr)w7A}_e(|Q!M-K#Mh@T)=L6)QHmNb+N4IF>QjY`NuHSr?aRZ75O z>$WR(iBg@-JiuEH4s6{pbe{bK$l%O~YjK}RyBki-TT=s}{G`}-e7^PZ$2mD% zTLcZL0eSSVIfiOy-H@8y4ews^FTbBLeW5dCa9&e$%lF^aKq!2A`|Xd>(fS*|f4r2` z)l~{@LoS>iOf+)?W&A19Wsl!fdKH^eszLp34VaOD8COZm5}^koX30*t6AAO1dUeQE zGFt1AxAL@R)slwVdBU5CDM^KK>?9bhVxxt6g1#{VeG3%B2Az zI-F47XDKg%^-oI3Cp8B(2$DN}U=DEYzTj{v6ZK}xx=fV2?<=j%7pf;f&<$P381OWC z7&zza{@#p>X4h%lPBgsrM&<0Y@7Ha-kCaPC0g3!kAi45gVaOP$$yWPRbm_jGO#tSB z_XbY<_P;xVDC6ILNLYx71X&IZSG~ArK`^tuv;1TCYmbUZ$K6O{!12rEv2DH!SLL2y zr9XJ?_FTDXuGblns&EJaUnC6%u{_ea9~2-^TBTMBQ9deDKIt0Kt6PnpS=w*XMCbKR z)4r-g_SwV*ho|8l{O#RQyS!y-Zw)I0OrL_%`K9l8hO%0Rq8>M>nsihW(}4&Ee|w_i z;u2zA;Nm^t8);Fg#XE3n`|+8s*;EV58JAxrYd`0yvQQTe0ChBE#%Tf(YFtxlO!+n0 zu=7J*8C@a`w+!#SWebC(obXVP(HP^A_Wr;CY_CruaJt7A7=ymrV_P z1)vL;UVJ{tZYlV`6vqJ~V{_lYd~9gwE{eJtZfH{cvA;zTRm8H&jVyazcm}Y3u7GZx zzZ=BrC@r!T<16R4e^*WsB)kxI@h!K3c)o~nI;oGdi1^dn%1X}GR?drKvAidJqVU~f zXR=T)uLHlaK>nP{(a29%#cYO!tQ>yz1hurO?_)sHOL~QZEpG#530RkbtO__N=8i=D zHLh3vJ}Qe(@g$5imX>}@G#0Kjl=0b#jKvsvBG`c@P4(IkvJnTjzyEZ{MOG)IOGgZQH) z-eW_*mg%DSQRd=nuFd}yoNjRhc={)(7$YMz+SxgbLy_jk8sVpvx#B(eV2=p5ca&@qjf!ocOM;yIMPmf7VthSx~ZfX zY*Hi7RgUNKKdh`FON?;pc|XVJNLn9n!wQs29PVxF?*BX3;%ffbeO}p2>sa&W&Cz@ktz1{TCsU`(udA3!m<5Q%*%kk| z+BBdqGj4(Dbu~`6@XSHbGrh4fxKD8ro|pwH~oP#A;RSHP6Odmh1&u5=SIf2+a^UbR79``@C`r*5!^~uRGqtCpx9kz z9or|I0Fp+5tTsM7>xiDpg~?vOV?3#UZV)>Zm@@#W8G!xVmY$e=$!K2W@e?@AA`Y#s zjh6qt?5Eq_PTetyx;I9dt1W2?*%$s6)eZ8QL53ZrnB0iX;*1TrQnR3K0Y|45s)3(&0nuRF|{I1;HkTL@0KCdFn7D^;YibGk# zt#JC~gFX;4^+RS$0EXHx$Sarb(3rEq?9=jvnX zJm{XgLp$ADsX69U?4iSvgyN6P;?BBD>ZKnj(oc%#CYi)FNNTDCs_9k6%XLM4xQa}z z>PF9ARoh;*i(75SCOz@fxSZt0kXk#-$Pyc=@OsCj_?VnTG<1uvJtSnSjTDPYnuXF9 z>SBwpIOuaHVbirLY|YY!_F_ohNB#Fvs!PFg&sKBNaOC;0Vt{KJs#Q?~vc?=V&lC4m zGnK&=H@CM-wc)Tj9?LIWRVq+m5hET6gi;o9sdlYb-2izO^|g14YNRqnwA~d5QdwjB zyjxI}CoUc`0Cu11yqJ|PE=72Gtgbe;w5ZdQv2xN<3VreuwcGHX?rzpC26)UK*xjv6 znOjXP7K`NOy2o1H>GoWi>+T)^d%aM=h?GnF6M-KX{=Pktf$gQizI?%3SWq_uy_^Rt z>)tN}4^^EhpvvLtm;IyzhMfw$@CTjNT-y z>fn5@`~}m-+l^Y$jAmEcc136xJ14LGHT)e@`lVzq%q1Xzs#aRc47?UZhK(K^*ey?L zG9EB51HJ1lEw7L&LF}(vvn0&jW%xf}ewrEAeE-{PaD5nz{;J-UKA~CR);Fu`=4KwR zqN1CCBrSv!{ZD^(W_akQu2VNgCV^0D)0Au@o9ArZffD+QC}PrmmF71fzl@Sw zAQa_KN8$=g)n&$*Y>x&%f6+s#PjiVx8zi;=c~Zw_S<ut#MD@A*{M@Vba_3wU1bfd9lZE;>(yEcdEfueg$Uf6^iFtDPv4M$Wx(aTwXf3 zsJIk}cc-P)EG;QjCHTmwY@(6hZCbSZ$_99I zkCw<-&E4P|7$5ZeTu{A;xQV7FDjO`?j~T9Al1s54?6scL7sm2AmopP52DcVAa`zW< zH)2dCP!(#86H1LZB~*-rg!QbJ)|vRA4b~Y9Qz2+WZ)flb@J~2@F!-lh1_cg>KMn*q z)JeaoraaTWb(E%Nm8Gpzc5&j18!0K zn;uHW2rHeVV3g0zMZ~tjp5MBLQNylYpy(&?iRyvb8J1|0}4ry!j zQ}i!T`e8M=w?QQLYt&6p8nS8Z+$xH#oxRqQ%*)ho;n4S|sUGHx2wfGat*~ct_0>;K zVCr%Bj~Jt5bblustfI@^+A{Fz zSdriHn;g?)_|*rlAG}CR%%Wz#e$6UQOiZNi8gA3XX9oxKezY+P!+lxIR>lqkJa@N& zsuB#ZQFyj&#cO}tq=z$U;;bVB0=jwGyVabC$UmnlkJ(5uXEk9#Q|3^7tu^CPWbdvA zU#X-XvU_c0n^}dXKcH*t>o4Xyj#G~inbpoPxk8T4_ zEzB5DLY<}z4Gp19O?uc067@jg@EejG4{ImZa4U`%Sr zIAQ1DU`9GrAiSc(Er#e;!`Yw&X#N!&AxaJ)y%%jQk Date: Thu, 19 Dec 2024 17:35:59 +0200 Subject: [PATCH 13/33] Added 4 LNS integrations for Flux --- .../Flux/ChirpStack/uplink/converter.json | 39 +++++++++ .../Flux/ChirpStack/uplink/metadata.json | 4 + .../Flux/ChirpStack/uplink/payload.json | 48 +++++++++++ .../Flux/ChirpStack/uplink/result.json | 27 ++++++ .../Flux/LORIOT/uplink/converter.json | 29 +++++++ .../Tektelic/Flux/LORIOT/uplink/metadata.json | 4 + .../Tektelic/Flux/LORIOT/uplink/payload.json | 17 ++++ .../Tektelic/Flux/LORIOT/uplink/result.json | 17 ++++ .../uplink/converter.json | 39 +++++++++ .../ThingsStackCommunity/uplink/metadata.json | 4 + .../ThingsStackCommunity/uplink/payload.json | 54 ++++++++++++ .../ThingsStackCommunity/uplink/result.json | 28 +++++++ .../uplink/converter.json | 40 +++++++++ .../uplink/metadata.json | 4 + .../ThingsStackIndustries/uplink/payload.json | 77 ++++++++++++++++++ .../ThingsStackIndustries/uplink/result.json | 28 +++++++ VENDORS/Tektelic/Flux/info.json | 5 ++ VENDORS/Tektelic/Flux/photo.png | Bin 0 -> 69090 bytes 18 files changed, 464 insertions(+) create mode 100644 VENDORS/Tektelic/Flux/ChirpStack/uplink/converter.json create mode 100644 VENDORS/Tektelic/Flux/ChirpStack/uplink/metadata.json create mode 100644 VENDORS/Tektelic/Flux/ChirpStack/uplink/payload.json create mode 100644 VENDORS/Tektelic/Flux/ChirpStack/uplink/result.json create mode 100644 VENDORS/Tektelic/Flux/LORIOT/uplink/converter.json create mode 100644 VENDORS/Tektelic/Flux/LORIOT/uplink/metadata.json create mode 100644 VENDORS/Tektelic/Flux/LORIOT/uplink/payload.json create mode 100644 VENDORS/Tektelic/Flux/LORIOT/uplink/result.json create mode 100644 VENDORS/Tektelic/Flux/ThingsStackCommunity/uplink/converter.json create mode 100644 VENDORS/Tektelic/Flux/ThingsStackCommunity/uplink/metadata.json create mode 100644 VENDORS/Tektelic/Flux/ThingsStackCommunity/uplink/payload.json create mode 100644 VENDORS/Tektelic/Flux/ThingsStackCommunity/uplink/result.json create mode 100644 VENDORS/Tektelic/Flux/ThingsStackIndustries/uplink/converter.json create mode 100644 VENDORS/Tektelic/Flux/ThingsStackIndustries/uplink/metadata.json create mode 100644 VENDORS/Tektelic/Flux/ThingsStackIndustries/uplink/payload.json create mode 100644 VENDORS/Tektelic/Flux/ThingsStackIndustries/uplink/result.json create mode 100644 VENDORS/Tektelic/Flux/info.json create mode 100644 VENDORS/Tektelic/Flux/photo.png diff --git a/VENDORS/Tektelic/Flux/ChirpStack/uplink/converter.json b/VENDORS/Tektelic/Flux/ChirpStack/uplink/converter.json new file mode 100644 index 00000000..3887d121 --- /dev/null +++ b/VENDORS/Tektelic/Flux/ChirpStack/uplink/converter.json @@ -0,0 +1,39 @@ +{ + "name": "ChirpStack Uplink Decoder for Flux", + "type": "UPLINK", + "debugMode": false, + "debugSettings": { + "failuresEnabled": true, + "allEnabled": false, + "allEnabledUntil": 1733331880270 + }, + "configuration": { + "scriptLang": "TBEL", + "decoder": null, + "tbelDecoder": "var data = decodeToJson(payload);\nvar deviceName = data.deviceInfo.deviceName + \" \" + data.deviceInfo.devEui;\nvar deviceType = \"Flux\";\nvar groupName = null; // If groupName is not null - created device will be added to the entity group with such name.\nvar customerName = null; // If customerName is not null - created devices will be assigned to customer with such name. \n\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// If you want to parse incoming data somehow, you can add your code to this function.\n// input: bytes\n// expected output:\n// {\n// \"attributes\": {\"attributeKey\": \"attributeValue\"},\n// \"telemetry\": [{\"ts\": 1...1, \"values\": {\"telemetryKey\":\"telemetryValue\"}, {\"ts\": 1...2, \"values\": {\"telemetryKey\":\"telemetryValue\"}}]\n// }\n\nfunction decodePayload(input) {\n var output = {\n attributes: {},\n telemetry: []\n };\n \n // --- Decoding code --- //\n var decoded = {};\n var fPort = data.fPort;\n if(fPort == 10) {\n for(var i = 0; i < input.length - 2; ) {\n var key_1 = input[i++] & 0xff;\n var key_2 = input[i++] & 0xff;\n \n if(key_1 == 0x00 && key_2 == 0xFE) {\n decoded.energy_consumption_meter_elapsed = parseBytesToInt(input, i, 4);\n decoded.energy_consumption_meter_consumed = parseBytesToInt(input, i + 4, 4);\n i += 8;\n }\n else if(key_1 == 0x00 && key_2 == 0x00) {\n decoded.energy_consumption_meter_status = parseBytesToInt(input, i, 1);\n if(decoded.energy_consumption_meter_status != 0) {\n decoded.energy_consumption_meter_status != 1;\n }\n }\n else if(key_1 == 0x00 && key_2 == 0x74) {\n decoded.voltmeter = (input[i] << 8) | (input[i + 1] & 0xFF);\n if (decoded.voltmeter != 65535) {\n decoded.voltmeter = decoded.voltmeter * 10;\n }\n \n i += 2;\n }\n else if(key_1 == 0x00 && key_2 == 0x75) {\n decoded.voltmeter = (input[i] << 8) | (input[i + 1] & 0xFF);\n if (decoded.ammeter != 65535) {\n decoded.ammeter = decoded.ammeter * 10;\n }\n \n i += 2;\n }\n else if(key_1 == 0x00 && key_2 == 0x80) {\n decoded.real_power = (input[i] << 8) | (input[i + 1] & 0xFF);\n if (decoded.real_power != 65535) {\n decoded.real_power = decoded.real_power * 10;\n }\n \n i += 2;\n }\n else if(key_1 == 0x01 && key_2 == 0x80) {\n decoded.apparent_power = (input[i] << 8) | (input[i + 1] & 0xFF);\n if (decoded.apparent_power != 65535) {\n decoded.apparent_power = decoded.apparent_power * 10;\n }\n \n i += 2;\n }\n else if(key_1 == 0x00 && key_2 == 0x81) {\n decoded.power_factor_meter = input[i] & 0xFF;\n if (decoded.power_factor_meter != 65535) {\n decoded.power_factor_meter = decoded.power_factor_meter * 100;\n }\n \n i += 1;\n }\n else if(key_1 == 0x00 && key_2 == 0x01) {\n decoded.relay_status = input[i] & 0xFF;\n \n if (decoded.relay_status != 0) {\n decoded.relay_status = 1;\n }\n \n i += 1;\n }\n }\n }\n else if (fPort == 100) {\n for(var i = 0; i < input.length -1; ) {\n var key = input[i++] & 0xff;\n \n if(key == 0x00) {\n output.attributes.eui = bytesToHex(java.util.Arrays.copyRange(input, i, i + 8));\n i += 8;\n }\n else if(key == 0x01) {\n output.attributes.app_eui = bytesToHex(java.util.Arrays.copyRange(input, i, i + 8));\n\t\t\t\ti += 8;\n }\n else if (key == 0x02) {\n output.attributes.app_key = bytesToHex(java.util.Arrays.copyRange(input, i, i + 16));\n i += 16;\n }\n else if (key == 0x03) {\n output.attributes.devAddr = bytesToHex(java.util.Arrays.copyRange(input, i, i + 4));\n i += 4;\n }\n else if(key == 0x04) {\n output.attributes.network_session_key = bytesToHex(java.util.Arrays.copyRange(input, i, i + 16));\n i += 16;\n }\n else if(key == 0x05) {\n output.attributes.app_session_key = bytesToHex(java.util.Arrays.copyRange(input, i, i + 16));\n i += 16;\n }\n else if(key == 0x10) {\n output.attributes.loramac_join_mode = (input[i] >> 7) & 1;\n i += 2;\n }\n else if (key == 0x11) {\n var val = (input[i] >> 4) & 0x0F;\n \n if(val == 0x0C) {\n output.attributes.lora_class = \"Class C\";\n }\n else if(val == 0x0B) {\n output.attributes.lora_class = \"Class B\";\n }\n else if(val == 0x0A) {\n output.attributes.lora_class = \"Class F\";\n }\n else {\n output.attributes.lora_class = \"Invalid\";\n }\n\t\t\t\t\n\t\t\t\toutput.attributes.confirm_mode = (input[i] >> 8) & 1; \n\t\t\t\toutput.attributes.sync_word = (input[i] >> 9) & 1;\n\t\t\t\toutput.attributes.duty_cycle = (input[i] >> 10) & 1;\n\t\t\t\toutput.attributes.adr = (input[i] >> 11) & 1; \n\t\t\t\t\n\t\t\t\ti += 2;\n }\n else if (key == 0x12) {\n output.attributes.dr_number = (((input[i] << 8) | input[i + 1]) >> 8) & 0xF;\n output.attributes.tx_power_number = ((input[i] << 8) | input[i + 1]) & 0xF;\n \n i +=2;\n }\n else if (key == 0x13) {\n output.attributes.frequency = (((input[i] << 32) | (input[i + 1] << 24) | (input[i + 2] << 16) | (input[i + 3] << 8) | input[i + 4]) >> 8) & 0xFFFFFFFF;\n output.attributes.dr_number_rx2 = input[i + 4] & 0xFF;\n \n i += 5;\n }\n else if(key == 0x19) {\n output.attributes.netid_msb = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if (key == 0x20) {\n output.attributes.seconds_per_core_tick = parseBytesToInt(input, i, 4);\n i += 4;\n }\n else if(key == 0x21) {\n output.attributes.tick_per_battery = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x71) {\n output.attributes.app_major_version = input[i];\n\t\t\t\toutput.attributes.app_minor_version = input[i + 1];\n\t\t\t\toutput.attributes.app_revision = input[i + 2];\n\t\t\t\toutput.attributes.loramac_major_version = input[i + 3];\n\t\t\t\toutput.attributes.loramac_minor_version = input[i + 4];\n\t\t\t\toutput.attributes.loramac_revision = input[i + 5];\n\t\t\t\toutput.attributes.region = input[i + 7];\n\t\t\t\ti += 7;\n }\n }\n }\n\n output.telemetry = [{\n ts: timestamp,\n values: decoded\n }];\n // --- Decoding code --- //\n return output;\n}\n\n// --- attributes and telemetry objects ---\nvar telemetry = [];\nvar attributes = {};\n// --- attributes and telemetry objects ---\n\n// --- Timestamp parsing\nvar dateString = data.time;\ntimestamp = parseDateToTimestamp(dateString);\n// --- Timestamp parsing\n\n// Passing incoming bytes to decodePayload function, to get custom decoding\nvar customDecoding = decodePayload(base64ToBytes(data.data));\n\n\nattributes.eui = data.deviceInfo.devEui;\n\n// Collecting data to result\nif (customDecoding.?telemetry.size() > 0) {\n if (customDecoding.telemetry instanceof java.util.ArrayList) {\n foreach(telemetryObj: customDecoding.telemetry) {\n if (telemetryObj.ts != null && telemetryObj.values != null) {\n telemetry.add(telemetryObj);\n }\n }\n } else {\n telemetry.putAll(customDecoding.telemetry);\n }\n}\n\nif (customDecoding.?attributes.size() > 0) {\n attributes.putAll(customDecoding.attributes);\n}\n\n// You can add some keys manually to attributes or telemetry\nattributes.eui = data.deviceInfo.?devEui;\nattributes.devAddr = data.devAddr;\nattributes.fPort = data.fPort;\nattributes.applicationId = data.deviceInfo.?applicationId;\nattributes.applicationName = data.deviceInfo.?applicationName;\nattributes.tenantId = data.deviceInfo.?tenantId;\nattributes.tenantName = data.deviceInfo.?tenantName;\nattributes.deviceProfileId = data.deviceInfo.?deviceProfileId;\nattributes.deviceProfileName = data.deviceInfo.?deviceProfileName;\nattributes.frequency = data.txInfo.?frequency;\nattributes.bandwidth = data.txInfo.?modulation.?lora.?bandwidth;\nattributes.spreadingFactor = data.txInfo.?modulation.?lora.?spreadingFactor;\nattributes.codeRate = data.txInfo.?modulation.?lora.?codeRate;\n\nif(Boolean.parseBoolean(metadata[\"includeGatewayInfo\"])) {\n var gatewayInfo = getGatewayInfo();\n var addDataToTelemetry = {};\n addDataToTelemetry.snr = gatewayInfo.snr;\n addDataToTelemetry.rssi = gatewayInfo.rssi;\n addDataToTelemetry.channel = gatewayInfo.channel;\n addDataToTelemetry.rfChain = gatewayInfo.rfChain;\n addDataToTelemetry.fCnt = data.fCnt;\n \n telemetry = processTelemetryData(telemetry, addDataToTelemetry);\n}\n\nvar result = {\n deviceName: deviceName,\n deviceType: deviceType,\n // assetName: assetName,\n // assetType: assetType,\n attributes: attributes,\n telemetry: telemetry\n};\n\naddAdditionalInfoForDeviceMsg(result, customerName, groupName);\n\nreturn result;\n\nfunction addAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName) {\n if (customerName != null) {\n deviceInfo.customerName = customerName;\n }\n if (groupName != null) {\n deviceInfo.groupName = groupName;\n }\n}\n\nfunction parseDateToTimestamp(dateString) {\n var date = new Date(dateString);\n var timestamp = date.getTime();\n \n // If we cannot parse timestamp - we will use the current timestamp\n if (timestamp == -1) {\n timestamp = Date.now();\n }\n \n return timestamp;\n}\n\nfunction getGatewayInfo() {\n var gatewayList = data.rxInfo;\n var maxRssi = Integer.MIN_VALUE;\n var gatewayInfo = {};\n \n foreach (gateway : gatewayList) {\n if(gateway.rssi > maxRssi) {\n maxRssi = gateway.rssi;\n gatewayInfo = gateway;\n }\n }\n \n return gatewayInfo;\n}\n\nfunction processTelemetryData(telemetry, addDataToTelemetry) {\n if (telemetry.size >= 1) {\n telemetry = addDataToTelemetries(telemetry, addDataToTelemetry);\n }\n else {\n telemetry.add(addDataToTelemetry);\n }\n \n return telemetry;\n}\n\nfunction addDataToTelemetries(telemetries, addDataToTelemetry) {\n foreach(telemetry : telemetries) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[\"values\"].keys.contains(element.key)) {\n telemetry[\"values\"][element.key] = element.value;\n }\n } \n }\n \n return telemetries;\n}", + "encoder": null, + "tbelEncoder": null, + "updateOnlyKeys": [ + "tenantId", + "tenantName", + "applicationId", + "applicationName", + "deviceProfileId", + "deviceProfileName", + "devAddr", + "fPort", + "frequency", + "bandwidth", + "spreadingFactor", + "codeRate", + "channel", + "rfChain", + "eui", + "battery" + ] + }, + "additionalInfo": { + "description": "" + }, + "edgeTemplate": false +} \ No newline at end of file diff --git a/VENDORS/Tektelic/Flux/ChirpStack/uplink/metadata.json b/VENDORS/Tektelic/Flux/ChirpStack/uplink/metadata.json new file mode 100644 index 00000000..23f54b34 --- /dev/null +++ b/VENDORS/Tektelic/Flux/ChirpStack/uplink/metadata.json @@ -0,0 +1,4 @@ +{ + "integrationName": "ChirpStack integration", + "includeGatewayInfo": "false" +} \ No newline at end of file diff --git a/VENDORS/Tektelic/Flux/ChirpStack/uplink/payload.json b/VENDORS/Tektelic/Flux/ChirpStack/uplink/payload.json new file mode 100644 index 00000000..1ac72155 --- /dev/null +++ b/VENDORS/Tektelic/Flux/ChirpStack/uplink/payload.json @@ -0,0 +1,48 @@ +{ + "deduplicationId": "57433366-50a6-4dc2-8145-2df1bbc70d9e", + "time": "2023-05-22T07:47:05.404859+00:00", + "deviceInfo": { + "tenantId": "52f14cd4-c6f1-4fbd-8f87-4025e1d49242", + "tenantName": "ChirpStack", + "applicationId": "ca739e26-7b67-4f14-b69e-d568c22a5a75", + "applicationName": "Chirpstack application", + "deviceProfileId": "605d08d4-65f5-4d2c-8a5a-3d2457662f79", + "deviceProfileName": "Chirpstack default device profile", + "deviceName": "Device name", + "devEui": "1000000000000001", + "tags": {} + }, + "devAddr": "20000001", + "adr": true, + "dr": 5, + "fCnt": 4, + "fPort": 10, + "confirmed": false, + "data": "AP4AAVGAAABqUAAAAA==", + "rxInfo": [{ + "gatewayId": "6a7e111a10000000", + "uplinkId": 24022, + "time": "2023-05-22T07:47:05.404859+00:00", + "rssi": -35, + "snr": 11.5, + "channel": 2, + "rfChain": 1, + "location": {}, + "context": "EFwMtA==", + "metadata": { + "region_common_name": "EU868", + "region_config_id": "eu868" + }, + "crcStatus": "CRC_OK" + }], + "txInfo": { + "frequency": 868500000, + "modulation": { + "lora": { + "bandwidth": 125000, + "spreadingFactor": 7, + "codeRate": "CR_4_5" + } + } + } +} \ No newline at end of file diff --git a/VENDORS/Tektelic/Flux/ChirpStack/uplink/result.json b/VENDORS/Tektelic/Flux/ChirpStack/uplink/result.json new file mode 100644 index 00000000..91810920 --- /dev/null +++ b/VENDORS/Tektelic/Flux/ChirpStack/uplink/result.json @@ -0,0 +1,27 @@ +{ + "deviceName": "Device name 1000000000000001", + "deviceType": "Flux", + "attributes": { + "eui": "1000000000000001", + "devAddr": "20000001", + "fPort": 10, + "applicationId": "ca739e26-7b67-4f14-b69e-d568c22a5a75", + "applicationName": "Chirpstack application", + "tenantId": "52f14cd4-c6f1-4fbd-8f87-4025e1d49242", + "tenantName": "ChirpStack", + "deviceProfileId": "605d08d4-65f5-4d2c-8a5a-3d2457662f79", + "deviceProfileName": "Chirpstack default device profile", + "frequency": 868500000, + "bandwidth": 125000, + "spreadingFactor": 7, + "codeRate": "CR_4_5" + }, + "telemetry": [{ + "ts": 1684741625404, + "values": { + "energy_consumption_meter_elapsed": 86400, + "energy_consumption_meter_consumed": 27216, + "energy_consumption_meter_status": 0 + } + }] +} \ No newline at end of file diff --git a/VENDORS/Tektelic/Flux/LORIOT/uplink/converter.json b/VENDORS/Tektelic/Flux/LORIOT/uplink/converter.json new file mode 100644 index 00000000..152df400 --- /dev/null +++ b/VENDORS/Tektelic/Flux/LORIOT/uplink/converter.json @@ -0,0 +1,29 @@ +{ + "name": "Loriot Uplink Decoder for Flux", + "type": "UPLINK", + "debugMode": false, + "debugSettings": { + "failuresEnabled": true, + "allEnabled": false, + "allEnabledUntil": 1733331880270 + }, + "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);\nvar deviceName = data.EUI;\nvar deviceType = \"Flux\";\nvar groupName = null; // If groupName is not null - created device will be added to the entity group with such name.\nvar customerName = null; // If customerName is not null - created devices will be assigned to customer with such name. \n\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// If you want to parse incoming data somehow, you can add your code to this function.\n// input: bytes\n// expected output:\n// {\n// \"attributes\": {\"attributeKey\": \"attributeValue\"},\n// \"telemetry\": {\"telemetryKey\": \"telemetryValue\"}\n// }\n\nfunction decodePayload(input) {\n var output = { attributes: {}, telemetry: []};\n \n var decoded = {};\n var fPort = data.port;\n if(fPort == 10) {\n for(var i = 0; i < input.length - 2; ) {\n var key_1 = input[i++] & 0xff;\n var key_2 = input[i++] & 0xff;\n \n if(key_1 == 0x00 && key_2 == 0xFE) {\n decoded.energy_consumption_meter_elapsed = parseBytesToInt(input, i, 4);\n decoded.energy_consumption_meter_consumed = parseBytesToInt(input, i + 4, 4);\n i += 8;\n }\n else if(key_1 == 0x00 && key_2 == 0x00) {\n decoded.energy_consumption_meter_status = parseBytesToInt(input, i, 1);\n if(decoded.energy_consumption_meter_status != 0) {\n decoded.energy_consumption_meter_status != 1;\n }\n }\n else if(key_1 == 0x00 && key_2 == 0x74) {\n decoded.voltmeter = (input[i] << 8) | (input[i + 1] & 0xFF);\n if (decoded.voltmeter != 65535) {\n decoded.voltmeter = decoded.voltmeter * 10;\n }\n \n i += 2;\n }\n else if(key_1 == 0x00 && key_2 == 0x75) {\n decoded.voltmeter = (input[i] << 8) | (input[i + 1] & 0xFF);\n if (decoded.ammeter != 65535) {\n decoded.ammeter = decoded.ammeter * 10;\n }\n \n i += 2;\n }\n else if(key_1 == 0x00 && key_2 == 0x80) {\n decoded.real_power = (input[i] << 8) | (input[i + 1] & 0xFF);\n if (decoded.real_power != 65535) {\n decoded.real_power = decoded.real_power * 10;\n }\n \n i += 2;\n }\n else if(key_1 == 0x01 && key_2 == 0x80) {\n decoded.apparent_power = (input[i] << 8) | (input[i + 1] & 0xFF);\n if (decoded.apparent_power != 65535) {\n decoded.apparent_power = decoded.apparent_power * 10;\n }\n \n i += 2;\n }\n else if(key_1 == 0x00 && key_2 == 0x81) {\n decoded.power_factor_meter = input[i] & 0xFF;\n if (decoded.power_factor_meter != 65535) {\n decoded.power_factor_meter = decoded.power_factor_meter * 100;\n }\n \n i += 1;\n }\n else if(key_1 == 0x00 && key_2 == 0x01) {\n decoded.relay_status = input[i] & 0xFF;\n \n if (decoded.relay_status != 0) {\n decoded.relay_status = 1;\n }\n \n i += 1;\n }\n }\n }\n else if (fPort == 100) {\n for(var i = 0; i < input.length -1; ) {\n var key = input[i++] & 0xff;\n \n if(key == 0x00) {\n output.attributes.eui = bytesToHex(java.util.Arrays.copyRange(input, i, i + 8));\n i += 8;\n }\n else if(key == 0x01) {\n output.attributes.app_eui = bytesToHex(java.util.Arrays.copyRange(input, i, i + 8));\n\t\t\t\ti += 8;\n }\n else if (key == 0x02) {\n output.attributes.app_key = bytesToHex(java.util.Arrays.copyRange(input, i, i + 16));\n i += 16;\n }\n else if (key == 0x03) {\n output.attributes.devAddr = bytesToHex(java.util.Arrays.copyRange(input, i, i + 4));\n i += 4;\n }\n else if(key == 0x04) {\n output.attributes.network_session_key = bytesToHex(java.util.Arrays.copyRange(input, i, i + 16));\n i += 16;\n }\n else if(key == 0x05) {\n output.attributes.app_session_key = bytesToHex(java.util.Arrays.copyRange(input, i, i + 16));\n i += 16;\n }\n else if(key == 0x10) {\n output.attributes.loramac_join_mode = (input[i] >> 7) & 1;\n i += 2;\n }\n else if (key == 0x11) {\n var val = (input[i] >> 4) & 0x0F;\n \n if(val == 0x0C) {\n output.attributes.lora_class = \"Class C\";\n }\n else if(val == 0x0B) {\n output.attributes.lora_class = \"Class B\";\n }\n else if(val == 0x0A) {\n output.attributes.lora_class = \"Class F\";\n }\n else {\n output.attributes.lora_class = \"Invalid\";\n }\n\t\t\t\t\n\t\t\t\toutput.attributes.confirm_mode = (input[i] >> 8) & 1; \n\t\t\t\toutput.attributes.sync_word = (input[i] >> 9) & 1;\n\t\t\t\toutput.attributes.duty_cycle = (input[i] >> 10) & 1;\n\t\t\t\toutput.attributes.adr = (input[i] >> 11) & 1; \n\t\t\t\t\n\t\t\t\ti += 2;\n }\n else if (key == 0x12) {\n output.attributes.dr_number = (((input[i] << 8) | input[i + 1]) >> 8) & 0xF;\n output.attributes.tx_power_number = ((input[i] << 8) | input[i + 1]) & 0xF;\n \n i +=2;\n }\n else if (key == 0x13) {\n output.attributes.frequency = (((input[i] << 32) | (input[i + 1] << 24) | (input[i + 2] << 16) | (input[i + 3] << 8) | input[i + 4]) >> 8) & 0xFFFFFFFF;\n output.attributes.dr_number_rx2 = input[i + 4] & 0xFF;\n \n i += 5;\n }\n else if(key == 0x19) {\n output.attributes.netid_msb = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if (key == 0x20) {\n output.attributes.seconds_per_core_tick = parseBytesToInt(input, i, 4);\n i += 4;\n }\n else if(key == 0x21) {\n output.attributes.tick_per_battery = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x71) {\n output.attributes.app_major_version = input[i];\n\t\t\t\toutput.attributes.app_minor_version = input[i + 1];\n\t\t\t\toutput.attributes.app_revision = input[i + 2];\n\t\t\t\toutput.attributes.loramac_major_version = input[i + 3];\n\t\t\t\toutput.attributes.loramac_minor_version = input[i + 4];\n\t\t\t\toutput.attributes.loramac_revision = input[i + 5];\n\t\t\t\toutput.attributes.region = input[i + 7];\n\t\t\t\ti += 7;\n }\n }\n }\n \n output.telemetry = [{\n ts: timestamp,\n values: decoded\n }];\n\n // --- Decoding code --- //\n return output;\n}\n\n// --- attributes and telemetry objects ---\nvar telemetry = [];\nvar attributes = {};\n// --- attributes and telemetry objects ---\n\n// --- Timestamp parsing\ntimestamp = data.ts;\n// --- Timestamp parsing\n\n// Message parsing\n// To avoid paths in the decoded objects we passing false value to function as \"pathInKey\" argument.\n// Warning: pathInKey can cause already found fields to be overwritten with the last value found.\n\nvar uplinkDataList = [];\n\n// Passing incoming bytes to decodePayload function, to get custom decoding\nvar customDecoding = decodePayload(hexToBytes(data.data));\n\n// Collecting data to result\nif (customDecoding.?telemetry.size() > 0) {\n if (customDecoding.telemetry instanceof java.util.ArrayList) {\n foreach(telemetryObj: customDecoding.telemetry) {\n if (telemetryObj.ts != null && telemetryObj.values != null) {\n telemetry.add(telemetryObj);\n }\n }\n } else {\n telemetry.putAll(customDecoding.telemetry);\n }\n}\n\nif (customDecoding.?attributes.size() > 0) {\n attributes.putAll(customDecoding.attributes);\n}\n\n// You can add some keys manually to attributes or telemetry\nattributes.eui = data.EUI;\nattributes.fPort = data.port;\nattributes.frequency = data.freq;\n\nvar isIncludeGatewayInfo = metadata[\"includeGatewayInfo\"];\nif(isIncludeGatewayInfo == true) {\n var addDataToTelemetry = {};\n addDataToTelemetry.rssi = data.rssi;\n addDataToTelemetry.seqno = data.seqno;\n addDataToTelemetry.snr = data.snr;\n addDataToTelemetry.ack = data.ack;\n addDataToTelemetry.toa = data.toa;\n addDataToTelemetry.fCnt = data.fcnt;\n \n telemetry = processTelemetryData(telemetry, addDataToTelemetry);\n}\n\nvar deviceInfo = {\n deviceName: deviceName,\n deviceType: deviceType,\n// assetName: assetName,\n// assetType: assetType,\n attributes: attributes,\n telemetry: telemetry, \n};\n\naddAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName);\n\nuplinkDataList.add(deviceInfo);\n\nvar gatewayDeviceNamePrefix = \"Gateway \";\nvar gatewayDeviceType = \"Lora gateway\";\nvar gatewayGroupName = null; // If gatewayGroupName is not null - created device will be added to the entity group with such name.\n\nif (data.cmd == \"gw\") {\n foreach( gatewayInfo : data.gws ) {\n var addGatewayInfo = {};\n\n // You can add some keys manually telemetry\n addGatewayInfo.rssi = gatewayInfo.rssi;\n addGatewayInfo.snr = gatewayInfo.snr;\n // You can add some keys manually telemetry\n \n var gatewayInfoMsg = {\n deviceName: gatewayDeviceNamePrefix + gatewayInfo.gweui,\n deviceType: gatewayDeviceType,\n telemetry: [{\n \"ts\": gatewayInfo.ts,\n \"values\": addGatewayInfo\n }],\n attributes: {\n eui: gatewayInfo.gweui\n }\n };\n addAdditionalInfoForDeviceMsg(gatewayInfoMsg, customerName, gatewayGroupName);\n uplinkDataList.add(gatewayInfoMsg);\n }\n}\n\nreturn uplinkDataList;\n\nfunction addAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName) {\n if (customerName != null) {\n deviceInfo.customerName = customerName;\n }\n if (groupName != null) {\n deviceInfo.groupName = groupName;\n }\n}\n\nfunction processTelemetryData(telemetry, addDataToTelemetry) {\n if (telemetry.size >= 1) {\n telemetry = addDataToTelemetries(telemetry, addDataToTelemetry);\n }\n else {\n telemetry.add(addDataToTelemetry);\n }\n \n return telemetry;\n}\n\nfunction addDataToTelemetries(telemetries, addDataToTelemetry) {\n foreach(telemetry : telemetries) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[\"values\"].keys.contains(element.key)) {\n telemetry[\"values\"][element.key] = element.value;\n }\n } \n }\n \n return telemetries;\n}", + "encoder": null, + "tbelEncoder": null, + "updateOnlyKeys": [ + "fPort", + "ack", + "eui", + "frequency", + "dr", + "battery" + ] + }, + "additionalInfo": { + "description": "" + }, + "edgeTemplate": false +} \ No newline at end of file diff --git a/VENDORS/Tektelic/Flux/LORIOT/uplink/metadata.json b/VENDORS/Tektelic/Flux/LORIOT/uplink/metadata.json new file mode 100644 index 00000000..ae2ee743 --- /dev/null +++ b/VENDORS/Tektelic/Flux/LORIOT/uplink/metadata.json @@ -0,0 +1,4 @@ +{ + "integrationName": "Loriot integration", + "includeGatewayInfo": "false" +} \ No newline at end of file diff --git a/VENDORS/Tektelic/Flux/LORIOT/uplink/payload.json b/VENDORS/Tektelic/Flux/LORIOT/uplink/payload.json new file mode 100644 index 00000000..0b10cef0 --- /dev/null +++ b/VENDORS/Tektelic/Flux/LORIOT/uplink/payload.json @@ -0,0 +1,17 @@ +{ + "cmd": "rx", + "seqno": 3040, + "EUI": "1000000000000001", + "ts": 1684478801936, + "fcnt": 2, + "port": 10, + "freq": 867500000, + "rssi": -21, + "snr": 10, + "toa": 206, + "dr": "SF9 BW125 4/5", + "ack": false, + "bat": 94, + "offline": false, + "data": "00FE0001518000006A50000000" +} \ No newline at end of file diff --git a/VENDORS/Tektelic/Flux/LORIOT/uplink/result.json b/VENDORS/Tektelic/Flux/LORIOT/uplink/result.json new file mode 100644 index 00000000..b2dc0c9f --- /dev/null +++ b/VENDORS/Tektelic/Flux/LORIOT/uplink/result.json @@ -0,0 +1,17 @@ +[{ + "deviceName": "1000000000000001", + "deviceType": "Flux", + "attributes": { + "eui": "1000000000000001", + "fPort": 10, + "frequency": 867500000 + }, + "telemetry": [{ + "ts": 1684478801936, + "values": { + "energy_consumption_meter_elapsed": 86400, + "energy_consumption_meter_consumed": 27216, + "energy_consumption_meter_status": 0 + } + }] +}] \ No newline at end of file diff --git a/VENDORS/Tektelic/Flux/ThingsStackCommunity/uplink/converter.json b/VENDORS/Tektelic/Flux/ThingsStackCommunity/uplink/converter.json new file mode 100644 index 00000000..388cc14b --- /dev/null +++ b/VENDORS/Tektelic/Flux/ThingsStackCommunity/uplink/converter.json @@ -0,0 +1,39 @@ +{ + "name": "The Things Stack Community Uplink Decoder for Flux", + "type": "UPLINK", + "debugMode": false, + "debugSettings": { + "failuresEnabled": true, + "allEnabled": false, + "allEnabledUntil": 1733331880270 + }, + "configuration": { + "scriptLang": "TBEL", + "decoder": null, + "tbelDecoder": "var data = decodeToJson(payload);\n\nvar deviceName = data.end_device_ids.device_id;\nvar deviceType = \"Flux\";\nvar groupName = null; // If groupName is not null - created device will be added to the entity group with such name.\nvar customerName = null; // If customerName is not null - created devices will be assigned to customer with such name. \n\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// If you want to parse incoming data somehow, you can add your code to this function.\n// input: bytes\n// expected output:\n// {\n// \"attributes\": {\"attributeKey\": \"attributeValue\"},\n// \"telemetry\": [{\"ts\": 1...1, \"values\": {\"telemetryKey\":\"telemetryValue\"}, {\"ts\": 1...2, \"values\": {\"telemetryKey\":\"telemetryValue\"}}]\n// }\n\nfunction decodeFrmPayload(input) {\n var output = {\n attributes: {}, telemetry: {}\n };\n \n // --- Decoding code --- //\n var decoded = {};\n var fPort = data.uplink_message.f_port;\n if(fPort == 10) {\n for(var i = 0; i < input.length - 2; ) {\n var key_1 = input[i++] & 0xff;\n var key_2 = input[i++] & 0xff;\n \n if(key_1 == 0x00 && key_2 == 0xFE) {\n decoded.energy_consumption_meter_elapsed = parseBytesToInt(input, i, 4);\n decoded.energy_consumption_meter_consumed = parseBytesToInt(input, i + 4, 4);\n i += 8;\n }\n else if(key_1 == 0x00 && key_2 == 0x00) {\n decoded.energy_consumption_meter_status = parseBytesToInt(input, i, 1);\n if(decoded.energy_consumption_meter_status != 0) {\n decoded.energy_consumption_meter_status != 1;\n }\n }\n else if(key_1 == 0x00 && key_2 == 0x74) {\n decoded.voltmeter = (input[i] << 8) | (input[i + 1] & 0xFF);\n if (decoded.voltmeter != 65535) {\n decoded.voltmeter = decoded.voltmeter * 10;\n }\n \n i += 2;\n }\n else if(key_1 == 0x00 && key_2 == 0x75) {\n decoded.voltmeter = (input[i] << 8) | (input[i + 1] & 0xFF);\n if (decoded.ammeter != 65535) {\n decoded.ammeter = decoded.ammeter * 10;\n }\n \n i += 2;\n }\n else if(key_1 == 0x00 && key_2 == 0x80) {\n decoded.real_power = (input[i] << 8) | (input[i + 1] & 0xFF);\n if (decoded.real_power != 65535) {\n decoded.real_power = decoded.real_power * 10;\n }\n \n i += 2;\n }\n else if(key_1 == 0x01 && key_2 == 0x80) {\n decoded.apparent_power = (input[i] << 8) | (input[i + 1] & 0xFF);\n if (decoded.apparent_power != 65535) {\n decoded.apparent_power = decoded.apparent_power * 10;\n }\n \n i += 2;\n }\n else if(key_1 == 0x00 && key_2 == 0x81) {\n decoded.power_factor_meter = input[i] & 0xFF;\n if (decoded.power_factor_meter != 65535) {\n decoded.power_factor_meter = decoded.power_factor_meter * 100;\n }\n \n i += 1;\n }\n else if(key_1 == 0x00 && key_2 == 0x01) {\n decoded.relay_status = input[i] & 0xFF;\n \n if (decoded.relay_status != 0) {\n decoded.relay_status = 1;\n }\n \n i += 1;\n }\n }\n }\n else if (fPort == 100) {\n for(var i = 0; i < input.length -1; ) {\n var key = input[i++] & 0xff;\n \n if(key == 0x00) {\n output.attributes.eui = bytesToHex(java.util.Arrays.copyRange(input, i, i + 8));\n i += 8;\n }\n else if(key == 0x01) {\n output.attributes.app_eui = bytesToHex(java.util.Arrays.copyRange(input, i, i + 8));\n\t\t\t\ti += 8;\n }\n else if (key == 0x02) {\n output.attributes.app_key = bytesToHex(java.util.Arrays.copyRange(input, i, i + 16));\n i += 16;\n }\n else if (key == 0x03) {\n output.attributes.devAddr = bytesToHex(java.util.Arrays.copyRange(input, i, i + 4));\n i += 4;\n }\n else if(key == 0x04) {\n output.attributes.network_session_key = bytesToHex(java.util.Arrays.copyRange(input, i, i + 16));\n i += 16;\n }\n else if(key == 0x05) {\n output.attributes.app_session_key = bytesToHex(java.util.Arrays.copyRange(input, i, i + 16));\n i += 16;\n }\n else if(key == 0x10) {\n output.attributes.loramac_join_mode = (input[i] >> 7) & 1;\n i += 2;\n }\n else if (key == 0x11) {\n var val = (input[i] >> 4) & 0x0F;\n \n if(val == 0x0C) {\n output.attributes.lora_class = \"Class C\";\n }\n else if(val == 0x0B) {\n output.attributes.lora_class = \"Class B\";\n }\n else if(val == 0x0A) {\n output.attributes.lora_class = \"Class F\";\n }\n else {\n output.attributes.lora_class = \"Invalid\";\n }\n\t\t\t\t\n\t\t\t\toutput.attributes.confirm_mode = (input[i] >> 8) & 1; \n\t\t\t\toutput.attributes.sync_word = (input[i] >> 9) & 1;\n\t\t\t\toutput.attributes.duty_cycle = (input[i] >> 10) & 1;\n\t\t\t\toutput.attributes.adr = (input[i] >> 11) & 1; \n\t\t\t\t\n\t\t\t\ti += 2;\n }\n else if (key == 0x12) {\n output.attributes.dr_number = (((input[i] << 8) | input[i + 1]) >> 8) & 0xF;\n output.attributes.tx_power_number = ((input[i] << 8) | input[i + 1]) & 0xF;\n \n i +=2;\n }\n else if (key == 0x13) {\n output.attributes.frequency = (((input[i] << 32) | (input[i + 1] << 24) | (input[i + 2] << 16) | (input[i + 3] << 8) | input[i + 4]) >> 8) & 0xFFFFFFFF;\n output.attributes.dr_number_rx2 = input[i + 4] & 0xFF;\n \n i += 5;\n }\n else if(key == 0x19) {\n output.attributes.netid_msb = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if (key == 0x20) {\n output.attributes.seconds_per_core_tick = parseBytesToInt(input, i, 4);\n i += 4;\n }\n else if(key == 0x21) {\n output.attributes.tick_per_battery = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x71) {\n output.attributes.app_major_version = input[i];\n\t\t\t\toutput.attributes.app_minor_version = input[i + 1];\n\t\t\t\toutput.attributes.app_revision = input[i + 2];\n\t\t\t\toutput.attributes.loramac_major_version = input[i + 3];\n\t\t\t\toutput.attributes.loramac_minor_version = input[i + 4];\n\t\t\t\toutput.attributes.loramac_revision = input[i + 5];\n\t\t\t\toutput.attributes.region = input[i + 7];\n\t\t\t\ti += 7;\n }\n }\n }\n \n output.telemetry = [{\n ts: timestamp,\n values: decoded\n }];\n \n // --- Decoding code --- //\n return output;\n}\n\n\n// --- attributes and telemetry objects ---\nvar telemetry = [];\nvar attributes = {};\n// --- attributes and telemetry objects ---\n\n// --- Timestamp parsing\nvar dateString = data.uplink_message.received_at;\n// If data is simulated or device doesn't send his own date string - we will use date from upcoming message, set by network server\nif ((data.simulated != null && data.simulated) || dateString == null) {\n dateString = data.received_at;\n}\ntimestamp = parseDateToTimestamp(dateString);\n// --- Timestamp parsing\n\n// Message parsing\n// To avoid paths in the decoded objects we passing false value to function as \"pathInKey\" argument.\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.\n\n// Passing incoming bytes to decodeFrmPayload function, to get custom decoding\nvar customDecoding = {};\nif (data.uplink_message.get(\"frm_payload\") != null) {\n customDecoding = decodeFrmPayload(base64ToBytes(data.uplink_message.frm_payload));\n}\n\n// Collecting data to result\nif (customDecoding.?telemetry.size() > 0) {\n if (customDecoding.telemetry instanceof java.util.ArrayList) {\n foreach(telemetryObj: customDecoding.telemetry) {\n if (telemetryObj.ts != null && telemetryObj.values != null) {\n telemetry.add(telemetryObj);\n }\n }\n } else {\n telemetry.putAll(customDecoding.telemetry);\n }\n}\n\nif (customDecoding.?attributes.size() > 0) {\n attributes.putAll(customDecoding.attributes);\n}\n\n// You can add some keys manually to attributes or telemetry\nvar applicationId = data.end_device_ids.?application_ids.?application_id;\nvar devAddr = data.end_device_ids.?dev_addr;\nvar spreadingFactor = data.uplink_message.?settings.?data_rate.?lora.?spreading_factor;\nvar codeRate = data.uplink_message.?settings.?data_rate.?lora.?coding_rate;\nvar tenantId = data.uplink_message.?network_ids.?tenant_id;\nattributes.eui = data.end_device_ids.dev_eui;\nattributes.fPort = data.uplink_message.f_port;\nattributes.applicationId = applicationId;\nattributes.devAddr = devAddr;\nattributes.spreadingFactor = spreadingFactor;\nattributes.codeRate = codeRate;\nattributes.tenantId = tenantId;\nattributes.device_id = data.end_device_ids.?device_id;\nattributes.join_eui = data.end_device_ids.?join_eui;\nattributes.net_id = data.uplink_message.?network_ids.?net_id;\nattributes.cluster_id = data.uplink_message.?network_ids.?cluster_id;\nattributes.cluster_adress = data.uplink_message.?network_ids.?cluster_address;\nattributes.bandwidth = data.uplink_message.?settings.?data_rate.?lora.?bandwidth;\nattributes.frequency = data.uplink_message.?settings.?frequency;\n\n\nvar gatewayInfo = getGatewayInfo();\nvar addDataToTelemetry = {};\naddDataToTelemetry.snr = gatewayInfo.snr;\naddDataToTelemetry.rssi = gatewayInfo.rssi;\naddDataToTelemetry.channel = gatewayInfo.channel_index;\naddDataToTelemetry.consumed_airtime = data.uplink_message.?consumed_airtime;\naddDataToTelemetry.fCnt = data.uplink_message.?f_cnt;\n\nvar isIncludeGatewayInfo = metadata[\"includeGatewayInfo\"];\nif(isIncludeGatewayInfo == true) {\n telemetry = processTelemetryData(telemetry, addDataToTelemetry);\n}\n\nvar result = {\n deviceName: deviceName,\n deviceType: deviceType,\n// assetName: assetName,\n// assetType: assetType,\n attributes: attributes,\n telemetry: telemetry\n};\n\naddAdditionalInfoForDeviceMsg(result, customerName, groupName);\n\nreturn result;\n\n\nfunction addAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName) {\n if (customerName != null) {\n deviceInfo.customerName = customerName;\n }\n if (groupName != null) {\n deviceInfo.groupName = groupName;\n }\n}\n\nfunction parseDateToTimestamp(dateString) {\n var date = new Date(dateString);\n var timestamp = date.getTime();\n \n // If we cannot parse timestamp - we will use the current timestamp\n if (timestamp == -1) {\n timestamp = Date.now();\n }\n \n return timestamp;\n}\n\nfunction getGatewayInfo() {\n var gatewayList = data.uplink_message.?rx_metadata;\n var maxRssi = Integer.MIN_VALUE;\n var gatewayInfo = {};\n \n foreach (gateway : gatewayList) {\n if(gateway.rssi > maxRssi) {\n maxRssi = gateway.rssi;\n gatewayInfo = gateway;\n }\n }\n \n return gatewayInfo;\n}\n\nfunction processTelemetryData(telemetry, addDataToTelemetry) {\n if (telemetry.size >= 1) {\n telemetry = addDataToTelemetries(telemetry, addDataToTelemetry);\n }\n else {\n telemetry.add(addDataToTelemetry);\n }\n \n return telemetry;\n}\n\nfunction addDataToTelemetries(telemetries, addDataToTelemetry) {\n foreach(telemetry : telemetries) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[\"values\"].keys.contains(element.key)) {\n telemetry[\"values\"][element.key] = element.value;\n }\n } \n }\n \n return telemetries;\n}", + "encoder": null, + "tbelEncoder": null, + "updateOnlyKeys": [ + "fPort", + "bandwidth", + "frequency", + "net_id", + "cluster_id", + "cluster_address", + "device_id", + "join_eui", + "battery", + "eui", + "channel", + "applicationId", + "devAddr", + "spreadingFactor", + "codeRate", + "tenantId" + ] + }, + "additionalInfo": { + "description": "" + }, + "edgeTemplate": false +} \ No newline at end of file diff --git a/VENDORS/Tektelic/Flux/ThingsStackCommunity/uplink/metadata.json b/VENDORS/Tektelic/Flux/ThingsStackCommunity/uplink/metadata.json new file mode 100644 index 00000000..0d75c374 --- /dev/null +++ b/VENDORS/Tektelic/Flux/ThingsStackCommunity/uplink/metadata.json @@ -0,0 +1,4 @@ +{ + "integrationName": "The Things Stack Community integration", + "includeGatewayInfo": "false" +} \ No newline at end of file diff --git a/VENDORS/Tektelic/Flux/ThingsStackCommunity/uplink/payload.json b/VENDORS/Tektelic/Flux/ThingsStackCommunity/uplink/payload.json new file mode 100644 index 00000000..9d86cc7d --- /dev/null +++ b/VENDORS/Tektelic/Flux/ThingsStackCommunity/uplink/payload.json @@ -0,0 +1,54 @@ +{ + "end_device_ids": { + "device_id": "eui-1000000000000001", + "application_ids": { + "application_id": "application-tts-name" + }, + "dev_eui": "1000000000000001", + "join_eui": "2000000000000001", + "dev_addr": "20000001" + }, + "correlation_ids": ["as:up:01H0S7ZJQ9MQPMVY49FT3SE07M", "gs:conn:01H03BQZ9342X3Y86DJ2P704E5", "gs:up:host:01H03BQZ99EGAM52KK1300GFKN", "gs:uplink:01H0S7ZJGS6D9TJSKJN8XNTMAV", "ns:uplink:01H0S7ZJGS9KKD4HTTPKFEMWCV", "rpc:/ttn.lorawan.v3.GsNs/HandleUplink:01H0S7ZJGSF3M38ZRZVTM38DEC", "rpc:/ttn.lorawan.v3.NsAs/HandleUplink:01H0S7ZJQ8R2EH5AA269AKM8DX"], + "received_at": "2023-05-19T05:33:35.848446463Z", + "uplink_message": { + "session_key_id": "AYfqmb0pc/1uRZv9xUydgQ==", + "f_port": 10, + "f_cnt": 10335, + "frm_payload": "AP4AAVGAAABqUAAAAA==", + "rx_metadata": [{ + "gateway_ids": { + "gateway_id": "eui-6a7e111a10000000", + "eui": "6A7E111A10000000" + }, + "time": "2023-05-19T05:33:35.608982Z", + "timestamp": 3893546133, + "rssi": -35, + "channel_rssi": -35, + "snr": 13.2, + "frequency_offset": "69", + "uplink_token": "CiIKIAoUZXVpLTZhN2UxMTFhMTAwMDAwMDASCCThJP/+9k6eEJWZy8AOGgwIr5ScowYQvNbUsQIgiMy8y6jwpwE=", + "channel_index": 3, + "received_at": "2023-05-19T05:33:35.607383681Z" + }], + "settings": { + "data_rate": { + "lora": { + "bandwidth": 125000, + "spreading_factor": 7, + "coding_rate": "4/5" + } + }, + "frequency": "867100000", + "timestamp": 3893546133, + "time": "2023-05-19T05:33:35.608982Z" + }, + "received_at": "2023-05-19T05:33:35.641841782Z", + "consumed_airtime": "0.056576s", + "network_ids": { + "net_id": "000013", + "tenant_id": "ttn", + "cluster_id": "eu1", + "cluster_address": "eu1.cloud.thethings.network" + } + } +} \ No newline at end of file diff --git a/VENDORS/Tektelic/Flux/ThingsStackCommunity/uplink/result.json b/VENDORS/Tektelic/Flux/ThingsStackCommunity/uplink/result.json new file mode 100644 index 00000000..54a2dd4c --- /dev/null +++ b/VENDORS/Tektelic/Flux/ThingsStackCommunity/uplink/result.json @@ -0,0 +1,28 @@ +{ + "deviceName": "eui-1000000000000001", + "deviceType": "Flux", + "attributes": { + "eui": "1000000000000001", + "fPort": 10, + "applicationId": "application-tts-name", + "devAddr": "20000001", + "spreadingFactor": 7, + "codeRate": "4/5", + "tenantId": "ttn", + "device_id": "eui-1000000000000001", + "join_eui": "2000000000000001", + "net_id": "000013", + "cluster_id": "eu1", + "cluster_adress": "eu1.cloud.thethings.network", + "bandwidth": 125000, + "frequency": "867100000" + }, + "telemetry": [{ + "ts": 1684474415641, + "values": { + "energy_consumption_meter_elapsed": 86400, + "energy_consumption_meter_consumed": 27216, + "energy_consumption_meter_status": 0 + } + }] +} \ No newline at end of file diff --git a/VENDORS/Tektelic/Flux/ThingsStackIndustries/uplink/converter.json b/VENDORS/Tektelic/Flux/ThingsStackIndustries/uplink/converter.json new file mode 100644 index 00000000..485c0ef2 --- /dev/null +++ b/VENDORS/Tektelic/Flux/ThingsStackIndustries/uplink/converter.json @@ -0,0 +1,40 @@ +{ + "name": "The Things Stack Industries Uplink Decoder for Flux", + "type": "UPLINK", + "debugMode": false, + "debugSettings": { + "failuresEnabled": true, + "allEnabled": false, + "allEnabledUntil": 1733331880270 + }, + "configuration": { + "scriptLang": "TBEL", + "decoder": null, + "tbelDecoder": "var data = decodeToJson(payload);\n\nvar deviceName = data.end_device_ids.device_id;\nvar deviceType = \"Flux\";\nvar groupName = null; // If groupName is not null - created device will be added to the entity group with such name.\nvar customerName = null; // If customerName is not null - created devices will be assigned to customer with such name. \n\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// If you want to parse incoming data somehow, you can add your code to this function.\n// input: bytes\n// expected output:\n// {\n// \"attributes\": {\"attributeKey\": \"attributeValue\"},\n// \"telemetry\": [{\"ts\": 1...1, \"values\": {\"telemetryKey\":\"telemetryValue\"}, {\"ts\": 1...2, \"values\": {\"telemetryKey\":\"telemetryValue\"}}]\n// }\n\nfunction decodeFrmPayload(input) {\n var output = { attributes: {}, telemetry: []};\n \n // --- Decoding code --- //\n var decoded = {};\n var fPort = data.uplink_message.f_port;\n if(fPort == 10) {\n for(var i = 0; i < input.length - 2; ) {\n var key_1 = input[i++] & 0xff;\n var key_2 = input[i++] & 0xff;\n \n if(key_1 == 0x00 && key_2 == 0xFE) {\n decoded.energy_consumption_meter_elapsed = parseBytesToInt(input, i, 4);\n decoded.energy_consumption_meter_consumed = parseBytesToInt(input, i + 4, 4);\n i += 8;\n }\n else if(key_1 == 0x00 && key_2 == 0x00) {\n decoded.energy_consumption_meter_status = parseBytesToInt(input, i, 1);\n if(decoded.energy_consumption_meter_status != 0) {\n decoded.energy_consumption_meter_status != 1;\n }\n }\n else if(key_1 == 0x00 && key_2 == 0x74) {\n decoded.voltmeter = (input[i] << 8) | (input[i + 1] & 0xFF);\n if (decoded.voltmeter != 65535) {\n decoded.voltmeter = decoded.voltmeter * 10;\n }\n \n i += 2;\n }\n else if(key_1 == 0x00 && key_2 == 0x75) {\n decoded.voltmeter = (input[i] << 8) | (input[i + 1] & 0xFF);\n if (decoded.ammeter != 65535) {\n decoded.ammeter = decoded.ammeter * 10;\n }\n \n i += 2;\n }\n else if(key_1 == 0x00 && key_2 == 0x80) {\n decoded.real_power = (input[i] << 8) | (input[i + 1] & 0xFF);\n if (decoded.real_power != 65535) {\n decoded.real_power = decoded.real_power * 10;\n }\n \n i += 2;\n }\n else if(key_1 == 0x01 && key_2 == 0x80) {\n decoded.apparent_power = (input[i] << 8) | (input[i + 1] & 0xFF);\n if (decoded.apparent_power != 65535) {\n decoded.apparent_power = decoded.apparent_power * 10;\n }\n \n i += 2;\n }\n else if(key_1 == 0x00 && key_2 == 0x81) {\n decoded.power_factor_meter = input[i] & 0xFF;\n if (decoded.power_factor_meter != 65535) {\n decoded.power_factor_meter = decoded.power_factor_meter * 100;\n }\n \n i += 1;\n }\n else if(key_1 == 0x00 && key_2 == 0x01) {\n decoded.relay_status = input[i] & 0xFF;\n \n if (decoded.relay_status != 0) {\n decoded.relay_status = 1;\n }\n \n i += 1;\n }\n }\n }\n else if (fPort == 100) {\n for(var i = 0; i < input.length -1; ) {\n var key = input[i++] & 0xff;\n \n if(key == 0x00) {\n output.attributes.eui = bytesToHex(java.util.Arrays.copyRange(input, i, i + 8));\n i += 8;\n }\n else if(key == 0x01) {\n output.attributes.app_eui = bytesToHex(java.util.Arrays.copyRange(input, i, i + 8));\n\t\t\t\ti += 8;\n }\n else if (key == 0x02) {\n output.attributes.app_key = bytesToHex(java.util.Arrays.copyRange(input, i, i + 16));\n i += 16;\n }\n else if (key == 0x03) {\n output.attributes.devAddr = bytesToHex(java.util.Arrays.copyRange(input, i, i + 4));\n i += 4;\n }\n else if(key == 0x04) {\n output.attributes.network_session_key = bytesToHex(java.util.Arrays.copyRange(input, i, i + 16));\n i += 16;\n }\n else if(key == 0x05) {\n output.attributes.app_session_key = bytesToHex(java.util.Arrays.copyRange(input, i, i + 16));\n i += 16;\n }\n else if(key == 0x10) {\n output.attributes.loramac_join_mode = (input[i] >> 7) & 1;\n i += 2;\n }\n else if (key == 0x11) {\n var val = (input[i] >> 4) & 0x0F;\n \n if(val == 0x0C) {\n output.attributes.lora_class = \"Class C\";\n }\n else if(val == 0x0B) {\n output.attributes.lora_class = \"Class B\";\n }\n else if(val == 0x0A) {\n output.attributes.lora_class = \"Class F\";\n }\n else {\n output.attributes.lora_class = \"Invalid\";\n }\n\t\t\t\t\n\t\t\t\toutput.attributes.confirm_mode = (input[i] >> 8) & 1; \n\t\t\t\toutput.attributes.sync_word = (input[i] >> 9) & 1;\n\t\t\t\toutput.attributes.duty_cycle = (input[i] >> 10) & 1;\n\t\t\t\toutput.attributes.adr = (input[i] >> 11) & 1; \n\t\t\t\t\n\t\t\t\ti += 2;\n }\n else if (key == 0x12) {\n output.attributes.dr_number = (((input[i] << 8) | input[i + 1]) >> 8) & 0xF;\n output.attributes.tx_power_number = ((input[i] << 8) | input[i + 1]) & 0xF;\n \n i +=2;\n }\n else if (key == 0x13) {\n output.attributes.frequency = (((input[i] << 32) | (input[i + 1] << 24) | (input[i + 2] << 16) | (input[i + 3] << 8) | input[i + 4]) >> 8) & 0xFFFFFFFF;\n output.attributes.dr_number_rx2 = input[i + 4] & 0xFF;\n \n i += 5;\n }\n else if(key == 0x19) {\n output.attributes.netid_msb = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if (key == 0x20) {\n output.attributes.seconds_per_core_tick = parseBytesToInt(input, i, 4);\n i += 4;\n }\n else if(key == 0x21) {\n output.attributes.tick_per_battery = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x71) {\n output.attributes.app_major_version = input[i];\n\t\t\t\toutput.attributes.app_minor_version = input[i + 1];\n\t\t\t\toutput.attributes.app_revision = input[i + 2];\n\t\t\t\toutput.attributes.loramac_major_version = input[i + 3];\n\t\t\t\toutput.attributes.loramac_minor_version = input[i + 4];\n\t\t\t\toutput.attributes.loramac_revision = input[i + 5];\n\t\t\t\toutput.attributes.region = input[i + 7];\n\t\t\t\ti += 7;\n }\n }\n }\n \n output.telemetry = [{\n ts: timestamp,\n values: decoded\n }];\n\n // --- Decoding code --- //\n return output;\n}\n\n// --- attributes and telemetry objects ---\nvar telemetry = [];\nvar attributes = {};\n// --- attributes and telemetry objects ---\n\n// --- Timestamp parsing\nvar dateString = data.uplink_message.received_at;\n\nif ((data.simulated != null && data.simulated) || dateString == null) {\n dateString = data.received_at;\n}\n\ntimestamp = parseDateToTimestamp(dateString);\n// --- Timestamp parsing\n\n// Message parsing\n// To avoid paths in the decoded objects we passing false value to function as \"pathInKey\" argument.\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.\n\n// Passing incoming bytes to decodeFrmPayload function, to get custom decoding\nvar customDecoding = {};\nif (data.uplink_message.get(\"frm_payload\") != null) {\n customDecoding = decodeFrmPayload(base64ToBytes(data.uplink_message.frm_payload));\n}\n\n// Collecting data to result\nif (customDecoding.?telemetry.size() > 0) {\n if (customDecoding.telemetry instanceof java.util.ArrayList) {\n foreach(telemetryObj: customDecoding.telemetry) {\n if (telemetryObj.ts != null && telemetryObj.values != null) {\n telemetry.add(telemetryObj);\n }\n }\n } else {\n telemetry.putAll(customDecoding.telemetry);\n }\n}\n\nif (customDecoding.?attributes.size() > 0) {\n attributes.putAll(customDecoding.attributes);\n}\n\n// You can add some keys manually to attributes or telemetry\nvar applicationId = data.end_device_ids.?application_ids.?application_id;\nvar devAddr = data.end_device_ids.?dev_addr;\nvar spreadingFactor = data.uplink_message.?settings.?data_rate.?lora.?spreading_factor;\nvar codeRate = data.uplink_message.?settings.?data_rate.?lora.?coding_rate;\nvar tenantId = data.uplink_message.?network_ids.?tenant_id;\nattributes.eui = data.end_device_ids.dev_eui;\nattributes.fPort = data.uplink_message.f_port;\nattributes.applicationId = applicationId;\nattributes.devAddr = devAddr;\nattributes.spreadingFactor = spreadingFactor;\nattributes.codeRate = codeRate;\nattributes.tenantId = tenantId;\nattributes.device_id = data.end_device_ids.?device_id;\nattributes.join_eui = data.end_device_ids.?join_eui;\nattributes.net_id = data.uplink_message.?network_ids.?net_id;\nattributes.cluster_id = data.uplink_message.?network_ids.?cluster_id;\nattributes.cluster_address = data.uplink_message.?network_ids.?cluster_address;\nattributes.bandwidth = data.uplink_message.?settings.?data_rate.?lora.?bandwidth;\nattributes.frequency = data.uplink_message.?settings.?frequency;\n\nvar isIncludeGatewayInfo = metadata[\"includeGatewayInfo\"];\nif(isIncludeGatewayInfo == true) {\n var gatewayInfo = getGatewayInfo();\n var addDataToTelemetry = {};\n addDataToTelemetry.snr = gatewayInfo.snr;\n addDataToTelemetry.rssi = gatewayInfo.rssi;\n addDataToTelemetry.channel = gatewayInfo.channel_index;\n addDataToTelemetry.consumed_airtime = data.uplink_message.?consumed_airtime;\n addDataToTelemetry.fCnt = data.uplink_message.?f_cnt;\n\n telemetry = processTelemetryData(telemetry, addDataToTelemetry);\n}\n\nvar result = {\n deviceName: deviceName,\n deviceType: deviceType,\n // assetName: assetName,\n // assetType: assetType,\n attributes: attributes,\n telemetry: telemetry\n};\n\naddAdditionalInfoForDeviceMsg(result, customerName, groupName);\n\nreturn result;\n\nfunction addAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName) {\n if (customerName != null) {\n deviceInfo.customerName = customerName;\n }\n if (groupName != null) {\n deviceInfo.groupName = groupName;\n }\n}\n\nfunction parseDateToTimestamp(dateString) {\n var date = new Date(dateString);\n var timestamp = date.getTime();\n \n // If we cannot parse timestamp - we will use the current timestamp\n if (timestamp == -1) {\n timestamp = Date.now();\n }\n \n return timestamp;\n}\n\nfunction getGatewayInfo() {\n var gatewayList = data.uplink_message.?rx_metadata;\n var maxRssi = Integer. MIN_VALUE;\n var gatewayInfo = {};\n \n foreach (gateway : gatewayList) {\n if(gateway.rssi > maxRssi) {\n maxRssi = gateway.rssi;\n gatewayInfo = gateway;\n }\n }\n \n return gatewayInfo;\n}\n\nfunction processTelemetryData(telemetry, addDataToTelemetry) {\n if (telemetry.size >= 1) {\n telemetry = addDataToTelemetries(telemetry, addDataToTelemetry);\n }\n else {\n telemetry.add(addDataToTelemetry);\n }\n \n return telemetry;\n}\n\nfunction addDataToTelemetries(telemetries, addDataToTelemetry) {\n foreach(telemetry : telemetries) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[\"values\"].keys.contains(element.key)) {\n telemetry[\"values\"][element.key] = element.value;\n }\n } \n }\n \n return telemetries;\n}", + "encoder": null, + "tbelEncoder": null, + "updateOnlyKeys": [ + "fPort", + "bandwidth", + "frequency", + "net_id", + "cluster_id", + "cluster_address", + "tenant_address", + "device_id", + "join_eui", + "eui", + "channel", + "devAddr", + "spreadingFactor", + "codeRate", + "tenantId", + "applicationId", + "battery" + ] + }, + "additionalInfo": { + "description": "" + }, + "edgeTemplate": false +} \ No newline at end of file diff --git a/VENDORS/Tektelic/Flux/ThingsStackIndustries/uplink/metadata.json b/VENDORS/Tektelic/Flux/ThingsStackIndustries/uplink/metadata.json new file mode 100644 index 00000000..23f54b34 --- /dev/null +++ b/VENDORS/Tektelic/Flux/ThingsStackIndustries/uplink/metadata.json @@ -0,0 +1,4 @@ +{ + "integrationName": "ChirpStack integration", + "includeGatewayInfo": "false" +} \ No newline at end of file diff --git a/VENDORS/Tektelic/Flux/ThingsStackIndustries/uplink/payload.json b/VENDORS/Tektelic/Flux/ThingsStackIndustries/uplink/payload.json new file mode 100644 index 00000000..31db41d3 --- /dev/null +++ b/VENDORS/Tektelic/Flux/ThingsStackIndustries/uplink/payload.json @@ -0,0 +1,77 @@ +{ + "end_device_ids": { + "device_id": "eui-1000000000000001", + "application_ids": { + "application_id": "application-tti-name" + }, + "dev_eui": "1000000000000001", + "join_eui": "2000000000000001", + "dev_addr": "20000001" + }, + "correlation_ids": ["as:up:01H0PZDGB1NW6NAPD815NGHPF6", "gs:conn:01H0FJRSXSYT7VKNYXJ89F95XT", "gs:up:host:01H0FJRSY3MZMGPPFBQ4FZV4T8", "gs:uplink:01H0PZDG4HHGFRTXRTXD4PFTH7", "ns:uplink:01H0PZDG4JZ3BM0K6J89EQK1J7", "rpc:/ttn.lorawan.v3.GsNs/HandleUplink:01H0PZDG4J02F85RYFPCNSNXCR", "rpc:/ttn.lorawan.v3.NsAs/HandleUplink:01H0PZDGB081PMP806BJHNHX1A"], + "received_at": "2023-05-18T08:25:26.112483370Z", + "uplink_message": { + "session_key_id": "AYfg8rhha5n+FWx0ZaAprA==", + "f_port": 10, + "f_cnt": 5017, + "frm_payload": "AP4AAVGAAABqUAAAAA==", + "rx_metadata": [{ + "gateway_ids": { + "gateway_id": "eui-6A7E111A10000000", + "eui": "6A7E111A10000000" + }, + "time": "2023-05-18T08:25:25.885310Z", + "timestamp": 818273765, + "rssi": -24, + "channel_rssi": -24, + "snr": 12, + "frequency_offset": "671", + "uplink_token": "CiIKIAoUZXVpLTZBN0UxMTFBMTAwMDAwMDASCCThJP/+9k6eEOW7l4YDGgwI9cGXowYQ5KPhrwMgiI2rp+jpOA=", + "channel_index": 2, + "received_at": "2023-05-18T08:25:25.869324983Z" + }, { + "gateway_ids": { + "gateway_id": "packetbroker" + }, + "packet_broker": { + "message_id": "01H0PZDG4MF9AYSMNY44MAVTDH", + "forwarder_net_id": "000013", + "forwarder_tenant_id": "ttn", + "forwarder_cluster_id": "eu1.cloud.thethings.network", + "forwarder_gateway_eui": "6A7E111A10000000", + "forwarder_gateway_id": "eui-6a7e111a10000000", + "home_network_net_id": "000013", + "home_network_tenant_id": "tenant", + "home_network_cluster_id": "eu1.cloud.thethings.industries" + }, + "time": "2023-05-18T08:25:25.885310Z", + "rssi": -24, + "channel_rssi": -24, + "snr": 12, + "frequency_offset": "671", + "uplink_token": "eyJnIjoiWlhsS2FHSkhZMmxQYVVwQ1RWUkpORkl3VGs1VE1XTnBURU5LYkdKdFRXbFBhVXBDVFZSSk5GSXdUazVKYVhkcFlWaFphVTlwU201a01uaGhWVlJvZDFSWFVuRmlSM1JtVFcxT2RVbHBkMmxrUjBadVNXcHZhV05ZY0RKT1IyeExaREpSZVZwR1pIUmpNRXBLVlVoR2RFNVZkR3BWVTBvNUxua3paVVJTWVRaM1lXOU1kbTQwVm5sdmIyWmlPWGN1ZUhCZmVrcElaa3hIWlZadGRVUlFVeTVuYlRaVlZXRXdkakpHV0VKMGJUUjZaMjVXUkVoeGVHRjRaMlJKTlVkS1VsbERhemc1VDNCbk5rVk1iM1JDUkVZM1VWbHdZbEJDTkdOblNqWjBlbkphYUV4MFRVMHhZMVZFTTFac01XdExURUo0YURaMFExTnhhMVJsWWw4eE5FdHlVVXcyZUhsRWFFbEhlakJITXpoTE0xaFdlRzR5VUVjMk4wNUViME5WTkhoTmRrazFZVk5oWkUwd2FXVnFjR294VGtoMFduZHlZMDFxVlVGNmRsbERUazlNY2s5eFdVeFpWMk5XTG1WVFFYVkpNVkptT1U5NWRqUTNhSEoxTUZoalYxRT0iLCJhIjp7ImZuaWQiOiIwMDAwMTMiLCJmdGlkIjoidHRuIiwiZmNpZCI6ImV1MS5jbG91ZC50aGV0aGluZ3MubmV0d29yayJ9fQ==", + "received_at": "2023-05-18T08:25:25.906038642Z" + }], + "settings": { + "data_rate": { + "lora": { + "bandwidth": 125000, + "spreading_factor": 7, + "coding_rate": "4/5" + } + }, + "frequency": "868500000", + "timestamp": 818273765, + "time": "2023-05-18T08:25:25.885310Z" + }, + "received_at": "2023-05-18T08:25:25.906399073Z", + "consumed_airtime": "0.097536s", + "network_ids": { + "net_id": "000013", + "tenant_id": "tenant", + "cluster_id": "eu1", + "cluster_address": "eu1.cloud.thethings.industries", + "tenant_address": "tenant.eu1.cloud.thethings.industries" + } + } +} \ No newline at end of file diff --git a/VENDORS/Tektelic/Flux/ThingsStackIndustries/uplink/result.json b/VENDORS/Tektelic/Flux/ThingsStackIndustries/uplink/result.json new file mode 100644 index 00000000..b81c3b94 --- /dev/null +++ b/VENDORS/Tektelic/Flux/ThingsStackIndustries/uplink/result.json @@ -0,0 +1,28 @@ +{ + "deviceName": "eui-1000000000000001", + "deviceType": "Flux", + "attributes": { + "eui": "1000000000000001", + "fPort": 10, + "applicationId": "application-tti-name", + "devAddr": "20000001", + "spreadingFactor": 7, + "codeRate": "4/5", + "tenantId": "tenant", + "device_id": "eui-1000000000000001", + "join_eui": "2000000000000001", + "net_id": "000013", + "cluster_id": "eu1", + "cluster_address": "eu1.cloud.thethings.industries", + "bandwidth": 125000, + "frequency": "868500000" + }, + "telemetry": [{ + "ts": 1684398325906, + "values": { + "energy_consumption_meter_elapsed": 86400, + "energy_consumption_meter_consumed": 27216, + "energy_consumption_meter_status": 0 + } + }] +} \ No newline at end of file diff --git a/VENDORS/Tektelic/Flux/info.json b/VENDORS/Tektelic/Flux/info.json new file mode 100644 index 00000000..bd800f9e --- /dev/null +++ b/VENDORS/Tektelic/Flux/info.json @@ -0,0 +1,5 @@ +{ + "url": "https://tektelic.com/products/sensors/flux-smart-ac-outlet/", + "label": "Flux: Conveniently control and monitor power consumption for facility automation and improved building efficiency", + "description": "FLUX is a 120V Smart Outlet in the form of a standard NEMA 5-15R Decorator-style duplex tamper-resistant receptacle, incorporating a LoRa radio with power control and monitoring circuitry that enables remote power on-off control and status, as well as precise measurement of consumed energy (kWh), line voltage (Vrms), load current (Arms), load power (real, reactive, and apparent, W), and load power factor." +} \ No newline at end of file diff --git a/VENDORS/Tektelic/Flux/photo.png b/VENDORS/Tektelic/Flux/photo.png new file mode 100644 index 0000000000000000000000000000000000000000..44033bfa3688014c9757fc6c96531c7cada479d2 GIT binary patch literal 69090 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 B2T}k4 literal 0 HcmV?d00001 From 1fede74e11bb0993e0e86a8f3e2dca74a6a08d9a Mon Sep 17 00:00:00 2001 From: thingsboard017 Date: Mon, 23 Dec 2024 12:45:52 +0200 Subject: [PATCH 14/33] Updated the validation script by adding checks for vendors' photo and info files. --- data_converters_validator.py | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/data_converters_validator.py b/data_converters_validator.py index 8d38e136..c3967404 100644 --- a/data_converters_validator.py +++ b/data_converters_validator.py @@ -182,6 +182,38 @@ def validate_device_files(device_path): return True +def validate_company_files(company_path): + required_files = ['logo.svg', 'info.json'] + all_present = True + + for file in required_files: + file_path = os.path.join(company_path, file) + if not os.path.exists(file_path): + print(f"Validation failed: Missing '{file}' in {company_path}") + all_present = False + + if "info.json" in required_files: + info_path = os.path.join(company_path, "info.json") + if os.path.exists(info_path): + with open(info_path, 'r') as f: + try: + data = json.load(f) + except json.JSONDecodeError: + print(f"Validation failed: 'info.json' in {company_path} is not valid JSON") + return False + + allowed_keys = {"description", "url"} + if set(data.keys()) != allowed_keys: + print(f"Validation failed: 'info.json' in {company_path} contains invalid keys. Allowed keys are {allowed_keys}.") + return False + + for key in allowed_keys: + if not data[key] or not isinstance(data[key], str): + print(f"Validation failed: '{key}' in 'info.json' in {company_path} is missing or empty.") + return False + + return all_present + def walk_vendors_directory(root_dir): all_success = True @@ -191,6 +223,10 @@ def walk_vendors_directory(root_dir): if not os.path.isdir(company_path): continue + if not validate_company_files(company_path): + all_success = False + continue + for device in os.listdir(company_path): device_path = os.path.join(company_path, device) From cf37fa2d81d29afe0c96262da0732b58f4fa9039 Mon Sep 17 00:00:00 2001 From: thingsboard017 Date: Mon, 23 Dec 2024 19:03:47 +0200 Subject: [PATCH 15/33] Added 4 LNS integrations for Comfort --- .../Comfort/ChirpStack/uplink/converter.json | 39 +++++++++ .../Comfort/ChirpStack/uplink/metadata.json | 4 + .../Comfort/ChirpStack/uplink/payload.json | 48 +++++++++++ .../Comfort/ChirpStack/uplink/result.json | 27 ++++++ .../Comfort/LORIOT/uplink/converter.json | 29 +++++++ .../Comfort/LORIOT/uplink/metadata.json | 4 + .../Comfort/LORIOT/uplink/payload.json | 17 ++++ .../Comfort/LORIOT/uplink/result.json | 17 ++++ .../uplink/converter.json | 39 +++++++++ .../ThingsStackCommunity/uplink/metadata.json | 4 + .../ThingsStackCommunity/uplink/payload.json | 54 ++++++++++++ .../ThingsStackCommunity/uplink/result.json | 28 +++++++ .../uplink/converter.json | 40 +++++++++ .../uplink/metadata.json | 4 + .../ThingsStackIndustries/uplink/payload.json | 77 ++++++++++++++++++ .../ThingsStackIndustries/uplink/result.json | 28 +++++++ VENDORS/Tektelic/Comfort/info.json | 5 ++ VENDORS/Tektelic/Comfort/photo.png | Bin 0 -> 81758 bytes 18 files changed, 464 insertions(+) create mode 100644 VENDORS/Tektelic/Comfort/ChirpStack/uplink/converter.json create mode 100644 VENDORS/Tektelic/Comfort/ChirpStack/uplink/metadata.json create mode 100644 VENDORS/Tektelic/Comfort/ChirpStack/uplink/payload.json create mode 100644 VENDORS/Tektelic/Comfort/ChirpStack/uplink/result.json create mode 100644 VENDORS/Tektelic/Comfort/LORIOT/uplink/converter.json create mode 100644 VENDORS/Tektelic/Comfort/LORIOT/uplink/metadata.json create mode 100644 VENDORS/Tektelic/Comfort/LORIOT/uplink/payload.json create mode 100644 VENDORS/Tektelic/Comfort/LORIOT/uplink/result.json create mode 100644 VENDORS/Tektelic/Comfort/ThingsStackCommunity/uplink/converter.json create mode 100644 VENDORS/Tektelic/Comfort/ThingsStackCommunity/uplink/metadata.json create mode 100644 VENDORS/Tektelic/Comfort/ThingsStackCommunity/uplink/payload.json create mode 100644 VENDORS/Tektelic/Comfort/ThingsStackCommunity/uplink/result.json create mode 100644 VENDORS/Tektelic/Comfort/ThingsStackIndustries/uplink/converter.json create mode 100644 VENDORS/Tektelic/Comfort/ThingsStackIndustries/uplink/metadata.json create mode 100644 VENDORS/Tektelic/Comfort/ThingsStackIndustries/uplink/payload.json create mode 100644 VENDORS/Tektelic/Comfort/ThingsStackIndustries/uplink/result.json create mode 100644 VENDORS/Tektelic/Comfort/info.json create mode 100644 VENDORS/Tektelic/Comfort/photo.png diff --git a/VENDORS/Tektelic/Comfort/ChirpStack/uplink/converter.json b/VENDORS/Tektelic/Comfort/ChirpStack/uplink/converter.json new file mode 100644 index 00000000..d0432d74 --- /dev/null +++ b/VENDORS/Tektelic/Comfort/ChirpStack/uplink/converter.json @@ -0,0 +1,39 @@ +{ + "name": "ChirpStack Uplink Decoder for Comfort", + "type": "UPLINK", + "debugMode": false, + "debugSettings": { + "failuresEnabled": true, + "allEnabled": false, + "allEnabledUntil": 1733331880270 + }, + "configuration": { + "scriptLang": "TBEL", + "decoder": null, + "tbelDecoder": "var data = decodeToJson(payload);\nvar deviceName = data.deviceInfo.deviceName + \" \" + data.deviceInfo.devEui;\nvar deviceType = \"Comfort\";\nvar groupName = null; // If groupName is not null - created device will be added to the entity group with such name.\nvar customerName = null; // If customerName is not null - created devices will be assigned to customer with such name. \n\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// If you want to parse incoming data somehow, you can add your code to this function.\n// input: bytes\n// expected output:\n// {\n// \"attributes\": {\"attributeKey\": \"attributeValue\"},\n// \"telemetry\": [{\"ts\": 1...1, \"values\": {\"telemetryKey\":\"telemetryValue\"}, {\"ts\": 1...2, \"values\": {\"telemetryKey\":\"telemetryValue\"}}]\n// }\n\nfunction decodePayload(input) {\n var output = {\n attributes: {},\n telemetry: []\n };\n \n // --- Decoding code --- //\n var decoded = {};\n var fPort = data.fPort;\n if(fPort == 10) {\n for(var i = 0; i < input.length - 2; ) {\n var key_1 = input[i++] & 0xff;\n var key_2 = input[i++] & 0xff;\n \n if(key_1 == 0x00 && key_2 == 0xBA) {\n decoded.battery_voltage = toFixed(parseBytesToInt(input, i, 2) * 0.001, 3);\n i += 2;\n }\n else if(key_1 == 0x01 && key_2 == 0x00) {\n val = parseBytesToInt(input, i, 1);\n switch (val){\n\t\t\t\t\tcase 0:\n\t\t\t\t\t\tdecoded.hall_effect_state = \"Magnet Present\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 255:\n\t\t\t\t\t\tdecoded.hall_effect_state = \"Magnet Absent\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tdecoded.hall_effect_state = \"Invalid\";\n\t\t\t\t}\n \n i += 1;\n }\n else if(key_1 == 0x08 && key_2 == 0x04) {\n decoded.hall_effect_count = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key_1 == 0x0C && key_2 == 0x00) {\n var val = parseBytesToInt(input, i, 1);\n \n switch (val){\n\t\t\t\t\tcase 0:\n\t\t\t\t\t\tdecoded.impact_alarm = \"Impact Alarm Inactive\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 255:\n\t\t\t\t\t\tdecoded.impact_alarm = \"Impact Alarm Active\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tdecoded.impact_alarm = \"Invalid\";\n\t\t\t\t}\n\t\t\t\t\n i += 1;\n }\n else if(key_1 == 0x05 && key_2 == 0x02) {\n decoded.impact_magnitude = toFixed(parseBytesToInt(input, i, 2) * 0.001, 3);\n i += 2;\n }\n else if(key_1 == 0x07 && key_2 == 0x71) {\n decoded.accelerationX = toFixed(parseBytesToInt(input, i + 4, 2) * 0.001, 3);\n decoded.accelerationY = toFixed(parseBytesToInt(input, i + 2, 2) * 0.001, 3);\n decoded.accelerationZ = toFixed(parseBytesToInt(input, i, 2) * 0.001, 3);\n i += 6;\n }\n else if(key_1 == 0x0E && key_2 == 0x00) {\n var val = parseBytesToInt(input, i, 1);\n\t\t\t\tswitch (val){\n\t\t\t\t\tcase 0:\n\t\t\t\t\t\tdecoded.extconnector_state = \"Low(short-circuit)\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 255:\n\t\t\t\t\t\tdecoded.extconnector_state = \"High(open-circuit)\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tdecoded.extconnector_state = \"Invalid\";\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\ti += 1;\n }\n else if(key_1 == 0x0F && key_2 == 0x04) {\n decoded.extconnector_count = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key_1 == 0x12 && key_2 == 0x04) {\n decoded.extconnector_total_count = parseBytesToInt(input, i, 4);\n i += 4;\n }\n else if(key_1 == 0x11 && key_2 == 0x02) {\n decoded.extconnector_analog = toFixed(parseBytesToInt(input, i, 2) * 0.001, 3);\n i += 2;\n }\n else if(key_1 == 0x0B && key_2 == 0x67) {\n decoded.mcu_temperature = toFixed(parseBytesToInt(input, i, 2) * 0.1, 1);\n i += 2;\n }\n else if(key_1 == 0x03 && key_2 == 0x67) {\n decoded.ambient_temperature = toFixed(parseBytesToInt(input, i, 2) * 0.1, 1);\n i += 2;\n }\n else if(key_1 == 0x04 && key_2 == 0x68) {\n decoded.relative_humidity = toFixed(parseBytesToInt(input, i, 1) * 0.5, 1);\n i += 1;\n }\n else if(key_1 == 0x02 && key_2 == 0x00) {\n var val = parseBytesToInt(input, i, 1);\n \n\t\t\t\tswitch (val){\n\t\t\t\t\tcase 0:\n\t\t\t\t\t\tdecoded.light_detected = \"Dark\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 255:\n\t\t\t\t\t\tdecoded.light_detected = \"Bright\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tdecoded.light_detected = \"Invalid\";\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\ti += 1;\n }\n else if(key_1 == 0x10 && key_2 == 0x02) {\n decoded.light_intensity = parseBytesToInt(input, i, 1);\n\t\t\t\t\n\t\t\t\ti += 1;\n }\n else if(key_1 == 0x0A && key_2 == 0x00) {\n var val = parseBytesToInt(input, i, 1);\n\t\t\t\t\n\t\t\t\tswitch (val){\n\t\t\t\t\tcase 0:\n\t\t\t\t\t\tdecoded.motion_event_state = \"None\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 255:\n\t\t\t\t\t\tdecoded.motion_event_state = \"Detected\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tdecoded.motion_event_state = \"Invalid\";\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\ti += 1;\n }\n else if(key_1 == 0x0D && key_2 == 0x04) {\n decoded.motion_event_count = parseBytesToInt(input, i, 2);\n\t\t\t\t\n\t\t\t\ti += 2;\n }\n }\n }\n else if(fPort == 0x05) {\n var key_1 = input[i++] & 0xff;\n var key_2 = input[i++] & 0xff;\n \n if(key_1 == 0x40 && key_2 == 0x06) {\n var val = input[i + 5];\n\t\t\tswitch (val){\n\t\t\t\tcase 1:\n\t\t\t\t\tdecoded_data.reset_diagnostics_reset_reason = \"Push-button reset\";\n\t\t\t\t\tbreak;\n\t\t\t\tcase 2:\n\t\t\t\t\tdecoded_data.reset_diagnostics_reset_reason = \"DL command rest\";\n\t\t\t\t\tbreak;\n\t\t\t\tcase 4:\n\t\t\t\t\tdecoded_data.reset_diagnostics_reset_reason = \"Independent watchdog reset\";\n\t\t\t\t\tbreak;\n\t\t\t\tcase 8:\n\t\t\t\t\tdecoded_data.reset_diagnostics_reset_reason = \"Power loss reset\";\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\tdecoded_data.reset_diagnostics_reset_reason = \"Invalid\";\n\t\t\t}\n\t\t\tdecoded_data.reset_diagnostics_power_loss_reset_count = input[i + 3];\n\t\t\tdecoded_data.reset_diagnostics_watchdog_reset_count = input[i + 2];\n\t\t\tdecoded_data.reset_diagnostics_dl_reset_count = input[i + 1];\n\t\t\tdecoded_data.reset_diagnostics_button_reset_count = input[i];\n }\n }\n else if (fPort == 100) {\n for(var i = 0; i < input.length -1; ) {\n var key = input[i++] & 0xff;\n \n if(key == 0x00) {\n output.attributes.eui = bytesToHex(java.util.Arrays.copyRange(input, i, i + 8));\n i += 8;\n }\n else if(key == 0x01) {\n output.attributes.app_eui = bytesToHex(java.util.Arrays.copyRange(input, i, i + 8));\n\t\t\t\ti += 8;\n }\n else if (key == 0x02) {\n output.attributes.app_key = bytesToHex(java.util.Arrays.copyRange(input, i, i + 16));\n i += 16;\n }\n else if (key == 0x03) {\n output.attributes.devAddr = bytesToHex(java.util.Arrays.copyRange(input, i, i + 4));\n i += 4;\n }\n else if(key == 0x04) {\n output.attributes.network_session_key = bytesToHex(java.util.Arrays.copyRange(input, i, i + 16));\n i += 16;\n }\n else if(key == 0x05) {\n output.attributes.app_session_key = bytesToHex(java.util.Arrays.copyRange(input, i, i + 16));\n i += 16;\n }\n else if(key == 0x10) {\n var val = (((input[i] << 8) | input[i + 1]) >> 15) & 1;\n switch (val){\n\t\t\t\t\tcase 0:\n\t\t\t\t\t\toutput.attributes.loramac_join_mode = \"ABP\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 1:\n\t\t\t\t\t\toutput.attributes.loramac_join_mode = \"OTAA\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\toutput.attributes.loramac_join_mode = \"Invalid\";\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\ti += 1;\n }\n else if (key == 0x11) {\n\t\t\t\tvar val = (((input[i] << 8) | input[i + 1]) >> 3) & 1;\n\t\t\t\toutput.attributes.adr = getEnableStatus(val);\n\t\t\t\t\n\t\t\t\tvar val = (((input[i] << 8) | input[i + 1]) >> 2) & 1;\n\t\t\t\toutput.attributes.duty_cycle = getEnableStatus(val);\n\t\t\t\t\n\t\t\t\tvar val = (((input[i] << 8) | input[i + 1]) >> 1) & 1;\n\t\t\t\t\n\t\t\t\tswitch (val) {\n\t\t\t\t\tcase 0:\n\t\t\t\t\t\toutput.attributes.sync_word = \"Private\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 1:\n\t\t\t\t\t\toutput.attributes.sync_word = \"Public\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\toutput.attributes.sync_word = \"Invalid\";\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tvar val = ((input[i] << 8) | input[i + 1]) & 1;\n\t\t\t\t\n\t\t\t\tswitch (val){\n\t\t\t\t\tcase 0:\n\t\t\t\t\t\toutput.attributes.confirm_mode = \"Unconfirmed\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 1:\n\t\t\t\t\t\toutput.attributes.confirm_mode = \"Confirmed\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t output.attributes.confirm_mode = \"Invalid\";\n\t\t\t\t}\n\t\t\t\ti += 2;\n }\n else if (key == 0x12) {\n output.attributes.dr_number = (((input[i] << 8) | input[i + 1]) >> 8) & 0xF;\n output.attributes.tx_power_number = ((input[i] << 8) | input[i + 1]) & 0xF;\n \n i +=2;\n }\n else if (key == 0x13) {\n output.attributes.frequency = (((input[i] << 32) | (input[i + 1] << 24) | (input[i + 2] << 16) | (input[i + 3] << 8) | input[i + 4]) >> 8) & 0xFFFFFFFF;\n output.attributes.dr_number_rx2 = input[i + 4] & 0xFF;\n \n i += 5;\n }\n else if(key == 0x19) {\n output.attributes.netid_msb = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x1A) {\n output.attributes.loramac_net_id_lsb = parseBytesToInt(input, i, 2);\n\t\t\t\ti += 2;\n }\n else if (key == 0x20) {\n output.attributes.seconds_per_core_tick = parseBytesToInt(input, i, 4);\n i += 4;\n }\n else if(key == 0x21) {\n output.attributes.tick_per_battery = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x22) {\n output.attributes.tick_per_ambient_temperature = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x23) {\n output.attributes.tick_per_relative_humidity = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x24) {\n output.attributes.tick_per_reed_switch = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x25) {\n output.attributes.tick_per_light = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x26) {\n output.attributes.tick_per_accelerometer = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x27) {\n output.attributes.tick_per_mcu_temperature = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x28) {\n output.attributes.tick_per_pir = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x29) {\n output.attributes.tick_per_external_connector = parseBytesToInt(input, i, 2);\n \n i += 2;\n }\n else if(key == 0x2A) {\n var bit0 = (input[i] >> 0) & 1;\n var bit1 = (input[i] >> 1) & 1;\n \n output.attributes.mode.rising_edge_enabled = getEnableStatus(bit0);\n output.attributes.mode.falling_edge_enabled = getEnableStatus(bit1);\n \n i += 1;\n }\n else if(key == 0x2B) {\n\t\t\t\toutput.attributes.reed_switch_count_threshold = parseBytesToInt(input, i, 2);\n\t\t\t\ti += 2;\n }\n else if(key == 0x2C) {\n var bit0 = (input[i] >> 0) & 1;\n var bit1 = (input[i] >> 1) & 1;\n \n output.attributes.reed_values_to_transmit_report_state_enabled = getOnOffStatus(bit0);\n output.attributes.reed_values_to_transmit_report_count_enabled = getOnOffStatus(bit1);\n \n i += 1;\n }\n else if(key == 0x2D) {\n var bit0 = (input[i] >> 0) & 1;\n var bit1 = (input[i] >> 1) & 1;\n var bit7 = (input[i] >> 7) & 1;\n \n output.attributes.external_mode_rising_edge_enabled_ex = getOnOffStatus(bit0);\n output.attributes.external_mode_falling_edge_enabled_ex = getOnOffStatus(bit1);\n \n switch (bit7){\n\t\t\t\t\tcase 0:\n\t\t\t\t\t\toutput.attributes.mode = \"Digital\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 1:\n\t\t\t\t\t output.attributes.mode = \"Analog\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\toutput.attributes.mode = \"Invalid\";\n\t\t\t\t}\n\t\t\t\t\n i += 1;\n }\n else if(key == 0x2E) {\n output.attributes.external_connector_count_threshold = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x2F) {\n var bit0 = (input[i] >> 0) & 1;\n var bit1 = (input[i] >> 1) & 1;\n var bit4 = (input[i] >> 4) & 1;\n \n output.attributes.external_values_to_transmit.report_state_enabled_ex = getOnOffStatus(bit0);\n output.attributes.external_values_to_transmit.report_count_enabled_ex = getOnOffStatus(bit1);\n output.attributes.external_values_to_transmit.count_type = bit4;\n i += 1;\n }\n else if(key == 0x30) {\n output.attributes.impact_event_threshold = toFixed(parseBytesToInt(input, i, 2) * 0x001, 3);\n i += 2;\n }\n else if(key == 0x31) {\n output.attributes.acceleration_event_threshold = toFixed(parseBytesToInt(input, i, 2) * 0.001, 3);\n i += 2;\n }\n else if(key == 0x32) {\n var bit0 = (input[i] >> 0) & 1;\n output.attributes.values_to_transmit.report_periodic_alarm_enabled = getOnOffStatus(bit0);\n \n var bit1 = (input[i] >> 1) & 1;\n output.attributes.values_to_transmit.report_periodic_magnitude_enabled = getOnOffStatus(bit1);\n \n var bit2 = (input[i] >> 2) & 1;\n output.attributes.values_to_transmit.report_periodic_vector_enabled = getOnOffStatus(bit2);\n \n var bit4 = (input[i] >> 4) & 1;\n output.attributes.values_to_transmit.report_event_magnitude_enabled = getOnOffStatus(bit4);\n \n var bit5 = (input[i] >> 5) & 1;\n output.attributes.values_to_transmit.report_event_vector_enabled = getOnOffStatus(bit5);\n \n i += 1;\n }\n else if(key == 0x33) {\n output.attributes.acceleration_impact_grace_period = parseBytesToInt(input, i, 2);\n\t\t\t\t\n\t\t\t\ti += 2;\n }\n else if (key == 0x34) {\n var bit0 = (input[i] >> 0) & 1;\n output.attributes.acceleration_mode.impact_threshold_enabled = getEnableStatus(bit0);\n \n var bit1 = (input[i] >> 1) & 1;\n\t\t\t\toutput.attributes.acceleration_mode.acceleration_threshold_enabled = getEnableStatus(bit1);\n\t\t\t\t\n\t\t\t\tvar bit4 = (input[i] >> 4) & 1;\n\t\t\t\toutput.attributes.acceleration_mode.xaxis_enabled = getEnableStatus(bit4);\n\t\t\t\t\n\t\t\t\tvar bit5 = (input[i] >> 5) & 1;\n\t\t\t\toutput.attributes.acceleration_mode.yaxis_enabled = getEnableStatus(bit5);\n\t\t\t\t\n\t\t\t\tvar bit6 = (input[i] >> 6) & 1;\n\t\t\t\toutput.attributes.acceleration_mode.zaxis_enabled = getEnableStatus(bit6);\n\t\t\t\t\n\t\t\t\tvar bit7 = (input[i] >> 7) & 1;\n\t\t\t\toutput.attributes.acceleration_mode.poweron = getOnOffStatus(bit7);\n\t\t\t\t\n\t\t\t\ti += 1;\n }\n else if (key == 0x35) {\n var val = (input[i] >> 1) & 0x03;\n\t\t\t\t\n\t\t\t\tswitch (val) {\n\t\t\t\t\tcase 1:\n\t\t\t\t\t\toutput.attributes.sensitivity_accelerometer_sample_rate = \"1 Hz\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 2:\n\t\t\t\t\t\toutput.attributes.sensitivity_accelerometer_sample_rate = \"10 Hz\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 3:\n\t\t\t\t\t\toutput.attributes.sensitivity_accelerometer_sample_rate = \"25 Hz\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 4:\n\t\t\t\t\t\toutput.attributes.sensitivity_accelerometer_sample_rate = \"50 Hz\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 5:\n\t\t\t\t\t\toutput.attributes.sensitivity_accelerometer_sample_rate = \"100 Hz\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 6:\n\t\t\t\t\t\toutput.attributes.sensitivity_accelerometer_sample_rate = \"200 Hz\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 7:\n\t\t\t\t\t\toutput.attributes.sensitivity_accelerometer_sample_rate = \"400 Hz\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\toutput.attributes.sensitivity_accelerometer_sample_rate = \"Invalid\";\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tvar val = (arg >> 4) & 0x03;\n\t\t\t\tswitch (val) {\n\t\t\t\t\tcase 0:\n\t\t\t\t\t\toutput.attributes.sensitivity_accelerometer_measurement_range = \"±2 g\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 1:\n\t\t\t\t\t\toutput.attributes.sensitivity_accelerometer_measurement_range = \"±4 g\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 2:\n\t\t\t\t\t\toutput.attributes.sensitivity_accelerometer_measurement_range = \"±8 g\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 3:\n\t\t\t\t\t\toutput.attributes.sensitivity_accelerometer_measurement_range = \"±16 g\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\toutput.attributes.sensitivity_accelerometer_measurement_range = \"Invalid\";\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\ti += 1;\n }\n else if (key == 0x36) {\n output.attributes.impact_alarm_grace_period = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if (key == 0x37) {\n output.attributes.impact_alarm_threshold_count = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if (key == 0x38) {\n output.attributes.impact_alarm_threshold_period = parseBytesToInt(input, i, 2);\n \n i += 2;\n }\n else if (key == 0x39) {\n output.attributes.temperature_relative_humidity_sample_period_idle = parseBytesToInt(input, i, 4);\n \n i += 4;\n }\n else if (key == 0x3A) {\n output.attributes.temperature_relative_humidity_sample_period_active = parseBytesToInt(input, i, 4);\n \n i += 4;\n }\n else if (key == 0x3B) {\n output.attributes.temperature_threshold_low_temp_threshold = parseBytesToInt(input, i, 1);\n output.attributes.temperature_threshold_high_temp_threshold = parseBytesToInt(input, i + 1, 1);\n \n i += 2;\n }\n else if (key == 0x3C) {\n var bit0 = (input[i] >> 0) & 1;\n output.attributes.ambient_temperature_threshold_enabled = getEnableStatus(bit0);\n \n i += 1;\n }\n else if (key == 0x3D) {\n output.attributes.rh_threshold.low_rh_threshold = parseBytesToInt(input, i, 1);\n output.attributes.rh_threshold.high_rh_threshold = parseBytesToInt(input, i + 1, 1);\n \n i += 2;\n }\n else if (key == 0x3E) {\n var bit0 = (input[i] >> 0) & 1;\n output.attributes.relative_humidity_threshold_enabled =getEnableStatus(bit0);\n \n i += 1;\n }\n else if (key == 0x40) {\n output.attributes.mcu_temperature_sample_period_idle = parseBytesToInt(input, i, 4);\n i += 4;\n }\n else if (key == 0x41) {\n output.attributes.mcu_temperature_sample_period_active = parseBytesToInt(input, i, 4);\n i += 4;\n }\n else if (key == 0x42) {\n output.attributes.mcu_temp_threshold_high_mcu_temp_threshold = input[i + 1];\n output.attributes.mcu_temp_threshold_low_mcu_temp_threshold = input[i];\n i += 4;\n }\n else if (key == 0x43) {\n var val = input[i] & 1;\n output.attributes.mcu_temperature_threshold_enabled = getEnableStatus(val);\n\n\t\t\t\ti += 2;\n }\n else if (key == 0x44) {\n output.attributes.analog_sample_period_idle = parseBytesToInt(input, i, 4);\n \n i += 4;\n }\n else if (key == 0x45) {\n output.attributes.analog_sample_period_active = parseBytesToInt(input, i, 4);\n \n i += 4;\n }\n else if(key == 0x46) {\n output.attributes.analog_threshold_high_analog_threshold = toFixed(parseBytesToInt(input, i + 2, 2) * 0.001, 3);\n\t\t\t\toutput.attributes.analog_threshold_low_analog_threshold = toFixed(parseBytesToInt(input, i, 2) * 0.001, 3);\n\t\t\t\ti += 4;\n }\n else if (key == 0x4A) {\n var bit0 = (input[i] >> 0) & 1;\n output.attributes.analog_input_threshold_enabled = getEnableStatus(bit0);\n \n i +=1;\n }\n else if (key == 0x47) {\n output.attributes.light_sample_period = parseBytesToInt(input, i, 4);\n \n i += 4;\n }\n else if (key == 0x48 ) {\n var val = (input[i] >> 7) & 1;\n output.attributes.light_thresholds.threshold_enabled = getEnableStatus(val);\n output.attributes.light_thresholds.threshold = input[i] & 0x3F;\n \n i += 1;\n }\n else if (key == 0x49) {\n var bit0 = (input[i] >> 0) & 1;\n output.attributes.light_values_to_transmit.state_reported = getEnableStatus(bit0);\n \n var bit1 = (input[i] >> 1) & 1;\n output.attributes.light_values_to_transmit.intensity_reported = getEnableStatus(bit1);\n \n i +=1;\n }\n else if (key == 0x50) {\n output.attributes.pir_grace_period = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if (key == 0x51) {\n output.attributes.pir_threshold = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if (key == 0x52) {\n output.attributes.pir_threshold_period = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if (key == 0x53) {\n var bit7 = (input[i] >> 7) & 1;\n output.attributes.pir_mode.motion_count_reported = getEnableStatus(bit7);\n \n var bit6 = (input[i] >> pir_mode) & 1;\n output.attributes.pir_mode.motion_state_reported = getEnableStatus(bit6);\n \n var bit1 = (input[i] >> 1) & 1;\n output.attributes.pir_mode.event_transmission_enabled = getEnableStatus(bit1);\n \n var bit0 = (input[i] >> 0) & 1;\n output.attributes.pir_mode.transducer_enabled = getEnableStatus(bit0);\n \n i += 1;\n }\n else if (key == 0x54) {\n output.attributes.pir_mode.motion_count_reported = input[i + 1];\n output.attributes.pir_mode.motion_state_reported = input[i];\n \n i += 1;\n }\n else if (key == 0x6F) {\n var val = (input[i] >> 0) & 1;\n \n switch (val){\n\t\t\t\t\tcase 0:\n\t\t\t\t\t\toutput.attributes_resp_to_dl_command_format = \"Invalid-write response format\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 1:\n\t\t\t\t\t\toutput.attributes_resp_to_dl_command_format = \"4-byte CRC\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\toutput.attributes_resp_to_dl_command_format = \"Invalid\";\n\t\t\t\t}\n \n i += 1;\n }\n else if (key == 0x71) {\n output.attributes.app_major_version = input[i + 6];\n\t\t\t\toutput.attributes.app_minor_version = input[i + 5];\n\t\t\t\toutput.attributes.app_revision = input[i + 4];\n\t\t\t\toutput.attributes.loramac_major_version = input[i + 3];\n\t\t\t\toutput.attributes.loramac_minor_version = input[i + 2];\n\t\t\t\toutput.attributes.loramac_revision = input[i + 1];\n\t\t\t\tvar val = input[i];\n\t\t\t\tswitch (val){\n\t\t\t\t\tcase 0:\n\t\t\t\t\t\toutput.attributes.region = \"EU868\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 1:\n\t\t\t\t\t\toutput.attributes.region = \"US915\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 2:\n\t\t\t\t\t\toutput.attributes.region = \"AS923\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 3:\n\t\t\t\t\t\toutput.attributes.region = \"AU915\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 4:\n\t\t\t\t\t\toutput.attributes.region = \"IN865\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 6:\n\t\t\t\t\t\toutput.attributes.region = \"KR920\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 7:\n\t\t\t\t\t\toutput.attributes.region = \"RU864\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\toutput.attributes.region = \"Invalid\";\n\t\t\t\t}\n\t\t\t\ti += 7;\n }\n }\n }\n else if (fPort == 101) {\n var size = input.length;\n var responses = [];\n \n var index = 0;\n while (index < size) {\n var downlinkFcnt = input[index++] & 0xFF; \n var numInvalidWrites = input[index++] & 0xFF; \n \n if (numInvalidWrites > 0) {\n var invalidRegisters = [];\n for (var i = 0; i < numInvalidWrites; i++) {\n invalidRegisters.add(String.format(\"0x%02X\", input[index + i]));\n }\n index += numInvalidWrites;\n \n responses.add(String.format(\n \"%d Invalid write command(s) from DL:%d for register(s): %s\",\n numInvalidWrites, downlinkFcnt, String.join(\", \", invalidRegisters)\n ));\n } else {\n responses.add(String.format(\"All write commands from DL:%d were successful\", downlinkFcnt));\n }\n }\n \n decoded.response = responses;\n }\n\n output.telemetry = [{\n ts: timestamp,\n values: decoded\n }];\n // --- Decoding code --- //\n return output;\n}\n\n// --- attributes and telemetry objects ---\nvar telemetry = [];\nvar attributes = {};\n// --- attributes and telemetry objects ---\n\n// --- Timestamp parsing\nvar dateString = data.time;\ntimestamp = parseDateToTimestamp(dateString);\n// --- Timestamp parsing\n\n// Passing incoming bytes to decodePayload function, to get custom decoding\nvar customDecoding = decodePayload(base64ToBytes(data.data));\n\n\nattributes.eui = data.deviceInfo.devEui;\n\n// Collecting data to result\nif (customDecoding.?telemetry.size() > 0) {\n if (customDecoding.telemetry instanceof java.util.ArrayList) {\n foreach(telemetryObj: customDecoding.telemetry) {\n if (telemetryObj.ts != null && telemetryObj.values != null) {\n telemetry.add(telemetryObj);\n }\n }\n } else {\n telemetry.putAll(customDecoding.telemetry);\n }\n}\n\nif (customDecoding.?attributes.size() > 0) {\n attributes.putAll(customDecoding.attributes);\n}\n\n// You can add some keys manually to attributes or telemetry\nattributes.eui = data.deviceInfo.?devEui;\nattributes.devAddr = data.devAddr;\nattributes.fPort = data.fPort;\nattributes.applicationId = data.deviceInfo.?applicationId;\nattributes.applicationName = data.deviceInfo.?applicationName;\nattributes.tenantId = data.deviceInfo.?tenantId;\nattributes.tenantName = data.deviceInfo.?tenantName;\nattributes.deviceProfileId = data.deviceInfo.?deviceProfileId;\nattributes.deviceProfileName = data.deviceInfo.?deviceProfileName;\nattributes.frequency = data.txInfo.?frequency;\nattributes.bandwidth = data.txInfo.?modulation.?lora.?bandwidth;\nattributes.spreadingFactor = data.txInfo.?modulation.?lora.?spreadingFactor;\nattributes.codeRate = data.txInfo.?modulation.?lora.?codeRate;\n\nif(Boolean.parseBoolean(metadata[\"includeGatewayInfo\"])) {\n var gatewayInfo = getGatewayInfo();\n var addDataToTelemetry = {};\n addDataToTelemetry.snr = gatewayInfo.snr;\n addDataToTelemetry.rssi = gatewayInfo.rssi;\n addDataToTelemetry.channel = gatewayInfo.channel;\n addDataToTelemetry.rfChain = gatewayInfo.rfChain;\n addDataToTelemetry.fCnt = data.fCnt;\n \n telemetry = processTelemetryData(telemetry, addDataToTelemetry);\n}\n\nvar result = {\n deviceName: deviceName,\n deviceType: deviceType,\n // assetName: assetName,\n // assetType: assetType,\n attributes: attributes,\n telemetry: telemetry\n};\n\naddAdditionalInfoForDeviceMsg(result, customerName, groupName);\n\nreturn result;\n\nfunction addAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName) {\n if (customerName != null) {\n deviceInfo.customerName = customerName;\n }\n if (groupName != null) {\n deviceInfo.groupName = groupName;\n }\n}\n\nfunction parseDateToTimestamp(dateString) {\n var date = new Date(dateString);\n var timestamp = date.getTime();\n \n // If we cannot parse timestamp - we will use the current timestamp\n if (timestamp == -1) {\n timestamp = Date.now();\n }\n \n return timestamp;\n}\n\nfunction getGatewayInfo() {\n var gatewayList = data.rxInfo;\n var maxRssi = Integer.MIN_VALUE;\n var gatewayInfo = {};\n \n foreach (gateway : gatewayList) {\n if(gateway.rssi > maxRssi) {\n maxRssi = gateway.rssi;\n gatewayInfo = gateway;\n }\n }\n \n return gatewayInfo;\n}\n\nfunction processTelemetryData(telemetry, addDataToTelemetry) {\n if (telemetry.size >= 1) {\n telemetry = addDataToTelemetries(telemetry, addDataToTelemetry);\n }\n else {\n telemetry.add(addDataToTelemetry);\n }\n \n return telemetry;\n}\n\nfunction addDataToTelemetries(telemetries, addDataToTelemetry) {\n foreach(telemetry : telemetries) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[\"values\"].keys.contains(element.key)) {\n telemetry[\"values\"][element.key] = element.value;\n }\n } \n }\n \n return telemetries;\n}\n\nfunction getEnableStatus(bit) {\n var enableResult = \"Invalid\";\n \n switch (bit) {\n\t\tcase 0:\n\t\t enableResult = \"Disable\";\n\t\t\tbreak;\n\t\tcase 1:\n\t\t\tenableResult = \"Enable\";\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tenableResult = \"Invalid\";\n\t}\n \n return enableResult;\n}\n\nfunction getOnOffStatus(bit) {\n var reportResult = \"Invalid\";\n \n switch (bit) {\n case 0:\n reportResult = \"Off\";\n break;\n case 1:\n reportResult = \"On\";\n break;\n default:\n reportResult = \"Invalid\";\n }\n \n return reportResult;\n}", + "encoder": null, + "tbelEncoder": null, + "updateOnlyKeys": [ + "tenantId", + "tenantName", + "applicationId", + "applicationName", + "deviceProfileId", + "deviceProfileName", + "devAddr", + "fPort", + "frequency", + "bandwidth", + "spreadingFactor", + "codeRate", + "channel", + "rfChain", + "eui", + "battery" + ] + }, + "additionalInfo": { + "description": "" + }, + "edgeTemplate": false +} \ No newline at end of file diff --git a/VENDORS/Tektelic/Comfort/ChirpStack/uplink/metadata.json b/VENDORS/Tektelic/Comfort/ChirpStack/uplink/metadata.json new file mode 100644 index 00000000..23f54b34 --- /dev/null +++ b/VENDORS/Tektelic/Comfort/ChirpStack/uplink/metadata.json @@ -0,0 +1,4 @@ +{ + "integrationName": "ChirpStack integration", + "includeGatewayInfo": "false" +} \ No newline at end of file diff --git a/VENDORS/Tektelic/Comfort/ChirpStack/uplink/payload.json b/VENDORS/Tektelic/Comfort/ChirpStack/uplink/payload.json new file mode 100644 index 00000000..8b17d0f9 --- /dev/null +++ b/VENDORS/Tektelic/Comfort/ChirpStack/uplink/payload.json @@ -0,0 +1,48 @@ +{ + "deduplicationId": "57433366-50a6-4dc2-8145-2df1bbc70d9e", + "time": "2023-05-22T07:47:05.404859+00:00", + "deviceInfo": { + "tenantId": "52f14cd4-c6f1-4fbd-8f87-4025e1d49242", + "tenantName": "ChirpStack", + "applicationId": "ca739e26-7b67-4f14-b69e-d568c22a5a75", + "applicationName": "Chirpstack application", + "deviceProfileId": "605d08d4-65f5-4d2c-8a5a-3d2457662f79", + "deviceProfileName": "Chirpstack default device profile", + "deviceName": "Device name", + "devEui": "1000000000000001", + "tags": {} + }, + "devAddr": "20000001", + "adr": true, + "dr": 5, + "fCnt": 4, + "fPort": 10, + "confirmed": false, + "data": "A2cA4QRoTQC6C54=", + "rxInfo": [{ + "gatewayId": "6a7e111a10000000", + "uplinkId": 24022, + "time": "2023-05-22T07:47:05.404859+00:00", + "rssi": -35, + "snr": 11.5, + "channel": 2, + "rfChain": 1, + "location": {}, + "context": "EFwMtA==", + "metadata": { + "region_common_name": "EU868", + "region_config_id": "eu868" + }, + "crcStatus": "CRC_OK" + }], + "txInfo": { + "frequency": 868500000, + "modulation": { + "lora": { + "bandwidth": 125000, + "spreadingFactor": 7, + "codeRate": "CR_4_5" + } + } + } +} \ No newline at end of file diff --git a/VENDORS/Tektelic/Comfort/ChirpStack/uplink/result.json b/VENDORS/Tektelic/Comfort/ChirpStack/uplink/result.json new file mode 100644 index 00000000..90b77baa --- /dev/null +++ b/VENDORS/Tektelic/Comfort/ChirpStack/uplink/result.json @@ -0,0 +1,27 @@ +{ + "deviceName": "Device name 1000000000000001", + "deviceType": "Comfort", + "attributes": { + "eui": "1000000000000001", + "devAddr": "20000001", + "fPort": 10, + "applicationId": "ca739e26-7b67-4f14-b69e-d568c22a5a75", + "applicationName": "Chirpstack application", + "tenantId": "52f14cd4-c6f1-4fbd-8f87-4025e1d49242", + "tenantName": "ChirpStack", + "deviceProfileId": "605d08d4-65f5-4d2c-8a5a-3d2457662f79", + "deviceProfileName": "Chirpstack default device profile", + "frequency": 868500000, + "bandwidth": 125000, + "spreadingFactor": 7, + "codeRate": "CR_4_5" + }, + "telemetry": [{ + "ts": 1684741625404, + "values": { + "ambient_temperature": 22.5, + "relative_humidity": 38.5, + "battery_voltage": 2.974 + } + }] +} \ No newline at end of file diff --git a/VENDORS/Tektelic/Comfort/LORIOT/uplink/converter.json b/VENDORS/Tektelic/Comfort/LORIOT/uplink/converter.json new file mode 100644 index 00000000..ae63ead2 --- /dev/null +++ b/VENDORS/Tektelic/Comfort/LORIOT/uplink/converter.json @@ -0,0 +1,29 @@ +{ + "name": "Loriot Uplink Decoder for Comfort", + "type": "UPLINK", + "debugMode": false, + "debugSettings": { + "failuresEnabled": true, + "allEnabled": false, + "allEnabledUntil": 1733331880270 + }, + "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);\nvar deviceName = data.EUI;\nvar deviceType = \"Comfort\";\nvar groupName = null; // If groupName is not null - created device will be added to the entity group with such name.\nvar customerName = null; // If customerName is not null - created devices will be assigned to customer with such name. \n\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// If you want to parse incoming data somehow, you can add your code to this function.\n// input: bytes\n// expected output:\n// {\n// \"attributes\": {\"attributeKey\": \"attributeValue\"},\n// \"telemetry\": {\"telemetryKey\": \"telemetryValue\"}\n// }\n\nfunction decodePayload(input) {\n var output = { attributes: {}, telemetry: []};\n \n var decoded = {};\n var fPort = data.port;\n if(fPort == 10) {\n for(var i = 0; i < input.length - 2; ) {\n var key_1 = input[i++] & 0xff;\n var key_2 = input[i++] & 0xff;\n \n if(key_1 == 0x00 && key_2 == 0xBA) {\n decoded.battery_voltage = toFixed(parseBytesToInt(input, i, 2) * 0.001, 3);\n i += 2;\n }\n else if(key_1 == 0x01 && key_2 == 0x00) {\n val = parseBytesToInt(input, i, 1);\n switch (val){\n\t\t\t\t\tcase 0:\n\t\t\t\t\t\tdecoded.hall_effect_state = \"Magnet Present\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 255:\n\t\t\t\t\t\tdecoded.hall_effect_state = \"Magnet Absent\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tdecoded.hall_effect_state = \"Invalid\";\n\t\t\t\t}\n \n i += 1;\n }\n else if(key_1 == 0x08 && key_2 == 0x04) {\n decoded.hall_effect_count = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key_1 == 0x0C && key_2 == 0x00) {\n var val = parseBytesToInt(input, i, 1);\n \n switch (val){\n\t\t\t\t\tcase 0:\n\t\t\t\t\t\tdecoded.impact_alarm = \"Impact Alarm Inactive\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 255:\n\t\t\t\t\t\tdecoded.impact_alarm = \"Impact Alarm Active\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tdecoded.impact_alarm = \"Invalid\";\n\t\t\t\t}\n\t\t\t\t\n i += 1;\n }\n else if(key_1 == 0x05 && key_2 == 0x02) {\n decoded.impact_magnitude = toFixed(parseBytesToInt(input, i, 2) * 0.001, 3);\n i += 2;\n }\n else if(key_1 == 0x07 && key_2 == 0x71) {\n decoded.accelerationX = toFixed(parseBytesToInt(input, i + 4, 2) * 0.001, 3);\n decoded.accelerationY = toFixed(parseBytesToInt(input, i + 2, 2) * 0.001, 3);\n decoded.accelerationZ = toFixed(parseBytesToInt(input, i, 2) * 0.001, 3);\n i += 6;\n }\n else if(key_1 == 0x0E && key_2 == 0x00) {\n var val = parseBytesToInt(input, i, 1);\n\t\t\t\tswitch (val){\n\t\t\t\t\tcase 0:\n\t\t\t\t\t\tdecoded.extconnector_state = \"Low(short-circuit)\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 255:\n\t\t\t\t\t\tdecoded.extconnector_state = \"High(open-circuit)\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tdecoded.extconnector_state = \"Invalid\";\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\ti += 1;\n }\n else if(key_1 == 0x0F && key_2 == 0x04) {\n decoded.extconnector_count = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key_1 == 0x12 && key_2 == 0x04) {\n decoded.extconnector_total_count = parseBytesToInt(input, i, 4);\n i += 4;\n }\n else if(key_1 == 0x11 && key_2 == 0x02) {\n decoded.extconnector_analog = toFixed(parseBytesToInt(input, i, 2) * 0.001, 3);\n i += 2;\n }\n else if(key_1 == 0x0B && key_2 == 0x67) {\n decoded.mcu_temperature = toFixed(parseBytesToInt(input, i, 2) * 0.1, 1);\n i += 2;\n }\n else if(key_1 == 0x03 && key_2 == 0x67) {\n decoded.ambient_temperature = toFixed(parseBytesToInt(input, i, 2) * 0.1, 1);\n i += 2;\n }\n else if(key_1 == 0x04 && key_2 == 0x68) {\n decoded.relative_humidity = toFixed(parseBytesToInt(input, i, 1) * 0.5, 1);\n i += 1;\n }\n else if(key_1 == 0x02 && key_2 == 0x00) {\n var val = parseBytesToInt(input, i, 1);\n \n\t\t\t\tswitch (val){\n\t\t\t\t\tcase 0:\n\t\t\t\t\t\tdecoded.light_detected = \"Dark\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 255:\n\t\t\t\t\t\tdecoded.light_detected = \"Bright\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tdecoded.light_detected = \"Invalid\";\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\ti += 1;\n }\n else if(key_1 == 0x10 && key_2 == 0x02) {\n decoded.light_intensity = parseBytesToInt(input, i, 1);\n\t\t\t\t\n\t\t\t\ti += 1;\n }\n else if(key_1 == 0x0A && key_2 == 0x00) {\n var val = parseBytesToInt(input, i, 1);\n\t\t\t\t\n\t\t\t\tswitch (val){\n\t\t\t\t\tcase 0:\n\t\t\t\t\t\tdecoded.motion_event_state = \"None\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 255:\n\t\t\t\t\t\tdecoded.motion_event_state = \"Detected\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tdecoded.motion_event_state = \"Invalid\";\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\ti += 1;\n }\n else if(key_1 == 0x0D && key_2 == 0x04) {\n decoded.motion_event_count = parseBytesToInt(input, i, 2);\n\t\t\t\t\n\t\t\t\ti += 2;\n }\n }\n }\n else if(fPort == 0x05) {\n var key_1 = input[i++] & 0xff;\n var key_2 = input[i++] & 0xff;\n \n if(key_1 == 0x40 && key_2 == 0x06) {\n var val = input[i + 5];\n\t\t\tswitch (val){\n\t\t\t\tcase 1:\n\t\t\t\t\tdecoded_data.reset_diagnostics_reset_reason = \"Push-button reset\";\n\t\t\t\t\tbreak;\n\t\t\t\tcase 2:\n\t\t\t\t\tdecoded_data.reset_diagnostics_reset_reason = \"DL command rest\";\n\t\t\t\t\tbreak;\n\t\t\t\tcase 4:\n\t\t\t\t\tdecoded_data.reset_diagnostics_reset_reason = \"Independent watchdog reset\";\n\t\t\t\t\tbreak;\n\t\t\t\tcase 8:\n\t\t\t\t\tdecoded_data.reset_diagnostics_reset_reason = \"Power loss reset\";\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\tdecoded_data.reset_diagnostics_reset_reason = \"Invalid\";\n\t\t\t}\n\t\t\tdecoded_data.reset_diagnostics_power_loss_reset_count = input[i + 3];\n\t\t\tdecoded_data.reset_diagnostics_watchdog_reset_count = input[i + 2];\n\t\t\tdecoded_data.reset_diagnostics_dl_reset_count = input[i + 1];\n\t\t\tdecoded_data.reset_diagnostics_button_reset_count = input[i];\n }\n }\n else if (fPort == 100) {\n for(var i = 0; i < input.length -1; ) {\n var key = input[i++] & 0xff;\n \n if(key == 0x00) {\n output.attributes.eui = bytesToHex(java.util.Arrays.copyRange(input, i, i + 8));\n i += 8;\n }\n else if(key == 0x01) {\n output.attributes.app_eui = bytesToHex(java.util.Arrays.copyRange(input, i, i + 8));\n\t\t\t\ti += 8;\n }\n else if (key == 0x02) {\n output.attributes.app_key = bytesToHex(java.util.Arrays.copyRange(input, i, i + 16));\n i += 16;\n }\n else if (key == 0x03) {\n output.attributes.devAddr = bytesToHex(java.util.Arrays.copyRange(input, i, i + 4));\n i += 4;\n }\n else if(key == 0x04) {\n output.attributes.network_session_key = bytesToHex(java.util.Arrays.copyRange(input, i, i + 16));\n i += 16;\n }\n else if(key == 0x05) {\n output.attributes.app_session_key = bytesToHex(java.util.Arrays.copyRange(input, i, i + 16));\n i += 16;\n }\n else if(key == 0x10) {\n var val = (((input[i] << 8) | input[i + 1]) >> 15) & 1;\n switch (val){\n\t\t\t\t\tcase 0:\n\t\t\t\t\t\toutput.attributes.loramac_join_mode = \"ABP\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 1:\n\t\t\t\t\t\toutput.attributes.loramac_join_mode = \"OTAA\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\toutput.attributes.loramac_join_mode = \"Invalid\";\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\ti += 1;\n }\n else if (key == 0x11) {\n\t\t\t\tvar val = (((input[i] << 8) | input[i + 1]) >> 3) & 1;\n\t\t\t\toutput.attributes.adr = getEnableStatus(val);\n\t\t\t\t\n\t\t\t\tvar val = (((input[i] << 8) | input[i + 1]) >> 2) & 1;\n\t\t\t\toutput.attributes.duty_cycle = getEnableStatus(val);\n\t\t\t\t\n\t\t\t\tvar val = (((input[i] << 8) | input[i + 1]) >> 1) & 1;\n\t\t\t\t\n\t\t\t\tswitch (val) {\n\t\t\t\t\tcase 0:\n\t\t\t\t\t\toutput.attributes.sync_word = \"Private\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 1:\n\t\t\t\t\t\toutput.attributes.sync_word = \"Public\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\toutput.attributes.sync_word = \"Invalid\";\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tvar val = ((input[i] << 8) | input[i + 1]) & 1;\n\t\t\t\t\n\t\t\t\tswitch (val){\n\t\t\t\t\tcase 0:\n\t\t\t\t\t\toutput.attributes.confirm_mode = \"Unconfirmed\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 1:\n\t\t\t\t\t\toutput.attributes.confirm_mode = \"Confirmed\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t output.attributes.confirm_mode = \"Invalid\";\n\t\t\t\t}\n\t\t\t\ti += 2;\n }\n else if (key == 0x12) {\n output.attributes.dr_number = (((input[i] << 8) | input[i + 1]) >> 8) & 0xF;\n output.attributes.tx_power_number = ((input[i] << 8) | input[i + 1]) & 0xF;\n \n i +=2;\n }\n else if (key == 0x13) {\n output.attributes.frequency = (((input[i] << 32) | (input[i + 1] << 24) | (input[i + 2] << 16) | (input[i + 3] << 8) | input[i + 4]) >> 8) & 0xFFFFFFFF;\n output.attributes.dr_number_rx2 = input[i + 4] & 0xFF;\n \n i += 5;\n }\n else if(key == 0x19) {\n output.attributes.netid_msb = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x1A) {\n output.attributes.loramac_net_id_lsb = parseBytesToInt(input, i, 2);\n\t\t\t\ti += 2;\n }\n else if (key == 0x20) {\n output.attributes.seconds_per_core_tick = parseBytesToInt(input, i, 4);\n i += 4;\n }\n else if(key == 0x21) {\n output.attributes.tick_per_battery = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x22) {\n output.attributes.tick_per_ambient_temperature = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x23) {\n output.attributes.tick_per_relative_humidity = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x24) {\n output.attributes.tick_per_reed_switch = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x25) {\n output.attributes.tick_per_light = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x26) {\n output.attributes.tick_per_accelerometer = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x27) {\n output.attributes.tick_per_mcu_temperature = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x28) {\n output.attributes.tick_per_pir = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x29) {\n output.attributes.tick_per_external_connector = parseBytesToInt(input, i, 2);\n \n i += 2;\n }\n else if(key == 0x2A) {\n var bit0 = (input[i] >> 0) & 1;\n var bit1 = (input[i] >> 1) & 1;\n \n output.attributes.mode.rising_edge_enabled = getEnableStatus(bit0);\n output.attributes.mode.falling_edge_enabled = getEnableStatus(bit1);\n \n i += 1;\n }\n else if(key == 0x2B) {\n\t\t\t\toutput.attributes.reed_switch_count_threshold = parseBytesToInt(input, i, 2);\n\t\t\t\ti += 2;\n }\n else if(key == 0x2C) {\n var bit0 = (input[i] >> 0) & 1;\n var bit1 = (input[i] >> 1) & 1;\n \n output.attributes.reed_values_to_transmit_report_state_enabled = getOnOffStatus(bit0);\n output.attributes.reed_values_to_transmit_report_count_enabled = getOnOffStatus(bit1);\n \n i += 1;\n }\n else if(key == 0x2D) {\n var bit0 = (input[i] >> 0) & 1;\n var bit1 = (input[i] >> 1) & 1;\n var bit7 = (input[i] >> 7) & 1;\n \n output.attributes.external_mode_rising_edge_enabled_ex = getOnOffStatus(bit0);\n output.attributes.external_mode_falling_edge_enabled_ex = getOnOffStatus(bit1);\n \n switch (bit7){\n\t\t\t\t\tcase 0:\n\t\t\t\t\t\toutput.attributes.mode = \"Digital\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 1:\n\t\t\t\t\t output.attributes.mode = \"Analog\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\toutput.attributes.mode = \"Invalid\";\n\t\t\t\t}\n\t\t\t\t\n i += 1;\n }\n else if(key == 0x2E) {\n output.attributes.external_connector_count_threshold = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x2F) {\n var bit0 = (input[i] >> 0) & 1;\n var bit1 = (input[i] >> 1) & 1;\n var bit4 = (input[i] >> 4) & 1;\n \n output.attributes.external_values_to_transmit.report_state_enabled_ex = getOnOffStatus(bit0);\n output.attributes.external_values_to_transmit.report_count_enabled_ex = getOnOffStatus(bit1);\n output.attributes.external_values_to_transmit.count_type = bit4;\n i += 1;\n }\n else if(key == 0x30) {\n output.attributes.impact_event_threshold = toFixed(parseBytesToInt(input, i, 2) * 0x001, 3);\n i += 2;\n }\n else if(key == 0x31) {\n output.attributes.acceleration_event_threshold = toFixed(parseBytesToInt(input, i, 2) * 0.001, 3);\n i += 2;\n }\n else if(key == 0x32) {\n var bit0 = (input[i] >> 0) & 1;\n output.attributes.values_to_transmit.report_periodic_alarm_enabled = getOnOffStatus(bit0);\n \n var bit1 = (input[i] >> 1) & 1;\n output.attributes.values_to_transmit.report_periodic_magnitude_enabled = getOnOffStatus(bit1);\n \n var bit2 = (input[i] >> 2) & 1;\n output.attributes.values_to_transmit.report_periodic_vector_enabled = getOnOffStatus(bit2);\n \n var bit4 = (input[i] >> 4) & 1;\n output.attributes.values_to_transmit.report_event_magnitude_enabled = getOnOffStatus(bit4);\n \n var bit5 = (input[i] >> 5) & 1;\n output.attributes.values_to_transmit.report_event_vector_enabled = getOnOffStatus(bit5);\n \n i += 1;\n }\n else if(key == 0x33) {\n output.attributes.acceleration_impact_grace_period = parseBytesToInt(input, i, 2);\n\t\t\t\t\n\t\t\t\ti += 2;\n }\n else if (key == 0x34) {\n var bit0 = (input[i] >> 0) & 1;\n output.attributes.acceleration_mode.impact_threshold_enabled = getEnableStatus(bit0);\n \n var bit1 = (input[i] >> 1) & 1;\n\t\t\t\toutput.attributes.acceleration_mode.acceleration_threshold_enabled = getEnableStatus(bit1);\n\t\t\t\t\n\t\t\t\tvar bit4 = (input[i] >> 4) & 1;\n\t\t\t\toutput.attributes.acceleration_mode.xaxis_enabled = getEnableStatus(bit4);\n\t\t\t\t\n\t\t\t\tvar bit5 = (input[i] >> 5) & 1;\n\t\t\t\toutput.attributes.acceleration_mode.yaxis_enabled = getEnableStatus(bit5);\n\t\t\t\t\n\t\t\t\tvar bit6 = (input[i] >> 6) & 1;\n\t\t\t\toutput.attributes.acceleration_mode.zaxis_enabled = getEnableStatus(bit6);\n\t\t\t\t\n\t\t\t\tvar bit7 = (input[i] >> 7) & 1;\n\t\t\t\toutput.attributes.acceleration_mode.poweron = getOnOffStatus(bit7);\n\t\t\t\t\n\t\t\t\ti += 1;\n }\n else if (key == 0x35) {\n var val = (input[i] >> 1) & 0x03;\n\t\t\t\t\n\t\t\t\tswitch (val) {\n\t\t\t\t\tcase 1:\n\t\t\t\t\t\toutput.attributes.sensitivity_accelerometer_sample_rate = \"1 Hz\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 2:\n\t\t\t\t\t\toutput.attributes.sensitivity_accelerometer_sample_rate = \"10 Hz\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 3:\n\t\t\t\t\t\toutput.attributes.sensitivity_accelerometer_sample_rate = \"25 Hz\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 4:\n\t\t\t\t\t\toutput.attributes.sensitivity_accelerometer_sample_rate = \"50 Hz\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 5:\n\t\t\t\t\t\toutput.attributes.sensitivity_accelerometer_sample_rate = \"100 Hz\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 6:\n\t\t\t\t\t\toutput.attributes.sensitivity_accelerometer_sample_rate = \"200 Hz\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 7:\n\t\t\t\t\t\toutput.attributes.sensitivity_accelerometer_sample_rate = \"400 Hz\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\toutput.attributes.sensitivity_accelerometer_sample_rate = \"Invalid\";\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tvar val = (arg >> 4) & 0x03;\n\t\t\t\tswitch (val) {\n\t\t\t\t\tcase 0:\n\t\t\t\t\t\toutput.attributes.sensitivity_accelerometer_measurement_range = \"±2 g\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 1:\n\t\t\t\t\t\toutput.attributes.sensitivity_accelerometer_measurement_range = \"±4 g\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 2:\n\t\t\t\t\t\toutput.attributes.sensitivity_accelerometer_measurement_range = \"±8 g\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 3:\n\t\t\t\t\t\toutput.attributes.sensitivity_accelerometer_measurement_range = \"±16 g\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\toutput.attributes.sensitivity_accelerometer_measurement_range = \"Invalid\";\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\ti += 1;\n }\n else if (key == 0x36) {\n output.attributes.impact_alarm_grace_period = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if (key == 0x37) {\n output.attributes.impact_alarm_threshold_count = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if (key == 0x38) {\n output.attributes.impact_alarm_threshold_period = parseBytesToInt(input, i, 2);\n \n i += 2;\n }\n else if (key == 0x39) {\n output.attributes.temperature_relative_humidity_sample_period_idle = parseBytesToInt(input, i, 4);\n \n i += 4;\n }\n else if (key == 0x3A) {\n output.attributes.temperature_relative_humidity_sample_period_active = parseBytesToInt(input, i, 4);\n \n i += 4;\n }\n else if (key == 0x3B) {\n output.attributes.temperature_threshold_low_temp_threshold = parseBytesToInt(input, i, 1);\n output.attributes.temperature_threshold_high_temp_threshold = parseBytesToInt(input, i + 1, 1);\n \n i += 2;\n }\n else if (key == 0x3C) {\n var bit0 = (input[i] >> 0) & 1;\n output.attributes.ambient_temperature_threshold_enabled = getEnableStatus(bit0);\n \n i += 1;\n }\n else if (key == 0x3D) {\n output.attributes.rh_threshold.low_rh_threshold = parseBytesToInt(input, i, 1);\n output.attributes.rh_threshold.high_rh_threshold = parseBytesToInt(input, i + 1, 1);\n \n i += 2;\n }\n else if (key == 0x3E) {\n var bit0 = (input[i] >> 0) & 1;\n output.attributes.relative_humidity_threshold_enabled =getEnableStatus(bit0);\n \n i += 1;\n }\n else if (key == 0x40) {\n output.attributes.mcu_temperature_sample_period_idle = parseBytesToInt(input, i, 4);\n i += 4;\n }\n else if (key == 0x41) {\n output.attributes.mcu_temperature_sample_period_active = parseBytesToInt(input, i, 4);\n i += 4;\n }\n else if (key == 0x42) {\n output.attributes.mcu_temp_threshold_high_mcu_temp_threshold = input[i + 1];\n output.attributes.mcu_temp_threshold_low_mcu_temp_threshold = input[i];\n i += 4;\n }\n else if (key == 0x43) {\n var val = input[i] & 1;\n output.attributes.mcu_temperature_threshold_enabled = getEnableStatus(val);\n\n\t\t\t\ti += 2;\n }\n else if (key == 0x44) {\n output.attributes.analog_sample_period_idle = parseBytesToInt(input, i, 4);\n \n i += 4;\n }\n else if (key == 0x45) {\n output.attributes.analog_sample_period_active = parseBytesToInt(input, i, 4);\n \n i += 4;\n }\n else if(key == 0x46) {\n output.attributes.analog_threshold_high_analog_threshold = toFixed(parseBytesToInt(input, i + 2, 2) * 0.001, 3);\n\t\t\t\toutput.attributes.analog_threshold_low_analog_threshold = toFixed(parseBytesToInt(input, i, 2) * 0.001, 3);\n\t\t\t\ti += 4;\n }\n else if (key == 0x4A) {\n var bit0 = (input[i] >> 0) & 1;\n output.attributes.analog_input_threshold_enabled = getEnableStatus(bit0);\n \n i +=1;\n }\n else if (key == 0x47) {\n output.attributes.light_sample_period = parseBytesToInt(input, i, 4);\n \n i += 4;\n }\n else if (key == 0x48 ) {\n var val = (input[i] >> 7) & 1;\n output.attributes.light_thresholds.threshold_enabled = getEnableStatus(val);\n output.attributes.light_thresholds.threshold = input[i] & 0x3F;\n \n i += 1;\n }\n else if (key == 0x49) {\n var bit0 = (input[i] >> 0) & 1;\n output.attributes.light_values_to_transmit.state_reported = getEnableStatus(bit0);\n \n var bit1 = (input[i] >> 1) & 1;\n output.attributes.light_values_to_transmit.intensity_reported = getEnableStatus(bit1);\n \n i +=1;\n }\n else if (key == 0x50) {\n output.attributes.pir_grace_period = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if (key == 0x51) {\n output.attributes.pir_threshold = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if (key == 0x52) {\n output.attributes.pir_threshold_period = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if (key == 0x53) {\n var bit7 = (input[i] >> 7) & 1;\n output.attributes.pir_mode.motion_count_reported = getEnableStatus(bit7);\n \n var bit6 = (input[i] >> pir_mode) & 1;\n output.attributes.pir_mode.motion_state_reported = getEnableStatus(bit6);\n \n var bit1 = (input[i] >> 1) & 1;\n output.attributes.pir_mode.event_transmission_enabled = getEnableStatus(bit1);\n \n var bit0 = (input[i] >> 0) & 1;\n output.attributes.pir_mode.transducer_enabled = getEnableStatus(bit0);\n \n i += 1;\n }\n else if (key == 0x54) {\n output.attributes.pir_mode.motion_count_reported = input[i + 1];\n output.attributes.pir_mode.motion_state_reported = input[i];\n \n i += 1;\n }\n else if (key == 0x6F) {\n var val = (input[i] >> 0) & 1;\n \n switch (val){\n\t\t\t\t\tcase 0:\n\t\t\t\t\t\toutput.attributes_resp_to_dl_command_format = \"Invalid-write response format\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 1:\n\t\t\t\t\t\toutput.attributes_resp_to_dl_command_format = \"4-byte CRC\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\toutput.attributes_resp_to_dl_command_format = \"Invalid\";\n\t\t\t\t}\n \n i += 1;\n }\n else if (key == 0x71) {\n output.attributes.app_major_version = input[i + 6];\n\t\t\t\toutput.attributes.app_minor_version = input[i + 5];\n\t\t\t\toutput.attributes.app_revision = input[i + 4];\n\t\t\t\toutput.attributes.loramac_major_version = input[i + 3];\n\t\t\t\toutput.attributes.loramac_minor_version = input[i + 2];\n\t\t\t\toutput.attributes.loramac_revision = input[i + 1];\n\t\t\t\tvar val = input[i];\n\t\t\t\tswitch (val){\n\t\t\t\t\tcase 0:\n\t\t\t\t\t\toutput.attributes.region = \"EU868\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 1:\n\t\t\t\t\t\toutput.attributes.region = \"US915\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 2:\n\t\t\t\t\t\toutput.attributes.region = \"AS923\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 3:\n\t\t\t\t\t\toutput.attributes.region = \"AU915\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 4:\n\t\t\t\t\t\toutput.attributes.region = \"IN865\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 6:\n\t\t\t\t\t\toutput.attributes.region = \"KR920\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 7:\n\t\t\t\t\t\toutput.attributes.region = \"RU864\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\toutput.attributes.region = \"Invalid\";\n\t\t\t\t}\n\t\t\t\ti += 7;\n }\n }\n }\n else if (fPort == 101) {\n var size = input.length;\n var responses = [];\n \n var index = 0;\n while (index < size) {\n var downlinkFcnt = input[index++] & 0xFF; \n var numInvalidWrites = input[index++] & 0xFF; \n \n if (numInvalidWrites > 0) {\n var invalidRegisters = [];\n for (var i = 0; i < numInvalidWrites; i++) {\n invalidRegisters.add(String.format(\"0x%02X\", input[index + i]));\n }\n index += numInvalidWrites;\n \n responses.add(String.format(\n \"%d Invalid write command(s) from DL:%d for register(s): %s\",\n numInvalidWrites, downlinkFcnt, String.join(\", \", invalidRegisters)\n ));\n } else {\n responses.add(String.format(\"All write commands from DL:%d were successful\", downlinkFcnt));\n }\n }\n \n decoded.response = responses;\n }\n \n output.telemetry = [{\n ts: timestamp,\n values: decoded\n }];\n\n // --- Decoding code --- //\n return output;\n}\n\n// --- attributes and telemetry objects ---\nvar telemetry = [];\nvar attributes = {};\n// --- attributes and telemetry objects ---\n\n// --- Timestamp parsing\ntimestamp = data.ts;\n// --- Timestamp parsing\n\n// Message parsing\n// To avoid paths in the decoded objects we passing false value to function as \"pathInKey\" argument.\n// Warning: pathInKey can cause already found fields to be overwritten with the last value found.\n\nvar uplinkDataList = [];\n\n// Passing incoming bytes to decodePayload function, to get custom decoding\nvar customDecoding = decodePayload(hexToBytes(data.data));\n\n// Collecting data to result\nif (customDecoding.?telemetry.size() > 0) {\n if (customDecoding.telemetry instanceof java.util.ArrayList) {\n foreach(telemetryObj: customDecoding.telemetry) {\n if (telemetryObj.ts != null && telemetryObj.values != null) {\n telemetry.add(telemetryObj);\n }\n }\n } else {\n telemetry.putAll(customDecoding.telemetry);\n }\n}\n\nif (customDecoding.?attributes.size() > 0) {\n attributes.putAll(customDecoding.attributes);\n}\n\n// You can add some keys manually to attributes or telemetry\nattributes.eui = data.EUI;\nattributes.fPort = data.port;\nattributes.frequency = data.freq;\n\nvar isIncludeGatewayInfo = metadata[\"includeGatewayInfo\"];\nif(isIncludeGatewayInfo == true) {\n var addDataToTelemetry = {};\n addDataToTelemetry.rssi = data.rssi;\n addDataToTelemetry.seqno = data.seqno;\n addDataToTelemetry.snr = data.snr;\n addDataToTelemetry.ack = data.ack;\n addDataToTelemetry.toa = data.toa;\n addDataToTelemetry.fCnt = data.fcnt;\n \n telemetry = processTelemetryData(telemetry, addDataToTelemetry);\n}\n\nvar deviceInfo = {\n deviceName: deviceName,\n deviceType: deviceType,\n// assetName: assetName,\n// assetType: assetType,\n attributes: attributes,\n telemetry: telemetry, \n};\n\naddAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName);\n\nuplinkDataList.add(deviceInfo);\n\nvar gatewayDeviceNamePrefix = \"Gateway \";\nvar gatewayDeviceType = \"Lora gateway\";\nvar gatewayGroupName = null; // If gatewayGroupName is not null - created device will be added to the entity group with such name.\n\nif (data.cmd == \"gw\") {\n foreach( gatewayInfo : data.gws ) {\n var addGatewayInfo = {};\n\n // You can add some keys manually telemetry\n addGatewayInfo.rssi = gatewayInfo.rssi;\n addGatewayInfo.snr = gatewayInfo.snr;\n // You can add some keys manually telemetry\n \n var gatewayInfoMsg = {\n deviceName: gatewayDeviceNamePrefix + gatewayInfo.gweui,\n deviceType: gatewayDeviceType,\n telemetry: [{\n \"ts\": gatewayInfo.ts,\n \"values\": addGatewayInfo\n }],\n attributes: {\n eui: gatewayInfo.gweui\n }\n };\n addAdditionalInfoForDeviceMsg(gatewayInfoMsg, customerName, gatewayGroupName);\n uplinkDataList.add(gatewayInfoMsg);\n }\n}\n\nreturn uplinkDataList;\n\nfunction addAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName) {\n if (customerName != null) {\n deviceInfo.customerName = customerName;\n }\n if (groupName != null) {\n deviceInfo.groupName = groupName;\n }\n}\n\nfunction processTelemetryData(telemetry, addDataToTelemetry) {\n if (telemetry.size >= 1) {\n telemetry = addDataToTelemetries(telemetry, addDataToTelemetry);\n }\n else {\n telemetry.add(addDataToTelemetry);\n }\n \n return telemetry;\n}\n\nfunction addDataToTelemetries(telemetries, addDataToTelemetry) {\n foreach(telemetry : telemetries) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[\"values\"].keys.contains(element.key)) {\n telemetry[\"values\"][element.key] = element.value;\n }\n } \n }\n \n return telemetries;\n}\n\nfunction getEnableStatus(bit) {\n var enableResult = \"Invalid\";\n \n switch (bit) {\n\t\tcase 0:\n\t\t enableResult = \"Disable\";\n\t\t\tbreak;\n\t\tcase 1:\n\t\t\tenableResult = \"Enable\";\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tenableResult = \"Invalid\";\n\t}\n \n return enableResult;\n}\n\nfunction getOnOffStatus(bit) {\n var reportResult = \"Invalid\";\n \n switch (bit) {\n case 0:\n reportResult = \"Off\";\n break;\n case 1:\n reportResult = \"On\";\n break;\n default:\n reportResult = \"Invalid\";\n }\n \n return reportResult;\n}", + "encoder": null, + "tbelEncoder": null, + "updateOnlyKeys": [ + "fPort", + "ack", + "eui", + "frequency", + "dr", + "battery" + ] + }, + "additionalInfo": { + "description": "" + }, + "edgeTemplate": false +} \ No newline at end of file diff --git a/VENDORS/Tektelic/Comfort/LORIOT/uplink/metadata.json b/VENDORS/Tektelic/Comfort/LORIOT/uplink/metadata.json new file mode 100644 index 00000000..ae2ee743 --- /dev/null +++ b/VENDORS/Tektelic/Comfort/LORIOT/uplink/metadata.json @@ -0,0 +1,4 @@ +{ + "integrationName": "Loriot integration", + "includeGatewayInfo": "false" +} \ No newline at end of file diff --git a/VENDORS/Tektelic/Comfort/LORIOT/uplink/payload.json b/VENDORS/Tektelic/Comfort/LORIOT/uplink/payload.json new file mode 100644 index 00000000..b930d85b --- /dev/null +++ b/VENDORS/Tektelic/Comfort/LORIOT/uplink/payload.json @@ -0,0 +1,17 @@ +{ + "cmd": "rx", + "seqno": 3040, + "EUI": "1000000000000001", + "ts": 1684478801936, + "fcnt": 2, + "port": 10, + "freq": 867500000, + "rssi": -21, + "snr": 10, + "toa": 206, + "dr": "SF9 BW125 4/5", + "ack": false, + "bat": 94, + "offline": false, + "data": "036700E104684D00BA0B9E" +} \ No newline at end of file diff --git a/VENDORS/Tektelic/Comfort/LORIOT/uplink/result.json b/VENDORS/Tektelic/Comfort/LORIOT/uplink/result.json new file mode 100644 index 00000000..584a1873 --- /dev/null +++ b/VENDORS/Tektelic/Comfort/LORIOT/uplink/result.json @@ -0,0 +1,17 @@ +[{ + "deviceName": "1000000000000001", + "deviceType": "Comfort", + "attributes": { + "eui": "1000000000000001", + "fPort": 10, + "frequency": 867500000 + }, + "telemetry": [{ + "ts": 1684478801936, + "values": { + "ambient_temperature": 22.5, + "relative_humidity": 38.5, + "battery_voltage": 2.974 + } + }] +}] \ No newline at end of file diff --git a/VENDORS/Tektelic/Comfort/ThingsStackCommunity/uplink/converter.json b/VENDORS/Tektelic/Comfort/ThingsStackCommunity/uplink/converter.json new file mode 100644 index 00000000..3b3cc8fe --- /dev/null +++ b/VENDORS/Tektelic/Comfort/ThingsStackCommunity/uplink/converter.json @@ -0,0 +1,39 @@ +{ + "name": "The Things Stack Community Uplink Decoder for Comfort", + "type": "UPLINK", + "debugMode": false, + "debugSettings": { + "failuresEnabled": true, + "allEnabled": false, + "allEnabledUntil": 1733331880270 + }, + "configuration": { + "scriptLang": "TBEL", + "decoder": null, + "tbelDecoder": "var data = decodeToJson(payload);\n\nvar deviceName = data.end_device_ids.device_id;\nvar deviceType = \"Comfort\";\nvar groupName = null; // If groupName is not null - created device will be added to the entity group with such name.\nvar customerName = null; // If customerName is not null - created devices will be assigned to customer with such name. \n\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// If you want to parse incoming data somehow, you can add your code to this function.\n// input: bytes\n// expected output:\n// {\n// \"attributes\": {\"attributeKey\": \"attributeValue\"},\n// \"telemetry\": [{\"ts\": 1...1, \"values\": {\"telemetryKey\":\"telemetryValue\"}, {\"ts\": 1...2, \"values\": {\"telemetryKey\":\"telemetryValue\"}}]\n// }\n\nfunction decodeFrmPayload(input) {\n var output = {\n attributes: {}, telemetry: {}\n };\n \n // --- Decoding code --- //\n var decoded = {};\n var fPort = data.uplink_message.f_port;\n if(fPort == 10) {\n for(var i = 0; i < input.length - 2; ) {\n var key_1 = input[i++] & 0xff;\n var key_2 = input[i++] & 0xff;\n \n if(key_1 == 0x00 && key_2 == 0xBA) {\n decoded.battery_voltage = toFixed(parseBytesToInt(input, i, 2) * 0.001, 3);\n i += 2;\n }\n else if(key_1 == 0x01 && key_2 == 0x00) {\n val = parseBytesToInt(input, i, 1);\n switch (val){\n\t\t\t\t\tcase 0:\n\t\t\t\t\t\tdecoded.hall_effect_state = \"Magnet Present\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 255:\n\t\t\t\t\t\tdecoded.hall_effect_state = \"Magnet Absent\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tdecoded.hall_effect_state = \"Invalid\";\n\t\t\t\t}\n \n i += 1;\n }\n else if(key_1 == 0x08 && key_2 == 0x04) {\n decoded.hall_effect_count = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key_1 == 0x0C && key_2 == 0x00) {\n var val = parseBytesToInt(input, i, 1);\n \n switch (val){\n\t\t\t\t\tcase 0:\n\t\t\t\t\t\tdecoded.impact_alarm = \"Impact Alarm Inactive\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 255:\n\t\t\t\t\t\tdecoded.impact_alarm = \"Impact Alarm Active\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tdecoded.impact_alarm = \"Invalid\";\n\t\t\t\t}\n\t\t\t\t\n i += 1;\n }\n else if(key_1 == 0x05 && key_2 == 0x02) {\n decoded.impact_magnitude = toFixed(parseBytesToInt(input, i, 2) * 0.001, 3);\n i += 2;\n }\n else if(key_1 == 0x07 && key_2 == 0x71) {\n decoded.accelerationX = toFixed(parseBytesToInt(input, i + 4, 2) * 0.001, 3);\n decoded.accelerationY = toFixed(parseBytesToInt(input, i + 2, 2) * 0.001, 3);\n decoded.accelerationZ = toFixed(parseBytesToInt(input, i, 2) * 0.001, 3);\n i += 6;\n }\n else if(key_1 == 0x0E && key_2 == 0x00) {\n var val = parseBytesToInt(input, i, 1);\n\t\t\t\tswitch (val){\n\t\t\t\t\tcase 0:\n\t\t\t\t\t\tdecoded.extconnector_state = \"Low(short-circuit)\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 255:\n\t\t\t\t\t\tdecoded.extconnector_state = \"High(open-circuit)\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tdecoded.extconnector_state = \"Invalid\";\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\ti += 1;\n }\n else if(key_1 == 0x0F && key_2 == 0x04) {\n decoded.extconnector_count = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key_1 == 0x12 && key_2 == 0x04) {\n decoded.extconnector_total_count = parseBytesToInt(input, i, 4);\n i += 4;\n }\n else if(key_1 == 0x11 && key_2 == 0x02) {\n decoded.extconnector_analog = toFixed(parseBytesToInt(input, i, 2) * 0.001, 3);\n i += 2;\n }\n else if(key_1 == 0x0B && key_2 == 0x67) {\n decoded.mcu_temperature = toFixed(parseBytesToInt(input, i, 2) * 0.1, 1);\n i += 2;\n }\n else if(key_1 == 0x03 && key_2 == 0x67) {\n decoded.ambient_temperature = toFixed(parseBytesToInt(input, i, 2) * 0.1, 1);\n i += 2;\n }\n else if(key_1 == 0x04 && key_2 == 0x68) {\n decoded.relative_humidity = toFixed(parseBytesToInt(input, i, 1) * 0.5, 1);\n i += 1;\n }\n else if(key_1 == 0x02 && key_2 == 0x00) {\n var val = parseBytesToInt(input, i, 1);\n \n\t\t\t\tswitch (val){\n\t\t\t\t\tcase 0:\n\t\t\t\t\t\tdecoded.light_detected = \"Dark\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 255:\n\t\t\t\t\t\tdecoded.light_detected = \"Bright\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tdecoded.light_detected = \"Invalid\";\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\ti += 1;\n }\n else if(key_1 == 0x10 && key_2 == 0x02) {\n decoded.light_intensity = parseBytesToInt(input, i, 1);\n\t\t\t\t\n\t\t\t\ti += 1;\n }\n else if(key_1 == 0x0A && key_2 == 0x00) {\n var val = parseBytesToInt(input, i, 1);\n\t\t\t\t\n\t\t\t\tswitch (val){\n\t\t\t\t\tcase 0:\n\t\t\t\t\t\tdecoded.motion_event_state = \"None\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 255:\n\t\t\t\t\t\tdecoded.motion_event_state = \"Detected\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tdecoded.motion_event_state = \"Invalid\";\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\ti += 1;\n }\n else if(key_1 == 0x0D && key_2 == 0x04) {\n decoded.motion_event_count = parseBytesToInt(input, i, 2);\n\t\t\t\t\n\t\t\t\ti += 2;\n }\n }\n }\n else if(fPort == 0x05) {\n var key_1 = input[i++] & 0xff;\n var key_2 = input[i++] & 0xff;\n \n if(key_1 == 0x40 && key_2 == 0x06) {\n var val = input[i + 5];\n\t\t\tswitch (val){\n\t\t\t\tcase 1:\n\t\t\t\t\tdecoded_data.reset_diagnostics_reset_reason = \"Push-button reset\";\n\t\t\t\t\tbreak;\n\t\t\t\tcase 2:\n\t\t\t\t\tdecoded_data.reset_diagnostics_reset_reason = \"DL command rest\";\n\t\t\t\t\tbreak;\n\t\t\t\tcase 4:\n\t\t\t\t\tdecoded_data.reset_diagnostics_reset_reason = \"Independent watchdog reset\";\n\t\t\t\t\tbreak;\n\t\t\t\tcase 8:\n\t\t\t\t\tdecoded_data.reset_diagnostics_reset_reason = \"Power loss reset\";\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\tdecoded_data.reset_diagnostics_reset_reason = \"Invalid\";\n\t\t\t}\n\t\t\tdecoded_data.reset_diagnostics_power_loss_reset_count = input[i + 3];\n\t\t\tdecoded_data.reset_diagnostics_watchdog_reset_count = input[i + 2];\n\t\t\tdecoded_data.reset_diagnostics_dl_reset_count = input[i + 1];\n\t\t\tdecoded_data.reset_diagnostics_button_reset_count = input[i];\n }\n }\n else if (fPort == 100) {\n for(var i = 0; i < input.length -1; ) {\n var key = input[i++] & 0xff;\n \n if(key == 0x00) {\n output.attributes.eui = bytesToHex(java.util.Arrays.copyRange(input, i, i + 8));\n i += 8;\n }\n else if(key == 0x01) {\n output.attributes.app_eui = bytesToHex(java.util.Arrays.copyRange(input, i, i + 8));\n\t\t\t\ti += 8;\n }\n else if (key == 0x02) {\n output.attributes.app_key = bytesToHex(java.util.Arrays.copyRange(input, i, i + 16));\n i += 16;\n }\n else if (key == 0x03) {\n output.attributes.devAddr = bytesToHex(java.util.Arrays.copyRange(input, i, i + 4));\n i += 4;\n }\n else if(key == 0x04) {\n output.attributes.network_session_key = bytesToHex(java.util.Arrays.copyRange(input, i, i + 16));\n i += 16;\n }\n else if(key == 0x05) {\n output.attributes.app_session_key = bytesToHex(java.util.Arrays.copyRange(input, i, i + 16));\n i += 16;\n }\n else if(key == 0x10) {\n var val = (((input[i] << 8) | input[i + 1]) >> 15) & 1;\n switch (val){\n\t\t\t\t\tcase 0:\n\t\t\t\t\t\toutput.attributes.loramac_join_mode = \"ABP\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 1:\n\t\t\t\t\t\toutput.attributes.loramac_join_mode = \"OTAA\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\toutput.attributes.loramac_join_mode = \"Invalid\";\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\ti += 1;\n }\n else if (key == 0x11) {\n\t\t\t\tvar val = (((input[i] << 8) | input[i + 1]) >> 3) & 1;\n\t\t\t\toutput.attributes.adr = getEnableStatus(val);\n\t\t\t\t\n\t\t\t\tvar val = (((input[i] << 8) | input[i + 1]) >> 2) & 1;\n\t\t\t\toutput.attributes.duty_cycle = getEnableStatus(val);\n\t\t\t\t\n\t\t\t\tvar val = (((input[i] << 8) | input[i + 1]) >> 1) & 1;\n\t\t\t\t\n\t\t\t\tswitch (val) {\n\t\t\t\t\tcase 0:\n\t\t\t\t\t\toutput.attributes.sync_word = \"Private\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 1:\n\t\t\t\t\t\toutput.attributes.sync_word = \"Public\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\toutput.attributes.sync_word = \"Invalid\";\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tvar val = ((input[i] << 8) | input[i + 1]) & 1;\n\t\t\t\t\n\t\t\t\tswitch (val){\n\t\t\t\t\tcase 0:\n\t\t\t\t\t\toutput.attributes.confirm_mode = \"Unconfirmed\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 1:\n\t\t\t\t\t\toutput.attributes.confirm_mode = \"Confirmed\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t output.attributes.confirm_mode = \"Invalid\";\n\t\t\t\t}\n\t\t\t\ti += 2;\n }\n else if (key == 0x12) {\n output.attributes.dr_number = (((input[i] << 8) | input[i + 1]) >> 8) & 0xF;\n output.attributes.tx_power_number = ((input[i] << 8) | input[i + 1]) & 0xF;\n \n i +=2;\n }\n else if (key == 0x13) {\n output.attributes.frequency = (((input[i] << 32) | (input[i + 1] << 24) | (input[i + 2] << 16) | (input[i + 3] << 8) | input[i + 4]) >> 8) & 0xFFFFFFFF;\n output.attributes.dr_number_rx2 = input[i + 4] & 0xFF;\n \n i += 5;\n }\n else if(key == 0x19) {\n output.attributes.netid_msb = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x1A) {\n output.attributes.loramac_net_id_lsb = parseBytesToInt(input, i, 2);\n\t\t\t\ti += 2;\n }\n else if (key == 0x20) {\n output.attributes.seconds_per_core_tick = parseBytesToInt(input, i, 4);\n i += 4;\n }\n else if(key == 0x21) {\n output.attributes.tick_per_battery = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x22) {\n output.attributes.tick_per_ambient_temperature = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x23) {\n output.attributes.tick_per_relative_humidity = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x24) {\n output.attributes.tick_per_reed_switch = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x25) {\n output.attributes.tick_per_light = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x26) {\n output.attributes.tick_per_accelerometer = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x27) {\n output.attributes.tick_per_mcu_temperature = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x28) {\n output.attributes.tick_per_pir = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x29) {\n output.attributes.tick_per_external_connector = parseBytesToInt(input, i, 2);\n \n i += 2;\n }\n else if(key == 0x2A) {\n var bit0 = (input[i] >> 0) & 1;\n var bit1 = (input[i] >> 1) & 1;\n \n output.attributes.mode.rising_edge_enabled = getEnableStatus(bit0);\n output.attributes.mode.falling_edge_enabled = getEnableStatus(bit1);\n \n i += 1;\n }\n else if(key == 0x2B) {\n\t\t\t\toutput.attributes.reed_switch_count_threshold = parseBytesToInt(input, i, 2);\n\t\t\t\ti += 2;\n }\n else if(key == 0x2C) {\n var bit0 = (input[i] >> 0) & 1;\n var bit1 = (input[i] >> 1) & 1;\n \n output.attributes.reed_values_to_transmit_report_state_enabled = getOnOffStatus(bit0);\n output.attributes.reed_values_to_transmit_report_count_enabled = getOnOffStatus(bit1);\n \n i += 1;\n }\n else if(key == 0x2D) {\n var bit0 = (input[i] >> 0) & 1;\n var bit1 = (input[i] >> 1) & 1;\n var bit7 = (input[i] >> 7) & 1;\n \n output.attributes.external_mode_rising_edge_enabled_ex = getOnOffStatus(bit0);\n output.attributes.external_mode_falling_edge_enabled_ex = getOnOffStatus(bit1);\n \n switch (bit7){\n\t\t\t\t\tcase 0:\n\t\t\t\t\t\toutput.attributes.mode = \"Digital\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 1:\n\t\t\t\t\t output.attributes.mode = \"Analog\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\toutput.attributes.mode = \"Invalid\";\n\t\t\t\t}\n\t\t\t\t\n i += 1;\n }\n else if(key == 0x2E) {\n output.attributes.external_connector_count_threshold = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x2F) {\n var bit0 = (input[i] >> 0) & 1;\n var bit1 = (input[i] >> 1) & 1;\n var bit4 = (input[i] >> 4) & 1;\n \n output.attributes.external_values_to_transmit.report_state_enabled_ex = getOnOffStatus(bit0);\n output.attributes.external_values_to_transmit.report_count_enabled_ex = getOnOffStatus(bit1);\n output.attributes.external_values_to_transmit.count_type = bit4;\n i += 1;\n }\n else if(key == 0x30) {\n output.attributes.impact_event_threshold = toFixed(parseBytesToInt(input, i, 2) * 0x001, 3);\n i += 2;\n }\n else if(key == 0x31) {\n output.attributes.acceleration_event_threshold = toFixed(parseBytesToInt(input, i, 2) * 0.001, 3);\n i += 2;\n }\n else if(key == 0x32) {\n var bit0 = (input[i] >> 0) & 1;\n output.attributes.values_to_transmit.report_periodic_alarm_enabled = getOnOffStatus(bit0);\n \n var bit1 = (input[i] >> 1) & 1;\n output.attributes.values_to_transmit.report_periodic_magnitude_enabled = getOnOffStatus(bit1);\n \n var bit2 = (input[i] >> 2) & 1;\n output.attributes.values_to_transmit.report_periodic_vector_enabled = getOnOffStatus(bit2);\n \n var bit4 = (input[i] >> 4) & 1;\n output.attributes.values_to_transmit.report_event_magnitude_enabled = getOnOffStatus(bit4);\n \n var bit5 = (input[i] >> 5) & 1;\n output.attributes.values_to_transmit.report_event_vector_enabled = getOnOffStatus(bit5);\n \n i += 1;\n }\n else if(key == 0x33) {\n output.attributes.acceleration_impact_grace_period = parseBytesToInt(input, i, 2);\n\t\t\t\t\n\t\t\t\ti += 2;\n }\n else if (key == 0x34) {\n var bit0 = (input[i] >> 0) & 1;\n output.attributes.acceleration_mode.impact_threshold_enabled = getEnableStatus(bit0);\n \n var bit1 = (input[i] >> 1) & 1;\n\t\t\t\toutput.attributes.acceleration_mode.acceleration_threshold_enabled = getEnableStatus(bit1);\n\t\t\t\t\n\t\t\t\tvar bit4 = (input[i] >> 4) & 1;\n\t\t\t\toutput.attributes.acceleration_mode.xaxis_enabled = getEnableStatus(bit4);\n\t\t\t\t\n\t\t\t\tvar bit5 = (input[i] >> 5) & 1;\n\t\t\t\toutput.attributes.acceleration_mode.yaxis_enabled = getEnableStatus(bit5);\n\t\t\t\t\n\t\t\t\tvar bit6 = (input[i] >> 6) & 1;\n\t\t\t\toutput.attributes.acceleration_mode.zaxis_enabled = getEnableStatus(bit6);\n\t\t\t\t\n\t\t\t\tvar bit7 = (input[i] >> 7) & 1;\n\t\t\t\toutput.attributes.acceleration_mode.poweron = getOnOffStatus(bit7);\n\t\t\t\t\n\t\t\t\ti += 1;\n }\n else if (key == 0x35) {\n var val = (input[i] >> 1) & 0x03;\n\t\t\t\t\n\t\t\t\tswitch (val) {\n\t\t\t\t\tcase 1:\n\t\t\t\t\t\toutput.attributes.sensitivity_accelerometer_sample_rate = \"1 Hz\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 2:\n\t\t\t\t\t\toutput.attributes.sensitivity_accelerometer_sample_rate = \"10 Hz\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 3:\n\t\t\t\t\t\toutput.attributes.sensitivity_accelerometer_sample_rate = \"25 Hz\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 4:\n\t\t\t\t\t\toutput.attributes.sensitivity_accelerometer_sample_rate = \"50 Hz\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 5:\n\t\t\t\t\t\toutput.attributes.sensitivity_accelerometer_sample_rate = \"100 Hz\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 6:\n\t\t\t\t\t\toutput.attributes.sensitivity_accelerometer_sample_rate = \"200 Hz\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 7:\n\t\t\t\t\t\toutput.attributes.sensitivity_accelerometer_sample_rate = \"400 Hz\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\toutput.attributes.sensitivity_accelerometer_sample_rate = \"Invalid\";\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tvar val = (arg >> 4) & 0x03;\n\t\t\t\tswitch (val) {\n\t\t\t\t\tcase 0:\n\t\t\t\t\t\toutput.attributes.sensitivity_accelerometer_measurement_range = \"±2 g\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 1:\n\t\t\t\t\t\toutput.attributes.sensitivity_accelerometer_measurement_range = \"±4 g\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 2:\n\t\t\t\t\t\toutput.attributes.sensitivity_accelerometer_measurement_range = \"±8 g\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 3:\n\t\t\t\t\t\toutput.attributes.sensitivity_accelerometer_measurement_range = \"±16 g\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\toutput.attributes.sensitivity_accelerometer_measurement_range = \"Invalid\";\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\ti += 1;\n }\n else if (key == 0x36) {\n output.attributes.impact_alarm_grace_period = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if (key == 0x37) {\n output.attributes.impact_alarm_threshold_count = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if (key == 0x38) {\n output.attributes.impact_alarm_threshold_period = parseBytesToInt(input, i, 2);\n \n i += 2;\n }\n else if (key == 0x39) {\n output.attributes.temperature_relative_humidity_sample_period_idle = parseBytesToInt(input, i, 4);\n \n i += 4;\n }\n else if (key == 0x3A) {\n output.attributes.temperature_relative_humidity_sample_period_active = parseBytesToInt(input, i, 4);\n \n i += 4;\n }\n else if (key == 0x3B) {\n output.attributes.temperature_threshold_low_temp_threshold = parseBytesToInt(input, i, 1);\n output.attributes.temperature_threshold_high_temp_threshold = parseBytesToInt(input, i + 1, 1);\n \n i += 2;\n }\n else if (key == 0x3C) {\n var bit0 = (input[i] >> 0) & 1;\n output.attributes.ambient_temperature_threshold_enabled = getEnableStatus(bit0);\n \n i += 1;\n }\n else if (key == 0x3D) {\n output.attributes.rh_threshold.low_rh_threshold = parseBytesToInt(input, i, 1);\n output.attributes.rh_threshold.high_rh_threshold = parseBytesToInt(input, i + 1, 1);\n \n i += 2;\n }\n else if (key == 0x3E) {\n var bit0 = (input[i] >> 0) & 1;\n output.attributes.relative_humidity_threshold_enabled =getEnableStatus(bit0);\n \n i += 1;\n }\n else if (key == 0x40) {\n output.attributes.mcu_temperature_sample_period_idle = parseBytesToInt(input, i, 4);\n i += 4;\n }\n else if (key == 0x41) {\n output.attributes.mcu_temperature_sample_period_active = parseBytesToInt(input, i, 4);\n i += 4;\n }\n else if (key == 0x42) {\n output.attributes.mcu_temp_threshold_high_mcu_temp_threshold = input[i + 1];\n output.attributes.mcu_temp_threshold_low_mcu_temp_threshold = input[i];\n i += 4;\n }\n else if (key == 0x43) {\n var val = input[i] & 1;\n output.attributes.mcu_temperature_threshold_enabled = getEnableStatus(val);\n\n\t\t\t\ti += 2;\n }\n else if (key == 0x44) {\n output.attributes.analog_sample_period_idle = parseBytesToInt(input, i, 4);\n \n i += 4;\n }\n else if (key == 0x45) {\n output.attributes.analog_sample_period_active = parseBytesToInt(input, i, 4);\n \n i += 4;\n }\n else if(key == 0x46) {\n output.attributes.analog_threshold_high_analog_threshold = toFixed(parseBytesToInt(input, i + 2, 2) * 0.001, 3);\n\t\t\t\toutput.attributes.analog_threshold_low_analog_threshold = toFixed(parseBytesToInt(input, i, 2) * 0.001, 3);\n\t\t\t\ti += 4;\n }\n else if (key == 0x4A) {\n var bit0 = (input[i] >> 0) & 1;\n output.attributes.analog_input_threshold_enabled = getEnableStatus(bit0);\n \n i +=1;\n }\n else if (key == 0x47) {\n output.attributes.light_sample_period = parseBytesToInt(input, i, 4);\n \n i += 4;\n }\n else if (key == 0x48 ) {\n var val = (input[i] >> 7) & 1;\n output.attributes.light_thresholds.threshold_enabled = getEnableStatus(val);\n output.attributes.light_thresholds.threshold = input[i] & 0x3F;\n \n i += 1;\n }\n else if (key == 0x49) {\n var bit0 = (input[i] >> 0) & 1;\n output.attributes.light_values_to_transmit.state_reported = getEnableStatus(bit0);\n \n var bit1 = (input[i] >> 1) & 1;\n output.attributes.light_values_to_transmit.intensity_reported = getEnableStatus(bit1);\n \n i +=1;\n }\n else if (key == 0x50) {\n output.attributes.pir_grace_period = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if (key == 0x51) {\n output.attributes.pir_threshold = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if (key == 0x52) {\n output.attributes.pir_threshold_period = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if (key == 0x53) {\n var bit7 = (input[i] >> 7) & 1;\n output.attributes.pir_mode.motion_count_reported = getEnableStatus(bit7);\n \n var bit6 = (input[i] >> pir_mode) & 1;\n output.attributes.pir_mode.motion_state_reported = getEnableStatus(bit6);\n \n var bit1 = (input[i] >> 1) & 1;\n output.attributes.pir_mode.event_transmission_enabled = getEnableStatus(bit1);\n \n var bit0 = (input[i] >> 0) & 1;\n output.attributes.pir_mode.transducer_enabled = getEnableStatus(bit0);\n \n i += 1;\n }\n else if (key == 0x54) {\n output.attributes.pir_mode.motion_count_reported = input[i + 1];\n output.attributes.pir_mode.motion_state_reported = input[i];\n \n i += 1;\n }\n else if (key == 0x6F) {\n var val = (input[i] >> 0) & 1;\n \n switch (val){\n\t\t\t\t\tcase 0:\n\t\t\t\t\t\toutput.attributes_resp_to_dl_command_format = \"Invalid-write response format\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 1:\n\t\t\t\t\t\toutput.attributes_resp_to_dl_command_format = \"4-byte CRC\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\toutput.attributes_resp_to_dl_command_format = \"Invalid\";\n\t\t\t\t}\n \n i += 1;\n }\n else if (key == 0x71) {\n output.attributes.app_major_version = input[i + 6];\n\t\t\t\toutput.attributes.app_minor_version = input[i + 5];\n\t\t\t\toutput.attributes.app_revision = input[i + 4];\n\t\t\t\toutput.attributes.loramac_major_version = input[i + 3];\n\t\t\t\toutput.attributes.loramac_minor_version = input[i + 2];\n\t\t\t\toutput.attributes.loramac_revision = input[i + 1];\n\t\t\t\tvar val = input[i];\n\t\t\t\tswitch (val){\n\t\t\t\t\tcase 0:\n\t\t\t\t\t\toutput.attributes.region = \"EU868\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 1:\n\t\t\t\t\t\toutput.attributes.region = \"US915\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 2:\n\t\t\t\t\t\toutput.attributes.region = \"AS923\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 3:\n\t\t\t\t\t\toutput.attributes.region = \"AU915\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 4:\n\t\t\t\t\t\toutput.attributes.region = \"IN865\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 6:\n\t\t\t\t\t\toutput.attributes.region = \"KR920\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 7:\n\t\t\t\t\t\toutput.attributes.region = \"RU864\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\toutput.attributes.region = \"Invalid\";\n\t\t\t\t}\n\t\t\t\ti += 7;\n }\n }\n }\n else if (fPort == 101) {\n var size = input.length;\n var responses = [];\n \n var index = 0;\n while (index < size) {\n var downlinkFcnt = input[index++] & 0xFF; \n var numInvalidWrites = input[index++] & 0xFF; \n \n if (numInvalidWrites > 0) {\n var invalidRegisters = [];\n for (var i = 0; i < numInvalidWrites; i++) {\n invalidRegisters.add(String.format(\"0x%02X\", input[index + i]));\n }\n index += numInvalidWrites;\n \n responses.add(String.format(\n \"%d Invalid write command(s) from DL:%d for register(s): %s\",\n numInvalidWrites, downlinkFcnt, String.join(\", \", invalidRegisters)\n ));\n } else {\n responses.add(String.format(\"All write commands from DL:%d were successful\", downlinkFcnt));\n }\n }\n \n decoded.response = responses;\n }\n \n output.telemetry = [{\n ts: timestamp,\n values: decoded\n }];\n \n // --- Decoding code --- //\n return output;\n}\n\n\n// --- attributes and telemetry objects ---\nvar telemetry = [];\nvar attributes = {};\n// --- attributes and telemetry objects ---\n\n// --- Timestamp parsing\nvar dateString = data.uplink_message.received_at;\n// If data is simulated or device doesn't send his own date string - we will use date from upcoming message, set by network server\nif ((data.simulated != null && data.simulated) || dateString == null) {\n dateString = data.received_at;\n}\ntimestamp = parseDateToTimestamp(dateString);\n// --- Timestamp parsing\n\n// Message parsing\n// To avoid paths in the decoded objects we passing false value to function as \"pathInKey\" argument.\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.\n\n// Passing incoming bytes to decodeFrmPayload function, to get custom decoding\nvar customDecoding = {};\nif (data.uplink_message.get(\"frm_payload\") != null) {\n customDecoding = decodeFrmPayload(base64ToBytes(data.uplink_message.frm_payload));\n}\n\n// Collecting data to result\nif (customDecoding.?telemetry.size() > 0) {\n if (customDecoding.telemetry instanceof java.util.ArrayList) {\n foreach(telemetryObj: customDecoding.telemetry) {\n if (telemetryObj.ts != null && telemetryObj.values != null) {\n telemetry.add(telemetryObj);\n }\n }\n } else {\n telemetry.putAll(customDecoding.telemetry);\n }\n}\n\nif (customDecoding.?attributes.size() > 0) {\n attributes.putAll(customDecoding.attributes);\n}\n\n// You can add some keys manually to attributes or telemetry\nvar applicationId = data.end_device_ids.?application_ids.?application_id;\nvar devAddr = data.end_device_ids.?dev_addr;\nvar spreadingFactor = data.uplink_message.?settings.?data_rate.?lora.?spreading_factor;\nvar codeRate = data.uplink_message.?settings.?data_rate.?lora.?coding_rate;\nvar tenantId = data.uplink_message.?network_ids.?tenant_id;\nattributes.eui = data.end_device_ids.dev_eui;\nattributes.fPort = data.uplink_message.f_port;\nattributes.applicationId = applicationId;\nattributes.devAddr = devAddr;\nattributes.spreadingFactor = spreadingFactor;\nattributes.codeRate = codeRate;\nattributes.tenantId = tenantId;\nattributes.device_id = data.end_device_ids.?device_id;\nattributes.join_eui = data.end_device_ids.?join_eui;\nattributes.net_id = data.uplink_message.?network_ids.?net_id;\nattributes.cluster_id = data.uplink_message.?network_ids.?cluster_id;\nattributes.cluster_adress = data.uplink_message.?network_ids.?cluster_address;\nattributes.bandwidth = data.uplink_message.?settings.?data_rate.?lora.?bandwidth;\nattributes.frequency = data.uplink_message.?settings.?frequency;\n\n\nvar gatewayInfo = getGatewayInfo();\nvar addDataToTelemetry = {};\naddDataToTelemetry.snr = gatewayInfo.snr;\naddDataToTelemetry.rssi = gatewayInfo.rssi;\naddDataToTelemetry.channel = gatewayInfo.channel_index;\naddDataToTelemetry.consumed_airtime = data.uplink_message.?consumed_airtime;\naddDataToTelemetry.fCnt = data.uplink_message.?f_cnt;\n\nvar isIncludeGatewayInfo = metadata[\"includeGatewayInfo\"];\nif(isIncludeGatewayInfo == true) {\n telemetry = processTelemetryData(telemetry, addDataToTelemetry);\n}\n\nvar result = {\n deviceName: deviceName,\n deviceType: deviceType,\n// assetName: assetName,\n// assetType: assetType,\n attributes: attributes,\n telemetry: telemetry\n};\n\naddAdditionalInfoForDeviceMsg(result, customerName, groupName);\n\nreturn result;\n\n\nfunction addAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName) {\n if (customerName != null) {\n deviceInfo.customerName = customerName;\n }\n if (groupName != null) {\n deviceInfo.groupName = groupName;\n }\n}\n\nfunction parseDateToTimestamp(dateString) {\n var date = new Date(dateString);\n var timestamp = date.getTime();\n \n // If we cannot parse timestamp - we will use the current timestamp\n if (timestamp == -1) {\n timestamp = Date.now();\n }\n \n return timestamp;\n}\n\nfunction getGatewayInfo() {\n var gatewayList = data.uplink_message.?rx_metadata;\n var maxRssi = Integer.MIN_VALUE;\n var gatewayInfo = {};\n \n foreach (gateway : gatewayList) {\n if(gateway.rssi > maxRssi) {\n maxRssi = gateway.rssi;\n gatewayInfo = gateway;\n }\n }\n \n return gatewayInfo;\n}\n\nfunction processTelemetryData(telemetry, addDataToTelemetry) {\n if (telemetry.size >= 1) {\n telemetry = addDataToTelemetries(telemetry, addDataToTelemetry);\n }\n else {\n telemetry.add(addDataToTelemetry);\n }\n \n return telemetry;\n}\n\nfunction addDataToTelemetries(telemetries, addDataToTelemetry) {\n foreach(telemetry : telemetries) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[\"values\"].keys.contains(element.key)) {\n telemetry[\"values\"][element.key] = element.value;\n }\n } \n }\n \n return telemetries;\n}\n\nfunction getEnableStatus(bit) {\n var enableResult = \"Invalid\";\n \n switch (bit) {\n\t\tcase 0:\n\t\t enableResult = \"Disable\";\n\t\t\tbreak;\n\t\tcase 1:\n\t\t\tenableResult = \"Enable\";\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tenableResult = \"Invalid\";\n\t}\n \n return enableResult;\n}\n\nfunction getOnOffStatus(bit) {\n var reportResult = \"Invalid\";\n \n switch (bit) {\n case 0:\n reportResult = \"Off\";\n break;\n case 1:\n reportResult = \"On\";\n break;\n default:\n reportResult = \"Invalid\";\n }\n \n return reportResult;\n}", + "encoder": null, + "tbelEncoder": null, + "updateOnlyKeys": [ + "fPort", + "bandwidth", + "frequency", + "net_id", + "cluster_id", + "cluster_address", + "device_id", + "join_eui", + "battery", + "eui", + "channel", + "applicationId", + "devAddr", + "spreadingFactor", + "codeRate", + "tenantId" + ] + }, + "additionalInfo": { + "description": "" + }, + "edgeTemplate": false +} \ No newline at end of file diff --git a/VENDORS/Tektelic/Comfort/ThingsStackCommunity/uplink/metadata.json b/VENDORS/Tektelic/Comfort/ThingsStackCommunity/uplink/metadata.json new file mode 100644 index 00000000..0d75c374 --- /dev/null +++ b/VENDORS/Tektelic/Comfort/ThingsStackCommunity/uplink/metadata.json @@ -0,0 +1,4 @@ +{ + "integrationName": "The Things Stack Community integration", + "includeGatewayInfo": "false" +} \ No newline at end of file diff --git a/VENDORS/Tektelic/Comfort/ThingsStackCommunity/uplink/payload.json b/VENDORS/Tektelic/Comfort/ThingsStackCommunity/uplink/payload.json new file mode 100644 index 00000000..3ab1656f --- /dev/null +++ b/VENDORS/Tektelic/Comfort/ThingsStackCommunity/uplink/payload.json @@ -0,0 +1,54 @@ +{ + "end_device_ids": { + "device_id": "eui-1000000000000001", + "application_ids": { + "application_id": "application-tts-name" + }, + "dev_eui": "1000000000000001", + "join_eui": "2000000000000001", + "dev_addr": "20000001" + }, + "correlation_ids": ["as:up:01H0S7ZJQ9MQPMVY49FT3SE07M", "gs:conn:01H03BQZ9342X3Y86DJ2P704E5", "gs:up:host:01H03BQZ99EGAM52KK1300GFKN", "gs:uplink:01H0S7ZJGS6D9TJSKJN8XNTMAV", "ns:uplink:01H0S7ZJGS9KKD4HTTPKFEMWCV", "rpc:/ttn.lorawan.v3.GsNs/HandleUplink:01H0S7ZJGSF3M38ZRZVTM38DEC", "rpc:/ttn.lorawan.v3.NsAs/HandleUplink:01H0S7ZJQ8R2EH5AA269AKM8DX"], + "received_at": "2023-05-19T05:33:35.848446463Z", + "uplink_message": { + "session_key_id": "AYfqmb0pc/1uRZv9xUydgQ==", + "f_port": 10, + "f_cnt": 10335, + "frm_payload": "A2cA4QRoTQC6C54=", + "rx_metadata": [{ + "gateway_ids": { + "gateway_id": "eui-6a7e111a10000000", + "eui": "6A7E111A10000000" + }, + "time": "2023-05-19T05:33:35.608982Z", + "timestamp": 3893546133, + "rssi": -35, + "channel_rssi": -35, + "snr": 13.2, + "frequency_offset": "69", + "uplink_token": "CiIKIAoUZXVpLTZhN2UxMTFhMTAwMDAwMDASCCThJP/+9k6eEJWZy8AOGgwIr5ScowYQvNbUsQIgiMy8y6jwpwE=", + "channel_index": 3, + "received_at": "2023-05-19T05:33:35.607383681Z" + }], + "settings": { + "data_rate": { + "lora": { + "bandwidth": 125000, + "spreading_factor": 7, + "coding_rate": "4/5" + } + }, + "frequency": "867100000", + "timestamp": 3893546133, + "time": "2023-05-19T05:33:35.608982Z" + }, + "received_at": "2023-05-19T05:33:35.641841782Z", + "consumed_airtime": "0.056576s", + "network_ids": { + "net_id": "000013", + "tenant_id": "ttn", + "cluster_id": "eu1", + "cluster_address": "eu1.cloud.thethings.network" + } + } +} \ No newline at end of file diff --git a/VENDORS/Tektelic/Comfort/ThingsStackCommunity/uplink/result.json b/VENDORS/Tektelic/Comfort/ThingsStackCommunity/uplink/result.json new file mode 100644 index 00000000..389179af --- /dev/null +++ b/VENDORS/Tektelic/Comfort/ThingsStackCommunity/uplink/result.json @@ -0,0 +1,28 @@ +{ + "deviceName": "eui-1000000000000001", + "deviceType": "Comfort", + "attributes": { + "eui": "1000000000000001", + "fPort": 10, + "applicationId": "application-tts-name", + "devAddr": "20000001", + "spreadingFactor": 7, + "codeRate": "4/5", + "tenantId": "ttn", + "device_id": "eui-1000000000000001", + "join_eui": "2000000000000001", + "net_id": "000013", + "cluster_id": "eu1", + "cluster_adress": "eu1.cloud.thethings.network", + "bandwidth": 125000, + "frequency": "867100000" + }, + "telemetry": [{ + "ts": 1684474415641, + "values": { + "ambient_temperature": 22.5, + "relative_humidity": 38.5, + "battery_voltage": 2.974 + } + }] +} \ No newline at end of file diff --git a/VENDORS/Tektelic/Comfort/ThingsStackIndustries/uplink/converter.json b/VENDORS/Tektelic/Comfort/ThingsStackIndustries/uplink/converter.json new file mode 100644 index 00000000..5dff1a9c --- /dev/null +++ b/VENDORS/Tektelic/Comfort/ThingsStackIndustries/uplink/converter.json @@ -0,0 +1,40 @@ +{ + "name": "The Things Stack Industries Uplink Decoder for Comfort", + "type": "UPLINK", + "debugMode": false, + "debugSettings": { + "failuresEnabled": true, + "allEnabled": false, + "allEnabledUntil": 1733331880270 + }, + "configuration": { + "scriptLang": "TBEL", + "decoder": null, + "tbelDecoder": "var data = decodeToJson(payload);\n\nvar deviceName = data.end_device_ids.device_id;\nvar deviceType = \"Comfort\";\nvar groupName = null; // If groupName is not null - created device will be added to the entity group with such name.\nvar customerName = null; // If customerName is not null - created devices will be assigned to customer with such name. \n\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// If you want to parse incoming data somehow, you can add your code to this function.\n// input: bytes\n// expected output:\n// {\n// \"attributes\": {\"attributeKey\": \"attributeValue\"},\n// \"telemetry\": [{\"ts\": 1...1, \"values\": {\"telemetryKey\":\"telemetryValue\"}, {\"ts\": 1...2, \"values\": {\"telemetryKey\":\"telemetryValue\"}}]\n// }\n\nfunction decodeFrmPayload(input) {\n var output = { attributes: {}, telemetry: []};\n \n // --- Decoding code --- //\n var decoded = {};\n var fPort = data.uplink_message.f_port;\n if(fPort == 10) {\n for(var i = 0; i < input.length - 2; ) {\n var key_1 = input[i++] & 0xff;\n var key_2 = input[i++] & 0xff;\n \n if(key_1 == 0x00 && key_2 == 0xBA) {\n decoded.battery_voltage = toFixed(parseBytesToInt(input, i, 2) * 0.001, 3);\n i += 2;\n }\n else if(key_1 == 0x01 && key_2 == 0x00) {\n val = parseBytesToInt(input, i, 1);\n switch (val){\n\t\t\t\t\tcase 0:\n\t\t\t\t\t\tdecoded.hall_effect_state = \"Magnet Present\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 255:\n\t\t\t\t\t\tdecoded.hall_effect_state = \"Magnet Absent\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tdecoded.hall_effect_state = \"Invalid\";\n\t\t\t\t}\n \n i += 1;\n }\n else if(key_1 == 0x08 && key_2 == 0x04) {\n decoded.hall_effect_count = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key_1 == 0x0C && key_2 == 0x00) {\n var val = parseBytesToInt(input, i, 1);\n \n switch (val){\n\t\t\t\t\tcase 0:\n\t\t\t\t\t\tdecoded.impact_alarm = \"Impact Alarm Inactive\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 255:\n\t\t\t\t\t\tdecoded.impact_alarm = \"Impact Alarm Active\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tdecoded.impact_alarm = \"Invalid\";\n\t\t\t\t}\n\t\t\t\t\n i += 1;\n }\n else if(key_1 == 0x05 && key_2 == 0x02) {\n decoded.impact_magnitude = toFixed(parseBytesToInt(input, i, 2) * 0.001, 3);\n i += 2;\n }\n else if(key_1 == 0x07 && key_2 == 0x71) {\n decoded.accelerationX = toFixed(parseBytesToInt(input, i + 4, 2) * 0.001, 3);\n decoded.accelerationY = toFixed(parseBytesToInt(input, i + 2, 2) * 0.001, 3);\n decoded.accelerationZ = toFixed(parseBytesToInt(input, i, 2) * 0.001, 3);\n i += 6;\n }\n else if(key_1 == 0x0E && key_2 == 0x00) {\n var val = parseBytesToInt(input, i, 1);\n\t\t\t\tswitch (val){\n\t\t\t\t\tcase 0:\n\t\t\t\t\t\tdecoded.extconnector_state = \"Low(short-circuit)\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 255:\n\t\t\t\t\t\tdecoded.extconnector_state = \"High(open-circuit)\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tdecoded.extconnector_state = \"Invalid\";\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\ti += 1;\n }\n else if(key_1 == 0x0F && key_2 == 0x04) {\n decoded.extconnector_count = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key_1 == 0x12 && key_2 == 0x04) {\n decoded.extconnector_total_count = parseBytesToInt(input, i, 4);\n i += 4;\n }\n else if(key_1 == 0x11 && key_2 == 0x02) {\n decoded.extconnector_analog = toFixed(parseBytesToInt(input, i, 2) * 0.001, 3);\n i += 2;\n }\n else if(key_1 == 0x0B && key_2 == 0x67) {\n decoded.mcu_temperature = toFixed(parseBytesToInt(input, i, 2) * 0.1, 1);\n i += 2;\n }\n else if(key_1 == 0x03 && key_2 == 0x67) {\n decoded.ambient_temperature = toFixed(parseBytesToInt(input, i, 2) * 0.1, 1);\n i += 2;\n }\n else if(key_1 == 0x04 && key_2 == 0x68) {\n decoded.relative_humidity = toFixed(parseBytesToInt(input, i, 1) * 0.5, 1);\n i += 1;\n }\n else if(key_1 == 0x02 && key_2 == 0x00) {\n var val = parseBytesToInt(input, i, 1);\n \n\t\t\t\tswitch (val){\n\t\t\t\t\tcase 0:\n\t\t\t\t\t\tdecoded.light_detected = \"Dark\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 255:\n\t\t\t\t\t\tdecoded.light_detected = \"Bright\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tdecoded.light_detected = \"Invalid\";\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\ti += 1;\n }\n else if(key_1 == 0x10 && key_2 == 0x02) {\n decoded.light_intensity = parseBytesToInt(input, i, 1);\n\t\t\t\t\n\t\t\t\ti += 1;\n }\n else if(key_1 == 0x0A && key_2 == 0x00) {\n var val = parseBytesToInt(input, i, 1);\n\t\t\t\t\n\t\t\t\tswitch (val){\n\t\t\t\t\tcase 0:\n\t\t\t\t\t\tdecoded.motion_event_state = \"None\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 255:\n\t\t\t\t\t\tdecoded.motion_event_state = \"Detected\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tdecoded.motion_event_state = \"Invalid\";\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\ti += 1;\n }\n else if(key_1 == 0x0D && key_2 == 0x04) {\n decoded.motion_event_count = parseBytesToInt(input, i, 2);\n\t\t\t\t\n\t\t\t\ti += 2;\n }\n }\n }\n else if(fPort == 0x05) {\n var key_1 = input[i++] & 0xff;\n var key_2 = input[i++] & 0xff;\n \n if(key_1 == 0x40 && key_2 == 0x06) {\n var val = input[i + 5];\n\t\t\tswitch (val){\n\t\t\t\tcase 1:\n\t\t\t\t\tdecoded_data.reset_diagnostics_reset_reason = \"Push-button reset\";\n\t\t\t\t\tbreak;\n\t\t\t\tcase 2:\n\t\t\t\t\tdecoded_data.reset_diagnostics_reset_reason = \"DL command rest\";\n\t\t\t\t\tbreak;\n\t\t\t\tcase 4:\n\t\t\t\t\tdecoded_data.reset_diagnostics_reset_reason = \"Independent watchdog reset\";\n\t\t\t\t\tbreak;\n\t\t\t\tcase 8:\n\t\t\t\t\tdecoded_data.reset_diagnostics_reset_reason = \"Power loss reset\";\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\tdecoded_data.reset_diagnostics_reset_reason = \"Invalid\";\n\t\t\t}\n\t\t\tdecoded_data.reset_diagnostics_power_loss_reset_count = input[i + 3];\n\t\t\tdecoded_data.reset_diagnostics_watchdog_reset_count = input[i + 2];\n\t\t\tdecoded_data.reset_diagnostics_dl_reset_count = input[i + 1];\n\t\t\tdecoded_data.reset_diagnostics_button_reset_count = input[i];\n }\n }\n else if (fPort == 100) {\n for(var i = 0; i < input.length -1; ) {\n var key = input[i++] & 0xff;\n \n if(key == 0x00) {\n output.attributes.eui = bytesToHex(java.util.Arrays.copyRange(input, i, i + 8));\n i += 8;\n }\n else if(key == 0x01) {\n output.attributes.app_eui = bytesToHex(java.util.Arrays.copyRange(input, i, i + 8));\n\t\t\t\ti += 8;\n }\n else if (key == 0x02) {\n output.attributes.app_key = bytesToHex(java.util.Arrays.copyRange(input, i, i + 16));\n i += 16;\n }\n else if (key == 0x03) {\n output.attributes.devAddr = bytesToHex(java.util.Arrays.copyRange(input, i, i + 4));\n i += 4;\n }\n else if(key == 0x04) {\n output.attributes.network_session_key = bytesToHex(java.util.Arrays.copyRange(input, i, i + 16));\n i += 16;\n }\n else if(key == 0x05) {\n output.attributes.app_session_key = bytesToHex(java.util.Arrays.copyRange(input, i, i + 16));\n i += 16;\n }\n else if(key == 0x10) {\n var val = (((input[i] << 8) | input[i + 1]) >> 15) & 1;\n switch (val){\n\t\t\t\t\tcase 0:\n\t\t\t\t\t\toutput.attributes.loramac_join_mode = \"ABP\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 1:\n\t\t\t\t\t\toutput.attributes.loramac_join_mode = \"OTAA\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\toutput.attributes.loramac_join_mode = \"Invalid\";\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\ti += 1;\n }\n else if (key == 0x11) {\n\t\t\t\tvar val = (((input[i] << 8) | input[i + 1]) >> 3) & 1;\n\t\t\t\toutput.attributes.adr = getEnableStatus(val);\n\t\t\t\t\n\t\t\t\tvar val = (((input[i] << 8) | input[i + 1]) >> 2) & 1;\n\t\t\t\toutput.attributes.duty_cycle = getEnableStatus(val);\n\t\t\t\t\n\t\t\t\tvar val = (((input[i] << 8) | input[i + 1]) >> 1) & 1;\n\t\t\t\t\n\t\t\t\tswitch (val) {\n\t\t\t\t\tcase 0:\n\t\t\t\t\t\toutput.attributes.sync_word = \"Private\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 1:\n\t\t\t\t\t\toutput.attributes.sync_word = \"Public\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\toutput.attributes.sync_word = \"Invalid\";\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tvar val = ((input[i] << 8) | input[i + 1]) & 1;\n\t\t\t\t\n\t\t\t\tswitch (val){\n\t\t\t\t\tcase 0:\n\t\t\t\t\t\toutput.attributes.confirm_mode = \"Unconfirmed\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 1:\n\t\t\t\t\t\toutput.attributes.confirm_mode = \"Confirmed\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t output.attributes.confirm_mode = \"Invalid\";\n\t\t\t\t}\n\t\t\t\ti += 2;\n }\n else if (key == 0x12) {\n output.attributes.dr_number = (((input[i] << 8) | input[i + 1]) >> 8) & 0xF;\n output.attributes.tx_power_number = ((input[i] << 8) | input[i + 1]) & 0xF;\n \n i +=2;\n }\n else if (key == 0x13) {\n output.attributes.frequency = (((input[i] << 32) | (input[i + 1] << 24) | (input[i + 2] << 16) | (input[i + 3] << 8) | input[i + 4]) >> 8) & 0xFFFFFFFF;\n output.attributes.dr_number_rx2 = input[i + 4] & 0xFF;\n \n i += 5;\n }\n else if(key == 0x19) {\n output.attributes.netid_msb = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x1A) {\n output.attributes.loramac_net_id_lsb = parseBytesToInt(input, i, 2);\n\t\t\t\ti += 2;\n }\n else if (key == 0x20) {\n output.attributes.seconds_per_core_tick = parseBytesToInt(input, i, 4);\n i += 4;\n }\n else if(key == 0x21) {\n output.attributes.tick_per_battery = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x22) {\n output.attributes.tick_per_ambient_temperature = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x23) {\n output.attributes.tick_per_relative_humidity = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x24) {\n output.attributes.tick_per_reed_switch = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x25) {\n output.attributes.tick_per_light = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x26) {\n output.attributes.tick_per_accelerometer = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x27) {\n output.attributes.tick_per_mcu_temperature = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x28) {\n output.attributes.tick_per_pir = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x29) {\n output.attributes.tick_per_external_connector = parseBytesToInt(input, i, 2);\n \n i += 2;\n }\n else if(key == 0x2A) {\n var bit0 = (input[i] >> 0) & 1;\n var bit1 = (input[i] >> 1) & 1;\n \n output.attributes.mode.rising_edge_enabled = getEnableStatus(bit0);\n output.attributes.mode.falling_edge_enabled = getEnableStatus(bit1);\n \n i += 1;\n }\n else if(key == 0x2B) {\n\t\t\t\toutput.attributes.reed_switch_count_threshold = parseBytesToInt(input, i, 2);\n\t\t\t\ti += 2;\n }\n else if(key == 0x2C) {\n var bit0 = (input[i] >> 0) & 1;\n var bit1 = (input[i] >> 1) & 1;\n \n output.attributes.reed_values_to_transmit_report_state_enabled = getOnOffStatus(bit0);\n output.attributes.reed_values_to_transmit_report_count_enabled = getOnOffStatus(bit1);\n \n i += 1;\n }\n else if(key == 0x2D) {\n var bit0 = (input[i] >> 0) & 1;\n var bit1 = (input[i] >> 1) & 1;\n var bit7 = (input[i] >> 7) & 1;\n \n output.attributes.external_mode_rising_edge_enabled_ex = getOnOffStatus(bit0);\n output.attributes.external_mode_falling_edge_enabled_ex = getOnOffStatus(bit1);\n \n switch (bit7){\n\t\t\t\t\tcase 0:\n\t\t\t\t\t\toutput.attributes.mode = \"Digital\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 1:\n\t\t\t\t\t output.attributes.mode = \"Analog\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\toutput.attributes.mode = \"Invalid\";\n\t\t\t\t}\n\t\t\t\t\n i += 1;\n }\n else if(key == 0x2E) {\n output.attributes.external_connector_count_threshold = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x2F) {\n var bit0 = (input[i] >> 0) & 1;\n var bit1 = (input[i] >> 1) & 1;\n var bit4 = (input[i] >> 4) & 1;\n \n output.attributes.external_values_to_transmit.report_state_enabled_ex = getOnOffStatus(bit0);\n output.attributes.external_values_to_transmit.report_count_enabled_ex = getOnOffStatus(bit1);\n output.attributes.external_values_to_transmit.count_type = bit4;\n i += 1;\n }\n else if(key == 0x30) {\n output.attributes.impact_event_threshold = toFixed(parseBytesToInt(input, i, 2) * 0x001, 3);\n i += 2;\n }\n else if(key == 0x31) {\n output.attributes.acceleration_event_threshold = toFixed(parseBytesToInt(input, i, 2) * 0.001, 3);\n i += 2;\n }\n else if(key == 0x32) {\n var bit0 = (input[i] >> 0) & 1;\n output.attributes.values_to_transmit.report_periodic_alarm_enabled = getOnOffStatus(bit0);\n \n var bit1 = (input[i] >> 1) & 1;\n output.attributes.values_to_transmit.report_periodic_magnitude_enabled = getOnOffStatus(bit1);\n \n var bit2 = (input[i] >> 2) & 1;\n output.attributes.values_to_transmit.report_periodic_vector_enabled = getOnOffStatus(bit2);\n \n var bit4 = (input[i] >> 4) & 1;\n output.attributes.values_to_transmit.report_event_magnitude_enabled = getOnOffStatus(bit4);\n \n var bit5 = (input[i] >> 5) & 1;\n output.attributes.values_to_transmit.report_event_vector_enabled = getOnOffStatus(bit5);\n \n i += 1;\n }\n else if(key == 0x33) {\n output.attributes.acceleration_impact_grace_period = parseBytesToInt(input, i, 2);\n\t\t\t\t\n\t\t\t\ti += 2;\n }\n else if (key == 0x34) {\n var bit0 = (input[i] >> 0) & 1;\n output.attributes.acceleration_mode.impact_threshold_enabled = getEnableStatus(bit0);\n \n var bit1 = (input[i] >> 1) & 1;\n\t\t\t\toutput.attributes.acceleration_mode.acceleration_threshold_enabled = getEnableStatus(bit1);\n\t\t\t\t\n\t\t\t\tvar bit4 = (input[i] >> 4) & 1;\n\t\t\t\toutput.attributes.acceleration_mode.xaxis_enabled = getEnableStatus(bit4);\n\t\t\t\t\n\t\t\t\tvar bit5 = (input[i] >> 5) & 1;\n\t\t\t\toutput.attributes.acceleration_mode.yaxis_enabled = getEnableStatus(bit5);\n\t\t\t\t\n\t\t\t\tvar bit6 = (input[i] >> 6) & 1;\n\t\t\t\toutput.attributes.acceleration_mode.zaxis_enabled = getEnableStatus(bit6);\n\t\t\t\t\n\t\t\t\tvar bit7 = (input[i] >> 7) & 1;\n\t\t\t\toutput.attributes.acceleration_mode.poweron = getOnOffStatus(bit7);\n\t\t\t\t\n\t\t\t\ti += 1;\n }\n else if (key == 0x35) {\n var val = (input[i] >> 1) & 0x03;\n\t\t\t\t\n\t\t\t\tswitch (val) {\n\t\t\t\t\tcase 1:\n\t\t\t\t\t\toutput.attributes.sensitivity_accelerometer_sample_rate = \"1 Hz\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 2:\n\t\t\t\t\t\toutput.attributes.sensitivity_accelerometer_sample_rate = \"10 Hz\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 3:\n\t\t\t\t\t\toutput.attributes.sensitivity_accelerometer_sample_rate = \"25 Hz\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 4:\n\t\t\t\t\t\toutput.attributes.sensitivity_accelerometer_sample_rate = \"50 Hz\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 5:\n\t\t\t\t\t\toutput.attributes.sensitivity_accelerometer_sample_rate = \"100 Hz\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 6:\n\t\t\t\t\t\toutput.attributes.sensitivity_accelerometer_sample_rate = \"200 Hz\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 7:\n\t\t\t\t\t\toutput.attributes.sensitivity_accelerometer_sample_rate = \"400 Hz\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\toutput.attributes.sensitivity_accelerometer_sample_rate = \"Invalid\";\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tvar val = (arg >> 4) & 0x03;\n\t\t\t\tswitch (val) {\n\t\t\t\t\tcase 0:\n\t\t\t\t\t\toutput.attributes.sensitivity_accelerometer_measurement_range = \"±2 g\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 1:\n\t\t\t\t\t\toutput.attributes.sensitivity_accelerometer_measurement_range = \"±4 g\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 2:\n\t\t\t\t\t\toutput.attributes.sensitivity_accelerometer_measurement_range = \"±8 g\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 3:\n\t\t\t\t\t\toutput.attributes.sensitivity_accelerometer_measurement_range = \"±16 g\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\toutput.attributes.sensitivity_accelerometer_measurement_range = \"Invalid\";\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\ti += 1;\n }\n else if (key == 0x36) {\n output.attributes.impact_alarm_grace_period = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if (key == 0x37) {\n output.attributes.impact_alarm_threshold_count = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if (key == 0x38) {\n output.attributes.impact_alarm_threshold_period = parseBytesToInt(input, i, 2);\n \n i += 2;\n }\n else if (key == 0x39) {\n output.attributes.temperature_relative_humidity_sample_period_idle = parseBytesToInt(input, i, 4);\n \n i += 4;\n }\n else if (key == 0x3A) {\n output.attributes.temperature_relative_humidity_sample_period_active = parseBytesToInt(input, i, 4);\n \n i += 4;\n }\n else if (key == 0x3B) {\n output.attributes.temperature_threshold_low_temp_threshold = parseBytesToInt(input, i, 1);\n output.attributes.temperature_threshold_high_temp_threshold = parseBytesToInt(input, i + 1, 1);\n \n i += 2;\n }\n else if (key == 0x3C) {\n var bit0 = (input[i] >> 0) & 1;\n output.attributes.ambient_temperature_threshold_enabled = getEnableStatus(bit0);\n \n i += 1;\n }\n else if (key == 0x3D) {\n output.attributes.rh_threshold.low_rh_threshold = parseBytesToInt(input, i, 1);\n output.attributes.rh_threshold.high_rh_threshold = parseBytesToInt(input, i + 1, 1);\n \n i += 2;\n }\n else if (key == 0x3E) {\n var bit0 = (input[i] >> 0) & 1;\n output.attributes.relative_humidity_threshold_enabled =getEnableStatus(bit0);\n \n i += 1;\n }\n else if (key == 0x40) {\n output.attributes.mcu_temperature_sample_period_idle = parseBytesToInt(input, i, 4);\n i += 4;\n }\n else if (key == 0x41) {\n output.attributes.mcu_temperature_sample_period_active = parseBytesToInt(input, i, 4);\n i += 4;\n }\n else if (key == 0x42) {\n output.attributes.mcu_temp_threshold_high_mcu_temp_threshold = input[i + 1];\n output.attributes.mcu_temp_threshold_low_mcu_temp_threshold = input[i];\n i += 4;\n }\n else if (key == 0x43) {\n var val = input[i] & 1;\n output.attributes.mcu_temperature_threshold_enabled = getEnableStatus(val);\n\n\t\t\t\ti += 2;\n }\n else if (key == 0x44) {\n output.attributes.analog_sample_period_idle = parseBytesToInt(input, i, 4);\n \n i += 4;\n }\n else if (key == 0x45) {\n output.attributes.analog_sample_period_active = parseBytesToInt(input, i, 4);\n \n i += 4;\n }\n else if(key == 0x46) {\n output.attributes.analog_threshold_high_analog_threshold = toFixed(parseBytesToInt(input, i + 2, 2) * 0.001, 3);\n\t\t\t\toutput.attributes.analog_threshold_low_analog_threshold = toFixed(parseBytesToInt(input, i, 2) * 0.001, 3);\n\t\t\t\ti += 4;\n }\n else if (key == 0x4A) {\n var bit0 = (input[i] >> 0) & 1;\n output.attributes.analog_input_threshold_enabled = getEnableStatus(bit0);\n \n i +=1;\n }\n else if (key == 0x47) {\n output.attributes.light_sample_period = parseBytesToInt(input, i, 4);\n \n i += 4;\n }\n else if (key == 0x48 ) {\n var val = (input[i] >> 7) & 1;\n output.attributes.light_thresholds.threshold_enabled = getEnableStatus(val);\n output.attributes.light_thresholds.threshold = input[i] & 0x3F;\n \n i += 1;\n }\n else if (key == 0x49) {\n var bit0 = (input[i] >> 0) & 1;\n output.attributes.light_values_to_transmit.state_reported = getEnableStatus(bit0);\n \n var bit1 = (input[i] >> 1) & 1;\n output.attributes.light_values_to_transmit.intensity_reported = getEnableStatus(bit1);\n \n i +=1;\n }\n else if (key == 0x50) {\n output.attributes.pir_grace_period = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if (key == 0x51) {\n output.attributes.pir_threshold = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if (key == 0x52) {\n output.attributes.pir_threshold_period = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if (key == 0x53) {\n var bit7 = (input[i] >> 7) & 1;\n output.attributes.pir_mode.motion_count_reported = getEnableStatus(bit7);\n \n var bit6 = (input[i] >> pir_mode) & 1;\n output.attributes.pir_mode.motion_state_reported = getEnableStatus(bit6);\n \n var bit1 = (input[i] >> 1) & 1;\n output.attributes.pir_mode.event_transmission_enabled = getEnableStatus(bit1);\n \n var bit0 = (input[i] >> 0) & 1;\n output.attributes.pir_mode.transducer_enabled = getEnableStatus(bit0);\n \n i += 1;\n }\n else if (key == 0x54) {\n output.attributes.pir_mode.motion_count_reported = input[i + 1];\n output.attributes.pir_mode.motion_state_reported = input[i];\n \n i += 1;\n }\n else if (key == 0x6F) {\n var val = (input[i] >> 0) & 1;\n \n switch (val){\n\t\t\t\t\tcase 0:\n\t\t\t\t\t\toutput.attributes_resp_to_dl_command_format = \"Invalid-write response format\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 1:\n\t\t\t\t\t\toutput.attributes_resp_to_dl_command_format = \"4-byte CRC\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\toutput.attributes_resp_to_dl_command_format = \"Invalid\";\n\t\t\t\t}\n \n i += 1;\n }\n else if (key == 0x71) {\n output.attributes.app_major_version = input[i + 6];\n\t\t\t\toutput.attributes.app_minor_version = input[i + 5];\n\t\t\t\toutput.attributes.app_revision = input[i + 4];\n\t\t\t\toutput.attributes.loramac_major_version = input[i + 3];\n\t\t\t\toutput.attributes.loramac_minor_version = input[i + 2];\n\t\t\t\toutput.attributes.loramac_revision = input[i + 1];\n\t\t\t\tvar val = input[i];\n\t\t\t\tswitch (val){\n\t\t\t\t\tcase 0:\n\t\t\t\t\t\toutput.attributes.region = \"EU868\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 1:\n\t\t\t\t\t\toutput.attributes.region = \"US915\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 2:\n\t\t\t\t\t\toutput.attributes.region = \"AS923\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 3:\n\t\t\t\t\t\toutput.attributes.region = \"AU915\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 4:\n\t\t\t\t\t\toutput.attributes.region = \"IN865\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 6:\n\t\t\t\t\t\toutput.attributes.region = \"KR920\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 7:\n\t\t\t\t\t\toutput.attributes.region = \"RU864\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\toutput.attributes.region = \"Invalid\";\n\t\t\t\t}\n\t\t\t\ti += 7;\n }\n }\n }\n else if (fPort == 101) {\n var size = input.length;\n var responses = [];\n \n var index = 0;\n while (index < size) {\n var downlinkFcnt = input[index++] & 0xFF; \n var numInvalidWrites = input[index++] & 0xFF; \n \n if (numInvalidWrites > 0) {\n var invalidRegisters = [];\n for (var i = 0; i < numInvalidWrites; i++) {\n invalidRegisters.add(String.format(\"0x%02X\", input[index + i]));\n }\n index += numInvalidWrites;\n \n responses.add(String.format(\n \"%d Invalid write command(s) from DL:%d for register(s): %s\",\n numInvalidWrites, downlinkFcnt, String.join(\", \", invalidRegisters)\n ));\n } else {\n responses.add(String.format(\"All write commands from DL:%d were successful\", downlinkFcnt));\n }\n }\n \n decoded.response = responses;\n }\n \n output.telemetry = [{\n ts: timestamp,\n values: decoded\n }];\n\n // --- Decoding code --- //\n return output;\n}\n\n// --- attributes and telemetry objects ---\nvar telemetry = [];\nvar attributes = {};\n// --- attributes and telemetry objects ---\n\n// --- Timestamp parsing\nvar dateString = data.uplink_message.received_at;\n\nif ((data.simulated != null && data.simulated) || dateString == null) {\n dateString = data.received_at;\n}\n\ntimestamp = parseDateToTimestamp(dateString);\n// --- Timestamp parsing\n\n// Message parsing\n// To avoid paths in the decoded objects we passing false value to function as \"pathInKey\" argument.\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.\n\n// Passing incoming bytes to decodeFrmPayload function, to get custom decoding\nvar customDecoding = {};\nif (data.uplink_message.get(\"frm_payload\") != null) {\n customDecoding = decodeFrmPayload(base64ToBytes(data.uplink_message.frm_payload));\n}\n\n// Collecting data to result\nif (customDecoding.?telemetry.size() > 0) {\n if (customDecoding.telemetry instanceof java.util.ArrayList) {\n foreach(telemetryObj: customDecoding.telemetry) {\n if (telemetryObj.ts != null && telemetryObj.values != null) {\n telemetry.add(telemetryObj);\n }\n }\n } else {\n telemetry.putAll(customDecoding.telemetry);\n }\n}\n\nif (customDecoding.?attributes.size() > 0) {\n attributes.putAll(customDecoding.attributes);\n}\n\n// You can add some keys manually to attributes or telemetry\nvar applicationId = data.end_device_ids.?application_ids.?application_id;\nvar devAddr = data.end_device_ids.?dev_addr;\nvar spreadingFactor = data.uplink_message.?settings.?data_rate.?lora.?spreading_factor;\nvar codeRate = data.uplink_message.?settings.?data_rate.?lora.?coding_rate;\nvar tenantId = data.uplink_message.?network_ids.?tenant_id;\nattributes.eui = data.end_device_ids.dev_eui;\nattributes.fPort = data.uplink_message.f_port;\nattributes.applicationId = applicationId;\nattributes.devAddr = devAddr;\nattributes.spreadingFactor = spreadingFactor;\nattributes.codeRate = codeRate;\nattributes.tenantId = tenantId;\nattributes.device_id = data.end_device_ids.?device_id;\nattributes.join_eui = data.end_device_ids.?join_eui;\nattributes.net_id = data.uplink_message.?network_ids.?net_id;\nattributes.cluster_id = data.uplink_message.?network_ids.?cluster_id;\nattributes.cluster_address = data.uplink_message.?network_ids.?cluster_address;\nattributes.bandwidth = data.uplink_message.?settings.?data_rate.?lora.?bandwidth;\nattributes.frequency = data.uplink_message.?settings.?frequency;\n\nvar isIncludeGatewayInfo = metadata[\"includeGatewayInfo\"];\nif(isIncludeGatewayInfo == true) {\n var gatewayInfo = getGatewayInfo();\n var addDataToTelemetry = {};\n addDataToTelemetry.snr = gatewayInfo.snr;\n addDataToTelemetry.rssi = gatewayInfo.rssi;\n addDataToTelemetry.channel = gatewayInfo.channel_index;\n addDataToTelemetry.consumed_airtime = data.uplink_message.?consumed_airtime;\n addDataToTelemetry.fCnt = data.uplink_message.?f_cnt;\n\n telemetry = processTelemetryData(telemetry, addDataToTelemetry);\n}\n\nvar result = {\n deviceName: deviceName,\n deviceType: deviceType,\n // assetName: assetName,\n // assetType: assetType,\n attributes: attributes,\n telemetry: telemetry\n};\n\naddAdditionalInfoForDeviceMsg(result, customerName, groupName);\n\nreturn result;\n\nfunction addAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName) {\n if (customerName != null) {\n deviceInfo.customerName = customerName;\n }\n if (groupName != null) {\n deviceInfo.groupName = groupName;\n }\n}\n\nfunction parseDateToTimestamp(dateString) {\n var date = new Date(dateString);\n var timestamp = date.getTime();\n \n // If we cannot parse timestamp - we will use the current timestamp\n if (timestamp == -1) {\n timestamp = Date.now();\n }\n \n return timestamp;\n}\n\nfunction getGatewayInfo() {\n var gatewayList = data.uplink_message.?rx_metadata;\n var maxRssi = Integer. MIN_VALUE;\n var gatewayInfo = {};\n \n foreach (gateway : gatewayList) {\n if(gateway.rssi > maxRssi) {\n maxRssi = gateway.rssi;\n gatewayInfo = gateway;\n }\n }\n \n return gatewayInfo;\n}\n\nfunction processTelemetryData(telemetry, addDataToTelemetry) {\n if (telemetry.size >= 1) {\n telemetry = addDataToTelemetries(telemetry, addDataToTelemetry);\n }\n else {\n telemetry.add(addDataToTelemetry);\n }\n \n return telemetry;\n}\n\nfunction addDataToTelemetries(telemetries, addDataToTelemetry) {\n foreach(telemetry : telemetries) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[\"values\"].keys.contains(element.key)) {\n telemetry[\"values\"][element.key] = element.value;\n }\n } \n }\n \n return telemetries;\n}\n\nfunction getEnableStatus(bit) {\n var enableResult = \"Invalid\";\n \n switch (bit) {\n\t\tcase 0:\n\t\t enableResult = \"Disable\";\n\t\t\tbreak;\n\t\tcase 1:\n\t\t\tenableResult = \"Enable\";\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tenableResult = \"Invalid\";\n\t}\n \n return enableResult;\n}\n\nfunction getOnOffStatus(bit) {\n var reportResult = \"Invalid\";\n \n switch (bit) {\n case 0:\n reportResult = \"Off\";\n break;\n case 1:\n reportResult = \"On\";\n break;\n default:\n reportResult = \"Invalid\";\n }\n \n return reportResult;\n}", + "encoder": null, + "tbelEncoder": null, + "updateOnlyKeys": [ + "fPort", + "bandwidth", + "frequency", + "net_id", + "cluster_id", + "cluster_address", + "tenant_address", + "device_id", + "join_eui", + "eui", + "channel", + "devAddr", + "spreadingFactor", + "codeRate", + "tenantId", + "applicationId", + "battery" + ] + }, + "additionalInfo": { + "description": "" + }, + "edgeTemplate": false +} \ No newline at end of file diff --git a/VENDORS/Tektelic/Comfort/ThingsStackIndustries/uplink/metadata.json b/VENDORS/Tektelic/Comfort/ThingsStackIndustries/uplink/metadata.json new file mode 100644 index 00000000..23f54b34 --- /dev/null +++ b/VENDORS/Tektelic/Comfort/ThingsStackIndustries/uplink/metadata.json @@ -0,0 +1,4 @@ +{ + "integrationName": "ChirpStack integration", + "includeGatewayInfo": "false" +} \ No newline at end of file diff --git a/VENDORS/Tektelic/Comfort/ThingsStackIndustries/uplink/payload.json b/VENDORS/Tektelic/Comfort/ThingsStackIndustries/uplink/payload.json new file mode 100644 index 00000000..6ccf662e --- /dev/null +++ b/VENDORS/Tektelic/Comfort/ThingsStackIndustries/uplink/payload.json @@ -0,0 +1,77 @@ +{ + "end_device_ids": { + "device_id": "eui-1000000000000001", + "application_ids": { + "application_id": "application-tti-name" + }, + "dev_eui": "1000000000000001", + "join_eui": "2000000000000001", + "dev_addr": "20000001" + }, + "correlation_ids": ["as:up:01H0PZDGB1NW6NAPD815NGHPF6", "gs:conn:01H0FJRSXSYT7VKNYXJ89F95XT", "gs:up:host:01H0FJRSY3MZMGPPFBQ4FZV4T8", "gs:uplink:01H0PZDG4HHGFRTXRTXD4PFTH7", "ns:uplink:01H0PZDG4JZ3BM0K6J89EQK1J7", "rpc:/ttn.lorawan.v3.GsNs/HandleUplink:01H0PZDG4J02F85RYFPCNSNXCR", "rpc:/ttn.lorawan.v3.NsAs/HandleUplink:01H0PZDGB081PMP806BJHNHX1A"], + "received_at": "2023-05-18T08:25:26.112483370Z", + "uplink_message": { + "session_key_id": "AYfg8rhha5n+FWx0ZaAprA==", + "f_port": 10, + "f_cnt": 5017, + "frm_payload": "A2cA4QRoTQC6C54=", + "rx_metadata": [{ + "gateway_ids": { + "gateway_id": "eui-6A7E111A10000000", + "eui": "6A7E111A10000000" + }, + "time": "2023-05-18T08:25:25.885310Z", + "timestamp": 818273765, + "rssi": -24, + "channel_rssi": -24, + "snr": 12, + "frequency_offset": "671", + "uplink_token": "CiIKIAoUZXVpLTZBN0UxMTFBMTAwMDAwMDASCCThJP/+9k6eEOW7l4YDGgwI9cGXowYQ5KPhrwMgiI2rp+jpOA=", + "channel_index": 2, + "received_at": "2023-05-18T08:25:25.869324983Z" + }, { + "gateway_ids": { + "gateway_id": "packetbroker" + }, + "packet_broker": { + "message_id": "01H0PZDG4MF9AYSMNY44MAVTDH", + "forwarder_net_id": "000013", + "forwarder_tenant_id": "ttn", + "forwarder_cluster_id": "eu1.cloud.thethings.network", + "forwarder_gateway_eui": "6A7E111A10000000", + "forwarder_gateway_id": "eui-6a7e111a10000000", + "home_network_net_id": "000013", + "home_network_tenant_id": "tenant", + "home_network_cluster_id": "eu1.cloud.thethings.industries" + }, + "time": "2023-05-18T08:25:25.885310Z", + "rssi": -24, + "channel_rssi": -24, + "snr": 12, + "frequency_offset": "671", + "uplink_token": "eyJnIjoiWlhsS2FHSkhZMmxQYVVwQ1RWUkpORkl3VGs1VE1XTnBURU5LYkdKdFRXbFBhVXBDVFZSSk5GSXdUazVKYVhkcFlWaFphVTlwU201a01uaGhWVlJvZDFSWFVuRmlSM1JtVFcxT2RVbHBkMmxrUjBadVNXcHZhV05ZY0RKT1IyeExaREpSZVZwR1pIUmpNRXBLVlVoR2RFNVZkR3BWVTBvNUxua3paVVJTWVRaM1lXOU1kbTQwVm5sdmIyWmlPWGN1ZUhCZmVrcElaa3hIWlZadGRVUlFVeTVuYlRaVlZXRXdkakpHV0VKMGJUUjZaMjVXUkVoeGVHRjRaMlJKTlVkS1VsbERhemc1VDNCbk5rVk1iM1JDUkVZM1VWbHdZbEJDTkdOblNqWjBlbkphYUV4MFRVMHhZMVZFTTFac01XdExURUo0YURaMFExTnhhMVJsWWw4eE5FdHlVVXcyZUhsRWFFbEhlakJITXpoTE0xaFdlRzR5VUVjMk4wNUViME5WTkhoTmRrazFZVk5oWkUwd2FXVnFjR294VGtoMFduZHlZMDFxVlVGNmRsbERUazlNY2s5eFdVeFpWMk5XTG1WVFFYVkpNVkptT1U5NWRqUTNhSEoxTUZoalYxRT0iLCJhIjp7ImZuaWQiOiIwMDAwMTMiLCJmdGlkIjoidHRuIiwiZmNpZCI6ImV1MS5jbG91ZC50aGV0aGluZ3MubmV0d29yayJ9fQ==", + "received_at": "2023-05-18T08:25:25.906038642Z" + }], + "settings": { + "data_rate": { + "lora": { + "bandwidth": 125000, + "spreading_factor": 7, + "coding_rate": "4/5" + } + }, + "frequency": "868500000", + "timestamp": 818273765, + "time": "2023-05-18T08:25:25.885310Z" + }, + "received_at": "2023-05-18T08:25:25.906399073Z", + "consumed_airtime": "0.097536s", + "network_ids": { + "net_id": "000013", + "tenant_id": "tenant", + "cluster_id": "eu1", + "cluster_address": "eu1.cloud.thethings.industries", + "tenant_address": "tenant.eu1.cloud.thethings.industries" + } + } +} \ No newline at end of file diff --git a/VENDORS/Tektelic/Comfort/ThingsStackIndustries/uplink/result.json b/VENDORS/Tektelic/Comfort/ThingsStackIndustries/uplink/result.json new file mode 100644 index 00000000..ea78fb66 --- /dev/null +++ b/VENDORS/Tektelic/Comfort/ThingsStackIndustries/uplink/result.json @@ -0,0 +1,28 @@ +{ + "deviceName": "eui-1000000000000001", + "deviceType": "Comfort", + "attributes": { + "eui": "1000000000000001", + "fPort": 10, + "applicationId": "application-tti-name", + "devAddr": "20000001", + "spreadingFactor": 7, + "codeRate": "4/5", + "tenantId": "tenant", + "device_id": "eui-1000000000000001", + "join_eui": "2000000000000001", + "net_id": "000013", + "cluster_id": "eu1", + "cluster_address": "eu1.cloud.thethings.industries", + "bandwidth": 125000, + "frequency": "868500000" + }, + "telemetry": [{ + "ts": 1684398325906, + "values": { + "ambient_temperature": 22.5, + "relative_humidity": 38.5, + "battery_voltage": 2.974 + } + }] +} \ No newline at end of file diff --git a/VENDORS/Tektelic/Comfort/info.json b/VENDORS/Tektelic/Comfort/info.json new file mode 100644 index 00000000..6c4489f1 --- /dev/null +++ b/VENDORS/Tektelic/Comfort/info.json @@ -0,0 +1,5 @@ +{ + "url": "https://tektelic.com/products/sensors/comfort-base-smart-room-sensor/", + "label": "Comfort: Compact and versatile smart room sensor for holistic indoor environment monitoring", + "description": "The Comfort is a versatile LoRaWAN IoT sensor in a compact form factor, ideal for monitoring and reporting temperature, humidity, light, shock and open/closed doors and windows in an indoor environment. Additional sensing features such as leak and motion detection, as well as counting pulses from an external device, are also supported with the appropriate model. " +} \ No newline at end of file diff --git a/VENDORS/Tektelic/Comfort/photo.png b/VENDORS/Tektelic/Comfort/photo.png new file mode 100644 index 0000000000000000000000000000000000000000..9c65689739d3b61f4f71d894c5ddc3cc736f6d77 GIT binary patch literal 81758 zcmeGEX*`sF*anPWc9B$)RF*eE^~X01jwARWd(ZS zb0SW{%1XRwyv(}7New@VT^kx1Nj(q=Nv7Alvu1xK_TK_rF76+&N`Ic7S>U3aGraRV zCc~?abhI%7l>*K^{1{a*$CuLA#9f&UK`m@m?O z8hl4qmhgFODW>pPT2`x}gHPh-yKH{WfPg*0fPjGTpEc>XDk>_1ZyK#Hc|GCz!}H&t z88$d`!2aOD1Mw^H2R!1GOyVU#l+ z)a@`MY)~i^i-bUG4vvmIHcevCXy`RaVBol~&*5^udCALP5nH9DrCa^|{VObMmstq3yV}yF3q;#0d!C^$TP^9GT z?(Sl)^YBsi1qGL=%`uoO*RP+n&v$mB_^xoD9Dew)0F%9QX9rJYWDM?mYKJK!9I~CJ zOk>KxD<@-YY#LD0Lqq$pLWdJsH@9?Z?yp}fb_EXPiOpR*nVK4EBysf>54FCuV1t_P z=6ae}U0qEr&dptgm6euKM8zn(aiaPZ0~eDqs;Q;L2|J&1@F}~NmKJ3~J%*P|UR+#6 znHd`&`0*(P9iuK?zD!AHV&^@LNTJk>9iU7sEs3(Do-iAAC#My=qWt`0r|LeGq0z{J z+0|1U6wDzUK7F)wPV2?TdVb&dU4G@@N#~-(uV1X}bX=!|B4099S#dau4 zOapPVNMsbt2U&?X3%>uQxXhWXF+PE!2x5-gWewZ1ZqdV7}Y!Sa!0f2rSHmYC?k$uS}O#0_OeV|(fRmnw>|LS95lM|eRnCsd?e)aM{tKWW`yz{eZ=9HE)Wmu~9) zRX6GN#Lquduhg)|Inf)JdE(+m`Zmd%uZN`{NQh-T(9=~cN>2(j&6~5UjW!sg;|D;8cW&$ZO>xG{aMDA1WysJd}~K&1Ct-BwHGV6&rV>e#;KX}-`=N%$hjuL?iIS#BYNicm zap5F6G$G-S$Df)iDpT?g*zoM^so5BbbnnfKvgBO6ICuweX^ZkOFfb?^*kLGAfg})Q z*kUHm#pvjsJEzy#)Rc5^7^CGu{c>=`rmc@J_a>YT7{WH3%VSGf-{3Lq*<4Z2>3|)) zoDAempL1?WSIRna>&QP$x^(23Jxul12@5{R!WR&f4uW-_CRDe~jlY%VMfl3x5MYO^>vJ%rM>5B2lC*x+>tO&&W-1ZF1z-KV5`2yu>X(zl(15&Y&1D@##XfN+U~{H`Jq7GOG@9D zXKe;7+a;2+MzZ!}pNPiU3%n8irRpuL!+vq!|3mzZQ=b-xv#ViUe~^etnKb6urGEYm zwpgd47YB2gFNA4ZkxBh>o^)gEQu!QY@qLoZ+)?kJk^zDEc_jAXcQM8-moq(Kq=Oh( z?n)nopv++cc>A8yfT*Kx0V!62IX{0Jy}?fBY-&~-8{gNka4Go_Kc?lT8z=THqkDOI z`B(+hR8qK?LiJy2k3!^HoCg4ZNn$TGE~OoV#q(|43rAu4?P@gn?zpw&8S8Y<5B>;L zyrmy{TRvL6dhwV@9vleO=p!T^3RwHe3}j?$>ACx95Q=gxhll?=C*55BYAs z{;NeoD2}CjIiQYzhvkE+3)WvuqLBIZo9zT5@mzo*T41FRxG5Pdz`m!wLP4u<{(f30 zR%AjmBq%7D9g1^H&nxUMq^#g(YHBU6fcHU$yVi3{OR`5`;OA=xx{a!y5A$P>RpXDb zPf?f@ULhCNVNMY{v02CdR-G<~hsp`w#05PuftwJlmXqzXcPvP;MX zVzhxdrKL7vMJX%0OY-r@iCt0kB+rdgwv(+EpIRSryOdNbCx3rqPC6)#jZGKp<5y1k zd;Jo4-}5V`-=0NLclfGm2nqDz)$WvgcV#4=2#&1!OfHKqoGtW{dGNY1j#6CIkef@BCZ@PeYzb{~N?i{JZ(Bd6BymtD%+qZQ+8 z-%{43-X49Q&VaZs1phnfZw$dHd_U^`sO9cM!+mR1XA&D`_Gt^}G+TrGf z$WkIO#|Zv4jDJPdqsI%*Mk^>cO35BLqem3PaOrfp%=sm5aS;*EZixj7)Oc`qIU~>s z+3Nj0zn?fSZ^ow@+SrJr6``Bd*^!O@(m7F|2W%dkAd3_rFoAQmO49o8PGwXd4`PGf zK$O2OIc8fN=I<>Z|1Br>iLCvA@s%72V7C0v6yEJ##*hBO=8uQes(c<6DAtdgiU`ty!wW!KiVDu=E{!J_ohn&x8+7Giw z-;bgttMyQl^dd9zbu5L2g|IdIxqpboH=rK*(s}XZXUJzK>Mx|TzpuM@u-?fBYcb77B7rE1sRla(Y$#xlT%!8%fe^edH9xndAUoxg7h!6!u{~F1)@?@k5}0#0-n2SYQpTT z9V13>EPZEia`MlbL31`LS6#)Iil+nMc%wW$o6|_PC>+6iSo-0kTO39Mj;@QzE~(ek zIHN@WRqCE*heN#s`~n|em>1FGZqZv@?6USh-QajEWpQ@kfH5Yy{~T)F|2-)ZYWvDE zsCIcLZl23OsO!Sk2)c}Ltr}J4FMS1Vddx#wkV>t>?NH%_#y$`6FOz#4f|Jko@T1ew zcKqvWL@^a@E7a&%jkemaiL>kDeFAcj)w(SV#MrY!wyTAZsMQ~Fz4my@>DH}VCT))! z?$=alI-A9~TppbpGBGwFE??u4v_956w96<0U8*4E5od--mL6(;jfbNSg3Onil%Qz> zoQ=}?b@AJsli#t)=64a2S!WtjmqnjFUi={`5N`YUY5#N`{s!k6&E$Xq)s|PH?V2;4 zRk)Kc$KZ+2Gx3wQJ zW_3O|sCrCa1h>)?GF1b^IygA#R7VdrHWc*R{?Qr6TC+T&uh-RHt)N4*vu%a%-sVwQ z>5hMN>*mcLdl6a%C2zkajQehEZI897c$lai*7YPxVIg!kLBKc;_BlNcvwNM7_s<`o zU~`p?Mg|E6iw`jcitdT?^`(uq>&e2qe?I5Ux|?@TCn zVLZsGGtuIm=xQMS^4u70=6hxR8H%KiSriBb^N=(pR)755KRev|^(#YNoyVo2`uiCJs|`&1 z&Xu>Nz5G$?9PfNLHZjqD;!s)j$43JKQHS`L9JXL5%Ba`PKoj;@ zDGSMbJJ>ws7t_OG@=xp^Dsc<7y^qmVi4_Q>E4O0)SZ0LnHD{jG^w0fxDi;gOW7e2{ zMI`rKLO7$j_`2|Zk_*9nQW%J?-DE@W0{L=7=V?I79DJJiE4S1}tLIuyW~OziO<&@O zs8mm5!)GV*bV9UT^5PVO&57uezh-a^>gK4>Sm&5a9n6nmErox-}LlZOs zs;a6q&HM)ZpFA1aXn}-LZ%Rqw)n`%c|J8XgSGN{c|MMp~#9g$6L;@voQ)iOjepxC! z=dtJ^Wq-L9qeQ|hGGd*!r#ke-N*opEf-#Y6dX&(2e^%V7PTKC_iHaFi!rjy?H7bm? zj;@4_1weBQ9x{0z^_s}}&;NBrR~aQpbS3!B1zF7nFX>wR@ef}vwiHg4b&s{-+cxeA z5^&brkftluRHe|}5*Ig9Q$g}7%v)GlsXx)woT_o3{kuD24Jz+>$ZWiqEUdPnp-eAE zr4T|M>VtXH%=?hJ^`8nXi0*H&0!8QFO+2s{-bV-))G#@FGMRfOMtwx$6YBy0ss48; zosK<|sHxyQUz%@qw9oTd;Mc-Dw`YCien7N*-7(@tl@nUyNWRXQGSm$`iu~txZ+EPd zc4Fb<7uC1um8KiiqpvGvMSR-##BDyf1+|v!>vJ0(8Y{_i&dJTCG=(DBgVkaLPU#LV z(F09{T#5>EvLPy6Z~bmcIB|DXgbV z=VGzi-nNxT*NjK~4SaqFVJ@KK60LZGWSr02@y?@?8Ar?<+4FehNg?xJ$zM*KAmv_W z;~yW9MGsG#T3VZ*T8ZkV9dm4BSOH*%Gf(O;QK|5hPZ9brE*BW2gXz+vVeN6>a=u{b zzHRiP5XX5Jp?K+p);!Hs+@RtmhVL$cw>R|TPCGcLiIsr=T<4Eb=M?q&vkPpD<74++ z-D$@|Kg1`fvBCvE4|HarnH>Ms^;HCQ-R%k_*cj0V5&C3TkcH<5bwlPLBp!<&)hed9 ztwi2>jdv#WSqTwFtgE9^4Xv#O9y~Z4o}T_034pN2>%W)tYAs$|7G{AFU8dl`iEC%@ zpGOn?x1z$`!h@>uW~XePah_i@T2ydXLz4D%O;3PBgi5hE|r@xDb5Wlym|9i~|^z6G#SKu#O(;+&|jP+F$C0Z!LdSRq3&?Xsr+rY32O3Q*HrD z)BEAB)8!_nCFTVe$+u1D>+@nMH7ht-%w4r6t1?Jf6KOR9ZpQ37Rizod%o|%TZYHEm z{a|cttm)to>Fs^A{`f`V@87qSsqU0A+*||c?KTE%!yV2aadD(2PR?qQPwdYDBDNXj zO`>K3Nk$j1-#`4F%g}|=++r$ewNjo4Cw|i!9&0?HWE6fx3+=p_9{G9e@S)Rc@{S!- z&$>D!C7^We#Oxg7=X$pkgRh~q{0Wng1z}h-#CuJ&eqb%)WNt3;8V1Gik87W&T^aL! zV`E|oIIHR4Rr9F8{d>o+YB77*ZL_ku#7gI~?(a|XR4cVc2fS>3yZ7O8ikcfiwo9}vI}18cIB!VS23cU#ji2Lg8)nye!M@egOl zuW_f}r;AKZN=fL_R6g)h&K(W*+5JgSmOkm7jXdAFK3Vm((BT?SYOFNJ$X%IjwL2cI ztvQ?z%C$kW+pe!0E-D9o@5*a?nNBxeuXN6}jw8VVA&<2B~u zk)EpuoN@;nnp2fnhpBq|qUC(r7gJen75>eSIf!pmo-?mQXuU7&5Nl8+ye1cRwvnrh z3vQ`3ogENDSHY6#%9}ZpTR}U|3k%=mSom>H|0-iV&>J5cv#a%5>PPkV^^v6s9%sNo z5iuwT)Kqz!1lqv$l9v_MX>L9Q5B1}uwr#!7!PK#4b)QtrM=>$WX<|-^L(_e}VZp0R zW|wCj&T@$RO}nmMz+j|ns2r6Nz*dg(E(=`j&5S~Z7WBzyW77v++3I7SYukdgK_}5^ z@&TIXf<1M7p?~#d$}qR(#7)&$;BBmzlLTHYF!6OV)maSsVPyI~%$@dQ3;F%6z|NC= zYgU#Zkt&mF8**-i_ipHCbOXe$yGOjQ$=(fTQ`ofqef-bS_~K__jH1ux=m7Ko48F}; z|J`Yfn;X`BBD_&4+ue`ms)r1RzUAz@nMv#`Ibts=mzth5=)5QD=xA)meMNSlqumGp zBu?xD!mzF7N3GVkh>h1ed5g&bK}TE3EM>spOi`&@V&SG~K@tAP_>q!Sc*Jbdb>&wt zbCb}12)Wo`^=)jKRxd7T%@PojQs(8R%Y4iUsI}=YAEgU`7n6|oFj!UTdsDgDku$RY0Cdw+YRbw~*C! z7xCfB97wxI)$Fo*v?Zyii#RR(a^-49tc&uKi5S1V9!E^`eg$;mf(2?raO!9wZ?Eg; zzUSVoPZ!cch`=JYY_D1J2~)5x6RAYmB(B( z(@pdFm$)W6qf*;EDV0di(^jWj0mc%#Z{*P4Sx7(gK+>rI{PBxVn!*1|RJ%0C8_kT*o5)8pt!>;X`-8)^`>?|Q)|0u zjUi@J2$ioVy#KF29Ki8FJx}(aQz-mLSG4bQ8Fz|?uw+e6RdI7wsyqIdv62-y}~nC5nn8zfl3W>L}Z`^i~U^v?bcWk5|?6ixTsNIPbOwyHQwm4(l=yDv4& zbD_mY&i5dVh+gYHazi?jQ`lk~Tx;!sbw`X8aPSst!tdkMBu;x7`=RBsgsEB+?Y^~C zO;DGiMT6%rF_H0}Xtx>T_q)HjRgYH>Qw@y|G~T?$8p$%(`1!J#{4fg&+U-q7Nmy8T zbFlzTJ*CI?E3u7~-_FEbyAcKu4wV_#ENPzX+&0m`*4&?eQ3&zjwI(uc2@b1EAU5ehSGVZ4urp1$DJ&7L1;X}d!`7BIm z*T)#X!70VpDTeDuqjk(*MD6#vcj;xlXpir<1&L5q|IT>X!IF0cV%jLm7xmaOvF2R;xRc*0m$Xv>SU@VB1Jo!nETA=RlrD^DyEEA>qC>6IRilsOb=ZTiGz3hU8i zK0%z=HTs9M*wC-PdTfzTFV9}K77}4Qj-w;GXGPm=nL?&5LJqp4ZPqJ4 zeQNI@xML_$4G;n)=bZ=0Af)n&i;MXROWfur2;RoRWLuhVqYSTem^D&wp7dCOH7v}G z3||=1biu7B=8h|!Yz^B?{ataeD1T8>zl&apO|P`^#mfnF=-b9CoNyXikMqYA8CTe$ z#Z0PkhBK4GhhiHpueW!zewkghBI@iTu0AL$gFXH9$%iYK!_ab$pUG>W=hGq5$$tE* zMWbuObwy8u?K$!ILQ#p~;_)%v4+qJk8I9k|<(_Xf)c;L7xxLeKarfh)T6-cjpuUrk zVh!XVR{IICKsgnaWO2r+r^zSaT;bvoKXyU^VzcF63`%30hB8X$~J4u;+!Jqk$!o?5{U<=YU+l2 zTm9e<9kVPI?~s*tQaZ~<3tW>!xk^L0nI3GB3D0JYT^YqANm7Mx!ruX~?n$hy10H&7 z9c|5)#U7NzR^C-lm|{>Fq<{Tg47j{O3-)!0h^p-#s`nBg-Wv}WUbO|F!Y_VG(t30J z6xMb$InuJIc~#^vGYFq(OoDyJi3g&mdWyAV^g%+uhhE!_-(D6 zobomW4T7d!);;GvN|1w5hhTbn%vW6qLzDk=z+W?BhW@4r{qY$c!>sJJfb88(npzQ) z#VjVN%?G+6b;i=qX9k63-8p-{XRoagqaN21G7UFV>l|M{6@DD*u&Sl{?HDVms8IJ= zr;-Pn0CRoJepbeXQEk)oOprcGE806GC#&JD`DRLBPJWf1UPhhRXLdv!wkD!C{==tS zcNY`2r+Hdg2T)*v6Mo{(xC|9pNDe04V@c3Vp|m~AU4Bqca9DL(yE=fBfGF172^Sgk zZLPV7kVXnLDT+|3<6k?t`zKIFPV#FX>GFjnm_U3&bOmEwWOa;@-KVaBPp<~bu@un%iiKR2TvkqbP>>Yzg zRX9($%XzMsTc2*l$|nTfl8}%M{S4C2O%c`M;o<23YCl?y$@luP*Z)XM;rArpX1lle zt+!)}M_)yJXs)LH@@9osg{eI3Yor~V9rx(p!mg?i86DD#{SLn-RT9|>?+otyBqFAF zI{!Wr^Z2njeeRwOVt0a$e?zq?L{j;)$&E}1?HhNT?99*%>$7v?g6w{qslp~S1~wCt z@pamR?UF`1>-X|OrvS>{6j@7qUT9F2W?sa9$fZ(S05$n8MszMqMu9Q_rdWr&LS%ZbOX^`H&FC4xg-2bzq#KsoVsZ)clgV zGa$nF=>V`BSuLh?u75lm4eF26vF*cT3Xk1 z6sSsyh4{%T9lZ^QG#LkAw$4h7Gd`*?f9Khq@dmaHw@ne9Rk2T)ubN!6HVyWRWdzQ& z6PSTB_1`-VdD+<&oX_lrolY;#^=S5Gt{XDEffO)>?O+9{e$EM`EG1=#ax%&aZ~kv7 z@*|ZhT+tYuUdOH;Lv!b4J8(x4h@a>Q{mkjPZ~Bv)erq{A^40lr9xK0Y#u0|scNpPb z>?+TJV;t3I9l~HLVdpMPj_l)xDWV}f4PxawT<4k_Xh1eu7;y&r;01ZQx&n%oIazKJ z1x+K1TA%$tKYlz)NJ)|R3N7cor@~1mTU2z7(kMo|E_MlkONDOJtnV%r$_5&H7IXNF zFyw3Y=3TrfE#91>mZaLmc<>sva0M`WLy~aQ@8c#n+v8muB!L4c4RPq;QBH>JpQE0C zvGOBi=O;!nnnB(pywF#6dx3eU$werdcc$&8%;M@9@ zW+x}N4NH6QVS-^jj8zs4D(qLl@Oc$(`{zI(zW@HlZ>CeNbh6pcRK|@WI@`od*1n3O z1PN`(xE+T7`YpiweP$VdK5i4F;3Rxk7K24@US^sJ@lDgSsRpk+&WMnuoS#mK+hLgu|V$daUdFV`IBTHu7sVeH`pezga+ULVZ zo;AdDY2q7cY=A1?M-Lc68>KP}sweIfq&rG3Qj8JQdqPzCVd3QF z`pLD}2pvtk;k%U?P;9sMj{?j(>}`%DB|7N7e?;JLUjv$?;psy2bevO%NRbbMh&P z0j^2(p_%Vk42yJHsaUD-ERY03gp_q}yoiMz=8uoqM*v=-J4_Yx4Fp~3%reI1V(VL} z<7J8I3cj7qbWF=FwFArB>7>2&A%`;L;8DM`{+nz1!9m0WeIzUnq&lpo*4C$Shlg%! z-iE~k#2H0ESlE1n1&BK!$)2WM*?|CtGs*XHM-8+pvUFl)t_i0hEOHP^^wu22dK)7J z8qmHj6MaFW6voeaPOr@o4G5V5AJrGJRB7mu9p?oOTl&5)x#TFUx}y9W1B2?>dXw9= zpQXB!y=0BQ4>?7gMN=>b#Cwq-vr1)#jGQ`3*w00Nog{pV@E%!`MlMB(PJ3b6_dgP9 z83(fQ;z90wW;>)UzIS=TP}^;pI021r^u|IX+NDc+BzVis0+n}`0UoS;bOo^G%B=RZ z^P@@e)9+8KeOU*PUlW3-D&9vH+r$g@Bu?7EEggWQBdWG>*0$Pn0JH`{52L>VxMN0J z|M*2g zzoZ`;r472e4AV%$`hd)RKc&I&FYZtHqG|425D_*VUKF`iK-;88=}U$wA9S|F1s|0i z9GnB!3@e^{qdrqrha48^l~4N98r^fpMtwER2<5j#4yMTSujUq{#ZPKj03MFGxpmZZ zYwM3$sr(;CdG4K*82uitYFx<-d%g>2ZquNwzHhR?i`8o|oa0@W6a^`{*&MIc);l)6 z^=0^#FEICQ!g)4=SByu8jVQ$iDt$rjocNT!89?s<7#Gsc8)!yt&>9l}Z{nzM7y01h z)?BT=jK}2dx2C09htqM5z)mT!J|V74g2kUoonZmQ6IvtT<-iUrEj4%H#VkCNxzo1s z@%U=7v~CDUD23I}@qE|jlG0QS{_rEwOv@!et$9N`ks?aKUj(B7A0#sxk0(-7kefag z_I1D*1AHT0oiNKGq;6Uf`|T9Mpi;$rW%Oq(^+tTBzV2rR70}YN?uYR6@jV1R_3a-{ z+A=AQW@1IYoxa{s>eZck~R6cXejYkQ_=2X-HWDqq53O$y4 zj4IW$wfh>9c6AbYdbU4i^`m=A*+EMsRY(-#RLJ_g24KDjLmPLzJy)e+S~92zNc<@U z%)3xL1p!A>FeyVb=7V6efJzKcCZ5k6)X~Lum8O5(ro@2M(e#-=F!B%o2>U> zXvpoL=#Aw{Z|zLQTf%#bs@HM1O&OX>6+4!;{E(+{>qH7R1s~gDvW>2h`cfmC5hfo-2EthrI5I%d4xDdQuH&b=LDwl%h}A)6t+q z7BJBV3z1Z5pyk)dCq@tpd zL>h09`$nR6#A^YM&kec+Kkm}R1GF&A&dXvoKybE{z#TZ_*Jy?Wo}Lkv4;-29K*Q{j2Sf&zBjY0uS>zFr3A%z;-bWyUn$2I)JcXt$P?ZUQ=c z9=vE;71X#QTY6LcHj z7$@P;P;D;bF((>e#-~xBm9%-S{ySU&S#SF}qYThsQTUMBw`cdPm1DlPBgjKA0J5-l zS$`6@rWqbkd?t#D7IGVyi&ju{LF`}Heh;}ohFxYg0@kI0Pr6*0W7Q>vnQq^h!Z<;d zvcFc^^;>Ywk=kfI)p+>CA`c1J{F&vW@5M8`{%JyQ&H(47@ei}~J&bS#cj}uuu)Wt! zzBKdC-Z9*`Sl9HNWL-B;XOR;DXTUc)1hNdPb)=*{sDSpEqO}JrLz&nc#k@i2ZHmn6 z0P+i5W@l%Vvo7LZoCT!M_zC?c#O0f};6HgWsBi&G91FJsp~5OL2SxZZgEoG8`5`Y{ zt^GLU3ldWA%kFL#(FZn0zpx;`UQAA0NB-P+^^BO?8Ok)!Lp(&TplcGlNcfU(ZZqdP z4^!20*M3%kIPwuI=g=6}b`o{=%&TeUi{7&K`dYIix_BOgf?#f5-dK%C`=GzExBG_R5% zNolVgFh>SP6%RT9IV|w7T)Ai{N4XrSY^`X}jP>AVQ!ZDgxfM0%izu;x1cZpwf&*2G z_Vn?KT_(PKfqC?(ZcC9_X>3WVY)_*N@|^3;ADlWGWdHy#G74ztMa9J4L~jT^iD|rc zmiARU@P!jNa|XrHtO)pW@FM~L@7~hy_s0dNkc6CK^G1U?e;m}J;-UIcu=i7U4D@!q zzGcqO0;}n1L`nwyz~s}5`}0#@S?{E3Xc^v9f3%TGk{MPDn(<2IljKs4%=l4WR~9Fz z<2&LeDi<5OTn-GPl+$-+P-f)m6ojRRFDdeK19j(QKgiCV=FXBd+egqWyzld?9q5$0 z8DC_E@0rSE9aKbgj_b}i^@$Y$gPJvZr-BS{%-K!^N?yUrRMP75W#IQm44Xoi-6j2F zatQx*@uqVgJ9nUV@a?ivnv8X=9;kn(>G|j_yIt>`d&Xz#RkA4yE zuafr&hp4a29Ai4tPcCBBb8)>+wn-{XsG;@yUXSSJ9O{82^zT>E?-08I_d2Y{$2vR$ zfz9jRi0yg>h753Sx_OF2R}U)^Kv!zV(3G2u7mqpsx2sv;IU*{y>nDMOrJULg%gR0s z{J+l+b~RW5e@E)wRr}alRM%TEmUH6t-j)15Iu;hW{N|`YA9CH+7HaYTUlV-4-5WQ2 z$;g=>6AbxDzDKK!FBDD?J~Zcfm|nbl{aBa~Clc=Bz7e-sr&r*y8Q(sxQ~+)@GZvJ^ zCwAqjE5`}<$aJTcN&ToUlIi)?NdXR&SI%N15RQ^WwB6NvlN8155JmdWMQ6AV^ApJnTIty0- z--aTt$AN)_2M)lpW7*ws&|q87!E7_!T&EZ*Z@zpHB?fr6@VU_bFbDp&seC&XMd{7l zzR9d;$0b_G+}YLdZi#%^CWVA$gCgOPg3souva1^wH`GN0O_JK*rWjYO@PWhXkdVQd zuEs>~lkd;zb5dy7bd#Or>ptaVL(DDZ8FO+Aw6%;E?RNf}?rER;8w;Majd_;kTe@?Z zcJpu&Ycqlg3mmoN%*XDW#)aw+Y#REd#(RpM_smXU^8@ODzrKXu*X5E$Q)RZLaaob0 zGDRjof6nM(kEnIrVGz2VwOXbZN1E0_JPIz*3|x?bbmCG^m1}N5vY^g7x>aG1(!IF0qgO@Xfs)h5k(+bQl%)R7f z-PKRF&~~&C1q25@nitQuP0kz}#uum3z5oU1ZE_le%Khe=IO?QsOK==NT5Y}1spqPh zlnv4Bf6<0Fypvri$oRwqS;we;n2!QE$;&{1Wgy=&{0G7@`DwQV{qQBAS)(biZaY97 z5io)EEmTkcD*NX^18P+BpIKb3<(iS7Z`c)h68Gv>k!$ST_;q9B8Vx6(BIANV+;QK5 zmPcS%ifL(XJa)xc)u14+pksLNS(h2ZzkljuAfNrzF6rWqi;Si@FGNLPS(>b0%7m|2 zCqQajv|ruhBkgkm^09w#RHYJ()0-3y`$fK9_8Jab9_AWu7;nt$=I<_)ef6E%O-%9j zjiTIsJZ)8e_cgltN-NLBV}=ud>J8Ao{8W9dm#rbUqycoqw;41z0r?Z#m)o43LyEvj z7tEZV-ky`rB{Jl77T;w?_X-c23p@Yb3V?K1($*TaemLPm3#LjUb6DXmEyL9DnY@`v zCL1_W5%?7w;~#>!bwXf)e-wD}ZrD{@RN7WwHBN+PA`Gr1h$+0d|H|ZiRlYh;pBr>I zGcxoQ54zy>4jgz@{jZtqT&q1U!6Y(L_K(K60_$x4Zt z4~N>k;)po2i9eba0S%Wfn|791v9BzKrFw3y%T3h~GF@jXo{X1SNQn#Dz&|ml9I(L6 zfOTHDsT61yQJbNF?}Zm?w@>uFjxdsELmV+@%7C3{r?wV`>M|6uTdEe8_g|kGGBmMs za>kc#!sNw5|Jk#vJP|Ys-n*cG?5su6rFjtn6mfqWyQJ~CQQ-WnLng;Nbd{>8Y`S7y z_%|*bI&^rvz=2=d`)(O&-@}E#H&Z_t_T)T~B@|ptdZdkp!<=jU7+Qp=xxh{=RVo)q zatmsFy4Mrs9sX{(YN}la8?djtcl}i95I_FZ9C#WdVIzdQ=h7&v7Hl56nvWsvXM z(l#1%0!3zj8C0Ir|23m6URL%L=D)E~(@zxT0&Iu*E&;^%T}=2Nr{f;b&>=VtIE`6Y zSc0o^b5FkMJ^GX;se*15i8mG&I(7GFfOFY*qjgv%#Qhfk7{Q=f~b8;6xt&_7#8htr=nI0;k4WIf`*LOOYCNFPdPMRN1+Cl{eUU<^nhOtThI=FfsOjSW1$rodNq*p? z&b`?yJ&DwUY2x@bd2Vjr^ayX7O%a6!?p}Y8xY+*%BIpV@2KesGi7==`yos`m_~ zs`Kt#{cDnktn~ikiu{Ovuke-tf6&?BRNt38^?x{gWJ7RuBe;{J?1pGXkJT@y!HDS& zZr&oKo+GrO7e2=D8jMqbC&fF_Nd_a0hn9_Lim9TXJwZ82s+UwTE0gXD1V_U)SKP9) z36L*jg8|aw8VoDQm6W;cYe(x%3F_mDhOk3KEy1@eBk#PrktVp@%&(G#Sl!|uBuIIE&w~v@N zpO5m7RS#-R!VlafA7zDC>J@hsuPQa)ry`Fy-qtWP!|1jtuUH8FizBnN!oE7=joIM5 zvmJiV09t49rGKJ>3yM4vyG3;ktqtAkfIeiP9q610)FOBj(F%m_)hH{+zQXJA&!ryd zLhD78O=;$3sk=)H0e9Z34}(J%MdVdOE{a$T35gp0bta)`{=_F57GU-T>^L1G2RsO58OqGKd5#y zwB`1t2|O82e|HxCKih|>3QOUGTqvv%4Ljh4m){zE88?U(2jqXoT&CG=#YoVGtSo7w zuBjUFK`YBln3DvWAdTJ&A-^XmJ7ab})Mx+QXE_5^ieh5aGR1~}9CZM*JD|r2Q21Yn zxI_!z-__8vysMU*tJ<|7f%mzw8HViR{&(H^5qBy?NYtlw|JiXsdz`(W1%zjf;9Rzb z3BpQpk+);>Af&T-Q{e#zVj;-jI*eHmY8z5T_%o8-SP_Q;j}(vLME}#?2x%VM3=68gPLpR#aI@{;0G+1;c-Zoj*fh$YH~asSHP< z>iEqYTQ33Wm{T-{4B5uq0)RU)-c~b(g~YbNv+$oE|HHQ_U2ns#uXoU0fL&@=Qv$uMXc9%C(0_T;)E$mCZ?uvsL^5<#izNp7dBeYfxl%&Ji5 z^qpoB*qz8JKA_n5jGLV~Lw&iQA4w|}A`VRTB&5CvVp#w$yQX1p1~}{pCdmNjXs+kf zPVB5;u!#4lCvMuk`(Gfaf)KXL;^W7*aS(a2e}Zv$<#30AwfS4!Yxf zL@uJ;u0M&G_va8KHs0-UO}Js}I0;g!lbB%HBLa_IKU+f@lFbjYAQStCLv!A!X9{aE z5Gw9kuwkDwPJkf;F?FoZ6&c~%v|tk0lm&bwXSzBF%wwlqR}6Y~1U8GzhBPpql4FZ- zVNa#5zXw9@Q6qJe#OcKjzBC68mgn3f~!hoM+ZmmZZQD#d_q6A>OGzPD4OOjMGz1iLp!%Tk~Qo}0)6V( zp{E|X;Da`^E(6yp(Q5>=r*TKeK~gOPeR_rWpt%L~R#ZuWoNPu&M?wflgpYDs(Ws%s20V54h+x6dF zytu=~>2(VTY30Ed(c9_>7@>oEB8o=Eh3uNqH;d^x$mAt3ubtKp3#Q64iP*= z(L+mJ-maR6Y`@#v!5mbWc~34|<<`erz`>Vs@NVxe6bUdklpufuD8O%JD_PugeI%~J zc};1mUe%ALZdzz1H;>NN{DUHbAfcurtVOWk53us$?n0qJY3nqV2ZSr*nuzQzCmt5Y~g82E1t zWbZzBc>hKmfT_~h@p4#mW$_@Yb6bNaaf`y9XN zk7`@UjV(*Q9HisAX5#i+Kg&n|4_99u*VMoNe>S?LL+P9d5~89K1Az}9rC^|v0s@M( zG}|aCX=Ng<2%-oGNHbCg(jtP?h|%3+EPls(@8f>GzyEmbAI{l%pV#YIuh-smHB;E$ zAr&_&x{eJ9*2I*1Q^Y12K7d$fgJ=StjpG-8cf_zp^$ zAk;xSXQ~_*t59#xZt9H+Ie!J+v@7F+wDK;iaEoAM!yU0QfN_(bF%`+}SK*OLU1DrI zxYAuwQIFaE(rI8V5^Lfc?ua#XJlElt zp7B_Umv`I2H|;|3z4M=axN9@eM{gcfW4RQ#&8(a&DI~oRY9-s@rO6SSQRjW))wj;_i(lZ|~%^9O_Y9a&1jr>cN3mbM-&Z-;iu87BVdWRGv8@n#*p_Zv!-h->&uzT;PYG&L^VwzfA9iC`stT)w=?AE<@Pmz zUwIP|ApV_=3o|TcNZb0kfc% znsm6kCP&IiEo$iQ_XD}|POx#DFE&TvVS|--tzl^Ldxr5|Qt%H>5sx3|p468Cb=Y)rpvR zO7bjGGJAQKVVY%^DWxE4TcS&$;l*-m*F2S`C^c zgKD>%bS)o-r`TFR5w`(q=T5YC^Z#0WRT}r$`&R)opdnyc#mHDjztjQ$WqdlHk&y-U z4kUa8lXf|@;>#La>cQ9@o4|Qc-~CrNo5%G~=lc?E{)9#eV2H;c36yPSo^q%DeC!`& z9dn374|JN7pBD{gL;cW>=4;6DBsWteKglTX)Xc486EeX)DXM|sK9qf?1M6<#R%$)oDK&(33 zH>I&8*h`3@7@bxCs7V378zoT@4cOaiRH?1wBR7l?nian6q*NbHPTw`|2)IX?z-H3YGH8-bMDdd7KWF*a2-JuZ25o7cs07=>G5;OtH}i(4hBn&BpV;_`d)6$a}*r2Q)p!Mc1bk z$1iRs??3*PSxu@BHVek%@+O;IgVN%pEAD|B+wJ#}aIn#HP61h9Vk4F8lDcV96AUmj zKzG|g==o5~$Z;@uGv|m1ZUegTf6ozF{rR(sElf$$!D2xKn50R@h>96porvs82=I1< z-7p+#+kZ38lxDa)rn$NaGd~Ck&c=iC5}44bf=eFm5@*|vt>$7M?Wt|QuIp%yS1Rrm ziXBgs9ym~r>K;30P3j_tMy}Q!Czu-9d<$)!p}ZM4IGcIqwsYcA@L{6(4rSQE4D1&E zCk#Rzif-Pjxz;szr49)fpqY*X8}ngbXvNc^i(tU)m()7wR-K3Jj7>)8vxH~y1_9;M z^mb(&p#F^5@i+vlD?~e!>T42eeh1)k@G1d1gBE+)mm!RQ3g<+fT=T@}kGmha`6ua? zbO-3(i_o-~IZilsCMX>-alIy-tBmcyE5_Kpt_)SPe@(_LR;-}~-5)IXQ6IFK-k#JQ zj?Xh-N!{C0%Q&i?JQO$PTvJ`UYuQKk5d%V@angpYWSR8+027<{; z!A!RL@FCBp>BF)H;0d@jVxKMB{HWmTbBO0*4yYl3DNXz|O#hQI;BB0`!A9hL0_Bkd z(&f{HhDgqL9~@Ihe^Wa?0tXpXvBo!Iw*+*#s7m3>zm3r9!Q}g8nE#l2B?Sc}QU4VM zty`&_pl-#(gbSn@y&-!ohbkBF!%;RJG@o8X^pij8LY3NyR>RT)T zx^pMjN8rb~g@9!#7wN)pxlhoRYn1G;mT*uL)@uRNhALETT0QMGW|T(gXGcXF_5EM| zm|emDP$T!r?^I-cJ%fJEiA4Pdz{EiJTy*xHl(eZ2n_|XuDPKyXUFP-^n6yL2gVOHi z_Xhq#Q+tGCU$kKjWicV6dKE_cyu~$Hu-TVr+?@$}(%{YuECiG+wpPs4AABAy zYmfO;Fu;?!t&4k1xPnPk>kTdovhm+^xkRsZD@|PZ#<0HUMh@m)Relsl`yGwtnfscZI9(rPn) zscqJM3BTocopg7+^l%Nwmu1R!K}iox+1z_7g~T5Cr6O5C9{AhEOJGe-9+)U}nAtfv z7z*v%eu7+3+N(Q9SCxOEcyN^OKL#0s z2h@>^N&xJ%*|k2VuYx{JM<%JZjO`W=o@dJ`1}3Mm4Bb;OU+iL=8OKtbgSxJ@DL@d)_g2)=V> zsABVN1eh3!row~4o4k{19sQM6&+C$mYvy@biz*Wpso%b*-XS-+by2{Y%-nq%4$q1Wro=1B2xWiDKKMyk<&j-{P_$NPb>pk?k*4r{%@BDmk z<`IGnMfAVv6!dyS=|>0dKE&LC_XR5AOj4ldgMWK#Z_On%muLXzm%s6&&@m+HX{h{< zO?j#^-j*525cxSK+M+`wE8%hK$^=@?piPEF+o0ulwzJI^t>JVmeDap%tYhzXc5Ih7 zgk|;LaBf04m{7}AbS-Tuy3cahvjWIcT3B7}?zENe%`8TQ=I(*I82%*}H4s~zl(C8N z>Q#NHGr=Y_>n7~qyn5L*aaj1ix3QsSDz>%%Q(|dHnl2Vf))hutXv_DjjI0emhqPT|nvpa^aP1w< zVh0yP@_f>Sa+3sJJ1EQ;-=gZXn8aM>L}Npp{O;SNpNK)~^;mPZEE)+{(#DDZuKKjB zgShB8u{TFt-2P2DojTPd&zWp#1wJ`c)BkP-p5PtOQ9>wLZe8b>L-(ItH0b( zytNE1KjiE1&tibb>r|LQ%k~EO-09BVcqUC4S-H#kYD+RQ_LADbgKTjFxbSsstx`EH z%7B6Rn;jRpsAHAhi7fihQ?WZ)HH1|pCF$t+%P1{UC+3R0m0Yq3Zc zzX++r1ZKqJ58!vV`q`-N=->Dh;>;7oUU{rSc&hic2P!P{s`-jO8eA?r{j?~-+{r}Z z$YLv<2K<8vx6HRB*TuwmLcGHThm6`|F;h^8A7i-iW&I4@lF6mmU|?Ft?!I5^*zl^v z)m+7mfyWTLvZE12>NPw1Jl?=vMj(l?ysOy^aH%Lubf~+sz=--??^Na!Gdn-G=kBiTR^-YEaJ}yiaZKjE zh9JRcHtOage?LiM8XdXUsH?y4ym05`jh(WU3_`$jKN7-o$0MZUX)Ul-^#z+Y0N;){ ziBh6_-w6^Zmf;JZz*SFdXoX1>H&(H2N<-hidqKGT;ryx2{yxr*2|gfh?_)FgNIVWI zN(_|n_xukXwt8D$0ZRUaF9OrSG#n5u-SD%3(uwDrZWg-a~H80m)-DGG6P<_D937T8C&U()M!)sORDV!**#vbe^ z`m9&5ru9SHaB_|MeGYehz*8Q4!7H7}?~Dq7JT=JU0!d)j+k{ldp)>%ERDj&8cNyFo z$B{QSw{XS(`R*<0&vF5_C8e(4>s9wT9*U~R+5+Er^7>`K#TH5Q2#Ni-I^NVs-w#2J z3RH}eXZX=vSniqx;jkyXubAc98#eKz-0M;?fDN3iJV5-(pwYMLBf9Wv(uN5YdvYmB z1=!bea^imR;^upvJn-CWk5(aAO5{)T$ZACaFcXA2Z&Uo@8-!PoJTPO5mFF4 z57vKBtJIUrNoZQx4l{9GbVUKd)On=U%uRr zpA2pP`pOC4sv`?@u(YU{@reN>UD-;h!y=kutTE%HI(`#&@}gmNS9LtzZ&@Py;)}*z z#QERpP%Y#FqWJp2ddPliOMj6D17>uA8>nyMQ}Ex=h#cH@U0N25xcCyXbg)i;S^>ib zMl*SX0kDkngA)CY>kXO-LIW+7%S62oMI`?N-4Va0_o%yT$-_z5Z+8jK_<(Yf5|XFMOzllSEM?b{4`dh-%=r#B!dS*?+hd$9Dq&VA}y zDLfSkZ9HyvV{(V4OWFd}wBR}tz`Mgg39u{Iy&4WEnL%#~?uUDs?j1(>Pf=uKWTyYR z^s#qFdPwz)nomW2DDcEis!$;iO5nN9L141bsyEO(LDhl6unQ_8{!E)~i(mJ(Lyx|n zu41QtaXYSNgo|%|6XmC)2)N|#D8j2b3`D_>B)qgD@@yep^Zf^R@Mu`oSuw*BZBe1Y zNo@-zYIghIza*ox<(M!w3u#yX6!@d=?I?RHON#*|_YNSyiJIq12RJZjbpqva8CjW{ z!2AavfW^dV^wAl?<_pS~cL|i9xd3)l2E#eJ_u^`Z9bOL9wA3hNji08`~`trvCG9Fk{zx&Ly7jEb)PZ&th~M=VvX5ojK|eB#%i5CIuG`K+N(c zi-dH%M#F}cr$=5JO$A=|FypXoP8v0rvK88?%YM{#KO#I)S+Tm(uIfhAj!Uqa2e_~ zz)}L`#w8Q0ez|aphC_{70RxEhwl@k_6p!(5`)X_hr3(PIe}BcAX7RKw=#@vWYwY|| zjw{WkyM_z^^*CD8HOLA~7m^W~fm?*d!8Kj3y0tW~1}QIeDP5p`!G?~nUy}7-?QVYd z-iKN-p>CKb(K0b?##=-_k)Ufn`QjB=R0;rLfjhx~ua2G`w^hS!$YLK~`;1PJ{bFKh zx!2@BmQ4?wbjK=Z-@(&?7(G;oc)&6&R}0}+%E1Z_C?OVcd_X~>%#rfZq7mvRH*{aK zMPD@J`a$+)$l@KsU#0K%?b`=N+1U~3a#_JyQ`a7^$#7unAU{yT^u(PJ;kTF9_YMh z>+v5-Dl=2d`T1m`zQO}x-LQRx=IDiqJqKd2oBIx=IwkU3K;UHNvnh;n9h0RF+5mFz z=1qEVa3!34oYY=@w!x14djI;XJ7S%FZvc+uWvy*t6u8AaIVv)%30RvT>qGKvM!#^d z0Q2o!Kq?-47b#FNyuJ3$Nb{Hw;m>lFKJVXMf6b>loY~=n`YQrGsy(?8m9hC&OHkt_^=~~QFlsg^qUUVoqXaR@k6vK56C*>}G zG-Ut=yeSRPpH72$G?KDMj{Xlpw*ML(-Dw5^WbYPF9_CB8f?)m*%w`DEj*BeefUpJv^^(C$7X05^Q& z7==E|ssPdTY$i3Z?+$wk=!B0cCEPwrQnx(VDkg!n_$62H_C#`B= zdf+j6-TN~wdweTW(YO&Yqw^;)R`L)y1S_S0;@F85us(IcLPOmjoPHJjpj-$Nym z(?ZF2sJPfaXbe19b-F?#nMnuG8{w7 zY?$Z;@GxrJmQO`4vlZ~(AJU=5VAMMlAuX!#i2CbJGm-tT3y*jP7CrwH?g_L&kERv` zxC%@pb)fVt1%BrjeC6O1T~JG338-JU7(Q~+an?!e*KZ3mTH^ z=68=SVnaKoB&f!;F&7g7G0msJH*g8Pynvq-0lGDcm)~PE28-2ePj-~dzc5+9Rg`3O ze@m(GG1wi>mVeMH0_Hn#ZkU&Pk$~pe&fW?Ya)A`p3fS5V3QUp)jO)$L0<=dkO*CS! z^%K8s$Ts|MY72s3%*5}@p7dRv5&C9M%-6*MM|v^QuI&i!bYErLabKdrQ+eTnjR@`w zqCbk$G)Z1kbAf$dudX&sJD5q-F1M?syM|OuA1=!c&ASWj-7CZ%3B3-oqLpgpWC#&a zpC?wv-aY)3lyR8@YWILX==hr+^FWX><+FB+awu z#i`vq1;BuWn4%hkcg5+M#Rn)xz=TlDF%3nv*RUEivE-pS=XEXjrqp2kO@vwW-vHT< zLOQZtT^IhO`{0cQSeFK5wL)J}=f6gYz0AFdCJETatc=Rl?Lg>%^3~c1waCx#BJyw6>wA{xCa7ADX z2-K%rD0AhvKmi4E8_&x)yUq=COWLCp$={%2S2Z;u;AOv*rbSU!?=$l(l16gB09rR% z^nl_dyzM4&l^NA}nEG{V=CGNn@&Bm~VDq3HEsZv*z1l@?bXk060GI)iDN~G&x6tgY zPCY(}OBLZZ<2e_kiQ|h6J^{~Q$WWC+!>dP^j#Tg$12N{pb6AVvG|ztag!WJR)Kg23 z#}cj6VOCVbtphkVCu?~Qv+V`m8C}bCc@N0j$Jjy9;d)Rdy@E}nf;nnd1h{{3lLOQr zN-+ktPr#myEy8gE_h_#}@;aLlqGAVM0=D1Q z*ajcrc5v_i%YfPZ$4g4wh{$iSjehYN>>pVFew4OH;zFF1D>MT6)fxRAo}LxtelQ#H^N56fXHctGy^gqGm}F134N&?TNw?h{ zMVEx-lIu}S2cHt;CFFhGm;M4k!xoB7%#H?8Eyx{e8Bn7?yL0MB!v<&|dL@rr-*F$2l}%)g*F9ZR})yFR$)dA-ck zxDPc-Yy1w#z9p;0wk+;QAIrj(>S|h;!}em&F?{bg`v>E&&c#rN@clz0Wb;u$Z|(#YA4GQc%`;+6EHAO#3@^! zE(C_VgU-96jlz2>#Ebw>4oF_JAS4eX$7xpqah(w(KRio$PwiE;Jt3O1RHScrmF5kJl;O1se<3UIppfZKQ0OTBLTrhK zM^Bbe;ek_5X0%|G8hrVSSa)^^pFZULn>gb5-h^4@1UrPo(;-SNy6@@B&@f zo6ieM$tU}x6e=Bz5(n9JDDy|)4ZWRH85mNfUl*ns82u@{3GpQE@uon1M?m0jKl#sR z1}*nr-j!?73zQmK;2~4nKDBP;1e_ZnZZsp5N5!d{kd~yb{#iYHGA+>6O#B$820`w$ z9xo!Ohe+z;-&MUj^!UJbd09|FhwEs1rYQC#iZ$hRlCg#$-?hYrXrl=}kp?w)?jmsM zO7(JkRgu?@<@z}j^-l!G8NYEw;E*RE@ZNQ0DNgeFZrQHFxjAyLS&2n2-LkFDJ$97?cIT250oYnurcKY~X=2P~&0+8HXtg>Ntd337w}dml`6?nI9Fwt!TJ55yV0#9rSuS zV{W-)u|?OL_e3 z8{MXlrV_4iTR*NU`1>4XNeI?qGEk^p^C*X^YXOGuX>?D_OjkXQ)n*0UqHu}x_GcT~3(y5(DA&&b4JtBIgZkd? zpQ!u=<2Lb0cu}SRdjv*;%(Fp6vK^mjmf69;0A1SmnxRm!`+J}Fmccc>J9kK`|1GZe zak-&#>q=!qw~Q5ZD)@}UMb|XBV)w$e=KLKN zr1~+HMvLvq>g0@Hhhc{=*Cey6nYL1pbVcshmR9vbWu$)B7n*A)DIUz{`oMoSD!DX| z*{a)ylVC?hPoD%}b&^)AXJ1_rt;!*;iNaiqRzOvq(rPFU=0lJ3s!N5xe}6Qy^G?un zb~JFb;aJISs!I4*$vqmn%MaOsY_fi;yU(I6j@;k%{TXjv-Sb8jNZv1M15_;ZIz$X3 zXB#y1x#X*8KW3lUjqE_a{jZ}?{rdI72yC+l8+DWm?LAfc3}K^@3IHbqRCS1NuA@!Roe^mmj~DVrogScL0YOkc@ZM37evOC5eFAp@Y#h z(pNQ4<~1-3`Lik=U*Fg<077;K2jXqXE1=~4SHnL9me!UOIZmP;=7JKP1l{{F8dMnf zr@gSqZ)bg0o%q~ybJGza-`T7RHGWpduE%%OSg*;|l77tiBR8EfnS8kb z-SLtU=Vc=k^3f}1I|DPPNo$-DmL;dG`k_=~lj~vM#Fg8jwjoRRBSwk_p11}tba%9t zGF;gB42t9HqS1+c;wjLod+QL-4J&0K&5%=m8>7zefG>X31U*zJOr*Qq-NvsPy>uUn z5>kPp6a}w+rtK__-W2TA1g9U53GL7BfNWso?=qW?Mj!4zdD6s?Yz691mOwdA-ivb2 zSu`uo%QTg+-6Qd2=Qu0bk!{f#11>XVlI@ra%3!?ejI>`r?~0Ec(w8uCQ$N9+|^tBsoHFqH#guAf4n7Zb|!vK zWsxmu?&zd&Gkeo3Xq6AgDNsVMs5n__{Sl?&T-uheQ)GudXezfqTL_$`ofz$wp@N51 z0od{Jjs�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

*P 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 z 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

LPSM&ubK%ca3`lhwu^N%K^ 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 MX&Y%(XxK&nA3I&c%m4rY literal 0 HcmV?d00001 From 76ab9f3dfcf75a8bb495e9677aa9edd516909222 Mon Sep 17 00:00:00 2001 From: thingsboard017 Date: Tue, 24 Dec 2024 12:37:17 +0200 Subject: [PATCH 16/33] Added 4 LNS integrations for Vivid --- .../Vivid/ChirpStack/uplink/converter.json | 39 +++++++++ .../Vivid/ChirpStack/uplink/metadata.json | 4 + .../Vivid/ChirpStack/uplink/payload.json | 48 +++++++++++ .../Vivid/ChirpStack/uplink/result.json | 27 ++++++ .../Vivid/LORIOT/uplink/converter.json | 29 +++++++ .../Vivid/LORIOT/uplink/metadata.json | 4 + .../Tektelic/Vivid/LORIOT/uplink/payload.json | 17 ++++ .../Tektelic/Vivid/LORIOT/uplink/result.json | 17 ++++ .../uplink/converter.json | 39 +++++++++ .../ThingsStackCommunity/uplink/metadata.json | 4 + .../ThingsStackCommunity/uplink/payload.json | 54 ++++++++++++ .../ThingsStackCommunity/uplink/result.json | 28 +++++++ .../uplink/converter.json | 40 +++++++++ .../uplink/metadata.json | 4 + .../ThingsStackIndustries/uplink/payload.json | 77 ++++++++++++++++++ .../ThingsStackIndustries/uplink/result.json | 28 +++++++ VENDORS/Tektelic/Vivid/info.json | 5 ++ VENDORS/Tektelic/Vivid/photo.png | Bin 0 -> 80030 bytes 18 files changed, 464 insertions(+) create mode 100644 VENDORS/Tektelic/Vivid/ChirpStack/uplink/converter.json create mode 100644 VENDORS/Tektelic/Vivid/ChirpStack/uplink/metadata.json create mode 100644 VENDORS/Tektelic/Vivid/ChirpStack/uplink/payload.json create mode 100644 VENDORS/Tektelic/Vivid/ChirpStack/uplink/result.json create mode 100644 VENDORS/Tektelic/Vivid/LORIOT/uplink/converter.json create mode 100644 VENDORS/Tektelic/Vivid/LORIOT/uplink/metadata.json create mode 100644 VENDORS/Tektelic/Vivid/LORIOT/uplink/payload.json create mode 100644 VENDORS/Tektelic/Vivid/LORIOT/uplink/result.json create mode 100644 VENDORS/Tektelic/Vivid/ThingsStackCommunity/uplink/converter.json create mode 100644 VENDORS/Tektelic/Vivid/ThingsStackCommunity/uplink/metadata.json create mode 100644 VENDORS/Tektelic/Vivid/ThingsStackCommunity/uplink/payload.json create mode 100644 VENDORS/Tektelic/Vivid/ThingsStackCommunity/uplink/result.json create mode 100644 VENDORS/Tektelic/Vivid/ThingsStackIndustries/uplink/converter.json create mode 100644 VENDORS/Tektelic/Vivid/ThingsStackIndustries/uplink/metadata.json create mode 100644 VENDORS/Tektelic/Vivid/ThingsStackIndustries/uplink/payload.json create mode 100644 VENDORS/Tektelic/Vivid/ThingsStackIndustries/uplink/result.json create mode 100644 VENDORS/Tektelic/Vivid/info.json create mode 100644 VENDORS/Tektelic/Vivid/photo.png diff --git a/VENDORS/Tektelic/Vivid/ChirpStack/uplink/converter.json b/VENDORS/Tektelic/Vivid/ChirpStack/uplink/converter.json new file mode 100644 index 00000000..04989e4d --- /dev/null +++ b/VENDORS/Tektelic/Vivid/ChirpStack/uplink/converter.json @@ -0,0 +1,39 @@ +{ + "name": "ChirpStack Uplink Decoder for Vivid", + "type": "UPLINK", + "debugMode": false, + "debugSettings": { + "failuresEnabled": true, + "allEnabled": false, + "allEnabledUntil": 1733331880270 + }, + "configuration": { + "scriptLang": "TBEL", + "decoder": null, + "tbelDecoder": "var data = decodeToJson(payload);\nvar deviceName = data.deviceInfo.deviceName + \" \" + data.deviceInfo.devEui;\nvar deviceType = \"Vivid\";\nvar groupName = null; // If groupName is not null - created device will be added to the entity group with such name.\nvar customerName = null; // If customerName is not null - created devices will be assigned to customer with such name. \n\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// If you want to parse incoming data somehow, you can add your code to this function.\n// input: bytes\n// expected output:\n// {\n// \"attributes\": {\"attributeKey\": \"attributeValue\"},\n// \"telemetry\": [{\"ts\": 1...1, \"values\": {\"telemetryKey\":\"telemetryValue\"}, {\"ts\": 1...2, \"values\": {\"telemetryKey\":\"telemetryValue\"}}]\n// }\n\nfunction decodePayload(input) {\n var output = {\n attributes: {},\n telemetry: []\n };\n \n // --- Decoding code --- //\n var decoded = {};\n var fPort = data.fPort;\n if(fPort == 10) {\n for(var i = 0; i < input.length - 2; ) {\n var key_1 = input[i++] & 0xff;\n var key_2 = input[i++] & 0xff;\n \n if(key_1 == 0x00 && key_2 == 0xBA) {\n decoded.battery_voltage = toFixed(parseBytesToInt(input, i, 2) * 0.001, 3);\n i += 2;\n }\n else if(key_1 == 0x01 && key_2 == 0x00) {\n val = parseBytesToInt(input, i, 1);\n switch (val){\n\t\t\t\t\tcase 0:\n\t\t\t\t\t\tdecoded.hall_effect_state = \"Magnet Present\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 255:\n\t\t\t\t\t\tdecoded.hall_effect_state = \"Magnet Absent\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tdecoded.hall_effect_state = \"Invalid\";\n\t\t\t\t}\n \n i += 1;\n }\n else if(key_1 == 0x08 && key_2 == 0x04) {\n decoded.hall_effect_count = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key_1 == 0x0C && key_2 == 0x00) {\n var val = parseBytesToInt(input, i, 1);\n \n switch (val){\n\t\t\t\t\tcase 0:\n\t\t\t\t\t\tdecoded.impact_alarm = \"Impact Alarm Inactive\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 255:\n\t\t\t\t\t\tdecoded.impact_alarm = \"Impact Alarm Active\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tdecoded.impact_alarm = \"Invalid\";\n\t\t\t\t}\n\t\t\t\t\n i += 1;\n }\n else if(key_1 == 0x05 && key_2 == 0x02) {\n decoded.impact_magnitude = toFixed(parseBytesToInt(input, i, 2) * 0.001, 3);\n i += 2;\n }\n else if(key_1 == 0x07 && key_2 == 0x71) {\n decoded.accelerationX = toFixed(parseBytesToInt(input, i + 4, 2) * 0.001, 3);\n decoded.accelerationY = toFixed(parseBytesToInt(input, i + 2, 2) * 0.001, 3);\n decoded.accelerationZ = toFixed(parseBytesToInt(input, i, 2) * 0.001, 3);\n i += 6;\n }\n else if(key_1 == 0x0E && key_2 == 0x00) {\n var val = parseBytesToInt(input, i, 1);\n\t\t\t\tswitch (val){\n\t\t\t\t\tcase 0:\n\t\t\t\t\t\tdecoded.extconnector_state = \"Low(short-circuit)\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 255:\n\t\t\t\t\t\tdecoded.extconnector_state = \"High(open-circuit)\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tdecoded.extconnector_state = \"Invalid\";\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\ti += 1;\n }\n else if(key_1 == 0x0F && key_2 == 0x04) {\n decoded.extconnector_count = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key_1 == 0x12 && key_2 == 0x04) {\n decoded.extconnector_total_count = parseBytesToInt(input, i, 4);\n i += 4;\n }\n else if(key_1 == 0x11 && key_2 == 0x02) {\n decoded.extconnector_analog = toFixed(parseBytesToInt(input, i, 2) * 0.001, 3);\n i += 2;\n }\n else if(key_1 == 0x0B && key_2 == 0x67) {\n decoded.mcu_temperature = toFixed(parseBytesToInt(input, i, 2) * 0.1, 1);\n i += 2;\n }\n else if(key_1 == 0x03 && key_2 == 0x67) {\n decoded.ambient_temperature = toFixed(parseBytesToInt(input, i, 2) * 0.1, 1);\n i += 2;\n }\n else if(key_1 == 0x04 && key_2 == 0x68) {\n decoded.relative_humidity = toFixed(parseBytesToInt(input, i, 1) * 0.5, 1);\n i += 1;\n }\n else if(key_1 == 0x02 && key_2 == 0x00) {\n var val = parseBytesToInt(input, i, 1);\n \n\t\t\t\tswitch (val){\n\t\t\t\t\tcase 0:\n\t\t\t\t\t\tdecoded.light_detected = \"Dark\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 255:\n\t\t\t\t\t\tdecoded.light_detected = \"Bright\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tdecoded.light_detected = \"Invalid\";\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\ti += 1;\n }\n else if(key_1 == 0x10 && key_2 == 0x02) {\n decoded.light_intensity = parseBytesToInt(input, i, 1);\n\t\t\t\t\n\t\t\t\ti += 1;\n }\n else if(key_1 == 0x0A && key_2 == 0x00) {\n var val = parseBytesToInt(input, i, 1);\n\t\t\t\t\n\t\t\t\tswitch (val){\n\t\t\t\t\tcase 0:\n\t\t\t\t\t\tdecoded.motion_event_state = \"None\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 255:\n\t\t\t\t\t\tdecoded.motion_event_state = \"Detected\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tdecoded.motion_event_state = \"Invalid\";\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\ti += 1;\n }\n else if(key_1 == 0x0D && key_2 == 0x04) {\n decoded.motion_event_count = parseBytesToInt(input, i, 2);\n\t\t\t\t\n\t\t\t\ti += 2;\n }\n }\n }\n else if(fPort == 0x05) {\n var key_1 = input[i++] & 0xff;\n var key_2 = input[i++] & 0xff;\n \n if(key_1 == 0x40 && key_2 == 0x06) {\n var val = input[i + 5];\n\t\t\tswitch (val){\n\t\t\t\tcase 1:\n\t\t\t\t\tdecoded_data.reset_diagnostics_reset_reason = \"Push-button reset\";\n\t\t\t\t\tbreak;\n\t\t\t\tcase 2:\n\t\t\t\t\tdecoded_data.reset_diagnostics_reset_reason = \"DL command rest\";\n\t\t\t\t\tbreak;\n\t\t\t\tcase 4:\n\t\t\t\t\tdecoded_data.reset_diagnostics_reset_reason = \"Independent watchdog reset\";\n\t\t\t\t\tbreak;\n\t\t\t\tcase 8:\n\t\t\t\t\tdecoded_data.reset_diagnostics_reset_reason = \"Power loss reset\";\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\tdecoded_data.reset_diagnostics_reset_reason = \"Invalid\";\n\t\t\t}\n\t\t\tdecoded_data.reset_diagnostics_power_loss_reset_count = input[i + 3];\n\t\t\tdecoded_data.reset_diagnostics_watchdog_reset_count = input[i + 2];\n\t\t\tdecoded_data.reset_diagnostics_dl_reset_count = input[i + 1];\n\t\t\tdecoded_data.reset_diagnostics_button_reset_count = input[i];\n }\n }\n else if (fPort == 100) {\n for(var i = 0; i < input.length -1; ) {\n var key = input[i++] & 0xff;\n \n if(key == 0x00) {\n output.attributes.eui = bytesToHex(java.util.Arrays.copyRange(input, i, i + 8));\n i += 8;\n }\n else if(key == 0x01) {\n output.attributes.app_eui = bytesToHex(java.util.Arrays.copyRange(input, i, i + 8));\n\t\t\t\ti += 8;\n }\n else if (key == 0x02) {\n output.attributes.app_key = bytesToHex(java.util.Arrays.copyRange(input, i, i + 16));\n i += 16;\n }\n else if (key == 0x03) {\n output.attributes.devAddr = bytesToHex(java.util.Arrays.copyRange(input, i, i + 4));\n i += 4;\n }\n else if(key == 0x04) {\n output.attributes.network_session_key = bytesToHex(java.util.Arrays.copyRange(input, i, i + 16));\n i += 16;\n }\n else if(key == 0x05) {\n output.attributes.app_session_key = bytesToHex(java.util.Arrays.copyRange(input, i, i + 16));\n i += 16;\n }\n else if(key == 0x10) {\n var val = (((input[i] << 8) | input[i + 1]) >> 15) & 1;\n switch (val){\n\t\t\t\t\tcase 0:\n\t\t\t\t\t\toutput.attributes.loramac_join_mode = \"ABP\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 1:\n\t\t\t\t\t\toutput.attributes.loramac_join_mode = \"OTAA\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\toutput.attributes.loramac_join_mode = \"Invalid\";\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\ti += 1;\n }\n else if (key == 0x11) {\n\t\t\t\tvar val = (((input[i] << 8) | input[i + 1]) >> 3) & 1;\n\t\t\t\toutput.attributes.adr = getEnableStatus(val);\n\t\t\t\t\n\t\t\t\tvar val = (((input[i] << 8) | input[i + 1]) >> 2) & 1;\n\t\t\t\toutput.attributes.duty_cycle = getEnableStatus(val);\n\t\t\t\t\n\t\t\t\tvar val = (((input[i] << 8) | input[i + 1]) >> 1) & 1;\n\t\t\t\t\n\t\t\t\tswitch (val) {\n\t\t\t\t\tcase 0:\n\t\t\t\t\t\toutput.attributes.sync_word = \"Private\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 1:\n\t\t\t\t\t\toutput.attributes.sync_word = \"Public\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\toutput.attributes.sync_word = \"Invalid\";\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tvar val = ((input[i] << 8) | input[i + 1]) & 1;\n\t\t\t\t\n\t\t\t\tswitch (val){\n\t\t\t\t\tcase 0:\n\t\t\t\t\t\toutput.attributes.confirm_mode = \"Unconfirmed\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 1:\n\t\t\t\t\t\toutput.attributes.confirm_mode = \"Confirmed\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t output.attributes.confirm_mode = \"Invalid\";\n\t\t\t\t}\n\t\t\t\ti += 2;\n }\n else if (key == 0x12) {\n output.attributes.dr_number = (((input[i] << 8) | input[i + 1]) >> 8) & 0xF;\n output.attributes.tx_power_number = ((input[i] << 8) | input[i + 1]) & 0xF;\n \n i +=2;\n }\n else if (key == 0x13) {\n output.attributes.frequency = (((input[i] << 32) | (input[i + 1] << 24) | (input[i + 2] << 16) | (input[i + 3] << 8) | input[i + 4]) >> 8) & 0xFFFFFFFF;\n output.attributes.dr_number_rx2 = input[i + 4] & 0xFF;\n \n i += 5;\n }\n else if(key == 0x19) {\n output.attributes.netid_msb = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x1A) {\n output.attributes.loramac_net_id_lsb = parseBytesToInt(input, i, 2);\n\t\t\t\ti += 2;\n }\n else if (key == 0x20) {\n output.attributes.seconds_per_core_tick = parseBytesToInt(input, i, 4);\n i += 4;\n }\n else if(key == 0x21) {\n output.attributes.tick_per_battery = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x22) {\n output.attributes.tick_per_ambient_temperature = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x23) {\n output.attributes.tick_per_relative_humidity = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x24) {\n output.attributes.tick_per_reed_switch = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x25) {\n output.attributes.tick_per_light = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x26) {\n output.attributes.tick_per_accelerometer = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x27) {\n output.attributes.tick_per_mcu_temperature = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x28) {\n output.attributes.tick_per_pir = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x29) {\n output.attributes.tick_per_external_connector = parseBytesToInt(input, i, 2);\n \n i += 2;\n }\n else if(key == 0x2A) {\n var bit0 = (input[i] >> 0) & 1;\n var bit1 = (input[i] >> 1) & 1;\n \n output.attributes.mode.rising_edge_enabled = getEnableStatus(bit0);\n output.attributes.mode.falling_edge_enabled = getEnableStatus(bit1);\n \n i += 1;\n }\n else if(key == 0x2B) {\n\t\t\t\toutput.attributes.reed_switch_count_threshold = parseBytesToInt(input, i, 2);\n\t\t\t\ti += 2;\n }\n else if(key == 0x2C) {\n var bit0 = (input[i] >> 0) & 1;\n var bit1 = (input[i] >> 1) & 1;\n \n output.attributes.reed_values_to_transmit_report_state_enabled = getOnOffStatus(bit0);\n output.attributes.reed_values_to_transmit_report_count_enabled = getOnOffStatus(bit1);\n \n i += 1;\n }\n else if(key == 0x2D) {\n var bit0 = (input[i] >> 0) & 1;\n var bit1 = (input[i] >> 1) & 1;\n var bit7 = (input[i] >> 7) & 1;\n \n output.attributes.external_mode_rising_edge_enabled_ex = getOnOffStatus(bit0);\n output.attributes.external_mode_falling_edge_enabled_ex = getOnOffStatus(bit1);\n \n switch (bit7){\n\t\t\t\t\tcase 0:\n\t\t\t\t\t\toutput.attributes.mode = \"Digital\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 1:\n\t\t\t\t\t output.attributes.mode = \"Analog\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\toutput.attributes.mode = \"Invalid\";\n\t\t\t\t}\n\t\t\t\t\n i += 1;\n }\n else if(key == 0x2E) {\n output.attributes.external_connector_count_threshold = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x2F) {\n var bit0 = (input[i] >> 0) & 1;\n var bit1 = (input[i] >> 1) & 1;\n var bit4 = (input[i] >> 4) & 1;\n \n output.attributes.external_values_to_transmit.report_state_enabled_ex = getOnOffStatus(bit0);\n output.attributes.external_values_to_transmit.report_count_enabled_ex = getOnOffStatus(bit1);\n output.attributes.external_values_to_transmit.count_type = bit4;\n i += 1;\n }\n else if(key == 0x30) {\n output.attributes.impact_event_threshold = toFixed(parseBytesToInt(input, i, 2) * 0x001, 3);\n i += 2;\n }\n else if(key == 0x31) {\n output.attributes.acceleration_event_threshold = toFixed(parseBytesToInt(input, i, 2) * 0.001, 3);\n i += 2;\n }\n else if(key == 0x32) {\n var bit0 = (input[i] >> 0) & 1;\n output.attributes.values_to_transmit.report_periodic_alarm_enabled = getOnOffStatus(bit0);\n \n var bit1 = (input[i] >> 1) & 1;\n output.attributes.values_to_transmit.report_periodic_magnitude_enabled = getOnOffStatus(bit1);\n \n var bit2 = (input[i] >> 2) & 1;\n output.attributes.values_to_transmit.report_periodic_vector_enabled = getOnOffStatus(bit2);\n \n var bit4 = (input[i] >> 4) & 1;\n output.attributes.values_to_transmit.report_event_magnitude_enabled = getOnOffStatus(bit4);\n \n var bit5 = (input[i] >> 5) & 1;\n output.attributes.values_to_transmit.report_event_vector_enabled = getOnOffStatus(bit5);\n \n i += 1;\n }\n else if(key == 0x33) {\n output.attributes.acceleration_impact_grace_period = parseBytesToInt(input, i, 2);\n\t\t\t\t\n\t\t\t\ti += 2;\n }\n else if (key == 0x34) {\n var bit0 = (input[i] >> 0) & 1;\n output.attributes.acceleration_mode.impact_threshold_enabled = getEnableStatus(bit0);\n \n var bit1 = (input[i] >> 1) & 1;\n\t\t\t\toutput.attributes.acceleration_mode.acceleration_threshold_enabled = getEnableStatus(bit1);\n\t\t\t\t\n\t\t\t\tvar bit4 = (input[i] >> 4) & 1;\n\t\t\t\toutput.attributes.acceleration_mode.xaxis_enabled = getEnableStatus(bit4);\n\t\t\t\t\n\t\t\t\tvar bit5 = (input[i] >> 5) & 1;\n\t\t\t\toutput.attributes.acceleration_mode.yaxis_enabled = getEnableStatus(bit5);\n\t\t\t\t\n\t\t\t\tvar bit6 = (input[i] >> 6) & 1;\n\t\t\t\toutput.attributes.acceleration_mode.zaxis_enabled = getEnableStatus(bit6);\n\t\t\t\t\n\t\t\t\tvar bit7 = (input[i] >> 7) & 1;\n\t\t\t\toutput.attributes.acceleration_mode.poweron = getOnOffStatus(bit7);\n\t\t\t\t\n\t\t\t\ti += 1;\n }\n else if (key == 0x35) {\n var val = (input[i] >> 1) & 0x03;\n\t\t\t\t\n\t\t\t\tswitch (val) {\n\t\t\t\t\tcase 1:\n\t\t\t\t\t\toutput.attributes.sensitivity_accelerometer_sample_rate = \"1 Hz\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 2:\n\t\t\t\t\t\toutput.attributes.sensitivity_accelerometer_sample_rate = \"10 Hz\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 3:\n\t\t\t\t\t\toutput.attributes.sensitivity_accelerometer_sample_rate = \"25 Hz\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 4:\n\t\t\t\t\t\toutput.attributes.sensitivity_accelerometer_sample_rate = \"50 Hz\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 5:\n\t\t\t\t\t\toutput.attributes.sensitivity_accelerometer_sample_rate = \"100 Hz\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 6:\n\t\t\t\t\t\toutput.attributes.sensitivity_accelerometer_sample_rate = \"200 Hz\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 7:\n\t\t\t\t\t\toutput.attributes.sensitivity_accelerometer_sample_rate = \"400 Hz\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\toutput.attributes.sensitivity_accelerometer_sample_rate = \"Invalid\";\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tvar val = (arg >> 4) & 0x03;\n\t\t\t\tswitch (val) {\n\t\t\t\t\tcase 0:\n\t\t\t\t\t\toutput.attributes.sensitivity_accelerometer_measurement_range = \"±2 g\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 1:\n\t\t\t\t\t\toutput.attributes.sensitivity_accelerometer_measurement_range = \"±4 g\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 2:\n\t\t\t\t\t\toutput.attributes.sensitivity_accelerometer_measurement_range = \"±8 g\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 3:\n\t\t\t\t\t\toutput.attributes.sensitivity_accelerometer_measurement_range = \"±16 g\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\toutput.attributes.sensitivity_accelerometer_measurement_range = \"Invalid\";\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\ti += 1;\n }\n else if (key == 0x36) {\n output.attributes.impact_alarm_grace_period = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if (key == 0x37) {\n output.attributes.impact_alarm_threshold_count = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if (key == 0x38) {\n output.attributes.impact_alarm_threshold_period = parseBytesToInt(input, i, 2);\n \n i += 2;\n }\n else if (key == 0x39) {\n output.attributes.temperature_relative_humidity_sample_period_idle = parseBytesToInt(input, i, 4);\n \n i += 4;\n }\n else if (key == 0x3A) {\n output.attributes.temperature_relative_humidity_sample_period_active = parseBytesToInt(input, i, 4);\n \n i += 4;\n }\n else if (key == 0x3B) {\n output.attributes.temperature_threshold_low_temp_threshold = parseBytesToInt(input, i, 1);\n output.attributes.temperature_threshold_high_temp_threshold = parseBytesToInt(input, i + 1, 1);\n \n i += 2;\n }\n else if (key == 0x3C) {\n var bit0 = (input[i] >> 0) & 1;\n output.attributes.ambient_temperature_threshold_enabled = getEnableStatus(bit0);\n \n i += 1;\n }\n else if (key == 0x3D) {\n output.attributes.rh_threshold.low_rh_threshold = parseBytesToInt(input, i, 1);\n output.attributes.rh_threshold.high_rh_threshold = parseBytesToInt(input, i + 1, 1);\n \n i += 2;\n }\n else if (key == 0x3E) {\n var bit0 = (input[i] >> 0) & 1;\n output.attributes.relative_humidity_threshold_enabled =getEnableStatus(bit0);\n \n i += 1;\n }\n else if (key == 0x40) {\n output.attributes.mcu_temperature_sample_period_idle = parseBytesToInt(input, i, 4);\n i += 4;\n }\n else if (key == 0x41) {\n output.attributes.mcu_temperature_sample_period_active = parseBytesToInt(input, i, 4);\n i += 4;\n }\n else if (key == 0x42) {\n output.attributes.mcu_temp_threshold_high_mcu_temp_threshold = input[i + 1];\n output.attributes.mcu_temp_threshold_low_mcu_temp_threshold = input[i];\n i += 4;\n }\n else if (key == 0x43) {\n var val = input[i] & 1;\n output.attributes.mcu_temperature_threshold_enabled = getEnableStatus(val);\n\n\t\t\t\ti += 2;\n }\n else if (key == 0x44) {\n output.attributes.analog_sample_period_idle = parseBytesToInt(input, i, 4);\n \n i += 4;\n }\n else if (key == 0x45) {\n output.attributes.analog_sample_period_active = parseBytesToInt(input, i, 4);\n \n i += 4;\n }\n else if(key == 0x46) {\n output.attributes.analog_threshold_high_analog_threshold = toFixed(parseBytesToInt(input, i + 2, 2) * 0.001, 3);\n\t\t\t\toutput.attributes.analog_threshold_low_analog_threshold = toFixed(parseBytesToInt(input, i, 2) * 0.001, 3);\n\t\t\t\ti += 4;\n }\n else if (key == 0x4A) {\n var bit0 = (input[i] >> 0) & 1;\n output.attributes.analog_input_threshold_enabled = getEnableStatus(bit0);\n \n i +=1;\n }\n else if (key == 0x47) {\n output.attributes.light_sample_period = parseBytesToInt(input, i, 4);\n \n i += 4;\n }\n else if (key == 0x48 ) {\n var val = (input[i] >> 7) & 1;\n output.attributes.light_thresholds.threshold_enabled = getEnableStatus(val);\n output.attributes.light_thresholds.threshold = input[i] & 0x3F;\n \n i += 1;\n }\n else if (key == 0x49) {\n var bit0 = (input[i] >> 0) & 1;\n output.attributes.light_values_to_transmit.state_reported = getEnableStatus(bit0);\n \n var bit1 = (input[i] >> 1) & 1;\n output.attributes.light_values_to_transmit.intensity_reported = getEnableStatus(bit1);\n \n i +=1;\n }\n else if (key == 0x50) {\n output.attributes.pir_grace_period = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if (key == 0x51) {\n output.attributes.pir_threshold = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if (key == 0x52) {\n output.attributes.pir_threshold_period = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if (key == 0x53) {\n var bit7 = (input[i] >> 7) & 1;\n output.attributes.pir_mode.motion_count_reported = getEnableStatus(bit7);\n \n var bit6 = (input[i] >> pir_mode) & 1;\n output.attributes.pir_mode.motion_state_reported = getEnableStatus(bit6);\n \n var bit1 = (input[i] >> 1) & 1;\n output.attributes.pir_mode.event_transmission_enabled = getEnableStatus(bit1);\n \n var bit0 = (input[i] >> 0) & 1;\n output.attributes.pir_mode.transducer_enabled = getEnableStatus(bit0);\n \n i += 1;\n }\n else if (key == 0x54) {\n output.attributes.pir_mode.motion_count_reported = input[i + 1];\n output.attributes.pir_mode.motion_state_reported = input[i];\n \n i += 1;\n }\n else if (key == 0x6F) {\n var val = (input[i] >> 0) & 1;\n \n switch (val){\n\t\t\t\t\tcase 0:\n\t\t\t\t\t\toutput.attributes_resp_to_dl_command_format = \"Invalid-write response format\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 1:\n\t\t\t\t\t\toutput.attributes_resp_to_dl_command_format = \"4-byte CRC\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\toutput.attributes_resp_to_dl_command_format = \"Invalid\";\n\t\t\t\t}\n \n i += 1;\n }\n else if (key == 0x71) {\n output.attributes.app_major_version = input[i + 6];\n\t\t\t\toutput.attributes.app_minor_version = input[i + 5];\n\t\t\t\toutput.attributes.app_revision = input[i + 4];\n\t\t\t\toutput.attributes.loramac_major_version = input[i + 3];\n\t\t\t\toutput.attributes.loramac_minor_version = input[i + 2];\n\t\t\t\toutput.attributes.loramac_revision = input[i + 1];\n\t\t\t\tvar val = input[i];\n\t\t\t\tswitch (val){\n\t\t\t\t\tcase 0:\n\t\t\t\t\t\toutput.attributes.region = \"EU868\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 1:\n\t\t\t\t\t\toutput.attributes.region = \"US915\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 2:\n\t\t\t\t\t\toutput.attributes.region = \"AS923\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 3:\n\t\t\t\t\t\toutput.attributes.region = \"AU915\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 4:\n\t\t\t\t\t\toutput.attributes.region = \"IN865\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 6:\n\t\t\t\t\t\toutput.attributes.region = \"KR920\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 7:\n\t\t\t\t\t\toutput.attributes.region = \"RU864\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\toutput.attributes.region = \"Invalid\";\n\t\t\t\t}\n\t\t\t\ti += 7;\n }\n }\n }\n else if (fPort == 101) {\n var size = input.length;\n var responses = [];\n \n var index = 0;\n while (index < size) {\n var downlinkFcnt = input[index++] & 0xFF; \n var numInvalidWrites = input[index++] & 0xFF; \n \n if (numInvalidWrites > 0) {\n var invalidRegisters = [];\n for (var i = 0; i < numInvalidWrites; i++) {\n invalidRegisters.add(String.format(\"0x%02X\", input[index + i]));\n }\n index += numInvalidWrites;\n \n responses.add(String.format(\n \"%d Invalid write command(s) from DL:%d for register(s): %s\",\n numInvalidWrites, downlinkFcnt, String.join(\", \", invalidRegisters)\n ));\n } else {\n responses.add(String.format(\"All write commands from DL:%d were successful\", downlinkFcnt));\n }\n }\n \n decoded.response = responses;\n }\n\n output.telemetry = [{\n ts: timestamp,\n values: decoded\n }];\n // --- Decoding code --- //\n return output;\n}\n\n// --- attributes and telemetry objects ---\nvar telemetry = [];\nvar attributes = {};\n// --- attributes and telemetry objects ---\n\n// --- Timestamp parsing\nvar dateString = data.time;\ntimestamp = parseDateToTimestamp(dateString);\n// --- Timestamp parsing\n\n// Passing incoming bytes to decodePayload function, to get custom decoding\nvar customDecoding = decodePayload(base64ToBytes(data.data));\n\n\nattributes.eui = data.deviceInfo.devEui;\n\n// Collecting data to result\nif (customDecoding.?telemetry.size() > 0) {\n if (customDecoding.telemetry instanceof java.util.ArrayList) {\n foreach(telemetryObj: customDecoding.telemetry) {\n if (telemetryObj.ts != null && telemetryObj.values != null) {\n telemetry.add(telemetryObj);\n }\n }\n } else {\n telemetry.putAll(customDecoding.telemetry);\n }\n}\n\nif (customDecoding.?attributes.size() > 0) {\n attributes.putAll(customDecoding.attributes);\n}\n\n// You can add some keys manually to attributes or telemetry\nattributes.eui = data.deviceInfo.?devEui;\nattributes.devAddr = data.devAddr;\nattributes.fPort = data.fPort;\nattributes.applicationId = data.deviceInfo.?applicationId;\nattributes.applicationName = data.deviceInfo.?applicationName;\nattributes.tenantId = data.deviceInfo.?tenantId;\nattributes.tenantName = data.deviceInfo.?tenantName;\nattributes.deviceProfileId = data.deviceInfo.?deviceProfileId;\nattributes.deviceProfileName = data.deviceInfo.?deviceProfileName;\nattributes.frequency = data.txInfo.?frequency;\nattributes.bandwidth = data.txInfo.?modulation.?lora.?bandwidth;\nattributes.spreadingFactor = data.txInfo.?modulation.?lora.?spreadingFactor;\nattributes.codeRate = data.txInfo.?modulation.?lora.?codeRate;\n\nif(Boolean.parseBoolean(metadata[\"includeGatewayInfo\"])) {\n var gatewayInfo = getGatewayInfo();\n var addDataToTelemetry = {};\n addDataToTelemetry.snr = gatewayInfo.snr;\n addDataToTelemetry.rssi = gatewayInfo.rssi;\n addDataToTelemetry.channel = gatewayInfo.channel;\n addDataToTelemetry.rfChain = gatewayInfo.rfChain;\n addDataToTelemetry.fCnt = data.fCnt;\n \n telemetry = processTelemetryData(telemetry, addDataToTelemetry);\n}\n\nvar result = {\n deviceName: deviceName,\n deviceType: deviceType,\n // assetName: assetName,\n // assetType: assetType,\n attributes: attributes,\n telemetry: telemetry\n};\n\naddAdditionalInfoForDeviceMsg(result, customerName, groupName);\n\nreturn result;\n\nfunction addAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName) {\n if (customerName != null) {\n deviceInfo.customerName = customerName;\n }\n if (groupName != null) {\n deviceInfo.groupName = groupName;\n }\n}\n\nfunction parseDateToTimestamp(dateString) {\n var date = new Date(dateString);\n var timestamp = date.getTime();\n \n // If we cannot parse timestamp - we will use the current timestamp\n if (timestamp == -1) {\n timestamp = Date.now();\n }\n \n return timestamp;\n}\n\nfunction getGatewayInfo() {\n var gatewayList = data.rxInfo;\n var maxRssi = Integer.MIN_VALUE;\n var gatewayInfo = {};\n \n foreach (gateway : gatewayList) {\n if(gateway.rssi > maxRssi) {\n maxRssi = gateway.rssi;\n gatewayInfo = gateway;\n }\n }\n \n return gatewayInfo;\n}\n\nfunction processTelemetryData(telemetry, addDataToTelemetry) {\n if (telemetry.size >= 1) {\n telemetry = addDataToTelemetries(telemetry, addDataToTelemetry);\n }\n else {\n telemetry.add(addDataToTelemetry);\n }\n \n return telemetry;\n}\n\nfunction addDataToTelemetries(telemetries, addDataToTelemetry) {\n foreach(telemetry : telemetries) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[\"values\"].keys.contains(element.key)) {\n telemetry[\"values\"][element.key] = element.value;\n }\n } \n }\n \n return telemetries;\n}\n\nfunction getEnableStatus(bit) {\n var enableResult = \"Invalid\";\n \n switch (bit) {\n\t\tcase 0:\n\t\t enableResult = \"Disable\";\n\t\t\tbreak;\n\t\tcase 1:\n\t\t\tenableResult = \"Enable\";\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tenableResult = \"Invalid\";\n\t}\n \n return enableResult;\n}\n\nfunction getOnOffStatus(bit) {\n var reportResult = \"Invalid\";\n \n switch (bit) {\n case 0:\n reportResult = \"Off\";\n break;\n case 1:\n reportResult = \"On\";\n break;\n default:\n reportResult = \"Invalid\";\n }\n \n return reportResult;\n}", + "encoder": null, + "tbelEncoder": null, + "updateOnlyKeys": [ + "tenantId", + "tenantName", + "applicationId", + "applicationName", + "deviceProfileId", + "deviceProfileName", + "devAddr", + "fPort", + "frequency", + "bandwidth", + "spreadingFactor", + "codeRate", + "channel", + "rfChain", + "eui", + "battery" + ] + }, + "additionalInfo": { + "description": "" + }, + "edgeTemplate": false +} \ No newline at end of file diff --git a/VENDORS/Tektelic/Vivid/ChirpStack/uplink/metadata.json b/VENDORS/Tektelic/Vivid/ChirpStack/uplink/metadata.json new file mode 100644 index 00000000..23f54b34 --- /dev/null +++ b/VENDORS/Tektelic/Vivid/ChirpStack/uplink/metadata.json @@ -0,0 +1,4 @@ +{ + "integrationName": "ChirpStack integration", + "includeGatewayInfo": "false" +} \ No newline at end of file diff --git a/VENDORS/Tektelic/Vivid/ChirpStack/uplink/payload.json b/VENDORS/Tektelic/Vivid/ChirpStack/uplink/payload.json new file mode 100644 index 00000000..8b17d0f9 --- /dev/null +++ b/VENDORS/Tektelic/Vivid/ChirpStack/uplink/payload.json @@ -0,0 +1,48 @@ +{ + "deduplicationId": "57433366-50a6-4dc2-8145-2df1bbc70d9e", + "time": "2023-05-22T07:47:05.404859+00:00", + "deviceInfo": { + "tenantId": "52f14cd4-c6f1-4fbd-8f87-4025e1d49242", + "tenantName": "ChirpStack", + "applicationId": "ca739e26-7b67-4f14-b69e-d568c22a5a75", + "applicationName": "Chirpstack application", + "deviceProfileId": "605d08d4-65f5-4d2c-8a5a-3d2457662f79", + "deviceProfileName": "Chirpstack default device profile", + "deviceName": "Device name", + "devEui": "1000000000000001", + "tags": {} + }, + "devAddr": "20000001", + "adr": true, + "dr": 5, + "fCnt": 4, + "fPort": 10, + "confirmed": false, + "data": "A2cA4QRoTQC6C54=", + "rxInfo": [{ + "gatewayId": "6a7e111a10000000", + "uplinkId": 24022, + "time": "2023-05-22T07:47:05.404859+00:00", + "rssi": -35, + "snr": 11.5, + "channel": 2, + "rfChain": 1, + "location": {}, + "context": "EFwMtA==", + "metadata": { + "region_common_name": "EU868", + "region_config_id": "eu868" + }, + "crcStatus": "CRC_OK" + }], + "txInfo": { + "frequency": 868500000, + "modulation": { + "lora": { + "bandwidth": 125000, + "spreadingFactor": 7, + "codeRate": "CR_4_5" + } + } + } +} \ No newline at end of file diff --git a/VENDORS/Tektelic/Vivid/ChirpStack/uplink/result.json b/VENDORS/Tektelic/Vivid/ChirpStack/uplink/result.json new file mode 100644 index 00000000..0cad6f60 --- /dev/null +++ b/VENDORS/Tektelic/Vivid/ChirpStack/uplink/result.json @@ -0,0 +1,27 @@ +{ + "deviceName": "Device name 1000000000000001", + "deviceType": "Vivid", + "attributes": { + "eui": "1000000000000001", + "devAddr": "20000001", + "fPort": 10, + "applicationId": "ca739e26-7b67-4f14-b69e-d568c22a5a75", + "applicationName": "Chirpstack application", + "tenantId": "52f14cd4-c6f1-4fbd-8f87-4025e1d49242", + "tenantName": "ChirpStack", + "deviceProfileId": "605d08d4-65f5-4d2c-8a5a-3d2457662f79", + "deviceProfileName": "Chirpstack default device profile", + "frequency": 868500000, + "bandwidth": 125000, + "spreadingFactor": 7, + "codeRate": "CR_4_5" + }, + "telemetry": [{ + "ts": 1684741625404, + "values": { + "ambient_temperature": 22.5, + "relative_humidity": 38.5, + "battery_voltage": 2.974 + } + }] +} \ No newline at end of file diff --git a/VENDORS/Tektelic/Vivid/LORIOT/uplink/converter.json b/VENDORS/Tektelic/Vivid/LORIOT/uplink/converter.json new file mode 100644 index 00000000..c32b899d --- /dev/null +++ b/VENDORS/Tektelic/Vivid/LORIOT/uplink/converter.json @@ -0,0 +1,29 @@ +{ + "name": "Loriot Uplink Decoder for Vivid", + "type": "UPLINK", + "debugMode": false, + "debugSettings": { + "failuresEnabled": true, + "allEnabled": false, + "allEnabledUntil": 1733331880270 + }, + "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);\nvar deviceName = data.EUI;\nvar deviceType = \"Vivid\";\nvar groupName = null; // If groupName is not null - created device will be added to the entity group with such name.\nvar customerName = null; // If customerName is not null - created devices will be assigned to customer with such name. \n\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// If you want to parse incoming data somehow, you can add your code to this function.\n// input: bytes\n// expected output:\n// {\n// \"attributes\": {\"attributeKey\": \"attributeValue\"},\n// \"telemetry\": {\"telemetryKey\": \"telemetryValue\"}\n// }\n\nfunction decodePayload(input) {\n var output = { attributes: {}, telemetry: []};\n \n var decoded = {};\n var fPort = data.port;\n if(fPort == 10) {\n for(var i = 0; i < input.length - 2; ) {\n var key_1 = input[i++] & 0xff;\n var key_2 = input[i++] & 0xff;\n \n if(key_1 == 0x00 && key_2 == 0xBA) {\n decoded.battery_voltage = toFixed(parseBytesToInt(input, i, 2) * 0.001, 3);\n i += 2;\n }\n else if(key_1 == 0x01 && key_2 == 0x00) {\n val = parseBytesToInt(input, i, 1);\n switch (val){\n\t\t\t\t\tcase 0:\n\t\t\t\t\t\tdecoded.hall_effect_state = \"Magnet Present\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 255:\n\t\t\t\t\t\tdecoded.hall_effect_state = \"Magnet Absent\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tdecoded.hall_effect_state = \"Invalid\";\n\t\t\t\t}\n \n i += 1;\n }\n else if(key_1 == 0x08 && key_2 == 0x04) {\n decoded.hall_effect_count = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key_1 == 0x0C && key_2 == 0x00) {\n var val = parseBytesToInt(input, i, 1);\n \n switch (val){\n\t\t\t\t\tcase 0:\n\t\t\t\t\t\tdecoded.impact_alarm = \"Impact Alarm Inactive\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 255:\n\t\t\t\t\t\tdecoded.impact_alarm = \"Impact Alarm Active\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tdecoded.impact_alarm = \"Invalid\";\n\t\t\t\t}\n\t\t\t\t\n i += 1;\n }\n else if(key_1 == 0x05 && key_2 == 0x02) {\n decoded.impact_magnitude = toFixed(parseBytesToInt(input, i, 2) * 0.001, 3);\n i += 2;\n }\n else if(key_1 == 0x07 && key_2 == 0x71) {\n decoded.accelerationX = toFixed(parseBytesToInt(input, i + 4, 2) * 0.001, 3);\n decoded.accelerationY = toFixed(parseBytesToInt(input, i + 2, 2) * 0.001, 3);\n decoded.accelerationZ = toFixed(parseBytesToInt(input, i, 2) * 0.001, 3);\n i += 6;\n }\n else if(key_1 == 0x0E && key_2 == 0x00) {\n var val = parseBytesToInt(input, i, 1);\n\t\t\t\tswitch (val){\n\t\t\t\t\tcase 0:\n\t\t\t\t\t\tdecoded.extconnector_state = \"Low(short-circuit)\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 255:\n\t\t\t\t\t\tdecoded.extconnector_state = \"High(open-circuit)\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tdecoded.extconnector_state = \"Invalid\";\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\ti += 1;\n }\n else if(key_1 == 0x0F && key_2 == 0x04) {\n decoded.extconnector_count = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key_1 == 0x12 && key_2 == 0x04) {\n decoded.extconnector_total_count = parseBytesToInt(input, i, 4);\n i += 4;\n }\n else if(key_1 == 0x11 && key_2 == 0x02) {\n decoded.extconnector_analog = toFixed(parseBytesToInt(input, i, 2) * 0.001, 3);\n i += 2;\n }\n else if(key_1 == 0x0B && key_2 == 0x67) {\n decoded.mcu_temperature = toFixed(parseBytesToInt(input, i, 2) * 0.1, 1);\n i += 2;\n }\n else if(key_1 == 0x03 && key_2 == 0x67) {\n decoded.ambient_temperature = toFixed(parseBytesToInt(input, i, 2) * 0.1, 1);\n i += 2;\n }\n else if(key_1 == 0x04 && key_2 == 0x68) {\n decoded.relative_humidity = toFixed(parseBytesToInt(input, i, 1) * 0.5, 1);\n i += 1;\n }\n else if(key_1 == 0x02 && key_2 == 0x00) {\n var val = parseBytesToInt(input, i, 1);\n \n\t\t\t\tswitch (val){\n\t\t\t\t\tcase 0:\n\t\t\t\t\t\tdecoded.light_detected = \"Dark\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 255:\n\t\t\t\t\t\tdecoded.light_detected = \"Bright\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tdecoded.light_detected = \"Invalid\";\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\ti += 1;\n }\n else if(key_1 == 0x10 && key_2 == 0x02) {\n decoded.light_intensity = parseBytesToInt(input, i, 1);\n\t\t\t\t\n\t\t\t\ti += 1;\n }\n else if(key_1 == 0x0A && key_2 == 0x00) {\n var val = parseBytesToInt(input, i, 1);\n\t\t\t\t\n\t\t\t\tswitch (val){\n\t\t\t\t\tcase 0:\n\t\t\t\t\t\tdecoded.motion_event_state = \"None\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 255:\n\t\t\t\t\t\tdecoded.motion_event_state = \"Detected\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tdecoded.motion_event_state = \"Invalid\";\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\ti += 1;\n }\n else if(key_1 == 0x0D && key_2 == 0x04) {\n decoded.motion_event_count = parseBytesToInt(input, i, 2);\n\t\t\t\t\n\t\t\t\ti += 2;\n }\n }\n }\n else if(fPort == 0x05) {\n var key_1 = input[i++] & 0xff;\n var key_2 = input[i++] & 0xff;\n \n if(key_1 == 0x40 && key_2 == 0x06) {\n var val = input[i + 5];\n\t\t\tswitch (val){\n\t\t\t\tcase 1:\n\t\t\t\t\tdecoded_data.reset_diagnostics_reset_reason = \"Push-button reset\";\n\t\t\t\t\tbreak;\n\t\t\t\tcase 2:\n\t\t\t\t\tdecoded_data.reset_diagnostics_reset_reason = \"DL command rest\";\n\t\t\t\t\tbreak;\n\t\t\t\tcase 4:\n\t\t\t\t\tdecoded_data.reset_diagnostics_reset_reason = \"Independent watchdog reset\";\n\t\t\t\t\tbreak;\n\t\t\t\tcase 8:\n\t\t\t\t\tdecoded_data.reset_diagnostics_reset_reason = \"Power loss reset\";\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\tdecoded_data.reset_diagnostics_reset_reason = \"Invalid\";\n\t\t\t}\n\t\t\tdecoded_data.reset_diagnostics_power_loss_reset_count = input[i + 3];\n\t\t\tdecoded_data.reset_diagnostics_watchdog_reset_count = input[i + 2];\n\t\t\tdecoded_data.reset_diagnostics_dl_reset_count = input[i + 1];\n\t\t\tdecoded_data.reset_diagnostics_button_reset_count = input[i];\n }\n }\n else if (fPort == 100) {\n for(var i = 0; i < input.length -1; ) {\n var key = input[i++] & 0xff;\n \n if(key == 0x00) {\n output.attributes.eui = bytesToHex(java.util.Arrays.copyRange(input, i, i + 8));\n i += 8;\n }\n else if(key == 0x01) {\n output.attributes.app_eui = bytesToHex(java.util.Arrays.copyRange(input, i, i + 8));\n\t\t\t\ti += 8;\n }\n else if (key == 0x02) {\n output.attributes.app_key = bytesToHex(java.util.Arrays.copyRange(input, i, i + 16));\n i += 16;\n }\n else if (key == 0x03) {\n output.attributes.devAddr = bytesToHex(java.util.Arrays.copyRange(input, i, i + 4));\n i += 4;\n }\n else if(key == 0x04) {\n output.attributes.network_session_key = bytesToHex(java.util.Arrays.copyRange(input, i, i + 16));\n i += 16;\n }\n else if(key == 0x05) {\n output.attributes.app_session_key = bytesToHex(java.util.Arrays.copyRange(input, i, i + 16));\n i += 16;\n }\n else if(key == 0x10) {\n var val = (((input[i] << 8) | input[i + 1]) >> 15) & 1;\n switch (val){\n\t\t\t\t\tcase 0:\n\t\t\t\t\t\toutput.attributes.loramac_join_mode = \"ABP\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 1:\n\t\t\t\t\t\toutput.attributes.loramac_join_mode = \"OTAA\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\toutput.attributes.loramac_join_mode = \"Invalid\";\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\ti += 1;\n }\n else if (key == 0x11) {\n\t\t\t\tvar val = (((input[i] << 8) | input[i + 1]) >> 3) & 1;\n\t\t\t\toutput.attributes.adr = getEnableStatus(val);\n\t\t\t\t\n\t\t\t\tvar val = (((input[i] << 8) | input[i + 1]) >> 2) & 1;\n\t\t\t\toutput.attributes.duty_cycle = getEnableStatus(val);\n\t\t\t\t\n\t\t\t\tvar val = (((input[i] << 8) | input[i + 1]) >> 1) & 1;\n\t\t\t\t\n\t\t\t\tswitch (val) {\n\t\t\t\t\tcase 0:\n\t\t\t\t\t\toutput.attributes.sync_word = \"Private\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 1:\n\t\t\t\t\t\toutput.attributes.sync_word = \"Public\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\toutput.attributes.sync_word = \"Invalid\";\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tvar val = ((input[i] << 8) | input[i + 1]) & 1;\n\t\t\t\t\n\t\t\t\tswitch (val){\n\t\t\t\t\tcase 0:\n\t\t\t\t\t\toutput.attributes.confirm_mode = \"Unconfirmed\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 1:\n\t\t\t\t\t\toutput.attributes.confirm_mode = \"Confirmed\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t output.attributes.confirm_mode = \"Invalid\";\n\t\t\t\t}\n\t\t\t\ti += 2;\n }\n else if (key == 0x12) {\n output.attributes.dr_number = (((input[i] << 8) | input[i + 1]) >> 8) & 0xF;\n output.attributes.tx_power_number = ((input[i] << 8) | input[i + 1]) & 0xF;\n \n i +=2;\n }\n else if (key == 0x13) {\n output.attributes.frequency = (((input[i] << 32) | (input[i + 1] << 24) | (input[i + 2] << 16) | (input[i + 3] << 8) | input[i + 4]) >> 8) & 0xFFFFFFFF;\n output.attributes.dr_number_rx2 = input[i + 4] & 0xFF;\n \n i += 5;\n }\n else if(key == 0x19) {\n output.attributes.netid_msb = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x1A) {\n output.attributes.loramac_net_id_lsb = parseBytesToInt(input, i, 2);\n\t\t\t\ti += 2;\n }\n else if (key == 0x20) {\n output.attributes.seconds_per_core_tick = parseBytesToInt(input, i, 4);\n i += 4;\n }\n else if(key == 0x21) {\n output.attributes.tick_per_battery = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x22) {\n output.attributes.tick_per_ambient_temperature = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x23) {\n output.attributes.tick_per_relative_humidity = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x24) {\n output.attributes.tick_per_reed_switch = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x25) {\n output.attributes.tick_per_light = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x26) {\n output.attributes.tick_per_accelerometer = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x27) {\n output.attributes.tick_per_mcu_temperature = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x28) {\n output.attributes.tick_per_pir = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x29) {\n output.attributes.tick_per_external_connector = parseBytesToInt(input, i, 2);\n \n i += 2;\n }\n else if(key == 0x2A) {\n var bit0 = (input[i] >> 0) & 1;\n var bit1 = (input[i] >> 1) & 1;\n \n output.attributes.mode.rising_edge_enabled = getEnableStatus(bit0);\n output.attributes.mode.falling_edge_enabled = getEnableStatus(bit1);\n \n i += 1;\n }\n else if(key == 0x2B) {\n\t\t\t\toutput.attributes.reed_switch_count_threshold = parseBytesToInt(input, i, 2);\n\t\t\t\ti += 2;\n }\n else if(key == 0x2C) {\n var bit0 = (input[i] >> 0) & 1;\n var bit1 = (input[i] >> 1) & 1;\n \n output.attributes.reed_values_to_transmit_report_state_enabled = getOnOffStatus(bit0);\n output.attributes.reed_values_to_transmit_report_count_enabled = getOnOffStatus(bit1);\n \n i += 1;\n }\n else if(key == 0x2D) {\n var bit0 = (input[i] >> 0) & 1;\n var bit1 = (input[i] >> 1) & 1;\n var bit7 = (input[i] >> 7) & 1;\n \n output.attributes.external_mode_rising_edge_enabled_ex = getOnOffStatus(bit0);\n output.attributes.external_mode_falling_edge_enabled_ex = getOnOffStatus(bit1);\n \n switch (bit7){\n\t\t\t\t\tcase 0:\n\t\t\t\t\t\toutput.attributes.mode = \"Digital\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 1:\n\t\t\t\t\t output.attributes.mode = \"Analog\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\toutput.attributes.mode = \"Invalid\";\n\t\t\t\t}\n\t\t\t\t\n i += 1;\n }\n else if(key == 0x2E) {\n output.attributes.external_connector_count_threshold = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x2F) {\n var bit0 = (input[i] >> 0) & 1;\n var bit1 = (input[i] >> 1) & 1;\n var bit4 = (input[i] >> 4) & 1;\n \n output.attributes.external_values_to_transmit.report_state_enabled_ex = getOnOffStatus(bit0);\n output.attributes.external_values_to_transmit.report_count_enabled_ex = getOnOffStatus(bit1);\n output.attributes.external_values_to_transmit.count_type = bit4;\n i += 1;\n }\n else if(key == 0x30) {\n output.attributes.impact_event_threshold = toFixed(parseBytesToInt(input, i, 2) * 0x001, 3);\n i += 2;\n }\n else if(key == 0x31) {\n output.attributes.acceleration_event_threshold = toFixed(parseBytesToInt(input, i, 2) * 0.001, 3);\n i += 2;\n }\n else if(key == 0x32) {\n var bit0 = (input[i] >> 0) & 1;\n output.attributes.values_to_transmit.report_periodic_alarm_enabled = getOnOffStatus(bit0);\n \n var bit1 = (input[i] >> 1) & 1;\n output.attributes.values_to_transmit.report_periodic_magnitude_enabled = getOnOffStatus(bit1);\n \n var bit2 = (input[i] >> 2) & 1;\n output.attributes.values_to_transmit.report_periodic_vector_enabled = getOnOffStatus(bit2);\n \n var bit4 = (input[i] >> 4) & 1;\n output.attributes.values_to_transmit.report_event_magnitude_enabled = getOnOffStatus(bit4);\n \n var bit5 = (input[i] >> 5) & 1;\n output.attributes.values_to_transmit.report_event_vector_enabled = getOnOffStatus(bit5);\n \n i += 1;\n }\n else if(key == 0x33) {\n output.attributes.acceleration_impact_grace_period = parseBytesToInt(input, i, 2);\n\t\t\t\t\n\t\t\t\ti += 2;\n }\n else if (key == 0x34) {\n var bit0 = (input[i] >> 0) & 1;\n output.attributes.acceleration_mode.impact_threshold_enabled = getEnableStatus(bit0);\n \n var bit1 = (input[i] >> 1) & 1;\n\t\t\t\toutput.attributes.acceleration_mode.acceleration_threshold_enabled = getEnableStatus(bit1);\n\t\t\t\t\n\t\t\t\tvar bit4 = (input[i] >> 4) & 1;\n\t\t\t\toutput.attributes.acceleration_mode.xaxis_enabled = getEnableStatus(bit4);\n\t\t\t\t\n\t\t\t\tvar bit5 = (input[i] >> 5) & 1;\n\t\t\t\toutput.attributes.acceleration_mode.yaxis_enabled = getEnableStatus(bit5);\n\t\t\t\t\n\t\t\t\tvar bit6 = (input[i] >> 6) & 1;\n\t\t\t\toutput.attributes.acceleration_mode.zaxis_enabled = getEnableStatus(bit6);\n\t\t\t\t\n\t\t\t\tvar bit7 = (input[i] >> 7) & 1;\n\t\t\t\toutput.attributes.acceleration_mode.poweron = getOnOffStatus(bit7);\n\t\t\t\t\n\t\t\t\ti += 1;\n }\n else if (key == 0x35) {\n var val = (input[i] >> 1) & 0x03;\n\t\t\t\t\n\t\t\t\tswitch (val) {\n\t\t\t\t\tcase 1:\n\t\t\t\t\t\toutput.attributes.sensitivity_accelerometer_sample_rate = \"1 Hz\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 2:\n\t\t\t\t\t\toutput.attributes.sensitivity_accelerometer_sample_rate = \"10 Hz\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 3:\n\t\t\t\t\t\toutput.attributes.sensitivity_accelerometer_sample_rate = \"25 Hz\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 4:\n\t\t\t\t\t\toutput.attributes.sensitivity_accelerometer_sample_rate = \"50 Hz\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 5:\n\t\t\t\t\t\toutput.attributes.sensitivity_accelerometer_sample_rate = \"100 Hz\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 6:\n\t\t\t\t\t\toutput.attributes.sensitivity_accelerometer_sample_rate = \"200 Hz\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 7:\n\t\t\t\t\t\toutput.attributes.sensitivity_accelerometer_sample_rate = \"400 Hz\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\toutput.attributes.sensitivity_accelerometer_sample_rate = \"Invalid\";\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tvar val = (arg >> 4) & 0x03;\n\t\t\t\tswitch (val) {\n\t\t\t\t\tcase 0:\n\t\t\t\t\t\toutput.attributes.sensitivity_accelerometer_measurement_range = \"±2 g\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 1:\n\t\t\t\t\t\toutput.attributes.sensitivity_accelerometer_measurement_range = \"±4 g\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 2:\n\t\t\t\t\t\toutput.attributes.sensitivity_accelerometer_measurement_range = \"±8 g\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 3:\n\t\t\t\t\t\toutput.attributes.sensitivity_accelerometer_measurement_range = \"±16 g\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\toutput.attributes.sensitivity_accelerometer_measurement_range = \"Invalid\";\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\ti += 1;\n }\n else if (key == 0x36) {\n output.attributes.impact_alarm_grace_period = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if (key == 0x37) {\n output.attributes.impact_alarm_threshold_count = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if (key == 0x38) {\n output.attributes.impact_alarm_threshold_period = parseBytesToInt(input, i, 2);\n \n i += 2;\n }\n else if (key == 0x39) {\n output.attributes.temperature_relative_humidity_sample_period_idle = parseBytesToInt(input, i, 4);\n \n i += 4;\n }\n else if (key == 0x3A) {\n output.attributes.temperature_relative_humidity_sample_period_active = parseBytesToInt(input, i, 4);\n \n i += 4;\n }\n else if (key == 0x3B) {\n output.attributes.temperature_threshold_low_temp_threshold = parseBytesToInt(input, i, 1);\n output.attributes.temperature_threshold_high_temp_threshold = parseBytesToInt(input, i + 1, 1);\n \n i += 2;\n }\n else if (key == 0x3C) {\n var bit0 = (input[i] >> 0) & 1;\n output.attributes.ambient_temperature_threshold_enabled = getEnableStatus(bit0);\n \n i += 1;\n }\n else if (key == 0x3D) {\n output.attributes.rh_threshold.low_rh_threshold = parseBytesToInt(input, i, 1);\n output.attributes.rh_threshold.high_rh_threshold = parseBytesToInt(input, i + 1, 1);\n \n i += 2;\n }\n else if (key == 0x3E) {\n var bit0 = (input[i] >> 0) & 1;\n output.attributes.relative_humidity_threshold_enabled =getEnableStatus(bit0);\n \n i += 1;\n }\n else if (key == 0x40) {\n output.attributes.mcu_temperature_sample_period_idle = parseBytesToInt(input, i, 4);\n i += 4;\n }\n else if (key == 0x41) {\n output.attributes.mcu_temperature_sample_period_active = parseBytesToInt(input, i, 4);\n i += 4;\n }\n else if (key == 0x42) {\n output.attributes.mcu_temp_threshold_high_mcu_temp_threshold = input[i + 1];\n output.attributes.mcu_temp_threshold_low_mcu_temp_threshold = input[i];\n i += 4;\n }\n else if (key == 0x43) {\n var val = input[i] & 1;\n output.attributes.mcu_temperature_threshold_enabled = getEnableStatus(val);\n\n\t\t\t\ti += 2;\n }\n else if (key == 0x44) {\n output.attributes.analog_sample_period_idle = parseBytesToInt(input, i, 4);\n \n i += 4;\n }\n else if (key == 0x45) {\n output.attributes.analog_sample_period_active = parseBytesToInt(input, i, 4);\n \n i += 4;\n }\n else if(key == 0x46) {\n output.attributes.analog_threshold_high_analog_threshold = toFixed(parseBytesToInt(input, i + 2, 2) * 0.001, 3);\n\t\t\t\toutput.attributes.analog_threshold_low_analog_threshold = toFixed(parseBytesToInt(input, i, 2) * 0.001, 3);\n\t\t\t\ti += 4;\n }\n else if (key == 0x4A) {\n var bit0 = (input[i] >> 0) & 1;\n output.attributes.analog_input_threshold_enabled = getEnableStatus(bit0);\n \n i +=1;\n }\n else if (key == 0x47) {\n output.attributes.light_sample_period = parseBytesToInt(input, i, 4);\n \n i += 4;\n }\n else if (key == 0x48 ) {\n var val = (input[i] >> 7) & 1;\n output.attributes.light_thresholds.threshold_enabled = getEnableStatus(val);\n output.attributes.light_thresholds.threshold = input[i] & 0x3F;\n \n i += 1;\n }\n else if (key == 0x49) {\n var bit0 = (input[i] >> 0) & 1;\n output.attributes.light_values_to_transmit.state_reported = getEnableStatus(bit0);\n \n var bit1 = (input[i] >> 1) & 1;\n output.attributes.light_values_to_transmit.intensity_reported = getEnableStatus(bit1);\n \n i +=1;\n }\n else if (key == 0x50) {\n output.attributes.pir_grace_period = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if (key == 0x51) {\n output.attributes.pir_threshold = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if (key == 0x52) {\n output.attributes.pir_threshold_period = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if (key == 0x53) {\n var bit7 = (input[i] >> 7) & 1;\n output.attributes.pir_mode.motion_count_reported = getEnableStatus(bit7);\n \n var bit6 = (input[i] >> pir_mode) & 1;\n output.attributes.pir_mode.motion_state_reported = getEnableStatus(bit6);\n \n var bit1 = (input[i] >> 1) & 1;\n output.attributes.pir_mode.event_transmission_enabled = getEnableStatus(bit1);\n \n var bit0 = (input[i] >> 0) & 1;\n output.attributes.pir_mode.transducer_enabled = getEnableStatus(bit0);\n \n i += 1;\n }\n else if (key == 0x54) {\n output.attributes.pir_mode.motion_count_reported = input[i + 1];\n output.attributes.pir_mode.motion_state_reported = input[i];\n \n i += 1;\n }\n else if (key == 0x6F) {\n var val = (input[i] >> 0) & 1;\n \n switch (val){\n\t\t\t\t\tcase 0:\n\t\t\t\t\t\toutput.attributes_resp_to_dl_command_format = \"Invalid-write response format\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 1:\n\t\t\t\t\t\toutput.attributes_resp_to_dl_command_format = \"4-byte CRC\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\toutput.attributes_resp_to_dl_command_format = \"Invalid\";\n\t\t\t\t}\n \n i += 1;\n }\n else if (key == 0x71) {\n output.attributes.app_major_version = input[i + 6];\n\t\t\t\toutput.attributes.app_minor_version = input[i + 5];\n\t\t\t\toutput.attributes.app_revision = input[i + 4];\n\t\t\t\toutput.attributes.loramac_major_version = input[i + 3];\n\t\t\t\toutput.attributes.loramac_minor_version = input[i + 2];\n\t\t\t\toutput.attributes.loramac_revision = input[i + 1];\n\t\t\t\tvar val = input[i];\n\t\t\t\tswitch (val){\n\t\t\t\t\tcase 0:\n\t\t\t\t\t\toutput.attributes.region = \"EU868\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 1:\n\t\t\t\t\t\toutput.attributes.region = \"US915\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 2:\n\t\t\t\t\t\toutput.attributes.region = \"AS923\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 3:\n\t\t\t\t\t\toutput.attributes.region = \"AU915\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 4:\n\t\t\t\t\t\toutput.attributes.region = \"IN865\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 6:\n\t\t\t\t\t\toutput.attributes.region = \"KR920\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 7:\n\t\t\t\t\t\toutput.attributes.region = \"RU864\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\toutput.attributes.region = \"Invalid\";\n\t\t\t\t}\n\t\t\t\ti += 7;\n }\n }\n }\n else if (fPort == 101) {\n var size = input.length;\n var responses = [];\n \n var index = 0;\n while (index < size) {\n var downlinkFcnt = input[index++] & 0xFF; \n var numInvalidWrites = input[index++] & 0xFF; \n \n if (numInvalidWrites > 0) {\n var invalidRegisters = [];\n for (var i = 0; i < numInvalidWrites; i++) {\n invalidRegisters.add(String.format(\"0x%02X\", input[index + i]));\n }\n index += numInvalidWrites;\n \n responses.add(String.format(\n \"%d Invalid write command(s) from DL:%d for register(s): %s\",\n numInvalidWrites, downlinkFcnt, String.join(\", \", invalidRegisters)\n ));\n } else {\n responses.add(String.format(\"All write commands from DL:%d were successful\", downlinkFcnt));\n }\n }\n \n decoded.response = responses;\n }\n \n output.telemetry = [{\n ts: timestamp,\n values: decoded\n }];\n\n // --- Decoding code --- //\n return output;\n}\n\n// --- attributes and telemetry objects ---\nvar telemetry = [];\nvar attributes = {};\n// --- attributes and telemetry objects ---\n\n// --- Timestamp parsing\ntimestamp = data.ts;\n// --- Timestamp parsing\n\n// Message parsing\n// To avoid paths in the decoded objects we passing false value to function as \"pathInKey\" argument.\n// Warning: pathInKey can cause already found fields to be overwritten with the last value found.\n\nvar uplinkDataList = [];\n\n// Passing incoming bytes to decodePayload function, to get custom decoding\nvar customDecoding = decodePayload(hexToBytes(data.data));\n\n// Collecting data to result\nif (customDecoding.?telemetry.size() > 0) {\n if (customDecoding.telemetry instanceof java.util.ArrayList) {\n foreach(telemetryObj: customDecoding.telemetry) {\n if (telemetryObj.ts != null && telemetryObj.values != null) {\n telemetry.add(telemetryObj);\n }\n }\n } else {\n telemetry.putAll(customDecoding.telemetry);\n }\n}\n\nif (customDecoding.?attributes.size() > 0) {\n attributes.putAll(customDecoding.attributes);\n}\n\n// You can add some keys manually to attributes or telemetry\nattributes.eui = data.EUI;\nattributes.fPort = data.port;\nattributes.frequency = data.freq;\n\nvar isIncludeGatewayInfo = metadata[\"includeGatewayInfo\"];\nif(isIncludeGatewayInfo == true) {\n var addDataToTelemetry = {};\n addDataToTelemetry.rssi = data.rssi;\n addDataToTelemetry.seqno = data.seqno;\n addDataToTelemetry.snr = data.snr;\n addDataToTelemetry.ack = data.ack;\n addDataToTelemetry.toa = data.toa;\n addDataToTelemetry.fCnt = data.fcnt;\n \n telemetry = processTelemetryData(telemetry, addDataToTelemetry);\n}\n\nvar deviceInfo = {\n deviceName: deviceName,\n deviceType: deviceType,\n// assetName: assetName,\n// assetType: assetType,\n attributes: attributes,\n telemetry: telemetry, \n};\n\naddAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName);\n\nuplinkDataList.add(deviceInfo);\n\nvar gatewayDeviceNamePrefix = \"Gateway \";\nvar gatewayDeviceType = \"Lora gateway\";\nvar gatewayGroupName = null; // If gatewayGroupName is not null - created device will be added to the entity group with such name.\n\nif (data.cmd == \"gw\") {\n foreach( gatewayInfo : data.gws ) {\n var addGatewayInfo = {};\n\n // You can add some keys manually telemetry\n addGatewayInfo.rssi = gatewayInfo.rssi;\n addGatewayInfo.snr = gatewayInfo.snr;\n // You can add some keys manually telemetry\n \n var gatewayInfoMsg = {\n deviceName: gatewayDeviceNamePrefix + gatewayInfo.gweui,\n deviceType: gatewayDeviceType,\n telemetry: [{\n \"ts\": gatewayInfo.ts,\n \"values\": addGatewayInfo\n }],\n attributes: {\n eui: gatewayInfo.gweui\n }\n };\n addAdditionalInfoForDeviceMsg(gatewayInfoMsg, customerName, gatewayGroupName);\n uplinkDataList.add(gatewayInfoMsg);\n }\n}\n\nreturn uplinkDataList;\n\nfunction addAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName) {\n if (customerName != null) {\n deviceInfo.customerName = customerName;\n }\n if (groupName != null) {\n deviceInfo.groupName = groupName;\n }\n}\n\nfunction processTelemetryData(telemetry, addDataToTelemetry) {\n if (telemetry.size >= 1) {\n telemetry = addDataToTelemetries(telemetry, addDataToTelemetry);\n }\n else {\n telemetry.add(addDataToTelemetry);\n }\n \n return telemetry;\n}\n\nfunction addDataToTelemetries(telemetries, addDataToTelemetry) {\n foreach(telemetry : telemetries) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[\"values\"].keys.contains(element.key)) {\n telemetry[\"values\"][element.key] = element.value;\n }\n } \n }\n \n return telemetries;\n}\n\nfunction getEnableStatus(bit) {\n var enableResult = \"Invalid\";\n \n switch (bit) {\n\t\tcase 0:\n\t\t enableResult = \"Disable\";\n\t\t\tbreak;\n\t\tcase 1:\n\t\t\tenableResult = \"Enable\";\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tenableResult = \"Invalid\";\n\t}\n \n return enableResult;\n}\n\nfunction getOnOffStatus(bit) {\n var reportResult = \"Invalid\";\n \n switch (bit) {\n case 0:\n reportResult = \"Off\";\n break;\n case 1:\n reportResult = \"On\";\n break;\n default:\n reportResult = \"Invalid\";\n }\n \n return reportResult;\n}", + "encoder": null, + "tbelEncoder": null, + "updateOnlyKeys": [ + "fPort", + "ack", + "eui", + "frequency", + "dr", + "battery" + ] + }, + "additionalInfo": { + "description": "" + }, + "edgeTemplate": false +} \ No newline at end of file diff --git a/VENDORS/Tektelic/Vivid/LORIOT/uplink/metadata.json b/VENDORS/Tektelic/Vivid/LORIOT/uplink/metadata.json new file mode 100644 index 00000000..ae2ee743 --- /dev/null +++ b/VENDORS/Tektelic/Vivid/LORIOT/uplink/metadata.json @@ -0,0 +1,4 @@ +{ + "integrationName": "Loriot integration", + "includeGatewayInfo": "false" +} \ No newline at end of file diff --git a/VENDORS/Tektelic/Vivid/LORIOT/uplink/payload.json b/VENDORS/Tektelic/Vivid/LORIOT/uplink/payload.json new file mode 100644 index 00000000..b930d85b --- /dev/null +++ b/VENDORS/Tektelic/Vivid/LORIOT/uplink/payload.json @@ -0,0 +1,17 @@ +{ + "cmd": "rx", + "seqno": 3040, + "EUI": "1000000000000001", + "ts": 1684478801936, + "fcnt": 2, + "port": 10, + "freq": 867500000, + "rssi": -21, + "snr": 10, + "toa": 206, + "dr": "SF9 BW125 4/5", + "ack": false, + "bat": 94, + "offline": false, + "data": "036700E104684D00BA0B9E" +} \ No newline at end of file diff --git a/VENDORS/Tektelic/Vivid/LORIOT/uplink/result.json b/VENDORS/Tektelic/Vivid/LORIOT/uplink/result.json new file mode 100644 index 00000000..f9ed2eb9 --- /dev/null +++ b/VENDORS/Tektelic/Vivid/LORIOT/uplink/result.json @@ -0,0 +1,17 @@ +[{ + "deviceName": "1000000000000001", + "deviceType": "vivid", + "attributes": { + "eui": "1000000000000001", + "fPort": 10, + "frequency": 867500000 + }, + "telemetry": [{ + "ts": 1684478801936, + "values": { + "ambient_temperature": 22.5, + "relative_humidity": 38.5, + "battery_voltage": 2.974 + } + }] +}] \ No newline at end of file diff --git a/VENDORS/Tektelic/Vivid/ThingsStackCommunity/uplink/converter.json b/VENDORS/Tektelic/Vivid/ThingsStackCommunity/uplink/converter.json new file mode 100644 index 00000000..d3f28a84 --- /dev/null +++ b/VENDORS/Tektelic/Vivid/ThingsStackCommunity/uplink/converter.json @@ -0,0 +1,39 @@ +{ + "name": "The Things Stack Community Uplink Decoder for Vivid", + "type": "UPLINK", + "debugMode": false, + "debugSettings": { + "failuresEnabled": true, + "allEnabled": false, + "allEnabledUntil": 1733331880270 + }, + "configuration": { + "scriptLang": "TBEL", + "decoder": null, + "tbelDecoder": "var data = decodeToJson(payload);\n\nvar deviceName = data.end_device_ids.device_id;\nvar deviceType = \"Vivid\";\nvar groupName = null; // If groupName is not null - created device will be added to the entity group with such name.\nvar customerName = null; // If customerName is not null - created devices will be assigned to customer with such name. \n\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// If you want to parse incoming data somehow, you can add your code to this function.\n// input: bytes\n// expected output:\n// {\n// \"attributes\": {\"attributeKey\": \"attributeValue\"},\n// \"telemetry\": [{\"ts\": 1...1, \"values\": {\"telemetryKey\":\"telemetryValue\"}, {\"ts\": 1...2, \"values\": {\"telemetryKey\":\"telemetryValue\"}}]\n// }\n\nfunction decodeFrmPayload(input) {\n var output = {\n attributes: {}, telemetry: {}\n };\n \n // --- Decoding code --- //\n var decoded = {};\n var fPort = data.uplink_message.f_port;\n if(fPort == 10) {\n for(var i = 0; i < input.length - 2; ) {\n var key_1 = input[i++] & 0xff;\n var key_2 = input[i++] & 0xff;\n \n if(key_1 == 0x00 && key_2 == 0xBA) {\n decoded.battery_voltage = toFixed(parseBytesToInt(input, i, 2) * 0.001, 3);\n i += 2;\n }\n else if(key_1 == 0x01 && key_2 == 0x00) {\n val = parseBytesToInt(input, i, 1);\n switch (val){\n\t\t\t\t\tcase 0:\n\t\t\t\t\t\tdecoded.hall_effect_state = \"Magnet Present\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 255:\n\t\t\t\t\t\tdecoded.hall_effect_state = \"Magnet Absent\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tdecoded.hall_effect_state = \"Invalid\";\n\t\t\t\t}\n \n i += 1;\n }\n else if(key_1 == 0x08 && key_2 == 0x04) {\n decoded.hall_effect_count = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key_1 == 0x0C && key_2 == 0x00) {\n var val = parseBytesToInt(input, i, 1);\n \n switch (val){\n\t\t\t\t\tcase 0:\n\t\t\t\t\t\tdecoded.impact_alarm = \"Impact Alarm Inactive\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 255:\n\t\t\t\t\t\tdecoded.impact_alarm = \"Impact Alarm Active\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tdecoded.impact_alarm = \"Invalid\";\n\t\t\t\t}\n\t\t\t\t\n i += 1;\n }\n else if(key_1 == 0x05 && key_2 == 0x02) {\n decoded.impact_magnitude = toFixed(parseBytesToInt(input, i, 2) * 0.001, 3);\n i += 2;\n }\n else if(key_1 == 0x07 && key_2 == 0x71) {\n decoded.accelerationX = toFixed(parseBytesToInt(input, i + 4, 2) * 0.001, 3);\n decoded.accelerationY = toFixed(parseBytesToInt(input, i + 2, 2) * 0.001, 3);\n decoded.accelerationZ = toFixed(parseBytesToInt(input, i, 2) * 0.001, 3);\n i += 6;\n }\n else if(key_1 == 0x0E && key_2 == 0x00) {\n var val = parseBytesToInt(input, i, 1);\n\t\t\t\tswitch (val){\n\t\t\t\t\tcase 0:\n\t\t\t\t\t\tdecoded.extconnector_state = \"Low(short-circuit)\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 255:\n\t\t\t\t\t\tdecoded.extconnector_state = \"High(open-circuit)\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tdecoded.extconnector_state = \"Invalid\";\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\ti += 1;\n }\n else if(key_1 == 0x0F && key_2 == 0x04) {\n decoded.extconnector_count = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key_1 == 0x12 && key_2 == 0x04) {\n decoded.extconnector_total_count = parseBytesToInt(input, i, 4);\n i += 4;\n }\n else if(key_1 == 0x11 && key_2 == 0x02) {\n decoded.extconnector_analog = toFixed(parseBytesToInt(input, i, 2) * 0.001, 3);\n i += 2;\n }\n else if(key_1 == 0x0B && key_2 == 0x67) {\n decoded.mcu_temperature = toFixed(parseBytesToInt(input, i, 2) * 0.1, 1);\n i += 2;\n }\n else if(key_1 == 0x03 && key_2 == 0x67) {\n decoded.ambient_temperature = toFixed(parseBytesToInt(input, i, 2) * 0.1, 1);\n i += 2;\n }\n else if(key_1 == 0x04 && key_2 == 0x68) {\n decoded.relative_humidity = toFixed(parseBytesToInt(input, i, 1) * 0.5, 1);\n i += 1;\n }\n else if(key_1 == 0x02 && key_2 == 0x00) {\n var val = parseBytesToInt(input, i, 1);\n \n\t\t\t\tswitch (val){\n\t\t\t\t\tcase 0:\n\t\t\t\t\t\tdecoded.light_detected = \"Dark\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 255:\n\t\t\t\t\t\tdecoded.light_detected = \"Bright\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tdecoded.light_detected = \"Invalid\";\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\ti += 1;\n }\n else if(key_1 == 0x10 && key_2 == 0x02) {\n decoded.light_intensity = parseBytesToInt(input, i, 1);\n\t\t\t\t\n\t\t\t\ti += 1;\n }\n else if(key_1 == 0x0A && key_2 == 0x00) {\n var val = parseBytesToInt(input, i, 1);\n\t\t\t\t\n\t\t\t\tswitch (val){\n\t\t\t\t\tcase 0:\n\t\t\t\t\t\tdecoded.motion_event_state = \"None\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 255:\n\t\t\t\t\t\tdecoded.motion_event_state = \"Detected\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tdecoded.motion_event_state = \"Invalid\";\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\ti += 1;\n }\n else if(key_1 == 0x0D && key_2 == 0x04) {\n decoded.motion_event_count = parseBytesToInt(input, i, 2);\n\t\t\t\t\n\t\t\t\ti += 2;\n }\n }\n }\n else if(fPort == 0x05) {\n var key_1 = input[i++] & 0xff;\n var key_2 = input[i++] & 0xff;\n \n if(key_1 == 0x40 && key_2 == 0x06) {\n var val = input[i + 5];\n\t\t\tswitch (val){\n\t\t\t\tcase 1:\n\t\t\t\t\tdecoded_data.reset_diagnostics_reset_reason = \"Push-button reset\";\n\t\t\t\t\tbreak;\n\t\t\t\tcase 2:\n\t\t\t\t\tdecoded_data.reset_diagnostics_reset_reason = \"DL command rest\";\n\t\t\t\t\tbreak;\n\t\t\t\tcase 4:\n\t\t\t\t\tdecoded_data.reset_diagnostics_reset_reason = \"Independent watchdog reset\";\n\t\t\t\t\tbreak;\n\t\t\t\tcase 8:\n\t\t\t\t\tdecoded_data.reset_diagnostics_reset_reason = \"Power loss reset\";\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\tdecoded_data.reset_diagnostics_reset_reason = \"Invalid\";\n\t\t\t}\n\t\t\tdecoded_data.reset_diagnostics_power_loss_reset_count = input[i + 3];\n\t\t\tdecoded_data.reset_diagnostics_watchdog_reset_count = input[i + 2];\n\t\t\tdecoded_data.reset_diagnostics_dl_reset_count = input[i + 1];\n\t\t\tdecoded_data.reset_diagnostics_button_reset_count = input[i];\n }\n }\n else if (fPort == 100) {\n for(var i = 0; i < input.length -1; ) {\n var key = input[i++] & 0xff;\n \n if(key == 0x00) {\n output.attributes.eui = bytesToHex(java.util.Arrays.copyRange(input, i, i + 8));\n i += 8;\n }\n else if(key == 0x01) {\n output.attributes.app_eui = bytesToHex(java.util.Arrays.copyRange(input, i, i + 8));\n\t\t\t\ti += 8;\n }\n else if (key == 0x02) {\n output.attributes.app_key = bytesToHex(java.util.Arrays.copyRange(input, i, i + 16));\n i += 16;\n }\n else if (key == 0x03) {\n output.attributes.devAddr = bytesToHex(java.util.Arrays.copyRange(input, i, i + 4));\n i += 4;\n }\n else if(key == 0x04) {\n output.attributes.network_session_key = bytesToHex(java.util.Arrays.copyRange(input, i, i + 16));\n i += 16;\n }\n else if(key == 0x05) {\n output.attributes.app_session_key = bytesToHex(java.util.Arrays.copyRange(input, i, i + 16));\n i += 16;\n }\n else if(key == 0x10) {\n var val = (((input[i] << 8) | input[i + 1]) >> 15) & 1;\n switch (val){\n\t\t\t\t\tcase 0:\n\t\t\t\t\t\toutput.attributes.loramac_join_mode = \"ABP\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 1:\n\t\t\t\t\t\toutput.attributes.loramac_join_mode = \"OTAA\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\toutput.attributes.loramac_join_mode = \"Invalid\";\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\ti += 1;\n }\n else if (key == 0x11) {\n\t\t\t\tvar val = (((input[i] << 8) | input[i + 1]) >> 3) & 1;\n\t\t\t\toutput.attributes.adr = getEnableStatus(val);\n\t\t\t\t\n\t\t\t\tvar val = (((input[i] << 8) | input[i + 1]) >> 2) & 1;\n\t\t\t\toutput.attributes.duty_cycle = getEnableStatus(val);\n\t\t\t\t\n\t\t\t\tvar val = (((input[i] << 8) | input[i + 1]) >> 1) & 1;\n\t\t\t\t\n\t\t\t\tswitch (val) {\n\t\t\t\t\tcase 0:\n\t\t\t\t\t\toutput.attributes.sync_word = \"Private\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 1:\n\t\t\t\t\t\toutput.attributes.sync_word = \"Public\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\toutput.attributes.sync_word = \"Invalid\";\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tvar val = ((input[i] << 8) | input[i + 1]) & 1;\n\t\t\t\t\n\t\t\t\tswitch (val){\n\t\t\t\t\tcase 0:\n\t\t\t\t\t\toutput.attributes.confirm_mode = \"Unconfirmed\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 1:\n\t\t\t\t\t\toutput.attributes.confirm_mode = \"Confirmed\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t output.attributes.confirm_mode = \"Invalid\";\n\t\t\t\t}\n\t\t\t\ti += 2;\n }\n else if (key == 0x12) {\n output.attributes.dr_number = (((input[i] << 8) | input[i + 1]) >> 8) & 0xF;\n output.attributes.tx_power_number = ((input[i] << 8) | input[i + 1]) & 0xF;\n \n i +=2;\n }\n else if (key == 0x13) {\n output.attributes.frequency = (((input[i] << 32) | (input[i + 1] << 24) | (input[i + 2] << 16) | (input[i + 3] << 8) | input[i + 4]) >> 8) & 0xFFFFFFFF;\n output.attributes.dr_number_rx2 = input[i + 4] & 0xFF;\n \n i += 5;\n }\n else if(key == 0x19) {\n output.attributes.netid_msb = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x1A) {\n output.attributes.loramac_net_id_lsb = parseBytesToInt(input, i, 2);\n\t\t\t\ti += 2;\n }\n else if (key == 0x20) {\n output.attributes.seconds_per_core_tick = parseBytesToInt(input, i, 4);\n i += 4;\n }\n else if(key == 0x21) {\n output.attributes.tick_per_battery = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x22) {\n output.attributes.tick_per_ambient_temperature = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x23) {\n output.attributes.tick_per_relative_humidity = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x24) {\n output.attributes.tick_per_reed_switch = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x25) {\n output.attributes.tick_per_light = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x26) {\n output.attributes.tick_per_accelerometer = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x27) {\n output.attributes.tick_per_mcu_temperature = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x28) {\n output.attributes.tick_per_pir = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x29) {\n output.attributes.tick_per_external_connector = parseBytesToInt(input, i, 2);\n \n i += 2;\n }\n else if(key == 0x2A) {\n var bit0 = (input[i] >> 0) & 1;\n var bit1 = (input[i] >> 1) & 1;\n \n output.attributes.mode.rising_edge_enabled = getEnableStatus(bit0);\n output.attributes.mode.falling_edge_enabled = getEnableStatus(bit1);\n \n i += 1;\n }\n else if(key == 0x2B) {\n\t\t\t\toutput.attributes.reed_switch_count_threshold = parseBytesToInt(input, i, 2);\n\t\t\t\ti += 2;\n }\n else if(key == 0x2C) {\n var bit0 = (input[i] >> 0) & 1;\n var bit1 = (input[i] >> 1) & 1;\n \n output.attributes.reed_values_to_transmit_report_state_enabled = getOnOffStatus(bit0);\n output.attributes.reed_values_to_transmit_report_count_enabled = getOnOffStatus(bit1);\n \n i += 1;\n }\n else if(key == 0x2D) {\n var bit0 = (input[i] >> 0) & 1;\n var bit1 = (input[i] >> 1) & 1;\n var bit7 = (input[i] >> 7) & 1;\n \n output.attributes.external_mode_rising_edge_enabled_ex = getOnOffStatus(bit0);\n output.attributes.external_mode_falling_edge_enabled_ex = getOnOffStatus(bit1);\n \n switch (bit7){\n\t\t\t\t\tcase 0:\n\t\t\t\t\t\toutput.attributes.mode = \"Digital\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 1:\n\t\t\t\t\t output.attributes.mode = \"Analog\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\toutput.attributes.mode = \"Invalid\";\n\t\t\t\t}\n\t\t\t\t\n i += 1;\n }\n else if(key == 0x2E) {\n output.attributes.external_connector_count_threshold = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x2F) {\n var bit0 = (input[i] >> 0) & 1;\n var bit1 = (input[i] >> 1) & 1;\n var bit4 = (input[i] >> 4) & 1;\n \n output.attributes.external_values_to_transmit.report_state_enabled_ex = getOnOffStatus(bit0);\n output.attributes.external_values_to_transmit.report_count_enabled_ex = getOnOffStatus(bit1);\n output.attributes.external_values_to_transmit.count_type = bit4;\n i += 1;\n }\n else if(key == 0x30) {\n output.attributes.impact_event_threshold = toFixed(parseBytesToInt(input, i, 2) * 0x001, 3);\n i += 2;\n }\n else if(key == 0x31) {\n output.attributes.acceleration_event_threshold = toFixed(parseBytesToInt(input, i, 2) * 0.001, 3);\n i += 2;\n }\n else if(key == 0x32) {\n var bit0 = (input[i] >> 0) & 1;\n output.attributes.values_to_transmit.report_periodic_alarm_enabled = getOnOffStatus(bit0);\n \n var bit1 = (input[i] >> 1) & 1;\n output.attributes.values_to_transmit.report_periodic_magnitude_enabled = getOnOffStatus(bit1);\n \n var bit2 = (input[i] >> 2) & 1;\n output.attributes.values_to_transmit.report_periodic_vector_enabled = getOnOffStatus(bit2);\n \n var bit4 = (input[i] >> 4) & 1;\n output.attributes.values_to_transmit.report_event_magnitude_enabled = getOnOffStatus(bit4);\n \n var bit5 = (input[i] >> 5) & 1;\n output.attributes.values_to_transmit.report_event_vector_enabled = getOnOffStatus(bit5);\n \n i += 1;\n }\n else if(key == 0x33) {\n output.attributes.acceleration_impact_grace_period = parseBytesToInt(input, i, 2);\n\t\t\t\t\n\t\t\t\ti += 2;\n }\n else if (key == 0x34) {\n var bit0 = (input[i] >> 0) & 1;\n output.attributes.acceleration_mode.impact_threshold_enabled = getEnableStatus(bit0);\n \n var bit1 = (input[i] >> 1) & 1;\n\t\t\t\toutput.attributes.acceleration_mode.acceleration_threshold_enabled = getEnableStatus(bit1);\n\t\t\t\t\n\t\t\t\tvar bit4 = (input[i] >> 4) & 1;\n\t\t\t\toutput.attributes.acceleration_mode.xaxis_enabled = getEnableStatus(bit4);\n\t\t\t\t\n\t\t\t\tvar bit5 = (input[i] >> 5) & 1;\n\t\t\t\toutput.attributes.acceleration_mode.yaxis_enabled = getEnableStatus(bit5);\n\t\t\t\t\n\t\t\t\tvar bit6 = (input[i] >> 6) & 1;\n\t\t\t\toutput.attributes.acceleration_mode.zaxis_enabled = getEnableStatus(bit6);\n\t\t\t\t\n\t\t\t\tvar bit7 = (input[i] >> 7) & 1;\n\t\t\t\toutput.attributes.acceleration_mode.poweron = getOnOffStatus(bit7);\n\t\t\t\t\n\t\t\t\ti += 1;\n }\n else if (key == 0x35) {\n var val = (input[i] >> 1) & 0x03;\n\t\t\t\t\n\t\t\t\tswitch (val) {\n\t\t\t\t\tcase 1:\n\t\t\t\t\t\toutput.attributes.sensitivity_accelerometer_sample_rate = \"1 Hz\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 2:\n\t\t\t\t\t\toutput.attributes.sensitivity_accelerometer_sample_rate = \"10 Hz\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 3:\n\t\t\t\t\t\toutput.attributes.sensitivity_accelerometer_sample_rate = \"25 Hz\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 4:\n\t\t\t\t\t\toutput.attributes.sensitivity_accelerometer_sample_rate = \"50 Hz\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 5:\n\t\t\t\t\t\toutput.attributes.sensitivity_accelerometer_sample_rate = \"100 Hz\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 6:\n\t\t\t\t\t\toutput.attributes.sensitivity_accelerometer_sample_rate = \"200 Hz\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 7:\n\t\t\t\t\t\toutput.attributes.sensitivity_accelerometer_sample_rate = \"400 Hz\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\toutput.attributes.sensitivity_accelerometer_sample_rate = \"Invalid\";\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tvar val = (arg >> 4) & 0x03;\n\t\t\t\tswitch (val) {\n\t\t\t\t\tcase 0:\n\t\t\t\t\t\toutput.attributes.sensitivity_accelerometer_measurement_range = \"±2 g\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 1:\n\t\t\t\t\t\toutput.attributes.sensitivity_accelerometer_measurement_range = \"±4 g\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 2:\n\t\t\t\t\t\toutput.attributes.sensitivity_accelerometer_measurement_range = \"±8 g\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 3:\n\t\t\t\t\t\toutput.attributes.sensitivity_accelerometer_measurement_range = \"±16 g\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\toutput.attributes.sensitivity_accelerometer_measurement_range = \"Invalid\";\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\ti += 1;\n }\n else if (key == 0x36) {\n output.attributes.impact_alarm_grace_period = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if (key == 0x37) {\n output.attributes.impact_alarm_threshold_count = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if (key == 0x38) {\n output.attributes.impact_alarm_threshold_period = parseBytesToInt(input, i, 2);\n \n i += 2;\n }\n else if (key == 0x39) {\n output.attributes.temperature_relative_humidity_sample_period_idle = parseBytesToInt(input, i, 4);\n \n i += 4;\n }\n else if (key == 0x3A) {\n output.attributes.temperature_relative_humidity_sample_period_active = parseBytesToInt(input, i, 4);\n \n i += 4;\n }\n else if (key == 0x3B) {\n output.attributes.temperature_threshold_low_temp_threshold = parseBytesToInt(input, i, 1);\n output.attributes.temperature_threshold_high_temp_threshold = parseBytesToInt(input, i + 1, 1);\n \n i += 2;\n }\n else if (key == 0x3C) {\n var bit0 = (input[i] >> 0) & 1;\n output.attributes.ambient_temperature_threshold_enabled = getEnableStatus(bit0);\n \n i += 1;\n }\n else if (key == 0x3D) {\n output.attributes.rh_threshold.low_rh_threshold = parseBytesToInt(input, i, 1);\n output.attributes.rh_threshold.high_rh_threshold = parseBytesToInt(input, i + 1, 1);\n \n i += 2;\n }\n else if (key == 0x3E) {\n var bit0 = (input[i] >> 0) & 1;\n output.attributes.relative_humidity_threshold_enabled =getEnableStatus(bit0);\n \n i += 1;\n }\n else if (key == 0x40) {\n output.attributes.mcu_temperature_sample_period_idle = parseBytesToInt(input, i, 4);\n i += 4;\n }\n else if (key == 0x41) {\n output.attributes.mcu_temperature_sample_period_active = parseBytesToInt(input, i, 4);\n i += 4;\n }\n else if (key == 0x42) {\n output.attributes.mcu_temp_threshold_high_mcu_temp_threshold = input[i + 1];\n output.attributes.mcu_temp_threshold_low_mcu_temp_threshold = input[i];\n i += 4;\n }\n else if (key == 0x43) {\n var val = input[i] & 1;\n output.attributes.mcu_temperature_threshold_enabled = getEnableStatus(val);\n\n\t\t\t\ti += 2;\n }\n else if (key == 0x44) {\n output.attributes.analog_sample_period_idle = parseBytesToInt(input, i, 4);\n \n i += 4;\n }\n else if (key == 0x45) {\n output.attributes.analog_sample_period_active = parseBytesToInt(input, i, 4);\n \n i += 4;\n }\n else if(key == 0x46) {\n output.attributes.analog_threshold_high_analog_threshold = toFixed(parseBytesToInt(input, i + 2, 2) * 0.001, 3);\n\t\t\t\toutput.attributes.analog_threshold_low_analog_threshold = toFixed(parseBytesToInt(input, i, 2) * 0.001, 3);\n\t\t\t\ti += 4;\n }\n else if (key == 0x4A) {\n var bit0 = (input[i] >> 0) & 1;\n output.attributes.analog_input_threshold_enabled = getEnableStatus(bit0);\n \n i +=1;\n }\n else if (key == 0x47) {\n output.attributes.light_sample_period = parseBytesToInt(input, i, 4);\n \n i += 4;\n }\n else if (key == 0x48 ) {\n var val = (input[i] >> 7) & 1;\n output.attributes.light_thresholds.threshold_enabled = getEnableStatus(val);\n output.attributes.light_thresholds.threshold = input[i] & 0x3F;\n \n i += 1;\n }\n else if (key == 0x49) {\n var bit0 = (input[i] >> 0) & 1;\n output.attributes.light_values_to_transmit.state_reported = getEnableStatus(bit0);\n \n var bit1 = (input[i] >> 1) & 1;\n output.attributes.light_values_to_transmit.intensity_reported = getEnableStatus(bit1);\n \n i +=1;\n }\n else if (key == 0x50) {\n output.attributes.pir_grace_period = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if (key == 0x51) {\n output.attributes.pir_threshold = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if (key == 0x52) {\n output.attributes.pir_threshold_period = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if (key == 0x53) {\n var bit7 = (input[i] >> 7) & 1;\n output.attributes.pir_mode.motion_count_reported = getEnableStatus(bit7);\n \n var bit6 = (input[i] >> pir_mode) & 1;\n output.attributes.pir_mode.motion_state_reported = getEnableStatus(bit6);\n \n var bit1 = (input[i] >> 1) & 1;\n output.attributes.pir_mode.event_transmission_enabled = getEnableStatus(bit1);\n \n var bit0 = (input[i] >> 0) & 1;\n output.attributes.pir_mode.transducer_enabled = getEnableStatus(bit0);\n \n i += 1;\n }\n else if (key == 0x54) {\n output.attributes.pir_mode.motion_count_reported = input[i + 1];\n output.attributes.pir_mode.motion_state_reported = input[i];\n \n i += 1;\n }\n else if (key == 0x6F) {\n var val = (input[i] >> 0) & 1;\n \n switch (val){\n\t\t\t\t\tcase 0:\n\t\t\t\t\t\toutput.attributes_resp_to_dl_command_format = \"Invalid-write response format\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 1:\n\t\t\t\t\t\toutput.attributes_resp_to_dl_command_format = \"4-byte CRC\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\toutput.attributes_resp_to_dl_command_format = \"Invalid\";\n\t\t\t\t}\n \n i += 1;\n }\n else if (key == 0x71) {\n output.attributes.app_major_version = input[i + 6];\n\t\t\t\toutput.attributes.app_minor_version = input[i + 5];\n\t\t\t\toutput.attributes.app_revision = input[i + 4];\n\t\t\t\toutput.attributes.loramac_major_version = input[i + 3];\n\t\t\t\toutput.attributes.loramac_minor_version = input[i + 2];\n\t\t\t\toutput.attributes.loramac_revision = input[i + 1];\n\t\t\t\tvar val = input[i];\n\t\t\t\tswitch (val){\n\t\t\t\t\tcase 0:\n\t\t\t\t\t\toutput.attributes.region = \"EU868\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 1:\n\t\t\t\t\t\toutput.attributes.region = \"US915\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 2:\n\t\t\t\t\t\toutput.attributes.region = \"AS923\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 3:\n\t\t\t\t\t\toutput.attributes.region = \"AU915\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 4:\n\t\t\t\t\t\toutput.attributes.region = \"IN865\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 6:\n\t\t\t\t\t\toutput.attributes.region = \"KR920\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 7:\n\t\t\t\t\t\toutput.attributes.region = \"RU864\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\toutput.attributes.region = \"Invalid\";\n\t\t\t\t}\n\t\t\t\ti += 7;\n }\n }\n }\n else if (fPort == 101) {\n var size = input.length;\n var responses = [];\n \n var index = 0;\n while (index < size) {\n var downlinkFcnt = input[index++] & 0xFF; \n var numInvalidWrites = input[index++] & 0xFF; \n \n if (numInvalidWrites > 0) {\n var invalidRegisters = [];\n for (var i = 0; i < numInvalidWrites; i++) {\n invalidRegisters.add(String.format(\"0x%02X\", input[index + i]));\n }\n index += numInvalidWrites;\n \n responses.add(String.format(\n \"%d Invalid write command(s) from DL:%d for register(s): %s\",\n numInvalidWrites, downlinkFcnt, String.join(\", \", invalidRegisters)\n ));\n } else {\n responses.add(String.format(\"All write commands from DL:%d were successful\", downlinkFcnt));\n }\n }\n \n decoded.response = responses;\n }\n \n output.telemetry = [{\n ts: timestamp,\n values: decoded\n }];\n \n // --- Decoding code --- //\n return output;\n}\n\n\n// --- attributes and telemetry objects ---\nvar telemetry = [];\nvar attributes = {};\n// --- attributes and telemetry objects ---\n\n// --- Timestamp parsing\nvar dateString = data.uplink_message.received_at;\n// If data is simulated or device doesn't send his own date string - we will use date from upcoming message, set by network server\nif ((data.simulated != null && data.simulated) || dateString == null) {\n dateString = data.received_at;\n}\ntimestamp = parseDateToTimestamp(dateString);\n// --- Timestamp parsing\n\n// Message parsing\n// To avoid paths in the decoded objects we passing false value to function as \"pathInKey\" argument.\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.\n\n// Passing incoming bytes to decodeFrmPayload function, to get custom decoding\nvar customDecoding = {};\nif (data.uplink_message.get(\"frm_payload\") != null) {\n customDecoding = decodeFrmPayload(base64ToBytes(data.uplink_message.frm_payload));\n}\n\n// Collecting data to result\nif (customDecoding.?telemetry.size() > 0) {\n if (customDecoding.telemetry instanceof java.util.ArrayList) {\n foreach(telemetryObj: customDecoding.telemetry) {\n if (telemetryObj.ts != null && telemetryObj.values != null) {\n telemetry.add(telemetryObj);\n }\n }\n } else {\n telemetry.putAll(customDecoding.telemetry);\n }\n}\n\nif (customDecoding.?attributes.size() > 0) {\n attributes.putAll(customDecoding.attributes);\n}\n\n// You can add some keys manually to attributes or telemetry\nvar applicationId = data.end_device_ids.?application_ids.?application_id;\nvar devAddr = data.end_device_ids.?dev_addr;\nvar spreadingFactor = data.uplink_message.?settings.?data_rate.?lora.?spreading_factor;\nvar codeRate = data.uplink_message.?settings.?data_rate.?lora.?coding_rate;\nvar tenantId = data.uplink_message.?network_ids.?tenant_id;\nattributes.eui = data.end_device_ids.dev_eui;\nattributes.fPort = data.uplink_message.f_port;\nattributes.applicationId = applicationId;\nattributes.devAddr = devAddr;\nattributes.spreadingFactor = spreadingFactor;\nattributes.codeRate = codeRate;\nattributes.tenantId = tenantId;\nattributes.device_id = data.end_device_ids.?device_id;\nattributes.join_eui = data.end_device_ids.?join_eui;\nattributes.net_id = data.uplink_message.?network_ids.?net_id;\nattributes.cluster_id = data.uplink_message.?network_ids.?cluster_id;\nattributes.cluster_adress = data.uplink_message.?network_ids.?cluster_address;\nattributes.bandwidth = data.uplink_message.?settings.?data_rate.?lora.?bandwidth;\nattributes.frequency = data.uplink_message.?settings.?frequency;\n\n\nvar gatewayInfo = getGatewayInfo();\nvar addDataToTelemetry = {};\naddDataToTelemetry.snr = gatewayInfo.snr;\naddDataToTelemetry.rssi = gatewayInfo.rssi;\naddDataToTelemetry.channel = gatewayInfo.channel_index;\naddDataToTelemetry.consumed_airtime = data.uplink_message.?consumed_airtime;\naddDataToTelemetry.fCnt = data.uplink_message.?f_cnt;\n\nvar isIncludeGatewayInfo = metadata[\"includeGatewayInfo\"];\nif(isIncludeGatewayInfo == true) {\n telemetry = processTelemetryData(telemetry, addDataToTelemetry);\n}\n\nvar result = {\n deviceName: deviceName,\n deviceType: deviceType,\n// assetName: assetName,\n// assetType: assetType,\n attributes: attributes,\n telemetry: telemetry\n};\n\naddAdditionalInfoForDeviceMsg(result, customerName, groupName);\n\nreturn result;\n\n\nfunction addAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName) {\n if (customerName != null) {\n deviceInfo.customerName = customerName;\n }\n if (groupName != null) {\n deviceInfo.groupName = groupName;\n }\n}\n\nfunction parseDateToTimestamp(dateString) {\n var date = new Date(dateString);\n var timestamp = date.getTime();\n \n // If we cannot parse timestamp - we will use the current timestamp\n if (timestamp == -1) {\n timestamp = Date.now();\n }\n \n return timestamp;\n}\n\nfunction getGatewayInfo() {\n var gatewayList = data.uplink_message.?rx_metadata;\n var maxRssi = Integer.MIN_VALUE;\n var gatewayInfo = {};\n \n foreach (gateway : gatewayList) {\n if(gateway.rssi > maxRssi) {\n maxRssi = gateway.rssi;\n gatewayInfo = gateway;\n }\n }\n \n return gatewayInfo;\n}\n\nfunction processTelemetryData(telemetry, addDataToTelemetry) {\n if (telemetry.size >= 1) {\n telemetry = addDataToTelemetries(telemetry, addDataToTelemetry);\n }\n else {\n telemetry.add(addDataToTelemetry);\n }\n \n return telemetry;\n}\n\nfunction addDataToTelemetries(telemetries, addDataToTelemetry) {\n foreach(telemetry : telemetries) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[\"values\"].keys.contains(element.key)) {\n telemetry[\"values\"][element.key] = element.value;\n }\n } \n }\n \n return telemetries;\n}\n\nfunction getEnableStatus(bit) {\n var enableResult = \"Invalid\";\n \n switch (bit) {\n\t\tcase 0:\n\t\t enableResult = \"Disable\";\n\t\t\tbreak;\n\t\tcase 1:\n\t\t\tenableResult = \"Enable\";\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tenableResult = \"Invalid\";\n\t}\n \n return enableResult;\n}\n\nfunction getOnOffStatus(bit) {\n var reportResult = \"Invalid\";\n \n switch (bit) {\n case 0:\n reportResult = \"Off\";\n break;\n case 1:\n reportResult = \"On\";\n break;\n default:\n reportResult = \"Invalid\";\n }\n \n return reportResult;\n}", + "encoder": null, + "tbelEncoder": null, + "updateOnlyKeys": [ + "fPort", + "bandwidth", + "frequency", + "net_id", + "cluster_id", + "cluster_address", + "device_id", + "join_eui", + "battery", + "eui", + "channel", + "applicationId", + "devAddr", + "spreadingFactor", + "codeRate", + "tenantId" + ] + }, + "additionalInfo": { + "description": "" + }, + "edgeTemplate": false +} \ No newline at end of file diff --git a/VENDORS/Tektelic/Vivid/ThingsStackCommunity/uplink/metadata.json b/VENDORS/Tektelic/Vivid/ThingsStackCommunity/uplink/metadata.json new file mode 100644 index 00000000..0d75c374 --- /dev/null +++ b/VENDORS/Tektelic/Vivid/ThingsStackCommunity/uplink/metadata.json @@ -0,0 +1,4 @@ +{ + "integrationName": "The Things Stack Community integration", + "includeGatewayInfo": "false" +} \ No newline at end of file diff --git a/VENDORS/Tektelic/Vivid/ThingsStackCommunity/uplink/payload.json b/VENDORS/Tektelic/Vivid/ThingsStackCommunity/uplink/payload.json new file mode 100644 index 00000000..3ab1656f --- /dev/null +++ b/VENDORS/Tektelic/Vivid/ThingsStackCommunity/uplink/payload.json @@ -0,0 +1,54 @@ +{ + "end_device_ids": { + "device_id": "eui-1000000000000001", + "application_ids": { + "application_id": "application-tts-name" + }, + "dev_eui": "1000000000000001", + "join_eui": "2000000000000001", + "dev_addr": "20000001" + }, + "correlation_ids": ["as:up:01H0S7ZJQ9MQPMVY49FT3SE07M", "gs:conn:01H03BQZ9342X3Y86DJ2P704E5", "gs:up:host:01H03BQZ99EGAM52KK1300GFKN", "gs:uplink:01H0S7ZJGS6D9TJSKJN8XNTMAV", "ns:uplink:01H0S7ZJGS9KKD4HTTPKFEMWCV", "rpc:/ttn.lorawan.v3.GsNs/HandleUplink:01H0S7ZJGSF3M38ZRZVTM38DEC", "rpc:/ttn.lorawan.v3.NsAs/HandleUplink:01H0S7ZJQ8R2EH5AA269AKM8DX"], + "received_at": "2023-05-19T05:33:35.848446463Z", + "uplink_message": { + "session_key_id": "AYfqmb0pc/1uRZv9xUydgQ==", + "f_port": 10, + "f_cnt": 10335, + "frm_payload": "A2cA4QRoTQC6C54=", + "rx_metadata": [{ + "gateway_ids": { + "gateway_id": "eui-6a7e111a10000000", + "eui": "6A7E111A10000000" + }, + "time": "2023-05-19T05:33:35.608982Z", + "timestamp": 3893546133, + "rssi": -35, + "channel_rssi": -35, + "snr": 13.2, + "frequency_offset": "69", + "uplink_token": "CiIKIAoUZXVpLTZhN2UxMTFhMTAwMDAwMDASCCThJP/+9k6eEJWZy8AOGgwIr5ScowYQvNbUsQIgiMy8y6jwpwE=", + "channel_index": 3, + "received_at": "2023-05-19T05:33:35.607383681Z" + }], + "settings": { + "data_rate": { + "lora": { + "bandwidth": 125000, + "spreading_factor": 7, + "coding_rate": "4/5" + } + }, + "frequency": "867100000", + "timestamp": 3893546133, + "time": "2023-05-19T05:33:35.608982Z" + }, + "received_at": "2023-05-19T05:33:35.641841782Z", + "consumed_airtime": "0.056576s", + "network_ids": { + "net_id": "000013", + "tenant_id": "ttn", + "cluster_id": "eu1", + "cluster_address": "eu1.cloud.thethings.network" + } + } +} \ No newline at end of file diff --git a/VENDORS/Tektelic/Vivid/ThingsStackCommunity/uplink/result.json b/VENDORS/Tektelic/Vivid/ThingsStackCommunity/uplink/result.json new file mode 100644 index 00000000..58607518 --- /dev/null +++ b/VENDORS/Tektelic/Vivid/ThingsStackCommunity/uplink/result.json @@ -0,0 +1,28 @@ +{ + "deviceName": "eui-1000000000000001", + "deviceType": "Vivid", + "attributes": { + "eui": "1000000000000001", + "fPort": 10, + "applicationId": "application-tts-name", + "devAddr": "20000001", + "spreadingFactor": 7, + "codeRate": "4/5", + "tenantId": "ttn", + "device_id": "eui-1000000000000001", + "join_eui": "2000000000000001", + "net_id": "000013", + "cluster_id": "eu1", + "cluster_adress": "eu1.cloud.thethings.network", + "bandwidth": 125000, + "frequency": "867100000" + }, + "telemetry": [{ + "ts": 1684474415641, + "values": { + "ambient_temperature": 22.5, + "relative_humidity": 38.5, + "battery_voltage": 2.974 + } + }] +} \ No newline at end of file diff --git a/VENDORS/Tektelic/Vivid/ThingsStackIndustries/uplink/converter.json b/VENDORS/Tektelic/Vivid/ThingsStackIndustries/uplink/converter.json new file mode 100644 index 00000000..c9eb70ab --- /dev/null +++ b/VENDORS/Tektelic/Vivid/ThingsStackIndustries/uplink/converter.json @@ -0,0 +1,40 @@ +{ + "name": "The Things Stack Industries Uplink Decoder for Vivid", + "type": "UPLINK", + "debugMode": false, + "debugSettings": { + "failuresEnabled": true, + "allEnabled": false, + "allEnabledUntil": 1733331880270 + }, + "configuration": { + "scriptLang": "TBEL", + "decoder": null, + "tbelDecoder": "var data = decodeToJson(payload);\n\nvar deviceName = data.end_device_ids.device_id;\nvar deviceType = \"Vivid\";\nvar groupName = null; // If groupName is not null - created device will be added to the entity group with such name.\nvar customerName = null; // If customerName is not null - created devices will be assigned to customer with such name. \n\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// If you want to parse incoming data somehow, you can add your code to this function.\n// input: bytes\n// expected output:\n// {\n// \"attributes\": {\"attributeKey\": \"attributeValue\"},\n// \"telemetry\": [{\"ts\": 1...1, \"values\": {\"telemetryKey\":\"telemetryValue\"}, {\"ts\": 1...2, \"values\": {\"telemetryKey\":\"telemetryValue\"}}]\n// }\n\nfunction decodeFrmPayload(input) {\n var output = { attributes: {}, telemetry: []};\n \n // --- Decoding code --- //\n var decoded = {};\n var fPort = data.uplink_message.f_port;\n if(fPort == 10) {\n for(var i = 0; i < input.length - 2; ) {\n var key_1 = input[i++] & 0xff;\n var key_2 = input[i++] & 0xff;\n \n if(key_1 == 0x00 && key_2 == 0xBA) {\n decoded.battery_voltage = toFixed(parseBytesToInt(input, i, 2) * 0.001, 3);\n i += 2;\n }\n else if(key_1 == 0x01 && key_2 == 0x00) {\n val = parseBytesToInt(input, i, 1);\n switch (val){\n\t\t\t\t\tcase 0:\n\t\t\t\t\t\tdecoded.hall_effect_state = \"Magnet Present\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 255:\n\t\t\t\t\t\tdecoded.hall_effect_state = \"Magnet Absent\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tdecoded.hall_effect_state = \"Invalid\";\n\t\t\t\t}\n \n i += 1;\n }\n else if(key_1 == 0x08 && key_2 == 0x04) {\n decoded.hall_effect_count = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key_1 == 0x0C && key_2 == 0x00) {\n var val = parseBytesToInt(input, i, 1);\n \n switch (val){\n\t\t\t\t\tcase 0:\n\t\t\t\t\t\tdecoded.impact_alarm = \"Impact Alarm Inactive\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 255:\n\t\t\t\t\t\tdecoded.impact_alarm = \"Impact Alarm Active\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tdecoded.impact_alarm = \"Invalid\";\n\t\t\t\t}\n\t\t\t\t\n i += 1;\n }\n else if(key_1 == 0x05 && key_2 == 0x02) {\n decoded.impact_magnitude = toFixed(parseBytesToInt(input, i, 2) * 0.001, 3);\n i += 2;\n }\n else if(key_1 == 0x07 && key_2 == 0x71) {\n decoded.accelerationX = toFixed(parseBytesToInt(input, i + 4, 2) * 0.001, 3);\n decoded.accelerationY = toFixed(parseBytesToInt(input, i + 2, 2) * 0.001, 3);\n decoded.accelerationZ = toFixed(parseBytesToInt(input, i, 2) * 0.001, 3);\n i += 6;\n }\n else if(key_1 == 0x0E && key_2 == 0x00) {\n var val = parseBytesToInt(input, i, 1);\n\t\t\t\tswitch (val){\n\t\t\t\t\tcase 0:\n\t\t\t\t\t\tdecoded.extconnector_state = \"Low(short-circuit)\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 255:\n\t\t\t\t\t\tdecoded.extconnector_state = \"High(open-circuit)\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tdecoded.extconnector_state = \"Invalid\";\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\ti += 1;\n }\n else if(key_1 == 0x0F && key_2 == 0x04) {\n decoded.extconnector_count = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key_1 == 0x12 && key_2 == 0x04) {\n decoded.extconnector_total_count = parseBytesToInt(input, i, 4);\n i += 4;\n }\n else if(key_1 == 0x11 && key_2 == 0x02) {\n decoded.extconnector_analog = toFixed(parseBytesToInt(input, i, 2) * 0.001, 3);\n i += 2;\n }\n else if(key_1 == 0x0B && key_2 == 0x67) {\n decoded.mcu_temperature = toFixed(parseBytesToInt(input, i, 2) * 0.1, 1);\n i += 2;\n }\n else if(key_1 == 0x03 && key_2 == 0x67) {\n decoded.ambient_temperature = toFixed(parseBytesToInt(input, i, 2) * 0.1, 1);\n i += 2;\n }\n else if(key_1 == 0x04 && key_2 == 0x68) {\n decoded.relative_humidity = toFixed(parseBytesToInt(input, i, 1) * 0.5, 1);\n i += 1;\n }\n else if(key_1 == 0x02 && key_2 == 0x00) {\n var val = parseBytesToInt(input, i, 1);\n \n\t\t\t\tswitch (val){\n\t\t\t\t\tcase 0:\n\t\t\t\t\t\tdecoded.light_detected = \"Dark\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 255:\n\t\t\t\t\t\tdecoded.light_detected = \"Bright\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tdecoded.light_detected = \"Invalid\";\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\ti += 1;\n }\n else if(key_1 == 0x10 && key_2 == 0x02) {\n decoded.light_intensity = parseBytesToInt(input, i, 1);\n\t\t\t\t\n\t\t\t\ti += 1;\n }\n else if(key_1 == 0x0A && key_2 == 0x00) {\n var val = parseBytesToInt(input, i, 1);\n\t\t\t\t\n\t\t\t\tswitch (val){\n\t\t\t\t\tcase 0:\n\t\t\t\t\t\tdecoded.motion_event_state = \"None\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 255:\n\t\t\t\t\t\tdecoded.motion_event_state = \"Detected\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tdecoded.motion_event_state = \"Invalid\";\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\ti += 1;\n }\n else if(key_1 == 0x0D && key_2 == 0x04) {\n decoded.motion_event_count = parseBytesToInt(input, i, 2);\n\t\t\t\t\n\t\t\t\ti += 2;\n }\n }\n }\n else if(fPort == 0x05) {\n var key_1 = input[i++] & 0xff;\n var key_2 = input[i++] & 0xff;\n \n if(key_1 == 0x40 && key_2 == 0x06) {\n var val = input[i + 5];\n\t\t\tswitch (val){\n\t\t\t\tcase 1:\n\t\t\t\t\tdecoded_data.reset_diagnostics_reset_reason = \"Push-button reset\";\n\t\t\t\t\tbreak;\n\t\t\t\tcase 2:\n\t\t\t\t\tdecoded_data.reset_diagnostics_reset_reason = \"DL command rest\";\n\t\t\t\t\tbreak;\n\t\t\t\tcase 4:\n\t\t\t\t\tdecoded_data.reset_diagnostics_reset_reason = \"Independent watchdog reset\";\n\t\t\t\t\tbreak;\n\t\t\t\tcase 8:\n\t\t\t\t\tdecoded_data.reset_diagnostics_reset_reason = \"Power loss reset\";\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\tdecoded_data.reset_diagnostics_reset_reason = \"Invalid\";\n\t\t\t}\n\t\t\tdecoded_data.reset_diagnostics_power_loss_reset_count = input[i + 3];\n\t\t\tdecoded_data.reset_diagnostics_watchdog_reset_count = input[i + 2];\n\t\t\tdecoded_data.reset_diagnostics_dl_reset_count = input[i + 1];\n\t\t\tdecoded_data.reset_diagnostics_button_reset_count = input[i];\n }\n }\n else if (fPort == 100) {\n for(var i = 0; i < input.length -1; ) {\n var key = input[i++] & 0xff;\n \n if(key == 0x00) {\n output.attributes.eui = bytesToHex(java.util.Arrays.copyRange(input, i, i + 8));\n i += 8;\n }\n else if(key == 0x01) {\n output.attributes.app_eui = bytesToHex(java.util.Arrays.copyRange(input, i, i + 8));\n\t\t\t\ti += 8;\n }\n else if (key == 0x02) {\n output.attributes.app_key = bytesToHex(java.util.Arrays.copyRange(input, i, i + 16));\n i += 16;\n }\n else if (key == 0x03) {\n output.attributes.devAddr = bytesToHex(java.util.Arrays.copyRange(input, i, i + 4));\n i += 4;\n }\n else if(key == 0x04) {\n output.attributes.network_session_key = bytesToHex(java.util.Arrays.copyRange(input, i, i + 16));\n i += 16;\n }\n else if(key == 0x05) {\n output.attributes.app_session_key = bytesToHex(java.util.Arrays.copyRange(input, i, i + 16));\n i += 16;\n }\n else if(key == 0x10) {\n var val = (((input[i] << 8) | input[i + 1]) >> 15) & 1;\n switch (val){\n\t\t\t\t\tcase 0:\n\t\t\t\t\t\toutput.attributes.loramac_join_mode = \"ABP\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 1:\n\t\t\t\t\t\toutput.attributes.loramac_join_mode = \"OTAA\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\toutput.attributes.loramac_join_mode = \"Invalid\";\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\ti += 1;\n }\n else if (key == 0x11) {\n\t\t\t\tvar val = (((input[i] << 8) | input[i + 1]) >> 3) & 1;\n\t\t\t\toutput.attributes.adr = getEnableStatus(val);\n\t\t\t\t\n\t\t\t\tvar val = (((input[i] << 8) | input[i + 1]) >> 2) & 1;\n\t\t\t\toutput.attributes.duty_cycle = getEnableStatus(val);\n\t\t\t\t\n\t\t\t\tvar val = (((input[i] << 8) | input[i + 1]) >> 1) & 1;\n\t\t\t\t\n\t\t\t\tswitch (val) {\n\t\t\t\t\tcase 0:\n\t\t\t\t\t\toutput.attributes.sync_word = \"Private\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 1:\n\t\t\t\t\t\toutput.attributes.sync_word = \"Public\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\toutput.attributes.sync_word = \"Invalid\";\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tvar val = ((input[i] << 8) | input[i + 1]) & 1;\n\t\t\t\t\n\t\t\t\tswitch (val){\n\t\t\t\t\tcase 0:\n\t\t\t\t\t\toutput.attributes.confirm_mode = \"Unconfirmed\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 1:\n\t\t\t\t\t\toutput.attributes.confirm_mode = \"Confirmed\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t output.attributes.confirm_mode = \"Invalid\";\n\t\t\t\t}\n\t\t\t\ti += 2;\n }\n else if (key == 0x12) {\n output.attributes.dr_number = (((input[i] << 8) | input[i + 1]) >> 8) & 0xF;\n output.attributes.tx_power_number = ((input[i] << 8) | input[i + 1]) & 0xF;\n \n i +=2;\n }\n else if (key == 0x13) {\n output.attributes.frequency = (((input[i] << 32) | (input[i + 1] << 24) | (input[i + 2] << 16) | (input[i + 3] << 8) | input[i + 4]) >> 8) & 0xFFFFFFFF;\n output.attributes.dr_number_rx2 = input[i + 4] & 0xFF;\n \n i += 5;\n }\n else if(key == 0x19) {\n output.attributes.netid_msb = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x1A) {\n output.attributes.loramac_net_id_lsb = parseBytesToInt(input, i, 2);\n\t\t\t\ti += 2;\n }\n else if (key == 0x20) {\n output.attributes.seconds_per_core_tick = parseBytesToInt(input, i, 4);\n i += 4;\n }\n else if(key == 0x21) {\n output.attributes.tick_per_battery = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x22) {\n output.attributes.tick_per_ambient_temperature = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x23) {\n output.attributes.tick_per_relative_humidity = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x24) {\n output.attributes.tick_per_reed_switch = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x25) {\n output.attributes.tick_per_light = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x26) {\n output.attributes.tick_per_accelerometer = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x27) {\n output.attributes.tick_per_mcu_temperature = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x28) {\n output.attributes.tick_per_pir = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x29) {\n output.attributes.tick_per_external_connector = parseBytesToInt(input, i, 2);\n \n i += 2;\n }\n else if(key == 0x2A) {\n var bit0 = (input[i] >> 0) & 1;\n var bit1 = (input[i] >> 1) & 1;\n \n output.attributes.mode.rising_edge_enabled = getEnableStatus(bit0);\n output.attributes.mode.falling_edge_enabled = getEnableStatus(bit1);\n \n i += 1;\n }\n else if(key == 0x2B) {\n\t\t\t\toutput.attributes.reed_switch_count_threshold = parseBytesToInt(input, i, 2);\n\t\t\t\ti += 2;\n }\n else if(key == 0x2C) {\n var bit0 = (input[i] >> 0) & 1;\n var bit1 = (input[i] >> 1) & 1;\n \n output.attributes.reed_values_to_transmit_report_state_enabled = getOnOffStatus(bit0);\n output.attributes.reed_values_to_transmit_report_count_enabled = getOnOffStatus(bit1);\n \n i += 1;\n }\n else if(key == 0x2D) {\n var bit0 = (input[i] >> 0) & 1;\n var bit1 = (input[i] >> 1) & 1;\n var bit7 = (input[i] >> 7) & 1;\n \n output.attributes.external_mode_rising_edge_enabled_ex = getOnOffStatus(bit0);\n output.attributes.external_mode_falling_edge_enabled_ex = getOnOffStatus(bit1);\n \n switch (bit7){\n\t\t\t\t\tcase 0:\n\t\t\t\t\t\toutput.attributes.mode = \"Digital\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 1:\n\t\t\t\t\t output.attributes.mode = \"Analog\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\toutput.attributes.mode = \"Invalid\";\n\t\t\t\t}\n\t\t\t\t\n i += 1;\n }\n else if(key == 0x2E) {\n output.attributes.external_connector_count_threshold = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if(key == 0x2F) {\n var bit0 = (input[i] >> 0) & 1;\n var bit1 = (input[i] >> 1) & 1;\n var bit4 = (input[i] >> 4) & 1;\n \n output.attributes.external_values_to_transmit.report_state_enabled_ex = getOnOffStatus(bit0);\n output.attributes.external_values_to_transmit.report_count_enabled_ex = getOnOffStatus(bit1);\n output.attributes.external_values_to_transmit.count_type = bit4;\n i += 1;\n }\n else if(key == 0x30) {\n output.attributes.impact_event_threshold = toFixed(parseBytesToInt(input, i, 2) * 0x001, 3);\n i += 2;\n }\n else if(key == 0x31) {\n output.attributes.acceleration_event_threshold = toFixed(parseBytesToInt(input, i, 2) * 0.001, 3);\n i += 2;\n }\n else if(key == 0x32) {\n var bit0 = (input[i] >> 0) & 1;\n output.attributes.values_to_transmit.report_periodic_alarm_enabled = getOnOffStatus(bit0);\n \n var bit1 = (input[i] >> 1) & 1;\n output.attributes.values_to_transmit.report_periodic_magnitude_enabled = getOnOffStatus(bit1);\n \n var bit2 = (input[i] >> 2) & 1;\n output.attributes.values_to_transmit.report_periodic_vector_enabled = getOnOffStatus(bit2);\n \n var bit4 = (input[i] >> 4) & 1;\n output.attributes.values_to_transmit.report_event_magnitude_enabled = getOnOffStatus(bit4);\n \n var bit5 = (input[i] >> 5) & 1;\n output.attributes.values_to_transmit.report_event_vector_enabled = getOnOffStatus(bit5);\n \n i += 1;\n }\n else if(key == 0x33) {\n output.attributes.acceleration_impact_grace_period = parseBytesToInt(input, i, 2);\n\t\t\t\t\n\t\t\t\ti += 2;\n }\n else if (key == 0x34) {\n var bit0 = (input[i] >> 0) & 1;\n output.attributes.acceleration_mode.impact_threshold_enabled = getEnableStatus(bit0);\n \n var bit1 = (input[i] >> 1) & 1;\n\t\t\t\toutput.attributes.acceleration_mode.acceleration_threshold_enabled = getEnableStatus(bit1);\n\t\t\t\t\n\t\t\t\tvar bit4 = (input[i] >> 4) & 1;\n\t\t\t\toutput.attributes.acceleration_mode.xaxis_enabled = getEnableStatus(bit4);\n\t\t\t\t\n\t\t\t\tvar bit5 = (input[i] >> 5) & 1;\n\t\t\t\toutput.attributes.acceleration_mode.yaxis_enabled = getEnableStatus(bit5);\n\t\t\t\t\n\t\t\t\tvar bit6 = (input[i] >> 6) & 1;\n\t\t\t\toutput.attributes.acceleration_mode.zaxis_enabled = getEnableStatus(bit6);\n\t\t\t\t\n\t\t\t\tvar bit7 = (input[i] >> 7) & 1;\n\t\t\t\toutput.attributes.acceleration_mode.poweron = getOnOffStatus(bit7);\n\t\t\t\t\n\t\t\t\ti += 1;\n }\n else if (key == 0x35) {\n var val = (input[i] >> 1) & 0x03;\n\t\t\t\t\n\t\t\t\tswitch (val) {\n\t\t\t\t\tcase 1:\n\t\t\t\t\t\toutput.attributes.sensitivity_accelerometer_sample_rate = \"1 Hz\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 2:\n\t\t\t\t\t\toutput.attributes.sensitivity_accelerometer_sample_rate = \"10 Hz\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 3:\n\t\t\t\t\t\toutput.attributes.sensitivity_accelerometer_sample_rate = \"25 Hz\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 4:\n\t\t\t\t\t\toutput.attributes.sensitivity_accelerometer_sample_rate = \"50 Hz\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 5:\n\t\t\t\t\t\toutput.attributes.sensitivity_accelerometer_sample_rate = \"100 Hz\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 6:\n\t\t\t\t\t\toutput.attributes.sensitivity_accelerometer_sample_rate = \"200 Hz\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 7:\n\t\t\t\t\t\toutput.attributes.sensitivity_accelerometer_sample_rate = \"400 Hz\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\toutput.attributes.sensitivity_accelerometer_sample_rate = \"Invalid\";\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tvar val = (arg >> 4) & 0x03;\n\t\t\t\tswitch (val) {\n\t\t\t\t\tcase 0:\n\t\t\t\t\t\toutput.attributes.sensitivity_accelerometer_measurement_range = \"±2 g\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 1:\n\t\t\t\t\t\toutput.attributes.sensitivity_accelerometer_measurement_range = \"±4 g\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 2:\n\t\t\t\t\t\toutput.attributes.sensitivity_accelerometer_measurement_range = \"±8 g\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 3:\n\t\t\t\t\t\toutput.attributes.sensitivity_accelerometer_measurement_range = \"±16 g\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\toutput.attributes.sensitivity_accelerometer_measurement_range = \"Invalid\";\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\ti += 1;\n }\n else if (key == 0x36) {\n output.attributes.impact_alarm_grace_period = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if (key == 0x37) {\n output.attributes.impact_alarm_threshold_count = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if (key == 0x38) {\n output.attributes.impact_alarm_threshold_period = parseBytesToInt(input, i, 2);\n \n i += 2;\n }\n else if (key == 0x39) {\n output.attributes.temperature_relative_humidity_sample_period_idle = parseBytesToInt(input, i, 4);\n \n i += 4;\n }\n else if (key == 0x3A) {\n output.attributes.temperature_relative_humidity_sample_period_active = parseBytesToInt(input, i, 4);\n \n i += 4;\n }\n else if (key == 0x3B) {\n output.attributes.temperature_threshold_low_temp_threshold = parseBytesToInt(input, i, 1);\n output.attributes.temperature_threshold_high_temp_threshold = parseBytesToInt(input, i + 1, 1);\n \n i += 2;\n }\n else if (key == 0x3C) {\n var bit0 = (input[i] >> 0) & 1;\n output.attributes.ambient_temperature_threshold_enabled = getEnableStatus(bit0);\n \n i += 1;\n }\n else if (key == 0x3D) {\n output.attributes.rh_threshold.low_rh_threshold = parseBytesToInt(input, i, 1);\n output.attributes.rh_threshold.high_rh_threshold = parseBytesToInt(input, i + 1, 1);\n \n i += 2;\n }\n else if (key == 0x3E) {\n var bit0 = (input[i] >> 0) & 1;\n output.attributes.relative_humidity_threshold_enabled =getEnableStatus(bit0);\n \n i += 1;\n }\n else if (key == 0x40) {\n output.attributes.mcu_temperature_sample_period_idle = parseBytesToInt(input, i, 4);\n i += 4;\n }\n else if (key == 0x41) {\n output.attributes.mcu_temperature_sample_period_active = parseBytesToInt(input, i, 4);\n i += 4;\n }\n else if (key == 0x42) {\n output.attributes.mcu_temp_threshold_high_mcu_temp_threshold = input[i + 1];\n output.attributes.mcu_temp_threshold_low_mcu_temp_threshold = input[i];\n i += 4;\n }\n else if (key == 0x43) {\n var val = input[i] & 1;\n output.attributes.mcu_temperature_threshold_enabled = getEnableStatus(val);\n\n\t\t\t\ti += 2;\n }\n else if (key == 0x44) {\n output.attributes.analog_sample_period_idle = parseBytesToInt(input, i, 4);\n \n i += 4;\n }\n else if (key == 0x45) {\n output.attributes.analog_sample_period_active = parseBytesToInt(input, i, 4);\n \n i += 4;\n }\n else if(key == 0x46) {\n output.attributes.analog_threshold_high_analog_threshold = toFixed(parseBytesToInt(input, i + 2, 2) * 0.001, 3);\n\t\t\t\toutput.attributes.analog_threshold_low_analog_threshold = toFixed(parseBytesToInt(input, i, 2) * 0.001, 3);\n\t\t\t\ti += 4;\n }\n else if (key == 0x4A) {\n var bit0 = (input[i] >> 0) & 1;\n output.attributes.analog_input_threshold_enabled = getEnableStatus(bit0);\n \n i +=1;\n }\n else if (key == 0x47) {\n output.attributes.light_sample_period = parseBytesToInt(input, i, 4);\n \n i += 4;\n }\n else if (key == 0x48 ) {\n var val = (input[i] >> 7) & 1;\n output.attributes.light_thresholds.threshold_enabled = getEnableStatus(val);\n output.attributes.light_thresholds.threshold = input[i] & 0x3F;\n \n i += 1;\n }\n else if (key == 0x49) {\n var bit0 = (input[i] >> 0) & 1;\n output.attributes.light_values_to_transmit.state_reported = getEnableStatus(bit0);\n \n var bit1 = (input[i] >> 1) & 1;\n output.attributes.light_values_to_transmit.intensity_reported = getEnableStatus(bit1);\n \n i +=1;\n }\n else if (key == 0x50) {\n output.attributes.pir_grace_period = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if (key == 0x51) {\n output.attributes.pir_threshold = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if (key == 0x52) {\n output.attributes.pir_threshold_period = parseBytesToInt(input, i, 2);\n i += 2;\n }\n else if (key == 0x53) {\n var bit7 = (input[i] >> 7) & 1;\n output.attributes.pir_mode.motion_count_reported = getEnableStatus(bit7);\n \n var bit6 = (input[i] >> pir_mode) & 1;\n output.attributes.pir_mode.motion_state_reported = getEnableStatus(bit6);\n \n var bit1 = (input[i] >> 1) & 1;\n output.attributes.pir_mode.event_transmission_enabled = getEnableStatus(bit1);\n \n var bit0 = (input[i] >> 0) & 1;\n output.attributes.pir_mode.transducer_enabled = getEnableStatus(bit0);\n \n i += 1;\n }\n else if (key == 0x54) {\n output.attributes.pir_mode.motion_count_reported = input[i + 1];\n output.attributes.pir_mode.motion_state_reported = input[i];\n \n i += 1;\n }\n else if (key == 0x6F) {\n var val = (input[i] >> 0) & 1;\n \n switch (val){\n\t\t\t\t\tcase 0:\n\t\t\t\t\t\toutput.attributes_resp_to_dl_command_format = \"Invalid-write response format\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 1:\n\t\t\t\t\t\toutput.attributes_resp_to_dl_command_format = \"4-byte CRC\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\toutput.attributes_resp_to_dl_command_format = \"Invalid\";\n\t\t\t\t}\n \n i += 1;\n }\n else if (key == 0x71) {\n output.attributes.app_major_version = input[i + 6];\n\t\t\t\toutput.attributes.app_minor_version = input[i + 5];\n\t\t\t\toutput.attributes.app_revision = input[i + 4];\n\t\t\t\toutput.attributes.loramac_major_version = input[i + 3];\n\t\t\t\toutput.attributes.loramac_minor_version = input[i + 2];\n\t\t\t\toutput.attributes.loramac_revision = input[i + 1];\n\t\t\t\tvar val = input[i];\n\t\t\t\tswitch (val){\n\t\t\t\t\tcase 0:\n\t\t\t\t\t\toutput.attributes.region = \"EU868\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 1:\n\t\t\t\t\t\toutput.attributes.region = \"US915\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 2:\n\t\t\t\t\t\toutput.attributes.region = \"AS923\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 3:\n\t\t\t\t\t\toutput.attributes.region = \"AU915\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 4:\n\t\t\t\t\t\toutput.attributes.region = \"IN865\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 6:\n\t\t\t\t\t\toutput.attributes.region = \"KR920\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 7:\n\t\t\t\t\t\toutput.attributes.region = \"RU864\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\toutput.attributes.region = \"Invalid\";\n\t\t\t\t}\n\t\t\t\ti += 7;\n }\n }\n }\n else if (fPort == 101) {\n var size = input.length;\n var responses = [];\n \n var index = 0;\n while (index < size) {\n var downlinkFcnt = input[index++] & 0xFF; \n var numInvalidWrites = input[index++] & 0xFF; \n \n if (numInvalidWrites > 0) {\n var invalidRegisters = [];\n for (var i = 0; i < numInvalidWrites; i++) {\n invalidRegisters.add(String.format(\"0x%02X\", input[index + i]));\n }\n index += numInvalidWrites;\n \n responses.add(String.format(\n \"%d Invalid write command(s) from DL:%d for register(s): %s\",\n numInvalidWrites, downlinkFcnt, String.join(\", \", invalidRegisters)\n ));\n } else {\n responses.add(String.format(\"All write commands from DL:%d were successful\", downlinkFcnt));\n }\n }\n \n decoded.response = responses;\n }\n \n output.telemetry = [{\n ts: timestamp,\n values: decoded\n }];\n\n // --- Decoding code --- //\n return output;\n}\n\n// --- attributes and telemetry objects ---\nvar telemetry = [];\nvar attributes = {};\n// --- attributes and telemetry objects ---\n\n// --- Timestamp parsing\nvar dateString = data.uplink_message.received_at;\n\nif ((data.simulated != null && data.simulated) || dateString == null) {\n dateString = data.received_at;\n}\n\ntimestamp = parseDateToTimestamp(dateString);\n// --- Timestamp parsing\n\n// Message parsing\n// To avoid paths in the decoded objects we passing false value to function as \"pathInKey\" argument.\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.\n\n// Passing incoming bytes to decodeFrmPayload function, to get custom decoding\nvar customDecoding = {};\nif (data.uplink_message.get(\"frm_payload\") != null) {\n customDecoding = decodeFrmPayload(base64ToBytes(data.uplink_message.frm_payload));\n}\n\n// Collecting data to result\nif (customDecoding.?telemetry.size() > 0) {\n if (customDecoding.telemetry instanceof java.util.ArrayList) {\n foreach(telemetryObj: customDecoding.telemetry) {\n if (telemetryObj.ts != null && telemetryObj.values != null) {\n telemetry.add(telemetryObj);\n }\n }\n } else {\n telemetry.putAll(customDecoding.telemetry);\n }\n}\n\nif (customDecoding.?attributes.size() > 0) {\n attributes.putAll(customDecoding.attributes);\n}\n\n// You can add some keys manually to attributes or telemetry\nvar applicationId = data.end_device_ids.?application_ids.?application_id;\nvar devAddr = data.end_device_ids.?dev_addr;\nvar spreadingFactor = data.uplink_message.?settings.?data_rate.?lora.?spreading_factor;\nvar codeRate = data.uplink_message.?settings.?data_rate.?lora.?coding_rate;\nvar tenantId = data.uplink_message.?network_ids.?tenant_id;\nattributes.eui = data.end_device_ids.dev_eui;\nattributes.fPort = data.uplink_message.f_port;\nattributes.applicationId = applicationId;\nattributes.devAddr = devAddr;\nattributes.spreadingFactor = spreadingFactor;\nattributes.codeRate = codeRate;\nattributes.tenantId = tenantId;\nattributes.device_id = data.end_device_ids.?device_id;\nattributes.join_eui = data.end_device_ids.?join_eui;\nattributes.net_id = data.uplink_message.?network_ids.?net_id;\nattributes.cluster_id = data.uplink_message.?network_ids.?cluster_id;\nattributes.cluster_address = data.uplink_message.?network_ids.?cluster_address;\nattributes.bandwidth = data.uplink_message.?settings.?data_rate.?lora.?bandwidth;\nattributes.frequency = data.uplink_message.?settings.?frequency;\n\nvar isIncludeGatewayInfo = metadata[\"includeGatewayInfo\"];\nif(isIncludeGatewayInfo == true) {\n var gatewayInfo = getGatewayInfo();\n var addDataToTelemetry = {};\n addDataToTelemetry.snr = gatewayInfo.snr;\n addDataToTelemetry.rssi = gatewayInfo.rssi;\n addDataToTelemetry.channel = gatewayInfo.channel_index;\n addDataToTelemetry.consumed_airtime = data.uplink_message.?consumed_airtime;\n addDataToTelemetry.fCnt = data.uplink_message.?f_cnt;\n\n telemetry = processTelemetryData(telemetry, addDataToTelemetry);\n}\n\nvar result = {\n deviceName: deviceName,\n deviceType: deviceType,\n // assetName: assetName,\n // assetType: assetType,\n attributes: attributes,\n telemetry: telemetry\n};\n\naddAdditionalInfoForDeviceMsg(result, customerName, groupName);\n\nreturn result;\n\nfunction addAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName) {\n if (customerName != null) {\n deviceInfo.customerName = customerName;\n }\n if (groupName != null) {\n deviceInfo.groupName = groupName;\n }\n}\n\nfunction parseDateToTimestamp(dateString) {\n var date = new Date(dateString);\n var timestamp = date.getTime();\n \n // If we cannot parse timestamp - we will use the current timestamp\n if (timestamp == -1) {\n timestamp = Date.now();\n }\n \n return timestamp;\n}\n\nfunction getGatewayInfo() {\n var gatewayList = data.uplink_message.?rx_metadata;\n var maxRssi = Integer. MIN_VALUE;\n var gatewayInfo = {};\n \n foreach (gateway : gatewayList) {\n if(gateway.rssi > maxRssi) {\n maxRssi = gateway.rssi;\n gatewayInfo = gateway;\n }\n }\n \n return gatewayInfo;\n}\n\nfunction processTelemetryData(telemetry, addDataToTelemetry) {\n if (telemetry.size >= 1) {\n telemetry = addDataToTelemetries(telemetry, addDataToTelemetry);\n }\n else {\n telemetry.add(addDataToTelemetry);\n }\n \n return telemetry;\n}\n\nfunction addDataToTelemetries(telemetries, addDataToTelemetry) {\n foreach(telemetry : telemetries) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[\"values\"].keys.contains(element.key)) {\n telemetry[\"values\"][element.key] = element.value;\n }\n } \n }\n \n return telemetries;\n}\n\nfunction getEnableStatus(bit) {\n var enableResult = \"Invalid\";\n \n switch (bit) {\n\t\tcase 0:\n\t\t enableResult = \"Disable\";\n\t\t\tbreak;\n\t\tcase 1:\n\t\t\tenableResult = \"Enable\";\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tenableResult = \"Invalid\";\n\t}\n \n return enableResult;\n}\n\nfunction getOnOffStatus(bit) {\n var reportResult = \"Invalid\";\n \n switch (bit) {\n case 0:\n reportResult = \"Off\";\n break;\n case 1:\n reportResult = \"On\";\n break;\n default:\n reportResult = \"Invalid\";\n }\n \n return reportResult;\n}", + "encoder": null, + "tbelEncoder": null, + "updateOnlyKeys": [ + "fPort", + "bandwidth", + "frequency", + "net_id", + "cluster_id", + "cluster_address", + "tenant_address", + "device_id", + "join_eui", + "eui", + "channel", + "devAddr", + "spreadingFactor", + "codeRate", + "tenantId", + "applicationId", + "battery" + ] + }, + "additionalInfo": { + "description": "" + }, + "edgeTemplate": false +} \ No newline at end of file diff --git a/VENDORS/Tektelic/Vivid/ThingsStackIndustries/uplink/metadata.json b/VENDORS/Tektelic/Vivid/ThingsStackIndustries/uplink/metadata.json new file mode 100644 index 00000000..23f54b34 --- /dev/null +++ b/VENDORS/Tektelic/Vivid/ThingsStackIndustries/uplink/metadata.json @@ -0,0 +1,4 @@ +{ + "integrationName": "ChirpStack integration", + "includeGatewayInfo": "false" +} \ No newline at end of file diff --git a/VENDORS/Tektelic/Vivid/ThingsStackIndustries/uplink/payload.json b/VENDORS/Tektelic/Vivid/ThingsStackIndustries/uplink/payload.json new file mode 100644 index 00000000..6ccf662e --- /dev/null +++ b/VENDORS/Tektelic/Vivid/ThingsStackIndustries/uplink/payload.json @@ -0,0 +1,77 @@ +{ + "end_device_ids": { + "device_id": "eui-1000000000000001", + "application_ids": { + "application_id": "application-tti-name" + }, + "dev_eui": "1000000000000001", + "join_eui": "2000000000000001", + "dev_addr": "20000001" + }, + "correlation_ids": ["as:up:01H0PZDGB1NW6NAPD815NGHPF6", "gs:conn:01H0FJRSXSYT7VKNYXJ89F95XT", "gs:up:host:01H0FJRSY3MZMGPPFBQ4FZV4T8", "gs:uplink:01H0PZDG4HHGFRTXRTXD4PFTH7", "ns:uplink:01H0PZDG4JZ3BM0K6J89EQK1J7", "rpc:/ttn.lorawan.v3.GsNs/HandleUplink:01H0PZDG4J02F85RYFPCNSNXCR", "rpc:/ttn.lorawan.v3.NsAs/HandleUplink:01H0PZDGB081PMP806BJHNHX1A"], + "received_at": "2023-05-18T08:25:26.112483370Z", + "uplink_message": { + "session_key_id": "AYfg8rhha5n+FWx0ZaAprA==", + "f_port": 10, + "f_cnt": 5017, + "frm_payload": "A2cA4QRoTQC6C54=", + "rx_metadata": [{ + "gateway_ids": { + "gateway_id": "eui-6A7E111A10000000", + "eui": "6A7E111A10000000" + }, + "time": "2023-05-18T08:25:25.885310Z", + "timestamp": 818273765, + "rssi": -24, + "channel_rssi": -24, + "snr": 12, + "frequency_offset": "671", + "uplink_token": "CiIKIAoUZXVpLTZBN0UxMTFBMTAwMDAwMDASCCThJP/+9k6eEOW7l4YDGgwI9cGXowYQ5KPhrwMgiI2rp+jpOA=", + "channel_index": 2, + "received_at": "2023-05-18T08:25:25.869324983Z" + }, { + "gateway_ids": { + "gateway_id": "packetbroker" + }, + "packet_broker": { + "message_id": "01H0PZDG4MF9AYSMNY44MAVTDH", + "forwarder_net_id": "000013", + "forwarder_tenant_id": "ttn", + "forwarder_cluster_id": "eu1.cloud.thethings.network", + "forwarder_gateway_eui": "6A7E111A10000000", + "forwarder_gateway_id": "eui-6a7e111a10000000", + "home_network_net_id": "000013", + "home_network_tenant_id": "tenant", + "home_network_cluster_id": "eu1.cloud.thethings.industries" + }, + "time": "2023-05-18T08:25:25.885310Z", + "rssi": -24, + "channel_rssi": -24, + "snr": 12, + "frequency_offset": "671", + "uplink_token": "eyJnIjoiWlhsS2FHSkhZMmxQYVVwQ1RWUkpORkl3VGs1VE1XTnBURU5LYkdKdFRXbFBhVXBDVFZSSk5GSXdUazVKYVhkcFlWaFphVTlwU201a01uaGhWVlJvZDFSWFVuRmlSM1JtVFcxT2RVbHBkMmxrUjBadVNXcHZhV05ZY0RKT1IyeExaREpSZVZwR1pIUmpNRXBLVlVoR2RFNVZkR3BWVTBvNUxua3paVVJTWVRaM1lXOU1kbTQwVm5sdmIyWmlPWGN1ZUhCZmVrcElaa3hIWlZadGRVUlFVeTVuYlRaVlZXRXdkakpHV0VKMGJUUjZaMjVXUkVoeGVHRjRaMlJKTlVkS1VsbERhemc1VDNCbk5rVk1iM1JDUkVZM1VWbHdZbEJDTkdOblNqWjBlbkphYUV4MFRVMHhZMVZFTTFac01XdExURUo0YURaMFExTnhhMVJsWWw4eE5FdHlVVXcyZUhsRWFFbEhlakJITXpoTE0xaFdlRzR5VUVjMk4wNUViME5WTkhoTmRrazFZVk5oWkUwd2FXVnFjR294VGtoMFduZHlZMDFxVlVGNmRsbERUazlNY2s5eFdVeFpWMk5XTG1WVFFYVkpNVkptT1U5NWRqUTNhSEoxTUZoalYxRT0iLCJhIjp7ImZuaWQiOiIwMDAwMTMiLCJmdGlkIjoidHRuIiwiZmNpZCI6ImV1MS5jbG91ZC50aGV0aGluZ3MubmV0d29yayJ9fQ==", + "received_at": "2023-05-18T08:25:25.906038642Z" + }], + "settings": { + "data_rate": { + "lora": { + "bandwidth": 125000, + "spreading_factor": 7, + "coding_rate": "4/5" + } + }, + "frequency": "868500000", + "timestamp": 818273765, + "time": "2023-05-18T08:25:25.885310Z" + }, + "received_at": "2023-05-18T08:25:25.906399073Z", + "consumed_airtime": "0.097536s", + "network_ids": { + "net_id": "000013", + "tenant_id": "tenant", + "cluster_id": "eu1", + "cluster_address": "eu1.cloud.thethings.industries", + "tenant_address": "tenant.eu1.cloud.thethings.industries" + } + } +} \ No newline at end of file diff --git a/VENDORS/Tektelic/Vivid/ThingsStackIndustries/uplink/result.json b/VENDORS/Tektelic/Vivid/ThingsStackIndustries/uplink/result.json new file mode 100644 index 00000000..92882bcd --- /dev/null +++ b/VENDORS/Tektelic/Vivid/ThingsStackIndustries/uplink/result.json @@ -0,0 +1,28 @@ +{ + "deviceName": "eui-1000000000000001", + "deviceType": "Vivid", + "attributes": { + "eui": "1000000000000001", + "fPort": 10, + "applicationId": "application-tti-name", + "devAddr": "20000001", + "spreadingFactor": 7, + "codeRate": "4/5", + "tenantId": "tenant", + "device_id": "eui-1000000000000001", + "join_eui": "2000000000000001", + "net_id": "000013", + "cluster_id": "eu1", + "cluster_address": "eu1.cloud.thethings.industries", + "bandwidth": 125000, + "frequency": "868500000" + }, + "telemetry": [{ + "ts": 1684398325906, + "values": { + "ambient_temperature": 22.5, + "relative_humidity": 38.5, + "battery_voltage": 2.974 + } + }] +} \ No newline at end of file diff --git a/VENDORS/Tektelic/Vivid/info.json b/VENDORS/Tektelic/Vivid/info.json new file mode 100644 index 00000000..ec59d281 --- /dev/null +++ b/VENDORS/Tektelic/Vivid/info.json @@ -0,0 +1,5 @@ +{ + "url": "https://tektelic.com/products/sensors/vivid-pir-smart-room-sensor/", + "label": "Vivid: Smart room & occupancy sensor", + "description": "The Vivid is a versatile LoRaWAN IoT sensor in a compact form factor, ideal for monitoring and reporting temperature, humidity, light, shock and open/closed doors and windows in an indoor environment. Additional sensing features such as leak and motion detection, as well as counting pulses from an external device, are also supported with the appropriate model." +} \ No newline at end of file diff --git a/VENDORS/Tektelic/Vivid/photo.png b/VENDORS/Tektelic/Vivid/photo.png new file mode 100644 index 0000000000000000000000000000000000000000..865af723aae1b1ff8dc5c756df96be663e3cdd37 GIT binary patch literal 80030 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 ccZ9<&bLr`MI*0M_Kev3_ Date: Tue, 24 Dec 2024 13:03:42 +0200 Subject: [PATCH 17/33] Added an additional test case for integrating Loriot (Bosch device) --- .../LORIOT/uplink/payload_3.json | 32 ++++++++++++++ .../LORIOT/uplink/result_3.json | 43 +++++++++++++++++++ 2 files changed, 75 insertions(+) create mode 100644 VENDORS/Bosch/Parking_Lot_Sensor/LORIOT/uplink/payload_3.json create mode 100644 VENDORS/Bosch/Parking_Lot_Sensor/LORIOT/uplink/result_3.json diff --git a/VENDORS/Bosch/Parking_Lot_Sensor/LORIOT/uplink/payload_3.json b/VENDORS/Bosch/Parking_Lot_Sensor/LORIOT/uplink/payload_3.json new file mode 100644 index 00000000..6f629f5b --- /dev/null +++ b/VENDORS/Bosch/Parking_Lot_Sensor/LORIOT/uplink/payload_3.json @@ -0,0 +1,32 @@ +{ + "cmd": "gw", + "seqno": 4, + "EUI": "0102030405060708", + "ts": 1690901260493, + "fcnt": 3, + "port": 2, + "freq": 868300000, + "toa": 1319, + "dr": "SF12 BW125 4/5", + "ack": false, + "gws": [ + { + "rssi": -38, + "snr": 8.5, + "ts": 1690901260493, + "time": "2023-08-01T14:47:40.493Z", + "gweui": "1020304080706050", + "ant": 0 + }, + { + "rssi": -42, + "snr": 8.8, + "ts": 1690901260495, + "time": "2023-08-01T14:47:40.495Z", + "gweui": "1020304081716151", + "ant": 0 + } + ], + "bat": 143, + "data": "0112" +} \ No newline at end of file diff --git a/VENDORS/Bosch/Parking_Lot_Sensor/LORIOT/uplink/result_3.json b/VENDORS/Bosch/Parking_Lot_Sensor/LORIOT/uplink/result_3.json new file mode 100644 index 00000000..603f4248 --- /dev/null +++ b/VENDORS/Bosch/Parking_Lot_Sensor/LORIOT/uplink/result_3.json @@ -0,0 +1,43 @@ +[{ + "deviceName": "Bosch parking lot sensor 0102030405060708", + "deviceType": "Parking sensor", + "attributes": { + "eui": "0102030405060708", + "fPort": 2, + "frequency": 868300000 + }, + "telemetry": [{ + "ts": 1690901260493, + "values": { + "type": "heartbeat", + "occupied": true, + "temperature": 18 + } + }] +}, { + "deviceName": "Gateway 1020304080706050", + "deviceType": "Lora gateway", + "telemetry": [{ + "ts": 1690901260493, + "values": { + "rssi": -38, + "snr": 8.5 + } + }], + "attributes": { + "eui": "1020304080706050" + } +}, { + "deviceName": "Gateway 1020304081716151", + "deviceType": "Lora gateway", + "telemetry": [{ + "ts": 1690901260495, + "values": { + "rssi": -42, + "snr": 8.8 + } + }], + "attributes": { + "eui": "1020304081716151" + } +}] \ No newline at end of file From 4a192eb93731878ff4cc846a617a31dbfc78b772 Mon Sep 17 00:00:00 2001 From: thingsboard017 Date: Tue, 24 Dec 2024 13:12:08 +0200 Subject: [PATCH 18/33] Fixed mismatch of expected result in Loriot integration --- VENDORS/Tektelic/Vivid/LORIOT/uplink/result.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VENDORS/Tektelic/Vivid/LORIOT/uplink/result.json b/VENDORS/Tektelic/Vivid/LORIOT/uplink/result.json index f9ed2eb9..ca7d7f4e 100644 --- a/VENDORS/Tektelic/Vivid/LORIOT/uplink/result.json +++ b/VENDORS/Tektelic/Vivid/LORIOT/uplink/result.json @@ -1,6 +1,6 @@ [{ "deviceName": "1000000000000001", - "deviceType": "vivid", + "deviceType": "Vivid", "attributes": { "eui": "1000000000000001", "fPort": 10, From 1eea580996ceb0f3ab1fcc0a4ec6772b64cbe211 Mon Sep 17 00:00:00 2001 From: thingsboard017 Date: Tue, 24 Dec 2024 13:13:32 +0200 Subject: [PATCH 19/33] Updated converter --- .../Parking_Lot_Sensor/LORIOT/uplink/converter.json | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/VENDORS/Bosch/Parking_Lot_Sensor/LORIOT/uplink/converter.json b/VENDORS/Bosch/Parking_Lot_Sensor/LORIOT/uplink/converter.json index c6c4aeaf..3d8b0716 100644 --- a/VENDORS/Bosch/Parking_Lot_Sensor/LORIOT/uplink/converter.json +++ b/VENDORS/Bosch/Parking_Lot_Sensor/LORIOT/uplink/converter.json @@ -1,11 +1,16 @@ { "name": "Loriot Uplink Decoder for Bosch parking lot sensor", "type": "UPLINK", - "debugMode": true, + "debugMode": false, + "debugSettings": { + "failuresEnabled": true, + "allEnabled": false, + "allEnabledUntil": 1735038404143 + }, "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);\nvar deviceName = \"Bosch parking lot sensor\" + data.EUI;\nvar deviceType = \"Parking sensor\";\nvar groupName = null; // If groupName is not null - created device will be added to the entity group with such name.\nvar customerName = null; // If customerName is not null - created devices will be assigned to customer with such name. \n\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// If you want to parse incoming data somehow, you can add your code to this function.\n// input: bytes\n// expected output:\n// {\n// \"attributes\": {\"attributeKey\": \"attributeValue\"},\n// \"telemetry\": {\"telemetryKey\": \"telemetryValue\"}\n// }\n\nfunction decodePayload(input) {\n var output = { attributes: {}, telemetry: []};\n \n // --- Decoding code --- //\n var decoded = {};\n var fPort = data.port;\n\n if (fPort === 1) { // Parking status\n decoded.type = \"parking status\";\n decoded.occupied = (input[0] & 0x1) === 0x1;\n\n } else if (fPort === 2) { // Heartbeat\n decoded.type = \"heartbeat\";\n decoded.occupied = (input[0] & 0x1) === 0x1;\n if (input.length >= 2) {\n var temperature = input[1];\n decoded.temperature = (temperature & 0x80) != 0 ? temperature - 0x100 : temperature;\n }\n } else if (fPort === 3) { // Start-up\n decoded.type = \"startup\";\n decoded.occupied = (input[16] & 0x1) === 0x1;\n\n var resetCause = input[15];\n if (resetCause === 0x01) {\n decoded.resetCause = \"Watchdog reset\";\n } else if (resetCause === 0x02) {\n decoded.resetCause = \"Power On Reset\";\n } else if (resetCause === 0x03) {\n decoded.resetCause = \"System Request Reset\";\n } else if (resetCause === 0x04) {\n decoded.resetCause = \"External Pin Reset\";\n } else if (resetCause === 0x05) {\n decoded.resetCause = \"Lockup Reset\";\n } else if (resetCause === 0x06) {\n decoded.resetCause = \"Brownout Reset\";\n } else {\n decoded.resetCause = \"Unknown\";\n }\n\n decoded.firmwareVersion = input[14] + \".\" + input[13] + \".\" + input[12];\n var debugInfo = \"\";\n for (int i = 0; i < 12; i++) {\n debugInfo += String.format(\"%02x\", input[i]);\n if (i < 11) {\n debugInfo += \" \";\n }\n } \n decoded.debugInfo = debugInfo;\n }\n \n output.telemetry = [{\n ts: timestamp,\n values: decoded\n }];\n\n // --- Decoding code --- //\n return output;\n}\n\n// --- attributes and telemetry objects ---\nvar telemetry = [];\nvar attributes = {};\n// --- attributes and telemetry objects ---\n\n// --- Timestamp parsing\ntimestamp = data.ts;\n// --- Timestamp parsing\n\n// Message parsing\n// To avoid paths in the decoded objects we passing false value to function as \"pathInKey\" argument.\n// Warning: pathInKey can cause already found fields to be overwritten with the last value found.\n\nvar uplinkDataList = [];\n\n// Passing incoming bytes to decodePayload function, to get custom decoding\nvar customDecoding = decodePayload(hexToBytes(data.data));\n\n// Collecting data to result\nif (customDecoding.?telemetry.size() > 0) {\n if (customDecoding.telemetry instanceof java.util.ArrayList) {\n foreach(telemetryObj: customDecoding.telemetry) {\n if (telemetryObj.ts != null && telemetryObj.values != null) {\n telemetry.add(telemetryObj);\n }\n }\n } else {\n telemetry.putAll(customDecoding.telemetry);\n }\n}\n\nif (customDecoding.?attributes.size() > 0) {\n attributes.putAll(customDecoding.attributes);\n}\n\n// You can add some keys manually to attributes or telemetry\nattributes.eui = data.EUI;\nattributes.fPort = data.port;\nattributes.frequency = data.freq;\n\nvar isIncludeGatewayInfo = metadata[\"includeGatewayInfo\"];\nif(isIncludeGatewayInfo == true) {\n var addDataToTelemetry = {};\n addDataToTelemetry.rssi = data.rssi;\n addDataToTelemetry.seqno = data.seqno;\n addDataToTelemetry.snr = data.snr;\n addDataToTelemetry.ack = data.ack;\n addDataToTelemetry.toa = data.toa;\n addDataToTelemetry.fCnt = data.fcnt;\n \n telemetry = processTelemetryData(telemetry, addDataToTelemetry);\n}\n\nvar deviceInfo = {\n deviceName: deviceName,\n deviceType: deviceType,\n// assetName: assetName,\n// assetType: assetType,\n attributes: attributes,\n telemetry: telemetry, \n};\n\naddAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName);\n\nuplinkDataList.add(deviceInfo);\n\nvar gatewayDeviceNamePrefix = \"Gateway \";\nvar gatewayDeviceType = \"Lora gateway\";\nvar gatewayGroupName = null; // If gatewayGroupName is not null - created device will be added to the entity group with such name.\n\nif (data.cmd == \"gw\") {\n foreach( gatewayInfo : data.gws ) {\n var addGatewayInfo = {};\n\n // You can add some keys manually telemetry\n addGatewayInfo.rssi = gatewayInfo.rssi;\n addGatewayInfo.snr = gatewayInfo.snr;\n // You can add some keys manually telemetry\n \n var gatewayInfoMsg = {\n deviceName: gatewayDeviceNamePrefix + gatewayInfo.gweui,\n deviceType: gatewayDeviceType,\n telemetry: [{\n \"ts\": gatewayInfo.ts,\n \"values\": addGatewayInfo\n }],\n attributes: {\n eui: gatewayInfo.gweui\n }\n };\n addAdditionalInfoForDeviceMsg(gatewayInfoMsg, customerName, gatewayGroupName);\n uplinkDataList.add(gatewayInfoMsg);\n }\n}\n\nreturn uplinkDataList;\n\nfunction addAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName) {\n if (customerName != null) {\n deviceInfo.customerName = customerName;\n }\n if (groupName != null) {\n deviceInfo.groupName = groupName;\n }\n}\n\nfunction processTelemetryData(telemetry, addDataToTelemetry) {\n if (telemetry.size > 1) {\n telemetry = addDataToMultipleTelemetries(telemetry, addDataToTelemetry);\n }\n else if (telemetry.size == 1) {\n telemetry = addDataToSingleTelemetry(telemetry, addDataToTelemetry);\n }\n else {\n telemetry.add(addDataToTelemetry);\n }\n \n return telemetry;\n}\n\nfunction addDataToMultipleTelemetries(telemetry, addDataToTelemetry) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[0][\"values\"].keys.contains(element.key)) {\n telemetry[0][\"values\"][element.key] = element.value;\n }\n if (!telemetry[1][\"values\"].keys.contains(element.key)) {\n telemetry[1][\"values\"][element.key] = element.value;\n }\n }\n \n return telemetry;\n}\n\nfunction addDataToSingleTelemetry(telemetry, addDataToTelemetry) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[0][\"values\"].keys.contains(element.key)) {\n telemetry[0][\"values\"][element.key] = element.value;\n }\n }\n \n return telemetry;\n}", + "tbelDecoder": "var data = decodeToJson(payload);\nvar deviceName = \"Bosch parking lot sensor \" + data.EUI;\nvar deviceType = \"Parking sensor\";\nvar groupName = null; // If groupName is not null - created device will be added to the entity group with such name.\nvar customerName = null; // If customerName is not null - created devices will be assigned to customer with such name. \n\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// If you want to parse incoming data somehow, you can add your code to this function.\n// input: bytes\n// expected output:\n// {\n// \"attributes\": {\"attributeKey\": \"attributeValue\"},\n// \"telemetry\": {\"telemetryKey\": \"telemetryValue\"}\n// }\n\nfunction decodePayload(input) {\n var output = { attributes: {}, telemetry: []};\n \n // --- Decoding code --- //\n var decoded = {};\n var fPort = data.port;\n\n if (fPort === 1) { // Parking status\n decoded.type = \"parking status\";\n decoded.occupied = (input[0] & 0x1) === 0x1;\n\n } else if (fPort === 2) { // Heartbeat\n decoded.type = \"heartbeat\";\n decoded.occupied = (input[0] & 0x1) === 0x1;\n if (input.length >= 2) {\n var temperature = input[1];\n decoded.temperature = (temperature & 0x80) != 0 ? temperature - 0x100 : temperature;\n }\n } else if (fPort === 3) { // Start-up\n decoded.type = \"startup\";\n decoded.occupied = (input[16] & 0x1) === 0x1;\n\n var resetCause = input[15];\n if (resetCause === 0x01) {\n decoded.resetCause = \"Watchdog reset\";\n } else if (resetCause === 0x02) {\n decoded.resetCause = \"Power On Reset\";\n } else if (resetCause === 0x03) {\n decoded.resetCause = \"System Request Reset\";\n } else if (resetCause === 0x04) {\n decoded.resetCause = \"External Pin Reset\";\n } else if (resetCause === 0x05) {\n decoded.resetCause = \"Lockup Reset\";\n } else if (resetCause === 0x06) {\n decoded.resetCause = \"Brownout Reset\";\n } else {\n decoded.resetCause = \"Unknown\";\n }\n\n decoded.firmwareVersion = input[14] + \".\" + input[13] + \".\" + input[12];\n var debugInfo = \"\";\n for (int i = 0; i < 12; i++) {\n debugInfo += String.format(\"%02x\", input[i]);\n if (i < 11) {\n debugInfo += \" \";\n }\n } \n decoded.debugInfo = debugInfo;\n }\n \n output.telemetry = [{\n ts: timestamp,\n values: decoded\n }];\n\n // --- Decoding code --- //\n return output;\n}\n\n// --- attributes and telemetry objects ---\nvar telemetry = [];\nvar attributes = {};\n// --- attributes and telemetry objects ---\n\n// --- Timestamp parsing\ntimestamp = data.ts;\n// --- Timestamp parsing\n\n// Message parsing\n// To avoid paths in the decoded objects we passing false value to function as \"pathInKey\" argument.\n// Warning: pathInKey can cause already found fields to be overwritten with the last value found.\n\nvar uplinkDataList = [];\n\n// Passing incoming bytes to decodePayload function, to get custom decoding\nvar customDecoding = decodePayload(hexToBytes(data.data));\n\n// Collecting data to result\nif (customDecoding.?telemetry.size() > 0) {\n if (customDecoding.telemetry instanceof java.util.ArrayList) {\n foreach(telemetryObj: customDecoding.telemetry) {\n if (telemetryObj.ts != null && telemetryObj.values != null) {\n telemetry.add(telemetryObj);\n }\n }\n } else {\n telemetry.putAll(customDecoding.telemetry);\n }\n}\n\nif (customDecoding.?attributes.size() > 0) {\n attributes.putAll(customDecoding.attributes);\n}\n\n// You can add some keys manually to attributes or telemetry\nattributes.eui = data.EUI;\nattributes.fPort = data.port;\nattributes.frequency = data.freq;\n\nvar isIncludeGatewayInfo = metadata[\"includeGatewayInfo\"];\nif(isIncludeGatewayInfo == true) {\n var addDataToTelemetry = {};\n addDataToTelemetry.rssi = data.rssi;\n addDataToTelemetry.seqno = data.seqno;\n addDataToTelemetry.snr = data.snr;\n addDataToTelemetry.ack = data.ack;\n addDataToTelemetry.toa = data.toa;\n addDataToTelemetry.fCnt = data.fcnt;\n \n telemetry = processTelemetryData(telemetry, addDataToTelemetry);\n}\n\nvar deviceInfo = {\n deviceName: deviceName,\n deviceType: deviceType,\n// assetName: assetName,\n// assetType: assetType,\n attributes: attributes,\n telemetry: telemetry, \n};\n\naddAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName);\n\nuplinkDataList.add(deviceInfo);\n\nvar gatewayDeviceNamePrefix = \"Gateway \";\nvar gatewayDeviceType = \"Lora gateway\";\nvar gatewayGroupName = null; // If gatewayGroupName is not null - created device will be added to the entity group with such name.\n\nif (data.cmd == \"gw\") {\n foreach( gatewayInfo : data.gws ) {\n var addGatewayInfo = {};\n\n // You can add some keys manually telemetry\n addGatewayInfo.rssi = gatewayInfo.rssi;\n addGatewayInfo.snr = gatewayInfo.snr;\n // You can add some keys manually telemetry\n \n var gatewayInfoMsg = {\n deviceName: gatewayDeviceNamePrefix + gatewayInfo.gweui,\n deviceType: gatewayDeviceType,\n telemetry: [{\n \"ts\": gatewayInfo.ts,\n \"values\": addGatewayInfo\n }],\n attributes: {\n eui: gatewayInfo.gweui\n }\n };\n addAdditionalInfoForDeviceMsg(gatewayInfoMsg, customerName, gatewayGroupName);\n uplinkDataList.add(gatewayInfoMsg);\n }\n}\n\nreturn uplinkDataList;\n\nfunction addAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName) {\n if (customerName != null) {\n deviceInfo.customerName = customerName;\n }\n if (groupName != null) {\n deviceInfo.groupName = groupName;\n }\n}\n\nfunction processTelemetryData(telemetry, addDataToTelemetry) {\n if (telemetry.size > 1) {\n telemetry = addDataToMultipleTelemetries(telemetry, addDataToTelemetry);\n }\n else if (telemetry.size == 1) {\n telemetry = addDataToSingleTelemetry(telemetry, addDataToTelemetry);\n }\n else {\n telemetry.add(addDataToTelemetry);\n }\n \n return telemetry;\n}\n\nfunction addDataToMultipleTelemetries(telemetry, addDataToTelemetry) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[0][\"values\"].keys.contains(element.key)) {\n telemetry[0][\"values\"][element.key] = element.value;\n }\n if (!telemetry[1][\"values\"].keys.contains(element.key)) {\n telemetry[1][\"values\"][element.key] = element.value;\n }\n }\n \n return telemetry;\n}\n\nfunction addDataToSingleTelemetry(telemetry, addDataToTelemetry) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[0][\"values\"].keys.contains(element.key)) {\n telemetry[0][\"values\"][element.key] = element.value;\n }\n }\n \n return telemetry;\n}", "encoder": null, "tbelEncoder": null, "updateOnlyKeys": [ From fe258d1127c1ce045e86e783c3f2c9bd879930d7 Mon Sep 17 00:00:00 2001 From: thingsboard017 Date: Tue, 24 Dec 2024 13:24:59 +0200 Subject: [PATCH 20/33] Added an additional test case for integrating Loriot (SensiEDGE device) --- .../SensiLora2_0/LORIOT/uplink/payload_2.json | 32 +++++++++++ .../SensiLora2_0/LORIOT/uplink/result_2.json | 54 +++++++++++++++++++ 2 files changed, 86 insertions(+) create mode 100644 VENDORS/SensiEDGE/SensiLora2_0/LORIOT/uplink/payload_2.json create mode 100644 VENDORS/SensiEDGE/SensiLora2_0/LORIOT/uplink/result_2.json diff --git a/VENDORS/SensiEDGE/SensiLora2_0/LORIOT/uplink/payload_2.json b/VENDORS/SensiEDGE/SensiLora2_0/LORIOT/uplink/payload_2.json new file mode 100644 index 00000000..85665229 --- /dev/null +++ b/VENDORS/SensiEDGE/SensiLora2_0/LORIOT/uplink/payload_2.json @@ -0,0 +1,32 @@ +{ + "cmd": "gw", + "seqno": 4, + "EUI": "0102030405060708", + "ts": 1690901260493, + "fcnt": 3, + "port": 207, + "freq": 868300000, + "toa": 1319, + "dr": "SF12 BW125 4/5", + "ack": false, + "gws": [ + { + "rssi": -38, + "snr": 8.5, + "ts": 1690901260493, + "time": "2023-08-01T14:47:40.493Z", + "gweui": "1020304080706050", + "ant": 0 + }, + { + "rssi": -42, + "snr": 8.8, + "ts": 1690901260495, + "time": "2023-08-01T14:47:40.495Z", + "gweui": "1020304081716151", + "ant": 0 + } + ], + "bat": 143, + "data": "277f09a5160f0061ff5b03d3ee17fe5cfdadfd6900bbff60005b01a4" +} \ No newline at end of file diff --git a/VENDORS/SensiEDGE/SensiLora2_0/LORIOT/uplink/result_2.json b/VENDORS/SensiEDGE/SensiLora2_0/LORIOT/uplink/result_2.json new file mode 100644 index 00000000..2335d742 --- /dev/null +++ b/VENDORS/SensiEDGE/SensiLora2_0/LORIOT/uplink/result_2.json @@ -0,0 +1,54 @@ +[{ + "deviceName": "0102030405060708", + "deviceType": "SensiLora2.0", + "attributes": { + "eui": "0102030405060708", + "fPort": 207, + "frequency": 868300000 + }, + "telemetry": [{ + "ts": 1690901260493, + "values": { + "pressure": 1011.1, + "temperature": 24.69, + "humidity": 56.47, + "accelerationX": 0.9512450499999999, + "accelerationY": -1.61809725, + "accelerationZ": 9.60071035, + "gyroX": -0.080022005, + "gyroY": -0.00733026, + "gyroZ": -0.010384534999999999, + "magX": -66.3, + "magY": 18.7, + "magZ": -16.0, + "light": 91, + "batteryVolt": 4.2 + } + }] +}, { + "deviceName": "Gateway 1020304080706050", + "deviceType": "Lora gateway", + "telemetry": [{ + "ts": 1690901260493, + "values": { + "rssi": -38, + "snr": 8.5 + } + }], + "attributes": { + "eui": "1020304080706050" + } +}, { + "deviceName": "Gateway 1020304081716151", + "deviceType": "Lora gateway", + "telemetry": [{ + "ts": 1690901260495, + "values": { + "rssi": -42, + "snr": 8.8 + } + }], + "attributes": { + "eui": "1020304081716151" + } +}] \ No newline at end of file From 762462fa3988ba2225272da6ec0d3d2e14fc8aa8 Mon Sep 17 00:00:00 2001 From: thingsboard017 Date: Tue, 24 Dec 2024 13:48:05 +0200 Subject: [PATCH 21/33] Added an additional test case for integrating Loriot (Nwave device) --- .../G4_NCC_FM/LORIOT/uplink/payload_1.json | 32 +++++++++++++ .../G4_NCC_FM/LORIOT/uplink/result_1.json | 44 ++++++++++++++++++ .../G4_NCC_SM/LORIOT/uplink/payload_1.json | 32 +++++++++++++ .../G4_NCC_SM/LORIOT/uplink/result_1.json | 44 ++++++++++++++++++ .../G4_NPS_FM/LORIOT/uplink/payload_3.json | 32 +++++++++++++ .../G4_NPS_FM/LORIOT/uplink/result_3.json | 46 +++++++++++++++++++ .../G4_NPS_SM/LORIOT/uplink/payload_3.json | 32 +++++++++++++ .../G4_NPS_SM/LORIOT/uplink/result_3.json | 46 +++++++++++++++++++ 8 files changed, 308 insertions(+) create mode 100644 VENDORS/Nwave/G4_NCC_FM/LORIOT/uplink/payload_1.json create mode 100644 VENDORS/Nwave/G4_NCC_FM/LORIOT/uplink/result_1.json create mode 100644 VENDORS/Nwave/G4_NCC_SM/LORIOT/uplink/payload_1.json create mode 100644 VENDORS/Nwave/G4_NCC_SM/LORIOT/uplink/result_1.json create mode 100644 VENDORS/Nwave/G4_NPS_FM/LORIOT/uplink/payload_3.json create mode 100644 VENDORS/Nwave/G4_NPS_FM/LORIOT/uplink/result_3.json create mode 100644 VENDORS/Nwave/G4_NPS_SM/LORIOT/uplink/payload_3.json create mode 100644 VENDORS/Nwave/G4_NPS_SM/LORIOT/uplink/result_3.json diff --git a/VENDORS/Nwave/G4_NCC_FM/LORIOT/uplink/payload_1.json b/VENDORS/Nwave/G4_NCC_FM/LORIOT/uplink/payload_1.json new file mode 100644 index 00000000..ef57e31c --- /dev/null +++ b/VENDORS/Nwave/G4_NCC_FM/LORIOT/uplink/payload_1.json @@ -0,0 +1,32 @@ +{ + "cmd": "gw", + "seqno": 4, + "EUI": "0102030405060708", + "ts": 1690901260493, + "fcnt": 3, + "port": 2, + "freq": 868300000, + "toa": 1319, + "dr": "SF12 BW125 4/5", + "ack": false, + "gws": [ + { + "rssi": -38, + "snr": 8.5, + "ts": 1690901260493, + "time": "2023-08-01T14:47:40.493Z", + "gweui": "1020304080706050", + "ant": 0 + }, + { + "rssi": -42, + "snr": 8.8, + "ts": 1690901260495, + "time": "2023-08-01T14:47:40.495Z", + "gweui": "1020304081716151", + "ant": 0 + } + ], + "bat": 143, + "data": "A86661" +} \ No newline at end of file diff --git a/VENDORS/Nwave/G4_NCC_FM/LORIOT/uplink/result_1.json b/VENDORS/Nwave/G4_NCC_FM/LORIOT/uplink/result_1.json new file mode 100644 index 00000000..4ce5b85c --- /dev/null +++ b/VENDORS/Nwave/G4_NCC_FM/LORIOT/uplink/result_1.json @@ -0,0 +1,44 @@ +[{ + "deviceName": "G4 Car Counter FM 0102030405060708", + "deviceType": "Parking sensor", + "attributes": { + "eui": "0102030405060708", + "fPort": 2, + "frequency": 868300000 + }, + "telemetry": [{ + "ts": 1690901260493, + "values": { + "type": "heartbeat", + "hw_health_status": 40, + "battery_voltage": 2.908, + "battery_voltage_mean_24h": 2.888 + } + }] +}, { + "deviceName": "Gateway 1020304080706050", + "deviceType": "Lora gateway", + "telemetry": [{ + "ts": 1690901260493, + "values": { + "rssi": -38, + "snr": 8.5 + } + }], + "attributes": { + "eui": "1020304080706050" + } +}, { + "deviceName": "Gateway 1020304081716151", + "deviceType": "Lora gateway", + "telemetry": [{ + "ts": 1690901260495, + "values": { + "rssi": -42, + "snr": 8.8 + } + }], + "attributes": { + "eui": "1020304081716151" + } +}] \ No newline at end of file diff --git a/VENDORS/Nwave/G4_NCC_SM/LORIOT/uplink/payload_1.json b/VENDORS/Nwave/G4_NCC_SM/LORIOT/uplink/payload_1.json new file mode 100644 index 00000000..5f036c57 --- /dev/null +++ b/VENDORS/Nwave/G4_NCC_SM/LORIOT/uplink/payload_1.json @@ -0,0 +1,32 @@ +{ + "cmd": "gw", + "seqno": 4, + "EUI": "0102030405060708", + "ts": 1690901260493, + "fcnt": 3, + "port": 2, + "freq": 868300000, + "toa": 1319, + "dr": "SF12 BW125 4/5", + "ack": false, + "gws": [ + { + "rssi": -38, + "snr": 8.5, + "ts": 1690901260493, + "time": "2023-08-01T14:47:40.493Z", + "gweui": "1020304080706050", + "ant": 0 + }, + { + "rssi": -42, + "snr": 8.8, + "ts": 1690901260495, + "time": "2023-08-01T14:47:40.495Z", + "gweui": "1020304081716151", + "ant": 0 + } + ], + "bat": 143, + "data": "A86661" +} diff --git a/VENDORS/Nwave/G4_NCC_SM/LORIOT/uplink/result_1.json b/VENDORS/Nwave/G4_NCC_SM/LORIOT/uplink/result_1.json new file mode 100644 index 00000000..8e0bf8bc --- /dev/null +++ b/VENDORS/Nwave/G4_NCC_SM/LORIOT/uplink/result_1.json @@ -0,0 +1,44 @@ +[{ + "deviceName": "G4 Car Counter SM 0102030405060708", + "deviceType": "Parking sensor", + "attributes": { + "eui": "0102030405060708", + "fPort": 2, + "frequency": 868300000 + }, + "telemetry": [{ + "ts": 1690901260493, + "values": { + "type": "heartbeat", + "hw_health_status": 40, + "battery_voltage": 2.908, + "battery_voltage_mean_24h": 2.888 + } + }] +}, { + "deviceName": "Gateway 1020304080706050", + "deviceType": "Lora gateway", + "telemetry": [{ + "ts": 1690901260493, + "values": { + "rssi": -38, + "snr": 8.5 + } + }], + "attributes": { + "eui": "1020304080706050" + } +}, { + "deviceName": "Gateway 1020304081716151", + "deviceType": "Lora gateway", + "telemetry": [{ + "ts": 1690901260495, + "values": { + "rssi": -42, + "snr": 8.8 + } + }], + "attributes": { + "eui": "1020304081716151" + } +}] \ No newline at end of file diff --git a/VENDORS/Nwave/G4_NPS_FM/LORIOT/uplink/payload_3.json b/VENDORS/Nwave/G4_NPS_FM/LORIOT/uplink/payload_3.json new file mode 100644 index 00000000..4d2cff1d --- /dev/null +++ b/VENDORS/Nwave/G4_NPS_FM/LORIOT/uplink/payload_3.json @@ -0,0 +1,32 @@ +{ + "cmd": "gw", + "seqno": 4, + "EUI": "0102030405060708", + "ts": 1690901260493, + "fcnt": 3, + "port": 2, + "freq": 868300000, + "toa": 1319, + "dr": "SF12 BW125 4/5", + "ack": false, + "gws": [ + { + "rssi": -38, + "snr": 8.5, + "ts": 1690901260493, + "time": "2023-08-01T14:47:40.493Z", + "gweui": "1020304080706050", + "ant": 0 + }, + { + "rssi": -42, + "snr": 8.8, + "ts": 1690901260495, + "time": "2023-08-01T14:47:40.495Z", + "gweui": "1020304081716151", + "ant": 0 + } + ], + "bat": 143, + "data": "00d3d800590b" +} diff --git a/VENDORS/Nwave/G4_NPS_FM/LORIOT/uplink/result_3.json b/VENDORS/Nwave/G4_NPS_FM/LORIOT/uplink/result_3.json new file mode 100644 index 00000000..35c30477 --- /dev/null +++ b/VENDORS/Nwave/G4_NPS_FM/LORIOT/uplink/result_3.json @@ -0,0 +1,46 @@ +[{ + "deviceName": "G4 Parking sensor FM 0102030405060708", + "deviceType": "Parking sensor", + "attributes": { + "eui": "0102030405060708", + "fPort": 2, + "frequency": 868300000 + }, + "telemetry": [{ + "ts": 1690901260493, + "values": { + "type": "heartbeat", + "occupied": false, + "hw_health_status": 0, + "temperature": -10, + "battery_voltage": 2.32, + "battery_health": "critical" + } + }] +}, { + "deviceName": "Gateway 1020304080706050", + "deviceType": "Lora gateway", + "telemetry": [{ + "ts": 1690901260493, + "values": { + "rssi": -38, + "snr": 8.5 + } + }], + "attributes": { + "eui": "1020304080706050" + } +}, { + "deviceName": "Gateway 1020304081716151", + "deviceType": "Lora gateway", + "telemetry": [{ + "ts": 1690901260495, + "values": { + "rssi": -42, + "snr": 8.8 + } + }], + "attributes": { + "eui": "1020304081716151" + } +}] \ No newline at end of file diff --git a/VENDORS/Nwave/G4_NPS_SM/LORIOT/uplink/payload_3.json b/VENDORS/Nwave/G4_NPS_SM/LORIOT/uplink/payload_3.json new file mode 100644 index 00000000..4d2cff1d --- /dev/null +++ b/VENDORS/Nwave/G4_NPS_SM/LORIOT/uplink/payload_3.json @@ -0,0 +1,32 @@ +{ + "cmd": "gw", + "seqno": 4, + "EUI": "0102030405060708", + "ts": 1690901260493, + "fcnt": 3, + "port": 2, + "freq": 868300000, + "toa": 1319, + "dr": "SF12 BW125 4/5", + "ack": false, + "gws": [ + { + "rssi": -38, + "snr": 8.5, + "ts": 1690901260493, + "time": "2023-08-01T14:47:40.493Z", + "gweui": "1020304080706050", + "ant": 0 + }, + { + "rssi": -42, + "snr": 8.8, + "ts": 1690901260495, + "time": "2023-08-01T14:47:40.495Z", + "gweui": "1020304081716151", + "ant": 0 + } + ], + "bat": 143, + "data": "00d3d800590b" +} diff --git a/VENDORS/Nwave/G4_NPS_SM/LORIOT/uplink/result_3.json b/VENDORS/Nwave/G4_NPS_SM/LORIOT/uplink/result_3.json new file mode 100644 index 00000000..9d0aa664 --- /dev/null +++ b/VENDORS/Nwave/G4_NPS_SM/LORIOT/uplink/result_3.json @@ -0,0 +1,46 @@ +[{ + "deviceName": "G4 Parking sensor SM 0102030405060708", + "deviceType": "Parking sensor", + "attributes": { + "eui": "0102030405060708", + "fPort": 2, + "frequency": 868300000 + }, + "telemetry": [{ + "ts": 1690901260493, + "values": { + "type": "heartbeat", + "occupied": false, + "hw_health_status": 0, + "temperature": -10, + "battery_voltage": 2.32, + "battery_health": "critical" + } + }] +}, { + "deviceName": "Gateway 1020304080706050", + "deviceType": "Lora gateway", + "telemetry": [{ + "ts": 1690901260493, + "values": { + "rssi": -38, + "snr": 8.5 + } + }], + "attributes": { + "eui": "1020304080706050" + } +}, { + "deviceName": "Gateway 1020304081716151", + "deviceType": "Lora gateway", + "telemetry": [{ + "ts": 1690901260495, + "values": { + "rssi": -42, + "snr": 8.8 + } + }], + "attributes": { + "eui": "1020304081716151" + } +}] \ No newline at end of file From ab2932da32f77c58ec396fd71e0e3fd1a00635e2 Mon Sep 17 00:00:00 2001 From: thingsboard017 Date: Tue, 24 Dec 2024 13:51:38 +0200 Subject: [PATCH 22/33] Fixed mismatch of expected result files for Bosch device --- VENDORS/Bosch/Parking_Lot_Sensor/LORIOT/uplink/result.json | 2 +- VENDORS/Bosch/Parking_Lot_Sensor/LORIOT/uplink/result_1.json | 2 +- VENDORS/Bosch/Parking_Lot_Sensor/LORIOT/uplink/result_2.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/VENDORS/Bosch/Parking_Lot_Sensor/LORIOT/uplink/result.json b/VENDORS/Bosch/Parking_Lot_Sensor/LORIOT/uplink/result.json index ec7b80b0..9d1a5eed 100644 --- a/VENDORS/Bosch/Parking_Lot_Sensor/LORIOT/uplink/result.json +++ b/VENDORS/Bosch/Parking_Lot_Sensor/LORIOT/uplink/result.json @@ -1,5 +1,5 @@ [{ - "deviceName": "Bosch parking lot sensor1000000000000001", + "deviceName": "Bosch parking lot sensor 1000000000000001", "deviceType": "Parking sensor", "attributes": { "eui": "1000000000000001", diff --git a/VENDORS/Bosch/Parking_Lot_Sensor/LORIOT/uplink/result_1.json b/VENDORS/Bosch/Parking_Lot_Sensor/LORIOT/uplink/result_1.json index ebed3a17..8edf9472 100644 --- a/VENDORS/Bosch/Parking_Lot_Sensor/LORIOT/uplink/result_1.json +++ b/VENDORS/Bosch/Parking_Lot_Sensor/LORIOT/uplink/result_1.json @@ -1,5 +1,5 @@ [{ - "deviceName": "Bosch parking lot sensor1000000000000001", + "deviceName": "Bosch parking lot sensor 1000000000000001", "deviceType": "Parking sensor", "attributes": { "eui": "1000000000000001", diff --git a/VENDORS/Bosch/Parking_Lot_Sensor/LORIOT/uplink/result_2.json b/VENDORS/Bosch/Parking_Lot_Sensor/LORIOT/uplink/result_2.json index 31b7be5e..0f734a8a 100644 --- a/VENDORS/Bosch/Parking_Lot_Sensor/LORIOT/uplink/result_2.json +++ b/VENDORS/Bosch/Parking_Lot_Sensor/LORIOT/uplink/result_2.json @@ -1,5 +1,5 @@ [{ - "deviceName": "Bosch parking lot sensor1000000000000001", + "deviceName": "Bosch parking lot sensor 1000000000000001", "deviceType": "Parking sensor", "attributes": { "eui": "1000000000000001", From 9530be31ba9d80c651a01f6a8b078af99c28aff9 Mon Sep 17 00:00:00 2001 From: Artem Barysh Date: Tue, 24 Dec 2024 15:20:22 +0200 Subject: [PATCH 23/33] Added an additional test cases for loriot integration(elsys devices) --- .../Elsys/ERS2/LORIOT/uplink/converter.json | 9 +++- .../Elsys/ERS2/LORIOT/uplink/payload_1.json | 32 +++++++++++++ .../Elsys/ERS2/LORIOT/uplink/result_1.json | 45 ++++++++++++++++++ .../ERS2_CO2/LORIOT/uplink/converter.json | 9 +++- .../ERS2_CO2/LORIOT/uplink/payload_1.json | 32 +++++++++++++ .../ERS2_CO2/LORIOT/uplink/result_1.json | 46 ++++++++++++++++++ .../LORIOT/uplink/converter.json | 9 +++- .../LORIOT/uplink/payload_1.json | 32 +++++++++++++ .../ERS2_CO2_Lite/LORIOT/uplink/result_1.json | 44 +++++++++++++++++ .../ERS2_Lite/LORIOT/uplink/converter.json | 9 +++- .../ERS2_Lite/LORIOT/uplink/payload_1.json | 32 +++++++++++++ .../ERS2_Lite/LORIOT/uplink/result_1.json | 43 +++++++++++++++++ .../ERS2_Sound/LORIOT/uplink/payload_1.json | 32 +++++++++++++ .../ERS2_Sound/LORIOT/uplink/result_1.json | 47 +++++++++++++++++++ .../ERS2_VOC/LORIOT/uplink/converter.json | 9 +++- .../ERS2_VOC/LORIOT/uplink/payload_1.json | 32 +++++++++++++ .../ERS2_VOC/LORIOT/uplink/result_1.json | 46 ++++++++++++++++++ 17 files changed, 498 insertions(+), 10 deletions(-) create mode 100644 VENDORS/Elsys/ERS2/LORIOT/uplink/payload_1.json create mode 100644 VENDORS/Elsys/ERS2/LORIOT/uplink/result_1.json create mode 100644 VENDORS/Elsys/ERS2_CO2/LORIOT/uplink/payload_1.json create mode 100644 VENDORS/Elsys/ERS2_CO2/LORIOT/uplink/result_1.json create mode 100644 VENDORS/Elsys/ERS2_CO2_Lite/LORIOT/uplink/payload_1.json create mode 100644 VENDORS/Elsys/ERS2_CO2_Lite/LORIOT/uplink/result_1.json create mode 100644 VENDORS/Elsys/ERS2_Lite/LORIOT/uplink/payload_1.json create mode 100644 VENDORS/Elsys/ERS2_Lite/LORIOT/uplink/result_1.json create mode 100644 VENDORS/Elsys/ERS2_Sound/LORIOT/uplink/payload_1.json create mode 100644 VENDORS/Elsys/ERS2_Sound/LORIOT/uplink/result_1.json create mode 100644 VENDORS/Elsys/ERS2_VOC/LORIOT/uplink/payload_1.json create mode 100644 VENDORS/Elsys/ERS2_VOC/LORIOT/uplink/result_1.json diff --git a/VENDORS/Elsys/ERS2/LORIOT/uplink/converter.json b/VENDORS/Elsys/ERS2/LORIOT/uplink/converter.json index ee7b05b9..f29d11f1 100644 --- a/VENDORS/Elsys/ERS2/LORIOT/uplink/converter.json +++ b/VENDORS/Elsys/ERS2/LORIOT/uplink/converter.json @@ -1,11 +1,16 @@ { "name": "Loriot Uplink Decoder for Elsys ERS2 Device", "type": "UPLINK", - "debugMode": true, + "debugMode": false, + "debugSettings": { + "failuresEnabled": true, + "allEnabled": false, + "allEnabledUntil": 1735046487936 + }, "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);\nvar deviceName = \"ERS2 \" + data.EUI;\nvar deviceType = \"ERS2\";\nvar groupName = null; // If groupName is not null - created device will be added to the entity group with such name.\nvar customerName = null; // If customerName is not null - created devices will be assigned to customer with such name. \n\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// If you want to parse incoming data somehow, you can add your code to this function.\n// input: bytes\n// expected output:\n// {\n// \"attributes\": {\"attributeKey\": \"attributeValue\"},\n// \"telemetry\": {\"telemetryKey\": \"telemetryValue\"}\n// }\n\nfunction decodePayload(input) {\n var output = { attributes: {}, telemetry: []};\n \n // --- Decoding code --- //\n var decoded = {};\n for (var i = 0; i < input.length;) {\n var type = input[i++] & 0xff;\n \n if (type == 0x01) { \n // Temperature Converts to °C\n decoded.temperature = parseBytesToInt(input, i, 2, true) / 10;\n i += 2;\n } else if (type == 0x02) { // Humidity\n decoded.humidity = input[i];\n i += 1;\n } else if (type == 0x04) { // Light\n decoded.light = parseBytesToInt(input, i, 2, true);\n i += 2;\n } else if (type == 0x05) { // Motion (PIR)\n decoded.pir = input[i];\n i += 1;\n } else if (type == 0x07) { // Battery Voltage (VDD)\n decoded.vdd = parseBytesToInt(input, i, 2, true); \n i += 2;\n }\n }\n \n output.telemetry = [{\n ts: timestamp,\n values: decoded\n }];\n\n // --- Decoding code --- //\n return output;\n}\n\n// --- attributes and telemetry objects ---\nvar telemetry = [];\nvar attributes = {};\n// --- attributes and telemetry objects ---\n\n// --- Timestamp parsing\ntimestamp = data.ts;\n// --- Timestamp parsing\n\n// Message parsing\n// To avoid paths in the decoded objects we passing false value to function as \"pathInKey\" argument.\n// Warning: pathInKey can cause already found fields to be overwritten with the last value found.\n\nvar uplinkDataList = [];\n\n// Passing incoming bytes to decodePayload function, to get custom decoding\nvar customDecoding = decodePayload(hexToBytes(data.data));\n\n// Collecting data to result\nif (customDecoding.?telemetry.size() > 0) {\n if (customDecoding.telemetry instanceof java.util.ArrayList) {\n foreach(telemetryObj: customDecoding.telemetry) {\n if (telemetryObj.ts != null && telemetryObj.values != null) {\n telemetry.add(telemetryObj);\n }\n }\n } else {\n telemetry.putAll(customDecoding.telemetry);\n }\n}\n\nif (customDecoding.?attributes.size() > 0) {\n attributes.putAll(customDecoding.attributes);\n}\n\n// You can add some keys manually to attributes or telemetry\nattributes.eui = data.EUI;\nattributes.fPort = data.port;\nattributes.frequency = data.freq;\n\nvar addDataToTelemetry = {};\naddDataToTelemetry.rssi = data.rssi;\naddDataToTelemetry.seqno = data.seqno;\naddDataToTelemetry.snr = data.snr;\naddDataToTelemetry.ack = data.ack;\naddDataToTelemetry.toa = data.toa;\naddDataToTelemetry.fCnt = data.fcnt;\n\nvar isIncludeGatewayInfo = metadata[\"includeGatewayInfo\"];\nif(isIncludeGatewayInfo == true) {\n telemetry = processTelemetryData(telemetry, addDataToTelemetry);\n}\n\nvar deviceInfo = {\n deviceName: deviceName,\n deviceType: deviceType,\n// assetName: assetName,\n// assetType: assetType,\n attributes: attributes,\n telemetry: telemetry, \n};\n\naddAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName);\n\nuplinkDataList.add(deviceInfo);\n\nvar includeGatewayInfo = [\"ts\", \"gweui\", \"rssi\"];\n\nvar gatewayDeviceNamePrefix = \"Gateway \";\nvar gatewayDeviceType = \"Lora gateway\";\nvar gatewayGroupName = null; // If gatewayGroupName is not null - created device will be added to the entity group with such name.\n\nif (data.cmd == \"gw\") {\n foreach( gatewayInfo : data.gws ) {\n var gatewayInfoMsg = {\n deviceName: gatewayDeviceNamePrefix + gatewayInfo.gweui,\n deviceType: gatewayDeviceType,\n telemetry: [{\n \"ts\": parseDateToTimestamp(gatewayInfo.ts),\n \"values\": getDataList(gatewayInfo, includeGatewayInfo)\n }],\n attributes: {\n eui: gatewayInfo.gweui\n }\n };\n addAdditionalInfoForDeviceMsg(gatewayInfoMsg, customerName, gatewayGroupName);\n uplinkDataList.add(gatewayInfoMsg);\n }\n}\n\nreturn uplinkDataList;\n\nfunction addAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName) {\n if (customerName != null) {\n deviceInfo.customerName = customerName;\n }\n if (groupName != null) {\n deviceInfo.groupName = groupName;\n }\n}\n\nfunction parseDateToTimestamp(dateString) {\n var timestamp = -1;\n if (dateString != null) {\n \n timestamp = new Date(dateString).getTime();\n if (timestamp == -1) {\n var secondsSeparatorIndex = dateString.lastIndexOf('.') + 1;\n var millisecondsEndIndex = dateString.lastIndexOf('+');\n if (millisecondsEndIndex == -1) {\n millisecondsEndIndex = dateString.lastIndexOf('Z');\n }\n if (millisecondsEndIndex == -1) {\n millisecondsEndIndex = dateString.lastIndexOf('-');\n }\n if (millisecondsEndIndex == -1) {\n if (dateString.length >= secondsSeparatorIndex + 3) {\n dateString = dateString.substring(0, secondsSeparatorIndex + 3);\n }\n } else {\n dateString = dateString.substring(0, secondsSeparatorIndex + 3) +\n dateString.substring(millisecondsEndIndex, dateString.length);\n }\n \n timestamp = new Date(dateString).getTime();\n }\n }\n // If we cannot parse timestamp - we will use the current timestamp\n if (timestamp == -1) {\n timestamp = Date.now();\n }\n \n return timestamp;\n}\n\nfunction processTelemetryData(telemetry, addDataToTelemetry) {\n if (telemetry.size > 1) {\n telemetry = addDataToMultipleTelemetries(telemetry, addDataToTelemetry);\n }\n else if (telemetry.size == 1) {\n telemetry = addDataToSingleTelemetry(telemetry, addDataToTelemetry);\n }\n else {\n telemetry.add(addDataToTelemetry);\n }\n \n return telemetry;\n}\n\nfunction addDataToMultipleTelemetries(telemetry, addDataToTelemetry) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[0][\"values\"].keys.contains(element.key)) {\n telemetry[0][\"values\"][element.key] = element.value;\n }\n if (!telemetry[1][\"values\"].keys.contains(element.key)) {\n telemetry[1][\"values\"][element.key] = element.value;\n }\n }\n \n return telemetry;\n}\n\nfunction addDataToSingleTelemetry(telemetry, addDataToTelemetry) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[0][\"values\"].keys.contains(element.key)) {\n telemetry[0][\"values\"][element.key] = element.value;\n }\n }\n \n return telemetry;\n}", + "tbelDecoder": "var data = decodeToJson(payload);\nvar deviceName = \"ERS2 \" + data.EUI;\nvar deviceType = \"ERS2\";\nvar groupName = null; // If groupName is not null - created device will be added to the entity group with such name.\nvar customerName = null; // If customerName is not null - created devices will be assigned to customer with such name. \n\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// If you want to parse incoming data somehow, you can add your code to this function.\n// input: bytes\n// expected output:\n// {\n// \"attributes\": {\"attributeKey\": \"attributeValue\"},\n// \"telemetry\": {\"telemetryKey\": \"telemetryValue\"}\n// }\n\nfunction decodePayload(input) {\n var output = { attributes: {}, telemetry: []};\n \n // --- Decoding code --- //\n var decoded = {};\n for (var i = 0; i < input.length;) {\n var type = input[i++] & 0xff;\n \n if (type == 0x01) { \n // Temperature Converts to °C\n decoded.temperature = parseBytesToInt(input, i, 2, true) / 10;\n i += 2;\n } else if (type == 0x02) { // Humidity\n decoded.humidity = input[i];\n i += 1;\n } else if (type == 0x04) { // Light\n decoded.light = parseBytesToInt(input, i, 2, true);\n i += 2;\n } else if (type == 0x05) { // Motion (PIR)\n decoded.pir = input[i];\n i += 1;\n } else if (type == 0x07) { // Battery Voltage (VDD)\n decoded.vdd = parseBytesToInt(input, i, 2, true); \n i += 2;\n }\n }\n \n output.telemetry = [{\n ts: timestamp,\n values: decoded\n }];\n\n // --- Decoding code --- //\n return output;\n}\n\n// --- attributes and telemetry objects ---\nvar telemetry = [];\nvar attributes = {};\n// --- attributes and telemetry objects ---\n\n// --- Timestamp parsing\ntimestamp = data.ts;\n// --- Timestamp parsing\n\n// Message parsing\n// To avoid paths in the decoded objects we passing false value to function as \"pathInKey\" argument.\n// Warning: pathInKey can cause already found fields to be overwritten with the last value found.\n\nvar uplinkDataList = [];\n\n// Passing incoming bytes to decodePayload function, to get custom decoding\nvar customDecoding = decodePayload(hexToBytes(data.data));\n\n// Collecting data to result\nif (customDecoding.?telemetry.size() > 0) {\n if (customDecoding.telemetry instanceof java.util.ArrayList) {\n foreach(telemetryObj: customDecoding.telemetry) {\n if (telemetryObj.ts != null && telemetryObj.values != null) {\n telemetry.add(telemetryObj);\n }\n }\n } else {\n telemetry.putAll(customDecoding.telemetry);\n }\n}\n\nif (customDecoding.?attributes.size() > 0) {\n attributes.putAll(customDecoding.attributes);\n}\n\n// You can add some keys manually to attributes or telemetry\nattributes.eui = data.EUI;\nattributes.fPort = data.port;\nattributes.frequency = data.freq;\n\nvar addDataToTelemetry = {};\naddDataToTelemetry.rssi = data.rssi;\naddDataToTelemetry.seqno = data.seqno;\naddDataToTelemetry.snr = data.snr;\naddDataToTelemetry.ack = data.ack;\naddDataToTelemetry.toa = data.toa;\naddDataToTelemetry.fCnt = data.fcnt;\n\nvar isIncludeGatewayInfo = metadata[\"includeGatewayInfo\"];\nif(isIncludeGatewayInfo == true) {\n telemetry = processTelemetryData(telemetry, addDataToTelemetry);\n}\n\nvar deviceInfo = {\n deviceName: deviceName,\n deviceType: deviceType,\n// assetName: assetName,\n// assetType: assetType,\n attributes: attributes,\n telemetry: telemetry, \n};\n\naddAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName);\n\nuplinkDataList.add(deviceInfo);\n\nvar gatewayDeviceNamePrefix = \"Gateway \";\nvar gatewayDeviceType = \"Lora gateway\";\nvar gatewayGroupName = null; // If gatewayGroupName is not null - created device will be added to the entity group with such name.\n\nif (data.cmd == \"gw\") {\n foreach( gatewayInfo : data.gws ) {\n var addGatewayInfo = {};\n\n // You can add some keys manually telemetry\n addGatewayInfo.rssi = gatewayInfo.rssi;\n addGatewayInfo.snr = gatewayInfo.snr;\n // You can add some keys manually telemetry\n \n var gatewayInfoMsg = {\n deviceName: gatewayDeviceNamePrefix + gatewayInfo.gweui,\n deviceType: gatewayDeviceType,\n telemetry: [{\n \"ts\": gatewayInfo.ts,\n \"values\": addGatewayInfo\n }],\n attributes: {\n eui: gatewayInfo.gweui\n }\n };\n addAdditionalInfoForDeviceMsg(gatewayInfoMsg, customerName, gatewayGroupName);\n uplinkDataList.add(gatewayInfoMsg);\n }\n}\n\nreturn uplinkDataList;\n\nfunction addAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName) {\n if (customerName != null) {\n deviceInfo.customerName = customerName;\n }\n if (groupName != null) {\n deviceInfo.groupName = groupName;\n }\n}\n\nfunction parseDateToTimestamp(dateString) {\n var timestamp = -1;\n if (dateString != null) {\n \n timestamp = new Date(dateString).getTime();\n if (timestamp == -1) {\n var secondsSeparatorIndex = dateString.lastIndexOf('.') + 1;\n var millisecondsEndIndex = dateString.lastIndexOf('+');\n if (millisecondsEndIndex == -1) {\n millisecondsEndIndex = dateString.lastIndexOf('Z');\n }\n if (millisecondsEndIndex == -1) {\n millisecondsEndIndex = dateString.lastIndexOf('-');\n }\n if (millisecondsEndIndex == -1) {\n if (dateString.length >= secondsSeparatorIndex + 3) {\n dateString = dateString.substring(0, secondsSeparatorIndex + 3);\n }\n } else {\n dateString = dateString.substring(0, secondsSeparatorIndex + 3) +\n dateString.substring(millisecondsEndIndex, dateString.length);\n }\n \n timestamp = new Date(dateString).getTime();\n }\n }\n // If we cannot parse timestamp - we will use the current timestamp\n if (timestamp == -1) {\n timestamp = Date.now();\n }\n \n return timestamp;\n}\n\nfunction processTelemetryData(telemetry, addDataToTelemetry) {\n if (telemetry.size > 1) {\n telemetry = addDataToMultipleTelemetries(telemetry, addDataToTelemetry);\n }\n else if (telemetry.size == 1) {\n telemetry = addDataToSingleTelemetry(telemetry, addDataToTelemetry);\n }\n else {\n telemetry.add(addDataToTelemetry);\n }\n \n return telemetry;\n}\n\nfunction addDataToMultipleTelemetries(telemetry, addDataToTelemetry) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[0][\"values\"].keys.contains(element.key)) {\n telemetry[0][\"values\"][element.key] = element.value;\n }\n if (!telemetry[1][\"values\"].keys.contains(element.key)) {\n telemetry[1][\"values\"][element.key] = element.value;\n }\n }\n \n return telemetry;\n}\n\nfunction addDataToSingleTelemetry(telemetry, addDataToTelemetry) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[0][\"values\"].keys.contains(element.key)) {\n telemetry[0][\"values\"][element.key] = element.value;\n }\n }\n \n return telemetry;\n}", "encoder": null, "tbelEncoder": null, "updateOnlyKeys": [ diff --git a/VENDORS/Elsys/ERS2/LORIOT/uplink/payload_1.json b/VENDORS/Elsys/ERS2/LORIOT/uplink/payload_1.json new file mode 100644 index 00000000..8742d0c5 --- /dev/null +++ b/VENDORS/Elsys/ERS2/LORIOT/uplink/payload_1.json @@ -0,0 +1,32 @@ +{ + "cmd": "gw", + "seqno": 4, + "EUI": "0102030405060708", + "ts": 1690901260493, + "fcnt": 3, + "port": 207, + "freq": 868300000, + "toa": 1319, + "dr": "SF12 BW125 4/5", + "ack": false, + "gws": [ + { + "rssi": -38, + "snr": 8.5, + "ts": 1690901260493, + "time": "2023-08-01T14:47:40.493Z", + "gweui": "1020304080706050", + "ant": 0 + }, + { + "rssi": -42, + "snr": 8.8, + "ts": 1690901260495, + "time": "2023-08-01T14:47:40.495Z", + "gweui": "1020304081716151", + "ant": 0 + } + ], + "bat": 143, + "data": "0100e202290400270506060308070d62" +} \ No newline at end of file diff --git a/VENDORS/Elsys/ERS2/LORIOT/uplink/result_1.json b/VENDORS/Elsys/ERS2/LORIOT/uplink/result_1.json new file mode 100644 index 00000000..10fd392e --- /dev/null +++ b/VENDORS/Elsys/ERS2/LORIOT/uplink/result_1.json @@ -0,0 +1,45 @@ +[{ + "deviceName": "ERS2 0102030405060708", + "deviceType": "ERS2", + "attributes": { + "eui": "0102030405060708", + "fPort": 207, + "frequency": 868300000 + }, + "telemetry": [{ + "ts": 1690901260493, + "values": { + "temperature": 22.6, + "humidity": 41, + "light": 39, + "pir": 6, + "vdd": 3426 + } + }] +}, { + "deviceName": "Gateway 1020304080706050", + "deviceType": "Lora gateway", + "telemetry": [{ + "ts": 1690901260493, + "values": { + "rssi": -38, + "snr": 8.5 + } + }], + "attributes": { + "eui": "1020304080706050" + } +}, { + "deviceName": "Gateway 1020304081716151", + "deviceType": "Lora gateway", + "telemetry": [{ + "ts": 1690901260495, + "values": { + "rssi": -42, + "snr": 8.8 + } + }], + "attributes": { + "eui": "1020304081716151" + } +}] \ No newline at end of file diff --git a/VENDORS/Elsys/ERS2_CO2/LORIOT/uplink/converter.json b/VENDORS/Elsys/ERS2_CO2/LORIOT/uplink/converter.json index 2c462394..024f2cb1 100644 --- a/VENDORS/Elsys/ERS2_CO2/LORIOT/uplink/converter.json +++ b/VENDORS/Elsys/ERS2_CO2/LORIOT/uplink/converter.json @@ -1,11 +1,16 @@ { "name": "Loriot Uplink Decoder for Elsys ERS2 C02 Device", "type": "UPLINK", - "debugMode": true, + "debugMode": false, + "debugSettings": { + "failuresEnabled": true, + "allEnabled": false, + "allEnabledUntil": 1735046693295 + }, "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);\nvar deviceName = \"ERS2 CO2 \" + data.EUI;\nvar deviceType = \"ERS2 CO2\";\nvar groupName = null; // If groupName is not null - created device will be added to the entity group with such name.\nvar customerName = null; // If customerName is not null - created devices will be assigned to customer with such name. \n\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// If you want to parse incoming data somehow, you can add your code to this function.\n// input: bytes\n// expected output:\n// {\n// \"attributes\": {\"attributeKey\": \"attributeValue\"},\n// \"telemetry\": {\"telemetryKey\": \"telemetryValue\"}\n// }\n\nfunction decodePayload(input) {\n var output = { attributes: {}, telemetry: []};\n \n // --- Decoding code --- //\n var decoded = {};\n for (var i = 0; i < input.length;) {\n var type = input[i++] & 0xff;\n \n if (type == 0x01) { \n // Temperature Converts to °C\n decoded.temperature = parseBytesToInt(input, i, 2, true) / 10;\n i += 2;\n } else if (type == 0x02) { // Humidity\n decoded.humidity = input[i];\n i += 1;\n } else if (type == 0x04) { // Light\n decoded.light = parseBytesToInt(input, i, 2, true);\n i += 2;\n } else if (type == 0x05) { // Pir\n decoded.pir = input[i];\n i += 1;\n } else if (type == 0x06) { // CO₂\n decoded.co2 = parseBytesToInt(input, i, 2, true);\n i += 2;\n } else if (type == 0x07) { // Battery Voltage (VDD)\n decoded.vdd = parseBytesToInt(input, i, 2, true); \n i += 2;\n }\n }\n \n output.telemetry = [{\n ts: timestamp,\n values: decoded\n }];\n\n // --- Decoding code --- //\n return output;\n}\n\n// --- attributes and telemetry objects ---\nvar telemetry = [];\nvar attributes = {};\n// --- attributes and telemetry objects ---\n\n// --- Timestamp parsing\ntimestamp = data.ts;\n// --- Timestamp parsing\n\n// Message parsing\n// To avoid paths in the decoded objects we passing false value to function as \"pathInKey\" argument.\n// Warning: pathInKey can cause already found fields to be overwritten with the last value found.\n\nvar uplinkDataList = [];\n\n// Passing incoming bytes to decodePayload function, to get custom decoding\nvar customDecoding = decodePayload(hexToBytes(data.data));\n\n// Collecting data to result\nif (customDecoding.?telemetry.size() > 0) {\n if (customDecoding.telemetry instanceof java.util.ArrayList) {\n foreach(telemetryObj: customDecoding.telemetry) {\n if (telemetryObj.ts != null && telemetryObj.values != null) {\n telemetry.add(telemetryObj);\n }\n }\n } else {\n telemetry.putAll(customDecoding.telemetry);\n }\n}\n\nif (customDecoding.?attributes.size() > 0) {\n attributes.putAll(customDecoding.attributes);\n}\n\n// You can add some keys manually to attributes or telemetry\nattributes.eui = data.EUI;\nattributes.fPort = data.port;\nattributes.frequency = data.freq;\n\nvar isIncludeGatewayInfo = metadata[\"includeGatewayInfo\"];\nif(isIncludeGatewayInfo == true) {\n var addDataToTelemetry = {};\n addDataToTelemetry.rssi = data.rssi;\n addDataToTelemetry.seqno = data.seqno;\n addDataToTelemetry.snr = data.snr;\n addDataToTelemetry.ack = data.ack;\n addDataToTelemetry.toa = data.toa;\n addDataToTelemetry.fCnt = data.fcnt;\n \n telemetry = processTelemetryData(telemetry, addDataToTelemetry);\n}\n\nvar deviceInfo = {\n deviceName: deviceName,\n deviceType: deviceType,\n// assetName: assetName,\n// assetType: assetType,\n attributes: attributes,\n telemetry: telemetry, \n};\n\naddAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName);\n\nuplinkDataList.add(deviceInfo);\n\nvar includeGatewayInfo = [\"ts\", \"gweui\", \"rssi\"];\n\nvar gatewayDeviceNamePrefix = \"Gateway \";\nvar gatewayDeviceType = \"Lora gateway\";\nvar gatewayGroupName = null; // If gatewayGroupName is not null - created device will be added to the entity group with such name.\n\nif (data.cmd == \"gw\") {\n foreach( gatewayInfo : data.gws ) {\n var addGatewayInfo = {};\n\n // You can add some keys manually telemetry\n addGatewayInfo.rssi = gatewayInfo.rssi;\n addGatewayInfo.snr = gatewayInfo.snr;\n // You can add some keys manually telemetry\n \n var gatewayInfoMsg = {\n deviceName: gatewayDeviceNamePrefix + gatewayInfo.gweui,\n deviceType: gatewayDeviceType,\n telemetry: [{\n \"ts\": gatewayInfo.ts,\n \"values\": addGatewayInfo\n }],\n attributes: {\n eui: gatewayInfo.gweui\n }\n };\n addAdditionalInfoForDeviceMsg(gatewayInfoMsg, customerName, gatewayGroupName);\n uplinkDataList.add(gatewayInfoMsg);\n }\n}\n\nreturn uplinkDataList;\n\nfunction addAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName) {\n if (customerName != null) {\n deviceInfo.customerName = customerName;\n }\n if (groupName != null) {\n deviceInfo.groupName = groupName;\n }\n}\n\nfunction processTelemetryData(telemetry, addDataToTelemetry) {\n if (telemetry.size > 1) {\n telemetry = addDataToMultipleTelemetries(telemetry, addDataToTelemetry);\n }\n else if (telemetry.size == 1) {\n telemetry = addDataToSingleTelemetry(telemetry, addDataToTelemetry);\n }\n else {\n telemetry.add(addDataToTelemetry);\n }\n \n return telemetry;\n}\n\nfunction addDataToMultipleTelemetries(telemetry, addDataToTelemetry) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[0][\"values\"].keys.contains(element.key)) {\n telemetry[0][\"values\"][element.key] = element.value;\n }\n if (!telemetry[1][\"values\"].keys.contains(element.key)) {\n telemetry[1][\"values\"][element.key] = element.value;\n }\n }\n \n return telemetry;\n}\n\nfunction addDataToSingleTelemetry(telemetry, addDataToTelemetry) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[0][\"values\"].keys.contains(element.key)) {\n telemetry[0][\"values\"][element.key] = element.value;\n }\n }\n \n return telemetry;\n}", + "tbelDecoder": "var data = decodeToJson(payload);\nvar deviceName = \"ERS2 CO2 \" + data.EUI;\nvar deviceType = \"ERS2 CO2\";\nvar groupName = null; // If groupName is not null - created device will be added to the entity group with such name.\nvar customerName = null; // If customerName is not null - created devices will be assigned to customer with such name. \n\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// If you want to parse incoming data somehow, you can add your code to this function.\n// input: bytes\n// expected output:\n// {\n// \"attributes\": {\"attributeKey\": \"attributeValue\"},\n// \"telemetry\": {\"telemetryKey\": \"telemetryValue\"}\n// }\n\nfunction decodePayload(input) {\n var output = { attributes: {}, telemetry: []};\n \n // --- Decoding code --- //\n var decoded = {};\n for (var i = 0; i < input.length;) {\n var type = input[i++] & 0xff;\n \n if (type == 0x01) { \n // Temperature Converts to °C\n decoded.temperature = parseBytesToInt(input, i, 2, true) / 10;\n i += 2;\n } else if (type == 0x02) { // Humidity\n decoded.humidity = input[i];\n i += 1;\n } else if (type == 0x04) { // Light\n decoded.light = parseBytesToInt(input, i, 2, true);\n i += 2;\n } else if (type == 0x05) { // Pir\n decoded.pir = input[i];\n i += 1;\n } else if (type == 0x06) { // CO₂\n decoded.co2 = parseBytesToInt(input, i, 2, true);\n i += 2;\n } else if (type == 0x07) { // Battery Voltage (VDD)\n decoded.vdd = parseBytesToInt(input, i, 2, true); \n i += 2;\n }\n }\n \n output.telemetry = [{\n ts: timestamp,\n values: decoded\n }];\n\n // --- Decoding code --- //\n return output;\n}\n\n// --- attributes and telemetry objects ---\nvar telemetry = [];\nvar attributes = {};\n// --- attributes and telemetry objects ---\n\n// --- Timestamp parsing\ntimestamp = data.ts;\n// --- Timestamp parsing\n\n// Message parsing\n// To avoid paths in the decoded objects we passing false value to function as \"pathInKey\" argument.\n// Warning: pathInKey can cause already found fields to be overwritten with the last value found.\n\nvar uplinkDataList = [];\n\n// Passing incoming bytes to decodePayload function, to get custom decoding\nvar customDecoding = decodePayload(hexToBytes(data.data));\n\n// Collecting data to result\nif (customDecoding.?telemetry.size() > 0) {\n if (customDecoding.telemetry instanceof java.util.ArrayList) {\n foreach(telemetryObj: customDecoding.telemetry) {\n if (telemetryObj.ts != null && telemetryObj.values != null) {\n telemetry.add(telemetryObj);\n }\n }\n } else {\n telemetry.putAll(customDecoding.telemetry);\n }\n}\n\nif (customDecoding.?attributes.size() > 0) {\n attributes.putAll(customDecoding.attributes);\n}\n\n// You can add some keys manually to attributes or telemetry\nattributes.eui = data.EUI;\nattributes.fPort = data.port;\nattributes.frequency = data.freq;\n\nvar isIncludeGatewayInfo = metadata[\"includeGatewayInfo\"];\nif(isIncludeGatewayInfo == true) {\n var addDataToTelemetry = {};\n addDataToTelemetry.rssi = data.rssi;\n addDataToTelemetry.seqno = data.seqno;\n addDataToTelemetry.snr = data.snr;\n addDataToTelemetry.ack = data.ack;\n addDataToTelemetry.toa = data.toa;\n addDataToTelemetry.fCnt = data.fcnt;\n \n telemetry = processTelemetryData(telemetry, addDataToTelemetry);\n}\n\nvar deviceInfo = {\n deviceName: deviceName,\n deviceType: deviceType,\n// assetName: assetName,\n// assetType: assetType,\n attributes: attributes,\n telemetry: telemetry, \n};\n\naddAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName);\n\nuplinkDataList.add(deviceInfo);\n\nvar gatewayDeviceNamePrefix = \"Gateway \";\nvar gatewayDeviceType = \"Lora gateway\";\nvar gatewayGroupName = null; // If gatewayGroupName is not null - created device will be added to the entity group with such name.\n\nif (data.cmd == \"gw\") {\n foreach( gatewayInfo : data.gws ) {\n var addGatewayInfo = {};\n\n // You can add some keys manually telemetry\n addGatewayInfo.rssi = gatewayInfo.rssi;\n addGatewayInfo.snr = gatewayInfo.snr;\n // You can add some keys manually telemetry\n \n var gatewayInfoMsg = {\n deviceName: gatewayDeviceNamePrefix + gatewayInfo.gweui,\n deviceType: gatewayDeviceType,\n telemetry: [{\n \"ts\": gatewayInfo.ts,\n \"values\": addGatewayInfo\n }],\n attributes: {\n eui: gatewayInfo.gweui\n }\n };\n addAdditionalInfoForDeviceMsg(gatewayInfoMsg, customerName, gatewayGroupName);\n uplinkDataList.add(gatewayInfoMsg);\n }\n}\n\nreturn uplinkDataList;\n\nfunction addAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName) {\n if (customerName != null) {\n deviceInfo.customerName = customerName;\n }\n if (groupName != null) {\n deviceInfo.groupName = groupName;\n }\n}\n\nfunction processTelemetryData(telemetry, addDataToTelemetry) {\n if (telemetry.size > 1) {\n telemetry = addDataToMultipleTelemetries(telemetry, addDataToTelemetry);\n }\n else if (telemetry.size == 1) {\n telemetry = addDataToSingleTelemetry(telemetry, addDataToTelemetry);\n }\n else {\n telemetry.add(addDataToTelemetry);\n }\n \n return telemetry;\n}\n\nfunction addDataToMultipleTelemetries(telemetry, addDataToTelemetry) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[0][\"values\"].keys.contains(element.key)) {\n telemetry[0][\"values\"][element.key] = element.value;\n }\n if (!telemetry[1][\"values\"].keys.contains(element.key)) {\n telemetry[1][\"values\"][element.key] = element.value;\n }\n }\n \n return telemetry;\n}\n\nfunction addDataToSingleTelemetry(telemetry, addDataToTelemetry) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[0][\"values\"].keys.contains(element.key)) {\n telemetry[0][\"values\"][element.key] = element.value;\n }\n }\n \n return telemetry;\n}", "encoder": null, "tbelEncoder": null, "updateOnlyKeys": [ diff --git a/VENDORS/Elsys/ERS2_CO2/LORIOT/uplink/payload_1.json b/VENDORS/Elsys/ERS2_CO2/LORIOT/uplink/payload_1.json new file mode 100644 index 00000000..8742d0c5 --- /dev/null +++ b/VENDORS/Elsys/ERS2_CO2/LORIOT/uplink/payload_1.json @@ -0,0 +1,32 @@ +{ + "cmd": "gw", + "seqno": 4, + "EUI": "0102030405060708", + "ts": 1690901260493, + "fcnt": 3, + "port": 207, + "freq": 868300000, + "toa": 1319, + "dr": "SF12 BW125 4/5", + "ack": false, + "gws": [ + { + "rssi": -38, + "snr": 8.5, + "ts": 1690901260493, + "time": "2023-08-01T14:47:40.493Z", + "gweui": "1020304080706050", + "ant": 0 + }, + { + "rssi": -42, + "snr": 8.8, + "ts": 1690901260495, + "time": "2023-08-01T14:47:40.495Z", + "gweui": "1020304081716151", + "ant": 0 + } + ], + "bat": 143, + "data": "0100e202290400270506060308070d62" +} \ No newline at end of file diff --git a/VENDORS/Elsys/ERS2_CO2/LORIOT/uplink/result_1.json b/VENDORS/Elsys/ERS2_CO2/LORIOT/uplink/result_1.json new file mode 100644 index 00000000..aa38c3e6 --- /dev/null +++ b/VENDORS/Elsys/ERS2_CO2/LORIOT/uplink/result_1.json @@ -0,0 +1,46 @@ +[{ + "deviceName": "ERS2 CO2 0102030405060708", + "deviceType": "ERS2 CO2", + "attributes": { + "eui": "0102030405060708", + "fPort": 207, + "frequency": 868300000 + }, + "telemetry": [{ + "ts": 1690901260493, + "values": { + "temperature": 22.6, + "humidity": 41, + "light": 39, + "pir": 6, + "co2": 776, + "vdd": 3426 + } + }] +}, { + "deviceName": "Gateway 1020304080706050", + "deviceType": "Lora gateway", + "telemetry": [{ + "ts": 1690901260493, + "values": { + "rssi": -38, + "snr": 8.5 + } + }], + "attributes": { + "eui": "1020304080706050" + } +}, { + "deviceName": "Gateway 1020304081716151", + "deviceType": "Lora gateway", + "telemetry": [{ + "ts": 1690901260495, + "values": { + "rssi": -42, + "snr": 8.8 + } + }], + "attributes": { + "eui": "1020304081716151" + } +}] \ No newline at end of file diff --git a/VENDORS/Elsys/ERS2_CO2_Lite/LORIOT/uplink/converter.json b/VENDORS/Elsys/ERS2_CO2_Lite/LORIOT/uplink/converter.json index 9dc26aa4..80acd49e 100644 --- a/VENDORS/Elsys/ERS2_CO2_Lite/LORIOT/uplink/converter.json +++ b/VENDORS/Elsys/ERS2_CO2_Lite/LORIOT/uplink/converter.json @@ -1,11 +1,16 @@ { "name": "Loriot Uplink Decoder for Elsys ERS2 C02 Lite Device", "type": "UPLINK", - "debugMode": true, + "debugMode": false, + "debugSettings": { + "failuresEnabled": true, + "allEnabled": false, + "allEnabledUntil": 1735046825246 + }, "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);\nvar deviceName = \"ERS2 CO2 Lite \" + data.EUI;\nvar deviceType = \"ERS2 CO2 Lite\";\nvar groupName = null; // If groupName is not null - created device will be added to the entity group with such name.\nvar customerName = null; // If customerName is not null - created devices will be assigned to customer with such name. \n\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// If you want to parse incoming data somehow, you can add your code to this function.\n// input: bytes\n// expected output:\n// {\n// \"attributes\": {\"attributeKey\": \"attributeValue\"},\n// \"telemetry\": {\"telemetryKey\": \"telemetryValue\"}\n// }\n\nfunction decodePayload(input) {\n var output = { attributes: {}, telemetry: []};\n \n // --- Decoding code --- //\n var decoded = {};\n for (var i = 0; i < input.length;) {\n var type = input[i++] & 0xff;\n \n if (type == 0x01) { \n // Temperature Converts to °C\n decoded.temperature = parseBytesToInt(input, i, 2, true) / 10;\n i += 2;\n } else if (type == 0x02) { // Humidity\n decoded.humidity = input[i];\n i += 1;\n } else if (type == 0x06) { // CO₂\n decoded.co2 = parseBytesToInt(input, i, 2, true);\n i += 2;\n } else if (type == 0x07) { // Battery Voltage (VDD)\n decoded.vdd = parseBytesToInt(input, i, 2, true); \n i += 2;\n }\n }\n \n output.telemetry = [{\n ts: timestamp,\n values: decoded\n }];\n\n // --- Decoding code --- //\n return output;\n}\n\n// --- attributes and telemetry objects ---\nvar telemetry = [];\nvar attributes = {};\n// --- attributes and telemetry objects ---\n\n// --- Timestamp parsing\ntimestamp = data.ts;\n// --- Timestamp parsing\n\n// Message parsing\n// To avoid paths in the decoded objects we passing false value to function as \"pathInKey\" argument.\n// Warning: pathInKey can cause already found fields to be overwritten with the last value found.\n\nvar uplinkDataList = [];\n\n// Passing incoming bytes to decodePayload function, to get custom decoding\nvar customDecoding = decodePayload(hexToBytes(data.data));\n\n// Collecting data to result\nif (customDecoding.?telemetry.size() > 0) {\n if (customDecoding.telemetry instanceof java.util.ArrayList) {\n foreach(telemetryObj: customDecoding.telemetry) {\n if (telemetryObj.ts != null && telemetryObj.values != null) {\n telemetry.add(telemetryObj);\n }\n }\n } else {\n telemetry.putAll(customDecoding.telemetry);\n }\n}\n\nif (customDecoding.?attributes.size() > 0) {\n attributes.putAll(customDecoding.attributes);\n}\n\n// You can add some keys manually to attributes or telemetry\nattributes.eui = data.EUI;\nattributes.fPort = data.port;\nattributes.frequency = data.freq;\n\nvar isIncludeGatewayInfo = metadata[\"includeGatewayInfo\"];\nif(isIncludeGatewayInfo == true) {\n var addDataToTelemetry = {};\n addDataToTelemetry.rssi = data.rssi;\n addDataToTelemetry.seqno = data.seqno;\n addDataToTelemetry.snr = data.snr;\n addDataToTelemetry.ack = data.ack;\n addDataToTelemetry.toa = data.toa;\n addDataToTelemetry.fCnt = data.fcnt;\n \n telemetry = processTelemetryData(telemetry, addDataToTelemetry);\n}\n\nvar deviceInfo = {\n deviceName: deviceName,\n deviceType: deviceType,\n// assetName: assetName,\n// assetType: assetType,\n attributes: attributes,\n telemetry: telemetry, \n};\n\naddAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName);\n\nuplinkDataList.add(deviceInfo);\n\nvar includeGatewayInfo = [\"ts\", \"gweui\", \"rssi\"];\n\nvar gatewayDeviceNamePrefix = \"Gateway \";\nvar gatewayDeviceType = \"Lora gateway\";\nvar gatewayGroupName = null; // If gatewayGroupName is not null - created device will be added to the entity group with such name.\n\nif (data.cmd == \"gw\") {\n foreach( gatewayInfo : data.gws ) {\n var addGatewayInfo = {};\n\n // You can add some keys manually telemetry\n addGatewayInfo.rssi = gatewayInfo.rssi;\n addGatewayInfo.snr = gatewayInfo.snr;\n // You can add some keys manually telemetry\n \n var gatewayInfoMsg = {\n deviceName: gatewayDeviceNamePrefix + gatewayInfo.gweui,\n deviceType: gatewayDeviceType,\n telemetry: [{\n \"ts\": gatewayInfo.ts,\n \"values\": addGatewayInfo\n }],\n attributes: {\n eui: gatewayInfo.gweui\n }\n };\n addAdditionalInfoForDeviceMsg(gatewayInfoMsg, customerName, gatewayGroupName);\n uplinkDataList.add(gatewayInfoMsg);\n }\n}\n\nreturn uplinkDataList;\n\nfunction addAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName) {\n if (customerName != null) {\n deviceInfo.customerName = customerName;\n }\n if (groupName != null) {\n deviceInfo.groupName = groupName;\n }\n}\n\nfunction processTelemetryData(telemetry, addDataToTelemetry) {\n if (telemetry.size > 1) {\n telemetry = addDataToMultipleTelemetries(telemetry, addDataToTelemetry);\n }\n else if (telemetry.size == 1) {\n telemetry = addDataToSingleTelemetry(telemetry, addDataToTelemetry);\n }\n else {\n telemetry.add(addDataToTelemetry);\n }\n \n return telemetry;\n}\n\nfunction addDataToMultipleTelemetries(telemetry, addDataToTelemetry) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[0][\"values\"].keys.contains(element.key)) {\n telemetry[0][\"values\"][element.key] = element.value;\n }\n if (!telemetry[1][\"values\"].keys.contains(element.key)) {\n telemetry[1][\"values\"][element.key] = element.value;\n }\n }\n \n return telemetry;\n}\n\nfunction addDataToSingleTelemetry(telemetry, addDataToTelemetry) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[0][\"values\"].keys.contains(element.key)) {\n telemetry[0][\"values\"][element.key] = element.value;\n }\n }\n \n return telemetry;\n}", + "tbelDecoder": "var data = decodeToJson(payload);\nvar deviceName = \"ERS2 CO2 Lite \" + data.EUI;\nvar deviceType = \"ERS2 CO2 Lite\";\nvar groupName = null; // If groupName is not null - created device will be added to the entity group with such name.\nvar customerName = null; // If customerName is not null - created devices will be assigned to customer with such name. \n\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// If you want to parse incoming data somehow, you can add your code to this function.\n// input: bytes\n// expected output:\n// {\n// \"attributes\": {\"attributeKey\": \"attributeValue\"},\n// \"telemetry\": {\"telemetryKey\": \"telemetryValue\"}\n// }\n\nfunction decodePayload(input) {\n var output = { attributes: {}, telemetry: []};\n \n // --- Decoding code --- //\n var decoded = {};\n for (var i = 0; i < input.length;) {\n var type = input[i++] & 0xff;\n \n if (type == 0x01) { \n // Temperature Converts to °C\n decoded.temperature = parseBytesToInt(input, i, 2, true) / 10;\n i += 2;\n } else if (type == 0x02) { // Humidity\n decoded.humidity = input[i];\n i += 1;\n } else if (type == 0x06) { // CO₂\n decoded.co2 = parseBytesToInt(input, i, 2, true);\n i += 2;\n } else if (type == 0x07) { // Battery Voltage (VDD)\n decoded.vdd = parseBytesToInt(input, i, 2, true); \n i += 2;\n }\n }\n \n output.telemetry = [{\n ts: timestamp,\n values: decoded\n }];\n\n // --- Decoding code --- //\n return output;\n}\n\n// --- attributes and telemetry objects ---\nvar telemetry = [];\nvar attributes = {};\n// --- attributes and telemetry objects ---\n\n// --- Timestamp parsing\ntimestamp = data.ts;\n// --- Timestamp parsing\n\n// Message parsing\n// To avoid paths in the decoded objects we passing false value to function as \"pathInKey\" argument.\n// Warning: pathInKey can cause already found fields to be overwritten with the last value found.\n\nvar uplinkDataList = [];\n\n// Passing incoming bytes to decodePayload function, to get custom decoding\nvar customDecoding = decodePayload(hexToBytes(data.data));\n\n// Collecting data to result\nif (customDecoding.?telemetry.size() > 0) {\n if (customDecoding.telemetry instanceof java.util.ArrayList) {\n foreach(telemetryObj: customDecoding.telemetry) {\n if (telemetryObj.ts != null && telemetryObj.values != null) {\n telemetry.add(telemetryObj);\n }\n }\n } else {\n telemetry.putAll(customDecoding.telemetry);\n }\n}\n\nif (customDecoding.?attributes.size() > 0) {\n attributes.putAll(customDecoding.attributes);\n}\n\n// You can add some keys manually to attributes or telemetry\nattributes.eui = data.EUI;\nattributes.fPort = data.port;\nattributes.frequency = data.freq;\n\nvar isIncludeGatewayInfo = metadata[\"includeGatewayInfo\"];\nif(isIncludeGatewayInfo == true) {\n var addDataToTelemetry = {};\n addDataToTelemetry.rssi = data.rssi;\n addDataToTelemetry.seqno = data.seqno;\n addDataToTelemetry.snr = data.snr;\n addDataToTelemetry.ack = data.ack;\n addDataToTelemetry.toa = data.toa;\n addDataToTelemetry.fCnt = data.fcnt;\n \n telemetry = processTelemetryData(telemetry, addDataToTelemetry);\n}\n\nvar deviceInfo = {\n deviceName: deviceName,\n deviceType: deviceType,\n// assetName: assetName,\n// assetType: assetType,\n attributes: attributes,\n telemetry: telemetry, \n};\n\naddAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName);\n\nuplinkDataList.add(deviceInfo);\n\nvar gatewayDeviceNamePrefix = \"Gateway \";\nvar gatewayDeviceType = \"Lora gateway\";\nvar gatewayGroupName = null; // If gatewayGroupName is not null - created device will be added to the entity group with such name.\n\nif (data.cmd == \"gw\") {\n foreach( gatewayInfo : data.gws ) {\n var addGatewayInfo = {};\n\n // You can add some keys manually telemetry\n addGatewayInfo.rssi = gatewayInfo.rssi;\n addGatewayInfo.snr = gatewayInfo.snr;\n // You can add some keys manually telemetry\n \n var gatewayInfoMsg = {\n deviceName: gatewayDeviceNamePrefix + gatewayInfo.gweui,\n deviceType: gatewayDeviceType,\n telemetry: [{\n \"ts\": gatewayInfo.ts,\n \"values\": addGatewayInfo\n }],\n attributes: {\n eui: gatewayInfo.gweui\n }\n };\n addAdditionalInfoForDeviceMsg(gatewayInfoMsg, customerName, gatewayGroupName);\n uplinkDataList.add(gatewayInfoMsg);\n }\n}\n\nreturn uplinkDataList;\n\nfunction addAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName) {\n if (customerName != null) {\n deviceInfo.customerName = customerName;\n }\n if (groupName != null) {\n deviceInfo.groupName = groupName;\n }\n}\n\nfunction processTelemetryData(telemetry, addDataToTelemetry) {\n if (telemetry.size > 1) {\n telemetry = addDataToMultipleTelemetries(telemetry, addDataToTelemetry);\n }\n else if (telemetry.size == 1) {\n telemetry = addDataToSingleTelemetry(telemetry, addDataToTelemetry);\n }\n else {\n telemetry.add(addDataToTelemetry);\n }\n \n return telemetry;\n}\n\nfunction addDataToMultipleTelemetries(telemetry, addDataToTelemetry) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[0][\"values\"].keys.contains(element.key)) {\n telemetry[0][\"values\"][element.key] = element.value;\n }\n if (!telemetry[1][\"values\"].keys.contains(element.key)) {\n telemetry[1][\"values\"][element.key] = element.value;\n }\n }\n \n return telemetry;\n}\n\nfunction addDataToSingleTelemetry(telemetry, addDataToTelemetry) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[0][\"values\"].keys.contains(element.key)) {\n telemetry[0][\"values\"][element.key] = element.value;\n }\n }\n \n return telemetry;\n}", "encoder": null, "tbelEncoder": null, "updateOnlyKeys": [ diff --git a/VENDORS/Elsys/ERS2_CO2_Lite/LORIOT/uplink/payload_1.json b/VENDORS/Elsys/ERS2_CO2_Lite/LORIOT/uplink/payload_1.json new file mode 100644 index 00000000..74aa5ddf --- /dev/null +++ b/VENDORS/Elsys/ERS2_CO2_Lite/LORIOT/uplink/payload_1.json @@ -0,0 +1,32 @@ +{ + "cmd": "gw", + "seqno": 4, + "EUI": "0102030405060708", + "ts": 1690901260493, + "fcnt": 3, + "port": 207, + "freq": 868300000, + "toa": 1319, + "dr": "SF12 BW125 4/5", + "ack": false, + "gws": [ + { + "rssi": -38, + "snr": 8.5, + "ts": 1690901260493, + "time": "2023-08-01T14:47:40.493Z", + "gweui": "1020304080706050", + "ant": 0 + }, + { + "rssi": -42, + "snr": 8.8, + "ts": 1690901260495, + "time": "2023-08-01T14:47:40.495Z", + "gweui": "1020304081716151", + "ant": 0 + } + ], + "bat": 143, + "data": "0100e20229060308070d62" +} \ No newline at end of file diff --git a/VENDORS/Elsys/ERS2_CO2_Lite/LORIOT/uplink/result_1.json b/VENDORS/Elsys/ERS2_CO2_Lite/LORIOT/uplink/result_1.json new file mode 100644 index 00000000..025cbacf --- /dev/null +++ b/VENDORS/Elsys/ERS2_CO2_Lite/LORIOT/uplink/result_1.json @@ -0,0 +1,44 @@ +[{ + "deviceName": "ERS2 CO2 Lite 0102030405060708", + "deviceType": "ERS2 CO2 Lite", + "attributes": { + "eui": "0102030405060708", + "fPort": 207, + "frequency": 868300000 + }, + "telemetry": [{ + "ts": 1690901260493, + "values": { + "temperature": 22.6, + "humidity": 41, + "co2": 776, + "vdd": 3426 + } + }] +}, { + "deviceName": "Gateway 1020304080706050", + "deviceType": "Lora gateway", + "telemetry": [{ + "ts": 1690901260493, + "values": { + "rssi": -38, + "snr": 8.5 + } + }], + "attributes": { + "eui": "1020304080706050" + } +}, { + "deviceName": "Gateway 1020304081716151", + "deviceType": "Lora gateway", + "telemetry": [{ + "ts": 1690901260495, + "values": { + "rssi": -42, + "snr": 8.8 + } + }], + "attributes": { + "eui": "1020304081716151" + } +}] \ No newline at end of file diff --git a/VENDORS/Elsys/ERS2_Lite/LORIOT/uplink/converter.json b/VENDORS/Elsys/ERS2_Lite/LORIOT/uplink/converter.json index 5f810faa..3907eece 100644 --- a/VENDORS/Elsys/ERS2_Lite/LORIOT/uplink/converter.json +++ b/VENDORS/Elsys/ERS2_Lite/LORIOT/uplink/converter.json @@ -1,11 +1,16 @@ { "name": "Loriot Uplink Decoder for Elsys ERS2 Lite Device", "type": "UPLINK", - "debugMode": true, + "debugMode": false, + "debugSettings": { + "failuresEnabled": true, + "allEnabled": false, + "allEnabledUntil": 1735046911061 + }, "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);\nvar deviceName = \"ERS2 Lite \" + data.EUI;\nvar deviceType = \"ERS2 Lite\";\nvar groupName = null; // If groupName is not null - created device will be added to the entity group with such name.\nvar customerName = null; // If customerName is not null - created devices will be assigned to customer with such name. \n\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// If you want to parse incoming data somehow, you can add your code to this function.\n// input: bytes\n// expected output:\n// {\n// \"attributes\": {\"attributeKey\": \"attributeValue\"},\n// \"telemetry\": {\"telemetryKey\": \"telemetryValue\"}\n// }\n\nfunction decodePayload(input) {\n var output = { attributes: {}, telemetry: []};\n \n // --- Decoding code --- //\n var decoded = {};\n for (var i = 0; i < input.length;) {\n var type = input[i++] & 0xff;\n \n if (type == 0x01) { \n // Temperature Converts to °C\n decoded.temperature = parseBytesToInt(input, i, 2, true) / 10;\n i += 2;\n } else if (type == 0x02) { // Humidity\n decoded.humidity = input[i];\n i += 1;\n } else if (type == 0x07) { // Battery Voltage (VDD)\n decoded.vdd = parseBytesToInt(input, i, 2, true); \n i += 2;\n }\n }\n \n output.telemetry = [{\n ts: timestamp,\n values: decoded\n }];\n\n // --- Decoding code --- //\n return output;\n}\n\n// --- attributes and telemetry objects ---\nvar telemetry = [];\nvar attributes = {};\n// --- attributes and telemetry objects ---\n\n// --- Timestamp parsing\ntimestamp = data.ts;\n// --- Timestamp parsing\n\n// Message parsing\n// To avoid paths in the decoded objects we passing false value to function as \"pathInKey\" argument.\n// Warning: pathInKey can cause already found fields to be overwritten with the last value found.\n\nvar uplinkDataList = [];\n\n// Passing incoming bytes to decodePayload function, to get custom decoding\nvar customDecoding = decodePayload(hexToBytes(data.data));\n\n// Collecting data to result\nif (customDecoding.?telemetry.size() > 0) {\n if (customDecoding.telemetry instanceof java.util.ArrayList) {\n foreach(telemetryObj: customDecoding.telemetry) {\n if (telemetryObj.ts != null && telemetryObj.values != null) {\n telemetry.add(telemetryObj);\n }\n }\n } else {\n telemetry.putAll(customDecoding.telemetry);\n }\n}\n\nif (customDecoding.?attributes.size() > 0) {\n attributes.putAll(customDecoding.attributes);\n}\n\n// You can add some keys manually to attributes or telemetry\nattributes.eui = data.EUI;\nattributes.fPort = data.port;\nattributes.frequency = data.freq;\n\nvar addDataToTelemetry = {};\naddDataToTelemetry.rssi = data.rssi;\naddDataToTelemetry.seqno = data.seqno;\naddDataToTelemetry.snr = data.snr;\naddDataToTelemetry.ack = data.ack;\naddDataToTelemetry.toa = data.toa;\naddDataToTelemetry.fCnt = data.fcnt;\n\nvar isIncludeGatewayInfo = metadata[\"includeGatewayInfo\"];\nif(isIncludeGatewayInfo == true) {\n telemetry = processTelemetryData(telemetry, addDataToTelemetry);\n}\n\nvar deviceInfo = {\n deviceName: deviceName,\n deviceType: deviceType,\n// assetName: assetName,\n// assetType: assetType,\n attributes: attributes,\n telemetry: telemetry, \n};\n\naddAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName);\n\nuplinkDataList.add(deviceInfo);\n\nvar includeGatewayInfo = [\"ts\", \"gweui\", \"rssi\"];\n\nvar gatewayDeviceNamePrefix = \"Gateway \";\nvar gatewayDeviceType = \"Lora gateway\";\nvar gatewayGroupName = null; // If gatewayGroupName is not null - created device will be added to the entity group with such name.\n\nif (data.cmd == \"gw\") {\n foreach( gatewayInfo : data.gws ) {\n var gatewayInfoMsg = {\n deviceName: gatewayDeviceNamePrefix + gatewayInfo.gweui,\n deviceType: gatewayDeviceType,\n telemetry: [{\n \"ts\": parseDateToTimestamp(gatewayInfo.ts),\n \"values\": getDataList(gatewayInfo, includeGatewayInfo)\n }],\n attributes: {\n eui: gatewayInfo.gweui\n }\n };\n addAdditionalInfoForDeviceMsg(gatewayInfoMsg, customerName, gatewayGroupName);\n uplinkDataList.add(gatewayInfoMsg);\n }\n}\n\nreturn uplinkDataList;\n\nfunction addAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName) {\n if (customerName != null) {\n deviceInfo.customerName = customerName;\n }\n if (groupName != null) {\n deviceInfo.groupName = groupName;\n }\n}\n\nfunction parseDateToTimestamp(dateString) {\n var timestamp = -1;\n if (dateString != null) {\n \n timestamp = new Date(dateString).getTime();\n if (timestamp == -1) {\n var secondsSeparatorIndex = dateString.lastIndexOf('.') + 1;\n var millisecondsEndIndex = dateString.lastIndexOf('+');\n if (millisecondsEndIndex == -1) {\n millisecondsEndIndex = dateString.lastIndexOf('Z');\n }\n if (millisecondsEndIndex == -1) {\n millisecondsEndIndex = dateString.lastIndexOf('-');\n }\n if (millisecondsEndIndex == -1) {\n if (dateString.length >= secondsSeparatorIndex + 3) {\n dateString = dateString.substring(0, secondsSeparatorIndex + 3);\n }\n } else {\n dateString = dateString.substring(0, secondsSeparatorIndex + 3) +\n dateString.substring(millisecondsEndIndex, dateString.length);\n }\n \n timestamp = new Date(dateString).getTime();\n }\n }\n // If we cannot parse timestamp - we will use the current timestamp\n if (timestamp == -1) {\n timestamp = Date.now();\n }\n \n return timestamp;\n}\n\nfunction processTelemetryData(telemetry, addDataToTelemetry) {\n if (telemetry.size > 1) {\n telemetry = addDataToMultipleTelemetries(telemetry, addDataToTelemetry);\n }\n else if (telemetry.size == 1) {\n telemetry = addDataToSingleTelemetry(telemetry, addDataToTelemetry);\n }\n else {\n telemetry.add(addDataToTelemetry);\n }\n \n return telemetry;\n}\n\nfunction addDataToMultipleTelemetries(telemetry, addDataToTelemetry) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[0][\"values\"].keys.contains(element.key)) {\n telemetry[0][\"values\"][element.key] = element.value;\n }\n if (!telemetry[1][\"values\"].keys.contains(element.key)) {\n telemetry[1][\"values\"][element.key] = element.value;\n }\n }\n \n return telemetry;\n}\n\nfunction addDataToSingleTelemetry(telemetry, addDataToTelemetry) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[0][\"values\"].keys.contains(element.key)) {\n telemetry[0][\"values\"][element.key] = element.value;\n }\n }\n \n return telemetry;\n}", + "tbelDecoder": "var data = decodeToJson(payload);\nvar deviceName = \"ERS2 Lite \" + data.EUI;\nvar deviceType = \"ERS2 Lite\";\nvar groupName = null; // If groupName is not null - created device will be added to the entity group with such name.\nvar customerName = null; // If customerName is not null - created devices will be assigned to customer with such name. \n\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// If you want to parse incoming data somehow, you can add your code to this function.\n// input: bytes\n// expected output:\n// {\n// \"attributes\": {\"attributeKey\": \"attributeValue\"},\n// \"telemetry\": {\"telemetryKey\": \"telemetryValue\"}\n// }\n\nfunction decodePayload(input) {\n var output = { attributes: {}, telemetry: []};\n \n // --- Decoding code --- //\n var decoded = {};\n for (var i = 0; i < input.length;) {\n var type = input[i++] & 0xff;\n \n if (type == 0x01) { \n // Temperature Converts to °C\n decoded.temperature = parseBytesToInt(input, i, 2, true) / 10;\n i += 2;\n } else if (type == 0x02) { // Humidity\n decoded.humidity = input[i];\n i += 1;\n } else if (type == 0x07) { // Battery Voltage (VDD)\n decoded.vdd = parseBytesToInt(input, i, 2, true); \n i += 2;\n }\n }\n \n output.telemetry = [{\n ts: timestamp,\n values: decoded\n }];\n\n // --- Decoding code --- //\n return output;\n}\n\n// --- attributes and telemetry objects ---\nvar telemetry = [];\nvar attributes = {};\n// --- attributes and telemetry objects ---\n\n// --- Timestamp parsing\ntimestamp = data.ts;\n// --- Timestamp parsing\n\n// Message parsing\n// To avoid paths in the decoded objects we passing false value to function as \"pathInKey\" argument.\n// Warning: pathInKey can cause already found fields to be overwritten with the last value found.\n\nvar uplinkDataList = [];\n\n// Passing incoming bytes to decodePayload function, to get custom decoding\nvar customDecoding = decodePayload(hexToBytes(data.data));\n\n// Collecting data to result\nif (customDecoding.?telemetry.size() > 0) {\n if (customDecoding.telemetry instanceof java.util.ArrayList) {\n foreach(telemetryObj: customDecoding.telemetry) {\n if (telemetryObj.ts != null && telemetryObj.values != null) {\n telemetry.add(telemetryObj);\n }\n }\n } else {\n telemetry.putAll(customDecoding.telemetry);\n }\n}\n\nif (customDecoding.?attributes.size() > 0) {\n attributes.putAll(customDecoding.attributes);\n}\n\n// You can add some keys manually to attributes or telemetry\nattributes.eui = data.EUI;\nattributes.fPort = data.port;\nattributes.frequency = data.freq;\n\nvar addDataToTelemetry = {};\naddDataToTelemetry.rssi = data.rssi;\naddDataToTelemetry.seqno = data.seqno;\naddDataToTelemetry.snr = data.snr;\naddDataToTelemetry.ack = data.ack;\naddDataToTelemetry.toa = data.toa;\naddDataToTelemetry.fCnt = data.fcnt;\n\nvar isIncludeGatewayInfo = metadata[\"includeGatewayInfo\"];\nif(isIncludeGatewayInfo == true) {\n telemetry = processTelemetryData(telemetry, addDataToTelemetry);\n}\n\nvar deviceInfo = {\n deviceName: deviceName,\n deviceType: deviceType,\n// assetName: assetName,\n// assetType: assetType,\n attributes: attributes,\n telemetry: telemetry, \n};\n\naddAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName);\n\nuplinkDataList.add(deviceInfo);\n\nvar gatewayDeviceNamePrefix = \"Gateway \";\nvar gatewayDeviceType = \"Lora gateway\";\nvar gatewayGroupName = null; // If gatewayGroupName is not null - created device will be added to the entity group with such name.\n\nif (data.cmd == \"gw\") {\n foreach( gatewayInfo : data.gws ) {\n var addGatewayInfo = {};\n\n // You can add some keys manually telemetry\n addGatewayInfo.rssi = gatewayInfo.rssi;\n addGatewayInfo.snr = gatewayInfo.snr;\n // You can add some keys manually telemetry\n \n var gatewayInfoMsg = {\n deviceName: gatewayDeviceNamePrefix + gatewayInfo.gweui,\n deviceType: gatewayDeviceType,\n telemetry: [{\n \"ts\": gatewayInfo.ts,\n \"values\": addGatewayInfo\n }],\n attributes: {\n eui: gatewayInfo.gweui\n }\n };\n addAdditionalInfoForDeviceMsg(gatewayInfoMsg, customerName, gatewayGroupName);\n uplinkDataList.add(gatewayInfoMsg);\n }\n}\n\nreturn uplinkDataList;\n\nfunction addAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName) {\n if (customerName != null) {\n deviceInfo.customerName = customerName;\n }\n if (groupName != null) {\n deviceInfo.groupName = groupName;\n }\n}\n\nfunction parseDateToTimestamp(dateString) {\n var timestamp = -1;\n if (dateString != null) {\n \n timestamp = new Date(dateString).getTime();\n if (timestamp == -1) {\n var secondsSeparatorIndex = dateString.lastIndexOf('.') + 1;\n var millisecondsEndIndex = dateString.lastIndexOf('+');\n if (millisecondsEndIndex == -1) {\n millisecondsEndIndex = dateString.lastIndexOf('Z');\n }\n if (millisecondsEndIndex == -1) {\n millisecondsEndIndex = dateString.lastIndexOf('-');\n }\n if (millisecondsEndIndex == -1) {\n if (dateString.length >= secondsSeparatorIndex + 3) {\n dateString = dateString.substring(0, secondsSeparatorIndex + 3);\n }\n } else {\n dateString = dateString.substring(0, secondsSeparatorIndex + 3) +\n dateString.substring(millisecondsEndIndex, dateString.length);\n }\n \n timestamp = new Date(dateString).getTime();\n }\n }\n // If we cannot parse timestamp - we will use the current timestamp\n if (timestamp == -1) {\n timestamp = Date.now();\n }\n \n return timestamp;\n}\n\nfunction processTelemetryData(telemetry, addDataToTelemetry) {\n if (telemetry.size > 1) {\n telemetry = addDataToMultipleTelemetries(telemetry, addDataToTelemetry);\n }\n else if (telemetry.size == 1) {\n telemetry = addDataToSingleTelemetry(telemetry, addDataToTelemetry);\n }\n else {\n telemetry.add(addDataToTelemetry);\n }\n \n return telemetry;\n}\n\nfunction addDataToMultipleTelemetries(telemetry, addDataToTelemetry) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[0][\"values\"].keys.contains(element.key)) {\n telemetry[0][\"values\"][element.key] = element.value;\n }\n if (!telemetry[1][\"values\"].keys.contains(element.key)) {\n telemetry[1][\"values\"][element.key] = element.value;\n }\n }\n \n return telemetry;\n}\n\nfunction addDataToSingleTelemetry(telemetry, addDataToTelemetry) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[0][\"values\"].keys.contains(element.key)) {\n telemetry[0][\"values\"][element.key] = element.value;\n }\n }\n \n return telemetry;\n}", "encoder": null, "tbelEncoder": null, "updateOnlyKeys": [ diff --git a/VENDORS/Elsys/ERS2_Lite/LORIOT/uplink/payload_1.json b/VENDORS/Elsys/ERS2_Lite/LORIOT/uplink/payload_1.json new file mode 100644 index 00000000..399b7aed --- /dev/null +++ b/VENDORS/Elsys/ERS2_Lite/LORIOT/uplink/payload_1.json @@ -0,0 +1,32 @@ +{ + "cmd": "gw", + "seqno": 4, + "EUI": "0102030405060708", + "ts": 1690901260493, + "fcnt": 3, + "port": 207, + "freq": 868300000, + "toa": 1319, + "dr": "SF12 BW125 4/5", + "ack": false, + "gws": [ + { + "rssi": -38, + "snr": 8.5, + "ts": 1690901260493, + "time": "2023-08-01T14:47:40.493Z", + "gweui": "1020304080706050", + "ant": 0 + }, + { + "rssi": -42, + "snr": 8.8, + "ts": 1690901260495, + "time": "2023-08-01T14:47:40.495Z", + "gweui": "1020304081716151", + "ant": 0 + } + ], + "bat": 143, + "data": "0100e20229070d62" +} \ No newline at end of file diff --git a/VENDORS/Elsys/ERS2_Lite/LORIOT/uplink/result_1.json b/VENDORS/Elsys/ERS2_Lite/LORIOT/uplink/result_1.json new file mode 100644 index 00000000..12f206e3 --- /dev/null +++ b/VENDORS/Elsys/ERS2_Lite/LORIOT/uplink/result_1.json @@ -0,0 +1,43 @@ +[{ + "deviceName": "ERS2 Lite 0102030405060708", + "deviceType": "ERS2 Lite", + "attributes": { + "eui": "0102030405060708", + "fPort": 207, + "frequency": 868300000 + }, + "telemetry": [{ + "ts": 1690901260493, + "values": { + "temperature": 22.6, + "humidity": 41, + "vdd": 3426 + } + }] +}, { + "deviceName": "Gateway 1020304080706050", + "deviceType": "Lora gateway", + "telemetry": [{ + "ts": 1690901260493, + "values": { + "rssi": -38, + "snr": 8.5 + } + }], + "attributes": { + "eui": "1020304080706050" + } +}, { + "deviceName": "Gateway 1020304081716151", + "deviceType": "Lora gateway", + "telemetry": [{ + "ts": 1690901260495, + "values": { + "rssi": -42, + "snr": 8.8 + } + }], + "attributes": { + "eui": "1020304081716151" + } +}] \ No newline at end of file diff --git a/VENDORS/Elsys/ERS2_Sound/LORIOT/uplink/payload_1.json b/VENDORS/Elsys/ERS2_Sound/LORIOT/uplink/payload_1.json new file mode 100644 index 00000000..f8ae5607 --- /dev/null +++ b/VENDORS/Elsys/ERS2_Sound/LORIOT/uplink/payload_1.json @@ -0,0 +1,32 @@ +{ + "cmd": "gw", + "seqno": 4, + "EUI": "0102030405060708", + "ts": 1690901260493, + "fcnt": 3, + "port": 207, + "freq": 868300000, + "toa": 1319, + "dr": "SF12 BW125 4/5", + "ack": false, + "gws": [ + { + "rssi": -38, + "snr": 8.5, + "ts": 1690901260493, + "time": "2023-08-01T14:47:40.493Z", + "gweui": "1020304080706050", + "ant": 0 + }, + { + "rssi": -42, + "snr": 8.8, + "ts": 1690901260495, + "time": "2023-08-01T14:47:40.495Z", + "gweui": "1020304081716151", + "ant": 0 + } + ], + "bat": 143, + "data": "0100e202290400270506070d62150710" +} \ No newline at end of file diff --git a/VENDORS/Elsys/ERS2_Sound/LORIOT/uplink/result_1.json b/VENDORS/Elsys/ERS2_Sound/LORIOT/uplink/result_1.json new file mode 100644 index 00000000..8d488ad7 --- /dev/null +++ b/VENDORS/Elsys/ERS2_Sound/LORIOT/uplink/result_1.json @@ -0,0 +1,47 @@ +[{ + "deviceName": "ERS2 Sound0102030405060708", + "deviceType": "ERS2 Sound", + "attributes": { + "eui": "0102030405060708", + "fPort": 207, + "frequency": 868300000 + }, + "telemetry": [{ + "ts": 1690901260493, + "values": { + "temperature": 22.6, + "humidity": 41, + "light": 39, + "pir": 6, + "vdd": 3426, + "soundPeak": 7, + "soundAvg": 16 + } + }] +}, { + "deviceName": "Gateway 1020304080706050", + "deviceType": "Lora gateway", + "telemetry": [{ + "ts": 1690901260493, + "values": { + "rssi": -38, + "snr": 8.5 + } + }], + "attributes": { + "eui": "1020304080706050" + } +}, { + "deviceName": "Gateway 1020304081716151", + "deviceType": "Lora gateway", + "telemetry": [{ + "ts": 1690901260495, + "values": { + "rssi": -42, + "snr": 8.8 + } + }], + "attributes": { + "eui": "1020304081716151" + } +}] \ No newline at end of file diff --git a/VENDORS/Elsys/ERS2_VOC/LORIOT/uplink/converter.json b/VENDORS/Elsys/ERS2_VOC/LORIOT/uplink/converter.json index 97a1a346..98c43a05 100644 --- a/VENDORS/Elsys/ERS2_VOC/LORIOT/uplink/converter.json +++ b/VENDORS/Elsys/ERS2_VOC/LORIOT/uplink/converter.json @@ -1,11 +1,16 @@ { "name": "Loriot Uplink Decoder for Elsys ERS2 VOC Device", "type": "UPLINK", - "debugMode": true, + "debugMode": false, + "debugSettings": { + "failuresEnabled": true, + "allEnabled": false, + "allEnabledUntil": 1735047102023 + }, "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);\nvar deviceName = \"ERS2 VOC \" + data.EUI;\nvar deviceType = \"ERS2 VOC\";\nvar groupName = null; // If groupName is not null - created device will be added to the entity group with such name.\nvar customerName = null; // If customerName is not null - created devices will be assigned to customer with such name. \n\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// If you want to parse incoming data somehow, you can add your code to this function.\n// input: bytes\n// expected output:\n// {\n// \"attributes\": {\"attributeKey\": \"attributeValue\"},\n// \"telemetry\": {\"telemetryKey\": \"telemetryValue\"}\n// }\n\nfunction decodePayload(input) {\n var output = { attributes: {}, telemetry: []};\n \n // --- Decoding code --- //\n var decoded = {};\n for (var i = 0; i < input.length;) {\n var type = input[i++] & 0xff;\n \n if (type == 0x01) { \n // Temperature Converts to °C\n decoded.temperature = parseBytesToInt(input, i, 2, true) / 10;\n i += 2;\n } else if (type == 0x02) { // Humidity\n decoded.humidity = input[i];\n i += 1;\n } else if (type == 0x04) { // Light\n decoded.light = parseBytesToInt(input, i, 2, true);\n i += 2;\n } else if (type == 0x05) { // Pir\n decoded.pir = input[i];\n i += 1;\n } else if (type == 0x07) { // Battery Voltage (VDD)\n decoded.vdd = parseBytesToInt(input, i, 2, true); \n i += 2;\n } else if (type == 0x1c) { // TVOC\n decoded.tvoc = parseBytesToInt(input, i, 2, true);\n i += 2;\n }\n }\n \n output.telemetry = [{\n ts: timestamp,\n values: decoded\n }];\n\n // --- Decoding code --- //\n return output;\n}\n\n// --- attributes and telemetry objects ---\nvar telemetry = [];\nvar attributes = {};\n// --- attributes and telemetry objects ---\n\n// --- Timestamp parsing\ntimestamp = data.ts;\n// --- Timestamp parsing\n\n// Message parsing\n// To avoid paths in the decoded objects we passing false value to function as \"pathInKey\" argument.\n// Warning: pathInKey can cause already found fields to be overwritten with the last value found.\n\nvar uplinkDataList = [];\n\n// Passing incoming bytes to decodePayload function, to get custom decoding\nvar customDecoding = decodePayload(hexToBytes(data.data));\n\n// Collecting data to result\nif (customDecoding.?telemetry.size() > 0) {\n if (customDecoding.telemetry instanceof java.util.ArrayList) {\n foreach(telemetryObj: customDecoding.telemetry) {\n if (telemetryObj.ts != null && telemetryObj.values != null) {\n telemetry.add(telemetryObj);\n }\n }\n } else {\n telemetry.putAll(customDecoding.telemetry);\n }\n}\n\nif (customDecoding.?attributes.size() > 0) {\n attributes.putAll(customDecoding.attributes);\n}\n\n// You can add some keys manually to attributes or telemetry\nattributes.eui = data.EUI;\nattributes.fPort = data.port;\nattributes.frequency = data.freq;\n\nvar isIncludeGatewayInfo = metadata[\"includeGatewayInfo\"];\nif(isIncludeGatewayInfo == true) {\n var addDataToTelemetry = {};\n addDataToTelemetry.rssi = data.rssi;\n addDataToTelemetry.seqno = data.seqno;\n addDataToTelemetry.snr = data.snr;\n addDataToTelemetry.ack = data.ack;\n addDataToTelemetry.toa = data.toa;\n addDataToTelemetry.fCnt = data.fcnt;\n \n telemetry = processTelemetryData(telemetry, addDataToTelemetry);\n}\n\nvar deviceInfo = {\n deviceName: deviceName,\n deviceType: deviceType,\n// assetName: assetName,\n// assetType: assetType,\n attributes: attributes,\n telemetry: telemetry, \n};\n\naddAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName);\n\nuplinkDataList.add(deviceInfo);\n\nvar includeGatewayInfo = [\"ts\", \"gweui\", \"rssi\"];\n\nvar gatewayDeviceNamePrefix = \"Gateway \";\nvar gatewayDeviceType = \"Lora gateway\";\nvar gatewayGroupName = null; // If gatewayGroupName is not null - created device will be added to the entity group with such name.\n\nif (data.cmd == \"gw\") {\n foreach( gatewayInfo : data.gws ) {\n var addGatewayInfo = {};\n\n // You can add some keys manually telemetry\n addGatewayInfo.rssi = gatewayInfo.rssi;\n addGatewayInfo.snr = gatewayInfo.snr;\n // You can add some keys manually telemetry\n \n var gatewayInfoMsg = {\n deviceName: gatewayDeviceNamePrefix + gatewayInfo.gweui,\n deviceType: gatewayDeviceType,\n telemetry: [{\n \"ts\": gatewayInfo.ts,\n \"values\": addGatewayInfo\n }],\n attributes: {\n eui: gatewayInfo.gweui\n }\n };\n addAdditionalInfoForDeviceMsg(gatewayInfoMsg, customerName, gatewayGroupName);\n uplinkDataList.add(gatewayInfoMsg);\n }\n}\n\nreturn uplinkDataList;\n\nfunction addAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName) {\n if (customerName != null) {\n deviceInfo.customerName = customerName;\n }\n if (groupName != null) {\n deviceInfo.groupName = groupName;\n }\n}\n\nfunction processTelemetryData(telemetry, addDataToTelemetry) {\n if (telemetry.size > 1) {\n telemetry = addDataToMultipleTelemetries(telemetry, addDataToTelemetry);\n }\n else if (telemetry.size == 1) {\n telemetry = addDataToSingleTelemetry(telemetry, addDataToTelemetry);\n }\n else {\n telemetry.add(addDataToTelemetry);\n }\n \n return telemetry;\n}\n\nfunction addDataToMultipleTelemetries(telemetry, addDataToTelemetry) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[0][\"values\"].keys.contains(element.key)) {\n telemetry[0][\"values\"][element.key] = element.value;\n }\n if (!telemetry[1][\"values\"].keys.contains(element.key)) {\n telemetry[1][\"values\"][element.key] = element.value;\n }\n }\n \n return telemetry;\n}\n\nfunction addDataToSingleTelemetry(telemetry, addDataToTelemetry) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[0][\"values\"].keys.contains(element.key)) {\n telemetry[0][\"values\"][element.key] = element.value;\n }\n }\n \n return telemetry;\n}", + "tbelDecoder": "var data = decodeToJson(payload);\nvar deviceName = \"ERS2 VOC \" + data.EUI;\nvar deviceType = \"ERS2 VOC\";\nvar groupName = null; // If groupName is not null - created device will be added to the entity group with such name.\nvar customerName = null; // If customerName is not null - created devices will be assigned to customer with such name. \n\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// If you want to parse incoming data somehow, you can add your code to this function.\n// input: bytes\n// expected output:\n// {\n// \"attributes\": {\"attributeKey\": \"attributeValue\"},\n// \"telemetry\": {\"telemetryKey\": \"telemetryValue\"}\n// }\n\nfunction decodePayload(input) {\n var output = { attributes: {}, telemetry: []};\n \n // --- Decoding code --- //\n var decoded = {};\n for (var i = 0; i < input.length;) {\n var type = input[i++] & 0xff;\n \n if (type == 0x01) { \n // Temperature Converts to °C\n decoded.temperature = parseBytesToInt(input, i, 2, true) / 10;\n i += 2;\n } else if (type == 0x02) { // Humidity\n decoded.humidity = input[i];\n i += 1;\n } else if (type == 0x04) { // Light\n decoded.light = parseBytesToInt(input, i, 2, true);\n i += 2;\n } else if (type == 0x05) { // Pir\n decoded.pir = input[i];\n i += 1;\n } else if (type == 0x07) { // Battery Voltage (VDD)\n decoded.vdd = parseBytesToInt(input, i, 2, true); \n i += 2;\n } else if (type == 0x1c) { // TVOC\n decoded.tvoc = parseBytesToInt(input, i, 2, true);\n i += 2;\n }\n }\n \n output.telemetry = [{\n ts: timestamp,\n values: decoded\n }];\n\n // --- Decoding code --- //\n return output;\n}\n\n// --- attributes and telemetry objects ---\nvar telemetry = [];\nvar attributes = {};\n// --- attributes and telemetry objects ---\n\n// --- Timestamp parsing\ntimestamp = data.ts;\n// --- Timestamp parsing\n\n// Message parsing\n// To avoid paths in the decoded objects we passing false value to function as \"pathInKey\" argument.\n// Warning: pathInKey can cause already found fields to be overwritten with the last value found.\n\nvar uplinkDataList = [];\n\n// Passing incoming bytes to decodePayload function, to get custom decoding\nvar customDecoding = decodePayload(hexToBytes(data.data));\n\n// Collecting data to result\nif (customDecoding.?telemetry.size() > 0) {\n if (customDecoding.telemetry instanceof java.util.ArrayList) {\n foreach(telemetryObj: customDecoding.telemetry) {\n if (telemetryObj.ts != null && telemetryObj.values != null) {\n telemetry.add(telemetryObj);\n }\n }\n } else {\n telemetry.putAll(customDecoding.telemetry);\n }\n}\n\nif (customDecoding.?attributes.size() > 0) {\n attributes.putAll(customDecoding.attributes);\n}\n\n// You can add some keys manually to attributes or telemetry\nattributes.eui = data.EUI;\nattributes.fPort = data.port;\nattributes.frequency = data.freq;\n\nvar isIncludeGatewayInfo = metadata[\"includeGatewayInfo\"];\nif(isIncludeGatewayInfo == true) {\n var addDataToTelemetry = {};\n addDataToTelemetry.rssi = data.rssi;\n addDataToTelemetry.seqno = data.seqno;\n addDataToTelemetry.snr = data.snr;\n addDataToTelemetry.ack = data.ack;\n addDataToTelemetry.toa = data.toa;\n addDataToTelemetry.fCnt = data.fcnt;\n \n telemetry = processTelemetryData(telemetry, addDataToTelemetry);\n}\n\nvar deviceInfo = {\n deviceName: deviceName,\n deviceType: deviceType,\n// assetName: assetName,\n// assetType: assetType,\n attributes: attributes,\n telemetry: telemetry, \n};\n\naddAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName);\n\nuplinkDataList.add(deviceInfo);\n\nvar gatewayDeviceNamePrefix = \"Gateway \";\nvar gatewayDeviceType = \"Lora gateway\";\nvar gatewayGroupName = null; // If gatewayGroupName is not null - created device will be added to the entity group with such name.\n\nif (data.cmd == \"gw\") {\n foreach( gatewayInfo : data.gws ) {\n var addGatewayInfo = {};\n\n // You can add some keys manually telemetry\n addGatewayInfo.rssi = gatewayInfo.rssi;\n addGatewayInfo.snr = gatewayInfo.snr;\n // You can add some keys manually telemetry\n \n var gatewayInfoMsg = {\n deviceName: gatewayDeviceNamePrefix + gatewayInfo.gweui,\n deviceType: gatewayDeviceType,\n telemetry: [{\n \"ts\": gatewayInfo.ts,\n \"values\": addGatewayInfo\n }],\n attributes: {\n eui: gatewayInfo.gweui\n }\n };\n addAdditionalInfoForDeviceMsg(gatewayInfoMsg, customerName, gatewayGroupName);\n uplinkDataList.add(gatewayInfoMsg);\n }\n}\n\nreturn uplinkDataList;\n\nfunction addAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName) {\n if (customerName != null) {\n deviceInfo.customerName = customerName;\n }\n if (groupName != null) {\n deviceInfo.groupName = groupName;\n }\n}\n\nfunction processTelemetryData(telemetry, addDataToTelemetry) {\n if (telemetry.size > 1) {\n telemetry = addDataToMultipleTelemetries(telemetry, addDataToTelemetry);\n }\n else if (telemetry.size == 1) {\n telemetry = addDataToSingleTelemetry(telemetry, addDataToTelemetry);\n }\n else {\n telemetry.add(addDataToTelemetry);\n }\n \n return telemetry;\n}\n\nfunction addDataToMultipleTelemetries(telemetry, addDataToTelemetry) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[0][\"values\"].keys.contains(element.key)) {\n telemetry[0][\"values\"][element.key] = element.value;\n }\n if (!telemetry[1][\"values\"].keys.contains(element.key)) {\n telemetry[1][\"values\"][element.key] = element.value;\n }\n }\n \n return telemetry;\n}\n\nfunction addDataToSingleTelemetry(telemetry, addDataToTelemetry) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[0][\"values\"].keys.contains(element.key)) {\n telemetry[0][\"values\"][element.key] = element.value;\n }\n }\n \n return telemetry;\n}", "encoder": null, "tbelEncoder": null, "updateOnlyKeys": [ diff --git a/VENDORS/Elsys/ERS2_VOC/LORIOT/uplink/payload_1.json b/VENDORS/Elsys/ERS2_VOC/LORIOT/uplink/payload_1.json new file mode 100644 index 00000000..350156c4 --- /dev/null +++ b/VENDORS/Elsys/ERS2_VOC/LORIOT/uplink/payload_1.json @@ -0,0 +1,32 @@ +{ + "cmd": "gw", + "seqno": 4, + "EUI": "0102030405060708", + "ts": 1690901260493, + "fcnt": 3, + "port": 207, + "freq": 868300000, + "toa": 1319, + "dr": "SF12 BW125 4/5", + "ack": false, + "gws": [ + { + "rssi": -38, + "snr": 8.5, + "ts": 1690901260493, + "time": "2023-08-01T14:47:40.493Z", + "gweui": "1020304080706050", + "ant": 0 + }, + { + "rssi": -42, + "snr": 8.8, + "ts": 1690901260495, + "time": "2023-08-01T14:47:40.495Z", + "gweui": "1020304081716151", + "ant": 0 + } + ], + "bat": 143, + "data": "0100e202290400270506070d621c0d62" +} \ No newline at end of file diff --git a/VENDORS/Elsys/ERS2_VOC/LORIOT/uplink/result_1.json b/VENDORS/Elsys/ERS2_VOC/LORIOT/uplink/result_1.json new file mode 100644 index 00000000..a9fc9d8a --- /dev/null +++ b/VENDORS/Elsys/ERS2_VOC/LORIOT/uplink/result_1.json @@ -0,0 +1,46 @@ +[{ + "deviceName": "ERS2 VOC 0102030405060708", + "deviceType": "ERS2 VOC", + "attributes": { + "eui": "0102030405060708", + "fPort": 207, + "frequency": 868300000 + }, + "telemetry": [{ + "ts": 1690901260493, + "values": { + "temperature": 22.6, + "humidity": 41, + "light": 39, + "pir": 6, + "vdd": 3426, + "tvoc": 3426 + } + }] +}, { + "deviceName": "Gateway 1020304080706050", + "deviceType": "Lora gateway", + "telemetry": [{ + "ts": 1690901260493, + "values": { + "rssi": -38, + "snr": 8.5 + } + }], + "attributes": { + "eui": "1020304080706050" + } +}, { + "deviceName": "Gateway 1020304081716151", + "deviceType": "Lora gateway", + "telemetry": [{ + "ts": 1690901260495, + "values": { + "rssi": -42, + "snr": 8.8 + } + }], + "attributes": { + "eui": "1020304081716151" + } +}] \ No newline at end of file From eaefa9ed281e605d5852f852a4760f95da038a38 Mon Sep 17 00:00:00 2001 From: Artem Barysh Date: Tue, 24 Dec 2024 16:13:55 +0200 Subject: [PATCH 24/33] Added an additional test cases for loriot integration(Netvox devices) --- .../Netvox/R311A/LORIOT/uplink/payload_3.json | 32 ++++++++++++++ .../Netvox/R311A/LORIOT/uplink/result_3.json | 42 ++++++++++++++++++ .../Netvox/R716S/LORIOT/uplink/payload_3.json | 32 ++++++++++++++ .../Netvox/R716S/LORIOT/uplink/result_3.json | 42 ++++++++++++++++++ .../Netvox/R718A/LORIOT/uplink/payload_2.json | 32 ++++++++++++++ .../Netvox/R718A/LORIOT/uplink/result_2.json | 43 +++++++++++++++++++ .../R718AB/LORIOT/uplink/payload_3.json | 32 ++++++++++++++ .../Netvox/R718AB/LORIOT/uplink/result_3.json | 43 +++++++++++++++++++ .../R718DA/LORIOT/uplink/payload_2.json | 32 ++++++++++++++ .../Netvox/R718DA/LORIOT/uplink/result_2.json | 42 ++++++++++++++++++ .../R718DA2/LORIOT/uplink/payload_2.json | 32 ++++++++++++++ .../R718DA2/LORIOT/uplink/result_2.json | 43 +++++++++++++++++++ .../Netvox/R718H/LORIOT/uplink/payload_3.json | 32 ++++++++++++++ .../Netvox/R718H/LORIOT/uplink/result_3.json | 42 ++++++++++++++++++ .../R718KA/LORIOT/uplink/payload_2.json | 32 ++++++++++++++ .../Netvox/R718KA/LORIOT/uplink/result_2.json | 43 +++++++++++++++++++ .../R718WB/LORIOT/uplink/payload_2.json | 32 ++++++++++++++ .../Netvox/R718WB/LORIOT/uplink/result_2.json | 42 ++++++++++++++++++ .../Netvox/R719A/LORIOT/uplink/payload_2.json | 32 ++++++++++++++ .../Netvox/R719A/LORIOT/uplink/result_2.json | 42 ++++++++++++++++++ .../R72624/LORIOT/uplink/payload_2.json | 32 ++++++++++++++ .../Netvox/R72624/LORIOT/uplink/result_2.json | 42 ++++++++++++++++++ .../RA0715/LORIOT/uplink/payload_2.json | 32 ++++++++++++++ .../Netvox/RA0715/LORIOT/uplink/result_2.json | 42 ++++++++++++++++++ .../RA0723/LORIOT/uplink/payload_3.json | 32 ++++++++++++++ .../Netvox/RA0723/LORIOT/uplink/result_3.json | 42 ++++++++++++++++++ 26 files changed, 966 insertions(+) create mode 100644 VENDORS/Netvox/R311A/LORIOT/uplink/payload_3.json create mode 100644 VENDORS/Netvox/R311A/LORIOT/uplink/result_3.json create mode 100644 VENDORS/Netvox/R716S/LORIOT/uplink/payload_3.json create mode 100644 VENDORS/Netvox/R716S/LORIOT/uplink/result_3.json create mode 100644 VENDORS/Netvox/R718A/LORIOT/uplink/payload_2.json create mode 100644 VENDORS/Netvox/R718A/LORIOT/uplink/result_2.json create mode 100644 VENDORS/Netvox/R718AB/LORIOT/uplink/payload_3.json create mode 100644 VENDORS/Netvox/R718AB/LORIOT/uplink/result_3.json create mode 100644 VENDORS/Netvox/R718DA/LORIOT/uplink/payload_2.json create mode 100644 VENDORS/Netvox/R718DA/LORIOT/uplink/result_2.json create mode 100644 VENDORS/Netvox/R718DA2/LORIOT/uplink/payload_2.json create mode 100644 VENDORS/Netvox/R718DA2/LORIOT/uplink/result_2.json create mode 100644 VENDORS/Netvox/R718H/LORIOT/uplink/payload_3.json create mode 100644 VENDORS/Netvox/R718H/LORIOT/uplink/result_3.json create mode 100644 VENDORS/Netvox/R718KA/LORIOT/uplink/payload_2.json create mode 100644 VENDORS/Netvox/R718KA/LORIOT/uplink/result_2.json create mode 100644 VENDORS/Netvox/R718WB/LORIOT/uplink/payload_2.json create mode 100644 VENDORS/Netvox/R718WB/LORIOT/uplink/result_2.json create mode 100644 VENDORS/Netvox/R719A/LORIOT/uplink/payload_2.json create mode 100644 VENDORS/Netvox/R719A/LORIOT/uplink/result_2.json create mode 100644 VENDORS/Netvox/R72624/LORIOT/uplink/payload_2.json create mode 100644 VENDORS/Netvox/R72624/LORIOT/uplink/result_2.json create mode 100644 VENDORS/Netvox/RA0715/LORIOT/uplink/payload_2.json create mode 100644 VENDORS/Netvox/RA0715/LORIOT/uplink/result_2.json create mode 100644 VENDORS/Netvox/RA0723/LORIOT/uplink/payload_3.json create mode 100644 VENDORS/Netvox/RA0723/LORIOT/uplink/result_3.json diff --git a/VENDORS/Netvox/R311A/LORIOT/uplink/payload_3.json b/VENDORS/Netvox/R311A/LORIOT/uplink/payload_3.json new file mode 100644 index 00000000..49a8a8da --- /dev/null +++ b/VENDORS/Netvox/R311A/LORIOT/uplink/payload_3.json @@ -0,0 +1,32 @@ +{ + "cmd": "gw", + "seqno": 4, + "EUI": "0102030405060708", + "ts": 1690901260493, + "fcnt": 3, + "port": 6, + "freq": 868300000, + "toa": 1319, + "dr": "SF12 BW125 4/5", + "ack": false, + "gws": [ + { + "rssi": -38, + "snr": 8.5, + "ts": 1690901260493, + "time": "2023-08-01T14:47:40.493Z", + "gweui": "1020304080706050", + "ant": 0 + }, + { + "rssi": -42, + "snr": 8.8, + "ts": 1690901260495, + "time": "2023-08-01T14:47:40.495Z", + "gweui": "1020304081716151", + "ant": 0 + } + ], + "bat": 143, + "data": "0102011c01000000000000" +} diff --git a/VENDORS/Netvox/R311A/LORIOT/uplink/result_3.json b/VENDORS/Netvox/R311A/LORIOT/uplink/result_3.json new file mode 100644 index 00000000..9c07d6b9 --- /dev/null +++ b/VENDORS/Netvox/R311A/LORIOT/uplink/result_3.json @@ -0,0 +1,42 @@ +[{ + "deviceName": "0102030405060708", + "deviceType": "R311A", + "attributes": { + "eui": "0102030405060708", + "fPort": 6, + "frequency": 868300000 + }, + "telemetry": [{ + "ts": 1690901260493, + "values": { + "battery_voltage": 2.8, + "contact_switch": "on" + } + }] +}, { + "deviceName": "Gateway 1020304080706050", + "deviceType": "Lora gateway", + "telemetry": [{ + "ts": 1690901260493, + "values": { + "rssi": -38, + "snr": 8.5 + } + }], + "attributes": { + "eui": "1020304080706050" + } +}, { + "deviceName": "Gateway 1020304081716151", + "deviceType": "Lora gateway", + "telemetry": [{ + "ts": 1690901260495, + "values": { + "rssi": -42, + "snr": 8.8 + } + }], + "attributes": { + "eui": "1020304081716151" + } +}] \ No newline at end of file diff --git a/VENDORS/Netvox/R716S/LORIOT/uplink/payload_3.json b/VENDORS/Netvox/R716S/LORIOT/uplink/payload_3.json new file mode 100644 index 00000000..49347517 --- /dev/null +++ b/VENDORS/Netvox/R716S/LORIOT/uplink/payload_3.json @@ -0,0 +1,32 @@ +{ + "cmd": "gw", + "seqno": 4, + "EUI": "0102030405060708", + "ts": 1690901260493, + "fcnt": 3, + "port": 20, + "freq": 868300000, + "toa": 1319, + "dr": "SF12 BW125 4/5", + "ack": false, + "gws": [ + { + "rssi": -38, + "snr": 8.5, + "ts": 1690901260493, + "time": "2023-08-01T14:47:40.493Z", + "gweui": "1020304080706050", + "ant": 0 + }, + { + "rssi": -42, + "snr": 8.8, + "ts": 1690901260495, + "time": "2023-08-01T14:47:40.495Z", + "gweui": "1020304081716151", + "ant": 0 + } + ], + "bat": 143, + "data": "810100000000" +} diff --git a/VENDORS/Netvox/R716S/LORIOT/uplink/result_3.json b/VENDORS/Netvox/R716S/LORIOT/uplink/result_3.json new file mode 100644 index 00000000..9cee9f8e --- /dev/null +++ b/VENDORS/Netvox/R716S/LORIOT/uplink/result_3.json @@ -0,0 +1,42 @@ +[{ + "deviceName": "0102030405060708", + "deviceType": "R716S", + "attributes": { + "eui": "0102030405060708", + "fPort": 20, + "frequency": 868300000 + }, + "telemetry": [{ + "ts": 1690901260493, + "values": { + "cmd": "setNetvoxLoRaWANRejoinRsp", + "status": "failure" + } + }] +}, { + "deviceName": "Gateway 1020304080706050", + "deviceType": "Lora gateway", + "telemetry": [{ + "ts": 1690901260493, + "values": { + "rssi": -38, + "snr": 8.5 + } + }], + "attributes": { + "eui": "1020304080706050" + } +}, { + "deviceName": "Gateway 1020304081716151", + "deviceType": "Lora gateway", + "telemetry": [{ + "ts": 1690901260495, + "values": { + "rssi": -42, + "snr": 8.8 + } + }], + "attributes": { + "eui": "1020304081716151" + } +}] \ No newline at end of file diff --git a/VENDORS/Netvox/R718A/LORIOT/uplink/payload_2.json b/VENDORS/Netvox/R718A/LORIOT/uplink/payload_2.json new file mode 100644 index 00000000..ff21fdb5 --- /dev/null +++ b/VENDORS/Netvox/R718A/LORIOT/uplink/payload_2.json @@ -0,0 +1,32 @@ +{ + "cmd": "gw", + "seqno": 4, + "EUI": "0102030405060708", + "ts": 1690901260493, + "fcnt": 3, + "port": 6, + "freq": 868300000, + "toa": 1319, + "dr": "SF12 BW125 4/5", + "ack": false, + "gws": [ + { + "rssi": -38, + "snr": 8.5, + "ts": 1690901260493, + "time": "2023-08-01T14:47:40.493Z", + "gweui": "1020304080706050", + "ant": 0 + }, + { + "rssi": -42, + "snr": 8.8, + "ts": 1690901260495, + "time": "2023-08-01T14:47:40.495Z", + "gweui": "1020304081716151", + "ant": 0 + } + ], + "bat": 143, + "data": "010B012406701A9E000000" +} diff --git a/VENDORS/Netvox/R718A/LORIOT/uplink/result_2.json b/VENDORS/Netvox/R718A/LORIOT/uplink/result_2.json new file mode 100644 index 00000000..52293a9f --- /dev/null +++ b/VENDORS/Netvox/R718A/LORIOT/uplink/result_2.json @@ -0,0 +1,43 @@ +[{ + "deviceName": "0102030405060708", + "deviceType": "R718A", + "attributes": { + "eui": "0102030405060708", + "fPort": 6, + "frequency": 868300000 + }, + "telemetry": [{ + "ts": 1690901260493, + "values": { + "battery_voltage": 3.6, + "temperature": 16.48, + "humidity": 68.14 + } + }] +}, { + "deviceName": "Gateway 1020304080706050", + "deviceType": "Lora gateway", + "telemetry": [{ + "ts": 1690901260493, + "values": { + "rssi": -38, + "snr": 8.5 + } + }], + "attributes": { + "eui": "1020304080706050" + } +}, { + "deviceName": "Gateway 1020304081716151", + "deviceType": "Lora gateway", + "telemetry": [{ + "ts": 1690901260495, + "values": { + "rssi": -42, + "snr": 8.8 + } + }], + "attributes": { + "eui": "1020304081716151" + } +}] \ No newline at end of file diff --git a/VENDORS/Netvox/R718AB/LORIOT/uplink/payload_3.json b/VENDORS/Netvox/R718AB/LORIOT/uplink/payload_3.json new file mode 100644 index 00000000..b2dfdd8e --- /dev/null +++ b/VENDORS/Netvox/R718AB/LORIOT/uplink/payload_3.json @@ -0,0 +1,32 @@ +{ + "cmd": "gw", + "seqno": 4, + "EUI": "0102030405060708", + "ts": 1690901260493, + "fcnt": 3, + "port": 6, + "freq": 868300000, + "toa": 1319, + "dr": "SF12 BW125 4/5", + "ack": false, + "gws": [ + { + "rssi": -38, + "snr": 8.5, + "ts": 1690901260493, + "time": "2023-08-01T14:47:40.493Z", + "gweui": "1020304080706050", + "ant": 0 + }, + { + "rssi": -42, + "snr": 8.8, + "ts": 1690901260495, + "time": "2023-08-01T14:47:40.495Z", + "gweui": "1020304081716151", + "ant": 0 + } + ], + "bat": 143, + "data": "0113012406701a9e000000" +} diff --git a/VENDORS/Netvox/R718AB/LORIOT/uplink/result_3.json b/VENDORS/Netvox/R718AB/LORIOT/uplink/result_3.json new file mode 100644 index 00000000..4762d020 --- /dev/null +++ b/VENDORS/Netvox/R718AB/LORIOT/uplink/result_3.json @@ -0,0 +1,43 @@ +[{ + "deviceName": "0102030405060708", + "deviceType": "R718AB", + "attributes": { + "eui": "0102030405060708", + "fPort": 6, + "frequency": 868300000 + }, + "telemetry": [{ + "ts": 1690901260493, + "values": { + "battery_voltage": 3.6, + "temperature": 16.48, + "humidity": 68.14 + } + }] +}, { + "deviceName": "Gateway 1020304080706050", + "deviceType": "Lora gateway", + "telemetry": [{ + "ts": 1690901260493, + "values": { + "rssi": -38, + "snr": 8.5 + } + }], + "attributes": { + "eui": "1020304080706050" + } +}, { + "deviceName": "Gateway 1020304081716151", + "deviceType": "Lora gateway", + "telemetry": [{ + "ts": 1690901260495, + "values": { + "rssi": -42, + "snr": 8.8 + } + }], + "attributes": { + "eui": "1020304081716151" + } +}] \ No newline at end of file diff --git a/VENDORS/Netvox/R718DA/LORIOT/uplink/payload_2.json b/VENDORS/Netvox/R718DA/LORIOT/uplink/payload_2.json new file mode 100644 index 00000000..dc1d155f --- /dev/null +++ b/VENDORS/Netvox/R718DA/LORIOT/uplink/payload_2.json @@ -0,0 +1,32 @@ +{ + "cmd": "gw", + "seqno": 4, + "EUI": "0102030405060708", + "ts": 1690901260493, + "fcnt": 3, + "port": 6, + "freq": 868300000, + "toa": 1319, + "dr": "SF12 BW125 4/5", + "ack": false, + "gws": [ + { + "rssi": -38, + "snr": 8.5, + "ts": 1690901260493, + "time": "2023-08-01T14:47:40.493Z", + "gweui": "1020304080706050", + "ant": 0 + }, + { + "rssi": -42, + "snr": 8.8, + "ts": 1690901260495, + "time": "2023-08-01T14:47:40.495Z", + "gweui": "1020304081716151", + "ant": 0 + } + ], + "bat": 143, + "data": "011A012401000000000000" +} diff --git a/VENDORS/Netvox/R718DA/LORIOT/uplink/result_2.json b/VENDORS/Netvox/R718DA/LORIOT/uplink/result_2.json new file mode 100644 index 00000000..d6d276c7 --- /dev/null +++ b/VENDORS/Netvox/R718DA/LORIOT/uplink/result_2.json @@ -0,0 +1,42 @@ +[{ + "deviceName": "0102030405060708", + "deviceType": "R718DA", + "attributes": { + "eui": "0102030405060708", + "fPort": 6, + "frequency": 868300000 + }, + "telemetry": [{ + "ts": 1690901260493, + "values": { + "battery_voltage": 3.6, + "ball_status": "on" + } + }] +}, { + "deviceName": "Gateway 1020304080706050", + "deviceType": "Lora gateway", + "telemetry": [{ + "ts": 1690901260493, + "values": { + "rssi": -38, + "snr": 8.5 + } + }], + "attributes": { + "eui": "1020304080706050" + } +}, { + "deviceName": "Gateway 1020304081716151", + "deviceType": "Lora gateway", + "telemetry": [{ + "ts": 1690901260495, + "values": { + "rssi": -42, + "snr": 8.8 + } + }], + "attributes": { + "eui": "1020304081716151" + } +}] \ No newline at end of file diff --git a/VENDORS/Netvox/R718DA2/LORIOT/uplink/payload_2.json b/VENDORS/Netvox/R718DA2/LORIOT/uplink/payload_2.json new file mode 100644 index 00000000..344f17ae --- /dev/null +++ b/VENDORS/Netvox/R718DA2/LORIOT/uplink/payload_2.json @@ -0,0 +1,32 @@ +{ + "cmd": "gw", + "seqno": 4, + "EUI": "0102030405060708", + "ts": 1690901260493, + "fcnt": 3, + "port": 6, + "freq": 868300000, + "toa": 1319, + "dr": "SF12 BW125 4/5", + "ack": false, + "gws": [ + { + "rssi": -38, + "snr": 8.5, + "ts": 1690901260493, + "time": "2023-08-01T14:47:40.493Z", + "gweui": "1020304080706050", + "ant": 0 + }, + { + "rssi": -42, + "snr": 8.8, + "ts": 1690901260495, + "time": "2023-08-01T14:47:40.495Z", + "gweui": "1020304081716151", + "ant": 0 + } + ], + "bat": 143, + "data": "012F012401000000000000" +} diff --git a/VENDORS/Netvox/R718DA2/LORIOT/uplink/result_2.json b/VENDORS/Netvox/R718DA2/LORIOT/uplink/result_2.json new file mode 100644 index 00000000..3010e363 --- /dev/null +++ b/VENDORS/Netvox/R718DA2/LORIOT/uplink/result_2.json @@ -0,0 +1,43 @@ +[{ + "deviceName": "0102030405060708", + "deviceType": "R718DA2", + "attributes": { + "eui": "0102030405060708", + "fPort": 6, + "frequency": 868300000 + }, + "telemetry": [{ + "ts": 1690901260493, + "values": { + "battery_voltage": 3.6, + "ball_status_1": "on", + "ball_status_2": "off" + } + }] +}, { + "deviceName": "Gateway 1020304080706050", + "deviceType": "Lora gateway", + "telemetry": [{ + "ts": 1690901260493, + "values": { + "rssi": -38, + "snr": 8.5 + } + }], + "attributes": { + "eui": "1020304080706050" + } +}, { + "deviceName": "Gateway 1020304081716151", + "deviceType": "Lora gateway", + "telemetry": [{ + "ts": 1690901260495, + "values": { + "rssi": -42, + "snr": 8.8 + } + }], + "attributes": { + "eui": "1020304081716151" + } +}] \ No newline at end of file diff --git a/VENDORS/Netvox/R718H/LORIOT/uplink/payload_3.json b/VENDORS/Netvox/R718H/LORIOT/uplink/payload_3.json new file mode 100644 index 00000000..c77d4aab --- /dev/null +++ b/VENDORS/Netvox/R718H/LORIOT/uplink/payload_3.json @@ -0,0 +1,32 @@ +{ + "cmd": "gw", + "seqno": 4, + "EUI": "0102030405060708", + "ts": 1690901260493, + "fcnt": 3, + "port": 6, + "freq": 868300000, + "toa": 1319, + "dr": "SF12 BW125 4/5", + "ack": false, + "gws": [ + { + "rssi": -38, + "snr": 8.5, + "ts": 1690901260493, + "time": "2023-08-01T14:47:40.493Z", + "gweui": "1020304080706050", + "ant": 0 + }, + { + "rssi": -42, + "snr": 8.8, + "ts": 1690901260495, + "time": "2023-08-01T14:47:40.495Z", + "gweui": "1020304081716151", + "ant": 0 + } + ], + "bat": 143, + "data": "011F012400C80000000000" +} diff --git a/VENDORS/Netvox/R718H/LORIOT/uplink/result_3.json b/VENDORS/Netvox/R718H/LORIOT/uplink/result_3.json new file mode 100644 index 00000000..2601e313 --- /dev/null +++ b/VENDORS/Netvox/R718H/LORIOT/uplink/result_3.json @@ -0,0 +1,42 @@ +[{ + "deviceName": "0102030405060708", + "deviceType": "R718H", + "attributes": { + "eui": "0102030405060708", + "fPort": 6, + "frequency": 868300000 + }, + "telemetry": [{ + "ts": 1690901260493, + "values": { + "battery_voltage": 3.6, + "pulseCount": 200 + } + }] +}, { + "deviceName": "Gateway 1020304080706050", + "deviceType": "Lora gateway", + "telemetry": [{ + "ts": 1690901260493, + "values": { + "rssi": -38, + "snr": 8.5 + } + }], + "attributes": { + "eui": "1020304080706050" + } +}, { + "deviceName": "Gateway 1020304081716151", + "deviceType": "Lora gateway", + "telemetry": [{ + "ts": 1690901260495, + "values": { + "rssi": -42, + "snr": 8.8 + } + }], + "attributes": { + "eui": "1020304081716151" + } +}] \ No newline at end of file diff --git a/VENDORS/Netvox/R718KA/LORIOT/uplink/payload_2.json b/VENDORS/Netvox/R718KA/LORIOT/uplink/payload_2.json new file mode 100644 index 00000000..95332e15 --- /dev/null +++ b/VENDORS/Netvox/R718KA/LORIOT/uplink/payload_2.json @@ -0,0 +1,32 @@ +{ + "cmd": "gw", + "seqno": 4, + "EUI": "0102030405060708", + "ts": 1690901260493, + "fcnt": 3, + "port": 6, + "freq": 868300000, + "toa": 1319, + "dr": "SF12 BW125 4/5", + "ack": false, + "gws": [ + { + "rssi": -38, + "snr": 8.5, + "ts": 1690901260493, + "time": "2023-08-01T14:47:40.493Z", + "gweui": "1020304080706050", + "ant": 0 + }, + { + "rssi": -42, + "snr": 8.8, + "ts": 1690901260495, + "time": "2023-08-01T14:47:40.495Z", + "gweui": "1020304081716151", + "ant": 0 + } + ], + "bat": 143, + "data": "01220123074E0000000000" +} diff --git a/VENDORS/Netvox/R718KA/LORIOT/uplink/result_2.json b/VENDORS/Netvox/R718KA/LORIOT/uplink/result_2.json new file mode 100644 index 00000000..a6e3eee9 --- /dev/null +++ b/VENDORS/Netvox/R718KA/LORIOT/uplink/result_2.json @@ -0,0 +1,43 @@ +[{ + "deviceName": "0102030405060708", + "deviceType": "R718KA", + "attributes": { + "eui": "0102030405060708", + "fPort": 6, + "frequency": 868300000 + }, + "telemetry": [{ + "ts": 1690901260493, + "values": { + "battery_voltage": 3.5, + "current": 7, + "fineCurrent": 7.8 + } + }] +}, { + "deviceName": "Gateway 1020304080706050", + "deviceType": "Lora gateway", + "telemetry": [{ + "ts": 1690901260493, + "values": { + "rssi": -38, + "snr": 8.5 + } + }], + "attributes": { + "eui": "1020304080706050" + } +}, { + "deviceName": "Gateway 1020304081716151", + "deviceType": "Lora gateway", + "telemetry": [{ + "ts": 1690901260495, + "values": { + "rssi": -42, + "snr": 8.8 + } + }], + "attributes": { + "eui": "1020304081716151" + } +}] \ No newline at end of file diff --git a/VENDORS/Netvox/R718WB/LORIOT/uplink/payload_2.json b/VENDORS/Netvox/R718WB/LORIOT/uplink/payload_2.json new file mode 100644 index 00000000..7680b019 --- /dev/null +++ b/VENDORS/Netvox/R718WB/LORIOT/uplink/payload_2.json @@ -0,0 +1,32 @@ +{ + "cmd": "gw", + "seqno": 4, + "EUI": "0102030405060708", + "ts": 1690901260493, + "fcnt": 3, + "port": 6, + "freq": 868300000, + "toa": 1319, + "dr": "SF12 BW125 4/5", + "ack": false, + "gws": [ + { + "rssi": -38, + "snr": 8.5, + "ts": 1690901260493, + "time": "2023-08-01T14:47:40.493Z", + "gweui": "1020304080706050", + "ant": 0 + }, + { + "rssi": -42, + "snr": 8.8, + "ts": 1690901260495, + "time": "2023-08-01T14:47:40.495Z", + "gweui": "1020304081716151", + "ant": 0 + } + ], + "bat": 143, + "data": "0112012401000000000000" +} diff --git a/VENDORS/Netvox/R718WB/LORIOT/uplink/result_2.json b/VENDORS/Netvox/R718WB/LORIOT/uplink/result_2.json new file mode 100644 index 00000000..2bee20a7 --- /dev/null +++ b/VENDORS/Netvox/R718WB/LORIOT/uplink/result_2.json @@ -0,0 +1,42 @@ +[{ + "deviceName": "0102030405060708", + "deviceType": "R718WB", + "attributes": { + "eui": "0102030405060708", + "fPort": 6, + "frequency": 868300000 + }, + "telemetry": [{ + "ts": 1690901260493, + "values": { + "battery_voltage": 3.6, + "water_leak": "leak" + } + }] +}, { + "deviceName": "Gateway 1020304080706050", + "deviceType": "Lora gateway", + "telemetry": [{ + "ts": 1690901260493, + "values": { + "rssi": -38, + "snr": 8.5 + } + }], + "attributes": { + "eui": "1020304080706050" + } +}, { + "deviceName": "Gateway 1020304081716151", + "deviceType": "Lora gateway", + "telemetry": [{ + "ts": 1690901260495, + "values": { + "rssi": -42, + "snr": 8.8 + } + }], + "attributes": { + "eui": "1020304081716151" + } +}] \ No newline at end of file diff --git a/VENDORS/Netvox/R719A/LORIOT/uplink/payload_2.json b/VENDORS/Netvox/R719A/LORIOT/uplink/payload_2.json new file mode 100644 index 00000000..170a695f --- /dev/null +++ b/VENDORS/Netvox/R719A/LORIOT/uplink/payload_2.json @@ -0,0 +1,32 @@ +{ + "cmd": "gw", + "seqno": 4, + "EUI": "0102030405060708", + "ts": 1690901260493, + "fcnt": 3, + "port": 6, + "freq": 868300000, + "toa": 1319, + "dr": "SF12 BW125 4/5", + "ack": false, + "gws": [ + { + "rssi": -38, + "snr": 8.5, + "ts": 1690901260493, + "time": "2023-08-01T14:47:40.493Z", + "gweui": "1020304080706050", + "ant": 0 + }, + { + "rssi": -42, + "snr": 8.8, + "ts": 1690901260495, + "time": "2023-08-01T14:47:40.495Z", + "gweui": "1020304081716151", + "ant": 0 + } + ], + "bat": 143, + "data": "0159012401000000000000" +} diff --git a/VENDORS/Netvox/R719A/LORIOT/uplink/result_2.json b/VENDORS/Netvox/R719A/LORIOT/uplink/result_2.json new file mode 100644 index 00000000..5ef5cf00 --- /dev/null +++ b/VENDORS/Netvox/R719A/LORIOT/uplink/result_2.json @@ -0,0 +1,42 @@ +[{ + "deviceName": "0102030405060708", + "deviceType": "R719A", + "attributes": { + "eui": "0102030405060708", + "fPort": 6, + "frequency": 868300000 + }, + "telemetry": [{ + "ts": 1690901260493, + "values": { + "battery_voltage": 3.6, + "occupied": "on" + } + }] +}, { + "deviceName": "Gateway 1020304080706050", + "deviceType": "Lora gateway", + "telemetry": [{ + "ts": 1690901260493, + "values": { + "rssi": -38, + "snr": 8.5 + } + }], + "attributes": { + "eui": "1020304080706050" + } +}, { + "deviceName": "Gateway 1020304081716151", + "deviceType": "Lora gateway", + "telemetry": [{ + "ts": 1690901260495, + "values": { + "rssi": -42, + "snr": 8.8 + } + }], + "attributes": { + "eui": "1020304081716151" + } +}] \ No newline at end of file diff --git a/VENDORS/Netvox/R72624/LORIOT/uplink/payload_2.json b/VENDORS/Netvox/R72624/LORIOT/uplink/payload_2.json new file mode 100644 index 00000000..08c4b728 --- /dev/null +++ b/VENDORS/Netvox/R72624/LORIOT/uplink/payload_2.json @@ -0,0 +1,32 @@ +{ + "cmd": "gw", + "seqno": 4, + "EUI": "0102030405060708", + "ts": 1690901260493, + "fcnt": 3, + "port": 6, + "freq": 868300000, + "toa": 1319, + "dr": "SF12 BW125 4/5", + "ack": false, + "gws": [ + { + "rssi": -38, + "snr": 8.5, + "ts": 1690901260493, + "time": "2023-08-01T14:47:40.493Z", + "gweui": "1020304080706050", + "ant": 0 + }, + { + "rssi": -42, + "snr": 8.8, + "ts": 1690901260495, + "time": "2023-08-01T14:47:40.495Z", + "gweui": "1020304081716151", + "ant": 0 + } + ], + "bat": 143, + "data": "01090778FFFFFFFF025800" +} diff --git a/VENDORS/Netvox/R72624/LORIOT/uplink/result_2.json b/VENDORS/Netvox/R72624/LORIOT/uplink/result_2.json new file mode 100644 index 00000000..b318288b --- /dev/null +++ b/VENDORS/Netvox/R72624/LORIOT/uplink/result_2.json @@ -0,0 +1,42 @@ +[{ + "deviceName": "0102030405060708", + "deviceType": "R72624", + "attributes": { + "eui": "0102030405060708", + "fPort": 6, + "frequency": 868300000 + }, + "telemetry": [{ + "ts": 1690901260493, + "values": { + "battery_volt": 12.0, + "noise": 60.0 + } + }] +}, { + "deviceName": "Gateway 1020304080706050", + "deviceType": "Lora gateway", + "telemetry": [{ + "ts": 1690901260493, + "values": { + "rssi": -38, + "snr": 8.5 + } + }], + "attributes": { + "eui": "1020304080706050" + } +}, { + "deviceName": "Gateway 1020304081716151", + "deviceType": "Lora gateway", + "telemetry": [{ + "ts": 1690901260495, + "values": { + "rssi": -42, + "snr": 8.8 + } + }], + "attributes": { + "eui": "1020304081716151" + } +}] \ No newline at end of file diff --git a/VENDORS/Netvox/RA0715/LORIOT/uplink/payload_2.json b/VENDORS/Netvox/RA0715/LORIOT/uplink/payload_2.json new file mode 100644 index 00000000..b2987cff --- /dev/null +++ b/VENDORS/Netvox/RA0715/LORIOT/uplink/payload_2.json @@ -0,0 +1,32 @@ +{ + "cmd": "gw", + "seqno": 4, + "EUI": "0102030405060708", + "ts": 1690901260493, + "fcnt": 3, + "port": 6, + "freq": 868300000, + "toa": 1319, + "dr": "SF12 BW125 4/5", + "ack": false, + "gws": [ + { + "rssi": -38, + "snr": 8.5, + "ts": 1690901260493, + "time": "2023-08-01T14:47:40.493Z", + "gweui": "1020304080706050", + "ant": 0 + }, + { + "rssi": -42, + "snr": 8.8, + "ts": 1690901260495, + "time": "2023-08-01T14:47:40.495Z", + "gweui": "1020304081716151", + "ant": 0 + } + ], + "bat": 143, + "data": "010507002134FFFFFFFF00" +} diff --git a/VENDORS/Netvox/RA0715/LORIOT/uplink/result_2.json b/VENDORS/Netvox/RA0715/LORIOT/uplink/result_2.json new file mode 100644 index 00000000..02495699 --- /dev/null +++ b/VENDORS/Netvox/RA0715/LORIOT/uplink/result_2.json @@ -0,0 +1,42 @@ +[{ + "deviceName": "0102030405060708", + "deviceType": "RA0715", + "attributes": { + "eui": "0102030405060708", + "fPort": 6, + "frequency": 868300000 + }, + "telemetry": [{ + "ts": 1690901260493, + "values": { + "battery_voltage": 0.0, + "co2": 850.0 + } + }] +}, { + "deviceName": "Gateway 1020304080706050", + "deviceType": "Lora gateway", + "telemetry": [{ + "ts": 1690901260493, + "values": { + "rssi": -38, + "snr": 8.5 + } + }], + "attributes": { + "eui": "1020304080706050" + } +}, { + "deviceName": "Gateway 1020304081716151", + "deviceType": "Lora gateway", + "telemetry": [{ + "ts": 1690901260495, + "values": { + "rssi": -42, + "snr": 8.8 + } + }], + "attributes": { + "eui": "1020304081716151" + } +}] \ No newline at end of file diff --git a/VENDORS/Netvox/RA0723/LORIOT/uplink/payload_3.json b/VENDORS/Netvox/RA0723/LORIOT/uplink/payload_3.json new file mode 100644 index 00000000..d6f16642 --- /dev/null +++ b/VENDORS/Netvox/RA0723/LORIOT/uplink/payload_3.json @@ -0,0 +1,32 @@ +{ + "cmd": "gw", + "seqno": 4, + "EUI": "0102030405060708", + "ts": 1690901260493, + "fcnt": 3, + "port": 6, + "freq": 868300000, + "toa": 1319, + "dr": "SF12 BW125 4/5", + "ack": false, + "gws": [ + { + "rssi": -38, + "snr": 8.5, + "ts": 1690901260493, + "time": "2023-08-01T14:47:40.493Z", + "gweui": "1020304080706050", + "ant": 0 + }, + { + "rssi": -42, + "snr": 8.8, + "ts": 1690901260495, + "time": "2023-08-01T14:47:40.495Z", + "gweui": "1020304081716151", + "ant": 0 + } + ], + "bat": 143, + "data": "01050278ffff000effff00" +} diff --git a/VENDORS/Netvox/RA0723/LORIOT/uplink/result_3.json b/VENDORS/Netvox/RA0723/LORIOT/uplink/result_3.json new file mode 100644 index 00000000..e4bcd58f --- /dev/null +++ b/VENDORS/Netvox/RA0723/LORIOT/uplink/result_3.json @@ -0,0 +1,42 @@ +[{ + "deviceName": "0102030405060708", + "deviceType": "RA0723", + "attributes": { + "eui": "0102030405060708", + "fPort": 6, + "frequency": 868300000 + }, + "telemetry": [{ + "ts": 1690901260493, + "values": { + "battery_voltage": 12.0, + "pm2_5": 14 + } + }] +}, { + "deviceName": "Gateway 1020304080706050", + "deviceType": "Lora gateway", + "telemetry": [{ + "ts": 1690901260493, + "values": { + "rssi": -38, + "snr": 8.5 + } + }], + "attributes": { + "eui": "1020304080706050" + } +}, { + "deviceName": "Gateway 1020304081716151", + "deviceType": "Lora gateway", + "telemetry": [{ + "ts": 1690901260495, + "values": { + "rssi": -42, + "snr": 8.8 + } + }], + "attributes": { + "eui": "1020304081716151" + } +}] \ No newline at end of file From 3defd9e447c34ffe1c5c3e7bfa5bcdcd18c034e1 Mon Sep 17 00:00:00 2001 From: Artem Barysh Date: Tue, 24 Dec 2024 17:20:28 +0200 Subject: [PATCH 25/33] Added an additional test cases for loriot integration(Tektelic devices) --- .../Aura/LORIOT/uplink/payload_1.json | 32 ++++++++++++++ .../Tektelic/Aura/LORIOT/uplink/result_1.json | 43 +++++++++++++++++++ .../Clover/LORIOT/uplink/payload_2.json | 32 ++++++++++++++ .../Clover/LORIOT/uplink/result_2.json | 42 ++++++++++++++++++ .../Comfort/LORIOT/uplink/payload_1.json | 32 ++++++++++++++ .../Comfort/LORIOT/uplink/result_1.json | 43 +++++++++++++++++++ .../Flux/LORIOT/uplink/payload_1.json | 32 ++++++++++++++ .../Tektelic/Flux/LORIOT/uplink/result_1.json | 43 +++++++++++++++++++ .../Kiwi/LORIOT/uplink/payload_2.json | 32 ++++++++++++++ .../Tektelic/Kiwi/LORIOT/uplink/result_2.json | 42 ++++++++++++++++++ .../Vivid/LORIOT/uplink/payload_1.json | 32 ++++++++++++++ .../Vivid/LORIOT/uplink/result_1.json | 43 +++++++++++++++++++ 12 files changed, 448 insertions(+) create mode 100644 VENDORS/Tektelic/Aura/LORIOT/uplink/payload_1.json create mode 100644 VENDORS/Tektelic/Aura/LORIOT/uplink/result_1.json create mode 100644 VENDORS/Tektelic/Clover/LORIOT/uplink/payload_2.json create mode 100644 VENDORS/Tektelic/Clover/LORIOT/uplink/result_2.json create mode 100644 VENDORS/Tektelic/Comfort/LORIOT/uplink/payload_1.json create mode 100644 VENDORS/Tektelic/Comfort/LORIOT/uplink/result_1.json create mode 100644 VENDORS/Tektelic/Flux/LORIOT/uplink/payload_1.json create mode 100644 VENDORS/Tektelic/Flux/LORIOT/uplink/result_1.json create mode 100644 VENDORS/Tektelic/Kiwi/LORIOT/uplink/payload_2.json create mode 100644 VENDORS/Tektelic/Kiwi/LORIOT/uplink/result_2.json create mode 100644 VENDORS/Tektelic/Vivid/LORIOT/uplink/payload_1.json create mode 100644 VENDORS/Tektelic/Vivid/LORIOT/uplink/result_1.json diff --git a/VENDORS/Tektelic/Aura/LORIOT/uplink/payload_1.json b/VENDORS/Tektelic/Aura/LORIOT/uplink/payload_1.json new file mode 100644 index 00000000..e8ca0eaa --- /dev/null +++ b/VENDORS/Tektelic/Aura/LORIOT/uplink/payload_1.json @@ -0,0 +1,32 @@ +{ + "cmd": "gw", + "seqno": 4, + "EUI": "0102030405060708", + "ts": 1690901260493, + "fcnt": 3, + "port": 10, + "freq": 868300000, + "toa": 1319, + "dr": "SF12 BW125 4/5", + "ack": false, + "gws": [ + { + "rssi": -38, + "snr": 8.5, + "ts": 1690901260493, + "time": "2023-08-01T14:47:40.493Z", + "gweui": "1020304080706050", + "ant": 0 + }, + { + "rssi": -42, + "snr": 8.8, + "ts": 1690901260495, + "time": "2023-08-01T14:47:40.495Z", + "gweui": "1020304081716151", + "ant": 0 + } + ], + "bat": 143, + "data": "00FE0001518000006A50000000" +} diff --git a/VENDORS/Tektelic/Aura/LORIOT/uplink/result_1.json b/VENDORS/Tektelic/Aura/LORIOT/uplink/result_1.json new file mode 100644 index 00000000..4a82f118 --- /dev/null +++ b/VENDORS/Tektelic/Aura/LORIOT/uplink/result_1.json @@ -0,0 +1,43 @@ +[{ + "deviceName": "0102030405060708", + "deviceType": "Aura", + "attributes": { + "eui": "0102030405060708", + "fPort": 10, + "frequency": 868300000 + }, + "telemetry": [{ + "ts": 1690901260493, + "values": { + "energy_consumption_meter_elapsed": 86400, + "energy_consumption_meter_consumed": 27216, + "energy_consumption_meter_status": 0 + } + }] +}, { + "deviceName": "Gateway 1020304080706050", + "deviceType": "Lora gateway", + "telemetry": [{ + "ts": 1690901260493, + "values": { + "rssi": -38, + "snr": 8.5 + } + }], + "attributes": { + "eui": "1020304080706050" + } +}, { + "deviceName": "Gateway 1020304081716151", + "deviceType": "Lora gateway", + "telemetry": [{ + "ts": 1690901260495, + "values": { + "rssi": -42, + "snr": 8.8 + } + }], + "attributes": { + "eui": "1020304081716151" + } +}] \ No newline at end of file diff --git a/VENDORS/Tektelic/Clover/LORIOT/uplink/payload_2.json b/VENDORS/Tektelic/Clover/LORIOT/uplink/payload_2.json new file mode 100644 index 00000000..52cedeef --- /dev/null +++ b/VENDORS/Tektelic/Clover/LORIOT/uplink/payload_2.json @@ -0,0 +1,32 @@ +{ + "cmd": "gw", + "seqno": 4, + "EUI": "0102030405060708", + "ts": 1690901260493, + "fcnt": 3, + "port": 10, + "freq": 868300000, + "toa": 1319, + "dr": "SF12 BW125 4/5", + "ack": false, + "gws": [ + { + "rssi": -38, + "snr": 8.5, + "ts": 1690901260493, + "time": "2023-08-01T14:47:40.493Z", + "gweui": "1020304080706050", + "ant": 0 + }, + { + "rssi": -42, + "snr": 8.8, + "ts": 1690901260495, + "time": "2023-08-01T14:47:40.495Z", + "gweui": "1020304081716151", + "ant": 0 + } + ], + "bat": 143, + "data": "00d35a00bd0a0a" +} diff --git a/VENDORS/Tektelic/Clover/LORIOT/uplink/result_2.json b/VENDORS/Tektelic/Clover/LORIOT/uplink/result_2.json new file mode 100644 index 00000000..b5fcd86a --- /dev/null +++ b/VENDORS/Tektelic/Clover/LORIOT/uplink/result_2.json @@ -0,0 +1,42 @@ +[{ + "deviceName": "0102030405060708", + "deviceType": "Clover", + "attributes": { + "eui": "0102030405060708", + "fPort": 10, + "frequency": 868300000 + }, + "telemetry": [{ + "ts": 1690901260493, + "values": { + "rem_batt_capacity": 90, + "rem_batt_days": 2570 + } + }] +}, { + "deviceName": "Gateway 1020304080706050", + "deviceType": "Lora gateway", + "telemetry": [{ + "ts": 1690901260493, + "values": { + "rssi": -38, + "snr": 8.5 + } + }], + "attributes": { + "eui": "1020304080706050" + } +}, { + "deviceName": "Gateway 1020304081716151", + "deviceType": "Lora gateway", + "telemetry": [{ + "ts": 1690901260495, + "values": { + "rssi": -42, + "snr": 8.8 + } + }], + "attributes": { + "eui": "1020304081716151" + } +}] \ No newline at end of file diff --git a/VENDORS/Tektelic/Comfort/LORIOT/uplink/payload_1.json b/VENDORS/Tektelic/Comfort/LORIOT/uplink/payload_1.json new file mode 100644 index 00000000..56e86f64 --- /dev/null +++ b/VENDORS/Tektelic/Comfort/LORIOT/uplink/payload_1.json @@ -0,0 +1,32 @@ +{ + "cmd": "gw", + "seqno": 4, + "EUI": "0102030405060708", + "ts": 1690901260493, + "fcnt": 3, + "port": 10, + "freq": 868300000, + "toa": 1319, + "dr": "SF12 BW125 4/5", + "ack": false, + "gws": [ + { + "rssi": -38, + "snr": 8.5, + "ts": 1690901260493, + "time": "2023-08-01T14:47:40.493Z", + "gweui": "1020304080706050", + "ant": 0 + }, + { + "rssi": -42, + "snr": 8.8, + "ts": 1690901260495, + "time": "2023-08-01T14:47:40.495Z", + "gweui": "1020304081716151", + "ant": 0 + } + ], + "bat": 143, + "data": "036700E104684D00BA0B9E" +} diff --git a/VENDORS/Tektelic/Comfort/LORIOT/uplink/result_1.json b/VENDORS/Tektelic/Comfort/LORIOT/uplink/result_1.json new file mode 100644 index 00000000..1fbc610a --- /dev/null +++ b/VENDORS/Tektelic/Comfort/LORIOT/uplink/result_1.json @@ -0,0 +1,43 @@ +[{ + "deviceName": "0102030405060708", + "deviceType": "Comfort", + "attributes": { + "eui": "0102030405060708", + "fPort": 10, + "frequency": 868300000 + }, + "telemetry": [{ + "ts": 1690901260493, + "values": { + "ambient_temperature": 22.5, + "relative_humidity": 38.5, + "battery_voltage": 2.974 + } + }] +}, { + "deviceName": "Gateway 1020304080706050", + "deviceType": "Lora gateway", + "telemetry": [{ + "ts": 1690901260493, + "values": { + "rssi": -38, + "snr": 8.5 + } + }], + "attributes": { + "eui": "1020304080706050" + } +}, { + "deviceName": "Gateway 1020304081716151", + "deviceType": "Lora gateway", + "telemetry": [{ + "ts": 1690901260495, + "values": { + "rssi": -42, + "snr": 8.8 + } + }], + "attributes": { + "eui": "1020304081716151" + } +}] \ No newline at end of file diff --git a/VENDORS/Tektelic/Flux/LORIOT/uplink/payload_1.json b/VENDORS/Tektelic/Flux/LORIOT/uplink/payload_1.json new file mode 100644 index 00000000..e8ca0eaa --- /dev/null +++ b/VENDORS/Tektelic/Flux/LORIOT/uplink/payload_1.json @@ -0,0 +1,32 @@ +{ + "cmd": "gw", + "seqno": 4, + "EUI": "0102030405060708", + "ts": 1690901260493, + "fcnt": 3, + "port": 10, + "freq": 868300000, + "toa": 1319, + "dr": "SF12 BW125 4/5", + "ack": false, + "gws": [ + { + "rssi": -38, + "snr": 8.5, + "ts": 1690901260493, + "time": "2023-08-01T14:47:40.493Z", + "gweui": "1020304080706050", + "ant": 0 + }, + { + "rssi": -42, + "snr": 8.8, + "ts": 1690901260495, + "time": "2023-08-01T14:47:40.495Z", + "gweui": "1020304081716151", + "ant": 0 + } + ], + "bat": 143, + "data": "00FE0001518000006A50000000" +} diff --git a/VENDORS/Tektelic/Flux/LORIOT/uplink/result_1.json b/VENDORS/Tektelic/Flux/LORIOT/uplink/result_1.json new file mode 100644 index 00000000..9cb55f00 --- /dev/null +++ b/VENDORS/Tektelic/Flux/LORIOT/uplink/result_1.json @@ -0,0 +1,43 @@ +[{ + "deviceName": "0102030405060708", + "deviceType": "Flux", + "attributes": { + "eui": "0102030405060708", + "fPort": 10, + "frequency": 868300000 + }, + "telemetry": [{ + "ts": 1690901260493, + "values": { + "energy_consumption_meter_elapsed": 86400, + "energy_consumption_meter_consumed": 27216, + "energy_consumption_meter_status": 0 + } + }] +}, { + "deviceName": "Gateway 1020304080706050", + "deviceType": "Lora gateway", + "telemetry": [{ + "ts": 1690901260493, + "values": { + "rssi": -38, + "snr": 8.5 + } + }], + "attributes": { + "eui": "1020304080706050" + } +}, { + "deviceName": "Gateway 1020304081716151", + "deviceType": "Lora gateway", + "telemetry": [{ + "ts": 1690901260495, + "values": { + "rssi": -42, + "snr": 8.8 + } + }], + "attributes": { + "eui": "1020304081716151" + } +}] \ No newline at end of file diff --git a/VENDORS/Tektelic/Kiwi/LORIOT/uplink/payload_2.json b/VENDORS/Tektelic/Kiwi/LORIOT/uplink/payload_2.json new file mode 100644 index 00000000..52cedeef --- /dev/null +++ b/VENDORS/Tektelic/Kiwi/LORIOT/uplink/payload_2.json @@ -0,0 +1,32 @@ +{ + "cmd": "gw", + "seqno": 4, + "EUI": "0102030405060708", + "ts": 1690901260493, + "fcnt": 3, + "port": 10, + "freq": 868300000, + "toa": 1319, + "dr": "SF12 BW125 4/5", + "ack": false, + "gws": [ + { + "rssi": -38, + "snr": 8.5, + "ts": 1690901260493, + "time": "2023-08-01T14:47:40.493Z", + "gweui": "1020304080706050", + "ant": 0 + }, + { + "rssi": -42, + "snr": 8.8, + "ts": 1690901260495, + "time": "2023-08-01T14:47:40.495Z", + "gweui": "1020304081716151", + "ant": 0 + } + ], + "bat": 143, + "data": "00d35a00bd0a0a" +} diff --git a/VENDORS/Tektelic/Kiwi/LORIOT/uplink/result_2.json b/VENDORS/Tektelic/Kiwi/LORIOT/uplink/result_2.json new file mode 100644 index 00000000..63f56d36 --- /dev/null +++ b/VENDORS/Tektelic/Kiwi/LORIOT/uplink/result_2.json @@ -0,0 +1,42 @@ +[{ + "deviceName": "0102030405060708", + "deviceType": "Kiwi", + "attributes": { + "eui": "0102030405060708", + "fPort": 10, + "frequency": 868300000 + }, + "telemetry": [{ + "ts": 1690901260493, + "values": { + "rem_batt_capacity": 90, + "rem_batt_days": 2570 + } + }] +}, { + "deviceName": "Gateway 1020304080706050", + "deviceType": "Lora gateway", + "telemetry": [{ + "ts": 1690901260493, + "values": { + "rssi": -38, + "snr": 8.5 + } + }], + "attributes": { + "eui": "1020304080706050" + } +}, { + "deviceName": "Gateway 1020304081716151", + "deviceType": "Lora gateway", + "telemetry": [{ + "ts": 1690901260495, + "values": { + "rssi": -42, + "snr": 8.8 + } + }], + "attributes": { + "eui": "1020304081716151" + } +}] \ No newline at end of file diff --git a/VENDORS/Tektelic/Vivid/LORIOT/uplink/payload_1.json b/VENDORS/Tektelic/Vivid/LORIOT/uplink/payload_1.json new file mode 100644 index 00000000..56e86f64 --- /dev/null +++ b/VENDORS/Tektelic/Vivid/LORIOT/uplink/payload_1.json @@ -0,0 +1,32 @@ +{ + "cmd": "gw", + "seqno": 4, + "EUI": "0102030405060708", + "ts": 1690901260493, + "fcnt": 3, + "port": 10, + "freq": 868300000, + "toa": 1319, + "dr": "SF12 BW125 4/5", + "ack": false, + "gws": [ + { + "rssi": -38, + "snr": 8.5, + "ts": 1690901260493, + "time": "2023-08-01T14:47:40.493Z", + "gweui": "1020304080706050", + "ant": 0 + }, + { + "rssi": -42, + "snr": 8.8, + "ts": 1690901260495, + "time": "2023-08-01T14:47:40.495Z", + "gweui": "1020304081716151", + "ant": 0 + } + ], + "bat": 143, + "data": "036700E104684D00BA0B9E" +} diff --git a/VENDORS/Tektelic/Vivid/LORIOT/uplink/result_1.json b/VENDORS/Tektelic/Vivid/LORIOT/uplink/result_1.json new file mode 100644 index 00000000..bbe32d05 --- /dev/null +++ b/VENDORS/Tektelic/Vivid/LORIOT/uplink/result_1.json @@ -0,0 +1,43 @@ +[{ + "deviceName": "0102030405060708", + "deviceType": "Vivid", + "attributes": { + "eui": "0102030405060708", + "fPort": 10, + "frequency": 868300000 + }, + "telemetry": [{ + "ts": 1690901260493, + "values": { + "ambient_temperature": 22.5, + "relative_humidity": 38.5, + "battery_voltage": 2.974 + } + }] +}, { + "deviceName": "Gateway 1020304080706050", + "deviceType": "Lora gateway", + "telemetry": [{ + "ts": 1690901260493, + "values": { + "rssi": -38, + "snr": 8.5 + } + }], + "attributes": { + "eui": "1020304080706050" + } +}, { + "deviceName": "Gateway 1020304081716151", + "deviceType": "Lora gateway", + "telemetry": [{ + "ts": 1690901260495, + "values": { + "rssi": -42, + "snr": 8.8 + } + }], + "attributes": { + "eui": "1020304081716151" + } +}] \ No newline at end of file From 82d191e0e56d0eb795190cc254836cc805aa1d99 Mon Sep 17 00:00:00 2001 From: Artem Barysh Date: Thu, 26 Dec 2024 11:38:41 +0200 Subject: [PATCH 26/33] Added an additional test case for integrating Loriot (Yobiiq device) --- .../EM2101/LORIOT/uplink/payload_5.json | 32 +++++++++++++++++ .../Yobiiq/EM2101/LORIOT/uplink/result_5.json | 27 +++++++++++++++ .../EM4301/LORIOT/uplink/payload_4.json | 32 +++++++++++++++++ .../Yobiiq/EM4301/LORIOT/uplink/result_4.json | 30 ++++++++++++++++ .../Yobiiq/RM200/LORIOT/uplink/payload_4.json | 32 +++++++++++++++++ .../Yobiiq/RM200/LORIOT/uplink/result_4.json | 34 +++++++++++++++++++ .../SD1001/LORIOT/uplink/payload_4.json | 32 +++++++++++++++++ .../Yobiiq/SD1001/LORIOT/uplink/result_4.json | 25 ++++++++++++++ 8 files changed, 244 insertions(+) create mode 100644 VENDORS/Yobiiq/EM2101/LORIOT/uplink/payload_5.json create mode 100644 VENDORS/Yobiiq/EM2101/LORIOT/uplink/result_5.json create mode 100644 VENDORS/Yobiiq/EM4301/LORIOT/uplink/payload_4.json create mode 100644 VENDORS/Yobiiq/EM4301/LORIOT/uplink/result_4.json create mode 100644 VENDORS/Yobiiq/RM200/LORIOT/uplink/payload_4.json create mode 100644 VENDORS/Yobiiq/RM200/LORIOT/uplink/result_4.json create mode 100644 VENDORS/Yobiiq/SD1001/LORIOT/uplink/payload_4.json create mode 100644 VENDORS/Yobiiq/SD1001/LORIOT/uplink/result_4.json diff --git a/VENDORS/Yobiiq/EM2101/LORIOT/uplink/payload_5.json b/VENDORS/Yobiiq/EM2101/LORIOT/uplink/payload_5.json new file mode 100644 index 00000000..73297087 --- /dev/null +++ b/VENDORS/Yobiiq/EM2101/LORIOT/uplink/payload_5.json @@ -0,0 +1,32 @@ +{ + "cmd": "gw", + "seqno": 4, + "EUI": "0102030405060708", + "ts": 1690901260493, + "fcnt": 3, + "port": 50, + "freq": 868300000, + "toa": 1319, + "dr": "SF12 BW125 4/5", + "ack": false, + "gws": [ + { + "rssi": -38, + "snr": 8.5, + "ts": 1690901260493, + "time": "2023-08-01T14:47:40.493Z", + "gweui": "1020304080706050", + "ant": 0 + }, + { + "rssi": -42, + "snr": 8.8, + "ts": 1690901260495, + "time": "2023-08-01T14:47:40.495Z", + "gweui": "1020304081716151", + "ant": 0 + } + ], + "bat": 143, + "data": "FF090200FF0A2301FF1601ED0333FF0F02FF0B01FF0001FF28454D32313031" +} diff --git a/VENDORS/Yobiiq/EM2101/LORIOT/uplink/result_5.json b/VENDORS/Yobiiq/EM2101/LORIOT/uplink/result_5.json new file mode 100644 index 00000000..eec7a385 --- /dev/null +++ b/VENDORS/Yobiiq/EM2101/LORIOT/uplink/result_5.json @@ -0,0 +1,27 @@ +{ + "deviceName": "0102030405060708", + "deviceType": "Electricity Meter", + "groupName": "Electricity Meters", + "attributes": { + "codecVersion": "1.0.0", + "genericModel": "EM2101", + "productCode": "P1002009", + "manufacturer": "YOBIIQ B.V.", + "devEui": "0102030405060708", + "latestFPort": 50, + "hardwareVersion": "V2.0", + "firmwareVersion": "V23.1", + "deviceSerialNumber": 32310067, + "deviceClass": "Class C", + "powerEvent": "AC Power On", + "relayStatus": "HIGH", + "deviceModel": "EM2101" + }, + "telemetry": [{ + "ts": 1690901260493, + "values": { + "fPort": 50, + "fCnt": 3 + } + }] +} \ No newline at end of file diff --git a/VENDORS/Yobiiq/EM4301/LORIOT/uplink/payload_4.json b/VENDORS/Yobiiq/EM4301/LORIOT/uplink/payload_4.json new file mode 100644 index 00000000..6c65ff8f --- /dev/null +++ b/VENDORS/Yobiiq/EM4301/LORIOT/uplink/payload_4.json @@ -0,0 +1,32 @@ +{ + "cmd": "gw", + "seqno": 4, + "EUI": "0102030405060708", + "ts": 1690901260493, + "fcnt": 3, + "port": 1, + "freq": 868300000, + "toa": 1319, + "dr": "SF12 BW125 4/5", + "ack": false, + "gws": [ + { + "rssi": -38, + "snr": 8.5, + "ts": 1690901260493, + "time": "2023-08-01T14:47:40.493Z", + "gweui": "1020304080706050", + "ant": 0 + }, + { + "rssi": -42, + "snr": 8.8, + "ts": 1690901260495, + "time": "2023-08-01T14:47:40.495Z", + "gweui": "1020304081716151", + "ant": 0 + } + ], + "bat": 143, + "data": "0101673B240C0203673B21B4030403080F040405000000000506000000000607000000000B0A00" +} diff --git a/VENDORS/Yobiiq/EM4301/LORIOT/uplink/result_4.json b/VENDORS/Yobiiq/EM4301/LORIOT/uplink/result_4.json new file mode 100644 index 00000000..730e7bf3 --- /dev/null +++ b/VENDORS/Yobiiq/EM4301/LORIOT/uplink/result_4.json @@ -0,0 +1,30 @@ +{ + "deviceName": "0102030405060708", + "deviceType": "Electricity Meter", + "groupName": "Electricity Meters", + "attributes": { + "codecVersion": "1.0.0", + "genericModel": "EM4301", + "productCode": "P1002011", + "manufacturer": "YOBIIQ B.V.", + "devEui": "0102030405060708", + "latestFPort": 1 + }, + "telemetry": [{ + "ts": 1690901260493, + "values": { + "fPort": 1, + "fCnt": 3 + } + }, { + "ts": 1731928500000, + "values": { + "timestamp": 1731929100, + "activeEnergyImportL123T1": 50859780, + "activeEnergyImportL123T2": 0, + "activeEnergyExportL123T1": 0, + "activeEnergyExportL123T2": 0, + "modbusErrorCode": 0 + } + }] +} \ No newline at end of file diff --git a/VENDORS/Yobiiq/RM200/LORIOT/uplink/payload_4.json b/VENDORS/Yobiiq/RM200/LORIOT/uplink/payload_4.json new file mode 100644 index 00000000..2eaabe1a --- /dev/null +++ b/VENDORS/Yobiiq/RM200/LORIOT/uplink/payload_4.json @@ -0,0 +1,32 @@ +{ + "cmd": "gw", + "seqno": 4, + "EUI": "0102030405060708", + "ts": 1690901260493, + "fcnt": 3, + "port": 11, + "freq": 868300000, + "toa": 1319, + "dr": "SF12 BW125 4/5", + "ack": false, + "gws": [ + { + "rssi": -38, + "snr": 8.5, + "ts": 1690901260493, + "time": "2023-08-01T14:47:40.493Z", + "gweui": "1020304080706050", + "ant": 0 + }, + { + "rssi": -42, + "snr": 8.8, + "ts": 1690901260495, + "time": "2023-08-01T14:47:40.495Z", + "gweui": "1020304081716151", + "ant": 0 + } + ], + "bat": 143, + "data": "AAFE6735D830AA0101AA9700000005AA0203AA9A00000005" +} diff --git a/VENDORS/Yobiiq/RM200/LORIOT/uplink/result_4.json b/VENDORS/Yobiiq/RM200/LORIOT/uplink/result_4.json new file mode 100644 index 00000000..98945b7d --- /dev/null +++ b/VENDORS/Yobiiq/RM200/LORIOT/uplink/result_4.json @@ -0,0 +1,34 @@ +{ + "deviceName": "0102030405060708", + "deviceType": "Digital Controller", + "groupName": "Digital Controllers", + "attributes": { + "codecVersion": "1.0.0", + "genericModel": "RM200", + "productCode": "P1002003", + "manufacturer": "YOBIIQ B.V.", + "devEui": "0102030405060708", + "latestFPort": 11 + }, + "telemetry": [{ + "ts": 1690901260493, + "values": { + "fPort": 11, + "fCnt": 3 + } + }, { + "ts": 1731582000000, + "values": { + "channel1State": { + "state": "ON", + "reason": "AUTO" + }, + "channel1Counter": 5, + "channel2State": { + "state": "ON", + "reason": "MANUAL" + }, + "channel2Counter": 5 + } + }] +} \ No newline at end of file diff --git a/VENDORS/Yobiiq/SD1001/LORIOT/uplink/payload_4.json b/VENDORS/Yobiiq/SD1001/LORIOT/uplink/payload_4.json new file mode 100644 index 00000000..5350e1b1 --- /dev/null +++ b/VENDORS/Yobiiq/SD1001/LORIOT/uplink/payload_4.json @@ -0,0 +1,32 @@ +{ + "cmd": "gw", + "seqno": 4, + "EUI": "0102030405060708", + "ts": 1690901260493, + "fcnt": 3, + "port": 8, + "freq": 868300000, + "toa": 1319, + "dr": "SF12 BW125 4/5", + "ack": false, + "gws": [ + { + "rssi": -38, + "snr": 8.5, + "ts": 1690901260493, + "time": "2023-08-01T14:47:40.493Z", + "gweui": "1020304080706050", + "ant": 0 + }, + { + "rssi": -42, + "snr": 8.8, + "ts": 1690901260495, + "time": "2023-08-01T14:47:40.495Z", + "gweui": "1020304081716151", + "ant": 0 + } + ], + "bat": 143, + "data": "017564020B00030000040000050000060000" +} diff --git a/VENDORS/Yobiiq/SD1001/LORIOT/uplink/result_4.json b/VENDORS/Yobiiq/SD1001/LORIOT/uplink/result_4.json new file mode 100644 index 00000000..6c07865b --- /dev/null +++ b/VENDORS/Yobiiq/SD1001/LORIOT/uplink/result_4.json @@ -0,0 +1,25 @@ +{ + "deviceName": "0102030405060708", + "deviceType": "Smoke Detector", + "groupName": "Smoke Detectors", + "attributes": { + "devEui": "0102030405060708", + "codecVersion": "1.1.0", + "deviceModel": "SD-1001", + "productCode": "1002015", + "manufacturer": "YOBIIQ B.V." + }, + "telemetry": { + "ts": 1690901260493, + "values": { + "fPort": 8, + "fCnt": 3, + "batteryLevelInPercentage": 100, + "powerEvent": "AC Power Off", + "lowBatteryAlarm": "Normal", + "faultAlarm": "Normal", + "smokeAlarm": "Normal", + "interconnectAlarm": "Normal" + } + } +} \ No newline at end of file From 7bfce90bd909b4612263f9c8a76f77232c92ef22 Mon Sep 17 00:00:00 2001 From: Artem Barysh Date: Thu, 26 Dec 2024 13:45:11 +0200 Subject: [PATCH 27/33] Added an additional test case for integrating Loriot (Milesight device) --- .../AM102/LORIOT/uplink/converter.json | 9 ++- .../AM102/LORIOT/uplink/payload_2.json | 32 +++++++++ .../AM102/LORIOT/uplink/result_3.json | 0 .../AM102L/LORIOT/uplink/converter.json | 9 ++- .../AM102L/LORIOT/uplink/payload_2.json | 32 +++++++++ .../AM102L/LORIOT/uplink/result_2.json | 43 +++++++++++ .../AM103/LORIOT/uplink/converter.json | 9 ++- .../AM103/LORIOT/uplink/payload_2.json | 32 +++++++++ .../AM103/LORIOT/uplink/result_2.json | 51 +++++++++++++ .../AM103L/LORIOT/uplink/converter.json | 9 ++- .../AM103L/LORIOT/uplink/payload_2.json | 32 +++++++++ .../AM103L/LORIOT/uplink/result_2.json | 44 ++++++++++++ .../AM104/LORIOT/uplink/converter.json | 11 ++- .../AM104/LORIOT/uplink/payload_1.json | 32 +++++++++ .../AM104/LORIOT/uplink/result_1.json | 47 ++++++++++++ .../AM107/LORIOT/uplink/converter.json | 9 ++- .../AM107/LORIOT/uplink/payload_1.json | 32 +++++++++ .../AM107/LORIOT/uplink/result_1.json | 50 +++++++++++++ .../AM307/LORIOT/uplink/converter.json | 9 ++- .../AM307/LORIOT/uplink/payload_2.json | 32 +++++++++ .../AM307/LORIOT/uplink/result_2.json | 60 ++++++++++++++++ .../AM307L/LORIOT/uplink/converter.json | 9 ++- .../AM307L/LORIOT/uplink/payload_2.json | 32 +++++++++ .../AM307L/LORIOT/uplink/result_2.json | 60 ++++++++++++++++ .../AM308/LORIOT/uplink/converter.json | 9 ++- .../AM308/LORIOT/uplink/payload_2.json | 32 +++++++++ .../AM308/LORIOT/uplink/result_2.json | 64 +++++++++++++++++ .../AM308L/LORIOT/uplink/converter.json | 9 ++- .../AM308L/LORIOT/uplink/payload_2.json | 32 +++++++++ .../AM308L/LORIOT/uplink/result_2.json | 64 +++++++++++++++++ .../AM319/LORIOT/uplink/converter.json | 9 ++- .../AM319/LORIOT/uplink/payload_2.json | 32 +++++++++ .../AM319/LORIOT/uplink/result_2.json | 66 +++++++++++++++++ .../AM319L/LORIOT/uplink/converter.json | 9 ++- .../AM319L/LORIOT/uplink/payload_2.json | 32 +++++++++ .../AM319L/LORIOT/uplink/result_2.json | 66 +++++++++++++++++ .../AT101/LORIOT/uplink/converter.json | 9 ++- .../AT101/LORIOT/uplink/payload_2.json | 32 +++++++++ .../AT101/LORIOT/uplink/result_2.json | 71 +++++++++++++++++++ .../CT101-CT103/LORIOT/uplink/converter.json | 9 ++- .../CT101-CT103/LORIOT/uplink/payload_5.json | 32 +++++++++ .../CT101-CT103/LORIOT/uplink/result_5.json | 41 +++++++++++ .../DS3604/LORIOT/uplink/converter.json | 9 ++- .../DS3604/LORIOT/uplink/payload_1.json | 32 +++++++++ .../DS3604/LORIOT/uplink/result_1.json | 44 ++++++++++++ .../EM300-CL/LORIOT/uplink/payload_1.json | 32 +++++++++ .../EM300-CL/LORIOT/uplink/result_1.json | 42 +++++++++++ .../EM310-TILT/LORIOT/uplink/payload_1.json | 32 +++++++++ .../EM310-TILT/LORIOT/uplink/result_1.json | 46 ++++++++++++ .../EM310-UDL/LORIOT/uplink/payload_1.json | 32 +++++++++ .../EM310-UDL/LORIOT/uplink/result_1.json | 43 +++++++++++ .../EM320-TILT/LORIOT/uplink/payload_1.json | 32 +++++++++ .../EM320-TILT/LORIOT/uplink/result_1.json | 47 ++++++++++++ .../EM400-TLD/LORIOT/uplink/payload_2.json | 32 +++++++++ .../EM400-TLD/LORIOT/uplink/result_2.json | 44 ++++++++++++ .../EM400-UDL/LORIOT/uplink/payload_2.json | 32 +++++++++ .../EM400-UDL/LORIOT/uplink/result_2.json | 44 ++++++++++++ .../EM500-CO2/LORIOT/uplink/converter.json | 2 +- .../EM500-CO2/LORIOT/uplink/payload_1.json | 32 +++++++++ .../EM500-CO2/LORIOT/uplink/result_1.json | 45 ++++++++++++ .../GS101/LORIOT/uplink/converter.json | 9 ++- .../GS101/LORIOT/uplink/payload_1.json | 32 +++++++++ .../GS101/LORIOT/uplink/result_1.json | 43 +++++++++++ .../GS301/LORIOT/uplink/converter.json | 9 ++- .../GS301/LORIOT/uplink/payload_1.json | 32 +++++++++ .../GS301/LORIOT/uplink/result_1.json | 45 ++++++++++++ .../TS101/LORIOT/uplink/converter.json | 9 ++- .../TS101/LORIOT/uplink/payload_2.json | 32 +++++++++ .../TS101/LORIOT/uplink/result_2.json | 42 +++++++++++ .../TS201/LORIOT/uplink/payload_2.json | 32 +++++++++ .../TS201/LORIOT/uplink/result_2.json | 46 ++++++++++++ .../WS101/LORIOT/uplink/converter.json | 9 ++- .../WS101/LORIOT/uplink/payload_1.json | 32 +++++++++ .../WS101/LORIOT/uplink/result_1.json | 42 +++++++++++ .../WS201/LORIOT/uplink/converter.json | 9 ++- .../WS201/LORIOT/uplink/payload_1.json | 32 +++++++++ .../WS201/LORIOT/uplink/result_1.json | 43 +++++++++++ .../WS202/LORIOT/uplink/converter.json | 9 ++- .../WS202/LORIOT/uplink/payload_1.json | 32 +++++++++ .../WS202/LORIOT/uplink/result_1.json | 43 +++++++++++ .../WS301/LORIOT/uplink/converter.json | 9 ++- .../WS301/LORIOT/uplink/payload_1.json | 32 +++++++++ .../WS301/LORIOT/uplink/result_1.json | 43 +++++++++++ .../WS302/LORIOT/uplink/converter.json | 9 ++- .../WS302/LORIOT/uplink/payload_1.json | 32 +++++++++ .../WS302/LORIOT/uplink/result_1.json | 44 ++++++++++++ .../WS303/LORIOT/uplink/converter.json | 9 ++- .../WS303/LORIOT/uplink/payload_1.json | 32 +++++++++ .../WS303/LORIOT/uplink/result_1.json | 42 +++++++++++ 89 files changed, 2709 insertions(+), 50 deletions(-) create mode 100644 VENDORS/Milesight/AM102/LORIOT/uplink/payload_2.json create mode 100644 VENDORS/Milesight/AM102/LORIOT/uplink/result_3.json create mode 100644 VENDORS/Milesight/AM102L/LORIOT/uplink/payload_2.json create mode 100644 VENDORS/Milesight/AM102L/LORIOT/uplink/result_2.json create mode 100644 VENDORS/Milesight/AM103/LORIOT/uplink/payload_2.json create mode 100644 VENDORS/Milesight/AM103/LORIOT/uplink/result_2.json create mode 100644 VENDORS/Milesight/AM103L/LORIOT/uplink/payload_2.json create mode 100644 VENDORS/Milesight/AM103L/LORIOT/uplink/result_2.json create mode 100644 VENDORS/Milesight/AM104/LORIOT/uplink/payload_1.json create mode 100644 VENDORS/Milesight/AM104/LORIOT/uplink/result_1.json create mode 100644 VENDORS/Milesight/AM107/LORIOT/uplink/payload_1.json create mode 100644 VENDORS/Milesight/AM107/LORIOT/uplink/result_1.json create mode 100644 VENDORS/Milesight/AM307/LORIOT/uplink/payload_2.json create mode 100644 VENDORS/Milesight/AM307/LORIOT/uplink/result_2.json create mode 100644 VENDORS/Milesight/AM307L/LORIOT/uplink/payload_2.json create mode 100644 VENDORS/Milesight/AM307L/LORIOT/uplink/result_2.json create mode 100644 VENDORS/Milesight/AM308/LORIOT/uplink/payload_2.json create mode 100644 VENDORS/Milesight/AM308/LORIOT/uplink/result_2.json create mode 100644 VENDORS/Milesight/AM308L/LORIOT/uplink/payload_2.json create mode 100644 VENDORS/Milesight/AM308L/LORIOT/uplink/result_2.json create mode 100644 VENDORS/Milesight/AM319/LORIOT/uplink/payload_2.json create mode 100644 VENDORS/Milesight/AM319/LORIOT/uplink/result_2.json create mode 100644 VENDORS/Milesight/AM319L/LORIOT/uplink/payload_2.json create mode 100644 VENDORS/Milesight/AM319L/LORIOT/uplink/result_2.json create mode 100644 VENDORS/Milesight/AT101/LORIOT/uplink/payload_2.json create mode 100644 VENDORS/Milesight/AT101/LORIOT/uplink/result_2.json create mode 100644 VENDORS/Milesight/CT101-CT103/LORIOT/uplink/payload_5.json create mode 100644 VENDORS/Milesight/CT101-CT103/LORIOT/uplink/result_5.json create mode 100644 VENDORS/Milesight/DS3604/LORIOT/uplink/payload_1.json create mode 100644 VENDORS/Milesight/DS3604/LORIOT/uplink/result_1.json create mode 100644 VENDORS/Milesight/EM300-CL/LORIOT/uplink/payload_1.json create mode 100644 VENDORS/Milesight/EM300-CL/LORIOT/uplink/result_1.json create mode 100644 VENDORS/Milesight/EM310-TILT/LORIOT/uplink/payload_1.json create mode 100644 VENDORS/Milesight/EM310-TILT/LORIOT/uplink/result_1.json create mode 100644 VENDORS/Milesight/EM310-UDL/LORIOT/uplink/payload_1.json create mode 100644 VENDORS/Milesight/EM310-UDL/LORIOT/uplink/result_1.json create mode 100644 VENDORS/Milesight/EM320-TILT/LORIOT/uplink/payload_1.json create mode 100644 VENDORS/Milesight/EM320-TILT/LORIOT/uplink/result_1.json create mode 100644 VENDORS/Milesight/EM400-TLD/LORIOT/uplink/payload_2.json create mode 100644 VENDORS/Milesight/EM400-TLD/LORIOT/uplink/result_2.json create mode 100644 VENDORS/Milesight/EM400-UDL/LORIOT/uplink/payload_2.json create mode 100644 VENDORS/Milesight/EM400-UDL/LORIOT/uplink/result_2.json create mode 100644 VENDORS/Milesight/EM500-CO2/LORIOT/uplink/payload_1.json create mode 100644 VENDORS/Milesight/EM500-CO2/LORIOT/uplink/result_1.json create mode 100644 VENDORS/Milesight/GS101/LORIOT/uplink/payload_1.json create mode 100644 VENDORS/Milesight/GS101/LORIOT/uplink/result_1.json create mode 100644 VENDORS/Milesight/GS301/LORIOT/uplink/payload_1.json create mode 100644 VENDORS/Milesight/GS301/LORIOT/uplink/result_1.json create mode 100644 VENDORS/Milesight/TS101/LORIOT/uplink/payload_2.json create mode 100644 VENDORS/Milesight/TS101/LORIOT/uplink/result_2.json create mode 100644 VENDORS/Milesight/TS201/LORIOT/uplink/payload_2.json create mode 100644 VENDORS/Milesight/TS201/LORIOT/uplink/result_2.json create mode 100644 VENDORS/Milesight/WS101/LORIOT/uplink/payload_1.json create mode 100644 VENDORS/Milesight/WS101/LORIOT/uplink/result_1.json create mode 100644 VENDORS/Milesight/WS201/LORIOT/uplink/payload_1.json create mode 100644 VENDORS/Milesight/WS201/LORIOT/uplink/result_1.json create mode 100644 VENDORS/Milesight/WS202/LORIOT/uplink/payload_1.json create mode 100644 VENDORS/Milesight/WS202/LORIOT/uplink/result_1.json create mode 100644 VENDORS/Milesight/WS301/LORIOT/uplink/payload_1.json create mode 100644 VENDORS/Milesight/WS301/LORIOT/uplink/result_1.json create mode 100644 VENDORS/Milesight/WS302/LORIOT/uplink/payload_1.json create mode 100644 VENDORS/Milesight/WS302/LORIOT/uplink/result_1.json create mode 100644 VENDORS/Milesight/WS303/LORIOT/uplink/payload_1.json create mode 100644 VENDORS/Milesight/WS303/LORIOT/uplink/result_1.json diff --git a/VENDORS/Milesight/AM102/LORIOT/uplink/converter.json b/VENDORS/Milesight/AM102/LORIOT/uplink/converter.json index 371d29e6..90cce360 100644 --- a/VENDORS/Milesight/AM102/LORIOT/uplink/converter.json +++ b/VENDORS/Milesight/AM102/LORIOT/uplink/converter.json @@ -1,11 +1,16 @@ { "name": "Uplink data converter for Loriot integration AM102", "type": "UPLINK", - "debugMode": true, + "debugMode": false, + "debugSettings": { + "failuresEnabled": true, + "allEnabled": false, + "allEnabledUntil": 1735207152023 + }, "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);\nvar deviceName = \"AM102 \" + data.EUI;\nvar deviceType = \"AM102\";\nvar groupName = null; // If groupName is not null - created device will be added to the entity group with such name.\nvar customerName = null; // If customerName is not null - created devices will be assigned to customer with such name. \n\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// If you want to parse incoming data somehow, you can add your code to this function.\n// input: bytes\n// expected output:\n// {\n// \"attributes\": {\"attributeKey\": \"attributeValue\"},\n// \"telemetry\": {\"telemetryKey\": \"telemetryValue\"}\n// }\n\nfunction decodePayload(input) {\n var output = { attributes: {}, telemetry: []};\n \n // --- Decoding code --- //\n var decoded = {};\n var historyData = {};\n for (var i = 0; i < input.length - 2; ) {\n var channel_id = input[i++] & 0xff;\n var channel_type = input[i++] & 0xff;\n // BATTERY\n if(channel_id === 0x01 && channel_type === 0x75) {\n decoded.battery = input[i]; \n i += 1;\n }\n // TEMPERATURE\n if (channel_id === 0x03 && channel_type === 0x67) {\n // ℃\n decoded.temperature = parseBytesToInt(input, i, 2, false) / 10;\n // ℉\n // decoded.temperature = parseBytesToInt(input, i, 2, false) / 10 * 1.8 + 32;\n i += 2;\n }\n // HUMIDITY\n if (channel_id === 0x04 && channel_type === 0x68) {\n decoded.humidity = parseBytesToInt(input, i, 1, false) / 2;\n i += 1;\n }\n \n // HISTORY DATA\n if (channel_id === 0x20 && channel_type === 0xce) {\n var historyData = {\n ts: parseBytesToInt(input, i, 4, false) * 1000,\n values: {\n temperature: parseBytesToInt(input, i + 4, 2, false) / 10,\n humidity: parseBytesToInt(input, i + 6, 1, false) / 2,\n }\n };\n \n i += 7;\n }\n }\n \n output.telemetry = [{\n ts: timestamp,\n values: decoded\n }, historyData];\n\n // --- Decoding code --- //\n return output;\n}\n\n// --- attributes and telemetry objects ---\nvar telemetry = [];\nvar attributes = {};\n// --- attributes and telemetry objects ---\n\n// --- Timestamp parsing\ntimestamp = data.ts;\n// --- Timestamp parsing\n\n// Message parsing\n// To avoid paths in the decoded objects we passing false value to function as \"pathInKey\" argument.\n// Warning: pathInKey can cause already found fields to be overwritten with the last value found.\n\nvar uplinkDataList = [];\n\n// Passing incoming bytes to decodePayload function, to get custom decoding\nvar customDecoding = decodePayload(hexToBytes(data.data));\n\n// Collecting data to result\nif (customDecoding.?telemetry.size() > 0) {\n if (customDecoding.telemetry instanceof java.util.ArrayList) {\n foreach(telemetryObj: customDecoding.telemetry) {\n if (telemetryObj.ts != null && telemetryObj.values != null) {\n telemetry.add(telemetryObj);\n }\n }\n } else {\n telemetry.putAll(customDecoding.telemetry);\n }\n}\n\nif (customDecoding.?attributes.size() > 0) {\n attributes.putAll(customDecoding.attributes);\n}\n\n// You can add some keys manually to attributes or telemetry\nattributes.eui = data.EUI;\nattributes.fPort = data.port;\nattributes.frequency = data.freq;\n\nvar addDataToTelemetry = {};\naddDataToTelemetry.rssi = data.rssi;\naddDataToTelemetry.seqno = data.seqno;\naddDataToTelemetry.snr = data.snr;\naddDataToTelemetry.ack = data.ack;\naddDataToTelemetry.toa = data.toa;\naddDataToTelemetry.fCnt = data.fcnt;\n\nvar isIncludeGatewayInfo = metadata[\"includeGatewayInfo\"];\nif(isIncludeGatewayInfo == true) {\n telemetry = processTelemetryData(telemetry, addDataToTelemetry);\n}\n\nvar deviceInfo = {\n deviceName: deviceName,\n deviceType: deviceType,\n// assetName: assetName,\n// assetType: assetType,\n attributes: attributes,\n telemetry: telemetry, \n};\n\naddAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName);\n\nuplinkDataList.add(deviceInfo);\n\nvar includeGatewayInfo = [\"ts\", \"gweui\", \"rssi\"];\n\nvar gatewayDeviceNamePrefix = \"Gateway \";\nvar gatewayDeviceType = \"Lora gateway\";\nvar gatewayGroupName = null; // If gatewayGroupName is not null - created device will be added to the entity group with such name.\n\nif (data.cmd == \"gw\") {\n foreach( gatewayInfo : data.gws ) {\n var gatewayInfoMsg = {\n deviceName: gatewayDeviceNamePrefix + gatewayInfo.gweui,\n deviceType: gatewayDeviceType,\n telemetry: [{\n \"ts\": parseDateToTimestamp(gatewayInfo.ts),\n \"values\": getDataList(gatewayInfo, includeGatewayInfo)\n }],\n attributes: {\n eui: gatewayInfo.gweui\n }\n };\n addAdditionalInfoForDeviceMsg(gatewayInfoMsg, customerName, gatewayGroupName);\n uplinkDataList.add(gatewayInfoMsg);\n }\n}\n\nreturn uplinkDataList;\n\nfunction addAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName) {\n if (customerName != null) {\n deviceInfo.customerName = customerName;\n }\n if (groupName != null) {\n deviceInfo.groupName = groupName;\n }\n}\n\nfunction parseDateToTimestamp(dateString) {\n var timestamp = -1;\n if (dateString != null) {\n \n timestamp = new Date(dateString).getTime();\n if (timestamp == -1) {\n var secondsSeparatorIndex = dateString.lastIndexOf('.') + 1;\n var millisecondsEndIndex = dateString.lastIndexOf('+');\n if (millisecondsEndIndex == -1) {\n millisecondsEndIndex = dateString.lastIndexOf('Z');\n }\n if (millisecondsEndIndex == -1) {\n millisecondsEndIndex = dateString.lastIndexOf('-');\n }\n if (millisecondsEndIndex == -1) {\n if (dateString.length >= secondsSeparatorIndex + 3) {\n dateString = dateString.substring(0, secondsSeparatorIndex + 3);\n }\n } else {\n dateString = dateString.substring(0, secondsSeparatorIndex + 3) +\n dateString.substring(millisecondsEndIndex, dateString.length);\n }\n \n timestamp = new Date(dateString).getTime();\n }\n }\n // If we cannot parse timestamp - we will use the current timestamp\n if (timestamp == -1) {\n timestamp = Date.now();\n }\n \n return timestamp;\n}\n\nfunction processTelemetryData(telemetry, addDataToTelemetry) {\n if (telemetry.size > 1) {\n telemetry = addDataToMultipleTelemetries(telemetry, addDataToTelemetry);\n }\n else if (telemetry.size == 1) {\n telemetry = addDataToSingleTelemetry(telemetry, addDataToTelemetry);\n }\n else {\n telemetry.add(addDataToTelemetry);\n }\n \n return telemetry;\n}\n\nfunction addDataToMultipleTelemetries(telemetry, addDataToTelemetry) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[0][\"values\"].keys.contains(element.key)) {\n telemetry[0][\"values\"][element.key] = element.value;\n }\n if (!telemetry[1][\"values\"].keys.contains(element.key)) {\n telemetry[1][\"values\"][element.key] = element.value;\n }\n }\n \n return telemetry;\n}\n\nfunction addDataToSingleTelemetry(telemetry, addDataToTelemetry) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[0][\"values\"].keys.contains(element.key)) {\n telemetry[0][\"values\"][element.key] = element.value;\n }\n }\n \n return telemetry;\n}", + "tbelDecoder": "var data = decodeToJson(payload);\nvar deviceName = \"AM102 \" + data.EUI;\nvar deviceType = \"AM102\";\nvar groupName = null; // If groupName is not null - created device will be added to the entity group with such name.\nvar customerName = null; // If customerName is not null - created devices will be assigned to customer with such name. \n\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// If you want to parse incoming data somehow, you can add your code to this function.\n// input: bytes\n// expected output:\n// {\n// \"attributes\": {\"attributeKey\": \"attributeValue\"},\n// \"telemetry\": {\"telemetryKey\": \"telemetryValue\"}\n// }\n\nfunction decodePayload(input) {\n var output = { attributes: {}, telemetry: []};\n \n // --- Decoding code --- //\n var decoded = {};\n var historyData = {};\n for (var i = 0; i < input.length - 2; ) {\n var channel_id = input[i++] & 0xff;\n var channel_type = input[i++] & 0xff;\n // BATTERY\n if(channel_id === 0x01 && channel_type === 0x75) {\n decoded.battery = input[i]; \n i += 1;\n }\n // TEMPERATURE\n if (channel_id === 0x03 && channel_type === 0x67) {\n // ℃\n decoded.temperature = parseBytesToInt(input, i, 2, false) / 10;\n // ℉\n // decoded.temperature = parseBytesToInt(input, i, 2, false) / 10 * 1.8 + 32;\n i += 2;\n }\n // HUMIDITY\n if (channel_id === 0x04 && channel_type === 0x68) {\n decoded.humidity = parseBytesToInt(input, i, 1, false) / 2;\n i += 1;\n }\n \n // HISTORY DATA\n if (channel_id === 0x20 && channel_type === 0xce) {\n var historyData = {\n ts: parseBytesToInt(input, i, 4, false) * 1000,\n values: {\n temperature: parseBytesToInt(input, i + 4, 2, false) / 10,\n humidity: parseBytesToInt(input, i + 6, 1, false) / 2,\n }\n };\n \n i += 7;\n }\n }\n \n output.telemetry = [{\n ts: timestamp,\n values: decoded\n }, historyData];\n\n // --- Decoding code --- //\n return output;\n}\n\n// --- attributes and telemetry objects ---\nvar telemetry = [];\nvar attributes = {};\n// --- attributes and telemetry objects ---\n\n// --- Timestamp parsing\ntimestamp = data.ts;\n// --- Timestamp parsing\n\n// Message parsing\n// To avoid paths in the decoded objects we passing false value to function as \"pathInKey\" argument.\n// Warning: pathInKey can cause already found fields to be overwritten with the last value found.\n\nvar uplinkDataList = [];\n\n// Passing incoming bytes to decodePayload function, to get custom decoding\nvar customDecoding = decodePayload(hexToBytes(data.data));\n\n// Collecting data to result\nif (customDecoding.?telemetry.size() > 0) {\n if (customDecoding.telemetry instanceof java.util.ArrayList) {\n foreach(telemetryObj: customDecoding.telemetry) {\n if (telemetryObj.ts != null && telemetryObj.values != null) {\n telemetry.add(telemetryObj);\n }\n }\n } else {\n telemetry.putAll(customDecoding.telemetry);\n }\n}\n\nif (customDecoding.?attributes.size() > 0) {\n attributes.putAll(customDecoding.attributes);\n}\n\n// You can add some keys manually to attributes or telemetry\nattributes.eui = data.EUI;\nattributes.fPort = data.port;\nattributes.frequency = data.freq;\n\nvar addDataToTelemetry = {};\naddDataToTelemetry.rssi = data.rssi;\naddDataToTelemetry.seqno = data.seqno;\naddDataToTelemetry.snr = data.snr;\naddDataToTelemetry.ack = data.ack;\naddDataToTelemetry.toa = data.toa;\naddDataToTelemetry.fCnt = data.fcnt;\n\nvar isIncludeGatewayInfo = metadata[\"includeGatewayInfo\"];\nif(isIncludeGatewayInfo == true) {\n telemetry = processTelemetryData(telemetry, addDataToTelemetry);\n}\n\nvar deviceInfo = {\n deviceName: deviceName,\n deviceType: deviceType,\n// assetName: assetName,\n// assetType: assetType,\n attributes: attributes,\n telemetry: telemetry, \n};\n\naddAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName);\n\nuplinkDataList.add(deviceInfo);\n\nvar gatewayDeviceNamePrefix = \"Gateway \";\nvar gatewayDeviceType = \"Lora gateway\";\nvar gatewayGroupName = null; // If gatewayGroupName is not null - created device will be added to the entity group with such name.\n\nif (data.cmd == \"gw\") {\n foreach( gatewayInfo : data.gws ) {\n var addGatewayInfo = {};\n\n // You can add some keys manually telemetry\n addGatewayInfo.rssi = gatewayInfo.rssi;\n addGatewayInfo.snr = gatewayInfo.snr;\n // You can add some keys manually telemetry\n \n var gatewayInfoMsg = {\n deviceName: gatewayDeviceNamePrefix + gatewayInfo.gweui,\n deviceType: gatewayDeviceType,\n telemetry: [{\n \"ts\": gatewayInfo.ts,\n \"values\": addGatewayInfo\n }],\n attributes: {\n eui: gatewayInfo.gweui\n }\n };\n addAdditionalInfoForDeviceMsg(gatewayInfoMsg, customerName, gatewayGroupName);\n uplinkDataList.add(gatewayInfoMsg);\n }\n}\n\nreturn uplinkDataList;\n\nfunction addAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName) {\n if (customerName != null) {\n deviceInfo.customerName = customerName;\n }\n if (groupName != null) {\n deviceInfo.groupName = groupName;\n }\n}\n\nfunction parseDateToTimestamp(dateString) {\n var timestamp = -1;\n if (dateString != null) {\n \n timestamp = new Date(dateString).getTime();\n if (timestamp == -1) {\n var secondsSeparatorIndex = dateString.lastIndexOf('.') + 1;\n var millisecondsEndIndex = dateString.lastIndexOf('+');\n if (millisecondsEndIndex == -1) {\n millisecondsEndIndex = dateString.lastIndexOf('Z');\n }\n if (millisecondsEndIndex == -1) {\n millisecondsEndIndex = dateString.lastIndexOf('-');\n }\n if (millisecondsEndIndex == -1) {\n if (dateString.length >= secondsSeparatorIndex + 3) {\n dateString = dateString.substring(0, secondsSeparatorIndex + 3);\n }\n } else {\n dateString = dateString.substring(0, secondsSeparatorIndex + 3) +\n dateString.substring(millisecondsEndIndex, dateString.length);\n }\n \n timestamp = new Date(dateString).getTime();\n }\n }\n // If we cannot parse timestamp - we will use the current timestamp\n if (timestamp == -1) {\n timestamp = Date.now();\n }\n \n return timestamp;\n}\n\nfunction processTelemetryData(telemetry, addDataToTelemetry) {\n if (telemetry.size > 1) {\n telemetry = addDataToMultipleTelemetries(telemetry, addDataToTelemetry);\n }\n else if (telemetry.size == 1) {\n telemetry = addDataToSingleTelemetry(telemetry, addDataToTelemetry);\n }\n else {\n telemetry.add(addDataToTelemetry);\n }\n \n return telemetry;\n}\n\nfunction addDataToMultipleTelemetries(telemetry, addDataToTelemetry) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[0][\"values\"].keys.contains(element.key)) {\n telemetry[0][\"values\"][element.key] = element.value;\n }\n if (!telemetry[1][\"values\"].keys.contains(element.key)) {\n telemetry[1][\"values\"][element.key] = element.value;\n }\n }\n \n return telemetry;\n}\n\nfunction addDataToSingleTelemetry(telemetry, addDataToTelemetry) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[0][\"values\"].keys.contains(element.key)) {\n telemetry[0][\"values\"][element.key] = element.value;\n }\n }\n \n return telemetry;\n}", "encoder": null, "tbelEncoder": null, "updateOnlyKeys": [ diff --git a/VENDORS/Milesight/AM102/LORIOT/uplink/payload_2.json b/VENDORS/Milesight/AM102/LORIOT/uplink/payload_2.json new file mode 100644 index 00000000..c34d2110 --- /dev/null +++ b/VENDORS/Milesight/AM102/LORIOT/uplink/payload_2.json @@ -0,0 +1,32 @@ +{ + "cmd": "gw", + "seqno": 4, + "EUI": "0102030405060708", + "ts": 1690901260493, + "fcnt": 3, + "port": 207, + "freq": 868300000, + "toa": 1319, + "dr": "SF12 BW125 4/5", + "ack": false, + "gws": [ + { + "rssi": -38, + "snr": 8.5, + "ts": 1690901260493, + "time": "2023-08-01T14:47:40.493Z", + "gweui": "1020304080706050", + "ant": 0 + }, + { + "rssi": -42, + "snr": 8.8, + "ts": 1690901260495, + "time": "2023-08-01T14:47:40.495Z", + "gweui": "1020304081716151", + "ant": 0 + } + ], + "bat": 143, + "data": "0175640367180104686D" +} diff --git a/VENDORS/Milesight/AM102/LORIOT/uplink/result_3.json b/VENDORS/Milesight/AM102/LORIOT/uplink/result_3.json new file mode 100644 index 00000000..e69de29b diff --git a/VENDORS/Milesight/AM102L/LORIOT/uplink/converter.json b/VENDORS/Milesight/AM102L/LORIOT/uplink/converter.json index 0e084f22..4b85acf1 100644 --- a/VENDORS/Milesight/AM102L/LORIOT/uplink/converter.json +++ b/VENDORS/Milesight/AM102L/LORIOT/uplink/converter.json @@ -1,11 +1,16 @@ { "name": "Uplink data converter for Loriot integration AM102L", "type": "UPLINK", - "debugMode": true, + "debugMode": false, + "debugSettings": { + "failuresEnabled": true, + "allEnabled": false, + "allEnabledUntil": 1735207408456 + }, "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);\nvar deviceName = \"AM102L \" + data.EUI;\nvar deviceType = \"AM102L\";\nvar groupName = null; // If groupName is not null - created device will be added to the entity group with such name.\nvar customerName = null; // If customerName is not null - created devices will be assigned to customer with such name. \n\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// If you want to parse incoming data somehow, you can add your code to this function.\n// input: bytes\n// expected output:\n// {\n// \"attributes\": {\"attributeKey\": \"attributeValue\"},\n// \"telemetry\": {\"telemetryKey\": \"telemetryValue\"}\n// }\n\nfunction decodePayload(input) {\n var output = { attributes: {}, telemetry: []};\n \n // --- Decoding code --- //\n var decoded = {};\n var historyData = {};\n for (var i = 0; i < input.length - 2; ) {\n var channel_id = input[i++] & 0xff;\n var channel_type = input[i++] & 0xff;\n // BATTERY\n if(channel_id === 0x01 && channel_type === 0x75) {\n decoded.battery = input[i]; \n i += 1;\n }\n // TEMPERATURE\n if (channel_id === 0x03 && channel_type === 0x67) {\n // ℃\n decoded.temperature = parseBytesToInt(input, i, 2, false) / 10;\n // ℉\n // decoded.temperature = parseBytesToInt(input, i, 2, false) / 10 * 1.8 + 32;\n i += 2;\n }\n // HUMIDITY\n if (channel_id === 0x04 && channel_type === 0x68) {\n decoded.humidity = parseBytesToInt(input, i, 1, false) / 2;\n i += 1;\n }\n \n // HISTORY DATA\n if (channel_id === 0x20 && channel_type === 0xce) {\n var historyData = {\n ts: parseBytesToInt(input, i, 4, false) * 1000,\n values: {\n temperature: parseBytesToInt(input, i + 4, 2, false) / 10,\n humidity: parseBytesToInt(input, i + 6, 1, false) / 2,\n }\n };\n \n i += 7;\n }\n }\n \n output.telemetry = [{\n ts: timestamp,\n values: decoded\n }, historyData];\n\n // --- Decoding code --- //\n return output;\n}\n\n// --- attributes and telemetry objects ---\nvar telemetry = [];\nvar attributes = {};\n// --- attributes and telemetry objects ---\n\n// --- Timestamp parsing\ntimestamp = data.ts;\n// --- Timestamp parsing\n\n// Message parsing\n// To avoid paths in the decoded objects we passing false value to function as \"pathInKey\" argument.\n// Warning: pathInKey can cause already found fields to be overwritten with the last value found.\n\nvar uplinkDataList = [];\n\n// Passing incoming bytes to decodePayload function, to get custom decoding\nvar customDecoding = decodePayload(hexToBytes(data.data));\n\n// Collecting data to result\nif (customDecoding.?telemetry.size() > 0) {\n if (customDecoding.telemetry instanceof java.util.ArrayList) {\n foreach(telemetryObj: customDecoding.telemetry) {\n if (telemetryObj.ts != null && telemetryObj.values != null) {\n telemetry.add(telemetryObj);\n }\n }\n } else {\n telemetry.putAll(customDecoding.telemetry);\n }\n}\n\nif (customDecoding.?attributes.size() > 0) {\n attributes.putAll(customDecoding.attributes);\n}\n\n// You can add some keys manually to attributes or telemetry\nattributes.eui = data.EUI;\nattributes.fPort = data.port;\nattributes.frequency = data.freq;\n\nvar addDataToTelemetry = {};\naddDataToTelemetry.rssi = data.rssi;\naddDataToTelemetry.seqno = data.seqno;\naddDataToTelemetry.snr = data.snr;\naddDataToTelemetry.ack = data.ack;\naddDataToTelemetry.toa = data.toa;\naddDataToTelemetry.fCnt = data.fcnt;\n\nvar isIncludeGatewayInfo = metadata[\"includeGatewayInfo\"];\nif(isIncludeGatewayInfo == true) {\n telemetry = processTelemetryData(telemetry, addDataToTelemetry);\n}\n\nvar deviceInfo = {\n deviceName: deviceName,\n deviceType: deviceType,\n// assetName: assetName,\n// assetType: assetType,\n attributes: attributes,\n telemetry: telemetry, \n};\n\naddAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName);\n\nuplinkDataList.add(deviceInfo);\n\nvar includeGatewayInfo = [\"ts\", \"gweui\", \"rssi\"];\n\nvar gatewayDeviceNamePrefix = \"Gateway \";\nvar gatewayDeviceType = \"Lora gateway\";\nvar gatewayGroupName = null; // If gatewayGroupName is not null - created device will be added to the entity group with such name.\n\nif (data.cmd == \"gw\") {\n foreach( gatewayInfo : data.gws ) {\n var gatewayInfoMsg = {\n deviceName: gatewayDeviceNamePrefix + gatewayInfo.gweui,\n deviceType: gatewayDeviceType,\n telemetry: [{\n \"ts\": parseDateToTimestamp(gatewayInfo.ts),\n \"values\": getDataList(gatewayInfo, includeGatewayInfo)\n }],\n attributes: {\n eui: gatewayInfo.gweui\n }\n };\n addAdditionalInfoForDeviceMsg(gatewayInfoMsg, customerName, gatewayGroupName);\n uplinkDataList.add(gatewayInfoMsg);\n }\n}\n\nreturn uplinkDataList;\n\nfunction addAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName) {\n if (customerName != null) {\n deviceInfo.customerName = customerName;\n }\n if (groupName != null) {\n deviceInfo.groupName = groupName;\n }\n}\n\nfunction parseDateToTimestamp(dateString) {\n var timestamp = -1;\n if (dateString != null) {\n \n timestamp = new Date(dateString).getTime();\n if (timestamp == -1) {\n var secondsSeparatorIndex = dateString.lastIndexOf('.') + 1;\n var millisecondsEndIndex = dateString.lastIndexOf('+');\n if (millisecondsEndIndex == -1) {\n millisecondsEndIndex = dateString.lastIndexOf('Z');\n }\n if (millisecondsEndIndex == -1) {\n millisecondsEndIndex = dateString.lastIndexOf('-');\n }\n if (millisecondsEndIndex == -1) {\n if (dateString.length >= secondsSeparatorIndex + 3) {\n dateString = dateString.substring(0, secondsSeparatorIndex + 3);\n }\n } else {\n dateString = dateString.substring(0, secondsSeparatorIndex + 3) +\n dateString.substring(millisecondsEndIndex, dateString.length);\n }\n \n timestamp = new Date(dateString).getTime();\n }\n }\n // If we cannot parse timestamp - we will use the current timestamp\n if (timestamp == -1) {\n timestamp = Date.now();\n }\n \n return timestamp;\n}\n\nfunction processTelemetryData(telemetry, addDataToTelemetry) {\n if (telemetry.size > 1) {\n telemetry = addDataToMultipleTelemetries(telemetry, addDataToTelemetry);\n }\n else if (telemetry.size == 1) {\n telemetry = addDataToSingleTelemetry(telemetry, addDataToTelemetry);\n }\n else {\n telemetry.add(addDataToTelemetry);\n }\n \n return telemetry;\n}\n\nfunction addDataToMultipleTelemetries(telemetry, addDataToTelemetry) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[0][\"values\"].keys.contains(element.key)) {\n telemetry[0][\"values\"][element.key] = element.value;\n }\n if (!telemetry[1][\"values\"].keys.contains(element.key)) {\n telemetry[1][\"values\"][element.key] = element.value;\n }\n }\n \n return telemetry;\n}\n\nfunction addDataToSingleTelemetry(telemetry, addDataToTelemetry) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[0][\"values\"].keys.contains(element.key)) {\n telemetry[0][\"values\"][element.key] = element.value;\n }\n }\n \n return telemetry;\n}", + "tbelDecoder": "var data = decodeToJson(payload);\nvar deviceName = \"AM102L \" + data.EUI;\nvar deviceType = \"AM102L\";\nvar groupName = null; // If groupName is not null - created device will be added to the entity group with such name.\nvar customerName = null; // If customerName is not null - created devices will be assigned to customer with such name. \n\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// If you want to parse incoming data somehow, you can add your code to this function.\n// input: bytes\n// expected output:\n// {\n// \"attributes\": {\"attributeKey\": \"attributeValue\"},\n// \"telemetry\": {\"telemetryKey\": \"telemetryValue\"}\n// }\n\nfunction decodePayload(input) {\n var output = { attributes: {}, telemetry: []};\n \n // --- Decoding code --- //\n var decoded = {};\n var historyData = {};\n for (var i = 0; i < input.length - 2; ) {\n var channel_id = input[i++] & 0xff;\n var channel_type = input[i++] & 0xff;\n // BATTERY\n if(channel_id === 0x01 && channel_type === 0x75) {\n decoded.battery = input[i]; \n i += 1;\n }\n // TEMPERATURE\n if (channel_id === 0x03 && channel_type === 0x67) {\n // ℃\n decoded.temperature = parseBytesToInt(input, i, 2, false) / 10;\n // ℉\n // decoded.temperature = parseBytesToInt(input, i, 2, false) / 10 * 1.8 + 32;\n i += 2;\n }\n // HUMIDITY\n if (channel_id === 0x04 && channel_type === 0x68) {\n decoded.humidity = parseBytesToInt(input, i, 1, false) / 2;\n i += 1;\n }\n \n // HISTORY DATA\n if (channel_id === 0x20 && channel_type === 0xce) {\n var historyData = {\n ts: parseBytesToInt(input, i, 4, false) * 1000,\n values: {\n temperature: parseBytesToInt(input, i + 4, 2, false) / 10,\n humidity: parseBytesToInt(input, i + 6, 1, false) / 2,\n }\n };\n \n i += 7;\n }\n }\n \n output.telemetry = [{\n ts: timestamp,\n values: decoded\n }, historyData];\n\n // --- Decoding code --- //\n return output;\n}\n\n// --- attributes and telemetry objects ---\nvar telemetry = [];\nvar attributes = {};\n// --- attributes and telemetry objects ---\n\n// --- Timestamp parsing\ntimestamp = data.ts;\n// --- Timestamp parsing\n\n// Message parsing\n// To avoid paths in the decoded objects we passing false value to function as \"pathInKey\" argument.\n// Warning: pathInKey can cause already found fields to be overwritten with the last value found.\n\nvar uplinkDataList = [];\n\n// Passing incoming bytes to decodePayload function, to get custom decoding\nvar customDecoding = decodePayload(hexToBytes(data.data));\n\n// Collecting data to result\nif (customDecoding.?telemetry.size() > 0) {\n if (customDecoding.telemetry instanceof java.util.ArrayList) {\n foreach(telemetryObj: customDecoding.telemetry) {\n if (telemetryObj.ts != null && telemetryObj.values != null) {\n telemetry.add(telemetryObj);\n }\n }\n } else {\n telemetry.putAll(customDecoding.telemetry);\n }\n}\n\nif (customDecoding.?attributes.size() > 0) {\n attributes.putAll(customDecoding.attributes);\n}\n\n// You can add some keys manually to attributes or telemetry\nattributes.eui = data.EUI;\nattributes.fPort = data.port;\nattributes.frequency = data.freq;\n\nvar addDataToTelemetry = {};\naddDataToTelemetry.rssi = data.rssi;\naddDataToTelemetry.seqno = data.seqno;\naddDataToTelemetry.snr = data.snr;\naddDataToTelemetry.ack = data.ack;\naddDataToTelemetry.toa = data.toa;\naddDataToTelemetry.fCnt = data.fcnt;\n\nvar isIncludeGatewayInfo = metadata[\"includeGatewayInfo\"];\nif(isIncludeGatewayInfo == true) {\n telemetry = processTelemetryData(telemetry, addDataToTelemetry);\n}\n\nvar deviceInfo = {\n deviceName: deviceName,\n deviceType: deviceType,\n// assetName: assetName,\n// assetType: assetType,\n attributes: attributes,\n telemetry: telemetry, \n};\n\naddAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName);\n\nuplinkDataList.add(deviceInfo);\n\nvar gatewayDeviceNamePrefix = \"Gateway \";\nvar gatewayDeviceType = \"Lora gateway\";\nvar gatewayGroupName = null; // If gatewayGroupName is not null - created device will be added to the entity group with such name.\n\nif (data.cmd == \"gw\") {\n foreach( gatewayInfo : data.gws ) {\n var addGatewayInfo = {};\n\n // You can add some keys manually telemetry\n addGatewayInfo.rssi = gatewayInfo.rssi;\n addGatewayInfo.snr = gatewayInfo.snr;\n // You can add some keys manually telemetry\n \n var gatewayInfoMsg = {\n deviceName: gatewayDeviceNamePrefix + gatewayInfo.gweui,\n deviceType: gatewayDeviceType,\n telemetry: [{\n \"ts\": gatewayInfo.ts,\n \"values\": addGatewayInfo\n }],\n attributes: {\n eui: gatewayInfo.gweui\n }\n };\n addAdditionalInfoForDeviceMsg(gatewayInfoMsg, customerName, gatewayGroupName);\n uplinkDataList.add(gatewayInfoMsg);\n }\n}\n\nreturn uplinkDataList;\n\nfunction addAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName) {\n if (customerName != null) {\n deviceInfo.customerName = customerName;\n }\n if (groupName != null) {\n deviceInfo.groupName = groupName;\n }\n}\n\nfunction parseDateToTimestamp(dateString) {\n var timestamp = -1;\n if (dateString != null) {\n \n timestamp = new Date(dateString).getTime();\n if (timestamp == -1) {\n var secondsSeparatorIndex = dateString.lastIndexOf('.') + 1;\n var millisecondsEndIndex = dateString.lastIndexOf('+');\n if (millisecondsEndIndex == -1) {\n millisecondsEndIndex = dateString.lastIndexOf('Z');\n }\n if (millisecondsEndIndex == -1) {\n millisecondsEndIndex = dateString.lastIndexOf('-');\n }\n if (millisecondsEndIndex == -1) {\n if (dateString.length >= secondsSeparatorIndex + 3) {\n dateString = dateString.substring(0, secondsSeparatorIndex + 3);\n }\n } else {\n dateString = dateString.substring(0, secondsSeparatorIndex + 3) +\n dateString.substring(millisecondsEndIndex, dateString.length);\n }\n \n timestamp = new Date(dateString).getTime();\n }\n }\n // If we cannot parse timestamp - we will use the current timestamp\n if (timestamp == -1) {\n timestamp = Date.now();\n }\n \n return timestamp;\n}\n\nfunction processTelemetryData(telemetry, addDataToTelemetry) {\n if (telemetry.size > 1) {\n telemetry = addDataToMultipleTelemetries(telemetry, addDataToTelemetry);\n }\n else if (telemetry.size == 1) {\n telemetry = addDataToSingleTelemetry(telemetry, addDataToTelemetry);\n }\n else {\n telemetry.add(addDataToTelemetry);\n }\n \n return telemetry;\n}\n\nfunction addDataToMultipleTelemetries(telemetry, addDataToTelemetry) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[0][\"values\"].keys.contains(element.key)) {\n telemetry[0][\"values\"][element.key] = element.value;\n }\n if (!telemetry[1][\"values\"].keys.contains(element.key)) {\n telemetry[1][\"values\"][element.key] = element.value;\n }\n }\n \n return telemetry;\n}\n\nfunction addDataToSingleTelemetry(telemetry, addDataToTelemetry) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[0][\"values\"].keys.contains(element.key)) {\n telemetry[0][\"values\"][element.key] = element.value;\n }\n }\n \n return telemetry;\n}", "encoder": null, "tbelEncoder": null, "updateOnlyKeys": [ diff --git a/VENDORS/Milesight/AM102L/LORIOT/uplink/payload_2.json b/VENDORS/Milesight/AM102L/LORIOT/uplink/payload_2.json new file mode 100644 index 00000000..f2493a25 --- /dev/null +++ b/VENDORS/Milesight/AM102L/LORIOT/uplink/payload_2.json @@ -0,0 +1,32 @@ +{ + "cmd": "gw", + "seqno": 4, + "EUI": "0102030405060708", + "ts": 1690901260493, + "fcnt": 3, + "port": 207, + "freq": 868300000, + "toa": 1319, + "dr": "SF12 BW125 4/5", + "ack": false, + "gws": [ + { + "rssi": -38, + "snr": 8.5, + "ts": 1690901260493, + "time": "2023-08-01T14:47:40.493Z", + "gweui": "1020304080706050", + "ant": 0 + }, + { + "rssi": -42, + "snr": 8.8, + "ts": 1690901260495, + "time": "2023-08-01T14:47:40.495Z", + "gweui": "1020304081716151", + "ant": 0 + } + ], + "bat": 143, + "data": "0175640367180104686D" +} \ No newline at end of file diff --git a/VENDORS/Milesight/AM102L/LORIOT/uplink/result_2.json b/VENDORS/Milesight/AM102L/LORIOT/uplink/result_2.json new file mode 100644 index 00000000..f6f029e6 --- /dev/null +++ b/VENDORS/Milesight/AM102L/LORIOT/uplink/result_2.json @@ -0,0 +1,43 @@ +[{ + "deviceName": "AM102L 0102030405060708", + "deviceType": "AM102L", + "attributes": { + "eui": "0102030405060708", + "fPort": 207, + "frequency": 868300000 + }, + "telemetry": [{ + "ts": 1690901260493, + "values": { + "battery": 100, + "temperature": 28.0, + "humidity": 54.5 + } + }] +}, { + "deviceName": "Gateway 1020304080706050", + "deviceType": "Lora gateway", + "telemetry": [{ + "ts": 1690901260493, + "values": { + "rssi": -38, + "snr": 8.5 + } + }], + "attributes": { + "eui": "1020304080706050" + } +}, { + "deviceName": "Gateway 1020304081716151", + "deviceType": "Lora gateway", + "telemetry": [{ + "ts": 1690901260495, + "values": { + "rssi": -42, + "snr": 8.8 + } + }], + "attributes": { + "eui": "1020304081716151" + } +}] \ No newline at end of file diff --git a/VENDORS/Milesight/AM103/LORIOT/uplink/converter.json b/VENDORS/Milesight/AM103/LORIOT/uplink/converter.json index 48a16552..97747b65 100644 --- a/VENDORS/Milesight/AM103/LORIOT/uplink/converter.json +++ b/VENDORS/Milesight/AM103/LORIOT/uplink/converter.json @@ -1,11 +1,16 @@ { "name": "Uplink data converter for Loriot integration AM-103", "type": "UPLINK", - "debugMode": true, + "debugMode": false, + "debugSettings": { + "failuresEnabled": true, + "allEnabled": false, + "allEnabledUntil": 1735207546204 + }, "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);\nvar deviceName = \"AM103 \" + data.EUI;\nvar deviceType = \"AM103\";\nvar groupName = null; // If groupName is not null - created device will be added to the entity group with such name.\nvar customerName = null; // If customerName is not null - created devices will be assigned to customer with such name. \n\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// If you want to parse incoming data somehow, you can add your code to this function.\n// input: bytes\n// expected output:\n// {\n// \"attributes\": {\"attributeKey\": \"attributeValue\"},\n// \"telemetry\": {\"telemetryKey\": \"telemetryValue\"}\n// }\n\nfunction decodePayload(input) {\n var output = { attributes: {}, telemetry: []};\n \n // --- Decoding code --- //\n var decoded = {};\n var historyData = {};\n for (var i = 0; i < input.length - 2; ) {\n var channel_id = input[i++] & 0xff;\n var channel_type = input[i++] & 0xff;\n // BATTERY\n if(channel_id === 0x01 && channel_type === 0x75) {\n decoded.battery = input[i]; \n i += 1;\n }\n // TEMPERATURE\n if (channel_id === 0x03 && channel_type === 0x67) {\n // ℃\n decoded.temperature = parseBytesToInt(input, i, 2, false) / 10;\n // ℉\n // decoded.temperature = parseBytesToInt(input, i, 2, false) / 10 * 1.8 + 32;\n i += 2;\n }\n // HUMIDITY\n if (channel_id === 0x04 && channel_type === 0x68) {\n decoded.humidity = parseBytesToInt(input, i, 1, false) / 2;\n i += 1;\n }\n // CO2\n if (channel_id === 0x07 && channel_type === 0x7d) {\n decoded.co2 = parseBytesToInt(input, i, 2, false);\n i += 2;\n }\n \n // HISTORY DATA\n if (channel_id === 0x20 && channel_type === 0xce) {\n var historyData = {\n ts: parseBytesToInt(input, i, 4, false) * 1000,\n values: {\n temperature: parseBytesToInt(input, i + 4, 2, false) / 10,\n humidity: parseBytesToInt(input, i + 6, 1, false) / 2,\n co2: parseBytesToInt(input, i + 7, 2, false),\n }\n };\n \n i += 9;\n }\n }\n \n output.telemetry = [{\n ts: timestamp,\n values: decoded\n }, historyData];\n\n // --- Decoding code --- //\n return output;\n}\n\n// --- attributes and telemetry objects ---\nvar telemetry = [];\nvar attributes = {};\n// --- attributes and telemetry objects ---\n\n// --- Timestamp parsing\ntimestamp = data.ts;\n// --- Timestamp parsing\n\n// Message parsing\n// To avoid paths in the decoded objects we passing false value to function as \"pathInKey\" argument.\n// Warning: pathInKey can cause already found fields to be overwritten with the last value found.\n\nvar uplinkDataList = [];\n\n// Passing incoming bytes to decodePayload function, to get custom decoding\nvar customDecoding = decodePayload(hexToBytes(data.data));\n\n// Collecting data to result\nif (customDecoding.?telemetry.size() > 0) {\n if (customDecoding.telemetry instanceof java.util.ArrayList) {\n foreach(telemetryObj: customDecoding.telemetry) {\n if (telemetryObj.ts != null && telemetryObj.values != null) {\n telemetry.add(telemetryObj);\n }\n }\n } else {\n telemetry.putAll(customDecoding.telemetry);\n }\n}\n\nif (customDecoding.?attributes.size() > 0) {\n attributes.putAll(customDecoding.attributes);\n}\n\n// You can add some keys manually to attributes or telemetry\nattributes.eui = data.EUI;\nattributes.fPort = data.port;\nattributes.frequency = data.freq;\n\nvar addDataToTelemetry = {};\naddDataToTelemetry.rssi = data.rssi;\naddDataToTelemetry.seqno = data.seqno;\naddDataToTelemetry.snr = data.snr;\naddDataToTelemetry.ack = data.ack;\naddDataToTelemetry.toa = data.toa;\naddDataToTelemetry.fCnt = data.fcnt;\n\nvar isIncludeGatewayInfo = metadata[\"includeGatewayInfo\"];\nif(isIncludeGatewayInfo == true) {\n telemetry = processTelemetryData(telemetry, addDataToTelemetry);\n}\n\nvar deviceInfo = {\n deviceName: deviceName,\n deviceType: deviceType,\n// assetName: assetName,\n// assetType: assetType,\n attributes: attributes,\n telemetry: telemetry, \n};\n\naddAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName);\n\nuplinkDataList.add(deviceInfo);\n\nvar includeGatewayInfo = [\"ts\", \"gweui\", \"rssi\"];\n\nvar gatewayDeviceNamePrefix = \"Gateway \";\nvar gatewayDeviceType = \"Lora gateway\";\nvar gatewayGroupName = null; // If gatewayGroupName is not null - created device will be added to the entity group with such name.\n\nif (data.cmd == \"gw\") {\n foreach( gatewayInfo : data.gws ) {\n var gatewayInfoMsg = {\n deviceName: gatewayDeviceNamePrefix + gatewayInfo.gweui,\n deviceType: gatewayDeviceType,\n telemetry: [{\n \"ts\": parseDateToTimestamp(gatewayInfo.ts),\n \"values\": getDataList(gatewayInfo, includeGatewayInfo)\n }],\n attributes: {\n eui: gatewayInfo.gweui\n }\n };\n addAdditionalInfoForDeviceMsg(gatewayInfoMsg, customerName, gatewayGroupName);\n uplinkDataList.add(gatewayInfoMsg);\n }\n}\n\nreturn uplinkDataList;\n\nfunction addAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName) {\n if (customerName != null) {\n deviceInfo.customerName = customerName;\n }\n if (groupName != null) {\n deviceInfo.groupName = groupName;\n }\n}\n\nfunction parseDateToTimestamp(dateString) {\n var timestamp = -1;\n if (dateString != null) {\n \n timestamp = new Date(dateString).getTime();\n if (timestamp == -1) {\n var secondsSeparatorIndex = dateString.lastIndexOf('.') + 1;\n var millisecondsEndIndex = dateString.lastIndexOf('+');\n if (millisecondsEndIndex == -1) {\n millisecondsEndIndex = dateString.lastIndexOf('Z');\n }\n if (millisecondsEndIndex == -1) {\n millisecondsEndIndex = dateString.lastIndexOf('-');\n }\n if (millisecondsEndIndex == -1) {\n if (dateString.length >= secondsSeparatorIndex + 3) {\n dateString = dateString.substring(0, secondsSeparatorIndex + 3);\n }\n } else {\n dateString = dateString.substring(0, secondsSeparatorIndex + 3) +\n dateString.substring(millisecondsEndIndex, dateString.length);\n }\n \n timestamp = new Date(dateString).getTime();\n }\n }\n // If we cannot parse timestamp - we will use the current timestamp\n if (timestamp == -1) {\n timestamp = Date.now();\n }\n \n return timestamp;\n}\n\nfunction processTelemetryData(telemetry, addDataToTelemetry) {\n if (telemetry.size > 1) {\n telemetry = addDataToMultipleTelemetries(telemetry, addDataToTelemetry);\n }\n else if (telemetry.size == 1) {\n telemetry = addDataToSingleTelemetry(telemetry, addDataToTelemetry);\n }\n else {\n telemetry.add(addDataToTelemetry);\n }\n \n return telemetry;\n}\n\nfunction addDataToMultipleTelemetries(telemetry, addDataToTelemetry) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[0][\"values\"].keys.contains(element.key)) {\n telemetry[0][\"values\"][element.key] = element.value;\n }\n if (!telemetry[1][\"values\"].keys.contains(element.key)) {\n telemetry[1][\"values\"][element.key] = element.value;\n }\n }\n \n return telemetry;\n}\n\nfunction addDataToSingleTelemetry(telemetry, addDataToTelemetry) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[0][\"values\"].keys.contains(element.key)) {\n telemetry[0][\"values\"][element.key] = element.value;\n }\n }\n \n return telemetry;\n}", + "tbelDecoder": "var data = decodeToJson(payload);\nvar deviceName = \"AM103 \" + data.EUI;\nvar deviceType = \"AM103\";\nvar groupName = null; // If groupName is not null - created device will be added to the entity group with such name.\nvar customerName = null; // If customerName is not null - created devices will be assigned to customer with such name. \n\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// If you want to parse incoming data somehow, you can add your code to this function.\n// input: bytes\n// expected output:\n// {\n// \"attributes\": {\"attributeKey\": \"attributeValue\"},\n// \"telemetry\": {\"telemetryKey\": \"telemetryValue\"}\n// }\n\nfunction decodePayload(input) {\n var output = { attributes: {}, telemetry: []};\n \n // --- Decoding code --- //\n var decoded = {};\n var historyData = {};\n for (var i = 0; i < input.length - 2; ) {\n var channel_id = input[i++] & 0xff;\n var channel_type = input[i++] & 0xff;\n // BATTERY\n if(channel_id === 0x01 && channel_type === 0x75) {\n decoded.battery = input[i]; \n i += 1;\n }\n // TEMPERATURE\n if (channel_id === 0x03 && channel_type === 0x67) {\n // ℃\n decoded.temperature = parseBytesToInt(input, i, 2, false) / 10;\n // ℉\n // decoded.temperature = parseBytesToInt(input, i, 2, false) / 10 * 1.8 + 32;\n i += 2;\n }\n // HUMIDITY\n if (channel_id === 0x04 && channel_type === 0x68) {\n decoded.humidity = parseBytesToInt(input, i, 1, false) / 2;\n i += 1;\n }\n // CO2\n if (channel_id === 0x07 && channel_type === 0x7d) {\n decoded.co2 = parseBytesToInt(input, i, 2, false);\n i += 2;\n }\n \n // HISTORY DATA\n if (channel_id === 0x20 && channel_type === 0xce) {\n var historyData = {\n ts: parseBytesToInt(input, i, 4, false) * 1000,\n values: {\n temperature: parseBytesToInt(input, i + 4, 2, false) / 10,\n humidity: parseBytesToInt(input, i + 6, 1, false) / 2,\n co2: parseBytesToInt(input, i + 7, 2, false),\n }\n };\n \n i += 9;\n }\n }\n \n output.telemetry = [{\n ts: timestamp,\n values: decoded\n }, historyData];\n\n // --- Decoding code --- //\n return output;\n}\n\n// --- attributes and telemetry objects ---\nvar telemetry = [];\nvar attributes = {};\n// --- attributes and telemetry objects ---\n\n// --- Timestamp parsing\ntimestamp = data.ts;\n// --- Timestamp parsing\n\n// Message parsing\n// To avoid paths in the decoded objects we passing false value to function as \"pathInKey\" argument.\n// Warning: pathInKey can cause already found fields to be overwritten with the last value found.\n\nvar uplinkDataList = [];\n\n// Passing incoming bytes to decodePayload function, to get custom decoding\nvar customDecoding = decodePayload(hexToBytes(data.data));\n\n// Collecting data to result\nif (customDecoding.?telemetry.size() > 0) {\n if (customDecoding.telemetry instanceof java.util.ArrayList) {\n foreach(telemetryObj: customDecoding.telemetry) {\n if (telemetryObj.ts != null && telemetryObj.values != null) {\n telemetry.add(telemetryObj);\n }\n }\n } else {\n telemetry.putAll(customDecoding.telemetry);\n }\n}\n\nif (customDecoding.?attributes.size() > 0) {\n attributes.putAll(customDecoding.attributes);\n}\n\n// You can add some keys manually to attributes or telemetry\nattributes.eui = data.EUI;\nattributes.fPort = data.port;\nattributes.frequency = data.freq;\n\nvar addDataToTelemetry = {};\naddDataToTelemetry.rssi = data.rssi;\naddDataToTelemetry.seqno = data.seqno;\naddDataToTelemetry.snr = data.snr;\naddDataToTelemetry.ack = data.ack;\naddDataToTelemetry.toa = data.toa;\naddDataToTelemetry.fCnt = data.fcnt;\n\nvar isIncludeGatewayInfo = metadata[\"includeGatewayInfo\"];\nif(isIncludeGatewayInfo == true) {\n telemetry = processTelemetryData(telemetry, addDataToTelemetry);\n}\n\nvar deviceInfo = {\n deviceName: deviceName,\n deviceType: deviceType,\n// assetName: assetName,\n// assetType: assetType,\n attributes: attributes,\n telemetry: telemetry, \n};\n\naddAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName);\n\nuplinkDataList.add(deviceInfo);\n\nvar includeGatewayInfo = [\"ts\", \"gweui\", \"rssi\"];\n\nvar gatewayDeviceNamePrefix = \"Gateway \";\nvar gatewayDeviceType = \"Lora gateway\";\nvar gatewayGroupName = null; // If gatewayGroupName is not null - created device will be added to the entity group with such name.\n\nif (data.cmd == \"gw\") {\n foreach( gatewayInfo : data.gws ) {\n var addGatewayInfo = {};\n\n // You can add some keys manually telemetry\n addGatewayInfo.rssi = gatewayInfo.rssi;\n addGatewayInfo.snr = gatewayInfo.snr;\n // You can add some keys manually telemetry\n \n var gatewayInfoMsg = {\n deviceName: gatewayDeviceNamePrefix + gatewayInfo.gweui,\n deviceType: gatewayDeviceType,\n telemetry: [{\n \"ts\": gatewayInfo.ts,\n \"values\": addGatewayInfo\n }],\n attributes: {\n eui: gatewayInfo.gweui\n }\n };\n addAdditionalInfoForDeviceMsg(gatewayInfoMsg, customerName, gatewayGroupName);\n uplinkDataList.add(gatewayInfoMsg);\n }\n}\n\nreturn uplinkDataList;\n\nfunction addAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName) {\n if (customerName != null) {\n deviceInfo.customerName = customerName;\n }\n if (groupName != null) {\n deviceInfo.groupName = groupName;\n }\n}\n\nfunction parseDateToTimestamp(dateString) {\n var timestamp = -1;\n if (dateString != null) {\n \n timestamp = new Date(dateString).getTime();\n if (timestamp == -1) {\n var secondsSeparatorIndex = dateString.lastIndexOf('.') + 1;\n var millisecondsEndIndex = dateString.lastIndexOf('+');\n if (millisecondsEndIndex == -1) {\n millisecondsEndIndex = dateString.lastIndexOf('Z');\n }\n if (millisecondsEndIndex == -1) {\n millisecondsEndIndex = dateString.lastIndexOf('-');\n }\n if (millisecondsEndIndex == -1) {\n if (dateString.length >= secondsSeparatorIndex + 3) {\n dateString = dateString.substring(0, secondsSeparatorIndex + 3);\n }\n } else {\n dateString = dateString.substring(0, secondsSeparatorIndex + 3) +\n dateString.substring(millisecondsEndIndex, dateString.length);\n }\n \n timestamp = new Date(dateString).getTime();\n }\n }\n // If we cannot parse timestamp - we will use the current timestamp\n if (timestamp == -1) {\n timestamp = Date.now();\n }\n \n return timestamp;\n}\n\nfunction processTelemetryData(telemetry, addDataToTelemetry) {\n if (telemetry.size > 1) {\n telemetry = addDataToMultipleTelemetries(telemetry, addDataToTelemetry);\n }\n else if (telemetry.size == 1) {\n telemetry = addDataToSingleTelemetry(telemetry, addDataToTelemetry);\n }\n else {\n telemetry.add(addDataToTelemetry);\n }\n \n return telemetry;\n}\n\nfunction addDataToMultipleTelemetries(telemetry, addDataToTelemetry) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[0][\"values\"].keys.contains(element.key)) {\n telemetry[0][\"values\"][element.key] = element.value;\n }\n if (!telemetry[1][\"values\"].keys.contains(element.key)) {\n telemetry[1][\"values\"][element.key] = element.value;\n }\n }\n \n return telemetry;\n}\n\nfunction addDataToSingleTelemetry(telemetry, addDataToTelemetry) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[0][\"values\"].keys.contains(element.key)) {\n telemetry[0][\"values\"][element.key] = element.value;\n }\n }\n \n return telemetry;\n}", "encoder": null, "tbelEncoder": null, "updateOnlyKeys": [ diff --git a/VENDORS/Milesight/AM103/LORIOT/uplink/payload_2.json b/VENDORS/Milesight/AM103/LORIOT/uplink/payload_2.json new file mode 100644 index 00000000..70b4f245 --- /dev/null +++ b/VENDORS/Milesight/AM103/LORIOT/uplink/payload_2.json @@ -0,0 +1,32 @@ +{ + "cmd": "gw", + "seqno": 4, + "EUI": "0102030405060708", + "ts": 1690901260493, + "fcnt": 3, + "port": 207, + "freq": 868300000, + "toa": 1319, + "dr": "SF12 BW125 4/5", + "ack": false, + "gws": [ + { + "rssi": -38, + "snr": 8.5, + "ts": 1690901260493, + "time": "2023-08-01T14:47:40.493Z", + "gweui": "1020304080706050", + "ant": 0 + }, + { + "rssi": -42, + "snr": 8.8, + "ts": 1690901260495, + "time": "2023-08-01T14:47:40.495Z", + "gweui": "1020304081716151", + "ant": 0 + } + ], + "bat": 143, + "data": "0175640367180104686d077dc50120ce781a4165df006e9001" +} diff --git a/VENDORS/Milesight/AM103/LORIOT/uplink/result_2.json b/VENDORS/Milesight/AM103/LORIOT/uplink/result_2.json new file mode 100644 index 00000000..517aec53 --- /dev/null +++ b/VENDORS/Milesight/AM103/LORIOT/uplink/result_2.json @@ -0,0 +1,51 @@ +[{ + "deviceName": "AM103 0102030405060708", + "deviceType": "AM103", + "attributes": { + "eui": "0102030405060708", + "fPort": 207, + "frequency": 868300000 + }, + "telemetry": [{ + "ts": 1690901260493, + "values": { + "battery": 100, + "temperature": 28.0, + "humidity": 54.5, + "co2": 453 + } + }, { + "ts": 1698765432000, + "values": { + "temperature": 22.3, + "humidity": 55.0, + "co2": 400 + } + }] +}, { + "deviceName": "Gateway 1020304080706050", + "deviceType": "Lora gateway", + "telemetry": [{ + "ts": 1690901260493, + "values": { + "rssi": -38, + "snr": 8.5 + } + }], + "attributes": { + "eui": "1020304080706050" + } +}, { + "deviceName": "Gateway 1020304081716151", + "deviceType": "Lora gateway", + "telemetry": [{ + "ts": 1690901260495, + "values": { + "rssi": -42, + "snr": 8.8 + } + }], + "attributes": { + "eui": "1020304081716151" + } +}] \ No newline at end of file diff --git a/VENDORS/Milesight/AM103L/LORIOT/uplink/converter.json b/VENDORS/Milesight/AM103L/LORIOT/uplink/converter.json index 77e3f11b..916a1344 100644 --- a/VENDORS/Milesight/AM103L/LORIOT/uplink/converter.json +++ b/VENDORS/Milesight/AM103L/LORIOT/uplink/converter.json @@ -1,11 +1,16 @@ { "name": "Uplink data converter for Loriot integration AM-103L", "type": "UPLINK", - "debugMode": true, + "debugMode": false, + "debugSettings": { + "failuresEnabled": true, + "allEnabled": false, + "allEnabledUntil": 1735207669353 + }, "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);\nvar deviceName = \"AM103L \" + data.EUI;\nvar deviceType = \"AM103L\";\nvar groupName = null; // If groupName is not null - created device will be added to the entity group with such name.\nvar customerName = null; // If customerName is not null - created devices will be assigned to customer with such name. \n\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// If you want to parse incoming data somehow, you can add your code to this function.\n// input: bytes\n// expected output:\n// {\n// \"attributes\": {\"attributeKey\": \"attributeValue\"},\n// \"telemetry\": {\"telemetryKey\": \"telemetryValue\"}\n// }\n\nfunction decodePayload(input) {\n var output = { attributes: {}, telemetry: []};\n \n // --- Decoding code --- //\n var decoded = {};\n var historyData = {};\n for (var i = 0; i < input.length - 2; ) {\n var channel_id = input[i++] & 0xff;\n var channel_type = input[i++] & 0xff;\n // BATTERY\n if(channel_id === 0x01 && channel_type === 0x75) {\n decoded.battery = input[i]; \n i += 1;\n }\n // TEMPERATURE\n if (channel_id === 0x03 && channel_type === 0x67) {\n // ℃\n decoded.temperature = parseBytesToInt(input, i, 2, false) / 10;\n // ℉\n // decoded.temperature = parseBytesToInt(input, i, 2, false) / 10 * 1.8 + 32;\n i += 2;\n }\n // HUMIDITY\n if (channel_id === 0x04 && channel_type === 0x68) {\n decoded.humidity = parseBytesToInt(input, i, 1, false) / 2;\n i += 1;\n }\n // CO2\n if (channel_id === 0x07 && channel_type === 0x7d) {\n decoded.co2 = parseBytesToInt(input, i, 2, false);\n i += 2;\n }\n \n // HISTORY DATA\n if (channel_id === 0x20 && channel_type === 0xce) {\n var historyData = {\n ts: parseBytesToInt(input, i, 4, false) * 1000,\n values: {\n temperature: parseBytesToInt(input, i + 4, 2, false) / 10,\n humidity: parseBytesToInt(input, i + 6, 1, false) / 2,\n co2: parseBytesToInt(input, i + 7, 2, false),\n }\n };\n \n i += 9;\n }\n }\n \n output.telemetry = [{\n ts: timestamp,\n values: decoded\n }, historyData];\n\n // --- Decoding code --- //\n return output;\n}\n\n// --- attributes and telemetry objects ---\nvar telemetry = [];\nvar attributes = {};\n// --- attributes and telemetry objects ---\n\n// --- Timestamp parsing\ntimestamp = data.ts;\n// --- Timestamp parsing\n\n// Message parsing\n// To avoid paths in the decoded objects we passing false value to function as \"pathInKey\" argument.\n// Warning: pathInKey can cause already found fields to be overwritten with the last value found.\n\nvar uplinkDataList = [];\n\n// Passing incoming bytes to decodePayload function, to get custom decoding\nvar customDecoding = decodePayload(hexToBytes(data.data));\n\n// Collecting data to result\nif (customDecoding.?telemetry.size() > 0) {\n if (customDecoding.telemetry instanceof java.util.ArrayList) {\n foreach(telemetryObj: customDecoding.telemetry) {\n if (telemetryObj.ts != null && telemetryObj.values != null) {\n telemetry.add(telemetryObj);\n }\n }\n } else {\n telemetry.putAll(customDecoding.telemetry);\n }\n}\n\nif (customDecoding.?attributes.size() > 0) {\n attributes.putAll(customDecoding.attributes);\n}\n\n// You can add some keys manually to attributes or telemetry\nattributes.eui = data.EUI;\nattributes.fPort = data.port;\nattributes.frequency = data.freq;\n\nvar addDataToTelemetry = {};\naddDataToTelemetry.rssi = data.rssi;\naddDataToTelemetry.seqno = data.seqno;\naddDataToTelemetry.snr = data.snr;\naddDataToTelemetry.ack = data.ack;\naddDataToTelemetry.toa = data.toa;\naddDataToTelemetry.fCnt = data.fcnt;\n\nvar isIncludeGatewayInfo = metadata[\"includeGatewayInfo\"];\nif(isIncludeGatewayInfo == true) {\n telemetry = processTelemetryData(telemetry, addDataToTelemetry);\n}\n\nvar deviceInfo = {\n deviceName: deviceName,\n deviceType: deviceType,\n// assetName: assetName,\n// assetType: assetType,\n attributes: attributes,\n telemetry: telemetry, \n};\n\naddAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName);\n\nuplinkDataList.add(deviceInfo);\n\nvar includeGatewayInfo = [\"ts\", \"gweui\", \"rssi\"];\n\nvar gatewayDeviceNamePrefix = \"Gateway \";\nvar gatewayDeviceType = \"Lora gateway\";\nvar gatewayGroupName = null; // If gatewayGroupName is not null - created device will be added to the entity group with such name.\n\nif (data.cmd == \"gw\") {\n foreach( gatewayInfo : data.gws ) {\n var gatewayInfoMsg = {\n deviceName: gatewayDeviceNamePrefix + gatewayInfo.gweui,\n deviceType: gatewayDeviceType,\n telemetry: [{\n \"ts\": parseDateToTimestamp(gatewayInfo.ts),\n \"values\": getDataList(gatewayInfo, includeGatewayInfo)\n }],\n attributes: {\n eui: gatewayInfo.gweui\n }\n };\n addAdditionalInfoForDeviceMsg(gatewayInfoMsg, customerName, gatewayGroupName);\n uplinkDataList.add(gatewayInfoMsg);\n }\n}\n\nreturn uplinkDataList;\n\nfunction addAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName) {\n if (customerName != null) {\n deviceInfo.customerName = customerName;\n }\n if (groupName != null) {\n deviceInfo.groupName = groupName;\n }\n}\n\nfunction parseDateToTimestamp(dateString) {\n var timestamp = -1;\n if (dateString != null) {\n \n timestamp = new Date(dateString).getTime();\n if (timestamp == -1) {\n var secondsSeparatorIndex = dateString.lastIndexOf('.') + 1;\n var millisecondsEndIndex = dateString.lastIndexOf('+');\n if (millisecondsEndIndex == -1) {\n millisecondsEndIndex = dateString.lastIndexOf('Z');\n }\n if (millisecondsEndIndex == -1) {\n millisecondsEndIndex = dateString.lastIndexOf('-');\n }\n if (millisecondsEndIndex == -1) {\n if (dateString.length >= secondsSeparatorIndex + 3) {\n dateString = dateString.substring(0, secondsSeparatorIndex + 3);\n }\n } else {\n dateString = dateString.substring(0, secondsSeparatorIndex + 3) +\n dateString.substring(millisecondsEndIndex, dateString.length);\n }\n \n timestamp = new Date(dateString).getTime();\n }\n }\n // If we cannot parse timestamp - we will use the current timestamp\n if (timestamp == -1) {\n timestamp = Date.now();\n }\n \n return timestamp;\n}\n\nfunction processTelemetryData(telemetry, addDataToTelemetry) {\n if (telemetry.size > 1) {\n telemetry = addDataToMultipleTelemetries(telemetry, addDataToTelemetry);\n }\n else if (telemetry.size == 1) {\n telemetry = addDataToSingleTelemetry(telemetry, addDataToTelemetry);\n }\n else {\n telemetry.add(addDataToTelemetry);\n }\n \n return telemetry;\n}\n\nfunction addDataToMultipleTelemetries(telemetry, addDataToTelemetry) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[0][\"values\"].keys.contains(element.key)) {\n telemetry[0][\"values\"][element.key] = element.value;\n }\n if (!telemetry[1][\"values\"].keys.contains(element.key)) {\n telemetry[1][\"values\"][element.key] = element.value;\n }\n }\n \n return telemetry;\n}\n\nfunction addDataToSingleTelemetry(telemetry, addDataToTelemetry) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[0][\"values\"].keys.contains(element.key)) {\n telemetry[0][\"values\"][element.key] = element.value;\n }\n }\n \n return telemetry;\n}", + "tbelDecoder": "var data = decodeToJson(payload);\nvar deviceName = \"AM103L \" + data.EUI;\nvar deviceType = \"AM103L\";\nvar groupName = null; // If groupName is not null - created device will be added to the entity group with such name.\nvar customerName = null; // If customerName is not null - created devices will be assigned to customer with such name. \n\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// If you want to parse incoming data somehow, you can add your code to this function.\n// input: bytes\n// expected output:\n// {\n// \"attributes\": {\"attributeKey\": \"attributeValue\"},\n// \"telemetry\": {\"telemetryKey\": \"telemetryValue\"}\n// }\n\nfunction decodePayload(input) {\n var output = { attributes: {}, telemetry: []};\n \n // --- Decoding code --- //\n var decoded = {};\n var historyData = {};\n for (var i = 0; i < input.length - 2; ) {\n var channel_id = input[i++] & 0xff;\n var channel_type = input[i++] & 0xff;\n // BATTERY\n if(channel_id === 0x01 && channel_type === 0x75) {\n decoded.battery = input[i]; \n i += 1;\n }\n // TEMPERATURE\n if (channel_id === 0x03 && channel_type === 0x67) {\n // ℃\n decoded.temperature = parseBytesToInt(input, i, 2, false) / 10;\n // ℉\n // decoded.temperature = parseBytesToInt(input, i, 2, false) / 10 * 1.8 + 32;\n i += 2;\n }\n // HUMIDITY\n if (channel_id === 0x04 && channel_type === 0x68) {\n decoded.humidity = parseBytesToInt(input, i, 1, false) / 2;\n i += 1;\n }\n // CO2\n if (channel_id === 0x07 && channel_type === 0x7d) {\n decoded.co2 = parseBytesToInt(input, i, 2, false);\n i += 2;\n }\n \n // HISTORY DATA\n if (channel_id === 0x20 && channel_type === 0xce) {\n var historyData = {\n ts: parseBytesToInt(input, i, 4, false) * 1000,\n values: {\n temperature: parseBytesToInt(input, i + 4, 2, false) / 10,\n humidity: parseBytesToInt(input, i + 6, 1, false) / 2,\n co2: parseBytesToInt(input, i + 7, 2, false),\n }\n };\n \n i += 9;\n }\n }\n \n output.telemetry = [{\n ts: timestamp,\n values: decoded\n }, historyData];\n\n // --- Decoding code --- //\n return output;\n}\n\n// --- attributes and telemetry objects ---\nvar telemetry = [];\nvar attributes = {};\n// --- attributes and telemetry objects ---\n\n// --- Timestamp parsing\ntimestamp = data.ts;\n// --- Timestamp parsing\n\n// Message parsing\n// To avoid paths in the decoded objects we passing false value to function as \"pathInKey\" argument.\n// Warning: pathInKey can cause already found fields to be overwritten with the last value found.\n\nvar uplinkDataList = [];\n\n// Passing incoming bytes to decodePayload function, to get custom decoding\nvar customDecoding = decodePayload(hexToBytes(data.data));\n\n// Collecting data to result\nif (customDecoding.?telemetry.size() > 0) {\n if (customDecoding.telemetry instanceof java.util.ArrayList) {\n foreach(telemetryObj: customDecoding.telemetry) {\n if (telemetryObj.ts != null && telemetryObj.values != null) {\n telemetry.add(telemetryObj);\n }\n }\n } else {\n telemetry.putAll(customDecoding.telemetry);\n }\n}\n\nif (customDecoding.?attributes.size() > 0) {\n attributes.putAll(customDecoding.attributes);\n}\n\n// You can add some keys manually to attributes or telemetry\nattributes.eui = data.EUI;\nattributes.fPort = data.port;\nattributes.frequency = data.freq;\n\nvar addDataToTelemetry = {};\naddDataToTelemetry.rssi = data.rssi;\naddDataToTelemetry.seqno = data.seqno;\naddDataToTelemetry.snr = data.snr;\naddDataToTelemetry.ack = data.ack;\naddDataToTelemetry.toa = data.toa;\naddDataToTelemetry.fCnt = data.fcnt;\n\nvar isIncludeGatewayInfo = metadata[\"includeGatewayInfo\"];\nif(isIncludeGatewayInfo == true) {\n telemetry = processTelemetryData(telemetry, addDataToTelemetry);\n}\n\nvar deviceInfo = {\n deviceName: deviceName,\n deviceType: deviceType,\n// assetName: assetName,\n// assetType: assetType,\n attributes: attributes,\n telemetry: telemetry, \n};\n\naddAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName);\n\nuplinkDataList.add(deviceInfo);\n\nvar includeGatewayInfo = [\"ts\", \"gweui\", \"rssi\"];\n\nvar gatewayDeviceNamePrefix = \"Gateway \";\nvar gatewayDeviceType = \"Lora gateway\";\nvar gatewayGroupName = null; // If gatewayGroupName is not null - created device will be added to the entity group with such name.\n\nif (data.cmd == \"gw\") {\n foreach( gatewayInfo : data.gws ) {\n var addGatewayInfo = {};\n\n // You can add some keys manually telemetry\n addGatewayInfo.rssi = gatewayInfo.rssi;\n addGatewayInfo.snr = gatewayInfo.snr;\n // You can add some keys manually telemetry\n \n var gatewayInfoMsg = {\n deviceName: gatewayDeviceNamePrefix + gatewayInfo.gweui,\n deviceType: gatewayDeviceType,\n telemetry: [{\n \"ts\": gatewayInfo.ts,\n \"values\": addGatewayInfo\n }],\n attributes: {\n eui: gatewayInfo.gweui\n }\n };\n addAdditionalInfoForDeviceMsg(gatewayInfoMsg, customerName, gatewayGroupName);\n uplinkDataList.add(gatewayInfoMsg);\n }\n}\n\nreturn uplinkDataList;\n\nfunction addAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName) {\n if (customerName != null) {\n deviceInfo.customerName = customerName;\n }\n if (groupName != null) {\n deviceInfo.groupName = groupName;\n }\n}\n\nfunction parseDateToTimestamp(dateString) {\n var timestamp = -1;\n if (dateString != null) {\n \n timestamp = new Date(dateString).getTime();\n if (timestamp == -1) {\n var secondsSeparatorIndex = dateString.lastIndexOf('.') + 1;\n var millisecondsEndIndex = dateString.lastIndexOf('+');\n if (millisecondsEndIndex == -1) {\n millisecondsEndIndex = dateString.lastIndexOf('Z');\n }\n if (millisecondsEndIndex == -1) {\n millisecondsEndIndex = dateString.lastIndexOf('-');\n }\n if (millisecondsEndIndex == -1) {\n if (dateString.length >= secondsSeparatorIndex + 3) {\n dateString = dateString.substring(0, secondsSeparatorIndex + 3);\n }\n } else {\n dateString = dateString.substring(0, secondsSeparatorIndex + 3) +\n dateString.substring(millisecondsEndIndex, dateString.length);\n }\n \n timestamp = new Date(dateString).getTime();\n }\n }\n // If we cannot parse timestamp - we will use the current timestamp\n if (timestamp == -1) {\n timestamp = Date.now();\n }\n \n return timestamp;\n}\n\nfunction processTelemetryData(telemetry, addDataToTelemetry) {\n if (telemetry.size > 1) {\n telemetry = addDataToMultipleTelemetries(telemetry, addDataToTelemetry);\n }\n else if (telemetry.size == 1) {\n telemetry = addDataToSingleTelemetry(telemetry, addDataToTelemetry);\n }\n else {\n telemetry.add(addDataToTelemetry);\n }\n \n return telemetry;\n}\n\nfunction addDataToMultipleTelemetries(telemetry, addDataToTelemetry) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[0][\"values\"].keys.contains(element.key)) {\n telemetry[0][\"values\"][element.key] = element.value;\n }\n if (!telemetry[1][\"values\"].keys.contains(element.key)) {\n telemetry[1][\"values\"][element.key] = element.value;\n }\n }\n \n return telemetry;\n}\n\nfunction addDataToSingleTelemetry(telemetry, addDataToTelemetry) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[0][\"values\"].keys.contains(element.key)) {\n telemetry[0][\"values\"][element.key] = element.value;\n }\n }\n \n return telemetry;\n}", "encoder": null, "tbelEncoder": null, "updateOnlyKeys": [ diff --git a/VENDORS/Milesight/AM103L/LORIOT/uplink/payload_2.json b/VENDORS/Milesight/AM103L/LORIOT/uplink/payload_2.json new file mode 100644 index 00000000..d1ffb584 --- /dev/null +++ b/VENDORS/Milesight/AM103L/LORIOT/uplink/payload_2.json @@ -0,0 +1,32 @@ +{ + "cmd": "gw", + "seqno": 4, + "EUI": "0102030405060708", + "ts": 1690901260493, + "fcnt": 3, + "port": 207, + "freq": 868300000, + "toa": 1319, + "dr": "SF12 BW125 4/5", + "ack": false, + "gws": [ + { + "rssi": -38, + "snr": 8.5, + "ts": 1690901260493, + "time": "2023-08-01T14:47:40.493Z", + "gweui": "1020304080706050", + "ant": 0 + }, + { + "rssi": -42, + "snr": 8.8, + "ts": 1690901260495, + "time": "2023-08-01T14:47:40.495Z", + "gweui": "1020304081716151", + "ant": 0 + } + ], + "bat": 143, + "data": "0175640367180104686d077dc501" +} diff --git a/VENDORS/Milesight/AM103L/LORIOT/uplink/result_2.json b/VENDORS/Milesight/AM103L/LORIOT/uplink/result_2.json new file mode 100644 index 00000000..1b598cac --- /dev/null +++ b/VENDORS/Milesight/AM103L/LORIOT/uplink/result_2.json @@ -0,0 +1,44 @@ +[{ + "deviceName": "AM103L 0102030405060708", + "deviceType": "AM103L", + "attributes": { + "eui": "0102030405060708", + "fPort": 207, + "frequency": 868300000 + }, + "telemetry": [{ + "ts": 1690901260493, + "values": { + "battery": 100, + "temperature": 28.0, + "humidity": 54.5, + "co2": 453 + } + }] +}, { + "deviceName": "Gateway 1020304080706050", + "deviceType": "Lora gateway", + "telemetry": [{ + "ts": 1690901260493, + "values": { + "rssi": -38, + "snr": 8.5 + } + }], + "attributes": { + "eui": "1020304080706050" + } +}, { + "deviceName": "Gateway 1020304081716151", + "deviceType": "Lora gateway", + "telemetry": [{ + "ts": 1690901260495, + "values": { + "rssi": -42, + "snr": 8.8 + } + }], + "attributes": { + "eui": "1020304081716151" + } +}] \ No newline at end of file diff --git a/VENDORS/Milesight/AM104/LORIOT/uplink/converter.json b/VENDORS/Milesight/AM104/LORIOT/uplink/converter.json index 06bc9d1b..73cb172f 100644 --- a/VENDORS/Milesight/AM104/LORIOT/uplink/converter.json +++ b/VENDORS/Milesight/AM104/LORIOT/uplink/converter.json @@ -1,11 +1,16 @@ { - "name": "Uplink data converter for Loriot integration AM-103", + "name": "Uplink data converter for Loriot integration AM-104", "type": "UPLINK", - "debugMode": true, + "debugMode": false, + "debugSettings": { + "failuresEnabled": true, + "allEnabled": false, + "allEnabledUntil": 1735207754530 + }, "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);\nvar deviceName = \"AM104 \" + data.EUI;\nvar deviceType = \"AM104\";\nvar groupName = null; // If groupName is not null - created device will be added to the entity group with such name.\nvar customerName = null; // If customerName is not null - created devices will be assigned to customer with such name. \n\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// If you want to parse incoming data somehow, you can add your code to this function.\n// input: bytes\n// expected output:\n// {\n// \"attributes\": {\"attributeKey\": \"attributeValue\"},\n// \"telemetry\": {\"telemetryKey\": \"telemetryValue\"}\n// }\n\nfunction decodePayload(input) {\n var output = { attributes: {}, telemetry: []};\n \n // --- Decoding code --- //\n var decoded = {};\n var historyData = {};\n for (var i = 0; i < input.length - 2; ) {\n var channel_id = input[i++] & 0xff;\n var channel_type = input[i++] & 0xff;\n // BATTERY\n if(channel_id === 0x01 && channel_type === 0x75) {\n decoded.battery = input[i]; \n i += 1;\n }\n // TEMPERATURE\n if (channel_id === 0x03 && channel_type === 0x67) {\n // ℃\n decoded.temperature = parseBytesToInt(input, i, 2, false) / 10;\n // ℉\n // decoded.temperature = parseBytesToInt(input, i, 2, false) / 10 * 1.8 + 32;\n i += 2;\n }\n // HUMIDITY\n if (channel_id === 0x04 && channel_type === 0x68) {\n decoded.humidity = parseBytesToInt(input, i, 1, false) / 2;\n i += 1;\n }\n \n // PIR\n if (channel_id === 0x05 && channel_type === 0x6a) {\n decoded.activity = parseBytesToInt(input, i, 2, false);\n i += 2;\n }\n \n // LIGHT\n if (channel_id === 0x06 && channel_type === 0x65) {\n decoded.illumination = parseBytesToInt(input, i, 2, false);\n decoded.infrared_and_visible = parseBytesToInt(input, i+2, 2, false);\n decoded.infrared = parseBytesToInt(input, i+4, 2, false);\n i += 6;\n }\n }\n \n output.telemetry = [{\n ts: timestamp,\n values: decoded\n }, historyData];\n\n // --- Decoding code --- //\n return output;\n}\n\n// --- attributes and telemetry objects ---\nvar telemetry = [];\nvar attributes = {};\n// --- attributes and telemetry objects ---\n\n// --- Timestamp parsing\ntimestamp = data.ts;\n// --- Timestamp parsing\n\n// Message parsing\n// To avoid paths in the decoded objects we passing false value to function as \"pathInKey\" argument.\n// Warning: pathInKey can cause already found fields to be overwritten with the last value found.\n\nvar uplinkDataList = [];\n\n// Passing incoming bytes to decodePayload function, to get custom decoding\nvar customDecoding = decodePayload(hexToBytes(data.data));\n\n// Collecting data to result\nif (customDecoding.?telemetry.size() > 0) {\n if (customDecoding.telemetry instanceof java.util.ArrayList) {\n foreach(telemetryObj: customDecoding.telemetry) {\n if (telemetryObj.ts != null && telemetryObj.values != null) {\n telemetry.add(telemetryObj);\n }\n }\n } else {\n telemetry.putAll(customDecoding.telemetry);\n }\n}\n\nif (customDecoding.?attributes.size() > 0) {\n attributes.putAll(customDecoding.attributes);\n}\n\n// You can add some keys manually to attributes or telemetry\nattributes.eui = data.EUI;\nattributes.fPort = data.port;\nattributes.frequency = data.freq;\n\nvar addDataToTelemetry = {};\naddDataToTelemetry.rssi = data.rssi;\naddDataToTelemetry.seqno = data.seqno;\naddDataToTelemetry.snr = data.snr;\naddDataToTelemetry.ack = data.ack;\naddDataToTelemetry.toa = data.toa;\naddDataToTelemetry.fCnt = data.fcnt;\n\nvar isIncludeGatewayInfo = metadata[\"includeGatewayInfo\"];\nif(isIncludeGatewayInfo == true) {\n telemetry = processTelemetryData(telemetry, addDataToTelemetry);\n}\n\nvar deviceInfo = {\n deviceName: deviceName,\n deviceType: deviceType,\n// assetName: assetName,\n// assetType: assetType,\n attributes: attributes,\n telemetry: telemetry, \n};\n\naddAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName);\n\nuplinkDataList.add(deviceInfo);\n\nvar includeGatewayInfo = [\"ts\", \"gweui\", \"rssi\"];\n\nvar gatewayDeviceNamePrefix = \"Gateway \";\nvar gatewayDeviceType = \"Lora gateway\";\nvar gatewayGroupName = null; // If gatewayGroupName is not null - created device will be added to the entity group with such name.\n\nif (data.cmd == \"gw\") {\n foreach( gatewayInfo : data.gws ) {\n var gatewayInfoMsg = {\n deviceName: gatewayDeviceNamePrefix + gatewayInfo.gweui,\n deviceType: gatewayDeviceType,\n telemetry: [{\n \"ts\": parseDateToTimestamp(gatewayInfo.ts),\n \"values\": getDataList(gatewayInfo, includeGatewayInfo)\n }],\n attributes: {\n eui: gatewayInfo.gweui\n }\n };\n addAdditionalInfoForDeviceMsg(gatewayInfoMsg, customerName, gatewayGroupName);\n uplinkDataList.add(gatewayInfoMsg);\n }\n}\n\nreturn uplinkDataList;\n\nfunction addAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName) {\n if (customerName != null) {\n deviceInfo.customerName = customerName;\n }\n if (groupName != null) {\n deviceInfo.groupName = groupName;\n }\n}\n\nfunction parseDateToTimestamp(dateString) {\n var timestamp = -1;\n if (dateString != null) {\n \n timestamp = new Date(dateString).getTime();\n if (timestamp == -1) {\n var secondsSeparatorIndex = dateString.lastIndexOf('.') + 1;\n var millisecondsEndIndex = dateString.lastIndexOf('+');\n if (millisecondsEndIndex == -1) {\n millisecondsEndIndex = dateString.lastIndexOf('Z');\n }\n if (millisecondsEndIndex == -1) {\n millisecondsEndIndex = dateString.lastIndexOf('-');\n }\n if (millisecondsEndIndex == -1) {\n if (dateString.length >= secondsSeparatorIndex + 3) {\n dateString = dateString.substring(0, secondsSeparatorIndex + 3);\n }\n } else {\n dateString = dateString.substring(0, secondsSeparatorIndex + 3) +\n dateString.substring(millisecondsEndIndex, dateString.length);\n }\n \n timestamp = new Date(dateString).getTime();\n }\n }\n // If we cannot parse timestamp - we will use the current timestamp\n if (timestamp == -1) {\n timestamp = Date.now();\n }\n \n return timestamp;\n}\n\nfunction processTelemetryData(telemetry, addDataToTelemetry) {\n if (telemetry.size > 1) {\n telemetry = addDataToMultipleTelemetries(telemetry, addDataToTelemetry);\n }\n else if (telemetry.size == 1) {\n telemetry = addDataToSingleTelemetry(telemetry, addDataToTelemetry);\n }\n else {\n telemetry.add(addDataToTelemetry);\n }\n \n return telemetry;\n}\n\nfunction addDataToMultipleTelemetries(telemetry, addDataToTelemetry) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[0][\"values\"].keys.contains(element.key)) {\n telemetry[0][\"values\"][element.key] = element.value;\n }\n if (!telemetry[1][\"values\"].keys.contains(element.key)) {\n telemetry[1][\"values\"][element.key] = element.value;\n }\n }\n \n return telemetry;\n}\n\nfunction addDataToSingleTelemetry(telemetry, addDataToTelemetry) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[0][\"values\"].keys.contains(element.key)) {\n telemetry[0][\"values\"][element.key] = element.value;\n }\n }\n \n return telemetry;\n}", + "tbelDecoder": "var data = decodeToJson(payload);\nvar deviceName = \"AM104 \" + data.EUI;\nvar deviceType = \"AM104\";\nvar groupName = null; // If groupName is not null - created device will be added to the entity group with such name.\nvar customerName = null; // If customerName is not null - created devices will be assigned to customer with such name. \n\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// If you want to parse incoming data somehow, you can add your code to this function.\n// input: bytes\n// expected output:\n// {\n// \"attributes\": {\"attributeKey\": \"attributeValue\"},\n// \"telemetry\": {\"telemetryKey\": \"telemetryValue\"}\n// }\n\nfunction decodePayload(input) {\n var output = { attributes: {}, telemetry: []};\n \n // --- Decoding code --- //\n var decoded = {};\n var historyData = {};\n for (var i = 0; i < input.length - 2; ) {\n var channel_id = input[i++] & 0xff;\n var channel_type = input[i++] & 0xff;\n // BATTERY\n if(channel_id === 0x01 && channel_type === 0x75) {\n decoded.battery = input[i]; \n i += 1;\n }\n // TEMPERATURE\n if (channel_id === 0x03 && channel_type === 0x67) {\n // ℃\n decoded.temperature = parseBytesToInt(input, i, 2, false) / 10;\n // ℉\n // decoded.temperature = parseBytesToInt(input, i, 2, false) / 10 * 1.8 + 32;\n i += 2;\n }\n // HUMIDITY\n if (channel_id === 0x04 && channel_type === 0x68) {\n decoded.humidity = parseBytesToInt(input, i, 1, false) / 2;\n i += 1;\n }\n \n // PIR\n if (channel_id === 0x05 && channel_type === 0x6a) {\n decoded.activity = parseBytesToInt(input, i, 2, false);\n i += 2;\n }\n \n // LIGHT\n if (channel_id === 0x06 && channel_type === 0x65) {\n decoded.illumination = parseBytesToInt(input, i, 2, false);\n decoded.infrared_and_visible = parseBytesToInt(input, i+2, 2, false);\n decoded.infrared = parseBytesToInt(input, i+4, 2, false);\n i += 6;\n }\n }\n \n output.telemetry = [{\n ts: timestamp,\n values: decoded\n }, historyData];\n\n // --- Decoding code --- //\n return output;\n}\n\n// --- attributes and telemetry objects ---\nvar telemetry = [];\nvar attributes = {};\n// --- attributes and telemetry objects ---\n\n// --- Timestamp parsing\ntimestamp = data.ts;\n// --- Timestamp parsing\n\n// Message parsing\n// To avoid paths in the decoded objects we passing false value to function as \"pathInKey\" argument.\n// Warning: pathInKey can cause already found fields to be overwritten with the last value found.\n\nvar uplinkDataList = [];\n\n// Passing incoming bytes to decodePayload function, to get custom decoding\nvar customDecoding = decodePayload(hexToBytes(data.data));\n\n// Collecting data to result\nif (customDecoding.?telemetry.size() > 0) {\n if (customDecoding.telemetry instanceof java.util.ArrayList) {\n foreach(telemetryObj: customDecoding.telemetry) {\n if (telemetryObj.ts != null && telemetryObj.values != null) {\n telemetry.add(telemetryObj);\n }\n }\n } else {\n telemetry.putAll(customDecoding.telemetry);\n }\n}\n\nif (customDecoding.?attributes.size() > 0) {\n attributes.putAll(customDecoding.attributes);\n}\n\n// You can add some keys manually to attributes or telemetry\nattributes.eui = data.EUI;\nattributes.fPort = data.port;\nattributes.frequency = data.freq;\n\nvar addDataToTelemetry = {};\naddDataToTelemetry.rssi = data.rssi;\naddDataToTelemetry.seqno = data.seqno;\naddDataToTelemetry.snr = data.snr;\naddDataToTelemetry.ack = data.ack;\naddDataToTelemetry.toa = data.toa;\naddDataToTelemetry.fCnt = data.fcnt;\n\nvar isIncludeGatewayInfo = metadata[\"includeGatewayInfo\"];\nif(isIncludeGatewayInfo == true) {\n telemetry = processTelemetryData(telemetry, addDataToTelemetry);\n}\n\nvar deviceInfo = {\n deviceName: deviceName,\n deviceType: deviceType,\n// assetName: assetName,\n// assetType: assetType,\n attributes: attributes,\n telemetry: telemetry, \n};\n\naddAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName);\n\nuplinkDataList.add(deviceInfo);\n\nvar includeGatewayInfo = [\"ts\", \"gweui\", \"rssi\"];\n\nvar gatewayDeviceNamePrefix = \"Gateway \";\nvar gatewayDeviceType = \"Lora gateway\";\nvar gatewayGroupName = null; // If gatewayGroupName is not null - created device will be added to the entity group with such name.\n\nif (data.cmd == \"gw\") {\n foreach( gatewayInfo : data.gws ) {\n var addGatewayInfo = {};\n\n // You can add some keys manually telemetry\n addGatewayInfo.rssi = gatewayInfo.rssi;\n addGatewayInfo.snr = gatewayInfo.snr;\n // You can add some keys manually telemetry\n \n var gatewayInfoMsg = {\n deviceName: gatewayDeviceNamePrefix + gatewayInfo.gweui,\n deviceType: gatewayDeviceType,\n telemetry: [{\n \"ts\": gatewayInfo.ts,\n \"values\": addGatewayInfo\n }],\n attributes: {\n eui: gatewayInfo.gweui\n }\n };\n addAdditionalInfoForDeviceMsg(gatewayInfoMsg, customerName, gatewayGroupName);\n uplinkDataList.add(gatewayInfoMsg);\n }\n}\n\nreturn uplinkDataList;\n\nfunction addAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName) {\n if (customerName != null) {\n deviceInfo.customerName = customerName;\n }\n if (groupName != null) {\n deviceInfo.groupName = groupName;\n }\n}\n\nfunction parseDateToTimestamp(dateString) {\n var timestamp = -1;\n if (dateString != null) {\n \n timestamp = new Date(dateString).getTime();\n if (timestamp == -1) {\n var secondsSeparatorIndex = dateString.lastIndexOf('.') + 1;\n var millisecondsEndIndex = dateString.lastIndexOf('+');\n if (millisecondsEndIndex == -1) {\n millisecondsEndIndex = dateString.lastIndexOf('Z');\n }\n if (millisecondsEndIndex == -1) {\n millisecondsEndIndex = dateString.lastIndexOf('-');\n }\n if (millisecondsEndIndex == -1) {\n if (dateString.length >= secondsSeparatorIndex + 3) {\n dateString = dateString.substring(0, secondsSeparatorIndex + 3);\n }\n } else {\n dateString = dateString.substring(0, secondsSeparatorIndex + 3) +\n dateString.substring(millisecondsEndIndex, dateString.length);\n }\n \n timestamp = new Date(dateString).getTime();\n }\n }\n // If we cannot parse timestamp - we will use the current timestamp\n if (timestamp == -1) {\n timestamp = Date.now();\n }\n \n return timestamp;\n}\n\nfunction processTelemetryData(telemetry, addDataToTelemetry) {\n if (telemetry.size > 1) {\n telemetry = addDataToMultipleTelemetries(telemetry, addDataToTelemetry);\n }\n else if (telemetry.size == 1) {\n telemetry = addDataToSingleTelemetry(telemetry, addDataToTelemetry);\n }\n else {\n telemetry.add(addDataToTelemetry);\n }\n \n return telemetry;\n}\n\nfunction addDataToMultipleTelemetries(telemetry, addDataToTelemetry) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[0][\"values\"].keys.contains(element.key)) {\n telemetry[0][\"values\"][element.key] = element.value;\n }\n if (!telemetry[1][\"values\"].keys.contains(element.key)) {\n telemetry[1][\"values\"][element.key] = element.value;\n }\n }\n \n return telemetry;\n}\n\nfunction addDataToSingleTelemetry(telemetry, addDataToTelemetry) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[0][\"values\"].keys.contains(element.key)) {\n telemetry[0][\"values\"][element.key] = element.value;\n }\n }\n \n return telemetry;\n}", "encoder": null, "tbelEncoder": null, "updateOnlyKeys": [ diff --git a/VENDORS/Milesight/AM104/LORIOT/uplink/payload_1.json b/VENDORS/Milesight/AM104/LORIOT/uplink/payload_1.json new file mode 100644 index 00000000..740f1ea6 --- /dev/null +++ b/VENDORS/Milesight/AM104/LORIOT/uplink/payload_1.json @@ -0,0 +1,32 @@ +{ + "cmd": "gw", + "seqno": 4, + "EUI": "0102030405060708", + "ts": 1690901260493, + "fcnt": 3, + "port": 207, + "freq": 868300000, + "toa": 1319, + "dr": "SF12 BW125 4/5", + "ack": false, + "gws": [ + { + "rssi": -38, + "snr": 8.5, + "ts": 1690901260493, + "time": "2023-08-01T14:47:40.493Z", + "gweui": "1020304080706050", + "ant": 0 + }, + { + "rssi": -42, + "snr": 8.8, + "ts": 1690901260495, + "time": "2023-08-01T14:47:40.495Z", + "gweui": "1020304081716151", + "ant": 0 + } + ], + "bat": 143, + "data": "01755C03673401046865056A490006651C0079001400" +} diff --git a/VENDORS/Milesight/AM104/LORIOT/uplink/result_1.json b/VENDORS/Milesight/AM104/LORIOT/uplink/result_1.json new file mode 100644 index 00000000..225c921a --- /dev/null +++ b/VENDORS/Milesight/AM104/LORIOT/uplink/result_1.json @@ -0,0 +1,47 @@ +[{ + "deviceName": "AM104 0102030405060708", + "deviceType": "AM104", + "attributes": { + "eui": "0102030405060708", + "fPort": 207, + "frequency": 868300000 + }, + "telemetry": [{ + "ts": 1690901260493, + "values": { + "battery": 92, + "temperature": 30.8, + "humidity": 50.5, + "activity": 73, + "illumination": 28, + "infrared_and_visible": 121, + "infrared": 20 + } + }] +}, { + "deviceName": "Gateway 1020304080706050", + "deviceType": "Lora gateway", + "telemetry": [{ + "ts": 1690901260493, + "values": { + "rssi": -38, + "snr": 8.5 + } + }], + "attributes": { + "eui": "1020304080706050" + } +}, { + "deviceName": "Gateway 1020304081716151", + "deviceType": "Lora gateway", + "telemetry": [{ + "ts": 1690901260495, + "values": { + "rssi": -42, + "snr": 8.8 + } + }], + "attributes": { + "eui": "1020304081716151" + } +}] \ No newline at end of file diff --git a/VENDORS/Milesight/AM107/LORIOT/uplink/converter.json b/VENDORS/Milesight/AM107/LORIOT/uplink/converter.json index 4e0df159..78fb90ed 100644 --- a/VENDORS/Milesight/AM107/LORIOT/uplink/converter.json +++ b/VENDORS/Milesight/AM107/LORIOT/uplink/converter.json @@ -1,11 +1,16 @@ { "name": "Uplink data converter for Loriot integration AM-107", "type": "UPLINK", - "debugMode": true, + "debugMode": false, + "debugSettings": { + "failuresEnabled": true, + "allEnabled": false, + "allEnabledUntil": 1735207888088 + }, "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);\nvar deviceName = \"AM107 \" + data.EUI;\nvar deviceType = \"AM107\";\nvar groupName = null; // If groupName is not null - created device will be added to the entity group with such name.\nvar customerName = null; // If customerName is not null - created devices will be assigned to customer with such name. \n\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// If you want to parse incoming data somehow, you can add your code to this function.\n// input: bytes\n// expected output:\n// {\n// \"attributes\": {\"attributeKey\": \"attributeValue\"},\n// \"telemetry\": {\"telemetryKey\": \"telemetryValue\"}\n// }\n\nfunction decodePayload(input) {\n var output = { attributes: {}, telemetry: []};\n \n // --- Decoding code --- //\n var decoded = {};\n var historyData = {};\n for (var i = 0; i < input.length - 2; ) {\n var channel_id = input[i++] & 0xff;\n var channel_type = input[i++] & 0xff;\n // BATTERY\n if(channel_id === 0x01 && channel_type === 0x75) {\n decoded.battery = input[i]; \n i += 1;\n }\n // TEMPERATURE\n if (channel_id === 0x03 && channel_type === 0x67) {\n // ℃\n decoded.temperature = parseBytesToInt(input, i, 2, false) / 10;\n // ℉\n // decoded.temperature = parseBytesToInt(input, i, 2, false) / 10 * 1.8 + 32;\n i += 2;\n }\n // HUMIDITY\n if (channel_id === 0x04 && channel_type === 0x68) {\n decoded.humidity = parseBytesToInt(input, i, 1, false) / 2;\n i += 1;\n }\n // PIR\n if (channel_id === 0x05 && channel_type === 0x6a) {\n decoded.activity = parseBytesToInt(input, i, 2, false);\n i += 2;\n }\n // LIGHT\n if (channel_id === 0x06 && channel_type === 0x65) {\n decoded.illumination = parseBytesToInt(input, i, 2, false);\n decoded.infrared_and_visible = parseBytesToInt(input, i+2, 2, false);\n decoded.infrared = parseBytesToInt(input, i+4, 2, false);\n i += 6;\n }\n // CO2\n if (channel_id === 0x07 && channel_type === 0x7d) {\n decoded.co2 = parseBytesToInt(input, i, 2, false);\n i += 2;\n }\n // TVOC\n if (channel_id === 0x08 && channel_type === 0x7d) {\n decoded.tvoc = parseBytesToInt(input, i, 2, false);\n i += 2;\n }\n // PRESSURE\n if (channel_id === 0x09 && channel_type === 0x73) {\n decoded.pressure = parseBytesToInt(input, i, 2, false) / 10;\n i += 2;\n }\n }\n \n output.telemetry = [{\n ts: timestamp,\n values: decoded\n }, historyData];\n\n // --- Decoding code --- //\n return output;\n}\n\n// --- attributes and telemetry objects ---\nvar telemetry = [];\nvar attributes = {};\n// --- attributes and telemetry objects ---\n\n// --- Timestamp parsing\ntimestamp = data.ts;\n// --- Timestamp parsing\n\n// Message parsing\n// To avoid paths in the decoded objects we passing false value to function as \"pathInKey\" argument.\n// Warning: pathInKey can cause already found fields to be overwritten with the last value found.\n\nvar uplinkDataList = [];\n\n// Passing incoming bytes to decodePayload function, to get custom decoding\nvar customDecoding = decodePayload(hexToBytes(data.data));\n\n// Collecting data to result\nif (customDecoding.?telemetry.size() > 0) {\n if (customDecoding.telemetry instanceof java.util.ArrayList) {\n foreach(telemetryObj: customDecoding.telemetry) {\n if (telemetryObj.ts != null && telemetryObj.values != null) {\n telemetry.add(telemetryObj);\n }\n }\n } else {\n telemetry.putAll(customDecoding.telemetry);\n }\n}\n\nif (customDecoding.?attributes.size() > 0) {\n attributes.putAll(customDecoding.attributes);\n}\n\n// You can add some keys manually to attributes or telemetry\nattributes.eui = data.EUI;\nattributes.fPort = data.port;\nattributes.frequency = data.freq;\n\nvar addDataToTelemetry = {};\naddDataToTelemetry.rssi = data.rssi;\naddDataToTelemetry.seqno = data.seqno;\naddDataToTelemetry.snr = data.snr;\naddDataToTelemetry.ack = data.ack;\naddDataToTelemetry.toa = data.toa;\naddDataToTelemetry.fCnt = data.fcnt;\n\nvar isIncludeGatewayInfo = metadata[\"includeGatewayInfo\"];\nif(isIncludeGatewayInfo == true) {\n telemetry = processTelemetryData(telemetry, addDataToTelemetry);\n}\n\nvar deviceInfo = {\n deviceName: deviceName,\n deviceType: deviceType,\n// assetName: assetName,\n// assetType: assetType,\n attributes: attributes,\n telemetry: telemetry, \n};\n\naddAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName);\n\nuplinkDataList.add(deviceInfo);\n\nvar includeGatewayInfo = [\"ts\", \"gweui\", \"rssi\"];\n\nvar gatewayDeviceNamePrefix = \"Gateway \";\nvar gatewayDeviceType = \"Lora gateway\";\nvar gatewayGroupName = null; // If gatewayGroupName is not null - created device will be added to the entity group with such name.\n\nif (data.cmd == \"gw\") {\n foreach( gatewayInfo : data.gws ) {\n var gatewayInfoMsg = {\n deviceName: gatewayDeviceNamePrefix + gatewayInfo.gweui,\n deviceType: gatewayDeviceType,\n telemetry: [{\n \"ts\": parseDateToTimestamp(gatewayInfo.ts),\n \"values\": getDataList(gatewayInfo, includeGatewayInfo)\n }],\n attributes: {\n eui: gatewayInfo.gweui\n }\n };\n addAdditionalInfoForDeviceMsg(gatewayInfoMsg, customerName, gatewayGroupName);\n uplinkDataList.add(gatewayInfoMsg);\n }\n}\n\nreturn uplinkDataList;\n\nfunction addAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName) {\n if (customerName != null) {\n deviceInfo.customerName = customerName;\n }\n if (groupName != null) {\n deviceInfo.groupName = groupName;\n }\n}\n\nfunction parseDateToTimestamp(dateString) {\n var timestamp = -1;\n if (dateString != null) {\n \n timestamp = new Date(dateString).getTime();\n if (timestamp == -1) {\n var secondsSeparatorIndex = dateString.lastIndexOf('.') + 1;\n var millisecondsEndIndex = dateString.lastIndexOf('+');\n if (millisecondsEndIndex == -1) {\n millisecondsEndIndex = dateString.lastIndexOf('Z');\n }\n if (millisecondsEndIndex == -1) {\n millisecondsEndIndex = dateString.lastIndexOf('-');\n }\n if (millisecondsEndIndex == -1) {\n if (dateString.length >= secondsSeparatorIndex + 3) {\n dateString = dateString.substring(0, secondsSeparatorIndex + 3);\n }\n } else {\n dateString = dateString.substring(0, secondsSeparatorIndex + 3) +\n dateString.substring(millisecondsEndIndex, dateString.length);\n }\n \n timestamp = new Date(dateString).getTime();\n }\n }\n // If we cannot parse timestamp - we will use the current timestamp\n if (timestamp == -1) {\n timestamp = Date.now();\n }\n \n return timestamp;\n}\n\nfunction processTelemetryData(telemetry, addDataToTelemetry) {\n if (telemetry.size > 1) {\n telemetry = addDataToMultipleTelemetries(telemetry, addDataToTelemetry);\n }\n else if (telemetry.size == 1) {\n telemetry = addDataToSingleTelemetry(telemetry, addDataToTelemetry);\n }\n else {\n telemetry.add(addDataToTelemetry);\n }\n \n return telemetry;\n}\n\nfunction addDataToMultipleTelemetries(telemetry, addDataToTelemetry) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[0][\"values\"].keys.contains(element.key)) {\n telemetry[0][\"values\"][element.key] = element.value;\n }\n if (!telemetry[1][\"values\"].keys.contains(element.key)) {\n telemetry[1][\"values\"][element.key] = element.value;\n }\n }\n \n return telemetry;\n}\n\nfunction addDataToSingleTelemetry(telemetry, addDataToTelemetry) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[0][\"values\"].keys.contains(element.key)) {\n telemetry[0][\"values\"][element.key] = element.value;\n }\n }\n \n return telemetry;\n}", + "tbelDecoder": "var data = decodeToJson(payload);\nvar deviceName = \"AM107 \" + data.EUI;\nvar deviceType = \"AM107\";\nvar groupName = null; // If groupName is not null - created device will be added to the entity group with such name.\nvar customerName = null; // If customerName is not null - created devices will be assigned to customer with such name. \n\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// If you want to parse incoming data somehow, you can add your code to this function.\n// input: bytes\n// expected output:\n// {\n// \"attributes\": {\"attributeKey\": \"attributeValue\"},\n// \"telemetry\": {\"telemetryKey\": \"telemetryValue\"}\n// }\n\nfunction decodePayload(input) {\n var output = { attributes: {}, telemetry: []};\n \n // --- Decoding code --- //\n var decoded = {};\n var historyData = {};\n for (var i = 0; i < input.length - 2; ) {\n var channel_id = input[i++] & 0xff;\n var channel_type = input[i++] & 0xff;\n // BATTERY\n if(channel_id === 0x01 && channel_type === 0x75) {\n decoded.battery = input[i]; \n i += 1;\n }\n // TEMPERATURE\n if (channel_id === 0x03 && channel_type === 0x67) {\n // ℃\n decoded.temperature = parseBytesToInt(input, i, 2, false) / 10;\n // ℉\n // decoded.temperature = parseBytesToInt(input, i, 2, false) / 10 * 1.8 + 32;\n i += 2;\n }\n // HUMIDITY\n if (channel_id === 0x04 && channel_type === 0x68) {\n decoded.humidity = parseBytesToInt(input, i, 1, false) / 2;\n i += 1;\n }\n // PIR\n if (channel_id === 0x05 && channel_type === 0x6a) {\n decoded.activity = parseBytesToInt(input, i, 2, false);\n i += 2;\n }\n // LIGHT\n if (channel_id === 0x06 && channel_type === 0x65) {\n decoded.illumination = parseBytesToInt(input, i, 2, false);\n decoded.infrared_and_visible = parseBytesToInt(input, i+2, 2, false);\n decoded.infrared = parseBytesToInt(input, i+4, 2, false);\n i += 6;\n }\n // CO2\n if (channel_id === 0x07 && channel_type === 0x7d) {\n decoded.co2 = parseBytesToInt(input, i, 2, false);\n i += 2;\n }\n // TVOC\n if (channel_id === 0x08 && channel_type === 0x7d) {\n decoded.tvoc = parseBytesToInt(input, i, 2, false);\n i += 2;\n }\n // PRESSURE\n if (channel_id === 0x09 && channel_type === 0x73) {\n decoded.pressure = parseBytesToInt(input, i, 2, false) / 10;\n i += 2;\n }\n }\n \n output.telemetry = [{\n ts: timestamp,\n values: decoded\n }, historyData];\n\n // --- Decoding code --- //\n return output;\n}\n\n// --- attributes and telemetry objects ---\nvar telemetry = [];\nvar attributes = {};\n// --- attributes and telemetry objects ---\n\n// --- Timestamp parsing\ntimestamp = data.ts;\n// --- Timestamp parsing\n\n// Message parsing\n// To avoid paths in the decoded objects we passing false value to function as \"pathInKey\" argument.\n// Warning: pathInKey can cause already found fields to be overwritten with the last value found.\n\nvar uplinkDataList = [];\n\n// Passing incoming bytes to decodePayload function, to get custom decoding\nvar customDecoding = decodePayload(hexToBytes(data.data));\n\n// Collecting data to result\nif (customDecoding.?telemetry.size() > 0) {\n if (customDecoding.telemetry instanceof java.util.ArrayList) {\n foreach(telemetryObj: customDecoding.telemetry) {\n if (telemetryObj.ts != null && telemetryObj.values != null) {\n telemetry.add(telemetryObj);\n }\n }\n } else {\n telemetry.putAll(customDecoding.telemetry);\n }\n}\n\nif (customDecoding.?attributes.size() > 0) {\n attributes.putAll(customDecoding.attributes);\n}\n\n// You can add some keys manually to attributes or telemetry\nattributes.eui = data.EUI;\nattributes.fPort = data.port;\nattributes.frequency = data.freq;\n\nvar addDataToTelemetry = {};\naddDataToTelemetry.rssi = data.rssi;\naddDataToTelemetry.seqno = data.seqno;\naddDataToTelemetry.snr = data.snr;\naddDataToTelemetry.ack = data.ack;\naddDataToTelemetry.toa = data.toa;\naddDataToTelemetry.fCnt = data.fcnt;\n\nvar isIncludeGatewayInfo = metadata[\"includeGatewayInfo\"];\nif(isIncludeGatewayInfo == true) {\n telemetry = processTelemetryData(telemetry, addDataToTelemetry);\n}\n\nvar deviceInfo = {\n deviceName: deviceName,\n deviceType: deviceType,\n// assetName: assetName,\n// assetType: assetType,\n attributes: attributes,\n telemetry: telemetry, \n};\n\naddAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName);\n\nuplinkDataList.add(deviceInfo);\n\nvar gatewayDeviceNamePrefix = \"Gateway \";\nvar gatewayDeviceType = \"Lora gateway\";\nvar gatewayGroupName = null; // If gatewayGroupName is not null - created device will be added to the entity group with such name.\n\nif (data.cmd == \"gw\") {\n foreach( gatewayInfo : data.gws ) {\n var addGatewayInfo = {};\n\n // You can add some keys manually telemetry\n addGatewayInfo.rssi = gatewayInfo.rssi;\n addGatewayInfo.snr = gatewayInfo.snr;\n // You can add some keys manually telemetry\n \n var gatewayInfoMsg = {\n deviceName: gatewayDeviceNamePrefix + gatewayInfo.gweui,\n deviceType: gatewayDeviceType,\n telemetry: [{\n \"ts\": gatewayInfo.ts,\n \"values\": addGatewayInfo\n }],\n attributes: {\n eui: gatewayInfo.gweui\n }\n };\n addAdditionalInfoForDeviceMsg(gatewayInfoMsg, customerName, gatewayGroupName);\n uplinkDataList.add(gatewayInfoMsg);\n }\n}\n\nreturn uplinkDataList;\n\nfunction addAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName) {\n if (customerName != null) {\n deviceInfo.customerName = customerName;\n }\n if (groupName != null) {\n deviceInfo.groupName = groupName;\n }\n}\n\nfunction parseDateToTimestamp(dateString) {\n var timestamp = -1;\n if (dateString != null) {\n \n timestamp = new Date(dateString).getTime();\n if (timestamp == -1) {\n var secondsSeparatorIndex = dateString.lastIndexOf('.') + 1;\n var millisecondsEndIndex = dateString.lastIndexOf('+');\n if (millisecondsEndIndex == -1) {\n millisecondsEndIndex = dateString.lastIndexOf('Z');\n }\n if (millisecondsEndIndex == -1) {\n millisecondsEndIndex = dateString.lastIndexOf('-');\n }\n if (millisecondsEndIndex == -1) {\n if (dateString.length >= secondsSeparatorIndex + 3) {\n dateString = dateString.substring(0, secondsSeparatorIndex + 3);\n }\n } else {\n dateString = dateString.substring(0, secondsSeparatorIndex + 3) +\n dateString.substring(millisecondsEndIndex, dateString.length);\n }\n \n timestamp = new Date(dateString).getTime();\n }\n }\n // If we cannot parse timestamp - we will use the current timestamp\n if (timestamp == -1) {\n timestamp = Date.now();\n }\n \n return timestamp;\n}\n\nfunction processTelemetryData(telemetry, addDataToTelemetry) {\n if (telemetry.size > 1) {\n telemetry = addDataToMultipleTelemetries(telemetry, addDataToTelemetry);\n }\n else if (telemetry.size == 1) {\n telemetry = addDataToSingleTelemetry(telemetry, addDataToTelemetry);\n }\n else {\n telemetry.add(addDataToTelemetry);\n }\n \n return telemetry;\n}\n\nfunction addDataToMultipleTelemetries(telemetry, addDataToTelemetry) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[0][\"values\"].keys.contains(element.key)) {\n telemetry[0][\"values\"][element.key] = element.value;\n }\n if (!telemetry[1][\"values\"].keys.contains(element.key)) {\n telemetry[1][\"values\"][element.key] = element.value;\n }\n }\n \n return telemetry;\n}\n\nfunction addDataToSingleTelemetry(telemetry, addDataToTelemetry) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[0][\"values\"].keys.contains(element.key)) {\n telemetry[0][\"values\"][element.key] = element.value;\n }\n }\n \n return telemetry;\n}", "encoder": null, "tbelEncoder": null, "updateOnlyKeys": [ diff --git a/VENDORS/Milesight/AM107/LORIOT/uplink/payload_1.json b/VENDORS/Milesight/AM107/LORIOT/uplink/payload_1.json new file mode 100644 index 00000000..45990550 --- /dev/null +++ b/VENDORS/Milesight/AM107/LORIOT/uplink/payload_1.json @@ -0,0 +1,32 @@ +{ + "cmd": "gw", + "seqno": 4, + "EUI": "0102030405060708", + "ts": 1690901260493, + "fcnt": 3, + "port": 207, + "freq": 868300000, + "toa": 1319, + "dr": "SF12 BW125 4/5", + "ack": false, + "gws": [ + { + "rssi": -38, + "snr": 8.5, + "ts": 1690901260493, + "time": "2023-08-01T14:47:40.493Z", + "gweui": "1020304080706050", + "ant": 0 + }, + { + "rssi": -42, + "snr": 8.8, + "ts": 1690901260495, + "time": "2023-08-01T14:47:40.495Z", + "gweui": "1020304081716151", + "ant": 0 + } + ], + "bat": 143, + "data": "01755C03673401046865056A490006651C0079001400077DE704087D070009733F27" +} diff --git a/VENDORS/Milesight/AM107/LORIOT/uplink/result_1.json b/VENDORS/Milesight/AM107/LORIOT/uplink/result_1.json new file mode 100644 index 00000000..f6a79af1 --- /dev/null +++ b/VENDORS/Milesight/AM107/LORIOT/uplink/result_1.json @@ -0,0 +1,50 @@ +[{ + "deviceName": "AM107 0102030405060708", + "deviceType": "AM107", + "attributes": { + "eui": "0102030405060708", + "fPort": 207, + "frequency": 868300000 + }, + "telemetry": [{ + "ts": 1690901260493, + "values": { + "battery": 92, + "temperature": 30.8, + "humidity": 50.5, + "activity": 73, + "illumination": 28, + "infrared_and_visible": 121, + "infrared": 20, + "co2": 1255, + "tvoc": 7, + "pressure": 1004.7 + } + }] +}, { + "deviceName": "Gateway 1020304080706050", + "deviceType": "Lora gateway", + "telemetry": [{ + "ts": 1690901260493, + "values": { + "rssi": -38, + "snr": 8.5 + } + }], + "attributes": { + "eui": "1020304080706050" + } +}, { + "deviceName": "Gateway 1020304081716151", + "deviceType": "Lora gateway", + "telemetry": [{ + "ts": 1690901260495, + "values": { + "rssi": -42, + "snr": 8.8 + } + }], + "attributes": { + "eui": "1020304081716151" + } +}] \ No newline at end of file diff --git a/VENDORS/Milesight/AM307/LORIOT/uplink/converter.json b/VENDORS/Milesight/AM307/LORIOT/uplink/converter.json index 267c88d9..b947c6f9 100644 --- a/VENDORS/Milesight/AM307/LORIOT/uplink/converter.json +++ b/VENDORS/Milesight/AM307/LORIOT/uplink/converter.json @@ -1,11 +1,16 @@ { "name": "Uplink data converter for Loriot integration AM-307", "type": "UPLINK", - "debugMode": true, + "debugMode": false, + "debugSettings": { + "failuresEnabled": true, + "allEnabled": false, + "allEnabledUntil": 1735208030138 + }, "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);\nvar deviceName = \"AM307 \" + data.EUI;\nvar deviceType = \"AM307\";\nvar groupName = null; // If groupName is not null - created device will be added to the entity group with such name.\nvar customerName = null; // If customerName is not null - created devices will be assigned to customer with such name. \n\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// If you want to parse incoming data somehow, you can add your code to this function.\n// input: bytes\n// expected output:\n// {\n// \"attributes\": {\"attributeKey\": \"attributeValue\"},\n// \"telemetry\": {\"telemetryKey\": \"telemetryValue\"}\n// }\n\nfunction decodePayload(input) {\n var output = { attributes: {}, telemetry: []};\n \n // --- Decoding code --- //\n var decoded = {};\n var historyData = {};\n for (var i = 0; i < input.length - 2; ) {\n var channel_id = input[i++] & 0xff;\n var channel_type = input[i++] & 0xff;\n // BATTERY\n if(channel_id === 0x01 && channel_type === 0x75) {\n decoded.battery = input[i]; \n i += 1;\n }\n // TEMPERATURE\n if (channel_id === 0x03 && channel_type === 0x67) {\n // ℃\n decoded.temperature = parseBytesToInt(input, i, 2, false) / 10;\n // ℉\n // decoded.temperature = parseBytesToInt(input, i, 2, false) / 10 * 1.8 + 32;\n i += 2;\n }\n // HUMIDITY\n if (channel_id === 0x04 && channel_type === 0x68) {\n decoded.humidity = parseBytesToInt(input, i, 1, false) / 2;\n i += 1;\n }\n // PIR\n if (channel_id === 0x05 && channel_type === 0x00) {\n decoded.pir = input[i] === 1 ? \"trigger\" : \"idle\";\n i += 1;\n }\n // LIGHT\n if (channel_id === 0x06 && channel_type === 0xcb) {\n decoded.light_level = input[i];\n i += 1;\n }\n // CO2\n if (channel_id === 0x07 && channel_type === 0x7d) {\n decoded.co2 = parseBytesToInt(input, i, 2, false);\n i += 2;\n }\n // TVOC\n if (channel_id === 0x08 && channel_type === 0x7d) {\n decoded.tvoc = parseBytesToInt(input, i, 2, false);\n i += 2;\n }\n // PRESSURE\n if (channel_id === 0x09 && channel_type === 0x73) {\n decoded.pressure = parseBytesToInt(input, i, 2, false) / 10;\n i += 2;\n }\n // BEEP\n if (channel_id === 0x0e && channel_type === 0x01) {\n decoded.beep = input[i] === 1 ? \"yes\" : \"no\";\n i += 1;\n }\n // HISTORY DATA\n if (channel_id === 0x20 && channel_type === 0xce) {\n var historyData = {\n ts: parseBytesToInt(input, i, 4, false) * 1000,\n values: {\n temperature: parseBytesToInt(input, i + 4, 2, false) / 10,\n humidity: parseBytesToInt(input, i + 6, 2, false) / 2,\n pir: input[i + 8] === 1 ? \"trigger\" : \"idle\",\n light_level: input[i + 9],\n co2: parseBytesToInt(input, i + 10, 2, false),\n tvoc: parseBytesToInt(input, i + 12, 2, false),\n pressure: parseBytesToInt(input, i + 14, 2, false) / 10\n }\n };\n \n i += 16;\n }\n }\n \n output.telemetry = [{\n ts: timestamp,\n values: decoded\n }, historyData];\n\n // --- Decoding code --- //\n return output;\n}\n\n// --- attributes and telemetry objects ---\nvar telemetry = [];\nvar attributes = {};\n// --- attributes and telemetry objects ---\n\n// --- Timestamp parsing\ntimestamp = data.ts;\n// --- Timestamp parsing\n\n// Message parsing\n// To avoid paths in the decoded objects we passing false value to function as \"pathInKey\" argument.\n// Warning: pathInKey can cause already found fields to be overwritten with the last value found.\n\nvar uplinkDataList = [];\n\n// Passing incoming bytes to decodePayload function, to get custom decoding\nvar customDecoding = decodePayload(hexToBytes(data.data));\n\n// Collecting data to result\nif (customDecoding.?telemetry.size() > 0) {\n if (customDecoding.telemetry instanceof java.util.ArrayList) {\n foreach(telemetryObj: customDecoding.telemetry) {\n if (telemetryObj.ts != null && telemetryObj.values != null) {\n telemetry.add(telemetryObj);\n }\n }\n } else {\n telemetry.putAll(customDecoding.telemetry);\n }\n}\n\nif (customDecoding.?attributes.size() > 0) {\n attributes.putAll(customDecoding.attributes);\n}\n\n// You can add some keys manually to attributes or telemetry\nattributes.eui = data.EUI;\nattributes.fPort = data.port;\nattributes.frequency = data.freq;\n\nvar addDataToTelemetry = {};\naddDataToTelemetry.rssi = data.rssi;\naddDataToTelemetry.seqno = data.seqno;\naddDataToTelemetry.snr = data.snr;\naddDataToTelemetry.ack = data.ack;\naddDataToTelemetry.toa = data.toa;\naddDataToTelemetry.fCnt = data.fcnt;\n\nvar isIncludeGatewayInfo = metadata[\"includeGatewayInfo\"];\nif(isIncludeGatewayInfo == true) {\n telemetry = processTelemetryData(telemetry, addDataToTelemetry);\n}\n\nvar deviceInfo = {\n deviceName: deviceName,\n deviceType: deviceType,\n// assetName: assetName,\n// assetType: assetType,\n attributes: attributes,\n telemetry: telemetry, \n};\n\naddAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName);\n\nuplinkDataList.add(deviceInfo);\n\nvar includeGatewayInfo = [\"ts\", \"gweui\", \"rssi\"];\n\nvar gatewayDeviceNamePrefix = \"Gateway \";\nvar gatewayDeviceType = \"Lora gateway\";\nvar gatewayGroupName = null; // If gatewayGroupName is not null - created device will be added to the entity group with such name.\n\nif (data.cmd == \"gw\") {\n foreach( gatewayInfo : data.gws ) {\n var gatewayInfoMsg = {\n deviceName: gatewayDeviceNamePrefix + gatewayInfo.gweui,\n deviceType: gatewayDeviceType,\n telemetry: [{\n \"ts\": parseDateToTimestamp(gatewayInfo.ts),\n \"values\": getDataList(gatewayInfo, includeGatewayInfo)\n }],\n attributes: {\n eui: gatewayInfo.gweui\n }\n };\n addAdditionalInfoForDeviceMsg(gatewayInfoMsg, customerName, gatewayGroupName);\n uplinkDataList.add(gatewayInfoMsg);\n }\n}\n\nreturn uplinkDataList;\n\nfunction addAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName) {\n if (customerName != null) {\n deviceInfo.customerName = customerName;\n }\n if (groupName != null) {\n deviceInfo.groupName = groupName;\n }\n}\n\nfunction parseDateToTimestamp(dateString) {\n var timestamp = -1;\n if (dateString != null) {\n \n timestamp = new Date(dateString).getTime();\n if (timestamp == -1) {\n var secondsSeparatorIndex = dateString.lastIndexOf('.') + 1;\n var millisecondsEndIndex = dateString.lastIndexOf('+');\n if (millisecondsEndIndex == -1) {\n millisecondsEndIndex = dateString.lastIndexOf('Z');\n }\n if (millisecondsEndIndex == -1) {\n millisecondsEndIndex = dateString.lastIndexOf('-');\n }\n if (millisecondsEndIndex == -1) {\n if (dateString.length >= secondsSeparatorIndex + 3) {\n dateString = dateString.substring(0, secondsSeparatorIndex + 3);\n }\n } else {\n dateString = dateString.substring(0, secondsSeparatorIndex + 3) +\n dateString.substring(millisecondsEndIndex, dateString.length);\n }\n \n timestamp = new Date(dateString).getTime();\n }\n }\n // If we cannot parse timestamp - we will use the current timestamp\n if (timestamp == -1) {\n timestamp = Date.now();\n }\n \n return timestamp;\n}\n\nfunction processTelemetryData(telemetry, addDataToTelemetry) {\n if (telemetry.size > 1) {\n telemetry = addDataToMultipleTelemetries(telemetry, addDataToTelemetry);\n }\n else if (telemetry.size == 1) {\n telemetry = addDataToSingleTelemetry(telemetry, addDataToTelemetry);\n }\n else {\n telemetry.add(addDataToTelemetry);\n }\n \n return telemetry;\n}\n\nfunction addDataToMultipleTelemetries(telemetry, addDataToTelemetry) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[0][\"values\"].keys.contains(element.key)) {\n telemetry[0][\"values\"][element.key] = element.value;\n }\n if (!telemetry[1][\"values\"].keys.contains(element.key)) {\n telemetry[1][\"values\"][element.key] = element.value;\n }\n }\n \n return telemetry;\n}\n\nfunction addDataToSingleTelemetry(telemetry, addDataToTelemetry) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[0][\"values\"].keys.contains(element.key)) {\n telemetry[0][\"values\"][element.key] = element.value;\n }\n }\n \n return telemetry;\n}", + "tbelDecoder": "var data = decodeToJson(payload);\nvar deviceName = \"AM307 \" + data.EUI;\nvar deviceType = \"AM307\";\nvar groupName = null; // If groupName is not null - created device will be added to the entity group with such name.\nvar customerName = null; // If customerName is not null - created devices will be assigned to customer with such name. \n\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// If you want to parse incoming data somehow, you can add your code to this function.\n// input: bytes\n// expected output:\n// {\n// \"attributes\": {\"attributeKey\": \"attributeValue\"},\n// \"telemetry\": {\"telemetryKey\": \"telemetryValue\"}\n// }\n\nfunction decodePayload(input) {\n var output = { attributes: {}, telemetry: []};\n \n // --- Decoding code --- //\n var decoded = {};\n var historyDataList = [];\n for (var i = 0; i < input.length - 2; ) {\n var channel_id = input[i++] & 0xff;\n var channel_type = input[i++] & 0xff;\n // BATTERY\n if(channel_id === 0x01 && channel_type === 0x75) {\n decoded.battery = input[i]; \n i += 1;\n }\n // TEMPERATURE\n if (channel_id === 0x03 && channel_type === 0x67) {\n // ℃\n decoded.temperature = parseBytesToInt(input, i, 2, false) / 10;\n // ℉\n // decoded.temperature = parseBytesToInt(input, i, 2, false) / 10 * 1.8 + 32;\n i += 2;\n }\n // HUMIDITY\n if (channel_id === 0x04 && channel_type === 0x68) {\n decoded.humidity = parseBytesToInt(input, i, 1, false) / 2;\n i += 1;\n }\n // PIR\n if (channel_id === 0x05 && channel_type === 0x00) {\n decoded.pir = input[i] === 1 ? \"trigger\" : \"idle\";\n i += 1;\n }\n // LIGHT\n if (channel_id === 0x06 && channel_type === 0xcb) {\n decoded.light_level = input[i];\n i += 1;\n }\n // CO2\n if (channel_id === 0x07 && channel_type === 0x7d) {\n decoded.co2 = parseBytesToInt(input, i, 2, false);\n i += 2;\n }\n // TVOC\n if (channel_id === 0x08 && channel_type === 0x7d) {\n decoded.tvoc = parseBytesToInt(input, i, 2, false);\n i += 2;\n }\n // PRESSURE\n if (channel_id === 0x09 && channel_type === 0x73) {\n decoded.pressure = parseBytesToInt(input, i, 2, false) / 10;\n i += 2;\n }\n // BEEP\n if (channel_id === 0x0e && channel_type === 0x01) {\n decoded.beep = input[i] === 1 ? \"yes\" : \"no\";\n i += 1;\n }\n // HISTORY DATA\n if (channel_id === 0x20 && channel_type === 0xce) {\n var historyData = {\n ts: parseBytesToInt(input, i, 4, false) * 1000,\n values: {\n temperature: parseBytesToInt(input, i + 4, 2, false) / 10,\n humidity: parseBytesToInt(input, i + 6, 2, false) / 2,\n pir: input[i + 8] === 1 ? \"trigger\" : \"idle\",\n light_level: input[i + 9],\n co2: parseBytesToInt(input, i + 10, 2, false),\n tvoc: parseBytesToInt(input, i + 12, 2, false),\n pressure: parseBytesToInt(input, i + 14, 2, false) / 10\n }\n };\n \n historyDataList.add(historyData);\n \n i += 16;\n }\n }\n \n output.telemetry = [{\n ts: timestamp,\n values: decoded\n }];\n \n output.telemetry.addAll(historyDataList);\n\n // --- Decoding code --- //\n return output;\n}\n\n// --- attributes and telemetry objects ---\nvar telemetry = [];\nvar attributes = {};\n// --- attributes and telemetry objects ---\n\n// --- Timestamp parsing\ntimestamp = data.ts;\n// --- Timestamp parsing\n\n// Message parsing\n// To avoid paths in the decoded objects we passing false value to function as \"pathInKey\" argument.\n// Warning: pathInKey can cause already found fields to be overwritten with the last value found.\n\nvar uplinkDataList = [];\n\n// Passing incoming bytes to decodePayload function, to get custom decoding\nvar customDecoding = decodePayload(hexToBytes(data.data));\n\n// Collecting data to result\nif (customDecoding.?telemetry.size() > 0) {\n if (customDecoding.telemetry instanceof java.util.ArrayList) {\n foreach(telemetryObj: customDecoding.telemetry) {\n if (telemetryObj.ts != null && telemetryObj.values != null) {\n telemetry.add(telemetryObj);\n }\n }\n } else {\n telemetry.putAll(customDecoding.telemetry);\n }\n}\n\nif (customDecoding.?attributes.size() > 0) {\n attributes.putAll(customDecoding.attributes);\n}\n\n// You can add some keys manually to attributes or telemetry\nattributes.eui = data.EUI;\nattributes.fPort = data.port;\nattributes.frequency = data.freq;\n\nvar addDataToTelemetry = {};\naddDataToTelemetry.rssi = data.rssi;\naddDataToTelemetry.seqno = data.seqno;\naddDataToTelemetry.snr = data.snr;\naddDataToTelemetry.ack = data.ack;\naddDataToTelemetry.toa = data.toa;\naddDataToTelemetry.fCnt = data.fcnt;\n\nvar isIncludeGatewayInfo = metadata[\"includeGatewayInfo\"];\nif(isIncludeGatewayInfo == true) {\n telemetry = processTelemetryData(telemetry, addDataToTelemetry);\n}\n\nvar deviceInfo = {\n deviceName: deviceName,\n deviceType: deviceType,\n// assetName: assetName,\n// assetType: assetType,\n attributes: attributes,\n telemetry: telemetry, \n};\n\naddAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName);\n\nuplinkDataList.add(deviceInfo);\n\nvar gatewayDeviceNamePrefix = \"Gateway \";\nvar gatewayDeviceType = \"Lora gateway\";\nvar gatewayGroupName = null; // If gatewayGroupName is not null - created device will be added to the entity group with such name.\n\nif (data.cmd == \"gw\") {\n foreach( gatewayInfo : data.gws ) {\n var addGatewayInfo = {};\n\n // You can add some keys manually telemetry\n addGatewayInfo.rssi = gatewayInfo.rssi;\n addGatewayInfo.snr = gatewayInfo.snr;\n // You can add some keys manually telemetry\n \n var gatewayInfoMsg = {\n deviceName: gatewayDeviceNamePrefix + gatewayInfo.gweui,\n deviceType: gatewayDeviceType,\n telemetry: [{\n \"ts\": gatewayInfo.ts,\n \"values\": addGatewayInfo\n }],\n attributes: {\n eui: gatewayInfo.gweui\n }\n };\n addAdditionalInfoForDeviceMsg(gatewayInfoMsg, customerName, gatewayGroupName);\n uplinkDataList.add(gatewayInfoMsg);\n }\n}\n\nreturn uplinkDataList;\n\nfunction addAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName) {\n if (customerName != null) {\n deviceInfo.customerName = customerName;\n }\n if (groupName != null) {\n deviceInfo.groupName = groupName;\n }\n}\n\nfunction parseDateToTimestamp(dateString) {\n var timestamp = -1;\n if (dateString != null) {\n \n timestamp = new Date(dateString).getTime();\n if (timestamp == -1) {\n var secondsSeparatorIndex = dateString.lastIndexOf('.') + 1;\n var millisecondsEndIndex = dateString.lastIndexOf('+');\n if (millisecondsEndIndex == -1) {\n millisecondsEndIndex = dateString.lastIndexOf('Z');\n }\n if (millisecondsEndIndex == -1) {\n millisecondsEndIndex = dateString.lastIndexOf('-');\n }\n if (millisecondsEndIndex == -1) {\n if (dateString.length >= secondsSeparatorIndex + 3) {\n dateString = dateString.substring(0, secondsSeparatorIndex + 3);\n }\n } else {\n dateString = dateString.substring(0, secondsSeparatorIndex + 3) +\n dateString.substring(millisecondsEndIndex, dateString.length);\n }\n \n timestamp = new Date(dateString).getTime();\n }\n }\n // If we cannot parse timestamp - we will use the current timestamp\n if (timestamp == -1) {\n timestamp = Date.now();\n }\n \n return timestamp;\n}\n\nfunction processTelemetryData(telemetry, addDataToTelemetry) {\n if (telemetry.size >= 1) {\n telemetry = addDataToTelemetries(telemetry, addDataToTelemetry);\n }\n else {\n telemetry.add(addDataToTelemetry);\n }\n \n return telemetry;\n}\n\nfunction addDataToTelemetries(telemetries, addDataToTelemetry) {\n foreach(telemetry : telemetries) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[\"values\"].keys.contains(element.key)) {\n telemetry[\"values\"][element.key] = element.value;\n }\n } \n }\n \n return telemetries;\n}", "encoder": null, "tbelEncoder": null, "updateOnlyKeys": [ diff --git a/VENDORS/Milesight/AM307/LORIOT/uplink/payload_2.json b/VENDORS/Milesight/AM307/LORIOT/uplink/payload_2.json new file mode 100644 index 00000000..313d704f --- /dev/null +++ b/VENDORS/Milesight/AM307/LORIOT/uplink/payload_2.json @@ -0,0 +1,32 @@ +{ + "cmd": "gw", + "seqno": 4, + "EUI": "0102030405060708", + "ts": 1690901260493, + "fcnt": 3, + "port": 207, + "freq": 868300000, + "toa": 1319, + "dr": "SF12 BW125 4/5", + "ack": false, + "gws": [ + { + "rssi": -38, + "snr": 8.5, + "ts": 1690901260493, + "time": "2023-08-01T14:47:40.493Z", + "gweui": "1020304080706050", + "ant": 0 + }, + { + "rssi": -42, + "snr": 8.8, + "ts": 1690901260495, + "time": "2023-08-01T14:47:40.495Z", + "gweui": "1020304081716151", + "ant": 0 + } + ], + "bat": 143, + "data": "0175550367ee0004687c05000106cb02077da803087d2500097366270a7d04000b7d20000c7d30000d7d20000e015520ce6535ca0c00e1006e016401c2000a279700190032" +} diff --git a/VENDORS/Milesight/AM307/LORIOT/uplink/result_2.json b/VENDORS/Milesight/AM307/LORIOT/uplink/result_2.json new file mode 100644 index 00000000..c2c8646d --- /dev/null +++ b/VENDORS/Milesight/AM307/LORIOT/uplink/result_2.json @@ -0,0 +1,60 @@ +[{ + "deviceName": "AM307 0102030405060708", + "deviceType": "AM307", + "attributes": { + "eui": "0102030405060708", + "fPort": 207, + "frequency": 868300000 + }, + "telemetry": [{ + "ts": 1690901260493, + "values": { + "battery": 85, + "temperature": 23.8, + "humidity": 62.0, + "pir": "trigger", + "light_level": 2, + "co2": 936, + "tvoc": 37, + "pressure": 1008.6, + "beep": "no" + } + }, { + "ts": 214578533000, + "values": { + "temperature": 5760.0, + "humidity": 14080.0, + "trigger": "idle", + "light_level": 100, + "co2": 49665, + "tvoc": 2560, + "pressure": 3869.5 + } + }] +}, { + "deviceName": "Gateway 1020304080706050", + "deviceType": "Lora gateway", + "telemetry": [{ + "ts": 1690901260493, + "values": { + "rssi": -38, + "snr": 8.5 + } + }], + "attributes": { + "eui": "1020304080706050" + } +}, { + "deviceName": "Gateway 1020304081716151", + "deviceType": "Lora gateway", + "telemetry": [{ + "ts": 1690901260495, + "values": { + "rssi": -42, + "snr": 8.8 + } + }], + "attributes": { + "eui": "1020304081716151" + } +}] \ No newline at end of file diff --git a/VENDORS/Milesight/AM307L/LORIOT/uplink/converter.json b/VENDORS/Milesight/AM307L/LORIOT/uplink/converter.json index 5fc200c7..9077b685 100644 --- a/VENDORS/Milesight/AM307L/LORIOT/uplink/converter.json +++ b/VENDORS/Milesight/AM307L/LORIOT/uplink/converter.json @@ -1,11 +1,16 @@ { "name": "Uplink data converter for Loriot integration AM-307L", "type": "UPLINK", - "debugMode": true, + "debugMode": false, + "debugSettings": { + "failuresEnabled": true, + "allEnabled": false, + "allEnabledUntil": 1735208254904 + }, "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);\nvar deviceName = \"AM307L \" + data.EUI;\nvar deviceType = \"AM307L\";\nvar groupName = null; // If groupName is not null - created device will be added to the entity group with such name.\nvar customerName = null; // If customerName is not null - created devices will be assigned to customer with such name. \n\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// If you want to parse incoming data somehow, you can add your code to this function.\n// input: bytes\n// expected output:\n// {\n// \"attributes\": {\"attributeKey\": \"attributeValue\"},\n// \"telemetry\": {\"telemetryKey\": \"telemetryValue\"}\n// }\n\nfunction decodePayload(input) {\n var output = { attributes: {}, telemetry: []};\n \n // --- Decoding code --- //\n var decoded = {};\n var historyData = {};\n for (var i = 0; i < input.length - 2; ) {\n var channel_id = input[i++] & 0xff;\n var channel_type = input[i++] & 0xff;\n // BATTERY\n if(channel_id === 0x01 && channel_type === 0x75) {\n decoded.battery = input[i]; \n i += 1;\n }\n // TEMPERATURE\n if (channel_id === 0x03 && channel_type === 0x67) {\n // ℃\n decoded.temperature = parseBytesToInt(input, i, 2, false) / 10;\n // ℉\n // decoded.temperature = parseBytesToInt(input, i, 2, false) / 10 * 1.8 + 32;\n i += 2;\n }\n // HUMIDITY\n if (channel_id === 0x04 && channel_type === 0x68) {\n decoded.humidity = parseBytesToInt(input, i, 1, false) / 2;\n i += 1;\n }\n // PIR\n if (channel_id === 0x05 && channel_type === 0x00) {\n decoded.pir = input[i] === 1 ? \"trigger\" : \"idle\";\n i += 1;\n }\n // LIGHT\n if (channel_id === 0x06 && channel_type === 0xcb) {\n decoded.light_level = input[i];\n i += 1;\n }\n // CO2\n if (channel_id === 0x07 && channel_type === 0x7d) {\n decoded.co2 = parseBytesToInt(input, i, 2, false);\n i += 2;\n }\n // TVOC\n if (channel_id === 0x08 && channel_type === 0x7d) {\n decoded.tvoc = parseBytesToInt(input, i, 2, false);\n i += 2;\n }\n // PRESSURE\n if (channel_id === 0x09 && channel_type === 0x73) {\n decoded.pressure = parseBytesToInt(input, i, 2, false) / 10;\n i += 2;\n }\n // BEEP\n if (channel_id === 0x0e && channel_type === 0x01) {\n decoded.beep = input[i] === 1 ? \"yes\" : \"no\";\n i += 1;\n }\n // HISTORY DATA\n if (channel_id === 0x20 && channel_type === 0xce) {\n var historyData = {\n ts: parseBytesToInt(input, i, 4, false) * 1000,\n values: {\n temperature: parseBytesToInt(input, i + 4, 2, false) / 10,\n humidity: parseBytesToInt(input, i + 6, 2, false) / 2,\n pir: input[i + 8] === 1 ? \"trigger\" : \"idle\",\n light_level: input[i + 9],\n co2: parseBytesToInt(input, i + 10, 2, false),\n tvoc: parseBytesToInt(input, i + 12, 2, false),\n pressure: parseBytesToInt(input, i + 14, 2, false) / 10\n }\n };\n \n i += 16;\n }\n }\n \n output.telemetry = [{\n ts: timestamp,\n values: decoded\n }, historyData];\n\n // --- Decoding code --- //\n return output;\n}\n\n// --- attributes and telemetry objects ---\nvar telemetry = [];\nvar attributes = {};\n// --- attributes and telemetry objects ---\n\n// --- Timestamp parsing\ntimestamp = data.ts;\n// --- Timestamp parsing\n\n// Message parsing\n// To avoid paths in the decoded objects we passing false value to function as \"pathInKey\" argument.\n// Warning: pathInKey can cause already found fields to be overwritten with the last value found.\n\nvar uplinkDataList = [];\n\n// Passing incoming bytes to decodePayload function, to get custom decoding\nvar customDecoding = decodePayload(hexToBytes(data.data));\n\n// Collecting data to result\nif (customDecoding.?telemetry.size() > 0) {\n if (customDecoding.telemetry instanceof java.util.ArrayList) {\n foreach(telemetryObj: customDecoding.telemetry) {\n if (telemetryObj.ts != null && telemetryObj.values != null) {\n telemetry.add(telemetryObj);\n }\n }\n } else {\n telemetry.putAll(customDecoding.telemetry);\n }\n}\n\nif (customDecoding.?attributes.size() > 0) {\n attributes.putAll(customDecoding.attributes);\n}\n\n// You can add some keys manually to attributes or telemetry\nattributes.eui = data.EUI;\nattributes.fPort = data.port;\nattributes.frequency = data.freq;\n\nvar addDataToTelemetry = {};\naddDataToTelemetry.rssi = data.rssi;\naddDataToTelemetry.seqno = data.seqno;\naddDataToTelemetry.snr = data.snr;\naddDataToTelemetry.ack = data.ack;\naddDataToTelemetry.toa = data.toa;\naddDataToTelemetry.fCnt = data.fcnt;\n\nvar isIncludeGatewayInfo = metadata[\"includeGatewayInfo\"];\nif(isIncludeGatewayInfo == true) {\n telemetry = processTelemetryData(telemetry, addDataToTelemetry);\n}\n\nvar deviceInfo = {\n deviceName: deviceName,\n deviceType: deviceType,\n// assetName: assetName,\n// assetType: assetType,\n attributes: attributes,\n telemetry: telemetry, \n};\n\naddAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName);\n\nuplinkDataList.add(deviceInfo);\n\nvar includeGatewayInfo = [\"ts\", \"gweui\", \"rssi\"];\n\nvar gatewayDeviceNamePrefix = \"Gateway \";\nvar gatewayDeviceType = \"Lora gateway\";\nvar gatewayGroupName = null; // If gatewayGroupName is not null - created device will be added to the entity group with such name.\n\nif (data.cmd == \"gw\") {\n foreach( gatewayInfo : data.gws ) {\n var gatewayInfoMsg = {\n deviceName: gatewayDeviceNamePrefix + gatewayInfo.gweui,\n deviceType: gatewayDeviceType,\n telemetry: [{\n \"ts\": parseDateToTimestamp(gatewayInfo.ts),\n \"values\": getDataList(gatewayInfo, includeGatewayInfo)\n }],\n attributes: {\n eui: gatewayInfo.gweui\n }\n };\n addAdditionalInfoForDeviceMsg(gatewayInfoMsg, customerName, gatewayGroupName);\n uplinkDataList.add(gatewayInfoMsg);\n }\n}\n\nreturn uplinkDataList;\n\nfunction addAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName) {\n if (customerName != null) {\n deviceInfo.customerName = customerName;\n }\n if (groupName != null) {\n deviceInfo.groupName = groupName;\n }\n}\n\nfunction parseDateToTimestamp(dateString) {\n var timestamp = -1;\n if (dateString != null) {\n \n timestamp = new Date(dateString).getTime();\n if (timestamp == -1) {\n var secondsSeparatorIndex = dateString.lastIndexOf('.') + 1;\n var millisecondsEndIndex = dateString.lastIndexOf('+');\n if (millisecondsEndIndex == -1) {\n millisecondsEndIndex = dateString.lastIndexOf('Z');\n }\n if (millisecondsEndIndex == -1) {\n millisecondsEndIndex = dateString.lastIndexOf('-');\n }\n if (millisecondsEndIndex == -1) {\n if (dateString.length >= secondsSeparatorIndex + 3) {\n dateString = dateString.substring(0, secondsSeparatorIndex + 3);\n }\n } else {\n dateString = dateString.substring(0, secondsSeparatorIndex + 3) +\n dateString.substring(millisecondsEndIndex, dateString.length);\n }\n \n timestamp = new Date(dateString).getTime();\n }\n }\n // If we cannot parse timestamp - we will use the current timestamp\n if (timestamp == -1) {\n timestamp = Date.now();\n }\n \n return timestamp;\n}\n\nfunction processTelemetryData(telemetry, addDataToTelemetry) {\n if (telemetry.size > 1) {\n telemetry = addDataToMultipleTelemetries(telemetry, addDataToTelemetry);\n }\n else if (telemetry.size == 1) {\n telemetry = addDataToSingleTelemetry(telemetry, addDataToTelemetry);\n }\n else {\n telemetry.add(addDataToTelemetry);\n }\n \n return telemetry;\n}\n\nfunction addDataToMultipleTelemetries(telemetry, addDataToTelemetry) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[0][\"values\"].keys.contains(element.key)) {\n telemetry[0][\"values\"][element.key] = element.value;\n }\n if (!telemetry[1][\"values\"].keys.contains(element.key)) {\n telemetry[1][\"values\"][element.key] = element.value;\n }\n }\n \n return telemetry;\n}\n\nfunction addDataToSingleTelemetry(telemetry, addDataToTelemetry) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[0][\"values\"].keys.contains(element.key)) {\n telemetry[0][\"values\"][element.key] = element.value;\n }\n }\n \n return telemetry;\n}", + "tbelDecoder": "var data = decodeToJson(payload);\nvar deviceName = \"AM307L \" + data.EUI;\nvar deviceType = \"AM307L\";\nvar groupName = null; // If groupName is not null - created device will be added to the entity group with such name.\nvar customerName = null; // If customerName is not null - created devices will be assigned to customer with such name. \n\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// If you want to parse incoming data somehow, you can add your code to this function.\n// input: bytes\n// expected output:\n// {\n// \"attributes\": {\"attributeKey\": \"attributeValue\"},\n// \"telemetry\": {\"telemetryKey\": \"telemetryValue\"}\n// }\n\nfunction decodePayload(input) {\n var output = { attributes: {}, telemetry: []};\n \n // --- Decoding code --- //\n var decoded = {};\n var historyData = {};\n for (var i = 0; i < input.length - 2; ) {\n var channel_id = input[i++] & 0xff;\n var channel_type = input[i++] & 0xff;\n // BATTERY\n if(channel_id === 0x01 && channel_type === 0x75) {\n decoded.battery = input[i]; \n i += 1;\n }\n // TEMPERATURE\n if (channel_id === 0x03 && channel_type === 0x67) {\n // ℃\n decoded.temperature = parseBytesToInt(input, i, 2, false) / 10;\n // ℉\n // decoded.temperature = parseBytesToInt(input, i, 2, false) / 10 * 1.8 + 32;\n i += 2;\n }\n // HUMIDITY\n if (channel_id === 0x04 && channel_type === 0x68) {\n decoded.humidity = parseBytesToInt(input, i, 1, false) / 2;\n i += 1;\n }\n // PIR\n if (channel_id === 0x05 && channel_type === 0x00) {\n decoded.pir = input[i] === 1 ? \"trigger\" : \"idle\";\n i += 1;\n }\n // LIGHT\n if (channel_id === 0x06 && channel_type === 0xcb) {\n decoded.light_level = input[i];\n i += 1;\n }\n // CO2\n if (channel_id === 0x07 && channel_type === 0x7d) {\n decoded.co2 = parseBytesToInt(input, i, 2, false);\n i += 2;\n }\n // TVOC\n if (channel_id === 0x08 && channel_type === 0x7d) {\n decoded.tvoc = parseBytesToInt(input, i, 2, false);\n i += 2;\n }\n // PRESSURE\n if (channel_id === 0x09 && channel_type === 0x73) {\n decoded.pressure = parseBytesToInt(input, i, 2, false) / 10;\n i += 2;\n }\n // BEEP\n if (channel_id === 0x0e && channel_type === 0x01) {\n decoded.beep = input[i] === 1 ? \"yes\" : \"no\";\n i += 1;\n }\n // HISTORY DATA\n if (channel_id === 0x20 && channel_type === 0xce) {\n var historyData = {\n ts: parseBytesToInt(input, i, 4, false) * 1000,\n values: {\n temperature: parseBytesToInt(input, i + 4, 2, false) / 10,\n humidity: parseBytesToInt(input, i + 6, 2, false) / 2,\n pir: input[i + 8] === 1 ? \"trigger\" : \"idle\",\n light_level: input[i + 9],\n co2: parseBytesToInt(input, i + 10, 2, false),\n tvoc: parseBytesToInt(input, i + 12, 2, false),\n pressure: parseBytesToInt(input, i + 14, 2, false) / 10\n }\n };\n \n i += 16;\n }\n }\n \n output.telemetry = [{\n ts: timestamp,\n values: decoded\n }, historyData];\n\n // --- Decoding code --- //\n return output;\n}\n\n// --- attributes and telemetry objects ---\nvar telemetry = [];\nvar attributes = {};\n// --- attributes and telemetry objects ---\n\n// --- Timestamp parsing\ntimestamp = data.ts;\n// --- Timestamp parsing\n\n// Message parsing\n// To avoid paths in the decoded objects we passing false value to function as \"pathInKey\" argument.\n// Warning: pathInKey can cause already found fields to be overwritten with the last value found.\n\nvar uplinkDataList = [];\n\n// Passing incoming bytes to decodePayload function, to get custom decoding\nvar customDecoding = decodePayload(hexToBytes(data.data));\n\n// Collecting data to result\nif (customDecoding.?telemetry.size() > 0) {\n if (customDecoding.telemetry instanceof java.util.ArrayList) {\n foreach(telemetryObj: customDecoding.telemetry) {\n if (telemetryObj.ts != null && telemetryObj.values != null) {\n telemetry.add(telemetryObj);\n }\n }\n } else {\n telemetry.putAll(customDecoding.telemetry);\n }\n}\n\nif (customDecoding.?attributes.size() > 0) {\n attributes.putAll(customDecoding.attributes);\n}\n\n// You can add some keys manually to attributes or telemetry\nattributes.eui = data.EUI;\nattributes.fPort = data.port;\nattributes.frequency = data.freq;\n\nvar addDataToTelemetry = {};\naddDataToTelemetry.rssi = data.rssi;\naddDataToTelemetry.seqno = data.seqno;\naddDataToTelemetry.snr = data.snr;\naddDataToTelemetry.ack = data.ack;\naddDataToTelemetry.toa = data.toa;\naddDataToTelemetry.fCnt = data.fcnt;\n\nvar isIncludeGatewayInfo = metadata[\"includeGatewayInfo\"];\nif(isIncludeGatewayInfo == true) {\n telemetry = processTelemetryData(telemetry, addDataToTelemetry);\n}\n\nvar deviceInfo = {\n deviceName: deviceName,\n deviceType: deviceType,\n// assetName: assetName,\n// assetType: assetType,\n attributes: attributes,\n telemetry: telemetry, \n};\n\naddAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName);\n\nuplinkDataList.add(deviceInfo);\n\nvar gatewayDeviceNamePrefix = \"Gateway \";\nvar gatewayDeviceType = \"Lora gateway\";\nvar gatewayGroupName = null; // If gatewayGroupName is not null - created device will be added to the entity group with such name.\n\nif (data.cmd == \"gw\") {\n foreach( gatewayInfo : data.gws ) {\n var addGatewayInfo = {};\n\n // You can add some keys manually telemetry\n addGatewayInfo.rssi = gatewayInfo.rssi;\n addGatewayInfo.snr = gatewayInfo.snr;\n // You can add some keys manually telemetry\n \n var gatewayInfoMsg = {\n deviceName: gatewayDeviceNamePrefix + gatewayInfo.gweui,\n deviceType: gatewayDeviceType,\n telemetry: [{\n \"ts\": gatewayInfo.ts,\n \"values\": addGatewayInfo\n }],\n attributes: {\n eui: gatewayInfo.gweui\n }\n };\n addAdditionalInfoForDeviceMsg(gatewayInfoMsg, customerName, gatewayGroupName);\n uplinkDataList.add(gatewayInfoMsg);\n }\n}\n\nreturn uplinkDataList;\n\nfunction addAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName) {\n if (customerName != null) {\n deviceInfo.customerName = customerName;\n }\n if (groupName != null) {\n deviceInfo.groupName = groupName;\n }\n}\n\nfunction parseDateToTimestamp(dateString) {\n var timestamp = -1;\n if (dateString != null) {\n \n timestamp = new Date(dateString).getTime();\n if (timestamp == -1) {\n var secondsSeparatorIndex = dateString.lastIndexOf('.') + 1;\n var millisecondsEndIndex = dateString.lastIndexOf('+');\n if (millisecondsEndIndex == -1) {\n millisecondsEndIndex = dateString.lastIndexOf('Z');\n }\n if (millisecondsEndIndex == -1) {\n millisecondsEndIndex = dateString.lastIndexOf('-');\n }\n if (millisecondsEndIndex == -1) {\n if (dateString.length >= secondsSeparatorIndex + 3) {\n dateString = dateString.substring(0, secondsSeparatorIndex + 3);\n }\n } else {\n dateString = dateString.substring(0, secondsSeparatorIndex + 3) +\n dateString.substring(millisecondsEndIndex, dateString.length);\n }\n \n timestamp = new Date(dateString).getTime();\n }\n }\n // If we cannot parse timestamp - we will use the current timestamp\n if (timestamp == -1) {\n timestamp = Date.now();\n }\n \n return timestamp;\n}\n\nfunction processTelemetryData(telemetry, addDataToTelemetry) {\n if (telemetry.size >= 1) {\n telemetry = addDataToTelemetries(telemetry, addDataToTelemetry);\n }\n else {\n telemetry.add(addDataToTelemetry);\n }\n \n return telemetry;\n}\n\nfunction addDataToTelemetries(telemetries, addDataToTelemetry) {\n foreach(telemetry : telemetries) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[\"values\"].keys.contains(element.key)) {\n telemetry[\"values\"][element.key] = element.value;\n }\n } \n }\n \n return telemetries;\n}", "encoder": null, "tbelEncoder": null, "updateOnlyKeys": [ diff --git a/VENDORS/Milesight/AM307L/LORIOT/uplink/payload_2.json b/VENDORS/Milesight/AM307L/LORIOT/uplink/payload_2.json new file mode 100644 index 00000000..313d704f --- /dev/null +++ b/VENDORS/Milesight/AM307L/LORIOT/uplink/payload_2.json @@ -0,0 +1,32 @@ +{ + "cmd": "gw", + "seqno": 4, + "EUI": "0102030405060708", + "ts": 1690901260493, + "fcnt": 3, + "port": 207, + "freq": 868300000, + "toa": 1319, + "dr": "SF12 BW125 4/5", + "ack": false, + "gws": [ + { + "rssi": -38, + "snr": 8.5, + "ts": 1690901260493, + "time": "2023-08-01T14:47:40.493Z", + "gweui": "1020304080706050", + "ant": 0 + }, + { + "rssi": -42, + "snr": 8.8, + "ts": 1690901260495, + "time": "2023-08-01T14:47:40.495Z", + "gweui": "1020304081716151", + "ant": 0 + } + ], + "bat": 143, + "data": "0175550367ee0004687c05000106cb02077da803087d2500097366270a7d04000b7d20000c7d30000d7d20000e015520ce6535ca0c00e1006e016401c2000a279700190032" +} diff --git a/VENDORS/Milesight/AM307L/LORIOT/uplink/result_2.json b/VENDORS/Milesight/AM307L/LORIOT/uplink/result_2.json new file mode 100644 index 00000000..5e5cd2d1 --- /dev/null +++ b/VENDORS/Milesight/AM307L/LORIOT/uplink/result_2.json @@ -0,0 +1,60 @@ +[{ + "deviceName": "AM307L 0102030405060708", + "deviceType": "AM307L", + "attributes": { + "eui": "0102030405060708", + "fPort": 207, + "frequency": 868300000 + }, + "telemetry": [{ + "ts": 1690901260493, + "values": { + "battery": 85, + "temperature": 23.8, + "humidity": 62.0, + "pir": "trigger", + "light_level": 2, + "co2": 936, + "tvoc": 37, + "pressure": 1008.6, + "beep": "no" + } + }, { + "ts": 214578533000, + "values": { + "temperature": 5760.0, + "humidity": 14080.0, + "trigger": "idle", + "light_level": 100, + "co2": 49665, + "tvoc": 2560, + "pressure": 3869.5 + } + }] +}, { + "deviceName": "Gateway 1020304080706050", + "deviceType": "Lora gateway", + "telemetry": [{ + "ts": 1690901260493, + "values": { + "rssi": -38, + "snr": 8.5 + } + }], + "attributes": { + "eui": "1020304080706050" + } +}, { + "deviceName": "Gateway 1020304081716151", + "deviceType": "Lora gateway", + "telemetry": [{ + "ts": 1690901260495, + "values": { + "rssi": -42, + "snr": 8.8 + } + }], + "attributes": { + "eui": "1020304081716151" + } +}] \ No newline at end of file diff --git a/VENDORS/Milesight/AM308/LORIOT/uplink/converter.json b/VENDORS/Milesight/AM308/LORIOT/uplink/converter.json index 53c4938e..a76ee69d 100644 --- a/VENDORS/Milesight/AM308/LORIOT/uplink/converter.json +++ b/VENDORS/Milesight/AM308/LORIOT/uplink/converter.json @@ -1,11 +1,16 @@ { "name": "Uplink data converter for Loriot integration AM-308", "type": "UPLINK", - "debugMode": true, + "debugMode": false, + "debugSettings": { + "failuresEnabled": true, + "allEnabled": false, + "allEnabledUntil": 1735208595731 + }, "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);\nvar deviceName = \"AM308 \" + data.EUI;\nvar deviceType = \"AM308\";\nvar groupName = null; // If groupName is not null - created device will be added to the entity group with such name.\nvar customerName = null; // If customerName is not null - created devices will be assigned to customer with such name. \n\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// If you want to parse incoming data somehow, you can add your code to this function.\n// input: bytes\n// expected output:\n// {\n// \"attributes\": {\"attributeKey\": \"attributeValue\"},\n// \"telemetry\": {\"telemetryKey\": \"telemetryValue\"}\n// }\n\nfunction decodePayload(input) {\n var output = { attributes: {}, telemetry: []};\n \n // --- Decoding code --- //\n var decoded = {};\n var historyData = {};\n for (var i = 0; i < input.length - 2; ) {\n var channel_id = input[i++] & 0xff;\n var channel_type = input[i++] & 0xff;\n // BATTERY\n if(channel_id === 0x01 && channel_type === 0x75) {\n decoded.battery = input[i]; \n i += 1;\n }\n // TEMPERATURE\n if (channel_id === 0x03 && channel_type === 0x67) {\n // ℃\n decoded.temperature = parseBytesToInt(input, i, 2, false) / 10;\n // ℉\n // decoded.temperature = parseBytesToInt(input, i, 2, false) / 10 * 1.8 + 32;\n i += 2;\n }\n // HUMIDITY\n if (channel_id === 0x04 && channel_type === 0x68) {\n decoded.humidity = parseBytesToInt(input, i, 1, false) / 2;\n i += 1;\n }\n // PIR\n if (channel_id === 0x05 && channel_type === 0x00) {\n decoded.pir = input[i] === 1 ? \"trigger\" : \"idle\";\n i += 1;\n }\n // LIGHT\n if (channel_id === 0x06 && channel_type === 0xcb) {\n decoded.light_level = input[i];\n i += 1;\n }\n // CO2\n if (channel_id === 0x07 && channel_type === 0x7d) {\n decoded.co2 = parseBytesToInt(input, i, 2, false);\n i += 2;\n }\n // TVOC\n if (channel_id === 0x08 && channel_type === 0x7d) {\n decoded.tvoc = parseBytesToInt(input, i, 2, false);\n i += 2;\n }\n // PRESSURE\n if (channel_id === 0x09 && channel_type === 0x73) {\n decoded.pressure = parseBytesToInt(input, i, 2, false) / 10;\n i += 2;\n }\n // PM2_5\n if (channel_id === 0x0b && channel_type === 0x7d) {\n decoded.pm2_5 = parseBytesToInt(input, i, 2, false);\n i += 2;\n }\n // PM10\n else if (channel_id === 0x0c && channel_type === 0x7d) {\n decoded.pm10 = parseBytesToInt(input, i, 2, false);\n i += 2;\n }\n // BEEP\n if (channel_id === 0x0e && channel_type === 0x01) {\n decoded.beep = input[i] === 1 ? \"yes\" : \"no\";\n i += 1;\n }\n // HISTORY DATA\n if (channel_id === 0x20 && channel_type === 0xce) {\n var historyData = {\n ts: parseBytesToInt(input, i, 4, false) * 1000,\n values: {\n temperature: parseBytesToInt(input, i + 4, 2, false) / 10,\n humidity: parseBytesToInt(input, i + 6, 2, false) / 2,\n pir: input[i + 8] === 1 ? \"trigger\" : \"idle\",\n light_level: input[i + 9],\n co2: parseBytesToInt(input, i + 10, 2, false),\n tvoc: parseBytesToInt(input, i + 12, 2, false),\n pressure: parseBytesToInt(input, i + 14, 2, false) / 10,\n pm2_5: parseBytesToInt(input, i + 16, 2, false),\n pm10: parseBytesToInt(input, i + 18, 2, false)\n }\n };\n \n i += 20;\n }\n }\n \n output.telemetry = [{\n ts: timestamp,\n values: decoded\n }, historyData];\n\n // --- Decoding code --- //\n return output;\n}\n\n// --- attributes and telemetry objects ---\nvar telemetry = [];\nvar attributes = {};\n// --- attributes and telemetry objects ---\n\n// --- Timestamp parsing\ntimestamp = data.ts;\n// --- Timestamp parsing\n\n// Message parsing\n// To avoid paths in the decoded objects we passing false value to function as \"pathInKey\" argument.\n// Warning: pathInKey can cause already found fields to be overwritten with the last value found.\n\nvar uplinkDataList = [];\n\n// Passing incoming bytes to decodePayload function, to get custom decoding\nvar customDecoding = decodePayload(hexToBytes(data.data));\n\n// Collecting data to result\nif (customDecoding.?telemetry.size() > 0) {\n if (customDecoding.telemetry instanceof java.util.ArrayList) {\n foreach(telemetryObj: customDecoding.telemetry) {\n if (telemetryObj.ts != null && telemetryObj.values != null) {\n telemetry.add(telemetryObj);\n }\n }\n } else {\n telemetry.putAll(customDecoding.telemetry);\n }\n}\n\nif (customDecoding.?attributes.size() > 0) {\n attributes.putAll(customDecoding.attributes);\n}\n\n// You can add some keys manually to attributes or telemetry\nattributes.eui = data.EUI;\nattributes.fPort = data.port;\nattributes.frequency = data.freq;\n\nvar addDataToTelemetry = {};\naddDataToTelemetry.rssi = data.rssi;\naddDataToTelemetry.seqno = data.seqno;\naddDataToTelemetry.snr = data.snr;\naddDataToTelemetry.ack = data.ack;\naddDataToTelemetry.toa = data.toa;\naddDataToTelemetry.fCnt = data.fcnt;\n\nvar isIncludeGatewayInfo = metadata[\"includeGatewayInfo\"];\nif(isIncludeGatewayInfo == true) {\n telemetry = processTelemetryData(telemetry, addDataToTelemetry);\n}\n\nvar deviceInfo = {\n deviceName: deviceName,\n deviceType: deviceType,\n// assetName: assetName,\n// assetType: assetType,\n attributes: attributes,\n telemetry: telemetry, \n};\n\naddAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName);\n\nuplinkDataList.add(deviceInfo);\n\nvar includeGatewayInfo = [\"ts\", \"gweui\", \"rssi\"];\n\nvar gatewayDeviceNamePrefix = \"Gateway \";\nvar gatewayDeviceType = \"Lora gateway\";\nvar gatewayGroupName = null; // If gatewayGroupName is not null - created device will be added to the entity group with such name.\n\nif (data.cmd == \"gw\") {\n foreach( gatewayInfo : data.gws ) {\n var gatewayInfoMsg = {\n deviceName: gatewayDeviceNamePrefix + gatewayInfo.gweui,\n deviceType: gatewayDeviceType,\n telemetry: [{\n \"ts\": parseDateToTimestamp(gatewayInfo.ts),\n \"values\": getDataList(gatewayInfo, includeGatewayInfo)\n }],\n attributes: {\n eui: gatewayInfo.gweui\n }\n };\n addAdditionalInfoForDeviceMsg(gatewayInfoMsg, customerName, gatewayGroupName);\n uplinkDataList.add(gatewayInfoMsg);\n }\n}\n\nreturn uplinkDataList;\n\nfunction addAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName) {\n if (customerName != null) {\n deviceInfo.customerName = customerName;\n }\n if (groupName != null) {\n deviceInfo.groupName = groupName;\n }\n}\n\nfunction parseDateToTimestamp(dateString) {\n var timestamp = -1;\n if (dateString != null) {\n \n timestamp = new Date(dateString).getTime();\n if (timestamp == -1) {\n var secondsSeparatorIndex = dateString.lastIndexOf('.') + 1;\n var millisecondsEndIndex = dateString.lastIndexOf('+');\n if (millisecondsEndIndex == -1) {\n millisecondsEndIndex = dateString.lastIndexOf('Z');\n }\n if (millisecondsEndIndex == -1) {\n millisecondsEndIndex = dateString.lastIndexOf('-');\n }\n if (millisecondsEndIndex == -1) {\n if (dateString.length >= secondsSeparatorIndex + 3) {\n dateString = dateString.substring(0, secondsSeparatorIndex + 3);\n }\n } else {\n dateString = dateString.substring(0, secondsSeparatorIndex + 3) +\n dateString.substring(millisecondsEndIndex, dateString.length);\n }\n \n timestamp = new Date(dateString).getTime();\n }\n }\n // If we cannot parse timestamp - we will use the current timestamp\n if (timestamp == -1) {\n timestamp = Date.now();\n }\n \n return timestamp;\n}\n\nfunction processTelemetryData(telemetry, addDataToTelemetry) {\n if (telemetry.size > 1) {\n telemetry = addDataToMultipleTelemetries(telemetry, addDataToTelemetry);\n }\n else if (telemetry.size == 1) {\n telemetry = addDataToSingleTelemetry(telemetry, addDataToTelemetry);\n }\n else {\n telemetry.add(addDataToTelemetry);\n }\n \n return telemetry;\n}\n\nfunction addDataToMultipleTelemetries(telemetry, addDataToTelemetry) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[0][\"values\"].keys.contains(element.key)) {\n telemetry[0][\"values\"][element.key] = element.value;\n }\n if (!telemetry[1][\"values\"].keys.contains(element.key)) {\n telemetry[1][\"values\"][element.key] = element.value;\n }\n }\n \n return telemetry;\n}\n\nfunction addDataToSingleTelemetry(telemetry, addDataToTelemetry) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[0][\"values\"].keys.contains(element.key)) {\n telemetry[0][\"values\"][element.key] = element.value;\n }\n }\n \n return telemetry;\n}", + "tbelDecoder": "var data = decodeToJson(payload);\nvar deviceName = \"AM308 \" + data.EUI;\nvar deviceType = \"AM308\";\nvar groupName = null; // If groupName is not null - created device will be added to the entity group with such name.\nvar customerName = null; // If customerName is not null - created devices will be assigned to customer with such name. \n\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// If you want to parse incoming data somehow, you can add your code to this function.\n// input: bytes\n// expected output:\n// {\n// \"attributes\": {\"attributeKey\": \"attributeValue\"},\n// \"telemetry\": {\"telemetryKey\": \"telemetryValue\"}\n// }\n\nfunction decodePayload(input) {\n var output = { attributes: {}, telemetry: []};\n \n // --- Decoding code --- //\n var decoded = {};\n var historyDataList = [];\n for (var i = 0; i < input.length - 2; ) {\n var channel_id = input[i++] & 0xff;\n var channel_type = input[i++] & 0xff;\n // BATTERY\n if(channel_id === 0x01 && channel_type === 0x75) {\n decoded.battery = input[i]; \n i += 1;\n }\n // TEMPERATURE\n if (channel_id === 0x03 && channel_type === 0x67) {\n // ℃\n decoded.temperature = parseBytesToInt(input, i, 2, false) / 10;\n // ℉\n // decoded.temperature = parseBytesToInt(input, i, 2, false) / 10 * 1.8 + 32;\n i += 2;\n }\n // HUMIDITY\n if (channel_id === 0x04 && channel_type === 0x68) {\n decoded.humidity = parseBytesToInt(input, i, 1, false) / 2;\n i += 1;\n }\n // PIR\n if (channel_id === 0x05 && channel_type === 0x00) {\n decoded.pir = input[i] === 1 ? \"trigger\" : \"idle\";\n i += 1;\n }\n // LIGHT\n if (channel_id === 0x06 && channel_type === 0xcb) {\n decoded.light_level = input[i];\n i += 1;\n }\n // CO2\n if (channel_id === 0x07 && channel_type === 0x7d) {\n decoded.co2 = parseBytesToInt(input, i, 2, false);\n i += 2;\n }\n // TVOC\n if (channel_id === 0x08 && channel_type === 0x7d) {\n decoded.tvoc = parseBytesToInt(input, i, 2, false);\n i += 2;\n }\n // PRESSURE\n if (channel_id === 0x09 && channel_type === 0x73) {\n decoded.pressure = parseBytesToInt(input, i, 2, false) / 10;\n i += 2;\n }\n // PM2_5\n if (channel_id === 0x0b && channel_type === 0x7d) {\n decoded.pm2_5 = parseBytesToInt(input, i, 2, false);\n i += 2;\n }\n // PM10\n else if (channel_id === 0x0c && channel_type === 0x7d) {\n decoded.pm10 = parseBytesToInt(input, i, 2, false);\n i += 2;\n }\n // BEEP\n if (channel_id === 0x0e && channel_type === 0x01) {\n decoded.beep = input[i] === 1 ? \"yes\" : \"no\";\n i += 1;\n }\n // HISTORY DATA\n if (channel_id === 0x20 && channel_type === 0xce) {\n var historyData = {\n ts: parseBytesToInt(input, i, 4, false) * 1000,\n values: {\n temperature: parseBytesToInt(input, i + 4, 2, false) / 10,\n humidity: parseBytesToInt(input, i + 6, 2, false) / 2,\n pir: input[i + 8] === 1 ? \"trigger\" : \"idle\",\n light_level: input[i + 9],\n co2: parseBytesToInt(input, i + 10, 2, false),\n tvoc: parseBytesToInt(input, i + 12, 2, false),\n pressure: parseBytesToInt(input, i + 14, 2, false) / 10,\n pm2_5: parseBytesToInt(input, i + 16, 2, false),\n pm10: parseBytesToInt(input, i + 18, 2, false)\n }\n };\n \n historyDataList.add(historyData);\n \n i += 20;\n }\n }\n \n output.telemetry = [{\n ts: timestamp,\n values: decoded\n }];\n \n output.telemetry.addAll(historyDataList);\n // --- Decoding code --- //\n return output;\n}\n\n// --- attributes and telemetry objects ---\nvar telemetry = [];\nvar attributes = {};\n// --- attributes and telemetry objects ---\n\n// --- Timestamp parsing\ntimestamp = data.ts;\n// --- Timestamp parsing\n\n// Message parsing\n// To avoid paths in the decoded objects we passing false value to function as \"pathInKey\" argument.\n// Warning: pathInKey can cause already found fields to be overwritten with the last value found.\n\nvar uplinkDataList = [];\n\n// Passing incoming bytes to decodePayload function, to get custom decoding\nvar customDecoding = decodePayload(hexToBytes(data.data));\n\n// Collecting data to result\nif (customDecoding.?telemetry.size() > 0) {\n if (customDecoding.telemetry instanceof java.util.ArrayList) {\n foreach(telemetryObj: customDecoding.telemetry) {\n if (telemetryObj.ts != null && telemetryObj.values != null) {\n telemetry.add(telemetryObj);\n }\n }\n } else {\n telemetry.putAll(customDecoding.telemetry);\n }\n}\n\nif (customDecoding.?attributes.size() > 0) {\n attributes.putAll(customDecoding.attributes);\n}\n\n// You can add some keys manually to attributes or telemetry\nattributes.eui = data.EUI;\nattributes.fPort = data.port;\nattributes.frequency = data.freq;\n\nvar addDataToTelemetry = {};\naddDataToTelemetry.rssi = data.rssi;\naddDataToTelemetry.seqno = data.seqno;\naddDataToTelemetry.snr = data.snr;\naddDataToTelemetry.ack = data.ack;\naddDataToTelemetry.toa = data.toa;\naddDataToTelemetry.fCnt = data.fcnt;\n\nvar isIncludeGatewayInfo = metadata[\"includeGatewayInfo\"];\nif(isIncludeGatewayInfo == true) {\n telemetry = processTelemetryData(telemetry, addDataToTelemetry);\n}\n\nvar deviceInfo = {\n deviceName: deviceName,\n deviceType: deviceType,\n// assetName: assetName,\n// assetType: assetType,\n attributes: attributes,\n telemetry: telemetry, \n};\n\naddAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName);\n\nuplinkDataList.add(deviceInfo);\n\nvar gatewayDeviceNamePrefix = \"Gateway \";\nvar gatewayDeviceType = \"Lora gateway\";\nvar gatewayGroupName = null; // If gatewayGroupName is not null - created device will be added to the entity group with such name.\n\nif (data.cmd == \"gw\") {\n foreach( gatewayInfo : data.gws ) {\n var addGatewayInfo = {};\n\n // You can add some keys manually telemetry\n addGatewayInfo.rssi = gatewayInfo.rssi;\n addGatewayInfo.snr = gatewayInfo.snr;\n // You can add some keys manually telemetry\n \n var gatewayInfoMsg = {\n deviceName: gatewayDeviceNamePrefix + gatewayInfo.gweui,\n deviceType: gatewayDeviceType,\n telemetry: [{\n \"ts\": gatewayInfo.ts,\n \"values\": addGatewayInfo\n }],\n attributes: {\n eui: gatewayInfo.gweui\n }\n };\n addAdditionalInfoForDeviceMsg(gatewayInfoMsg, customerName, gatewayGroupName);\n uplinkDataList.add(gatewayInfoMsg);\n }\n}\n\nreturn uplinkDataList;\n\nfunction addAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName) {\n if (customerName != null) {\n deviceInfo.customerName = customerName;\n }\n if (groupName != null) {\n deviceInfo.groupName = groupName;\n }\n}\n\nfunction parseDateToTimestamp(dateString) {\n var timestamp = -1;\n if (dateString != null) {\n \n timestamp = new Date(dateString).getTime();\n if (timestamp == -1) {\n var secondsSeparatorIndex = dateString.lastIndexOf('.') + 1;\n var millisecondsEndIndex = dateString.lastIndexOf('+');\n if (millisecondsEndIndex == -1) {\n millisecondsEndIndex = dateString.lastIndexOf('Z');\n }\n if (millisecondsEndIndex == -1) {\n millisecondsEndIndex = dateString.lastIndexOf('-');\n }\n if (millisecondsEndIndex == -1) {\n if (dateString.length >= secondsSeparatorIndex + 3) {\n dateString = dateString.substring(0, secondsSeparatorIndex + 3);\n }\n } else {\n dateString = dateString.substring(0, secondsSeparatorIndex + 3) +\n dateString.substring(millisecondsEndIndex, dateString.length);\n }\n \n timestamp = new Date(dateString).getTime();\n }\n }\n // If we cannot parse timestamp - we will use the current timestamp\n if (timestamp == -1) {\n timestamp = Date.now();\n }\n \n return timestamp;\n}\n\nfunction processTelemetryData(telemetry, addDataToTelemetry) {\n if (telemetry.size >= 1) {\n telemetry = addDataToTelemetries(telemetry, addDataToTelemetry);\n }\n else {\n telemetry.add(addDataToTelemetry);\n }\n \n return telemetry;\n}\n\nfunction addDataToTelemetries(telemetries, addDataToTelemetry) {\n foreach(telemetry : telemetries) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[\"values\"].keys.contains(element.key)) {\n telemetry[\"values\"][element.key] = element.value;\n }\n } \n }\n \n return telemetries;\n}", "encoder": null, "tbelEncoder": null, "updateOnlyKeys": [ diff --git a/VENDORS/Milesight/AM308/LORIOT/uplink/payload_2.json b/VENDORS/Milesight/AM308/LORIOT/uplink/payload_2.json new file mode 100644 index 00000000..79534d6c --- /dev/null +++ b/VENDORS/Milesight/AM308/LORIOT/uplink/payload_2.json @@ -0,0 +1,32 @@ +{ + "cmd": "gw", + "seqno": 4, + "EUI": "0102030405060708", + "ts": 1690901260493, + "fcnt": 3, + "port": 207, + "freq": 868300000, + "toa": 1319, + "dr": "SF12 BW125 4/5", + "ack": false, + "gws": [ + { + "rssi": -38, + "snr": 8.5, + "ts": 1690901260493, + "time": "2023-08-01T14:47:40.493Z", + "gweui": "1020304080706050", + "ant": 0 + }, + { + "rssi": -42, + "snr": 8.8, + "ts": 1690901260495, + "time": "2023-08-01T14:47:40.495Z", + "gweui": "1020304081716151", + "ant": 0 + } + ], + "bat": 143, + "data": "0175550367ee0004687c05000106cb02077da803087d2500097366270a7d04000b7d20000c7d30000d7d20000e015520ce6535ca0c00e1006e016401c2000a279700190032" +} \ No newline at end of file diff --git a/VENDORS/Milesight/AM308/LORIOT/uplink/result_2.json b/VENDORS/Milesight/AM308/LORIOT/uplink/result_2.json new file mode 100644 index 00000000..41f65138 --- /dev/null +++ b/VENDORS/Milesight/AM308/LORIOT/uplink/result_2.json @@ -0,0 +1,64 @@ +[{ + "deviceName": "AM308 0102030405060708", + "deviceType": "AM308", + "attributes": { + "eui": "0102030405060708", + "fPort": 207, + "frequency": 868300000 + }, + "telemetry": [{ + "ts": 1690901260493, + "values": { + "battery": 85, + "temperature": 23.8, + "humidity": 62.0, + "pir": "trigger", + "light_level": 2, + "co2": 936, + "tvoc": 37, + "pressure": 1008.6, + "pm2_5": 32, + "pm10": 48, + "beep": "no" + } + }, { + "ts": 214578533000, + "values": { + "temperature": 5760.0, + "humidity": 14080.0, + "trigger": "idle", + "light_level": 100, + "co2": 49665, + "tvoc": 2560, + "pressure": 3869.5, + "pm2_5": 6400, + "pm10": 12800 + } + }] +}, { + "deviceName": "Gateway 1020304080706050", + "deviceType": "Lora gateway", + "telemetry": [{ + "ts": 1690901260493, + "values": { + "rssi": -38, + "snr": 8.5 + } + }], + "attributes": { + "eui": "1020304080706050" + } +}, { + "deviceName": "Gateway 1020304081716151", + "deviceType": "Lora gateway", + "telemetry": [{ + "ts": 1690901260495, + "values": { + "rssi": -42, + "snr": 8.8 + } + }], + "attributes": { + "eui": "1020304081716151" + } +}] \ No newline at end of file diff --git a/VENDORS/Milesight/AM308L/LORIOT/uplink/converter.json b/VENDORS/Milesight/AM308L/LORIOT/uplink/converter.json index 4a086272..18290e35 100644 --- a/VENDORS/Milesight/AM308L/LORIOT/uplink/converter.json +++ b/VENDORS/Milesight/AM308L/LORIOT/uplink/converter.json @@ -1,11 +1,16 @@ { "name": "Uplink data converter for Loriot integration AM-308L", "type": "UPLINK", - "debugMode": true, + "debugMode": false, + "debugSettings": { + "failuresEnabled": true, + "allEnabled": false, + "allEnabledUntil": 1735208821523 + }, "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);\nvar deviceName = \"AM308L \" + data.EUI;\nvar deviceType = \"AM308L\";\nvar groupName = null; // If groupName is not null - created device will be added to the entity group with such name.\nvar customerName = null; // If customerName is not null - created devices will be assigned to customer with such name. \n\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// If you want to parse incoming data somehow, you can add your code to this function.\n// input: bytes\n// expected output:\n// {\n// \"attributes\": {\"attributeKey\": \"attributeValue\"},\n// \"telemetry\": {\"telemetryKey\": \"telemetryValue\"}\n// }\n\nfunction decodePayload(input) {\n var output = { attributes: {}, telemetry: []};\n \n // --- Decoding code --- //\n var decoded = {};\n var historyData = {};\n for (var i = 0; i < input.length - 2; ) {\n var channel_id = input[i++] & 0xff;\n var channel_type = input[i++] & 0xff;\n // BATTERY\n if(channel_id === 0x01 && channel_type === 0x75) {\n decoded.battery = input[i]; \n i += 1;\n }\n // TEMPERATURE\n if (channel_id === 0x03 && channel_type === 0x67) {\n // ℃\n decoded.temperature = parseBytesToInt(input, i, 2, false) / 10;\n // ℉\n // decoded.temperature = parseBytesToInt(input, i, 2, false) / 10 * 1.8 + 32;\n i += 2;\n }\n // HUMIDITY\n if (channel_id === 0x04 && channel_type === 0x68) {\n decoded.humidity = parseBytesToInt(input, i, 1, false) / 2;\n i += 1;\n }\n // PIR\n if (channel_id === 0x05 && channel_type === 0x00) {\n decoded.pir = input[i] === 1 ? \"trigger\" : \"idle\";\n i += 1;\n }\n // LIGHT\n if (channel_id === 0x06 && channel_type === 0xcb) {\n decoded.light_level = input[i];\n i += 1;\n }\n // CO2\n if (channel_id === 0x07 && channel_type === 0x7d) {\n decoded.co2 = parseBytesToInt(input, i, 2, false);\n i += 2;\n }\n // TVOC\n if (channel_id === 0x08 && channel_type === 0x7d) {\n decoded.tvoc = parseBytesToInt(input, i, 2, false);\n i += 2;\n }\n // PRESSURE\n if (channel_id === 0x09 && channel_type === 0x73) {\n decoded.pressure = parseBytesToInt(input, i, 2, false) / 10;\n i += 2;\n }\n // PM2_5\n if (channel_id === 0x0b && channel_type === 0x7d) {\n decoded.pm2_5 = parseBytesToInt(input, i, 2, false);\n i += 2;\n }\n // PM10\n else if (channel_id === 0x0c && channel_type === 0x7d) {\n decoded.pm10 = parseBytesToInt(input, i, 2, false);\n i += 2;\n }\n // BEEP\n if (channel_id === 0x0e && channel_type === 0x01) {\n decoded.beep = input[i] === 1 ? \"yes\" : \"no\";\n i += 1;\n }\n // HISTORY DATA\n if (channel_id === 0x20 && channel_type === 0xce) {\n var historyData = {\n ts: parseBytesToInt(input, i, 4, false) * 1000,\n values: {\n temperature: parseBytesToInt(input, i + 4, 2, false) / 10,\n humidity: parseBytesToInt(input, i + 6, 2, false) / 2,\n pir: input[i + 8] === 1 ? \"trigger\" : \"idle\",\n light_level: input[i + 9],\n co2: parseBytesToInt(input, i + 10, 2, false),\n tvoc: parseBytesToInt(input, i + 12, 2, false),\n pressure: parseBytesToInt(input, i + 14, 2, false) / 10,\n pm2_5: parseBytesToInt(input, i + 16, 2, false),\n pm10: parseBytesToInt(input, i + 18, 2, false)\n }\n };\n \n i += 20;\n }\n }\n \n output.telemetry = [{\n ts: timestamp,\n values: decoded\n }, historyData];\n\n // --- Decoding code --- //\n return output;\n}\n\n// --- attributes and telemetry objects ---\nvar telemetry = [];\nvar attributes = {};\n// --- attributes and telemetry objects ---\n\n// --- Timestamp parsing\ntimestamp = data.ts;\n// --- Timestamp parsing\n\n// Message parsing\n// To avoid paths in the decoded objects we passing false value to function as \"pathInKey\" argument.\n// Warning: pathInKey can cause already found fields to be overwritten with the last value found.\n\nvar uplinkDataList = [];\n\n// Passing incoming bytes to decodePayload function, to get custom decoding\nvar customDecoding = decodePayload(hexToBytes(data.data));\n\n// Collecting data to result\nif (customDecoding.?telemetry.size() > 0) {\n if (customDecoding.telemetry instanceof java.util.ArrayList) {\n foreach(telemetryObj: customDecoding.telemetry) {\n if (telemetryObj.ts != null && telemetryObj.values != null) {\n telemetry.add(telemetryObj);\n }\n }\n } else {\n telemetry.putAll(customDecoding.telemetry);\n }\n}\n\nif (customDecoding.?attributes.size() > 0) {\n attributes.putAll(customDecoding.attributes);\n}\n\n// You can add some keys manually to attributes or telemetry\nattributes.eui = data.EUI;\nattributes.fPort = data.port;\nattributes.frequency = data.freq;\n\nvar addDataToTelemetry = {};\naddDataToTelemetry.rssi = data.rssi;\naddDataToTelemetry.seqno = data.seqno;\naddDataToTelemetry.snr = data.snr;\naddDataToTelemetry.ack = data.ack;\naddDataToTelemetry.toa = data.toa;\naddDataToTelemetry.fCnt = data.fcnt;\n\nvar isIncludeGatewayInfo = metadata[\"includeGatewayInfo\"];\nif(isIncludeGatewayInfo == true) {\n telemetry = processTelemetryData(telemetry, addDataToTelemetry);\n}\n\nvar deviceInfo = {\n deviceName: deviceName,\n deviceType: deviceType,\n// assetName: assetName,\n// assetType: assetType,\n attributes: attributes,\n telemetry: telemetry, \n};\n\naddAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName);\n\nuplinkDataList.add(deviceInfo);\n\nvar includeGatewayInfo = [\"ts\", \"gweui\", \"rssi\"];\n\nvar gatewayDeviceNamePrefix = \"Gateway \";\nvar gatewayDeviceType = \"Lora gateway\";\nvar gatewayGroupName = null; // If gatewayGroupName is not null - created device will be added to the entity group with such name.\n\nif (data.cmd == \"gw\") {\n foreach( gatewayInfo : data.gws ) {\n var gatewayInfoMsg = {\n deviceName: gatewayDeviceNamePrefix + gatewayInfo.gweui,\n deviceType: gatewayDeviceType,\n telemetry: [{\n \"ts\": parseDateToTimestamp(gatewayInfo.ts),\n \"values\": getDataList(gatewayInfo, includeGatewayInfo)\n }],\n attributes: {\n eui: gatewayInfo.gweui\n }\n };\n addAdditionalInfoForDeviceMsg(gatewayInfoMsg, customerName, gatewayGroupName);\n uplinkDataList.add(gatewayInfoMsg);\n }\n}\n\nreturn uplinkDataList;\n\nfunction addAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName) {\n if (customerName != null) {\n deviceInfo.customerName = customerName;\n }\n if (groupName != null) {\n deviceInfo.groupName = groupName;\n }\n}\n\nfunction parseDateToTimestamp(dateString) {\n var timestamp = -1;\n if (dateString != null) {\n \n timestamp = new Date(dateString).getTime();\n if (timestamp == -1) {\n var secondsSeparatorIndex = dateString.lastIndexOf('.') + 1;\n var millisecondsEndIndex = dateString.lastIndexOf('+');\n if (millisecondsEndIndex == -1) {\n millisecondsEndIndex = dateString.lastIndexOf('Z');\n }\n if (millisecondsEndIndex == -1) {\n millisecondsEndIndex = dateString.lastIndexOf('-');\n }\n if (millisecondsEndIndex == -1) {\n if (dateString.length >= secondsSeparatorIndex + 3) {\n dateString = dateString.substring(0, secondsSeparatorIndex + 3);\n }\n } else {\n dateString = dateString.substring(0, secondsSeparatorIndex + 3) +\n dateString.substring(millisecondsEndIndex, dateString.length);\n }\n \n timestamp = new Date(dateString).getTime();\n }\n }\n // If we cannot parse timestamp - we will use the current timestamp\n if (timestamp == -1) {\n timestamp = Date.now();\n }\n \n return timestamp;\n}\n\nfunction processTelemetryData(telemetry, addDataToTelemetry) {\n if (telemetry.size > 1) {\n telemetry = addDataToMultipleTelemetries(telemetry, addDataToTelemetry);\n }\n else if (telemetry.size == 1) {\n telemetry = addDataToSingleTelemetry(telemetry, addDataToTelemetry);\n }\n else {\n telemetry.add(addDataToTelemetry);\n }\n \n return telemetry;\n}\n\nfunction addDataToMultipleTelemetries(telemetry, addDataToTelemetry) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[0][\"values\"].keys.contains(element.key)) {\n telemetry[0][\"values\"][element.key] = element.value;\n }\n if (!telemetry[1][\"values\"].keys.contains(element.key)) {\n telemetry[1][\"values\"][element.key] = element.value;\n }\n }\n \n return telemetry;\n}\n\nfunction addDataToSingleTelemetry(telemetry, addDataToTelemetry) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[0][\"values\"].keys.contains(element.key)) {\n telemetry[0][\"values\"][element.key] = element.value;\n }\n }\n \n return telemetry;\n}", + "tbelDecoder": "var data = decodeToJson(payload);\nvar deviceName = \"AM308L \" + data.EUI;\nvar deviceType = \"AM308L\";\nvar groupName = null; // If groupName is not null - created device will be added to the entity group with such name.\nvar customerName = null; // If customerName is not null - created devices will be assigned to customer with such name. \n\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// If you want to parse incoming data somehow, you can add your code to this function.\n// input: bytes\n// expected output:\n// {\n// \"attributes\": {\"attributeKey\": \"attributeValue\"},\n// \"telemetry\": {\"telemetryKey\": \"telemetryValue\"}\n// }\n\nfunction decodePayload(input) {\n var output = { attributes: {}, telemetry: []};\n \n // --- Decoding code --- //\n var decoded = {};\n var historyDataList = [];\n for (var i = 0; i < input.length - 2; ) {\n var channel_id = input[i++] & 0xff;\n var channel_type = input[i++] & 0xff;\n // BATTERY\n if(channel_id === 0x01 && channel_type === 0x75) {\n decoded.battery = input[i]; \n i += 1;\n }\n // TEMPERATURE\n if (channel_id === 0x03 && channel_type === 0x67) {\n // ℃\n decoded.temperature = parseBytesToInt(input, i, 2, false) / 10;\n // ℉\n // decoded.temperature = parseBytesToInt(input, i, 2, false) / 10 * 1.8 + 32;\n i += 2;\n }\n // HUMIDITY\n if (channel_id === 0x04 && channel_type === 0x68) {\n decoded.humidity = parseBytesToInt(input, i, 1, false) / 2;\n i += 1;\n }\n // PIR\n if (channel_id === 0x05 && channel_type === 0x00) {\n decoded.pir = input[i] === 1 ? \"trigger\" : \"idle\";\n i += 1;\n }\n // LIGHT\n if (channel_id === 0x06 && channel_type === 0xcb) {\n decoded.light_level = input[i];\n i += 1;\n }\n // CO2\n if (channel_id === 0x07 && channel_type === 0x7d) {\n decoded.co2 = parseBytesToInt(input, i, 2, false);\n i += 2;\n }\n // TVOC\n if (channel_id === 0x08 && channel_type === 0x7d) {\n decoded.tvoc = parseBytesToInt(input, i, 2, false);\n i += 2;\n }\n // PRESSURE\n if (channel_id === 0x09 && channel_type === 0x73) {\n decoded.pressure = parseBytesToInt(input, i, 2, false) / 10;\n i += 2;\n }\n // PM2_5\n if (channel_id === 0x0b && channel_type === 0x7d) {\n decoded.pm2_5 = parseBytesToInt(input, i, 2, false);\n i += 2;\n }\n // PM10\n else if (channel_id === 0x0c && channel_type === 0x7d) {\n decoded.pm10 = parseBytesToInt(input, i, 2, false);\n i += 2;\n }\n // BEEP\n if (channel_id === 0x0e && channel_type === 0x01) {\n decoded.beep = input[i] === 1 ? \"yes\" : \"no\";\n i += 1;\n }\n // HISTORY DATA\n if (channel_id === 0x20 && channel_type === 0xce) {\n var historyData = {\n ts: parseBytesToInt(input, i, 4, false) * 1000,\n values: {\n temperature: parseBytesToInt(input, i + 4, 2, false) / 10,\n humidity: parseBytesToInt(input, i + 6, 2, false) / 2,\n pir: input[i + 8] === 1 ? \"trigger\" : \"idle\",\n light_level: input[i + 9],\n co2: parseBytesToInt(input, i + 10, 2, false),\n tvoc: parseBytesToInt(input, i + 12, 2, false),\n pressure: parseBytesToInt(input, i + 14, 2, false) / 10,\n pm2_5: parseBytesToInt(input, i + 16, 2, false),\n pm10: parseBytesToInt(input, i + 18, 2, false)\n }\n };\n \n historyDataList.add(historyData);\n \n i += 20;\n }\n }\n \n output.telemetry = [{\n ts: timestamp,\n values: decoded\n }];\n \n output.telemetry.addAll(historyDataList);\n // --- Decoding code --- //\n return output;\n}\n\n// --- attributes and telemetry objects ---\nvar telemetry = [];\nvar attributes = {};\n// --- attributes and telemetry objects ---\n\n// --- Timestamp parsing\ntimestamp = data.ts;\n// --- Timestamp parsing\n\n// Message parsing\n// To avoid paths in the decoded objects we passing false value to function as \"pathInKey\" argument.\n// Warning: pathInKey can cause already found fields to be overwritten with the last value found.\n\nvar uplinkDataList = [];\n\n// Passing incoming bytes to decodePayload function, to get custom decoding\nvar customDecoding = decodePayload(hexToBytes(data.data));\n\n// Collecting data to result\nif (customDecoding.?telemetry.size() > 0) {\n if (customDecoding.telemetry instanceof java.util.ArrayList) {\n foreach(telemetryObj: customDecoding.telemetry) {\n if (telemetryObj.ts != null && telemetryObj.values != null) {\n telemetry.add(telemetryObj);\n }\n }\n } else {\n telemetry.putAll(customDecoding.telemetry);\n }\n}\n\nif (customDecoding.?attributes.size() > 0) {\n attributes.putAll(customDecoding.attributes);\n}\n\n// You can add some keys manually to attributes or telemetry\nattributes.eui = data.EUI;\nattributes.fPort = data.port;\nattributes.frequency = data.freq;\n\nvar addDataToTelemetry = {};\naddDataToTelemetry.rssi = data.rssi;\naddDataToTelemetry.seqno = data.seqno;\naddDataToTelemetry.snr = data.snr;\naddDataToTelemetry.ack = data.ack;\naddDataToTelemetry.toa = data.toa;\naddDataToTelemetry.fCnt = data.fcnt;\n\nvar isIncludeGatewayInfo = metadata[\"includeGatewayInfo\"];\nif(isIncludeGatewayInfo == true) {\n telemetry = processTelemetryData(telemetry, addDataToTelemetry);\n}\n\nvar deviceInfo = {\n deviceName: deviceName,\n deviceType: deviceType,\n// assetName: assetName,\n// assetType: assetType,\n attributes: attributes,\n telemetry: telemetry, \n};\n\naddAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName);\n\nuplinkDataList.add(deviceInfo);\n\nvar gatewayDeviceNamePrefix = \"Gateway \";\nvar gatewayDeviceType = \"Lora gateway\";\nvar gatewayGroupName = null; // If gatewayGroupName is not null - created device will be added to the entity group with such name.\n\nif (data.cmd == \"gw\") {\n foreach( gatewayInfo : data.gws ) {\n var addGatewayInfo = {};\n\n // You can add some keys manually telemetry\n addGatewayInfo.rssi = gatewayInfo.rssi;\n addGatewayInfo.snr = gatewayInfo.snr;\n // You can add some keys manually telemetry\n \n var gatewayInfoMsg = {\n deviceName: gatewayDeviceNamePrefix + gatewayInfo.gweui,\n deviceType: gatewayDeviceType,\n telemetry: [{\n \"ts\": gatewayInfo.ts,\n \"values\": addGatewayInfo\n }],\n attributes: {\n eui: gatewayInfo.gweui\n }\n };\n addAdditionalInfoForDeviceMsg(gatewayInfoMsg, customerName, gatewayGroupName);\n uplinkDataList.add(gatewayInfoMsg);\n }\n}\n\nreturn uplinkDataList;\n\nfunction addAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName) {\n if (customerName != null) {\n deviceInfo.customerName = customerName;\n }\n if (groupName != null) {\n deviceInfo.groupName = groupName;\n }\n}\n\nfunction parseDateToTimestamp(dateString) {\n var timestamp = -1;\n if (dateString != null) {\n \n timestamp = new Date(dateString).getTime();\n if (timestamp == -1) {\n var secondsSeparatorIndex = dateString.lastIndexOf('.') + 1;\n var millisecondsEndIndex = dateString.lastIndexOf('+');\n if (millisecondsEndIndex == -1) {\n millisecondsEndIndex = dateString.lastIndexOf('Z');\n }\n if (millisecondsEndIndex == -1) {\n millisecondsEndIndex = dateString.lastIndexOf('-');\n }\n if (millisecondsEndIndex == -1) {\n if (dateString.length >= secondsSeparatorIndex + 3) {\n dateString = dateString.substring(0, secondsSeparatorIndex + 3);\n }\n } else {\n dateString = dateString.substring(0, secondsSeparatorIndex + 3) +\n dateString.substring(millisecondsEndIndex, dateString.length);\n }\n \n timestamp = new Date(dateString).getTime();\n }\n }\n // If we cannot parse timestamp - we will use the current timestamp\n if (timestamp == -1) {\n timestamp = Date.now();\n }\n \n return timestamp;\n}\n\nfunction processTelemetryData(telemetry, addDataToTelemetry) {\n if (telemetry.size >= 1) {\n telemetry = addDataToTelemetries(telemetry, addDataToTelemetry);\n }\n else {\n telemetry.add(addDataToTelemetry);\n }\n \n return telemetry;\n}\n\nfunction addDataToTelemetries(telemetries, addDataToTelemetry) {\n foreach(telemetry : telemetries) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[\"values\"].keys.contains(element.key)) {\n telemetry[\"values\"][element.key] = element.value;\n }\n } \n }\n \n return telemetries;\n}", "encoder": null, "tbelEncoder": null, "updateOnlyKeys": [ diff --git a/VENDORS/Milesight/AM308L/LORIOT/uplink/payload_2.json b/VENDORS/Milesight/AM308L/LORIOT/uplink/payload_2.json new file mode 100644 index 00000000..313d704f --- /dev/null +++ b/VENDORS/Milesight/AM308L/LORIOT/uplink/payload_2.json @@ -0,0 +1,32 @@ +{ + "cmd": "gw", + "seqno": 4, + "EUI": "0102030405060708", + "ts": 1690901260493, + "fcnt": 3, + "port": 207, + "freq": 868300000, + "toa": 1319, + "dr": "SF12 BW125 4/5", + "ack": false, + "gws": [ + { + "rssi": -38, + "snr": 8.5, + "ts": 1690901260493, + "time": "2023-08-01T14:47:40.493Z", + "gweui": "1020304080706050", + "ant": 0 + }, + { + "rssi": -42, + "snr": 8.8, + "ts": 1690901260495, + "time": "2023-08-01T14:47:40.495Z", + "gweui": "1020304081716151", + "ant": 0 + } + ], + "bat": 143, + "data": "0175550367ee0004687c05000106cb02077da803087d2500097366270a7d04000b7d20000c7d30000d7d20000e015520ce6535ca0c00e1006e016401c2000a279700190032" +} diff --git a/VENDORS/Milesight/AM308L/LORIOT/uplink/result_2.json b/VENDORS/Milesight/AM308L/LORIOT/uplink/result_2.json new file mode 100644 index 00000000..1132e127 --- /dev/null +++ b/VENDORS/Milesight/AM308L/LORIOT/uplink/result_2.json @@ -0,0 +1,64 @@ +[{ + "deviceName": "AM308L 0102030405060708", + "deviceType": "AM308L", + "attributes": { + "eui": "0102030405060708", + "fPort": 207, + "frequency": 868300000 + }, + "telemetry": [{ + "ts": 1690901260493, + "values": { + "battery": 85, + "temperature": 23.8, + "humidity": 62.0, + "pir": "trigger", + "light_level": 2, + "co2": 936, + "tvoc": 37, + "pressure": 1008.6, + "pm2_5": 32, + "pm10": 48, + "beep": "no" + } + }, { + "ts": 214578533000, + "values": { + "temperature": 5760.0, + "humidity": 14080.0, + "trigger": "idle", + "light_level": 100, + "co2": 49665, + "tvoc": 2560, + "pressure": 3869.5, + "pm2_5": 6400, + "pm10": 12800 + } + }] +}, { + "deviceName": "Gateway 1020304080706050", + "deviceType": "Lora gateway", + "telemetry": [{ + "ts": 1690901260493, + "values": { + "rssi": -38, + "snr": 8.5 + } + }], + "attributes": { + "eui": "1020304080706050" + } +}, { + "deviceName": "Gateway 1020304081716151", + "deviceType": "Lora gateway", + "telemetry": [{ + "ts": 1690901260495, + "values": { + "rssi": -42, + "snr": 8.8 + } + }], + "attributes": { + "eui": "1020304081716151" + } +}] \ No newline at end of file diff --git a/VENDORS/Milesight/AM319/LORIOT/uplink/converter.json b/VENDORS/Milesight/AM319/LORIOT/uplink/converter.json index 181ef04d..e00c8a11 100644 --- a/VENDORS/Milesight/AM319/LORIOT/uplink/converter.json +++ b/VENDORS/Milesight/AM319/LORIOT/uplink/converter.json @@ -1,11 +1,16 @@ { "name": "Uplink data converter for Loriot integration AM-319", "type": "UPLINK", - "debugMode": true, + "debugMode": false, + "debugSettings": { + "failuresEnabled": true, + "allEnabled": false, + "allEnabledUntil": 1735209025134 + }, "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);\nvar deviceName = \"AM319 \" + data.EUI;\nvar deviceType = \"AM319\";\nvar groupName = null; // If groupName is not null - created device will be added to the entity group with such name.\nvar customerName = null; // If customerName is not null - created devices will be assigned to customer with such name. \n\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// If you want to parse incoming data somehow, you can add your code to this function.\n// input: bytes\n// expected output:\n// {\n// \"attributes\": {\"attributeKey\": \"attributeValue\"},\n// \"telemetry\": {\"telemetryKey\": \"telemetryValue\"}\n// }\n\nfunction decodePayload(input) {\n var output = { attributes: {}, telemetry: []};\n \n // --- Decoding code --- //\n var decoded = {};\n var historyData = {};\n for (var i = 0; i < input.length - 2; ) {\n var channel_id = input[i++] & 0xff;\n var channel_type = input[i++] & 0xff;\n // BATTERY\n if(channel_id === 0x01 && channel_type === 0x75) {\n decoded.battery = input[i]; \n i += 1;\n }\n // TEMPERATURE\n if (channel_id === 0x03 && channel_type === 0x67) {\n // ℃\n decoded.temperature = parseBytesToInt(input, i, 2, false) / 10;\n // ℉\n // decoded.temperature = parseBytesToInt(input, i, 2, false) / 10 * 1.8 + 32;\n i += 2;\n }\n // HUMIDITY\n if (channel_id === 0x04 && channel_type === 0x68) {\n decoded.humidity = parseBytesToInt(input, i, 1, false) / 2;\n i += 1;\n }\n // PIR\n if (channel_id === 0x05 && channel_type === 0x00) {\n decoded.pir = input[i] === 1 ? \"trigger\" : \"idle\";\n i += 1;\n }\n // LIGHT\n if (channel_id === 0x06 && channel_type === 0xcb) {\n decoded.light_level = input[i];\n i += 1;\n }\n // CO2\n if (channel_id === 0x07 && channel_type === 0x7d) {\n decoded.co2 = parseBytesToInt(input, i, 2, false);\n i += 2;\n }\n // TVOC\n if (channel_id === 0x08 && channel_type === 0x7d) {\n decoded.tvoc = parseBytesToInt(input, i, 2, false);\n i += 2;\n }\n // PRESSURE\n if (channel_id === 0x09 && channel_type === 0x73) {\n decoded.pressure = parseBytesToInt(input, i, 2, false) / 10;\n i += 2;\n }\n // HCHO\n if (channel_id === 0x0a && channel_type === 0x7d) {\n decoded.hcho = parseBytesToInt(input, i, 2, false) / 100;\n i += 2;\n }\n // PM2.5\n if (channel_id === 0x0b && channel_type === 0x7d) {\n decoded.pm2_5 = parseBytesToInt(input, i, 2, false);\n i += 2;\n }\n // PM10\n if (channel_id === 0x0c && channel_type === 0x7d) {\n decoded.pm10 = parseBytesToInt(input, i, 2, false);\n i += 2;\n }\n // O3\n if (channel_id === 0x0d && channel_type === 0x7d) {\n decoded.o3 = parseBytesToInt(input, i, 2, false) / 100;\n i += 2;\n }\n // BEEP\n if (channel_id === 0x0E && channel_type === 0x01) {\n decoded.beep = input[i] === 1 ? \"yes\" : \"no\";\n i += 1;\n }\n \n // HISTORY DATA (CH2O)\n if (channel_id === 0x20 && channel_type === 0xCE) {\n var historyData = {\n ts: parseBytesToInt(input, i, 4, false) * 1000,\n values: {\n temperature: parseBytesToInt(input, i + 4, 2, false) / 10,\n humidity: parseBytesToInt(input, i + 6, 2, false) / 2,\n pir: input[i + 8] === 1 ? \"trigger\" : \"idle\",\n light_level: input[i + 9],\n co2: parseBytesToInt(input, i + 10, 2, false),\n tvoc: parseBytesToInt(input, i + 12, 2, false),\n pressure: parseBytesToInt(input, i + 14, 2, false) / 10,\n pm2_5: parseBytesToInt(input, i + 16, 2, false),\n pm10: parseBytesToInt(input, i + 18, 2, false),\n hcho: parseBytesToInt(input, i + 20, 2, false) / 100\n }\n };\n \n i += 22;\n }\n \n // HISTORY DATA (O3)\n /*if (channel_id === 0x20 && channel_type === 0xCE) {\n var historyData = {\n ts: parseBytesToInt(input, i, 4, false) * 1000,\n values: {\n temperature: parseBytesToInt(input, i + 4, 2, false) / 10,\n humidity: parseBytesToInt(input, i + 6, 2, false) / 2,\n pir: input[i + 8] === 1 ? \"trigger\" : \"idle\",\n light_level: input[i + 9],\n co2: parseBytesToInt(input, i + 10, 2, false),\n tvoc: parseBytesToInt(input, i + 12, 2, false),\n pressure: parseBytesToInt(input, i + 14, 2, false) / 10,\n pm2_5: parseBytesToInt(input, i + 16, 2, false),\n pm10: parseBytesToInt(input, i + 18, 2, false),\n o3: parseBytesToInt(input, i + 20, 2, false) / 100\n }\n };\n \n i += 22;\n }*/\n }\n \n output.telemetry = [{\n ts: timestamp,\n values: decoded\n }, historyData];\n\n // --- Decoding code --- //\n return output;\n}\n\n// --- attributes and telemetry objects ---\nvar telemetry = [];\nvar attributes = {};\n// --- attributes and telemetry objects ---\n\n// --- Timestamp parsing\ntimestamp = data.ts;\n// --- Timestamp parsing\n\n// Message parsing\n// To avoid paths in the decoded objects we passing false value to function as \"pathInKey\" argument.\n// Warning: pathInKey can cause already found fields to be overwritten with the last value found.\n\nvar uplinkDataList = [];\n\n// Passing incoming bytes to decodePayload function, to get custom decoding\nvar customDecoding = decodePayload(hexToBytes(data.data));\n\n// Collecting data to result\nif (customDecoding.?telemetry.size() > 0) {\n if (customDecoding.telemetry instanceof java.util.ArrayList) {\n foreach(telemetryObj: customDecoding.telemetry) {\n if (telemetryObj.ts != null && telemetryObj.values != null) {\n telemetry.add(telemetryObj);\n }\n }\n } else {\n telemetry.putAll(customDecoding.telemetry);\n }\n}\n\nif (customDecoding.?attributes.size() > 0) {\n attributes.putAll(customDecoding.attributes);\n}\n\n// You can add some keys manually to attributes or telemetry\nattributes.eui = data.EUI;\nattributes.fPort = data.port;\nattributes.frequency = data.freq;\n\nvar addDataToTelemetry = {};\naddDataToTelemetry.rssi = data.rssi;\naddDataToTelemetry.seqno = data.seqno;\naddDataToTelemetry.snr = data.snr;\naddDataToTelemetry.ack = data.ack;\naddDataToTelemetry.toa = data.toa;\naddDataToTelemetry.fCnt = data.fcnt;\n\nvar isIncludeGatewayInfo = metadata[\"includeGatewayInfo\"];\nif(isIncludeGatewayInfo == true) {\n telemetry = processTelemetryData(telemetry, addDataToTelemetry);\n}\n\nvar deviceInfo = {\n deviceName: deviceName,\n deviceType: deviceType,\n// assetName: assetName,\n// assetType: assetType,\n attributes: attributes,\n telemetry: telemetry, \n};\n\naddAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName);\n\nuplinkDataList.add(deviceInfo);\n\nvar includeGatewayInfo = [\"ts\", \"gweui\", \"rssi\"];\n\nvar gatewayDeviceNamePrefix = \"Gateway \";\nvar gatewayDeviceType = \"Lora gateway\";\nvar gatewayGroupName = null; // If gatewayGroupName is not null - created device will be added to the entity group with such name.\n\nif (data.cmd == \"gw\") {\n foreach( gatewayInfo : data.gws ) {\n var gatewayInfoMsg = {\n deviceName: gatewayDeviceNamePrefix + gatewayInfo.gweui,\n deviceType: gatewayDeviceType,\n telemetry: [{\n \"ts\": parseDateToTimestamp(gatewayInfo.ts),\n \"values\": getDataList(gatewayInfo, includeGatewayInfo)\n }],\n attributes: {\n eui: gatewayInfo.gweui\n }\n };\n addAdditionalInfoForDeviceMsg(gatewayInfoMsg, customerName, gatewayGroupName);\n uplinkDataList.add(gatewayInfoMsg);\n }\n}\n\nreturn uplinkDataList;\n\nfunction addAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName) {\n if (customerName != null) {\n deviceInfo.customerName = customerName;\n }\n if (groupName != null) {\n deviceInfo.groupName = groupName;\n }\n}\n\nfunction parseDateToTimestamp(dateString) {\n var timestamp = -1;\n if (dateString != null) {\n \n timestamp = new Date(dateString).getTime();\n if (timestamp == -1) {\n var secondsSeparatorIndex = dateString.lastIndexOf('.') + 1;\n var millisecondsEndIndex = dateString.lastIndexOf('+');\n if (millisecondsEndIndex == -1) {\n millisecondsEndIndex = dateString.lastIndexOf('Z');\n }\n if (millisecondsEndIndex == -1) {\n millisecondsEndIndex = dateString.lastIndexOf('-');\n }\n if (millisecondsEndIndex == -1) {\n if (dateString.length >= secondsSeparatorIndex + 3) {\n dateString = dateString.substring(0, secondsSeparatorIndex + 3);\n }\n } else {\n dateString = dateString.substring(0, secondsSeparatorIndex + 3) +\n dateString.substring(millisecondsEndIndex, dateString.length);\n }\n \n timestamp = new Date(dateString).getTime();\n }\n }\n // If we cannot parse timestamp - we will use the current timestamp\n if (timestamp == -1) {\n timestamp = Date.now();\n }\n \n return timestamp;\n}\n\nfunction processTelemetryData(telemetry, addDataToTelemetry) {\n if (telemetry.size > 1) {\n telemetry = addDataToMultipleTelemetries(telemetry, addDataToTelemetry);\n }\n else if (telemetry.size == 1) {\n telemetry = addDataToSingleTelemetry(telemetry, addDataToTelemetry);\n }\n else {\n telemetry.add(addDataToTelemetry);\n }\n \n return telemetry;\n}\n\nfunction addDataToMultipleTelemetries(telemetry, addDataToTelemetry) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[0][\"values\"].keys.contains(element.key)) {\n telemetry[0][\"values\"][element.key] = element.value;\n }\n if (!telemetry[1][\"values\"].keys.contains(element.key)) {\n telemetry[1][\"values\"][element.key] = element.value;\n }\n }\n \n return telemetry;\n}\n\nfunction addDataToSingleTelemetry(telemetry, addDataToTelemetry) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[0][\"values\"].keys.contains(element.key)) {\n telemetry[0][\"values\"][element.key] = element.value;\n }\n }\n \n return telemetry;\n}", + "tbelDecoder": "var data = decodeToJson(payload);\nvar deviceName = \"AM319 \" + data.EUI;\nvar deviceType = \"AM319\";\nvar groupName = null; // If groupName is not null - created device will be added to the entity group with such name.\nvar customerName = null; // If customerName is not null - created devices will be assigned to customer with such name. \n\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// If you want to parse incoming data somehow, you can add your code to this function.\n// input: bytes\n// expected output:\n// {\n// \"attributes\": {\"attributeKey\": \"attributeValue\"},\n// \"telemetry\": {\"telemetryKey\": \"telemetryValue\"}\n// }\n\nfunction decodePayload(input) {\n var output = { attributes: {}, telemetry: []};\n \n // --- Decoding code --- //\n var decoded = {};\n var historyDataList = [];\n for (var i = 0; i < input.length - 2; ) {\n var channel_id = input[i++] & 0xff;\n var channel_type = input[i++] & 0xff;\n // BATTERY\n if(channel_id === 0x01 && channel_type === 0x75) {\n decoded.battery = input[i]; \n i += 1;\n }\n // TEMPERATURE\n if (channel_id === 0x03 && channel_type === 0x67) {\n // ℃\n decoded.temperature = parseBytesToInt(input, i, 2, false) / 10;\n // ℉\n // decoded.temperature = parseBytesToInt(input, i, 2, false) / 10 * 1.8 + 32;\n i += 2;\n }\n // HUMIDITY\n if (channel_id === 0x04 && channel_type === 0x68) {\n decoded.humidity = parseBytesToInt(input, i, 1, false) / 2;\n i += 1;\n }\n // PIR\n if (channel_id === 0x05 && channel_type === 0x00) {\n decoded.pir = input[i] === 1 ? \"trigger\" : \"idle\";\n i += 1;\n }\n // LIGHT\n if (channel_id === 0x06 && channel_type === 0xcb) {\n decoded.light_level = input[i];\n i += 1;\n }\n // CO2\n if (channel_id === 0x07 && channel_type === 0x7d) {\n decoded.co2 = parseBytesToInt(input, i, 2, false);\n i += 2;\n }\n // TVOC\n if (channel_id === 0x08 && channel_type === 0x7d) {\n decoded.tvoc = parseBytesToInt(input, i, 2, false);\n i += 2;\n }\n // PRESSURE\n if (channel_id === 0x09 && channel_type === 0x73) {\n decoded.pressure = parseBytesToInt(input, i, 2, false) / 10;\n i += 2;\n }\n // HCHO\n if (channel_id === 0x0a && channel_type === 0x7d) {\n decoded.hcho = parseBytesToInt(input, i, 2, false) / 100;\n i += 2;\n }\n // PM2.5\n if (channel_id === 0x0b && channel_type === 0x7d) {\n decoded.pm2_5 = parseBytesToInt(input, i, 2, false);\n i += 2;\n }\n // PM10\n if (channel_id === 0x0c && channel_type === 0x7d) {\n decoded.pm10 = parseBytesToInt(input, i, 2, false);\n i += 2;\n }\n // O3\n if (channel_id === 0x0d && channel_type === 0x7d) {\n decoded.o3 = parseBytesToInt(input, i, 2, false) / 100;\n i += 2;\n }\n // BEEP\n if (channel_id === 0x0E && channel_type === 0x01) {\n decoded.beep = input[i] === 1 ? \"yes\" : \"no\";\n i += 1;\n }\n \n // HISTORY DATA (CH2O)\n if (channel_id === 0x20 && channel_type === 0xCE) {\n var historyData = {\n ts: parseBytesToInt(input, i, 4, false) * 1000,\n values: {\n temperature: parseBytesToInt(input, i + 4, 2, false) / 10,\n humidity: parseBytesToInt(input, i + 6, 2, false) / 2,\n pir: input[i + 8] === 1 ? \"trigger\" : \"idle\",\n light_level: input[i + 9],\n co2: parseBytesToInt(input, i + 10, 2, false),\n tvoc: parseBytesToInt(input, i + 12, 2, false),\n pressure: parseBytesToInt(input, i + 14, 2, false) / 10,\n pm2_5: parseBytesToInt(input, i + 16, 2, false),\n pm10: parseBytesToInt(input, i + 18, 2, false),\n hcho: parseBytesToInt(input, i + 20, 2, false) / 100\n }\n };\n \n historyDataList.add(historyData);\n \n i += 22;\n }\n \n // HISTORY DATA (O3)\n /*if (channel_id === 0x20 && channel_type === 0xCE) {\n var historyData = {\n ts: parseBytesToInt(input, i, 4, false) * 1000,\n values: {\n temperature: parseBytesToInt(input, i + 4, 2, false) / 10,\n humidity: parseBytesToInt(input, i + 6, 2, false) / 2,\n pir: input[i + 8] === 1 ? \"trigger\" : \"idle\",\n light_level: input[i + 9],\n co2: parseBytesToInt(input, i + 10, 2, false),\n tvoc: parseBytesToInt(input, i + 12, 2, false),\n pressure: parseBytesToInt(input, i + 14, 2, false) / 10,\n pm2_5: parseBytesToInt(input, i + 16, 2, false),\n pm10: parseBytesToInt(input, i + 18, 2, false),\n o3: parseBytesToInt(input, i + 20, 2, false) / 100\n }\n };\n \n historyDataList.add(historyData);\n \n i += 22;\n }*/\n }\n \n output.telemetry = [{\n ts: timestamp,\n values: decoded\n }];\n \n output.telemetry.addAll(historyDataList);\n \n // --- Decoding code --- //\n return output;\n}\n\n// --- attributes and telemetry objects ---\nvar telemetry = [];\nvar attributes = {};\n// --- attributes and telemetry objects ---\n\n// --- Timestamp parsing\ntimestamp = data.ts;\n// --- Timestamp parsing\n\n// Message parsing\n// To avoid paths in the decoded objects we passing false value to function as \"pathInKey\" argument.\n// Warning: pathInKey can cause already found fields to be overwritten with the last value found.\n\nvar uplinkDataList = [];\n\n// Passing incoming bytes to decodePayload function, to get custom decoding\nvar customDecoding = decodePayload(hexToBytes(data.data));\n\n// Collecting data to result\nif (customDecoding.?telemetry.size() > 0) {\n if (customDecoding.telemetry instanceof java.util.ArrayList) {\n foreach(telemetryObj: customDecoding.telemetry) {\n if (telemetryObj.ts != null && telemetryObj.values != null) {\n telemetry.add(telemetryObj);\n }\n }\n } else {\n telemetry.putAll(customDecoding.telemetry);\n }\n}\n\nif (customDecoding.?attributes.size() > 0) {\n attributes.putAll(customDecoding.attributes);\n}\n\n// You can add some keys manually to attributes or telemetry\nattributes.eui = data.EUI;\nattributes.fPort = data.port;\nattributes.frequency = data.freq;\n\nvar addDataToTelemetry = {};\naddDataToTelemetry.rssi = data.rssi;\naddDataToTelemetry.seqno = data.seqno;\naddDataToTelemetry.snr = data.snr;\naddDataToTelemetry.ack = data.ack;\naddDataToTelemetry.toa = data.toa;\naddDataToTelemetry.fCnt = data.fcnt;\n\nvar isIncludeGatewayInfo = metadata[\"includeGatewayInfo\"];\nif(isIncludeGatewayInfo == true) {\n telemetry = processTelemetryData(telemetry, addDataToTelemetry);\n}\n\nvar deviceInfo = {\n deviceName: deviceName,\n deviceType: deviceType,\n// assetName: assetName,\n// assetType: assetType,\n attributes: attributes,\n telemetry: telemetry, \n};\n\naddAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName);\n\nuplinkDataList.add(deviceInfo);\n\nvar includeGatewayInfo = [\"ts\", \"gweui\", \"rssi\"];\n\nvar gatewayDeviceNamePrefix = \"Gateway \";\nvar gatewayDeviceType = \"Lora gateway\";\nvar gatewayGroupName = null; // If gatewayGroupName is not null - created device will be added to the entity group with such name.\n\nif (data.cmd == \"gw\") {\n foreach( gatewayInfo : data.gws ) {\n var addGatewayInfo = {};\n\n // You can add some keys manually telemetry\n addGatewayInfo.rssi = gatewayInfo.rssi;\n addGatewayInfo.snr = gatewayInfo.snr;\n // You can add some keys manually telemetry\n \n var gatewayInfoMsg = {\n deviceName: gatewayDeviceNamePrefix + gatewayInfo.gweui,\n deviceType: gatewayDeviceType,\n telemetry: [{\n \"ts\": gatewayInfo.ts,\n \"values\": addGatewayInfo\n }],\n attributes: {\n eui: gatewayInfo.gweui\n }\n };\n addAdditionalInfoForDeviceMsg(gatewayInfoMsg, customerName, gatewayGroupName);\n uplinkDataList.add(gatewayInfoMsg);\n }\n}\n\nreturn uplinkDataList;\n\nfunction addAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName) {\n if (customerName != null) {\n deviceInfo.customerName = customerName;\n }\n if (groupName != null) {\n deviceInfo.groupName = groupName;\n }\n}\n\nfunction parseDateToTimestamp(dateString) {\n var timestamp = -1;\n if (dateString != null) {\n \n timestamp = new Date(dateString).getTime();\n if (timestamp == -1) {\n var secondsSeparatorIndex = dateString.lastIndexOf('.') + 1;\n var millisecondsEndIndex = dateString.lastIndexOf('+');\n if (millisecondsEndIndex == -1) {\n millisecondsEndIndex = dateString.lastIndexOf('Z');\n }\n if (millisecondsEndIndex == -1) {\n millisecondsEndIndex = dateString.lastIndexOf('-');\n }\n if (millisecondsEndIndex == -1) {\n if (dateString.length >= secondsSeparatorIndex + 3) {\n dateString = dateString.substring(0, secondsSeparatorIndex + 3);\n }\n } else {\n dateString = dateString.substring(0, secondsSeparatorIndex + 3) +\n dateString.substring(millisecondsEndIndex, dateString.length);\n }\n \n timestamp = new Date(dateString).getTime();\n }\n }\n // If we cannot parse timestamp - we will use the current timestamp\n if (timestamp == -1) {\n timestamp = Date.now();\n }\n \n return timestamp;\n}\n\nfunction processTelemetryData(telemetry, addDataToTelemetry) {\n if (telemetry.size >= 1) {\n telemetry = addDataToTelemetries(telemetry, addDataToTelemetry);\n }\n else {\n telemetry.add(addDataToTelemetry);\n }\n \n return telemetry;\n}\n\nfunction addDataToTelemetries(telemetries, addDataToTelemetry) {\n foreach(telemetry : telemetries) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[\"values\"].keys.contains(element.key)) {\n telemetry[\"values\"][element.key] = element.value;\n }\n } \n }\n \n return telemetries;\n}", "encoder": null, "tbelEncoder": null, "updateOnlyKeys": [ diff --git a/VENDORS/Milesight/AM319/LORIOT/uplink/payload_2.json b/VENDORS/Milesight/AM319/LORIOT/uplink/payload_2.json new file mode 100644 index 00000000..197d64b0 --- /dev/null +++ b/VENDORS/Milesight/AM319/LORIOT/uplink/payload_2.json @@ -0,0 +1,32 @@ +{ + "cmd": "gw", + "seqno": 4, + "EUI": "0102030405060708", + "ts": 1690901260493, + "fcnt": 3, + "port": 207, + "freq": 868300000, + "toa": 1319, + "dr": "SF12 BW125 4/5", + "ack": false, + "gws": [ + { + "rssi": -38, + "snr": 8.5, + "ts": 1690901260493, + "time": "2023-08-01T14:47:40.493Z", + "gweui": "1020304080706050", + "ant": 0 + }, + { + "rssi": -42, + "snr": 8.8, + "ts": 1690901260495, + "time": "2023-08-01T14:47:40.495Z", + "gweui": "1020304081716151", + "ant": 0 + } + ], + "bat": 143, + "data": "0175550367ee0004687c05000106cb02077da803087d2500097366270a7d04000b7d20000c7d30000e015520ce6535ca0c00e1006e016401c2000a2797001900320400" +} diff --git a/VENDORS/Milesight/AM319/LORIOT/uplink/result_2.json b/VENDORS/Milesight/AM319/LORIOT/uplink/result_2.json new file mode 100644 index 00000000..abfe0c09 --- /dev/null +++ b/VENDORS/Milesight/AM319/LORIOT/uplink/result_2.json @@ -0,0 +1,66 @@ +[{ + "deviceName": "AM319 0102030405060708", + "deviceType": "AM319", + "attributes": { + "eui": "0102030405060708", + "fPort": 207, + "frequency": 868300000 + }, + "telemetry": [{ + "ts": 1690901260493, + "values": { + "battery": 85, + "temperature": 23.8, + "humidity": 62.0, + "pir": "trigger", + "light_level": 2, + "co2": 936, + "tvoc": 37, + "pressure": 1008.6, + "hcho": 0.04, + "pm2_5": 32, + "pm10": 48, + "beep": "no" + } + }, { + "ts": 214578533000, + "values": { + "temperature": 5760.0, + "humidity": 14080.0, + "trigger": "idle", + "light_level": 100, + "co2": 49665, + "tvoc": 2560, + "pressure": 3869.5, + "pm2_5": 6400, + "pm10": 12800, + "hcho": 0.04 + } + }] +}, { + "deviceName": "Gateway 1020304080706050", + "deviceType": "Lora gateway", + "telemetry": [{ + "ts": 1690901260493, + "values": { + "rssi": -38, + "snr": 8.5 + } + }], + "attributes": { + "eui": "1020304080706050" + } +}, { + "deviceName": "Gateway 1020304081716151", + "deviceType": "Lora gateway", + "telemetry": [{ + "ts": 1690901260495, + "values": { + "rssi": -42, + "snr": 8.8 + } + }], + "attributes": { + "eui": "1020304081716151" + } +}] \ No newline at end of file diff --git a/VENDORS/Milesight/AM319L/LORIOT/uplink/converter.json b/VENDORS/Milesight/AM319L/LORIOT/uplink/converter.json index 08228bb0..d2348d18 100644 --- a/VENDORS/Milesight/AM319L/LORIOT/uplink/converter.json +++ b/VENDORS/Milesight/AM319L/LORIOT/uplink/converter.json @@ -1,11 +1,16 @@ { "name": "Uplink data converter for Loriot integration AM-319L", "type": "UPLINK", - "debugMode": true, + "debugMode": false, + "debugSettings": { + "failuresEnabled": true, + "allEnabled": false, + "allEnabledUntil": 1735209232367 + }, "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);\nvar deviceName = \"AM319L \" + data.EUI;\nvar deviceType = \"AM319L\";\nvar groupName = null; // If groupName is not null - created device will be added to the entity group with such name.\nvar customerName = null; // If customerName is not null - created devices will be assigned to customer with such name. \n\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// If you want to parse incoming data somehow, you can add your code to this function.\n// input: bytes\n// expected output:\n// {\n// \"attributes\": {\"attributeKey\": \"attributeValue\"},\n// \"telemetry\": {\"telemetryKey\": \"telemetryValue\"}\n// }\n\nfunction decodePayload(input) {\n var output = { attributes: {}, telemetry: []};\n \n // --- Decoding code --- //\n var decoded = {};\n var historyData = {};\n for (var i = 0; i < input.length - 2; ) {\n var channel_id = input[i++] & 0xff;\n var channel_type = input[i++] & 0xff;\n // BATTERY\n if(channel_id === 0x01 && channel_type === 0x75) {\n decoded.battery = input[i]; \n i += 1;\n }\n // TEMPERATURE\n if (channel_id === 0x03 && channel_type === 0x67) {\n // ℃\n decoded.temperature = parseBytesToInt(input, i, 2, false) / 10;\n // ℉\n // decoded.temperature = parseBytesToInt(input, i, 2, false) / 10 * 1.8 + 32;\n i += 2;\n }\n // HUMIDITY\n if (channel_id === 0x04 && channel_type === 0x68) {\n decoded.humidity = parseBytesToInt(input, i, 1, false) / 2;\n i += 1;\n }\n // PIR\n if (channel_id === 0x05 && channel_type === 0x00) {\n decoded.pir = input[i] === 1 ? \"trigger\" : \"idle\";\n i += 1;\n }\n // LIGHT\n if (channel_id === 0x06 && channel_type === 0xcb) {\n decoded.light_level = input[i];\n i += 1;\n }\n // CO2\n if (channel_id === 0x07 && channel_type === 0x7d) {\n decoded.co2 = parseBytesToInt(input, i, 2, false);\n i += 2;\n }\n // TVOC\n if (channel_id === 0x08 && channel_type === 0x7d) {\n decoded.tvoc = parseBytesToInt(input, i, 2, false);\n i += 2;\n }\n // PRESSURE\n if (channel_id === 0x09 && channel_type === 0x73) {\n decoded.pressure = parseBytesToInt(input, i, 2, false) / 10;\n i += 2;\n }\n // HCHO\n if (channel_id === 0x0a && channel_type === 0x7d) {\n decoded.hcho = parseBytesToInt(input, i, 2, false) / 100;\n i += 2;\n }\n // PM2.5\n if (channel_id === 0x0b && channel_type === 0x7d) {\n decoded.pm2_5 = parseBytesToInt(input, i, 2, false);\n i += 2;\n }\n // PM10\n if (channel_id === 0x0c && channel_type === 0x7d) {\n decoded.pm10 = parseBytesToInt(input, i, 2, false);\n i += 2;\n }\n // O3\n if (channel_id === 0x0d && channel_type === 0x7d) {\n decoded.o3 = parseBytesToInt(input, i, 2, false) / 100;\n i += 2;\n }\n // BEEP\n if (channel_id === 0x0E && channel_type === 0x01) {\n decoded.beep = input[i] === 1 ? \"yes\" : \"no\";\n i += 1;\n }\n \n // HISTORY DATA (CH2O)\n if (channel_id === 0x20 && channel_type === 0xCE) {\n var historyData = {\n ts: parseBytesToInt(input, i, 4, false) * 1000,\n values: {\n temperature: parseBytesToInt(input, i + 4, 2, false) / 10,\n humidity: parseBytesToInt(input, i + 6, 2, false) / 2,\n pir: input[i + 8] === 1 ? \"trigger\" : \"idle\",\n light_level: input[i + 9],\n co2: parseBytesToInt(input, i + 10, 2, false),\n tvoc: parseBytesToInt(input, i + 12, 2, false),\n pressure: parseBytesToInt(input, i + 14, 2, false) / 10,\n pm2_5: parseBytesToInt(input, i + 16, 2, false),\n pm10: parseBytesToInt(input, i + 18, 2, false),\n hcho: parseBytesToInt(input, i + 20, 2, false) / 100\n }\n };\n \n i += 22;\n }\n \n // HISTORY DATA (O3)\n /*if (channel_id === 0x20 && channel_type === 0xCE) {\n var historyData = {\n ts: parseBytesToInt(input, i, 4, false) * 1000,\n values: {\n temperature: parseBytesToInt(input, i + 4, 2, false) / 10,\n humidity: parseBytesToInt(input, i + 6, 2, false) / 2,\n pir: input[i + 8] === 1 ? \"trigger\" : \"idle\",\n light_level: input[i + 9],\n co2: parseBytesToInt(input, i + 10, 2, false),\n tvoc: parseBytesToInt(input, i + 12, 2, false),\n pressure: parseBytesToInt(input, i + 14, 2, false) / 10,\n pm2_5: parseBytesToInt(input, i + 16, 2, false),\n pm10: parseBytesToInt(input, i + 18, 2, false),\n o3: parseBytesToInt(input, i + 20, 2, false) / 100\n }\n };\n \n i += 22;\n }*/\n }\n \n output.telemetry = [{\n ts: timestamp,\n values: decoded\n }, historyData];\n\n // --- Decoding code --- //\n return output;\n}\n\n// --- attributes and telemetry objects ---\nvar telemetry = [];\nvar attributes = {};\n// --- attributes and telemetry objects ---\n\n// --- Timestamp parsing\ntimestamp = data.ts;\n// --- Timestamp parsing\n\n// Message parsing\n// To avoid paths in the decoded objects we passing false value to function as \"pathInKey\" argument.\n// Warning: pathInKey can cause already found fields to be overwritten with the last value found.\n\nvar uplinkDataList = [];\n\n// Passing incoming bytes to decodePayload function, to get custom decoding\nvar customDecoding = decodePayload(hexToBytes(data.data));\n\n// Collecting data to result\nif (customDecoding.?telemetry.size() > 0) {\n if (customDecoding.telemetry instanceof java.util.ArrayList) {\n foreach(telemetryObj: customDecoding.telemetry) {\n if (telemetryObj.ts != null && telemetryObj.values != null) {\n telemetry.add(telemetryObj);\n }\n }\n } else {\n telemetry.putAll(customDecoding.telemetry);\n }\n}\n\nif (customDecoding.?attributes.size() > 0) {\n attributes.putAll(customDecoding.attributes);\n}\n\n// You can add some keys manually to attributes or telemetry\nattributes.eui = data.EUI;\nattributes.fPort = data.port;\nattributes.frequency = data.freq;\n\nvar addDataToTelemetry = {};\naddDataToTelemetry.rssi = data.rssi;\naddDataToTelemetry.seqno = data.seqno;\naddDataToTelemetry.snr = data.snr;\naddDataToTelemetry.ack = data.ack;\naddDataToTelemetry.toa = data.toa;\naddDataToTelemetry.fCnt = data.fcnt;\n\nvar isIncludeGatewayInfo = metadata[\"includeGatewayInfo\"];\nif(isIncludeGatewayInfo == true) {\n telemetry = processTelemetryData(telemetry, addDataToTelemetry);\n}\n\nvar deviceInfo = {\n deviceName: deviceName,\n deviceType: deviceType,\n// assetName: assetName,\n// assetType: assetType,\n attributes: attributes,\n telemetry: telemetry, \n};\n\naddAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName);\n\nuplinkDataList.add(deviceInfo);\n\nvar includeGatewayInfo = [\"ts\", \"gweui\", \"rssi\"];\n\nvar gatewayDeviceNamePrefix = \"Gateway \";\nvar gatewayDeviceType = \"Lora gateway\";\nvar gatewayGroupName = null; // If gatewayGroupName is not null - created device will be added to the entity group with such name.\n\nif (data.cmd == \"gw\") {\n foreach( gatewayInfo : data.gws ) {\n var gatewayInfoMsg = {\n deviceName: gatewayDeviceNamePrefix + gatewayInfo.gweui,\n deviceType: gatewayDeviceType,\n telemetry: [{\n \"ts\": parseDateToTimestamp(gatewayInfo.ts),\n \"values\": getDataList(gatewayInfo, includeGatewayInfo)\n }],\n attributes: {\n eui: gatewayInfo.gweui\n }\n };\n addAdditionalInfoForDeviceMsg(gatewayInfoMsg, customerName, gatewayGroupName);\n uplinkDataList.add(gatewayInfoMsg);\n }\n}\n\nreturn uplinkDataList;\n\nfunction addAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName) {\n if (customerName != null) {\n deviceInfo.customerName = customerName;\n }\n if (groupName != null) {\n deviceInfo.groupName = groupName;\n }\n}\n\nfunction parseDateToTimestamp(dateString) {\n var timestamp = -1;\n if (dateString != null) {\n \n timestamp = new Date(dateString).getTime();\n if (timestamp == -1) {\n var secondsSeparatorIndex = dateString.lastIndexOf('.') + 1;\n var millisecondsEndIndex = dateString.lastIndexOf('+');\n if (millisecondsEndIndex == -1) {\n millisecondsEndIndex = dateString.lastIndexOf('Z');\n }\n if (millisecondsEndIndex == -1) {\n millisecondsEndIndex = dateString.lastIndexOf('-');\n }\n if (millisecondsEndIndex == -1) {\n if (dateString.length >= secondsSeparatorIndex + 3) {\n dateString = dateString.substring(0, secondsSeparatorIndex + 3);\n }\n } else {\n dateString = dateString.substring(0, secondsSeparatorIndex + 3) +\n dateString.substring(millisecondsEndIndex, dateString.length);\n }\n \n timestamp = new Date(dateString).getTime();\n }\n }\n // If we cannot parse timestamp - we will use the current timestamp\n if (timestamp == -1) {\n timestamp = Date.now();\n }\n \n return timestamp;\n}\n\nfunction processTelemetryData(telemetry, addDataToTelemetry) {\n if (telemetry.size > 1) {\n telemetry = addDataToMultipleTelemetries(telemetry, addDataToTelemetry);\n }\n else if (telemetry.size == 1) {\n telemetry = addDataToSingleTelemetry(telemetry, addDataToTelemetry);\n }\n else {\n telemetry.add(addDataToTelemetry);\n }\n \n return telemetry;\n}\n\nfunction addDataToMultipleTelemetries(telemetry, addDataToTelemetry) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[0][\"values\"].keys.contains(element.key)) {\n telemetry[0][\"values\"][element.key] = element.value;\n }\n if (!telemetry[1][\"values\"].keys.contains(element.key)) {\n telemetry[1][\"values\"][element.key] = element.value;\n }\n }\n \n return telemetry;\n}\n\nfunction addDataToSingleTelemetry(telemetry, addDataToTelemetry) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[0][\"values\"].keys.contains(element.key)) {\n telemetry[0][\"values\"][element.key] = element.value;\n }\n }\n \n return telemetry;\n}", + "tbelDecoder": "var data = decodeToJson(payload);\nvar deviceName = \"AM319L \" + data.EUI;\nvar deviceType = \"AM319L\";\nvar groupName = null; // If groupName is not null - created device will be added to the entity group with such name.\nvar customerName = null; // If customerName is not null - created devices will be assigned to customer with such name. \n\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// If you want to parse incoming data somehow, you can add your code to this function.\n// input: bytes\n// expected output:\n// {\n// \"attributes\": {\"attributeKey\": \"attributeValue\"},\n// \"telemetry\": {\"telemetryKey\": \"telemetryValue\"}\n// }\n\nfunction decodePayload(input) {\n var output = { attributes: {}, telemetry: []};\n \n // --- Decoding code --- //\n var decoded = {};\n var historyDataList = [];\n for (var i = 0; i < input.length - 2; ) {\n var channel_id = input[i++] & 0xff;\n var channel_type = input[i++] & 0xff;\n // BATTERY\n if(channel_id === 0x01 && channel_type === 0x75) {\n decoded.battery = input[i]; \n i += 1;\n }\n // TEMPERATURE\n if (channel_id === 0x03 && channel_type === 0x67) {\n // ℃\n decoded.temperature = parseBytesToInt(input, i, 2, false) / 10;\n // ℉\n // decoded.temperature = parseBytesToInt(input, i, 2, false) / 10 * 1.8 + 32;\n i += 2;\n }\n // HUMIDITY\n if (channel_id === 0x04 && channel_type === 0x68) {\n decoded.humidity = parseBytesToInt(input, i, 1, false) / 2;\n i += 1;\n }\n // PIR\n if (channel_id === 0x05 && channel_type === 0x00) {\n decoded.pir = input[i] === 1 ? \"trigger\" : \"idle\";\n i += 1;\n }\n // LIGHT\n if (channel_id === 0x06 && channel_type === 0xcb) {\n decoded.light_level = input[i];\n i += 1;\n }\n // CO2\n if (channel_id === 0x07 && channel_type === 0x7d) {\n decoded.co2 = parseBytesToInt(input, i, 2, false);\n i += 2;\n }\n // TVOC\n if (channel_id === 0x08 && channel_type === 0x7d) {\n decoded.tvoc = parseBytesToInt(input, i, 2, false);\n i += 2;\n }\n // PRESSURE\n if (channel_id === 0x09 && channel_type === 0x73) {\n decoded.pressure = parseBytesToInt(input, i, 2, false) / 10;\n i += 2;\n }\n // HCHO\n if (channel_id === 0x0a && channel_type === 0x7d) {\n decoded.hcho = parseBytesToInt(input, i, 2, false) / 100;\n i += 2;\n }\n // PM2.5\n if (channel_id === 0x0b && channel_type === 0x7d) {\n decoded.pm2_5 = parseBytesToInt(input, i, 2, false);\n i += 2;\n }\n // PM10\n if (channel_id === 0x0c && channel_type === 0x7d) {\n decoded.pm10 = parseBytesToInt(input, i, 2, false);\n i += 2;\n }\n // O3\n if (channel_id === 0x0d && channel_type === 0x7d) {\n decoded.o3 = parseBytesToInt(input, i, 2, false) / 100;\n i += 2;\n }\n // BEEP\n if (channel_id === 0x0E && channel_type === 0x01) {\n decoded.beep = input[i] === 1 ? \"yes\" : \"no\";\n i += 1;\n }\n \n // HISTORY DATA (CH2O)\n if (channel_id === 0x20 && channel_type === 0xCE) {\n var historyData = {\n ts: parseBytesToInt(input, i, 4, false) * 1000,\n values: {\n temperature: parseBytesToInt(input, i + 4, 2, false) / 10,\n humidity: parseBytesToInt(input, i + 6, 2, false) / 2,\n pir: input[i + 8] === 1 ? \"trigger\" : \"idle\",\n light_level: input[i + 9],\n co2: parseBytesToInt(input, i + 10, 2, false),\n tvoc: parseBytesToInt(input, i + 12, 2, false),\n pressure: parseBytesToInt(input, i + 14, 2, false) / 10,\n pm2_5: parseBytesToInt(input, i + 16, 2, false),\n pm10: parseBytesToInt(input, i + 18, 2, false),\n hcho: parseBytesToInt(input, i + 20, 2, false) / 100\n }\n };\n \n historyDataList.add(historyData);\n \n i += 22;\n }\n \n // HISTORY DATA (O3)\n /*if (channel_id === 0x20 && channel_type === 0xCE) {\n var historyData = {\n ts: parseBytesToInt(input, i, 4, false) * 1000,\n values: {\n temperature: parseBytesToInt(input, i + 4, 2, false) / 10,\n humidity: parseBytesToInt(input, i + 6, 2, false) / 2,\n pir: input[i + 8] === 1 ? \"trigger\" : \"idle\",\n light_level: input[i + 9],\n co2: parseBytesToInt(input, i + 10, 2, false),\n tvoc: parseBytesToInt(input, i + 12, 2, false),\n pressure: parseBytesToInt(input, i + 14, 2, false) / 10,\n pm2_5: parseBytesToInt(input, i + 16, 2, false),\n pm10: parseBytesToInt(input, i + 18, 2, false),\n o3: parseBytesToInt(input, i + 20, 2, false) / 100\n }\n };\n \n historyDataList.add(historyData);\n \n i += 22;\n }*/\n }\n \n output.telemetry = [{\n ts: timestamp,\n values: decoded\n }];\n \n output.telemetry.addAll(historyDataList);\n // --- Decoding code --- //\n return output;\n}\n\n// --- attributes and telemetry objects ---\nvar telemetry = [];\nvar attributes = {};\n// --- attributes and telemetry objects ---\n\n// --- Timestamp parsing\ntimestamp = data.ts;\n// --- Timestamp parsing\n\n// Message parsing\n// To avoid paths in the decoded objects we passing false value to function as \"pathInKey\" argument.\n// Warning: pathInKey can cause already found fields to be overwritten with the last value found.\n\nvar uplinkDataList = [];\n\n// Passing incoming bytes to decodePayload function, to get custom decoding\nvar customDecoding = decodePayload(hexToBytes(data.data));\n\n// Collecting data to result\nif (customDecoding.?telemetry.size() > 0) {\n if (customDecoding.telemetry instanceof java.util.ArrayList) {\n foreach(telemetryObj: customDecoding.telemetry) {\n if (telemetryObj.ts != null && telemetryObj.values != null) {\n telemetry.add(telemetryObj);\n }\n }\n } else {\n telemetry.putAll(customDecoding.telemetry);\n }\n}\n\nif (customDecoding.?attributes.size() > 0) {\n attributes.putAll(customDecoding.attributes);\n}\n\n// You can add some keys manually to attributes or telemetry\nattributes.eui = data.EUI;\nattributes.fPort = data.port;\nattributes.frequency = data.freq;\n\nvar addDataToTelemetry = {};\naddDataToTelemetry.rssi = data.rssi;\naddDataToTelemetry.seqno = data.seqno;\naddDataToTelemetry.snr = data.snr;\naddDataToTelemetry.ack = data.ack;\naddDataToTelemetry.toa = data.toa;\naddDataToTelemetry.fCnt = data.fcnt;\n\nvar isIncludeGatewayInfo = metadata[\"includeGatewayInfo\"];\nif(isIncludeGatewayInfo == true) {\n telemetry = processTelemetryData(telemetry, addDataToTelemetry);\n}\n\nvar deviceInfo = {\n deviceName: deviceName,\n deviceType: deviceType,\n// assetName: assetName,\n// assetType: assetType,\n attributes: attributes,\n telemetry: telemetry, \n};\n\naddAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName);\n\nuplinkDataList.add(deviceInfo);\n\nvar gatewayDeviceNamePrefix = \"Gateway \";\nvar gatewayDeviceType = \"Lora gateway\";\nvar gatewayGroupName = null; // If gatewayGroupName is not null - created device will be added to the entity group with such name.\n\nif (data.cmd == \"gw\") {\n foreach( gatewayInfo : data.gws ) {\n var addGatewayInfo = {};\n\n // You can add some keys manually telemetry\n addGatewayInfo.rssi = gatewayInfo.rssi;\n addGatewayInfo.snr = gatewayInfo.snr;\n // You can add some keys manually telemetry\n \n var gatewayInfoMsg = {\n deviceName: gatewayDeviceNamePrefix + gatewayInfo.gweui,\n deviceType: gatewayDeviceType,\n telemetry: [{\n \"ts\": gatewayInfo.ts,\n \"values\": addGatewayInfo\n }],\n attributes: {\n eui: gatewayInfo.gweui\n }\n };\n addAdditionalInfoForDeviceMsg(gatewayInfoMsg, customerName, gatewayGroupName);\n uplinkDataList.add(gatewayInfoMsg);\n }\n}\n\nreturn uplinkDataList;\n\nfunction addAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName) {\n if (customerName != null) {\n deviceInfo.customerName = customerName;\n }\n if (groupName != null) {\n deviceInfo.groupName = groupName;\n }\n}\n\nfunction parseDateToTimestamp(dateString) {\n var timestamp = -1;\n if (dateString != null) {\n \n timestamp = new Date(dateString).getTime();\n if (timestamp == -1) {\n var secondsSeparatorIndex = dateString.lastIndexOf('.') + 1;\n var millisecondsEndIndex = dateString.lastIndexOf('+');\n if (millisecondsEndIndex == -1) {\n millisecondsEndIndex = dateString.lastIndexOf('Z');\n }\n if (millisecondsEndIndex == -1) {\n millisecondsEndIndex = dateString.lastIndexOf('-');\n }\n if (millisecondsEndIndex == -1) {\n if (dateString.length >= secondsSeparatorIndex + 3) {\n dateString = dateString.substring(0, secondsSeparatorIndex + 3);\n }\n } else {\n dateString = dateString.substring(0, secondsSeparatorIndex + 3) +\n dateString.substring(millisecondsEndIndex, dateString.length);\n }\n \n timestamp = new Date(dateString).getTime();\n }\n }\n // If we cannot parse timestamp - we will use the current timestamp\n if (timestamp == -1) {\n timestamp = Date.now();\n }\n \n return timestamp;\n}\n\nfunction processTelemetryData(telemetry, addDataToTelemetry) {\n if (telemetry.size >= 1) {\n telemetry = addDataToTelemetries(telemetry, addDataToTelemetry);\n }\n else {\n telemetry.add(addDataToTelemetry);\n }\n \n return telemetry;\n}\n\nfunction addDataToTelemetries(telemetries, addDataToTelemetry) {\n foreach(telemetry : telemetries) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[\"values\"].keys.contains(element.key)) {\n telemetry[\"values\"][element.key] = element.value;\n }\n } \n }\n \n return telemetries;\n}", "encoder": null, "tbelEncoder": null, "updateOnlyKeys": [ diff --git a/VENDORS/Milesight/AM319L/LORIOT/uplink/payload_2.json b/VENDORS/Milesight/AM319L/LORIOT/uplink/payload_2.json new file mode 100644 index 00000000..197d64b0 --- /dev/null +++ b/VENDORS/Milesight/AM319L/LORIOT/uplink/payload_2.json @@ -0,0 +1,32 @@ +{ + "cmd": "gw", + "seqno": 4, + "EUI": "0102030405060708", + "ts": 1690901260493, + "fcnt": 3, + "port": 207, + "freq": 868300000, + "toa": 1319, + "dr": "SF12 BW125 4/5", + "ack": false, + "gws": [ + { + "rssi": -38, + "snr": 8.5, + "ts": 1690901260493, + "time": "2023-08-01T14:47:40.493Z", + "gweui": "1020304080706050", + "ant": 0 + }, + { + "rssi": -42, + "snr": 8.8, + "ts": 1690901260495, + "time": "2023-08-01T14:47:40.495Z", + "gweui": "1020304081716151", + "ant": 0 + } + ], + "bat": 143, + "data": "0175550367ee0004687c05000106cb02077da803087d2500097366270a7d04000b7d20000c7d30000e015520ce6535ca0c00e1006e016401c2000a2797001900320400" +} diff --git a/VENDORS/Milesight/AM319L/LORIOT/uplink/result_2.json b/VENDORS/Milesight/AM319L/LORIOT/uplink/result_2.json new file mode 100644 index 00000000..3833a17c --- /dev/null +++ b/VENDORS/Milesight/AM319L/LORIOT/uplink/result_2.json @@ -0,0 +1,66 @@ +[{ + "deviceName": "AM319L 0102030405060708", + "deviceType": "AM319L", + "attributes": { + "eui": "0102030405060708", + "fPort": 207, + "frequency": 868300000 + }, + "telemetry": [{ + "ts": 1690901260493, + "values": { + "battery": 85, + "temperature": 23.8, + "humidity": 62.0, + "pir": "trigger", + "light_level": 2, + "co2": 936, + "tvoc": 37, + "pressure": 1008.6, + "hcho": 0.04, + "pm2_5": 32, + "pm10": 48, + "beep": "no" + } + }, { + "ts": 214578533000, + "values": { + "temperature": 5760.0, + "humidity": 14080.0, + "trigger": "idle", + "light_level": 100, + "co2": 49665, + "tvoc": 2560, + "pressure": 3869.5, + "pm2_5": 6400, + "pm10": 12800, + "hcho": 0.04 + } + }] +}, { + "deviceName": "Gateway 1020304080706050", + "deviceType": "Lora gateway", + "telemetry": [{ + "ts": 1690901260493, + "values": { + "rssi": -38, + "snr": 8.5 + } + }], + "attributes": { + "eui": "1020304080706050" + } +}, { + "deviceName": "Gateway 1020304081716151", + "deviceType": "Lora gateway", + "telemetry": [{ + "ts": 1690901260495, + "values": { + "rssi": -42, + "snr": 8.8 + } + }], + "attributes": { + "eui": "1020304081716151" + } +}] \ No newline at end of file diff --git a/VENDORS/Milesight/AT101/LORIOT/uplink/converter.json b/VENDORS/Milesight/AT101/LORIOT/uplink/converter.json index b48a8e47..4235e59b 100644 --- a/VENDORS/Milesight/AT101/LORIOT/uplink/converter.json +++ b/VENDORS/Milesight/AT101/LORIOT/uplink/converter.json @@ -1,11 +1,16 @@ { "name": "Uplink data converter for Loriot integration AT101", "type": "UPLINK", - "debugMode": true, + "debugMode": false, + "debugSettings": { + "failuresEnabled": true, + "allEnabled": false, + "allEnabledUntil": 1735209505483 + }, "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);\nvar deviceName = \"AT101 \" + data.EUI;\nvar deviceType = \"AT101\";\nvar groupName = null; // If groupName is not null - created device will be added to the entity group with such name.\nvar customerName = null; // If customerName is not null - created devices will be assigned to customer with such name. \n\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// If you want to parse incoming data somehow, you can add your code to this function.\n// input: bytes\n// expected output:\n// {\n// \"attributes\": {\"attributeKey\": \"attributeValue\"},\n// \"telemetry\": {\"telemetryKey\": \"telemetryValue\"}\n// }\n\nfunction decodePayload(input) {\n var output = { attributes: {}, telemetry: []};\n \n // --- Decoding code --- //\n var decoded = {};\n var historyData = {};\n var wifi = [];\n for (var i = 0; i < input.length - 2; ) {\n var channel_id = input[i++] & 0xff;\n var channel_type = input[i++] & 0xff;\n // BATTERY\n if(channel_id === 0x01 && channel_type === 0x75) {\n decoded.battery = input[i]; \n i += 1;\n }\n // TEMPERATURE\n if (channel_id === 0x03 && channel_type === 0x67) {\n // ℃\n decoded.temperature = parseBytesToInt(input, i, 2, false) / 10;\n // ℉\n // decoded.temperature = parseBytesToInt(input, i, 2, false) / 10 * 1.8 + 32;\n i += 2;\n }\n // Location\n if ((channel_id === 0x04 || channel_id == 0x84) && channel_type === 0x88) {\n decoded.latitude = parseBytesToInt(input, i, 4, false) / 1000000;\n decoded.longitude = parseBytesToInt(input, i+4, 4, false) / 1000000;\n var status = input[i+8];\n decoded.motion_status = getMotionStatus(status & 0x0f);\n decoded.geofence_status = getGeofenceStatus((status >> 4) & 0x0f);\n i +=9;\n }\n // Position\n if (channel_id === 0x05 && channel_type === 0x00) {\n decoded.position = input[i] === 0 ? \"normal\" : \"tilt\";\n i += 1;\n }\n // Wi-Fi SCAN RESULT\n if (channel_id === 0x06 && channel_type === 0xd9) {\n var wifiObject = {};\n wifiObject.group = input[i];\n wifiObject.mac = readMAC(input.slice(i + 1, i + 7));\n wifiObject.rssi = input[i+7];\n wifiObject.motion_status = getMotionStatus(input[i + 8] & 0x0f);\n i += 9;\n\n decoded.wifi_scan_result = \"finish\";\n if (wifiObject.mac === \"ff:ff:ff:ff:ff:ff\") {\n decoded.wifi_scan_result = \"timeout\";\n continue;\n }\n decoded.motion_status = wifiObject.motion_status;\n\n wifi.add(wifiObject);\n }\n //Tamper Status\n if (channel_id === 0x07 && channel_type === 0x00) {\n decoded.tamper_status = input[i] === 0 ? \"install\" : \"uninstall\";\n i +=1;\n }\n // TEMPERATURE WITH ABNORMAL\n if (channel_id === 0x83 && channel_type === 0x67) {\n decoded.temperature = parseBytesToInt(input, i, 2, false) / 10;\n decoded.temperature_abnormal = input[i + 2] == 0 ? false : true;\n i += 3;\n }\n // HISTORICAL DATA\n if (channel_id === 0x20 && channel_type === 0xce) {\n historyData = {\n ts : parseBytesToInt(input, i, 4, false),\n values : {\n longitude : parseBytesToInt(input, i + 4, 4, false) / 1000000,\n latitude : parseBytesToInt(input, i + 8, 4, false) / 1000000\n }\n };\n i += 12;\n } \n }\n \n decoded.wifi = wifi.size > 0 ? wifi : null;\n \n output.telemetry = [{\n ts: timestamp,\n values: decoded\n }, historyData];\n\n // --- Decoding code --- //\n return output;\n}\n\n// --- attributes and telemetry objects ---\nvar telemetry = [];\nvar attributes = {};\n// --- attributes and telemetry objects ---\n\n// --- Timestamp parsing\ntimestamp = data.ts;\n// --- Timestamp parsing\n\n// Message parsing\n// To avoid paths in the decoded objects we passing false value to function as \"pathInKey\" argument.\n// Warning: pathInKey can cause already found fields to be overwritten with the last value found.\n\nvar uplinkDataList = [];\n\n// Passing incoming bytes to decodePayload function, to get custom decoding\nvar customDecoding = decodePayload(hexToBytes(data.data));\n\n// Collecting data to result\nif (customDecoding.?telemetry.size() > 0) {\n if (customDecoding.telemetry instanceof java.util.ArrayList) {\n foreach(telemetryObj: customDecoding.telemetry) {\n if (telemetryObj.ts != null && telemetryObj.values != null) {\n telemetry.add(telemetryObj);\n }\n }\n } else {\n telemetry.putAll(customDecoding.telemetry);\n }\n}\n\nif (customDecoding.?attributes.size() > 0) {\n attributes.putAll(customDecoding.attributes);\n}\n\n// You can add some keys manually to attributes or telemetry\nattributes.eui = data.EUI;\nattributes.fPort = data.port;\nattributes.frequency = data.freq;\n\nvar addDataToTelemetry = {};\naddDataToTelemetry.rssi = data.rssi;\naddDataToTelemetry.seqno = data.seqno;\naddDataToTelemetry.snr = data.snr;\naddDataToTelemetry.ack = data.ack;\naddDataToTelemetry.toa = data.toa;\naddDataToTelemetry.fCnt = data.fcnt;\n\nvar isIncludeGatewayInfo = metadata[\"includeGatewayInfo\"];\nif(isIncludeGatewayInfo == true) {\n telemetry = processTelemetryData(telemetry, addDataToTelemetry);\n}\n\nvar deviceInfo = {\n deviceName: deviceName,\n deviceType: deviceType,\n// assetName: assetName,\n// assetType: assetType,\n attributes: attributes,\n telemetry: telemetry, \n};\n\naddAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName);\n\nuplinkDataList.add(deviceInfo);\n\nvar includeGatewayInfo = [\"ts\", \"gweui\", \"rssi\"];\n\nvar gatewayDeviceNamePrefix = \"Gateway \";\nvar gatewayDeviceType = \"Lora gateway\";\nvar gatewayGroupName = null; // If gatewayGroupName is not null - created device will be added to the entity group with such name.\n\nif (data.cmd == \"gw\") {\n foreach( gatewayInfo : data.gws ) {\n var gatewayInfoMsg = {\n deviceName: gatewayDeviceNamePrefix + gatewayInfo.gweui,\n deviceType: gatewayDeviceType,\n telemetry: [{\n \"ts\": parseDateToTimestamp(gatewayInfo.ts),\n \"values\": getDataList(gatewayInfo, includeGatewayInfo)\n }],\n attributes: {\n eui: gatewayInfo.gweui\n }\n };\n addAdditionalInfoForDeviceMsg(gatewayInfoMsg, customerName, gatewayGroupName);\n uplinkDataList.add(gatewayInfoMsg);\n }\n}\n\nreturn uplinkDataList;\n\nfunction addAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName) {\n if (customerName != null) {\n deviceInfo.customerName = customerName;\n }\n if (groupName != null) {\n deviceInfo.groupName = groupName;\n }\n}\n\nfunction parseDateToTimestamp(dateString) {\n var timestamp = -1;\n if (dateString != null) {\n \n timestamp = new Date(dateString).getTime();\n if (timestamp == -1) {\n var secondsSeparatorIndex = dateString.lastIndexOf('.') + 1;\n var millisecondsEndIndex = dateString.lastIndexOf('+');\n if (millisecondsEndIndex == -1) {\n millisecondsEndIndex = dateString.lastIndexOf('Z');\n }\n if (millisecondsEndIndex == -1) {\n millisecondsEndIndex = dateString.lastIndexOf('-');\n }\n if (millisecondsEndIndex == -1) {\n if (dateString.length >= secondsSeparatorIndex + 3) {\n dateString = dateString.substring(0, secondsSeparatorIndex + 3);\n }\n } else {\n dateString = dateString.substring(0, secondsSeparatorIndex + 3) +\n dateString.substring(millisecondsEndIndex, dateString.length);\n }\n \n timestamp = new Date(dateString).getTime();\n }\n }\n // If we cannot parse timestamp - we will use the current timestamp\n if (timestamp == -1) {\n timestamp = Date.now();\n }\n \n return timestamp;\n}\n\nfunction processTelemetryData(telemetry, addDataToTelemetry) {\n if (telemetry.size > 1) {\n telemetry = addDataToMultipleTelemetries(telemetry, addDataToTelemetry);\n }\n else if (telemetry.size == 1) {\n telemetry = addDataToSingleTelemetry(telemetry, addDataToTelemetry);\n }\n else {\n telemetry.add(addDataToTelemetry);\n }\n \n return telemetry;\n}\n\nfunction addDataToMultipleTelemetries(telemetry, addDataToTelemetry) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[0][\"values\"].keys.contains(element.key)) {\n telemetry[0][\"values\"][element.key] = element.value;\n }\n if (!telemetry[1][\"values\"].keys.contains(element.key)) {\n telemetry[1][\"values\"][element.key] = element.value;\n }\n }\n \n return telemetry;\n}\n\nfunction addDataToSingleTelemetry(telemetry, addDataToTelemetry) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[0][\"values\"].keys.contains(element.key)) {\n telemetry[0][\"values\"][element.key] = element.value;\n }\n }\n \n return telemetry;\n}\n\nfunction getMotionStatus(status) {\n if(status == 0) {\n return \"unknown\";\n }\n else if (status == 1) {\n return \"start moving\";\n }\n else if (status == 2) {\n return \"moving\";\n }\n else {\n return \"stop moving\";\n }\n}\n\nfunction getGeofenceStatus(status) {\n if(status == 0) {\n return \"inside\";\n }\n else if (status == 1) {\n return \"outside\";\n }\n else if (status == 2) {\n return \"unset\";\n }\n else {\n return \"unknown\";\n }\n}\n\nfunction readMAC(bytes) {\n var temp = [];\n for (b : bytes) {\n temp.add(String.format(\"%02x\", b & 0xFF));\n }\n return String.join(\":\", temp);\n}", + "tbelDecoder": "var data = decodeToJson(payload);\nvar deviceName = \"AT101 \" + data.EUI;\nvar deviceType = \"AT101\";\nvar groupName = null; // If groupName is not null - created device will be added to the entity group with such name.\nvar customerName = null; // If customerName is not null - created devices will be assigned to customer with such name. \n\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// If you want to parse incoming data somehow, you can add your code to this function.\n// input: bytes\n// expected output:\n// {\n// \"attributes\": {\"attributeKey\": \"attributeValue\"},\n// \"telemetry\": {\"telemetryKey\": \"telemetryValue\"}\n// }\n\nfunction decodePayload(input) {\n var output = { attributes: {}, telemetry: []};\n \n // --- Decoding code --- //\n var decoded = {};\n var historyDataList = [];\n var wifi = [];\n for (var i = 0; i < input.length - 2; ) {\n var channel_id = input[i++] & 0xff;\n var channel_type = input[i++] & 0xff;\n // BATTERY\n if(channel_id === 0x01 && channel_type === 0x75) {\n decoded.battery = input[i]; \n i += 1;\n }\n // TEMPERATURE\n if (channel_id === 0x03 && channel_type === 0x67) {\n // ℃\n decoded.temperature = parseBytesToInt(input, i, 2, false) / 10;\n // ℉\n // decoded.temperature = parseBytesToInt(input, i, 2, false) / 10 * 1.8 + 32;\n i += 2;\n }\n // Location\n if ((channel_id === 0x04 || channel_id == 0x84) && channel_type === 0x88) {\n decoded.latitude = parseBytesToInt(input, i, 4, false) / 1000000;\n decoded.longitude = parseBytesToInt(input, i+4, 4, false) / 1000000;\n var status = input[i+8];\n decoded.motion_status = getMotionStatus(status & 0x0f);\n decoded.geofence_status = getGeofenceStatus((status >> 4) & 0x0f);\n i +=9;\n }\n // Position\n if (channel_id === 0x05 && channel_type === 0x00) {\n decoded.position = input[i] === 0 ? \"normal\" : \"tilt\";\n i += 1;\n }\n // Wi-Fi SCAN RESULT\n if (channel_id === 0x06 && channel_type === 0xd9) {\n var wifiObject = {};\n wifiObject.group = input[i];\n wifiObject.mac = readMAC(input.slice(i + 1, i + 7));\n wifiObject.rssi = input[i+7];\n wifiObject.motion_status = getMotionStatus(input[i + 8] & 0x0f);\n i += 9;\n\n decoded.wifi_scan_result = \"finish\";\n if (wifiObject.mac === \"ff:ff:ff:ff:ff:ff\") {\n decoded.wifi_scan_result = \"timeout\";\n continue;\n }\n decoded.motion_status = wifiObject.motion_status;\n\n wifi.add(wifiObject);\n }\n //Tamper Status\n if (channel_id === 0x07 && channel_type === 0x00) {\n decoded.tamper_status = input[i] === 0 ? \"install\" : \"uninstall\";\n i +=1;\n }\n // TEMPERATURE WITH ABNORMAL\n if (channel_id === 0x83 && channel_type === 0x67) {\n decoded.temperature = parseBytesToInt(input, i, 2, false) / 10;\n decoded.temperature_abnormal = input[i + 2] == 0 ? false : true;\n i += 3;\n }\n // HISTORICAL DATA\n if (channel_id === 0x20 && channel_type === 0xce) {\n var historyData = {\n ts : parseBytesToInt(input, i, 4, false),\n values : {\n longitude : parseBytesToInt(input, i + 4, 4, false) / 1000000,\n latitude : parseBytesToInt(input, i + 8, 4, false) / 1000000\n }\n };\n \n historyDataList.add(historyData);\n \n i += 12;\n } \n }\n \n decoded.wifi = wifi.size > 0 ? wifi : null;\n \n output.telemetry = [{\n ts: timestamp,\n values: decoded\n }];\n \n output.telemetry.addAll(historyDataList);\n\n // --- Decoding code --- //\n return output;\n}\n\n// --- attributes and telemetry objects ---\nvar telemetry = [];\nvar attributes = {};\n// --- attributes and telemetry objects ---\n\n// --- Timestamp parsing\ntimestamp = data.ts;\n// --- Timestamp parsing\n\n// Message parsing\n// To avoid paths in the decoded objects we passing false value to function as \"pathInKey\" argument.\n// Warning: pathInKey can cause already found fields to be overwritten with the last value found.\n\nvar uplinkDataList = [];\n\n// Passing incoming bytes to decodePayload function, to get custom decoding\nvar customDecoding = decodePayload(hexToBytes(data.data));\n\n// Collecting data to result\nif (customDecoding.?telemetry.size() > 0) {\n if (customDecoding.telemetry instanceof java.util.ArrayList) {\n foreach(telemetryObj: customDecoding.telemetry) {\n if (telemetryObj.ts != null && telemetryObj.values != null) {\n telemetry.add(telemetryObj);\n }\n }\n } else {\n telemetry.putAll(customDecoding.telemetry);\n }\n}\n\nif (customDecoding.?attributes.size() > 0) {\n attributes.putAll(customDecoding.attributes);\n}\n\n// You can add some keys manually to attributes or telemetry\nattributes.eui = data.EUI;\nattributes.fPort = data.port;\nattributes.frequency = data.freq;\n\nvar addDataToTelemetry = {};\naddDataToTelemetry.rssi = data.rssi;\naddDataToTelemetry.seqno = data.seqno;\naddDataToTelemetry.snr = data.snr;\naddDataToTelemetry.ack = data.ack;\naddDataToTelemetry.toa = data.toa;\naddDataToTelemetry.fCnt = data.fcnt;\n\nvar isIncludeGatewayInfo = metadata[\"includeGatewayInfo\"];\nif(isIncludeGatewayInfo == true) {\n telemetry = processTelemetryData(telemetry, addDataToTelemetry);\n}\n\nvar deviceInfo = {\n deviceName: deviceName,\n deviceType: deviceType,\n// assetName: assetName,\n// assetType: assetType,\n attributes: attributes,\n telemetry: telemetry, \n};\n\naddAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName);\n\nuplinkDataList.add(deviceInfo);\n\nvar gatewayDeviceNamePrefix = \"Gateway \";\nvar gatewayDeviceType = \"Lora gateway\";\nvar gatewayGroupName = null; // If gatewayGroupName is not null - created device will be added to the entity group with such name.\n\nif (data.cmd == \"gw\") {\n foreach( gatewayInfo : data.gws ) {\n var addGatewayInfo = {};\n\n // You can add some keys manually telemetry\n addGatewayInfo.rssi = gatewayInfo.rssi;\n addGatewayInfo.snr = gatewayInfo.snr;\n // You can add some keys manually telemetry\n \n var gatewayInfoMsg = {\n deviceName: gatewayDeviceNamePrefix + gatewayInfo.gweui,\n deviceType: gatewayDeviceType,\n telemetry: [{\n \"ts\": gatewayInfo.ts,\n \"values\": addGatewayInfo\n }],\n attributes: {\n eui: gatewayInfo.gweui\n }\n };\n addAdditionalInfoForDeviceMsg(gatewayInfoMsg, customerName, gatewayGroupName);\n uplinkDataList.add(gatewayInfoMsg);\n }\n}\n\nreturn uplinkDataList;\n\nfunction addAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName) {\n if (customerName != null) {\n deviceInfo.customerName = customerName;\n }\n if (groupName != null) {\n deviceInfo.groupName = groupName;\n }\n}\n\nfunction parseDateToTimestamp(dateString) {\n var timestamp = -1;\n if (dateString != null) {\n \n timestamp = new Date(dateString).getTime();\n if (timestamp == -1) {\n var secondsSeparatorIndex = dateString.lastIndexOf('.') + 1;\n var millisecondsEndIndex = dateString.lastIndexOf('+');\n if (millisecondsEndIndex == -1) {\n millisecondsEndIndex = dateString.lastIndexOf('Z');\n }\n if (millisecondsEndIndex == -1) {\n millisecondsEndIndex = dateString.lastIndexOf('-');\n }\n if (millisecondsEndIndex == -1) {\n if (dateString.length >= secondsSeparatorIndex + 3) {\n dateString = dateString.substring(0, secondsSeparatorIndex + 3);\n }\n } else {\n dateString = dateString.substring(0, secondsSeparatorIndex + 3) +\n dateString.substring(millisecondsEndIndex, dateString.length);\n }\n \n timestamp = new Date(dateString).getTime();\n }\n }\n // If we cannot parse timestamp - we will use the current timestamp\n if (timestamp == -1) {\n timestamp = Date.now();\n }\n \n return timestamp;\n}\n\nfunction processTelemetryData(telemetry, addDataToTelemetry) {\n if (telemetry.size >= 1) {\n telemetry = addDataToTelemetries(telemetry, addDataToTelemetry);\n }\n else {\n telemetry.add(addDataToTelemetry);\n }\n \n return telemetry;\n}\n\nfunction addDataToTelemetries(telemetries, addDataToTelemetry) {\n foreach(telemetry : telemetries) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[\"values\"].keys.contains(element.key)) {\n telemetry[\"values\"][element.key] = element.value;\n }\n } \n }\n \n return telemetries;\n}\n\nfunction getMotionStatus(status) {\n if(status == 0) {\n return \"unknown\";\n }\n else if (status == 1) {\n return \"start moving\";\n }\n else if (status == 2) {\n return \"moving\";\n }\n else {\n return \"stop moving\";\n }\n}\n\nfunction getGeofenceStatus(status) {\n if(status == 0) {\n return \"inside\";\n }\n else if (status == 1) {\n return \"outside\";\n }\n else if (status == 2) {\n return \"unset\";\n }\n else {\n return \"unknown\";\n }\n}\n\nfunction readMAC(bytes) {\n var temp = [];\n for (b : bytes) {\n temp.add(String.format(\"%02x\", b & 0xFF));\n }\n return String.join(\":\", temp);\n}", "encoder": null, "tbelEncoder": null, "updateOnlyKeys": [ diff --git a/VENDORS/Milesight/AT101/LORIOT/uplink/payload_2.json b/VENDORS/Milesight/AT101/LORIOT/uplink/payload_2.json new file mode 100644 index 00000000..72fe9064 --- /dev/null +++ b/VENDORS/Milesight/AT101/LORIOT/uplink/payload_2.json @@ -0,0 +1,32 @@ +{ + "cmd": "gw", + "seqno": 4, + "EUI": "0102030405060708", + "ts": 1690901260493, + "fcnt": 3, + "port": 207, + "freq": 868300000, + "toa": 1319, + "dr": "SF12 BW125 4/5", + "ack": false, + "gws": [ + { + "rssi": -38, + "snr": 8.5, + "ts": 1690901260493, + "time": "2023-08-01T14:47:40.493Z", + "gweui": "1020304080706050", + "ant": 0 + }, + { + "rssi": -42, + "snr": 8.8, + "ts": 1690901260495, + "time": "2023-08-01T14:47:40.495Z", + "gweui": "1020304081716151", + "ant": 0 + } + ], + "bat": 143, + "data": "0175640367120105000106d90024e124f5b797b30006d90024e124ff0004c80006d90024e124f319a8c10006d9000650c20eaa8dc50006d90024e124f721c4b900" +} diff --git a/VENDORS/Milesight/AT101/LORIOT/uplink/result_2.json b/VENDORS/Milesight/AT101/LORIOT/uplink/result_2.json new file mode 100644 index 00000000..3fd16ece --- /dev/null +++ b/VENDORS/Milesight/AT101/LORIOT/uplink/result_2.json @@ -0,0 +1,71 @@ +[{ + "deviceName": "AT101 0102030405060708", + "deviceType": "AT101", + "attributes": { + "eui": "0102030405060708", + "fPort": 207, + "frequency": 868300000 + }, + "telemetry": [{ + "ts": 1690901260493, + "values": { + "battery": 100, + "temperature": 27.4, + "position": "tilt", + "wifi_scan_result": "finish", + "motion_status": "unknown", + "wifi": [{ + "group": 0, + "mac": "24:e1:24:f5:b7:97", + "rssi": -77, + "motion_status": "unknown" + }, { + "group": 0, + "mac": "24:e1:24:ff:00:04", + "rssi": -56, + "motion_status": "unknown" + }, { + "group": 0, + "mac": "24:e1:24:f3:19:a8", + "rssi": -63, + "motion_status": "unknown" + }, { + "group": 0, + "mac": "06:50:c2:0e:aa:8d", + "rssi": -59, + "motion_status": "unknown" + }, { + "group": 0, + "mac": "24:e1:24:f7:21:c4", + "rssi": -71, + "motion_status": "unknown" + }] + } + }] +}, { + "deviceName": "Gateway 1020304080706050", + "deviceType": "Lora gateway", + "telemetry": [{ + "ts": 1690901260493, + "values": { + "rssi": -38, + "snr": 8.5 + } + }], + "attributes": { + "eui": "1020304080706050" + } +}, { + "deviceName": "Gateway 1020304081716151", + "deviceType": "Lora gateway", + "telemetry": [{ + "ts": 1690901260495, + "values": { + "rssi": -42, + "snr": 8.8 + } + }], + "attributes": { + "eui": "1020304081716151" + } +}] \ No newline at end of file diff --git a/VENDORS/Milesight/CT101-CT103/LORIOT/uplink/converter.json b/VENDORS/Milesight/CT101-CT103/LORIOT/uplink/converter.json index c9ce64f0..4262820c 100644 --- a/VENDORS/Milesight/CT101-CT103/LORIOT/uplink/converter.json +++ b/VENDORS/Milesight/CT101-CT103/LORIOT/uplink/converter.json @@ -1,11 +1,16 @@ { "name": "Uplink data converter for Loriot integration СТ101/СТ103", "type": "UPLINK", - "debugMode": true, + "debugMode": false, + "debugSettings": { + "failuresEnabled": true, + "allEnabled": false, + "allEnabledUntil": 1735209748497 + }, "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);\nvar deviceName = \"CT101/CT103 \" + data.EUI;\nvar deviceType = \"CT101/CT103\";\nvar groupName = null; // If groupName is not null - created device will be added to the entity group with such name.\nvar customerName = null; // If customerName is not null - created devices will be assigned to customer with such name. \n\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// If you want to parse incoming data somehow, you can add your code to this function.\n// input: bytes\n// expected output:\n// {\n// \"attributes\": {\"attributeKey\": \"attributeValue\"},\n// \"telemetry\": {\"telemetryKey\": \"telemetryValue\"}\n// }\n\nfunction decodePayload(input) {\n var output = { attributes: {}, telemetry: []};\n \n // --- Decoding code --- //\n var decoded = {};\n for (var i = 0; i < input.length - 2; ) {\n var channel_id = input[i++] & 0xff;\n var channel_type = input[i++] & 0xff;\n \n // POWER STATE\n if (channel_id === 0xff && channel_type === 0x0b) {\n decoded.power = \"on\";\n i += 1;\n }\n // IPSO VERSION\n if (channel_id === 0xff && channel_type === 0x01) {\n decoded.ipso_version = readProtocolVersion(input[i]);\n i += 1;\n }\n // PRODUCT SERIAL NUMBER\n if (channel_id === 0xff && channel_type === 0x16) {\n decoded.sn = bytesToHex(input.slice(i, i + 8));\n i += 8;\n }\n // HARDWARE VERSION\n if (channel_id === 0xff && channel_type === 0x09) {\n decoded.hardware_version = readHardwareVersion(input.slice(i, i + 2));\n i += 2;\n }\n // FIRMWARE VERSION\n if (channel_id === 0xff && channel_type === 0x0a) {\n decoded.firmware_version = readFirmwareVersion(input.slice(i, i + 2));\n i += 2;\n }\n // TOTAL CURRENT\n if (channel_id === 0x03 && channel_type === 0x97) {\n decoded.total_current = parseBytesToInt(input, i, 4, false) / 100;\n i += 4;\n }\n // CURRENT\n if (channel_id === 0x04 && channel_type === 0x98) {\n var value = parseBytesToInt(input, i, 2, false);\n if (value === 0xffff) {\n decoded.alarm = \"read failed\";\n } else {\n decoded.current = value / 100;\n }\n i += 2;\n }\n // TEMPERATURE\n if (channel_id === 0x09 && channel_type === 0x67) {\n var temperature_value = parseBytesToInt(input, i, 2, false);\n if (temperature_value === 0xfffd) {\n decoded.temperature_exception = \"over range alarm\";\n } else if (temperature_value === 0xffff) {\n decoded.temperature_exception = \"read failed\";\n } else {\n decoded.temperature = parseBytesToInt(input, i, 2, false) / 10;\n }\n i += 2;\n }\n // CURRENT ALARM\n if (channel_id === 0x84 && channel_type === 0x98) {\n decoded.current_max = parseBytesToInt(input, i, 2, false) / 100;\n decoded.current_min = parseBytesToInt(input, i+2, 2, false) / 100;\n decoded.current = parseBytesToInt(input, i+4, 2, false) / 100;\n decoded.alarm = readCurrentAlarm(input[i + 6]);\n i += 7;\n }\n // TEMPERATURE ALARM\n if (channel_id === 0x89 && channel_type === 0x67) {\n decoded.temperature = parseBytesToInt(input, i, 2, false) / 10;\n decoded.temperature_alarm = readTemperatureAlarm(input[i + 2]);\n i += 3;\n }\n }\n \n output.telemetry = [{\n ts: timestamp,\n values: decoded\n }];\n\n // --- Decoding code --- //\n return output;\n}\n\n// --- attributes and telemetry objects ---\nvar telemetry = [];\nvar attributes = {};\n// --- attributes and telemetry objects ---\n\n// --- Timestamp parsing\ntimestamp = data.ts;\n// --- Timestamp parsing\n\n// Message parsing\n// To avoid paths in the decoded objects we passing false value to function as \"pathInKey\" argument.\n// Warning: pathInKey can cause already found fields to be overwritten with the last value found.\n\nvar uplinkDataList = [];\n\n// Passing incoming bytes to decodePayload function, to get custom decoding\nvar customDecoding = decodePayload(hexToBytes(data.data));\n\n// Collecting data to result\nif (customDecoding.?telemetry.size() > 0) {\n if (customDecoding.telemetry instanceof java.util.ArrayList) {\n foreach(telemetryObj: customDecoding.telemetry) {\n if (telemetryObj.ts != null && telemetryObj.values != null) {\n telemetry.add(telemetryObj);\n }\n }\n } else {\n telemetry.putAll(customDecoding.telemetry);\n }\n}\n\nif (customDecoding.?attributes.size() > 0) {\n attributes.putAll(customDecoding.attributes);\n}\n\n// You can add some keys manually to attributes or telemetry\nattributes.eui = data.EUI;\nattributes.fPort = data.port;\nattributes.frequency = data.freq;\n\nvar addDataToTelemetry = {};\naddDataToTelemetry.rssi = data.rssi;\naddDataToTelemetry.seqno = data.seqno;\naddDataToTelemetry.snr = data.snr;\naddDataToTelemetry.ack = data.ack;\naddDataToTelemetry.toa = data.toa;\naddDataToTelemetry.fCnt = data.fcnt;\n\nvar isIncludeGatewayInfo = metadata[\"includeGatewayInfo\"];\nif(isIncludeGatewayInfo == true) {\n telemetry = processTelemetryData(telemetry, addDataToTelemetry);\n}\n\nvar deviceInfo = {\n deviceName: deviceName,\n deviceType: deviceType,\n// assetName: assetName,\n// assetType: assetType,\n attributes: attributes,\n telemetry: telemetry, \n};\n\naddAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName);\n\nuplinkDataList.add(deviceInfo);\n\nvar includeGatewayInfo = [\"ts\", \"gweui\", \"rssi\"];\n\nvar gatewayDeviceNamePrefix = \"Gateway \";\nvar gatewayDeviceType = \"Lora gateway\";\nvar gatewayGroupName = null; // If gatewayGroupName is not null - created device will be added to the entity group with such name.\n\nif (data.cmd == \"gw\") {\n foreach( gatewayInfo : data.gws ) {\n var gatewayInfoMsg = {\n deviceName: gatewayDeviceNamePrefix + gatewayInfo.gweui,\n deviceType: gatewayDeviceType,\n telemetry: [{\n \"ts\": parseDateToTimestamp(gatewayInfo.ts),\n \"values\": getDataList(gatewayInfo, includeGatewayInfo)\n }],\n attributes: {\n eui: gatewayInfo.gweui\n }\n };\n addAdditionalInfoForDeviceMsg(gatewayInfoMsg, customerName, gatewayGroupName);\n uplinkDataList.add(gatewayInfoMsg);\n }\n}\n\nreturn uplinkDataList;\n\nfunction addAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName) {\n if (customerName != null) {\n deviceInfo.customerName = customerName;\n }\n if (groupName != null) {\n deviceInfo.groupName = groupName;\n }\n}\n\nfunction parseDateToTimestamp(dateString) {\n var timestamp = -1;\n if (dateString != null) {\n \n timestamp = new Date(dateString).getTime();\n if (timestamp == -1) {\n var secondsSeparatorIndex = dateString.lastIndexOf('.') + 1;\n var millisecondsEndIndex = dateString.lastIndexOf('+');\n if (millisecondsEndIndex == -1) {\n millisecondsEndIndex = dateString.lastIndexOf('Z');\n }\n if (millisecondsEndIndex == -1) {\n millisecondsEndIndex = dateString.lastIndexOf('-');\n }\n if (millisecondsEndIndex == -1) {\n if (dateString.length >= secondsSeparatorIndex + 3) {\n dateString = dateString.substring(0, secondsSeparatorIndex + 3);\n }\n } else {\n dateString = dateString.substring(0, secondsSeparatorIndex + 3) +\n dateString.substring(millisecondsEndIndex, dateString.length);\n }\n \n timestamp = new Date(dateString).getTime();\n }\n }\n // If we cannot parse timestamp - we will use the current timestamp\n if (timestamp == -1) {\n timestamp = Date.now();\n }\n \n return timestamp;\n}\n\nfunction processTelemetryData(telemetry, addDataToTelemetry) {\n if (telemetry.size > 1) {\n telemetry = addDataToMultipleTelemetries(telemetry, addDataToTelemetry);\n }\n else if (telemetry.size == 1) {\n telemetry = addDataToSingleTelemetry(telemetry, addDataToTelemetry);\n }\n else {\n telemetry.add(addDataToTelemetry);\n }\n \n return telemetry;\n}\n\nfunction addDataToMultipleTelemetries(telemetry, addDataToTelemetry) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[0][\"values\"].keys.contains(element.key)) {\n telemetry[0][\"values\"][element.key] = element.value;\n }\n if (!telemetry[1][\"values\"].keys.contains(element.key)) {\n telemetry[1][\"values\"][element.key] = element.value;\n }\n }\n \n return telemetry;\n}\n\nfunction addDataToSingleTelemetry(telemetry, addDataToTelemetry) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[0][\"values\"].keys.contains(element.key)) {\n telemetry[0][\"values\"][element.key] = element.value;\n }\n }\n \n return telemetry;\n}\n\nfunction readProtocolVersion(bytes) {\n var major = (bytes & 0xf0) >> 4;\n var minor = bytes & 0x0f;\n return \"v\" + major + \".\" + minor;\n}\n\nfunction readHardwareVersion(bytes) {\n var major = bytes[0] & 0xff;\n var minor = (bytes[1] & 0xff) >> 4;\n return \"v\" + major + \".\" + minor;\n}\n\nfunction readFirmwareVersion(bytes) {\n var major = bytes[0] & 0xff;\n var minor = bytes[1] & 0xff;\n return \"v\" + major + \".\" + minor;\n}\n\nfunction readCurrentAlarm(type) {\n var alarm = [];\n if ((type >> 0 & 0x01) != 0) {\n alarm.add(\"threshold alarm\");\n }\n if ((type >> 1 & 0x01) != 0) {\n alarm.add(\"threshold alarm release\");\n }\n if ((type >> 2 & 0x01) != 0) {\n alarm.add(\"over range alarm\");\n }\n if ((type >> 3 & 0x01) != 0) {\n alarm.add(\"over range alarm release\");\n }\n \n return alarm;\n}\n\nfunction readTemperatureAlarm(type) {\n var alarms = [];\n \n if ((type & 0x01) != 0) {\n alarms.add(\"Threshold alarm\");\n }\n if ((type & 0x02) != 0) {\n alarms.add(\"Threshold alarm dismiss\");\n }\n\n return alarms;\n}", + "tbelDecoder": "var data = decodeToJson(payload);\nvar deviceName = \"CT101/CT103 \" + data.EUI;\nvar deviceType = \"CT101/CT103\";\nvar groupName = null; // If groupName is not null - created device will be added to the entity group with such name.\nvar customerName = null; // If customerName is not null - created devices will be assigned to customer with such name. \n\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// If you want to parse incoming data somehow, you can add your code to this function.\n// input: bytes\n// expected output:\n// {\n// \"attributes\": {\"attributeKey\": \"attributeValue\"},\n// \"telemetry\": {\"telemetryKey\": \"telemetryValue\"}\n// }\n\nfunction decodePayload(input) {\n var output = { attributes: {}, telemetry: []};\n \n // --- Decoding code --- //\n var decoded = {};\n for (var i = 0; i < input.length - 2; ) {\n var channel_id = input[i++] & 0xff;\n var channel_type = input[i++] & 0xff;\n \n // POWER STATE\n if (channel_id === 0xff && channel_type === 0x0b) {\n decoded.power = \"on\";\n i += 1;\n }\n // IPSO VERSION\n if (channel_id === 0xff && channel_type === 0x01) {\n decoded.ipso_version = readProtocolVersion(input[i]);\n i += 1;\n }\n // PRODUCT SERIAL NUMBER\n if (channel_id === 0xff && channel_type === 0x16) {\n decoded.sn = bytesToHex(input.slice(i, i + 8));\n i += 8;\n }\n // HARDWARE VERSION\n if (channel_id === 0xff && channel_type === 0x09) {\n decoded.hardware_version = readHardwareVersion(input.slice(i, i + 2));\n i += 2;\n }\n // FIRMWARE VERSION\n if (channel_id === 0xff && channel_type === 0x0a) {\n decoded.firmware_version = readFirmwareVersion(input.slice(i, i + 2));\n i += 2;\n }\n // TOTAL CURRENT\n if (channel_id === 0x03 && channel_type === 0x97) {\n decoded.total_current = parseBytesToInt(input, i, 4, false) / 100;\n i += 4;\n }\n // CURRENT\n if (channel_id === 0x04 && channel_type === 0x98) {\n var value = parseBytesToInt(input, i, 2, false);\n if (value === 0xffff) {\n decoded.alarm = \"read failed\";\n } else {\n decoded.current = value / 100;\n }\n i += 2;\n }\n // TEMPERATURE\n if (channel_id === 0x09 && channel_type === 0x67) {\n var temperature_value = parseBytesToInt(input, i, 2, false);\n if (temperature_value === 0xfffd) {\n decoded.temperature_exception = \"over range alarm\";\n } else if (temperature_value === 0xffff) {\n decoded.temperature_exception = \"read failed\";\n } else {\n decoded.temperature = parseBytesToInt(input, i, 2, false) / 10;\n }\n i += 2;\n }\n // CURRENT ALARM\n if (channel_id === 0x84 && channel_type === 0x98) {\n decoded.current_max = parseBytesToInt(input, i, 2, false) / 100;\n decoded.current_min = parseBytesToInt(input, i+2, 2, false) / 100;\n decoded.current = parseBytesToInt(input, i+4, 2, false) / 100;\n decoded.alarm = readCurrentAlarm(input[i + 6]);\n i += 7;\n }\n // TEMPERATURE ALARM\n if (channel_id === 0x89 && channel_type === 0x67) {\n decoded.temperature = parseBytesToInt(input, i, 2, false) / 10;\n decoded.temperature_alarm = readTemperatureAlarm(input[i + 2]);\n i += 3;\n }\n }\n \n output.telemetry = [{\n ts: timestamp,\n values: decoded\n }];\n\n // --- Decoding code --- //\n return output;\n}\n\n// --- attributes and telemetry objects ---\nvar telemetry = [];\nvar attributes = {};\n// --- attributes and telemetry objects ---\n\n// --- Timestamp parsing\ntimestamp = data.ts;\n// --- Timestamp parsing\n\n// Message parsing\n// To avoid paths in the decoded objects we passing false value to function as \"pathInKey\" argument.\n// Warning: pathInKey can cause already found fields to be overwritten with the last value found.\n\nvar uplinkDataList = [];\n\n// Passing incoming bytes to decodePayload function, to get custom decoding\nvar customDecoding = decodePayload(hexToBytes(data.data));\n\n// Collecting data to result\nif (customDecoding.?telemetry.size() > 0) {\n if (customDecoding.telemetry instanceof java.util.ArrayList) {\n foreach(telemetryObj: customDecoding.telemetry) {\n if (telemetryObj.ts != null && telemetryObj.values != null) {\n telemetry.add(telemetryObj);\n }\n }\n } else {\n telemetry.putAll(customDecoding.telemetry);\n }\n}\n\nif (customDecoding.?attributes.size() > 0) {\n attributes.putAll(customDecoding.attributes);\n}\n\n// You can add some keys manually to attributes or telemetry\nattributes.eui = data.EUI;\nattributes.fPort = data.port;\nattributes.frequency = data.freq;\n\nvar addDataToTelemetry = {};\naddDataToTelemetry.rssi = data.rssi;\naddDataToTelemetry.seqno = data.seqno;\naddDataToTelemetry.snr = data.snr;\naddDataToTelemetry.ack = data.ack;\naddDataToTelemetry.toa = data.toa;\naddDataToTelemetry.fCnt = data.fcnt;\n\nvar isIncludeGatewayInfo = metadata[\"includeGatewayInfo\"];\nif(isIncludeGatewayInfo == true) {\n telemetry = processTelemetryData(telemetry, addDataToTelemetry);\n}\n\nvar deviceInfo = {\n deviceName: deviceName,\n deviceType: deviceType,\n// assetName: assetName,\n// assetType: assetType,\n attributes: attributes,\n telemetry: telemetry, \n};\n\naddAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName);\n\nuplinkDataList.add(deviceInfo);\n\nvar gatewayDeviceNamePrefix = \"Gateway \";\nvar gatewayDeviceType = \"Lora gateway\";\nvar gatewayGroupName = null; // If gatewayGroupName is not null - created device will be added to the entity group with such name.\n\nif (data.cmd == \"gw\") {\n foreach( gatewayInfo : data.gws ) {\n var addGatewayInfo = {};\n\n // You can add some keys manually telemetry\n addGatewayInfo.rssi = gatewayInfo.rssi;\n addGatewayInfo.snr = gatewayInfo.snr;\n // You can add some keys manually telemetry\n \n var gatewayInfoMsg = {\n deviceName: gatewayDeviceNamePrefix + gatewayInfo.gweui,\n deviceType: gatewayDeviceType,\n telemetry: [{\n \"ts\": gatewayInfo.ts,\n \"values\": addGatewayInfo\n }],\n attributes: {\n eui: gatewayInfo.gweui\n }\n };\n addAdditionalInfoForDeviceMsg(gatewayInfoMsg, customerName, gatewayGroupName);\n uplinkDataList.add(gatewayInfoMsg);\n }\n}\n\nreturn uplinkDataList;\n\nfunction addAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName) {\n if (customerName != null) {\n deviceInfo.customerName = customerName;\n }\n if (groupName != null) {\n deviceInfo.groupName = groupName;\n }\n}\n\nfunction parseDateToTimestamp(dateString) {\n var timestamp = -1;\n if (dateString != null) {\n \n timestamp = new Date(dateString).getTime();\n if (timestamp == -1) {\n var secondsSeparatorIndex = dateString.lastIndexOf('.') + 1;\n var millisecondsEndIndex = dateString.lastIndexOf('+');\n if (millisecondsEndIndex == -1) {\n millisecondsEndIndex = dateString.lastIndexOf('Z');\n }\n if (millisecondsEndIndex == -1) {\n millisecondsEndIndex = dateString.lastIndexOf('-');\n }\n if (millisecondsEndIndex == -1) {\n if (dateString.length >= secondsSeparatorIndex + 3) {\n dateString = dateString.substring(0, secondsSeparatorIndex + 3);\n }\n } else {\n dateString = dateString.substring(0, secondsSeparatorIndex + 3) +\n dateString.substring(millisecondsEndIndex, dateString.length);\n }\n \n timestamp = new Date(dateString).getTime();\n }\n }\n // If we cannot parse timestamp - we will use the current timestamp\n if (timestamp == -1) {\n timestamp = Date.now();\n }\n \n return timestamp;\n}\n\nfunction processTelemetryData(telemetry, addDataToTelemetry) {\n if (telemetry.size >= 1) {\n telemetry = addDataToTelemetries(telemetry, addDataToTelemetry);\n }\n else {\n telemetry.add(addDataToTelemetry);\n }\n \n return telemetry;\n}\n\nfunction addDataToTelemetries(telemetries, addDataToTelemetry) {\n foreach(telemetry : telemetries) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[\"values\"].keys.contains(element.key)) {\n telemetry[\"values\"][element.key] = element.value;\n }\n } \n }\n \n return telemetries;\n}\n\nfunction readProtocolVersion(bytes) {\n var major = (bytes & 0xf0) >> 4;\n var minor = bytes & 0x0f;\n return \"v\" + major + \".\" + minor;\n}\n\nfunction readHardwareVersion(bytes) {\n var major = bytes[0] & 0xff;\n var minor = (bytes[1] & 0xff) >> 4;\n return \"v\" + major + \".\" + minor;\n}\n\nfunction readFirmwareVersion(bytes) {\n var major = bytes[0] & 0xff;\n var minor = bytes[1] & 0xff;\n return \"v\" + major + \".\" + minor;\n}\n\nfunction readCurrentAlarm(type) {\n var alarm = [];\n if ((type >> 0 & 0x01) != 0) {\n alarm.add(\"threshold alarm\");\n }\n if ((type >> 1 & 0x01) != 0) {\n alarm.add(\"threshold alarm release\");\n }\n if ((type >> 2 & 0x01) != 0) {\n alarm.add(\"over range alarm\");\n }\n if ((type >> 3 & 0x01) != 0) {\n alarm.add(\"over range alarm release\");\n }\n \n return alarm;\n}\n\nfunction readTemperatureAlarm(type) {\n var alarms = [];\n \n if ((type & 0x01) != 0) {\n alarms.add(\"Threshold alarm\");\n }\n if ((type & 0x02) != 0) {\n alarms.add(\"Threshold alarm dismiss\");\n }\n\n return alarms;\n}", "encoder": null, "tbelEncoder": null, "updateOnlyKeys": [ diff --git a/VENDORS/Milesight/CT101-CT103/LORIOT/uplink/payload_5.json b/VENDORS/Milesight/CT101-CT103/LORIOT/uplink/payload_5.json new file mode 100644 index 00000000..ece22ce2 --- /dev/null +++ b/VENDORS/Milesight/CT101-CT103/LORIOT/uplink/payload_5.json @@ -0,0 +1,32 @@ +{ + "cmd": "gw", + "seqno": 4, + "EUI": "0102030405060708", + "ts": 1690901260493, + "fcnt": 3, + "port": 207, + "freq": 868300000, + "toa": 1319, + "dr": "SF12 BW125 4/5", + "ack": false, + "gws": [ + { + "rssi": -38, + "snr": 8.5, + "ts": 1690901260493, + "time": "2023-08-01T14:47:40.493Z", + "gweui": "1020304080706050", + "ant": 0 + }, + { + "rssi": -42, + "snr": 8.8, + "ts": 1690901260495, + "time": "2023-08-01T14:47:40.495Z", + "gweui": "1020304081716151", + "ant": 0 + } + ], + "bat": 143, + "data": "039710270000" +} diff --git a/VENDORS/Milesight/CT101-CT103/LORIOT/uplink/result_5.json b/VENDORS/Milesight/CT101-CT103/LORIOT/uplink/result_5.json new file mode 100644 index 00000000..3c208ab8 --- /dev/null +++ b/VENDORS/Milesight/CT101-CT103/LORIOT/uplink/result_5.json @@ -0,0 +1,41 @@ +[{ + "deviceName": "CT101/CT103 0102030405060708", + "deviceType": "CT101/CT103", + "attributes": { + "eui": "0102030405060708", + "fPort": 207, + "frequency": 868300000 + }, + "telemetry": [{ + "ts": 1690901260493, + "values": { + "total_current": 100.0 + } + }] +}, { + "deviceName": "Gateway 1020304080706050", + "deviceType": "Lora gateway", + "telemetry": [{ + "ts": 1690901260493, + "values": { + "rssi": -38, + "snr": 8.5 + } + }], + "attributes": { + "eui": "1020304080706050" + } +}, { + "deviceName": "Gateway 1020304081716151", + "deviceType": "Lora gateway", + "telemetry": [{ + "ts": 1690901260495, + "values": { + "rssi": -42, + "snr": 8.8 + } + }], + "attributes": { + "eui": "1020304081716151" + } +}] \ No newline at end of file diff --git a/VENDORS/Milesight/DS3604/LORIOT/uplink/converter.json b/VENDORS/Milesight/DS3604/LORIOT/uplink/converter.json index b726608e..717d4287 100644 --- a/VENDORS/Milesight/DS3604/LORIOT/uplink/converter.json +++ b/VENDORS/Milesight/DS3604/LORIOT/uplink/converter.json @@ -1,11 +1,16 @@ { "name": "Uplink data converter for Loriot integration DS3604", "type": "UPLINK", - "debugMode": true, + "debugMode": false, + "debugSettings": { + "failuresEnabled": true, + "allEnabled": false, + "allEnabledUntil": 1735209985818 + }, "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);\nvar deviceName = \"DS3604 \" + data.EUI;\nvar deviceType = \"DS3604\";\nvar groupName = null; // If groupName is not null - created device will be added to the entity group with such name.\nvar customerName = null; // If customerName is not null - created devices will be assigned to customer with such name. \n\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// If you want to parse incoming data somehow, you can add your code to this function.\n// input: bytes\n// expected output:\n// {\n// \"attributes\": {\"attributeKey\": \"attributeValue\"},\n// \"telemetry\": {\"telemetryKey\": \"telemetryValue\"}\n// }\n\nfunction decodePayload(input) {\n var output = { attributes: {}, telemetry: []};\n \n // --- Decoding code --- //\n var decoded = {};\n for (var i = 0; i < input.length - 2; ) {\n var channel_id = input[i++] & 0xff;\n var channel_type = input[i++] & 0xff;\n // BATTERY\n if(channel_id === 0x01 && channel_type === 0x75) {\n decoded.battery = input[i]; \n i += 1;\n }\n // TEMPLATE\n else if (channel_id == 0xff && channel_type == 0x73) {\n decoded.template = input[i] + 1;\n i += 1;\n }\n // TEMPLATE BLOCK CHANNEL DATA\n if (channel_id == 0xfb && channel_type == 0x01) {\n var template_id = (input[i] >> 6) + 1;\n var block_id = input[i++] & 0x3f;\n var block_name;\n if (block_id < 10) {\n block_name = \"text_\" + (block_id + 1);\n block_length = input[i++];\n decoded[block_name] = fromUtf8Bytes(input.slice(i, i + block_length));\n i += block_length;\n } else if (block_id == 10) {\n block_name = \"qrcode\";\n block_length = input[i++];\n decoded[block_name] = fromUtf8Bytes(input.slice(i, i + block_length));\n i += block_length;\n }\n decoded.template = template_id;\n }\n }\n \n output.telemetry = [{\n ts: timestamp,\n values: decoded\n }];\n\n // --- Decoding code --- //\n return output;\n}\n\n// --- attributes and telemetry objects ---\nvar telemetry = [];\nvar attributes = {};\n// --- attributes and telemetry objects ---\n\n// --- Timestamp parsing\ntimestamp = data.ts;\n// --- Timestamp parsing\n\n// Message parsing\n// To avoid paths in the decoded objects we passing false value to function as \"pathInKey\" argument.\n// Warning: pathInKey can cause already found fields to be overwritten with the last value found.\n\nvar uplinkDataList = [];\n\n// Passing incoming bytes to decodePayload function, to get custom decoding\nvar customDecoding = decodePayload(hexToBytes(data.data));\n\n// Collecting data to result\nif (customDecoding.?telemetry.size() > 0) {\n if (customDecoding.telemetry instanceof java.util.ArrayList) {\n foreach(telemetryObj: customDecoding.telemetry) {\n if (telemetryObj.ts != null && telemetryObj.values != null) {\n telemetry.add(telemetryObj);\n }\n }\n } else {\n telemetry.putAll(customDecoding.telemetry);\n }\n}\n\nif (customDecoding.?attributes.size() > 0) {\n attributes.putAll(customDecoding.attributes);\n}\n\n// You can add some keys manually to attributes or telemetry\nattributes.eui = data.EUI;\nattributes.fPort = data.port;\nattributes.frequency = data.freq;\n\nvar addDataToTelemetry = {};\naddDataToTelemetry.rssi = data.rssi;\naddDataToTelemetry.seqno = data.seqno;\naddDataToTelemetry.snr = data.snr;\naddDataToTelemetry.ack = data.ack;\naddDataToTelemetry.toa = data.toa;\naddDataToTelemetry.fCnt = data.fcnt;\n\nvar isIncludeGatewayInfo = metadata[\"includeGatewayInfo\"];\nif(isIncludeGatewayInfo == true) {\n telemetry = processTelemetryData(telemetry, addDataToTelemetry);\n}\n\nvar deviceInfo = {\n deviceName: deviceName,\n deviceType: deviceType,\n// assetName: assetName,\n// assetType: assetType,\n attributes: attributes,\n telemetry: telemetry, \n};\n\naddAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName);\n\nuplinkDataList.add(deviceInfo);\n\nvar includeGatewayInfo = [\"ts\", \"gweui\", \"rssi\"];\n\nvar gatewayDeviceNamePrefix = \"Gateway \";\nvar gatewayDeviceType = \"Lora gateway\";\nvar gatewayGroupName = null; // If gatewayGroupName is not null - created device will be added to the entity group with such name.\n\nif (data.cmd == \"gw\") {\n foreach( gatewayInfo : data.gws ) {\n var gatewayInfoMsg = {\n deviceName: gatewayDeviceNamePrefix + gatewayInfo.gweui,\n deviceType: gatewayDeviceType,\n telemetry: [{\n \"ts\": parseDateToTimestamp(gatewayInfo.ts),\n \"values\": getDataList(gatewayInfo, includeGatewayInfo)\n }],\n attributes: {\n eui: gatewayInfo.gweui\n }\n };\n addAdditionalInfoForDeviceMsg(gatewayInfoMsg, customerName, gatewayGroupName);\n uplinkDataList.add(gatewayInfoMsg);\n }\n}\n\nreturn uplinkDataList;\n\nfunction addAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName) {\n if (customerName != null) {\n deviceInfo.customerName = customerName;\n }\n if (groupName != null) {\n deviceInfo.groupName = groupName;\n }\n}\n\nfunction parseDateToTimestamp(dateString) {\n var timestamp = -1;\n if (dateString != null) {\n \n timestamp = new Date(dateString).getTime();\n if (timestamp == -1) {\n var secondsSeparatorIndex = dateString.lastIndexOf('.') + 1;\n var millisecondsEndIndex = dateString.lastIndexOf('+');\n if (millisecondsEndIndex == -1) {\n millisecondsEndIndex = dateString.lastIndexOf('Z');\n }\n if (millisecondsEndIndex == -1) {\n millisecondsEndIndex = dateString.lastIndexOf('-');\n }\n if (millisecondsEndIndex == -1) {\n if (dateString.length >= secondsSeparatorIndex + 3) {\n dateString = dateString.substring(0, secondsSeparatorIndex + 3);\n }\n } else {\n dateString = dateString.substring(0, secondsSeparatorIndex + 3) +\n dateString.substring(millisecondsEndIndex, dateString.length);\n }\n \n timestamp = new Date(dateString).getTime();\n }\n }\n // If we cannot parse timestamp - we will use the current timestamp\n if (timestamp == -1) {\n timestamp = Date.now();\n }\n \n return timestamp;\n}\n\nfunction processTelemetryData(telemetry, addDataToTelemetry) {\n if (telemetry.size > 1) {\n telemetry = addDataToMultipleTelemetries(telemetry, addDataToTelemetry);\n }\n else if (telemetry.size == 1) {\n telemetry = addDataToSingleTelemetry(telemetry, addDataToTelemetry);\n }\n else {\n telemetry.add(addDataToTelemetry);\n }\n \n return telemetry;\n}\n\nfunction addDataToMultipleTelemetries(telemetry, addDataToTelemetry) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[0][\"values\"].keys.contains(element.key)) {\n telemetry[0][\"values\"][element.key] = element.value;\n }\n if (!telemetry[1][\"values\"].keys.contains(element.key)) {\n telemetry[1][\"values\"][element.key] = element.value;\n }\n }\n \n return telemetry;\n}\n\nfunction addDataToSingleTelemetry(telemetry, addDataToTelemetry) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[0][\"values\"].keys.contains(element.key)) {\n telemetry[0][\"values\"][element.key] = element.value;\n }\n }\n \n return telemetry;\n}\n\nfunction fromUtf8Bytes(bytes) {\n var resultObject = \"\";\n \n foreach (b : bytes) {\n resultObject += String.format(\"%%%02X\", b & 0xFF);\n }\n \n return decodeUrlEncodedString(resultObject);\n}\n\nfunction decodeUrlEncodedString(encoded) {\n var decoded = \"\";\n for (int i = 0; i < encoded.length(); i++) {\n char c = encoded.charAt(i);\n if (c == '%' && i + 2 < encoded.length()) {\n var hexValue = \"\" + encoded.charAt(i + 1) + encoded.charAt(i + 2);\n var decodedChar = Integer.parseInt(hexValue, 16);\n decoded += (char) decodedChar;\n i += 2;\n } else {\n decoded += c;\n }\n }\n return decoded;\n}", + "tbelDecoder": "var data = decodeToJson(payload);\nvar deviceName = \"DS3604 \" + data.EUI;\nvar deviceType = \"DS3604\";\nvar groupName = null; // If groupName is not null - created device will be added to the entity group with such name.\nvar customerName = null; // If customerName is not null - created devices will be assigned to customer with such name. \n\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// If you want to parse incoming data somehow, you can add your code to this function.\n// input: bytes\n// expected output:\n// {\n// \"attributes\": {\"attributeKey\": \"attributeValue\"},\n// \"telemetry\": {\"telemetryKey\": \"telemetryValue\"}\n// }\n\nfunction decodePayload(input) {\n var output = { attributes: {}, telemetry: []};\n \n // --- Decoding code --- //\n var decoded = {};\n for (var i = 0; i < input.length - 2; ) {\n var channel_id = input[i++] & 0xff;\n var channel_type = input[i++] & 0xff;\n // BATTERY\n if(channel_id === 0x01 && channel_type === 0x75) {\n decoded.battery = input[i]; \n i += 1;\n }\n // TEMPLATE\n else if (channel_id == 0xff && channel_type == 0x73) {\n decoded.template = input[i] + 1;\n i += 1;\n }\n // TEMPLATE BLOCK CHANNEL DATA\n if (channel_id == 0xfb && channel_type == 0x01) {\n var template_id = (input[i] >> 6) + 1;\n var block_id = input[i++] & 0x3f;\n var block_name;\n if (block_id < 10) {\n block_name = \"text_\" + (block_id + 1);\n block_length = input[i++];\n decoded[block_name] = fromUtf8Bytes(input.slice(i, i + block_length));\n i += block_length;\n } else if (block_id == 10) {\n block_name = \"qrcode\";\n block_length = input[i++];\n decoded[block_name] = fromUtf8Bytes(input.slice(i, i + block_length));\n i += block_length;\n }\n decoded.template = template_id;\n }\n }\n \n output.telemetry = [{\n ts: timestamp,\n values: decoded\n }];\n\n // --- Decoding code --- //\n return output;\n}\n\n// --- attributes and telemetry objects ---\nvar telemetry = [];\nvar attributes = {};\n// --- attributes and telemetry objects ---\n\n// --- Timestamp parsing\ntimestamp = data.ts;\n// --- Timestamp parsing\n\n// Message parsing\n// To avoid paths in the decoded objects we passing false value to function as \"pathInKey\" argument.\n// Warning: pathInKey can cause already found fields to be overwritten with the last value found.\n\nvar uplinkDataList = [];\n\n// Passing incoming bytes to decodePayload function, to get custom decoding\nvar customDecoding = decodePayload(hexToBytes(data.data));\n\n// Collecting data to result\nif (customDecoding.?telemetry.size() > 0) {\n if (customDecoding.telemetry instanceof java.util.ArrayList) {\n foreach(telemetryObj: customDecoding.telemetry) {\n if (telemetryObj.ts != null && telemetryObj.values != null) {\n telemetry.add(telemetryObj);\n }\n }\n } else {\n telemetry.putAll(customDecoding.telemetry);\n }\n}\n\nif (customDecoding.?attributes.size() > 0) {\n attributes.putAll(customDecoding.attributes);\n}\n\n// You can add some keys manually to attributes or telemetry\nattributes.eui = data.EUI;\nattributes.fPort = data.port;\nattributes.frequency = data.freq;\n\nvar addDataToTelemetry = {};\naddDataToTelemetry.rssi = data.rssi;\naddDataToTelemetry.seqno = data.seqno;\naddDataToTelemetry.snr = data.snr;\naddDataToTelemetry.ack = data.ack;\naddDataToTelemetry.toa = data.toa;\naddDataToTelemetry.fCnt = data.fcnt;\n\nvar isIncludeGatewayInfo = metadata[\"includeGatewayInfo\"];\nif(isIncludeGatewayInfo == true) {\n telemetry = processTelemetryData(telemetry, addDataToTelemetry);\n}\n\nvar deviceInfo = {\n deviceName: deviceName,\n deviceType: deviceType,\n// assetName: assetName,\n// assetType: assetType,\n attributes: attributes,\n telemetry: telemetry, \n};\n\naddAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName);\n\nuplinkDataList.add(deviceInfo);\n\nvar gatewayDeviceNamePrefix = \"Gateway \";\nvar gatewayDeviceType = \"Lora gateway\";\nvar gatewayGroupName = null; // If gatewayGroupName is not null - created device will be added to the entity group with such name.\n\nif (data.cmd == \"gw\") {\n foreach( gatewayInfo : data.gws ) {\n var addGatewayInfo = {};\n\n // You can add some keys manually telemetry\n addGatewayInfo.rssi = gatewayInfo.rssi;\n addGatewayInfo.snr = gatewayInfo.snr;\n // You can add some keys manually telemetry\n \n var gatewayInfoMsg = {\n deviceName: gatewayDeviceNamePrefix + gatewayInfo.gweui,\n deviceType: gatewayDeviceType,\n telemetry: [{\n \"ts\": gatewayInfo.ts,\n \"values\": addGatewayInfo\n }],\n attributes: {\n eui: gatewayInfo.gweui\n }\n };\n addAdditionalInfoForDeviceMsg(gatewayInfoMsg, customerName, gatewayGroupName);\n uplinkDataList.add(gatewayInfoMsg);\n }\n}\n\nreturn uplinkDataList;\n\nfunction addAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName) {\n if (customerName != null) {\n deviceInfo.customerName = customerName;\n }\n if (groupName != null) {\n deviceInfo.groupName = groupName;\n }\n}\n\nfunction parseDateToTimestamp(dateString) {\n var timestamp = -1;\n if (dateString != null) {\n \n timestamp = new Date(dateString).getTime();\n if (timestamp == -1) {\n var secondsSeparatorIndex = dateString.lastIndexOf('.') + 1;\n var millisecondsEndIndex = dateString.lastIndexOf('+');\n if (millisecondsEndIndex == -1) {\n millisecondsEndIndex = dateString.lastIndexOf('Z');\n }\n if (millisecondsEndIndex == -1) {\n millisecondsEndIndex = dateString.lastIndexOf('-');\n }\n if (millisecondsEndIndex == -1) {\n if (dateString.length >= secondsSeparatorIndex + 3) {\n dateString = dateString.substring(0, secondsSeparatorIndex + 3);\n }\n } else {\n dateString = dateString.substring(0, secondsSeparatorIndex + 3) +\n dateString.substring(millisecondsEndIndex, dateString.length);\n }\n \n timestamp = new Date(dateString).getTime();\n }\n }\n // If we cannot parse timestamp - we will use the current timestamp\n if (timestamp == -1) {\n timestamp = Date.now();\n }\n \n return timestamp;\n}\n\nfunction processTelemetryData(telemetry, addDataToTelemetry) {\n if (telemetry.size >= 1) {\n telemetry = addDataToTelemetries(telemetry, addDataToTelemetry);\n }\n else {\n telemetry.add(addDataToTelemetry);\n }\n \n return telemetry;\n}\n\nfunction addDataToTelemetries(telemetries, addDataToTelemetry) {\n foreach(telemetry : telemetries) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[\"values\"].keys.contains(element.key)) {\n telemetry[\"values\"][element.key] = element.value;\n }\n } \n }\n \n return telemetries;\n}\n\nfunction fromUtf8Bytes(bytes) {\n var resultObject = \"\";\n \n foreach (b : bytes) {\n resultObject += String.format(\"%%%02X\", b & 0xFF);\n }\n \n return decodeUrlEncodedString(resultObject);\n}\n\nfunction decodeUrlEncodedString(encoded) {\n var decoded = \"\";\n for (int i = 0; i < encoded.length(); i++) {\n char c = encoded.charAt(i);\n if (c == '%' && i + 2 < encoded.length()) {\n var hexValue = \"\" + encoded.charAt(i + 1) + encoded.charAt(i + 2);\n var decodedChar = Integer.parseInt(hexValue, 16);\n decoded += (char) decodedChar;\n i += 2;\n } else {\n decoded += c;\n }\n }\n return decoded;\n}", "encoder": null, "tbelEncoder": null, "updateOnlyKeys": [ diff --git a/VENDORS/Milesight/DS3604/LORIOT/uplink/payload_1.json b/VENDORS/Milesight/DS3604/LORIOT/uplink/payload_1.json new file mode 100644 index 00000000..8ce483f7 --- /dev/null +++ b/VENDORS/Milesight/DS3604/LORIOT/uplink/payload_1.json @@ -0,0 +1,32 @@ +{ + "cmd": "gw", + "seqno": 4, + "EUI": "0102030405060708", + "ts": 1690901260493, + "fcnt": 3, + "port": 207, + "freq": 868300000, + "toa": 1319, + "dr": "SF12 BW125 4/5", + "ack": false, + "gws": [ + { + "rssi": -38, + "snr": 8.5, + "ts": 1690901260493, + "time": "2023-08-01T14:47:40.493Z", + "gweui": "1020304080706050", + "ant": 0 + }, + { + "rssi": -42, + "snr": 8.8, + "ts": 1690901260495, + "time": "2023-08-01T14:47:40.495Z", + "gweui": "1020304081716151", + "ant": 0 + } + ], + "bat": 143, + "data": "017564FB0100054D696C6573FB010A0568656C6C6F" +} diff --git a/VENDORS/Milesight/DS3604/LORIOT/uplink/result_1.json b/VENDORS/Milesight/DS3604/LORIOT/uplink/result_1.json new file mode 100644 index 00000000..c3d8ca86 --- /dev/null +++ b/VENDORS/Milesight/DS3604/LORIOT/uplink/result_1.json @@ -0,0 +1,44 @@ +[{ + "deviceName": "DS3604 0102030405060708", + "deviceType": "DS3604", + "attributes": { + "eui": "0102030405060708", + "fPort": 207, + "frequency": 868300000 + }, + "telemetry": [{ + "ts": 1690901260493, + "values": { + "battery": 100, + "text_1": "Miles", + "template": 1, + "qrcode": "hello" + } + }] +}, { + "deviceName": "Gateway 1020304080706050", + "deviceType": "Lora gateway", + "telemetry": [{ + "ts": 1690901260493, + "values": { + "rssi": -38, + "snr": 8.5 + } + }], + "attributes": { + "eui": "1020304080706050" + } +}, { + "deviceName": "Gateway 1020304081716151", + "deviceType": "Lora gateway", + "telemetry": [{ + "ts": 1690901260495, + "values": { + "rssi": -42, + "snr": 8.8 + } + }], + "attributes": { + "eui": "1020304081716151" + } +}] \ No newline at end of file diff --git a/VENDORS/Milesight/EM300-CL/LORIOT/uplink/payload_1.json b/VENDORS/Milesight/EM300-CL/LORIOT/uplink/payload_1.json new file mode 100644 index 00000000..913623be --- /dev/null +++ b/VENDORS/Milesight/EM300-CL/LORIOT/uplink/payload_1.json @@ -0,0 +1,32 @@ +{ + "cmd": "gw", + "seqno": 4, + "EUI": "0102030405060708", + "ts": 1690901260493, + "fcnt": 3, + "port": 207, + "freq": 868300000, + "toa": 1319, + "dr": "SF12 BW125 4/5", + "ack": false, + "gws": [ + { + "rssi": -38, + "snr": 8.5, + "ts": 1690901260493, + "time": "2023-08-01T14:47:40.493Z", + "gweui": "1020304080706050", + "ant": 0 + }, + { + "rssi": -42, + "snr": 8.8, + "ts": 1690901260495, + "time": "2023-08-01T14:47:40.495Z", + "gweui": "1020304081716151", + "ant": 0 + } + ], + "bat": 143, + "data": "01756403ED00" +} diff --git a/VENDORS/Milesight/EM300-CL/LORIOT/uplink/result_1.json b/VENDORS/Milesight/EM300-CL/LORIOT/uplink/result_1.json new file mode 100644 index 00000000..0b9e3aab --- /dev/null +++ b/VENDORS/Milesight/EM300-CL/LORIOT/uplink/result_1.json @@ -0,0 +1,42 @@ +[{ + "deviceName": "0102030405060708", + "deviceType": "EM-300CL", + "attributes": { + "eui": "0102030405060708", + "fPort": 207, + "frequency": 868300000 + }, + "telemetry": [{ + "ts": 1690901260493, + "values": { + "battery": 100, + "liquid": "uncalibrated" + } + }] +}, { + "deviceName": "Gateway 1020304080706050", + "deviceType": "Lora gateway", + "telemetry": [{ + "ts": 1690901260493, + "values": { + "rssi": -38, + "snr": 8.5 + } + }], + "attributes": { + "eui": "1020304080706050" + } +}, { + "deviceName": "Gateway 1020304081716151", + "deviceType": "Lora gateway", + "telemetry": [{ + "ts": 1690901260495, + "values": { + "rssi": -42, + "snr": 8.8 + } + }], + "attributes": { + "eui": "1020304081716151" + } +}] \ No newline at end of file diff --git a/VENDORS/Milesight/EM310-TILT/LORIOT/uplink/payload_1.json b/VENDORS/Milesight/EM310-TILT/LORIOT/uplink/payload_1.json new file mode 100644 index 00000000..d066f5c3 --- /dev/null +++ b/VENDORS/Milesight/EM310-TILT/LORIOT/uplink/payload_1.json @@ -0,0 +1,32 @@ +{ + "cmd": "gw", + "seqno": 4, + "EUI": "0102030405060708", + "ts": 1690901260493, + "fcnt": 3, + "port": 207, + "freq": 868300000, + "toa": 1319, + "dr": "SF12 BW125 4/5", + "ack": false, + "gws": [ + { + "rssi": -38, + "snr": 8.5, + "ts": 1690901260493, + "time": "2023-08-01T14:47:40.493Z", + "gweui": "1020304080706050", + "ant": 0 + }, + { + "rssi": -42, + "snr": 8.8, + "ts": 1690901260495, + "time": "2023-08-01T14:47:40.495Z", + "gweui": "1020304081716151", + "ant": 0 + } + ], + "bat": 143, + "data": "03CF00000000282307" +} \ No newline at end of file diff --git a/VENDORS/Milesight/EM310-TILT/LORIOT/uplink/result_1.json b/VENDORS/Milesight/EM310-TILT/LORIOT/uplink/result_1.json new file mode 100644 index 00000000..5e803590 --- /dev/null +++ b/VENDORS/Milesight/EM310-TILT/LORIOT/uplink/result_1.json @@ -0,0 +1,46 @@ +[{ + "deviceName": "0102030405060708", + "deviceType": " EM310-TILT", + "attributes": { + "eui": "0102030405060708", + "fPort": 207, + "frequency": 868300000 + }, + "telemetry": [{ + "ts": 1690901260493, + "values": { + "angle_x": 0.0, + "angle_y": 0.0, + "angle_z": 90.0, + "threshold_x": "trigger", + "threshold_y": "trigger", + "threshold_z": "trigger" + } + }] +}, { + "deviceName": "Gateway 1020304080706050", + "deviceType": "Lora gateway", + "telemetry": [{ + "ts": 1690901260493, + "values": { + "rssi": -38, + "snr": 8.5 + } + }], + "attributes": { + "eui": "1020304080706050" + } +}, { + "deviceName": "Gateway 1020304081716151", + "deviceType": "Lora gateway", + "telemetry": [{ + "ts": 1690901260495, + "values": { + "rssi": -42, + "snr": 8.8 + } + }], + "attributes": { + "eui": "1020304081716151" + } +}] \ No newline at end of file diff --git a/VENDORS/Milesight/EM310-UDL/LORIOT/uplink/payload_1.json b/VENDORS/Milesight/EM310-UDL/LORIOT/uplink/payload_1.json new file mode 100644 index 00000000..f84d62f4 --- /dev/null +++ b/VENDORS/Milesight/EM310-UDL/LORIOT/uplink/payload_1.json @@ -0,0 +1,32 @@ +{ + "cmd": "gw", + "seqno": 4, + "EUI": "0102030405060708", + "ts": 1690901260493, + "fcnt": 3, + "port": 207, + "freq": 868300000, + "toa": 1319, + "dr": "SF12 BW125 4/5", + "ack": false, + "gws": [ + { + "rssi": -38, + "snr": 8.5, + "ts": 1690901260493, + "time": "2023-08-01T14:47:40.493Z", + "gweui": "1020304080706050", + "ant": 0 + }, + { + "rssi": -42, + "snr": 8.8, + "ts": 1690901260495, + "time": "2023-08-01T14:47:40.495Z", + "gweui": "1020304081716151", + "ant": 0 + } + ], + "bat": 143, + "data": "01755C03824408040001" +} \ No newline at end of file diff --git a/VENDORS/Milesight/EM310-UDL/LORIOT/uplink/result_1.json b/VENDORS/Milesight/EM310-UDL/LORIOT/uplink/result_1.json new file mode 100644 index 00000000..883672ba --- /dev/null +++ b/VENDORS/Milesight/EM310-UDL/LORIOT/uplink/result_1.json @@ -0,0 +1,43 @@ +[{ + "deviceName": "0102030405060708", + "deviceType": "EM310-UDL", + "attributes": { + "eui": "0102030405060708", + "fPort": 207, + "frequency": 868300000 + }, + "telemetry": [{ + "ts": 1690901260493, + "values": { + "battery": 92, + "distance": 2116, + "position": "tilt" + } + }] +}, { + "deviceName": "Gateway 1020304080706050", + "deviceType": "Lora gateway", + "telemetry": [{ + "ts": 1690901260493, + "values": { + "rssi": -38, + "snr": 8.5 + } + }], + "attributes": { + "eui": "1020304080706050" + } +}, { + "deviceName": "Gateway 1020304081716151", + "deviceType": "Lora gateway", + "telemetry": [{ + "ts": 1690901260495, + "values": { + "rssi": -42, + "snr": 8.8 + } + }], + "attributes": { + "eui": "1020304081716151" + } +}] \ No newline at end of file diff --git a/VENDORS/Milesight/EM320-TILT/LORIOT/uplink/payload_1.json b/VENDORS/Milesight/EM320-TILT/LORIOT/uplink/payload_1.json new file mode 100644 index 00000000..9587eeb3 --- /dev/null +++ b/VENDORS/Milesight/EM320-TILT/LORIOT/uplink/payload_1.json @@ -0,0 +1,32 @@ +{ + "cmd": "gw", + "seqno": 4, + "EUI": "0102030405060708", + "ts": 1690901260493, + "fcnt": 3, + "port": 207, + "freq": 868300000, + "toa": 1319, + "dr": "SF12 BW125 4/5", + "ack": false, + "gws": [ + { + "rssi": -38, + "snr": 8.5, + "ts": 1690901260493, + "time": "2023-08-01T14:47:40.493Z", + "gweui": "1020304080706050", + "ant": 0 + }, + { + "rssi": -42, + "snr": 8.8, + "ts": 1690901260495, + "time": "2023-08-01T14:47:40.495Z", + "gweui": "1020304081716151", + "ant": 0 + } + ], + "bat": 143, + "data": "01756403D4000001005046" +} \ No newline at end of file diff --git a/VENDORS/Milesight/EM320-TILT/LORIOT/uplink/result_1.json b/VENDORS/Milesight/EM320-TILT/LORIOT/uplink/result_1.json new file mode 100644 index 00000000..afa611ef --- /dev/null +++ b/VENDORS/Milesight/EM320-TILT/LORIOT/uplink/result_1.json @@ -0,0 +1,47 @@ +[{ + "deviceName": "0102030405060708", + "deviceType": "EM320-TILT", + "attributes": { + "eui": "0102030405060708", + "fPort": 207, + "frequency": 868300000 + }, + "telemetry": [{ + "ts": 1690901260493, + "values": { + "battery": 100, + "angle_x": 0, + "angle_y": 0, + "angle_z": 90, + "threshold_x": "normal", + "threshold_y": "trigger", + "threshold_z": "normal" + } + }] +}, { + "deviceName": "Gateway 1020304080706050", + "deviceType": "Lora gateway", + "telemetry": [{ + "ts": 1690901260493, + "values": { + "rssi": -38, + "snr": 8.5 + } + }], + "attributes": { + "eui": "1020304080706050" + } +}, { + "deviceName": "Gateway 1020304081716151", + "deviceType": "Lora gateway", + "telemetry": [{ + "ts": 1690901260495, + "values": { + "rssi": -42, + "snr": 8.8 + } + }], + "attributes": { + "eui": "1020304081716151" + } +}] \ No newline at end of file diff --git a/VENDORS/Milesight/EM400-TLD/LORIOT/uplink/payload_2.json b/VENDORS/Milesight/EM400-TLD/LORIOT/uplink/payload_2.json new file mode 100644 index 00000000..4e7f19ff --- /dev/null +++ b/VENDORS/Milesight/EM400-TLD/LORIOT/uplink/payload_2.json @@ -0,0 +1,32 @@ +{ + "cmd": "gw", + "seqno": 4, + "EUI": "0102030405060708", + "ts": 1690901260493, + "fcnt": 3, + "port": 207, + "freq": 868300000, + "toa": 1319, + "dr": "SF12 BW125 4/5", + "ack": false, + "gws": [ + { + "rssi": -38, + "snr": 8.5, + "ts": 1690901260493, + "time": "2023-08-01T14:47:40.493Z", + "gweui": "1020304080706050", + "ant": 0 + }, + { + "rssi": -42, + "snr": 8.8, + "ts": 1690901260495, + "time": "2023-08-01T14:47:40.495Z", + "gweui": "1020304081716151", + "ant": 0 + } + ], + "bat": 143, + "data": "01755C0367010104824408050001" +} \ No newline at end of file diff --git a/VENDORS/Milesight/EM400-TLD/LORIOT/uplink/result_2.json b/VENDORS/Milesight/EM400-TLD/LORIOT/uplink/result_2.json new file mode 100644 index 00000000..7670f3b6 --- /dev/null +++ b/VENDORS/Milesight/EM400-TLD/LORIOT/uplink/result_2.json @@ -0,0 +1,44 @@ +[{ + "deviceName": "0102030405060708", + "deviceType": "EM400-TLD", + "attributes": { + "eui": "0102030405060708", + "fPort": 207, + "frequency": 868300000 + }, + "telemetry": [{ + "ts": 1690901260493, + "values": { + "battery": 92, + "temperature": 25.7, + "distance": 2116, + "position": "tilt" + } + }] +}, { + "deviceName": "Gateway 1020304080706050", + "deviceType": "Lora gateway", + "telemetry": [{ + "ts": 1690901260493, + "values": { + "rssi": -38, + "snr": 8.5 + } + }], + "attributes": { + "eui": "1020304080706050" + } +}, { + "deviceName": "Gateway 1020304081716151", + "deviceType": "Lora gateway", + "telemetry": [{ + "ts": 1690901260495, + "values": { + "rssi": -42, + "snr": 8.8 + } + }], + "attributes": { + "eui": "1020304081716151" + } +}] \ No newline at end of file diff --git a/VENDORS/Milesight/EM400-UDL/LORIOT/uplink/payload_2.json b/VENDORS/Milesight/EM400-UDL/LORIOT/uplink/payload_2.json new file mode 100644 index 00000000..4e7f19ff --- /dev/null +++ b/VENDORS/Milesight/EM400-UDL/LORIOT/uplink/payload_2.json @@ -0,0 +1,32 @@ +{ + "cmd": "gw", + "seqno": 4, + "EUI": "0102030405060708", + "ts": 1690901260493, + "fcnt": 3, + "port": 207, + "freq": 868300000, + "toa": 1319, + "dr": "SF12 BW125 4/5", + "ack": false, + "gws": [ + { + "rssi": -38, + "snr": 8.5, + "ts": 1690901260493, + "time": "2023-08-01T14:47:40.493Z", + "gweui": "1020304080706050", + "ant": 0 + }, + { + "rssi": -42, + "snr": 8.8, + "ts": 1690901260495, + "time": "2023-08-01T14:47:40.495Z", + "gweui": "1020304081716151", + "ant": 0 + } + ], + "bat": 143, + "data": "01755C0367010104824408050001" +} \ No newline at end of file diff --git a/VENDORS/Milesight/EM400-UDL/LORIOT/uplink/result_2.json b/VENDORS/Milesight/EM400-UDL/LORIOT/uplink/result_2.json new file mode 100644 index 00000000..da1342a4 --- /dev/null +++ b/VENDORS/Milesight/EM400-UDL/LORIOT/uplink/result_2.json @@ -0,0 +1,44 @@ +[{ + "deviceName": "0102030405060708", + "deviceType": "EM400-UDL", + "attributes": { + "eui": "0102030405060708", + "fPort": 207, + "frequency": 868300000 + }, + "telemetry": [{ + "ts": 1690901260493, + "values": { + "battery": 92, + "temperature": 25.7, + "distance": 2116, + "position": "tilt" + } + }] +}, { + "deviceName": "Gateway 1020304080706050", + "deviceType": "Lora gateway", + "telemetry": [{ + "ts": 1690901260493, + "values": { + "rssi": -38, + "snr": 8.5 + } + }], + "attributes": { + "eui": "1020304080706050" + } +}, { + "deviceName": "Gateway 1020304081716151", + "deviceType": "Lora gateway", + "telemetry": [{ + "ts": 1690901260495, + "values": { + "rssi": -42, + "snr": 8.8 + } + }], + "attributes": { + "eui": "1020304081716151" + } +}] \ No newline at end of file diff --git a/VENDORS/Milesight/EM500-CO2/LORIOT/uplink/converter.json b/VENDORS/Milesight/EM500-CO2/LORIOT/uplink/converter.json index 593aaa31..0e50e061 100644 --- a/VENDORS/Milesight/EM500-CO2/LORIOT/uplink/converter.json +++ b/VENDORS/Milesight/EM500-CO2/LORIOT/uplink/converter.json @@ -10,7 +10,7 @@ "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);\nvar deviceName = data.EUI;\nvar deviceType = \"EM500-C02\";\nvar groupName = null; // If groupName is not null - created device will be added to the entity group with such name.\nvar customerName = null; // If customerName is not null - created devices will be assigned to customer with such name. \n\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// If you want to parse incoming data somehow, you can add your code to this function.\n// input: bytes\n// expected output:\n// {\n// \"attributes\": {\"attributeKey\": \"attributeValue\"},\n// \"telemetry\": {\"telemetryKey\": \"telemetryValue\"}\n// }\n\nfunction decodePayload(input) {\n var output = { attributes: {}, telemetry: []};\n \n var decoded = {};\n var historyDataList = [];\n for (var i = 0; i < input.length - 2 ; ) {\n var channel_id = input[i++] & 0xff;\n var channel_type = input[i++] & 0xff;\n \n // BATTERY\n if (channel_id === 0x01 && channel_type === 0x75) {\n decoded.battery = input[i];\n i += 1;\n }\n // TEMPERATURE\n else if (channel_id === 0x03 && channel_type === 0x67) {\n decoded.temperature = parseBytesToInt(input, i, 2, false) / 10;\n i += 2;\n \n // ℉\n // decoded.temperature = parseBytesToInt(input, i, 2, false) / 10 * 1.8 + 32;\n // i +=2;\n }\n // HUMIDITY\n else if (channel_id === 0x04 && channel_type === 0x68) {\n decoded.humidity = parseBytesToInt(input, i, 1, false) / 2;\n i += 1;\n }\n // CO2\n else if (channel_id === 0x05 && channel_type === 0x7d) {\n decoded.co2 = parseBytesToInt(input, i, 2, false);\n i += 2;\n }\n // PRESSURE\n else if (channel_id === 0x06 && channel_type === 0x73) {\n decoded.pressure = parseBytesToInt(input, i, 2, false) / 10;\n i += 2;\n }\n // TEMPERATURE CHANGE ALARM\n else if (channel_id === 0x83 && channel_type === 0xd7) {\n decoded.temperature = parseBytesToInt(input, i, 2, false) / 10;\n decoded.temperature_change = parseBytesToInt(input, i + 2, 2, false) / 10;\n decoded.temperature_alarm = readTemperatureAlarm(input[i + 4]);\n i += 5;\n }\n // HISTROY\n else if (channel_id === 0x20 && channel_type === 0xce) {\n var historyData = {\n ts: parseBytesToInt(input, i, 4, false) * 1000,\n values: {\n co2: parseBytesToInt(input, i + 4, 2, false),\n pressure: parseBytesToInt(input, i + 6, 1, false) / 10,\n temperature: parseBytesToInt(input, i + 8, 2, false) / 10,\n humidity: parseBytesToInt(input, i + 10, 1, false, false) / 2\n }\n };\n i += 11;\n \n historyDataList.add(historyData);\n } \n }\n \n output.telemetry = [{\n ts: timestamp,\n values: decoded\n }];\n\n // --- Decoding code --- //\n return output;\n}\n\n// --- attributes and telemetry objects ---\nvar telemetry = [];\nvar attributes = {};\n// --- attributes and telemetry objects ---\n\n// --- Timestamp parsing\ntimestamp = data.ts;\n// --- Timestamp parsing\n\n// Message parsing\n// To avoid paths in the decoded objects we passing false value to function as \"pathInKey\" argument.\n// Warning: pathInKey can cause already found fields to be overwritten with the last value found.\n\nvar uplinkDataList = [];\n\n// Passing incoming bytes to decodePayload function, to get custom decoding\nvar customDecoding = decodePayload(hexToBytes(data.data));\n\n// Collecting data to result\nif (customDecoding.?telemetry.size() > 0) {\n if (customDecoding.telemetry instanceof java.util.ArrayList) {\n foreach(telemetryObj: customDecoding.telemetry) {\n if (telemetryObj.ts != null && telemetryObj.values != null) {\n telemetry.add(telemetryObj);\n }\n }\n } else {\n telemetry.putAll(customDecoding.telemetry);\n }\n}\n\nif (customDecoding.?attributes.size() > 0) {\n attributes.putAll(customDecoding.attributes);\n}\n\n// You can add some keys manually to attributes or telemetry\nattributes.eui = data.EUI;\nattributes.fPort = data.port;\nattributes.frequency = data.freq;\n\nvar isIncludeGatewayInfo = metadata[\"includeGatewayInfo\"];\nif(isIncludeGatewayInfo == true) {\n var addDataToTelemetry = {};\n addDataToTelemetry.rssi = data.rssi;\n addDataToTelemetry.seqno = data.seqno;\n addDataToTelemetry.snr = data.snr;\n addDataToTelemetry.ack = data.ack;\n addDataToTelemetry.toa = data.toa;\n addDataToTelemetry.fCnt = data.fcnt;\n \n telemetry = processTelemetryData(telemetry, addDataToTelemetry);\n}\n\nvar deviceInfo = {\n deviceName: deviceName,\n deviceType: deviceType,\n// assetName: assetName,\n// assetType: assetType,\n attributes: attributes,\n telemetry: telemetry, \n};\n\naddAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName);\n\nuplinkDataList.add(deviceInfo);\n\nvar gatewayDeviceNamePrefix = \"Gateway \";\nvar gatewayDeviceType = \"Lora gateway\";\nvar gatewayGroupName = null; // If gatewayGroupName is not null - created device will be added to the entity group with such name.\n\nif (data.cmd == \"gw\") {\n foreach( gatewayInfo : data.gws ) {\n var addGatewayInfo = {};\n\n // You can add some keys manually telemetry\n addGatewayInfo.rssi = gatewayInfo.rssi;\n addGatewayInfo.snr = gatewayInfo.snr;\n // You can add some keys manually telemetry\n \n var gatewayInfoMsg = {\n deviceName: gatewayDeviceNamePrefix + gatewayInfo.gweui,\n deviceType: gatewayDeviceType,\n telemetry: [{\n \"ts\": gatewayInfo.ts,\n \"values\": addGatewayInfo\n }],\n attributes: {\n eui: gatewayInfo.gweui\n }\n };\n addAdditionalInfoForDeviceMsg(gatewayInfoMsg, customerName, gatewayGroupName);\n uplinkDataList.add(gatewayInfoMsg);\n }\n}\n\nreturn uplinkDataList;\n\nfunction addAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName) {\n if (customerName != null) {\n deviceInfo.customerName = customerName;\n }\n if (groupName != null) {\n deviceInfo.groupName = groupName;\n }\n}\n\nfunction processTelemetryData(telemetry, addDataToTelemetry) {\n if (telemetry.size >= 1) {\n telemetry = addDataToTelemetries(telemetry, addDataToTelemetry);\n }\n else {\n telemetry.add(addDataToTelemetry);\n }\n \n return telemetry;\n}\n\nfunction addDataToTelemetries(telemetries, addDataToTelemetry) {\n foreach(telemetry : telemetries) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[\"values\"].keys.contains(element.key)) {\n telemetry[\"values\"][element.key] = element.value;\n }\n } \n }\n \n return telemetries;\n}\n\nfunction readTemperatureAlarm(type) {\n switch (type) {\n case 0:\n return \"threshold alarm\";\n case 1:\n return \"threshold alarm release\";\n case 2:\n return \"mutation alarm\";\n default:\n return \"unkown\";\n }\n}", + "tbelDecoder": "var data = decodeToJson(payload);\nvar deviceName = data.EUI;\nvar deviceType = \"EM500-C02\";\nvar groupName = null; // If groupName is not null - created device will be added to the entity group with such name.\nvar customerName = null; // If customerName is not null - created devices will be assigned to customer with such name. \n\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// If you want to parse incoming data somehow, you can add your code to this function.\n// input: bytes\n// expected output:\n// {\n// \"attributes\": {\"attributeKey\": \"attributeValue\"},\n// \"telemetry\": {\"telemetryKey\": \"telemetryValue\"}\n// }\n\nfunction decodePayload(input) {\n var output = { attributes: {}, telemetry: []};\n \n var decoded = {};\n var historyDataList = [];\n for (var i = 0; i < input.length - 2 ; ) {\n var channel_id = input[i++] & 0xff;\n var channel_type = input[i++] & 0xff;\n \n // BATTERY\n if (channel_id === 0x01 && channel_type === 0x75) {\n decoded.battery = input[i];\n i += 1;\n }\n // TEMPERATURE\n else if (channel_id === 0x03 && channel_type === 0x67) {\n decoded.temperature = parseBytesToInt(input, i, 2, false) / 10;\n i += 2;\n \n // ℉\n // decoded.temperature = parseBytesToInt(input, i, 2, false) / 10 * 1.8 + 32;\n // i +=2;\n }\n // HUMIDITY\n else if (channel_id === 0x04 && channel_type === 0x68) {\n decoded.humidity = parseBytesToInt(input, i, 1, false) / 2;\n i += 1;\n }\n // CO2\n else if (channel_id === 0x05 && channel_type === 0x7d) {\n decoded.co2 = parseBytesToInt(input, i, 2, false);\n i += 2;\n }\n // PRESSURE\n else if (channel_id === 0x06 && channel_type === 0x73) {\n decoded.pressure = parseBytesToInt(input, i, 2, false) / 10;\n i += 2;\n }\n // TEMPERATURE CHANGE ALARM\n else if (channel_id === 0x83 && channel_type === 0xd7) {\n decoded.temperature = parseBytesToInt(input, i, 2, false) / 10;\n decoded.temperature_change = parseBytesToInt(input, i + 2, 2, false) / 10;\n decoded.temperature_alarm = readTemperatureAlarm(input[i + 4]);\n i += 5;\n }\n // HISTROY\n else if (channel_id === 0x20 && channel_type === 0xce) {\n var historyData = {\n ts: parseBytesToInt(input, i, 4, false) * 1000,\n values: {\n co2: parseBytesToInt(input, i + 4, 2, false),\n pressure: parseBytesToInt(input, i + 6, 1, false) / 10,\n temperature: parseBytesToInt(input, i + 8, 2, false) / 10,\n humidity: parseBytesToInt(input, i + 10, 1, false, false) / 2\n }\n };\n i += 11;\n \n historyDataList.add(historyData);\n } \n }\n \n output.telemetry = [{\n ts: timestamp,\n values: decoded\n }];\n \n output.telemetry.addAll(historyDataList);\n // --- Decoding code --- //\n return output;\n}\n\n// --- attributes and telemetry objects ---\nvar telemetry = [];\nvar attributes = {};\n// --- attributes and telemetry objects ---\n\n// --- Timestamp parsing\ntimestamp = data.ts;\n// --- Timestamp parsing\n\n// Message parsing\n// To avoid paths in the decoded objects we passing false value to function as \"pathInKey\" argument.\n// Warning: pathInKey can cause already found fields to be overwritten with the last value found.\n\nvar uplinkDataList = [];\n\n// Passing incoming bytes to decodePayload function, to get custom decoding\nvar customDecoding = decodePayload(hexToBytes(data.data));\n\n// Collecting data to result\nif (customDecoding.?telemetry.size() > 0) {\n if (customDecoding.telemetry instanceof java.util.ArrayList) {\n foreach(telemetryObj: customDecoding.telemetry) {\n if (telemetryObj.ts != null && telemetryObj.values != null) {\n telemetry.add(telemetryObj);\n }\n }\n } else {\n telemetry.putAll(customDecoding.telemetry);\n }\n}\n\nif (customDecoding.?attributes.size() > 0) {\n attributes.putAll(customDecoding.attributes);\n}\n\n// You can add some keys manually to attributes or telemetry\nattributes.eui = data.EUI;\nattributes.fPort = data.port;\nattributes.frequency = data.freq;\n\nvar isIncludeGatewayInfo = metadata[\"includeGatewayInfo\"];\nif(isIncludeGatewayInfo == true) {\n var addDataToTelemetry = {};\n addDataToTelemetry.rssi = data.rssi;\n addDataToTelemetry.seqno = data.seqno;\n addDataToTelemetry.snr = data.snr;\n addDataToTelemetry.ack = data.ack;\n addDataToTelemetry.toa = data.toa;\n addDataToTelemetry.fCnt = data.fcnt;\n \n telemetry = processTelemetryData(telemetry, addDataToTelemetry);\n}\n\nvar deviceInfo = {\n deviceName: deviceName,\n deviceType: deviceType,\n// assetName: assetName,\n// assetType: assetType,\n attributes: attributes,\n telemetry: telemetry, \n};\n\naddAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName);\n\nuplinkDataList.add(deviceInfo);\n\nvar gatewayDeviceNamePrefix = \"Gateway \";\nvar gatewayDeviceType = \"Lora gateway\";\nvar gatewayGroupName = null; // If gatewayGroupName is not null - created device will be added to the entity group with such name.\n\nif (data.cmd == \"gw\") {\n foreach( gatewayInfo : data.gws ) {\n var addGatewayInfo = {};\n\n // You can add some keys manually telemetry\n addGatewayInfo.rssi = gatewayInfo.rssi;\n addGatewayInfo.snr = gatewayInfo.snr;\n // You can add some keys manually telemetry\n \n var gatewayInfoMsg = {\n deviceName: gatewayDeviceNamePrefix + gatewayInfo.gweui,\n deviceType: gatewayDeviceType,\n telemetry: [{\n \"ts\": gatewayInfo.ts,\n \"values\": addGatewayInfo\n }],\n attributes: {\n eui: gatewayInfo.gweui\n }\n };\n addAdditionalInfoForDeviceMsg(gatewayInfoMsg, customerName, gatewayGroupName);\n uplinkDataList.add(gatewayInfoMsg);\n }\n}\n\nreturn uplinkDataList;\n\nfunction addAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName) {\n if (customerName != null) {\n deviceInfo.customerName = customerName;\n }\n if (groupName != null) {\n deviceInfo.groupName = groupName;\n }\n}\n\nfunction processTelemetryData(telemetry, addDataToTelemetry) {\n if (telemetry.size >= 1) {\n telemetry = addDataToTelemetries(telemetry, addDataToTelemetry);\n }\n else {\n telemetry.add(addDataToTelemetry);\n }\n \n return telemetry;\n}\n\nfunction addDataToTelemetries(telemetries, addDataToTelemetry) {\n foreach(telemetry : telemetries) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[\"values\"].keys.contains(element.key)) {\n telemetry[\"values\"][element.key] = element.value;\n }\n } \n }\n \n return telemetries;\n}\n\nfunction readTemperatureAlarm(type) {\n switch (type) {\n case 0:\n return \"threshold alarm\";\n case 1:\n return \"threshold alarm release\";\n case 2:\n return \"mutation alarm\";\n default:\n return \"unkown\";\n }\n}", "encoder": null, "tbelEncoder": null, "updateOnlyKeys": [ diff --git a/VENDORS/Milesight/EM500-CO2/LORIOT/uplink/payload_1.json b/VENDORS/Milesight/EM500-CO2/LORIOT/uplink/payload_1.json new file mode 100644 index 00000000..ce781b81 --- /dev/null +++ b/VENDORS/Milesight/EM500-CO2/LORIOT/uplink/payload_1.json @@ -0,0 +1,32 @@ +{ + "cmd": "gw", + "seqno": 4, + "EUI": "0102030405060708", + "ts": 1690901260493, + "fcnt": 3, + "port": 207, + "freq": 868300000, + "toa": 1319, + "dr": "SF12 BW125 4/5", + "ack": false, + "gws": [ + { + "rssi": -38, + "snr": 8.5, + "ts": 1690901260493, + "time": "2023-08-01T14:47:40.493Z", + "gweui": "1020304080706050", + "ant": 0 + }, + { + "rssi": -42, + "snr": 8.8, + "ts": 1690901260495, + "time": "2023-08-01T14:47:40.495Z", + "gweui": "1020304081716151", + "ant": 0 + } + ], + "bat": 143, + "data": "01756403671901046873057D670406736827" +} \ No newline at end of file diff --git a/VENDORS/Milesight/EM500-CO2/LORIOT/uplink/result_1.json b/VENDORS/Milesight/EM500-CO2/LORIOT/uplink/result_1.json new file mode 100644 index 00000000..883ede5b --- /dev/null +++ b/VENDORS/Milesight/EM500-CO2/LORIOT/uplink/result_1.json @@ -0,0 +1,45 @@ +[{ + "deviceName": "0102030405060708", + "deviceType": "EM500-C02", + "attributes": { + "eui": "0102030405060708", + "fPort": 207, + "frequency": 868300000 + }, + "telemetry": [{ + "ts": 1690901260493, + "values": { + "battery": 100, + "temperature": 28.1, + "humidity": 57.5, + "co2": 1127, + "pressure": 1008.8 + } + }] +}, { + "deviceName": "Gateway 1020304080706050", + "deviceType": "Lora gateway", + "telemetry": [{ + "ts": 1690901260493, + "values": { + "rssi": -38, + "snr": 8.5 + } + }], + "attributes": { + "eui": "1020304080706050" + } +}, { + "deviceName": "Gateway 1020304081716151", + "deviceType": "Lora gateway", + "telemetry": [{ + "ts": 1690901260495, + "values": { + "rssi": -42, + "snr": 8.8 + } + }], + "attributes": { + "eui": "1020304081716151" + } +}] \ No newline at end of file diff --git a/VENDORS/Milesight/GS101/LORIOT/uplink/converter.json b/VENDORS/Milesight/GS101/LORIOT/uplink/converter.json index 85ab36ac..e5c3889a 100644 --- a/VENDORS/Milesight/GS101/LORIOT/uplink/converter.json +++ b/VENDORS/Milesight/GS101/LORIOT/uplink/converter.json @@ -1,11 +1,16 @@ { "name": "Loriot Uplink Decoder for GS101", "type": "UPLINK", - "debugMode": true, + "debugMode": false, + "debugSettings": { + "failuresEnabled": true, + "allEnabled": false, + "allEnabledUntil": 1735211336948 + }, "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);\nvar deviceName = \"GS 101 \" + data.EUI;\nvar deviceType = \"Gas sensor\";\nvar groupName = null; // If groupName is not null - created device will be added to the entity group with such name.\nvar customerName = null; // If customerName is not null - created devices will be assigned to customer with such name. \n\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// If you want to parse incoming data somehow, you can add your code to this function.\n// input: bytes\n// expected output:\n// {\n// \"attributes\": {\"attributeKey\": \"attributeValue\"},\n// \"telemetry\": {\"telemetryKey\": \"telemetryValue\"}\n// }\n\nfunction decodePayload(input) {\n var output = { attributes: {}, telemetry: []};\n \n // --- Decoding code --- //\n var decoded = {};\n for (var i = 0; i < input.length -2; ) {\n var channel_id = input[i++] & 0xff;\n var channel_type = input[i++] & 0xff;\n \n // GAS STATUS\n if (channel_id === 0x05 && channel_type === 0x8e) {\n decoded.state = input[i] === 0 ? \"normal\" : \"abnormal\";\n i += 1;\n }\n // VALVE\n if (channel_id === 0x06 && channel_type === 0x01) {\n decoded.valve = input[i] === 0 ? \"close\" : \"open\";\n i += 1;\n }\n // RELAY\n if (channel_id === 0x07 && channel_type === 0x01) {\n decoded.relay = input[i] === 0 ? \"close\" : \"open\";\n i += 1;\n }\n // REMAINED LIFE TIME\n if (channel_id === 0x08 && channel_type === 0x90) {\n decoded.life_remain = parseBytesToInt(input, i, 4, false);\n i += 4;\n }\n // ALARM\n else if (channel_id === 0xff && channel_type === 0x3f) {\n var alarm_type = input[i];\n i += 1;\n decoded.alarm = decodeAlarmType(alarm_type);\n }\n }\n \n output.telemetry = [{\n ts: timestamp,\n values: decoded\n }];\n\n // --- Decoding code --- //\n return output;\n}\n\n// --- attributes and telemetry objects ---\nvar telemetry = [];\nvar attributes = {};\n// --- attributes and telemetry objects ---\n\n// --- Timestamp parsing\ntimestamp = data.ts;\n// --- Timestamp parsing\n\n// Message parsing\n// To avoid paths in the decoded objects we passing false value to function as \"pathInKey\" argument.\n// Warning: pathInKey can cause already found fields to be overwritten with the last value found.\n\nvar uplinkDataList = [];\n\n// Passing incoming bytes to decodePayload function, to get custom decoding\nvar customDecoding = decodePayload(hexToBytes(data.data));\n\n// Collecting data to result\nif (customDecoding.?telemetry.size() > 0) {\n if (customDecoding.telemetry instanceof java.util.ArrayList) {\n foreach(telemetryObj: customDecoding.telemetry) {\n if (telemetryObj.ts != null && telemetryObj.values != null) {\n telemetry.add(telemetryObj);\n }\n }\n } else {\n telemetry.putAll(customDecoding.telemetry);\n }\n}\n\nif (customDecoding.?attributes.size() > 0) {\n attributes.putAll(customDecoding.attributes);\n}\n\n// You can add some keys manually to attributes or telemetry\nattributes.eui = data.EUI;\nattributes.fPort = data.port;\nattributes.frequency = data.freq;\n\nvar isIncludeGatewayInfo = metadata[\"includeGatewayInfo\"];\nif(isIncludeGatewayInfo == true) {\n var addDataToTelemetry = {};\n addDataToTelemetry.rssi = data.rssi;\n addDataToTelemetry.seqno = data.seqno;\n addDataToTelemetry.snr = data.snr;\n addDataToTelemetry.ack = data.ack;\n addDataToTelemetry.toa = data.toa;\n addDataToTelemetry.fCnt = data.fcnt;\n \n telemetry = processTelemetryData(telemetry, addDataToTelemetry);\n}\n\nvar deviceInfo = {\n deviceName: deviceName,\n deviceType: deviceType,\n// assetName: assetName,\n// assetType: assetType,\n attributes: attributes,\n telemetry: telemetry, \n};\n\naddAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName);\n\nuplinkDataList.add(deviceInfo);\n\nvar gatewayDeviceNamePrefix = \"Gateway \";\nvar gatewayDeviceType = \"Lora gateway\";\nvar gatewayGroupName = null; // If gatewayGroupName is not null - created device will be added to the entity group with such name.\n\nif (data.cmd == \"gw\") {\n foreach( gatewayInfo : data.gws ) {\n var addGatewayInfo = {};\n\n // You can add some keys manually telemetry\n addGatewayInfo.rssi = gatewayInfo.rssi;\n addGatewayInfo.snr = gatewayInfo.snr;\n // You can add some keys manually telemetry\n \n var gatewayInfoMsg = {\n deviceName: gatewayDeviceNamePrefix + gatewayInfo.gweui,\n deviceType: gatewayDeviceType,\n telemetry: [{\n \"ts\": gatewayInfo.ts,\n \"values\": addGatewayInfo\n }],\n attributes: {\n eui: gatewayInfo.gweui\n }\n };\n addAdditionalInfoForDeviceMsg(gatewayInfoMsg, customerName, gatewayGroupName);\n uplinkDataList.add(gatewayInfoMsg);\n }\n}\n\nreturn uplinkDataList;\n\nfunction addAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName) {\n if (customerName != null) {\n deviceInfo.customerName = customerName;\n }\n if (groupName != null) {\n deviceInfo.groupName = groupName;\n }\n}\n\nfunction processTelemetryData(telemetry, addDataToTelemetry) {\n if (telemetry.size > 1) {\n telemetry = addDataToMultipleTelemetries(telemetry, addDataToTelemetry);\n }\n else if (telemetry.size == 1) {\n telemetry = addDataToSingleTelemetry(telemetry, addDataToTelemetry);\n }\n else {\n telemetry.add(addDataToTelemetry);\n }\n \n return telemetry;\n}\n\nfunction addDataToMultipleTelemetries(telemetry, addDataToTelemetry) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[0][\"values\"].keys.contains(element.key)) {\n telemetry[0][\"values\"][element.key] = element.value;\n }\n if (!telemetry[1][\"values\"].keys.contains(element.key)) {\n telemetry[1][\"values\"][element.key] = element.value;\n }\n }\n \n return telemetry;\n}\n\nfunction addDataToSingleTelemetry(telemetry, addDataToTelemetry) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[0][\"values\"].keys.contains(element.key)) {\n telemetry[0][\"values\"][element.key] = element.value;\n }\n }\n \n return telemetry;\n}\n\nfunction calculatePreviousState(compressedDuration) {\n var state = {};\n state.previous_state_duration_overflow = false;\n\n if (compressedDuration < 90) {\n state.previous_state_duration = compressedDuration;\n state.previous_state_duration_error = 0;\n } else if (compressedDuration >= 90 && compressedDuration < 120) {\n state.previous_state_duration = 90 + (compressedDuration - 90) * 5;\n state.previous_state_duration_error = 4;\n } else if (compressedDuration >= 120 && compressedDuration < 127) {\n result.previous_state_duration = 240 + (compressedDuration - 120) * 60;\n result.previous_state_duration_error = 59;\n } else if (compressedDuration === 127) {\n state.previous_state_duration = 660;\n state.previous_state_duration_error = null;\n state.previous_state_duration_overflow = true;\n }\n\n return state;\n }", + "tbelDecoder": "var data = decodeToJson(payload);\nvar deviceName = \"GS 101 \" + data.EUI;\nvar deviceType = \"Gas sensor\";\nvar groupName = null; // If groupName is not null - created device will be added to the entity group with such name.\nvar customerName = null; // If customerName is not null - created devices will be assigned to customer with such name. \n\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// If you want to parse incoming data somehow, you can add your code to this function.\n// input: bytes\n// expected output:\n// {\n// \"attributes\": {\"attributeKey\": \"attributeValue\"},\n// \"telemetry\": {\"telemetryKey\": \"telemetryValue\"}\n// }\n\nfunction decodePayload(input) {\n var output = { attributes: {}, telemetry: []};\n \n // --- Decoding code --- //\n var decoded = {};\n for (var i = 0; i < input.length -2; ) {\n var channel_id = input[i++] & 0xff;\n var channel_type = input[i++] & 0xff;\n \n // GAS STATUS\n if (channel_id === 0x05 && channel_type === 0x8e) {\n decoded.state = input[i] === 0 ? \"normal\" : \"abnormal\";\n i += 1;\n }\n // VALVE\n if (channel_id === 0x06 && channel_type === 0x01) {\n decoded.valve = input[i] === 0 ? \"close\" : \"open\";\n i += 1;\n }\n // RELAY\n if (channel_id === 0x07 && channel_type === 0x01) {\n decoded.relay = input[i] === 0 ? \"close\" : \"open\";\n i += 1;\n }\n // REMAINED LIFE TIME\n if (channel_id === 0x08 && channel_type === 0x90) {\n decoded.life_remain = parseBytesToInt(input, i, 4, false);\n i += 4;\n }\n // ALARM\n else if (channel_id === 0xff && channel_type === 0x3f) {\n var alarm_type = input[i];\n i += 1;\n decoded.alarm = decodeAlarmType(alarm_type);\n }\n }\n \n output.telemetry = [{\n ts: timestamp,\n values: decoded\n }];\n\n // --- Decoding code --- //\n return output;\n}\n\n// --- attributes and telemetry objects ---\nvar telemetry = [];\nvar attributes = {};\n// --- attributes and telemetry objects ---\n\n// --- Timestamp parsing\ntimestamp = data.ts;\n// --- Timestamp parsing\n\n// Message parsing\n// To avoid paths in the decoded objects we passing false value to function as \"pathInKey\" argument.\n// Warning: pathInKey can cause already found fields to be overwritten with the last value found.\n\nvar uplinkDataList = [];\n\n// Passing incoming bytes to decodePayload function, to get custom decoding\nvar customDecoding = decodePayload(hexToBytes(data.data));\n\n// Collecting data to result\nif (customDecoding.?telemetry.size() > 0) {\n if (customDecoding.telemetry instanceof java.util.ArrayList) {\n foreach(telemetryObj: customDecoding.telemetry) {\n if (telemetryObj.ts != null && telemetryObj.values != null) {\n telemetry.add(telemetryObj);\n }\n }\n } else {\n telemetry.putAll(customDecoding.telemetry);\n }\n}\n\nif (customDecoding.?attributes.size() > 0) {\n attributes.putAll(customDecoding.attributes);\n}\n\n// You can add some keys manually to attributes or telemetry\nattributes.eui = data.EUI;\nattributes.fPort = data.port;\nattributes.frequency = data.freq;\n\nvar isIncludeGatewayInfo = metadata[\"includeGatewayInfo\"];\nif(isIncludeGatewayInfo == true) {\n var addDataToTelemetry = {};\n addDataToTelemetry.rssi = data.rssi;\n addDataToTelemetry.seqno = data.seqno;\n addDataToTelemetry.snr = data.snr;\n addDataToTelemetry.ack = data.ack;\n addDataToTelemetry.toa = data.toa;\n addDataToTelemetry.fCnt = data.fcnt;\n \n telemetry = processTelemetryData(telemetry, addDataToTelemetry);\n}\n\nvar deviceInfo = {\n deviceName: deviceName,\n deviceType: deviceType,\n// assetName: assetName,\n// assetType: assetType,\n attributes: attributes,\n telemetry: telemetry, \n};\n\naddAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName);\n\nuplinkDataList.add(deviceInfo);\n\nvar gatewayDeviceNamePrefix = \"Gateway \";\nvar gatewayDeviceType = \"Lora gateway\";\nvar gatewayGroupName = null; // If gatewayGroupName is not null - created device will be added to the entity group with such name.\n\nif (data.cmd == \"gw\") {\n foreach( gatewayInfo : data.gws ) {\n var addGatewayInfo = {};\n\n // You can add some keys manually telemetry\n addGatewayInfo.rssi = gatewayInfo.rssi;\n addGatewayInfo.snr = gatewayInfo.snr;\n // You can add some keys manually telemetry\n \n var gatewayInfoMsg = {\n deviceName: gatewayDeviceNamePrefix + gatewayInfo.gweui,\n deviceType: gatewayDeviceType,\n telemetry: [{\n \"ts\": gatewayInfo.ts,\n \"values\": addGatewayInfo\n }],\n attributes: {\n eui: gatewayInfo.gweui\n }\n };\n addAdditionalInfoForDeviceMsg(gatewayInfoMsg, customerName, gatewayGroupName);\n uplinkDataList.add(gatewayInfoMsg);\n }\n}\n\nreturn uplinkDataList;\n\nfunction addAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName) {\n if (customerName != null) {\n deviceInfo.customerName = customerName;\n }\n if (groupName != null) {\n deviceInfo.groupName = groupName;\n }\n}\n\nfunction processTelemetryData(telemetry, addDataToTelemetry) {\n if (telemetry.size >= 1) {\n telemetry = addDataToTelemetries(telemetry, addDataToTelemetry);\n }\n else {\n telemetry.add(addDataToTelemetry);\n }\n \n return telemetry;\n}\n\nfunction addDataToTelemetries(telemetries, addDataToTelemetry) {\n foreach(telemetry : telemetries) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[\"values\"].keys.contains(element.key)) {\n telemetry[\"values\"][element.key] = element.value;\n }\n } \n }\n \n return telemetries;\n}\n\nfunction calculatePreviousState(compressedDuration) {\n var state = {};\n state.previous_state_duration_overflow = false;\n\n if (compressedDuration < 90) {\n state.previous_state_duration = compressedDuration;\n state.previous_state_duration_error = 0;\n } else if (compressedDuration >= 90 && compressedDuration < 120) {\n state.previous_state_duration = 90 + (compressedDuration - 90) * 5;\n state.previous_state_duration_error = 4;\n } else if (compressedDuration >= 120 && compressedDuration < 127) {\n result.previous_state_duration = 240 + (compressedDuration - 120) * 60;\n result.previous_state_duration_error = 59;\n } else if (compressedDuration === 127) {\n state.previous_state_duration = 660;\n state.previous_state_duration_error = null;\n state.previous_state_duration_overflow = true;\n }\n\n return state;\n }", "encoder": null, "tbelEncoder": null, "updateOnlyKeys": [ diff --git a/VENDORS/Milesight/GS101/LORIOT/uplink/payload_1.json b/VENDORS/Milesight/GS101/LORIOT/uplink/payload_1.json new file mode 100644 index 00000000..2d3a200b --- /dev/null +++ b/VENDORS/Milesight/GS101/LORIOT/uplink/payload_1.json @@ -0,0 +1,32 @@ +{ + "cmd": "gw", + "seqno": 4, + "EUI": "0102030405060708", + "ts": 1690901260493, + "fcnt": 3, + "port": 207, + "freq": 868300000, + "toa": 1319, + "dr": "SF12 BW125 4/5", + "ack": false, + "gws": [ + { + "rssi": -38, + "snr": 8.5, + "ts": 1690901260493, + "time": "2023-08-01T14:47:40.493Z", + "gweui": "1020304080706050", + "ant": 0 + }, + { + "rssi": -42, + "snr": 8.8, + "ts": 1690901260495, + "time": "2023-08-01T14:47:40.495Z", + "gweui": "1020304081716151", + "ant": 0 + } + ], + "bat": 143, + "data": "058e00060101070100" +} \ No newline at end of file diff --git a/VENDORS/Milesight/GS101/LORIOT/uplink/result_1.json b/VENDORS/Milesight/GS101/LORIOT/uplink/result_1.json new file mode 100644 index 00000000..027072d1 --- /dev/null +++ b/VENDORS/Milesight/GS101/LORIOT/uplink/result_1.json @@ -0,0 +1,43 @@ +[{ + "deviceName": "GS 101 0102030405060708", + "deviceType": "Gas sensor", + "attributes": { + "eui": "0102030405060708", + "fPort": 207, + "frequency": 868300000 + }, + "telemetry": [{ + "ts": 1690901260493, + "values": { + "state": "normal", + "valve": "open", + "relay": "close" + } + }] +}, { + "deviceName": "Gateway 1020304080706050", + "deviceType": "Lora gateway", + "telemetry": [{ + "ts": 1690901260493, + "values": { + "rssi": -38, + "snr": 8.5 + } + }], + "attributes": { + "eui": "1020304080706050" + } +}, { + "deviceName": "Gateway 1020304081716151", + "deviceType": "Lora gateway", + "telemetry": [{ + "ts": 1690901260495, + "values": { + "rssi": -42, + "snr": 8.8 + } + }], + "attributes": { + "eui": "1020304081716151" + } +}] \ No newline at end of file diff --git a/VENDORS/Milesight/GS301/LORIOT/uplink/converter.json b/VENDORS/Milesight/GS301/LORIOT/uplink/converter.json index bdc3cc55..1eaa34bd 100644 --- a/VENDORS/Milesight/GS301/LORIOT/uplink/converter.json +++ b/VENDORS/Milesight/GS301/LORIOT/uplink/converter.json @@ -1,11 +1,16 @@ { "name": "Loriot Uplink Decoder for GS301", "type": "UPLINK", - "debugMode": true, + "debugMode": false, + "debugSettings": { + "failuresEnabled": true, + "allEnabled": false, + "allEnabledUntil": 1735211457581 + }, "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);\nvar deviceName = \"GS 301 \" + data.EUI;\nvar deviceType = \"Bathroom Odor Sensor\";\nvar groupName = null; // If groupName is not null - created device will be added to the entity group with such name.\nvar customerName = null; // If customerName is not null - created devices will be assigned to customer with such name. \n\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// If you want to parse incoming data somehow, you can add your code to this function.\n// input: bytes\n// expected output:\n// {\n// \"attributes\": {\"attributeKey\": \"attributeValue\"},\n// \"telemetry\": {\"telemetryKey\": \"telemetryValue\"}\n// }\n\nfunction decodePayload(input) {\n var output = { attributes: {}, telemetry: []};\n \n // --- Decoding code --- //\n var decoded = {};\n for (var i = 0; i < input.length -2; ) {\n var channel_id = input[i++] & 0xff;\n var channel_type = input[i++] & 0xff;\n \n // BATTERY\n if (channel_id === 0x01 && channel_type === 0x75) {\n decoded.battery = input[i];\n i += 1;\n }\n // TEMPERATURE\n else if (channel_id === 0x02 && channel_type === 0x67) {\n // ℃\n decoded.temperature = parseBytesToInt(input, i, 2, false) / 10;\n i += 2;\n\n // ℉\n // decoded.temperature = parseBytesToInt(input, i, 2, false) / 10 * 1.8 + 32;\n // i +=2;\n }\n // HUMIDITY\n else if (channel_id === 0x03 && channel_type === 0x68) {\n decoded.humidity = parseBytesToInt(input, i, 1, false) / 2;\n i += 1;\n }\n // NH3\n else if (channel_id === 0x04 && channel_type === 0x7d) {\n decoded.nh3 = parseBytesToInt(input, i, 2, false) / 100;\n i += 2;\n }\n // H2S\n else if (channel_id === 0x05 && channel_type === 0x7d) {\n decoded.h2s = parseBytesToInt(input, i, 2, false) / 100;\n i += 2;\n }\n }\n \n output.telemetry = [{\n ts: timestamp,\n values: decoded\n }];\n\n // --- Decoding code --- //\n return output;\n}\n\n// --- attributes and telemetry objects ---\nvar telemetry = [];\nvar attributes = {};\n// --- attributes and telemetry objects ---\n\n// --- Timestamp parsing\ntimestamp = data.ts;\n// --- Timestamp parsing\n\n// Message parsing\n// To avoid paths in the decoded objects we passing false value to function as \"pathInKey\" argument.\n// Warning: pathInKey can cause already found fields to be overwritten with the last value found.\n\nvar uplinkDataList = [];\n\n// Passing incoming bytes to decodePayload function, to get custom decoding\nvar customDecoding = decodePayload(hexToBytes(data.data));\n\n// Collecting data to result\nif (customDecoding.?telemetry.size() > 0) {\n if (customDecoding.telemetry instanceof java.util.ArrayList) {\n foreach(telemetryObj: customDecoding.telemetry) {\n if (telemetryObj.ts != null && telemetryObj.values != null) {\n telemetry.add(telemetryObj);\n }\n }\n } else {\n telemetry.putAll(customDecoding.telemetry);\n }\n}\n\nif (customDecoding.?attributes.size() > 0) {\n attributes.putAll(customDecoding.attributes);\n}\n\n// You can add some keys manually to attributes or telemetry\nattributes.eui = data.EUI;\nattributes.fPort = data.port;\nattributes.frequency = data.freq;\n\nvar isIncludeGatewayInfo = metadata[\"includeGatewayInfo\"];\nif(isIncludeGatewayInfo == true) {\n var addDataToTelemetry = {};\n addDataToTelemetry.rssi = data.rssi;\n addDataToTelemetry.seqno = data.seqno;\n addDataToTelemetry.snr = data.snr;\n addDataToTelemetry.ack = data.ack;\n addDataToTelemetry.toa = data.toa;\n addDataToTelemetry.fCnt = data.fcnt;\n \n telemetry = processTelemetryData(telemetry, addDataToTelemetry);\n}\n\nvar deviceInfo = {\n deviceName: deviceName,\n deviceType: deviceType,\n// assetName: assetName,\n// assetType: assetType,\n attributes: attributes,\n telemetry: telemetry, \n};\n\naddAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName);\n\nuplinkDataList.add(deviceInfo);\n\nvar gatewayDeviceNamePrefix = \"Gateway \";\nvar gatewayDeviceType = \"Lora gateway\";\nvar gatewayGroupName = null; // If gatewayGroupName is not null - created device will be added to the entity group with such name.\n\nif (data.cmd == \"gw\") {\n foreach( gatewayInfo : data.gws ) {\n var addGatewayInfo = {};\n\n // You can add some keys manually telemetry\n addGatewayInfo.rssi = gatewayInfo.rssi;\n addGatewayInfo.snr = gatewayInfo.snr;\n // You can add some keys manually telemetry\n \n var gatewayInfoMsg = {\n deviceName: gatewayDeviceNamePrefix + gatewayInfo.gweui,\n deviceType: gatewayDeviceType,\n telemetry: [{\n \"ts\": gatewayInfo.ts,\n \"values\": addGatewayInfo\n }],\n attributes: {\n eui: gatewayInfo.gweui\n }\n };\n addAdditionalInfoForDeviceMsg(gatewayInfoMsg, customerName, gatewayGroupName);\n uplinkDataList.add(gatewayInfoMsg);\n }\n}\n\nreturn uplinkDataList;\n\nfunction addAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName) {\n if (customerName != null) {\n deviceInfo.customerName = customerName;\n }\n if (groupName != null) {\n deviceInfo.groupName = groupName;\n }\n}\n\nfunction processTelemetryData(telemetry, addDataToTelemetry) {\n if (telemetry.size > 1) {\n telemetry = addDataToMultipleTelemetries(telemetry, addDataToTelemetry);\n }\n else if (telemetry.size == 1) {\n telemetry = addDataToSingleTelemetry(telemetry, addDataToTelemetry);\n }\n else {\n telemetry.add(addDataToTelemetry);\n }\n \n return telemetry;\n}\n\nfunction addDataToMultipleTelemetries(telemetry, addDataToTelemetry) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[0][\"values\"].keys.contains(element.key)) {\n telemetry[0][\"values\"][element.key] = element.value;\n }\n if (!telemetry[1][\"values\"].keys.contains(element.key)) {\n telemetry[1][\"values\"][element.key] = element.value;\n }\n }\n \n return telemetry;\n}\n\nfunction addDataToSingleTelemetry(telemetry, addDataToTelemetry) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[0][\"values\"].keys.contains(element.key)) {\n telemetry[0][\"values\"][element.key] = element.value;\n }\n }\n \n return telemetry;\n}\n\nfunction calculatePreviousState(compressedDuration) {\n var state = {};\n state.previous_state_duration_overflow = false;\n\n if (compressedDuration < 90) {\n state.previous_state_duration = compressedDuration;\n state.previous_state_duration_error = 0;\n } else if (compressedDuration >= 90 && compressedDuration < 120) {\n state.previous_state_duration = 90 + (compressedDuration - 90) * 5;\n state.previous_state_duration_error = 4;\n } else if (compressedDuration >= 120 && compressedDuration < 127) {\n result.previous_state_duration = 240 + (compressedDuration - 120) * 60;\n result.previous_state_duration_error = 59;\n } else if (compressedDuration === 127) {\n state.previous_state_duration = 660;\n state.previous_state_duration_error = null;\n state.previous_state_duration_overflow = true;\n }\n\n return state;\n }", + "tbelDecoder": "var data = decodeToJson(payload);\nvar deviceName = \"GS 301 \" + data.EUI;\nvar deviceType = \"Bathroom Odor Sensor\";\nvar groupName = null; // If groupName is not null - created device will be added to the entity group with such name.\nvar customerName = null; // If customerName is not null - created devices will be assigned to customer with such name. \n\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// If you want to parse incoming data somehow, you can add your code to this function.\n// input: bytes\n// expected output:\n// {\n// \"attributes\": {\"attributeKey\": \"attributeValue\"},\n// \"telemetry\": {\"telemetryKey\": \"telemetryValue\"}\n// }\n\nfunction decodePayload(input) {\n var output = { attributes: {}, telemetry: []};\n \n // --- Decoding code --- //\n var decoded = {};\n for (var i = 0; i < input.length -2; ) {\n var channel_id = input[i++] & 0xff;\n var channel_type = input[i++] & 0xff;\n \n // BATTERY\n if (channel_id === 0x01 && channel_type === 0x75) {\n decoded.battery = input[i];\n i += 1;\n }\n // TEMPERATURE\n else if (channel_id === 0x02 && channel_type === 0x67) {\n // ℃\n decoded.temperature = parseBytesToInt(input, i, 2, false) / 10;\n i += 2;\n\n // ℉\n // decoded.temperature = parseBytesToInt(input, i, 2, false) / 10 * 1.8 + 32;\n // i +=2;\n }\n // HUMIDITY\n else if (channel_id === 0x03 && channel_type === 0x68) {\n decoded.humidity = parseBytesToInt(input, i, 1, false) / 2;\n i += 1;\n }\n // NH3\n else if (channel_id === 0x04 && channel_type === 0x7d) {\n decoded.nh3 = parseBytesToInt(input, i, 2, false) / 100;\n i += 2;\n }\n // H2S\n else if (channel_id === 0x05 && channel_type === 0x7d) {\n decoded.h2s = parseBytesToInt(input, i, 2, false) / 100;\n i += 2;\n }\n }\n \n output.telemetry = [{\n ts: timestamp,\n values: decoded\n }];\n\n // --- Decoding code --- //\n return output;\n}\n\n// --- attributes and telemetry objects ---\nvar telemetry = [];\nvar attributes = {};\n// --- attributes and telemetry objects ---\n\n// --- Timestamp parsing\ntimestamp = data.ts;\n// --- Timestamp parsing\n\n// Message parsing\n// To avoid paths in the decoded objects we passing false value to function as \"pathInKey\" argument.\n// Warning: pathInKey can cause already found fields to be overwritten with the last value found.\n\nvar uplinkDataList = [];\n\n// Passing incoming bytes to decodePayload function, to get custom decoding\nvar customDecoding = decodePayload(hexToBytes(data.data));\n\n// Collecting data to result\nif (customDecoding.?telemetry.size() > 0) {\n if (customDecoding.telemetry instanceof java.util.ArrayList) {\n foreach(telemetryObj: customDecoding.telemetry) {\n if (telemetryObj.ts != null && telemetryObj.values != null) {\n telemetry.add(telemetryObj);\n }\n }\n } else {\n telemetry.putAll(customDecoding.telemetry);\n }\n}\n\nif (customDecoding.?attributes.size() > 0) {\n attributes.putAll(customDecoding.attributes);\n}\n\n// You can add some keys manually to attributes or telemetry\nattributes.eui = data.EUI;\nattributes.fPort = data.port;\nattributes.frequency = data.freq;\n\nvar isIncludeGatewayInfo = metadata[\"includeGatewayInfo\"];\nif(isIncludeGatewayInfo == true) {\n var addDataToTelemetry = {};\n addDataToTelemetry.rssi = data.rssi;\n addDataToTelemetry.seqno = data.seqno;\n addDataToTelemetry.snr = data.snr;\n addDataToTelemetry.ack = data.ack;\n addDataToTelemetry.toa = data.toa;\n addDataToTelemetry.fCnt = data.fcnt;\n \n telemetry = processTelemetryData(telemetry, addDataToTelemetry);\n}\n\nvar deviceInfo = {\n deviceName: deviceName,\n deviceType: deviceType,\n// assetName: assetName,\n// assetType: assetType,\n attributes: attributes,\n telemetry: telemetry, \n};\n\naddAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName);\n\nuplinkDataList.add(deviceInfo);\n\nvar gatewayDeviceNamePrefix = \"Gateway \";\nvar gatewayDeviceType = \"Lora gateway\";\nvar gatewayGroupName = null; // If gatewayGroupName is not null - created device will be added to the entity group with such name.\n\nif (data.cmd == \"gw\") {\n foreach( gatewayInfo : data.gws ) {\n var addGatewayInfo = {};\n\n // You can add some keys manually telemetry\n addGatewayInfo.rssi = gatewayInfo.rssi;\n addGatewayInfo.snr = gatewayInfo.snr;\n // You can add some keys manually telemetry\n \n var gatewayInfoMsg = {\n deviceName: gatewayDeviceNamePrefix + gatewayInfo.gweui,\n deviceType: gatewayDeviceType,\n telemetry: [{\n \"ts\": gatewayInfo.ts,\n \"values\": addGatewayInfo\n }],\n attributes: {\n eui: gatewayInfo.gweui\n }\n };\n addAdditionalInfoForDeviceMsg(gatewayInfoMsg, customerName, gatewayGroupName);\n uplinkDataList.add(gatewayInfoMsg);\n }\n}\n\nreturn uplinkDataList;\n\nfunction addAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName) {\n if (customerName != null) {\n deviceInfo.customerName = customerName;\n }\n if (groupName != null) {\n deviceInfo.groupName = groupName;\n }\n}\n\nfunction processTelemetryData(telemetry, addDataToTelemetry) {\n if (telemetry.size >= 1) {\n telemetry = addDataToTelemetries(telemetry, addDataToTelemetry);\n }\n else {\n telemetry.add(addDataToTelemetry);\n }\n \n return telemetry;\n}\n\nfunction addDataToTelemetries(telemetries, addDataToTelemetry) {\n foreach(telemetry : telemetries) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[\"values\"].keys.contains(element.key)) {\n telemetry[\"values\"][element.key] = element.value;\n }\n } \n }\n \n return telemetries;\n}\n\nfunction calculatePreviousState(compressedDuration) {\n var state = {};\n state.previous_state_duration_overflow = false;\n\n if (compressedDuration < 90) {\n state.previous_state_duration = compressedDuration;\n state.previous_state_duration_error = 0;\n } else if (compressedDuration >= 90 && compressedDuration < 120) {\n state.previous_state_duration = 90 + (compressedDuration - 90) * 5;\n state.previous_state_duration_error = 4;\n } else if (compressedDuration >= 120 && compressedDuration < 127) {\n result.previous_state_duration = 240 + (compressedDuration - 120) * 60;\n result.previous_state_duration_error = 59;\n } else if (compressedDuration === 127) {\n state.previous_state_duration = 660;\n state.previous_state_duration_error = null;\n state.previous_state_duration_overflow = true;\n }\n\n return state;\n }", "encoder": null, "tbelEncoder": null, "updateOnlyKeys": [ diff --git a/VENDORS/Milesight/GS301/LORIOT/uplink/payload_1.json b/VENDORS/Milesight/GS301/LORIOT/uplink/payload_1.json new file mode 100644 index 00000000..10df41bc --- /dev/null +++ b/VENDORS/Milesight/GS301/LORIOT/uplink/payload_1.json @@ -0,0 +1,32 @@ +{ + "cmd": "gw", + "seqno": 4, + "EUI": "0102030405060708", + "ts": 1690901260493, + "fcnt": 3, + "port": 207, + "freq": 868300000, + "toa": 1319, + "dr": "SF12 BW125 4/5", + "ack": false, + "gws": [ + { + "rssi": -38, + "snr": 8.5, + "ts": 1690901260493, + "time": "2023-08-01T14:47:40.493Z", + "gweui": "1020304080706050", + "ant": 0 + }, + { + "rssi": -42, + "snr": 8.8, + "ts": 1690901260495, + "time": "2023-08-01T14:47:40.495Z", + "gweui": "1020304081716151", + "ant": 0 + } + ], + "bat": 143, + "data": "01756402671C01036864047D0000057D0100" +} \ No newline at end of file diff --git a/VENDORS/Milesight/GS301/LORIOT/uplink/result_1.json b/VENDORS/Milesight/GS301/LORIOT/uplink/result_1.json new file mode 100644 index 00000000..2dca6b89 --- /dev/null +++ b/VENDORS/Milesight/GS301/LORIOT/uplink/result_1.json @@ -0,0 +1,45 @@ +[{ + "deviceName": "GS 301 0102030405060708", + "deviceType": "Bathroom Odor Sensor", + "attributes": { + "eui": "0102030405060708", + "fPort": 207, + "frequency": 868300000 + }, + "telemetry": [{ + "ts": 1690901260493, + "values": { + "battery": 100, + "temperature": 28.4, + "humidity": 50.0, + "nh3": 0.0, + "h2s": 0.01 + } + }] +}, { + "deviceName": "Gateway 1020304080706050", + "deviceType": "Lora gateway", + "telemetry": [{ + "ts": 1690901260493, + "values": { + "rssi": -38, + "snr": 8.5 + } + }], + "attributes": { + "eui": "1020304080706050" + } +}, { + "deviceName": "Gateway 1020304081716151", + "deviceType": "Lora gateway", + "telemetry": [{ + "ts": 1690901260495, + "values": { + "rssi": -42, + "snr": 8.8 + } + }], + "attributes": { + "eui": "1020304081716151" + } +}] \ No newline at end of file diff --git a/VENDORS/Milesight/TS101/LORIOT/uplink/converter.json b/VENDORS/Milesight/TS101/LORIOT/uplink/converter.json index 102ab55c..6f9068e3 100644 --- a/VENDORS/Milesight/TS101/LORIOT/uplink/converter.json +++ b/VENDORS/Milesight/TS101/LORIOT/uplink/converter.json @@ -1,11 +1,16 @@ { "name": "Loriot Uplink Decoder for TS101", "type": "UPLINK", - "debugMode": true, + "debugMode": false, + "debugSettings": { + "failuresEnabled": true, + "allEnabled": false, + "allEnabledUntil": 1735211789013 + }, "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);\nvar deviceName = \"TS101 \" + data.EUI;\nvar deviceType = \"Temperature Sensor\";\nvar groupName = null; // If groupName is not null - created device will be added to the entity group with such name.\nvar customerName = null; // If customerName is not null - created devices will be assigned to customer with such name. \n\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// If you want to parse incoming data somehow, you can add your code to this function.\n// input: bytes\n// expected output:\n// {\n// \"attributes\": {\"attributeKey\": \"attributeValue\"},\n// \"telemetry\": {\"telemetryKey\": \"telemetryValue\"}\n// }\n\nfunction decodePayload(input) {\n var output = { attributes: {}, telemetry: []};\n \n var decoded = {};\n var historyDate = {};\n for (var i = 0; i < input.length; ) {\n var channel_id = input[i++] & 0xff;\n var channel_type = input[i++] & 0xff;\n\n // BATTERY\n if (channel_id === 0x01 && channel_type === 0x75) {\n decoded.battery = input[i];\n i += 1;\n }\n // TEMPERATURE\n else if (channel_id === 0x03 && channel_type === 0x67) {\n decoded.temperature = parseBytesToInt(input, i, 2, false) / 10; \n i += 2;\n }\n // TEMPERATURE ALARM\n else if (channel_id === 0x83 && channel_type === 0x67) {\n decoded.temperature = parseBytesToInt(input, i, 2, false) / 10; \n decoded.temperature_alarm = readTemperatureAlarm(input[i + 2]);\n i += 3;\n }\n // TEMPERATURE MUTATION ALERT\n else if (channel_id === 0x93 && channel_type === 0xd7) {\n decoded.temperature = parseBytesToInt(input, i, 2, false) / 10; \n decoded.temperature_change = parseBytesToInt(input, i + 2, 2, false) / 100;\n decoded.temperature_alarm = readTemperatureAlarm(input[i + 4]);\n i += 5;\n }\n // HISTORY\n else if (channel_id === 0x20 && channel_type === 0xce) {\n historyDate = {\n ts : parseBytesToInt(input, i, 4, false) * 1000,\n values : {\n temperature: parseBytesToInt(input, i + 4, 2) / 10\n }\n };\n i += 6;\n }\n }\n \n output.telemetry = [{\n ts: timestamp,\n values: decoded\n }, historyDate];\n\n // --- Decoding code --- //\n return output;\n}\n\n// --- attributes and telemetry objects ---\nvar telemetry = [];\nvar attributes = {};\n// --- attributes and telemetry objects ---\n\n// --- Timestamp parsing\ntimestamp = data.ts;\n// --- Timestamp parsing\n\n// Message parsing\n// To avoid paths in the decoded objects we passing false value to function as \"pathInKey\" argument.\n// Warning: pathInKey can cause already found fields to be overwritten with the last value found.\n\nvar uplinkDataList = [];\n\n// Passing incoming bytes to decodePayload function, to get custom decoding\nvar customDecoding = decodePayload(hexToBytes(data.data));\n\n// Collecting data to result\nif (customDecoding.?telemetry.size() > 0) {\n if (customDecoding.telemetry instanceof java.util.ArrayList) {\n foreach(telemetryObj: customDecoding.telemetry) {\n if (telemetryObj.ts != null && telemetryObj.values != null) {\n telemetry.add(telemetryObj);\n }\n }\n } else {\n telemetry.putAll(customDecoding.telemetry);\n }\n}\n\nif (customDecoding.?attributes.size() > 0) {\n attributes.putAll(customDecoding.attributes);\n}\n\n// You can add some keys manually to attributes or telemetry\nattributes.eui = data.EUI;\nattributes.fPort = data.port;\nattributes.frequency = data.freq;\n\nvar isIncludeGatewayInfo = metadata[\"includeGatewayInfo\"];\nif(isIncludeGatewayInfo == true) {\n var addDataToTelemetry = {};\n addDataToTelemetry.rssi = data.rssi;\n addDataToTelemetry.seqno = data.seqno;\n addDataToTelemetry.snr = data.snr;\n addDataToTelemetry.ack = data.ack;\n addDataToTelemetry.toa = data.toa;\n addDataToTelemetry.fCnt = data.fcnt;\n \n telemetry = processTelemetryData(telemetry, addDataToTelemetry);\n}\n\nvar deviceInfo = {\n deviceName: deviceName,\n deviceType: deviceType,\n// assetName: assetName,\n// assetType: assetType,\n attributes: attributes,\n telemetry: telemetry, \n};\n\naddAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName);\n\nuplinkDataList.add(deviceInfo);\n\nvar gatewayDeviceNamePrefix = \"Gateway \";\nvar gatewayDeviceType = \"Lora gateway\";\nvar gatewayGroupName = null; // If gatewayGroupName is not null - created device will be added to the entity group with such name.\n\nif (data.cmd == \"gw\") {\n foreach( gatewayInfo : data.gws ) {\n var addGatewayInfo = {};\n\n // You can add some keys manually telemetry\n addGatewayInfo.rssi = gatewayInfo.rssi;\n addGatewayInfo.snr = gatewayInfo.snr;\n // You can add some keys manually telemetry\n \n var gatewayInfoMsg = {\n deviceName: gatewayDeviceNamePrefix + gatewayInfo.gweui,\n deviceType: gatewayDeviceType,\n telemetry: [{\n \"ts\": gatewayInfo.ts,\n \"values\": addGatewayInfo\n }],\n attributes: {\n eui: gatewayInfo.gweui\n }\n };\n addAdditionalInfoForDeviceMsg(gatewayInfoMsg, customerName, gatewayGroupName);\n uplinkDataList.add(gatewayInfoMsg);\n }\n}\n\nreturn uplinkDataList;\n\nfunction addAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName) {\n if (customerName != null) {\n deviceInfo.customerName = customerName;\n }\n if (groupName != null) {\n deviceInfo.groupName = groupName;\n }\n}\n\nfunction processTelemetryData(telemetry, addDataToTelemetry) {\n if (telemetry.size > 1) {\n telemetry = addDataToMultipleTelemetries(telemetry, addDataToTelemetry);\n }\n else if (telemetry.size == 1) {\n telemetry = addDataToSingleTelemetry(telemetry, addDataToTelemetry);\n }\n else {\n telemetry.add(addDataToTelemetry);\n }\n \n return telemetry;\n}\n\nfunction addDataToMultipleTelemetries(telemetry, addDataToTelemetry) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[0][\"values\"].keys.contains(element.key)) {\n telemetry[0][\"values\"][element.key] = element.value;\n }\n if (!telemetry[1][\"values\"].keys.contains(element.key)) {\n telemetry[1][\"values\"][element.key] = element.value;\n }\n }\n \n return telemetry;\n}\n\nfunction addDataToSingleTelemetry(telemetry, addDataToTelemetry) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[0][\"values\"].keys.contains(element.key)) {\n telemetry[0][\"values\"][element.key] = element.value;\n }\n }\n \n return telemetry;\n}\n\nfunction readTemperatureAlarm(type) {\n switch (type) {\n case 0:\n return \"threshold alarm release\";\n case 1:\n return \"threshold alarm\";\n case 2:\n return \"mutation alarm\";\n default:\n return \"unkown\";\n }\n}", + "tbelDecoder": "var data = decodeToJson(payload);\nvar deviceName = \"TS101 \" + data.EUI;\nvar deviceType = \"Temperature Sensor\";\nvar groupName = null; // If groupName is not null - created device will be added to the entity group with such name.\nvar customerName = null; // If customerName is not null - created devices will be assigned to customer with such name. \n\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// If you want to parse incoming data somehow, you can add your code to this function.\n// input: bytes\n// expected output:\n// {\n// \"attributes\": {\"attributeKey\": \"attributeValue\"},\n// \"telemetry\": {\"telemetryKey\": \"telemetryValue\"}\n// }\n\nfunction decodePayload(input) {\n var output = { attributes: {}, telemetry: []};\n \n var decoded = {};\n var historyDate = {};\n for (var i = 0; i < input.length; ) {\n var channel_id = input[i++] & 0xff;\n var channel_type = input[i++] & 0xff;\n\n // BATTERY\n if (channel_id === 0x01 && channel_type === 0x75) {\n decoded.battery = input[i];\n i += 1;\n }\n // TEMPERATURE\n else if (channel_id === 0x03 && channel_type === 0x67) {\n decoded.temperature = parseBytesToInt(input, i, 2, false) / 10; \n i += 2;\n }\n // TEMPERATURE ALARM\n else if (channel_id === 0x83 && channel_type === 0x67) {\n decoded.temperature = parseBytesToInt(input, i, 2, false) / 10; \n decoded.temperature_alarm = readTemperatureAlarm(input[i + 2]);\n i += 3;\n }\n // TEMPERATURE MUTATION ALERT\n else if (channel_id === 0x93 && channel_type === 0xd7) {\n decoded.temperature = parseBytesToInt(input, i, 2, false) / 10; \n decoded.temperature_change = parseBytesToInt(input, i + 2, 2, false) / 100;\n decoded.temperature_alarm = readTemperatureAlarm(input[i + 4]);\n i += 5;\n }\n // HISTORY\n else if (channel_id === 0x20 && channel_type === 0xce) {\n historyDate = {\n ts : parseBytesToInt(input, i, 4, false) * 1000,\n values : {\n temperature: parseBytesToInt(input, i + 4, 2) / 10\n }\n };\n i += 6;\n }\n }\n \n output.telemetry = [{\n ts: timestamp,\n values: decoded\n }, historyDate];\n\n // --- Decoding code --- //\n return output;\n}\n\n// --- attributes and telemetry objects ---\nvar telemetry = [];\nvar attributes = {};\n// --- attributes and telemetry objects ---\n\n// --- Timestamp parsing\ntimestamp = data.ts;\n// --- Timestamp parsing\n\n// Message parsing\n// To avoid paths in the decoded objects we passing false value to function as \"pathInKey\" argument.\n// Warning: pathInKey can cause already found fields to be overwritten with the last value found.\n\nvar uplinkDataList = [];\n\n// Passing incoming bytes to decodePayload function, to get custom decoding\nvar customDecoding = decodePayload(hexToBytes(data.data));\n\n// Collecting data to result\nif (customDecoding.?telemetry.size() > 0) {\n if (customDecoding.telemetry instanceof java.util.ArrayList) {\n foreach(telemetryObj: customDecoding.telemetry) {\n if (telemetryObj.ts != null && telemetryObj.values != null) {\n telemetry.add(telemetryObj);\n }\n }\n } else {\n telemetry.putAll(customDecoding.telemetry);\n }\n}\n\nif (customDecoding.?attributes.size() > 0) {\n attributes.putAll(customDecoding.attributes);\n}\n\n// You can add some keys manually to attributes or telemetry\nattributes.eui = data.EUI;\nattributes.fPort = data.port;\nattributes.frequency = data.freq;\n\nvar isIncludeGatewayInfo = metadata[\"includeGatewayInfo\"];\nif(isIncludeGatewayInfo == true) {\n var addDataToTelemetry = {};\n addDataToTelemetry.rssi = data.rssi;\n addDataToTelemetry.seqno = data.seqno;\n addDataToTelemetry.snr = data.snr;\n addDataToTelemetry.ack = data.ack;\n addDataToTelemetry.toa = data.toa;\n addDataToTelemetry.fCnt = data.fcnt;\n \n telemetry = processTelemetryData(telemetry, addDataToTelemetry);\n}\n\nvar deviceInfo = {\n deviceName: deviceName,\n deviceType: deviceType,\n// assetName: assetName,\n// assetType: assetType,\n attributes: attributes,\n telemetry: telemetry, \n};\n\naddAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName);\n\nuplinkDataList.add(deviceInfo);\n\nvar gatewayDeviceNamePrefix = \"Gateway \";\nvar gatewayDeviceType = \"Lora gateway\";\nvar gatewayGroupName = null; // If gatewayGroupName is not null - created device will be added to the entity group with such name.\n\nif (data.cmd == \"gw\") {\n foreach( gatewayInfo : data.gws ) {\n var addGatewayInfo = {};\n\n // You can add some keys manually telemetry\n addGatewayInfo.rssi = gatewayInfo.rssi;\n addGatewayInfo.snr = gatewayInfo.snr;\n // You can add some keys manually telemetry\n \n var gatewayInfoMsg = {\n deviceName: gatewayDeviceNamePrefix + gatewayInfo.gweui,\n deviceType: gatewayDeviceType,\n telemetry: [{\n \"ts\": gatewayInfo.ts,\n \"values\": addGatewayInfo\n }],\n attributes: {\n eui: gatewayInfo.gweui\n }\n };\n addAdditionalInfoForDeviceMsg(gatewayInfoMsg, customerName, gatewayGroupName);\n uplinkDataList.add(gatewayInfoMsg);\n }\n}\n\nreturn uplinkDataList;\n\nfunction addAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName) {\n if (customerName != null) {\n deviceInfo.customerName = customerName;\n }\n if (groupName != null) {\n deviceInfo.groupName = groupName;\n }\n}\n\nfunction processTelemetryData(telemetry, addDataToTelemetry) {\n if (telemetry.size >= 1) {\n telemetry = addDataToTelemetries(telemetry, addDataToTelemetry);\n }\n else {\n telemetry.add(addDataToTelemetry);\n }\n \n return telemetry;\n}\n\nfunction addDataToTelemetries(telemetries, addDataToTelemetry) {\n foreach(telemetry : telemetries) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[\"values\"].keys.contains(element.key)) {\n telemetry[\"values\"][element.key] = element.value;\n }\n } \n }\n \n return telemetries;\n}\n\nfunction readTemperatureAlarm(type) {\n switch (type) {\n case 0:\n return \"threshold alarm release\";\n case 1:\n return \"threshold alarm\";\n case 2:\n return \"mutation alarm\";\n default:\n return \"unkown\";\n }\n}", "encoder": null, "tbelEncoder": null, "updateOnlyKeys": [ diff --git a/VENDORS/Milesight/TS101/LORIOT/uplink/payload_2.json b/VENDORS/Milesight/TS101/LORIOT/uplink/payload_2.json new file mode 100644 index 00000000..a4d6f514 --- /dev/null +++ b/VENDORS/Milesight/TS101/LORIOT/uplink/payload_2.json @@ -0,0 +1,32 @@ +{ + "cmd": "gw", + "seqno": 4, + "EUI": "0102030405060708", + "ts": 1690901260493, + "fcnt": 3, + "port": 207, + "freq": 868300000, + "toa": 1319, + "dr": "SF12 BW125 4/5", + "ack": false, + "gws": [ + { + "rssi": -38, + "snr": 8.5, + "ts": 1690901260493, + "time": "2023-08-01T14:47:40.493Z", + "gweui": "1020304080706050", + "ant": 0 + }, + { + "rssi": -42, + "snr": 8.8, + "ts": 1690901260495, + "time": "2023-08-01T14:47:40.495Z", + "gweui": "1020304081716151", + "ant": 0 + } + ], + "bat": 143, + "data": "8367520101" +} \ No newline at end of file diff --git a/VENDORS/Milesight/TS101/LORIOT/uplink/result_2.json b/VENDORS/Milesight/TS101/LORIOT/uplink/result_2.json new file mode 100644 index 00000000..a4cf60a9 --- /dev/null +++ b/VENDORS/Milesight/TS101/LORIOT/uplink/result_2.json @@ -0,0 +1,42 @@ +[{ + "deviceName": "TS101 0102030405060708", + "deviceType": "Temperature Sensor", + "attributes": { + "eui": "0102030405060708", + "fPort": 207, + "frequency": 868300000 + }, + "telemetry": [{ + "ts": 1690901260493, + "values": { + "temperature": 33.8, + "temperature_alarm": "threshold alarm" + } + }] +}, { + "deviceName": "Gateway 1020304080706050", + "deviceType": "Lora gateway", + "telemetry": [{ + "ts": 1690901260493, + "values": { + "rssi": -38, + "snr": 8.5 + } + }], + "attributes": { + "eui": "1020304080706050" + } +}, { + "deviceName": "Gateway 1020304081716151", + "deviceType": "Lora gateway", + "telemetry": [{ + "ts": 1690901260495, + "values": { + "rssi": -42, + "snr": 8.8 + } + }], + "attributes": { + "eui": "1020304081716151" + } +}] \ No newline at end of file diff --git a/VENDORS/Milesight/TS201/LORIOT/uplink/payload_2.json b/VENDORS/Milesight/TS201/LORIOT/uplink/payload_2.json new file mode 100644 index 00000000..5f6f4ba0 --- /dev/null +++ b/VENDORS/Milesight/TS201/LORIOT/uplink/payload_2.json @@ -0,0 +1,32 @@ +{ + "cmd": "gw", + "seqno": 4, + "EUI": "0102030405060708", + "ts": 1690901260493, + "fcnt": 3, + "port": 207, + "freq": 868300000, + "toa": 1319, + "dr": "SF12 BW125 4/5", + "ack": false, + "gws": [ + { + "rssi": -38, + "snr": 8.5, + "ts": 1690901260493, + "time": "2023-08-01T14:47:40.493Z", + "gweui": "1020304080706050", + "ant": 0 + }, + { + "rssi": -42, + "snr": 8.8, + "ts": 1690901260495, + "time": "2023-08-01T14:47:40.495Z", + "gweui": "1020304081716151", + "ant": 0 + } + ], + "bat": 143, + "data": "20cec79afa6402bdff" +} \ No newline at end of file diff --git a/VENDORS/Milesight/TS201/LORIOT/uplink/result_2.json b/VENDORS/Milesight/TS201/LORIOT/uplink/result_2.json new file mode 100644 index 00000000..529ae28f --- /dev/null +++ b/VENDORS/Milesight/TS201/LORIOT/uplink/result_2.json @@ -0,0 +1,46 @@ +[{ + "deviceName": "0102030405060708", + "deviceType": "TS201", + "attributes": { + "eui": "0102030405060708", + "fPort": 207, + "frequency": 868300000 + }, + "telemetry": [{ + "ts": 1690901260493, + "values": {} + }, { + "ts": 1694145223000, + "values": { + "temperature": -6.7, + "read_status": "Success", + "event_type": "Alarm(Threshold or Mutation)" + } + }] +}, { + "deviceName": "Gateway 1020304080706050", + "deviceType": "Lora gateway", + "telemetry": [{ + "ts": 1690901260493, + "values": { + "rssi": -38, + "snr": 8.5 + } + }], + "attributes": { + "eui": "1020304080706050" + } +}, { + "deviceName": "Gateway 1020304081716151", + "deviceType": "Lora gateway", + "telemetry": [{ + "ts": 1690901260495, + "values": { + "rssi": -42, + "snr": 8.8 + } + }], + "attributes": { + "eui": "1020304081716151" + } +}] \ No newline at end of file diff --git a/VENDORS/Milesight/WS101/LORIOT/uplink/converter.json b/VENDORS/Milesight/WS101/LORIOT/uplink/converter.json index 3b1f6eb6..27cc17cc 100644 --- a/VENDORS/Milesight/WS101/LORIOT/uplink/converter.json +++ b/VENDORS/Milesight/WS101/LORIOT/uplink/converter.json @@ -1,11 +1,16 @@ { "name": "Loriot Uplink Decoder for WS101", "type": "UPLINK", - "debugMode": true, + "debugMode": false, + "debugSettings": { + "failuresEnabled": true, + "allEnabled": false, + "allEnabledUntil": 1735212363893 + }, "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);\nvar deviceName = data.EUI;\nvar deviceType = \"WS101\";\nvar groupName = null; // If groupName is not null - created device will be added to the entity group with such name.\nvar customerName = null; // If customerName is not null - created devices will be assigned to customer with such name. \n\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// If you want to parse incoming data somehow, you can add your code to this function.\n// input: bytes\n// expected output:\n// {\n// \"attributes\": {\"attributeKey\": \"attributeValue\"},\n// \"telemetry\": {\"telemetryKey\": \"telemetryValue\"}\n// }\n\nfunction decodePayload(input) {\n var output = { attributes: {}, telemetry: []};\n \n var decoded = {};\n for (var i = 0; i < input.length - 2; ) {\n var channel_id = input[i++] & 0xff;\n var channel_type = input[i++] & 0xff;\n // BATTERY\n if (channel_id === 0x01 && channel_type === 0x75) {\n decoded.battery = input[i];\n i += 1;\n }\n // PRESS STATE\n else if (channel_id === 0xff && channel_type === 0x2e) {\n setPressState(decoded, input[i]);\n i += 1;\n } \n }\n \n \n output.telemetry = [{\n ts: timestamp,\n values: decoded\n }];\n\n // --- Decoding code --- //\n return output;\n}\n\n// --- attributes and telemetry objects ---\nvar telemetry = [];\nvar attributes = {};\n// --- attributes and telemetry objects ---\n\n// --- Timestamp parsing\ntimestamp = data.ts;\n// --- Timestamp parsing\n\n// Message parsing\n// To avoid paths in the decoded objects we passing false value to function as \"pathInKey\" argument.\n// Warning: pathInKey can cause already found fields to be overwritten with the last value found.\n\nvar uplinkDataList = [];\n\n// Passing incoming bytes to decodePayload function, to get custom decoding\nvar customDecoding = decodePayload(hexToBytes(data.data));\n\n// Collecting data to result\nif (customDecoding.?telemetry.size() > 0) {\n if (customDecoding.telemetry instanceof java.util.ArrayList) {\n foreach(telemetryObj: customDecoding.telemetry) {\n if (telemetryObj.ts != null && telemetryObj.values != null) {\n telemetry.add(telemetryObj);\n }\n }\n } else {\n telemetry.putAll(customDecoding.telemetry);\n }\n}\n\nif (customDecoding.?attributes.size() > 0) {\n attributes.putAll(customDecoding.attributes);\n}\n\n// You can add some keys manually to attributes or telemetry\nattributes.eui = data.EUI;\nattributes.fPort = data.port;\nattributes.frequency = data.freq;\n\nvar isIncludeGatewayInfo = metadata[\"includeGatewayInfo\"];\nif(isIncludeGatewayInfo == true) {\n var addDataToTelemetry = {};\n addDataToTelemetry.rssi = data.rssi;\n addDataToTelemetry.seqno = data.seqno;\n addDataToTelemetry.snr = data.snr;\n addDataToTelemetry.ack = data.ack;\n addDataToTelemetry.toa = data.toa;\n addDataToTelemetry.fCnt = data.fcnt;\n \n telemetry = processTelemetryData(telemetry, addDataToTelemetry);\n}\n\nvar deviceInfo = {\n deviceName: deviceName,\n deviceType: deviceType,\n// assetName: assetName,\n// assetType: assetType,\n attributes: attributes,\n telemetry: telemetry, \n};\n\naddAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName);\n\nuplinkDataList.add(deviceInfo);\n\nvar gatewayDeviceNamePrefix = \"Gateway \";\nvar gatewayDeviceType = \"Lora gateway\";\nvar gatewayGroupName = null; // If gatewayGroupName is not null - created device will be added to the entity group with such name.\n\nif (data.cmd == \"gw\") {\n foreach( gatewayInfo : data.gws ) {\n var addGatewayInfo = {};\n\n // You can add some keys manually telemetry\n addGatewayInfo.rssi = gatewayInfo.rssi;\n addGatewayInfo.snr = gatewayInfo.snr;\n // You can add some keys manually telemetry\n \n var gatewayInfoMsg = {\n deviceName: gatewayDeviceNamePrefix + gatewayInfo.gweui,\n deviceType: gatewayDeviceType,\n telemetry: [{\n \"ts\": gatewayInfo.ts,\n \"values\": addGatewayInfo\n }],\n attributes: {\n eui: gatewayInfo.gweui\n }\n };\n addAdditionalInfoForDeviceMsg(gatewayInfoMsg, customerName, gatewayGroupName);\n uplinkDataList.add(gatewayInfoMsg);\n }\n}\n\nreturn uplinkDataList;\n\nfunction addAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName) {\n if (customerName != null) {\n deviceInfo.customerName = customerName;\n }\n if (groupName != null) {\n deviceInfo.groupName = groupName;\n }\n}\n\nfunction processTelemetryData(telemetry, addDataToTelemetry) {\n if (telemetry.size > 1) {\n telemetry = addDataToMultipleTelemetries(telemetry, addDataToTelemetry);\n }\n else if (telemetry.size == 1) {\n telemetry = addDataToSingleTelemetry(telemetry, addDataToTelemetry);\n }\n else {\n telemetry.add(addDataToTelemetry);\n }\n \n return telemetry;\n}\n\nfunction addDataToMultipleTelemetries(telemetry, addDataToTelemetry) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[0][\"values\"].keys.contains(element.key)) {\n telemetry[0][\"values\"][element.key] = element.value;\n }\n if (!telemetry[1][\"values\"].keys.contains(element.key)) {\n telemetry[1][\"values\"][element.key] = element.value;\n }\n }\n \n return telemetry;\n}\n\nfunction addDataToSingleTelemetry(telemetry, addDataToTelemetry) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[0][\"values\"].keys.contains(element.key)) {\n telemetry[0][\"values\"][element.key] = element.value;\n }\n }\n \n return telemetry;\n}\n\nfunction setPressState(decoded, type) {\n switch (type) {\n case 1:\n decoded.press = \"short\";\n break;\n case 2:\n decoded.press = \"long\";\n break;\n case 3:\n decoded.press = \"double\";\n break;\n default:\n decoded.press = \"unknown\";\n break;\n }\n}", + "tbelDecoder": "var data = decodeToJson(payload);\nvar deviceName = data.EUI;\nvar deviceType = \"WS101\";\nvar groupName = null; // If groupName is not null - created device will be added to the entity group with such name.\nvar customerName = null; // If customerName is not null - created devices will be assigned to customer with such name. \n\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// If you want to parse incoming data somehow, you can add your code to this function.\n// input: bytes\n// expected output:\n// {\n// \"attributes\": {\"attributeKey\": \"attributeValue\"},\n// \"telemetry\": {\"telemetryKey\": \"telemetryValue\"}\n// }\n\nfunction decodePayload(input) {\n var output = { attributes: {}, telemetry: []};\n \n var decoded = {};\n for (var i = 0; i < input.length - 2; ) {\n var channel_id = input[i++] & 0xff;\n var channel_type = input[i++] & 0xff;\n // BATTERY\n if (channel_id === 0x01 && channel_type === 0x75) {\n decoded.battery = input[i];\n i += 1;\n }\n // PRESS STATE\n else if (channel_id === 0xff && channel_type === 0x2e) {\n setPressState(decoded, input[i]);\n i += 1;\n } \n }\n \n \n output.telemetry = [{\n ts: timestamp,\n values: decoded\n }];\n\n // --- Decoding code --- //\n return output;\n}\n\n// --- attributes and telemetry objects ---\nvar telemetry = [];\nvar attributes = {};\n// --- attributes and telemetry objects ---\n\n// --- Timestamp parsing\ntimestamp = data.ts;\n// --- Timestamp parsing\n\n// Message parsing\n// To avoid paths in the decoded objects we passing false value to function as \"pathInKey\" argument.\n// Warning: pathInKey can cause already found fields to be overwritten with the last value found.\n\nvar uplinkDataList = [];\n\n// Passing incoming bytes to decodePayload function, to get custom decoding\nvar customDecoding = decodePayload(hexToBytes(data.data));\n\n// Collecting data to result\nif (customDecoding.?telemetry.size() > 0) {\n if (customDecoding.telemetry instanceof java.util.ArrayList) {\n foreach(telemetryObj: customDecoding.telemetry) {\n if (telemetryObj.ts != null && telemetryObj.values != null) {\n telemetry.add(telemetryObj);\n }\n }\n } else {\n telemetry.putAll(customDecoding.telemetry);\n }\n}\n\nif (customDecoding.?attributes.size() > 0) {\n attributes.putAll(customDecoding.attributes);\n}\n\n// You can add some keys manually to attributes or telemetry\nattributes.eui = data.EUI;\nattributes.fPort = data.port;\nattributes.frequency = data.freq;\n\nvar isIncludeGatewayInfo = metadata[\"includeGatewayInfo\"];\nif(isIncludeGatewayInfo == true) {\n var addDataToTelemetry = {};\n addDataToTelemetry.rssi = data.rssi;\n addDataToTelemetry.seqno = data.seqno;\n addDataToTelemetry.snr = data.snr;\n addDataToTelemetry.ack = data.ack;\n addDataToTelemetry.toa = data.toa;\n addDataToTelemetry.fCnt = data.fcnt;\n \n telemetry = processTelemetryData(telemetry, addDataToTelemetry);\n}\n\nvar deviceInfo = {\n deviceName: deviceName,\n deviceType: deviceType,\n// assetName: assetName,\n// assetType: assetType,\n attributes: attributes,\n telemetry: telemetry, \n};\n\naddAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName);\n\nuplinkDataList.add(deviceInfo);\n\nvar gatewayDeviceNamePrefix = \"Gateway \";\nvar gatewayDeviceType = \"Lora gateway\";\nvar gatewayGroupName = null; // If gatewayGroupName is not null - created device will be added to the entity group with such name.\n\nif (data.cmd == \"gw\") {\n foreach( gatewayInfo : data.gws ) {\n var addGatewayInfo = {};\n\n // You can add some keys manually telemetry\n addGatewayInfo.rssi = gatewayInfo.rssi;\n addGatewayInfo.snr = gatewayInfo.snr;\n // You can add some keys manually telemetry\n \n var gatewayInfoMsg = {\n deviceName: gatewayDeviceNamePrefix + gatewayInfo.gweui,\n deviceType: gatewayDeviceType,\n telemetry: [{\n \"ts\": gatewayInfo.ts,\n \"values\": addGatewayInfo\n }],\n attributes: {\n eui: gatewayInfo.gweui\n }\n };\n addAdditionalInfoForDeviceMsg(gatewayInfoMsg, customerName, gatewayGroupName);\n uplinkDataList.add(gatewayInfoMsg);\n }\n}\n\nreturn uplinkDataList;\n\nfunction addAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName) {\n if (customerName != null) {\n deviceInfo.customerName = customerName;\n }\n if (groupName != null) {\n deviceInfo.groupName = groupName;\n }\n}\n\nfunction processTelemetryData(telemetry, addDataToTelemetry) {\n if (telemetry.size >= 1) {\n telemetry = addDataToTelemetries(telemetry, addDataToTelemetry);\n }\n else {\n telemetry.add(addDataToTelemetry);\n }\n \n return telemetry;\n}\n\nfunction addDataToTelemetries(telemetries, addDataToTelemetry) {\n foreach(telemetry : telemetries) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[\"values\"].keys.contains(element.key)) {\n telemetry[\"values\"][element.key] = element.value;\n }\n } \n }\n \n return telemetries;\n}\n\nfunction setPressState(decoded, type) {\n switch (type) {\n case 1:\n decoded.press = \"short\";\n break;\n case 2:\n decoded.press = \"long\";\n break;\n case 3:\n decoded.press = \"double\";\n break;\n default:\n decoded.press = \"unknown\";\n break;\n }\n}", "encoder": null, "tbelEncoder": null, "updateOnlyKeys": [ diff --git a/VENDORS/Milesight/WS101/LORIOT/uplink/payload_1.json b/VENDORS/Milesight/WS101/LORIOT/uplink/payload_1.json new file mode 100644 index 00000000..5561fb8d --- /dev/null +++ b/VENDORS/Milesight/WS101/LORIOT/uplink/payload_1.json @@ -0,0 +1,32 @@ +{ + "cmd": "gw", + "seqno": 4, + "EUI": "0102030405060708", + "ts": 1690901260493, + "fcnt": 3, + "port": 207, + "freq": 868300000, + "toa": 1319, + "dr": "SF12 BW125 4/5", + "ack": false, + "gws": [ + { + "rssi": -38, + "snr": 8.5, + "ts": 1690901260493, + "time": "2023-08-01T14:47:40.493Z", + "gweui": "1020304080706050", + "ant": 0 + }, + { + "rssi": -42, + "snr": 8.8, + "ts": 1690901260495, + "time": "2023-08-01T14:47:40.495Z", + "gweui": "1020304081716151", + "ant": 0 + } + ], + "bat": 143, + "data": "017510FF2E01" +} \ No newline at end of file diff --git a/VENDORS/Milesight/WS101/LORIOT/uplink/result_1.json b/VENDORS/Milesight/WS101/LORIOT/uplink/result_1.json new file mode 100644 index 00000000..e34e8ec0 --- /dev/null +++ b/VENDORS/Milesight/WS101/LORIOT/uplink/result_1.json @@ -0,0 +1,42 @@ +[{ + "deviceName": "0102030405060708", + "deviceType": "WS101", + "attributes": { + "eui": "0102030405060708", + "fPort": 207, + "frequency": 868300000 + }, + "telemetry": [{ + "ts": 1690901260493, + "values": { + "battery": 16, + "press": "short" + } + }] +}, { + "deviceName": "Gateway 1020304080706050", + "deviceType": "Lora gateway", + "telemetry": [{ + "ts": 1690901260493, + "values": { + "rssi": -38, + "snr": 8.5 + } + }], + "attributes": { + "eui": "1020304080706050" + } +}, { + "deviceName": "Gateway 1020304081716151", + "deviceType": "Lora gateway", + "telemetry": [{ + "ts": 1690901260495, + "values": { + "rssi": -42, + "snr": 8.8 + } + }], + "attributes": { + "eui": "1020304081716151" + } +}] \ No newline at end of file diff --git a/VENDORS/Milesight/WS201/LORIOT/uplink/converter.json b/VENDORS/Milesight/WS201/LORIOT/uplink/converter.json index e57b314c..b756da9a 100644 --- a/VENDORS/Milesight/WS201/LORIOT/uplink/converter.json +++ b/VENDORS/Milesight/WS201/LORIOT/uplink/converter.json @@ -1,11 +1,16 @@ { "name": "Loriot Uplink Decoder for WS201", "type": "UPLINK", - "debugMode": true, + "debugMode": false, + "debugSettings": { + "failuresEnabled": true, + "allEnabled": false, + "allEnabledUntil": 1735213277304 + }, "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);\nvar deviceName = data.EUI;\nvar deviceType = \"WS201\";\nvar groupName = null; // If groupName is not null - created device will be added to the entity group with such name.\nvar customerName = null; // If customerName is not null - created devices will be assigned to customer with such name. \n\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// If you want to parse incoming data somehow, you can add your code to this function.\n// input: bytes\n// expected output:\n// {\n// \"attributes\": {\"attributeKey\": \"attributeValue\"},\n// \"telemetry\": {\"telemetryKey\": \"telemetryValue\"}\n// }\n\nfunction decodePayload(input) {\n var output = { attributes: {}, telemetry: []};\n \n var decoded = {};\n for (var i = 0; i < input.length - 2; ) {\n var channel_id = input[i++] & 0xff;\n var channel_type = input[i++] & 0xff;\n // BATTERY\n if (channel_id === 0x01 && channel_type === 0x75) {\n decoded.battery = input[i];\n i += 1;\n }\n // DISTANCE\n else if (channel_id === 0x03 && channel_type === 0x82) {\n decoded.distance = parseBytesToInt(input, i, 2, false);\n i += 2;\n }\n // REMAINING AMOUNT\n else if (channel_id === 0x04 && channel_type === 0xd6) {\n decoded.remaining = input[i];\n i += 1;\n }\n }\n \n \n output.telemetry = [{\n ts: timestamp,\n values: decoded\n }];\n\n // --- Decoding code --- //\n return output;\n}\n\n// --- attributes and telemetry objects ---\nvar telemetry = [];\nvar attributes = {};\n// --- attributes and telemetry objects ---\n\n// --- Timestamp parsing\ntimestamp = data.ts;\n// --- Timestamp parsing\n\n// Message parsing\n// To avoid paths in the decoded objects we passing false value to function as \"pathInKey\" argument.\n// Warning: pathInKey can cause already found fields to be overwritten with the last value found.\n\nvar uplinkDataList = [];\n\n// Passing incoming bytes to decodePayload function, to get custom decoding\nvar customDecoding = decodePayload(hexToBytes(data.data));\n\n// Collecting data to result\nif (customDecoding.?telemetry.size() > 0) {\n if (customDecoding.telemetry instanceof java.util.ArrayList) {\n foreach(telemetryObj: customDecoding.telemetry) {\n if (telemetryObj.ts != null && telemetryObj.values != null) {\n telemetry.add(telemetryObj);\n }\n }\n } else {\n telemetry.putAll(customDecoding.telemetry);\n }\n}\n\nif (customDecoding.?attributes.size() > 0) {\n attributes.putAll(customDecoding.attributes);\n}\n\n// You can add some keys manually to attributes or telemetry\nattributes.eui = data.EUI;\nattributes.fPort = data.port;\nattributes.frequency = data.freq;\n\nvar isIncludeGatewayInfo = metadata[\"includeGatewayInfo\"];\nif(isIncludeGatewayInfo == true) {\n var addDataToTelemetry = {};\n addDataToTelemetry.rssi = data.rssi;\n addDataToTelemetry.seqno = data.seqno;\n addDataToTelemetry.snr = data.snr;\n addDataToTelemetry.ack = data.ack;\n addDataToTelemetry.toa = data.toa;\n addDataToTelemetry.fCnt = data.fcnt;\n \n telemetry = processTelemetryData(telemetry, addDataToTelemetry);\n}\n\nvar deviceInfo = {\n deviceName: deviceName,\n deviceType: deviceType,\n// assetName: assetName,\n// assetType: assetType,\n attributes: attributes,\n telemetry: telemetry, \n};\n\naddAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName);\n\nuplinkDataList.add(deviceInfo);\n\nvar gatewayDeviceNamePrefix = \"Gateway \";\nvar gatewayDeviceType = \"Lora gateway\";\nvar gatewayGroupName = null; // If gatewayGroupName is not null - created device will be added to the entity group with such name.\n\nif (data.cmd == \"gw\") {\n foreach( gatewayInfo : data.gws ) {\n var addGatewayInfo = {};\n\n // You can add some keys manually telemetry\n addGatewayInfo.rssi = gatewayInfo.rssi;\n addGatewayInfo.snr = gatewayInfo.snr;\n // You can add some keys manually telemetry\n \n var gatewayInfoMsg = {\n deviceName: gatewayDeviceNamePrefix + gatewayInfo.gweui,\n deviceType: gatewayDeviceType,\n telemetry: [{\n \"ts\": gatewayInfo.ts,\n \"values\": addGatewayInfo\n }],\n attributes: {\n eui: gatewayInfo.gweui\n }\n };\n addAdditionalInfoForDeviceMsg(gatewayInfoMsg, customerName, gatewayGroupName);\n uplinkDataList.add(gatewayInfoMsg);\n }\n}\n\nreturn uplinkDataList;\n\nfunction addAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName) {\n if (customerName != null) {\n deviceInfo.customerName = customerName;\n }\n if (groupName != null) {\n deviceInfo.groupName = groupName;\n }\n}\n\nfunction processTelemetryData(telemetry, addDataToTelemetry) {\n if (telemetry.size > 1) {\n telemetry = addDataToMultipleTelemetries(telemetry, addDataToTelemetry);\n }\n else if (telemetry.size == 1) {\n telemetry = addDataToSingleTelemetry(telemetry, addDataToTelemetry);\n }\n else {\n telemetry.add(addDataToTelemetry);\n }\n \n return telemetry;\n}\n\nfunction addDataToMultipleTelemetries(telemetry, addDataToTelemetry) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[0][\"values\"].keys.contains(element.key)) {\n telemetry[0][\"values\"][element.key] = element.value;\n }\n if (!telemetry[1][\"values\"].keys.contains(element.key)) {\n telemetry[1][\"values\"][element.key] = element.value;\n }\n }\n \n return telemetry;\n}\n\nfunction addDataToSingleTelemetry(telemetry, addDataToTelemetry) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[0][\"values\"].keys.contains(element.key)) {\n telemetry[0][\"values\"][element.key] = element.value;\n }\n }\n \n return telemetry;\n}\n\nfunction setPressState(decoded, type) {\n switch (type) {\n case 1:\n decoded.press = \"short\";\n break;\n case 2:\n decoded.press = \"long\";\n break;\n case 3:\n decoded.press = \"double\";\n break;\n default:\n decoded.press = \"unknown\";\n break;\n }\n}", + "tbelDecoder": "var data = decodeToJson(payload);\nvar deviceName = data.EUI;\nvar deviceType = \"WS201\";\nvar groupName = null; // If groupName is not null - created device will be added to the entity group with such name.\nvar customerName = null; // If customerName is not null - created devices will be assigned to customer with such name. \n\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// If you want to parse incoming data somehow, you can add your code to this function.\n// input: bytes\n// expected output:\n// {\n// \"attributes\": {\"attributeKey\": \"attributeValue\"},\n// \"telemetry\": {\"telemetryKey\": \"telemetryValue\"}\n// }\n\nfunction decodePayload(input) {\n var output = { attributes: {}, telemetry: []};\n \n var decoded = {};\n for (var i = 0; i < input.length - 2; ) {\n var channel_id = input[i++] & 0xff;\n var channel_type = input[i++] & 0xff;\n // BATTERY\n if (channel_id === 0x01 && channel_type === 0x75) {\n decoded.battery = input[i];\n i += 1;\n }\n // DISTANCE\n else if (channel_id === 0x03 && channel_type === 0x82) {\n decoded.distance = parseBytesToInt(input, i, 2, false);\n i += 2;\n }\n // REMAINING AMOUNT\n else if (channel_id === 0x04 && channel_type === 0xd6) {\n decoded.remaining = input[i];\n i += 1;\n }\n }\n \n \n output.telemetry = [{\n ts: timestamp,\n values: decoded\n }];\n\n // --- Decoding code --- //\n return output;\n}\n\n// --- attributes and telemetry objects ---\nvar telemetry = [];\nvar attributes = {};\n// --- attributes and telemetry objects ---\n\n// --- Timestamp parsing\ntimestamp = data.ts;\n// --- Timestamp parsing\n\n// Message parsing\n// To avoid paths in the decoded objects we passing false value to function as \"pathInKey\" argument.\n// Warning: pathInKey can cause already found fields to be overwritten with the last value found.\n\nvar uplinkDataList = [];\n\n// Passing incoming bytes to decodePayload function, to get custom decoding\nvar customDecoding = decodePayload(hexToBytes(data.data));\n\n// Collecting data to result\nif (customDecoding.?telemetry.size() > 0) {\n if (customDecoding.telemetry instanceof java.util.ArrayList) {\n foreach(telemetryObj: customDecoding.telemetry) {\n if (telemetryObj.ts != null && telemetryObj.values != null) {\n telemetry.add(telemetryObj);\n }\n }\n } else {\n telemetry.putAll(customDecoding.telemetry);\n }\n}\n\nif (customDecoding.?attributes.size() > 0) {\n attributes.putAll(customDecoding.attributes);\n}\n\n// You can add some keys manually to attributes or telemetry\nattributes.eui = data.EUI;\nattributes.fPort = data.port;\nattributes.frequency = data.freq;\n\nvar isIncludeGatewayInfo = metadata[\"includeGatewayInfo\"];\nif(isIncludeGatewayInfo == true) {\n var addDataToTelemetry = {};\n addDataToTelemetry.rssi = data.rssi;\n addDataToTelemetry.seqno = data.seqno;\n addDataToTelemetry.snr = data.snr;\n addDataToTelemetry.ack = data.ack;\n addDataToTelemetry.toa = data.toa;\n addDataToTelemetry.fCnt = data.fcnt;\n \n telemetry = processTelemetryData(telemetry, addDataToTelemetry);\n}\n\nvar deviceInfo = {\n deviceName: deviceName,\n deviceType: deviceType,\n// assetName: assetName,\n// assetType: assetType,\n attributes: attributes,\n telemetry: telemetry, \n};\n\naddAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName);\n\nuplinkDataList.add(deviceInfo);\n\nvar gatewayDeviceNamePrefix = \"Gateway \";\nvar gatewayDeviceType = \"Lora gateway\";\nvar gatewayGroupName = null; // If gatewayGroupName is not null - created device will be added to the entity group with such name.\n\nif (data.cmd == \"gw\") {\n foreach( gatewayInfo : data.gws ) {\n var addGatewayInfo = {};\n\n // You can add some keys manually telemetry\n addGatewayInfo.rssi = gatewayInfo.rssi;\n addGatewayInfo.snr = gatewayInfo.snr;\n // You can add some keys manually telemetry\n \n var gatewayInfoMsg = {\n deviceName: gatewayDeviceNamePrefix + gatewayInfo.gweui,\n deviceType: gatewayDeviceType,\n telemetry: [{\n \"ts\": gatewayInfo.ts,\n \"values\": addGatewayInfo\n }],\n attributes: {\n eui: gatewayInfo.gweui\n }\n };\n addAdditionalInfoForDeviceMsg(gatewayInfoMsg, customerName, gatewayGroupName);\n uplinkDataList.add(gatewayInfoMsg);\n }\n}\n\nreturn uplinkDataList;\n\nfunction addAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName) {\n if (customerName != null) {\n deviceInfo.customerName = customerName;\n }\n if (groupName != null) {\n deviceInfo.groupName = groupName;\n }\n}\n\nfunction processTelemetryData(telemetry, addDataToTelemetry) {\n if (telemetry.size >= 1) {\n telemetry = addDataToTelemetries(telemetry, addDataToTelemetry);\n }\n else {\n telemetry.add(addDataToTelemetry);\n }\n \n return telemetry;\n}\n\nfunction addDataToTelemetries(telemetries, addDataToTelemetry) {\n foreach(telemetry : telemetries) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[\"values\"].keys.contains(element.key)) {\n telemetry[\"values\"][element.key] = element.value;\n }\n } \n }\n \n return telemetries;\n}\n\nfunction setPressState(decoded, type) {\n switch (type) {\n case 1:\n decoded.press = \"short\";\n break;\n case 2:\n decoded.press = \"long\";\n break;\n case 3:\n decoded.press = \"double\";\n break;\n default:\n decoded.press = \"unknown\";\n break;\n }\n}", "encoder": null, "tbelEncoder": null, "updateOnlyKeys": [ diff --git a/VENDORS/Milesight/WS201/LORIOT/uplink/payload_1.json b/VENDORS/Milesight/WS201/LORIOT/uplink/payload_1.json new file mode 100644 index 00000000..59e6877b --- /dev/null +++ b/VENDORS/Milesight/WS201/LORIOT/uplink/payload_1.json @@ -0,0 +1,32 @@ +{ + "cmd": "gw", + "seqno": 4, + "EUI": "0102030405060708", + "ts": 1690901260493, + "fcnt": 3, + "port": 207, + "freq": 868300000, + "toa": 1319, + "dr": "SF12 BW125 4/5", + "ack": false, + "gws": [ + { + "rssi": -38, + "snr": 8.5, + "ts": 1690901260493, + "time": "2023-08-01T14:47:40.493Z", + "gweui": "1020304080706050", + "ant": 0 + }, + { + "rssi": -42, + "snr": 8.8, + "ts": 1690901260495, + "time": "2023-08-01T14:47:40.495Z", + "gweui": "1020304081716151", + "ant": 0 + } + ], + "bat": 143, + "data": "01756403823E0004D645" +} \ No newline at end of file diff --git a/VENDORS/Milesight/WS201/LORIOT/uplink/result_1.json b/VENDORS/Milesight/WS201/LORIOT/uplink/result_1.json new file mode 100644 index 00000000..a7ead7a8 --- /dev/null +++ b/VENDORS/Milesight/WS201/LORIOT/uplink/result_1.json @@ -0,0 +1,43 @@ +[{ + "deviceName": "0102030405060708", + "deviceType": "WS201", + "attributes": { + "eui": "0102030405060708", + "fPort": 207, + "frequency": 868300000 + }, + "telemetry": [{ + "ts": 1690901260493, + "values": { + "battery": 100, + "distance": 62, + "remaining": 69 + } + }] +}, { + "deviceName": "Gateway 1020304080706050", + "deviceType": "Lora gateway", + "telemetry": [{ + "ts": 1690901260493, + "values": { + "rssi": -38, + "snr": 8.5 + } + }], + "attributes": { + "eui": "1020304080706050" + } +}, { + "deviceName": "Gateway 1020304081716151", + "deviceType": "Lora gateway", + "telemetry": [{ + "ts": 1690901260495, + "values": { + "rssi": -42, + "snr": 8.8 + } + }], + "attributes": { + "eui": "1020304081716151" + } +}] \ No newline at end of file diff --git a/VENDORS/Milesight/WS202/LORIOT/uplink/converter.json b/VENDORS/Milesight/WS202/LORIOT/uplink/converter.json index 3b2665cf..a1438681 100644 --- a/VENDORS/Milesight/WS202/LORIOT/uplink/converter.json +++ b/VENDORS/Milesight/WS202/LORIOT/uplink/converter.json @@ -1,11 +1,16 @@ { "name": "Loriot Uplink Decoder for WS202", "type": "UPLINK", - "debugMode": true, + "debugMode": false, + "debugSettings": { + "failuresEnabled": true, + "allEnabled": false, + "allEnabledUntil": 1735213802446 + }, "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);\nvar deviceName = data.EUI;\nvar deviceType = \"WS202\";\nvar groupName = null; // If groupName is not null - created device will be added to the entity group with such name.\nvar customerName = null; // If customerName is not null - created devices will be assigned to customer with such name. \n\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// If you want to parse incoming data somehow, you can add your code to this function.\n// input: bytes\n// expected output:\n// {\n// \"attributes\": {\"attributeKey\": \"attributeValue\"},\n// \"telemetry\": {\"telemetryKey\": \"telemetryValue\"}\n// }\n\nfunction decodePayload(input) {\n var output = { attributes: {}, telemetry: []};\n \n var decoded = {};\n for (var i = 0; i < input.length - 2; ) {\n var channel_id = input[i++] & 0xff;\n var channel_type = input[i++] & 0xff;\n // BATTERY\n if (channel_id === 0x01 && channel_type === 0x75) {\n decoded.battery = input[i];\n i += 1;\n }\n // PIR\n else if (channel_id === 0x03 && channel_type === 0x00) {\n decoded.pir = input[i] === 0 ? \"normal\" : \"trigger\";\n i += 1;\n }\n // DAYLIGHT\n else if (channel_id === 0x04 && channel_type === 0x00) {\n decoded.daylight = input[i] === 0 ? \"dark\" : \"light\";\n i += 1;\n }\n }\n \n \n output.telemetry = [{\n ts: timestamp,\n values: decoded\n }];\n\n // --- Decoding code --- //\n return output;\n}\n\n// --- attributes and telemetry objects ---\nvar telemetry = [];\nvar attributes = {};\n// --- attributes and telemetry objects ---\n\n// --- Timestamp parsing\ntimestamp = data.ts;\n// --- Timestamp parsing\n\n// Message parsing\n// To avoid paths in the decoded objects we passing false value to function as \"pathInKey\" argument.\n// Warning: pathInKey can cause already found fields to be overwritten with the last value found.\n\nvar uplinkDataList = [];\n\n// Passing incoming bytes to decodePayload function, to get custom decoding\nvar customDecoding = decodePayload(hexToBytes(data.data));\n\n// Collecting data to result\nif (customDecoding.?telemetry.size() > 0) {\n if (customDecoding.telemetry instanceof java.util.ArrayList) {\n foreach(telemetryObj: customDecoding.telemetry) {\n if (telemetryObj.ts != null && telemetryObj.values != null) {\n telemetry.add(telemetryObj);\n }\n }\n } else {\n telemetry.putAll(customDecoding.telemetry);\n }\n}\n\nif (customDecoding.?attributes.size() > 0) {\n attributes.putAll(customDecoding.attributes);\n}\n\n// You can add some keys manually to attributes or telemetry\nattributes.eui = data.EUI;\nattributes.fPort = data.port;\nattributes.frequency = data.freq;\n\nvar isIncludeGatewayInfo = metadata[\"includeGatewayInfo\"];\nif(isIncludeGatewayInfo == true) {\n var addDataToTelemetry = {};\n addDataToTelemetry.rssi = data.rssi;\n addDataToTelemetry.seqno = data.seqno;\n addDataToTelemetry.snr = data.snr;\n addDataToTelemetry.ack = data.ack;\n addDataToTelemetry.toa = data.toa;\n addDataToTelemetry.fCnt = data.fcnt;\n \n telemetry = processTelemetryData(telemetry, addDataToTelemetry);\n}\n\nvar deviceInfo = {\n deviceName: deviceName,\n deviceType: deviceType,\n// assetName: assetName,\n// assetType: assetType,\n attributes: attributes,\n telemetry: telemetry, \n};\n\naddAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName);\n\nuplinkDataList.add(deviceInfo);\n\nvar gatewayDeviceNamePrefix = \"Gateway \";\nvar gatewayDeviceType = \"Lora gateway\";\nvar gatewayGroupName = null; // If gatewayGroupName is not null - created device will be added to the entity group with such name.\n\nif (data.cmd == \"gw\") {\n foreach( gatewayInfo : data.gws ) {\n var addGatewayInfo = {};\n\n // You can add some keys manually telemetry\n addGatewayInfo.rssi = gatewayInfo.rssi;\n addGatewayInfo.snr = gatewayInfo.snr;\n // You can add some keys manually telemetry\n \n var gatewayInfoMsg = {\n deviceName: gatewayDeviceNamePrefix + gatewayInfo.gweui,\n deviceType: gatewayDeviceType,\n telemetry: [{\n \"ts\": gatewayInfo.ts,\n \"values\": addGatewayInfo\n }],\n attributes: {\n eui: gatewayInfo.gweui\n }\n };\n addAdditionalInfoForDeviceMsg(gatewayInfoMsg, customerName, gatewayGroupName);\n uplinkDataList.add(gatewayInfoMsg);\n }\n}\n\nreturn uplinkDataList;\n\nfunction addAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName) {\n if (customerName != null) {\n deviceInfo.customerName = customerName;\n }\n if (groupName != null) {\n deviceInfo.groupName = groupName;\n }\n}\n\nfunction processTelemetryData(telemetry, addDataToTelemetry) {\n if (telemetry.size > 1) {\n telemetry = addDataToMultipleTelemetries(telemetry, addDataToTelemetry);\n }\n else if (telemetry.size == 1) {\n telemetry = addDataToSingleTelemetry(telemetry, addDataToTelemetry);\n }\n else {\n telemetry.add(addDataToTelemetry);\n }\n \n return telemetry;\n}\n\nfunction addDataToMultipleTelemetries(telemetry, addDataToTelemetry) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[0][\"values\"].keys.contains(element.key)) {\n telemetry[0][\"values\"][element.key] = element.value;\n }\n if (!telemetry[1][\"values\"].keys.contains(element.key)) {\n telemetry[1][\"values\"][element.key] = element.value;\n }\n }\n \n return telemetry;\n}\n\nfunction addDataToSingleTelemetry(telemetry, addDataToTelemetry) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[0][\"values\"].keys.contains(element.key)) {\n telemetry[0][\"values\"][element.key] = element.value;\n }\n }\n \n return telemetry;\n}\n\nfunction setPressState(decoded, type) {\n switch (type) {\n case 1:\n decoded.press = \"short\";\n break;\n case 2:\n decoded.press = \"long\";\n break;\n case 3:\n decoded.press = \"double\";\n break;\n default:\n decoded.press = \"unknown\";\n break;\n }\n}", + "tbelDecoder": "var data = decodeToJson(payload);\nvar deviceName = data.EUI;\nvar deviceType = \"WS202\";\nvar groupName = null; // If groupName is not null - created device will be added to the entity group with such name.\nvar customerName = null; // If customerName is not null - created devices will be assigned to customer with such name. \n\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// If you want to parse incoming data somehow, you can add your code to this function.\n// input: bytes\n// expected output:\n// {\n// \"attributes\": {\"attributeKey\": \"attributeValue\"},\n// \"telemetry\": {\"telemetryKey\": \"telemetryValue\"}\n// }\n\nfunction decodePayload(input) {\n var output = { attributes: {}, telemetry: []};\n \n var decoded = {};\n for (var i = 0; i < input.length - 2; ) {\n var channel_id = input[i++] & 0xff;\n var channel_type = input[i++] & 0xff;\n // BATTERY\n if (channel_id === 0x01 && channel_type === 0x75) {\n decoded.battery = input[i];\n i += 1;\n }\n // PIR\n else if (channel_id === 0x03 && channel_type === 0x00) {\n decoded.pir = input[i] === 0 ? \"normal\" : \"trigger\";\n i += 1;\n }\n // DAYLIGHT\n else if (channel_id === 0x04 && channel_type === 0x00) {\n decoded.daylight = input[i] === 0 ? \"dark\" : \"light\";\n i += 1;\n }\n }\n \n \n output.telemetry = [{\n ts: timestamp,\n values: decoded\n }];\n\n // --- Decoding code --- //\n return output;\n}\n\n// --- attributes and telemetry objects ---\nvar telemetry = [];\nvar attributes = {};\n// --- attributes and telemetry objects ---\n\n// --- Timestamp parsing\ntimestamp = data.ts;\n// --- Timestamp parsing\n\n// Message parsing\n// To avoid paths in the decoded objects we passing false value to function as \"pathInKey\" argument.\n// Warning: pathInKey can cause already found fields to be overwritten with the last value found.\n\nvar uplinkDataList = [];\n\n// Passing incoming bytes to decodePayload function, to get custom decoding\nvar customDecoding = decodePayload(hexToBytes(data.data));\n\n// Collecting data to result\nif (customDecoding.?telemetry.size() > 0) {\n if (customDecoding.telemetry instanceof java.util.ArrayList) {\n foreach(telemetryObj: customDecoding.telemetry) {\n if (telemetryObj.ts != null && telemetryObj.values != null) {\n telemetry.add(telemetryObj);\n }\n }\n } else {\n telemetry.putAll(customDecoding.telemetry);\n }\n}\n\nif (customDecoding.?attributes.size() > 0) {\n attributes.putAll(customDecoding.attributes);\n}\n\n// You can add some keys manually to attributes or telemetry\nattributes.eui = data.EUI;\nattributes.fPort = data.port;\nattributes.frequency = data.freq;\n\nvar isIncludeGatewayInfo = metadata[\"includeGatewayInfo\"];\nif(isIncludeGatewayInfo == true) {\n var addDataToTelemetry = {};\n addDataToTelemetry.rssi = data.rssi;\n addDataToTelemetry.seqno = data.seqno;\n addDataToTelemetry.snr = data.snr;\n addDataToTelemetry.ack = data.ack;\n addDataToTelemetry.toa = data.toa;\n addDataToTelemetry.fCnt = data.fcnt;\n \n telemetry = processTelemetryData(telemetry, addDataToTelemetry);\n}\n\nvar deviceInfo = {\n deviceName: deviceName,\n deviceType: deviceType,\n// assetName: assetName,\n// assetType: assetType,\n attributes: attributes,\n telemetry: telemetry, \n};\n\naddAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName);\n\nuplinkDataList.add(deviceInfo);\n\nvar gatewayDeviceNamePrefix = \"Gateway \";\nvar gatewayDeviceType = \"Lora gateway\";\nvar gatewayGroupName = null; // If gatewayGroupName is not null - created device will be added to the entity group with such name.\n\nif (data.cmd == \"gw\") {\n foreach( gatewayInfo : data.gws ) {\n var addGatewayInfo = {};\n\n // You can add some keys manually telemetry\n addGatewayInfo.rssi = gatewayInfo.rssi;\n addGatewayInfo.snr = gatewayInfo.snr;\n // You can add some keys manually telemetry\n \n var gatewayInfoMsg = {\n deviceName: gatewayDeviceNamePrefix + gatewayInfo.gweui,\n deviceType: gatewayDeviceType,\n telemetry: [{\n \"ts\": gatewayInfo.ts,\n \"values\": addGatewayInfo\n }],\n attributes: {\n eui: gatewayInfo.gweui\n }\n };\n addAdditionalInfoForDeviceMsg(gatewayInfoMsg, customerName, gatewayGroupName);\n uplinkDataList.add(gatewayInfoMsg);\n }\n}\n\nreturn uplinkDataList;\n\nfunction addAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName) {\n if (customerName != null) {\n deviceInfo.customerName = customerName;\n }\n if (groupName != null) {\n deviceInfo.groupName = groupName;\n }\n}\n\nfunction processTelemetryData(telemetry, addDataToTelemetry) {\n if (telemetry.size >= 1) {\n telemetry = addDataToTelemetries(telemetry, addDataToTelemetry);\n }\n else {\n telemetry.add(addDataToTelemetry);\n }\n \n return telemetry;\n}\n\nfunction addDataToTelemetries(telemetries, addDataToTelemetry) {\n foreach(telemetry : telemetries) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[\"values\"].keys.contains(element.key)) {\n telemetry[\"values\"][element.key] = element.value;\n }\n } \n }\n \n return telemetries;\n}\n\nfunction setPressState(decoded, type) {\n switch (type) {\n case 1:\n decoded.press = \"short\";\n break;\n case 2:\n decoded.press = \"long\";\n break;\n case 3:\n decoded.press = \"double\";\n break;\n default:\n decoded.press = \"unknown\";\n break;\n }\n}", "encoder": null, "tbelEncoder": null, "updateOnlyKeys": [ diff --git a/VENDORS/Milesight/WS202/LORIOT/uplink/payload_1.json b/VENDORS/Milesight/WS202/LORIOT/uplink/payload_1.json new file mode 100644 index 00000000..91564ce7 --- /dev/null +++ b/VENDORS/Milesight/WS202/LORIOT/uplink/payload_1.json @@ -0,0 +1,32 @@ +{ + "cmd": "gw", + "seqno": 4, + "EUI": "0102030405060708", + "ts": 1690901260493, + "fcnt": 3, + "port": 207, + "freq": 868300000, + "toa": 1319, + "dr": "SF12 BW125 4/5", + "ack": false, + "gws": [ + { + "rssi": -38, + "snr": 8.5, + "ts": 1690901260493, + "time": "2023-08-01T14:47:40.493Z", + "gweui": "1020304080706050", + "ant": 0 + }, + { + "rssi": -42, + "snr": 8.8, + "ts": 1690901260495, + "time": "2023-08-01T14:47:40.495Z", + "gweui": "1020304081716151", + "ant": 0 + } + ], + "bat": 143, + "data": "017510030001040000" +} \ No newline at end of file diff --git a/VENDORS/Milesight/WS202/LORIOT/uplink/result_1.json b/VENDORS/Milesight/WS202/LORIOT/uplink/result_1.json new file mode 100644 index 00000000..d1573ad4 --- /dev/null +++ b/VENDORS/Milesight/WS202/LORIOT/uplink/result_1.json @@ -0,0 +1,43 @@ +[{ + "deviceName": "0102030405060708", + "deviceType": "WS202", + "attributes": { + "eui": "0102030405060708", + "fPort": 207, + "frequency": 868300000 + }, + "telemetry": [{ + "ts": 1690901260493, + "values": { + "battery": 16, + "pir": "trigger", + "daylight": "dark" + } + }] +}, { + "deviceName": "Gateway 1020304080706050", + "deviceType": "Lora gateway", + "telemetry": [{ + "ts": 1690901260493, + "values": { + "rssi": -38, + "snr": 8.5 + } + }], + "attributes": { + "eui": "1020304080706050" + } +}, { + "deviceName": "Gateway 1020304081716151", + "deviceType": "Lora gateway", + "telemetry": [{ + "ts": 1690901260495, + "values": { + "rssi": -42, + "snr": 8.8 + } + }], + "attributes": { + "eui": "1020304081716151" + } +}] \ No newline at end of file diff --git a/VENDORS/Milesight/WS301/LORIOT/uplink/converter.json b/VENDORS/Milesight/WS301/LORIOT/uplink/converter.json index e1567fcf..69ab1869 100644 --- a/VENDORS/Milesight/WS301/LORIOT/uplink/converter.json +++ b/VENDORS/Milesight/WS301/LORIOT/uplink/converter.json @@ -1,11 +1,16 @@ { "name": "Loriot Uplink Decoder for WS301", "type": "UPLINK", - "debugMode": true, + "debugMode": false, + "debugSettings": { + "failuresEnabled": true, + "allEnabled": false, + "allEnabledUntil": 1735214015703 + }, "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);\nvar deviceName = data.EUI;\nvar deviceType = \"WS301\";\nvar groupName = null; // If groupName is not null - created device will be added to the entity group with such name.\nvar customerName = null; // If customerName is not null - created devices will be assigned to customer with such name. \n\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// If you want to parse incoming data somehow, you can add your code to this function.\n// input: bytes\n// expected output:\n// {\n// \"attributes\": {\"attributeKey\": \"attributeValue\"},\n// \"telemetry\": {\"telemetryKey\": \"telemetryValue\"}\n// }\n\nfunction decodePayload(input) {\n var output = { attributes: {}, telemetry: []};\n \n var decoded = {};\n for (var i = 0; i < input.length - 2; ) {\n var channel_id = input[i++] & 0xff;\n var channel_type = input[i++] & 0xff;\n\n // BATTERY\n if (channel_id === 0x01 && channel_type === 0x75) {\n decoded.battery = input[i];\n i += 1;\n }\n // DOOR / WINDOW STATE (0: close 1: open)\n else if (channel_id === 0x03 && channel_type === 0x00) {\n decoded.magnet_status = input[i] === 0 ? \"close\" : \"open\";\n i += 1;\n }\n // INSTALL STATE (0: install 1: uninstall)\n else if (channel_id === 0x04 && channel_type === 0x00) {\n decoded.tamper_status = input[i] === 0 ? \"installed\" : \"uninstalled\";\n i += 1;\n }\n }\n \n output.telemetry = [{\n ts: timestamp,\n values: decoded\n }];\n\n // --- Decoding code --- //\n return output;\n}\n\n// --- attributes and telemetry objects ---\nvar telemetry = [];\nvar attributes = {};\n// --- attributes and telemetry objects ---\n\n// --- Timestamp parsing\ntimestamp = data.ts;\n// --- Timestamp parsing\n\n// Message parsing\n// To avoid paths in the decoded objects we passing false value to function as \"pathInKey\" argument.\n// Warning: pathInKey can cause already found fields to be overwritten with the last value found.\n\nvar uplinkDataList = [];\n\n// Passing incoming bytes to decodePayload function, to get custom decoding\nvar customDecoding = decodePayload(hexToBytes(data.data));\n\n// Collecting data to result\nif (customDecoding.?telemetry.size() > 0) {\n if (customDecoding.telemetry instanceof java.util.ArrayList) {\n foreach(telemetryObj: customDecoding.telemetry) {\n if (telemetryObj.ts != null && telemetryObj.values != null) {\n telemetry.add(telemetryObj);\n }\n }\n } else {\n telemetry.putAll(customDecoding.telemetry);\n }\n}\n\nif (customDecoding.?attributes.size() > 0) {\n attributes.putAll(customDecoding.attributes);\n}\n\n// You can add some keys manually to attributes or telemetry\nattributes.eui = data.EUI;\nattributes.fPort = data.port;\nattributes.frequency = data.freq;\n\nvar isIncludeGatewayInfo = metadata[\"includeGatewayInfo\"];\nif(isIncludeGatewayInfo == true) {\n var addDataToTelemetry = {};\n addDataToTelemetry.rssi = data.rssi;\n addDataToTelemetry.seqno = data.seqno;\n addDataToTelemetry.snr = data.snr;\n addDataToTelemetry.ack = data.ack;\n addDataToTelemetry.toa = data.toa;\n addDataToTelemetry.fCnt = data.fcnt;\n \n telemetry = processTelemetryData(telemetry, addDataToTelemetry);\n}\n\nvar deviceInfo = {\n deviceName: deviceName,\n deviceType: deviceType,\n// assetName: assetName,\n// assetType: assetType,\n attributes: attributes,\n telemetry: telemetry, \n};\n\naddAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName);\n\nuplinkDataList.add(deviceInfo);\n\nvar gatewayDeviceNamePrefix = \"Gateway \";\nvar gatewayDeviceType = \"Lora gateway\";\nvar gatewayGroupName = null; // If gatewayGroupName is not null - created device will be added to the entity group with such name.\n\nif (data.cmd == \"gw\") {\n foreach( gatewayInfo : data.gws ) {\n var addGatewayInfo = {};\n\n // You can add some keys manually telemetry\n addGatewayInfo.rssi = gatewayInfo.rssi;\n addGatewayInfo.snr = gatewayInfo.snr;\n // You can add some keys manually telemetry\n \n var gatewayInfoMsg = {\n deviceName: gatewayDeviceNamePrefix + gatewayInfo.gweui,\n deviceType: gatewayDeviceType,\n telemetry: [{\n \"ts\": gatewayInfo.ts,\n \"values\": addGatewayInfo\n }],\n attributes: {\n eui: gatewayInfo.gweui\n }\n };\n addAdditionalInfoForDeviceMsg(gatewayInfoMsg, customerName, gatewayGroupName);\n uplinkDataList.add(gatewayInfoMsg);\n }\n}\n\nreturn uplinkDataList;\n\nfunction addAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName) {\n if (customerName != null) {\n deviceInfo.customerName = customerName;\n }\n if (groupName != null) {\n deviceInfo.groupName = groupName;\n }\n}\n\nfunction processTelemetryData(telemetry, addDataToTelemetry) {\n if (telemetry.size > 1) {\n telemetry = addDataToMultipleTelemetries(telemetry, addDataToTelemetry);\n }\n else if (telemetry.size == 1) {\n telemetry = addDataToSingleTelemetry(telemetry, addDataToTelemetry);\n }\n else {\n telemetry.add(addDataToTelemetry);\n }\n \n return telemetry;\n}\n\nfunction addDataToMultipleTelemetries(telemetry, addDataToTelemetry) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[0][\"values\"].keys.contains(element.key)) {\n telemetry[0][\"values\"][element.key] = element.value;\n }\n if (!telemetry[1][\"values\"].keys.contains(element.key)) {\n telemetry[1][\"values\"][element.key] = element.value;\n }\n }\n \n return telemetry;\n}\n\nfunction addDataToSingleTelemetry(telemetry, addDataToTelemetry) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[0][\"values\"].keys.contains(element.key)) {\n telemetry[0][\"values\"][element.key] = element.value;\n }\n }\n \n return telemetry;\n}\n\nfunction setPressState(decoded, type) {\n switch (type) {\n case 1:\n decoded.press = \"short\";\n break;\n case 2:\n decoded.press = \"long\";\n break;\n case 3:\n decoded.press = \"double\";\n break;\n default:\n decoded.press = \"unknown\";\n break;\n }\n}", + "tbelDecoder": "var data = decodeToJson(payload);\nvar deviceName = data.EUI;\nvar deviceType = \"WS301\";\nvar groupName = null; // If groupName is not null - created device will be added to the entity group with such name.\nvar customerName = null; // If customerName is not null - created devices will be assigned to customer with such name. \n\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// If you want to parse incoming data somehow, you can add your code to this function.\n// input: bytes\n// expected output:\n// {\n// \"attributes\": {\"attributeKey\": \"attributeValue\"},\n// \"telemetry\": {\"telemetryKey\": \"telemetryValue\"}\n// }\n\nfunction decodePayload(input) {\n var output = { attributes: {}, telemetry: []};\n \n var decoded = {};\n for (var i = 0; i < input.length - 2; ) {\n var channel_id = input[i++] & 0xff;\n var channel_type = input[i++] & 0xff;\n\n // BATTERY\n if (channel_id === 0x01 && channel_type === 0x75) {\n decoded.battery = input[i];\n i += 1;\n }\n // DOOR / WINDOW STATE (0: close 1: open)\n else if (channel_id === 0x03 && channel_type === 0x00) {\n decoded.magnet_status = input[i] === 0 ? \"close\" : \"open\";\n i += 1;\n }\n // INSTALL STATE (0: install 1: uninstall)\n else if (channel_id === 0x04 && channel_type === 0x00) {\n decoded.tamper_status = input[i] === 0 ? \"installed\" : \"uninstalled\";\n i += 1;\n }\n }\n \n output.telemetry = [{\n ts: timestamp,\n values: decoded\n }];\n\n // --- Decoding code --- //\n return output;\n}\n\n// --- attributes and telemetry objects ---\nvar telemetry = [];\nvar attributes = {};\n// --- attributes and telemetry objects ---\n\n// --- Timestamp parsing\ntimestamp = data.ts;\n// --- Timestamp parsing\n\n// Message parsing\n// To avoid paths in the decoded objects we passing false value to function as \"pathInKey\" argument.\n// Warning: pathInKey can cause already found fields to be overwritten with the last value found.\n\nvar uplinkDataList = [];\n\n// Passing incoming bytes to decodePayload function, to get custom decoding\nvar customDecoding = decodePayload(hexToBytes(data.data));\n\n// Collecting data to result\nif (customDecoding.?telemetry.size() > 0) {\n if (customDecoding.telemetry instanceof java.util.ArrayList) {\n foreach(telemetryObj: customDecoding.telemetry) {\n if (telemetryObj.ts != null && telemetryObj.values != null) {\n telemetry.add(telemetryObj);\n }\n }\n } else {\n telemetry.putAll(customDecoding.telemetry);\n }\n}\n\nif (customDecoding.?attributes.size() > 0) {\n attributes.putAll(customDecoding.attributes);\n}\n\n// You can add some keys manually to attributes or telemetry\nattributes.eui = data.EUI;\nattributes.fPort = data.port;\nattributes.frequency = data.freq;\n\nvar isIncludeGatewayInfo = metadata[\"includeGatewayInfo\"];\nif(isIncludeGatewayInfo == true) {\n var addDataToTelemetry = {};\n addDataToTelemetry.rssi = data.rssi;\n addDataToTelemetry.seqno = data.seqno;\n addDataToTelemetry.snr = data.snr;\n addDataToTelemetry.ack = data.ack;\n addDataToTelemetry.toa = data.toa;\n addDataToTelemetry.fCnt = data.fcnt;\n \n telemetry = processTelemetryData(telemetry, addDataToTelemetry);\n}\n\nvar deviceInfo = {\n deviceName: deviceName,\n deviceType: deviceType,\n// assetName: assetName,\n// assetType: assetType,\n attributes: attributes,\n telemetry: telemetry, \n};\n\naddAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName);\n\nuplinkDataList.add(deviceInfo);\n\nvar gatewayDeviceNamePrefix = \"Gateway \";\nvar gatewayDeviceType = \"Lora gateway\";\nvar gatewayGroupName = null; // If gatewayGroupName is not null - created device will be added to the entity group with such name.\n\nif (data.cmd == \"gw\") {\n foreach( gatewayInfo : data.gws ) {\n var addGatewayInfo = {};\n\n // You can add some keys manually telemetry\n addGatewayInfo.rssi = gatewayInfo.rssi;\n addGatewayInfo.snr = gatewayInfo.snr;\n // You can add some keys manually telemetry\n \n var gatewayInfoMsg = {\n deviceName: gatewayDeviceNamePrefix + gatewayInfo.gweui,\n deviceType: gatewayDeviceType,\n telemetry: [{\n \"ts\": gatewayInfo.ts,\n \"values\": addGatewayInfo\n }],\n attributes: {\n eui: gatewayInfo.gweui\n }\n };\n addAdditionalInfoForDeviceMsg(gatewayInfoMsg, customerName, gatewayGroupName);\n uplinkDataList.add(gatewayInfoMsg);\n }\n}\n\nreturn uplinkDataList;\n\nfunction addAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName) {\n if (customerName != null) {\n deviceInfo.customerName = customerName;\n }\n if (groupName != null) {\n deviceInfo.groupName = groupName;\n }\n}\n\nfunction processTelemetryData(telemetry, addDataToTelemetry) {\n if (telemetry.size >= 1) {\n telemetry = addDataToTelemetries(telemetry, addDataToTelemetry);\n }\n else {\n telemetry.add(addDataToTelemetry);\n }\n \n return telemetry;\n}\n\nfunction addDataToTelemetries(telemetries, addDataToTelemetry) {\n foreach(telemetry : telemetries) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[\"values\"].keys.contains(element.key)) {\n telemetry[\"values\"][element.key] = element.value;\n }\n } \n }\n \n return telemetries;\n}\n\nfunction setPressState(decoded, type) {\n switch (type) {\n case 1:\n decoded.press = \"short\";\n break;\n case 2:\n decoded.press = \"long\";\n break;\n case 3:\n decoded.press = \"double\";\n break;\n default:\n decoded.press = \"unknown\";\n break;\n }\n}", "encoder": null, "tbelEncoder": null, "updateOnlyKeys": [ diff --git a/VENDORS/Milesight/WS301/LORIOT/uplink/payload_1.json b/VENDORS/Milesight/WS301/LORIOT/uplink/payload_1.json new file mode 100644 index 00000000..8969d29f --- /dev/null +++ b/VENDORS/Milesight/WS301/LORIOT/uplink/payload_1.json @@ -0,0 +1,32 @@ +{ + "cmd": "gw", + "seqno": 4, + "EUI": "0102030405060708", + "ts": 1690901260493, + "fcnt": 3, + "port": 207, + "freq": 868300000, + "toa": 1319, + "dr": "SF12 BW125 4/5", + "ack": false, + "gws": [ + { + "rssi": -38, + "snr": 8.5, + "ts": 1690901260493, + "time": "2023-08-01T14:47:40.493Z", + "gweui": "1020304080706050", + "ant": 0 + }, + { + "rssi": -42, + "snr": 8.8, + "ts": 1690901260495, + "time": "2023-08-01T14:47:40.495Z", + "gweui": "1020304081716151", + "ant": 0 + } + ], + "bat": 143, + "data": "017564030001040001" +} \ No newline at end of file diff --git a/VENDORS/Milesight/WS301/LORIOT/uplink/result_1.json b/VENDORS/Milesight/WS301/LORIOT/uplink/result_1.json new file mode 100644 index 00000000..61bde284 --- /dev/null +++ b/VENDORS/Milesight/WS301/LORIOT/uplink/result_1.json @@ -0,0 +1,43 @@ +[{ + "deviceName": "0102030405060708", + "deviceType": "WS301", + "attributes": { + "eui": "0102030405060708", + "fPort": 207, + "frequency": 868300000 + }, + "telemetry": [{ + "ts": 1690901260493, + "values": { + "battery": 100, + "magnet_status": "open", + "tamper_status": "uninstalled" + } + }] +}, { + "deviceName": "Gateway 1020304080706050", + "deviceType": "Lora gateway", + "telemetry": [{ + "ts": 1690901260493, + "values": { + "rssi": -38, + "snr": 8.5 + } + }], + "attributes": { + "eui": "1020304080706050" + } +}, { + "deviceName": "Gateway 1020304081716151", + "deviceType": "Lora gateway", + "telemetry": [{ + "ts": 1690901260495, + "values": { + "rssi": -42, + "snr": 8.8 + } + }], + "attributes": { + "eui": "1020304081716151" + } +}] \ No newline at end of file diff --git a/VENDORS/Milesight/WS302/LORIOT/uplink/converter.json b/VENDORS/Milesight/WS302/LORIOT/uplink/converter.json index 9cb5591a..f212f6b3 100644 --- a/VENDORS/Milesight/WS302/LORIOT/uplink/converter.json +++ b/VENDORS/Milesight/WS302/LORIOT/uplink/converter.json @@ -1,11 +1,16 @@ { "name": "Loriot Uplink Decoder for WS302", "type": "UPLINK", - "debugMode": true, + "debugMode": false, + "debugSettings": { + "failuresEnabled": true, + "allEnabled": false, + "allEnabledUntil": 1735214125805 + }, "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);\nvar deviceName = data.EUI;\nvar deviceType = \"WS302\";\nvar groupName = null; // If groupName is not null - created device will be added to the entity group with such name.\nvar customerName = null; // If customerName is not null - created devices will be assigned to customer with such name. \n\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// If you want to parse incoming data somehow, you can add your code to this function.\n// input: bytes\n// expected output:\n// {\n// \"attributes\": {\"attributeKey\": \"attributeValue\"},\n// \"telemetry\": {\"telemetryKey\": \"telemetryValue\"}\n// }\n\nfunction decodePayload(input) {\n var output = { attributes: {}, telemetry: []};\n \n var decoded = {};\n for (var i = 0; i < input.length - 2; ) {\n var channel_id = input[i++] & 0xff;\n var channel_type = input[i++] & 0xff;\n\n // BATTERY\n if (channel_id === 0x01 && channel_type === 0x75) {\n decoded.battery = input[i];\n i += 1;\n }\n // SOUND\n else if (channel_id === 0x05 && channel_type === 0x5b) {\n var weight = input[i];\n var freq_weight = readFrequencyWeightType(weight & 0x03);\n var time_weight = readTimeWeightType((weight >> 2) & 0x03);\n\n var sound_level_name = \"L\" + freq_weight + time_weight;\n var sound_level_eq_name = \"L\" + freq_weight + \"eq\";\n var sound_level_max_name = \"L\" + freq_weight + time_weight + \"max\";\n decoded[sound_level_name] = parseBytesToInt(input, i + 1, 2, false) / 10;\n decoded[sound_level_eq_name] = parseBytesToInt(input, i + 3, 2, false) / 10;\n decoded[sound_level_max_name] = parseBytesToInt(input, i + 5, 2, false) / 10;\n i += 7;\n }\n // LoRaWAN Class Type\n else if (channel_id === 0xff && channel_type === 0x0f) {\n decoded.lorawan_class = readLoRaWANClass(input[i]);\n i += 1;\n }\n }\n \n output.telemetry = [{\n ts: timestamp,\n values: decoded\n }];\n\n // --- Decoding code --- //\n return output;\n}\n\n// --- attributes and telemetry objects ---\nvar telemetry = [];\nvar attributes = {};\n// --- attributes and telemetry objects ---\n\n// --- Timestamp parsing\ntimestamp = data.ts;\n// --- Timestamp parsing\n\n// Message parsing\n// To avoid paths in the decoded objects we passing false value to function as \"pathInKey\" argument.\n// Warning: pathInKey can cause already found fields to be overwritten with the last value found.\n\nvar uplinkDataList = [];\n\n// Passing incoming bytes to decodePayload function, to get custom decoding\nvar customDecoding = decodePayload(hexToBytes(data.data));\n\n// Collecting data to result\nif (customDecoding.?telemetry.size() > 0) {\n if (customDecoding.telemetry instanceof java.util.ArrayList) {\n foreach(telemetryObj: customDecoding.telemetry) {\n if (telemetryObj.ts != null && telemetryObj.values != null) {\n telemetry.add(telemetryObj);\n }\n }\n } else {\n telemetry.putAll(customDecoding.telemetry);\n }\n}\n\nif (customDecoding.?attributes.size() > 0) {\n attributes.putAll(customDecoding.attributes);\n}\n\n// You can add some keys manually to attributes or telemetry\nattributes.eui = data.EUI;\nattributes.fPort = data.port;\nattributes.frequency = data.freq;\n\nvar isIncludeGatewayInfo = metadata[\"includeGatewayInfo\"];\nif(isIncludeGatewayInfo == true) {\n var addDataToTelemetry = {};\n addDataToTelemetry.rssi = data.rssi;\n addDataToTelemetry.seqno = data.seqno;\n addDataToTelemetry.snr = data.snr;\n addDataToTelemetry.ack = data.ack;\n addDataToTelemetry.toa = data.toa;\n addDataToTelemetry.fCnt = data.fcnt;\n \n telemetry = processTelemetryData(telemetry, addDataToTelemetry);\n}\n\nvar deviceInfo = {\n deviceName: deviceName,\n deviceType: deviceType,\n// assetName: assetName,\n// assetType: assetType,\n attributes: attributes,\n telemetry: telemetry, \n};\n\naddAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName);\n\nuplinkDataList.add(deviceInfo);\n\nvar gatewayDeviceNamePrefix = \"Gateway \";\nvar gatewayDeviceType = \"Lora gateway\";\nvar gatewayGroupName = null; // If gatewayGroupName is not null - created device will be added to the entity group with such name.\n\nif (data.cmd == \"gw\") {\n foreach( gatewayInfo : data.gws ) {\n var addGatewayInfo = {};\n\n // You can add some keys manually telemetry\n addGatewayInfo.rssi = gatewayInfo.rssi;\n addGatewayInfo.snr = gatewayInfo.snr;\n // You can add some keys manually telemetry\n \n var gatewayInfoMsg = {\n deviceName: gatewayDeviceNamePrefix + gatewayInfo.gweui,\n deviceType: gatewayDeviceType,\n telemetry: [{\n \"ts\": gatewayInfo.ts,\n \"values\": addGatewayInfo\n }],\n attributes: {\n eui: gatewayInfo.gweui\n }\n };\n addAdditionalInfoForDeviceMsg(gatewayInfoMsg, customerName, gatewayGroupName);\n uplinkDataList.add(gatewayInfoMsg);\n }\n}\n\nreturn uplinkDataList;\n\nfunction addAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName) {\n if (customerName != null) {\n deviceInfo.customerName = customerName;\n }\n if (groupName != null) {\n deviceInfo.groupName = groupName;\n }\n}\n\nfunction processTelemetryData(telemetry, addDataToTelemetry) {\n if (telemetry.size > 1) {\n telemetry = addDataToMultipleTelemetries(telemetry, addDataToTelemetry);\n }\n else if (telemetry.size == 1) {\n telemetry = addDataToSingleTelemetry(telemetry, addDataToTelemetry);\n }\n else {\n telemetry.add(addDataToTelemetry);\n }\n \n return telemetry;\n}\n\nfunction addDataToMultipleTelemetries(telemetry, addDataToTelemetry) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[0][\"values\"].keys.contains(element.key)) {\n telemetry[0][\"values\"][element.key] = element.value;\n }\n if (!telemetry[1][\"values\"].keys.contains(element.key)) {\n telemetry[1][\"values\"][element.key] = element.value;\n }\n }\n \n return telemetry;\n}\n\nfunction addDataToSingleTelemetry(telemetry, addDataToTelemetry) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[0][\"values\"].keys.contains(element.key)) {\n telemetry[0][\"values\"][element.key] = element.value;\n }\n }\n \n return telemetry;\n}\n\nfunction readFrequencyWeightType(type) {\n switch (type) {\n case 0:\n return \"Z\";\n case 1:\n return \"A\";\n case 2:\n return \"C\";\n }\n}\n\nfunction readTimeWeightType(type) {\n switch (type) {\n case 0: // impulse time weighting\n return \"I\";\n case 1: // fast time weighting\n return \"F\";\n case 2: // slow time weighting\n return \"S\";\n }\n}\n\nfunction readLoRaWANClass(type) {\n switch (type) {\n case 0:\n return \"ClassA\";\n case 1:\n return \"ClassB\";\n case 2:\n return \"ClassC\";\n case 3:\n return \"ClassCtoB\";\n }\n}", + "tbelDecoder": "var data = decodeToJson(payload);\nvar deviceName = data.EUI;\nvar deviceType = \"WS302\";\nvar groupName = null; // If groupName is not null - created device will be added to the entity group with such name.\nvar customerName = null; // If customerName is not null - created devices will be assigned to customer with such name. \n\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// If you want to parse incoming data somehow, you can add your code to this function.\n// input: bytes\n// expected output:\n// {\n// \"attributes\": {\"attributeKey\": \"attributeValue\"},\n// \"telemetry\": {\"telemetryKey\": \"telemetryValue\"}\n// }\n\nfunction decodePayload(input) {\n var output = { attributes: {}, telemetry: []};\n \n var decoded = {};\n for (var i = 0; i < input.length - 2; ) {\n var channel_id = input[i++] & 0xff;\n var channel_type = input[i++] & 0xff;\n\n // BATTERY\n if (channel_id === 0x01 && channel_type === 0x75) {\n decoded.battery = input[i];\n i += 1;\n }\n // SOUND\n else if (channel_id === 0x05 && channel_type === 0x5b) {\n var weight = input[i];\n var freq_weight = readFrequencyWeightType(weight & 0x03);\n var time_weight = readTimeWeightType((weight >> 2) & 0x03);\n\n var sound_level_name = \"L\" + freq_weight + time_weight;\n var sound_level_eq_name = \"L\" + freq_weight + \"eq\";\n var sound_level_max_name = \"L\" + freq_weight + time_weight + \"max\";\n decoded[sound_level_name] = parseBytesToInt(input, i + 1, 2, false) / 10;\n decoded[sound_level_eq_name] = parseBytesToInt(input, i + 3, 2, false) / 10;\n decoded[sound_level_max_name] = parseBytesToInt(input, i + 5, 2, false) / 10;\n i += 7;\n }\n // LoRaWAN Class Type\n else if (channel_id === 0xff && channel_type === 0x0f) {\n decoded.lorawan_class = readLoRaWANClass(input[i]);\n i += 1;\n }\n }\n \n output.telemetry = [{\n ts: timestamp,\n values: decoded\n }];\n\n // --- Decoding code --- //\n return output;\n}\n\n// --- attributes and telemetry objects ---\nvar telemetry = [];\nvar attributes = {};\n// --- attributes and telemetry objects ---\n\n// --- Timestamp parsing\ntimestamp = data.ts;\n// --- Timestamp parsing\n\n// Message parsing\n// To avoid paths in the decoded objects we passing false value to function as \"pathInKey\" argument.\n// Warning: pathInKey can cause already found fields to be overwritten with the last value found.\n\nvar uplinkDataList = [];\n\n// Passing incoming bytes to decodePayload function, to get custom decoding\nvar customDecoding = decodePayload(hexToBytes(data.data));\n\n// Collecting data to result\nif (customDecoding.?telemetry.size() > 0) {\n if (customDecoding.telemetry instanceof java.util.ArrayList) {\n foreach(telemetryObj: customDecoding.telemetry) {\n if (telemetryObj.ts != null && telemetryObj.values != null) {\n telemetry.add(telemetryObj);\n }\n }\n } else {\n telemetry.putAll(customDecoding.telemetry);\n }\n}\n\nif (customDecoding.?attributes.size() > 0) {\n attributes.putAll(customDecoding.attributes);\n}\n\n// You can add some keys manually to attributes or telemetry\nattributes.eui = data.EUI;\nattributes.fPort = data.port;\nattributes.frequency = data.freq;\n\nvar isIncludeGatewayInfo = metadata[\"includeGatewayInfo\"];\nif(isIncludeGatewayInfo == true) {\n var addDataToTelemetry = {};\n addDataToTelemetry.rssi = data.rssi;\n addDataToTelemetry.seqno = data.seqno;\n addDataToTelemetry.snr = data.snr;\n addDataToTelemetry.ack = data.ack;\n addDataToTelemetry.toa = data.toa;\n addDataToTelemetry.fCnt = data.fcnt;\n \n telemetry = processTelemetryData(telemetry, addDataToTelemetry);\n}\n\nvar deviceInfo = {\n deviceName: deviceName,\n deviceType: deviceType,\n// assetName: assetName,\n// assetType: assetType,\n attributes: attributes,\n telemetry: telemetry, \n};\n\naddAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName);\n\nuplinkDataList.add(deviceInfo);\n\nvar gatewayDeviceNamePrefix = \"Gateway \";\nvar gatewayDeviceType = \"Lora gateway\";\nvar gatewayGroupName = null; // If gatewayGroupName is not null - created device will be added to the entity group with such name.\n\nif (data.cmd == \"gw\") {\n foreach( gatewayInfo : data.gws ) {\n var addGatewayInfo = {};\n\n // You can add some keys manually telemetry\n addGatewayInfo.rssi = gatewayInfo.rssi;\n addGatewayInfo.snr = gatewayInfo.snr;\n // You can add some keys manually telemetry\n \n var gatewayInfoMsg = {\n deviceName: gatewayDeviceNamePrefix + gatewayInfo.gweui,\n deviceType: gatewayDeviceType,\n telemetry: [{\n \"ts\": gatewayInfo.ts,\n \"values\": addGatewayInfo\n }],\n attributes: {\n eui: gatewayInfo.gweui\n }\n };\n addAdditionalInfoForDeviceMsg(gatewayInfoMsg, customerName, gatewayGroupName);\n uplinkDataList.add(gatewayInfoMsg);\n }\n}\n\nreturn uplinkDataList;\n\nfunction addAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName) {\n if (customerName != null) {\n deviceInfo.customerName = customerName;\n }\n if (groupName != null) {\n deviceInfo.groupName = groupName;\n }\n}\n\nfunction processTelemetryData(telemetry, addDataToTelemetry) {\n if (telemetry.size >= 1) {\n telemetry = addDataToTelemetries(telemetry, addDataToTelemetry);\n }\n else {\n telemetry.add(addDataToTelemetry);\n }\n \n return telemetry;\n}\n\nfunction addDataToTelemetries(telemetries, addDataToTelemetry) {\n foreach(telemetry : telemetries) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[\"values\"].keys.contains(element.key)) {\n telemetry[\"values\"][element.key] = element.value;\n }\n } \n }\n \n return telemetries;\n}\n\nfunction readFrequencyWeightType(type) {\n switch (type) {\n case 0:\n return \"Z\";\n case 1:\n return \"A\";\n case 2:\n return \"C\";\n }\n}\n\nfunction readTimeWeightType(type) {\n switch (type) {\n case 0: // impulse time weighting\n return \"I\";\n case 1: // fast time weighting\n return \"F\";\n case 2: // slow time weighting\n return \"S\";\n }\n}\n\nfunction readLoRaWANClass(type) {\n switch (type) {\n case 0:\n return \"ClassA\";\n case 1:\n return \"ClassB\";\n case 2:\n return \"ClassC\";\n case 3:\n return \"ClassCtoB\";\n }\n}", "encoder": null, "tbelEncoder": null, "updateOnlyKeys": [ diff --git a/VENDORS/Milesight/WS302/LORIOT/uplink/payload_1.json b/VENDORS/Milesight/WS302/LORIOT/uplink/payload_1.json new file mode 100644 index 00000000..5e70320c --- /dev/null +++ b/VENDORS/Milesight/WS302/LORIOT/uplink/payload_1.json @@ -0,0 +1,32 @@ +{ + "cmd": "gw", + "seqno": 4, + "EUI": "0102030405060708", + "ts": 1690901260493, + "fcnt": 3, + "port": 207, + "freq": 868300000, + "toa": 1319, + "dr": "SF12 BW125 4/5", + "ack": false, + "gws": [ + { + "rssi": -38, + "snr": 8.5, + "ts": 1690901260493, + "time": "2023-08-01T14:47:40.493Z", + "gweui": "1020304080706050", + "ant": 0 + }, + { + "rssi": -42, + "snr": 8.8, + "ts": 1690901260495, + "time": "2023-08-01T14:47:40.495Z", + "gweui": "1020304081716151", + "ant": 0 + } + ], + "bat": 143, + "data": "017564055B053F02DA016A02" +} \ No newline at end of file diff --git a/VENDORS/Milesight/WS302/LORIOT/uplink/result_1.json b/VENDORS/Milesight/WS302/LORIOT/uplink/result_1.json new file mode 100644 index 00000000..21ec4ed5 --- /dev/null +++ b/VENDORS/Milesight/WS302/LORIOT/uplink/result_1.json @@ -0,0 +1,44 @@ +[{ + "deviceName": "0102030405060708", + "deviceType": "WS302", + "attributes": { + "eui": "0102030405060708", + "fPort": 207, + "frequency": 868300000 + }, + "telemetry": [{ + "ts": 1690901260493, + "values": { + "battery": 100, + "LAF": 57.5, + "LAeq": 47.4, + "LAFmax": 61.8 + } + }] +}, { + "deviceName": "Gateway 1020304080706050", + "deviceType": "Lora gateway", + "telemetry": [{ + "ts": 1690901260493, + "values": { + "rssi": -38, + "snr": 8.5 + } + }], + "attributes": { + "eui": "1020304080706050" + } +}, { + "deviceName": "Gateway 1020304081716151", + "deviceType": "Lora gateway", + "telemetry": [{ + "ts": 1690901260495, + "values": { + "rssi": -42, + "snr": 8.8 + } + }], + "attributes": { + "eui": "1020304081716151" + } +}] \ No newline at end of file diff --git a/VENDORS/Milesight/WS303/LORIOT/uplink/converter.json b/VENDORS/Milesight/WS303/LORIOT/uplink/converter.json index 582d7b74..1eb6d560 100644 --- a/VENDORS/Milesight/WS303/LORIOT/uplink/converter.json +++ b/VENDORS/Milesight/WS303/LORIOT/uplink/converter.json @@ -1,11 +1,16 @@ { "name": "Loriot Uplink Decoder for WS303", "type": "UPLINK", - "debugMode": true, + "debugMode": false, + "debugSettings": { + "failuresEnabled": true, + "allEnabled": false, + "allEnabledUntil": 1735214286964 + }, "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);\nvar deviceName = data.EUI;\nvar deviceType = \"WS303\";\nvar groupName = null; // If groupName is not null - created device will be added to the entity group with such name.\nvar customerName = null; // If customerName is not null - created devices will be assigned to customer with such name. \n\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// If you want to parse incoming data somehow, you can add your code to this function.\n// input: bytes\n// expected output:\n// {\n// \"attributes\": {\"attributeKey\": \"attributeValue\"},\n// \"telemetry\": {\"telemetryKey\": \"telemetryValue\"}\n// }\n\nfunction decodePayload(input) {\n var output = { attributes: {}, telemetry: []};\n \n var decoded = {};\n for (var i = 0; i < input.length - 2; ) {\n var channel_id = input[i++] & 0xff;\n var channel_type = input[i++] & 0xff;\n\n // BATTERY\n if (channel_id === 0x01 && channel_type === 0x75) {\n decoded.battery = input[i];\n i += 1;\n }\n // WATER LEAK\n else if (channel_id === 0x03 && channel_type === 0x00) {\n decoded.leakage_status = input[i] === 0 ? \"normal\" : \"leak\";\n i += 1;\n }\n }\n \n output.telemetry = [{\n ts: timestamp,\n values: decoded\n }];\n\n // --- Decoding code --- //\n return output;\n}\n\n// --- attributes and telemetry objects ---\nvar telemetry = [];\nvar attributes = {};\n// --- attributes and telemetry objects ---\n\n// --- Timestamp parsing\ntimestamp = data.ts;\n// --- Timestamp parsing\n\n// Message parsing\n// To avoid paths in the decoded objects we passing false value to function as \"pathInKey\" argument.\n// Warning: pathInKey can cause already found fields to be overwritten with the last value found.\n\nvar uplinkDataList = [];\n\n// Passing incoming bytes to decodePayload function, to get custom decoding\nvar customDecoding = decodePayload(hexToBytes(data.data));\n\n// Collecting data to result\nif (customDecoding.?telemetry.size() > 0) {\n if (customDecoding.telemetry instanceof java.util.ArrayList) {\n foreach(telemetryObj: customDecoding.telemetry) {\n if (telemetryObj.ts != null && telemetryObj.values != null) {\n telemetry.add(telemetryObj);\n }\n }\n } else {\n telemetry.putAll(customDecoding.telemetry);\n }\n}\n\nif (customDecoding.?attributes.size() > 0) {\n attributes.putAll(customDecoding.attributes);\n}\n\n// You can add some keys manually to attributes or telemetry\nattributes.eui = data.EUI;\nattributes.fPort = data.port;\nattributes.frequency = data.freq;\n\nvar isIncludeGatewayInfo = metadata[\"includeGatewayInfo\"];\nif(isIncludeGatewayInfo == true) {\n var addDataToTelemetry = {};\n addDataToTelemetry.rssi = data.rssi;\n addDataToTelemetry.seqno = data.seqno;\n addDataToTelemetry.snr = data.snr;\n addDataToTelemetry.ack = data.ack;\n addDataToTelemetry.toa = data.toa;\n addDataToTelemetry.fCnt = data.fcnt;\n \n telemetry = processTelemetryData(telemetry, addDataToTelemetry);\n}\n\nvar deviceInfo = {\n deviceName: deviceName,\n deviceType: deviceType,\n// assetName: assetName,\n// assetType: assetType,\n attributes: attributes,\n telemetry: telemetry, \n};\n\naddAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName);\n\nuplinkDataList.add(deviceInfo);\n\nvar gatewayDeviceNamePrefix = \"Gateway \";\nvar gatewayDeviceType = \"Lora gateway\";\nvar gatewayGroupName = null; // If gatewayGroupName is not null - created device will be added to the entity group with such name.\n\nif (data.cmd == \"gw\") {\n foreach( gatewayInfo : data.gws ) {\n var addGatewayInfo = {};\n\n // You can add some keys manually telemetry\n addGatewayInfo.rssi = gatewayInfo.rssi;\n addGatewayInfo.snr = gatewayInfo.snr;\n // You can add some keys manually telemetry\n \n var gatewayInfoMsg = {\n deviceName: gatewayDeviceNamePrefix + gatewayInfo.gweui,\n deviceType: gatewayDeviceType,\n telemetry: [{\n \"ts\": gatewayInfo.ts,\n \"values\": addGatewayInfo\n }],\n attributes: {\n eui: gatewayInfo.gweui\n }\n };\n addAdditionalInfoForDeviceMsg(gatewayInfoMsg, customerName, gatewayGroupName);\n uplinkDataList.add(gatewayInfoMsg);\n }\n}\n\nreturn uplinkDataList;\n\nfunction addAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName) {\n if (customerName != null) {\n deviceInfo.customerName = customerName;\n }\n if (groupName != null) {\n deviceInfo.groupName = groupName;\n }\n}\n\nfunction processTelemetryData(telemetry, addDataToTelemetry) {\n if (telemetry.size > 1) {\n telemetry = addDataToMultipleTelemetries(telemetry, addDataToTelemetry);\n }\n else if (telemetry.size == 1) {\n telemetry = addDataToSingleTelemetry(telemetry, addDataToTelemetry);\n }\n else {\n telemetry.add(addDataToTelemetry);\n }\n \n return telemetry;\n}\n\nfunction addDataToMultipleTelemetries(telemetry, addDataToTelemetry) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[0][\"values\"].keys.contains(element.key)) {\n telemetry[0][\"values\"][element.key] = element.value;\n }\n if (!telemetry[1][\"values\"].keys.contains(element.key)) {\n telemetry[1][\"values\"][element.key] = element.value;\n }\n }\n \n return telemetry;\n}\n\nfunction addDataToSingleTelemetry(telemetry, addDataToTelemetry) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[0][\"values\"].keys.contains(element.key)) {\n telemetry[0][\"values\"][element.key] = element.value;\n }\n }\n \n return telemetry;\n}", + "tbelDecoder": "var data = decodeToJson(payload);\nvar deviceName = data.EUI;\nvar deviceType = \"WS303\";\nvar groupName = null; // If groupName is not null - created device will be added to the entity group with such name.\nvar customerName = null; // If customerName is not null - created devices will be assigned to customer with such name. \n\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// If you want to parse incoming data somehow, you can add your code to this function.\n// input: bytes\n// expected output:\n// {\n// \"attributes\": {\"attributeKey\": \"attributeValue\"},\n// \"telemetry\": {\"telemetryKey\": \"telemetryValue\"}\n// }\n\nfunction decodePayload(input) {\n var output = { attributes: {}, telemetry: []};\n \n var decoded = {};\n for (var i = 0; i < input.length - 2; ) {\n var channel_id = input[i++] & 0xff;\n var channel_type = input[i++] & 0xff;\n\n // BATTERY\n if (channel_id === 0x01 && channel_type === 0x75) {\n decoded.battery = input[i];\n i += 1;\n }\n // WATER LEAK\n else if (channel_id === 0x03 && channel_type === 0x00) {\n decoded.leakage_status = input[i] === 0 ? \"normal\" : \"leak\";\n i += 1;\n }\n }\n \n output.telemetry = [{\n ts: timestamp,\n values: decoded\n }];\n\n // --- Decoding code --- //\n return output;\n}\n\n// --- attributes and telemetry objects ---\nvar telemetry = [];\nvar attributes = {};\n// --- attributes and telemetry objects ---\n\n// --- Timestamp parsing\ntimestamp = data.ts;\n// --- Timestamp parsing\n\n// Message parsing\n// To avoid paths in the decoded objects we passing false value to function as \"pathInKey\" argument.\n// Warning: pathInKey can cause already found fields to be overwritten with the last value found.\n\nvar uplinkDataList = [];\n\n// Passing incoming bytes to decodePayload function, to get custom decoding\nvar customDecoding = decodePayload(hexToBytes(data.data));\n\n// Collecting data to result\nif (customDecoding.?telemetry.size() > 0) {\n if (customDecoding.telemetry instanceof java.util.ArrayList) {\n foreach(telemetryObj: customDecoding.telemetry) {\n if (telemetryObj.ts != null && telemetryObj.values != null) {\n telemetry.add(telemetryObj);\n }\n }\n } else {\n telemetry.putAll(customDecoding.telemetry);\n }\n}\n\nif (customDecoding.?attributes.size() > 0) {\n attributes.putAll(customDecoding.attributes);\n}\n\n// You can add some keys manually to attributes or telemetry\nattributes.eui = data.EUI;\nattributes.fPort = data.port;\nattributes.frequency = data.freq;\n\nvar isIncludeGatewayInfo = metadata[\"includeGatewayInfo\"];\nif(isIncludeGatewayInfo == true) {\n var addDataToTelemetry = {};\n addDataToTelemetry.rssi = data.rssi;\n addDataToTelemetry.seqno = data.seqno;\n addDataToTelemetry.snr = data.snr;\n addDataToTelemetry.ack = data.ack;\n addDataToTelemetry.toa = data.toa;\n addDataToTelemetry.fCnt = data.fcnt;\n \n telemetry = processTelemetryData(telemetry, addDataToTelemetry);\n}\n\nvar deviceInfo = {\n deviceName: deviceName,\n deviceType: deviceType,\n// assetName: assetName,\n// assetType: assetType,\n attributes: attributes,\n telemetry: telemetry, \n};\n\naddAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName);\n\nuplinkDataList.add(deviceInfo);\n\nvar gatewayDeviceNamePrefix = \"Gateway \";\nvar gatewayDeviceType = \"Lora gateway\";\nvar gatewayGroupName = null; // If gatewayGroupName is not null - created device will be added to the entity group with such name.\n\nif (data.cmd == \"gw\") {\n foreach( gatewayInfo : data.gws ) {\n var addGatewayInfo = {};\n\n // You can add some keys manually telemetry\n addGatewayInfo.rssi = gatewayInfo.rssi;\n addGatewayInfo.snr = gatewayInfo.snr;\n // You can add some keys manually telemetry\n \n var gatewayInfoMsg = {\n deviceName: gatewayDeviceNamePrefix + gatewayInfo.gweui,\n deviceType: gatewayDeviceType,\n telemetry: [{\n \"ts\": gatewayInfo.ts,\n \"values\": addGatewayInfo\n }],\n attributes: {\n eui: gatewayInfo.gweui\n }\n };\n addAdditionalInfoForDeviceMsg(gatewayInfoMsg, customerName, gatewayGroupName);\n uplinkDataList.add(gatewayInfoMsg);\n }\n}\n\nreturn uplinkDataList;\n\nfunction addAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName) {\n if (customerName != null) {\n deviceInfo.customerName = customerName;\n }\n if (groupName != null) {\n deviceInfo.groupName = groupName;\n }\n}\n\nfunction processTelemetryData(telemetry, addDataToTelemetry) {\n if (telemetry.size >= 1) {\n telemetry = addDataToTelemetries(telemetry, addDataToTelemetry);\n }\n else {\n telemetry.add(addDataToTelemetry);\n }\n \n return telemetry;\n}\n\nfunction addDataToTelemetries(telemetries, addDataToTelemetry) {\n foreach(telemetry : telemetries) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[\"values\"].keys.contains(element.key)) {\n telemetry[\"values\"][element.key] = element.value;\n }\n } \n }\n \n return telemetries;\n}", "encoder": null, "tbelEncoder": null, "updateOnlyKeys": [ diff --git a/VENDORS/Milesight/WS303/LORIOT/uplink/payload_1.json b/VENDORS/Milesight/WS303/LORIOT/uplink/payload_1.json new file mode 100644 index 00000000..92555d08 --- /dev/null +++ b/VENDORS/Milesight/WS303/LORIOT/uplink/payload_1.json @@ -0,0 +1,32 @@ +{ + "cmd": "gw", + "seqno": 4, + "EUI": "0102030405060708", + "ts": 1690901260493, + "fcnt": 3, + "port": 207, + "freq": 868300000, + "toa": 1319, + "dr": "SF12 BW125 4/5", + "ack": false, + "gws": [ + { + "rssi": -38, + "snr": 8.5, + "ts": 1690901260493, + "time": "2023-08-01T14:47:40.493Z", + "gweui": "1020304080706050", + "ant": 0 + }, + { + "rssi": -42, + "snr": 8.8, + "ts": 1690901260495, + "time": "2023-08-01T14:47:40.495Z", + "gweui": "1020304081716151", + "ant": 0 + } + ], + "bat": 143, + "data": "017564030000" +} \ No newline at end of file diff --git a/VENDORS/Milesight/WS303/LORIOT/uplink/result_1.json b/VENDORS/Milesight/WS303/LORIOT/uplink/result_1.json new file mode 100644 index 00000000..8cd89f48 --- /dev/null +++ b/VENDORS/Milesight/WS303/LORIOT/uplink/result_1.json @@ -0,0 +1,42 @@ +[{ + "deviceName": "0102030405060708", + "deviceType": "WS303", + "attributes": { + "eui": "0102030405060708", + "fPort": 207, + "frequency": 868300000 + }, + "telemetry": [{ + "ts": 1690901260493, + "values": { + "battery": 100, + "leakage_status": "normal" + } + }] +}, { + "deviceName": "Gateway 1020304080706050", + "deviceType": "Lora gateway", + "telemetry": [{ + "ts": 1690901260493, + "values": { + "rssi": -38, + "snr": 8.5 + } + }], + "attributes": { + "eui": "1020304080706050" + } +}, { + "deviceName": "Gateway 1020304081716151", + "deviceType": "Lora gateway", + "telemetry": [{ + "ts": 1690901260495, + "values": { + "rssi": -42, + "snr": 8.8 + } + }], + "attributes": { + "eui": "1020304081716151" + } +}] \ No newline at end of file From 6778af23ca9ed13ba44cf9b74a9dcb441a5135eb Mon Sep 17 00:00:00 2001 From: Artem Barysh Date: Thu, 26 Dec 2024 17:48:46 +0200 Subject: [PATCH 28/33] Added an additional test case for integrating Loriot (Decentlab device) --- .../DL-5TM/LORIOT/uplink/payload_2.json | 32 +++++++++++++++++ .../DL-5TM/LORIOT/uplink/result_2.json | 21 +++++++++++ .../DL-ALB/LORIOT/uplink/payload_2.json | 32 +++++++++++++++++ .../DL-ALB/LORIOT/uplink/result_2.json | 21 +++++++++++ .../DL-ATM22/LORIOT/uplink/payload_2.json | 32 +++++++++++++++++ .../DL-ATM22/LORIOT/uplink/result_2.json | 18 ++++++++++ .../DL-ATM41/LORIOT/uplink/payload_2.json | 32 +++++++++++++++++ .../DL-ATM41/LORIOT/uplink/result_2.json | 35 ++++++++++++++++++ .../DL-BLG/LORIOT/uplink/payload_2.json | 32 +++++++++++++++++ .../DL-BLG/LORIOT/uplink/result_2.json | 21 +++++++++++ .../DL-CTD10/LORIOT/uplink/payload_2.json | 32 +++++++++++++++++ .../DL-CTD10/LORIOT/uplink/result_2.json | 18 ++++++++++ .../DL-CWS/LORIOT/uplink/payload_2.json | 32 +++++++++++++++++ .../DL-CWS/LORIOT/uplink/result_2.json | 24 +++++++++++++ .../DL-CWS2/LORIOT/uplink/payload_2.json | 32 +++++++++++++++++ .../DL-CWS2/LORIOT/uplink/result_2.json | 26 ++++++++++++++ .../DL-DLR2-002/LORIOT/uplink/payload_1.json | 32 +++++++++++++++++ .../DL-DLR2-002/LORIOT/uplink/result_1.json | 21 +++++++++++ .../DL-DLR2-003/LORIOT/uplink/payload_1.json | 32 +++++++++++++++++ .../DL-DLR2-003/LORIOT/uplink/result_1.json | 21 +++++++++++ .../DL-DLR2-004/LORIOT/uplink/payload_2.json | 32 +++++++++++++++++ .../DL-DLR2-004/LORIOT/uplink/result_2.json | 19 ++++++++++ .../DL-DLR2-005/LORIOT/uplink/payload_2.json | 32 +++++++++++++++++ .../DL-DLR2-005/LORIOT/uplink/result_2.json | 18 ++++++++++ .../DL-DLR2-006/LORIOT/uplink/payload_2.json | 32 +++++++++++++++++ .../DL-DLR2-006/LORIOT/uplink/result_2.json | 18 ++++++++++ .../DL-DLR2-008/LORIOT/uplink/payload_2.json | 32 +++++++++++++++++ .../DL-DLR2-008/LORIOT/uplink/result_2.json | 19 ++++++++++ .../DL-DLR2-009/LORIOT/uplink/payload_2.json | 32 +++++++++++++++++ .../DL-DLR2-009/LORIOT/uplink/result_2.json | 20 +++++++++++ .../DL-DLR2-010/LORIOT/uplink/payload_2.json | 32 +++++++++++++++++ .../DL-DLR2-010/LORIOT/uplink/result_2.json | 24 +++++++++++++ .../DL-DLR2-011/LORIOT/uplink/payload_2.json | 32 +++++++++++++++++ .../DL-DLR2-011/LORIOT/uplink/result_2.json | 18 ++++++++++ .../DL-DLR2-012/LORIOT/uplink/payload_2.json | 32 +++++++++++++++++ .../DL-DLR2-012/LORIOT/uplink/result_2.json | 19 ++++++++++ .../DL-DS18/LORIOT/uplink/payload_2.json | 32 +++++++++++++++++ .../DL-DS18/LORIOT/uplink/result_2.json | 19 ++++++++++ .../DL-DWS/LORIOT/uplink/payload_2.json | 32 +++++++++++++++++ .../DL-DWS/LORIOT/uplink/result_2.json | 20 +++++++++++ .../DL-GMM/LORIOT/uplink/payload_2.json | 32 +++++++++++++++++ .../DL-GMM/LORIOT/uplink/result_2.json | 25 +++++++++++++ .../DL-IAM/LORIOT/uplink/payload_3.json | 32 +++++++++++++++++ .../DL-IAM/LORIOT/uplink/result_3.json | 29 +++++++++++++++ .../DL-IFD/LORIOT/uplink/payload_2.json | 32 +++++++++++++++++ .../DL-IFD/LORIOT/uplink/result_2.json | 19 ++++++++++ .../DL-ILT/LORIOT/uplink/payload_2.json | 32 +++++++++++++++++ .../DL-ILT/LORIOT/uplink/result_2.json | 18 ++++++++++ .../DL-ISD/LORIOT/uplink/payload_2.json | 32 +++++++++++++++++ .../DL-ISD/LORIOT/uplink/result_2.json | 18 ++++++++++ .../DL-ISF/LORIOT/uplink/payload_2.json | 32 +++++++++++++++++ .../DL-ISF/LORIOT/uplink/result_2.json | 33 +++++++++++++++++ .../DL-ITST/LORIOT/uplink/payload_2.json | 32 +++++++++++++++++ .../DL-ITST/LORIOT/uplink/result_2.json | 20 +++++++++++ .../DL-KL66/LORIOT/uplink/payload_2.json | 32 +++++++++++++++++ .../DL-KL66/LORIOT/uplink/result_2.json | 24 +++++++++++++ .../DL-LID/LORIOT/uplink/payload_2.json | 32 +++++++++++++++++ .../DL-LID/LORIOT/uplink/result_2.json | 29 +++++++++++++++ .../DL-LP8P/LORIOT/uplink/payload_3.json | 32 +++++++++++++++++ .../DL-LP8P/LORIOT/uplink/result_3.json | 30 ++++++++++++++++ .../DL-LPW/LORIOT/uplink/payload_2.json | 32 +++++++++++++++++ .../DL-LPW/LORIOT/uplink/result_2.json | 19 ++++++++++ .../DL-LWS/LORIOT/uplink/payload_2.json | 32 +++++++++++++++++ .../DL-LWS/LORIOT/uplink/result_2.json | 19 ++++++++++ .../DL-MBX/LORIOT/uplink/payload_3.json | 32 +++++++++++++++++ .../DL-MBX/LORIOT/uplink/result_3.json | 20 +++++++++++ .../DL-MES5/LORIOT/uplink/payload_2.json | 32 +++++++++++++++++ .../DL-MES5/LORIOT/uplink/result_2.json | 23 ++++++++++++ .../DL-NTU/LORIOT/uplink/payload_2.json | 32 +++++++++++++++++ .../DL-NTU/LORIOT/uplink/result_2.json | 23 ++++++++++++ .../DL-OPTOD/LORIOT/uplink/payload_2.json | 32 +++++++++++++++++ .../DL-OPTOD/LORIOT/uplink/result_2.json | 23 ++++++++++++ .../DL-PAR/LORIOT/uplink/payload_2.json | 32 +++++++++++++++++ .../DL-PAR/LORIOT/uplink/result_2.json | 19 ++++++++++ .../DL-PHEHT/LORIOT/uplink/payload_2.json | 32 +++++++++++++++++ .../DL-PHEHT/LORIOT/uplink/result_2.json | 23 ++++++++++++ .../DL-PM/LORIOT/uplink/payload_3.json | 32 +++++++++++++++++ .../DL-PM/LORIOT/uplink/result_3.json | 31 ++++++++++++++++ .../DL-PR21/LORIOT/uplink/payload_2.json | 32 +++++++++++++++++ .../DL-PR21/LORIOT/uplink/result_2.json | 20 +++++++++++ .../DL-PR26/LORIOT/uplink/payload_2.json | 32 +++++++++++++++++ .../DL-PR26/LORIOT/uplink/result_2.json | 20 +++++++++++ .../DL-PR36/LORIOT/uplink/payload_2.json | 32 +++++++++++++++++ .../DL-PR36/LORIOT/uplink/result_2.json | 20 +++++++++++ .../DL-PR36CTD/LORIOT/uplink/payload_2.json | 32 +++++++++++++++++ .../DL-PR36CTD/LORIOT/uplink/result_2.json | 22 ++++++++++++ .../DL-PYR/LORIOT/uplink/payload_2.json | 32 +++++++++++++++++ .../DL-PYR/LORIOT/uplink/result_2.json | 18 ++++++++++ .../DL-RHC/LORIOT/uplink/payload_1.json | 32 +++++++++++++++++ .../DL-RHC/LORIOT/uplink/result_1.json | 21 +++++++++++ .../DL-SDD/LORIOT/uplink/payload_2.json | 32 +++++++++++++++++ .../DL-SDD/LORIOT/uplink/result_2.json | 36 +++++++++++++++++++ .../DL-SHT35-001/LORIOT/uplink/payload_2.json | 32 +++++++++++++++++ .../DL-SHT35-001/LORIOT/uplink/result_2.json | 20 +++++++++++ .../DL-SHT35-002/LORIOT/uplink/payload_2.json | 32 +++++++++++++++++ .../DL-SHT35-002/LORIOT/uplink/result_2.json | 20 +++++++++++ .../DL-SMTP/LORIOT/uplink/payload_2.json | 32 +++++++++++++++++ .../DL-SMTP/LORIOT/uplink/result_2.json | 34 ++++++++++++++++++ .../DL-TBRG/LORIOT/uplink/payload_2.json | 32 +++++++++++++++++ .../DL-TBRG/LORIOT/uplink/result_2.json | 18 ++++++++++ .../DL-TP/LORIOT/uplink/payload_2.json | 32 +++++++++++++++++ .../DL-TP/LORIOT/uplink/result_2.json | 34 ++++++++++++++++++ .../DL-TRS11/LORIOT/uplink/payload_1.json | 32 +++++++++++++++++ .../DL-TRS11/LORIOT/uplink/result_1.json | 21 +++++++++++ .../DL-TRS12/LORIOT/uplink/payload_2.json | 32 +++++++++++++++++ .../DL-TRS12/LORIOT/uplink/result_2.json | 22 ++++++++++++ .../DL-TRS21/LORIOT/uplink/payload_2.json | 32 +++++++++++++++++ .../DL-TRS21/LORIOT/uplink/result_2.json | 20 +++++++++++ VENDORS/Decentlab/DL-TRS21/info.json | 2 +- .../DL-WRM/LORIOT/uplink/payload_2.json | 32 +++++++++++++++++ .../DL-WRM/LORIOT/uplink/result_2.json | 18 ++++++++++ .../DL-ZN1/LORIOT/uplink/payload_2.json | 32 +++++++++++++++++ .../DL-ZN1/LORIOT/uplink/result_2.json | 19 ++++++++++ .../DL-ZN2/LORIOT/uplink/payload_1.json | 32 +++++++++++++++++ .../DL-ZN2/LORIOT/uplink/result_1.json | 20 +++++++++++ 115 files changed, 3093 insertions(+), 1 deletion(-) create mode 100644 VENDORS/Decentlab/DL-5TM/LORIOT/uplink/payload_2.json create mode 100644 VENDORS/Decentlab/DL-5TM/LORIOT/uplink/result_2.json create mode 100644 VENDORS/Decentlab/DL-ALB/LORIOT/uplink/payload_2.json create mode 100644 VENDORS/Decentlab/DL-ALB/LORIOT/uplink/result_2.json create mode 100644 VENDORS/Decentlab/DL-ATM22/LORIOT/uplink/payload_2.json create mode 100644 VENDORS/Decentlab/DL-ATM22/LORIOT/uplink/result_2.json create mode 100644 VENDORS/Decentlab/DL-ATM41/LORIOT/uplink/payload_2.json create mode 100644 VENDORS/Decentlab/DL-ATM41/LORIOT/uplink/result_2.json create mode 100644 VENDORS/Decentlab/DL-BLG/LORIOT/uplink/payload_2.json create mode 100644 VENDORS/Decentlab/DL-BLG/LORIOT/uplink/result_2.json create mode 100644 VENDORS/Decentlab/DL-CTD10/LORIOT/uplink/payload_2.json create mode 100644 VENDORS/Decentlab/DL-CTD10/LORIOT/uplink/result_2.json create mode 100644 VENDORS/Decentlab/DL-CWS/LORIOT/uplink/payload_2.json create mode 100644 VENDORS/Decentlab/DL-CWS/LORIOT/uplink/result_2.json create mode 100644 VENDORS/Decentlab/DL-CWS2/LORIOT/uplink/payload_2.json create mode 100644 VENDORS/Decentlab/DL-CWS2/LORIOT/uplink/result_2.json create mode 100644 VENDORS/Decentlab/DL-DLR2-002/LORIOT/uplink/payload_1.json create mode 100644 VENDORS/Decentlab/DL-DLR2-002/LORIOT/uplink/result_1.json create mode 100644 VENDORS/Decentlab/DL-DLR2-003/LORIOT/uplink/payload_1.json create mode 100644 VENDORS/Decentlab/DL-DLR2-003/LORIOT/uplink/result_1.json create mode 100644 VENDORS/Decentlab/DL-DLR2-004/LORIOT/uplink/payload_2.json create mode 100644 VENDORS/Decentlab/DL-DLR2-004/LORIOT/uplink/result_2.json create mode 100644 VENDORS/Decentlab/DL-DLR2-005/LORIOT/uplink/payload_2.json create mode 100644 VENDORS/Decentlab/DL-DLR2-005/LORIOT/uplink/result_2.json create mode 100644 VENDORS/Decentlab/DL-DLR2-006/LORIOT/uplink/payload_2.json create mode 100644 VENDORS/Decentlab/DL-DLR2-006/LORIOT/uplink/result_2.json create mode 100644 VENDORS/Decentlab/DL-DLR2-008/LORIOT/uplink/payload_2.json create mode 100644 VENDORS/Decentlab/DL-DLR2-008/LORIOT/uplink/result_2.json create mode 100644 VENDORS/Decentlab/DL-DLR2-009/LORIOT/uplink/payload_2.json create mode 100644 VENDORS/Decentlab/DL-DLR2-009/LORIOT/uplink/result_2.json create mode 100644 VENDORS/Decentlab/DL-DLR2-010/LORIOT/uplink/payload_2.json create mode 100644 VENDORS/Decentlab/DL-DLR2-010/LORIOT/uplink/result_2.json create mode 100644 VENDORS/Decentlab/DL-DLR2-011/LORIOT/uplink/payload_2.json create mode 100644 VENDORS/Decentlab/DL-DLR2-011/LORIOT/uplink/result_2.json create mode 100644 VENDORS/Decentlab/DL-DLR2-012/LORIOT/uplink/payload_2.json create mode 100644 VENDORS/Decentlab/DL-DLR2-012/LORIOT/uplink/result_2.json create mode 100644 VENDORS/Decentlab/DL-DS18/LORIOT/uplink/payload_2.json create mode 100644 VENDORS/Decentlab/DL-DS18/LORIOT/uplink/result_2.json create mode 100644 VENDORS/Decentlab/DL-DWS/LORIOT/uplink/payload_2.json create mode 100644 VENDORS/Decentlab/DL-DWS/LORIOT/uplink/result_2.json create mode 100644 VENDORS/Decentlab/DL-GMM/LORIOT/uplink/payload_2.json create mode 100644 VENDORS/Decentlab/DL-GMM/LORIOT/uplink/result_2.json create mode 100644 VENDORS/Decentlab/DL-IAM/LORIOT/uplink/payload_3.json create mode 100644 VENDORS/Decentlab/DL-IAM/LORIOT/uplink/result_3.json create mode 100644 VENDORS/Decentlab/DL-IFD/LORIOT/uplink/payload_2.json create mode 100644 VENDORS/Decentlab/DL-IFD/LORIOT/uplink/result_2.json create mode 100644 VENDORS/Decentlab/DL-ILT/LORIOT/uplink/payload_2.json create mode 100644 VENDORS/Decentlab/DL-ILT/LORIOT/uplink/result_2.json create mode 100644 VENDORS/Decentlab/DL-ISD/LORIOT/uplink/payload_2.json create mode 100644 VENDORS/Decentlab/DL-ISD/LORIOT/uplink/result_2.json create mode 100644 VENDORS/Decentlab/DL-ISF/LORIOT/uplink/payload_2.json create mode 100644 VENDORS/Decentlab/DL-ISF/LORIOT/uplink/result_2.json create mode 100644 VENDORS/Decentlab/DL-ITST/LORIOT/uplink/payload_2.json create mode 100644 VENDORS/Decentlab/DL-ITST/LORIOT/uplink/result_2.json create mode 100644 VENDORS/Decentlab/DL-KL66/LORIOT/uplink/payload_2.json create mode 100644 VENDORS/Decentlab/DL-KL66/LORIOT/uplink/result_2.json create mode 100644 VENDORS/Decentlab/DL-LID/LORIOT/uplink/payload_2.json create mode 100644 VENDORS/Decentlab/DL-LID/LORIOT/uplink/result_2.json create mode 100644 VENDORS/Decentlab/DL-LP8P/LORIOT/uplink/payload_3.json create mode 100644 VENDORS/Decentlab/DL-LP8P/LORIOT/uplink/result_3.json create mode 100644 VENDORS/Decentlab/DL-LPW/LORIOT/uplink/payload_2.json create mode 100644 VENDORS/Decentlab/DL-LPW/LORIOT/uplink/result_2.json create mode 100644 VENDORS/Decentlab/DL-LWS/LORIOT/uplink/payload_2.json create mode 100644 VENDORS/Decentlab/DL-LWS/LORIOT/uplink/result_2.json create mode 100644 VENDORS/Decentlab/DL-MBX/LORIOT/uplink/payload_3.json create mode 100644 VENDORS/Decentlab/DL-MBX/LORIOT/uplink/result_3.json create mode 100644 VENDORS/Decentlab/DL-MES5/LORIOT/uplink/payload_2.json create mode 100644 VENDORS/Decentlab/DL-MES5/LORIOT/uplink/result_2.json create mode 100644 VENDORS/Decentlab/DL-NTU/LORIOT/uplink/payload_2.json create mode 100644 VENDORS/Decentlab/DL-NTU/LORIOT/uplink/result_2.json create mode 100644 VENDORS/Decentlab/DL-OPTOD/LORIOT/uplink/payload_2.json create mode 100644 VENDORS/Decentlab/DL-OPTOD/LORIOT/uplink/result_2.json create mode 100644 VENDORS/Decentlab/DL-PAR/LORIOT/uplink/payload_2.json create mode 100644 VENDORS/Decentlab/DL-PAR/LORIOT/uplink/result_2.json create mode 100644 VENDORS/Decentlab/DL-PHEHT/LORIOT/uplink/payload_2.json create mode 100644 VENDORS/Decentlab/DL-PHEHT/LORIOT/uplink/result_2.json create mode 100644 VENDORS/Decentlab/DL-PM/LORIOT/uplink/payload_3.json create mode 100644 VENDORS/Decentlab/DL-PM/LORIOT/uplink/result_3.json create mode 100644 VENDORS/Decentlab/DL-PR21/LORIOT/uplink/payload_2.json create mode 100644 VENDORS/Decentlab/DL-PR21/LORIOT/uplink/result_2.json create mode 100644 VENDORS/Decentlab/DL-PR26/LORIOT/uplink/payload_2.json create mode 100644 VENDORS/Decentlab/DL-PR26/LORIOT/uplink/result_2.json create mode 100644 VENDORS/Decentlab/DL-PR36/LORIOT/uplink/payload_2.json create mode 100644 VENDORS/Decentlab/DL-PR36/LORIOT/uplink/result_2.json create mode 100644 VENDORS/Decentlab/DL-PR36CTD/LORIOT/uplink/payload_2.json create mode 100644 VENDORS/Decentlab/DL-PR36CTD/LORIOT/uplink/result_2.json create mode 100644 VENDORS/Decentlab/DL-PYR/LORIOT/uplink/payload_2.json create mode 100644 VENDORS/Decentlab/DL-PYR/LORIOT/uplink/result_2.json create mode 100644 VENDORS/Decentlab/DL-RHC/LORIOT/uplink/payload_1.json create mode 100644 VENDORS/Decentlab/DL-RHC/LORIOT/uplink/result_1.json create mode 100644 VENDORS/Decentlab/DL-SDD/LORIOT/uplink/payload_2.json create mode 100644 VENDORS/Decentlab/DL-SDD/LORIOT/uplink/result_2.json create mode 100644 VENDORS/Decentlab/DL-SHT35-001/LORIOT/uplink/payload_2.json create mode 100644 VENDORS/Decentlab/DL-SHT35-001/LORIOT/uplink/result_2.json create mode 100644 VENDORS/Decentlab/DL-SHT35-002/LORIOT/uplink/payload_2.json create mode 100644 VENDORS/Decentlab/DL-SHT35-002/LORIOT/uplink/result_2.json create mode 100644 VENDORS/Decentlab/DL-SMTP/LORIOT/uplink/payload_2.json create mode 100644 VENDORS/Decentlab/DL-SMTP/LORIOT/uplink/result_2.json create mode 100644 VENDORS/Decentlab/DL-TBRG/LORIOT/uplink/payload_2.json create mode 100644 VENDORS/Decentlab/DL-TBRG/LORIOT/uplink/result_2.json create mode 100644 VENDORS/Decentlab/DL-TP/LORIOT/uplink/payload_2.json create mode 100644 VENDORS/Decentlab/DL-TP/LORIOT/uplink/result_2.json create mode 100644 VENDORS/Decentlab/DL-TRS11/LORIOT/uplink/payload_1.json create mode 100644 VENDORS/Decentlab/DL-TRS11/LORIOT/uplink/result_1.json create mode 100644 VENDORS/Decentlab/DL-TRS12/LORIOT/uplink/payload_2.json create mode 100644 VENDORS/Decentlab/DL-TRS12/LORIOT/uplink/result_2.json create mode 100644 VENDORS/Decentlab/DL-TRS21/LORIOT/uplink/payload_2.json create mode 100644 VENDORS/Decentlab/DL-TRS21/LORIOT/uplink/result_2.json create mode 100644 VENDORS/Decentlab/DL-WRM/LORIOT/uplink/payload_2.json create mode 100644 VENDORS/Decentlab/DL-WRM/LORIOT/uplink/result_2.json create mode 100644 VENDORS/Decentlab/DL-ZN1/LORIOT/uplink/payload_2.json create mode 100644 VENDORS/Decentlab/DL-ZN1/LORIOT/uplink/result_2.json create mode 100644 VENDORS/Decentlab/DL-ZN2/LORIOT/uplink/payload_1.json create mode 100644 VENDORS/Decentlab/DL-ZN2/LORIOT/uplink/result_1.json diff --git a/VENDORS/Decentlab/DL-5TM/LORIOT/uplink/payload_2.json b/VENDORS/Decentlab/DL-5TM/LORIOT/uplink/payload_2.json new file mode 100644 index 00000000..4bf804b4 --- /dev/null +++ b/VENDORS/Decentlab/DL-5TM/LORIOT/uplink/payload_2.json @@ -0,0 +1,32 @@ +{ + "cmd": "gw", + "seqno": 4, + "EUI": "0102030405060708", + "ts": 1690901260493, + "fcnt": 3, + "port": 1, + "freq": 868300000, + "toa": 1319, + "dr": "SF12 BW125 4/5", + "ack": false, + "gws": [ + { + "rssi": -38, + "snr": 8.5, + "ts": 1690901260493, + "time": "2023-08-01T14:47:40.493Z", + "gweui": "1020304080706050", + "ant": 0 + }, + { + "rssi": -42, + "snr": 8.8, + "ts": 1690901260495, + "time": "2023-08-01T14:47:40.495Z", + "gweui": "1020304081716151", + "ant": 0 + } + ], + "bat": 143, + "data": "02023b0003003702710c60" +} diff --git a/VENDORS/Decentlab/DL-5TM/LORIOT/uplink/result_2.json b/VENDORS/Decentlab/DL-5TM/LORIOT/uplink/result_2.json new file mode 100644 index 00000000..5c37022a --- /dev/null +++ b/VENDORS/Decentlab/DL-5TM/LORIOT/uplink/result_2.json @@ -0,0 +1,21 @@ +{ + "deviceName": "571", + "deviceType": "DL-5TM", + "attributes": { + "lora_dev_eui": "0102030405060708", + "protocol_version": 2 + }, + "telemetry": [{ + "ts": 1690901260493, + "values": { + "dielectric_permittivity": 1.1, + "volumetric_water_content": -0.0215397767, + "soil_temperature": 22.5, + "battery_voltage": 3.168, + "lora_frame_counter": 3, + "lora_frame_port": 1, + "lora_frequency": 868300000, + "lora_spreading_factor": 12 + } + }] +} \ No newline at end of file diff --git a/VENDORS/Decentlab/DL-ALB/LORIOT/uplink/payload_2.json b/VENDORS/Decentlab/DL-ALB/LORIOT/uplink/payload_2.json new file mode 100644 index 00000000..4bf804b4 --- /dev/null +++ b/VENDORS/Decentlab/DL-ALB/LORIOT/uplink/payload_2.json @@ -0,0 +1,32 @@ +{ + "cmd": "gw", + "seqno": 4, + "EUI": "0102030405060708", + "ts": 1690901260493, + "fcnt": 3, + "port": 1, + "freq": 868300000, + "toa": 1319, + "dr": "SF12 BW125 4/5", + "ack": false, + "gws": [ + { + "rssi": -38, + "snr": 8.5, + "ts": 1690901260493, + "time": "2023-08-01T14:47:40.493Z", + "gweui": "1020304080706050", + "ant": 0 + }, + { + "rssi": -42, + "snr": 8.8, + "ts": 1690901260495, + "time": "2023-08-01T14:47:40.495Z", + "gweui": "1020304081716151", + "ant": 0 + } + ], + "bat": 143, + "data": "02023b0003003702710c60" +} diff --git a/VENDORS/Decentlab/DL-ALB/LORIOT/uplink/result_2.json b/VENDORS/Decentlab/DL-ALB/LORIOT/uplink/result_2.json new file mode 100644 index 00000000..70a51ba0 --- /dev/null +++ b/VENDORS/Decentlab/DL-ALB/LORIOT/uplink/result_2.json @@ -0,0 +1,21 @@ +{ + "deviceName": "571", + "deviceType": "DL-ALB", + "attributes": { + "lora_dev_eui": "0102030405060708", + "protocol_version": 2 + }, + "telemetry": [{ + "ts": 1690901260493, + "values": { + "incoming_radiation": -3271.3, + "reflected_radiation": -3214.3, + "albedo": 0, + "battery_voltage": 3.168, + "lora_frame_counter": 3, + "lora_frame_port": 1, + "lora_frequency": 868300000, + "lora_spreading_factor": 12 + } + }] +} \ No newline at end of file diff --git a/VENDORS/Decentlab/DL-ATM22/LORIOT/uplink/payload_2.json b/VENDORS/Decentlab/DL-ATM22/LORIOT/uplink/payload_2.json new file mode 100644 index 00000000..8d99f6d1 --- /dev/null +++ b/VENDORS/Decentlab/DL-ATM22/LORIOT/uplink/payload_2.json @@ -0,0 +1,32 @@ +{ + "cmd": "gw", + "seqno": 4, + "EUI": "0102030405060708", + "ts": 1690901260493, + "fcnt": 3, + "port": 1, + "freq": 868300000, + "toa": 1319, + "dr": "SF12 BW125 4/5", + "ack": false, + "gws": [ + { + "rssi": -38, + "snr": 8.5, + "ts": 1690901260493, + "time": "2023-08-01T14:47:40.493Z", + "gweui": "1020304080706050", + "ant": 0 + }, + { + "rssi": -42, + "snr": 8.8, + "ts": 1690901260495, + "time": "2023-08-01T14:47:40.495Z", + "gweui": "1020304081716151", + "ant": 0 + } + ], + "bat": 143, + "data": "0208c900020bf5" +} diff --git a/VENDORS/Decentlab/DL-ATM22/LORIOT/uplink/result_2.json b/VENDORS/Decentlab/DL-ATM22/LORIOT/uplink/result_2.json new file mode 100644 index 00000000..590c0fce --- /dev/null +++ b/VENDORS/Decentlab/DL-ATM22/LORIOT/uplink/result_2.json @@ -0,0 +1,18 @@ +{ + "deviceName": "2249", + "deviceType": "DL-ATM22", + "attributes": { + "lora_dev_eui": "0102030405060708", + "protocol_version": 2 + }, + "telemetry": [{ + "ts": 1690901260493, + "values": { + "battery_voltage": 3.061, + "lora_frame_counter": 3, + "lora_frame_port": 1, + "lora_frequency": 868300000, + "lora_spreading_factor": 12 + } + }] +} \ No newline at end of file diff --git a/VENDORS/Decentlab/DL-ATM41/LORIOT/uplink/payload_2.json b/VENDORS/Decentlab/DL-ATM41/LORIOT/uplink/payload_2.json new file mode 100644 index 00000000..a13c34a3 --- /dev/null +++ b/VENDORS/Decentlab/DL-ATM41/LORIOT/uplink/payload_2.json @@ -0,0 +1,32 @@ +{ + "cmd": "gw", + "seqno": 4, + "EUI": "0102030405060708", + "ts": 1690901260493, + "fcnt": 3, + "port": 1, + "freq": 868300000, + "toa": 1319, + "dr": "SF12 BW125 4/5", + "ack": false, + "gws": [ + { + "rssi": -38, + "snr": 8.5, + "ts": 1690901260493, + "time": "2023-08-01T14:47:40.493Z", + "gweui": "1020304080706050", + "ant": 0 + }, + { + "rssi": -42, + "snr": 8.8, + "ts": 1690901260495, + "time": "2023-08-01T14:47:40.495Z", + "gweui": "1020304081716151", + "ant": 0 + } + ], + "bat": 143, + "data": "02035a0003800a8000800080008009812b8014810880b4a57c820c810980027fe88056800880040bf5" +} diff --git a/VENDORS/Decentlab/DL-ATM41/LORIOT/uplink/result_2.json b/VENDORS/Decentlab/DL-ATM41/LORIOT/uplink/result_2.json new file mode 100644 index 00000000..cbddab65 --- /dev/null +++ b/VENDORS/Decentlab/DL-ATM41/LORIOT/uplink/result_2.json @@ -0,0 +1,35 @@ +{ + "deviceName": "858", + "deviceType": "DL-ATM41", + "attributes": { + "lora_dev_eui": "0102030405060708", + "protocol_version": 2 + }, + "telemetry": [{ + "ts": 1690901260493, + "values": { + "solar_radiation": 10, + "precipitation": 0, + "lightning_strike_count": 0, + "lightning_average_distance": 0, + "wind_speed": 0.09, + "wind_direction": 29.9, + "maximum_wind_speed": 0.2, + "air_temperature": 26.4, + "vapor_pressure": 1.8, + "atmospheric_pressure": 95.96, + "relative_humidity": 52.4, + "sensor_temperature_internal": 26.5, + "x_orientation_angle": 0.2, + "y_orientation_angle": -2.4, + "compass_heading": 86, + "north_wind_speed": 0.08, + "east_wind_speed": 0.04, + "battery_voltage": 3.061, + "lora_frame_counter": 3, + "lora_frame_port": 1, + "lora_frequency": 868300000, + "lora_spreading_factor": 12 + } + }] +} \ No newline at end of file diff --git a/VENDORS/Decentlab/DL-BLG/LORIOT/uplink/payload_2.json b/VENDORS/Decentlab/DL-BLG/LORIOT/uplink/payload_2.json new file mode 100644 index 00000000..eb615d43 --- /dev/null +++ b/VENDORS/Decentlab/DL-BLG/LORIOT/uplink/payload_2.json @@ -0,0 +1,32 @@ +{ + "cmd": "gw", + "seqno": 4, + "EUI": "0102030405060708", + "ts": 1690901260493, + "fcnt": 3, + "port": 1, + "freq": 868300000, + "toa": 1319, + "dr": "SF12 BW125 4/5", + "ack": false, + "gws": [ + { + "rssi": -38, + "snr": 8.5, + "ts": 1690901260493, + "time": "2023-08-01T14:47:40.493Z", + "gweui": "1020304080706050", + "ant": 0 + }, + { + "rssi": -42, + "snr": 8.8, + "ts": 1690901260495, + "time": "2023-08-01T14:47:40.495Z", + "gweui": "1020304081716151", + "ant": 0 + } + ], + "bat": 143, + "data": "0230c50003a40c00810c60" +} diff --git a/VENDORS/Decentlab/DL-BLG/LORIOT/uplink/result_2.json b/VENDORS/Decentlab/DL-BLG/LORIOT/uplink/result_2.json new file mode 100644 index 00000000..0fce6e05 --- /dev/null +++ b/VENDORS/Decentlab/DL-BLG/LORIOT/uplink/result_2.json @@ -0,0 +1,21 @@ +{ + "deviceName": "12485", + "deviceType": "DL-BLG", + "attributes": { + "lora_dev_eui": "0102030405060708", + "protocol_version": 2 + }, + "telemetry": [{ + "ts": 1690901260493, + "values": { + "voltage_ratio": 0.006409406661987305, + "thermistor_resistance": 115020.68221552655, + "temperature": 22.028848392450755, + "battery_voltage": 3.168, + "lora_frame_counter": 3, + "lora_frame_port": 1, + "lora_frequency": 868300000, + "lora_spreading_factor": 12 + } + }] +} \ No newline at end of file diff --git a/VENDORS/Decentlab/DL-CTD10/LORIOT/uplink/payload_2.json b/VENDORS/Decentlab/DL-CTD10/LORIOT/uplink/payload_2.json new file mode 100644 index 00000000..14525c19 --- /dev/null +++ b/VENDORS/Decentlab/DL-CTD10/LORIOT/uplink/payload_2.json @@ -0,0 +1,32 @@ +{ + "cmd": "gw", + "seqno": 4, + "EUI": "0102030405060708", + "ts": 1690901260493, + "fcnt": 3, + "port": 1, + "freq": 868300000, + "toa": 1319, + "dr": "SF12 BW125 4/5", + "ack": false, + "gws": [ + { + "rssi": -38, + "snr": 8.5, + "ts": 1690901260493, + "time": "2023-08-01T14:47:40.493Z", + "gweui": "1020304080706050", + "ant": 0 + }, + { + "rssi": -42, + "snr": 8.8, + "ts": 1690901260495, + "time": "2023-08-01T14:47:40.495Z", + "gweui": "1020304081716151", + "ant": 0 + } + ], + "bat": 143, + "data": "0207d900020c60" +} diff --git a/VENDORS/Decentlab/DL-CTD10/LORIOT/uplink/result_2.json b/VENDORS/Decentlab/DL-CTD10/LORIOT/uplink/result_2.json new file mode 100644 index 00000000..f0fb8977 --- /dev/null +++ b/VENDORS/Decentlab/DL-CTD10/LORIOT/uplink/result_2.json @@ -0,0 +1,18 @@ +{ + "deviceName": "2009", + "deviceType": "DL-CTD10", + "attributes": { + "lora_dev_eui": "0102030405060708", + "protocol_version": 2 + }, + "telemetry": [{ + "ts": 1690901260493, + "values": { + "battery_voltage": 3.168, + "lora_frame_counter": 3, + "lora_frame_port": 1, + "lora_frequency": 868300000, + "lora_spreading_factor": 12 + } + }] +} \ No newline at end of file diff --git a/VENDORS/Decentlab/DL-CWS/LORIOT/uplink/payload_2.json b/VENDORS/Decentlab/DL-CWS/LORIOT/uplink/payload_2.json new file mode 100644 index 00000000..d9ee4eb3 --- /dev/null +++ b/VENDORS/Decentlab/DL-CWS/LORIOT/uplink/payload_2.json @@ -0,0 +1,32 @@ +{ + "cmd": "gw", + "seqno": 4, + "EUI": "0102030405060708", + "ts": 1690901260493, + "fcnt": 3, + "port": 1, + "freq": 868300000, + "toa": 1319, + "dr": "SF12 BW125 4/5", + "ack": false, + "gws": [ + { + "rssi": -38, + "snr": 8.5, + "ts": 1690901260493, + "time": "2023-08-01T14:47:40.493Z", + "gweui": "1020304080706050", + "ant": 0 + }, + { + "rssi": -42, + "snr": 8.8, + "ts": 1690901260495, + "time": "2023-08-01T14:47:40.495Z", + "gweui": "1020304081716151", + "ant": 0 + } + ], + "bat": 143, + "data": "02463900038a778a95977a874c80478a5e0b74" +} diff --git a/VENDORS/Decentlab/DL-CWS/LORIOT/uplink/result_2.json b/VENDORS/Decentlab/DL-CWS/LORIOT/uplink/result_2.json new file mode 100644 index 00000000..ea4273e2 --- /dev/null +++ b/VENDORS/Decentlab/DL-CWS/LORIOT/uplink/result_2.json @@ -0,0 +1,24 @@ +{ + "deviceName": "17977", + "deviceType": "DL-CWS", + "attributes": { + "lora_dev_eui": "0102030405060708", + "protocol_version": 2 + }, + "telemetry": [{ + "ts": 1690901260493, + "values": { + "surface_temperature": 26.79, + "air_temperature": 27.09, + "air_humidity": 60.1, + "dew_point": 18.68, + "angle": 71, + "sensor_temperature": 26.54, + "battery_voltage": 2.932, + "lora_frame_counter": 3, + "lora_frame_port": 1, + "lora_frequency": 868300000, + "lora_spreading_factor": 12 + } + }] +} \ No newline at end of file diff --git a/VENDORS/Decentlab/DL-CWS2/LORIOT/uplink/payload_2.json b/VENDORS/Decentlab/DL-CWS2/LORIOT/uplink/payload_2.json new file mode 100644 index 00000000..3aeb0eb2 --- /dev/null +++ b/VENDORS/Decentlab/DL-CWS2/LORIOT/uplink/payload_2.json @@ -0,0 +1,32 @@ +{ + "cmd": "gw", + "seqno": 4, + "EUI": "0102030405060708", + "ts": 1690901260493, + "fcnt": 3, + "port": 1, + "freq": 868300000, + "toa": 1319, + "dr": "SF12 BW125 4/5", + "ack": false, + "gws": [ + { + "rssi": -38, + "snr": 8.5, + "ts": 1690901260493, + "time": "2023-08-01T14:47:40.493Z", + "gweui": "1020304080706050", + "ant": 0 + }, + { + "rssi": -42, + "snr": 8.8, + "ts": 1690901260495, + "time": "2023-08-01T14:47:40.495Z", + "gweui": "1020304081716151", + "ant": 0 + } + ], + "bat": 143, + "data": "0258c000074676fa0a81c9813fa6d88137802581300b91" +} diff --git a/VENDORS/Decentlab/DL-CWS2/LORIOT/uplink/result_2.json b/VENDORS/Decentlab/DL-CWS2/LORIOT/uplink/result_2.json new file mode 100644 index 00000000..c3b8d794 --- /dev/null +++ b/VENDORS/Decentlab/DL-CWS2/LORIOT/uplink/result_2.json @@ -0,0 +1,26 @@ +{ + "deviceName": "22720", + "deviceType": "DL-CWS2", + "attributes": { + "lora_dev_eui": "0102030405060708", + "protocol_version": 2 + }, + "telemetry": [{ + "ts": 1690901260493, + "values": { + "air_temperature_radiation_shield": 3.167391470206759, + "air_humidity_radiation_shield": 97.67299916075379, + "surface_temperature": 4.57, + "air_temperature": 3.19, + "air_humidity": 99.44, + "dew_point": 3.11, + "angle": 37, + "sensor_temperature": 3.04, + "battery_voltage": 2.961, + "lora_frame_counter": 3, + "lora_frame_port": 1, + "lora_frequency": 868300000, + "lora_spreading_factor": 12 + } + }] +} \ No newline at end of file diff --git a/VENDORS/Decentlab/DL-DLR2-002/LORIOT/uplink/payload_1.json b/VENDORS/Decentlab/DL-DLR2-002/LORIOT/uplink/payload_1.json new file mode 100644 index 00000000..6475bb71 --- /dev/null +++ b/VENDORS/Decentlab/DL-DLR2-002/LORIOT/uplink/payload_1.json @@ -0,0 +1,32 @@ +{ + "cmd": "gw", + "seqno": 4, + "EUI": "0102030405060708", + "ts": 1690901260493, + "fcnt": 3, + "port": 1, + "freq": 868300000, + "toa": 1319, + "dr": "SF12 BW125 4/5", + "ack": false, + "gws": [ + { + "rssi": -38, + "snr": 8.5, + "ts": 1690901260493, + "time": "2023-08-01T14:47:40.493Z", + "gweui": "1020304080706050", + "ant": 0 + }, + { + "rssi": -42, + "snr": 8.8, + "ts": 1690901260495, + "time": "2023-08-01T14:47:40.495Z", + "gweui": "1020304081716151", + "ant": 0 + } + ], + "bat": 143, + "data": "02199e000300000258000000000c9b" +} diff --git a/VENDORS/Decentlab/DL-DLR2-002/LORIOT/uplink/result_1.json b/VENDORS/Decentlab/DL-DLR2-002/LORIOT/uplink/result_1.json new file mode 100644 index 00000000..9f235539 --- /dev/null +++ b/VENDORS/Decentlab/DL-DLR2-002/LORIOT/uplink/result_1.json @@ -0,0 +1,21 @@ +{ + "deviceName": "6558", + "deviceType": "DL-DLR2-002", + "attributes": { + "lora_dev_eui": "0102030405060708", + "protocol_version": 2 + }, + "telemetry": [{ + "ts": 1690901260493, + "values": { + "pulse_count": 0, + "pulse_interval": 600, + "cumulative_pulse_count": 0, + "battery_voltage": 3.227, + "lora_frame_counter": 3, + "lora_frame_port": 1, + "lora_frequency": 868300000, + "lora_spreading_factor": 12 + } + }] +} \ No newline at end of file diff --git a/VENDORS/Decentlab/DL-DLR2-003/LORIOT/uplink/payload_1.json b/VENDORS/Decentlab/DL-DLR2-003/LORIOT/uplink/payload_1.json new file mode 100644 index 00000000..6475bb71 --- /dev/null +++ b/VENDORS/Decentlab/DL-DLR2-003/LORIOT/uplink/payload_1.json @@ -0,0 +1,32 @@ +{ + "cmd": "gw", + "seqno": 4, + "EUI": "0102030405060708", + "ts": 1690901260493, + "fcnt": 3, + "port": 1, + "freq": 868300000, + "toa": 1319, + "dr": "SF12 BW125 4/5", + "ack": false, + "gws": [ + { + "rssi": -38, + "snr": 8.5, + "ts": 1690901260493, + "time": "2023-08-01T14:47:40.493Z", + "gweui": "1020304080706050", + "ant": 0 + }, + { + "rssi": -42, + "snr": 8.8, + "ts": 1690901260495, + "time": "2023-08-01T14:47:40.495Z", + "gweui": "1020304081716151", + "ant": 0 + } + ], + "bat": 143, + "data": "02199e000300000258000000000c9b" +} diff --git a/VENDORS/Decentlab/DL-DLR2-003/LORIOT/uplink/result_1.json b/VENDORS/Decentlab/DL-DLR2-003/LORIOT/uplink/result_1.json new file mode 100644 index 00000000..9f235539 --- /dev/null +++ b/VENDORS/Decentlab/DL-DLR2-003/LORIOT/uplink/result_1.json @@ -0,0 +1,21 @@ +{ + "deviceName": "6558", + "deviceType": "DL-DLR2-002", + "attributes": { + "lora_dev_eui": "0102030405060708", + "protocol_version": 2 + }, + "telemetry": [{ + "ts": 1690901260493, + "values": { + "pulse_count": 0, + "pulse_interval": 600, + "cumulative_pulse_count": 0, + "battery_voltage": 3.227, + "lora_frame_counter": 3, + "lora_frame_port": 1, + "lora_frequency": 868300000, + "lora_spreading_factor": 12 + } + }] +} \ No newline at end of file diff --git a/VENDORS/Decentlab/DL-DLR2-004/LORIOT/uplink/payload_2.json b/VENDORS/Decentlab/DL-DLR2-004/LORIOT/uplink/payload_2.json new file mode 100644 index 00000000..9956fb23 --- /dev/null +++ b/VENDORS/Decentlab/DL-DLR2-004/LORIOT/uplink/payload_2.json @@ -0,0 +1,32 @@ +{ + "cmd": "gw", + "seqno": 4, + "EUI": "0102030405060708", + "ts": 1690901260493, + "fcnt": 3, + "port": 1, + "freq": 868300000, + "toa": 1319, + "dr": "SF12 BW125 4/5", + "ack": false, + "gws": [ + { + "rssi": -38, + "snr": 8.5, + "ts": 1690901260493, + "time": "2023-08-01T14:47:40.493Z", + "gweui": "1020304080706050", + "ant": 0 + }, + { + "rssi": -42, + "snr": 8.8, + "ts": 1690901260495, + "time": "2023-08-01T14:47:40.495Z", + "gweui": "1020304081716151", + "ant": 0 + } + ], + "bat": 143, + "data": "0208b200038bb80c60" +} diff --git a/VENDORS/Decentlab/DL-DLR2-004/LORIOT/uplink/result_2.json b/VENDORS/Decentlab/DL-DLR2-004/LORIOT/uplink/result_2.json new file mode 100644 index 00000000..208f668e --- /dev/null +++ b/VENDORS/Decentlab/DL-DLR2-004/LORIOT/uplink/result_2.json @@ -0,0 +1,19 @@ +{ + "deviceName": "2226", + "deviceType": "DL-DLR2-004", + "attributes": { + "lora_dev_eui": "0102030405060708", + "protocol_version": 2 + }, + "telemetry": [{ + "ts": 1690901260493, + "values": { + "current": 13.73291015625, + "battery_voltage": 3.168, + "lora_frame_counter": 3, + "lora_frame_port": 1, + "lora_frequency": 868300000, + "lora_spreading_factor": 12 + } + }] +} \ No newline at end of file diff --git a/VENDORS/Decentlab/DL-DLR2-005/LORIOT/uplink/payload_2.json b/VENDORS/Decentlab/DL-DLR2-005/LORIOT/uplink/payload_2.json new file mode 100644 index 00000000..b32b3721 --- /dev/null +++ b/VENDORS/Decentlab/DL-DLR2-005/LORIOT/uplink/payload_2.json @@ -0,0 +1,32 @@ +{ + "cmd": "gw", + "seqno": 4, + "EUI": "0102030405060708", + "ts": 1690901260493, + "fcnt": 3, + "port": 1, + "freq": 868300000, + "toa": 1319, + "dr": "SF12 BW125 4/5", + "ack": false, + "gws": [ + { + "rssi": -38, + "snr": 8.5, + "ts": 1690901260493, + "time": "2023-08-01T14:47:40.493Z", + "gweui": "1020304080706050", + "ant": 0 + }, + { + "rssi": -42, + "snr": 8.8, + "ts": 1690901260495, + "time": "2023-08-01T14:47:40.495Z", + "gweui": "1020304081716151", + "ant": 0 + } + ], + "bat": 143, + "data": "02113a00020c6d" +} diff --git a/VENDORS/Decentlab/DL-DLR2-005/LORIOT/uplink/result_2.json b/VENDORS/Decentlab/DL-DLR2-005/LORIOT/uplink/result_2.json new file mode 100644 index 00000000..3547be06 --- /dev/null +++ b/VENDORS/Decentlab/DL-DLR2-005/LORIOT/uplink/result_2.json @@ -0,0 +1,18 @@ +{ + "deviceName": "4410", + "deviceType": "DL-DLR2-004", + "attributes": { + "lora_dev_eui": "0102030405060708", + "protocol_version": 2 + }, + "telemetry": [{ + "ts": 1690901260493, + "values": { + "battery_voltage": 3.181, + "lora_frame_counter": 3, + "lora_frame_port": 1, + "lora_frequency": 868300000, + "lora_spreading_factor": 12 + } + }] +} \ No newline at end of file diff --git a/VENDORS/Decentlab/DL-DLR2-006/LORIOT/uplink/payload_2.json b/VENDORS/Decentlab/DL-DLR2-006/LORIOT/uplink/payload_2.json new file mode 100644 index 00000000..3c69bb97 --- /dev/null +++ b/VENDORS/Decentlab/DL-DLR2-006/LORIOT/uplink/payload_2.json @@ -0,0 +1,32 @@ +{ + "cmd": "gw", + "seqno": 4, + "EUI": "0102030405060708", + "ts": 1690901260493, + "fcnt": 3, + "port": 1, + "freq": 868300000, + "toa": 1319, + "dr": "SF12 BW125 4/5", + "ack": false, + "gws": [ + { + "rssi": -38, + "snr": 8.5, + "ts": 1690901260493, + "time": "2023-08-01T14:47:40.493Z", + "gweui": "1020304080706050", + "ant": 0 + }, + { + "rssi": -42, + "snr": 8.8, + "ts": 1690901260495, + "time": "2023-08-01T14:47:40.495Z", + "gweui": "1020304081716151", + "ant": 0 + } + ], + "bat": 143, + "data": "02111100020c54" +} diff --git a/VENDORS/Decentlab/DL-DLR2-006/LORIOT/uplink/result_2.json b/VENDORS/Decentlab/DL-DLR2-006/LORIOT/uplink/result_2.json new file mode 100644 index 00000000..ca66a1d8 --- /dev/null +++ b/VENDORS/Decentlab/DL-DLR2-006/LORIOT/uplink/result_2.json @@ -0,0 +1,18 @@ +{ + "deviceName": "4369", + "deviceType": "DL-DLR2-006", + "attributes": { + "lora_dev_eui": "0102030405060708", + "protocol_version": 2 + }, + "telemetry": [{ + "ts": 1690901260493, + "values": { + "battery_voltage": 3.156, + "lora_frame_counter": 3, + "lora_frame_port": 1, + "lora_frequency": 868300000, + "lora_spreading_factor": 12 + } + }] +} \ No newline at end of file diff --git a/VENDORS/Decentlab/DL-DLR2-008/LORIOT/uplink/payload_2.json b/VENDORS/Decentlab/DL-DLR2-008/LORIOT/uplink/payload_2.json new file mode 100644 index 00000000..b215d68d --- /dev/null +++ b/VENDORS/Decentlab/DL-DLR2-008/LORIOT/uplink/payload_2.json @@ -0,0 +1,32 @@ +{ + "cmd": "gw", + "seqno": 4, + "EUI": "0102030405060708", + "ts": 1690901260493, + "fcnt": 3, + "port": 1, + "freq": 868300000, + "toa": 1319, + "dr": "SF12 BW125 4/5", + "ack": false, + "gws": [ + { + "rssi": -38, + "snr": 8.5, + "ts": 1690901260493, + "time": "2023-08-01T14:47:40.493Z", + "gweui": "1020304080706050", + "ant": 0 + }, + { + "rssi": -42, + "snr": 8.8, + "ts": 1690901260495, + "time": "2023-08-01T14:47:40.495Z", + "gweui": "1020304081716151", + "ant": 0 + } + ], + "bat": 143, + "data": "0207df000317de008d0c60" +} diff --git a/VENDORS/Decentlab/DL-DLR2-008/LORIOT/uplink/result_2.json b/VENDORS/Decentlab/DL-DLR2-008/LORIOT/uplink/result_2.json new file mode 100644 index 00000000..0f67e61b --- /dev/null +++ b/VENDORS/Decentlab/DL-DLR2-008/LORIOT/uplink/result_2.json @@ -0,0 +1,19 @@ +{ + "deviceName": "2015", + "deviceType": "DL-DLR2-008", + "attributes": { + "lora_dev_eui": "0102030405060708", + "protocol_version": 2 + }, + "telemetry": [{ + "ts": 1690901260493, + "values": { + "temperature": 20.031064968287208, + "battery_voltage": 3.168, + "lora_frame_counter": 3, + "lora_frame_port": 1, + "lora_frequency": 868300000, + "lora_spreading_factor": 12 + } + }] +} \ No newline at end of file diff --git a/VENDORS/Decentlab/DL-DLR2-009/LORIOT/uplink/payload_2.json b/VENDORS/Decentlab/DL-DLR2-009/LORIOT/uplink/payload_2.json new file mode 100644 index 00000000..20d05d94 --- /dev/null +++ b/VENDORS/Decentlab/DL-DLR2-009/LORIOT/uplink/payload_2.json @@ -0,0 +1,32 @@ +{ + "cmd": "gw", + "seqno": 4, + "EUI": "0102030405060708", + "ts": 1690901260493, + "fcnt": 3, + "port": 1, + "freq": 868300000, + "toa": 1319, + "dr": "SF12 BW125 4/5", + "ack": false, + "gws": [ + { + "rssi": -38, + "snr": 8.5, + "ts": 1690901260493, + "time": "2023-08-01T14:47:40.493Z", + "gweui": "1020304080706050", + "ant": 0 + }, + { + "rssi": -42, + "snr": 8.8, + "ts": 1690901260495, + "time": "2023-08-01T14:47:40.495Z", + "gweui": "1020304081716151", + "ant": 0 + } + ], + "bat": 143, + "data": "024c620003573400ad0ae1" +} diff --git a/VENDORS/Decentlab/DL-DLR2-009/LORIOT/uplink/result_2.json b/VENDORS/Decentlab/DL-DLR2-009/LORIOT/uplink/result_2.json new file mode 100644 index 00000000..b552e94d --- /dev/null +++ b/VENDORS/Decentlab/DL-DLR2-009/LORIOT/uplink/result_2.json @@ -0,0 +1,20 @@ +{ + "deviceName": "19554", + "deviceType": "DL-DLR2-009", + "attributes": { + "lora_dev_eui": "0102030405060708", + "protocol_version": 2 + }, + "telemetry": [{ + "ts": 1690901260493, + "values": { + "thermistor_resistance": 1097.0478279778865, + "temperature": 24.908127512458456, + "battery_voltage": 2.785, + "lora_frame_counter": 3, + "lora_frame_port": 1, + "lora_frequency": 868300000, + "lora_spreading_factor": 12 + } + }] +} \ No newline at end of file diff --git a/VENDORS/Decentlab/DL-DLR2-010/LORIOT/uplink/payload_2.json b/VENDORS/Decentlab/DL-DLR2-010/LORIOT/uplink/payload_2.json new file mode 100644 index 00000000..3ee3ac17 --- /dev/null +++ b/VENDORS/Decentlab/DL-DLR2-010/LORIOT/uplink/payload_2.json @@ -0,0 +1,32 @@ +{ + "cmd": "gw", + "seqno": 4, + "EUI": "0102030405060708", + "ts": 1690901260493, + "fcnt": 3, + "port": 1, + "freq": 868300000, + "toa": 1319, + "dr": "SF12 BW125 4/5", + "ack": false, + "gws": [ + { + "rssi": -38, + "snr": 8.5, + "ts": 1690901260493, + "time": "2023-08-01T14:47:40.493Z", + "gweui": "1020304080706050", + "ant": 0 + }, + { + "rssi": -42, + "snr": 8.8, + "ts": 1690901260495, + "time": "2023-08-01T14:47:40.495Z", + "gweui": "1020304081716151", + "ant": 0 + } + ], + "bat": 143, + "data": "02198f0007000402580bf0000100000258dece00000c33" +} diff --git a/VENDORS/Decentlab/DL-DLR2-010/LORIOT/uplink/result_2.json b/VENDORS/Decentlab/DL-DLR2-010/LORIOT/uplink/result_2.json new file mode 100644 index 00000000..46d7387f --- /dev/null +++ b/VENDORS/Decentlab/DL-DLR2-010/LORIOT/uplink/result_2.json @@ -0,0 +1,24 @@ +{ + "deviceName": "6543", + "deviceType": "DL-DLR2-010", + "attributes": { + "lora_dev_eui": "0102030405060708", + "protocol_version": 2 + }, + "telemetry": [{ + "ts": 1690901260493, + "values": { + "ch0_pulse_count": 4, + "ch0_pulse_interval": 600, + "ch0_cumulative_pulse_count": 68592, + "ch1_pulse_count": 0, + "ch1_pulse_interval": 600, + "ch1_cumulative_pulse_count": 57038, + "battery_voltage": 3.123, + "lora_frame_counter": 3, + "lora_frame_port": 1, + "lora_frequency": 868300000, + "lora_spreading_factor": 12 + } + }] +} \ No newline at end of file diff --git a/VENDORS/Decentlab/DL-DLR2-011/LORIOT/uplink/payload_2.json b/VENDORS/Decentlab/DL-DLR2-011/LORIOT/uplink/payload_2.json new file mode 100644 index 00000000..43ef14bb --- /dev/null +++ b/VENDORS/Decentlab/DL-DLR2-011/LORIOT/uplink/payload_2.json @@ -0,0 +1,32 @@ +{ + "cmd": "gw", + "seqno": 4, + "EUI": "0102030405060708", + "ts": 1690901260493, + "fcnt": 3, + "port": 1, + "freq": 868300000, + "toa": 1319, + "dr": "SF12 BW125 4/5", + "ack": false, + "gws": [ + { + "rssi": -38, + "snr": 8.5, + "ts": 1690901260493, + "time": "2023-08-01T14:47:40.493Z", + "gweui": "1020304080706050", + "ant": 0 + }, + { + "rssi": -42, + "snr": 8.8, + "ts": 1690901260495, + "time": "2023-08-01T14:47:40.495Z", + "gweui": "1020304081716151", + "ant": 0 + } + ], + "bat": 143, + "data": "02437100040af9" +} diff --git a/VENDORS/Decentlab/DL-DLR2-011/LORIOT/uplink/result_2.json b/VENDORS/Decentlab/DL-DLR2-011/LORIOT/uplink/result_2.json new file mode 100644 index 00000000..c5d01b7a --- /dev/null +++ b/VENDORS/Decentlab/DL-DLR2-011/LORIOT/uplink/result_2.json @@ -0,0 +1,18 @@ +{ + "deviceName": "17265", + "deviceType": "DL-DLR2-011", + "attributes": { + "lora_dev_eui": "0102030405060708", + "protocol_version": 2 + }, + "telemetry": [{ + "ts": 1690901260493, + "values": { + "battery_voltage": 2.809, + "lora_frame_counter": 3, + "lora_frame_port": 1, + "lora_frequency": 868300000, + "lora_spreading_factor": 12 + } + }] +} \ No newline at end of file diff --git a/VENDORS/Decentlab/DL-DLR2-012/LORIOT/uplink/payload_2.json b/VENDORS/Decentlab/DL-DLR2-012/LORIOT/uplink/payload_2.json new file mode 100644 index 00000000..4475d785 --- /dev/null +++ b/VENDORS/Decentlab/DL-DLR2-012/LORIOT/uplink/payload_2.json @@ -0,0 +1,32 @@ +{ + "cmd": "gw", + "seqno": 4, + "EUI": "0102030405060708", + "ts": 1690901260493, + "fcnt": 3, + "port": 1, + "freq": 868300000, + "toa": 1319, + "dr": "SF12 BW125 4/5", + "ack": false, + "gws": [ + { + "rssi": -38, + "snr": 8.5, + "ts": 1690901260493, + "time": "2023-08-01T14:47:40.493Z", + "gweui": "1020304080706050", + "ant": 0 + }, + { + "rssi": -42, + "snr": 8.8, + "ts": 1690901260495, + "time": "2023-08-01T14:47:40.495Z", + "gweui": "1020304081716151", + "ant": 0 + } + ], + "bat": 143, + "data": "0217830003162e00870c33" +} diff --git a/VENDORS/Decentlab/DL-DLR2-012/LORIOT/uplink/result_2.json b/VENDORS/Decentlab/DL-DLR2-012/LORIOT/uplink/result_2.json new file mode 100644 index 00000000..3c8fb159 --- /dev/null +++ b/VENDORS/Decentlab/DL-DLR2-012/LORIOT/uplink/result_2.json @@ -0,0 +1,19 @@ +{ + "deviceName": "6019", + "deviceType": "DL-DLR2-012", + "attributes": { + "lora_dev_eui": "0102030405060708", + "protocol_version": 2 + }, + "telemetry": [{ + "ts": 1690901260493, + "values": { + "strain_gauge": 1713.0065082323433, + "battery_voltage": 3.123, + "lora_frame_counter": 3, + "lora_frame_port": 1, + "lora_frequency": 868300000, + "lora_spreading_factor": 12 + } + }] +} \ No newline at end of file diff --git a/VENDORS/Decentlab/DL-DS18/LORIOT/uplink/payload_2.json b/VENDORS/Decentlab/DL-DS18/LORIOT/uplink/payload_2.json new file mode 100644 index 00000000..a9a9379b --- /dev/null +++ b/VENDORS/Decentlab/DL-DS18/LORIOT/uplink/payload_2.json @@ -0,0 +1,32 @@ +{ + "cmd": "gw", + "seqno": 4, + "EUI": "0102030405060708", + "ts": 1690901260493, + "fcnt": 3, + "port": 1, + "freq": 868300000, + "toa": 1319, + "dr": "SF12 BW125 4/5", + "ack": false, + "gws": [ + { + "rssi": -38, + "snr": 8.5, + "ts": 1690901260493, + "time": "2023-08-01T14:47:40.493Z", + "gweui": "1020304080706050", + "ant": 0 + }, + { + "rssi": -42, + "snr": 8.8, + "ts": 1690901260495, + "time": "2023-08-01T14:47:40.495Z", + "gweui": "1020304081716151", + "ant": 0 + } + ], + "bat": 143, + "data": "02023d0003815e0c15" +} diff --git a/VENDORS/Decentlab/DL-DS18/LORIOT/uplink/result_2.json b/VENDORS/Decentlab/DL-DS18/LORIOT/uplink/result_2.json new file mode 100644 index 00000000..02fc1e8c --- /dev/null +++ b/VENDORS/Decentlab/DL-DS18/LORIOT/uplink/result_2.json @@ -0,0 +1,19 @@ +{ + "deviceName": "573", + "deviceType": "DL-DS18", + "attributes": { + "lora_dev_eui": "0102030405060708", + "protocol_version": 2 + }, + "telemetry": [{ + "ts": 1690901260493, + "values": { + "temperature": 21.875, + "battery_voltage": 3.093, + "lora_frame_counter": 3, + "lora_frame_port": 1, + "lora_frequency": 868300000, + "lora_spreading_factor": 12 + } + }] +} \ No newline at end of file diff --git a/VENDORS/Decentlab/DL-DWS/LORIOT/uplink/payload_2.json b/VENDORS/Decentlab/DL-DWS/LORIOT/uplink/payload_2.json new file mode 100644 index 00000000..b447fdaf --- /dev/null +++ b/VENDORS/Decentlab/DL-DWS/LORIOT/uplink/payload_2.json @@ -0,0 +1,32 @@ +{ + "cmd": "gw", + "seqno": 4, + "EUI": "0102030405060708", + "ts": 1690901260493, + "fcnt": 3, + "port": 1, + "freq": 868300000, + "toa": 1319, + "dr": "SF12 BW125 4/5", + "ack": false, + "gws": [ + { + "rssi": -38, + "snr": 8.5, + "ts": 1690901260493, + "time": "2023-08-01T14:47:40.493Z", + "gweui": "1020304080706050", + "ant": 0 + }, + { + "rssi": -42, + "snr": 8.8, + "ts": 1690901260495, + "time": "2023-08-01T14:47:40.495Z", + "gweui": "1020304081716151", + "ant": 0 + } + ], + "bat": 143, + "data": "0203d400033bf67fff3bf60c60" +} diff --git a/VENDORS/Decentlab/DL-DWS/LORIOT/uplink/result_2.json b/VENDORS/Decentlab/DL-DWS/LORIOT/uplink/result_2.json new file mode 100644 index 00000000..7163580e --- /dev/null +++ b/VENDORS/Decentlab/DL-DWS/LORIOT/uplink/result_2.json @@ -0,0 +1,20 @@ +{ + "deviceName": "980", + "deviceType": "DL-DWS", + "attributes": { + "lora_dev_eui": "0102030405060708", + "protocol_version": 2 + }, + "telemetry": [{ + "ts": 1690901260493, + "values": { + "frequency": 15350.468459120457, + "weight": 2390.4101368512333, + "battery_voltage": 3.168, + "lora_frame_counter": 3, + "lora_frame_port": 1, + "lora_frequency": 868300000, + "lora_spreading_factor": 12 + } + }] +} \ No newline at end of file diff --git a/VENDORS/Decentlab/DL-GMM/LORIOT/uplink/payload_2.json b/VENDORS/Decentlab/DL-GMM/LORIOT/uplink/payload_2.json new file mode 100644 index 00000000..69524752 --- /dev/null +++ b/VENDORS/Decentlab/DL-GMM/LORIOT/uplink/payload_2.json @@ -0,0 +1,32 @@ +{ + "cmd": "gw", + "seqno": 4, + "EUI": "0102030405060708", + "ts": 1690901260493, + "fcnt": 3, + "port": 1, + "freq": 868300000, + "toa": 1319, + "dr": "SF12 BW125 4/5", + "ack": false, + "gws": [ + { + "rssi": -38, + "snr": 8.5, + "ts": 1690901260493, + "time": "2023-08-01T14:47:40.493Z", + "gweui": "1020304080706050", + "ant": 0 + }, + { + "rssi": -42, + "snr": 8.8, + "ts": 1690901260495, + "time": "2023-08-01T14:47:40.495Z", + "gweui": "1020304081716151", + "ant": 0 + } + ], + "bat": 143, + "data": "02532b00038726892081148297a57380cf81700bbc" +} diff --git a/VENDORS/Decentlab/DL-GMM/LORIOT/uplink/result_2.json b/VENDORS/Decentlab/DL-GMM/LORIOT/uplink/result_2.json new file mode 100644 index 00000000..87c3a449 --- /dev/null +++ b/VENDORS/Decentlab/DL-GMM/LORIOT/uplink/result_2.json @@ -0,0 +1,25 @@ +{ + "deviceName": "21291", + "deviceType": "DL-GMM", + "attributes": { + "lora_dev_eui": "0102030405060708", + "protocol_version": 2 + }, + "telemetry": [{ + "ts": 1690901260493, + "values": { + "photosynthetically_active_radiation": 183, + "air_temperature": 23.36, + "air_humidity": 27.6, + "co2_concentration": 663, + "atmospheric_pressure": 95.87, + "vapor_pressure_deficit": 2.07, + "dew_point": 3.68, + "battery_voltage": 3.004, + "lora_frame_counter": 3, + "lora_frame_port": 1, + "lora_frequency": 868300000, + "lora_spreading_factor": 12 + } + }] +} \ No newline at end of file diff --git a/VENDORS/Decentlab/DL-IAM/LORIOT/uplink/payload_3.json b/VENDORS/Decentlab/DL-IAM/LORIOT/uplink/payload_3.json new file mode 100644 index 00000000..4a961eea --- /dev/null +++ b/VENDORS/Decentlab/DL-IAM/LORIOT/uplink/payload_3.json @@ -0,0 +1,32 @@ +{ + "cmd": "gw", + "seqno": 4, + "EUI": "0102030405060708", + "ts": 1690901260493, + "fcnt": 3, + "port": 1, + "freq": 868300000, + "toa": 1319, + "dr": "SF12 BW125 4/5", + "ack": false, + "gws": [ + { + "rssi": -38, + "snr": 8.5, + "ts": 1690901260493, + "time": "2023-08-01T14:47:40.493Z", + "gweui": "1020304080706050", + "ant": 0 + }, + { + "rssi": -42, + "snr": 8.8, + "ts": 1690901260495, + "time": "2023-08-01T14:47:40.495Z", + "gweui": "1020304081716151", + "ant": 0 + } + ], + "bat": 143, + "data": "020bbd007f0b926a515d48bc4e0262006981c7000093d4000b0111" +} diff --git a/VENDORS/Decentlab/DL-IAM/LORIOT/uplink/result_3.json b/VENDORS/Decentlab/DL-IAM/LORIOT/uplink/result_3.json new file mode 100644 index 00000000..ec16c066 --- /dev/null +++ b/VENDORS/Decentlab/DL-IAM/LORIOT/uplink/result_3.json @@ -0,0 +1,29 @@ +{ + "deviceName": "3005", + "deviceType": "DL-IAM", + "attributes": { + "lora_dev_eui": "0102030405060708", + "protocol_version": 2 + }, + "telemetry": [{ + "ts": 1690901260493, + "values": { + "battery_voltage": 2.962, + "air_temperature": 27.67833981841764, + "air_humidity": 36.438544289311054, + "barometric_pressure": 96412, + "ambient_light_visible_infrared": 610, + "ambient_light_infrared": 105, + "illuminance": 678.76512, + "co2_concentration": 455, + "co2_sensor_status": 0, + "raw_ir_reading": 37844, + "activity_counter": 11, + "total_voc": 273, + "lora_frame_counter": 3, + "lora_frame_port": 1, + "lora_frequency": 868300000, + "lora_spreading_factor": 12 + } + }] +} \ No newline at end of file diff --git a/VENDORS/Decentlab/DL-IFD/LORIOT/uplink/payload_2.json b/VENDORS/Decentlab/DL-IFD/LORIOT/uplink/payload_2.json new file mode 100644 index 00000000..5032c69e --- /dev/null +++ b/VENDORS/Decentlab/DL-IFD/LORIOT/uplink/payload_2.json @@ -0,0 +1,32 @@ +{ + "cmd": "gw", + "seqno": 4, + "EUI": "0102030405060708", + "ts": 1690901260493, + "fcnt": 3, + "port": 1, + "freq": 868300000, + "toa": 1319, + "dr": "SF12 BW125 4/5", + "ack": false, + "gws": [ + { + "rssi": -38, + "snr": 8.5, + "ts": 1690901260493, + "time": "2023-08-01T14:47:40.493Z", + "gweui": "1020304080706050", + "ant": 0 + }, + { + "rssi": -42, + "snr": 8.8, + "ts": 1690901260495, + "time": "2023-08-01T14:47:40.495Z", + "gweui": "1020304081716151", + "ant": 0 + } + ], + "bat": 143, + "data": "0256dc000302bc0c48" +} diff --git a/VENDORS/Decentlab/DL-IFD/LORIOT/uplink/result_2.json b/VENDORS/Decentlab/DL-IFD/LORIOT/uplink/result_2.json new file mode 100644 index 00000000..196af2b4 --- /dev/null +++ b/VENDORS/Decentlab/DL-IFD/LORIOT/uplink/result_2.json @@ -0,0 +1,19 @@ +{ + "deviceName": "22236", + "deviceType": "DL-IFD", + "attributes": { + "lora_dev_eui": "0102030405060708", + "protocol_version": 2 + }, + "telemetry": [{ + "ts": 1690901260493, + "values": { + "fruit_size": 7, + "battery_voltage": 3.144, + "lora_frame_counter": 3, + "lora_frame_port": 1, + "lora_frequency": 868300000, + "lora_spreading_factor": 12 + } + }] +} \ No newline at end of file diff --git a/VENDORS/Decentlab/DL-ILT/LORIOT/uplink/payload_2.json b/VENDORS/Decentlab/DL-ILT/LORIOT/uplink/payload_2.json new file mode 100644 index 00000000..402f07b0 --- /dev/null +++ b/VENDORS/Decentlab/DL-ILT/LORIOT/uplink/payload_2.json @@ -0,0 +1,32 @@ +{ + "cmd": "gw", + "seqno": 4, + "EUI": "0102030405060708", + "ts": 1690901260493, + "fcnt": 3, + "port": 1, + "freq": 868300000, + "toa": 1319, + "dr": "SF12 BW125 4/5", + "ack": false, + "gws": [ + { + "rssi": -38, + "snr": 8.5, + "ts": 1690901260493, + "time": "2023-08-01T14:47:40.493Z", + "gweui": "1020304080706050", + "ant": 0 + }, + { + "rssi": -42, + "snr": 8.8, + "ts": 1690901260495, + "time": "2023-08-01T14:47:40.495Z", + "gweui": "1020304081716151", + "ant": 0 + } + ], + "bat": 143, + "data": "0256d200020c9d" +} diff --git a/VENDORS/Decentlab/DL-ILT/LORIOT/uplink/result_2.json b/VENDORS/Decentlab/DL-ILT/LORIOT/uplink/result_2.json new file mode 100644 index 00000000..f64270d6 --- /dev/null +++ b/VENDORS/Decentlab/DL-ILT/LORIOT/uplink/result_2.json @@ -0,0 +1,18 @@ +{ + "deviceName": "22226", + "deviceType": "DL-ILT", + "attributes": { + "lora_dev_eui": "0102030405060708", + "protocol_version": 2 + }, + "telemetry": [{ + "ts": 1690901260493, + "values": { + "battery_voltage": 3.229, + "lora_frame_counter": 3, + "lora_frame_port": 1, + "lora_frequency": 868300000, + "lora_spreading_factor": 12 + } + }] +} \ No newline at end of file diff --git a/VENDORS/Decentlab/DL-ISD/LORIOT/uplink/payload_2.json b/VENDORS/Decentlab/DL-ISD/LORIOT/uplink/payload_2.json new file mode 100644 index 00000000..3cb2a33e --- /dev/null +++ b/VENDORS/Decentlab/DL-ISD/LORIOT/uplink/payload_2.json @@ -0,0 +1,32 @@ +{ + "cmd": "gw", + "seqno": 4, + "EUI": "0102030405060708", + "ts": 1690901260493, + "fcnt": 3, + "port": 1, + "freq": 868300000, + "toa": 1319, + "dr": "SF12 BW125 4/5", + "ack": false, + "gws": [ + { + "rssi": -38, + "snr": 8.5, + "ts": 1690901260493, + "time": "2023-08-01T14:47:40.493Z", + "gweui": "1020304080706050", + "ant": 0 + }, + { + "rssi": -42, + "snr": 8.8, + "ts": 1690901260495, + "time": "2023-08-01T14:47:40.495Z", + "gweui": "1020304081716151", + "ant": 0 + } + ], + "bat": 143, + "data": "0256e100020c52" +} diff --git a/VENDORS/Decentlab/DL-ISD/LORIOT/uplink/result_2.json b/VENDORS/Decentlab/DL-ISD/LORIOT/uplink/result_2.json new file mode 100644 index 00000000..4e253763 --- /dev/null +++ b/VENDORS/Decentlab/DL-ISD/LORIOT/uplink/result_2.json @@ -0,0 +1,18 @@ +{ + "deviceName": "22241", + "deviceType": "DL-ISD", + "attributes": { + "lora_dev_eui": "0102030405060708", + "protocol_version": 2 + }, + "telemetry": [{ + "ts": 1690901260493, + "values": { + "battery_voltage": 3.154, + "lora_frame_counter": 3, + "lora_frame_port": 1, + "lora_frequency": 868300000, + "lora_spreading_factor": 12 + } + }] +} \ No newline at end of file diff --git a/VENDORS/Decentlab/DL-ISF/LORIOT/uplink/payload_2.json b/VENDORS/Decentlab/DL-ISF/LORIOT/uplink/payload_2.json new file mode 100644 index 00000000..745702c7 --- /dev/null +++ b/VENDORS/Decentlab/DL-ISF/LORIOT/uplink/payload_2.json @@ -0,0 +1,32 @@ +{ + "cmd": "gw", + "seqno": 4, + "EUI": "0102030405060708", + "ts": 1690901260493, + "fcnt": 3, + "port": 1, + "freq": 868300000, + "toa": 1319, + "dr": "SF12 BW125 4/5", + "ack": false, + "gws": [ + { + "rssi": -38, + "snr": 8.5, + "ts": 1690901260493, + "time": "2023-08-01T14:47:40.493Z", + "gweui": "1020304080706050", + "ant": 0 + }, + { + "rssi": -42, + "snr": 8.8, + "ts": 1690901260495, + "time": "2023-08-01T14:47:40.495Z", + "gweui": "1020304081716151", + "ant": 0 + } + ], + "bat": 143, + "data": "023d0100030c290bab0c3e79707a1d78437991490845997e4cacdeaa6e00000000457e415a0b59" +} diff --git a/VENDORS/Decentlab/DL-ISF/LORIOT/uplink/result_2.json b/VENDORS/Decentlab/DL-ISF/LORIOT/uplink/result_2.json new file mode 100644 index 00000000..d7707c9d --- /dev/null +++ b/VENDORS/Decentlab/DL-ISF/LORIOT/uplink/result_2.json @@ -0,0 +1,33 @@ +{ + "deviceName": "15617", + "deviceType": "DL-ISF", + "attributes": { + "lora_dev_eui": "0102030405060708", + "protocol_version": 2 + }, + "telemetry": [{ + "ts": 1690901260493, + "values": { + "sap_flow": -0.192, + "heat_velocity_outer": -2.208, + "heat_velocity_inner": 0.144, + "alpha_outer": -0.05184, + "alpha_inner": 0.00352, + "beta_outer": -0.14816, + "beta_inner": -0.04128, + "tmax_outer": 37.392, + "tmax_inner": 35.634, + "temperature_outer": -4.36, + "max_voltage": 11.486, + "min_voltage": 10.862, + "diagnostic": 0, + "upstream_tmax_outer": 35.58, + "upstream_tmax_inner": 33.46, + "battery_voltage": 2.905, + "lora_frame_counter": 3, + "lora_frame_port": 1, + "lora_frequency": 868300000, + "lora_spreading_factor": 12 + } + }] +} \ No newline at end of file diff --git a/VENDORS/Decentlab/DL-ITST/LORIOT/uplink/payload_2.json b/VENDORS/Decentlab/DL-ITST/LORIOT/uplink/payload_2.json new file mode 100644 index 00000000..9669c7e9 --- /dev/null +++ b/VENDORS/Decentlab/DL-ITST/LORIOT/uplink/payload_2.json @@ -0,0 +1,32 @@ +{ + "cmd": "gw", + "seqno": 4, + "EUI": "0102030405060708", + "ts": 1690901260493, + "fcnt": 3, + "port": 1, + "freq": 868300000, + "toa": 1319, + "dr": "SF12 BW125 4/5", + "ack": false, + "gws": [ + { + "rssi": -38, + "snr": 8.5, + "ts": 1690901260493, + "time": "2023-08-01T14:47:40.493Z", + "gweui": "1020304080706050", + "ant": 0 + }, + { + "rssi": -42, + "snr": 8.8, + "ts": 1690901260495, + "time": "2023-08-01T14:47:40.495Z", + "gweui": "1020304081716151", + "ant": 0 + } + ], + "bat": 143, + "data": "0202d9000304f904c40c54" +} diff --git a/VENDORS/Decentlab/DL-ITST/LORIOT/uplink/result_2.json b/VENDORS/Decentlab/DL-ITST/LORIOT/uplink/result_2.json new file mode 100644 index 00000000..c665ee12 --- /dev/null +++ b/VENDORS/Decentlab/DL-ITST/LORIOT/uplink/result_2.json @@ -0,0 +1,20 @@ +{ + "deviceName": "729", + "deviceType": "DL-ITST", + "attributes": { + "lora_dev_eui": "0102030405060708", + "protocol_version": 2 + }, + "telemetry": [{ + "ts": 1690901260493, + "values": { + "temperature_target": 27.3, + "temperature_head": 22, + "battery_voltage": 3.156, + "lora_frame_counter": 3, + "lora_frame_port": 1, + "lora_frequency": 868300000, + "lora_spreading_factor": 12 + } + }] +} \ No newline at end of file diff --git a/VENDORS/Decentlab/DL-KL66/LORIOT/uplink/payload_2.json b/VENDORS/Decentlab/DL-KL66/LORIOT/uplink/payload_2.json new file mode 100644 index 00000000..b447fdaf --- /dev/null +++ b/VENDORS/Decentlab/DL-KL66/LORIOT/uplink/payload_2.json @@ -0,0 +1,32 @@ +{ + "cmd": "gw", + "seqno": 4, + "EUI": "0102030405060708", + "ts": 1690901260493, + "fcnt": 3, + "port": 1, + "freq": 868300000, + "toa": 1319, + "dr": "SF12 BW125 4/5", + "ack": false, + "gws": [ + { + "rssi": -38, + "snr": 8.5, + "ts": 1690901260493, + "time": "2023-08-01T14:47:40.493Z", + "gweui": "1020304080706050", + "ant": 0 + }, + { + "rssi": -42, + "snr": 8.8, + "ts": 1690901260495, + "time": "2023-08-01T14:47:40.495Z", + "gweui": "1020304081716151", + "ant": 0 + } + ], + "bat": 143, + "data": "0203d400033bf67fff3bf60c60" +} diff --git a/VENDORS/Decentlab/DL-KL66/LORIOT/uplink/result_2.json b/VENDORS/Decentlab/DL-KL66/LORIOT/uplink/result_2.json new file mode 100644 index 00000000..9ef7e3c0 --- /dev/null +++ b/VENDORS/Decentlab/DL-KL66/LORIOT/uplink/result_2.json @@ -0,0 +1,24 @@ +{ + "deviceName": "980", + "deviceType": "DL-KL66", + "attributes": { + "lora_dev_eui": "0102030405060708", + "protocol_version": 2 + }, + "telemetry": [{ + "ts": 1690901260493, + "values": { + "counter_reading": 15350, + "measurement_interval": 0.999969482421875, + "frequency": 15350.468459120457, + "weight": -47.5066896399347, + "elongation": 0.6988257799379214, + "strain": 10.588269392998809, + "battery_voltage": 3.168, + "lora_frame_counter": 3, + "lora_frame_port": 1, + "lora_frequency": 868300000, + "lora_spreading_factor": 12 + } + }] +} \ No newline at end of file diff --git a/VENDORS/Decentlab/DL-LID/LORIOT/uplink/payload_2.json b/VENDORS/Decentlab/DL-LID/LORIOT/uplink/payload_2.json new file mode 100644 index 00000000..d6b0811c --- /dev/null +++ b/VENDORS/Decentlab/DL-LID/LORIOT/uplink/payload_2.json @@ -0,0 +1,32 @@ +{ + "cmd": "gw", + "seqno": 4, + "EUI": "0102030405060708", + "ts": 1690901260493, + "fcnt": 3, + "port": 1, + "freq": 868300000, + "toa": 1319, + "dr": "SF12 BW125 4/5", + "ack": false, + "gws": [ + { + "rssi": -38, + "snr": 8.5, + "ts": 1690901260493, + "time": "2023-08-01T14:47:40.493Z", + "gweui": "1020304080706050", + "ant": 0 + }, + { + "rssi": -42, + "snr": 8.8, + "ts": 1690901260495, + "time": "2023-08-01T14:47:40.495Z", + "gweui": "1020304081716151", + "ant": 0 + } + ], + "bat": 143, + "data": "0211c90003119b117611bc119e118a119411a811a81194006401990abd" +} diff --git a/VENDORS/Decentlab/DL-LID/LORIOT/uplink/result_2.json b/VENDORS/Decentlab/DL-LID/LORIOT/uplink/result_2.json new file mode 100644 index 00000000..7ca9f991 --- /dev/null +++ b/VENDORS/Decentlab/DL-LID/LORIOT/uplink/result_2.json @@ -0,0 +1,29 @@ +{ + "deviceName": "4553", + "deviceType": "DL-LID", + "attributes": { + "lora_dev_eui": "0102030405060708", + "protocol_version": 2 + }, + "telemetry": [{ + "ts": 1690901260493, + "values": { + "distance_average": 4507, + "distance_minimum": 4470, + "distance_maximum": 4540, + "distance_median": 4510, + "distance_10th_percentile": 4490, + "distance_25th_percentile": 4500, + "distance_75th_percentile": 4520, + "distance_90th_percentile": 4520, + "distance_most_frequent_value": 4500, + "number_of_samples": 100, + "total_acquisition_time": 399.4140625, + "battery_voltage": 2.749, + "lora_frame_counter": 3, + "lora_frame_port": 1, + "lora_frequency": 868300000, + "lora_spreading_factor": 12 + } + }] +} \ No newline at end of file diff --git a/VENDORS/Decentlab/DL-LP8P/LORIOT/uplink/payload_3.json b/VENDORS/Decentlab/DL-LP8P/LORIOT/uplink/payload_3.json new file mode 100644 index 00000000..c6990039 --- /dev/null +++ b/VENDORS/Decentlab/DL-LP8P/LORIOT/uplink/payload_3.json @@ -0,0 +1,32 @@ +{ + "cmd": "gw", + "seqno": 4, + "EUI": "0102030405060708", + "ts": 1690901260493, + "fcnt": 3, + "port": 1, + "freq": 868300000, + "toa": 1319, + "dr": "SF12 BW125 4/5", + "ack": false, + "gws": [ + { + "rssi": -38, + "snr": 8.5, + "ts": 1690901260493, + "time": "2023-08-01T14:47:40.493Z", + "gweui": "1020304080706050", + "ant": 0 + }, + { + "rssi": -42, + "snr": 8.8, + "ts": 1690901260495, + "time": "2023-08-01T14:47:40.495Z", + "gweui": "1020304081716151", + "ant": 0 + } + ], + "bat": 143, + "data": "020578000f67bd618d1cedbd1081d981f4895b0bd80bb50000959895390c25" +} diff --git a/VENDORS/Decentlab/DL-LP8P/LORIOT/uplink/result_3.json b/VENDORS/Decentlab/DL-LP8P/LORIOT/uplink/result_3.json new file mode 100644 index 00000000..6f84f91f --- /dev/null +++ b/VENDORS/Decentlab/DL-LP8P/LORIOT/uplink/result_3.json @@ -0,0 +1,30 @@ +{ + "deviceName": "1400", + "deviceType": "DL-LP8P", + "attributes": { + "lora_dev_eui": "0102030405060708", + "protocol_version": 2 + }, + "telemetry": [{ + "ts": 1690901260493, + "values": { + "air_temperature": 24.35660461425781, + "air_humidity": 41.63221740722656, + "barometer_temperature": 24.05, + "barometric_pressure": 96800, + "co2_concentration": 473, + "co2_concentration_lpf": 500, + "co2_sensor_temperature": 23.95, + "capacitor_voltage_1": 3.032, + "capacitor_voltage_2": 2.997, + "co2_sensor_status": 0, + "raw_ir_reading": 38296, + "raw_ir_reading_lpf": 38201, + "battery_voltage": 3.109, + "lora_frame_counter": 3, + "lora_frame_port": 1, + "lora_frequency": 868300000, + "lora_spreading_factor": 12 + } + }] +} \ No newline at end of file diff --git a/VENDORS/Decentlab/DL-LPW/LORIOT/uplink/payload_2.json b/VENDORS/Decentlab/DL-LPW/LORIOT/uplink/payload_2.json new file mode 100644 index 00000000..4b89cdb2 --- /dev/null +++ b/VENDORS/Decentlab/DL-LPW/LORIOT/uplink/payload_2.json @@ -0,0 +1,32 @@ +{ + "cmd": "gw", + "seqno": 4, + "EUI": "0102030405060708", + "ts": 1690901260493, + "fcnt": 3, + "port": 1, + "freq": 868300000, + "toa": 1319, + "dr": "SF12 BW125 4/5", + "ack": false, + "gws": [ + { + "rssi": -38, + "snr": 8.5, + "ts": 1690901260493, + "time": "2023-08-01T14:47:40.493Z", + "gweui": "1020304080706050", + "ant": 0 + }, + { + "rssi": -42, + "snr": 8.8, + "ts": 1690901260495, + "time": "2023-08-01T14:47:40.495Z", + "gweui": "1020304081716151", + "ant": 0 + } + ], + "bat": 143, + "data": "0211110003409a00860c54" +} diff --git a/VENDORS/Decentlab/DL-LPW/LORIOT/uplink/result_2.json b/VENDORS/Decentlab/DL-LPW/LORIOT/uplink/result_2.json new file mode 100644 index 00000000..d3d8057d --- /dev/null +++ b/VENDORS/Decentlab/DL-LPW/LORIOT/uplink/result_2.json @@ -0,0 +1,19 @@ +{ + "deviceName": "4369", + "deviceType": "DL-LPW", + "attributes": { + "lora_dev_eui": "0102030405060708", + "protocol_version": 2 + }, + "telemetry": [{ + "ts": 1690901260493, + "values": { + "potentiometer_position": 4.884648323059082, + "battery_voltage": 3.156, + "lora_frame_counter": 3, + "lora_frame_port": 1, + "lora_frequency": 868300000, + "lora_spreading_factor": 12 + } + }] +} \ No newline at end of file diff --git a/VENDORS/Decentlab/DL-LWS/LORIOT/uplink/payload_2.json b/VENDORS/Decentlab/DL-LWS/LORIOT/uplink/payload_2.json new file mode 100644 index 00000000..4b89cdb2 --- /dev/null +++ b/VENDORS/Decentlab/DL-LWS/LORIOT/uplink/payload_2.json @@ -0,0 +1,32 @@ +{ + "cmd": "gw", + "seqno": 4, + "EUI": "0102030405060708", + "ts": 1690901260493, + "fcnt": 3, + "port": 1, + "freq": 868300000, + "toa": 1319, + "dr": "SF12 BW125 4/5", + "ack": false, + "gws": [ + { + "rssi": -38, + "snr": 8.5, + "ts": 1690901260493, + "time": "2023-08-01T14:47:40.493Z", + "gweui": "1020304080706050", + "ant": 0 + }, + { + "rssi": -42, + "snr": 8.8, + "ts": 1690901260495, + "time": "2023-08-01T14:47:40.495Z", + "gweui": "1020304081716151", + "ant": 0 + } + ], + "bat": 143, + "data": "0211110003409a00860c54" +} diff --git a/VENDORS/Decentlab/DL-LWS/LORIOT/uplink/result_2.json b/VENDORS/Decentlab/DL-LWS/LORIOT/uplink/result_2.json new file mode 100644 index 00000000..c8f00b86 --- /dev/null +++ b/VENDORS/Decentlab/DL-LWS/LORIOT/uplink/result_2.json @@ -0,0 +1,19 @@ +{ + "deviceName": "4369", + "deviceType": "DL-LWS", + "attributes": { + "lora_dev_eui": "0102030405060708", + "protocol_version": 2 + }, + "telemetry": [{ + "ts": 1690901260493, + "values": { + "leaf_wetness_index": 0.04884648323059082, + "battery_voltage": 3.156, + "lora_frame_counter": 3, + "lora_frame_port": 1, + "lora_frequency": 868300000, + "lora_spreading_factor": 12 + } + }] +} \ No newline at end of file diff --git a/VENDORS/Decentlab/DL-MBX/LORIOT/uplink/payload_3.json b/VENDORS/Decentlab/DL-MBX/LORIOT/uplink/payload_3.json new file mode 100644 index 00000000..b96f24a2 --- /dev/null +++ b/VENDORS/Decentlab/DL-MBX/LORIOT/uplink/payload_3.json @@ -0,0 +1,32 @@ +{ + "cmd": "gw", + "seqno": 4, + "EUI": "0102030405060708", + "ts": 1690901260493, + "fcnt": 3, + "port": 1, + "freq": 868300000, + "toa": 1319, + "dr": "SF12 BW125 4/5", + "ack": false, + "gws": [ + { + "rssi": -38, + "snr": 8.5, + "ts": 1690901260493, + "time": "2023-08-01T14:47:40.493Z", + "gweui": "1020304080706050", + "ant": 0 + }, + { + "rssi": -42, + "snr": 8.8, + "ts": 1690901260495, + "time": "2023-08-01T14:47:40.495Z", + "gweui": "1020304081716151", + "ant": 0 + } + ], + "bat": 143, + "data": "02012f000304d200010bb1" +} diff --git a/VENDORS/Decentlab/DL-MBX/LORIOT/uplink/result_3.json b/VENDORS/Decentlab/DL-MBX/LORIOT/uplink/result_3.json new file mode 100644 index 00000000..a3287c76 --- /dev/null +++ b/VENDORS/Decentlab/DL-MBX/LORIOT/uplink/result_3.json @@ -0,0 +1,20 @@ +{ + "deviceName": "303", + "deviceType": "DL-MBX", + "attributes": { + "lora_dev_eui": "0102030405060708", + "protocol_version": 2 + }, + "telemetry": [{ + "ts": 1690901260493, + "values": { + "distance": 1234, + "number_of_valid_samples": 1, + "battery_voltage": 2.993, + "lora_frame_counter": 3, + "lora_frame_port": 1, + "lora_frequency": 868300000, + "lora_spreading_factor": 12 + } + }] +} \ No newline at end of file diff --git a/VENDORS/Decentlab/DL-MES5/LORIOT/uplink/payload_2.json b/VENDORS/Decentlab/DL-MES5/LORIOT/uplink/payload_2.json new file mode 100644 index 00000000..6cdb51e9 --- /dev/null +++ b/VENDORS/Decentlab/DL-MES5/LORIOT/uplink/payload_2.json @@ -0,0 +1,32 @@ +{ + "cmd": "gw", + "seqno": 4, + "EUI": "0102030405060708", + "ts": 1690901260493, + "fcnt": 3, + "port": 1, + "freq": 868300000, + "toa": 1319, + "dr": "SF12 BW125 4/5", + "ack": false, + "gws": [ + { + "rssi": -38, + "snr": 8.5, + "ts": 1690901260493, + "time": "2023-08-01T14:47:40.493Z", + "gweui": "1020304080706050", + "ant": 0 + }, + { + "rssi": -42, + "snr": 8.8, + "ts": 1690901260495, + "time": "2023-08-01T14:47:40.495Z", + "gweui": "1020304081716151", + "ant": 0 + } + ], + "bat": 143, + "data": "024E030003000088e6210800f223650af5" +} diff --git a/VENDORS/Decentlab/DL-MES5/LORIOT/uplink/result_2.json b/VENDORS/Decentlab/DL-MES5/LORIOT/uplink/result_2.json new file mode 100644 index 00000000..570ea0bd --- /dev/null +++ b/VENDORS/Decentlab/DL-MES5/LORIOT/uplink/result_2.json @@ -0,0 +1,23 @@ +{ + "deviceName": "19971", + "deviceType": "DL-MES5", + "attributes": { + "lora_dev_eui": "0102030405060708", + "protocol_version": 2 + }, + "telemetry": [{ + "ts": 1690901260493, + "values": { + "status": 0, + "temperature": 22.78, + "sludge_blanket": 84.56, + "suspended_solid": 2.42, + "turbidity": 906.1, + "battery_voltage": 2.805, + "lora_frame_counter": 3, + "lora_frame_port": 1, + "lora_frequency": 868300000, + "lora_spreading_factor": 12 + } + }] +} \ No newline at end of file diff --git a/VENDORS/Decentlab/DL-NTU/LORIOT/uplink/payload_2.json b/VENDORS/Decentlab/DL-NTU/LORIOT/uplink/payload_2.json new file mode 100644 index 00000000..eea84c28 --- /dev/null +++ b/VENDORS/Decentlab/DL-NTU/LORIOT/uplink/payload_2.json @@ -0,0 +1,32 @@ +{ + "cmd": "gw", + "seqno": 4, + "EUI": "0102030405060708", + "ts": 1690901260493, + "fcnt": 3, + "port": 1, + "freq": 868300000, + "toa": 1319, + "dr": "SF12 BW125 4/5", + "ack": false, + "gws": [ + { + "rssi": -38, + "snr": 8.5, + "ts": 1690901260493, + "time": "2023-08-01T14:47:40.493Z", + "gweui": "1020304080706050", + "ant": 0 + }, + { + "rssi": -42, + "snr": 8.8, + "ts": 1690901260495, + "time": "2023-08-01T14:47:40.495Z", + "gweui": "1020304081716151", + "ant": 0 + } + ], + "bat": 143, + "data": "022332000300008885013e013e02330b10" +} diff --git a/VENDORS/Decentlab/DL-NTU/LORIOT/uplink/result_2.json b/VENDORS/Decentlab/DL-NTU/LORIOT/uplink/result_2.json new file mode 100644 index 00000000..8f169ed5 --- /dev/null +++ b/VENDORS/Decentlab/DL-NTU/LORIOT/uplink/result_2.json @@ -0,0 +1,23 @@ +{ + "deviceName": "9010", + "deviceType": "DL-NTU", + "attributes": { + "lora_dev_eui": "0102030405060708", + "protocol_version": 2 + }, + "telemetry": [{ + "ts": 1690901260493, + "values": { + "status": 0, + "temperature": 21.81, + "turbidity_in_ntu": 31.8, + "turbidity_in_fnu": 31.8, + "turbidity_in_mg_l": 56.3, + "battery_voltage": 2.832, + "lora_frame_counter": 3, + "lora_frame_port": 1, + "lora_frequency": 868300000, + "lora_spreading_factor": 12 + } + }] +} \ No newline at end of file diff --git a/VENDORS/Decentlab/DL-OPTOD/LORIOT/uplink/payload_2.json b/VENDORS/Decentlab/DL-OPTOD/LORIOT/uplink/payload_2.json new file mode 100644 index 00000000..cd0813f3 --- /dev/null +++ b/VENDORS/Decentlab/DL-OPTOD/LORIOT/uplink/payload_2.json @@ -0,0 +1,32 @@ +{ + "cmd": "gw", + "seqno": 4, + "EUI": "0102030405060708", + "ts": 1690901260493, + "fcnt": 3, + "port": 1, + "freq": 868300000, + "toa": 1319, + "dr": "SF12 BW125 4/5", + "ack": false, + "gws": [ + { + "rssi": -38, + "snr": 8.5, + "ts": 1690901260493, + "time": "2023-08-01T14:47:40.493Z", + "gweui": "1020304080706050", + "ant": 0 + }, + { + "rssi": -42, + "snr": 8.8, + "ts": 1690901260495, + "time": "2023-08-01T14:47:40.495Z", + "gweui": "1020304081716151", + "ant": 0 + } + ], + "bat": 143, + "data": "02186c000300008862a618836583650c60" +} diff --git a/VENDORS/Decentlab/DL-OPTOD/LORIOT/uplink/result_2.json b/VENDORS/Decentlab/DL-OPTOD/LORIOT/uplink/result_2.json new file mode 100644 index 00000000..ebfd8391 --- /dev/null +++ b/VENDORS/Decentlab/DL-OPTOD/LORIOT/uplink/result_2.json @@ -0,0 +1,23 @@ +{ + "deviceName": "6252", + "deviceType": "DL-OPTOD", + "attributes": { + "lora_dev_eui": "0102030405060708", + "protocol_version": 2 + }, + "telemetry": [{ + "ts": 1690901260493, + "values": { + "status": 0, + "temperature": 21.46, + "oxygen_saturation": 97.52, + "oxygen_concentration": 8.69, + "oxygen_concentration_alt": 8.69, + "battery_voltage": 3.168, + "lora_frame_counter": 3, + "lora_frame_port": 1, + "lora_frequency": 868300000, + "lora_spreading_factor": 12 + } + }] +} \ No newline at end of file diff --git a/VENDORS/Decentlab/DL-PAR/LORIOT/uplink/payload_2.json b/VENDORS/Decentlab/DL-PAR/LORIOT/uplink/payload_2.json new file mode 100644 index 00000000..8c894b04 --- /dev/null +++ b/VENDORS/Decentlab/DL-PAR/LORIOT/uplink/payload_2.json @@ -0,0 +1,32 @@ +{ + "cmd": "gw", + "seqno": 4, + "EUI": "0102030405060708", + "ts": 1690901260493, + "fcnt": 3, + "port": 1, + "freq": 868300000, + "toa": 1319, + "dr": "SF12 BW125 4/5", + "ack": false, + "gws": [ + { + "rssi": -38, + "snr": 8.5, + "ts": 1690901260493, + "time": "2023-08-01T14:47:40.493Z", + "gweui": "1020304080706050", + "ant": 0 + }, + { + "rssi": -42, + "snr": 8.8, + "ts": 1690901260495, + "time": "2023-08-01T14:47:40.495Z", + "gweui": "1020304081716151", + "ant": 0 + } + ], + "bat": 143, + "data": "020291000380690c60" +} diff --git a/VENDORS/Decentlab/DL-PAR/LORIOT/uplink/result_2.json b/VENDORS/Decentlab/DL-PAR/LORIOT/uplink/result_2.json new file mode 100644 index 00000000..31fe9462 --- /dev/null +++ b/VENDORS/Decentlab/DL-PAR/LORIOT/uplink/result_2.json @@ -0,0 +1,19 @@ +{ + "deviceName": "657", + "deviceType": "DL-PAR", + "attributes": { + "lora_dev_eui": "0102030405060708", + "protocol_version": 2 + }, + "telemetry": [{ + "ts": 1690901260493, + "values": { + "photosynthetically_active_radiation": 48.065185546875, + "battery_voltage": 3.168, + "lora_frame_counter": 3, + "lora_frame_port": 1, + "lora_frequency": 868300000, + "lora_spreading_factor": 12 + } + }] +} \ No newline at end of file diff --git a/VENDORS/Decentlab/DL-PHEHT/LORIOT/uplink/payload_2.json b/VENDORS/Decentlab/DL-PHEHT/LORIOT/uplink/payload_2.json new file mode 100644 index 00000000..eeec5e5e --- /dev/null +++ b/VENDORS/Decentlab/DL-PHEHT/LORIOT/uplink/payload_2.json @@ -0,0 +1,32 @@ +{ + "cmd": "gw", + "seqno": 4, + "EUI": "0102030405060708", + "ts": 1690901260493, + "fcnt": 3, + "port": 1, + "freq": 868300000, + "toa": 1319, + "dr": "SF12 BW125 4/5", + "ack": false, + "gws": [ + { + "rssi": -38, + "snr": 8.5, + "ts": 1690901260493, + "time": "2023-08-01T14:47:40.493Z", + "gweui": "1020304080706050", + "ant": 0 + }, + { + "rssi": -42, + "snr": 8.8, + "ts": 1690901260495, + "time": "2023-08-01T14:47:40.495Z", + "gweui": "1020304081716151", + "ant": 0 + } + ], + "bat": 143, + "data": "0252b800030000884282c77f637ff60c5c" +} diff --git a/VENDORS/Decentlab/DL-PHEHT/LORIOT/uplink/result_2.json b/VENDORS/Decentlab/DL-PHEHT/LORIOT/uplink/result_2.json new file mode 100644 index 00000000..d6f17592 --- /dev/null +++ b/VENDORS/Decentlab/DL-PHEHT/LORIOT/uplink/result_2.json @@ -0,0 +1,23 @@ +{ + "deviceName": "21176", + "deviceType": "DL-PHEHT", + "attributes": { + "lora_dev_eui": "0102030405060708", + "protocol_version": 2 + }, + "telemetry": [{ + "ts": 1690901260493, + "values": { + "status": 0, + "temperature": 21.14, + "ph": 7.11, + "redox": -15.7, + "ph_mv": -1, + "battery_voltage": 3.164, + "lora_frame_counter": 3, + "lora_frame_port": 1, + "lora_frequency": 868300000, + "lora_spreading_factor": 12 + } + }] +} \ No newline at end of file diff --git a/VENDORS/Decentlab/DL-PM/LORIOT/uplink/payload_3.json b/VENDORS/Decentlab/DL-PM/LORIOT/uplink/payload_3.json new file mode 100644 index 00000000..81ce8c77 --- /dev/null +++ b/VENDORS/Decentlab/DL-PM/LORIOT/uplink/payload_3.json @@ -0,0 +1,32 @@ +{ + "cmd": "gw", + "seqno": 4, + "EUI": "0102030405060708", + "ts": 1690901260493, + "fcnt": 3, + "port": 1, + "freq": 868300000, + "toa": 1319, + "dr": "SF12 BW125 4/5", + "ack": false, + "gws": [ + { + "rssi": -38, + "snr": 8.5, + "ts": 1690901260493, + "time": "2023-08-01T14:47:40.493Z", + "gweui": "1020304080706050", + "ant": 0 + }, + { + "rssi": -42, + "snr": 8.8, + "ts": 1690901260495, + "time": "2023-08-01T14:47:40.495Z", + "gweui": "1020304081716151", + "ant": 0 + } + ], + "bat": 143, + "data": "021b50000f0c25002500270027002701f50107012c012d012d012d67bd618dbd10" +} diff --git a/VENDORS/Decentlab/DL-PM/LORIOT/uplink/result_3.json b/VENDORS/Decentlab/DL-PM/LORIOT/uplink/result_3.json new file mode 100644 index 00000000..7a507604 --- /dev/null +++ b/VENDORS/Decentlab/DL-PM/LORIOT/uplink/result_3.json @@ -0,0 +1,31 @@ +{ + "deviceName": "6992", + "deviceType": "DL-PM", + "attributes": { + "lora_dev_eui": "0102030405060708", + "protocol_version": 2 + }, + "telemetry": [{ + "ts": 1690901260493, + "values": { + "battery_voltage": 3.109, + "pm1_0_mass_concentration": 3.7, + "pm2_5_mass_concentration": 3.9, + "pm4_mass_concentration": 3.9, + "pm10_mass_concentration": 3.9, + "typical_particle_size": 501, + "pm0_5_number_concentration": 26.3, + "pm1_0_number_concentration": 30, + "pm2_5_number_concentration": 30.1, + "pm4_number_concentration": 30.1, + "pm10_number_concentration": 30.1, + "air_temperature": 24.35660461425781, + "air_humidity": 41.63221740722656, + "barometric_pressure": 96800, + "lora_frame_counter": 3, + "lora_frame_port": 1, + "lora_frequency": 868300000, + "lora_spreading_factor": 12 + } + }] +} \ No newline at end of file diff --git a/VENDORS/Decentlab/DL-PR21/LORIOT/uplink/payload_2.json b/VENDORS/Decentlab/DL-PR21/LORIOT/uplink/payload_2.json new file mode 100644 index 00000000..1e56c809 --- /dev/null +++ b/VENDORS/Decentlab/DL-PR21/LORIOT/uplink/payload_2.json @@ -0,0 +1,32 @@ +{ + "cmd": "gw", + "seqno": 4, + "EUI": "0102030405060708", + "ts": 1690901260493, + "fcnt": 3, + "port": 1, + "freq": 868300000, + "toa": 1319, + "dr": "SF12 BW125 4/5", + "ack": false, + "gws": [ + { + "rssi": -38, + "snr": 8.5, + "ts": 1690901260493, + "time": "2023-08-01T14:47:40.493Z", + "gweui": "1020304080706050", + "ant": 0 + }, + { + "rssi": -42, + "snr": 8.8, + "ts": 1690901260495, + "time": "2023-08-01T14:47:40.495Z", + "gweui": "1020304081716151", + "ant": 0 + } + ], + "bat": 143, + "data": "02016700034e8060170c7f" +} diff --git a/VENDORS/Decentlab/DL-PR21/LORIOT/uplink/result_2.json b/VENDORS/Decentlab/DL-PR21/LORIOT/uplink/result_2.json new file mode 100644 index 00000000..3902edae --- /dev/null +++ b/VENDORS/Decentlab/DL-PR21/LORIOT/uplink/result_2.json @@ -0,0 +1,20 @@ +{ + "deviceName": "359", + "deviceType": "DL-PR21", + "attributes": { + "lora_dev_eui": "0102030405060708", + "protocol_version": 2 + }, + "telemetry": [{ + "ts": 1690901260493, + "values": { + "pressure": 0.24609375, + "temperature": 25.671875, + "battery_voltage": 3.199, + "lora_frame_counter": 3, + "lora_frame_port": 1, + "lora_frequency": 868300000, + "lora_spreading_factor": 12 + } + }] +} \ No newline at end of file diff --git a/VENDORS/Decentlab/DL-PR26/LORIOT/uplink/payload_2.json b/VENDORS/Decentlab/DL-PR26/LORIOT/uplink/payload_2.json new file mode 100644 index 00000000..5c952029 --- /dev/null +++ b/VENDORS/Decentlab/DL-PR26/LORIOT/uplink/payload_2.json @@ -0,0 +1,32 @@ +{ + "cmd": "gw", + "seqno": 4, + "EUI": "0102030405060708", + "ts": 1690901260493, + "fcnt": 3, + "port": 1, + "freq": 868300000, + "toa": 1319, + "dr": "SF12 BW125 4/5", + "ack": false, + "gws": [ + { + "rssi": -38, + "snr": 8.5, + "ts": 1690901260493, + "time": "2023-08-01T14:47:40.493Z", + "gweui": "1020304080706050", + "ant": 0 + }, + { + "rssi": -42, + "snr": 8.8, + "ts": 1690901260495, + "time": "2023-08-01T14:47:40.495Z", + "gweui": "1020304081716151", + "ant": 0 + } + ], + "bat": 143, + "data": "02016700033e8060170c7f" +} diff --git a/VENDORS/Decentlab/DL-PR26/LORIOT/uplink/result_2.json b/VENDORS/Decentlab/DL-PR26/LORIOT/uplink/result_2.json new file mode 100644 index 00000000..46605f9b --- /dev/null +++ b/VENDORS/Decentlab/DL-PR26/LORIOT/uplink/result_2.json @@ -0,0 +1,20 @@ +{ + "deviceName": "359", + "deviceType": "DL-PR26", + "attributes": { + "lora_dev_eui": "0102030405060708", + "protocol_version": 2 + }, + "telemetry": [{ + "ts": 1690901260493, + "values": { + "pressure": -0.01171875, + "temperature": 25.671875, + "battery_voltage": 3.199, + "lora_frame_counter": 3, + "lora_frame_port": 1, + "lora_frequency": 868300000, + "lora_spreading_factor": 12 + } + }] +} \ No newline at end of file diff --git a/VENDORS/Decentlab/DL-PR36/LORIOT/uplink/payload_2.json b/VENDORS/Decentlab/DL-PR36/LORIOT/uplink/payload_2.json new file mode 100644 index 00000000..feffc7ad --- /dev/null +++ b/VENDORS/Decentlab/DL-PR36/LORIOT/uplink/payload_2.json @@ -0,0 +1,32 @@ +{ + "cmd": "gw", + "seqno": 4, + "EUI": "0102030405060708", + "ts": 1690901260493, + "fcnt": 3, + "port": 1, + "freq": 868300000, + "toa": 1319, + "dr": "SF12 BW125 4/5", + "ack": false, + "gws": [ + { + "rssi": -38, + "snr": 8.5, + "ts": 1690901260493, + "time": "2023-08-01T14:47:40.493Z", + "gweui": "1020304080706050", + "ant": 0 + }, + { + "rssi": -42, + "snr": 8.8, + "ts": 1690901260495, + "time": "2023-08-01T14:47:40.495Z", + "gweui": "1020304081716151", + "ant": 0 + } + ], + "bat": 143, + "data": "02032b0003806797810c2b" +} diff --git a/VENDORS/Decentlab/DL-PR36/LORIOT/uplink/result_2.json b/VENDORS/Decentlab/DL-PR36/LORIOT/uplink/result_2.json new file mode 100644 index 00000000..9db74732 --- /dev/null +++ b/VENDORS/Decentlab/DL-PR36/LORIOT/uplink/result_2.json @@ -0,0 +1,20 @@ +{ + "deviceName": "811", + "deviceType": "DL-PR36", + "attributes": { + "lora_dev_eui": "0102030405060708", + "protocol_version": 2 + }, + "telemetry": [{ + "ts": 1690901260493, + "values": { + "pressure": 0.0125732421875, + "temperature": 23.50390625, + "battery_voltage": 3.115, + "lora_frame_counter": 3, + "lora_frame_port": 1, + "lora_frequency": 868300000, + "lora_spreading_factor": 12 + } + }] +} \ No newline at end of file diff --git a/VENDORS/Decentlab/DL-PR36CTD/LORIOT/uplink/payload_2.json b/VENDORS/Decentlab/DL-PR36CTD/LORIOT/uplink/payload_2.json new file mode 100644 index 00000000..4923774e --- /dev/null +++ b/VENDORS/Decentlab/DL-PR36CTD/LORIOT/uplink/payload_2.json @@ -0,0 +1,32 @@ +{ + "cmd": "gw", + "seqno": 4, + "EUI": "0102030405060708", + "ts": 1690901260493, + "fcnt": 3, + "port": 1, + "freq": 868300000, + "toa": 1319, + "dr": "SF12 BW125 4/5", + "ack": false, + "gws": [ + { + "rssi": -38, + "snr": 8.5, + "ts": 1690901260493, + "time": "2023-08-01T14:47:40.493Z", + "gweui": "1020304080706050", + "ant": 0 + }, + { + "rssi": -42, + "snr": 8.8, + "ts": 1690901260495, + "time": "2023-08-01T14:47:40.495Z", + "gweui": "1020304081716151", + "ant": 0 + } + ], + "bat": 143, + "data": "020a17000380079786978180060c2b" +} diff --git a/VENDORS/Decentlab/DL-PR36CTD/LORIOT/uplink/result_2.json b/VENDORS/Decentlab/DL-PR36CTD/LORIOT/uplink/result_2.json new file mode 100644 index 00000000..1a488fc1 --- /dev/null +++ b/VENDORS/Decentlab/DL-PR36CTD/LORIOT/uplink/result_2.json @@ -0,0 +1,22 @@ +{ + "deviceName": "2583", + "deviceType": "DL-PR36CTD", + "attributes": { + "lora_dev_eui": "0102030405060708", + "protocol_version": 2 + }, + "telemetry": [{ + "ts": 1690901260493, + "values": { + "pressure": 0.0008544921875, + "temperature_electronics": 23.5234375, + "temperature_pt1000": 23.50390625, + "electrical_conductivity": 0.005859375, + "battery_voltage": 3.115, + "lora_frame_counter": 3, + "lora_frame_port": 1, + "lora_frequency": 868300000, + "lora_spreading_factor": 12 + } + }] +} \ No newline at end of file diff --git a/VENDORS/Decentlab/DL-PYR/LORIOT/uplink/payload_2.json b/VENDORS/Decentlab/DL-PYR/LORIOT/uplink/payload_2.json new file mode 100644 index 00000000..d574dc87 --- /dev/null +++ b/VENDORS/Decentlab/DL-PYR/LORIOT/uplink/payload_2.json @@ -0,0 +1,32 @@ +{ + "cmd": "gw", + "seqno": 4, + "EUI": "0102030405060708", + "ts": 1690901260493, + "fcnt": 3, + "port": 1, + "freq": 868300000, + "toa": 1319, + "dr": "SF12 BW125 4/5", + "ack": false, + "gws": [ + { + "rssi": -38, + "snr": 8.5, + "ts": 1690901260493, + "time": "2023-08-01T14:47:40.493Z", + "gweui": "1020304080706050", + "ant": 0 + }, + { + "rssi": -42, + "snr": 8.8, + "ts": 1690901260495, + "time": "2023-08-01T14:47:40.495Z", + "gweui": "1020304081716151", + "ant": 0 + } + ], + "bat": 143, + "data": "02029100020c60" +} diff --git a/VENDORS/Decentlab/DL-PYR/LORIOT/uplink/result_2.json b/VENDORS/Decentlab/DL-PYR/LORIOT/uplink/result_2.json new file mode 100644 index 00000000..4e95d5e3 --- /dev/null +++ b/VENDORS/Decentlab/DL-PYR/LORIOT/uplink/result_2.json @@ -0,0 +1,18 @@ +{ + "deviceName": "657", + "deviceType": "DL-PYR", + "attributes": { + "lora_dev_eui": "0102030405060708", + "protocol_version": 2 + }, + "telemetry": [{ + "ts": 1690901260493, + "values": { + "battery_voltage": 3.168, + "lora_frame_counter": 3, + "lora_frame_port": 1, + "lora_frequency": 868300000, + "lora_spreading_factor": 12 + } + }] +} \ No newline at end of file diff --git a/VENDORS/Decentlab/DL-RHC/LORIOT/uplink/payload_1.json b/VENDORS/Decentlab/DL-RHC/LORIOT/uplink/payload_1.json new file mode 100644 index 00000000..6a57849e --- /dev/null +++ b/VENDORS/Decentlab/DL-RHC/LORIOT/uplink/payload_1.json @@ -0,0 +1,32 @@ +{ + "cmd": "gw", + "seqno": 4, + "EUI": "0102030405060708", + "ts": 1690901260493, + "fcnt": 3, + "port": 1, + "freq": 868300000, + "toa": 1319, + "dr": "SF12 BW125 4/5", + "ack": false, + "gws": [ + { + "rssi": -38, + "snr": 8.5, + "ts": 1690901260493, + "time": "2023-08-01T14:47:40.493Z", + "gweui": "1020304080706050", + "ant": 0 + }, + { + "rssi": -42, + "snr": 8.8, + "ts": 1690901260495, + "time": "2023-08-01T14:47:40.495Z", + "gweui": "1020304081716151", + "ant": 0 + } + ], + "bat": 143, + "data": "0202e00003a9fd01341ca285f30c60" +} diff --git a/VENDORS/Decentlab/DL-RHC/LORIOT/uplink/result_1.json b/VENDORS/Decentlab/DL-RHC/LORIOT/uplink/result_1.json new file mode 100644 index 00000000..41a84a00 --- /dev/null +++ b/VENDORS/Decentlab/DL-RHC/LORIOT/uplink/result_1.json @@ -0,0 +1,21 @@ +{ + "deviceName": "736", + "deviceType": "DL-RHC", + "attributes": { + "lora_dev_eui": "0102030405060708", + "protocol_version": 2 + }, + "telemetry": [{ + "ts": 1690901260493, + "values": { + "sensor_id": 20228605, + "air_humidity": 73.3, + "air_temperature": 15.23, + "battery_voltage": 3.168, + "lora_frame_counter": 3, + "lora_frame_port": 1, + "lora_frequency": 868300000, + "lora_spreading_factor": 12 + } + }] +} \ No newline at end of file diff --git a/VENDORS/Decentlab/DL-SDD/LORIOT/uplink/payload_2.json b/VENDORS/Decentlab/DL-SDD/LORIOT/uplink/payload_2.json new file mode 100644 index 00000000..f93162e5 --- /dev/null +++ b/VENDORS/Decentlab/DL-SDD/LORIOT/uplink/payload_2.json @@ -0,0 +1,32 @@ +{ + "cmd": "gw", + "seqno": 4, + "EUI": "0102030405060708", + "ts": 1690901260493, + "fcnt": 3, + "port": 1, + "freq": 868300000, + "toa": 1319, + "dr": "SF12 BW125 4/5", + "ack": false, + "gws": [ + { + "rssi": -38, + "snr": 8.5, + "ts": 1690901260493, + "time": "2023-08-01T14:47:40.493Z", + "gweui": "1020304080706050", + "ant": 0 + }, + { + "rssi": -42, + "snr": 8.8, + "ts": 1690901260495, + "time": "2023-08-01T14:47:40.495Z", + "gweui": "1020304081716151", + "ant": 0 + } + ], + "bat": 143, + "data": "0243e300058000800080008000800080008741877b8749876c876c876600000000000000000000014a09e3" +} diff --git a/VENDORS/Decentlab/DL-SDD/LORIOT/uplink/result_2.json b/VENDORS/Decentlab/DL-SDD/LORIOT/uplink/result_2.json new file mode 100644 index 00000000..a2349d58 --- /dev/null +++ b/VENDORS/Decentlab/DL-SDD/LORIOT/uplink/result_2.json @@ -0,0 +1,36 @@ +{ + "deviceName": "17379", + "deviceType": "DL-SDD", + "attributes": { + "lora_dev_eui": "0102030405060708", + "protocol_version": 2 + }, + "telemetry": [{ + "ts": 1690901260493, + "values": { + "moisture_at_level_0": 0, + "moisture_at_level_1": 0, + "moisture_at_level_2": 0, + "moisture_at_level_3": 0, + "moisture_at_level_4": 0, + "moisture_at_level_5": 0, + "temperature_at_level_0": 18.57, + "temperature_at_level_1": 19.15, + "temperature_at_level_2": 18.65, + "temperature_at_level_3": 19, + "temperature_at_level_4": 19, + "temperature_at_level_5": 18.94, + "salinity_at_level_0": -100, + "salinity_at_level_1": -100, + "salinity_at_level_2": -100, + "salinity_at_level_3": -100, + "salinity_at_level_4": -100, + "salinity_at_level_5": 230, + "battery_voltage": 2.531, + "lora_frame_counter": 3, + "lora_frame_port": 1, + "lora_frequency": 868300000, + "lora_spreading_factor": 12 + } + }] +} \ No newline at end of file diff --git a/VENDORS/Decentlab/DL-SHT35-001/LORIOT/uplink/payload_2.json b/VENDORS/Decentlab/DL-SHT35-001/LORIOT/uplink/payload_2.json new file mode 100644 index 00000000..dbd5395a --- /dev/null +++ b/VENDORS/Decentlab/DL-SHT35-001/LORIOT/uplink/payload_2.json @@ -0,0 +1,32 @@ +{ + "cmd": "gw", + "seqno": 4, + "EUI": "0102030405060708", + "ts": 1690901260493, + "fcnt": 3, + "port": 1, + "freq": 868300000, + "toa": 1319, + "dr": "SF12 BW125 4/5", + "ack": false, + "gws": [ + { + "rssi": -38, + "snr": 8.5, + "ts": 1690901260493, + "time": "2023-08-01T14:47:40.493Z", + "gweui": "1020304080706050", + "ant": 0 + }, + { + "rssi": -42, + "snr": 8.8, + "ts": 1690901260495, + "time": "2023-08-01T14:47:40.495Z", + "gweui": "1020304081716151", + "ant": 0 + } + ], + "bat": 143, + "data": "02030e000364a079b10c60" +} diff --git a/VENDORS/Decentlab/DL-SHT35-001/LORIOT/uplink/result_2.json b/VENDORS/Decentlab/DL-SHT35-001/LORIOT/uplink/result_2.json new file mode 100644 index 00000000..991fde36 --- /dev/null +++ b/VENDORS/Decentlab/DL-SHT35-001/LORIOT/uplink/result_2.json @@ -0,0 +1,20 @@ +{ + "deviceName": "782", + "deviceType": "DL-SHT35-001", + "attributes": { + "lora_dev_eui": "0102030405060708", + "protocol_version": 2 + }, + "telemetry": [{ + "ts": 1690901260493, + "values": { + "air_temperature": 23.787670710307466, + "air_humidity": 47.536430914778364, + "battery_voltage": 3.168, + "lora_frame_counter": 3, + "lora_frame_port": 1, + "lora_frequency": 868300000, + "lora_spreading_factor": 12 + } + }] +} \ No newline at end of file diff --git a/VENDORS/Decentlab/DL-SHT35-002/LORIOT/uplink/payload_2.json b/VENDORS/Decentlab/DL-SHT35-002/LORIOT/uplink/payload_2.json new file mode 100644 index 00000000..dbd5395a --- /dev/null +++ b/VENDORS/Decentlab/DL-SHT35-002/LORIOT/uplink/payload_2.json @@ -0,0 +1,32 @@ +{ + "cmd": "gw", + "seqno": 4, + "EUI": "0102030405060708", + "ts": 1690901260493, + "fcnt": 3, + "port": 1, + "freq": 868300000, + "toa": 1319, + "dr": "SF12 BW125 4/5", + "ack": false, + "gws": [ + { + "rssi": -38, + "snr": 8.5, + "ts": 1690901260493, + "time": "2023-08-01T14:47:40.493Z", + "gweui": "1020304080706050", + "ant": 0 + }, + { + "rssi": -42, + "snr": 8.8, + "ts": 1690901260495, + "time": "2023-08-01T14:47:40.495Z", + "gweui": "1020304081716151", + "ant": 0 + } + ], + "bat": 143, + "data": "02030e000364a079b10c60" +} diff --git a/VENDORS/Decentlab/DL-SHT35-002/LORIOT/uplink/result_2.json b/VENDORS/Decentlab/DL-SHT35-002/LORIOT/uplink/result_2.json new file mode 100644 index 00000000..562a1cc0 --- /dev/null +++ b/VENDORS/Decentlab/DL-SHT35-002/LORIOT/uplink/result_2.json @@ -0,0 +1,20 @@ +{ + "deviceName": "782", + "deviceType": "DL-SHT35-002", + "attributes": { + "lora_dev_eui": "0102030405060708", + "protocol_version": 2 + }, + "telemetry": [{ + "ts": 1690901260493, + "values": { + "air_temperature": 23.787670710307466, + "air_humidity": 47.536430914778364, + "battery_voltage": 3.168, + "lora_frame_counter": 3, + "lora_frame_port": 1, + "lora_frequency": 868300000, + "lora_spreading_factor": 12 + } + }] +} \ No newline at end of file diff --git a/VENDORS/Decentlab/DL-SMTP/LORIOT/uplink/payload_2.json b/VENDORS/Decentlab/DL-SMTP/LORIOT/uplink/payload_2.json new file mode 100644 index 00000000..f0836c8b --- /dev/null +++ b/VENDORS/Decentlab/DL-SMTP/LORIOT/uplink/payload_2.json @@ -0,0 +1,32 @@ +{ + "cmd": "gw", + "seqno": 4, + "EUI": "0102030405060708", + "ts": 1690901260493, + "fcnt": 3, + "port": 1, + "freq": 868300000, + "toa": 1319, + "dr": "SF12 BW125 4/5", + "ack": false, + "gws": [ + { + "rssi": -38, + "snr": 8.5, + "ts": 1690901260493, + "time": "2023-08-01T14:47:40.493Z", + "gweui": "1020304080706050", + "ant": 0 + }, + { + "rssi": -42, + "snr": 8.8, + "ts": 1690901260495, + "time": "2023-08-01T14:47:40.495Z", + "gweui": "1020304081716151", + "ant": 0 + } + ], + "bat": 143, + "data": "020b50000309018a8c09438a9809278a920b3c8aa50c9c8a8c11e08aa500000000000000000b3b" +} diff --git a/VENDORS/Decentlab/DL-SMTP/LORIOT/uplink/result_2.json b/VENDORS/Decentlab/DL-SMTP/LORIOT/uplink/result_2.json new file mode 100644 index 00000000..619737db --- /dev/null +++ b/VENDORS/Decentlab/DL-SMTP/LORIOT/uplink/result_2.json @@ -0,0 +1,34 @@ +{ + "deviceName": "2896", + "deviceType": "DL-SMTP", + "attributes": { + "lora_dev_eui": "0102030405060708", + "protocol_version": 2 + }, + "telemetry": [{ + "ts": 1690901260493, + "values": { + "soil_moisture_at_depth_0": -0.39, + "soil_temperature_at_depth_0": 27, + "soil_moisture_at_depth_1": -0.258, + "soil_temperature_at_depth_1": 27.12, + "soil_moisture_at_depth_2": -0.314, + "soil_temperature_at_depth_2": 27.06, + "soil_moisture_at_depth_3": 0.752, + "soil_temperature_at_depth_3": 27.25, + "soil_moisture_at_depth_4": 1.456, + "soil_temperature_at_depth_4": 27, + "soil_moisture_at_depth_5": 4.152, + "soil_temperature_at_depth_5": 27.25, + "soil_moisture_at_depth_6": -5, + "soil_temperature_at_depth_6": -327.68, + "soil_moisture_at_depth_7": -5, + "soil_temperature_at_depth_7": -327.68, + "battery_voltage": 2.875, + "lora_frame_counter": 3, + "lora_frame_port": 1, + "lora_frequency": 868300000, + "lora_spreading_factor": 12 + } + }] +} \ No newline at end of file diff --git a/VENDORS/Decentlab/DL-TBRG/LORIOT/uplink/payload_2.json b/VENDORS/Decentlab/DL-TBRG/LORIOT/uplink/payload_2.json new file mode 100644 index 00000000..5df82e32 --- /dev/null +++ b/VENDORS/Decentlab/DL-TBRG/LORIOT/uplink/payload_2.json @@ -0,0 +1,32 @@ +{ + "cmd": "gw", + "seqno": 4, + "EUI": "0102030405060708", + "ts": 1690901260493, + "fcnt": 3, + "port": 1, + "freq": 868300000, + "toa": 1319, + "dr": "SF12 BW125 4/5", + "ack": false, + "gws": [ + { + "rssi": -38, + "snr": 8.5, + "ts": 1690901260493, + "time": "2023-08-01T14:47:40.493Z", + "gweui": "1020304080706050", + "ant": 0 + }, + { + "rssi": -42, + "snr": 8.8, + "ts": 1690901260495, + "time": "2023-08-01T14:47:40.495Z", + "gweui": "1020304081716151", + "ant": 0 + } + ], + "bat": 143, + "data": "0202f800020c54" +} diff --git a/VENDORS/Decentlab/DL-TBRG/LORIOT/uplink/result_2.json b/VENDORS/Decentlab/DL-TBRG/LORIOT/uplink/result_2.json new file mode 100644 index 00000000..1292ae6f --- /dev/null +++ b/VENDORS/Decentlab/DL-TBRG/LORIOT/uplink/result_2.json @@ -0,0 +1,18 @@ +{ + "deviceName": "760", + "deviceType": "DL-TBRG", + "attributes": { + "lora_dev_eui": "0102030405060708", + "protocol_version": 2 + }, + "telemetry": [{ + "ts": 1690901260493, + "values": { + "battery_voltage": 3.156, + "lora_frame_counter": 3, + "lora_frame_port": 1, + "lora_frequency": 868300000, + "lora_spreading_factor": 12 + } + }] +} \ No newline at end of file diff --git a/VENDORS/Decentlab/DL-TP/LORIOT/uplink/payload_2.json b/VENDORS/Decentlab/DL-TP/LORIOT/uplink/payload_2.json new file mode 100644 index 00000000..455744d2 --- /dev/null +++ b/VENDORS/Decentlab/DL-TP/LORIOT/uplink/payload_2.json @@ -0,0 +1,32 @@ +{ + "cmd": "gw", + "seqno": 4, + "EUI": "0102030405060708", + "ts": 1690901260493, + "fcnt": 3, + "port": 1, + "freq": 868300000, + "toa": 1319, + "dr": "SF12 BW125 4/5", + "ack": false, + "gws": [ + { + "rssi": -38, + "snr": 8.5, + "ts": 1690901260493, + "time": "2023-08-01T14:47:40.493Z", + "gweui": "1020304080706050", + "ant": 0 + }, + { + "rssi": -42, + "snr": 8.8, + "ts": 1690901260495, + "time": "2023-08-01T14:47:40.495Z", + "gweui": "1020304081716151", + "ant": 0 + } + ], + "bat": 143, + "data": "023e3e00038abc8a928aa08a848ab38a898ac38aad8ab78a928aa1000000000000000000000afc" +} diff --git a/VENDORS/Decentlab/DL-TP/LORIOT/uplink/result_2.json b/VENDORS/Decentlab/DL-TP/LORIOT/uplink/result_2.json new file mode 100644 index 00000000..5c6f1e18 --- /dev/null +++ b/VENDORS/Decentlab/DL-TP/LORIOT/uplink/result_2.json @@ -0,0 +1,34 @@ +{ + "deviceName": "15934", + "deviceType": "DL-TP", + "attributes": { + "lora_dev_eui": "0102030405060708", + "protocol_version": 2 + }, + "telemetry": [{ + "ts": 1690901260493, + "values": { + "temperature_at_level_0": 27.48, + "temperature_at_level_1": 27.06, + "temperature_at_level_2": 27.2, + "temperature_at_level_3": 26.92, + "temperature_at_level_4": 27.39, + "temperature_at_level_5": 26.97, + "temperature_at_level_6": 27.55, + "temperature_at_level_7": 27.33, + "temperature_at_level_8": 27.43, + "temperature_at_level_9": 27.06, + "temperature_at_level_10": 27.21, + "temperature_at_level_11": -327.68, + "temperature_at_level_12": -327.68, + "temperature_at_level_13": -327.68, + "temperature_at_level_14": -327.68, + "temperature_at_level_15": -327.68, + "battery_voltage": 2.812, + "lora_frame_counter": 3, + "lora_frame_port": 1, + "lora_frequency": 868300000, + "lora_spreading_factor": 12 + } + }] +} \ No newline at end of file diff --git a/VENDORS/Decentlab/DL-TRS11/LORIOT/uplink/payload_1.json b/VENDORS/Decentlab/DL-TRS11/LORIOT/uplink/payload_1.json new file mode 100644 index 00000000..83719e76 --- /dev/null +++ b/VENDORS/Decentlab/DL-TRS11/LORIOT/uplink/payload_1.json @@ -0,0 +1,32 @@ +{ + "cmd": "gw", + "seqno": 4, + "EUI": "0102030405060708", + "ts": 1690901260493, + "fcnt": 3, + "port": 1, + "freq": 868300000, + "toa": 1319, + "dr": "SF12 BW125 4/5", + "ack": false, + "gws": [ + { + "rssi": -38, + "snr": 8.5, + "ts": 1690901260493, + "time": "2023-08-01T14:47:40.493Z", + "gweui": "1020304080706050", + "ant": 0 + }, + { + "rssi": -42, + "snr": 8.8, + "ts": 1690901260495, + "time": "2023-08-01T14:47:40.495Z", + "gweui": "1020304081716151", + "ant": 0 + } + ], + "bat": 143, + "data": "0210d50003463f810b0c79" +} diff --git a/VENDORS/Decentlab/DL-TRS11/LORIOT/uplink/result_1.json b/VENDORS/Decentlab/DL-TRS11/LORIOT/uplink/result_1.json new file mode 100644 index 00000000..bd1dc349 --- /dev/null +++ b/VENDORS/Decentlab/DL-TRS11/LORIOT/uplink/result_1.json @@ -0,0 +1,21 @@ +{ + "deviceName": "4309", + "deviceType": "DL-TRS11", + "attributes": { + "lora_dev_eui": "0102030405060708", + "protocol_version": 2 + }, + "telemetry": [{ + "ts": 1690901260493, + "values": { + "dielectric_permittivity": 1.0259018697121183, + "volumetric_water_content": 0.0019605699999999393, + "soil_temperature": 26.7, + "battery_voltage": 3.193, + "lora_frame_counter": 3, + "lora_frame_port": 1, + "lora_frequency": 868300000, + "lora_spreading_factor": 12 + } + }] +} \ No newline at end of file diff --git a/VENDORS/Decentlab/DL-TRS12/LORIOT/uplink/payload_2.json b/VENDORS/Decentlab/DL-TRS12/LORIOT/uplink/payload_2.json new file mode 100644 index 00000000..ea76deee --- /dev/null +++ b/VENDORS/Decentlab/DL-TRS12/LORIOT/uplink/payload_2.json @@ -0,0 +1,32 @@ +{ + "cmd": "gw", + "seqno": 4, + "EUI": "0102030405060708", + "ts": 1690901260493, + "fcnt": 3, + "port": 1, + "freq": 868300000, + "toa": 1319, + "dr": "SF12 BW125 4/5", + "ack": false, + "gws": [ + { + "rssi": -38, + "snr": 8.5, + "ts": 1690901260493, + "time": "2023-08-01T14:47:40.493Z", + "gweui": "1020304080706050", + "ant": 0 + }, + { + "rssi": -42, + "snr": 8.8, + "ts": 1690901260495, + "time": "2023-08-01T14:47:40.495Z", + "gweui": "1020304081716151", + "ant": 0 + } + ], + "bat": 143, + "data": "0210d3000346be813d00000c80" +} diff --git a/VENDORS/Decentlab/DL-TRS12/LORIOT/uplink/result_2.json b/VENDORS/Decentlab/DL-TRS12/LORIOT/uplink/result_2.json new file mode 100644 index 00000000..b5f28413 --- /dev/null +++ b/VENDORS/Decentlab/DL-TRS12/LORIOT/uplink/result_2.json @@ -0,0 +1,22 @@ +{ + "deviceName": "4307", + "deviceType": "DL-TRS12", + "attributes": { + "lora_dev_eui": "0102030405060708", + "protocol_version": 2 + }, + "telemetry": [{ + "ts": 1690901260493, + "values": { + "dielectric_permittivity": 1.1831248966814998, + "volumetric_water_content": 0.006886900000000029, + "soil_temperature": 31.7, + "electrical_conductivity": 0, + "battery_voltage": 3.2, + "lora_frame_counter": 3, + "lora_frame_port": 1, + "lora_frequency": 868300000, + "lora_spreading_factor": 12 + } + }] +} \ No newline at end of file diff --git a/VENDORS/Decentlab/DL-TRS21/LORIOT/uplink/payload_2.json b/VENDORS/Decentlab/DL-TRS21/LORIOT/uplink/payload_2.json new file mode 100644 index 00000000..11124286 --- /dev/null +++ b/VENDORS/Decentlab/DL-TRS21/LORIOT/uplink/payload_2.json @@ -0,0 +1,32 @@ +{ + "cmd": "gw", + "seqno": 4, + "EUI": "0102030405060708", + "ts": 1690901260493, + "fcnt": 3, + "port": 1, + "freq": 868300000, + "toa": 1319, + "dr": "SF12 BW125 4/5", + "ack": false, + "gws": [ + { + "rssi": -38, + "snr": 8.5, + "ts": 1690901260493, + "time": "2023-08-01T14:47:40.493Z", + "gweui": "1020304080706050", + "ant": 0 + }, + { + "rssi": -42, + "snr": 8.8, + "ts": 1690901260495, + "time": "2023-08-01T14:47:40.495Z", + "gweui": "1020304081716151", + "ant": 0 + } + ], + "bat": 143, + "data": "0201920003007580a10c25" +} diff --git a/VENDORS/Decentlab/DL-TRS21/LORIOT/uplink/result_2.json b/VENDORS/Decentlab/DL-TRS21/LORIOT/uplink/result_2.json new file mode 100644 index 00000000..db814c91 --- /dev/null +++ b/VENDORS/Decentlab/DL-TRS21/LORIOT/uplink/result_2.json @@ -0,0 +1,20 @@ +{ + "deviceName": "402", + "deviceType": "DL-TRS21", + "attributes": { + "lora_dev_eui": "0102030405060708", + "protocol_version": 2 + }, + "telemetry": [{ + "ts": 1690901260493, + "values": { + "water_potential": -11.7, + "soil_temperature": 16.1, + "battery_voltage": 3.109, + "lora_frame_counter": 3, + "lora_frame_port": 1, + "lora_frequency": 868300000, + "lora_spreading_factor": 12 + } + }] +} \ No newline at end of file diff --git a/VENDORS/Decentlab/DL-TRS21/info.json b/VENDORS/Decentlab/DL-TRS21/info.json index 84300074..ad9e9fc1 100644 --- a/VENDORS/Decentlab/DL-TRS21/info.json +++ b/VENDORS/Decentlab/DL-TRS21/info.json @@ -1,5 +1,5 @@ { "url": "https://www.decentlab.com/products/soil-water-potential-and-temperature-sensor-for-lorawan", - "label": "DL-TRS12: Soil water potential and temperature sensor", + "label": "DL-TRS21: Soil water potential and temperature sensor", "description": "The Decentlab DL-TRS21 is a soil water potential and temperature sensor for LoRaWAN®. Suitable for applications such as irrigation control, smart agriculture, parks, and golf courses." } \ No newline at end of file diff --git a/VENDORS/Decentlab/DL-WRM/LORIOT/uplink/payload_2.json b/VENDORS/Decentlab/DL-WRM/LORIOT/uplink/payload_2.json new file mode 100644 index 00000000..fdc4edeb --- /dev/null +++ b/VENDORS/Decentlab/DL-WRM/LORIOT/uplink/payload_2.json @@ -0,0 +1,32 @@ +{ + "cmd": "gw", + "seqno": 4, + "EUI": "0102030405060708", + "ts": 1690901260493, + "fcnt": 3, + "port": 1, + "freq": 868300000, + "toa": 1319, + "dr": "SF12 BW125 4/5", + "ack": false, + "gws": [ + { + "rssi": -38, + "snr": 8.5, + "ts": 1690901260493, + "time": "2023-08-01T14:47:40.493Z", + "gweui": "1020304080706050", + "ant": 0 + }, + { + "rssi": -42, + "snr": 8.8, + "ts": 1690901260495, + "time": "2023-08-01T14:47:40.495Z", + "gweui": "1020304081716151", + "ant": 0 + } + ], + "bat": 143, + "data": "021a1000040c60" +} diff --git a/VENDORS/Decentlab/DL-WRM/LORIOT/uplink/result_2.json b/VENDORS/Decentlab/DL-WRM/LORIOT/uplink/result_2.json new file mode 100644 index 00000000..3f42e961 --- /dev/null +++ b/VENDORS/Decentlab/DL-WRM/LORIOT/uplink/result_2.json @@ -0,0 +1,18 @@ +{ + "deviceName": "6672", + "deviceType": "DL-WRM", + "attributes": { + "lora_dev_eui": "0102030405060708", + "protocol_version": 2 + }, + "telemetry": [{ + "ts": 1690901260493, + "values": { + "battery_voltage": 3.168, + "lora_frame_counter": 3, + "lora_frame_port": 1, + "lora_frequency": 868300000, + "lora_spreading_factor": 12 + } + }] +} \ No newline at end of file diff --git a/VENDORS/Decentlab/DL-ZN1/LORIOT/uplink/payload_2.json b/VENDORS/Decentlab/DL-ZN1/LORIOT/uplink/payload_2.json new file mode 100644 index 00000000..4b89cdb2 --- /dev/null +++ b/VENDORS/Decentlab/DL-ZN1/LORIOT/uplink/payload_2.json @@ -0,0 +1,32 @@ +{ + "cmd": "gw", + "seqno": 4, + "EUI": "0102030405060708", + "ts": 1690901260493, + "fcnt": 3, + "port": 1, + "freq": 868300000, + "toa": 1319, + "dr": "SF12 BW125 4/5", + "ack": false, + "gws": [ + { + "rssi": -38, + "snr": 8.5, + "ts": 1690901260493, + "time": "2023-08-01T14:47:40.493Z", + "gweui": "1020304080706050", + "ant": 0 + }, + { + "rssi": -42, + "snr": 8.8, + "ts": 1690901260495, + "time": "2023-08-01T14:47:40.495Z", + "gweui": "1020304081716151", + "ant": 0 + } + ], + "bat": 143, + "data": "0211110003409a00860c54" +} diff --git a/VENDORS/Decentlab/DL-ZN1/LORIOT/uplink/result_2.json b/VENDORS/Decentlab/DL-ZN1/LORIOT/uplink/result_2.json new file mode 100644 index 00000000..6dede2dd --- /dev/null +++ b/VENDORS/Decentlab/DL-ZN1/LORIOT/uplink/result_2.json @@ -0,0 +1,19 @@ +{ + "deviceName": "4369", + "deviceType": "DL-ZN1", + "attributes": { + "lora_dev_eui": "0102030405060708", + "protocol_version": 2 + }, + "telemetry": [{ + "ts": 1690901260493, + "values": { + "dendrometer_position": 976.9296646118164, + "battery_voltage": 3.156, + "lora_frame_counter": 3, + "lora_frame_port": 1, + "lora_frequency": 868300000, + "lora_spreading_factor": 12 + } + }] +} \ No newline at end of file diff --git a/VENDORS/Decentlab/DL-ZN2/LORIOT/uplink/payload_1.json b/VENDORS/Decentlab/DL-ZN2/LORIOT/uplink/payload_1.json new file mode 100644 index 00000000..9563f60b --- /dev/null +++ b/VENDORS/Decentlab/DL-ZN2/LORIOT/uplink/payload_1.json @@ -0,0 +1,32 @@ +{ + "cmd": "gw", + "seqno": 4, + "EUI": "0102030405060708", + "ts": 1690901260493, + "fcnt": 3, + "port": 1, + "freq": 868300000, + "toa": 1319, + "dr": "SF12 BW125 4/5", + "ack": false, + "gws": [ + { + "rssi": -38, + "snr": 8.5, + "ts": 1690901260493, + "time": "2023-08-01T14:47:40.493Z", + "gweui": "1020304080706050", + "ant": 0 + }, + { + "rssi": -42, + "snr": 8.8, + "ts": 1690901260495, + "time": "2023-08-01T14:47:40.495Z", + "gweui": "1020304081716151", + "ant": 0 + } + ], + "bat": 143, + "data": "0211110003409a00863039003e0c54" +} diff --git a/VENDORS/Decentlab/DL-ZN2/LORIOT/uplink/result_1.json b/VENDORS/Decentlab/DL-ZN2/LORIOT/uplink/result_1.json new file mode 100644 index 00000000..0113f60a --- /dev/null +++ b/VENDORS/Decentlab/DL-ZN2/LORIOT/uplink/result_1.json @@ -0,0 +1,20 @@ +{ + "deviceName": "4369", + "deviceType": "DL-ZN2", + "attributes": { + "lora_dev_eui": "0102030405060708", + "protocol_version": 2 + }, + "telemetry": [{ + "ts": 1690901260493, + "values": { + "dendrometer_a_position": 976.9296646118164, + "dendrometer_b_position": 11259.996891021729, + "battery_voltage": 3.156, + "lora_frame_counter": 3, + "lora_frame_port": 1, + "lora_frequency": 868300000, + "lora_spreading_factor": 12 + } + }] +} \ No newline at end of file From 9e56357fd2dc417b2164ea0a5a40576b1f57ea10 Mon Sep 17 00:00:00 2001 From: Artem Barysh Date: Thu, 26 Dec 2024 17:58:06 +0200 Subject: [PATCH 29/33] Fixed result output for dl-dlr2-005 --- VENDORS/Decentlab/DL-DLR2-005/LORIOT/uplink/result_2.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VENDORS/Decentlab/DL-DLR2-005/LORIOT/uplink/result_2.json b/VENDORS/Decentlab/DL-DLR2-005/LORIOT/uplink/result_2.json index 3547be06..4c3265a7 100644 --- a/VENDORS/Decentlab/DL-DLR2-005/LORIOT/uplink/result_2.json +++ b/VENDORS/Decentlab/DL-DLR2-005/LORIOT/uplink/result_2.json @@ -1,6 +1,6 @@ { "deviceName": "4410", - "deviceType": "DL-DLR2-004", + "deviceType": "DL-DLR2-005", "attributes": { "lora_dev_eui": "0102030405060708", "protocol_version": 2 From d0931c94ff9553da70965860a33f85d326bf1002 Mon Sep 17 00:00:00 2001 From: Artem Barysh Date: Thu, 26 Dec 2024 18:17:37 +0200 Subject: [PATCH 30/33] Fixed result output for dl-dlr2-003 --- VENDORS/Decentlab/DL-DLR2-003/LORIOT/uplink/result_1.json | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/VENDORS/Decentlab/DL-DLR2-003/LORIOT/uplink/result_1.json b/VENDORS/Decentlab/DL-DLR2-003/LORIOT/uplink/result_1.json index 9f235539..dfa3dab0 100644 --- a/VENDORS/Decentlab/DL-DLR2-003/LORIOT/uplink/result_1.json +++ b/VENDORS/Decentlab/DL-DLR2-003/LORIOT/uplink/result_1.json @@ -1,6 +1,6 @@ { "deviceName": "6558", - "deviceType": "DL-DLR2-002", + "deviceType": "DL-DLR2-003", "attributes": { "lora_dev_eui": "0102030405060708", "protocol_version": 2 @@ -8,10 +8,8 @@ "telemetry": [{ "ts": 1690901260493, "values": { - "pulse_count": 0, - "pulse_interval": 600, - "cumulative_pulse_count": 0, - "battery_voltage": 3.227, + "input": 0, + "battery_voltage": 0.6, "lora_frame_counter": 3, "lora_frame_port": 1, "lora_frequency": 868300000, From bd48b9a528bd306f10995dd22a9ce1e83b1aed3c Mon Sep 17 00:00:00 2001 From: ArtemAbrams Date: Mon, 30 Dec 2024 16:49:30 +0200 Subject: [PATCH 31/33] Added HTTP integration for Milesight devices --- .../AM102/HTTP/uplink/converter.json | 29 +++++++++++ .../Milesight/AM102/HTTP/uplink/metadata.json | 4 ++ .../Milesight/AM102/HTTP/uplink/payload.json | 31 ++++++++++++ .../Milesight/AM102/HTTP/uplink/result.json | 20 ++++++++ .../AM102L/HTTP/uplink/converter.json | 29 +++++++++++ .../AM102L/HTTP/uplink/metadata.json | 4 ++ .../Milesight/AM102L/HTTP/uplink/payload.json | 31 ++++++++++++ .../Milesight/AM102L/HTTP/uplink/result.json | 20 ++++++++ .../AM103/HTTP/uplink/converter.json | 29 +++++++++++ .../Milesight/AM103/HTTP/uplink/metadata.json | 4 ++ .../Milesight/AM103/HTTP/uplink/payload.json | 31 ++++++++++++ .../Milesight/AM103/HTTP/uplink/result.json | 28 +++++++++++ .../AM103L/HTTP/uplink/converter.json | 29 +++++++++++ .../AM103L/HTTP/uplink/metadata.json | 4 ++ .../Milesight/AM103L/HTTP/uplink/payload.json | 31 ++++++++++++ .../Milesight/AM103L/HTTP/uplink/result.json | 28 +++++++++++ .../AM104/HTTP/uplink/converter.json | 29 +++++++++++ .../Milesight/AM104/HTTP/uplink/metadata.json | 4 ++ .../Milesight/AM104/HTTP/uplink/payload.json | 31 ++++++++++++ .../Milesight/AM104/HTTP/uplink/result.json | 24 ++++++++++ .../AM107/HTTP/uplink/converter.json | 29 +++++++++++ .../Milesight/AM107/HTTP/uplink/metadata.json | 4 ++ .../Milesight/AM107/HTTP/uplink/payload.json | 31 ++++++++++++ .../Milesight/AM107/HTTP/uplink/result.json | 27 +++++++++++ .../AM307/HTTP/uplink/converter.json | 29 +++++++++++ .../Milesight/AM307/HTTP/uplink/metadata.json | 4 ++ .../Milesight/AM307/HTTP/uplink/payload.json | 31 ++++++++++++ .../Milesight/AM307/HTTP/uplink/result.json | 37 ++++++++++++++ .../AM307L/HTTP/uplink/converter.json | 29 +++++++++++ .../AM307L/HTTP/uplink/metadata.json | 4 ++ .../Milesight/AM307L/HTTP/uplink/payload.json | 31 ++++++++++++ .../Milesight/AM307L/HTTP/uplink/result.json | 37 ++++++++++++++ .../AM308/HTTP/uplink/converter.json | 29 +++++++++++ .../Milesight/AM308/HTTP/uplink/metadata.json | 4 ++ .../Milesight/AM308/HTTP/uplink/payload.json | 31 ++++++++++++ .../Milesight/AM308/HTTP/uplink/result.json | 41 ++++++++++++++++ .../AM308L/HTTP/uplink/converter.json | 29 +++++++++++ .../AM308L/HTTP/uplink/metadata.json | 4 ++ .../Milesight/AM308L/HTTP/uplink/payload.json | 31 ++++++++++++ .../Milesight/AM308L/HTTP/uplink/result.json | 41 ++++++++++++++++ .../AM319/HTTP/uplink/converter.json | 29 +++++++++++ .../Milesight/AM319/HTTP/uplink/metadata.json | 4 ++ .../Milesight/AM319/HTTP/uplink/payload.json | 31 ++++++++++++ .../Milesight/AM319/HTTP/uplink/result.json | 43 +++++++++++++++++ .../AM319L/HTTP/uplink/converter.json | 29 +++++++++++ .../AM319L/HTTP/uplink/metadata.json | 4 ++ .../Milesight/AM319L/HTTP/uplink/payload.json | 31 ++++++++++++ .../Milesight/AM319L/HTTP/uplink/result.json | 43 +++++++++++++++++ .../AT101/HTTP/uplink/converter.json | 29 +++++++++++ .../Milesight/AT101/HTTP/uplink/metadata.json | 4 ++ .../Milesight/AT101/HTTP/uplink/payload.json | 31 ++++++++++++ .../Milesight/AT101/HTTP/uplink/result.json | 48 +++++++++++++++++++ .../ChirpStack/uplink/converter.json | 2 +- .../CT101-CT103/HTTP/uplink/converter.json | 31 ++++++++++++ .../CT101-CT103/HTTP/uplink/metadata.json | 4 ++ .../CT101-CT103/HTTP/uplink/payload.json | 31 ++++++++++++ .../CT101-CT103/HTTP/uplink/result.json | 22 +++++++++ .../DS3604/HTTP/uplink/converter.json | 29 +++++++++++ .../DS3604/HTTP/uplink/metadata.json | 4 ++ .../Milesight/DS3604/HTTP/uplink/payload.json | 31 ++++++++++++ .../Milesight/DS3604/HTTP/uplink/result.json | 21 ++++++++ .../EM300-CL/HTTP/uplink/converter.json | 29 +++++++++++ .../EM300-CL/HTTP/uplink/metadata.json | 4 ++ .../EM300-CL/HTTP/uplink/payload.json | 31 ++++++++++++ .../EM300-CL/HTTP/uplink/result.json | 19 ++++++++ .../EM310-TILT/HTTP/uplink/converter.json | 29 +++++++++++ .../EM310-TILT/HTTP/uplink/metadata.json | 4 ++ .../EM310-TILT/HTTP/uplink/payload.json | 31 ++++++++++++ .../EM310-TILT/HTTP/uplink/result.json | 23 +++++++++ .../EM310-UDL/HTTP/uplink/converter.json | 29 +++++++++++ .../EM310-UDL/HTTP/uplink/metadata.json | 4 ++ .../EM310-UDL/HTTP/uplink/payload.json | 31 ++++++++++++ .../EM310-UDL/HTTP/uplink/result.json | 20 ++++++++ .../EM320-TILT/HTTP/uplink/converter.json | 29 +++++++++++ .../EM320-TILT/HTTP/uplink/metadata.json | 4 ++ .../EM320-TILT/HTTP/uplink/payload.json | 31 ++++++++++++ .../EM320-TILT/HTTP/uplink/result.json | 24 ++++++++++ .../EM400-TLD/HTTP/uplink/converter.json | 29 +++++++++++ .../EM400-TLD/HTTP/uplink/metadata.json | 4 ++ .../EM400-TLD/HTTP/uplink/payload.json | 31 ++++++++++++ .../EM400-TLD/HTTP/uplink/result.json | 21 ++++++++ .../EM400-UDL/HTTP/uplink/converter.json | 29 +++++++++++ .../EM400-UDL/HTTP/uplink/metadata.json | 4 ++ .../EM400-UDL/HTTP/uplink/payload.json | 31 ++++++++++++ .../EM400-UDL/HTTP/uplink/result.json | 21 ++++++++ .../EM500-CO2/HTTP/uplink/converter.json | 29 +++++++++++ .../EM500-CO2/HTTP/uplink/metadata.json | 4 ++ .../EM500-CO2/HTTP/uplink/payload.json | 31 ++++++++++++ .../EM500-CO2/HTTP/uplink/result.json | 22 +++++++++ .../GS101/HTTP/uplink/converter.json | 29 +++++++++++ .../Milesight/GS101/HTTP/uplink/metadata.json | 4 ++ .../Milesight/GS101/HTTP/uplink/payload.json | 31 ++++++++++++ .../Milesight/GS101/HTTP/uplink/result.json | 20 ++++++++ .../GS301/HTTP/uplink/converter.json | 29 +++++++++++ .../Milesight/GS301/HTTP/uplink/metadata.json | 4 ++ .../Milesight/GS301/HTTP/uplink/payload.json | 31 ++++++++++++ .../Milesight/GS301/HTTP/uplink/result.json | 22 +++++++++ .../TS101/HTTP/uplink/converter.json | 29 +++++++++++ .../Milesight/TS101/HTTP/uplink/metadata.json | 4 ++ .../Milesight/TS101/HTTP/uplink/payload.json | 31 ++++++++++++ .../Milesight/TS101/HTTP/uplink/result.json | 19 ++++++++ .../TS201/HTTP/uplink/converter.json | 29 +++++++++++ .../Milesight/TS201/HTTP/uplink/metadata.json | 4 ++ .../Milesight/TS201/HTTP/uplink/payload.json | 31 ++++++++++++ .../Milesight/TS201/HTTP/uplink/result.json | 23 +++++++++ .../WS101/HTTP/uplink/converter.json | 29 +++++++++++ .../Milesight/WS101/HTTP/uplink/metadata.json | 4 ++ .../Milesight/WS101/HTTP/uplink/payload.json | 31 ++++++++++++ .../Milesight/WS101/HTTP/uplink/result.json | 19 ++++++++ .../WS201/HTTP/uplink/converter.json | 29 +++++++++++ .../Milesight/WS201/HTTP/uplink/metadata.json | 4 ++ .../Milesight/WS201/HTTP/uplink/payload.json | 31 ++++++++++++ .../Milesight/WS201/HTTP/uplink/result.json | 20 ++++++++ .../WS202/HTTP/uplink/converter.json | 29 +++++++++++ .../Milesight/WS202/HTTP/uplink/metadata.json | 4 ++ .../Milesight/WS202/HTTP/uplink/payload.json | 31 ++++++++++++ .../Milesight/WS202/HTTP/uplink/result.json | 20 ++++++++ .../WS301/HTTP/uplink/converter.json | 29 +++++++++++ .../Milesight/WS301/HTTP/uplink/metadata.json | 4 ++ .../Milesight/WS301/HTTP/uplink/payload.json | 31 ++++++++++++ .../Milesight/WS301/HTTP/uplink/result.json | 20 ++++++++ .../WS302/HTTP/uplink/converter.json | 29 +++++++++++ .../Milesight/WS302/HTTP/uplink/metadata.json | 4 ++ .../Milesight/WS302/HTTP/uplink/payload.json | 31 ++++++++++++ .../Milesight/WS302/HTTP/uplink/result.json | 21 ++++++++ .../WS303/HTTP/uplink/converter.json | 29 +++++++++++ .../Milesight/WS303/HTTP/uplink/metadata.json | 4 ++ .../Milesight/WS303/HTTP/uplink/payload.json | 31 ++++++++++++ .../Milesight/WS303/HTTP/uplink/result.json | 19 ++++++++ 129 files changed, 2884 insertions(+), 1 deletion(-) create mode 100644 VENDORS/Milesight/AM102/HTTP/uplink/converter.json create mode 100644 VENDORS/Milesight/AM102/HTTP/uplink/metadata.json create mode 100644 VENDORS/Milesight/AM102/HTTP/uplink/payload.json create mode 100644 VENDORS/Milesight/AM102/HTTP/uplink/result.json create mode 100644 VENDORS/Milesight/AM102L/HTTP/uplink/converter.json create mode 100644 VENDORS/Milesight/AM102L/HTTP/uplink/metadata.json create mode 100644 VENDORS/Milesight/AM102L/HTTP/uplink/payload.json create mode 100644 VENDORS/Milesight/AM102L/HTTP/uplink/result.json create mode 100644 VENDORS/Milesight/AM103/HTTP/uplink/converter.json create mode 100644 VENDORS/Milesight/AM103/HTTP/uplink/metadata.json create mode 100644 VENDORS/Milesight/AM103/HTTP/uplink/payload.json create mode 100644 VENDORS/Milesight/AM103/HTTP/uplink/result.json create mode 100644 VENDORS/Milesight/AM103L/HTTP/uplink/converter.json create mode 100644 VENDORS/Milesight/AM103L/HTTP/uplink/metadata.json create mode 100644 VENDORS/Milesight/AM103L/HTTP/uplink/payload.json create mode 100644 VENDORS/Milesight/AM103L/HTTP/uplink/result.json create mode 100644 VENDORS/Milesight/AM104/HTTP/uplink/converter.json create mode 100644 VENDORS/Milesight/AM104/HTTP/uplink/metadata.json create mode 100644 VENDORS/Milesight/AM104/HTTP/uplink/payload.json create mode 100644 VENDORS/Milesight/AM104/HTTP/uplink/result.json create mode 100644 VENDORS/Milesight/AM107/HTTP/uplink/converter.json create mode 100644 VENDORS/Milesight/AM107/HTTP/uplink/metadata.json create mode 100644 VENDORS/Milesight/AM107/HTTP/uplink/payload.json create mode 100644 VENDORS/Milesight/AM107/HTTP/uplink/result.json create mode 100644 VENDORS/Milesight/AM307/HTTP/uplink/converter.json create mode 100644 VENDORS/Milesight/AM307/HTTP/uplink/metadata.json create mode 100644 VENDORS/Milesight/AM307/HTTP/uplink/payload.json create mode 100644 VENDORS/Milesight/AM307/HTTP/uplink/result.json create mode 100644 VENDORS/Milesight/AM307L/HTTP/uplink/converter.json create mode 100644 VENDORS/Milesight/AM307L/HTTP/uplink/metadata.json create mode 100644 VENDORS/Milesight/AM307L/HTTP/uplink/payload.json create mode 100644 VENDORS/Milesight/AM307L/HTTP/uplink/result.json create mode 100644 VENDORS/Milesight/AM308/HTTP/uplink/converter.json create mode 100644 VENDORS/Milesight/AM308/HTTP/uplink/metadata.json create mode 100644 VENDORS/Milesight/AM308/HTTP/uplink/payload.json create mode 100644 VENDORS/Milesight/AM308/HTTP/uplink/result.json create mode 100644 VENDORS/Milesight/AM308L/HTTP/uplink/converter.json create mode 100644 VENDORS/Milesight/AM308L/HTTP/uplink/metadata.json create mode 100644 VENDORS/Milesight/AM308L/HTTP/uplink/payload.json create mode 100644 VENDORS/Milesight/AM308L/HTTP/uplink/result.json create mode 100644 VENDORS/Milesight/AM319/HTTP/uplink/converter.json create mode 100644 VENDORS/Milesight/AM319/HTTP/uplink/metadata.json create mode 100644 VENDORS/Milesight/AM319/HTTP/uplink/payload.json create mode 100644 VENDORS/Milesight/AM319/HTTP/uplink/result.json create mode 100644 VENDORS/Milesight/AM319L/HTTP/uplink/converter.json create mode 100644 VENDORS/Milesight/AM319L/HTTP/uplink/metadata.json create mode 100644 VENDORS/Milesight/AM319L/HTTP/uplink/payload.json create mode 100644 VENDORS/Milesight/AM319L/HTTP/uplink/result.json create mode 100644 VENDORS/Milesight/AT101/HTTP/uplink/converter.json create mode 100644 VENDORS/Milesight/AT101/HTTP/uplink/metadata.json create mode 100644 VENDORS/Milesight/AT101/HTTP/uplink/payload.json create mode 100644 VENDORS/Milesight/AT101/HTTP/uplink/result.json create mode 100644 VENDORS/Milesight/CT101-CT103/HTTP/uplink/converter.json create mode 100644 VENDORS/Milesight/CT101-CT103/HTTP/uplink/metadata.json create mode 100644 VENDORS/Milesight/CT101-CT103/HTTP/uplink/payload.json create mode 100644 VENDORS/Milesight/CT101-CT103/HTTP/uplink/result.json create mode 100644 VENDORS/Milesight/DS3604/HTTP/uplink/converter.json create mode 100644 VENDORS/Milesight/DS3604/HTTP/uplink/metadata.json create mode 100644 VENDORS/Milesight/DS3604/HTTP/uplink/payload.json create mode 100644 VENDORS/Milesight/DS3604/HTTP/uplink/result.json create mode 100644 VENDORS/Milesight/EM300-CL/HTTP/uplink/converter.json create mode 100644 VENDORS/Milesight/EM300-CL/HTTP/uplink/metadata.json create mode 100644 VENDORS/Milesight/EM300-CL/HTTP/uplink/payload.json create mode 100644 VENDORS/Milesight/EM300-CL/HTTP/uplink/result.json create mode 100644 VENDORS/Milesight/EM310-TILT/HTTP/uplink/converter.json create mode 100644 VENDORS/Milesight/EM310-TILT/HTTP/uplink/metadata.json create mode 100644 VENDORS/Milesight/EM310-TILT/HTTP/uplink/payload.json create mode 100644 VENDORS/Milesight/EM310-TILT/HTTP/uplink/result.json create mode 100644 VENDORS/Milesight/EM310-UDL/HTTP/uplink/converter.json create mode 100644 VENDORS/Milesight/EM310-UDL/HTTP/uplink/metadata.json create mode 100644 VENDORS/Milesight/EM310-UDL/HTTP/uplink/payload.json create mode 100644 VENDORS/Milesight/EM310-UDL/HTTP/uplink/result.json create mode 100644 VENDORS/Milesight/EM320-TILT/HTTP/uplink/converter.json create mode 100644 VENDORS/Milesight/EM320-TILT/HTTP/uplink/metadata.json create mode 100644 VENDORS/Milesight/EM320-TILT/HTTP/uplink/payload.json create mode 100644 VENDORS/Milesight/EM320-TILT/HTTP/uplink/result.json create mode 100644 VENDORS/Milesight/EM400-TLD/HTTP/uplink/converter.json create mode 100644 VENDORS/Milesight/EM400-TLD/HTTP/uplink/metadata.json create mode 100644 VENDORS/Milesight/EM400-TLD/HTTP/uplink/payload.json create mode 100644 VENDORS/Milesight/EM400-TLD/HTTP/uplink/result.json create mode 100644 VENDORS/Milesight/EM400-UDL/HTTP/uplink/converter.json create mode 100644 VENDORS/Milesight/EM400-UDL/HTTP/uplink/metadata.json create mode 100644 VENDORS/Milesight/EM400-UDL/HTTP/uplink/payload.json create mode 100644 VENDORS/Milesight/EM400-UDL/HTTP/uplink/result.json create mode 100644 VENDORS/Milesight/EM500-CO2/HTTP/uplink/converter.json create mode 100644 VENDORS/Milesight/EM500-CO2/HTTP/uplink/metadata.json create mode 100644 VENDORS/Milesight/EM500-CO2/HTTP/uplink/payload.json create mode 100644 VENDORS/Milesight/EM500-CO2/HTTP/uplink/result.json create mode 100644 VENDORS/Milesight/GS101/HTTP/uplink/converter.json create mode 100644 VENDORS/Milesight/GS101/HTTP/uplink/metadata.json create mode 100644 VENDORS/Milesight/GS101/HTTP/uplink/payload.json create mode 100644 VENDORS/Milesight/GS101/HTTP/uplink/result.json create mode 100644 VENDORS/Milesight/GS301/HTTP/uplink/converter.json create mode 100644 VENDORS/Milesight/GS301/HTTP/uplink/metadata.json create mode 100644 VENDORS/Milesight/GS301/HTTP/uplink/payload.json create mode 100644 VENDORS/Milesight/GS301/HTTP/uplink/result.json create mode 100644 VENDORS/Milesight/TS101/HTTP/uplink/converter.json create mode 100644 VENDORS/Milesight/TS101/HTTP/uplink/metadata.json create mode 100644 VENDORS/Milesight/TS101/HTTP/uplink/payload.json create mode 100644 VENDORS/Milesight/TS101/HTTP/uplink/result.json create mode 100644 VENDORS/Milesight/TS201/HTTP/uplink/converter.json create mode 100644 VENDORS/Milesight/TS201/HTTP/uplink/metadata.json create mode 100644 VENDORS/Milesight/TS201/HTTP/uplink/payload.json create mode 100644 VENDORS/Milesight/TS201/HTTP/uplink/result.json create mode 100644 VENDORS/Milesight/WS101/HTTP/uplink/converter.json create mode 100644 VENDORS/Milesight/WS101/HTTP/uplink/metadata.json create mode 100644 VENDORS/Milesight/WS101/HTTP/uplink/payload.json create mode 100644 VENDORS/Milesight/WS101/HTTP/uplink/result.json create mode 100644 VENDORS/Milesight/WS201/HTTP/uplink/converter.json create mode 100644 VENDORS/Milesight/WS201/HTTP/uplink/metadata.json create mode 100644 VENDORS/Milesight/WS201/HTTP/uplink/payload.json create mode 100644 VENDORS/Milesight/WS201/HTTP/uplink/result.json create mode 100644 VENDORS/Milesight/WS202/HTTP/uplink/converter.json create mode 100644 VENDORS/Milesight/WS202/HTTP/uplink/metadata.json create mode 100644 VENDORS/Milesight/WS202/HTTP/uplink/payload.json create mode 100644 VENDORS/Milesight/WS202/HTTP/uplink/result.json create mode 100644 VENDORS/Milesight/WS301/HTTP/uplink/converter.json create mode 100644 VENDORS/Milesight/WS301/HTTP/uplink/metadata.json create mode 100644 VENDORS/Milesight/WS301/HTTP/uplink/payload.json create mode 100644 VENDORS/Milesight/WS301/HTTP/uplink/result.json create mode 100644 VENDORS/Milesight/WS302/HTTP/uplink/converter.json create mode 100644 VENDORS/Milesight/WS302/HTTP/uplink/metadata.json create mode 100644 VENDORS/Milesight/WS302/HTTP/uplink/payload.json create mode 100644 VENDORS/Milesight/WS302/HTTP/uplink/result.json create mode 100644 VENDORS/Milesight/WS303/HTTP/uplink/converter.json create mode 100644 VENDORS/Milesight/WS303/HTTP/uplink/metadata.json create mode 100644 VENDORS/Milesight/WS303/HTTP/uplink/payload.json create mode 100644 VENDORS/Milesight/WS303/HTTP/uplink/result.json diff --git a/VENDORS/Milesight/AM102/HTTP/uplink/converter.json b/VENDORS/Milesight/AM102/HTTP/uplink/converter.json new file mode 100644 index 00000000..9f971faf --- /dev/null +++ b/VENDORS/Milesight/AM102/HTTP/uplink/converter.json @@ -0,0 +1,29 @@ +{ + "name": "HTTP Uplink integration for AM102", + "type": "UPLINK", + "debugMode": false, + "debugSettings": { + "failuresEnabled": true, + "allEnabled": false, + "allEnabledUntil": 1735560006385 + }, + "configuration": { + "scriptLang": "TBEL", + "decoder": null, + "tbelDecoder": "var data = decodeToJson(payload);\nvar deviceName = \"AM102 \" + data.devEUI;\nvar deviceType = \"AM102\";\nvar groupName = null; // If groupName is not null - created device will be added to the entity group with such name.\nvar customerName = null; // If customerName is not null - created devices will be assigned to customer with such name. \n\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// If you want to parse incoming data somehow, you can add your code to this function.\n// input: bytes\n// expected output:\n// {\n// \"attributes\": {\"attributeKey\": \"attributeValue\"},\n// \"telemetry\": [{\"ts\": 1...1, \"values\": {\"telemetryKey\":\"telemetryValue\"}, {\"ts\": 1...2, \"values\": {\"telemetryKey\":\"telemetryValue\"}}]\n// }\n\nfunction decodePayload(input) {\n var output = {\n attributes: {},\n telemetry: []\n };\n \n // --- Decoding code --- //\n var decoded = {};\n var fPort = data.fPort;\n var historyDataList = [];\n if(fPort == 85) {\n for (var i = 0; i < input.length - 2;) {\n var channel_id = input[i++] & 0xff;\n var channel_type = input[i++] & 0xff;\n // BATTERY\n if (channel_id === 0x01 && channel_type === 0x75) {\n decoded.battery = input[i];\n i += 1;\n }\n // TEMPERATURE\n if (channel_id === 0x03 && channel_type === 0x67) {\n // ℃\n decoded.temperature = parseBytesToInt(input, i,\n 2, false) / 10;\n i += 2;\n // ℉\n // decoded.temperature = parseBytesToInt(input, i, 2, false) / 10 * 1.8 + 32;\n // i +=2;\n }\n // HUMIDITY\n if (channel_id === 0x04 && channel_type === 0x68) {\n decoded.humidity = parseBytesToInt(input, i, 1, false) / 2;\n i += 1;\n }\n // HISTORY DATA\n if (channel_id === 0x20 && channel_type === 0xCE) {\n var historyData = {\n ts: parseBytesToInt(input, i, 4, false) * 1000,\n values: {\n temperature: parseBytesToInt(input, i + 4, 2, false) / 10,\n humidity: parseBytesToInt(input, i + 6, 1, false) / 2,\n }\n };\n \n historyDataList.add(historyData);\n \n i += 7;\n }\n }\n }\n\n output.telemetry = [{\n ts: timestamp,\n values: decoded\n }];\n \n output.telemetry.addAll(historyDataList);\n \n // --- Decoding code --- //\n return output;\n}\n\n// --- attributes and telemetry objects ---\nvar telemetry = [];\nvar attributes = {};\n// --- attributes and telemetry objects ---\n\n// --- Timestamp parsing\nvar dateString = data.time;\ntimestamp = parseDateToTimestamp(dateString);\n// --- Timestamp parsing\n\n// Passing incoming bytes to decodePayload function, to get custom decoding\nvar customDecoding = decodePayload(base64ToBytes(data.data));\n\n// Collecting data to result\nif (customDecoding.?telemetry.size() > 0) {\n foreach(telemetryObj: customDecoding.telemetry) {\n if (telemetryObj.ts != null && telemetryObj.values != null) {\n telemetry.add(telemetryObj);\n }\n }\n}\n\nif (customDecoding.?attributes.size() > 0) {\n attributes.putAll(customDecoding.attributes);\n}\n\n// You can add some keys manually to attributes or telemetry\nattributes.eui = data.?devEui;\nattributes.fPort = data.fPort;\nattributes.applicationId = data.?applicationId;\nattributes.applicationName = data.?applicationName;\nattributes.frequency = data.txInfo.?frequency;\nattributes.bandwidth = data.txInfo.?dataRate.?bandwidth;\nattributes.spreadingFactor = data.txInfo.?dataRate.?spreadFactor;\nattributes.codeRate = data.txInfo.?codeRate;\n\nif(Boolean.parseBoolean(metadata[\"includeGatewayInfo\"])) {\n var gatewayInfo = getGatewayInfo();\n var addDataToTelemetry = {};\n addDataToTelemetry.snr = gatewayInfo.?loRaSNR;\n addDataToTelemetry.rssi = gatewayInfo.rssi;\n addDataToTelemetry.fCnt = data.fCnt;\n \n telemetry = processTelemetryData(telemetry, addDataToTelemetry);\n}\n\nvar result = {\n deviceName: deviceName,\n deviceType: deviceType,\n // assetName: assetName,\n // assetType: assetType,\n attributes: attributes,\n telemetry: telemetry\n};\n\naddAdditionalInfoForDeviceMsg(result, customerName, groupName);\n\nreturn result;\n\nfunction addAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName) {\n if (customerName != null) {\n deviceInfo.customerName = customerName;\n }\n if (groupName != null) {\n deviceInfo.groupName = groupName;\n }\n}\n\nfunction parseDateToTimestamp(dateString) {\n dateString = dateString.replaceFirst(\"(\\\\d{4}-\\\\d{2})(\\\\d{2})\", \"$1-$2\");\n dateString = dateString.replaceFirst(\"\\\\.(\\\\d{3})\\\\d+Z\", \".$1Z\");\n dateString = dateString.replace(\"Z\", \"+0000\");\n var date = new Date(dateString);\n var timestamp = date.getTime();\n \n // If we cannot parse timestamp - we will use the current timestamp\n if (timestamp == -1) {\n timestamp = Date.now();\n }\n \n return timestamp;\n}\n\nfunction getGatewayInfo() {\n var gatewayList = data.rxInfo;\n var maxRssi = Integer.MIN_VALUE;\n var gatewayInfo = {};\n \n foreach (gateway : gatewayList) {\n if(gateway.rssi > maxRssi) {\n maxRssi = gateway.rssi;\n gatewayInfo = gateway;\n }\n }\n \n return gatewayInfo;\n}\n\nfunction processTelemetryData(telemetry, addDataToTelemetry) {\n if (telemetry.size >= 1) {\n telemetry = addDataToTelemetries(telemetry, addDataToTelemetry);\n }\n else {\n telemetry.add(addDataToTelemetry);\n }\n \n return telemetry;\n}\n\nfunction addDataToTelemetries(telemetries, addDataToTelemetry) {\n foreach(telemetry : telemetries) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[\"values\"].keys.contains(element.key)) {\n telemetry[\"values\"][element.key] = element.value;\n }\n } \n }\n \n return telemetries;\n}", + "encoder": null, + "tbelEncoder": null, + "updateOnlyKeys": [ + "fPort", + "applicationName", + "frequency", + "bandwidth", + "spreadingFactor", + "codeRate" + ] + }, + "additionalInfo": { + "description": "" + }, + "edgeTemplate": false +} \ No newline at end of file diff --git a/VENDORS/Milesight/AM102/HTTP/uplink/metadata.json b/VENDORS/Milesight/AM102/HTTP/uplink/metadata.json new file mode 100644 index 00000000..87ee6615 --- /dev/null +++ b/VENDORS/Milesight/AM102/HTTP/uplink/metadata.json @@ -0,0 +1,4 @@ +{ + "integrationName": "HTTP integration", + "includeGatewayInfo": "false" +} \ No newline at end of file diff --git a/VENDORS/Milesight/AM102/HTTP/uplink/payload.json b/VENDORS/Milesight/AM102/HTTP/uplink/payload.json new file mode 100644 index 00000000..dddfb341 --- /dev/null +++ b/VENDORS/Milesight/AM102/HTTP/uplink/payload.json @@ -0,0 +1,31 @@ +{ + "applicationID": 1, + "applicationName": "cloud", + "deviceName": "24e1641092176759", + "devEUI": "24e1641092176759", + "time": "2020-0327T12:39:05.547336Z", + "rxInfo": [ + { + "mac": "24e124fffef021be", + "rssi": -57, + "loRaSNR": 10, + "name": "local_gateway", + "latitude": 0, + "longitude": 0, + "altitude": 0 + } + ], + "txInfo": { + "frequency": 868300000, + "dataRate": { + "modulation": "LORA", + "bandwidth": 125, + "spreadFactor": 7 + }, + "adr": false, + "codeRate": "4/5" + }, + "fCnt": 0, + "fPort": 85, + "data": "AXVkA2cYAQRobQ==" +} \ No newline at end of file diff --git a/VENDORS/Milesight/AM102/HTTP/uplink/result.json b/VENDORS/Milesight/AM102/HTTP/uplink/result.json new file mode 100644 index 00000000..f8c9c0d2 --- /dev/null +++ b/VENDORS/Milesight/AM102/HTTP/uplink/result.json @@ -0,0 +1,20 @@ +{ + "deviceName": "AM102 24e1641092176759", + "deviceType": "AM102", + "attributes": { + "fPort": 85, + "applicationName": "cloud", + "frequency": 868300000, + "bandwidth": 125, + "spreadingFactor": 7, + "codeRate": "4/5" + }, + "telemetry": [{ + "ts": 1585312745547, + "values": { + "battery": 100, + "temperature": 28.0, + "humidity": 54.5 + } + }] +} \ No newline at end of file diff --git a/VENDORS/Milesight/AM102L/HTTP/uplink/converter.json b/VENDORS/Milesight/AM102L/HTTP/uplink/converter.json new file mode 100644 index 00000000..c1c0f59c --- /dev/null +++ b/VENDORS/Milesight/AM102L/HTTP/uplink/converter.json @@ -0,0 +1,29 @@ +{ + "name": "HTTP Uplink integration for AM102L", + "type": "UPLINK", + "debugMode": false, + "debugSettings": { + "failuresEnabled": true, + "allEnabled": false, + "allEnabledUntil": 1735560006385 + }, + "configuration": { + "scriptLang": "TBEL", + "decoder": null, + "tbelDecoder": "var data = decodeToJson(payload);\nvar deviceName = \"AM102L \" + data.devEUI;\nvar deviceType = \"AM102L\";\nvar groupName = null; // If groupName is not null - created device will be added to the entity group with such name.\nvar customerName = null; // If customerName is not null - created devices will be assigned to customer with such name. \n\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// If you want to parse incoming data somehow, you can add your code to this function.\n// input: bytes\n// expected output:\n// {\n// \"attributes\": {\"attributeKey\": \"attributeValue\"},\n// \"telemetry\": [{\"ts\": 1...1, \"values\": {\"telemetryKey\":\"telemetryValue\"}, {\"ts\": 1...2, \"values\": {\"telemetryKey\":\"telemetryValue\"}}]\n// }\n\nfunction decodePayload(input) {\n var output = {\n attributes: {},\n telemetry: []\n };\n \n // --- Decoding code --- //\n var decoded = {};\n var fPort = data.fPort;\n var historyDataList = [];\n if(fPort == 85) {\n for (var i = 0; i < input.length - 2;) {\n var channel_id = input[i++] & 0xff;\n var channel_type = input[i++] & 0xff;\n // BATTERY\n if (channel_id === 0x01 && channel_type === 0x75) {\n decoded.battery = input[i];\n i += 1;\n }\n // TEMPERATURE\n if (channel_id === 0x03 && channel_type === 0x67) {\n // ℃\n decoded.temperature = parseBytesToInt(input, i,\n 2, false) / 10;\n i += 2;\n // ℉\n // decoded.temperature = parseBytesToInt(input, i, 2, false) / 10 * 1.8 + 32;\n // i +=2;\n }\n // HUMIDITY\n if (channel_id === 0x04 && channel_type === 0x68) {\n decoded.humidity = parseBytesToInt(input, i, 1, false) / 2;\n i += 1;\n }\n // HISTORY DATA\n if (channel_id === 0x20 && channel_type === 0xCE) {\n var historyData = {\n ts: parseBytesToInt(input, i, 4, false) * 1000,\n values: {\n temperature: parseBytesToInt(input, i + 4, 2, false) / 10,\n humidity: parseBytesToInt(input, i + 6, 1, false) / 2,\n }\n };\n \n historyDataList.add(historyData);\n \n i += 7;\n }\n }\n }\n\n output.telemetry = [{\n ts: timestamp,\n values: decoded\n }];\n \n output.telemetry.addAll(historyDataList);\n \n // --- Decoding code --- //\n return output;\n}\n\n// --- attributes and telemetry objects ---\nvar telemetry = [];\nvar attributes = {};\n// --- attributes and telemetry objects ---\n\n// --- Timestamp parsing\nvar dateString = data.time;\ntimestamp = parseDateToTimestamp(dateString);\n// --- Timestamp parsing\n\n// Passing incoming bytes to decodePayload function, to get custom decoding\nvar customDecoding = decodePayload(base64ToBytes(data.data));\n\n// Collecting data to result\nif (customDecoding.?telemetry.size() > 0) {\n foreach(telemetryObj: customDecoding.telemetry) {\n if (telemetryObj.ts != null && telemetryObj.values != null) {\n telemetry.add(telemetryObj);\n }\n }\n}\n\nif (customDecoding.?attributes.size() > 0) {\n attributes.putAll(customDecoding.attributes);\n}\n\n// You can add some keys manually to attributes or telemetry\nattributes.eui = data.?devEui;\nattributes.fPort = data.fPort;\nattributes.applicationId = data.?applicationId;\nattributes.applicationName = data.?applicationName;\nattributes.frequency = data.txInfo.?frequency;\nattributes.bandwidth = data.txInfo.?dataRate.?bandwidth;\nattributes.spreadingFactor = data.txInfo.?dataRate.?spreadFactor;\nattributes.codeRate = data.txInfo.?codeRate;\n\nif(Boolean.parseBoolean(metadata[\"includeGatewayInfo\"])) {\n var gatewayInfo = getGatewayInfo();\n var addDataToTelemetry = {};\n addDataToTelemetry.snr = gatewayInfo.?loRaSNR;\n addDataToTelemetry.rssi = gatewayInfo.rssi;\n addDataToTelemetry.fCnt = data.fCnt;\n \n telemetry = processTelemetryData(telemetry, addDataToTelemetry);\n}\n\nvar result = {\n deviceName: deviceName,\n deviceType: deviceType,\n // assetName: assetName,\n // assetType: assetType,\n attributes: attributes,\n telemetry: telemetry\n};\n\naddAdditionalInfoForDeviceMsg(result, customerName, groupName);\n\nreturn result;\n\nfunction addAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName) {\n if (customerName != null) {\n deviceInfo.customerName = customerName;\n }\n if (groupName != null) {\n deviceInfo.groupName = groupName;\n }\n}\n\nfunction parseDateToTimestamp(dateString) {\n dateString = dateString.replaceFirst(\"(\\\\d{4}-\\\\d{2})(\\\\d{2})\", \"$1-$2\");\n dateString = dateString.replaceFirst(\"\\\\.(\\\\d{3})\\\\d+Z\", \".$1Z\");\n dateString = dateString.replace(\"Z\", \"+0000\");\n var date = new Date(dateString);\n var timestamp = date.getTime();\n \n // If we cannot parse timestamp - we will use the current timestamp\n if (timestamp == -1) {\n timestamp = Date.now();\n }\n \n return timestamp;\n}\n\nfunction getGatewayInfo() {\n var gatewayList = data.rxInfo;\n var maxRssi = Integer.MIN_VALUE;\n var gatewayInfo = {};\n \n foreach (gateway : gatewayList) {\n if(gateway.rssi > maxRssi) {\n maxRssi = gateway.rssi;\n gatewayInfo = gateway;\n }\n }\n \n return gatewayInfo;\n}\n\nfunction processTelemetryData(telemetry, addDataToTelemetry) {\n if (telemetry.size >= 1) {\n telemetry = addDataToTelemetries(telemetry, addDataToTelemetry);\n }\n else {\n telemetry.add(addDataToTelemetry);\n }\n \n return telemetry;\n}\n\nfunction addDataToTelemetries(telemetries, addDataToTelemetry) {\n foreach(telemetry : telemetries) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[\"values\"].keys.contains(element.key)) {\n telemetry[\"values\"][element.key] = element.value;\n }\n } \n }\n \n return telemetries;\n}", + "encoder": null, + "tbelEncoder": null, + "updateOnlyKeys": [ + "fPort", + "applicationName", + "frequency", + "bandwidth", + "spreadingFactor", + "codeRate" + ] + }, + "additionalInfo": { + "description": "" + }, + "edgeTemplate": false +} \ No newline at end of file diff --git a/VENDORS/Milesight/AM102L/HTTP/uplink/metadata.json b/VENDORS/Milesight/AM102L/HTTP/uplink/metadata.json new file mode 100644 index 00000000..87ee6615 --- /dev/null +++ b/VENDORS/Milesight/AM102L/HTTP/uplink/metadata.json @@ -0,0 +1,4 @@ +{ + "integrationName": "HTTP integration", + "includeGatewayInfo": "false" +} \ No newline at end of file diff --git a/VENDORS/Milesight/AM102L/HTTP/uplink/payload.json b/VENDORS/Milesight/AM102L/HTTP/uplink/payload.json new file mode 100644 index 00000000..dddfb341 --- /dev/null +++ b/VENDORS/Milesight/AM102L/HTTP/uplink/payload.json @@ -0,0 +1,31 @@ +{ + "applicationID": 1, + "applicationName": "cloud", + "deviceName": "24e1641092176759", + "devEUI": "24e1641092176759", + "time": "2020-0327T12:39:05.547336Z", + "rxInfo": [ + { + "mac": "24e124fffef021be", + "rssi": -57, + "loRaSNR": 10, + "name": "local_gateway", + "latitude": 0, + "longitude": 0, + "altitude": 0 + } + ], + "txInfo": { + "frequency": 868300000, + "dataRate": { + "modulation": "LORA", + "bandwidth": 125, + "spreadFactor": 7 + }, + "adr": false, + "codeRate": "4/5" + }, + "fCnt": 0, + "fPort": 85, + "data": "AXVkA2cYAQRobQ==" +} \ No newline at end of file diff --git a/VENDORS/Milesight/AM102L/HTTP/uplink/result.json b/VENDORS/Milesight/AM102L/HTTP/uplink/result.json new file mode 100644 index 00000000..3b140424 --- /dev/null +++ b/VENDORS/Milesight/AM102L/HTTP/uplink/result.json @@ -0,0 +1,20 @@ +{ + "deviceName": "AM103 24e1641092176759", + "deviceType": "AM103", + "attributes": { + "fPort": 85, + "applicationName": "cloud", + "frequency": 868300000, + "bandwidth": 125, + "spreadingFactor": 7, + "codeRate": "4/5" + }, + "telemetry": [{ + "ts": 1585312745547, + "values": { + "battery": 100, + "temperature": 28.0, + "humidity": 54.5 + } + }] +} \ No newline at end of file diff --git a/VENDORS/Milesight/AM103/HTTP/uplink/converter.json b/VENDORS/Milesight/AM103/HTTP/uplink/converter.json new file mode 100644 index 00000000..e7ecb462 --- /dev/null +++ b/VENDORS/Milesight/AM103/HTTP/uplink/converter.json @@ -0,0 +1,29 @@ +{ + "name": "HTTP Uplink integration for AM103", + "type": "UPLINK", + "debugMode": false, + "debugSettings": { + "failuresEnabled": true, + "allEnabled": false, + "allEnabledUntil": 1735560006385 + }, + "configuration": { + "scriptLang": "TBEL", + "decoder": null, + "tbelDecoder": "var data = decodeToJson(payload);\nvar deviceName = \"AM103 \" + data.devEUI;\nvar deviceType = \"AM103\";\nvar groupName = null; // If groupName is not null - created device will be added to the entity group with such name.\nvar customerName = null; // If customerName is not null - created devices will be assigned to customer with such name. \n\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// If you want to parse incoming data somehow, you can add your code to this function.\n// input: bytes\n// expected output:\n// {\n// \"attributes\": {\"attributeKey\": \"attributeValue\"},\n// \"telemetry\": [{\"ts\": 1...1, \"values\": {\"telemetryKey\":\"telemetryValue\"}, {\"ts\": 1...2, \"values\": {\"telemetryKey\":\"telemetryValue\"}}]\n// }\n\nfunction decodePayload(input) {\n var output = {\n attributes: {},\n telemetry: []\n };\n \n // --- Decoding code --- //\n var decoded = {};\n var fPort = data.fPort;\n var historyDataList = [];\n if(fPort == 85) {\n for (var i = 0; i < input.length - 2;) {\n var channel_id = input[i++] & 0xff;\n var channel_type = input[i++] & 0xff;\n // BATTERY\n if (channel_id === 0x01 && channel_type === 0x75) {\n decoded.battery = input[i];\n i += 1;\n }\n // TEMPERATURE\n if (channel_id === 0x03 && channel_type === 0x67) {\n // ℃\n decoded.temperature = parseBytesToInt(input, i,\n 2, false) / 10;\n i += 2;\n // ℉\n // decoded.temperature = parseBytesToInt(input, i, 2, false) / 10 * 1.8 + 32;\n // i +=2;\n }\n // HUMIDITY\n if (channel_id === 0x04 && channel_type === 0x68) {\n decoded.humidity = parseBytesToInt(input, i, 1, false) / 2;\n i += 1;\n }\n // CO2\n if (channel_id === 0x07 && channel_type === 0x7D) {\n decoded.co2 = parseBytesToInt(input, i, 2,\n false);\n i += 2;\n }\n \n // HISTORY DATA \n if (channel_id === 0x20 && channel_type === 0xCE) {\n var historyData = {\n ts: parseBytesToInt(input, i, 4, false) * 1000,\n values: {\n temperature: parseBytesToInt(input, i + 4, 2, false) / 10,\n humidity: parseBytesToInt(input, i + 6, 1, false) / 2,\n co2: parseBytesToInt(input, i + 7, 2, false),\n }\n };\n \n historyDataList.add(historyData);\n i += 9;\n }\n }\n }\n\n output.telemetry = [{\n ts: timestamp,\n values: decoded\n }];\n \n output.telemetry.addAll(historyDataList);\n \n // --- Decoding code --- //\n return output;\n}\n\n// --- attributes and telemetry objects ---\nvar telemetry = [];\nvar attributes = {};\n// --- attributes and telemetry objects ---\n\n// --- Timestamp parsing\nvar dateString = data.time;\ntimestamp = parseDateToTimestamp(dateString);\n// --- Timestamp parsing\n\n// Passing incoming bytes to decodePayload function, to get custom decoding\nvar customDecoding = decodePayload(base64ToBytes(data.data));\n\n// Collecting data to result\nif (customDecoding.?telemetry.size() > 0) {\n foreach(telemetryObj: customDecoding.telemetry) {\n if (telemetryObj.ts != null && telemetryObj.values != null) {\n telemetry.add(telemetryObj);\n }\n }\n}\n\nif (customDecoding.?attributes.size() > 0) {\n attributes.putAll(customDecoding.attributes);\n}\n\n// You can add some keys manually to attributes or telemetry\nattributes.eui = data.?devEui;\nattributes.fPort = data.fPort;\nattributes.applicationId = data.?applicationId;\nattributes.applicationName = data.?applicationName;\nattributes.frequency = data.txInfo.?frequency;\nattributes.bandwidth = data.txInfo.?dataRate.?bandwidth;\nattributes.spreadingFactor = data.txInfo.?dataRate.?spreadFactor;\nattributes.codeRate = data.txInfo.?codeRate;\n\nif(Boolean.parseBoolean(metadata[\"includeGatewayInfo\"])) {\n var gatewayInfo = getGatewayInfo();\n var addDataToTelemetry = {};\n addDataToTelemetry.snr = gatewayInfo.?loRaSNR;\n addDataToTelemetry.rssi = gatewayInfo.rssi;\n addDataToTelemetry.fCnt = data.fCnt;\n \n telemetry = processTelemetryData(telemetry, addDataToTelemetry);\n}\n\nvar result = {\n deviceName: deviceName,\n deviceType: deviceType,\n // assetName: assetName,\n // assetType: assetType,\n attributes: attributes,\n telemetry: telemetry\n};\n\naddAdditionalInfoForDeviceMsg(result, customerName, groupName);\n\nreturn result;\n\nfunction addAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName) {\n if (customerName != null) {\n deviceInfo.customerName = customerName;\n }\n if (groupName != null) {\n deviceInfo.groupName = groupName;\n }\n}\n\nfunction parseDateToTimestamp(dateString) {\n dateString = dateString.replaceFirst(\"(\\\\d{4}-\\\\d{2})(\\\\d{2})\", \"$1-$2\");\n dateString = dateString.replaceFirst(\"\\\\.(\\\\d{3})\\\\d+Z\", \".$1Z\");\n dateString = dateString.replace(\"Z\", \"+0000\");\n var date = new Date(dateString);\n var timestamp = date.getTime();\n \n // If we cannot parse timestamp - we will use the current timestamp\n if (timestamp == -1) {\n timestamp = Date.now();\n }\n \n return timestamp;\n}\n\nfunction getGatewayInfo() {\n var gatewayList = data.rxInfo;\n var maxRssi = Integer.MIN_VALUE;\n var gatewayInfo = {};\n \n foreach (gateway : gatewayList) {\n if(gateway.rssi > maxRssi) {\n maxRssi = gateway.rssi;\n gatewayInfo = gateway;\n }\n }\n \n return gatewayInfo;\n}\n\nfunction processTelemetryData(telemetry, addDataToTelemetry) {\n if (telemetry.size >= 1) {\n telemetry = addDataToTelemetries(telemetry, addDataToTelemetry);\n }\n else {\n telemetry.add(addDataToTelemetry);\n }\n \n return telemetry;\n}\n\nfunction addDataToTelemetries(telemetries, addDataToTelemetry) {\n foreach(telemetry : telemetries) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[\"values\"].keys.contains(element.key)) {\n telemetry[\"values\"][element.key] = element.value;\n }\n } \n }\n \n return telemetries;\n}", + "encoder": null, + "tbelEncoder": null, + "updateOnlyKeys": [ + "fPort", + "applicationName", + "frequency", + "bandwidth", + "spreadingFactor", + "codeRate" + ] + }, + "additionalInfo": { + "description": "" + }, + "edgeTemplate": false +} \ No newline at end of file diff --git a/VENDORS/Milesight/AM103/HTTP/uplink/metadata.json b/VENDORS/Milesight/AM103/HTTP/uplink/metadata.json new file mode 100644 index 00000000..87ee6615 --- /dev/null +++ b/VENDORS/Milesight/AM103/HTTP/uplink/metadata.json @@ -0,0 +1,4 @@ +{ + "integrationName": "HTTP integration", + "includeGatewayInfo": "false" +} \ No newline at end of file diff --git a/VENDORS/Milesight/AM103/HTTP/uplink/payload.json b/VENDORS/Milesight/AM103/HTTP/uplink/payload.json new file mode 100644 index 00000000..ecdffd17 --- /dev/null +++ b/VENDORS/Milesight/AM103/HTTP/uplink/payload.json @@ -0,0 +1,31 @@ +{ + "applicationID": 1, + "applicationName": "cloud", + "deviceName": "24e1641092176759", + "devEUI": "24e1641092176759", + "time": "2020-0327T12:39:05.547336Z", + "rxInfo": [ + { + "mac": "24e124fffef021be", + "rssi": -57, + "loRaSNR": 10, + "name": "local_gateway", + "latitude": 0, + "longitude": 0, + "altitude": 0 + } + ], + "txInfo": { + "frequency": 868300000, + "dataRate": { + "modulation": "LORA", + "bandwidth": 125, + "spreadFactor": 7 + }, + "adr": false, + "codeRate": "4/5" + }, + "fCnt": 0, + "fPort": 85, + "data": "AXVkA2cYAQRobQd9xQEgzngaQWXfAG6QAQ==" +} \ No newline at end of file diff --git a/VENDORS/Milesight/AM103/HTTP/uplink/result.json b/VENDORS/Milesight/AM103/HTTP/uplink/result.json new file mode 100644 index 00000000..eda2ebec --- /dev/null +++ b/VENDORS/Milesight/AM103/HTTP/uplink/result.json @@ -0,0 +1,28 @@ +{ + "deviceName": "AM103 24e1641092176759", + "deviceType": "AM103", + "attributes": { + "fPort": 85, + "applicationName": "cloud", + "frequency": 868300000, + "bandwidth": 125, + "spreadingFactor": 7, + "codeRate": "4/5" + }, + "telemetry": [{ + "ts": 1585312745547, + "values": { + "battery": 100, + "temperature": 28.0, + "humidity": 54.5, + "co2": 453 + } + }, { + "ts": 1698765432000, + "values": { + "temperature": 22.3, + "humidity": 55.0, + "co2": 400 + } + }] +} \ No newline at end of file diff --git a/VENDORS/Milesight/AM103L/HTTP/uplink/converter.json b/VENDORS/Milesight/AM103L/HTTP/uplink/converter.json new file mode 100644 index 00000000..a864c5f8 --- /dev/null +++ b/VENDORS/Milesight/AM103L/HTTP/uplink/converter.json @@ -0,0 +1,29 @@ +{ + "name": "HTTP Uplink integration for AM103L", + "type": "UPLINK", + "debugMode": false, + "debugSettings": { + "failuresEnabled": true, + "allEnabled": false, + "allEnabledUntil": 1735560006385 + }, + "configuration": { + "scriptLang": "TBEL", + "decoder": null, + "tbelDecoder": "var data = decodeToJson(payload);\nvar deviceName = \"AM103L \" + data.devEUI;\nvar deviceType = \"AM103L\";\nvar groupName = null; // If groupName is not null - created device will be added to the entity group with such name.\nvar customerName = null; // If customerName is not null - created devices will be assigned to customer with such name. \n\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// If you want to parse incoming data somehow, you can add your code to this function.\n// input: bytes\n// expected output:\n// {\n// \"attributes\": {\"attributeKey\": \"attributeValue\"},\n// \"telemetry\": [{\"ts\": 1...1, \"values\": {\"telemetryKey\":\"telemetryValue\"}, {\"ts\": 1...2, \"values\": {\"telemetryKey\":\"telemetryValue\"}}]\n// }\n\nfunction decodePayload(input) {\n var output = {\n attributes: {},\n telemetry: []\n };\n \n // --- Decoding code --- //\n var decoded = {};\n var fPort = data.fPort;\n var historyDataList = [];\n if(fPort == 85) {\n for (var i = 0; i < input.length - 2;) {\n var channel_id = input[i++] & 0xff;\n var channel_type = input[i++] & 0xff;\n // BATTERY\n if (channel_id === 0x01 && channel_type === 0x75) {\n decoded.battery = input[i];\n i += 1;\n }\n // TEMPERATURE\n if (channel_id === 0x03 && channel_type === 0x67) {\n // ℃\n decoded.temperature = parseBytesToInt(input, i,\n 2, false) / 10;\n i += 2;\n // ℉\n // decoded.temperature = parseBytesToInt(input, i, 2, false) / 10 * 1.8 + 32;\n // i +=2;\n }\n // HUMIDITY\n if (channel_id === 0x04 && channel_type === 0x68) {\n decoded.humidity = parseBytesToInt(input, i, 1, false) / 2;\n i += 1;\n }\n // CO2\n if (channel_id === 0x07 && channel_type === 0x7D) {\n decoded.co2 = parseBytesToInt(input, i, 2,\n false);\n i += 2;\n }\n \n // HISTORY DATA \n if (channel_id === 0x20 && channel_type === 0xCE) {\n var historyData = {\n ts: parseBytesToInt(input, i, 4, false) * 1000,\n values: {\n temperature: parseBytesToInt(input, i + 4, 2, false) / 10,\n humidity: parseBytesToInt(input, i + 6, 1, false) / 2,\n co2: parseBytesToInt(input, i + 7, 2, false),\n }\n };\n \n historyDataList.add(historyData);\n i += 9;\n }\n }\n }\n\n output.telemetry = [{\n ts: timestamp,\n values: decoded\n }];\n \n output.telemetry.addAll(historyDataList);\n \n // --- Decoding code --- //\n return output;\n}\n\n// --- attributes and telemetry objects ---\nvar telemetry = [];\nvar attributes = {};\n// --- attributes and telemetry objects ---\n\n// --- Timestamp parsing\nvar dateString = data.time;\ntimestamp = parseDateToTimestamp(dateString);\n// --- Timestamp parsing\n\n// Passing incoming bytes to decodePayload function, to get custom decoding\nvar customDecoding = decodePayload(base64ToBytes(data.data));\n\n// Collecting data to result\nif (customDecoding.?telemetry.size() > 0) {\n foreach(telemetryObj: customDecoding.telemetry) {\n if (telemetryObj.ts != null && telemetryObj.values != null) {\n telemetry.add(telemetryObj);\n }\n }\n}\n\nif (customDecoding.?attributes.size() > 0) {\n attributes.putAll(customDecoding.attributes);\n}\n\n// You can add some keys manually to attributes or telemetry\nattributes.eui = data.?devEui;\nattributes.fPort = data.fPort;\nattributes.applicationId = data.?applicationId;\nattributes.applicationName = data.?applicationName;\nattributes.frequency = data.txInfo.?frequency;\nattributes.bandwidth = data.txInfo.?dataRate.?bandwidth;\nattributes.spreadingFactor = data.txInfo.?dataRate.?spreadFactor;\nattributes.codeRate = data.txInfo.?codeRate;\n\nif(Boolean.parseBoolean(metadata[\"includeGatewayInfo\"])) {\n var gatewayInfo = getGatewayInfo();\n var addDataToTelemetry = {};\n addDataToTelemetry.snr = gatewayInfo.?loRaSNR;\n addDataToTelemetry.rssi = gatewayInfo.rssi;\n addDataToTelemetry.fCnt = data.fCnt;\n \n telemetry = processTelemetryData(telemetry, addDataToTelemetry);\n}\n\nvar result = {\n deviceName: deviceName,\n deviceType: deviceType,\n // assetName: assetName,\n // assetType: assetType,\n attributes: attributes,\n telemetry: telemetry\n};\n\naddAdditionalInfoForDeviceMsg(result, customerName, groupName);\n\nreturn result;\n\nfunction addAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName) {\n if (customerName != null) {\n deviceInfo.customerName = customerName;\n }\n if (groupName != null) {\n deviceInfo.groupName = groupName;\n }\n}\n\nfunction parseDateToTimestamp(dateString) {\n dateString = dateString.replaceFirst(\"(\\\\d{4}-\\\\d{2})(\\\\d{2})\", \"$1-$2\");\n dateString = dateString.replaceFirst(\"\\\\.(\\\\d{3})\\\\d+Z\", \".$1Z\");\n dateString = dateString.replace(\"Z\", \"+0000\");\n var date = new Date(dateString);\n var timestamp = date.getTime();\n \n // If we cannot parse timestamp - we will use the current timestamp\n if (timestamp == -1) {\n timestamp = Date.now();\n }\n \n return timestamp;\n}\n\nfunction getGatewayInfo() {\n var gatewayList = data.rxInfo;\n var maxRssi = Integer.MIN_VALUE;\n var gatewayInfo = {};\n \n foreach (gateway : gatewayList) {\n if(gateway.rssi > maxRssi) {\n maxRssi = gateway.rssi;\n gatewayInfo = gateway;\n }\n }\n \n return gatewayInfo;\n}\n\nfunction processTelemetryData(telemetry, addDataToTelemetry) {\n if (telemetry.size >= 1) {\n telemetry = addDataToTelemetries(telemetry, addDataToTelemetry);\n }\n else {\n telemetry.add(addDataToTelemetry);\n }\n \n return telemetry;\n}\n\nfunction addDataToTelemetries(telemetries, addDataToTelemetry) {\n foreach(telemetry : telemetries) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[\"values\"].keys.contains(element.key)) {\n telemetry[\"values\"][element.key] = element.value;\n }\n } \n }\n \n return telemetries;\n}", + "encoder": null, + "tbelEncoder": null, + "updateOnlyKeys": [ + "fPort", + "applicationName", + "frequency", + "bandwidth", + "spreadingFactor", + "codeRate" + ] + }, + "additionalInfo": { + "description": "" + }, + "edgeTemplate": false +} \ No newline at end of file diff --git a/VENDORS/Milesight/AM103L/HTTP/uplink/metadata.json b/VENDORS/Milesight/AM103L/HTTP/uplink/metadata.json new file mode 100644 index 00000000..87ee6615 --- /dev/null +++ b/VENDORS/Milesight/AM103L/HTTP/uplink/metadata.json @@ -0,0 +1,4 @@ +{ + "integrationName": "HTTP integration", + "includeGatewayInfo": "false" +} \ No newline at end of file diff --git a/VENDORS/Milesight/AM103L/HTTP/uplink/payload.json b/VENDORS/Milesight/AM103L/HTTP/uplink/payload.json new file mode 100644 index 00000000..ecdffd17 --- /dev/null +++ b/VENDORS/Milesight/AM103L/HTTP/uplink/payload.json @@ -0,0 +1,31 @@ +{ + "applicationID": 1, + "applicationName": "cloud", + "deviceName": "24e1641092176759", + "devEUI": "24e1641092176759", + "time": "2020-0327T12:39:05.547336Z", + "rxInfo": [ + { + "mac": "24e124fffef021be", + "rssi": -57, + "loRaSNR": 10, + "name": "local_gateway", + "latitude": 0, + "longitude": 0, + "altitude": 0 + } + ], + "txInfo": { + "frequency": 868300000, + "dataRate": { + "modulation": "LORA", + "bandwidth": 125, + "spreadFactor": 7 + }, + "adr": false, + "codeRate": "4/5" + }, + "fCnt": 0, + "fPort": 85, + "data": "AXVkA2cYAQRobQd9xQEgzngaQWXfAG6QAQ==" +} \ No newline at end of file diff --git a/VENDORS/Milesight/AM103L/HTTP/uplink/result.json b/VENDORS/Milesight/AM103L/HTTP/uplink/result.json new file mode 100644 index 00000000..5a0f60a9 --- /dev/null +++ b/VENDORS/Milesight/AM103L/HTTP/uplink/result.json @@ -0,0 +1,28 @@ +{ + "deviceName": "AM103L 24e1641092176759", + "deviceType": "AM103L", + "attributes": { + "fPort": 85, + "applicationName": "cloud", + "frequency": 868300000, + "bandwidth": 125, + "spreadingFactor": 7, + "codeRate": "4/5" + }, + "telemetry": [{ + "ts": 1585312745547, + "values": { + "battery": 100, + "temperature": 28.0, + "humidity": 54.5, + "co2": 453 + } + }, { + "ts": 1698765432000, + "values": { + "temperature": 22.3, + "humidity": 55.0, + "co2": 400 + } + }] +} \ No newline at end of file diff --git a/VENDORS/Milesight/AM104/HTTP/uplink/converter.json b/VENDORS/Milesight/AM104/HTTP/uplink/converter.json new file mode 100644 index 00000000..82c6db13 --- /dev/null +++ b/VENDORS/Milesight/AM104/HTTP/uplink/converter.json @@ -0,0 +1,29 @@ +{ + "name": "HTTP Uplink integration for AM104", + "type": "UPLINK", + "debugMode": false, + "debugSettings": { + "failuresEnabled": true, + "allEnabled": false, + "allEnabledUntil": 1735560006385 + }, + "configuration": { + "scriptLang": "TBEL", + "decoder": null, + "tbelDecoder": "var data = decodeToJson(payload);\nvar deviceName = \"AM104 \" + data.devEUI;\nvar deviceType = \"AM104\";\nvar groupName = null; // If groupName is not null - created device will be added to the entity group with such name.\nvar customerName = null; // If customerName is not null - created devices will be assigned to customer with such name. \n\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// If you want to parse incoming data somehow, you can add your code to this function.\n// input: bytes\n// expected output:\n// {\n// \"attributes\": {\"attributeKey\": \"attributeValue\"},\n// \"telemetry\": [{\"ts\": 1...1, \"values\": {\"telemetryKey\":\"telemetryValue\"}, {\"ts\": 1...2, \"values\": {\"telemetryKey\":\"telemetryValue\"}}]\n// }\n\nfunction decodePayload(input) {\n var output = {\n attributes: {},\n telemetry: []\n };\n \n // --- Decoding code --- //\n var decoded = {};\n var fPort = data.fPort;\n if(fPort == 85) {\n for (var i = 0; i < input.length - 2;) {\n var channel_id = input[i++] & 0xff;\n var channel_type = input[i++] & 0xff;\n // BATTERY\n if (channel_id === 0x01 && channel_type === 0x75) {\n decoded.battery = input[i];\n i += 1;\n }\n // TEMPERATURE\n if (channel_id === 0x03 && channel_type === 0x67) {\n // ℃\n decoded.temperature = parseBytesToInt(input, i,\n 2, false) / 10;\n i += 2;\n // ℉\n // decoded.temperature = parseBytesToInt(input, i, 2, false) / 10 * 1.8 + 32;\n // i +=2;\n }\n // HUMIDITY\n if (channel_id === 0x04 && channel_type === 0x68) {\n decoded.humidity = parseBytesToInt(input, i, 1, false) / 2;\n i += 1;\n }\n // PIR\n if (channel_id === 0x05 && channel_type === 0x6a) {\n decoded.activity = parseBytesToInt(input, i, 2, false);\n i += 2;\n }\n \n // LIGHT\n if (channel_id === 0x06 && channel_type === 0x65) {\n decoded.illumination = parseBytesToInt(input, i, 2, false);\n decoded.infrared_and_visible = parseBytesToInt(input, i+2, 2, false);\n decoded.infrared = parseBytesToInt(input, i+4, 2, false);\n i += 6;\n }\n }\n }\n\n output.telemetry = [{\n ts: timestamp,\n values: decoded\n }];\n \n // --- Decoding code --- //\n return output;\n}\n\n// --- attributes and telemetry objects ---\nvar telemetry = [];\nvar attributes = {};\n// --- attributes and telemetry objects ---\n\n// --- Timestamp parsing\nvar dateString = data.time;\ntimestamp = parseDateToTimestamp(dateString);\n// --- Timestamp parsing\n\n// Passing incoming bytes to decodePayload function, to get custom decoding\nvar customDecoding = decodePayload(base64ToBytes(data.data));\n\n// Collecting data to result\nif (customDecoding.?telemetry.size() > 0) {\n foreach(telemetryObj: customDecoding.telemetry) {\n if (telemetryObj.ts != null && telemetryObj.values != null) {\n telemetry.add(telemetryObj);\n }\n }\n}\n\nif (customDecoding.?attributes.size() > 0) {\n attributes.putAll(customDecoding.attributes);\n}\n\n// You can add some keys manually to attributes or telemetry\nattributes.eui = data.?devEui;\nattributes.fPort = data.fPort;\nattributes.applicationId = data.?applicationId;\nattributes.applicationName = data.?applicationName;\nattributes.frequency = data.txInfo.?frequency;\nattributes.bandwidth = data.txInfo.?dataRate.?bandwidth;\nattributes.spreadingFactor = data.txInfo.?dataRate.?spreadFactor;\nattributes.codeRate = data.txInfo.?codeRate;\n\nif(Boolean.parseBoolean(metadata[\"includeGatewayInfo\"])) {\n var gatewayInfo = getGatewayInfo();\n var addDataToTelemetry = {};\n addDataToTelemetry.snr = gatewayInfo.?loRaSNR;\n addDataToTelemetry.rssi = gatewayInfo.rssi;\n addDataToTelemetry.fCnt = data.fCnt;\n \n telemetry = processTelemetryData(telemetry, addDataToTelemetry);\n}\n\nvar result = {\n deviceName: deviceName,\n deviceType: deviceType,\n // assetName: assetName,\n // assetType: assetType,\n attributes: attributes,\n telemetry: telemetry\n};\n\naddAdditionalInfoForDeviceMsg(result, customerName, groupName);\n\nreturn result;\n\nfunction addAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName) {\n if (customerName != null) {\n deviceInfo.customerName = customerName;\n }\n if (groupName != null) {\n deviceInfo.groupName = groupName;\n }\n}\n\nfunction parseDateToTimestamp(dateString) {\n dateString = dateString.replaceFirst(\"(\\\\d{4}-\\\\d{2})(\\\\d{2})\", \"$1-$2\");\n dateString = dateString.replaceFirst(\"\\\\.(\\\\d{3})\\\\d+Z\", \".$1Z\");\n dateString = dateString.replace(\"Z\", \"+0000\");\n var date = new Date(dateString);\n var timestamp = date.getTime();\n \n // If we cannot parse timestamp - we will use the current timestamp\n if (timestamp == -1) {\n timestamp = Date.now();\n }\n \n return timestamp;\n}\n\nfunction getGatewayInfo() {\n var gatewayList = data.rxInfo;\n var maxRssi = Integer.MIN_VALUE;\n var gatewayInfo = {};\n \n foreach (gateway : gatewayList) {\n if(gateway.rssi > maxRssi) {\n maxRssi = gateway.rssi;\n gatewayInfo = gateway;\n }\n }\n \n return gatewayInfo;\n}\n\nfunction processTelemetryData(telemetry, addDataToTelemetry) {\n if (telemetry.size >= 1) {\n telemetry = addDataToTelemetries(telemetry, addDataToTelemetry);\n }\n else {\n telemetry.add(addDataToTelemetry);\n }\n \n return telemetry;\n}\n\nfunction addDataToTelemetries(telemetries, addDataToTelemetry) {\n foreach(telemetry : telemetries) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[\"values\"].keys.contains(element.key)) {\n telemetry[\"values\"][element.key] = element.value;\n }\n } \n }\n \n return telemetries;\n}", + "encoder": null, + "tbelEncoder": null, + "updateOnlyKeys": [ + "fPort", + "applicationName", + "frequency", + "bandwidth", + "spreadingFactor", + "codeRate" + ] + }, + "additionalInfo": { + "description": "" + }, + "edgeTemplate": false +} \ No newline at end of file diff --git a/VENDORS/Milesight/AM104/HTTP/uplink/metadata.json b/VENDORS/Milesight/AM104/HTTP/uplink/metadata.json new file mode 100644 index 00000000..87ee6615 --- /dev/null +++ b/VENDORS/Milesight/AM104/HTTP/uplink/metadata.json @@ -0,0 +1,4 @@ +{ + "integrationName": "HTTP integration", + "includeGatewayInfo": "false" +} \ No newline at end of file diff --git a/VENDORS/Milesight/AM104/HTTP/uplink/payload.json b/VENDORS/Milesight/AM104/HTTP/uplink/payload.json new file mode 100644 index 00000000..6b65f9fd --- /dev/null +++ b/VENDORS/Milesight/AM104/HTTP/uplink/payload.json @@ -0,0 +1,31 @@ +{ + "applicationID": 1, + "applicationName": "cloud", + "deviceName": "24e1641092176759", + "devEUI": "24e1641092176759", + "time": "2020-0327T12:39:05.547336Z", + "rxInfo": [ + { + "mac": "24e124fffef021be", + "rssi": -57, + "loRaSNR": 10, + "name": "local_gateway", + "latitude": 0, + "longitude": 0, + "altitude": 0 + } + ], + "txInfo": { + "frequency": 868300000, + "dataRate": { + "modulation": "LORA", + "bandwidth": 125, + "spreadFactor": 7 + }, + "adr": false, + "codeRate": "4/5" + }, + "fCnt": 0, + "fPort": 85, + "data": "AXVcA2c0AQRoZQVqSQAGZRwAeQAUAA==" +} \ No newline at end of file diff --git a/VENDORS/Milesight/AM104/HTTP/uplink/result.json b/VENDORS/Milesight/AM104/HTTP/uplink/result.json new file mode 100644 index 00000000..c4d9ddd2 --- /dev/null +++ b/VENDORS/Milesight/AM104/HTTP/uplink/result.json @@ -0,0 +1,24 @@ +{ + "deviceName": "AM104 24e1641092176759", + "deviceType": "AM104", + "attributes": { + "fPort": 85, + "applicationName": "cloud", + "frequency": 868300000, + "bandwidth": 125, + "spreadingFactor": 7, + "codeRate": "4/5" + }, + "telemetry": [{ + "ts": 1585312745547, + "values": { + "battery": 92, + "temperature": 30.8, + "humidity": 50.5, + "activity": 73, + "illumination": 28, + "infrared_and_visible": 121, + "infrared": 20 + } + }] +} \ No newline at end of file diff --git a/VENDORS/Milesight/AM107/HTTP/uplink/converter.json b/VENDORS/Milesight/AM107/HTTP/uplink/converter.json new file mode 100644 index 00000000..a779b6d0 --- /dev/null +++ b/VENDORS/Milesight/AM107/HTTP/uplink/converter.json @@ -0,0 +1,29 @@ +{ + "name": "HTTP Uplink integration for AM107", + "type": "UPLINK", + "debugMode": false, + "debugSettings": { + "failuresEnabled": true, + "allEnabled": false, + "allEnabledUntil": 1735560006385 + }, + "configuration": { + "scriptLang": "TBEL", + "decoder": null, + "tbelDecoder": "var data = decodeToJson(payload);\nvar deviceName = \"AM107 \" + data.devEUI;\nvar deviceType = \"AM107\";\nvar groupName = null; // If groupName is not null - created device will be added to the entity group with such name.\nvar customerName = null; // If customerName is not null - created devices will be assigned to customer with such name. \n\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// If you want to parse incoming data somehow, you can add your code to this function.\n// input: bytes\n// expected output:\n// {\n// \"attributes\": {\"attributeKey\": \"attributeValue\"},\n// \"telemetry\": [{\"ts\": 1...1, \"values\": {\"telemetryKey\":\"telemetryValue\"}, {\"ts\": 1...2, \"values\": {\"telemetryKey\":\"telemetryValue\"}}]\n// }\n\nfunction decodePayload(input) {\n var output = {\n attributes: {},\n telemetry: []\n };\n \n // --- Decoding code --- //\n var decoded = {};\n var fPort = data.fPort;\n if(fPort == 85) {\n for (var i = 0; i < input.length - 2;) {\n var channel_id = input[i++] & 0xff;\n var channel_type = input[i++] & 0xff;\n // BATTERY\n if (channel_id === 0x01 && channel_type === 0x75) {\n decoded.battery = input[i];\n i += 1;\n }\n // TEMPERATURE\n if (channel_id === 0x03 && channel_type === 0x67) {\n // ℃\n decoded.temperature = parseBytesToInt(input, i,\n 2, false) / 10;\n i += 2;\n // ℉\n // decoded.temperature = parseBytesToInt(input, i, 2, false) / 10 * 1.8 + 32;\n // i +=2;\n }\n // HUMIDITY\n if (channel_id === 0x04 && channel_type === 0x68) {\n decoded.humidity = parseBytesToInt(input, i, 1, false) / 2;\n i += 1;\n }\n // PIR\n if (channel_id === 0x05 && channel_type === 0x6a) {\n decoded.activity = parseBytesToInt(input, i, 2, false);\n i += 2;\n }\n \n // LIGHT\n if (channel_id === 0x06 && channel_type === 0x65) {\n decoded.illumination = parseBytesToInt(input, i, 2, false);\n decoded.infrared_and_visible = parseBytesToInt(input, i+2, 2, false);\n decoded.infrared = parseBytesToInt(input, i+4, 2, false);\n i += 6;\n }\n // CO2\n if (channel_id === 0x07 && channel_type === 0x7d) {\n decoded.co2 = parseBytesToInt(input, i, 2, false);\n i += 2;\n }\n // TVOC\n if (channel_id === 0x08 && channel_type === 0x7d) {\n decoded.tvoc = parseBytesToInt(input, i, 2, false);\n i += 2;\n }\n // PRESSURE\n if (channel_id === 0x09 && channel_type === 0x73) {\n decoded.pressure = parseBytesToInt(input, i, 2, false) / 10;\n i += 2;\n }\n }\n }\n\n output.telemetry = [{\n ts: timestamp,\n values: decoded\n }];\n \n // --- Decoding code --- //\n return output;\n}\n\n// --- attributes and telemetry objects ---\nvar telemetry = [];\nvar attributes = {};\n// --- attributes and telemetry objects ---\n\n// --- Timestamp parsing\nvar dateString = data.time;\ntimestamp = parseDateToTimestamp(dateString);\n// --- Timestamp parsing\n\n// Passing incoming bytes to decodePayload function, to get custom decoding\nvar customDecoding = decodePayload(base64ToBytes(data.data));\n\n// Collecting data to result\nif (customDecoding.?telemetry.size() > 0) {\n foreach(telemetryObj: customDecoding.telemetry) {\n if (telemetryObj.ts != null && telemetryObj.values != null) {\n telemetry.add(telemetryObj);\n }\n }\n}\n\nif (customDecoding.?attributes.size() > 0) {\n attributes.putAll(customDecoding.attributes);\n}\n\n// You can add some keys manually to attributes or telemetry\nattributes.eui = data.?devEui;\nattributes.fPort = data.fPort;\nattributes.applicationId = data.?applicationId;\nattributes.applicationName = data.?applicationName;\nattributes.frequency = data.txInfo.?frequency;\nattributes.bandwidth = data.txInfo.?dataRate.?bandwidth;\nattributes.spreadingFactor = data.txInfo.?dataRate.?spreadFactor;\nattributes.codeRate = data.txInfo.?codeRate;\n\nif(Boolean.parseBoolean(metadata[\"includeGatewayInfo\"])) {\n var gatewayInfo = getGatewayInfo();\n var addDataToTelemetry = {};\n addDataToTelemetry.snr = gatewayInfo.?loRaSNR;\n addDataToTelemetry.rssi = gatewayInfo.rssi;\n addDataToTelemetry.fCnt = data.fCnt;\n \n telemetry = processTelemetryData(telemetry, addDataToTelemetry);\n}\n\nvar result = {\n deviceName: deviceName,\n deviceType: deviceType,\n // assetName: assetName,\n // assetType: assetType,\n attributes: attributes,\n telemetry: telemetry\n};\n\naddAdditionalInfoForDeviceMsg(result, customerName, groupName);\n\nreturn result;\n\nfunction addAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName) {\n if (customerName != null) {\n deviceInfo.customerName = customerName;\n }\n if (groupName != null) {\n deviceInfo.groupName = groupName;\n }\n}\n\nfunction parseDateToTimestamp(dateString) {\n dateString = dateString.replaceFirst(\"(\\\\d{4}-\\\\d{2})(\\\\d{2})\", \"$1-$2\");\n dateString = dateString.replaceFirst(\"\\\\.(\\\\d{3})\\\\d+Z\", \".$1Z\");\n dateString = dateString.replace(\"Z\", \"+0000\");\n var date = new Date(dateString);\n var timestamp = date.getTime();\n \n // If we cannot parse timestamp - we will use the current timestamp\n if (timestamp == -1) {\n timestamp = Date.now();\n }\n \n return timestamp;\n}\n\nfunction getGatewayInfo() {\n var gatewayList = data.rxInfo;\n var maxRssi = Integer.MIN_VALUE;\n var gatewayInfo = {};\n \n foreach (gateway : gatewayList) {\n if(gateway.rssi > maxRssi) {\n maxRssi = gateway.rssi;\n gatewayInfo = gateway;\n }\n }\n \n return gatewayInfo;\n}\n\nfunction processTelemetryData(telemetry, addDataToTelemetry) {\n if (telemetry.size >= 1) {\n telemetry = addDataToTelemetries(telemetry, addDataToTelemetry);\n }\n else {\n telemetry.add(addDataToTelemetry);\n }\n \n return telemetry;\n}\n\nfunction addDataToTelemetries(telemetries, addDataToTelemetry) {\n foreach(telemetry : telemetries) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[\"values\"].keys.contains(element.key)) {\n telemetry[\"values\"][element.key] = element.value;\n }\n } \n }\n \n return telemetries;\n}", + "encoder": null, + "tbelEncoder": null, + "updateOnlyKeys": [ + "fPort", + "applicationName", + "frequency", + "bandwidth", + "spreadingFactor", + "codeRate" + ] + }, + "additionalInfo": { + "description": "" + }, + "edgeTemplate": false +} \ No newline at end of file diff --git a/VENDORS/Milesight/AM107/HTTP/uplink/metadata.json b/VENDORS/Milesight/AM107/HTTP/uplink/metadata.json new file mode 100644 index 00000000..87ee6615 --- /dev/null +++ b/VENDORS/Milesight/AM107/HTTP/uplink/metadata.json @@ -0,0 +1,4 @@ +{ + "integrationName": "HTTP integration", + "includeGatewayInfo": "false" +} \ No newline at end of file diff --git a/VENDORS/Milesight/AM107/HTTP/uplink/payload.json b/VENDORS/Milesight/AM107/HTTP/uplink/payload.json new file mode 100644 index 00000000..e475505f --- /dev/null +++ b/VENDORS/Milesight/AM107/HTTP/uplink/payload.json @@ -0,0 +1,31 @@ +{ + "applicationID": 1, + "applicationName": "cloud", + "deviceName": "24e1641092176759", + "devEUI": "24e1641092176759", + "time": "2020-0327T12:39:05.547336Z", + "rxInfo": [ + { + "mac": "24e124fffef021be", + "rssi": -57, + "loRaSNR": 10, + "name": "local_gateway", + "latitude": 0, + "longitude": 0, + "altitude": 0 + } + ], + "txInfo": { + "frequency": 868300000, + "dataRate": { + "modulation": "LORA", + "bandwidth": 125, + "spreadFactor": 7 + }, + "adr": false, + "codeRate": "4/5" + }, + "fCnt": 0, + "fPort": 85, + "data": "AXVcA2c0AQRoZQVqSQAGZRwAeQAUAAd95wQIfQcACXM/Jw==" +} \ No newline at end of file diff --git a/VENDORS/Milesight/AM107/HTTP/uplink/result.json b/VENDORS/Milesight/AM107/HTTP/uplink/result.json new file mode 100644 index 00000000..0e9b1315 --- /dev/null +++ b/VENDORS/Milesight/AM107/HTTP/uplink/result.json @@ -0,0 +1,27 @@ +{ + "deviceName": "AM107 24e1641092176759", + "deviceType": "AM107", + "attributes": { + "fPort": 85, + "applicationName": "cloud", + "frequency": 868300000, + "bandwidth": 125, + "spreadingFactor": 7, + "codeRate": "4/5" + }, + "telemetry": [{ + "ts": 1585312745547, + "values": { + "battery": 92, + "temperature": 30.8, + "humidity": 50.5, + "activity": 73, + "illumination": 28, + "infrared_and_visible": 121, + "infrared": 20, + "co2": 1255, + "tvoc": 7, + "pressure": 1004.7 + } + }] +} \ No newline at end of file diff --git a/VENDORS/Milesight/AM307/HTTP/uplink/converter.json b/VENDORS/Milesight/AM307/HTTP/uplink/converter.json new file mode 100644 index 00000000..490e72b9 --- /dev/null +++ b/VENDORS/Milesight/AM307/HTTP/uplink/converter.json @@ -0,0 +1,29 @@ +{ + "name": "HTTP Uplink integration for AM307", + "type": "UPLINK", + "debugMode": false, + "debugSettings": { + "failuresEnabled": true, + "allEnabled": false, + "allEnabledUntil": 1735560006385 + }, + "configuration": { + "scriptLang": "TBEL", + "decoder": null, + "tbelDecoder": "var data = decodeToJson(payload);\nvar deviceName = \"AM307 \" + data.devEUI;\nvar deviceType = \"AM307\";\nvar groupName = null; // If groupName is not null - created device will be added to the entity group with such name.\nvar customerName = null; // If customerName is not null - created devices will be assigned to customer with such name. \n\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// If you want to parse incoming data somehow, you can add your code to this function.\n// input: bytes\n// expected output:\n// {\n// \"attributes\": {\"attributeKey\": \"attributeValue\"},\n// \"telemetry\": [{\"ts\": 1...1, \"values\": {\"telemetryKey\":\"telemetryValue\"}, {\"ts\": 1...2, \"values\": {\"telemetryKey\":\"telemetryValue\"}}]\n// }\n\nfunction decodePayload(input) {\n var output = {\n attributes: {},\n telemetry: []\n };\n \n // --- Decoding code --- //\n var decoded = {};\n var fPort = data.fPort;\n var historyDataList = [];\n if(fPort == 85) {\n for (var i = 0; i < input.length - 2;) {\n var channel_id = input[i++] & 0xff;\n var channel_type = input[i++] & 0xff;\n // BATTERY\n if (channel_id === 0x01 && channel_type === 0x75) {\n decoded.battery = input[i];\n i += 1;\n }\n // TEMPERATURE\n if (channel_id === 0x03 && channel_type === 0x67) {\n // ℃\n decoded.temperature = parseBytesToInt(input, i,\n 2, false) / 10;\n i += 2;\n // ℉\n // decoded.temperature = parseBytesToInt(input, i, 2, false) / 10 * 1.8 + 32;\n // i +=2;\n }\n // HUMIDITY\n if (channel_id === 0x04 && channel_type === 0x68) {\n decoded.humidity = parseBytesToInt(input, i, 1, false) / 2;\n i += 1;\n }\n // PIR\n if (channel_id === 0x05 && channel_type === 0x00) {\n decoded.pir = input[i] === 1 ? \"trigger\" :\n \"idle\";\n i += 1;\n }\n // LIGHT\n if (channel_id === 0x06 && channel_type === 0xCB) {\n decoded.light_level = input[i];\n i += 1;\n }\n // CO2\n if (channel_id === 0x07 && channel_type === 0x7D) {\n decoded.co2 = parseBytesToInt(input, i, 2,\n false);\n i += 2;\n }\n // TVOC\n if (channel_id === 0x08 && channel_type === 0x7D) {\n decoded.tvoc = parseBytesToInt(input, i, 2,\n false);\n i += 2;\n }\n // PRESSURE\n if (channel_id === 0x09 && channel_type === 0x73) {\n decoded.pressure = parseBytesToInt(input, i, 2,\n false) / 10;\n i += 2;\n }\n // BEEP\n if (channel_id === 0x0E && channel_type === 0x01) {\n decoded.beep = input[i] === 1 ? \"yes\" : \"no\";\n i += 1;\n }\n // HISTORY DATA\n if (channel_id === 0x20 && channel_type === 0xCE) {\n var historyData = {\n ts: parseBytesToInt(input, i, 4, false) * 1000,\n values: {\n temperature: parseBytesToInt(input, i + 4, 2, false) / 10,\n humidity: parseBytesToInt(input, i + 6, 2, false) / 2,\n pir: input[i + 8] === 1 ? \"trigger\" : \"idle\",\n light_level: input[i + 9],\n co2: parseBytesToInt(input, i + 10, 2, false),\n tvoc: parseBytesToInt(input, i + 12, 2, false),\n pressure: parseBytesToInt(input, i + 14, 2, false) / 10,\n }\n };\n \n historyDataList.add(historyData);\n \n i += 16;\n } \n }\n }\n\n output.telemetry = [{\n ts: timestamp,\n values: decoded\n }];\n \n output.telemetry.addAll(historyDataList);\n \n // --- Decoding code --- //\n return output;\n}\n\n// --- attributes and telemetry objects ---\nvar telemetry = [];\nvar attributes = {};\n// --- attributes and telemetry objects ---\n\n// --- Timestamp parsing\nvar dateString = data.time;\ntimestamp = parseDateToTimestamp(dateString);\n// --- Timestamp parsing\n\n// Passing incoming bytes to decodePayload function, to get custom decoding\nvar customDecoding = decodePayload(base64ToBytes(data.data));\n\n// Collecting data to result\nif (customDecoding.?telemetry.size() > 0) {\n foreach(telemetryObj: customDecoding.telemetry) {\n if (telemetryObj.ts != null && telemetryObj.values != null) {\n telemetry.add(telemetryObj);\n }\n }\n}\n\nif (customDecoding.?attributes.size() > 0) {\n attributes.putAll(customDecoding.attributes);\n}\n\n// You can add some keys manually to attributes or telemetry\nattributes.eui = data.?devEui;\nattributes.fPort = data.fPort;\nattributes.applicationId = data.?applicationId;\nattributes.applicationName = data.?applicationName;\nattributes.frequency = data.txInfo.?frequency;\nattributes.bandwidth = data.txInfo.?dataRate.?bandwidth;\nattributes.spreadingFactor = data.txInfo.?dataRate.?spreadFactor;\nattributes.codeRate = data.txInfo.?codeRate;\n\nif(Boolean.parseBoolean(metadata[\"includeGatewayInfo\"])) {\n var gatewayInfo = getGatewayInfo();\n var addDataToTelemetry = {};\n addDataToTelemetry.snr = gatewayInfo.?loRaSNR;\n addDataToTelemetry.rssi = gatewayInfo.rssi;\n addDataToTelemetry.fCnt = data.fCnt;\n \n telemetry = processTelemetryData(telemetry, addDataToTelemetry);\n}\n\nvar result = {\n deviceName: deviceName,\n deviceType: deviceType,\n // assetName: assetName,\n // assetType: assetType,\n attributes: attributes,\n telemetry: telemetry\n};\n\naddAdditionalInfoForDeviceMsg(result, customerName, groupName);\n\nreturn result;\n\nfunction addAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName) {\n if (customerName != null) {\n deviceInfo.customerName = customerName;\n }\n if (groupName != null) {\n deviceInfo.groupName = groupName;\n }\n}\n\nfunction parseDateToTimestamp(dateString) {\n dateString = dateString.replaceFirst(\"(\\\\d{4}-\\\\d{2})(\\\\d{2})\", \"$1-$2\");\n dateString = dateString.replaceFirst(\"\\\\.(\\\\d{3})\\\\d+Z\", \".$1Z\");\n dateString = dateString.replace(\"Z\", \"+0000\");\n var date = new Date(dateString);\n var timestamp = date.getTime();\n \n // If we cannot parse timestamp - we will use the current timestamp\n if (timestamp == -1) {\n timestamp = Date.now();\n }\n \n return timestamp;\n}\n\nfunction getGatewayInfo() {\n var gatewayList = data.rxInfo;\n var maxRssi = Integer.MIN_VALUE;\n var gatewayInfo = {};\n \n foreach (gateway : gatewayList) {\n if(gateway.rssi > maxRssi) {\n maxRssi = gateway.rssi;\n gatewayInfo = gateway;\n }\n }\n \n return gatewayInfo;\n}\n\nfunction processTelemetryData(telemetry, addDataToTelemetry) {\n if (telemetry.size >= 1) {\n telemetry = addDataToTelemetries(telemetry, addDataToTelemetry);\n }\n else {\n telemetry.add(addDataToTelemetry);\n }\n \n return telemetry;\n}\n\nfunction addDataToTelemetries(telemetries, addDataToTelemetry) {\n foreach(telemetry : telemetries) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[\"values\"].keys.contains(element.key)) {\n telemetry[\"values\"][element.key] = element.value;\n }\n } \n }\n \n return telemetries;\n}", + "encoder": null, + "tbelEncoder": null, + "updateOnlyKeys": [ + "fPort", + "applicationName", + "frequency", + "bandwidth", + "spreadingFactor", + "codeRate" + ] + }, + "additionalInfo": { + "description": "" + }, + "edgeTemplate": false +} \ No newline at end of file diff --git a/VENDORS/Milesight/AM307/HTTP/uplink/metadata.json b/VENDORS/Milesight/AM307/HTTP/uplink/metadata.json new file mode 100644 index 00000000..87ee6615 --- /dev/null +++ b/VENDORS/Milesight/AM307/HTTP/uplink/metadata.json @@ -0,0 +1,4 @@ +{ + "integrationName": "HTTP integration", + "includeGatewayInfo": "false" +} \ No newline at end of file diff --git a/VENDORS/Milesight/AM307/HTTP/uplink/payload.json b/VENDORS/Milesight/AM307/HTTP/uplink/payload.json new file mode 100644 index 00000000..aa80cdcc --- /dev/null +++ b/VENDORS/Milesight/AM307/HTTP/uplink/payload.json @@ -0,0 +1,31 @@ +{ + "applicationID": 1, + "applicationName": "cloud", + "deviceName": "24e1641092176759", + "devEUI": "24e1641092176759", + "time": "2020-0327T12:39:05.547336Z", + "rxInfo": [ + { + "mac": "24e124fffef021be", + "rssi": -57, + "loRaSNR": 10, + "name": "local_gateway", + "latitude": 0, + "longitude": 0, + "altitude": 0 + } + ], + "txInfo": { + "frequency": 868300000, + "dataRate": { + "modulation": "LORA", + "bandwidth": 125, + "spreadFactor": 7 + }, + "adr": false, + "codeRate": "4/5" + }, + "fCnt": 0, + "fPort": 85, + "data": "AXVVA2fuAARofAUAAQbLAgd9qAMIfSUACXNmJwp9BAALfSAADH0wAA19IAAOAVUgzmU1ygwA4QBuAWQBwgAKJ5cAGQAy" +} \ No newline at end of file diff --git a/VENDORS/Milesight/AM307/HTTP/uplink/result.json b/VENDORS/Milesight/AM307/HTTP/uplink/result.json new file mode 100644 index 00000000..110663eb --- /dev/null +++ b/VENDORS/Milesight/AM307/HTTP/uplink/result.json @@ -0,0 +1,37 @@ +{ + "deviceName": "AM307 24e1641092176759", + "deviceType": "AM307", + "attributes": { + "fPort": 85, + "applicationName": "cloud", + "frequency": 868300000, + "bandwidth": 125, + "spreadingFactor": 7, + "codeRate": "4/5" + }, + "telemetry": [{ + "ts": 1585312745547, + "values": { + "battery": 85, + "temperature": 23.8, + "humidity": 62.0, + "pir": "trigger", + "light_level": 2, + "co2": 936, + "tvoc": 37, + "pressure": 1008.6, + "beep": "no" + } + }, { + "ts": 214578533000, + "values": { + "temperature": 5760.0, + "humidity": 14080.0, + "trigger": "idle", + "light_level": 100, + "co2": 49665, + "tvoc": 2560, + "pressure": 3869.5 + } + }] +} \ No newline at end of file diff --git a/VENDORS/Milesight/AM307L/HTTP/uplink/converter.json b/VENDORS/Milesight/AM307L/HTTP/uplink/converter.json new file mode 100644 index 00000000..3b4ca37f --- /dev/null +++ b/VENDORS/Milesight/AM307L/HTTP/uplink/converter.json @@ -0,0 +1,29 @@ +{ + "name": "HTTP Uplink integration for AM307L", + "type": "UPLINK", + "debugMode": false, + "debugSettings": { + "failuresEnabled": true, + "allEnabled": false, + "allEnabledUntil": 1735560006385 + }, + "configuration": { + "scriptLang": "TBEL", + "decoder": null, + "tbelDecoder": "var data = decodeToJson(payload);\nvar deviceName = \"AM307L \" + data.devEUI;\nvar deviceType = \"AM307L\";\nvar groupName = null; // If groupName is not null - created device will be added to the entity group with such name.\nvar customerName = null; // If customerName is not null - created devices will be assigned to customer with such name. \n\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// If you want to parse incoming data somehow, you can add your code to this function.\n// input: bytes\n// expected output:\n// {\n// \"attributes\": {\"attributeKey\": \"attributeValue\"},\n// \"telemetry\": [{\"ts\": 1...1, \"values\": {\"telemetryKey\":\"telemetryValue\"}, {\"ts\": 1...2, \"values\": {\"telemetryKey\":\"telemetryValue\"}}]\n// }\n\nfunction decodePayload(input) {\n var output = {\n attributes: {},\n telemetry: []\n };\n \n // --- Decoding code --- //\n var decoded = {};\n var fPort = data.fPort;\n var historyDataList = [];\n if(fPort == 85) {\n for (var i = 0; i < input.length - 2;) {\n var channel_id = input[i++] & 0xff;\n var channel_type = input[i++] & 0xff;\n // BATTERY\n if (channel_id === 0x01 && channel_type === 0x75) {\n decoded.battery = input[i];\n i += 1;\n }\n // TEMPERATURE\n if (channel_id === 0x03 && channel_type === 0x67) {\n // ℃\n decoded.temperature = parseBytesToInt(input, i,\n 2, false) / 10;\n i += 2;\n // ℉\n // decoded.temperature = parseBytesToInt(input, i, 2, false) / 10 * 1.8 + 32;\n // i +=2;\n }\n // HUMIDITY\n if (channel_id === 0x04 && channel_type === 0x68) {\n decoded.humidity = parseBytesToInt(input, i, 1, false) / 2;\n i += 1;\n }\n // PIR\n if (channel_id === 0x05 && channel_type === 0x00) {\n decoded.pir = input[i] === 1 ? \"trigger\" :\n \"idle\";\n i += 1;\n }\n // LIGHT\n if (channel_id === 0x06 && channel_type === 0xCB) {\n decoded.light_level = input[i];\n i += 1;\n }\n // CO2\n if (channel_id === 0x07 && channel_type === 0x7D) {\n decoded.co2 = parseBytesToInt(input, i, 2,\n false);\n i += 2;\n }\n // TVOC\n if (channel_id === 0x08 && channel_type === 0x7D) {\n decoded.tvoc = parseBytesToInt(input, i, 2,\n false);\n i += 2;\n }\n // PRESSURE\n if (channel_id === 0x09 && channel_type === 0x73) {\n decoded.pressure = parseBytesToInt(input, i, 2,\n false) / 10;\n i += 2;\n }\n // BEEP\n if (channel_id === 0x0E && channel_type === 0x01) {\n decoded.beep = input[i] === 1 ? \"yes\" : \"no\";\n i += 1;\n }\n // HISTORY DATA\n if (channel_id === 0x20 && channel_type === 0xCE) {\n var historyData = {\n ts: parseBytesToInt(input, i, 4, false) * 1000,\n values: {\n temperature: parseBytesToInt(input, i + 4, 2, false) / 10,\n humidity: parseBytesToInt(input, i + 6, 2, false) / 2,\n pir: input[i + 8] === 1 ? \"trigger\" : \"idle\",\n light_level: input[i + 9],\n co2: parseBytesToInt(input, i + 10, 2, false),\n tvoc: parseBytesToInt(input, i + 12, 2, false),\n pressure: parseBytesToInt(input, i + 14, 2, false) / 10,\n }\n };\n \n historyDataList.add(historyData);\n \n i += 16;\n } \n }\n }\n\n output.telemetry = [{\n ts: timestamp,\n values: decoded\n }];\n \n output.telemetry.addAll(historyDataList);\n \n // --- Decoding code --- //\n return output;\n}\n\n// --- attributes and telemetry objects ---\nvar telemetry = [];\nvar attributes = {};\n// --- attributes and telemetry objects ---\n\n// --- Timestamp parsing\nvar dateString = data.time;\ntimestamp = parseDateToTimestamp(dateString);\n// --- Timestamp parsing\n\n// Passing incoming bytes to decodePayload function, to get custom decoding\nvar customDecoding = decodePayload(base64ToBytes(data.data));\n\n// Collecting data to result\nif (customDecoding.?telemetry.size() > 0) {\n foreach(telemetryObj: customDecoding.telemetry) {\n if (telemetryObj.ts != null && telemetryObj.values != null) {\n telemetry.add(telemetryObj);\n }\n }\n}\n\nif (customDecoding.?attributes.size() > 0) {\n attributes.putAll(customDecoding.attributes);\n}\n\n// You can add some keys manually to attributes or telemetry\nattributes.eui = data.?devEui;\nattributes.fPort = data.fPort;\nattributes.applicationId = data.?applicationId;\nattributes.applicationName = data.?applicationName;\nattributes.frequency = data.txInfo.?frequency;\nattributes.bandwidth = data.txInfo.?dataRate.?bandwidth;\nattributes.spreadingFactor = data.txInfo.?dataRate.?spreadFactor;\nattributes.codeRate = data.txInfo.?codeRate;\n\nif(Boolean.parseBoolean(metadata[\"includeGatewayInfo\"])) {\n var gatewayInfo = getGatewayInfo();\n var addDataToTelemetry = {};\n addDataToTelemetry.snr = gatewayInfo.?loRaSNR;\n addDataToTelemetry.rssi = gatewayInfo.rssi;\n addDataToTelemetry.fCnt = data.fCnt;\n \n telemetry = processTelemetryData(telemetry, addDataToTelemetry);\n}\n\nvar result = {\n deviceName: deviceName,\n deviceType: deviceType,\n // assetName: assetName,\n // assetType: assetType,\n attributes: attributes,\n telemetry: telemetry\n};\n\naddAdditionalInfoForDeviceMsg(result, customerName, groupName);\n\nreturn result;\n\nfunction addAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName) {\n if (customerName != null) {\n deviceInfo.customerName = customerName;\n }\n if (groupName != null) {\n deviceInfo.groupName = groupName;\n }\n}\n\nfunction parseDateToTimestamp(dateString) {\n dateString = dateString.replaceFirst(\"(\\\\d{4}-\\\\d{2})(\\\\d{2})\", \"$1-$2\");\n dateString = dateString.replaceFirst(\"\\\\.(\\\\d{3})\\\\d+Z\", \".$1Z\");\n dateString = dateString.replace(\"Z\", \"+0000\");\n var date = new Date(dateString);\n var timestamp = date.getTime();\n \n // If we cannot parse timestamp - we will use the current timestamp\n if (timestamp == -1) {\n timestamp = Date.now();\n }\n \n return timestamp;\n}\n\nfunction getGatewayInfo() {\n var gatewayList = data.rxInfo;\n var maxRssi = Integer.MIN_VALUE;\n var gatewayInfo = {};\n \n foreach (gateway : gatewayList) {\n if(gateway.rssi > maxRssi) {\n maxRssi = gateway.rssi;\n gatewayInfo = gateway;\n }\n }\n \n return gatewayInfo;\n}\n\nfunction processTelemetryData(telemetry, addDataToTelemetry) {\n if (telemetry.size >= 1) {\n telemetry = addDataToTelemetries(telemetry, addDataToTelemetry);\n }\n else {\n telemetry.add(addDataToTelemetry);\n }\n \n return telemetry;\n}\n\nfunction addDataToTelemetries(telemetries, addDataToTelemetry) {\n foreach(telemetry : telemetries) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[\"values\"].keys.contains(element.key)) {\n telemetry[\"values\"][element.key] = element.value;\n }\n } \n }\n \n return telemetries;\n}", + "encoder": null, + "tbelEncoder": null, + "updateOnlyKeys": [ + "fPort", + "applicationName", + "frequency", + "bandwidth", + "spreadingFactor", + "codeRate" + ] + }, + "additionalInfo": { + "description": "" + }, + "edgeTemplate": false +} \ No newline at end of file diff --git a/VENDORS/Milesight/AM307L/HTTP/uplink/metadata.json b/VENDORS/Milesight/AM307L/HTTP/uplink/metadata.json new file mode 100644 index 00000000..87ee6615 --- /dev/null +++ b/VENDORS/Milesight/AM307L/HTTP/uplink/metadata.json @@ -0,0 +1,4 @@ +{ + "integrationName": "HTTP integration", + "includeGatewayInfo": "false" +} \ No newline at end of file diff --git a/VENDORS/Milesight/AM307L/HTTP/uplink/payload.json b/VENDORS/Milesight/AM307L/HTTP/uplink/payload.json new file mode 100644 index 00000000..aa80cdcc --- /dev/null +++ b/VENDORS/Milesight/AM307L/HTTP/uplink/payload.json @@ -0,0 +1,31 @@ +{ + "applicationID": 1, + "applicationName": "cloud", + "deviceName": "24e1641092176759", + "devEUI": "24e1641092176759", + "time": "2020-0327T12:39:05.547336Z", + "rxInfo": [ + { + "mac": "24e124fffef021be", + "rssi": -57, + "loRaSNR": 10, + "name": "local_gateway", + "latitude": 0, + "longitude": 0, + "altitude": 0 + } + ], + "txInfo": { + "frequency": 868300000, + "dataRate": { + "modulation": "LORA", + "bandwidth": 125, + "spreadFactor": 7 + }, + "adr": false, + "codeRate": "4/5" + }, + "fCnt": 0, + "fPort": 85, + "data": "AXVVA2fuAARofAUAAQbLAgd9qAMIfSUACXNmJwp9BAALfSAADH0wAA19IAAOAVUgzmU1ygwA4QBuAWQBwgAKJ5cAGQAy" +} \ No newline at end of file diff --git a/VENDORS/Milesight/AM307L/HTTP/uplink/result.json b/VENDORS/Milesight/AM307L/HTTP/uplink/result.json new file mode 100644 index 00000000..7d3b2eea --- /dev/null +++ b/VENDORS/Milesight/AM307L/HTTP/uplink/result.json @@ -0,0 +1,37 @@ +{ + "deviceName": "AM307L 24e1641092176759", + "deviceType": "AM307L", + "attributes": { + "fPort": 85, + "applicationName": "cloud", + "frequency": 868300000, + "bandwidth": 125, + "spreadingFactor": 7, + "codeRate": "4/5" + }, + "telemetry": [{ + "ts": 1585312745547, + "values": { + "battery": 85, + "temperature": 23.8, + "humidity": 62.0, + "pir": "trigger", + "light_level": 2, + "co2": 936, + "tvoc": 37, + "pressure": 1008.6, + "beep": "no" + } + }, { + "ts": 214578533000, + "values": { + "temperature": 5760.0, + "humidity": 14080.0, + "trigger": "idle", + "light_level": 100, + "co2": 49665, + "tvoc": 2560, + "pressure": 3869.5 + } + }] +} \ No newline at end of file diff --git a/VENDORS/Milesight/AM308/HTTP/uplink/converter.json b/VENDORS/Milesight/AM308/HTTP/uplink/converter.json new file mode 100644 index 00000000..a6b4e9e5 --- /dev/null +++ b/VENDORS/Milesight/AM308/HTTP/uplink/converter.json @@ -0,0 +1,29 @@ +{ + "name": "HTTP Uplink integration for AM308", + "type": "UPLINK", + "debugMode": false, + "debugSettings": { + "failuresEnabled": true, + "allEnabled": false, + "allEnabledUntil": 1735560006385 + }, + "configuration": { + "scriptLang": "TBEL", + "decoder": null, + "tbelDecoder": "var data = decodeToJson(payload);\nvar deviceName = \"AM308 \" + data.devEUI;\nvar deviceType = \"AM308\";\nvar groupName = null; // If groupName is not null - created device will be added to the entity group with such name.\nvar customerName = null; // If customerName is not null - created devices will be assigned to customer with such name. \n\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// If you want to parse incoming data somehow, you can add your code to this function.\n// input: bytes\n// expected output:\n// {\n// \"attributes\": {\"attributeKey\": \"attributeValue\"},\n// \"telemetry\": [{\"ts\": 1...1, \"values\": {\"telemetryKey\":\"telemetryValue\"}, {\"ts\": 1...2, \"values\": {\"telemetryKey\":\"telemetryValue\"}}]\n// }\n\nfunction decodePayload(input) {\n var output = {\n attributes: {},\n telemetry: []\n };\n \n // --- Decoding code --- //\n var decoded = {};\n var fPort = data.fPort;\n var historyDataList = [];\n if(fPort == 85) {\n for (var i = 0; i < input.length - 2;) {\n var channel_id = input[i++] & 0xff;\n var channel_type = input[i++] & 0xff;\n // BATTERY\n if (channel_id === 0x01 && channel_type === 0x75) {\n decoded.battery = input[i];\n i += 1;\n }\n // TEMPERATURE\n if (channel_id === 0x03 && channel_type === 0x67) {\n // ℃\n decoded.temperature = parseBytesToInt(input, i,\n 2, false) / 10;\n i += 2;\n // ℉\n // decoded.temperature = parseBytesToInt(input, i, 2, false) / 10 * 1.8 + 32;\n // i +=2;\n }\n // HUMIDITY\n if (channel_id === 0x04 && channel_type === 0x68) {\n decoded.humidity = parseBytesToInt(input, i, 1, false) / 2;\n i += 1;\n }\n // PIR\n if (channel_id === 0x05 && channel_type === 0x00) {\n decoded.pir = input[i] === 1 ? \"trigger\" :\n \"idle\";\n i += 1;\n }\n // LIGHT\n if (channel_id === 0x06 && channel_type === 0xCB) {\n decoded.light_level = input[i];\n i += 1;\n }\n // CO2\n if (channel_id === 0x07 && channel_type === 0x7D) {\n decoded.co2 = parseBytesToInt(input, i, 2,\n false);\n i += 2;\n }\n // TVOC\n if (channel_id === 0x08 && channel_type === 0x7D) {\n decoded.tvoc = parseBytesToInt(input, i, 2,\n false);\n i += 2;\n }\n // PRESSURE\n if (channel_id === 0x09 && channel_type === 0x73) {\n decoded.pressure = parseBytesToInt(input, i, 2,\n false) / 10;\n i += 2;\n }\n // PM2.5\n if (channel_id === 0x0B && channel_type === 0x7D) {\n decoded.pm2_5 = parseBytesToInt(input, i, 2,\n false);\n i += 2;\n }\n // PM10\n if (channel_id === 0x0C && channel_type === 0x7D) {\n decoded.pm10 = parseBytesToInt(input, i, 2,\n false);\n i += 2;\n }\n // BEEP\n if (channel_id === 0x0E && channel_type === 0x01) {\n decoded.beep = input[i] === 1 ? \"yes\" : \"no\";\n i += 1;\n }\n // HISTORY DATA\n if (channel_id === 0x20 && channel_type === 0xCE) {\n var historyData = {\n ts: parseBytesToInt(input, i, 4, false) * 1000,\n values: {\n temperature: parseBytesToInt(input, i + 4, 2, false) / 10,\n humidity: parseBytesToInt(input, i + 6, 2, false) / 2,\n pir: input[i + 8] === 1 ? \"trigger\" : \"idle\",\n light_level: input[i + 9],\n co2: parseBytesToInt(input, i + 10, 2, false),\n tvoc: parseBytesToInt(input, i + 12, 2, false),\n pressure: parseBytesToInt(input, i + 14, 2, false) / 10,\n pm2_5: parseBytesToInt(input, i + 16, 2, false),\n pm10: parseBytesToInt(input, i + 18, 2, false)\n }\n };\n \n historyDataList.add(historyData);\n \n i += 20;\n }\n }\n }\n\n output.telemetry = [{\n ts: timestamp,\n values: decoded\n }];\n \n output.telemetry.addAll(historyDataList);\n \n // --- Decoding code --- //\n return output;\n}\n\n// --- attributes and telemetry objects ---\nvar telemetry = [];\nvar attributes = {};\n// --- attributes and telemetry objects ---\n\n// --- Timestamp parsing\nvar dateString = data.time;\ntimestamp = parseDateToTimestamp(dateString);\n// --- Timestamp parsing\n\n// Passing incoming bytes to decodePayload function, to get custom decoding\nvar customDecoding = decodePayload(base64ToBytes(data.data));\n\n// Collecting data to result\nif (customDecoding.?telemetry.size() > 0) {\n foreach(telemetryObj: customDecoding.telemetry) {\n if (telemetryObj.ts != null && telemetryObj.values != null) {\n telemetry.add(telemetryObj);\n }\n }\n}\n\nif (customDecoding.?attributes.size() > 0) {\n attributes.putAll(customDecoding.attributes);\n}\n\n// You can add some keys manually to attributes or telemetry\nattributes.eui = data.?devEui;\nattributes.fPort = data.fPort;\nattributes.applicationId = data.?applicationId;\nattributes.applicationName = data.?applicationName;\nattributes.frequency = data.txInfo.?frequency;\nattributes.bandwidth = data.txInfo.?dataRate.?bandwidth;\nattributes.spreadingFactor = data.txInfo.?dataRate.?spreadFactor;\nattributes.codeRate = data.txInfo.?codeRate;\n\nif(Boolean.parseBoolean(metadata[\"includeGatewayInfo\"])) {\n var gatewayInfo = getGatewayInfo();\n var addDataToTelemetry = {};\n addDataToTelemetry.snr = gatewayInfo.?loRaSNR;\n addDataToTelemetry.rssi = gatewayInfo.rssi;\n addDataToTelemetry.fCnt = data.fCnt;\n \n telemetry = processTelemetryData(telemetry, addDataToTelemetry);\n}\n\nvar result = {\n deviceName: deviceName,\n deviceType: deviceType,\n // assetName: assetName,\n // assetType: assetType,\n attributes: attributes,\n telemetry: telemetry\n};\n\naddAdditionalInfoForDeviceMsg(result, customerName, groupName);\n\nreturn result;\n\nfunction addAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName) {\n if (customerName != null) {\n deviceInfo.customerName = customerName;\n }\n if (groupName != null) {\n deviceInfo.groupName = groupName;\n }\n}\n\nfunction parseDateToTimestamp(dateString) {\n dateString = dateString.replaceFirst(\"(\\\\d{4}-\\\\d{2})(\\\\d{2})\", \"$1-$2\");\n dateString = dateString.replaceFirst(\"\\\\.(\\\\d{3})\\\\d+Z\", \".$1Z\");\n dateString = dateString.replace(\"Z\", \"+0000\");\n var date = new Date(dateString);\n var timestamp = date.getTime();\n \n // If we cannot parse timestamp - we will use the current timestamp\n if (timestamp == -1) {\n timestamp = Date.now();\n }\n \n return timestamp;\n}\n\nfunction getGatewayInfo() {\n var gatewayList = data.rxInfo;\n var maxRssi = Integer.MIN_VALUE;\n var gatewayInfo = {};\n \n foreach (gateway : gatewayList) {\n if(gateway.rssi > maxRssi) {\n maxRssi = gateway.rssi;\n gatewayInfo = gateway;\n }\n }\n \n return gatewayInfo;\n}\n\nfunction processTelemetryData(telemetry, addDataToTelemetry) {\n if (telemetry.size >= 1) {\n telemetry = addDataToTelemetries(telemetry, addDataToTelemetry);\n }\n else {\n telemetry.add(addDataToTelemetry);\n }\n \n return telemetry;\n}\n\nfunction addDataToTelemetries(telemetries, addDataToTelemetry) {\n foreach(telemetry : telemetries) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[\"values\"].keys.contains(element.key)) {\n telemetry[\"values\"][element.key] = element.value;\n }\n } \n }\n \n return telemetries;\n}", + "encoder": null, + "tbelEncoder": null, + "updateOnlyKeys": [ + "fPort", + "applicationName", + "frequency", + "bandwidth", + "spreadingFactor", + "codeRate" + ] + }, + "additionalInfo": { + "description": "" + }, + "edgeTemplate": false +} \ No newline at end of file diff --git a/VENDORS/Milesight/AM308/HTTP/uplink/metadata.json b/VENDORS/Milesight/AM308/HTTP/uplink/metadata.json new file mode 100644 index 00000000..87ee6615 --- /dev/null +++ b/VENDORS/Milesight/AM308/HTTP/uplink/metadata.json @@ -0,0 +1,4 @@ +{ + "integrationName": "HTTP integration", + "includeGatewayInfo": "false" +} \ No newline at end of file diff --git a/VENDORS/Milesight/AM308/HTTP/uplink/payload.json b/VENDORS/Milesight/AM308/HTTP/uplink/payload.json new file mode 100644 index 00000000..aa80cdcc --- /dev/null +++ b/VENDORS/Milesight/AM308/HTTP/uplink/payload.json @@ -0,0 +1,31 @@ +{ + "applicationID": 1, + "applicationName": "cloud", + "deviceName": "24e1641092176759", + "devEUI": "24e1641092176759", + "time": "2020-0327T12:39:05.547336Z", + "rxInfo": [ + { + "mac": "24e124fffef021be", + "rssi": -57, + "loRaSNR": 10, + "name": "local_gateway", + "latitude": 0, + "longitude": 0, + "altitude": 0 + } + ], + "txInfo": { + "frequency": 868300000, + "dataRate": { + "modulation": "LORA", + "bandwidth": 125, + "spreadFactor": 7 + }, + "adr": false, + "codeRate": "4/5" + }, + "fCnt": 0, + "fPort": 85, + "data": "AXVVA2fuAARofAUAAQbLAgd9qAMIfSUACXNmJwp9BAALfSAADH0wAA19IAAOAVUgzmU1ygwA4QBuAWQBwgAKJ5cAGQAy" +} \ No newline at end of file diff --git a/VENDORS/Milesight/AM308/HTTP/uplink/result.json b/VENDORS/Milesight/AM308/HTTP/uplink/result.json new file mode 100644 index 00000000..b7d5a1e8 --- /dev/null +++ b/VENDORS/Milesight/AM308/HTTP/uplink/result.json @@ -0,0 +1,41 @@ +{ + "deviceName": "AM308 24e1641092176759", + "deviceType": "AM308", + "attributes": { + "fPort": 85, + "applicationName": "cloud", + "frequency": 868300000, + "bandwidth": 125, + "spreadingFactor": 7, + "codeRate": "4/5" + }, + "telemetry": [{ + "ts": 1585312745547, + "values": { + "battery": 85, + "temperature": 23.8, + "humidity": 62.0, + "pir": "trigger", + "light_level": 2, + "co2": 936, + "tvoc": 37, + "pressure": 1008.6, + "pm2_5": 32, + "pm10": 48, + "beep": "no" + } + }, { + "ts": 214578533000, + "values": { + "temperature": 5760.0, + "humidity": 14080.0, + "trigger": "idle", + "light_level": 100, + "co2": 49665, + "tvoc": 2560, + "pressure": 3869.5, + "pm2_5": 6400, + "pm10": 12800 + } + }] +} \ No newline at end of file diff --git a/VENDORS/Milesight/AM308L/HTTP/uplink/converter.json b/VENDORS/Milesight/AM308L/HTTP/uplink/converter.json new file mode 100644 index 00000000..2a49dd3a --- /dev/null +++ b/VENDORS/Milesight/AM308L/HTTP/uplink/converter.json @@ -0,0 +1,29 @@ +{ + "name": "HTTP Uplink integration for AM308L", + "type": "UPLINK", + "debugMode": false, + "debugSettings": { + "failuresEnabled": true, + "allEnabled": false, + "allEnabledUntil": 1735560006385 + }, + "configuration": { + "scriptLang": "TBEL", + "decoder": null, + "tbelDecoder": "var data = decodeToJson(payload);\nvar deviceName = \"AM308L \" + data.devEUI;\nvar deviceType = \"AM308L\";\nvar groupName = null; // If groupName is not null - created device will be added to the entity group with such name.\nvar customerName = null; // If customerName is not null - created devices will be assigned to customer with such name. \n\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// If you want to parse incoming data somehow, you can add your code to this function.\n// input: bytes\n// expected output:\n// {\n// \"attributes\": {\"attributeKey\": \"attributeValue\"},\n// \"telemetry\": [{\"ts\": 1...1, \"values\": {\"telemetryKey\":\"telemetryValue\"}, {\"ts\": 1...2, \"values\": {\"telemetryKey\":\"telemetryValue\"}}]\n// }\n\nfunction decodePayload(input) {\n var output = {\n attributes: {},\n telemetry: []\n };\n \n // --- Decoding code --- //\n var decoded = {};\n var fPort = data.fPort;\n var historyDataList = [];\n if(fPort == 85) {\n for (var i = 0; i < input.length - 2;) {\n var channel_id = input[i++] & 0xff;\n var channel_type = input[i++] & 0xff;\n // BATTERY\n if (channel_id === 0x01 && channel_type === 0x75) {\n decoded.battery = input[i];\n i += 1;\n }\n // TEMPERATURE\n if (channel_id === 0x03 && channel_type === 0x67) {\n // ℃\n decoded.temperature = parseBytesToInt(input, i,\n 2, false) / 10;\n i += 2;\n // ℉\n // decoded.temperature = parseBytesToInt(input, i, 2, false) / 10 * 1.8 + 32;\n // i +=2;\n }\n // HUMIDITY\n if (channel_id === 0x04 && channel_type === 0x68) {\n decoded.humidity = parseBytesToInt(input, i, 1, false) / 2;\n i += 1;\n }\n // PIR\n if (channel_id === 0x05 && channel_type === 0x00) {\n decoded.pir = input[i] === 1 ? \"trigger\" :\n \"idle\";\n i += 1;\n }\n // LIGHT\n if (channel_id === 0x06 && channel_type === 0xCB) {\n decoded.light_level = input[i];\n i += 1;\n }\n // CO2\n if (channel_id === 0x07 && channel_type === 0x7D) {\n decoded.co2 = parseBytesToInt(input, i, 2,\n false);\n i += 2;\n }\n // TVOC\n if (channel_id === 0x08 && channel_type === 0x7D) {\n decoded.tvoc = parseBytesToInt(input, i, 2,\n false);\n i += 2;\n }\n // PRESSURE\n if (channel_id === 0x09 && channel_type === 0x73) {\n decoded.pressure = parseBytesToInt(input, i, 2,\n false) / 10;\n i += 2;\n }\n // PM2.5\n if (channel_id === 0x0B && channel_type === 0x7D) {\n decoded.pm2_5 = parseBytesToInt(input, i, 2,\n false);\n i += 2;\n }\n // PM10\n if (channel_id === 0x0C && channel_type === 0x7D) {\n decoded.pm10 = parseBytesToInt(input, i, 2,\n false);\n i += 2;\n }\n // BEEP\n if (channel_id === 0x0E && channel_type === 0x01) {\n decoded.beep = input[i] === 1 ? \"yes\" : \"no\";\n i += 1;\n }\n // HISTORY DATA\n if (channel_id === 0x20 && channel_type === 0xCE) {\n var historyData = {\n ts: parseBytesToInt(input, i, 4, false) * 1000,\n values: {\n temperature: parseBytesToInt(input, i + 4, 2, false) / 10,\n humidity: parseBytesToInt(input, i + 6, 2, false) / 2,\n pir: input[i + 8] === 1 ? \"trigger\" : \"idle\",\n light_level: input[i + 9],\n co2: parseBytesToInt(input, i + 10, 2, false),\n tvoc: parseBytesToInt(input, i + 12, 2, false),\n pressure: parseBytesToInt(input, i + 14, 2, false) / 10,\n pm2_5: parseBytesToInt(input, i + 16, 2, false),\n pm10: parseBytesToInt(input, i + 18, 2, false)\n }\n };\n \n historyDataList.add(historyData);\n \n i += 20;\n }\n }\n }\n\n output.telemetry = [{\n ts: timestamp,\n values: decoded\n }];\n \n output.telemetry.addAll(historyDataList);\n \n // --- Decoding code --- //\n return output;\n}\n\n// --- attributes and telemetry objects ---\nvar telemetry = [];\nvar attributes = {};\n// --- attributes and telemetry objects ---\n\n// --- Timestamp parsing\nvar dateString = data.time;\ntimestamp = parseDateToTimestamp(dateString);\n// --- Timestamp parsing\n\n// Passing incoming bytes to decodePayload function, to get custom decoding\nvar customDecoding = decodePayload(base64ToBytes(data.data));\n\n// Collecting data to result\nif (customDecoding.?telemetry.size() > 0) {\n foreach(telemetryObj: customDecoding.telemetry) {\n if (telemetryObj.ts != null && telemetryObj.values != null) {\n telemetry.add(telemetryObj);\n }\n }\n}\n\nif (customDecoding.?attributes.size() > 0) {\n attributes.putAll(customDecoding.attributes);\n}\n\n// You can add some keys manually to attributes or telemetry\nattributes.eui = data.?devEui;\nattributes.fPort = data.fPort;\nattributes.applicationId = data.?applicationId;\nattributes.applicationName = data.?applicationName;\nattributes.frequency = data.txInfo.?frequency;\nattributes.bandwidth = data.txInfo.?dataRate.?bandwidth;\nattributes.spreadingFactor = data.txInfo.?dataRate.?spreadFactor;\nattributes.codeRate = data.txInfo.?codeRate;\n\nif(Boolean.parseBoolean(metadata[\"includeGatewayInfo\"])) {\n var gatewayInfo = getGatewayInfo();\n var addDataToTelemetry = {};\n addDataToTelemetry.snr = gatewayInfo.?loRaSNR;\n addDataToTelemetry.rssi = gatewayInfo.rssi;\n addDataToTelemetry.fCnt = data.fCnt;\n \n telemetry = processTelemetryData(telemetry, addDataToTelemetry);\n}\n\nvar result = {\n deviceName: deviceName,\n deviceType: deviceType,\n // assetName: assetName,\n // assetType: assetType,\n attributes: attributes,\n telemetry: telemetry\n};\n\naddAdditionalInfoForDeviceMsg(result, customerName, groupName);\n\nreturn result;\n\nfunction addAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName) {\n if (customerName != null) {\n deviceInfo.customerName = customerName;\n }\n if (groupName != null) {\n deviceInfo.groupName = groupName;\n }\n}\n\nfunction parseDateToTimestamp(dateString) {\n dateString = dateString.replaceFirst(\"(\\\\d{4}-\\\\d{2})(\\\\d{2})\", \"$1-$2\");\n dateString = dateString.replaceFirst(\"\\\\.(\\\\d{3})\\\\d+Z\", \".$1Z\");\n dateString = dateString.replace(\"Z\", \"+0000\");\n var date = new Date(dateString);\n var timestamp = date.getTime();\n \n // If we cannot parse timestamp - we will use the current timestamp\n if (timestamp == -1) {\n timestamp = Date.now();\n }\n \n return timestamp;\n}\n\nfunction getGatewayInfo() {\n var gatewayList = data.rxInfo;\n var maxRssi = Integer.MIN_VALUE;\n var gatewayInfo = {};\n \n foreach (gateway : gatewayList) {\n if(gateway.rssi > maxRssi) {\n maxRssi = gateway.rssi;\n gatewayInfo = gateway;\n }\n }\n \n return gatewayInfo;\n}\n\nfunction processTelemetryData(telemetry, addDataToTelemetry) {\n if (telemetry.size >= 1) {\n telemetry = addDataToTelemetries(telemetry, addDataToTelemetry);\n }\n else {\n telemetry.add(addDataToTelemetry);\n }\n \n return telemetry;\n}\n\nfunction addDataToTelemetries(telemetries, addDataToTelemetry) {\n foreach(telemetry : telemetries) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[\"values\"].keys.contains(element.key)) {\n telemetry[\"values\"][element.key] = element.value;\n }\n } \n }\n \n return telemetries;\n}", + "encoder": null, + "tbelEncoder": null, + "updateOnlyKeys": [ + "fPort", + "applicationName", + "frequency", + "bandwidth", + "spreadingFactor", + "codeRate" + ] + }, + "additionalInfo": { + "description": "" + }, + "edgeTemplate": false +} \ No newline at end of file diff --git a/VENDORS/Milesight/AM308L/HTTP/uplink/metadata.json b/VENDORS/Milesight/AM308L/HTTP/uplink/metadata.json new file mode 100644 index 00000000..87ee6615 --- /dev/null +++ b/VENDORS/Milesight/AM308L/HTTP/uplink/metadata.json @@ -0,0 +1,4 @@ +{ + "integrationName": "HTTP integration", + "includeGatewayInfo": "false" +} \ No newline at end of file diff --git a/VENDORS/Milesight/AM308L/HTTP/uplink/payload.json b/VENDORS/Milesight/AM308L/HTTP/uplink/payload.json new file mode 100644 index 00000000..aa80cdcc --- /dev/null +++ b/VENDORS/Milesight/AM308L/HTTP/uplink/payload.json @@ -0,0 +1,31 @@ +{ + "applicationID": 1, + "applicationName": "cloud", + "deviceName": "24e1641092176759", + "devEUI": "24e1641092176759", + "time": "2020-0327T12:39:05.547336Z", + "rxInfo": [ + { + "mac": "24e124fffef021be", + "rssi": -57, + "loRaSNR": 10, + "name": "local_gateway", + "latitude": 0, + "longitude": 0, + "altitude": 0 + } + ], + "txInfo": { + "frequency": 868300000, + "dataRate": { + "modulation": "LORA", + "bandwidth": 125, + "spreadFactor": 7 + }, + "adr": false, + "codeRate": "4/5" + }, + "fCnt": 0, + "fPort": 85, + "data": "AXVVA2fuAARofAUAAQbLAgd9qAMIfSUACXNmJwp9BAALfSAADH0wAA19IAAOAVUgzmU1ygwA4QBuAWQBwgAKJ5cAGQAy" +} \ No newline at end of file diff --git a/VENDORS/Milesight/AM308L/HTTP/uplink/result.json b/VENDORS/Milesight/AM308L/HTTP/uplink/result.json new file mode 100644 index 00000000..3499c5b0 --- /dev/null +++ b/VENDORS/Milesight/AM308L/HTTP/uplink/result.json @@ -0,0 +1,41 @@ +{ + "deviceName": "AM308L 24e1641092176759", + "deviceType": "AM308L", + "attributes": { + "fPort": 85, + "applicationName": "cloud", + "frequency": 868300000, + "bandwidth": 125, + "spreadingFactor": 7, + "codeRate": "4/5" + }, + "telemetry": [{ + "ts": 1585312745547, + "values": { + "battery": 85, + "temperature": 23.8, + "humidity": 62.0, + "pir": "trigger", + "light_level": 2, + "co2": 936, + "tvoc": 37, + "pressure": 1008.6, + "pm2_5": 32, + "pm10": 48, + "beep": "no" + } + }, { + "ts": 214578533000, + "values": { + "temperature": 5760.0, + "humidity": 14080.0, + "trigger": "idle", + "light_level": 100, + "co2": 49665, + "tvoc": 2560, + "pressure": 3869.5, + "pm2_5": 6400, + "pm10": 12800 + } + }] +} \ No newline at end of file diff --git a/VENDORS/Milesight/AM319/HTTP/uplink/converter.json b/VENDORS/Milesight/AM319/HTTP/uplink/converter.json new file mode 100644 index 00000000..7f1a17e0 --- /dev/null +++ b/VENDORS/Milesight/AM319/HTTP/uplink/converter.json @@ -0,0 +1,29 @@ +{ + "name": "HTTP Uplink integration for AM319", + "type": "UPLINK", + "debugMode": false, + "debugSettings": { + "failuresEnabled": true, + "allEnabled": false, + "allEnabledUntil": 1735560006385 + }, + "configuration": { + "scriptLang": "TBEL", + "decoder": null, + "tbelDecoder": "var data = decodeToJson(payload);\nvar deviceName = \"AM319 \" + data.devEUI;\nvar deviceType = \"AM319\";\nvar groupName = null; // If groupName is not null - created device will be added to the entity group with such name.\nvar customerName = null; // If customerName is not null - created devices will be assigned to customer with such name. \n\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// If you want to parse incoming data somehow, you can add your code to this function.\n// input: bytes\n// expected output:\n// {\n// \"attributes\": {\"attributeKey\": \"attributeValue\"},\n// \"telemetry\": [{\"ts\": 1...1, \"values\": {\"telemetryKey\":\"telemetryValue\"}, {\"ts\": 1...2, \"values\": {\"telemetryKey\":\"telemetryValue\"}}]\n// }\n\nfunction decodePayload(input) {\n var output = {\n attributes: {},\n telemetry: []\n };\n \n // --- Decoding code --- //\n var decoded = {};\n var fPort = data.fPort;\n var historyDataList = [];\n if(fPort == 85) {\n for (var i = 0; i < input.length - 2;) {\n var channel_id = input[i++] & 0xff;\n var channel_type = input[i++] & 0xff;\n \n // BATTERY\n if (channel_id === 0x01 && channel_type === 0x75) {\n decoded.battery = input[i];\n i += 1;\n }\n // TEMPERATURE\n if (channel_id === 0x03 && channel_type === 0x67) {\n // ℃\n decoded.temperature = parseBytesToInt(input, i,\n 2, false) / 10;\n i += 2;\n // ℉\n // decoded.temperature = parseBytesToInt(input, i, 2, false) / 10 * 1.8 + 32;\n // i +=2;\n }\n // HUMIDITY\n if (channel_id === 0x04 && channel_type === 0x68) {\n decoded.humidity = parseBytesToInt(input, i, 1, false) / 2;\n i += 1;\n }\n // PIR\n if (channel_id === 0x05 && channel_type === 0x00) {\n decoded.pir = input[i] === 1 ? \"trigger\" :\n \"idle\";\n i += 1;\n }\n // LIGHT\n if (channel_id === 0x06 && channel_type === 0xCB) {\n decoded.light_level = input[i];\n i += 1;\n }\n // CO2\n if (channel_id === 0x07 && channel_type === 0x7D) {\n decoded.co2 = parseBytesToInt(input, i, 2,\n false);\n i += 2;\n }\n // TVOC\n if (channel_id === 0x08 && channel_type === 0x7D) {\n decoded.tvoc = parseBytesToInt(input, i, 2,\n false);\n i += 2;\n }\n // PRESSURE\n if (channel_id === 0x09 && channel_type === 0x73) {\n decoded.pressure = parseBytesToInt(input, i, 2,\n false) / 10;\n i += 2;\n }\n // HCHO\n if (channel_id === 0x0a && channel_type === 0x7d) {\n decoded.hcho = parseBytesToInt(input, i, 2, false) / 100;\n i += 2;\n }\n // PM2.5\n if (channel_id === 0x0b && channel_type === 0x7d) {\n decoded.pm2_5 = parseBytesToInt(input, i, 2, false);\n i += 2;\n }\n // PM10\n if (channel_id === 0x0c && channel_type === 0x7d) {\n decoded.pm10 = parseBytesToInt(input, i, 2, false);\n i += 2;\n }\n // O3\n if (channel_id === 0x0d && channel_type === 0x7d) {\n decoded.o3 = parseBytesToInt(input, i, 2, false) / 100;\n i += 2;\n }\n // BEEP\n if (channel_id === 0x0E && channel_type === 0x01) {\n decoded.beep = input[i] === 1 ? \"yes\" : \"no\";\n i += 1;\n }\n \n // HISTORY DATA (CH2O)\n if (channel_id === 0x20 && channel_type === 0xCE) {\n var historyData = {\n ts: parseBytesToInt(input, i, 4, false) * 1000,\n values: {\n temperature: parseBytesToInt(input, i + 4, 2, false) / 10,\n humidity: parseBytesToInt(input, i + 6, 2, false) / 2,\n pir: input[i + 8] === 1 ? \"trigger\" : \"idle\",\n light_level: input[i + 9],\n co2: parseBytesToInt(input, i + 10, 2, false),\n tvoc: parseBytesToInt(input, i + 12, 2, false),\n pressure: parseBytesToInt(input, i + 14, 2, false) / 10,\n pm2_5: parseBytesToInt(input, i + 16, 2, false),\n pm10: parseBytesToInt(input, i + 18, 2, false),\n hcho: parseBytesToInt(input, i + 20, 2, false) / 100\n }\n };\n \n historyDataList.add(historyData);\n i += 22;\n }\n \n // HISTORY DATA (O3)\n /*if (channel_id === 0x20 && channel_type === 0xCE) {\n var historyData = {\n ts: parseBytesToInt(input, i, 4, false) * 1000,\n values: {\n temperature: parseBytesToInt(input, i + 4, 2, false) / 10,\n humidity: parseBytesToInt(input, i + 6, 2, false) / 2,\n pir: input[i + 8] === 1 ? \"trigger\" : \"idle\",\n light_level: input[i + 9],\n co2: parseBytesToInt(input, i + 10, 2, false),\n tvoc: parseBytesToInt(input, i + 12, 2, false),\n pressure: parseBytesToInt(input, i + 14, 2, false) / 10,\n pm2_5: parseBytesToInt(input, i + 16, 2, false),\n pm10: parseBytesToInt(input, i + 18, 2, false),\n o3: parseBytesToInt(input, i + 20, 2, false) / 100\n }\n };\n \n historyDataList.add(historyData);\n i += 22;\n }*/\n }\n }\n\n output.telemetry = [{\n ts: timestamp,\n values: decoded\n }];\n \n output.telemetry.addAll(historyDataList);\n \n // --- Decoding code --- //\n return output;\n}\n\n// --- attributes and telemetry objects ---\nvar telemetry = [];\nvar attributes = {};\n// --- attributes and telemetry objects ---\n\n// --- Timestamp parsing\nvar dateString = data.time;\ntimestamp = parseDateToTimestamp(dateString);\n// --- Timestamp parsing\n\n// Passing incoming bytes to decodePayload function, to get custom decoding\nvar customDecoding = decodePayload(base64ToBytes(data.data));\n\n// Collecting data to result\nif (customDecoding.?telemetry.size() > 0) {\n foreach(telemetryObj: customDecoding.telemetry) {\n if (telemetryObj.ts != null && telemetryObj.values != null) {\n telemetry.add(telemetryObj);\n }\n }\n}\n\nif (customDecoding.?attributes.size() > 0) {\n attributes.putAll(customDecoding.attributes);\n}\n\n// You can add some keys manually to attributes or telemetry\nattributes.eui = data.?devEui;\nattributes.fPort = data.fPort;\nattributes.applicationId = data.?applicationId;\nattributes.applicationName = data.?applicationName;\nattributes.frequency = data.txInfo.?frequency;\nattributes.bandwidth = data.txInfo.?dataRate.?bandwidth;\nattributes.spreadingFactor = data.txInfo.?dataRate.?spreadFactor;\nattributes.codeRate = data.txInfo.?codeRate;\n\nif(Boolean.parseBoolean(metadata[\"includeGatewayInfo\"])) {\n var gatewayInfo = getGatewayInfo();\n var addDataToTelemetry = {};\n addDataToTelemetry.snr = gatewayInfo.?loRaSNR;\n addDataToTelemetry.rssi = gatewayInfo.rssi;\n addDataToTelemetry.fCnt = data.fCnt;\n \n telemetry = processTelemetryData(telemetry, addDataToTelemetry);\n}\n\nvar result = {\n deviceName: deviceName,\n deviceType: deviceType,\n // assetName: assetName,\n // assetType: assetType,\n attributes: attributes,\n telemetry: telemetry\n};\n\naddAdditionalInfoForDeviceMsg(result, customerName, groupName);\n\nreturn result;\n\nfunction addAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName) {\n if (customerName != null) {\n deviceInfo.customerName = customerName;\n }\n if (groupName != null) {\n deviceInfo.groupName = groupName;\n }\n}\n\nfunction parseDateToTimestamp(dateString) {\n dateString = dateString.replaceFirst(\"(\\\\d{4}-\\\\d{2})(\\\\d{2})\", \"$1-$2\");\n dateString = dateString.replaceFirst(\"\\\\.(\\\\d{3})\\\\d+Z\", \".$1Z\");\n dateString = dateString.replace(\"Z\", \"+0000\");\n var date = new Date(dateString);\n var timestamp = date.getTime();\n \n // If we cannot parse timestamp - we will use the current timestamp\n if (timestamp == -1) {\n timestamp = Date.now();\n }\n \n return timestamp;\n}\n\nfunction getGatewayInfo() {\n var gatewayList = data.rxInfo;\n var maxRssi = Integer.MIN_VALUE;\n var gatewayInfo = {};\n \n foreach (gateway : gatewayList) {\n if(gateway.rssi > maxRssi) {\n maxRssi = gateway.rssi;\n gatewayInfo = gateway;\n }\n }\n \n return gatewayInfo;\n}\n\nfunction processTelemetryData(telemetry, addDataToTelemetry) {\n if (telemetry.size >= 1) {\n telemetry = addDataToTelemetries(telemetry, addDataToTelemetry);\n }\n else {\n telemetry.add(addDataToTelemetry);\n }\n \n return telemetry;\n}\n\nfunction addDataToTelemetries(telemetries, addDataToTelemetry) {\n foreach(telemetry : telemetries) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[\"values\"].keys.contains(element.key)) {\n telemetry[\"values\"][element.key] = element.value;\n }\n } \n }\n \n return telemetries;\n}", + "encoder": null, + "tbelEncoder": null, + "updateOnlyKeys": [ + "fPort", + "applicationName", + "frequency", + "bandwidth", + "spreadingFactor", + "codeRate" + ] + }, + "additionalInfo": { + "description": "" + }, + "edgeTemplate": false +} \ No newline at end of file diff --git a/VENDORS/Milesight/AM319/HTTP/uplink/metadata.json b/VENDORS/Milesight/AM319/HTTP/uplink/metadata.json new file mode 100644 index 00000000..87ee6615 --- /dev/null +++ b/VENDORS/Milesight/AM319/HTTP/uplink/metadata.json @@ -0,0 +1,4 @@ +{ + "integrationName": "HTTP integration", + "includeGatewayInfo": "false" +} \ No newline at end of file diff --git a/VENDORS/Milesight/AM319/HTTP/uplink/payload.json b/VENDORS/Milesight/AM319/HTTP/uplink/payload.json new file mode 100644 index 00000000..7e6e0ec1 --- /dev/null +++ b/VENDORS/Milesight/AM319/HTTP/uplink/payload.json @@ -0,0 +1,31 @@ +{ + "applicationID": 1, + "applicationName": "cloud", + "deviceName": "24e1641092176759", + "devEUI": "24e1641092176759", + "time": "2020-0327T12:39:05.547336Z", + "rxInfo": [ + { + "mac": "24e124fffef021be", + "rssi": -57, + "loRaSNR": 10, + "name": "local_gateway", + "latitude": 0, + "longitude": 0, + "altitude": 0 + } + ], + "txInfo": { + "frequency": 868300000, + "dataRate": { + "modulation": "LORA", + "bandwidth": 125, + "spreadFactor": 7 + }, + "adr": false, + "codeRate": "4/5" + }, + "fCnt": 0, + "fPort": 85, + "data": "AXVVA2fuAARofAUAAQbLAgd9qAMIfSUACXNmJwp9BAALfSAADH0wAA4BVSDOZTXKDADhAG4BZAHCAAonlwAZADIEAA==" +} \ No newline at end of file diff --git a/VENDORS/Milesight/AM319/HTTP/uplink/result.json b/VENDORS/Milesight/AM319/HTTP/uplink/result.json new file mode 100644 index 00000000..919cfb66 --- /dev/null +++ b/VENDORS/Milesight/AM319/HTTP/uplink/result.json @@ -0,0 +1,43 @@ +{ + "deviceName": "AM319 24e1641092176759", + "deviceType": "AM319", + "attributes": { + "fPort": 85, + "applicationName": "cloud", + "frequency": 868300000, + "bandwidth": 125, + "spreadingFactor": 7, + "codeRate": "4/5" + }, + "telemetry": [{ + "ts": 1585312745547, + "values": { + "battery": 85, + "temperature": 23.8, + "humidity": 62.0, + "pir": "trigger", + "light_level": 2, + "co2": 936, + "tvoc": 37, + "pressure": 1008.6, + "hcho": 0.04, + "pm2_5": 32, + "pm10": 48, + "beep": "no" + } + }, { + "ts": 214578533000, + "values": { + "temperature": 5760.0, + "humidity": 14080.0, + "trigger": "idle", + "light_level": 100, + "co2": 49665, + "tvoc": 2560, + "pressure": 3869.5, + "pm2_5": 6400, + "pm10": 12800, + "hcho": 0.04 + } + }] +} \ No newline at end of file diff --git a/VENDORS/Milesight/AM319L/HTTP/uplink/converter.json b/VENDORS/Milesight/AM319L/HTTP/uplink/converter.json new file mode 100644 index 00000000..6f4eb723 --- /dev/null +++ b/VENDORS/Milesight/AM319L/HTTP/uplink/converter.json @@ -0,0 +1,29 @@ +{ + "name": "HTTP Uplink integration for AM319L", + "type": "UPLINK", + "debugMode": false, + "debugSettings": { + "failuresEnabled": true, + "allEnabled": false, + "allEnabledUntil": 1735560006385 + }, + "configuration": { + "scriptLang": "TBEL", + "decoder": null, + "tbelDecoder": "var data = decodeToJson(payload);\nvar deviceName = \"AM319L \" + data.devEUI;\nvar deviceType = \"AM319L\";\nvar groupName = null; // If groupName is not null - created device will be added to the entity group with such name.\nvar customerName = null; // If customerName is not null - created devices will be assigned to customer with such name. \n\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// If you want to parse incoming data somehow, you can add your code to this function.\n// input: bytes\n// expected output:\n// {\n// \"attributes\": {\"attributeKey\": \"attributeValue\"},\n// \"telemetry\": [{\"ts\": 1...1, \"values\": {\"telemetryKey\":\"telemetryValue\"}, {\"ts\": 1...2, \"values\": {\"telemetryKey\":\"telemetryValue\"}}]\n// }\n\nfunction decodePayload(input) {\n var output = {\n attributes: {},\n telemetry: []\n };\n \n // --- Decoding code --- //\n var decoded = {};\n var fPort = data.fPort;\n var historyDataList = [];\n if(fPort == 85) {\n for (var i = 0; i < input.length - 2;) {\n var channel_id = input[i++] & 0xff;\n var channel_type = input[i++] & 0xff;\n \n // BATTERY\n if (channel_id === 0x01 && channel_type === 0x75) {\n decoded.battery = input[i];\n i += 1;\n }\n // TEMPERATURE\n if (channel_id === 0x03 && channel_type === 0x67) {\n // ℃\n decoded.temperature = parseBytesToInt(input, i,\n 2, false) / 10;\n i += 2;\n // ℉\n // decoded.temperature = parseBytesToInt(input, i, 2, false) / 10 * 1.8 + 32;\n // i +=2;\n }\n // HUMIDITY\n if (channel_id === 0x04 && channel_type === 0x68) {\n decoded.humidity = parseBytesToInt(input, i, 1, false) / 2;\n i += 1;\n }\n // PIR\n if (channel_id === 0x05 && channel_type === 0x00) {\n decoded.pir = input[i] === 1 ? \"trigger\" :\n \"idle\";\n i += 1;\n }\n // LIGHT\n if (channel_id === 0x06 && channel_type === 0xCB) {\n decoded.light_level = input[i];\n i += 1;\n }\n // CO2\n if (channel_id === 0x07 && channel_type === 0x7D) {\n decoded.co2 = parseBytesToInt(input, i, 2,\n false);\n i += 2;\n }\n // TVOC\n if (channel_id === 0x08 && channel_type === 0x7D) {\n decoded.tvoc = parseBytesToInt(input, i, 2,\n false);\n i += 2;\n }\n // PRESSURE\n if (channel_id === 0x09 && channel_type === 0x73) {\n decoded.pressure = parseBytesToInt(input, i, 2,\n false) / 10;\n i += 2;\n }\n // HCHO\n if (channel_id === 0x0a && channel_type === 0x7d) {\n decoded.hcho = parseBytesToInt(input, i, 2, false) / 100;\n i += 2;\n }\n // PM2.5\n if (channel_id === 0x0b && channel_type === 0x7d) {\n decoded.pm2_5 = parseBytesToInt(input, i, 2, false);\n i += 2;\n }\n // PM10\n if (channel_id === 0x0c && channel_type === 0x7d) {\n decoded.pm10 = parseBytesToInt(input, i, 2, false);\n i += 2;\n }\n // O3\n if (channel_id === 0x0d && channel_type === 0x7d) {\n decoded.o3 = parseBytesToInt(input, i, 2, false) / 100;\n i += 2;\n }\n // BEEP\n if (channel_id === 0x0E && channel_type === 0x01) {\n decoded.beep = input[i] === 1 ? \"yes\" : \"no\";\n i += 1;\n }\n \n // HISTORY DATA (CH2O)\n if (channel_id === 0x20 && channel_type === 0xCE) {\n var historyData = {\n ts: parseBytesToInt(input, i, 4, false) * 1000,\n values: {\n temperature: parseBytesToInt(input, i + 4, 2, false) / 10,\n humidity: parseBytesToInt(input, i + 6, 2, false) / 2,\n pir: input[i + 8] === 1 ? \"trigger\" : \"idle\",\n light_level: input[i + 9],\n co2: parseBytesToInt(input, i + 10, 2, false),\n tvoc: parseBytesToInt(input, i + 12, 2, false),\n pressure: parseBytesToInt(input, i + 14, 2, false) / 10,\n pm2_5: parseBytesToInt(input, i + 16, 2, false),\n pm10: parseBytesToInt(input, i + 18, 2, false),\n hcho: parseBytesToInt(input, i + 20, 2, false) / 100\n }\n };\n \n historyDataList.add(historyData);\n i += 22;\n }\n \n // HISTORY DATA (O3)\n /*if (channel_id === 0x20 && channel_type === 0xCE) {\n var historyData = {\n ts: parseBytesToInt(input, i, 4, false) * 1000,\n values: {\n temperature: parseBytesToInt(input, i + 4, 2, false) / 10,\n humidity: parseBytesToInt(input, i + 6, 2, false) / 2,\n pir: input[i + 8] === 1 ? \"trigger\" : \"idle\",\n light_level: input[i + 9],\n co2: parseBytesToInt(input, i + 10, 2, false),\n tvoc: parseBytesToInt(input, i + 12, 2, false),\n pressure: parseBytesToInt(input, i + 14, 2, false) / 10,\n pm2_5: parseBytesToInt(input, i + 16, 2, false),\n pm10: parseBytesToInt(input, i + 18, 2, false),\n o3: parseBytesToInt(input, i + 20, 2, false) / 100\n }\n };\n \n historyDataList.add(historyData);\n i += 22;\n }*/\n }\n }\n\n output.telemetry = [{\n ts: timestamp,\n values: decoded\n }];\n \n output.telemetry.addAll(historyDataList);\n \n // --- Decoding code --- //\n return output;\n}\n\n// --- attributes and telemetry objects ---\nvar telemetry = [];\nvar attributes = {};\n// --- attributes and telemetry objects ---\n\n// --- Timestamp parsing\nvar dateString = data.time;\ntimestamp = parseDateToTimestamp(dateString);\n// --- Timestamp parsing\n\n// Passing incoming bytes to decodePayload function, to get custom decoding\nvar customDecoding = decodePayload(base64ToBytes(data.data));\n\n// Collecting data to result\nif (customDecoding.?telemetry.size() > 0) {\n foreach(telemetryObj: customDecoding.telemetry) {\n if (telemetryObj.ts != null && telemetryObj.values != null) {\n telemetry.add(telemetryObj);\n }\n }\n}\n\nif (customDecoding.?attributes.size() > 0) {\n attributes.putAll(customDecoding.attributes);\n}\n\n// You can add some keys manually to attributes or telemetry\nattributes.eui = data.?devEui;\nattributes.fPort = data.fPort;\nattributes.applicationId = data.?applicationId;\nattributes.applicationName = data.?applicationName;\nattributes.frequency = data.txInfo.?frequency;\nattributes.bandwidth = data.txInfo.?dataRate.?bandwidth;\nattributes.spreadingFactor = data.txInfo.?dataRate.?spreadFactor;\nattributes.codeRate = data.txInfo.?codeRate;\n\nif(Boolean.parseBoolean(metadata[\"includeGatewayInfo\"])) {\n var gatewayInfo = getGatewayInfo();\n var addDataToTelemetry = {};\n addDataToTelemetry.snr = gatewayInfo.?loRaSNR;\n addDataToTelemetry.rssi = gatewayInfo.rssi;\n addDataToTelemetry.fCnt = data.fCnt;\n \n telemetry = processTelemetryData(telemetry, addDataToTelemetry);\n}\n\nvar result = {\n deviceName: deviceName,\n deviceType: deviceType,\n // assetName: assetName,\n // assetType: assetType,\n attributes: attributes,\n telemetry: telemetry\n};\n\naddAdditionalInfoForDeviceMsg(result, customerName, groupName);\n\nreturn result;\n\nfunction addAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName) {\n if (customerName != null) {\n deviceInfo.customerName = customerName;\n }\n if (groupName != null) {\n deviceInfo.groupName = groupName;\n }\n}\n\nfunction parseDateToTimestamp(dateString) {\n dateString = dateString.replaceFirst(\"(\\\\d{4}-\\\\d{2})(\\\\d{2})\", \"$1-$2\");\n dateString = dateString.replaceFirst(\"\\\\.(\\\\d{3})\\\\d+Z\", \".$1Z\");\n dateString = dateString.replace(\"Z\", \"+0000\");\n var date = new Date(dateString);\n var timestamp = date.getTime();\n \n // If we cannot parse timestamp - we will use the current timestamp\n if (timestamp == -1) {\n timestamp = Date.now();\n }\n \n return timestamp;\n}\n\nfunction getGatewayInfo() {\n var gatewayList = data.rxInfo;\n var maxRssi = Integer.MIN_VALUE;\n var gatewayInfo = {};\n \n foreach (gateway : gatewayList) {\n if(gateway.rssi > maxRssi) {\n maxRssi = gateway.rssi;\n gatewayInfo = gateway;\n }\n }\n \n return gatewayInfo;\n}\n\nfunction processTelemetryData(telemetry, addDataToTelemetry) {\n if (telemetry.size >= 1) {\n telemetry = addDataToTelemetries(telemetry, addDataToTelemetry);\n }\n else {\n telemetry.add(addDataToTelemetry);\n }\n \n return telemetry;\n}\n\nfunction addDataToTelemetries(telemetries, addDataToTelemetry) {\n foreach(telemetry : telemetries) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[\"values\"].keys.contains(element.key)) {\n telemetry[\"values\"][element.key] = element.value;\n }\n } \n }\n \n return telemetries;\n}", + "encoder": null, + "tbelEncoder": null, + "updateOnlyKeys": [ + "fPort", + "applicationName", + "frequency", + "bandwidth", + "spreadingFactor", + "codeRate" + ] + }, + "additionalInfo": { + "description": "" + }, + "edgeTemplate": false +} \ No newline at end of file diff --git a/VENDORS/Milesight/AM319L/HTTP/uplink/metadata.json b/VENDORS/Milesight/AM319L/HTTP/uplink/metadata.json new file mode 100644 index 00000000..87ee6615 --- /dev/null +++ b/VENDORS/Milesight/AM319L/HTTP/uplink/metadata.json @@ -0,0 +1,4 @@ +{ + "integrationName": "HTTP integration", + "includeGatewayInfo": "false" +} \ No newline at end of file diff --git a/VENDORS/Milesight/AM319L/HTTP/uplink/payload.json b/VENDORS/Milesight/AM319L/HTTP/uplink/payload.json new file mode 100644 index 00000000..7e6e0ec1 --- /dev/null +++ b/VENDORS/Milesight/AM319L/HTTP/uplink/payload.json @@ -0,0 +1,31 @@ +{ + "applicationID": 1, + "applicationName": "cloud", + "deviceName": "24e1641092176759", + "devEUI": "24e1641092176759", + "time": "2020-0327T12:39:05.547336Z", + "rxInfo": [ + { + "mac": "24e124fffef021be", + "rssi": -57, + "loRaSNR": 10, + "name": "local_gateway", + "latitude": 0, + "longitude": 0, + "altitude": 0 + } + ], + "txInfo": { + "frequency": 868300000, + "dataRate": { + "modulation": "LORA", + "bandwidth": 125, + "spreadFactor": 7 + }, + "adr": false, + "codeRate": "4/5" + }, + "fCnt": 0, + "fPort": 85, + "data": "AXVVA2fuAARofAUAAQbLAgd9qAMIfSUACXNmJwp9BAALfSAADH0wAA4BVSDOZTXKDADhAG4BZAHCAAonlwAZADIEAA==" +} \ No newline at end of file diff --git a/VENDORS/Milesight/AM319L/HTTP/uplink/result.json b/VENDORS/Milesight/AM319L/HTTP/uplink/result.json new file mode 100644 index 00000000..8a223814 --- /dev/null +++ b/VENDORS/Milesight/AM319L/HTTP/uplink/result.json @@ -0,0 +1,43 @@ +{ + "deviceName": "AM319L 24e1641092176759", + "deviceType": "AM319L", + "attributes": { + "fPort": 85, + "applicationName": "cloud", + "frequency": 868300000, + "bandwidth": 125, + "spreadingFactor": 7, + "codeRate": "4/5" + }, + "telemetry": [{ + "ts": 1585312745547, + "values": { + "battery": 85, + "temperature": 23.8, + "humidity": 62.0, + "pir": "trigger", + "light_level": 2, + "co2": 936, + "tvoc": 37, + "pressure": 1008.6, + "hcho": 0.04, + "pm2_5": 32, + "pm10": 48, + "beep": "no" + } + }, { + "ts": 214578533000, + "values": { + "temperature": 5760.0, + "humidity": 14080.0, + "trigger": "idle", + "light_level": 100, + "co2": 49665, + "tvoc": 2560, + "pressure": 3869.5, + "pm2_5": 6400, + "pm10": 12800, + "hcho": 0.04 + } + }] +} \ No newline at end of file diff --git a/VENDORS/Milesight/AT101/HTTP/uplink/converter.json b/VENDORS/Milesight/AT101/HTTP/uplink/converter.json new file mode 100644 index 00000000..edcee7d4 --- /dev/null +++ b/VENDORS/Milesight/AT101/HTTP/uplink/converter.json @@ -0,0 +1,29 @@ +{ + "name": "HTTP Uplink integration for AT101", + "type": "UPLINK", + "debugMode": false, + "debugSettings": { + "failuresEnabled": true, + "allEnabled": false, + "allEnabledUntil": 1735560006385 + }, + "configuration": { + "scriptLang": "TBEL", + "decoder": null, + "tbelDecoder": "var data = decodeToJson(payload);\nvar deviceName = \"AT101 \" + data.devEUI;\nvar deviceType = \"AT101\";\nvar groupName = null; // If groupName is not null - created device will be added to the entity group with such name.\nvar customerName = null; // If customerName is not null - created devices will be assigned to customer with such name. \n\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// If you want to parse incoming data somehow, you can add your code to this function.\n// input: bytes\n// expected output:\n// {\n// \"attributes\": {\"attributeKey\": \"attributeValue\"},\n// \"telemetry\": [{\"ts\": 1...1, \"values\": {\"telemetryKey\":\"telemetryValue\"}, {\"ts\": 1...2, \"values\": {\"telemetryKey\":\"telemetryValue\"}}]\n// }\n\nfunction decodePayload(input) {\n var output = {\n attributes: {},\n telemetry: []\n };\n \n // --- Decoding code --- //\n var decoded = {};\n var wifi = [];\n var fPort = data.fPort;\n var historyDataList = [];\n if(fPort == 85) {\n for (var i = 0; i < input.length - 2;) {\n var channel_id = input[i++] & 0xff;\n var channel_type = input[i++] & 0xff;\n // BATTERY\n if (channel_id === 0x01 && channel_type === 0x75) {\n decoded.battery = input[i];\n i += 1;\n }\n // TEMPERATURE\n if (channel_id === 0x03 && channel_type === 0x67) {\n // ℃\n decoded.temperature = parseBytesToInt(input, i,\n 2, false) / 10;\n i += 2;\n // ℉\n // decoded.temperature = parseBytesToInt(input, i, 2, false) / 10 * 1.8 + 32;\n // i +=2;\n }\n // Location\n if ((channel_id === 0x04 || channel_id == 0x84) && channel_type === 0x88) {\n decoded.latitude = parseBytesToInt(input, i, 4, false) / 1000000;\n decoded.longitude = parseBytesToInt(input, i+4, 4, false) / 1000000;\n var status = input[i+8];\n decoded.motion_status = getMotionStatus(status & 0x0f);\n decoded.geofence_status = getGeofenceStatus((status >> 4) & 0x0f);\n i +=9;\n }\n // Position\n if (channel_id === 0x05 && channel_type === 0x00) {\n decoded.position = input[i] === 0 ? \"normal\" : \"tilt\";\n i += 1;\n }\n // Wi-Fi SCAN RESULT\n if (channel_id === 0x06 && channel_type === 0xd9) {\n var wifiObject = {};\n wifiObject.group = input[i];\n var macBytes = java.util.Arrays.copyOfRange(input, i + 1, i + 7);\n wifiObject.mac = readMAC(macBytes);\n wifiObject.rssi = input[i+7];\n wifiObject.motion_status = getMotionStatus(input[i + 8] & 0x0f);\n i += 9;\n \n decoded.wifi_scan_result = \"finish\";\n if (wifiObject.mac === \"ff:ff:ff:ff:ff:ff\") {\n decoded.wifi_scan_result = \"timeout\";\n continue;\n }\n decoded.motion_status = wifiObject.motion_status;\n \n wifi.add(wifiObject);\n }\n //Tamper Status\n if (channel_id === 0x07 && channel_type === 0x00) {\n decoded.tamper_status = input[i] === 0 ? \"install\" : \"uninstall\";\n i +=1;\n }\n // TEMPERATURE WITH ABNORMAL\n if (channel_id === 0x83 && channel_type === 0x67) {\n decoded.temperature = parseBytesToInt(input, i, 2, false) / 10;\n decoded.temperature_abnormal = input[i + 2] == 0 ? false : true;\n i += 3;\n }\n // HISTORICAL DATA\n if (channel_id === 0x20 && channel_type === 0xce) {\n historyData = {\n ts : parseBytesToInt(input, i, 4, false),\n values : {\n longitude : parseBytesToInt(input, i + 4, 4, false) / 1000000,\n latitude : parseBytesToInt(input, i + 8, 4, false) / 1000000\n }\n };\n \n historyDataList.add(historyData);\n i += 12;\n } \n }\n \n decoded.wifi = wifi.size > 0 ? wifi : null;\n }\n\n output.telemetry = [{\n ts: timestamp,\n values: decoded\n }];\n \n output.telemetry.addAll(historyDataList);\n \n // --- Decoding code --- //\n return output;\n}\n\n// --- attributes and telemetry objects ---\nvar telemetry = [];\nvar attributes = {};\n// --- attributes and telemetry objects ---\n\n// --- Timestamp parsing\nvar dateString = data.time;\ntimestamp = parseDateToTimestamp(dateString);\n// --- Timestamp parsing\n\n// Passing incoming bytes to decodePayload function, to get custom decoding\nvar customDecoding = decodePayload(base64ToBytes(data.data));\n\n// Collecting data to result\nif (customDecoding.?telemetry.size() > 0) {\n foreach(telemetryObj: customDecoding.telemetry) {\n if (telemetryObj.ts != null && telemetryObj.values != null) {\n telemetry.add(telemetryObj);\n }\n }\n}\n\nif (customDecoding.?attributes.size() > 0) {\n attributes.putAll(customDecoding.attributes);\n}\n\n// You can add some keys manually to attributes or telemetry\nattributes.eui = data.?devEui;\nattributes.fPort = data.fPort;\nattributes.applicationId = data.?applicationId;\nattributes.applicationName = data.?applicationName;\nattributes.frequency = data.txInfo.?frequency;\nattributes.bandwidth = data.txInfo.?dataRate.?bandwidth;\nattributes.spreadingFactor = data.txInfo.?dataRate.?spreadFactor;\nattributes.codeRate = data.txInfo.?codeRate;\n\nif(Boolean.parseBoolean(metadata[\"includeGatewayInfo\"])) {\n var gatewayInfo = getGatewayInfo();\n var addDataToTelemetry = {};\n addDataToTelemetry.snr = gatewayInfo.?loRaSNR;\n addDataToTelemetry.rssi = gatewayInfo.rssi;\n addDataToTelemetry.fCnt = data.fCnt;\n \n telemetry = processTelemetryData(telemetry, addDataToTelemetry);\n}\n\nvar result = {\n deviceName: deviceName,\n deviceType: deviceType,\n // assetName: assetName,\n // assetType: assetType,\n attributes: attributes,\n telemetry: telemetry\n};\n\naddAdditionalInfoForDeviceMsg(result, customerName, groupName);\n\nreturn result;\n\nfunction addAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName) {\n if (customerName != null) {\n deviceInfo.customerName = customerName;\n }\n if (groupName != null) {\n deviceInfo.groupName = groupName;\n }\n}\n\nfunction parseDateToTimestamp(dateString) {\n dateString = dateString.replaceFirst(\"(\\\\d{4}-\\\\d{2})(\\\\d{2})\", \"$1-$2\");\n dateString = dateString.replaceFirst(\"\\\\.(\\\\d{3})\\\\d+Z\", \".$1Z\");\n dateString = dateString.replace(\"Z\", \"+0000\");\n var date = new Date(dateString);\n var timestamp = date.getTime();\n \n // If we cannot parse timestamp - we will use the current timestamp\n if (timestamp == -1) {\n timestamp = Date.now();\n }\n \n return timestamp;\n}\n\nfunction getGatewayInfo() {\n var gatewayList = data.rxInfo;\n var maxRssi = Integer.MIN_VALUE;\n var gatewayInfo = {};\n \n foreach (gateway : gatewayList) {\n if(gateway.rssi > maxRssi) {\n maxRssi = gateway.rssi;\n gatewayInfo = gateway;\n }\n }\n \n return gatewayInfo;\n}\n\nfunction processTelemetryData(telemetry, addDataToTelemetry) {\n if (telemetry.size >= 1) {\n telemetry = addDataToTelemetries(telemetry, addDataToTelemetry);\n }\n else {\n telemetry.add(addDataToTelemetry);\n }\n \n return telemetry;\n}\n\nfunction addDataToTelemetries(telemetries, addDataToTelemetry) {\n foreach(telemetry : telemetries) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[\"values\"].keys.contains(element.key)) {\n telemetry[\"values\"][element.key] = element.value;\n }\n } \n }\n \n return telemetries;\n}\n\nfunction getMotionStatus(status) {\n if(status == 0) {\n return \"unknown\";\n }\n else if (status == 1) {\n return \"start moving\";\n }\n else if (status == 2) {\n return \"moving\";\n }\n else {\n return \"stop moving\";\n }\n}\n\nfunction getGeofenceStatus(status) {\n if(status == 0) {\n return \"inside\";\n }\n else if (status == 1) {\n return \"outside\";\n }\n else if (status == 2) {\n return \"unset\";\n }\n else {\n return \"unknown\";\n }\n}\n\nfunction readMAC(bytes) {\n var temp = [];\n for (b : bytes) {\n temp.add(String.format(\"%02x\", b & 0xFF));\n }\n \n return String.join(\":\", temp);\n}", + "encoder": null, + "tbelEncoder": null, + "updateOnlyKeys": [ + "fPort", + "applicationName", + "frequency", + "bandwidth", + "spreadingFactor", + "codeRate" + ] + }, + "additionalInfo": { + "description": "" + }, + "edgeTemplate": false +} \ No newline at end of file diff --git a/VENDORS/Milesight/AT101/HTTP/uplink/metadata.json b/VENDORS/Milesight/AT101/HTTP/uplink/metadata.json new file mode 100644 index 00000000..87ee6615 --- /dev/null +++ b/VENDORS/Milesight/AT101/HTTP/uplink/metadata.json @@ -0,0 +1,4 @@ +{ + "integrationName": "HTTP integration", + "includeGatewayInfo": "false" +} \ No newline at end of file diff --git a/VENDORS/Milesight/AT101/HTTP/uplink/payload.json b/VENDORS/Milesight/AT101/HTTP/uplink/payload.json new file mode 100644 index 00000000..22b32fe3 --- /dev/null +++ b/VENDORS/Milesight/AT101/HTTP/uplink/payload.json @@ -0,0 +1,31 @@ +{ + "applicationID": 1, + "applicationName": "cloud", + "deviceName": "24e1641092176759", + "devEUI": "24e1641092176759", + "time": "2020-0327T12:39:05.547336Z", + "rxInfo": [ + { + "mac": "24e124fffef021be", + "rssi": -57, + "loRaSNR": 10, + "name": "local_gateway", + "latitude": 0, + "longitude": 0, + "altitude": 0 + } + ], + "txInfo": { + "frequency": 868300000, + "dataRate": { + "modulation": "LORA", + "bandwidth": 125, + "spreadFactor": 7 + }, + "adr": false, + "codeRate": "4/5" + }, + "fCnt": 0, + "fPort": 85, + "data": "AXVkA2cSAQUAAQbZACThJPW3l7MABtkAJOEk/wAEyAAG2QAk4STzGajBAAbZAAZQwg6qjcUABtkAJOEk9yHEuQA=" +} \ No newline at end of file diff --git a/VENDORS/Milesight/AT101/HTTP/uplink/result.json b/VENDORS/Milesight/AT101/HTTP/uplink/result.json new file mode 100644 index 00000000..b2aa22d3 --- /dev/null +++ b/VENDORS/Milesight/AT101/HTTP/uplink/result.json @@ -0,0 +1,48 @@ +{ + "deviceName": "AT101 24e1641092176759", + "deviceType": "AT101", + "attributes": { + "fPort": 85, + "applicationName": "cloud", + "frequency": 868300000, + "bandwidth": 125, + "spreadingFactor": 7, + "codeRate": "4/5" + }, + "telemetry": [{ + "ts": 1585312745547, + "values": { + "battery": 100, + "temperature": 27.4, + "position": "tilt", + "wifi_scan_result": "finish", + "motion_status": "unknown", + "wifi": [{ + "group": 0, + "mac": "24:e1:24:f5:b7:97", + "rssi": -77, + "motion_status": "unknown" + }, { + "group": 0, + "mac": "24:e1:24:ff:00:04", + "rssi": -56, + "motion_status": "unknown" + }, { + "group": 0, + "mac": "24:e1:24:f3:19:a8", + "rssi": -63, + "motion_status": "unknown" + }, { + "group": 0, + "mac": "06:50:c2:0e:aa:8d", + "rssi": -59, + "motion_status": "unknown" + }, { + "group": 0, + "mac": "24:e1:24:f7:21:c4", + "rssi": -71, + "motion_status": "unknown" + }] + } + }] +} \ No newline at end of file diff --git a/VENDORS/Milesight/CT101-CT103/ChirpStack/uplink/converter.json b/VENDORS/Milesight/CT101-CT103/ChirpStack/uplink/converter.json index e925431a..e2e79533 100644 --- a/VENDORS/Milesight/CT101-CT103/ChirpStack/uplink/converter.json +++ b/VENDORS/Milesight/CT101-CT103/ChirpStack/uplink/converter.json @@ -1,5 +1,5 @@ { - "name": "ChirpStack uplink converter for Milesight AT101/103", + "name": "ChirpStack uplink converter for Milesight CT101/103", "type": "UPLINK", "debugMode": true, "configuration": { diff --git a/VENDORS/Milesight/CT101-CT103/HTTP/uplink/converter.json b/VENDORS/Milesight/CT101-CT103/HTTP/uplink/converter.json new file mode 100644 index 00000000..029fcce4 --- /dev/null +++ b/VENDORS/Milesight/CT101-CT103/HTTP/uplink/converter.json @@ -0,0 +1,31 @@ +{ + "name": "HTTP Uplink integration for CT101/103", + "type": "UPLINK", + "debugMode": false, + "debugSettings": { + "failuresEnabled": true, + "allEnabled": false, + "allEnabledUntil": 1735560006385 + }, + "configuration": { + "scriptLang": "TBEL", + "decoder": null, + "tbelDecoder": "var data = decodeToJson(payload);\nvar deviceName = \"CT101/103 \" + data.devEUI;\nvar deviceType = \"CT101/103\";\nvar groupName = null; // If groupName is not null - created device will be added to the entity group with such name.\nvar customerName = null; // If customerName is not null - created devices will be assigned to customer with such name. \n\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// If you want to parse incoming data somehow, you can add your code to this function.\n// input: bytes\n// expected output:\n// {\n// \"attributes\": {\"attributeKey\": \"attributeValue\"},\n// \"telemetry\": [{\"ts\": 1...1, \"values\": {\"telemetryKey\":\"telemetryValue\"}, {\"ts\": 1...2, \"values\": {\"telemetryKey\":\"telemetryValue\"}}]\n// }\n\nfunction decodePayload(input) {\n var output = {\n attributes: {},\n telemetry: []\n };\n \n // --- Decoding code --- //\n var decoded = {};\n var wifi = [];\n var fPort = data.fPort;\n if(fPort == 85) {\n for (var i = 0; i < input.length - 2;) {\n var channel_id = input[i++] & 0xff;\n var channel_type = input[i++] & 0xff;\n \n // POWER STATE\n if (channel_id === 0xff && channel_type === 0x0b) {\n decoded.power = \"on\";\n i += 1;\n }\n // IPSO VERSION\n if (channel_id === 0xff && channel_type === 0x01) {\n output.attributes.ipso_version = readProtocolVersion(input[i]);\n i += 1;\n }\n // PRODUCT SERIAL NUMBER\n if (channel_id === 0xff && channel_type === 0x16) {\n output.attributes.sn = bytesToHex(java.util.Arrays.copyOfRange(input, i, i + 8));\n i += 8;\n }\n // HARDWARE VERSION\n if (channel_id === 0xff && channel_type === 0x09) {\n output.attributes.hardware_version = readHardwareVersion(java.util.Arrays.copyOfRange(input, i, i + 2));\n i += 2;\n }\n // FIRMWARE VERSION\n if (channel_id === 0xff && channel_type === 0x0a) {\n output.attributes.firmware_version = readFirmwareVersion(java.util.Arrays.copyOfRange(input, i, i + 2));\n i += 2;\n }\n // TOTAL CURRENT\n if (channel_id === 0x03 && channel_type === 0x97) {\n decoded.total_current = parseBytesToInt(input, i, 4, false) / 100;\n i += 4;\n }\n // CURRENT\n if (channel_id === 0x04 && channel_type === 0x98) {\n var value = parseBytesToInt(input, i, 2, false);\n if (value === 0xffff) {\n decoded.alarm = \"read failed\";\n } else {\n decoded.current = value / 100;\n }\n i += 2;\n }\n // TEMPERATURE\n if (channel_id === 0x09 && channel_type === 0x67) {\n var temperature_value = parseBytesToInt(input, i, 2, false);\n if (temperature_value === 0xfffd) {\n decoded.temperature_exception = \"over range alarm\";\n } else if (temperature_value === 0xffff) {\n decoded.temperature_exception = \"read failed\";\n } else {\n decoded.temperature = parseBytesToInt(input, i, 2, false) / 10;\n }\n i += 2;\n }\n // CURRENT ALARM\n if (channel_id === 0x84 && channel_type === 0x98) {\n decoded.current_max = parseBytesToInt(input, i, 2, false) / 100;\n decoded.current_min = parseBytesToInt(input, i + 2, 2, false) / 100;\n decoded.current = parseBytesToInt(input, i + 4, 2, false) / 100;\n decoded.alarm = readCurrentAlarm(input[i + 6]);\n i += 7;\n }\n // TEMPERATURE ALARM\n if (channel_id === 0x89 && channel_type === 0x67) {\n decoded.temperature = parseBytesToInt(input, i, 2, false) / 10;\n decoded.temperature_alarm = readTemperatureAlarm(input[i + 2]);\n i += 3;\n }\n }\n }\n\n output.telemetry = [{\n ts: timestamp,\n values: decoded\n }];\n \n // --- Decoding code --- //\n return output;\n}\n\n// --- attributes and telemetry objects ---\nvar telemetry = [];\nvar attributes = {};\n// --- attributes and telemetry objects ---\n\n// --- Timestamp parsing\nvar dateString = data.time;\ntimestamp = parseDateToTimestamp(dateString);\n// --- Timestamp parsing\n\n// Passing incoming bytes to decodePayload function, to get custom decoding\nvar customDecoding = decodePayload(base64ToBytes(data.data));\n\n// Collecting data to result\nif (customDecoding.?telemetry.size() > 0) {\n foreach(telemetryObj: customDecoding.telemetry) {\n if (telemetryObj.ts != null && telemetryObj.values != null) {\n telemetry.add(telemetryObj);\n }\n }\n}\n\nif (customDecoding.?attributes.size() > 0) {\n attributes.putAll(customDecoding.attributes);\n}\n\n// You can add some keys manually to attributes or telemetry\nattributes.eui = data.?devEui;\nattributes.fPort = data.fPort;\nattributes.applicationId = data.?applicationId;\nattributes.applicationName = data.?applicationName;\nattributes.frequency = data.txInfo.?frequency;\nattributes.bandwidth = data.txInfo.?dataRate.?bandwidth;\nattributes.spreadingFactor = data.txInfo.?dataRate.?spreadFactor;\nattributes.codeRate = data.txInfo.?codeRate;\n\nif(Boolean.parseBoolean(metadata[\"includeGatewayInfo\"])) {\n var gatewayInfo = getGatewayInfo();\n var addDataToTelemetry = {};\n addDataToTelemetry.snr = gatewayInfo.?loRaSNR;\n addDataToTelemetry.rssi = gatewayInfo.rssi;\n addDataToTelemetry.fCnt = data.fCnt;\n \n telemetry = processTelemetryData(telemetry, addDataToTelemetry);\n}\n\nvar result = {\n deviceName: deviceName,\n deviceType: deviceType,\n // assetName: assetName,\n // assetType: assetType,\n attributes: attributes,\n telemetry: telemetry\n};\n\naddAdditionalInfoForDeviceMsg(result, customerName, groupName);\n\nreturn result;\n\nfunction addAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName) {\n if (customerName != null) {\n deviceInfo.customerName = customerName;\n }\n if (groupName != null) {\n deviceInfo.groupName = groupName;\n }\n}\n\nfunction parseDateToTimestamp(dateString) {\n dateString = dateString.replaceFirst(\"(\\\\d{4}-\\\\d{2})(\\\\d{2})\", \"$1-$2\");\n dateString = dateString.replaceFirst(\"\\\\.(\\\\d{3})\\\\d+Z\", \".$1Z\");\n dateString = dateString.replace(\"Z\", \"+0000\");\n var date = new Date(dateString);\n var timestamp = date.getTime();\n \n // If we cannot parse timestamp - we will use the current timestamp\n if (timestamp == -1) {\n timestamp = Date.now();\n }\n \n return timestamp;\n}\n\nfunction getGatewayInfo() {\n var gatewayList = data.rxInfo;\n var maxRssi = Integer.MIN_VALUE;\n var gatewayInfo = {};\n \n foreach (gateway : gatewayList) {\n if(gateway.rssi > maxRssi) {\n maxRssi = gateway.rssi;\n gatewayInfo = gateway;\n }\n }\n \n return gatewayInfo;\n}\n\nfunction processTelemetryData(telemetry, addDataToTelemetry) {\n if (telemetry.size >= 1) {\n telemetry = addDataToTelemetries(telemetry, addDataToTelemetry);\n }\n else {\n telemetry.add(addDataToTelemetry);\n }\n \n return telemetry;\n}\n\nfunction addDataToTelemetries(telemetries, addDataToTelemetry) {\n foreach(telemetry : telemetries) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[\"values\"].keys.contains(element.key)) {\n telemetry[\"values\"][element.key] = element.value;\n }\n } \n }\n \n return telemetries;\n}\n\nfunction readProtocolVersion(bytes) {\n var major = (bytes & 0xf0) >> 4;\n var minor = bytes & 0x0f;\n return \"v\" + major + \".\" + minor;\n}\n\nfunction readHardwareVersion(bytes) {\n var major = bytes[0] & 0xff;\n var minor = (bytes[1] & 0xff) >> 4;\n return \"v\" + major + \".\" + minor;\n}\n\nfunction readFirmwareVersion(bytes) {\n var major = bytes[0] & 0xff;\n var minor = bytes[1] & 0xff;\n return \"v\" + major + \".\" + minor;\n}\n\nfunction readCurrentAlarm(type) {\n var alarm = [];\n if ((type >> 0 & 0x01) != 0) {\n alarm.add(\"threshold alarm\");\n }\n if ((type >> 1 & 0x01) != 0) {\n alarm.add(\"threshold alarm release\");\n }\n if ((type >> 2 & 0x01) != 0) {\n alarm.add(\"over range alarm\");\n }\n if ((type >> 3 & 0x01) != 0) {\n alarm.add(\"over range alarm release\");\n }\n \n return alarm;\n}\n\nfunction readTemperatureAlarm(type) {\n var alarms = [];\n \n if ((type & 0x01) != 0) {\n alarms.add(\"Threshold alarm\");\n }\n if ((type & 0x02) != 0) {\n alarms.add(\"Threshold alarm dismiss\");\n }\n\n return alarms;\n}", + "encoder": null, + "tbelEncoder": null, + "updateOnlyKeys": [ + "fPort", + "applicationName", + "frequency", + "bandwidth", + "spreadingFactor", + "codeRate", + "hardware_version", + "firmware_version" + ] + }, + "additionalInfo": { + "description": "" + }, + "edgeTemplate": false +} \ No newline at end of file diff --git a/VENDORS/Milesight/CT101-CT103/HTTP/uplink/metadata.json b/VENDORS/Milesight/CT101-CT103/HTTP/uplink/metadata.json new file mode 100644 index 00000000..87ee6615 --- /dev/null +++ b/VENDORS/Milesight/CT101-CT103/HTTP/uplink/metadata.json @@ -0,0 +1,4 @@ +{ + "integrationName": "HTTP integration", + "includeGatewayInfo": "false" +} \ No newline at end of file diff --git a/VENDORS/Milesight/CT101-CT103/HTTP/uplink/payload.json b/VENDORS/Milesight/CT101-CT103/HTTP/uplink/payload.json new file mode 100644 index 00000000..b6100ab3 --- /dev/null +++ b/VENDORS/Milesight/CT101-CT103/HTTP/uplink/payload.json @@ -0,0 +1,31 @@ +{ + "applicationID": 1, + "applicationName": "cloud", + "deviceName": "24e1641092176759", + "devEUI": "24e1641092176759", + "time": "2020-0327T12:39:05.547336Z", + "rxInfo": [ + { + "mac": "24e124fffef021be", + "rssi": -57, + "loRaSNR": 10, + "name": "local_gateway", + "latitude": 0, + "longitude": 0, + "altitude": 0 + } + ], + "txInfo": { + "frequency": 868300000, + "dataRate": { + "modulation": "LORA", + "bandwidth": 125, + "spreadFactor": 7 + }, + "adr": false, + "codeRate": "4/5" + }, + "fCnt": 0, + "fPort": 85, + "data": "/wv//wEB/xZnRtOIAlgAAP8JAQD/CgEB/w8A" +} \ No newline at end of file diff --git a/VENDORS/Milesight/CT101-CT103/HTTP/uplink/result.json b/VENDORS/Milesight/CT101-CT103/HTTP/uplink/result.json new file mode 100644 index 00000000..0792a6a2 --- /dev/null +++ b/VENDORS/Milesight/CT101-CT103/HTTP/uplink/result.json @@ -0,0 +1,22 @@ +{ + "deviceName": "CT101/103 24e1641092176759", + "deviceType": "CT101/103", + "attributes": { + "ipso_version": "v0.1", + "sn": "6746D38802580000", + "hardware_version": "v1.0", + "firmware_version": "v1.1", + "fPort": 85, + "applicationName": "cloud", + "frequency": 868300000, + "bandwidth": 125, + "spreadingFactor": 7, + "codeRate": "4/5" + }, + "telemetry": [{ + "ts": 1585312745547, + "values": { + "power": "on" + } + }] +} \ No newline at end of file diff --git a/VENDORS/Milesight/DS3604/HTTP/uplink/converter.json b/VENDORS/Milesight/DS3604/HTTP/uplink/converter.json new file mode 100644 index 00000000..b02062b4 --- /dev/null +++ b/VENDORS/Milesight/DS3604/HTTP/uplink/converter.json @@ -0,0 +1,29 @@ +{ + "name": "HTTP Uplink integration for DS3604", + "type": "UPLINK", + "debugMode": false, + "debugSettings": { + "failuresEnabled": true, + "allEnabled": false, + "allEnabledUntil": 1735560006385 + }, + "configuration": { + "scriptLang": "TBEL", + "decoder": null, + "tbelDecoder": "var data = decodeToJson(payload);\nvar deviceName = \"DS3604 \" + data.devEUI;\nvar deviceType = \"DS3604\";\nvar groupName = null; // If groupName is not null - created device will be added to the entity group with such name.\nvar customerName = null; // If customerName is not null - created devices will be assigned to customer with such name. \n\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// If you want to parse incoming data somehow, you can add your code to this function.\n// input: bytes\n// expected output:\n// {\n// \"attributes\": {\"attributeKey\": \"attributeValue\"},\n// \"telemetry\": [{\"ts\": 1...1, \"values\": {\"telemetryKey\":\"telemetryValue\"}, {\"ts\": 1...2, \"values\": {\"telemetryKey\":\"telemetryValue\"}}]\n// }\n\nfunction decodePayload(input) {\n var output = {\n attributes: {},\n telemetry: []\n };\n \n // --- Decoding code --- //\n var decoded = {};\n var wifi = [];\n var fPort = data.fPort;\n if(fPort == 85) {\n for (var i = 0; i < input.length - 2;) {\n var channel_id = input[i++] & 0xff;\n var channel_type = input[i++] & 0xff;\n \n // BATTERY\n if (channel_id === 0x01 && channel_type === 0x75) {\n decoded.battery = input[i];\n i += 1;\n }\n // TEMPLATE\n else if (channel_id == 0xff && channel_type == 0x73) {\n decoded.template = input[i] + 1;\n i += 1;\n }\n // TEMPLATE BLOCK CHANNEL DATA\n if (channel_id == 0xfb && channel_type == 0x01) {\n var template_id = (input[i] >> 6) + 1;\n var block_id = input[i++] & 0x3f;\n var block_name;\n if (block_id < 10) {\n block_name = \"text_\" + (block_id + 1);\n block_length = input[i++];\n var bytes = java.util.Arrays.copyOfRange(input, i, i + block_length);\n decoded[block_name] = fromUtf8Bytes(bytes);\n i += block_length;\n } else if (block_id == 10) {\n block_name = \"qrcode\";\n block_length = input[i++];\n var bytes = java.util.Arrays.copyOfRange(input, i, i + block_length);\n decoded[block_name] = fromUtf8Bytes(bytes);\n i += block_length;\n }\n decoded.template = template_id;\n }\n }\n }\n\n output.telemetry = [{\n ts: timestamp,\n values: decoded\n }];\n \n // --- Decoding code --- //\n return output;\n}\n\n// --- attributes and telemetry objects ---\nvar telemetry = [];\nvar attributes = {};\n// --- attributes and telemetry objects ---\n\n// --- Timestamp parsing\nvar dateString = data.time;\ntimestamp = parseDateToTimestamp(dateString);\n// --- Timestamp parsing\n\n// Passing incoming bytes to decodePayload function, to get custom decoding\nvar customDecoding = decodePayload(base64ToBytes(data.data));\n\n// Collecting data to result\nif (customDecoding.?telemetry.size() > 0) {\n foreach(telemetryObj: customDecoding.telemetry) {\n if (telemetryObj.ts != null && telemetryObj.values != null) {\n telemetry.add(telemetryObj);\n }\n }\n}\n\nif (customDecoding.?attributes.size() > 0) {\n attributes.putAll(customDecoding.attributes);\n}\n\n// You can add some keys manually to attributes or telemetry\nattributes.eui = data.?devEui;\nattributes.fPort = data.fPort;\nattributes.applicationId = data.?applicationId;\nattributes.applicationName = data.?applicationName;\nattributes.frequency = data.txInfo.?frequency;\nattributes.bandwidth = data.txInfo.?dataRate.?bandwidth;\nattributes.spreadingFactor = data.txInfo.?dataRate.?spreadFactor;\nattributes.codeRate = data.txInfo.?codeRate;\n\nif(Boolean.parseBoolean(metadata[\"includeGatewayInfo\"])) {\n var gatewayInfo = getGatewayInfo();\n var addDataToTelemetry = {};\n addDataToTelemetry.snr = gatewayInfo.?loRaSNR;\n addDataToTelemetry.rssi = gatewayInfo.rssi;\n addDataToTelemetry.fCnt = data.fCnt;\n \n telemetry = processTelemetryData(telemetry, addDataToTelemetry);\n}\n\nvar result = {\n deviceName: deviceName,\n deviceType: deviceType,\n // assetName: assetName,\n // assetType: assetType,\n attributes: attributes,\n telemetry: telemetry\n};\n\naddAdditionalInfoForDeviceMsg(result, customerName, groupName);\n\nreturn result;\n\nfunction addAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName) {\n if (customerName != null) {\n deviceInfo.customerName = customerName;\n }\n if (groupName != null) {\n deviceInfo.groupName = groupName;\n }\n}\n\nfunction parseDateToTimestamp(dateString) {\n dateString = dateString.replaceFirst(\"(\\\\d{4}-\\\\d{2})(\\\\d{2})\", \"$1-$2\");\n dateString = dateString.replaceFirst(\"\\\\.(\\\\d{3})\\\\d+Z\", \".$1Z\");\n dateString = dateString.replace(\"Z\", \"+0000\");\n var date = new Date(dateString);\n var timestamp = date.getTime();\n \n // If we cannot parse timestamp - we will use the current timestamp\n if (timestamp == -1) {\n timestamp = Date.now();\n }\n \n return timestamp;\n}\n\nfunction getGatewayInfo() {\n var gatewayList = data.rxInfo;\n var maxRssi = Integer.MIN_VALUE;\n var gatewayInfo = {};\n \n foreach (gateway : gatewayList) {\n if(gateway.rssi > maxRssi) {\n maxRssi = gateway.rssi;\n gatewayInfo = gateway;\n }\n }\n \n return gatewayInfo;\n}\n\nfunction processTelemetryData(telemetry, addDataToTelemetry) {\n if (telemetry.size >= 1) {\n telemetry = addDataToTelemetries(telemetry, addDataToTelemetry);\n }\n else {\n telemetry.add(addDataToTelemetry);\n }\n \n return telemetry;\n}\n\nfunction addDataToTelemetries(telemetries, addDataToTelemetry) {\n foreach(telemetry : telemetries) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[\"values\"].keys.contains(element.key)) {\n telemetry[\"values\"][element.key] = element.value;\n }\n } \n }\n \n return telemetries;\n}\n\nfunction fromUtf8Bytes(bytes) {\n var resultObject = \"\";\n \n foreach (b : bytes) {\n resultObject += String.format(\"%%%02X\", b & 0xFF);\n }\n \n return decodeUrlEncodedString(resultObject);\n}\n\nfunction decodeUrlEncodedString(encoded) {\n var decoded = \"\";\n for (int i = 0; i < encoded.length(); i++) {\n char c = encoded.charAt(i);\n if (c == '%' && i + 2 < encoded.length()) {\n var hexValue = \"\" + encoded.charAt(i + 1) + encoded.charAt(i + 2);\n var decodedChar = Integer.parseInt(hexValue, 16);\n decoded += (char) decodedChar;\n i += 2;\n } else {\n decoded += c;\n }\n }\n return decoded;\n}", + "encoder": null, + "tbelEncoder": null, + "updateOnlyKeys": [ + "fPort", + "applicationName", + "frequency", + "bandwidth", + "spreadingFactor", + "codeRate" + ] + }, + "additionalInfo": { + "description": "" + }, + "edgeTemplate": false +} \ No newline at end of file diff --git a/VENDORS/Milesight/DS3604/HTTP/uplink/metadata.json b/VENDORS/Milesight/DS3604/HTTP/uplink/metadata.json new file mode 100644 index 00000000..87ee6615 --- /dev/null +++ b/VENDORS/Milesight/DS3604/HTTP/uplink/metadata.json @@ -0,0 +1,4 @@ +{ + "integrationName": "HTTP integration", + "includeGatewayInfo": "false" +} \ No newline at end of file diff --git a/VENDORS/Milesight/DS3604/HTTP/uplink/payload.json b/VENDORS/Milesight/DS3604/HTTP/uplink/payload.json new file mode 100644 index 00000000..9138f014 --- /dev/null +++ b/VENDORS/Milesight/DS3604/HTTP/uplink/payload.json @@ -0,0 +1,31 @@ +{ + "applicationID": 1, + "applicationName": "cloud", + "deviceName": "24e1641092176759", + "devEUI": "24e1641092176759", + "time": "2020-0327T12:39:05.547336Z", + "rxInfo": [ + { + "mac": "24e124fffef021be", + "rssi": -57, + "loRaSNR": 10, + "name": "local_gateway", + "latitude": 0, + "longitude": 0, + "altitude": 0 + } + ], + "txInfo": { + "frequency": 868300000, + "dataRate": { + "modulation": "LORA", + "bandwidth": 125, + "spreadFactor": 7 + }, + "adr": false, + "codeRate": "4/5" + }, + "fCnt": 0, + "fPort": 85, + "data": "AXVk+wEABU1pbGVz+wEKBWhlbGxv" +} \ No newline at end of file diff --git a/VENDORS/Milesight/DS3604/HTTP/uplink/result.json b/VENDORS/Milesight/DS3604/HTTP/uplink/result.json new file mode 100644 index 00000000..485ec86f --- /dev/null +++ b/VENDORS/Milesight/DS3604/HTTP/uplink/result.json @@ -0,0 +1,21 @@ +{ + "deviceName": "DS3604 24e1641092176759", + "deviceType": "DS3604", + "attributes": { + "fPort": 85, + "applicationName": "cloud", + "frequency": 868300000, + "bandwidth": 125, + "spreadingFactor": 7, + "codeRate": "4/5" + }, + "telemetry": [{ + "ts": 1585312745547, + "values": { + "battery": 100, + "text_1": "Miles", + "template": 1, + "qrcode": "hello" + } + }] +} \ No newline at end of file diff --git a/VENDORS/Milesight/EM300-CL/HTTP/uplink/converter.json b/VENDORS/Milesight/EM300-CL/HTTP/uplink/converter.json new file mode 100644 index 00000000..489ec9d4 --- /dev/null +++ b/VENDORS/Milesight/EM300-CL/HTTP/uplink/converter.json @@ -0,0 +1,29 @@ +{ + "name": "HTTP Uplink integration for EM-300CL", + "type": "UPLINK", + "debugMode": false, + "debugSettings": { + "failuresEnabled": true, + "allEnabled": false, + "allEnabledUntil": 1735560006385 + }, + "configuration": { + "scriptLang": "TBEL", + "decoder": null, + "tbelDecoder": "var data = decodeToJson(payload);\nvar deviceName = \"EM-300CL \" + data.devEUI;\nvar deviceType = \"EM-300CL\";\nvar groupName = null; // If groupName is not null - created device will be added to the entity group with such name.\nvar customerName = null; // If customerName is not null - created devices will be assigned to customer with such name. \n\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// If you want to parse incoming data somehow, you can add your code to this function.\n// input: bytes\n// expected output:\n// {\n// \"attributes\": {\"attributeKey\": \"attributeValue\"},\n// \"telemetry\": [{\"ts\": 1...1, \"values\": {\"telemetryKey\":\"telemetryValue\"}, {\"ts\": 1...2, \"values\": {\"telemetryKey\":\"telemetryValue\"}}]\n// }\n\nfunction decodePayload(input) {\n var output = {\n attributes: {},\n telemetry: []\n };\n \n // --- Decoding code --- //\n var decoded = {};\n var wifi = [];\n var fPort = data.fPort;\n if(fPort == 85) {\n for (var i = 0; i < input.length - 2;) {\n var channel_id = input[i++] & 0xff;\n var channel_type = input[i++] & 0xff;\n \n // BATTERY\n if (channel_id === 0x01 && channel_type === 0x75) {\n decoded.battery = input[i];\n i += 1;\n }\n // LIQUID\n else if (channel_id === 0x03 && channel_type === 0xed) {\n decoded.liquid = readLiquidStatus(input[i]);\n i += 1;\n }\n // CALIBRATION RESULT\n else if (channel_id === 0x04 && channel_type === 0xee) {\n decoded.calibration_result = input[i] === 0 ? \"failed\" : \"success\";\n i += 1;\n }\n // LIQUID ALARM\n else if (channel_id === 0x83 && channel_type === 0xed) {\n decoded.liquid = readLiquidStatus(input[i]);\n decoded.liquid_alarm = readAlarmType(input[i + 1]);\n i += 2;\n }\n }\n }\n\n output.telemetry = [{\n ts: timestamp,\n values: decoded\n }];\n \n // --- Decoding code --- //\n return output;\n}\n\n// --- attributes and telemetry objects ---\nvar telemetry = [];\nvar attributes = {};\n// --- attributes and telemetry objects ---\n\n// --- Timestamp parsing\nvar dateString = data.time;\ntimestamp = parseDateToTimestamp(dateString);\n// --- Timestamp parsing\n\n// Passing incoming bytes to decodePayload function, to get custom decoding\nvar customDecoding = decodePayload(base64ToBytes(data.data));\n\n// Collecting data to result\nif (customDecoding.?telemetry.size() > 0) {\n foreach(telemetryObj: customDecoding.telemetry) {\n if (telemetryObj.ts != null && telemetryObj.values != null) {\n telemetry.add(telemetryObj);\n }\n }\n}\n\nif (customDecoding.?attributes.size() > 0) {\n attributes.putAll(customDecoding.attributes);\n}\n\n// You can add some keys manually to attributes or telemetry\nattributes.eui = data.?devEui;\nattributes.fPort = data.fPort;\nattributes.applicationId = data.?applicationId;\nattributes.applicationName = data.?applicationName;\nattributes.frequency = data.txInfo.?frequency;\nattributes.bandwidth = data.txInfo.?dataRate.?bandwidth;\nattributes.spreadingFactor = data.txInfo.?dataRate.?spreadFactor;\nattributes.codeRate = data.txInfo.?codeRate;\n\nif(Boolean.parseBoolean(metadata[\"includeGatewayInfo\"])) {\n var gatewayInfo = getGatewayInfo();\n var addDataToTelemetry = {};\n addDataToTelemetry.snr = gatewayInfo.?loRaSNR;\n addDataToTelemetry.rssi = gatewayInfo.rssi;\n addDataToTelemetry.fCnt = data.fCnt;\n \n telemetry = processTelemetryData(telemetry, addDataToTelemetry);\n}\n\nvar result = {\n deviceName: deviceName,\n deviceType: deviceType,\n // assetName: assetName,\n // assetType: assetType,\n attributes: attributes,\n telemetry: telemetry\n};\n\naddAdditionalInfoForDeviceMsg(result, customerName, groupName);\n\nreturn result;\n\nfunction addAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName) {\n if (customerName != null) {\n deviceInfo.customerName = customerName;\n }\n if (groupName != null) {\n deviceInfo.groupName = groupName;\n }\n}\n\nfunction parseDateToTimestamp(dateString) {\n dateString = dateString.replaceFirst(\"(\\\\d{4}-\\\\d{2})(\\\\d{2})\", \"$1-$2\");\n dateString = dateString.replaceFirst(\"\\\\.(\\\\d{3})\\\\d+Z\", \".$1Z\");\n dateString = dateString.replace(\"Z\", \"+0000\");\n var date = new Date(dateString);\n var timestamp = date.getTime();\n \n // If we cannot parse timestamp - we will use the current timestamp\n if (timestamp == -1) {\n timestamp = Date.now();\n }\n \n return timestamp;\n}\n\nfunction getGatewayInfo() {\n var gatewayList = data.rxInfo;\n var maxRssi = Integer.MIN_VALUE;\n var gatewayInfo = {};\n \n foreach (gateway : gatewayList) {\n if(gateway.rssi > maxRssi) {\n maxRssi = gateway.rssi;\n gatewayInfo = gateway;\n }\n }\n \n return gatewayInfo;\n}\n\nfunction processTelemetryData(telemetry, addDataToTelemetry) {\n if (telemetry.size >= 1) {\n telemetry = addDataToTelemetries(telemetry, addDataToTelemetry);\n }\n else {\n telemetry.add(addDataToTelemetry);\n }\n \n return telemetry;\n}\n\nfunction addDataToTelemetries(telemetries, addDataToTelemetry) {\n foreach(telemetry : telemetries) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[\"values\"].keys.contains(element.key)) {\n telemetry[\"values\"][element.key] = element.value;\n }\n } \n }\n \n return telemetries;\n}\n\nfunction readLiquidStatus(type) {\n switch (type) {\n case 0:\n return \"uncalibrated\";\n case 1:\n return \"full\";\n case 2:\n return \"empty\";\n case 0xff:\n return \"error\";\n default:\n return \"unknown\";\n }\n}\n\nfunction readAlarmType(type) {\n switch (type) {\n case 0:\n return \"empty alarm release\";\n case 1:\n return \"empty alarm\";\n default:\n return \"unknown\";\n }\n}", + "encoder": null, + "tbelEncoder": null, + "updateOnlyKeys": [ + "fPort", + "applicationName", + "frequency", + "bandwidth", + "spreadingFactor", + "codeRate" + ] + }, + "additionalInfo": { + "description": "" + }, + "edgeTemplate": false +} \ No newline at end of file diff --git a/VENDORS/Milesight/EM300-CL/HTTP/uplink/metadata.json b/VENDORS/Milesight/EM300-CL/HTTP/uplink/metadata.json new file mode 100644 index 00000000..87ee6615 --- /dev/null +++ b/VENDORS/Milesight/EM300-CL/HTTP/uplink/metadata.json @@ -0,0 +1,4 @@ +{ + "integrationName": "HTTP integration", + "includeGatewayInfo": "false" +} \ No newline at end of file diff --git a/VENDORS/Milesight/EM300-CL/HTTP/uplink/payload.json b/VENDORS/Milesight/EM300-CL/HTTP/uplink/payload.json new file mode 100644 index 00000000..fedc4e44 --- /dev/null +++ b/VENDORS/Milesight/EM300-CL/HTTP/uplink/payload.json @@ -0,0 +1,31 @@ +{ + "applicationID": 1, + "applicationName": "cloud", + "deviceName": "24e1641092176759", + "devEUI": "24e1641092176759", + "time": "2020-0327T12:39:05.547336Z", + "rxInfo": [ + { + "mac": "24e124fffef021be", + "rssi": -57, + "loRaSNR": 10, + "name": "local_gateway", + "latitude": 0, + "longitude": 0, + "altitude": 0 + } + ], + "txInfo": { + "frequency": 868300000, + "dataRate": { + "modulation": "LORA", + "bandwidth": 125, + "spreadFactor": 7 + }, + "adr": false, + "codeRate": "4/5" + }, + "fCnt": 0, + "fPort": 85, + "data": "AXVkA+0A" +} \ No newline at end of file diff --git a/VENDORS/Milesight/EM300-CL/HTTP/uplink/result.json b/VENDORS/Milesight/EM300-CL/HTTP/uplink/result.json new file mode 100644 index 00000000..5651d6d8 --- /dev/null +++ b/VENDORS/Milesight/EM300-CL/HTTP/uplink/result.json @@ -0,0 +1,19 @@ +{ + "deviceName": "EM-300CL 24e1641092176759", + "deviceType": "EM-300CL", + "attributes": { + "fPort": 85, + "applicationName": "cloud", + "frequency": 868300000, + "bandwidth": 125, + "spreadingFactor": 7, + "codeRate": "4/5" + }, + "telemetry": [{ + "ts": 1585312745547, + "values": { + "battery": 100, + "liquid": "uncalibrated" + } + }] +} \ No newline at end of file diff --git a/VENDORS/Milesight/EM310-TILT/HTTP/uplink/converter.json b/VENDORS/Milesight/EM310-TILT/HTTP/uplink/converter.json new file mode 100644 index 00000000..d1854fd5 --- /dev/null +++ b/VENDORS/Milesight/EM310-TILT/HTTP/uplink/converter.json @@ -0,0 +1,29 @@ +{ + "name": "HTTP Uplink integration for EM310-TILT", + "type": "UPLINK", + "debugMode": false, + "debugSettings": { + "failuresEnabled": true, + "allEnabled": false, + "allEnabledUntil": 1735560006385 + }, + "configuration": { + "scriptLang": "TBEL", + "decoder": null, + "tbelDecoder": "var data = decodeToJson(payload);\nvar deviceName = \"EM310-TILT \" + data.devEUI;\nvar deviceType = \"EM310-TILT\";\nvar groupName = null; // If groupName is not null - created device will be added to the entity group with such name.\nvar customerName = null; // If customerName is not null - created devices will be assigned to customer with such name. \n\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// If you want to parse incoming data somehow, you can add your code to this function.\n// input: bytes\n// expected output:\n// {\n// \"attributes\": {\"attributeKey\": \"attributeValue\"},\n// \"telemetry\": [{\"ts\": 1...1, \"values\": {\"telemetryKey\":\"telemetryValue\"}, {\"ts\": 1...2, \"values\": {\"telemetryKey\":\"telemetryValue\"}}]\n// }\n\nfunction decodePayload(input) {\n var output = {\n attributes: {},\n telemetry: []\n };\n \n // --- Decoding code --- //\n var decoded = {};\n var wifi = [];\n var fPort = data.fPort;\n if(fPort == 85) {\n for (var i = 0; i < input.length - 2;) {\n var channel_id = input[i++] & 0xff;\n var channel_type = input[i++] & 0xff;\n \n // BATTERY\n if (channel_id === 0x01 && channel_type === 0x75) {\n decoded.battery = input[i];\n i += 1;\n }\n // ANGLE\n else if (channel_id === 0x03 && channel_type === 0xcf) {\n decoded.angle_x = parseBytesToInt(input, i, 2, false) / 100;\n decoded.angle_y = parseBytesToInt(input, i + 2, 2, false) / 100;\n decoded.angle_z = parseBytesToInt(input, i + 4, 2, false) / 100;\n decoded.threshold_x = (input[i + 6] & 0x01) === 0x01 ? \"trigger\" : \"normal\";\n decoded.threshold_y = (input[i + 6] & 0x02) === 0x02 ? \"trigger\" : \"normal\";\n decoded.threshold_z = (input[i + 6] & 0x04) === 0x04 ? \"trigger\" : \"normal\";\n i += 7;\n }\n }\n }\n\n output.telemetry = [{\n ts: timestamp,\n values: decoded\n }];\n \n // --- Decoding code --- //\n return output;\n}\n\n// --- attributes and telemetry objects ---\nvar telemetry = [];\nvar attributes = {};\n// --- attributes and telemetry objects ---\n\n// --- Timestamp parsing\nvar dateString = data.time;\ntimestamp = parseDateToTimestamp(dateString);\n// --- Timestamp parsing\n\n// Passing incoming bytes to decodePayload function, to get custom decoding\nvar customDecoding = decodePayload(base64ToBytes(data.data));\n\n// Collecting data to result\nif (customDecoding.?telemetry.size() > 0) {\n foreach(telemetryObj: customDecoding.telemetry) {\n if (telemetryObj.ts != null && telemetryObj.values != null) {\n telemetry.add(telemetryObj);\n }\n }\n}\n\nif (customDecoding.?attributes.size() > 0) {\n attributes.putAll(customDecoding.attributes);\n}\n\n// You can add some keys manually to attributes or telemetry\nattributes.eui = data.?devEui;\nattributes.fPort = data.fPort;\nattributes.applicationId = data.?applicationId;\nattributes.applicationName = data.?applicationName;\nattributes.frequency = data.txInfo.?frequency;\nattributes.bandwidth = data.txInfo.?dataRate.?bandwidth;\nattributes.spreadingFactor = data.txInfo.?dataRate.?spreadFactor;\nattributes.codeRate = data.txInfo.?codeRate;\n\nif(Boolean.parseBoolean(metadata[\"includeGatewayInfo\"])) {\n var gatewayInfo = getGatewayInfo();\n var addDataToTelemetry = {};\n addDataToTelemetry.snr = gatewayInfo.?loRaSNR;\n addDataToTelemetry.rssi = gatewayInfo.rssi;\n addDataToTelemetry.fCnt = data.fCnt;\n \n telemetry = processTelemetryData(telemetry, addDataToTelemetry);\n}\n\nvar result = {\n deviceName: deviceName,\n deviceType: deviceType,\n // assetName: assetName,\n // assetType: assetType,\n attributes: attributes,\n telemetry: telemetry\n};\n\naddAdditionalInfoForDeviceMsg(result, customerName, groupName);\n\nreturn result;\n\nfunction addAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName) {\n if (customerName != null) {\n deviceInfo.customerName = customerName;\n }\n if (groupName != null) {\n deviceInfo.groupName = groupName;\n }\n}\n\nfunction parseDateToTimestamp(dateString) {\n dateString = dateString.replaceFirst(\"(\\\\d{4}-\\\\d{2})(\\\\d{2})\", \"$1-$2\");\n dateString = dateString.replaceFirst(\"\\\\.(\\\\d{3})\\\\d+Z\", \".$1Z\");\n dateString = dateString.replace(\"Z\", \"+0000\");\n var date = new Date(dateString);\n var timestamp = date.getTime();\n \n // If we cannot parse timestamp - we will use the current timestamp\n if (timestamp == -1) {\n timestamp = Date.now();\n }\n \n return timestamp;\n}\n\nfunction getGatewayInfo() {\n var gatewayList = data.rxInfo;\n var maxRssi = Integer.MIN_VALUE;\n var gatewayInfo = {};\n \n foreach (gateway : gatewayList) {\n if(gateway.rssi > maxRssi) {\n maxRssi = gateway.rssi;\n gatewayInfo = gateway;\n }\n }\n \n return gatewayInfo;\n}\n\nfunction processTelemetryData(telemetry, addDataToTelemetry) {\n if (telemetry.size >= 1) {\n telemetry = addDataToTelemetries(telemetry, addDataToTelemetry);\n }\n else {\n telemetry.add(addDataToTelemetry);\n }\n \n return telemetry;\n}\n\nfunction addDataToTelemetries(telemetries, addDataToTelemetry) {\n foreach(telemetry : telemetries) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[\"values\"].keys.contains(element.key)) {\n telemetry[\"values\"][element.key] = element.value;\n }\n } \n }\n \n return telemetries;\n}\n\nfunction readLiquidStatus(type) {\n switch (type) {\n case 0:\n return \"uncalibrated\";\n case 1:\n return \"full\";\n case 2:\n return \"empty\";\n case 0xff:\n return \"error\";\n default:\n return \"unknown\";\n }\n}\n\nfunction readAlarmType(type) {\n switch (type) {\n case 0:\n return \"empty alarm release\";\n case 1:\n return \"empty alarm\";\n default:\n return \"unknown\";\n }\n}", + "encoder": null, + "tbelEncoder": null, + "updateOnlyKeys": [ + "fPort", + "applicationName", + "frequency", + "bandwidth", + "spreadingFactor", + "codeRate" + ] + }, + "additionalInfo": { + "description": "" + }, + "edgeTemplate": false +} \ No newline at end of file diff --git a/VENDORS/Milesight/EM310-TILT/HTTP/uplink/metadata.json b/VENDORS/Milesight/EM310-TILT/HTTP/uplink/metadata.json new file mode 100644 index 00000000..87ee6615 --- /dev/null +++ b/VENDORS/Milesight/EM310-TILT/HTTP/uplink/metadata.json @@ -0,0 +1,4 @@ +{ + "integrationName": "HTTP integration", + "includeGatewayInfo": "false" +} \ No newline at end of file diff --git a/VENDORS/Milesight/EM310-TILT/HTTP/uplink/payload.json b/VENDORS/Milesight/EM310-TILT/HTTP/uplink/payload.json new file mode 100644 index 00000000..89357630 --- /dev/null +++ b/VENDORS/Milesight/EM310-TILT/HTTP/uplink/payload.json @@ -0,0 +1,31 @@ +{ + "applicationID": 1, + "applicationName": "cloud", + "deviceName": "24e1641092176759", + "devEUI": "24e1641092176759", + "time": "2020-0327T12:39:05.547336Z", + "rxInfo": [ + { + "mac": "24e124fffef021be", + "rssi": -57, + "loRaSNR": 10, + "name": "local_gateway", + "latitude": 0, + "longitude": 0, + "altitude": 0 + } + ], + "txInfo": { + "frequency": 868300000, + "dataRate": { + "modulation": "LORA", + "bandwidth": 125, + "spreadFactor": 7 + }, + "adr": false, + "codeRate": "4/5" + }, + "fCnt": 0, + "fPort": 85, + "data": "A88AAAAAKCMH" +} \ No newline at end of file diff --git a/VENDORS/Milesight/EM310-TILT/HTTP/uplink/result.json b/VENDORS/Milesight/EM310-TILT/HTTP/uplink/result.json new file mode 100644 index 00000000..90818c23 --- /dev/null +++ b/VENDORS/Milesight/EM310-TILT/HTTP/uplink/result.json @@ -0,0 +1,23 @@ +{ + "deviceName": "EM310-TILT 24e1641092176759", + "deviceType": "EM310-TILT", + "attributes": { + "fPort": 85, + "applicationName": "cloud", + "frequency": 868300000, + "bandwidth": 125, + "spreadingFactor": 7, + "codeRate": "4/5" + }, + "telemetry": [{ + "ts": 1585312745547, + "values": { + "angle_x": 0.0, + "angle_y": 0.0, + "angle_z": 90.0, + "threshold_x": "trigger", + "threshold_y": "trigger", + "threshold_z": "trigger" + } + }] +} \ No newline at end of file diff --git a/VENDORS/Milesight/EM310-UDL/HTTP/uplink/converter.json b/VENDORS/Milesight/EM310-UDL/HTTP/uplink/converter.json new file mode 100644 index 00000000..1b6f2676 --- /dev/null +++ b/VENDORS/Milesight/EM310-UDL/HTTP/uplink/converter.json @@ -0,0 +1,29 @@ +{ + "name": "HTTP Uplink integration for EM310-UDL", + "type": "UPLINK", + "debugMode": false, + "debugSettings": { + "failuresEnabled": true, + "allEnabled": false, + "allEnabledUntil": 1735560006385 + }, + "configuration": { + "scriptLang": "TBEL", + "decoder": null, + "tbelDecoder": "var data = decodeToJson(payload);\nvar deviceName = \"EM310-UDL \" + data.devEUI;\nvar deviceType = \"EM310-UDL\";\nvar groupName = null; // If groupName is not null - created device will be added to the entity group with such name.\nvar customerName = null; // If customerName is not null - created devices will be assigned to customer with such name. \n\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// If you want to parse incoming data somehow, you can add your code to this function.\n// input: bytes\n// expected output:\n// {\n// \"attributes\": {\"attributeKey\": \"attributeValue\"},\n// \"telemetry\": [{\"ts\": 1...1, \"values\": {\"telemetryKey\":\"telemetryValue\"}, {\"ts\": 1...2, \"values\": {\"telemetryKey\":\"telemetryValue\"}}]\n// }\n\nfunction decodePayload(input) {\n var output = {\n attributes: {},\n telemetry: []\n };\n \n // --- Decoding code --- //\n var decoded = {};\n var wifi = [];\n var fPort = data.fPort;\n if(fPort == 85) {\n for (var i = 0; i < input.length - 2;) {\n var channel_id = input[i++] & 0xff;\n var channel_type = input[i++] & 0xff;\n \n // BATTERY\n if (channel_id === 0x01 && channel_type === 0x75) {\n decoded.battery = input[i];\n i += 1;\n }\n // DISTANCE\n else if (channel_id === 0x03 && channel_type === 0x82) {\n decoded.distance = parseBytesToInt(input, i, 2, false);\n i += 2;\n }\n // POSITION\n else if (channel_id === 0x04 && channel_type === 0x00) {\n decoded.position = input[i] === 0 ? \"normal\" : \"tilt\";\n i += 1;\n }\n }\n }\n\n output.telemetry = [{\n ts: timestamp,\n values: decoded\n }];\n \n // --- Decoding code --- //\n return output;\n}\n\n// --- attributes and telemetry objects ---\nvar telemetry = [];\nvar attributes = {};\n// --- attributes and telemetry objects ---\n\n// --- Timestamp parsing\nvar dateString = data.time;\ntimestamp = parseDateToTimestamp(dateString);\n// --- Timestamp parsing\n\n// Passing incoming bytes to decodePayload function, to get custom decoding\nvar customDecoding = decodePayload(base64ToBytes(data.data));\n\n// Collecting data to result\nif (customDecoding.?telemetry.size() > 0) {\n foreach(telemetryObj: customDecoding.telemetry) {\n if (telemetryObj.ts != null && telemetryObj.values != null) {\n telemetry.add(telemetryObj);\n }\n }\n}\n\nif (customDecoding.?attributes.size() > 0) {\n attributes.putAll(customDecoding.attributes);\n}\n\n// You can add some keys manually to attributes or telemetry\nattributes.eui = data.?devEui;\nattributes.fPort = data.fPort;\nattributes.applicationId = data.?applicationId;\nattributes.applicationName = data.?applicationName;\nattributes.frequency = data.txInfo.?frequency;\nattributes.bandwidth = data.txInfo.?dataRate.?bandwidth;\nattributes.spreadingFactor = data.txInfo.?dataRate.?spreadFactor;\nattributes.codeRate = data.txInfo.?codeRate;\n\nif(Boolean.parseBoolean(metadata[\"includeGatewayInfo\"])) {\n var gatewayInfo = getGatewayInfo();\n var addDataToTelemetry = {};\n addDataToTelemetry.snr = gatewayInfo.?loRaSNR;\n addDataToTelemetry.rssi = gatewayInfo.rssi;\n addDataToTelemetry.fCnt = data.fCnt;\n \n telemetry = processTelemetryData(telemetry, addDataToTelemetry);\n}\n\nvar result = {\n deviceName: deviceName,\n deviceType: deviceType,\n // assetName: assetName,\n // assetType: assetType,\n attributes: attributes,\n telemetry: telemetry\n};\n\naddAdditionalInfoForDeviceMsg(result, customerName, groupName);\n\nreturn result;\n\nfunction addAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName) {\n if (customerName != null) {\n deviceInfo.customerName = customerName;\n }\n if (groupName != null) {\n deviceInfo.groupName = groupName;\n }\n}\n\nfunction parseDateToTimestamp(dateString) {\n dateString = dateString.replaceFirst(\"(\\\\d{4}-\\\\d{2})(\\\\d{2})\", \"$1-$2\");\n dateString = dateString.replaceFirst(\"\\\\.(\\\\d{3})\\\\d+Z\", \".$1Z\");\n dateString = dateString.replace(\"Z\", \"+0000\");\n var date = new Date(dateString);\n var timestamp = date.getTime();\n \n // If we cannot parse timestamp - we will use the current timestamp\n if (timestamp == -1) {\n timestamp = Date.now();\n }\n \n return timestamp;\n}\n\nfunction getGatewayInfo() {\n var gatewayList = data.rxInfo;\n var maxRssi = Integer.MIN_VALUE;\n var gatewayInfo = {};\n \n foreach (gateway : gatewayList) {\n if(gateway.rssi > maxRssi) {\n maxRssi = gateway.rssi;\n gatewayInfo = gateway;\n }\n }\n \n return gatewayInfo;\n}\n\nfunction processTelemetryData(telemetry, addDataToTelemetry) {\n if (telemetry.size >= 1) {\n telemetry = addDataToTelemetries(telemetry, addDataToTelemetry);\n }\n else {\n telemetry.add(addDataToTelemetry);\n }\n \n return telemetry;\n}\n\nfunction addDataToTelemetries(telemetries, addDataToTelemetry) {\n foreach(telemetry : telemetries) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[\"values\"].keys.contains(element.key)) {\n telemetry[\"values\"][element.key] = element.value;\n }\n } \n }\n \n return telemetries;\n}", + "encoder": null, + "tbelEncoder": null, + "updateOnlyKeys": [ + "fPort", + "applicationName", + "frequency", + "bandwidth", + "spreadingFactor", + "codeRate" + ] + }, + "additionalInfo": { + "description": "" + }, + "edgeTemplate": false +} \ No newline at end of file diff --git a/VENDORS/Milesight/EM310-UDL/HTTP/uplink/metadata.json b/VENDORS/Milesight/EM310-UDL/HTTP/uplink/metadata.json new file mode 100644 index 00000000..87ee6615 --- /dev/null +++ b/VENDORS/Milesight/EM310-UDL/HTTP/uplink/metadata.json @@ -0,0 +1,4 @@ +{ + "integrationName": "HTTP integration", + "includeGatewayInfo": "false" +} \ No newline at end of file diff --git a/VENDORS/Milesight/EM310-UDL/HTTP/uplink/payload.json b/VENDORS/Milesight/EM310-UDL/HTTP/uplink/payload.json new file mode 100644 index 00000000..1202f549 --- /dev/null +++ b/VENDORS/Milesight/EM310-UDL/HTTP/uplink/payload.json @@ -0,0 +1,31 @@ +{ + "applicationID": 1, + "applicationName": "cloud", + "deviceName": "24e1641092176759", + "devEUI": "24e1641092176759", + "time": "2020-0327T12:39:05.547336Z", + "rxInfo": [ + { + "mac": "24e124fffef021be", + "rssi": -57, + "loRaSNR": 10, + "name": "local_gateway", + "latitude": 0, + "longitude": 0, + "altitude": 0 + } + ], + "txInfo": { + "frequency": 868300000, + "dataRate": { + "modulation": "LORA", + "bandwidth": 125, + "spreadFactor": 7 + }, + "adr": false, + "codeRate": "4/5" + }, + "fCnt": 0, + "fPort": 85, + "data": "AXVcA4JECAQAAQ==" +} \ No newline at end of file diff --git a/VENDORS/Milesight/EM310-UDL/HTTP/uplink/result.json b/VENDORS/Milesight/EM310-UDL/HTTP/uplink/result.json new file mode 100644 index 00000000..5df65dfc --- /dev/null +++ b/VENDORS/Milesight/EM310-UDL/HTTP/uplink/result.json @@ -0,0 +1,20 @@ +{ + "deviceName": "EM310-UDL 24e1641092176759", + "deviceType": "EM310-UDL", + "attributes": { + "fPort": 85, + "applicationName": "cloud", + "frequency": 868300000, + "bandwidth": 125, + "spreadingFactor": 7, + "codeRate": "4/5" + }, + "telemetry": [{ + "ts": 1585312745547, + "values": { + "battery": 92, + "distance": 2116, + "position": "tilt" + } + }] +} \ No newline at end of file diff --git a/VENDORS/Milesight/EM320-TILT/HTTP/uplink/converter.json b/VENDORS/Milesight/EM320-TILT/HTTP/uplink/converter.json new file mode 100644 index 00000000..40b0f033 --- /dev/null +++ b/VENDORS/Milesight/EM320-TILT/HTTP/uplink/converter.json @@ -0,0 +1,29 @@ +{ + "name": "HTTP Uplink integration for EM320-TILT", + "type": "UPLINK", + "debugMode": false, + "debugSettings": { + "failuresEnabled": true, + "allEnabled": false, + "allEnabledUntil": 1735560006385 + }, + "configuration": { + "scriptLang": "TBEL", + "decoder": null, + "tbelDecoder": "var data = decodeToJson(payload);\nvar deviceName = \"EM320-TILT \" + data.devEUI;\nvar deviceType = \"EM320-TILT\";\nvar groupName = null; // If groupName is not null - created device will be added to the entity group with such name.\nvar customerName = null; // If customerName is not null - created devices will be assigned to customer with such name. \n\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// If you want to parse incoming data somehow, you can add your code to this function.\n// input: bytes\n// expected output:\n// {\n// \"attributes\": {\"attributeKey\": \"attributeValue\"},\n// \"telemetry\": [{\"ts\": 1...1, \"values\": {\"telemetryKey\":\"telemetryValue\"}, {\"ts\": 1...2, \"values\": {\"telemetryKey\":\"telemetryValue\"}}]\n// }\n\nfunction decodePayload(input) {\n var output = {\n attributes: {},\n telemetry: []\n };\n \n // --- Decoding code --- //\n var decoded = {};\n var wifi = [];\n var fPort = data.fPort;\n if(fPort == 85) {\n for (var i = 0; i < input.length - 2;) {\n var channel_id = input[i++] & 0xff;\n var channel_type = input[i++] & 0xff;\n \n // BATTERY\n if (channel_id === 0x01 && channel_type === 0x75) {\n decoded.battery = input[i];\n i += 1;\n }\n // ANGLE\n else if (channel_id === 0x03 && channel_type === 0xd4) {\n decoded.angle_x = (((input[i] & 0xFF) | (input[i + 1] << 8)) >> 1) / 100;\n decoded.angle_y = (((input[i + 2] & 0xFF) | (input[i + 3] << 8)) >> 1) / 100;\n decoded.angle_z = (((input[i + 4] & 0xFF) | (input[i + 5] << 8)) >> 1) / 100;\n decoded.threshold_x = (input[i] & 0x01) === 0x01 ? \"trigger\" : \"normal\";\n decoded.threshold_y = (input[i + 2] & 0x01) === 0x01 ? \"trigger\" : \"normal\";\n decoded.threshold_z = (input[i + 4] & 0x01) === 0x01 ? \"trigger\" : \"normal\";\n i += 6;\n }\n }\n }\n\n output.telemetry = [{\n ts: timestamp,\n values: decoded\n }];\n \n // --- Decoding code --- //\n return output;\n}\n\n// --- attributes and telemetry objects ---\nvar telemetry = [];\nvar attributes = {};\n// --- attributes and telemetry objects ---\n\n// --- Timestamp parsing\nvar dateString = data.time;\ntimestamp = parseDateToTimestamp(dateString);\n// --- Timestamp parsing\n\n// Passing incoming bytes to decodePayload function, to get custom decoding\nvar customDecoding = decodePayload(base64ToBytes(data.data));\n\n// Collecting data to result\nif (customDecoding.?telemetry.size() > 0) {\n foreach(telemetryObj: customDecoding.telemetry) {\n if (telemetryObj.ts != null && telemetryObj.values != null) {\n telemetry.add(telemetryObj);\n }\n }\n}\n\nif (customDecoding.?attributes.size() > 0) {\n attributes.putAll(customDecoding.attributes);\n}\n\n// You can add some keys manually to attributes or telemetry\nattributes.eui = data.?devEui;\nattributes.fPort = data.fPort;\nattributes.applicationId = data.?applicationId;\nattributes.applicationName = data.?applicationName;\nattributes.frequency = data.txInfo.?frequency;\nattributes.bandwidth = data.txInfo.?dataRate.?bandwidth;\nattributes.spreadingFactor = data.txInfo.?dataRate.?spreadFactor;\nattributes.codeRate = data.txInfo.?codeRate;\n\nif(Boolean.parseBoolean(metadata[\"includeGatewayInfo\"])) {\n var gatewayInfo = getGatewayInfo();\n var addDataToTelemetry = {};\n addDataToTelemetry.snr = gatewayInfo.?loRaSNR;\n addDataToTelemetry.rssi = gatewayInfo.rssi;\n addDataToTelemetry.fCnt = data.fCnt;\n \n telemetry = processTelemetryData(telemetry, addDataToTelemetry);\n}\n\nvar result = {\n deviceName: deviceName,\n deviceType: deviceType,\n // assetName: assetName,\n // assetType: assetType,\n attributes: attributes,\n telemetry: telemetry\n};\n\naddAdditionalInfoForDeviceMsg(result, customerName, groupName);\n\nreturn result;\n\nfunction addAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName) {\n if (customerName != null) {\n deviceInfo.customerName = customerName;\n }\n if (groupName != null) {\n deviceInfo.groupName = groupName;\n }\n}\n\nfunction parseDateToTimestamp(dateString) {\n dateString = dateString.replaceFirst(\"(\\\\d{4}-\\\\d{2})(\\\\d{2})\", \"$1-$2\");\n dateString = dateString.replaceFirst(\"\\\\.(\\\\d{3})\\\\d+Z\", \".$1Z\");\n dateString = dateString.replace(\"Z\", \"+0000\");\n var date = new Date(dateString);\n var timestamp = date.getTime();\n \n // If we cannot parse timestamp - we will use the current timestamp\n if (timestamp == -1) {\n timestamp = Date.now();\n }\n \n return timestamp;\n}\n\nfunction getGatewayInfo() {\n var gatewayList = data.rxInfo;\n var maxRssi = Integer.MIN_VALUE;\n var gatewayInfo = {};\n \n foreach (gateway : gatewayList) {\n if(gateway.rssi > maxRssi) {\n maxRssi = gateway.rssi;\n gatewayInfo = gateway;\n }\n }\n \n return gatewayInfo;\n}\n\nfunction processTelemetryData(telemetry, addDataToTelemetry) {\n if (telemetry.size >= 1) {\n telemetry = addDataToTelemetries(telemetry, addDataToTelemetry);\n }\n else {\n telemetry.add(addDataToTelemetry);\n }\n \n return telemetry;\n}\n\nfunction addDataToTelemetries(telemetries, addDataToTelemetry) {\n foreach(telemetry : telemetries) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[\"values\"].keys.contains(element.key)) {\n telemetry[\"values\"][element.key] = element.value;\n }\n } \n }\n \n return telemetries;\n}", + "encoder": null, + "tbelEncoder": null, + "updateOnlyKeys": [ + "fPort", + "applicationName", + "frequency", + "bandwidth", + "spreadingFactor", + "codeRate" + ] + }, + "additionalInfo": { + "description": "" + }, + "edgeTemplate": false +} \ No newline at end of file diff --git a/VENDORS/Milesight/EM320-TILT/HTTP/uplink/metadata.json b/VENDORS/Milesight/EM320-TILT/HTTP/uplink/metadata.json new file mode 100644 index 00000000..87ee6615 --- /dev/null +++ b/VENDORS/Milesight/EM320-TILT/HTTP/uplink/metadata.json @@ -0,0 +1,4 @@ +{ + "integrationName": "HTTP integration", + "includeGatewayInfo": "false" +} \ No newline at end of file diff --git a/VENDORS/Milesight/EM320-TILT/HTTP/uplink/payload.json b/VENDORS/Milesight/EM320-TILT/HTTP/uplink/payload.json new file mode 100644 index 00000000..ffc45489 --- /dev/null +++ b/VENDORS/Milesight/EM320-TILT/HTTP/uplink/payload.json @@ -0,0 +1,31 @@ +{ + "applicationID": 1, + "applicationName": "cloud", + "deviceName": "24e1641092176759", + "devEUI": "24e1641092176759", + "time": "2020-0327T12:39:05.547336Z", + "rxInfo": [ + { + "mac": "24e124fffef021be", + "rssi": -57, + "loRaSNR": 10, + "name": "local_gateway", + "latitude": 0, + "longitude": 0, + "altitude": 0 + } + ], + "txInfo": { + "frequency": 868300000, + "dataRate": { + "modulation": "LORA", + "bandwidth": 125, + "spreadFactor": 7 + }, + "adr": false, + "codeRate": "4/5" + }, + "fCnt": 0, + "fPort": 85, + "data": "AXVkA9QAAAEAUEY=" +} \ No newline at end of file diff --git a/VENDORS/Milesight/EM320-TILT/HTTP/uplink/result.json b/VENDORS/Milesight/EM320-TILT/HTTP/uplink/result.json new file mode 100644 index 00000000..2ee3b947 --- /dev/null +++ b/VENDORS/Milesight/EM320-TILT/HTTP/uplink/result.json @@ -0,0 +1,24 @@ +{ + "deviceName": "EM320-TILT 24e1641092176759", + "deviceType": "EM320-TILT", + "attributes": { + "fPort": 85, + "applicationName": "cloud", + "frequency": 868300000, + "bandwidth": 125, + "spreadingFactor": 7, + "codeRate": "4/5" + }, + "telemetry": [{ + "ts": 1585312745547, + "values": { + "battery": 100, + "angle_x": 0, + "angle_y": 0, + "angle_z": 90, + "threshold_x": "normal", + "threshold_y": "trigger", + "threshold_z": "normal" + } + }] +} \ No newline at end of file diff --git a/VENDORS/Milesight/EM400-TLD/HTTP/uplink/converter.json b/VENDORS/Milesight/EM400-TLD/HTTP/uplink/converter.json new file mode 100644 index 00000000..94042d51 --- /dev/null +++ b/VENDORS/Milesight/EM400-TLD/HTTP/uplink/converter.json @@ -0,0 +1,29 @@ +{ + "name": "HTTP Uplink integration for EM400-TLD", + "type": "UPLINK", + "debugMode": false, + "debugSettings": { + "failuresEnabled": true, + "allEnabled": false, + "allEnabledUntil": 1735560006385 + }, + "configuration": { + "scriptLang": "TBEL", + "decoder": null, + "tbelDecoder": "var data = decodeToJson(payload);\nvar deviceName = \"EM400-TLD \" + data.devEUI;\nvar deviceType = \"EM400-TLD\";\nvar groupName = null; // If groupName is not null - created device will be added to the entity group with such name.\nvar customerName = null; // If customerName is not null - created devices will be assigned to customer with such name. \n\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// If you want to parse incoming data somehow, you can add your code to this function.\n// input: bytes\n// expected output:\n// {\n// \"attributes\": {\"attributeKey\": \"attributeValue\"},\n// \"telemetry\": [{\"ts\": 1...1, \"values\": {\"telemetryKey\":\"telemetryValue\"}, {\"ts\": 1...2, \"values\": {\"telemetryKey\":\"telemetryValue\"}}]\n// }\n\nfunction decodePayload(input) {\n var output = {\n attributes: {},\n telemetry: []\n };\n \n // --- Decoding code --- //\n var decoded = {};\n var wifi = [];\n var fPort = data.fPort;\n if(fPort == 85) {\n for (var i = 0; i < input.length - 2;) {\n var channel_id = input[i++] & 0xff;\n var channel_type = input[i++] & 0xff;\n \n // BATTERY\n if (channel_id === 0x01 && channel_type === 0x75) {\n decoded.battery = input[i];\n i += 1;\n }\n // TEMPERATURE\n else if (channel_id === 0x03 && channel_type === 0x67) {\n decoded.temperature = parseBytesToInt(input, i, 2, false) / 10;\n i += 2;\n }\n // DISTANCE\n else if (channel_id === 0x04 && channel_type === 0x82) {\n decoded.distance = parseBytesToInt(input, i, 2, false);\n i += 2;\n }\n // POSITION\n else if (channel_id === 0x05 && channel_type === 0x00) {\n decoded.position = input[i] === 0 ? \"normal\" : \"tilt\";\n i += 1;\n }\n // TEMPERATURE WITH ABNORMAL\n else if (channel_id === 0x83 && channel_type === 0x67) {\n decoded.temperature = parseBytesToInt(input, i, 2, false) / 10;\n decoded.temperature_abnormal = input[i + 2] == 0 ? false : true;\n i += 3;\n }\n // DISTANCE WITH ALARMING\n else if (channel_id === 0x84 && channel_type === 0x82) {\n decoded.distance = parseBytesToInt(input, i, 2, false);\n decoded.distance_alarming = input[i + 2] == 0 ? false : true;\n i += 3;\n }\n }\n }\n\n output.telemetry = [{\n ts: timestamp,\n values: decoded\n }];\n \n // --- Decoding code --- //\n return output;\n}\n\n// --- attributes and telemetry objects ---\nvar telemetry = [];\nvar attributes = {};\n// --- attributes and telemetry objects ---\n\n// --- Timestamp parsing\nvar dateString = data.time;\ntimestamp = parseDateToTimestamp(dateString);\n// --- Timestamp parsing\n\n// Passing incoming bytes to decodePayload function, to get custom decoding\nvar customDecoding = decodePayload(base64ToBytes(data.data));\n\n// Collecting data to result\nif (customDecoding.?telemetry.size() > 0) {\n foreach(telemetryObj: customDecoding.telemetry) {\n if (telemetryObj.ts != null && telemetryObj.values != null) {\n telemetry.add(telemetryObj);\n }\n }\n}\n\nif (customDecoding.?attributes.size() > 0) {\n attributes.putAll(customDecoding.attributes);\n}\n\n// You can add some keys manually to attributes or telemetry\nattributes.eui = data.?devEui;\nattributes.fPort = data.fPort;\nattributes.applicationId = data.?applicationId;\nattributes.applicationName = data.?applicationName;\nattributes.frequency = data.txInfo.?frequency;\nattributes.bandwidth = data.txInfo.?dataRate.?bandwidth;\nattributes.spreadingFactor = data.txInfo.?dataRate.?spreadFactor;\nattributes.codeRate = data.txInfo.?codeRate;\n\nif(Boolean.parseBoolean(metadata[\"includeGatewayInfo\"])) {\n var gatewayInfo = getGatewayInfo();\n var addDataToTelemetry = {};\n addDataToTelemetry.snr = gatewayInfo.?loRaSNR;\n addDataToTelemetry.rssi = gatewayInfo.rssi;\n addDataToTelemetry.fCnt = data.fCnt;\n \n telemetry = processTelemetryData(telemetry, addDataToTelemetry);\n}\n\nvar result = {\n deviceName: deviceName,\n deviceType: deviceType,\n // assetName: assetName,\n // assetType: assetType,\n attributes: attributes,\n telemetry: telemetry\n};\n\naddAdditionalInfoForDeviceMsg(result, customerName, groupName);\n\nreturn result;\n\nfunction addAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName) {\n if (customerName != null) {\n deviceInfo.customerName = customerName;\n }\n if (groupName != null) {\n deviceInfo.groupName = groupName;\n }\n}\n\nfunction parseDateToTimestamp(dateString) {\n dateString = dateString.replaceFirst(\"(\\\\d{4}-\\\\d{2})(\\\\d{2})\", \"$1-$2\");\n dateString = dateString.replaceFirst(\"\\\\.(\\\\d{3})\\\\d+Z\", \".$1Z\");\n dateString = dateString.replace(\"Z\", \"+0000\");\n var date = new Date(dateString);\n var timestamp = date.getTime();\n \n // If we cannot parse timestamp - we will use the current timestamp\n if (timestamp == -1) {\n timestamp = Date.now();\n }\n \n return timestamp;\n}\n\nfunction getGatewayInfo() {\n var gatewayList = data.rxInfo;\n var maxRssi = Integer.MIN_VALUE;\n var gatewayInfo = {};\n \n foreach (gateway : gatewayList) {\n if(gateway.rssi > maxRssi) {\n maxRssi = gateway.rssi;\n gatewayInfo = gateway;\n }\n }\n \n return gatewayInfo;\n}\n\nfunction processTelemetryData(telemetry, addDataToTelemetry) {\n if (telemetry.size >= 1) {\n telemetry = addDataToTelemetries(telemetry, addDataToTelemetry);\n }\n else {\n telemetry.add(addDataToTelemetry);\n }\n \n return telemetry;\n}\n\nfunction addDataToTelemetries(telemetries, addDataToTelemetry) {\n foreach(telemetry : telemetries) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[\"values\"].keys.contains(element.key)) {\n telemetry[\"values\"][element.key] = element.value;\n }\n } \n }\n \n return telemetries;\n}", + "encoder": null, + "tbelEncoder": null, + "updateOnlyKeys": [ + "fPort", + "applicationName", + "frequency", + "bandwidth", + "spreadingFactor", + "codeRate" + ] + }, + "additionalInfo": { + "description": "" + }, + "edgeTemplate": false +} \ No newline at end of file diff --git a/VENDORS/Milesight/EM400-TLD/HTTP/uplink/metadata.json b/VENDORS/Milesight/EM400-TLD/HTTP/uplink/metadata.json new file mode 100644 index 00000000..87ee6615 --- /dev/null +++ b/VENDORS/Milesight/EM400-TLD/HTTP/uplink/metadata.json @@ -0,0 +1,4 @@ +{ + "integrationName": "HTTP integration", + "includeGatewayInfo": "false" +} \ No newline at end of file diff --git a/VENDORS/Milesight/EM400-TLD/HTTP/uplink/payload.json b/VENDORS/Milesight/EM400-TLD/HTTP/uplink/payload.json new file mode 100644 index 00000000..3fe39aa1 --- /dev/null +++ b/VENDORS/Milesight/EM400-TLD/HTTP/uplink/payload.json @@ -0,0 +1,31 @@ +{ + "applicationID": 1, + "applicationName": "cloud", + "deviceName": "24e1641092176759", + "devEUI": "24e1641092176759", + "time": "2020-0327T12:39:05.547336Z", + "rxInfo": [ + { + "mac": "24e124fffef021be", + "rssi": -57, + "loRaSNR": 10, + "name": "local_gateway", + "latitude": 0, + "longitude": 0, + "altitude": 0 + } + ], + "txInfo": { + "frequency": 868300000, + "dataRate": { + "modulation": "LORA", + "bandwidth": 125, + "spreadFactor": 7 + }, + "adr": false, + "codeRate": "4/5" + }, + "fCnt": 0, + "fPort": 85, + "data": "g2foAAGEgkEGAQ==" +} \ No newline at end of file diff --git a/VENDORS/Milesight/EM400-TLD/HTTP/uplink/result.json b/VENDORS/Milesight/EM400-TLD/HTTP/uplink/result.json new file mode 100644 index 00000000..888add00 --- /dev/null +++ b/VENDORS/Milesight/EM400-TLD/HTTP/uplink/result.json @@ -0,0 +1,21 @@ +{ + "deviceName": "EM400-TLD 24e1641092176759", + "deviceType": "EM400-TLD", + "attributes": { + "fPort": 85, + "applicationName": "cloud", + "frequency": 868300000, + "bandwidth": 125, + "spreadingFactor": 7, + "codeRate": "4/5" + }, + "telemetry": [{ + "ts": 1585312745547, + "values": { + "temperature": 23.2, + "temperature_abnormal": true, + "distance": 1601, + "distance_alarming": true + } + }] +} \ No newline at end of file diff --git a/VENDORS/Milesight/EM400-UDL/HTTP/uplink/converter.json b/VENDORS/Milesight/EM400-UDL/HTTP/uplink/converter.json new file mode 100644 index 00000000..0f6c53c9 --- /dev/null +++ b/VENDORS/Milesight/EM400-UDL/HTTP/uplink/converter.json @@ -0,0 +1,29 @@ +{ + "name": "HTTP Uplink integration for EM400-UDL", + "type": "UPLINK", + "debugMode": false, + "debugSettings": { + "failuresEnabled": true, + "allEnabled": false, + "allEnabledUntil": 1735560006385 + }, + "configuration": { + "scriptLang": "TBEL", + "decoder": null, + "tbelDecoder": "var data = decodeToJson(payload);\nvar deviceName = \"EM400-UDL \" + data.devEUI;\nvar deviceType = \"EM400-UDL\";\nvar groupName = null; // If groupName is not null - created device will be added to the entity group with such name.\nvar customerName = null; // If customerName is not null - created devices will be assigned to customer with such name. \n\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// If you want to parse incoming data somehow, you can add your code to this function.\n// input: bytes\n// expected output:\n// {\n// \"attributes\": {\"attributeKey\": \"attributeValue\"},\n// \"telemetry\": [{\"ts\": 1...1, \"values\": {\"telemetryKey\":\"telemetryValue\"}, {\"ts\": 1...2, \"values\": {\"telemetryKey\":\"telemetryValue\"}}]\n// }\n\nfunction decodePayload(input) {\n var output = {\n attributes: {},\n telemetry: []\n };\n \n // --- Decoding code --- //\n var decoded = {};\n var wifi = [];\n var fPort = data.fPort;\n if(fPort == 85) {\n for (var i = 0; i < input.length - 2;) {\n var channel_id = input[i++] & 0xff;\n var channel_type = input[i++] & 0xff;\n \n // BATTERY\n if (channel_id === 0x01 && channel_type === 0x75) {\n decoded.battery = input[i];\n i += 1;\n }\n // TEMPERATURE\n else if (channel_id === 0x03 && channel_type === 0x67) {\n decoded.temperature = parseBytesToInt(input, i, 2, false) / 10;\n i += 2;\n }\n // DISTANCE\n else if (channel_id === 0x04 && channel_type === 0x82) {\n decoded.distance = parseBytesToInt(input, i, 2, false);\n i += 2;\n }\n // POSITION\n else if (channel_id === 0x05 && channel_type === 0x00) {\n decoded.position = input[i] === 0 ? \"normal\" : \"tilt\";\n i += 1;\n }\n // TEMPERATURE WITH ABNORMAL\n else if (channel_id === 0x83 && channel_type === 0x67) {\n decoded.temperature = parseBytesToInt(input, i, 2, false) / 10;\n decoded.temperature_abnormal = input[i + 2] == 0 ? false : true;\n i += 3;\n }\n // DISTANCE WITH ALARMING\n else if (channel_id === 0x84 && channel_type === 0x82) {\n decoded.distance = parseBytesToInt(input, i, 2, false);\n decoded.distance_alarming = input[i + 2] == 0 ? false : true;\n i += 3;\n }\n }\n }\n\n output.telemetry = [{\n ts: timestamp,\n values: decoded\n }];\n \n // --- Decoding code --- //\n return output;\n}\n\n// --- attributes and telemetry objects ---\nvar telemetry = [];\nvar attributes = {};\n// --- attributes and telemetry objects ---\n\n// --- Timestamp parsing\nvar dateString = data.time;\ntimestamp = parseDateToTimestamp(dateString);\n// --- Timestamp parsing\n\n// Passing incoming bytes to decodePayload function, to get custom decoding\nvar customDecoding = decodePayload(base64ToBytes(data.data));\n\n// Collecting data to result\nif (customDecoding.?telemetry.size() > 0) {\n foreach(telemetryObj: customDecoding.telemetry) {\n if (telemetryObj.ts != null && telemetryObj.values != null) {\n telemetry.add(telemetryObj);\n }\n }\n}\n\nif (customDecoding.?attributes.size() > 0) {\n attributes.putAll(customDecoding.attributes);\n}\n\n// You can add some keys manually to attributes or telemetry\nattributes.eui = data.?devEui;\nattributes.fPort = data.fPort;\nattributes.applicationId = data.?applicationId;\nattributes.applicationName = data.?applicationName;\nattributes.frequency = data.txInfo.?frequency;\nattributes.bandwidth = data.txInfo.?dataRate.?bandwidth;\nattributes.spreadingFactor = data.txInfo.?dataRate.?spreadFactor;\nattributes.codeRate = data.txInfo.?codeRate;\n\nif(Boolean.parseBoolean(metadata[\"includeGatewayInfo\"])) {\n var gatewayInfo = getGatewayInfo();\n var addDataToTelemetry = {};\n addDataToTelemetry.snr = gatewayInfo.?loRaSNR;\n addDataToTelemetry.rssi = gatewayInfo.rssi;\n addDataToTelemetry.fCnt = data.fCnt;\n \n telemetry = processTelemetryData(telemetry, addDataToTelemetry);\n}\n\nvar result = {\n deviceName: deviceName,\n deviceType: deviceType,\n // assetName: assetName,\n // assetType: assetType,\n attributes: attributes,\n telemetry: telemetry\n};\n\naddAdditionalInfoForDeviceMsg(result, customerName, groupName);\n\nreturn result;\n\nfunction addAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName) {\n if (customerName != null) {\n deviceInfo.customerName = customerName;\n }\n if (groupName != null) {\n deviceInfo.groupName = groupName;\n }\n}\n\nfunction parseDateToTimestamp(dateString) {\n dateString = dateString.replaceFirst(\"(\\\\d{4}-\\\\d{2})(\\\\d{2})\", \"$1-$2\");\n dateString = dateString.replaceFirst(\"\\\\.(\\\\d{3})\\\\d+Z\", \".$1Z\");\n dateString = dateString.replace(\"Z\", \"+0000\");\n var date = new Date(dateString);\n var timestamp = date.getTime();\n \n // If we cannot parse timestamp - we will use the current timestamp\n if (timestamp == -1) {\n timestamp = Date.now();\n }\n \n return timestamp;\n}\n\nfunction getGatewayInfo() {\n var gatewayList = data.rxInfo;\n var maxRssi = Integer.MIN_VALUE;\n var gatewayInfo = {};\n \n foreach (gateway : gatewayList) {\n if(gateway.rssi > maxRssi) {\n maxRssi = gateway.rssi;\n gatewayInfo = gateway;\n }\n }\n \n return gatewayInfo;\n}\n\nfunction processTelemetryData(telemetry, addDataToTelemetry) {\n if (telemetry.size >= 1) {\n telemetry = addDataToTelemetries(telemetry, addDataToTelemetry);\n }\n else {\n telemetry.add(addDataToTelemetry);\n }\n \n return telemetry;\n}\n\nfunction addDataToTelemetries(telemetries, addDataToTelemetry) {\n foreach(telemetry : telemetries) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[\"values\"].keys.contains(element.key)) {\n telemetry[\"values\"][element.key] = element.value;\n }\n } \n }\n \n return telemetries;\n}", + "encoder": null, + "tbelEncoder": null, + "updateOnlyKeys": [ + "fPort", + "applicationName", + "frequency", + "bandwidth", + "spreadingFactor", + "codeRate" + ] + }, + "additionalInfo": { + "description": "" + }, + "edgeTemplate": false +} \ No newline at end of file diff --git a/VENDORS/Milesight/EM400-UDL/HTTP/uplink/metadata.json b/VENDORS/Milesight/EM400-UDL/HTTP/uplink/metadata.json new file mode 100644 index 00000000..87ee6615 --- /dev/null +++ b/VENDORS/Milesight/EM400-UDL/HTTP/uplink/metadata.json @@ -0,0 +1,4 @@ +{ + "integrationName": "HTTP integration", + "includeGatewayInfo": "false" +} \ No newline at end of file diff --git a/VENDORS/Milesight/EM400-UDL/HTTP/uplink/payload.json b/VENDORS/Milesight/EM400-UDL/HTTP/uplink/payload.json new file mode 100644 index 00000000..b559a7d6 --- /dev/null +++ b/VENDORS/Milesight/EM400-UDL/HTTP/uplink/payload.json @@ -0,0 +1,31 @@ +{ + "applicationID": 1, + "applicationName": "cloud", + "deviceName": "24e1641092176759", + "devEUI": "24e1641092176759", + "time": "2020-0327T12:39:05.547336Z", + "rxInfo": [ + { + "mac": "24e124fffef021be", + "rssi": -57, + "loRaSNR": 10, + "name": "local_gateway", + "latitude": 0, + "longitude": 0, + "altitude": 0 + } + ], + "txInfo": { + "frequency": 868300000, + "dataRate": { + "modulation": "LORA", + "bandwidth": 125, + "spreadFactor": 7 + }, + "adr": false, + "codeRate": "4/5" + }, + "fCnt": 0, + "fPort": 85, + "data": "AXVcA2cBAQSCRAgFAAE=" +} \ No newline at end of file diff --git a/VENDORS/Milesight/EM400-UDL/HTTP/uplink/result.json b/VENDORS/Milesight/EM400-UDL/HTTP/uplink/result.json new file mode 100644 index 00000000..34bba608 --- /dev/null +++ b/VENDORS/Milesight/EM400-UDL/HTTP/uplink/result.json @@ -0,0 +1,21 @@ +{ + "deviceName": "EM400-UDL 24e1641092176759", + "deviceType": "EM400-UDL", + "attributes": { + "fPort": 85, + "applicationName": "cloud", + "frequency": 868300000, + "bandwidth": 125, + "spreadingFactor": 7, + "codeRate": "4/5" + }, + "telemetry": [{ + "ts": 1585312745547, + "values": { + "battery": 92, + "temperature": 25.7, + "distance": 2116, + "position": "tilt" + } + }] +} \ No newline at end of file diff --git a/VENDORS/Milesight/EM500-CO2/HTTP/uplink/converter.json b/VENDORS/Milesight/EM500-CO2/HTTP/uplink/converter.json new file mode 100644 index 00000000..de2f47c1 --- /dev/null +++ b/VENDORS/Milesight/EM500-CO2/HTTP/uplink/converter.json @@ -0,0 +1,29 @@ +{ + "name": "HTTP Uplink integration for EM500-C02", + "type": "UPLINK", + "debugMode": false, + "debugSettings": { + "failuresEnabled": true, + "allEnabled": false, + "allEnabledUntil": 1735560006385 + }, + "configuration": { + "scriptLang": "TBEL", + "decoder": null, + "tbelDecoder": "var data = decodeToJson(payload);\nvar deviceName = \"EM500-C02 \" + data.devEUI;\nvar deviceType = \"EM500-C02\";\nvar groupName = null; // If groupName is not null - created device will be added to the entity group with such name.\nvar customerName = null; // If customerName is not null - created devices will be assigned to customer with such name. \n\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// If you want to parse incoming data somehow, you can add your code to this function.\n// input: bytes\n// expected output:\n// {\n// \"attributes\": {\"attributeKey\": \"attributeValue\"},\n// \"telemetry\": [{\"ts\": 1...1, \"values\": {\"telemetryKey\":\"telemetryValue\"}, {\"ts\": 1...2, \"values\": {\"telemetryKey\":\"telemetryValue\"}}]\n// }\n\nfunction decodePayload(input) {\n var output = {\n attributes: {},\n telemetry: []\n };\n \n // --- Decoding code --- //\n var decoded = {};\n var wifi = [];\n var fPort = data.fPort;\n var historyDataList = [];\n if(fPort == 85) {\n for (var i = 0; i < input.length - 2;) {\n var channel_id = input[i++] & 0xff;\n var channel_type = input[i++] & 0xff;\n \n // BATTERY\n if (channel_id === 0x01 && channel_type === 0x75) {\n decoded.battery = input[i];\n i += 1;\n }\n // TEMPERATURE\n else if (channel_id === 0x03 && channel_type === 0x67) {\n decoded.temperature = parseBytesToInt(input, i, 2, false) / 10;\n i += 2;\n \n // ℉\n // decoded.temperature = parseBytesToInt(input, i, 2, false) / 10 * 1.8 + 32;\n // i +=2;\n }\n // HUMIDITY\n else if (channel_id === 0x04 && channel_type === 0x68) {\n decoded.humidity = parseBytesToInt(input, i, 1, false) / 2;\n i += 1;\n }\n // CO2\n else if (channel_id === 0x05 && channel_type === 0x7d) {\n decoded.co2 = parseBytesToInt(input, i, 2, false);\n i += 2;\n }\n // PRESSURE\n else if (channel_id === 0x06 && channel_type === 0x73) {\n decoded.pressure = parseBytesToInt(input, i, 2, false) / 10;\n i += 2;\n }\n // TEMPERATURE CHANGE ALARM\n else if (channel_id === 0x83 && channel_type === 0xd7) {\n decoded.temperature = parseBytesToInt(input, i, 2, false) / 10;\n decoded.temperature_change = parseBytesToInt(input, i + 2, 2, false) / 10;\n decoded.temperature_alarm = readTemperatureAlarm(input[i + 4]);\n i += 5;\n }\n // HISTROY\n else if (channel_id === 0x20 && channel_type === 0xce) {\n var historyData = {\n ts: parseBytesToInt(input, i, 4, false) * 1000,\n values: {\n co2: parseBytesToInt(input, i + 4, 2, false),\n pressure: parseBytesToInt(input, i + 6, 1, false) / 10,\n temperature: parseBytesToInt(input, i + 8, 2, false) / 10,\n humidity: parseBytesToInt(input, i + 10, 1, false, false) / 2\n }\n };\n i += 11;\n \n historyDataList.add(historyData);\n }\n }\n }\n\n output.telemetry = [{\n ts: timestamp,\n values: decoded\n }];\n \n output.telemetry.addAll(historyDataList);\n // --- Decoding code --- //\n return output;\n}\n\n// --- attributes and telemetry objects ---\nvar telemetry = [];\nvar attributes = {};\n// --- attributes and telemetry objects ---\n\n// --- Timestamp parsing\nvar dateString = data.time;\ntimestamp = parseDateToTimestamp(dateString);\n// --- Timestamp parsing\n\n// Passing incoming bytes to decodePayload function, to get custom decoding\nvar customDecoding = decodePayload(base64ToBytes(data.data));\n\n// Collecting data to result\nif (customDecoding.?telemetry.size() > 0) {\n foreach(telemetryObj: customDecoding.telemetry) {\n if (telemetryObj.ts != null && telemetryObj.values != null) {\n telemetry.add(telemetryObj);\n }\n }\n}\n\nif (customDecoding.?attributes.size() > 0) {\n attributes.putAll(customDecoding.attributes);\n}\n\n// You can add some keys manually to attributes or telemetry\nattributes.eui = data.?devEui;\nattributes.fPort = data.fPort;\nattributes.applicationId = data.?applicationId;\nattributes.applicationName = data.?applicationName;\nattributes.frequency = data.txInfo.?frequency;\nattributes.bandwidth = data.txInfo.?dataRate.?bandwidth;\nattributes.spreadingFactor = data.txInfo.?dataRate.?spreadFactor;\nattributes.codeRate = data.txInfo.?codeRate;\n\nif(Boolean.parseBoolean(metadata[\"includeGatewayInfo\"])) {\n var gatewayInfo = getGatewayInfo();\n var addDataToTelemetry = {};\n addDataToTelemetry.snr = gatewayInfo.?loRaSNR;\n addDataToTelemetry.rssi = gatewayInfo.rssi;\n addDataToTelemetry.fCnt = data.fCnt;\n \n telemetry = processTelemetryData(telemetry, addDataToTelemetry);\n}\n\nvar result = {\n deviceName: deviceName,\n deviceType: deviceType,\n // assetName: assetName,\n // assetType: assetType,\n attributes: attributes,\n telemetry: telemetry\n};\n\naddAdditionalInfoForDeviceMsg(result, customerName, groupName);\n\nreturn result;\n\nfunction addAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName) {\n if (customerName != null) {\n deviceInfo.customerName = customerName;\n }\n if (groupName != null) {\n deviceInfo.groupName = groupName;\n }\n}\n\nfunction parseDateToTimestamp(dateString) {\n dateString = dateString.replaceFirst(\"(\\\\d{4}-\\\\d{2})(\\\\d{2})\", \"$1-$2\");\n dateString = dateString.replaceFirst(\"\\\\.(\\\\d{3})\\\\d+Z\", \".$1Z\");\n dateString = dateString.replace(\"Z\", \"+0000\");\n var date = new Date(dateString);\n var timestamp = date.getTime();\n \n // If we cannot parse timestamp - we will use the current timestamp\n if (timestamp == -1) {\n timestamp = Date.now();\n }\n \n return timestamp;\n}\n\nfunction getGatewayInfo() {\n var gatewayList = data.rxInfo;\n var maxRssi = Integer.MIN_VALUE;\n var gatewayInfo = {};\n \n foreach (gateway : gatewayList) {\n if(gateway.rssi > maxRssi) {\n maxRssi = gateway.rssi;\n gatewayInfo = gateway;\n }\n }\n \n return gatewayInfo;\n}\n\nfunction processTelemetryData(telemetry, addDataToTelemetry) {\n if (telemetry.size >= 1) {\n telemetry = addDataToTelemetries(telemetry, addDataToTelemetry);\n }\n else {\n telemetry.add(addDataToTelemetry);\n }\n \n return telemetry;\n}\n\nfunction addDataToTelemetries(telemetries, addDataToTelemetry) {\n foreach(telemetry : telemetries) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[\"values\"].keys.contains(element.key)) {\n telemetry[\"values\"][element.key] = element.value;\n }\n } \n }\n \n return telemetries;\n}\n\nfunction readTemperatureAlarm(type) {\n switch (type) {\n case 0:\n return \"threshold alarm\";\n case 1:\n return \"threshold alarm release\";\n case 2:\n return \"mutation alarm\";\n default:\n return \"unkown\";\n }\n}", + "encoder": null, + "tbelEncoder": null, + "updateOnlyKeys": [ + "fPort", + "applicationName", + "frequency", + "bandwidth", + "spreadingFactor", + "codeRate" + ] + }, + "additionalInfo": { + "description": "" + }, + "edgeTemplate": false +} \ No newline at end of file diff --git a/VENDORS/Milesight/EM500-CO2/HTTP/uplink/metadata.json b/VENDORS/Milesight/EM500-CO2/HTTP/uplink/metadata.json new file mode 100644 index 00000000..87ee6615 --- /dev/null +++ b/VENDORS/Milesight/EM500-CO2/HTTP/uplink/metadata.json @@ -0,0 +1,4 @@ +{ + "integrationName": "HTTP integration", + "includeGatewayInfo": "false" +} \ No newline at end of file diff --git a/VENDORS/Milesight/EM500-CO2/HTTP/uplink/payload.json b/VENDORS/Milesight/EM500-CO2/HTTP/uplink/payload.json new file mode 100644 index 00000000..0cca0e50 --- /dev/null +++ b/VENDORS/Milesight/EM500-CO2/HTTP/uplink/payload.json @@ -0,0 +1,31 @@ +{ + "applicationID": 1, + "applicationName": "cloud", + "deviceName": "24e1641092176759", + "devEUI": "24e1641092176759", + "time": "2020-0327T12:39:05.547336Z", + "rxInfo": [ + { + "mac": "24e124fffef021be", + "rssi": -57, + "loRaSNR": 10, + "name": "local_gateway", + "latitude": 0, + "longitude": 0, + "altitude": 0 + } + ], + "txInfo": { + "frequency": 868300000, + "dataRate": { + "modulation": "LORA", + "bandwidth": 125, + "spreadFactor": 7 + }, + "adr": false, + "codeRate": "4/5" + }, + "fCnt": 0, + "fPort": 85, + "data": "AXVkA2cZAQRocwV9ZwQGc2gn" +} \ No newline at end of file diff --git a/VENDORS/Milesight/EM500-CO2/HTTP/uplink/result.json b/VENDORS/Milesight/EM500-CO2/HTTP/uplink/result.json new file mode 100644 index 00000000..82a4dda7 --- /dev/null +++ b/VENDORS/Milesight/EM500-CO2/HTTP/uplink/result.json @@ -0,0 +1,22 @@ +{ + "deviceName": "EM500-C02 24e1641092176759", + "deviceType": "EM500-C02", + "attributes": { + "fPort": 85, + "applicationName": "cloud", + "frequency": 868300000, + "bandwidth": 125, + "spreadingFactor": 7, + "codeRate": "4/5" + }, + "telemetry": [{ + "ts": 1585312745547, + "values": { + "battery": 100, + "temperature": 28.1, + "humidity": 57.5, + "co2": 1127, + "pressure": 1008.8 + } + }] +} \ No newline at end of file diff --git a/VENDORS/Milesight/GS101/HTTP/uplink/converter.json b/VENDORS/Milesight/GS101/HTTP/uplink/converter.json new file mode 100644 index 00000000..f61a137c --- /dev/null +++ b/VENDORS/Milesight/GS101/HTTP/uplink/converter.json @@ -0,0 +1,29 @@ +{ + "name": "HTTP Uplink integration for GS101", + "type": "UPLINK", + "debugMode": false, + "debugSettings": { + "failuresEnabled": true, + "allEnabled": false, + "allEnabledUntil": 1735560006385 + }, + "configuration": { + "scriptLang": "TBEL", + "decoder": null, + "tbelDecoder": "var data = decodeToJson(payload);\nvar deviceName = \"GS101 \" + data.devEUI;\nvar deviceType = \"GS101\";\nvar groupName = null; // If groupName is not null - created device will be added to the entity group with such name.\nvar customerName = null; // If customerName is not null - created devices will be assigned to customer with such name. \n\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// If you want to parse incoming data somehow, you can add your code to this function.\n// input: bytes\n// expected output:\n// {\n// \"attributes\": {\"attributeKey\": \"attributeValue\"},\n// \"telemetry\": [{\"ts\": 1...1, \"values\": {\"telemetryKey\":\"telemetryValue\"}, {\"ts\": 1...2, \"values\": {\"telemetryKey\":\"telemetryValue\"}}]\n// }\n\nfunction decodePayload(input) {\n var output = {\n attributes: {},\n telemetry: []\n };\n \n // --- Decoding code --- //\n var decoded = {};\n var wifi = [];\n var fPort = data.fPort;\n var historyDataList = [];\n if(fPort == 85) {\n for (var i = 0; i < input.length - 2;) {\n var channel_id = input[i++] & 0xff;\n var channel_type = input[i++] & 0xff;\n \n // GAS STATUS\n if (channel_id === 0x05 && channel_type === 0x8e) {\n decoded.state = input[i] === 0 ? \"normal\" : \"abnormal\";\n i += 1;\n }\n // VALVE\n if (channel_id === 0x06 && channel_type === 0x01) {\n decoded.valve = input[i] === 0 ? \"close\" : \"open\";\n i += 1;\n }\n // RELAY\n if (channel_id === 0x07 && channel_type === 0x01) {\n decoded.relay = input[i] === 0 ? \"close\" : \"open\";\n i += 1;\n }\n // REMAINED LIFE TIME\n if (channel_id === 0x08 && channel_type === 0x90) {\n decoded.life_remain = parseBytesToInt(input, i, 4, false);\n i += 4;\n }\n // ALARM\n else if (channel_id === 0xff && channel_type === 0x3f) {\n var alarm_type = input[i];\n i += 1;\n decoded.alarm = decodeAlarmType(alarm_type);\n }\n }\n }\n\n output.telemetry = [{\n ts: timestamp,\n values: decoded\n }];\n \n output.telemetry.addAll(historyDataList);\n // --- Decoding code --- //\n return output;\n}\n\n// --- attributes and telemetry objects ---\nvar telemetry = [];\nvar attributes = {};\n// --- attributes and telemetry objects ---\n\n// --- Timestamp parsing\nvar dateString = data.time;\ntimestamp = parseDateToTimestamp(dateString);\n// --- Timestamp parsing\n\n// Passing incoming bytes to decodePayload function, to get custom decoding\nvar customDecoding = decodePayload(base64ToBytes(data.data));\n\n// Collecting data to result\nif (customDecoding.?telemetry.size() > 0) {\n foreach(telemetryObj: customDecoding.telemetry) {\n if (telemetryObj.ts != null && telemetryObj.values != null) {\n telemetry.add(telemetryObj);\n }\n }\n}\n\nif (customDecoding.?attributes.size() > 0) {\n attributes.putAll(customDecoding.attributes);\n}\n\n// You can add some keys manually to attributes or telemetry\nattributes.eui = data.?devEui;\nattributes.fPort = data.fPort;\nattributes.applicationId = data.?applicationId;\nattributes.applicationName = data.?applicationName;\nattributes.frequency = data.txInfo.?frequency;\nattributes.bandwidth = data.txInfo.?dataRate.?bandwidth;\nattributes.spreadingFactor = data.txInfo.?dataRate.?spreadFactor;\nattributes.codeRate = data.txInfo.?codeRate;\n\nif(Boolean.parseBoolean(metadata[\"includeGatewayInfo\"])) {\n var gatewayInfo = getGatewayInfo();\n var addDataToTelemetry = {};\n addDataToTelemetry.snr = gatewayInfo.?loRaSNR;\n addDataToTelemetry.rssi = gatewayInfo.rssi;\n addDataToTelemetry.fCnt = data.fCnt;\n \n telemetry = processTelemetryData(telemetry, addDataToTelemetry);\n}\n\nvar result = {\n deviceName: deviceName,\n deviceType: deviceType,\n // assetName: assetName,\n // assetType: assetType,\n attributes: attributes,\n telemetry: telemetry\n};\n\naddAdditionalInfoForDeviceMsg(result, customerName, groupName);\n\nreturn result;\n\nfunction addAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName) {\n if (customerName != null) {\n deviceInfo.customerName = customerName;\n }\n if (groupName != null) {\n deviceInfo.groupName = groupName;\n }\n}\n\nfunction parseDateToTimestamp(dateString) {\n dateString = dateString.replaceFirst(\"(\\\\d{4}-\\\\d{2})(\\\\d{2})\", \"$1-$2\");\n dateString = dateString.replaceFirst(\"\\\\.(\\\\d{3})\\\\d+Z\", \".$1Z\");\n dateString = dateString.replace(\"Z\", \"+0000\");\n var date = new Date(dateString);\n var timestamp = date.getTime();\n \n // If we cannot parse timestamp - we will use the current timestamp\n if (timestamp == -1) {\n timestamp = Date.now();\n }\n \n return timestamp;\n}\n\nfunction getGatewayInfo() {\n var gatewayList = data.rxInfo;\n var maxRssi = Integer.MIN_VALUE;\n var gatewayInfo = {};\n \n foreach (gateway : gatewayList) {\n if(gateway.rssi > maxRssi) {\n maxRssi = gateway.rssi;\n gatewayInfo = gateway;\n }\n }\n \n return gatewayInfo;\n}\n\nfunction processTelemetryData(telemetry, addDataToTelemetry) {\n if (telemetry.size >= 1) {\n telemetry = addDataToTelemetries(telemetry, addDataToTelemetry);\n }\n else {\n telemetry.add(addDataToTelemetry);\n }\n \n return telemetry;\n}\n\nfunction addDataToTelemetries(telemetries, addDataToTelemetry) {\n foreach(telemetry : telemetries) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[\"values\"].keys.contains(element.key)) {\n telemetry[\"values\"][element.key] = element.value;\n }\n } \n }\n \n return telemetries;\n}\n\nfunction decodeAlarmType(alarm_type) {\n if (alarm_type === 0) {\n return \"power down\";\n } else if (alarm_type === 1) {\n return \"power on\";\n } else if (alarm_type === 2) {\n return \"sensor failure\";\n } else if (alarm_type === 3) {\n return \"sensor recover\";\n } else if (alarm_type === 4) {\n return \"sensor about to fail\";\n } else if (alarm_type === 5) {\n return \"sensor failed\";\n } else {\n return \"unknown\";\n }\n}", + "encoder": null, + "tbelEncoder": null, + "updateOnlyKeys": [ + "fPort", + "applicationName", + "frequency", + "bandwidth", + "spreadingFactor", + "codeRate" + ] + }, + "additionalInfo": { + "description": "" + }, + "edgeTemplate": false +} \ No newline at end of file diff --git a/VENDORS/Milesight/GS101/HTTP/uplink/metadata.json b/VENDORS/Milesight/GS101/HTTP/uplink/metadata.json new file mode 100644 index 00000000..87ee6615 --- /dev/null +++ b/VENDORS/Milesight/GS101/HTTP/uplink/metadata.json @@ -0,0 +1,4 @@ +{ + "integrationName": "HTTP integration", + "includeGatewayInfo": "false" +} \ No newline at end of file diff --git a/VENDORS/Milesight/GS101/HTTP/uplink/payload.json b/VENDORS/Milesight/GS101/HTTP/uplink/payload.json new file mode 100644 index 00000000..8e075050 --- /dev/null +++ b/VENDORS/Milesight/GS101/HTTP/uplink/payload.json @@ -0,0 +1,31 @@ +{ + "applicationID": 1, + "applicationName": "cloud", + "deviceName": "24e1641092176759", + "devEUI": "24e1641092176759", + "time": "2020-0327T12:39:05.547336Z", + "rxInfo": [ + { + "mac": "24e124fffef021be", + "rssi": -57, + "loRaSNR": 10, + "name": "local_gateway", + "latitude": 0, + "longitude": 0, + "altitude": 0 + } + ], + "txInfo": { + "frequency": 868300000, + "dataRate": { + "modulation": "LORA", + "bandwidth": 125, + "spreadFactor": 7 + }, + "adr": false, + "codeRate": "4/5" + }, + "fCnt": 0, + "fPort": 85, + "data": "BY4ABgEBBwEA" +} \ No newline at end of file diff --git a/VENDORS/Milesight/GS101/HTTP/uplink/result.json b/VENDORS/Milesight/GS101/HTTP/uplink/result.json new file mode 100644 index 00000000..6f8cf3ee --- /dev/null +++ b/VENDORS/Milesight/GS101/HTTP/uplink/result.json @@ -0,0 +1,20 @@ +{ + "deviceName": "GS101 24e1641092176759", + "deviceType": "GS101", + "attributes": { + "fPort": 85, + "applicationName": "cloud", + "frequency": 868300000, + "bandwidth": 125, + "spreadingFactor": 7, + "codeRate": "4/5" + }, + "telemetry": [{ + "ts": 1585312745547, + "values": { + "state": "normal", + "valve": "open", + "relay": "close" + } + }] +} \ No newline at end of file diff --git a/VENDORS/Milesight/GS301/HTTP/uplink/converter.json b/VENDORS/Milesight/GS301/HTTP/uplink/converter.json new file mode 100644 index 00000000..ab5b7069 --- /dev/null +++ b/VENDORS/Milesight/GS301/HTTP/uplink/converter.json @@ -0,0 +1,29 @@ +{ + "name": "HTTP Uplink integration for GS301", + "type": "UPLINK", + "debugMode": false, + "debugSettings": { + "failuresEnabled": true, + "allEnabled": false, + "allEnabledUntil": 1735560006385 + }, + "configuration": { + "scriptLang": "TBEL", + "decoder": null, + "tbelDecoder": "var data = decodeToJson(payload);\nvar deviceName = \"GS301 \" + data.devEUI;\nvar deviceType = \"Bathroom Odor Sensor\";\nvar groupName = null; // If groupName is not null - created device will be added to the entity group with such name.\nvar customerName = null; // If customerName is not null - created devices will be assigned to customer with such name. \n\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// If you want to parse incoming data somehow, you can add your code to this function.\n// input: bytes\n// expected output:\n// {\n// \"attributes\": {\"attributeKey\": \"attributeValue\"},\n// \"telemetry\": [{\"ts\": 1...1, \"values\": {\"telemetryKey\":\"telemetryValue\"}, {\"ts\": 1...2, \"values\": {\"telemetryKey\":\"telemetryValue\"}}]\n// }\n\nfunction decodePayload(input) {\n var output = {\n attributes: {},\n telemetry: []\n };\n \n // --- Decoding code --- //\n var decoded = {};\n var wifi = [];\n var fPort = data.fPort;\n var historyDataList = [];\n if(fPort == 85) {\n for (var i = 0; i < input.length - 2;) {\n var channel_id = input[i++] & 0xff;\n var channel_type = input[i++] & 0xff;\n \n // BATTERY\n if (channel_id === 0x01 && channel_type === 0x75) {\n decoded.battery = input[i];\n i += 1;\n }\n // TEMPERATURE\n else if (channel_id === 0x02 && channel_type === 0x67) {\n // ℃\n decoded.temperature = parseBytesToInt(input, i, 2, false) / 10;\n i += 2;\n \n // ℉\n // decoded.temperature = parseBytesToInt(input, i, 2, false) / 10 * 1.8 + 32;\n // i +=2;\n }\n // HUMIDITY\n else if (channel_id === 0x03 && channel_type === 0x68) {\n decoded.humidity = parseBytesToInt(input, i, 1, false) / 2;\n i += 1;\n }\n // NH3\n else if (channel_id === 0x04 && channel_type === 0x7d) {\n decoded.nh3 = parseBytesToInt(input, i, 2, false) / 100;\n i += 2;\n }\n // H2S\n else if (channel_id === 0x05 && channel_type === 0x7d) {\n decoded.h2s = parseBytesToInt(input, i, 2, false) / 100;\n i += 2;\n }\n }\n }\n\n output.telemetry = [{\n ts: timestamp,\n values: decoded\n }];\n \n output.telemetry.addAll(historyDataList);\n // --- Decoding code --- //\n return output;\n}\n\n// --- attributes and telemetry objects ---\nvar telemetry = [];\nvar attributes = {};\n// --- attributes and telemetry objects ---\n\n// --- Timestamp parsing\nvar dateString = data.time;\ntimestamp = parseDateToTimestamp(dateString);\n// --- Timestamp parsing\n\n// Passing incoming bytes to decodePayload function, to get custom decoding\nvar customDecoding = decodePayload(base64ToBytes(data.data));\n\n// Collecting data to result\nif (customDecoding.?telemetry.size() > 0) {\n foreach(telemetryObj: customDecoding.telemetry) {\n if (telemetryObj.ts != null && telemetryObj.values != null) {\n telemetry.add(telemetryObj);\n }\n }\n}\n\nif (customDecoding.?attributes.size() > 0) {\n attributes.putAll(customDecoding.attributes);\n}\n\n// You can add some keys manually to attributes or telemetry\nattributes.eui = data.?devEui;\nattributes.fPort = data.fPort;\nattributes.applicationId = data.?applicationId;\nattributes.applicationName = data.?applicationName;\nattributes.frequency = data.txInfo.?frequency;\nattributes.bandwidth = data.txInfo.?dataRate.?bandwidth;\nattributes.spreadingFactor = data.txInfo.?dataRate.?spreadFactor;\nattributes.codeRate = data.txInfo.?codeRate;\n\nif(Boolean.parseBoolean(metadata[\"includeGatewayInfo\"])) {\n var gatewayInfo = getGatewayInfo();\n var addDataToTelemetry = {};\n addDataToTelemetry.snr = gatewayInfo.?loRaSNR;\n addDataToTelemetry.rssi = gatewayInfo.rssi;\n addDataToTelemetry.fCnt = data.fCnt;\n \n telemetry = processTelemetryData(telemetry, addDataToTelemetry);\n}\n\nvar result = {\n deviceName: deviceName,\n deviceType: deviceType,\n // assetName: assetName,\n // assetType: assetType,\n attributes: attributes,\n telemetry: telemetry\n};\n\naddAdditionalInfoForDeviceMsg(result, customerName, groupName);\n\nreturn result;\n\nfunction addAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName) {\n if (customerName != null) {\n deviceInfo.customerName = customerName;\n }\n if (groupName != null) {\n deviceInfo.groupName = groupName;\n }\n}\n\nfunction parseDateToTimestamp(dateString) {\n dateString = dateString.replaceFirst(\"(\\\\d{4}-\\\\d{2})(\\\\d{2})\", \"$1-$2\");\n dateString = dateString.replaceFirst(\"\\\\.(\\\\d{3})\\\\d+Z\", \".$1Z\");\n dateString = dateString.replace(\"Z\", \"+0000\");\n var date = new Date(dateString);\n var timestamp = date.getTime();\n \n // If we cannot parse timestamp - we will use the current timestamp\n if (timestamp == -1) {\n timestamp = Date.now();\n }\n \n return timestamp;\n}\n\nfunction getGatewayInfo() {\n var gatewayList = data.rxInfo;\n var maxRssi = Integer.MIN_VALUE;\n var gatewayInfo = {};\n \n foreach (gateway : gatewayList) {\n if(gateway.rssi > maxRssi) {\n maxRssi = gateway.rssi;\n gatewayInfo = gateway;\n }\n }\n \n return gatewayInfo;\n}\n\nfunction processTelemetryData(telemetry, addDataToTelemetry) {\n if (telemetry.size >= 1) {\n telemetry = addDataToTelemetries(telemetry, addDataToTelemetry);\n }\n else {\n telemetry.add(addDataToTelemetry);\n }\n \n return telemetry;\n}\n\nfunction addDataToTelemetries(telemetries, addDataToTelemetry) {\n foreach(telemetry : telemetries) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[\"values\"].keys.contains(element.key)) {\n telemetry[\"values\"][element.key] = element.value;\n }\n } \n }\n \n return telemetries;\n}\n\nfunction decodeAlarmType(alarm_type) {\n if (alarm_type === 0) {\n return \"power down\";\n } else if (alarm_type === 1) {\n return \"power on\";\n } else if (alarm_type === 2) {\n return \"sensor failure\";\n } else if (alarm_type === 3) {\n return \"sensor recover\";\n } else if (alarm_type === 4) {\n return \"sensor about to fail\";\n } else if (alarm_type === 5) {\n return \"sensor failed\";\n } else {\n return \"unknown\";\n }\n}", + "encoder": null, + "tbelEncoder": null, + "updateOnlyKeys": [ + "fPort", + "applicationName", + "frequency", + "bandwidth", + "spreadingFactor", + "codeRate" + ] + }, + "additionalInfo": { + "description": "" + }, + "edgeTemplate": false +} \ No newline at end of file diff --git a/VENDORS/Milesight/GS301/HTTP/uplink/metadata.json b/VENDORS/Milesight/GS301/HTTP/uplink/metadata.json new file mode 100644 index 00000000..87ee6615 --- /dev/null +++ b/VENDORS/Milesight/GS301/HTTP/uplink/metadata.json @@ -0,0 +1,4 @@ +{ + "integrationName": "HTTP integration", + "includeGatewayInfo": "false" +} \ No newline at end of file diff --git a/VENDORS/Milesight/GS301/HTTP/uplink/payload.json b/VENDORS/Milesight/GS301/HTTP/uplink/payload.json new file mode 100644 index 00000000..b26a6123 --- /dev/null +++ b/VENDORS/Milesight/GS301/HTTP/uplink/payload.json @@ -0,0 +1,31 @@ +{ + "applicationID": 1, + "applicationName": "cloud", + "deviceName": "24e1641092176759", + "devEUI": "24e1641092176759", + "time": "2020-0327T12:39:05.547336Z", + "rxInfo": [ + { + "mac": "24e124fffef021be", + "rssi": -57, + "loRaSNR": 10, + "name": "local_gateway", + "latitude": 0, + "longitude": 0, + "altitude": 0 + } + ], + "txInfo": { + "frequency": 868300000, + "dataRate": { + "modulation": "LORA", + "bandwidth": 125, + "spreadFactor": 7 + }, + "adr": false, + "codeRate": "4/5" + }, + "fCnt": 0, + "fPort": 85, + "data": "AXVkAmccAQNoZAR9AAAFfQEA" +} \ No newline at end of file diff --git a/VENDORS/Milesight/GS301/HTTP/uplink/result.json b/VENDORS/Milesight/GS301/HTTP/uplink/result.json new file mode 100644 index 00000000..45018113 --- /dev/null +++ b/VENDORS/Milesight/GS301/HTTP/uplink/result.json @@ -0,0 +1,22 @@ +{ + "deviceName": "GS301 24e1641092176759", + "deviceType": "Bathroom Odor Sensor", + "attributes": { + "fPort": 85, + "applicationName": "cloud", + "frequency": 868300000, + "bandwidth": 125, + "spreadingFactor": 7, + "codeRate": "4/5" + }, + "telemetry": [{ + "ts": 1585312745547, + "values": { + "battery": 100, + "temperature": 28.4, + "humidity": 50.0, + "nh3": 0.0, + "h2s": 0.01 + } + }] +} \ No newline at end of file diff --git a/VENDORS/Milesight/TS101/HTTP/uplink/converter.json b/VENDORS/Milesight/TS101/HTTP/uplink/converter.json new file mode 100644 index 00000000..c292d378 --- /dev/null +++ b/VENDORS/Milesight/TS101/HTTP/uplink/converter.json @@ -0,0 +1,29 @@ +{ + "name": "HTTP Uplink integration for TS101", + "type": "UPLINK", + "debugMode": false, + "debugSettings": { + "failuresEnabled": true, + "allEnabled": false, + "allEnabledUntil": 1735560006385 + }, + "configuration": { + "scriptLang": "TBEL", + "decoder": null, + "tbelDecoder": "var data = decodeToJson(payload);\nvar deviceName = \"TS101 \" + data.devEUI;\nvar deviceType = \"Smoke detector\";\nvar groupName = null; // If groupName is not null - created device will be added to the entity group with such name.\nvar customerName = null; // If customerName is not null - created devices will be assigned to customer with such name. \n\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// If you want to parse incoming data somehow, you can add your code to this function.\n// input: bytes\n// expected output:\n// {\n// \"attributes\": {\"attributeKey\": \"attributeValue\"},\n// \"telemetry\": [{\"ts\": 1...1, \"values\": {\"telemetryKey\":\"telemetryValue\"}, {\"ts\": 1...2, \"values\": {\"telemetryKey\":\"telemetryValue\"}}]\n// }\n\nfunction decodePayload(input) {\n var output = {\n attributes: {},\n telemetry: []\n };\n \n // --- Decoding code --- //\n var decoded = {};\n var wifi = [];\n var fPort = data.fPort;\n var historyDataList = [];\n if(fPort == 85) {\n for (var i = 0; i < input.length - 2;) {\n var channel_id = input[i++] & 0xff;\n var channel_type = input[i++] & 0xff;\n \n // BATTERY\n if (channel_id === 0x01 && channel_type === 0x75) {\n decoded.battery = input[i];\n i += 1;\n }\n // TEMPERATURE\n else if (channel_id === 0x03 && channel_type === 0x67) {\n decoded.temperature = parseBytesToInt(input, i, 2, false) / 10; \n i += 2;\n }\n // TEMPERATURE ALARM\n else if (channel_id === 0x83 && channel_type === 0x67) {\n decoded.temperature = parseBytesToInt(input, i, 2, false) / 10; \n decoded.temperature_alarm = readTemperatureAlarm(input[i + 2]);\n i += 3;\n }\n // TEMPERATURE MUTATION ALERT\n else if (channel_id === 0x93 && channel_type === 0xd7) {\n decoded.temperature = parseBytesToInt(input, i, 2, false) / 10; \n decoded.temperature_change = parseBytesToInt(input, i + 2, 2, false) / 100;\n decoded.temperature_alarm = readTemperatureAlarm(input[i + 4]);\n i += 5;\n }\n // HISTORY\n else if (channel_id === 0x20 && channel_type === 0xce) {\n historyDate = {\n ts : parseBytesToInt(input, i, 4, false) * 1000,\n values : {\n temperature: parseBytesToInt(input, i + 4, 2) / 10\n }\n };\n \n historyDataList.add(historyDate);\n i += 6;\n }\n }\n }\n\n output.telemetry = [{\n ts: timestamp,\n values: decoded\n }];\n \n output.telemetry.addAll(historyDataList);\n // --- Decoding code --- //\n return output;\n}\n\n// --- attributes and telemetry objects ---\nvar telemetry = [];\nvar attributes = {};\n// --- attributes and telemetry objects ---\n\n// --- Timestamp parsing\nvar dateString = data.time;\ntimestamp = parseDateToTimestamp(dateString);\n// --- Timestamp parsing\n\n// Passing incoming bytes to decodePayload function, to get custom decoding\nvar customDecoding = decodePayload(base64ToBytes(data.data));\n\n// Collecting data to result\nif (customDecoding.?telemetry.size() > 0) {\n foreach(telemetryObj: customDecoding.telemetry) {\n if (telemetryObj.ts != null && telemetryObj.values != null) {\n telemetry.add(telemetryObj);\n }\n }\n}\n\nif (customDecoding.?attributes.size() > 0) {\n attributes.putAll(customDecoding.attributes);\n}\n\n// You can add some keys manually to attributes or telemetry\nattributes.eui = data.?devEui;\nattributes.fPort = data.fPort;\nattributes.applicationId = data.?applicationId;\nattributes.applicationName = data.?applicationName;\nattributes.frequency = data.txInfo.?frequency;\nattributes.bandwidth = data.txInfo.?dataRate.?bandwidth;\nattributes.spreadingFactor = data.txInfo.?dataRate.?spreadFactor;\nattributes.codeRate = data.txInfo.?codeRate;\n\nif(Boolean.parseBoolean(metadata[\"includeGatewayInfo\"])) {\n var gatewayInfo = getGatewayInfo();\n var addDataToTelemetry = {};\n addDataToTelemetry.snr = gatewayInfo.?loRaSNR;\n addDataToTelemetry.rssi = gatewayInfo.rssi;\n addDataToTelemetry.fCnt = data.fCnt;\n \n telemetry = processTelemetryData(telemetry, addDataToTelemetry);\n}\n\nvar result = {\n deviceName: deviceName,\n deviceType: deviceType,\n // assetName: assetName,\n // assetType: assetType,\n attributes: attributes,\n telemetry: telemetry\n};\n\naddAdditionalInfoForDeviceMsg(result, customerName, groupName);\n\nreturn result;\n\nfunction addAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName) {\n if (customerName != null) {\n deviceInfo.customerName = customerName;\n }\n if (groupName != null) {\n deviceInfo.groupName = groupName;\n }\n}\n\nfunction parseDateToTimestamp(dateString) {\n dateString = dateString.replaceFirst(\"(\\\\d{4}-\\\\d{2})(\\\\d{2})\", \"$1-$2\");\n dateString = dateString.replaceFirst(\"\\\\.(\\\\d{3})\\\\d+Z\", \".$1Z\");\n dateString = dateString.replace(\"Z\", \"+0000\");\n var date = new Date(dateString);\n var timestamp = date.getTime();\n \n // If we cannot parse timestamp - we will use the current timestamp\n if (timestamp == -1) {\n timestamp = Date.now();\n }\n \n return timestamp;\n}\n\nfunction getGatewayInfo() {\n var gatewayList = data.rxInfo;\n var maxRssi = Integer.MIN_VALUE;\n var gatewayInfo = {};\n \n foreach (gateway : gatewayList) {\n if(gateway.rssi > maxRssi) {\n maxRssi = gateway.rssi;\n gatewayInfo = gateway;\n }\n }\n \n return gatewayInfo;\n}\n\nfunction processTelemetryData(telemetry, addDataToTelemetry) {\n if (telemetry.size >= 1) {\n telemetry = addDataToTelemetries(telemetry, addDataToTelemetry);\n }\n else {\n telemetry.add(addDataToTelemetry);\n }\n \n return telemetry;\n}\n\nfunction addDataToTelemetries(telemetries, addDataToTelemetry) {\n foreach(telemetry : telemetries) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[\"values\"].keys.contains(element.key)) {\n telemetry[\"values\"][element.key] = element.value;\n }\n } \n }\n \n return telemetries;\n}\n\nfunction readTemperatureAlarm(type) {\n switch (type) {\n case 0:\n return \"threshold alarm release\";\n case 1:\n return \"threshold alarm\";\n case 2:\n return \"mutation alarm\";\n default:\n return \"unkown\";\n }\n}", + "encoder": null, + "tbelEncoder": null, + "updateOnlyKeys": [ + "fPort", + "applicationName", + "frequency", + "bandwidth", + "spreadingFactor", + "codeRate" + ] + }, + "additionalInfo": { + "description": "" + }, + "edgeTemplate": false +} \ No newline at end of file diff --git a/VENDORS/Milesight/TS101/HTTP/uplink/metadata.json b/VENDORS/Milesight/TS101/HTTP/uplink/metadata.json new file mode 100644 index 00000000..87ee6615 --- /dev/null +++ b/VENDORS/Milesight/TS101/HTTP/uplink/metadata.json @@ -0,0 +1,4 @@ +{ + "integrationName": "HTTP integration", + "includeGatewayInfo": "false" +} \ No newline at end of file diff --git a/VENDORS/Milesight/TS101/HTTP/uplink/payload.json b/VENDORS/Milesight/TS101/HTTP/uplink/payload.json new file mode 100644 index 00000000..dc321fce --- /dev/null +++ b/VENDORS/Milesight/TS101/HTTP/uplink/payload.json @@ -0,0 +1,31 @@ +{ + "applicationID": 1, + "applicationName": "cloud", + "deviceName": "24e1641092176759", + "devEUI": "24e1641092176759", + "time": "2020-0327T12:39:05.547336Z", + "rxInfo": [ + { + "mac": "24e124fffef021be", + "rssi": -57, + "loRaSNR": 10, + "name": "local_gateway", + "latitude": 0, + "longitude": 0, + "altitude": 0 + } + ], + "txInfo": { + "frequency": 868300000, + "dataRate": { + "modulation": "LORA", + "bandwidth": 125, + "spreadFactor": 7 + }, + "adr": false, + "codeRate": "4/5" + }, + "fCnt": 0, + "fPort": 85, + "data": "g2dSAQE=" +} \ No newline at end of file diff --git a/VENDORS/Milesight/TS101/HTTP/uplink/result.json b/VENDORS/Milesight/TS101/HTTP/uplink/result.json new file mode 100644 index 00000000..b4770acb --- /dev/null +++ b/VENDORS/Milesight/TS101/HTTP/uplink/result.json @@ -0,0 +1,19 @@ +{ + "deviceName": "TS101 24e1641092176759", + "deviceType": "Smoke detector", + "attributes": { + "fPort": 85, + "applicationName": "cloud", + "frequency": 868300000, + "bandwidth": 125, + "spreadingFactor": 7, + "codeRate": "4/5" + }, + "telemetry": [{ + "ts": 1585312745547, + "values": { + "temperature": 33.8, + "temperature_alarm": "threshold alarm" + } + }] +} \ No newline at end of file diff --git a/VENDORS/Milesight/TS201/HTTP/uplink/converter.json b/VENDORS/Milesight/TS201/HTTP/uplink/converter.json new file mode 100644 index 00000000..905a61fe --- /dev/null +++ b/VENDORS/Milesight/TS201/HTTP/uplink/converter.json @@ -0,0 +1,29 @@ +{ + "name": "HTTP Uplink integration for TS201", + "type": "UPLINK", + "debugMode": false, + "debugSettings": { + "failuresEnabled": true, + "allEnabled": false, + "allEnabledUntil": 1735560006385 + }, + "configuration": { + "scriptLang": "TBEL", + "decoder": null, + "tbelDecoder": "var data = decodeToJson(payload);\nvar deviceName = \"TS201 \" + data.devEUI;\nvar deviceType = \"Smoke detector\";\nvar groupName = null; // If groupName is not null - created device will be added to the entity group with such name.\nvar customerName = null; // If customerName is not null - created devices will be assigned to customer with such name. \n\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// If you want to parse incoming data somehow, you can add your code to this function.\n// input: bytes\n// expected output:\n// {\n// \"attributes\": {\"attributeKey\": \"attributeValue\"},\n// \"telemetry\": [{\"ts\": 1...1, \"values\": {\"telemetryKey\":\"telemetryValue\"}, {\"ts\": 1...2, \"values\": {\"telemetryKey\":\"telemetryValue\"}}]\n// }\n\nfunction decodePayload(input) {\n var output = {\n attributes: {},\n telemetry: []\n };\n \n // --- Decoding code --- //\n var decoded = {};\n var wifi = [];\n var fPort = data.fPort;\n var historyDataList = [];\n if(fPort == 85) {\n for (var i = 0; i < input.length - 2;) {\n var channel_id = input[i++] & 0xff;\n var channel_type = input[i++] & 0xff;\n \n // IPSO VERSION\n if (channel_id === 0xff && channel_type === 0x01) {\n output.attributes.ipso_version = readProtocolVersion(input[i]);\n i += 1;\n }\n // HARDWARE VERSION\n else if (channel_id === 0xff && channel_type === 0x09) {\n output.attributes.hardware_version = readHardwareVersion(java.util.Arrays.copyOfRange(input, i, i + 2));\n i += 2;\n }\n // FIRMWARE VERSION\n else if (channel_id === 0xff && channel_type === 0x0a) {\n output.attributes.firmware_version = readFirmwareVersion(java.util.Arrays.copyOfRange(input, i, i + 2));\n i += 2;\n }\n // DEVICE STATUS\n else if (channel_id === 0xff && channel_type === 0x0b) {\n decoded.device_status = \"on\";\n i += 1;\n }\n // LORAWAN CLASS TYPE\n else if (channel_id === 0xff && channel_type === 0x0f) {\n output.attributes.lorawan_class = readLoRaWANType(input[i]);\n i += 1;\n }\n // SERIAL NUMBER\n else if (channel_id === 0xff && channel_type === 0x16) {\n output.attributes.sn = readSerialNumber(java.util.Arrays.copyOfRange(input, i, i + 8));\n i += 8;\n }\n // TSL VERSION\n else if (channel_id === 0xff && channel_type === 0xff) {\n output.attributes.tsl_version = readTslVersion(java.util.Arrays.copyOfRange(input, i, i + 2));\n i += 2;\n }\n // BATTERY\n else if (channel_id === 0x01 && channel_type === 0x75) {\n decoded.battery = input[i];\n i += 1;\n }\n // TEMPERATURE\n else if (channel_id === 0x03 && channel_type === 0x67) {\n decoded.temperature = getTemperatureValue(java.util.Arrays.copyOfRange(input, i, i + 2));\n i += 2;\n }\n // TEMPERATURE THRESHOLD ALARM\n else if (channel_id === 0x83 && channel_type === 0x67) {\n decoded.temperature = getTemperatureValue(java.util.Arrays.copyOfRange(input, i, i + 2));\n decoded.temperature_alarm = readAlarmType(input[i + 2]);\n i += 3;\n }\n // TEMPERATURE MUTATION ALARM\n else if (channel_id === 0x93 && channel_type === 0x67) {\n decoded.temperature = getTemperatureValue(java.util.Arrays.copyOfRange(input, i, i + 2));\n decoded.temperature_mutation = parseBytesToInt(input, i + 2, 2, false) / 10;\n decoded.temperature_alarm = readAlarmType(input[i + 4]);\n i += 5;\n }\n // TEMPERATURE ERROR\n else if (channel_id === 0xb3 && channel_type === 0x67) {\n decoded.temperature_error = readErrorType(input[i]);\n i += 1;\n }\n // HISTORY DATA\n else if (channel_id === 0x20 && channel_type === 0xce) {\n var event = input[i + 4];\n var historyData = {\n ts : parseBytesToInt(input, i, 4, false) * 1000,\n values : {\n temperature : getTemperatureValue(java.util.Arrays.copyOfRange(input, i + 5, i + 7)),\n read_status : readStatus((event >>> 4) & 0x0f),\n event_type : readType(event & 0x0f)\n }\n };\n \n historyDataList.push(historyData);\n i += 7;\n }\n }\n }\n\n output.telemetry = [{\n ts: timestamp,\n values: decoded\n }];\n \n output.telemetry.addAll(historyDataList);\n // --- Decoding code --- //\n return output;\n}\n\n// --- attributes and telemetry objects ---\nvar telemetry = [];\nvar attributes = {};\n// --- attributes and telemetry objects ---\n\n// --- Timestamp parsing\nvar dateString = data.time;\ntimestamp = parseDateToTimestamp(dateString);\n// --- Timestamp parsing\n\n// Passing incoming bytes to decodePayload function, to get custom decoding\nvar customDecoding = decodePayload(base64ToBytes(data.data));\n\n// Collecting data to result\nif (customDecoding.?telemetry.size() > 0) {\n foreach(telemetryObj: customDecoding.telemetry) {\n if (telemetryObj.ts != null && telemetryObj.values != null) {\n telemetry.add(telemetryObj);\n }\n }\n}\n\nif (customDecoding.?attributes.size() > 0) {\n attributes.putAll(customDecoding.attributes);\n}\n\n// You can add some keys manually to attributes or telemetry\nattributes.eui = data.?devEui;\nattributes.fPort = data.fPort;\nattributes.applicationId = data.?applicationId;\nattributes.applicationName = data.?applicationName;\nattributes.frequency = data.txInfo.?frequency;\nattributes.bandwidth = data.txInfo.?dataRate.?bandwidth;\nattributes.spreadingFactor = data.txInfo.?dataRate.?spreadFactor;\nattributes.codeRate = data.txInfo.?codeRate;\n\nif(Boolean.parseBoolean(metadata[\"includeGatewayInfo\"])) {\n var gatewayInfo = getGatewayInfo();\n var addDataToTelemetry = {};\n addDataToTelemetry.snr = gatewayInfo.?loRaSNR;\n addDataToTelemetry.rssi = gatewayInfo.rssi;\n addDataToTelemetry.fCnt = data.fCnt;\n \n telemetry = processTelemetryData(telemetry, addDataToTelemetry);\n}\n\nvar result = {\n deviceName: deviceName,\n deviceType: deviceType,\n // assetName: assetName,\n // assetType: assetType,\n attributes: attributes,\n telemetry: telemetry\n};\n\naddAdditionalInfoForDeviceMsg(result, customerName, groupName);\n\nreturn result;\n\nfunction addAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName) {\n if (customerName != null) {\n deviceInfo.customerName = customerName;\n }\n if (groupName != null) {\n deviceInfo.groupName = groupName;\n }\n}\n\nfunction parseDateToTimestamp(dateString) {\n dateString = dateString.replaceFirst(\"(\\\\d{4}-\\\\d{2})(\\\\d{2})\", \"$1-$2\");\n dateString = dateString.replaceFirst(\"\\\\.(\\\\d{3})\\\\d+Z\", \".$1Z\");\n dateString = dateString.replace(\"Z\", \"+0000\");\n var date = new Date(dateString);\n var timestamp = date.getTime();\n \n // If we cannot parse timestamp - we will use the current timestamp\n if (timestamp == -1) {\n timestamp = Date.now();\n }\n \n return timestamp;\n}\n\nfunction getGatewayInfo() {\n var gatewayList = data.rxInfo;\n var maxRssi = Integer.MIN_VALUE;\n var gatewayInfo = {};\n \n foreach (gateway : gatewayList) {\n if(gateway.rssi > maxRssi) {\n maxRssi = gateway.rssi;\n gatewayInfo = gateway;\n }\n }\n \n return gatewayInfo;\n}\n\nfunction processTelemetryData(telemetry, addDataToTelemetry) {\n if (telemetry.size >= 1) {\n telemetry = addDataToTelemetries(telemetry, addDataToTelemetry);\n }\n else {\n telemetry.add(addDataToTelemetry);\n }\n \n return telemetry;\n}\n\nfunction addDataToTelemetries(telemetries, addDataToTelemetry) {\n foreach(telemetry : telemetries) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[\"values\"].keys.contains(element.key)) {\n telemetry[\"values\"][element.key] = element.value;\n }\n } \n }\n \n return telemetries;\n}\n\nfunction getTemperatureValue(temperatureBytes) {\n var ref = parseBytesToInt(temperatureBytes, 0, 2, false);\n return (ref > 0x7fff ? ref - 0x10000 : ref) / 10;\n}\n\nfunction readProtocolVersion(bytes) {\n var major = (bytes & 0xf0) >> 4;\n var minor = bytes & 0x0f;\n return \"v\" + major + \".\" + minor;\n}\n\nfunction readHardwareVersion(bytes) {\n var major = bytes[0] & 0xff;\n var minor = (bytes[1] & 0xff) >> 4;\n return \"v\" + major + \".\" + minor;\n}\n\nfunction readFirmwareVersion(bytes) {\n var major = bytes[0] & 0xff;\n var minor = bytes[1] & 0xff;\n return \"v\" + major + \".\" + minor;\n}\n\nfunction readTslVersion(bytes) {\n var major = bytes[0] & 0xff;\n var minor = bytes[1] & 0xff;\n return \"v\" + major + \".\" + minor;\n}\n\nfunction readSerialNumber(bytes) {\n var temp = [];\n for (var idx = 0; idx < bytes.length; idx++) {\n temp.push((\"0\" + (bytes[idx] & 0xff).toString(16)).slice(-2));\n }\n return temp.join(\"\");\n}\n\nfunction readLoRaWANType(type) {\n switch (type) {\n case 0x00:\n return \"ClassA\";\n case 0x01:\n return \"ClassB\";\n case 0x02:\n return \"ClassC\";\n case 0x03:\n return \"ClassCtoB\";\n default:\n return \"Unknown\";\n }\n}\n\nfunction readAlarmType(type) {\n switch (type) {\n case 0x00:\n return \"Threshold Alarm Release\";\n case 0x01:\n return \"Threshold Alarm\";\n case 0x02:\n return \"Mutation Alarm\";\n default:\n return \"Unknown\";\n }\n}\n\nfunction readErrorType(type) {\n switch (type) {\n case 0x00:\n return \"Read Error\";\n case 0x01:\n return \"Overload\";\n default:\n return \"Unknown\";\n }\n}\n\nfunction readHistoryEvent(type) {\n switch (type) {\n case 0x00:\n return \"Time Update\";\n case 0x01:\n return \"Periodic\";\n case 0x02:\n return \"Alarm(Threshold or Mutation)\";\n case 0x03:\n return \"Alarm Release\";\n case 0x04:\n return \"Read Error\";\n case 0x05:\n return \"Overload\";\n default:\n return \"Unknown\";\n }\n}\n\nfunction readStatus(type) {\n switch (type) {\n case 0x00:\n return \"Success\";\n case 0x01:\n return \"Read Error\";\n case 0x02:\n return \"Overload\";\n default:\n return \"Unknown\";\n }\n}\n\nfunction readType(type) {\n switch (type) {\n case 0x00:\n return \"\";\n case 0x01:\n return \"Periodic\";\n case 0x02:\n return \"Alarm(Threshold or Mutation)\";\n case 0x03:\n return \"Alarm Release\";\n default:\n return \"Unknown\";\n }\n}", + "encoder": null, + "tbelEncoder": null, + "updateOnlyKeys": [ + "fPort", + "applicationName", + "frequency", + "bandwidth", + "spreadingFactor", + "codeRate" + ] + }, + "additionalInfo": { + "description": "" + }, + "edgeTemplate": false +} \ No newline at end of file diff --git a/VENDORS/Milesight/TS201/HTTP/uplink/metadata.json b/VENDORS/Milesight/TS201/HTTP/uplink/metadata.json new file mode 100644 index 00000000..87ee6615 --- /dev/null +++ b/VENDORS/Milesight/TS201/HTTP/uplink/metadata.json @@ -0,0 +1,4 @@ +{ + "integrationName": "HTTP integration", + "includeGatewayInfo": "false" +} \ No newline at end of file diff --git a/VENDORS/Milesight/TS201/HTTP/uplink/payload.json b/VENDORS/Milesight/TS201/HTTP/uplink/payload.json new file mode 100644 index 00000000..6e27f50b --- /dev/null +++ b/VENDORS/Milesight/TS201/HTTP/uplink/payload.json @@ -0,0 +1,31 @@ +{ + "applicationID": 1, + "applicationName": "cloud", + "deviceName": "24e1641092176759", + "devEUI": "24e1641092176759", + "time": "2020-0327T12:39:05.547336Z", + "rxInfo": [ + { + "mac": "24e124fffef021be", + "rssi": -57, + "loRaSNR": 10, + "name": "local_gateway", + "latitude": 0, + "longitude": 0, + "altitude": 0 + } + ], + "txInfo": { + "frequency": 868300000, + "dataRate": { + "modulation": "LORA", + "bandwidth": 125, + "spreadFactor": 7 + }, + "adr": false, + "codeRate": "4/5" + }, + "fCnt": 0, + "fPort": 85, + "data": "IM7HmvpkAr3/" +} \ No newline at end of file diff --git a/VENDORS/Milesight/TS201/HTTP/uplink/result.json b/VENDORS/Milesight/TS201/HTTP/uplink/result.json new file mode 100644 index 00000000..810e2f8e --- /dev/null +++ b/VENDORS/Milesight/TS201/HTTP/uplink/result.json @@ -0,0 +1,23 @@ +{ + "deviceName": "TS201 24e1641092176759", + "deviceType": "Smoke detector", + "attributes": { + "fPort": 85, + "applicationName": "cloud", + "frequency": 868300000, + "bandwidth": 125, + "spreadingFactor": 7, + "codeRate": "4/5" + }, + "telemetry": [{ + "ts": 1585312745547, + "values": {} + }, { + "ts": 1694145223000, + "values": { + "temperature": -6.7, + "read_status": "Success", + "event_type": "Alarm(Threshold or Mutation)" + } + }] +} \ No newline at end of file diff --git a/VENDORS/Milesight/WS101/HTTP/uplink/converter.json b/VENDORS/Milesight/WS101/HTTP/uplink/converter.json new file mode 100644 index 00000000..d2731e93 --- /dev/null +++ b/VENDORS/Milesight/WS101/HTTP/uplink/converter.json @@ -0,0 +1,29 @@ +{ + "name": "HTTP Uplink integration for WS101", + "type": "UPLINK", + "debugMode": false, + "debugSettings": { + "failuresEnabled": true, + "allEnabled": false, + "allEnabledUntil": 1735560006385 + }, + "configuration": { + "scriptLang": "TBEL", + "decoder": null, + "tbelDecoder": "var data = decodeToJson(payload);\nvar deviceName = \"WS101 \" + data.devEUI;\nvar deviceType = \"Smoke detector\";\nvar groupName = null; // If groupName is not null - created device will be added to the entity group with such name.\nvar customerName = null; // If customerName is not null - created devices will be assigned to customer with such name. \n\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// If you want to parse incoming data somehow, you can add your code to this function.\n// input: bytes\n// expected output:\n// {\n// \"attributes\": {\"attributeKey\": \"attributeValue\"},\n// \"telemetry\": [{\"ts\": 1...1, \"values\": {\"telemetryKey\":\"telemetryValue\"}, {\"ts\": 1...2, \"values\": {\"telemetryKey\":\"telemetryValue\"}}]\n// }\n\nfunction decodePayload(input) {\n var output = {\n attributes: {},\n telemetry: []\n };\n \n // --- Decoding code --- //\n var decoded = {};\n var fPort = data.fPort;\n if(fPort == 85) {\n for (var i = 0; i < input.length - 2;) {\n var channel_id = input[i++] & 0xff;\n var channel_type = input[i++] & 0xff;\n \n // BATTERY\n if (channel_id === 0x01 && channel_type === 0x75) {\n decoded.battery = input[i];\n i += 1;\n }\n // PRESS STATE\n else if (channel_id === 0xff && channel_type === 0x2e) {\n setPressState(decoded, input[i]);\n i += 1;\n } \n }\n }\n\n output.telemetry = [{\n ts: timestamp,\n values: decoded\n }];\n \n // --- Decoding code --- //\n return output;\n}\n\n// --- attributes and telemetry objects ---\nvar telemetry = [];\nvar attributes = {};\n// --- attributes and telemetry objects ---\n\n// --- Timestamp parsing\nvar dateString = data.time;\ntimestamp = parseDateToTimestamp(dateString);\n// --- Timestamp parsing\n\n// Passing incoming bytes to decodePayload function, to get custom decoding\nvar customDecoding = decodePayload(base64ToBytes(data.data));\n\n// Collecting data to result\nif (customDecoding.?telemetry.size() > 0) {\n foreach(telemetryObj: customDecoding.telemetry) {\n if (telemetryObj.ts != null && telemetryObj.values != null) {\n telemetry.add(telemetryObj);\n }\n }\n}\n\nif (customDecoding.?attributes.size() > 0) {\n attributes.putAll(customDecoding.attributes);\n}\n\n// You can add some keys manually to attributes or telemetry\nattributes.eui = data.?devEui;\nattributes.fPort = data.fPort;\nattributes.applicationId = data.?applicationId;\nattributes.applicationName = data.?applicationName;\nattributes.frequency = data.txInfo.?frequency;\nattributes.bandwidth = data.txInfo.?dataRate.?bandwidth;\nattributes.spreadingFactor = data.txInfo.?dataRate.?spreadFactor;\nattributes.codeRate = data.txInfo.?codeRate;\n\nif(Boolean.parseBoolean(metadata[\"includeGatewayInfo\"])) {\n var gatewayInfo = getGatewayInfo();\n var addDataToTelemetry = {};\n addDataToTelemetry.snr = gatewayInfo.?loRaSNR;\n addDataToTelemetry.rssi = gatewayInfo.rssi;\n addDataToTelemetry.fCnt = data.fCnt;\n \n telemetry = processTelemetryData(telemetry, addDataToTelemetry);\n}\n\nvar result = {\n deviceName: deviceName,\n deviceType: deviceType,\n // assetName: assetName,\n // assetType: assetType,\n attributes: attributes,\n telemetry: telemetry\n};\n\naddAdditionalInfoForDeviceMsg(result, customerName, groupName);\n\nreturn result;\n\nfunction addAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName) {\n if (customerName != null) {\n deviceInfo.customerName = customerName;\n }\n if (groupName != null) {\n deviceInfo.groupName = groupName;\n }\n}\n\nfunction parseDateToTimestamp(dateString) {\n dateString = dateString.replaceFirst(\"(\\\\d{4}-\\\\d{2})(\\\\d{2})\", \"$1-$2\");\n dateString = dateString.replaceFirst(\"\\\\.(\\\\d{3})\\\\d+Z\", \".$1Z\");\n dateString = dateString.replace(\"Z\", \"+0000\");\n var date = new Date(dateString);\n var timestamp = date.getTime();\n \n // If we cannot parse timestamp - we will use the current timestamp\n if (timestamp == -1) {\n timestamp = Date.now();\n }\n \n return timestamp;\n}\n\nfunction getGatewayInfo() {\n var gatewayList = data.rxInfo;\n var maxRssi = Integer.MIN_VALUE;\n var gatewayInfo = {};\n \n foreach (gateway : gatewayList) {\n if(gateway.rssi > maxRssi) {\n maxRssi = gateway.rssi;\n gatewayInfo = gateway;\n }\n }\n \n return gatewayInfo;\n}\n\nfunction processTelemetryData(telemetry, addDataToTelemetry) {\n if (telemetry.size >= 1) {\n telemetry = addDataToTelemetries(telemetry, addDataToTelemetry);\n }\n else {\n telemetry.add(addDataToTelemetry);\n }\n \n return telemetry;\n}\n\nfunction addDataToTelemetries(telemetries, addDataToTelemetry) {\n foreach(telemetry : telemetries) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[\"values\"].keys.contains(element.key)) {\n telemetry[\"values\"][element.key] = element.value;\n }\n } \n }\n \n return telemetries;\n}\n\nfunction setPressState(decoded, type) {\n switch (type) {\n case 1:\n decoded.press = \"short\";\n break;\n case 2:\n decoded.press = \"long\";\n break;\n case 3:\n decoded.press = \"double\";\n break;\n default:\n decoded.press = \"unknown\";\n break;\n }\n}", + "encoder": null, + "tbelEncoder": null, + "updateOnlyKeys": [ + "fPort", + "applicationName", + "frequency", + "bandwidth", + "spreadingFactor", + "codeRate" + ] + }, + "additionalInfo": { + "description": "" + }, + "edgeTemplate": false +} \ No newline at end of file diff --git a/VENDORS/Milesight/WS101/HTTP/uplink/metadata.json b/VENDORS/Milesight/WS101/HTTP/uplink/metadata.json new file mode 100644 index 00000000..87ee6615 --- /dev/null +++ b/VENDORS/Milesight/WS101/HTTP/uplink/metadata.json @@ -0,0 +1,4 @@ +{ + "integrationName": "HTTP integration", + "includeGatewayInfo": "false" +} \ No newline at end of file diff --git a/VENDORS/Milesight/WS101/HTTP/uplink/payload.json b/VENDORS/Milesight/WS101/HTTP/uplink/payload.json new file mode 100644 index 00000000..769156f7 --- /dev/null +++ b/VENDORS/Milesight/WS101/HTTP/uplink/payload.json @@ -0,0 +1,31 @@ +{ + "applicationID": 1, + "applicationName": "cloud", + "deviceName": "24e1641092176759", + "devEUI": "24e1641092176759", + "time": "2020-0327T12:39:05.547336Z", + "rxInfo": [ + { + "mac": "24e124fffef021be", + "rssi": -57, + "loRaSNR": 10, + "name": "local_gateway", + "latitude": 0, + "longitude": 0, + "altitude": 0 + } + ], + "txInfo": { + "frequency": 868300000, + "dataRate": { + "modulation": "LORA", + "bandwidth": 125, + "spreadFactor": 7 + }, + "adr": false, + "codeRate": "4/5" + }, + "fCnt": 0, + "fPort": 85, + "data": "AXUQ/y4B" +} \ No newline at end of file diff --git a/VENDORS/Milesight/WS101/HTTP/uplink/result.json b/VENDORS/Milesight/WS101/HTTP/uplink/result.json new file mode 100644 index 00000000..897d8079 --- /dev/null +++ b/VENDORS/Milesight/WS101/HTTP/uplink/result.json @@ -0,0 +1,19 @@ +{ + "deviceName": "WS101 24e1641092176759", + "deviceType": "Smoke detector", + "attributes": { + "fPort": 85, + "applicationName": "cloud", + "frequency": 868300000, + "bandwidth": 125, + "spreadingFactor": 7, + "codeRate": "4/5" + }, + "telemetry": [{ + "ts": 1585312745547, + "values": { + "battery": 16, + "press": "short" + } + }] +} \ No newline at end of file diff --git a/VENDORS/Milesight/WS201/HTTP/uplink/converter.json b/VENDORS/Milesight/WS201/HTTP/uplink/converter.json new file mode 100644 index 00000000..2048596e --- /dev/null +++ b/VENDORS/Milesight/WS201/HTTP/uplink/converter.json @@ -0,0 +1,29 @@ +{ + "name": "HTTP Uplink integration for WS201", + "type": "UPLINK", + "debugMode": false, + "debugSettings": { + "failuresEnabled": true, + "allEnabled": false, + "allEnabledUntil": 1735560006385 + }, + "configuration": { + "scriptLang": "TBEL", + "decoder": null, + "tbelDecoder": "var data = decodeToJson(payload);\nvar deviceName = \"WS201 \" + data.devEUI;\nvar deviceType = \"WS201\";\nvar groupName = null; // If groupName is not null - created device will be added to the entity group with such name.\nvar customerName = null; // If customerName is not null - created devices will be assigned to customer with such name. \n\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// If you want to parse incoming data somehow, you can add your code to this function.\n// input: bytes\n// expected output:\n// {\n// \"attributes\": {\"attributeKey\": \"attributeValue\"},\n// \"telemetry\": [{\"ts\": 1...1, \"values\": {\"telemetryKey\":\"telemetryValue\"}, {\"ts\": 1...2, \"values\": {\"telemetryKey\":\"telemetryValue\"}}]\n// }\n\nfunction decodePayload(input) {\n var output = {\n attributes: {},\n telemetry: []\n };\n \n // --- Decoding code --- //\n var decoded = {};\n var fPort = data.fPort;\n if(fPort == 85) {\n for (var i = 0; i < input.length - 2;) {\n var channel_id = input[i++] & 0xff;\n var channel_type = input[i++] & 0xff;\n \n // BATTERY\n if (channel_id === 0x01 && channel_type === 0x75) {\n decoded.battery = input[i];\n i += 1;\n }\n // DISTANCE\n else if (channel_id === 0x03 && channel_type === 0x82) {\n decoded.distance = parseBytesToInt(input, i, 2, false);\n i += 2;\n }\n // REMAINING AMOUNT\n else if (channel_id === 0x04 && channel_type === 0xd6) {\n decoded.remaining = input[i];\n i += 1;\n }\n }\n }\n\n output.telemetry = [{\n ts: timestamp,\n values: decoded\n }];\n \n // --- Decoding code --- //\n return output;\n}\n\n// --- attributes and telemetry objects ---\nvar telemetry = [];\nvar attributes = {};\n// --- attributes and telemetry objects ---\n\n// --- Timestamp parsing\nvar dateString = data.time;\ntimestamp = parseDateToTimestamp(dateString);\n// --- Timestamp parsing\n\n// Passing incoming bytes to decodePayload function, to get custom decoding\nvar customDecoding = decodePayload(base64ToBytes(data.data));\n\n// Collecting data to result\nif (customDecoding.?telemetry.size() > 0) {\n foreach(telemetryObj: customDecoding.telemetry) {\n if (telemetryObj.ts != null && telemetryObj.values != null) {\n telemetry.add(telemetryObj);\n }\n }\n}\n\nif (customDecoding.?attributes.size() > 0) {\n attributes.putAll(customDecoding.attributes);\n}\n\n// You can add some keys manually to attributes or telemetry\nattributes.eui = data.?devEui;\nattributes.fPort = data.fPort;\nattributes.applicationId = data.?applicationId;\nattributes.applicationName = data.?applicationName;\nattributes.frequency = data.txInfo.?frequency;\nattributes.bandwidth = data.txInfo.?dataRate.?bandwidth;\nattributes.spreadingFactor = data.txInfo.?dataRate.?spreadFactor;\nattributes.codeRate = data.txInfo.?codeRate;\n\nif(Boolean.parseBoolean(metadata[\"includeGatewayInfo\"])) {\n var gatewayInfo = getGatewayInfo();\n var addDataToTelemetry = {};\n addDataToTelemetry.snr = gatewayInfo.?loRaSNR;\n addDataToTelemetry.rssi = gatewayInfo.rssi;\n addDataToTelemetry.fCnt = data.fCnt;\n \n telemetry = processTelemetryData(telemetry, addDataToTelemetry);\n}\n\nvar result = {\n deviceName: deviceName,\n deviceType: deviceType,\n // assetName: assetName,\n // assetType: assetType,\n attributes: attributes,\n telemetry: telemetry\n};\n\naddAdditionalInfoForDeviceMsg(result, customerName, groupName);\n\nreturn result;\n\nfunction addAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName) {\n if (customerName != null) {\n deviceInfo.customerName = customerName;\n }\n if (groupName != null) {\n deviceInfo.groupName = groupName;\n }\n}\n\nfunction parseDateToTimestamp(dateString) {\n dateString = dateString.replaceFirst(\"(\\\\d{4}-\\\\d{2})(\\\\d{2})\", \"$1-$2\");\n dateString = dateString.replaceFirst(\"\\\\.(\\\\d{3})\\\\d+Z\", \".$1Z\");\n dateString = dateString.replace(\"Z\", \"+0000\");\n var date = new Date(dateString);\n var timestamp = date.getTime();\n \n // If we cannot parse timestamp - we will use the current timestamp\n if (timestamp == -1) {\n timestamp = Date.now();\n }\n \n return timestamp;\n}\n\nfunction getGatewayInfo() {\n var gatewayList = data.rxInfo;\n var maxRssi = Integer.MIN_VALUE;\n var gatewayInfo = {};\n \n foreach (gateway : gatewayList) {\n if(gateway.rssi > maxRssi) {\n maxRssi = gateway.rssi;\n gatewayInfo = gateway;\n }\n }\n \n return gatewayInfo;\n}\n\nfunction processTelemetryData(telemetry, addDataToTelemetry) {\n if (telemetry.size >= 1) {\n telemetry = addDataToTelemetries(telemetry, addDataToTelemetry);\n }\n else {\n telemetry.add(addDataToTelemetry);\n }\n \n return telemetry;\n}\n\nfunction addDataToTelemetries(telemetries, addDataToTelemetry) {\n foreach(telemetry : telemetries) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[\"values\"].keys.contains(element.key)) {\n telemetry[\"values\"][element.key] = element.value;\n }\n } \n }\n \n return telemetries;\n}", + "encoder": null, + "tbelEncoder": null, + "updateOnlyKeys": [ + "fPort", + "applicationName", + "frequency", + "bandwidth", + "spreadingFactor", + "codeRate" + ] + }, + "additionalInfo": { + "description": "" + }, + "edgeTemplate": false +} \ No newline at end of file diff --git a/VENDORS/Milesight/WS201/HTTP/uplink/metadata.json b/VENDORS/Milesight/WS201/HTTP/uplink/metadata.json new file mode 100644 index 00000000..87ee6615 --- /dev/null +++ b/VENDORS/Milesight/WS201/HTTP/uplink/metadata.json @@ -0,0 +1,4 @@ +{ + "integrationName": "HTTP integration", + "includeGatewayInfo": "false" +} \ No newline at end of file diff --git a/VENDORS/Milesight/WS201/HTTP/uplink/payload.json b/VENDORS/Milesight/WS201/HTTP/uplink/payload.json new file mode 100644 index 00000000..1ef85a50 --- /dev/null +++ b/VENDORS/Milesight/WS201/HTTP/uplink/payload.json @@ -0,0 +1,31 @@ +{ + "applicationID": 1, + "applicationName": "cloud", + "deviceName": "24e1641092176759", + "devEUI": "24e1641092176759", + "time": "2020-0327T12:39:05.547336Z", + "rxInfo": [ + { + "mac": "24e124fffef021be", + "rssi": -57, + "loRaSNR": 10, + "name": "local_gateway", + "latitude": 0, + "longitude": 0, + "altitude": 0 + } + ], + "txInfo": { + "frequency": 868300000, + "dataRate": { + "modulation": "LORA", + "bandwidth": 125, + "spreadFactor": 7 + }, + "adr": false, + "codeRate": "4/5" + }, + "fCnt": 0, + "fPort": 85, + "data": "AXVkA4I+AATWRQ==" +} \ No newline at end of file diff --git a/VENDORS/Milesight/WS201/HTTP/uplink/result.json b/VENDORS/Milesight/WS201/HTTP/uplink/result.json new file mode 100644 index 00000000..d64fa54a --- /dev/null +++ b/VENDORS/Milesight/WS201/HTTP/uplink/result.json @@ -0,0 +1,20 @@ +{ + "deviceName": "WS201 24e1641092176759", + "deviceType": "WS201", + "attributes": { + "fPort": 85, + "applicationName": "cloud", + "frequency": 868300000, + "bandwidth": 125, + "spreadingFactor": 7, + "codeRate": "4/5" + }, + "telemetry": [{ + "ts": 1585312745547, + "values": { + "battery": 100, + "distance": 62, + "remaining": 69 + } + }] +} \ No newline at end of file diff --git a/VENDORS/Milesight/WS202/HTTP/uplink/converter.json b/VENDORS/Milesight/WS202/HTTP/uplink/converter.json new file mode 100644 index 00000000..7a47fb19 --- /dev/null +++ b/VENDORS/Milesight/WS202/HTTP/uplink/converter.json @@ -0,0 +1,29 @@ +{ + "name": "HTTP Uplink integration for WS202", + "type": "UPLINK", + "debugMode": false, + "debugSettings": { + "failuresEnabled": true, + "allEnabled": false, + "allEnabledUntil": 1735560006385 + }, + "configuration": { + "scriptLang": "TBEL", + "decoder": null, + "tbelDecoder": "var data = decodeToJson(payload);\nvar deviceName = \"WS202 \" + data.devEUI;\nvar deviceType = \"WS202\";\nvar groupName = null; // If groupName is not null - created device will be added to the entity group with such name.\nvar customerName = null; // If customerName is not null - created devices will be assigned to customer with such name. \n\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// If you want to parse incoming data somehow, you can add your code to this function.\n// input: bytes\n// expected output:\n// {\n// \"attributes\": {\"attributeKey\": \"attributeValue\"},\n// \"telemetry\": [{\"ts\": 1...1, \"values\": {\"telemetryKey\":\"telemetryValue\"}, {\"ts\": 1...2, \"values\": {\"telemetryKey\":\"telemetryValue\"}}]\n// }\n\nfunction decodePayload(input) {\n var output = {\n attributes: {},\n telemetry: []\n };\n \n // --- Decoding code --- //\n var decoded = {};\n var fPort = data.fPort;\n if(fPort == 85) {\n for (var i = 0; i < input.length - 2;) {\n var channel_id = input[i++] & 0xff;\n var channel_type = input[i++] & 0xff;\n \n // BATTERY\n if (channel_id === 0x01 && channel_type === 0x75) {\n decoded.battery = input[i];\n i += 1;\n }\n // PIR\n else if (channel_id === 0x03 && channel_type === 0x00) {\n decoded.pir = input[i] === 0 ? \"normal\" : \"trigger\";\n i += 1;\n }\n // DAYLIGHT\n else if (channel_id === 0x04 && channel_type === 0x00) {\n decoded.daylight = input[i] === 0 ? \"dark\" : \"light\";\n i += 1;\n }\n }\n }\n\n output.telemetry = [{\n ts: timestamp,\n values: decoded\n }];\n \n // --- Decoding code --- //\n return output;\n}\n\n// --- attributes and telemetry objects ---\nvar telemetry = [];\nvar attributes = {};\n// --- attributes and telemetry objects ---\n\n// --- Timestamp parsing\nvar dateString = data.time;\ntimestamp = parseDateToTimestamp(dateString);\n// --- Timestamp parsing\n\n// Passing incoming bytes to decodePayload function, to get custom decoding\nvar customDecoding = decodePayload(base64ToBytes(data.data));\n\n// Collecting data to result\nif (customDecoding.?telemetry.size() > 0) {\n foreach(telemetryObj: customDecoding.telemetry) {\n if (telemetryObj.ts != null && telemetryObj.values != null) {\n telemetry.add(telemetryObj);\n }\n }\n}\n\nif (customDecoding.?attributes.size() > 0) {\n attributes.putAll(customDecoding.attributes);\n}\n\n// You can add some keys manually to attributes or telemetry\nattributes.eui = data.?devEui;\nattributes.fPort = data.fPort;\nattributes.applicationId = data.?applicationId;\nattributes.applicationName = data.?applicationName;\nattributes.frequency = data.txInfo.?frequency;\nattributes.bandwidth = data.txInfo.?dataRate.?bandwidth;\nattributes.spreadingFactor = data.txInfo.?dataRate.?spreadFactor;\nattributes.codeRate = data.txInfo.?codeRate;\n\nif(Boolean.parseBoolean(metadata[\"includeGatewayInfo\"])) {\n var gatewayInfo = getGatewayInfo();\n var addDataToTelemetry = {};\n addDataToTelemetry.snr = gatewayInfo.?loRaSNR;\n addDataToTelemetry.rssi = gatewayInfo.rssi;\n addDataToTelemetry.fCnt = data.fCnt;\n \n telemetry = processTelemetryData(telemetry, addDataToTelemetry);\n}\n\nvar result = {\n deviceName: deviceName,\n deviceType: deviceType,\n // assetName: assetName,\n // assetType: assetType,\n attributes: attributes,\n telemetry: telemetry\n};\n\naddAdditionalInfoForDeviceMsg(result, customerName, groupName);\n\nreturn result;\n\nfunction addAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName) {\n if (customerName != null) {\n deviceInfo.customerName = customerName;\n }\n if (groupName != null) {\n deviceInfo.groupName = groupName;\n }\n}\n\nfunction parseDateToTimestamp(dateString) {\n dateString = dateString.replaceFirst(\"(\\\\d{4}-\\\\d{2})(\\\\d{2})\", \"$1-$2\");\n dateString = dateString.replaceFirst(\"\\\\.(\\\\d{3})\\\\d+Z\", \".$1Z\");\n dateString = dateString.replace(\"Z\", \"+0000\");\n var date = new Date(dateString);\n var timestamp = date.getTime();\n \n // If we cannot parse timestamp - we will use the current timestamp\n if (timestamp == -1) {\n timestamp = Date.now();\n }\n \n return timestamp;\n}\n\nfunction getGatewayInfo() {\n var gatewayList = data.rxInfo;\n var maxRssi = Integer.MIN_VALUE;\n var gatewayInfo = {};\n \n foreach (gateway : gatewayList) {\n if(gateway.rssi > maxRssi) {\n maxRssi = gateway.rssi;\n gatewayInfo = gateway;\n }\n }\n \n return gatewayInfo;\n}\n\nfunction processTelemetryData(telemetry, addDataToTelemetry) {\n if (telemetry.size >= 1) {\n telemetry = addDataToTelemetries(telemetry, addDataToTelemetry);\n }\n else {\n telemetry.add(addDataToTelemetry);\n }\n \n return telemetry;\n}\n\nfunction addDataToTelemetries(telemetries, addDataToTelemetry) {\n foreach(telemetry : telemetries) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[\"values\"].keys.contains(element.key)) {\n telemetry[\"values\"][element.key] = element.value;\n }\n } \n }\n \n return telemetries;\n}", + "encoder": null, + "tbelEncoder": null, + "updateOnlyKeys": [ + "fPort", + "applicationName", + "frequency", + "bandwidth", + "spreadingFactor", + "codeRate" + ] + }, + "additionalInfo": { + "description": "" + }, + "edgeTemplate": false +} \ No newline at end of file diff --git a/VENDORS/Milesight/WS202/HTTP/uplink/metadata.json b/VENDORS/Milesight/WS202/HTTP/uplink/metadata.json new file mode 100644 index 00000000..87ee6615 --- /dev/null +++ b/VENDORS/Milesight/WS202/HTTP/uplink/metadata.json @@ -0,0 +1,4 @@ +{ + "integrationName": "HTTP integration", + "includeGatewayInfo": "false" +} \ No newline at end of file diff --git a/VENDORS/Milesight/WS202/HTTP/uplink/payload.json b/VENDORS/Milesight/WS202/HTTP/uplink/payload.json new file mode 100644 index 00000000..94204df7 --- /dev/null +++ b/VENDORS/Milesight/WS202/HTTP/uplink/payload.json @@ -0,0 +1,31 @@ +{ + "applicationID": 1, + "applicationName": "cloud", + "deviceName": "24e1641092176759", + "devEUI": "24e1641092176759", + "time": "2020-0327T12:39:05.547336Z", + "rxInfo": [ + { + "mac": "24e124fffef021be", + "rssi": -57, + "loRaSNR": 10, + "name": "local_gateway", + "latitude": 0, + "longitude": 0, + "altitude": 0 + } + ], + "txInfo": { + "frequency": 868300000, + "dataRate": { + "modulation": "LORA", + "bandwidth": 125, + "spreadFactor": 7 + }, + "adr": false, + "codeRate": "4/5" + }, + "fCnt": 0, + "fPort": 85, + "data": "AXUQAwABBAAA" +} \ No newline at end of file diff --git a/VENDORS/Milesight/WS202/HTTP/uplink/result.json b/VENDORS/Milesight/WS202/HTTP/uplink/result.json new file mode 100644 index 00000000..d6d72435 --- /dev/null +++ b/VENDORS/Milesight/WS202/HTTP/uplink/result.json @@ -0,0 +1,20 @@ +{ + "deviceName": "WS202 24e1641092176759", + "deviceType": "WS202", + "attributes": { + "fPort": 85, + "applicationName": "cloud", + "frequency": 868300000, + "bandwidth": 125, + "spreadingFactor": 7, + "codeRate": "4/5" + }, + "telemetry": [{ + "ts": 1585312745547, + "values": { + "battery": 16, + "pir": "trigger", + "daylight": "dark" + } + }] +} \ No newline at end of file diff --git a/VENDORS/Milesight/WS301/HTTP/uplink/converter.json b/VENDORS/Milesight/WS301/HTTP/uplink/converter.json new file mode 100644 index 00000000..0c95323f --- /dev/null +++ b/VENDORS/Milesight/WS301/HTTP/uplink/converter.json @@ -0,0 +1,29 @@ +{ + "name": "HTTP Uplink integration for WS301", + "type": "UPLINK", + "debugMode": false, + "debugSettings": { + "failuresEnabled": true, + "allEnabled": false, + "allEnabledUntil": 1735560006385 + }, + "configuration": { + "scriptLang": "TBEL", + "decoder": null, + "tbelDecoder": "var data = decodeToJson(payload);\nvar deviceName = \"WS301 \" + data.devEUI;\nvar deviceType = \"WS301\";\nvar groupName = null; // If groupName is not null - created device will be added to the entity group with such name.\nvar customerName = null; // If customerName is not null - created devices will be assigned to customer with such name. \n\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// If you want to parse incoming data somehow, you can add your code to this function.\n// input: bytes\n// expected output:\n// {\n// \"attributes\": {\"attributeKey\": \"attributeValue\"},\n// \"telemetry\": [{\"ts\": 1...1, \"values\": {\"telemetryKey\":\"telemetryValue\"}, {\"ts\": 1...2, \"values\": {\"telemetryKey\":\"telemetryValue\"}}]\n// }\n\nfunction decodePayload(input) {\n var output = {\n attributes: {},\n telemetry: []\n };\n \n // --- Decoding code --- //\n var decoded = {};\n var fPort = data.fPort;\n if(fPort == 85) {\n for (var i = 0; i < input.length - 2;) {\n var channel_id = input[i++] & 0xff;\n var channel_type = input[i++] & 0xff;\n \n // BATTERY\n if (channel_id === 0x01 && channel_type === 0x75) {\n decoded.battery = input[i];\n i += 1;\n }\n // DOOR / WINDOW STATE (0: close 1: open)\n else if (channel_id === 0x03 && channel_type === 0x00) {\n decoded.magnet_status = input[i] === 0 ? \"close\" : \"open\";\n i += 1;\n }\n // INSTALL STATE (0: install 1: uninstall)\n else if (channel_id === 0x04 && channel_type === 0x00) {\n decoded.tamper_status = input[i] === 0 ? \"installed\" : \"uninstalled\";\n i += 1;\n }\n }\n }\n\n output.telemetry = [{\n ts: timestamp,\n values: decoded\n }];\n \n // --- Decoding code --- //\n return output;\n}\n\n// --- attributes and telemetry objects ---\nvar telemetry = [];\nvar attributes = {};\n// --- attributes and telemetry objects ---\n\n// --- Timestamp parsing\nvar dateString = data.time;\ntimestamp = parseDateToTimestamp(dateString);\n// --- Timestamp parsing\n\n// Passing incoming bytes to decodePayload function, to get custom decoding\nvar customDecoding = decodePayload(base64ToBytes(data.data));\n\n// Collecting data to result\nif (customDecoding.?telemetry.size() > 0) {\n foreach(telemetryObj: customDecoding.telemetry) {\n if (telemetryObj.ts != null && telemetryObj.values != null) {\n telemetry.add(telemetryObj);\n }\n }\n}\n\nif (customDecoding.?attributes.size() > 0) {\n attributes.putAll(customDecoding.attributes);\n}\n\n// You can add some keys manually to attributes or telemetry\nattributes.eui = data.?devEui;\nattributes.fPort = data.fPort;\nattributes.applicationId = data.?applicationId;\nattributes.applicationName = data.?applicationName;\nattributes.frequency = data.txInfo.?frequency;\nattributes.bandwidth = data.txInfo.?dataRate.?bandwidth;\nattributes.spreadingFactor = data.txInfo.?dataRate.?spreadFactor;\nattributes.codeRate = data.txInfo.?codeRate;\n\nif(Boolean.parseBoolean(metadata[\"includeGatewayInfo\"])) {\n var gatewayInfo = getGatewayInfo();\n var addDataToTelemetry = {};\n addDataToTelemetry.snr = gatewayInfo.?loRaSNR;\n addDataToTelemetry.rssi = gatewayInfo.rssi;\n addDataToTelemetry.fCnt = data.fCnt;\n \n telemetry = processTelemetryData(telemetry, addDataToTelemetry);\n}\n\nvar result = {\n deviceName: deviceName,\n deviceType: deviceType,\n // assetName: assetName,\n // assetType: assetType,\n attributes: attributes,\n telemetry: telemetry\n};\n\naddAdditionalInfoForDeviceMsg(result, customerName, groupName);\n\nreturn result;\n\nfunction addAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName) {\n if (customerName != null) {\n deviceInfo.customerName = customerName;\n }\n if (groupName != null) {\n deviceInfo.groupName = groupName;\n }\n}\n\nfunction parseDateToTimestamp(dateString) {\n dateString = dateString.replaceFirst(\"(\\\\d{4}-\\\\d{2})(\\\\d{2})\", \"$1-$2\");\n dateString = dateString.replaceFirst(\"\\\\.(\\\\d{3})\\\\d+Z\", \".$1Z\");\n dateString = dateString.replace(\"Z\", \"+0000\");\n var date = new Date(dateString);\n var timestamp = date.getTime();\n \n // If we cannot parse timestamp - we will use the current timestamp\n if (timestamp == -1) {\n timestamp = Date.now();\n }\n \n return timestamp;\n}\n\nfunction getGatewayInfo() {\n var gatewayList = data.rxInfo;\n var maxRssi = Integer.MIN_VALUE;\n var gatewayInfo = {};\n \n foreach (gateway : gatewayList) {\n if(gateway.rssi > maxRssi) {\n maxRssi = gateway.rssi;\n gatewayInfo = gateway;\n }\n }\n \n return gatewayInfo;\n}\n\nfunction processTelemetryData(telemetry, addDataToTelemetry) {\n if (telemetry.size >= 1) {\n telemetry = addDataToTelemetries(telemetry, addDataToTelemetry);\n }\n else {\n telemetry.add(addDataToTelemetry);\n }\n \n return telemetry;\n}\n\nfunction addDataToTelemetries(telemetries, addDataToTelemetry) {\n foreach(telemetry : telemetries) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[\"values\"].keys.contains(element.key)) {\n telemetry[\"values\"][element.key] = element.value;\n }\n } \n }\n \n return telemetries;\n}", + "encoder": null, + "tbelEncoder": null, + "updateOnlyKeys": [ + "fPort", + "applicationName", + "frequency", + "bandwidth", + "spreadingFactor", + "codeRate" + ] + }, + "additionalInfo": { + "description": "" + }, + "edgeTemplate": false +} \ No newline at end of file diff --git a/VENDORS/Milesight/WS301/HTTP/uplink/metadata.json b/VENDORS/Milesight/WS301/HTTP/uplink/metadata.json new file mode 100644 index 00000000..87ee6615 --- /dev/null +++ b/VENDORS/Milesight/WS301/HTTP/uplink/metadata.json @@ -0,0 +1,4 @@ +{ + "integrationName": "HTTP integration", + "includeGatewayInfo": "false" +} \ No newline at end of file diff --git a/VENDORS/Milesight/WS301/HTTP/uplink/payload.json b/VENDORS/Milesight/WS301/HTTP/uplink/payload.json new file mode 100644 index 00000000..9c95766b --- /dev/null +++ b/VENDORS/Milesight/WS301/HTTP/uplink/payload.json @@ -0,0 +1,31 @@ +{ + "applicationID": 1, + "applicationName": "cloud", + "deviceName": "24e1641092176759", + "devEUI": "24e1641092176759", + "time": "2020-0327T12:39:05.547336Z", + "rxInfo": [ + { + "mac": "24e124fffef021be", + "rssi": -57, + "loRaSNR": 10, + "name": "local_gateway", + "latitude": 0, + "longitude": 0, + "altitude": 0 + } + ], + "txInfo": { + "frequency": 868300000, + "dataRate": { + "modulation": "LORA", + "bandwidth": 125, + "spreadFactor": 7 + }, + "adr": false, + "codeRate": "4/5" + }, + "fCnt": 0, + "fPort": 85, + "data": "AXVkAwABBAAB" +} \ No newline at end of file diff --git a/VENDORS/Milesight/WS301/HTTP/uplink/result.json b/VENDORS/Milesight/WS301/HTTP/uplink/result.json new file mode 100644 index 00000000..7e7c7eb2 --- /dev/null +++ b/VENDORS/Milesight/WS301/HTTP/uplink/result.json @@ -0,0 +1,20 @@ +{ + "deviceName": "WS301 24e1641092176759", + "deviceType": "WS301", + "attributes": { + "fPort": 85, + "applicationName": "cloud", + "frequency": 868300000, + "bandwidth": 125, + "spreadingFactor": 7, + "codeRate": "4/5" + }, + "telemetry": [{ + "ts": 1585312745547, + "values": { + "battery": 100, + "magnet_status": "open", + "tamper_status": "uninstalled" + } + }] +} \ No newline at end of file diff --git a/VENDORS/Milesight/WS302/HTTP/uplink/converter.json b/VENDORS/Milesight/WS302/HTTP/uplink/converter.json new file mode 100644 index 00000000..feb24d4d --- /dev/null +++ b/VENDORS/Milesight/WS302/HTTP/uplink/converter.json @@ -0,0 +1,29 @@ +{ + "name": "HTTP Uplink integration for WS302", + "type": "UPLINK", + "debugMode": false, + "debugSettings": { + "failuresEnabled": true, + "allEnabled": false, + "allEnabledUntil": 1735560006385 + }, + "configuration": { + "scriptLang": "TBEL", + "decoder": null, + "tbelDecoder": "var data = decodeToJson(payload);\nvar deviceName = \"WS302 \" + data.devEUI;\nvar deviceType = \"WS302\";\nvar groupName = null; // If groupName is not null - created device will be added to the entity group with such name.\nvar customerName = null; // If customerName is not null - created devices will be assigned to customer with such name. \n\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// If you want to parse incoming data somehow, you can add your code to this function.\n// input: bytes\n// expected output:\n// {\n// \"attributes\": {\"attributeKey\": \"attributeValue\"},\n// \"telemetry\": [{\"ts\": 1...1, \"values\": {\"telemetryKey\":\"telemetryValue\"}, {\"ts\": 1...2, \"values\": {\"telemetryKey\":\"telemetryValue\"}}]\n// }\n\nfunction decodePayload(input) {\n var output = {\n attributes: {},\n telemetry: []\n };\n \n // --- Decoding code --- //\n var decoded = {};\n var fPort = data.fPort;\n if(fPort == 85) {\n for (var i = 0; i < input.length - 2;) {\n var channel_id = input[i++] & 0xff;\n var channel_type = input[i++] & 0xff;\n \n // BATTERY\n if (channel_id === 0x01 && channel_type === 0x75) {\n decoded.battery = input[i];\n i += 1;\n }\n // SOUND\n else if (channel_id === 0x05 && channel_type === 0x5b) {\n var weight = input[i];\n var freq_weight = readFrequencyWeightType(weight & 0x03);\n var time_weight = readTimeWeightType((weight >> 2) & 0x03);\n \n var sound_level_name = \"L\" + freq_weight + time_weight;\n sound_level_eq_name = \"L\" + freq_weight + \"eq\";\n sound_level_max_name = \"L\" + freq_weight + time_weight + \"max\";\n decoded[sound_level_name] = parseBytesToInt(input, i + 1, 2, false) / 10;\n decoded[sound_level_eq_name] = parseBytesToInt(input, i + 3, 2, false) / 10;\n decoded[sound_level_max_name] = parseBytesToInt(input, i + 5, 2, false) / 10;\n i += 7;\n }\n // LoRaWAN Class Type\n else if (channel_id === 0xff && channel_type === 0x0f) {\n output.attributes.lorawan_class = readLoRaWANClass(input[i]);\n i += 1;\n }\n }\n }\n\n output.telemetry = [{\n ts: timestamp,\n values: decoded\n }];\n \n // --- Decoding code --- //\n return output;\n}\n\n// --- attributes and telemetry objects ---\nvar telemetry = [];\nvar attributes = {};\n// --- attributes and telemetry objects ---\n\n// --- Timestamp parsing\nvar dateString = data.time;\ntimestamp = parseDateToTimestamp(dateString);\n// --- Timestamp parsing\n\n// Passing incoming bytes to decodePayload function, to get custom decoding\nvar customDecoding = decodePayload(base64ToBytes(data.data));\n\n// Collecting data to result\nif (customDecoding.?telemetry.size() > 0) {\n foreach(telemetryObj: customDecoding.telemetry) {\n if (telemetryObj.ts != null && telemetryObj.values != null) {\n telemetry.add(telemetryObj);\n }\n }\n}\n\nif (customDecoding.?attributes.size() > 0) {\n attributes.putAll(customDecoding.attributes);\n}\n\n// You can add some keys manually to attributes or telemetry\nattributes.eui = data.?devEui;\nattributes.fPort = data.fPort;\nattributes.applicationId = data.?applicationId;\nattributes.applicationName = data.?applicationName;\nattributes.frequency = data.txInfo.?frequency;\nattributes.bandwidth = data.txInfo.?dataRate.?bandwidth;\nattributes.spreadingFactor = data.txInfo.?dataRate.?spreadFactor;\nattributes.codeRate = data.txInfo.?codeRate;\n\nif(Boolean.parseBoolean(metadata[\"includeGatewayInfo\"])) {\n var gatewayInfo = getGatewayInfo();\n var addDataToTelemetry = {};\n addDataToTelemetry.snr = gatewayInfo.?loRaSNR;\n addDataToTelemetry.rssi = gatewayInfo.rssi;\n addDataToTelemetry.fCnt = data.fCnt;\n \n telemetry = processTelemetryData(telemetry, addDataToTelemetry);\n}\n\nvar result = {\n deviceName: deviceName,\n deviceType: deviceType,\n // assetName: assetName,\n // assetType: assetType,\n attributes: attributes,\n telemetry: telemetry\n};\n\naddAdditionalInfoForDeviceMsg(result, customerName, groupName);\n\nreturn result;\n\nfunction addAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName) {\n if (customerName != null) {\n deviceInfo.customerName = customerName;\n }\n if (groupName != null) {\n deviceInfo.groupName = groupName;\n }\n}\n\nfunction parseDateToTimestamp(dateString) {\n dateString = dateString.replaceFirst(\"(\\\\d{4}-\\\\d{2})(\\\\d{2})\", \"$1-$2\");\n dateString = dateString.replaceFirst(\"\\\\.(\\\\d{3})\\\\d+Z\", \".$1Z\");\n dateString = dateString.replace(\"Z\", \"+0000\");\n var date = new Date(dateString);\n var timestamp = date.getTime();\n \n // If we cannot parse timestamp - we will use the current timestamp\n if (timestamp == -1) {\n timestamp = Date.now();\n }\n \n return timestamp;\n}\n\nfunction getGatewayInfo() {\n var gatewayList = data.rxInfo;\n var maxRssi = Integer.MIN_VALUE;\n var gatewayInfo = {};\n \n foreach (gateway : gatewayList) {\n if(gateway.rssi > maxRssi) {\n maxRssi = gateway.rssi;\n gatewayInfo = gateway;\n }\n }\n \n return gatewayInfo;\n}\n\nfunction processTelemetryData(telemetry, addDataToTelemetry) {\n if (telemetry.size >= 1) {\n telemetry = addDataToTelemetries(telemetry, addDataToTelemetry);\n }\n else {\n telemetry.add(addDataToTelemetry);\n }\n \n return telemetry;\n}\n\nfunction addDataToTelemetries(telemetries, addDataToTelemetry) {\n foreach(telemetry : telemetries) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[\"values\"].keys.contains(element.key)) {\n telemetry[\"values\"][element.key] = element.value;\n }\n } \n }\n \n return telemetries;\n}\n\nfunction readFrequencyWeightType(type) {\n switch (type) {\n case 0:\n return \"Z\";\n case 1:\n return \"A\";\n case 2:\n return \"C\";\n }\n}\n\nfunction readTimeWeightType(type) {\n switch (type) {\n case 0: // impulse time weighting\n return \"I\";\n case 1: // fast time weighting\n return \"F\";\n case 2: // slow time weighting\n return \"S\";\n }\n}\n\nfunction readLoRaWANClass(type) {\n switch (type) {\n case 0:\n return \"ClassA\";\n case 1:\n return \"ClassB\";\n case 2:\n return \"ClassC\";\n case 3:\n return \"ClassCtoB\";\n }\n}", + "encoder": null, + "tbelEncoder": null, + "updateOnlyKeys": [ + "fPort", + "applicationName", + "frequency", + "bandwidth", + "spreadingFactor", + "codeRate" + ] + }, + "additionalInfo": { + "description": "" + }, + "edgeTemplate": false +} \ No newline at end of file diff --git a/VENDORS/Milesight/WS302/HTTP/uplink/metadata.json b/VENDORS/Milesight/WS302/HTTP/uplink/metadata.json new file mode 100644 index 00000000..87ee6615 --- /dev/null +++ b/VENDORS/Milesight/WS302/HTTP/uplink/metadata.json @@ -0,0 +1,4 @@ +{ + "integrationName": "HTTP integration", + "includeGatewayInfo": "false" +} \ No newline at end of file diff --git a/VENDORS/Milesight/WS302/HTTP/uplink/payload.json b/VENDORS/Milesight/WS302/HTTP/uplink/payload.json new file mode 100644 index 00000000..fcbd5ee3 --- /dev/null +++ b/VENDORS/Milesight/WS302/HTTP/uplink/payload.json @@ -0,0 +1,31 @@ +{ + "applicationID": 1, + "applicationName": "cloud", + "deviceName": "24e1641092176759", + "devEUI": "24e1641092176759", + "time": "2020-0327T12:39:05.547336Z", + "rxInfo": [ + { + "mac": "24e124fffef021be", + "rssi": -57, + "loRaSNR": 10, + "name": "local_gateway", + "latitude": 0, + "longitude": 0, + "altitude": 0 + } + ], + "txInfo": { + "frequency": 868300000, + "dataRate": { + "modulation": "LORA", + "bandwidth": 125, + "spreadFactor": 7 + }, + "adr": false, + "codeRate": "4/5" + }, + "fCnt": 0, + "fPort": 85, + "data": "AXVkBVsFPwLaAWoC" +} \ No newline at end of file diff --git a/VENDORS/Milesight/WS302/HTTP/uplink/result.json b/VENDORS/Milesight/WS302/HTTP/uplink/result.json new file mode 100644 index 00000000..3ee8020b --- /dev/null +++ b/VENDORS/Milesight/WS302/HTTP/uplink/result.json @@ -0,0 +1,21 @@ +{ + "deviceName": "WS302 24e1641092176759", + "deviceType": "WS302", + "attributes": { + "fPort": 85, + "applicationName": "cloud", + "frequency": 868300000, + "bandwidth": 125, + "spreadingFactor": 7, + "codeRate": "4/5" + }, + "telemetry": [{ + "ts": 1585312745547, + "values": { + "battery": 100, + "LAF": 57.5, + "LAeq": 47.4, + "LAFmax": 61.8 + } + }] +} \ No newline at end of file diff --git a/VENDORS/Milesight/WS303/HTTP/uplink/converter.json b/VENDORS/Milesight/WS303/HTTP/uplink/converter.json new file mode 100644 index 00000000..a85ef7d7 --- /dev/null +++ b/VENDORS/Milesight/WS303/HTTP/uplink/converter.json @@ -0,0 +1,29 @@ +{ + "name": "HTTP Uplink integration for WS303", + "type": "UPLINK", + "debugMode": false, + "debugSettings": { + "failuresEnabled": true, + "allEnabled": false, + "allEnabledUntil": 1735560006385 + }, + "configuration": { + "scriptLang": "TBEL", + "decoder": null, + "tbelDecoder": "var data = decodeToJson(payload);\nvar deviceName = \"WS303 \" + data.devEUI;\nvar deviceType = \"WS303\";\nvar groupName = null; // If groupName is not null - created device will be added to the entity group with such name.\nvar customerName = null; // If customerName is not null - created devices will be assigned to customer with such name. \n\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// If you want to parse incoming data somehow, you can add your code to this function.\n// input: bytes\n// expected output:\n// {\n// \"attributes\": {\"attributeKey\": \"attributeValue\"},\n// \"telemetry\": [{\"ts\": 1...1, \"values\": {\"telemetryKey\":\"telemetryValue\"}, {\"ts\": 1...2, \"values\": {\"telemetryKey\":\"telemetryValue\"}}]\n// }\n\nfunction decodePayload(input) {\n var output = {\n attributes: {},\n telemetry: []\n };\n \n // --- Decoding code --- //\n var decoded = {};\n var fPort = data.fPort;\n if(fPort == 85) {\n for (var i = 0; i < input.length - 2;) {\n var channel_id = input[i++] & 0xff;\n var channel_type = input[i++] & 0xff;\n \n // BATTERY\n if (channel_id === 0x01 && channel_type === 0x75) {\n decoded.battery = input[i];\n i += 1;\n }\n // WATER LEAK\n else if (channel_id === 0x03 && channel_type === 0x00) {\n decoded.leakage_status = input[i] === 0 ? \"normal\" : \"leak\";\n i += 1;\n }\n }\n }\n\n output.telemetry = [{\n ts: timestamp,\n values: decoded\n }];\n \n // --- Decoding code --- //\n return output;\n}\n\n// --- attributes and telemetry objects ---\nvar telemetry = [];\nvar attributes = {};\n// --- attributes and telemetry objects ---\n\n// --- Timestamp parsing\nvar dateString = data.time;\ntimestamp = parseDateToTimestamp(dateString);\n// --- Timestamp parsing\n\n// Passing incoming bytes to decodePayload function, to get custom decoding\nvar customDecoding = decodePayload(base64ToBytes(data.data));\n\n// Collecting data to result\nif (customDecoding.?telemetry.size() > 0) {\n foreach(telemetryObj: customDecoding.telemetry) {\n if (telemetryObj.ts != null && telemetryObj.values != null) {\n telemetry.add(telemetryObj);\n }\n }\n}\n\nif (customDecoding.?attributes.size() > 0) {\n attributes.putAll(customDecoding.attributes);\n}\n\n// You can add some keys manually to attributes or telemetry\nattributes.eui = data.?devEui;\nattributes.fPort = data.fPort;\nattributes.applicationId = data.?applicationId;\nattributes.applicationName = data.?applicationName;\nattributes.frequency = data.txInfo.?frequency;\nattributes.bandwidth = data.txInfo.?dataRate.?bandwidth;\nattributes.spreadingFactor = data.txInfo.?dataRate.?spreadFactor;\nattributes.codeRate = data.txInfo.?codeRate;\n\nif(Boolean.parseBoolean(metadata[\"includeGatewayInfo\"])) {\n var gatewayInfo = getGatewayInfo();\n var addDataToTelemetry = {};\n addDataToTelemetry.snr = gatewayInfo.?loRaSNR;\n addDataToTelemetry.rssi = gatewayInfo.rssi;\n addDataToTelemetry.fCnt = data.fCnt;\n \n telemetry = processTelemetryData(telemetry, addDataToTelemetry);\n}\n\nvar result = {\n deviceName: deviceName,\n deviceType: deviceType,\n // assetName: assetName,\n // assetType: assetType,\n attributes: attributes,\n telemetry: telemetry\n};\n\naddAdditionalInfoForDeviceMsg(result, customerName, groupName);\n\nreturn result;\n\nfunction addAdditionalInfoForDeviceMsg(deviceInfo, customerName, groupName) {\n if (customerName != null) {\n deviceInfo.customerName = customerName;\n }\n if (groupName != null) {\n deviceInfo.groupName = groupName;\n }\n}\n\nfunction parseDateToTimestamp(dateString) {\n dateString = dateString.replaceFirst(\"(\\\\d{4}-\\\\d{2})(\\\\d{2})\", \"$1-$2\");\n dateString = dateString.replaceFirst(\"\\\\.(\\\\d{3})\\\\d+Z\", \".$1Z\");\n dateString = dateString.replace(\"Z\", \"+0000\");\n var date = new Date(dateString);\n var timestamp = date.getTime();\n \n // If we cannot parse timestamp - we will use the current timestamp\n if (timestamp == -1) {\n timestamp = Date.now();\n }\n \n return timestamp;\n}\n\nfunction getGatewayInfo() {\n var gatewayList = data.rxInfo;\n var maxRssi = Integer.MIN_VALUE;\n var gatewayInfo = {};\n \n foreach (gateway : gatewayList) {\n if(gateway.rssi > maxRssi) {\n maxRssi = gateway.rssi;\n gatewayInfo = gateway;\n }\n }\n \n return gatewayInfo;\n}\n\nfunction processTelemetryData(telemetry, addDataToTelemetry) {\n if (telemetry.size >= 1) {\n telemetry = addDataToTelemetries(telemetry, addDataToTelemetry);\n }\n else {\n telemetry.add(addDataToTelemetry);\n }\n \n return telemetry;\n}\n\nfunction addDataToTelemetries(telemetries, addDataToTelemetry) {\n foreach(telemetry : telemetries) {\n foreach(element : addDataToTelemetry.entrySet()) {\n if(!telemetry[\"values\"].keys.contains(element.key)) {\n telemetry[\"values\"][element.key] = element.value;\n }\n } \n }\n \n return telemetries;\n}", + "encoder": null, + "tbelEncoder": null, + "updateOnlyKeys": [ + "fPort", + "applicationName", + "frequency", + "bandwidth", + "spreadingFactor", + "codeRate" + ] + }, + "additionalInfo": { + "description": "" + }, + "edgeTemplate": false +} \ No newline at end of file diff --git a/VENDORS/Milesight/WS303/HTTP/uplink/metadata.json b/VENDORS/Milesight/WS303/HTTP/uplink/metadata.json new file mode 100644 index 00000000..87ee6615 --- /dev/null +++ b/VENDORS/Milesight/WS303/HTTP/uplink/metadata.json @@ -0,0 +1,4 @@ +{ + "integrationName": "HTTP integration", + "includeGatewayInfo": "false" +} \ No newline at end of file diff --git a/VENDORS/Milesight/WS303/HTTP/uplink/payload.json b/VENDORS/Milesight/WS303/HTTP/uplink/payload.json new file mode 100644 index 00000000..8c94d4ab --- /dev/null +++ b/VENDORS/Milesight/WS303/HTTP/uplink/payload.json @@ -0,0 +1,31 @@ +{ + "applicationID": 1, + "applicationName": "cloud", + "deviceName": "24e1641092176759", + "devEUI": "24e1641092176759", + "time": "2020-0327T12:39:05.547336Z", + "rxInfo": [ + { + "mac": "24e124fffef021be", + "rssi": -57, + "loRaSNR": 10, + "name": "local_gateway", + "latitude": 0, + "longitude": 0, + "altitude": 0 + } + ], + "txInfo": { + "frequency": 868300000, + "dataRate": { + "modulation": "LORA", + "bandwidth": 125, + "spreadFactor": 7 + }, + "adr": false, + "codeRate": "4/5" + }, + "fCnt": 0, + "fPort": 85, + "data": "AXVkAwAA" +} \ No newline at end of file diff --git a/VENDORS/Milesight/WS303/HTTP/uplink/result.json b/VENDORS/Milesight/WS303/HTTP/uplink/result.json new file mode 100644 index 00000000..6d48044d --- /dev/null +++ b/VENDORS/Milesight/WS303/HTTP/uplink/result.json @@ -0,0 +1,19 @@ +{ + "deviceName": "WS303 24e1641092176759", + "deviceType": "WS303", + "attributes": { + "fPort": 85, + "applicationName": "cloud", + "frequency": 868300000, + "bandwidth": 125, + "spreadingFactor": 7, + "codeRate": "4/5" + }, + "telemetry": [{ + "ts": 1585312745547, + "values": { + "battery": 100, + "leakage_status": "normal" + } + }] +} \ No newline at end of file From 7fb584ecc5fa8948feda626e124ae37402f593f0 Mon Sep 17 00:00:00 2001 From: ArtemAbrams Date: Mon, 30 Dec 2024 17:19:26 +0200 Subject: [PATCH 32/33] Fixed mismatch between payload and result for AM102L --- VENDORS/Milesight/AM102L/HTTP/uplink/result.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/VENDORS/Milesight/AM102L/HTTP/uplink/result.json b/VENDORS/Milesight/AM102L/HTTP/uplink/result.json index 3b140424..a98a4529 100644 --- a/VENDORS/Milesight/AM102L/HTTP/uplink/result.json +++ b/VENDORS/Milesight/AM102L/HTTP/uplink/result.json @@ -1,6 +1,6 @@ { - "deviceName": "AM103 24e1641092176759", - "deviceType": "AM103", + "deviceName": "AM102L 24e1641092176759", + "deviceType": "AM102L", "attributes": { "fPort": 85, "applicationName": "cloud", From a43034dea8c36ed9f8747d22d643b7a073a0ff82 Mon Sep 17 00:00:00 2001 From: ArtemAbrams Date: Mon, 30 Dec 2024 17:24:09 +0200 Subject: [PATCH 33/33] Added missing result for AM102 Loriot integration --- .../AM102/LORIOT/uplink/result_2.json | 43 +++++++++++++++++++ .../AM102/LORIOT/uplink/result_3.json | 0 2 files changed, 43 insertions(+) create mode 100644 VENDORS/Milesight/AM102/LORIOT/uplink/result_2.json delete mode 100644 VENDORS/Milesight/AM102/LORIOT/uplink/result_3.json diff --git a/VENDORS/Milesight/AM102/LORIOT/uplink/result_2.json b/VENDORS/Milesight/AM102/LORIOT/uplink/result_2.json new file mode 100644 index 00000000..10e240d0 --- /dev/null +++ b/VENDORS/Milesight/AM102/LORIOT/uplink/result_2.json @@ -0,0 +1,43 @@ +[{ + "deviceName": "AM102 0102030405060708", + "deviceType": "AM102", + "attributes": { + "eui": "0102030405060708", + "fPort": 207, + "frequency": 868300000 + }, + "telemetry": [{ + "ts": 1690901260493, + "values": { + "battery": 100, + "temperature": 28.0, + "humidity": 54.5 + } + }] +}, { + "deviceName": "Gateway 1020304080706050", + "deviceType": "Lora gateway", + "telemetry": [{ + "ts": 1690901260493, + "values": { + "rssi": -38, + "snr": 8.5 + } + }], + "attributes": { + "eui": "1020304080706050" + } +}, { + "deviceName": "Gateway 1020304081716151", + "deviceType": "Lora gateway", + "telemetry": [{ + "ts": 1690901260495, + "values": { + "rssi": -42, + "snr": 8.8 + } + }], + "attributes": { + "eui": "1020304081716151" + } +}] \ No newline at end of file diff --git a/VENDORS/Milesight/AM102/LORIOT/uplink/result_3.json b/VENDORS/Milesight/AM102/LORIOT/uplink/result_3.json deleted file mode 100644 index e69de29b..00000000