rsmp 0.37.0 → 0.39.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.
Files changed (108) hide show
  1. checksums.yaml +4 -4
  2. data/.devcontainer/devcontainer.json +22 -0
  3. data/.github/workflows/rubocop.yaml +17 -0
  4. data/.gitignore +5 -6
  5. data/.rubocop.yml +69 -0
  6. data/.tool-versions +1 -1
  7. data/Gemfile +14 -1
  8. data/Gemfile.lock +64 -29
  9. data/Rakefile +3 -3
  10. data/lib/rsmp/cli.rb +148 -124
  11. data/lib/rsmp/collect/ack_collector.rb +8 -7
  12. data/lib/rsmp/collect/aggregated_status_collector.rb +4 -4
  13. data/lib/rsmp/collect/alarm_collector.rb +31 -23
  14. data/lib/rsmp/collect/alarm_matcher.rb +6 -6
  15. data/lib/rsmp/collect/collector/logging.rb +18 -0
  16. data/lib/rsmp/collect/collector/reporting.rb +44 -0
  17. data/lib/rsmp/collect/collector/status.rb +34 -0
  18. data/lib/rsmp/collect/collector.rb +69 -150
  19. data/lib/rsmp/collect/command_matcher.rb +19 -6
  20. data/lib/rsmp/collect/command_response_collector.rb +7 -7
  21. data/lib/rsmp/collect/distributor.rb +14 -11
  22. data/lib/rsmp/collect/filter.rb +31 -15
  23. data/lib/rsmp/collect/matcher.rb +9 -13
  24. data/lib/rsmp/collect/queue.rb +7 -7
  25. data/lib/rsmp/collect/receiver.rb +11 -15
  26. data/lib/rsmp/collect/state_collector.rb +116 -77
  27. data/lib/rsmp/collect/status_collector.rb +6 -6
  28. data/lib/rsmp/collect/status_matcher.rb +15 -4
  29. data/lib/rsmp/{alarm_state.rb → component/alarm_state.rb} +76 -38
  30. data/lib/rsmp/{component.rb → component/component.rb} +15 -15
  31. data/lib/rsmp/component/component_base.rb +88 -0
  32. data/lib/rsmp/component/component_proxy.rb +75 -0
  33. data/lib/rsmp/component/components.rb +62 -0
  34. data/lib/rsmp/convert/export/json_schema.rb +118 -110
  35. data/lib/rsmp/convert/import/yaml.rb +22 -18
  36. data/lib/rsmp/{rsmp.rb → helpers/clock.rb} +8 -11
  37. data/lib/rsmp/{deep_merge.rb → helpers/deep_merge.rb} +3 -1
  38. data/lib/rsmp/helpers/error.rb +72 -0
  39. data/lib/rsmp/helpers/inspect.rb +41 -0
  40. data/lib/rsmp/log/archive.rb +97 -0
  41. data/lib/rsmp/log/colorization.rb +41 -0
  42. data/lib/rsmp/log/filtering.rb +54 -0
  43. data/lib/rsmp/log/logger.rb +207 -0
  44. data/lib/rsmp/{logging.rb → log/logging.rb} +6 -7
  45. data/lib/rsmp/message.rb +185 -148
  46. data/lib/rsmp/{node.rb → node/node.rb} +20 -19
  47. data/lib/rsmp/{protocol.rb → node/protocol.rb} +6 -3
  48. data/lib/rsmp/node/site/site.rb +192 -0
  49. data/lib/rsmp/node/supervisor/modules/configuration.rb +59 -0
  50. data/lib/rsmp/node/supervisor/modules/connection.rb +140 -0
  51. data/lib/rsmp/node/supervisor/modules/sites.rb +64 -0
  52. data/lib/rsmp/node/supervisor/supervisor.rb +69 -0
  53. data/lib/rsmp/{task.rb → node/task.rb} +13 -14
  54. data/lib/rsmp/proxy/modules/acknowledgements.rb +144 -0
  55. data/lib/rsmp/proxy/modules/receive.rb +119 -0
  56. data/lib/rsmp/proxy/modules/send.rb +76 -0
  57. data/lib/rsmp/proxy/modules/state.rb +25 -0
  58. data/lib/rsmp/proxy/modules/tasks.rb +105 -0
  59. data/lib/rsmp/proxy/modules/versions.rb +69 -0
  60. data/lib/rsmp/proxy/modules/watchdogs.rb +66 -0
  61. data/lib/rsmp/proxy/proxy.rb +197 -0
  62. data/lib/rsmp/proxy/site/modules/aggregated_status.rb +52 -0
  63. data/lib/rsmp/proxy/site/modules/alarms.rb +27 -0
  64. data/lib/rsmp/proxy/site/modules/commands.rb +31 -0
  65. data/lib/rsmp/proxy/site/modules/status.rb +110 -0
  66. data/lib/rsmp/proxy/site/site_proxy.rb +204 -0
  67. data/lib/rsmp/proxy/supervisor/modules/aggregated_status.rb +47 -0
  68. data/lib/rsmp/proxy/supervisor/modules/alarms.rb +73 -0
  69. data/lib/rsmp/proxy/supervisor/modules/commands.rb +53 -0
  70. data/lib/rsmp/proxy/supervisor/modules/status.rb +204 -0
  71. data/lib/rsmp/proxy/supervisor/supervisor_proxy.rb +177 -0
  72. data/lib/rsmp/tlc/detector_logic.rb +19 -34
  73. data/lib/rsmp/tlc/input_states.rb +126 -0
  74. data/lib/rsmp/tlc/modules/detector_logics.rb +50 -0
  75. data/lib/rsmp/tlc/modules/display.rb +78 -0
  76. data/lib/rsmp/tlc/modules/helpers.rb +41 -0
  77. data/lib/rsmp/tlc/modules/inputs.rb +173 -0
  78. data/lib/rsmp/tlc/modules/modes.rb +253 -0
  79. data/lib/rsmp/tlc/modules/outputs.rb +30 -0
  80. data/lib/rsmp/tlc/modules/plans.rb +218 -0
  81. data/lib/rsmp/tlc/modules/signal_groups.rb +109 -0
  82. data/lib/rsmp/tlc/modules/startup_sequence.rb +22 -0
  83. data/lib/rsmp/tlc/modules/system.rb +140 -0
  84. data/lib/rsmp/tlc/modules/traffic_data.rb +49 -0
  85. data/lib/rsmp/tlc/signal_group.rb +38 -41
  86. data/lib/rsmp/tlc/signal_plan.rb +14 -11
  87. data/lib/rsmp/tlc/signal_priority.rb +40 -35
  88. data/lib/rsmp/tlc/startup_sequence.rb +59 -0
  89. data/lib/rsmp/tlc/traffic_controller.rb +38 -1010
  90. data/lib/rsmp/tlc/traffic_controller_site.rb +58 -57
  91. data/lib/rsmp/version.rb +1 -1
  92. data/lib/rsmp.rb +82 -48
  93. data/rsmp.gemspec +24 -31
  94. metadata +79 -139
  95. data/lib/rsmp/archive.rb +0 -76
  96. data/lib/rsmp/collect/message_matchers.rb +0 -0
  97. data/lib/rsmp/component_base.rb +0 -87
  98. data/lib/rsmp/component_proxy.rb +0 -57
  99. data/lib/rsmp/components.rb +0 -65
  100. data/lib/rsmp/error.rb +0 -71
  101. data/lib/rsmp/inspect.rb +0 -46
  102. data/lib/rsmp/logger.rb +0 -216
  103. data/lib/rsmp/proxy.rb +0 -693
  104. data/lib/rsmp/site.rb +0 -188
  105. data/lib/rsmp/site_proxy.rb +0 -389
  106. data/lib/rsmp/supervisor.rb +0 -302
  107. data/lib/rsmp/supervisor_proxy.rb +0 -510
  108. data/lib/rsmp/tlc/inputs.rb +0 -134
