# 数据解析
本文档介绍了如何将数据手册中描述的二进制数据解码为 JSON 格式,以及如何将 JSON 格式编码为二进制数据,方便用户将硬件设备直接集成在自己的系统里。JS 脚本主要运行在 Lora 网络服务器中,若网络服务器支持脚本解析,可将编解码的脚本配置在服务器中,这样服务器直接输出 JSON 格式的数据,方便应用服务器的数据处理,同理,应用服务器可直接向网络服务器发送 JSON 格式的参数或命令。若网络服务器不支持脚本解析,用户可参考 Java 代码在自己的应用服务器中实现数据的编解码。
目前支持
- JavaScript
- Java(开发中)
# JavaScript
# 解码 (opens new window)
输入参数:
fPort:lora 协议的端口号
bytes:二进制数组,从基站接收的原始数据,若为 Base64 编码,需要先解码。
function Decode(fPort, bytes, variables) {
var obj = {};
var offset = 0;
if( (fPort < 10 || fPort > 27) && fPort != 197 && fPort != 198){
obj.msgType = "unknown";
obj.code = 1;
obj.error = "Unknown fPort,expect([10,25]),actual(" + fPort + ")";
return obj;
}
if(null == bytes){
return {};
}
var indexI, indexJ;
switch(fPort){
//It's a heartbeat message.
case 10:
{
obj.msgType = "heartbeat";
if(bytes.length < 16){
obj.code = 2;
obj.error = "Wrong message length,expect(16,18,20),actual(" + bytes.length + ")";
return obj;
}
obj.code = 0;
obj.version = {};
obj.version.swVer = ((bytes[0] >> 4) & 0x3).toString() + "." + (bytes[0] & 0xf).toString();
obj.version.hardwareType = (bytes[0] >> 6);// 1: "gateway" , 0: "badge";
obj.signal = {};
if (bytes[1] <= 127)
obj.signal.rssi = bytes[1] - 20;
else
obj.signal.rssi = bytes[1] - 275;
if(bytes[2] <= 127)
obj.signal.snr = bytes[2];
else
obj.signal.snr = bytes[2]- 255;
obj.status = {};
//GNSS status
obj.status.gnss = (bytes[3] >>> 5) & 0x3; //0:off,1:positioning,2:successful,3:failed
obj.status.battery = (bytes[3] >> 3) & 0x3; //0:not charging,1:charging,2:complete,3:unknown
//During the heartbeat period, whether the device is moved.
obj.status.vibstate = (bytes[3] >> 2) & 0x1;//1: moved,0:static;
/*
Only used when the hardware type is badge.
0 indicates it works as a tracker
1 indicates it works as a BLE gateway
*/
obj.workmode = (bytes[3] >> 1) & 0x1;//1:gateway,0:tracker;
//Calculate the available power of the battery.
var voltage = bytes[4]/ 100.0 + 2;
if(voltage < 3.3){
obj.status.soc = 0;
}
else if(voltage >= 4.15){
obj.status.soc = 100;
}
else if(voltage >= 4.1){
obj.status.soc = 99;
}
else if(voltage >= 4.04){
obj.status.soc = Math.round(96 + 3 * (voltage - 4.04) / (4.1 - 4.04));
}
else if(voltage >= 3.97){
obj.status.soc = Math.round(90 + 6 * (voltage - 3.97) / (4.04 - 3.97));
}
else if(voltage >= 3.92){
obj.status.soc = Math.round(69 + 21 * (voltage - 3.92) / (3.97 - 3.92));
}
else if(voltage >= 3.69){
obj.status.soc =Math.round (25 + 44 * (voltage - 3.69) / (3.92 - 3.69));
}
else if(voltage >= 3.4){
obj.status.soc = Math.round(3 + 22 * (voltage - 3.4) / (3.69 - 3.4));
}
else if(voltage >= 3.3){
obj.status.soc = Math.round(3 * (voltage - 3.3) / (3.4 - 3.3));
}
//Parse the parameters.
obj.parameters = {};
obj.parameters.txPower = bytes[5] >>> 6;
//Data rate
obj.parameters.dr = (bytes[5] >> 3) & 0x7;
//Scheme
// 0:US915,1:EU868,2:AU915,3:CN470,4:AS923,5:KR920,6:IN865,7:RU864;
obj.parameters.scheme = bytes[5] & 0x7;
obj.parameters.ble = {};
obj.parameters.ble.auReport = bytes[6] >>> 7;//1:enable,0:disable;
var bleperiod = [0,5,10,20,30,60,120,300,600,900,1200,1800,3600,7200,21600,43200];
obj.parameters.ble.period = bleperiod[(bytes[6] >> 3) & 0x0f];
var scan = [1,2,3,6,9,12,15,255];
obj.parameters.ble.scan = scan[bytes[6] & 0x7];
obj.parameters.ble.scale = (bytes[7] >> 6) & 0x3;
obj.parameters.ble.stepsOff = ((bytes[7] >> 3) & 0x7) * 5;
obj.parameters.ble.bleOff = bytes[7] & 0x7;
obj.parameters.warning = {};
//buzzer 0:disable,1:enable;
obj.parameters.warning.buzzer = (bytes[8] >> 5) & 0x1;
obj.parameters.warning.vibrator = (bytes[8] >> 4) & 0x1;//1:enabled,0:disabled;
var distance = [2,4,6,8,10,15,255];
obj.parameters.warning.distance = distance[(bytes[8] >> 1) & 0x7];
obj.parameters.warning.proximity = bytes[8] & 0x1;//1:enabled,0:disabled;
//Gnss report period
var gnssperiod = [0,10,20,30,60,120,300,600,1800,3600,7200,10800,21600,43200];
obj.parameters.gnssPeriod = gnssperiod[(bytes[9] >> 4) & 0xf];
//Heartbeat report period
var heartbeatperiod = [60,300,600,1200,1800,3600,7200,21600,43200,86400,86400,86400,86400,86400,86400,86400];
obj.parameters.heartBeatPeriod = heartbeatperiod[bytes[9] & 0xf];
if(obj.version.swVer > "1.4"){
obj.parameters.sleepy = {};
obj.parameters.sleepy.start = ((bytes[10] & 0x3) << 3) | ((bytes[11] >> 5) & 0x7);
obj.parameters.sleepy.end = bytes[11] & 0x1f;
obj.parameters.sleepy.degree = (bytes[10] >> 2) & 0x7;
if(obj.parameters.sleepy.start != obj.parameters.sleepy.end){
obj.parameters.timestamp = ((bytes[12] & 0xff) << 24) | ((bytes[13] & 0xff) << 16) | ((bytes[14] & 0xff) << 8) | (bytes[15] & 0xff);
obj.bleAck = (bytes[16] >> 3) & 0x01;
obj.thres = bytes[16] & 0x07;
obj.steps = ((bytes[17] & 0xff) << 16) | ((bytes[18] & 0xff) << 8) | (bytes[19] & 0xff);
}
else{
obj.bleAck = (bytes[12] >> 3) & 0x01;
obj.thres = bytes[12] & 0x07;
obj.steps = ((bytes[13] & 0xff) << 16) | ((bytes[14] & 0xff) << 8) | (bytes[15] & 0xff);
}
}
else{
var dateInd = bytes[10] & 0x40;
obj.parameters.time = {};
if(dateInd){
obj.parameters.time.date = ((bytes[14] & 0xff) << 8) | (bytes[15] & 0xff);
}
obj.parameters.time.hour = ((bytes[11] & 0x1)<<4) | (bytes[12] >> 4);
obj.parameters.time.minute = ((bytes[12] & 0xf) << 2) | (bytes[13] >> 6);
obj.parameters.time.second = bytes[13] & 0x3f;
obj.parameters.sleepy = {};
obj.parameters.sleepy.start = ((bytes[10] & 0x7) << 2) | (bytes[11] >> 6);
obj.parameters.sleepy.end = (bytes[11] >> 1) & 0x1f;
obj.parameters.sleepy.degree = (bytes[10] >> 3) & 0x7;
//Threshold
if(dateInd){
obj.bleAck = (bytes[16] >> 3) & 0x01;
obj.thres = bytes[16] & 0x07;
obj.steps = ((bytes[17] & 0xff) << 16) | ((bytes[18] & 0xff) << 8) | (bytes[19] & 0xff);
}
else{
obj.bleAck = (bytes[14] >> 3) & 0x01;
obj.thres = bytes[14] & 0x07;
obj.steps = ((bytes[15] & 0xff) << 16) | ((bytes[16] & 0xff) << 8) | (bytes[17] & 0xff);
}
}
return obj;
}
case 11:
{
obj.msgType = "GNSS coordinate";
if(bytes.length != 9 && bytes.length != 25){
obj.code = 2;
obj.error = "Wrong message length,expect(9,25),actual(" + bytes.length + ")";
return obj;
}
obj.code = 0;
if(bytes.length == 9)
{
obj.longitude = {};
obj.longitude.orientation = bytes[0] & 0x80 ? "W" : "E";
var longi = (bytes[0] & 0x7f) << 24 | bytes[1] << 16 | bytes[2] << 8 | bytes[3];
obj.longitude.value = (parseInt(longi / 10000000) + (longi % 10000000) / 6000000.0).toFixed(7);
obj.latitude = {};
obj.latitude.orientation = bytes[4] & 0x80 ? "S" : "N";
var lati = (bytes[4] & 0x7f) << 24 | bytes[5] << 16 | bytes[6] << 8 | bytes[7];
obj.latitude.value = (parseInt(lati / 10000000) + (lati % 10000000) / 6000000.0).toFixed(7);
obj.time = bytes[8];
}
else if(bytes.length == 25)
{
obj.longitude = {};
obj.longitude.orientation = bytes[0] & 0x80 ? "W" : "E";
var longi = (bytes[0] & 0x7f) << 24 | bytes[1] << 16 | bytes[2] << 8 | bytes[3];
obj.longitude.value = (parseInt(longi / 10000000) + (longi % 10000000) / 6000000.0).toFixed(7);
obj.latitude = {};
obj.latitude.orientation = bytes[4] & 0x80 ? "S" : "N";
var lati = (bytes[4] & 0x7f) << 24 | bytes[5] << 16 | bytes[6] << 8 | bytes[7];
obj.latitude.value = (parseInt(lati / 10000000) + (lati % 10000000) / 6000000.0).toFixed(7);
obj.longitude1 = {};
obj.longitude1.orientation = bytes[8] & 0x80 ? "W" : "E";
longi = (bytes[8] & 0x7f) << 24 | bytes[9] << 16 | bytes[10] << 8 | bytes[11];
obj.longitude1.value = (parseInt(longi / 10000000) + (longi % 10000000) / 6000000.0).toFixed(7);
obj.latitude1 = {};
obj.latitude1.orientation = bytes[12] & 0x80 ? "S" : "N";
lati = (bytes[12] & 0x7f) << 24 | bytes[13] << 16 | bytes[14] << 8 | bytes[15];
obj.latitude1.value = (parseInt(lati / 10000000) + (lati % 10000000) / 6000000.0).toFixed(7);
obj.longitude2 = {};
obj.longitude2.orientation = bytes[16] & 0x80 ? "W" : "E";
longi = (bytes[16] & 0x7f) << 24 | bytes[17] << 16 | bytes[18] << 8 | bytes[19];
obj.longitude2.value = (parseInt(longi / 10000000) + (longi % 10000000) / 6000000.0).toFixed(7);
obj.latitude2 = {};
obj.latitude2.orientation = bytes[20] & 0x80 ? "S" : "N";
lati = (bytes[20] & 0x7f) << 24 | bytes[21] << 16 | bytes[22] << 8 | bytes[23];
obj.latitude2.value = (parseInt(lati / 10000000) + (lati % 10000000) / 6000000.0).toFixed(7);
obj.time = bytes[24];
}
return obj;
}
case 12:
{
obj.msgType = "BLE coordinate";
if(bytes.length < 7){
obj.code = 2;
obj.error = "wrong message length,less than minimum length(10)";
return obj;
}
obj.code = 0;
var majorLen,majorShift,beaconStart;
if(bytes[1] == 0)
{
obj.step = bytes[0] << 16 | bytes[1] << 8 | bytes[2];
//How many kinds of Major value of the beacons.
majorLen = bytes[3] & 0xf;
majorShift = 4 + majorLen;
beaconStart = 4;
}
else{
majorLen = bytes[0] & 0xf;
majorShift = 1 + majorLen;
beaconStart = 1;
obj.closecontact = (bytes[0] >> 4) & 0x1;
}
obj.beaconList = [];
for(indexI = 0; indexI < majorLen; indexI++){
var beaconNum = bytes[beaconStart + indexI];
var major = (bytes[majorShift] << 8 | bytes[majorShift + 1]).toString(16);
var minorShift = majorShift + 2;
for(indexJ = 0; indexJ < beaconNum; indexJ++){
//var minorShift = majorShift + 2 + indexJ *3;
var beaconObj = {};
beaconObj.major = major;
beaconObj.minor = ((bytes[minorShift] << 8) | bytes[minorShift + 1]).toString(16);
beaconObj.type = (bytes[minorShift + 2] >> 5) & 0x3;//0:locator,1:asset,2:alarm,3:proximity
beaconObj.rssi = -(bytes[minorShift + 2] & 0x1f) - 59;
minorShift += 2;
if(bytes[minorShift] >> 7){
beaconObj.battery = bytes[minorShift + 1] & 0x7f;
minorShift += 1;
}
minorShift += 1;
obj.beaconList.push(beaconObj);
}
majorShift = minorShift;
}
return obj;
}
case 13:
{
obj.msgType = "alarm";
if(bytes.length != 2){
obj.code = 2;
obj.error = "Wrong message length,expect(2),actual(" + bytes.length + ")";
return obj;
}
obj.code = 0;
obj.msgId = bytes[0];
obj.ack = (bytes[1] >> 4) & 0x1;// 1:true,0:false;
//0:SOS,1:SOS dismissed,2:power off,3:BLE disable,4:LoRa disable,5:GPS disable,6:Enter hazardous area,7:Unknown
obj.alarm = bytes[1] & 0x7;
return obj;
}
case 14:
{
obj.msgType = "ack";
if(bytes.length != 2){
obj.code = 2;
obj.error = "Wrong message length,expect(2),actual(" + bytes.length + ")";
return obj;
}
obj.code = 0;
obj.msgId = bytes[0];
//0:succeed,1:parameter not supported,2:parameter out of range,3:unknown;
obj.result = bytes[1] & 0x3;
return obj;
}
case 15:
{
obj.msgType = "Positioning UUID list";
obj.code = 0;
if(bytes[0] == 0){
return {};
}
obj.uuidList = [];
for(indexI = 0; indexI < bytes[0]; indexI++){
var uuid = {};
uuid.index = bytes[1 + 17 * indexI];
var str = "";
for(indexJ = 2 + 17 * indexI; indexJ < 18 + 17 * indexI; indexJ++){
var tmp = bytes[indexJ].toString(16);
if(tmp.length == 1){
tmp = "0" + tmp;
}
str += tmp;
}
uuid.uuid = str;
obj.uuidList.push(uuid);
}
return obj;
}
case 16:
{
obj.msgType = "Asset UUID list";
obj.code = 0;
if(bytes[0] == 0){
return {};
}
obj.uuidList = [];
for(indexI = 0; indexI < bytes[0]; indexI++){
var uuidAsset = {};
uuidAsset.index = bytes[1 + 17 * indexI];
var strAsset = "";
for(indexJ = 2 + 17 * indexI; indexJ < 18 + 17 * indexI; indexJ++){
var tmpAsset = bytes[indexJ].toString(16);
if(tmpAsset.length == 1){
tmpAsset = "0" + tmpAsset;
}
strAsset += tmpAsset;
}
uuidAsset.uuid = strAsset;
obj.uuidList.push(uuidAsset);
}
return obj;
}
case 17:
{
obj.msgType = "Pass-through filter list";
obj.code = 0;
if(bytes[0] == 0){
return obj;
}
obj.filterList = [];
var pos = 1;
for(indexI = 0; indexI < bytes[0]; indexI++){
var filterPosPass = {};
filterPosPass.port = bytes[pos];
filterPosPass.start = bytes[pos+1];
filterPosPass.end = bytes[pos+2];
filterPosPass.filterStart = bytes[pos + 3];
filterPosPass.filterLen= bytes[pos+4];
var filterLen = bytes[pos+4];
var strPosPass = "";
for(indexJ = 0; indexJ < filterLen; indexJ++){
var tmpPosPass = bytes[pos+5+indexJ].toString(16);
if(tmpPosPass.length == 1){
tmpPosPass = "0" + tmpPosPass;
}
strPosPass += tmpPosPass;
}
pos = pos + 5 + filterLen;
filterPosPass.filter = strPosPass;
obj.filterList.push(filterPosPass);
}
return obj;
}
case 18:
{
obj.msgType = "History Beacon Config List";
obj.code = 0;
if(bytes[0] == 0){
return {};
}
obj.number = bytes[0];
obj.beaconList = [];
for(indexI = 0; indexI < bytes[0]; indexI++){
var beacon= {};
offset = 5 * indexI;
beacon.index = bytes[1 + offset];
beacon.major = (bytes[2 + offset] << 8 | bytes[3 + offset]).toString(16);
beacon.minor = (bytes[4 + offset] << 8 | bytes[5 + offset]).toString(16);
obj.beaconList.push(beacon);
}
return obj;
}
case 19:
{
obj.msgType = "History Beacon Info List";
obj.code = 0;
if(bytes[0] == 0){
return {};
}
obj.number = bytes[0];
obj.beaconList = [];
for(indexI = 0; indexI < bytes[0]; indexI++){
var bea= {};
offset = 9 * indexI;
bea.major = (bytes[1 + offset] << 8 | bytes[2 + offset]).toString(16);
bea.minor = (bytes[3 + offset] << 8 | bytes[4 + offset]).toString(16);
bea.rssi = -((bytes[5 + offset] & 0x1f) + 59);
bea.frmOff = (bytes[6 + offset] << 8 | bytes[7 + offset]);
bea.timeOff = (bytes[8 + offset] << 8 | bytes[9 + offset]);
obj.beaconList.push(bea);
}
return obj;
}
case 20:
{
obj.msgType = "History GNSS Info List";
obj.code = 0;
if(bytes[0] == 0){
return {};
}
obj.number = bytes[0];
obj.gnssList = [];
for(indexI = 0; indexI < bytes[0]; indexI++){
var gnss = {};
offset = 12 * indexI;
gnss.longitude = {};
gnss.longitude.orientation = bytes[1+offset] & 0x80 ? "W" : "E";
var longiH = (bytes[1+offset] & 0x7f) << 24 | bytes[2+offset] << 16 | bytes[3+offset] << 8 | bytes[4+offset];
gnss.longitude.value = (parseInt(longiH / 10000000) + (longiH % 10000000) / 6000000.0).toFixed(7);
gnss.latitude = {};
gnss.latitude.orientation = bytes[5+offset] & 0x80 ? "S" : "N";
var latiH = (bytes[5+offset] & 0x7f) << 24 | bytes[6+offset] << 16 | bytes[7+offset] << 8 | bytes[8+offset];
gnss.latitude.value = (parseInt(latiH / 10000000) + (latiH % 10000000) / 6000000.0).toFixed(7);
gnss.frmOff = (bytes[9 + offset] << 8 | bytes[10 + offset]);
gnss.timeoff = (bytes[11 + offset] << 8 | bytes[12 + offset]);
obj.gnssList.push(gnss);
}
return obj;
}
case 21:
case 22:
case 23:
case 24:
case 25:
{
obj.msgType = "Pass-through data list";
obj.port = fPort;
obj.code = 0;
if(bytes[0] == 0){
return {};
}
obj.dataList = [];
var dataLen = (bytes.length - 1)/bytes[0];
for(indexI = 0; indexI < bytes[0]; indexI++){
var passData = {};
passData.index = indexI;
var strDataPass = "";
for(indexJ = 1 + dataLen * indexI; indexJ < 1 + dataLen + dataLen * indexI; indexJ++){
var tmpDataPass = bytes[indexJ].toString(16);
if(tmpDataPass.length == 1){
tmpDataPass = "0" + tmpDataPass;
}
strDataPass += tmpDataPass;
}
passData.payload = strDataPass;
obj.dataList.push(passData);
}
return obj;
}
case 26:
{
var ii = 0;
var len = bytes.length;
var out = {access_points: []};
for (; ii < len ;) {
out.access_points.push({macAddress: bytes.slice(ii, ii + 6), signalStrength: int8(bytes[ii+6])});
ii += 7;
}
return out;
}
case 27:
{
return {
"sat_count": bytes[0],
"lr1110_gnss": bytes.slice(2, bytes.length)
};
}
default:
return {};
}
return {};
}
// convert a byte value to signed int8
function int8(byte) {
var sign = byte & (1 << 7);
if (sign) {
return 0xFFFFFF00 | byte;
}
return byte;
}
# 编码 (opens new window)
输入参数:
fPort:下行 lora 协议端口。
obj:JSON 格式的参数或命令。
function Encode(fPort, obj) {
var rst = [];
if(fPort < 10 || fPort > 17){
console.log("Unknown fPort,expect([10,17]),actual(" + fPort + ")");
return rst;
}
if(null == obj){
console.log("obj is null");
return [];
}
if(obj.msgId <0 || obj.msgId > 255){
return [];
}
var arrayIndex = 0;
switch(fPort){
//It's a parameters setting message.
case 10:
{
var index;
rst[arrayIndex++] = obj.msgId;
var power = [0,1,2,3];
index = power.indexOf(obj.txPower);
if(-1 != index){
rst[arrayIndex++] = 1;
rst[arrayIndex++] = index;
}
var dr = [0,1,2];
index = dr.indexOf(obj.dr);
if(-1 != index){
rst[arrayIndex++] = 2;
rst[arrayIndex++] = index;
}
var auReport = ["disable","enable"];
index = auReport.indexOf(obj.bleAuReport);
if(-1 != index){
rst[arrayIndex++] = 3;
rst[arrayIndex++] = index;
}
var blePeriod = [0,5,10,20,30,60,120,300,600,900,1200,1800,3600,7200,21600,43200];
index = blePeriod.indexOf(obj.blePeriod);
if(-1 != index){
rst[arrayIndex++] = 4;
rst[arrayIndex++] = index;
}
var bleScan = [1,2,3,6,9,12,15,255];
index = bleScan.indexOf(obj.bleScan);
if(-1 != index){
rst[arrayIndex++] = 5;
rst[arrayIndex++] = index;
}
var scale = [0,1,2,3];
index = scale.indexOf(obj.scale);
if(-1 != index){
rst[arrayIndex++] = 6;
rst[arrayIndex++] = index;
}
var bleStepsOff = [0,1,2,3,4,5,6,7];
index = bleStepsOff.indexOf(obj.bleStepsOff);
if(-1 != index){
rst[arrayIndex++] = 7;
rst[arrayIndex++] = index;
}
var bleBleOff = [0,1,2,3,4,5,6,7];
index = bleBleOff.indexOf(obj.bleBleOff);
if(-1 != index){
rst[arrayIndex++] = 8;
rst[arrayIndex++] = index;
}
var warnBuzzer = ["disable","enable"];
index = warnBuzzer.indexOf(obj.warnBuzzer);
if(-1 != index){
rst[arrayIndex++] = 9;
rst[arrayIndex++] = index;
}
var warnVibrator = ["disable","enable"];
index = warnVibrator.indexOf(obj.warnVibrator);
if(-1 != index){
rst[arrayIndex++] = 10;
rst[arrayIndex++] = index;
}
var warnDistance = [2,4,6,8,10,15,255];
index = warnDistance.indexOf(obj.warnDistance);
if(-1 != index){
rst[arrayIndex++] = 11;
rst[arrayIndex++] = index;
}
var warnProximity = ["disable","enable"];
index = warnProximity.indexOf(obj.warnProximity);
if(-1 != index){
rst[arrayIndex++] = 12;
rst[arrayIndex++] = index;
}
var gnssPeriod = [0,10,20,30,60,120,300,600,1800,3600,7200,10800,21600,43200];
index = gnssPeriod.indexOf(obj.gnssPeriod);
if(-1 != index){
rst[arrayIndex++] = 13;
rst[arrayIndex++] = index;
}
var heartBeatPeriod = [60,300,600,1200,1800,3600,7200,21600,43200,86400];
index = heartBeatPeriod.indexOf(obj.heartBeatPeriod);
if(-1 != index){
rst[arrayIndex++] = 14;
rst[arrayIndex++] = index;
}
if(null != obj.time){
if(obj.time.hour >= 0 && obj.time.hour <=23 &&
obj.time.minute >= 0 && obj.time.minute <= 59 &&
obj.time.second >=0 && obj.time.second <=59){
rst[arrayIndex++] = 15;
rst[arrayIndex++] = obj.time.hour;
rst[arrayIndex++] = obj.time.minute;
rst[arrayIndex++] = obj.time.second;
}
if(null != obj.time.date){
rst[arrayIndex++] = 19;
rst[arrayIndex++] = obj.time.date >> 8;
rst[arrayIndex++] = obj.time.date & 0xff;
}
}
else{
if(null != obj.datetime){
rst[arrayIndex++] = 15;
rst[arrayIndex++] = (obj.datetime >> 24) & 0xff;
rst[arrayIndex++] = (obj.datetime >> 16) & 0xff;
rst[arrayIndex++] = (obj.datetime >> 8) & 0xff;
rst[arrayIndex++] = obj.datetime & 0xff;
}
}
if(null != obj.sleepy){
if(obj.sleepy.start >= 0 && obj.sleepy.start <=23 &&
obj.sleepy.end >= 0 && obj.sleepy.end <= 23 &&
obj.sleepy.degree >=0 && obj.sleepy.degree <=7){
rst[arrayIndex++] = 16;
rst[arrayIndex++] = obj.sleepy.degree;
rst[arrayIndex++] = obj.sleepy.start;
rst[arrayIndex++] = obj.sleepy.end;
}
}
var bleThres= [0,1,2,3,4,5,6,7];
index = bleThres.indexOf(obj.thres);
if(-1 != index){
rst[arrayIndex++] = 17;
rst[arrayIndex++] = index;
}
var bleAck = [0,1];
index = bleAck.indexOf(obj.bleAck);
if(-1 == index){
var bleAckStr= ["disable","enable"];
index = bleAckStr.indexOf(obj.bleAck);
if(-1 != index){
rst[arrayIndex++] = 18;
rst[arrayIndex++] = index;
}
}
else{
rst[arrayIndex++] = 18;
rst[arrayIndex++] = index;
}
return rst;
}
break;
case 11:
{
rst[arrayIndex++] = obj.msgId;
rst[arrayIndex++] = obj.time >> 8;
rst[arrayIndex++] = obj.time & 0xFF;
return rst;
}
break;
//command
case 12:
{
rst[arrayIndex++] = obj.msgId;
if(obj.cmd >= 0 && obj.cmd <= 9){
rst[arrayIndex] = obj.cmd;
return rst;
}
}
break;
//ack
case 13:
{
rst[arrayIndex] = obj.msgId;
return rst;
}
break;
//Positioning beacon UUID setting
case 14:
//Asset beacon UUID setting
case 15:
{
var uuidNum = obj.uuidList.length;
rst[arrayIndex++] = obj.msgId;
rst[arrayIndex++] = uuidNum;
if(uuidNum >= 1 && uuidNum <=5){
for(var i=0; i<uuidNum; i++){
var uuidIndex = obj.uuidList[i].index;
if(uuidIndex >= 0 && uuidIndex <= 4){
var uuid = obj.uuidList[i].uuid;
if(uuid.length == 32){
rst[arrayIndex++] = uuidIndex;
var pos=0;
for(var j=0; j<16; j++)
{
var s = uuid.substr(pos, 2);
var v = parseInt(s, 16);
rst[arrayIndex++] = v;
pos += 2;
}
}
else{
return [];
}
}
}
return rst;
}
}
break;
case 16:
{
rst[arrayIndex++] = obj.msgId;
var filterPort = obj.port;
if(filterPort >= 21 && filterPort <= 25){
var filterLen = obj.filterLen;
var filter = obj.filter;
if(filter.length == (filterLen<<1)){
rst[arrayIndex++] = filterPort;
rst[arrayIndex++] = obj.start;
rst[arrayIndex++] = obj.end;
rst[arrayIndex++] = obj.filterStart;
rst[arrayIndex++] = obj.filterLen;
var filterPos=0;
for(var j1=0; j1<filterLen ; j1++)
{
var s1 = filter.substr(filterPos, 2);
var v1 = parseInt(s1, 16);
rst[arrayIndex++] = v1;
filterPos += 2;
}
}
return rst;
}
}
break;
case 17:
{
var beaconNum = obj.number;
rst[arrayIndex++] = obj.msgId;
rst[arrayIndex++] = beaconNum;
if(beaconNum >= 1 && beaconNum <=20){
for(var beaconI=0; beaconI<beaconNum; beaconI++){
var beaconIndex = obj.beaconList[beaconI].index;
if(beaconIndex >= 0 && beaconIndex <= 19){
var beaconMajor= obj.beaconList[beaconI].major;
var beaconMinor= obj.beaconList[beaconI].minor;
rst[arrayIndex++] = beaconIndex;
rst[arrayIndex++] = beaconMajor >> 8;
rst[arrayIndex++] = beaconMajor & 0xff;
rst[arrayIndex++] = beaconMinor >> 8;
rst[arrayIndex++] = beaconMinor & 0xff;
}
}
return rst;
}
}
break;
default:
}
return [];
}
# 上行消息
本章列出各消息解码后的 JSON 格式示例。
# 心跳消息
端口:10
{
"bleAck":1,
"code":0,
"msgType":"heartbeat",
"parameters":
{
"ble":
{
"alReport":0,
"bleOff":0,
"period":10,
"scale":3,
"scan":1,
"stepsOff":5
},
"dr":3,
"gnssPeriod":30,
"heartBeatPeriod":300,
"scheme":3,
"sleepy":
{
"degree":0, //睡眠程度
"end":7,
"start":22
},
"time":
{
"hour":9,
"minute":29,
"second":3
},
"txPower":20,
"warning":{
"buzzer":0,
"distance":6,
"proximity":0,
"vibrator":0
}
},
"signal":
{
"rssi":-27,
"snr":10.0
},
"status":
{
"battery":0,
"gnss":0,
"soc":100, //电池剩余电量,百分比
"vibstate":0
},
"steps":60,
"thres":0, //信标RSSI检测门限
"version":
{
"hardwareType":0,
"swVer":"1.3"
},
"workMode":0
}
# GNSS
端口:11
{
"latitude": //纬度
{
"orientation":"N",
"value":32.0818933
},
"longitude": //经度
{
"orientation":"E",
"value":118.8034133
},
"msgType":"GNSS coordinate",
"time":4
}
# 蓝牙信息
端口:12
{
"beaconList":[
{
"major":"3001",
"minor":"3000",
"rssi":-68,
"type":0
},
{
"major":"3001",
"minor":"3001",
"rssi":-75,
"type":0
},
{
"major":"2001",
"minor":"2000",
"rssi":-75,
"type":0
}
],
"code":0,
"msgType":"BLE coordinate",
"step":9710
}
# 报警消息
端口:13
{
"ack":0,
"alarm":2, //报警类型,参考数据手册获取具体定义。
"msgId":0,
"msgType":"alarm"
}
# 确认消息
端口:14
{
"code":0,
"msgId":0,
"msgType":"ack",
"result":0
}
# 定位信标 UUID
端口:15
{
"code":0,
"msgType":"Positioning UUID list",
"uuidList":[
{
"index":0,
"uuid":"22222222222222222222222222222222"
},
{
"index":1,
"uuid":"33333333333333333333333333333333"
},
{
"index":2,
"uuid":"44444444444444444444444444444444"
},
{
"index":3,
"uuid":"55555555555555555555555555555555"
},
{
"index":4,
"uuid":"66666666666666666666666666666666"
}
]
}
# 资产信标 UUID
端口:16
{
"code":0,
"msgType":"Asset UUID list",
"uuidList":[
{
"index":0,
"uuid":"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
},
{
"index":1,
"uuid":"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"
},
{
"index":2,
"uuid":"cccccccccccccccccccccccccccccccc"
},
{
"index":3,
"uuid":"dddddddddddddddddddddddddddddddd"
},
{
"index":4,
"uuid":"eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee"
}
]
}
# 透传信标过滤器
端口:17
{
"code":0,
"filterList":[
{
"end":30,
"filter":"02a6fd0110004653",
"filterLen":8,
"filterStart":7,
"port":21,
"start":0
}
],
"length":1,
"msgType":"Pass-through filter list"
}
# 需确认信标配置列表
端口:18
{
"beaconList":[
{
"index":0,
"major":"2001",
"minor":"2000"
},
{
"index":1,
"major":"2001",
"minor":"2001"
},
{
"index":2,
"major":"3001",
"minor":"3000"
},
{
"index":3,
"major":"3001",
"minor":"3001"
}
],
"code":0,
"msgType":"History Beacon Config List",
"number":4
}
# 历史信标列表
端口:19
{
"beaconList":[
{
"frmOff":3,
"major":"1101",
"minor":"110e",
"rssi":-85,
"timeOff":50
}
],
"code":0,
"msgType":"History Beacon Info List",
"number":1
}
# 历史室外坐标列表
端口:20
{
"code":0,
"gnssList":[
{
"frmOff":9,
"latitude":
{
"orientation":"N",
"value":32.0813933
},
"longitude":
{
"orientation":"E",
"value":118.8016
},
"timeoff":141
},
{
"frmOff":8,
"latitude":
{
"orientation":"N",
"value":32.0821467
},
"longitude":
{
"orientation":"E",
"value":118.80228
},
"timeoff":101
}
],
"msgType":"History GNSS Info List",
"number":2
}
# 透传蓝牙消息
端口:21 到 25
{
"code":0,
"dataList":[
{
"index":0,
"payload":"0201061bffa60202a6fd011000465392deae3f6b83a6d5450c61aaaabbbbbf"
}
],
"msgType":"Pass-through data list"
}
# 下行数据
数据以 JSON 格式提供,经编码后转为二进制数据。用户可发送下列 JSON 数据对设备进行控制。
# 参数设置
端口:10
TX Power
{
"txPower":18,
"msgId":2
}
Data Rate
{
"msgId":4,
"dr":2
}
AUREPORT
{
"msgId":5,
"bleAuReport":"enable"
}
BLE
{
"blePeriod":20,
"msgId":7
}
SCAN
{
"msgId":8,
"bleScan":2
}
SCALE
{
"scale":0,
"msgId":9
}
STEPSOFF
{
"bleStepsOff":3,
"msgId":11
}
BLEOFF
{
"bleBleOff":2,
"msgId":10
}
BUZZER
{
"warnBuzzer":"enable",
"msgId":13
}
VIBRATOR
{
"warnVibrator":"enable",
"msgId":14
}
DISTANCE
{
"warnDistance":4,
"msgId":15
}
PROXIMITY
{
"warnProximity":"enable",
"msgId":12
}
GNSS
{
"gnssPeriod":60,
"msgId":17
}
HEARTBEAT
{
"msgId":18,
"heartBeatPeriod":600
}
TIME
{
"msgId":1,
"time":
{
"hour":20,
"minute":20,
"second":30
}
}
SLEEP
{
"msgId":19,
"sleepy":
{
"degree":1,
"end":6,
"start":21
}
}
THRES
{
"msgId":20,
"thres":2
}
BLEACK
{
"bleAck":0,
"msgId":21
}
多个参数可以同时配置,如:
{
"warnProximity":"disable",
"warnVibrator":"disable",
"bleBleOff":1,
"warnBuzzer":"disable",
"scale":3,
"msgId":22,
"dr":5,
"txPower":20,
"blePeriod":10,
"bleAck":1,
"bleStepsOff":2,
"warnDistance":2,
"gnssPeriod":30,
"bleAlReport":"disable",
"bleScan":1,
"sleepy":
{
"degree":0,
"end":7,
"start":23
},
"heartBeatPeriod":300,
"thres":0
}
# BLE 扫描开始时间
端口:11
{
“time": 12,
"msgId": 22
}
# 控制命令
端口:12
{
"cmd": 2,
"msgId", 23
}
# 确认消息
端口:13
{
"msgId": 24
}
# 配置定位信标 UUID
端口:14
{
"msgId":23,
"uuidList": [
{
"index":0,
"uuid":"22222222222222222222222222222222"
},
{
"index":1,
"uuid":"33333333333333333333333333333333"
},
{
"index":2,
"uuid":"44444444444444444444444444444444"
},
{
"index":3,
"uuid":"55555555555555555555555555555555"
},
{
"index":4,
"uuid":"66666666666666666666666666666666"
}
]
}
# 配置资产信标 UUID
端口:15
{
"msgId":24,
"uuidList":[
{
"index":0,
"uuid":"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
},
{
"index":1,
"uuid":"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"
},
{
"index":2,
"uuid":"cccccccccccccccccccccccccccccccc"
},
{
"index":3,
"uuid":"dddddddddddddddddddddddddddddddd"
},
{
"index":4,
"uuid":"eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee"
}]
}
# 透传蓝牙过滤器
端口:16
{
"filter":"02a6fd0110004653",
"filterStart":7,
"port":21,
"start":15,
"filterLen":8,
"end":30
}
# 配置需确认信标列表
端口:17
{
"number":4,
"beaconList":[
{
"major":8193,
"minor":8192,
"index":0
},
{
"major":8193,
"minor":8193,
"index":1
},
{
"major":12289,
"minor":12288,
"index":2
},
{
"major":12289,
"minor":12289,
"index":3
}]
}