Skip to content

Commit e76ed53

Browse files
authored
Merge pull request #2229 from OpenC3/playback
TlmViewer Playback
2 parents e013baf + b787d43 commit e76ed53

File tree

47 files changed

+2418
-205
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

47 files changed

+2418
-205
lines changed

.env

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ OPENC3_ENTERPRISE_REGISTRY=ghcr.io
1212
OPENC3_ENTERPRISE_NAMESPACE=openc3
1313
OPENC3_UBI_REGISTRY=registry1.dso.mil
1414
OPENC3_UBI_IMAGE=ironbank/redhat/ubi/ubi9-minimal
15-
OPENC3_UBI_TAG=9.5
15+
OPENC3_UBI_TAG=9.6
1616
# Defined here as blank to avoid warnings. Used in the compose.yaml to pass '-ubi'.
1717
OPENC3_IMAGE_SUFFIX=
1818
# Bucket & Volume configuration
@@ -35,6 +35,12 @@ OPENC3_REDIS_HOSTNAME=openc3-redis
3535
OPENC3_REDIS_PORT=6379
3636
OPENC3_REDIS_EPHEMERAL_HOSTNAME=openc3-redis-ephemeral
3737
OPENC3_REDIS_EPHEMERAL_PORT=6380
38+
# Database configuration
39+
# OPENC3_TSDB_HOSTNAME=openc3-tsdb
40+
# OPENC3_TSDB_QUERY_PORT=8812
41+
# OPENC3_TSDB_INGEST_PORT=9000
42+
# OPENC3_TSDB_USERNAME=openc3quest
43+
# OPENC3_TSDB_PASSWORD=openc3questpassword
3844
# Usernames and passwords
3945
# These lines can be removed from this file if available in the host computer environment variables
4046
OPENC3_REDIS_USERNAME=openc3

compose-build.yaml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,14 @@ services:
6666
OPENC3_DEPENDENCY_REGISTRY: ${OPENC3_DEPENDENCY_REGISTRY}
6767
image: "${OPENC3_REGISTRY}/${OPENC3_NAMESPACE}/openc3-minio:${OPENC3_TAG}"
6868

69+
openc3-tsdb:
70+
build:
71+
context: "openc3-tsdb"
72+
network: host
73+
args:
74+
OPENC3_DEPENDENCY_REGISTRY: ${OPENC3_DEPENDENCY_REGISTRY}
75+
image: "${OPENC3_REGISTRY}/${OPENC3_NAMESPACE}/openc3-tsdb:${OPENC3_TAG}"
76+
6977
openc3-redis:
7078
build:
7179
context: "openc3-redis"

compose.yaml

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,32 @@ services:
4949
REQUESTS_CA_BUNDLE: "/devel/cacert.pem"
5050
NODE_EXTRA_CA_CERTS: "/devel/cacert.pem"
5151

52+
# Uncomment to use QuestDB as the time series database
53+
# Also uncomment the openc3-tsdb-v volume in the volumes section
54+
# openc3-tsdb:
55+
# image: "${OPENC3_REGISTRY}/${OPENC3_NAMESPACE}/openc3-tsdb${OPENC3_IMAGE_SUFFIX}:${OPENC3_TAG}"
56+
# ports:
57+
# # You should disable the QuestDB Console in production
58+
# # as it gives unlimited access to the database
59+
# - "127.0.0.1:9000:9000" # OPENC3_TSDB_INGEST_PORT & QuestDB Console
60+
# # The Postgresql port doesn't typically need to be exposed to the host
61+
# # but if you have external software that needs to connect to QuestDB
62+
# # you can uncomment the following line to expose it.
63+
# # - "127.0.0.1:8812:8812" # OPENC3_TSDB_QUERY_PORT
64+
# volumes:
65+
# - "openc3-tsdb-v:/var/lib/questdb"
66+
# restart: "unless-stopped"
67+
# logging:
68+
# driver: "json-file"
69+
# options:
70+
# max-size: "10m"
71+
# max-file: "3"
72+
# environment:
73+
# QDB_PG_USER: "${OPENC3_TSDB_USERNAME}"
74+
# QDB_PG_PASSWORD: "${OPENC3_TSDB_PASSWORD}"
75+
# QDB_HTTP_USER: "${OPENC3_TSDB_USERNAME}"
76+
# QDB_HTTP_PASSWORD: "${OPENC3_TSDB_PASSWORD}"
77+
5278
openc3-redis:
5379
user: "${OPENC3_USER_ID:-1001}:${OPENC3_GROUP_ID:-1001}"
5480
image: "${OPENC3_REGISTRY}/${OPENC3_NAMESPACE}/openc3-redis${OPENC3_IMAGE_SUFFIX}:${OPENC3_TAG}"
@@ -263,6 +289,7 @@ services:
263289
- .env
264290

