技术服务中心

概述

本文主要介绍如何将星纵物联LoRaWAN®网关和终端节点连接到LinkWAN平台。目前平台只支持CN470频段,如下以星纵物联UG65网关和EM300传感器(LinkWAN版本)为例。

准备

  • 星纵物联LoRaWAN®网关
  • LoRaWAN®终端节点(LinkWAN版)

步骤

1. 网关配置

1.1 获取密钥文件

  1. 用户提供网关序列号给设备厂商,厂商使用网关密钥管理工具生成配置文件;
  2. 用户获取配置压缩文件:(该文件包含了GwEUI和PIN Code两个参数,该参数在平台添加网关时需要使用)。

1.2 网关启用LinkWAN

进入网关配置页面“Packet Forwarder > 常规”,根据下图,配置LinkWAN连接,需要在“导入配置文件”位置导入上一步生成的配置文件。

2. LinkWAN平台配置

登录LinkWAN物联网络管理平台:https://signin.aliyun.com。(可自助申请登录账号)

  1. 登录控制台,选择“物联网络管理平台> 网络管理 > 网关管理 > 添加网关”

  1. 输入配置文件中的GwEUI和PIN Code参数及对应信息,如下图所示。

  1. “物联网络管理平台> 网络管理 > 网关管理”,查看网关状态为在线。

  1. 点击查看,可以看到该网关的上下行数据,以及无效数据。(当无法收到节点数据时,可以查看无效数据。一般节点的JoinEUI或者DevEUI不合法等错误会打印在无效数据中。)

LinkWAN相关程序说明如下:

3. 传感器连接LinkWAN

3.1 创建凭证和密钥

登录物联网络管理平台,先创建凭证和申请密钥。凭证用于后续创建产品使用,密钥用于设备烧录和添加设备时使用。

  1. 进入“网络管理> 入网开通 > 添加专用凭证”授权给自己。

  1. 进入“密钥管理> 申请密钥 > 申请购买密钥”。注意:一个密钥配置文件1元。

3.2 新建产品

切换到物联网平台,先创建一个产品,如果没有凭证需要先创建凭证,并授权(选择授权给自己)。

3.3 添加设备

  1. 进入“设备管理> 设备 > 添加设备”,输入节点的DevEUI和PIN Code,这两个参数在平台成功购买密钥后,可以从下载的密钥文件EXCEL表格中获取。

  1. 查看设备启用状态,刚添加完设备为未激活状态,设备成功上线后变为在线。

3.4 创建模型

  1. 进入物联网平台设备管理> 产品 > 产品详情”,选择对应产品,为设备创建物理模型。

  1. 添加自定义功能。

注意:标识符和数据类型应该遵循Decoder内的定义进行填写,否则会解析不成功。

A、EM300设备自定义功能参考如下:

B、UC1152设备自定义功能参考如下:

3.5 发布上线

3.6 设置数据解析

  1. 选择数据解析,将数据解析代码拷贝进去,具体代码见4.7(EM300)或4.8(UC1152)。

  1. 到设备物理模型下,可以查看设备的上报数据。

3.7 EM300数据解析代码如下

