news 2026/9/16 18:03:38

IoT-For-Beginners 智慧农场实战:Raspberry Pi 与虚拟设备通过 MQTT 发布温度遥测数据

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
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

本篇指南基于 IoT-For-Beginners 课程第 2 周农场场景(预测植物生长)中"发布温度"这一实战环节,讲解如何把 Raspberry Pi 或虚拟 IoT 设备(CounterFit)上 DHT11 传感器采集到的温度值,通过 MQTT 发布到公共 Broker,供服务端订阅并存储,最终用于计算植物的生长度日(GDD,Growing Degree Days)。学完本篇,你将掌握:复用第 4 课的 MQTT 连接模式改造遥测应用、按正确字段名与 JSON 结构发布温度数据、为传感器轮询设定合理的休眠周期,并在真实 Pi 与虚拟设备两种环境下验证发布结果。

背景:为什么要把温度发出去

在 预测植物生长课程 中,温度是计算 GDD 的核心输入。GDD 的简化公式为:

  • Tmax—— 当日最高温度(摄氏度)
  • Tmin—— 当日最低温度(摄氏度)
  • Tbase—— 该植物的基础温度(base temperature),如草莓约为 10°C

要算出当日的 GDD,就必须持续、长期地收集温度数据。因此本课的架构是:IoT 设备测量温度后,通过 MQTT 把遥测数据(telemetry)发布到互联网上的 Broker;服务端代码订阅这些数据并追加保存到 CSV 文件,之后(例如夜间任务)再基于历史数据计算 GDD、累计作物生长进度并在接近成熟时发出告警。原文档中对这一步的概括是:温度被读取后,就可以通过 MQTT 发布给某个"服务端"代码,由它读取数值并存储好,等待被用于 GDD 计算。

本篇对应的正是整个链路中的"设备侧发布"环节,官方指南为 single-board-computer-temp-publish.md,适用对象是Raspberry Pi 单板计算机虚拟 IoT 设备(使用 Seeed 的 CounterFit 应用模拟硬件);Wio Terminal(Arduino)走的是另一份指南 wio-terminal-temp-publish.md。

前提:已建好的 temperature-sensor 项目

发布温度之前,你需要已经完成本课前面"测量温度"的小节,拥有一个名为temperature-sensor的项目,其中app.py能够读取 DHT11 传感器并打印温度。Pi 与虚拟设备两条路线的前置条件分别见:

  • Raspberry Pi 路线:pi-temp.md —— DHT11 Grove 传感器插在 Grove Base Hat 的数字口D5上,代码侧通过pip3 install seeed-python-dht安装驱动,并创建sensor = DHT("11", 5)实例(第一个参数指定 DHT11 型号,第二个参数指定 D5 引脚),用sensor.read()返回(humidity, temperature)元组。
  • 虚拟设备路线:virtual-device-temp.md —— 安装counterfit-shims-seeed-python-dht垫片包,并在 CounterFit 应用中创建两个传感器:湿度传感器放在 Pin 5、温度传感器放在 Pin 6(shim 会把DHT("11", 5)模拟为这两个组合传感器),代码以counterfit_shims_seeed_python_dht替代seeed_dht导入DHT类。

任务:改造程序以发布温度数据

按原文档,任务是"给设备编程,让它发布温度数据"。完整步骤如下。

第 1 步:打开项目,复用第 4 课的 MQTT 连接步骤

打开temperature-sensor应用项目(如尚未打开)。然后重复你在 第 4 课"连接互联网" 中做过的两件事:连接 MQTT Broker发送遥测,使用的仍然是同一个公共 Mosquitto Broker(test.mosquitto.org)。这两步各自包含的细分为:

  • 添加 MQTT 的 pip 包:pip3 install paho-mqtt
  • 添加连接 MQTT Broker 的代码
  • 添加发布遥测的代码

如果需要回看细节,可参考第 4 课的两份指南:single-board-computer-mqtt.md(连接 MQTT)与 single-board-computer-telemetry.md(发送遥测)。其中与本项目直接相关的要点:

  • app.py顶部导入import paho.mqtt.client as mqtt
  • test.mosquitto.org是公共 Broker,很多使用者(包括其他学习本课程的同学)同时在线,因此必须给自己分配一个唯一 ID作为客户端名和主题名的前缀,避免与他人的客户端/主题冲突;
  • client_name是本 MQTT 客户端在 Broker 上的唯一名称;
  • mqtt_client.connect('test.mosquitto.org')建立连接,mqtt_client.loop_start()启动后台线程处理订阅消息。

第 2 步:让 client_name 体现本项目名称

把第 4 课小夜灯项目里的客户端名后缀改成本项目的名称:

client_name = id + 'temperature_sensor_client'

从仓库中 Pi 版完整示例 code-publish-temperature/pi/temperature-sensor/app.py 可以看到,与客户端名配套的主题定义是:

id = '<ID>' client_telemetry_topic = id + '/telemetry' client_name = id + 'temperature_sensor_client' mqtt_client = mqtt.Client(client_name) mqtt_client.connect('test.mosquitto.org') mqtt_client.loop_start() print("MQTT connected!")

