Files
DistributedCollectorGateway/docs/OFFLINE_STORAGE.md

11 KiB
Raw Blame History

离线数据存储和补传功能说明

功能概述

本设备支持离线数据存储功能当网络断开时数据会自动存储到Flash文件系统中当网络恢复后数据会自动补传到MQTT服务器。

系统架构

┌─────────────────────────────────────────────────┐
│                   应用层                          │
├─────────────────────────────────────────────────┤
│  MODBUS数据     设备状态      MQTT客户端         │
│       │              │              │            │
│       ▼              ▼              ▼            │
│  ┌─────────────────────────────────────┐       │
│  │        离线数据管理模块               │       │
│  │    (OFFLINE_STORAGE 组件)            │       │
│  └─────────────────────────────────────┘       │
│       │                                    │    │
│       ▼                                    │    │
│  ┌─────────────────────────────────────┐       │
│  │     SPIFFS文件系统                 │       │
│  │    (FLASH_SPIFS 组件)               │       │
│  └─────────────────────────────────────┘       │
│       │                                    │    │
│       ▼                                    │    │
│  ┌─────────────────────────────────────┐       │
│  │       16MB Flash存储区               │       │
│  │          (8MB可用)                   │       │
│  └─────────────────────────────────────┘       │
└─────────────────────────────────────────────────┘

分区表配置

# 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最小文件大小为4KB200字节的文件实际占用4KB空间因此实际可存储的时长会更短。建议将多条数据合并到一个文件中存储以提高空间利用率。

文件组织结构

/flash/
├── data/
│   ├── modbus/              # MODBUS采集数据
│   │   ├── 1738452345.json  # 时间戳命名
│   │   ├── 1738452346.json
│   │   └── ...
│   └── status/              # 设备状态数据
│       ├── 1738452345.json
│       └── ...
└── index.json              # 索引文件

工作流程

正常模式(网络在线)

数据产生
  ↓
检测网络状态(在线)
  ↓
直接发布到MQTT
  ↓
不存储

离线模式(网络断开)

数据产生
  ↓
检测网络状态(离线)
  ↓
存储到Flash SPIFFS
  ↓
写入成功
  ↓
等待网络恢复

补传模式(网络恢复)

检测网络状态(在线)
  ↓
检查是否有离线数据
  ↓
读取最旧的数据
  ↓
发布到MQTT
  ↓
发布成功?
  ├─ 是 → 删除该数据 → 继续下一条
  └─ 否 → 等待重试

API接口

FLASH_SPIFS 组件

初始化文件系统

esp_err_t flash_spiffs_init(void);

检查是否挂载

bool flash_spiffs_is_mounted(void);

获取存储使用情况

uint32_t flash_spiffs_get_total_size(void);
uint32_t flash_spiffs_get_used_size(void);

格式化文件系统

esp_err_t flash_spiffs_format(void);

OFFLINE_STORAGE 组件

初始化存储模块

esp_err_t offline_storage_init(void);

存储离线数据

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_MODBUSMODBUS采集数据
    • OFFLINE_DATA_TYPE_DEVICE_STATUS:设备状态数据

读取最旧的数据

esp_err_t offline_storage_read_oldest(char *buffer, size_t max_len, offline_data_type_t *out_data_type);

删除最旧的数据

esp_err_t offline_storage_delete_oldest(void);

获取数据数量

uint32_t offline_storage_get_count(void);
bool offline_storage_has_data(void);

清空所有数据

esp_err_t offline_storage_clear_all(void);

MQTT_ESP 扩展接口

存储离线数据(内部使用)

esp_err_t mqtt_store_offline(const char *data, size_t length, offline_data_type_t data_type);

启动/停止补传任务

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. 合并多条数据

将多条数据合并到一个文件中存储:

// 示例每100条数据存储为一个文件
// 空间利用率100 * 200字节 / 4096字节 ≈ 4.9%
// 单文件存储100 * 200字节 / 4096字节 = 100%

2. 降低存储频率

网络离线时降低存储频率:

// 在线1秒/次
// 离线10秒/次
// 可存储时长110小时

3. 选择性存储

只存储关键数据:

// 只存储异常数据、状态变化
// 正常数据丢弃

4. 定期格式化

建议每隔1-3个月格式化一次文件系统消除碎片

flash_spiffs_format();

监控和调试

查看存储使用情况

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);

查看离线数据数量

uint32_t count = offline_storage_get_count();
ESP_LOGI(TAG, "Offline data files: %u", count);

格式化存储

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需手动添加组件