// Decode decodes an array of bytes into an object. // - fPort contains the LoRaWAN fPort number // - bytes is an array of bytes, e.g. [225, 230, 255, 0] // - variables contains the device variables e.g. {"calibration": "3.5"} (both the key / value are of type string) // The function must return an object, e.g. {"temperature": 22.5} function Decode(fPort, bytes, variables) { // O5 Door contact sensor if (fPort === 4) { return [ { led_state: bytes[0]===0 ? "Off":"On", mtm_code_1: bytes[1], mtm_code_2: bytes[2], hw_code: bytes[3], battery_level: bytes[4]+"%", size_value: bytes[5], door_state: bytes[6] === 1 ? "Closed": "Open", } ]; } // heart-beat of O5 else if (fPort === 5) { return [ { led_state: (bytes[0] & 0x7f) === 0 ? "Off" : "On", battery_level: bytes[1] + " %", } ]; } // R4 soap/sanitizer sensor else if (fPort === 7) { return [ { led_state: bytes[0]===0 ? "Off":"On", mtm_code_1: bytes[1], mtm_code_2: bytes[2], hw_code: bytes[3], battery_level: bytes[4]+"%", size_value: bytes[5], measure_tech:bytes[6] === 0? "Capacitive":"Other", liquid_level_event: bytes[7] === 0? "Liquid Detected":"No Liquid", } ]; } // R4 soap/sanitizer heart-beat else if (fPort === 8) { return [ { led_state: (bytes[0] & 0x7f) === 0 ? "Off" : "On", //battery_level: bytes[1] + " %", battery_level_mV: bytes[1]*100 + " mV", } ]; } // R1D dual roll toilet paper sensor else if (fPort === 57) { return [ { led_state:bytes[0]===0 ? "Off":"On", mtm_code_1:bytes[1], mtm_code_2:bytes[2], hw_code:bytes[3], battery_level:bytes[4]+"%", size_value:bytes[5], distance_1_mm:bytes[6]*256+bytes[7], distance_2_mm:bytes[8]*256+bytes[9], distance_unit: "mm", } ]; } // R1D, Heart-beat else if (fPort === 58) { return [ { led_state: (bytes[0] & 0x7f) === 0 ? "Off" : "On", //battery_level: bytes[1] + " %", battery_level_mV: bytes[1]*100 + " mV", } ]; } // R5 waste bin sensor else if (fPort === 11) { return [ { led_state:bytes[0]===0 ? "Off":"On", mtm_code_1:bytes[1], mtm_code_2:bytes[2], hw_code:bytes[3], battery_level:bytes[4]+"%", size_value:bytes[5], distance_mm: bytes[6]*256 + bytes[7], distance_unit: "mm", } ]; } // R5, Heart-beat else if (fPort === 12) { return [ { led_state: (bytes[0] & 0x7f) === 0 ? "Off" : "On", //battery_level_percent: bytes[1] + " %", battery_level_mV: bytes[1]*100 + "mV", } ]; } // UPLINK, RFAC else if (fPort === 1 ) { var data={}; data.length = bytes.length; if ((data.length ===10) && (bytes[0] == 0x59)&&(bytes[9]==0x38)) { data.Yunhorn_PRD ="True"; data.PRD_String = String.fromCharCode(bytes); } else if ((data.length ===4) && (bytes[0] == 0x52)&&(bytes[1]==0x46)) //RFAC { data.Request_Performed = "OK"; data.RFAC = "OK"; data.AC0 = bytes[0]; data.AC1 = bytes[1]; } else if ((data.length ===4) && (bytes[0]===0x50)&&(bytes[1]===0x31)&&(bytes[2]===0x31)) { data.Work_Mode_Switch ="OK"; switch (bytes[3]-0x30) { case 0x0: data.workmode = "Network_mode"; break; case 0x01: data.workmode = "Wired_Mode"; break; case 0x02: data.workmode = "Hall_element_mode"; break; case 0x03: data.workmode = "MotionDetect_mode"; break; case 0x04: data.workmode = "Dual_mode"; break; case 0x05: data.workmode = "Uni_Mode"; break; default: data.workmode = "Unknown Mode"; break; } } else if ((bytes[0]===0x59) && (bytes[1] === 0x44)) //Duration interval { data.Uplink_interval=(bytes[2]-0x30)*10+(bytes[3]-0x30); data.Uplink_interval_unit=String.fromCharCode(bytes[4]); //data.Heart_beat_Duration = (bytes[2]-0x30)*10 + (bytes[3]-0x30); //data.Unit = String.fromCharCode(bytes[4]); } else if ((bytes[0]===0x59) && (bytes[1] === 0x53)) //Sampling interval or Heart-beat interval { data.Heart_Beat_interval=(bytes[2]-0x30)*10+(bytes[3]-0x30); data.Heart_Beat_interval_unit=String.fromCharCode(bytes[4]); //data.Wakeup_sampling_interval = (bytes[2]-0x30)*10 + (bytes[3]-0x30); //data.Unit = String.fromCharCode(bytes[4]); } else if (bytes[0]===0x43) { // report current nvm config data.mtm_code1=bytes[1]; data.mtm_code2=bytes[2]; data.sts_verion=bytes[3]; data.sts_hw_ver=bytes[4]; data.sts_uplink_interval = bytes[5]; data.sts_uplink_interval_unit = String.fromCharCode(bytes[6]); data.sts_sampling_interval = bytes[7]; data.sts_sampling_interval_unit = String.fromCharCode(bytes[8]); data.sts_work_mode=bytes[9]; data.sts_service_mask=bytes[10]; data.sts_reserve01=bytes[11]; data.sts_payload_length=bytes[12]; data.rss_start_distance=bytes[13]*0.1+" meter"; data.rss_range_length = bytes[14]*0.1+" meter"; data.rss_threshold = bytes[15]*0.1; data.rss_receiving_gain=bytes[16]+" %"; data.rss_profile=bytes[17]; data.rss_rate_tracking=bytes[18]; data.rss_rate_presence=bytes[19]; data.rss_HWAAS = bytes[20]; data.rss_nbr_removed_pc=bytes[21]; data.rss_inter_frame_deviation_time_const=bytes[22]*0.1; data.rss_inter_frame_fast_cutoff=bytes[23]; data.rss_inter_frame_slow_cutoff=bytes[24]; data.rss_intra_frame_time_const=bytes[25]; data.rss_intra_frame_weight=bytes[26]*0.1; data.rss_output_time_const=bytes[27]*0.1; data.rss_downsampling_factor=bytes[28]; data.rss_power_saving_mode_active=bytes[29]; data.rss_reserve02=bytes[30]; data.rss_reserve03=bytes[31]; data.rss_reserve04=bytes[32]; data.reserve2=bytes[33]; data.reserve3=bytes[34]; data.sensor_install_height=bytes[35]*10+" cm"; data.alarm_parameter05=bytes[36]; data.alarm_mute_expire_timer=bytes[37]; data.alarm_lamp_bar_flashing_color=bytes[38]; data.occupancy_overtime_threshold=bytes[39]; data.motionless_duration_threshold=bytes[40]; data.unconcious_threshold = bytes[41]; data.fall_detection_acc_threshold=bytes[42]; data.fall_detection_depth_threshold=bytes[43]; data.fall_down_confirm_threshold=bytes[44]; } else if (bytes[0]===0x53) { // SELF TEST FUNCTION data.mtm_code1=bytes[1]; data.mtm_code2=bytes[2]; data.sts_verion=bytes[3]; data.sts_hw_ver=bytes[4]; data.battery_level=bytes[5]; if ((bytes[6]===0x03)) { // report sensor install height data.sts_sensor_install_height= (bytes[7]<<8|bytes[8]); data.sts_sensor_install_height_unit="mm"; } else if ((bytes[6]===0x58)) { data.sts_Test_Result="### Motion Sensor Not Detected ###"; } else if ((bytes[6]===0x0E)) //result length, 10 rss bytes, 4 distance bytes { data.sts_Test_Result="Motion Sensor Test Result:"; data.sts_test_result_length=bytes[6]; data.sts_rss_sub_code1=bytes[7]; data.sts_rss_sub_code2=bytes[8]; data.sts_rss_sub_code3=bytes[9]; data.sts_rss_sub_code4=bytes[10]; data.sts_rss_sub_code5=bytes[11]; data.sts_rss_sub_code6=bytes[12]; data.sts_rss_sub_code7=bytes[13]; data.sts_rss_sub_code8=bytes[14]; data.sts_rss_sub_code9=bytes[15]; data.sts_rss_sub_code10=bytes[16]; data.sts_sensor_install_height = String.fromCharCode(bytes[17])+String.fromCharCode(bytes[18])+String.fromCharCode(bytes[19])+String.fromCharCode(bytes[20])+" mm"; } } else if (bytes[0]===0x44) { // MEASURE INSTALLATION HEIGHT data.mtm_code1=bytes[1]; data.mtm_code2=bytes[2]; data.sts_verion=bytes[3]; data.sts_hw_ver=bytes[4]; data.battery_level=bytes[5]; data.payload_length=bytes[6]; data.Measure_Distance=String.fromCharCode(bytes[7])+String.fromCharCode(bytes[8])+String.fromCharCode(bytes[9])+String.fromCharCode(bytes[10]); data.Distance_unit="mm"; } else if (bytes[0] === 0x4c) { // LoRaWAN Class A/B/C data.mtm_code1=bytes[1]; data.mtm_code2=bytes[2]; data.sts_verion=bytes[3]; data.LoRaWAN_Class=String.fromCharCode(bytes[4]); } else if (bytes[0]===0x56) { // FIRMWARE VERSION data.mtm_code1=bytes[1]; data.mtm_code2=bytes[2]; data.sts_verion=bytes[3]; data.sts_hw_ver=bytes[4]; data.sts_major=bytes[5]; data.sts_minor=bytes[6]; data.subminor=bytes[7]; if (data.length ===15) { data.L_year=(bytes[8]<<8|bytes[9]); data.L_mon=bytes[10]; data.L_day=bytes[11]; data.L_hour=bytes[12]; data.L_min=bytes[13]; data.L_sec=bytes[14]; data.LocalTime_UTC="UTC: "+data.L_year+"/"+data.L_mon+"/"+data.L_day+" "+data.L_hour+":"+data.L_min+":"+data.L_sec; data.LocalTime_EST8="GMT+8: "+data.L_year+"/"+data.L_mon+"/"+data.L_day+" "+(data.L_hour+8)+":"+data.L_min+":"+data.L_sec; } } else if (bytes[0] === 0x54) { //T: date & time data.L_year=(bytes[1]<<8|bytes[2]); data.L_mon=bytes[3]; data.L_day=bytes[4]; data.L_hour=bytes[5]; data.L_min=bytes[6]; data.L_sec=bytes[7]; data.LocalTime_UTC="UTC: "+data.L_year+"/"+data.L_mon+"/"+data.L_day+" "+data.L_hour+":"+data.L_min+":"+data.L_sec; } else if (bytes[0]===0x50) { // P cmd report if (data.length ==7) { switch (bytes[3]) { case 0x46: // F --- fall down & unconscious detection threshold data.FALL_acceleration = (bytes[4]==0x30?"Disabled":((bytes[4]-0x30)*10)+" mg/s2"); data.FALL_depth_measure = (bytes[5]==0x30?"Disabled":((bytes[5]-0x30)*10)+" cm"); data.FALL_confirm_threshold = (bytes[6]==0x30?"Disabled":((bytes[6]-0x30)*10)+" seconds"); //data.FALL_reserved = (bytes[7]==0x0?"Disabled":((bytes[6]-0x30)*10)+" min"); break; } //switch } else if (data.length ==8) { switch (bytes[3]) { case 0x4f: // O -- over stay, onconscious, long stay data.OMU_Motionless_duration_in_min = (bytes[4]==0x30?"Disabled":((bytes[4]-0x30))+" Min"); data.OMU_Long_Occupy_duration_in_Min= (bytes[5]==0x30?"Disabled":((bytes[5]-0x30)*10)+" Min"); data.OMU_Unconcious_Threshold = (bytes[6]==0x30?"Disabled":((bytes[6]-0x30)*100)+"ml"); data.OMU_Alarm_Mute_Reset_Timer = (bytes[7] ==0x30?"Disabled":((bytes[7]-0x30)*10)+" Seconds"); break; case 0x46: // F --- fall down & unconscious detection threshold data.FALL_acceleration = (bytes[4]==0x30?"Disabled":((bytes[4]-0x30)*10)+" mg/s2"); data.FALL_depth_measure = (bytes[5]==0x30?"Disabled":((bytes[5]-0x30)*10)+" cm"); data.FALL_confirm_threshold = (bytes[6]==0x30?"Disabled":((bytes[6]-0x30)*10)+" seconds"); data.FALL_reserved = (bytes[7]==0x30?"Disabled":((bytes[6]-0x30)*10)+" min"); break; } //switch } else if (data.length == 11) { // P 1108201365 data.RSS_SIMPLE_Start = ((bytes[3]-0x30)*100+(bytes[4]-0x30)*10)+" cm"; data.RSS_SIMPLE_Length = ((bytes[5]-0x30)*100+(bytes[6]-0x030)*10)+" cm"; data.RSS_SIMPLE_Threshold = ((bytes[7]-0x30)*1000+(bytes[8]-0x30)*100)+" ml"; data.RSS_SIMPLE_Gain = ((bytes[9]-0x30)*10+(bytes[10]-0x30))+" %"; } else if (data.length == 33) { // P 11 data.RSS_FULL_Start = ((bytes[3]-0x30)*100+(bytes[4]-0x30)*10)+" cm"; data.RSS_FULL_Length = ((bytes[5]-0x30)*100+(bytes[6]-0x30)*10)+" cm"; data.RSS_FULL_Threshold= ((bytes[7]-0x30)*1000+(bytes[8]-0x30)*100)+" ml"; data.RSS_FULL_Gain = ((bytes[9]-0x30)*10+(bytes[10]-0x30))+" %"; data.RSS_FULL_Profile = (bytes[11]-0x30); data.RSS_FULL_Rate_Tracking = ((bytes[12]-0x30)*10+(bytes[13]-0x30)); data.RSS_FULL_Rate_Presence = ((bytes[14]-0x30)*10+(bytes[15]-0x30)); data.RSS_FULL_HWAAS = ((bytes[16]-0x30)*10+(bytes[17]-0x30)); data.RSS_FULL_Num_Removed_PC = (bytes[18]-0x30); data.RSS_FULL_Inter_Deviation_Time_Const_in_Sec = ((bytes[19]-0x30)+(bytes[20]-0x30)*0.1); data.RSS_FULL_Inter_Fast_Cut_Off = ((bytes[21]-0x30)*10+(bytes[22]-0x30)); data.RSS_FULL_Inter_Slow_Cut_Off = ((bytes[23]-0x30)*0.1+(bytes[24]-0x30)*0.001); data.RSS_FULL_Inter_Time_Const_in_Sec = ((bytes[25]-0x30)*10+(bytes[26]-0x30)); data.RSS_FULL_Inter_Weight = ((bytes[27]-0x30)+(bytes[28]-0x30)*0.1); data.RSS_FULL_Output_Time_Const_in_Sec = ((bytes[29]-0x30)+(bytes[30]-0x30)*0.1); data.RSS_FULL_DownSampling_factor = (bytes[31]-0x30); data.RSS_FULL_Power_Saving_mode = (bytes[32]-0x30); } } return {"Yunhorn_SmarToilets_data": data }; } }