rsmp 0.11.7 → 0.12.2

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 85f5c9ffaa15773f1f5e6722bd93fcf8ecff524166859bafec85e6871a285330
4
- data.tar.gz: 90f8edb63fb20d324885c9e9b15c5bde49bcbdc80086fa48c36fd4c78b183475
3
+ metadata.gz: 34c922ce1e22f31aabc3b476f1aa3d9a6eeaa4b89e4550255f237c5f5810b4e8
4
+ data.tar.gz: 95590c49d1ba70af34dfd913808239cea39b5dae0324003deb921c21a0bf0aa2
5
5
  SHA512:
6
- metadata.gz: 01c22ef28ddbaedcf45d7c24518d1cf9ffe190f434c0e8e0e07a9e7d12f6333ea5ccc16f2532502755d1efa6619e9a2c7d73e462aeed9ea75f93deb55e4cb0ab
7
- data.tar.gz: ebca1461398deacd9ff211e0bbc24c4586e286d46806c8b62718a36eaf41b5b53c2cef5a6f1882b81d4009778172a0173bf390812478e47bca86927465bde179
6
+ metadata.gz: 3d1c8bfd469ae45764292bf3e2615bf95b1904229d34c2df0eb18ad496a7d1b6ecfd0aeff594f07a0bbf59c34d7b6247fc566e1a94d65412f78719e3f4f42b1b
7
+ data.tar.gz: 66edc8044373bca92cc52641f49c78f3336d4e5c6caa8615a8da05aad6176d8e2c6161a5d835716fe7feac38948a059b4de6ec1f772de3c1f992d8c7f76bc8e0
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- rsmp (0.11.7)
4
+ rsmp (0.12.2)
5
5
  async (~> 1.29.1)
6
6
  async-io (~> 1.32.2)
7
7
  colorize (~> 0.8.1)
@@ -27,7 +27,7 @@ GEM
27
27
  builder (3.2.4)
28
28
  childprocess (4.1.0)
29
29
  colorize (0.8.1)
30
- console (1.14.0)
30
+ console (1.15.0)
31
31
  fiber-local
32
32
  contracts (0.17)
33
33
  cucumber (7.1.0)
data/config/tlc.yaml CHANGED
@@ -51,8 +51,11 @@ security_codes:
51
51
  log:
52
52
  ip: false
53
53
  site_id: 9
54
- component: 2
54
+ component: 3
55
55
  level: false
56
56
  debug: true
57
57
  json: true
58
58
  live_output: tmp/tlc.state
59
+ skip_validation:
60
+ - AlarmSuspend
61
+ - AlarmResume
@@ -0,0 +1,33 @@
1
+ module RSMP
2
+ # class that tracks the state of an alarm
3
+ class AlarmState
4
+ attr_reader :component_id, :code, :acknowledged, :suspended, :active, :timestamp, :category, :priority
5
+
6
+ def initialize component_id:, code:
7
+ @component_id = component_id
8
+ @code = code
9
+ @acknowledged = false
10
+ @suspended = false
11
+ @active = false
12
+ @timestamp = nil
13
+ @category = nil
14
+ @priority = nil
15
+ end
16
+
17
+ def suspend
18
+ @suspended = true
19
+ end
20
+
21
+ def resume
22
+ @suspended = false
23
+ end
24
+
25
+ def activate
26
+ @active = true
27
+ end
28
+
29
+ def deactivate
30
+ @active = false
31
+ end
32
+ end
33
+ end
@@ -159,6 +159,7 @@ module RSMP
159
159
  if message.attribute('oMId') == @options[:m_id]
160
160
  m_id_short = RSMP::Message.shorten_m_id @options[:m_id], 8
161
161
  cancel RSMP::MessageRejected.new("#{@title} #{m_id_short} was rejected with '#{message.attribute('rea')}'")
162
+ @notifier.log "#{identifier}: cancelled due to a NotAck", level: :debug
162
163
  true
163
164
  end
164
165
  end
@@ -1,72 +1,10 @@
1
1
  module RSMP
