ladder_drive 0.6.4 → 0.6.8

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.
@@ -52,9 +52,11 @@ module Emulator
52
52
  Thread.new do
53
53
  server = TCPServer.open @port
54
54
  puts "launching emulator ... "
55
+ launched = false
55
56
  loop do
56
57
  Thread.start(server.accept) do |socket|
57
- puts "done launching"
58
+ puts "done launching" unless launched
59
+ launched ||= true
58
60
  while line = socket.gets
59
61
  begin
60
62
  r = @plc.execute_console_commands line
@@ -1,5 +1,5 @@
1
1
  #
2
- # Copyright (c) 2018 ITO SOFT DESIGN Inc.
2
+ # Copyright (c) 201 ITO SOFT DESIGN Inc.
3
3
  #
4
4
  # Permission is hereby granted, free of charge, to any person obtaining
5
5
  # a copy of this software and associated documentation files (the
@@ -25,6 +25,8 @@ $:.unshift dir unless $:.include? dir
25
25
 
26
26
  require 'active_support'
27
27
  require 'active_support/core_ext'
28
+ require 'erb'
29
+ require 'plugin_trigger_state'
28
30
 
29
31
  module PlcPlugins
30
32
 
@@ -110,6 +112,8 @@ class Plugin
110
112
  def initialize plc
111
113
  @config = load_config
112
114
  @plc = plc
115
+ @device_states = {}
116
+ @trigger_states = {}
113
117
  end
114
118
 
115
119
  def name
@@ -124,31 +128,34 @@ class Plugin
124
128
  return false unless self.plc == plc
125
129
  end
126
130
 
131
+ def triggered? trigger_config
132
+ state = trigger_state_for trigger_config
133
+ state.reset
134
+ state.update
135
+ state.triggered?
136
+ end
137
+
138
+ def trigger_state_for trigger_config
139
+ @trigger_states[trigger_config.object_id] ||= PluginTriggerState.new(plc, trigger_config)
140
+ end
141
+
142
+
127
143
  private
128
144
 
129
145
  def load_config
130
146
  h = {}
131
147
  path = File.join("config", "plugins", "#{name}.yml")
132
148
  if File.exist?(path)
133
- h = YAML.load(File.read(path))
149
+ erb = ERB.new File.read(path)
150
+ h = YAML.load(erb.result(binding))
134
151
  h = JSON.parse(h.to_json, symbolize_names: true)
135
152
  end
136
153
  h
137
154
  end
138
155
 
139
- end
140
156
 
141
157
  end
142
- end
143
158
 
144
159
 
145
- # @deprecated use LadderDrive::Emulator::Plugin class instead of this.
146
- def load_plugin_config name
147
- h = {}
148
- path = File.join("config", "plugins", "#{name}.yml")
149
- if File.exist?(path)
150
- h = YAML.load(File.read(path))
151
- h = JSON.parse(h.to_json, symbolize_names: true)
152
- end
153
- h
160
+ end
154
161
  end