@@ -35,91 +35,103 @@ module RSMP
35
35
  attr_reader :matchers
36
36
 
37
37
  # Initialize with a list of wanted statuses
38
- def initialize proxy, want, options={}
39
- raise ArgumentError.new("num option cannot be used") if options[:num]
40
- super proxy, options
38
+ def initialize(proxy, want, options = {})
39
+ raise ArgumentError, 'num option cannot be used' if options[:num]
40
+
41
+ super(proxy, options)
41
42
  @matchers = want.map { |item| build_matcher item }
42
43
  end
43
44
 
44
45
  # Build a matcher object.
45
46
  # Sub-classes should override to use their own matcher classes.
46
- def build_matcher want
47
+ def build_matcher(want)
47
48
  Matcher.new want
48
49
  end
49
50
 
50
51
  # Get a results
51
- def matcher_result want
52
- matcher = @matchers.find { |q| q.want == want}
52
+ def matcher_result(want)
53
+ matcher = @matchers.find { |q| q.want == want }
53
54
  raise unless matcher
55
+
54
56
  matcher.got
55
57
  end
56
58
 
57
59
  # Get an array of the last item received for each matcher
58
60
  def reached
59
- @matchers.map { |matcher| matcher.got }.compact
61
+ @matchers.map(&:got).compact
60
62
  end
