python工业互联网监控项目实战4—python opcua
<p> 前面章节我们采用OPC作为设备到上位的信息交互的协议,本章我们介绍跨平台的<span style="font-family: Calibri">OPC UA</span>。OPC作为早期的工业通信规范,是基于<span style="font-family: Calibri">COM/DCOM</span>的技术实现的,用于设备和软件之间交换数据,最初,<span style="font-family: Calibri">OPC</span>标准仅限于<span style="font-family: Calibri">Windows</span>操作系统。<span style="font-family: Calibri">OPC</span>是<span style="font-family: Calibri">OLE for Process Control</span>的缩写(中文意思:用于过程控制的<span style="font-family: Calibri">OLE</span>)。</p><p>OPC规范包括了<span style="font-family: Calibri">3</span>大部分:</p>
<ol>
<li>OPC DA:<span style="font-family: Calibri">OPC</span>实时数据访问规范,定义了包括数据值,更新时间与数据品质信息的相关标准。前面实战2我们使用openOPC获取的<span style="font-family: Calibri">tag</span>位号值就属于<span style="font-family: Calibri">OPC DA</span>,通过<span style="font-family: Calibri">OPC DA</span>读取底层设备的状态、工业参数等位号的实时数据。</li>
<li>OPC HDA:<span style="font-family: Calibri">OPC</span>历史数据访问规范,定义了查询、分析历史数据和含有时标的数据的方法。</li>
<li>OPC AE:<span style="font-family: Calibri">OPC</span>报警事件访问规范,定义了报警与时间类型的消息类信息,以及状态变化管理等相关标准。</li>
</ol>
<p>由于基于COM/DCOM的技术有着不能跨平台的根本缺点,随着技术的发展,<span style="font-family: Calibri">OPC</span>基金会在<span style="font-family: Calibri">2008</span>年发布了新的规范:<span style="font-family: Calibri">OPC UA </span>(<span style="font-family: Calibri">OPC Unified Architecture</span>)<span style="font-family: Calibri">OPC </span>统一框架。</p>
<h4>1. <strong>OPC UA<span style="font-family: 宋体">是什么</span></strong> </h4>
<p> 2008年发布的OPC统一架构(UA)将各个OPC Classic规范的所有功能集成到一个可扩展的框架中,独立于平台并且面向服务。OPC UA规范不再是基于COM/DCOM技术,因此OPC UA不仅能在Windows平台上实现,更可以在Linux,以及其它的嵌入式平台中实现。 </p>
<p><span style="font-family: 宋体">这种多层方法实现了最初设计</span>UA规范时的目标: </p>
<ol>
<li><span style="font-family: 宋体">功能对等性:所有</span>COM OPC Classic规范都映射到UA</li>
<li>平台独立性:从嵌入式微控制器到基于云的基础设施</li>
<li>安全性:信息加密、身份验证和审核</li>
<li>可扩展性:添加新功能而不影响现有应用程序的能力</li>
<li>综合信息建模:用于定义复杂信息</li>
</ol>
<h4>2. <strong>OPC UA<span style="font-family: 宋体">相对于传统</span><span style="font-family: Arial">OPC</span><span style="font-family: 宋体">的变化</span></strong> </h4>
<p><span style="font-size: 16px; font-family: 黑体">功能对等性</span> </p>
<p>OPC UA不仅支持传统OPC的所有功能,更支持更多新的功能: </p>
<ol>
<li><span style="font-family: 宋体">发现:在本地</span>PC和/或网络上查找可用的OPC服务器</li>
<li><span style="font-family: 宋体">地址空间:所有数据都是分层表示的(例如文件和文件夹),允许</span>OPC客户端发现、利用简单和复杂的数据结构</li>
<li><span style="font-family: 宋体">按需:基于访问权限读取和写入数据</span>/信息</li>
<li><span style="font-family: 宋体">订阅:监视数据</span>/信息,并且当值变化超出客户端的设定时报告异常</li>
<li>事件:基于客户端的设定通知重要信息</li>
<li>方法:客户端可以基于在服务器上定义的方法来执行程序等</li>
<li>OPC UA产品和OPC Classic产品之间的集成可以通过COM/Proxy Wrappers轻松实现。</li>
</ol>
<p><span style="font-family: 黑体">平台独立性</span></p>
<p><span style="font-family: 宋体"> 鉴于市场上有各种各样的硬件平台和操作系统,平台独立性就显得至关重要。</span>OPC UA<span style="font-family: 宋体">包含但不限于以下平台及系统:</span></p>
<p><span style="font-family: 宋体"> 硬件平台:传统</span>PC<span style="font-family: 宋体">硬件、云服务器、</span><span style="font-family: Calibri">PLC</span><span style="font-family: 宋体">、微控制器(</span><span style="font-family: Calibri">ARM</span><span style="font-family: 宋体">等)</span></p>
<p><span style="font-family: 宋体"> 操作系统:</span>Microsoft Windows<span style="font-family: 宋体">、</span><span style="font-family: Calibri">Apple OSX</span><span style="font-family: 宋体">、</span><span style="font-family: Calibri">Android</span><span style="font-family: 宋体">或任何</span><span style="font-family: Calibri">Linux</span><span style="font-family: 宋体">发行版本等</span></p>
<p> OPC UA<span style="font-family: 宋体">为企业之间的互操作性提供必要的</span><span style="font-family: Calibri">M2M</span><span style="font-family: 宋体">、</span><span style="font-family: Calibri">M2E</span><span style="font-family: 宋体">及两者之间的基础架构。</span></p>
<p>安全性</p>
<p><span style="font-family: 宋体"> 最大的变化是</span>OPC UA<span style="font-family: 宋体">可以通过任何单一端口(经管理员开放后)进行通信,这使得</span><span style="font-family: Calibri">OPC</span><span style="font-family: 宋体">通信不再会由于防火墙受到大量的限制,实现</span><span style="font-family: Calibri">Internet </span><span style="font-family: 宋体">通讯。</span></p>
<p>综合信息建模</p>
<p> OPC UA<span style="font-family: 宋体">信息建模框架将数据转换为信息。通过完全面向对象的功能,即使是最复杂的多级结构也可以建模和扩展。数据类型和结构在配置文件中定义。 例如,现有的</span><span style="font-family: Calibri">OPC Classic</span><span style="font-family: 宋体">规范被建模为</span><span style="font-family: Calibri">UA</span><span style="font-family: 宋体">配置文件,也可以由其他组织扩展:</span></p>
<p> </p>
<p><span style="font-family: 宋体"><img src="https://img2020.cnblogs.com/blog/67400/202004/67400-20200422115012719-518200184.png" alt=""></span></p>
<p> </p>
<p> <span style="font-family: 宋体">更详细的内容请参阅</span>OPC基金会官网:http://opcfoundation.cn/ </p>
<p> 3. <strong>安装</strong><strong>python-opcua</strong><strong>组件</strong> </p>
<p> pip<span style="font-family: 宋体">安装:</span><span style="font-family: Calibri">pip install opcua </span> </p>
<p> 组件按照完毕后,我们可以在python<span style="font-family: 宋体">环境</span><span style="font-family: 宋体">执行</span>uadiscover<span style="font-family: 宋体">命令</span>查看效果: </p>
<p><span style="font-family: Calibri"><img src="https://img2020.cnblogs.com/blog/67400/202004/67400-20200422115109942-1333836761.png" alt=""></span></p>
<p> <span style="font-family: 宋体">由于运行电脑上没有运行的</span>opcua<span style="font-family: 宋体">服务端,命令没有发现任何</span><span style="font-family: Calibri">opcua</span><span style="font-family: 宋体">服务。下面通过运行</span><span style="font-family: Calibri">opcua</span><span style="font-family: 宋体">上最新的服务端代码再来看看效果。</span></p>
<ol>
<li><span style="font-family: 宋体">在</span>C:\Python\Python36-32\Scripts\<span style="font-family: 宋体">下创建</span><span style="font-family: Calibri">examples</span><span style="font-family: 宋体">目录;</span></li>
<li>Copy opcua<span style="font-family: 宋体">源码下的</span><span style="font-family: Calibri">server-minimal.py</span><span style="font-family: 宋体">到</span><span style="font-family: Calibri">C:\Python\Python36-32\Scripts\examples</span><span style="font-family: 宋体">;</span></li>
<li><span style="font-family: 宋体">在</span>C:\Python\Python36-32<span style="font-family: 宋体">目录下运行命令,如下图:</span></li>
<li>python C:\Python\Python36-32\Scripts\examples\server-minimal.py </li>
</ol>
<p><span style="font-family: Calibri"><img src="https://img2020.cnblogs.com/blog/67400/202004/67400-20200422115142027-1474888305.png" alt=""></span></p>
<p><span style="font-family: 宋体"> 重新运行</span>uadiscover<span style="font-family: 宋体">命令,结果如下:</span></p>
<p><img src="https://img2020.cnblogs.com/blog/67400/202004/67400-20200422115221496-164789929.png" alt=""></p>
<p> <span style="font-family: 宋体"> 现在连接到 OPCUA Sever 的模拟器提供的 OPC UA 服务了。</span></p>
<h4>4. <strong><span style="font-family: 宋体">创建一个</span>4C9<span style="font-family: 宋体">反应罐的</span><span style="font-family: Arial">OPCUA Server</span><span style="font-family: 宋体">模拟器</span></strong></h4>
<p><strong>4.1. <span style="font-family: 宋体">在</span>Solution<span style="font-family: 宋体">上添加一个</span><span style="font-family: Calibri">Python Application Project </span><span style="color: rgba(153, 51, 0, 1)">Tank4C9Svr</span></strong></p>
<p> <strong><span style="font-family: Calibri"><img src="https://img2020.cnblogs.com/blog/67400/202004/67400-20200422115445451-1139901981.png" alt=""></span></strong></p>
<p> <span style="font-family: 宋体"> 打开</span>Tank4C9Svr.py<span style="font-family: 宋体">文件,修改</span><span style="font-family: Calibri">Example</span><span style="font-family: 宋体">里的</span><span style="font-family: Calibri">server-minimal.py</span><span style="font-family: 宋体">文件里代码,模拟</span><span style="font-family: Calibri">4C9</span><span style="font-family: 宋体">反应罐如下:</span> </p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> sys
sys.path.insert(0, </span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">..</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> time
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> random
</span><span style="color: rgba(0, 0, 255, 1)">from</span> opcua <span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> ua, Server
</span><span style="color: rgba(0, 0, 255, 1)">if</span> <span style="color: rgba(128, 0, 128, 1)">__name__</span> == <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">__main__</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">:
</span><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> setup our server</span>
server =<span style="color: rgba(0, 0, 0, 1)"> Server()
server.set_endpoint(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">opc.tcp://0.0.0.0:4840/freeopcua/server/</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> setup our own namespace, not really necessary but should as spec</span>
uri = <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">http://examples.freeopcua.github.io</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">
idx </span>=<span style="color: rgba(0, 0, 0, 1)"> server.register_namespace(uri)
</span><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> get Objects node, this is where we should put our nodes</span>
objects =<span style="color: rgba(0, 0, 0, 1)"> server.get_objects_node()
</span><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> populating our address space</span>
myobj = objects.add_object(idx, <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Tank4C9</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">)
status </span>= myobj.add_variable(idx, <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Status</span><span style="color: rgba(128, 0, 0, 1)">"</span>, 0<span style="color: rgba(0, 0, 0, 1)">)
overheadFlow </span>= myobj.add_variable(idx, <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">OverheadFlow</span><span style="color: rgba(128, 0, 0, 1)">"</span>, 0<span style="color: rgba(0, 0, 0, 1)">)
buttomsFlow </span>= myobj.add_variable(idx, <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">ButtomsFlow</span><span style="color: rgba(128, 0, 0, 1)">"</span>, 0<span style="color: rgba(0, 0, 0, 1)">)
power </span>= myobj.add_variable(idx, <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Power</span><span style="color: rgba(128, 0, 0, 1)">"</span>, 0<span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)">myVar.set_writable() # Set MyVariable to be writable by clients</span>
<span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> starting!</span>
<span style="color: rgba(0, 0, 0, 1)"> server.start()
</span><span style="color: rgba(0, 0, 255, 1)">try</span><span style="color: rgba(0, 0, 0, 1)">:
count </span>=<span style="color: rgba(0, 0, 0, 1)"> 0
</span><span style="color: rgba(0, 0, 255, 1)">while</span><span style="color: rgba(0, 0, 0, 1)"> True:
time.sleep(</span>5<span style="color: rgba(0, 0, 0, 1)">)
count </span>= count + 1
<span style="color: rgba(0, 0, 255, 1)">print</span>(count%4<span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 0, 255, 1)">if</span> count%4><span style="color: rgba(0, 0, 0, 1)">0:
status.set_value(</span>1<span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)">:
status.set_value(0)
a</span>= random.randint(100,500<span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 0, 255, 1)">print</span>(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">OverheadFlow:</span><span style="color: rgba(128, 0, 0, 1)">"</span>+<span style="color: rgba(0, 0, 0, 1)">str(a))
overheadFlow.set_value(a)
buttomsFlow.set_value(random.randint(</span>50,500<span style="color: rgba(0, 0, 0, 1)">))
power.set_value(random.randint(</span>1000,5000<span style="color: rgba(0, 0, 0, 1)">))
</span><span style="color: rgba(0, 0, 255, 1)">finally</span><span style="color: rgba(0, 0, 0, 1)">:
</span><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)">close connection, remove subcsriptions, etc</span>
server.stop()</pre>
</div>
<p> 我们把Tank4C9Svr<span style="font-family: 宋体">设置成</span><span style="font-family: Calibri">solution</span><span style="font-family: 宋体">默认启动项目后,</span><span style="font-family: Calibri">F5</span><span style="font-family: 宋体">调试运行</span><span style="font-family: Calibri">Tank4C9Svr</span><span style="font-family: 宋体">,如下图:</span></p>
<p><span style="font-family: 宋体"><img src="https://img2020.cnblogs.com/blog/67400/202004/67400-20200422115633560-2030159611.png" alt=""></span></p>
<h4> 5. <strong>opcua-client<span style="font-family: 宋体">浏览</span><span style="font-family: Arial">4C9 opcua</span><span style="font-family: 宋体">服务器</span></strong></h4>
<p><span style="font-family: 宋体"> 安装:</span><span style="font-family: 宋体">pip install opcua-client</span></p>
<p> cmd<span style="font-family: 宋体">窗口</span><span style="font-family: Calibri">C:\Python\Python36-32\Scripts</span><span style="font-family: 宋体">目录下执行</span><span style="font-family: Calibri">opcua-client.exe</span><span style="font-family: 宋体">命令,如下图:</span> </p>
<p> <img src="https://img2020.cnblogs.com/blog/67400/202004/67400-20200422115724480-1207100436.png" alt=""></p>
<p> </p>
<p> <img src="https://img2020.cnblogs.com/blog/67400/202004/67400-20200422115730941-1678464316.png" alt=""></p>
<p> <span style="font-family: 宋体"> 地址栏输入 opc.tcp://localhost:4840 点击连接按钮,就能看见我们构建的Tank4C9设备和对于的tag变量了,如下图:</span></p>
<p><span style="font-family: 宋体"><img src="https://img2020.cnblogs.com/blog/67400/202004/67400-20200422115950180-962921408.png" alt=""></span></p>
<p> 我们可以在变量上右键来订阅数据变化的读取最新的数据值。</p>
<p><img src="https://img2020.cnblogs.com/blog/67400/202004/67400-20200422120008602-2017769609.png" alt=""></p>
<p> </p>
<p> <img src="https://img2020.cnblogs.com/blog/67400/202004/67400-20200422120015185-725275006.png" alt=""></p>
<h4> 6. <strong>小结</strong></h4>
<p><span style="font-family: 宋体"> 本小节主要介绍了</span>OPC DA<span style="font-family: 宋体">到</span><span style="font-family: Calibri">OPC UA</span><span style="font-family: 宋体">之间的关系,更多详细的信息参考</span><span style="font-family: Calibri">OPC</span><span style="font-family: 宋体">基金会官网。首先,我们使用 </span><strong>python-opcua </strong>组件<span style="font-family: 宋体">模拟构建一个</span><span style="font-family: Calibri">Tank4C9</span><span style="font-family: 宋体">的反应罐</span><span style="font-family: Calibri">OPC UA</span><span style="font-family: 宋体">服务器,然后,演示</span><span style="font-family: Calibri">OPC UA</span><span style="font-family: 宋体">的</span><span style="font-family: Calibri">Objects</span><span style="font-family: 宋体">是如何构建的。最后,展示</span><span style="font-family: Calibri">opcua-client</span><span style="font-family: 宋体">连接这个</span><span style="font-family: Calibri">OPCUA</span><span style="font-family: 宋体">服务器并订阅数据变化是如何的显示效果。下一节我们将用演示监控如何迁移到OPC UA数据通信协议。</span></p>
<p> </p><br><br>
来源:https://www.cnblogs.com/haozi0804/p/12751127.html
頁:
[1]