资讯动态

使用 MQTT 命令远程控制夜灯:Raspberry Pi 与虚拟 IoT 设备实战(IoT-For-Beginners 第 4 课)

发布时间:2026/9/14 18:10:42 来源:尧图企业网站定制
使用 MQTT 命令远程控制夜灯Raspberry Pi 与虚拟 IoT 设备实战IoT-For-Beginners 第 4 课【免费下载链接】IoT-For-Beginners12 Weeks, 24 Lessons, IoT for All!项目地址: https://gitcode.com/GitHub_Trending/io/IoT-For-Beginners本篇技术指南聚焦于 IoT-For-Beginners 课程第 4 课「Connect your device to the Internet」中的核心环节让夜灯设备通过 MQTT 协议订阅云端或本地 Server 代码下发的命令并据此控制 LED 的开关。文中以 translations/en/1-getting-started/lessons/4-connect-internet/single-board-computer-commands.md 为骨架结合仓库内code-commands目录的完整可运行源码进行验证与扩展。阅读完成后你将掌握 MQTT 命令主题command topic的设计、on_message回调的用法、JSON 命令载荷的解析以及如何在 Raspberry Pi 与 CounterFit 虚拟 IoT 设备上实现完整的遥测上报 → 服务端决策 → 命令下发 → 执行器响应闭环。一、背景从遥测到命令的闭环在本次课程的前几步中夜灯设备已经完成了两件事通过paho-mqtt连接到公共 MQTT 代理test.mosquitto.org将光敏传感器读到的光照值以 JSON 遥测消息发布到ID/telemetry主题。而运行在电脑或树莓派上的 Server 代码会订阅该遥测主题根据光照阈值默认 300计算出一个led_on布尔值并把它作为命令消息发布到ID/commands主题。本文要做的就是让设备订阅commands主题、解析命令并驱动 LED从而形成完整闭环这一模式正是真实 IoT 应用的缩影设备只负责上报数据 执行指令决策逻辑放在云端或本地服务端便于集中管理、便于多传感器联合判断例如课程 README 中提到的体育场灯光场景——只有当多个光敏传感器都判定光照不足时才开灯避免单点误判。完整课程背景见 1-getting-started/lessons/4-connect-internet/README.md其中详细介绍了 MQTT 协议、遥测telemetry与命令commands的概念。二、理解命令主题server_command_topic在设备代码中遥测与命令使用了两条互补的主题均由同一个设备唯一 ID 派生id ID client_telemetry_topic id /telemetry server_command_topic id /commandsclient_telemetry_topic设备发布光照遥测的主题server_command_topic设备订阅LED 命令的主题。课程文档明确指出server_command_topic是设备为了接收 LED 命令而订阅的 MQTT 主题。这一点可以在仓库的完整实现中得到印证例如 code-commands/virtual-device/nightlight/app.py 与 code-commands/pi/nightlight/app.py 中两条主题紧邻定义而 code-commands/server/app.py 中 Server 端定义了完全相同的两条主题名这正是双方能够通信的契约基础。⚠️ 设备端与 Server 端必须使用同一个ID。该 ID 同时用于 MQTT 客户端名称IDnightlight_client/IDnightlight_server与主题名。由于test.mosquitto.org是公共代理、使用者众多使用唯一 ID 可避免与其他学习者的流量互相干扰。在主题层级上/telemetry与/commands是平行关系而非嵌套关系。三、编写命令处理函数handle_command在mqtt_client.loop_start()之后、主循环while True之前添加以下代码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这段代码做三件事定义handle_command(client, userdata, message)回调函数将message.payload从字节流解码为字符串再用json.loads解析为 Python 字典读取led_on属性若为True则调用led.on()开灯否则调用led.off()关灯注册订阅与回调mqtt_client.subscribe(server_command_topic)让客户端订阅命令主题mqtt_client.on_message handle_command指定消息到达时的处理函数。与源码的对应关系上述代码与仓库中 code-commands/virtual-device/nightlight/app.py 及 code-commands/pi/nightlight/app.py 完全一致区别仅在于硬件抽象层的导入方式Raspberry Pi物理硬件从grove.grove_light_sensor_v1_2与grove.grove_led导入真实的 Grove 传感器/执行器驱动虚拟 IoT 设备CounterFit从counterfit_shims_grove.*导入同名 shim数据读写被重定向到本地运行的 CounterFit 应用你可以在浏览器界面中手动调节光照值、观察 LED 虚拟状态。两种实现共享同一套 MQTT 命令处理逻辑说明本文的核心知识完全可迁移无论底层硬件如何设备端只需要订阅主题 解析 JSON 驱动执行器三步。on_message回调的语义paho-mqtt的on_message回调对所有已订阅主题的消息都会触发。这意味着如果你只订阅了server_command_topic回调收到的每条消息都来自该主题如果你后续订阅了多个主题例如同时监听/commands与/firmware则必须通过回调收到的message对象其.topic属性来判断消息来源再分流处理。文档特别强调了这一点 提示它是在一个设备上扩展多种命令通道时的关键设计点。四、Server 端如何生成命令为了验证设备端行为有必要理解命令从何而来。仓库中的 code-commands/server/app.py 给出了完整的 Server 实现def handle_telemetry(client, userdata, message): payload json.loads(message.payload.decode()) print(Message received:, payload) command { led_on : payload[light] 300 } print(Sending message:, command) client.publish(server_command_topic, json.dumps(command)) mqtt_client.subscribe(client_telemetry_topic) mqtt_client.on_message handle_telemetry处理流程为Server 订阅ID/telemetry收到遥测后解析 JSON读取light字段与阈值300比较light 300时led_on为True光照不足 → 开灯否则为False将命令序列化为 JSON 发布到ID/commands。由此可以看到完整的双向消息格式约定方向主题消息体JSON示例设备 → 云ID/telemetry{light: int}{light: 250}云 → 设备ID/commands{led_on: bool}{led_on: true}设备端payload[led_on]读取的正是这个布尔字段。两边代码分别位于 code-commands/server/app.py 与 code-commands/virtual-device/nightlight/app.py对照阅读即可直观理解契约的两端实现。五、运行与验证按照文档要求完成编码后打开夜灯项目在 VS Code 中打开nightlight工程目录激活环境若使用虚拟 IoT 设备确保终端处于虚拟环境.venv中若直接在 Raspberry Pi 上运行则不需要虚拟环境确保 CounterFit 就绪仅虚拟设备CounterFit 应用正在运行且光敏传感器与 LED 已按正确引脚创建传感器接 Grove 引脚 0LED 接引脚 5与源码中GroveLightSensor(0)、GroveLed(5)对应启动 Server 代码用于生成命令启动设备代码python app.py改变光照物理设备可遮挡/照射光敏传感器虚拟设备可在 CounterFit 界面中拖动光照滑块。预期终端输出Server 端Message received: {light: 0} Sending message: {led_on: True} Message received: {light: 400} Sending message: {led_on: False}设备端则会打印收到的命令同时 LED 随命令开/关Message received: {led_on: True} Message received: {led_on: False}阈值 300 的含义是光照值低于 300 视为天黑开灯高于或等于 300 视为天亮关灯。可自行调整 Server 代码中的阈值以匹配不同环境的光线条件。六、扩展要点与设计启示1. 多设备命令隔离本文采用单条commands主题承载所有命令。课程 README 提醒若要让命令精确路由到特定设备可使用唯一主题例如ID/commands/commands/device1、/commands/device2让每台设备只订阅属于自己的主题。这是主题即寻址这一 MQTT 核心思想的直接应用。2. 断连期间的命令处理命令与遥测同样面临断连问题若最新命令可以覆盖旧命令例如开灯之后又来关灯则旧命令可丢弃若命令必须按序执行例如机械臂先抬起、再夹取则应本地排队并在恢复连接后按序补发。这取决于具体业务对命令时序的敏感性。3. QoS 与保留消息MQTT 消息可指定 QoS 等级至多一次 / 至少一次 / 恰好一次决定投递保证强度带 retained 标志的消息会被代理保存新订阅者上线时会立即收到该主题的最新保留消息。对于设备重启后应恢复到上次 LED 状态这类需求保留消息是值得考虑的机制。相关内容详见 1-getting-started/lessons/4-connect-internet/README.md。4. 代码位置速查用途仓库路径虚拟设备命令处理完整源码1-getting-started/lessons/4-connect-internet/code-commands/virtual-device/nightlight/app.pyRaspberry Pi 命令处理完整源码1-getting-started/lessons/4-connect-internet/code-commands/pi/nightlight/app.pyServer 端遥测→命令转换1-getting-started/lessons/4-connect-internet/code-commands/server/app.py设备连接 MQTT 的起步代码1-getting-started/lessons/4-connect-internet/code-mqtt遥测上报代码1-getting-started/lessons/4-connect-internet/code-telemetry此外本课还提供了基于 Arduino/Wio Terminal 的等价实现wio-terminal-commands.md 与 code-commands/wio-terminal使用 C 与 PlatformIO思想完全一致可作为跨语言对照学习的素材。结语至此你的夜灯设备已经从单机传感器演示进化为一台真正可远程控制的 IoT 设备它持续上报光照遥测订阅命令主题解析 JSON 命令并驱动 LED。这套遥测上行 命令下行的双主题 MQTT 架构是几乎所有云连接 IoT 产品恒温器、智能照明、工业监控的通用骨架。掌握本文的命令订阅与回调处理模式后你可以自由扩展出多主题、多命令、多设备隔离、保留消息等更复杂的应用形态。【免费下载链接】IoT-For-Beginners12 Weeks, 24 Lessons, IoT for All!项目地址: https://gitcode.com/GitHub_Trending/io/IoT-For-Beginners创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价