/**
* 将设备自定义topic数据转换为json格式数据, 设备上报数据到物联网平台时调用
* 入参:topic   string 设备上报消息的topic
* 入参:rawData byte[]数组 不能为空
* 出参:jsonObj JSON对象 不能为空
*/
function array(length) {
    return new Array(length).fill(null);
}
function fixFloat(float, fractionDigits) {
    fractionDigits = fractionDigits || 1;
    var value = typeof float === "string" ? parseFloat(float) : float;
    return parseFloat(value.toFixed(fractionDigits));
}
function readUInt8(bytes) {
    return (bytes & 0xFF);
}
function readInt8(bytes) {
    var ref = readUInt8(bytes);
    return (ref > 0x7F) ? ref - 0x100 : ref;
}
function readUInt16LE(bytes) {
    var value = (bytes[1] << 8) + bytes[0];
    return (value & 0xFFFF);
}
function readInt16LE(bytes) {
    var ref = readUInt16LE(bytes);
    return (ref > 0x7FFF) ? ref - 0x10000 : ref;
}
function readUInt32LE(bytes) {
    var value = (bytes[3] << 24) + (bytes[2] << 16) + (bytes[1] << 8) + bytes[0];
    return (value & 0xFFFFFFFF);
}
function readInt32LE(bytes) {
    var ref = readUInt32LE(bytes);
    return (ref > 0x7FFFFFFF) ? ref - 0x100000000 : ref;
}
function readFloatLE(bytes) {
    var bits = bytes[3] << 24 | bytes[2] << 16 | bytes[1] << 8 | bytes[0];
    var sign = (bits >>> 31 === 0) ? 1.0 : -1.0;
    var e = bits >>> 23 & 0xff;
    var m = (e === 0) ? (bits & 0x7fffff) << 1 : (bits & 0x7fffff) | 0x800000;
    var f = sign * m * Math.pow(2, e - 150);
    return f;
}
function BufferReader(buffer) {
    this.buffer = buffer;
    this.offset = 0;
}
BufferReader.prototype.getBuffer = function () {
    return this.buffer;
}
BufferReader.prototype.byteAt = function (index) {
    return this.buffer[index];
}
BufferReader.prototype.firstByte = function () {
    return this.buffer[0];
}
BufferReader.prototype.lastByte = function () {
    return this.buffer[this.buffer.length - 1];
}
BufferReader.prototype.hasNextByte = function () {
    return this.buffer.length > this.offset;
}
BufferReader.prototype.moveOffset = function (plus) {
    this.offset += plus;
}
BufferReader.prototype.setOffset = function (offset) {
    this.offset = offset;
}
BufferReader.prototype.getOffset = function () {
    return this.offset;
}
BufferReader.prototype.readBit = function (bits) {
    var result = [];
    var binary = this.readUInt8();
    for (var idx = 0; idx < bits; idx++) {
        result[idx] = (binary >> idx) & 1;
    }
    return result;
}
BufferReader.prototype.readUInt8 = function () {
    var result = readUInt8(this.buffer.slice(this.offset, this.offset + 1));
    this.offset += 1;
    return result;
}
BufferReader.prototype.readInt16LE = function () {
    var result = readInt16LE(this.buffer.slice(this.offset, this.offset + 2));
    this.offset += 2;
    return result;
}
BufferReader.prototype.readUInt16LE = function () {
    var result = readUInt16LE(this.buffer.slice(this.offset, this.offset + 2));
    this.offset += 2;
    return result;
}
BufferReader.prototype.readInt32LE = function () {
    var result = readInt32LE(this.buffer.slice(this.offset, this.offset + 4));
    this.offset += 4;
    return result;
}
BufferReader.prototype.readUInt32LE = function () {
    var result = readUInt32LE(this.buffer.slice(this.offset, this.offset + 4));
    this.offset += 4;
    return result;
}
BufferReader.prototype.readFloatLE = function () {
    var result = readFloatLE(this.buffer.slice(this.offset, this.offset + 4));
    this.offset += 4;
    return result;
}
BufferReader.prototype.readString = function (size) {
    var result = this.buffer.slice(this.offset, this.offset + size);
    this.offset += size;
    return result.toString().replace(/\0/g, "");
}
BufferReader.prototype.readHex = function (length) {
    var hex = this.buffer.slice(this.offset, this.offset + length).toString(16);
    this.offset += length;
    return hex;
}
BufferReader.prototype.readBuffer = function (length) {
    var buffer = this.buffer.slice(this.offset, this.offset + length);
    this.offset += length;
    return buffer;
}
var DATA_TYPE = {
    Int8: "Int8",
    UInt8: "UInt8",
    Int16: "Int16LE",
    UInt16: "UInt16LE",
    Int32LE: "Int32LE",
    UInt32LE: "UInt32LE",
};
var IPSO_PARSER = {
    0: defCommonChannelParser("digitalInput", DATA_TYPE.UInt8),
    1: defCommonChannelParser("digitalOutput", DATA_TYPE.UInt8),
    3: defCommonChannelParser("analogOutput", DATA_TYPE.Int16, undefined, function (value) { return fixFloat(value * 0.01, 2) }),
    101: defCommonChannelParser("illumianceSensor", DATA_TYPE.UInt16, "lux"),
    102: defCommonChannelParser("presenceSensor", DATA_TYPE.UInt8),
    103: defCommonChannelParser("temperatureSensor", DATA_TYPE.Int16, "¡ãC", function (value) { return fixFloat(value * 0.1) }),
    104: defCommonChannelParser("humiditySensor", DATA_TYPE.UInt8, "%", function (value) { return fixFloat(value * 0.5) }),
    106: defCommonChannelParser("actuation", DATA_TYPE.UInt16, ""),
    115: defCommonChannelParser("barometerPressure", DATA_TYPE.UInt16, "kPa", function (value) { return fixFloat(value * 0.1) }),
    116: defCommonChannelParser("voltage", DATA_TYPE.UInt16, "V", function (value) { return fixFloat(value * 0.01, 2) }),
    117: defCommonChannelParser("current", DATA_TYPE.UInt8, "%"),
    119: defCommonChannelParser("depth", DATA_TYPE.UInt16, "cm", function (value) { return value }),
    123: defCommonChannelParser("pressure", DATA_TYPE.UInt16, "", function (value) { return fixFloat(value * 0.1) }),
    124: defCommonChannelParser("loudness", DATA_TYPE.UInt16, "dB", function (value) { return fixFloat(value * 0.1) }),
    125: defCommonChannelParser("concentration", DATA_TYPE.UInt16, ""),
    128: defCommonChannelParser("power", DATA_TYPE.UInt16, "W", function (value) { return fixFloat(value * 0.01, 2) }),
    130: defCommonChannelParser("distance", DATA_TYPE.UInt16, "m", function (value) { return fixFloat(value / 1000, 3) }),
    146: defCommonChannelParser("par", DATA_TYPE.UInt16, "¦Ìmol¡¤m?2¡¤s?1", function (value) { return fixFloat(value * 0.1) }),
    200: defCommonChannelParser("counter", DATA_TYPE.UInt32LE),
};
// analog input
IPSO_PARSER[2] = function (channel) {
    return function (reader, data) {
        data[channel] = {
            channel: channel,
            type: "analogInput",
            value: {
                ccy: fixFloat(reader.readInt16LE() * 0.01, 2),
                min: fixFloat(reader.readInt16LE() * 0.01, 2),
                max: fixFloat(reader.readInt16LE() * 0.01, 2),
                avg: fixFloat(reader.readInt16LE() * 0.01, 2),
            },
        };
    }
};
var URSA_PARSER = {
    1: defConfigDataParser("version", DATA_TYPE.UInt8, function (value) { return value.toString() }),
    2: defConfigDataParser("interval", DATA_TYPE.UInt16),
    3: defConfigDataParser("period", DATA_TYPE.UInt16),
    4: defConfigDataParser("response", DATA_TYPE.UInt8),
    5: parseLoRaChanMask,
    6: skip(9, "alarmConfig"),
    7: defConfigDataParser("debugLevel", DATA_TYPE.UInt8),
    8: defSNParser(6),
    9: parseVersion("hardware"),
    10: parseVersion("firmware"),
    11: defConfigDataParser("powerOn", DATA_TYPE.UInt8, function (value) { return value > 0 }),
    12: defConfigDataParser("powerOff", DATA_TYPE.UInt8, function (value) { return value > 0 }),
    13: parseAlarm,
    14: parseChannels,
    15: defConfigDataParser("class", DATA_TYPE.UInt8),
    16: defConfigDataParser("reboot", DATA_TYPE.UInt8),
    17: defConfigDataParser("timestamp", DATA_TYPE.UInt16),
    18: parseText,
    19: defConfigDataParser("intelligenceReport", DATA_TYPE.UInt8),
    20: parseConversion,
    21: parseCollectFailedChannelIds,
    22: defSNParser(8),
};
function convertBufferToObject(buffer) {
    var reader = new BufferReader(buffer);
    var data = { config: {} };
    while (reader.hasNextByte()) {
        var channel = reader.readUInt8();
        var type = reader.readUInt8();
        var parser = getReadParser(channel, type);
        if (parser) {
            parser.parse(reader, data);
        }
    }
    return data;
}
function getReadParser(channel, type) {
    if (channel === 255) {
        return { parse: URSA_PARSER[type] };
    } else {
        return { parse: IPSO_PARSER[type](channel) };
    }
}
function defCommonChannelParser(type, dataType, unit, converter) {
    return function (channel) {
        return function (reader, data) {
            var value = reader["read" + dataType]();
            data[channel] = {
                channel: channel,
                type: type,
                unit: unit,
                value: (converter || function (value) { return value })(value),
            };
        }
    };
}
function defConfigDataParser(property, dataType, converter) {
    return function (reader, data) {
        var value = reader["read" + dataType]();
        if (!data.config) {
            data.config = {};
        }
        data.config[property] = (converter || function (value) { return value })(value);
    };
}
function skip(length, property) {
    return function (reader, data) {
        reader.moveOffset(length);
    };
}
function defSNParser(length) {
    return function (reader, data) {
        data.config.sn = reader.readHex(length);
    };
}
function parseLoRaChanMask(reader, data) {
    var id = reader.readUInt8();
    var value = reader.readUInt16LE();
    data.config.loRaChanMask = { id: id, value: value };
}
function parseText(reader, data) {
    var length = reader.readUInt8();
    data.config.text = reader.readString(length);
}
function parseAlarm(reader, data) {
    var MODE = ["DISABLE", "BELOW", "ABOVE", "WITHIN", "BELOW_OR_ABOVE"];
    var idAndMode = reader.readUInt8();
    var id = (idAndMode & 56) >>> 3; // & 0x00111000 >> 3
    var mode = MODE[idAndMode & 7]; // & 0x00000111
    var min = reader.readInt16LE() / 10;
    var max = reader.readInt16LE() / 10;
    var current = reader.readInt16LE() / 10;
    var lessThan = min;
    var greaterThan = max;
    if (mode === "WITHIN") {
        lessThan = max;
        greaterThan = min;
    } else if (mode === "BELOW_OR_ABOVE") {
        mode = current < lessThan ? "BELOW" : "ABOVE";
    }
    data.config.alarm = { id: id, mode: mode, greaterThan: greaterThan, lessThan: lessThan, current: current };
}
function parseConversion(reader, data) {
    var value = reader.readUInt8();
    var index = (value & 240) >>> 4; // & 11110000 >> 4
    var type = (value & 15) === 0 ? "mA" : "V"; // & 00001111
    if (!data.config.conversion) {
        data.config.conversion = [];
    }
    data.config.conversion.push({ index: index, type: type });
}
function parseVersion(property) {
    return function (reader, data) {
        var mainVer = reader.readUInt8();
        var subVer = reader.readUInt8();
        var realMainVer = mainVer % 16 + Math.floor(mainVer / 16) * 10;
        var realSubVer = subVer % 16 === 0 && property === "hardware"
            ? Math.floor(subVer / 16)
            : subVer % 16 + Math.floor(subVer / 16) * 10;
        if (property === "hardware") {
            data.config.hardware = "v" + realMainVer + "." + realSubVer;
        } else if (property === "firmware") {
            data.config.firmware = "v" + realMainVer + "." + realSubVer;
        }
    };
}
var CHANNEL_TYPE = ["REG_COIL", "REG_DISCRETE", "REG_INPUT", "REG_HOLD_INT16", "REG_HOLD_INT32",
    "REG_HOLD_FLOAT", "REG_INPUT_INT32", "REG_INPUT_FLOAT",
    "REG_INPUT_INT32_AB", "REG_INPUT_INT32_CD", "REG_HOLD_INT32_AB", "REG_HOLD_INT32_CD"];
