openc3 5.12.0 → 5.13.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of openc3 might be problematic. Click here for more details.

Files changed (51) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +1 -1
  3. data/bin/openc3cli +3 -3
  4. data/data/config/graph_settings.yaml +1 -1
  5. data/data/config/item_modifiers.yaml +1 -2
  6. data/data/config/parameter_modifiers.yaml +13 -14
  7. data/data/config/screen.yaml +1 -2
  8. data/data/config/target_config.yaml +2 -6
  9. data/lib/openc3/api/cmd_api.rb +99 -35
  10. data/lib/openc3/api/tlm_api.rb +63 -24
  11. data/lib/openc3/interfaces/mqtt_interface.rb +11 -9
  12. data/lib/openc3/interfaces/mqtt_stream_interface.rb +78 -0
  13. data/lib/openc3/logs/packet_log_reader.rb +2 -2
  14. data/lib/openc3/logs/text_log_writer.rb +3 -2
  15. data/lib/openc3/microservices/trigger_group_microservice.rb +2 -1
  16. data/lib/openc3/models/plugin_model.rb +38 -4
  17. data/lib/openc3/packets/json_packet.rb +46 -15
  18. data/lib/openc3/packets/packet_config.rb +2 -1
  19. data/lib/openc3/packets/parsers/xtce_parser.rb +5 -1
  20. data/lib/openc3/script/api_shared.rb +31 -31
  21. data/lib/openc3/script/commands.rb +18 -12
  22. data/lib/openc3/script/limits.rb +1 -1
  23. data/lib/openc3/script/storage.rb +4 -4
  24. data/lib/openc3/script/web_socket_api.rb +2 -2
  25. data/lib/openc3/streams/mqtt_stream.rb +109 -0
  26. data/lib/openc3/utilities/cli_generator.rb +33 -20
  27. data/lib/openc3/utilities/local_mode.rb +2 -2
  28. data/lib/openc3/utilities/logger.rb +17 -16
  29. data/lib/openc3/utilities/process_manager.rb +1 -1
  30. data/lib/openc3/version.rb +5 -5
  31. data/templates/conversion/conversion.py +28 -0
  32. data/templates/conversion/conversion.rb +1 -18
  33. data/templates/limits_response/response.py +37 -0
  34. data/templates/limits_response/response.rb +0 -17
  35. data/templates/microservice/microservices/TEMPLATE/microservice.py +54 -0
  36. data/templates/microservice/microservices/TEMPLATE/microservice.rb +0 -7
  37. data/templates/plugin/.gitignore +1 -0
  38. data/templates/target/targets/TARGET/lib/target.py +9 -0
  39. data/templates/target/targets/TARGET/procedures/procedure.py +3 -0
  40. data/templates/tool_angular/package.json +20 -19
  41. data/templates/tool_angular/yarn.lock +2222 -3212
  42. data/templates/tool_react/package.json +12 -12
  43. data/templates/tool_react/yarn.lock +586 -521
  44. data/templates/tool_svelte/package.json +11 -10
  45. data/templates/tool_svelte/src/services/openc3-api.js +17 -22
  46. data/templates/tool_svelte/yarn.lock +600 -516
  47. data/templates/tool_vue/package.json +10 -9
  48. data/templates/tool_vue/yarn.lock +113 -41
  49. data/templates/widget/package.json +9 -8
  50. data/templates/widget/yarn.lock +96 -35
  51. metadata +26 -4
@@ -217,14 +217,14 @@ module OpenC3
217
217
 
218
218
  # Log Messages WebSocket
219
219
  class MessagesWebSocketApi < CmdTlmWebSocketApi
220
- def initialize(history_count: 0, start_time: nil, end_time: nil, severity: nil, types: nil, url: nil, write_timeout: 10.0, read_timeout: 10.0, connect_timeout: 5.0, authentication: nil, scope: $openc3_scope)
220
+ def initialize(history_count: 0, start_time: nil, end_time: nil, level: nil, types: nil, url: nil, write_timeout: 10.0, read_timeout: 10.0, connect_timeout: 5.0, authentication: nil, scope: $openc3_scope)
221
221
  @identifier = {
222
222
  channel: "MessagesChannel",
223
223
  history_count: history_count
224
224
  }
