openc3 5.14.1 → 5.14.2

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.

Potentially problematic release.


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

Files changed (35) hide show
  1. checksums.yaml +4 -4
  2. data/bin/openc3cli +19 -15
  3. data/bin/pipinstall +9 -0
  4. data/data/config/target_config.yaml +2 -1
  5. data/lib/openc3/config/config_parser.rb +12 -12
  6. data/lib/openc3/conversions/conversion.rb +4 -4
  7. data/lib/openc3/interfaces/interface.rb +25 -18
  8. data/lib/openc3/microservices/interface_microservice.rb +27 -23
  9. data/lib/openc3/models/plugin_model.rb +10 -6
  10. data/lib/openc3/packets/limits_response.rb +1 -1
  11. data/lib/openc3/packets/packet_config.rb +41 -24
  12. data/lib/openc3/packets/packet_item.rb +3 -2
  13. data/lib/openc3/packets/packet_item_limits.rb +2 -1
  14. data/lib/openc3/packets/parsers/limits_response_parser.rb +21 -10
  15. data/lib/openc3/packets/parsers/processor_parser.rb +19 -10
  16. data/lib/openc3/system/system.rb +1 -1
  17. data/lib/openc3/system/system_config.rb +9 -10
  18. data/lib/openc3/system/target.rb +6 -6
  19. data/lib/openc3/utilities/cli_generator.rb +18 -3
  20. data/lib/openc3/utilities/python_proxy.rb +52 -0
  21. data/lib/openc3/version.rb +5 -5
  22. data/templates/conversion/conversion.py +1 -1
  23. data/templates/conversion/conversion.rb +1 -1
  24. data/templates/limits_response/response.py +2 -2
  25. data/templates/limits_response/response.rb +2 -2
  26. data/templates/microservice/microservices/TEMPLATE/microservice.py +6 -3
  27. data/templates/target/targets/TARGET/lib/target.py +2 -2
  28. data/templates/target/targets/TARGET/target.txt +2 -0
  29. data/templates/tool_angular/package.json +2 -2
  30. data/templates/tool_svelte/package.json +1 -1
  31. data/templates/tool_svelte/src/services/config-parser.js +5 -6
  32. data/templates/tool_svelte/src/services/openc3-api.js +9 -1
  33. data/templates/tool_vue/package.json +2 -2
  34. data/templates/widget/package.json +2 -2
  35. metadata +4 -2
@@ -14,7 +14,7 @@
14
14
  # GNU Affero General Public License for more details.
15
15
 
16
16
  # Modified by OpenC3, Inc.
17
- # All changes Copyright 2022, OpenC3, Inc.
17
+ # All changes Copyright 2024, OpenC3, Inc.
18
18
  # All Rights Reserved
19
19
  #
20
20
  # This file may also be used under the terms of a commercial license
@@ -31,6 +31,7 @@ require 'openc3/packets/parsers/format_string_parser'
31
31
  require 'openc3/packets/parsers/processor_parser'
32
32
  require 'openc3/packets/parsers/xtce_parser'
33
33
  require 'openc3/packets/parsers/xtce_converter'
34
+ require 'openc3/utilities/python_proxy'
34
35
  require 'openc3/conversions'
35
36
  require 'openc3/processors'
36
37
  require 'nokogiri'
@@ -82,6 +83,9 @@ module OpenC3
82
83
  # defined by that identification. Telemetry version
83
84
  attr_reader :tlm_id_value_hash
84
85
 
86
+ # @return [String] Language of current target (ruby or python)
87
+ attr_reader :language
88
+
85
89
  COMMAND = "Command"
86
90
  TELEMETRY = "Telemetry"
87
91
 
@@ -117,7 +121,7 @@ module OpenC3
117
121
  # @param filename [String] The name of the configuration file
118
122
  # @param process_target_name [String] The target name. Pass nil when parsing
119
123
  # an xtce file to automatically determine the target name.
120
- def process_file(filename, process_target_name)
124
+ def process_file(filename, process_target_name, language = 'ruby')
121
125
  # Handle .xtce files
122
126
  extension = File.extname(filename).to_s.downcase