function parseChannels(reader, data) {
    var channelId = reader.readUInt8();
    var ptype = reader.readUInt8();
    var dataType = CHANNEL_TYPE[ptype & 7];
    var dataLength = ptype >> 3;
    var offset = reader.getOffset();
    var raw = "";
    var value = 0;
    switch (dataType) {
        case "REG_COIL":
        case "REG_DISCRETE":
            value = reader.readUInt8();
            reader.setOffset(offset);
            raw = reader.readHex(1);
            break;
        case "REG_INPUT":
        case "REG_HOLD_INT16":
        case "REG_INPUT_INT32_AB":
        case "REG_INPUT_INT32_CD":
        case "REG_HOLD_INT32_AB":
        case "REG_HOLD_INT32_CD":
            value = reader.readUInt16LE();
            reader.setOffset(offset);
            raw = reader.readHex(2);
            break;
        case "REG_HOLD_INT32":
        case "REG_INPUT_INT32":
            value = reader.readUInt32LE();
            reader.setOffset(offset);
            raw = reader.readHex(4);
            break;
        case "REG_HOLD_FLOAT":
        case "REG_INPUT_FLOAT":
            value = fixFloat(reader.readFloatLE(), 4);
            reader.setOffset(offset);
            raw = reader.readHex(4);
            break;
    }
    if (!data.config.channelData) {
        data.config.channelData = array(8);
    }
    data.config.channelData[channelId] = {
        channelId: channelId,
        dataType: dataType,
        dataLength: dataLength,
        value: value,
        raw: raw,
    };
}
function writeUInt8(bytes, value, index) {
    bytes[index] = value;
}
function writeUInt16LE(bytes, value, index) {
    var low = value & 0xFF;
    var high = (value & 0xFF00) >> 8;
    bytes[index] = low;
    bytes[index + 1] = high;
}
function safeValue(value, defaultValue) {
    if (value === null || value === undefined) {
        return defaultValue;
    }
    value = Number(value);
    if (value === NaN) {
        return defaultValue;
    }
    return value;
}
function writeAlarm(alarmConfig) {
    var MODE = { DISABLE: 0, BELOW: 1, ABOVE: 2, WITHIN: 3, BELOW_OR_ABOVE: 4 };
    const bytes = new Uint8Array(11);
    writeUInt8(bytes, 255, 0);
    writeUInt8(bytes, 6, 1);
    var idAndMode = ((alarmConfig.id || 0) << 3) + (MODE[alarmConfig.mode || "DISABLE"]);
    writeUInt8(bytes, idAndMode, 2);
    writeUInt8(bytes)
    var upper = safeValue(alarmConfig.upper, 9999);
    var lower = safeValue(alarmConfig.lower, 9999);
    if ((alarmConfig.mode === "BELOW_OR_ABOVE" || alarmConfig.mode === "WITHIN") && upper > lower) {
        // min和max都有值时min一定小于max
        [upper, lower] = [lower, upper];
    }
    writeUInt16LE(bytes, upper, 3); // min
    writeUInt16LE(bytes, lower, 5); // max
    writeUInt16LE(bytes, 0, 7);
    writeUInt16LE(bytes, 0, 9);
    return bytes;
}
function parseCollectFailedChannelIds(reader, data) {
    var ids = data.config.collectFailedChannelIds || [];
    ids.push(reader.readUInt8());
    data.config.collectFailedChannelIds = ids;
}
function Decoder(bytes, port) {
    return convertBufferToObject(bytes);
}
function bufferToBytes(buffer) {
    var bytes = [];
    buffer.forEach(function (v) { bytes.push(v) });
    return bytes;
}
function rawDataToProtocol(bytes) {
    var data = convertBufferToObject(new Uint8Array(bytes));
    var result = {};
    //  {"method":"thing.event.property.post", "id":"12345", "params":{"Temperature":1,"Humidity":2}, "version":"1.1"}
    result.method = "thing.event.property.post";
    result.version = "1.1";
    result.id = "1";
    result.params = {};
    if (data[3]) {
        result.params.temperature = data[3].value;
    }
    if (data[4]) {
        result.params.humiditySensor = data[4].value;
    }
    if (data[6]) {
        result.params.digitalInput = data[6].value;
    }
    if (data[5]) {
        result.params.digitalInput1 = data[5].value;
    }
    if (data[1]) {
        result.params.BatteryLevel = data[1].value;
    }
    return result;
}
function protocolToRawData(json) {
    // {
    //     "method": "thing.service.SetTempHumiThreshold",
    //     "id": "12345",
    //     "version": "1.1",
    //     "params": {
    //         "MaxTemp": 50,
    //         "MinTemp": 8,
    //         "MaxHumi": 90,
    //         "MinHumi": 10
    //     }
    // }
    var header = [0x5D, 0x01, 0x00];
    var params = json.params;
    var lower = params.maxtemp;
    var upper = params.mintemp;
    var mode;
    var isUpperExists = !!upper || upper === 0;
    var isLowerExists = !!lower || lower === 0;
    if (isUpperExists && !isLowerExists) {
        mode = "BELOW";
    } else if (!isUpperExists && isLowerExists) {
        mode = "ABOVE";
    } else if (!isUpperExists && !isLowerExists) {
        return new Uint8Array([0x5d, 0x01, 0x00, 0xff, 0x06, 0x11, 0x14, 0x00, 0x32, 0x00, 0x3c, 0x00, 0x00, 0x00]);
    }else if (lower <= upper) {
        mode = "WITHIN";
    } else if (lower > upper) {
        mode = "BELOW_OR_ABOVE";
    }
    var payload = writeAlarm({id: 1, mode, upper, lower});
    var arr = [];
    payload.forEach(function (v, i) {
        arr[i] = v;
    })
    return new Uint8Array(header.concat(arr));
}
function transformPayload() {
}

 

