citrascope 0.1.0__py3-none-any.whl → 0.3.0__py3-none-any.whl

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.
Files changed (35) hide show
  1. citrascope/__main__.py +8 -5
  2. citrascope/api/abstract_api_client.py +7 -0
  3. citrascope/api/citra_api_client.py +30 -1
  4. citrascope/citra_scope_daemon.py +214 -61
  5. citrascope/hardware/abstract_astro_hardware_adapter.py +70 -2
  6. citrascope/hardware/adapter_registry.py +94 -0
  7. citrascope/hardware/indi_adapter.py +456 -16
  8. citrascope/hardware/kstars_dbus_adapter.py +179 -0
  9. citrascope/hardware/nina_adv_http_adapter.py +593 -0
  10. citrascope/hardware/nina_adv_http_survey_template.json +328 -0
  11. citrascope/logging/__init__.py +2 -1
  12. citrascope/logging/_citrascope_logger.py +80 -1
  13. citrascope/logging/web_log_handler.py +74 -0
  14. citrascope/settings/citrascope_settings.py +145 -0
  15. citrascope/settings/settings_file_manager.py +126 -0
  16. citrascope/tasks/runner.py +124 -28
  17. citrascope/tasks/scope/base_telescope_task.py +25 -10
  18. citrascope/tasks/scope/static_telescope_task.py +11 -3
  19. citrascope/web/__init__.py +1 -0
  20. citrascope/web/app.py +470 -0
  21. citrascope/web/server.py +123 -0
  22. citrascope/web/static/api.js +82 -0
  23. citrascope/web/static/app.js +500 -0
  24. citrascope/web/static/config.js +362 -0
  25. citrascope/web/static/img/citra.png +0 -0
  26. citrascope/web/static/img/favicon.png +0 -0
  27. citrascope/web/static/style.css +120 -0
  28. citrascope/web/static/websocket.js +127 -0
  29. citrascope/web/templates/dashboard.html +354 -0
  30. {citrascope-0.1.0.dist-info → citrascope-0.3.0.dist-info}/METADATA +68 -36
  31. citrascope-0.3.0.dist-info/RECORD +38 -0
  32. {citrascope-0.1.0.dist-info → citrascope-0.3.0.dist-info}/WHEEL +1 -1
  33. citrascope/settings/_citrascope_settings.py +0 -42
  34. citrascope-0.1.0.dist-info/RECORD +0 -21
  35. {citrascope-0.1.0.dist-info → citrascope-0.3.0.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,354 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+
4
+ <head>
5
+ <meta charset="UTF-8">
6
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
7
+ <title>CitraScope Dashboard</title>
8
+ <link rel="icon" type="image/png" href="/static/img/favicon.png">
9
+ <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css" rel="stylesheet"
10
+ integrity="sha384-sRIl4kxILFvY47J16cr9ZwB07vP4J8+LH7qKQnuqkuIAvNWLzeN8tE5YBujZqJLB" crossorigin="anonymous">
11
+ <link href="/static/style.css" rel="stylesheet">
12
+ </head>
13
+
14
+ <body data-bs-theme="dark">
15
+ <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/js/bootstrap.bundle.min.js"
16
+ integrity="sha384-FKyoEForCGlyvwx9Hj09JcYn3nv7wiPVlz7YYwJrWVcXK/BmnVDxM+D2scQbITxI"
17
+ crossorigin="anonymous"></script>
18
+
19
+
20
+ <div class="container">
21
+ <header class="d-flex flex-wrap justify-content-center py-3 mb-4 border-bottom align-items-center">
22
+ <span class="d-flex align-items-center mb-3 mb-md-0 me-md-auto link-body-emphasis text-decoration-none">
23
+ <span class="fs-4 d-flex align-items-center gap-2">
24
+ <img src="/static/img/citra.png" alt="CitraScope Logo" class="logo-img" />
25
+ CitraScope
26
+
27
+ </span>
28
+ <span class="ms-2 me-3 d-flex align-items-center status-badge-container">
29
+ <span id="wsStatus"><span class="badge rounded-pill bg-secondary" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Dashboard connection status">Connecting...</span></span>
30
+ </span>
31
+ </span>
32
+
33
+ <ul class="nav" id="mainNav">
34
+ <li class="nav-item"><a href="#" class="nav-link px-2 text-white" data-section="monitoring"
35
+ aria-current="page">Monitoring</a></li>
36
+ <li class="nav-item"><a href="#" class="nav-link px-2" data-section="config">Config</a></li>
37
+ <li class="nav-item"><a href="#" class="nav-link bg-success text-white btn" style="display: none;"
38
+ id="taskScopeButton" target="_blank">Task my Scope</a></li>
39
+ </ul>
40
+ </header>
41
+
42
+ <!-- Template for connection status badge -->
43
+ <template id="connectionStatusTemplate">
44
+ <span class="badge rounded-pill connection-status-badge" data-bs-toggle="tooltip" data-bs-placement="bottom">
45
+ <span class="status-text"></span>
46
+ </span>
47
+ </template>
48
+ </div>
49
+
50
+ <div id="monitoringSection">
51
+ <div class="container">
52
+ <div class="row g-3 mb-3">
53
+ <div class="col-12 col-md-6">
54
+ <div class="card bg-dark text-light border-secondary h-100">
55
+ <div class="card-header">
56
+ System Status
57
+ </div>
58
+ <div class="card-body">
59
+ <div class="row mb-2">
60
+ <div class="col-6 fw-semibold">Hardware</div>
61
+ <div class="col-6" id="hardwareAdapter">-</div>
62
+ </div>
63
+ <div class="row mb-2">
64
+ <div class="col-6 fw-semibold">Telescope</div>
65
+ <div class="col-6" id="telescopeConnected"><span class="badge rounded-pill bg-secondary">Unknown</span></div>
66
+ </div>
67
+ <div class="row mb-2">
68
+ <div class="col-6 fw-semibold">Camera</div>
69
+ <div class="col-6" id="cameraConnected"><span class="badge rounded-pill bg-secondary">Unknown</span></div>
70
+ </div>
71
+ </div>
72
+ </div>
73
+ </div>
74
+ <div class="col-12 col-md-6">
75
+ <div class="card bg-dark text-light border-secondary h-100">
76
+ <div class="card-header">
77
+ Telescope
78
+ </div>
79
+ <div class="card-body">
80
+ <div class="row mb-2">
81
+ <div class="col-6 fw-semibold">Right Ascension</div>
82
+ <div class="col-6" id="telescopeRA">-</div>
83
+ </div>
84
+ <div class="row mb-2">
85
+ <div class="col-6 fw-semibold">Declination</div>
86
+ <div class="col-6" id="telescopeDEC">-</div>
87
+ </div>
88
+ <div class="row">
89
+ <div class="col-6 fw-semibold">Ground Station</div>
90
+ <div class="col-6" id="groundStationName">-</div>
91
+ </div>
92
+ </div>
93
+ </div>
94
+ </div>
95
+
96
+ </div>
97
+ </div>
98
+ <div class="container">
99
+ <div class="row g-3 mb-3">
100
+ <div class="col-12">
101
+ <div class="card bg-dark text-light border-secondary">
102
+ <div class="card-header">
103
+ Current Task
104
+ </div>
105
+ <div class="card-body">
106
+ <div id="currentTaskDisplay">
107
+ <p class="text-muted-dark">No active task</p>
108
+ </div>
109
+ </div>
110
+ </div>
111
+
112
+ <!-- Template for active task display -->
113
+ <template id="activeTaskTemplate">
114
+ <div class="d-flex align-items-center gap-2 mb-2">
115
+ <div class="spinner-border spinner-border-sm text-success" role="status">
116
+ <span class="visually-hidden">Loading...</span>
117
+ </div>
118
+ <div class="fw-bold task-target-name" style="font-size: 1.3em;"></div>
119
+ </div>
120
+ <div class="text-secondary small">
121
+ <span class="task-id-text"></span>
122
+ </div>
123
+ </template>
124
+ </div>
125
+ </div>
126
+ <div class="row g-3 mb-3">
127
+ <div class="col-12">
128
+ <div class="card bg-dark text-light border-secondary">
129
+ <div class="card-header d-flex align-items-center justify-content-between">
130
+ <span>Task Queue</span>
131
+ <span class="small text-secondary"><span id="tasksPending">0</span> pending</span>
132
+ </div>
133
+ <div class="card-body p-0">
134
+ <div id="taskList" class="table-responsive">
135
+ <p class="p-3 text-muted-dark">Loading tasks...</p>
136
+ </div>
137
+ </div>
138
+ </div>
139
+
140
+ <!-- Template for task queue rows -->
141
+ <template id="taskRowTemplate">
142
+ <tr class="task-row">
143
+ <td class="fw-semibold task-target"></td>
144
+ <td class="text-secondary small task-start"></td>
145
+ <td class="text-secondary small task-end"></td>
146
+ <td><span class="badge rounded-pill task-status"></span></td>
147
+ </tr>
148
+ </template>
149
+ </div>
150
+ </div>
151
+ </div>
152
+ </div>
153
+
154
+ <div class="container my-4" id="configSection" style="display: none;">
155
+ <div id="configError" class="alert alert-danger" style="display: none;" role="alert"></div>
156
+ <div id="configSuccess" class="alert alert-success" style="display: none;" role="alert"></div>
157
+
158
+ <form id="configForm">
159
+ <div class="row g-3 mb-3">
160
+ <!-- API Configuration Card -->
161
+ <div class="col-12">
162
+ <div class="card bg-dark text-light border-secondary">
163
+ <div class="card-header">
164
+ <h5 class="mb-0">API Configuration</h5>
165
+ </div>
166
+ <div class="card-body">
167
+ <div class="row g-3">
168
+ <div class="col-12 col-md-6">
169
+ <label for="personal_access_token" class="form-label">Personal Access Token <span class="text-danger">*</span></label>
170
+ <input type="password" id="personal_access_token" class="form-control" placeholder="Enter your Citra API token" required>
171
+ <small class="text-muted">Get your token and telescope ID from <a href="" id="appUrlLink" target="_blank"></a></small>
172
+ </div>
173
+ <div class="col-12 col-md-6">
174
+ <label for="telescopeId" class="form-label">Telescope ID <span class="text-danger">*</span></label>
175
+ <input type="text" id="telescopeId" class="form-control" placeholder="Enter telescope ID" required>
176
+ </div>
177
+ </div>
178
+ </div>
179
+ </div>
180
+ </div>
181
+
182
+ <!-- Hardware Configuration Card -->
183
+ <div class="col-12">
184
+ <div class="card bg-dark text-light border-secondary">
185
+ <div class="card-header">
186
+ <h5 class="mb-0">Hardware Configuration</h5>
187
+ </div>
188
+ <div class="card-body">
189
+ <div class="row g-3 mb-3">
190
+ <div class="col-12">
191
+ <label for="hardwareAdapterSelect" class="form-label">Hardware Adapter <span class="text-danger">*</span></label>
192
+ <select id="hardwareAdapterSelect" class="form-select" required>
193
+ <option value="">-- Select Hardware Adapter --</option>
194
+ <!-- Options populated dynamically from API -->
195
+ </select>
196
+ </div>
197
+ </div>
198
+
199
+ <!-- Dynamic Adapter Settings Container -->
200
+ <div id="adapter-settings-container"></div>
201
+ </div>
202
+ </div>
203
+ </div>
204
+
205
+ <!-- Logging Settings Card -->
206
+ <div class="col-12">
207
+ <div class="card bg-dark text-light border-secondary">
208
+ <div class="card-header">
209
+ <h5 class="mb-0">Logging Settings</h5>
210
+ </div>
211
+ <div class="card-body">
212
+ <div class="row g-3">
213
+ <div class="col-12 col-md-6">
214
+ <label for="logLevel" class="form-label">Log Level</label>
215
+ <select id="logLevel" class="form-select">
216
+ <option value="DEBUG">DEBUG</option>
217
+ <option value="INFO">INFO</option>
218
+ <option value="WARNING">WARNING</option>
219
+ <option value="ERROR">ERROR</option>
220
+ </select>
221
+ </div>
222
+ <div class="col-12 col-md-6">
223
+ <div class="form-check mt-4">
224
+ <input class="form-check-input" type="checkbox" id="file_logging_enabled">
225
+ <label class="form-check-label" for="file_logging_enabled">
226
+ Enable file logging
227
+ </label>
228
+ </div>
229
+ </div>
230
+ <div class="col-12">
231
+ <small class="text-muted">
232
+ Log file: <span id="logFilePath" class="text-secondary">Loading...</span>
233
+ </small>
234
+ </div>
235
+ </div>
236
+ </div>
237
+ </div>
238
+ </div>
239
+
240
+ <!-- Task Settings Card -->
241
+ <div class="col-12">
242
+ <div class="card bg-dark text-light border-secondary">
243
+ <div class="card-header">
244
+ <h5 class="mb-0">Task Settings</h5>
245
+ </div>
246
+ <div class="card-body">
247
+ <div class="row g-3">
248
+ <div class="col-12 col-md-6">
249
+ <div class="form-check mt-2">
250
+ <input class="form-check-input" type="checkbox" id="keep_images">
251
+ <label class="form-check-label" for="keep_images">
252
+ Keep captured images
253
+ </label>
254
+ </div>
255
+ <small class="text-muted ms-4">By default, images are deleted after upload unless this is enabled</small>
256
+ </div>
257
+ <div class="col-12">
258
+ <small class="text-muted">
259
+ Images directory: <span id="imagesDirPath" class="text-secondary">Loading...</span>
260
+ </small>
261
+ </div>
262
+ </div>
263
+ </div>
264
+ </div>
265
+ </div>
266
+ </div>
267
+
268
+ <!-- Save Button -->
269
+ <div class="row">
270
+ <div class="col">
271
+ <button type="submit" class="btn btn-primary" id="saveConfigButton">
272
+ <span id="saveButtonText">Save Configuration</span>
273
+ <span id="saveButtonSpinner" class="spinner-border spinner-border-sm ms-2" style="display: none;" role="status"></span>
274
+ </button>
275
+ <small class="text-muted ms-3">
276
+ Config file: <span id="configFilePath" class="text-secondary">Loading...</span>
277
+ </small>
278
+ </div>
279
+ </div>
280
+ </form>
281
+ </div>
282
+
283
+ <!-- Setup Wizard Modal -->
284
+ <div class="modal fade" id="setupWizard" data-bs-backdrop="static" data-bs-keyboard="false" tabindex="-1" aria-hidden="true">
285
+ <div class="modal-dialog modal-lg modal-dialog-centered">
286
+ <div class="modal-content bg-dark text-light border-secondary">
287
+ <div class="modal-header border-secondary">
288
+ <h5 class="modal-title">Welcome to CitraScope Setup</h5>
289
+ </div>
290
+ <div class="modal-body">
291
+ <p class="lead">Let's configure your telescope system.</p>
292
+ <p>You'll need:</p>
293
+ <ul>
294
+ <li>Your Citra API personal access token from <a href="" id="setupAppUrlLink" target="_blank"></a></li>
295
+ <li>Your telescope ID</li>
296
+ <li>Information about your hardware adapter (INDI, N.I.N.A., or KStars)</li>
297
+ </ul>
298
+ <div class="alert alert-info">
299
+ <strong>Note:</strong> The configuration screen is available in the "Config" tab at the top of the page.
300
+ </div>
301
+ </div>
302
+ <div class="modal-footer border-secondary">
303
+ <button type="button" class="btn btn-primary" onclick="showConfigSection()">Configure Now</button>
304
+ </div>
305
+ </div>
306
+ </div>
307
+ </div>
308
+
309
+ <!-- Roll-up Terminal Overlay as Bootstrap Accordion -->
310
+ <div class="position-fixed bottom-0 start-0 w-100 z-3" style="max-width: 100vw;">
311
+ <div class="accordion" id="logAccordion">
312
+ <div class="accordion-item bg-dark text-light border-secondary">
313
+ <h2 class="accordion-header" id="logAccordionHeader">
314
+ <button class="accordion-button collapsed bg-secondary text-light log-accordion-button" type="button"
315
+ data-bs-toggle="collapse" data-bs-target="#logAccordionCollapse" aria-expanded="false"
316
+ aria-controls="logAccordionCollapse">
317
+ <span id="latestLogLine" class="log-latest-line">Log Terminal</span>
318
+ </button>
319
+ </h2>
320
+ <div id="logAccordionCollapse" class="accordion-collapse collapse" aria-labelledby="logAccordionHeader"
321
+ data-bs-parent="#logAccordion">
322
+ <div class="accordion-body p-0 log-accordion-body">
323
+ <div class="log-container p-3" id="logContainer">
324
+ <p class="text-muted-dark">Loading logs...</p>
325
+ </div>
326
+ </div>
327
+ </div>
328
+ </div>
329
+ </div>
330
+
331
+ <!-- Templates for log display -->
332
+ <template id="logEntryTemplate">
333
+ <div class="log-entry">
334
+ <span class="log-timestamp"></span>
335
+ <span class="log-level"></span>
336
+ <span class="log-message"></span>
337
+ </div>
338
+ </template>
339
+
340
+ <template id="latestLogLineTemplate">
341
+ <span class="log-timestamp"></span>
342
+ <span class="log-level"></span>
343
+ <span class="log-message"></span>
344
+ </template>
345
+
346
+ </div>
347
+
348
+
349
+ <script type="module" src="/static/app.js"></script>
350
+
351
+
352
+ </body>
353
+
354
+ </html>
@@ -1,27 +1,35 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: citrascope
3
- Version: 0.1.0
3
+ Version: 0.3.0
4
4
  Summary: Remotely control a telescope while it polls for tasks, collects and edge processes data, and delivers results and data for further processing.
5
- Author-email: Christopher Stevens <chris@citra.space>
5
+ Author-email: Patrick McDavid <patrick@citra.space>
6
6
  License-Expression: MIT
7
- Requires-Python: >=3.9
7
+ Requires-Python: <3.13,>=3.10
8
8
  Requires-Dist: click
9
+ Requires-Dist: fastapi>=0.104.0
9
10
  Requires-Dist: httpx
10
- Requires-Dist: pixelemon
11
+ Requires-Dist: platformdirs>=4.0.0
11
12
  Requires-Dist: pydantic-settings
12
- Requires-Dist: pyindi-client
13
13
  Requires-Dist: pytest-cov
14
14
  Requires-Dist: python-dateutil
15
15
  Requires-Dist: python-json-logger
16
16
  Requires-Dist: requests
17
17
  Requires-Dist: skyfield
18
18
  Requires-Dist: types-python-dateutil
19
+ Requires-Dist: uvicorn[standard]>=0.24.0
20
+ Requires-Dist: websockets>=12.0
21
+ Provides-Extra: all
22
+ Requires-Dist: dbus-python; extra == 'all'
23
+ Requires-Dist: pixelemon; extra == 'all'
24
+ Requires-Dist: plotly; extra == 'all'
25
+ Requires-Dist: pyindi-client; extra == 'all'
19
26
  Provides-Extra: build
20
27
  Requires-Dist: build; extra == 'build'
21
28
  Provides-Extra: deploy
22
29
  Requires-Dist: twine; extra == 'deploy'
23
30
  Provides-Extra: dev
24
31
  Requires-Dist: black; extra == 'dev'
32
+ Requires-Dist: bump-my-version; extra == 'dev'
25
33
  Requires-Dist: flake8; extra == 'dev'
26
34
  Requires-Dist: flake8-pytest-style; extra == 'dev'
27
35
  Requires-Dist: isort; extra == 'dev'
@@ -34,6 +42,12 @@ Provides-Extra: docs
34
42
  Requires-Dist: sphinx; extra == 'docs'
35
43
  Requires-Dist: sphinx-autodoc-typehints; extra == 'docs'
36
44
  Requires-Dist: sphinx-markdown-builder; extra == 'docs'
45
+ Provides-Extra: indi
46
+ Requires-Dist: pixelemon; extra == 'indi'
47
+ Requires-Dist: plotly; extra == 'indi'
48
+ Requires-Dist: pyindi-client; extra == 'indi'
49
+ Provides-Extra: kstars
50
+ Requires-Dist: dbus-python; extra == 'kstars'
37
51
  Provides-Extra: test
38
52
  Requires-Dist: mockito; extra == 'test'
39
53
  Requires-Dist: pytest; extra == 'test'
@@ -41,24 +55,44 @@ Requires-Dist: pytest-cov; extra == 'test'
41
55
  Description-Content-Type: text/markdown
42
56
 
43
57
  # CitraScope
44
- [![Pytest](https://github.com/citra-space/citrascope/actions/workflows/pytest.yml/badge.svg)](https://github.com/citra-space/citrascope/actions/workflows/pytest.yml) [![Build and Push Docker Image](https://github.com/citra-space/citrascope/actions/workflows/docker-publish.yml/badge.svg)](https://github.com/citra-space/citrascope/actions/workflows/docker-publish.yml)
58
+ [![Pytest](https://github.com/citra-space/citrascope/actions/workflows/pytest.yml/badge.svg)](https://github.com/citra-space/citrascope/actions/workflows/pytest.yml) [![Publish Python Package](https://github.com/citra-space/citrascope/actions/workflows/pypi-publish.yml/badge.svg)](https://github.com/citra-space/citrascope/actions/workflows/pypi-publish.yml)
45
59
 
46
60
  Remotely control a telescope while it polls for tasks, collects observations, and delivers data for further processing.
47
61
 
48
62
  ## Features
49
-
63
+ - Offers a web UI to configure hardware and connect to Citra.space's api
50
64
  - Connects to Citra.space's API and identifies itself as an online telescope
51
- - Connects to configured INDI telescope and camera hardware
65
+ - Connects to configured telescope and camera hardware
52
66
  - Acts as a task daemon carrying out and remitting photography tasks
53
67
 
54
68
  ## Installation
55
69
 
56
- Install CitraScope from PyPI:
70
+ ### Install with pipx
71
+
72
+ [pipx](https://pipx.pypa.io/) installs the CLI tool in an isolated environment while making it globally available:
57
73
 
58
74
  ```sh
59
- pip install citrascope
75
+ pipx install citrascope
60
76
  ```
61
77
 
78
+ ### Optional Dependencies
79
+
80
+ CitraScope supports different hardware adapters through optional dependency groups:
81
+
82
+ - **INDI adapter** (for Linux-based telescope control):
83
+ ```sh
84
+ pipx install citrascope[indi]
85
+ # or with pip: pip install citrascope[indi]
86
+ ```
87
+
88
+ - **All optional dependencies**:
89
+ ```sh
90
+ pipx install citrascope[all]
91
+ # or with pip: pip install citrascope[all]
92
+ ```
93
+
94
+ The base installation without optional dependencies supports the NINA adapter, which works via HTTP API calls and does not require additional Python packages.
95
+
62
96
  This provides the `citrascope` command-line tool. To see available commands:
63
97
 
64
98
  ```sh
@@ -79,31 +113,6 @@ To connect to the Citra Dev server:
79
113
  citrascope start --dev
80
114
  ```
81
115
 
82
- ## Configuration
83
-
84
- Settings are managed via environment variables with the prefix `CITRASCOPE_`. You must configure your personal access token and telescope ID, as well as INDI server details. You can set these variables in your shell or in a `.env` file at the project root.
85
-
86
- Example `.env` file:
87
-
88
- ```env
89
- CITRASCOPE_PERSONAL_ACCESS_TOKEN=citra_pat_xxx
90
- CITRASCOPE_TELESCOPE_ID=xxx
91
- # CITRASCOPE_INDI_SERVER_URL=127.0.0.1
92
- CITRASCOPE_INDI_SERVER_URL=host.docker.internal # use with devcontainer for accessing a localhost indi server
93
- CITRASCOPE_INDI_SERVER_PORT=7624
94
- CITRASCOPE_INDI_TELESCOPE_NAME=Telescope Simulator
95
- ```
96
-
97
- **Variable descriptions:**
98
-
99
- - `CITRASCOPE_PERSONAL_ACCESS_TOKEN`: Your CitraScope personal access token (required)
100
- - `CITRASCOPE_TELESCOPE_ID`: Your telescope ID (required)
101
- - `CITRASCOPE_INDI_SERVER_URL`: Hostname or IP address of the INDI server (default: `host.docker.internal` for devcontainers, or `127.0.0.1` for local)
102
- - `CITRASCOPE_INDI_SERVER_PORT`: Port for the INDI server (default: `7624`)
103
- - `CITRASCOPE_INDI_TELESCOPE_NAME`: Name of the INDI telescope device (default: `Telescope Simulator`)
104
-
105
- You can copy `.env.example` to `.env` and tweak your values.
106
-
107
116
  ## Developer Setup
108
117
 
109
118
  If you are developing on macOS or Windows, use the provided [VS Code Dev Container](https://code.visualstudio.com/docs/devcontainers/containers) setup. The devcontainer provides a full Linux environment, which is required for the `pyindi-client` dependency to work. This is necessary because `pyindi-client` only works on Linux, and will not function natively on Mac or Windows.
@@ -112,6 +121,16 @@ By opening this project in VS Code and choosing "Reopen in Container" (or using
112
121
 
113
122
  The devcontainer also ensures all required system dependencies (like `cmake`) are installed automatically.
114
123
 
124
+ ### Python Version
125
+
126
+ This project requires Python 3.10 or higher, up to Python 3.12. A `.python-version` file is included specifying Python 3.12 as the recommended version. If you use [pyenv](https://github.com/pyenv/pyenv), it will automatically use this version when you enter the project directory.
127
+
128
+ ### If not using the dev container:
129
+ ```sh
130
+ python -m venv .venv
131
+ source .venv/bin/activate
132
+ ```
133
+
115
134
  ### Installing Development Dependencies
116
135
 
117
136
  To install development dependencies (for code style, linting, and pre-commit hooks):
@@ -138,6 +157,19 @@ pre-commit run --all-files
138
157
 
139
158
  This ensures code style and quality checks are enforced for all contributors.
140
159
 
160
+ ### Releasing a New Version
161
+
162
+ To bump the version and create a release:
163
+
164
+ ```sh
165
+ bump-my-version bump patch # 0.1.3 → 0.1.4
166
+ bump-my-version bump minor # 0.1.3 → 0.2.0
167
+ bump-my-version bump major # 0.1.3 → 1.0.0
168
+ git push && git push --tags
169
+ ```
170
+
171
+ Then create a release in the GitHub UI from the new tag. This triggers automatic PyPI publishing.
172
+
141
173
  ### Running and Debugging with VS Code
142
174
 
143
175
  If you are using Visual Studio Code, you can run or debug the project directly using the pre-configured launch options in `.vscode/launch.json`:
@@ -151,7 +183,7 @@ To use these, open the Run and Debug panel in VS Code, select the desired config
151
183
 
152
184
  This project uses [pytest](https://pytest.org/) for unit testing. All tests are located in the `tests/` directory.
153
185
 
154
- To run tests manually:
186
+ To run unit tests within your devcontainer:
155
187
 
156
188
  ```bash
157
189
  pytest
@@ -0,0 +1,38 @@
1
+ citrascope/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
+ citrascope/__main__.py,sha256=r8y3_mgY2fm5XOzPgkDjq-a8uQFgdrxLrzup11UEB-I,1091
3
+ citrascope/citra_scope_daemon.py,sha256=e4PGeoBRzO14PN-g4bm_14WOugRhNQtUW-QzrBXvePQ,10598
4
+ citrascope/api/abstract_api_client.py,sha256=gjmA9mw1O-TK16nYahOWClAwqPc_L1E3F2llZJeKTPw,624
5
+ citrascope/api/citra_api_client.py,sha256=FBxqVLIhozBycFqHcx_348ZvYFjWTIFiVbIKkTrgEEU,5253
6
+ citrascope/hardware/abstract_astro_hardware_adapter.py,sha256=BdQrZkLSh2siszG8fGNEWpknC5wyZXZWgbaq7Zc7cAo,6131
7
+ citrascope/hardware/adapter_registry.py,sha256=fFIZhXYphZ_p480c6hICpcx9fNOeX-EG2tvLHm372dM,3170
8
+ citrascope/hardware/indi_adapter.py,sha256=uNrjkfxD0zjOPfar6J-frb6A87VkEjsL7SD9N9bEsC8,29903
9
+ citrascope/hardware/kstars_dbus_adapter.py,sha256=Nv6ijVDvgTCTZUmRFh3Wh-YS7ChiztiXF17OWlzJwoo,7001
10
+ citrascope/hardware/nina_adv_http_adapter.py,sha256=RCvCefwd4RWQke8AxAlafZX6vkAY26zHPO9rWOtrQB0,26217
11
+ citrascope/hardware/nina_adv_http_survey_template.json,sha256=beg4H6Bzby-0x5uDc_eRJQ_rKs8VT64sDJyAzS_q1l4,14424
12
+ citrascope/logging/__init__.py,sha256=YU38HLMWfbXh_H-s7W7Zx2pbCR4f_tRk7z0G8xqz4_o,179
13
+ citrascope/logging/_citrascope_logger.py,sha256=GkqNpFJWiatqrBr8t4o2nHt7V9bBDJ8mysM0F4AXMa8,3479
14
+ citrascope/logging/web_log_handler.py,sha256=PhltZ4l6kWQDL3ALrPeGmwMNZ1iEyWE_Lb5-F5CF82w,2599
15
+ citrascope/settings/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
16
+ citrascope/settings/citrascope_settings.py,sha256=hNy25dp7suh4F9kYsxIycSVBwpshjPLSHvytAPzzcpk,5930
17
+ citrascope/settings/settings_file_manager.py,sha256=Yijb-I9hbbVJ2thkr7OrfkNknSPt1RDpsE7VvqAs0a8,4193
18
+ citrascope/tasks/runner.py,sha256=Y_dySx0IXnhK6lzipzqRlC9ti5EZPEixri8FXYBWun0,12426
19
+ citrascope/tasks/task.py,sha256=0u0oN56E6KaNz19ba_7WuY43Sk4CTXc8UPT7sdUpRXo,1287
20
+ citrascope/tasks/scope/base_telescope_task.py,sha256=wIdyUxplFNhf_YMdCXOK6pG7HF7tZn_id59TvYyWZAY,9674
21
+ citrascope/tasks/scope/static_telescope_task.py,sha256=XP53zYVcyLHLvebDU06Jx0ghPK3tb0c_XmO60yj_XSA,1132
22
+ citrascope/tasks/scope/tracking_telescope_task.py,sha256=k5LEmEi_xnFHNjqPNYb8_tqDdCFD3YGe25Wh_brJXHk,1130
23
+ citrascope/web/__init__.py,sha256=CgU36fyNSxGXjUy3hsHwx7UxF8UO4Qsb7PjC9-6tRmY,38
24
+ citrascope/web/app.py,sha256=SPFtQTs8XJ_MijH8LMNO8SuIVg7AkibMEktJdIFnXbI,20146
25
+ citrascope/web/server.py,sha256=9nyrjep2yajZzelWKgDUwowhRRvyo-X3nCNGt2nex8Y,4758
26
+ citrascope/web/static/api.js,sha256=s-b1FIw-pTo3A8kLlLINVqHhIvfHwTWA7cEvz4N8Gqc,1924
27
+ citrascope/web/static/app.js,sha256=shzo_dtmTF7pu4S3bBtWo2EpIdFp5vzq8sefF8OFgl0,17620
28
+ citrascope/web/static/config.js,sha256=fF9Hnd_TLJWogGP_ZnsvNzLlZBRjmmgDg9w13uMUCps,12814
29
+ citrascope/web/static/style.css,sha256=wlxeWN4j5OKg9DDFnBX_WFlgNytAL61H2Mt3-NcXEZU,2155
30
+ citrascope/web/static/websocket.js,sha256=UITw1DDfehOKpjlltn5MXhewZYGKzPFmaTtMFtC0-Ps,3931
31
+ citrascope/web/static/img/citra.png,sha256=Bq8dPWB6fNz7a_H0FuEtNmZWcPHH2iV2OC-fMg4REbQ,205570
32
+ citrascope/web/static/img/favicon.png,sha256=zrbUlpFXDB_zmsIdhhn8_klnc2Ma3N6Q8ouBMAxFjbM,24873
33
+ citrascope/web/templates/dashboard.html,sha256=pRaD8Dzxo9BqDxMktBz24xbTkWpeC6_Wa41yJdJFV48,18293
34
+ docs/index.md,sha256=YQDeVrN9AcbRzo88Jc4iRCO70gAh_4GSgImrJMwcSCo,1402
35
+ citrascope-0.3.0.dist-info/METADATA,sha256=8tWhBpEf785kKyW5aPkA-MxNwof6-MWqDLQQWEp7-iQ,6650
36
+ citrascope-0.3.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
37
+ citrascope-0.3.0.dist-info/entry_points.txt,sha256=fP22Lt8bNZ_whBowDnOWSADf_FUrgAWnIhqqPf5Xo2g,55
38
+ citrascope-0.3.0.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: hatchling 1.27.0
2
+ Generator: hatchling 1.28.0
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
@@ -1,42 +0,0 @@
1
- from pydantic_settings import BaseSettings, SettingsConfigDict
2
-
3
- from citrascope.logging import CITRASCOPE_LOGGER
4
-
5
- UNDEFINED_STRING = "undefined"
6
-
7
-
8
- class CitraScopeSettings(BaseSettings):
9
- model_config = SettingsConfigDict(
10
- env_prefix="CITRASCOPE_",
11
- env_nested_delimiter="__",
12
- )
13
-
14
- # Default to production API
15
- host: str = "api.citra.space"
16
- port: int = 443
17
-
18
- personal_access_token: str = UNDEFINED_STRING
19
- use_ssl: bool = True
20
- telescope_id: str = UNDEFINED_STRING
21
-
22
- indi_server_url: str = "localhost"
23
- indi_server_port: int = 7624
24
- indi_telescope_name: str = UNDEFINED_STRING
25
- indi_camera_name: str = UNDEFINED_STRING
26
-
27
- log_level: str = "INFO"
28
-
29
- def __init__(self, dev: bool = False, log_level: str = "INFO", **kwargs):
30
- super().__init__(**kwargs)
31
- self.log_level = log_level
32
- if dev:
33
- self.host = "dev.api.citra.space"
34
- CITRASCOPE_LOGGER.info("Using development API endpoint.")
35
-
36
- def model_post_init(self, __context) -> None:
37
- if self.personal_access_token == UNDEFINED_STRING:
38
- CITRASCOPE_LOGGER.warning(f"{self.__class__.__name__} personal_access_token has not been set")
39
- exit(1)
40
- if self.telescope_id == UNDEFINED_STRING:
41
- CITRASCOPE_LOGGER.warning(f"{self.__class__.__name__} telescope_id has not been set")
42
- exit(1)
@@ -1,21 +0,0 @@
1
- citrascope/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
- citrascope/__main__.py,sha256=MlIzMVRL_tnvd8vJcZXENIglepirST3KDPfVpN7V9bE,673
3
- citrascope/citra_scope_daemon.py,sha256=rQ4U7r2q5n9FSxM7E7xTdhpJjYCT7Mv_3PhUPkWwMTc,4073
4
- citrascope/api/abstract_api_client.py,sha256=FG386RwHZtsCNaGGx0bhwxajyj_0B6SxU3p2w0R4tYU,472
5
- citrascope/api/citra_api_client.py,sha256=7T7woGN-cjTYF8CNkGSjWXCKO-q0ufnBLGrdT2pdY3w,4173
6
- citrascope/hardware/abstract_astro_hardware_adapter.py,sha256=JOw0PDoFrgicB5qZrurlLrVcDsjQNjHcxyFJ6674KJ8,3748
7
- citrascope/hardware/indi_adapter.py,sha256=57AvH-AzthqXyefUgMq21GfcFfNh9WcGoara03NiJkg,12564
8
- citrascope/logging/__init__.py,sha256=bXX2PX6MZelEX3fi_-lmT51uZCfN9WnLPZfx5_RswAA,101
9
- citrascope/logging/_citrascope_logger.py,sha256=-KZ3ufQc3VOSlP1I3KC1YFDU7o880-O0iu3URlzRGlM,1056
10
- citrascope/settings/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
11
- citrascope/settings/_citrascope_settings.py,sha256=JpuVFroZERPjbx58ZCw9BM9xr41qW6MNxm3sYGjYS14,1386
12
- citrascope/tasks/runner.py,sha256=pUyQlrQkSNbM_SKl6AUFY8QSV2NzZfGvybGlzV7Q-BU,7320
13
- citrascope/tasks/task.py,sha256=0u0oN56E6KaNz19ba_7WuY43Sk4CTXc8UPT7sdUpRXo,1287
14
- citrascope/tasks/scope/base_telescope_task.py,sha256=He8W9OSHDL2tp56sY5dPdtYDswzp5HDMMeWpSNYNcgY,9198
15
- citrascope/tasks/scope/static_telescope_task.py,sha256=DTrKZiOJ3ZPSDPvmMbyWkW50kS4I6Li6qC6SyrpWbaI,612
16
- citrascope/tasks/scope/tracking_telescope_task.py,sha256=k5LEmEi_xnFHNjqPNYb8_tqDdCFD3YGe25Wh_brJXHk,1130
17
- docs/index.md,sha256=YQDeVrN9AcbRzo88Jc4iRCO70gAh_4GSgImrJMwcSCo,1402
18
- citrascope-0.1.0.dist-info/METADATA,sha256=u7Uc7lN6PZz78TUNFqmYe3IWBgxPdfudIpg31kuuVX0,5817
19
- citrascope-0.1.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
20
- citrascope-0.1.0.dist-info/entry_points.txt,sha256=fP22Lt8bNZ_whBowDnOWSADf_FUrgAWnIhqqPf5Xo2g,55
21
- citrascope-0.1.0.dist-info/RECORD,,