注意<ID>需要替换成你自己的唯一标识(可以用 GUID 生成器等工具产生),这个 ID 之后写服务端订阅代码时还会用到——客户端与服务端必须共用同一个 ID 才能对上同一个/telemetry主题。

第 3 步:发布温度遥测(字段名为 temperature)

与第 4 课发送光照值({'light': ...})不同,这里要发送从 DHT 传感器读到的温度值,放在 JSON 文档中名为temperature的属性上:

_, temp = sensor.read() telemetry = json.dumps({'temperature' : temp})

这里sensor.read()返回(湿度, 温度)元组,下划线丢弃湿度,temp是摄氏温度。json.dumps把它编码成 JSON 字符串,如{"temperature": 25}。这个字段名不是随意的:服务端代码在解析消息时会直接按payload['temperature']取值(见下文服务端剖析),字段名不一致会导致KeyError

第 4 步:把轮询间隔设为 10 分钟

温度值不需要高频读取——短时间内变化很小,所以把time.sleep设为 10 分钟:

time.sleep(10 * 60)

time.sleep为单位,因此传一个计算式的结果:60 秒/分钟 × 10 分钟 = 600 秒。这个低频策略同时兼顾了数据用途(GDD 只关心每日最高/最低温)和设备能耗。

第 5 步:运行并验证

像之前运行本项目代码的方式一样运行:Pi 上在用户家目录的temperature-sensor文件夹里执行python3 app.py;虚拟设备则在激活虚拟环境的终端中执行python app.py,并确保CounterFit 应用在运行湿度与温度传感器已创建在正确引脚(湿度 Pin 5、温度 Pin 6)。

预期输出:

pi@raspberrypi:~/temperature-sensor $ python3 app.py MQTT connected! Sending telemetry {"temperature": 25} Sending telemetry {"temperature": 25}

看到MQTT connected!与每 10 分钟一次的Sending telemetry {"temperature": ...}日志,即表示温度已成功作为遥测从设备发布出去。如果用的是虚拟设备,建议在 CounterFit 里勾选Random复选框并设置一个 Min/Max 区间(参考课程中的截图 select-the-random-checkbox-and-set-a-range.png),这样每次读取会得到不同的温度值,便于后续验证服务端是否正确累计了多条记录。

💡 完整可运行代码可在仓库中找到:code-publish-temperature/virtual-device(虚拟设备版)或 code-publish-temperature/pi(Pi 版)。

源码纵深:客户端完整代码剖析

把上面 5 步合起来,Pi 版 app.py 全文只有 28 行,结构非常清晰:

import time from seeed_dht import DHT import paho.mqtt.client as mqtt import json sensor = DHT("11", 5) id = '<ID>' client_telemetry_topic = id + '/telemetry' client_name = id + 'temperature_sensor_client' mqtt_client = mqtt.Client(client_name) mqtt_client.connect('test.mosquitto.org') mqtt_client.loop_start() print("MQTT connected!") while True: _, temp = sensor.read() telemetry = json.dumps({'temperature' : temp}) print("Sending telemetry ", telemetry) mqtt_client.publish(client_telemetry_topic, telemetry) time.sleep(10 * 60)

几个值得注意的实现细节:

  • 连接是一次性的,发布是循环的connect/loop_startwhile True之外只执行一次;循环体内依次是"读传感器 → 编码 JSON → 打印 → publish → 休眠"。paho 的loop_start()让网络收发在后台线程进行,因此即使主线程sleep600 秒也不会丢失连接处理。
  • 虚拟设备版与 Pi 版仅两处差异:对比 虚拟设备版 app.py,它额外在前两行初始化 CounterFit 连接(CounterFitConnection.init('127.0.0.1', 5000)),并把传感器库从seeed_dht换成垫片包counterfit_shims_seeed_python_dht,其余 MQTT 逻辑完全一致。这说明"应用层代码与硬件解耦"是本课程的刻意设计:同一套发布逻辑可以无缝跑在真机与模拟器上。
  • time.sleep(10 * 60)位于 publish 之后:先发送再休眠,保证程序启动后立即产生第一条遥测,而不是空等 10 分钟。

数据流向哪:服务端订阅与 CSV 落盘

发布的温度并不是终点。同一课程提供了一份配套服务端代码 code-server/temperature-sensor-server/app.py,它展示了设备侧发布的数据如何被消费,理解它对把握"发布端字段约定"很有帮助:

client_telemetry_topic = id + '/telemetry' server_command_topic = id + '/commands' client_name = id + 'temperature_sensor_server' mqtt_client = mqtt.Client(client_name) mqtt_client.connect('test.mosquitto.org') mqtt_client.loop_start() temperature_file_name = 'temperature.csv' fieldnames = ['date', 'temperature'] if not path.exists(temperature_file_name): with open(temperature_file_name, mode='w') as csv_file: writer = csv.DictWriter(csv_file, fieldnames=fieldnames) writer.writeheader() def handle_telemetry(client, userdata, message): payload = json.loads(message.payload.decode()) print("Message received:", payload) with open(temperature_file_name, mode='a') as temperature_file: temperature_writer = csv.DictWriter(temperature_file, fieldnames=fieldnames) temperature_writer.writerow({'date' : datetime.now().astimezone().replace(microsecond=0).isoformat(), 'temperature' : payload['temperature']}) mqtt_client.subscribe(client_telemetry_topic) mqtt_client.on_message = handle_telemetry