61
63
 
62
64
  # Get messages from results
63
65
  def messages
64
- @matchers.map { |matcher| matcher.message }.uniq.compact
66
+ @matchers.map(&:message).uniq.compact
65
67
  end
66
68
 
67
69
  # Return progress as completes matchers vs. total number of matchers
68
70
  def progress
69
71
  need = @matchers.size
70
- reached = @matchers.count { |matcher| matcher.done? }
72
+ reached = @matchers.count(&:done?)
71
73
  { need: need, reached: reached }
72
74
  end
73
75
 
74
76
  # Are there matchers left to type_match?
75
77
  def done?
76
- @matchers.all? { |matcher| matcher.done? }
78
+ @matchers.all?(&:done?)
77
79
  end
78
80
 
79
81
  # Get a simplified hash of matchers, with values set to either true or false,
80
82
  # indicating which matchers have been matched.
81
83
  def matcher_status
82
- @matchers.map { |matcher| [matcher.want, matcher.done?] }.to_h
84
+ @matchers.to_h { |matcher| [matcher.want, matcher.done?] }
83
85
  end
84
86
 
85
87
  # Get a simply array of bools, showing which matchers have been matched.
86
88
  def summary
87
- @matchers.map { |matcher| matcher.done? }
89
+ @matchers.map(&:done?)
90
+ end
91
+
92
+ def log_match_result(message, matched, matcher, item)
93
+ type = { true => 'match', false => 'mismatch' }[matched]
94
+ @distributor.log "#{@title.capitalize} #{message.m_id_short} collect #{type} #{matcher.want}, item #{item}",
95
+ level: :debug
96
+ end
97
+
98
+ def handle_match_result(matched, matcher, message, item)
99
+ return if matched.nil?
100
+
101
+ log_match_result(message, matched, matcher, item)
102
+ if matched == true
103
+ matcher.keep message, item
104
+ elsif matched == false
105
+ matcher.forget
106
+ end
88
107
  end
89
108
 
90
- # Check if a messages matches our criteria.
91
- # Match each matcher against each item in the message
92
- def perform_match message
93
- return false if super(message) == false
109
+ def perform_match(message)
110
+ return false if super == false
94
111
  return unless collecting?
