- OpcUA 数据采集应用示例
OpcUA 数据采集应用示例
- 使用了opcua的Lua模块: open62541-lua
- 读取Simulation节点下所有数据项
代码:
--- 导入需求的模块local class = require 'middleclass'local opcua = require 'opcua'--- 注册对象(请尽量使用唯一的标识字符串)local app = class("IOT_OPCUA_CLIENT_APP")--- 设定应用最小运行接口版本(目前版本为1,为了以后的接口兼容性)app.API_VER = 1----- 应用对象初始化函数-- @param name 应用本地安装名称。 如modbus_com_1-- @param sys 系统sys接口对象。参考API文档中的sys接口说明-- @param conf 应用配置参数。由安装配置中的json数据转换出来的数据对象function app:initialize(name, sys, conf)self._name = nameself._sys = sysself._conf = conf--- 获取数据接口self._api = sys:data_api()--- 获取日志接口self._log = sys:logger()self._connect_retry = 1000end----- 检测连接可用性function app:is_connected()if self._client thenreturn trueendend----- 获取设备的OpcUa节点function app:get_device_node(namespace, obj_name)if not self:is_connected() thenself._log:warning("Client is not connected!")returnendlocal client = self._clientlocal nodes = self._nodes--- 获取Objects节点local objects = client:getObjectsNode()--- 获取名字空间的id号local idx, err = client:getNamespaceIndex(namespace)if not idx thenself._log:warning("Cannot find namespace", err)returnend--- 获取设备节点local devobj, err = objects:getChild(idx..":"..obj_name)if not devobj thenself._log:error('Device object not found', err)returnelseself._log:debug("Device object found", devobj)end--- 返回节点对象return {idx = idx,name = obj_name,device = device,devobj = devobj,vars = {}}end----- 定义需要获取数据的输入项local inputs = {{ name = "Counter1", desc = "Counter1"},{ name = "s1", desc = "Simulation 1"},}----- 连接成功后的处理函数function app:on_connected(client)-- Cleanup nodes bufferself._nodes = {}-- Set client objectself._client = client--- Get opcua object instance by namespace and browse name-- 根据名字空间和节点名称获取OpcUa对象实体local namespace = self._conf.namespace or "http://www.prosysopc.com/OPCUA/SimulationNodes"local obj_name = "Simulation"local node, err = self:get_device_node(namespace, obj_name)----- 获取设备对象节点下的变量节点if node thenfor _,v in ipairs(inputs) dolocal var, err = node.devobj:getChild(v.name)--print(_,v.name,var)if not var thenself._log:error('Variable not found', err)elsenode.vars[v.name] = varendendlocal sn = namespace..'/'..obj_nameself._nodes[sn] = nodeendend----- 连接断开后的处理函数function app:on_disconnect()self._nodes = {}self._client = nilself._sys:timeout(self._connect_retry, function() self:connect_proc() end)self._connect_retry = self._connect_retry * 2if self._connect_retry > 2000 * 64 thenself._connect_retry = 2000endend----- 连接处理函数function app:connect_proc()self._log:notice("OPC Client start connection!")local client = self._client_objlocal ep = self._conf.endpoint or "opc.tcp://172.30.1.162:53530/OPCUA/SimulationServer"local username = self._conf.username or "user1"local password = self._conf.password or "password"--local r, err = client:connect_username(ep, username, password)local r, err = client:connect(ep)if r thenself._log:notice("OPC Client connect successfully!", self._sys:time())self._connect_retry = 2000self:on_connected(client)elseself._log:error("OPC Client connect failure!", err, self._sys:time())self:on_disconnect()endend--- 应用启动函数function app:start()self._nodes = {}self._devs = {}--- 设定OpcUa连接配置local config = opcua.ConnectionConfig.new()config.protocolVersion = 0 -- 协议版本config.sendBufferSize = 65535 -- 发送缓存大小config.recvBufferSize = 65535 -- 接受缓存大小config.maxMessageSize = 0 -- 消息大小限制config.maxChunkCount = 0 ----- 生成OpcUa客户端对象local client = opcua.Client.new(5000, 10 * 60 * 1000, config)self._client_obj = client--- 发起OpcUa连接self._sys:fork(function() self:connect_proc() end)--- 设定接口处理函数self._api:set_handler({on_output = function(...)print(...)end,on_ctrl = function(...)print(...)end})--- 创建设备对象实例local sys_id = self._sys:id()local meta = self._api:default_meta()meta.name = "Unknow OPCUA"meta.description = "Unknow OPCUA Device"meta.series = "X1"local dev = self._api:add_device(sys_id..'.OPCUA_TEST', meta, inputs)self._devs['Simulation'] = devreturn trueend--- 应用退出函数function app:close(reason)print('close', self._name, reason)--- 清理OpcUa客户端连接self._client = nilif self._client_obj thenself._nodes = {}self._client_obj:disconnect()self._client_obj = nilendend--- 应用运行入口function app:run(tms)if not self._client thenreturn 1000end--- 获取节点当前值数据for sn, node in pairs(self._nodes) dolocal dev = self._devs[node.name]assert(dev)for k, v in pairs(node.vars) dolocal dv = v:getValue()--[[print(dv, dv:isEmpty(), dv:isScalar())print(dv:asLong(), dv:asDouble(), dv:asString())]]--local now = self._sys:time()--- 设定当前值dev:set_input_prop(k, "value", dv:asDouble(), now, 0)endend--- 返回下一次调用run函数的间隔return 2000end--- 返回应用对象return app
