基于边缘计算网关的 Modbus 与 DL/T 645 协议数据清洗与断网续传实现

在公共空间、园区、楼宇的物联网项目中,底层设备协议繁杂:电表多为 DL/T 645,温湿度、氨气、液位等传感器多为 Modbus RTU,部分新设备又走 MQTT。现场网络还极不稳定,4G 波动、信号遮挡、断网是常态。如果所有协议解析、数据清洗都放在云端,不仅延迟高,断网期间数据还会永久丢失。本文从嵌入式实现角度,讨论如何在边缘计算网关本地完成多协议解析、数据清洗和断网续传。

协议解析与统一数据模型

Modbus RTU 的帧结构相对简单,典型组成包括从站地址、功能码、数据长度、寄存器数据、CRC 校验。例如读取保持寄存器时,主站下发:

复制代码
[从站地址][03H][起始寄存器高][起始寄存器低][寄存器数量高][寄存器数量低][CRC低][CRC高]

DL/T 645 的帧格式则不同,常见为:

复制代码
68H | A0~A5 | 68H | 控制码 | 数据长度 | 数据域 | CS | 16H

其中 68H 为帧起始符,A0~A5 为表地址,控制码决定读/写操作,数据域携带寄存器值或电量数据,CS 为校验和。两种协议在物理层、帧结构、校验方式上都不一致,直接交给云端处理会让上层业务承担过多适配成本。

更合理的做法是在网关侧完成协议解析,然后映射到统一数据模型。示例如下:

复制代码
typedef struct {
    uint32_t timestamp;      /* 采集时间戳,单位秒 */
    uint16_t device_id;      /* 设备ID */
    uint8_t  protocol;       /* 0: Modbus, 1: DL/T645 */
    float    voltage;        /* 电压 V */
    float    current;        /* 电流 A */
    float    active_power;   /* 有功功率 kW */
    uint8_t  is_clean;       /* 0: 原始数据, 1: 清洗后数据 */
} StandardDataPoint;

解析 Modbus 时,可根据寄存器地址映射电压、电流、功率;解析 DL/T 645 时,则从数据域中提取对应编码字段。解析完成后,统一写入 StandardDataPoint,后续清洗、缓存、上传都基于同一结构体处理。

边缘数据清洗:去毛刺,但不丢原始数据

现场采集的数据经常会出现毛刺。通信干扰、传感器瞬态异常、设备重启、电源波动,都可能让某一次采样值明显偏离正常范围。如果直接上传,云端报表会出现跳变;如果简单丢弃,又可能丢失真实异常。

一个较实用的做法是:滑动窗口均值 + 3-Sigma 异常剔除,同时保留原始数据。

复制代码
import math

def clean_data_point(values, window=5, k=3.0):
    if len(values) < 2:
        return values[-1], True

    window_data = values[-window:]
    mean = sum(window_data) / len(window_data)
    variance = sum((x - mean) ** 2 for x in window_data) / len(window_data)
    std = math.sqrt(variance)

    current = values[-1]

    if std < 1e-6:
        return current, True

    if abs(current - mean) > k * std:
        return mean, False  # 异常值,用均值替代,但原始值仍入库
    return current, True

这里的关键不是"把异常值删掉",而是区分两条数据链路:

  • 原始通道 :所有原始采样值入库,is_clean = 0,用于审计、追溯、故障定位。
  • 清洗通道 :经过滤波后的数据入库,is_clean = 1,用于平台展示、报表和告警。

这样即使清洗算法误判,也能通过原始数据回溯。边缘侧保留原始数据,是后续断网续传和审计对账的基础。

断网缓存与断点续传

现场网络不稳定时,网关不能因为云端暂时不可达就丢弃数据。通常做法是把数据先写入本地轻量数据库,网络恢复后再按时间顺序补传。Redis 并不适合这种场景,因为它默认内存存储,断电后数据容易丢失;SQLite 或本地时序库更稳妥。

本地建表示例:

复制代码
CREATE TABLE IF NOT EXISTS data_points (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    timestamp INTEGER NOT NULL,
    device_id INTEGER NOT NULL,
    protocol  INTEGER NOT NULL,
    voltage   REAL,
    current   REAL,
    active_power REAL,
    is_clean  INTEGER NOT NULL DEFAULT 0,
    uploaded  INTEGER NOT NULL DEFAULT 0
);

CREATE INDEX IF NOT EXISTS idx_ts_uploaded
ON data_points(timestamp, uploaded);

采集线程每次解析完成后,将数据插入本地表,uploaded = 0 表示尚未上传。上传线程在网络正常时查询未上传数据:

复制代码
SELECT * FROM data_points
WHERE uploaded = 0
ORDER BY timestamp ASC
LIMIT 100;

每批上传成功后,再更新状态:

复制代码
UPDATE data_points
SET uploaded = 1
WHERE id IN (/* 本批已上传ID */);

断点续传的核心逻辑是时间戳比对。网络恢复后,网关可以先向云端查询最新已接收时间戳 T_cloud,然后从本地查询:

复制代码
SELECT * FROM data_points
WHERE timestamp > :T_cloud AND uploaded = 0
ORDER BY timestamp ASC
LIMIT 100;

补传流程如下:

  1. 网关检测网络恢复;
  2. 请求云端最新 T_cloud;
  3. 本地查询 timestamp > T_cloud 且未上传的数据;
  4. 按时间顺序分批补传;
  5. 每批确认后再标记 uploaded = 1;
  6. 若补传中途再次断网,下次恢复后继续从 T_cloud 比对。

这种方式可以避免重复上传,也能防止断网期间数据空洞。对碳核查、能耗审计类项目尤其重要,因为缺失的数据段会直接影响统计完整性。

工程实现中的几个注意点

  • 时间同步:网关本地时间必须可靠,建议通过 NTP 校时;断网期间可依赖 RTC 维持时间连续性。
  • 事务写入:本地入库应使用事务,避免断电导致半条记录。
  • 背压控制:如果断网时间过长,本地存储可能打满,需要设定保留策略,例如保留最近 30 天原始数据,超期数据归档或告警。
  • 双通道一致性:原始数据和清洗数据应共享同一时间戳和设备 ID,便于后续对账。
  • 上传幂等 :云端接收接口应支持按 timestamp + device_id 去重,防止补传时产生重复记录。

小结

边缘计算网关在物联网数据链路中的价值,主要体现在三点:屏蔽底层协议差异、保证数据完整性、降低云端处理压力。Modbus 和 DL/T 645 只是常见起点,实际项目中还会遇到 MQTT、BACnet、私有 TCP 协议等。无论上层协议如何变化,边缘侧的职责相对稳定:把不同来源的数据解析成统一模型,在本地完成初步清洗,断网时可靠缓存,网络恢复后按时间戳有序补传。

这类实现没有太多"炫酷"的地方,但决定了整套系统在现场能不能长期跑稳。欢迎同行在评论区讨论边缘侧的协议适配、清洗策略和本地存储方案。

相关推荐
u1301301 小时前
GitHub 热榜项目:日榜(2026-10-24)
人工智能·github·1024程序员节
悟天特斯1 小时前
边缘计算的“智能下沉“:从本地处理到边缘AI的推理加速
人工智能·边缘计算
sbjdhjd1 小时前
从黑板事实到长链路剪枝:AI 渗透测试 Agent 的实验、失效与改造
人工智能·网络安全·数据挖掘·php·agent·剪枝·1024程序员节
Xxtaoaooo8 小时前
双11避坑:我用 WorkBuddy + TextIn xParse 做了个「避坑对比台」,商品详情图丢进去,参数矛盾自动现形
人工智能·1024程序员节·textin·workbuddy·ai数据层基础设施
AI视觉网奇12 小时前
3d 网格布尔几何 Manifold
1024程序员节·3d算法
Geek-Chow15 小时前
00 · DeepSeek V4.1 Flash 大规模推理部署实践学习指南:总览、思维导图与阅读路线(专栏目录)
人工智能·1024程序员节
JiNan.YouQuan.Soft15 小时前
Windows下编译CGMA
其他·1024程序员节