2
2
 
3
- # Class that represents an RMSP component.
4
- # Currently this class is used by both SiteProxy and SupervisorProxy, and can
5
- # therefore represent either a local or remote (proxy) component.
6
-
7
- class Component
8
- include Inspect
9
-
10
- attr_reader :c_id, :node, :alarms, :statuses, :aggregated_status, :aggregated_status_bools, :grouped
11
-
12
- AGGREGATED_STATUS_KEYS = [ :local_control,
13
- :communication_distruption,
14
- :high_priority_alarm,
15
- :medium_priority_alarm,
16
- :low_priority_alarm,
17
- :normal,
18
- :rest,
19
- :not_connected ]
3
+ # RSMP component
20
4
 
5
+ class Component < ComponentBase
21
6
  def initialize node:, id:, grouped: false
22
- @c_id = id
23
- @node = node
24
- @grouped = grouped
25
- @alarms = {}
26
- @statuses = {}
27
- @subscribes = {}
28
- clear_aggregated_status
29
- end
30
-
31
- def clear_aggregated_status
32
- @aggregated_status = []
33
- @aggregated_status_bools = Array.new(8,false)
34
- @aggregated_status_bools[5] = true
35
- end
36
-
37
- def set_aggregated_status status, options={}
38
- status = [status] if status.is_a? Symbol
39
- raise InvalidArgument unless status.is_a? Array
40
- input = status & AGGREGATED_STATUS_KEYS
41
- if input != @aggregated_status
42
- AGGREGATED_STATUS_KEYS.each_with_index do |key,index|
43
- @aggregated_status_bools[index] = status.include?(key)
44
- end
45
- aggregated_status_changed options
46
- end
47
- end
48
-
49
- def set_aggregated_status_bools status
50
- raise InvalidArgument unless status.is_a? Array
51
- raise InvalidArgument unless status.size == 8
52
- if status != @aggregated_status_bools
53
- @aggregated_status = []
54
- AGGREGATED_STATUS_KEYS.each_with_index do |key,index|
55
- on = status[index] == true
56
- @aggregated_status_bools[index] = on
57
- @aggregated_status << key if on
58
- end
59
- aggregated_status_changed
60
- end
61
- end
62
-
63
- def aggregated_status_changed options={}
64
- @node.aggregated_status_changed self, options
65
- end
66
-
67
- def log str, options
68
- default = { component: c_id}
69
- @node.log str, default.merge(options)
7
+ super
70
8
  end
71
9
 
72
10
  def handle_command command_code, arg
@@ -77,109 +15,40 @@ module RSMP
77
15
  raise UnknownStatus.new "Status #{status_code}/#{status_name} not implemented by #{self.class}"
78
16
  end
79
17
 
80
- # handle incoming alarm
81
- def handle_alarm message
82
- code = message.attribute('aCId')
83
- previous = @alarms[code]
84
- if previous
85
- unless message.differ?(previous)
86
- raise RepeatedAlarmError.new("no changes from previous alarm #{previous.m_id_short}")
87
- end
88
- if Time.parse(message.attribute('aTs')) < Time.parse(previous.attribute('aTs'))
89
- raise TimestampError.new("timestamp is earlier than previous alarm #{previous.m_id_short}")
90
- end
91
- end
92
- ensure
93
- @alarms[code] = message
94
- end
95
-
96
- # set alarm
97
- def send_alarm code:, status:
98
- # TODO
99
- # we need to manage the state of alarms internally (an ALarm class probably),
100
- # and handle request from the supervisor to suspend and resume alarms etc.
101
- # when this state changes, we then send an alarm message
102
- alarm = Alarm.new(
103
- 'cId' => c_id,
104
- 'aTs' => @node.clock.to_s,
105
- 'aCId' => code,
106
- 'aSp' => 'Issue',
107
- 'ack' => 'Acknowledged',
108
- 'sS' => 'notSuspended',
109
- 'aS' => status,
110
- 'cat' => 'D',
111
- 'pri' => '2',
112
- 'rvs' => []
113
- )
114
- @node.alarm_changed self, alarm
115
- end
116
-
117
- # Handle an incoming status respone, by storing the values
118
- def handle_status_response message
119
- store_status message, check_repeated: false
18
+ def get_alarm_state alarm_code
19
+ alarm = @alarms[alarm_code] ||= RSMP::AlarmState.new component_id: c_id, code: alarm_code
120
20
  end
