ladder_drive 0.6.3 → 0.6.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (36) hide show
  1. checksums.yaml +5 -5
  2. data/Gemfile +7 -2
  3. data/Gemfile.lock +107 -62
  4. data/README.md +1 -0
  5. data/README_jp.md +2 -2
  6. data/ladder_drive.gemspec +12 -8
  7. data/lib/ladder_drive/cli.rb +16 -4
  8. data/lib/ladder_drive/config.rb +4 -1
  9. data/lib/ladder_drive/config_target.rb +1 -0
  10. data/lib/ladder_drive/plc_device.rb +11 -0
  11. data/lib/ladder_drive/protocol/keyence/kv_protocol.rb +1 -11
  12. data/lib/ladder_drive/protocol/mitsubishi/fx_protocol.rb +0 -11
  13. data/lib/ladder_drive/protocol/mitsubishi/mc_protocol.rb +1 -11
  14. data/lib/ladder_drive/protocol/omron/c_mode_protocol.rb +224 -0
  15. data/lib/ladder_drive/protocol/omron/fins_tcp_protocol.rb +380 -0
  16. data/lib/ladder_drive/protocol/omron/omron.rb +28 -0
  17. data/lib/ladder_drive/protocol/omron/omron_device.rb +139 -0
  18. data/lib/ladder_drive/protocol/protocol.rb +16 -5
  19. data/lib/ladder_drive/tasks/build.rb +1 -1
  20. data/lib/ladder_drive/version.rb +1 -1
  21. data/lib/ladder_drive.rb +3 -0
  22. data/lib/plc/emulator/emu_plc_server.rb +3 -1
  23. data/lib/plc/emulator/plc_plugins.rb +20 -13
  24. data/lib/plc/emulator/plugin_trigger_state.rb +152 -0
  25. data/plugins/ambient_plugin.rb +155 -0
  26. data/plugins/config/ambient.yaml.example +34 -0
  27. data/plugins/config/google_drive.yaml.example +39 -0
  28. data/plugins/config/ifttt.yaml.example +24 -0
  29. data/plugins/config/plc_mapper.yaml.example +36 -0
  30. data/plugins/config/slack.yaml.example +36 -0
  31. data/plugins/config/trello.yaml.example +41 -0
  32. data/plugins/ifttt_plugin.rb +4 -27
  33. data/plugins/plc_mapper_plugin.rb +27 -15
  34. data/plugins/slack_plugin.rb +14 -3
  35. data/plugins/trello_plugin.rb +30 -42
  36. metadata +72 -15