265291
volumes:
292+
# openc3-tsdb-v: {}
266293
openc3-redis-v: {}
267294
openc3-redis-ephemeral-v: {}
268295
openc3-bucket-v: {}

docs.openc3.com/docs/guides/scripting-api.md

Lines changed: 63 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ The following API methods are either deprecated (will not be ported to COSMOS 5)
131131
| stop_tlm_log | Command and Telemetry Server | Deprecated |
132132
| subscribe_limits_events | Command and Telemetry Server | Deprecated |
133133
| subscribe_packet_data | Command and Telemetry Server | Deprecated, use subscribe_packets |
134-
| subscribe_server_messages | Command and Telemetry Server | Unimplemented |
134+
| subscribe_server_messages | Command and Telemetry Server | Deprecated |
135135
| tlm_variable | Script Runner | Deprecated, use tlm() and pass type |
136136
| unsubscribe_limits_events | Command and Telemetry Server | Deprecated |
137137
| unsubscribe_packet_data | Command and Telemetry Server | Deprecated |
@@ -1928,7 +1928,7 @@ status = critical_cmd_can_approve("2fa14183-3148-4399-9a74-a130257118f9") #=> tr
19281928
<TabItem value="python" label="Python Example">
19291929

19301930
```python
1931-
status = critical_cmd_can_approve("2fa14183-3148-4399-9a74-a130257118f9") #=> true / false
1931+
status = critical_cmd_can_approve("2fa14183-3148-4399-9a74-a130257118f9") #=> True / False
19321932
```
19331933

