Python-opcua 编程(3)历史数据读写

news2024/9/28 1:15:41

        历史数据就是将opcua 信息模型中的某一些变量保存起来,以便Client 端程序能够读取历史数据,作各种数据处理。

       Opcua 标准指出历史数据的读写,主要包括:

  1.      属性 Historizing 当设置为True 时,该变量支持历史数据读写
  2.      属性 AccessLevel 设置为HistoryReadWirte

History 机制

存储方式:

  • 存储在内存
  • 存储在sqlite3 数据库中

我们重点关注Sqlite3 数据库方式。

Sqlite3

      SQLite是一种用C写的小巧的嵌入式数据库,它的数据库就是一个文件。SQLite 不需要一个单独的服务器进程或操作的系统,不需要配置,这意味着不需要安装或管理,所有的维护都来自于SQLite 软件本身。python自带的轻量级数据库模块-sqlite3.python-opcua 的历史数据存储就是采用了python自带的sqlite3 实现的。具体的就是HistorySQLite 模块实现,它是一个类。

实例1 数据存储

import sys
sys.path.insert(0, "..")
import time
import math


from opcua import ua, Server
from opcua.server.history_sql import HistorySQLite


if __name__ == "__main__":

    # setup our server
    server = Server()
    server.set_endpoint("opc.tcp://127.0.0.1:48401/freeopcua/server/")

    # setup our own namespace, not really necessary but should as spec
    uri = "http://examples.freeopcua.github.io"
    idx = server.register_namespace(uri)

    # get Objects node, this is where we should put our custom stuff
    objects = server.get_objects_node()

    # populating our address space
    myobj = objects.add_object(idx, "MyObject")
    myvar = myobj.add_variable(idx, "MyVariable", ua.Variant(0, ua.VariantType.Double))
    myvar.set_writable()  # Set MyVariable to be writable by clients
    myvar1 = myobj.add_variable(idx, "MyVariable1", ua.Variant(0, ua.VariantType.Double))
    myvar1.set_writable()
    # Configure server to use sqlite as history database (default is a simple memory dict)
    server.iserver.history_manager.set_storage(HistorySQLite("my_datavalue_history.sql"))

    # starting!
    server.start()

    # enable data change history for this particular node, must be called after start since it uses subscription
    server.historize_node_data_change(myvar, period=None, count=100)
    server.historize_node_data_change(myvar1, period=None, count=100)
    try:
        count = 0
        while True:
            time.sleep(1)
            count += 0.1
            myvar.set_value(math.sin(count))
            myvar1.set_value(1-math.sin(count))
    finally:
        # close connection, remove subscriptions, etc
        server.stop()

从上述的程序可见:

定义了两个变量MyVariable和MyVariable1.

配置服务器的历史存储方式

  server.iserver.history_manager.set_storage(HistorySQLite("my_datavalue_history.sql"))

       HistorySQLite就是前面提及的访问sqlite 的类。它的源代码是history_sql.py。我认为,如果我们向物使用其它的数据库,例如 influxDB,mongoDB,TD Engine 等,大概只要改写history_sql.py模块就可以了。

执行上述程序行,将在程序所在目录中打开my_datavalue_history.sql文件,如果每一这样的文件,程序将自动兴建一个my_datavalue_history.sql文件。

另外就是实现历史数据值改变的handle就可以了。

 # enable data change history for this particular node, must be called after start since it uses subscription
    server.historize_node_data_change(myvar, period=None, count=100)
    server.historize_node_data_change(myvar1, period=None, count=100)

      period是历史数据的存储周期,默认为7 天。操过这个时间会自动地被删除。count是存储数据的次数。

令人惊奇的是一旦设置完成,history 数据存储是完全自动地完成的。不需要额外的程序。

sqlite3 数据库的查看

my_datavalue_history.sql是一个二进制文件,在调试阶段如果要查看存储的数据,可以使用一个sqlite3 数据库浏览器程序,我使用DB Browser  for SQLite。可以在其官网下载,安装。

这是它的界面截图

浏览数据

 

值得一提的是,数据库表的名称是变量NodeId 的名称构成的。在我的程序中 

MyVariable的NodeId 是(ns=2,i=2)和(ns=2,i=3) 所以,对应表的名称为2_2 和2_3.

历史事件的存储

