很多嵌入式 Linux 产品的核心不是驱动,而是设备服务。它负责联网、接收云端或其他设备的控制协议、保存配置、上报状态、处理升级和自恢复。设备服务写得稳不稳,直接影响产品现场表现。
一、设备服务负责什么
常见职责:
- 加载本地配置。
- 建立 MQTT 或 HTTP 连接。
- 上报设备状态。
- 接收控制命令。
- 写入持久化配置。
- 控制本地外设或业务进程。
- 记录日志。
- 异常退出后恢复。
典型目录:
1 | /usr/bin/device_agent |
二、MQTT topic 设计
可以按设备 ID 组织:
1 | device/{device_id}/cmd |
示例命令:
1 | { |
ack:
1 | { |
request_id 很重要。没有它,重试、超时和重复消息会很难处理。
三、命令处理流程
收到 MQTT 命令后建议按顺序处理:
- 解析 JSON。
- 校验
cmd和request_id。 - 校验参数白名单。
- 执行业务动作。
- 持久化配置。
- 通知相关服务。
- 发布 ack。
- 记录日志。
不要先 ack 再执行。否则上层以为成功,设备实际失败。
四、配置持久化
配置建议放在:
1 | /data/config/device.json |
写入时使用临时文件和原子替换:
1 | int save_config_atomic(const char *path, const char *content) |
异常断电时,这种方式比直接覆盖原文件安全。
五、服务自恢复
最简单的 supervisor 脚本:
1 |
|
真实项目还需要:
- 防止频繁崩溃导致刷日志。
- 和硬件 watchdog 配合。
- 支持优雅退出。
- 区分升级重启和异常重启。
六、以设置时区为例
MQTT 收到时区修改后:
- 校验时区是否在白名单。
- 写入
/data/config/timezone。 - 优先 bind mount 到
/etc/localtime。 - 失败时设置
TZ并重启依赖本地时间的服务。 - 发布 ack。
这类命令不要只改内存状态。设备重启后必须能恢复。
七、日志要能定位现场问题
日志至少包含:
- 时间。
- 模块。
- request_id。
- 命令名称。
- 参数摘要。
- 结果。
- 错误码。
示例:
1 | 2026-06-26 21:48:54 mqtt cmd=set_timezone request_id=... timezone=Asia/Shanghai result=ok |
现场排查时,日志比口头描述可靠。
- 本文链接: https://blog.hansong.icu/2026/06/26/Embedded_Linux_Series_06_Device_Service_MQTT/
- 版权声明: 本博客所有文章除特别声明外,均默认采用 CC BY-NC-SA 4.0 许可协议。