3.8 UC1152数据解析代码如下

/**
 * 将设备自定义topic数据转换为json格式数据, 设备上报数据到物联网平台时调用
 * 入参:topic   string 设备上报消息的topic
 * 入参:rawData byte[]数组 不能为空
 * 出参:jsonObj JSON对象 不能为空
 */
function transformPayload(topic, rawData) {
  var data = Decoder(rawData, 85);
    
    var jsonObj = {};
    jsonObj.method=topic;
    jsonObj.version="1.0";
    jsonObj.id="1";
    jsonObj.params=data;
    
    return jsonObj;
   
}
/**
 * 将设备的自定义格式数据转换为Alink协议的数据,设备上报数据到物联网平台时调用
 * 入参:rawData byte[]数组 不能为空
 * 出参:jsonObj Alink JSON对象 不能为空
 */
function rawDataToProtocol(rawData) {
    var data = Decoder(rawData, 85);
    
    var jsonObj = {};
    jsonObj.method="thing.event.property.post";
    jsonObj.version="1.0";
    jsonObj.id="1";
    jsonObj.params=data;
    
    return jsonObj;
}
/**
 *  将Alink协议的数据转换为设备能识别的格式数据,物联网平台给设备下发数据时调用
 *  入参:jsonObj Alink JSON对象  不能为空
 *  出参:rawData byte[]数组      不能为空
 *
 */
