ladder_drive 0.6.0 → 0.6.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2bd6ed103f79bb7083b861a6464f83c668dcbb5c14808d3e702cc5a4206c9c6b
4
- data.tar.gz: e7c1f12717307d569f203f8c054413cf97c69e66c832247846f675f0405b9d4f
3
+ metadata.gz: 89e93e6ad6630128bf1a0996dd9de4c399e246acbb1c92615eb92fc83f0ec206
4
+ data.tar.gz: 5cb779d24babb0d23284276765c79e6edb27bbf1901d946eceb1a88a7b1cca99
5
5
  SHA512:
6
- metadata.gz: f6b4b164bbeba262f1c57334955ea09e423662b6e63a1b502f953211df9640645731a3970316e376f4545f046a75db2c3c5a0d3705d16725dd033ce3156e3483
7
- data.tar.gz: a0525951ac3a7d82a1b767806a0b59e2c5a7f95b55621e7ab7fd456689659d3f537f5c90f2baa3cc5cd618c536c66510ccb97cc2bc29b751a5b74a0e2b314518
6
+ metadata.gz: ea1e43769ad3deb7845a208c501906b2db81f04c9223ce7152f35d663ff5529cb44f2f8ebd0920f37443cb963715280bf8a69ac7efab3319504d218adc721b23
7
+ data.tar.gz: 59dae9cd3d5080ee2d7ce616951d05e1cf387c2e7920b8f3a2a2ce0411492ed662ae5da91517c69f99c9969fd3f82256049839e89f135bc5de99a89e59647091
data/Gemfile.lock CHANGED
@@ -4,7 +4,7 @@ PATH
4
4
  ladder_drive (0.6.0)
5
5
  activesupport (~> 4.2, >= 4.2.7)
6
6
  ffi (~> 1.9.24, >= 1.9.24)
7
- pi_piper (>= 2.0.0)
7
+ pi_piper (~> 2.0, >= 2.0.0)
8
8
  thor (~> 0)
9
9
 
10
10
  GEM
@@ -110,16 +110,16 @@ PLATFORMS
110
110
  ruby
111
111
 
112
112
  DEPENDENCIES
113
- activesupport
113
+ activesupport (~> 4.2, >= 4.2.7)
114
114
  bundler (~> 1.11)
115
- ffi
115
+ ffi (~> 1.9.24)
116
116
  google_drive
117
117
  ladder_drive!
118
- pi_piper
118
+ pi_piper (>= 2.0.0)
119
119
  rake (~> 10.0)
120
120
  ruby-trello
121
121
  serialport
122
122
  test-unit
123
123
 
124
124
  BUNDLED WITH
