Class: RSMP::Component

Inherits:
Object
  • Object
show all
Includes:
Inspect
Defined in:
lib/rsmp/component.rb

Overview

Class that represents an RMSP component. Currently this class is used by both SiteProxy and SupervisorProxy, and can therefore represent either a local or remote (proxy) component.

Constant Summary collapse

AGGREGATED_STATUS_KEYS =
[ :local_control,
:communication_distruption,
:high_priority_alarm,
:medium_priority_alarm,
:low_priority_alarm,
:normal,
:rest,
:not_connected ]

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from Inspect

#inspect, #inspector

Constructor Details

#initialize(node:, id:, grouped: false) ⇒ Component

Returns a new instance of Component.



21
22
23
24
25
26
27
28
29
# File 'lib/rsmp/component.rb', line 21

def initialize node:, id:, grouped: false
  @c_id = id
  @node = node
  @grouped = grouped
  @alarms = {}
  @statuses = {}
  @subscribes = {}
  clear_aggregated_status
end

Instance Attribute Details

#aggregated_statusObject (readonly)

Returns the value of attribute aggregated_status.



10
11
12
# File 'lib/rsmp/component.rb', line 10

def aggregated_status
  @aggregated_status
end

#aggregated_status_boolsObject (readonly)

Returns the value of attribute aggregated_status_bools.



10
11
12
# File 'lib/rsmp/component.rb', line 10

def aggregated_status_bools
  @aggregated_status_bools
end

#alarmsObject (readonly)

Returns the value of attribute alarms.



10
11
12
# File 'lib/rsmp/component.rb', line 10

def alarms
  @alarms
end

#c_idObject (readonly)

Returns the value of attribute c_id.



10
11
12
# File 'lib/rsmp/component.rb', line 10

def c_id
  @c_id
end

#groupedObject (readonly)

Returns the value of attribute grouped.



10
11
12
# File 'lib/rsmp/component.rb', line 10

def grouped
  @grouped
end

#nodeObject (readonly)

Returns the value of attribute node.



10
11
12
# File 'lib/rsmp/component.rb', line 10

def node
  @node
end

#statusesObject (readonly)

Returns the value of attribute statuses.



10
11
12
# File 'lib/rsmp/component.rb', line 10

def statuses
  @statuses
end

Instance Method Details

#aggregated_status_changed(options = {}) ⇒ Object



63
64
65
# File 'lib/rsmp/component.rb', line 63

def aggregated_status_changed options={}
  @node.aggregated_status_changed self, options
end

#clear_aggregated_statusObject



31
32
33
34
35
# File 'lib/rsmp/component.rb', line 31

def clear_aggregated_status
  @aggregated_status = []
  @aggregated_status_bools = Array.new(8,false)
  @aggregated_status_bools[5] = true
end

#get_status(status_code, status_name = nil) ⇒ Object



76
77
78
# File 'lib/rsmp/component.rb', line 76

def get_status status_code, status_name=nil
  raise UnknownStatus.new "Status #{status_code}/#{status_name} not implemented by #{self.class}"
end

#handle_alarm(message) ⇒ Object



80
81
82
83
84
85
86
87
88
89
90
91
92
93
# File 'lib/rsmp/component.rb', line 80

def handle_alarm message
  code = message.attribute('aCId')
  previous = @alarms[code]
  if previous
    unless message.differ?(previous)
      raise RepeatedAlarmError.new("no changes from previous alarm #{previous.m_id_short}")
    end
    if Time.parse(message.attribute('aTs')) < Time.parse(previous.attribute('aTs'))
      raise TimestampError.new("timestamp is earlier than previous alarm #{previous.m_id_short}")
    end
  end
ensure
  @alarms[code] = message
end

#handle_command(command_code, arg) ⇒ Object



72
73
74
# File 'lib/rsmp/component.rb', line 72

def handle_command command_code, arg
  raise UnknownCommand.new "Command #{command_code} not implemented by #{self.class}"
end

#handle_status_response(message) ⇒ Object

Handle an incoming status respone, by storing the values



96
97
98
# File 'lib/rsmp/component.rb', line 96

