{ "name": "ChirpStack Uplink Converter for Milesight WS202", "type": "UPLINK", "integrationType": "CHIRPSTACK", "debugMode": false, "debugSettings": { "failuresEnabled": true, "allEnabled": false, "allEnabledUntil": 0 }, "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": "/**\n * Decodes the incoming payload and returns a structured object containing telemetry data and attributes.\n *\n * @param {byte[]} input - The raw payload received as an array of bytes.\n * @returns {Object} output - The structured output with decoded telemetry and attributes.\n */\n\nfunction decodePayload(input) {\n // Initialize the output object with empty attributes and telemetry for clarity.\n var result = { attributes: {}, telemetry: {}};\n\n\n // Extract the timestamp from metadata (represented in milliseconds).\n var timestamp = metadata.ts; // ts is the timestamp parsed from the incoming message's time, or returns the current time if it cannot be parsed.\n\n var values = {};\n for (var i = 0; i < input.length; ) {\n var channel_id = input[i++] & 0xff;\n var channel_type = input[i++] & 0xff;\n // IPSO VERSION\n if (channel_id === 0xff && channel_type === 0x01) {\n values.ipso_version = readProtocolVersion(input[i]);\n i += 1;\n }\n // HARDWARE VERSION\n else if (channel_id === 0xff && channel_type === 0x09) {\n values.hardware_version = readHardwareVersion(input.slice(i, i + 2));\n i += 2;\n }\n // FIRMWARE VERSION\n else if (channel_id === 0xff && channel_type === 0x0a) {\n values.firmware_version = readFirmwareVersion(input.slice(i, i + 2));\n i += 2;\n }\n // TSL VERSION\n else if (channel_id === 0xff && channel_type === 0xff) {\n values.tsl_version = readTslVersion(input.slice(i, i + 2));\n i += 2;\n }\n // SERIAL NUMBER\n else if (channel_id === 0xff && channel_type === 0x16) {\n values.sn = readSerialNumber(input.slice(i, i + 8));\n i += 8;\n }\n // LORAWAN CLASS TYPE\n else if (channel_id === 0xff && channel_type === 0x0f) {\n values.lorawan_class = readLoRaWANClass(input[i]);\n i += 1;\n }\n // RESET EVENT\n else if (channel_id === 0xff && channel_type === 0xfe) {\n values.reset_event = readResetEvent(1);\n i += 1;\n }\n // DEVICE STATUS\n else if (channel_id === 0xff && channel_type === 0x0b) {\n values.device_status = readDeviceStatus(1);\n i += 1;\n }\n // BATTERY\n if (channel_id === 0x01 && channel_type === 0x75) {\n values.battery = input[i];\n i += 1;\n }\n // PIR\n else if (channel_id === 0x03 && channel_type === 0x00) {\n values.pir = input[i] === 0 ? \"normal\" : \"trigger\";\n i += 1;\n }\n // DAYLIGHT\n else if (channel_id === 0x04 && channel_type === 0x00) {\n values.daylight = input[i] === 0 ? \"dark\" : \"light\";\n i += 1;\n }\n }\n\n // Combine the timestamp with values and add it to the telemetry.\n result.telemetry = {\n ts: timestamp,\n values: values\n };\n\n // Return the fully constructed output object.\n return result;\n}\n\nvar result = decodePayload(payload);\n\n// Return the final result object.\nreturn result;\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 result = \"\";\n for (int i = 0; i < bytes.length; i++) {\n var hex = Integer.toHexString(bytes[i] & 0xFF);\n if (hex.length() == 1) {\n hex = \"0\" + hex;\n }\n result += hex;\n }\n return result;\n}\n\nfunction readLoRaWANClass(type) {\n switch (type) {\n case 0: return \"Class A\";\n case 1: return \"Class B\";\n case 2: return \"Class C\";\n case 3: return \"Class CtoB\";\n default: return null;\n }\n}\n\nfunction readResetEvent(status) {\n switch (status) {\n case 0: return \"normal\";\n case 1: return \"reset\";\n default: return null;\n }\n}\n\nfunction readDeviceStatus(status) {\n switch (status) {\n case 0: return \"off\";\n case 1: return \"on\";\n default: return null;\n }\n}\n\nfunction readYesNoStatus(status) {\n switch (status) {\n case 0: return \"no\";\n case 1: return \"yes\";\n default: return null;\n }\n}\n\nfunction readPirStatus(status) {\n switch (status) {\n case 0: return \"normal\";\n case 1: return \"trigger\";\n default: return null;\n }\n}\n\nfunction readDaylight(status) {\n switch (status) {\n case 0: return \"dim\";\n case 1: return \"bright\";\n default: return null;\n }\n}", "encoder": null, "tbelEncoder": null, "updateOnlyKeys": [ "eui", "devAddr", "fPort", "tenantId", "tenantName", "applicationId", "applicationName", "adr", "dr", "frequency", "bandwidth", "spreadingFactor", "codeRate", "deviceProfileId", "deviceProfileName" ], "type": "DEVICE", "name": "WS202 $eui", "profile": "$deviceProfileName", "label": "$deviceName", "customer": "", "group": "", "telemetry": null, "attributes": [ "eui", "devAddr", "fPort", "tenantId", "tenantName", "applicationId", "applicationName", "adr", "dr", "frequency", "bandwidth", "spreadingFactor", "codeRate", "deviceProfileId", "deviceProfileName" ] }, "additionalInfo": { "description": "" }, "edgeTemplate": false, "converterVersion": 2 }