121
21
 
122
- # Handle an incoming status update, by storing the values
123
- def handle_status_update message
124
- store_status message, check_repeated: true
22
+ def suspend_alarm alarm_code
23
+ alarm = get_alarm_state alarm_code
24
+ return if alarm.suspended
25
+ log "Suspending alarm #{alarm_code}", level: :info
26
+ alarm.suspend
27
+ @node.alarm_changed alarm
125
28
  end
126
29
 
127
- # Our proxy subscribed to status updates
128
- # Store update rates, so we can check for repeated alarm if we asked for updates only
129
- # when there's a change, not on a regular interval.
130
- # After subscribing, an update status us send regarless of whether values changes,
131
- # and we store that.
132
- def handle_status_subscribe status_list
133
- status_list.each do |item|
134
- sCI, n, uRt = item['sCI'], item['n'], item['uRt']
135
-
136
- # record the update rate, so we can check for repeated status values if rate is zero
137
- @subscribes[sCI] ||= {}
138
- @subscribes[sCI][n] = {'uRt'=>uRt}
139
-
140
- # record that we expect an upeate, even though the value might not change
141
- @statuses[sCI] ||= {}
142
- @statuses[sCI][n] ||= {}
143
- @statuses[sCI][n][:initial] = true
144
- end
30
+ def resume_alarm alarm_code
31
+ alarm = get_alarm_state alarm_code
32
+ return unless alarm.suspended
33
+ log "Resuming alarm #{alarm_code}", level: :info
34
+ alarm.resume
35
+ @node.alarm_changed alarm
145
36
  end
146
37
 
147
- # Our proxy unsubscribed to status updates.
148
- # Update our list of update rates.
149
- def handle_status_unsubscribe status_list
150
- status_list.each do |item|
151
- sCI, n = item['sCI'], item['n']
152
- if @subscribes[sCI]
153
- @subscribes[sCI].delete n
154
- end
155
- if @subscribes[sCI].empty?
156
- @subscribes.delete sCI
157
- end
158
-
159
- # remove any mark that would allow the next update to be a repeat
160
- item = @statuses.dig sCI, n
161
- item.delete(:initial) if item
162
- end
38
+ def activate_alarm alarm_code
39
+ alarm = get_alarm_state alarm_code
40
+ return if alarm.active
41
+ log "Activating alarm #{alarm_code}", level: :info
42
+ alarm.activate
43
+ @node.alarm_changed alarm
163
44
  end
164
45
 
165
- # Store the latest status update values, optionally
166
- # checking that we're not receiving unchanged values if we're subscribed
167
- # wit updates only on change
168
- def store_status message, check_repeated:
169
- message.attribute('sS').each do |item|
170
- sCI, n, s, q = item['sCI'], item['n'], item['s'], item['q']
171
- uRt = @subscribes.dig(sCI,n,'uRt')
172
- new_values = {'s'=>s,'q'=>q}
173
- old_values = @statuses.dig(sCI,n)
174
- if check_repeated && uRt.to_i == 0
175
- if new_values == old_values
176
- raise RSMP::RepeatedStatusError.new "no change for #{sCI} '#{n}'"
177
- end
178
- end
179
- @statuses[sCI] ||= {}
180
- @statuses[sCI][n] = new_values
181
- end
46
+ def deactivate_alarm alarm_code
47
+ alarm = get_alarm_state alarm_code
48
+ return unless alarm.active
49
+ log "Deactivating alarm #{alarm_code}", level: :info
50
+ alarm.deactivate
51
+ @node.alarm_changed alarm
182
52
  end
