【从零搭建物联网智能充电桩系统】3、MQTT 客户端:设备接入云端的第一道关口

设备接入云端,靠的是 MQTT。本文讲解本项目中最核心的 MQTT 客户端模块:如何订阅设备上报、如何解析二进制报文、如何通过 Spring Integration 与 EMQX 建立连接,以及下行指令如何转发给设备。


一、模块定位

charge-mqtt-client设备接入的核心模块,全项目实现最完整(14 个 Java 文件,成熟度 ★★★★☆)。职责:

  • 上行:订阅 EMQX 的 charge/stat,接收设备二进制报文 → 解析 → 投 RabbitMQ
  • 下行:消费 RabbitMQ 的下行指令 → MQTT publish 给设备

端口:HTTP 8080 | MQTT over WebSocket: ws://emqx:8083


二、模块结构(14 个类)

复制代码
charge-mqtt-client/src/main/java/com/yeseesion/SmartChargeStation/mqtt/client/
├── MqttApplication.java            启动类
├── api/SendApi.java                发送/模拟 REST 接口(/mqtt/send、/mqtt/simulate)
├── conf/MqttProps.java             @ConfigurationProperties(prefix="mqtt") 配置映射
├── factory/
│   ├── FactoryBuilder.java         MqttPahoClientFactory 构建
│   ├── InBoundMessageRev.java      ★★核心:入站消息分发(471 行,全项目最大类)
│   ├── InBoundSubscribe.java       入站适配器/订阅配置
│   └── OutBoundSend.java           出站 Handler 配置
├── model/MqttConstants.java        通道常量 OUT_CHANNEL="out" / In_CHANNEL="in"
├── mq/
│   ├── ChargeCmdConsumer.java      消费下行指令 → MQTT
│   ├── ChargeStatConsumers.java    三路 Fanout 消费者(手动 ACK)
│   ├── ChargeStatProducer.java     Fanout 广播生产者
│   └── RabbitConfig.java           Fanout 交换机 + 3 队列 + TTL
├── service/MqttService.java        @MessagingGateway 网关接口
└── utils/TransformerUtils.java     objectToHex / hexStringToByteArray / bytesToHex

三、上行链路核心:InBoundMessageRev(471 行)

按 Topic 分发逻辑

Topic 处理
charge/stat hex → ChargeStatData.fromHexString() 解析 24 字节帧 → buildStatJson() → 投 Fanout
charge/stat/json 调试通道,直接收 JSON(跳过二进制解析)
charge/cmd 指令回环/日志

三个 HTTP 回调(均带 X-Internal-Key 头)

java 复制代码
callNettyPush()   → POST http://netty:8085/netty/push      // 推小程序
cacheStatToRedis()→ SET charge:stat:{chargeRecordId} TTL 24h
callIotDBSave()   → POST http://iotdb-service:8087/iotdb/charge/stat // 写时序库

代码 172-174 行有一段被注释掉的旧逻辑------原先收到 MQTT 后同步串行调用三个下游,重构为 RabbitMQ Fanout 后异步解耦,但旧代码未删除。


四、Spring Integration MQTT 集成(常见疑问)

关键概念

概念 本项目用法
MqttPahoClientFactory FactoryBuilder 构建,配置 broker 地址/账号/密码
MqttPahoMessageDrivenChannelAdapter 入站适配器(InBoundSubscribe),订阅 charge/stat 等
MqttPahoMessageHandler 出站 handler(OutBoundSend),publish 到 charge/cmd
@MessagingGateway MqttService 接口,声明式发送消息
Channel 内部消息通道(out / in 两个常量)

为什么用 Spring Integration 而不是裸 Paho?

  • 消息收发的生命周期由 Spring 管理,与 Boot 应用集成度高
  • 通道抽象(Channel)方便后续加拦截器/过滤器/转换器
  • 断线重连由 Paho 客户端 + Spring 适配器协同处理

下行指令的格式选择:为什么不是真·二进制?(重要!)

java 复制代码
// ChargeCmdPayload 只有字段,没有 toBytes()
// 实际发送走 TransformerUtils.objectToHex():
//   整个对象 JSON 序列化 → 转 hex 字符串 → MQTT publish

