openc3 5.11.3 → 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 (109) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +2 -2
  3. data/bin/openc3cli +29 -15
  4. data/data/config/_id_items.yaml +6 -4
  5. data/data/config/_id_params.yaml +9 -6
  6. data/data/config/_items.yaml +6 -4
  7. data/data/config/_params.yaml +3 -2
  8. data/data/config/graph_settings.yaml +1 -1
  9. data/data/config/interface_modifiers.yaml +1 -1
  10. data/data/config/item_modifiers.yaml +1 -2
  11. data/data/config/microservice.yaml +10 -1
  12. data/data/config/parameter_modifiers.yaml +13 -14
  13. data/data/config/plugins.yaml +13 -3
  14. data/data/config/screen.yaml +1 -2
  15. data/data/config/target.yaml +9 -0
  16. data/data/config/target_config.yaml +14 -6
  17. data/data/config/tool.yaml +12 -3
  18. data/lib/openc3/api/api.rb +1 -1
  19. data/lib/openc3/api/cmd_api.rb +123 -59
  20. data/lib/openc3/api/config_api.rb +12 -12
  21. data/lib/openc3/api/limits_api.rb +4 -3
  22. data/lib/openc3/api/settings_api.rb +5 -2
  23. data/lib/openc3/api/tlm_api.rb +70 -34
  24. data/lib/openc3/conversions/unix_time_conversion.rb +8 -6
  25. data/lib/openc3/interfaces/mqtt_interface.rb +11 -9
  26. data/lib/openc3/interfaces/mqtt_stream_interface.rb +78 -0
  27. data/lib/openc3/interfaces/tcpip_server_interface.rb +0 -7
  28. data/lib/openc3/io/json_drb.rb +3 -2
  29. data/lib/openc3/io/json_rpc.rb +6 -6
  30. data/lib/openc3/logs/buffered_packet_log_writer.rb +4 -2
  31. data/lib/openc3/logs/packet_log_reader.rb +2 -2
  32. data/lib/openc3/logs/packet_log_writer.rb +22 -7
  33. data/lib/openc3/logs/text_log_writer.rb +3 -2
  34. data/lib/openc3/microservices/cleanup_microservice.rb +8 -1
  35. data/lib/openc3/microservices/decom_microservice.rb +1 -1
  36. data/lib/openc3/microservices/interface_microservice.rb +2 -2
  37. data/lib/openc3/microservices/microservice.rb +5 -2
  38. data/lib/openc3/microservices/reaction_microservice.rb +1 -0
  39. data/lib/openc3/microservices/timeline_microservice.rb +7 -5
  40. data/lib/openc3/microservices/trigger_group_microservice.rb +2 -1
  41. data/lib/openc3/migrations/20231022000000_tlm_viewer_config.rb +22 -0
  42. data/lib/openc3/models/activity_model.rb +21 -3
  43. data/lib/openc3/models/cvt_model.rb +2 -1
  44. data/lib/openc3/models/gem_model.rb +4 -1
  45. data/lib/openc3/models/interface_model.rb +11 -5
  46. data/lib/openc3/models/metadata_model.rb +11 -0
  47. data/lib/openc3/models/microservice_model.rb +16 -3
  48. data/lib/openc3/models/model.rb +18 -0
  49. data/lib/openc3/models/note_model.rb +11 -0
  50. data/lib/openc3/models/plugin_model.rb +56 -4
  51. data/lib/openc3/models/python_package_model.rb +104 -0
  52. data/lib/openc3/models/scope_model.rb +2 -0
  53. data/lib/openc3/models/sorted_model.rb +17 -8
  54. data/lib/openc3/models/target_model.rb +53 -18
  55. data/lib/openc3/models/tool_config_model.rb +9 -3
  56. data/lib/openc3/models/tool_model.rb +22 -7
  57. data/lib/openc3/models/widget_model.rb +19 -3
  58. data/lib/openc3/operators/microservice_operator.rb +2 -0
  59. data/lib/openc3/packets/json_packet.rb +46 -15
  60. data/lib/openc3/packets/limits.rb +6 -18
  61. data/lib/openc3/packets/packet.rb +1 -0
  62. data/lib/openc3/packets/packet_config.rb +2 -1
  63. data/lib/openc3/packets/parsers/format_string_parser.rb +4 -4
  64. data/lib/openc3/packets/parsers/limits_parser.rb +4 -4
  65. data/lib/openc3/packets/parsers/limits_response_parser.rb +5 -5
  66. data/lib/openc3/packets/parsers/processor_parser.rb +4 -4
  67. data/lib/openc3/packets/parsers/state_parser.rb +3 -3
  68. data/lib/openc3/packets/parsers/xtce_parser.rb +5 -1
  69. data/lib/openc3/script/api_shared.rb +81 -63
  70. data/lib/openc3/script/calendar.rb +109 -0
  71. data/lib/openc3/script/commands.rb +18 -19
  72. data/lib/openc3/script/limits.rb +1 -1
  73. data/lib/openc3/script/{gems.rb → packages.rb} +20 -16
  74. data/lib/openc3/script/script.rb +49 -38
  75. data/lib/openc3/script/storage.rb +4 -4
  76. data/lib/openc3/script/web_socket_api.rb +2 -2
  77. data/lib/openc3/streams/mqtt_stream.rb +109 -0
  78. data/lib/openc3/system/system.rb +2 -0
  79. data/lib/openc3/system/target.rb +10 -1
  80. data/lib/openc3/top_level.rb +2 -2
  81. data/lib/openc3/utilities/aws_bucket.rb +3 -2
  82. data/lib/openc3/utilities/bucket_file_cache.rb +1 -1
  83. data/lib/openc3/utilities/cli_generator.rb +33 -20
  84. data/lib/openc3/utilities/local_mode.rb +5 -3
  85. data/lib/openc3/utilities/logger.rb +18 -17
  86. data/lib/openc3/utilities/process_manager.rb +1 -1
  87. data/lib/openc3/utilities/ruby_lex_utils.rb +0 -8
  88. data/lib/openc3/version.rb +6 -6
  89. data/templates/conversion/conversion.py +28 -0
  90. data/templates/conversion/conversion.rb +1 -18
  91. data/templates/limits_response/response.py +37 -0
  92. data/templates/limits_response/response.rb +0 -17
  93. data/templates/microservice/microservices/TEMPLATE/microservice.py +54 -0
  94. data/templates/microservice/microservices/TEMPLATE/microservice.rb +0 -7
  95. data/templates/plugin/.gitignore +1 -0
  96. data/templates/target/targets/TARGET/lib/target.py +9 -0
  97. data/templates/target/targets/TARGET/procedures/procedure.py +3 -0
  98. data/templates/tool_angular/package.json +22 -21
  99. data/templates/tool_angular/yarn.lock +2319 -3156
  100. data/templates/tool_react/package.json +16 -16
  101. data/templates/tool_react/yarn.lock +763 -645
  102. data/templates/tool_svelte/package.json +15 -14
  103. data/templates/tool_svelte/src/services/openc3-api.js +33 -82
  104. data/templates/tool_svelte/yarn.lock +748 -538
  105. data/templates/tool_vue/package.json +15 -14
  106. data/templates/tool_vue/yarn.lock +150 -64
  107. data/templates/widget/package.json +14 -13
  108. data/templates/widget/yarn.lock +133 -58
  109. metadata +60 -7
