ThingsBoard OPC-UA数据采集与控制


2020.4.20 更新内容:2.6版本网关使用问题.
本文内容将帮助你通过`thingsboard网关`快速接入`opc ua`协议的设备。并演示一个简单的数据读取与控制的例子。 ## 准备环境 具体搭建步骤不在本文介绍
  • thingsboard 3.2.1
  • tb-gateway 2.5.5.2
  • python3 3.7

OPC UA服务器

使用python的opcua搭建,各个步骤含义看注释 依赖安装 pip install opcua

import sys

sys.path.insert(0, "..")
import time
from opcua import ua, Server, uamethod


@uamethod
def set_value(parent, node_id, value):
    """
    给node_id的节点赋值为value
    :param parent:
    :param node_id:
    :param value:
    :return: res:boolean
    """
    node = server.get_node(node_id)
    res = False
    if ua.AccessLevel.CurrentWrite in list(node.get_access_level()):
        node.set_value(value)
        res = True
    return res


def argument(name, date_type, value_rank):
    """
    构建参数
    :param name:
    :param date_type: ua.ObjectIds.xxx
    :param value_rank:
    :return:
    """
    v = ua.Argument()
    v.Name = name
    v.DataType = ua.NodeId(date_type)
    v.ValueRank = value_rank
    v.ArrayDimensions = []
    v.Description = ua.LocalizedText(name)
    return v


if __name__ == "__main__":

    global server
    server = Server()
    # 服务地址
    server.set_endpoint("opc.tcp://0.0.0.0:4840/freeopcua/server/")
    # 允许的访问策略
    server.set_security_policy([
        ua.SecurityPolicyType.NoSecurity,
        ua.SecurityPolicyType.Basic256Sha256_SignAndEncrypt,
        ua.SecurityPolicyType.Basic256Sha256_Sign])
    uri = "http://examples.freeopcua.github.io"
    idx = server.register_namespace(uri)
    objects = server.get_objects_node()
    # 添加节点
    dev = objects.add_object(idx, "Device")
    dev_name = dev.add_variable(idx, "Name", "opcua_sensor")
    dev_battery = dev.add_variable(idx, "BatteryLevel", 9.0)
    dev_humidity = dev.add_variable(idx, "Humidity", 13)
    dev_switch = dev.add_variable(idx, "Switch", 1)
    dev_temperature = dev.add_variable(idx, "Temperature", 19)
    # 设置客户端可写
    dev_switch.set_writable()
    # 定义方法参数
    in_arg_node_id = argument("node_id", ua.ObjectIds.String, -1)
    in_arg_value = argument("value", ua.ObjectIds.Int64, -1)
    out_arg = argument("result", ua.ObjectIds.Boolean, -1)
    # 添加方法
    set_value_node = dev.add_method(idx, "set_value", set_value, [in_arg_node_id, in_arg_value], [out_arg])

    # 启动服务
    server.start()

    try:
        count = 0
        while True:
            time.sleep(1)
            count += 0.1
            dev_battery.set_value(count)
    finally:
        server.stop()

OPC UA py可视化客户端

安装
pip3 install opcua-client
pip3 install PyQt5

命令行执行opcua-client就可以看到下面界面,在前面的python opcua服务器启动的情况下,点击右上方的Connect按钮就能看到数据

路径就是图中左边的树形路径,推荐使用图中右边的,命名空间标识符+节点标识符。像这样:Switch的值就是 ${ns=2;i=5}原因文章末尾说。在这里插入图片描述

tb网关配置

tb_gateway.yaml中打开opcua连接器

thingsboard:
  host: localhost
  port: 1883
  remoteShell: false
  remoteConfiguration: false
  security:
    accessToken: z5zRQmSXe64U39my83jd
  qos: 0
storage:
  type: memory
  read_records_count: 100
  max_records_count: 100000
connectors: #打开opcua连接器
  -
    name: OPC-UA Connector
    type: opcua
    configuration: opcua-test.json

