ladder_drive 0.5.2 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,155 @@
1
+ #
2
+ # Copyright (c) 2018 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/slack.yml
26
+
27
+ device_comments:
28
+ - M0: エラー0
29
+ - M1: エラー1
30
+ - M2: エラー2
31
+ - M10: エラー10
32
+
33
+ events:
34
+ - webhook_url: your_web_hook_url
35
+ trigger:
36
+ type: raise_and_fall
37
+ value_type: bool
38
+ format:
39
+ raise: __device_comment__ が発生しました。
40
+ fall: __device_comment__ が解除になりました。
41
+ devices: M0-M2,M10
42
+ DOC
43
+
44
+ require 'net/https'
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
+
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
108
+ end
109
+ end
110
+ end
111
+
112
+ next unless triggered || interval_triggered
113
+
114
+ @plugin_slack_worker_queue.push event:event,
115
+ device_name:device.name,
116
+ value:v,
117
+ time: now
118
+ end
119
+ rescue => e
120
+ p e
121
+ end
122
+ end if @plugin_slack_config[:events]
123
+ end
124
+
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
155
+ end
@@ -0,0 +1,156 @@
1
+ #
2
+ # Copyright (c) 2018 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/trello.yml
26
+
27
+ consummer_key: your_consumer_key
28
+ consumer_secret: your_consumer_secret
29
+ oauth_token: your_oauth_token
30
+
31
+ events:
32
+ - trigger:
33
+ device: D0
34
+ type: changed
35
+ value_type: text
36
+ text_length: 8
37
+ board_name: 工程モニター
38
+ list_name: 工程1
39
+ title: __value__
40
+ - trigger:
41
+ device: D10
42
+ type: changed
43
+ value_type: text
44
+ text_length: 8
45
+ board_name: 工程モニター
46
+ list_name: 工程2
47
+ title: __value__
48
+ DOC
49
+
50
+ require 'net/https'
51
+ require 'trello'
52
+
53
+ # @see https://qiita.com/tbpgr/items/60fc13aca8afd153e37b
54
+
55
+ =begin
56
+ Dotenv.load
57
+
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
61
+
62
+
63
+ def plugin_trello_init plc
64
+ @plugin_trello_config = load_plugin_config 'trello'
65
+
66
+ @plugin_trello_values = {}
67
+ @plugin_trello_times = {}
68
+ @plugin_trello_worker_queue = Queue.new
69
+
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]
74
+ end
75
+
76
+ Thread.start {
77
+ plugin_trello_worker_loop
78
+ }
79
+ end
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
112
+ triggered = true
113
+ end
114
+ end
115
+ end
116
+
117
+ next unless triggered
118
+
119
+ @plugin_trello_worker_queue.push event:event, device_name:device.name, value:v, time: now
120
+
121
+ rescue => e
122
+ p e
123
+ end
124
+ end if @plugin_trello_config[:events]
125
+ end
126
+
127
+ def plugin_trello_worker_loop
128
+ while arg = @plugin_trello_worker_queue.pop
129
+ begin
130
+ event = arg[:event]
131
+
132
+ board = Trello::Board.all.find{|b| b.name == event[:board_name]}
133
+ next unless board
134
+
135
+ card_name = event[:card_name].dup || ""
136
+ card_name.gsub!(/__value__/, arg[:value] || "")
137
+ next if (card_name || "").empty?
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
143
+
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
150
+
151
+ rescue => e
152
+ # TODO: Resend if it fails.
153
+ p e
154
+ end
155
+ end
156
+ 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.5.2
4
+ version: 0.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Katsuyoshi Ito
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2017-10-24 00:00:00.000000000 Z
11
+ date: 2018-11-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: thor
@@ -44,20 +44,46 @@ dependencies:
44
44
  - - ">="
45
45
  - !ruby/object:Gem::Version
46
46
  version: 4.2.7