function protocolToRawData(jsonObj) {
    var rawdata = [];
    return rawdata;
}
function Decoder(bytes, port) {
    var decoded = {};
    for (i = 0; i < bytes.length;) {
        var channel_id = bytes[i++];
        var channel_type = bytes[i++];
        // Digital Input 1
         if (channel_id === 0x01 && channel_type !== 0xc8) {
            decoded.din1 = bytes[i] === 0 ? "off" : "on";
            i += 1;
        }
        // Digital Input 2
        else if (channel_id === 0x02 && channel_type !== 0xc8) {
            decoded.din2 = bytes[i] === 0 ? "off" : "on";
            i += 1;
        }
        // Pulse Counter 1
        else if (channel_id === 0x01 && channel_type === 0xc8) {
            decoded.counter1 = readUInt32LE(bytes.slice(i, i + 4));
            i += 4;
        }
        // Pulse Counter 1
        else if (channel_id === 0x02 && channel_type === 0xc8) {
            decoded.counter2 = readUInt32LE(bytes.slice(i, i + 4));
            i += 4;
        }
// Digital Output 1
        else if (channel_id === 0x09) {
            decoded.dout1 = bytes[i] === 0 ? "off" : "on";
            i += 1;
        }
        // Digital Output 2
        else if (channel_id === 0x0a) {
            decoded.dout2 = bytes[i] === 0 ? "off" : "on";
            i += 1;
        }
        // ADC 1
        else if (channel_id === 0x11) {
            decoded.adc1 = {};
            decoded.adc1.cur = readInt16LE(bytes.slice(i, i + 2)) / 100;
            decoded.adc1.min = readInt16LE(bytes.slice(i + 2, i + 4)) / 100;
            decoded.adc1.max = readInt16LE(bytes.slice(i + 4, i + 6)) / 100;
            decoded.adc1.avg = readInt16LE(bytes.slice(i + 6, i + 8)) / 100;
            i += 8;
            continue;
        }
        // ADC 2
        else if (channel_id === 0x12) {
            decoded.adc2 = {};
            decoded.adc2.cur = readInt16LE(bytes.slice(i, i + 2)) / 100;
            decoded.adc2.min = readInt16LE(bytes.slice(i + 2, i + 4)) / 100;
            decoded.adc2.max = readInt16LE(bytes.slice(i + 4, i + 6)) / 100;
            decoded.adc2.avg = readInt16LE(bytes.slice(i + 6, i + 8)) / 100;
            i += 8;
            continue;
        }
        // MODBUS
        else if (channel_id === 0xFF && channel_type === 0x0E) {
            var modbus_chn_id = bytes[i++];
            var package_type = bytes[i++];
            var data_type = package_type & 7;
            var date_length = package_type >> 3;
            var chn = 'chn' + modbus_chn_id;
            switch (data_type) {
                case 0:
                    decoded[chn] = bytes[i] ? "on" : "off";
                    i += 1;
                    break;
                case 1:
                    decoded[chn] = bytes[i];
                    i += 1;
                    break;
                case 2:
                case 3:
                    decoded[chn] = readUInt16LE(bytes.slice(i, i + 2));
                    i += 2;
                    break;
                case 4:
                case 6:
                    decoded[chn] = readUInt32LE(bytes.slice(i, i + 4));
                    i += 4;
                    break;
                case 5:
                case 7:
                    decoded[chn] = readFloatLE(bytes.slice(i, i + 4));
                    i += 4;
                    break;
            }
        }
    }
    return decoded;
}
/* ******************************************
 * bytes to number
 ********************************************/