225
225
  @identifier['start_time'] = start_time if start_time
226
226
  @identifier['end_time'] = end_time if end_time
227
- @identifier['severity'] = severity if severity
227
+ @identifier['level'] = level if level
228
228
  @identifier['types'] = types if types
229
229
  super(url: url, write_timeout: write_timeout, read_timeout: read_timeout, connect_timeout: connect_timeout, authentication: authentication, scope: scope)
230
230
  end
@@ -0,0 +1,109 @@
1
+ # encoding: ascii-8bit
2
+
3
+ # Copyright 2023 OpenC3, Inc.
4
+ # All Rights Reserved.
5
+ #
6
+ # This program is free software; you can modify and/or redistribute it
7
+ # under the terms of the GNU Affero General Public License
8
+ # as published by the Free Software Foundation; version 3 with
9
+ # attribution addendums as found in the LICENSE.txt
10
+ #
11
+ # This program is distributed in the hope that it will be useful,
12
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+ # GNU Affero General Public License for more details.
15
+ #
16
+ # This file may also be used under the terms of a commercial license
17
+ # if purchased from OpenC3, Inc.
18
+
19
+ require 'openc3/interfaces/mqtt_interface' # For MQTT patches
20
+ require 'openc3/streams/stream'
21
+ require 'openc3/config/config_parser'
22
+
23
+ module OpenC3
24
+ class MqttStream < Stream
25
+ attr_reader :hostname
26
+ attr_reader :port
27
+ attr_reader :ssl
28
+ attr_reader :write_topic
29
+ attr_reader :read_topic
30
+ attr_accessor :username
31
+ attr_accessor :password
32
+ attr_accessor :cert
33
+ attr_accessor :key
34
+ attr_accessor :ca_file
35
+
36
+ def initialize(hostname, port = 1883, ssl = false, write_topic = nil, read_topic = nil)
37
+ super()
38
+
39
+ @hostname = hostname
40
+ @port = Integer(port)
41
+ @ssl = ConfigParser.handle_true_false(ssl)
42
+ @write_topic = ConfigParser.handle_nil(write_topic)
43
+ @read_topic = ConfigParser.handle_nil(read_topic)
44
+ @connected = false
45
+
46
+ @username = nil
47
+ @password = nil
48
+ @cert = nil
49
+ @key = nil
50
+ @ca_file = nil
51
+
52
+ # Mutex on write is needed to protect from commands coming in from more
53
+ # than one tool
54
+ @write_mutex = Mutex.new
55
+ end
56
+
57
+ # @return [String] Returns a binary string of data from the read_topic
58
+ def read
59
+ raise "Attempt to read from write only stream" unless @read_topic
60
+
61
+ # No read mutex is needed because reads happen serially
62
+ _, data = @client.get
63
+ if data.nil? or data.length <= 0
64
+ Logger.info "MqttStream: read returned nil" if data.nil?
65
+ Logger.info "MqttStream: read returned 0 bytes" if not data.nil? and data.length <= 0
66
+ return nil
67
+ end
68
+
69
+ return data
70
+ end
71
+
72
+ # @param data [String] A binary string of data to write to the write_topic
73
+ def write(data)
74
+ raise "Attempt to write to read only stream" unless @write_topic
75
+
76
+ @write_mutex.synchronize do
77
+ @client.publish(@write_topic, data)
78
+ end
79
+ end
80
+
81
+ # Connect the stream
82
+ def connect
83
+ @client = MQTT::Client.new
84
+ @client.host = @hostname
85
+ @client.port = @port
86
+ @client.ssl = @ssl
87
+ @client.username = @username if @username
88
+ @client.password = @password if @password
89
+ @client.cert = @cert if @cert
90
+ @client.key = @key if @key
91
+ @client.ca_file = @ca_file.path if @ca_file
92
+ @client.connect
93
+ @client.subscribe(@read_topic) if @read_topic
94
+ @connected = true
95
+ end
96
+
97
+ def connected?
98
+ @connected
99
+ end
100
+
101
+ def disconnect
102
+ if @connected
103
+ @client.disconnect
104
+ @client = nil
105
+ @connected = false
106
+ end
107
+ end
108
+ end
109
+ end
@@ -40,20 +40,33 @@ module OpenC3
40
40
  if args[0] != 'plugin' and Dir.glob("*.gemspec").empty?
