云计算百科
云计算领域专业知识百科平台

DLMS/COSEM 蓝皮书解读(四):Extended register 类(class_id = 4)—— 给数值加上“时刻“与“状态“

DLMS/COSEM 蓝皮书解读(四):Extended register 类(class_id = 4)—— 给数值加上"时刻"与"状态"

系列说明:本系列基于 DLMS UA《Blue Book(蓝皮书)第 16 版 · 第 2 部分》,一个接口类一篇。第 3 篇讲了 Register(class_id = 3),它解决了"这个数是什么单位"。本篇的 Extended register 再往前走一步:解决"这个数是哪一时刻的?它还有效吗?"

上篇回顾:Register 的三个属性是 logical_name / value / scaler_unit,能完整表达"1 234,5 Wh"。但它记录不了这个值是什么时候采下来的,也记录不了这份数据是否可信。


0. 为什么需要"时刻 + 状态"

先看两个真实的工程痛点:

痛点一:这个值是什么时候的?

主站凌晨 3 点读到 1-0:1.8.0 = 1 234,5 kWh。这个值是此刻的实时值,还是昨夜 24:00 冻结下来的结算值?

  • 如果是实时值,它每秒都在变,主站读到的是"读的那一刻"的快照;
  • 如果是冻结值,它从冻结时刻起就不变了,主站今天读、明天读都一样。

Register 分不清这两种情况 —— 它只有 value。而在结算、计费、对账场景里,"这个值属于哪个时刻"是刚需,不能靠主站"我读的时候是几点"来推断(因为可能抄表失败、补抄、数据延迟)。

痛点二:这份数据还有效吗?

表计掉电、时钟被回拨、校验失败、数值溢出……这些情况下 value 依然会返回一个数字,但这个数字不可信。怎么把"不可信"这件事告诉主站?

Extended register 的答案就是多出来的两个属性:

  • capture_time:这个 value 是在什么时刻被采集/冻结下来的;
  • status:这份数据的状态(是否有效、是否被改、是否溢出……)。

蓝皮书原文(Extended register, Overview):
“This IC allows modelling a process value with its associated scaler, unit, status and capture time information.”

一句话定位:

Extended register = Register + 采集时刻 + 数据状态。用于"冻结值""带状态的瞬时量"这类需要自证时间与可信度的数据。


1. 类蓝图

Extended register 0…n class_id = 4, version = 0

属性静态/动态数据类型Short name
logical_name (static) octet-string x
value (dyn.) CHOICE x + 0x08
scaler_unit (static) scal_unit_type x + 0x10
status (dyn.) CHOICE x + 0x18
capture_time (dyn.) octet-string x + 0x20
方法必选/可选(m/o)Short name
reset (data) o(可选) x + 0x38

对比 Register(class_id = 3)一眼就能看出来:前三个属性完全一样(连 Short name 偏移 x / x+0x08 / x+0x10 都一致),只是多挂了 status(x+0x18)和 capture_time(x+0x20)。

这个"偏移复用"不是巧合,而是 COSEM 的设计习惯:派生能力的新类会沿用父类的属性偏移,保证 SN 寻址下主站的逻辑可复用。


2. 属性逐条解读

2.1 value 与 scaler_unit:直接继承 Register

蓝皮书在这两个属性上没有重复写规格,而是直接指向 Register:

value:“See the specification of the IC ‘Register’.”
scaler_unit:“See the specification of the IC ‘Register’.”

也就是说:

  • value 的 CHOICE 数据类型表与 Register 完全一致(16 种:null-data[0] … float64[24]);
  • scaler_unit 同样 structure { scaler: integer, unit: enum },换算规则同样是 真值 = value × 10^scaler。

所以换算出真值的代码可以完全复用,这也是把 Extended register 视作"Register 的扩展"的原因。

2.2 status(dyn., CHOICE)—— 灵活,但不标准化

status 的类型是另一个 CHOICE,可选类型比 value 少(去掉了有符号和浮点,偏重"标志位/枚举/字符串"):

CHOICE
{
— simple data types
null-data [0],
bit-string [4],
double-long-unsigned [6],
octet-string [9],
visible-string [10],
utf8-string [12],
unsigned [17],
long-unsigned [18],
long64-unsigned [21]
}
Def. Depending on the status type definition.

但蓝皮书紧接着给了一句非常关键的限定:

“Provides ‘Extended register’ specific status information. The meaning of the elements of the status shall be provided for each object instance. The data type and the encoding depend on the instantiation and possibly on the choice of the manufacturer. For the interpretation, extra information from the manufacturer may be necessary.”