字段名(start_tag 等 snake_case)也会进 payload。这是刻意为之 :下行指令由小程序发起 ,用 JSON 序列化转 hex,小程序端和抓包工具都能直接看到请求参数 (目标桩 ID、充电时长等),调试体验远优于二进制帧。上行(设备→云端)走真·二进制是设备端省流量,下行走 JSON 是前端要可读------同一个项目里按方向选协议,这正是"按场景做取舍"的体现。

注意:若未来设备端指令下发频率变高或需严格省流,可再评估是否统一为二进制------当前下行频率低(用户手动点击),JSON 方案是合理的。


五、消息可靠性设计

层级 措施
设备→EMQX MQTT QoS 1(至少一次)
EMQX→MQTT客户端 订阅 QoS 1
MQTT客户端→下游 RabbitMQ 手动 ACK + 失败重入队(当前无重试上限,见下面缺陷)
RabbitMQ 队列 持久化队列(重启不丢)

已知缺陷basicNack(requeue=true) 且未配置死信队列(DLQ)→ 毒药消息无限重投(见 05 篇)。


六、常见问题与解答

  1. MQTT 的 QoS 0/1/2 有什么区别?为什么用 QoS 1 不用 2?(QoS1 至少一次、有重复;QoS2 恰好一次、开销大;充电状态可容忍重复上报)
  2. MQTT 的 retain 消息有什么用?(保留最近一条,新订阅者立即收到;本项目未用)
  3. buildStatJson() 把二进制解析结果转 JSON 的字段有哪些?(chargingTime/chargedEnergy/currentPower/currentCost/chargingProgress/state;注意 chargeRecordId 是 URL 参数,不在 JSON 内;state 对应"充电中/已完成"等状态枚举)
  4. 如果三个下游全部宕机,MQTT 客户端会发生什么?(RabbitMQ 消息堆积,队列 TTL 到期丢弃;MQTT 客户端本身不阻塞)
  5. Spring Integration 的 Channel 和 MQ 的 Queue 是一回事吗?(不是:Channel 是应用内消息管道,Queue 是跨应用的消息存储)

小结

MQTT 客户端是设备接入的咽喉:上行把二进制报文解析后交给 RabbitMQ 分发,下行把指令发布到 MQTT。它本身不直接连数据库,靠消息中间件与下游解耦。下一篇 【从零搭建物联网智能充电桩系统】4、Netty WebSocket 服务 讲解与小程序保持长连接的 Netty 服务端。

相关推荐
hnsoyon12 小时前
依托物联网工程守护城市地下管网运行安全
物联网·物联网工程·地下管网监测
qq_3164110313 小时前
物联网大健康管理平台的功能模块与技术架构详解
物联网
SL-staff17 小时前
技术实践:解决IoT网关单点故障导致子设备批量‘失联’问题
物联网·zigbee·边缘缓存·jvs·iot架构·物模型设计·设备生命周期
TDengine (老段)18 小时前
TDengine 应用案例 — 能源与电力监控
大数据·数据库·物联网·能源·时序数据库·tdengine·涛思数据
虎王物联19 小时前
Docker WASM 边缘计算:12ms 冷启动如何重塑 IoT 网关部署
物联网·docker·容器·边缘计算·wasm
2601_9567436819 小时前
上海物联网应用开发技术选型指南:从HTTP/MQTT/Modbus协议适配、平台化架构设计到源代码交付与私有化部署,解析工程落地的关键考量点
物联网·网络协议·http·开发经验·上海
黎阳之光19 小时前
软硬协同国产化 | 黎阳之光矩阵式视频融合管理系统完成摩尔线程国产GPU兼容适配
大数据·人工智能·物联网·安全·数字孪生
智圣新创0120 小时前
存量数字化校园升级破局:从基础数据集成到校务服务全域提效的通用落地路径
大数据·人工智能·物联网
HZZD_HZZD1 天前
远传水表系统技术选型:大口径物联网水表与 OCR 摄像水表对比
物联网·ocr
虎王物联1 天前
工业Modbus TCP协议深度实战:STM32 HAL库实现从机通信与数据上云
stm32·物联网·网络协议·tcp/ip·嵌入式