ladder_drive 0.5.2 → 0.6.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.
@@ -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