123
127
  if extension == ".xtce" or extension == ".xml"
@@ -128,13 +132,14 @@ module OpenC3
128
132
  # Partial files are included into another file and thus aren't directly processed
129
133
  return if File.basename(filename)[0] == '_' # Partials start with underscore
130
134
 
135
+ @language = language
131
136
  @converted_type = nil
132
137
  @converted_bit_size = nil
133
138
  @proc_text = ''
134
139
  @building_generic_conversion = false
135
140
 
136
141
  process_target_name = process_target_name.upcase
137
- parser = ConfigParser.new("https://openc3.com/docs/v5")
142
+ parser = ConfigParser.new("https://docs.openc3.com/docs")
138
143
  parser.instance_variable_set(:@target_name, process_target_name)
139
144
  parser.parse_file(filename) do |keyword, params|
140
145
  if @building_generic_conversion
@@ -258,7 +263,7 @@ module OpenC3
258
263
  rescue
259
264
  # Doesn't exist
260
265
  end
261
- packets.each do |packet_name, packet|
266
+ packets.each do |_packet_name, packet|
262
267
  File.open(filename, 'a') do |file|
263
268
  file.puts packet.to_config(:TELEMETRY)
264
269
  file.puts ""
@@ -276,7 +281,7 @@ module OpenC3
276
281
  rescue
277
282
  # Doesn't exist
278
283
  end
279
- packets.each do |packet_name, packet|
284
+ packets.each do |_packet_name, packet|
280
285
  File.open(filename, 'a') do |file|
281
286
  file.puts packet.to_config(:COMMAND)
282
287
  file.puts ""
@@ -424,7 +429,7 @@ module OpenC3
424
429
 
425
430
  # Define a processor class that will be called once when a packet is received
426
431
  when 'PROCESSOR'
427
- ProcessorParser.parse(parser, @current_packet, @current_cmd_or_tlm)
432
+ ProcessorParser.parse(parser, @current_packet, @current_cmd_or_tlm, @language)
428
433
 
429
434
  when 'DISABLE_MESSAGES'
430
435
  usage = "#{keyword}"
@@ -463,18 +468,27 @@ module OpenC3
463
468
  parser.verify_num_parameters(0, 0, usage)
464
469
  @current_packet.hidden = true
465
470
  @current_packet.disabled = true
471
+
466
472
  when 'ACCESSOR'
467
473
  usage = "#{keyword} <Accessor class name>"
468
474
  parser.verify_num_parameters(1, nil, usage)
469
475
  begin
470
- klass = OpenC3.require_class(params[0])
471
- if params.length > 1
472
- @current_packet.accessor = klass.new(@current_packet, *params[1..-1])
476
+ if @language == 'ruby'
477
+ klass = OpenC3.require_class(params[0])
478
+ if params.length > 1
479
+ @current_packet.accessor = klass.new(@current_packet, *params[1..-1])
480
+ else
481
+ @current_packet.accessor = klass.new(@current_packet)
482
+ end
473
483
  else
474
- @current_packet.accessor = klass.new(@current_packet)
484
+ if params.length > 1
485
+ @current_packet.accessor = PythonProxy.new('Accessor', params[0], @current_packet, *params[1..-1])
486
+ else
487
+ @current_packet.accessor = PythonProxy.new('Accessor', params[0], @current_packet)
488
+ end
475
489
  end
476
- rescue Exception => err
477
- raise parser.error(err)
490
+ rescue Exception => e
491
+ raise parser.error(e)
478
492
  end
479
493
 
480
494
  when 'TEMPLATE'
@@ -488,8 +502,8 @@ module OpenC3
488
502
 
489
503
  begin
490
504
  @current_packet.template = parser.read_file(params[0])
491
- rescue Exception => err
492
- raise parser.error(err)
505
+ rescue Exception => e
506
+ raise parser.error(e)
493
507
  end
494
508
 
495
509
  when 'RESPONSE'
@@ -530,16 +544,19 @@ module OpenC3
530
544
  usage = "#{keyword} <conversion class filename> <custom parameters> ..."
531
545
  parser.verify_num_parameters(1, nil, usage)
532
546
  begin