95
- @matchers.each do |matcher| # look through matchers
96
- get_items(message).each do |item| # look through items in message
97
- matched = matcher.perform_match(item,message,@block)
98
- return unless collecting?
99
- if matched != nil
100
- type = {true=>'match',false=>'mismatch'}[matched]
101
- @distributor.log "#{@title.capitalize} #{message.m_id_short} collect #{type} #{matcher.want}, item #{item}", level: :debug
102
- if matched == true
103
- matcher.keep message, item
104
- elsif matched == false
105
- matcher.forget
106
- end
107
- end
112
+
113
+ @matchers.each do |matcher|
114
+ break unless collecting?
115
+
116
+ get_items(message).each do |item|
117
+ matched = matcher.perform_match(item, message, @block)
118
+ break unless collecting?
119
+
120
+ handle_match_result(matched, matcher, message, item)
108
121
  end
109
122
  end
110
123
  end
111
124
 
112
125
  # don't collect anything. Matcher will collect them instead
113
- def keep message
114
- end
126
+ def keep(message); end
115
127
 
116
128
  def describe
117
- @matchers.map {|q| q.want.to_s }
129
+ @matchers.map { |q| q.want.to_s }
118
130
  end
119
131
 
120
132
  # return a string that describes the attributes that we're looking for
121
133
  def describe_matcher
122
- "#{super} matching #{matcher_want_hash.to_s}"
134
+ "#{super} matching #{matcher_want_hash}"
123
135
  end
124
136
 
125
137
  # return a hash that describe the status of all matchers
@@ -128,33 +140,45 @@ module RSMP
128
140
  @matchers.each do |matcher|
129
141
  want = matcher.want
130
142
  if want['cCI']
131
- cCI = want['cCI']
132
- h[cCI] ||= {}
133
- cO = h['cO']
134
- n = h['n']
135
- v = h['v']
136
- h[cCI][cO] ||= {}
137
- h[cCI][cO][n] = v
143
+ process_command_matcher(h, matcher, want)
138
144
  elsif want['sCI']
139
- sCI = want['sCI']
140
- h[sCI] ||= {}
141
- n = want['n']
142
- s = want['s']
143
- if matcher.got && matcher.got['s']
144
- h[sCI][n] = { {s=>matcher.got['s']} => matcher.done? }
145
- else
146
- h[sCI][n] = { s=>nil }
147
- end
145
+ process_status_matcher(h, matcher, want)
148
146
  end
149
147
  end
150
148
  h
151
149
  end
152
150
 
151
+ private
152
+
153
+ def process_command_matcher(hash, _matcher, want)
154
+ cci = want['cCI']
155
+ hash[cci] ||= {}
156
+ co = want['cO']
157
+ n = want['n']
158
+ v = want['v']
159
+ hash[cci][co] ||= {}
160
+ hash[cci][co][n] = v
161
+ end
162
+
163
+ def process_status_matcher(hash, matcher, want)
164
+ sci = want['sCI']
165
+ hash[sci] ||= {}
166
+ n = want['n']
167
+ s = want['s']
168
+ hash[sci][n] = if matcher.got && matcher.got['s']
169
+ { { s => matcher.got['s'] } => matcher.done? }
170
+ else
171
+ { s => nil }
172
+ end
173
+ end
174
+
175
+ public
176
+
153
177
  # return a string that describe how many many messages have been collected
154
178
  def describe_progress
155
179
  num_matchers = @matchers.size
156
- num_matched = @matchers.count { |matcher| matcher.done? }
157
- ".. Matched #{num_matched}/#{num_matchers} with #{progress_hash.to_s}"
180
+ num_matched = @matchers.count(&:done?)
181
+ ".. Matched #{num_matched}/#{num_matchers} with #{progress_hash}"
158
182
  end
159
183
 
160
184
  def matcher_want_hash
@@ -162,44 +186,59 @@ module RSMP
162
186
  @matchers.each do |matcher|
163
187
  item = matcher.want
164
188
  if item['cCI']
