ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

IoT-For-Beginners 实战:Raspberry Pi 与虚拟设备通过 MQTT 订阅命令远程控制夜灯

IoT-For-Beginners 实战:Raspberry Pi 与虚拟设备通过 MQTT 订阅命令远程控制夜灯 IoT-For-Beginners 实战Raspberry Pi 与虚拟设备通过 MQTT 订阅命令远程控制夜灯【免费下载链接】IoT-For-Beginners12 Weeks, 24 Lessons, IoT for All!项目地址: https://gitcode.com/GitHub_Trending/io/IoT-For-Beginners导读本文聚焦于 Microsoft「IoT-For-Beginners」课程第 4 课「Connect your device to the Internet」中的设备端环节让运行在Raspberry Pi 或虚拟 IoT 设备上的夜灯nightlight项目订阅来自 MQTT 代理的commands命令根据服务端下发的led_on指令点亮或熄灭 LED从而完成「光照遥测上传 → 云端判断 → 命令下发 → 执行器动作」的完整闭环。读完本文你将掌握 Paho-MQTT 客户端订阅主题、注册on_message回调、解析 JSON 命令负载并驱动 Grove LED 的完整方法并能对照仓库源码独立复现这一可远程控制的物联网应用。一、场景回顾遥测上行、命令下行在进入命令订阅之前需要先明确这条链路在课程中的位置。本课共分为三个阶段前两个阶段是本文的前提连接 MQTT 代理single-board-computer-mqtt.md为设备安装paho-mqtt依赖创建id nightlight_client的客户端名称并连接公共测试代理test.mosquitto.org发布遥测single-board-computer-telemetry.md将光敏传感器读数封装为 JSON{light: 数值}发布到id /telemetry主题订阅命令即本文订阅id /commands主题接收服务端回传的{led_on: true/false}指令并驱动 LED。整条数据流可以用课程 README 中的流程图概括设备读取光强后发布遥测运行在本地或 Pi 上的「服务器代码」订阅遥测、判断光强阈值再向命令主题发布控制指令设备收到指令后点亮或熄灭 LED。 该课程文档中使用的是test.mosquitto.org公共测试代理无需注册账号即可使用但它公开且不加密任何数据都可能被监听因此只适合教学测试严禁用于任何需要保密的业务数据。在 MQTT 的发布/订阅模型下命令是「云端 → 设备」方向的消息。课程 README 用恒温器做了类比云端根据多个传感器的遥测数据做出决策后向设备发送「打开暖气」的命令设备端再通过执行器产生实际输出。二、定义命令主题server_command_topic设备端的第一步是在遥测主题定义之后声明命令主题。打开夜灯项目Raspberry Pi 直接编辑虚拟设备则需确保终端处于虚拟环境中在client_telemetry_topic定义之后添加server_command_topic id /commands这里的id是你此前为设备生成并填写在代码中的唯一标识如 GUID它同时被用于客户端名称、遥测主题和命令主题的命名起到命名空间隔离的作用。由于test.mosquitto.org是公共代理很多学习者共用同一 broker只有使用唯一 ID才能保证你的主题不会与他人冲突。server_command_topic就是设备要订阅的、用来接收 LED 控制命令的 MQTT 主题。对应仓库中的完整实现见 code-commands/virtual-device/nightlight/app.pyid ID client_telemetry_topic id /telemetry server_command_topic id /commands client_name id nightlight_client三、编写命令处理函数并订阅3.1handle_command解析 JSON 并驱动 LED在主循环之前、mqtt_client.loop_start()之后添加以下代码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这段代码做了三件事解码负载message.payload.decode()将 MQTT 消息的字节负载转为字符串json.loads(...)再将其解析为 Python 字典读取指令从字典中取出led_on键——服务端发送的{led_on: true}表示点亮 LED{led_on: false}表示熄灭 LED执行动作分别调用led.on()与led.off()驱动 Grove LED 执行器。随后mqtt_client.subscribe(server_command_topic)让客户端订阅命令主题mqtt_client.on_message handle_command将handle_command注册为消息到达时的回调函数。 关键细节on_message回调对所有已订阅主题都会触发。如果后续代码同时监听多个主题需要通过回调传入的message对象获取消息实际来自哪个主题即message.topic属性据此分发处理逻辑。3.2 回调执行在后台线程需要理解loop_start()与回调之间的关系。mqtt_client.loop_start()会启动一个后台线程持续处理网络收发与消息分发因此主线程中的while True:无限循环发布遥测可以与命令接收并行运行二者互不阻塞。这正是从源码中可以确认的设计mqtt_client.loop_start() def handle_command(client, userdata, message): ... 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)四、完整设备代码对照4.1 虚拟设备版本CounterFit仓库 code-commands/virtual-device/nightlight/app.py 给出了虚拟设备的完整实现import time from counterfit_connection import CounterFitConnection from counterfit_shims_grove.grove_light_sensor_v1_2 import GroveLightSensor from counterfit_shims_grove.grove_led import GroveLed import json import paho.mqtt.client as mqtt CounterFitConnection.init(127.0.0.1, 5000) light_sensor GroveLightSensor(0) led GroveLed(5) id ID client_telemetry_topic id /telemetry server_command_topic id /commands client_name id nightlight_client mqtt_client mqtt.Client(client_name) mqtt_client.connect(test.mosquitto.org) mqtt_client.loop_start() 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)虚拟设备版本与 Pi 版本的差异仅在于硬件抽象层虚拟设备通过counterfit_connection.CounterFitConnection.init(127.0.0.1, 5000)连接本机运行的 CounterFit 模拟应用传感器与 LED 均来自counterfit_shims_grove模拟库并在 CounterFit 界面中创建到对应引脚光敏传感器在引脚 0LED 在引脚 5。运行前务必保证 CounterFit 应用已启动且光敏传感器与 LED 已创建在正确引脚上。4.2 Raspberry Pi 版本真实硬件仓库 code-commands/pi/nightlight/app.py 提供了真实硬件的实现核心逻辑与虚拟设备完全一致仅替换了 Grove 驱动库import time from grove.grove_light_sensor_v1_2 import GroveLightSensor from grove.grove_led import GroveLed import json import paho.mqtt.client as mqtt light_sensor GroveLightSensor(0) led GroveLed(5) id ID client_telemetry_topic id /telemetry server_command_topic id /commands client_name id nightlight_client mqtt_client mqtt.Client(client_name) mqtt_client.connect(test.mosquitto.org) mqtt_client.loop_start() 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)两种环境下的handle_command、主题定义、订阅与回调注册逻辑完全同构这意味着你可以在 CounterFit 虚拟环境中完成调试后将同一套 MQTT 逻辑直接迁移到真实 Pi 硬件上。五、配套服务端命令从哪里来为了让命令真正「发得出去」课程还提供了一段运行在本地或 Pi 上的服务器代码见 code-commands/server/app.py。它订阅遥测主题根据光强阈值反向生成命令并发布import json import time import paho.mqtt.client as mqtt id ID client_telemetry_topic id /telemetry server_command_topic id /commands 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) 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 while True: time.sleep(2)关键点阈值逻辑command { led_on : payload[light] 300 }—— 当遥测光强小于 300 时led_on为True命令设备开灯否则为False命令关灯对称主题服务端用与设备端完全相同的id /commands主题发布命令这正是两端能对上暗号的根本原因⚠️ ID 一致性服务器代码中的ID必须与设备端使用的 ID 完全一致否则服务器订阅不到设备的遥测设备也收不到服务器发布的命令命令负载同样是 JSON 文本json.dumps编码与设备端json.loads(message.payload.decode())的解析一一对应。运行服务器后调整物理或虚拟设备的光照强度终端会交替打印遥测与命令LED 也随之亮灭例如(.venv) ➜ nightlight-server python app.py Message received: {light: 0} Sending message: {led_on: True} Message received: {light: 400} Sending message: {led_on: False}六、运行与验证先用前一课的方法运行设备端代码python app.py。虚拟设备环境请确认 CounterFit 已运行、光敏传感器与 LED 已就位Pi 环境无需虚拟环境。在另一个终端运行服务器代码同样python app.py。遮挡或照射光敏传感器改变检测到的光照水平。设备端终端会打印Message received: {...}LED 会按命令点亮或熄灭。整个闭环即告完成遥测上行设备 → broker→ 服务端决策 → 命令下行broker → 设备→ LED 动作。七、深入理解主题设计与多设备扩展课程 README 对命令主题设计给出了重要补充值得在实现时一并考虑单主题广播本文方案中所有设备共用id /commands这一条命令主题适合单设备或广播场景按设备拆分主题若需向特定设备下发命令可使用带唯一设备 ID 的多主题例如/commands/device1、/commands/device2让每台设备只订阅属于自己的主题例如id /commands与/commands/device1这类设计避免设备间命令串扰通配符订阅MQTT 主题支持层级与通配符例如订阅/commands/*可接收全部设备的命令也可利用message.topic区分来源QoS 等级MQTT 支持「至多一次 / 至少一次 / 恰好一次」三种服务质量命令类消息通常比遥测更依赖可靠投递可按需为subscribe/publish指定 QoS离线补偿MQTT 本身不提供消息队列设备断线重连后不会收到断开期间的消息若命令有先后顺序要求如机械臂先抬升再合拢夹爪需要在应用层设计确认与重放机制。八、小结至此你已经完成了「Internet 控制夜灯」项目在**单板计算机Raspberry Pi / 虚拟设备**上的全部设备端工作通过server_command_topic定义命令主题用handle_command回调解析 JSON 命令并驱动 Grove LED再借助loop_start()后台线程实现遥测发布与命令接收的并行。整个项目的源码分别存放在虚拟设备完整实现code-commands/virtual-device/nightlight/app.pyRaspberry Pi 完整实现code-commands/pi/nightlight/app.py服务端决策与命令发布实现code-commands/server/app.py若使用 ArduinoWio Terminal平台请参考同课的 wio-terminal-commands.md完整的课程背景与 MQTT 协议讲解见 课程 README。这套「遥测 命令」的发布/订阅模式是绝大多数物联网云控应用的通用骨架掌握后即可迁移到智能家居、远程监测等更多真实场景。【免费下载链接】IoT-For-Beginners12 Weeks, 24 Lessons, IoT for All!项目地址: https://gitcode.com/GitHub_Trending/io/IoT-For-Beginners创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表