TTN Smart Sensor (Imst)

Sensor

Codec Description

Codec for Imst

Codec Preview

/* * range-extender.js * * Modification History: * Date Version Modified By Description * 2020-12-16 1.0 MR Initial creation * 2021-02-17 1.1 MR synchonized --> synchronized * 2021-02-26 1.2 MR payload length check and right start of payload of one WMBus packet * 2021-08-03 1.3 MR status extended with system voltage and firmware type for firmware 1.1ff * support port 0x4B == 75 with RSSI values for WM-BUS data for firmware 1.1ff * 2021-10-26 1.4 MR WmBus data interpretation removed - only status available * fix for detecting flash errors bits */ function decodeUplink(input) { var port = input.fPort; var bytes = input.bytes; var decoded = Decoder(bytes, port); var returnObject = {}; returnObject.data = decoded; return returnObject; } function encodeDownlink(input) { return { // Decoded data data: {}, // Warnings warnings: "Encoding of downlink is not supported" }; } function decodeDownlink(input) { return { // Decoded data data: {}, // Warnings warnings: "Decoding of downlink is not supported" }; } function Decoder(bytes, port) { return startRangeExtenderIMSTDecoder(bytes, port); } //ports of none segmented payload var STATUS_PORT = 0x03; function startRangeExtenderIMSTDecoder (bytes, port) { //create object to fill with indicated data fields var retObject = { }; switch (port) { case STATUS_PORT: //upload port for status data retObject = decodeStatusPayload(bytes); break; } return retObject; } /***** decode status start ******/ var SYSTEM_TIME_FIELD_POS = 0; var SYSTEM_TIME_FIELD_SIZE = 4; var FIRMWARE_VERSION_MINOR_POS = 4; var FIRMWARE_VERSION_MAJOR_POS = 5; var LAST_SYNC_TIME_FIELD_POS = 6; var LAST_SYNC_TIME_FIELD_SIZE = 4; var RESET_COUNTER_FIELD_POS = 10; var RESET_COUNTER_FIELD_SIZE = 4; var STATUS_BITS_FIELD_POS = 14; var STATUS_BITS_FIELD_SIZE = 2; var RX_COUNTER_FIELD_POS = 16; var RX_COUNTER_FIELD_SIZE = 4; var SD_COUNTER_FIELD_POS = 20; var SD_COUNTER_FIELD_SIZE = 4; var TX_COUNTER_FIELD_POS = 24; var TX_COUNTER_FIELD_SIZE = 4; var SYSTEM_VOLTAGE_FIELD_POS = 28; var SYSTEM_VOLTAGE_FIELD_SIZE = 2; var FIRMWARE_TYPE_FIELD_POS = 30; var FIRMWARE_TYPE_FIELD_SIZE = 1; var STATUS_SIZE_1_0 = TX_COUNTER_FIELD_POS + TX_COUNTER_FIELD_SIZE; var STATUS_SIZE_1_1 = FIRMWARE_TYPE_FIELD_POS + FIRMWARE_TYPE_FIELD_SIZE; //individual bits of the status bytes var LORAWAN_ACTIVATED_STATE_STATUS_BIT_MASK = 1 << 0; var NETWORK_TIME_SYNCHRONIZATION_STATE_STATUS_BIT_MASK = 1 << 1; var SYSTEM_TIME_SYNCHRONIZATION_STATE_STATUS_BIT_MASK = 1 << 2; var LORAWAN_CONFIGURATION_STATE_STATUS_BIT_MASK = 1 << 4; var WMBUS_FILTER_LIST_CONFIGURATION_STATE_STATUS_BIT_MASK = 1 << 5; var CALENDAR_EVENT_LIST_CONFIGURATION_STATE_STATUS_BIT_MASK = 1 << 6; var FLASH_MEMORY_FULL_STATE_STATUS_BIT_MASK = 1 << 8; var FLASH_MEMORY_CRC_ERROR_STATE_STATUS_BIT_MASK = 1 << 9; //lookup table for uploaded integer value to firmware type var FirmwareTypeMap = { 0: 'Release', 1: 'Field Test Beta Version', 2: 'Internal Debug Version', } /**** go through the payload bytes and interpret individual bytes @param: uploaded payload bytes of status (without segmentation byte if preivously attached) @return: object of interpreted status information ****/ function decodeStatusPayload (statusData) { //create empty object to fill with indicated status fields var statusResults = {}; //go through the payload bytes, but not beyond the end if (statusData.length >= STATUS_SIZE_1_0) { //create empty object to fill with indicated status fields var statusResults = {}; //iO881A System Time ( from embedded RTC ) bytes buffer var systemTimeBuffer = statusData.slice(SYSTEM_TIME_FIELD_POS, SYSTEM_TIME_FIELD_POS + SYSTEM_TIME_FIELD_SIZE); //Firmware Version - minor version var firmwareVersionMinor = statusData[FIRMWARE_VERSION_MINOR_POS]; //Firmware Version - major version var firmwareVersionMajor = statusData[FIRMWARE_VERSION_MAJOR_POS]; //Time of last Synchronization bytes buffer var lastSyncTimeBuffer = statusData.slice(LAST_SYNC_TIME_FIELD_POS, LAST_SYNC_TIME_FIELD_POS + LAST_SYNC_TIME_FIELD_SIZE); //Reset Counter bytes buffer var resetCounterBuffer = statusData.slice(RESET_COUNTER_FIELD_POS, RESET_COUNTER_FIELD_POS + RESET_COUNTER_FIELD_SIZE); //Status / Error bytes buffer var statusBitsBuffer = statusData.slice(STATUS_BITS_FIELD_POS, STATUS_BITS_FIELD_POS + STATUS_BITS_FIELD_SIZE); //WMBus packages received bytes buffer var rxCounterBuffer = statusData.slice(RX_COUNTER_FIELD_POS, RX_COUNTER_FIELD_POS + RX_COUNTER_FIELD_SIZE); //WMBus packages saved bytes buffer var sdCounterBuffer = statusData.slice(SD_COUNTER_FIELD_POS, SD_COUNTER_FIELD_POS + SD_COUNTER_FIELD_SIZE); //WMBus packages sent bytes buffer var txCounterBuffer = statusData.slice(TX_COUNTER_FIELD_POS, TX_COUNTER_FIELD_POS + TX_COUNTER_FIELD_SIZE); //convert system time buffer to seconds | >>> 0 for UINT32 var epochSeconds = (systemTimeBuffer[0] | systemTimeBuffer[1] << 8 | systemTimeBuffer[2] << 16 | systemTimeBuffer[3] << 24) >>> 0; //create date object of system time milliseconds var systemTime = new Date(epochSeconds * 1000); //convert last sync time buffer to seconds | >>> 0 for UINT32 var epochSeconds = (lastSyncTimeBuffer[0] | lastSyncTimeBuffer[1] << 8 | lastSyncTimeBuffer[2] << 16 | lastSyncTimeBuffer[3] << 24) >>> 0; //create date object of last sync time milliseconds var lastSyncTime = new Date(epochSeconds * 1000); //convert reset Counter bytes buffer to number | >>> 0 for UINT32 var resetCounter = (resetCounterBuffer[0] | resetCounterBuffer[1] << 8 | resetCounterBuffer[2] << 16 | resetCounterBuffer[3] << 24) >>> 0; //convert status / error bytes buffer to number var statusBits = statusBitsBuffer[0] | statusBitsBuffer[1] << 8; //convert WMBus packages received bytes buffer to number | >>> 0 for UINT32 var rxCounter = (rxCounterBuffer[0] | rxCounterBuffer[1] << 8 | rxCounterBuffer[2] << 16 | rxCounterBuffer[3] << 24) >>> 0; //convert WMBus packages saved bytes buffer to number | >>> 0 for UINT32 var sdCounter = (sdCounterBuffer[0] | sdCounterBuffer[1] << 8 | sdCounterBuffer[2] << 16 | sdCounterBuffer[3] << 24) >>> 0; //convert WMBus packages sent bytes buffer to number | >>> 0 for UINT32 var txCounter = (txCounterBuffer[0] | txCounterBuffer[1] << 8 | txCounterBuffer[2] << 16 | txCounterBuffer[3] << 24) >>> 0; //add system time to status result object as string statusResults["Time"] = systemTime.toUTCString(); //add firmware version string to status result object, consisting of major and minor version statusResults["FirmwareVersion"] = firmwareVersionMajor + "." + firmwareVersionMinor; //add last sync time to status result object as string statusResults["LastSyncTime"] = lastSyncTime.toUTCString(); //add reset counter number to status result object statusResults["ResetCounter"] = resetCounter; //analyze status / error bytes and add accordingly named info to to status result object //Bit 0: LoRaWAN® Activation State statusResults = analyzeBitsToResultString(statusResults, statusBits, LORAWAN_ACTIVATED_STATE_STATUS_BIT_MASK, "LoRaWAN", "not activated", "activated"); //Bit 1: Network Time Synchronization State statusResults = analyzeBitsToResultString(statusResults, statusBits, NETWORK_TIME_SYNCHRONIZATION_STATE_STATUS_BIT_MASK, "NetworkTime", "not synchronized", "synchronized"); //Bit 2: System Time Synchronization State statusResults = analyzeBitsToResultString(statusResults, statusBits, SYSTEM_TIME_SYNCHRONIZATION_STATE_STATUS_BIT_MASK, "SystemTimeBit", "not synchronized", "synchronized"); //Bit 4: LoRaWAN Configuration State statusResults = analyzeBitsToResultString(statusResults, statusBits, SYSTEM_TIME_SYNCHRONIZATION_STATE_STATUS_BIT_MASK, "LoRaWANConfiguration", "not available", "available"); //Bit 5: Wireless M-Bus Address Filter List Configuration State statusResults = analyzeBitsToResultString(statusResults, statusBits, WMBUS_FILTER_LIST_CONFIGURATION_STATE_STATUS_BIT_MASK, "WMBusFilterList", "is empty", "contains at least one item"); //Bit 6: Calendar Event List Configuration State statusResults = analyzeBitsToResultString(statusResults, statusBits, CALENDAR_EVENT_LIST_CONFIGURATION_STATE_STATUS_BIT_MASK, "CalendarEventList", "is empty", "contains at least one item"); //Bit 8: Flash Memory Full State statusResults = analyzeBitsToResultString(statusResults, statusBits, FLASH_MEMORY_FULL_STATE_STATUS_BIT_MASK, "FlashMemoryFullState", "A flash memory full condition has been detected during capture phase", "no error"); //Bit 9: Flash Memory CRC Error State statusResults = analyzeBitsToResultString(statusResults, statusBits, FLASH_MEMORY_CRC_ERROR_STATE_STATUS_BIT_MASK, "FlashMemoryCRCErrorState", "A file CRC error has been detected during read & upload operation", "no error"); //add reader counters to status result object as string statusResults["WMBusPackagesReceived"] = rxCounter; statusResults["WMBusPackagesSaved"] = sdCounter; statusResults["WMBusPackagesSent"] = txCounter; //system voltage added in status from version 1.1 if (statusData.length >= STATUS_SIZE_1_1) { //system voltage bytes buffer var systemVoltageBuffer = statusData.slice(SYSTEM_VOLTAGE_FIELD_POS, SYSTEM_VOLTAGE_FIELD_POS + SYSTEM_VOLTAGE_FIELD_SIZE); //convert system voltage bytes buffer to number | >>> 0 for UINT16 var systemVoltage = (systemVoltageBuffer[0] | systemVoltageBuffer[1] << 8) >>> 0; //add system voltage to status result object as string statusResults["SystemVoltage"] = systemVoltage; //Firmware Type var firmwareType = statusData[FIRMWARE_TYPE_FIELD_POS]; //add system voltage to status result object as string statusResults["FirmwareType"] = resolveFirmwareType(firmwareType); } } return statusResults; } /**** analyze single bit of status / error bytes @param: results - object with indicated status fields bits - status / errors bytes for analyzing propertyName - name, with will be the key on adding to result object setString - string, which will be added as value to result object, if specified bit is set notSetString - string, which will be added as value to result object, if specified bit is not set @return: object of interpreted status information ****/ function analyzeBitsToResultString (results, bits, mask, propertyName, setString, notSetString) { if ((bits & mask) == mask) //specified bit is set results[propertyName] = setString; else //specified bit is not set results[propertyName] = notSetString; //return result object with added information return results; } /**** convert number to firmware type string @param: byte @return: string representation for firmware type ****/ function resolveFirmwareType(type) { //check if number is contained in lookup table if (FirmwareTypeMap[type]) //return string representation for unit number return FirmwareTypeMap[type]; //if not contained in lookup table return number as string return 'unknown' } function modulo(a, b) { return a - Math.floor(a/b)*b; } function ToUint32(x) { return modulo(x, Math.pow(2, 32)); } /***** decode status end ******/ 

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.

Community Feedback