ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

DLMS/COSEM 蓝皮书解读(五十):Parameter monitor(class_id = 65)—— 配置被谁改了?

DLMS/COSEM 蓝皮书解读(五十):Parameter monitor(class_id = 65)—— 配置被谁改了?

DLMS/COSEM 蓝皮书解读(五十):Parameter monitor(class_id = 65)—— 配置被谁改了?version 1 用一个哈希值回答

系列说明:本系列基于 DLMS UA《Blue Book(蓝皮书)第 16 版 · 第 2 部分》,一个接口类一篇。第 49 篇的Security setup(class_id = 64)管的是"通信怎么保护"。本篇的Parameter monitor(class_id = 65)管的是另一件事:配置参数本身有没有被人改过——尤其是被"另一个主站/现场手持设备"改过。它有 version 0 与 version 1 两个版本,version 1 用参数哈希把这件事变得极其轻量。

上篇回顾:Security setup保护的是信道上的数据,但它回答不了"上次巡检到这次巡检之间,表里的费率配置是不是被现场人员用手持设备改过?"。这类改动往往是合法客户端做的,安全策略拦不住,但主站必须知道——否则用旧配置去解析新数据就会出错。Parameter monitor就是为这个"配置变更可追溯"而生的。


0. 为什么需要这个类 —— "配置漂移"是隐形故障源

先描述问题(原文说得很清楚):

蓝皮书原文(Parameter monitorversion 1):
“Each client that has access to the server has to be aware of the current parametrisation in order to be able to correctly exchange data with servers. The parameters may be grouped and each group may have a name. Although the parametrisation may be known initially, it may change during the lifetime of the meter, for example it may be changed by another client such as a field service device.”

三种应对方式,代价差别很大:

做法代价问题
每次通信前把配置全读一遍高原文:“This is not efficient and in the case of push operation it is not practical.”
不管,假设配置不变低配置漂移会导致数据解析错误,且错误很隐蔽
Parameter monitorversion 1极低(读一个摘要)只比对哈希,不一致再细查

version 1 的精髓在原文这段:

“To achieve this, version 1 of the Parameter monitor IC specifies new attributes to hold: the parameter_list_name; the hash_algorithm_id; the parameter_value_digest; and the parameter values.”
“When a client configures the server, it can retrieve these attributes and share them with other clients. When a client starts a data exchange with the server, it can read the parameter_value_digest attribute and compare it to the value it has stored. If they match, the configuration is as expected, if not, the client can read the parameter_values attribute to identify which one(s) have changed.”

这就是"配置指纹":配置时记下指纹,之后每次通信先比指纹。指纹一致 → 放心用缓存配置;指纹不一致 → 再读parameter_values定位到底哪个参数变了。


1. 类蓝图

1.1 version = 1

Parameter monitor 0…n class_id = 65, version = 1
#属性数据类型Short name
1logical_name(static) octet-stringx
2changed_parameterstructurex + 0x08
3capture_timedate-timex + 0x10
4parameter_listarrayx + 0x18
5parameter_list_nameoctet-stringx + 0x20
6hash_algorithm_idenumx + 0x28
7parameter_value_digestoctet-stringx + 0x30
8parameter_valuesstructurex + 0x38
#方法必选/可选(m/o)Short name
1add_parameter (data)ox + 0x48
2delete_parameter (data)ox + 0x50

说明:原文 version 1 的属性表中仅logical_name标注了(static),其余属性未标注静态/动态(原文表格如此,本文照录,不作推断)。Min/Max/Def 列原文未给出。

1.2 version = 0

Parameter monitor 0…n class_id = 65, version = 0
属性数据类型Short name
logical_name(static) octet-stringx
changed_parameterstructurex + 0x08
capture_timedate-timex + 0x10
parameter_listarrayx + 0x18
方法必选/可选(m/o)Short name
add_parameter (data)ox + 0x20
delete_parameter (data)ox + 0x28

1.3 版本差异

维度version 0version 1
属性数48(新增 parameter_list_name、hash_algorithm_id、parameter_value_digest、parameter_values)
能否检测"配置是否变化"只能事后看changed_parameter(最近一次变化)可主动比对摘要(parameter_value_digest),且能读出全部当前值
方法偏移x+0x20 / x+0x28x+0x48 / x+0x50
分组命名无有parameter_list_name

2. 属性逐条解读

2.1 logical_name

“Identifies the ‘Parameter monitor’ object instance.”

2.2 changed_parameter —— 最近一次变化的参数