@@ -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 2023, OpenC3, Inc.
18
18
  # All Rights Reserved
19
19
  #
20
20
  # This file may also be used under the terms of a commercial license
@@ -78,6 +78,7 @@ module OpenC3
78
78
  attr_accessor :needs_dependencies
79
79
  attr_accessor :target_microservices
80
80
  attr_accessor :children
81
+ attr_accessor :disable_erb
81
82
 
82
83
  # NOTE: The following three class methods are used by the ModelController
83
84
  # and are reimplemented to enable various Model class methods to work
@@ -349,6 +350,7 @@ module OpenC3
349
350
  target_microservices: {'REDUCER' => [[]]},
350
351
  reducer_disable: false,
351
352
  reducer_max_cpu_utilization: 30.0,
353
+ disable_erb: nil,
352
354
  scope:
353
355
  )
354
356
  super("#{scope}__#{PRIMARY_KEY}", name: name, plugin: plugin, updated_at: updated_at,
@@ -396,6 +398,7 @@ module OpenC3
396
398
  @target_microservices = target_microservices
397
399
  @reducer_disable = reducer_disable
398
400
  @reducer_max_cpu_utilization = reducer_max_cpu_utilization
401
+ @disable_erb = disable_erb
399
402
  @bucket = Bucket.getClient()
400
403
  @children = []
401
404
  end
@@ -435,7 +438,8 @@ module OpenC3
435
438
  'needs_dependencies' => @needs_dependencies,
436
439
  'target_microservices' => @target_microservices.as_json(:allow_nan => true),
437
440
  'reducer_disable' => @reducer_disable,
438
- 'reducer_max_cpu_utilization' => @reducer_max_cpu_utilization
441
+ 'reducer_max_cpu_utilization' => @reducer_max_cpu_utilization,
442
+ 'disable_erb' => @disable_erb
439
443
  }
440
444
  end
441
445
 
@@ -544,6 +548,12 @@ module OpenC3
544
548
  else
545
549
  raise ConfigParser::Error.new(parser, "PACKET cannot be used without a TARGET_MICROSERVICE")
546
550
  end
551
+ when 'DISABLE_ERB'
552
+ # 0 to unlimited parameters
553
+ @disable_erb ||= []
554
+ if parameters
555
+ @disable_erb.concat(parameters)
556
+ end
547
557
  else
