尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

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

ESP32+Python+Vue构建智能家居环境监测系统实战

ESP32+Python+Vue构建智能家居环境监测系统实战 家有矿机、阳台种菜、远程看猫的人越来越多“环境监测”这个词已经从工厂车间走进了普通住宅。作为一名物联网开发者最近在实际项目中需要快速搭一个分布式的室内环境采集节点评估了多种方案后我最终选择基于ESP32自己做一套轻量级的智能家居环境检测节点。这套方案既绕不开单片机开发又涉及Python 后端的数据处理和Vue 前端的可视化展示正好覆盖了目前物联网方向毕业设计、个人项目里最常见的几块核心内容。本文将围绕这套“ESP32 Python Vue”的智能家居环境检测小系统从硬件选型、开发环境搭建、固件编写到后端接口开发、前端页面展示完整走一遍闭环流程。如果你正在做计算机毕业设计或者想入门物联网开发这篇文章可以当作一份可直接对照复现的工程笔记。1. 项目背景与整体方案先想清楚一个问题一套所谓的“智能家居环境检测系统”它到底在“智能”什么传统的水银温度计也好独立的温湿度计也罢它们都只能解决“单点、本地、即时”的读数需求。而当我们想实现“打开手机就能看到客厅、卧室、阳台各个位置的温湿度曲线”“环境温度过高时自动触发风扇或者报警”这一类需求时就必须让设备具备三个能力感知能力通过传感器采集环境物理量。联网能力把采集到的数据传出去。展示与控制能力在服务端完成数据存储、分析在前端完成可视化展示和远程控制。ESP32 之所以非常适合做这类节点的核心是因为它几乎把“感知 联网”两个要求浓缩到了极致。1.1 ESP32 是什么ESP32 是乐鑫Espressif推出的一系列低功耗、高集成度的 Wi-Fi/蓝牙 SoC 芯片。它最大的特点是单芯片同时支持 Wi-Fi 和蓝牙而且价格低、生态成熟在物联网领域已经成为事实上的入门标准。从硬件资源来看ESP32 通常包含双核或单核 Xtensa LX6 处理器主频 160MHz/240MHz支持 2.4GHz Wi-Fi802.11 b/g/n和 Bluetooth v4.2 BR/EDR/BLE丰富的外设接口ADC、DAC、SPI、I2C、UART、I2S、PWM、触摸传感器等常见的模组如 ESP32-WROOM-32集成了 4MB Flash部分型号还支持 PSRAM。在实际项目中我们可以直接用一块 ESP32 开发板外接一个温湿度传感器如 DHT11、DHT22、SHT30甚至气体传感器就可以在几分钟内构建出一个环境数据采集节点。1.2 系统整体架构本项目的整体结构可以用下面这张表来理解层级技术选型职责描述感知层ESP32 DHT11/DHT22采集温湿度数据通过 Wi-Fi 上报传输层HTTP/MQTT将传感器数据发送到后端服务服务层Python Flask提供数据接收接口、存储和查询接口存储层SQLite/MySQL/JSON保存历史数据便于后续分析展示层Vue ECharts实时展示环境数据、历史曲线这个架构并不复杂但它是一个非常典型的物联网“感知-传输-处理-展示”四层模型。理解这个模型比单纯跑通某一个 Demo 更重要。整套系统的工作流程如下ESP32 开发板上电连接 Wi-Fi。主循环每隔一段时间读取 DHT11 传感器的温湿度数据。将数据通过 HTTP POST 方式发送给 Python 后端接口。Flask 后端解析 JSON 数据存入数据库并预留查询接口。前端 Vue 项目通过 HTTP GET 请求获取最新数据用 ECharts 图表展示曲线。说句实在话在设备端实时查看数据当然可行但如果想做出“历史记录”“远程查看”这些功能一个独立的后端服务几乎是必需品。这也是为什么这个项目非常适合作为计算机毕业设计或者“物联网前后端”综合练手项目的原因。2. 环境准备与硬件选型在动手写代码之前先把工具链梳理清楚。很多初学者容易在环境搭建上卡住一卡就是半天所以这部分我尽量写详细。2.1 硬件清单本项目的硬件门槛很低典型清单如下硬件型号/规格用途主控开发板ESP32 DevKitC或 NodeMCU-32S主控与联网温湿度传感器DHT11 或 DHT22AM2302采集环境温湿度面包板400 孔/800 孔均可连接电路杜邦线母对母、公对母若干接线数据线Micro-USB 或 USB-C视开发板而定供电与烧录传感器这里多说一句DHT11 和 DHT22 都是单总线数字温湿度传感器但 DHT11 精度较低温度 ±2℃湿度 ±5%RHDHT22 精度更高温度 ±0.5℃湿度 ±2%RH价格也贵一些。本篇示例以 DHT11 为主因为它在学习阶段最容易买到代码上也完全兼容。2.2 开发软件与版本说明工具说明Arduino IDE编写并烧录 ESP32 固件本文示例版本为 2.x需要支持 ESP32 开发板管理ESP32 开发包在 Arduino 开发板管理器中安装包名esp32 by Espressif SystemsPython建议 Python 3.8用于编写 Flask 后端Node.js建议 Node 14用于创建和运行 Vue 前端项目数据库本文为了便于演示采用 SQLite无需额外安装也可替换为 MySQL版本需要根据你的项目实际情况调整本文示例以常见环境为例重点演示配置思路。2.3 Arduino IDE 搭建 ESP32 开发环境Arduino IDE 默认不包含 ESP32 支持需要手动添加开发板管理器地址。前面说过“arduino ide搭建esp32或esp8266开发环境”是很多新手会搜索的内容这里给出标准操作。在主界面选择文件 - 首选项 - 附加开发板管理器网址填入https://dl.espressif.com/dl/package_esp32_index.json这一步的目的是让 Arduino IDE 知道从哪里拉取 ESP32 的开发板定义和工具链。然后选择工具 - 开发板 - 开发板管理器搜索esp32找到esp32 by Espressif Systems点击安装。这里有一个非常实际的痛点由于国内网络环境从 GitHub 或乐鑫服务器下载 ESP32 工具链可能非常慢甚至反复失败也就是大家经常遇到的arduino下载esp32库失败问题。如果等待安装时间太长可以考虑使用国内镜像源替换下载地址下载社区整理的离线安装包解压到 Arduino 的hardware/espressif目录使用代理方式访问国外资源这里需要说明请使用合规的网络接入方式并且不要涉及违规工具。安装完成后在工具 - 开发板中选择ESP32 Dev Module选择正确的 COM 口就可以开始写代码了。在开发板选择上补充一点ESP32 系列有很多型号比如经典的 ESP32-WROOM-32、带 RGB 的 ESP32-S3、带摄像头接口的 ESP32-EYE 等。本文代码基于经典 ESP32 编写如果你使用其他型号大部分代码可以直接复用但引脚定义可能需要按开发板原理图调整。3. ESP32 端数据采集与发送芯片是硬件系统的“大脑”而代码是这个大脑的“思维”。下面我们直接进入 ESP32 端的核心代码实现。3.1 引脚接线DHT11 传感器通常是三脚或四脚封装。以常见的三脚模块为例DHT11 引脚接 ESP32 引脚VCC3.3V 或 5V模块多数可直连 3.3VDATASGPIO4示例中用 GPIO4GND-GND注意有些 DHT11 裸传感器需要外接 4.7kΩ 上拉电阻但大多数市售模块已经集成上拉电阻插上杜邦线就能用。3.2 代码结构在 Arduino IDE 中新建一个项目主要代码文件是.ino。为了让代码清晰我通常会在同一个项目中拆成几个 Tab例如esp32_env_node/ |- esp32_env_node.ino // 主程序 |- secrets.h // Wi-Fi 和服务器配置可选但为了便于读者复制本文给出一个单文件的完整示例。3.3 完整固件代码// 文件路径esp32_env_node/esp32_env_node.ino // 功能读取 DHT11 温湿度数据通过 HTTP POST 上报到 Python 后端 #include WiFi.h #include HTTPClient.h #include DHT.h // Wi-Fi 配置 const char* ssid your_wifi_ssid; const char* password your_wifi_password; // 后端接口地址 const char* serverUrl http://192.168.1.100:5000/api/upload; // 传感器配置 #define DHTPIN 4 // 数据引脚 GPIO4 #define DHTTYPE DHT11 // DHT11 传感器 DHT dht(DHTPIN, DHTTYPE); // 上传时间间隔毫秒 const unsigned long interval 10000; unsigned long previousMillis 0; void setup() { Serial.begin(115200); delay(1000); // 初始化 DHT11 dht.begin(); // 连接 Wi-Fi WiFi.begin(ssid, password); Serial.print(Connecting to WiFi); while (WiFi.status() ! WL_CONNECTED) { delay(500); Serial.print(.); } Serial.println(); Serial.print(Connected, IP address: ); Serial.println(WiFi.localIP()); } void loop() { unsigned long currentMillis millis(); // 定时上传 if (currentMillis - previousMillis interval) { previousMillis currentMillis; uploadSensorData(); } } void uploadSensorData() { // 读取温湿度 float humidity dht.readHumidity(); float temperature dht.readTemperature(); // 检查读取是否成功 if (isnan(humidity) || isnan(temperature)) { Serial.println(Failed to read from DHT sensor!); return; } // 构造 JSON 字符串 String jsonPayload {\temperature\: String(temperature, 2) ,\humidity\: String(humidity, 2) ,\device_id\:\esp32_room_001\}; Serial.println(jsonPayload); // 创建 HTTPClient 并发送 POST 请求 HTTPClient http; http.begin(serverUrl); http.addHeader(Content-Type, application/json); int httpCode http.POST(jsonPayload); if (httpCode 0) { String response http.getString(); Serial.print(HTTP Response code: ); Serial.println(httpCode); Serial.print(Response body: ); Serial.println(response); } else { Serial.print(HTTP POST failed. Error code: ); Serial.println(http.errorToString(httpCode).c_str()); } http.end(); }3.4 代码关键点分析这段代码看起来不长但有几个关键点需要理解。第一为什么使用millis()而不是delay()做定时delay()会阻塞整个程序。如果发送一次 HTTP 请求耗时 2 秒那么这 2 秒内程序无法处理其他逻辑。millis()的非阻塞方式让代码在等待上传的间隙仍可执行其他任务这在多传感器、多任务场景下是更好的习惯。第二为什么要检查 DHT 读取结果DHT11 在读取过程中可能因为信号干扰、接线松动等原因读到NANNot a Number。如果不检查后续String(temperature, 2)会把非法值拼进 JSON导致后端数据脏乱。经验之谈所有传感器数据在进入网络传输之前都必须做合法性校验。第三为什么使用HTTPClientESP32 的HTTPClient库封装了常用的 HTTP 请求方法。示例中使用POST将 JSON 数据发给后端这是物联网设备上报数据最通用的方式之一。更进阶的方案是使用 MQTT 协议但 HTTP 在简单性、调试便利性上对新手更友好。3.5 运行与验证将代码中的 Wi-Fi 账号密码和后端地址改成你自己的然后点击 Arduino IDE 的“上传”按钮。打开串口监视器波特率选择 115200可以看到类似下面的输出Connecting to WiFi...... Connected, IP address: 192.168.1.44 {temperature:27.50,humidity:58.00,device_id:esp32_room_001} HTTP Response code: 200 Response body: {code:0,message:success}只要看到HTTP Response code: 200说明 ESP32 端已经打通后面就可以集中精力写后端服务了。需要提醒的是serverUrl中的 IP 地址必须是后端服务所在机器在同一局域网内可访问的 IP。如果后端和 ESP32 不在同一个网络环境还需要考虑内网穿透或公网服务器部署这部分不在本示例范围内。4. Python 后端接口开发前端叫 Vue硬件端叫 ESP32那“中间人”角色自然落到后端。Python 生态中Flask 以轻量、灵活而著称非常适合快速搭建一个数据接收服务。4.1 为什么选 Flask 而不是 DjangoDjango 功能全面自带 Admin 后台、ORM、认证体系适合大型 Web 应用。但在这个物联网场景中我们需要的只是一个能接收 POST、提供 GET 的小服务。Flask 的“微框架”理念让代码更聚焦而且写起来非常灵活。当然这只是一种选择。如果项目后续要扩展到用户管理、设备权限控制等复杂业务换 Django 或 FastAPI 也是很自然的事情。4.2 安装依赖先在项目目录下创建虚拟环境然后安装依赖mkdir env-server cd env-server python -m venv venv # Windows venv\Scripts\activate # macOS/Linux source venv/bin/activate pip install flask flask-cors requests依赖说明flaskWeb 框架flask-cors解决前端跨域访问问题requests虽然在服务器端不一定直接用但调试和后续扩展会用到。4.3 数据库设计为了减少部署复杂度本示例使用 SQLite 作为存储。数据库只有一张表用来保存环境数据。字段类型说明idINTEGER PRIMARY KEY自增主键device_idTEXT设备标识temperatureREAL温度值humidityREAL湿度值create_timeTEXT上报时间SQLite 不需要安装独立数据库服务文件即数据库非常契合演示项目。如果后续数据量增长可以直接把存储层替换成 MySQL 或时序数据库如 InfluxDB。4.4 Flask 完整代码# 文件路径env-server/app.py import sqlite3 import time from flask import Flask, request, jsonify from flask_cors import CORS app Flask(__name__) CORS(app) # 允许跨域请求方便 Vue 前端调试 DB_PATH env_data.db def init_db(): 初始化数据库表 conn sqlite3.connect(DB_PATH) cursor conn.cursor() cursor.execute( CREATE TABLE IF NOT EXISTS env_data ( id INTEGER PRIMARY KEY AUTOINCREMENT, device_id TEXT NOT NULL, temperature REAL NOT NULL, humidity REAL NOT NULL, create_time TEXT NOT NULL ) ) conn.commit() conn.close() app.route(/) def index(): return ESP32 Environment Server is running. app.route(/api/upload, methods[POST]) def upload(): 接收 ESP32 上报的传感器数据 try: data request.get_json() if not data: return jsonify({code: 1, message: 请求体为空或不是 JSON}), 400 temperature data.get(temperature) humidity data.get(humidity) device_id data.get(device_id, unknown) if temperature is None or humidity is None: return jsonify({code: 1, message: temperature 和 humidity 不能为空}), 400 # 基本数据范围校验 try: temperature float(temperature) humidity float(humidity) except (TypeError, ValueError): return jsonify({code: 1, message: temperature 或 humidity 格式不正确}), 400 if temperature -40 or temperature 80 or humidity 0 or humidity 100: return jsonify({code: 1, message: 数据超出合理范围}), 400 create_time time.strftime(%Y-%m-%d %H:%M:%S, time.localtime()) conn sqlite3.connect(DB_PATH) cursor conn.cursor() cursor.execute( INSERT INTO env_data (device_id, temperature, humidity, create_time) VALUES (?, ?, ?, ?), (device_id, temperature, humidity, create_time) ) conn.commit() conn.close() return jsonify({code: 0, message: success}), 200 except Exception as e: return jsonify({code: 1, message: f服务器内部错误: {str(e)}}), 500 app.route(/api/latest, methods[GET]) def latest(): 查询最新一条环境数据 conn sqlite3.connect(DB_PATH) cursor conn.cursor() cursor.execute( SELECT device_id, temperature, humidity, create_time FROM env_data ORDER BY id DESC LIMIT 1 ) row cursor.fetchone() conn.close() if row is None: return jsonify({code: 1, message: 暂无数据}), 404 return jsonify({ code: 0, data: { device_id: row[0], temperature: row[1], humidity: row[2], create_time: row[3] } }) app.route(/api/history, methods[GET]) def history(): 查询最近 N 条历史数据 limit request.args.get(limit, default50, typeint) # 限制最大查询数量防止一次性拉取过多数据 if limit 1000: limit 1000 conn sqlite3.connect(DB_PATH) cursor conn.cursor() cursor.execute( SELECT device_id, temperature, humidity, create_time FROM env_data ORDER BY id DESC LIMIT ? , (limit,)) rows cursor.fetchall() conn.close() data_list [ { device_id: row[0], temperature: row[1], humidity: row[2], create_time: row[3] } for row in rows ] return jsonify({code: 0, data: data_list}) if __name__ __main__: init_db() # 监听所有网络接口使局域网内 ESP32 可以访问 app.run(host0.0.0.0, port5000, debugTrue)4.5 接口设计解析整个后端只暴露了 3 个接口POST /api/upload设备数据上报入口也是 ESP32 调用的目标GET /api/latest获取最新一条数据GET /api/history获取历史数据供前端画曲线。在upload接口中我做了三层校验第一层判断 JSON 是否为空第二层判断关键字段是否存在第三层判断数据值的范围。这些校验虽然看起来“啰嗦”但实际项目中非常必要。比如传感器偶尔上报一个-999的温度值如果后端不做校验前面端展示时就会出现一个非常离谱的尖峰。启动服务python app.py看到类似输出说明服务已启动* Running on all addresses (0.0.0.0) * Running on http://127.0.0.1:5000此时可以先在浏览器里访问http://127.0.0.1:5000/看到ESP32 Environment Server is running.就说明后端就绪。5. Vue 前端可视化展示硬件采集、后端接收都已经完成还差最后一块拼图给用户一个可视化界面。这里采用 Vue 3 Element Plus ECharts 来展示数据。5.1 初始化 Vue 项目如果本地还没有 Vue 项目最简单的方式是使用 Vite 创建npm create vitelatest env-web -- --template vue cd env-web npm install然后安装需要的依赖npm install axios echarts element-plus依赖说明axios发起 HTTP 请求echarts绘制数据图表element-plusUI 组件库提供卡片、表格等组件。5.2 前端页面结构这里做一个简洁的单页展示页面顶部显示当前温湿度卡片中间区域用 ECharts 展示历史数据曲线。为了控制篇幅下面给出最核心的组件代码。5.3 Vue 组件代码!-- 文件路径env-web/src/App.vue -- template div classcontainer h2智能家居环境检测节点/h2 div classcard-row el-card classdata-card div classcard-title当前温度/div div classcard-value{{ currentData.temperature ?? -- }} °C/div /el-card el-card classdata-card div classcard-title当前湿度/div div classcard-value{{ currentData.humidity ?? -- }} %RH/div /el-card el-card classdata-card div classcard-title设备ID/div div classcard-value small{{ currentData.device_id ?? 暂无 }}/div /el-card /div el-card classchart-card div refchartRef classchart/div /el-card /div /template script setup import { ref, onMounted, onUnmounted } from vue; import axios from axios; import * as echarts from echarts; const currentData ref({}); const chartRef ref(null); let chartInstance null; let timer null; const API_BASE http://127.0.0.1:5000; // 获取最新一条数据 async function fetchLatest() { try { const resp await axios.get(${API_BASE}/api/latest); if (resp.data.code 0) { currentData.value resp.data.data; } } catch (e) { console.error(获取最新数据失败, e); } } // 获取历史数据并更新图表 async function fetchHistory() { try { const resp await axios.get(${API_BASE}/api/history?limit50); if (resp.data.code 0 chartInstance) { const list resp.data.data; // 后端返回的是倒序需要反转成时间正序 const reversed list.reverse(); const labels reversed.map(item item.create_time); const tempData reversed.map(item item.temperature); const humiData reversed.map(item item.humidity); chartInstance.setOption({ tooltip: { trigger: axis }, legend: { data: [温度, 湿度] }, xAxis: { type: category, data: labels }, yAxis: [ { type: value, name: 温度(°C), min: (value) Math.floor(value.min - 2), max: (value) Math.ceil(value.max 2) }, { type: value, name: 湿度(%RH), min: 0, max: 100 } ], series: [ { name: 温度, type: line, smooth: true, data: tempData }, { name: 湿度, type: line, smooth: true, yAxisIndex: 1, data: humiData } ] }); } } catch (e) { console.error(获取历史数据失败, e); } } onMounted(() { chartInstance echarts.init(chartRef.value); // 先请求一次然后定时轮询 fetchLatest(); fetchHistory(); timer setInterval(() { fetchLatest(); fetchHistory(); }, 5000); }); onUnmounted(() { if (timer) { clearInterval(timer); } if (chartInstance) { chartInstance.dispose(); } }); /script style scoped .container { max-width: 1000px; margin: 40px auto; padding: 0 20px; } .card-row { display: flex; gap: 20px; margin-bottom: 20px; } .data-card { flex: 1; text-align: center; } .card-title { color: #666; font-size: 14px; margin-bottom: 8px; } .card-value { font-size: 32px; font-weight: bold; color: #333; } .card-value.small { font-size: 18px; word-break: break-all; } .chart-card { padding: 10px; } .chart { height: 400px; } /style5.4 前端要点解析轮询而不是 WebSocket在这个项目中前端每 5 秒向后端请求一次最新数据这属于“轮询”模式。它的优点是实现简单、兼容性好。如果想让实时性更强可以后续替换为 WebSocket 或 SSE让后端主动推送数据。ECharts 双 Y 轴温度和湿度的量纲不同温度通常在 20~30 之间湿度可能在 40~70 之间。如果共用同一个 Y 轴两条曲线的波动幅度差异会很大影响观察。因此示例设置了两个 Y 轴左侧是温度右侧是湿度。为什么需要在页面销毁时处理定时器和图表实例如果页面被关闭或组件被销毁但定时器还在运行会导致内存泄漏。同样ECharts 实例虽然会被浏览器垃圾回收但显式dispose()是更稳妥的做法。运行前端项目npm run dev访问 Vite 输出的本地地址应该能看到页面。如果后端数据已经有记录图表会渲染出温湿度曲线如果没有数据图表暂时是空的但卡片区域会显示占位符--。6. 常见问题与排错实战工具链越长可能踩的坑就越多。这里把最常出现的问题整理成一个清单方便你按图索骥。问题现象常见原因解决思路Arduino 开发板管理器里搜不到 ESP32附加开发板管理器 URL 未添加或添加错误检查文件 - 首选项中的 URL确认与官方源一致安装 ESP32 开发包时下载很慢或失败网络原因导致下载工具链超时使用国内镜像源或离线安装包检查合规的网络接入方式点击“上传”后串口报Failed to connect未进入下载模式或 COM 口选择错误按住开发板 BOOT 键再点上传换一根数据线尝试串口监视器显示乱码波特率不匹配将串口波特率调为 115200DHT 读取失败输出nan接线松动、供电不足、传感器损坏重新插拔杜邦线换一个 GPIO 引脚确认模块供电 3.3V/5VESP32 POST 后无响应后端服务未启动、IP 地址错误、防火墙拦截先用浏览器访问后端地址确认服务可通检查serverUrl是否写对上传数据时 CORS 报错前端跨域访问受限后端引入flask-cors并调用CORS(app)前端图表不显示任何数据数据库为空或后端接口路径不对先用 Postman/浏览器访问/api/history确认返回 JSONESP32 上报的数据一直不更新后端服务崩溃、数据库文件被锁定查看后端控制台日志重启服务确认 SQLite 文件路径一致这里单独展开一个高频场景arduino 下载 ESP32 库失败。如果你在使用 Arduino IDE 安装 ESP32 开发包时出现类似Error downloading http://downloads.arduino.cc/...或者卡在“Downloading packages”长时间没有任何进度多半是网络原因。常见处理顺序是删除 Arduino 目录下的staging/packages临时文件避免缓存损坏。重新打开开发板管理器重试。如果依然不行换一个网络环境或者使用能顺畅访问国外站点的合规网络工具。从社区下载离线安装包esp32_package_2.x.x.zip解压到Arduino/hardware/espressif目录然后重启 Arduino IDE。需要说明的是不同版本的 Arduino IDE 对离线包目录结构的要求略有不同建议在操作前先阅读对应版本的官方说明。7. 最佳实践与工程建议到这里Demo 已经能跑通了。但作为一个认真做项目的人我们还可以把工程水平再提一个档次。以下几条建议来自实际项目中的经验做毕设、做产品都适用。7.1 设备端做好断电重连与状态上报ESP32 上电后连接 Wi-Fi 是一套固定流程但如果家里路由器重启ESP32 可能长时间无法重连。建议增加 Wi-Fi 掉线检测和自动重连机制void loop() { if (WiFi.status() ! WL_CONNECTED) { Serial.println(WiFi disconnected, reconnecting...); WiFi.reconnect(); delay(3000); return; } // 原有定时上传逻辑 }另外上报的数据里最好包含device_id。当项目中存在多个检测节点时device_id不仅是数据的身份标签也是后续做设备分组、权限控制的基础。7.2 后端数据校验要紧但不能太死前文已经写了数据范围校验。这里补充一点校验范围要根据传感器量程设计而不是瞎写。DHT11 的温度量程一般是 0~50℃DHT22 是 -40~80℃。如果后端把温度上限做成 100那么传感器损坏时上报的 99℃ 就会往数据库里灌垃圾数据。7.3 后端使用环境变量管理配置不要在代码里硬编码数据库路径、端口、密钥等信息。一个简单的做法是使用环境变量import os DB_PATH os.getenv(ENV_DB_PATH, env_data.db) PORT os.getenv(ENV_PORT, 5000)这样在开发、测试、生产环境之间切换时不需要修改代码。7.4 前端接口地址不要写死前端示例里直接把接口地址写成了http://127.0.0.1:5000。这在本地开发很方便但部署到服务器后就需要改代码。更好的方案是在项目根目录创建.env.development和.env.production文件# .env.development VITE_API_BASEhttp://127.0.0.1:5000# .env.production VITE_API_BASEhttps://api.example.com然后在代码中通过import.meta.env.VITE_API_BASE读取。7.5 数据库生命周期规划SQLite 适合小数据量场景。如果设备每天 24 小时不间断每 10 秒上报一次一天就是 8640 条数据一年就是 300 多万条。1 年后 SQLite 依然能工作但查询性能明显下降特别是有大量历史记录时。如果项目要长期运行建议提前做两步增加数据保留策略定期清理 90 天前的数据按需迁移到 MySQL 或 InfluxDB。7.6 安全不要把后端暴露在公网裸奔如果用内网穿透或公网服务器部署后端一定要考虑基本安全增加简单的 Token 认证ESP32 请求时携带Authorization: Bearer tokenFlask 服务不要以debugTrue运行在生产环境启用 HTTPS避免明文传输传感器数据对接口做限流防止被外部频繁调用打爆服务。8. 总结与下一步整个项目走下来你会发现自己其实已经完成了一个典型的物联网应用闭环ESP32 负责感知和上报Python 后端负责接收和存储Vue 前端负责可视化和展示。这套模型不仅仅是毕业设计也是很多商业物联网产品的基础架构。下一步你可以继续探索这几个方向接入更多传感器比如光照BH1750、空气质量PMS5003、烟雾MQ-2把 HTTP 改成 MQTT尝试用 EMQX/Mosquitto 做消息中间件增加报警功能温度超过阈值时后端自动发送钉钉/邮件通知增加控制功能通过后端指令控制 ESP32 上的继电器开关把前端从“只读”升级为“可配置”比如在页面设置温度报警阈值。如果本文对你有帮助可以先收藏备用。等技术细节吃透后建议自己动手把代码逐行敲一遍再扩展一个小功能。只有真正踩过坑、改过代码这套系统才会变成你自己的东西。
返回列表