41
41
  abort("No gemspec file detected. #{args[0].to_s.downcase} generator should be run within an existing plugin.")
42
42
  end
43
+
44
+ if args[-1] == '--python'
45
+ @@language = 'py'
46
+ else
47
+ @@language = 'rb'
48
+ end
43
49
  end
44
50
 
45
51
  def self.process_template(template_dir, the_binding)
46
52
  Dir.glob("#{template_dir}/**/*", File::FNM_DOTMATCH).each do |file|
47
53
  next if File.basename(file) == '.'
54
+ if @@language == 'rb'
55
+ # Ignore python files if we're ruby
56
+ next if File.extname(file) == '.py'
57
+ elsif @@language == 'py'
58
+ # Ignore ruby files if we're python
59
+ next if File.extname(file) == '.rb'
60
+ end
48
61
  base_name = file.sub("#{template_dir}/", '')
49
62
  next if yield base_name
50
63
  if File.directory?(file)
51
- FileUtils.mkdir(base_name) unless File.exist?(base_name)
64
+ FileUtils.mkdir_p(base_name)
52
65
  next
53
66
  end
54
- output = ERB.new(File.read(file).comment_erb(), trim_mode: "-").result(the_binding)
55
- File.open(base_name, 'w') do |file|
56
- file.write output
67
+ output = ERB.new(File.read(file), trim_mode: "-").result(the_binding)
68
+ File.open(base_name, 'w') do |base_file|
69
+ base_file.write output
57
70
  end
58
71
  end
59
72
  end
@@ -82,8 +95,8 @@ module OpenC3
82
95
  end
83
96
 
84
97
  def self.generate_target(args)
85
- if args.length != 2
86
- abort("Usage: cli generate #{args[0]} <NAME>")
98
+ if args.length < 2 or args.length > 3
99
+ abort("Usage: cli generate #{args[0]} <NAME> (--ruby or --python)")
87
100
  end
88
101
 
89
102
  # Create the local variables
@@ -92,14 +105,14 @@ module OpenC3
92
105
  if File.exist?(target_path)
93
106
  abort("Target #{target_path} already exists!")
94
107
  end
95
- target_lib_filename = "#{target_name.downcase}.rb"
108
+ target_lib_filename = "#{target_name.downcase}.#{@@language}"
96
109
  target_class = target_lib_filename.filename_to_class_name
97
110
  target_object = target_name.downcase
98
111
 
99
112
  process_template("#{TEMPLATES_DIR}/target", binding) do |filename|
100
113
  # Rename the template TARGET to our actual target named after the plugin
101
114
  filename.sub!("targets/TARGET", "targets/#{target_name}")
102
- filename.sub!("target.rb", target_lib_filename)
115
+ filename.sub!("target.#{@@language}", target_lib_filename)
103
116
  false
104
117
  end
105
118
 
@@ -120,8 +133,8 @@ module OpenC3
120
133
  end
121
134
 
122
135
  def self.generate_microservice(args)
123
- if args.length != 2
124
- abort("Usage: cli generate #{args[0]} <NAME>")
136
+ if args.length < 2 or args.length > 3
137
+ abort("Usage: cli generate #{args[0]} <NAME> (--ruby or --python)")
125
138
  end
126
139
 
127
140
  # Create the local variables