蓝皮书原文(Parameter monitor, changed_parameter):
“Holds the identifier and the value of the most recently changed parameter.”

structure { class_id: long-unsigned, logical_name: octet-string, attribute_index: integer, attribute_value: CHOICE -- CHOICE as specified in the ‘Data’ interface class }

即"是哪个对象的哪个 attribute,变成了什么值"。注意attribute_value用的是Data(1) 里那个 CHOICE——所以它可以是任意 COSEM 数据类型(这点在原文 NOTE 2 里有呼应)。

2.3 capture_time —— 变化发生的时间

“Provides data and time information showing when the value of the changed_parameter attribute has been captured.”
date-time is formatted as specified in ...

2.4 parameter_list —— 监视清单

parameter_list ::= array parameter_list_element parameter_list_element ::= structure { class_id: long-unsigned, logical_name: octet-string, attribute_index: integer }

原文 NOTE(version 0 与 version 1 都有):“The list of parameters monitored may be changed by using the add_parameter or delete_parameter methods or writing this attribute.”

三种改法:两个 method,或直接写这个 attribute。

2.5 parameter_list_name(version 1)

“Holds the name given to the list of parameter as defined by the parameter_list attribute.”

对应 §0 原文里那句“The parameters may be grouped and each group may have a name”——不同用途的参数可以分成不同的组,每组一个Parameter monitor对象、一个名字。

为什么分组?原文 NOTE 2 解释了:

“As the various parameters may be of different type and length, the entries in the profile column holding the parameters will be also of different type and length. This can be managed by capturing different kind of parameters into different Parameter list Profile generic objects and parameter logs.”

参数类型五花八门(有的是long-unsigned、有的是octet-string),塞进同一个Profile generic的同一列会很难处理——所以按类型/用途分组,各建各的日志。

2.6 hash_algorithm_id(version 1)

enum (0) SHA-256, (1) SHA-384, (2) Last 16 bytes of SHA-256, (3) Last 8 bytes of SHA-256, (4) Last 4 bytes of SHA-256

注意 (2)(3)(4):不是新算法,而是截断的 SHA-256——分别取最后 16 / 8 / 4 字节。这是为窄带信道准备的:摘要越短,比对越省字节,代价是碰撞概率上升。

取值摘要长度适用
(0) SHA-25632 字节默认,最稳
(1) SHA-38448 字节与 suite 2 的 SHA-384 对齐时
(2)16 字节窄带但要求较低碰撞率
(3)8 字节极窄带
(4)4 字节极限省字节

2.7 parameter_value_digest(version 1)—— 本篇的主角

蓝皮书原文(Parameter monitor, parameter_value_digest):
“Result of the digest calculation according to the algorithm specified by the hash_algorithm_id attribute. The digest is calculated on all the parameter list values as defined by attribute parameter_list in the order they are placed in the array. To calculate the digest, the whole set of parameter_list attribute values is first transformed into an octet-string. Rules for this transformation are defined , 9.2.3.4.3. Data conversion, for all the data types which are not an octet-string.”

计算流程(三步,严格按原文):

① 按 parameter_list 数组中元素的顺序,取每个参数的当前值; ② 把这一整组值转换成一个 octet-string (非 octet-string 类型的转换规则见 9.2.3.4.3 Data conversion); ③ 用 hash_algorithm_id 指定的算法对 ② 的结果算摘要。

两个必须注意的点:

  1. 顺序敏感——“in the order they are placed in the array”。清单顺序变了,摘要就变了,即使值没变。所以改parameter_list会导致摘要变化,别误判成"参数被改了"。
  2. 转换规则不在本类里——在文档的 9.2.3.4.3(Data conversion)。实现时两端必须用同一套转换规则,否则摘要对不上。

2.8 parameter_values(version 1)

“Holds a copy of the values of the attributes referenced in parameter_list attribute. It is a structure that holds the A-XDR encoded value of each attribute in the order of the parameter_list array.”

是"当前全部参数值的一份副本",每个值是A-XDR 编码的,顺序同parameter_list。

配合摘要使用:摘要不一致 → 读parameter_values→ 逐个与本地记录比对 → 定位是哪个变了。


3. 方法:add_parameter 与 delete_parameter

3.1 add_parameter (data)

“Adds one parameter to the parameter_list. data ::= parameter_list_element”
NOTE:“A parameter can be logged as soon as it is added to the list. Adding an element to the list does not affect the buffer of the ‘Profile generic’ object capturing the changed_parameter attribute.”

3.2 delete_parameter (data)

