这是本节的多页打印视图。 点击此处打印.

返回本页常规视图.

接入设备

设备接入协议与规范

本章节介绍通过平台标准协议接入的设备。

设备说明文档
应变读数仪高频应变监测设备查看详情 →

1 - 应变读数仪

高频应变监测设备

应变读数仪用于结构健康监测中的应变数据采集,通过 MQTT + Protobuf 协议上报数据。

快速导航

文档说明
协议规格MQTT 主题、Protobuf 定义、字段说明

产品型号

型号通道数最高采样频率说明
SGR-1010100Hz振玄 10 通道应变读数仪

1.1 - 协议规格

应变读数仪通信协议技术规格

连接参数

参数值
协议MQTT v3.1.1
Broker由平台提供
端口1883
PayloadProtobuf

认证方式

支持两种 MQTT 认证方式:

方式clientIdusernamepassword
Access Token任意Access Token留空
BasicdeviceIdusernamepassword

认证凭据在平台创建设备后获取。clientId 建议使用 deviceId。

主题结构

主题方向QoS说明
strain/{deviceId}/telemetry上行0遥测数据(高频应变值)
strain/{deviceId}/attributes上行1设备属性上报
strain/{deviceId}/attributes/subscribe下行1平台下发配置指令

Protobuf 定义

设备端编译以下 .proto 文件生成对应语言的代码:

syntax = "proto3";

package shm.strain.v1;

// 遥测上报消息
message StrainTelemetry {
  StrainBatch strainBatch = 1;

  message StrainBatch {
    uint64 timestamp = 1;            // 首样本设备时间戳(毫秒)
    uint32 ch_no = 2;                // 通道编号(从 1 开始)
    uint32 sample_interval_ms = 3;   // 采样间隔(ms),100Hz=10, 50Hz=20, 20Hz=50
    repeated sint32 values = 4;      // 该通道的应变值数组(με)
    optional float temperature = 5;   // 该通道温度值(℃)
    optional uint32 battery = 6;     // 电池电量 0-100%
    optional uint32 mode = 7;        // 设备工作模式
    optional uint32 status = 8;      // 状态码,0=正常
  }
}

// 属性上报消息
message StrainDeviceAttributes {
  string firmware_version = 1;       // 固件版本
  string serial_number = 2;          // 设备序列号
  string device_model = 3;           // 设备型号
  uint32 channel_count = 4;          // 通道数
  uint32 sample_interval_ms = 5;     // 采样间隔(ms),所有通道统一
}

遥测字段

遥测数据封装在 StrainTelemetry.strainBatch 中,每个通道独立一包。

字段类型必填说明示例
timestampuint64是本批次首样本的设备时间戳,毫秒1776206400000
ch_nouint32是通道编号,从 1 开始1
sample_interval_msuint32是采样间隔,100Hz=10, 50Hz=20, 20Hz=5010
valuesrepeated sint32是该通道应变值数组(με),长度 = 1000 / sample_interval_ms[1500,1502,1498,...]
temperaturefloat否该通道温度值(℃)25.3
batteryuint32否电池电量百分比60
modeuint32否工作模式编码0
statusuint32否0=正常,其他=异常码0

属性字段

设备启动、固件升级或配置变更时上报一次。

字段类型必填说明示例
firmware_versionstring是固件版本"1.0.3"
serial_numberstring是设备序列号"ZX-0001"
device_modelstring是设备型号"SGR-10"
channel_countuint32是通道数10
sample_interval_msuint32是采样间隔(ms),所有通道统一10

下行指令(共享属性)

平台通过修改共享属性下发配置指令,设备订阅 strain/{deviceId}/attributes/subscribe 接收变更。

属性类型说明示例
sample_interval_msuint32修改采样间隔20(50Hz)
modeuint32切换工作模式1
rebootbool重启设备true
sync_timeuint64时间同步,平台当前时间(ms)1776206400000

设备收到属性变更后直接执行,无需回复。设备重连后可主动请求最新共享属性获取最新配置。