548
558
  raise ConfigParser::Error.new(parser, "Unknown keyword and parameters for Target: #{keyword} #{parameters.join(" ")}")
549
559
  end
@@ -567,10 +577,13 @@ module OpenC3
567
577
  # Load target files
568
578
  @filename = filename # For render
569
579
  data = File.read(filename, mode: "rb")
580
+ erb_disabled = check_disable_erb(filename)
570
581
  begin
571
- OpenC3.set_working_dir(File.dirname(filename)) do
572
- if ERB_EXTENSIONS.include?(File.extname(filename).downcase) and File.basename(filename)[0] != '_'
573
- data = ERB.new(data.force_encoding("UTF-8").comment_erb(), trim_mode: "-").result(binding.set_variables(variables))
582
+ unless erb_disabled
583
+ OpenC3.set_working_dir(File.dirname(filename)) do
584
+ if ERB_EXTENSIONS.include?(File.extname(filename).downcase) and File.basename(filename)[0] != '_'
585
+ data = ERB.new(data.force_encoding("UTF-8").comment_erb(), trim_mode: "-").result(binding.set_variables(variables))
586
+ end
574
587
  end
575
588
  end
576
589
  rescue => error
@@ -679,9 +692,15 @@ module OpenC3
679
692
  path = File.join(File.dirname(@filename), template_name)
680
693
  end
681
694
 
695
+ data = File.read(path, mode: "rb")
696
+ erb_disabled = check_disable_erb(path)
682
697
  begin
683
- OpenC3.set_working_dir(File.dirname(path)) do
684
- return ERB.new(File.read(path).force_encoding("UTF-8").comment_erb(), trim_mode: "-").result(b)
698
+ if erb_disabled
699
+ return data
700
+ else
701
+ OpenC3.set_working_dir(File.dirname(path)) do
702
+ return ERB.new(data.force_encoding("UTF-8").comment_erb(), trim_mode: "-").result(b)
703
+ end
685
704
  end
686
705
  rescue => error
687
706
  raise "ERB error parsing: #{path}: #{error.formatted}"
@@ -692,14 +711,14 @@ module OpenC3
692
711
  target_files = []
693
712
  Find.find(target_folder) { |file| target_files << file }
694
713
  target_files.sort!
695
- hash = OpenC3.hash_files(target_files, nil, 'SHA256').hexdigest
696
- File.open(File.join(target_folder, 'target_id.txt'), 'wb') { |file| file.write(hash) }
714
+ @id = OpenC3.hash_files(target_files, nil, 'SHA256').hexdigest
715
+ File.open(File.join(target_folder, 'target_id.txt'), 'wb') { |file| file.write(@id) }
697
716
  key = "#{@scope}/targets/#{@name}/target_id.txt"
698
- @bucket.put_object(bucket: ENV['OPENC3_CONFIG_BUCKET'], key: key, body: hash)
717
+ @bucket.put_object(bucket: ENV['OPENC3_CONFIG_BUCKET'], key: key, body: @id)
699
718
 
700
719
  # Create target archive zip file
701
720
  prefix = File.dirname(target_folder) + '/'
702
- output_file = File.join(temp_dir, @name + '_' + hash + '.zip')
721
+ output_file = File.join(temp_dir, @name + '_' + @id + '.zip')
703
722
  Zip.continue_on_exists_proc = true
704
723
  Zip::File.open(output_file, Zip::File::CREATE) do |zipfile|
705
724
  target_files.each do |target_file|
@@ -718,7 +737,7 @@ module OpenC3
718
737
  @bucket.put_object(bucket: ENV['OPENC3_CONFIG_BUCKET'], key: bucket_key, body: file)
719
738
  end
720
739
  File.open(output_file, 'rb') do |file|
721
- bucket_key = key = "#{@scope}/target_archives/#{@name}/#{@name}_#{hash}.zip"
740
+ bucket_key = key = "#{@scope}/target_archives/#{@name}/#{@name}_#{@id}.zip"
722
741
  @bucket.put_object(bucket: ENV['OPENC3_CONFIG_BUCKET'], key: bucket_key, body: file)
723
742
  end
724
743
  end
@@ -733,7 +752,6 @@ module OpenC3
733
752
  @cmd_tlm_files = target.cmd_tlm_files
734
753
  @cmd_unique_id_mode = target.cmd_unique_id_mode
735
754
  @tlm_unique_id_mode = target.tlm_unique_id_mode
736
- @id = target.id
737
755
  @limits_groups = system.limits.groups.keys
738
756
  update()
739
757
 
@@ -897,13 +915,21 @@ module OpenC3
897
915
  Logger.info "Configured microservice #{microservice_name}"
898
916
  end
899
917
 
