Module: RSMP::SupervisorProxy::Modules::StatusUpdates

Included in:
Status
Defined in:
lib/rsmp/proxy/supervisor/modules/status_updates.rb

Overview

Periodic and on-change status update handling.

Defined Under Namespace

Classes: PrecomputedStatusValue

Instance Method Summary collapse

Instance Method Details

#add_status_update(update_list, component_id, code, name, value) ⇒ Object



86
87
88
89
90
# File 'lib/rsmp/proxy/supervisor/modules/status_updates.rb', line 86

def add_status_update(update_list, component_id, code, name, value)
  update_list[component_id] ||= {}
  update_list[component_id][code] ||= {}
  update_list[component_id][code][name] = value
end

#build_status_item(component, code, status_name, value) ⇒ Object



112
113
114
115
# File 'lib/rsmp/proxy/supervisor/modules/status_updates.rb', line 112

def build_status_item(component, code, status_name, value)
  value, quality = status_item_value(component, code, status_name, value)
  { 'sCI' => code, 'n' => status_name, 's' => rsmpify_value(value, quality), 'q' => quality }
end

#build_status_list(component, by_code) ⇒ Object



96
97
98
99
100
101
102
# File 'lib/rsmp/proxy/supervisor/modules/status_updates.rb', line 96

def build_status_list(component, by_code)
  by_code.each_pair.with_object([]) do |(code, names), ss|
    each_status_name(names) do |status_name, value|
      ss << build_status_item(component, code, status_name, value)
    end
  end
end

#check_on_change_update(subscription, component, code, name) ⇒ Object



24
25
26
27
28
29
30
# File 'lib/rsmp/proxy/supervisor/modules/status_updates.rb', line 24

def check_on_change_update(subscription, component, code, name)
  return [nil, false] unless subscription[:interval].zero?

  current = current_status_value(component, code, name)
  last_sent = fetch_last_sent_status component.c_id, code, name
  [current, encode_status_value(code, name, current) != last_sent]
end

#check_status_subscription(subscription, component, code, name, now) ⇒ Object



52
53
54
55
56
57
58
59
# File 'lib/rsmp/proxy/supervisor/modules/status_updates.rb', line 52

def check_status_subscription(subscription, component, code, name, now)
  current, should_send = check_on_change_update(subscription, component, code, name)
  should_send ||= interval_update_due?(subscription, now) if subscription[:interval].positive?
  return [nil, false] unless should_send

  subscription[:last_sent_at] = now
  [current, true]
end

#collect_component_status_updates(update_list, component_id, by_code, now) ⇒ Object



73
74
75
76
77
78
79
80
81
82
83
84
# File 'lib/rsmp/proxy/supervisor/modules/status_updates.rb', line 73

def collect_component_status_updates(update_list, component_id, by_code, now)
  component = @site.find_component component_id
  by_code.each_pair do |code, by_name|
    by_name.each_pair do |name, subscription|
      current, should_send = check_status_subscription(subscription, component, code, name, now)
      next unless should_send

      value = precomputed_status_value(subscription, current)
      add_status_update(update_list, component.c_id, code, name, value)
    end
  end
end

#current_status_value(component, code, name) ⇒ Object



32
33
34
35
36
37
# File 'lib/rsmp/proxy/supervisor/modules/status_updates.rb', line 32

def current_status_value(component, code, name)
  return unless component

  value, quality = *(component.get_status code, name)
  rsmpify_value(value, quality)
end

#each_status_name(names, &block) ⇒ Object



104
105
106
107
108
109
110
# File 'lib/rsmp/proxy/supervisor/modules/status_updates.rb', line 104

def each_status_name(names, &block)
  if names.respond_to?(:each_pair)
    names.each_pair(&block)
  else
    names.each { |status_name| block.call(status_name, nil) }
  end
end

#encode_status_value(code, name, value) ⇒ Object



39
40
41
42
43
44
# File 'lib/rsmp/proxy/supervisor/modules/status_updates.rb', line 39