@@ -0,0 +1,155 @@
1
+ #
2
+ # Copyright (c) 2019 ITO SOFT DESIGN Inc.
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining
5
+ # a copy of this software and associated documentation files (the
6
+ # "Software"), to deal in the Software without restriction, including
7
+ # without limitation the rights to use, copy, modify, merge, publish,
8
+ # distribute, sublicense, and/or sell copies of the Software, and to
9
+ # permit persons to whom the Software is furnished to do so, subject to
10
+ # the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be
13
+ # included in all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
+
23
+ <<-DOC
24
+ Here is a sample configuration.
25
+ Puts your configuration to config/plugins/ambient.yml
26
+
27
+ channels:
28
+ - channel_id: 12345
29
+ write_key: your_write_key
30
+ trigger:
31
+ device: M100
32
+ type: raise_and_fall
33
+ value_type: bool
34
+ devices:
35
+ d1:
36
+ device: D30
37
+ value_type: value
38
+ d2:
39
+ device: D17
40
+ value_type: value
41
+ d3:
42
+ device: D11
43
+ value_type: value
44
+ d4:
45
+ device: D22
46
+ value_type: value
47
+ d5:
48
+ device: D25
49
+ value_type: value
50
+ - channel_id: 12345
51
+ write_key: your_write_key
52
+ type: interval
53
+ interval: 60
54
+ devices:
55
+ d1:
56
+ device: D30
57
+ value_type: value
58
+ d2:
59
+ device: D17
60
+ value_type: value
61
+ d3:
62
+ device: D11
63
+ value_type: value
64
+ d4:
65
+ device: D22
66
+ value_type: value
67
+ d5:
68
+ device: D25
69
+ value_type: value
70
+ DOC
71
+
72
+ require 'ambient_iot'
73
+
74
+
75
+ module LadderDrive
76
+ module Emulator
77
+
78
+ class AmbientPlugin < Plugin
79
+
80
+ def initialize plc
81
+ super #plc
82
+ return if disabled?
83
+
84
+ @values = {}
85
+ @worker_queue = Queue.new
86
+
87
+ setup
88
+ end
89
+
90
+ def run_cycle plc
91
+ return if disabled?
92
+ return unless config[:channels]
93
+
94
+ config[:channels].each do |channel|
95
+ next unless channel[:channel_id]
96
+ next unless channel[:write_key]
97
+ begin
98
+ next unless self.triggered?(channel)
99
+
100
+ # gether values
101
+ values = channel[:devices].inject({}) do |h, pair|
102
+ d = plc.device_by_name pair.last[:device]
103
+ v = d.send pair.last[:value_type], pair.last[:text_length] || 8
104
+ h[pair.first] = v
105
+ h
106
+ end
107
+
108
+ @worker_queue.push channel:channel, values:values
109
+ rescue => e
110
+ p e
111
+ end
112
+ end
113
+ end
114
+
115
+ private
116
+
117
+ def setup
118
+ Thread.start {
119
+ thread_proc
120
+ }
121
+ end
122
+
123
+ def thread_proc
124
+ @uploaded_at = nil
125
+
126
+ while arg = @worker_queue.pop
127
+ begin
128
+ now = Time.now
129
+ # ignore a request if it's requested in a 5 sec from previous request.
130
+ next unless @uploaded_at.nil? || (now - @uploaded_at >= 5)
131
+
132
+ channel = arg[:channel]
133
+ client = AmbientIot::Client.new channel[:channel_id], write_key:channel[:write_key]
134
+ client << arg[:values]
135
+ client.sync
136
+ @uploaded_at = now
137
+ rescue => e
138
+ p e
139
+ end
140
+ end
141
+ end
142
+
143
+ end
144
+
145
+ end
146
+ end
147
+
148
+
149
+ def plugin_ambient_init plc
150
+ @ambient_plugin = LadderDrive::Emulator::AmbientPlugin.new plc
151
+ end
152
+
153
+ def plugin_ambient_exec plc
154
+ @ambient_plugin.run_cycle plc
155
+ end
@@ -0,0 +1,34 @@
1
+ # This is a sample setting for ambient plugin
2
+ # Copy this file to ambient.yaml or rename.
3
+
4
+ # If you want to disable this plugin, uncomment it.
5
+ #disable: true
6
+
7
+ # Configure ambient channels
8
+ # Set the Ambient channel, which is to send data you want to.
9
+ channels:
10
+
11
+ # set ambient configuration.
12
+ # We recommend setting write_key from an environment variable.
13
+ - channel_id: 12824
14
+ write_key: <%= ENV['AMBIENT_WRITE_KEY'] %>
15
+
16
+ # Set trigger conditions
17
+ # You can use type raise, fall, raise_and_fall, changed, and interval.
18
+ triggers:
19
+ - type: raise_and_fall
20
+ device: M100
21
+ - type: interval
22
+ interval: 60
23
+
24
+ # Set data to send, if triggered.
25
+ devices:
26
+ d1:
27
+ device: D10
28
+ value_type: value
29
+ d2:
30
+ device: D11
31
+ value_type: value
32
+ d3:
33
+ device: D12
34
+ value_type: value
@@ -0,0 +1,39 @@
1
+ # This is a sample setting for google drive plugin
2
+ # Copy this file to google_drive.yaml or rename.
3
+
4
+ # If you want to disable this plugin, uncomment it.
5
+ #disable: true
6
+
7
+ # Api configuration.
8
+ client_id: <%= ENV['GOOGLE_CLIENT_ID'] %>
9
+ client_secret: <%= ENV['GOOGLE_CLIENT_SECRET'] %>
10
+ access_token: <%= ENV['GOOGLE_ACCESS_TOKEN'] %>
11
+ refresh_token: <%= ENV['GOOGLE_REFRESH_TOKEN'] %>
12
+
13
+ # Logging setting
14
+ loggings:
15
+ - name: temperature
16
+
17
+ # Set trigger conditions
18
+ # You can use type raise, fall, raise_and_fall, changed, and interval.
19
+ trigger:
20
+ device: M0
21
+ type: raise_and_fall
22
+ value_type: bool
23
+
24
+ # Column header
25
+ columns: D0,D1,D2,D3,D4,D5,D6,D7,D8,D9,D20,M0
26
+
27
+ # Devices for logging
28
+ devices:
29
+ - device: D0-D9
30
+ type: value
31
+ - device: D20
32
+ type: value
33
+ - device: M0
34
+ type: bool
35
+
36
+ # Spreadsheet to access
37
+ spread_sheet:
38
+ spread_sheet_key: <%= ENV['GOOGLE_SPREADSHEET_KEY'] %>
39
+ sheet_no: 0
@@ -0,0 +1,24 @@
1
+ # This is a sample setting for ifttt plugin
2
+ # Copy this file to ifttt.yaml or rename.
3
+
4
+ # If you want to disable this plugin, uncomment it.
5
+ #disable: true
6
+
7
+ # Set webhook key of Webhooks service for IFTTT.
8
+ # To see your webhook key, to open https://ifttt.com/maker_webhook
9
+ # and click the Documentation link.
10
+ # We recommend setting web_hook_key from an environment variable.
11
+ web_hook_key: <%= ENV['IFTTT_WEBHOOK_KEY'] %>
12
+
13
+ # Set trigger event of webhook.
14
+ # Set event name to name attribute.
15
+ # Pass values to the params to display information.
16
+ events:
17
+ - name: rubyworldconference2019
18
+ trigger:
19
+ type: raise
20
+ device: M100
21
+ params:
22
+ value1: Abnormal temperature
23
+ value2: Something additional information.
24
+ value3: and more.
@@ -0,0 +1,36 @@
1
+ # This is a sample setting for Plc mapper plugin
2
+ # Copy this file to plc_mapper.yaml or rename.
3
+
4
+ # If you want to disable this plugin, uncomment it.
5
+ #disable: true
6
+
7
+ # This is a sample setting for Plc mapper plugin
8
+ plcs:
9
+ - description: Machine A-123
10
+
11
+ # Set connection conditions between PLC
12
+ protocol: mc_protocol
13
+ host: 192.168.1.10
14
+ port: 5010
15
+ interval: 10
16
+
17
+ # Set address mapping.
18
+ mapping:
19
+
20
+ # Read from PLC to set Ladder drive.
21
+ # plc: PLC address area
22
+ # ld: Ladder drive area
23
+ read:
24
+ - plc: M1000-M1099
25
+ ld: M0
26
+ - plc: D1000-D1099
27
+ ld: D0
28
+ # Read from Ladder drive to set PLC.
29
+ # plc: PLC address area
30
+ # ld: Ladder drive area
31
+ write:
32
+ # LadderDrive address: PLC address
33
+ - plc: M100-M199
34
+ ld: M1100
35
+ - plc: D100-D199
36
+ ld: D1100
@@ -0,0 +1,36 @@
1
+ # This is a sample setting for Slack plugin
2
+ # Copy this file to slack.yaml or rename.
3
+
4
+ # If you want to disable this plugin, uncomment it.
5
+ #disable: true
6
+
7
+ # Define comment for a device
8
+ device_comments:
9
+ M210: Full error
10
+ D10: Running
11
+
12
+ # Event setting
13
+ events:
14
+
15
+ # Set webhook url for IFTTT.
16
+ # We recommend setting web_hook_key from an environment variable.
17
+ - webhook_url: <%= ENV['SLACK_WEBHOOK_NOTIFICATION_URL'] %>
18
+
19
+ # Set trigger conditions
20
+ # You can use type raise, fall, raise_and_fall, changed, and interval.
21
+ trigger:
22
+ type: raise_and_fall
23
+
24
+ # String format to send Slack.
25
+ format:
26
+ raise: __device_comment__ has occurred at __time__ .
27
+ fall: __device_comment__ was reset at __time__ .
28
+ devices: M210
29
+
30
+ - webhook_url: <%= ENV['SLACK_WEBHOOK_URL'] %>
31
+ trigger:
32
+ type: raise_and_fall
33
+ format:
34
+ raise: Start __device_comment__ at __time__ .
35
+ fall: Stop __device_comment__ at __time__ .
36
+ devices: M100
@@ -0,0 +1,41 @@
1
+ # This is a sample setting for Trello plugin
2
+ # Copy this file to trello.yaml or rename.
3
+
4
+ # If you want to disable this plugin, uncomment it.
5
+ #disable: true
6
+
7
+ # Connection configuration.
8
+ consumer_key: <%= ENV['TRELLO_CONSUMER_KEY'] %>
9
+ consumer_secret: <%= ENV['TRELLO_CONSUMMER_SECRET'] %>
10
+ oauth_token: <%= ENV['TRELLO_OAUTH_TOKEN'] %>
11
+
12
+ events:
13
+
14
+ # Set trigger conditions
15
+ # You can use type raise, fall, raise_and_fall, changed, and interval.
16
+ - trigger:
17
+ device: M100
18
+ type: raise
19
+
20
+ # Board name
21
+ board_name: Floor 1
22
+ # List name.
23
+ # If you set it, move the card into this list.
24
+ list_name: RUNNING
25
+ # Card name.
26
+ card_name: Machine A
27
+
28
+ # color label
29
+ color:
30
+ # Add color label
31
+ add: green
32
+
33
+ - trigger:
34
+ device: M100
35
+ type: fall
36
+ board_name: Floor 1
37
+ list_name: STOPPING
38
+ card_name: Machine A
39
+ color:
40
+ # Remove color label
41
+ remove: green
@@ -76,36 +76,13 @@ class IftttPlugin < Plugin
76
76
  return if disabled?
