ThingsBoard——自定义规则节点

一般的功能,可以使用现有的节点来完成。但如果有比较复杂,或有自己特殊业务需求的,可能就需要自定义了。按官方教程来基本就可以入门,如果需要深入,可以参考ThingsBoard自有节点的实现,见源码

一、编译example

这里以docker为例。先下载example源码,然后编译好放入到TB中

# 下载源码
$ git clone https://github.com/thingsboard/rule-node-examples

# 编译成jar包(target/rule-engine-1.0.0-custom-nodes.jar)
$ mvn clean install

# 默认是没有extensions目录的,需要到docker(mytb)中创建extensions文件夹
$ docker exec -it mytb bash
$ cd /usr/share/thingsboard
$ mkdir extensions

# 拷贝jar包到docker中
$ docker cp target/rule-engine-1.0.0-custom-nodes.jar mytb:/usr/share/thingsboard/extensions/

# 重启docker。不行,就依次执行stop和start
$ docker restart mytb

如果编译时报错:

[ERROR] Failed to execute goal com.mycila:license-maven-plugin:3.0:check (default) on project rule-engine: Some files do not have the expected license header -> [Help 1]

因为检查了头部的license注释,可以换成:

$ mvn -Dlicense.skip=true clean install

重启后,在TB后台刷新,就可以看到新的节点了。这里就不放图了

二、文件结构

核心就这四块:
  • 第1个是打包时的配置,在pom.xml中配置
  • 第2个是源码,一个节点,基本包括两个java文件,一个是节点,一个是节点配置数据
  • 第3个是节点UI对应的js文件
  • 第4个是pom.xml

三、自定义节点步骤

  1. 实现TbNode接口
  2. 添加@RuleNode注解,并添加对应的名称、关联类型、说明、UI文件、及UI的selector模块名(驼峰命名法,对应着js的短横线命名法)等
  3. init()中初始化,主要获取用户配置的数据
  4. onMsg()中处理业务逻辑
  5. 通过ctx.tellSuccess()ctx.tellNext()ctx.tellFailure()把结果传递给下一个节点

    如果在子线程处理,也必须通过上面三个方法来处理结果

  6. 【可选】如果修改了原包名(org.thingsboard.rule.engine),需要把新包名(eg:com.test.rule.engine)添加到thingsboard.yml文件中:
       # Plugins configuration parameters
       plugins:
         # Comma separated package list used during classpath scanning for plugins
         scan_packages: "${PLUGINS_SCAN_PACKAGES:org.thingsboard.server.extensions,org.thingsboard.rule.engine,com.test.rule.engine}"
    

    如果不是源码,而是docker,在这修改:/usr/share/thingsboard/bin/thingsboard.yml

  7. 打包

四、demo参考

这里写了个demo,主要用于展示如何获取、修改msgmetadata的数据

4.1 源码

TbTestNode.java

/**
 * @author ralap
 * @date 2022/3/6
 */
@RuleNode(
        type = ComponentType.ENRICHMENT,
        name = "convert m/s to km/h",
        configClazz = TbTestConfiguration.class,
        nodeDescription = "获取msg中的速度数据,并修改",
        nodeDetails = "获取msg的速度数据,速度对应的key为输入框<code>speedKey</code>对应的值,并把它转换成km/h。metadata中增加是否转换成功的结果<code>metadata.cvtResult</code>"
//        uiResources = {"static/rulenode/custom-nodes-config.js"},
//        configDirective = "tbEnrichmentNodeSumIntoMetadataConfig")
)
@Slf4j
public class TbTestNode implements TbNode{

    private static final ObjectMapper mapper = new ObjectMapper();
    private TbTestConfiguration config;
    private String speedKey;

    @Override
    public void init(TbContext ctx, TbNodeConfiguration configuration) throws TbNodeException {
        this.config = TbNodeUtils.convert(configuration, TbTestConfiguration.class);
        this.speedKey = this.config.getSpeedKey();
    }

