将入站消息数据存储为消息originator的attribute数据。
前置条件
该节点接受类型为 POST_ATTRIBUTES_REQUEST 的消息,并要求消息数据为JSON对象,每个属性名表示attribute的key,对应的值表示attribute的value。例如:
1
2
3
4
{
"firmware_version": "1.0.1",
"serial_number": "SN-001"
}
配置
处理设置
save attributes节点可执行三种操作,每种操作由可配置的处理策略控制:
- Attributes:将attribute数据保存到数据库。
- WebSockets:向WebSocket订阅通知attribute数据更新。
- Calculated fields:向calculated fields通知attribute数据更新。
对于每种操作,您可选择下列 processing strategies(处理策略):
- 每条消息均执行:对每条入站消息执行操作。
- 去重:将来自同一来源实体的消息按时间间隔分组,仅在每个间隔内的第一条消息上执行操作。
间隔时长由去重间隔设置指定。
系统使用以下公式计算消息所属的去重间隔编号:
1
long intervalNumber = ts / deduplicationIntervalMillis;
其中:
ts为用于去重的时间戳(毫秒)。deduplicationIntervalMillis为配置的去重间隔(自动转换为毫秒)。intervalNumber决定消息所属的逻辑时间桶。
时间戳
ts按以下优先级确定:- 若消息元数据中包含
ts属性(UNIX毫秒),则使用该值。 - 否则,使用消息创建时间。
所有时间戳均为UNIX毫秒(UTC)。
示例
60秒去重间隔下:
- 设备在10:00:15、10:00:45、10:01:10发送消息
- 前两条消息(10:00:15和10:00:45)落在同一间隔内,仅处理10:00:15的消息
- 10:01:10的消息落在下一间隔,会被处理
- 跳过:永不执行操作。
processing strategies可通过 Basic 或 Advanced processing settings 设置。

- Basic processing settings — 为所有操作提供预设策略:
- On every message:对所有操作应用 On every message 策略。所有消息都会执行所有操作。
- Deduplicate:对所有操作应用 Deduplicate 策略(指定间隔)。
- WebSockets only:除WebSocket通知外,所有操作应用 Skip 策略,WebSocket通知使用 On every message 策略。 实际效果为:不写入数据库;数据仅通过WebSocket订阅实时可用。

- Advanced processing settings — 允许为每个操作独立配置处理策略。

在高级模式下配置处理策略时,某些组合可能导致意外行为。请考虑以下场景:
-
跳过数据库存储
选择禁用一个或多个持久化操作(例如跳过Time series或Latest values的数据库存储,同时保持WebSocket更新启用)会带来仅部分数据可用的风险:
- 若消息仅用于实时通知(WebSocket)且未存入数据库,历史查询可能与仪表板上的数据不一致。
- 当Time series和Latest values的处理策略不同步时,遥测数据可能只存入一个表(如Time series),而另一个表(如Latest values)中缺失相同数据。
-
禁用WebSocket (WS) 更新
若禁用WS更新,对时序数据的任何更改不会推送到仪表板(或其他WS订阅)。 这意味着即使数据库已更新,仪表板可能不会显示更新后的数据,直到重新加载浏览器页面。
-
跳过字段计算重新计算
若遥测数据保存到数据库但绕过了字段计算重新计算,汇总值可能不会更新以反映最新数据。 反之,若字段计算用新数据重新计算但对应的遥测值未持久化到数据库,字段计算的值可能包含未存储的数据。
-
跨操作的不同去重间隔
为各操作配置不同的去重间隔时,同一传入消息可能对不同操作进行不同处理。 例如,消息可能立即存入Time series表(若设为 On every message),而因Latest values表的去重间隔未到而不存入。 若WebSocket更新配置了不同间隔,仪表板显示的更新可能与数据库中的存储内容不一致。
-
去重缓存清理
去重机制使用内存缓存按间隔跟踪已处理消息。此缓存最多保留100个间隔,最长2天,但因其使用软引用,条目可能随时被清理。 因此,即使负载较轻,去重也不保证。例如,去重间隔为一天且每小时收到一条消息,若在两次到达之间缓存被清理,每条消息仍可能被处理。 去重应视为性能优化,而非每间隔单次处理的严格保证。
-
整条消息去重
需注意的是,去重应用于整条传入消息,而非单个时序key。 例如,若第一条消息包含key A并已处理,第二条消息(在去重间隔内收到)包含key B,第二条消息将被跳过——尽管包含新key。 要安全利用去重,请确保消息保持一致结构,使所有必需key出现在同一条消息中,避免意外数据丢失。
鉴于上述场景,将每个持久化操作独立配置(包括设置不同的去重间隔)的能力应视为性能优化,而非严格的处理保证。
Scope