“Deletes one parameter from the parameter_list. data ::= parameter_list_element”
NOTE:“When a parameter is deleted from the parameter list, its changes will not be logged any more. Removing an element from the list does not affect the buffer of the ‘Profile generic’ object capturing the changed_parameter attribute.”

两个 method 的 NOTE 都明确了一件事:增删清单元素不会影响正在捕获changed_parameter的那个Profile generic的 buffer。也就是说:

  • ✅ 缓冲区里已有的历史记录不受影响;
  • ❌ 被删掉的参数,之后的变化不再入日志。

4. 【实战举例】

说明:以下 OBIS、取值、字节均为帮助理解而构造的示例,非蓝皮书原文,实际以设备对象列表与项目配套规范为准。

示例 1:建一个"费率配置"监视组

Parameter monitor 对象: logical_name = 0-0:16.2.0.255 (示意 OBIS) parameter_list_name = "TARIFF_CFG" -- 分组名(version 1) hash_algorithm_id = 0 -- SHA-256 parameter_list = [ { class_id = 20, logical_name = 0-0:13.0.0.255, attribute_index = 2 }, -- Activity calendar name active { class_id = 10, logical_name = 0-0:11.0.0.255, attribute_index = 2 }, -- Schedule passive { class_id = 3, logical_name = 1-0:13.7.0.255, attribute_index = 3 } -- Register scaler_unit ]

主站配置完成后读一次parameter_value_digest,存进自己的数据库(比如a3f1…c92b,32 字节)。

示例 2:每次通信前的"指纹校验"

GET parameter_value_digest → 0x A3F1…C92B(32 字节) 与本地记录比对: 一致 → 配置未变,继续用缓存配置解析数据 不一致 → 读 parameter_values,逐个定位

开销对比(假设 3 个参数):

方式读取字节量(示意)
每次读全部配置参数需要 3 次(或 GET-WITH-LIST)描述符 + 完整值
只读parameter_value_digest1 个 attribute,32 字节(SHA-256)

若用hash_algorithm_id = 4(Last 4 bytes of SHA-256),只要 4 字节——一次 GET 就能确认配置没动过。

示例 3:定位"哪个参数变了"

摘要不一致后读parameter_values(structure,顺序同parameter_list):

parameter_values = { <A-XDR> 0-0:13.0.0.255 attr2 = "SUMMER2024", -- 变化:原为 "WINTER2024" <A-XDR> 0-0:11.0.0.255 attr2 = <unchanged>, <A-XDR> 1-0:13.7.0.255 attr3 = { -1, 30 } -- 未变 }

逐个与本地记录比对 → 发现是 Activity calendar name 从WINTER2024换成了SUMMER2024(季节切换,属正常变更)。

示例 4:changed_parameter + capture_time 留下变更痕迹

某次参数被改:

changed_parameter = { class_id = 20, logical_name = 0-0:13.0.0.255, attribute_index = 2, attribute_value = octet-string "SUMMER2024" } capture_time = 2024-04-01 02:00:00

原文:“If the value of an attribute changes and this attribute is present in the parameter_list attribute, the identifier and the value of that attribute is automatically captured to the changed_parameter attribute.”——只有清单内的参数变化才会被捕获。

示例 5:用 Profile generic 做"参数变更日志"

把changed_parameter和capture_time交给Profile generic(7):

Profile generic 的 capture_objects = [ { class_id = 65, logical_name = 0-0:16.2.0.255, attribute_index = 3, data_index = 0 }, -- capture_time { class_id = 65, logical_name = 0-0:16.2.1.255, attribute_index = 2, data_index = 0 } -- changed_parameter ]

原文 NOTE 3:“The ‘Profile generic’ object holding the parameter change log may capture other suitable object attributes, such as the time attribute of the Clock object and any other relevant values.”

于是形成一张"时间 + 变更内容"的审计表。

原文 NOTE 1 的提醒:“In the case of simultaneous or quasi simultaneous parameter changes the order of capturing and logging the changed parameters has to be managed by the application.”——几乎同时发生的多个变更,其捕获顺序由应用自己管理,标准不保证顺序。

示例 6:add_parameter 的"即刻生效"

ACTION add_parameter (data = { class_id = 8, logical_name = 0-0:1.0.0.255, attribute_index = 2 })

原文 NOTE:“A parameter can be logged as soon as it is added to the list.”—— 加入即可入日志。

连带影响:加了元素 →parameter_list变了 → 摘要计算输入变了 →parameter_value_digest会变。这是"合法变化",不是配置漂移,主站需要重新记录基线。