533
- klass = OpenC3.require_class(params[0])
534
- conversion = klass.new(*params[1..(params.length - 1)])
535
- @current_item.public_send("#{keyword.downcase}=".to_sym, conversion)
536
- if klass != ProcessorConversion and (conversion.converted_type.nil? or conversion.converted_bit_size.nil?)
537
- msg = "Read Conversion #{params[0]} on item #{@current_item.name} does not specify converted type or bit size"
538
- @warnings << msg
539
- Logger.instance.warn @warnings[-1]
547
+ if @language == 'ruby'
548
+ klass = OpenC3.require_class(params[0])
549
+ conversion = klass.new(*params[1..(params.length - 1)])
550
+ @current_item.public_send("#{keyword.downcase}=".to_sym, conversion)
551
+ if klass != ProcessorConversion and (conversion.converted_type.nil? or conversion.converted_bit_size.nil?)
552
+ msg = "Read Conversion #{params[0]} on item #{@current_item.name} does not specify converted type or bit size"
553
+ @warnings << msg
554
+ Logger.instance.warn @warnings[-1]
555
+ end
556
+ else
557
+ conversion = PythonProxy.new('Conversion', params[0], *params[1..(params.length - 1)])
558
+ @current_item.public_send("#{keyword.downcase}=".to_sym, conversion)
540
559
  end
541
- rescue Exception => err
542
- raise parser.error(err)
543
560
  end
544
561
 
545
562
  # Apply a polynomial conversion to the current item
@@ -600,7 +617,7 @@ module OpenC3
600
617
  # Define a response class that will be called when the limits state of the
601
618
  # current item changes.
602
619
  when 'LIMITS_RESPONSE'
603
- LimitsResponseParser.parse(parser, @current_item, @current_cmd_or_tlm)
620
+ LimitsResponseParser.parse(parser, @current_item, @current_cmd_or_tlm, @language)
604
621
 
605
622
  # Define a printf style formatting string for the current telemetry item
606
623
  when 'FORMAT_STRING'
@@ -23,6 +23,7 @@
23
23
  require 'openc3/packets/structure_item'
24
24
  require 'openc3/packets/packet_item_limits'
25
25
  require 'openc3/conversions/conversion'
26
+ require 'openc3/utilities/python_proxy'
26
27
  require 'openc3/io/json_rpc' # Includes needed as_json code
27
28
 
28
29
  module OpenC3
@@ -129,7 +130,7 @@ module OpenC3
129
130
 
130
131
  def read_conversion=(read_conversion)
131
132
  if read_conversion
132
- raise ArgumentError, "#{@name}: read_conversion must be a OpenC3::Conversion but is a #{read_conversion.class}" unless OpenC3::Conversion === read_conversion
133
+ raise ArgumentError, "#{@name}: read_conversion must be a OpenC3::Conversion but is a #{read_conversion.class}" unless OpenC3::Conversion === read_conversion or OpenC3::PythonProxy === read_conversion
133
134
 
134
135
  @read_conversion = read_conversion.clone
135
136
  else
@@ -139,7 +140,7 @@ module OpenC3
139
140
 
140
141
  def write_conversion=(write_conversion)
141
142
  if write_conversion
142
- raise ArgumentError, "#{@name}: write_conversion must be a OpenC3::Conversion but is a #{write_conversion.class}" unless OpenC3::Conversion === write_conversion
143
+ raise ArgumentError, "#{@name}: write_conversion must be a OpenC3::Conversion but is a #{write_conversion.class}" unless OpenC3::Conversion === write_conversion or OpenC3::PythonProxy === write_conversion
143
144
 
144
145
  @write_conversion = write_conversion.clone
145
146
  else
@@ -21,6 +21,7 @@
21
21
  # if purchased from OpenC3, Inc.
22
22
 
23
23
  require 'openc3/packets/limits_response'
24
+ require 'openc3/utilities/python_proxy'
24
25
 
25
26
  module OpenC3
26
27
  # Maintains knowledge of limits for a PacketItem
@@ -96,7 +97,7 @@ module OpenC3
96
97
 
97
98
  def response=(response)
98
99
  if response