翻译成工程语言,三层意思:

  • status 的含义是"逐实例"定义的 —— 蓝皮书不规定第 0 位表示什么;
  • 数据类型和编码取决于实例化方式,且厂商有选择权;
  • 要解释 status,通常需要厂商额外提供的信息(设备文档 / 对象字典)。
  • 这一点务必记住:status 不是可移植的。 同样是 long-unsigned 的状态字,A 厂的 bit0 = “时钟失效”,B 厂的 bit0 可能 = “数据被修改”。跨厂商集成时必须查厂商文档,不能照搬。

    常见的两种编码方式(行业惯例,非蓝皮书强制):

    • bit-string / long-unsigned:当作位域用,每位一个标志(数据有效 / 溢出 / 被人工修改 / 时钟回拨 …);
    • visible-string / enum:当作枚举或文字状态用(如 “OK” / “INVALID”)。

    2.3 capture_time(dyn., octet-string)—— 本篇最有价值的属性

    “Provides an ‘Extended register’ specific date and time information showing when the value of the attribute value has been captured. octet-string, formatted as specified in for date-time.”

    要点:

    • 类型是 octet-string,但格式遵循蓝皮书的 date-time 定义(不是随便一个字符串);
    • 语义是:value 这个值是在什么时刻被采集/冻结的;
    • 它是 (dyn.) 属性 —— 每次采集/冻结都会更新。

    DLMS 的 date-time 类型是 12 字节的 octet-string,字段排布如下(这是 DLMS 通用定义):

    字节字段类型说明
    1–2 year long-unsigned 如 0x07E7 = 2023;0xFFFF 表示"未知"
    3 month unsigned 1–12
    4 day of month unsigned 1–31
    5 day of week unsigned 1–7(1 = 周一);0 = 未指定
    6 hour unsigned 0–23
    7 minute unsigned 0–59
    8 second unsigned 0–59
    9 hundredths unsigned 0–99
    10–11 deviation integer 与 UTC 的偏差,单位 分钟(如 0x003C = +60 min)
    12 clock status unsigned 位 0:与 UTC 是否同步等标志位

    说明:上表是 DLMS date-time 的通用结构(蓝皮书 capture_time 直接引用该定义)。解析 capture_time 时按这 12 字节拆即可。


    3. 方法:reset (data) —— 与 Register 的关键差异

    reset (data)
    data ::= integer (0)

    Extended register 的 reset 比 Register 多了一个动作:

    “This method forces a reset of the object. By invoking this method, the attribute value is set to the default value. The default value is an instance specific constant. The attribute capture_time is set to the time of the reset execution.”

    对比一下:

    动作Register.resetExtended register.reset
    value 置为默认值(实例特定常量) ✅ ✅
    capture_time 置为 reset 执行的时刻 ❌(无此属性) ✅

    工程意义:复位一个 Extended register 之后,capture_time 会变成"刚才复位的时间"。所以 capture_time 不仅能表示"数据何时采集",还能隐含表示"上一次复位发生在什么时候"。如果你发现某个冻结对象的 capture_time 是某个异常时刻,很可能是被人复位过。


    4. 【实战举例】

    示例 1:月结算冻结电能(最典型场景)

    假设一块电表每月 1 日 00:00:00 冻结一次正向有功总电能。用 Extended register 建模:

    对象:Extended register (class_id = 4)
    logical_name = 1-0:1.8.0 (示例 OBIS,实际由设备对象列表决定)
    value = 1234567 (long-unsigned)
    scaler_unit = { scaler = -1, unit = 30 } → 123456.7 Wh = 123.4567 kWh
    capture_time = 2023-02-01 00:00:00 (12 字节 date-time)
    status = 0x00 (bit-string/long-unsigned:0 = 数据正常)

    主站的抄表流程:

    # 1. 读 capture_time(attribute 5)→ 确认这个值"属于哪个时刻"
    GET (4, 1-0:1.8.0, 5) → 07 E7 02 01 03 00 00 00 00 00 00 00
    (2023-02-01, 周三, 00:00:00, deviation=0, status=0)

    # 2. 读 scaler_unit(attribute 3)→ 拿到量纲
    GET (4, 1-0:1.8.0, 3) → structure { -1, 30 }

    # 3. 读 value(attribute 2)→ 拿到数值
    GET (4, 1-0:1.8.0, 2) → 1234567

    # 4. 读 status(attribute 4)→ 确认数据可信
    GET (4, 1-0:1.8.0, 4) → 0x00

    # 5. 换算:1234567 × 10^(-1) = 123456.7 Wh

    对比:如果用 Register 存这个冻结值会怎样?

    Register 没有 capture_time,主站只能知道"我现在读到了 123456.7 kWh",但无法证明这个值属于 2 月 1 日 00:00:00 —— 万一表计冻结失败、主站读到的是上一次的值呢?有了 capture_time,主站可以直接校验:“我要的冻结时刻是 2 月 1 日,你返回的 capture_time 是不是 2 月 1 日?不是就丢弃。”

    示例 2:status 怎么用 —— 位域用法

    假设厂商定义 status 为 long-unsigned,位含义如下(厂商自定义,仅为示例):

    bit含义
    0 数据有效(0 = 有效,1 = 无效)
    1 数值溢出
    2 数据被人工修改过
    3 时钟曾失效(数据时刻不可信)
    4 掉电期间数据不完整

    主站读到 status = 0x0A(二进制 0000 1010):

    • bit1 = 1 → 数值溢出
    • bit3 = 1 → 时钟曾失效

    此时即使 value 和 scaler_unit 都正常,这份数据也不应该用于结算 —— 主站应记录异常并告警。

    再强调一次:这张位表是示例,真实含义必须查该型号的设备文档。蓝皮书只给了 CHOICE(能用什么类型),没给语义。

    示例 3:reset 之后 capture_time 会变

    # 复位前
    capture_time = 2023-02-01 00:00:00

    # 主站在 2023-02-05 09:30:00 调用 reset(x + 0x38)
    ACTION (4, 1-0:1.8.0, 1) # reset 方法索引为 1

    # 复位后
    value = <实例特定的默认值> # 注意:不是 0
    capture_time = 2023-02-05 09:30:00 # ← 被设为 reset 执行时刻

    这个特性常被用来做审计:如果某冻结对象的 capture_time 不是预期的整点/月初,而是某个奇怪的时刻,那就说明它被人动过。

    示例 4:SN 寻址下的偏移

    属性Register (3)Extended register (4)
    logical_name x x
    value x + 0x08 x + 0x08
    scaler_unit x + 0x10 x + 0x10
    status — x + 0x18
    capture_time — x + 0x20
    方法 reset x + 0x28 x + 0x38

    注意 reset 的偏移从 0x28 变成 0x38 —— 因为中间多了 2 个属性(各占 0x08),方法区整体后移了 0x10。


    5. 四个"寄存器兄弟"横向对比

    这是第 3 篇预告的对比表,把最容易混淆的四个类放在一起:

    Data (1)Register (3)Extended register (4)Demand register (5)
    属性个数 2 3 5 9
    logical_name ✅ ✅ ✅ ✅
    value ✅ ✅ ✅ ❌(拆成 current / last average)
    scaler_unit(量纲) ❌ ✅ ✅ ✅
    status(数据状态) ❌ ❌ ✅ ✅
    capture_time(采集时刻) ❌ ❌ ✅ ✅
    需量计算能力 ❌ ❌ ❌ ✅(period / number_of_periods)
    解决的核心问题 “装一个数” “这个数什么单位” “什么时候的、可信吗” “平均需量是多少”
    典型用途 序列号、固件版本、配置参数 电能、功率、电压、电流 冻结值、带状态瞬时量 最大需量、滑动需量

    选型口诀:

    • 只是参数/标识,没有单位 → Data
    • 有物理单位,值实时变化 → Register
    • 有单位,且需要知道时刻 / 判断有效性 → Extended register
    • 要算一段时间内的平均值(需量) → Demand register

    6. 工程上容易踩的坑

  • status 跨厂商不可移植:蓝皮书明确规定其含义逐实例定义、可能需要厂商额外信息。不要写死位含义。
  • capture_time 是"采集时刻",不是"读取时刻":两者可能相差很久(比如补抄上个月冻结值)。别把主站当前时间当 capture_time 用。
  • 复位会改 capture_time:审计时要注意。
  • value 的默认值不是 0:与 Register 一样,reset 后是"实例特定的默认值"。
  • 不要为了 status 滥用 Extended register:如果这份数据不需要时刻和状态语义,用 Register 就够了 —— 属性越少,实现越简单、互操作性越好。
  • capture_time 的 year = 0xFFFF 表示未知:解析时要处理(DLMS date-time 里 0xFFFF/0xFF 常表示"未指定/未知")。

  • 7. 小结 & 下期预告

    本篇要点:

  • Extended register(class_id = 4)= Register + status + capture_time,前三个属性的类型与 Short name 偏移完全沿用 Register;
  • capture_time 是 12 字节 date-time 格式的 octet-string,表示 value 被采集/冻结的时刻 —— 这是冻结值、结算值能自证归属时刻的关键;
  • status 是 CHOICE(9 种类型),但语义由实例/厂商定义,蓝皮书不标准化,可能需要厂商文档才能解释;
  • 它的 reset 除了把 value 置为实例特定默认值,还会把 capture_time 设为复位执行时刻(与 Register.reset 的关键差异);
  • 四个寄存器兄弟的选型:无单位→Data、有单位→Register、要时刻与状态→Extended register、要需量→Demand register。
  • 下一篇(第 5 篇):Demand register(class_id = 5)—— 四个兄弟里属性最多(9 个)、也是唯一自己会算数的一个。它会周期性计算 current_average_value(运行中需量)和 last_average_value(上一周期需量),并且能区分区间需量(block demand)和滑动需量(sliding demand)。我们会用 period = 900 s(15 分钟)的真实例子,手算一遍"1,5 kWh / 15 min = 6 kW"是怎么来的,并讲清 reset 与 next_period 两个方法的区别。


    参考资料:DLMS UA《Blue Book Ed.16 Part 2 – COSEM interface classes》,Extended register (class_id = 4, version = 0) 章节;date-time 通用定义。文中属性、数据类型、Short name 偏移、方法定义与引文均与该章节原文一致;示例 2 的 status 位表为帮助理解的示例,非蓝皮书原文。

    赞(0)
    未经允许不得转载:网硕互联帮助中心 » DLMS/COSEM 蓝皮书解读(四):Extended register 类(class_id = 4)—— 给数值加上“时刻“与“状态“
    分享到: 更多 (0)

    评论 抢沙发

    评论前必须登录!