节点支持三种属性范围:客户端属性、共享属性和服务端属性。可在节点配置中设置默认范围,也可通过在消息metadata中指定有效的 scope 属性进行覆盖。
支持的 scope 值:
CLIENT_SCOPE对应 客户端属性SHARED_SCOPE对应 共享属性SERVER_SCOPE对应 服务端属性
若消息metadata包含无效的 scope 值(如 INVALID_SCOPE),消息处理将失败。
Advanced settings

- Save attributes only if the value changes — 若启用,节点将入站属性与当前存储值比较,仅保存新增、值已变更或数据类型不同的属性。
- Send attributes updated notification — 若启用,节点对
SHARED_SCOPE和SERVER_SCOPE属性向来源实体的默认规则链发送 Attributes Updated 事件。 - Force notification to the device — 若启用,节点始终向有活跃订阅的设备发送属性更新通知。若禁用,设备通知由消息metadata中的
notifyDevice属性控制(缺失时默认为true)。
JSON Schema
消息处理算法
-
节点验证消息类型是否为
POST_ATTRIBUTES_REQUEST。若不是,处理失败并将消息路由到Failure连接。 -
节点解析消息数据以提取属性键值对。若数据为空,处理结束并将消息路由到
Success连接。 - 节点按下列优先级确定属性作用域:
- 消息metadata中的
scope属性值(若存在且有效:CLIENT_SCOPE、SHARED_SCOPE或SERVER_SCOPE) - 若metadata中提供无效的scope(如
INVALID_SCOPE),处理失败并将消息路由到Failure连接 - 若metadata未提供scope,则使用节点配置的默认scope
- 消息metadata中的
- 若启用 Save attributes only if the value changes(仅当值变更时保存属性),节点执行变更检测:
- 从数据库获取所有入站属性key的当前值
- 将每个入站属性与其当前存储值比较
- 仅保留下列属性:
- 新增(当前未存储)
- 与当前存储值不同
- 与当前存储数据类型不同
- 若未检测到变更,处理结束并将消息路由到
Success连接
- 节点按下列优先级确定设备通知设置:
- 若配置中启用 Force notification to the device,始终发送通知
- 否则检查消息metadata中的
notifyDevice属性:- 若缺失或为空字符串:默认发送通知
- 若存在:仅当值为
true(不区分大小写)时发送通知
- 按配置的处理策略将属性保存到数据库。保存完成时:
- 成功:处理成功,消息路由到
Success连接 - 失败:处理失败,消息路由到
Failure连接 - 若启用 Send attributes updated notification,会向originator的默认规则链发布
ATTRIBUTES_UPDATED事件(针对SHARED_SCOPE和SERVER_SCOPE属性)
- 成功:处理成功,消息路由到
输出连接
Success- 入站消息被成功处理时
Failure- 入站消息类型不是
POST_ATTRIBUTES_REQUEST时 - 入站消息payload无法解析为属性键值对时
- 入站消息metadata包含非空
scope属性且其值不是有效作用域(即CLIENT_SCOPE、SHARED_SCOPE或SERVER_SCOPE)时 - 消息处理过程中发生意外错误时
- 入站消息类型不是
示例
示例1 — On every message策略
入站消息
类型:POST_ATTRIBUTES_REQUEST
Originator:DEVICE
数据:
1
2
3
4
5
{
"firmware_version": "1.0.1",
"serial_number": "SN-001",
"last_maintenance": "2025-01-15"
}
节点配置
1
2
3
4
5
6
7
8
9
{
"scope": "SERVER_SCOPE",
"notifyDevice": false,
"sendAttributesUpdatedNotification": true,
"updateAttributesOnlyOnValueChange": false,
"processingSettings": {
"type": "ON_EVERY_MESSAGE"
}
}
出站消息
出站消息与入站消息相同。经 Success 连接路由。
结果
保存了三个服务器属性:
firmware_version: “1.0.1”serial_number: “SN-001”last_maintenance: “2025-01-15”
WebSocket订阅和calculated fields收到通知。由于scope为 SERVER_SCOPE,会向originator的默认规则链发送 ATTRIBUTES_UPDATED 事件。
示例2 — 使用Deduplicate策略的属性
入站消息
类型:POST_ATTRIBUTES_REQUEST
Originator:DEVICE
数据:
1
2
3
4
5
{
"battery_level": 85,
"signal_strength": -65,
"location": "Building A, Floor 2"
}
节点配置
1
2
3
4
5
6
7
8
9
10
{
"scope": "CLIENT_SCOPE",
"notifyDevice": true,
"sendAttributesUpdatedNotification": false,
"updateAttributesOnlyOnValueChange": false,
"processingSettings": {
"type": "DEDUPLICATE",
"deduplicationIntervalSecs": 120
}
}
系统状态
该设备在当前120秒间隔内的消息已处理过。
出站消息
出站消息与入站消息相同。经 Success 连接路由。
结果
由于启用了120秒去重间隔且该消息已处理过,属性不会保存到数据库。也不会触发WebSocket通知和calculated fields。
示例3 — 混合策略的高级处理
入站消息
类型:POST_ATTRIBUTES_REQUEST
Originator:DEVICE
数据:
1
2
3
4
5
{
"cpu_usage": 45.7,
"memory_usage": 78.2,
"disk_usage": 62.5
}
节点配置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
{
"scope": "SHARED_SCOPE",
"notifyDevice": false,
"sendAttributesUpdatedNotification": true,
"updateAttributesOnlyOnValueChange": false,
"processingSettings": {
"type": "ADVANCED",
"attributes": {
"type": "DEDUPLICATE",
"deduplicationIntervalSecs": 300
},
"webSockets": {
"type": "ON_EVERY_MESSAGE"
},
"calculatedFields": {
"type": "SKIP"
}
}
}
系统状态
该设备在当前去重间隔内的消息已处理过。
出站消息
出站消息与入站消息相同。经 Success 连接路由。
结果
- 由于去重,属性未保存到数据库
- WebSocket订阅已收到通知
- Calculated fields未触发(SKIP策略)
- 由于属性未保存,不发送
ATTRIBUTES_UPDATED事件
示例4 — 仅当值变更时保存属性
入站消息
类型:POST_ATTRIBUTES_REQUEST
Originator:DEVICE
数据:
1
2
3
4
5
{
"temperature_threshold": 25.0,
"humidity_threshold": 70.0,
"maintenance_scheduled": true
}
节点配置
1
2
3
4
5
6
7
8
9
{
"scope": "SERVER_SCOPE",
"notifyDevice": false,
"sendAttributesUpdatedNotification": true,
"updateAttributesOnlyOnValueChange": true,
"processingSettings": {
"type": "ON_EVERY_MESSAGE"
}
}
系统状态
当前已存储属性:
temperature_threshold: 25.0(值相同)humidity_threshold: 65.0(值不同)maintenance_scheduled: 未存储(新属性)
出站消息
出站消息与入站消息相同。经 Success 连接路由。
结果
因变更检测仅保存两个属性:
humidity_threshold: 70.0(值从65.0变为70.0)maintenance_scheduled: true(新属性)
temperature_threshold 未保存,因其值未变更。WebSocket订阅和calculated fields仅对被变更属性收到通知。
示例5 — 从消息metadata覆盖scope
入站消息
类型:POST_ATTRIBUTES_REQUEST
Originator:DEVICE
数据:
1
2
3
{
"power_setting": "low"
}
Metadata:
1
2
3
{
"scope": "CLIENT_SCOPE"
}
节点配置
1
2
3
4
5
6
7
8
9
{
"scope": "SERVER_SCOPE",
"notifyDevice": false,
"sendAttributesUpdatedNotification": true,
"updateAttributesOnlyOnValueChange": false,
"processingSettings": {
"type": "ON_EVERY_MESSAGE"
}
}
出站消息
出站消息与入站消息相同。经 Success 连接路由。
结果
保存了一个客户端属性(使用metadata中的scope):
power_setting: “low”
由于客户端属性不触发该通知,不会发送 ATTRIBUTES_UPDATED 事件。