Sensor
//IEEE754 hex to float convert function hex2float(num) { var sign = num & 0x80000000 ? -1 : 1; var exponent = ((num >> 23) & 0xff) - 127; var mantissa = 1 + (num & 0x7fffff) / 0x7fffff; return sign * mantissa * Math.pow(2, exponent); } function decodeUplink(input) { if (input.fPort != 3) { return { errors: ['unknown FPort'], }; } switch (input.bytes.length) { case 18: return { // Decoded data data: { level: (input.bytes[5] << 8) + input.bytes[6], alarmLevel: Boolean(input.bytes[11] >> 4), alarmBattery: Boolean(input.bytes[12] & 0x0f), temperature: input.bytes[8], volt: ((input.bytes[13] << 8) + input.bytes[14]) / 100, frameCounter: (input.bytes[15] << 8) + input.bytes[16], }, }; case 12: return { // Decoded data data: { firmware: input.bytes[5] + "." +input.bytes[6], uploadInterval: input.bytes[7], detectInterval: input.bytes[8], levelThreshold: input.bytes[9], workMode: input.bytes[10], }, }; default: return { errors: ['wrong length'], }; } } // Encode downlink function. // // Input is an object with the following fields: // - data = Object representing the payload that must be encoded. // - variables = Object containing the configured device variables. // // Output must be an object with the following fields: // - bytes = Byte array containing the downlink payload. function encodeDownlink(input) { if (input.data.uploadInterval != null && !isNaN(input.data.uploadInterval)) { var uploadInterval = input.data.uploadInterval; var uploadInterval_high = uploadInterval.toString(16).padStart(2, '0').toUpperCase()[0].charCodeAt(0); var uploadInterval_low = uploadInterval.toString(16).padStart(2, '0').toUpperCase()[1].charCodeAt(0); if (uploadInterval > 255 || uploadInterval < 1) { return { errors: ['upload interval range 1-255 hours.'], }; } else { return { // LoRaWAN FPort used for the downlink message fPort: 3, // Encoded bytes bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x31, uploadInterval_high, uploadInterval_low, 0x38, 0x31], }; } } if (input.data.detectInterval != null && !isNaN(input.data.detectInterval)) { var detectInterval = input.data.detectInterval; var detectInterval_high = detectInterval.toString(16).padStart(2, '0').toUpperCase()[0].charCodeAt(0); var detectInterval_low = detectInterval.toString(16).padStart(2, '0').toUpperCase()[1].charCodeAt(0); if (detectInterval > 255 || detectInterval < 1) { return { errors: ['detection interval range 1-255 minutes.'], }; } else { return { // LoRaWAN FPort used for the downlink message fPort: 3, // Encoded bytes bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x38, detectInterval_high, detectInterval_low, 0x38, 0x31], }; } } if (input.data.levelThreshold != null && !isNaN(input.data.levelThreshold)) { var levelThreshold = input.data.levelThreshold; var levelThreshold_high = levelThreshold.toString(16).padStart(2, '0').toUpperCase()[0].charCodeAt(0); var levelThreshold_low = levelThreshold.toString(16).padStart(2, '0').toUpperCase()[1].charCodeAt(0); if (levelThreshold > 3 || levelThreshold < 1) { return { errors: ['Air quality alarm threshold range 1-3.'], }; } else { return { // LoRaWAN FPort used for the downlink message fPort: 3, // Encoded bytes bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x32, levelThreshold_high, levelThreshold_low, 0x38, 0x31], }; } } if (input.data.workMode != null && !isNaN(input.data.workMode)) { var workMode = input.data.workMode; if (workMode === 0) { return { // LoRaWAN FPort used for the downlink message fPort: 3, // Encoded bytes bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x39, 0x30, 0x35, 0x38, 0x31], }; } else if(workMode === 1) { return { // LoRaWAN FPort used for the downlink message fPort: 3, // Encoded bytes bytes: [0x38, 0x30, 0x30, 0x32, 0x39, 0x39, 0x39, 0x39, 0x30, 0x39, 0x30, 0x36, 0x38, 0x31], }; }else{ return { errors: ['Work mode range 0-1.'], } } } return { errors: ['invalid downlink parameter.'], }; } function decodeDownlink(input) { var input_length = input.bytes.length; if (input.fPort != 3) { return { errors: ['invalid FPort.'], }; } if ( input_length < 12 || input.bytes[0] != 0x38 || input.bytes[1] != 0x30 || input.bytes[2] != 0x30 || input.bytes[3] != 0x32 || input.bytes[4] != 0x39 || input.bytes[5] != 0x39 || input.bytes[6] != 0x39 || input.bytes[7] != 0x39 || input.bytes[input_length - 2] != 0x38 || input.bytes[input_length - 1] != 0x31 ) { return { errors: ['invalid format.'], }; } var option = parseInt(String.fromCharCode(input.bytes[8]) + String.fromCharCode(input.bytes[9]), 16); var value = parseInt(String.fromCharCode(input.bytes[10]) + String.fromCharCode(input.bytes[11]), 16); switch (option) { case 1: return { data: { uploadInterval: value, }, }; case 8: return { data: { detectInterval: value, }, }; case 2: return { data: { levelThreshold: value, }, }; case 9: switch (value) { case 0x05: return { data: { workMode: 0, }, }; case 0x06: return { data: { workMode: 1, }, }; default: return { errors: ['invalid parameter value.'], }; } default: return { errors: ['invalid parameter key.'], }; } }
This codec is sourced from The Things Network. All rights belong to The Things Network.
This codec is licensed under the GNU General Public License v3 (GPL v3). Modifications, if any, are clearly marked. You are free to use, modify, and distribute the codec under the terms of GPL v3.