基于行空板K10与SHT30传感器打造大屏温湿度监测终端

基于行空板K10与SHT30传感器打造大屏温湿度监测终端 1. 项目概述从“玩具”到“生产力工具”的蜕变最近在工作室折腾一个环境监测的小项目手头正好有一块行空板K10看着它那块2.8英寸的IPS大屏总觉得只用来跑跑例程、显示几行文字有点“屈才”了。市面上温湿度计不少但要么数据看不见摸不着要么功能单一。我就琢磨着能不能用这块板子结合常见的传感器做一个既有实时数据显示、又有历史曲线、还能超限告警的“大屏温湿度计”这想法一出来就收不住了。这不只是一个简单的数据读取显示更是一次将开源硬件从“学习验证”转向“实际应用”的尝试让手头的工具真正解决实际问题。行空板K10本身集成了Wi-Fi、蓝牙、丰富的GPIO接口和一块素质不错的屏幕这为我们打造一个联网的、智能的温湿度监测终端提供了绝佳的基础。而DHT22或SHT30这类数字温湿度传感器精度和可靠性也足以满足大多数室内环境监测的需求。这个项目的核心价值在于它演示了如何以极低的硬件成本和简单的代码构建一个功能完整、体验良好的数据可视化终端。无论是放在书房监控环境舒适度还是用于小型温室、设备机房的简易监测都非常实用。接下来我就把从硬件连接到软件实现再到界面美化和功能扩展的完整过程以及中间踩过的坑和总结的技巧毫无保留地分享出来。2. 硬件选型与连接稳定可靠的基石2.1 核心硬件解析为什么是它们工欲善其事必先利其器。硬件选型直接决定了项目的稳定性、精度和最终体验。主控行空板K10选择行空板K10而非更常见的树莓派Pico或Arduino主要基于三点考量。第一是集成度K10板载了显示屏、Wi-Fi模块、按键、蜂鸣器甚至麦克风开箱即用省去了额外连接屏幕和无线模块的繁琐工作和硬件成本。第二是性能与生态其采用的Linux系统与Python环境使得开发复杂逻辑和网络应用比在单片机MicroPython上更为顺畅丰富的Python库支持让图表绘制、网络请求等功能实现起来轻而易举。第三是供电便利一根Type-C线即可完成供电和编程调试部署位置非常灵活。传感器DHT22 vs SHT30这是两个非常流行的数字温湿度传感器。DHT22价格亲民单总线通信使用简单但其响应速度和精度在极端环境下可能稍逊一筹。SHT30作为新一代传感器使用I2C接口精度更高湿度±2%RH温度±0.2°C响应更快抗冷凝能力也更好当然价格也略高。对于室内环境监测DHT22完全够用如果项目用于对精度要求稍高的场合或者希望有更稳定的长期表现SHT30是更优的选择。本项目以SHT30为例进行讲解其思路完全适用于DHT22。其他物料杜邦线用于连接传感器与行空板。建议使用公对母的杜邦线连接牢固且方便。Type-C数据线用于供电和初始程序上传。可选外壳或亚克力支架让作品更美观也能保护电路。2.2 物理连接一步都不能错硬件连接是实操的第一步务必仔细。行空板K10的GPIO引脚标注清晰我们主要使用其I2C接口和电源引脚。给SHT30传感器接线SHT30通常有4个引脚VCC, GND, SDA, SCL。使用4根杜邦线按如下方式连接SHT30 VCC-行空板 3.3V引脚。非常重要务必接3.3V行空板的GPIO电平是3.3V接5V可能会损坏传感器或主板。SHT30 GND-行空板 GND引脚。SHT30 SDA-行空板 SDA引脚通常对应GPIO引脚图中的某个特定引脚例如Pin 8具体需查看行空板引脚定义图。SHT30 SCL-行空板 SCL引脚例如Pin 9。检查与上电连接完成后务必再次检查线序特别是VCC电压。确认无误后将Type-C线连接行空板并接入电源电脑USB口或5V/2A的充电器均可。行空板将自动启动。注意不同版本的行空板或传感器模块引脚排列可能略有不同。连接前一定要查阅你手头传感器的数据手册Datasheet和行空板的官方引脚定义图以“VCC/GND/SDA/SCL”的功能标识为准而不是单纯看颜色或位置。3. 软件环境搭建与基础驱动3.1 行空板系统初始化与编程准备行空板预装了基于Linux的系统。我们首先需要通过SSH或串口登录到板子进行操作。更推荐使用其自带的“行空板”客户端软件如果支持它提供了文件管理和终端模拟的集成环境。连接网络首次使用可能需要通过板载按键或客户端软件配置Wi-Fi让行空板接入局域网。确保你的电脑和行空板在同一个网络下。找到IP地址在行空板客户端或路由器后台查看行空板获取到的IP地址。SSH登录打开终端Windows可用PuTTYMac/Linux用系统终端输入ssh pi行空板IP地址。默认密码通常是pi或raspberry请以行空板官方文档为准。登录成功后你就进入了行空板的命令行界面。更新与安装必要工具建议先更新软件包列表。sudo apt-get update sudo apt-get upgrade -y安装常用的Python包管理工具pip如果尚未安装sudo apt-get install python3-pip -y3.2 传感器驱动库安装与测试我们需要Python库来驱动SHT30传感器。一个常用且稳定的库是adafruit-circuitpython-sht3x但需要先安装其依赖。安装Blinka库Adafruit的CircuitPython库在Linux单板电脑上运行需要Adafruit-Blinka。sudo pip3 install adafruit-blinka安装SHT30专用库sudo pip3 install adafruit-circuitpython-sht3x编写一个简单的测试脚本在行空板上创建一个Python文件例如test_sht30.py。nano test_sht30.py输入以下内容import time import board import adafruit_sht3x # 初始化I2C总线并创建传感器对象 i2c board.I2C() # 使用板载默认I2C引脚 sensor adafruit_sht3x.SHT3x(i2c) print(SHT30传感器测试) print() try: while True: temperature_c sensor.temperature # 摄氏度 humidity sensor.relative_humidity # 相对湿度百分比 print(f温度: {temperature_c:.2f} °C) print(f湿度: {humidity:.2f} %) print(- * 20) time.sleep(2) # 每2秒读取一次 except KeyboardInterrupt: print(\n程序退出。)按CtrlX然后按Y再按Enter保存并退出。运行测试python3 test_sht30.py如果一切正常终端将每隔2秒打印出当前的温度和湿度读数。这验证了硬件连接和驱动库都是正确的。如果出现I2C错误或找不到设备请返回检查硬件连接和I2C引脚定义。4. 图形界面GUI设计与实现让数据跃然屏上终端输出显然不是我们的目标。行空板的屏幕可以通过unihiker这个优秀的GUI库来驱动它专为行空板设计API简单易用。4.1 安装GUI库与创建基础窗口安装unihiker库sudo pip3 install unihiker规划界面布局一个直观的大屏温湿度计界面应该包含大号数字显示实时温湿度数值清晰醒目。图标与单位用图标如太阳、水滴和文字°C %增强可读性。历史趋势图显示最近一段时间如30分钟的数据变化曲线。状态提示根据预设的舒适范围显示“舒适”、“偏热”、“干燥”等状态。时间显示当前时间。编写基础GUI框架新建humiture_dashboard.py。from unihiker import GUI import time from datetime import datetime # 传感器驱动部分稍后引入 # 初始化GUI gui GUI() # 1. 绘制静态背景和标题 title gui.draw_text(x120, y20, text环境监测仪, font_size20, color#333333) # 2. 预留温湿度数值显示区域先用文本占位 temp_label gui.draw_text(x80, y80, text--.- °C, font_size48, color#FF6B6B) humi_label gui.draw_text(x200, y80, text--.- %, font_size48, color#4D96FF) # 3. 绘制图标可以使用文本符号或加载小图片 # 温度图标简易火焰符号 gui.draw_text(x50, y85, text, font_size30) # 湿度图标水滴符号 gui.draw_text(x170, y85, text, font_size30) # 4. 绘制历史图表区域用一个矩形框表示 chart_bg gui.draw_rect(x20, y150, w280, h120, color#F5F5F5, outline#CCCCCC, width2) # 5. 状态提示区域 status_label gui.draw_text(x120, y280, text状态初始化..., font_size16, color#666666) # 6. 时间显示 time_label gui.draw_text(x120, y310, text00:00:00, font_size14, color#999999) # 保持窗口运行 gui.wait()运行这个脚本你将看到一个基本的界面框架。但这只是静态的我们需要让它动起来。4.2 动态数据更新与图表绘制动态更新的核心是定时器threading.Timer或sched和数据的全局管理。我们将创建一个数据队列来存储最近的历史数据并定时更新界面。整合传感器读取与数据管理import board import adafruit_sht3x from collections import deque import threading # 初始化传感器 i2c board.I2C() sensor adafruit_sht3x.SHT3x(i2c) # 定义数据队列存储最近N个数据点用于绘图 HISTORY_MAXLEN 30 # 存储30个点假设每10秒一个点即5分钟历史 time_history deque(maxlenHISTORY_MAXLEN) temp_history deque(maxlenHISTORY_MAXLEN) humi_history deque(maxlenHISTORY_MAXLEN) def read_sensor_data(): 读取一次传感器数据并存入历史队列 try: temp_c sensor.temperature humi sensor.relative_humidity current_time datetime.now().strftime(%H:%M:%S) # 存入历史 time_history.append(current_time) temp_history.append(temp_c) humi_history.append(humi) return temp_c, humi except Exception as e: print(f读取传感器失败: {e}) return None, None创建数据更新与界面刷新函数def update_display(): 定时执行的任务读取数据并更新所有UI组件 temp, humi read_sensor_data() if temp is not None and humi is not None: # 1. 更新大数字显示 temp_label.config(textf{temp:.1f} °C) humi_label.config(textf{humi:.1f} %) # 2. 更新状态提示 status evaluate_comfort(temp, humi) status_label.config(textf状态{status[text]}, colorstatus[color]) # 3. 更新图表需要先清空旧图再重绘 update_chart() # 4. 更新时间 current_time_str datetime.now().strftime(%H:%M:%S) time_label.config(textcurrent_time_str) # 5. 设置下一个定时器实现循环例如每2秒更新一次 threading.Timer(2.0, update_display).start() def evaluate_comfort(t, h): 根据温湿度评估舒适度状态规则可自定义 if 18 t 26 and 40 h 60: return {text: 舒适, color: #52C41A} elif t 26: return {text: 偏热, color: #FAAD14} elif t 18: return {text: 偏冷, color: #1890FF} elif h 40: return {text: 干燥, color: #FFA940} else: return {text: 潮湿, color: #722ED1} def update_chart(): 绘制历史数据折线图简化版使用draw_line拼接 # 首先清除图表区域内的旧线条一个取巧的方法用背景色矩形覆盖 gui.draw_rect(x21, y151, w278, h118, color#F5F5F5, outline#F5F5F5) if len(temp_history) 2: return # 计算绘图坐标将数据映射到图表区域的像素坐标 chart_x_start, chart_y_start, chart_w, chart_h 21, 151, 278, 118 # 找到温度和历史数据的最大最小值用于归一化 temp_min, temp_max min(temp_history), max(temp_history) humi_min, humi_max min(humi_history), max(humi_history) # 防止除零 temp_range temp_max - temp_min if temp_max ! temp_min else 1 humi_range humi_max - humi_min if humi_max ! humi_min else 1 # 绘制温度曲线红色 points_temp [] for i, val in enumerate(temp_history): x chart_x_start (i / (len(temp_history) - 1)) * (chart_w - 1) if len(temp_history) 1 else chart_x_start y chart_y_start chart_h - ((val - temp_min) / temp_range) * chart_h points_temp.append((x, y)) for i in range(len(points_temp) - 1): gui.draw_line(x0points_temp[i][0], y0points_temp[i][1], x1points_temp[i1][0], y1points_temp[i1][1], width2, color#FF6B6B) # 绘制湿度曲线蓝色- 可选为避免重叠可以分开两个小图或使用右侧Y轴 # 这里简单演示在同一区域用不同颜色绘制实际应用可能需要更复杂的坐标变换 # points_humi [] # for i, val in enumerate(humi_history): # x chart_x_start (i / (len(humi_history) - 1)) * (chart_w - 1) # y chart_y_start chart_h - ((val - humi_min) / humi_range) * chart_h # points_humi.append((x, y)) # for i in range(len(points_humi) - 1): # gui.draw_line(x0points_humi[i][0], y0points_humi[i][1], # x1points_humi[i1][0], y1points_humi[i1][1], # width2, color#4D96FF)启动定时更新在gui.wait()之前添加一行代码启动第一次更新。# 启动第一次数据更新之后会由定时器循环触发 update_display() gui.wait()现在运行完整的脚本你将看到一个动态更新的温湿度计界面数字每2秒刷新状态根据规则变化底部还会绘制出温度的历史趋势曲线。虽然这个图表比较简单但已经实现了核心的数据可视化功能。5. 功能增强与优化从“能用”到“好用”基础功能实现后我们可以从稳定性、实用性和扩展性上进行优化。5.1 数据持久化与历史查询将数据保存下来才能分析长期趋势。最简单的方法是使用SQLite数据库或CSV文件。使用SQLite存储数据import sqlite3 from datetime import datetime def init_database(): conn sqlite3.connect(/home/pi/humiture_data.db) # 数据库文件路径 c conn.cursor() c.execute(CREATE TABLE IF NOT EXISTS sensor_data (id INTEGER PRIMARY KEY AUTOINCREMENT, timestamp DATETIME DEFAULT CURRENT_TIMESTAMP, temperature REAL, humidity REAL)) conn.commit() conn.close() def save_data_to_db(temp, humi): conn sqlite3.connect(/home/pi/humiture_data.db) c conn.cursor() c.execute(INSERT INTO sensor_data (temperature, humidity) VALUES (?, ?), (temp, humi)) conn.commit() conn.close()在read_sensor_data函数成功读取数据后调用save_data_to_db(temp_c, humi)。优化读取频率对于历史存储不需要像界面刷新2秒那么高频。可以设置一个单独的定时器每60秒或300秒存储一次数据避免数据库过快膨胀。5.2 网络功能与远程访问行空板有Wi-Fi我们可以让它成为一个简单的Web服务器在手机或电脑浏览器上查看数据。使用Flask创建微型Web APIfrom flask import Flask, jsonify import threading # 在全局初始化Flask app注意不要在主线程中运行 web_app Flask(__name__) web_app.route(/api/current) def get_current_data(): # 从全局变量或最近一次读取中获取数据 latest_temp temp_history[-1] if temp_history else None latest_humi humi_history[-1] if humi_history else None return jsonify({ temperature: latest_temp, humidity: latest_humi, timestamp: datetime.now().isoformat() }) web_app.route(/api/history) def get_history_data(): # 从数据库查询最近N条记录 conn sqlite3.connect(/home/pi/humiture_data.db) c conn.cursor() c.execute(SELECT timestamp, temperature, humidity FROM sensor_data ORDER BY id DESC LIMIT 100) rows c.fetchall() conn.close() history [{time: r[0], temp: r[1], humi: r[2]} for r in rows] return jsonify(history) def run_web_server(): # 在子线程中运行Flask默认端口5000 web_app.run(host0.0.0.0, port5000, debugFalse, threadedTrue) # 在主程序启动时开启Web服务器线程 web_thread threading.Thread(targetrun_web_server, daemonTrue) web_thread.start()启动程序后在同一局域网的设备上浏览器访问http://行空板IP:5000/api/current即可看到JSON格式的实时数据。5.3 界面美化与交互优化使用图片资源用更精美的PNG图标替换文本符号。将图片文件上传到行空板使用gui.draw_image()加载。添加交互按钮利用行空板的触摸屏可以添加按钮来切换显示模式如温度/湿度曲线切换、清除历史、或进入配置页面。# 示例添加一个切换按钮 def toggle_chart(): global show_temp_chart show_temp_chart not show_temp_chart update_chart() # 重绘图表 toggle_btn gui.add_button(x260, y20, text切换, onclicktoggle_chart)优化图表绘制上述的draw_line方式绘制复杂图表效率较低。可以考虑使用matplotlib生成图表图片然后显示在屏幕上但这需要更多的系统资源。对于行空板折中的办法是使用专门的轻量级绘图库或者继续优化我们的简易绘图函数。6. 部署、调试与常见问题6.1 设置开机自启动我们希望设备上电后就能自动运行这个温湿度计程序。创建系统服务推荐在行空板上创建服务文件。sudo nano /etc/systemd/system/humiture-dashboard.service输入以下内容[Unit] DescriptionHumiture Dashboard Service Afternetwork.target [Service] Typesimple Userpi WorkingDirectory/home/pi ExecStart/usr/bin/python3 /home/pi/humiture_dashboard.py Restarton-failure RestartSec10 [Install] WantedBymulti-user.target注意修改WorkingDirectory和ExecStart的路径为你脚本存放的实际位置。启用并启动服务sudo systemctl daemon-reload sudo systemctl enable humiture-dashboard.service sudo systemctl start humiture-dashboard.service使用sudo systemctl status humiture-dashboard.service检查服务状态。6.2 常见问题与排查技巧问题运行脚本提示“No module named board”或“No module named adafruit_sht3x”。排查说明Python库没有安装成功或不在当前Python路径。确保使用sudo pip3 install进行安装。尝试在Python交互环境中import board测试。问题传感器读取失败I2C地址错误。排查SHT30的默认I2C地址是0x44也有可能是0x45。可以使用i2cdetect工具扫描。sudo apt-get install i2c-tools -y sudo i2cdetect -y 1查看输出中是否有44或45出现。然后在代码中初始化传感器时可以指定地址sensor adafruit_sht3x.SHT3x(i2c, address0x45)。问题GUI界面卡顿或无响应。排查定时器阻塞确保update_display函数中的操作尤其是绘图和数据库操作执行时间远小于定时间隔如2秒。耗时的操作如复杂图表计算、大量数据库查询应放到单独的线程或降低执行频率。内存泄漏避免在定时回调中不断创建新的GUI对象而不删除。更新内容应尽量使用widget.config()修改现有组件绘图时注意清理旧图形。简化图表如果历史数据点很多用draw_line逐段绘制会非常慢。可以尝试减少历史数据点数HISTORY_MAXLEN或改为只绘制点。问题Web页面无法访问。排查检查行空板IP地址是否变化。检查防火墙是否屏蔽了5000端口行空板默认一般没有防火墙。查看Flask服务是否成功启动是否有错误日志程序输出中查看。问题数据读数异常如湿度始终99%。排查这很可能是传感器硬件问题或接触不良。首先检查所有连接是否牢固。尝试用之前的test_sht30.py脚本单独测试传感器。如果问题依旧可能是传感器损坏尤其是DHT22对静电敏感易损坏。6.3 性能优化与资源管理心得绘图是性能瓶颈unihiker的draw_line,draw_circle等函数每次调用都有开销。在绘制动态图表时最好的策略是“增量更新”或“双缓冲”。例如我们上面用背景色矩形覆盖旧图表区域再重绘就是一种简单的全量重绘数据点少时可行多了就卡。更优的方案是只绘制新的数据点连接到旧的线段末端但这需要更精细的状态管理。数据库操作的优化如果存储频率高直接每次插入一条记录可能影响性能。可以考虑在内存中缓存一定数量的数据点每隔一段时间批量写入数据库。线程安全当使用多线程如GUI主线程、传感器读取线程、Web服务器线程时对共享数据如temp_history,humi_history的访问需要加锁threading.Lock防止数据错乱。电源管理如果使用电池供电需要考虑功耗。可以降低屏幕亮度如果支持、减少传感器读取和屏幕刷新频率甚至让屏幕在无操作一段时间后休眠。经过以上步骤一个功能相对完整、界面直观、且具备网络访问能力的“大屏温湿度计”就真正完成了。它不再是一个简单的演示程序而是一个可以持续运行、提供价值的小工具。这个项目最大的收获不在于实现了某个具体功能而在于完整走通了从硬件选型、驱动调试、数据处理、界面交互到系统部署的全流程。每一个环节遇到的问题和解决方案都是宝贵的经验。你可以在此基础上继续扩展比如增加MQTT上报至物联网平台、添加更多传感器如大气压强、空气质量、设计更炫酷的UI动画甚至用这块屏幕显示天气预报。硬件项目的乐趣就在于这种不断迭代和创造的过程中。