if __name__ == "__main__":

    # setup our server
    server = Server()
    server.set_endpoint("opc.tcp://localhost:48410/freeopcua/server/")

    # setup our own namespace, not really necessary but should as spec
    uri = "http://examples.freeopcua.github.io"
    idx = server.register_namespace(uri)

    # get Objects node, this is where we should put our custom stuff
    objects = server.get_objects_node()

    # populating our address space
    myobj = objects.add_object(idx, "MyObject")

    # Creating a custom event: Approach 1
    # The custom event object automatically will have members from its parent (BaseEventType)
    etype = server.create_custom_event_type(2, 'MyFirstEvent', ua.ObjectIds.BaseEventType,
                                            [('MyNumericProperty', ua.VariantType.Float),
                                             ('MyStringProperty', ua.VariantType.String)])
    # create second event
    etype2 = server.create_custom_event_type(2, 'MySecondEvent', ua.ObjectIds.BaseEventType,
                                             [('MyOtherProperty', ua.VariantType.Float)])

    # get an event generator for the myobj node which generates custom events
    myevgen = server.get_event_generator(etype, myobj)
    myevgen.event.Severity = 500
    myevgen.event.MyStringProperty = ua.Variant("hello world")
    myevgen.event.MyNumericProperty = ua.Variant(-456)

    # get another event generator for the myobj node which generates different custom events
    myevgen2 = server.get_event_generator(etype2, myobj)
    myevgen2.event.Severity = 123
    myevgen2.event.MyOtherProperty = ua.Variant(1.337)

    # get an event generator for the server node which generates BaseEventType
    serverevgen = server.get_event_generator()
    serverevgen.event.Severity = 111

    # Configure server to use sqlite as history database (default is a simple in memory dict)
    server.iserver.history_manager.set_storage(HistorySQLite("my_event_history.sql"))

    # starting!
    server.start()

    # enable history for myobj events; must be called after start since it uses subscription
    server.iserver.enable_history_event(myobj, period=None)

    # enable history for server events; must be called after start since it uses subscription
    server_node = server.get_node(ua.ObjectIds.Server)
    server.historize_node_event(server_node, period=None)

    try:
        count = 0
        while True:
            time.sleep(1)
            count += 0.1

            # generate events for subscribed clients and history
            myevgen.trigger(message="This is MyFirstEvent " + str(count))
            myevgen2.trigger(message="This is MySecondEvent " + str(count))
            serverevgen.trigger(message="Server Event Message")

            # read event history from sql
            end_time = datetime.utcnow()
            server_event_history = server_node.read_event_history(None, end_time, 0)

    finally:
        # close connection, remove subscriptions, etc
        server.stop()

上述两个程序均能在spyder 中运行。希望能够帮到你。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/738066.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

kafka主题支持路由功能

背景: 我们知道rabbitmq是支持消息路由的功能的,但是当我们统一消息中间件到kafka后,有一些旧的应用依然想要使用消息路由的功能时,我们可以怎么让kafka也支持消息路由的功能呢? 技术实现: 为了不影响ka…

web实现小米商城首页选择内容

一、需求&#xff1a;实现如下图所示的web内容 二、实现结果 三、代码展示 <!DOCTYPE html> <html> <head><title>小米商场</title><style>body {display: flex;flex-direction: column;align-items: center;justify-content: center;he…

阿里云轻量应用服务器使用教程(以建站为例)

阿里云轻量应用服务器怎么使用&#xff1f;阿里云轻量应用服务器使用教程&#xff1a;轻量应用服务器购买、重置密码、远程连接、宝塔面板的Web环境搭建、WordPress网站程序安装到网站上线&#xff0c;阿里云服务器网分享轻量应用服务器从购买、配置建站环境、轻量服务器应用服…

【SLAM】Ceres优化库超详细解析

Ceres是由Google开发的开源C通用非线性优化库&#xff0c;与g2o并列为目前视觉SLAM中应用最广泛的优化算法库。 对于任何一个优化问题&#xff0c;我们首先需要对问题进行建模&#xff0c;之后采用合适的优化方法&#xff0c;进行求解。在求解的过程中&#xff0c;往往需要进行…

用 Nginx 禁止国外 IP 访问我的网站...

先来说说为啥要写这篇文章&#xff0c;之前看了下 Nginx 的访问日志&#xff0c;发现每天有好多国外的 IP 地址来访问我的网站&#xff0c;并且访问的内容基本上都是恶意的。因此我决定禁止国外 IP 来访问我的网站。 想要实现这个功能有很多方法&#xff0c;下面我就来介绍基于…

(动态规划) 132. 分割回文串 II ——【Leetcode每日一题】

❓ 132. 分割回文串 II 难度&#xff1a;困难 给你一个字符串 s&#xff0c;请你将 s 分割成一些子串&#xff0c;使每个子串都是回文。 返回符合要求的 最少分割次数 。 示例 1&#xff1a; 输入&#xff1a;s “aab” 输出&#xff1a;1 解释&#xff1a;只需一次分割就…

Vision Transformer (ViT)介绍

paper&#xff1a;An Image is Worth 16x16 Words: Transformers for Image Recognition at Scale 摘要 把transformer直接应用于图像块序列&#xff0c;也可以在图像分类任务上表现很好。通过在大数据集上预训练&#xff0c;然后迁移到中等规模和小规模数据集上&#xff0c;…

Android之签字板

文章目录 前言一、效果图二、实现步骤1.GestureSignatureView类2.xml布局3.Activity类(kotlin)4.Activity类(Java)5.动态申请权限(kotlin)6.动态申请权限(Java) 总结 前言 随着公司发展需求&#xff0c;很多金融APP都会涉及到需要用户签字的环节&#xff0c;所以在此贴出代码以…