function readUInt8LE(bytes) {
    return (bytes & 0xFF);
}
function readInt8LE(bytes) {
    var ref = readUInt8LE(bytes);
    return (ref > 0x7F) ? ref - 0x100 : ref;
}
function readUInt16LE(bytes) {
    var value = (bytes[1] << 8) + bytes[0];
    return (value & 0xFFFF);
}
function readInt16LE(bytes) {
    var ref = readUInt16LE(bytes);
    return (ref > 0x7FFF) ? ref - 0x10000 : ref;
}
function readUInt32LE(bytes) {
    var value = (bytes[3] << 24) + (bytes[2] << 16) + (bytes[1] << 8) + bytes[0];
    return (value & 0xFFFFFFFF);
}
function readInt32LE(bytes) {
    var ref = readUInt32LE(bytes);
    return (ref > 0x7FFFFFFF) ? ref - 0x100000000 : ref;
}
function readFloatLE(bytes) {
    // JavaScript bitwise operators yield a 32 bits integer, not a float.
    // Assume LSB (least significant byte first).
    var bits = bytes[3] << 24 | bytes[2] << 16 | bytes[1] << 8 | bytes[0];
    var sign = (bits >>> 31 === 0) ? 1.0 : -1.0;
    var e = bits >>> 23 & 0xff;
    var m = (e === 0) ? (bits & 0x7fffff) << 1 : (bits & 0x7fffff) | 0x800000;
    var f = sign * m * Math.pow(2, e - 150);
    return f;
}
返回目录

样机试用

微信客服 wechat code

在线客服

工业路由器 Lorawan®网关 LoRaWAN®传感器 数传终端DTU 智能安防产品 更多产品咨询

电话咨询

phone icon 给我回电!