def handle_status_response message
  store_status message, check_repeated: false
end

#handle_status_subscribe(status_list) ⇒ Object

Our proxy subscribed to status updates Store update rates, so we can check for repeated alarm if we asked for updates only when there's a change, not on a regular interval. After subscribing, an update status us send regarless of whether values changes, and we store that.



110
111
112
113
114
115
116
117
118
119
120
121
122
123
# File 'lib/rsmp/component.rb', line 110

def handle_status_subscribe status_list
  status_list.each do |item|
    sCI, n, uRt = item['sCI'], item['n'], item['uRt']

    # record the update rate, so we can check for repeated status values if rate is zero
    @subscribes[sCI] ||= {}
    @subscribes[sCI][n] = {'uRt'=>uRt}

    # record that we expect an upeate, even though the value might not change
    @statuses[sCI] ||= {}
    @statuses[sCI][n] ||= {}
    @statuses[sCI][n][:initial] = true
  end
end

#handle_status_unsubscribe(status_list) ⇒ Object

Our proxy unsubscribed to status updates. Update our list of update rates.



127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
# File 'lib/rsmp/component.rb', line 127

def handle_status_unsubscribe status_list
  status_list.each do |item|
    sCI, n = item['sCI'], item['n']
    if @subscribes[sCI]
      @subscribes[sCI].delete n
    end
    if @subscribes[sCI].empty?
      @subscribes.delete sCI
    end

    # remove any mark that would allow the next update to be a repeat
    item = @statuses.dig sCI, n
    item.delete(:initial) if item
  end
end

#handle_status_update(message) ⇒ Object

Handle an incoming status update, by storing the values



101
102
103
# File 'lib/rsmp/component.rb', line 101

def handle_status_update message
  store_status message, check_repeated: true
end

#log(str, options) ⇒ Object



67
68
69
70
# File 'lib/rsmp/component.rb', line 67

def log str, options
  default = { component: c_id}
  @node.log str, default.merge(options)
end

#set_aggregated_status(status, options = {}) ⇒ Object

Raises:

  • (InvalidArgument)


37
38
39
40
41
42
43
44
45
46
47
# File 'lib/rsmp/component.rb', line 37

def set_aggregated_status status, options={}
  status = [status] if status.is_a? Symbol
  raise InvalidArgument unless status.is_a? Array
  input = status & AGGREGATED_STATUS_KEYS
  if input != @aggregated_status
    AGGREGATED_STATUS_KEYS.each_with_index do |key,index|
      @aggregated_status_bools[index] = status.include?(key)
    end
    aggregated_status_changed options
  end
end

#set_aggregated_status_bools(status) ⇒ Object

Raises:

  • (InvalidArgument)


49
50
51
52
53
54
55
56
57
58
59
60
61
# File 'lib/rsmp/component.rb', line 49

def set_aggregated_status_bools status
  raise InvalidArgument unless status.is_a? Array
  raise InvalidArgument unless status.size == 8
  if status != @aggregated_status_bools
    @aggregated_status = []
    AGGREGATED_STATUS_KEYS.each_with_index do |key,index|
      on = status[index] == true
      @aggregated_status_bools[index] = on
      @aggregated_status << key if on
    end
    aggregated_status_changed
  end
end

#store_status(message, check_repeated:) ⇒ Object

Store the latest status update values, optionally checking that we're not receiving unchanged values if we're subscribed wit updates only on change



146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
# File 'lib/rsmp/component.rb', line 146

def store_status message, check_repeated:
  message.attribute('sS').each do |item|
    sCI, n, s, q = item['sCI'], item['n'], item['s'], item['q']
    uRt = @subscribes.dig(sCI,n,'uRt')
    new_values = {'s'=>s,'q'=>q}
    old_values = @statuses.dig(sCI,n)
    if check_repeated && uRt.to_i == 0
      if new_values == old_values
        raise RSMP::RepeatedStatusError.new "no change for #{sCI} '#{n}'"
      end
    end
    @statuses[sCI] ||= {}
    @statuses[sCI][n] = new_values
  end
end