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 monitor version 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 monitor version 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
| 1 | logical_name | (static) octet-string | x |
| 2 | changed_parameter | structure | x + 0x08 |
| 3 | capture_time | date-time | x + 0x10 |
| 4 | parameter_list | array | x + 0x18 |
| 5 | parameter_list_name | octet-string | x + 0x20 |
| 6 | hash_algorithm_id | enum | x + 0x28 |
| 7 | parameter_value_digest | octet-string | x + 0x30 |
| 8 | parameter_values | structure | x + 0x38 |
| 1 | add_parameter (data) | o | x + 0x48 |
| 2 | delete_parameter (data) | o | x + 0x50 |
说明:原文 version 1 的属性表中仅 logical_name 标注了 (static),其余属性未标注静态/动态(原文表格如此,本文照录,不作推断)。Min/Max/Def 列原文未给出。
1.2 version = 0
Parameter monitor 0…n class_id = 65, version = 0
| logical_name | (static) octet-string | x |
| changed_parameter | structure | x + 0x08 |
| capture_time | date-time | x + 0x10 |
| parameter_list | array | x + 0x18 |
| add_parameter (data) | o | x + 0x20 |
| delete_parameter (data) | o | x + 0x28 |
1.3 版本差异
| 属性数 | 4 | 8(新增 parameter_list_name、hash_algorithm_id、parameter_value_digest、parameter_values) |
| 能否检测"配置是否变化" | 只能事后看 changed_parameter(最近一次变化) | 可主动比对摘要(parameter_value_digest),且能读出全部当前值 |
| 方法偏移 | x+0x20 / x+0x28 | x+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-256 | 32 字节 | 默认,最稳 |
| (1) SHA-384 | 48 字节 | 与 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 指定的算法对 ② 的结果算摘要。
两个必须注意的点:
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_digest | 1 个 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. 工程上容易踩的坑
6. 小结 & 下期预告
本篇要点:
下一篇(第 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、取值与字节为帮助理解而构造(非蓝皮书原文,实际以设备对象列表及项目配套规范为准)。
网硕互联帮助中心






评论前必须登录!
注册