软考高级架构师笔记-9系统架构

目录 1. 前文回顾 & 考情分析2. 软件架构概述3. 软件架构风格3.1 层次架构风格3.2 面向服务架构风格4. 软件架构复用5. 特定领域软件体系结构DSSA6. ABSD7. 质量属性8. 架构评估9 结语1. 前文回顾 & 考情分析 前文回顾: 软考高级架构师笔记-1计算机硬件软考高级架构师…

TCP 协议(三)十种核心机制

1.确认应答&#xff08;可靠机制&#xff09; 2.超时重传&#xff08;可靠机制&#xff09; 3.连接管理&#xff08;可靠机制&#xff09; 4.滑动窗口&#xff08;效率机制&#xff09; 5.流量控制&#xff08;效率机制&#xff09; 6.拥塞控制&#xff08;效率机制&#xff09…

优维低代码实践:权限设置

优维低代码技术专栏&#xff0c;是一个全新的、技术为主的专栏&#xff0c;由优维技术委员会成员执笔&#xff0c;基于优维7年低代码技术研发及运维成果&#xff0c;主要介绍低代码相关的技术原理及架构逻辑&#xff0c;目的是给广大运维人提供一个技术交流与学习的平台。 优维…

js两种对象混合写,返回的是哪一个

<script>function jiafa() {this.name "xuhaitao";this.age 36;var obj {};obj.xx "hunkxu";obj.yy "88";return obj;}var aa new jiafa();console.log(aa);</script> 打印&#xff1a; FR&#xff1a;徐海涛(hunk xu)

3D引擎龙头Unity:元宇宙和AI活跃玩家

Unity是用于创建和操作交互式实时3D内容的世界领先平台。凭借灵活的编辑器、友好的开发环境、丰富的工具套件&#xff0c;Unity吸引了大量开发者&#xff0c;全球排名前1000的移动游戏70%以上使用了Unity的创作和运营解决方案&#xff0c;如今&#xff0c;Unity引擎在工业场景、…

leaflet地图移动防抖问题

现在有这么一个需求&#xff0c;当移动地图时&#xff0c;需要获取当前地图范围属于那个城市。如果频繁移动地图&#xff0c;会不停的调用接口获取当前地图视图所属城市&#xff0c;所以加个防抖&#xff0c;减少请求。代码示例&#xff1a;<!DOCTYPE html> <html>…

【Leetcode】36. 有效的数独

一、题目 1、题目描述 请你判断一个 9 x 9 的数独是否有效。只需要 根据以下规则 ,验证已经填入的数字是否有效即可。 数字 1-9 在每一行只能出现一次。 数字 1-9 在每一列只能出现一次。 数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。(请参考示例图) 注意:…

微信小程序生态15- 批量提交微信小程序审核的一种方式

文章导航 微信小程序生态1-初识小程序 微信小程序生态2-创建一个微信小程序 微信小程序生态3-微信小程序登录流程设计 微信小程序生态4-扫普通二维码进入小程序、打开短链接进入小程序 微信小程序生态5-微信公众号扫码登录PC端网页 微信小程序生态6-微信公众号授权登录(适用于…

字节跳动(抖音),软件测试四面,面试题总结!走过路过不要错过

面试一 1、 简单做一下自我介绍 2、 简要介绍一下项目/你负责的模块/选一个模块说一下你设计的用例 3 、get请求和post请求的区别 4、 如何判断前后端bug/3xx是什么意思 5、 说一下XXX项目中你做的接口测试/做了多少次 6、 http和https的区别 7、 考了几个ADB命令/查看连…

JAVA_WEB 购物商城(WEB端)

仓库地址&#xff1a;https://gitee.com/ThMyGitee/EeasyEeasyCityFrontEnd.git CSDN的友友们&#xff0c;项目如果适合您的话&#xff0c;麻烦给个小小的Star&#xff0c;谢谢啦&#xff01; JAVA_WEB 购物商城(WEB端) 效果图: 技术选型: 后端技术栈 Jsp Servlet &#x…

【力扣算法01】之最接近的三数之和

文章目录 前言问题描述示例 1示例 2提示 解题思路代码分析完整代码运行效果如图执行示例代码1执行示例代码2 完结 前言 近期已经将python 的大部分内容讲完了, 接下来的一段时间会着重于算法和面试题相关的内容, 确保学有所用, 同时也为准备进入大厂的童靴们做个铺垫, 记得关注…

抖音seo源码-源代码开发搭建-开源部署操作日志

一、开发者前言大环境概述 抖音seo源码开发是一项非常重要的技术&#xff0c;在抖音上&#xff0c;有很多视频&#xff0c;如果你想让自己的视频脱颖而出&#xff0c;那么就需要优化自己的seo源码。不过&#xff0c;为了保护用户的隐私&#xff0c;抖音并不公开其seo算法的细节…