arcsecond 3.20.1__tar.gz → 4.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- arcsecond-4.0.0/.gitattributes +6 -0
- {arcsecond-3.20.1 → arcsecond-4.0.0}/.github/workflows/tests.yml +22 -0
- {arcsecond-3.20.1 → arcsecond-4.0.0}/PKG-INFO +34 -5
- {arcsecond-3.20.1 → arcsecond-4.0.0}/README.md +33 -0
- {arcsecond-3.20.1 → arcsecond-4.0.0}/arcsecond/alpaca/commands.py +55 -26
- arcsecond-4.0.0/arcsecond/alpaca/dome_probe.py +90 -0
- arcsecond-3.20.1/arcsecond/alpaca/dome_probe.py → arcsecond-4.0.0/arcsecond/alpaca/probe.py +114 -120
- arcsecond-4.0.0/arcsecond/alpaca/telescope_probe.py +182 -0
- {arcsecond-3.20.1 → arcsecond-4.0.0}/arcsecond/api/config.py +125 -5
- {arcsecond-3.20.1 → arcsecond-4.0.0}/arcsecond/cli.py +31 -15
- {arcsecond-3.20.1 → arcsecond-4.0.0}/arcsecond/cloud/__init__.py +3 -5
- arcsecond-4.0.0/arcsecond/cloud/auth.py +176 -0
- {arcsecond-3.20.1 → arcsecond-4.0.0}/arcsecond/cloud/uploads.py +13 -2
- arcsecond-4.0.0/arcsecond/docgen.py +295 -0
- arcsecond-4.0.0/arcsecond/errors.py +18 -0
- arcsecond-4.0.0/arcsecond/hosting/__init__.py +17 -0
- {arcsecond-3.20.1 → arcsecond-4.0.0}/arcsecond/hosting/database.py +9 -31
- arcsecond-4.0.0/arcsecond/hosting/docker/__init__.py +1 -0
- arcsecond-4.0.0/arcsecond/hosting/lifecycle.py +328 -0
- {arcsecond-3.20.1 → arcsecond-4.0.0}/arcsecond/hosting/local.py +111 -17
- arcsecond-4.0.0/arcsecond/hosting/stack.py +401 -0
- {arcsecond-3.20.1 → arcsecond-4.0.0}/arcsecond/hosting/utils.py +40 -0
- arcsecond-4.0.0/arcsecond/imagesources/autostart.py +270 -0
- {arcsecond-3.20.1 → arcsecond-4.0.0}/arcsecond/imagesources/commands.py +57 -21
- {arcsecond-3.20.1 → arcsecond-4.0.0}/arcsecond/options.py +6 -16
- {arcsecond-3.20.1 → arcsecond-4.0.0}/pyproject.toml +1 -5
- {arcsecond-3.20.1 → arcsecond-4.0.0}/tests/api/test_api_endpoint.py +21 -6
- {arcsecond-3.20.1 → arcsecond-4.0.0}/tests/api/test_config.py +7 -1
- arcsecond-4.0.0/tests/api/test_config_pointer.py +119 -0
- {arcsecond-3.20.1 → arcsecond-4.0.0}/tests/test_alpaca_probe.py +348 -15
- {arcsecond-3.20.1 → arcsecond-4.0.0}/tests/test_cli.py +2 -1
- arcsecond-4.0.0/tests/test_cli_api_commands.py +147 -0
- arcsecond-4.0.0/tests/test_docgen.py +128 -0
- {arcsecond-3.20.1 → arcsecond-4.0.0}/tests/test_hosting_database.py +1 -1
- arcsecond-4.0.0/tests/test_hosting_lifecycle.py +327 -0
- {arcsecond-3.20.1 → arcsecond-4.0.0}/tests/test_hosting_local.py +84 -0
- arcsecond-4.0.0/tests/test_hosting_stack.py +289 -0
- arcsecond-4.0.0/tests/test_imagesources_autostart.py +112 -0
- {arcsecond-3.20.1 → arcsecond-4.0.0}/tests/test_imagesources_commands.py +93 -8
- {arcsecond-3.20.1 → arcsecond-4.0.0}/uv.lock +1 -84
- arcsecond-3.20.1/arcsecond/cloud/auth.py +0 -120
- arcsecond-3.20.1/arcsecond/errors.py +0 -7
- arcsecond-3.20.1/arcsecond/hosting/__init__.py +0 -7
- arcsecond-3.20.1/arcsecond/hosting/checks.py +0 -94
- arcsecond-3.20.1/arcsecond/hosting/constants.py +0 -8
- arcsecond-3.20.1/arcsecond/hosting/docker/__init__.py +0 -33
- arcsecond-3.20.1/arcsecond/hosting/docker/constants.py +0 -12
- arcsecond-3.20.1/arcsecond/hosting/docker/containers.py +0 -216
- arcsecond-3.20.1/arcsecond/hosting/docker/images.py +0 -43
- arcsecond-3.20.1/arcsecond/hosting/docker/utils.py +0 -69
- arcsecond-3.20.1/arcsecond/hosting/keygen/__init__.py +0 -3
- arcsecond-3.20.1/arcsecond/hosting/keygen/client.py +0 -233
- arcsecond-3.20.1/arcsecond/hosting/keygen/utils.py +0 -7
- arcsecond-3.20.1/arcsecond/hosting/main.py +0 -74
- arcsecond-3.20.1/arcsecond/hosting/postgres/init-db.sh +0 -8
- arcsecond-3.20.1/arcsecond/hosting/setup.py +0 -75
- arcsecond-3.20.1/arcsecond/hosting/validation.py +0 -47
- {arcsecond-3.20.1 → arcsecond-4.0.0}/.docker/Dockerfile_postgres +0 -0
- {arcsecond-3.20.1 → arcsecond-4.0.0}/.docker/Dockerfile_redis +0 -0
- {arcsecond-3.20.1 → arcsecond-4.0.0}/.flake8 +0 -0
- {arcsecond-3.20.1 → arcsecond-4.0.0}/.github/dependabot.yml +0 -0
- {arcsecond-3.20.1 → arcsecond-4.0.0}/.github/workflows/pythonpublish.yml +0 -0
- {arcsecond-3.20.1 → arcsecond-4.0.0}/.gitignore +0 -0
- {arcsecond-3.20.1 → arcsecond-4.0.0}/LICENSE +0 -0
- {arcsecond-3.20.1 → arcsecond-4.0.0}/Makefile +0 -0
- {arcsecond-3.20.1 → arcsecond-4.0.0}/arcsecond/__init__.py +0 -0
- {arcsecond-3.20.1 → arcsecond-4.0.0}/arcsecond/__version__.py +0 -0
- {arcsecond-3.20.1 → arcsecond-4.0.0}/arcsecond/alpaca/__init__.py +0 -0
- {arcsecond-3.20.1 → arcsecond-4.0.0}/arcsecond/api/__init__.py +0 -0
- {arcsecond-3.20.1 → arcsecond-4.0.0}/arcsecond/api/constants.py +0 -0
- {arcsecond-3.20.1 → arcsecond-4.0.0}/arcsecond/api/endpoint.py +0 -0
- {arcsecond-3.20.1 → arcsecond-4.0.0}/arcsecond/api/main.py +0 -0
- {arcsecond-3.20.1 → arcsecond-4.0.0}/arcsecond/api/resources.py +0 -0
- {arcsecond-3.20.1 → arcsecond-4.0.0}/arcsecond/cloud/resources.py +0 -0
- {arcsecond-3.20.1 → arcsecond-4.0.0}/arcsecond/cloud/uploader/__init__.py +0 -0
- {arcsecond-3.20.1 → arcsecond-4.0.0}/arcsecond/cloud/uploader/constants.py +0 -0
- {arcsecond-3.20.1 → arcsecond-4.0.0}/arcsecond/cloud/uploader/context.py +0 -0
- {arcsecond-3.20.1 → arcsecond-4.0.0}/arcsecond/cloud/uploader/datafiles/__init__.py +0 -0
- {arcsecond-3.20.1 → arcsecond-4.0.0}/arcsecond/cloud/uploader/datafiles/context.py +0 -0
- {arcsecond-3.20.1 → arcsecond-4.0.0}/arcsecond/cloud/uploader/datafiles/errors.py +0 -0
- {arcsecond-3.20.1 → arcsecond-4.0.0}/arcsecond/cloud/uploader/datafiles/uploader.py +0 -0
- {arcsecond-3.20.1 → arcsecond-4.0.0}/arcsecond/cloud/uploader/datafiles/utils.py +0 -0
- {arcsecond-3.20.1 → arcsecond-4.0.0}/arcsecond/cloud/uploader/errors.py +0 -0
- {arcsecond-3.20.1 → arcsecond-4.0.0}/arcsecond/cloud/uploader/logger.py +0 -0
- {arcsecond-3.20.1 → arcsecond-4.0.0}/arcsecond/cloud/uploader/uploader.py +0 -0
- {arcsecond-3.20.1 → arcsecond-4.0.0}/arcsecond/cloud/uploader/utils.py +0 -0
- {arcsecond-3.20.1 → arcsecond-4.0.0}/arcsecond/cloud/uploader/walker.py +0 -0
- {arcsecond-3.20.1 → arcsecond-4.0.0}/arcsecond/hosting/backups.py +0 -0
- {arcsecond-3.20.1 → arcsecond-4.0.0}/arcsecond/hosting/docker/docker-compose.yml +0 -0
- {arcsecond-3.20.1 → arcsecond-4.0.0}/arcsecond/imagesources/__init__.py +0 -0
- {arcsecond-3.20.1 → arcsecond-4.0.0}/arcsecond/imagesources/detection.py +0 -0
- {arcsecond-3.20.1 → arcsecond-4.0.0}/arcsecond/imagesources/proxy.py +0 -0
- {arcsecond-3.20.1 → arcsecond-4.0.0}/arcsecond/imagesources/registry.py +0 -0
- {arcsecond-3.20.1 → arcsecond-4.0.0}/arcsecond/imagesources/runtime.py +0 -0
- {arcsecond-3.20.1 → arcsecond-4.0.0}/arcsecond/imagesources/sources/__init__.py +0 -0
- {arcsecond-3.20.1 → arcsecond-4.0.0}/arcsecond/imagesources/sources/base.py +0 -0
- {arcsecond-3.20.1 → arcsecond-4.0.0}/arcsecond/imagesources/sources/filewatch.py +0 -0
- {arcsecond-3.20.1 → arcsecond-4.0.0}/arcsecond/imagesources/sources/mdns.py +0 -0
- {arcsecond-3.20.1 → arcsecond-4.0.0}/arcsecond/imagesources/sources/network.py +0 -0
- {arcsecond-3.20.1 → arcsecond-4.0.0}/arcsecond/imagesources/sources/opencv.py +0 -0
- {arcsecond-3.20.1 → arcsecond-4.0.0}/arcsecond/imagesources/store.py +0 -0
- {arcsecond-3.20.1 → arcsecond-4.0.0}/arcsecond/targets.py +0 -0
- {arcsecond-3.20.1 → arcsecond-4.0.0}/examples/example_upload_files.py +0 -0
- {arcsecond-3.20.1 → arcsecond-4.0.0}/requirements.txt +0 -0
- {arcsecond-3.20.1 → arcsecond-4.0.0}/setup.cfg +0 -0
- {arcsecond-3.20.1 → arcsecond-4.0.0}/setup.py +0 -0
- {arcsecond-3.20.1 → arcsecond-4.0.0}/sonar-project.properties +0 -0
- {arcsecond-3.20.1 → arcsecond-4.0.0}/tests/__init__.py +0 -0
- {arcsecond-3.20.1 → arcsecond-4.0.0}/tests/api/__init__.py +0 -0
- {arcsecond-3.20.1 → arcsecond-4.0.0}/tests/api/test_api.py +0 -0
- {arcsecond-3.20.1 → arcsecond-4.0.0}/tests/api/test_targets.py +0 -0
- {arcsecond-3.20.1 → arcsecond-4.0.0}/tests/cloud/__init__.py +0 -0
- {arcsecond-3.20.1 → arcsecond-4.0.0}/tests/cloud/uploader/__init__.py +0 -0
- {arcsecond-3.20.1 → arcsecond-4.0.0}/tests/cloud/uploader/datafiles/__init__.py +0 -0
- {arcsecond-3.20.1 → arcsecond-4.0.0}/tests/cloud/uploader/datafiles/test_uploader_errors.py +0 -0
- {arcsecond-3.20.1 → arcsecond-4.0.0}/tests/cloud/uploader/datafiles/test_uploader_full_process.py +0 -0
- {arcsecond-3.20.1 → arcsecond-4.0.0}/tests/cloud/uploader/datafiles/test_uploader_init.py +0 -0
- {arcsecond-3.20.1 → arcsecond-4.0.0}/tests/cloud/uploader/datafiles/test_uploader_prepare.py +0 -0
- {arcsecond-3.20.1 → arcsecond-4.0.0}/tests/cloud/uploader/datafiles/test_uploader_upload.py +0 -0
- {arcsecond-3.20.1 → arcsecond-4.0.0}/tests/conftest.py +0 -0
- {arcsecond-3.20.1 → arcsecond-4.0.0}/tests/fixtures/file1.fits +0 -0
- {arcsecond-3.20.1 → arcsecond-4.0.0}/tests/test_hosting_backups_restore.py +0 -0
- {arcsecond-3.20.1 → arcsecond-4.0.0}/tests/test_hosting_utils_secret_key.py +0 -0
- {arcsecond-3.20.1 → arcsecond-4.0.0}/tests/test_imagesources_detection.py +0 -0
- {arcsecond-3.20.1 → arcsecond-4.0.0}/tests/test_imagesources_mdns.py +0 -0
- {arcsecond-3.20.1 → arcsecond-4.0.0}/tests/test_imagesources_network.py +0 -0
- {arcsecond-3.20.1 → arcsecond-4.0.0}/tests/test_imagesources_proxy.py +0 -0
- {arcsecond-3.20.1 → arcsecond-4.0.0}/tests/test_imagesources_store.py +0 -0
- {arcsecond-3.20.1 → arcsecond-4.0.0}/tests/test_imagesources_webcam.py +0 -0
- {arcsecond-3.20.1 → arcsecond-4.0.0}/tests/test_targets_planning.py +0 -0
- {arcsecond-3.20.1 → arcsecond-4.0.0}/tests/utils.py +0 -0
|
@@ -40,6 +40,28 @@ jobs:
|
|
|
40
40
|
name: coverage
|
|
41
41
|
path: coverage.xml
|
|
42
42
|
|
|
43
|
+
# The CLI's operators run it on Windows — the observatory PC — and until
|
|
44
|
+
# now nothing here ever executed it there. No Docker on this runner; this
|
|
45
|
+
# covers the pure-Python paths: path handling, the console, the registry
|
|
46
|
+
# backend of the proxy's login item, and every Windows branch in the suite.
|
|
47
|
+
tests-windows:
|
|
48
|
+
runs-on: windows-latest
|
|
49
|
+
|
|
50
|
+
steps:
|
|
51
|
+
- uses: actions/checkout@v5
|
|
52
|
+
|
|
53
|
+
- name: Install uv
|
|
54
|
+
uses: astral-sh/setup-uv@v6
|
|
55
|
+
with:
|
|
56
|
+
python-version: '3.12'
|
|
57
|
+
enable-cache: true
|
|
58
|
+
|
|
59
|
+
- name: Install dependencies
|
|
60
|
+
run: uv sync --extra webcam --group dev
|
|
61
|
+
|
|
62
|
+
- name: Test
|
|
63
|
+
run: uv run pytest -q tests/
|
|
64
|
+
|
|
43
65
|
scan:
|
|
44
66
|
runs-on: ubuntu-latest
|
|
45
67
|
needs: tests
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: arcsecond
|
|
3
|
-
Version:
|
|
3
|
+
Version: 4.0.0
|
|
4
4
|
Summary: CLI for arcsecond.io
|
|
5
5
|
Project-URL: Homepage, https://github.com/arcsecond-io/cli
|
|
6
6
|
Project-URL: Issues, https://github.com/arcsecond-io/cli/issues
|
|
@@ -40,12 +40,8 @@ Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
|
40
40
|
Requires-Python: >=3.12
|
|
41
41
|
Requires-Dist: alpyca==3.1.2
|
|
42
42
|
Requires-Dist: click>=8
|
|
43
|
-
Requires-Dist: configparser
|
|
44
|
-
Requires-Dist: docker
|
|
45
43
|
Requires-Dist: httpx
|
|
46
|
-
Requires-Dist: py-machineid
|
|
47
44
|
Requires-Dist: tqdm<5.0.0,>=4.67.1
|
|
48
|
-
Requires-Dist: wait-for-it
|
|
49
45
|
Provides-Extra: webcam
|
|
50
46
|
Requires-Dist: aiohttp>=3.9; extra == 'webcam'
|
|
51
47
|
Requires-Dist: opencv-python-headless<5,>=4.10; extra == 'webcam'
|
|
@@ -62,6 +58,39 @@ public and private ones.
|
|
|
62
58
|
|
|
63
59
|
[Read the docs](https://docs.arcsecond.io/cli)
|
|
64
60
|
|
|
61
|
+
## Running Arcsecond.local
|
|
62
|
+
|
|
63
|
+
The CLI owns the whole lifecycle of a self-hosted installation; there is no
|
|
64
|
+
`docker` command to type:
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
$ arcsecond setup --lan-host 192.168.1.42 # writes .env and docker-compose.yml
|
|
68
|
+
$ arcsecond start # first run downloads the images
|
|
69
|
+
$ arcsecond status
|
|
70
|
+
$ arcsecond logs backend -f
|
|
71
|
+
$ arcsecond restart backend worker # after editing .env
|
|
72
|
+
$ arcsecond update # newer images, refreshed compose file
|
|
73
|
+
$ arcsecond stop
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
Every one of these finds the installation in the current folder, or in the
|
|
77
|
+
folder `arcsecond setup` last ran in, or where `--dir` points.
|
|
78
|
+
|
|
79
|
+
## Which server the CLI talks to
|
|
80
|
+
|
|
81
|
+
The CLI points at one API server at a time — the cloud by default, or a
|
|
82
|
+
server you registered, typically your own Arcsecond.local — and every command
|
|
83
|
+
follows that pointer:
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
$ arcsecond api # list them, * marks the current one
|
|
87
|
+
$ arcsecond api use local # `setup` registered `local` for you
|
|
88
|
+
$ arcsecond login # on that server
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Credentials are kept per server. For a script or a cron job, `ARCSECOND_API=<name>`
|
|
92
|
+
selects a server for that process alone, without moving the pointer.
|
|
93
|
+
|
|
65
94
|
## Configuration
|
|
66
95
|
|
|
67
96
|
Credentials and settings live in `~/.config/arcsecond/`, alongside the list of
|
|
@@ -9,6 +9,39 @@ public and private ones.
|
|
|
9
9
|
|
|
10
10
|
[Read the docs](https://docs.arcsecond.io/cli)
|
|
11
11
|
|
|
12
|
+
## Running Arcsecond.local
|
|
13
|
+
|
|
14
|
+
The CLI owns the whole lifecycle of a self-hosted installation; there is no
|
|
15
|
+
`docker` command to type:
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
$ arcsecond setup --lan-host 192.168.1.42 # writes .env and docker-compose.yml
|
|
19
|
+
$ arcsecond start # first run downloads the images
|
|
20
|
+
$ arcsecond status
|
|
21
|
+
$ arcsecond logs backend -f
|
|
22
|
+
$ arcsecond restart backend worker # after editing .env
|
|
23
|
+
$ arcsecond update # newer images, refreshed compose file
|
|
24
|
+
$ arcsecond stop
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Every one of these finds the installation in the current folder, or in the
|
|
28
|
+
folder `arcsecond setup` last ran in, or where `--dir` points.
|
|
29
|
+
|
|
30
|
+
## Which server the CLI talks to
|
|
31
|
+
|
|
32
|
+
The CLI points at one API server at a time — the cloud by default, or a
|
|
33
|
+
server you registered, typically your own Arcsecond.local — and every command
|
|
34
|
+
follows that pointer:
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
$ arcsecond api # list them, * marks the current one
|
|
38
|
+
$ arcsecond api use local # `setup` registered `local` for you
|
|
39
|
+
$ arcsecond login # on that server
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Credentials are kept per server. For a script or a cron job, `ARCSECOND_API=<name>`
|
|
43
|
+
selects a server for that process alone, without moving the pointer.
|
|
44
|
+
|
|
12
45
|
## Configuration
|
|
13
46
|
|
|
14
47
|
Credentials and settings live in `~/.config/arcsecond/`, alongside the list of
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
"""
|
|
2
2
|
Click command group: ``arcsecond alpaca``.
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
``SupportedActions``, ``CommandString`` /
|
|
7
|
-
passthrough behaviour, and local host hints
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
``probe camera`` / ``probe focuser`` and
|
|
11
|
-
under the same group.
|
|
4
|
+
``arcsecond alpaca probe dome`` and ``arcsecond alpaca probe telescope`` are
|
|
5
|
+
read-only diagnostics that capture what surface a given Alpaca device server
|
|
6
|
+
exposes (device metadata, ``SupportedActions``, ``CommandString`` /
|
|
7
|
+
``CommandBool`` / ``CommandBlind`` passthrough behaviour, and local host hints
|
|
8
|
+
when the target is this machine), one JSON report per run.
|
|
9
|
+
|
|
10
|
+
Structure leaves room for ``probe camera`` / ``probe focuser`` and
|
|
11
|
+
``arcsecond alpaca discover`` later under the same group.
|
|
12
12
|
"""
|
|
13
13
|
|
|
14
14
|
from __future__ import annotations
|
|
@@ -17,11 +17,14 @@ import json
|
|
|
17
17
|
import os
|
|
18
18
|
from datetime import datetime, timezone
|
|
19
19
|
from pathlib import Path
|
|
20
|
+
from typing import Callable
|
|
20
21
|
|
|
21
22
|
import click
|
|
22
23
|
|
|
23
24
|
from ..errors import ArcsecondError
|
|
24
|
-
from .dome_probe import
|
|
25
|
+
from .dome_probe import probe_dome
|
|
26
|
+
from .probe import HOST_HINTS_REASON_LOCAL, ProbeProgress, ProbeResult
|
|
27
|
+
from .telescope_probe import probe_telescope
|
|
25
28
|
|
|
26
29
|
|
|
27
30
|
@click.group(name="alpaca", help="Diagnostics for local ASCOM Alpaca devices.")
|
|
@@ -122,20 +125,10 @@ def _format_progress(label: str, ok: bool, detail: str | None) -> str:
|
|
|
122
125
|
return f" {tag} {label}{suffix}"
|
|
123
126
|
|
|
124
127
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
"Captures device metadata, SupportedActions, and the behaviour of the "
|
|
130
|
-
"legacy CommandString / CommandBool / CommandBlind passthroughs. "
|
|
131
|
-
"Useful for figuring out whether a proprietary driver (e.g. TCSGalil) "
|
|
132
|
-
"exposes any vendor-specific extension surface beyond the standard "
|
|
133
|
-
"ASCOM IDome interface. Local host hints (open ports, COM ProgIDs) "
|
|
134
|
-
"are added when HOST is this machine."
|
|
135
|
-
),
|
|
136
|
-
)
|
|
137
|
-
@_add_options(_COMMON_OPTIONS)
|
|
138
|
-
def probe_dome_cmd(
|
|
128
|
+
def _run_probe(
|
|
129
|
+
kind: str,
|
|
130
|
+
runner: Callable[..., ProbeResult],
|
|
131
|
+
*,
|
|
139
132
|
host: str,
|
|
140
133
|
port: int,
|
|
141
134
|
device_number: int,
|
|
@@ -144,10 +137,11 @@ def probe_dome_cmd(
|
|
|
144
137
|
collect_host_info: bool | None,
|
|
145
138
|
output_path: str | None,
|
|
146
139
|
) -> None:
|
|
147
|
-
|
|
140
|
+
"""Drive one probe from the terminal: banner, progress lines, report, summary."""
|
|
141
|
+
output_path = output_path or _default_output_path(kind)
|
|
148
142
|
|
|
149
143
|
click.echo(
|
|
150
|
-
click.style("Alpaca
|
|
144
|
+
click.style(f"Alpaca {kind} probe", bold=True)
|
|
151
145
|
+ f" → {protocol}://{host}:{port} (device {device_number})"
|
|
152
146
|
)
|
|
153
147
|
if allow_active:
|
|
@@ -163,7 +157,7 @@ def probe_dome_cmd(
|
|
|
163
157
|
)
|
|
164
158
|
|
|
165
159
|
try:
|
|
166
|
-
result =
|
|
160
|
+
result = runner(
|
|
167
161
|
host=host,
|
|
168
162
|
port=port,
|
|
169
163
|
device_number=device_number,
|
|
@@ -192,3 +186,38 @@ def probe_dome_cmd(
|
|
|
192
186
|
click.echo(f" SupportedActions: {supported_n} entries")
|
|
193
187
|
click.echo(f" Host hints: {_describe_host_hints(result.report)}")
|
|
194
188
|
click.echo(f" Report written to {click.style(os.fspath(output_path), fg='cyan')}")
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
@probe_group.command(
|
|
192
|
+
name="dome",
|
|
193
|
+
help=(
|
|
194
|
+
"Probe a local Alpaca dome device read-only and write a JSON report.\n\n"
|
|
195
|
+
"Captures device metadata, SupportedActions, and the behaviour of the "
|
|
196
|
+
"legacy CommandString / CommandBool / CommandBlind passthroughs. "
|
|
197
|
+
"Useful for figuring out whether a proprietary driver (e.g. TCSGalil) "
|
|
198
|
+
"exposes any vendor-specific extension surface beyond the standard "
|
|
199
|
+
"ASCOM IDome interface. Local host hints (open ports, COM ProgIDs) "
|
|
200
|
+
"are added when HOST is this machine."
|
|
201
|
+
),
|
|
202
|
+
)
|
|
203
|
+
@_add_options(_COMMON_OPTIONS)
|
|
204
|
+
def probe_dome_cmd(**options) -> None:
|
|
205
|
+
_run_probe("dome", probe_dome, **options)
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
@probe_group.command(
|
|
209
|
+
name="telescope",
|
|
210
|
+
help=(
|
|
211
|
+
"Probe a local Alpaca telescope (mount) device read-only and write a "
|
|
212
|
+
"JSON report.\n\n"
|
|
213
|
+
"Captures device metadata, optics, site, pointing and tracking state, "
|
|
214
|
+
"capabilities, CanMoveAxis and AxisRates per movable axis, "
|
|
215
|
+
"SupportedActions, and the behaviour of the legacy CommandString / "
|
|
216
|
+
"CommandBool / CommandBlind passthroughs. Never moves the mount. "
|
|
217
|
+
"Local host hints (open ports, COM ProgIDs) are added when HOST is "
|
|
218
|
+
"this machine."
|
|
219
|
+
),
|
|
220
|
+
)
|
|
221
|
+
@_add_options(_COMMON_OPTIONS)
|
|
222
|
+
def probe_telescope_cmd(**options) -> None:
|
|
223
|
+
_run_probe("telescope", probe_telescope, **options)
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Read-only diagnostic for an ASCOM Alpaca *dome* device.
|
|
3
|
+
|
|
4
|
+
The standard ASCOM Alpaca ``IDome`` interface only exposes a single
|
|
5
|
+
``OpenShutter`` / ``CloseShutter`` pair. Multi-shutter domes (e.g. DFM domes
|
|
6
|
+
driven by TCSGalil) coordinate their shutters internally; if the driver does
|
|
7
|
+
not advertise per-shutter custom actions via ``SupportedActions``, there is
|
|
8
|
+
no canonical client-side way to drive the upper and lower shutters
|
|
9
|
+
independently. This probe writes down exactly what surface a dome server
|
|
10
|
+
exposes, so that decision can be made on evidence.
|
|
11
|
+
|
|
12
|
+
The engine, the report layout and the safety rules live in :mod:`.probe`;
|
|
13
|
+
this module only says which dome properties to read.
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
from __future__ import annotations
|
|
17
|
+
|
|
18
|
+
from typing import Any, Callable, Iterable
|
|
19
|
+
|
|
20
|
+
from .probe import ProbeProgress, ProbeResult
|
|
21
|
+
from .probe import iter_probe_labels as _iter_probe_labels
|
|
22
|
+
from .probe import probe_device
|
|
23
|
+
|
|
24
|
+
# Read-only device descriptors and dome state, in the order we want them
|
|
25
|
+
# presented in the report. Names are PascalCase to match the alpyca surface.
|
|
26
|
+
_READ_ONLY_PROPERTIES: tuple[str, ...] = (
|
|
27
|
+
"Name",
|
|
28
|
+
"Description",
|
|
29
|
+
"DriverInfo",
|
|
30
|
+
"DriverVersion",
|
|
31
|
+
"InterfaceVersion",
|
|
32
|
+
"ShutterStatus",
|
|
33
|
+
"Altitude",
|
|
34
|
+
"Azimuth",
|
|
35
|
+
"AtHome",
|
|
36
|
+
"AtPark",
|
|
37
|
+
"Slewing",
|
|
38
|
+
"Slaved",
|
|
39
|
+
"CanFindHome",
|
|
40
|
+
"CanPark",
|
|
41
|
+
"CanSetAltitude",
|
|
42
|
+
"CanSetPark",
|
|
43
|
+
"CanSetShutter",
|
|
44
|
+
"CanSlave",
|
|
45
|
+
"CanSyncAzimuth",
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def probe_dome(
|
|
50
|
+
host: str,
|
|
51
|
+
port: int,
|
|
52
|
+
device_number: int = 0,
|
|
53
|
+
*,
|
|
54
|
+
protocol: str = "http",
|
|
55
|
+
allow_active: bool = False,
|
|
56
|
+
collect_host_info: bool | None = None,
|
|
57
|
+
dome_factory: Callable[[str, int, str], Any] | None = None,
|
|
58
|
+
progress: ProbeProgress | None = None,
|
|
59
|
+
) -> ProbeResult:
|
|
60
|
+
"""
|
|
61
|
+
Build a JSON-serialisable diagnostic report for an Alpaca dome at
|
|
62
|
+
``protocol://host:port`` (device_number). See :func:`.probe.probe_device`
|
|
63
|
+
for the ``collect_host_info`` semantics.
|
|
64
|
+
|
|
65
|
+
``dome_factory(address, device_number, protocol)`` is only there for
|
|
66
|
+
tests — production callers leave it ``None`` and the real
|
|
67
|
+
``alpaca.dome.Dome`` is used.
|
|
68
|
+
"""
|
|
69
|
+
if dome_factory is None:
|
|
70
|
+
from alpaca.dome import Dome # local import: keep cost off cold paths
|
|
71
|
+
|
|
72
|
+
dome_factory = Dome
|
|
73
|
+
|
|
74
|
+
return probe_device(
|
|
75
|
+
"dome",
|
|
76
|
+
host,
|
|
77
|
+
port,
|
|
78
|
+
device_number,
|
|
79
|
+
properties=_READ_ONLY_PROPERTIES,
|
|
80
|
+
device_factory=dome_factory,
|
|
81
|
+
protocol=protocol,
|
|
82
|
+
allow_active=allow_active,
|
|
83
|
+
collect_host_info=collect_host_info,
|
|
84
|
+
progress=progress,
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def iter_probe_labels() -> Iterable[str]:
|
|
89
|
+
"""Convenience for tests / docs: enumerate the labels emitted by a run."""
|
|
90
|
+
return _iter_probe_labels(_READ_ONLY_PROPERTIES)
|