77
77
  config[:events].each do |event|
78
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
102
- end
103
- end
104
-
105
- next unless triggered
79
+ next unless self.triggered?(event)
106
80
 
81
+ v = trigger_state_for(event).value
107
82
  @worker_queue.push event:event[:name], payload:event[:params].dup || {}, value:v
108
83
  rescue => e
84
+ puts $!
85
+ puts $@
109
86
  p e
110
87
  end
111
88
  end if config[:events]
@@ -63,18 +63,19 @@ class PlcMapperPlugin < Plugin
63
63
 
64
64
  def run_cycle plc
65
65
  return if disabled?
66
- return false unless super
66
+ #return false unless super
67
67
  @lock.synchronize {
68
68
  # set values from plcs to ladder drive.
69
- values_for_reading.each do |d, v|
69
+ self.values_for_reading.each do |d, v|
70
70
  plc.device_by_name(d).value = v
71
71
  end
72
- values_for_reading.clear
72
+ self.values_for_reading.clear
73
73
 
74
74
  # set values from ladder drive to values_for_writing.
75
75
  # then set it to plc at #sync_with_plc
76
- values_for_writing.each do |d, v|
77
- values_for_writing[d] = plc.device_by_name(d).value
76
+ self.values_for_writing.each do |d, v|
77
+ dev = plc.device_by_name(d)
78
+ self.values_for_writing[d] = dev.bit_device? ? dev.bool : dev.value
78
79
  end
79
80
  }