opcua-test.json配置 「和python代码中的服务器设置对应」

  • path的俩种配置方法「路径」「nodeId」可按照opcua客户端快速定位
  • switch开关量 ns=2;i=5 是opcua中的nodeid 作为属性上传到tb
  • humidity湿度、batteryLevel、temperature 作为遥测数据
  • set_value对应py中定义控制方法供tb服务端rpc调用

不推荐使用下列路径方式
"deviceNodePattern": "${Root\\.Objects\\.Device}",
"deviceNamePattern": "${Root\\.Objects\\.Device\\.Name}",

{
  "server": {
    "name": "OPC-UA Default Server",
    "url": "localhost:4840/freeopcua/server/",
    "timeoutInMillis": 5000,
    "scanPeriodInMillis": 5000,
    "disableSubscriptions":true,
    "subCheckPeriodInMillis": 100,
    "showMap": false,
    "security": "Basic128Rsa15",
    "identity": {
      "type": "anonymous"
    },
    "mapping": [
      {
        "deviceNodePattern": "${ns=2;i=1}",
        "deviceNamePattern": "${ns=2;i=2}",
        "attributes": [
          {
            "key": "switch",
            "path": "${ns=2;i=5}"
          }
        ],
        "timeseries": [
          {
            "key": "humidity",
            "path": "${ns=2;i=4}"
          },
          {
            "key": "batteryLevel",
            "path": "${ns=2;i=3}"
          },
          {
            "key": "temperature °C",
            "path": "${ns=2;i=6}"
          }
        ],
        "rpc_methods": [
          {
            "method": "set_value"
          }
        ],
        "attributes_updates": [
          {
            "attributeOnThingsBoard": "deviceName",
            "attributeOnDevice": "${ns=2;i=2}"
          }
        ]
      }
    ]
  }
}

thingsboard ui观察结果

设备列表出现opcua-test.json中配置的设备,设备名称是在py服务器中定义的。

这一步第一次使用tb网关的朋友很容易忽视,直接去tb网关查看设备遥测数据,网关实际工作中会接入多种协议的多个设备,所以遥测数据等 不会出现在网关上面。而是如果对应的连接器配置文件定义正确的情况下会在设备列表新出现json文件定义的设备

在这里插入图片描述
在这里插入图片描述

服务端rpc远程调用控制方法

postman示例:图1请求jwt_token;图2发送双向控制命令,得到响应
在这里插入图片描述
在这里插入图片描述

2.6版本网关使用问题

有朋友用2.6版本的tb网关,完全按照上面方式操作,网关会报下面的错list index out of range

""2021-04-20 14:07:59" - ERROR - [opcua_connector.py] - opcua_connector - 285 - list index out of range"
Traceback (most recent call last):
  File "/Users/weijixin/PycharmProjects/thingsboard-gateway/thingsboard_gateway/connectors/opcua/opcua_connector.py", line 268, in scan_nodes_from_config
    devices_info_array = self.__search_general_info(device_configuration)
  File "/Users/weijixin/PycharmProjects/thingsboard-gateway/thingsboard_gateway/connectors/opcua/opcua_connector.py", line 410, in __search_general_info
    device_name_node = device_name_node[0]

加群740168592联系后,源码debug看了下
这个方法内出了问题
在这里插入图片描述
如果使用命名空间标识符+节点标识符。像这样:${ns=2;i=5} 代码执行的就是图中A代码块,如果使用path方式就执行图中B代码块,debug可以看到B代码块找某个节点是循坏所有的子节点,性能低。而且2.6的C代码块部分我认为是有问题的,他会把Root.Objects.Device.Name解析成Root.Objects.Name,然后就报错说找不到节点,如果直接配置成Root.Objects.Name不符合opcua的路径,也不符合官网文档的节点介绍。

说这么多,一句话就是:用${ns=2;i=5}这种方式就可以了。
在这里插入图片描述
在这里插入图片描述

  • 3
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

fool_dawei

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值