openc3 6.4.2 → 6.5.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/bin/openc3cli +172 -97
- data/data/config/_graph_params.yaml +4 -4
- data/data/config/conversions.yaml +2 -1
- data/data/config/item_modifiers.yaml +1 -0
- data/data/config/plugins.yaml +14 -1
- data/data/config/processors.yaml +51 -0
- data/data/config/telemetry_modifiers.yaml +1 -0
- data/lib/openc3/api/tlm_api.rb +10 -5
- data/lib/openc3/microservices/interface_microservice.rb +15 -9
- data/lib/openc3/models/plugin_model.rb +5 -4
- data/lib/openc3/models/scope_model.rb +87 -57
- data/lib/openc3/models/script_engine_model.rb +93 -0
- data/lib/openc3/models/script_status_model.rb +4 -0
- data/lib/openc3/models/target_model.rb +7 -1
- data/lib/openc3/script/script.rb +5 -1
- data/lib/openc3/script_engines/script_engine.rb +118 -0
- data/lib/openc3/topics/interface_topic.rb +23 -3
- data/lib/openc3/utilities/cli_generator.rb +42 -15
- data/lib/openc3/utilities/running_script.rb +1460 -0
- data/lib/openc3/version.rb +6 -6
- data/templates/conversion/conversion.py +1 -1
- data/templates/conversion/conversion.rb +1 -1
- data/templates/processor/processor.py +32 -0
- data/templates/processor/processor.rb +36 -0
- data/templates/tool_angular/package.json +2 -2
- data/templates/tool_react/package.json +1 -1
- data/templates/tool_svelte/package.json +1 -1
- data/templates/tool_vue/package.json +3 -3
- data/templates/widget/package.json +2 -2
- metadata +7 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5c28c663c7d3743f9bb095a0818ae486accf2f1bb69f5079ec95788153f3005f
|
4
|
+
data.tar.gz: 64a60dc5bad2e3cdc78953b2dbd49a689d4b91a08e80bf8a2c4668b308a811bf
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 88c76af077c0feeec36831656367e9a5c2ff4968d8d567a6d3822f4a7dec1afea33d4921aa6d5941f97c4234a85da68aa7ef7b1767eeb629650a85589f9db673
|
7
|
+
data.tar.gz: 0c548964225e629edff50e0666347eedcc8e6b0d9fb7ab5d134fb0a206e481ba2353568fa6ab99f0fbdfdc6758c62eec7320deeb1c0a37a4448544b2ee26215d
|
data/bin/openc3cli
CHANGED
@@ -15,7 +15,7 @@
|
|
15
15
|
# GNU Affero General Public License for more details.
|
16
16
|
|
17
17
|
# Modified by OpenC3, Inc.
|
18
|
-
# All changes Copyright
|
18
|
+
# All changes Copyright 2025, OpenC3, Inc.
|
19
19
|
# All Rights Reserved
|
20
20
|
#
|
21
21
|
# This file may also be used under the terms of a commercial license
|
@@ -62,14 +62,7 @@ def print_usage
|
|
62
62
|
puts " cli help # Displays this information"
|
63
63
|
puts " cli rake # Runs rake in the local directory"
|
64
64
|
puts " cli irb # Runs irb in the local directory"
|
65
|
-
puts " cli script
|
66
|
-
puts " cli script spawn NAME SCOPE variable1=value1 variable2=value2 # Starts named script remotely"
|
67
|
-
puts " cli script run NAME SCOPE variable1=value1 variable2=value2 # Starts named script, monitoring status on console,\
|
68
|
-
by default until error or exit"
|
69
|
-
puts " cli script init # initialize running scripts (Enterprise Only)"
|
70
|
-
puts " PARAMETERS name-value pairs to form the script's runtime environment"
|
71
|
-
puts " OPTIONS: --wait 0 seconds to monitor status before detaching from the running script; ie --wait 100"
|
72
|
-
puts " --disconnect run the script in disconnect mode"
|
65
|
+
puts " cli script # Interact with scripts. Run with --help for more info."
|
73
66
|
puts " cli validate /PATH/FILENAME.gem SCOPE variables.txt # Validate a COSMOS plugin gem file"
|
74
67
|
puts " cli load /PATH/FILENAME.gem SCOPE variables.txt # Loads a COSMOS plugin gem file"
|
75
68
|
puts " cli list <SCOPE> # Lists installed plugins, SCOPE is DEFAULT if not given"
|
@@ -619,86 +612,180 @@ def cli_script_monitor(script_id)
|
|
619
612
|
return ret_code
|
620
613
|
end
|
621
614
|
|
622
|
-
def
|
623
|
-
|
624
|
-
|
625
|
-
|
615
|
+
def get_env_from_args(args)
|
616
|
+
# Figure out if there are any optional environment variables
|
617
|
+
# args[0] is the command, args[1] is the script file
|
618
|
+
# args[2..-1] are environment variables specified as NAME=VALUE
|
619
|
+
environ = {}
|
620
|
+
if args.length > 2
|
621
|
+
args[2..-1].each do |arg|
|
622
|
+
name, value = arg.split('=')
|
623
|
+
if name and value
|
624
|
+
environ[name] = value
|
625
|
+
end
|
626
|
+
end
|
626
627
|
end
|
627
|
-
|
628
|
-
|
628
|
+
return environ
|
629
|
+
end
|
630
|
+
|
631
|
+
def cli_script_init
|
629
632
|
require 'openc3/script'
|
630
|
-
|
631
|
-
puts(script_name) if script_name.start_with?(path)
|
632
|
-
end
|
633
|
+
initialize_offline_access()
|
633
634
|
return 0
|
634
635
|
end
|
635
636
|
|
636
|
-
def
|
637
|
-
|
638
|
-
|
637
|
+
def cli_script_list(args, options)
|
638
|
+
require 'openc3/script'
|
639
|
+
puts script_list(scope: options[:scope])
|
640
|
+
return 0
|
641
|
+
end
|
642
|
+
|
643
|
+
def cli_script_run(args, options)
|
644
|
+
environment = get_env_from_args(args)
|
645
|
+
|
639
646
|
ret_code = ERROR_CODE
|
640
|
-
wait_limit = 0
|
641
|
-
if (i = args.index('--wait'))
|
642
|
-
begin
|
643
|
-
args.delete('--wait')
|
644
|
-
# pull out the flag
|
645
|
-
seconds = args[i]
|
646
|
-
wait_limit = Integer(seconds, 10) # only decimal, ignore leading 0
|
647
|
-
args.delete_at(i)
|
648
|
-
# and its value
|
649
|
-
rescue ArgumentError
|
650
|
-
abort(" --wait requires a number of seconds to wait, not [#{seconds}]")
|
651
|
-
end
|
652
|
-
end
|
653
|
-
abort("No script file provided") if args[0].nil?
|
654
|
-
scope = args[1]
|
655
|
-
scope ||= 'DEFAULT'
|
656
647
|
require 'openc3/script'
|
657
|
-
id = script_run(args[
|
658
|
-
|
659
|
-
|
660
|
-
|
661
|
-
else
|
662
|
-
Timeout::timeout(wait_limit, nil, "--wait #{wait_limit} exceeded") do
|
648
|
+
if (id = script_run(args[1], disconnect: options[:disconnect], environment: environment, scope: options[:scope]))
|
649
|
+
puts id
|
650
|
+
$script_interrupt_text = " Script #{args[1]} still running remotely.\n" # for Ctrl-C
|
651
|
+
if (options[:wait] < 1) then
|
663
652
|
ret_code = cli_script_monitor(id)
|
664
|
-
|
665
|
-
|
666
|
-
|
667
|
-
|
668
|
-
|
669
|
-
|
653
|
+
else
|
654
|
+
Timeout::timeout(options[:wait], nil, "--wait #{options[:wait]} exceeded") do
|
655
|
+
ret_code = cli_script_monitor(id)
|
656
|
+
rescue Timeout::ExitException, Timeout::Error => e
|
657
|
+
# Timeout exceptions are also raised by the Websocket API, so we check
|
658
|
+
if e.message =~ /^--wait /
|
659
|
+
puts e.message + ", detaching from running script #{args[1]}"
|
660
|
+
else
|
661
|
+
raise
|
662
|
+
end
|
670
663
|
end
|
671
664
|
end
|
672
665
|
end
|
673
666
|
return ret_code
|
667
|
+
rescue => e
|
668
|
+
puts "Error running script: #{e.message}"
|
669
|
+
puts "Have you called 'script init'?"
|
670
|
+
puts e.backtrace
|
671
|
+
return ERROR_CODE
|
674
672
|
end
|
675
673
|
|
676
|
-
def cli_script_spawn(
|
674
|
+
def cli_script_spawn(args, options)
|
675
|
+
environment = get_env_from_args(args)
|
676
|
+
|
677
677
|
ret_code = ERROR_CODE
|
678
|
-
if (args.index('--wait'))
|
679
|
-
abort("Did you mean \"script run --wait <seconds> [...]\"?")
|
680
|
-
end
|
681
|
-
abort("No script file provided") if args[0].nil?
|
682
|
-
# heaven help you if you left out the script name
|
683
|
-
scope = args[1]
|
684
|
-
scope ||= 'DEFAULT'
|
685
678
|
require 'openc3/script'
|
686
|
-
if (id = script_run(args[
|
679
|
+
if (id = script_run(args[1], disconnect: options[:disconnect], environment: environment, scope: options[:scope]))
|
687
680
|
puts id
|
688
681
|
ret_code = 0
|
689
682
|
end
|
690
683
|
return ret_code
|
684
|
+
rescue => e
|
685
|
+
puts "Error running script: #{e.message}"
|
686
|
+
puts "Have you called 'script init'?"
|
687
|
+
puts e.backtrace
|
688
|
+
return ERROR_CODE
|
691
689
|
end
|
692
690
|
|
693
|
-
def
|
691
|
+
def cli_script_running(args, options)
|
692
|
+
ret_code = ERROR_CODE
|
694
693
|
require 'openc3/script'
|
695
|
-
|
694
|
+
if args[1]
|
695
|
+
limit = args[1].to_i
|
696
|
+
else
|
697
|
+
limit = 100
|
698
|
+
end
|
699
|
+
if args[2]
|
700
|
+
offset = args[2].to_i
|
701
|
+
else
|
702
|
+
offset = 0
|
703
|
+
end
|
704
|
+
if (list = running_script_list(limit: limit, offset: offset, scope: options[:scope]))
|
705
|
+
if options[:verbose]
|
706
|
+
pp list
|
707
|
+
else
|
708
|
+
printf("%-5s %-20s %-30s %-22s %-10s\n", "ID", "User", "Filename", "Start Time", "State")
|
709
|
+
list.each do |hash|
|
710
|
+
printf("%-5s %-20s %-30s %-22s %-10s\n", hash['name'], hash['user_full_name'], hash['filename'], hash['start_time'], hash['state'])
|
711
|
+
end
|
712
|
+
end
|
713
|
+
ret_code = 0
|
714
|
+
end
|
715
|
+
return ret_code
|
716
|
+
rescue => e
|
717
|
+
puts "Error getting script status for #{args[1]}: #{e.message}"
|
718
|
+
puts "Have you called 'script init'?"
|
719
|
+
puts e.backtrace
|
720
|
+
return ERROR_CODE
|
721
|
+
end
|
722
|
+
|
723
|
+
def cli_script_status(args, options)
|
724
|
+
ret_code = ERROR_CODE
|
725
|
+
require 'openc3/script'
|
726
|
+
if (hash = script_get(args[1], scope: options[:scope]))
|
727
|
+
if options[:verbose]
|
728
|
+
pp hash
|
729
|
+
else
|
730
|
+
printf("%-5s %-20s %-30s %-22s %-10s\n", "ID", "User", "Filename", "Start Time", "State")
|
731
|
+
printf("%-5s %-20s %-30s %-22s %-10s\n", hash['name'], hash['user_full_name'], hash['filename'], hash['start_time'], hash['state'])
|
732
|
+
end
|
733
|
+
ret_code = 0
|
734
|
+
end
|
735
|
+
return ret_code
|
736
|
+
rescue => e
|
737
|
+
puts "Error getting script status for #{args[1]}: #{e.message}"
|
738
|
+
puts "Have you called 'script init'?"
|
739
|
+
puts e.backtrace
|
740
|
+
return ERROR_CODE
|
741
|
+
end
|
742
|
+
|
743
|
+
def cli_script_stop(args, options)
|
744
|
+
require 'openc3/script'
|
745
|
+
running_script_stop(args[1], scope: options[:scope])
|
696
746
|
return 0
|
747
|
+
rescue => e
|
748
|
+
puts "Error stopping script #{args[1]}: #{e.message}"
|
749
|
+
puts "Have you called 'script init'?"
|
750
|
+
puts e.backtrace
|
751
|
+
return ERROR_CODE
|
697
752
|
end
|
698
753
|
|
699
|
-
## cli_script(args) turns an ARGV of [spawn|run] <--wait 123...> <--disconnect> SCRIPT <scope> <ENV_A=1 ENV_B=2 ...>
|
700
|
-
# into function calls and tidied parameters to remote-control a script via RunningScriptWebSocketApi
|
701
754
|
def cli_script(args=[])
|
755
|
+
options = {scope: 'DEFAULT', disconnect: false, wait: 0, verbose: false}
|
756
|
+
option_parser = OptionParser.new do |opts|
|
757
|
+
opts.banner = "Usage: script --scope SCOPE [init | list | spawn | run]\n" +
|
758
|
+
" init Initialize running scripts (Enterprise Only)\n" +
|
759
|
+
" list List scripts in the specified scope\n" +
|
760
|
+
" spawn SCRIPT [ENV=VALUE] Spawn SCRIPT in the specified scope with optional env vars and return script ID\n" +
|
761
|
+
" run SCRIPT [ENV=VALUE] Run SCRIPT in the specified scope with optional env vars and print script output\n" +
|
762
|
+
" running [LIMIT] [OFFSET] Get a list of all running scripts (limit 100 by default). Use LIMIT and OFFSET to get large batches.\n" +
|
763
|
+
" status SCRIPT_ID Get status for the running script given by SCRIPT_ID\n" +
|
764
|
+
" stop SCRIPT_ID Stop the running script given by SCRIPT_ID\n"
|
765
|
+
opts.on("-h", "--help", "Show this message") do
|
766
|
+
puts opts
|
767
|
+
exit
|
768
|
+
end
|
769
|
+
opts.on("--scope SCOPE", "Run with specified scope (default = DEFAULT)") do |arg|
|
770
|
+
options[:scope] = arg
|
771
|
+
end
|
772
|
+
opts.on("-d", "--disconnect", "Run a script in disconnect mode (default = false)") do |arg|
|
773
|
+
options[:disconnect] = arg
|
774
|
+
end
|
775
|
+
opts.on("-w SECONDS", "--wait SECONDS", "*run only* - wait for the specified number of seconds before aborting script monitoring") do |arg|
|
776
|
+
options[:wait] = Integer(arg)
|
777
|
+
end
|
778
|
+
opts.on("-v", "--verbose", "*status only* - output ALL status information") do |arg|
|
779
|
+
options[:verbose] = arg
|
780
|
+
end
|
781
|
+
end
|
782
|
+
|
783
|
+
begin
|
784
|
+
option_parser.parse!(args)
|
785
|
+
rescue
|
786
|
+
abort(option_parser.to_s)
|
787
|
+
end
|
788
|
+
|
702
789
|
ret_code = ERROR_CODE
|
703
790
|
check_environment()
|
704
791
|
# Double check for the OPENC3_API_PASSWORD because it is absolutely required
|
@@ -706,38 +793,30 @@ def cli_script(args=[])
|
|
706
793
|
if ENV['OPENC3_API_PASSWORD'].nil? or ENV['OPENC3_API_PASSWORD'].empty?
|
707
794
|
abort "OPENC3_API_PASSWORD environment variable is required for cli script"
|
708
795
|
end
|
709
|
-
|
710
|
-
#
|
711
|
-
|
712
|
-
|
713
|
-
|
714
|
-
args.each do |arg|
|
715
|
-
name, value = arg.split('=')
|
716
|
-
if name and value
|
717
|
-
# add env[k]=v ; pull out "k=v"
|
718
|
-
environ[name] = value
|
719
|
-
args.delete(arg)
|
720
|
-
end
|
721
|
-
end
|
796
|
+
|
797
|
+
# The script command is the first parameter and it is required
|
798
|
+
command = args[0]
|
799
|
+
abort(option_parser.to_s) unless command
|
800
|
+
|
722
801
|
case command
|
723
|
-
|
724
|
-
|
725
|
-
# or ["/<path>"]
|
726
|
-
# or ["<scope>"]
|
727
|
-
# or []
|
802
|
+
when 'init'
|
803
|
+
ret_code = cli_script_init()
|
728
804
|
when 'list'
|
729
|
-
ret_code = cli_script_list(args)
|
730
|
-
# for spawn or run
|
731
|
-
# args[] should now be ["--wait 100", "script_name", "<scope>"]
|
732
|
-
# or ["--wait 100", "script_name"]
|
733
|
-
# or ["script_name", "<scope>"]
|
734
|
-
# or ["script_name"]
|
805
|
+
ret_code = cli_script_list(args, options)
|
735
806
|
when 'spawn'
|
736
|
-
|
807
|
+
abort(option_parser.to_s) unless args[1] # script file is required
|
808
|
+
ret_code = cli_script_spawn(args, options)
|
737
809
|
when 'run'
|
738
|
-
|
739
|
-
|
740
|
-
|
810
|
+
abort(option_parser.to_s) unless args[1] # script file is required
|
811
|
+
ret_code = cli_script_run(args, options)
|
812
|
+
when 'running'
|
813
|
+
ret_code = cli_script_running(args, options)
|
814
|
+
when 'status'
|
815
|
+
abort(option_parser.to_s) unless args[1] # script ID is required
|
816
|
+
ret_code = cli_script_status(args, options)
|
817
|
+
when 'stop'
|
818
|
+
abort(option_parser.to_s) unless args[1] # script ID is required
|
819
|
+
ret_code = cli_script_stop(args, options)
|
741
820
|
else
|
742
821
|
abort 'openc3cli internal error: parsing arguments'
|
743
822
|
end
|
@@ -754,13 +833,7 @@ if not ARGV[0].nil? # argument(s) given
|
|
754
833
|
IRB.start
|
755
834
|
|
756
835
|
when 'script'
|
757
|
-
|
758
|
-
when 'list', 'run', 'spawn', 'init'
|
759
|
-
cli_script(ARGV[1..-1])
|
760
|
-
else
|
761
|
-
# invalid actions, misplaced and malformed leading options and 'help' come here
|
762
|
-
abort("cli script <action> must be one of #{CLI_SCRIPT_ACTIONS}, not [#{ARGV[1]}]")
|
763
|
-
end
|
836
|
+
cli_script(ARGV[1..-1])
|
764
837
|
|
765
838
|
when 'rake'
|
766
839
|
if File.exist?('Rakefile')
|
@@ -790,6 +863,8 @@ if not ARGV[0].nil? # argument(s) given
|
|
790
863
|
cli_pkg_uninstall(ARGV[1], scope: ARGV[2])
|
791
864
|
|
792
865
|
when 'generate'
|
866
|
+
# To test against a local copy call this file from the root cosmos directory like this:
|
867
|
+
# ruby -Iopenc3/lib openc3/bin/openc3cli generate ...
|
793
868
|
OpenC3::CliGenerator.generate(ARGV[1..-1])
|
794
869
|
|
795
870
|
when 'rubysloc'
|
@@ -1,17 +1,17 @@
|
|
1
1
|
---
|
2
|
-
- name: Target
|
2
|
+
- name: Target Name
|
3
3
|
required: true
|
4
4
|
description: The target name
|
5
5
|
values: .+
|
6
|
-
- name: Packet
|
6
|
+
- name: Packet Name
|
7
7
|
required: true
|
8
8
|
description: The packet name
|
9
9
|
values: .+
|
10
|
-
- name: Item
|
10
|
+
- name: Item Name
|
11
11
|
required: true
|
12
12
|
description: The item name
|
13
13
|
values: .+
|
14
|
-
- name: Value
|
14
|
+
- name: Value Type
|
15
15
|
required: false
|
16
16
|
description: The type of the value to display. Default is CONVERTED.
|
17
17
|
values: <%= %w(RAW CONVERTED) %>
|
@@ -118,6 +118,7 @@ PROCESSOR_CONVERSION:
|
|
118
118
|
description: |
|
119
119
|
This command reads a value from a processor. The value is read from the
|
120
120
|
processor's available values. The processor must be defined in the target's configuration.
|
121
|
+
See the [Processor](/docs/configuration/processors) documentation for more information.
|
121
122
|
parameters:
|
122
123
|
- name: Processor Name
|
123
124
|
required: true
|
@@ -132,7 +133,7 @@ PROCESSOR_CONVERSION:
|
|
132
133
|
ITEM TEMP1HIGH 0 0 DERIVED "High-water mark for TEMP1"
|
133
134
|
READ_CONVERSION processor_conversion.rb TEMP1WATER HIGH_WATER
|
134
135
|
python_example: |
|
135
|
-
PROCESSOR TEMP1WATER watermark_processor.
|
136
|
+
PROCESSOR TEMP1WATER openc3/conversions/watermark_processor.py TEMP1
|
136
137
|
ITEM TEMP1HIGH 0 0 DERIVED "High-water mark for TEMP1"
|
137
138
|
READ_CONVERSION openc3/conversions/processor_conversion.py TEMP1WATER HIGH_WATER
|
138
139
|
RECEIVED_COUNT_CONVERSION:
|
@@ -162,6 +162,7 @@ LIMITS:
|
|
162
162
|
values: .+
|
163
163
|
LIMITS_RESPONSE:
|
164
164
|
summary: Defines a response class that is called when the limits state of the current item changes
|
165
|
+
description: See the [Limits Response](/docs/configuration/limits-response) documentation for more information.
|
165
166
|
ruby_example: LIMITS_RESPONSE example_limits_response.rb 10
|
166
167
|
python_example: LIMITS_RESPONSE example_limits_response.py 10
|
167
168
|
parameters:
|
data/data/config/plugins.yaml
CHANGED
@@ -88,4 +88,17 @@ WIDGET:
|
|
88
88
|
- name: Regex
|
89
89
|
required: false
|
90
90
|
description: Regex to match against filenames. If match, then no ERB processing
|
91
|
-
values: .+
|
91
|
+
values: .+
|
92
|
+
SCRIPT_ENGINE:
|
93
|
+
summary: Define a script engine to add language support to Script Runner
|
94
|
+
example: SCRIPT_ENGINE .print print_script_engine.py
|
95
|
+
description: Defines a script engine to add language support to Script Runner
|
96
|
+
parameters:
|
97
|
+
- name: Extension
|
98
|
+
description: Extension that will use this script engine
|
99
|
+
required: true
|
100
|
+
values: .+
|
101
|
+
- name: Script Engine Filename
|
102
|
+
description: Filename that implements the script engine. Should be in top level lib folder in plugin.
|
103
|
+
required: true
|
104
|
+
values: .+
|
@@ -0,0 +1,51 @@
|
|
1
|
+
---
|
2
|
+
WATERMARK_PROCESSOR:
|
3
|
+
summary: Calculates high and low values for a given item
|
4
|
+
description: |
|
5
|
+
Stores high and low values for a given item as HIGH_WATER and LOW_WATER.
|
6
|
+
Values are retrieved using a [ProcessorConversion](/docs/configuration/conversions#processor_conversion).
|
7
|
+
parameters:
|
8
|
+
- name: Item Name
|
9
|
+
description: The item name to calculate high and low values for
|
10
|
+
required: true
|
11
|
+
values: .+
|
12
|
+
- name: Value Type
|
13
|
+
required: false
|
14
|
+
description: The type of the value to display. Default is CONVERTED.
|
15
|
+
values: <%= %w(RAW CONVERTED) %>
|
16
|
+
ruby_example: |
|
17
|
+
PROCESSOR TEMP1WATER watermark_processor.rb TEMP1
|
18
|
+
ITEM TEMP1HIGH 0 0 DERIVED "High-water mark for TEMP1"
|
19
|
+
READ_CONVERSION processor_conversion.rb TEMP1WATER HIGH_WATER
|
20
|
+
python_example: |
|
21
|
+
PROCESSOR TEMP1WATER openc3/conversions/watermark_processor.py TEMP1
|
22
|
+
ITEM TEMP1HIGH 0 0 DERIVED "High-water mark for TEMP1"
|
23
|
+
READ_CONVERSION openc3/conversions/processor_conversion.py TEMP1WATER HIGH_WATER
|
24
|
+
STATISTICS_PROCESSOR:
|
25
|
+
summary: Calculates statistics for a given item
|
26
|
+
description: |
|
27
|
+
This processor calculates statistics for a given item as MIN, MAX, MEAN, and STDDEV
|
28
|
+
over a specified number of samples. Values are retrieved using a [ProcessorConversion](/docs/configuration/conversions#processor_conversion).
|
29
|
+
parameters:
|
30
|
+
- name: Item Name
|
31
|
+
description: The item name to calculate statistics for
|
32
|
+
required: true
|
33
|
+
values: .+
|
34
|
+
- name: Samples to Average
|
35
|
+
required: true
|
36
|
+
description: The number of samples to average for statistics
|
37
|
+
values: .*
|
38
|
+
- name: Value Type
|
39
|
+
required: false
|
40
|
+
description: The type of the value to display. Default is CONVERTED.
|
41
|
+
values: <%= %w(RAW CONVERTED) %>
|
42
|
+
ruby_example: PROCESSOR TEMP1STAT statistics_processor.rb TEMP1 100
|
43
|
+
python_example: PROCESSOR TEMP1STAT openc3/processors/statistics_processor.rb TEMP1 100
|
44
|
+
ruby_example: |
|
45
|
+
PROCESSOR TEMP1STAT statistics_processor.rb TEMP1 100
|
46
|
+
ITEM TEMP1STDDEV 0 0 DERIVED "Stddev of most recent 100 samples for TEMP1"
|
47
|
+
READ_CONVERSION processor_conversion.rb TEMP1STAT STDDEV FLOAT 64
|
48
|
+
python_example: |
|
49
|
+
PROCESSOR TEMP1STAT openc3/conversions/statistics_processor.py TEMP1 100
|
50
|
+
ITEM TEMP1STDDEV 0 0 DERIVED "Stddev of most recent 100 samples for TEMP1"
|
51
|
+
READ_CONVERSION openc3/conversions/processor_conversion.py TEMP1STAT STDDEV FLOAT 64
|
@@ -135,6 +135,7 @@ META:
|
|
135
135
|
values: .*
|
136
136
|
PROCESSOR:
|
137
137
|
summary: Defines a processor class that executes code every time a packet is received
|
138
|
+
description: See the [Processor](/docs/configuration/processors) documentation for more information.
|
138
139
|
ruby_example: PROCESSOR TEMP1HIGH watermark_processor.rb TEMP1
|
139
140
|
python_example: PROCESSOR TEMP1HIGH watermark_processor.py TEMP1
|
140
141
|
parameters:
|
data/lib/openc3/api/tlm_api.rb
CHANGED
@@ -114,8 +114,8 @@ module OpenC3
|
|
114
114
|
#
|
115
115
|
# @param args [String|Array<String>] See the description for calling style
|
116
116
|
# @param type [Symbol] Telemetry type, :RAW, :CONVERTED (default), :FORMATTED, or :WITH_UNITS
|
117
|
-
def set_tlm(*args, type: :CONVERTED, manual: false, scope: $openc3_scope, token: $openc3_token)
|
118
|
-
target_name, packet_name, item_name, value = _set_tlm_process_args(args, __method__, scope: scope)
|
117
|
+
def set_tlm(*args, type: :CONVERTED, manual: false, cache_timeout: nil, scope: $openc3_scope, token: $openc3_token)
|
118
|
+
target_name, packet_name, item_name, value = _set_tlm_process_args(args, __method__, cache_timeout: cache_timeout, scope: scope)
|
119
119
|
authorize(permission: 'tlm_set', target_name: target_name, packet_name: packet_name, manual: manual, scope: scope, token: token)
|
120
120
|
CvtModel.set_item(target_name, packet_name, item_name, value, type: type.intern, scope: scope)
|
121
121
|
end
|
@@ -528,7 +528,7 @@ module OpenC3
|
|
528
528
|
return [target_name, packet_name, item_name]
|
529
529
|
end
|
530
530
|
|
531
|
-
def _set_tlm_process_args(args, method_name, scope: $openc3_scope, token: $openc3_token)
|
531
|
+
def _set_tlm_process_args(args, method_name, cache_timeout: nil, scope: $openc3_scope, token: $openc3_token)
|
532
532
|
case args.length
|
533
533
|
when 1
|
534
534
|
target_name, packet_name, item_name, value = extract_fields_from_set_tlm_text(args[0])
|
@@ -544,8 +544,13 @@ module OpenC3
|
|
544
544
|
target_name = target_name.upcase
|
545
545
|
packet_name = packet_name.upcase
|
546
546
|
item_name = item_name.upcase
|
547
|
-
|
548
|
-
|
547
|
+
|
548
|
+
if packet_name == 'LATEST'
|
549
|
+
packet_name = CvtModel.determine_latest_packet_for_item(target_name, item_name, cache_timeout: cache_timeout, scope: scope)
|
550
|
+
else
|
551
|
+
# Determine if this item exists, it will raise appropriate errors if not
|
552
|
+
TargetModel.packet_item(target_name, packet_name, item_name, scope: scope)
|
553
|
+
end
|
549
554
|
|
550
555
|
return [target_name, packet_name, item_name, value]
|
551
556
|
end
|
@@ -128,15 +128,21 @@ module OpenC3
|
|
128
128
|
end
|
129
129
|
if msg_hash['raw']
|
130
130
|
if @interface.connected?
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
131
|
+
begin
|
132
|
+
@logger.info "#{@interface.name}: Write raw"
|
133
|
+
# A raw interface write results in an UNKNOWN packet
|
134
|
+
command = System.commands.packet('UNKNOWN', 'UNKNOWN')
|
135
|
+
command.received_count = TargetModel.increment_command_count('UNKNOWN', 'UNKNOWN', 1, scope: @scope)
|
136
|
+
command = command.clone
|
137
|
+
command.buffer = msg_hash['raw']
|
138
|
+
command.received_time = Time.now
|
139
|
+
CommandTopic.write_packet(command, scope: @scope)
|
140
|
+
@logger.info("write_raw sent #{msg_hash['raw'].length} bytes to #{@interface.name}", scope: @scope)
|
141
|
+
@interface.write_raw(msg_hash['raw'])
|
142
|
+
rescue => e
|
143
|
+
@logger.error "#{@interface.name}: write_raw: #{e.formatted}"
|
144
|
+
next e.message
|
145
|
+
end
|
140
146
|
next 'SUCCESS'
|
141
147
|
else
|
142
148
|
next "Interface not connected: #{@interface.name}"
|
@@ -31,6 +31,7 @@ require 'openc3/models/gem_model'
|
|
31
31
|
require 'openc3/models/target_model'
|
32
32
|
require 'openc3/models/interface_model'
|
33
33
|
require 'openc3/models/router_model'
|
34
|
+
require 'openc3/models/script_engine_model'
|
34
35
|
require 'openc3/models/tool_model'
|
35
36
|
require 'openc3/models/widget_model'
|
36
37
|
require 'openc3/models/microservice_model'
|
@@ -249,7 +250,7 @@ module OpenC3
|
|
249
250
|
case keyword
|
250
251
|
when 'VARIABLE', 'NEEDS_DEPENDENCIES'
|
251
252
|
# Ignore during phase 2
|
252
|
-
when 'TARGET', 'INTERFACE', 'ROUTER', 'MICROSERVICE', 'TOOL', 'WIDGET'
|
253
|
+
when 'TARGET', 'INTERFACE', 'ROUTER', 'MICROSERVICE', 'TOOL', 'WIDGET', 'SCRIPT_ENGINE'
|
253
254
|
begin
|
254
255
|
if current_model
|
255
256
|
current_model.create unless validate_only
|
@@ -260,7 +261,7 @@ module OpenC3
|
|
260
261
|
# Otherwise we're stuck constantly iterating on the last model
|
261
262
|
ensure
|
262
263
|
current_model = nil
|
263
|
-
current_model = OpenC3.const_get((keyword.capitalize + 'Model').intern).handle_config(parser,
|
264
|
+
current_model = OpenC3.const_get((keyword.split('_').collect(&:capitalize).join + 'Model').intern).handle_config(parser,
|
264
265
|
keyword, params, plugin: plugin_model.name, needs_dependencies: needs_dependencies, scope: scope)
|
265
266
|
end
|
266
267
|
else
|
@@ -339,7 +340,7 @@ module OpenC3
|
|
339
340
|
sleep 15 if microservice_count > 0 # Cycle time 5s times 2 plus 5s wait for soft stop and then hard stop
|
340
341
|
# Remove all the other models now that the processes have stopped
|
341
342
|
# Save TargetModel for last as it has the most to cleanup
|
342
|
-
[InterfaceModel, RouterModel, ToolModel, WidgetModel, TargetModel].each do |model|
|
343
|
+
[InterfaceModel, RouterModel, ToolModel, WidgetModel, TargetModel, ScriptEngineModel].each do |model|
|
343
344
|
model.find_all_by_plugin(plugin: @name, scope: @scope).each do |_name, model_instance|
|
344
345
|
begin
|
345
346
|
model_instance.destroy
|
@@ -369,7 +370,7 @@ module OpenC3
|
|
369
370
|
ensure
|
370
371
|
# Double check everything is gone
|
371
372
|
found = []
|
372
|
-
[MicroserviceModel, InterfaceModel, RouterModel, ToolModel, WidgetModel, TargetModel].each do |model|
|
373
|
+
[MicroserviceModel, InterfaceModel, RouterModel, ToolModel, WidgetModel, TargetModel, ScriptEngineModel].each do |model|
|
373
374
|
model.find_all_by_plugin(plugin: @name, scope: @scope).each do |_name, model_instance|
|
374
375
|
found << model_instance
|
375
376
|
end
|