基于树莓派与Flask的物联网气象监测系统:从传感器到Web可视化
1. 项目概述:打造你的专属气象站
你是否曾对天气预报的准确性感到好奇,或者想亲手搭建一个属于自己的环境监测系统?在智能家居、小型温室种植或是工作室环境监控等场景下,一个能够实时、精准反馈本地微气候的设备,其价值远超依赖宏观区域预报的通用天气应用。今天,我们就来动手实现一个基于树莓派(Raspberry Pi)和Flask框架的物联网气象监测系统。这个项目不仅成本低廉、易于构建,更能让你深入理解物联网(IoT)从数据采集、传输到可视化展示的完整链路。
整个系统的核心逻辑非常清晰:我们利用树莓派作为“大脑”和微型服务器,通过其通用输入输出(GPIO)引脚连接DHT11温湿度传感器,实时采集物理环境数据。随后,使用Python编写数据采集逻辑,并借助轻量级的Flask Web框架,将采集到的数据封装成RESTful API接口。最终,通过一个简洁的网页前端,你可以在任何连接同一网络的设备上,实时查看当前的温湿度读数,甚至回溯过去一段时间的数据变化曲线。这不仅仅是拼接硬件和复制代码,我们将深入探讨每一步背后的设计考量、参数选择以及实际部署中可能遇到的“坑”,确保你不仅能成功复现,更能透彻理解其工作原理。
2. 核心硬件选型与电路连接解析
2.1 硬件清单与选型理由
一份清晰的物料清单是项目成功的起点。以下是构建本系统所需的核心硬件及其选型背后的思考:
- Raspberry Pi 3 Model B+ (或更新型号) :作为项目的主控制器和服务器。选择树莓派3B+而非更早型号,主要因其集成了Wi-Fi和蓝牙,免去了额外配置无线网卡的麻烦,部署位置更灵活。如果使用树莓派4,其更强的处理能力和双频Wi-Fi会带来更流畅的Web服务体验,但本项目对算力要求不高,三代及以上型号均完全胜任。
- Micro SD卡 (建议16GB Class10及以上) :用于安装树莓派操作系统(Raspberry Pi OS)和项目代码。Class10及以上规格能保证系统运行和读写速度,避免因存储卡性能瓶颈导致系统卡顿。
- DHT11温湿度传感器 :本项目的数据来源。选择DHT11而非更精确的DHT22或BME280,主要基于两点考虑:一是成本极低,非常适合入门和验证概念;二是其单总线(1-Wire)通信协议,仅需一个GPIO引脚进行数据读写,接线和编程都相对简单。需要明确的是,DHT11的精度(温度±2°C,湿度±5%RH)和响应速度对于家庭室内环境监测是完全足够的,它的局限性在于不适合需要高精度或快速变化的工业场景。
- 杜邦线 (母对母,4根) :用于连接树莓派GPIO引脚与DHT11传感器。母对母接口可以直接插在引脚和传感器针脚上,无需焊接,非常适合原型搭建。
- 5V Micro USB电源 (额定电流≥2.5A) :为树莓派供电。务必使用质量合格的电源,电流不足可能导致树莓派在高负载时重启,尤其是在连接了外设的情况下。
- 可选配件 :
- 面包板 :虽然不是必须,但使用面包板进行连接可以使接线更整洁,也方便后续扩展其他传感器(如光敏电阻、气压计)。
- 外壳与散热片 :为树莓派安装外壳和散热片能提升其长期运行的稳定性,尤其是在密闭空间或夏季高温环境。
- 显示器、键盘、鼠标 :用于初次设置树莓派。一旦完成基础系统配置并开启SSH,后续所有操作都可以通过远程终端完成。
注意 :DHT11传感器有模块化和封装体两种常见形态。建议使用自带板载上拉电阻和滤波电容的模块化版本(通常为蓝色PCB),它比三针的封装体版本更稳定,抗干扰能力更强,对新手更友好。
2.2 电路连接详解与原理
正确的硬件连接是数据采集的物理基础。DHT11与树莓派的连接看似简单,但理解其原理能有效避免后续的通信故障。
DHT11模块通常有三个引脚(有些是四个,其中一个是空脚):
- VCC (电源正极) :接树莓派的 3.3V 引脚(例如物理引脚1)。 这里有一个关键点 :虽然DHT11模块的工作电压范围是3.3V-5.5V,但树莓派的GPIO引脚逻辑电平是3.3V。如果将DHT11的VCC接到5V引脚,其数据引脚输出的高电平可能是5V,这有可能损坏树莓派的GPIO引脚。为安全起见,统一使用3.3V供电是最稳妥的方案。
- DATA (数据线) :接树莓派的任意一个 GPIO 引脚(例如我们选用 GPIO4 ,对应物理引脚7)。这条线负责双向通信。
- GND (地线) :接树莓派的 GND 引脚(例如物理引脚6)。
连接示意图(文字描述) :
- 将DHT11模块的 VCC 引脚(通常标记为‘+’或‘VDD’)用一根杜邦线连接到树莓派的 物理引脚1 (3.3V电源) 。
- 将DHT11模块的 DATA 引脚(有时标记为‘OUT’或‘S’)用一根杜邦线连接到树莓派的 物理引脚7 (GPIO4) 。
- 将DHT11模块的 GND 引脚(标记为‘-’或‘GND’)用一根杜邦线连接到树莓派的 物理引脚6 (GND) 。
为什么选择GPIO4? 树莓派的GPIO引脚在软件层面是通用的,选择GPIO4并没有特殊硬件原因,主要是因为它位置方便(靠近3.3V和GND引脚),且不易与其他系统功能(如UART、I2C)冲突。你完全可以选择其他可用的GPIO,如GPIO17、GPIO27等,只需在代码中相应修改即可。
实操心得 :连接时,最好在树莓派断电状态下进行。插拔杜邦线时,确保对准引脚,避免因短路或错位导致硬件损坏。连接完成后,可以轻轻拉扯一下线材,确认接触牢固。
3. 软件环境搭建与核心库剖析
硬件准备就绪后,我们需要为树莓派构建一个稳定的软件运行环境。这个过程包括操作系统安装、基础配置以及Python库的安装。
3.1 树莓派系统初始化与远程访问配置
首先,需要在SD卡上安装树莓派操作系统(Raspberry Pi OS Lite版本即可,无需桌面环境以节省资源)。使用官方工具Raspberry Pi Imager进行烧录是最简单的方式。在烧录前,Imager的高级设置(按Ctrl+Shift+X)中,务必预先完成以下几项关键配置,这能极大简化后续步骤:
- 启用SSH :勾选“Enable SSH”,并设置密码认证或公钥认证。这是实现无头(Headless,即无显示器)运行和远程管理的基石。
- 配置Wi-Fi :填入你的无线网络名称(SSID)和密码,并选择国家代码(如CN)。这样树莓派在首次启动时就能自动连接网络。
- 设置主机名与用户 :建议设置一个易记的主机名,如
weather-pi,并创建你的用户名和密码。避免使用默认的pi用户以增强安全性。
烧录完成后,将SD卡插入树莓派并上电。等待几分钟后,你可以在路由器管理界面查找名为 weather-pi (或你设置的主机名)的设备,记下其IP地址。随后,即可在电脑上使用SSH客户端(如Windows的PuTTY或终端下的 ssh 命令)进行连接: ssh your_username@weather-pi.local 或 ssh your_username@<树莓派IP地址> 。
3.2 Python虚拟环境与依赖库安装
连接到树莓派后,首先更新系统软件包列表: sudo apt update && sudo apt upgrade -y 。
接下来,我们为项目创建一个独立的Python虚拟环境。这能隔离项目依赖,避免与系统Python环境发生冲突,是Python项目开发的最佳实践。
# 安装python3虚拟环境工具(如果尚未安装)
sudo apt install python3-venv -y
# 创建一个项目目录并进入
mkdir ~/weather_station && cd ~/weather_station
# 创建名为‘venv’的虚拟环境
python3 -m venv venv
# 激活虚拟环境
source venv/bin/activate
激活后,命令行提示符前会出现 (venv) 标识。现在所有 pip 安装的包都将仅限于此环境内。
根据项目描述,我们需要安装以下Python库。我们来逐一解释每个库的作用:
pip install RPi.GPIO requests flask flask-restful flask-wtf wtforms
- RPi.GPIO :这是树莓派GPIO编程的核心库。它提供了用Python控制GPIO引脚(如设置输入/输出模式、读取数字信号、输出PWM波等)的接口。我们的代码将通过它来与DHT11传感器通信。
- Flask :一个极其轻量灵活的Python Web框架。它负责处理HTTP请求和响应。在我们的项目中,Flask将扮演Web服务器的角色,监听特定的网络端口,当用户通过浏览器访问时,返回包含温湿度数据的网页。
- Flask-RESTful :Flask的一个扩展,用于快速构建RESTful API。它可以帮助我们以更结构化、更符合REST规范的方式定义数据接口(如
/api/temperature,/api/humidity),虽然在本项目的简单表单交互中不是必须,但它让后端API设计更清晰,便于未来扩展为手机App提供数据。 - Flask-WTF 与 WTForms :这两个库配合使用,用于在Web应用中安全地生成和处理表单。WTForms定义了表单的结构和验证规则,Flask-WTF则将其与Flask集成。我们将用它来创建网页上那个让用户选择查看“温度”、“湿度”或“图表”的复选框表单。
- requests :一个优雅而简单的HTTP库。虽然在我们的服务器端代码中可能不直接使用,但在测试API接口,或者未来编写一个独立的客户端程序来从多个气象站聚合数据时,它会非常有用。先安装以备不时之需。
注意事项 :在树莓派上使用
pip安装某些需要编译的库时,可能会因为内存不足而失败。如果遇到这种情况,可以尝试增加交换空间(swap),或者使用pip install --no-cache-dir选项。对于RPi.GPIO,也可以直接通过系统包管理器安装:sudo apt install python3-rpi.gpio,但这样安装的库会在系统Python环境中,而非我们的虚拟环境内。
4. 核心代码实现与Flask应用架构
有了环境,我们就可以开始编写项目的核心代码了。我们将按照MVC(模型-视图-控制器)的简化思想来组织代码,但更贴切地说,是数据采集层、业务逻辑层和表现层的分离。
4.1 数据采集层:与DHT11传感器对话
首先,我们创建一个专门负责与传感器打交道的模块 sensor_reader.py 。DHT11的通信协议是单总线协议,时序要求严格。虽然我们可以用 RPi.GPIO 库手动实现时序,但使用一个成熟的第三方库 Adafruit_DHT 会更稳定、更简单。我们需要先安装它: pip install Adafruit_DHT 。
# sensor_reader.py
import Adafruit_DHT
import time
from datetime import datetime
# 定义传感器类型和GPIO引脚
DHT_SENSOR = Adafruit_DHT.DHT11
DHT_PIN = 4 # 对应我们之前连接的GPIO4
class SensorReader:
def __init__(self, max_retries=3):
self.max_retries = max_retries
self.readings_cache = [] # 用于存储最近24次读数
self.max_cache_size = 24
def read_sensor(self):
"""尝试读取传感器数据,失败时重试"""
for attempt in range(self.max_retries):
humidity, temperature = Adafruit_DHT.read_retry(DHT_SENSOR, DHT_PIN)
if humidity is not None and temperature is not None:
# 读取成功,构建数据对象
reading = {
'timestamp': datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
'temperature': round(temperature, 1),
'humidity': round(humidity, 1)
}
# 更新缓存
self._update_cache(reading)
return reading
else:
print(f"传感器读取失败,第{attempt+1}次重试...")
time.sleep(1) # 等待1秒后重试
# 所有重试都失败
print("错误:无法从DHT11传感器获取数据。请检查连接。")
return None
def _update_cache(self, new_reading):
"""管理最近24次读数的缓存"""
self.readings_cache.append(new_reading)
# 如果超过最大缓存数,移除最旧的读数
if len(self.readings_cache) > self.max_cache_size:
self.readings_cache.pop(0)
def get_recent_readings(self):
"""获取缓存的最近读数"""
return self.readings_cache
# 单例模式,确保全局只有一个传感器读取实例
sensor_reader = SensorReader()
代码解析 :
Adafruit_DHT.read_retry()函数封装了DHT11通信的复杂时序和错误重试逻辑,比我们自己写轮询更可靠。- 我们定义了一个
SensorReader类,它内部维护了一个最多存储24次读数的缓存列表。每次成功读取后,新数据被追加,如果超过24条,最老的数据被移除(先进先出)。 read_sensor方法在读取失败时会自动重试最多3次,提高了在偶尔信号干扰下的鲁棒性。- 数据中加入了时间戳,这对于绘制历史图表至关重要。
4.2 业务逻辑与API层:Flask应用核心
接下来,创建主应用文件 app.py ,这里将集成Flask服务器、表单处理和数据接口。
# app.py
from flask import Flask, render_template, request, jsonify
from flask_wtf import FlaskForm
from wtforms import BooleanField, SubmitField
from wtforms.validators import DataRequired
from sensor_reader import sensor_reader
import json
app = Flask(__name__)
app.config['SECRET_KEY'] = 'your-secret-key-please-change-this' # 务必修改!
# 定义Web表单
class WeatherRequestForm(FlaskForm):
request_temp = BooleanField('温度')
request_humid = BooleanField('湿度')
request_graph = BooleanField('历史图表')
submit = SubmitField('获取数据')
@app.route('/', methods=['GET', 'POST'])
def index():
form = WeatherRequestForm()
latest_reading = None
recent_for_chart = []
if form.validate_on_submit():
# 用户提交了表单
latest_reading = sensor_reader.read_sensor() # 触发一次新的读取
# 根据用户选择,准备要传递到模板的数据
show_temp = form.request_temp.data
show_humid = form.request_humid.data
show_graph = form.request_graph.data
if show_graph:
recent_for_chart = sensor_reader.get_recent_readings()
# 渲染模板,并传递用户需要的选项和对应的数据
return render_template('display.html',
form=form,
show_temp=show_temp,
show_humid=show_humid,
show_graph=show_graph,
reading=latest_reading,
chart_data=recent_for_chart)
# GET请求或表单未验证,只显示空表单
return render_template('index.html', form=form)
# 新增:纯数据API接口,供其他程序调用(如手机App)
@app.route('/api/current', methods=['GET'])
def api_current():
reading = sensor_reader.read_sensor()
if reading:
return jsonify(reading), 200
else:
return jsonify({'error': 'Sensor read failed'}), 500
@app.route('/api/history', methods=['GET'])
def api_history():
return jsonify(sensor_reader.get_recent_readings()), 200
if __name__ == '__main__':
# 在树莓派上运行时,host='0.0.0.0'允许同一网络内其他设备访问
app.run(host='0.0.0.0', port=5000, debug=True)
设计思路解析 :
- 表单驱动交互 :我们没有设计复杂的多页面,而是用一个表单(
WeatherRequestForm)控制所有交互。用户勾选需要的选项后提交,服务器根据勾选情况采集一次新数据,并只渲染用户关心的部分到结果页面(display.html)。这种设计非常简洁高效。 - RESTful API扩展 :除了表单页面,我们还增加了
/api/current和/api/history两个API端点。它们直接返回JSON格式的数据,不包含任何HTML。这使得我们的气象站数据可以被其他应用程序(比如用Python脚本定时记录、或用手机App框架开发的客户端)轻松消费,极大地提升了项目的可扩展性。 - 密钥安全 :
SECRET_KEY用于保护表单免受跨站请求伪造(CSRF)攻击。 务必在生产环境中将其修改为一个强随机字符串 ,例如通过os.urandom(24)生成。
4.3 表现层:HTML模板构建
Flask使用Jinja2模板引擎。我们需要在项目根目录下创建一个 templates 文件夹,并在其中放置HTML文件。
index.html 是首页,仅包含表单:
<!DOCTYPE html>
<html>
<head>
<title>我的个人气象站</title>
<style>
body { font-family: sans-serif; margin: 40px; }
.form-group { margin-bottom: 15px; }
label { margin-right: 10px; }
</style>
</head>
<body>
<h1>欢迎使用个人气象站</h1>
<p>请选择您要查看的信息:</p>
<form method="POST">
{{ form.hidden_tag() }} <!-- 渲染CSRF令牌 -->
<div class="form-group">
{{ form.request_temp.label }} {{ form.request_temp() }}
</div>
<div class="form-group">
{{ form.request_humid.label }} {{ form.request_humid() }}
</div>
<div class="form-group">
{{ form.request_graph.label }} {{ form.request_graph() }}
</div>
<div class="form-group">
{{ form.submit() }}
</div>
</form>
</body>
</html>
display.html 是结果显示页,动态渲染内容:
<!DOCTYPE html>
<html>
<head>
<title>气象数据 - 我的个人气象站</title>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script> <!-- 引入Chart.js用于绘图 -->
<style>
body { font-family: sans-serif; margin: 40px; }
.data-box { border: 1px solid #ccc; padding: 20px; margin: 20px 0; border-radius: 5px; }
h2 { color: #333; }
</style>
</head>
<body>
<h1>气象数据</h1>
<a href="/">返回首页</a>
{% if show_temp or show_humid %}
<div class="data-box">
<h2>实时读数</h2>
<p><strong>数据更新时间:</strong>{{ reading.timestamp if reading else 'N/A' }}</p>
{% if show_temp %}
<p><strong>温度:</strong>{{ reading.temperature if reading else 'N/A' }} °C</p>
{% endif %}
{% if show_humid %}
<p><strong>湿度:</strong>{{ reading.humidity if reading else 'N/A' }} %</p>
{% endif %}
</div>
{% endif %}
{% if show_graph and chart_data %}
<div class="data-box">
<h2>最近24次读数趋势</h2>
<canvas id="weatherChart" width="800" height="400"></canvas>
<script>
const chartData = {{ chart_data | tojson }};
const labels = chartData.map(d => d.timestamp);
const tempData = chartData.map(d => d.temperature);
const humidData = chartData.map(d => d.humidity);
const ctx = document.getElementById('weatherChart').getContext('2d');
const weatherChart = new Chart(ctx, {
type: 'line',
data: {
labels: labels,
datasets: [{
label: '温度 (°C)',
data: tempData,
borderColor: 'rgb(255, 99, 132)',
tension: 0.1
}, {
label: '湿度 (%)',
data: humidData,
borderColor: 'rgb(54, 162, 235)',
tension: 0.1
}]
},
options: {
responsive: false,
scales: {
y: {
beginAtZero: false
}
}
}
});
</script>
</div>
{% elif show_graph %}
<p>暂无足够的历史数据绘制图表。</p>
{% endif %}
<hr>
<h3>再次查询</h3>
<!-- 复用同一个表单,方便用户继续查询 -->
<form method="POST">
{{ form.hidden_tag() }}
<div>
{{ form.request_temp.label }} {{ form.request_temp() }}
{{ form.request_humid.label }} {{ form.request_humid() }}
{{ form.request_graph.label }} {{ form.request_graph() }}
</div>
{{ form.submit() }}
</form>
</body>
</html>
前端交互亮点 :
- 条件渲染 :使用Jinja2的
{% if %}语句,只在用户勾选了相应选项时才渲染对应的数据区块(温度、湿度、图表)。这使得页面非常干净。 - 动态图表 :我们引入了强大的Chart.js库来绘制折线图。后端将缓存的24次数据以JSON格式传递给模板,前端JavaScript解析这些数据并动态生成交互式图表。这比让后端生成静态图片要灵活和美观得多。
- 用户体验 :在结果显示页底部再次放置了表单,用户无需返回首页即可进行下一次查询,操作流程更顺畅。
5. 系统部署、测试与优化
代码编写完成后,我们需要将其部署到树莓派上并确保其稳定、长期运行。
5.1 启动测试与问题排查
首先,在项目目录下激活虚拟环境并运行Flask开发服务器:
cd ~/weather_station
source venv/bin/activate
python app.py
如果一切正常,终端会输出类似 * Running on http://0.0.0.0:5000/ 的信息。
现在,从同一局域网内的另一台设备(如笔记本电脑或手机)的浏览器中,访问 http://<树莓派的IP地址>:5000 。你应该能看到表单页面。尝试勾选不同选项并提交,观察是否能正确显示数据。
常见问题与排查技巧实录 :
-
问题:页面显示“无法从DHT11传感器获取数据”或读数一直为None。
- 排查思路 :
- 检查硬件连接 :这是最常见的问题。务必确认VCC、DATA、GND三根线没有接错或接触不良。可以尝试重新插拔杜邦线。
- 检查GPIO引脚号 :确认代码中的
DHT_PIN(如GPIO4)与实际物理连接(物理引脚7)对应。树莓派有BCM编号(GPIO编号)和物理引脚编号,RPi.GPIO和Adafruit_DHT库默认使用BCM编号。 - 电源问题 :确保树莓派电源充足,且传感器由3.3V供电。尝试用万用表测量3.3V引脚和GND之间的电压是否稳定。
- 软件库问题 :确认
Adafruit_DHT库已正确安装在当前虚拟环境中。可以尝试在Python交互环境中手动导入并测试:import Adafruit_DHT; Adafruit_DHT.read_retry(Adafruit_DHT.DHT11, 4)。 - 传感器损坏 :DHT11是静电敏感器件,有极小的概率在操作中损坏。有条件的话可以换一个传感器测试。
- 排查思路 :
-
问题:能读到数据,但数值明显不准(如温度30°C,实际只有25°C)。
- ��查思路 :
- 传感器位置 :DHT11对热源非常敏感。确保它没有靠近树莓派的CPU(树莓派运行时会有一定发热)、电源模块或其他热源。
- 通风与遮蔽 :传感器不应被阳光直射,也不应被完全密闭在不透气的容器内。将其放置在能代表你希望监测环境空气的位置。
- 理解精度 :回忆DHT11的精度指标(±2°C, ±5%RH)。对于室内环境监测,这个精度通常可以接受。如果要求更高,应考虑升级到DHT22或BME280。
- ��查思路 :
-
问题:Web页面无法访问(连接被拒绝)。
- 排查思路 :
- 检查Flask是否运行 :确认在树莓派终端上,Flask应用正在运行且没有报错退出。
- 检查IP地址和端口 :确认你输入的树莓派IP地址正确,并且Flask运行在
0.0.0.0:5000。 - 检查防火墙 :树莓派OS Lite版默认防火墙(UFW)可能是关闭的。如果开启了,需要允许5000端口:
sudo ufw allow 5000。 - 检查网络 :确保测试设备和树莓派连接在同一个局域网内。
- 排查思路 :
5.2 生产环境部署:使用Gunicorn与Nginx
Flask自带的开发服务器( app.run )性能较弱且不安全,不适合长期对外服务。我们需要使用专业的WSGI服务器和反向代理。
-
安装Gunicorn :在虚拟环境中安装生产级WSGI服务器。
pip install gunicorn -
使用Gunicorn启动应用 :
cd ~/weather_station source venv/bin/activate gunicorn -w 2 -b 0.0.0.0:8000 app:app-w 2:启动2个工作进程,处理并发请求。-b 0.0.0.0:8000:绑定到所有网络接口的8000端口。app:app:冒号前的app是模块名(即我们的app.py文件),冒号后的app是Flask应用实例的名字。
现在应用运行在8000端口。访问
http://<树莓派IP>:8000进行测试。 -
配置系统服务(让应用开机自启) : 创建一个系统服务文件,让树莓派在启动时自动运行我们的气象站应用。
sudo nano /etc/systemd/system/weather-station.service写入以下内容( 注意修改
User、WorkingDirectory和ExecStart的路径为你的实际信息 ):[Unit] Description=Personal Weather Station Flask App After=network.target [Service] User=your_username # 替换为你的树莓派用户名 WorkingDirectory=/home/your_username/weather_station ExecStart=/home/your_username/weather_station/venv/bin/gunicorn -w 2 -b 0.0.0.0:8000 app:app Restart=always RestartSec=10 StandardOutput=syslog StandardError=syslog SyslogIdentifier=weather-station [Install] WantedBy=multi-user.target保存退出后,启用并启动服务:
sudo systemctl daemon-reload sudo systemctl enable weather-station.service sudo systemctl start weather-station.service sudo systemctl status weather-station.service # 检查状态,应为active (running) -
配置Nginx作为反向代理(可选但推荐) : 使用Nginx可以将服务映射到标准的80端口(HTTP),并提供更好的静态文件处理和安全性。
- 安装Nginx:
sudo apt install nginx -y - 编辑默认站点配置:
sudo nano /etc/nginx/sites-available/default - 在
server块内,找到location /部分,修改或添加如下配置:location / { proxy_pass http://127.0.0.1:8000; # 转发给Gunicorn proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } - 测试配置并重启Nginx:
sudo nginx -t # 测试配置文件语法 sudo systemctl restart nginx
现在,你可以直接通过
http://<树莓派IP>访问你的气象站,无需输入端口号。 - 安装Nginx:
5.3 项目优化与扩展思路
一个基础系统搭建完成后,可以考虑以下方向进行优化和扩展,使其更实用、更强大:
- 数据持久化 :目前数据仅保存在内存列表中,树莓派重启后历史数据会丢失。可以集成SQLite或轻量级数据库TinyDB,将每次读数连同时间戳存入数据库,实现长期存储和更复杂的数据查询。
- 定时自动采集 :当前是“请求-响应”模式,数据只在用户访问时更新。可以编写一个后台定时任务(例如使用
cron或schedule库),每隔一定时间(如每5分钟)自动读取一次传感器数据并存储,无论用户是否访问。 - 多传感器集成 :树莓派的GPIO和I2C/SPI接口可以连接更多传感器。例如,添加一个BMP280气压传感器来获取气压和海拔数据;添加一个光敏电阻来监测光照强度;甚至连接一个雨滴传感器或风速计。
- 数据可视化增强 :使用更强大的前端图表库(如ECharts),展示更丰富的图表类型,如24小时温度变化曲线、温湿度关联散点图等。
- 报警功能 :在代码中添加逻辑,当温度或湿度超过设定的阈值时,通过发送电子邮件(使用
smtplib)、推送通知到手机(使用Pushover、Bark等服务)或点亮一个LED灯的方式进行报警。 - 远程访问(进阶) :通过内网穿透工具(如frp、ngrok)或配置路由器端口转发(需公网IP),可以在家庭网络之外访问你的气象站。 请注意,此举会暴露你的树莓派服务到公网,务必设置强密码、考虑使用HTTPS,并做好安全加固。
- 电源优化 :如果部署在远离电源插座的地方,可以考虑使用大容量充电宝供电,或者为树莓派配置一个安全的关机/唤醒电路,以节省电量。
通过以上步骤,你不仅完成了一个可工作的物联网气象监测系统,更掌握了从硬件连接到软件部署、从原型开发到生产环境配置的完整技能链。这个项目是一个绝佳的起点,你可以根据自己的兴趣和需求,不断为其添加新的功能和模块,真正打造一个完全个性化、功能强大的环境监测中心。
更多推荐



所有评论(0)