时间规则

每个通道每秒上报一包,包内样本时间按以下公式推导:

第 n 个样本时间 = timestamp + n × sample_interval_ms

示例(通道 1,100Hz,timestamp = 1776206400000):

样本时间戳
第 1 个(n=0)1776206400000
第 2 个(n=1)1776206400010
第 100 个(n=99)1776206400990

上报流程

以 10 通道 100Hz 设备为例,每秒上报 10 个包:

每秒重复:
  1. 获取当前设备时间戳 timestamp
  2. 对每个通道 ch_no = 1..10:
     a. 采集 100 个应变值
     b. 构造 StrainTelemetry 消息
     c. 序列化为 Protobuf 二进制
     d. 发布到 strain/{deviceId}/telemetry,QoS 0
包ch_nosample_interval_msvalues 长度
包1110100
包2210100
…………
包101010100

同一秒的 10 个包共享同一个 timestamp。


Python 示例

1. 安装依赖

pip install paho-mqtt protobuf

2. 编译 Proto

将上方 Protobuf 定义保存为 strain.proto,然后编译:

protoc --python_out=. strain.proto

3. 模拟器代码

#!/usr/bin/env python3
"""应变读数仪模拟器 - 10通道 100Hz"""

import math, random, time
import paho.mqtt.client as mqtt
import strain_pb2

BROKER = "gw.mqtt.inteagle.com"
PORT = 1883
TOKEN = "your_access_token"       # 替换为平台分配的 Access Token
DEVICE_ID = "ZX-0001"             # 替换为平台分配的设备编号
CHANNELS = 10
SAMPLE_INTERVAL_MS = 10           # 100Hz

def on_connect(client, userdata, flags, rc, properties=None):
    print(f"连接{'成功' if rc == 0 else '失败: ' + str(rc)}")

def main():
    client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2, client_id=f"strain-{DEVICE_ID}")
    client.username_pw_set(TOKEN)
    client.on_connect = on_connect
    client.connect(BROKER, PORT, keepalive=60)
    client.loop_start()
    time.sleep(1)

    # 上报设备属性(仅启动时一次)
    attrs = strain_pb2.StrainDeviceAttributes()
    attrs.firmware_version = "1.0.3"
    attrs.serial_number = DEVICE_ID
    attrs.device_model = "SGR-10"
    attrs.channel_count = CHANNELS
    attrs.sample_interval_ms = SAMPLE_INTERVAL_MS
    client.publish(f"strain/{DEVICE_ID}/attributes", attrs.SerializeToString(), qos=1)
    print("属性上报完成")

    # 持续上报遥测
    topic = f"strain/{DEVICE_ID}/telemetry"
    num_samples = 1000 // SAMPLE_INTERVAL_MS  # 100

    for sec in range(10):
        ts_ms = int(time.time() * 1000)

        for ch in range(1, CHANNELS + 1):
            msg = strain_pb2.StrainTelemetry()
            batch = msg.strainBatch
            batch.timestamp = ts_ms
            batch.ch_no = ch
            batch.sample_interval_ms = SAMPLE_INTERVAL_MS

            # 模拟应变数据
            base = 1500 + ch * 100
            for i in range(num_samples):
                t = i * SAMPLE_INTERVAL_MS / 1000.0
                val = int(base + 200 * math.sin(2 * math.pi * 2.0 * t) + random.randint(-10, 10))
                batch.values.append(val)

            batch.temperature = 25.3
            batch.battery = 85
            batch.status = 0
            client.publish(topic, msg.SerializeToString(), qos=0)

        print(f"第{sec+1}秒: 发送 {CHANNELS} 包")
        time.sleep(1)

    client.loop_stop()
    client.disconnect()
    print("完成")

if __name__ == "__main__":
    main()

4. 运行

python sim_strain.py

5. 预期输出

连接成功
属性上报完成
第1秒: 发送 10 包
第2秒: 发送 10 包
第3秒: 发送 10 包
...
完成