356 lines
14 KiB
JavaScript
356 lines
14 KiB
JavaScript
// 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 };
|
|
}
|
|
} |