99
- raise ArgumentError, "response must be a OpenC3::LimitsResponse but is a #{response.class}" unless OpenC3::LimitsResponse === response
100
+ raise ArgumentError, "response must be a OpenC3::LimitsResponse but is a #{response.class}" unless OpenC3::LimitsResponse === response or OpenC3::PythonProxy === response
100
101
 
101
102
  @response = response.clone
102
103
  else
@@ -14,26 +14,29 @@
14
14
  # GNU Affero General Public License for more details.
15
15
 
16
16
  # Modified by OpenC3, Inc.
17
- # All changes Copyright 2023, OpenC3, Inc.
17
+ # All changes Copyright 2024, OpenC3, Inc.
18
18
  # All Rights Reserved
19
19
  #
20
20
  # This file may also be used under the terms of a commercial license
21
21
  # if purchased from OpenC3, Inc.
22
22
 
23
+ require 'openc3/utilities/python_proxy'
24
+
23
25
  module OpenC3
24
26
  class LimitsResponseParser
25
27
  # @param parser [ConfigParser] Configuration parser
26
28
  # @param item [Packet] The current item
27
29
  # @param cmd_or_tlm [String] Whether this is a command or telemetry packet
28
- def self.parse(parser, item, cmd_or_tlm)
29
- parser = LimitsResponseParser.new(parser)
30
+ def self.parse(parser, item, cmd_or_tlm, language = 'ruby')
31
+ parser = LimitsResponseParser.new(parser, language)
30
32
  parser.verify_parameters(cmd_or_tlm)
31
33
  parser.create_limits_response(item)
32
34
  end
33
35
 
34
36
  # @param parser [ConfigParser] Configuration parser
35
- def initialize(parser)
37
+ def initialize(parser, language = 'ruby')
36
38
  @parser = parser
39
+ @language = language
37
40
  end
38
41
 
39
42
  # @param cmd_or_tlm [String] Whether this is a command or telemetry packet
@@ -48,15 +51,23 @@ module OpenC3
48
51
 
49
52
  # @param item [PacketItem] The item the limits response should be added to
50
53
  def create_limits_response(item)
51
- klass = OpenC3.require_class(@parser.parameters[0])
54
+ if @language == 'ruby'
55
+ klass = OpenC3.require_class(@parser.parameters[0])
52
56
 
53
- if @parser.parameters[1]
54
- item.limits.response = klass.new(*@parser.parameters[1..(@parser.parameters.length - 1)])
57
+ if @parser.parameters[1]
58
+ item.limits.response = klass.new(*@parser.parameters[1..(@parser.parameters.length - 1)])
59
+ else
60
+ item.limits.response = klass.new
61
+ end
55
62
  else
56
- item.limits.response = klass.new
63
+ if @parser.parameters[1]
64
+ item.limits.response = PythonProxy.new('LimitsResponse', @parser.parameters[0], *@parser.parameters[1..(@parser.parameters.length - 1)])
65
+ else
66
+ item.limits.response = PythonProxy.new('LimitsResponse', @parser.parameters[0], [])
67
+ end
57
68
  end
58
- rescue Exception => err
59
- raise @parser.error(err, @usage)
69
+ rescue Exception => e
70
+ raise @parser.error(e, @usage)
60
71
  end
61
72
  end
62
73
  end
@@ -21,21 +21,23 @@
21
21
  # if purchased from OpenC3, Inc.
22
22
 
23
23
  require 'openc3/processors'
24
+ require 'openc3/utilities/python_proxy'
24
25
 
25
26
  module OpenC3
26
27
  class ProcessorParser
27
28
  # @param parser [ConfigParser] Configuration parser
28
29
  # @param packet [Packet] The current packet
29
30
  # @param cmd_or_tlm [String] Whether this is a command or telemetry packet
30
- def self.parse(parser, packet, cmd_or_tlm)
31
- parser = ProcessorParser.new(parser)
31
+ def self.parse(parser, packet, cmd_or_tlm, language = 'ruby')
32
+ parser = ProcessorParser.new(parser, language)
32
33
  parser.verify_parameters(cmd_or_tlm)
33
34
  parser.create_processor(packet)
34
35
  end
35
36
 