900
- def deploy_decom_microservice(gem_path, variables, topics, instance = nil, parent = nil)
918
+ def deploy_decom_microservice(target, gem_path, variables, topics, instance = nil, parent = nil)
901
919
  microservice_name = "#{@scope}__DECOM#{instance}__#{@name}"
920
+ # Assume Ruby initially
921
+ filename = 'decom_microservice.rb'
922
+ work_dir = '/openc3/lib/openc3/microservices'
923
+ if target.language == 'python'
924
+ filename = 'decom_microservice.py'
925
+ work_dir.sub!('openc3/lib', 'openc3/python')
926
+ parent = nil
927
+ end
902
928
  microservice = MicroserviceModel.new(
903
929
  name: microservice_name,
904
930
  folder_name: @folder_name,
905
- cmd: ["ruby", "decom_microservice.rb", microservice_name],
906
- work_dir: '/openc3/lib/openc3/microservices',
931
+ cmd: [target.language, filename, microservice_name],
932
+ work_dir: work_dir,
907
933
  topics: topics,
908
934
  target_names: [@name],
909
935
  plugin: @plugin,
@@ -963,7 +989,6 @@ module OpenC3
963
989
  name: microservice_name,
964
990
  cmd: ["ruby", "multi_microservice.rb", *@children],
965
991
  work_dir: '/openc3/lib/openc3/microservices',
966
- target_names: [@name],
967
992
  plugin: @plugin,
968
993
  scope: @scope
969
994
  )
@@ -976,9 +1001,14 @@ module OpenC3
976
1001
  def deploy_target_microservices(type, base_topic_list, topic_prefix)
977
1002
  target_microservices = @target_microservices[type]
978
1003
  if target_microservices
1004
+ # These are stand alone microservice(s) ... not part of MULTI
979
1005
  if base_topic_list
1006
+ # Only create the microservice if there are topics
1007
+ # This prevents creation of DECOM with no TLM Packets (for example)
980
1008
  deploy_count = 0
981
1009
  all_topics = base_topic_list.dup
1010
+
1011
+ # Figure out if there are individual packets assigned to this microservice
982
1012
  target_microservices.sort! {|a, b| a.length <=> b.length}
983
1013
  target_microservices.each_with_index do |packet_names, index|
984
1014
  topics = []
@@ -996,15 +1026,19 @@ module OpenC3
996
1026
  end
997
1027
  end
998
1028
  end
1029
+ # If there are any topics (packets) left over that haven't been
1030
+ # explictly handled above, spawn another microservice
999
1031
  if all_topics.length > 0
1000
1032
  instance = nil
1001
1033
  instance = deploy_count unless deploy_count == 0
1002
1034
  yield all_topics, instance, nil
1003
1035
  end
1004
1036
  else
1037
+ # Do not spawn the microservice
1005
1038
  yield nil, nil, nil
1006
1039
  end
1007
1040
  else
1041
+ # Not a stand alone microservice ... part of MULTI
1008
1042
  yield base_topic_list, nil, @parent if not base_topic_list or base_topic_list.length > 0
1009
1043
  end
1010
1044
  end
@@ -1068,11 +1102,12 @@ module OpenC3
1068
1102
 
1069
1103
  # Decommutation Microservice
1070
1104
  deploy_target_microservices('DECOM', packet_topic_list, "#{@scope}__TELEMETRY__{#{@name}}") do |topics, instance, parent|
1071
- deploy_decom_microservice(gem_path, variables, topics, instance, parent)
1105
+ deploy_decom_microservice(system.targets[@name], gem_path, variables, topics, instance, parent)
1072
1106
  end
1073
1107
 
1074
1108
  # Reducer Microservice
1075
1109
  unless @reducer_disable
1110
+ # TODO: Does Reducer even need a topic list?
1076
1111
  deploy_target_microservices('REDUCER', decom_topic_list, "#{@scope}__DECOM__{#{@name}}") do |topics, instance, parent|
1077
1112
  deploy_reducer_microservice(gem_path, variables, topics, instance, parent)
1078
1113
  end
@@ -24,6 +24,12 @@ require 'openc3/utilities/local_mode'
24
24
 
25
25
  module OpenC3
26
26
  class ToolConfigModel
27
+ def self.config_tool_names(scope: $openc3_scope)
28
+ cursor, keys = Store.scan(0, match: "#{scope}__config__*", type: 'hash', count: 100)
29
+ # Just return the tool name that is used in the other APIs
30
+ return keys.map! { |key| key.split('__')[2] }.sort
31
+ end
32
+
27
33
  def self.list_configs(tool, scope: $openc3_scope)
28
34
  Store.hkeys("#{scope}__config__#{tool}")
29
35
  end
@@ -32,14 +38,14 @@ module OpenC3
32
38
  Store.hget("#{scope}__config__#{tool}", name)
33
39
  end
34
40
 
