Skip to content
  • 版块
  • 最新
  • 标签
  • 热门
  • 用户
  • 群组
皮肤
  • Light
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • 默认(不使用皮肤)
  • 不使用皮肤
折叠
品牌标识

AIRIOT智慧系统搭建平台经验交流

  1. 主页
  2. 设备接入
  3. MQTT驱动解析报文返回结果为什么会少一个字段

MQTT驱动解析报文返回结果为什么会少一个字段

已定时 已固定 已锁定 已移动 设备接入
帖子 发布者 浏览
  • 从旧到新
  • 从新到旧
  • 最多赞同
回复
  • 在新帖中回复
登录后回复
此主题已被删除。只有拥有主题管理权限的用户可以查看。
  • Y 离线
    Y 离线
    yunmoo
    编写 最后由 yunmoo 编辑
    #1

    解析脚本如下

    
    // Parse the received data.(解析接收数据)
    // This method will be called to parse the messages received by this server and topic. The message topic is the method parameter topic, and the message content is the method parameter package.(该服务器和主题收到的消息会调用此方法进行解析,消息主题是方法参数topic,消息内容是方法参数package.)
    // The type of topic is string. Considering that the message content of some devices is binary data, the type of package is byte array.(topic类型为字符串;考虑到部分设备的消息内容为二进制数据,package类型为字节数组,)
    // When the uploaded data is a JSON string, first use JSON.parse(package) to convert the received data into a JSON object.(当上传数据为json字符串时,首先使用JSON.parse(package)将收到的数据转为json对象.)
    
    ParseHandle = function (topic, package) {
        // 1. 将输入数据转换为HEX字符串
        let hexData = '';
        if (typeof package === 'string') {
            hexData = package;
        } else if (package instanceof Uint8Array || Buffer.isBuffer(package)) {
            hexData = Array.from(package).map(b => 
                b.toString(16).padStart(2, '0')).join('');
        } else {
            console.error('[ERROR] 不支持的数据格式');
            return [];
        }
        hexData = hexData.toLowerCase().replace(/\s+/g, '');
        console.log('[DEBUG] 原始HEX数据:', hexData);
    
        // 2. 去除头部51(严格验证位置)
        if (hexData.startsWith('51')) {
            hexData = hexData.slice(2);
            console.log('[DEBUG] 去除头部51后的数据:', hexData);
        }
    
        // 3. 验证起始符(0xAC)和结束符(0xCA)
        // ------------------------------------------------------------
        // 关键修复:正确提取结束符位置(倒数第4-2字节为结束符0xCA)
        // ------------------------------------------------------------
        const endFlagPosition = hexData.length - 4; // 结束符位于倒数第4-2字节
        const actualEndFlag = hexData.substr(endFlagPosition, 2);
        if (!hexData.startsWith('ac')) {
            console.error('[ERROR] 起始符校验失败: 期望ac,实际为', hexData.substr(0,2));
            return [];
        }
        if (actualEndFlag !== 'ca') {
            console.error('[ERROR] 结束符校验失败: 期望ca,实际为', actualEndFlag);
            return [];
        }
    
        // 4. 提取核心数据区(去除起始符ac和结束符ca及后续字节)
        const coreData = hexData.slice(2, endFlagPosition);
        console.log('[DEBUG] 核心数据区:', coreData);
        if (coreData.length % 2 !== 0) {
            console.error('[ERROR] 数据长度异常: 非偶数字节长度');
            return [];
        }
    
        // 5. 转换为字节数组
        const bytes = [];
        for (let i = 0; i < coreData.length; i += 2) {
            bytes.push(parseInt(coreData.substr(i, 2), 16));
        }
        console.log('[DEBUG] 字节数组:', bytes);
        // 6. 关键字段解析(根据协议文档索引)
        const params = {
            isDaytime: "未知",
            batteryVoltage: null,
            loadCurrent: null,
            loadVoltage: null,
            isWorking: false,
            temp:null
        };
    
        try {
            // 6.1 蓄电池电压(命令字0x03-0x04,索引4-5)
            if (bytes.length >= 6) { // 至少需要6字节
                const batHigh = bytes[4];
                const batLow = bytes[5];
                params.batteryVoltage = ((batHigh << 8 | batLow) / 100).toFixed(2);
                console.log('[DEBUG] 蓄电池电压计算:', { batHigh, batLow, voltage: params.batteryVoltage });
            }
    
            // 6.2 负载电压(命令字0x08,索引8)
            if (bytes.length >= 9) { // 至少需要7字节
                params.loadVoltage = (bytes[8] * 0.1).toFixed(1);
                console.log('[DEBUG] 负载电压计算:', params.loadVoltage );
            }
    
            // 6.3 负载电流(命令字0x06-0x07,索引6-7)
            if (bytes.length >= 8) { // 至少需要8字节
                const loadCHigh = bytes[6];
                const loadCLow = bytes[7];
                params.loadCurrent = ((loadCHigh << 8 | loadCLow) / 10).toFixed(2);
                console.log('[DEBUG] 负载电流:', {loadCHigh, loadCLow, voltage: params.loadCurrent});
            }
    
            // 6.4 昼夜模式(命令字0x01,索引2低4位)
            if (bytes.length >= 4) {
                const modeByte = bytes[2];
                const mode = (modeByte & 0xF0) >> 4;
                params.isDaytime = mode === 0 ? "白天" : mode === 1 ? "夜晚" : "异常";
                console.log('[DEBUG] 昼夜模式:', { modeByte, mode });
            }
            //温度采集
            if (bytes.length >= 24) {
                params.temp = ((bytes[23] + 100) * 0.1).toFixed(1);
                console.log('[DEBUG] 温度:', params.temp );
            }
            // 6.5 工作状态判断(阈值过滤噪声)
            params.isWorking = (
                params.loadVoltage !== null && parseFloat(params.loadVoltage) > 0 &&
                params.loadCurrent !== null && parseFloat(params.loadCurrent) > 0
            );
            console.log('[DEBUG] 工作状态:', params.isWorking);
        } catch (e) {
            console.error('[ERROR] 解析异常:', e);
            return [];
        }
    
        // 7. 返回结果(设备ID从topic中提取)
        const topicParts = topic.split('/').filter(seg => seg !== '');
        const deviceId = topicParts.length >= 3 ? topicParts[1] : 'unknown'; 
        return [{
            id: deviceId,
            values: {
                operating_mode: params.isDaytime,
                battery_voltage: params.batteryVoltage !== null ? parseFloat(params.batteryVoltage) : 0,
                load_current: params.loadCurrent !== null ? parseFloat(params.loadCurrent) : 0,
                load_voltage: params.loadVoltage !== null ? parseFloat(params.loadVoltage) : 0,
                working_status: params.isWorking,
                temperature: params.temp !== null ? parseFloat(params.temp) : 0
            },
            time: Date.now()
        }];
    };
    // Build sending data. (构建发送数据。)
    CommandHandle = function (topic, id, op) {
      console.log(topic)
      console.log(id)
      console.log(JSON.stringify(op))
    
      // Build sending data. (构建发送数据。)
      let sendTopic = topic
      let c = JSON.stringify([{ "abc": op.value }])
      console.log(c)
      let sendData = Buffer.from(c)
      return {sendTopic, sendData} //The names of the keys in the returned object must be sendTopic and sendData. (返回的对象中的 key 的名字必须为 sendTopic、sendData。)
    }
    

    以下是日志
    b07a045e-1b33-46c6-8b84-a9abae485b2c-a56d78ee2124f0fe925e91df8c9b6ac.png
    没有返回 load_current

    1 条回复 最后回复
    0
  • Y yunmoo 删除了该主题
  • Y yunmoo 恢复了该主题
  • Zhang书书Z 在线
    Zhang书书Z 在线
    Zhang书书
    编写 最后由 编辑
    #2

    发一下你们接收到的 数据json

    1 条回复 最后回复
    0
  • Y 离线
    Y 离线
    yunmoo
    编写 最后由 编辑
    #3

    收到数据不是json,是16进制数据帧51ac 2017 1ac8 0474 0000 0016 0000 0000 0000 0000 0000 0000 0081 7bca 14

    1 条回复 最后回复
    0
  • Zhang书书Z 在线
    Zhang书书Z 在线
    Zhang书书
    编写 最后由 Zhang书书 编辑
    #4

    这个负载电流是不是load_current,把对象 JSON处理一下
    62ddeb237a01ca329276c70ab9887a5.png
    75d0ee83b827a913d4c2ba4e2f18d8f.png

    1 条回复 最后回复
    0
  • Y 离线
    Y 离线
    yunmoo
    编写 最后由 编辑
    #5

    image.png这个返回的里面是有的

    Zhang书书Z 1 条回复 最后回复
    0
  • Zhang书书Z 在线
    Zhang书书Z 在线
    Zhang书书
    回复了yunmoo 最后由 编辑
    #6

    @yunmoo 这里面的0应该是因为走的这个判断,所以展示0

    1 条回复 最后回复
    0
  • Y 离线
    Y 离线
    yunmoo
    编写 最后由 编辑
    #7

    image.png负载电流为空
    image.png

    1 条回复 最后回复
    0
  • Zhang书书Z 在线
    Zhang书书Z 在线
    Zhang书书
    编写 最后由 Zhang书书 编辑
    #8

    params.loadCurrent !== null ? parseFloat(params.loadCurrent) : 0
    日志中展示0是因为你这个params.loadCurrent为null,所以数据点不显示,可以直接打印一下params.loadCurrent 看看是什么格式

    1 条回复 最后回复
    0

  • 登录

  • 没有帐号? 注册

  • 登录或注册以进行搜索。
  • 第一个帖子
    最后一个帖子
0
  • 版块
  • 最新
  • 标签
  • 热门
  • 用户
  • 群组