36
37
  # @param parser [ConfigParser] Configuration parser
37
- def initialize(parser)
38
+ def initialize(parser, language = 'ruby')
38
39
  @parser = parser
40
+ @language = language
39
41
  end
40
42
 
41
43
  # @param cmd_or_tlm [String] Whether this is a command or telemetry packet
@@ -50,16 +52,23 @@ module OpenC3
50
52
 
51
53
  # @param packet [Packet] The packet the processor should be added to
52
54
  def create_processor(packet)
53
- # require should be performed in target.txt
54
- klass = OpenC3.require_class(@parser.parameters[1])
55
+ if @language == 'ruby'
56
+ # require should be performed in target.txt
57
+ klass = OpenC3.require_class(@parser.parameters[1])
55
58
 
56
- if @parser.parameters[2]
57
- processor = klass.new(*@parser.parameters[2..(@parser.parameters.length - 1)])
59
+ if @parser.parameters[2]
60
+ processor = klass.new(*@parser.parameters[2..(@parser.parameters.length - 1)])
61
+ else
62
+ processor = klass.new
63
+ end
64
+ raise ArgumentError, "processor must be a OpenC3::Processor but is a #{processor.class}" unless OpenC3::Processor === processor
58
65
  else
59
- processor = klass.new
66
+ if @parser.parameters[2]
67
+ processor = PythonProxy.new('Processor', @parser.parameters[1], *@parser.parameters[2..(@parser.parameters.length - 1)])
68
+ else
69
+ processor = PythonProxy.new('Processor', @parser.parameters[1], [])
70
+ end
60
71
  end
61
- raise ArgumentError, "processor must be a OpenC3::Processor but is a #{processor.class}" unless OpenC3::Processor === processor
62
-
63
72
  processor.name = get_processor_name()
64
73
  packet.processors[processor.name] = processor
65
74
  rescue Exception => err
@@ -179,7 +179,7 @@ module OpenC3
179
179
  @targets[target.name] = target
180
180
  errors = [] # Store all errors processing the cmd_tlm files
181
181
  target.cmd_tlm_files.each do |cmd_tlm_file|
182
- @packet_config.process_file(cmd_tlm_file, target.name)
182
+ @packet_config.process_file(cmd_tlm_file, target.name, target.language)
183
183
  rescue Exception => error
184
184
  errors << "Error processing #{cmd_tlm_file}:\n#{error.message}"
185
185
  end
@@ -14,10 +14,10 @@
14
14
  # GNU Affero General Public License for more details.
15
15
 
16
16
  # Modified by OpenC3, Inc.
17
- # All changes Copyright 2022, OpenC3, Inc.
17
+ # All changes Copyright 2024, OpenC3, Inc.
18
18
  # All Rights Reserved
19
19
  #
20
- # This file may also be used under the terms of a commercial license
20
+ # This file may also be used under the terms of a commercial license
21
21
  # if purchased from OpenC3, Inc.
22
22
 
23
23
  require 'openc3/config/config_parser'
@@ -30,7 +30,6 @@ require 'openc3/logs'
30
30
  require 'fileutils'
31
31
  require 'openc3/utilities/zip'
32
32
  require 'bundler'
33
- require 'thread'
34
33
 
35
34
  module OpenC3
36
35
  # System is the primary entry point into the OpenC3 framework. It captures
@@ -90,7 +89,7 @@ module OpenC3
90
89
  # @param targets_config_dir [String] The configuration directory to
91
90
  # search for the target command and telemetry files.
92
91
  def process_file(filename, targets_config_dir)
93
- parser = ConfigParser.new("https://openc3.com/docs/v5")
92
+ parser = ConfigParser.new("https://docs.openc3.com/docs")
94
93
 
95
94
  # First pass - Everything except targets
96
95
  parser.parse_file(filename) do |keyword, parameters|
@@ -192,7 +191,7 @@ module OpenC3
192
191
  # If any of the targets original directory name matches the
193
192
  # current directory then it must have been already processed by
194
193
  # DECLARE_TARGET so we skip it.
