├── .flake8 ├── .github └── workflows │ └── ci.yml ├── .gitignore ├── LICENSE ├── README.md ├── docs ├── .gitignore ├── Makefile ├── _static │ └── css-overrides.css ├── archive │ ├── client.rst │ ├── index.rst │ └── model.rst ├── conf.py ├── examples │ ├── alarms.rst │ ├── archive_breakdown.rst │ ├── archive_retrieval.rst │ ├── authenticate.rst │ ├── ccsds_completeness.rst │ ├── commanding.rst │ ├── cop1.rst │ ├── events.rst │ ├── file_transfer.rst │ ├── index.rst │ ├── links.rst │ ├── mission_time.rst │ ├── packet_subscription.rst │ ├── parameter_subscription.rst │ ├── plot_with_matplotlib.rst │ ├── query_mdb.rst │ ├── read_write_parameters.rst │ ├── reconnection.rst │ ├── timeline.rst │ └── write_mdb.rst ├── filetransfer │ ├── client.rst │ ├── index.rst │ └── model.rst ├── general │ ├── authentication.rst │ ├── client.rst │ ├── exceptions.rst │ ├── futures.rst │ ├── index.rst │ └── model.rst ├── index.rst ├── link │ ├── client.rst │ ├── index.rst │ └── model.rst ├── mdb │ ├── client.rst │ ├── index.rst │ └── model.rst ├── requirements.txt ├── storage │ ├── client.rst │ ├── index.rst │ └── model.rst ├── tco │ ├── client.rst │ ├── index.rst │ └── model.rst ├── timeline │ ├── client.rst │ ├── index.rst │ └── model.rst └── tmtc │ ├── client.rst │ ├── index.rst │ └── model.rst ├── pyrightconfig.json ├── yamcs-client-kerberos ├── .flake8 ├── Makefile ├── README.md ├── examples │ └── authenticate.py ├── requirements.txt ├── setup.py └── src │ └── yamcs │ └── kerberos.py └── yamcs-client ├── .flake8 ├── CONTRIBUTING.md ├── LICENSE ├── MANIFEST.in ├── Makefile ├── README.md ├── examples ├── alarms.py ├── archive_breakdown.py ├── archive_retrieval.py ├── authenticate.py ├── ccsds_completeness.py ├── change_alarms.py ├── change_algorithm.py ├── change_calibration.py ├── command_bench.py ├── command_history.py ├── commanding.py ├── cop1.py ├── create_instance.py ├── events.py ├── file_transfer.py ├── links.py ├── mission_time.py ├── modify_dump.py ├── multiple_commands.py ├── object_storage.py ├── packet_subscription.py ├── parameter_subscription.py ├── plot_with_matplotlib.py ├── query_mdb.py ├── read_write_parameters.py ├── reconnection.py ├── run-all.sh ├── scripting.py ├── sql.py ├── timeline.py └── write_mdb.py ├── requirements.txt ├── setup.py ├── src └── yamcs │ ├── api │ ├── annotations_pb2.py │ ├── exception_pb2.py │ ├── httpbody_pb2.py │ └── websocket_pb2.py │ ├── archive │ ├── __init__.py │ ├── client.py │ └── model.py │ ├── client │ ├── __init__.py │ ├── activities.py │ ├── archive │ │ ├── __init__.py │ │ ├── client.py │ │ └── model.py │ ├── clientversion.py │ ├── core │ │ ├── __init__.py │ │ ├── auth.py │ │ ├── context.py │ │ ├── exceptions.py │ │ ├── futures.py │ │ ├── helpers.py │ │ ├── pagination.py │ │ └── subscriptions.py │ ├── filetransfer │ │ ├── __init__.py │ │ ├── client.py │ │ └── model.py │ ├── links │ │ ├── __init__.py │ │ ├── client.py │ │ └── model.py │ ├── mdb │ │ ├── __init__.py │ │ ├── client.py │ │ └── model.py │ ├── model.py │ ├── storage │ │ ├── __init__.py │ │ ├── client.py │ │ └── model.py │ ├── tco │ │ ├── __init__.py │ │ ├── client.py │ │ └── model.py │ ├── timeline │ │ ├── __init__.py │ │ ├── client.py │ │ └── model.py │ └── tmtc │ │ ├── __init__.py │ │ ├── client.py │ │ └── model.py │ ├── clientversion.py │ ├── core │ ├── __init__.py │ ├── auth.py │ ├── context.py │ ├── exceptions.py │ ├── futures.py │ ├── helpers.py │ ├── pagination.py │ └── subscriptions.py │ ├── filetransfer │ ├── __init__.py │ ├── client.py │ └── model.py │ ├── link │ ├── __init__.py │ ├── client.py │ └── model.py │ ├── mdb │ ├── __init__.py │ ├── client.py │ └── model.py │ ├── model.py │ ├── protobuf │ ├── actions │ │ └── actions_pb2.py │ ├── activities │ │ ├── activities_pb2.py │ │ └── activities_service_pb2.py │ ├── alarms │ │ ├── alarms_pb2.py │ │ └── alarms_service_pb2.py │ ├── archive │ │ ├── archive_pb2.py │ │ ├── index_service_pb2.py │ │ ├── parameter_archive_service_pb2.py │ │ └── rocksdb_service_pb2.py │ ├── audit │ │ └── audit_pb2.py │ ├── auth │ │ └── auth_pb2.py │ ├── buckets │ │ └── buckets_pb2.py │ ├── commanding │ │ ├── clearance_service_pb2.py │ │ ├── commanding_pb2.py │ │ ├── commands_service_pb2.py │ │ └── queues_service_pb2.py │ ├── config │ │ └── config_pb2.py │ ├── cop1 │ │ └── cop1_pb2.py │ ├── database │ │ └── database_service_pb2.py │ ├── events │ │ ├── events_pb2.py │ │ └── events_service_pb2.py │ ├── filetransfer │ │ └── filetransfer_pb2.py │ ├── iam │ │ ├── iam_pb2.py │ │ └── sessions_service_pb2.py │ ├── instances │ │ ├── instances_pb2.py │ │ └── instances_service_pb2.py │ ├── links │ │ └── links_pb2.py │ ├── mdb │ │ └── mdb_pb2.py │ ├── packets │ │ ├── packets_pb2.py │ │ └── packets_service_pb2.py │ ├── plists │ │ ├── plists_pb2.py │ │ └── plists_service_pb2.py │ ├── processing │ │ ├── mdb_override_service_pb2.py │ │ └── processing_pb2.py │ ├── pvalue │ │ ├── pvalue_pb2.py │ │ └── pvalue_service_pb2.py │ ├── replication │ │ └── replication_pb2.py │ ├── server │ │ └── server_service_pb2.py │ ├── services │ │ ├── services_pb2.py │ │ └── services_service_pb2.py │ ├── table │ │ └── table_pb2.py │ ├── tco │ │ └── tco_pb2.py │ ├── time │ │ └── time_service_pb2.py │ ├── timeline │ │ └── timeline_pb2.py │ ├── yamcsManagement │ │ └── yamcsManagement_pb2.py │ └── yamcs_pb2.py │ ├── storage │ ├── __init__.py │ ├── client.py │ └── model.py │ ├── tco │ ├── __init__.py │ ├── client.py │ └── model.py │ ├── timeline │ ├── __init__.py │ ├── client.py │ └── model.py │ └── tmtc │ ├── __init__.py │ ├── client.py │ └── model.py └── update-proto.sh /.flake8: -------------------------------------------------------------------------------- 1 | [flake8] 2 | max-line-length = 88 3 | extend-ignore = E203 4 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | examples: 7 | name: Examples 8 | runs-on: ubuntu-latest 9 | strategy: 10 | matrix: 11 | python: ["3.8", "3.9", "3.10", "3.11", "3.12", "3.13"] 12 | services: 13 | yamcs: 14 | image: yamcs/example-simulation 15 | ports: 16 | - 8090:8090 17 | steps: 18 | - uses: actions/checkout@v4 19 | - uses: actions/setup-python@v5 20 | with: 21 | python-version: ${{ matrix.python }} 22 | - name: Set up yamcs-client 23 | run: | 24 | python -m pip install --upgrade pip 25 | cd yamcs-client 26 | python -m pip install -e . 27 | - name: Run examples 28 | run: | 29 | cd yamcs-client/examples 30 | ./run-all.sh 31 | 32 | lint: 33 | name: Lint 34 | runs-on: ubuntu-latest 35 | steps: 36 | - uses: actions/checkout@v4 37 | - uses: actions/setup-python@v5 38 | with: 39 | python-version: 3.8 40 | - name: Install dependencies 41 | run: | 42 | pip install --upgrade pip 43 | pip install flake8 44 | - name: Lint with flake8 45 | run: flake8 . --exclude '*pb2.py' --count --show-source --statistics 46 | 47 | docs: 48 | name: Documentation 49 | runs-on: ubuntu-latest 50 | steps: 51 | - uses: actions/checkout@v4 52 | - uses: actions/setup-python@v5 53 | with: 54 | python-version: 3.8 55 | - name: Set up sphinx 56 | run: | 57 | python -m pip install --upgrade pip 58 | pip install -r yamcs-client/requirements.txt 59 | pip install -r docs/requirements.txt 60 | - name: Generate documentation 61 | run: | 62 | cd yamcs-client 63 | python -m pip install -e . 64 | cd ../docs 65 | make html 66 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.egg-info/ 2 | .eggs/ 3 | build/ 4 | dist/ 5 | 6 | .idea/ 7 | .vscode/ 8 | 9 | .python-version 10 | *.pyc 11 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Yamcs Client for Python 2 | 3 | | Module | Description || 4 | | --------------------------------------------------- | --------------------------------- | ----- | 5 | | [yamcs-client](yamcs-client) | Core client libraries | [![PyPI](https://img.shields.io/pypi/v/yamcs-client.svg)](https://pypi.python.org/pypi/yamcs-client) | 6 | | [yamcs-client-kerberos](yamcs-client-kerberos) | Negotiate/SPNEGO authentication | [![PyPI](https://img.shields.io/pypi/v/yamcs-client-kerberos.svg)](https://pypi.python.org/pypi/yamcs-client-kerberos) | 7 | 8 | 9 | ## License 10 | 11 | LGPL-3.0. See [LICENSE](https://github.com/yamcs/python-yamcs-client/blob/master/LICENSE) 12 | -------------------------------------------------------------------------------- /docs/.gitignore: -------------------------------------------------------------------------------- 1 | /_build/ -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Minimal makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line. 5 | SPHINXOPTS = 6 | SPHINXBUILD = sphinx-build 7 | SPHINXPROJ = YamcsPythonClient 8 | SOURCEDIR = . 9 | BUILDDIR = _build 10 | 11 | # Put it first so that "make" without argument is like "make help". 12 | help: 13 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 14 | 15 | .PHONY: help Makefile 16 | 17 | # Catch-all target: route all unknown targets to Sphinx using the new 18 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 19 | %: Makefile 20 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) -------------------------------------------------------------------------------- /docs/_static/css-overrides.css: -------------------------------------------------------------------------------- 1 | pre, tt, code { 2 | font-size: 13px; 3 | } 4 | 5 | pre { 6 | background: #fafafb; 7 | border: 1px solid #cacaca; 8 | padding: 8px 12px; 9 | } 10 | 11 | div.body { 12 | max-width: none !important; 13 | } 14 | 15 | dl.class, dl.exception { 16 | border: 1px solid #eee; 17 | margin-bottom: 1em; 18 | } 19 | 20 | .class > dt, .exception > dt { 21 | background-color: #eee; 22 | min-height: 48px; 23 | line-height: 48px; 24 | box-shadow: 0 .125rem .3125rem rgba(0,0,0,.26); 25 | padding-left: 10px; 26 | } 27 | 28 | dl.class > dd, dl.exception > dd { 29 | margin-left: 0; 30 | } 31 | 32 | dl.class > dd > p, dl.exception > dd > p { 33 | padding-left: 15px; 34 | } 35 | 36 | dl.method > dt, dl.attribute > dt { 37 | border-top: 1px solid #eee; 38 | border-bottom: 1px solid #eee; 39 | padding-left: 15px; 40 | background-color: #f7f7f7; 41 | } 42 | 43 | tt.descname, tt.descclassname, code.descname, code.descclassname { 44 | font-size: normal !important; 45 | } 46 | 47 | /*.attribute code.descname, .method code.descname { 48 | background-color: #ffe4b5; 49 | }*/ 50 | 51 | a.reference .pre { 52 | font-weight: normal; 53 | border-bottom: 1px dotted#004B6B; 54 | color: #004B6B; 55 | } 56 | 57 | a.reference { 58 | color: #1756a9; 59 | text-decoration: none; 60 | border-bottom: none; 61 | } 62 | 63 | a.reference:visited { 64 | color: #1756a9; 65 | } 66 | 67 | a.reference:hover { 68 | color: #222; 69 | text-decoration: underline; 70 | border-bottom: none; 71 | } 72 | 73 | th.field-name { 74 | white-space: nowrap; 75 | } 76 | 77 | dt:target, span.highlighted { 78 | background-color: #fbe54e !important; 79 | } 80 | 81 | div#searchbox { 82 | margin-top: 2em; 83 | } 84 | 85 | /* Hide 'Navigation' header */ 86 | .sphinxsidebarwrapper > h3 { 87 | display: none; 88 | } 89 | 90 | #searchbox > h3 { 91 | text-transform: capitalize; 92 | } 93 | 94 | .sphinxsidebarwrapper { 95 | padding-right: 0 !important; 96 | } 97 | 98 | .searchformwrapper { 99 | padding-right: 15px; 100 | } 101 | 102 | .blurb { 103 | margin-bottom: 2em !important; 104 | } 105 | 106 | div.footer { 107 | /* Hide, instead of display:none, so it still print some whitespace in the footer */ 108 | visibility: hidden; 109 | } 110 | 111 | .sphinxsidebar { 112 | border-right: 1px solid #e8e8e8; 113 | } 114 | 115 | .sphinxsidebar ul ul { 116 | list-style: none !important; 117 | border-left: 1px solid #e8e8e8; 118 | margin-left: 15px !important; 119 | margin-bottom: 15px !important; 120 | } 121 | 122 | .sphinxsidebar ul a { 123 | text-decoration: none !important; 124 | font-weight: 300 !important; 125 | border-bottom: none !important; 126 | display: block; 127 | padding-left: 1em !important; 128 | padding-top: 0.3em; 129 | padding-bottom: 0.3em; 130 | font-size: 100% !important; 131 | color: black !important; 132 | } 133 | 134 | .sphinxsidebar ul li.current > a, .sphinxsidebar ul li.current > a:hover { 135 | background-color: #1756a9; 136 | color: white !important; 137 | } 138 | 139 | .sphinxsidebar ul li.current li.current > a, .sphinxsidebar ul li.current li.current > a:hover { 140 | background-color: #e8e8e8; 141 | color: black !important; 142 | } 143 | 144 | .sphinxsidebar ul a:hover { 145 | background-color: #efefef; 146 | } 147 | 148 | div.body h1, div.body h2, div.body h3, div.body h4, div.body h5, div.body h6 { 149 | font-weight: 300; 150 | } 151 | 152 | div.body h1 { 153 | font-size: 2em; 154 | } 155 | 156 | div.body h2 { 157 | font-size: 1.5em; 158 | } 159 | -------------------------------------------------------------------------------- /docs/archive/client.rst: -------------------------------------------------------------------------------- 1 | Client 2 | ------ 3 | 4 | .. note:: 5 | 6 | ``ArchiveClient`` instances are usually created via 7 | :func:`YamcsClient.get_archive() `: 8 | 9 | .. code-block:: python 10 | 11 | from yamcs.client import YamcsClient 12 | 13 | client = YamcsClient('localhost:8090') 14 | archive = client.get_archive(instance='simulator') 15 | # ... 16 | 17 | .. autoclass:: yamcs.client.ArchiveClient 18 | :members: 19 | :undoc-members: 20 | -------------------------------------------------------------------------------- /docs/archive/index.rst: -------------------------------------------------------------------------------- 1 | Archive 2 | ======= 3 | 4 | The Archive API provides methods that you can use to programmatically retrieve the content of a Yamcs Archive. 5 | 6 | Reference 7 | --------- 8 | 9 | .. toctree:: 10 | :maxdepth: 2 11 | 12 | client 13 | model 14 | 15 | Snippets 16 | -------- 17 | 18 | Create an :class:`.ArchiveClient` for a specific instance: 19 | 20 | .. code-block:: python 21 | 22 | from yamcs.client import YamcsClient 23 | 24 | client = YamcsClient('localhost:8090') 25 | archive = client.get_archive(instance='simulator') 26 | 27 | 28 | Packet Retrieval 29 | ^^^^^^^^^^^^^^^^ 30 | 31 | Print the last 10 packets: 32 | 33 | .. literalinclude:: ../../yamcs-client/examples/archive_retrieval.py 34 | :pyobject: print_last_packets 35 | :start-after: """ 36 | :dedent: 4 37 | 38 | Print available range of archived packets: 39 | 40 | .. literalinclude:: ../../yamcs-client/examples/archive_retrieval.py 41 | :pyobject: print_packet_range 42 | :start-after: """ 43 | :dedent: 4 44 | 45 | Iterate a specific range of packets: 46 | 47 | .. literalinclude:: ../../yamcs-client/examples/archive_retrieval.py 48 | :pyobject: iterate_specific_packet_range 49 | :start-after: """ 50 | :dedent: 4 51 | 52 | Download raw packet binary to a file: 53 | 54 | .. literalinclude:: ../../yamcs-client/examples/archive_retrieval.py 55 | :pyobject: export_raw_packets 56 | :start-after: """ 57 | :dedent: 4 58 | 59 | 60 | Parameter Retrieval 61 | ^^^^^^^^^^^^^^^^^^^ 62 | 63 | Retrieve the last 10 values of a parameter: 64 | 65 | .. literalinclude:: ../../yamcs-client/examples/archive_retrieval.py 66 | :pyobject: print_last_values 67 | :start-after: """ 68 | :dedent: 4 69 | 70 | Iterate a specific range of values: 71 | 72 | .. literalinclude:: ../../yamcs-client/examples/archive_retrieval.py 73 | :pyobject: iterate_specific_parameter_range 74 | :start-after: """ 75 | :dedent: 4 76 | 77 | Iterate values of multiple parameters by unique generation time: 78 | 79 | .. literalinclude:: ../../yamcs-client/examples/archive_retrieval.py 80 | :pyobject: stream_specific_parameter_range 81 | :start-after: """ 82 | :dedent: 4 83 | 84 | 85 | Event Retrieval 86 | ^^^^^^^^^^^^^^^ 87 | 88 | Iterate a specific range of events: 89 | 90 | .. literalinclude:: ../../yamcs-client/examples/archive_retrieval.py 91 | :pyobject: iterate_specific_event_range 92 | :start-after: """ 93 | :dedent: 4 94 | 95 | 96 | Command Retrieval 97 | ^^^^^^^^^^^^^^^^^ 98 | 99 | Retrieve the last 10 issued commands: 100 | 101 | .. literalinclude:: ../../yamcs-client/examples/archive_retrieval.py 102 | :pyobject: print_last_commands 103 | :start-after: """ 104 | :dedent: 4 105 | 106 | 107 | Histogram Retrieval 108 | ^^^^^^^^^^^^^^^^^^^ 109 | 110 | Print the number of packets grouped by packet name: 111 | 112 | .. literalinclude:: ../../yamcs-client/examples/archive_breakdown.py 113 | :pyobject: print_packet_count 114 | :start-after: """ 115 | :dedent: 4 116 | 117 | Print the number of events grouped by source: 118 | 119 | .. literalinclude:: ../../yamcs-client/examples/archive_breakdown.py 120 | :pyobject: print_event_count 121 | :start-after: """ 122 | :dedent: 4 123 | 124 | Print the number of processed parameter frames grouped by group name: 125 | 126 | .. literalinclude:: ../../yamcs-client/examples/archive_breakdown.py 127 | :pyobject: print_pp_groups 128 | :start-after: """ 129 | :dedent: 4 130 | 131 | Print the number of commands grouped by name: 132 | 133 | .. literalinclude:: ../../yamcs-client/examples/archive_breakdown.py 134 | :pyobject: print_command_count 135 | :start-after: """ 136 | :dedent: 4 137 | -------------------------------------------------------------------------------- /docs/archive/model.rst: -------------------------------------------------------------------------------- 1 | Model 2 | ===== 3 | 4 | .. autoclass:: yamcs.client.ColumnData 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | 9 | .. autoclass:: yamcs.client.IndexGroup 10 | :members: 11 | :undoc-members: 12 | :show-inheritance: 13 | 14 | .. autoclass:: yamcs.client.IndexRecord 15 | :members: 16 | :undoc-members: 17 | :show-inheritance: 18 | 19 | .. autoclass:: yamcs.client.ParameterRange 20 | :members: 21 | :undoc-members: 22 | :show-inheritance: 23 | 24 | .. autoclass:: yamcs.client.ParameterRangeEntry 25 | :members: 26 | :undoc-members: 27 | :show-inheritance: 28 | 29 | .. autoclass:: yamcs.client.ResultSet 30 | :members: 31 | :undoc-members: 32 | :show-inheritance: 33 | 34 | .. autoclass:: yamcs.client.Sample 35 | :members: 36 | :undoc-members: 37 | :show-inheritance: 38 | 39 | .. autoclass:: yamcs.client.Stream 40 | :members: 41 | :undoc-members: 42 | :show-inheritance: 43 | 44 | .. autoclass:: yamcs.client.StreamData 45 | :members: 46 | :undoc-members: 47 | :show-inheritance: 48 | 49 | .. autoclass:: yamcs.client.Table 50 | :members: 51 | :undoc-members: 52 | :show-inheritance: 53 | -------------------------------------------------------------------------------- /docs/conf.py: -------------------------------------------------------------------------------- 1 | import pkg_resources 2 | 3 | project = "yamcs-client" 4 | copyright = "2020, Space Applications Services" 5 | author = "Space Applications Services" 6 | version = "" 7 | source_suffix = ".rst" 8 | master_doc = "index" 9 | language = "en" 10 | exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"] 11 | pygments_style = "sphinx" 12 | templates_path = ["_templates"] 13 | 14 | dist = pkg_resources.get_distribution("yamcs-client") 15 | release = dist.version 16 | 17 | extensions = [ 18 | # We don't use napolean style, but keep this because it suppresses 19 | # errors coming from docstring when Future is inherited. 20 | "sphinx.ext.napoleon", 21 | "sphinx.ext.autodoc", 22 | "sphinx.ext.doctest", 23 | "sphinx.ext.intersphinx", 24 | "sphinxcontrib.yamcs", 25 | ] 26 | 27 | html_theme = "alabaster" 28 | html_theme_options = { 29 | "description": "Yamcs Client Library for Python", 30 | "fixed_sidebar": False, 31 | "show_powered_by": False, 32 | "font_family": "Helvetica,Arial,sans-serif", 33 | "font_size": "15px", 34 | } 35 | html_static_path = ["_static"] 36 | html_sidebars = { 37 | "**": [ 38 | "about.html", 39 | "navigation.html", 40 | "relations.html", 41 | "searchbox.html", 42 | ] 43 | } 44 | 45 | html_show_sourcelink = False 46 | 47 | 48 | latex_elements = { 49 | "papersize": "a4paper", 50 | "figure_align": "htbp", 51 | } 52 | 53 | # Grouping the document tree into LaTeX files. List of tuples 54 | # (source start file, target name, title, 55 | # author, documentclass [howto, manual, or own class]). 56 | latex_documents = [ 57 | ( 58 | master_doc, 59 | f"python-yamcs-client-{release}.tex", 60 | "Python Yamcs Client", 61 | "Space Applications Services", 62 | "manual", 63 | ), 64 | ] 65 | 66 | # Too many URLs (for each datatype), so hide them 67 | latex_show_urls = "no" 68 | latex_show_pagerefs = False 69 | 70 | autoclass_content = "both" 71 | 72 | intersphinx_mapping = { 73 | "requests": ("https://requests.kennethreitz.org/en/stable/", None), 74 | "python": ("https://docs.python.org/3", None), 75 | } 76 | 77 | 78 | def setup(app): 79 | app.add_css_file("css-overrides.css") 80 | -------------------------------------------------------------------------------- /docs/examples/alarms.rst: -------------------------------------------------------------------------------- 1 | alarms.py 2 | ========= 3 | 4 | .. literalinclude:: ../../yamcs-client/examples/alarms.py 5 | -------------------------------------------------------------------------------- /docs/examples/archive_breakdown.rst: -------------------------------------------------------------------------------- 1 | archive_breakdown.py 2 | ==================== 3 | 4 | .. literalinclude:: ../../yamcs-client/examples/archive_breakdown.py 5 | -------------------------------------------------------------------------------- /docs/examples/archive_retrieval.rst: -------------------------------------------------------------------------------- 1 | archive_retrieval.py 2 | ==================== 3 | 4 | .. literalinclude:: ../../yamcs-client/examples/archive_retrieval.py 5 | -------------------------------------------------------------------------------- /docs/examples/authenticate.rst: -------------------------------------------------------------------------------- 1 | authenticate.py 2 | =============== 3 | 4 | .. literalinclude:: ../../yamcs-client/examples/authenticate.py 5 | -------------------------------------------------------------------------------- /docs/examples/ccsds_completeness.rst: -------------------------------------------------------------------------------- 1 | ccsds_completeness.py 2 | ===================== 3 | 4 | .. note:: 5 | 6 | CCSDS Completeness is a concept specific to CCSDS-style packets. If you store 7 | a different type of packet in Yamcs, then this code example is not applicable. 8 | 9 | .. literalinclude:: ../../yamcs-client/examples/ccsds_completeness.py 10 | -------------------------------------------------------------------------------- /docs/examples/commanding.rst: -------------------------------------------------------------------------------- 1 | commanding.py 2 | ============= 3 | 4 | .. literalinclude:: ../../yamcs-client/examples/commanding.py 5 | -------------------------------------------------------------------------------- /docs/examples/cop1.rst: -------------------------------------------------------------------------------- 1 | cop1.py 2 | ======= 3 | 4 | .. literalinclude:: ../../yamcs-client/examples/cop1.py 5 | -------------------------------------------------------------------------------- /docs/examples/events.rst: -------------------------------------------------------------------------------- 1 | events.py 2 | ========= 3 | 4 | .. literalinclude:: ../../yamcs-client/examples/events.py 5 | -------------------------------------------------------------------------------- /docs/examples/file_transfer.rst: -------------------------------------------------------------------------------- 1 | file_transfer.py 2 | ================ 3 | 4 | .. literalinclude:: ../../yamcs-client/examples/file_transfer.py 5 | -------------------------------------------------------------------------------- /docs/examples/index.rst: -------------------------------------------------------------------------------- 1 | Examples 2 | ======== 3 | 4 | All of these examples run against a simulation that is used to 5 | develop and demo Yamcs. This setup is linked to a simple simulator 6 | which emits TM in the form of CCSDS packets and accepts a few 7 | telecommands as well. 8 | 9 | Most of the telemetered parameters are in a space system 10 | called ``/YSS/SIMULATOR``. 11 | 12 | .. toctree:: 13 | 14 | alarms 15 | archive_breakdown 16 | archive_retrieval 17 | authenticate 18 | ccsds_completeness 19 | commanding 20 | cop1 21 | file_transfer 22 | links 23 | events 24 | mission_time 25 | packet_subscription 26 | parameter_subscription 27 | plot_with_matplotlib 28 | query_mdb 29 | read_write_parameters 30 | reconnection 31 | timeline 32 | write_mdb 33 | -------------------------------------------------------------------------------- /docs/examples/links.rst: -------------------------------------------------------------------------------- 1 | links.py 2 | ======== 3 | 4 | .. literalinclude:: ../../yamcs-client/examples/links.py 5 | -------------------------------------------------------------------------------- /docs/examples/mission_time.rst: -------------------------------------------------------------------------------- 1 | mission_time.py 2 | =============== 3 | 4 | .. literalinclude:: ../../yamcs-client/examples/mission_time.py 5 | -------------------------------------------------------------------------------- /docs/examples/packet_subscription.rst: -------------------------------------------------------------------------------- 1 | packet_subscription.py 2 | ====================== 3 | 4 | .. literalinclude:: ../../yamcs-client/examples/packet_subscription.py 5 | -------------------------------------------------------------------------------- /docs/examples/parameter_subscription.rst: -------------------------------------------------------------------------------- 1 | parameter_subscription.py 2 | ========================= 3 | 4 | .. literalinclude:: ../../yamcs-client/examples/parameter_subscription.py 5 | -------------------------------------------------------------------------------- /docs/examples/plot_with_matplotlib.rst: -------------------------------------------------------------------------------- 1 | plot_with_matplotlib.py 2 | ======================= 3 | 4 | .. note:: 5 | 6 | To run this example, install matplotlib:: 7 | 8 | pip install matplotlib 9 | 10 | 11 | .. literalinclude:: ../../yamcs-client/examples/plot_with_matplotlib.py 12 | -------------------------------------------------------------------------------- /docs/examples/query_mdb.rst: -------------------------------------------------------------------------------- 1 | query_mdb.py 2 | ============ 3 | 4 | .. literalinclude:: ../../yamcs-client/examples/query_mdb.py 5 | -------------------------------------------------------------------------------- /docs/examples/read_write_parameters.rst: -------------------------------------------------------------------------------- 1 | read_write_parameters.py 2 | ======================== 3 | 4 | .. literalinclude:: ../../yamcs-client/examples/read_write_parameters.py 5 | -------------------------------------------------------------------------------- /docs/examples/reconnection.rst: -------------------------------------------------------------------------------- 1 | reconnection.py 2 | =============== 3 | 4 | .. literalinclude:: ../../yamcs-client/examples/reconnection.py 5 | -------------------------------------------------------------------------------- /docs/examples/timeline.rst: -------------------------------------------------------------------------------- 1 | timeline.py 2 | =========== 3 | 4 | .. literalinclude:: ../../yamcs-client/examples/timeline.py 5 | -------------------------------------------------------------------------------- /docs/examples/write_mdb.rst: -------------------------------------------------------------------------------- 1 | write_mdb.py 2 | ============ 3 | 4 | If a system is marked as *writable* in the loader tree, Yamcs becomes responsible for updating the file, and the HTTP API can then be used to update it. This capability exists only for XTCE files. 5 | 6 | Note that this functionality is experimental, and does not offer the same degree of customizations as when loading the MDB from a predefined XTCE file. 7 | 8 | To demonstrate this capability, add a writable subsystem ``test`` to the `Yamcs Quickstart `_ example: 9 | 10 | .. code-block:: yaml 11 | :caption: :file:`mdb/yamcs.myproject.yaml` 12 | 13 | mdb: 14 | - type: xtce 15 | args: 16 | file: mdb/xtce.xml 17 | subLoaders: 18 | - type: xtce 19 | writable: true 20 | args: 21 | file: /path/to/test.xml 22 | 23 | Because the quickstart example works on a copy of the files (in :file:`target/yamcs/`), we specify :file:`test.xml` as an absolute rather than relative reference. 24 | 25 | The initial content can just be an empty XTCE SpaceSystem, specifying its name: 26 | 27 | .. code-block:: xml 28 | :caption: :file:`mdb/test.xml` 29 | 30 | 31 | 32 | 33 | 34 | Then you can add parameter types and values like this: 35 | 36 | .. literalinclude:: ../../yamcs-client/examples/write_mdb.py 37 | 38 | Afterwards you should see that :file:`test.xml` has been updated automatically: 39 | 40 | .. code-block:: xml 41 | :caption: :file:`mdb/test.xml` 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /docs/filetransfer/client.rst: -------------------------------------------------------------------------------- 1 | Client 2 | ------ 3 | 4 | .. autoclass:: yamcs.client.FileTransferClient 5 | :members: 6 | :undoc-members: 7 | 8 | .. autoclass:: yamcs.client.FileTransferServiceClient 9 | :members: 10 | :undoc-members: 11 | 12 | .. autoclass:: yamcs.client.FileListSubscription 13 | :members: 14 | :undoc-members: 15 | 16 | .. autoclass:: yamcs.client.TransferSubscription 17 | :members: 18 | :undoc-members: 19 | -------------------------------------------------------------------------------- /docs/filetransfer/index.rst: -------------------------------------------------------------------------------- 1 | File Transfer 2 | ============= 3 | 4 | The File Transfer API provides methods that you can use to programmatically work with file transfers such as CFDP. 5 | 6 | 7 | Reference 8 | --------- 9 | 10 | .. toctree:: 11 | :maxdepth: 2 12 | 13 | client 14 | model 15 | 16 | 17 | Snippets 18 | -------- 19 | 20 | Create a :class:`.FileTransferClient` for a specific instance: 21 | 22 | .. code-block:: python 23 | 24 | from yamcs.client import YamcsClient 25 | 26 | client = YamcsClient('localhost:8090') 27 | cfdp = client.get_file_transfer_client(instance='cfdp') 28 | 29 | # Operations are grouped by service. 30 | # Here: take the first available 31 | service = next(cfdp.list_services()) 32 | 33 | Upload a file to the specified location on the remote entity: 34 | 35 | .. literalinclude:: ../../yamcs-client/examples/file_transfer.py 36 | :pyobject: upload_file 37 | :start-after: """ 38 | :dedent: 4 39 | 40 | Start file download: 41 | 42 | .. literalinclude:: ../../yamcs-client/examples/file_transfer.py 43 | :pyobject: download_file 44 | :start-after: """ 45 | :lines: 1-2 46 | :dedent: 4 47 | 48 | Initiate transfer with non-default parameters: 49 | 50 | .. literalinclude:: ../../yamcs-client/examples/file_transfer.py 51 | :pyobject: upload_file_extra 52 | :start-after: """ 53 | :lines: 1-4 54 | :dedent: 4 55 | 56 | Initiate transfer with extra transfer options: 57 | 58 | .. literalinclude:: ../../yamcs-client/examples/file_transfer.py 59 | :pyobject: upload_file_options 60 | :start-after: """ 61 | :lines: 1-3 62 | :dedent: 4 63 | 64 | Subscribe to file list changes: 65 | 66 | .. literalinclude:: ../../yamcs-client/examples/file_transfer.py 67 | :pyobject: subscribe_filelist 68 | :start-after: """ 69 | :lines: 1 70 | :dedent: 4 71 | 72 | Fetch file list from remote directory: 73 | 74 | .. literalinclude:: ../../yamcs-client/examples/file_transfer.py 75 | :pyobject: fetch_filelist 76 | :start-after: """ 77 | :lines: 1 78 | :dedent: 4 79 | 80 | Get the latest saved remote file list for the given directory, and display it: 81 | 82 | .. literalinclude:: ../../yamcs-client/examples/file_transfer.py 83 | :pyobject: get_filelist 84 | :start-after: """ 85 | :dedent: 4 86 | -------------------------------------------------------------------------------- /docs/filetransfer/model.rst: -------------------------------------------------------------------------------- 1 | Model 2 | ===== 3 | 4 | 5 | .. autoclass:: yamcs.client.EntityInfo 6 | :members: 7 | :undoc-members: 8 | :show-inheritance: 9 | 10 | .. autoclass:: yamcs.client.FileTransferCapabilities 11 | :members: 12 | :undoc-members: 13 | :show-inheritance: 14 | 15 | .. autoclass:: yamcs.client.FileTransferOption 16 | :members: 17 | :undoc-members: 18 | :show-inheritance: 19 | 20 | .. autoclass:: yamcs.client.RemoteFile 21 | :members: 22 | :undoc-members: 23 | :show-inheritance: 24 | 25 | .. autoclass:: yamcs.client.RemoteFileListing 26 | :members: 27 | :undoc-members: 28 | :show-inheritance: 29 | 30 | .. autoclass:: yamcs.client.FileTransferService 31 | :members: 32 | :undoc-members: 33 | :show-inheritance: 34 | 35 | .. autoclass:: yamcs.client.Transfer 36 | :members: 37 | :undoc-members: 38 | :show-inheritance: 39 | -------------------------------------------------------------------------------- /docs/general/authentication.rst: -------------------------------------------------------------------------------- 1 | Authentication 2 | ============== 3 | 4 | User Accounts 5 | ------------- 6 | 7 | Yamcs Server can be configured for different authentication setups. 8 | 9 | The common use case is to entrust Yamcs with validating user credentials 10 | (either by locally verifying passwords, or by delegating to an upstream 11 | server such as an LDAP tree). 12 | 13 | To authenticate in such a scenario, do: 14 | 15 | .. literalinclude:: ../../yamcs-client/examples/authenticate.py 16 | :pyobject: authenticate_with_username_password 17 | :start-after: """ 18 | :lines: 1-2 19 | :dedent: 4 20 | 21 | In the background this will convert your username/password credentials 22 | to an access token with limited lifetime, and a long-lived refresh token 23 | for automatically generating new access tokens. 24 | 25 | Further HTTP requests do not use your username/password but instead use 26 | these tokens. 27 | 28 | 29 | Service Accounts 30 | ---------------- 31 | 32 | Service accounts are useful in server-to-server scenarios. Support for service 33 | accounts will be available in future releases. 34 | 35 | 36 | Types 37 | ----- 38 | 39 | .. autoclass:: yamcs.client.APIKeyCredentials 40 | :members: 41 | :undoc-members: 42 | :show-inheritance: 43 | 44 | .. autoclass:: yamcs.client.BasicAuthCredentials 45 | :members: 46 | :undoc-members: 47 | :show-inheritance: 48 | 49 | .. autoclass:: yamcs.client.Credentials 50 | :members: 51 | :undoc-members: 52 | :show-inheritance: 53 | -------------------------------------------------------------------------------- /docs/general/client.rst: -------------------------------------------------------------------------------- 1 | YamcsClient 2 | ----------- 3 | 4 | .. autoclass:: yamcs.client.YamcsClient 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | 9 | .. autoclass:: yamcs.client.TimeSubscription 10 | :members: 11 | :undoc-members: 12 | :show-inheritance: 13 | 14 | .. autoclass:: yamcs.client.LinkSubscription 15 | :members: 16 | :undoc-members: 17 | :show-inheritance: 18 | -------------------------------------------------------------------------------- /docs/general/exceptions.rst: -------------------------------------------------------------------------------- 1 | Exceptions 2 | ========== 3 | 4 | .. autoclass:: yamcs.client.ConnectionFailure 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | 9 | .. autoclass:: yamcs.client.NotFound 10 | :members: 11 | :undoc-members: 12 | :show-inheritance: 13 | 14 | .. autoclass:: yamcs.client.TimeoutError 15 | :members: 16 | :undoc-members: 17 | :show-inheritance: 18 | 19 | .. autoclass:: yamcs.client.Unauthorized 20 | :members: 21 | :undoc-members: 22 | :show-inheritance: 23 | 24 | .. autoclass:: yamcs.client.YamcsError 25 | :members: 26 | :undoc-members: 27 | :show-inheritance: 28 | -------------------------------------------------------------------------------- /docs/general/futures.rst: -------------------------------------------------------------------------------- 1 | Futures 2 | ======= 3 | 4 | .. autoclass:: yamcs.client.WebSocketSubscriptionFuture 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/general/index.rst: -------------------------------------------------------------------------------- 1 | General Client 2 | ============== 3 | 4 | Reference 5 | --------- 6 | 7 | .. toctree:: 8 | :maxdepth: 2 9 | 10 | client 11 | model 12 | authentication 13 | exceptions 14 | futures 15 | 16 | Snippets 17 | -------- 18 | 19 | Create a :class:`.YamcsClient`: 20 | 21 | .. code-block:: python 22 | 23 | from yamcs.client import YamcsClient 24 | 25 | client = YamcsClient('localhost:8090') 26 | 27 | Provide credentials if Yamcs is secured: 28 | 29 | .. code-block:: python 30 | 31 | from yamcs.client import Credentials, YamcsClient 32 | 33 | credentials = Credentials(username='admin', password='password') 34 | client = YamcsClient('localhost:8090', credentials=credentials) 35 | 36 | 37 | Events 38 | ^^^^^^ 39 | 40 | Receive :class:`.Event` callbacks: 41 | 42 | .. literalinclude:: ../../yamcs-client/examples/events.py 43 | :pyobject: listen_to_event_updates 44 | :start-after: """ 45 | :dedent: 4 46 | 47 | Send an event: 48 | 49 | .. literalinclude:: ../../yamcs-client/examples/events.py 50 | :pyobject: send_event 51 | :start-after: """ 52 | :dedent: 4 53 | -------------------------------------------------------------------------------- /docs/general/model.rst: -------------------------------------------------------------------------------- 1 | Model 2 | ===== 3 | 4 | .. autoclass:: yamcs.client.AuthInfo 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | 9 | .. autoclass:: yamcs.client.Event 10 | :members: 11 | :undoc-members: 12 | :show-inheritance: 13 | 14 | .. autoclass:: yamcs.client.Instance 15 | :members: 16 | :undoc-members: 17 | :show-inheritance: 18 | 19 | .. autoclass:: yamcs.client.InstanceTemplate 20 | :members: 21 | :undoc-members: 22 | :show-inheritance: 23 | 24 | .. autoclass:: yamcs.client.Link 25 | :members: 26 | :undoc-members: 27 | :show-inheritance: 28 | 29 | .. autoclass:: yamcs.client.LinkAction 30 | :members: 31 | :undoc-members: 32 | :show-inheritance: 33 | 34 | .. autoclass:: yamcs.client.LoadParameterValuesResult 35 | :members: 36 | :undoc-members: 37 | :show-inheritance: 38 | 39 | .. autoclass:: yamcs.client.ObjectPrivilege 40 | :members: 41 | :undoc-members: 42 | :show-inheritance: 43 | 44 | .. autoclass:: yamcs.client.Processor 45 | :members: 46 | :undoc-members: 47 | :show-inheritance: 48 | 49 | .. autoclass:: yamcs.client.RdbTablespace 50 | :members: 51 | :undoc-members: 52 | :show-inheritance: 53 | 54 | .. autoclass:: yamcs.client.ServerInfo 55 | :members: 56 | :undoc-members: 57 | :show-inheritance: 58 | 59 | .. autoclass:: yamcs.client.Service 60 | :members: 61 | :undoc-members: 62 | :show-inheritance: 63 | 64 | .. autoclass:: yamcs.client.UserInfo 65 | :members: 66 | :undoc-members: 67 | :show-inheritance: 68 | -------------------------------------------------------------------------------- /docs/index.rst: -------------------------------------------------------------------------------- 1 | Python Yamcs Client 2 | =================== 3 | 4 | .. rubric:: Getting Started 5 | 6 | Install Python 3.8 or higher. 7 | 8 | Install ``yamcs-client`` from PyPI:: 9 | 10 | pip install --upgrade yamcs-client 11 | 12 | 13 | .. rubric:: Usage 14 | 15 | Get domain-specific clients: 16 | 17 | .. code-block:: python 18 | 19 | from yamcs.client import YamcsClient 20 | client = YamcsClient('localhost:8090') 21 | 22 | mdb = client.get_mdb(instance='simulator') 23 | # ... 24 | 25 | archive = client.get_archive(instance='simulator') 26 | # ... 27 | 28 | processor = client.get_processor(instance='simulator', processor='realtime') 29 | # ... 30 | 31 | 32 | .. rubric:: Documentation 33 | 34 | * :doc:`general/index` 35 | * :doc:`mdb/index` 36 | * :doc:`tmtc/index` 37 | * :doc:`archive/index` 38 | * :doc:`link/index` 39 | * :doc:`storage/index` 40 | * :doc:`filetransfer/index` 41 | * :doc:`tco/index` 42 | * :doc:`timeline/index` 43 | 44 | 45 | .. rubric:: Examples 46 | 47 | * :doc:`examples/index` 48 | 49 | 50 | .. toctree:: 51 | :hidden: 52 | :maxdepth: 2 53 | :titlesonly: 54 | 55 | general/index 56 | mdb/index 57 | tmtc/index 58 | archive/index 59 | link/index 60 | storage/index 61 | filetransfer/index 62 | tco/index 63 | timeline/index 64 | examples/index 65 | -------------------------------------------------------------------------------- /docs/link/client.rst: -------------------------------------------------------------------------------- 1 | Client 2 | ------ 3 | 4 | .. note:: 5 | 6 | ``LinkClient`` instances are usually created via 7 | :func:`YamcsClient.get_link() `: 8 | 9 | .. code-block:: python 10 | 11 | from yamcs.client import YamcsClient 12 | 13 | client = YamcsClient('localhost:8090') 14 | link = client.get_link(instance='simulator', link='udp-in') 15 | # ... 16 | 17 | .. autoclass:: yamcs.client.LinkClient 18 | :members: 19 | :undoc-members: 20 | 21 | .. autoclass:: yamcs.client.Cop1Subscription 22 | :members: 23 | :undoc-members: 24 | :show-inheritance: 25 | -------------------------------------------------------------------------------- /docs/link/index.rst: -------------------------------------------------------------------------------- 1 | Link Management 2 | =============== 3 | 4 | The Link API provides methods that you can use to programmatically interact 5 | with a Yamcs link. 6 | 7 | 8 | Reference 9 | --------- 10 | 11 | .. toctree:: 12 | :maxdepth: 2 13 | 14 | client 15 | model 16 | 17 | 18 | Snippets 19 | -------- 20 | 21 | Create a :class:`.LinkClient` for a specific link: 22 | 23 | .. code-block:: python 24 | 25 | from yamcs.client import YamcsClient 26 | 27 | client = YamcsClient('localhost:8090') 28 | link = client.get_link(instance='simulator', link='udp-in') 29 | 30 | 31 | Enable a link: 32 | 33 | .. literalinclude:: ../../yamcs-client/examples/links.py 34 | :pyobject: enable_link 35 | :start-after: """ 36 | :dedent: 4 37 | 38 | Run a link action: 39 | 40 | .. literalinclude:: ../../yamcs-client/examples/links.py 41 | :pyobject: run_action 42 | :start-after: """ 43 | :dedent: 4 44 | 45 | -------------------------------------------------------------------------------- /docs/link/model.rst: -------------------------------------------------------------------------------- 1 | Model 2 | ===== 3 | 4 | .. autoclass:: yamcs.client.Cop1Config 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | 9 | .. autoclass:: yamcs.client.Cop1Status 10 | :members: 11 | :undoc-members: 12 | :show-inheritance: 13 | -------------------------------------------------------------------------------- /docs/mdb/client.rst: -------------------------------------------------------------------------------- 1 | Client 2 | ------ 3 | .. note:: 4 | 5 | ``MDBClient`` instances are usually created via 6 | :func:`YamcsClient.get_mdb() `: 7 | 8 | .. code-block:: python 9 | 10 | from yamcs.client import YamcsClient 11 | 12 | client = YamcsClient('localhost:8090') 13 | mdb = client.get_mdb(instance='simulator') 14 | # ... 15 | 16 | .. autoclass:: yamcs.client.MDBClient 17 | :members: 18 | :undoc-members: 19 | -------------------------------------------------------------------------------- /docs/mdb/index.rst: -------------------------------------------------------------------------------- 1 | Mission Database 2 | ================ 3 | 4 | The Mission Database API provides methods for reading the entries in 5 | a Yamcs Mission Database (MDB). An MDB groups telemetry and command 6 | definitions for one or more *space systems*. The MDB is used to: 7 | 8 | * Instruct Yamcs how to process incoming packets 9 | * Describe items in Yamcs Archive 10 | * Instruct Yamcs how to compose telecommands 11 | 12 | Space systems form a hierarchical multi-rooted tree. Each level of the tree 13 | may contain any number of definitions. These break down in: 14 | 15 | * parameters 16 | * containers 17 | * commands 18 | * algorithms 19 | 20 | Entries in the Space system are addressable via a qualified name that 21 | looks like a Unix file path. Each segment of the path contains the name of 22 | the space system node, the final path segment is the name of the entry itself. 23 | 24 | For example, in an MDB that contains these parameter entries:: 25 | 26 | └── YSS 27 | └── SIMULATOR 28 | ├── BatteryVoltage1 29 | └── BatteryVoltage2 30 | 31 | we find two space systems ``/YSS`` and ``/YSS/SIMULATOR`` and two parameter 32 | entries ``/YSS/SIMULATOR/BatteryVoltage1`` and 33 | ``/YSS/SIMULATOR/BatteryVoltage2``. 34 | 35 | Some MDB entries may also define an alias. An alias is a unique name to 36 | address the entry under a custom namespace (unrelated to XTCE space systems). 37 | 38 | When it comes to addressing entries via this client, it is possible to 39 | provide either the fully-qualified XTCE name in the format 40 | ``/YSS/SIMULATOR/BatteryVoltage1`` or an alias in the format 41 | ``NAMESPACE/NAME``. 42 | 43 | 44 | Reference 45 | --------- 46 | 47 | .. toctree:: 48 | :maxdepth: 2 49 | 50 | client 51 | model 52 | 53 | 54 | Snippets 55 | -------- 56 | 57 | Create an :class:`.MDBClient` for a specific instance: 58 | 59 | .. code-block:: python 60 | 61 | from yamcs.client import YamcsClient 62 | 63 | client = YamcsClient('localhost:8090') 64 | mdb = client.get_mdb(instance='simulator') 65 | 66 | Print all space systems: 67 | 68 | .. literalinclude:: ../../yamcs-client/examples/query_mdb.py 69 | :pyobject: print_space_systems 70 | :start-after: """ 71 | :dedent: 4 72 | 73 | Print all parameters of type ``float``: 74 | 75 | .. literalinclude:: ../../yamcs-client/examples/query_mdb.py 76 | :pyobject: print_parameters 77 | :start-after: """ 78 | :dedent: 4 79 | 80 | Print all commands: 81 | 82 | .. literalinclude:: ../../yamcs-client/examples/query_mdb.py 83 | :pyobject: print_commands 84 | :start-after: """ 85 | :dedent: 4 86 | 87 | Find a parameter by qualified name or alias: 88 | 89 | .. literalinclude:: ../../yamcs-client/examples/query_mdb.py 90 | :pyobject: find_parameter 91 | :start-after: """ 92 | :dedent: 4 93 | -------------------------------------------------------------------------------- /docs/mdb/model.rst: -------------------------------------------------------------------------------- 1 | Model 2 | ===== 3 | 4 | .. autoclass:: yamcs.client.Algorithm 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | 9 | .. autoclass:: yamcs.client.Argument 10 | :members: 11 | :undoc-members: 12 | :show-inheritance: 13 | 14 | .. autoclass:: yamcs.client.ArgumentType 15 | :members: 16 | :undoc-members: 17 | :show-inheritance: 18 | 19 | .. autoclass:: yamcs.client.ArrayType 20 | :members: 21 | :undoc-members: 22 | :show-inheritance: 23 | 24 | .. autoclass:: yamcs.client.Command 25 | :members: 26 | :undoc-members: 27 | :show-inheritance: 28 | 29 | .. autoclass:: yamcs.client.Container 30 | :members: 31 | :undoc-members: 32 | :show-inheritance: 33 | 34 | .. autoclass:: yamcs.client.DataEncoding 35 | :members: 36 | :undoc-members: 37 | :show-inheritance: 38 | 39 | .. autoclass:: yamcs.client.EnumValue 40 | :members: 41 | :undoc-members: 42 | :show-inheritance: 43 | 44 | .. autoclass:: yamcs.client.Member 45 | :members: 46 | :undoc-members: 47 | :show-inheritance: 48 | 49 | .. autoclass:: yamcs.client.MissionDatabaseItem 50 | :members: 51 | :undoc-members: 52 | :show-inheritance: 53 | 54 | .. autoclass:: yamcs.client.Parameter 55 | :members: 56 | :undoc-members: 57 | :show-inheritance: 58 | 59 | .. autoclass:: yamcs.client.ParameterType 60 | :members: 61 | :undoc-members: 62 | :show-inheritance: 63 | 64 | .. autoclass:: yamcs.client.RangeSet 65 | :members: 66 | :undoc-members: 67 | :show-inheritance: 68 | 69 | .. autoclass:: yamcs.client.Significance 70 | :members: 71 | :undoc-members: 72 | :show-inheritance: 73 | 74 | .. autoclass:: yamcs.client.SpaceSystem 75 | :members: 76 | :undoc-members: 77 | :show-inheritance: 78 | -------------------------------------------------------------------------------- /docs/requirements.txt: -------------------------------------------------------------------------------- 1 | Sphinx 2 | sphinxcontrib-yamcs 3 | -------------------------------------------------------------------------------- /docs/storage/client.rst: -------------------------------------------------------------------------------- 1 | Client 2 | ------ 3 | 4 | .. autoclass:: yamcs.client.StorageClient 5 | :members: 6 | :undoc-members: 7 | -------------------------------------------------------------------------------- /docs/storage/index.rst: -------------------------------------------------------------------------------- 1 | Object Storage 2 | ============== 3 | 4 | The Storage API provides methods that you can use to programmatically work with Yamcs buckets and objects. 5 | 6 | Reference 7 | --------- 8 | 9 | .. toctree:: 10 | :maxdepth: 2 11 | 12 | client 13 | model 14 | 15 | 16 | Snippets 17 | -------- 18 | 19 | Create a :class:`.StorageClient`: 20 | 21 | .. code-block:: python 22 | 23 | from yamcs.client import YamcsClient 24 | 25 | client = YamcsClient('localhost:8090') 26 | storage = client.get_storage_client() 27 | -------------------------------------------------------------------------------- /docs/storage/model.rst: -------------------------------------------------------------------------------- 1 | Model 2 | ===== 3 | 4 | .. autoclass:: yamcs.client.Bucket 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | 9 | .. autoclass:: yamcs.client.ObjectInfo 10 | :members: 11 | :undoc-members: 12 | :show-inheritance: 13 | 14 | .. autoclass:: yamcs.client.ObjectListing 15 | :members: 16 | :undoc-members: 17 | :show-inheritance: 18 | -------------------------------------------------------------------------------- /docs/tco/client.rst: -------------------------------------------------------------------------------- 1 | Client 2 | ------ 3 | 4 | .. autoclass:: yamcs.client.TCOClient 5 | :members: 6 | :undoc-members: 7 | -------------------------------------------------------------------------------- /docs/tco/index.rst: -------------------------------------------------------------------------------- 1 | Time Correlation (TCO) 2 | ====================== 3 | 4 | The Time Correlation API provides methods that you can use to programmatically interact with a Yamcs TCO service. 5 | 6 | Reference 7 | --------- 8 | 9 | .. toctree:: 10 | :maxdepth: 2 11 | 12 | client 13 | model 14 | 15 | 16 | Snippets 17 | -------- 18 | 19 | Create a :class:`.TCOClient` for a specific instance: 20 | 21 | .. code-block:: python 22 | 23 | from yamcs.client import YamcsClient 24 | 25 | client = YamcsClient('localhost:8090') 26 | tco = client.get_tco_client(instance='pus', service='tco0') 27 | -------------------------------------------------------------------------------- /docs/tco/model.rst: -------------------------------------------------------------------------------- 1 | Model 2 | ===== 3 | 4 | .. autoclass:: yamcs.client.TCOCoefficients 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | 9 | .. autoclass:: yamcs.client.TCOSample 10 | :members: 11 | :undoc-members: 12 | :show-inheritance: 13 | 14 | .. autoclass:: yamcs.client.TCOStatus 15 | :members: 16 | :undoc-members: 17 | :show-inheritance: 18 | 19 | .. autoclass:: yamcs.client.TofInterval 20 | :members: 21 | :undoc-members: 22 | :show-inheritance: 23 | -------------------------------------------------------------------------------- /docs/timeline/client.rst: -------------------------------------------------------------------------------- 1 | Client 2 | ------ 3 | 4 | .. autoclass:: yamcs.client.TimelineClient 5 | :members: 6 | :undoc-members: 7 | -------------------------------------------------------------------------------- /docs/timeline/index.rst: -------------------------------------------------------------------------------- 1 | Timeline 2 | ======== 3 | 4 | The Timeline API provides methods that you can use to programmatically work with Yamcs bands and items. 5 | 6 | Reference 7 | --------- 8 | 9 | .. toctree:: 10 | :maxdepth: 2 11 | 12 | client 13 | model 14 | 15 | 16 | Snippets 17 | -------- 18 | 19 | Create a :class:`.TimelineClient` for a specific instance: 20 | 21 | .. code-block:: python 22 | 23 | from yamcs.client import YamcsClient 24 | 25 | client = YamcsClient("localhost:8090") 26 | timeline = client.get_timeline_client(instance="simulator") 27 | 28 | 29 | Create a few :class:`.Band` objects: 30 | 31 | .. literalinclude:: ../../yamcs-client/examples/timeline.py 32 | :pyobject: create_bands 33 | :start-after: global 34 | :dedent: 4 35 | 36 | Create some :class:`.Item` objects. Bands of type :class:`.ItemBand` will display items with matching tags: 37 | 38 | .. literalinclude:: ../../yamcs-client/examples/timeline.py 39 | :pyobject: create_items 40 | :start-after: """ 41 | :dedent: 4 42 | 43 | Create a :class:`.View` showing all bands: 44 | 45 | .. literalinclude:: ../../yamcs-client/examples/timeline.py 46 | :pyobject: create_view 47 | :start-after: """ 48 | :dedent: 4 49 | 50 | To update a :class:`.Band`, :class:`.Item` or :class:`.View` use the same save methods as for inserting. When saving or fetching these objects they are assigned a server identifier that is used to detect whether further saves require an insert or update. 51 | 52 | .. literalinclude:: ../../yamcs-client/examples/timeline.py 53 | :pyobject: edit_band 54 | :start-after: global 55 | :dedent: 4 56 | 57 | .. literalinclude:: ../../yamcs-client/examples/timeline.py 58 | :pyobject: edit_fetched_items 59 | :start-after: """ 60 | :dedent: 4 61 | 62 | Create a view with :class:`.ParameterStateBand` and :class:`.ParameterPlot` bands: 63 | 64 | .. literalinclude:: ../../yamcs-client/examples/timeline.py 65 | :pyobject: create_parameter_bands 66 | :start-after: """ 67 | :dedent: 4 68 | -------------------------------------------------------------------------------- /docs/timeline/model.rst: -------------------------------------------------------------------------------- 1 | Model 2 | ===== 3 | 4 | .. autoclass:: yamcs.client.Band 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | 9 | .. autoclass:: yamcs.client.CommandBand 10 | :members: 11 | :undoc-members: 12 | :show-inheritance: 13 | 14 | .. autoclass:: yamcs.client.Item 15 | :members: 16 | :undoc-members: 17 | :show-inheritance: 18 | 19 | .. autoclass:: yamcs.client.ItemBand 20 | :members: 21 | :undoc-members: 22 | :show-inheritance: 23 | 24 | .. autoclass:: yamcs.client.ParameterPlot 25 | :members: 26 | :undoc-members: 27 | :show-inheritance: 28 | 29 | .. autoclass:: yamcs.client.ParameterStateBand 30 | :members: 31 | :undoc-members: 32 | :show-inheritance: 33 | 34 | .. autoclass:: yamcs.client.RangeMapping 35 | :members: 36 | :undoc-members: 37 | :show-inheritance: 38 | 39 | .. autoclass:: yamcs.client.Spacer 40 | :members: 41 | :undoc-members: 42 | :show-inheritance: 43 | 44 | .. autoclass:: yamcs.client.TimeRuler 45 | :members: 46 | :undoc-members: 47 | :show-inheritance: 48 | 49 | .. autoclass:: yamcs.client.Trace 50 | :members: 51 | :undoc-members: 52 | :show-inheritance: 53 | 54 | .. autoclass:: yamcs.client.ValueMapping 55 | :members: 56 | :undoc-members: 57 | :show-inheritance: 58 | 59 | .. autoclass:: yamcs.client.View 60 | :members: 61 | :undoc-members: 62 | :show-inheritance: 63 | -------------------------------------------------------------------------------- /docs/tmtc/client.rst: -------------------------------------------------------------------------------- 1 | Client 2 | ------ 3 | 4 | .. note:: 5 | 6 | ``ProcessorClient`` instances are usually created via 7 | :func:`YamcsClient.get_processor() `: 8 | 9 | .. code-block:: python 10 | 11 | from yamcs.client import YamcsClient 12 | 13 | client = YamcsClient('localhost:8090') 14 | processor = client.get_processor(instance='simulator', 15 | processor='realtime') 16 | # ... 17 | 18 | .. autoclass:: yamcs.client.ProcessorClient 19 | :members: 20 | :undoc-members: 21 | 22 | .. autoclass:: yamcs.client.CommandConnection 23 | :members: 24 | :undoc-members: 25 | :show-inheritance: 26 | 27 | .. autoclass:: yamcs.client.AlarmSubscription 28 | :members: 29 | :undoc-members: 30 | :show-inheritance: 31 | 32 | .. autoclass:: yamcs.client.CommandHistorySubscription 33 | :members: 34 | :undoc-members: 35 | :show-inheritance: 36 | 37 | .. autoclass:: yamcs.client.ContainerSubscription 38 | :members: 39 | :undoc-members: 40 | :show-inheritance: 41 | 42 | .. autoclass:: yamcs.client.ParameterSubscription 43 | :members: 44 | :undoc-members: 45 | :show-inheritance: 46 | -------------------------------------------------------------------------------- /docs/tmtc/index.rst: -------------------------------------------------------------------------------- 1 | TM/TC Processing 2 | ================ 3 | 4 | The TM/TC API provides methods that you can use to programmatically interact 5 | with a TM/TC processor. 6 | 7 | 8 | Reference 9 | --------- 10 | 11 | .. toctree:: 12 | :maxdepth: 2 13 | 14 | client 15 | model 16 | 17 | 18 | Snippets 19 | -------- 20 | 21 | Create a :class:`.ProcessorClient` for a specific processor: 22 | 23 | .. code-block:: python 24 | 25 | from yamcs.client import YamcsClient 26 | 27 | client = YamcsClient('localhost:8090') 28 | processor = client.get_processor(instance='simulator', processor='realtime') 29 | 30 | 31 | Read/Write Parameters 32 | ^^^^^^^^^^^^^^^^^^^^^ 33 | 34 | Read a single value. This returns the latest value from server cache. 35 | 36 | .. literalinclude:: ../../yamcs-client/examples/read_write_parameters.py 37 | :pyobject: print_cached_value 38 | :start-after: """ 39 | :dedent: 4 40 | 41 | Read a single value, but block until a fresh value could be processed: 42 | 43 | .. literalinclude:: ../../yamcs-client/examples/read_write_parameters.py 44 | :pyobject: print_realtime_value 45 | :start-after: """ 46 | :dedent: 4 47 | 48 | Read the latest value of multiple parameters at the same time: 49 | 50 | .. literalinclude:: ../../yamcs-client/examples/read_write_parameters.py 51 | :pyobject: print_current_values 52 | :start-after: """ 53 | :dedent: 4 54 | 55 | Set the value of a parameter. Only some types of parameters can 56 | be written to. This includes software parameters (local to Yamcs) 57 | and parameters that are linked to an external system (such as 58 | a simulator). 59 | 60 | .. literalinclude:: ../../yamcs-client/examples/read_write_parameters.py 61 | :pyobject: write_value 62 | :start-after: """ 63 | :dedent: 4 64 | 65 | Set the value of multiple parameters: 66 | 67 | .. literalinclude:: ../../yamcs-client/examples/read_write_parameters.py 68 | :pyobject: write_values 69 | :start-after: """ 70 | :dedent: 4 71 | 72 | 73 | Parameter Subscription 74 | ^^^^^^^^^^^^^^^^^^^^^^ 75 | 76 | Poll latest values from a subscription: 77 | 78 | .. literalinclude:: ../../yamcs-client/examples/parameter_subscription.py 79 | :pyobject: poll_values 80 | :start-after: """ 81 | :dedent: 4 82 | 83 | Receive :class:`.ParameterData` callbacks whenever one or more of the 84 | subscribed parameters have been updated: 85 | 86 | .. literalinclude:: ../../yamcs-client/examples/parameter_subscription.py 87 | :pyobject: receive_callbacks 88 | :start-after: """ 89 | :dedent: 4 90 | 91 | Create and modify a parameter subscription: 92 | 93 | .. literalinclude:: ../../yamcs-client/examples/parameter_subscription.py 94 | :pyobject: manage_subscription 95 | :start-after: """ 96 | :dedent: 4 97 | 98 | 99 | Commanding 100 | ^^^^^^^^^^ 101 | 102 | Issue a command (fire-and-forget): 103 | 104 | .. literalinclude:: ../../yamcs-client/examples/commanding.py 105 | :pyobject: issue_command 106 | :start-after: """ 107 | :dedent: 4 108 | 109 | To monitor acknowledgments, establish a command connection first. Commands issued from this connection are automatically updated with progress status: 110 | 111 | .. literalinclude:: ../../yamcs-client/examples/commanding.py 112 | :pyobject: monitor_acknowledgment 113 | :start-after: """ 114 | :dedent: 4 115 | 116 | The default Yamcs-local acknowledgments are: 117 | 118 | * Acknowledge_Queued 119 | * Acknowledge_Released 120 | * Acknowledge_Sent 121 | 122 | Custom telemetry verifiers or command links may cause additional acknowledgments to be generated. 123 | 124 | If configured, command completion can also be monitored: 125 | 126 | .. literalinclude:: ../../yamcs-client/examples/commanding.py 127 | :pyobject: monitor_command 128 | :start-after: """ 129 | :dedent: 4 130 | 131 | 132 | Alarm Monitoring 133 | ^^^^^^^^^^^^^^^^ 134 | 135 | Receive :class:`.AlarmUpdate` callbacks: 136 | 137 | .. literalinclude:: ../../yamcs-client/examples/alarms.py 138 | :pyobject: receive_callbacks 139 | :start-after: """ 140 | :dedent: 4 141 | 142 | Acknowledge all active alarms: 143 | 144 | .. literalinclude:: ../../yamcs-client/examples/alarms.py 145 | :pyobject: acknowledge_all 146 | :start-after: """ 147 | :dedent: 4 148 | 149 | 150 | Run a Script 151 | ^^^^^^^^^^^^ 152 | 153 | Run a custom script. The script has to be known by Yamcs. By default, this is done by placing an executable file in the :file:`etc/scripts/` directory of Yamcs. 154 | 155 | Scripts have access to special environment variables ``YAMCS_URL``, ``YAMCS_API_KEY``, 156 | ``YAMCS_INSTANCE`` and ``YAMCS_PROCESSOR``, which is used by :func:`YamcsClient.from_environment() ` 157 | 158 | 159 | .. literalinclude:: ../../yamcs-client/examples/scripting.py 160 | :pyobject: run_script 161 | :start-after: """ 162 | :dedent: 4 163 | 164 | .. code-block:: python 165 | :caption: :file:`etc/scripts/simulate_los.sh` 166 | 167 | #!/usr/bin/env -S python3 -u 168 | 169 | import argparse 170 | import os 171 | import time 172 | 173 | from yamcs.client import YamcsClient 174 | 175 | parser = argparse.ArgumentParser() 176 | parser.add_argument("-d", "--duration", type=float, default=60) 177 | args = parser.parse_args() 178 | 179 | client = YamcsClient.from_environment() 180 | processor = client.get_processor( 181 | instance=os.environ["YAMCS_INSTANCE"], 182 | processor=os.environ["YAMCS_PROCESSOR"], 183 | ) 184 | 185 | print("Starting LOS") 186 | processor.issue_command("/TSE/simulator/start_los") 187 | time.sleep(args.duration) 188 | 189 | print("Stopping LOS") 190 | processor.issue_command("/TSE/simulator/stop_los") 191 | 192 | Notice the use of ``-u`` in the shebang. This disables Python output buffering, so that print statements are immediately seen. 193 | -------------------------------------------------------------------------------- /docs/tmtc/model.rst: -------------------------------------------------------------------------------- 1 | Model 2 | ===== 3 | 4 | .. autoclass:: yamcs.client.Acknowledgment 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | 9 | .. autoclass:: yamcs.client.Alarm 10 | :members: 11 | :undoc-members: 12 | :show-inheritance: 13 | 14 | .. autoclass:: yamcs.client.AlarmRangeSet 15 | :members: 16 | :undoc-members: 17 | :show-inheritance: 18 | 19 | .. autoclass:: yamcs.client.AlarmUpdate 20 | :members: 21 | :undoc-members: 22 | :show-inheritance: 23 | 24 | .. autoclass:: yamcs.client.Calibrator 25 | :members: 26 | :undoc-members: 27 | :show-inheritance: 28 | 29 | .. autoclass:: yamcs.client.CommandHistory 30 | :members: 31 | :undoc-members: 32 | :show-inheritance: 33 | 34 | .. autoclass:: yamcs.client.ContainerData 35 | :members: 36 | :undoc-members: 37 | :show-inheritance: 38 | 39 | .. autoclass:: yamcs.client.EventAlarm 40 | :members: 41 | :undoc-members: 42 | :show-inheritance: 43 | 44 | .. autoclass:: yamcs.client.IssuedCommand 45 | :members: 46 | :undoc-members: 47 | :show-inheritance: 48 | 49 | .. autoclass:: yamcs.client.MonitoredCommand 50 | :members: 51 | :undoc-members: 52 | :show-inheritance: 53 | 54 | .. autoclass:: yamcs.client.Packet 55 | :members: 56 | :undoc-members: 57 | :show-inheritance: 58 | 59 | .. autoclass:: yamcs.client.ParameterAlarm 60 | :members: 61 | :undoc-members: 62 | :show-inheritance: 63 | 64 | .. autoclass:: yamcs.client.ParameterData 65 | :members: 66 | :undoc-members: 67 | :show-inheritance: 68 | 69 | .. autoclass:: yamcs.client.ParameterValue 70 | :members: 71 | :undoc-members: 72 | :show-inheritance: 73 | 74 | .. autoclass:: yamcs.client.ValueUpdate 75 | :members: 76 | :undoc-members: 77 | :show-inheritance: 78 | 79 | .. autoclass:: yamcs.client.VerificationConfig 80 | :members: 81 | :undoc-members: 82 | :show-inheritance: 83 | -------------------------------------------------------------------------------- /pyrightconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "ignore": [ 3 | "**/*_pb2.py" 4 | ], 5 | "reportAttributeAccessIssue": false, 6 | "reportInvalidTypeForm": "none" 7 | } 8 | -------------------------------------------------------------------------------- /yamcs-client-kerberos/.flake8: -------------------------------------------------------------------------------- 1 | [flake8] 2 | max-line-length = 88 3 | extend-ignore = E203 4 | -------------------------------------------------------------------------------- /yamcs-client-kerberos/Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: clean lint build deploy 2 | 3 | clean: 4 | rm -rf build dist *.egg-info 5 | 6 | lint: 7 | flake8 src --exclude '*pb2.py' --count --show-source --statistics 8 | 9 | build_legacy: lint 10 | python setup.py sdist bdist_wheel 11 | 12 | build: lint 13 | python -m build 14 | 15 | deploy: clean build 16 | twine upload -r pypi dist/* 17 | -------------------------------------------------------------------------------- /yamcs-client-kerberos/README.md: -------------------------------------------------------------------------------- 1 | # Kerberos authentication for Yamcs Client Library 2 | [![PyPI](https://img.shields.io/pypi/v/yamcs-client-kerberos.svg)](https://pypi.python.org/pypi/yamcs-client-kerberos) 3 | [![PyPI pyversions](https://img.shields.io/pypi/pyversions/yamcs-client-kerberos.svg)](https://pypi.python.org/pypi/yamcs-client-kerberos/) 4 | -------------------------------------------------------------------------------- /yamcs-client-kerberos/examples/authenticate.py: -------------------------------------------------------------------------------- 1 | from time import sleep 2 | 3 | from yamcs.client import YamcsClient 4 | from yamcs.kerberos import KerberosCredentials 5 | 6 | if __name__ == "__main__": 7 | client = YamcsClient("localhost:8090", credentials=KerberosCredentials()) 8 | 9 | while True: 10 | print(client.get_time("simulator")) 11 | sleep(1) 12 | -------------------------------------------------------------------------------- /yamcs-client-kerberos/requirements.txt: -------------------------------------------------------------------------------- 1 | requests-kerberos 2 | yamcs-client 3 | -------------------------------------------------------------------------------- /yamcs-client-kerberos/setup.py: -------------------------------------------------------------------------------- 1 | import io 2 | 3 | import setuptools 4 | 5 | with io.open("README.md", encoding="utf-8") as f: 6 | readme = f.read() 7 | 8 | setuptools.setup( 9 | name="yamcs-client-kerberos", 10 | version="1.3.0", 11 | description="Kerberos integration for Yamcs API client library", 12 | long_description=readme, 13 | long_description_content_type="text/markdown", 14 | url="https://github.com/yamcs/python-yamcs-client/yamcs-client-kerberos", 15 | author="Space Applications Services", 16 | author_email="yamcs@spaceapplications.com", 17 | license="LGPL", 18 | packages=setuptools.find_namespace_packages(where="src"), 19 | package_dir={"": "src"}, 20 | python_requires=">=3.8", 21 | classifiers=[ 22 | "Development Status :: 5 - Production/Stable", 23 | "Intended Audience :: Developers", 24 | "License :: OSI Approved :: GNU Lesser General Public License v3 (LGPLv3)", 25 | "Programming Language :: Python", 26 | "Programming Language :: Python :: 3", 27 | "Programming Language :: Python :: 3.8", 28 | "Programming Language :: Python :: 3.9", 29 | "Programming Language :: Python :: 3.10", 30 | "Programming Language :: Python :: 3.11", 31 | "Programming Language :: Python :: 3.12", 32 | "Programming Language :: Python :: 3.13", 33 | "Operating System :: OS Independent", 34 | ], 35 | platforms="Posix; MacOS X; Windows", 36 | install_requires=["requests-kerberos", "yamcs-client>=1.11.0"], 37 | include_package_data=True, 38 | zip_safe=False, 39 | ) 40 | -------------------------------------------------------------------------------- /yamcs-client-kerberos/src/yamcs/kerberos.py: -------------------------------------------------------------------------------- 1 | from datetime import datetime, timedelta, timezone 2 | 3 | try: 4 | from requests_kerberos import DISABLED, HTTPKerberosAuth 5 | except ImportError: 6 | # To be removed eventually 7 | from requests_gssapi import HTTPSPNEGOAuth 8 | 9 | from yamcs.client import Credentials, Unauthorized, YamcsError, do_get, do_post 10 | 11 | 12 | class KerberosCredentials(Credentials): 13 | def __init__(self, access_token=None, expiry=None): 14 | super().__init__(access_token=access_token, expiry=expiry) 15 | 16 | def login(self, session, auth_url, on_token_update): 17 | self._on_token_update = on_token_update 18 | code = self.fetch_authorization_code(session, auth_url) 19 | creds = self.convert_authorization_code(session, auth_url, code) 20 | 21 | if on_token_update: 22 | on_token_update(creds) 23 | return creds 24 | 25 | def refresh(self, session, auth_url): 26 | code = self.fetch_authorization_code(session, auth_url) 27 | new_creds = self.convert_authorization_code(session, auth_url, code) 28 | 29 | self.access_token = new_creds.access_token 30 | self.refresh_token = new_creds.refresh_token 31 | self.expiry = new_creds.expiry 32 | if self._on_token_update: 33 | self._on_token_update(self) 34 | 35 | def fetch_authorization_code(self, session, auth_url): 36 | try: 37 | auth = HTTPKerberosAuth( 38 | mutual_authentication=DISABLED, force_preemptive=True 39 | ) 40 | except NameError: 41 | auth = HTTPSPNEGOAuth(opportunistic_auth=True) 42 | 43 | response = do_get(session, auth_url + "/spnego", auth=auth) 44 | if response.status_code == 401: 45 | raise Unauthorized("401 Client Error: Unauthorized") 46 | elif response.status_code == 200: 47 | return response.text 48 | else: 49 | raise YamcsError(f"{response.status_code} Server Error") 50 | 51 | def convert_authorization_code(self, session, auth_url, code): 52 | data = {"grant_type": "authorization_code", "code": code} 53 | response = do_post(session, auth_url + "/token", data=data) 54 | if response.status_code == 401: 55 | raise Unauthorized("401 Client Error: Unauthorized") 56 | elif response.status_code == 200: 57 | d = response.json() 58 | expiry = datetime.now(tz=timezone.utc) + timedelta(seconds=d["expires_in"]) 59 | return KerberosCredentials( 60 | access_token=d["access_token"], 61 | expiry=expiry, 62 | ) 63 | else: 64 | raise YamcsError(f"{response.status_code} Server Error") 65 | -------------------------------------------------------------------------------- /yamcs-client/.flake8: -------------------------------------------------------------------------------- 1 | [flake8] 2 | max-line-length = 88 3 | extend-ignore = E203 4 | -------------------------------------------------------------------------------- /yamcs-client/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Development Setup 2 | 3 | Install `yamcs-client` from a source directory: 4 | 5 | pip install -e . 6 | 7 | Changes to any source file have immediate impact. 8 | 9 | # Release Procedure 10 | 11 | ## Dependencies 12 | 13 | pip install wheel twine 14 | 15 | ## Build Release 16 | 17 | Build source and binary wheel to `dist/`: 18 | 19 | rm -rf dist/ 20 | make clean build 21 | 22 | ## Publish to PyPI 23 | 24 | Upload to test PyPI (assumes a repository testpypi in `~/.pypirc`): 25 | 26 | twine upload -r testpypi dist/* 27 | 28 | Upload to PyPI (assumes a repository pypi in `~/.pypirc`): 29 | 30 | twine upload -r pypi dist/* 31 | 32 | Be careful as both testpypi and pypi do not allow to reupload files under any circumstances (even after delete). So when using testpypi multiple times you may need to play with the version number beyond the third digit. PEP 440 convention for beta releases is to use string like `1.0.0b1` 33 | 34 | 35 | -------------------------------------------------------------------------------- /yamcs-client/MANIFEST.in: -------------------------------------------------------------------------------- 1 | include LICENSE 2 | include README.md 3 | -------------------------------------------------------------------------------- /yamcs-client/Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: clean lint build deploy 2 | 3 | clean: 4 | rm -rf build dist *.egg-info 5 | 6 | lint: 7 | flake8 src --exclude '*pb2.py' --count --show-source --statistics 8 | 9 | build_legacy: lint 10 | python setup.py sdist bdist_wheel 11 | 12 | build: lint 13 | python -m build 14 | 15 | deploy: clean build 16 | twine upload -r pypi dist/* 17 | -------------------------------------------------------------------------------- /yamcs-client/README.md: -------------------------------------------------------------------------------- 1 | # Yamcs Client Library for Python 2 | [![PyPI](https://img.shields.io/pypi/v/yamcs-client.svg)](https://pypi.python.org/pypi/yamcs-client) 3 | [![PyPI pyversions](https://img.shields.io/pypi/pyversions/yamcs-client.svg)](https://pypi.python.org/pypi/yamcs-client/) 4 | 5 | 6 | ## Features 7 | 8 | * MDB retrieval 9 | * Telemetry updates 10 | * Command History updates 11 | * Alarm updates 12 | * Event updates 13 | * Archive retrieval 14 | * Histogram retrieval 15 | 16 | 17 | ## Installation 18 | 19 | Install with pip 20 | 21 | pip install yamcs-client 22 | 23 | 24 | ## License 25 | 26 | LGPL-3.0. See [LICENSE](https://github.com/yamcs/python-yamcs-client/blob/master/LICENSE) 27 | -------------------------------------------------------------------------------- /yamcs-client/examples/alarms.py: -------------------------------------------------------------------------------- 1 | from time import sleep 2 | 3 | from yamcs.client import YamcsClient 4 | 5 | 6 | def receive_callbacks(): 7 | """Registers an alarm callback.""" 8 | 9 | def callback(alarm_update): 10 | print("Alarm Update:", alarm_update) 11 | 12 | processor.create_alarm_subscription(callback) 13 | 14 | 15 | def acknowledge_all(): 16 | """Acknowledges all active alarms.""" 17 | for alarm in processor.list_alarms(): 18 | if not alarm.is_acknowledged: 19 | processor.acknowledge_alarm( 20 | alarm.name, 21 | alarm.sequence_number, 22 | comment="false alarm", 23 | ) 24 | 25 | 26 | if __name__ == "__main__": 27 | client = YamcsClient("localhost:8090") 28 | processor = client.get_processor(instance="simulator", processor="realtime") 29 | receive_callbacks() 30 | sleep(10) 31 | 32 | print("Acknowledging all...") 33 | acknowledge_all() 34 | 35 | # If a parameter remains out of limits, a new alarm instance is created 36 | # on the next value update. So you would keep receiving callbacks on 37 | # the subscription. 38 | 39 | # The subscription is non-blocking. Prevent the main 40 | # thread from exiting 41 | while True: 42 | sleep(10) 43 | -------------------------------------------------------------------------------- /yamcs-client/examples/archive_breakdown.py: -------------------------------------------------------------------------------- 1 | from yamcs.client import YamcsClient 2 | 3 | 4 | def print_packet_count(): 5 | """Print the number of packets grouped by packet name.""" 6 | for name in archive.list_packet_names(): 7 | packet_count = 0 8 | for group in archive.list_packet_histogram(name): 9 | for rec in group.records: 10 | packet_count += rec.count 11 | print(f" {name: <40} {packet_count: >20}") 12 | 13 | 14 | def print_pp_groups(): 15 | """Print the number of processed parameter frames by group name.""" 16 | for group in archive.list_processed_parameter_groups(): 17 | frame_count = 0 18 | for pp_group in archive.list_processed_parameter_group_histogram(group): 19 | for rec in pp_group.records: 20 | frame_count += rec.count 21 | print(f" {group: <40} {frame_count: >20}") 22 | 23 | 24 | def print_event_count(): 25 | """Print the number of events grouped by source.""" 26 | for source in archive.list_event_sources(): 27 | event_count = 0 28 | for group in archive.list_event_histogram(source): 29 | for rec in group.records: 30 | event_count += rec.count 31 | print(f" {source: <40} {event_count: >20}") 32 | 33 | 34 | def print_command_count(): 35 | """Print the number of commands grouped by name.""" 36 | mdb = client.get_mdb(instance="simulator") 37 | for command in mdb.list_commands(): 38 | total = 0 39 | for group in archive.list_command_histogram(command.qualified_name): 40 | for rec in group.records: 41 | total += rec.count 42 | print(f" {command.qualified_name: <40} {total: >20}") 43 | 44 | 45 | if __name__ == "__main__": 46 | client = YamcsClient("localhost:8090") 47 | archive = client.get_archive(instance="simulator") 48 | 49 | print("Packets:") 50 | print_packet_count() 51 | 52 | print("\nProcessed Parameter Groups:") 53 | print_pp_groups() 54 | 55 | print("\nEvents:") 56 | print_event_count() 57 | 58 | print("\nCommands:") 59 | print_command_count() 60 | -------------------------------------------------------------------------------- /yamcs-client/examples/archive_retrieval.py: -------------------------------------------------------------------------------- 1 | from datetime import datetime, timedelta, timezone 2 | from itertools import islice 3 | 4 | from yamcs.client import YamcsClient 5 | 6 | 7 | def print_last_packets(): 8 | """Print the last 10 packets.""" 9 | for packet in islice(archive.list_packets(descending=True), 0, 10): 10 | print(packet) 11 | 12 | 13 | def print_packet_range(): 14 | """Print the range of archived packets.""" 15 | first_packet = next(iter(archive.list_packets())) 16 | last_packet = next(iter(archive.list_packets(descending=True))) 17 | print("First packet:", first_packet) 18 | print("Last packet:", last_packet) 19 | 20 | td = last_packet.generation_time - first_packet.generation_time 21 | print("Timespan:", td) 22 | 23 | 24 | def iterate_specific_packet_range(): 25 | """Count the number of packets in a specific range.""" 26 | now = datetime.now(tz=timezone.utc) 27 | start = now - timedelta(hours=1) 28 | 29 | total = 0 30 | for packet in archive.list_packets(start=start, stop=now): 31 | total += 1 32 | # print(packet) 33 | print("Found", total, "packets in range") 34 | 35 | 36 | def export_raw_packets(): 37 | """Export raw packet binary.""" 38 | now = datetime.now(tz=timezone.utc) 39 | start = now - timedelta(hours=1) 40 | 41 | with open("/tmp/dump.raw", "wb") as f: 42 | for chunk in archive.export_packets(start=start, stop=now): 43 | f.write(chunk) 44 | 45 | 46 | def iterate_specific_event_range(): 47 | """Count the number of events in a specific range.""" 48 | now = datetime.now(tz=timezone.utc) 49 | start = now - timedelta(hours=1) 50 | 51 | total = 0 52 | for event in archive.list_events(start=start, stop=now): 53 | total += 1 54 | # print(event) 55 | print("Found", total, "events in range") 56 | 57 | 58 | def print_last_values(): 59 | """Print the last 10 values.""" 60 | iterable = archive.list_parameter_values( 61 | "/YSS/SIMULATOR/BatteryVoltage1", descending=True 62 | ) 63 | for pval in islice(iterable, 0, 10): 64 | print(pval) 65 | 66 | 67 | def iterate_specific_parameter_range(): 68 | """Count the number of parameter values in a specific range.""" 69 | now = datetime.now(tz=timezone.utc) 70 | start = now - timedelta(hours=1) 71 | 72 | total = 0 73 | for pval in archive.list_parameter_values( 74 | "/YSS/SIMULATOR/BatteryVoltage1", start=start, stop=now 75 | ): 76 | total += 1 77 | # print(pval) 78 | print("Found", total, "parameter values in range") 79 | 80 | 81 | def stream_specific_parameter_range(): 82 | """Stream one or more parameters in a specific range.""" 83 | now = datetime.now(tz=timezone.utc) 84 | start = now - timedelta(hours=1) 85 | 86 | total = 0 87 | for pdata in archive.stream_parameter_values( 88 | ["/YSS/SIMULATOR/BatteryVoltage1", "/YSS/SIMULATOR/BatteryVoltage2"], 89 | start=start, 90 | stop=now, 91 | ): 92 | total += 1 93 | # print(pdata) 94 | print("Found", total, "updates in range") 95 | 96 | 97 | def print_last_commands(): 98 | """Print the last 10 commands.""" 99 | iterable = archive.list_command_history(descending=True) 100 | for entry in islice(iterable, 0, 10): 101 | print(entry) 102 | 103 | 104 | if __name__ == "__main__": 105 | client = YamcsClient("localhost:8090") 106 | archive = client.get_archive(instance="simulator") 107 | 108 | print("Last 10 packets:") 109 | print_last_packets() 110 | 111 | print("\nPacket range:") 112 | print_packet_range() 113 | 114 | print("\nIterate specific packet range:") 115 | iterate_specific_packet_range() 116 | 117 | print("\nIterate specific event range:") 118 | iterate_specific_event_range() 119 | 120 | print("\nLast 10 parameter values:") 121 | print_last_values() 122 | 123 | print("\nIterate specific parameter range:") 124 | iterate_specific_parameter_range() 125 | 126 | print("\nStream specific parameter range:") 127 | stream_specific_parameter_range() 128 | 129 | print("\nLast 10 commands:") 130 | print_last_commands() 131 | -------------------------------------------------------------------------------- /yamcs-client/examples/authenticate.py: -------------------------------------------------------------------------------- 1 | from time import sleep 2 | 3 | from yamcs.client import Credentials, YamcsClient 4 | 5 | # For this example to work, enable security in Yamcs by 6 | # configuring appropriate authentication modules. 7 | 8 | 9 | def authenticate_with_username_password(): 10 | """Authenticate by directly providing username/password to Yamcs.""" 11 | credentials = Credentials(username="admin", password="password") 12 | client = YamcsClient("localhost:8090", credentials=credentials) 13 | 14 | for link in client.list_links("simulator"): 15 | print(link) 16 | 17 | 18 | def authenticate_with_access_token(access_token): 19 | """Authenticate using an existing access token.""" 20 | credentials = Credentials(access_token=access_token) 21 | client = YamcsClient("localhost:8090", credentials=credentials) 22 | 23 | for link in client.list_links("simulator"): 24 | print(link) 25 | 26 | 27 | def impersonate_with_client_credentials(): 28 | credentials = Credentials( 29 | client_id="cf79cfbd-ed01-4ae2-93e1-c606a2ebc36f", 30 | client_secret="!#?hgbu1*3", 31 | become="admin", 32 | ) 33 | client = YamcsClient("localhost:8090", credentials=credentials) 34 | print("have", client.get_user_info().username) 35 | while True: 36 | print(client.get_time("simulator")) 37 | sleep(1) 38 | 39 | 40 | def authenticate_with_basic_auth(): 41 | """Authenticate by providing username/password on each request to Yamcs.""" 42 | from yamcs.client import BasicAuthCredentials 43 | 44 | credentials = BasicAuthCredentials(username="admin", password="password") 45 | client = YamcsClient("localhost:8090", credentials=credentials) 46 | 47 | for link in client.list_links("simulator"): 48 | print(link) 49 | 50 | 51 | if __name__ == "__main__": 52 | print("Authenticate with username/password") 53 | authenticate_with_username_password() 54 | 55 | print("\nImpersonate with client credentials") 56 | impersonate_with_client_credentials() 57 | -------------------------------------------------------------------------------- /yamcs-client/examples/ccsds_completeness.py: -------------------------------------------------------------------------------- 1 | from datetime import datetime, timedelta, timezone 2 | 3 | from yamcs.client import YamcsClient 4 | 5 | 6 | def print_latest(): 7 | """ 8 | Prints completeness records for the last two days 9 | """ 10 | now = datetime.now(tz=timezone.utc) 11 | start = now - timedelta(days=2) 12 | 13 | # Results are returned in records per 'group'. 14 | # A completeness group matches with a CCSDS APID. 15 | 16 | # We may receive multiple groups with the same APID 17 | # depending on how much data there is for the selected 18 | # range. 19 | 20 | # Combine all returned pages by APID 21 | records_by_apid = {} 22 | for group in archive.list_completeness_index(start=start, stop=now): 23 | if group.name not in records_by_apid: 24 | records_by_apid[group.name] = [] 25 | records_by_apid[group.name].extend(group.records) 26 | 27 | for apid, records in records_by_apid.items(): 28 | print("APID:", apid) 29 | 30 | total = 0 31 | for rec in records: 32 | print(" -", rec) 33 | total += rec.count 34 | print(f" --> Total packets for {apid}: {total}") 35 | 36 | 37 | if __name__ == "__main__": 38 | client = YamcsClient("localhost:8090") 39 | archive = client.get_archive(instance="simulator") 40 | print_latest() 41 | -------------------------------------------------------------------------------- /yamcs-client/examples/change_alarms.py: -------------------------------------------------------------------------------- 1 | from time import sleep 2 | 3 | from yamcs.client import YamcsClient 4 | 5 | 6 | def subscribe_param(): 7 | """Print value of parameter""" 8 | 9 | def print_data(data): 10 | for parameter in data.parameters: 11 | print(parameter) 12 | 13 | processor.create_parameter_subscription( 14 | "/YSS/SIMULATOR/BatteryVoltage2", on_data=print_data 15 | ) 16 | 17 | 18 | def set_alarms(): 19 | """Set the default (i.e. non-contextual) limits for the parameter.""" 20 | processor.set_default_alarm_ranges( 21 | "/YSS/SIMULATOR/BatteryVoltage2", watch=(-10, 10), critical=(-100, None) 22 | ) 23 | 24 | 25 | def clear_alarm_ranges(): 26 | """ 27 | Clear (remove) all limits for the parameter. Note that if the is an alarm 28 | being triggered, it is not automatically acknowledged. 29 | """ 30 | processor.clear_alarm_ranges("/YSS/SIMULATOR/BatteryVoltage2") 31 | 32 | 33 | def reset_alarms(): 34 | """Reset the alarm limits for the parameter to the original MDB value.""" 35 | processor.reset_alarm_ranges("/YSS/SIMULATOR/BatteryVoltage2") 36 | 37 | 38 | if __name__ == "__main__": 39 | client = YamcsClient("localhost:8090") 40 | processor = client.get_processor(instance="simulator", processor="realtime") 41 | 42 | subscribe_param() 43 | sleep(5) 44 | 45 | print("Set alarms") 46 | set_alarms() 47 | sleep(10) 48 | 49 | print("Clear(remove) all alarms") 50 | clear_alarm_ranges() 51 | sleep(10) 52 | 53 | print("reset alarms to their MDB value") 54 | reset_alarms() 55 | sleep(10) 56 | -------------------------------------------------------------------------------- /yamcs-client/examples/change_algorithm.py: -------------------------------------------------------------------------------- 1 | from time import sleep 2 | 3 | from yamcs.client import YamcsClient 4 | 5 | 6 | def subscribe_param(): 7 | """Print value of parameter""" 8 | 9 | def print_data(data): 10 | for parameter in data.parameters: 11 | print(parameter) 12 | 13 | processor.create_parameter_subscription( 14 | "/YSS/SIMULATOR/battery_voltage_avg", on_data=print_data 15 | ) 16 | 17 | 18 | def set_algorithm(): 19 | processor.set_algorithm( 20 | "/YSS/SIMULATOR/Battery_Voltage_Avg", 21 | text="r.value = 10*(b1.value + b2.value+b3.value)", 22 | ) 23 | 24 | 25 | def reset_algorithm(): 26 | processor.reset_algorithm("/YSS/SIMULATOR/Battery_Voltage_Avg") 27 | 28 | 29 | if __name__ == "__main__": 30 | client = YamcsClient("localhost:8090") 31 | processor = client.get_processor(instance="simulator", processor="realtime") 32 | 33 | subscribe_param() 34 | sleep(5) 35 | print("Set new algo") 36 | set_algorithm() 37 | sleep(10) 38 | print("reset algo to the MDB definition") 39 | reset_algorithm() 40 | sleep(10) 41 | -------------------------------------------------------------------------------- /yamcs-client/examples/change_calibration.py: -------------------------------------------------------------------------------- 1 | from time import sleep 2 | 3 | from yamcs.client import YamcsClient 4 | 5 | 6 | def subscribe_param(): 7 | """Print value of parameter""" 8 | 9 | def print_data(data): 10 | for parameter in data.parameters: 11 | print(parameter) 12 | 13 | processor.create_parameter_subscription( 14 | "/YSS/SIMULATOR/BatteryVoltage2", on_data=print_data 15 | ) 16 | 17 | 18 | def set_calibrator(): 19 | """Set the calibrator to a constant polynomial.""" 20 | processor.set_default_calibrator( 21 | "/YSS/SIMULATOR/BatteryVoltage2", "polynomial", [1, 0.1] 22 | ) 23 | 24 | 25 | def reset_calibrator(): 26 | """Reset the calibrator to the original MDB value.""" 27 | processor.reset_calibrators("/YSS/SIMULATOR/BatteryVoltage2") 28 | 29 | 30 | def clear_calibrator(): 31 | """Clear(remove) the calibrator.""" 32 | processor.clear_calibrators("/YSS/SIMULATOR/BatteryVoltage2") 33 | 34 | 35 | if __name__ == "__main__": 36 | client = YamcsClient("localhost:8090") 37 | processor = client.get_processor(instance="simulator", processor="realtime") 38 | 39 | subscribe_param() 40 | sleep(5) 41 | print("Set calibrator") 42 | set_calibrator() 43 | sleep(10) 44 | print("Remove calibrator") 45 | clear_calibrator() 46 | sleep(10) 47 | print("reset calibrator to original MDB value") 48 | reset_calibrator() 49 | sleep(10) 50 | -------------------------------------------------------------------------------- /yamcs-client/examples/command_bench.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | from yamcs.client import YamcsClient 4 | 5 | if __name__ == "__main__": 6 | client = YamcsClient("localhost:8090") 7 | processor = client.get_processor("simulator", "realtime") 8 | 9 | conn = processor.create_command_connection() 10 | 11 | while True: 12 | command = conn.issue( 13 | "/YSS/SIMULATOR/SWITCH_VOLTAGE_OFF", args={"voltage_num": 1} 14 | ) 15 | 16 | sys.stdout.write(command.id) 17 | sys.stdout.write(" ... ") 18 | sys.stdout.flush() 19 | 20 | ack = command.await_acknowledgment("Acknowledge_Queued") 21 | sys.stdout.write(str(ack)) 22 | sys.stdout.write(" ... ") 23 | sys.stdout.flush() 24 | 25 | if ack.status == "OK": 26 | ack = command.await_acknowledgment("Acknowledge_Sent") 27 | sys.stdout.write(str(ack)) 28 | sys.stdout.write(" ... ") 29 | sys.stdout.flush() 30 | 31 | command.await_complete() 32 | sys.stdout.write("complete\n") 33 | sys.stdout.flush() 34 | -------------------------------------------------------------------------------- /yamcs-client/examples/command_history.py: -------------------------------------------------------------------------------- 1 | from time import sleep 2 | 3 | from yamcs.client import YamcsClient 4 | 5 | # This demonstrates how to use a single command history subscription to 6 | # follow the acknowledgments of multiple commands. 7 | 8 | if __name__ == "__main__": 9 | client = YamcsClient("localhost:8090") 10 | processor = client.get_processor("simulator", "realtime") 11 | 12 | # Start to listen to command history 13 | history_subscription = processor.create_command_history_subscription() 14 | 15 | commands = [] 16 | 17 | # Submit a few commands 18 | for i in range(5): 19 | command = processor.issue_command( 20 | "/YSS/SIMULATOR/SWITCH_VOLTAGE_OFF", args={"voltage_num": 1} 21 | ) 22 | commands.append(command) 23 | print("Issued", command) 24 | 25 | command = processor.issue_command( 26 | "/YSS/SIMULATOR/SWITCH_VOLTAGE_ON", args={"voltage_num": 1} 27 | ) 28 | commands.append(command) 29 | print("Issued", command) 30 | 31 | while True: 32 | print("------") 33 | for command in commands: 34 | cmdhistory = history_subscription.get_command_history(command) 35 | print(cmdhistory) 36 | sleep(5) 37 | -------------------------------------------------------------------------------- /yamcs-client/examples/commanding.py: -------------------------------------------------------------------------------- 1 | from time import sleep 2 | 3 | from yamcs.client import VerificationConfig, YamcsClient 4 | 5 | 6 | def issue_command(): 7 | """Issue a command to turn battery 1 off.""" 8 | command = processor.issue_command( 9 | "/YSS/SIMULATOR/SWITCH_VOLTAGE_OFF", args={"voltage_num": 1} 10 | ) 11 | print("Issued", command) 12 | 13 | 14 | def issue_command_modify_verification(): 15 | """Issue a command with changed verification.""" 16 | verification = VerificationConfig() 17 | verification.disable("Started") 18 | verification.modify_check_window("Queued", 1, 5) 19 | 20 | command = processor.issue_command( 21 | "/YSS/SIMULATOR/SWITCH_VOLTAGE_OFF", 22 | args={"voltage_num": 1}, 23 | verification=verification, 24 | ) 25 | 26 | print("Issued", command) 27 | 28 | 29 | def issue_command_no_verification(): 30 | """Issue a command with no verification.""" 31 | verification = VerificationConfig() 32 | verification.disable() 33 | 34 | command = processor.issue_command( 35 | "/YSS/SIMULATOR/SWITCH_VOLTAGE_OFF", 36 | args={"voltage_num": 1}, 37 | verification=verification, 38 | ) 39 | 40 | print("Issued", command) 41 | 42 | 43 | def monitor_command(): 44 | """Monitor command completion.""" 45 | conn = processor.create_command_connection() 46 | 47 | command1 = conn.issue("/YSS/SIMULATOR/SWITCH_VOLTAGE_OFF", args={"voltage_num": 1}) 48 | 49 | # Issue 2nd command only if the previous command was completed successfully. 50 | command1.await_complete() 51 | if command1.is_success(): 52 | conn.issue("/YSS/SIMULATOR/SWITCH_VOLTAGE_ON", args={"voltage_num": 1}) 53 | else: 54 | print("Command 1 failed:", command1.error) 55 | 56 | 57 | def monitor_acknowledgment(): 58 | """Monitor command acknowledgment.""" 59 | conn = processor.create_command_connection() 60 | 61 | command = conn.issue("/YSS/SIMULATOR/SWITCH_VOLTAGE_OFF", args={"voltage_num": 1}) 62 | 63 | ack = command.await_acknowledgment("Acknowledge_Sent") 64 | print(ack.status) 65 | 66 | 67 | def listen_to_command_history(): 68 | """Receive updates on command history updates.""" 69 | 70 | def tc_callback(rec): 71 | print("TC:", rec) 72 | 73 | processor.create_command_history_subscription(on_data=tc_callback) 74 | 75 | 76 | def tm_callback(delivery): 77 | for parameter in delivery.parameters: 78 | print("TM:", parameter) 79 | 80 | 81 | if __name__ == "__main__": 82 | client = YamcsClient("localhost:8090") 83 | processor = client.get_processor("simulator", "realtime") 84 | 85 | print("Start to listen to command history") 86 | listen_to_command_history() 87 | 88 | issue_command_no_verification() 89 | issue_command_modify_verification() 90 | 91 | print("Issue a command") 92 | issue_command() 93 | 94 | # Monitor the voltage parameter to confirm that it is 0 95 | subscription = processor.create_parameter_subscription( 96 | ["/YSS/SIMULATOR/BatteryVoltage1"], on_data=tm_callback 97 | ) 98 | 99 | # Subscription is non-blocking 100 | sleep(20) 101 | -------------------------------------------------------------------------------- /yamcs-client/examples/cop1.py: -------------------------------------------------------------------------------- 1 | from time import sleep 2 | 3 | from yamcs.client import YamcsClient 4 | 5 | 6 | def callback(status): 7 | print(" status:", status) 8 | 9 | 10 | if __name__ == "__main__": 11 | client = YamcsClient("localhost:8090") 12 | link = client.get_link("simulator", link="UDP_FRAME_OUT.vc0") 13 | 14 | config = link.get_cop1_config() 15 | print(config) 16 | 17 | print("Changing COP1 configuration") 18 | link.update_cop1_config(t1=3.1, tx_limit=4) 19 | 20 | monitor = link.create_cop1_subscription(on_data=callback) 21 | print("COP1 status subscribed.") 22 | 23 | sleep(5) 24 | 25 | print("Disabling COP1....") 26 | link.disable_cop1() 27 | 28 | sleep(3) 29 | print("Initializing COP1 with CLCW_CHECK") 30 | print(" (if no CLCW is received, COP1 will be suspended in 3 seconds)") 31 | link.initialize_cop1("WITH_CLCW_CHECK", clcw_wait_timeout=3) 32 | 33 | sleep(5) 34 | 35 | if monitor.state == "SUSPENDED": 36 | print("Resuming COP1") 37 | link.resume_cop1() 38 | 39 | sleep(3) 40 | 41 | print("Disabling COP1....") 42 | link.disable_cop1() 43 | 44 | sleep(3) 45 | 46 | print("Initializing COP1 with set v(R)=200") 47 | print(" (if no CLCW is received, COP1 will be suspended in 3 seconds)") 48 | link.initialize_cop1("SET_VR", v_r=200) 49 | 50 | sleep(2) 51 | -------------------------------------------------------------------------------- /yamcs-client/examples/create_instance.py: -------------------------------------------------------------------------------- 1 | from yamcs.client import YamcsClient 2 | 3 | client = YamcsClient("localhost:8090") 4 | client.create_instance( 5 | "blub", template="abc", args={"port": "8888"}, labels={"foo": "bar", "bar": "baz"} 6 | ) 7 | -------------------------------------------------------------------------------- /yamcs-client/examples/events.py: -------------------------------------------------------------------------------- 1 | from time import sleep 2 | 3 | from yamcs.client import YamcsClient 4 | 5 | 6 | def listen_to_event_updates(): 7 | """Subscribe to events.""" 8 | 9 | def callback(event): 10 | print("Event:", event) 11 | 12 | client.create_event_subscription(instance="simulator", on_data=callback) 13 | 14 | sleep(5) # Subscription is non-blocking 15 | 16 | 17 | def send_event(): 18 | """Post an event.""" 19 | client.send_event(instance="simulator", message="hello world") 20 | 21 | 22 | if __name__ == "__main__": 23 | client = YamcsClient("localhost:8090") 24 | listen_to_event_updates() 25 | 26 | print("Sending an event:") 27 | send_event() 28 | 29 | sleep(5) 30 | -------------------------------------------------------------------------------- /yamcs-client/examples/file_transfer.py: -------------------------------------------------------------------------------- 1 | import io 2 | import time 3 | 4 | from yamcs.client import YamcsClient 5 | 6 | 7 | def upload_file(): 8 | """Snippet used in docs to initiate upload.""" 9 | # Transfer myfile from bucket to spacecraft 10 | upload = service.upload(out_bucket.name, "myfile", "/CF:/mytarget") 11 | upload.await_complete(timeout=10) 12 | 13 | if not upload.is_success(): 14 | print("Upload failure:", upload.error) 15 | else: 16 | print(f"Successfully uploaded {upload.remote_path} ({upload.size} bytes)") 17 | 18 | 19 | def upload_file_extra(): 20 | """Snippet used in docs to initiate upload with extra parameters.""" 21 | # Transfer myfile, but use an alternative destination entity 22 | upload = service.upload( 23 | out_bucket.name, "myfile", "/CF:/mytarget", destination_entity="target2" 24 | ) 25 | upload.await_complete(timeout=10) 26 | 27 | if not upload.is_success(): 28 | print("Upload failure:", upload.error) 29 | else: 30 | print(f"Successfully uploaded {upload.remote_path} ({upload.size} bytes)") 31 | 32 | 33 | def upload_file_options(): 34 | """Snippet used in docs to initiate upload with extra options.""" 35 | upload = service.upload( 36 | out_bucket.name, "myfile", "/CF:/mytarget", options={"reliable": True} 37 | ) 38 | upload.await_complete(timeout=60) 39 | 40 | if not upload.is_success(): 41 | print("Upload failure:", upload.error) 42 | else: 43 | print(f"Successfully uploaded {upload.remote_path} ({upload.size} bytes)") 44 | 45 | 46 | def download_file(): 47 | """Snippet used in docs to initiate download.""" 48 | # Download todownload from the remote 49 | download = service.download(in_bucket.name, "todownload") 50 | download.await_complete(timeout=10) 51 | 52 | if not download.is_success(): 53 | print("Download failure:", download.error) 54 | else: 55 | print(f"Successfully downloaded {download.remote_path} ({download.size} bytes)") 56 | 57 | 58 | def subscribe_filelist(): 59 | """Snippet used in docs to subscribe to filelist updates.""" 60 | subscription = service.create_filelist_subscription(on_data=filelist_callback) 61 | return subscription 62 | 63 | 64 | def filelist_callback(filelist): 65 | global updated 66 | updated = True 67 | print(f"Filelist updated with {len(filelist.files)} files or directories") 68 | 69 | 70 | def fetch_filelist(): 71 | """Snippet used in docs to fetch a remote filelist.""" 72 | filelist_request = service.fetch_filelist("/") 73 | return filelist_request 74 | 75 | 76 | def get_filelist(): 77 | """Snippet used in docs to get a saved filelist and display it.""" 78 | filelist = service.get_filelist("/") 79 | 80 | # Display file list 81 | if filelist: 82 | print("File list received:") 83 | if not filelist.files: 84 | print("\tEmpty file list") 85 | for file in filelist.files: 86 | print( 87 | f"\t{file.name + ('/' if file.is_directory else ''):<12}\ 88 | t{str(file.size) + ' bytes':>12}\tLast Modified: {file.modified}" 89 | ) 90 | else: 91 | print("No filelist found") 92 | 93 | 94 | if __name__ == "__main__": 95 | client = YamcsClient("localhost:8090") 96 | storage = client.get_storage_client() 97 | cfdp = client.get_file_transfer_client(instance="cfdp") 98 | 99 | # Use pre-existing buckets, one for each direction 100 | out_bucket = storage.get_bucket("cfdpUp") 101 | in_bucket = storage.get_bucket("cfdpDown") 102 | 103 | # Prepare a sample file 104 | file_like = io.StringIO("Sample file content") 105 | out_bucket.upload_object("myfile", file_like) 106 | 107 | # Assume only one CFDP service 108 | service = next(iter(cfdp.list_services())) 109 | 110 | # Show transfer service capabilities 111 | print(service.capabilities) 112 | 113 | # Show possible transfer options 114 | for option in service.transfer_options: 115 | print(option) 116 | 117 | if service.capabilities.upload: 118 | upload_file() 119 | 120 | upload_file_extra() 121 | 122 | upload_file_options() 123 | 124 | if service.capabilities.download: 125 | download_file() 126 | 127 | # DIRECTORY LISTING 128 | if service.capabilities.filelist: 129 | updated = False 130 | 131 | subscribe_filelist() 132 | 133 | fetch_filelist() 134 | 135 | start = time.time() 136 | while not updated and time.time() - start < 20: 137 | time.sleep(0.1) 138 | 139 | # The saved filelist can either be retrieved from the subscription callback or 140 | # via the get_filelist function 141 | get_filelist() 142 | -------------------------------------------------------------------------------- /yamcs-client/examples/links.py: -------------------------------------------------------------------------------- 1 | from time import sleep 2 | 3 | from yamcs.client import YamcsClient 4 | 5 | 6 | def enable_link(link): 7 | """Enable a link.""" 8 | link.enable_link() 9 | 10 | 11 | def run_action(link, action_id, message=None): 12 | """Run an action.""" 13 | link.run_action(action_id, message) 14 | 15 | 16 | if __name__ == "__main__": 17 | client = YamcsClient("localhost:8090") 18 | link = client.get_link("simulator", link="tm_dump") 19 | 20 | print("Enabling link") 21 | enable_link(link) 22 | 23 | subscription = client.create_link_subscription("simulator") 24 | 25 | sleep(10) 26 | 27 | print("-----") 28 | # Retrieve the latest data link state from local cache: 29 | print("Last values from cache:") 30 | for link in subscription.list_links(): 31 | print(link) 32 | -------------------------------------------------------------------------------- /yamcs-client/examples/mission_time.py: -------------------------------------------------------------------------------- 1 | from time import sleep 2 | 3 | from yamcs.client import YamcsClient 4 | 5 | 6 | def callback(dt): 7 | print("Mission time:", dt) 8 | 9 | 10 | if __name__ == "__main__": 11 | client = YamcsClient("localhost:8090") 12 | subscription = client.create_time_subscription("simulator", callback) 13 | 14 | sleep(6) 15 | 16 | print("-----") 17 | # You don't have to use the on_data callback. You could also 18 | # directly retrieve the latest state from a local cache: 19 | print("Last time from cache:", subscription.time) 20 | 21 | # But then maybe you don't need a subscription, so do simply: 22 | time = client.get_time("simulator") 23 | print("Mission time (fresh from server)", time) 24 | -------------------------------------------------------------------------------- /yamcs-client/examples/modify_dump.py: -------------------------------------------------------------------------------- 1 | import struct 2 | 3 | from google.protobuf.internal.encoder import _VarintBytes 4 | from yamcs.client import split_protobuf_stream 5 | from yamcs.protobuf.table import table_pb2 6 | 7 | """ 8 | This script provides some hints as to how one might modify a 9 | raw table dump, for example to manually apply data migrations 10 | between a dump and restore. 11 | 12 | This is a rare use case. The decode/encode logic is not easy 13 | to come up with, so we keep it around for reference. 14 | """ 15 | 16 | 17 | def read_in_chunks(file_object, chunk_size=1024): 18 | while True: 19 | data = file_object.read(chunk_size) 20 | if not data: 21 | break 22 | yield data 23 | 24 | 25 | def read_rows(file_object): 26 | chunk_generator = read_in_chunks(file_object) 27 | for message in split_protobuf_stream(chunk_generator, table_pb2.Row): 28 | yield message 29 | 30 | 31 | def replace_cell_data(data, search, replacement): 32 | utf_like = data.decode("utf-8") 33 | return utf_like.replace(search, replacement).encode("utf-8") 34 | 35 | 36 | def mutf8_decode(data): 37 | # Just cut off the leading short 38 | return str(data[2:], "utf-8") 39 | 40 | 41 | def mutf8_encode(string_value): 42 | utf8 = string_value.encode("utf-8") 43 | length = len(utf8) 44 | data = struct.pack("!H", length) 45 | format = "!" + str(length) + "s" 46 | return data + struct.pack(format, utf8) 47 | 48 | 49 | if __name__ == "__main__": 50 | 51 | with open("cmdhist.dump", "rb") as f: 52 | with open("cmdhist_modified.dump", "wb") as fout: 53 | columns = {} 54 | for row in read_rows(f): 55 | # Column mapping only set on first row 56 | for col in row.columns: 57 | columns[col.id] = col.name 58 | 59 | for cell in row.cells: 60 | if columns[cell.columnId] == "Acknowledge_C_Status": 61 | if "ACK C: OK" == mutf8_decode(cell.data): 62 | cell.data = mutf8_encode("OK") 63 | 64 | fout.write(_VarintBytes(row.ByteSize())) 65 | fout.write(row.SerializeToString()) 66 | -------------------------------------------------------------------------------- /yamcs-client/examples/multiple_commands.py: -------------------------------------------------------------------------------- 1 | from time import sleep 2 | 3 | from yamcs.client import YamcsClient 4 | 5 | # This demonstrates how to use a "command connection" for monitoring the 6 | # lifecycle of multiple commands. 7 | 8 | if __name__ == "__main__": 9 | client = YamcsClient("localhost:8090") 10 | processor = client.get_processor("simulator", "realtime") 11 | 12 | # Start to listen to command history 13 | conn = processor.create_command_connection() 14 | 15 | commands = [] 16 | 17 | # Submit a few commands 18 | for i in range(5): 19 | command = conn.issue( 20 | "/YSS/SIMULATOR/SWITCH_VOLTAGE_OFF", args={"voltage_num": 1} 21 | ) 22 | commands.append(command) 23 | print("Issued", command) 24 | 25 | command = conn.issue( 26 | "/YSS/SIMULATOR/SWITCH_VOLTAGE_ON", args={"voltage_num": 1} 27 | ) 28 | commands.append(command) 29 | print("Issued", command) 30 | 31 | while True: 32 | print("------") 33 | for command in commands: 34 | print(command) 35 | sleep(5) 36 | -------------------------------------------------------------------------------- /yamcs-client/examples/object_storage.py: -------------------------------------------------------------------------------- 1 | from yamcs.client import YamcsClient 2 | 3 | 4 | def print_buckets(): 5 | for bucket in storage_client.list_buckets(): 6 | print(f" {bucket} ({bucket.object_count} objects, {bucket.size} bytes)") 7 | listing = bucket.list_objects() 8 | print(" prefixes:", listing.prefixes) 9 | for obj in listing.objects: 10 | print(" object:", obj) 11 | 12 | 13 | if __name__ == "__main__": 14 | client = YamcsClient("localhost:8090") 15 | storage_client = client.get_storage_client() 16 | 17 | print("Buckets:") 18 | print_buckets() 19 | -------------------------------------------------------------------------------- /yamcs-client/examples/packet_subscription.py: -------------------------------------------------------------------------------- 1 | from binascii import hexlify 2 | from time import sleep 3 | 4 | from yamcs.client import YamcsClient 5 | 6 | 7 | def receive_callbacks(): 8 | """Shows how to receive callbacks on packet updates.""" 9 | 10 | def print_data(packet): 11 | hexpacket = hexlify(packet.binary).decode("ascii") 12 | print(packet.generation_time, ":", hexpacket) 13 | 14 | processor.create_container_subscription( 15 | containers=["/YSS/SIMULATOR/FlightData", "/YSS/SIMULATOR/Power"], 16 | on_data=print_data, 17 | ) 18 | 19 | 20 | if __name__ == "__main__": 21 | client = YamcsClient("localhost:8090") 22 | processor = client.get_processor("simulator", "realtime") 23 | 24 | print("\nReceive callbacks") 25 | receive_callbacks() 26 | 27 | sleep(5) # Subscription is non-blocking 28 | -------------------------------------------------------------------------------- /yamcs-client/examples/parameter_subscription.py: -------------------------------------------------------------------------------- 1 | from time import sleep 2 | 3 | from yamcs.client import YamcsClient 4 | 5 | 6 | def poll_values(): 7 | """Shows how to poll values from the subscription.""" 8 | subscription = processor.create_parameter_subscription( 9 | ["/YSS/SIMULATOR/BatteryVoltage1"] 10 | ) 11 | 12 | sleep(5) 13 | print("Latest value:") 14 | print(subscription.get_value("/YSS/SIMULATOR/BatteryVoltage1")) 15 | 16 | sleep(5) 17 | print("Latest value:") 18 | print(subscription.get_value("/YSS/SIMULATOR/BatteryVoltage1")) 19 | 20 | 21 | def receive_callbacks(): 22 | """Shows how to receive callbacks on value updates.""" 23 | 24 | def print_data(data): 25 | for parameter in data.parameters: 26 | print(parameter) 27 | 28 | processor.create_parameter_subscription( 29 | "/YSS/SIMULATOR/BatteryVoltage1", on_data=print_data 30 | ) 31 | sleep(5) # Subscription is non-blocking 32 | 33 | 34 | def manage_subscription(): 35 | """Shows how to interact with a parameter subscription.""" 36 | subscription = processor.create_parameter_subscription( 37 | ["/YSS/SIMULATOR/BatteryVoltage1"] 38 | ) 39 | 40 | sleep(5) 41 | 42 | print("Adding extra items to the existing subscription...") 43 | subscription.add( 44 | [ 45 | "/YSS/SIMULATOR/Alpha", 46 | "/YSS/SIMULATOR/BatteryVoltage2", 47 | "MDB:OPS Name/SIMULATOR_PrimBusVoltage1", 48 | ] 49 | ) 50 | 51 | sleep(5) 52 | 53 | print("Shrinking subscription...") 54 | subscription.remove("/YSS/SIMULATOR/Alpha") 55 | 56 | print("Cancelling the subscription...") 57 | subscription.cancel() 58 | 59 | print("Last values from cache:") 60 | print(subscription.get_value("/YSS/SIMULATOR/BatteryVoltage1")) 61 | print(subscription.get_value("/YSS/SIMULATOR/BatteryVoltage2")) 62 | print(subscription.get_value("/YSS/SIMULATOR/Alpha")) 63 | print(subscription.get_value("MDB:OPS Name/SIMULATOR_PrimBusVoltage1")) 64 | 65 | 66 | if __name__ == "__main__": 67 | client = YamcsClient("localhost:8090") 68 | processor = client.get_processor("simulator", "realtime") 69 | 70 | print("Poll value cache") 71 | poll_values() 72 | 73 | print("\nReceive callbacks") 74 | receive_callbacks() 75 | 76 | print("\nModify the subscription") 77 | manage_subscription() 78 | -------------------------------------------------------------------------------- /yamcs-client/examples/plot_with_matplotlib.py: -------------------------------------------------------------------------------- 1 | from datetime import datetime, timedelta, timezone 2 | 3 | import matplotlib.pyplot as plt 4 | from yamcs.client import YamcsClient 5 | 6 | if __name__ == "__main__": 7 | client = YamcsClient("localhost:8090") 8 | archive = client.get_archive(instance="simulator") 9 | 10 | stop = datetime.now(tz=timezone.utc) 11 | start = stop - timedelta(hours=1) 12 | 13 | samples = archive.sample_parameter_values( 14 | "/YSS/SIMULATOR/Altitude", start=start, stop=stop 15 | ) 16 | x = [s.time for s in samples] 17 | y = [s.avg for s in samples] 18 | plt.subplot(2, 1, 1) 19 | plt.title("Sampled at " + str(stop)) 20 | plt.plot(x, y) 21 | plt.ylabel("Altitude") 22 | plt.grid() 23 | 24 | samples = archive.sample_parameter_values( 25 | "/YSS/SIMULATOR/SinkRate", start=start, stop=stop 26 | ) 27 | x = [s.time for s in samples] 28 | y = [s.avg for s in samples] 29 | plt.subplot(2, 1, 2) 30 | plt.plot(x, y) 31 | plt.xlabel("UTC") 32 | plt.ylabel("Sink Rate") 33 | plt.grid() 34 | 35 | plt.show() 36 | -------------------------------------------------------------------------------- /yamcs-client/examples/query_mdb.py: -------------------------------------------------------------------------------- 1 | from yamcs.client import YamcsClient 2 | 3 | 4 | def print_space_systems(): 5 | """Print all space systems.""" 6 | for space_system in mdb.list_space_systems(): 7 | print(space_system) 8 | 9 | 10 | def print_parameters(): 11 | """Print all float parameters.""" 12 | for parameter in mdb.list_parameters(parameter_type="float"): 13 | print(parameter) 14 | 15 | 16 | def print_commands(): 17 | """Print all commands.""" 18 | for command in mdb.list_commands(): 19 | print(command) 20 | 21 | 22 | def find_parameter(): 23 | """Find one parameter.""" 24 | p1 = mdb.get_parameter("/YSS/SIMULATOR/BatteryVoltage2") 25 | print("Via qualified name:", p1) 26 | 27 | p2 = mdb.get_parameter("MDB:OPS Name/SIMULATOR_BatteryVoltage2") 28 | print("Via domain-specific alias:", p2) 29 | 30 | 31 | if __name__ == "__main__": 32 | client = YamcsClient("localhost:8090") 33 | mdb = client.get_mdb(instance="simulator") 34 | 35 | print("\nSpace systems:") 36 | print_space_systems() 37 | 38 | print("\nParameters:") 39 | print_parameters() 40 | 41 | print("\nCommands:") 42 | print_commands() 43 | 44 | print("\nFind a specific parameter using different names") 45 | find_parameter() 46 | -------------------------------------------------------------------------------- /yamcs-client/examples/read_write_parameters.py: -------------------------------------------------------------------------------- 1 | from yamcs.client import YamcsClient 2 | 3 | 4 | def print_cached_value(): 5 | """Print a single value from server cache.""" 6 | pval = processor.get_parameter_value("/YSS/SIMULATOR/BatteryVoltage1") 7 | print(pval) 8 | 9 | 10 | def print_realtime_value(): 11 | """Print a newly processed value.""" 12 | pval = processor.get_parameter_value( 13 | "/YSS/SIMULATOR/BatteryVoltage2", from_cache=False, timeout=5 14 | ) 15 | print(pval) 16 | 17 | 18 | def print_current_values(): 19 | """Print multiple parameters from server cache.""" 20 | pvals = processor.get_parameter_values( 21 | ["/YSS/SIMULATOR/BatteryVoltage1", "/YSS/SIMULATOR/BatteryVoltage2"] 22 | ) 23 | print("battery1", pvals[0]) 24 | print("battery2", pvals[1]) 25 | 26 | 27 | def write_value(): 28 | """Writes to a software parameter.""" 29 | processor.set_parameter_value("/YSS/SIMULATOR/AllowCriticalTC1", True) 30 | 31 | 32 | def write_values(): 33 | """Writes multiple software parameters.""" 34 | processor.set_parameter_values( 35 | { 36 | "/YSS/SIMULATOR/AllowCriticalTC1": False, 37 | "/YSS/SIMULATOR/AllowCriticalTC2": False, 38 | } 39 | ) 40 | 41 | 42 | if __name__ == "__main__": 43 | client = YamcsClient("localhost:8090") 44 | processor = client.get_processor(instance="simulator", processor="realtime") 45 | 46 | print("Fetch parameter value from cache") 47 | print_cached_value() 48 | 49 | print("\nFetch newly processed parameter value") 50 | print_realtime_value() 51 | 52 | print("\nFetch multiple parameters at the same time") 53 | print_current_values() 54 | 55 | print("\nWrite to a software parameter") 56 | write_value() 57 | 58 | print("\nWrite multiple software parameters at once") 59 | write_values() 60 | -------------------------------------------------------------------------------- /yamcs-client/examples/reconnection.py: -------------------------------------------------------------------------------- 1 | from time import sleep 2 | 3 | from yamcs.client import ConnectionFailure, YamcsClient 4 | 5 | """ 6 | Subscription types are modeled as Python futures which cover 7 | the lifetime of the underlying WebSocket call. 8 | 9 | Therefore we can use methods like ``result()`` or 10 | ``add_done_callback(fn)`` to observe connection failures. 11 | 12 | The following example uses ``result()`` to trigger 13 | a delayed reconnection attempt. 14 | """ 15 | 16 | 17 | def print_data(data): 18 | for parameter in data.parameters: 19 | print(parameter) 20 | 21 | 22 | while True: 23 | try: 24 | client = YamcsClient("localhost:8090") 25 | processor = client.get_processor("simulator", "realtime") 26 | subscription = processor.create_parameter_subscription( 27 | "/YSS/SIMULATOR/BatteryVoltage1", on_data=print_data 28 | ) 29 | 30 | # Wait until WebSocket close 31 | subscription.result() 32 | except ConnectionFailure: 33 | print("Retrying in 5 seconds...") 34 | sleep(5) 35 | -------------------------------------------------------------------------------- /yamcs-client/examples/run-all.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh -e 2 | 3 | # Ensure presence of data 4 | sleep 20 5 | 6 | # python alarms.py # runs forever 7 | python archive_breakdown.py 8 | python archive_retrieval.py 9 | python ccsds_completeness.py 10 | python change_alarms.py 11 | python change_algorithm.py 12 | python change_calibration.py 13 | # python command_bench.py # runs forever 14 | # python command_history.py # runs forever 15 | python commanding.py 16 | # python cop1.py 17 | python events.py 18 | python links.py 19 | python mission_time.py 20 | # python multiple_commands.py # runs forever 21 | python object_storage.py 22 | python packet_subscription.py 23 | python parameter_subscription.py 24 | python query_mdb.py 25 | python read_write_parameters.py 26 | # python reconnection.py # runs forever 27 | python sql.py 28 | python timeline.py 29 | -------------------------------------------------------------------------------- /yamcs-client/examples/scripting.py: -------------------------------------------------------------------------------- 1 | from yamcs.client import YamcsClient 2 | 3 | 4 | def run_script(): 5 | """Example used in docs to run a script""" 6 | 7 | # Simulate LOS for 5 seconds 8 | # (the run_script call does not block) 9 | processor.run_script("simulate_los.py", "--duration 5") 10 | 11 | 12 | if __name__ == "__main__": 13 | client = YamcsClient("localhost:8090") 14 | processor = client.get_processor("simulator", "realtime") 15 | run_script() 16 | -------------------------------------------------------------------------------- /yamcs-client/examples/sql.py: -------------------------------------------------------------------------------- 1 | from yamcs.client import YamcsClient 2 | 3 | if __name__ == "__main__": 4 | client = YamcsClient("localhost:8090") 5 | archive = client.get_archive("simulator") 6 | 7 | results = archive.execute_sql( 8 | """ 9 | select * from tm limit 2 10 | """ 11 | ) 12 | 13 | for i, row in enumerate(results): 14 | if i == 0: 15 | print(results.columns) 16 | print(row) 17 | -------------------------------------------------------------------------------- /yamcs-client/examples/timeline.py: -------------------------------------------------------------------------------- 1 | from yamcs.client import YamcsClient 2 | 3 | 4 | def create_bands(): 5 | """Snippet used in docs to create a few bands.""" 6 | global utc_time, local_time, group_a, group_b 7 | from yamcs.client import ItemBand, TimeRuler 8 | 9 | utc_time = TimeRuler() 10 | utc_time.name = "UTC" 11 | timeline.save_band(utc_time) 12 | 13 | local_time = TimeRuler() 14 | local_time.name = "Local" 15 | local_time.timezone = "Europe/Brussels" 16 | timeline.save_band(local_time) 17 | 18 | group_a = ItemBand() 19 | group_a.name = "Group A" 20 | group_a.tags = ["group-a"] 21 | timeline.save_band(group_a) 22 | 23 | group_b = ItemBand() 24 | group_b.name = "Group B" 25 | group_b.tags = ["group-b"] 26 | group_b.item_border_color = "#ff4500" 27 | group_b.item_background_color = "#ffa500" 28 | timeline.save_band(group_b) 29 | 30 | 31 | def create_items(): 32 | """Snippet used in docs to create a few items.""" 33 | from datetime import datetime, timedelta, timezone 34 | 35 | from yamcs.client import Item 36 | 37 | now = datetime.now(tz=timezone.utc) 38 | 39 | for i in range(10): 40 | item = Item() 41 | item.name = f"A {i + 1}" 42 | item.start = now + timedelta(seconds=i * 7200) 43 | item.duration = timedelta(seconds=3600) 44 | item.tags = ["group-a"] 45 | timeline.save_item(item) 46 | 47 | item = Item() 48 | item.name = f"B {i + 1}" 49 | item.start = now + timedelta(seconds=3600 + (i * 7200)) 50 | item.duration = timedelta(seconds=3600) 51 | item.tags = ["group-b"] 52 | timeline.save_item(item) 53 | 54 | 55 | def create_view(): 56 | """Snippet used in docs to create a view.""" 57 | from yamcs.client import View 58 | 59 | view = View() 60 | view.name = "Two groups" 61 | view.bands = [utc_time, local_time, group_a, group_b] 62 | timeline.save_view(view) 63 | 64 | 65 | def edit_band(): 66 | """Snippet used in docs to edit a band.""" 67 | global group_a 68 | group_a.description = "A few random items" 69 | timeline.save_band(group_a) 70 | 71 | 72 | def edit_fetched_items(): 73 | """Snippet used in docs to edit a fetched band.""" 74 | for item in timeline.list_items(): 75 | item.tags.append("example") 76 | timeline.save_item(item) 77 | 78 | 79 | def create_parameter_bands(): 80 | """Snippet used in docs to create parameter-based bands.""" 81 | from yamcs.client import ( 82 | ParameterPlot, 83 | ParameterStateBand, 84 | RangeMapping, 85 | Trace, 86 | ValueMapping, 87 | View, 88 | ) 89 | 90 | states = ParameterStateBand() 91 | states.name = "State example" 92 | states.parameter = "/YSS/SIMULATOR/BatteryVoltage2" 93 | states.mappings.append(RangeMapping(40, 56, label="LOW", color="#ff0000")) 94 | states.mappings.append(ValueMapping(57, label="OK", color="#00ff00")) 95 | states.mappings.append(RangeMapping(58, 70, label="HIGH", color="#ff0000")) 96 | timeline.save_band(states) 97 | 98 | plot = ParameterPlot() 99 | plot.name = "Plot example" 100 | plot.maximum = 65 101 | trace = Trace( 102 | parameter="/YSS/SIMULATOR/BatteryVoltage2", 103 | line_color="#ffff00", 104 | fill=True, 105 | ) 106 | plot.traces.append(trace) 107 | timeline.save_band(plot) 108 | 109 | view = View() 110 | view.name = "Parameter examples" 111 | view.bands = [states, plot] 112 | timeline.save_view(view) 113 | 114 | 115 | if __name__ == "__main__": 116 | client = YamcsClient("localhost:8090") 117 | timeline = client.get_timeline_client("simulator") 118 | 119 | # Delete all 120 | for view in timeline.list_views(): 121 | timeline.delete_view(view.id) 122 | for band in timeline.list_bands(): 123 | timeline.delete_band(band.id) 124 | for item in timeline.list_items(): 125 | timeline.delete_item(item.id) 126 | 127 | create_bands() 128 | create_items() 129 | create_view() 130 | edit_band() 131 | edit_fetched_items() 132 | create_parameter_bands() 133 | -------------------------------------------------------------------------------- /yamcs-client/examples/write_mdb.py: -------------------------------------------------------------------------------- 1 | from yamcs.client import NotFound, YamcsClient 2 | 3 | """ 4 | The following example requires a _writable_ system. 5 | 6 | In this example the system ``/myproject/test`` is writable, whereas 7 | the top-level system ``/myproject`` is populated based on a predefined 8 | XTCE file (not managed by Yamcs itself). 9 | """ 10 | 11 | if __name__ == "__main__": 12 | client = YamcsClient("localhost:8090") 13 | mdb = client.get_mdb(instance="myproject") 14 | 15 | system = "/myproject/test" 16 | try: 17 | mdb.get_parameter_type(f"{system}/float_t") 18 | except NotFound: 19 | mdb.create_parameter_type(f"{system}/float_t", eng_type="float") 20 | 21 | try: 22 | mdb.get_parameter(f"{system}/testparam") 23 | except NotFound: 24 | mdb.create_parameter( 25 | f"{system}/testparam", 26 | data_source="LOCAL", 27 | parameter_type=f"{system}/float_t", 28 | ) 29 | 30 | # MDB is present, now publish a parameter value 31 | processor = client.get_processor("myproject", "realtime") 32 | processor.set_parameter_value(f"{system}/testparam", 123.4) 33 | -------------------------------------------------------------------------------- /yamcs-client/requirements.txt: -------------------------------------------------------------------------------- 1 | requests 2 | setuptools 3 | websocket-client 4 | -------------------------------------------------------------------------------- /yamcs-client/setup.py: -------------------------------------------------------------------------------- 1 | import io 2 | 3 | import setuptools 4 | 5 | with io.open("README.md", encoding="utf-8") as f: 6 | readme = f.read() 7 | 8 | version = {} 9 | with io.open("src/yamcs/client/clientversion.py", encoding="utf-8") as f: 10 | exec(f.read(), version) 11 | version = version["__version__"] 12 | 13 | setuptools.setup( 14 | name="yamcs-client", 15 | version=version, 16 | description="Yamcs API client library", 17 | long_description=readme, 18 | long_description_content_type="text/markdown", 19 | url="https://github.com/yamcs/python-yamcs-client", 20 | author="Space Applications Services", 21 | author_email="yamcs@spaceapplications.com", 22 | license="LGPL", 23 | packages=setuptools.find_namespace_packages(where="src"), 24 | package_dir={"": "src"}, 25 | python_requires=">=3.8", 26 | classifiers=[ 27 | "Development Status :: 5 - Production/Stable", 28 | "Intended Audience :: Developers", 29 | "License :: OSI Approved :: GNU Lesser General Public License v3 (LGPLv3)", 30 | "Programming Language :: Python", 31 | "Programming Language :: Python :: 3", 32 | "Programming Language :: Python :: 3.8", 33 | "Programming Language :: Python :: 3.9", 34 | "Programming Language :: Python :: 3.10", 35 | "Programming Language :: Python :: 3.11", 36 | "Programming Language :: Python :: 3.12", 37 | "Programming Language :: Python :: 3.13", 38 | "Operating System :: OS Independent", 39 | ], 40 | platforms="Posix; MacOS X; Windows", 41 | install_requires=[ 42 | # Protobuf 4 is very different: https://protobuf.dev/news/2022-05-06/ 43 | # We should only run with it, once generating with protoc 3.19 44 | "protobuf>=3.11,<4", 45 | "requests", 46 | "setuptools", 47 | "websocket-client", 48 | ], 49 | include_package_data=True, 50 | zip_safe=False, 51 | ) 52 | -------------------------------------------------------------------------------- /yamcs-client/src/yamcs/api/exception_pb2.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by the protocol buffer compiler. DO NOT EDIT! 3 | # source: yamcs/api/exception.proto 4 | 5 | from google.protobuf import descriptor as _descriptor 6 | from google.protobuf import message as _message 7 | from google.protobuf import reflection as _reflection 8 | from google.protobuf import symbol_database as _symbol_database 9 | # @@protoc_insertion_point(imports) 10 | 11 | _sym_db = _symbol_database.Default() 12 | 13 | 14 | from google.protobuf import any_pb2 as google_dot_protobuf_dot_any__pb2 15 | 16 | 17 | DESCRIPTOR = _descriptor.FileDescriptor( 18 | name='yamcs/api/exception.proto', 19 | package='yamcs.api', 20 | syntax='proto3', 21 | serialized_options=b'\n\rorg.yamcs.apiB\016ExceptionProtoP\001', 22 | serialized_pb=b'\n\x19yamcs/api/exception.proto\x12\tyamcs.api\x1a\x19google/protobuf/any.proto\"a\n\x10\x45xceptionMessage\x12\x0c\n\x04\x63ode\x18\x01 \x01(\x05\x12\x0c\n\x04type\x18\x02 \x01(\t\x12\x0b\n\x03msg\x18\x03 \x01(\t\x12$\n\x06\x64\x65tail\x18\x04 \x01(\x0b\x32\x14.google.protobuf.Any\"c\n\x15\x46ilterSyntaxException\x12\x11\n\tbeginLine\x18\x01 \x01(\x05\x12\x13\n\x0b\x62\x65ginColumn\x18\x02 \x01(\x05\x12\x0f\n\x07\x65ndLine\x18\x03 \x01(\x05\x12\x11\n\tendColumn\x18\x04 \x01(\x05\x42!\n\rorg.yamcs.apiB\x0e\x45xceptionProtoP\x01\x62\x06proto3' 23 | , 24 | dependencies=[google_dot_protobuf_dot_any__pb2.DESCRIPTOR,]) 25 | 26 | 27 | 28 | 29 | _EXCEPTIONMESSAGE = _descriptor.Descriptor( 30 | name='ExceptionMessage', 31 | full_name='yamcs.api.ExceptionMessage', 32 | filename=None, 33 | file=DESCRIPTOR, 34 | containing_type=None, 35 | fields=[ 36 | _descriptor.FieldDescriptor( 37 | name='code', full_name='yamcs.api.ExceptionMessage.code', index=0, 38 | number=1, type=5, cpp_type=1, label=1, 39 | has_default_value=False, default_value=0, 40 | message_type=None, enum_type=None, containing_type=None, 41 | is_extension=False, extension_scope=None, 42 | serialized_options=None, file=DESCRIPTOR), 43 | _descriptor.FieldDescriptor( 44 | name='type', full_name='yamcs.api.ExceptionMessage.type', index=1, 45 | number=2, type=9, cpp_type=9, label=1, 46 | has_default_value=False, default_value=b"".decode('utf-8'), 47 | message_type=None, enum_type=None, containing_type=None, 48 | is_extension=False, extension_scope=None, 49 | serialized_options=None, file=DESCRIPTOR), 50 | _descriptor.FieldDescriptor( 51 | name='msg', full_name='yamcs.api.ExceptionMessage.msg', index=2, 52 | number=3, type=9, cpp_type=9, label=1, 53 | has_default_value=False, default_value=b"".decode('utf-8'), 54 | message_type=None, enum_type=None, containing_type=None, 55 | is_extension=False, extension_scope=None, 56 | serialized_options=None, file=DESCRIPTOR), 57 | _descriptor.FieldDescriptor( 58 | name='detail', full_name='yamcs.api.ExceptionMessage.detail', index=3, 59 | number=4, type=11, cpp_type=10, label=1, 60 | has_default_value=False, default_value=None, 61 | message_type=None, enum_type=None, containing_type=None, 62 | is_extension=False, extension_scope=None, 63 | serialized_options=None, file=DESCRIPTOR), 64 | ], 65 | extensions=[ 66 | ], 67 | nested_types=[], 68 | enum_types=[ 69 | ], 70 | serialized_options=None, 71 | is_extendable=False, 72 | syntax='proto3', 73 | extension_ranges=[], 74 | oneofs=[ 75 | ], 76 | serialized_start=67, 77 | serialized_end=164, 78 | ) 79 | 80 | 81 | _FILTERSYNTAXEXCEPTION = _descriptor.Descriptor( 82 | name='FilterSyntaxException', 83 | full_name='yamcs.api.FilterSyntaxException', 84 | filename=None, 85 | file=DESCRIPTOR, 86 | containing_type=None, 87 | fields=[ 88 | _descriptor.FieldDescriptor( 89 | name='beginLine', full_name='yamcs.api.FilterSyntaxException.beginLine', index=0, 90 | number=1, type=5, cpp_type=1, label=1, 91 | has_default_value=False, default_value=0, 92 | message_type=None, enum_type=None, containing_type=None, 93 | is_extension=False, extension_scope=None, 94 | serialized_options=None, file=DESCRIPTOR), 95 | _descriptor.FieldDescriptor( 96 | name='beginColumn', full_name='yamcs.api.FilterSyntaxException.beginColumn', index=1, 97 | number=2, type=5, cpp_type=1, label=1, 98 | has_default_value=False, default_value=0, 99 | message_type=None, enum_type=None, containing_type=None, 100 | is_extension=False, extension_scope=None, 101 | serialized_options=None, file=DESCRIPTOR), 102 | _descriptor.FieldDescriptor( 103 | name='endLine', full_name='yamcs.api.FilterSyntaxException.endLine', index=2, 104 | number=3, type=5, cpp_type=1, label=1, 105 | has_default_value=False, default_value=0, 106 | message_type=None, enum_type=None, containing_type=None, 107 | is_extension=False, extension_scope=None, 108 | serialized_options=None, file=DESCRIPTOR), 109 | _descriptor.FieldDescriptor( 110 | name='endColumn', full_name='yamcs.api.FilterSyntaxException.endColumn', index=3, 111 | number=4, type=5, cpp_type=1, label=1, 112 | has_default_value=False, default_value=0, 113 | message_type=None, enum_type=None, containing_type=None, 114 | is_extension=False, extension_scope=None, 115 | serialized_options=None, file=DESCRIPTOR), 116 | ], 117 | extensions=[ 118 | ], 119 | nested_types=[], 120 | enum_types=[ 121 | ], 122 | serialized_options=None, 123 | is_extendable=False, 124 | syntax='proto3', 125 | extension_ranges=[], 126 | oneofs=[ 127 | ], 128 | serialized_start=166, 129 | serialized_end=265, 130 | ) 131 | 132 | _EXCEPTIONMESSAGE.fields_by_name['detail'].message_type = google_dot_protobuf_dot_any__pb2._ANY 133 | DESCRIPTOR.message_types_by_name['ExceptionMessage'] = _EXCEPTIONMESSAGE 134 | DESCRIPTOR.message_types_by_name['FilterSyntaxException'] = _FILTERSYNTAXEXCEPTION 135 | _sym_db.RegisterFileDescriptor(DESCRIPTOR) 136 | 137 | ExceptionMessage = _reflection.GeneratedProtocolMessageType('ExceptionMessage', (_message.Message,), { 138 | 'DESCRIPTOR' : _EXCEPTIONMESSAGE, 139 | '__module__' : 'yamcs.api.exception_pb2' 140 | # @@protoc_insertion_point(class_scope:yamcs.api.ExceptionMessage) 141 | }) 142 | _sym_db.RegisterMessage(ExceptionMessage) 143 | 144 | FilterSyntaxException = _reflection.GeneratedProtocolMessageType('FilterSyntaxException', (_message.Message,), { 145 | 'DESCRIPTOR' : _FILTERSYNTAXEXCEPTION, 146 | '__module__' : 'yamcs.api.exception_pb2' 147 | # @@protoc_insertion_point(class_scope:yamcs.api.FilterSyntaxException) 148 | }) 149 | _sym_db.RegisterMessage(FilterSyntaxException) 150 | 151 | 152 | DESCRIPTOR._options = None 153 | # @@protoc_insertion_point(module_scope) 154 | -------------------------------------------------------------------------------- /yamcs-client/src/yamcs/api/httpbody_pb2.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by the protocol buffer compiler. DO NOT EDIT! 3 | # source: yamcs/api/httpbody.proto 4 | 5 | from google.protobuf import descriptor as _descriptor 6 | from google.protobuf import message as _message 7 | from google.protobuf import reflection as _reflection 8 | from google.protobuf import symbol_database as _symbol_database 9 | # @@protoc_insertion_point(imports) 10 | 11 | _sym_db = _symbol_database.Default() 12 | 13 | 14 | 15 | 16 | DESCRIPTOR = _descriptor.FileDescriptor( 17 | name='yamcs/api/httpbody.proto', 18 | package='yamcs.api', 19 | syntax='proto2', 20 | serialized_options=b'\n\rorg.yamcs.apiB\rHttpBodyProtoP\001', 21 | serialized_pb=b'\n\x18yamcs/api/httpbody.proto\x12\tyamcs.api\"\xa6\x01\n\x08HttpBody\x12\x14\n\x0c\x63ontent_type\x18\x01 \x01(\t\x12\x10\n\x08\x66ilename\x18\x02 \x01(\t\x12\x0c\n\x04\x64\x61ta\x18\x03 \x01(\x0c\x12\x33\n\x08metadata\x18\x04 \x03(\x0b\x32!.yamcs.api.HttpBody.MetadataEntry\x1a/\n\rMetadataEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\x42 \n\rorg.yamcs.apiB\rHttpBodyProtoP\x01' 22 | ) 23 | 24 | 25 | 26 | 27 | _HTTPBODY_METADATAENTRY = _descriptor.Descriptor( 28 | name='MetadataEntry', 29 | full_name='yamcs.api.HttpBody.MetadataEntry', 30 | filename=None, 31 | file=DESCRIPTOR, 32 | containing_type=None, 33 | fields=[ 34 | _descriptor.FieldDescriptor( 35 | name='key', full_name='yamcs.api.HttpBody.MetadataEntry.key', index=0, 36 | number=1, type=9, cpp_type=9, label=1, 37 | has_default_value=False, default_value=b"".decode('utf-8'), 38 | message_type=None, enum_type=None, containing_type=None, 39 | is_extension=False, extension_scope=None, 40 | serialized_options=None, file=DESCRIPTOR), 41 | _descriptor.FieldDescriptor( 42 | name='value', full_name='yamcs.api.HttpBody.MetadataEntry.value', index=1, 43 | number=2, type=9, cpp_type=9, label=1, 44 | has_default_value=False, default_value=b"".decode('utf-8'), 45 | message_type=None, enum_type=None, containing_type=None, 46 | is_extension=False, extension_scope=None, 47 | serialized_options=None, file=DESCRIPTOR), 48 | ], 49 | extensions=[ 50 | ], 51 | nested_types=[], 52 | enum_types=[ 53 | ], 54 | serialized_options=b'8\001', 55 | is_extendable=False, 56 | syntax='proto2', 57 | extension_ranges=[], 58 | oneofs=[ 59 | ], 60 | serialized_start=159, 61 | serialized_end=206, 62 | ) 63 | 64 | _HTTPBODY = _descriptor.Descriptor( 65 | name='HttpBody', 66 | full_name='yamcs.api.HttpBody', 67 | filename=None, 68 | file=DESCRIPTOR, 69 | containing_type=None, 70 | fields=[ 71 | _descriptor.FieldDescriptor( 72 | name='content_type', full_name='yamcs.api.HttpBody.content_type', index=0, 73 | number=1, type=9, cpp_type=9, label=1, 74 | has_default_value=False, default_value=b"".decode('utf-8'), 75 | message_type=None, enum_type=None, containing_type=None, 76 | is_extension=False, extension_scope=None, 77 | serialized_options=None, file=DESCRIPTOR), 78 | _descriptor.FieldDescriptor( 79 | name='filename', full_name='yamcs.api.HttpBody.filename', index=1, 80 | number=2, type=9, cpp_type=9, label=1, 81 | has_default_value=False, default_value=b"".decode('utf-8'), 82 | message_type=None, enum_type=None, containing_type=None, 83 | is_extension=False, extension_scope=None, 84 | serialized_options=None, file=DESCRIPTOR), 85 | _descriptor.FieldDescriptor( 86 | name='data', full_name='yamcs.api.HttpBody.data', index=2, 87 | number=3, type=12, cpp_type=9, label=1, 88 | has_default_value=False, default_value=b"", 89 | message_type=None, enum_type=None, containing_type=None, 90 | is_extension=False, extension_scope=None, 91 | serialized_options=None, file=DESCRIPTOR), 92 | _descriptor.FieldDescriptor( 93 | name='metadata', full_name='yamcs.api.HttpBody.metadata', index=3, 94 | number=4, type=11, cpp_type=10, label=3, 95 | has_default_value=False, default_value=[], 96 | message_type=None, enum_type=None, containing_type=None, 97 | is_extension=False, extension_scope=None, 98 | serialized_options=None, file=DESCRIPTOR), 99 | ], 100 | extensions=[ 101 | ], 102 | nested_types=[_HTTPBODY_METADATAENTRY, ], 103 | enum_types=[ 104 | ], 105 | serialized_options=None, 106 | is_extendable=False, 107 | syntax='proto2', 108 | extension_ranges=[], 109 | oneofs=[ 110 | ], 111 | serialized_start=40, 112 | serialized_end=206, 113 | ) 114 | 115 | _HTTPBODY_METADATAENTRY.containing_type = _HTTPBODY 116 | _HTTPBODY.fields_by_name['metadata'].message_type = _HTTPBODY_METADATAENTRY 117 | DESCRIPTOR.message_types_by_name['HttpBody'] = _HTTPBODY 118 | _sym_db.RegisterFileDescriptor(DESCRIPTOR) 119 | 120 | HttpBody = _reflection.GeneratedProtocolMessageType('HttpBody', (_message.Message,), { 121 | 122 | 'MetadataEntry' : _reflection.GeneratedProtocolMessageType('MetadataEntry', (_message.Message,), { 123 | 'DESCRIPTOR' : _HTTPBODY_METADATAENTRY, 124 | '__module__' : 'yamcs.api.httpbody_pb2' 125 | # @@protoc_insertion_point(class_scope:yamcs.api.HttpBody.MetadataEntry) 126 | }) 127 | , 128 | 'DESCRIPTOR' : _HTTPBODY, 129 | '__module__' : 'yamcs.api.httpbody_pb2' 130 | # @@protoc_insertion_point(class_scope:yamcs.api.HttpBody) 131 | }) 132 | _sym_db.RegisterMessage(HttpBody) 133 | _sym_db.RegisterMessage(HttpBody.MetadataEntry) 134 | 135 | 136 | DESCRIPTOR._options = None 137 | _HTTPBODY_METADATAENTRY._options = None 138 | # @@protoc_insertion_point(module_scope) 139 | -------------------------------------------------------------------------------- /yamcs-client/src/yamcs/archive/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yamcs/python-yamcs-client/24860c21f9f82b02b73240a2b7d3ca547178a331/yamcs-client/src/yamcs/archive/__init__.py -------------------------------------------------------------------------------- /yamcs-client/src/yamcs/archive/client.py: -------------------------------------------------------------------------------- 1 | """ 2 | Old-style. For backwards compatibility. 3 | Avoid use. 4 | """ 5 | 6 | from yamcs.client.archive.client import ArchiveClient # noqa 7 | -------------------------------------------------------------------------------- /yamcs-client/src/yamcs/archive/model.py: -------------------------------------------------------------------------------- 1 | """ 2 | Old-style. For backwards compatibility. 3 | Avoid use. 4 | """ 5 | 6 | from yamcs.client.archive.model import ( # noqa 7 | ColumnData, 8 | IndexGroup, 9 | IndexRecord, 10 | ParameterRange, 11 | ParameterRangeEntry, 12 | ResultSet, 13 | Sample, 14 | Stream, 15 | StreamData, 16 | Table, 17 | ) 18 | -------------------------------------------------------------------------------- /yamcs-client/src/yamcs/client/__init__.py: -------------------------------------------------------------------------------- 1 | from yamcs.client import clientversion # noqa 2 | from yamcs.client.activities import * # noqa 3 | from yamcs.client.archive.client import * # noqa 4 | from yamcs.client.archive.model import * # noqa 5 | from yamcs.client.core import * # noqa 6 | from yamcs.client.core.auth import * # noqa 7 | from yamcs.client.core.context import * # noqa 8 | from yamcs.client.core.exceptions import * # noqa 9 | from yamcs.client.core.futures import * # noqa 10 | from yamcs.client.core.helpers import * # noqa 11 | from yamcs.client.core.pagination import * # noqa 12 | from yamcs.client.core.subscriptions import * # noqa 13 | from yamcs.client.filetransfer.client import * # noqa 14 | from yamcs.client.filetransfer.model import * # noqa 15 | from yamcs.client.links.client import * # noqa 16 | from yamcs.client.links.model import * # noqa 17 | from yamcs.client.mdb.client import * # noqa 18 | from yamcs.client.mdb.model import * # noqa 19 | from yamcs.client.model import * # noqa 20 | from yamcs.client.storage.client import * # noqa 21 | from yamcs.client.storage.model import * # noqa 22 | from yamcs.client.tco.client import * # noqa 23 | from yamcs.client.tco.model import * # noqa 24 | from yamcs.client.timeline.client import * # noqa 25 | from yamcs.client.timeline.model import * # noqa 26 | from yamcs.client.tmtc.client import * # noqa 27 | from yamcs.client.tmtc.model import * # noqa 28 | -------------------------------------------------------------------------------- /yamcs-client/src/yamcs/client/activities.py: -------------------------------------------------------------------------------- 1 | import abc 2 | from dataclasses import dataclass, field 3 | from typing import Any, List, Mapping, Optional, Union 4 | 5 | import pkg_resources 6 | from yamcs.client.core.helpers import to_argument_value 7 | from yamcs.protobuf.activities import activities_pb2 8 | 9 | __all__ = [ 10 | "Activity", 11 | "CommandActivity", 12 | "CommandStackActivity", 13 | "ManualActivity", 14 | "ScriptActivity", 15 | ] 16 | 17 | 18 | @dataclass 19 | class Activity: 20 | """ 21 | Superclass for activities. Core implementations: 22 | 23 | * :class:`.CommandActivity` 24 | * :class:`.CommandStackActivity` 25 | * :class:`.ManualActivity` 26 | * :class:`.ScriptActivity` 27 | """ 28 | 29 | @staticmethod 30 | @abc.abstractmethod 31 | def _from_proto(proto: activities_pb2.ActivityDefinitionInfo) -> "Activity": 32 | pass 33 | 34 | @abc.abstractmethod 35 | def _to_proto(self) -> activities_pb2.ActivityDefinitionInfo: 36 | pass 37 | 38 | @staticmethod 39 | def _as_subclass(proto): 40 | # No need for MANUAL. 41 | # It is recognized by Yamcs, by not having an 42 | # activity definition. 43 | if proto.type == "COMMAND": 44 | return CommandActivity._from_proto(proto) 45 | elif proto.type == "COMMAND_STACK": 46 | return CommandStackActivity._from_proto(proto) 47 | elif proto.type == "SCRIPT": 48 | return ScriptActivity._from_proto(proto) 49 | else: 50 | for entry in pkg_resources.iter_entry_points( 51 | group="yamcs.client.activities" 52 | ): 53 | if proto.type == entry.name: 54 | activity_cls = entry.load() 55 | return activity_cls._from_proto(proto) 56 | 57 | raise ValueError(f"Unexpected activity type: {proto.type}") 58 | 59 | 60 | @dataclass 61 | class ManualActivity(Activity): 62 | """ 63 | An activity whose execution status is managed outside of Yamcs 64 | """ 65 | 66 | 67 | @dataclass 68 | class ScriptActivity(Activity): 69 | """ 70 | An activity that runs a script 71 | """ 72 | 73 | script: str 74 | """ 75 | Script identifier. 76 | 77 | This should be the relative path to an an executable file in one of 78 | the search locations. When unconfigured, the default search 79 | location is :file:`etc/scripts/` relative to the Yamcs working 80 | directory. 81 | """ 82 | 83 | args: Optional[Union[str, List[str]]] = None 84 | """ 85 | Optional script arguments, passed verbatim in the command line. 86 | """ 87 | 88 | processor: Optional[str] = None 89 | """ 90 | Optional processor name. If provided, this is provided to the 91 | script as the environment variable ``YAMCS_PROCESSOR``. 92 | """ 93 | 94 | @staticmethod 95 | def _from_proto(proto: activities_pb2.ActivityDefinitionInfo): 96 | activity = ScriptActivity(script=proto.args["script"]) 97 | 98 | if "args" in proto.args: 99 | activity.args = proto.args["args"] 100 | 101 | if "processor" in proto.args: 102 | activity.processor = proto.args["processor"] 103 | 104 | return activity 105 | 106 | def _to_proto(self) -> activities_pb2.ActivityDefinitionInfo: 107 | proto = activities_pb2.ActivityDefinitionInfo() 108 | proto.type = "SCRIPT" 109 | proto.args["script"] = self.script 110 | 111 | if self.args: 112 | proto.args["args"] = self.args 113 | 114 | if self.processor: 115 | proto.args["processor"] = self.processor 116 | 117 | return proto 118 | 119 | 120 | @dataclass 121 | class CommandActivity(Activity): 122 | """ 123 | An activity that executes a single command 124 | """ 125 | 126 | command: str 127 | """Qualified name of a command""" 128 | 129 | args: Mapping[str, Any] = field(default_factory=dict) 130 | """Named arguments, if the command requires any""" 131 | 132 | extra: Mapping[str, Any] = field(default_factory=dict) 133 | """Extra command options""" 134 | 135 | processor: Optional[str] = None 136 | """ 137 | Optional processor name. If not provided, Yamcs defaults to any 138 | processor it can find with commanding enabled. 139 | """ 140 | 141 | @staticmethod 142 | def _from_proto(proto: activities_pb2.ActivityDefinitionInfo): 143 | activity = CommandActivity(command=proto.args["command"]) 144 | 145 | if "args" in proto.args: 146 | command_args = proto.args["args"] 147 | activity.args = {key: value for key, value in command_args.items()} 148 | 149 | if "extra" in proto.args: 150 | command_extra = proto.args["extra"] 151 | activity.extra = {key: value for key, value in command_extra.items()} 152 | 153 | if "processor" in proto.args: 154 | activity.processor = proto.args["processor"] 155 | 156 | return activity 157 | 158 | def _to_proto(self) -> activities_pb2.ActivityDefinitionInfo: 159 | proto = activities_pb2.ActivityDefinitionInfo() 160 | proto.type = "COMMAND" 161 | proto.args["command"] = self.command 162 | 163 | if self.processor: 164 | proto.args["processor"] = self.processor 165 | 166 | proto.args["args"] = {} 167 | for k, v in self.args.items(): 168 | proto.args["args"][k] = to_argument_value(v, force_string=True) 169 | 170 | proto.args["extra"] = {} 171 | for k, v in self.extra.items(): 172 | proto.args["extra"][k] = to_argument_value(v, force_string=False) 173 | 174 | return proto 175 | 176 | 177 | @dataclass 178 | class CommandStackActivity(Activity): 179 | """ 180 | An activity that executes a command stack 181 | """ 182 | 183 | bucket: str 184 | """The name of the bucket containing the stack.""" 185 | 186 | stack: str 187 | """The name of the stack object inside the bucket.""" 188 | 189 | processor: Optional[str] = None 190 | """ 191 | Optional processor name. If not provided, Yamcs defaults to any 192 | processor it can find with commanding enabled. 193 | """ 194 | 195 | @staticmethod 196 | def _from_proto(proto: activities_pb2.ActivityDefinitionInfo): 197 | activity = CommandStackActivity( 198 | bucket=proto.args["bucket"], 199 | stack=proto.args["stack"], 200 | ) 201 | 202 | if "processor" in proto.args: 203 | activity.processor = proto.args["processor"] 204 | 205 | return activity 206 | 207 | def _to_proto(self) -> activities_pb2.ActivityDefinitionInfo: 208 | proto = activities_pb2.ActivityDefinitionInfo() 209 | proto.type = "COMMAND_STACK" 210 | proto.args["bucket"] = self.bucket 211 | proto.args["stack"] = self.stack 212 | if self.processor: 213 | proto.args["processor"] = self.processor 214 | return proto 215 | -------------------------------------------------------------------------------- /yamcs-client/src/yamcs/client/archive/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yamcs/python-yamcs-client/24860c21f9f82b02b73240a2b7d3ca547178a331/yamcs-client/src/yamcs/client/archive/__init__.py -------------------------------------------------------------------------------- /yamcs-client/src/yamcs/client/clientversion.py: -------------------------------------------------------------------------------- 1 | __version__ = "1.11.3" 2 | -------------------------------------------------------------------------------- /yamcs-client/src/yamcs/client/core/context.py: -------------------------------------------------------------------------------- 1 | from datetime import datetime, timezone 2 | from typing import Callable, Optional, Union 3 | 4 | import requests 5 | import urllib3 6 | from google.protobuf.message import DecodeError 7 | from yamcs.api import exception_pb2 8 | from yamcs.client import clientversion 9 | from yamcs.client.core.auth import Credentials 10 | from yamcs.client.core.exceptions import NotFound, Unauthorized, YamcsError 11 | from yamcs.client.core.helpers import FixedDelay, do_request 12 | 13 | __all__ = [ 14 | "Context", 15 | ] 16 | 17 | 18 | class Context: 19 | 20 | def __init__( 21 | self, 22 | address: str, 23 | tls: bool = False, 24 | credentials: Optional[Credentials] = None, 25 | user_agent: Optional[str] = None, 26 | on_token_update: Optional[Callable[[Credentials], None]] = None, 27 | tls_verify: Union[bool, str] = True, 28 | keep_alive: bool = True, 29 | ): 30 | if address.endswith("/"): 31 | self.address = address[:-1] 32 | else: 33 | self.address = address 34 | 35 | if tls: 36 | self.url = f"https://{self.address}" 37 | self.auth_root = f"https://{self.address}/auth" 38 | self.api_root = f"https://{self.address}/api" 39 | self.ws_root = f"wss://{self.address}/api/websocket" 40 | else: 41 | self.url = f"http://{self.address}" 42 | self.auth_root = f"http://{self.address}/auth" 43 | self.api_root = f"http://{self.address}/api" 44 | self.ws_root = f"ws://{self.address}/api/websocket" 45 | 46 | self.session = requests.Session() 47 | self.session.verify = tls_verify 48 | if not tls_verify: 49 | try: 50 | # requests < 2.16.0 51 | requests.packages.urllib3.disable_warnings( 52 | requests.packages.urllib3.exceptions.InsecureRequestWarning 53 | ) 54 | except Exception: 55 | # requests >= 2.16.0 56 | urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) 57 | 58 | self.credentials: Optional[Credentials] = None 59 | self._session_renewer = None 60 | 61 | if credentials: 62 | converted_creds = credentials.login( 63 | self.session, self.auth_root, on_token_update 64 | ) 65 | self.credentials = converted_creds 66 | 67 | # An assigned refresh token lives only for about 30 minutes. We actively 68 | # extend it, so that the session survives when idle. 69 | if converted_creds.expiry and keep_alive: 70 | 71 | def renew_session(): 72 | expiry = converted_creds.expiry 73 | if expiry: 74 | remaining = expiry - datetime.now(tz=timezone.utc) 75 | if 0 < remaining.total_seconds() < 60: 76 | converted_creds.refresh(self.session, self.auth_root) 77 | 78 | self._session_renewer = FixedDelay(renew_session, 10, 10) 79 | 80 | if not user_agent: 81 | user_agent = "python-yamcs-client v" + clientversion.__version__ 82 | self.session.headers.update({"User-Agent": user_agent}) 83 | 84 | def get_proto(self, path: str, **kwargs) -> requests.Response: 85 | headers = kwargs.pop("headers", {}) 86 | headers["Accept"] = "application/protobuf" 87 | kwargs.update({"headers": headers}) 88 | return self.request("get", path, **kwargs) 89 | 90 | def put_proto(self, path: str, **kwargs) -> requests.Response: 91 | headers = kwargs.pop("headers", {}) 92 | headers["Content-Type"] = "application/protobuf" 93 | headers["Accept"] = "application/protobuf" 94 | kwargs.update({"headers": headers}) 95 | return self.request("put", path, **kwargs) 96 | 97 | def patch_proto(self, path: str, **kwargs) -> requests.Response: 98 | headers = kwargs.pop("headers", {}) 99 | headers["Content-Type"] = "application/protobuf" 100 | headers["Accept"] = "application/protobuf" 101 | kwargs.update({"headers": headers}) 102 | return self.request("patch", path, **kwargs) 103 | 104 | def post_proto(self, path: str, **kwargs) -> requests.Response: 105 | headers = kwargs.pop("headers", {}) 106 | headers["Content-Type"] = "application/protobuf" 107 | headers["Accept"] = "application/protobuf" 108 | kwargs.update({"headers": headers}) 109 | return self.request("post", path, **kwargs) 110 | 111 | def delete_proto(self, path: str, **kwargs) -> requests.Response: 112 | headers = kwargs.pop("headers", {}) 113 | headers["Accept"] = "application/protobuf" 114 | kwargs.update({"headers": headers}) 115 | return self.request("delete", path, **kwargs) 116 | 117 | def request(self, method: str, path: str, **kwargs) -> requests.Response: 118 | path = f"{self.api_root}{path}" 119 | 120 | if self.credentials: 121 | self.credentials.before_request(self.session, self.auth_root) 122 | 123 | response = do_request(self.session, method, path, **kwargs) 124 | if 200 <= response.status_code < 300: 125 | return response 126 | 127 | exception_message = exception_pb2.ExceptionMessage() 128 | try: 129 | exception_message.ParseFromString(response.content) 130 | except DecodeError: 131 | pass 132 | 133 | if response.status_code == 401: 134 | raise Unauthorized("401 Client Error: Unauthorized") 135 | elif response.status_code == 404: 136 | msg = getattr(exception_message, "msg") 137 | raise NotFound(f"404 Client Error: {msg}") 138 | elif 400 <= response.status_code < 500: 139 | msg = getattr(exception_message, "msg") 140 | raise YamcsError(f"{response.status_code} Client Error: {msg}") 141 | msg = getattr(exception_message, "msg") 142 | raise YamcsError(f"{response.status_code} Server Error: {msg}") 143 | 144 | def close(self): 145 | """Close this context""" 146 | 147 | if self._session_renewer: 148 | self._session_renewer.stop() 149 | 150 | self.session.close() 151 | -------------------------------------------------------------------------------- /yamcs-client/src/yamcs/client/core/exceptions.py: -------------------------------------------------------------------------------- 1 | __all__ = [ 2 | "ConnectionFailure", 3 | "NotFound", 4 | "TimeoutError", 5 | "Unauthorized", 6 | "YamcsError", 7 | ] 8 | 9 | 10 | class YamcsError(Exception): 11 | """Base class for raised exceptions.""" 12 | 13 | 14 | class ConnectionFailure(YamcsError): 15 | """Yamcs is not or no longer available.""" 16 | 17 | 18 | class TimeoutError(YamcsError): 19 | """The operation exceeded the given deadline.""" 20 | 21 | 22 | class NotFound(YamcsError): 23 | """The resource was not found.""" 24 | 25 | 26 | class Unauthorized(YamcsError): 27 | """Unable to get access the resource.""" 28 | -------------------------------------------------------------------------------- /yamcs-client/src/yamcs/client/core/futures.py: -------------------------------------------------------------------------------- 1 | import threading 2 | from concurrent.futures import Future 3 | 4 | from yamcs.client.core.exceptions import TimeoutError, YamcsError 5 | from yamcs.client.core.subscriptions import WebSocketSubscriptionManager 6 | 7 | __all__ = [ 8 | "WebSocketSubscriptionFuture", 9 | ] 10 | 11 | 12 | class WebSocketSubscriptionFuture(Future): 13 | """ 14 | Future for capturing the asynchronous execution of a WebSocket subscription. 15 | """ 16 | 17 | def __init__(self, manager: WebSocketSubscriptionManager): 18 | super(WebSocketSubscriptionFuture, self).__init__() 19 | self.ctx = manager.ctx 20 | self._manager = manager 21 | self._manager.add_response_callback(self._on_response_callback) 22 | self._manager.add_close_callback(self._on_close_callback) 23 | 24 | # Yamcs send either a 'reply' message or an 'exception' message on 25 | # every websocket subscription. If the ``_response_received`` event 26 | # is set it means either of these two has arrived, or the connection 27 | # failed entirely 28 | self._response_received = threading.Event() 29 | self._response_reply = None 30 | self._response_exception = None 31 | 32 | self._result = None 33 | self._exception = None 34 | self._callbacks = [] 35 | 36 | self._completed = threading.Event() 37 | self._cancelled = False 38 | 39 | def _on_response_callback(self, manager, reply=None, exception=None): 40 | self._response_reply = reply 41 | self._response_exception = exception 42 | self._response_received.set() 43 | 44 | # Yamcs leaves the socket open because it was designed with 45 | # multiple parallel subscriptions in mind. We don't use this 46 | # notion, so close the connection. 47 | if exception: 48 | closer = threading.Thread( 49 | target=self._manager.close, 50 | kwargs={"reason": exception}, 51 | ) 52 | closer.daemon = True 53 | closer.start() 54 | 55 | def _on_close_callback(self, manager, result): 56 | if result is None: 57 | self.set_result(True) 58 | else: 59 | self.set_exception(result) 60 | 61 | # Make sure no subscriptions get stuck 62 | # on waiting for an initial reply. 63 | self._response_received.set() 64 | 65 | def cancel(self): 66 | """ 67 | Closes the websocket and shutdowns the background thread consuming 68 | messages. 69 | """ 70 | self._cancelled = True 71 | return self._manager.close() 72 | 73 | def cancelled(self): 74 | return self._cancelled 75 | 76 | def running(self): 77 | if self.done(): 78 | return False 79 | return True 80 | 81 | def done(self): 82 | # Assume that None cannot be a valid result 83 | return self._exception is not None or self._result is not None 84 | 85 | def reply(self, timeout=None): 86 | """ 87 | Returns the initial reply. This is emitted before any subscription 88 | data is emitted. This function raises an exception if the subscription 89 | attempt failed. 90 | """ 91 | self._wait_on_signal(self._response_received, timeout) 92 | if self._response_exception is not None: 93 | msg = self._response_exception.msg 94 | raise YamcsError(msg) 95 | elif self._exception: 96 | raise self._exception 97 | return self._response_reply 98 | 99 | def result(self, timeout=None): 100 | err = self.exception(timeout=timeout) 101 | if err is None: 102 | return self._result 103 | raise err 104 | 105 | def exception(self, timeout=None): 106 | self._wait_on_signal(self._completed, timeout) 107 | 108 | if self._result is not None: 109 | return None 110 | 111 | return self._exception 112 | 113 | def _wait_on_signal(self, event, timeout=None): 114 | if not event.wait(timeout=timeout): 115 | # Remark that a timeout does *not* mean that the underlying 116 | # work is canceled. 117 | raise TimeoutError("Timed out.") 118 | 119 | def add_done_callback(self, fn): 120 | if self.done(): 121 | fn(self) 122 | self._callbacks.append(fn) 123 | 124 | def set_result(self, result): 125 | assert not self.done() 126 | 127 | self._result = result 128 | self._completed.set() 129 | for callback in self._callbacks: 130 | callback(self) 131 | 132 | def set_exception(self, exception): 133 | assert not self.done() 134 | 135 | self._exception = exception 136 | self._completed.set() 137 | for callback in self._callbacks: 138 | callback(self) 139 | -------------------------------------------------------------------------------- /yamcs-client/src/yamcs/client/core/pagination.py: -------------------------------------------------------------------------------- 1 | from yamcs.client.core.context import Context 2 | 3 | __all__ = [ 4 | "Iterator", 5 | ] 6 | 7 | 8 | class Iterator: 9 | def __init__( 10 | self, 11 | ctx: Context, 12 | path: str, 13 | params, 14 | response_class, 15 | items_key="items", 16 | item_mapper=None, 17 | ): 18 | self.ctx = ctx 19 | self.path = path 20 | self.params = params 21 | self.response_class = response_class 22 | self.items_key = items_key 23 | self.item_mapper = item_mapper 24 | 25 | self.num_results = 0 26 | self.page_number = 0 27 | self._continuation_token = None 28 | 29 | def __iter__(self): 30 | page_items = self._next_page() 31 | while page_items: 32 | self.page_number += 1 33 | 34 | for item in page_items: 35 | self.num_results += 1 36 | if self.item_mapper: 37 | yield self.item_mapper(item) 38 | else: 39 | yield item 40 | 41 | page_items = self._next_page() 42 | 43 | def _next_page(self): 44 | if self.page_number == 0 or self._continuation_token: 45 | params = dict(self.params) 46 | 47 | # 'next' is only allowed to be used by this class 48 | params.pop("next", None) 49 | if self._continuation_token is not None: 50 | params["next"] = self._continuation_token 51 | 52 | response = self.ctx.get_proto(path=self.path, params=params) 53 | message = self.response_class() 54 | message.ParseFromString(response.content) 55 | items = getattr(message, self.items_key) 56 | self._continuation_token = getattr(message, "continuationToken") 57 | return items 58 | else: 59 | return None 60 | -------------------------------------------------------------------------------- /yamcs-client/src/yamcs/client/filetransfer/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yamcs/python-yamcs-client/24860c21f9f82b02b73240a2b7d3ca547178a331/yamcs-client/src/yamcs/client/filetransfer/__init__.py -------------------------------------------------------------------------------- /yamcs-client/src/yamcs/client/links/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yamcs/python-yamcs-client/24860c21f9f82b02b73240a2b7d3ca547178a331/yamcs-client/src/yamcs/client/links/__init__.py -------------------------------------------------------------------------------- /yamcs-client/src/yamcs/client/links/model.py: -------------------------------------------------------------------------------- 1 | from typing import Optional 2 | 3 | from yamcs.protobuf.cop1 import cop1_pb2 4 | 5 | __all__ = [ 6 | "Cop1Status", 7 | "Cop1Config", 8 | ] 9 | 10 | 11 | class Cop1Status: 12 | """ 13 | COP1 status 14 | """ 15 | 16 | def __init__(self, proto): 17 | self._proto = proto 18 | 19 | @property 20 | def cop1_active(self) -> bool: 21 | return self._proto.cop1Active 22 | 23 | @property 24 | def state(self) -> Optional[str]: 25 | if self._proto.HasField("state"): 26 | return cop1_pb2.Cop1State.Name(self._proto.state) 27 | return None 28 | 29 | @property 30 | def bypass_all(self) -> Optional[bool]: 31 | if self._proto.HasField("setBypassAll"): 32 | return self._proto.setBypassAll 33 | return None 34 | 35 | @property 36 | def v_s(self) -> Optional[int]: 37 | if self._proto.HasField("vS"): 38 | return self._proto.vS 39 | return None 40 | 41 | @property 42 | def nn_r(self) -> Optional[int]: 43 | if self._proto.HasField("nnR"): 44 | return self._proto.nnR 45 | return None 46 | 47 | def __str__(self): 48 | line = f"COP1_ACTIVE: {self.cop1_active}" 49 | if self.cop1_active: 50 | return line + f", state: {self.state}, nn_r: {self.nn_r}, v_s: {self.v_s}" 51 | else: 52 | return line + f", bypass_all: {self.bypass_all}" 53 | 54 | 55 | class Cop1Config: 56 | """ 57 | COP1 configuration 58 | """ 59 | 60 | def __init__(self, proto): 61 | self._proto = proto 62 | 63 | @property 64 | def vc_id(self) -> int: 65 | """ 66 | Virtual Channel ID. 67 | """ 68 | return self._proto.vcId 69 | 70 | @property 71 | def window_width(self) -> int: 72 | return self._proto.windowWidth 73 | 74 | @property 75 | def timeout_type(self) -> str: 76 | return cop1_pb2.TimeoutType.Name(self._proto.timeoutType) 77 | 78 | @property 79 | def tx_limit(self) -> int: 80 | return self._proto.txLimit 81 | 82 | @property 83 | def t1(self) -> float: 84 | return self._proto.t1 / 1000.0 85 | 86 | def __str__(self): 87 | res = f"VC_ID: {self.vc_id}, win: {self.window_width}" 88 | res += f", timeout_type: {self.timeout_type}" 89 | return res + f", tx_limit: {self.tx_limit}, t1: {self.t1}" 90 | -------------------------------------------------------------------------------- /yamcs-client/src/yamcs/client/mdb/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yamcs/python-yamcs-client/24860c21f9f82b02b73240a2b7d3ca547178a331/yamcs-client/src/yamcs/client/mdb/__init__.py -------------------------------------------------------------------------------- /yamcs-client/src/yamcs/client/storage/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yamcs/python-yamcs-client/24860c21f9f82b02b73240a2b7d3ca547178a331/yamcs-client/src/yamcs/client/storage/__init__.py -------------------------------------------------------------------------------- /yamcs-client/src/yamcs/client/storage/client.py: -------------------------------------------------------------------------------- 1 | from typing import IO, Any, Iterable, Mapping, Optional, Union 2 | 3 | from yamcs.client.core.context import Context 4 | from yamcs.client.core.exceptions import NotFound 5 | from yamcs.client.storage.model import Bucket, ObjectListing 6 | from yamcs.protobuf.buckets import buckets_pb2 7 | 8 | __all__ = [ 9 | "StorageClient", 10 | ] 11 | 12 | 13 | class StorageClient: 14 | """ 15 | Client for working with buckets and objects managed by Yamcs. 16 | """ 17 | 18 | def __init__(self, ctx: Context): 19 | super(StorageClient, self).__init__() 20 | self.ctx = ctx 21 | 22 | def list_buckets(self) -> Iterable[Bucket]: 23 | """ 24 | List the buckets. 25 | """ 26 | # Server does not do pagination on listings of this resource. 27 | # Return an iterator anyway for similarity with other API methods 28 | response = self.ctx.get_proto(path="/storage/buckets") 29 | message = buckets_pb2.ListBucketsResponse() 30 | message.ParseFromString(response.content) 31 | buckets = getattr(message, "buckets") 32 | return iter([Bucket(bucket, self) for bucket in buckets]) 33 | 34 | def get_bucket(self, name: str, create=False) -> Bucket: 35 | """ 36 | Get a specific bucket. 37 | 38 | :param name: 39 | The bucket name. 40 | :param create: 41 | If specified, create the bucket if it does not yet exist. 42 | """ 43 | url = "/storage/buckets/" + name 44 | 45 | if create: 46 | try: 47 | response = self.ctx.get_proto(path=url) 48 | except NotFound: 49 | self.create_bucket(name) 50 | response = self.ctx.get_proto(path=url) 51 | else: 52 | response = self.ctx.get_proto(path=url) 53 | message = buckets_pb2.BucketInfo() 54 | message.ParseFromString(response.content) 55 | return Bucket(message, self) 56 | 57 | def list_objects( 58 | self, 59 | bucket_name: str, 60 | prefix: Optional[str] = None, 61 | delimiter: Optional[str] = None, 62 | ) -> ObjectListing: 63 | """ 64 | List the objects for a bucket. 65 | 66 | :param bucket_name: 67 | The name of the bucket. 68 | :param prefix: 69 | If specified, only objects that start with this 70 | prefix are listed. 71 | :param delimiter: 72 | If specified, return only objects whose name 73 | do not contain the delimiter after the prefix. 74 | For the other objects, the response contains 75 | (in the prefix response parameter) the name 76 | truncated after the delimiter. Duplicates are 77 | omitted. 78 | """ 79 | url = f"/storage/buckets/{bucket_name}/objects" 80 | params = {} 81 | if prefix is not None: 82 | params["prefix"] = prefix 83 | if delimiter is not None: 84 | params["delimiter"] = delimiter 85 | response = self.ctx.get_proto(path=url, params=params) 86 | message = buckets_pb2.ListObjectsResponse() 87 | message.ParseFromString(response.content) 88 | return ObjectListing(message, bucket_name, self) 89 | 90 | def create_bucket(self, bucket_name: str): 91 | """ 92 | Create a new bucket. 93 | 94 | :param bucket_name: 95 | The name of the bucket. 96 | """ 97 | req = buckets_pb2.CreateBucketRequest() 98 | req.name = bucket_name 99 | url = "/storage/buckets" 100 | self.ctx.post_proto(url, data=req.SerializeToString()) 101 | 102 | def remove_bucket(self, bucket_name: str): 103 | """ 104 | Remove a bucket. 105 | 106 | :param bucket_name: 107 | The name of the bucket. 108 | """ 109 | url = f"/storage/buckets/{bucket_name}" 110 | self.ctx.delete_proto(url) 111 | 112 | def download_object(self, bucket_name: str, object_name: str) -> bytes: 113 | """ 114 | Download an object. 115 | 116 | :param bucket_name: 117 | The name of the bucket. 118 | :param object_name: 119 | The object to fetch. 120 | """ 121 | url = f"/storage/buckets/{bucket_name}/objects/{object_name}" 122 | response = self.ctx.get_proto(path=url) 123 | return response.content 124 | 125 | def upload_object( 126 | self, 127 | bucket_name: str, 128 | object_name: str, 129 | file_obj: Union[str, IO], 130 | content_type: Optional[str] = None, 131 | metadata: Optional[Mapping[str, str]] = None, 132 | ): 133 | """ 134 | Upload an object to a bucket. 135 | 136 | :param bucket_name: 137 | The name of the bucket. 138 | :param object_name: 139 | The target name of the object. 140 | :param file_obj: 141 | The file (or file-like object) to upload. 142 | :param content_type: 143 | The content type associated to this object. 144 | This is mainly useful when accessing an object 145 | directly via a web browser. If unspecified, a 146 | content type *may* be automatically derived 147 | from the specified ``file_obj``. 148 | :param metadata: 149 | Optional metadata associated to this object. 150 | """ 151 | url = f"/storage/buckets/{bucket_name}/objects/{object_name}" 152 | if content_type: 153 | files: Any = {object_name: (object_name, file_obj, content_type)} 154 | else: 155 | files: Any = {object_name: (object_name, file_obj)} 156 | if metadata: 157 | for k, v in metadata.items(): 158 | files[k] = (None, v) 159 | self.ctx.request(path=url, method="post", files=files) 160 | 161 | def remove_object(self, bucket_name: str, object_name: str): 162 | """ 163 | Remove an object from a bucket. 164 | 165 | :param bucket_name: 166 | The name of the bucket. 167 | :param object_name: 168 | The object to remove. 169 | """ 170 | url = f"/storage/buckets/{bucket_name}/objects/{object_name}" 171 | self.ctx.delete_proto(url) 172 | -------------------------------------------------------------------------------- /yamcs-client/src/yamcs/client/storage/model.py: -------------------------------------------------------------------------------- 1 | import datetime 2 | from typing import IO, TYPE_CHECKING, List, Mapping, Optional, Union 3 | 4 | from yamcs.client.core.helpers import parse_server_time 5 | 6 | if TYPE_CHECKING: 7 | from yamcs.client.storage.client import StorageClient 8 | 9 | 10 | __all__ = [ 11 | "Bucket", 12 | "ObjectInfo", 13 | "ObjectListing", 14 | ] 15 | 16 | 17 | class Bucket: 18 | def __init__(self, proto, storage_client: "StorageClient"): 19 | self._proto = proto 20 | self._storage_client = storage_client 21 | 22 | @property 23 | def name(self) -> str: 24 | """Name of this bucket.""" 25 | return self._proto.name 26 | 27 | @property 28 | def created(self) -> datetime.datetime: 29 | """ 30 | When this bucket was created. 31 | """ 32 | return parse_server_time(self._proto.created) 33 | 34 | @property 35 | def object_count(self) -> int: 36 | """Number of objects in this bucket.""" 37 | return self._proto.numObjects 38 | 39 | @property 40 | def max_object_count(self) -> Optional[int]: 41 | """Maximum allowed number of objects.""" 42 | if self._proto.HasField("maxObjects"): 43 | return self._proto.maxObjects 44 | return None 45 | 46 | @property 47 | def size(self) -> int: 48 | """Total size in bytes of this bucket (excluding metadata).""" 49 | return self._proto.size 50 | 51 | @property 52 | def max_size(self) -> Optional[int]: 53 | """Maximum allowed total size of all objects.""" 54 | if self._proto.HasField("maxSize"): 55 | return self._proto.maxSize 56 | return None 57 | 58 | @property 59 | def directory(self) -> Optional[str]: 60 | """ 61 | Bucket root directory. This field is only set when 62 | the bucket is mapped to the file system. Therefore 63 | it is not set for buckets that store objects in 64 | RocksDB. 65 | """ 66 | if self._proto.HasField("directory"): 67 | return self._proto.directory 68 | return None 69 | 70 | def list_objects( 71 | self, prefix: Optional[str] = None, delimiter: Optional[str] = None 72 | ): 73 | """ 74 | List the objects for this bucket. 75 | 76 | :param prefix: 77 | If specified, only objects that start with this prefix are listed. 78 | :param delimiter: 79 | If specified, return only objects whose name 80 | do not contain the delimiter after the prefix. 81 | For the other objects, the response contains 82 | (in the prefix response parameter) the name 83 | truncated after the delimiter. Duplicates are 84 | omitted. 85 | """ 86 | return self._storage_client.list_objects( 87 | bucket_name=self.name, 88 | prefix=prefix, 89 | delimiter=delimiter, 90 | ) 91 | 92 | def download_object(self, object_name: str) -> bytes: 93 | """ 94 | Download an object. 95 | 96 | :param object_name: 97 | The object to fetch. 98 | """ 99 | return self._storage_client.download_object(self.name, object_name) 100 | 101 | def upload_object( 102 | self, 103 | object_name: str, 104 | file_obj: Union[str, IO], 105 | content_type: Optional[str] = None, 106 | metadata: Optional[Mapping[str, str]] = None, 107 | ): 108 | """ 109 | Upload an object to this bucket. 110 | 111 | :param object_name: 112 | The target name of the object. 113 | :param file_obj: 114 | The file (or file-like object) to upload. 115 | :param content_type: 116 | The content type associated to this object. 117 | This is mainly useful when accessing an object 118 | directly via a web browser. If unspecified, a 119 | content type *may* be automatically derived 120 | from the specified ``file_obj``. 121 | :param metadata: 122 | Optional metadata associated to this object. 123 | """ 124 | return self._storage_client.upload_object( 125 | bucket_name=self.name, 126 | object_name=object_name, 127 | file_obj=file_obj, 128 | content_type=content_type, 129 | metadata=metadata, 130 | ) 131 | 132 | def delete_object(self, object_name: str): 133 | """ 134 | Remove an object from this bucket. 135 | 136 | :param object_name: 137 | The object to remove. 138 | """ 139 | self._storage_client.remove_object(self.name, object_name) 140 | 141 | def delete(self): 142 | """ 143 | Remove this bucket in its entirety. 144 | """ 145 | self._storage_client.remove_bucket(self.name) 146 | 147 | def __str__(self): 148 | return self.name 149 | 150 | 151 | class ObjectInfo: 152 | def __init__(self, proto, bucket, storage_client): 153 | self._proto = proto 154 | self._bucket = bucket 155 | self._storage_client = storage_client 156 | 157 | @property 158 | def name(self) -> str: 159 | """ 160 | The name of this object. 161 | """ 162 | return self._proto.name 163 | 164 | @property 165 | def size(self) -> int: 166 | """ 167 | Size in bytes of this object (excluding metadata). 168 | """ 169 | return self._proto.size 170 | 171 | @property 172 | def created(self) -> datetime.datetime: 173 | """ 174 | Return when this object was created (or re-created). 175 | """ 176 | return parse_server_time(self._proto.created) 177 | 178 | def delete(self): 179 | """ 180 | Remove this object. 181 | """ 182 | self._storage_client.remove_object(self._bucket, self.name) 183 | 184 | def download(self): 185 | """ 186 | Download this object. 187 | """ 188 | return self._storage_client.download_object(self._bucket, self.name) 189 | 190 | def upload( 191 | self, 192 | file_obj: Union[str, IO], 193 | metadata: Optional[Mapping[str, str]] = None, 194 | ): 195 | """ 196 | Replace the content of this object. 197 | 198 | :param file_obj: 199 | The file (or file-like object) to upload. 200 | :param metadata: 201 | Optional metadata associated to this object. 202 | """ 203 | return self._storage_client.upload_object( 204 | bucket_name=self._bucket, 205 | object_name=self.name, 206 | file_obj=file_obj, 207 | metadata=metadata, 208 | ) 209 | 210 | def __str__(self): 211 | return f"{self.name} ({self.size} bytes, created {self.created})" 212 | 213 | 214 | class ObjectListing: 215 | def __init__(self, proto, bucket, storage_client): 216 | self._proto = proto 217 | self._bucket = bucket 218 | self._storage_client = storage_client 219 | 220 | @property 221 | def prefixes(self) -> List[str]: 222 | """ 223 | The prefixes in this listing. 224 | """ 225 | return [p for p in self._proto.prefixes] 226 | 227 | @property 228 | def objects(self) -> List[ObjectInfo]: 229 | """ 230 | The objects in this listing. 231 | """ 232 | return [ 233 | ObjectInfo(o, self._bucket, self._storage_client) 234 | for o in self._proto.objects 235 | ] 236 | -------------------------------------------------------------------------------- /yamcs-client/src/yamcs/client/tco/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yamcs/python-yamcs-client/24860c21f9f82b02b73240a2b7d3ca547178a331/yamcs-client/src/yamcs/client/tco/__init__.py -------------------------------------------------------------------------------- /yamcs-client/src/yamcs/client/tco/client.py: -------------------------------------------------------------------------------- 1 | import datetime 2 | from typing import List, Optional 3 | 4 | from yamcs.client.core.context import Context 5 | from yamcs.client.core.helpers import to_server_time 6 | from yamcs.client.tco.model import TCOStatus, TofInterval 7 | from yamcs.protobuf.tco import tco_pb2 8 | 9 | __all__ = [ 10 | "TCOClient", 11 | ] 12 | 13 | 14 | class TCOClient: 15 | """ 16 | Client for interacting with a Time Correlation service managed by Yamcs. 17 | """ 18 | 19 | def __init__(self, ctx: Context, instance: str, service: str): 20 | super(TCOClient, self).__init__() 21 | self.ctx = ctx 22 | self._instance = instance 23 | self._service = service 24 | 25 | def get_status(self) -> TCOStatus: 26 | """ 27 | Retrieve the TCO status. 28 | """ 29 | response = self.ctx.get_proto(f"/tco/{self._instance}/{self._service}/status") 30 | message = tco_pb2.TcoStatus() 31 | message.ParseFromString(response.content) 32 | return TCOStatus(message) 33 | 34 | def reconfigure( 35 | self, 36 | accuracy: Optional[float] = None, 37 | validity: Optional[float] = None, 38 | ob_delay: Optional[float] = None, 39 | default_tof: Optional[float] = None, 40 | ): 41 | """ 42 | Updates one or more TCO options 43 | 44 | :param accuracy: 45 | Accuracy in seconds. 46 | :param validity: 47 | Validity in seconds. 48 | :param ob_delay: 49 | Onboard delay in seconds. 50 | :param default_tof: 51 | Default ToF in seconds. This value is used if the ToF estimator 52 | does not find a matching interval. 53 | """ 54 | req = tco_pb2.TcoConfig() 55 | if accuracy is not None: 56 | req.accuracy = accuracy 57 | if validity is not None: 58 | req.validity = validity 59 | if ob_delay is not None: 60 | req.onboardDelay = ob_delay 61 | if default_tof is not None: 62 | req.defaultTof = default_tof 63 | 64 | url = f"/tco/{self._instance}/{self._service}/config" 65 | self.ctx.post_proto(url, data=req.SerializeToString()) # TODO should be patch 66 | 67 | def add_tof_interval( 68 | self, start: datetime.datetime, stop: datetime.datetime, polynomial: List[float] 69 | ): 70 | """ 71 | Defines a ToF interval for the ERT range ``[start, stop]``, specifying 72 | a polynomial function of the form: `tof = a + bx + cx^2 + ...` where `x` 73 | is ERT minus the provided start date. 74 | 75 | :param start: 76 | ERT start 77 | :param stop: 78 | ERT stop 79 | :param polynomial: 80 | Coefficients in the order ``[a, b, c, ...]`` 81 | """ 82 | self.add_tof_intervals([TofInterval(start, stop, polynomial)]) 83 | 84 | def add_tof_intervals(self, intervals: List[TofInterval]): 85 | """ 86 | Adds multiple ToF intervals at once. 87 | 88 | :param intervals: 89 | List of ToF intervals. 90 | """ 91 | req = tco_pb2.AddTimeOfFlightIntervalsRequest() 92 | for interval in intervals: 93 | tof = req.intervals.add() 94 | tof.ertStart.MergeFrom(to_server_time(interval.start)) 95 | tof.ertStop.MergeFrom(to_server_time(interval.stop)) 96 | tof.polCoef.extend(interval.polynomial) 97 | 98 | url = f"/tco/{self._instance}/{self._service}/tof:addIntervals" 99 | self.ctx.post_proto(url, data=req.SerializeToString()) 100 | 101 | def remove_tof_intervals(self, start: datetime.datetime, stop: datetime.datetime): 102 | """ 103 | Removes previously registered ToF intervals whose start date 104 | falls in the specified range ``[start, stop]``. 105 | 106 | :param start: 107 | ERT start 108 | :param stop: 109 | ERT stop 110 | """ 111 | req = tco_pb2.DeleteTimeOfFlightIntervalsRequest() 112 | req.start.MergeFrom(to_server_time(start)) 113 | req.stop.MergeFrom(to_server_time(stop)) 114 | 115 | url = f"/tco/{self._instance}/{self._service}/tof:deleteIntervals" 116 | self.ctx.post_proto(url, data=req.SerializeToString()) 117 | 118 | def reset_coefficients(self): 119 | """ 120 | Resets current TCO coefficients, as well as any 121 | collected samples. 122 | """ 123 | url = f"/tco/{self._instance}/{self._service}:reset" 124 | self.ctx.post_proto(url) 125 | 126 | def override_coefficients( 127 | self, utc: datetime.datetime, obt: int, gradient: float = 0, offset: float = 0 128 | ): 129 | """ 130 | Manually override the assocation between UTC and 131 | onboard time. 132 | 133 | .. note:: 134 | If later on you want to revert to automatically computed 135 | coefficients, use :meth:`reset_coefficients`. 136 | 137 | :param utc: 138 | UTC 139 | :param obt: 140 | Onboard time 141 | :param gradient: 142 | Gradient 143 | :param offset: 144 | Offset 145 | """ 146 | req = tco_pb2.TcoCoefficients() 147 | req.utc.MergeFrom(to_server_time(utc)) 148 | req.obt = obt 149 | req.gradient = gradient 150 | req.offset = offset 151 | 152 | url = f"/tco/{self._instance}/{self._service}/coefficients" 153 | self.ctx.post_proto(url, data=req.SerializeToString()) 154 | -------------------------------------------------------------------------------- /yamcs-client/src/yamcs/client/tco/model.py: -------------------------------------------------------------------------------- 1 | import datetime 2 | from typing import List, Optional 3 | 4 | from yamcs.client.core.helpers import parse_server_time 5 | 6 | __all__ = [ 7 | "TCOStatus", 8 | "TCOCoefficients", 9 | "TCOSample", 10 | "TofInterval", 11 | ] 12 | 13 | 14 | class TCOStatus: 15 | """ 16 | TCO Status 17 | """ 18 | 19 | def __init__(self, proto): 20 | self._proto = proto 21 | 22 | @property 23 | def coefficients(self) -> Optional["TCOCoefficients"]: 24 | """ 25 | Current coefficients. Or ``None`` if the synchronization is not 26 | yet established. 27 | """ 28 | if self._proto.HasField("coefficients"): 29 | return TCOCoefficients(self._proto.coefficients) 30 | return None 31 | 32 | @property 33 | def coefficients_time(self) -> Optional[datetime.datetime]: 34 | """ 35 | Time when the coefficients have been computed 36 | """ 37 | if self._proto.HasField("coefficientsTime"): 38 | return parse_server_time(self._proto.coefficientsTime) 39 | return None 40 | 41 | @property 42 | def deviation(self) -> Optional[float]: 43 | """ 44 | Last computed deviation 45 | """ 46 | if self._proto.HasField("deviation"): 47 | return self._proto.deviation 48 | return None 49 | 50 | @property 51 | def samples(self) -> List["TCOSample"]: 52 | """ 53 | The last accumulated samples 54 | """ 55 | return [TCOSample(p) for p in self._proto.samples] 56 | 57 | 58 | class TCOCoefficients: 59 | """ 60 | TCO Coefficients 61 | """ 62 | 63 | def __init__(self, proto): 64 | self._proto = proto 65 | 66 | @property 67 | def utc(self) -> Optional[datetime.datetime]: 68 | if self._proto.HasField("utc"): 69 | return parse_server_time(self._proto.utc) 70 | return None 71 | 72 | @property 73 | def obt(self) -> Optional[int]: 74 | if self._proto.HasField("obt"): 75 | return self._proto.obt 76 | return None 77 | 78 | @property 79 | def gradient(self) -> Optional[float]: 80 | if self._proto.HasField("gradient"): 81 | return self._proto.gradient 82 | return None 83 | 84 | @property 85 | def offset(self) -> Optional[float]: 86 | if self._proto.HasField("offset"): 87 | return self._proto.offset 88 | return None 89 | 90 | 91 | class TCOSample: 92 | def __init__(self, proto): 93 | self._proto = proto 94 | 95 | @property 96 | def utc(self) -> Optional[datetime.datetime]: 97 | if self._proto.HasField("utc"): 98 | return parse_server_time(self._proto.utc) 99 | return None 100 | 101 | @property 102 | def obt(self) -> Optional[int]: 103 | if self._proto.HasField("obt"): 104 | return self._proto.obt 105 | return None 106 | 107 | def __str__(self): 108 | return f"({self.utc}, {self.obt})" 109 | 110 | 111 | class TofInterval: 112 | """ 113 | ToF interval for the ERT range ``[start, stop]``, specifying 114 | a polynomial function of the form: `tof = a + bx + cx^2 + ...` where `x` 115 | is ERT minus the provided start date. 116 | """ 117 | 118 | def __init__( 119 | self, start: datetime.datetime, stop: datetime.datetime, polynomial: List[float] 120 | ): 121 | """ 122 | :param start: 123 | ERT start 124 | :param stop: 125 | ERT stop 126 | :param polynomial: 127 | Coefficients in the order ``[a, b, c, ...]`` 128 | """ 129 | self.start = start 130 | self.stop = stop 131 | self.polynomial = polynomial 132 | -------------------------------------------------------------------------------- /yamcs-client/src/yamcs/client/timeline/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yamcs/python-yamcs-client/24860c21f9f82b02b73240a2b7d3ca547178a331/yamcs-client/src/yamcs/client/timeline/__init__.py -------------------------------------------------------------------------------- /yamcs-client/src/yamcs/client/tmtc/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yamcs/python-yamcs-client/24860c21f9f82b02b73240a2b7d3ca547178a331/yamcs-client/src/yamcs/client/tmtc/__init__.py -------------------------------------------------------------------------------- /yamcs-client/src/yamcs/clientversion.py: -------------------------------------------------------------------------------- 1 | """ 2 | Old-style. For backwards compatibility. 3 | Avoid use. 4 | """ 5 | 6 | from yamcs.client.clientversion import __version__ # noqa 7 | -------------------------------------------------------------------------------- /yamcs-client/src/yamcs/core/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | Old-style. For backwards compatibility. 3 | Avoid use. 4 | """ 5 | 6 | from yamcs.client.core import GLOBAL_INSTANCE # noqa 7 | -------------------------------------------------------------------------------- /yamcs-client/src/yamcs/core/auth.py: -------------------------------------------------------------------------------- 1 | """ 2 | Old-style. For backwards compatibility. 3 | Avoid use. 4 | """ 5 | 6 | from yamcs.client.core.auth import ( # noqa 7 | APIKeyCredentials, 8 | BasicAuthCredentials, 9 | Credentials, 10 | ) 11 | -------------------------------------------------------------------------------- /yamcs-client/src/yamcs/core/context.py: -------------------------------------------------------------------------------- 1 | """ 2 | Old-style. For backwards compatibility. 3 | Avoid use. 4 | """ 5 | 6 | from yamcs.client.core.context import Context # noqa 7 | -------------------------------------------------------------------------------- /yamcs-client/src/yamcs/core/exceptions.py: -------------------------------------------------------------------------------- 1 | """ 2 | Old-style. For backwards compatibility. 3 | Avoid use. 4 | """ 5 | 6 | from yamcs.client.core.exceptions import ( # noqa 7 | ConnectionFailure, 8 | NotFound, 9 | TimeoutError, 10 | Unauthorized, 11 | YamcsError, 12 | ) 13 | -------------------------------------------------------------------------------- /yamcs-client/src/yamcs/core/futures.py: -------------------------------------------------------------------------------- 1 | """ 2 | Old-style. For backwards compatibility. 3 | Avoid use. 4 | """ 5 | 6 | from yamcs.client.core.futures import WebSocketSubscriptionFuture # noqa 7 | -------------------------------------------------------------------------------- /yamcs-client/src/yamcs/core/helpers.py: -------------------------------------------------------------------------------- 1 | """ 2 | Old-style. For backwards compatibility. 3 | Avoid use. 4 | """ 5 | 6 | from yamcs.client.core.helpers import ( # noqa 7 | FixedDelay, 8 | ProtoList, 9 | adapt_name_for_rest, 10 | delimit_protobuf, 11 | do_get, 12 | do_post, 13 | do_request, 14 | parse_server_time, 15 | parse_server_timestring, 16 | parse_value, 17 | split_protobuf_stream, 18 | to_argument_value, 19 | to_isostring, 20 | to_named_object_id, 21 | to_named_object_ids, 22 | to_server_time, 23 | ) 24 | -------------------------------------------------------------------------------- /yamcs-client/src/yamcs/core/pagination.py: -------------------------------------------------------------------------------- 1 | """ 2 | Old-style. For backwards compatibility. 3 | Avoid use. 4 | """ 5 | 6 | from yamcs.client.core.pagination import Iterator # noqa 7 | -------------------------------------------------------------------------------- /yamcs-client/src/yamcs/core/subscriptions.py: -------------------------------------------------------------------------------- 1 | """ 2 | Old-style. For backwards compatibility. 3 | Avoid use. 4 | """ 5 | 6 | from yamcs.client.core.subscriptions import WebSocketSubscriptionManager # noqa 7 | -------------------------------------------------------------------------------- /yamcs-client/src/yamcs/filetransfer/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | Old-style. For backwards compatibility. 3 | Avoid use. 4 | """ 5 | 6 | from yamcs.client.filetransfer.client import FileTransferClient # noqa 7 | -------------------------------------------------------------------------------- /yamcs-client/src/yamcs/filetransfer/client.py: -------------------------------------------------------------------------------- 1 | """ 2 | Old-style. For backwards compatibility. 3 | Avoid use. 4 | """ 5 | 6 | from yamcs.client.filetransfer.model import ( # noqa 7 | FileListSubscription, 8 | FileTransferClient, 9 | FileTransferServiceClient, 10 | TransferSubscription, 11 | ) 12 | 13 | ServiceClient = FileTransferServiceClient 14 | """ 15 | Temporary backwards compatibility. 16 | Prefer to use the class 'FileTransferServiceService'. 17 | """ 18 | -------------------------------------------------------------------------------- /yamcs-client/src/yamcs/filetransfer/model.py: -------------------------------------------------------------------------------- 1 | """ 2 | Old-style. For backwards compatibility. 3 | Avoid use. 4 | """ 5 | 6 | from yamcs.client.filetransfer.model import ( # noqa 7 | EntityInfo, 8 | FileTransferCapabilities, 9 | FileTransferOption, 10 | FileTransferService, 11 | RemoteFile, 12 | RemoteFileListing, 13 | Transfer, 14 | ) 15 | 16 | Service = FileTransferService 17 | """ 18 | Temporary backwards compatibility. 19 | Prefer to use the class 'FileTransferService'. 20 | """ 21 | -------------------------------------------------------------------------------- /yamcs-client/src/yamcs/link/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yamcs/python-yamcs-client/24860c21f9f82b02b73240a2b7d3ca547178a331/yamcs-client/src/yamcs/link/__init__.py -------------------------------------------------------------------------------- /yamcs-client/src/yamcs/link/client.py: -------------------------------------------------------------------------------- 1 | """ 2 | Old-style. For backwards compatibility. 3 | Avoid use. 4 | """ 5 | 6 | from yamcs.client.links.client import Cop1Subscription, LinkClient # noqa 7 | -------------------------------------------------------------------------------- /yamcs-client/src/yamcs/link/model.py: -------------------------------------------------------------------------------- 1 | """ 2 | Old-style. For backwards compatibility. 3 | Avoid use. 4 | """ 5 | 6 | from yamcs.client.links.model import Cop1Config, Cop1Status # noqa 7 | -------------------------------------------------------------------------------- /yamcs-client/src/yamcs/mdb/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yamcs/python-yamcs-client/24860c21f9f82b02b73240a2b7d3ca547178a331/yamcs-client/src/yamcs/mdb/__init__.py -------------------------------------------------------------------------------- /yamcs-client/src/yamcs/mdb/client.py: -------------------------------------------------------------------------------- 1 | """ 2 | Old-style. For backwards compatibility. 3 | Avoid use. 4 | """ 5 | 6 | from yamcs.client.mdb.client import MDBClient # noqa 7 | -------------------------------------------------------------------------------- /yamcs-client/src/yamcs/mdb/model.py: -------------------------------------------------------------------------------- 1 | """ 2 | Old-style. For backwards compatibility. 3 | Avoid use. 4 | """ 5 | 6 | from yamcs.client.mdb.model import ( # noqa 7 | Algorithm, 8 | Argument, 9 | ArgumentType, 10 | ArrayType, 11 | Command, 12 | Container, 13 | DataEncoding, 14 | EnumValue, 15 | Member, 16 | MissionDatabaseItem, 17 | Parameter, 18 | ParameterType, 19 | RangeSet, 20 | Significance, 21 | SpaceSystem, 22 | ) 23 | -------------------------------------------------------------------------------- /yamcs-client/src/yamcs/model.py: -------------------------------------------------------------------------------- 1 | """ 2 | Old-style. For backwards compatibility. 3 | Avoid use. 4 | """ 5 | 6 | from yamcs.client.model import ( # noqa 7 | AuthInfo, 8 | Event, 9 | Instance, 10 | InstanceTemplate, 11 | Link, 12 | LinkAction, 13 | LoadParameterValuesResult, 14 | ObjectPrivilege, 15 | Processor, 16 | RdbTablespace, 17 | ServerInfo, 18 | Service, 19 | UserInfo, 20 | ) 21 | -------------------------------------------------------------------------------- /yamcs-client/src/yamcs/protobuf/actions/actions_pb2.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by the protocol buffer compiler. DO NOT EDIT! 3 | # source: yamcs/protobuf/actions/actions.proto 4 | 5 | from google.protobuf import descriptor as _descriptor 6 | from google.protobuf import message as _message 7 | from google.protobuf import reflection as _reflection 8 | from google.protobuf import symbol_database as _symbol_database 9 | # @@protoc_insertion_point(imports) 10 | 11 | _sym_db = _symbol_database.Default() 12 | 13 | 14 | from yamcs.protobuf.config import config_pb2 as yamcs_dot_protobuf_dot_config_dot_config__pb2 15 | 16 | 17 | DESCRIPTOR = _descriptor.FileDescriptor( 18 | name='yamcs/protobuf/actions/actions.proto', 19 | package='yamcs.protobuf.actions', 20 | syntax='proto2', 21 | serialized_options=b'\n\032org.yamcs.protobuf.actionsB\014ActionsProtoP\001', 22 | serialized_pb=b'\n$yamcs/protobuf/actions/actions.proto\x12\x16yamcs.protobuf.actions\x1a\"yamcs/protobuf/config/config.proto\"\x87\x01\n\nActionInfo\x12\n\n\x02id\x18\x01 \x01(\t\x12\r\n\x05label\x18\x02 \x01(\t\x12\r\n\x05style\x18\x03 \x01(\t\x12\x0f\n\x07\x65nabled\x18\x04 \x01(\x08\x12\x0f\n\x07\x63hecked\x18\x05 \x01(\x08\x12-\n\x04spec\x18\x06 \x01(\x0b\x32\x1f.yamcs.protobuf.config.SpecInfoB,\n\x1aorg.yamcs.protobuf.actionsB\x0c\x41\x63tionsProtoP\x01' 23 | , 24 | dependencies=[yamcs_dot_protobuf_dot_config_dot_config__pb2.DESCRIPTOR,]) 25 | 26 | 27 | 28 | 29 | _ACTIONINFO = _descriptor.Descriptor( 30 | name='ActionInfo', 31 | full_name='yamcs.protobuf.actions.ActionInfo', 32 | filename=None, 33 | file=DESCRIPTOR, 34 | containing_type=None, 35 | fields=[ 36 | _descriptor.FieldDescriptor( 37 | name='id', full_name='yamcs.protobuf.actions.ActionInfo.id', index=0, 38 | number=1, type=9, cpp_type=9, label=1, 39 | has_default_value=False, default_value=b"".decode('utf-8'), 40 | message_type=None, enum_type=None, containing_type=None, 41 | is_extension=False, extension_scope=None, 42 | serialized_options=None, file=DESCRIPTOR), 43 | _descriptor.FieldDescriptor( 44 | name='label', full_name='yamcs.protobuf.actions.ActionInfo.label', index=1, 45 | number=2, type=9, cpp_type=9, label=1, 46 | has_default_value=False, default_value=b"".decode('utf-8'), 47 | message_type=None, enum_type=None, containing_type=None, 48 | is_extension=False, extension_scope=None, 49 | serialized_options=None, file=DESCRIPTOR), 50 | _descriptor.FieldDescriptor( 51 | name='style', full_name='yamcs.protobuf.actions.ActionInfo.style', index=2, 52 | number=3, type=9, cpp_type=9, label=1, 53 | has_default_value=False, default_value=b"".decode('utf-8'), 54 | message_type=None, enum_type=None, containing_type=None, 55 | is_extension=False, extension_scope=None, 56 | serialized_options=None, file=DESCRIPTOR), 57 | _descriptor.FieldDescriptor( 58 | name='enabled', full_name='yamcs.protobuf.actions.ActionInfo.enabled', index=3, 59 | number=4, type=8, cpp_type=7, label=1, 60 | has_default_value=False, default_value=False, 61 | message_type=None, enum_type=None, containing_type=None, 62 | is_extension=False, extension_scope=None, 63 | serialized_options=None, file=DESCRIPTOR), 64 | _descriptor.FieldDescriptor( 65 | name='checked', full_name='yamcs.protobuf.actions.ActionInfo.checked', index=4, 66 | number=5, type=8, cpp_type=7, label=1, 67 | has_default_value=False, default_value=False, 68 | message_type=None, enum_type=None, containing_type=None, 69 | is_extension=False, extension_scope=None, 70 | serialized_options=None, file=DESCRIPTOR), 71 | _descriptor.FieldDescriptor( 72 | name='spec', full_name='yamcs.protobuf.actions.ActionInfo.spec', index=5, 73 | number=6, type=11, cpp_type=10, label=1, 74 | has_default_value=False, default_value=None, 75 | message_type=None, enum_type=None, containing_type=None, 76 | is_extension=False, extension_scope=None, 77 | serialized_options=None, file=DESCRIPTOR), 78 | ], 79 | extensions=[ 80 | ], 81 | nested_types=[], 82 | enum_types=[ 83 | ], 84 | serialized_options=None, 85 | is_extendable=False, 86 | syntax='proto2', 87 | extension_ranges=[], 88 | oneofs=[ 89 | ], 90 | serialized_start=101, 91 | serialized_end=236, 92 | ) 93 | 94 | _ACTIONINFO.fields_by_name['spec'].message_type = yamcs_dot_protobuf_dot_config_dot_config__pb2._SPECINFO 95 | DESCRIPTOR.message_types_by_name['ActionInfo'] = _ACTIONINFO 96 | _sym_db.RegisterFileDescriptor(DESCRIPTOR) 97 | 98 | ActionInfo = _reflection.GeneratedProtocolMessageType('ActionInfo', (_message.Message,), { 99 | 'DESCRIPTOR' : _ACTIONINFO, 100 | '__module__' : 'yamcs.protobuf.actions.actions_pb2' 101 | # @@protoc_insertion_point(class_scope:yamcs.protobuf.actions.ActionInfo) 102 | }) 103 | _sym_db.RegisterMessage(ActionInfo) 104 | 105 | 106 | DESCRIPTOR._options = None 107 | # @@protoc_insertion_point(module_scope) 108 | -------------------------------------------------------------------------------- /yamcs-client/src/yamcs/protobuf/packets/packets_pb2.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by the protocol buffer compiler. DO NOT EDIT! 3 | # source: yamcs/protobuf/packets/packets.proto 4 | 5 | from google.protobuf import descriptor as _descriptor 6 | from google.protobuf import message as _message 7 | from google.protobuf import reflection as _reflection 8 | from google.protobuf import symbol_database as _symbol_database 9 | # @@protoc_insertion_point(imports) 10 | 11 | _sym_db = _symbol_database.Default() 12 | 13 | 14 | from google.protobuf import timestamp_pb2 as google_dot_protobuf_dot_timestamp__pb2 15 | from yamcs.protobuf import yamcs_pb2 as yamcs_dot_protobuf_dot_yamcs__pb2 16 | 17 | 18 | DESCRIPTOR = _descriptor.FileDescriptor( 19 | name='yamcs/protobuf/packets/packets.proto', 20 | package='yamcs.protobuf.packets', 21 | syntax='proto2', 22 | serialized_options=b'\n\022org.yamcs.protobufB\014PacketsProtoP\001', 23 | serialized_pb=b'\n$yamcs/protobuf/packets/packets.proto\x12\x16yamcs.protobuf.packets\x1a\x1fgoogle/protobuf/timestamp.proto\x1a\x1ayamcs/protobuf/yamcs.proto\"\x9c\x02\n\x0cTmPacketData\x12\x0e\n\x06packet\x18\x02 \x01(\x0c\x12\x16\n\x0esequenceNumber\x18\x04 \x01(\x05\x12)\n\x02id\x18\x05 \x01(\x0b\x32\x1d.yamcs.protobuf.NamedObjectId\x12\x32\n\x0egenerationTime\x18\t \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12\x36\n\x12\x65\x61rthReceptionTime\x18\n \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12\x31\n\rreceptionTime\x18\x08 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12\x0c\n\x04link\x18\x0b \x01(\t\x12\x0c\n\x04size\x18\x0c \x01(\x05\x42$\n\x12org.yamcs.protobufB\x0cPacketsProtoP\x01' 24 | , 25 | dependencies=[google_dot_protobuf_dot_timestamp__pb2.DESCRIPTOR,yamcs_dot_protobuf_dot_yamcs__pb2.DESCRIPTOR,]) 26 | 27 | 28 | 29 | 30 | _TMPACKETDATA = _descriptor.Descriptor( 31 | name='TmPacketData', 32 | full_name='yamcs.protobuf.packets.TmPacketData', 33 | filename=None, 34 | file=DESCRIPTOR, 35 | containing_type=None, 36 | fields=[ 37 | _descriptor.FieldDescriptor( 38 | name='packet', full_name='yamcs.protobuf.packets.TmPacketData.packet', index=0, 39 | number=2, type=12, cpp_type=9, label=1, 40 | has_default_value=False, default_value=b"", 41 | message_type=None, enum_type=None, containing_type=None, 42 | is_extension=False, extension_scope=None, 43 | serialized_options=None, file=DESCRIPTOR), 44 | _descriptor.FieldDescriptor( 45 | name='sequenceNumber', full_name='yamcs.protobuf.packets.TmPacketData.sequenceNumber', index=1, 46 | number=4, type=5, cpp_type=1, label=1, 47 | has_default_value=False, default_value=0, 48 | message_type=None, enum_type=None, containing_type=None, 49 | is_extension=False, extension_scope=None, 50 | serialized_options=None, file=DESCRIPTOR), 51 | _descriptor.FieldDescriptor( 52 | name='id', full_name='yamcs.protobuf.packets.TmPacketData.id', index=2, 53 | number=5, type=11, cpp_type=10, label=1, 54 | has_default_value=False, default_value=None, 55 | message_type=None, enum_type=None, containing_type=None, 56 | is_extension=False, extension_scope=None, 57 | serialized_options=None, file=DESCRIPTOR), 58 | _descriptor.FieldDescriptor( 59 | name='generationTime', full_name='yamcs.protobuf.packets.TmPacketData.generationTime', index=3, 60 | number=9, type=11, cpp_type=10, label=1, 61 | has_default_value=False, default_value=None, 62 | message_type=None, enum_type=None, containing_type=None, 63 | is_extension=False, extension_scope=None, 64 | serialized_options=None, file=DESCRIPTOR), 65 | _descriptor.FieldDescriptor( 66 | name='earthReceptionTime', full_name='yamcs.protobuf.packets.TmPacketData.earthReceptionTime', index=4, 67 | number=10, type=11, cpp_type=10, label=1, 68 | has_default_value=False, default_value=None, 69 | message_type=None, enum_type=None, containing_type=None, 70 | is_extension=False, extension_scope=None, 71 | serialized_options=None, file=DESCRIPTOR), 72 | _descriptor.FieldDescriptor( 73 | name='receptionTime', full_name='yamcs.protobuf.packets.TmPacketData.receptionTime', index=5, 74 | number=8, type=11, cpp_type=10, label=1, 75 | has_default_value=False, default_value=None, 76 | message_type=None, enum_type=None, containing_type=None, 77 | is_extension=False, extension_scope=None, 78 | serialized_options=None, file=DESCRIPTOR), 79 | _descriptor.FieldDescriptor( 80 | name='link', full_name='yamcs.protobuf.packets.TmPacketData.link', index=6, 81 | number=11, type=9, cpp_type=9, label=1, 82 | has_default_value=False, default_value=b"".decode('utf-8'), 83 | message_type=None, enum_type=None, containing_type=None, 84 | is_extension=False, extension_scope=None, 85 | serialized_options=None, file=DESCRIPTOR), 86 | _descriptor.FieldDescriptor( 87 | name='size', full_name='yamcs.protobuf.packets.TmPacketData.size', index=7, 88 | number=12, type=5, cpp_type=1, label=1, 89 | has_default_value=False, default_value=0, 90 | message_type=None, enum_type=None, containing_type=None, 91 | is_extension=False, extension_scope=None, 92 | serialized_options=None, file=DESCRIPTOR), 93 | ], 94 | extensions=[ 95 | ], 96 | nested_types=[], 97 | enum_types=[ 98 | ], 99 | serialized_options=None, 100 | is_extendable=False, 101 | syntax='proto2', 102 | extension_ranges=[], 103 | oneofs=[ 104 | ], 105 | serialized_start=126, 106 | serialized_end=410, 107 | ) 108 | 109 | _TMPACKETDATA.fields_by_name['id'].message_type = yamcs_dot_protobuf_dot_yamcs__pb2._NAMEDOBJECTID 110 | _TMPACKETDATA.fields_by_name['generationTime'].message_type = google_dot_protobuf_dot_timestamp__pb2._TIMESTAMP 111 | _TMPACKETDATA.fields_by_name['earthReceptionTime'].message_type = google_dot_protobuf_dot_timestamp__pb2._TIMESTAMP 112 | _TMPACKETDATA.fields_by_name['receptionTime'].message_type = google_dot_protobuf_dot_timestamp__pb2._TIMESTAMP 113 | DESCRIPTOR.message_types_by_name['TmPacketData'] = _TMPACKETDATA 114 | _sym_db.RegisterFileDescriptor(DESCRIPTOR) 115 | 116 | TmPacketData = _reflection.GeneratedProtocolMessageType('TmPacketData', (_message.Message,), { 117 | 'DESCRIPTOR' : _TMPACKETDATA, 118 | '__module__' : 'yamcs.protobuf.packets.packets_pb2' 119 | # @@protoc_insertion_point(class_scope:yamcs.protobuf.packets.TmPacketData) 120 | }) 121 | _sym_db.RegisterMessage(TmPacketData) 122 | 123 | 124 | DESCRIPTOR._options = None 125 | # @@protoc_insertion_point(module_scope) 126 | -------------------------------------------------------------------------------- /yamcs-client/src/yamcs/protobuf/plists/plists_pb2.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by the protocol buffer compiler. DO NOT EDIT! 3 | # source: yamcs/protobuf/plists/plists.proto 4 | 5 | from google.protobuf import descriptor as _descriptor 6 | from google.protobuf import message as _message 7 | from google.protobuf import reflection as _reflection 8 | from google.protobuf import symbol_database as _symbol_database 9 | # @@protoc_insertion_point(imports) 10 | 11 | _sym_db = _symbol_database.Default() 12 | 13 | 14 | from yamcs.protobuf.mdb import mdb_pb2 as yamcs_dot_protobuf_dot_mdb_dot_mdb__pb2 15 | 16 | 17 | DESCRIPTOR = _descriptor.FileDescriptor( 18 | name='yamcs/protobuf/plists/plists.proto', 19 | package='yamcs.protobuf.plists', 20 | syntax='proto2', 21 | serialized_options=b'\n\031org.yamcs.protobuf.plistsB\023ParameterListsProtoP\001', 22 | serialized_pb=b'\n\"yamcs/protobuf/plists/plists.proto\x12\x15yamcs.protobuf.plists\x1a\x1cyamcs/protobuf/mdb/mdb.proto\"\x86\x01\n\x11ParameterListInfo\x12\n\n\x02id\x18\x01 \x01(\t\x12\x0c\n\x04name\x18\x02 \x01(\t\x12\x13\n\x0b\x64\x65scription\x18\x03 \x01(\t\x12\x10\n\x08patterns\x18\x04 \x03(\t\x12\x30\n\x05match\x18\x05 \x03(\x0b\x32!.yamcs.protobuf.mdb.ParameterInfoB2\n\x19org.yamcs.protobuf.plistsB\x13ParameterListsProtoP\x01' 23 | , 24 | dependencies=[yamcs_dot_protobuf_dot_mdb_dot_mdb__pb2.DESCRIPTOR,]) 25 | 26 | 27 | 28 | 29 | _PARAMETERLISTINFO = _descriptor.Descriptor( 30 | name='ParameterListInfo', 31 | full_name='yamcs.protobuf.plists.ParameterListInfo', 32 | filename=None, 33 | file=DESCRIPTOR, 34 | containing_type=None, 35 | fields=[ 36 | _descriptor.FieldDescriptor( 37 | name='id', full_name='yamcs.protobuf.plists.ParameterListInfo.id', index=0, 38 | number=1, type=9, cpp_type=9, label=1, 39 | has_default_value=False, default_value=b"".decode('utf-8'), 40 | message_type=None, enum_type=None, containing_type=None, 41 | is_extension=False, extension_scope=None, 42 | serialized_options=None, file=DESCRIPTOR), 43 | _descriptor.FieldDescriptor( 44 | name='name', full_name='yamcs.protobuf.plists.ParameterListInfo.name', index=1, 45 | number=2, type=9, cpp_type=9, label=1, 46 | has_default_value=False, default_value=b"".decode('utf-8'), 47 | message_type=None, enum_type=None, containing_type=None, 48 | is_extension=False, extension_scope=None, 49 | serialized_options=None, file=DESCRIPTOR), 50 | _descriptor.FieldDescriptor( 51 | name='description', full_name='yamcs.protobuf.plists.ParameterListInfo.description', index=2, 52 | number=3, type=9, cpp_type=9, label=1, 53 | has_default_value=False, default_value=b"".decode('utf-8'), 54 | message_type=None, enum_type=None, containing_type=None, 55 | is_extension=False, extension_scope=None, 56 | serialized_options=None, file=DESCRIPTOR), 57 | _descriptor.FieldDescriptor( 58 | name='patterns', full_name='yamcs.protobuf.plists.ParameterListInfo.patterns', index=3, 59 | number=4, type=9, cpp_type=9, label=3, 60 | has_default_value=False, default_value=[], 61 | message_type=None, enum_type=None, containing_type=None, 62 | is_extension=False, extension_scope=None, 63 | serialized_options=None, file=DESCRIPTOR), 64 | _descriptor.FieldDescriptor( 65 | name='match', full_name='yamcs.protobuf.plists.ParameterListInfo.match', index=4, 66 | number=5, type=11, cpp_type=10, label=3, 67 | has_default_value=False, default_value=[], 68 | message_type=None, enum_type=None, containing_type=None, 69 | is_extension=False, extension_scope=None, 70 | serialized_options=None, file=DESCRIPTOR), 71 | ], 72 | extensions=[ 73 | ], 74 | nested_types=[], 75 | enum_types=[ 76 | ], 77 | serialized_options=None, 78 | is_extendable=False, 79 | syntax='proto2', 80 | extension_ranges=[], 81 | oneofs=[ 82 | ], 83 | serialized_start=92, 84 | serialized_end=226, 85 | ) 86 | 87 | _PARAMETERLISTINFO.fields_by_name['match'].message_type = yamcs_dot_protobuf_dot_mdb_dot_mdb__pb2._PARAMETERINFO 88 | DESCRIPTOR.message_types_by_name['ParameterListInfo'] = _PARAMETERLISTINFO 89 | _sym_db.RegisterFileDescriptor(DESCRIPTOR) 90 | 91 | ParameterListInfo = _reflection.GeneratedProtocolMessageType('ParameterListInfo', (_message.Message,), { 92 | 'DESCRIPTOR' : _PARAMETERLISTINFO, 93 | '__module__' : 'yamcs.protobuf.plists.plists_pb2' 94 | # @@protoc_insertion_point(class_scope:yamcs.protobuf.plists.ParameterListInfo) 95 | }) 96 | _sym_db.RegisterMessage(ParameterListInfo) 97 | 98 | 99 | DESCRIPTOR._options = None 100 | # @@protoc_insertion_point(module_scope) 101 | -------------------------------------------------------------------------------- /yamcs-client/src/yamcs/protobuf/services/services_pb2.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by the protocol buffer compiler. DO NOT EDIT! 3 | # source: yamcs/protobuf/services/services.proto 4 | 5 | from google.protobuf.internal import enum_type_wrapper 6 | from google.protobuf import descriptor as _descriptor 7 | from google.protobuf import message as _message 8 | from google.protobuf import reflection as _reflection 9 | from google.protobuf import symbol_database as _symbol_database 10 | # @@protoc_insertion_point(imports) 11 | 12 | _sym_db = _symbol_database.Default() 13 | 14 | 15 | 16 | 17 | DESCRIPTOR = _descriptor.FileDescriptor( 18 | name='yamcs/protobuf/services/services.proto', 19 | package='yamcs.protobuf.services', 20 | syntax='proto2', 21 | serialized_options=b'\n\022org.yamcs.protobufB\rServicesProtoP\001', 22 | serialized_pb=b'\n&yamcs/protobuf/services/services.proto\x12\x17yamcs.protobuf.services\"\xb7\x01\n\x0bServiceInfo\x12\x10\n\x08instance\x18\x01 \x01(\t\x12\x0c\n\x04name\x18\x02 \x01(\t\x12\x34\n\x05state\x18\x03 \x01(\x0e\x32%.yamcs.protobuf.services.ServiceState\x12\x11\n\tclassName\x18\x04 \x01(\t\x12\x11\n\tprocessor\x18\x05 \x01(\t\x12\x16\n\x0e\x66\x61ilureMessage\x18\x06 \x01(\t\x12\x14\n\x0c\x66\x61ilureCause\x18\x07 \x01(\t*\\\n\x0cServiceState\x12\x07\n\x03NEW\x10\x00\x12\x0c\n\x08STARTING\x10\x01\x12\x0b\n\x07RUNNING\x10\x02\x12\x0c\n\x08STOPPING\x10\x03\x12\x0e\n\nTERMINATED\x10\x04\x12\n\n\x06\x46\x41ILED\x10\x05\x42%\n\x12org.yamcs.protobufB\rServicesProtoP\x01' 23 | ) 24 | 25 | _SERVICESTATE = _descriptor.EnumDescriptor( 26 | name='ServiceState', 27 | full_name='yamcs.protobuf.services.ServiceState', 28 | filename=None, 29 | file=DESCRIPTOR, 30 | values=[ 31 | _descriptor.EnumValueDescriptor( 32 | name='NEW', index=0, number=0, 33 | serialized_options=None, 34 | type=None), 35 | _descriptor.EnumValueDescriptor( 36 | name='STARTING', index=1, number=1, 37 | serialized_options=None, 38 | type=None), 39 | _descriptor.EnumValueDescriptor( 40 | name='RUNNING', index=2, number=2, 41 | serialized_options=None, 42 | type=None), 43 | _descriptor.EnumValueDescriptor( 44 | name='STOPPING', index=3, number=3, 45 | serialized_options=None, 46 | type=None), 47 | _descriptor.EnumValueDescriptor( 48 | name='TERMINATED', index=4, number=4, 49 | serialized_options=None, 50 | type=None), 51 | _descriptor.EnumValueDescriptor( 52 | name='FAILED', index=5, number=5, 53 | serialized_options=None, 54 | type=None), 55 | ], 56 | containing_type=None, 57 | serialized_options=None, 58 | serialized_start=253, 59 | serialized_end=345, 60 | ) 61 | _sym_db.RegisterEnumDescriptor(_SERVICESTATE) 62 | 63 | ServiceState = enum_type_wrapper.EnumTypeWrapper(_SERVICESTATE) 64 | NEW = 0 65 | STARTING = 1 66 | RUNNING = 2 67 | STOPPING = 3 68 | TERMINATED = 4 69 | FAILED = 5 70 | 71 | 72 | 73 | _SERVICEINFO = _descriptor.Descriptor( 74 | name='ServiceInfo', 75 | full_name='yamcs.protobuf.services.ServiceInfo', 76 | filename=None, 77 | file=DESCRIPTOR, 78 | containing_type=None, 79 | fields=[ 80 | _descriptor.FieldDescriptor( 81 | name='instance', full_name='yamcs.protobuf.services.ServiceInfo.instance', index=0, 82 | number=1, type=9, cpp_type=9, label=1, 83 | has_default_value=False, default_value=b"".decode('utf-8'), 84 | message_type=None, enum_type=None, containing_type=None, 85 | is_extension=False, extension_scope=None, 86 | serialized_options=None, file=DESCRIPTOR), 87 | _descriptor.FieldDescriptor( 88 | name='name', full_name='yamcs.protobuf.services.ServiceInfo.name', index=1, 89 | number=2, type=9, cpp_type=9, label=1, 90 | has_default_value=False, default_value=b"".decode('utf-8'), 91 | message_type=None, enum_type=None, containing_type=None, 92 | is_extension=False, extension_scope=None, 93 | serialized_options=None, file=DESCRIPTOR), 94 | _descriptor.FieldDescriptor( 95 | name='state', full_name='yamcs.protobuf.services.ServiceInfo.state', index=2, 96 | number=3, type=14, cpp_type=8, label=1, 97 | has_default_value=False, default_value=0, 98 | message_type=None, enum_type=None, containing_type=None, 99 | is_extension=False, extension_scope=None, 100 | serialized_options=None, file=DESCRIPTOR), 101 | _descriptor.FieldDescriptor( 102 | name='className', full_name='yamcs.protobuf.services.ServiceInfo.className', index=3, 103 | number=4, type=9, cpp_type=9, label=1, 104 | has_default_value=False, default_value=b"".decode('utf-8'), 105 | message_type=None, enum_type=None, containing_type=None, 106 | is_extension=False, extension_scope=None, 107 | serialized_options=None, file=DESCRIPTOR), 108 | _descriptor.FieldDescriptor( 109 | name='processor', full_name='yamcs.protobuf.services.ServiceInfo.processor', index=4, 110 | number=5, type=9, cpp_type=9, label=1, 111 | has_default_value=False, default_value=b"".decode('utf-8'), 112 | message_type=None, enum_type=None, containing_type=None, 113 | is_extension=False, extension_scope=None, 114 | serialized_options=None, file=DESCRIPTOR), 115 | _descriptor.FieldDescriptor( 116 | name='failureMessage', full_name='yamcs.protobuf.services.ServiceInfo.failureMessage', index=5, 117 | number=6, type=9, cpp_type=9, label=1, 118 | has_default_value=False, default_value=b"".decode('utf-8'), 119 | message_type=None, enum_type=None, containing_type=None, 120 | is_extension=False, extension_scope=None, 121 | serialized_options=None, file=DESCRIPTOR), 122 | _descriptor.FieldDescriptor( 123 | name='failureCause', full_name='yamcs.protobuf.services.ServiceInfo.failureCause', index=6, 124 | number=7, type=9, cpp_type=9, label=1, 125 | has_default_value=False, default_value=b"".decode('utf-8'), 126 | message_type=None, enum_type=None, containing_type=None, 127 | is_extension=False, extension_scope=None, 128 | serialized_options=None, file=DESCRIPTOR), 129 | ], 130 | extensions=[ 131 | ], 132 | nested_types=[], 133 | enum_types=[ 134 | ], 135 | serialized_options=None, 136 | is_extendable=False, 137 | syntax='proto2', 138 | extension_ranges=[], 139 | oneofs=[ 140 | ], 141 | serialized_start=68, 142 | serialized_end=251, 143 | ) 144 | 145 | _SERVICEINFO.fields_by_name['state'].enum_type = _SERVICESTATE 146 | DESCRIPTOR.message_types_by_name['ServiceInfo'] = _SERVICEINFO 147 | DESCRIPTOR.enum_types_by_name['ServiceState'] = _SERVICESTATE 148 | _sym_db.RegisterFileDescriptor(DESCRIPTOR) 149 | 150 | ServiceInfo = _reflection.GeneratedProtocolMessageType('ServiceInfo', (_message.Message,), { 151 | 'DESCRIPTOR' : _SERVICEINFO, 152 | '__module__' : 'yamcs.protobuf.services.services_pb2' 153 | # @@protoc_insertion_point(class_scope:yamcs.protobuf.services.ServiceInfo) 154 | }) 155 | _sym_db.RegisterMessage(ServiceInfo) 156 | 157 | 158 | DESCRIPTOR._options = None 159 | # @@protoc_insertion_point(module_scope) 160 | -------------------------------------------------------------------------------- /yamcs-client/src/yamcs/storage/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | Old-style. For backwards compatibility. 3 | Avoid use. 4 | """ 5 | 6 | from yamcs.client.storage.client import StorageClient # noqa 7 | -------------------------------------------------------------------------------- /yamcs-client/src/yamcs/storage/client.py: -------------------------------------------------------------------------------- 1 | """ 2 | Old-style. For backwards compatibility. 3 | Avoid use. 4 | """ 5 | 6 | from yamcs.client.storage.client import StorageClient # noqa 7 | -------------------------------------------------------------------------------- /yamcs-client/src/yamcs/storage/model.py: -------------------------------------------------------------------------------- 1 | """ 2 | Old-style. For backwards compatibility. 3 | Avoid use. 4 | """ 5 | 6 | from yamcs.client.storage.model import Bucket, ObjectInfo, ObjectListing # noqa 7 | -------------------------------------------------------------------------------- /yamcs-client/src/yamcs/tco/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yamcs/python-yamcs-client/24860c21f9f82b02b73240a2b7d3ca547178a331/yamcs-client/src/yamcs/tco/__init__.py -------------------------------------------------------------------------------- /yamcs-client/src/yamcs/tco/client.py: -------------------------------------------------------------------------------- 1 | """ 2 | Old-style. For backwards compatibility. 3 | Avoid use. 4 | """ 5 | 6 | from yamcs.client.tco.client import TCOClient # noqa 7 | -------------------------------------------------------------------------------- /yamcs-client/src/yamcs/tco/model.py: -------------------------------------------------------------------------------- 1 | """ 2 | Old-style. For backwards compatibility. 3 | Avoid use. 4 | """ 5 | 6 | from yamcs.client.tco.model import ( # noqa 7 | TCOCoefficients, 8 | TCOSample, 9 | TCOStatus, 10 | TofInterval, 11 | ) 12 | -------------------------------------------------------------------------------- /yamcs-client/src/yamcs/timeline/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | Old-style. For backwards compatibility. 3 | Avoid use. 4 | """ 5 | 6 | from yamcs.client.timeline.client import TimelineClient # noqa 7 | -------------------------------------------------------------------------------- /yamcs-client/src/yamcs/timeline/client.py: -------------------------------------------------------------------------------- 1 | """ 2 | Old-style. For backwards compatibility. 3 | Avoid use. 4 | """ 5 | 6 | from yamcs.client.timeline.client import TimelineClient # noqa 7 | -------------------------------------------------------------------------------- /yamcs-client/src/yamcs/timeline/model.py: -------------------------------------------------------------------------------- 1 | """ 2 | Old-style. For backwards compatibility. 3 | Avoid use. 4 | """ 5 | 6 | from yamcs.client.timeline.model import ( # noqa 7 | Band, 8 | CommandBand, 9 | Item, 10 | ItemBand, 11 | Spacer, 12 | TimeRuler, 13 | View, 14 | ) 15 | -------------------------------------------------------------------------------- /yamcs-client/src/yamcs/tmtc/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yamcs/python-yamcs-client/24860c21f9f82b02b73240a2b7d3ca547178a331/yamcs-client/src/yamcs/tmtc/__init__.py -------------------------------------------------------------------------------- /yamcs-client/src/yamcs/tmtc/client.py: -------------------------------------------------------------------------------- 1 | """ 2 | Old-style. For backwards compatibility. 3 | Avoid use. 4 | """ 5 | 6 | from yamcs.client.tmtc.client import ( # noqa 7 | AlarmSubscription, 8 | CommandConnection, 9 | CommandHistorySubscription, 10 | ContainerSubscription, 11 | ParameterSubscription, 12 | ProcessorClient, 13 | ) 14 | -------------------------------------------------------------------------------- /yamcs-client/src/yamcs/tmtc/model.py: -------------------------------------------------------------------------------- 1 | """ 2 | Old-style. For backwards compatibility. 3 | Avoid use. 4 | """ 5 | 6 | from yamcs.client.tmtc.model import ( # noqa 7 | Acknowledgment, 8 | Alarm, 9 | AlarmRangeSet, 10 | AlarmUpdate, 11 | Calibrator, 12 | CommandHistory, 13 | ContainerData, 14 | EventAlarm, 15 | IssuedCommand, 16 | MonitoredCommand, 17 | Packet, 18 | ParameterAlarm, 19 | ParameterData, 20 | ParameterValue, 21 | ValueUpdate, 22 | VerificationConfig, 23 | ) 24 | 25 | RangeSet = AlarmRangeSet 26 | """ 27 | Temporary backwards compatibility. 28 | Prefer to use the class 'AlarmRangeSet'. 29 | """ 30 | -------------------------------------------------------------------------------- /yamcs-client/update-proto.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | cd src 4 | rm -rf yamcs/api/ yamcs/protobuf/ 5 | cp -r ../../../yamcs/yamcs-api/src/main/proto/yamcs . 6 | 7 | # Current code is generated with 3.11.4 8 | 9 | protoc --proto_path=. --python_out=. `find yamcs/protobuf -name '*.proto'` `find yamcs/api -name '*.proto'` 10 | 11 | for d in `find yamcs/protobuf -type d` `find yamcs/api -type d`; do 12 | rm $d/*.proto 13 | done 14 | --------------------------------------------------------------------------------