
1. 项目概述与核心价值最近在捣鼓一个智能家居的小项目需要实时监控书房的温湿度看看是不是该开加湿器或者空调了。市面上现成的智能温湿度计不少但要么数据出不来要么云端服务说停就停总感觉不够“自主可控”。于是我决定自己动手用ESP32和AHT10传感器攒一个。这个方案的好处是硬件成本极低一套下来几十块钱软件完全开源数据可以存在本地也能同步到你自己可控的云端最关键的是整个链路透明从传感器读数到网页显示再到云端同步每一步你都能自己掌控和修改。这个项目本质上是一个典型的物联网数据采集终端。它的核心工作流非常清晰ESP32作为主控通过I2C总线从高精度的AHT10传感器读取温度和湿度数据然后ESP32利用其内置的Wi-Fi模块一方面创建一个本地Web服务器让你在同一个局域网内用手机或电脑浏览器就能实时查看数据另一方面它周期性地将数据打包通过HTTP协议发送到ThingSpeak这类物联网平台实现数据的云端存储、可视化图表生成以及历史记录查询。无论是想做个温室环境监测还是仓库的仓储环境监控或者像我一样只是做个家庭环境看板这套方案都是一个非常扎实的起点。下面我就把从硬件选型、环境搭建、代码编写到调试部署的完整过程以及我踩过的坑和总结的经验毫无保留地分享出来。2. 硬件选型与电路连接解析2.1 核心器件选型理由为什么是ESP32和AHT10这是经过一番对比后的选择。首先看主控芯片ESP32。在物联网开发领域ESP32几乎是性价比的代名词。它集成了双核240MHz的处理器、520KB SRAM、4MB Flash以DevKit开发板常见配置为例性能足以应对复杂的网络任务。最关键的是它原生支持Wi-Fi和蓝牙省去了外接无线模块的麻烦和成本。相比于经典的ESP8266ESP32的处理器性能更强、内存更大、外设更丰富比如更多的GPIO、DAC等在多任务处理和稳定性上更有优势。对于我们这个需要同时运行Web服务器和进行HTTP客户端上传的项目ESP32游刃有余。其次是传感器AHT10。温湿度传感器有很多比如DHT11、DHT22、SHT30等。AHT10是继SHT30之后的一个不错选择。它采用I2C数字接口比DHT系列的单总线通信更标准、更可靠抗干扰能力更强。其测量精度也相当可观温度精度±0.3°C湿度精度±2% RH在25°C条件下完全满足绝大多数民用和一般工业监控场景。此外它的体积小巧功耗很低长期运行的稳定性也很好。相比于一些模拟传感器数字输出的AHT10无需复杂的AD转换和校准使用起来非常方便。注意购买AHT10时注意区分AHT10和AHT20。AHT20是升级款精度略有提升且内部算法有优化但引脚和通信协议完全兼容我们使用的Adafruit库可以自动识别所以两者在这个项目中可以通用。2.2 电路连接与原理图连接非常简单只需要4根杜邦线。这里务必理解每个引脚的作用接错了可能烧毁传感器。VCC - 3.3VAHT10的工作电压是2.2V-5.5VESP32的3.3V输出引脚为其供电。严禁连接到5V引脚否则会损坏传感器。GND - GND共地为电路提供共同的参考零电位这是所有电路正常通信的基础。SCL - GPIO22I2C时钟线。ESP32上I2C接口的引脚可以自定义但通常默认使用GPIO22作为SCL。SDA - GPIO21I2C数据线。同样通常默认使用GPIO21作为SDA。I2C总线是一种同步、半双工、多主多从的串行通信总线。你可以把它想象成一条电话线SDA配上一个节拍器SCL。主设备ESP32控制节拍器SCL发出规律的时钟信号然后在特定的节拍上通过电话线SDA发送设备地址、命令或数据。总线上可以挂载多个从设备比如AHT10或者再加一个光照传感器BMP280每个设备有唯一的地址主设备通过“呼叫”这个地址来与特定的从设备对话。这种结构使得用很少的线两根就能管理多个传感器非常适合嵌入式系统。连接实物时建议使用面包板或者直接焊接避免杜邦线接触不良导致数据读取失败。如果使用ESP32 DevKit V1这类板子引脚通常都有清晰的丝印标注。连接完成后最好用万用表通断档检查一下VCC和GND有没有短路这是上电前的好习惯。3. 软件开发环境搭建与配置3.1 Arduino IDE与ESP32开发包安装虽然ESP32可以用乐鑫官方的ESP-IDF框架开发但对于大多数从Arduino入门的开发者来说使用Arduino IDE配合ESP32开发包是最快上手的路径。首先去Arduino官网下载并安装最新版的Arduino IDE。安装完成后打开我们需要告诉IDE去哪里找ESP32的开发板支持。点击文件(File) 首选项(Preferences)找到“附加开发板管理器网址”输入框。如果里面已经有其他网址用逗号隔开然后添加以下网址https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json这个URL指向了乐鑫官方维护的ESP32 Arduino核心库的索引文件。接着点击工具(Tools) 开发板(Board) 开发板管理器(Boards Manager)在搜索框输入“esp32”。你应该会看到由“Espressif Systems”提供的“esp32”包。点击它然后选择安装。这个过程会下载编译工具链、核心库以及各种ESP32板型的定义耗时可能几分钟取决于你的网络。实操心得安装过程中如果遇到下载失败通常是网络问题。可以尝试使用稳定的网络连接或者查找国内开发者提供的镜像源进行替换。安装成功后在工具 开发板菜单下你应该能看到一长串ESP32系列的板型选择“ESP32 Dev Module”即可它是最通用的配置。3.2 必要库文件的安装我们的项目需要两个关键的库来驱动AHT10传感器Adafruit Unified Sensor库和Adafruit AHTx0库。前者是一个传感器抽象层为不同类型的Adafruit传感器提供统一的接口后者是专门针对AHT10/AHT20/AHT21传感器的驱动库。在Arduino IDE中点击项目(Sketch) 加载库(Include Library) 管理库(Manage Libraries...)打开库管理器。在搜索框输入“Adafruit Unified Sensor”找到后点击安装。再次搜索“Adafruit AHTx0”找到后点击安装。安装库时IDE可能会提示某些库有依赖关系需要一并安装务必点击“安装全部”同意。这些库文件会被下载到你的Arduino IDE安装目录下的libraries文件夹中。库安装成功后在代码中通过#include Adafruit_AHTX0.h即可调用。注意事项务必确保安装的是“Adafruit AHTx0”库而不是旧的“Adafruit AHT10”库如果存在。新库兼容性更好且支持AHT20等新型号。库的版本也可能影响功能如果遇到编译问题可以尝试在库管理器中查看库的详情选择另一个版本安装测试。4. 核心功能实现本地Web服务器4.1 代码结构与初始化流程我们先实现本地Web服务器功能这样即使没有互联网也能在局域网内查看数据。完整的代码思维如下#include WiFi.h #include WebServer.h #include Adafruit_AHTX0.h // 1. 网络配置 const char* ssid 你的Wi-Fi名称; const char* password 你的Wi-Fi密码; // 2. 创建Web服务器对象监听80端口 WebServer server(80); // 3. 创建AHT传感器对象 Adafruit_AHTX0 aht; // 获取独立的温湿度传感器对象指针便于分别读取 Adafruit_Sensor *aht_humidity nullptr; Adafruit_Sensor *aht_temp nullptr; // 4. 处理根路径请求的函数 void handleRoot() { // 读取传感器数据 sensors_event_t humidity_event, temp_event; aht_humidity-getEvent(humidity_event); aht_temp-getEvent(temp_event); // 构建一个简单的HTML页面 String html !DOCTYPE htmlhtmlheadmeta charsetUTF-8; html title环境监测/title; html meta http-equivrefresh content5; // 每5秒自动刷新页面 html stylebody{font-family: sans-serif; text-align: center; margin-top: 50px;}; html .data{font-size: 2.5em; color: #333; margin: 20px;}; html .label{color: #666;}/style/headbody; html h1 实时环境监测/h1; html div classdataspan classlabel温度: /span; html String(temp_event.temperature, 1); // 保留一位小数 html °C/div; html div classdataspan classlabel湿度: /span; html String(humidity_event.relative_humidity, 1); html %/div; html psmall数据更新时间: String(millis() / 1000) 秒前/small/p; html /body/html; // 发送HTTP 200响应和HTML内容 server.send(200, text/html, html); } void setup() { Serial.begin(115200); delay(1000); // 给串口和硬件一个启动时间 // 第一步连接Wi-Fi Serial.println(正在连接Wi-Fi: String(ssid)); WiFi.begin(ssid, password); while (WiFi.status() ! WL_CONNECTED) { delay(500); Serial.print(.); } Serial.println(\nWi-Fi连接成功!); Serial.print(本地IP地址: ); Serial.println(WiFi.localIP()); // 打印出ESP32获取到的IP用于浏览器访问 // 第二步初始化AHT10传感器 Serial.println(正在初始化AHT10传感器...); if (!aht.begin()) { Serial.println(未找到AHT10/AHT20传感器请检查接线。); while (1) delay(10); // 卡死在这里提示错误 } Serial.println(AHT10传感器初始化成功); // 获取温湿度传感器的抽象对象 aht_temp aht.getTemperatureSensor(); aht_humidity aht.getHumiditySensor(); // 第三步配置Web服务器路由 server.on(/, handleRoot); // 将根路径“/”的请求绑定到handleRoot函数 // 可以添加更多路由例如 /api/data 返回JSON数据 // server.on(/api/data, handleApiData); // 启动Web服务器 server.begin(); Serial.println(HTTP Web服务器已启动); } void loop() { // 必须不断调用此函数以处理客户端请求 server.handleClient(); // 这里可以添加其他非阻塞任务例如LED闪烁指示状态 }4.2 关键代码段深度解析WiFi连接过程WiFi.begin(ssid, password)是发起连接但这是一个非阻塞操作。后面的while循环不断检查WiFi.status()直到其变为WL_CONNECTED才表示连接成功。打印出的WiFi.localIP()至关重要这是你在浏览器中需要输入的地址如192.168.1.100。传感器初始化与数据读取aht.begin()会尝试通过I2C与传感器通信。如果失败最常见的原因是接线错误SDA/SCL接反、电源接错或I2C地址不对AHT10的默认地址是0x38。成功初始化后我们通过aht.getTemperatureSensor()和aht.getHumiditySensor()获取了两个独立的传感器对象指针。这样做的好处是代码结构清晰符合Adafruit统一传感器库的设计模式。在handleRoot函数中getEvent()方法用于触发一次数据读取并将结果填充到sensors_event_t结构体中。Web服务器工作原理WebServer库创建了一个轻量级的HTTP服务器。server.on(“/“, handleRoot)这行代码注册了一个“路由”——当有客户端比如浏览器访问ESP32的IP地址时即根路径“/”服务器就会自动调用handleRoot函数来生成响应内容。server.handleClient()必须在loop()中频繁调用它负责监听网络端口检查是否有新的HTTP请求到达并分发给对应的处理函数。HTML页面与自动刷新我们构建的HTML字符串中meta http-equiv’refresh’ content’5’这一行实现了页面每5秒自动刷新一次达到了“伪实时”的效果。这是一种简单粗暴但有效的实时数据展示方法。对于更复杂的交互可以考虑使用WebSocket或AJAX技术。5. 核心功能实现数据上传至ThingSpeak5.1 ThingSpeak平台配置详解本地查看解决了“有无”问题但数据无法持久化也无法远程查看。这时就需要云端平台这里我们选择ThingSpeak因为它对个人开发者免费且配置简单可视化功能强大。注册与登录访问ThingSpeak官网用MathWorks账户即MATLAB账户登录。如果没有需要先注册一个。创建频道(Channel)登录后点击“Channels” - “My Channels” - “New Channel”。每个频道代表一个数据源。Name给你的频道起个名字如“My Room Monitor”。Description可选的描述。Field 1勾选“Field 1”标签(Label)填写“Temperature” 可以勾选“Show last value on chart”。Field 2勾选“Field 2”标签填写“Humidity”。其他字段可以留空。然后点击“Save Channel”保存。获取API密钥频道创建成功后点击顶部的“API Keys”标签页。这里你会看到两个关键的KeyWrite API Key用于向这个频道写入数据。这是我们代码中需要的。务必保管好不要泄露。Read API Keys用于从频道读取数据可以创建多个并设置不同的权限。查看数据视图保存频道后你可以直接进入“Private View”或“Public View”标签页这里已经为你生成了Field 1和Field 2的实时图表。当有数据写入后图表就会动态更新。5.2 集成ThingSpeak的Arduino代码实现现在我们修改代码在读取传感器数据后额外增加一个向ThingSpeak发送数据的任务。为了不阻塞本地Web服务器我们需要合理安排两个任务的执行时机。一个常见的做法是Web服务器实时响应请求而云端上传则按固定间隔如每15秒或每分钟执行一次。我们需要安装ThingSpeak的官方库。同样在库管理器中搜索“ThingSpeak”由“MathWorks”发布安装即可。但这里为了更清晰地理解HTTP通信过程我将展示直接使用ESP32内置的HTTPClient库进行上传的代码这更有助于理解底层机制。#include WiFi.h #include WebServer.h #include Adafruit_AHTX0.h #include HTTPClient.h // 用于HTTP请求 // 网络和ThingSpeak配置 const char* ssid 你的Wi-Fi名称; const char* password 你的Wi-Fi密码; const char* thingspeak_server api.thingspeak.com; const String write_api_key 你的Write_API_Key; // 替换为你的密钥 WebServer server(80); Adafruit_AHTX0 aht; Adafruit_Sensor *aht_humidity nullptr; Adafruit_Sensor *aht_temp nullptr; // 新增记录上次上传时间 unsigned long lastUploadTime 0; const unsigned long uploadInterval 15000; // 上传间隔单位毫秒 (15秒) void handleRoot() { // ... (与之前相同的handleRoot函数用于生成网页) } void uploadToThingSpeak(float temperature, float humidity) { // 检查Wi-Fi连接状态 if (WiFi.status() ! WL_CONNECTED) { Serial.println(Wi-Fi断开无法上传数据到ThingSpeak); return; } HTTPClient http; // 构建完整的请求URL // 格式http://api.thingspeak.com/update?api_keyYOUR_KEYfield1温度值field2湿度值 String url http:// String(thingspeak_server) /update?; url api_key write_api_key; url field1 String(temperature, 2); // field1对应温度保留2位小数 url field2 String(humidity, 2); // field2对应湿度 Serial.print(正在上传数据到ThingSpeakURL: ); Serial.println(url); // 开始HTTP GET请求 http.begin(url); int httpResponseCode http.GET(); // 检查响应 if (httpResponseCode 0) { Serial.print(HTTP响应代码: ); Serial.println(httpResponseCode); String response http.getString(); // 获取服务器响应内容 Serial.print(服务器响应: ); Serial.println(response); // ThingSpeak成功接收数据后通常会返回一个大于0的整数如数据条目ID if (response.toInt() 0) { Serial.println(数据上传成功); } else { Serial.println(数据上传可能失败请检查API Key和字段设置。); } } else { Serial.print(HTTP请求失败错误代码: ); Serial.println(httpResponseCode); Serial.println(错误信息: http.errorToString(httpResponseCode)); } // 释放资源 http.end(); } void setup() { // ... (与之前相同的setup函数初始化串口、Wi-Fi、传感器、Web服务器) } void loop() { // 1. 必须首先处理客户端请求这是Web服务器的核心 server.handleClient(); // 2. 定时执行ThingSpeak上传任务非阻塞方式 unsigned long currentMillis millis(); // 获取当前运行时间 if (currentMillis - lastUploadTime uploadInterval) { lastUploadTime currentMillis; // 更新上次上传时间 // 读取传感器数据 sensors_event_t humidity_event, temp_event; if (aht_humidity aht_temp) { // 安全检查 aht_humidity-getEvent(humidity_event); aht_temp-getEvent(temp_event); float temp temp_event.temperature; float humi humidity_event.relative_humidity; Serial.printf(准备上传数据 - 温度: %.2f°C, 湿度: %.2f%%\n, temp, humi); // 调用上传函数 uploadToThingSpeak(temp, humi); } } // 这里可以添加其他非阻塞任务例如用LED指示状态 // 例如快速闪烁表示正在处理网络慢闪表示空闲常亮表示错误等 }5.3 双任务协作与非阻塞设计解析这段代码实现了一个简单的协作式多任务系统。关键在于loop()函数中的设计Web服务器任务server.handleClient()调用频率非常高每次loop()都执行它负责快速响应来自浏览器的HTTP请求保证网页访问的实时性。这是一个事件驱动的任务有请求才工作。数据上传任务我们使用基于时间的状态机来实现定时。millis()函数返回ESP32上电后的毫秒数不会像delay()那样阻塞整个程序。我们记录上次上传的时间lastUploadTime每次loop()都检查当前时间currentMillis是否已经过去了设定的间隔uploadInterval。如果到了就执行一次数据读取和上传然后更新lastUploadTime。这样上传任务就以固定的周期在后台运行完全不影响Web服务器对请求的即时响应。这种模式避免了在loop()中使用delay(15000)否则在这15秒内Web服务器将完全无法响应用户体验极差。这是嵌入式网络编程中的一个重要技巧。6. 系统集成、优化与深度调试6.1 将两个功能整合为一个完整项目现在我们将本地Web服务器和ThingSpeak上传功能整合到一个完整的项目中。上面的代码已经是一个很好的整合范例。上传功能不会影响本地网页的访问两者并行不悖。你可以将完整的代码编译上传到ESP32。上传与测试步骤用USB线连接ESP32和电脑。在Arduino IDE中选择正确的板型工具 开发板 ESP32 Arduino ESP32 Dev Module和端口工具 端口。点击上传按钮。首次上传可能需要按一下ESP32板上的“BOOT”或“EN”按钮来进入下载模式具体因板而异。上传成功后打开串口监视器工具 串口监视器波特率设置为115200。你将看到Wi-Fi连接过程、传感器初始化信息、Web服务器启动信息以及周期性的ThingSpeak上传日志。在串口监视器中找到打印出的本地IP地址如192.168.31.220在电脑或手机的浏览器中输入这个地址即可看到实时刷新的温湿度网页。同时打开你的ThingSpeak频道页面等待一两个上传周期约30秒你应该能看到图表上开始出现数据点。6.2 功耗优化与电源考量如果你希望设备是电池供电的比如放在没有电源的阳台花房那么功耗就是关键。ESP32在全速运行Wi-Fi和处理器时电流可能达到100mA以上这对电池是巨大的消耗。优化策略使用深度睡眠Deep Sleep这是最有效的省电方式。让ESP32每隔一段时间如5分钟唤醒一次连接Wi-Fi读取传感器数据上传到云端然后立刻进入深度睡眠。在深度睡眠模式下电流可以降至10μA级别。这需要修改硬件接线将ESP32的GPIO0或GPIO2取决于型号连接到RST引脚并通过代码调用esp_deep_sleep_start()。但这样无法运行本地Web服务器因为设备大部分时间在睡觉。降低CPU频率在setup()中调用setCpuFrequencyMhz(80)将CPU主频从240MHz降到80MHz可以显著降低动态功耗。调整Wi-Fi模式如果不需要作为AP热点确保只使用STA模式。在长时间不通信时可以尝试断开Wi-Fi连接WiFi.disconnect(true)但重新连接耗时且耗电需要权衡。使用高效的电源方案对于长期监测推荐使用18650锂电池配合TP4056充电模块和AMS1117-3.3V稳压模块供电或者直接使用专用的锂电池供电的ESP32开发板。实操心得对于需要同时保持本地Web访问和云端上传的常供电设备深度睡眠不适用。此时可以关注ESP32的“轻睡眠”模式或动态调频但省电效果有限。我的经验是如果插电方便优先保证功能稳定如果是电池供电且数据更新频率要求不高如每小时一次果断采用“深度睡眠云端上传”的架构放弃本地实时网页。6.3 提升数据可靠性与错误处理工业级应用要求系统稳定可靠。我们的代码需要增加健壮性。传感器读取失败重试AHT10偶尔可能读取失败。我们应该增加重试机制。bool readSensorData(float temp, float humi, int maxRetries 3) { sensors_event_t humidity_event, temp_event; for (int i 0; i maxRetries; i) { if (aht_humidity-getEvent(humidity_event) aht_temp-getEvent(temp_event)) { temp temp_event.temperature; humi humidity_event.relative_humidity; // 可以增加数据合理性校验例如温度在-40到85度之间 if (temp -40 temp 85 humi 0 humi 100) { return true; } } delay(50); // 短暂延迟后重试 } Serial.println(传感器读取失败); return false; }在uploadToThingSpeak和handleRoot中调用这个函数而不是直接getEvent。Wi-Fi断开重连网络环境可能不稳定。可以在loop()中增加Wi-Fi状态监控。void checkWiFiConnection() { if (WiFi.status() ! WL_CONNECTED) { Serial.println(Wi-Fi连接丢失尝试重连...); WiFi.disconnect(); WiFi.reconnect(); int retries 0; while (WiFi.status() ! WL_CONNECTED retries 20) { delay(500); Serial.print(.); retries; } if (WiFi.status() WL_CONNECTED) { Serial.println(\nWi-Fi重连成功); } else { Serial.println(\nWi-Fi重连失败); } } }然后在loop()中定期调用checkWiFiConnection()。HTTP上传失败处理与数据缓存如果网络暂时不通上传ThingSpeak会失败。我们可以将失败的数据暂时缓存到SPIFFSESP32的文件系统中等网络恢复后再尝试补传。这涉及到更复杂的队列管理和文件操作是提升数据可靠性的高级技巧。7. 常见问题排查与进阶扩展7.1 问题排查速查表在实际操作中你几乎一定会遇到下面这些问题。这里是一个快速排查指南问题现象可能原因排查步骤编译错误1. 库未安装或版本冲突。2. 开发板未正确选择。3. 代码语法错误。1. 检查库管理器确保Adafruit AHTx0和Unified Sensor库已安装。2. 确认工具 开发板中选择了“ESP32 Dev Module”。3. 查看Arduino IDE下方的输出窗口根据具体错误信息修改代码。上传失败1. USB线或端口问题。2. ESP32未进入下载模式。3. 驱动未安装Windows系统常见。1. 换一根数据线确保能传数据不只是充电。2. 上传时尝试按住ESP32板上的“BOOT”键再点击上传等开始编译后再松开。3. 在设备管理器中查看端口安装CP210x或CH340驱动。串口监视器无输出/乱码1. 波特率设置错误。2. 串口被其他软件占用。3. 板子型号或引脚定义错误。1. 确保波特率设置为115200。2. 关闭可能占用串口的其他软件如串口助手、Putty。3. 检查代码中Serial.begin(115200)与监视器设置一致。“Failed to find AHT10”1. 物理接线错误VCC/GND/SCL/SDA。2. I2C地址错误。3. 传感器损坏。1.重点检查VCC是否接3.3VSDA/SCL是否接对GPIO21/22接触是否良好2. 使用I2C扫描程序确认传感器地址AHT10通常是0x38。3. 万用表测量VCC和GND之间电压是否为3.3V。Wi-Fi无法连接1. SSID/密码错误。2. ESP32离路由器太远。3. 路由器设置了MAC过滤或仅支持5GHz。1. 仔细核对代码中的SSID和密码注意大小写和特殊字符。2. 查看串口输出确认连接过程。尝试将设备靠近路由器。3. 确保路由器2.4GHz网络开启并暂时关闭MAC地址过滤。能连Wi-Fi但无法访问网页1. 防火墙或杀毒软件拦截。2. 手机/电脑与ESP32不在同一局域网。3. Web服务器未成功启动。1. 暂时关闭电脑防火墙和杀毒软件试试。2. 确认手机连接的是同一个Wi-Fi而非流量。3. 查看串口日志确认“HTTP Web服务器已启动”并记下正确的IP地址。ThingSpeak无数据1. Write API Key错误。2. 网络问题导致HTTP请求失败。3. 字段(Field)编号不对。1.最常见原因仔细核对代码中的write_api_key确保与ThingSpeak频道API Keys页面的Write API Key完全一致。2. 查看串口日志中uploadToThingSpeak函数的输出看HTTP响应代码和服务器返回信息。3. 确保URL中的field1和field2与频道中创建的字段顺序对应。7.2 项目进阶扩展思路这个基础项目可以作为一个平台进行无限扩展多传感器融合ESP32的I2C总线可以挂载多个设备。你可以轻松地添加一个BMP280气压传感器、SGP30VOC/CO2传感器或光照传感器在网页和ThingSpeak上展示更多环境参数。本地数据记录使用ESP32的SPIFFS或外接MicroSD卡模块将传感器数据以CSV格式记录在本地防止网络中断时数据丢失。设计Web界面用更美观的HTML/CSS/JavaScript重写前端页面使用Chart.js绘制实时曲线图甚至添加控制按钮如控制一个继电器开关加湿器。更换云平台ThingSpeak适合快速原型。你可以将数据上传到更强大的平台如阿里云物联网平台、腾讯云IoT Explorer、Home Assistant或自建的MQTT服务器如EMQX获得更灵活的数据处理和自动化能力。低功耗远程监测结合前述的深度睡眠和锂电池供电将设备封装进3D打印的外壳做成一个真正的无线传感器节点部署到任何需要监测的地方。添加报警功能在代码中设置温湿度阈值当数据超标时可以通过ESP32连接蜂鸣器发出本地警报或者通过IFTTT、Bark等服务平台向你的手机发送推送通知。从我实际搭建和运行这个系统的经验来看最关键的其实不是代码本身而是耐心调试。硬件连接、网络环境、平台配置每一个环节都可能出点小问题。但只要按照步骤充分利用串口打印的信息进行排查最终看到网页上跳动的数字和ThingSpeak上生成的曲线时那种成就感是非常实在的。这个项目就像一把钥匙帮你打开了物联网硬件开发的大门后面的世界更精彩。