@@ -130,13 +143,13 @@ module OpenC3
130
143
  if File.exist?(microservice_path)
131
144
  abort("Microservice #{microservice_path} already exists!")
132
145
  end
133
- microservice_filename = "#{microservice_name.downcase}.rb"
146
+ microservice_filename = "#{microservice_name.downcase}.#{@@language}"
134
147
  microservice_class = microservice_filename.filename_to_class_name
135
148
 
136
149
  process_template("#{TEMPLATES_DIR}/microservice", binding) do |filename|
137
150
  # Rename the template MICROSERVICE to our actual microservice name
138
151
  filename.sub!("microservices/TEMPLATE", "microservices/#{microservice_name}")
139
- filename.sub!("microservice.rb", microservice_filename)
152
+ filename.sub!("microservice.#{@@language}", microservice_filename)
140
153
  false
141
154
  end
142
155
 
@@ -252,8 +265,8 @@ module OpenC3
252
265
  self.singleton_class.send(:alias_method, :generate_tool_svelte, :generate_tool)
253
266
 
254
267
  def self.generate_conversion(args)
255
- if args.length != 3
256
- abort("Usage: cli generate conversion <TARGET> <NAME>")
268
+ if args.length < 3 or args.length > 4
269
+ abort("Usage: cli generate conversion <TARGET> <NAME> (--ruby or --python)")
257
270
  end
258
271
 
259
272
  # Create the local variables
@@ -263,7 +276,7 @@ module OpenC3
263
276
  end
264
277
  conversion_name = "#{args[2].upcase.gsub(/_+|-+/, '_')}_CONVERSION"
265
278
  conversion_path = "targets/#{target_name}/lib/"
266
- conversion_basename = "#{conversion_name.downcase}.rb"
279
+ conversion_basename = "#{conversion_name.downcase}.#{@@language}"
267
280
  conversion_class = conversion_basename.filename_to_class_name
268
281
  conversion_filename = "targets/#{target_name}/lib/#{conversion_basename}"
269
282
  if File.exist?(conversion_filename)
@@ -271,7 +284,7 @@ module OpenC3
271
284
  end
272
285
 
273
286
  process_template("#{TEMPLATES_DIR}/conversion", binding) do |filename|
274
- filename.sub!("conversion.rb", conversion_filename)
287
+ filename.sub!("conversion.#{@@language}", conversion_filename)
275
288
  false
276
289
  end
277
290
 
@@ -282,8 +295,8 @@ module OpenC3
282
295
  end
283
296
 
284
297
  def self.generate_limits_response(args)
285
- if args.length != 3
286
- abort("Usage: cli generate limits_response <TARGET> <NAME>")
298
+ if args.length < 3 or args.length > 4
299
+ abort("Usage: cli generate limits_response <TARGET> <NAME> (--ruby or --python)")
287
300
  end
288
301
 
289
302
  # Create the local variables
@@ -293,7 +306,7 @@ module OpenC3
293
306
  end
294
307
  response_name = "#{args[2].upcase.gsub(/_+|-+/, '_')}_LIMITS_RESPONSE"
295
308
  response_path = "targets/#{target_name}/lib/"
296
- response_basename = "#{response_name.downcase}.rb"
309
+ response_basename = "#{response_name.downcase}.#{@@language}"
297
310
  response_class = response_basename.filename_to_class_name
298
311
  response_filename = "targets/#{target_name}/lib/#{response_basename}"
299
312
  if File.exist?(response_filename)
@@ -301,7 +314,7 @@ module OpenC3
301
314
  end
302
315
 
303
316
  process_template("#{TEMPLATES_DIR}/limits_response", binding) do |filename|
304
- filename.sub!("response.rb", response_filename)
317
+ filename.sub!("response.#{@@language}", response_filename)
305
318
  false
306
319
  end
307
320
 
@@ -29,9 +29,7 @@ module OpenC3
29
29
  # When updating update local_mode.py, PluginsTab.vue, plugins.spec.ts