183
-
184
53
  end
185
54
  end
@@ -0,0 +1,69 @@
1
+ module RSMP
2
+
3
+ # RSMP component base class.
4
+
5
+ class ComponentBase
6
+ include Inspect
7
+
8
+ attr_reader :c_id, :node, :alarms, :statuses, :aggregated_status, :aggregated_status_bools, :grouped
9
+
10
+ AGGREGATED_STATUS_KEYS = [ :local_control,
11
+ :communication_distruption,
12
+ :high_priority_alarm,
13
+ :medium_priority_alarm,
14
+ :low_priority_alarm,
15
+ :normal,
16
+ :rest,
17
+ :not_connected ]
18
+
19
+ def initialize node:, id:, grouped: false
20
+ @c_id = id
21
+ @node = node
22
+ @grouped = grouped
23
+ @alarms = {}
24
+ clear_aggregated_status
25
+ end
26
+
27
+ def clear_aggregated_status
28
+ @aggregated_status = []
29
+ @aggregated_status_bools = Array.new(8,false)
30
+ @aggregated_status_bools[5] = true
31
+ end
32
+
33
+ def log str, options
34
+ default = { component: c_id}
35
+ @node.log str, default.merge(options)
36
+ end
37
+
38
+ def set_aggregated_status status, options={}
39
+ status = [status] if status.is_a? Symbol
40
+ raise InvalidArgument unless status.is_a? Array
41
+ input = status & AGGREGATED_STATUS_KEYS
42
+ if input != @aggregated_status
43
+ AGGREGATED_STATUS_KEYS.each_with_index do |key,index|
44
+ @aggregated_status_bools[index] = status.include?(key)
45
+ end
46
+ aggregated_status_changed options
47
+ end
48
+ end
49
+
50
+ def set_aggregated_status_bools status
51
+ raise InvalidArgument unless status.is_a? Array
52
+ raise InvalidArgument unless status.size == 8
53
+ if status != @aggregated_status_bools
54
+ @aggregated_status = []
55
+ AGGREGATED_STATUS_KEYS.each_with_index do |key,index|
56
+ on = status[index] == true
57
+ @aggregated_status_bools[index] = on
58
+ @aggregated_status << key if on
59
+ end
60
+ aggregated_status_changed
61
+ end
62
+ end
63
+
64
+ def aggregated_status_changed options={}
65
+ @node.aggregated_status_changed self, options
66
+ end
67
+
68
+ end
69
+ end
@@ -0,0 +1,67 @@
1
+ module RSMP
2
+
3
+ # A proxy to a remote RSMP component.
4
+
5
+ class ComponentProxy < ComponentBase
6
+ def initialize node:, id:, grouped: false
7
+ super
8
+ @statuses = {}
9
+ @allow_repeat_updates = {}
10
+ end
11
+
12
+ # allow the next status update to be a repeat value
13
+ def allow_repeat_updates subscribe_list
14
+ subscribe_list.each do |item|
15
+ sCI = item['sCI']
16
+ n = item['n']
17
+ @allow_repeat_updates[sCI] ||= Set.new # Set is like an array, but with no duplicates
18
+ @allow_repeat_updates[sCI] << n
19
+ end
20
+ end
21
+
22
+ # Check that were not receiving repeated update values.
23
+ # The check is not performed for item with an update interval.
24
+ def check_repeat_values message, subscription_list
25
+ message.attribute('sS').each do |item|
26
+ sCI, n, s, q = item['sCI'], item['n'], item['s'], item['q']
27
+ uRt = subscription_list.dig(c_id,sCI,n,'uRt')
28
+ next if uRt.to_i > 0
29
+ next if @allow_repeat_updates[sCI] && @allow_repeat_updates[sCI].include?(n)
30
+ new_values = {'s'=>s,'q'=>q}
31
+ old_values = @statuses.dig(sCI,n)
32
+ if new_values == old_values
33
+ raise RSMP::RepeatedStatusError.new "no change for #{sCI} '#{n}'"
34
+ end
35
+ end
36
+ end
37
+ # Store the latest status update values
38
+ def store_status message
39
+ message.attribute('sS').each do |item|
40
+ sCI, n, s, q = item['sCI'], item['n'], item['s'], item['q']
41
+ @statuses[sCI] ||= {}
42
+ @statuses[sCI][n] = {'s'=>s,'q'=>q}
43
+
44
+ # once a value is received, don't allow the value to be a repeat
45
+ @allow_repeat_updates[sCI].delete(n) if @allow_repeat_updates[sCI]
46
+ end
47
+ end
48
+
49
+ # handle incoming alarm
50
+ def handle_alarm message
51
+ # code = message.attribute('aCId')
52
+ # previous = @alarms[code]
53
+ # if previous
54
+ # unless message.differ?(previous)
55
+ # raise RepeatedAlarmError.new("no changes from previous alarm #{previous.m_id_short}")
56
+ # end
57
+ # if Time.parse(message.attribute('aTs')) < Time.parse(previous.attribute('aTs'))
58
+ # raise TimestampError.new("timestamp is earlier than previous alarm #{previous.m_id_short}")
59
+ # end
60
+ # end
61
+ # p message
62
+ # ensure
63
+ # @alarms[code] = message
64
+ end
65
+
66
+ end
67
+ end
@@ -36,9 +36,9 @@ module RSMP
36
36
  @components[component.c_id] = component
