Files
DistributedCollectorGateway/docs/OFFLINE_STORAGE.md

433 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 离线数据存储和补传功能说明
## 功能概述
本设备支持离线数据存储功能当网络断开时数据会自动存储到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最小文件大小为4KB200字节的文件实际占用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需手动添加组件