195
- next if @targets.select { |name, target| target.original_name == dir_filename }.length > 0
194
+ next if @targets.select { |_name, target| target.original_name == dir_filename }.length > 0
196
195
  next if dir_filename == 'SYSTEM'
197
196
 
198
197
  target = Target.new(dir_filename, nil, targets_config_dir)
@@ -352,7 +351,7 @@ module OpenC3
352
351
  # If any of the targets original directory name matches the
353
352
  # current directory then it must have been already processed by
354
353
  # DECLARE_TARGET so we skip it.
355
- next if @targets.select { |name, target| target.original_name == target_name }.length > 0
354
+ next if @targets.select { |_name, target| target.original_name == target_name }.length > 0
356
355
 
357
356
  target = Target.new(target_name, nil, nil, nil, spec.gem_dir)
358
357
  @targets[target.name] = target
@@ -377,7 +376,7 @@ module OpenC3
377
376
 
378
377
  # Copy target files into archive
379
378
  zip_targets = []
380
- @targets.each do |target_name, target|
379
+ @targets.each do |_target_name, target|
381
380
  entries = Dir.entries(target.dir) - %w(. ..)
382
381
  zip_target = File.join(zip_file_path, target.original_name)
383
382
  # Check the stored list of targets. We can't ask the zip file
@@ -390,7 +389,7 @@ module OpenC3
390
389
 
391
390
  # Create custom system.txt file
392
391
  zipfile.get_output_stream(File.join(zip_file_path, 'system.txt')) do |file|
393
- @targets.each do |target_name, target|
392
+ @targets.each do |_target_name, target|
394
393
  target_filename = File.basename(target.filename)
395
394
  target_filename = nil unless File.exist?(target.filename)
396
395
  # Create a newline character since Zip opens files in binary mode
@@ -405,8 +404,8 @@ module OpenC3
405
404
  end
406
405
  File.rename(configuration_tmp, configuration)
407
406
  File.chmod(0444, configuration) # Mark readonly
408
- rescue Exception => error
409
- Logger.error "Problem saving configuration to #{configuration}: #{error.class}:#{error.message}\n#{error.backtrace.join("\n")}\n"
407
+ rescue Exception => e
408
+ Logger.error "Problem saving configuration to #{configuration}: #{e.class}:#{e.message}\n#{e.backtrace.join("\n")}\n"
410
409
  end
411
410
  end
412
411
  end
@@ -14,7 +14,7 @@
14
14
  # GNU Affero General Public License for more details.
15
15
 
16
16
  # Modified by OpenC3, Inc.
17
- # All changes Copyright 2022, OpenC3, Inc.
17
+ # All changes Copyright 2024, OpenC3, Inc.
18
18
  # All Rights Reserved
19
19
  #
20
20
  # This file may also be used under the terms of a commercial license
@@ -114,8 +114,8 @@ module OpenC3
114
114
  #
115
115
  # @param filename [String] The target configuration file to parse
116
116
  def process_file(filename)
117
- Logger.instance.info "Processing ruby target definition in file '#{filename}'"
118
- parser = ConfigParser.new("https://openc3.com/docs/v5/target")
117
+ Logger.instance.info "Processing target definition in file '#{filename}'"
118
+ parser = ConfigParser.new("https://docs.openc3.com/docs/configuration/target")
119
119
  parser.parse_file(filename) do |keyword, parameters|
120
120
  case keyword
121
121
  when 'LANGUAGE'
@@ -143,8 +143,8 @@ module OpenC3
143
143
  rescue Exception => err
144
144
  raise parser.error(err.message)
145
145
  end
146
- rescue Exception => err
147
- raise parser.error(err.message)
146
+ rescue Exception => e
147
+ raise parser.error(e.message)
148
148
  end
149
149
 
150
150
  # This code resolves any relative paths to absolute before putting into the @requires array
@@ -196,7 +196,7 @@ module OpenC3
196
196
  end
197
197
  end
198
198
 
199
- def as_json(*a)
199
+ def as_json(*_a)
200
200
  config = {}
201
201
  config['name'] = @name
202
202
  config['requires'] = @requires
@@ -128,6 +128,16 @@ module OpenC3
128
128
  gemspec = File.read(gemspec_filename)
