拓十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

ThingsBoard TBEL 规则节点实战:编写 Create Alarm 节点的 Alarm Details 构建函数

ThingsBoard TBEL 规则节点实战:编写 Create Alarm 节点的 Alarm Details 构建函数
  • 物联网
  • 后端
  • 数据可视化
  • 消息队列

【免费下载链接】thingsboard

All-in-one IoT Platform - Device management, data collection, processing and visualization.

项目地址:https://gitcode.com/GitHub_Trending/th/thingsboard
点击查看免费下载

导读

在 ThingsBoard 规则引擎中,Create Alarm(创建告警)节点允许你通过一段 TBEL(ThingsBoard Expression Language)脚本自定义存入告警(Alarm)实体的附加详情(Alarm Details),例如把入站消息 payload 中的temperature属性、元数据中的设备名称等保存到告警中。本文将围绕 create_alarm_node_script_fn.md 中定义的Details(msg, metadata, msgType)构建函数,讲解它的签名、参数、返回值约定,以及如何通过metadata.prevAlarmDetails读取并合并历史告警详情,实现告警次数的累计计数。读完本文,你将能够在 ThingsBoard 中独立编写、配置并调试这段 TBEL 脚本。

Details 函数:Create Alarm 节点如何生成 Alarm Details

Create Alarm 节点在创建或更新告警时,会调用一段用户编写的脚本函数来生成Alarm Details对象。该对象最终作为告警实体的details字段存储,用于承载告警之外的附加业务参数。

函数的完整声明如下:

function Details(msg, metadata, msgType): any
  • 这段脚本属于 TBEL 语言(ThingsBoard 基于 JavaScript 语法的表达式语言),配置位置在 Create Alarm 节点的Alarm details配置项中;
  • 脚本的返回值被序列化为 JSON,作为告警的Alarm Details存储;
  • 常见用法是:从原始消息(Original Message)的 payload 或 metadata中挑选出若干键值对,保存到告警详情里,便于后续规则链节点或仪表板直接使用。

参数说明

参数类型含义
msg{[key: string]: any}消息 payload 的键值对象,值可以是任意类型(数字、字符串、布尔、嵌套对象等)
metadata{[key: string]: string}消息元数据键值映射,键和值都必须是字符串
msgTypestring消息类型字符串,对应规则引擎中常见的MessageType枚举值(如POST_TELEMETRY_REQUEST、ENTITY_CREATED等)

关于三个参数的完整定义,可参见 common_node_script_args.md。其中metadata强调键值均为字符串,因此从msg中取值可以保留数字类型,而从metadata中取出的任何值本质上都是字符串,需要时记得自行转换。

返回值约定

函数必须返回一个对象(object),该对象即告警的 Alarm Details。返回{}空对象也是合法的,此时告警详情为空。如果返回null或抛出异常,将导致该节点的消息处理失败(节点会走 Failure 链路),这一点在源码测试中也有明确验证(见下文“源码级验证”部分)。

通过 metadata.prevAlarmDetails 读取历史告警详情

这是本函数最有价值、也最容易踩坑的一个点。

当规则链中有多个消息持续触发同一告警(例如同一设备连续上报超温数据)时,Create Alarm 节点可能会更新已存在的告警。此时,TBEL 引擎会把上一次保存的 Alarm Details 以原始字符串形式注入到本次脚本的metadata.prevAlarmDetails字段中,供你读取、合并。

需要特别注意:

  1. 仅在存在上一次告警详情时才存在该字段;如果这是第一次创建该告警,metadata.prevAlarmDetails不会出现在 metadata 中;
  2. metadata.prevAlarmDetails是raw String(原始字符串),不是对象,必须先用JSON.parse(...)反序列化后才能访问其中的属性;
  3. 解析完成后,建议立即用delete metadata.prevAlarmDetails(TBEL 写法)把它从 metadata 中移除,避免该字段被后续规则节点继续携带。

标准解析模板

