Hi Markosplit,
I created the following decoder which you can add to your device payload parser or add to a connector you created:
function Decoder(bytes, port) {const decode = {};const mode = (bytes[6] & 0x7C) >> 2;decode.Digital_IStatus = (bytes[6] & 0x02) ? "H" : "L";if (mode != 2) {decode.BatV = (bytes[0] << 8 | bytes[1]) / 1000;decode.TempC1 = (bytes[2] == 0x7f && bytes[3] == 0xff) ? "NULL" : parseFloat(((bytes[2] << 24 >> 16 | bytes[3]) / 10).toFixed(1));if (mode != 8) {decode.ADC_CH0V = (bytes[4] << 8 | bytes[5]) / 1000;}}if (mode != 5 && mode != 6) {decode.EXTI_Trigger = (bytes[6] & 0x01) ? "TRUE" : "FALSE";decode.Door_status = (bytes[6] & 0x80) ? "CLOSE" : "OPEN";}switch (mode) {case 0:decode.Work_mode = "IIC";if ((bytes[9] << 8 | bytes[10]) === 0) {decode.Illum = (bytes[7] << 8 | bytes[8]);} else {decode.TempC_SHT = ((bytes[7] == 0x7f && bytes[8] == 0xff) || (bytes[7] == 0xff && bytes[8] == 0xff)) ? "NULL" : parseFloat(((bytes[7] << 24 >> 16 | bytes[8]) / 10).toFixed(1));decode.Hum_SHT = (bytes[9] == 0xff && bytes[10] == 0xff) ? "NULL" : parseFloat(((bytes[9] << 8 | bytes[10]) / 10).toFixed(1));}break;case 1:decode.Work_mode = "Distance";decode.Distance_cm = (bytes[7] === 0x00 && bytes[8] === 0x00) ? "NULL" : parseFloat(((bytes[7] << 8 | bytes[8]) / 10).toFixed(1));if (!(bytes[9] == 0xff && bytes[10] == 0xff)) {decode.Distance_signal_strength = (bytes[9] << 8 | bytes[10]);}break;case 2:decode.Work_mode = "3ADC+IIC";decode.BatV = bytes[11] / 10;decode.ADC_CH0V = (bytes[0] << 8 | bytes[1]) / 1000;decode.ADC_CH1V = (bytes[2] << 8 | bytes[3]) / 1000;decode.ADC_CH4V = (bytes[4] << 8 | bytes[5]) / 1000;if ((bytes[9] << 8 | bytes[10]) === 0) {decode.Illum = (bytes[7] << 8 | bytes[8]);} else {decode.TempC_SHT = ((bytes[7] == 0x7f && bytes[8] == 0xff) || (bytes[7] == 0xff && bytes[8] == 0xff)) ? "NULL" : parseFloat(((bytes[7] << 24 >> 16 | bytes[8]) / 10).toFixed(1));decode.Hum_SHT = (bytes[9] == 0xff && bytes[10] == 0xff) ? "NULL" : parseFloat(((bytes[9] << 8 | bytes[10]) / 10).toFixed(1));}break;case 3:decode.Work_mode = "3DS18B20";decode.TempC2 = (bytes[7] == 0x7f && bytes[8] == 0xff) ? "NULL" : parseFloat(((bytes[7] << 24 >> 16 | bytes[8]) / 10).toFixed(1));decode.TempC3 = (bytes[9] == 0x7f && bytes[10] == 0xff) ? "NULL" : parseFloat(((bytes[9] << 24 >> 16 | bytes[10]) / 10).toFixed(1));break;case 4:decode.Work_mode = "Weight";decode.Weight = (bytes[9] << 24 | bytes[10] << 16 | bytes[7] << 8 | bytes[8]);break;case 5:decode.Work_mode = "1Count";decode.Count = (bytes[7] << 24 | bytes[8] << 16 | bytes[9] << 8 | bytes[10]) >>> 0;break;case 6:decode.Work_mode = "3Interrupt";decode.EXTI1_Trigger = (bytes[6] & 0x01) ? "TRUE" : "FALSE";decode.EXTI1_Status = (bytes[6] & 0x80) ? "CLOSE" : "OPEN";decode.EXTI2_Trigger = (bytes[7] & 0x10) ? "TRUE" : "FALSE";decode.EXTI2_Status = (bytes[7] & 0x01) ? "CLOSE" : "OPEN";decode.EXTI3_Trigger = (bytes[8] & 0x10) ? "TRUE" : "FALSE";decode.EXTI3_Status = (bytes[8] & 0x01) ? "CLOSE" : "OPEN";break;case 7:decode.Work_mode = "3ADC+1DS18B20";decode.ADC_CH1V = (bytes[7] << 8 | bytes[8]) / 1000;decode.ADC_CH4V = (bytes[9] << 8 | bytes[10]) / 1000;break;case 8:decode.Work_mode = "3DS18B20+2Count";decode.TempC2 = (bytes[4] == 0x7f && bytes[5] == 0xff) ? "NULL" : parseFloat(((bytes[4] << 24 >> 16 | bytes[5]) / 10).toFixed(1));decode.TempC3 = (bytes[7] == 0x7f && bytes[8] == 0xff) ? "NULL" : parseFloat(((bytes[7] << 24 >> 16 | bytes[8]) / 10).toFixed(1));decode.Count1 = (bytes[9] << 24 | bytes[10] << 16 | bytes[11] << 8 | bytes[12]) >>> 0;decode.Count2 = (bytes[13] << 24 | bytes[14] << 16 | bytes[15] << 8 | bytes[16]) >>> 0;break;}return decode;}function parsePort5(bytes) {const freq_band_map = {0x01: "EU868",0x02: "US915",0x03: "IN865",0x04: "AU915",0x05: "KZ865",0x06: "RU864",0x07: "AS923",0x08: "AS923_1",0x09: "AS923_2",0x0A: "AS923_3",0x0F: "AS923_4",0x0B: "CN470",0x0C: "EU433",0x0D: "KR920",0x0E: "MA869"};const freq_band = freq_band_map[bytes[0]] || "UNKNOWN";const sub_band = bytes[1] == 0xff ? "NULL" : bytes[1];const firm_ver = (bytes[2] & 0x0f) + '.' + (bytes[3] >> 4 & 0x0f) + '.' + (bytes[3] & 0x0f);const tdc_time = bytes[4] << 16 | bytes[5] << 8 | bytes[6];return {FIRMWARE_VERSION: firm_ver,FREQUENCY_BAND: freq_band,SUB_BAND: sub_band,TDC_sec: tdc_time};}const data = payload.find((x) => ["payload_raw", "payload", "data"].includes(x.variable));const port = payload.find((x) => ["port", "fport", "fPort"].includes(x.variable));if (data && port) {const bytes = Buffer.from(data.value, "hex");let decodedData;if (port.value == 0x02) {decodedData = Decoder(bytes, port.value);} else if (port.value == 5) {decodedData = parsePort5(bytes);}const time = data.time || new Date().toISOString();const group = data.group || `${new Date().getTime()}-${Math.random().toString(36).substring(2, 5)}`;const tagoData = Object.keys(decodedData).map(key => ({variable: key,value: decodedData[key],group,time}));payload = payload.concat(tagoData);}
Since your decoder already outputs the following:
{ "EXTI3_Trigger": "FALSE", "ADC_CH0V": 0, "TempC1": 25, "EXTI2_Trigger": "FALSE", "EXTI1_Trigger": "TRUE", "Digital_IStatus": "L", "EXTI2_Status": "OPEN", "EXTI3_Status": "OPEN", "EXTI1_Status": "OPEN", "BatV": 3.68, "Work_mode": "3Interrupt" }
I’ve add the following code to map it over to the TagoIO Format:
const time = data.time || new Date().toISOString();const group = data.group || `${new Date().getTime()}-${Math.random().toString(36).substring(2, 5)}`;const tagoData = Object.keys(decodedData).map(key => ({variable: key,value: decodedData[key],group,time}));
Note that this is just one of several ways you can achieve this, you could also modify the Decoder function to just return the data already in the TagoIO Format for example.
Hope this helps! 