35
- def self.save_config(tool, name, data, scope: $openc3_scope, local_mode: true)
41
+ def self.save_config(tool, name, data, local_mode: true, scope: $openc3_scope)
36
42
  Store.hset("#{scope}__config__#{tool}", name, data)
37
43
  LocalMode.save_tool_config(scope, tool, name, data) if local_mode
38
44
  end
39
45
 
40
- def self.delete_config(tool, name, scope: $openc3_scope)
46
+ def self.delete_config(tool, name, local_mode: true, scope: $openc3_scope)
41
47
  Store.hdel("#{scope}__config__#{tool}", name)
42
- LocalMode.delete_tool_config(scope, tool, name)
48
+ LocalMode.delete_tool_config(scope, tool, name) if local_mode
43
49
  end
44
50
  end
45
51
  end
@@ -39,6 +39,7 @@ module OpenC3
39
39
  attr_accessor :shown
40
40
  attr_accessor :position
41
41
  attr_accessor :needs_dependencies
42
+ attr_accessor :disable_erb
42
43
 
43
44
  # NOTE: The following three class methods are used by the ModelController
44
45
  # and are reimplemented to enable various Model class methods to work
@@ -135,6 +136,7 @@ module OpenC3
135
136
  updated_at: nil,
136
137
  plugin: nil,
137
138
  needs_dependencies: false,
139
+ disable_erb: nil,
138
140
  scope:
139
141
  )
140
142
  super("#{scope}__#{PRIMARY_KEY}", name: name, plugin: plugin, updated_at: updated_at, scope: scope)
@@ -152,6 +154,7 @@ module OpenC3
152
154
  @url = "/tools/#{folder_name}" unless @url
153
155
  end
154
156
  @needs_dependencies = needs_dependencies
157
+ @disable_erb = disable_erb
155
158
  end
156
159
 
157
160
  def create(update: false, force: false)
@@ -159,9 +162,11 @@ module OpenC3
159
162
 
160
163
  # Make sure a tool with this folder_name doesn't already exist
161
164
  unless update
162
- tools.each do |_tool_name, tool|
163
- if tool['folder_name'] == @folder_name
164
- raise "Tool with folder_name #{@folder_name} already exists at create"
165
+ if @folder_name
166
+ tools.each do |_tool_name, tool|
167
+ if tool['folder_name'] == @folder_name
168
+ raise "Tool with folder_name #{@folder_name} already exists at create"
169
+ end
165
170
  end
166
171
  end
167
172
  end
@@ -193,6 +198,7 @@ module OpenC3
193
198
  'updated_at' => @updated_at,
194
199
  'plugin' => @plugin,
195
200
  'needs_dependencies' => @needs_dependencies,
201
+ 'disable_erb' => @disable_erb
196
202
  }
197
203
  end
198
204
 
@@ -203,14 +209,14 @@ module OpenC3
203
209
  @url = parameters[0]
204
210
  when 'INLINE_URL'
205
211
  parser.verify_num_parameters(1, 1, "INLINE_URL <URL>")
206
- @inline_url = parameters[0]
212
+ @inline_url = ConfigParser.handle_nil(parameters[0])
207
213
  when 'ICON'
208
214
  parser.verify_num_parameters(1, 1, "ICON <ICON Name>")
209
215
  @icon = parameters[0]
210
216
  when 'WINDOW'
211
- parser.verify_num_parameters(1, 1, "WINDOW <INLINE | IFRAME | NEW>")
217
+ parser.verify_num_parameters(1, 1, "WINDOW <INLINE | IFRAME | SAME | NEW>")
212
218
  @window = parameters[0].to_s.upcase
213
- raise ConfigParser::Error.new(parser, "Invalid WINDOW setting: #{@window}") unless ['INLINE', 'IFRAME', 'NEW'].include?(@window)
219
+ raise ConfigParser::Error.new(parser, "Invalid WINDOW setting: #{@window}") unless ['INLINE', 'IFRAME', 'SAME', 'NEW'].include?(@window)
214
220
  when 'CATEGORY'
215
221
  parser.verify_num_parameters(1, 1, "CATEGORY <Category Name>")
216
222
  @category = parameters[0].to_s
@@ -220,6 +226,12 @@ module OpenC3
220
226
  when 'POSITION'
221
227
  parser.verify_num_parameters(1, 1, "POSITION <value>")
222
228
  @position = parameters[0].to_i
229
+ when 'DISABLE_ERB'
230
+ # 0 to unlimited parameters
231
+ @disable_erb ||= []
232
+ if parameters
233
+ @disable_erb.concat(parameters)
234
+ end
223
235
  else
224
236
  raise ConfigParser::Error.new(parser, "Unknown keyword and parameters for Tool: #{keyword} #{parameters.join(" ")}")
225
237
  end
@@ -240,7 +252,10 @@ module OpenC3
240
252
 