129
129
  gemspec.gsub!('plugin.txt', 'plugin.txt requirements.txt')
130
130
  File.write(gemspec_filename, gemspec)
131
+
132
+ target_txt_filename = "targets/#{target_name}/target.txt"
133
+ target_txt = File.read(target_txt_filename)
134
+ target_txt.gsub!('LANGUAGE ruby', 'LANGUAGE python')
135
+ File.write(target_txt_filename, target_txt)
136
+ end
137
+
138
+ interface_line = "INTERFACE <%= #{target_name.downcase}_target_name %>_INT tcpip_client_interface.rb host.docker.internal 8080 8081 10.0 nil BURST"
139
+ if @@language == 'py'
140
+ interface_line = "INTERFACE <%= #{target_name.downcase}_target_name %>_INT openc3/interfaces/tcpip_client_interface.py host.docker.internal 8080 8081 10.0 None BURST"
131
141
  end
132
142
 
133
143
  # Add this target to plugin.txt
@@ -137,7 +147,7 @@ module OpenC3
137
147
  VARIABLE #{target_name.downcase}_target_name #{target_name}
138
148
 
139
149
  TARGET #{target_name} <%= #{target_name.downcase}_target_name %>
140
- INTERFACE <%= #{target_name.downcase}_target_name %>_INT tcpip_client_interface.rb host.docker.internal 8080 8081 10.0 nil BURST
150
+ #{interface_line}
141
151
  MAP_TARGET <%= #{target_name.downcase}_target_name %>
142
152
  DOC
143
153
  end
@@ -167,12 +177,17 @@ module OpenC3
167
177
  false
168
178
  end
169
179
 
180
+ cmd_line = "CMD ruby #{microservice_name.downcase}.rb"
181
+ if @@language == 'py'
182
+ cmd_line = "CMD python #{microservice_name.downcase}.py"
183
+ end
184
+
170
185
  # Add this microservice to plugin.txt
171
186
  File.open("plugin.txt", 'a') do |file|
172
187
  file.puts <<~DOC
173
188
 
174
189
  MICROSERVICE #{microservice_name} #{microservice_name.downcase.gsub('_','-')}-microservice
175
- CMD ruby #{microservice_name.downcase}.rb
190
+ #{cmd_line}
176
191
  DOC
177
192
  end
178
193
 
@@ -222,7 +237,7 @@ module OpenC3
222
237
  end
223
238
 
224
239
  puts "Widget #{widget_name} successfully generated!"
225
- puts "Please be sure #{widget_name} does not overlap an existing widget: https://openc3.com/docs/v5/telemetry-screens"
240
+ puts "Please be sure #{widget_name} does not overlap an existing widget: https://docs.openc3.com/docs/configuration/telemetry-screens"
226
241
  return widget_name
227
242
  end
228
243
 
@@ -0,0 +1,52 @@
1
+ # encoding: ascii-8bit
2
+
3
+ # Copyright 2024 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
+ # TODO: Delegate to actual Python to verify that classes exist
20
+ # and to get proper data from them like converted_type
21
+
22
+ module OpenC3
23
+ class PythonProxy
24
+ attr_accessor :name
25
+ attr_accessor :args
26
+
27
+ def initialize(type, class_name, *params)
28
+ @type = type
29
+ @class_name = class_name
30
+ @params = params
31
+ @args = params
32
+ @name = nil
33
+ end
34
+
35
+ def class
36
+ return @class_name
37
+ end
38
+
39
+ def as_json(*args, **kw_args)
40
+ case @type
41
+ when "Processor"
42
+ return { 'name' => @name, 'class' => @class_name, 'params' => @params }
43
+ when "Conversion"
44
+ return { 'class' => @class_name, 'params' => @params }
45
+ when "LimitsResponse"
46
+ return { "class" => @class_name, 'params' => @params }
47
+ else
48
+ raise "Unknown PythonProxy type: #{@type}"
49
+ end
50
+ end
51
+ end
52
+ end
@@ -1,14 +1,14 @@
1
1
  # encoding: ascii-8bit
2
2
 
3
- OPENC3_VERSION = '5.14.1'
3
+ OPENC3_VERSION = '5.14.2'
4
4
  module OpenC3
