# 物联网设备接口和数据格式 ## 一、MQTT Topic 结构 后端同时订阅 `silk/+/+/+/up/telemetry` 和 `silk/+/+/+/down/cmd`(部分设备 publish/subscribe 方向反配)。下行命令主题根据设备实际上报主题自动推导: - 设备上报 `/up/telemetry` -> 命令发送到 `/down/cmd` - 设备上报 `/down/cmd` -> 命令发送到 `/up/telemetry`(反配设备) | 方向 | 主题格式 | 示例 | |------|----------|------| | **上行**(设备 -> 后端) | `silk/{appId}/{roomKey}/{deviceKey}/up/telemetry` | `silk/default/room-001/sensor-001/up/telemetry` | | **下行**(后端 -> 设备) | `silk/{appId}/{roomKey}/{deviceKey}/down/cmd` | `silk/default/room-001/sensor-001/down/cmd` | ### 路径段说明 | 段 | 说明 | 示例值 | |----|------|--------| | `silk` | 系统前缀(固定) | `silk` | | `{appId}` | 应用标识 | `default` | | `{roomKey}` | 房间标识 | `room-001` | | `{deviceKey}` | 设备标识(MAC 或自定义 ID) | `sensor-001`、`28562f8c35e8` | > **注意**:GSTMB1 设备的 `deviceKey` 在数据库中使用 MAC 地址(如 `28562f8c35e8`),但 topic 路径中仍使用配网时配置的名称(如 `sensor-001`)。后端通过消息体中的 `mac` 字段识别设备。 --- ## 二、GSTMB1 温湿度传感器 ### 设备信息 | 项目 | 值 | |------|-----| | 型号 | GSTMB1 | | 厂商 | GeekOpen / smart-bird.cn | | 通信协议 | MQTT | | 设备标识 | MAC 地址(如 `28562f8c35e8`) | | 上报指标 | temperature、humidity、signal 等 | ### 1. 设备定时上报(遥测数据) 设备直接在 body 顶层放置数值字段,后端自动提取 `temperature`、`humidity`、`signal`、`lux`、`co2` 等字段。 ```json { "type": "GSTMB1", "mac": "28562f8c35e8", "temperature": 28.24, "humidity": 57.83, "signal": -75, "ip": "192.168.1.56", "ssid": "GeekOpen", "version": "1.0.5" } ``` ### 2. 命令响应(设备 -> 后端) `source` 字段为 `"command"` 表示是对下行命令的回复。 **成功响应(info-all):** ```json { "commandName": "info-all", "mac": "28562f8c35e8", "source": "command", "success": true, "temperature": 28.24, "humidity": 57.83, "signal": "-75", "ip": "192.168.1.56", "ssid": "GeekOpen", "version": "1.0.5", "dhcpEnable": 1, "h_compensate": 0, "t_compensate": 0, "timerEnable": 1, "timerInterval": 15 } ``` **错误响应:** ```json { "commandName": "error", "mac": "28562f8c35e8", "source": "command", "success": false, "message": "MQTT消息缺少必要的type字段" } ``` ### 3. 下行命令(后端 -> 设备) | 功能 | API 端点 | 命令 JSON | |------|----------|-----------| | 获取设备信息 | `POST /api/v1/devices/:id/gstmb1/info` | `{"type":"info","messageId":"..."}` | | 重启设备 | `POST /api/v1/devices/:id/gstmb1/restart` | `{"type":"setting","system":"restart"}` | | 恢复出厂设置 | `POST /api/v1/devices/:id/gstmb1/command` | `{"type":"setting","system":"reset"}` | | 设置上报间隔 | `POST /api/v1/devices/:id/gstmb1/interval` | `{"type":"setting","messageId":"...","timerEnable":1,"timerInterval":60}` | | 自定义命令 | `POST /api/v1/devices/:id/gstmb1/command` | 任意 JSON 原样转发 | **参数说明:** | 字段 | 类型 | 说明 | |------|------|------| | `type` | String | **必填**。命令类型:`info`(查询)、`setting`(设置)、`event`(控制) | | `messageId` | String | 消息 ID,设备响应时原样返回 | | `system` | String | `restart`(重启)、`reset`(恢复出厂) | | `timerEnable` | int | 定时上报开关:`0`(关闭)、`1`(开启) | | `timerInterval` | int | 上报间隔(秒),范围 5-86400 | > API 端点中的 `:id` 是数据库中设备的 UUID,不是 MAC 地址。需 JWT 认证。 ### 4. 命令响应字段说明 | 字段 | 类型 | 说明 | |------|------|------| | `commandName` | String | 命令名称:`info-all`、`device-timer-interval`、`controller-restart`、`controller-reset`、`error` | | `mac` | String | 设备 MAC 地址 | | `source` | String | 固定 `"command"`,表示命令响应 | | `success` | boolean | 执行结果 | | `message` | String | 执行返回结果或错误信息 | | `temperature` | Float | 温度(摄氏度) | | `humidity` | Float | 湿度(%) | | `signal` | String | WiFi 信号强度(dBm),0~-50 最好,<-100 无信号 | | `ip` | String | 设备内网 IP | | `ssid` | String | WiFi 名称 | | `version` | String | 固件版本 | | `dhcpEnable` | int | DHCP 开关:`1`(开启)、`0`(关闭) | | `t_compensate` | Float | 温度补偿(范围 -20 至 +20) | | `h_compensate` | Float | 湿度补偿(范围 -20 至 +20) | | `timerEnable` | int | 定时上报开关 | | `timerInterval` | int | 上报间隔(秒) | --- ## 三、GSPE1B 智能插座 ### 设备信息 | 项目 | 值 | |------|-----| | 型号 | GSPE1B | | 厂商 | GeekOpen / smart-bird.cn | | 通信协议 | MQTT | | 设备类型 | 控制器(actuator) | | 设备标识 | MAC 地址(如 `e8f60a2f01e8`) | | 上报指标 | voltage、current、power、energy、key(通断状态) | > **注意**:该设备的 MQTT 主题方向与常规配置相反——设备发布到 `/down/cmd` 主题,订阅 `/up/telemetry` 主题接收命令。后端已适配此情况。 ### 1. 设备定时上报(遥测数据) 设备每 15 秒自动上报电量数据,`source` 字段为 `"auto"`: ```json { "mac": "e8f60a2f01e8", "source": "auto", "voltage": 226.234, "current": 0.327, "power": 66.795, "energy": 0.025, "key": 1 } ``` ### 2. 命令响应(设备 -> 后端) `source` 字段为 `"command"` 表示是对下行命令的回复。 **info-all 响应(设备信息):** ```json { "commandName": "info-all", "mac": "e8f60a2f01e8", "source": "command", "success": true, "key": 1, "onState": 2, "wifiLock": 0, "keyLock": 0, "timerEnable": 1, "timerInterval": 15, "signal": "-75", "ip": "192.168.1.59", "version": "1.0.5" } ``` **info-statistic 响应(电量信息):** ```json { "commandName": "info-statistic", "mac": "e8f60a2f01e8", "source": "command", "success": true, "voltage": 226.234, "current": 0.327, "power": 66.795, "energy": 0.025, "key": 1 } ``` **controller-event 响应(通断控制后回复):** 与 info-all 格式相同,包含设备状态信息。 ### 3. 下行命令(后端 -> 设备) | 功能 | API 端点 | 命令 JSON | |------|----------|-----------| | 通电 | `POST /api/v1/devices/:id/plug/on` | `{"type":"event","key":1}` | | 断电 | `POST /api/v1/devices/:id/plug/off` | `{"type":"event","key":0}` | | 查询设备信息 | `POST /api/v1/devices/:id/plug/info` | `{"type":"info","messageId":"..."}` | | 查询电量 | `POST /api/v1/devices/:id/plug/statistic` | `{"type":"statistic","messageId":"..."}` | | 重启设备 | `POST /api/v1/devices/:id/gstmb1/restart` | `{"type":"setting","system":"restart"}` | | 设置上报间隔 | `POST /api/v1/devices/:id/gstmb1/interval` | `{"type":"setting","timerEnable":1,"timerInterval":60}` | > API 端点中的 `:id` 是数据库中设备的 UUID,不是 MAC 地址。需 JWT 认证。 ### 4. 指标字段说明 | 字段 | 类型 | 说明 | |------|------|------| | `voltage` | Float | 电压(V),如 `226.234` | | `current` | Float | 电流(A),如 `0.327` | | `power` | Float | 功率(W),如 `66.795` | | `energy` | Float | 累计电量(kWh),如 `0.025` | | `key` | int | 通断状态:`1`(通电)、`0`(断电) | | `onState` | int | 上电状态:`0`(保持断电)、`1`(保持通电)、`2`(记忆上次状态) | | `wifiLock` | int | WiFi 锁:`0`(关闭)、`1`(开启) | | `keyLock` | int | 按键锁:`0`(关闭)、`1`(开启) | ### 5. 命令响应字段说明 | commandName | 说明 | |-------------|------| | `info-all` | 设备信息查询响应,包含 key、onState、wifiLock、timerEnable 等 | | `info-statistic` | 电量查询响应,包含 voltage、current、power、energy、key | | `controller-event` | 通断控制响应,格式同 info-all | | `error` | 错误响应,`success: false`,`message` 字段描述错误原因 | --- ## 四、GSCW1M-4G 4G 智能断路器 ### 设备信息 | 项目 | 值 | |------|-----| | 型号 | GSCW1M-4G | | 厂商 | GeekOpen / smart-bird.cn | | 通信协议 | MQTT over 4G LTE(合宙780ex,4G全网通) | | 设备类型 | 控制器(actuator) | | 设备标识 | IMEI 号(如 `862323080741518`),消息体中使用 `imei` 字段 | | 上报指标 | voltage、current、power、energy、key(通断状态)、signal(0-31) | > **与 GSPE1B 的区别**:4G 通信(非 WiFi);设备标识用 `imei`(非 `mac`);信号强度为 0-31 整数(非 dBm);`timerInterval` 单位为毫秒(非秒);响应消息**无** `source` 和 `commandName` 字段。 > > **固件 Bug**:部分设备在 info 响应中 `imei` 的第二位 `6` 误发为 `G`(如 `8G2323080741518`),statistic 响应中则为正确的 `862323080741518`。后端已做规范化处理(`G` -> `6`)。 > > **主题方向**:与 GSPE1B 智能插座相同,设备响应消息出现在订阅主题(`/down/cmd`)上,而非发布主题(`/up/telemetry`)。后端已适配。 ### 1. 设备响应(设备 -> 后端) 断路器的响应消息**没有** `source: "command"` 字段,所有响应均作为遥测数据处理,后端自动提取 body 中的数值字段。 **info 响应(设备信息):** ```json { "key": 0, "iccid": "898604E6192390306804", "imei": "862323080741518", "signal": 30, "version": "1.0.1", "timerEnable": 0, "keyLock": 0, "type": "Breaker-plus-1-4G", "timerInterval": 0, "resetLock": 0, "onState": 2 } ``` **statistic 响应(电量信息):** ```json { "voltage": "230.547", "current": "0.035", "power": "4.547", "energy": "0.001", "key": 1, "imei": "862323080741518", "messageId": "auto" } ``` > **注意**:断路器的 `voltage`、`current`、`power`、`energy` 字段为**字符串类型**(如 `"230.547"`),后端 `toFloat` 函数自动转换为数值入库。`messageId` 为 `"auto"` 时表示定时上报数据。 **event 响应(通断控制后回复):** ```json { "iccid": "898604E6192390306804", "timerEnable": 1, "onState": 2, "timerInterval": 60, "resetLock": 0, "imei": "862323080741518", "messageId": "0875c300-a0eb-475b-83ea-607eb27d19a0", "keyLock": 0, "type": "Breaker-plus-1-4G", "signal": 30, "version": "1.0.1", "key": 0 } ``` ### 2. 下行命令(后端 -> 设备) 命令格式与 GSPE1B 智能插座完全相同,复用同一套 API: | 功能 | API 端点 | 命令 JSON | |------|----------|-----------| | 通电 | `POST /api/v1/devices/:id/plug/on` | `{"type":"event","key":1}` | | 断电 | `POST /api/v1/devices/:id/plug/off` | `{"type":"event","key":0}` | | 查询设备信息 | `POST /api/v1/devices/:id/plug/info` | `{"type":"info","messageId":"..."}` | | 查询电量 | `POST /api/v1/devices/:id/plug/statistic` | `{"type":"statistic","messageId":"..."}` | | 设置按键锁 | `POST /api/v1/devices/:id/gstmb1/command` | `{"type":"setting","keyLock":0}` | | 设置定时上报 | `POST /api/v1/devices/:id/gstmb1/interval` | `{"type":"setting","timerEnable":1,"timerInterval":10000}` | | 重启设备 | `POST /api/v1/devices/:id/gstmb1/restart` | `{"type":"setting","system":"restart"}` | | 恢复出厂设置 | `POST /api/v1/devices/:id/gstmb1/command` | `{"type":"setting","system":"reset"}` | > `timerInterval` 单位为**毫秒**(如 `10000` = 10 秒),取值范围 5000-86400000。 ### 3. 指标字段说明 | 字段 | 类型 | 说明 | |------|------|------| | `voltage` | Float | 电压(V),如 `226.024` | | `current` | Float | 电流(A),如 `15.027` | | `power` | Float | 功率(W),如 `2921.511` | | `energy` | Float | 累计电量(kWh),如 `25.047`,断电不归零,重置后归零 | | `key` | int | 通断状态:`1`(通电)、`0`(断电) | | `signal` | int | 4G 信号强度,0-31,值越大越好 | | `imei` | String | 设备 IMEI(唯一标识,非数值指标) | | `iccid` | String | 物联网卡 ICCID(非数值指标) | | `onState` | int | 上电默认状态:`0`(记忆)、`1`(断电)、`2`(通电) | | `keyLock` | int | 按键锁:`0`(关闭)、`1`(开启) | | `resetLock` | int | 重置锁:`0`(关闭)、`1`(开启) | | `timerEnable` | int | 定时上报:`0`(关闭)、`1`(开启) | | `timerInterval` | int | 上报间隔(毫秒),如 `10000` = 10 秒 | --- ## 五、GSCU1B-4G 智能红外控制器 ### 设备信息 | 项目 | 值 | |------|-----| | 型号 | GSCU1B-4G | | 厂商 | GeekOpen / smart-bird.cn | | 通信协议 | MQTT over 4G LTE(合宙780ex,4G全网通) | | 设备类型 | 控制器(actuator) | | 设备标识 | IMEI 号(如 `864269069911747`),消息体中使用 `imei` 字段 | | 设备代号 | `Infrared-Controller-4G` | | 功能 | 红外码学习、发射、擦除,遥控空调/电视/风扇等家电 | | 红外码编号 | 1-248,可同时存储多个遥控器的红外码 | > 与断路器共用 `imei` 标识和 IMEI 规范化逻辑。无电压/电流/功率等电量指标,仅有 `signal`(4G 信号强度 0-31)。 ### 1. 设备响应(设备 -> 后端) **info 响应(设备信息):** ```json { "signal": 25, "code": "Infrared-Controller-4G", "version": "1.0.0", "iccid": "89860323442024493202", "type": "info", "imei": "864269069911747" } ``` **learn 响应(学习红外码结果):** ```json { "type": "infrared", "action": "learn", "imei": "864269069911747", "success": true } ``` **emit 响应(发射红外码结果):** ```json { "type": "infrared", "action": "emit", "imei": "864269069911747", "success": true } ``` > `success: false` 表示发射失败(红外编号对应的红外码为空)。学习成功蜂鸣器响 1 声,失败无声。 ### 2. 下行命令(后端 -> 设备) | 功能 | API 端点 | 命令 JSON | |------|----------|-----------| | 查询设备信息 | `POST /api/v1/devices/:id/plug/info` | `{"type":"info","messageId":"..."}` | | 学习红外码 | `POST /api/v1/devices/:id/ir/learn` | `{"type":"infrared","action":"learn","data":{"no":100}}` | | 发射红外码 | `POST /api/v1/devices/:id/ir/emit` | `{"type":"infrared","action":"emit","data":{"no":100}}` | | 取消学习 | `POST /api/v1/devices/:id/ir/cancel` | `{"type":"infrared","action":"learnCancel"}` | | 擦除全部红外码 | `POST /api/v1/devices/:id/ir/erase` | `{"type":"infrared","action":"erase"}` | | 重启设备 | `POST /api/v1/devices/:id/gstmb1/restart` | `{"type":"setting","system":"restart"}` | > 学习和发射命令的 body 需包含 `{"no": N}`,N 为 1-248 的红外码编号。 ### 3. 推荐红外码编号规划 | 编号 | 用途 | 学习方法 | |------|------|---------| | 100 | 关机 | 遥控器对准控制器,按关机键 | | 101 | 标准制冷 | 遥控器设为制冷 25°C 风量自动,按开机键 | | 102 | 标准制热 | 遥控器设为制热 30°C 风量自动,按开机键 | | 103+ | 自定义 | 按需扩展 | ### 4. 红外码学习流程 1. 后端发送 `{"type":"infrared","action":"learn","data":{"no":100}}` 2. 设备进入学习状态(不响应其他指令) 3. 遥控器对准设备,按一下对应按键 4. 设备"嘀"一声,返回 `{"success":true}` 5. 后续发送 `{"type":"infrared","action":"emit","data":{"no":100}}` 即可控制 --- ## 六、通用 MQTT 数据格式(非 GSTMB1 设备) 后端同时兼容以下消息格式,按优先级依次匹配: ### 1. metrics 对象格式 ```json { "msgId": "msg-test-001", "ts": 1751900000000, "metrics": { "temperature": 24.8, "humidity": 78.2, "lux": 360, "co2": 890 } } ``` ### 2. data 数组格式 ```json { "data": [ {"metric": "temperature", "value": 24.8}, {"metric": "humidity", "value": 78.2} ] } ``` ### 3. 单值格式 ```json { "metric": "temperature", "value": 24.8 } ``` ### 4. GSTMB1 顶层字段格式 ```json { "type": "GSTMB1", "mac": "28562f8c35e8", "temperature": 28.24, "humidity": 57.83 } ``` ### 设备标识优先级 1. `body.deviceKey`(显式指定) 2. `body.mac`(GSTMB1 传感器 / GSPE1B 智能插座) 3. `body.imei`(GSCW1M-4G 断路器,自动将 `G` 规范化为 `6`) 4. topic 路径第 4 段(如 `sensor-001`) --- ## 七、后端处理逻辑 ### 消息处理流程 ``` MQTT 消息到达 │ ├── JSON 解析失败 → 记录警告,丢弃 │ ├── 提取 deviceKey(mac > deviceKey > topic[3]) │ ├── 记录 deviceKey → 上行主题映射(用于下行命令) │ ├── 更新设备 online_status = "online", last_seen = now │ ├── source == "command"? │ ├── success == false -> 记录警告,结束 │ ├── commandName == "info-all" / "device-timer-interval" -> 提取温湿度入库 │ ├── commandName == "info-statistic" / "controller-event" -> 提取电压/电流/功率/电量入库 │ └── 其他 -> 记录日志,结束 │ └── 提取遥测指标(按优先级) ├── body.metrics(对象) ├── body.data(数组) ├── body.value(单值) └── body 顶层字段(温度/湿度/电压/电流/功率/电量/通断状态等) │ ├── 持久化(IoTDB 优先,降级 PostgreSQL) ├── WebSocket 推送前端 └── 阈值检测 ``` ### 离线检测 - 每 60 秒检查一次 - 超过 5 分钟未上报的设备标记为 `offline` - 通过 WebSocket 广播状态变更