165
- cCI = item['cCI']
166
- h[cCI] ||= {}
167
- cO = item['cO']
168
- h[cCI][cO] ||= {}
169
- n = item['n']
170
- v = item['v']
171
- h[cCI][cO][n] = v || :any
189
+ add_command_want_to_hash(h, item)
172
190
  elsif item['sCI']
173
- sCI = item['sCI']
174
- h[sCI] ||= {}
175
- n = item['n']
176
- s = item['s']
177
- h[sCI][n] = s || :any
191
+ add_status_want_to_hash(h, item)
178
192
  end
179
193
  end
180
194
  h
181
195
  end
182
196
 
183
- # return a hash that describe the end result
197
+ def add_command_want_to_hash(hash, item)
198
+ cci = item['cCI']
199
+ hash[cci] ||= {}
200
+ co = item['cO']
201
+ hash[cci][co] ||= {}
202
+ n = item['n']
203
+ v = item['v']
204
+ hash[cci][co][n] = v || :any
205
+ end
206
+
207
+ def add_status_want_to_hash(hash, item)
208
+ sci = item['sCI']
209
+ hash[sci] ||= {}
210
+ n = item['n']
211
+ s = item['s']
212
+ hash[sci][n] = s || :any
213
+ end
214
+
215
+ def add_command_result(hash, want, got)
216
+ cci = want['cCI']
217
+ hash[cci] ||= {}
218
+ co = want['cO']
219
+ hash[cci][co] ||= {}
220
+ n = want['n']
221
+ v = got ? got['v'] : nil
222
+ hash[cci][co][n] = v
223
+ end
224
+
225
+ def add_status_result(hash, want, got)
226
+ sci = want['sCI']
227
+ hash[sci] ||= {}
228
+ n = want['n']
229
+ s = got ? got['s'] : nil
230
+ hash[sci][n] = s
231
+ end
232
+
184
233
  def matcher_got_hash
185
234
  h = {}
186
235
  @matchers.each do |matcher|
187
236
  want = matcher.want
188
237
  got = matcher.got
189
238
  if want['cCI']
190
- cCI = want['cCI']
191
- h[cCI] ||= {}
192
- cO = want['cO']
193
- h[cCI][cO] ||= {}
194
- n = want['n']
195
- v = got ? got['v'] : nil
196
- h[cCI][cO][n] = v
239
+ add_command_result(h, want, got)
197
240
  elsif want['sCI']
198
- sCI = want['sCI']
199
- h[sCI] ||= {}
200
- n = want['n']
201
- s = got ? got['s'] : nil
202
- h[sCI][n] = s
241
+ add_status_result(h, want, got)
203
242
  end
204
243
  end
205
244
  h
@@ -207,7 +246,7 @@ module RSMP
207
246
 
208
247
  # log when we end collecting
209
248
  def log_complete
210
- @distributor.log "#{identifier}: Completed with #{matcher_got_hash.to_s}", level: :collect
249
+ @distributor.log "#{identifier}: Completed with #{matcher_got_hash}", level: :collect
211
250
  end
212
251
  end
213
252
  end
@@ -1,24 +1,24 @@
1
1
  module RSMP
2
2
  # Base class for waiting for status updates or responses
3
3
  class StatusCollector < StateCollector
4
- def initialize proxy, want, options={}
4
+ def initialize(proxy, want, options = {})
5
5
  type = []
6
6
  type << 'StatusUpdate' unless options[:updates] == false
7
7
  type << 'StatusResponse' unless options[:reponses] == false
8
8
 
9
- super proxy, want, options.merge(
9
+ super(proxy, want, options.merge(
10
10
  title: 'status response',
11
11
  filter: RSMP::Filter.new(ingoing: true, outgoing: false, type: type)
12
- )
12
+ ))
13
13
  end
14
14
 
15
- def build_matcher want
15
+ def build_matcher(want)
16
16
  RSMP::StatusMatcher.new want
17
17
  end
18
18
 