19341934
</TabItem>
@@ -2309,6 +2309,52 @@ names_values_and_limits_states = get_tlm_packet("INST HEALTH_STATUS", type='FORM
23092309
</TabItem>
23102310
</Tabs>
23112311

2312+
### get_tlm_available
2313+
2314+
Returns the _actual_ items available based on the specified set of telemetry items. For example, if you request `INST__HEALTH_STATUS__CCSDSVER__WITH_UNITS` the method will return `INST__HEALTH_STATUS__CCSDSVER__RAW` for that item because it does not have formatting or conversions so only the RAW value is available. This _must_ be called before calling `get_tlm_values` when passing a `start_time` / `end_time` as it ensures a correct request of historical data.
2315+
2316+
<Tabs groupId="script-language">
2317+
<TabItem value="ruby" label="Ruby Syntax">
2318+
2319+
```ruby
2320+
actual = get_tlm_available(<Items>)
2321+
```
2322+
2323+
</TabItem>
2324+
2325+
<TabItem value="python" label="Python Syntax">
2326+
2327+
```python
2328+
actual = get_tlm_available(<Items>)
2329+
```
2330+
2331+
</TabItem>
2332+
</Tabs>
2333+
2334+
| Parameter | Description |
2335+
| --------- | ----------------------------------------------------------- |
2336+
| Items | Array of strings of the form ['TGT__PKT__ITEM__TYPE', ... ] |
2337+
2338+
<Tabs groupId="script-language">
2339+
<TabItem value="ruby" label="Ruby Example">
2340+
2341+
```ruby
2342+
actual = get_tlm_available(["INST__HEALTH_STATUS__CCSDSVER__WITH_UNITS", "INST__HEALTH_STATUS__TEMP1__WITH_UNITS"])
2343+
puts values # ["INST__HEALTH_STATUS__CCSDSVER__RAW", "INST__HEALTH_STATUS__TEMP1__WITH_UNITS"]
2344+
```
2345+
2346+
</TabItem>
2347+
2348+
<TabItem value="python" label="Python Example">
2349+
2350+
```python
2351+
values = get_tlm_available(["INST__HEALTH_STATUS__CCSDSVER__WITH_UNITS", "INST__HEALTH_STATUS__TEMP1__WITH_UNITS"])
2352+
print(values) # ["INST__HEALTH_STATUS__CCSDSVER__RAW", "INST__HEALTH_STATUS__TEMP1__WITH_UNITS"]
2353+
```
2354+
2355+
</TabItem>
2356+
</Tabs>
2357+
23122358
### get_tlm_values
23132359

23142360
Returns the values and current limits state for a specified set of telemetry items. Items can be in any telemetry packet in the system. They can all be retrieved using the same value type or a specific value type can be specified for each item.
@@ -2340,7 +2386,7 @@ values, limits_states, limits_settings, limits_set = get_tlm_values(<Items>)
23402386

23412387
```ruby
23422388
values = get_tlm_values(["INST__HEALTH_STATUS__TEMP1__CONVERTED", "INST__HEALTH_STATUS__TEMP2__RAW"])
2343-
print(values) # [[-100.0, :RED_LOW], [0, :RED_LOW]]
2389+
puts values # [[-100.0, :RED_LOW], [0, :RED_LOW]]
23442390
```
23452391

23462392
</TabItem>
@@ -2388,7 +2434,7 @@ get_all_tlm("<Target Name>")
23882434

23892435
```ruby
23902436
packets = get_all_tlm("INST")
2391-
print(packets)
2437+
puts packets
23922438
#[{"target_name"=>"INST",
23932439
# "packet_name"=>"ADCS",
23942440
# "endianness"=>"BIG_ENDIAN",
@@ -2549,7 +2595,7 @@ get_tlm("<Target Name>", "<Packet Name>")
25492595

25502596
```ruby
25512597
packet = get_tlm("INST HEALTH_STATUS")
2552-
print(packet)
2598+
puts packet
25532599
#{"target_name"=>"INST",
25542600
# "packet_name"=>"HEALTH_STATUS",
25552601
# "endianness"=>"BIG_ENDIAN",
@@ -2633,7 +2679,7 @@ get_item("<Target Name>", "<Packet Name>", "<Item Name>")
26332679

26342680
```ruby
26352681
item = get_item("INST HEALTH_STATUS CCSDSVER")
2636-
print(item)
2682+
puts item
26372683
#{"name"=>"CCSDSVER",
26382684
# "bit_offset"=>0,
26392685
# "bit_size"=>3,
@@ -3258,7 +3304,7 @@ success = wait("<Target Name> <Packet Name> <Item Name> <Comparison>", <Timeout>
32583304
<TabItem value="python" label="Python Syntax">
32593305

32603306
```python
3261-
# Returns true or false based on the whether the expression is true or false
3307+
# Returns True or False based on the whether the expression is True or False
32623308
success = wait("<Target Name> <Packet Name> <Item Name> <Comparison>", <Timeout>, <Polling Rate (optional)>, type, quiet)
32633309
```
32643310

@@ -3435,7 +3481,7 @@ success = wait_packet("<Target>", "<Packet>", <Num Packets>, <Timeout>, <Polling
34353481
<TabItem value="python" label="Python Syntax">
34363482

34373483
```python
3438-
# Returns true or false based on the whether the packet was received
3484+
# Returns True or False based on the whether the packet was received
34393485
success = wait_packet("<Target>", "<Packet>", <Num Packets>, <Timeout>, <Polling Rate (optional)>, quiet)
34403486
```
34413487

@@ -4133,7 +4179,7 @@ set_limits('INST', 'HEALTH_STATUS', 'TEMP1', -10.0, 0.0, 50.0, 60.0, 30.0, 40.0,
41334179
<TabItem value="python" label="Python Example">
41344180

41354181
```python
4136-
set_limits('INST', 'HEALTH_STATUS', 'TEMP1', -10.0, 0.0, 50.0, 60.0, 30.0, 40.0, 'TVAC', 1, true)
4182+
set_limits('INST', 'HEALTH_STATUS', 'TEMP1', -10.0, 0.0, 50.0, 60.0, 30.0, 40.0, 'TVAC', 1, True)
41374183
```
41384184

41394185
</TabItem>
@@ -4239,7 +4285,7 @@ get_limits_event(<Offset>, count)
42394285

42404286
```ruby
42414287
events = get_limits_event()
4242-
print(events)
4288+
puts events
42434289
#[["1613077715557-0",
42444290
# {"type"=>"LIMITS_CHANGE",
42454291
# "target_name"=>"TGT",
@@ -4260,7 +4306,7 @@ print(events)
42604306
# "message"=>"message"}]]
42614307
# The last offset is the first item ([0]) in the last event ([-1])
42624308
events = get_limits_event(events[-1][0])
4263-
print(events)
4309+
puts events
42644310
#[["1613077715657-0",
42654311
# {"type"=>"LIMITS_CHANGE",
42664312
# ...
@@ -4363,7 +4409,7 @@ plugins = plugin_list(default: true) #=>
43634409

43644410
```python
43654411
plugins = plugin_list() #=> ['openc3-cosmos-demo-6.0.3.pre.beta0.20250116214358.gem__20250116214539']
4366-
plugins = plugin_list(default: true) #=>
4412+
plugins = plugin_list(default=True) #=>
43674413
# ['openc3-cosmos-demo-6.0.3.pre.beta0.20250116214358.gem__20250116214539',
43684414
# 'openc3-cosmos-tool-admin-6.0.3.pre.beta0.20250115200004.gem__20250116211504',
43694415
# 'openc3-cosmos-tool-bucketexplorer-6.0.3.pre.beta0.20250115200008.gem__20250116211525',
@@ -4521,7 +4567,7 @@ get_target("<Target Name>")
45214567

45224568
```ruby
45234569
target = get_target("INST")
4524-
print(target)
4570+
puts target
45254571
# {"name"=>"INST",
45264572
# "folder_name"=>"INST",
45274573
# "requires"=>[],
@@ -4663,7 +4709,7 @@ get_interface("<Interface Name>")
46634709

46644710
```ruby
46654711
interface = get_interface("INST_INT")
4666-
print(interface)
4712+
puts interface
46674713
# {"name"=>"INST_INT",
46684714
# "config_params"=>["interface.rb"],
46694715
# "target_names"=>["INST"],
@@ -5243,7 +5289,7 @@ get_router("<Router Name>")
52435289

52445290
```ruby
52455291
router = get_router("ROUTER_INT")
5246-
print(router)
5292+
puts router
52475293
#{"name"=>"ROUTER_INT",
52485294
# "config_params"=>["router.rb"],
52495295
# "target_names"=>["INST"],
@@ -7429,7 +7475,7 @@ The method gets the maximum number of characters to display in Script Runner out
74297475
<TabItem value="ruby" label="Ruby Example">
74307476

74317477
```ruby
7432-
print(get_max_output()) #=> 50000
7478+
puts get_max_output() #=> 50000
74337479
```
74347480

74357481
</TabItem>
@@ -9660,3 +9706,4 @@ autonomic_reaction_destroy("REACT1")
96609706

96619707
</TabItem>
96629708
</Tabs>
9709+
````

docs.openc3.com/docs/guides/troubleshooting.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,4 +67,13 @@ We've seen a number of issues deploying COSMOS via Docker in various types of in
6767

6868
We've seen this on old versions of Docker Desktop when using bind mounts instead of named volumes. Our docker compose files use named volumes by default so be careful with bind mounts. We also recommend upgrading Docker Desktop and WLS2 if possible as this maybe OBE in newer versions of Docker Desktop / WSL2.
6969

70+
1. When exposing COSMOS to the network through http, Chrome [DevTools](https://developer.chrome.com/docs/devtools/open) shows "Web crypto API is not available".
71+
72+
Make sure to follow all the instructions in the [COSMOS Enterprise Project README](https://github.com/OpenC3/cosmos-enterprise-project/blob/main/README.md). In this case you need to do the following:
73+
74+
- In Chrome go to: chrome://flags/#unsafely-treat-insecure-origin-as-secure
75+
- Add your http://&lt;Your IP Address&gt;:2900
76+
- Enable the Setting
77+
- Completely restart Chrome. On MacOS make sure the dot below the icon in chrome is gone by long pressing the icon and choosing Quit.
78+
7079
Encountering an issue not on this list? If you're a customer, please get in touch at [[email protected]](mailto:[email protected]).

mise.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
[tools]
22
node = "22.11"
33
python = "3.12"
4-
ruby = "3.3"
4+
ruby = "3.4"

openc3-cosmos-cmd-tlm-api/app/controllers/api_controller.rb

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,19 +14,41 @@
1414
# GNU Affero General Public License for more details.
1515

1616
# Modified by OpenC3, Inc.
17-
# All changes Copyright 2023, OpenC3, Inc.
17+
# All changes Copyright 2025, OpenC3, Inc.
1818
# All Rights Reserved
1919
#
2020
# This file may also be used under the terms of a commercial license
2121
# if purchased from OpenC3, Inc.
2222

2323
require 'openc3/utilities/open_telemetry'
24+
require 'pg'
25+
26+
$tsdb_connection = nil
2427

2528
class ApiController < ApplicationController
2629
def ping
2730
render plain: 'OK'
2831
end
2932

33+
# Time Seriese Database (TSDB) presence check
34+
def tsdb
35+
if $tsdb_connection
36+
render plain: 'OK', status: 200
37+
return
38+
end
39+
begin
40+
PG::Connection.new(host: ENV['OPENC3_TSDB_HOSTNAME'],
41+
port: ENV['OPENC3_TSDB_QUERY_PORT'],
42+
user: ENV['OPENC3_TSDB_USERNAME'],
43+
password: ENV['OPENC3_TSDB_PASSWORD'],
44+
dbname: 'qdb').close() # Default dbname
45+
$tsdb_connection = 'OK'
46+
render plain: 'OK', status: 200
47+
rescue => e
48+
render plain: e.message, status: 404
49+
end
50+
end
51+
3052
def api
3153
OpenC3.in_span('jsonrpc_api') do |span|
3254
req = Rack::Request.new(request.env)

openc3-cosmos-cmd-tlm-api/config/routes.rb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
# GNU Affero General Public License for more details.
1515

1616
# Modified by OpenC3, Inc.
17-
# All changes Copyright 2024, OpenC3, Inc.
17+
# All changes Copyright 2025, OpenC3, Inc.
1818
# All Rights Reserved
1919
#
2020
# This file may also be used under the terms of a commercial license
@@ -193,6 +193,7 @@
193193
# to do the remote procedure call
194194
post "/api" => "api#api"
195195
get "/ping" => "api#ping"
196+
get "/tsdb" => "api#tsdb"
196197

197198
get "/auth/token-exists" => "auth#token_exists"
198199
post "/auth/verify" => "auth#verify"

0 commit comments

Comments
 (0)