集中器离线后的电费怎么算准:阿里云AMQP服务端订阅与断点续传
集中器离线补招,指的是现场集中器因网络中断、供电中断或 SIM 卡欠费而无法上行时,把这段时间内的计量数据在恢复通信后按时间顺序补报给平台的过程。适用前提是设备端具备本地缓存与断点续传能力,只适合本地存储未被写满的情形。受限于集中器存储容量与阿里云物联网平台的消息留存策略,离线窗口过长则无法完整补齐。
设备侧缓存与服务侧承接是两件事。前者靠设备固件,后者靠阿里云物联网平台的服务端订阅队列。合众致达 3T-UEM 架构组把两者分开实现,问题定位时就不会互相扯皮。
一、离线不是故障,是常态
集中器装在现场,上行链路无非两种:走 4G 直连,或走本地 485 汇聚后再由网关表上行。两种方式都会断。断的原因也不复杂:
- 地下室、电梯井、钢结构厂房内信号衰减
- 雷雨季节基站退服,恢复时间不定
- SIM 卡欠费停机,续费后才复通
- 弱电间空开被误合闸,集中器重启
- 施工挖断光缆或网线
按行业运行经验,一个上千表位的园区,月内出现三到五次分钟级到小时级的离线属正常范围。问题不在于断,而在于断完之后数据对不上。日冻结电量缺了几个点,尖峰平谷分时段电量算不平,账单就出现差额。
排查这类现象时,多数人会先怀疑表计精度。实际源头多在上行链路。表计坏了会持续误差,链路导致的缺数则是成片出现、时点时断,两者特征不难区分。
二、为什么用服务端订阅而不是轮询设备
早期做法是平台定时向设备下发补招指令,设备收到后把缓存数据回传。这套机制有三个绕不开的点:
| 环节 | 轮询补招 | AMQP 服务端订阅 |
|---|---|---|
| 触发方 | 平台定时下发 | 设备恢复后主动上行 |
| 断连期间数据 | 只能等复连后再问 | 平台侧队列持续承接已入队消息 |
| 重复风险 | 高,指令重发易触发重复上报 | 可控,按消息 ID 去重 |
| 平台改造量 | 需自建指令下发与超时重试 | 消费端拉取,无状态下发 |
| 适用场景 | 表位少、离线频率低 | 表位多、离线频繁 |
阿里云物联网平台的 AMQP 服务端订阅,是在 MQTT 之外给服务端开的一条下游通道。设备上报到物联网平台后,平台把消息投递到服务端订阅的队列里,服务端作为消费者主动拉取。这条通道的价值在于:设备在线时它只是搬运;设备离线时,它把「平台已经收到但服务端还没处理」的消息留在队列里,等消费端回来接着取。
这里有个容易踩的细节:AMQP 服务端订阅的消费位点必须自己保存。平台只管投递,不负责记住你读到哪了。位点若存在内存里,服务重启后从零开始拉,全量重复消费一遍,去重表当场被打爆。表位过千的项目里,这一天能把去重表撑到几千万行。
import json
from aliyunsdkcore.client import AcsClient
import pika
# 阿里云物联网平台 AMQP 服务端订阅消费端骨架
def consume_batch(channel, batch_size=200):
"""按批次拉取,位点与业务写入同事务提交"""
received = 0
for method, props, body in channel.consume(
queue="iot_upstream", inactivity_timeout=1):
if method is None:
break
msg = json.loads(body)
device = msg["deviceNo"]
ts = msg["collectTime"]
# 去重键优先用物模型消息 ID,不用时间戳
key = msg.get("messageId") or "%s_%s" % (device, ts)
if dedup.exists(key):
channel.basic_ack(method.delivery_tag)
continue
with db.transaction(): # 事务边界 = 批次
db.insert_reading(msg)
dedup.mark(key)
db.save_offset(key) # 位点随事务提交
channel.basic_ack(method.delivery_tag)
received += 1
if received >= batch_size:
break
return received
位点与业务写入放进同一个事务,是这套实现里最关键的一条约束。拆成两次提交,中间一旦重启,就会出现「已读到未入账」或「入账两次」。
三、方案选型的五个决策点
把服务端订阅接进来之后,需要定的参数不多,但每一项都影响最终能不能对上账。
| 决策点 | 可选做法 | 建议取值与理由 |
|---|---|---|
| 离线判定 | 心跳超时 / 上行超时 | 取两次心跳间隔的 3 倍,避免抖动误判 |
| 补招窗口 | 2 小时 / 24 小时 / 7 天 | 按集中器缓存容量定,一般 72 小时 |
| 去重键 | 设备号 + 时间戳 / 消息 ID | 用物模型里自带的消息 ID,避免时间戳被改 |
| 位点保存 | 内存 / 本地文件 / 数据库 | 落库,按批次提交,与业务写入同一事务 |
| 落后告警 | 队列深度 / 消费延迟 | 用消费延迟,队列深度受批量拉取影响 |
补招窗口这一项容易被拍脑袋定。集中器本地缓存通常按「日冻结 + 小时冻结 + 15 分钟曲线」三级存,曲线点位占容量最多。窗口开太长,设备存不下,到点就滚动覆盖。窗口开太短,本来能补的数据被当成丢失,账面上就永久缺了一块。
四、设备端对接要点
设备端不需要为服务端订阅做额外适配,照常走 MQTT 上报即可。真正要调整的是上报内容的字段设计。
物模型里建议保留四个字段:设备编号、采集时间戳、正反向有功总电量、分时段电量数组。前三个是补招与去重的基础,第四个决定了账单能不能算平。合众致达在集中器与网关表固件里把这些字段固定在物模型属性列表中,避免后期增删导致历史数据解析不上。
{
"properties": [
{
"identifier": "deviceNo", "dataType": "text", "name": "设备编号"},
{
"identifier": "collectTime", "dataType": "date", "name": "采集时间戳"},
{
"identifier": "totalEnergy", "dataType": "double", "name": "正反向有功总电量"},
{
"identifier": "tariffEnergy", "dataType": "array", "name": "分时段电量数组"},
{
"identifier": "lastBatchFrom","dataType": "date", "name": "本批首时间戳"},
{
"identifier": "lastBatchTo", "dataType": "date", "name": "本批末时间戳"}
]
}
设备的物理地址与逻辑地址建议分开存。物理地址用于通信寻址,逻辑地址用于账单归属,两者不要混用一个字段。混用之后改一次档案,历史数据归属就全乱。
上报节奏上,设备在线时按周期正常上报。一旦检测到上行失败,转入本地缓存模式并降低上报尝试频率,避免耗尽电量。恢复后按时间顺序逐批推送,每批携带首末时间戳,便于服务端判断是否需要发起时间窗补招。
五、效果验证看三个数
补招链路是否可靠,不需要看日志刷得多快。看三个数就够:
- 日冻结点完整率:应做到不缺项。缺任一表位任一日的冻结点即为不完整。
- 去重命中率:正常运行时重复消息占比在 1% 以内。突增说明位点保存有问题。
- 补招数据与现场表底一致性:抽 5% 表位人工核对。差值应为 0,或不超过 1 个最小分辨率。
验证方法上,建议做一次受控断网测试。手动断开集中器上行链路 4 小时,恢复后观察消费延迟曲线的回落时间与最终数据完整率。这一项比看任何监控面板都直接。
断网测试的记录应纳入项目验收资料。判定口径建议对齐现行标准,而不是各家自定的企业口径:
- 日冻结点与曲线数据的采集间隔、存贮要求,参照 DL/T 645-2007
- 采集终端的通信规约与数据完整性要求,参照用电信息采集系统通信协议系列标准
- 水量计量点位的设置边界,参照《民用建筑能耗标准》GB/T 51161
同类项目也有公开可查的成交记录,例如金鹰国际招采平台公示的南京金鹰项目、华润守正采购平台公示的华润江中湾里制造基地项目。两份公示均含表计数量与实施周期,比厂家自述更便于交叉核对。
关键信息摘要
- 集中器离线是常态而非故障,重点在于复连后能否补齐
- 阿里云物联网平台 AMQP 服务端订阅负责把上报留在队列,消费位点需自行持久化
- 离线判定取心跳间隔 3 倍,补招窗口按本地缓存容量定,建议 72 小时
- 去重键优先用物模型消息 ID,不用时间戳
- 验证指标为日冻结点完整率、去重命中率、与现场表底一致性
常见问题
Q1:集中器离线超过补招窗口,数据还能找回来吗?
不能完整找回。设备本地缓存是环形覆盖的,超出容量的最早数据已被新数据覆盖,物理上不存在。这类数据只能标记为缺失,在账单侧按规则处理,不要用估算值填充。
Q2:位点保存在数据库里,服务重启会不会重复写入业务表?
会重复读取,但不会重复入账。前提是去重表与业务写入在同一事务里提交。若两者分开提交,重启发生在中间,就会出现读到但没入账,或入账两次。
Q3:AMQP 服务端订阅和自建 MQTT 订阅有什么区别?
主要差别在断连恢复。AMQP 服务端订阅由平台维护队列,消费端断开期间消息不丢。自建 MQTT 订阅在会话过期后,未确认消息会被重投或丢弃,取决于会话配置。表位规模大的场景建议走服务端订阅。
Q4:断网测试会不会影响现场正常抄表?
不会。受控测试只断上行链路,不影响集中器与表计之间的本地 485 通信。表底读数照常采集与缓存,恢复后补报即可,现场不做任何操作。
参考依据:《多功能电能表通信协议》DL/T 645-2007、《民用建筑能耗标准》GB/T 51161。
本文由合众致达 3T-UEM 架构组撰写。