资讯详情

基于MQTT协议的智慧路灯物联网系统开发实战指南

📅 2026/9/16 6:39:11 | 华诺云谱 👁 阅读
基于MQTT协议的智慧路灯物联网系统开发实战指南
简介一套完整的基于MQTT协议的智慧路灯管理系统源码覆盖物联网云平台Web开发全流程采集端通过MQTT.fx模拟路灯数据经由MQTT协议传输至服务端最终在前端页面实时展示。整个压缩包共102个文件、14.24MB以Java源码、class编译文件、XML配置、properties属性文件为主同时含JSP/HTML/JS/CSS等前端资源可快速导入IDE运行并二次开发。源码已通过导师指导认可答辩评审分达95分代码测试运行成功适合物联网、电子信息、计算机等专业的课程设计、毕业设计或初学者学习MQTT通信与Web可视化。随包附带详细文档与全部资料可帮助理解从设备模拟、消息订阅/推送、数据存储到前端展示的完整链路。目前已有71人学习下载。1. 智慧路灯管理系统里的 MQTT 协议到底在解决什么问题做智慧路灯项目时最容易踩的坑不是前端图表画得不好看而是把路灯设备当成普通网页请求来处理。一盏路灯要上报电压、电流、功率、亮度、故障码若干个字段一条街几十盏灯一个区上千盏灯如果用 HTTP 轮询请求频率上不去网络拥塞时数据就堆在设备端服务端还要维护大量长短连接吃力不讨好。MQTT 协议天生为这种低带宽、高延迟、设备数量大且经常掉线的物联网场景设计基于发布/订阅模型设备和服务端都只跟 Broker 打交道数据流解耦路灯掉线重连也不会把服务端拖垮。这套系统在 PC 机上做 Web 开发采集端用 MQTT.fx 模拟路灯上报数据经 MQTT 传输到服务端整个过程不用真实硬件也能把完整链路跑通无论你是做毕设、竞赛还是企业级原型验证这条路径都够典型。2. 物联网云平台的 MQTT 协议选型Broker、主题与 QoS 策略2.1 MQTT 协议核心机制发布/订阅、QoS 与遗嘱消息MQTT 协议的全称是 Message Queuing Telemetry Transport设计目标极其明确在不可靠网络上用最小开销传输遥测数据。它的核心是发布/订阅模型生产者发布消息到某个主题消费者订阅这个主题双方不需要知道对方的存在中间由 Broker 转发。这和 HTTP 的请求/响应模型本质不同路灯设备永远不会直接和 Web 服务端建立连接它们只和 Broker 保持 TCP 连接Web 服务端也以订阅者的身份接入 Broker两端彻底解耦。MQTT 消息有五个关键字段值得在写代码前先想清楚主题是路由依据Payload 是业务数据QoS 决定投递可靠性Retain 标志决定是否保留最后一条消息遗嘱消息则是设备异常掉线时由 Broker 代为发布的遗言。其中 QoS 有三个级别QoS 0 最多发一次可能丢消息适合普通温湿度这类允许丢点的数据QoS 1 保证至少到达一次会重复适合路灯开关状态这类不能漏但可以幂等处理的消息QoS 2 保证恰好一次性能开销最大业务上很少用到。在设计智慧路灯系统时我一般会把遥测数据定为 QoS 0 或 QoS 1控制命令定为 QoS 1因为控制指令重发一次问题不大但丢失可能导致灯开不了。遗嘱消息是 MQTT 协议里容易被轻视但极其实用的能力。路灯设备接入 Broker 时可以在 CONNECT 报文里携带遗嘱消息指定一个遗嘱主题和遗嘱载荷比如{status: offline, deviceId: SL-001}。此后如果设备因为断电、断网而异常掉线Broker 会代替设备向遗嘱主题发布这条消息如果是正常断开连接Broker 则不发布遗嘱。智慧路灯系统里的设备离线检测靠的就是这个机制比 Web 服务端隔几秒查一次数据库要实时得多。2.2 Broker 选型EMQX 还是 Mosquitto同一个 MQTT 协议Broker 实现的选择直接决定这套系统能扛多大压力也决定后续开发时你在调试上花多少时间。目前主流开源方案是 EMQX 和 Mosquitto 二选一。Mosquitto 是 eclipse 基金会下的轻量级 Broker安装包只有几 MB单机能承载的连接数在上万级别对学校实验和百盏灯级别的毕设项目完全够用但它的管理界面弱默认配置下没有可视化 Dashboard连接断了、消息丢了都得靠日志查。EMQX 是国产开源项目基于 Erlang/OTP 开发最大优势是百万级连接能力和内置的 DashboardWeb 界面里能直接看到连接数、订阅关系、消息速率还能在线发消息调试做 Web 开发的人会非常舒服。智慧路灯如果只是演示Mosquitto 最少折腾如果要模拟上千盏灯而且需要频繁看消息流转状态EMQX 更合适。我一般建议直接在 Windows 或 Linux 上装 EMQX因为后续的 Web 开发调试会大量依赖它的 Dashboard。以 Windows 为例下载解压后进入 bin 目录双击emqx start或执行./bin/emqx start浏览器访问http://localhost:18083默认账号 admin密码 public就能进入管理界面。EMQX 默认同时监听 1883 端口MQTT over TCP和 8083 端口MQTT over WebSocketWeb 前端如果不想自己写消息代理可以直接用 WebSocket 连 8083 端口订阅主题省去一层后端转发。下面是在 Linux 服务器上用 Docker 跑 EMQX 的最小命令。docker run -d --name emqx -p 1883:1883 -p 18083:18083 -p 8083:8083 emqx/emqx:5.0.26-p参数把容器内的三个端口映射到宿主机1883 是 MQTT 设备接入端口18083 是 Dashboard Web 管理页面8083 是 WebSocket 入口Web 端通过这个端口做实时通信。装完先不急着写代码打开 Dashboard 能看到整体架构后续排查问题会轻松很多。2.3 主题设计与命名规范主题是 MQTT 消息路由的唯一依据主题设计得不好后面写通配符订阅、做权限控制都会很难受。智慧路灯系统的主题我建议按地域/设备类型/设备ID/数据类型四级来规划具体示例streetlight/district-01/SL-001/telemetry表示 1 号片区 SL-001 号路灯的遥测数据streetlight/district-01/SL-001/command表示对 SL-001 号路灯的控制命令streetlight/district-01/broadcast表示对整个片区的广播命令。这样设计有几个好处一是通配符可以一层层匹配设备比如订阅streetlight//SL-001/telemetry就是订阅所有片区的 SL-001二是#通配符可以订阅整个片区比如streetlight/district-01/#就是 1 号片区的所有数据三是日志和排查问题时主题本身就包含了设备位置信息不用再解析 Payload。有了主题规范接入流程就变得清晰写 Spring Boot 或 Node.js 后端时订阅逻辑完全由主题决定不用在业务代码里做设备分配。比如 EMQX 的 Dashboard 中创建规则时也可以直接用主题通配符匹配把遥测数据流转发到 Kafka 或数据库中。需要说明一点主题本身有长度上限EMQX 默认限制是 65535 字节但实际项目中建议控制在 80 字节以内多级主题虽然灵活但层次太多容易带来性能损耗和消息体积膨胀。3. 用 MQTT.fx 模拟路灯采集端从单灯到千灯的可复现方案3.1 MQTT.fx 连接参数配置与 Broker 连通性验证MQTT.fx 是目前 PC 端最常用的桌面版 MQTT 调试客户端基于 JavaFX 开发界面直观支持多个连接配置切换在 Windows 上无需写代码就能模拟设备端发布和订阅消息是智慧路灯系统早期开发阶段验证数据通道的关键工具。需要说明的是MQTT.fx 自带的是一个图形化发布订阅界面模拟多台设备时需要通过新建多个连接配置来模拟不同 Client ID从而达到以假乱真的效果。安装完成后打开 MQTT.fx点击齿轮图标进入连接配置页面理解每个参数的含义比记住配置更关键Broker Address 填 EMQX 所在机器的 IP本地跑就填 127.0.0.1Broker Port 默认 1883不用加密Client ID 是每个设备的唯一标识智慧路灯场景下建议直接填SL-001、SL-002这类与业务对应的编号而不是让工具随机生成的一串字符这样 Dashboard 里能直接分辨设备如果 EMQX 开了认证则需填 Username 和 Password默认关闭时留空即可。Keep Alive Interval 是心跳间隔默认 60 秒这表示设备每 60 秒发一次 PINGREQ 报文告诉 Broker我还活着。配置完成后点击 Connect绿色指示灯亮起说明 TCP 连接和 MQTT 握手都成功了此时到 EMQX Dashboard 的客户端管理页面能看到SL-001这个 Client ID 已经在连接列表里。这一步是整个链路的第一道验证关卡连接不上就往下排查 IP、端口、防火墙而不是去调业务代码。3.2 发布遥测数据路灯状态上报的 Payload 设计路灯遥测数据本质是一份 JSON 字符串MQTT 协议本身不关心 Payload 格式传输任何字节数组都可以因此字段设计完全由业务决定。智慧路灯的核心指标包括电压、电流、功率、功率因数、照明亮度、灯状态、故障码、采集时间等我给出一个可复用的上报格式{ deviceId: SL-001, timestamp: 2024-05-20T14:30:0008:00, status: on, illuminance: 85, voltage: 220.5, current: 0.42, power: 92.6, powerFactor: 0.98, faultCode: 0, lng: 113.2714, lat: 23.1284 }status表示灯的开关状态illuminance表示亮度百分比 0-100voltage、current、power是电网数据faultCode为 0 表示无故障非零值对应具体故障类型lng和lat是路灯经纬度用于 Web 端地图可视化。在 MQTT.fx 中把上述 JSON 粘贴到 Publish 区域的 Payload 输入框主题填streetlight/district-01/SL-001/telemetryQoS 选 1然后点击 Publish消息就会进入 EMQX。此时打开第二个 MQTT.fx 配置Client ID 随意订阅streetlight/district-01/#就能看到刚才那条遥测消息被实时转发过来发布/订阅链路到此打通。3.3 订阅控制命令验证指挥路灯的完整回路采集端能发数据还不够智慧路灯的核心功能还包括远程开关灯和亮度调节因此模拟设备端还得有监听命令的能力。在 MQTT.fx 中点击 Subscribe 页签输入streetlight/district-01/SL-001/commandQoS 选择 1点击 Subscribe 按钮该条订阅会出现在下方的订阅列表中。现在可以用另一台设备向这个主题发布一条控制命令模拟 Web 端下发指令控制指令的 Payload 同样用 JSON例如{ deviceId: SL-001, command: setBrightness, value: 60, timestamp: 2024-05-20T14:35:0008:00 }command字段定义操作类型常见值有setBrightness、turnOn、turnOff、rebootvalue字段是操作参数亮度值或开关状态。当模拟设备端收到这条消息时MQTT.fx 界面会弹出消息提示节点收到命令后需要返回一条确认消息发布到streetlight/district-01/SL-001/commandAck主题Web 端才能判断控制指令是否被成功执行。如果控制命令下发后没有任何确认消息通常不是 MQTT 的问题而是命令主题和遥测主题在订阅时没分开。实际项目中建议给每个设备单独建命令主题不要用广播主题下发单灯控制避免设备误执行其他灯的命令。整个采集端模拟流程走下来你其实已经完成了真实嵌入式设备比如 STM32 或 ESP32工作的全部逻辑连接 Broker、上报遥测、订阅命令、执行动作、回复确认。这也是 MQTT 协议在设备端移植价值所在无论底层 MCU 是什么物联网云平台交互的逻辑完全一致。4. PC 端 Web 开发落地从 EMQX 到 Vue3 前后端实时链路4.1 后端订阅 MQTT 消息并转发 WebSocket 的通用架构智慧路灯 Web 系统如果直接让浏览器连 EMQX 的 8083 WebSocket 端口架构最简单但存在两个问题一是 EMQX 对外暴露在公网时浏览器直连会绕过服务端认证安全风险大二是后端拿不到数据就没法做持久化存储、告警规则、历史查询这些业务逻辑。因此企业级 Web 开发中规中矩的做法是在服务端单独写一个消息消费模块用 MQTT 客户端库连接 EMQX订阅streetlight/#再把解析后的数据通过 WebSocket 推送给前端同时写入数据库。这里以 Node.js 为例用mqtt库实现一个最小消费服务这段代码是整套 Web 端的数据入口必须吃透逻辑。后端代码负责两件事建立 MQTT 客户端连接绑定消息回调启动 WebSocket 服务把到达的消息实时推给所有已连接的前端页面。const mqtt require(mqtt); const WebSocket require(ws); // 连接 EMQX Broker const mqttClient mqtt.connect(mqtt://127.0.0.1:1883, { clientId: web-backend-service, clean: false, sessionExpiryInterval: 7200, }); // 订阅所有路灯的数据主题和遗嘱主题 mqttClient.on(connect, () { mqttClient.subscribe(streetlight///telemetry, { qos: 1 }); mqttClient.subscribe(streetlight///status, { qos: 1 }); console.log(MQTT connected and subscribed); }); // 启动 WebSocket 服务 const wss new WebSocket.Server({ port: 8080 }); wss.on(connection, (ws) { console.log(Web frontend connected); }); // 收到 MQTT 消息后直接转发给所有连接的 Web 客户端 mqttClient.on(message, (topic, payload) { const message JSON.stringify({ topic, data: JSON.parse(payload.toString()), }); wss.clients.forEach((client) { if (client.readyState WebSocket.OPEN) { client.send(message); } }); });上面的代码中clientId固定为web-backend-service这就是为什么之前强调 Client ID 要有业务含义的原因调试时一目了然。clean: false表示会话持久化Broker 会保留该客户端的订阅关系即使后端重启重启期间的离线消息也能在重连后继续接收这是智慧路灯这类生产系统的必备配置。sessionExpiryInterval: 7200定义了会话在两小时没连接后才会被服务端清理。wss.clients.forEach是典型的 WebSocket 广播模式每台电脑浏览器打开的页面都是这个服务端的 WebSocket 客户端MQTT 消息一到就能实时推送。4.2 前端 Web 界面Vue3 ECharts 的地图监控与配电工艺图前端的核心不是把数据在界面上滚一条列表而是把实时状态以可视化方式呈现。智慧路灯管理系统的典型界面包括全城路灯分布地图、实时数据面板、故障报警列表和设备控制区。这里地图监控用 ECharts 是最成熟的做法Vue3 中通过echarts的 npm 包引入不需要额外地图服务也能用 effectScatter 散点图画出路灯位置和状态颜色绿色表示在线正常、红色表示故障、灰色表示离线。要实现类似配电工艺图的场控效果可以在页面中间放一个变电站到配电柜、配电柜到路灯的连线图电压电流数据实时标注在连线上ECharts 的 graph 类型就能处理这种关系图。前端还需要一个 MQTT 数据的接入层这里推荐造一个轻量的 WebSocket 封装沿用上面后端 WebSocket 服务的消息格式。下面的 Vue3 组合式函数实现了连接 WebSocket、解析 MQTT 消息、按主题分发到不同处理函数的逻辑import { ref } from vue; export function useRealTimeData() { const telemetryData ref({}); let ws; function connectWebSocket() { ws new WebSocket(ws://localhost:8080); ws.onmessage (event) { const { topic, data } JSON.parse(event.data); const parts topic.split(/); // streetlight / district-01 / SL-001 / telemetry const deviceId parts[2]; if (topic.endsWith(/telemetry)) { telemetryData.value[deviceId] data; // 这里触发界面上相关组件的刷新 handleTelemetryUpdate(deviceId, data); } else if (topic.endsWith(/status)) { handleDeviceStatusChange(deviceId, data); } }; ws.onclose () { // 自动重连避免掉线后界面失去更新 setTimeout(connectWebSocket, 3000); }; } function sendCommand(deviceId, command, value) { const payload JSON.stringify({ deviceId, command, value, timestamp: new Date().toISOString(), }); // 这里应通过后端转发而不是直接连接 MQTT ws.send(JSON.stringify({ topic: streetlight/district-01/${deviceId}/command, data: JSON.parse(payload), })); } return { telemetryData, connectWebSocket, sendCommand }; }这里的逻辑要点是topic.split(/)把主题结构拆开取第三段作为设备 ID前端展示层不需要关心有没有真实设备只需要维护一个以设备 ID 为 key 的响应式对象telemetryData。ECharts 地图的 series 数据可以直接从telemetryData里的经纬度字段生成数据点颜色根据faultCode和status动态设置。VSCode 开发时配置一个 BrowserSync 或 Vite 热更新插件保存代码后页面自动刷新调试效率会明显提升。4.3 控制指令下发Web 界面到路灯设备的完整链路Web 管理页面除了看数据还得能远程操作路灯。界面上的开关按钮触发sendCommand函数通过 WebSocket 发给后端后端收到后解析出主题用同一个 MQTT 客户端发布到对应的命令主题上。这样做的价值在于统一了消息入口前端无论是地图点击还是表格按钮最终都转化为一条 MQTT 消息发布逻辑不会写多份。代码逻辑如下// 后端 WebSocket 收到前端指令 wss.on(connection, (ws) { ws.on(message, (message) { const { topic, data } JSON.parse(message); mqttClient.publish(topic, JSON.stringify(data), { qos: 1 }); }); });这里要注意安全边界千万别让前端随便指定任意主题进行发布否则任何用户都能向所有路灯下发命令。生产项目至少要做一个主题白名单校验只允许streetlight/district-01//command格式的发布请求并且从服务端 Session 中获取用户所属片区后再拼接主题前端传过来的设备 ID 仅作参考。命令下发后如果设备端回复了 commandAck 消息Web 界面可以弹出控制成功提示超过 5 秒未收到 ack 则提示超时并要求检查设备在线状态。5. 智慧路灯系统的掉线监控与遗嘱消息实战技巧路灯设备常年野外工作断电、断网是常态系统必须有自动检测设备离线的能力。虽然 EMQX 能查看当前连接数但 Web 管理系统数据库里实时维护的仍然是设备在线状态需要用注册遗嘱消息机制。智慧路灯采集端接入时在 CONNECT 报文中同时携带遗嘱消息遗嘱主题为streetlight/district-01/SL-001/status遗嘱 Payload 为{deviceId:SL-001,status:offline,timestamp:...}。当设备网络异常断开时Broker 会自动向该主题发布这条消息后端订阅了streetlight///status主题收到后更新数据库状态并触发告警通知。相比定时轮询这种方式秒级感知掉线而且是 Broker 主动上报不消耗额外设备流量。这里的几个调优经验值得直接借鉴一是遗嘱消息要跟随设备发送的心跳频率设置keepalive值是 60 秒时Broker 会在 90 秒后判定设备失联因此设备异常掉线后最多一分半钟后才能收到离线通知如需更快感知可把心跳压缩到 20 秒但会增加少量网络开销。二是遗嘱消息最好由真实设备在每次连接时重新注册不要写在 MQTT.fx 的全局配置里一次注册永久生效否则设备主动重启时会发送正常 DISCONNECT不会触发遗嘱发布但服务器可能保留旧遗嘱下次异常断开时代理发布的还是旧数据。三是带电控箱的场景建议加一级单灯故障告警合并10 分钟没收到某盏灯遥测再标记离线避免瞬时网络抖动造成误报。验证遗嘱功能是否生效最直接的办法是打开两个窗口一个用 MQTT.fx 把 SL-001 的 Client ID 连接上并订阅streetlight///status另一个把设备端模拟的连接强杀关闭 MQTT.fx 而不是点击断开按钮然后看订阅窗口是否收到{status:offline}的消息。在 EMQX Dashboard 的消息页面里也能看到发布记录。如果没收到优先检查 CONNECT 报文里遗嘱消息是否成功写入在 Dashboard 的客户端详情页能看到当前已设置的遗嘱主题和遗嘱 Payload。这套机制在任何 MQTT 协议的物联网系统里都是通用的智慧路灯只是其中一个最典型的应用场景它把设备离线检测从定时轮询上升为事件驱动这是物联网云平台和传统 Web 管理系统在架构思想上最核心的差异点。本文还有配套的精品资源点击获取
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。