241
253
  # Load tool files
242
254
  data = File.read(filename, mode: "rb")
243
- data = ERB.new(data.comment_erb(), trim_mode: "-").result(binding.set_variables(variables)) if data.is_printable?
255
+ erb_disabled = check_disable_erb(filename)
256
+ unless erb_disabled
257
+ data = ERB.new(data.comment_erb(), trim_mode: "-").result(binding.set_variables(variables)) if data.is_printable?
258
+ end
244
259
  unless validate_only
245
260
  client = Bucket.getClient()
246
261
  cache_control = BucketUtilities.get_cache_control(filename)
@@ -35,6 +35,7 @@ module OpenC3
35
35
  attr_accessor :filename
36
36
  attr_accessor :bucket_key
37
37
  attr_accessor :needs_dependencies
38
+ attr_accessor :disable_erb
38
39
 
39
40
  # NOTE: The following three class methods are used by the ModelController
40
41
  # and are reimplemented to enable various Model class methods to work
@@ -87,6 +88,7 @@ module OpenC3
87
88
  plugin: nil,
88
89
  label: nil,
89
90
  needs_dependencies: false,
91
+ disable_erb: nil,
90
92
  scope:
91
93
  )
92
94
  super("#{scope}__#{PRIMARY_KEY}", name: name, plugin: plugin, updated_at: updated_at, scope: scope)
@@ -95,6 +97,7 @@ module OpenC3
95
97
  @bucket_key = 'widgets/' + @full_name + '/' + @filename
96
98
  @label = label
97
99
  @needs_dependencies = needs_dependencies
100
+ @disable_erb = disable_erb
98
101
  end
99
102
 
100
103
  def as_json(*a)
@@ -104,11 +107,21 @@ module OpenC3
104
107
  'plugin' => @plugin,
105
108
  'label' => @label,
106
109
  'needs_dependencies' => @needs_dependencies,
110
+ 'disable_erb' => @disable_erb
107
111
  }
108
112
  end
109
113
 
110
114
  def handle_config(parser, keyword, parameters)
111
- raise ConfigParser::Error.new(parser, "Unknown keyword and parameters for Widget: #{keyword} #{parameters.join(" ")}")
115
+ case keyword
116
+ when 'DISABLE_ERB'
117
+ # 0 to unlimited parameters
118
+ @disable_erb ||= []
119
+ if parameters
120
+ @disable_erb.concat(parameters)
121
+ end
122
+ else
123
+ raise ConfigParser::Error.new(parser, "Unknown keyword and parameters for Widget: #{keyword} #{parameters.join(" ")}")
124
+ end
112
125
  end
113
126
 
114
127
  def deploy(gem_path, variables, validate_only: false)
@@ -123,8 +136,11 @@ module OpenC3
123
136
 
124
137
  # Load widget file
125
138
  data = File.read(filename, mode: "rb")
126
- OpenC3.set_working_dir(File.dirname(filename)) do
127
- data = ERB.new(data.comment_erb(), trim_mode: "-").result(binding.set_variables(variables)) if data.is_printable?
139
+ erb_disabled = check_disable_erb(filename)
140
+ unless erb_disabled
141
+ OpenC3.set_working_dir(File.dirname(filename)) do
142
+ data = ERB.new(data.comment_erb(), trim_mode: "-").result(binding.set_variables(variables)) if data.is_printable?
143
+ end
128
144
  end
129
145
  unless validate_only
130
146
  cache_control = BucketUtilities.get_cache_control(@filename)
@@ -50,8 +50,10 @@ module OpenC3
50
50
  env = microservice_config["env"].dup
51
51
  if microservice_config["needs_dependencies"]
52
52
  env['GEM_HOME'] = '/gems'
53
+ env['PYTHONUSERBASE'] = '/gems/python_packages'
53
54
  else
54
55
  env['GEM_HOME'] = nil
56
+ env['PYTHONUSERBASE'] = nil
55
57
  end
56
58
  env['OPENC3_MICROSERVICE_NAME'] = microservice_name
57
59
  container = microservice_config["container"]
@@ -65,66 +65,97 @@ module OpenC3
65
65
  # @param name [String] Name of the item to read - Should already by upcase
66
66
  # @param value_type (see #read_item)
67
67
  def read(name, value_type = :CONVERTED, reduced_type = nil)
68
+ value = nil
69
+ array_index = nil
70
+ if name[-1] == ']'
71
+ open_bracket_index = name.index('[')
72
+ if open_bracket_index
73
+ array_index = name[(open_bracket_index + 1)..-2].to_i
74
+ name = name[0..(open_bracket_index - 1)]
75
+ end
76
+ end
68
77
  if reduced_type
69
78
  raise "Reduced types only support RAW or CONVERTED value types: #{value_type} unsupported" if value_type == :WITH_UNITS or value_type == :FORMATTED
