rsmp 0.40.0 → 0.41.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +645 -3
- data/Gemfile.lock +12 -12
- data/config/supervisor.yaml +1 -1
- data/documentation/configuration.md +67 -1
- data/lib/rsmp/cli.rb +2 -2
- data/lib/rsmp/helpers/inspect.rb +1 -1
- data/lib/rsmp/node/supervisor/modules/configuration.rb +10 -8
- data/lib/rsmp/node/supervisor/modules/connection.rb +14 -5
- data/lib/rsmp/node/supervisor/supervisor.rb +7 -0
- data/lib/rsmp/options/schemas/supervisor.json +6 -3
- data/lib/rsmp/options/schemas/supervisor_site.json +46 -0
- data/lib/rsmp/options/schemas/traffic_controller_site.json +3 -2
- data/lib/rsmp/options/supervisor_options.rb +4 -2
- data/lib/rsmp/proxy/proxy.rb +1 -0
- data/lib/rsmp/proxy/site/modules/alarms.rb +58 -0
- data/lib/rsmp/proxy/site/modules/status.rb +9 -0
- data/lib/rsmp/proxy/site/site_proxy.rb +12 -7
- data/lib/rsmp/tlc/modules/inputs.rb +30 -1
- data/lib/rsmp/tlc/proxy/control.rb +158 -0
- data/lib/rsmp/tlc/proxy/detectors.rb +58 -0
- data/lib/rsmp/tlc/proxy/io.rb +119 -0
- data/lib/rsmp/tlc/proxy/plans.rb +226 -0
- data/lib/rsmp/tlc/proxy/status.rb +120 -0
- data/lib/rsmp/tlc/proxy/system.rb +58 -0
- data/lib/rsmp/tlc/traffic_controller_proxy.rb +143 -0
- data/lib/rsmp/tlc/traffic_controller_site.rb +10 -1
- data/lib/rsmp/version.rb +1 -1
- data/lib/rsmp.rb +7 -1
- data/rsmp.gemspec +1 -1
- metadata +11 -4
- data/lib/rsmp/convert/export/json_schema.rb +0 -214
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
# Proxy for handling communication with a remote Traffic Light Controller (TLC).
|
|
2
|
+
# Provides high-level methods for interacting with TLC functionality.
|
|
3
|
+
# Acts as a mirror of the remote TLC by automatically subscribing to status updates.
|
|
4
|
+
|
|
5
|
+
module RSMP
|
|
6
|
+
module TLC
|
|
7
|
+
# Proxy for handling communication with a remote traffic light controller.
|
|
8
|
+
class TrafficControllerProxy < SiteProxy
|
|
9
|
+
include Proxy::Control
|
|
10
|
+
include Proxy::IO
|
|
11
|
+
include Proxy::Plans
|
|
12
|
+
include Proxy::Status
|
|
13
|
+
include Proxy::Detectors
|
|
14
|
+
include Proxy::System
|
|
15
|
+
|
|
16
|
+
attr_reader :timeplan_source, :timeplan, :timeouts,
|
|
17
|
+
:functional_position, :yellow_flash, :traffic_situation
|
|
18
|
+
|
|
19
|
+
# Backwards-compatible accessors expected by tests and callers
|
|
20
|
+
def current_plan
|
|
21
|
+
@timeplan
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def plan_source
|
|
25
|
+
@timeplan_source
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def initialize(options)
|
|
29
|
+
super
|
|
30
|
+
@timeplan_source = nil
|
|
31
|
+
@timeplan = nil
|
|
32
|
+
@functional_position = nil
|
|
33
|
+
@yellow_flash = nil
|
|
34
|
+
@traffic_situation = nil
|
|
35
|
+
@timeouts = node.supervisor_settings.dig('default', 'timeouts') || {}
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def subscribe_to_timeplan(options: {})
|
|
39
|
+
validate_ready 'subscribe to timeplan'
|
|
40
|
+
|
|
41
|
+
status_list = [
|
|
42
|
+
{ 'sCI' => 'S0014', 'n' => 'status', 'uRt' => '0' },
|
|
43
|
+
{ 'sCI' => 'S0014', 'n' => 'source', 'uRt' => '0' }
|
|
44
|
+
]
|
|
45
|
+
status_list.each { |item| item['sOc'] = true } if use_soc?
|
|
46
|
+
|
|
47
|
+
merged_options = @timeouts.merge(options)
|
|
48
|
+
|
|
49
|
+
raise 'TLC main component not found' unless main
|
|
50
|
+
|
|
51
|
+
subscribe_to_status main.c_id, status_list, merged_options
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# Override status update processing to automatically store cached status values.
|
|
55
|
+
def process_status_update(message)
|
|
56
|
+
super
|
|
57
|
+
|
|
58
|
+
status_values = message.attribute('sS')
|
|
59
|
+
return unless status_values
|
|
60
|
+
|
|
61
|
+
status_values.each { |item| cache_status_item(item) }
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# Get all timeplan attributes stored in the main ComponentProxy.
|
|
65
|
+
def timeplan_attributes
|
|
66
|
+
main&.statuses&.dig('S0014') || {}
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# Returns true if sOc (send on change) should be used.
|
|
70
|
+
# sOc is supported in RSMP core version 3.1.5 and later.
|
|
71
|
+
def use_soc?
|
|
72
|
+
return false unless core_version
|
|
73
|
+
|
|
74
|
+
RSMP::Proxy.version_meets_requirement?(core_version, '>=3.1.5')
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
private
|
|
78
|
+
|
|
79
|
+
# Automatically subscribe to key TLC statuses to keep proxy in sync.
|
|
80
|
+
def auto_subscribe_to_statuses
|
|
81
|
+
return unless main
|
|
82
|
+
|
|
83
|
+
subscribe_to_timeplan
|
|
84
|
+
subscribe_to_key_statuses
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
# Look up security code for a given level from site settings.
|
|
88
|
+
# Expects @site_settings['security_codes'] = { 1 => 'code1', 2 => 'code2' }
|
|
89
|
+
def security_code_for(level)
|
|
90
|
+
codes = @site_settings&.dig('security_codes') || {}
|
|
91
|
+
code = codes[level] || codes[level.to_s]
|
|
92
|
+
raise ArgumentError, "Security code for level #{level} is not configured" unless code
|
|
93
|
+
|
|
94
|
+
code
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
# Send a command and, if confirm: or confirm!: is present in options, wait for
|
|
98
|
+
# confirming status updates afterwards.
|
|
99
|
+
#
|
|
100
|
+
# confirm_description - human-readable label used in log output
|
|
101
|
+
# confirm_status_list - status items to wait for (passed to wait_for_status)
|
|
102
|
+
# component_id - component to wait on (defaults to main)
|
|
103
|
+
#
|
|
104
|
+
# If options[:confirm] is set, timeout errors are silently swallowed.
|
|
105
|
+
# If options[:confirm!] is set, timeout errors are raised.
|
|
106
|
+
def send_command_with_confirm(component_id, command_list, options, confirm_description, confirm_status_list)
|
|
107
|
+
result = send_command component_id, command_list, @timeouts.merge(options.except(:confirm, :confirm!))
|
|
108
|
+
|
|
109
|
+
confirm_opts = options[:confirm] || options[:confirm!]
|
|
110
|
+
return result unless confirm_opts
|
|
111
|
+
return result if confirm_status_list.nil? || confirm_status_list.empty?
|
|
112
|
+
|
|
113
|
+
timeout = confirm_opts.is_a?(Hash) ? confirm_opts[:timeout] : nil
|
|
114
|
+
wait_kwargs = { timeout: timeout }.compact
|
|
115
|
+
begin
|
|
116
|
+
wait_for_status confirm_description, confirm_status_list, **wait_kwargs
|
|
117
|
+
rescue RSMP::TimeoutError
|
|
118
|
+
raise if options[:confirm!]
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
result
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
# Process a single status item and update the corresponding cached value.
|
|
125
|
+
def cache_status_item(item)
|
|
126
|
+
case item['sCI']
|
|
127
|
+
when 'S0007' then @functional_position = item['s'] if item['n'] == 'status'
|
|
128
|
+
when 'S0011' then @yellow_flash = item['s'] if item['n'] == 'status'
|
|
129
|
+
when 'S0014' then cache_s0014_attribute(item)
|
|
130
|
+
when 'S0015' then @traffic_situation = item['s'] if item['n'] == 'status'
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
# Update cached values for S0014 (timeplan) status attributes.
|
|
135
|
+
def cache_s0014_attribute(item)
|
|
136
|
+
case item['n']
|
|
137
|
+
when 'status' then @timeplan = item['s'].to_i
|
|
138
|
+
when 'source' then @timeplan_source = item['s']
|
|
139
|
+
end
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
end
|
|
143
|
+
end
|
|
@@ -12,7 +12,7 @@ module RSMP
|
|
|
12
12
|
# setup options before calling super initializer,
|
|
13
13
|
# since build of components depend on options
|
|
14
14
|
@sxl = 'traffic_light_controller'
|
|
15
|
-
@security_codes = options
|
|
15
|
+
@security_codes = normalize_security_codes(options.dig(:site_settings, 'security_codes'))
|
|
16
16
|
@interval = options[:site_settings].dig('intervals', 'timer') || 1
|
|
17
17
|
@startup_sequence = options[:site_settings]['startup_sequence'] || 'efg'
|
|
18
18
|
build_plans options[:site_settings]['signal_plans']
|
|
@@ -131,6 +131,15 @@ module RSMP
|
|
|
131
131
|
raise MessageRejected, "Wrong security code for level #{level}"
|
|
132
132
|
end
|
|
133
133
|
|
|
134
|
+
def normalize_security_codes(codes)
|
|
135
|
+
return {} unless codes.is_a?(Hash)
|
|
136
|
+
|
|
137
|
+
codes.each_with_object({}) do |(key, value), memo|
|
|
138
|
+
int_key = key.is_a?(String) && key.match?(/^\d+$/) ? key.to_i : key
|
|
139
|
+
memo[int_key] = value
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
|
|
134
143
|
def change_security_code(level, old_code, new_code)
|
|
135
144
|
verify_security_code level, old_code
|
|
136
145
|
@security_codes[level] = new_code
|
data/lib/rsmp/version.rb
CHANGED
data/lib/rsmp.rb
CHANGED
|
@@ -88,6 +88,13 @@ require_relative 'rsmp/tlc/modules/display'
|
|
|
88
88
|
require_relative 'rsmp/tlc/modules/helpers'
|
|
89
89
|
require_relative 'rsmp/tlc/startup_sequence'
|
|
90
90
|
require_relative 'rsmp/tlc/traffic_controller_site'
|
|
91
|
+
require_relative 'rsmp/tlc/proxy/control'
|
|
92
|
+
require_relative 'rsmp/tlc/proxy/detectors'
|
|
93
|
+
require_relative 'rsmp/tlc/proxy/io'
|
|
94
|
+
require_relative 'rsmp/tlc/proxy/plans'
|
|
95
|
+
require_relative 'rsmp/tlc/proxy/status'
|
|
96
|
+
require_relative 'rsmp/tlc/proxy/system'
|
|
97
|
+
require_relative 'rsmp/tlc/traffic_controller_proxy'
|
|
91
98
|
require_relative 'rsmp/tlc/traffic_controller'
|
|
92
99
|
require_relative 'rsmp/tlc/detector_logic'
|
|
93
100
|
require_relative 'rsmp/tlc/signal_group'
|
|
@@ -95,5 +102,4 @@ require_relative 'rsmp/tlc/signal_plan'
|
|
|
95
102
|
require_relative 'rsmp/tlc/input_states'
|
|
96
103
|
require_relative 'rsmp/tlc/signal_priority'
|
|
97
104
|
require_relative 'rsmp/convert/import/yaml'
|
|
98
|
-
require_relative 'rsmp/convert/export/json_schema'
|
|
99
105
|
require_relative 'rsmp/version'
|
data/rsmp.gemspec
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: rsmp
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.41.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Emil Tin
|
|
@@ -99,14 +99,14 @@ dependencies:
|
|
|
99
99
|
requirements:
|
|
100
100
|
- - "~>"
|
|
101
101
|
- !ruby/object:Gem::Version
|
|
102
|
-
version: '0.
|
|
102
|
+
version: '0.10'
|
|
103
103
|
type: :runtime
|
|
104
104
|
prerelease: false
|
|
105
105
|
version_requirements: !ruby/object:Gem::Requirement
|
|
106
106
|
requirements:
|
|
107
107
|
- - "~>"
|
|
108
108
|
- !ruby/object:Gem::Version
|
|
109
|
-
version: '0.
|
|
109
|
+
version: '0.10'
|
|
110
110
|
description: Easy RSMP site and supervisor communication.
|
|
111
111
|
email:
|
|
112
112
|
- zf0f@kk.dk
|
|
@@ -167,7 +167,6 @@ files:
|
|
|
167
167
|
- lib/rsmp/component/component_base.rb
|
|
168
168
|
- lib/rsmp/component/component_proxy.rb
|
|
169
169
|
- lib/rsmp/component/components.rb
|
|
170
|
-
- lib/rsmp/convert/export/json_schema.rb
|
|
171
170
|
- lib/rsmp/convert/import/yaml.rb
|
|
172
171
|
- lib/rsmp/helpers/clock.rb
|
|
173
172
|
- lib/rsmp/helpers/deep_merge.rb
|
|
@@ -190,6 +189,7 @@ files:
|
|
|
190
189
|
- lib/rsmp/options/options.rb
|
|
191
190
|
- lib/rsmp/options/schemas/site.json
|
|
192
191
|
- lib/rsmp/options/schemas/supervisor.json
|
|
192
|
+
- lib/rsmp/options/schemas/supervisor_site.json
|
|
193
193
|
- lib/rsmp/options/schemas/traffic_controller_site.json
|
|
194
194
|
- lib/rsmp/options/site_options.rb
|
|
195
195
|
- lib/rsmp/options/supervisor_options.rb
|
|
@@ -225,11 +225,18 @@ files:
|
|
|
225
225
|
- lib/rsmp/tlc/modules/startup_sequence.rb
|
|
226
226
|
- lib/rsmp/tlc/modules/system.rb
|
|
227
227
|
- lib/rsmp/tlc/modules/traffic_data.rb
|
|
228
|
+
- lib/rsmp/tlc/proxy/control.rb
|
|
229
|
+
- lib/rsmp/tlc/proxy/detectors.rb
|
|
230
|
+
- lib/rsmp/tlc/proxy/io.rb
|
|
231
|
+
- lib/rsmp/tlc/proxy/plans.rb
|
|
232
|
+
- lib/rsmp/tlc/proxy/status.rb
|
|
233
|
+
- lib/rsmp/tlc/proxy/system.rb
|
|
228
234
|
- lib/rsmp/tlc/signal_group.rb
|
|
229
235
|
- lib/rsmp/tlc/signal_plan.rb
|
|
230
236
|
- lib/rsmp/tlc/signal_priority.rb
|
|
231
237
|
- lib/rsmp/tlc/startup_sequence.rb
|
|
232
238
|
- lib/rsmp/tlc/traffic_controller.rb
|
|
239
|
+
- lib/rsmp/tlc/traffic_controller_proxy.rb
|
|
233
240
|
- lib/rsmp/tlc/traffic_controller_site.rb
|
|
234
241
|
- lib/rsmp/version.rb
|
|
235
242
|
- rsmp.gemspec
|
|
@@ -1,214 +0,0 @@
|
|
|
1
|
-
# Import SXL from YAML format
|
|
2
|
-
|
|
3
|
-
require 'yaml'
|
|
4
|
-
require 'json'
|
|
5
|
-
require 'fileutils'
|
|
6
|
-
|
|
7
|
-
module RSMP
|
|
8
|
-
module Convert
|
|
9
|
-
module Export
|
|
10
|
-
# Converts SXL (YAML) structures into JSON Schema files.
|
|
11
|
-
# Converts SXL (YAML) structures into JSON Schema files.
|
|
12
|
-
module JSONSchema
|
|
13
|
-
JSON_OPTIONS = {
|
|
14
|
-
array_nl: "\n",
|
|
15
|
-
object_nl: "\n",
|
|
16
|
-
indent: ' ',
|
|
17
|
-
space_before: ' ',
|
|
18
|
-
space: ' '
|
|
19
|
-
}.freeze
|
|
20
|
-
|
|
21
|
-
def self.output_json(item)
|
|
22
|
-
JSON.generate(item, JSON_OPTIONS)
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
def self.build_value(item)
|
|
26
|
-
out = {}
|
|
27
|
-
out['description'] = item['description'] if item['description']
|
|
28
|
-
|
|
29
|
-
if item['list']
|
|
30
|
-
build_list_value(out, item)
|
|
31
|
-
else
|
|
32
|
-
build_single_value(out, item)
|
|
33
|
-
end
|
|
34
|
-
|
|
35
|
-
out
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
def self.build_list_value(out, item)
|
|
39
|
-
case item['type']
|
|
40
|
-
when 'boolean'
|
|
41
|
-
out['$ref'] = '../../../core/3.1.1/definitions.json#/boolean_list'
|
|
42
|
-
when 'integer', 'ordinal', 'unit', 'scale', 'long'
|
|
43
|
-
out['$ref'] = '../../../core/3.1.1/definitions.json#/integer_list'
|
|
44
|
-
else
|
|
45
|
-
raise "Error: List of #{item['type']} is not supported: #{item.inspect}"
|
|
46
|
-
end
|
|
47
|
-
|
|
48
|
-
if item['values']
|
|
49
|
-
value_list = item['values'].keys.join('|')
|
|
50
|
-
out['pattern'] = /(?-mix:^(#{value_list})(?:,(#{value_list}))*$)/
|
|
51
|
-
end
|
|
52
|
-
|
|
53
|
-
puts "Warning: Pattern not support for lists: #{item.inspect}" if item['pattern']
|
|
54
|
-
end
|
|
55
|
-
|
|
56
|
-
def self.build_single_value(out, item)
|
|
57
|
-
case item['type']
|
|
58
|
-
when 'boolean'
|
|
59
|
-
out['$ref'] = '../../../core/3.1.1/definitions.json#/boolean'
|
|
60
|
-
when 'timestamp'
|
|
61
|
-
out['$ref'] = '../../../core/3.1.1/definitions.json#/timestamp'
|
|
62
|
-
when 'integer', 'ordinal', 'unit', 'scale', 'long'
|
|
63
|
-
out['$ref'] = '../../../core/3.1.1/definitions.json#/integer'
|
|
64
|
-
else # includes 'string', 'base64' and any other types
|
|
65
|
-
out['type'] = 'string'
|
|
66
|
-
end
|
|
67
|
-
|
|
68
|
-
out['enum'] = item['values'].keys.sort if item['values']
|
|
69
|
-
out['pattern'] = item['pattern'] if item['pattern']
|
|
70
|
-
end
|
|
71
|
-
|
|
72
|
-
def self.build_item(item, property_key: 'v')
|
|
73
|
-
json = { 'allOf' => [{ 'description' => item['description'] }] }
|
|
74
|
-
if item['arguments']
|
|
75
|
-
json['allOf'].first['properties'] = { 'n' => { 'enum' => item['arguments'].keys.sort } }
|
|
76
|
-
item['arguments'].each_pair do |key, argument|
|
|
77
|
-
json['allOf'] << {
|
|
78
|
-
'if' => { 'required' => ['n'], 'properties' => { 'n' => { 'const' => key } } },
|
|
79
|
-
'then' => { 'properties' => { property_key => build_value(argument) } }
|
|
80
|
-
}
|
|
81
|
-
end
|
|
82
|
-
end
|
|
83
|
-
json
|
|
84
|
-
end
|
|
85
|
-
|
|
86
|
-
def self.output_alarms(out, items)
|
|
87
|
-
list = items.keys.sort.map do |key|
|
|
88
|
-
{
|
|
89
|
-
'if' => { 'required' => ['aCId'], 'properties' => { 'aCId' => { 'const' => key } } },
|
|
90
|
-
'then' => { '$ref' => "#{key}.json" }
|
|
91
|
-
}
|
|
92
|
-
end
|
|
93
|
-
json = {
|
|
94
|
-
'properties' => {
|
|
95
|
-
'aCId' => { 'enum' => items.keys.sort },
|
|
96
|
-
'rvs' => { 'items' => { 'allOf' => list } }
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
out['alarms/alarms.json'] = output_json json
|
|
100
|
-
items.each_pair { |key, item| output_alarm out, key, item }
|
|
101
|
-
end
|
|
102
|
-
|
|
103
|
-
def self.output_alarm(out, key, item)
|
|
104
|
-
json = build_item item
|
|
105
|
-
out["alarms/#{key}.json"] = output_json json
|
|
106
|
-
end
|
|
107
|
-
|
|
108
|
-
def self.output_statuses(out, items)
|
|
109
|
-
list = [{ 'properties' => { 'sCI' => { 'enum' => items.keys.sort } } }]
|
|
110
|
-
items.keys.sort.each do |key|
|
|
111
|
-
list << {
|
|
112
|
-
'if' => { 'required' => ['sCI'], 'properties' => { 'sCI' => { 'const' => key } } },
|
|
113
|
-
'then' => { '$ref' => "#{key}.json" }
|
|
114
|
-
}
|
|
115
|
-
end
|
|
116
|
-
json = { 'properties' => { 'sS' => { 'items' => { 'allOf' => list } } } }
|
|
117
|
-
out['statuses/statuses.json'] = output_json json
|
|
118
|
-
items.each_pair { |key, item| output_status out, key, item }
|
|
119
|
-
end
|
|
120
|
-
|
|
121
|
-
def self.output_status(out, key, item)
|
|
122
|
-
json = build_item item, property_key: 's'
|
|
123
|
-
out["statuses/#{key}.json"] = output_json json
|
|
124
|
-
end
|
|
125
|
-
|
|
126
|
-
def self.output_commands(out, items)
|
|
127
|
-
list = [{ 'properties' => { 'cCI' => { 'enum' => items.keys.sort } } }]
|
|
128
|
-
items.keys.sort.each do |key|
|
|
129
|
-
list << {
|
|
130
|
-
'if' => { 'required' => ['cCI'], 'properties' => { 'cCI' => { 'const' => key } } },
|
|
131
|
-
'then' => { '$ref' => "#{key}.json" }
|
|
132
|
-
}
|
|
133
|
-
end
|
|
134
|
-
json = { 'items' => { 'allOf' => list } }
|
|
135
|
-
out['commands/commands.json'] = output_json json
|
|
136
|
-
|
|
137
|
-
json = { 'properties' => { 'arg' => { '$ref' => 'commands.json' } } }
|
|
138
|
-
out['commands/command_requests.json'] = output_json json
|
|
139
|
-
|
|
140
|
-
json = { 'properties' => { 'rvs' => { '$ref' => 'commands.json' } } }
|
|
141
|
-
out['commands/command_responses.json'] = output_json json
|
|
142
|
-
|
|
143
|
-
items.each_pair { |key, item| output_command out, key, item }
|
|
144
|
-
end
|
|
145
|
-
|
|
146
|
-
def self.output_command(out, key, item)
|
|
147
|
-
json = build_item item
|
|
148
|
-
json['allOf'].first['properties']['cO'] = { 'const' => item['command'] }
|
|
149
|
-
out["commands/#{key}.json"] = output_json json
|
|
150
|
-
end
|
|
151
|
-
|
|
152
|
-
def self.build_root_schema(meta)
|
|
153
|
-
{
|
|
154
|
-
'name' => meta['name'],
|
|
155
|
-
'description' => meta['description'],
|
|
156
|
-
'version' => meta['version'],
|
|
157
|
-
'allOf' => build_root_refs
|
|
158
|
-
}
|
|
159
|
-
end
|
|
160
|
-
|
|
161
|
-
def self.build_root_refs
|
|
162
|
-
[
|
|
163
|
-
{
|
|
164
|
-
'if' => { 'required' => ['type'], 'properties' => { 'type' => { 'const' => 'CommandRequest' } } },
|
|
165
|
-
'then' => { '$ref' => 'commands/command_requests.json' }
|
|
166
|
-
},
|
|
167
|
-
{
|
|
168
|
-
'if' => { 'required' => ['type'], 'properties' => { 'type' => { 'const' => 'CommandResponse' } } },
|
|
169
|
-
'then' => { '$ref' => 'commands/command_responses.json' }
|
|
170
|
-
},
|
|
171
|
-
{
|
|
172
|
-
'if' => { 'required' => ['type'],
|
|
173
|
-
'properties' => {
|
|
174
|
-
'type' => {
|
|
175
|
-
'enum' => %w[StatusRequest StatusResponse StatusSubscribe
|
|
176
|
-
StatusUnsubscribe StatusUpdate]
|
|
177
|
-
}
|
|
178
|
-
} },
|
|
179
|
-
'then' => { '$ref' => 'statuses/statuses.json' }
|
|
180
|
-
},
|
|
181
|
-
{
|
|
182
|
-
'if' => { 'required' => ['type'], 'properties' => { 'type' => { 'const' => 'Alarm' } } },
|
|
183
|
-
'then' => { '$ref' => 'alarms/alarms.json' }
|
|
184
|
-
}
|
|
185
|
-
]
|
|
186
|
-
end
|
|
187
|
-
|
|
188
|
-
def self.output_root(out, meta)
|
|
189
|
-
json = build_root_schema(meta)
|
|
190
|
-
out['sxl.json'] = output_json json
|
|
191
|
-
end
|
|
192
|
-
|
|
193
|
-
def self.generate(sxl)
|
|
194
|
-
out = {}
|
|
195
|
-
output_root out, sxl[:meta]
|
|
196
|
-
output_alarms out, sxl[:alarms]
|
|
197
|
-
output_statuses out, sxl[:statuses]
|
|
198
|
-
output_commands out, sxl[:commands]
|
|
199
|
-
out
|
|
200
|
-
end
|
|
201
|
-
|
|
202
|
-
def self.write(sxl, folder)
|
|
203
|
-
out = generate sxl
|
|
204
|
-
out.each_pair do |relative_path, str|
|
|
205
|
-
path = File.join(folder, relative_path)
|
|
206
|
-
FileUtils.mkdir_p File.dirname(path) # create folders if needed
|
|
207
|
-
file = File.open(path, 'w+') # w+ means truncate or create new file
|
|
208
|
-
file.puts str
|
|
209
|
-
end
|
|
210
|
-
end
|
|
211
|
-
end
|
|
212
|
-
end
|
|
213
|
-
end
|
|
214
|
-
end
|