ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

树莓派B+环境监测实战:换源、DHT22与Flask Web服务器

树莓派B+环境监测实战:换源、DHT22与Flask Web服务器 简介面向树莓派 B 初学者的实用资料包围绕换源、中文显示、DHT22 温湿度驱动、搭建 Web 服务器四个典型场景展开适合物联网、嵌入式、自动化等方向的在校生或课程设计使用。包内每个 demo 都配有 docx 操作文档并附可运行 Python 代码、项目说明和必要授权信息既能帮助新手理清环境配置与外设控制的基本流程也可作为课设、作业或项目初期的演示素材。全部文件共 7 个以 4 份 docx 说明文档为主结合 py 脚本、md 说明与 txt 文本压缩包仅 895KB内容紧凑、结构清晰下载后可按文档顺序逐步实践。目前已有约 150 人浏览学习其价值在于把换源、中文字体、DHT22 数据读取到 Web 服务这些常见需求成套整理并给出详细步骤与可执行代码适合想快速复现、深入理解树莓派基础开发的读者。1. 树莓派B的四个demo为什么从换源和中文显示开始一块树莓派B吃灰两三年很多人会直接说它跑不动。其实它做家庭环境监测站正合适功耗不到1WGPIO直连DHT22再挂一个Flask页面一晚上就能把温度湿度画成曲线。这四个demo——换源、中文显示、驱动DHT22、搭建web服务器恰好对应了玩树莓派最常用的四条路系统层的源和locale外设层的GPIO读取应用层的HTTP服务。单拆开都不难但串起来能让你摸清从apt到浏览器的完整链路。这套操作适合刚入手树莓派的同学也适合把手里的旧B重新翻出来的熟手。2. 树莓派换源与中文显示先把系统的“地基”调顺2.1 换源前先认清树莓派B的源长什么样树莓派B默认跑的是Raspbian系统软件源写在两处主系统源在/etc/apt/sources.list树莓派基金会自己的源在/etc/apt/sources.list.d/raspi.list。后者用来管raspi-config、rpi-update等包只换前者会导致部分包还是从海外服务器拉速度依旧上不去。先确认当前系统的版本代号再决定换源时该填哪个目录lsb_release -cs cat /etc/apt/sources.list cat /etc/apt/sources.list.d/raspi.listlsb_release -cs会输出类似buster或stretch的代号。B这类老设备常见的是Buster也有从Stretch升上来的。换源时要让镜像站目录和代号一致不然apt update会报404。2.2 动手换源备份、修改、更新换源前先备份这是最稳妥的习惯。下面用mirrors.tuna.tsinghua.edu.cn做例子你可以换成自己测速后延迟最低的镜像站sudo cp /etc/apt/sources.list /etc/apt/sources.list.bak sudo cp /etc/apt/sources.list.d/raspi.list /etc/apt/sources.list.d/raspi.list.bak sudo sed -i s|^deb http://raspbian.raspberrypi.org/raspbian/|deb http://mirrors.tuna.tsinghua.edu.cn/raspbian/raspbian/| /etc/apt/sources.list sudo sed -i s|^deb http://archive.raspberrypi.org/debian/|deb http://mirrors.tuna.tsinghua.edu.cn/raspberrypi/| /etc/apt/sources.list.d/raspi.list sudo apt update这段命令用sed做前缀替换第一行把系统主源指向清华镜像第二行把树莓派官方源也指过去。|作为分隔符是为了避开URL里的斜杠避免转义麻烦。执行后再apt update如果出现Release file is not valid yet先检查系统时间老主板电池没电会导致时钟漂移。注意raspi.list文件里可能有deb-src开头或带#[signed-by...]参数的行替换前缀时不要误伤。更安全的做法是用nano打开文件手动改只替换域名部分。2.3 中文显示安装字体和配置locale换完源后中文显示才真正有安装依赖的基础。B上中文乱码核心是两个原因系统没有中文字体以及locale没有生成中文编码。很多人只调locale不装字体结果依旧显示方框。执行以下步骤sudo apt install -y fonts-wqy-zenhei fonts-wqy-microhei sudo apt install -y locales sudo sed -i s/# zh_CN.UTF-8 UTF-8/zh_CN.UTF-8 UTF-8/ /etc/locale.gen sudo locale-gen sudo update-locale LANGzh_CN.UTF-8fonts-wqy-zenhei是文泉驿正黑fonts-wqy-microhei是微米黑体积不大带桌面环境的B装这两个足够日常显示。locale.gen里的# zh_CN.UTF-8 UTF-8默认是注释掉的去掉注释后执行locale-gen才会生成对应的中文locale。最后update-locale设置全局默认语言。需要注意如果你用的是无桌面精简版系统设置LANGzh_CN.UTF-8后纯命令行的ncurses界面可能显示异常。这时优先保留en_GB.UTF-8只在需要显示中文的程序里临时设置语言环境。2.4 验证中文显示和排查乱码验证是否成功看下面几点date fc-list :langzh | head localedate如果能输出中文星期和月份并且fc-list列出中文字体说明系统级中文显示已经就绪。SSH客户端如果还是看到乱码多半是客户端字体或编码问题和树莓派无关。下面是一个常见问题的排查表我在老板子上遇到过好几次。表现原因操作网页显示方框缺中文字体apt install fonts-wqy-zenhei程序输出??locale未生成检查locale -a是否有zh_CN.utf8SSH终端中文乱码客户端未用UTF-8编码把SSH终端编码切到UTF-8命令行界面花屏无桌面系统强行设置中文locale保留en_GB.UTF-8程序内单独指定zh_CN.UTF-83. 树莓派驱动DHT22从接线到用gpiozero读温湿度3.1 DHT22信号线和GPIO为什么B需要精准时序DHT22是单总线数字温湿度传感器数据线只占一个GPIO脚但读取难度比I2C高不少。因为DHT22拉的信号宽度是微秒级0和1的区别只在高电平维持时间上Linux内核调度稍微一抖读出来的值就是None或乱码。树莓派B是单核700MHz跑桌面系统时更容易出现这种问题。接线很简单DHT22的VCC接3.3VGND接GNDDATA接BCM编号的GPIO4物理第7脚。数据线和3.3V之间要接一个4.7kΩ上拉电阻。没有上拉电阻的话信号沿会变缓读数经常失败。B是老板子很多教程直接用RPi.GPIO软件时序去读建议放弃这条路改用pigpio守护进程。3.2 安装pigpio和gpiozero并启动守护进程gpiozero是树莓派官方外设库它的DHT22组件在use_pigpioTrue模式下会通过pigpio读取时序由内核级线程保证稳定得多。sudo apt install -y pigpio python3-gpiozero sudo pigpiod安装后启动pigpiod它会在后台打开一个守护进程默认监听8888端口gpiozero通过这个端口向pigpio请求读取GPIO状态。检查进程是否存活pgrep pigpiod如果树莓派B用的是systemd版本可以直接设置开机自启sudo systemctl enable pigpiod这样就算断电重启也避免手动敲pigpiod。3.3 写一个可用的DHT22读取程序下面是一个带重试的读取脚本我在B上验证过能稳定读到值#!/usr/bin/env python3 from gpiozero import DHT22 from time import sleep DHT_PIN 4 sensor DHT22(DHT_PIN, use_pigpioTrue) def read_sensor(): for i in range(5): t sensor.temperature h sensor.humidity if t is not None and h is not None: print(f温度: {t:.2f} C, 湿度: {h:.2f} %) return t, h sleep(1) print(读取失败请检查上拉电阻和接线) return None, None if __name__ __main__: read_sensor()sensor对象放在__main__外避免每次调用都重新初始化GPIO。DHT22构造函数的use_pigpioTrue是关键参数它告诉gpiozero不要用软件时序而是把读取请求发给pigpiod。循环重试5次每次间隔1秒因为DHT22两次通信之间需要拉高一段恢复时间太频繁读取必然失败。3.4 读取失败的重试机制与信号完整性DHT22偶尔丢失响应是常态不是代码写错。常见原因有三个第一次上电后传感器需要2秒稳定立刻读取会返回None线路接触不良缺失上拉电阻。如果你把程序写到一半发现永远读不到用万用表量GPIO4对地电压空闲时应接近3.3V。低于2.5V基本可以确定上拉电阻没接。也可以换一个GPIO口试试BCM4和BCM17都方便接线。下表给出排查方向现象可能原因操作连续读不到上拉电阻没接加4.7kΩ上拉至3.3V偶尔返回None读取间隔太短sleep至少1秒地址或程序报GPIO忙上一次实例未释放重启程序或调用sensor.close()读数跳变离谱电源噪声VCC和GND之间加0.1uF电容4. 树莓派搭建Web服务器用Flask把DHT22数据推到浏览器4.1 为什么选用Flask而不是Apache/nginxB内存512MB跑一个Nginx一点问题没有但Nginx本身没有传感器驱动能力动态内容还得靠PHP或uWSGI中转。Flask是纯Python可以直接在进程里调用gpiozero读取DHT22省掉一层轮询和缓存。开发模式下Flask自带Werkzeug服务器处理内网几台设备的并发足够没必要再加一层反代。如果你的目标是“树莓派搭建web服务器”做一个能长期跑的demo我会推荐结构是Flask只负责提供HTTP接口数据写入SQLite后面再决定要不要用Nginx做静态文件和缓存。这个顺序比一开始就堆两个进程更利于调试。4.2 最简Flask应用读取DHT22并渲染页面安装Flasksudo pip3 install flask在B的老系统上如果pip3安装提示externally-managed-environment可以加--break-system-packages或者用venv虚拟环境。内网demo用venv更干净但systemd服务配置会多几行这里直接用系统级安装。创建/home/pi/weather_server.py#!/usr/bin/env python3 from flask import Flask, jsonify, render_template_string from gpiozero import DHT22 from time import sleep app Flask(__name__) sensor DHT22(4, use_pigpioTrue) def read_dht(): for _ in range(3): t sensor.temperature h sensor.humidity if t is not None and h is not None: return t, h sleep(1) return None, None app.route(/) def index(): t, h read_dht() if t is None: return DHT22 读取失败, 503 html h2树莓派B 环境监测/h2 p温度: {{ %.2f|format(t) }} deg;C/p p湿度: {{ %.2f|format(h) }} %/p return render_template_string(html, tt, hh) app.route(/api) def api(): t, h read_dht() if t is None: return jsonify({error: sensor read failed}), 503 return jsonify({temperature: round(t, 2), humidity: round(h, 2)}) if __name__ __main__: app.run(host0.0.0.0, port8080)代码里render_template_string直接渲染一个内联模板适合demo。/api接口返回JSON方便你之后接前端图表或让其他程序定时拉取。host0.0.0.0让B局域网里的设备都能访问端口8080避开常见的80端口权限问题——Linux下非root用户绑定80端口会失败。启动测试python3 /home/pi/weather_server.py curl http://localhost:8080/apicurl返回{humidity:45.3,temperature:26.7}这类结果说明Flask到DHT22整条链路都通了。4.3 用systemd把Web服务器设为开机自启确认脚本能跑通后把它注册成systemd服务sudo nano /etc/systemd/system/weather.service写入[Unit] DescriptionFlask weather web server Afterpigpiod.service Requirespigpiod.service [Service] ExecStart/usr/bin/python3 /home/pi/weather_server.py WorkingDirectory/home/pi Restartalways Userpi [Install] WantedBymulti-user.target关键参数是Requirespigpiod.service它保证pigpiod先启动否则Flask在创建DHT22实例时连不上守护进程整个服务直接崩溃。Userpi避免用root权限跑Python即使脚本有漏洞也不会直接给攻击者root shell。Restartalways应对偶发异常退出。然后执行sudo systemctl daemon-reload sudo systemctl enable --now weather sudo systemctl status weatherenable --now把服务设为开机自启并立即启动。检查状态如果看到Active: active (running)就说明Web服务已经挂住重启B也能自动拉起。4.4 查看日志和排查端口占用Web服务跑起来后最常见的两个问题是端口被占和传感器读取失败。先看日志sudo journalctl -u weather -f日志里会直接打出Flask的请求记录和Python异常。如果看到Address already in use说明8080端口被其他程序占用把端口改成8081或者找出占用进程ss -tlnp | grep 8080ss输出里能看到占用端口的进程名和PID。如果你发现pigpiod没启动journalctl会提示连接失败此时执行sudo systemctl enable --now pigpiod再重启weather服务。5. 树莓派Web服务器进阶历史记录、访问控制与迁移到4B/55.1 用SQLite保存历史温湿度Flask进程里只拿当前温度不够经看把每次读取写进SQLite后面就能画趋势图。在weather_server.py加一个初始化代码import sqlite3, datetime conn sqlite3.connect(/home/pi/weather.db, check_same_threadFalse) conn.execute(CREATE TABLE IF NOT EXISTS dht_log (timestamp text, temperature real, humidity real)) def log_dht(t, h): now datetime.datetime.now().isoformat() conn.execute(INSERT INTO dht_log VALUES (?, ?, ?), (now, t, h)) conn.commit()然后在read_dht读取成功后调用log_dht(t, h)。check_same_threadFalse是必须的因为Flask开发服务器会开多个线程默认SQLite连接只允许创建它的线程使用。5.2 给Web服务器加一个简单token只读接口虽然没风险但局域网里被扫描到也别扭。最省事的办法是在Flask里加一个before_request钩子要求请求头带X-Auth-Tokenfrom flask import request, abort VALID_TOKEN pi-weather-demo app.before_request def check_token(): if request.headers.get(X-Auth-Token) ! VALID_TOKEN: abort(401)加上后浏览器直接打开会得到401用curl加头才能访问curl -H X-Auth-Token: pi-weather-demo http://192.168.1.10:8080/api这个token只是防君子不防小人不要用来代替HTTPS或鉴权。正式环境建议通过SSH隧道或内网隔离访问。5.3 迁移到树莓派4B/5的差异B上这套方案拿到树莓派4B/5上基本不用改代码但有几个点要留意新系统默认是Bookworm/etc/apt/sources.list里不再直接写raspbian路径而是用/etc/apt/sources.list.d/下的debian.sources文件换源时文件名和后缀变了但逻辑一样。引脚排列从B到4B/5也是40针GPIO编码不变5代对3.3V的电源噪声控制更好DHT22甚至不用上拉电阻也能读但加上更稳。如果你想在4B/5上继续用gpiozero记得先sudo raspi-config确认接口没被SPI/I2C占用。DHT22程序代码无需改动这才是这套demo的价值系统层配置只要做一遍应用层代码跨代可复用。本文还有配套的精品资源点击获取
返回列表