47
+ - !ruby/object:Gem::Dependency
48
+ name: ffi
49
+ requirement: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - "~>"
52
+ - !ruby/object:Gem::Version
53
+ version: 1.9.24
54
+ - - ">="
55
+ - !ruby/object:Gem::Version
56
+ version: 1.9.24
57
+ type: :runtime
58
+ prerelease: false
59
+ version_requirements: !ruby/object:Gem::Requirement
60
+ requirements:
61
+ - - "~>"
62
+ - !ruby/object:Gem::Version
63
+ version: 1.9.24
64
+ - - ">="
65
+ - !ruby/object:Gem::Version
66
+ version: 1.9.24
47
67
  - !ruby/object:Gem::Dependency
48
68
  name: pi_piper
49
69
  requirement: !ruby/object:Gem::Requirement
50
70
  requirements:
71
+ - - "~>"
72
+ - !ruby/object:Gem::Version
73
+ version: '2.0'
51
74
  - - ">="
52
75
  - !ruby/object:Gem::Version
53
- version: '0'
76
+ version: 2.0.0
54
77
  type: :runtime
55
78
  prerelease: false
56
79
  version_requirements: !ruby/object:Gem::Requirement
57
80
  requirements:
81
+ - - "~>"
82
+ - !ruby/object:Gem::Version
83
+ version: '2.0'
58
84
  - - ">="
59
85
  - !ruby/object:Gem::Version
60
- version: '0'
86
+ version: 2.0.0
61
87
  - !ruby/object:Gem::Dependency
62
88
  name: bundler
63
89
  requirement: !ruby/object:Gem::Requirement
@@ -105,6 +131,7 @@ files:
105
131
  - Rakefile
106
132
  - bin/console
107
133
  - bin/setup
134
+ - doc/jp/raspberrypi.md
108
135
  - exe/ladder_drive
109
136
  - ladder_drive.gemspec
110
137
  - lib/ladder_drive.rb
@@ -122,6 +149,8 @@ files:
122
149
  - lib/ladder_drive/protocol/keyence/keyence.rb
123
150
  - lib/ladder_drive/protocol/keyence/kv_device.rb
124
151
  - lib/ladder_drive/protocol/keyence/kv_protocol.rb
152
+ - lib/ladder_drive/protocol/mitsubishi/fx_device.rb
153
+ - lib/ladder_drive/protocol/mitsubishi/fx_protocol.rb
125
154
  - lib/ladder_drive/protocol/mitsubishi/mc_protocol.rb
126
155
  - lib/ladder_drive/protocol/mitsubishi/mitsubishi.rb
127
156
  - lib/ladder_drive/protocol/mitsubishi/qdevice.rb
@@ -134,6 +163,7 @@ files:
134
163
  - lib/plc/emulator/emu_plc.rb
135
164
  - lib/plc/emulator/emu_plc_server.rb
136
165
  - lib/plc/emulator/emulator.rb
166
+ - lib/plc/emulator/plc_plugins.rb
137
167
  - lib/plc/keyence/kv/kv-5000/DocumentWindowInfo.xml
138
168
  - lib/plc/keyence/kv/kv-5000/KvsMon.ini
139
169
  - lib/plc/keyence/kv/kv-5000/LadderDrive.mod
@@ -160,6 +190,12 @@ files:
160
190
  - lib/plc/raspberrypi/raspberrypi.rb
161
191
  - lib/plc/raspberrypi/raspberrypi_plc.rb
162
192
  - lib/plc/raspberrypi/raspberrypi_plc_server.rb
193
+ - plugins/blank_plugin.rb
194
+ - plugins/google_drive_plugin.rb
195
+ - plugins/ifttt_plugin.rb
196
+ - plugins/plc_mapper_plugin.rb
197
+ - plugins/slack_plugin.rb
198
+ - plugins/trello_plugin.rb
163
199
  - sample/ladder_drive/sample1.esc
164
200
  - sample/ladder_drive/sample2.esc
165
201
  - sample/ladder_drive/sample2.png
@@ -189,7 +225,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
189
225
  version: '0'
190
226
  requirements: []
191
227
  rubyforge_project:
192
- rubygems_version: 2.5.1
228
+ rubygems_version: 2.7.7
193
229
  signing_key:
194
230
  specification_version: 4
195
231
  summary: The ladder_drive is a simple abstract ladder for PLC (Programmable Logic