var details = {}; if (metadata.prevAlarmDetails) { // remove prevAlarmDetails from metadata delete metadata.prevAlarmDetails; details = JSON.parse(metadata.prevAlarmDetails); }

这段代码的语义是:优先继承上一次告警的全部详情字段,作为本次详情的基础对象;然后再在上面叠加本次消息带来的新数据。

从源码看,该字段的注入发生在 TbAbstractAlarmNode.java 的buildAlarmDetails方法中:

static final String PREV_ALARM_DETAILS = "prevAlarmDetails"; ... protected ListenableFuture<JsonNode> buildAlarmDetails(TbMsg msg, JsonNode previousDetails) { try { TbMsg dummyMsg = msg; if (previousDetails != null) { TbMsgMetaData metaData = msg.getMetaData().copy(); metaData.putValue(PREV_ALARM_DETAILS, JacksonUtil.toString(previousDetails)); dummyMsg = msg.transform().metaData(metaData).build(); } return scriptEngine.executeJsonAsync(dummyMsg); } ... }

可以看到:当存在历史详情(previousDetails != null)时,节点会把历史详情序列化成字符串写入prevAlarmDetails元数据,再交给 TBEL 脚本引擎执行。这正解释了为什么脚本中拿到的metadata.prevAlarmDetails是一个需要JSON.parse的字符串。

实战示例:计数累加 + 温度属性入库

文档中给出的完整示例覆盖了最常见的两类操作:从历史详情中读取计数并累加、从入站消息 payload 中取属性写入详情。

var details = {temperature: msg.temperature, count: 1}; if (metadata.prevAlarmDetails) { var prevDetails = JSON.parse(metadata.prevAlarmDetails); // remove prevAlarmDetails from metadata delete metadata.prevAlarmDetails; if (prevDetails.count) { details.count = prevDetails.count + 1; } } return details;

逐行解读:

  1. 初始化新详情:var details = {temperature: msg.temperature, count: 1};
    • 直接把入站消息 payload 中的temperature属性存入详情;
    • count初始为1,代表这是第一次告警(或首次检测到的次数)。
  2. 合并历史详情:如果存在metadata.prevAlarmDetails,先JSON.parse得到上一次的详情对象prevDetails。
  3. 清理 metadata:delete metadata.prevAlarmDetails,保证向下游节点传递的 metadata 与进入本节点时一致。
  4. 递增计数:如果上一次详情里已有count字段,则在其基础上+1,实现“该告警累计触发次数”的持久化统计。
  5. 返回:return details;,最终count会变成历史次数 + 1,temperature则是本次消息的最新值。

这一“历史计数 + 实时属性”的组合,在实际中非常有用:例如统计某设备连续超温的告警次数,同时保留最近一次的超温温度值。

与 Clear Alarm 节点的关联

类似地,Clear Alarm(清除告警)节点 也使用同样的Details函数形态来生成更新后的详情对象,同样依赖metadata.prevAlarmDetails读取当前告警详情,并通过metadata.remove('prevAlarmDetails')清理元数据。两者的写法可以相互借鉴。

源码级验证:默认模板、脚本语言选择与测试覆盖

两种脚本语言的默认模板

Create Alarm 节点同时支持TBEL和JS两种脚本语言,对应源码中的两个默认模板,见 TbAbstractAlarmNodeConfiguration.java:

  • JS 模板(ALARM_DETAILS_BUILD_JS_TEMPLATE):使用if (metadata.prevAlarmDetails)判断,并用delete metadata.prevAlarmDetails清理;
  • TBEL 模板(ALARM_DETAILS_BUILD_TBEL_TEMPLATE):使用if (metadata.prevAlarmDetails != null)判断,并用metadata.remove('prevAlarmDetails')清理。

两者的判断条件与清理方式略有差异,但语义一致。TBEL 更推荐使用!= null判断与metadata.remove(...)写法(本文沿用原文档的 TBEL 风格)。

脚本语言的实际选择发生在 TbAbstractAlarmNode.java 的init方法中:

scriptEngine = ctx.createScriptEngine(config.getScriptLang(), ScriptLanguage.TBEL.equals(config.getScriptLang()) ? config.getAlarmDetailsBuildTbel() : config.getAlarmDetailsBuildJs());

即:当scriptLang为TBEL时,执行的是alarmDetailsBuildTbel字段中的脚本;否则执行alarmDetailsBuildJs中的脚本。

测试用例验证的行为

仓库中的单元测试 TbCreateAlarmNodeTest.java 对这一机制做了完整验证,可以佐证以下几点:

  • 默认配置下,alarmDetailsBuildJs与alarmDetailsBuildTbel分别等于上文两套默认模板(测试第 106–129 行);
  • 当存在历史告警时,脚本执行前会被注入一个带有prevAlarmDetails元数据的 dummy 消息(测试第 625 行断言actualDummyMsg.getMetaData().getData()包含prevAlarmDetails键);
  • 当overwriteAlarmDetails为false时,历史详情会被读取并合并进新详情;当其为true时则直接用新详情覆盖(测试第 856–1000 行分别覆盖了两种分支);
  • 当告警详情脚本抛出异常时,消息会走失败链路,且不会执行其他动作(测试第 1224–1243 行的whenAlarmDetailsScriptThrowsException用例)。

这些测试同时印证了一个重要行为:告警详情的写入是否覆盖历史数据,还取决于节点配置中的 “Overwrite alarm details” 选项,而不仅仅是脚本逻辑本身。

调试与验证

在 ThingsBoard 界面配置该节点时:

  1. 在规则链编辑器中打开Create Alarm节点;
  2. 在Script language中选择TBEL;
  3. 在Alarm details文本框中粘贴上述脚本(此为该函数对应的配置项);
  4. 开启节点的 Debug 模式,即可在规则链的调试面板中近乎实时地查看每次经过该节点的消息(含入站消息与经过脚本处理后出站的消息),确认生成的 Alarm Details 是否符合预期。

Debug 模式的详细使用方法可参考仓库中 common_node_script_args.md 中的指引。

延伸阅读

  • 告警(Alarm)实体的整体模型、生命周期与告警规则配置,可进一步查阅仓库内ui-ngx/src/assets/help中关于告警的教程类文档;
  • 结合 create_alarm_node_script_fn.md 同目录下的其他节点脚本文档(如 filter_node_script_fn.md、transformation_node_script_fn.md),可以系统掌握 TBEL 在规则引擎各节点中的通用写法;
  • 若要实际演练“创建与清除告警”的完整规则链配置步骤,可参考官方针对 Create and Clear Alarms 场景的逐步教程。
  • 物联网
  • 后端
  • 数据可视化
  • 消息队列

【免费下载链接】thingsboard

All-in-one IoT Platform - Device management, data collection, processing and visualization.

项目地址:https://gitcode.com/GitHub_Trending/th/thingsboard
点击查看免费下载

相关推荐

上一篇:Wand-Enhancer终极指南:免费解锁WeMod Pro会员功能
下一篇:ComfyUI-VideoHelperSuite:5分钟掌握AI视频创作的终极解决方案

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

返回列表