文章目录
OPC python使用说明
运行环境
运行环境 python2.7 + window10 + KEPServerEX.6.4
链接:https://pan.baidu.com/s/1R4bC-NKLEl4s4FqRfhAIwQ
提取码:07yy
一、安装 OpenOPC
-
pip 安装依赖包
pip install Pywin32
pip install Pyro
- 修改环境变量
OPC_MODE = open
2. api 使用
说明:鉴于Pyro库版本的原因,本人实际运行的返回值跟文档有些对不上,但是不影响使用👌
1. 导包
前提:
将 OpenOPC 安装目录下 src 文件夹下的 OpenOPC.py
复制到 python2 安装目录下的 Lib\site-packages
目录下,或者你的项目目录下。
>>> import OpenOPC
2. 创建客户端实例
DCOM 模式
DCOM 模式是直连 OPC servers,无需 OpenOPC 网关服务. 但是只允许在 windows上运行。
>>> opc = OpenOPC.client()
open 模式
Open 模式下是连接到指定的 OpenOPC 网关服务,Windows和Linux 都可以使用。
>> opc = OpenOPC.open_client()
3. 列出本机所有可用的 OPC 服务器
>>> opc.servers()
['Matrikon.OPC.Simulation.1', 'Kepware.KEPServerEX.V6']
👍4. 连接服务器
连接到指定的服务器节点,如果服务器节点不在本机,需要传入第二个参数:节点的IP地址,默认 localhost
连接成功返回None
>>> opc.connect('Matrikon.OPC.Simulation', 'localhost')
👍5. 读取 opc 服务器数据
读取单个item
读取成功返回一个 (value, quality, timestamp)
元组,读取失败quality 为(None, 'Error', None)
>>> opc.read('Random.Int4')
(19169, 'Good', '06/24/07 15:56:11')
>>> value, quality, time = opc.read('Random.Int4')
读取多个Item
传入一个标签名列表,返回一个包含一系列元组的列表
>>> taglist = [u'通道 1.设备 1.标记 1', u'通道 1.设备 1.标记 2']
>>> opc.read(taglist)
[["通道 1.设备 1.标记 1", 51765, "Good", "06/22/20 13:18:55"], ["通道 1.设备 1.标记 2", 22, "Good", "06/22/20 13:18:55"]]
注: 由于Pyro版本原因,贫僧用的最新的 3.16 版本,在调用 opc.iread()方法时,提示PicklingError
错误,这是个以迭代器的方式读取数据方法,资源占用会少一点。
for name, value, quality, time in opc.iread( ['Random.Int2', 'Random.Int4'] ):
print name, value
6. 👍按Group读取OPC数据
为了获得最佳性能,通常需要将item放入指定的group中,然后重复请求更新group组的值。
>>> tags = ['Random.String', 'Random.Int4', 'Random.Real4']
>>> opc.read(tags, group='test')
[('Random.String', 'options', 'Good', '06/24/07 23:38:24'), ('Random.Int4', 31101, 'Good', '06/24/07 23:38:24')]
一旦声明了一个组,你就可以直接用group
参数,重复读取这些组里的item了。
>>> opc.read(group='test')
[('Random.String', 'clients', 'Good', '06/24/07 23:38:30'), ('Random.Int4', 26308, 'Good', '06/24/07 23:38:24')]
当你不想用 group组去访问了,记得移除组标签,这将释放所有已分配的资源。释放成功返回True
,失败返回False
>>> opc.remove('test')
True
释放所有组对象:
opc.remove(opc.groups())
7. 写入一个点
传入一个 (name, value) 元组即可,成功返回Success
, 失败返回Error
方式1
>>> opc.write( ('Triangle Waves.Real8', 100.0) )
'Success'
方式2
>>> opc['Triangle Waves.Real8'] = 100.0
8. 写入多个点
传入多个(name, value) 元组组成的列表即可,返回每个点写入的结果,效果如下
>>> opc.write( [('Triangle Waves.Real4', 10.0), ('Random.String', 20.0)] )
[('Triangle Waves.Real4', 'Success'), ('Random.String', 'Error')]
👍9. 包含写入结果的提示信息
>>> opc.write( [('Triangle Waves.Real4', 10.0), ('Random.Int4', 20.0)], include_error=True)
[('Triangle Waves.Real4', 'Success', '操作成功完成。 '), ('Random.Int4', 'Error', "该项目在服务器地址空间中不再可用。"
10. 获取Item属性
请求一个Item的所有属性,返回一个元组列表,每一个属性包括(id、属性名、属性值)
,举例如下:
>>> opc.properties('Random.Int4')
[(1, 'Item Canonical DataType', 'VT_I4'), (2, 'Item Value', 491), (3, 'Item Quality', 'Good'), (4, 'Item Timestamp', '06/25/07 02:24:44'), (5, 'Item Access Rights', 'Read'), (6, 'Server Scan Rate', 100.0), (7, 'Item EU Type', 0), (8, 'Item EUInfo', None), (101, 'Item Description', 'Random value.')]
可选参数 id
,直接返回上面返回的属性列表中的对应的单个 id属性。比如,返回id为1的属性值
>>> opc.properties('Random.Int4', id=1)
'VT_I4'
id 参数也可以指定多个,比如返回 Random.Int4 点的 1、2、5属性
>>> opc.properties('Random.Int4', id=(1,2,5))
[(1, 'VT_I4'), (2, 1869), (5, 'Read')]
同样的,也支持批量查询多个Item属性,返回值包括Item名和属性值
>>> opc.properties( ['Random.Int2', 'Random.Int4', 'Random.String'], id=1)
[('Random.Int2', 'VT_I2'), ('Random.Int4', 'VT_I4'), ('Random.String', 'VT_BSTR')]
🍎11. 查询可用Item点位
查询根节点
>>> opc.list()
['Simulation Items', 'Configured Aliases']
查询指定节点下的子节点
>>> opc.list('Simulation Items')
['Bucket Brigade', 'Random', 'Read Error', 'Saw-toothed Waves', 'Square Waves', 'Triangle Waves']
使用 .
连接符进一步查询子节点下可用 点位,比如
>>> opc.list('Simulation Items.Random')
['Random.ArrayOfReal8', 'Random.ArrayOfString', 'Random.Boolean', 'Random.Int1', 'Random.Int2']
使用 通配符
查询
>>> opc.list('Simulation Items.Random.*Real*')
['Random.ArrayOfReal8', 'Random.Real4', 'Random.Real8']
使用通配符
+递归 查询,指定参数 recursive=True
>>> opc.list('Sim*.R*.Real*', recursive=True)
['Random.Real4', 'Random.Real8', 'Read Error.Real4', 'Read Error.Real8']
同样地,支持批量查询:
>>> opc.list(('Simulation Items.Random.*Int*', 'Simulation Items.Random.Real*'))
['Random.Int1', 'Random.Int2', 'Random.Int4', 'Random.UInt1', 'Random.UInt2', 'Random.UInt4', 'Random.Real4', 'Random.Real8']
👍12. 查询OPC Server信息
>>> opc.info()
[('Protocol', 'OpenOPC'),
('Gateway Host', 'DESKTOP-EFDSAFO:7766'),
('Gateway Version', '1.3.1'),
('Class', 'Graybox.OPC.DAWrapper'),
('Client Name', u'OpenOPC'),
('OPC Host', 'DESKTOP-EFDSAFO'),
('OPC Server', u'Kepware.KEPServerEX.V6'),
('State', 'Running'),
('Version', '6.4 (Build 321)'),
('Browser', 'Hierarchical'),
('Start Time', '06/25/20 05:16:11'),
('Current Time', '06/26/20 07:32:43'),
('Vendor', u'Kepware')]
13. 复合查询
以上介绍的OpenOPC 方法可以组合使用,从而简化代码量。
比如使用模糊查询,并且获取实时值。
>>> opc.read(opc.list('Simulation Items.Random.*Int*'))
[('Random.Int1', 99, 'Good', '06/24/07 22:44:28'), ('Random.Int2', 26299, 'Good', '06/24/07 22:44:28'), ('Random.Int4', 17035, 'Good', '06/24/07 22:44:28'), ('Random.UInt1', 77, 'Good', '06/24/07 22:44:28'), ('Random.UInt2', 28703, 'Good', '06/24/07 22:44:28'), ('Random.UInt4', 23811.0, 'Good', '06/24/07 22:44:28')]
模糊查询所有Real4点位的 1#属性值(日期)
>>> opc.properties(opc.list('*.Real4', flat=True), id=1)
[('Bucket Brigade.Real4', 'VT_R4'), ('Random.Real4', 'VT_R4'), ('Read Error.Real4', 'VT_R4'), ('Saw-toothed Waves.Real4', 'VT_R4'), ('Square Waves.Real4', 'VT_R4'), ('Triangle Waves.Real4', 'VT_R4'), ('Write Error.Real4', 'VT_R4'), ('Write Only.Real4', 'VT_R4')]
从一个OPC服务器读取数据并写入另一个服务器:
>>> opc1.write(opc2.read(opc.list('Simulation Items.Triangle Waves.*Int*')))
[('Triangle Waves.Int1', 'Success'), ('Triangle Waves.Int2', 'Success'), ('Triangle Waves.Int4', 'Success'), ('Triangle Waves.UInt1', 'Success'), ('Triangle Waves.UInt2', 'Success'), ('Triangle Waves.UInt4', 'Success')]
14. 断开连接
>>> opc.close()
常用Demo
import time
import OpenOPC
GROUP_NAME = 'test'
opc = OpenOPC.open_client('localhost')
# 连接到本地 OPC模拟Server
opc.connect('Kepware.KEPServerEX.V6', 'localhost')
# 点位列表
taglist = [u'通道 1.设备 1.标记 1', u'通道 1.设备 1.标记 2', u'通道 1.设备 1.TAG1']
# 创建组对象
opc.read(taglist, group=GROUP_NAME)
try:
# 循环周期读取
while True:
# 请求组
opc_data = opc.read(group=GROUP_NAME)
# 保存字典
send_values = {}
for item in opc_data:
name, value, quality, time_ = item
if quality == 'Good':
send_values[name] = value
else:
print('Error: {}'.format(item))
print(send_values)
time.sleep(5)
finally:
# 释放资源
opc.remove(opc.groups())
opc.close()