5
5
  module Version
6
6
  MAJOR = '5'
7
7
  MINOR = '14'
8
- PATCH = '1'
8
+ PATCH = '2'
9
9
  OTHER = ''
10
- BUILD = '902e54e502f6070c58183746a7db21a50e7b5263'
10
+ BUILD = 'e5d9da06d95d4404fba6f9fd5a74a130ef176bd4'
11
11
  end
12
- VERSION = '5.14.1'
13
- GEM_VERSION = '5.14.1'
12
+ VERSION = '5.14.2'
13
+ GEM_VERSION = '5.14.2'
14
14
  end
@@ -1,7 +1,7 @@
1
1
  from openc3.conversions.conversion import Conversion
2
2
 
3
3
  # Custom conversion class
4
- # See https://openc3.com/docs/v5/telemetry#read_conversion
4
+ # See https://docs.openc3.com/docs/configuration/telemetry#read_conversion
5
5
  class <%= conversion_class %>(Conversion):
6
6
  def __init__(self):
7
7
  super().__init__()
@@ -3,7 +3,7 @@ require 'openc3/conversions/conversion'
3
3
 
4
4
  module OpenC3
5
5
  # Custom conversion class
6
- # See https://openc3.com/docs/v5/telemetry#read_conversion
6
+ # See https://docs.openc3.com/docs/configuration/telemetry#read_conversion
7
7
  class <%= conversion_class %> < Conversion
8
8
  def initialize
9
9
  super()
@@ -24,13 +24,13 @@ class <%= response_class %>(LimitsResponse):
24
24
  pass
25
25
  # GREEN limits are only available if a telemetry item has them defined
26
26
  # COSMOS refers to these as "operational limits"
27
- # See https://openc3.com/docs/v5/telemetry#limits
27
+ # See https://docs.openc3.com/docs/configuration/telemetry#limits
28
28
  case "GREEN_LOW":
29
29
  pass
30
30
  case "GREEN_HIGH":
31
31
  pass
32
32
  # :RED and :YELLOW limits are triggered for STATES with defined RED and YELLOW states
33
- # See https://openc3.com/docs/v5/telemetry#state
33
+ # See https://docs.openc3.com/docs/configuration/telemetry#state
34
34
  case "RED":
35
35
  pass
36
36
  case "YELLOW":
@@ -21,11 +21,11 @@ module OpenC3
21
21
  when :YELLOW_HIGH
22
22
  # GREEN limits are only available if a telemetry item has them defined
23
23
  # COSMOS refers to these as "operational limits"
24
- # See https://openc3.com/docs/v5/telemetry#limits
24
+ # See https://docs.openc3.com/docs/configuration/telemetry#limits
25
25
  when :GREEN_LOW
26
26
  when :GREEN_HIGH
27
27
  # :RED and :YELLOW limits are triggered for STATES with defined RED and YELLOW states
28
- # See https://openc3.com/docs/v5/telemetry#state
28
+ # See https://docs.openc3.com/docs/configuration/telemetry#state
29
29
  when :RED
30
30
  when :YELLOW
31
31
  end
@@ -14,14 +14,17 @@ class <%= microservice_class %>(Microservice):
14
14
  self.period = int(option[1])
15
15
  case _:
16
16
  self.logger.error(
17
- "Unknown option passed to microservice #{@name}: #{option}"
17
+ f"Unknown option passed to microservice {name}: {option}"
18
18
  )
19
19
 
20
- if not self.period:
20
+ if not hasattr(self, 'period'):
21
21
  self.period = 60 # 1 minutes
22
22
  self.sleeper = Sleeper()
23
23
 
24
24
  def run(self):
25
+ # Allow the other target processes to start before running the microservice
26
+ self.sleeper.sleep(self.period)
27
+
25
28
  while True:
26
29
  start_time = time.time()
27
30
  if self.cancel_thread:
@@ -51,4 +54,4 @@ class <%= microservice_class %>(Microservice):
51
54
 
52
55
 
53
56
  if __name__ == "__main__":
54
- <%= microservice_class %>.run()
57
+ <%= microservice_class %>.class_run()