30
30
  DEFAULT_PLUGINS = [
31
31
  'openc3-cosmos-tool-admin',
32
- 'openc3-cosmos-tool-autonomic',
33
32
  'openc3-cosmos-tool-bucketexplorer',
34
- 'openc3-cosmos-tool-calendar',
35
33
  'openc3-cosmos-tool-cmdsender',
36
34
  'openc3-cosmos-tool-cmdtlmserver',
37
35
  'openc3-cosmos-tool-dataextractor',
@@ -47,6 +45,8 @@ module OpenC3
47
45
  'openc3-cosmos-tool-tlmviewer',
48
46
  'openc3-cosmos-enterprise-tool-admin',
49
47
  'openc3-enterprise-tool-base',
48
+ 'openc3-cosmos-tool-autonomic',
49
+ 'openc3-cosmos-tool-calendar',
50
50
  'openc3-tool-base',
51
51
  ]
52
52
 
@@ -59,11 +59,11 @@ module OpenC3
59
59
  # FATAL prints FATAL, ERROR, WARN, INFO, DEBUG messages
60
60
  FATAL = ::Logger::FATAL
61
61
 
62
- DEBUG_SEVERITY_STRING = 'DEBUG'
63
- INFO_SEVERITY_STRING = 'INFO'
64
- WARN_SEVERITY_STRING = 'WARN'
65
- ERROR_SEVERITY_STRING = 'ERROR'
66
- FATAL_SEVERITY_STRING = 'FATAL'
62
+ DEBUG_LEVEL = 'DEBUG'
63
+ INFO_LEVEL = 'INFO'
64
+ WARN_LEVEL = 'WARN'
65
+ ERROR_LEVEL = 'ERROR'
66
+ FATAL_LEVEL = 'FATAL'
67
67
 
68
68
  # Types
69
69
  LOG = 'log'
@@ -98,27 +98,27 @@ module OpenC3
98
98
  # @param block [Proc] Block to call which should return a string to append
99
99
  # to the log message
100
100
  def debug(message = nil, scope: @@scope, user: nil, type: LOG, url: nil, &block)
101
- log_message(DEBUG_SEVERITY_STRING, message, scope: scope, user: user, type: type, url: url, &block) if @level <= DEBUG
101
+ log_message(DEBUG_LEVEL, message, scope: scope, user: user, type: type, url: url, &block) if @level <= DEBUG
102
102
  end
103
103
 
104
104
  # (see #debug)
105
105
  def info(message = nil, scope: @@scope, user: nil, type: LOG, url: nil, &block)
106
- log_message(INFO_SEVERITY_STRING, message, scope: scope, user: user, type: type, url: url, &block) if @level <= INFO
106
+ log_message(INFO_LEVEL, message, scope: scope, user: user, type: type, url: url, &block) if @level <= INFO
107
107
  end
108
108
 
109
109
  # (see #debug)
110
110
  def warn(message = nil, scope: @@scope, user: nil, type: LOG, url: nil, &block)
111
- log_message(WARN_SEVERITY_STRING, message, scope: scope, user: user, type: type, url: url, &block) if @level <= WARN
111
+ log_message(WARN_LEVEL, message, scope: scope, user: user, type: type, url: url, &block) if @level <= WARN
112
112
  end
113
113
 
114
114
  # (see #debug)
115
115
  def error(message = nil, scope: @@scope, user: nil, type: LOG, url: nil, &block)
116
- log_message(ERROR_SEVERITY_STRING, message, scope: scope, user: user, type: type, url: url, &block) if @level <= ERROR
116
+ log_message(ERROR_LEVEL, message, scope: scope, user: user, type: type, url: url, &block) if @level <= ERROR
117
117
  end
118
118
 
119
119
  # (see #debug)
120
120
  def fatal(message = nil, scope: @@scope, user: nil, type: LOG, url: nil, &block)