80
81
  end
@@ -110,7 +111,7 @@ class PlcMapperPlugin < Plugin
110
111
  d1 = devs.first
111
112
  d2 = devs.last
112
113
  a << k
113
- a << [d1, [d2.number - d1.number + 1, 1].max]
114
+ a << [d1, [d2 - d1 + 1, 1].max]
114
115
  end
115
116
  Hash[*a]
116
117
  end
@@ -137,11 +138,14 @@ class PlcMapperPlugin < Plugin
137
138
  sync_with_plc protocol, read_mappings, write_mappings
138
139
  next_time += interval
139
140
  end
140
- sleep next_time - Time.now
141
+ sleep [next_time - Time.now, 0].max
141
142
  alerted = false
142
- rescue
143
- puts "#{config[:description]} is not reachable." unless alerted
143
+ rescue => e
144
+ puts "#{config[:description]} is not reachable. #{e}" unless alerted
145
+ puts $!
146
+ puts $@
144
147
  alerted = true
148
+ protocol.close
145
149
  end
146
150
  end
147
151
  end
@@ -160,7 +164,7 @@ class PlcMapperPlugin < Plugin
160
164
  }
161
165
  end
162
166
 
163
- # set values form ladder drive (values_for_writing) to plc
167
+ # set values from ladder drive (values_for_writing) to plc
164
168
  # values_for_writing was set at run_cycle
165
169
  # but for the first time, it's not known what device it should take.
166
170
  # after running below, devices for need is listed to values_for_writing.
@@ -169,10 +173,12 @@ class PlcMapperPlugin < Plugin
169
173
  src_d = plc.device_by_name mapping[:ld].first.name
170
174
  values = []
171
175
  lock.synchronize {
172
- # It may not get the value for the first time, set zero instead of it.
173
- values_for_writing[src_d.name] ||= 0
174
- values << values_for_writing[src_d.name]
175
- src_d = src_d.next_device
176
+ c.times do
177
+ # It may not get the value for the first time, set zero instead of it.
178
+ self.values_for_writing[src_d.name] ||= (src_d.bit_device? ? false : 0)
179
+ values << self.values_for_writing[src_d.name]
180
+ src_d = src_d.next_device
181
+ end
176
182
  }
177
183
  protocol[dst_d.name, c] = values
178
184
  end
@@ -189,5 +195,11 @@ def plugin_plc_mapper_init plc
189
195
  end
190
196
 
191
197
  def plugin_plc_mapper_exec plc
192
- @plugin_plc_mapper.run_cycle plc
198
+ begin
199
+ @plugin_plc_mapper.run_cycle plc
200
+ rescue
201
+ puts $!
202
+ puts $@
203
+ plc.close
204
+ end
193
205
  end