    @Override
    public void onMsg(TbContext ctx, TbMsg msg) throws ExecutionException, InterruptedException, TbNodeException {
        // 获取msg数据
        String msgData = msg.getData();
        log.info("onMsg.data=" + msgData);

        // 获取metadata数据
        TbMsgMetaData metaData = msg.getMetaData();
        metaData.getData().forEach((key, val) ->
            log.info("onMsg.metadata: " + key + "=" + val)
        );

        try {
            // 找speedKey
            JsonNode dataNode = mapper.readTree(msgData);
            JsonNode speedNode = dataNode.get(speedKey);
            int speed = speedNode.asInt();
            double newSpeed = speed * 3.6;
            ObjectNode node = mapper.createObjectNode();
            node.put("newSpeed", newSpeed);
            log.info("onMsg.newNode=" + mapper.writeValueAsString(node));

            // 增加metaData结果
            msg.getMetaData().putValue("cvtResult", "True");

            // 重新生成msg
            TbMsg newMsg = TbMsg.transformMsg(msg, msg.getType(), msg.getOriginator(), msg.getMetaData(), mapper.writeValueAsString(node));
            ctx.tellSuccess(newMsg);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
            msg.getMetaData().putValue("cvtResult", "False");
            ctx.tellFailure(msg, e);
        }
    }

    @Override
    public void destroy() { }
}

说明一下:
这里@RuleNode注解中,把最后两行注释掉了,代表没有用自定义的UI(即resources下的custom-nodes-config.js),使用的是默认UI(ThingsBoard自带的rulenode-core-config.js)。因为自定义UI编译出来的js,放到tb中会报错:加载配置UI资源失败。暂时没解决,可以自己去试试看

TbTestConfiguration.java

@Data
public class TbTestConfiguration implements NodeConfiguration<TbTestConfiguration> {

    private String speedKey;

    @Override
    public TbTestConfiguration defaultConfiguration() {
        TbTestConfiguration configuration = new TbTestConfiguration();
        configuration.setSpeedKey("speed");
        return configuration;
    }
}

4.2 结果展示

规则链中,通过generator节点来模拟设备的数据,这样就不需要等外部设备的数据,保存时就能触发数据

generator的节点配置

var msg = { speed: 100};
var metadata = { car: "Maybach" };
var msgType = "POST_TELEMETRY_REQUEST";

return { msg: msg, metadata: metadata, msgType: msgType };

自定义节点展示

配置内容

打开调试模式后,查看输出的msg结果

输出的metadata数据:

控制台打印的日志:

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
ThingsBoard是一个开源的物联网平台,用于连接、管理和监控物联网设备。它提供丰富的功能和自定义配置,使用户可以根据自己的需求创建和定制不同类型的节点。 华为云SMS(Short Message Service)是一种用于发送短信的云服务。通过使用华为云SMS,用户可以方便地向设备用户发送短信通知和提醒。 为了自定义华为云SMS规则节点,我们可以按照以下步骤进行设置: 1. 在ThingsBoard平台中登录并导航到所需的设备或设备组。 2. 选择“规则引擎”选项卡并选择“新建规则链”。 3. 在规则链的页面中,选择“节点”选项卡,并从可用节点列表中选择“华为云SMS”节点。 4. 点击该节点,然后在右侧的配置面板中填写所需的信息,例如华为云SMS的API密钥、用户名、密码、目标手机号码、短信内容等。 5. 点击“保存”按钮保存并应用节点配置。 6. 返回到规则链页面,并根据需要添加其他节点来构建完整的规则链。 7. 最后,保存并应用规则链,使其生效。 通过配置自定义的华为云SMS规则节点,我们可以实现在满足特定条件时自动发送短信通知的功能。例如,当温度超过设定阈值或设备状态异常时,发送短信提醒给设备用户。 总结而言,通过使用ThingsBoard平台的自定义规则节点功能,并结合华为云SMS服务,我们可以轻松创建自定义的短信通知规则,以满足不同应用场景下的需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值