如何将网页数据推送存储到CSV文件?基于ESP32+BME680传感器场景
ESP32 WebServer对接BME680数据存储CSV实现方案
核心逻辑说明
不建议从HTML前端主动推送数据存储,最优方案是ESP32采集完BME680传感器数据后,同步做两个操作:
- 把数据返回给前端网页做实时展示
- 直接在ESP32本地写入CSV文件,后续绘图时直接读取本地CSV内容返回前端即可
该方案不需要额外的前端交互逻辑,稳定性更高,资源占用更低。
具体实现步骤
1. 前置准备
首先在Arduino IDE中安装ESP32 LittleFS文件系统上传插件,使用LittleFS存储CSV文件,相比SPIFFS读写效率更高、容错性更好。
2. 文件系统与CSV初始化
启动WebServer前先挂载LittleFS,若CSV文件不存在则自动创建并写入表头:
#include <WebServer.h> #include <LittleFS.h> #include <Adafruit_BME680.h> // 按需替换为你使用的BME680库 WebServer server(80); Adafruit_BME680 bme1; Adafruit_BME680 bme2; void setup() { Serial.begin(115200); // 初始化BME680传感器代码省略 // 初始化WiFi连接代码省略 // 挂载LittleFS if(!LittleFS.begin(true)){ Serial.println("LittleFS挂载失败"); return; } // 初始化CSV文件 if(!LittleFS.exists("/sensor_data.csv")){ File csvFile = LittleFS.open("/sensor_data.csv", "w"); if(csvFile){ // 写入表头,按需调整字段 csvFile.println("timestamp,s1_temp,s1_hum,s1_press,s1_voc,s2_temp,s2_hum,s2_press,s2_voc"); csvFile.close(); } } // 注册Web接口代码省略 server.begin(); }
3. 传感器数据写入CSV逻辑
每次完成传感器读数后调用追加写入函数,把数据存入CSV:
void appendCsv(long ts, float s1t, float s1h, float s1p, float s1v, float s2t, float s2h, float s2p, float s2v){ File csvFile = LittleFS.open("/sensor_data.csv", "a"); if(csvFile){ csvFile.printf("%ld,%.2f,%.2f,%.2f,%.0f,%.2f,%.2f,%.2f,%.0f\n", ts, s1t, s1h, s1p, s1v, s2t, s2h, s2p, s2v); csvFile.close(); } } // 传感器读数示例调用 void readSensorAndSave(){ bme1.performReading(); bme2.performReading(); long timestamp = millis(); // 可替换为NTP同步的UTC时间戳 appendCsv( timestamp, bme1.temperature, bme1.humidity, bme1.pressure/100, bme1.gas_resistance/1000, bme2.temperature, bme2.humidity, bme2.pressure/100, bme2.gas_resistance/1000 ); }
4. 可选:前端主动推送存储方案
如果业务需要前端触发存储,可在ESP32新增POST接收接口,前端通过fetch请求推送数据:
ESP32接口代码
server.on("/save-data", HTTP_POST, [](){ if(!server.hasArg("s1_temp") || !server.hasArg("s2_temp")){ server.send(400, "text/plain", "参数缺失"); return; } long ts = millis(); appendCsv( ts, server.arg("s1_temp").toFloat(), server.arg("s1_hum").toFloat(), server.arg("s1_press").toFloat(), server.arg("s1_voc").toFloat(), server.arg("s2_temp").toFloat(), server.arg("s2_hum").toFloat(), server.arg("s2_press").toFloat(), server.arg("s2_voc").toFloat() ); server.send(200, "text/plain", "保存成功"); });
前端JS调用代码
// 拿到页面上展示的传感器数值后调用 function pushDataToSave(s1Data, s2Data){ fetch('/save-data', { method: 'POST', headers: {'Content-Type': 'application/x-www-form-urlencoded'}, body: `s1_temp=${s1Data.temp}&s1_hum=${s1Data.hum}&s1_press=${s1Data.press}&s1_voc=${s1Data.voc}&s2_temp=${s2Data.temp}&s2_hum=${s2Data.hum}&s2_press=${s2Data.press}&s2_voc=${s2Data.voc}` }) }
5. 绘图用CSV读取接口
新增接口返回CSV全量内容,前端拿到后即可解析为数组传入图表库绘图:
server.on("/get-csv", [](){ if(!LittleFS.exists("/sensor_data.csv")){ server.send(404, "text/plain", "文件不存在"); return; } File csvFile = LittleFS.open("/sensor_data.csv", "r"); server.send(200, "text/csv", csvFile.readString()); csvFile.close(); });
注意事项
- LittleFS默认分配的存储空间有限,建议采样间隔不小于1分钟,避免快速占满Flash空间
- 写入前可调用
LittleFS.totalBytes() - LittleFS.usedBytes()判断剩余空间,避免写入失败 - 如需长期大量存储,可外接SD卡模块,替换LittleFS为ESP32 SD库即可,读写逻辑基本一致
- 存储在Flash中的CSV文件掉电不会丢失,重启设备后可正常读取
内容的提问来源于stack exchange,提问作者Cezar Constantin
相关产品推荐
相关产品推荐

