/*
LPWANLAB LTH5200
Temperature + Humidity Sensor
type : [header] [object type] [Data] [tail]
bytes : 1 1 N 1
value: 0xFF 0xFF
*/
var TYPE_UPLINK_UPDATE_TIME = 0x00; //request platform to update device time (power on message)
var TYPE_UPLINK_T_H_P_ALARM_REPORT = 0x01; //temperature , humidity power alarm report
var TYPE_UPLINK_T_H_P_BATCH_REPORT = 0x02; //temperature , humidity power batch report
var TYPE_UPLINK_ACK = 0x04; //Device response to down-link message ACK
var TYPE_UPLINK_MAX_MIN = 0x05; //The device modifies the maximum and minimum values
var TYPE_DNLINK_UPDATE_TIME_REQ = 0x10; //Platform request device update time
var TYPE_DNLINK_TH_RANGE = 0x11; // Temperature& humidity range setting
var TYPE_DNLINK_FREQ = 0x12; // Modify data up-link frequency
var TYPE_DNLINK_UPDATE_TIME = 0x13; // Update time request
var TYPE_DNLINK_DUTY_CYCLE = 0x14; // Change duty cycle
var TYPE_DNLINK_ALARM_ACK = 0x15; // Temporary release of device alarm
function bin16dec(bin) {
var num=bin&0xFFFF;
if (0x8000 & num)
{
num = - (0x010000 - num);
}
return num;
}
function bin8dec(bin) {
var num=bin&0xFF;
if (0x80 & num)
{
num = - (0x0100 - num);
}
return num;
}
function hexToBytes(hex) {
for (var bytes = [], c = 0; c < hex.length; c += 2)
{
bytes.push(parseInt(hex.substr(c, 2), 16));
}
return bytes;
}
function byte8bool(b8, mask) {
var num = b8 & mask;
if (num > 0)
{
return true;
}
return false;
}
function DecodeLTH5200Payload(data)
{
var obj = {};
var data_len = 0;
var i = 1;
var data_start = 2;
//obj.error = 0x00;
if (data[0] != 0xFF)
{
//bad header
obj.error = 0x01;
return obj;
}
switch(data[1])
{
case TYPE_UPLINK_UPDATE_TIME: // power on
data_len = 0;
obj.powered=true;
break;
case TYPE_UPLINK_T_H_P_ALARM_REPORT: //
i = data_start;
data_len = 9;
i=data_start;
obj.wsTime=(data[i]<<24) | (data[i+1] <<16) | (data[i+2]<<8) | (data[i+3]);
i +=4;
obj.Temperature=(data[i]<<8) | (data[i+1]);
i +=2;
obj.Humidity=(data[i]);
i +=1;
obj.Battery=(data[i]);
i +=1;
obj.Alarm_TemperatureMax=byte8bool(data[i], 0x01);
obj.Alarm_TemperatureMin=byte8bool(data[i], 0x02);
obj.Alarm_HumidityMax=byte8bool(data[i], 0x04);
obj.Alarm_HumidityMin=byte8bool(data[i], 0x08);
obj.Alarm_BatteryLow=byte8bool(data[i], 0x10); //battery_soc <20%
break;
case TYPE_UPLINK_T_H_P_BATCH_REPORT:
//yet to be deciphered, clarification by manufacturer required 20190410
//Format : Header|Object type |actual number of packets| Time stamp |High byte temperature|High byte temperature | Temperature high byte data | Temperature low byte data | Humidity data length | Humidity data | Power data length | Power data | Tail
// FF |02 |0001 | 5CAD934B | 01 | 01 | 17 | 02 | 01 | 2F | 01 | 5B | FF
//
//Actual Payload : FF0200015CB57D210101170101420157FF
//
//No. Packets: 2 Bytes Uint16_t
//
//Data: Time, DWORD, only upload the first package time.
// The temperature is divided into high byte and low byte. The byte
// length indicates the length of the data. The low byte temperature
// data is the fractional part. The result of the analysis needs to be
// divided by 10. When there is repeated data, the repeated portion
// after the uploaded data is denoted by A, A1 indicates that one data
// is repeated, and AF indicates that 15 data is repeated. The humidity
// is only one byte. The length of the humidity byte indicates the
// length of the humidity data. The analysis of the humidity data is the
// same as the temperature data. When the data is repeated, it is
// represented by An, and the power is the same as above.
//
//Format : | Header | Object type | actual number of packets| Time stamp |
//Actual : | FF | 02 | 00 01 | 5C B5 7D 21 |
//
//Format : | No Samples |
//Actual : | 01 |
//
//Format : | Temperature data Length | High byte temperature | Temperature low byte data |
//Actual : | 01 | 17 | 01 |
//
//Format : | Humidity data length | Humidity data |
//Actual : | 01 | 42 |
//
//Format : | Power data length | Power data | Footer |
//Actual : | 01 | 57 | FF |
//
//Format : | Footer |
//Actual : | FF |
i = data_start;
var packets = (data[i]<<8) | (data[i+1]);
obj.packets= packets;
i+=2;
if (obj.packets == 1)
{
obj.wsTime = (data[i]<<24) | (data[i+1] <<16) | (data[i+2]<<8) | (data[i+3]);
i+=4;
var samples_no = data[i];
i+=1;
//obj.samples_no = samples_no;
var temp_no = data[i];
i+=1;
//obj.temp_no = temp_no;
if (temp_no == 1)
{
var temp = data[i];
temp += data[i+1]/10.0;
obj.temperature = temp;
}
i+=2;
var humid_no = data[i];
i+=1;
//obj.humid_no = humid_no;
if (humid_no == 1)
{
var humidity = data[i];
obj.humidity = humidity;
}
i+=1;
var pwr_no = data[i];
i+=1;
//obj.pwr_no = pwr_no;
if (pwr_no == 1)
{
var power = data[i];
obj.battery = power;
}
i+=1;
}
else
{
obj.report_batch_supported = false;
}
i = data_start;
break;
case TYPE_UPLINK_ACK: //
i=data_start;
obj.downlink_counter=(data[i]<<24) | (data[i+1] <<16) | (data[i+2]<<8) | (data[i+3]);
i+=4;
if (byte8bool(data[i], 0x01))
{
obj.result = "success";
}
else
{
obj.result = "fail";
}
break;
case TYPE_UPLINK_MAX_MIN: //Temperature& humidity range setting
i=data_start;
obj.HumidityMax=(data[i]);
i+=1;
obj.HumidityMin=(data[i]);
i+=1;
obj.TemperatureMax=(data[i]);
i+=1;
obj.TemperatureMin=(data[i]);
i+=1;
break;
default: //something is wrong with data
i=data.length;
break;
}
return obj;
}
function Decoder(bytes, port) {
return DecodeLTH5200Payload(bytes);
}