70
79
  if value_type == :CONVERTED
71
80
  case reduced_type
72
81
  when :AVG
73
82
  value = @json_hash["#{name}__CA"]
74
- return value if value
75
83
  when :STDDEV
76
84
  value = @json_hash["#{name}__CS"]
77
- return value if value
78
85
  when :MIN
79
86
  value = @json_hash["#{name}__CN"]
80
- return value if value
81
87
  when :MAX
82
88
  value = @json_hash["#{name}__CX"]
83
- return value if value
89
+ end
90
+ if value
91
+ value = value[array_index] if array_index
92
+ return value
84
93
  end
85
94
  end
86
95
  case reduced_type
87
96
  when :AVG
88
97
  value = @json_hash["#{name}__A"]
89
- return value if value
90
98
  when :STDDEV
91
99
  value = @json_hash["#{name}__S"]
92
- return value if value
93
100
  when :MIN
94
101
  value = @json_hash["#{name}__N"]
95
- return value if value
96
102
  when :MAX
97
103
  value = @json_hash["#{name}__X"]
98
- return value if value
104
+ end
105
+ if value
106
+ value = value[array_index] if array_index
107
+ return value
99
108
  end
100
109
  end
101
110
  if value_type == :WITH_UNITS
102
111
  value = @json_hash["#{name}__U"]
103
- return value if value
112
+ if value
113
+ value = value[array_index] if array_index
114
+ return value
115
+ end
104
116
  end
105
117
  if value_type == :WITH_UNITS or value_type == :FORMATTED
106
118
  value = @json_hash["#{name}__F"]
107
- return value if value
119
+ if value
120
+ value = value[array_index] if array_index
121
+ return value
122
+ end
108
123
 
109
124
  value = @json_hash["#{name}__C"]
110
- return value.to_s if value
125
+ if value
126
+ value = value[array_index] if array_index
127
+ return value.to_s
128
+ end
111
129
 
112
130
  value = @json_hash[name]
113
- return value.to_s if value
131
+ if value
132
+ value = value[array_index] if array_index
133
+ return value.to_s
134
+ end
114
135
 
115
136
  return nil
116
137
  end
117
138
  if value_type == :CONVERTED
118
139
  value = @json_hash["#{name}__C"]
119
- return value if value
140
+ if value
141
+ value = value[array_index] if array_index
142
+ return value
143
+ end
120
144
  end
121
- return @json_hash[name]
145
+ value = @json_hash[name]
146
+ if value
147
+ value = value[array_index] if array_index
148
+ return value
149
+ end
150
+ return nil
122
151
  end
123
152
 
124
153
  def read_with_limits_state(name, value_type = :CONVERTED, reduced_type = nil)
125
154
  value = read(name, value_type, reduced_type)
126
155
  limits_state = @json_hash["#{name}__L"]
127
- limits_state.intern if limits_state
156
+ if limits_state
157
+ limits_state = limits_state.intern
158
+ end
128
159
  return [value, limits_state]
129
160
  end
130
161
 
@@ -73,21 +73,21 @@ module OpenC3
73
73
  # @param packet_name [String] The packet name. Must be a defined packet name and not 'LATEST'.
74
74
  # @param item_name [String] The item name
75
75
  def enabled?(target_name, packet_name, item_name)
76
- get_packet(target_name, packet_name).get_item(item_name).limits.enabled
76
+ _get_packet(target_name, packet_name).get_item(item_name).limits.enabled
77
77
  end
78
78
 
79
79
  # Enables limit checking for the specified item
80
80
  #
81
81
  # @param (see #enabled?)
82
82
  def enable(target_name, packet_name, item_name)
83
- get_packet(target_name, packet_name).enable_limits(item_name)
83
+ _get_packet(target_name, packet_name).enable_limits(item_name)
84
84
  end
85
85
 
86
86
  # Disables limit checking for the specified item
87
87
  #
88
88
  # @param (see #enabled?)
89
89
  def disable(target_name, packet_name, item_name)
90
- get_packet(target_name, packet_name).disable_limits(item_name)
90
+ _get_packet(target_name, packet_name).disable_limits(item_name)
91
91
  end
92
92
 
93
93
  # Get the limits for a telemetry item
@@ -98,7 +98,7 @@ module OpenC3
98
98
  # @param limits_set [String or Symbol or nil] Desired Limits set. nil = current limits set
99
99
  # @return [Array<limits_set, persistence, enabled, red_low, yellow_low, red_high, yellow_high, green_low (optional), green_high (optional)] Limits information
100
100
  def get(target_name, packet_name, item_name, limits_set = nil)
101
- limits = get_packet(target_name, packet_name).get_item(item_name).limits
101
+ limits = _get_packet(target_name, packet_name).get_item(item_name).limits
102
102
  if limits.values
103
103
  if limits_set
