ropc 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/lib/ropc.rb +4 -0
- data/lib/ropc/client.rb +158 -0
- data/lib/ropc/version.rb +3 -0
- metadata +61 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: db471e5edce66fb370612a4889ea5e281d3e7a36
|
4
|
+
data.tar.gz: 29a579ba8ebf66b889b047593ece02474aad37b6
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 1615ac3edfebd1c31746a71c899c00ee0ce074db8fc044c8c672b065a64f55f35384a745f66803afc6e1ee727b1a7c5a801636d3ab9e029bef2ef00b07dc5e4b
|
7
|
+
data.tar.gz: 24cdcad9e93a717de7d45f61ee54cc2ee44fc0caac6f4e66d9c158056ebc69d9cf0aa64f2b9a1eb4a9236522ca2167d6334bf1eea59fefbbba364d2099135418
|
data/lib/ropc.rb
ADDED
data/lib/ropc/client.rb
ADDED
@@ -0,0 +1,158 @@
|
|
1
|
+
require 'win32ole'
|
2
|
+
require 'logger'
|
3
|
+
|
4
|
+
module ROPC
|
5
|
+
|
6
|
+
module OPCDataSource
|
7
|
+
OPCCache = 1
|
8
|
+
OPCDevice = 2
|
9
|
+
end
|
10
|
+
|
11
|
+
module OPCQuality
|
12
|
+
OPCQualityMask = 192
|
13
|
+
OPCQualityBad = 0
|
14
|
+
OPCQualityUncertain = 64
|
15
|
+
OPCQualityGood = 192
|
16
|
+
OPCQuality = {192 => "Good", 64 => "Uncertain", 0 => "Bad"}
|
17
|
+
end
|
18
|
+
|
19
|
+
class Client
|
20
|
+
def initialize(tags: [], server: nil, node: nil, logger: Logger.new(STDOUT), level: "WARN")
|
21
|
+
@tags = tags
|
22
|
+
|
23
|
+
@server = server
|
24
|
+
@server ||= ENV["ROPC_SERVER"]
|
25
|
+
fail "Environment variable ROPC_SERVER not set or not server given." if @server.nil?
|
26
|
+
|
27
|
+
@node = node
|
28
|
+
@node ||= ENV["ROPC_NODE"]
|
29
|
+
fail "Environment variable ROPC_NODE not set or not node given." if @node.nil?
|
30
|
+
|
31
|
+
@logger = logger
|
32
|
+
@logger.level = level
|
33
|
+
|
34
|
+
establish_connection
|
35
|
+
end
|
36
|
+
|
37
|
+
def establish_connection
|
38
|
+
begin
|
39
|
+
@opc_automation = WIN32OLE.new 'OPC.Automation.1'
|
40
|
+
@logger.info("OPC.Automation.1 created.")
|
41
|
+
rescue => err
|
42
|
+
@logger.fatal("Cannot create win32ole OPC Automation object")
|
43
|
+
@logger.fatal(err)
|
44
|
+
exit
|
45
|
+
end
|
46
|
+
|
47
|
+
begin
|
48
|
+
@opc_automation.Connect(@server,@node)
|
49
|
+
@logger.info("Connected to OPC Server.")
|
50
|
+
@logger.info("OPC Server StartTime: #{@opc_automation.invoke("StartTime")}") # returns Time Class
|
51
|
+
@logger.info("OPC Server CurrentTime: #{@opc_automation.invoke("CurrentTime")}") # returns Time Class
|
52
|
+
rescue => err
|
53
|
+
@logger.fatal("Cannot connect to OPC #{@server} on #{@node}")
|
54
|
+
@logger.fatal(err)
|
55
|
+
exit
|
56
|
+
end
|
57
|
+
|
58
|
+
begin
|
59
|
+
@opc_group = @opc_automation.OPCGroups.add "OPCGroup"
|
60
|
+
@opc_items = @opc_group.OPCItems
|
61
|
+
#opc_group.UpdateRate = 1000
|
62
|
+
@logger.info("Group UpdateRate: #{@opc_group.UpdateRate}")
|
63
|
+
@logger.info("OPC Group IsSubscribed: #{@opc_group.IsSubscribed}")
|
64
|
+
@logger.info("OPC Group IsActive: #{@opc_group.IsActive}")
|
65
|
+
rescue => err
|
66
|
+
@logger.fatal("Could not add OPCGroup")
|
67
|
+
@logger.fatal(err)
|
68
|
+
exit
|
69
|
+
end
|
70
|
+
|
71
|
+
@items = {}
|
72
|
+
|
73
|
+
if @tags.respond_to?("each")
|
74
|
+
@tags.each {|tag| self.add tag }
|
75
|
+
else
|
76
|
+
self.add @tags
|
77
|
+
end
|
78
|
+
|
79
|
+
@logger.info("Number of OPCGroup in OPCGroups: #{@opc_automation.OPCGroups.Count}")
|
80
|
+
@logger.info("Number of OPCItem in OPCitems: #{@opc_items.Count}")
|
81
|
+
|
82
|
+
end
|
83
|
+
|
84
|
+
def add(tag)
|
85
|
+
begin
|
86
|
+
@items[tag] = @opc_items.AddItem(tag, 1)
|
87
|
+
rescue
|
88
|
+
@logger.warn("Failed to add this tag: #{tag}")
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
def remove(tag)
|
93
|
+
@items.delete(tag) if @items.has_key?(tag)
|
94
|
+
end
|
95
|
+
|
96
|
+
def read_tag(tag)
|
97
|
+
if @items.has_key?(tag)
|
98
|
+
opcitem = @items[tag]
|
99
|
+
begin
|
100
|
+
opcitem.read OPCDataSource::OPCCache # 1: reading from cache, 2: reading from device
|
101
|
+
rescue
|
102
|
+
@logger.warn("Failed to read opc tag: #{tag}")
|
103
|
+
cleanup
|
104
|
+
establish_connection
|
105
|
+
return tags
|
106
|
+
end
|
107
|
+
ts = opcitem.TimeStamp + opcitem.TimeStamp.gmtoff
|
108
|
+
@logger.info("Read #{opcitem.ItemID} Value: #{extract_value(opcitem.Value)}, Quality: #{OPCQuality::OPCQuality[opcitem.Quality]}, Time: #{ts}")
|
109
|
+
return {tag: opcitem.ItemID, value: extract_value(opcitem.Value), quality: OPCQuality::OPCQuality[opcitem.Quality], timestamp: ts}
|
110
|
+
else
|
111
|
+
return {}
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
def read
|
116
|
+
read_all
|
117
|
+
end
|
118
|
+
|
119
|
+
def read_all
|
120
|
+
tags = []
|
121
|
+
@items.keys.each do |tag|
|
122
|
+
tags << read_tag(tag)
|
123
|
+
end
|
124
|
+
return tags
|
125
|
+
end
|
126
|
+
|
127
|
+
def cleanup
|
128
|
+
@opc_groups.RemoveAll if @opc_groups
|
129
|
+
@opc_automation.Disconnect if @opc_automation
|
130
|
+
end
|
131
|
+
|
132
|
+
def extract_value str
|
133
|
+
begin
|
134
|
+
if str.kind_of?(FalseClass)
|
135
|
+
return 0.0
|
136
|
+
elsif str.kind_of?(TrueClass)
|
137
|
+
return 1.0
|
138
|
+
elsif Float(str)
|
139
|
+
return str
|
140
|
+
elsif Int(str)
|
141
|
+
return str
|
142
|
+
end
|
143
|
+
rescue
|
144
|
+
@logger.warn("failed to extract value: #{str}; returning 0.0")
|
145
|
+
return 0.0
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
end
|
150
|
+
|
151
|
+
def self.read_tags(tags)
|
152
|
+
opc = ROPC::Client.new(tags: tags, level: "WARN")
|
153
|
+
ret = opc.read
|
154
|
+
opc.cleanup
|
155
|
+
ret
|
156
|
+
end
|
157
|
+
|
158
|
+
end
|
data/lib/ropc/version.rb
ADDED
metadata
ADDED
@@ -0,0 +1,61 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: ropc
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Koni Marti
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2018-09-24 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: win32ole-pp
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.2'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.2'
|
27
|
+
description: Read the tags from an OPC server using Win32 OLE for monitoring and data
|
28
|
+
analysis.
|
29
|
+
email: ''
|
30
|
+
executables: []
|
31
|
+
extensions: []
|
32
|
+
extra_rdoc_files: []
|
33
|
+
files:
|
34
|
+
- lib/ropc.rb
|
35
|
+
- lib/ropc/client.rb
|
36
|
+
- lib/ropc/version.rb
|
37
|
+
homepage: https://github.com/konimarti
|
38
|
+
licenses:
|
39
|
+
- MIT
|
40
|
+
metadata: {}
|
41
|
+
post_install_message:
|
42
|
+
rdoc_options: []
|
43
|
+
require_paths:
|
44
|
+
- lib
|
45
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
46
|
+
requirements:
|
47
|
+
- - ">="
|
48
|
+
- !ruby/object:Gem::Version
|
49
|
+
version: '0'
|
50
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
requirements: []
|
56
|
+
rubyforge_project:
|
57
|
+
rubygems_version: 2.5.2
|
58
|
+
signing_key:
|
59
|
+
specification_version: 4
|
60
|
+
summary: Minimal, read-only OPC client
|
61
|
+
test_files: []
|