1. 项目概述
树莓派作为一款信用卡大小的微型计算机,凭借其丰富的GPIO接口和强大的扩展能力,成为物联网开发的理想平台。这个项目将指导你使用树莓派配合常见传感器,构建一个功能完善的环境监测站,实时采集温度、湿度等环境数据,并通过本地存储或云端服务实现数据可视化。
环境监测是物联网技术最典型的应用场景之一。通过这个项目,你不仅能掌握传感器数据采集的核心技术,还能学习到物联网系统的完整架构设计。相比商业环境监测设备,DIY方案具有成本低(整套设备可控制在300元以内)、可定制性强(支持任意传感器扩展)和开源生态丰富(Python库支持完善)三大优势。
2. 硬件准备与连接
2.1 核心硬件选型建议
树莓派型号选择:
- 推荐树莓派4B(2GB内存版)或树莓派3B+,其GPIO接口完全兼容
- 避免使用树莓派Zero系列,因其缺少标准40pin接口需转接
传感器选型对比表:
| 传感器类型 | 推荐型号 | 接口方式 | 测量范围 | 精度 | 单价 |
|---|---|---|---|---|---|
| 温湿度 | DHT22 | 单总线 | -40~80℃, 0~100%RH | ±0.5℃, ±2%RH | ¥25 |
| 气压 | BMP280 | I2C | 300-1100hPa | ±0.12hPa | ¥35 |
| 空气质量 | CCS811 | I2C | eCO2:400-32768ppm | ±10% | ¥60 |
| 光照强度 | BH1750 | I2C | 1-65535lux | ±1lux | ¥15 |
提示:初学者建议从DHT22+BMP280组合入手,这两个传感器足以覆盖基础环境监测需求,且接线简单。
2.2 硬件连接示意图
以树莓派4B为例的接线方法:
树莓派 GPIO 引脚布局: 3V3 (1) ── (2) 5V GPIO2/SDA (3) ── (4) 5V GPIO3/SCL (5) ── (6) GND GPIO4 (7) ── (8) TXD GND (9) ── (10) RXD GPIO17 (11) ── (12) GPIO18 GPIO27 (13) ── (14) GND GPIO22 (15) ── (16) GPIO23 3V3 (17) ── (18) GPIO24 GPIO10 (19) ── (20) GND GPIO9 (21) ── (22) GPIO25 GPIO11 (23) ── (24) GPIO8 GND (25) ── (26) GPIO7具体连接方式:
- DHT22: VCC→3.3V(引脚1), DATA→GPIO4(引脚7), GND→任意GND
- BMP280: VCC→3.3V(引脚1), SDA→GPIO2(引脚3), SCL→GPIO3(引脚5), GND→GND
注意:务必确认传感器工作电压,部分5V传感器需电平转换模块,直接连接可能损坏树莓派GPIO。
3. 系统环境配置
3.1 操作系统准备
推荐使用Raspberry Pi OS Lite版本(无桌面环境),通过以下命令完成基础配置:
# 更新系统 sudo apt update && sudo apt upgrade -y # 安装必要工具 sudo apt install -y python3-pip git build-essential libgpiod2 # 启用I2C接口 sudo raspi-config nonint do_i2c 0 sudo reboot3.2 Python环境搭建
建议使用虚拟环境管理项目依赖:
python3 -m venv ~/env_monitor source ~/env_monitor/bin/activate pip install RPi.GPIO adafruit-circuitpython-dht adafruit-circuitpython-bmp2804. 数据采集程序开发
4.1 传感器驱动实现
创建sensor_reader.py文件:
import time import board import adafruit_dht import adafruit_bmp280 class SensorHub: def __init__(self): # 初始化DHT22 self.dht = adafruit_dht.DHT22(board.D4) # 初始化BMP280 self.i2c = board.I2C() self.bmp = adafruit_bmp280.Adafruit_BMP280_I2C(self.i2c) self.bmp.sea_level_pressure = 1013.25 # 设置海平面基准压力 def read_all(self): data = {} retry = 3 # 读取温湿度 while retry > 0: try: data['temperature'] = self.dht.temperature data['humidity'] = self.dht.humidity break except RuntimeError: retry -= 1 time.sleep(2) # 读取气压和海拔 data['pressure'] = self.bmp.pressure data['altitude'] = self.bmp.altitude return data if __name__ == "__main__": hub = SensorHub() print(hub.read_all())4.2 数据持久化方案
推荐使用SQLite进行本地存储:
import sqlite3 from datetime import datetime class DataLogger: def __init__(self, db_path='environment.db'): self.conn = sqlite3.connect(db_path) self._init_db() def _init_db(self): cursor = self.conn.cursor() cursor.execute('''CREATE TABLE IF NOT EXISTS sensor_data (timestamp TEXT, temperature REAL, humidity REAL, pressure REAL)''') self.conn.commit() def log_data(self, data): cursor = self.conn.cursor() cursor.execute('''INSERT INTO sensor_data VALUES (?, ?, ?, ?)''', (datetime.now().isoformat(), data.get('temperature'), data.get('humidity'), data.get('pressure'))) self.conn.commit()5. 数据可视化实现
5.1 本地Web服务搭建
使用Flask创建简单的数据展示界面:
from flask import Flask, render_template import sqlite3 from datetime import datetime, timedelta app = Flask(__name__) @app.route('/') def dashboard(): conn = sqlite3.connect('environment.db') cursor = conn.cursor() # 获取最近24小时数据 end_time = datetime.now() start_time = end_time - timedelta(hours=24) cursor.execute('''SELECT timestamp, temperature, humidity, pressure FROM sensor_data WHERE timestamp BETWEEN ? AND ?''', (start_time.isoformat(), end_time.isoformat())) records = cursor.fetchall() return render_template('dashboard.html', records=records, update_time=end_time.strftime('%Y-%m-%d %H:%M')) if __name__ == '__main__': app.run(host='0.0.0.0', port=8080)对应的HTML模板(templates/dashboard.html):
<!DOCTYPE html> <html> <head> <title>环境监测站</title> <script src="https://cdn.jsdelivr.net/npm/chart.js"></script> <style> .sensor-card { margin: 10px; padding: 15px; border-radius: 8px; background: #f8f9fa; } .chart-container { width: 100%; height: 300px; } </style> </head> <body> <h1>环境监测仪表板</h1> <p>最后更新: {{ update_time }}</p> <div class="sensor-card"> <h2>温度趋势</h2> <div class="chart-container"> <canvas id="tempChart"></canvas> </div> </div> <script> const records = {{ records|tojson }}; const timestamps = records.map(r => new Date(r[0]).toLocaleTimeString()); // 温度图表 new Chart(document.getElementById('tempChart'), { type: 'line', data: { labels: timestamps, datasets: [{ label: '温度 (°C)', data: records.map(r => r[1]), borderColor: 'rgb(255, 99, 132)', tension: 0.1 }] } }); </script> </body> </html>6. 进阶功能扩展
6.1 云端数据同步
通过MQTT协议将数据上传至阿里云物联网平台:
import paho.mqtt.client as mqtt import json class CloudSync: def __init__(self): self.client = mqtt.Client() self.client.username_pw_set("your_device_secret") self.client.connect("iot-xxx.mqtt.aliyuncs.com", 1883, 60) def publish_data(self, data): payload = { "device": "env_monitor_001", "timestamp": datetime.now().isoformat(), "data": data } self.client.publish("env/data", json.dumps(payload))6.2 异常报警功能
当温度超过阈值时发送邮件报警:
import smtplib from email.mime.text import MIMEText class AlertSystem: def __init__(self): self.thresholds = { 'temperature': 35.0, 'humidity': 80.0 } def check_thresholds(self, data): alerts = [] if data['temperature'] > self.thresholds['temperature']: alerts.append(f"高温警告: {data['temperature']}°C") if data['humidity'] > self.thresholds['humidity']: alerts.append(f"高湿警告: {data['humidity']}%") return alerts def send_email(self, alerts): msg = MIMEText("\n".join(alerts)) msg['Subject'] = "环境监测警报" msg['From'] = "monitor@example.com" msg['To'] = "admin@example.com" with smtplib.SMTP('smtp.example.com', 587) as server: server.starttls() server.login("user", "password") server.send_message(msg)7. 系统优化与部署
7.1 开机自启动配置
创建systemd服务单元文件/etc/systemd/system/env_monitor.service:
[Unit] Description=Environment Monitoring Service After=network.target [Service] ExecStart=/home/pi/env_monitor/bin/python /home/pi/monitor/main.py WorkingDirectory=/home/pi/monitor User=pi Restart=always [Install] WantedBy=multi-user.target启用服务:
sudo systemctl daemon-reload sudo systemctl enable env_monitor sudo systemctl start env_monitor7.2 功耗优化技巧
对于需要7×24小时运行的场景:
- 启用树莓派低功耗模式:
sudo raspi-config→ Performance Options → Overclock → None - 关闭HDMI输出:在
/boot/config.txt添加hdmi_blanking=1 - 使用USB电源管理:安装
apt install tlp电源管理工具
8. 常见问题排查
8.1 传感器读数异常
症状:DHT22频繁返回None或错误数据
解决方案:
- 检查接线是否牢固,尝试缩短传感器到树莓派的距离(建议<1m)
- 在数据引脚添加4.7KΩ上拉电阻
- 增加读取重试机制(如示例代码中的retry逻辑)
8.2 数据库写入冲突
症状:多线程同时写入时出现database locked错误
解决方法:
# 修改DataLogger类 import threading class DataLogger: def __init__(self): self.lock = threading.Lock() # ... def log_data(self, data): with self.lock: # 原有写入逻辑8.3 Web界面访问缓慢
优化方案:
- 限制查询数据量:
SELECT ... LIMIT 500 - 添加数据库索引:
CREATE INDEX idx_timestamp ON sensor_data(timestamp) - 使用缓存机制(如Flask-Caching)
9. 项目扩展方向
- 多节点组网:部署多个监测点,使用LoRa或Zigbee实现无线组网
- 移动端适配:开发Flutter应用实时查看数据
- 机器学习预测:基于历史数据训练温度变化预测模型
- 语音播报:通过语音合成模块播报环境状态
- 自动化控制:连接继电器模块,当温度过高时自动开启风扇
这个项目最让我惊喜的是树莓派GPIO的稳定性——在连续运行测试中,即使经过30天不间断数据采集,系统仍能保持稳定工作。建议在正式部署前,用stress工具进行72小时压力测试,验证系统可靠性。