-
Notifications
You must be signed in to change notification settings - Fork 12
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #42 from artem-barysh-dev/ers2-sound
ERS2 Sound
- Loading branch information
Showing
19 changed files
with
496 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
{ | ||
"name": "ChirpStack Uplink Decoder for Elsys ERS2 Sound Device", | ||
"type": "UPLINK", | ||
"debugMode": true, | ||
"configuration": { | ||
"scriptLang": "TBEL", | ||
"decoder": null, | ||
"tbelDecoder": "var data = decodeToJson(payload);\nvar deviceName = data.deviceInfo.deviceName + \" \" + data.deviceInfo.devEui;\nvar deviceType = data.deviceInfo.deviceProfileName;\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;) {\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 == 0x15) { // Sound\n decoded.soundPeak = input[i];\n decoded.soundAvg = input[i+1];\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\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\n.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\nvar gatewayInfo = getGatewayInfo();\nvar addDataToTelemetry = {};\naddDataToTelemetry.snr = gatewayInfo.snr;\naddDataToTelemetry.rssi = gatewayInfo.rssi;\naddDataToTelemetry.channel = gatewayInfo.channel;\naddDataToTelemetry.rfChain = gatewayInfo.rfChain;\naddDataToTelemetry.fCnt = data.fCnt;\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\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 timestamp = new Date(dateString).getTime();\n if (timestamp == -1) {\n var secondsSeparatorIndex = dateString.lastIndexOf(\n '.') + 1;\n var millisecondsEndIndex = dateString.lastIndexOf(\n '+');\n if (millisecondsEndIndex == -1) {\n millisecondsEndIndex = dateString.lastIndexOf(\n 'Z');\n }\n if (millisecondsEndIndex == -1) {\n millisecondsEndIndex = dateString.lastIndexOf(\n '-');\n }\n if (millisecondsEndIndex == -1) {\n if (dateString.length >= secondsSeparatorIndex +\n 3) {\n dateString = dateString.substring(0,\n secondsSeparatorIndex + 3);\n }\n } else {\n dateString = dateString.substring(0,\n secondsSeparatorIndex + 3) +\n dateString.substring(millisecondsEndIndex,\n 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 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 = 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": [ | ||
"tenantId", | ||
"tenantName", | ||
"applicationId", | ||
"applicationName", | ||
"deviceProfileId", | ||
"deviceProfileName", | ||
"devAddr", | ||
"fPort", | ||
"frequency", | ||
"bandwidth", | ||
"spreadingFactor", | ||
"codeRate", | ||
"channel", | ||
"rfChain", | ||
"eui", | ||
"vdd" | ||
] | ||
}, | ||
"additionalInfo": { | ||
"description": "" | ||
}, | ||
"edgeTemplate": false | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
{ | ||
"integrationName": "ChirpStack integration", | ||
"includeGatewayInfo": "false" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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": "AQDiAikEACcFBgcNYhUHEA==", | ||
"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" | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
{ | ||
"deviceName": "Device name 1000000000000001", | ||
"deviceType": "Chirpstack default device profile", | ||
"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": 22.6, | ||
"humidity": 41, | ||
"light": 39, | ||
"pir": 6, | ||
"vdd": 3426, | ||
"soundPeak": 7, | ||
"soundAvg": 16 | ||
} | ||
}] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
{ | ||
"name": "Loriot Uplink Decoder for Elsys ERS2 Sound Device", | ||
"type": "UPLINK", | ||
"debugMode": true, | ||
"configuration": { | ||
"scriptLang": "TBEL", | ||
"decoder": "// Decode an uplink message from a buffer\n// payload - array of bytes\n// metadata - key/value object\n\n/** Decoder **/\n\n// decode payload to string\nvar payloadStr = decodeToString(payload);\n\n// decode payload to JSON\n// var data = decodeToJson(payload);\n\nvar deviceName = 'Device A';\nvar deviceType = 'thermostat';\nvar customerName = 'Customer C';\nvar groupName = 'thermostat devices';\nvar manufacturer = 'Example corporation';\n// use assetName and assetType instead of deviceName and deviceType\n// to automatically create assets instead of devices.\n// var assetName = 'Asset A';\n// var assetType = 'building';\n\n// Result object with device/asset attributes/telemetry data\nvar result = {\n// Use deviceName and deviceType or assetName and assetType, but not both.\n deviceName: deviceName,\n deviceType: deviceType,\n// assetName: assetName,\n// assetType: assetType,\n// customerName: customerName,\n groupName: groupName,\n attributes: {\n model: 'Model A',\n serialNumber: 'SN111',\n integrationName: metadata['integrationName'],\n manufacturer: manufacturer\n },\n telemetry: {\n temperature: 42,\n humidity: 80,\n rawData: payloadStr\n }\n};\n\n/** Helper functions **/\n\nfunction decodeToString(payload) {\n return String.fromCharCode.apply(String, payload);\n}\n\nfunction decodeToJson(payload) {\n // covert payload to string.\n var str = decodeToString(payload);\n\n // parse string to JSON\n var data = JSON.parse(str);\n return data;\n}\n\nreturn result;", | ||
"tbelDecoder": "var data = decodeToJson(payload);\nvar deviceName = \"ERS2 Sound\" + data.EUI;\nvar deviceType = \"ERS2 Sound\";\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 == 0x15) { // Sound\n decoded.soundPeak = input[i];\n decoded.soundAvg = input[i+1];\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": [ | ||
"fPort", | ||
"ack", | ||
"eui", | ||
"frequency", | ||
"dr", | ||
"vdd" | ||
] | ||
}, | ||
"additionalInfo": { | ||
"description": "" | ||
}, | ||
"edgeTemplate": false | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
{ | ||
"integrationName": "Loriot integration", | ||
"includeGatewayInfo": "false" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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": "0100e202290400270506070d62150710" | ||
} |
Oops, something went wrong.