从源码结构看,服务端做三件与设备侧呼应的事:

  1. 同名主题订阅subscribe(id + '/telemetry'),即设备端 publish 的那个主题。两边id必须一致,这是公共 Broker 上避免串数据的关键约定;
  2. 服务端自己补时间戳:很多 IoT 设备缺乏可靠的时钟,所以 CSV 中的date列取的是服务端收到消息的时刻(带时区、去掉微秒的 ISO 8601 格式),而非设备端时间;
  3. 追加写入 CSV:文件不存在时先建表头date,temperature,之后每条消息append一行。这正是 README 中"服务端代码可以增强数据(augment the data)"的体现——设备只发温度,位置、时间等上下文由服务端补齐。

积累一天的数据后(理想情况),就可按 课程 README 中的方法找出当日最高/最低温并套用 GDD 公式,最终用 Jupyter Notebook 作业 可视化 GDD 数据。

常见问题与注意事项

  • ID 不唯一:公共 Broker 上若客户端名或主题与他人重复,会互相干扰甚至导致断连。务必使用唯一 ID,并在设备端与服务端保持一致。
  • 虚拟设备传感器引脚DHT("11", 5)在 CounterFit 中隐含要求湿度传感器在 Pin 5、温度传感器在 Pin 6(shim 假设温度传感器在"下一个引脚")。只建了温度传感器会导致读数异常。
  • sleep 单位是秒time.sleep(10 * 60)是 600 秒。调试时可以先改成更短的值(如 10 秒)快速验证,确认无误后再改回 10 分钟。
  • 长时间采集:如果计划让服务端连续运行一整天采集 GDD 数据,需要确保运行服务端代码的电脑不会进入睡眠(调整电源设置或运行保持唤醒的脚本)。

小结

本篇完成了"预测植物生长"课程中设备侧的关键一步:temperature-sensor应用从"打印温度"升级为"通过 MQTT 发布{"temperature": ...}遥测",核心改动只有三处——客户端名id + 'temperature_sensor_client'、遥测字段改为temperature、休眠周期拉长到 10 分钟;发布链路复用第 4 课的paho-mqtt+test.mosquitto.org模式。数据落地端(服务端订阅 + CSV 落盘)的对应代码在 code-server/temperature-sensor-server 中可以直接对照阅读,两者拼合起来就是"传感器 → MQTT → 存储 → GDD 计算"这条数字农业数据链的完整最小实现。

【免费下载链接】IoT-For-Beginners12 Weeks, 24 Lessons, IoT for All!项目地址: https://gitcode.com/GitHub_Trending/io/IoT-For-Beginners

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/16 18:02:41

STM32F103智能小车闭环控制:红外循迹+超声波避障实战

简介&#xff1a;本资源是一套基于STM32F103微控制器的智能循迹避障小车完整工程代码包&#xff0c;面向嵌入式初学者、课程设计学生及智能硬件实践者&#xff0c;解决红外自主循迹与超声波实时避障停车两大核心控制问题。压缩包含192个文件&#xff0c;以34个C源文件&#xff…

作者头像 李华
网站建设 2026/9/16 18:02:31

Wan2.1 LoRA训练与推理实战:从原理到显存优化全解析

Wan2.1&#xff0c;也就是通义万相2.1这套开源权重&#xff0c;发布之后热度一直没降。我用它做了一阵子风格化生成&#xff0c;底模能力确实在线&#xff0c;但很快发现一个问题&#xff1a;我想要稳定的产品拍摄风格、固定的人物外观&#xff0c;或者某一种贯穿全片的色调习惯…

作者头像 李华
网站建设 2026/9/16 18:00:46

PLC三轴点胶机运动控制:脉冲当量、插补与回零补偿详解

简介&#xff1a;这是一份面向PLC自动化工程师与初学者的三轴控制实验资料包&#xff0c;聚焦点胶机与三维运动控制场景。内容围绕PLC三轴运动程序、三轴点胶机控制及运动控制基础展开&#xff0c;涵盖位置、速度、压力控制与PID调节等关键知识点&#xff0c;可为理解三轴联动调…

作者头像 李华
网站建设 2026/9/16 18:00:09

自然语言处理中上下文长度的原理与应用

1. 上下文长度的本质解析上下文长度&#xff08;Context Length&#xff09;在自然语言处理领域指的是模型能够同时考虑和处理的文本范围。这个概念最早源于传统N-gram语言模型&#xff0c;当时受限于计算能力&#xff0c;通常只能处理3-5个连续词&#xff08;即3-gram或5-gram…

作者头像 李华