ladder_drive 0.6.3 → 0.6.7

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.
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