/*
提供如下变量可直接使用:
app : Object, iot 平台需要的字段
lora : Object, lora 平台需要的字段
config : Object, 最终的配置结果放入此字段内即可完成配置
defaultConfig : Object, 默认字段集
*/
const DEVICE_TYPE = {
NODE = 0;
MODULE = 1;
CHIP = 2;
CO = 3;
CO2 = 4;
NO2 = 5;
CH4 = 6;
LPG = 7;
PM2_5 = 8;
PM10 = 9;
GPS = 10;
TEMP = 11;
HUMI = 12;
TRACKER = 13;
chip_s = 14;
chip_e = 15;
chip_l = 16;
tester = 17;
temp_humi_one = 18;
fhsj_ch4 = 19;
fhsj_lpg = 20;
fhsj_elec_fires = 21;
fhsj_smoke = 22;
tk = 23;
concox_tracker = 24;
jf_connection = 25;
siter_lpg = 26;
mantun_fires = 27;
acrel_fires = 28;
taycan_smoke = 29;
bigbang_tracker = 30;
t1 = 31;
acrel_single = 32;
baymax_ch4 = 33;
baymax_lpg = 34;
jetfire_water_soak = 47;
sss_door = 51;
sss_pir = 52;
hiwits_water = 60;
};
const CLASS = { A: 'A', B: 'B', C: 'C', G: 'G', };
const ACTIVATION = { ABP: 'ABP', OTAA: 'OTAA' }
function getClassTypeIndex(classType) { if (classType === CLASS.A) { return 0; } else if (classType === CLASS.B) { return 1; } else if (classType === CLASS.C) { return 2; } else if (classType === CLASS.G) { return 3; } }
function getActivationIndex(activation) { if (activation === ACTIVATION.ABP) { return 0; } else if (activation === ACTIVATION.OTAA) { return 1; } }
// 修改lora默认参数 lora.classType = CLASS.A; lora.activation = ACTIVATION.ABP; lora.adr = false; lora.txPower = 1; lora.maxEIRP = 20; lora.joinAcceptDelay = 5; lora.rx2DataRate = 1;
// lora 配置参数填充 config.loraActivation = getActivationIndex(lora.activation); config.loraClassType = getClassTypeIndex(lora.classType); config.loraEui = new Buffer(lora.EUI, 'hex'); config.loraAppEui = new Buffer(lora.appEUI, 'hex'); config.loraNetId = new Buffer(lora.netId, 'hex'); config.loraAppKey = new Buffer(lora.appKey, 'hex'); config.loraNwkSKey = new Buffer(lora.nwkSKey, 'hex'); config.loraAppSKey = new Buffer(lora.appSKey, 'hex'); config.loraAppNonce = new Buffer(lora.appNonce, 'hex'); config.loraDevNonce = new Buffer(lora.devNonce, 'hex'); config.loraDevAddr = new Buffer(lora.devAddr, 'hex'); config.loraBands = lora.bands; config.loraTxPower = lora.txPower; config.loraDataRate = lora.dataRate; config.loraAdr = lora.adr; config.loraDelay = lora.delay; config.loraJoinDelay = lora.joinAcceptDelay; config.loraRx2DataRate = lora.rx2DataRate; config.loraRx2Frequency = lora.rx2Frequency; config.loraMaxEIRP = lora.maxEIRP; config.loraRx1DRoffset = lora.rx1DRoffset; config.loraNbTrans = lora.nbTrans; config.loraChannelMask = lora.channelMask; config.loraMaxDutyCycle = lora.maxDutyCycle; config.loraSglFrequency = 486300000; config.loraSglDatarate = 3; config.loraSglEnabled = 0;
//12小时一次心跳 app.interval = 43200;
//蓝牙广播间隔400ms app.bleInterval = 400;
config.appDeviceType = DEVICE_TYPE.hiwits_water; config.appSn = new Buffer(defaultConfig.sn, 'hex'); config.appToken = new Buffer(defaultConfig.token); config.appHardwareversion = new Buffer(defaultConfig.hardwareVersion, 'hex'); config.appSecureKey = new Buffer(app.secureKey, 'hex'); config.appPassword = new Buffer(app.password); config.appInterval = app.interval; config.appBleTxPower = app.bleTxPower; config.appBleInterval = app.bleInterval; config.appAlarmReportIntervalAcked = 600; config.appAlarmReportIntervalUnAcked = 60; config.appAlarmReport_nb=3; config.appReportRepeat = 1;
config.app = app; config.lora = lora;
/*
提供如下变量可直接使用:
hexStr : String, 设备上报数据的 hex string 格式
buffer : Buffer, 设备上报的原始数据
customFields : Object, 自定义字段集
defaultFields : Object, 默认字段集,包含:设备电量(battery), 设备状态(normalStatus),设备周期(interval)
battery: Number, 取值范围:0 ~ 100 的整数
normalStatus: Number, 取值范围: -1: 未激活,0: 正常,1 报警,3:超时,4:离线
interval: Number, 设备上报周期,单位:秒
txPower: Number, 功率,单位:dBm
sf: Number, 扩频因子
band: String, 设备频段
protobufStr : String, protobuf 配置内容,即:上一个表单中填写的内容
protobufjs : npm 安装的 package, https://github.com/dcodeIO/protobuf.js
protobufObj : Object, protobuf解析结果,使用默认protobuf配置可使用此变量
root : Object, root = protobufjs.parse(protobufStr,{ keepCase: true }).root
schedule : Object, 传感器最近下行任务内容及taskId,示例: {data:{}, taskId: 123},
taskId: Number, 任务id
data : Object, 任务内容
netWork : Object, 网络信息
fcnt : Number, 上行包帧号
port : Number, 上行端口
请将要传入系统的数据放入指定变量中:
customFields : Object, 自定义字段集(只做存储,主要用来提供设备上一次上报的数据内容)
metaData : Object, 纯透传字段集(只做透传,不存储)
defaultFields : Object, 默认字段集,包含:设备电量(battery), 设备状态(normalStatus),设备周期(interval)
sensorFields : Object, 设备上报传感器数据,示例: { light: 1000, lightAlarmHigh: 3000, lightAlarmLow: 0 },两个阈值为可选参数
schedule : Object, 任务执行是否成功,执行成功则 schedule.status = "success", 执行失败则 schedule.status = "error"
*/
/* frame format : FF01(2 Bytes) + HOSTSN(8 Bytes) + DATA
data format: typedef struct { uint8_t device_type; uint8_t version; uint8_t data_type;
uint16_t task_id;
uint8_t cmd_ret;
uint16_t battery;
uint16_t interval;
uint8_t tx_power: 4;
uint8_t datarate: 4;
uint8_t door: 1;
uint8_t installed: 1;
uint8_t reserved0: 6;
uint16_t major;
uint16_t minor;
int8_t mrssi;
} attribute((packed )) encode_data_normal_t;
typedef struct { uint8_t device_type; uint8_t version; uint8_t data_type;
uint8_t door: 1;
uint8_t installed: 1;
uint8_t reserved0: 6;
} attribute((packed )) encode_data_alarm_t; */
const META_DATA_ERROR_DEVICE_NOT_INSTALLED = 5020001; const META_DATA_ERROR_LOW_BATTERY_LEVEL = 5040001;
const ENCODE_DATA_TYPE_NORMAL = 0x01; const ENCODE_DATA_TYPE_ALARM = 0x02;
function destructuring (buffer, define) { return define.reduce(([res, dataIndex], item) => { return [ Object.assign(res, {[item.name]: item.value(buffer, dataIndex)}), dataIndex + item.size, ]; }, [{}, 0]); }
function mvolt2level(mvolts){ let batt_level = 0; if(mvolts >= 3000){ batt_level = 100; } else if(mvolts > 2950) { batt_level = 100 - ((3000 - mvolts) * 20) / 50; } else if(mvolts > 2900) { batt_level = 80 - ((2950 - mvolts) * 40) / 50; } else if(mvolts > 2850) { batt_level = 40 - ((2900 - mvolts) * 30) / 50; } else if(mvolts > 2800) { batt_level = 10 - ((2850 - mvolts) * 9) / 50; } else { batt_level = 1; } batt_level = Number(batt_level.toFixed(1)); return batt_level; }
let define_normal = [ {size: 2, name: 'taskId', value: (buffer, dataIndex) => buffer.readUInt16LE(dataIndex) }, {size: 1, name: 'cmdRet', value: (buffer, dataIndex) => buffer.readUInt8(dataIndex) }, {size: 2, name: 'batteryV', value: (buffer, dataIndex) => buffer.readUInt16LE(dataIndex) }, {size: 2, name: 'interval', value: (buffer, dataIndex) => buffer.readUInt16LE(dataIndex) }, {size: 0, name: 'datarate', value: (buffer, dataIndex) => buffer.readUInt8(dataIndex) >> 4 }, {size: 1, name: 'txPower', value: (buffer, dataIndex) => buffer.readUInt8(dataIndex) & 0x0F },
{size: 0, name: 'door', value: (buffer, dataIndex) => buffer.readUInt8(dataIndex) & 0x01 }, {size: 0, name: 'installed', value: (buffer, dataIndex) => (buffer.readUInt8(dataIndex) >> 1) & 0x01 }, {size: 0, name: 'quiet', value: (buffer, dataIndex) => (buffer.readUInt8(dataIndex) >> 2) & 0x01 }, {size: 1, name: 'quietMode', value: (buffer, dataIndex) => (buffer.readUInt8(dataIndex) >> 3) & 0x01 },
{size: 1, name: 'tempError', value: (buffer, dataIndex) => buffer.readUInt8(dataIndex) & 0x01 },
{size: 2, name: 'major', value: (buffer, dataIndex) => buffer.readUInt16LE(dataIndex) }, {size: 2, name: 'minor', value: (buffer, dataIndex) => buffer.readUInt16LE(dataIndex) }, {size: 1, name: 'mrssi', value: (buffer, dataIndex) => buffer.readInt8(dataIndex) }, ];
let define_normal_v11 = [ {size: 2, name: 'taskId', value: (buffer, dataIndex) => buffer.readUInt16LE(dataIndex) }, {size: 1, name: 'cmdRet', value: (buffer, dataIndex) => buffer.readUInt8(dataIndex) }, {size: 2, name: 'batteryV', value: (buffer, dataIndex) => buffer.readUInt16LE(dataIndex) }, {size: 2, name: 'interval', value: (buffer, dataIndex) => buffer.readUInt16LE(dataIndex) }, {size: 0, name: 'datarate', value: (buffer, dataIndex) => buffer.readUInt8(dataIndex) >> 4 }, {size: 1, name: 'txPower', value: (buffer, dataIndex) => buffer.readUInt8(dataIndex) & 0x0F },
{size: 0, name: 'door', value: (buffer, dataIndex) => buffer.readUInt8(dataIndex) & 0x01 }, {size: 0, name: 'installed', value: (buffer, dataIndex) => (buffer.readUInt8(dataIndex) >> 1) & 0x01 }, {size: 0, name: 'quiet', value: (buffer, dataIndex) => (buffer.readUInt8(dataIndex) >> 2) & 0x01 }, {size: 1, name: 'quietMode', value: (buffer, dataIndex) => (buffer.readUInt8(dataIndex) >> 3) & 0x01 },
{size: 1, name: 'tempError', value: (buffer, dataIndex) => buffer.readUInt8(dataIndex) & 0x01 },
{size: 2, name: 'major', value: (buffer, dataIndex) => buffer.readUInt16LE(dataIndex) }, {size: 2, name: 'minor', value: (buffer, dataIndex) => buffer.readUInt16LE(dataIndex) }, {size: 1, name: 'mrssi', value: (buffer, dataIndex) => buffer.readInt8(dataIndex) },
{size: 2, name: 'temp', value: (buffer, dataIndex) => buffer.readInt16LE(dataIndex)/10.0 }, ];
let define_normal_v14 = [ {size: 2, name: 'taskId', value: (buffer, dataIndex) => buffer.readUInt16LE(dataIndex) }, {size: 1, name: 'cmdRet', value: (buffer, dataIndex) => buffer.readUInt8(dataIndex) }, {size: 2, name: 'batteryV', value: (buffer, dataIndex) => buffer.readUInt16LE(dataIndex) }, {size: 2, name: 'interval', value: (buffer, dataIndex) => buffer.readUInt16LE(dataIndex) }, {size: 0, name: 'datarate', value: (buffer, dataIndex) => buffer.readUInt8(dataIndex) >> 4 }, {size: 1, name: 'txPower', value: (buffer, dataIndex) => buffer.readUInt8(dataIndex) & 0x0F },
{size: 0, name: 'door', value: (buffer, dataIndex) => buffer.readUInt8(dataIndex) & 0x01 }, {size: 0, name: 'installed', value: (buffer, dataIndex) => (buffer.readUInt8(dataIndex) >> 1) & 0x01 }, {size: 0, name: 'quiet', value: (buffer, dataIndex) => (buffer.readUInt8(dataIndex) >> 2) & 0x01 }, {size: 1, name: 'quietMode', value: (buffer, dataIndex) => (buffer.readUInt8(dataIndex) >> 3) & 0x01 },
{size: 1, name: 'tempError', value: (buffer, dataIndex) => buffer.readUInt8(dataIndex) & 0x01 },
{size: 2, name: 'major', value: (buffer, dataIndex) => buffer.readUInt16LE(dataIndex) }, {size: 2, name: 'minor', value: (buffer, dataIndex) => buffer.readUInt16LE(dataIndex) }, {size: 1, name: 'mrssi', value: (buffer, dataIndex) => buffer.readInt8(dataIndex) },
{size: 2, name: 'temp', value: (buffer, dataIndex) => buffer.readInt16LE(dataIndex)/10.0 }, {size: 1, name: 'binded', value: (buffer, dataIndex) => buffer.readUInt8(dataIndex) }, ];
let define_normal_old = [ {size: 2, name: 'taskId', value: (buffer, dataIndex) => buffer.readUInt16LE(dataIndex) }, {size: 1, name: 'cmdRet', value: (buffer, dataIndex) => buffer.readUInt8(dataIndex) }, {size: 2, name: 'batteryV', value: (buffer, dataIndex) => buffer.readUInt16LE(dataIndex) }, {size: 2, name: 'interval', value: (buffer, dataIndex) => buffer.readUInt16LE(dataIndex) }, {size: 0, name: 'datarate', value: (buffer, dataIndex) => buffer.readUInt8(dataIndex) >> 4 }, {size: 1, name: 'txPower', value: (buffer, dataIndex) => buffer.readUInt8(dataIndex) & 0x0F },
{size: 0, name: 'door', value: (buffer, dataIndex) => buffer.readUInt8(dataIndex) & 0x01 }, {size: 0, name: 'installed', value: (buffer, dataIndex) => (buffer.readUInt8(dataIndex) >> 1) & 0x01 }, {size: 0, name: 'quiet', value: (buffer, dataIndex) => (buffer.readUInt8(dataIndex) >> 2) & 0x01 }, {size: 1, name: 'quietMode', value: (buffer, dataIndex) => (buffer.readUInt8(dataIndex) >> 3) & 0x01 },
{size: 2, name: 'major', value: (buffer, dataIndex) => buffer.readUInt16LE(dataIndex) }, {size: 2, name: 'minor', value: (buffer, dataIndex) => buffer.readUInt16LE(dataIndex) }, {size: 1, name: 'mrssi', value: (buffer, dataIndex) => buffer.readInt8(dataIndex) }, ];
let define_alarm = [
{size: 0, name: 'door', value: (buffer, dataIndex) => buffer.readUInt8(dataIndex) & 0x01 },
{size: 1, name: 'installed', value: (buffer, dataIndex) => (buffer.readUInt8(dataIndex) >> 1) & 0x01 },
];
let headerVersion = buffer.readUInt16BE(0); let headerObj = {};
if(headerVersion == 0xFF01){ headerObj = { hostsn: buffer.slice(2, 10).toString('hex').toUpperCase(), };
data = buffer.slice(10); } else if(headerVersion == 0xFF02) {
headerObj = { hostsn: buffer.slice(2, 10).toString('hex').toUpperCase(), fcnt: buffer.readUInt16LE(10), rssi: buffer.readInt16LE(12), snr: buffer.readInt8(14), netMode: "sss", };
data = buffer.slice(15);
} else if(headerVersion == 0xFF03) {
// format: FF03 + headerLength(2B) + headerData + nodeData
let headerLength = buffer.readUInt16LE(2);
let Msg = protobufParser.root.lookupType("MsgHeader"); let message = Msg.decode(buffer.slice(4, 4 + headerLength)); let obj = Msg.toObject(message);
headerObj = { hostsn: obj.hostsn.toString('hex').toUpperCase(), fcnt: obj.fcnt, rssi: obj.rssi, snr: obj.snr, armed: obj.armed, armDelay: obj.armDelay, demoMode: obj.demoMode, errorInsulateSwitch: obj.errorInsulateSwitch, armDelayStatus: obj.armDelayStatus, netMode: "sss", };
data = buffer.slice(headerLength + 4);
} else { headerObj = { netMode: "alpha", fcnt: customFields.fcnt, rssi: customFields.rssi, snr: customFields.snr, };
data = buffer; }
let device_type = data[0]; let version = data[1]; let data_type = data[2];
let dataObj = {};
if(version >= 0x14){ [dataObj,] = destructuring(data.slice(3), define_normal_v14); }else if(version >= 0x11){ [dataObj,] = destructuring(data.slice(3), define_normal_v11); } else if(version === 0x10){ if(data_type === ENCODE_DATA_TYPE_NORMAL){ if(data.length == 17){ [dataObj,] = destructuring(data.slice(3), define_normal_old); } else { [dataObj,] = destructuring(data.slice(3), define_normal); } } }
sensorFields.lowBatt = (mvolt2level(dataObj.batteryV) < 10) ? 1 : 0; sensorFields.binded = dataObj.binded;
Object.assign(dataObj, headerObj);
dataObj.armDelayStatus = dataObj.armDelayStatus || 0; dataObj.errorInsulateSwitch = dataObj.errorInsulateSwitch || 0;
Object.assign(sensorFields, dataObj); Object.assign(customFields, sensorFields);
if(typeof dataObj.taskId == 'number'){ schedule.taskId = dataObj.taskId; if(dataObj.cmdRet === 0){ schedule.status = 'success'; } else{ schedule.status = 'error'; } }
defaultFields.battery = mvolt2level(dataObj.batteryV); defaultFields.interval = dataObj.interval; defaultFields.txPower = 20 - dataObj.txPower * 2; defaultFields.sf = 12 - dataObj.datarate;
metaData = { sensor: { door: Number(dataObj.door === 0), }, threshold: { }, thresholdApply: 0, alarm: { }, error: { error_type: [], }, battery: defaultFields.battery, interval: dataObj.interval, demoMode: dataObj.demoMode, errorInsulateSwitch: dataObj.errorInsulateSwitch, other: { quietMode: dataObj.quietMode, netMode: dataObj.netMode } };
if(dataObj.errorInsulateSwitch === 0){ if(dataObj.battery < 10){ metaData.error.error_type.push(META_DATA_ERROR_LOW_BATTERY_LEVEL); }
if(dataObj.installed === 0){ metaData.error.error_type.push(META_DATA_ERROR_DEVICE_NOT_INSTALLED); } }
1 if [ "$color_prompt" = yes ]; then
82 export CLICOLOR=1
83 export LSCOLORS=ExFxBxDxCxegedabagacad
84 PS1="[\033[33;1m]\w[\033[m]$git_branch[\033[0m] $ "
85 else
86 PS1='${debian_chroot:+(