@@ -0,0 +1,152 @@
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
+ dir = Dir.pwd
24
+ $:.unshift dir unless $:.include? dir
25
+
26
+ require 'active_support'
27
+ require 'active_support/core_ext'
28
+ require 'erb'
29
+
30
+
31
+ module LadderDrive
32
+ module Emulator
33
+
34
+
35
+ class PluginTriggerState
36
+ attr_reader :plc
37
+ attr_reader :config
38
+ attr_reader :device
39
+ attr_reader :value_type
40
+ attr_reader :value
41
+
42
+ def initialize plc, config
43
+ @plc = plc
44
+ @config = config
45
+ @value_type = config[:value_type]
46
+ @devices = {}
47
+ @next_trigger_times = {}
48
+ end
49
+
50
+ def key
51
+ object_id
52
+ end
53
+
54
+ def value
55
+ @value
56
+ end
57
+
58
+ def value= value
59
+ if @changed.nil?
60
+ @changed = @value != value
61
+ @raised = @changed && !!value
62
+ @fallen = @changed && !value
63
+ @value = value
64
+ end
65
+ end
66
+
67
+ def changed?
68
+ !!@changed
69
+ end
70
+
71
+ def raised?
72
+ !!@raised
73
+ end
74
+
75
+ def fallen?
76
+ !!@fallen
77
+ end
78
+
79
+ def triggered?
80
+ !!@triggered
81
+ end
82
+
83
+ def device
84
+ device_with_trigger(config[:triggers]&.first || config[:trigger])
85
+ end
86
+
87
+ def update
88
+ return unless @triggered.nil?
89
+
90
+ triggers = config[:triggers]
91
+ triggers ||= [config[:trigger]]
92
+
93
+ @triggered = false
94
+
95
+ triggers.each do |trigger|
96
+ case trigger[:type]
97
+ when "changed", "raise", "fall", "raise_and_fall"
98
+ device = device_with_trigger(trigger)
99
+ value = device.send(@value_type || :value)
100
+
101
+ # update flags
102
+ @changed = @value != value
103
+ case value
104
+ when true, false, nil
105
+ @raised = @changed && !!value
106
+ @fallen = @changed && !value
107
+ else
108
+ @fallen = @changed && value == 0
109
+ @raised = @changed && !@fallen
110
+ end
111
+ @value = value
112
+
113
+ # judgement triggered
114
+ case trigger[:type]
115
+ when "raise"
116
+ @triggered = true if @raised
117
+ when "fall"
118
+ @triggered = true if @fallen
119
+ else
120
+ @triggered = true if @changed
121
+ end
122
+
123
+ when "interval"
124
+ now = Time.now
125
+ t = @next_trigger_times[trigger.object_id] || now
126
+ while now >= t
127
+ @triggered ||= true
128
+ t += trigger[:interval]
129
+ end
130
+ @next_trigger_times[trigger.object_id] = t
131
+ else
132
+ @triggered = false
133
+ end
134
+ end
135
+ @triggered
136
+ end
137
+
138
+ def reset
139
+ @changed = nil
140
+ @raised = nil
141
+ @fallen = nil
142
+ @triggered = nil
143
+ end
144
+
145
+ def device_with_trigger trigger
146
+ @devices[trigger.object_id] ||= @plc.device_by_name(trigger[:device])
147
+ end
148
+
149
+ end
150
+
151
+ end
152
+ end
@@ -82,7 +82,6 @@ class AmbientPlugin < Plugin
82
82
  return if disabled?
83
83
 
84
84
  @values = {}
85
- @times = {}
86
85
  @worker_queue = Queue.new
87
86
 
88
87
  setup
@@ -93,41 +92,10 @@ class AmbientPlugin < Plugin
93
92
  return unless config[:channels]
94
93
 
95
94
  config[:channels].each do |channel|
96
- channel = channel
97
95
  next unless channel[:channel_id]
98
96
  next unless channel[:write_key]
99
97
  begin
100
-
101
- interval_triggered = false
102
- now = Time.now
103
- triggered = false
104
- v = nil
105
- case channel[:trigger][:type]
106
- when "interval"
107
- t = @times[channel.object_id] || now
108
- triggered = t <= now
109
- if triggered
110
- interval_triggered = true
111
- t += channel[:trigger][:interval] || 300
112
- @times[channel.object_id] = t
113
- end
114
- else
115
- device = plc.device_by_name channel[:trigger][:device]
116
- v = device.send channel[:trigger][:value_type]
117
- unless @values[device.name] == v
118
- @values[device.name] = v
119
- case channel[:trigger][:type]
120
- when "raise"
121
- triggered = !!v
122
- when "fall"
123
- triggered = !v
124
- else
125
- triggered = true
126
- end
127
- end
128
- end
129
-
130
- next unless triggered || interval_triggered
98
+ next unless self.triggered?(channel)
131
99
 
132
100
  # gether values
133
101
  values = channel[:devices].inject({}) do |h, pair|
@@ -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