尧图精选

IoT-For-Beginners 第 4 课深度指南:用 MQTT 将物联网设备接入互联网——遥测、命令与夜灯远程控制实战

🕒 发布时间:2026/9/15 15:56:33 📁 来源:尧图网络
IoT-For-Beginners 第 4 课深度指南用 MQTT 将物联网设备接入互联网——遥测、命令与夜灯远程控制实战【免费下载链接】IoT-For-Beginners12 Weeks, 24 Lessons, IoT for All!项目地址: https://gitcode.com/GitHub_Trending/io/IoT-For-Beginners本指南以开源课程《IoT-For-Beginners》第 4 课1-getting-started/lessons/4-connect-internet/README.md为核心系统讲解物联网设备接入互联网的关键机制publish/subscribe 通信模型、MQTT 协议核心特性、遥测telemetry数据上行与命令commands下行。课程将带你动手改造上一课完成的夜灯项目——通过公共 MQTT brokertest.mosquitto.org把光照传感器读数发送到服务端再由服务端代码判断后回传指令控制 LED 开关完整走通设备采集 → 云端处理 → 反向控制的闭环。学完本篇你将掌握 MQTT 主题、QoS、retained 消息等概念并能在 Wio TerminalArduino与树莓派/虚拟设备两种平台上实现 IoT 双向通信。从IoT中的 I 说起为什么需要通信协议IoT 中的I 代表 Internet互联网。云连接和云端服务支撑了 IoT 设备的大部分能力——从采集连接在设备上的传感器测量值到发送消息控制执行器。典型架构中IoT 设备通过标准通信协议连接到单个云端 IoT 服务该服务再与 IoT 应用的其他部分打通用于基于数据做智能决策的 AI 服务、用于控制或报表的 Web 应用等。两个贯穿全课的核心方向遥测Telemetry从传感器采集数据并发送到云端例如光照强度、温度、湿度。命令Commands从云端发送到设备、指示其执行某种动作的消息。动作可以是内部操作如重启、固件更新也可以是通过执行器输出的物理动作如开灯。通信协议总览publish/subscribe 与 brokerIoT 设备与互联网通信有若干主流协议其中最流行的一类基于**发布/订阅publish/subscribe**消息模型借助某种broker消息代理完成路由IoT 设备连接到 broker发布publish遥测并订阅subscribe命令云端服务同样连接到 broker订阅全部遥测消息并向特定设备或设备组发布命令。在该模型中发送方与接收方完全解耦设备不需要知道云服务是谁云服务也不需要知道设备是谁双方只与 broker 交互通过命名主题路由消息。除了本课重点的 MQTT 之外常见的 IoT 通信协议还包括 AMQP 与 HTTP/HTTPS。MQTT 协议深入轻量级消息传输的机制与特性MQTTMessage Queueing Telemetry Transport是目前 IoT 设备最流行的通信协议。它是一个轻量、开放标准的设备间消息协议1999 年最初设计用于监控石油管道15 年后由 IBM 以开放标准形式发布。MQTT 采用一个 broker 多个客户端的拓扑所有客户端都连接到 brokerbroker 负责把消息路由给相关客户端。消息按命名主题路由而不是直接发给某个客户端——客户端可以向主题发布消息所有订阅了该主题的客户端都会收到。主题层级与通配符主题可以拥有层级结构客户端可以用通配符订阅层级中的不同级别。例如温度遥测发布到/telemetry/temperature湿度遥测发布到/telemetry/humidity云端应用订阅/telemetry/*即可同时收到温度与湿度两类遥测消息。QoS服务质量三档消息可以携带服务质量Quality of ServiceQoS决定投递保障的强弱级别语义投递保障QoS 0至多一次消息只发送一次客户端与 broker 不做任何确认属于发了就忘fire and forgetQoS 1至少一次发送方反复重试直到收到确认acknowledged deliveryQoS 2恰好一次发送方与接收方进行两级握手确保消息只被收到一份assured delivery思考题什么场景下必须用恰好一次级别的可靠投递而不是发了就忘关于队列的澄清、retained 标志与 keep alive尽管协议名中包含Message Queueing但 MQTT实际上并不支持消息队列。这意味着客户端断线后重连将收不到断线期间发送的消息QoS 处理流程中已经开始处理的消息除外。MQTT 提供以下三个关键补充机制retained 标志消息可以设置保留标志。若设置了该标志broker 会保存该主题上最近一条带此标志的消息并在之后订阅该主题的客户端上线时发给它。这样新订阅者总能拿到该主题的最新消息。keep aliveMQTT 支持保活机制在消息间隔较长时检查连接是否仍然存活。安全与传输MQTT 连接可以是公开开放的也可以用用户名/密码或证书加密保护。MQTT 走TCP/IP与 HTTP 相同的底层网络协议但端口不同还可以通过websocket与浏览器中的 Web 应用通信或在防火墙/网络规则阻断标准 MQTT 连接时使用。动手第一步把夜灯设备连接到 MQTT broker现在进入实战。本节为夜灯添加互联网控制的第一步——连接到 MQTT broker。课程不要求自己搭建 broker而是直接使用Eclipse Mosquitto开源 MQTT broker运营的公共测试服务器test.mosquitto.org。该测试 broker 无需注册账号非常适合测试 MQTT 客户端与服务端。⚠️ 注意该测试 broker 是公开且不安全的——任何人都可能监听你发布的内容因此绝不能用于任何需要保密的私有数据。整体流程如下IoT 设备将光照水平作为遥测通过 MQTT 发布到公共 broker你编写的服务端代码捕获该消息检查光照水平后回发一条命令消息指示设备开/关 LED。一个真实的同类场景是在拥有大量灯具的场所如体育场汇总多个光传感器的数据后再决定是否开灯——如果只有一个传感器被云或鸟遮挡而其他传感器检测到足够光线就可以避免误开灯。根据硬件平台选择对应步骤Arduino - Wio Terminal单板计算机 - Raspberry Pi / 虚拟 IoT 设备仓库中的连接实现参考以 Python 版本为例连接代码展示在仓库的code-mqtt目录中。虚拟设备版本code-mqtt/virtual-device/nightlight/app.py与树莓派版本code-mqtt/pi/nightlight/app.py的核心连接逻辑一致id ID client_name id nightlight_client mqtt_client mqtt.Client(client_name) mqtt_client.connect(test.mosquitto.org) mqtt_client.loop_start() print(MQTT connected!)关键点在于id必须全局唯一可自行替换ID为任意标识串它用于构造客户端名称与后续的主题名保证多个学习者之间互不串扰。loop_start()会在后台线程启动网络处理循环让客户端持续收发消息。Wio TerminalArduino版本的完整工程位于 code-mqtt/wio-terminal 目录。遥测Telemetry把传感器数据送上天Telemetry一词源自希腊语词根含义是远程测量——即从传感器收集数据并发送到云端的行为。有趣的是最早的遥测设备之一于 1874 年在法国发明用物理导线把勃朗峰Mont Blanc的实时天气与积雪深度发送到巴黎。回到第 1 课引入的智能恒温器例子恒温器用温度传感器收集遥测通常内置一个温度传感器还可以通过蓝牙低功耗BLE等无线协议连接多个外部温度传感器。它可能发送的遥测数据示例如下名称值描述thermostat_temperature18°C恒温器内置温度传感器测得的温度livingroom_temperature19°C名为livingroom的远程温度传感器测得的温度用于标识所在房间bedroom_temperature21°C名为bedroom的远程温度传感器测得的温度用于标识所在房间云端服务可以利用这些遥测数据决策发送何种命令来控制供暖。从 IoT 设备发送遥测JSON 编码为夜灯添加互联网控制的下一步是把光照水平遥测发布到 MQTT broker 的遥测主题上。消息以JSONJavaScript Object Notation编码——一种用键值对在文本中编码数据的标准格式。按硬件平台选择对应步骤Arduino - Wio Terminal单板计算机 - Raspberry Pi / 虚拟 IoT 设备以 Python 虚拟设备版本code-telemetry/virtual-device/nightlight/app.py为例遥测发布代码为client_telemetry_topic id /telemetry # ... while True: light light_sensor.light telemetry json.dumps({light : light}) print(Sending telemetry , telemetry) mqtt_client.publish(client_telemetry_topic, telemetry) time.sleep(5)设备每 5 秒读取一次光传感器用json.dumps把{light: 读数}序列化为 JSON 字符串发布到id /telemetry主题。Wio TerminalArduino版本则借助ArduinoJson库完成同样的工作。在platformio.ini的lib_deps中添加依赖bblanchon/ArduinoJson 6.17.3在config.h中定义主题名const string CLIENT_TELEMETRY_TOPIC ID /telemetry;然后在loop中读取模拟引脚WIO_LIGHT的数值、构造 JSON 文档并发布int light analogRead(WIO_LIGHT); DynamicJsonDocument doc(1024); doc[light] light; string telemetry; serializeJson(doc, telemetry); Serial.print(Sending telemetry ); Serial.println(telemetry.c_str()); client.publish(CLIENT_TELEMETRY_TOPIC.c_str(), telemetry.c_str());Wio Terminal 的完整工程位于 code-telemetry/wio-terminal通过串口监视器可以看到类似Sending telemetry {light:652}的输出。服务端接收遥测的 Python 程序只发不收没有意义——光照遥测需要监听端来处理数据。这种服务端代码正是大型 IoT 应用中部署到云服务的代码类型但本课先在本地电脑或在树莓派上直接编程运行。安装 Python 与 VS Code若本地尚未安装 Python 和 VS Code需要先安装使用虚拟 IoT 设备或在树莓派上工作时可跳过环境已就绪安装 Python建议最新稳定版。安装 Visual Studio Code。安装 VS Code 的Pylance扩展提供 Python 语言支持。你也可以使用任何惯用的 Python IDE 或编辑器但本课操作说明基于 VS Code。配置 Python 虚拟环境并安装 paho-mqttPython 的强项之一是通过pip安装第三方包。但默认安装的包全局可用容易引发版本冲突——例如某应用依赖包版本 A而另一个应用安装新版本后导致前者不可用。解决方案是Python 虚拟环境venv它本质上是专用文件夹中的一份 Python 副本pip安装的包只进入该文件夹。操作步骤mkdir nightlight-server cd nightlight-serverpython3 -m venv .venv 创建虚拟环境时须显式调用python3以防机器上还装有 Python 2 时python指向旧版本。激活虚拟环境Windows 命令提示符.venv\Scripts\activate.batWindows PowerShell.\.venv\Scripts\Activate.ps1macOS / Linuxsource ./.venv/bin/activate激活后默认python命令将运行创建虚拟环境所用的 Python 版本用python --version确认3.6 及以上均可。最后安装 MQTT 库pip install paho-mqttpaho-mqtt是流行的 Python MQTT 库且只安装在该虚拟环境内部。编写服务端代码 app.py在虚拟环境内创建app.pyWindows 用type nul app.pymacOS/Linux 用touch app.py再用code .打开当前文件夹。VS Code 会自动识别并激活虚拟环境状态栏可见若已有终端未激活可用Kill the active terminal instance按钮结束旧终端再通过Terminal - New Terminal新建终端加载虚拟环境。app.py的完整代码与 code-server/server/app.py 一致import json import time import paho.mqtt.client as mqtt id ID client_telemetry_topic id /telemetry client_name id nightlight_server mqtt_client mqtt.Client(client_name) mqtt_client.connect(test.mosquitto.org) mqtt_client.loop_start() def handle_telemetry(client, userdata, message): payload json.loads(message.payload.decode()) print(Message received:, payload) mqtt_client.subscribe(client_telemetry_topic) mqtt_client.on_message handle_telemetry while True: time.sleep(2)请把ID替换为创建设备代码时使用的同一唯一 ID。⚠️ 该 ID 必须与设备端完全一致否则服务端代码将订阅/发布到错误的主题导致两端失联。这段代码的逻辑以唯一名称创建 MQTT 客户端连接test.mosquitto.orgbrokerloop_start()在后台线程启动处理循环持续监听已订阅主题的消息订阅遥测主题并把handle_telemetry注册为消息回调handle_telemetry用json.loads解码 JSON 负载并打印到控制台while True死循环保持主程序存活后台线程则持续监听消息。运行服务端python app.py确保设备在运行并发送遥测后调节物理或虚拟设备检测到的光照水平终端会实时打印(.venv) ➜ nightlight-server python app.py Message received: {light: 0} Message received: {light: 400}注意设备端nightlight虚拟环境中的app.py必须保持运行nightlight-server虚拟环境中的app.py才能收到消息。遥测应该多久发送一次这是遥测设计的关键权衡采样越频繁对变化的响应越快但功耗、带宽、数据量、云端处理成本也越高——需要足够频繁但不过于频繁。恒温器每几分钟测量一次通常绰绰有余因为温度变化没那么快。每天只测一次可能在大晴天正午仍按夜间温度供暖每秒测一次则会积累成千上万条重复的温度测量浪费用户带宽对流量受限用户是问题、消耗更多电量对电池供电的远程传感器是问题并抬高云端计算与存储成本。工厂机械监控如果设备故障可能造成灾难性损坏和数百万美元损失可能必须每秒多次测量——浪费带宽好过漏掉机械需要停机检修的遥测信号。在这种高要求场景下可考虑先用**边缘设备edge device**处理遥测降低对互联网的依赖。断连怎么办互联网连接不可靠断网时有发生。IoT 设备应丢弃数据还是暂存到恢复连接后补发答案依然是看情况恒温器一旦新的温度测量完成旧数据即可丢弃——供暖系统不关心 20 分钟前是 20.5°C只要现在是 19°C决定开关供暖的是当前温度。机械设备可能希望保留所有数据尤其是用于趋势分析时。存在能检测数据流异常的机器学习模型观察最近一小时等时间段的数据并识别异常常用于预测性维护——寻找即将故障的迹象以便提前维修更换。此时可能希望每条遥测都被发送用于异常检测一旦设备重连就把断网期间产生的全部遥测补发。设备设计者还应考虑断网或信号差如地下车库时设备能否降级工作智能恒温器在无法向云端发送遥测时也应具备有限的本地供暖决策能力。这好比一辆因在地下车库无信号环境尝试 OTA 升级而被变砖的汽车——完全依赖云端的设备在连接丢失时会彻底失效。对 MQTT 而言处理连接丢失需要设备与服务端代码共同负责保障投递例如要求所有发出的消息都在回复主题上收到确认否则手动入队、待重连后重放。命令Commands从云端反向控制设备命令是从云端发送到设备、指示其执行动作的消息。多数时候命令通过执行器产生某种输出但也可以是指令设备本身——例如重启或采集额外遥测并作为命令的响应返回。恒温器可能收到云端发来的打开供暖命令云服务根据所有传感器的遥测数据做出应开启供暖的决策后发送相应命令。服务端发送命令基于光照阈值决策为互联网控制的夜灯添加命令环节服务端代码根据感知到的光照水平向 IoT 设备发送控制灯光的命令。在服务端代码中于client_telemetry_topic声明之后增加命令主题server_command_topic id /commands然后在handle_telemetry函数末尾追加command { led_on : payload[light] 300 } print(Sending message:, command) client.publish(server_command_topic, json.dumps(command))这段代码向命令主题发送一条 JSON 消息led_on根据光照是否小于 300 设为true或false——光照小于 300 时发送true指示设备打开 LED。完整代码见 code-commands/server/app.py。运行后调节光照终端输出遥测接收与命令发送的完整闭环(.venv) ➜ nightlight-server python app.py Message received: {light: 0} Sending message: {led_on: True} Message received: {light: 400} Sending message: {led_on: False} 本实现中遥测与命令各自只用一个主题因此多个设备的遥测会出现在同一遥测主题、命令也会出现在同一命令主题。若要向特定设备发送命令可以用唯一设备 ID 命名多个主题例如/commands/device1、/commands/device2这样设备只监听发给自己的消息。设备端处理命令并控制 LED服务端发送命令后需要在 IoT 设备侧增加处理逻辑来驱动 LED。按硬件平台选择对应步骤Arduino - Wio Terminal单板计算机 - Raspberry Pi / 虚拟 IoT 设备Python 版本的完整实现见 code-commands/virtual-device/nightlight/app.py虚拟设备与 code-commands/pi/nightlight/app.py树莓派def handle_command(client, userdata, message): payload json.loads(message.payload.decode()) print(Message received:, payload) if payload[led_on]: led.on() else: led.off() mqtt_client.subscribe(server_command_topic) mqtt_client.on_message handle_command while True: light light_sensor.light print(Light level:, light) mqtt_client.publish(client_telemetry_topic, json.dumps({light : light})) time.sleep(5)设备订阅id /commands主题注册handle_command回调收到命令后解码 JSON、读取led_on字段并调用led.on()/led.off()控制 LED主循环仍持续采集并发布光照遥测。Wio TerminalArduino版本在 code-commands/wio-terminal 中。其实现要点config.h中定义const string SERVER_COMMAND_TOPIC ID /commands;在reconnectMQTTClient函数末尾调用client.subscribe(SERVER_COMMAND_TOPIC.c_str())保证重连后自动恢复订阅定义clientCallback回调消息以无符号 8 位整数数组到达需先转为字符数组再用 ArduinoJson 的deserializeJson解码 JSON 文档读取led_on字段后通过digitalWrite(D0, HIGH/LOW)控制 LED在createMQTTClient中通过client.setCallback(clientCallback)注册回调。 注意clientCallback会处理所有已订阅主题的消息。若以后订阅多个主题可从回调的topic参数判断消息来自哪个主题。全部代码写好后运行调节光照水平即可观察完整效果服务端收到遥测、决策并发送命令设备端打印收到的命令并相应点亮/熄灭 LED。命令与断连云服务需要向离线设备发送命令时怎么办同样取决于场景若最新命令覆盖旧命令旧命令可以忽略。例如云端先发送打开供暖再发送关闭供暖那么打开命令可以忽略且无需补发。若命令必须按顺序处理如先上移机械臂、再闭合夹爪则必须在连接恢复后按顺序补发。思考题如果需要设备端或服务端代码如何确保命令始终按正确顺序通过 MQTT 发送和处理实践练习与延伸学习挑战延续前三课的练习——尽可能多地列出家中、学校或工作场所的 IoT 设备判断它们基于微控制器还是单板计算机或两者混合并思考它们使用的传感器和执行器。对每个设备进一步分析它们发送什么遥测可能接收什么消息或命令它们安全吗延伸学习自行运行 MQTT broker例如 Mosquitto并从 IoT 设备与服务端代码连接它。注意默认配置下 Mosquitto不允许匿名连接无用户名/密码也不接受运行主机之外的连接。可通过mosquitto.conf配置文件开启仅建议本地实验listener 1883 0.0.0.0 allow_anonymous true完成课后作业对比 MQTT 与其他通信协议从协议机制、适用场景、可靠性保障等维度做横向分析。小结一条完整的 IoT 双向通信链路本课完整走通了 IoT 双向通信的最小闭环设备端读取光传感器 → JSON 编码后经 MQTT 发布到/telemetry主题 → 本地服务端订阅并解码遥测 → 依据阈值光照 300决策 → 向/commands主题发布命令 → 设备端回调解码命令、驱动 LED。四份渐进式代码目录code-mqtt、code-telemetry、code-server、code-commands恰好对应这一学习路径的每个里程碑读者可在 1-getting-started/lessons/4-connect-internet 目录下逐一对照验证。理解 MQTT 的主题路由、QoS、retained 与 keep alive 机制以及遥测频率、断连处理等设计权衡是构建可靠、可扩展的 IoT 应用的基础能力。【免费下载链接】IoT-For-Beginners12 Weeks, 24 Lessons, IoT for All!项目地址: https://gitcode.com/GitHub_Trending/io/IoT-For-Beginners创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
上一篇/下一篇内容由系统自动关联 返回资讯列表 →