19
19
  # Get items, in our case status values
20
- def get_items message
20
+ def get_items(message)
21
21
  message.attributes['sS'] || []
22
22
  end
23
23
  end
24
- end
24
+ end
@@ -1,12 +1,17 @@
1
1
  module RSMP
2
- # Match a specific status response or update
2
+ # Match a specific status
3
3
  class StatusMatcher < Matcher
4
- # Match a status value against a matcher
5
- def match? item
4
+ def match_code(item)
6
5
  return nil if @want['sCI'] && @want['sCI'] != item['sCI']
7
6
  return nil if @want['cO'] && @want['cO'] != item['cO']
8
7
  return nil if @want['n'] && @want['n'] != item['n']
8
+
9
+ true
10
+ end
11
+
12
+ def match_value?(item)
9
13
  return false if @want['q'] && @want['q'] != item['q']
14
+
10
15
  if @want['s'].is_a? Regexp
11
16
  return false if item['s'] !~ @want['s']
12
17
  elsif @want['s']
@@ -14,5 +19,11 @@ module RSMP
14
19
  end
15
20
  true
16
21
  end
22
+
23
+ def match(item)
24
+ return nil unless match_code(item)
25
+
26
+ match_value?(item)
27
+ end
17
28
  end
18
- end
29
+ end
@@ -1,17 +1,13 @@
1
1
  module RSMP
2
-
3
2
  # The state of an alarm on a component.
4
3
  # The alarm state is for a particular alarm code,
5
4
  # a component typically have an alarm state for each
6
5
  # alarm code that is defined for the component type.
7
-
8
6
  class AlarmState
9
7
  attr_reader :component_id, :code, :acknowledged, :suspended, :active, :timestamp, :category, :priority, :rvs
10
8
 
11
- def self.create_from_message component, message
12
- self.new(
13
- component: component,
14
- code: message.attribute("aCId"),
9
+ def self.create_from_message(component, message)
10
+ options = {
15
11
  timestamp: RSMP::Clock.parse(message.attribute('aTs')),
16
12
  acknowledged: message.attribute('ack') == 'Acknowledged',
17
13
  suspended: message.attribute('aS') == 'Suspended',
@@ -19,22 +15,21 @@ module RSMP
19
15
  category: message.attribute('cat'),
20
16
  priority: message.attribute('pri').to_i,
21
17
  rvs: message.attribute('rvs')
22
- )
18
+ }
19
+ new(component: component, code: message.attribute('aCId'), **options)
23
20
  end
24
21
 
25
- def initialize component:, code:,
26
- suspended: false, acknowledged: false, active: false, timestamp: nil,
27
- category: 'D', priority: 2, rvs: []
22
+ def initialize(component:, code:, **options)
28
23
  @component = component
29
24
  @component_id = component.c_id
30
25
  @code = code
31
- @suspended = !!suspended
32
- @acknowledged = !!acknowledged
33
- @active = !!active
34
- @timestamp = timestamp
35
- @category = category || 'D'
36
- @priority = priority || 2
37
- @rvs = rvs
26
+ @suspended = options[:suspended] == true
27
+ @acknowledged = options[:acknowledged] == true
28
+ @active = options[:active] == true
29
+ @timestamp = options[:timestamp]
30
+ @category = options[:category] || 'D'
31
+ @priority = options[:priority] || 2
32
+ @rvs = options[:rvs] || []
38
33
  end
39
34
 
40
35
  def to_hash
@@ -52,19 +47,22 @@ module RSMP
52
47
  end
53
48
 
54
49
  def acknowledge
55
- change, @acknowledged = !@acknowledged, true
50
+ change = !@acknowledged
51
+ @acknowledged = true
56
52
  update_timestamp if change
57
53
  change
58
54
  end
59
55
 
60
56
  def suspend
61
- change, @suspended = !@suspended, true
57
+ change = !@suspended
58
+ @suspended = true
62
59
  update_timestamp if change