104
104
  limits_set = limits_set.to_s.upcase.intern
@@ -132,7 +132,7 @@ module OpenC3
132
132
  # @param enabled [Boolean] If limits monitoring is enabled for this item
133
133
  # @return [Array<limits_set, persistence, enabled, red_low, yellow_low, red_high, yellow_high, green_low (optional), green_high (optional)] Limits information
134
134
  def set(target_name, packet_name, item_name, red_low, yellow_low, yellow_high, red_high, green_low = nil, green_high = nil, limits_set = :CUSTOM, persistence = nil, enabled = true)
135
- packet = get_packet(target_name, packet_name)
135
+ packet = _get_packet(target_name, packet_name)
136
136
  item = packet.get_item(item_name)
137
137
  limits = item.limits
138
138
  if limits_set
@@ -172,7 +172,7 @@ module OpenC3
172
172
 
173
173
  protected
174
174
 
175
- def get_packet(target_name, packet_name)
175
+ def _get_packet(target_name, packet_name)
176
176
  raise "LATEST packet not valid" if packet_name.upcase == LATEST_PACKET_NAME
177
177
 
178
178
  packets = @config.telemetry[target_name.to_s.upcase]
@@ -183,17 +183,5 @@ module OpenC3
183
183
 
184
184
  return packet
185
185
  end
186
-
187
- def includes_item?(ignored_items, target_name, packet_name, item_name)
188
- ignored_items.each do |array_target_name, array_packet_name, array_item_name|
189
- if (array_target_name == target_name) &&
190
- (array_packet_name == packet_name) &&
191
- # If the item name is nil we're ignoring an entire packet
192
- (array_item_name == item_name || array_item_name.nil?)
193
- return true
194
- end
195
- end
196
- return false
197
- end
198
186
  end
199
187
  end
@@ -1061,6 +1061,7 @@ module OpenC3
1061
1061
  config['accessor'] = @accessor.class.to_s
1062
1062
  config['accessor_args'] = @accessor.args
1063
1063
  config['template'] = Base64.encode64(@template) if @template
1064
+ config['config_name'] = self.config_name
1064
1065
 
1065
1066
  if @processors
1066
1067
  processors = []
@@ -119,7 +119,8 @@ module OpenC3
119
119
  # an xtce file to automatically determine the target name.
120
120
  def process_file(filename, process_target_name)
121
121
  # Handle .xtce files
122
- if File.extname(filename).to_s.downcase == ".xtce"
122
+ extension = File.extname(filename).to_s.downcase
123
+ if extension == ".xtce" or extension == ".xml"
123
124
  XtceParser.process(@commands, @telemetry, @warnings, filename, process_target_name)
124
125
  return
125
126
  end
@@ -17,7 +17,7 @@
17
17
  # All changes Copyright 2022, 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
  module OpenC3
@@ -25,9 +25,9 @@ module OpenC3
25
25
  # @param parser [ConfigParser] Configuration parser
26
26
  # @param item [Packet] The current item
27
27
  def self.parse(parser, item)
28
- @parser = FormatStringParser.new(parser)
29
- @parser.verify_parameters()
30
- @parser.create_format_string(item)
28
+ parser = FormatStringParser.new(parser)
29
+ parser.verify_parameters()
30
+ parser.create_format_string(item)
31
31
  end
32
32
 
33
33
  # @param parser [ConfigParser] Configuration parser
@@ -17,7 +17,7 @@
17
17
  # All changes Copyright 2022, 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
  module OpenC3
@@ -31,9 +31,9 @@ module OpenC3
31
31
  def self.parse(parser, packet, cmd_or_tlm, item, warnings)
32
32
  raise parser.error("Items with STATE can't define LIMITS") if item.states
33
33
 
34
- @parser = LimitsParser.new(parser)
35
- @parser.verify_parameters(cmd_or_tlm)
36
- @parser.create_limits(packet, item, warnings)
34
+ parser = LimitsParser.new(parser)
35
+ parser.verify_parameters(cmd_or_tlm)
36
+ parser.create_limits(packet, item, warnings)
37
37
  end
38
38
 
39
39
  def initialize(parser)
@@ -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 2023, 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
  module OpenC3
@@ -26,9 +26,9 @@ module OpenC3
26
26
  # @param item [Packet] The current item
27
27
  # @param cmd_or_tlm [String] Whether this is a command or telemetry packet
28
28
  def self.parse(parser, item, cmd_or_tlm)
29
- @parser = LimitsResponseParser.new(parser)
30
- @parser.verify_parameters(cmd_or_tlm)
31
- @parser.create_limits_response(item)
29
+ parser = LimitsResponseParser.new(parser)
30
+ parser.verify_parameters(cmd_or_tlm)
31
+ parser.create_limits_response(item)
32
32
  end
33
33
 
34
34
  # @param parser [ConfigParser] Configuration parser