def encode_status_value(code, name, value)
  message = { 'type' => 'StatusUpdate', 'sS' => [{ 'sCI' => code, 'n' => name }] }
  type, version = RSMP::Schema.resolve_sxl(message, schemas: schemas)
  descriptor = RSMP::Schema.sxl_argument_descriptor(type, version, :statuses, code, name)
  descriptor ? RSMP::Message.encode_sxl_value(value, descriptor) : value
end

#fetch_last_sent_status(component, code, name) ⇒ Object



8
9
10
# File 'lib/rsmp/proxy/supervisor/modules/status_updates.rb', line 8

def fetch_last_sent_status(component, code, name)
  @last_status_sent&.dig component, code, name
end

#interval_update_due?(subscription, now) ⇒ Boolean

Returns:

  • (Boolean)


46
47
48
49
50
# File 'lib/rsmp/proxy/supervisor/modules/status_updates.rb', line 46

def interval_update_due?(subscription, now)
  return true if subscription[:last_sent_at].nil?

  (now - subscription[:last_sent_at]) >= subscription[:interval]
end

#precomputed_status_value(subscription, current) ⇒ Object



92
93
94
# File 'lib/rsmp/proxy/supervisor/modules/status_updates.rb', line 92

def precomputed_status_value(subscription, current)
  PrecomputedStatusValue.new(current) if subscription[:interval].zero?
end

#send_component_status_update(component_id, by_code, now) ⇒ Object



133
134
135
136
137
138
139
140
141
142
143
144
# File 'lib/rsmp/proxy/supervisor/modules/status_updates.rb', line 133

def send_component_status_update(component_id, by_code, now)
  component = @site.find_component component_id
  update = StatusUpdate.new({
                              'cId' => component_id,
                              'sTs' => now,
                              'sS' => build_status_list(component, by_code)
                            })
  apply_nts_message_attributes update
  send_message update
  store_last_sent_status update
  component.status_updates_sent
end

#send_status_updates(update_list) ⇒ Object



126
127
128
129
130
131
# File 'lib/rsmp/proxy/supervisor/modules/status_updates.rb', line 126

def send_status_updates(update_list)
  now = clock.to_s
  update_list.each_pair do |component_id, by_code|
    send_component_status_update(component_id, by_code, now)
  end
end

#status_item_value(component, code, status_name, value) ⇒ Object



117
118
119
120
121
122
123
124
# File 'lib/rsmp/proxy/supervisor/modules/status_updates.rb', line 117

def status_item_value(component, code, status_name, value)
  return [value.value, 'recent'] if value.is_a?(PrecomputedStatusValue)

  component.get_status code, status_name
rescue UnknownStatus => e
  log e.to_s, level: :warning
  [nil, 'unknown']
end

#status_update_timer(now) ⇒ Object



61
62
63
# File 'lib/rsmp/proxy/supervisor/modules/status_updates.rb', line 61

def status_update_timer(now)
  send_status_updates status_updates_due(now)
end

#status_updates_due(now) ⇒ Object



65
66
67
68
69
70
71
# File 'lib/rsmp/proxy/supervisor/modules/status_updates.rb', line 65

def status_updates_due(now)
  update_list = {}
  @status_subscriptions.each_pair do |component_id, by_code|
    collect_component_status_updates(update_list, component_id, by_code, now)
  end
  update_list
end

#store_last_sent_status(message) ⇒ Object



12
13
14
15
16
17
# File 'lib/rsmp/proxy/supervisor/modules/status_updates.rb', line 12

def store_last_sent_status(message)
  component_id = message.attribute('cId')
  @last_status_sent ||= {}
  @last_status_sent[component_id] ||= {}
  message.attribute('sS').each { |item| store_last_sent_status_item(component_id, item) }
end

#store_last_sent_status_item(component_id, item) ⇒ Object



19
20
21
22
# File 'lib/rsmp/proxy/supervisor/modules/status_updates.rb', line 19

def store_last_sent_status_item(component_id, item)
  @last_status_sent[component_id][item['sCI']] ||= {}
  @last_status_sent[component_id][item['sCI']][item['n']] = item['s']
end