63
60
  change
64
61
  end
65
62
 
66
63
  def resume
67
- change, @suspended = @suspended, false
64
+ change = @suspended
65
+ @suspended = false
68
66
  update_timestamp if change
69
67
  change
70
68
  end
@@ -73,29 +71,33 @@ module RSMP
73
71
  # is when it's activated. See:
74
72
  # https://rsmp-nordic.org/rsmp_specifications/core/3.2.0/applicability/basic_structure.html#alarm-status
75
73
  def activate
76
- change, @active, @acknowledged = !@active, true, false
74
+ change = !@active
75
+ @active = true
76
+ @acknowledged = false
77
77
  update_timestamp if change
78
78
  change
79
79
  end
80
80
 
81
81
  def deactivate
82
- change, @active = @active, false
82
+ change = @active
83
+ @active = false
83
84
  update_timestamp if change
84
85
  change
85
86
  end
86
-
87
+
87
88
  def update_timestamp
88
89
  @timestamp = @component.now
89
90
  end
90
91
 
91
- def differ_from_message? message
92
- return true if RSMP::Clock.to_s(@timestamp) != message.attribute('aTs')
93
- return true if message.attribute('ack') && @acknowledged != (message.attribute('ack').downcase == 'acknowledged')
94
- return true if message.attribute('sS') && @suspended != (message.attribute('sS').downcase == 'suspended')
95
- return true if message.attribute('aS') && @active != (message.attribute('aS').downcase == 'active')
96
- return true if message.attribute('cat') && @category != message.attribute('cat')
97
- return true if message.attribute('pri') && @priority != message.attribute('pri').to_i
98
- #return true @rvs = message.attribute('rvs')
92
+ def differ_from_message?(message)
93
+ return true if timestamp_differs?(message)
94
+ return true if acknowledgment_differs?(message)
95
+ return true if suspension_differs?(message)
96
+ return true if activity_differs?(message)
97
+ return true if category_differs?(message)
98
+ return true if priority_differs?(message)
99
+
100
+ # return true @rvs = message.attribute('rvs')
99
101
  false
100
102
  end
101
103
 
@@ -103,20 +105,20 @@ module RSMP
103
105
  @timestamp = nil
104
106
  end
105
107
 
106
- def older_message? message
107
- return false if @timestamp == nil
108
+ def older_message?(message)
109
+ return false if @timestamp.nil?
110
+
108
111
  RSMP::Clock.parse(message.attribute('aTs')) < @timestamp
109
112
  end
110
113
 
111
114
  # update from rsmp message
112
115
  # component id, alarm code and specialization are not updated
113
- def update_from_message message
116
+ def update_from_message(message)
114
117
  unless differ_from_message? message
115
- raise RepeatedAlarmError.new("no changes from previous alarm #{message.m_id_short}")
116
- end
117
- if older_message? message
118
- raise TimestampError.new("timestamp is earlier than previous alarm #{message.m_id_short}")
118
+ raise RepeatedAlarmError,
119
+ "no changes from previous alarm #{message.m_id_short}"
119
120
  end
121
+ raise TimestampError, "timestamp is earlier than previous alarm #{message.m_id_short}" if older_message? message
120
122
  ensure
121
123
  @timestamp = RSMP::Clock.parse message.attribute('aTs')
122
124
  @acknowledged = message.attribute('ack') == 'True'
@@ -126,5 +128,41 @@ module RSMP
126
128
  @priority = message.attribute('pri').to_i
127
129
  @rvs = message.attribute('rvs')
128
130
  end
