Skip to content

Latest commit

 

History

History
492 lines (415 loc) · 17.7 KB

草稿.md

File metadata and controls

492 lines (415 loc) · 17.7 KB

/*
提供如下变量可直接使用:
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:+($debian_chroot)}\w$ ' 87 fi 88 unset color_prompt force_color_prompt 89 90 # If this is an xterm set the title to user@host:dir 91 case "$TERM" in 92 xterm*|rxvt*) 93 PS1="[\e]0;${debian_chroot:+($debian_chroot)}\w\a]$PS1" 94 ;; 95 *)