O7/AS923_HK_DECODER.js

473 lines
22 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}
// for Yunhorn SmarToilets STS-O7 Occupancy/Fall Detection/Over stay sensor
function Decode(fPort, data, variables) {
var data = {};
data.length = bytes.length;
if ((fPort === 10)) { // STS_O2_O6 V3 version 2023,pixel-network version
switch (bytes[0]) {
case 0x00:
data.LEDcolor = "Dark";
break;
case 0x01:
data.LEDcolor = "Green";
data.cubicleOccupyStatus = "Vacant";
break;
case 0x02:
data.LEDcolor = "Red";
data.cubicleOccupyStatus = "Occupied";
break;
case 0x03:
data.LEDcolor = "Blue";
data.cubicleOccupyStatus = "Maintenance";
break;
case 0x04:
data.LEDcolor = "Yellow";
data.cubicleOccupyStatus = "TBD";
break;
case 0x05:
data.LEDcolor = "Pink";
data.cubicleOccupyStatus = "TBD";
break;
case 0x06:
data.LEDcolor = "Cyan";
data.cubicleOccupyStatus = "TBD";
break;
case 0x07:
data.LEDcolor = "White";
data.cubicleOccupyStatus = "TBD";
break;
case 0x08:
data.LEDcolor = "Red_Blue";
data.cubicleOccupyStatus = "EMERGENCY";
break;
case 0x23:
data.LEDcolor = "Red_Blue";
data.cubicleOccupyStatus = "EMERGENCY";
break;
case 0x20:
data.LEDcolor = "Red_Flash";
data.cubicleOccupyStatus = "EMERGENCY";
break;
default:
data.LEDcolor = "TBD_COLOR";
data.cubicleOccupyStatus = "TBD_status";
break;
}
switch (bytes[1]) {
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;
}
// select only one below
// For NC(Normal Closed states
data.Sensor1_Door_Contact_Open = bytes[2] === 0 ? "Door Closed" : "Door Open";
// For NC(Normal Closed states
//data.Sensor1_Door_Contact_Open = bytes[3]===1?"Door Closed":"Door Open";
if (bytes[1] == 0x02) //Hall_element_mode
{
data.Sensor2_SOS_Pushed = bytes[3] === 0 ? "PushDown" : "RelaseUP";
} else if (bytes[1] > 0x02) {
data.Sensor2_Motion_Detected = bytes[3] === 0 ? "No Motion" : "Motion Detected";
}
return { "Yunhorn_SmarToilets_data": data };
}
else if ((fPort === 17) || (fPort === 19) || (fPort === 21)) {
data.BoardLED = ((bytes[0] & 0x7F) === 0x01) ? "ON" : "OFF";
switch (bytes[1]) {
case 0x00:
data.LEDcolor = "Dark";
break;
case 0x01:
data.LEDcolor = "Green";
data.cubicleOccupyStatus = "Vacant";
break;
case 0x02:
data.LEDcolor = "Red";
data.cubicleOccupyStatus = "Occupied";
break;
case 0x03:
data.LEDcolor = "Blue";
data.cubicleOccupyStatus = "Maintenance";
break;
case 0x04:
data.LEDcolor = "Yellow";
data.cubicleOccupyStatus = "TBD";
break;
case 0x05:
data.LEDcolor = "Pink";
data.cubicleOccupyStatus = "TBD";
break;
case 0x06:
data.LEDcolor = "Cyan";
data.cubicleOccupyStatus = "TBD";
break;
case 0x07:
data.LEDcolor = "White";
data.cubicleOccupyStatus = "TBD";
break;
case 0x08:
data.LEDcolor = "Red_Blue";
data.cubicleOccupyStatus = "EMERGENCY";
break;
case 0x23:
data.LEDcolor = "Red_Blue";
data.cubicleOccupyStatus = "EMERGENCY";
break;
case 0x20:
data.LEDcolor = "Red_Flash";
data.cubicleOccupyStatus = "EMERGENCY";
break;
default:
data.LEDcolor = "TBD_COLOR";
data.cubicleOccupyStatus = "TBD_status";
break;
}
switch (bytes[2]) {
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;
}
// select only one below
// For NC(Normal Closed states
data.Sensor1_Door_Contact_Open = bytes[3] === 0 ? "Door Closed" : "Door Open";
// For NC(Normal Closed states
//data.Sensor1_Door_Contact_Open = bytes[3]===1?"Door Closed":"Door Open";
data.Sensor2_Emergency_Button = bytes[4] === 0 ? "Alarm Push Down" : "No Alarm, Released";
data.Sensor3_Motion_Detected = bytes[5] === 0 ? "No Motion" : "Motion Detected";
data.length = bytes.length;
if (data.length === 9) {
data.Over_stay_state = (bytes[6] === 0) ? "False" : "True";
data.Over_Stay_duration_in_Seconds = (bytes[7] << 8 | bytes[8]);
return { "Yunhorn_SmarToilets_data": data };
}
else if (data.length > 9) {
data.Sensor4_ALARM_MUTE = (bytes[6] === 0) ? "Down Mute" : "No Mute";
data.Sensor5_ALARM_RESET = (bytes[7] === 0) ? "Down RESET" : "NO Reset";
data.Distance_in_mm = (bytes[8] << 8 | bytes[9]);
data.MotionLevel = (bytes[10] << 8 | bytes[11]);
data.Unconcious_State = (bytes[12] == 0) ? "False" : "True";
switch (bytes[13]) {
case 0x0:
data.Fall_Down_Detected_State = "Presence_Normal";
break;
case 0x01:
data.Fall_Down_Detected_State = "Presence_Fall_Down";
break;
case 0x02:
data.Fall_Down_Detected_State = "Presence_Rising_Up";
break;
case 0x03:
data.Fall_Down_Detected_State = "Presence_LayDown";
break;
case 0x04:
data.Fall_Down_Detected_State = "Presence_Unconcious";
break;
case 0x05:
data.Fall_Down_Detected_State = "Presence_Stay_Still";
break;
default:
data.Fall_Down_Detected_State = "Presence_Normal";
break;
}
data.OverStay_Detected_State = (bytes[14] == 0x0) ? "False" : "True";
data.OverStay_Duration_in_Seconds = (bytes[15] << 8 | bytes[16]);
data.No_Movement_Duration_in_Seconds = (bytes[17] << 8 | bytes[18]);
data.Unconcious_Duration_in_Seconds = (bytes[17] << 8 | bytes[18]);
data.Fall_Down_Speed_in_m_per_s = (bytes[19]);
data.Fall_Down_Gravity_in_g = (bytes[20]);
data.SOS_PushDown_Stamp = (bytes[21] << 24 | bytes[22] << 16 | bytes[23] << 8 | bytes[24]);
if (data.SOS_PushDown_Stamp != 0) {
var sos_start = new Date(1000 * data.SOS_PushDown_Stamp);
data.SOS_PushDown_Time = "[" + sos_start.getDate() + "." + (sos_start.getMonth() + 1) + "." + (sos_start.getFullYear()) + "] " + sos_start.getHours() + ":" + sos_start.getMinutes() + ":" + sos_start.getSeconds();
} else data.SOS_PushDown_Time = "N/A";
data.SOS_ReleaseUP_Stamp = (bytes[25] << 24 | bytes[26] << 16 | bytes[27] << 8 | bytes[28]);
if (data.SOS_ReleaseUP_Stamp != 0) {
var sos_stop = new Date(1000 * data.SOS_ReleaseUP_Stamp);
data.SOS_ReleaseUP_Time = "[" + sos_stop.getDate() + "." + (sos_stop.getMonth() + 1) + "." + (sos_stop.getFullYear()) + "] " + sos_stop.getHours() + ":" + sos_stop.getMinutes() + ":" + sos_stop.getSeconds();
} else data.SOS_ReleaseUP_Time = "N/A";
data.Fall_Down_Stamp = (bytes[29] << 24 | bytes[30] << 16 | bytes[31] << 8 | bytes[32]);
if (data.Fall_Down_Stamp != 0) {
var fall_start = new Date(1000 * data.Fall_Down_Stamp);
data.Fall_Down_Time = "[" + fall_start.getDate() + "." + (fall_start.getMonth() + 1) + "." + (fall_start.getFullYear()) + "] " + fall_start.getHours() + ":" + fall_start.getMinutes() + ":" + fall_start.getSeconds();
} else data.Fall_RiseUp_Stamp = "N/A";
data.Fall_RiseUp_Stamp = (bytes[33] << 24 | bytes[34] << 16 | bytes[35] << 8 | bytes[36]);
if (data.Fall_RiseUp_Stamp != 0) {
var fall_stop = new Date(1000 * data.Fall_RiseUp_Stamp);
data.Fall_RiseUp_Time = "[" + fall_stop.getDate() + "." + (fall_stop.getMonth() + 1) + "." + (fall_stop.getFullYear()) + "] " + fall_stop.getHours() + ":" + fall_stop.getMinutes() + ":" + fall_stop.getSeconds();
} else data.Fall_RiseUp_Time = "N/A";
}
return { "Yunhorn_SmarToilets_data": data };
}
// Heart Beat
else if ((fPort === 20) || (fPort === 18) || (fPort === 5)) {
var data = {};
//data.led_state=(bytes[0] & 0x7f) === 0 ? "Off" : "On";
data.BoardLED = ((bytes[0] & 0x7F) === 0x01) ? "ON" : "OFF";
data.battery_level = bytes[1] + " %";
return { "Yunhorn_SmarToilets_data": data };
}
// UPLINK, RFAC
else if (fPort === 1) {
var data = {};
data.length = bytes.length;
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;
}
}
if ((bytes[0] === 0x59) && (bytes[1] === 0x44)) //Duration interval
{
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.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.reserve4 = bytes[35];
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];
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) {
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] === 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 };
}
}