121
- log_message(FATAL_SEVERITY_STRING, message, scope: scope, user: user, type: type, url: url, &block) if @level <= FATAL
121
+ log_message(FATAL_LEVEL, message, scope: scope, user: user, type: type, url: url, &block) if @level <= FATAL
122
122
  end
123
123
 
124
124
  # (see #debug)
@@ -174,10 +174,11 @@ module OpenC3
174
174
 
175
175
  protected
176
176
 
177
- def log_message(severity_string, message, scope:, user:, type:, url:)
177
+ def log_message(log_level, message, scope:, user:, type:, url:)
178
178
  @@mutex.synchronize do
179
- time = Time.now
180
- data = { time: time.to_nsec_from_epoch, '@timestamp' => time.xmlschema(3), severity: severity_string }
179
+ time = Time.now.utc
180
+ # timestamp iso8601 with 6 decimal places to match the python output format
181
+ data = { time: time.to_nsec_from_epoch, '@timestamp' => time.iso8601(6), level: log_level }
181
182
  data[:microservice_name] = @microservice_name if @microservice_name
182
183
  data[:detail] = @detail_string if @detail_string
183
184
  data[:user] = user if user # EE: If a user is passed, put its name. Don't include user data if no user was passed.
@@ -185,12 +186,12 @@ module OpenC3
185
186
  message = yield
186
187
  end
187
188
  data[:container_name] = @container_name
188
- data[:log] = message
189
+ data[:message] = message
189
190
  data[:type] = type
190
191
  data[:url] = url if url
191
192
  if @stdout
192
- case severity_string
193
- when WARN_SEVERITY_STRING, ERROR_SEVERITY_STRING, FATAL_SEVERITY_STRING
193
+ case log_level
194
+ when WARN_LEVEL, ERROR_LEVEL, FATAL_LEVEL
194
195
  if ENV['OPENC3_LOG_STDERR']
195
196
  $stderr.puts data.as_json(:allow_nan => true).to_json(:allow_nan => true)
196
197
  $stderr.flush
@@ -96,7 +96,7 @@ module OpenC3
96
96
  process.status.output = output
97
97
  if process.exit_code != 0
98
98
  process.status.state = "Crashed"
99
- elsif output.include?('"severity":"ERROR"') || output.include?('"severity":"WARN"')
99
+ elsif output.include?('"level":"ERROR"') || output.include?('"level":"WARN"')
100
100
  process.status.state = "Warning"
101
101
  else
102
102
  process.status.state = "Complete"
@@ -1,14 +1,14 @@
1
1
  # encoding: ascii-8bit
2
2
 
3
- OPENC3_VERSION = '5.12.0'
3
+ OPENC3_VERSION = '5.13.0'
4
4
  module OpenC3
5
5
  module Version
6
6
  MAJOR = '5'
7
- MINOR = '12'
7
+ MINOR = '13'
8
8
  PATCH = '0'
9
9
  OTHER = ''
10
- BUILD = '8f36977eacfebdcdae21f02223be66e69feaa2bf'
10
+ BUILD = 'b4c2afb3edf2a5786422538ddef91f00d173855d'
11
11
  end
12
- VERSION = '5.12.0'
13
- GEM_VERSION = '5.12.0'
12
+ VERSION = '5.13.0'
13
+ GEM_VERSION = '5.13.0'
14
14
  end