37
37
  end
38
38
 
39
- def build_component id:, type:, settings:{}
40
- Component.new id:id, node: self, grouped: type=='main'
41
- end
39
+ #def build_component id:, type:, settings:{}
40
+ # Component.new id:id, node: self, grouped: type=='main'
41
+ #end
42
42
 
43
43
  def infer_component_type component_id
44
44
  Component
data/lib/rsmp/message.rb CHANGED
@@ -61,15 +61,15 @@ module RSMP
61
61
 
62
62
  def self.build_alarm attributes
63
63
  case attributes["aSp"]
64
- when 'Issue'
64
+ when /Issue/i
65
65
  AlarmIssue.new attributes
66
- when 'Request'
66
+ when /Request/i
67
67
  AlarmRequest.new attributes
68
- when 'Acknowledge'
68
+ when /Acknowledge/i
69
69
  AlarmAcknowledged.new attributes
70
- when 'Suspend'
70
+ when /Suspend/i
71
71
  AlarmSuspend.new attributes
72
- when 'Resume'
72
+ when /Resume/i
73
73
  AlarmResume.new attributes
74
74
  else
75
75
  Alarm.new attributes
data/lib/rsmp/proxy.rb CHANGED
@@ -438,6 +438,7 @@ module RSMP
438
438
  end
439
439
 
440
440
  def will_not_handle message
441
+ "WILL NOT HANDLE"
441
442
  reason = "since we're a #{self.class.name.downcase}" unless reason
442
443
  log "Ignoring #{message.type}, #{reason}", message: message, level: :warning
443
444
  dont_acknowledge message, nil, reason
data/lib/rsmp/site.rb CHANGED
@@ -93,9 +93,25 @@ module RSMP
93
93
  end
94
94
  end
95
95
 
96
- def alarm_changed component, alarm
96
+ def alarm_state_to_message alarm_state
97
+ Alarm.new(
98
+ 'cId' => alarm_state.component_id,
99
+ 'aTs' => clock.to_s,
100
+ 'aCId' => alarm_state.code,
101
+ 'aSp' => (alarm_state.suspended ? 'Suspend' : 'Issue'),
102
+ 'ack' => (alarm_state.acknowledged ? 'Acknowledged' : 'notAcknowledged'),
103
+ 'sS' => (alarm_state.suspended ? 'suspended' : 'notSuspended'),
104
+ 'aS' => (alarm_state.active ? 'Active' : 'inActive'),
105
+ 'cat' => (alarm_state.category || 'D'),
106
+ 'pri' => (alarm_state.priority || '2'),
107
+ 'rvs' => []
108
+ )
109
+ end
110
+
111
+ def alarm_changed alarm_state
112
+ alarm = alarm_state_to_message alarm_state
97
113
  @proxies.each do |proxy|