示例 7:delete_parameter 之后不再记录

ACTION delete_parameter (data = { class_id = 3, logical_name = 1-0:13.7.0.255, attribute_index = 3 })
  • 该参数之后的变化不再入日志;
  • 不影响已有Profile generic的 buffer(原文两处 NOTE 都强调了)。

示例 8:多主站共享配置指纹(version 1 的设计初衷)

原文场景:“When a client configures the server, it can retrieve these attributes and share them with other clients.”

① 主站 A 配置设备 → 读下 parameter_list_name / hash_algorithm_id / parameter_value_digest ② 主站 A 把这套指纹共享给主站 B(走后台系统,不走 DLMS) ③ 主站 B 与主站 C 之后只需比对指纹即可确认配置一致

这在多主站环境(营销系统 + 采集系统 + 现场运维)里价值最大:谁改了配置,所有主站下一次通信时都能立刻发现。

示例 9:把摘要也捕获进 Profile generic

原文:“The attributes can also be captured into Profile generic object buffer attributes to assure the validity of the data captured. The resulting overhead can be minimized by the use of null-data encoding.”

在负荷曲线的capture_objects里加一列parameter_value_digest:

{ class_id = 65, logical_name = 0-0:16.2.1.255, attribute_index = 7, data_index = 0 }

这样每条曲线记录都带着"当时的配置指纹",事后核查时能证明这条数据是用哪套配置产生的。开销可用null-data编码压缩(指纹没变时不必重复存)。


5. 工程上容易踩的坑

  1. 以为改了parameter_list摘要不变:摘要是对清单顺序敏感的,增删参数会让摘要变化——要重新记录基线,别误报"配置被改"。
  2. 两端数据转换规则不一致:摘要计算依赖 9.2.3.4.3 的 Data conversion 规则,实现必须对齐,否则永远对不上。
  3. 用截断摘要(2/3/4)却不评估碰撞率:4 字节摘要碰撞概率不低,只适合"粗筛",真不一致还要读parameter_values复核。
  4. 指望changed_parameter能记录所有变化:只有parameter_list内的参数变化才会被捕获。
  5. 指望标准保证并发变更的顺序:原文 NOTE 1 明确说顺序由应用自己管理。
  6. 把不同类型的参数塞进同一个监视组:原文 NOTE 2 建议按类型/用途分组,否则日志列的类型和长度会很混乱。
  7. 以为增删参数会清掉 Profile generic 的 buffer:原文 NOTE 明确说不影响。
  8. version 0 设备上找parameter_value_digest:只有 version 1 有;version 0 只能靠changed_parameter做事后发现。
  9. 把parameter_values当成历史:它是当前值的一份副本,历史要靠Profile generic捕changed_parameter。
  10. 忽略了parameter_list_name的分组价值:不分组的话,"哪一组配置变了"这件事本身就分不清。

6. 小结 & 下期预告

本篇要点:

  1. Parameter monitor(65) 监视一组配置参数,任何清单内参数变化都会自动捕获到changed_parameter+capture_time;
  2. version 1 新增四个 attribute:parameter_list_name(分组名)、hash_algorithm_id、parameter_value_digest(配置指纹)、parameter_values(当前值副本);
  3. hash_algorithm_id支持 SHA-256 / SHA-384 和SHA-256 的截断(16/8/4 字节),窄带场景可省到 4 字节一次比对;
  4. 摘要按parameter_list顺序计算,值先整体转为octet-string(规则见 9.2.3.4.3);
  5. add_parameter/delete_parameter增删清单元素,不影响捕获changed_parameter的Profile genericbuffer;
  6. 典型用法:配置时记指纹 → 每次通信比指纹 → 不一致再读parameter_values定位;配合Profile generic可做参数变更审计日志。

下一篇(第 51 篇):Measurement data monitoring objects(class_id = 66)—— 从"配置监视"转向"波形捕获":触发点前后各留多少采样点、采样率怎么定,以及怎么把一段波形塞进Profile generic。


参考资料:DLMS UA《Blue Book Ed.16 Part 2 – COSEM interface classes》,Parameter monitor(class_id = 65, version = 0 与 version 1) 章节;文中属性名与顺序、数据类型、Short name 偏移、方法 m/o、hash_algorithm_id 枚举、摘要计算规则与引文均与原文一致;示例中的 OBIS、取值与字节为帮助理解而构造(非蓝皮书原文,实际以设备对象列表及项目配套规范为准)。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进