@@ -0,0 +1,28 @@
1
+ from openc3.conversions.conversion import Conversion
2
+
3
+ # Custom conversion class
4
+ # See https://openc3.com/docs/v5/telemetry#read_conversion
5
+ class <%= conversion_class %>(Conversion):
6
+ def __init__(self):
7
+ super().__init__()
8
+ # Should be one of 'INT', 'UINT', 'FLOAT', 'STRING', 'BLOCK'
9
+ self.converted_type = 'STRING'
10
+ # Size of the converted type in bits
11
+ # Use 0 for 'STRING' or 'BLOCK' where the size can be variable
12
+ self.converted_bit_size = 0
13
+
14
+ # @param value [Object] Value based on the item definition. This could be
15
+ # a string, integer, float, or array of values.
16
+ # @param packet [Packet] The packet object where the conversion is defined
17
+ # @param buffer [String] The raw packet buffer
18
+ def call(self, value, packet, buffer):
19
+ # Read values from the packet and do a conversion
20
+ # Used for DERIVED items that don't have a value
21
+ # item1 = packet.read("ITEM1") # returns CONVERTED value (default)
22
+ # item2 = packet.read("ITEM2", 'RAW') # returns RAW value
23
+ # return (item1 + item2) / 2
24
+ #
25
+ # Perform conversion logic directly on value
26
+ # Used when conversion is applied to a regular (not DERIVED) item
27
+ # NOTE: You can also use packet.read("ITEM") to get additional values
28
+ # return value / 2 * packet.read("OTHER_ITEM")
@@ -1,21 +1,4 @@
1
1
  # encoding: ascii-8bit
2
-
3
- # Copyright 2023 OpenC3, Inc
4
- # All Rights Reserved.
5
- #
6
- # This program is free software; you can modify and/or redistribute it
7
- # under the terms of the GNU Affero General Public License
8
- # as published by the Free Software Foundation; version 3 with
9
- # attribution addendums as found in the LICENSE.txt
10
- #
11
- # This program is distributed in the hope that it will be useful,
12
- # but WITHOUT ANY WARRANTY; without even the implied warranty of
13
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
- # GNU Affero General Public License for more details.
15
-
16
- # This file may also be used under the terms of a commercial license
17
- # if purchased from OpenC3, Inc.
18
-
19
2
  require 'openc3/conversions/conversion'
20
3
 
21
4
  module OpenC3
@@ -37,7 +20,7 @@ module OpenC3
37
20
  # @param buffer [String] The raw packet buffer
38
21
  def call(value, packet, buffer)
39
22
  # Read values from the packet and do a conversion
40
- # Used for DERVIVED items that don't have a value
23
+ # Used for DERIVED items that don't have a value
41
24
  # item1 = packet.read("ITEM1") # returns CONVERTED value (default)
42
25
  # item2 = packet.read("ITEM2", :RAW) # returns RAW value
43
26
  # return (item1 + item2) / 2
@@ -0,0 +1,37 @@
1
+ from openc3.packets.limits_response import LimitsResponse
2
+
3
+
4
+ class <%= response_class %>(LimitsResponse):
5
+ # @param packet [Packet] Packet the limits response is assigned to
6
+ # @param item [PacketItem] PacketItem the limits response is assigned to
7
+ # @param old_limits_state [Symbol] Previous value of the limit. One of nil,
8
+ # "GREEN_HIGH", "GREEN_LOW", "YELLOW", "YELLOW_HIGH", "YELLOW_LOW",
9
+ # "RED", "RED_HIGH", "RED_LOW". nil if the previous limit state has not yet
10
+ # been established.
11
+ def call(self, packet, item, old_limits_state):
12
+ # Take action based on the current limits state
13
+ # Delete any of the case lines that do not apply or you don't care about
14
+ match item.limits.state:
15
+ case "RED_HIGH":
16
+ # Take action like sending a command:
17
+ # cmd("TARGET SAFE")
18
+ pass
19
+ case "RED_LOW":
20
+ pass
21
+ case "YELLOW_LOW":
22
+ pass
23
+ case "YELLOW_HIGH":
24
+ pass
25
+ # GREEN limits are only available if a telemetry item has them defined
26
+ # COSMOS refers to these as "operational limits"
27
+ # See https://openc3.com/docs/v5/telemetry#limits
28
+ case "GREEN_LOW":
29
+ pass
30
+ case "GREEN_HIGH":
31
+ pass
32
+ # :RED and :YELLOW limits are triggered for STATES with defined RED and YELLOW states
33
+ # See https://openc3.com/docs/v5/telemetry#state
34
+ case "RED":
35
+ pass
36
+ case "YELLOW":
37
+ pass
@@ -1,21 +1,4 @@
1
1
  # encoding: ascii-8bit