98
- proxy.send_alarm component, alarm if proxy.ready?
114
+ proxy.send_message alarm if proxy.ready?
99
115
  end
100
116
  end
101
117
 
@@ -135,5 +151,9 @@ module RSMP
135
151
  end
136
152
  nil
137
153
  end
154
+
155
+ def build_component id:, type:, settings:{}
156
+ Component.new id:id, node: self, grouped: type=='main'
157
+ end
138
158
  end
139
159
  end
@@ -12,6 +12,7 @@ module RSMP
12
12
  @supervisor = options[:supervisor]
13
13
  @settings = @supervisor.supervisor_settings.clone
14
14
  @site_id = options[:site_id]
15
+ @status_subscriptions = {}
15
16
  end
16
17
 
17
18
  # handle communication
@@ -203,7 +204,7 @@ module RSMP
203
204
 
204
205
  def process_status_response message
205
206
  component = find_component message.attribute("cId")
206
- component.handle_status_response message
207
+ component.store_status message
207
208
  log "Received #{message.type}", message: message, level: :log
208
209
  acknowledge message
209
210
  end
@@ -213,11 +214,22 @@ module RSMP
213
214
  m_id = options[:m_id] || RSMP::Message.make_m_id
214
215
 
215
216
  # additional items can be used when verifying the response,
216
- # but must to remove from the subscribe message
217
+ # but must be removed from the subscribe message
217
218
  subscribe_list = status_list.map { |item| item.slice('sCI','n','uRt') }
218
219
 
220
+ # update our subcription list
221
+ @status_subscriptions[component_id] ||= {}
222
+ subscribe_list.each do |item|
223
+ sCI = item["sCI"]
224
+ n = item["n"]
225
+ uRt = item["uRt"]
226
+ @status_subscriptions[component_id][sCI] ||= {}
227
+ @status_subscriptions[component_id][sCI][n] ||= {}
228
+ @status_subscriptions[component_id][sCI][n]['uRt'] = uRt
229
+ end
230
+
219
231
  component = find_component component_id
220
- component.handle_status_subscribe subscribe_list
232
+ component.allow_repeat_updates subscribe_list
221
233
 
