ESPHome实战:在reTerminal E上集成RTC、SD卡与麦克风实现离线数据记录
1. 项目缘起为什么要在ESPHome里折腾RTC、SD卡和麦克风最近在折腾一个基于reTerminal E系列开发板的智能家居边缘节点项目核心需求是让它成为一个能独立工作的“数据记录员”。这个想法源于一个很实际的痛点家里的几个传感器温湿度、光照、空气质量数据虽然可以通过Wi-Fi上报到云端但一旦网络波动或者路由器重启那段时间的数据就丢了。更别提有些需要高频率采样比如每秒钟记录一次噪音水平的场景持续往云端发数据不仅占带宽对服务器和电费也不友好。所以我的目标很明确让这个边缘节点具备本地存储和精确计时的能力必要时还能采集音频进行分析比如判断家里是否异常安静或者识别特定的环境声音模式。reTerminal E系列板子本身集成了ESP32-S3芯片、一个彩色LCD屏、几个物理按键外设接口也挺丰富是个绝佳的平台。而ESPHome作为智能家居领域广受喜爱的固件框架以其声明式的配置和强大的集成能力成了我的首选。但当我真正开始配置时发现官方文档和社区案例对于“同时启用RTC实时时钟、SD卡存储和I2S麦克风”这个组合拳的完整指南并不多。尤其是如何让它们协同工作——比如用SD卡记录带精确时间戳的传感器数据或者用麦克风录制一段定时启动的音频片段——需要自己摸索。这就是这篇“菜谱”的由来它不是简单的功能堆砌而是解决一个具体场景下“离线、带时间戳、多模态数据记录”需求的完整方案。如果你也想打造一个不依赖云、数据自主的智能设备这篇内容应该能帮你省下不少折腾的时间。2. 硬件选型与核心原理拆解在动手写YAML配置之前我们必须先搞清楚手头的“食材”——reTerminal E系列开发板——以及我们要用的几个“厨具”到底是怎么工作的。理解原理才能避免后面配置时一头雾水。2.1 reTerminal E系列开发板外设接口分析reTerminal E系列板载的ESP32-S3芯片功能强大但我们要用的功能大多依赖于其外围接口。关键点在于引脚复用和电源管理。首先RTC实时时钟。ESP32-S3内部集成了一个RTC模块但它通常依赖一个外部的32.768kHz晶振来保持高精度计时。更重要的是这个RTC在深度睡眠Deep Sleep模式下依然可以运行并由板上的纽扣电池如果有的话供电。reTerminal E系列通常预留了纽扣电池接口这是实现离线精确计时的硬件基础。RTC的核心价值是提供一个不受网络同步和主电源影响的独立时间源。即使设备重启或断网只要后备电池有电它就知道“现在几点”。其次SD卡。ESP32-S3通过SDMMC或SPI接口与SD卡通信。reTerminal E板上的SD卡槽通常连接的是SDMMC主机控制器这是一条高速的4位数据总线CMD, CLK, D0, D1, D2, D3比SPI模式快得多。启用SD卡功能时ESPHome会将其挂载为本地文件系统类似于/sd目录这样我们就可以用熟悉的文件操作API来读写数据。这里的一个关键细节是电源SD卡特别是大容量或高速卡在启动和写入时峰值电流可能不小。如果板载的3.3V电源线路设计余量不足可能导致SD卡初始化失败或写入不稳定。这也是很多人在其他ESP32板子上常踩的坑。最后麦克风以INMP441为例。这是一款常见的I2S数字麦克风。I2SInter-IC Sound是一种专门用于传输音频数据的串行总线标准包含三条线位时钟BCLK、帧时钟LRCLK和数据线SD。INMP441是PDM麦克风输出的是脉冲密度调制信号需要ESP32-S3内部的I2S外设或PDM转PCM的硬件单元将其转换为标准的PCM音频数据。这里涉及两个层面的配置一是正确的物理连接数据线、时钟线、电源和接地二是ESPHome中I2S总线和麦克风传感器组件的软件配置。时序和时钟配置不对就只会收到一片噪音或沉默。2.2 ESPHome组件协同工作原理在ESPHome的配置中这三个组件并非孤立存在而是通过框架的生命周期管理和服务调用联系在一起的。初始化顺序ESPHome启动时会按照配置文件的顺序初始化组件。一个稳健的顺序是先初始化i2c总线如果RTC模块如DS3231是I2C接口然后初始化rtc时间源接着是sdmmc或spi总线及sdcard最后是i2s和microphone。这样确保当麦克风开始工作时时间服务和存储服务已经就绪。时间同步流理想情况下我们优先从网络NTP获取精确时间并同步到内部RTC。当网络不可用时则完全依靠RTC提供时间。在ESPHome中这通过time组件实现它可以配置多个时间源如homeassistant、ntp并指定一个rtc作为后备存储。每次从网络获取到时间后会自动写入RTC启动时则优先从RTC读取时间。数据记录流麦克风采集到的音频数据PCM格式是一个巨大的字节流。直接写入SD卡是不现实的我们需要一个“管道”。通常的做法是在lambda或on_...触发器中将处理后的数据比如每秒钟的噪音分贝值以追加模式写入SD卡上的一个文件如/sd/log.csv。同时将RTC提供的当前时间戳一并写入形成一条完整记录。电源管理协同如果我们想让设备定时录音比如每小时录10秒就需要用到深度睡眠。流程是RTC作为唤醒源设备被唤醒后初始化SD卡和麦克风执行录音并保存文件然后再次进入深度睡眠。这里要特别注意进入深度睡眠前必须妥善卸载SD卡文件系统sd.unmount()否则可能损坏文件系统。ESPHome的deep_sleep组件可以配置在进入睡眠前执行特定的动作。注意硬件I2S和SDMMC可能会共用ESP32-S3的某些IO引脚或DMA通道。虽然ESP32-S3外设资源相对丰富但在配置时仍需查阅你手中具体版本的reTerminal E原理图确认引脚分配无冲突。例如SD卡的标准SDMMC接口通常会占用一组特定的GPIO而这组GPIO可能无法同时用作其他功能。3. 分步配置详解从零搭建数据记录系统理论讲完了现在进入实战环节。假设我们的reTerminal E板子已经通过USB连接电脑并且ESPHome环境无论是HA插件、Docker还是CLI已经就绪。下面是一份完整的、可逐段验证的esp32-s3-devkitc-1.yaml或其他对应板型配置详解。3.1 基础板型与日志配置任何ESPHome项目的第一步都是正确定义开发板并配置好串口日志这对调试至关重要。esphome: name: reterminal-data-logger friendly_name: ReTerminal Data Logger esp32: board: esp32-s3-devkitc-1 # 请根据你的reTerminal E具体型号调整可能是 esp32-s3-box-3 或其他 variant: esp32s3 framework: type: arduino # 启用详细的日志方便排查SD卡、I2S初始化问题 logger: level: DEBUG baud_rate: 0 # 禁用启动时的串口日志波特率设置避免与某些硬件冲突 # 启用Wi-Fi和OTA方便后续更新固件 wifi: ssid: !secret wifi_ssid password: !secret wifi_password ap: {} # 保留AP模式作为后备 api: encryption: key: !secret api_encryption_key ota: password: !secret ota_password web_server: port: 80关键点解析board的定义直接影响后续的引脚定义。务必从Seeed Studio的官方文档或示例中确认正确的板型名称。选错了可能导致引脚编号映射错误。将logger的baud_rate设为0是因为某些板子的串口在启动时被用于其他通信如LCD设置波特率可能会干扰。我们依赖Wi-Fi下的api日志输出或web_server的日志页面来查看调试信息。3.2 配置RTC时间源这里我们使用ESP32内部的RTC并通过NTP进行网络同步。这是最常见和经济的方案。# 首先配置NTP时间同步作为主要时间源 time: - platform: sntp id: ntp_time servers: - 0.pool.ntp.org - 1.pool.ntp.org timezone: Asia/Shanghai # 设置你的时区 on_time: # 每分钟同步一次到RTC可选用于保持RTC精度 - cron: * * * * * then: - lambda: |- if (id(rtc_clock).is_ready()) { auto tm id(ntp_time).now(); id(rtc_clock).update_time(tm); } # 配置内部RTC作为后备时钟存储 rtc: - platform: esp32_rtc id: rtc_clock关键点解析sntp平台从互联网获取时间。on_time触发器配合cron表达式可以定期将网络时间写入硬件RTC抵消RTC晶振的微小漂移。esp32_rtc平台就是芯片内部的硬件RTC。它的id被其他组件引用。当设备启动时time组件会优先尝试从rtc_clock读取时间如果RTC未初始化或时间无效则等待NTP同步。一个常见坑点在深度睡眠唤醒后的首次启动中Wi-Fi连接需要时间NTP同步可能几秒甚至几十秒后才完成。如果你的应用唤醒后需要立刻知道准确时间那么必须依赖RTC。确保在进入深度睡眠前RTC的时间是正确的即已经通过网络同步过。3.3 挂载SD卡存储SD卡配置是稳定性关键。我们使用速度更快的SDMMC模式。# 配置SDMMC主机4位模式高速 sdmmc: clk_pin: GPIO36 # 请务必根据reTerminal E原理图确认这些引脚 cmd_pin: GPIO37 d0_pin: GPIO38 d1_pin: GPIO39 d2_pin: GPIO40 d3_pin: GPIO41 frequency: 20MHz # 初始频率可设低一些提高兼容性 mode: SDMMC # 将SD卡挂载为文件系统 sdcard: id: my_sdcard mount_point: /sd # 设置最大打开文件数如果你需要同时操作多个文件 max_open_files: 5 # 定义一个文本传感器来显示SD卡信息可选用于调试 text_sensor: - platform: sdcard id: sd_info type: info on_value: then: - logger.log: SD Card: %s关键点解析引脚定义是重中之重clk_pin,cmd_pin,d0_pin等必须与reTerminal E板上SD卡槽的实际物理连接一致。错误是100%失败的。查阅官方Wiki或原理图是唯一途径。frequency: 20MHz是一个保守的起始值。如果卡能正常初始化你可以在后续尝试提高到40MHz以获得更快读写速度。但有些质量一般的卡或长线连接可能在高速下不稳定。mount_point: /sd指定了挂载点。之后在lambda中就可以使用/sd/xxx的路径来访问文件。实测避坑经验SD卡最好使用Class 10或更高速度等级的知名品牌卡并格式化为FAT32文件系统对于32GB及以下的卡。首次插入前在电脑上完整格式化一次而不是快速格式化。ESP32的SDMMC驱动对某些卡尤其是山寨卡或exFAT格式的卡兼容性不佳。3.4 集成I2S数字麦克风以INMP441为例假设INMP441麦克风模块通过排线连接到了reTerminal E的某个I2S接口。# 首先启用I2S音频总线 i2s_audio: i2s_lrclk_pin: GPIO5 # LRCLK (WS) i2s_bclk_pin: GPIO6 # BCLK (SCK) i2s_din_pin: GPIO7 # DIN (SD) - 麦克风数据输入 # i2s_dout_pin: GPIOXX # 如果是扬声器输出才需要 mode: master bits_per_sample: 32 # INMP441输出24位数据放在32位容器中 sample_rate: 16000Hz # 采样率16kHz对于环境音足够越高数据量越大 # 配置I2S麦克风传感器 microphone: - platform: i2s_audio id: i2s_mic i2s_audio_id: i2s_audio_default # 引用上面定义的i2s_audio组件 adc_type: external pdm: true # INMP441是PDM麦克风需要设置此标志 channel: left # 通常接左声道 bits_per_sample: 32 sample_rate: 16000Hz # 可以添加一个增益可选 gain: 1.0 # 定义一个传感器将麦克风的原始音频数据转换为分贝值A加权 sensor: - platform: i2s_audio microphone: i2s_mic id: sound_level_db name: Sound Level dB(A) type: db_a update_interval: 1s # 每秒钟计算并输出一次分贝值 filters: - sliding_window_moving_average: # 加一个移动平均滤波使读数更稳定 window_size: 10 send_every: 1关键点解析引脚再次确认i2s_lrclk_pin,i2s_bclk_pin,i2s_din_pin必须与硬件连接匹配。reTerminal E可能预留了特定的I2S引脚排母。mode: master表示ESP32作为I2S主机为麦克风提供时钟信号。pdm: true是关键。INMP441输出的是PDM信号ESP32-S3内部有硬件PDM转PCM单元设置此标志会启用该硬件加速降低CPU负载。如果设为false你会收到一堆无法解析的噪音。type: db_a是ESPHome提供的一个非常实用的功能它直接将原始的PCM音频数据流实时计算为A加权分贝值省去了我们自己写DSP算法的麻烦。这对于噪音监测应用来说就是“开箱即用”。供电与接地确保麦克风模块的3.3V和GND连接良好且稳定。数字麦克风对电源噪声比较敏感糟糕的供电会导致底噪增大。如果可能使用板载的线性稳压器LDO输出而不是开关电源输出。4. 功能集成与数据流实战组件都配好了现在让它们“活”起来实现我们预设的场景定时将传感器数据包括声音分贝连同时间戳记录到SD卡。4.1 创建数据记录服务我们首先在ESPHome中定义一个“服务”Service这个服务可以被自动化调用执行一次数据记录动作。# 在 esphome: 块同级定义一个自定义的“服务” api: # ... (前面的api配置) services: - service: log_data_to_sd description: 记录当前时间、声音分贝值到SD卡文件 fields: - name: note type: string description: 可选的备注信息 optional: true on_call: then: - lambda: |- // 1. 获取当前时间 auto tm id(ntp_time).now(); if (!tm.is_valid()) { // 如果网络时间无效尝试从RTC获取 tm id(rtc_clock).now(); } char time_str[64]; snprintf(time_str, sizeof(time_str), %04d-%02d-%02d %02d:%02d:%02d, tm.year, tm.month, tm.day_of_month, tm.hour, tm.minute, tm.second); // 2. 获取声音分贝值 float db_level id(sound_level_db).state; if (isnan(db_level)) { db_level -99.0; // 表示无效数据 } // 3. 获取可选备注 std::string note_str ; if (note.has_value()) { note_str *note; } // 4. 构造CSV格式的一行数据 char line_buffer[256]; snprintf(line_buffer, sizeof(line_buffer), \%s\,%.2f,\%s\\n, time_str, db_level, note_str.c_str()); // 5. 打开SD卡文件并追加写入重要使用追加模式a FILE *file fopen(/sd/data_log.csv, a); if (file nullptr) { ESP_LOGE(main, Failed to open file for writing!); return; } fputs(line_buffer, file); fclose(file); // 务必关闭文件 ESP_LOGI(main, Data logged: %s, line_buffer);关键点解析服务定义在api.services下这样可以通过Home Assistant的esphome.service调用也可以通过ESPHome的本地API调用。on_call内的lambda是核心逻辑。我们首先尝试获取最精确的时间先网络后RTC。文件操作使用了标准的C库fopen,fputs,fclose。路径前缀/sd对应之前的挂载点。关键细节文件打开模式。使用a追加模式而不是w写入。w模式每次都会清空文件只会保留最后一次记录。a模式则在文件末尾追加符合数据记录的需求。务必检查fopen返回值并关闭文件SD卡操作可能因卡拔出、写保护或文件系统错误而失败。不检查返回值会导致后续fputs崩溃。不关闭文件不仅可能导致数据丢失还可能损坏文件系统。4.2 配置自动化触发器有了记录服务我们需要决定何时触发它。这里配置两个自动化一个是基于时间的定期记录另一个是当声音超过阈值时的触发记录。# 在 time 组件的 on_time 触发器里添加定期记录 time: - platform: sntp id: ntp_time # ... 其他配置 on_time: # 每分钟的第30秒记录一次数据 - seconds: 30 minutes: /1 # 每分钟 then: - service: esphome.log_data_to_sd data: note: Scheduled Log # 利用传感器的 on_value 触发器在声音过大时记录 sensor: - platform: i2s_audio id: sound_level_db # ... 其他配置 on_value: above: 70.0 # 当分贝值超过70dB时触发 then: - throttle: 10s # 10秒内只触发一次防止持续尖叫写爆SD卡 - service: esphome.log_data_to_sd data: note: High Noise Alert!关键点解析time的on_time触发器非常精确适合做定时采样。这里配置为每分钟的第30秒记录一次避免在整点时刻与其他任务冲突。sensor的on_value触发器配合above条件实现了事件驱动记录。throttle限制器至关重要防止在持续高噪音环境下每秒写入几十次快速耗尽SD卡寿命和存储空间。你还可以添加更多传感器如温湿度、光照到log_data_to_sd服务的lambda中一并记录形成多参数的环境日志。4.3 实现深度睡眠与定时唤醒录音对于电池供电的场景深度睡眠是省电的关键。我们希望设备每小时唤醒一次录音10秒后保存然后继续睡眠。# 首先定义一个全局变量来标记是否正在录音非必须但有助于逻辑清晰 globals: - id: is_recording type: bool restore_value: no initial_value: false # 配置深度睡眠组件 deep_sleep: id: deep_sleep_1 run_duration: 10s # 唤醒后运行10秒用于录音和保存 sleep_duration: 1h # 然后睡眠1小时 wakeup_pin: GPIO0 # 通常RTC可以通过GPIO0唤醒具体看板子设计 # 在进入睡眠前我们需要卸载SD卡 on_before_deep_sleep: then: - lambda: |- // 停止I2S麦克风 id(i2s_mic).stop(); // 卸载SD卡文件系统这是防止数据损坏的关键步骤 if (id(my_sdcard).is_mounted()) { id(my_sdcard).unmount(); ESP_LOGI(main, SD card unmounted for sleep.); } # 在启动时根据唤醒原因决定做什么 esphome: name: reterminal-data-logger # ... 其他配置 on_boot: priority: -100 # 较低优先级让其他组件先初始化 then: - lambda: |- // 检查是否是深度睡眠唤醒 if (id(deep_sleep_1).wakeup_cause() esp_sleep_wakeup_cause_t::ESP_SLEEP_WAKEUP_TIMER) { ESP_LOGI(main, Woke up from deep sleep. Starting recording task.); id(is_recording) true; // 延迟一小段时间确保SD卡和麦克风初始化完成 delay(1000); // 开始录音这里需要你实现一个开始录音的函数见下文 start_recording_for_duration(10000); // 录音10秒 } else { ESP_LOGI(main, Cold boot or other wakeup.); id(is_recording) false; } # 你需要实现一个自定义函数来开始录音并保存到文件 # 这通常需要更底层的I2S音频流处理超出了基础组件范围。 # 一个思路是在on_boot触发后启动一个任务从麦克风读取原始PCM数据写入一个.wav文件。 # 由于代码较长这里给出概念性伪代码 # 1. 使用 id(i2s_mic).start() 开始采集。 # 2. 在一个循环中调用 id(i2s_mic).read_samples(buffer, buffer_size) 获取音频数据。 # 3. 将数据追加写入 /sd/record_YYYYMMDD_HHMMSS.wav 文件注意先写入WAV文件头。 # 4. 录音达到指定时长后停止采集关闭文件然后调用 id(deep_sleep_1).begin_sleep()。关键点解析deep_sleep的run_duration和sleep_duration是核心参数决定了设备的工作/休眠占空比。on_before_deep_sleep是黄金安全钩子。必须在睡眠前调用sd.unmount()否则正在进行的写操作会被强行中断极大概率导致文件系统损坏下次唤醒可能无法挂载。on_boot中的逻辑区分了冷启动和深度睡眠唤醒。对于定时录音场景我们只在睡眠唤醒后才执行录音任务。重要限制ESPHome的标准microphone组件主要面向实时处理如分贝计算不直接提供“录制原始音频到文件”的高级API。实现完整录音功能需要编写自定义组件或使用更底层的i2s_audio流API这涉及管理音频数据缓冲区、写入WAV格式文件头等复杂度较高。对于大多数环境监测场景记录分贝值随时间变化的曲线已经足够。如果需要录音可能需要考虑使用Arduino原生开发或等待ESPHome未来增强此功能。5. 调试、排错与性能优化配置写好了编译刷入设备跑起来了但事情往往没那么顺利。下面分享一些我踩过的坑和对应的解决办法。5.1 SD卡初始化失败从硬件到软件的排查链现象日志中看到sdmmc: card init failed!或sdcard: Mount failed!。第一步检查硬件连接与电源物理接触SD卡是否插到底卡槽弹簧是否老化用酒精棉片擦拭SD卡金手指。电源质量这是最常见的原因。用万用表测量SD卡槽的VCC引脚电压。在ESP32启动和SD卡初始化的瞬间电压是否被拉低到3.0V以下如果是说明板载LDO功率不足或电源路径阻抗太大。可以尝试换用容量更小、速度等级较低的SD卡如4GB Class 4。在SD卡的VCC和GND之间并联一个100μF的钽电容或低ESR的电解电容以提供瞬间电流。如果板子有外部供电接口尝试使用5V/2A以上的电源适配器供电而非USB。第二步检查软件配置引脚定义再次、三次核对sdmmc部分的clk_pin,cmd_pin,d0_pin等是否与你的具体板型的原理图完全一致。不同批次的reTerminal E可能有细微改动。频率设置将frequency从20MHz降低到10MHz甚至5MHz。高频率对布线要求高。文件系统将SD卡在电脑上格式化为FAT32分配单元大小32KB并执行完整格式化而非快速格式化。驱动日志将logger的level设置为VERBOSE或DEBUG可以获取更详细的SDMMC驱动初始化日志有时会提示具体的错误码。第三步分步测试先注释掉所有其他组件麦克风、RTC等只保留最基本的Wi-Fi、Logger和SD卡配置看能否成功挂载。如果不行尝试使用spi模式而不是sdmmc模式需要修改硬件连接和配置虽然速度慢但兼容性更好。5.2 麦克风无声或全是噪音现象sound_level_db传感器读数一直是0、-99或者是一个毫无规律的疯狂跳动的值。第一步确认物理连接与供电接线确认INMP441的3.3V、GND、SD数据、SCK位时钟、WS帧时钟五条线是否正确且牢固连接。WS线接错会导致左右声道混乱或无声。供电噪声数字麦克风对电源纹波敏感。尝试在麦克风模块的VCC和GND之间并联一个0.1μF和10μF的电容组合进行退耦。第二步检查I2S配置核心配置pdm: true对于INMP441这个必须设为true。如果设为falseESP32会试图解析PCM数据结果就是噪音。引脚映射确认i2s_din_pin连接的是麦克风的DOUT引脚。这是一个常见的反向错误。时钟极性大多数I2S设备在时钟上升沿采样。虽然ESPHome默认配置通常正确但如果遇到问题可以尝试在i2s_audio配置中添加dma_buf_count和dma_buf_len参数来调整DMA缓冲区有时能解决爆音或断流问题。例如i2s_audio: # ... 引脚配置 dma_buf_count: 8 dma_buf_len: 256第三步软件诊断将microphone的gain暂时调到10.0或更高看看读数是否有任何变化。如果还是完全没变化可能是数据根本没进来。在lambda中尝试直接读取原始的I2S数据流并打印一小段十六进制看是否是全0或固定模式。这需要更深入的代码但能直接判断硬件层是否有数据。5.3 RTC时间不准或丢失现象设备断电再上电后时间归零或者每天慢/快几分钟。第一步检查后备电池如果reTerminal E板上有纽扣电池座通常是CR1220或类似确保电池有电且极性正确。用万用表测量电压应不低于2.8V。如果没有电池那么ESP32的RTC在完全断电后肯定会丢失时间。你需要依赖每次启动时的NTP同步。第二步优化时间同步逻辑确保Wi-Fi连接稳定。可以在time组件配置中增加更多备用NTP服务器如cn.pool.ntp.org。在on_boot的最开始增加一个等待NTP同步的循环带超时确保关键任务在获得有效时间后才执行。on_boot: then: - lambda: |- int timeout 0; while (!id(ntp_time).now().is_valid() timeout 30) { delay(1000); timeout; ESP_LOGI(main, Waiting for NTP sync... %d, timeout); } if (timeout 30) { ESP_LOGW(main, NTP sync timeout, using RTC time.); }定期比如每天一次用NTP时间校准RTC以修正晶振漂移。本文3.2节on_time中的cron任务就是干这个的。5.4 系统稳定性与内存优化当同时运行SD卡文件操作、I2S音频流处理、Wi-Fi通信时ESP32-S3的资源可能紧张。堆内存监控在logger中启用heap传感器定期查看剩余内存。sensor: - platform: free_heap name: Free Heap Memory update_interval: 30s如果内存持续下降内存泄漏检查lambda中是否有动态内存分配new,malloc而没有释放。优先使用栈上变量或全局静态缓冲区。任务堆栈如果自行创建了Arduino任务xTaskCreate来处理音频流务必分配足够的堆栈空间建议至少4096字。文件操作优化避免在高速循环中频繁fopen/fclose。对于数据记录可以在启动时打开文件在需要时写入在睡眠前或定期才关闭。但要注意意外断电的风险。使用setbuf(file, NULL)禁用文件缓冲或者定期fflush(file)确保数据及时写入卡中而不是留在内存缓冲区。电源管理如果不需要实时连接可以配置Wi-Fi在数据同步后进入睡眠模式。使用deep_sleep是最终的省电方案但如前所述需要妥善处理外设SD卡卸载、麦克风停止。