131
+
132
+ private
133
+
134
+ def timestamp_differs?(message)
135
+ RSMP::Clock.to_s(@timestamp) != message.attribute('aTs')
136
+ end
137
+
138
+ def acknowledgment_differs?(message)
139
+ return false unless message.attribute('ack')
140
+
141
+ @acknowledged != (message.attribute('ack').downcase == 'acknowledged')
142
+ end
143
+
144
+ def suspension_differs?(message)
145
+ return false unless message.attribute('sS')
146
+
147
+ @suspended != (message.attribute('sS').downcase == 'suspended')
148
+ end
149
+
150
+ def activity_differs?(message)
151
+ return false unless message.attribute('aS')
152
+
153
+ @active != (message.attribute('aS').downcase == 'active')
154
+ end
155
+
156
+ def category_differs?(message)
157
+ return false unless message.attribute('cat')
158
+
159
+ @category != message.attribute('cat')
160
+ end
161
+
162
+ def priority_differs?(message)
163
+ return false unless message.attribute('pri')
164
+
165
+ @priority != message.attribute('pri').to_i
166
+ end
129
167
  end
130
168
  end
@@ -1,19 +1,19 @@
1
1
  module RSMP
2
2
  # RSMP component
3
3
  class Component < ComponentBase
4
- def initialize node:, id:, ntsOId: nil, xNId: nil, grouped: false
4
+ def initialize(node:, id:, ntsoid: nil, xnid: nil, grouped: false)
5
5
  super
6
6
  end
7
7
 
8
- def handle_command command_code, arg
9
- raise UnknownCommand.new "Command #{command_code} not implemented by #{self.class}"
8
+ def handle_command(command_code, _arg)
9
+ raise UnknownCommand, "Command #{command_code} not implemented by #{self.class}"
10
10
  end
11
11
 
12
- def get_status status_code, status_name=nil, options={}
13
- raise UnknownStatus.new "Status #{status_code}/#{status_name} not implemented by #{self.class}"
12
+ def get_status(status_code, status_name = nil, _options = {})
13
+ raise UnknownStatus, "Status #{status_code}/#{status_name} not implemented by #{self.class}"
14
14
  end
15
15
 
16
- def acknowledge_alarm alarm_code
16
+ def acknowledge_alarm(alarm_code)
17
17
  alarm = get_alarm_state alarm_code
18
18
  if alarm.acknowledge
19
19
  log "Acknowledging alarm #{alarm_code}", level: :info
@@ -23,17 +23,17 @@ module RSMP
23
23
  end
24
24
  end
25
25
 
26
- def suspend_alarm alarm_code
26
+ def suspend_alarm(alarm_code)
27
27
  alarm = get_alarm_state alarm_code
28
28
  if alarm.suspend
29
29
  log "Suspending alarm #{alarm_code}", level: :info
30
30
  @node.alarm_suspended_or_resumed alarm
31
31
  else
32
32
  log "Alarm #{alarm_code} already suspended", level: :info
33
- end
33
+ end
34
34
  end
35
35
 
36
- def resume_alarm alarm_code
36
+ def resume_alarm(alarm_code)
37
37
  alarm = get_alarm_state alarm_code
38
38
  if alarm.resume
39
39
  log "Resuming alarm #{alarm_code}", level: :info
@@ -43,22 +43,22 @@ module RSMP
43
43
  end
44
44
  end
45
45
 
46
- def activate_alarm alarm_code
46
+ def activate_alarm(alarm_code)
47
47
  alarm = get_alarm_state alarm_code
48
48
  return unless alarm.activate
49
+
49
50
  log "Activating alarm #{alarm_code}", level: :info
50
51
  @node.alarm_activated_or_deactivated alarm
51
52
  end
52
53
 
53
- def deactivate_alarm alarm_code
54
+ def deactivate_alarm(alarm_code)
54
55
  alarm = get_alarm_state alarm_code
55
56
  return unless alarm.deactivate
57
+
56
58
  log "Deactivating alarm #{alarm_code}", level: :info
57
59
  @node.alarm_activated_or_deactivated alarm
58
60
  end
59
61
 
60
- def status_updates_sent
61
- end
62
-
62
+ def status_updates_sent; end
63
63
  end
64
- end
64
+ end