222
234
  message = RSMP::StatusSubscribe.new({
223
235
  "ntsOId" => '',
@@ -236,15 +248,24 @@ module RSMP
236
248
  end
237
249
 
238
250
  def unsubscribe_to_status component_id, status_list, options={}
239
- component = find_component component_id
240
- component.handle_status_subscribe status_list
241
-
242
251
  validate_ready 'unsubscribe to status'
252
+
253
+ # update our subcription list
254
+ status_list.each do |item|
255
+ sCI = item["sCI"]
256
+ n = item["n"]
257
+ if @status_subscriptions.dig(component_id,sCI,n)
258
+ @status_subscriptions[component_id][sCI].delete n
259
+ @status_subscriptions[component_id].delete(sCI) if @status_subscriptions[component_id][sCI].empty?
260
+ @status_subscriptions.delete(component_id) if @status_subscriptions[component_id].empty?
261
+ end
262
+ end
263
+
243
264
  message = RSMP::StatusUnsubscribe.new({
244
- "ntsOId" => '',
245
- "xNId" => '',
246
- "cId" => component_id,
247
- "sS" => status_list
265
+ "ntsOId" => '',
266
+ "xNId" => '',
267
+ "cId" => component_id,
268
+ "sS" => status_list
248
269
  })
249
270
  send_message message, validate: options[:validate]
250
271
  message
@@ -252,7 +273,8 @@ module RSMP
252
273
 
253
274
  def process_status_update message
254
275
  component = find_component message.attribute("cId")
255
- component.handle_status_update message
276
+ component.check_repeat_values message, @status_subscriptions
277
+ component.store_status message
256
278
  log "Received #{message.type}", message: message, level: :log
257
279
  acknowledge message
258
280
  end
@@ -357,5 +379,10 @@ module RSMP
357
379
  @supervisor.notify_error e, options if @supervisor
358
380
  distribute_error e, options
359
381
  end
382
+
383
+ def build_component id:, type:, settings:{}
384
+ ComponentProxy.new id:id, node: self, grouped: type=='main'
385
+ end
386
+
360
387
  end
361
388
  end
@@ -91,25 +91,24 @@ module RSMP
91
91
 
92
92
  def process_message message
93
93
  case message
94
- when Alarm
95
- when StatusResponse
96
- when StatusUpdate
97
- when AggregatedStatus
98
- will_not_handle message
99
- when AggregatedStatusRequest
100
- process_aggregated_status_request message
101
- when CommandRequest
102
- process_command_request message
103
- when CommandResponse
104
- process_command_response message
105
- when StatusRequest
106
- process_status_request message
107
- when StatusSubscribe
108
- process_status_subcribe message
109
- when StatusUnsubscribe
110
- process_status_unsubcribe message
111
- else
112
- super message
94
+ when StatusResponse, StatusUpdate, AggregatedStatus, AlarmIssue
95
+ will_not_handle message
96
+ when AggregatedStatusRequest
97
+ process_aggregated_status_request message
98
+ when CommandRequest
99
+ process_command_request message
100
+ when CommandResponse
101
+ process_command_response message
102
+ when StatusRequest
103
+ process_status_request message
104
+ when StatusSubscribe
105
+ process_status_subcribe message
106
+ when StatusUnsubscribe
107
+ process_status_unsubcribe message
108
+ when AlarmAcknowledged, AlarmSuspend, AlarmResume, AlarmRequest
109
+ process_alarm message
110
+ else
111
+ super message
113
112
  end
114
113
  rescue UnknownComponent, UnknownCommand, UnknownStatus,
115
114
  MessageRejected, MissingAttribute => e
@@ -182,13 +181,39 @@ module RSMP
182
181
  end
183
182
 
184
183
  def process_alarm message
184
+ case message
185
+ when AlarmAcknowledged
186
+ handle_alarm_acknowledge message
187
+ when AlarmSuspend
188
+ handle_alarm_suspend message
189
+ when AlarmResume
190
+ handle_alarm_resume message
191
+ when AlarmRequest
192
+ handle_alarm_request message
193
+ else
194
+ dont_acknowledge message, "Invalid alarm message type"
195
+ end
196
+ end
197
+
198
+ # handle incoming alarm suspend
199
+ def handle_alarm_suspend message
200
+ component_id = message.attributes["cId"]
201
+ component = @site.find_component component_id
185
202
  alarm_code = message.attribute("aCId")
186
- asp = message.attribute("aSp")
187
- status = ["ack","aS","sS"].map { |key| message.attribute(key) }.join(',')
188
- log "Received #{message.type}, #{alarm_code} #{asp} [#{status}]", message: message, level: :log
203
+ log "Received #{message.type} #{alarm_code} suspend", message: message, level: :log
189
204
  acknowledge message
205
+ component.suspend_alarm alarm_code
190
206
  end
191
207
 
208
+ # handle incoming alarm resume
209
+ def handle_alarm_resume message
210
+ component_id = message.attributes["cId"]
211
+ component = @site.find_component component_id
212
+ alarm_code = message.attribute("aCId")
213
+ log "Received #{message.type} #{alarm_code} resume", message: message, level: :log
214
+ acknowledge message
215
+ component.resume_alarm alarm_code
216
+ end
192
217
  # reorganize rmsp command request arg attribute:
193
218
  # [{"cCI":"M0002","cO":"setPlan","n":"status","v":"True"},{"cCI":"M0002","cO":"setPlan","n":"securityCode","v":"5678"},{"cCI":"M0002","cO":"setPlan","n":"timeplan","v":"3"}]
194
219
  # into the simpler, but equivalent:
@@ -262,24 +287,28 @@ module RSMP
262
287
  # for each component, containing all the requested statuses
263
288
 
264
289
  update_list = {}
265
- component = message.attributes["cId"]
266
- @status_subscriptions[component] ||= {}
267
- update_list[component] ||= {}
290
+ component_id = message.attributes["cId"]
291
+ @status_subscriptions[component_id] ||= {}
292
+ update_list[component_id] ||= {}
268
293
  now = Time.now # internal timestamp
269
- subs = @status_subscriptions[component]
294
+ subs = @status_subscriptions[component_id]
270
295
 
271
296
  message.attributes["sS"].each do |arg|
272
297
  sCI = arg["sCI"]
273
298
  subcription = {interval: arg["uRt"].to_i, last_sent_at: now}
274
299
  subs[sCI] ||= {}
275
300
  subs[sCI][arg["n"]] = subcription
276
- update_list[component][sCI] ||= []
277
- update_list[component][sCI] << arg["n"]
301
+ update_list[component_id][sCI] ||= []
302
+ update_list[component_id][sCI] << arg["n"]
278
303
  end
279
304
  acknowledge message
280
305
  send_status_updates update_list # send status after subscribing is accepted
281
306
  end
282
307
 
308
+ def get_status_subscribe_interval component_id, sCI, n
309
+ @status_subscriptions.dig component_id, sCI, n
310
+ end
311
+
283
312
  def process_status_unsubcribe message
284
313
  log "Received #{message.type}", message: message, level: :log
285
314
  component = message.attributes["cId"]
@@ -264,10 +264,10 @@ module RSMP
264
264
  alarm_code = actions['raise']
265
265
  if change
266
266
  log "Activating alarm #{alarm_code}, because input #{input} was activated", level: :info
267
- send_alarm code:alarm_code, status:'Active'
267
+ activate_alarm alarm_code
268
268
  else
269
269
  log "Deactivating alarm #{alarm_code}, because input #{input} was deactivated", level: :info
270
- send_alarm code:alarm_code, status:'inActive'
270
+ deactivate_alarm alarm_code
271
271
  end
272
272
  end
273
273
  end
data/lib/rsmp/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module RSMP
2
- VERSION = "0.11.7"
2
+ VERSION = "0.12.2"
3
3
  end
data/lib/rsmp.rb CHANGED
@@ -30,7 +30,10 @@ require 'rsmp/collect/status_collector'
30
30
  require 'rsmp/collect/command_response_collector'
31
31
  require 'rsmp/collect/aggregated_status_collector'
32
32
  require 'rsmp/collect/alarm_collector'
33
+ require 'rsmp/alarm_state'
34
+ require 'rsmp/component_base'
33
35
  require 'rsmp/component'
36
+ require 'rsmp/component_proxy'
34
37
  require 'rsmp/site'
35
38
  require 'rsmp/proxy'
36
39
  require 'rsmp/supervisor_proxy'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rsmp
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.11.7
4
+ version: 0.12.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Emil Tin
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-03-25 00:00:00.000000000 Z
11
+ date: 2022-04-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: async
@@ -208,6 +208,7 @@ files:
208
208
  - documentation/tasks.md
209
209
  - exe/rsmp
210
210
  - lib/rsmp.rb
211
+ - lib/rsmp/alarm_state.rb
211
212
  - lib/rsmp/archive.rb
212
213
  - lib/rsmp/cli.rb
213
214
  - lib/rsmp/collect/aggregated_status_collector.rb
@@ -225,6 +226,8 @@ files:
225
226
  - lib/rsmp/collect/status_collector.rb
226
227
  - lib/rsmp/collect/status_query.rb
227
228
  - lib/rsmp/component.rb
229
+ - lib/rsmp/component_base.rb
230
+ - lib/rsmp/component_proxy.rb
228
231
  - lib/rsmp/components.rb
229
232
  - lib/rsmp/convert/export/json_schema.rb
230
233
  - lib/rsmp/convert/import/yaml.rb