AM300 series is a compact indoor ambiance monitoring sensor for measurement of temperature, humidity, light, CO2 concentration, barometric pressure, PM2.5, PM10 and motion.
The data will be shown on the E-ink screen in real-time, which helps to measure the indoor environment and comfort.
AM300 series is widely used for offices, stores, classrooms, hospitals, etc. Sensor data is transmitted using LoRaWAN ® technology.
Using Milesight LoRaWAN® gateway and ThingsBoard, users can manage all sensor data remotely and visually.
Features of the AM300 series device:
Integrated with multiple sensors like humidity, temperature, CO2, level light, barometric pressure, PM2.5, PM10, etc. Multiple display modes and clear emoticons to easily understand the comfort levels via screen;
Support batteries or DC power supply;
Equipped with traffic light indicator and buzzer to indicate device status and threshold alarms;
Able to store locally more than 18, 000 records of 512 KB in total;
Compliant with standard LoRaWAN® gateways and network servers.
According to the official user manual, we need a smartphone with NFC enabled and the ToolBox application to connect the sensor.
Since this device can only be operated using a LoRaWAN® gateway, we must first connect it to a network server that has an integration configured with ThingsBoard.
Afterward, it can be provisioned to ThingsBoard.
varhistoryData={};vardecoded={};decoded.hexString=bytesToHex(input);for(vari=0;i<input.length;){varchannel_id=input[i++];varchannel_type=input[i++];// BATTERYif(channel_id===0x01&&channel_type===0x75){decoded.battery=input[i];i+=1;}// TEMPERATUREif(channel_id===0x03&&channel_type===0x67){// ℃decoded.temperature=parseBytesToInt(input,i,2,false)/10;i+=2;// ℉// decoded.temperature = parseBytesToInt(input, i, 2, false) / 10 * 1.8 + 32;// i +=2;}// HUMIDITYif(channel_id===0x04&&channel_type===0x68){decoded.humidity=input[i]/2;i+=1;}// PIRif(channel_id===0x05&&channel_type===0x00){decoded.pir=input[i]===1?"trigger":"idle";i+=1;}// LIGHTif(channel_id==0x06&&channel_type==-53){decoded.light_level=input[i];i+=1;}// CO2if(channel_id===0x07&&channel_type===0x7d){decoded.co2=parseBytesToInt(input,i,2,false);i+=2;}// TVOCif(channel_id===0x08&&channel_type===0x7d){decoded.tvoc=parseBytesToInt(input,i,2,false);i+=2;}// PRESSUREif(channel_id===0x09&&channel_type===0x73){decoded.pressure=parseBytesToInt(input,i,2,false)/10;i+=2;}// HCHOif(channel_id===0x0a&&channel_type===0x7d){decoded.hcho=parseBytesToInt(input,i,2,false)/100;i+=2;}// PM2.5if(channel_id===0x0b&&channel_type===0x7d){decoded.pm2_5=parseBytesToInt(input,i,2,false);i+=2;}// PM10if(channel_id===0x0c&&channel_type===0x7d){decoded.pm10=parseBytesToInt(input,i,2,false);i+=2;}// O3if(channel_id===0x0d&&channel_type===0x7d){decoded.o3=parseBytesToInt(input,i,2,false)/100;i+=2;}// BEEPif(channel_id===0x0e&&channel_type===0x01){decoded.beep=input[i]===1?"yes":"no";i+=1;}// HISTORY DATA (AM307)if(channel_id===32&&channel_type===206){historyData={};historyData.timestamp=parseBytesToInt(input,i,4,false);historyData.temperature=parseBytesToInt(input,i+4,2,false)/10;historyData.humidity=parseBytesToInt(input,i+6,2,false)/2;historyData.pir=input[i+8]===1?"trigger":"idle";historyData.light_level=input[i+9]===1;historyData.co2=parseBytesToInt(input,i+10,2,false);historyData.tvoc=parseBytesToInt(input,i+12,2,false);historyData.pressure=parseBytesToInt(input,i+14,2,false)/10;i+=16;if(decoded.history==null){decoded.history=[];}decoded.history.push(historyData);}// HISTORY DATA (AM308)if(channel_id===32&&channel_type===206){historyData={};historyData.timestamp=parseBytesToInt(input,i,4,false);historyData.temperature=parseBytesToInt(input,i+4,2,false)/10;historyData.humidity=parseBytesToInt(input,i+6,2,false)/2;historyData.pir=input[i+8]===1?"trigger":"idle";historyData.light_level=input[i+9]===1;historyData.co2=parseBytesToInt(input,i+10,2,false);historyData.tvoc=parseBytesToInt(input,i+12,2,false);historyData.pressure=parseBytesToInt(input,i+14,2,false)/10;historyData.pm2_5=parseBytesToInt(input,i+16,2,false);historyData.pm10=parseBytesToInt(input,i+18,2,false);i+=20;if(decoded.history==null){decoded.history=[];}decoded.history.push(historyData);}// HISTORY DATA (AM319 CH2O)if(channel_id===32&&channel_type===206){historyData={};historyData.timestamp=parseBytesToInt(input,i,4,false);historyData.temperature=parseBytesToInt(input,i+4,2,false)/10;historyData.humidity=parseBytesToInt(input,i+6,2,false)/2;historyData.pir=input[i+8]===1?"trigger":"idle";historyData.light_level=input[i+9]===1;historyData.co2=parseBytesToInt(input,i+10,2,false);historyData.tvoc=parseBytesToInt(input,i+12,2,false);historyData.pressure=parseBytesToInt(input,i+14,2,false)/10;historyData.pm2_5=parseBytesToInt(input,i+16,2,false);historyData.pm10=parseBytesToInt(input,i+18,2,false);historyData.hcho=parseBytesToInt(input,i+20,2,false)/100;i+=22;if(decoded.history==null){decoded.history=[];}decoded.history.push(historyData);}// HISTORY historyData (AM319 O3)if(channel_id===0x20&&channel_type===0xce){historyData={};historyData.timestamp=parseBytesToInt(input,i,4,false);historyData.temperature=parseBytesToInt(input,i+4,2,false)/10;historyData.humidity=parseBytesToInt(input,i+6,2,false)/2;historyData.pir=input[i+8]===1?"trigger":"idle";historyData.light_level=input[i+9]===1;historyData.co2=parseBytesToInt(input,i+10,2,false);historyData.tvoc=parseBytesToInt(input,i+12,2,false);historyData.pressure=parseBytesToInt(input,i+14,2,false)/10;historyData.pm2_5=parseBytesToInt(input,i+16,2,false);historyData.pm10=parseBytesToInt(input,i+18,2,false);historyData.o3=parseBytesToInt(input,i+20,2,false)/100;i+=22;if(decoded.history==null){decoded.history=[];}decoded.history.push(historyData);}}output.telemetry=decoded;
vardata=decodeToJson(payload);vardeviceName=data.deviceInfo.deviceName;vardeviceType=data.deviceInfo.deviceProfileName;// var groupName = 'IAQ devices';// var customerName = 'Customer A';// use assetName and assetType instead of deviceName and deviceType// to automatically create assets instead of devices.// var assetName = 'Asset A';// var assetType = 'building';// If you want to parse incoming data somehow, you can add your code to this function.// input: bytes// expected output:// {// "attributes": {"attributeKey": "attributeValue"},// "telemetry": {"telemetryKey": "telemetryValue"}// }//// In the example - bytes will be saved as HEX string and also parsed as light level, battery level and PIR sensor value.//functiondecodePayload(input){varoutput={attributes:{},telemetry:{}};// --- Decoding code --- //output.telemetry.HEX_bytes=bytesToHex(input);varhistoryData={};vardecoded={};decoded.hexString=bytesToHex(input);for(vari=0;i<input.length;){varchannel_id=input[i++];varchannel_type=input[i++];// BATTERYif(channel_id===0x01&&channel_type===0x75){decoded.battery=input[i];i+=1;}// TEMPERATUREif(channel_id===0x03&&channel_type===0x67){// ℃decoded.temperature=parseBytesToInt(input,i,2,false)/10;i+=2;// ℉// decoded.temperature = parseBytesToInt(input, i, 2, false) / 10 * 1.8 + 32;// i +=2;}// HUMIDITYif(channel_id===0x04&&channel_type===0x68){decoded.humidity=input[i]/2;i+=1;}// PIRif(channel_id===0x05&&channel_type===0x00){decoded.pir=input[i]===1?"trigger":"idle";i+=1;}// LIGHTif(channel_id==0x06&&channel_type==-53){decoded.light_level=input[i];i+=1;}// CO2if(channel_id===0x07&&channel_type===0x7d){decoded.co2=parseBytesToInt(input,i,2,false);i+=2;}// TVOCif(channel_id===0x08&&channel_type===0x7d){decoded.tvoc=parseBytesToInt(input,i,2,false);i+=2;}// PRESSUREif(channel_id===0x09&&channel_type===0x73){decoded.pressure=parseBytesToInt(input,i,2,false)/10;i+=2;}// HCHOif(channel_id===0x0a&&channel_type===0x7d){decoded.hcho=parseBytesToInt(input,i,2,false)/100;i+=2;}// PM2.5if(channel_id===0x0b&&channel_type===0x7d){decoded.pm2_5=parseBytesToInt(input,i,2,false);i+=2;}// PM10if(channel_id===0x0c&&channel_type===0x7d){decoded.pm10=parseBytesToInt(input,i,2,false);i+=2;}// O3if(channel_id===0x0d&&channel_type===0x7d){decoded.o3=parseBytesToInt(input,i,2,false)/100;i+=2;}// BEEPif(channel_id===0x0e&&channel_type===0x01){decoded.beep=input[i]===1?"yes":"no";i+=1;}// HISTORY DATA (AM307)if(channel_id===32&&channel_type===206){historyData={};historyData.timestamp=parseBytesToInt(input,i,4,false);historyData.temperature=parseBytesToInt(input,i+4,2,false)/10;historyData.humidity=parseBytesToInt(input,i+6,2,false)/2;historyData.pir=input[i+8]===1?"trigger":"idle";historyData.light_level=input[i+9]===1;historyData.co2=parseBytesToInt(input,i+10,2,false);historyData.tvoc=parseBytesToInt(input,i+12,2,false);historyData.pressure=parseBytesToInt(input,i+14,2,false)/10;i+=16;if(decoded.history==null){decoded.history=[];}decoded.history.push(historyData);}// HISTORY DATA (AM308)if(channel_id===32&&channel_type===206){historyData={};historyData.timestamp=parseBytesToInt(input,i,4,false);historyData.temperature=parseBytesToInt(input,i+4,2,false)/10;historyData.humidity=parseBytesToInt(input,i+6,2,false)/2;historyData.pir=input[i+8]===1?"trigger":"idle";historyData.light_level=input[i+9]===1;historyData.co2=parseBytesToInt(input,i+10,2,false);historyData.tvoc=parseBytesToInt(input,i+12,2,false);historyData.pressure=parseBytesToInt(input,i+14,2,false)/10;historyData.pm2_5=parseBytesToInt(input,i+16,2,false);historyData.pm10=parseBytesToInt(input,i+18,2,false);i+=20;if(decoded.history==null){decoded.history=[];}decoded.history.push(historyData);}// HISTORY DATA (AM319 CH2O)if(channel_id===32&&channel_type===206){historyData={};historyData.timestamp=parseBytesToInt(input,i,4,false);historyData.temperature=parseBytesToInt(input,i+4,2,false)/10;historyData.humidity=parseBytesToInt(input,i+6,2,false)/2;historyData.pir=input[i+8]===1?"trigger":"idle";historyData.light_level=input[i+9]===1;historyData.co2=parseBytesToInt(input,i+10,2,false);historyData.tvoc=parseBytesToInt(input,i+12,2,false);historyData.pressure=parseBytesToInt(input,i+14,2,false)/10;historyData.pm2_5=parseBytesToInt(input,i+16,2,false);historyData.pm10=parseBytesToInt(input,i+18,2,false);historyData.hcho=parseBytesToInt(input,i+20,2,false)/100;i+=22;if(decoded.history==null){decoded.history=[];}decoded.history.push(historyData);}// HISTORY historyData (AM319 O3)if(channel_id===0x20&&channel_type===0xce){historyData={};historyData.timestamp=parseBytesToInt(input,i,4,false);historyData.temperature=parseBytesToInt(input,i+4,2,false)/10;historyData.humidity=parseBytesToInt(input,i+6,2,false)/2;historyData.pir=input[i+8]===1?"trigger":"idle";historyData.light_level=input[i+9]===1;historyData.co2=parseBytesToInt(input,i+10,2,false);historyData.tvoc=parseBytesToInt(input,i+12,2,false);historyData.pressure=parseBytesToInt(input,i+14,2,false)/10;historyData.pm2_5=parseBytesToInt(input,i+16,2,false);historyData.pm10=parseBytesToInt(input,i+18,2,false);historyData.o3=parseBytesToInt(input,i+20,2,false)/100;i+=22;if(decoded.history==null){decoded.history=[];}decoded.history.push(historyData);}}output.telemetry=decoded;// --- Decoding code --- //returnoutput;}// --- attributes and telemetry objects ---vartelemetry={};varattributes={};// --- attributes and telemetry objects ---// --- Timestamp parsingvardateString=data.time;vartimestamp=-1;if(dateString!=null){timestamp=newDate(dateString).getTime();if(timestamp==-1){varsecondsSeparatorIndex=dateString.lastIndexOf('.')+1;varmillisecondsEndIndex=dateString.lastIndexOf('+');if(millisecondsEndIndex==-1){millisecondsEndIndex=dateString.lastIndexOf('Z');}if(millisecondsEndIndex==-1){millisecondsEndIndex=dateString.lastIndexOf('-');}if(millisecondsEndIndex==-1){if(dateString.length>=secondsSeparatorIndex+3){dateString=dateString.substring(0,secondsSeparatorIndex+3);}}else{dateString=dateString.substring(0,secondsSeparatorIndex+3)+dateString.substring(millisecondsEndIndex,dateString.length);}timestamp=newDate(dateString).getTime();}}// If we cannot parse timestamp - we will use the current timestampif(timestamp==-1){timestamp=Date.now();}// --- Timestamp parsing// You can add some keys manually to attributes or telemetryattributes.deduplicationId=data.deduplicationId;// You can exclude some keys from the resultvarexcludeFromAttributesList=["deviceName","rxInfo","confirmed","data","deduplicationId","time","adr","dr","fCnt"];varexcludeFromTelemetryList=["data","deviceInfo","txInfo","devAddr","adr","time","fPort","region_common_name","region_config_id","deduplicationId"];// Message parsing// To avoid paths in the decoded objects we passing false value to function as "pathInKey" argument.// Warning: pathInKey can cause already found fields to be overwritten with the last value found.vartelemetryData=toFlatMap(data,excludeFromTelemetryList,false);varattributesData=toFlatMap(data,excludeFromAttributesList,false);varuplinkDataList=[];// Passing incoming bytes to decodePayload function, to get custom decodingvarcustomDecoding=decodePayload(base64ToBytes(data.data));// Collecting data to resultif(customDecoding.?telemetry.size()>0){telemetry.putAll(customDecoding.telemetry);}if(customDecoding.?attributes.size()>0){attributes.putAll(customDecoding.attributes);}telemetry.putAll(telemetryData);attributes.putAll(attributesData);varresult={deviceName:deviceName,deviceType:deviceType,// assetName: assetName,// assetType: assetType,// customerName: customerName,// groupName: groupName,attributes:attributes,telemetry:{ts:timestamp,values:telemetry}};returnresult;
varhistoryData={};vardecoded={};decoded.hexString=bytesToHex(input);for(vari=0;i<input.length;){varchannel_id=input[i++];varchannel_type=input[i++];// BATTERYif(channel_id===0x01&&channel_type===0x75){decoded.battery=input[i];i+=1;}// TEMPERATUREif(channel_id===0x03&&channel_type===0x67){// ℃decoded.temperature=parseBytesToInt(input,i,2,false)/10;i+=2;// ℉// decoded.temperature = parseBytesToInt(input, i, 2, false) / 10 * 1.8 + 32;// i +=2;}// HUMIDITYif(channel_id===0x04&&channel_type===0x68){decoded.humidity=input[i]/2;i+=1;}// PIRif(channel_id===0x05&&channel_type===0x00){decoded.pir=input[i]===1?"trigger":"idle";i+=1;}// LIGHTif(channel_id==0x06&&channel_type==-53){decoded.light_level=input[i];i+=1;}// CO2if(channel_id===0x07&&channel_type===0x7d){decoded.co2=parseBytesToInt(input,i,2,false);i+=2;}// TVOCif(channel_id===0x08&&channel_type===0x7d){decoded.tvoc=parseBytesToInt(input,i,2,false);i+=2;}// PRESSUREif(channel_id===0x09&&channel_type===0x73){decoded.pressure=parseBytesToInt(input,i,2,false)/10;i+=2;}// HCHOif(channel_id===0x0a&&channel_type===0x7d){decoded.hcho=parseBytesToInt(input,i,2,false)/100;i+=2;}// PM2.5if(channel_id===0x0b&&channel_type===0x7d){decoded.pm2_5=parseBytesToInt(input,i,2,false);i+=2;}// PM10if(channel_id===0x0c&&channel_type===0x7d){decoded.pm10=parseBytesToInt(input,i,2,false);i+=2;}// O3if(channel_id===0x0d&&channel_type===0x7d){decoded.o3=parseBytesToInt(input,i,2,false)/100;i+=2;}// BEEPif(channel_id===0x0e&&channel_type===0x01){decoded.beep=input[i]===1?"yes":"no";i+=1;}// HISTORY DATA (AM307)if(channel_id===32&&channel_type===206){historyData={};historyData.timestamp=parseBytesToInt(input,i,4,false);historyData.temperature=parseBytesToInt(input,i+4,2,false)/10;historyData.humidity=parseBytesToInt(input,i+6,2,false)/2;historyData.pir=input[i+8]===1?"trigger":"idle";historyData.light_level=input[i+9]===1;historyData.co2=parseBytesToInt(input,i+10,2,false);historyData.tvoc=parseBytesToInt(input,i+12,2,false);historyData.pressure=parseBytesToInt(input,i+14,2,false)/10;i+=16;if(decoded.history==null){decoded.history=[];}decoded.history.push(historyData);}// HISTORY DATA (AM308)if(channel_id===32&&channel_type===206){historyData={};historyData.timestamp=parseBytesToInt(input,i,4,false);historyData.temperature=parseBytesToInt(input,i+4,2,false)/10;historyData.humidity=parseBytesToInt(input,i+6,2,false)/2;historyData.pir=input[i+8]===1?"trigger":"idle";historyData.light_level=input[i+9]===1;historyData.co2=parseBytesToInt(input,i+10,2,false);historyData.tvoc=parseBytesToInt(input,i+12,2,false);historyData.pressure=parseBytesToInt(input,i+14,2,false)/10;historyData.pm2_5=parseBytesToInt(input,i+16,2,false);historyData.pm10=parseBytesToInt(input,i+18,2,false);i+=20;if(decoded.history==null){decoded.history=[];}decoded.history.push(historyData);}// HISTORY DATA (AM319 CH2O)if(channel_id===32&&channel_type===206){historyData={};historyData.timestamp=parseBytesToInt(input,i,4,false);historyData.temperature=parseBytesToInt(input,i+4,2,false)/10;historyData.humidity=parseBytesToInt(input,i+6,2,false)/2;historyData.pir=input[i+8]===1?"trigger":"idle";historyData.light_level=input[i+9]===1;historyData.co2=parseBytesToInt(input,i+10,2,false);historyData.tvoc=parseBytesToInt(input,i+12,2,false);historyData.pressure=parseBytesToInt(input,i+14,2,false)/10;historyData.pm2_5=parseBytesToInt(input,i+16,2,false);historyData.pm10=parseBytesToInt(input,i+18,2,false);historyData.hcho=parseBytesToInt(input,i+20,2,false)/100;i+=22;if(decoded.history==null){decoded.history=[];}decoded.history.push(historyData);}// HISTORY historyData (AM319 O3)if(channel_id===0x20&&channel_type===0xce){historyData={};historyData.timestamp=parseBytesToInt(input,i,4,false);historyData.temperature=parseBytesToInt(input,i+4,2,false)/10;historyData.humidity=parseBytesToInt(input,i+6,2,false)/2;historyData.pir=input[i+8]===1?"trigger":"idle";historyData.light_level=input[i+9]===1;historyData.co2=parseBytesToInt(input,i+10,2,false);historyData.tvoc=parseBytesToInt(input,i+12,2,false);historyData.pressure=parseBytesToInt(input,i+14,2,false)/10;historyData.pm2_5=parseBytesToInt(input,i+16,2,false);historyData.pm10=parseBytesToInt(input,i+18,2,false);historyData.o3=parseBytesToInt(input,i+20,2,false)/100;i+=22;if(decoded.history==null){decoded.history=[];}decoded.history.push(historyData);}}output.telemetry=decoded;
vardata=decodeToJson(payload);vardeviceName=data.end_device_ids.device_id;vardeviceType=data.end_device_ids.application_ids.application_id;// var groupName = 'IAQ devices';// var customerName = 'Customer A';// use assetName and assetType instead of deviceName and deviceType// to automatically create assets instead of devices.// var assetName = 'Asset A';// var assetType = 'building';// If you want to parse incoming data somehow, you can add your code to this function.// input: bytes// expected output:// {// "attributes": {"attributeKey": "attributeValue"},// "telemetry": {"telemetryKey": "telemetryValue"}// }//// In the example - bytes will be saved as HEX string and also parsed as light level, battery level and PIR sensor value.//functiondecodeFrmPayload(input){varoutput={attributes:{},telemetry:{}};// --- Decoding code --- //output.telemetry.HEX_bytes=bytesToHex(input);varhistoryData={};vardecoded={};decoded.hexString=bytesToHex(input);for(vari=0;i<input.length;){varchannel_id=input[i++];varchannel_type=input[i++];// BATTERYif(channel_id===0x01&&channel_type===0x75){decoded.battery=input[i];i+=1;}// TEMPERATUREif(channel_id===0x03&&channel_type===0x67){// ℃decoded.temperature=parseBytesToInt(input,i,2,false)/10;i+=2;// ℉// decoded.temperature = parseBytesToInt(input, i, 2, false) / 10 * 1.8 + 32;// i +=2;}// HUMIDITYif(channel_id===0x04&&channel_type===0x68){decoded.humidity=input[i]/2;i+=1;}// PIRif(channel_id===0x05&&channel_type===0x00){decoded.pir=input[i]===1?"trigger":"idle";i+=1;}// LIGHTif(channel_id==0x06&&channel_type==-53){decoded.light_level=input[i];i+=1;}// CO2if(channel_id===0x07&&channel_type===0x7d){decoded.co2=parseBytesToInt(input,i,2,false);i+=2;}// TVOCif(channel_id===0x08&&channel_type===0x7d){decoded.tvoc=parseBytesToInt(input,i,2,false);i+=2;}// PRESSUREif(channel_id===0x09&&channel_type===0x73){decoded.pressure=parseBytesToInt(input,i,2,false)/10;i+=2;}// HCHOif(channel_id===0x0a&&channel_type===0x7d){decoded.hcho=parseBytesToInt(input,i,2,false)/100;i+=2;}// PM2.5if(channel_id===0x0b&&channel_type===0x7d){decoded.pm2_5=parseBytesToInt(input,i,2,false);i+=2;}// PM10if(channel_id===0x0c&&channel_type===0x7d){decoded.pm10=parseBytesToInt(input,i,2,false);i+=2;}// O3if(channel_id===0x0d&&channel_type===0x7d){decoded.o3=parseBytesToInt(input,i,2,false)/100;i+=2;}// BEEPif(channel_id===0x0e&&channel_type===0x01){decoded.beep=input[i]===1?"yes":"no";i+=1;}// HISTORY DATA (AM307)if(channel_id===32&&channel_type===206){historyData={};historyData.timestamp=parseBytesToInt(input,i,4,false);historyData.temperature=parseBytesToInt(input,i+4,2,false)/10;historyData.humidity=parseBytesToInt(input,i+6,2,false)/2;historyData.pir=input[i+8]===1?"trigger":"idle";historyData.light_level=input[i+9]===1;historyData.co2=parseBytesToInt(input,i+10,2,false);historyData.tvoc=parseBytesToInt(input,i+12,2,false);historyData.pressure=parseBytesToInt(input,i+14,2,false)/10;i+=16;if(decoded.history==null){decoded.history=[];}decoded.history.push(historyData);}// HISTORY DATA (AM308)if(channel_id===32&&channel_type===206){historyData={};historyData.timestamp=parseBytesToInt(input,i,4,false);historyData.temperature=parseBytesToInt(input,i+4,2,false)/10;historyData.humidity=parseBytesToInt(input,i+6,2,false)/2;historyData.pir=input[i+8]===1?"trigger":"idle";historyData.light_level=input[i+9]===1;historyData.co2=parseBytesToInt(input,i+10,2,false);historyData.tvoc=parseBytesToInt(input,i+12,2,false);historyData.pressure=parseBytesToInt(input,i+14,2,false)/10;historyData.pm2_5=parseBytesToInt(input,i+16,2,false);historyData.pm10=parseBytesToInt(input,i+18,2,false);i+=20;if(decoded.history==null){decoded.history=[];}decoded.history.push(historyData);}// HISTORY DATA (AM319 CH2O)if(channel_id===32&&channel_type===206){historyData={};historyData.timestamp=parseBytesToInt(input,i,4,false);historyData.temperature=parseBytesToInt(input,i+4,2,false)/10;historyData.humidity=parseBytesToInt(input,i+6,2,false)/2;historyData.pir=input[i+8]===1?"trigger":"idle";historyData.light_level=input[i+9]===1;historyData.co2=parseBytesToInt(input,i+10,2,false);historyData.tvoc=parseBytesToInt(input,i+12,2,false);historyData.pressure=parseBytesToInt(input,i+14,2,false)/10;historyData.pm2_5=parseBytesToInt(input,i+16,2,false);historyData.pm10=parseBytesToInt(input,i+18,2,false);historyData.hcho=parseBytesToInt(input,i+20,2,false)/100;i+=22;if(decoded.history==null){decoded.history=[];}decoded.history.push(historyData);}// HISTORY historyData (AM319 O3)if(channel_id===0x20&&channel_type===0xce){historyData={};historyData.timestamp=parseBytesToInt(input,i,4,false);historyData.temperature=parseBytesToInt(input,i+4,2,false)/10;historyData.humidity=parseBytesToInt(input,i+6,2,false)/2;historyData.pir=input[i+8]===1?"trigger":"idle";historyData.light_level=input[i+9]===1;historyData.co2=parseBytesToInt(input,i+10,2,false);historyData.tvoc=parseBytesToInt(input,i+12,2,false);historyData.pressure=parseBytesToInt(input,i+14,2,false)/10;historyData.pm2_5=parseBytesToInt(input,i+16,2,false);historyData.pm10=parseBytesToInt(input,i+18,2,false);historyData.o3=parseBytesToInt(input,i+20,2,false)/100;i+=22;if(decoded.history==null){decoded.history=[];}decoded.history.push(historyData);}}output.telemetry=decoded;// --- Decoding code --- //returnoutput;}// --- attributes and telemetry objects ---vartelemetry={};varattributes={};// --- attributes and telemetry objects ---// --- Timestamp parsingvardateString=data.uplink_message.received_at;// If data is simulated or device doesn't send his own date string - we will use date from upcoming message, set by network serverif((data.simulated!=null&&data.simulated)||dateString==null){dateString=data.received_at;}vartimestamp=newDate(dateString).getTime();vartimestamp=-1;if(dateString!=null){timestamp=newDate(dateString).getTime();if(timestamp==-1){varsecondsSeparatorIndex=dateString.lastIndexOf('.')+1;varmillisecondsEndIndex=dateString.lastIndexOf('+');if(millisecondsEndIndex==-1){millisecondsEndIndex=dateString.lastIndexOf('Z');}if(millisecondsEndIndex==-1){millisecondsEndIndex=dateString.lastIndexOf('-');}if(millisecondsEndIndex==-1){if(dateString.length>=secondsSeparatorIndex+3){dateString=dateString.substring(0,secondsSeparatorIndex+3);}}else{dateString=dateString.substring(0,secondsSeparatorIndex+3)+dateString.substring(millisecondsEndIndex,dateString.length);}timestamp=newDate(dateString).getTime();}}// If we cannot parse timestamp - we will use the current timestampif(timestamp==-1){timestamp=Date.now();}// --- Timestamp parsing// You can add some keys manually to attributes or telemetryattributes.devEui=data.end_device_ids.dev_eui;attributes.fPort=data.uplink_message.f_port;// We want to save correlation ids as single object, so we are excluding them from attributes parse and add manuallyattributes.correlation_ids=data.correlation_ids;// You can exclude some keys from the resultvarexcludeFromTelemetryList=["uplink_token","gateway_id","settings","f_port","time","timestamp","received_at","network_ids"];varexcludeFromAttributesList=["uplink_token","gateway_id","f_port","time","timestamp","received_at","session_key_id","dev_eui"];// Message parsing// To avoid paths in the decoded objects we passing false value to function as "pathInKey" argument.// 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.vartelemetryData=toFlatMap(data.uplink_message,excludeFromTelemetryList,false);varattributesData={};attributesData.putAll(toFlatMap(data.uplink_message.settings,excludeFromAttributesList,false));attributesData.putAll(toFlatMap(data.uplink_message.network_ids,excludeFromAttributesList,false));attributesData.putAll(toFlatMap(data.end_device_ids,excludeFromAttributesList,false));// Passing incoming bytes to decodeFrmPayload function, to get custom decodingvarcustomDecoding={};if(data.uplink_message.get("frm_payload")!=null){customDecoding=decodeFrmPayload(base64ToBytes(data.uplink_message.frm_payload));}// Collecting data to resultif(customDecoding.?telemetry.size()>0){telemetry.putAll(customDecoding.telemetry);}if(customDecoding.?attributes.size()>0){attributes.putAll(customDecoding.attributes);}telemetry.putAll(telemetryData);attributes.putAll(attributesData);varresult={deviceName:deviceName,deviceType:deviceType,// assetName: assetName,// assetType: assetType,// customerName: customerName// groupName: groupName,attributes:attributes,telemetry:{ts:timestamp,values:telemetry}};returnresult;
varhistoryData={};vardecoded={};decoded.hexString=bytesToHex(input);for(vari=0;i<input.length;){varchannel_id=input[i++];varchannel_type=input[i++];// BATTERYif(channel_id===0x01&&channel_type===0x75){decoded.battery=input[i];i+=1;}// TEMPERATUREif(channel_id===0x03&&channel_type===0x67){// ℃decoded.temperature=parseBytesToInt(input,i,2,false)/10;i+=2;// ℉// decoded.temperature = parseBytesToInt(input, i, 2, false) / 10 * 1.8 + 32;// i +=2;}// HUMIDITYif(channel_id===0x04&&channel_type===0x68){decoded.humidity=input[i]/2;i+=1;}// PIRif(channel_id===0x05&&channel_type===0x00){decoded.pir=input[i]===1?"trigger":"idle";i+=1;}// LIGHTif(channel_id==0x06&&channel_type==-53){decoded.light_level=input[i];i+=1;}// CO2if(channel_id===0x07&&channel_type===0x7d){decoded.co2=parseBytesToInt(input,i,2,false);i+=2;}// TVOCif(channel_id===0x08&&channel_type===0x7d){decoded.tvoc=parseBytesToInt(input,i,2,false);i+=2;}// PRESSUREif(channel_id===0x09&&channel_type===0x73){decoded.pressure=parseBytesToInt(input,i,2,false)/10;i+=2;}// HCHOif(channel_id===0x0a&&channel_type===0x7d){decoded.hcho=parseBytesToInt(input,i,2,false)/100;i+=2;}// PM2.5if(channel_id===0x0b&&channel_type===0x7d){decoded.pm2_5=parseBytesToInt(input,i,2,false);i+=2;}// PM10if(channel_id===0x0c&&channel_type===0x7d){decoded.pm10=parseBytesToInt(input,i,2,false);i+=2;}// O3if(channel_id===0x0d&&channel_type===0x7d){decoded.o3=parseBytesToInt(input,i,2,false)/100;i+=2;}// BEEPif(channel_id===0x0e&&channel_type===0x01){decoded.beep=input[i]===1?"yes":"no";i+=1;}// HISTORY DATA (AM307)if(channel_id===32&&channel_type===206){historyData={};historyData.timestamp=parseBytesToInt(input,i,4,false);historyData.temperature=parseBytesToInt(input,i+4,2,false)/10;historyData.humidity=parseBytesToInt(input,i+6,2,false)/2;historyData.pir=input[i+8]===1?"trigger":"idle";historyData.light_level=input[i+9]===1;historyData.co2=parseBytesToInt(input,i+10,2,false);historyData.tvoc=parseBytesToInt(input,i+12,2,false);historyData.pressure=parseBytesToInt(input,i+14,2,false)/10;i+=16;if(decoded.history==null){decoded.history=[];}decoded.history.push(historyData);}// HISTORY DATA (AM308)if(channel_id===32&&channel_type===206){historyData={};historyData.timestamp=parseBytesToInt(input,i,4,false);historyData.temperature=parseBytesToInt(input,i+4,2,false)/10;historyData.humidity=parseBytesToInt(input,i+6,2,false)/2;historyData.pir=input[i+8]===1?"trigger":"idle";historyData.light_level=input[i+9]===1;historyData.co2=parseBytesToInt(input,i+10,2,false);historyData.tvoc=parseBytesToInt(input,i+12,2,false);historyData.pressure=parseBytesToInt(input,i+14,2,false)/10;historyData.pm2_5=parseBytesToInt(input,i+16,2,false);historyData.pm10=parseBytesToInt(input,i+18,2,false);i+=20;if(decoded.history==null){decoded.history=[];}decoded.history.push(historyData);}// HISTORY DATA (AM319 CH2O)if(channel_id===32&&channel_type===206){historyData={};historyData.timestamp=parseBytesToInt(input,i,4,false);historyData.temperature=parseBytesToInt(input,i+4,2,false)/10;historyData.humidity=parseBytesToInt(input,i+6,2,false)/2;historyData.pir=input[i+8]===1?"trigger":"idle";historyData.light_level=input[i+9]===1;historyData.co2=parseBytesToInt(input,i+10,2,false);historyData.tvoc=parseBytesToInt(input,i+12,2,false);historyData.pressure=parseBytesToInt(input,i+14,2,false)/10;historyData.pm2_5=parseBytesToInt(input,i+16,2,false);historyData.pm10=parseBytesToInt(input,i+18,2,false);historyData.hcho=parseBytesToInt(input,i+20,2,false)/100;i+=22;if(decoded.history==null){decoded.history=[];}decoded.history.push(historyData);}// HISTORY historyData (AM319 O3)if(channel_id===0x20&&channel_type===0xce){historyData={};historyData.timestamp=parseBytesToInt(input,i,4,false);historyData.temperature=parseBytesToInt(input,i+4,2,false)/10;historyData.humidity=parseBytesToInt(input,i+6,2,false)/2;historyData.pir=input[i+8]===1?"trigger":"idle";historyData.light_level=input[i+9]===1;historyData.co2=parseBytesToInt(input,i+10,2,false);historyData.tvoc=parseBytesToInt(input,i+12,2,false);historyData.pressure=parseBytesToInt(input,i+14,2,false)/10;historyData.pm2_5=parseBytesToInt(input,i+16,2,false);historyData.pm10=parseBytesToInt(input,i+18,2,false);historyData.o3=parseBytesToInt(input,i+20,2,false)/100;i+=22;if(decoded.history==null){decoded.history=[];}decoded.history.push(historyData);}}output.telemetry=decoded;
vardata=decodeToJson(payload);vardeviceName=data.end_device_ids.device_id;vardeviceType=data.end_device_ids.application_ids.application_id;// var groupName = 'IAQ devices';// var customerName = 'Customer A';// use assetName and assetType instead of deviceName and deviceType// to automatically create assets instead of devices.// var assetName = 'Asset A';// var assetType = 'building';// If you want to parse incoming data somehow, you can add your code to this function.// input: bytes// expected output:// {// "attributes": {"attributeKey": "attributeValue"},// "telemetry": {"telemetryKey": "telemetryValue"}// }//// In the example - bytes will be saved as HEX string and also parsed as light level, battery level and PIR sensor value.//functiondecodeFrmPayload(input){varoutput={attributes:{},telemetry:{}};// --- Decoding code --- //output.telemetry.HEX_bytes=bytesToHex(input);varhistoryData={};vardecoded={};decoded.hexString=bytesToHex(input);for(vari=0;i<input.length;){varchannel_id=input[i++];varchannel_type=input[i++];// BATTERYif(channel_id===0x01&&channel_type===0x75){decoded.battery=input[i];i+=1;}// TEMPERATUREif(channel_id===0x03&&channel_type===0x67){// ℃decoded.temperature=parseBytesToInt(input,i,2,false)/10;i+=2;// ℉// decoded.temperature = parseBytesToInt(input, i, 2, false) / 10 * 1.8 + 32;// i +=2;}// HUMIDITYif(channel_id===0x04&&channel_type===0x68){decoded.humidity=input[i]/2;i+=1;}// PIRif(channel_id===0x05&&channel_type===0x00){decoded.pir=input[i]===1?"trigger":"idle";i+=1;}// LIGHTif(channel_id==0x06&&channel_type==-53){decoded.light_level=input[i];i+=1;}// CO2if(channel_id===0x07&&channel_type===0x7d){decoded.co2=parseBytesToInt(input,i,2,false);i+=2;}// TVOCif(channel_id===0x08&&channel_type===0x7d){decoded.tvoc=parseBytesToInt(input,i,2,false);i+=2;}// PRESSUREif(channel_id===0x09&&channel_type===0x73){decoded.pressure=parseBytesToInt(input,i,2,false)/10;i+=2;}// HCHOif(channel_id===0x0a&&channel_type===0x7d){decoded.hcho=parseBytesToInt(input,i,2,false)/100;i+=2;}// PM2.5if(channel_id===0x0b&&channel_type===0x7d){decoded.pm2_5=parseBytesToInt(input,i,2,false);i+=2;}// PM10if(channel_id===0x0c&&channel_type===0x7d){decoded.pm10=parseBytesToInt(input,i,2,false);i+=2;}// O3if(channel_id===0x0d&&channel_type===0x7d){decoded.o3=parseBytesToInt(input,i,2,false)/100;i+=2;}// BEEPif(channel_id===0x0e&&channel_type===0x01){decoded.beep=input[i]===1?"yes":"no";i+=1;}// HISTORY DATA (AM307)if(channel_id===32&&channel_type===206){historyData={};historyData.timestamp=parseBytesToInt(input,i,4,false);historyData.temperature=parseBytesToInt(input,i+4,2,false)/10;historyData.humidity=parseBytesToInt(input,i+6,2,false)/2;historyData.pir=input[i+8]===1?"trigger":"idle";historyData.light_level=input[i+9]===1;historyData.co2=parseBytesToInt(input,i+10,2,false);historyData.tvoc=parseBytesToInt(input,i+12,2,false);historyData.pressure=parseBytesToInt(input,i+14,2,false)/10;i+=16;if(decoded.history==null){decoded.history=[];}decoded.history.push(historyData);}// HISTORY DATA (AM308)if(channel_id===32&&channel_type===206){historyData={};historyData.timestamp=parseBytesToInt(input,i,4,false);historyData.temperature=parseBytesToInt(input,i+4,2,false)/10;historyData.humidity=parseBytesToInt(input,i+6,2,false)/2;historyData.pir=input[i+8]===1?"trigger":"idle";historyData.light_level=input[i+9]===1;historyData.co2=parseBytesToInt(input,i+10,2,false);historyData.tvoc=parseBytesToInt(input,i+12,2,false);historyData.pressure=parseBytesToInt(input,i+14,2,false)/10;historyData.pm2_5=parseBytesToInt(input,i+16,2,false);historyData.pm10=parseBytesToInt(input,i+18,2,false);i+=20;if(decoded.history==null){decoded.history=[];}decoded.history.push(historyData);}// HISTORY DATA (AM319 CH2O)if(channel_id===32&&channel_type===206){historyData={};historyData.timestamp=parseBytesToInt(input,i,4,false);historyData.temperature=parseBytesToInt(input,i+4,2,false)/10;historyData.humidity=parseBytesToInt(input,i+6,2,false)/2;historyData.pir=input[i+8]===1?"trigger":"idle";historyData.light_level=input[i+9]===1;historyData.co2=parseBytesToInt(input,i+10,2,false);historyData.tvoc=parseBytesToInt(input,i+12,2,false);historyData.pressure=parseBytesToInt(input,i+14,2,false)/10;historyData.pm2_5=parseBytesToInt(input,i+16,2,false);historyData.pm10=parseBytesToInt(input,i+18,2,false);historyData.hcho=parseBytesToInt(input,i+20,2,false)/100;i+=22;if(decoded.history==null){decoded.history=[];}decoded.history.push(historyData);}// HISTORY historyData (AM319 O3)if(channel_id===0x20&&channel_type===0xce){historyData={};historyData.timestamp=parseBytesToInt(input,i,4,false);historyData.temperature=parseBytesToInt(input,i+4,2,false)/10;historyData.humidity=parseBytesToInt(input,i+6,2,false)/2;historyData.pir=input[i+8]===1?"trigger":"idle";historyData.light_level=input[i+9]===1;historyData.co2=parseBytesToInt(input,i+10,2,false);historyData.tvoc=parseBytesToInt(input,i+12,2,false);historyData.pressure=parseBytesToInt(input,i+14,2,false)/10;historyData.pm2_5=parseBytesToInt(input,i+16,2,false);historyData.pm10=parseBytesToInt(input,i+18,2,false);historyData.o3=parseBytesToInt(input,i+20,2,false)/100;i+=22;if(decoded.history==null){decoded.history=[];}decoded.history.push(historyData);}}output.telemetry=decoded;// --- Decoding code --- //returnoutput;}// --- attributes and telemetry objects ---vartelemetry={};varattributes={};// --- attributes and telemetry objects ---// --- Timestamp parsingvardateString=data.uplink_message.received_at;// If data is simulated or device doesn't send his own date string - we will use date from upcoming message, set by network serverif((data.simulated!=null&&data.simulated)||dateString==null){dateString=data.received_at;}vartimestamp=-1;if(dateString!=null){timestamp=newDate(dateString).getTime();if(timestamp==-1){varsecondsSeparatorIndex=dateString.lastIndexOf('.')+1;varmillisecondsEndIndex=dateString.lastIndexOf('+');if(millisecondsEndIndex==-1){millisecondsEndIndex=dateString.lastIndexOf('Z');}if(millisecondsEndIndex==-1){millisecondsEndIndex=dateString.lastIndexOf('-');}if(millisecondsEndIndex==-1){if(dateString.length>=secondsSeparatorIndex+3){dateString=dateString.substring(0,secondsSeparatorIndex+3);}}else{dateString=dateString.substring(0,secondsSeparatorIndex+3)+dateString.substring(millisecondsEndIndex,dateString.length);}timestamp=newDate(dateString).getTime();}}// If we cannot parse timestamp - we will use the current timestampif(timestamp==-1){timestamp=Date.now();}// --- Timestamp parsing// You can add some keys manually to attributes or telemetryattributes.devEui=data.end_device_ids.dev_eui;attributes.fPort=data.uplink_message.f_port;// We want to save correlation ids as single object, so we are excluding them from attributes parse and add manuallyattributes.correlation_ids=data.correlation_ids;// You can exclude some keys from the resultvarexcludeFromTelemetryList=["uplink_token","gateway_id","settings","f_port","time","timestamp","received_at","network_ids"];varexcludeFromAttributesList=["uplink_token","gateway_id","f_port","time","timestamp","received_at","session_key_id","dev_eui"];// Message parsing// To avoid paths in the decoded objects we passing false value to function as "pathInKey" argument.// 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.vartelemetryData=toFlatMap(data.uplink_message,excludeFromTelemetryList,false);varattributesData={};attributesData.putAll(toFlatMap(data.uplink_message.settings,excludeFromAttributesList,false));attributesData.putAll(toFlatMap(data.uplink_message.network_ids,excludeFromAttributesList,false));attributesData.putAll(toFlatMap(data.end_device_ids,excludeFromAttributesList,false));// Passing incoming bytes to decodeFrmPayload function, to get custom decodingvarcustomDecoding={};if(data.uplink_message.get("frm_payload")!=null){customDecoding=decodeFrmPayload(base64ToBytes(data.uplink_message.frm_payload));}// Collecting data to resultif(customDecoding.?telemetry.size()>0){telemetry.putAll(customDecoding.telemetry);}if(customDecoding.?attributes.size()>0){attributes.putAll(customDecoding.attributes);}telemetry.putAll(telemetryData);attributes.putAll(attributesData);varresult={deviceName:deviceName,deviceType:deviceType,// assetName: assetName,// assetType: assetType,// customerName: customerName,// groupName: groupName,attributes:attributes,telemetry:{ts:timestamp,values:telemetry}};returnresult;
varhistoryData={};vardecoded={};decoded.hexString=bytesToHex(input);for(vari=0;i<input.length;){varchannel_id=input[i++];varchannel_type=input[i++];// BATTERYif(channel_id===0x01&&channel_type===0x75){decoded.battery=input[i];i+=1;}// TEMPERATUREif(channel_id===0x03&&channel_type===0x67){// ℃decoded.temperature=parseBytesToInt(input,i,2,false)/10;i+=2;// ℉// decoded.temperature = parseBytesToInt(input, i, 2, false) / 10 * 1.8 + 32;// i +=2;}// HUMIDITYif(channel_id===0x04&&channel_type===0x68){decoded.humidity=input[i]/2;i+=1;}// PIRif(channel_id===0x05&&channel_type===0x00){decoded.pir=input[i]===1?"trigger":"idle";i+=1;}// LIGHTif(channel_id==0x06&&channel_type==-53){decoded.light_level=input[i];i+=1;}// CO2if(channel_id===0x07&&channel_type===0x7d){decoded.co2=parseBytesToInt(input,i,2,false);i+=2;}// TVOCif(channel_id===0x08&&channel_type===0x7d){decoded.tvoc=parseBytesToInt(input,i,2,false);i+=2;}// PRESSUREif(channel_id===0x09&&channel_type===0x73){decoded.pressure=parseBytesToInt(input,i,2,false)/10;i+=2;}// HCHOif(channel_id===0x0a&&channel_type===0x7d){decoded.hcho=parseBytesToInt(input,i,2,false)/100;i+=2;}// PM2.5if(channel_id===0x0b&&channel_type===0x7d){decoded.pm2_5=parseBytesToInt(input,i,2,false);i+=2;}// PM10if(channel_id===0x0c&&channel_type===0x7d){decoded.pm10=parseBytesToInt(input,i,2,false);i+=2;}// O3if(channel_id===0x0d&&channel_type===0x7d){decoded.o3=parseBytesToInt(input,i,2,false)/100;i+=2;}// BEEPif(channel_id===0x0e&&channel_type===0x01){decoded.beep=input[i]===1?"yes":"no";i+=1;}// HISTORY DATA (AM307)if(channel_id===32&&channel_type===206){historyData={};historyData.timestamp=parseBytesToInt(input,i,4,false);historyData.temperature=parseBytesToInt(input,i+4,2,false)/10;historyData.humidity=parseBytesToInt(input,i+6,2,false)/2;historyData.pir=input[i+8]===1?"trigger":"idle";historyData.light_level=input[i+9]===1;historyData.co2=parseBytesToInt(input,i+10,2,false);historyData.tvoc=parseBytesToInt(input,i+12,2,false);historyData.pressure=parseBytesToInt(input,i+14,2,false)/10;i+=16;if(decoded.history==null){decoded.history=[];}decoded.history.push(historyData);}// HISTORY DATA (AM308)if(channel_id===32&&channel_type===206){historyData={};historyData.timestamp=parseBytesToInt(input,i,4,false);historyData.temperature=parseBytesToInt(input,i+4,2,false)/10;historyData.humidity=parseBytesToInt(input,i+6,2,false)/2;historyData.pir=input[i+8]===1?"trigger":"idle";historyData.light_level=input[i+9]===1;historyData.co2=parseBytesToInt(input,i+10,2,false);historyData.tvoc=parseBytesToInt(input,i+12,2,false);historyData.pressure=parseBytesToInt(input,i+14,2,false)/10;historyData.pm2_5=parseBytesToInt(input,i+16,2,false);historyData.pm10=parseBytesToInt(input,i+18,2,false);i+=20;if(decoded.history==null){decoded.history=[];}decoded.history.push(historyData);}// HISTORY DATA (AM319 CH2O)if(channel_id===32&&channel_type===206){historyData={};historyData.timestamp=parseBytesToInt(input,i,4,false);historyData.temperature=parseBytesToInt(input,i+4,2,false)/10;historyData.humidity=parseBytesToInt(input,i+6,2,false)/2;historyData.pir=input[i+8]===1?"trigger":"idle";historyData.light_level=input[i+9]===1;historyData.co2=parseBytesToInt(input,i+10,2,false);historyData.tvoc=parseBytesToInt(input,i+12,2,false);historyData.pressure=parseBytesToInt(input,i+14,2,false)/10;historyData.pm2_5=parseBytesToInt(input,i+16,2,false);historyData.pm10=parseBytesToInt(input,i+18,2,false);historyData.hcho=parseBytesToInt(input,i+20,2,false)/100;i+=22;if(decoded.history==null){decoded.history=[];}decoded.history.push(historyData);}// HISTORY historyData (AM319 O3)if(channel_id===0x20&&channel_type===0xce){historyData={};historyData.timestamp=parseBytesToInt(input,i,4,false);historyData.temperature=parseBytesToInt(input,i+4,2,false)/10;historyData.humidity=parseBytesToInt(input,i+6,2,false)/2;historyData.pir=input[i+8]===1?"trigger":"idle";historyData.light_level=input[i+9]===1;historyData.co2=parseBytesToInt(input,i+10,2,false);historyData.tvoc=parseBytesToInt(input,i+12,2,false);historyData.pressure=parseBytesToInt(input,i+14,2,false)/10;historyData.pm2_5=parseBytesToInt(input,i+16,2,false);historyData.pm10=parseBytesToInt(input,i+18,2,false);historyData.o3=parseBytesToInt(input,i+20,2,false)/100;i+=22;if(decoded.history==null){decoded.history=[];}decoded.history.push(historyData);}}output.telemetry=decoded;
vardata=decodeToJson(payload);vardeviceName=data.EUI;vardeviceType="LoraDevices";// groupName = 'IAQ devices';// var customerName = 'Customer A';// use assetName and assetType instead of deviceName and deviceType// to automatically create assets instead of devices.// var assetName = 'Asset A';// var assetType = 'building';vargatewayDeviceType="LoraGateway";// If you want to parse incoming data somehow, you can add your code to this function.// input: bytes// expected output:// {// "attributes": {"attributeKey": "attributeValue"},// "telemetry": {"telemetryKey": "telemetryValue"}// }//// In the example - bytes will be saved as HEX string and also parsed as light level, battery level and PIR sensor value.//functiondecodePayload(input){varoutput={attributes:{},telemetry:{}};// --- Decoding code --- //output.telemetry.HEX_bytes=bytesToHex(input);varhistoryData={};vardecoded={};decoded.hexString=bytesToHex(input);for(vari=0;i<input.length;){varchannel_id=input[i++];varchannel_type=input[i++];// BATTERYif(channel_id===0x01&&channel_type===0x75){decoded.battery=input[i];i+=1;}// TEMPERATUREif(channel_id===0x03&&channel_type===0x67){// ℃decoded.temperature=parseBytesToInt(input,i,2,false)/10;i+=2;// ℉// decoded.temperature = parseBytesToInt(input, i, 2, false) / 10 * 1.8 + 32;// i +=2;}// HUMIDITYif(channel_id===0x04&&channel_type===0x68){decoded.humidity=input[i]/2;i+=1;}// PIRif(channel_id===0x05&&channel_type===0x00){decoded.pir=input[i]===1?"trigger":"idle";i+=1;}// LIGHTif(channel_id==0x06&&channel_type==-53){decoded.light_level=input[i];i+=1;}// CO2if(channel_id===0x07&&channel_type===0x7d){decoded.co2=parseBytesToInt(input,i,2,false);i+=2;}// TVOCif(channel_id===0x08&&channel_type===0x7d){decoded.tvoc=parseBytesToInt(input,i,2,false);i+=2;}// PRESSUREif(channel_id===0x09&&channel_type===0x73){decoded.pressure=parseBytesToInt(input,i,2,false)/10;i+=2;}// HCHOif(channel_id===0x0a&&channel_type===0x7d){decoded.hcho=parseBytesToInt(input,i,2,false)/100;i+=2;}// PM2.5if(channel_id===0x0b&&channel_type===0x7d){decoded.pm2_5=parseBytesToInt(input,i,2,false);i+=2;}// PM10if(channel_id===0x0c&&channel_type===0x7d){decoded.pm10=parseBytesToInt(input,i,2,false);i+=2;}// O3if(channel_id===0x0d&&channel_type===0x7d){decoded.o3=parseBytesToInt(input,i,2,false)/100;i+=2;}// BEEPif(channel_id===0x0e&&channel_type===0x01){decoded.beep=input[i]===1?"yes":"no";i+=1;}// HISTORY DATA (AM307)if(channel_id===32&&channel_type===206){historyData={};historyData.timestamp=parseBytesToInt(input,i,4,false);historyData.temperature=parseBytesToInt(input,i+4,2,false)/10;historyData.humidity=parseBytesToInt(input,i+6,2,false)/2;historyData.pir=input[i+8]===1?"trigger":"idle";historyData.light_level=input[i+9]===1;historyData.co2=parseBytesToInt(input,i+10,2,false);historyData.tvoc=parseBytesToInt(input,i+12,2,false);historyData.pressure=parseBytesToInt(input,i+14,2,false)/10;i+=16;if(decoded.history==null){decoded.history=[];}decoded.history.push(historyData);}// HISTORY DATA (AM308)if(channel_id===32&&channel_type===206){historyData={};historyData.timestamp=parseBytesToInt(input,i,4,false);historyData.temperature=parseBytesToInt(input,i+4,2,false)/10;historyData.humidity=parseBytesToInt(input,i+6,2,false)/2;historyData.pir=input[i+8]===1?"trigger":"idle";historyData.light_level=input[i+9]===1;historyData.co2=parseBytesToInt(input,i+10,2,false);historyData.tvoc=parseBytesToInt(input,i+12,2,false);historyData.pressure=parseBytesToInt(input,i+14,2,false)/10;historyData.pm2_5=parseBytesToInt(input,i+16,2,false);historyData.pm10=parseBytesToInt(input,i+18,2,false);i+=20;if(decoded.history==null){decoded.history=[];}decoded.history.push(historyData);}// HISTORY DATA (AM319 CH2O)if(channel_id===32&&channel_type===206){historyData={};historyData.timestamp=parseBytesToInt(input,i,4,false);historyData.temperature=parseBytesToInt(input,i+4,2,false)/10;historyData.humidity=parseBytesToInt(input,i+6,2,false)/2;historyData.pir=input[i+8]===1?"trigger":"idle";historyData.light_level=input[i+9]===1;historyData.co2=parseBytesToInt(input,i+10,2,false);historyData.tvoc=parseBytesToInt(input,i+12,2,false);historyData.pressure=parseBytesToInt(input,i+14,2,false)/10;historyData.pm2_5=parseBytesToInt(input,i+16,2,false);historyData.pm10=parseBytesToInt(input,i+18,2,false);historyData.hcho=parseBytesToInt(input,i+20,2,false)/100;i+=22;if(decoded.history==null){decoded.history=[];}decoded.history.push(historyData);}// HISTORY historyData (AM319 O3)if(channel_id===0x20&&channel_type===0xce){historyData={};historyData.timestamp=parseBytesToInt(input,i,4,false);historyData.temperature=parseBytesToInt(input,i+4,2,false)/10;historyData.humidity=parseBytesToInt(input,i+6,2,false)/2;historyData.pir=input[i+8]===1?"trigger":"idle";historyData.light_level=input[i+9]===1;historyData.co2=parseBytesToInt(input,i+10,2,false);historyData.tvoc=parseBytesToInt(input,i+12,2,false);historyData.pressure=parseBytesToInt(input,i+14,2,false)/10;historyData.pm2_5=parseBytesToInt(input,i+16,2,false);historyData.pm10=parseBytesToInt(input,i+18,2,false);historyData.o3=parseBytesToInt(input,i+20,2,false)/100;i+=22;if(decoded.history==null){decoded.history=[];}decoded.history.push(historyData);}}output.telemetry=decoded;// --- Decoding code --- //returnoutput;}// --- attributes and telemetry objects ---vartelemetry={};varattributes={};// --- attributes and telemetry objects ---// --- Timestamp parsingvartimestamp=data.ts;// If we cannot parse timestamp - we will use the current timestampif(timestamp==-1){timestamp=Date.now();}// --- Timestamp parsing// You can add some keys manually to attributes or telemetryattributes.fPort=data.port;attributes.dataRange=data.dr;// You can exclude some keys from the resultvarexcludeFromAttributesList=["data","gws","EUI","ts","cmd","port","seqno","fcnt","toa","dr","ack","bat","snr","rssi"];varexcludeFromTelemetryList=["gws","EUI","ts","freq","port","data","cmd","dr","offline"];// Message parsing// To avoid paths in the decoded objects we passing false value to function as "pathInKey" argument.// Warning: pathInKey can cause already found fields to be overwritten with the last value found.vartelemetryData=toFlatMap(data,excludeFromTelemetryList,false);varattributesData=toFlatMap(data,excludeFromAttributesList,false);varuplinkDataList=[];// Passing incoming bytes to decodePayload function, to get custom decodingvarcustomDecoding=decodePayload(hexToBytes(data.data));// Collecting data to resultif(customDecoding.?telemetry.size()>0){telemetry.putAll(customDecoding.telemetry);}if(customDecoding.?attributes.size()>0){attributes.putAll(customDecoding.attributes);}telemetry.putAll(telemetryData);attributes.putAll(attributesData);vardeviceInfo={deviceName:deviceName,deviceType:deviceType,// assetName: assetName,// assetType: assetType,// customerName: customerName,// groupName: groupName,attributes:attributes,telemetry:{ts:timestamp,values:telemetry}};uplinkDataList.add(deviceInfo);if(data.cmd=="gw"){foreach(gatewayInfo:data.gws){vargatewayInfoMsg={deviceName:gatewayInfo.gweui,deviceType:gatewayDeviceType,attributes:{},telemetry:{"ts":gatewayInfo.ts,"values":toFlatMap(gatewayInfo,["ts","time","gweui"],false)}};uplinkDataList.add(gatewayInfoMsg);}}returnuplinkDataList;