125
- 1.16.6
125
+ 1.17.2
data/README_jp.md CHANGED
@@ -184,12 +184,6 @@ OUT M1
184
184
  <!-- [![](http://img.youtube.com/vi/qGbicGLB7Gs/0.jpg)](https://youtu.be/qGbicGLB7Gs) -->
185
185
 
186
186
 
187
- ```warning: constant ::Fixnum is deprecated``` の表示が出る場合は次の様にしてみてください。
188
-
189
- ```sh
190
- $ RUBYOPT="-W0" rake
191
- ```
192
-
193
187
  ## Raspberry Pi
194
188
 
195
189
  Raspberry Pi上で動作させることもできます。
data/ladder_drive.gemspec CHANGED
@@ -18,6 +18,7 @@ Gem::Specification.new do |spec|
18
18
  spec.add_runtime_dependency 'activesupport', '~> 4.2', '>= 4.2.7'
19
19
  spec.add_runtime_dependency 'ffi', '~> 1.9.24', '>= 1.9.24'
20
20
  spec.add_runtime_dependency 'pi_piper', '~> 2.0', '>= 2.0.0'
21
+ spec.add_runtime_dependency 'serialport'
21
22
 
22
23
  spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
23
24
  spec.bindir = "exe"
@@ -33,7 +33,7 @@ module LadderDrive
33
33
  def create(name)
34
34
  if File.exist? name
35
35
  puts "ERROR: #{name} already exists."
36
- exit -1
36
+ exit(-1)
37
37
  end
38
38
 
39
39
  # copy from template file
@@ -58,7 +58,7 @@ module LadderDrive
58
58
  path = File.join(plugins_path, "#{name}_plugin.rb")
59
59
  if File.exist? path
60
60
  mkdir_p "plugins"
61
- cp path, "plugins/#{name}_plugins.rb"
61
+ cp path, "plugins/#{name}_plugin.rb"
62
62
  end
63
63
  end
64
64
 
@@ -30,7 +30,6 @@ module LadderDrive
30
30
  include Singleton
31
31
 
32
32
  def run
33
- l = true
34
33
  trap(:INT) { puts "\n> " }
35
34
 
36
35
  display_title
@@ -54,7 +54,7 @@ module LadderDrive
54
54
  @suffix = nil
55
55
  @value = 0
56
56
  case a
57
- when Fixnum
57
+ when Integer
58
58
  @suffix = ESC_SUFFIXES[a]
59
59
  @number = b
60
60
  when String, Symbol
@@ -127,7 +127,7 @@ module LadderDrive
127
127
 
128
128
  def bool
129
129
  case @value
130
- when Fixnum
130
+ when Integer
131
131
  @value != 0
132
132
  else
133
133
  !!@value
@@ -29,6 +29,7 @@ module Keyence
29
29
 
30
30
  def initialize options={}
31
31
  super
32
+ @socket = nil
32
33
  @host = options[:host] || "192.168.0.10"
33
34
  @port = options[:port] || 8501
34
35
  prepare_device_map
@@ -148,6 +149,7 @@ module Keyence
148
149
 
149
150
  def available_bits_range suffix=nil
150
151
  case suffix
152
+ # FIXME: duplicated
151
153
  when "TM"
152
154
  1..512
153
155
  when "TM"
@@ -167,13 +169,13 @@ module Keyence
167
169
 
168
170
  def available_words_range suffix=nil
169
171
  case suffix
172
+ # FIXME: duplicated
170
173
  when "TM"
171
174
  1..256
172
175
  when "TM"
173
176
  1..12
174
177
  when "T", "TC", "TS", "C", "CC", "CS"
175
178
  1..120
176
- 1..120
177
179
  when "CTH"
178
180
  1..2
179
181
  when "CTC"
@@ -51,6 +51,7 @@ module Mitsubishi
51
51
  @baudrate = 19200
52
52
  @station_no = 0
53
53
  @wait_time = 0
54
+ @comm = nil
54
55
  #prepare_device_map
55
56
  end
56
57
 
@@ -29,6 +29,7 @@ module Mitsubishi
29
29
 
30
30
  def initialize options={}
31
31
  super
32
+ @socket = nil
32
33
  @host = options[:host] || "192.168.0.10"
33
34
  @port = options[:port] || 5010
34
35
  prepare_device_map
@@ -29,13 +29,17 @@ module Protocol
29
29
 
30
30
  class Protocol
31
31
 
32
- attr_accessor :host, :port, :log_level
32
+ attr_accessor :host, :port
33
33
 
34
34
  def initialize options={}
35
35
  @logger = Logger.new(STDOUT)
36
36
  self.log_level = options[:log_level] || :info
37
37
  end
38
38
 
39
+ def log_level
40
+ @log_level
41
+ end
42
+
39
43
  def log_level= level
40
44
  @log_level = level.is_a?(String) ? level.to_sym : level
41
45
  case @log_level
@@ -31,7 +31,6 @@ module LadderDrive
31
31
 
32
32
  attr_accessor :protocol
33
33
  attr_accessor :source
34
- attr_accessor :data
35
34
 
36
35
  def initialize options={}
37
36
  @protocol = options[:protocol] if options[:protocol]
@@ -22,5 +22,5 @@
22
22
  # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23
23
 
24
24
  module LadderDrive
25
- VERSION = "0.6.0"
25
+ VERSION = "0.6.1"
26
26
  end
@@ -31,7 +31,7 @@ module Emulator
31
31
  class EmuDevice < PlcDevice
32
32
 
33
33
  attr_reader :in_value, :out_value
34
- attr_accessor :plc
34
+ attr_reader :plc
35
35
 
36
36
  def initialize a, b = nil
37
37
  super
@@ -63,6 +63,7 @@ module Emulator
63
63
  end
64
64
  @lock = Mutex.new
65
65
  @config = config
66
+ @pending_save = nil
66
67
  reset
67
68
  load_plugins
68
69
  end
@@ -341,12 +342,12 @@ module Emulator
341
342
  (SIZE_OF_BIT_STACK - 1).downto 0 do |i|
342
343
  values << stack_device(i).word
343
344
  end
344
- v = values.pop
345
+ value = values.pop
345
346
  values.each_with_index do |v, i|
346
347
  stack_device(i).word = v
347
348
  end
348
349
  stack_count_device.word -= 1
349
- v
350
+ value
350
351
  end
351
352
  # ----------------
352
353
 
@@ -85,11 +85,10 @@ class Plugin
85
85
  class << self
86
86
 
87
87
  def devices_with_plc_from_str plc, dev_str
88
- devices = dev_str.split(",").map{|e| e.split("-")}.map do |devs|
88
+ dev_str.split(",").map{|e| e.split("-")}.map do |devs|
89
89
  devs = devs.map{|d| plc.device_by_name d.strip}
90
90
  d1 = devs.first
91
91
  d2 = devs.last
92
- d = d1
93
92
  [d2.number - d1.number + 1, 1].max.times.inject([]){|a, i| a << d1; d1 += 1; a}
94
93
  end.flatten
95
94
  end
@@ -118,7 +117,7 @@ class Plugin
118
117
  end
119
118
 
120
119
  def disabled?
121
- config[:disable]
120
+ config.empty? || config[:disable]
122
121
  end
123
122
 
124
123
  def run_cycle plc
@@ -65,127 +65,154 @@ DOC
65
65
  require 'net/https'
66
66
  require 'google_drive'
67
67
 
68
- def plugin_google_drive_init plc
69
- @plugin_google_drive_config = load_plugin_config 'google_drive'
70
- return if @plugin_google_drive_config[:disable]
71
-
72
- @plugin_google_drive_values = {}
73
- @plugin_google_drive_times = {}
74
- @plugin_google_drive_worker_queue = Queue.new
75
-
76
- begin
77
- # generate config file for google drive session
78
- tmp_dir = File.expand_path "tmp"
79
- session_path = File.join(tmp_dir, "google_drive_session.json")
80
- unless File.exist? session_path
81
- mkdir_p tmp_dir
82
- conf =
83
- [:client_id, :client_secret, :refresh_token].inject({}) do |h, key|
84
- v = @plugin_google_drive_config[key]
85
- h[key] = v if v
86
- h
87
- end
88
- File.write session_path, JSON.generate(conf)
89
- end
68
+ module LadderDrive
69
+ module Emulator
90
70
 
91
- # create google drive session
92
- @plugin_google_drive_session = GoogleDrive::Session.from_config(session_path)
71
+ class GoogleDrivePlugin < Plugin
93
72
 
94
- # start worker thread
95
- Thread.start {
96
- plugin_google_drive_worker_loop
97
- }
98
- rescue => e
99
- p e
100
- @plugin_google_drive_session = nil
101
- end
102
- end
73
+ def initialize plc
74
+ super #plc
75
+ return if disabled?
103
76
 
104
- def plugin_google_drive_exec plc
105
- return if @plugin_google_drive_config[:disable]
106
- return unless @plugin_google_drive_session
77
+ @values = {}
78
+ @times = {}
79
+ @worker_queue = Queue.new
107
80
 
108
- @plugin_google_drive_config[:loggings].each do |logging|
109
81
  begin
110
- # check triggered or not
111
- triggered = false
112
- case logging[:trigger][:type]
113
- when "interval"
114
- now = Time.now
115
- t = @plugin_google_drive_times[logging.object_id] || now
116
- triggered = t <= now
117
- if triggered
118
- t += logging[:trigger][:interval] || 300
119
- @plugin_google_drive_times[logging.object_id] = t
120
- end
121
- else
122
- d = plc.device_by_name logging[:trigger][:device]
123
- v = d.send logging[:trigger][:value_type], logging[:trigger][:text_length] || 8
124
- unless @plugin_google_drive_values[logging.object_id] == v
125
- @plugin_google_drive_values[logging.object_id] = v
126
- case logging[:trigger][:type]
127
- when "raise"
128
- triggered = !!v
129
- when "fall"
130
- triggered = !v
131
- else
132
- triggered = true
82
+ # generate config file for google drive session
83
+ tmp_dir = File.expand_path "tmp"
84
+ session_path = File.join(tmp_dir, "google_drive_session.json")
85
+ unless File.exist? session_path
86
+ mkdir_p tmp_dir
87
+ conf =
88
+ [:client_id, :client_secret, :access_token, :refresh_token].inject({}) do |h, key|
89
+ v = config[key]
90
+ h[key] = v if v
91
+ h
133
92
  end
134
- end
93
+ File.write session_path, JSON.generate(conf)
135
94
  end
136
95
 
137
- next unless triggered
96
+ # create google drive session
97
+ @session = GoogleDrive::Session.from_config(session_path)
138
98
 
139
- # gether values
140
- values = logging[:devices].map do |config|
141
- d1, d2 = config[:device].split("-").map{|d| plc.device_by_name d}
142
- devices = [d1]
143
- if d2
144
- d = d1 + 1
145
- devices += [d2.number - d1.number, 0].max.times.inject([]){|a, i| a << d; d += 1; a}
146
- end
147
- devices.map{|d| d.send config[:type], config[:length] || 8}
148
- end.flatten
149
- @plugin_google_drive_worker_queue.push logging:logging, values:values, time:Time.now
99
+ # start worker thread
100
+ setup if @session
150
101
  rescue => e
151
102
  p e
103
+ @session = nil
104
+ exit(1)
152
105
  end
153
- end if @plugin_google_drive_config[:loggings]
154
- end
155
106
 
156
- def plugin_google_drive_worker_loop
157
- while arg = @plugin_google_drive_worker_queue.pop
158
- begin
159
- logging = arg[:logging]
160
- spread_sheet = @plugin_google_drive_session.spreadsheet_by_key(logging[:spread_sheet][:spread_sheet_key])
107
+ end
161
108
 
162
- # get worksheet
163
- worksheet = begin
164
- if logging[:spread_sheet][:sheet_name]
165
- spread_sheet.worksheet_by_title logging[:spread_sheet][:sheet_name]
109
+ def run_cycle plc
110
+ return if disabled?
111
+ return unless @session
112
+
113
+ config[:loggings].each do |logging|
114
+ begin
115
+ # check triggered or not
116
+ triggered = false
117
+ case logging[:trigger][:type]
118
+ when "interval"
119
+ now = Time.now
120
+ t = @times[logging.object_id] || now
121
+ triggered = t <= now
122
+ if triggered
123
+ t += logging[:trigger][:interval] || 300
124
+ @times[logging.object_id] = t
125
+ end
166
126
  else
167
- spread_sheet.worksheets[logging[:spread_sheet][:sheet_no] || 0]
127
+ d = plc.device_by_name logging[:trigger][:device]
128
+ v = d.send logging[:trigger][:value_type], logging[:trigger][:text_length] || 8
129
+ unless @values[logging.object_id] == v
130
+ @values[logging.object_id] = v
131
+ case logging[:trigger][:type]
132
+ when "raise"
133
+ triggered = !!v
134
+ when "fall"
135
+ triggered = !v
136
+ else
137
+ triggered = true
138
+ end
139
+ end
168
140
  end
141
+
142
+ next unless triggered
143
+
144
+ # gether values
145
+ values = logging[:devices].map do |config|
146
+ d1, d2 = config[:device].split("-").map{|d| plc.device_by_name d}
147
+ devices = [d1]
148
+ if d2
149
+ d3 = d1 + 1
150
+ devices += [d2.number - d1.number, 0].max.times.inject([]){|a, i| a << d3; d3 += 1; a}
151
+ end
152
+ devices.map{|d| d.send config[:type], config[:length] || 8}
153
+ end.flatten
154
+ @worker_queue.push logging:logging, values:values, time:Time.now
155
+ rescue => e
156
+ #p e, caller
169
157
  end
158
+ end if config[:loggings]
159
+ end
160
+
161
+ private
162
+
163
+ def setup
164
+ Thread.start {
165
+ thread_proc
166
+ }
167
+ end
168
+
169
+ def thread_proc
170
+ while arg = @worker_queue.pop
171
+ begin
172
+ logging = arg[:logging]
173
+ spread_sheet = @session.spreadsheet_by_key(logging[:spread_sheet][:spread_sheet_key])
174
+
175
+ # get worksheet
176
+ worksheet = begin
177
+ if logging[:spread_sheet][:sheet_name]
178
+ spread_sheet.worksheet_by_title logging[:spread_sheet][:sheet_name]
179
+ else
180
+ spread_sheet.worksheets[logging[:spread_sheet][:sheet_no] || 0]
181
+ end
182
+ end
183
+
184
+ # write columns if needs
185
+ if worksheet.num_rows == 0
186
+ worksheet[1, 1] = "Time"
187
+ logging[:columns].split(",").each_with_index do |t, i|
188
+ worksheet[1, i + 2] = t
189
+ end
190
+ end
170
191
 
171
- # write columns if needs
172
- if worksheet.num_rows == 0
173
- worksheet[1, 1] = "Time"
174
- logging[:columns].split(",").each_with_index do |t, i|
175
- worksheet[1, i + 2] = t
192
+ # write values
193
+ r = worksheet.num_rows + 1
194
+ worksheet[r, 1] = arg[:time]
195
+ arg[:values].each_with_index do |v, i|
196
+ worksheet[r, i + 2] = v
197
+ end if arg[:values]
198
+ worksheet.save
199
+ rescue => e
200
+ # TODO: Resend if it fails.
201
+ #p e, caller
176
202
  end
177
203
  end
178
-
179
- # write values
180
- r = worksheet.num_rows + 1
181
- worksheet[r, 1] = arg[:time]
182
- arg[:values].each_with_index do |v, i|
183
- worksheet[r, i + 2] = v
184
- end if arg[:values]
185
- worksheet.save
186
- rescue => e
187
- # TODO: Resend if it fails.
188
- p e
189
204
  end
190
- end
205
+
206
+ end
207
+
208
+ end
209
+ end
210
+
211
+
212
+ def plugin_google_drive_init plc
213
+ @google_drive_plugin = LadderDrive::Emulator::GoogleDrivePlugin.new plc
214
+ end
215
+
216
+ def plugin_google_drive_exec plc
217
+ @google_drive_plugin.run_cycle plc
191
218
  end
@@ -57,78 +57,111 @@ DOC
57
57
 
58
58
  require 'net/https'
59
59
 
60
- def plugin_ifttt_init plc
61
- @plugin_ifttt_config = load_plugin_config 'ifttt'
62
- return if @plugin_ifttt_config[:disable]
63
-
64
- @plugin_ifttt_values = {}
65
- @plugin_ifttt_times = {}
66
- @plugin_ifttt_worker_queue = Queue.new
67
- Thread.start {
68
- plugin_ifttt_worker_loop
69
- }
70
- end
60
+ module LadderDrive
61
+ module Emulator
71
62
 
72
- def plugin_ifttt_exec plc
73
- return if @plugin_ifttt_config[:disable]
74
- return unless @plugin_ifttt_config[:web_hook_key]
75
-
76
- @plugin_ifttt_config[:events].each do |event|
77
- begin
78
- triggered = false
79
- case event[:trigger][:type]
80
- when "interval"
81
- now = Time.now
82
- t = @plugin_ifttt_times[event.object_id] || now
83
- triggered = t <= now
84
- if triggered
85
- t += event[:trigger][:interval] || 300
86
- @plugin_ifttt_times[event.object_id] = t
87
- end
88
- else
89
- d = plc.device_by_name event[:trigger][:device]
90
- v = d.send event[:trigger][:value_type], event[:trigger][:text_length] || 8
91
- unless @plugin_ifttt_values[event.object_id] == v
92
- @plugin_ifttt_values[event.object_id] = v
93
- case event[:trigger][:type]
94
- when "raise"
95
- triggered = !!v
96
- when "fall"
97
- triggered = !v
98
- else
99
- triggered = true
63
+ class IftttPlugin < Plugin
64
+
65
+ def initialize plc
66
+ super #plc
67
+ return if disabled?
68
+
69
+ @values = {}
70
+ @times = {}
71
+ @worker_queue = Queue.new
72
+ setup
73
+ end
74
+
75
+ def run_cycle plc
76
+ return if disabled?
77
+ config[:events].each do |event|
78
+ begin
79
+ triggered = false
80
+ case event[:trigger][:type]
81
+ when "interval"
82
+ now = Time.now
83
+ t = @times[event.object_id] || now
84
+ triggered = t <= now
85
+ if triggered
86
+ t += event[:trigger][:interval] || 300
87
+ @times[event.object_id] = t
88
+ end
89
+ else
90
+ d = plc.device_by_name event[:trigger][:device]
91
+ v = d.send event[:trigger][:value_type], event[:trigger][:text_length] || 8
92
+ unless @values[event.object_id] == v
93
+ @values[event.object_id] = v
94
+ case event[:trigger][:type]
95
+ when "raise"
96
+ triggered = !!v
97
+ when "fall"
98
+ triggered = !v
99
+ else
100
+ triggered = true
101
+ end
100
102
  end
101
103
  end
104
+
105
+ next unless triggered
106
+
107
+ @worker_queue.push event:event[:name], payload:event[:params].dup || {}, value:v
108
+ rescue => e
109
+ p e
102
110
  end
111
+ end if config[:events]
112
+ end
113
+
114
+ def disabled?
115
+ return false unless super
116
+ unless config[:web_hook_key]
117
+ puts "ERROR: IftttPlugin requires web_hook_key."
118
+ false
119
+ else
120
+ super
121
+ end
122
+ end
103
123
 
104
- next unless triggered
105
124
 
106
- @plugin_ifttt_worker_queue.push event:event[:name], payload:event[:params].dup || {}, value:v
107
- rescue => e
108
- p e
125
+ private
126
+
127
+ def setup
128
+ Thread.start {
129
+ thread_proc
130
+ }
109
131
  end
110
- end if @plugin_ifttt_config[:events]
111
- end
112
132
 
113
- def plugin_ifttt_worker_loop
114
- while arg = @plugin_ifttt_worker_queue.pop
115
- begin
116
- uri = URI.parse("https://maker.ifttt.com/trigger/#{arg[:event]}/with/key/#{@plugin_ifttt_config[:web_hook_key]}")
117
- http = Net::HTTP.new(uri.host, uri.port)
118
- http.use_ssl = true
119
- http.verify_mode = OpenSSL::SSL::VERIFY_NONE
120
-
121
- req = Net::HTTP::Post.new(uri.path)
122
- payload = arg[:payload]
123
- payload.keys.each do |key|
124
- payload[key] = arg[:value] if payload[key] == "__value__"
125
- end
126
- req.set_form_data(payload)
133
+ def thread_proc
134
+ while arg = @worker_queue.pop
135
+ begin
136
+ uri = URI.parse("https://maker.ifttt.com/trigger/#{arg[:event]}/with/key/#{config[:web_hook_key]}")
137
+ http = Net::HTTP.new(uri.host, uri.port)
138
+ http.use_ssl = true
139
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
140
+
141
+ req = Net::HTTP::Post.new(uri.path)
142
+ payload = arg[:payload]
143
+ payload.keys.each do |key|
144
+ payload[key] = arg[:value] if payload[key] == "__value__"
145
+ end
146
+ req.set_form_data(payload)
127
147
 
128
- http.request(req)
129
- rescue => e
130
- # TODO: Resend if it fails.
131
- p e
148
+ http.request(req)
149
+ rescue => e
150
+ # TODO: Resend if it fails.
151
+ p e
152
+ end
153
+ end
132
154
  end
133
- end
155
+
156
+ end
157
+
158
+ end
159
+ end
160
+
161
+ def plugin_ifttt_init plc
162
+ @ifttt_plugin = LadderDrive::Emulator::IftttPlugin.new plc
163
+ end
164
+
165
+ def plugin_ifttt_exec plc
166
+ @ifttt_plugin.run_cycle plc
134
167
  end
@@ -54,13 +54,15 @@ class PlcMapperPlugin < Plugin
54
54
 
55
55
  def initialize plc
56
56
  super #plc
57
+ return if disabled?
57
58
  @lock = Mutex.new
58
59
  @values_for_reading = {}
59
60
  @values_for_writing = {}
60
- setup
61
+ setup unless config.empty? || config[:disable]
61
62
  end
62
63
 
63
64
  def run_cycle plc
65
+ return if disabled?
64
66
  return false unless super
65
67
  @lock.synchronize {
66
68
  # set values from plcs to ladder drive.
@@ -81,8 +83,8 @@ class PlcMapperPlugin < Plugin
81
83
 
82
84
  def setup
83
85
  config[:plcs].each do |plc_config|
84
- Thread.start(plc_config) {|plc_config|
85
- mapping_thread_proc plc_config
86
+ Thread.start(plc_config) {|config|
87
+ mapping_thread_proc config
86
88
  }
87
89
  end
88
90
  end
@@ -102,7 +104,9 @@ class PlcMapperPlugin < Plugin
102
104
  mappings.map do |h|
103
105
  a = []
104
106
  h.each do |k, v|
105
- devs = v.split("-").map{|d| protocol.device_by_name d.strip}
107
+ devs = v.split("-").map{|d|
108
+ protocol.device_by_name d.strip
109
+ }
106
110
  d1 = devs.first
107
111
  d2 = devs.last
108
112
  a << k
@@ -125,6 +129,7 @@ class PlcMapperPlugin < Plugin
125
129
  Time.at t
126
130
  end
127
131
 
132
+ alerted = false
128
133
  loop do
129
134
  begin
130
135
  now = Time.now
@@ -133,8 +138,10 @@ class PlcMapperPlugin < Plugin
133
138
  next_time += interval
134
139
  end
135
140
  sleep next_time - Time.now
136
- rescue => e
137
- puts e, caller
141
+ alerted = false
142
+ rescue
143
+ puts "#{config[:description]} is not reachable." unless alerted
144
+ alerted = true
138
145
  end
139
146
  end
140
147
  end
@@ -43,113 +43,139 @@ DOC
43
43
 
44
44
  require 'net/https'
45
45
 
46
- def plugin_slack_init plc
47
- @plugin_slack_config = load_plugin_config 'slack'
48
-
49
- @plugin_slack_values = {}
50
- @plugin_slack_times = {}
51
- @plugin_slack_worker_queue = Queue.new
52
-
53
- # collect comments
54
- @plugin_slack_comments = {}
55
- @plugin_slack_config[:device_comments].each do |k, v|
56
- d = plc.device_by_name(k)
57
- @plugin_slack_comments[d.name] = v if d
58
- end if @plugin_slack_config[:device_comments]
59
-
60
- Thread.start {
61
- plugin_slack_worker_loop
62
- }
63
- end
64
46
 
65
- def plugin_slack_exec plc
66
- return if @plugin_slack_config[:disable]
67
-
68
- @plugin_slack_config[:events].each do |event|
69
- next unless event[:devices]
70
- next unless event[:webhook_url]
71
- begin
72
-
73
- # gether values
74
- devices = event[:devices].split(",").map{|e| e.split("-")}.map do |devs|
75
- devs = devs.map{|d| plc.device_by_name d.strip}
76
- d1 = devs.first
77
- d2 = devs.last
78
- d = d1
79
- [d2.number - d1.number + 1, 1].max.times.inject([]){|a, i| a << d1; d1 += 1; a}
80
- end.flatten
81
-
82
- interval_triggered = false
83
- now = Time.now
84
- devices.each do |device|
85
- triggered = false
86
- v = nil
87
- case event[:trigger][:type]
88
- when "interval"
89
- t = @plugin_slack_times[event.object_id] || now
90
- triggered = t <= now
91
- if triggered
92
- interval_triggered = true
93
- t += event[:trigger][:interval] || 300
94
- @plugin_slack_times[event.object_id] = t
95
- end
96
- v = device.send event[:value_type], event[:trigger][:text_length] || 8
97
- else
98
- v = device.send event[:value_type], event[:text_length] || 8
99
- unless @plugin_slack_values[device.name] == v
100
- @plugin_slack_values[device.name] = v
101
- case event[:trigger][:type]
102
- when "raise"
103
- triggered = !!v
104
- when "fall"
105
- triggered = !v
106
- else
107
- triggered = true
47
+ module LadderDrive
48
+ module Emulator
49
+
50
+ class SlackPlugin < Plugin
51
+
52
+ def initialize plc
53
+ super #plc
54
+ return if disabled?
55
+
56
+ @values = {}
57
+ @times = {}
58
+ @worker_queue = Queue.new
59
+
60
+ # collect comments
61
+ @comments = {}
62
+ config[:device_comments].each do |k, v|
63
+ d = plc.device_by_name(k)
64
+ @comments[d.name] = v if d
65
+ end if config[:device_comments]
66
+ setup
67
+ end
68
+
69
+ def run_cycle plc
70
+ return if disabled?
71
+ return unless config[:events]
72
+
73
+ config[:events].each do |event|
74
+ next unless event[:devices]
75
+ next unless event[:webhook_url]
76
+ begin
77
+
78
+ # gether values
79
+ devices = event[:devices].split(",").map{|e| e.split("-")}.map do |devs|
80
+ devs = devs.map{|d| plc.device_by_name d.strip}
81
+ d1 = devs.first
82
+ d2 = devs.last
83
+ [d2.number - d1.number + 1, 1].max.times.inject([]){|a, i| a << d1; d1 += 1; a}
84
+ end.flatten
85
+
86
+ interval_triggered = false
87
+ now = Time.now
88
+ devices.each do |device|
89
+ triggered = false
90
+ v = nil
91
+ case event[:trigger][:type]
92
+ when "interval"
93
+ t = @times[event.object_id] || now
94
+ triggered = t <= now
95
+ if triggered
96
+ interval_triggered = true
97
+ t += event[:trigger][:interval] || 300
98
+ @times[event.object_id] = t
99
+ end
100
+ v = device.send event[:value_type], event[:trigger][:text_length] || 8
101
+ else
102
+ v = device.send event[:value_type], event[:text_length] || 8
103
+ unless @values[device.name] == v
104
+ @values[device.name] = v
105
+ case event[:trigger][:type]
106
+ when "raise"
107
+ triggered = !!v
108
+ when "fall"
109
+ triggered = !v
110
+ else
111
+ triggered = true
112
+ end
108
113
  end
109
114
  end
115
+
116
+ next unless triggered || interval_triggered
117
+
118
+ @worker_queue.push event:event,
119
+ device_name:device.name,
120
+ value:v,
121
+ time: now
110
122
  end
123
+ rescue => e
124
+ p e
125
+ end
126
+ end
127
+ end
128
+
129
+ private
111
130
 
112
- next unless triggered || interval_triggered
131
+ def setup
132
+ Thread.start {
133
+ thread_proc
134
+ }
135
+ end
113
136
 
114
- @plugin_slack_worker_queue.push event:event,
115
- device_name:device.name,
116
- value:v,
117
- time: now
137
+ def thread_proc
138
+ while arg = @worker_queue.pop
139
+ begin
140
+ event = arg[:event]
141
+ uri = URI.parse(event[:webhook_url])
142
+ http = Net::HTTP.new(uri.host, uri.port)
143
+ http.use_ssl = true
144
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
145
+
146
+ req = Net::HTTP::Post.new(uri.path)
147
+ req["Content-Type"] = "application/json"
148
+
149
+ format = event[:format] || "__comment__ occured at __time__"
150
+ format = arg[:value] ? format[:raise] : format[:fall] unless format.is_a? String
151
+
152
+ device_name = arg[:device_name]
153
+ comment = @comments[device_name] || device_name
154
+ value = arg[:value].to_s
155
+ time = arg[:time].iso8601
156
+
157
+ payload = {text:format.gsub(/__device_comment__/, comment).gsub(/__value__/, value).gsub(/__time__/, time).gsub(/__device_name__/, device_name)
158
+ }
159
+ req.body = payload.to_json
160
+
161
+ http.request(req)
162
+ rescue => e
163
+ # TODO: Resend if it fails.
164
+ p e
165
+ end
118
166
  end
119
- rescue => e
120
- p e
121
167
  end
122
- end if @plugin_slack_config[:events]
168
+
123
169
  end
124
170
 
125
- def plugin_slack_worker_loop
126
- while arg = @plugin_slack_worker_queue.pop
127
- begin
128
- event = arg[:event]
129
- uri = URI.parse(event[:webhook_url])
130
- http = Net::HTTP.new(uri.host, uri.port)
131
- http.use_ssl = true
132
- http.verify_mode = OpenSSL::SSL::VERIFY_NONE
133
-
134
- req = Net::HTTP::Post.new(uri.path)
135
- req["Content-Type"] = "application/json"
136
-
137
- format = event[:format] || "__comment__ occured at __time__"
138
- format = arg[:value] ? format[:raise] : format[:fall] unless format.is_a? String
139
-
140
- device_name = arg[:device_name]
141
- comment = @plugin_slack_comments[device_name] || device_name
142
- value = arg[:value].to_s
143
- time = arg[:time].iso8601
144
-
145
- payload = {text:format.gsub(/__device_comment__/, comment).gsub(/__value__/, value).gsub(/__time__/, time).gsub(/__device_name__/, device_name)
146
- }
147
- req.body = payload.to_json
148
-
149
- http.request(req)
150
- rescue => e
151
- # TODO: Resend if it fails.
152
- p e
153
- end
154
- end
171
+ end
172
+ end
173
+
174
+
175
+ def plugin_slack_init plc
176
+ @slack_plugin = LadderDrive::Emulator::SlackPlugin.new plc
177
+ end
178
+
179
+ def plugin_slack_exec plc
180
+ @slack_plugin.run_cycle plc
155
181
  end
@@ -52,105 +52,122 @@ require 'trello'
52
52
 
53
53
  # @see https://qiita.com/tbpgr/items/60fc13aca8afd153e37b
54
54
 
55
- =begin
56
- Dotenv.load
57
55
 
58
- b = Trello::Board.all.find{|b| b.name == "工程モニター"}
59
- pp b.lists.map{|l| {id:l.id, name:l.name, cards:l.cards.map{|c| {id:c.id, name:c.name}}}}
60
- =end
56
+ module LadderDrive
57
+ module Emulator
61
58
 
59
+ class TrelloPlugin < Plugin
62
60
 
63
- def plugin_trello_init plc
64
- @plugin_trello_config = load_plugin_config 'trello'
61
+ def initialize plc
62
+ super #plc
63
+ return if disabled?
65
64
 
66
- @plugin_trello_values = {}
67
- @plugin_trello_times = {}
68
- @plugin_trello_worker_queue = Queue.new
65
+ @values = {}
66
+ @times = {}
67
+ @worker_queue = Queue.new
69
68
 
70
- @plugin_trello_configured = Trello.configure do |config|
71
- config.consumer_key = @plugin_trello_config[:consumer_key]
72
- config.consumer_secret = @plugin_trello_config[:consumer_secret]
73
- config.oauth_token = @plugin_trello_config[:oauth_token]
69
+ @configured = Trello.configure do |config|
70
+ config.consumer_key = self.config[:consumer_key]
71
+ config.consumer_secret = self.config[:consumer_secret]
72
+ config.oauth_token = self.config[:oauth_token]
73
+ end
74
+ setup
74
75
  end
75
76
 
76
- Thread.start {
77
- plugin_trello_worker_loop
78
- }
79
- end
77
+ def run_cycle plc
78
+ return if disabled?
79
+ return if config[:events].nil?
80
80
 
81
- def plugin_trello_exec plc
82
- return if @plugin_trello_config[:disable]
83
- # return unless @plugin_trello_configured
84
-
85
- @plugin_trello_config[:events].each do |event|
86
- begin
87
-
88
- triggered = false
89
- now = Time.now
90
- device = nil
91
-
92
- case event[:trigger][:type]
93
- when "interval"
94
- t = @plugin_trello_times[event.object_id] || now
95
- triggered = t <= now
96
- if triggered
97
- interval_triggered = true
98
- t += event[:trigger][:interval] || 300
99
- @plugin_trello_times[event.object_id] = t
100
- end
101
- else
102
- device = plc.device_by_name event[:trigger][:device]
103
- v = device.send event[:trigger][:value_type], event[:trigger][:text_length] || 8
104
- unless @plugin_trello_values[device.name] == v
105
- @plugin_trello_values[device.name] = v
106
- case event[:trigger][:type]
107
- when "raise"
108
- triggered = !!v
109
- when "fall"
110
- triggered = !v
111
- else
81
+ @config[:events].each do |event|
82
+ begin
83
+
84
+ triggered = false
85
+ now = Time.now
86
+ device = nil
87
+
88
+ case event[:trigger][:type]
89
+ when "interval"
90
+ t = @times[event.object_id] || now
91
+ triggered = t <= now
92
+ if triggered
112
93
  triggered = true
94
+ t += event[:trigger][:interval] || 300
95
+ @times[event.object_id] = t
96
+ end
97
+ else
98
+ device = plc.device_by_name event[:trigger][:device]
99
+ v = device.send event[:trigger][:value_type], event[:trigger][:text_length] || 8
100
+ unless @values[device.name] == v
101
+ @values[device.name] = v
102
+ case event[:trigger][:type]
103
+ when "raise"
104
+ triggered = !!v
105
+ when "fall"
106
+ triggered = !v
107
+ else
108
+ triggered = true
109
+ end
113
110
  end
114
111
  end
115
- end
116
112
 
117
- next unless triggered
113
+ next unless triggered
118
114
 
119
- @plugin_trello_worker_queue.push event:event, device_name:device.name, value:v, time: now
115
+ @worker_queue.push event:event, device_name:device.name, value:v, time: now
120
116
 
121
- rescue => e
122
- p e
117
+ rescue => e
118
+ p e
119
+ end
123
120
  end
124
- end if @plugin_trello_config[:events]
125
- end
121
+ end
122
+
123
+ private
126
124
 
127
- def plugin_trello_worker_loop
128
- while arg = @plugin_trello_worker_queue.pop
129
- begin
130
- event = arg[:event]
125
+ def setup
126
+ Thread.start {
127
+ thread_proc
128
+ }
129
+ end
131
130
 
132
- board = Trello::Board.all.find{|b| b.name == event[:board_name]}
133
- next unless board
131
+ def thread_proc
132
+ while arg = @worker_queue.pop
133
+ begin
134
+ event = arg[:event]
134
135
 
135
- card_name = event[:card_name].dup || ""
136
- card_name.gsub!(/__value__/, arg[:value] || "")
137
- next if (card_name || "").empty?
136
+ board = Trello::Board.all.find{|b| b.name == event[:board_name]}
137
+ next unless board
138
138
 
139
- list_name = event[:list_name]
140
- next unless list_name
141
- list = board.lists.find{|l| l.name == list_name}
142
- next unless list
139
+ card_name = event[:card_name].dup || ""
140
+ card_name.gsub!(/__value__/, arg[:value] || "")
141
+ next if (card_name || "").empty?
143
142
 
144
- card = board.lists.map{|l| l.cards.map{|c| c}}.flatten.find{|c| c.name == card_name}
145
- if card
146
- card.move_to_list list
147
- else
148
- card = Trello::Card.create name:card_name, list_id:list.id
149
- end
143
+ list_name = event[:list_name]
144
+ next unless list_name
145
+ list = board.lists.find{|l| l.name == list_name}
146
+ next unless list
150
147
 
151
- rescue => e
152
- # TODO: Resend if it fails.
153
- p e
148
+ card = board.lists.map{|l| l.cards.map{|c| c}}.flatten.find{|c| c.name == card_name}
149
+ if card
150
+ card.move_to_list list
151
+ else
152
+ card = Trello::Card.create name:card_name, list_id:list.id
153
+ end
154
+
155
+ rescue => e
156
+ # TODO: Resend if it fails.
157
+ p e
158
+ end
159
+ end
154
160
  end
155
- end
161
+
162
+ end
163
+
164
+ end
165
+ end
166
+
167
+ def plugin_trello_init plc
168
+ @trello_plugin = LadderDrive::Emulator::TrelloPlugin.new plc
169
+ end
170
+
171
+ def plugin_trello_exec plc
172
+ @trello_plugin.run_cycle plc
156
173
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ladder_drive
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.0
4
+ version: 0.6.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Katsuyoshi Ito
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2018-11-29 00:00:00.000000000 Z
11
+ date: 2019-04-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: thor
@@ -48,42 +48,56 @@ dependencies:
48
48
  name: ffi
49
49
  requirement: !ruby/object:Gem::Requirement
50
50
  requirements:
51
- - - "~>"
51
+ - - ">="
52
52
  - !ruby/object:Gem::Version
53
53
  version: 1.9.24
54
- - - ">="
54
+ - - "~>"
55
55
  - !ruby/object:Gem::Version
56
56
  version: 1.9.24
57
57
  type: :runtime
58
58
  prerelease: false
59
59
  version_requirements: !ruby/object:Gem::Requirement
60
60
  requirements:
61
- - - "~>"
61
+ - - ">="
62
62
  - !ruby/object:Gem::Version
63
63
  version: 1.9.24
64
- - - ">="
64
+ - - "~>"
65
65
  - !ruby/object:Gem::Version
66
66
  version: 1.9.24
67
67
  - !ruby/object:Gem::Dependency
68
68
  name: pi_piper
69
69
  requirement: !ruby/object:Gem::Requirement
70
70
  requirements:
71
- - - "~>"
72
- - !ruby/object:Gem::Version
73
- version: '2.0'
74
71
  - - ">="
75
72
  - !ruby/object:Gem::Version
76
73
  version: 2.0.0
74
+ - - "~>"
75
+ - !ruby/object:Gem::Version
76
+ version: '2.0'
77
77
  type: :runtime
78
78
  prerelease: false
79
79
  version_requirements: !ruby/object:Gem::Requirement
80
80
  requirements:
81
+ - - ">="
82
+ - !ruby/object:Gem::Version
83
+ version: 2.0.0
81
84
  - - "~>"
82
85
  - !ruby/object:Gem::Version
83
86
  version: '2.0'
87
+ - !ruby/object:Gem::Dependency
88
+ name: serialport
89
+ requirement: !ruby/object:Gem::Requirement
90
+ requirements:
84
91
  - - ">="
85
92
  - !ruby/object:Gem::Version
86
- version: 2.0.0
93
+ version: '0'
94
+ type: :runtime
95
+ prerelease: false
96
+ version_requirements: !ruby/object:Gem::Requirement
97
+ requirements:
98
+ - - ">="
99
+ - !ruby/object:Gem::Version
100
+ version: '0'
87
101
  - !ruby/object:Gem::Dependency
88
102
  name: bundler
89
103
  requirement: !ruby/object:Gem::Requirement
@@ -224,8 +238,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
224
238
  - !ruby/object:Gem::Version
225
239
  version: '0'
226
240
  requirements: []
227
- rubyforge_project:
228
- rubygems_version: 2.7.7
241
+ rubygems_version: 3.0.1
229
242
  signing_key:
230
243
  specification_version: 4
231
244
  summary: The ladder_drive is a simple abstract ladder for PLC (Programmable Logic