2
-
3
- # Copyright 2022 OpenC3, Inc.
4
- # All Rights Reserved.
5
- #
6
- # This program is free software; you can modify and/or redistribute it
7
- # under the terms of the GNU Affero General Public License
8
- # as published by the Free Software Foundation; version 3 with
9
- # attribution addendums as found in the LICENSE.txt
10
- #
11
- # This program is distributed in the hope that it will be useful,
12
- # but WITHOUT ANY WARRANTY; without even the implied warranty of
13
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
- # GNU Affero General Public License for more details.
15
-
16
- # This file may also be used under the terms of a commercial license
17
- # if purchased from OpenC3, Inc.
18
-
19
2
  require 'openc3/packets/limits_response'
20
3
 
21
4
  module OpenC3
@@ -0,0 +1,54 @@
1
+ import time
2
+ from openc3.microservices.microservice import Microservice
3
+ from openc3.utilities.sleeper import Sleeper
4
+ from openc3.api import *
5
+
6
+
7
+ class <%= microservice_class %>(Microservice):
8
+ def __init__(self, name):
9
+ super().__init__(name)
10
+ for option in self.config['options']:
11
+ # Update with your own OPTION handling
12
+ match option[0].upper():
13
+ case 'PERIOD':
14
+ self.period = int(option[1])
15
+ case _:
16
+ self.logger.error(
17
+ "Unknown option passed to microservice #{@name}: #{option}"
18
+ )
19
+
20
+ if not self.period:
21
+ self.period = 60 # 1 minutes
22
+ self.sleeper = Sleeper()
23
+
24
+ def run(self):
25
+ while True:
26
+ start_time = time.time()
27
+ if self.cancel_thread:
28
+ break
29
+
30
+ # Do your microservice work here
31
+ self.logger.info("Template Microservice ran")
32
+ # cmd("INST ABORT")
33
+
34
+ # The self.state variable is set to 'RUNNING' by the microservice base class
35
+ # The self.state is reflected to the user in the MICROSERVICES tab so you can
36
+ # convey long running actions by changing it, e.g. self.state = 'CALCULATING ...'
37
+
38
+ run_time = time.time() - start_time
39
+ delta = self.period - run_time
40
+ if delta > 0:
41
+ # Delay till the next period
42
+ if self.sleeper.sleep(
43
+ delta
44
+ ): # returns true and breaks loop on shutdown
45
+ break
46
+ self.count += 1
47
+
48
+ def shutdown(self):
49
+ self.sleeper.cancel() # Breaks out of run()
50
+ super().shutdown()
51
+
52
+
53
+ if __name__ == "__main__":
54
+ <%= microservice_class %>.run()
@@ -1,11 +1,4 @@
1
1
  # encoding: ascii-8bit
2
-
3
- # Copyright 2023 OpenC3, Inc.
4
- # All Rights Reserved.
5
- #
6
- # This file may also be used under the terms of a commercial license
7
- # if purchased from OpenC3, Inc.
8
-
9
2
  require 'openc3/microservices/microservice'
10
3
  require 'openc3/api/api'
11
4
 
@@ -0,0 +1 @@
1
+ node_modules
@@ -0,0 +1,9 @@
1
+ # This class can be used in your scripts like so:
2
+ # require_utility '<%= target_class.upcase %>/lib/<%= target_lib_filename %>'
3
+ # <%= target_object %> = <%= target_class %>()
4
+ # <%= target_object %>.utility()
5
+ # For more information see the OpenC3 scripting guide
6
+
7
+ class <%= target_class %>:
8
+ def utility():
9
+ pass
@@ -0,0 +1,3 @@
1
+ # Script Runner test script
2
+ cmd("<%= target_name %> EXAMPLE")
3
+ wait_check("<%= target_name %> STATUS BOOL == 'FALSE'", 5)