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.
- citrascope/__main__.py +8 -5
- citrascope/api/abstract_api_client.py +7 -0
- citrascope/api/citra_api_client.py +30 -1
- citrascope/citra_scope_daemon.py +214 -61
- citrascope/hardware/abstract_astro_hardware_adapter.py +70 -2
- citrascope/hardware/adapter_registry.py +94 -0
- citrascope/hardware/indi_adapter.py +456 -16
- citrascope/hardware/kstars_dbus_adapter.py +179 -0
- citrascope/hardware/nina_adv_http_adapter.py +593 -0
- citrascope/hardware/nina_adv_http_survey_template.json +328 -0
- citrascope/logging/__init__.py +2 -1
- citrascope/logging/_citrascope_logger.py +80 -1
- citrascope/logging/web_log_handler.py +74 -0
- citrascope/settings/citrascope_settings.py +145 -0
- citrascope/settings/settings_file_manager.py +126 -0
- citrascope/tasks/runner.py +124 -28
- citrascope/tasks/scope/base_telescope_task.py +25 -10
- citrascope/tasks/scope/static_telescope_task.py +11 -3
- citrascope/web/__init__.py +1 -0
- citrascope/web/app.py +470 -0
- citrascope/web/server.py +123 -0
- citrascope/web/static/api.js +82 -0
- citrascope/web/static/app.js +500 -0
- citrascope/web/static/config.js +362 -0
- citrascope/web/static/img/citra.png +0 -0
- citrascope/web/static/img/favicon.png +0 -0
- citrascope/web/static/style.css +120 -0
- citrascope/web/static/websocket.js +127 -0
- citrascope/web/templates/dashboard.html +354 -0
- {citrascope-0.1.0.dist-info → citrascope-0.3.0.dist-info}/METADATA +68 -36
- citrascope-0.3.0.dist-info/RECORD +38 -0
- {citrascope-0.1.0.dist-info → citrascope-0.3.0.dist-info}/WHEEL +1 -1
- citrascope/settings/_citrascope_settings.py +0 -42
- citrascope-0.1.0.dist-info/RECORD +0 -21
- {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.
|
|
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:
|
|
5
|
+
Author-email: Patrick McDavid <patrick@citra.space>
|
|
6
6
|
License-Expression: MIT
|
|
7
|
-
Requires-Python:
|
|
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:
|
|
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
|
-
[](https://github.com/citra-space/citrascope/actions/workflows/pytest.yml) [](https://github.com/citra-space/citrascope/actions/workflows/pytest.yml) [](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
|
|
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
|
|
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
|
-
|
|
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
|
|
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,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,,
|
|
File without changes
|