ladder_drive 0.6.4 → 0.6.8

Sign up to get free protection for your applications and to get access to all the features.
@@ -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