# 离线数据存储和补传功能说明 ## 功能概述 本设备支持离线数据存储功能,当网络断开时,数据会自动存储到Flash文件系统中;当网络恢复后,数据会自动补传到MQTT服务器。 ## 系统架构 ``` ┌─────────────────────────────────────────────────┐ │ 应用层 │ ├─────────────────────────────────────────────────┤ │ MODBUS数据 设备状态 MQTT客户端 │ │ │ │ │ │ │ ▼ ▼ ▼ │ │ ┌─────────────────────────────────────┐ │ │ │ 离线数据管理模块 │ │ │ │ (OFFLINE_STORAGE 组件) │ │ │ └─────────────────────────────────────┘ │ │ │ │ │ │ ▼ │ │ │ ┌─────────────────────────────────────┐ │ │ │ SPIFFS文件系统 │ │ │ │ (FLASH_SPIFS 组件) │ │ │ └─────────────────────────────────────┘ │ │ │ │ │ │ ▼ │ │ │ ┌─────────────────────────────────────┐ │ │ │ 16MB Flash存储区 │ │ │ │ (8MB可用) │ │ │ └─────────────────────────────────────┘ │ └─────────────────────────────────────────────────┘ ``` ## 分区表配置 ```csv # Name, Type, SubType, Offset, Size, Flags nvs, data, nvs, 0x9000, 0x6000, phy_init, data, phy, 0xf000, 0x1000, factory, app, factory, 0x10000, 2MB, storage, data, spiffs, 0x210000,8MB, ``` - **storage分区**:8MB,用于离线数据存储 - **挂载点**:`/flash` - **文件系统**:SPIFFS ## 存储容量估算 | 参数 | 数值 | |------|------| | Flash总容量 | 16MB | | 存储分区大小 | 8MB | | MODBUS数据量 | 200字节/条(1秒/次) | | 每小时数据量 | 720KB | | 可存储时长 | 约11小时 | **注意**:SPIFFS最小文件大小为4KB,200字节的文件实际占用4KB空间,因此实际可存储的时长会更短。建议将多条数据合并到一个文件中存储以提高空间利用率。 ## 文件组织结构 ``` /flash/ ├── data/ │ ├── modbus/ # MODBUS采集数据 │ │ ├── 1738452345.json # 时间戳命名 │ │ ├── 1738452346.json │ │ └── ... │ └── status/ # 设备状态数据 │ ├── 1738452345.json │ └── ... └── index.json # 索引文件 ``` ## 工作流程 ### 正常模式(网络在线) ``` 数据产生 ↓ 检测网络状态(在线) ↓ 直接发布到MQTT ↓ 不存储 ``` ### 离线模式(网络断开) ``` 数据产生 ↓ 检测网络状态(离线) ↓ 存储到Flash SPIFFS ↓ 写入成功 ↓ 等待网络恢复 ``` ### 补传模式(网络恢复) ``` 检测网络状态(在线) ↓ 检查是否有离线数据 ↓ 读取最旧的数据 ↓ 发布到MQTT ↓ 发布成功? ├─ 是 → 删除该数据 → 继续下一条 └─ 否 → 等待重试 ``` ## API接口 ### FLASH_SPIFS 组件 #### 初始化文件系统 ```c esp_err_t flash_spiffs_init(void); ``` #### 检查是否挂载 ```c bool flash_spiffs_is_mounted(void); ``` #### 获取存储使用情况 ```c uint32_t flash_spiffs_get_total_size(void); uint32_t flash_spiffs_get_used_size(void); ``` #### 格式化文件系统 ```c esp_err_t flash_spiffs_format(void); ``` ### OFFLINE_STORAGE 组件 #### 初始化存储模块 ```c esp_err_t offline_storage_init(void); ``` #### 存储离线数据 ```c esp_err_t offline_storage_store(const char *data, size_t length, offline_data_type_t data_type); ``` **参数**: - `data`:数据内容(JSON字符串) - `length`:数据长度 - `data_type`:数据类型 - `OFFLINE_DATA_TYPE_MODBUS`:MODBUS采集数据 - `OFFLINE_DATA_TYPE_DEVICE_STATUS`:设备状态数据 #### 读取最旧的数据 ```c esp_err_t offline_storage_read_oldest(char *buffer, size_t max_len, offline_data_type_t *out_data_type); ``` #### 删除最旧的数据 ```c esp_err_t offline_storage_delete_oldest(void); ``` #### 获取数据数量 ```c uint32_t offline_storage_get_count(void); bool offline_storage_has_data(void); ``` #### 清空所有数据 ```c esp_err_t offline_storage_clear_all(void); ``` ### MQTT_ESP 扩展接口 #### 存储离线数据(内部使用) ```c esp_err_t mqtt_store_offline(const char *data, size_t length, offline_data_type_t data_type); ``` #### 启动/停止补传任务 ```c BaseType_t mqtt_start_offline_upload_task(void); void mqtt_stop_offline_upload_task(void); ``` ## 网络状态检测 系统通过MQTT连接状态判断网络是否在线: | MQTT事件 | 网络状态 | 处理 | |---------|---------|------| | `MQTT_EVENT_CONNECTED` | 在线 | 启动补传任务 | | `MQTT_EVENT_DISCONNECTED` | 离线 | 停止补传任务 | ## 存储策略 ### 自动循环覆盖 - **最大文件数限制**:10,000个文件 - **触发条件**:当文件数超过限制时,自动删除最旧的数据 - **优先级**:按时间戳排序,删除最旧的数据 ### 数据完整性保护 - **索引文件**:`/flash/index.json` 记录所有文件信息 - **原子写入**:使用临时文件+重命名机制 - **断电保护**:SPIFFS提供基本断电保护 ### 存储空间管理 ``` 获取空间使用情况 ↓ 检查可用空间 ↓ 空间不足? ├─ 否 → 正常存储 └─ 是 → 删除最旧数据 → 重试 ``` ## SPIFFS 特性说明 ### 优点 - ESP-IDF原生支持,无需额外组件 - 代码成熟稳定 - 内存占用小(约2KB) - 挂载速度快 ### 缺点 - 最小文件大小为4KB,小文件浪费空间 - 无磨损均衡,Flash寿命相对较短 - 碎片严重,长期使用后性能下降 - 不支持目录(所有文件在根目录) ### 优化建议 1. **合并多条数据到单个文件**:减少文件数量,提高空间利用率 2. **定期格式化**:消除碎片,恢复性能 3. **限制文件数量**:避免碎片积累 ## 日志输出 ### 初始化日志 ``` I (xxxx) main: Initializing SPIFFS file system... I (xxxx) FLASH_SPIFS: 正在初始化SPIFFS文件系统... I (xxxx) FLASH_SPIFS: SPIFFS文件系统挂载成功 I (xxxx) FLASH_SPIFS: 总空间: 8388608 字节 I (xxxx) FLASH_SPIFS: 已用空间: 4096 字节 I (xxxx) FLASH_SPIFS: 可用空间: 8384512 字节 I (xxxx) FLASH_SPIFS: 挂载点: /flash I (xxxx) main: Initializing offline storage module... I (xxxx) main: 离线存储模块初始化完成 ``` ### 存储日志 ``` I (xxxx) mqtt_esp: Storing offline data (type=1, size=256) I (xxxx) OFFLINE_STORAGE: 存储数据: /flash/data/modbus/1738452345.json, 大小: 256 字节 I (xxxx) OFFLINE_STORAGE: Storage usage: 4096 / 8388608 bytes (0.0%) W (xxxx) OFFLINE_STORAGE: 注意:SPIFFS最小文件大小为4KB,小文件会占用更多空间 ``` ### 补传日志 ``` I (xxxx) mqtt_esp: Network is online, starting offline data upload I (xxxx) mqtt_esp: Found 10 offline data files, uploading... I (xxxx) mqtt_esp: Publishing offline data (type=1, size=256) I (xxxx) mqtt_esp: Offline data published successfully, msg_id=12345 ``` ## 故障处理 ### Flash空间不足 **现象**: ``` E (xxxx) OFFLINE_STORAGE: 无法创建文件 ``` **解决**: 1. 自动删除最旧的数据 2. 格式化存储分区 ### 文件系统损坏 **现象**: ``` E (xxxx) FLASH_SPIFS: 挂载失败 ``` **解决**: 1. 系统会尝试自动修复 2. 如修复失败,格式化文件系统 3. 检查Flash硬件 ### 数据补传失败 **现象**: ``` E (xxxx) mqtt_esp: Failed to publish offline data ``` **解决**: 1. 检查网络连接 2. 检查MQTT服务器状态 3. 数据会保留在Flash中,下次重试 ## 性能优化建议 ### 1. 合并多条数据 将多条数据合并到一个文件中存储: ```c // 示例:每100条数据存储为一个文件 // 空间利用率:100 * 200字节 / 4096字节 ≈ 4.9% // 单文件存储:100 * 200字节 / 4096字节 = 100% ``` ### 2. 降低存储频率 网络离线时降低存储频率: ```c // 在线:1秒/次 // 离线:10秒/次 // 可存储时长:110小时 ``` ### 3. 选择性存储 只存储关键数据: ```c // 只存储异常数据、状态变化 // 正常数据丢弃 ``` ### 4. 定期格式化 建议每隔1-3个月格式化一次文件系统,消除碎片: ```c flash_spiffs_format(); ``` ## 监控和调试 ### 查看存储使用情况 ```c size_t used = 0, total = 0; offline_storage_get_usage(&used, &total); ESP_LOGI(TAG, "Storage: %zu / %zu bytes", used, total); ESP_LOGI(TAG, "Usage: %.1f%%", (used * 100.0) / total); ``` ### 查看离线数据数量 ```c uint32_t count = offline_storage_get_count(); ESP_LOGI(TAG, "Offline data files: %u", count); ``` ### 格式化存储 ```c flash_spiffs_format(); ``` ## 注意事项 1. **首次启动**:会自动格式化文件系统(如果需要) 2. **断电保护**:SPIFFS提供基本断电保护,但建议避免频繁断电 3. **Flash寿命**:SPIFFS无磨损均衡,建议定期格式化以延长寿命 4. **容量限制**:由于SPIFFS最小文件4KB,实际可存储时长会少于理论值 5. **补传速率**:每秒处理一条数据,避免阻塞新数据上传 6. **碎片问题**:长期使用后性能可能下降,建议定期格式化 ## 后续扩展建议 1. **数据压缩**:集成zlib压缩,延长存储时长 2. **批量存储**:将多条数据合并到一个文件中 3. **优先级队列**:重要数据优先补传 4. **数据导出**:通过Web界面导出离线数据 5. **统计信息**:记录丢失/补传的数据统计 6. **智能采样**:根据存储空间动态调整采样率 7. **定期维护**:实现自动碎片整理和格式化 ## 与LittleFS对比 | 特性 | SPIFFS | LittleFS | |------|--------|----------| | 最小文件大小 | 4KB | 0字节 | | 内存占用 | ~2KB | ~4KB | | 磨损均衡 | ❌ 无 | ✅ 自带 | | 断电保护 | ⚠️ 一般 | ✅ 优秀 | | 支持目录 | ❌ 不支持 | ✅ 支持 | | 碎片问题 | ❌ 严重 | ✅ 轻微 | | ESP-IDF支持 | ✅ 原生支持 | ❌ 需第三方组件 | **选择建议**: - 如果需要ESP-IDF原生支持且数据量不大 → SPIFFS - 如果需要更好的性能和寿命 → LittleFS(需手动添加组件)