Loading noctua/api/stage.py +9 −0 Original line number Diff line number Diff line Loading @@ -39,6 +39,15 @@ class Position(BaseStageResource): return self.make_response(res) class Positions(BaseStageResource): """Manage the list of the named positions""" async def get(self): """Retrieve the current stage position.""" res = await self.run_blocking(lambda: self.dev.named_position) return self.make_response(res) class Named(BaseStageResource): """Manage named positions (e.g. 'imaging', 'spectroscopy').""" Loading noctua/config/api.ini +5 −0 Original line number Diff line number Diff line Loading @@ -26,6 +26,11 @@ resource = Position device = stage depends-on = /stage/power [/stage/positions] resource = Positions device = stage depends-on = /stage/power [/stage/named] resource = Named device = stage Loading noctua/config/viewer.ini +2 −2 Original line number Diff line number Diff line Loading @@ -12,10 +12,10 @@ path = test_stx.fits path = temp2.fits [station2/scicam] path = /data/station2/latest_sci.fits path = temp2.fits [station2/teccam] path = /data/station2/latest_tec.fits path = temp2.fits [station3/scicam] path = /data/station3/latest_sci.fits Loading noctua/web/pages/base.html +3 −3 Original line number Diff line number Diff line Loading @@ -78,17 +78,17 @@ </a> <ul class="dropdown-menu dropdown-menu-dark shadow" aria-labelledby="viewerDropdown"> <li> <a class="dropdown-item" href="{{ url_for('web.viewer', station='station1') }}" target="_blank"> <a class="dropdown-item" href="{{ url_for('web.viewer', station='station1') }}"> Station 1 </a> </li> <li> <a class="dropdown-item" href="{{ url_for('web.viewer', station='station2') }}" target="_blank"> <a class="dropdown-item" href="{{ url_for('web.viewer', station='station2') }}"> Station 2 </a> </li> <li> <a class="dropdown-item" href="{{ url_for('web.viewer', station='station3') }}" target="_blank"> <a class="dropdown-item" href="{{ url_for('web.viewer', station='station3') }}"> Station 3 </a> </li> Loading noctua/web/pages/control.html +23 −21 Original line number Diff line number Diff line Loading @@ -5,9 +5,10 @@ {% block content %} <div class="row g-3"> <!-- LEFT: Telescope & Dome Controls --> <!-- LEFT: Telescope, Dome & Stage --> <section class="col-xl-4 col-lg-6"> {{ ctrl.mount_pointing() }} {{ ctrl.stage_control() }} <div class="bg-dark p-3 rounded border border-secondary shadow-sm mb-3"> {{ w.widget_input({ Loading @@ -21,49 +22,47 @@ </div> <div class="bg-dark p-3 rounded border border-secondary shadow-sm"> <h6 class="text-info mb-3">Dome & Shutter</h6> {{ w.widget_shutter("/dome/shutter", "/dome/shutter/movement", extra_flags=False) }} <aside class="row g-0 mt-2 small font-monospace"> <div class="col-4 text-success">Az: <var data-status="dome-position-azimuth">N/A</var>°</div> <div class="col-4 text-success">T: <var data-status="environment-external-Temperature_meteo_station">N/A</var>°</div> <div class="col-4 text-success text-end">Hum: <var data-status="environment-external-Humidity_meteo_station">N/A</var>%</div> </aside> </div> </section> <!-- CENTER: Camera & Sequencer Expose --> <!-- CENTER: Mode Selection & Camera --> <section class="col-xl-4 col-lg-6"> <!-- The Mode Selector dictates which station/camera is active --> {{ ctrl.observing_mode_selector() }} {{ ctrl.camera_exposure() }} <!-- Quick status of the camera --> <div class="card bg-black border-secondary p-2 small font-monospace text-success"> <div>State: <var data-status="camera-snapshot-state">N/A</var></div> <div>Mode: <span id="current-mode-label" class="text-info fw-bold">Imaging</span></div> <div>Camera State: <var data-status="camera-snapshot-state">N/A</var></div> <div>Cooler: <var data-status="camera-cooler">N/A</var> (<var data-status="camera-temperature">N/A</var>°C)</div> </div> </section> <!-- RIGHT: Monitors (FITS, Webcam, Output) --> <!-- RIGHT: Monitors --> <section class="col-xl-4 col-12"> <div class="card bg-dark border-secondary h-100 shadow-sm"> <div class="card-header p-0 border-secondary"> <div class="card-header p-0 border-secondary d-flex justify-content-between align-items-center"> <ul class="nav nav-tabs border-0" role="tablist"> <li class="nav-item"><button class="nav-link active py-2" data-bs-toggle="tab" data-bs-target="#mon-fits">FITS</button></li> <li class="nav-item"><button class="nav-link active py-2" data-bs-toggle="tab" data-bs-target="#mon-fits">FITS Viewer</button></li> <li class="nav-item"><button class="nav-link py-2" data-bs-toggle="tab" data-bs-target="#mon-webcam">Webcam</button></li> <li class="nav-item"><button class="nav-link py-2" data-bs-toggle="tab" data-bs-target="#mon-output">Output</button></li> </ul> <small class="text-muted px-3" id="active-station-id">STATION 1</small> </div> <div class="card-body p-2 bg-black overflow-auto" style="min-height: 400px;"> <div class="tab-content"> <div class="tab-pane fade show active" id="mon-fits"> <!-- Placeholder for FITS Viewer component --> <div class="text-center text-muted mt-5">FITS Monitor active</div> <div class="card-body p-0 bg-black position-relative" style="min-height: 500px;"> <div class="tab-content h-100"> <div class="tab-pane fade show active h-100" id="mon-fits"> <!-- We will inject the FitsViewer here dynamically --> <div id="fits-viewer-container" class="h-100"></div> </div> <div class="tab-pane fade" id="mon-webcam"> <img id="webcam-snapshot" class="img-fluid w-100" alt="Webcam"> </div> <div class="tab-pane fade" id="mon-output"> <div id="sequencer-output-display" class="p-3 text-info font-monospace small"> Waiting for template output data... Waiting for output data... </div> </div> </div> Loading @@ -71,11 +70,14 @@ </div> </section> {{ ctrl.fits_viewer_blueprint() }} </div> {% endblock %} {% block scripts %} <script src="{{ url_for('web.static', filename='js/control.js') }}"></script> <!-- Include the viewer as a module --> <script type="module" src="{{ url_for('web.static', filename='js/control.js') }}"></script> <script src="{{ url_for('web.static', filename='js/webcam.js') }}"></script> <script src="{{ url_for('web.static', filename='js/status-stream.js') }}"></script> <script src="{{ url_for('web.static', filename='js/actions.js') }}"></script> Loading Loading
noctua/api/stage.py +9 −0 Original line number Diff line number Diff line Loading @@ -39,6 +39,15 @@ class Position(BaseStageResource): return self.make_response(res) class Positions(BaseStageResource): """Manage the list of the named positions""" async def get(self): """Retrieve the current stage position.""" res = await self.run_blocking(lambda: self.dev.named_position) return self.make_response(res) class Named(BaseStageResource): """Manage named positions (e.g. 'imaging', 'spectroscopy').""" Loading
noctua/config/api.ini +5 −0 Original line number Diff line number Diff line Loading @@ -26,6 +26,11 @@ resource = Position device = stage depends-on = /stage/power [/stage/positions] resource = Positions device = stage depends-on = /stage/power [/stage/named] resource = Named device = stage Loading
noctua/config/viewer.ini +2 −2 Original line number Diff line number Diff line Loading @@ -12,10 +12,10 @@ path = test_stx.fits path = temp2.fits [station2/scicam] path = /data/station2/latest_sci.fits path = temp2.fits [station2/teccam] path = /data/station2/latest_tec.fits path = temp2.fits [station3/scicam] path = /data/station3/latest_sci.fits Loading
noctua/web/pages/base.html +3 −3 Original line number Diff line number Diff line Loading @@ -78,17 +78,17 @@ </a> <ul class="dropdown-menu dropdown-menu-dark shadow" aria-labelledby="viewerDropdown"> <li> <a class="dropdown-item" href="{{ url_for('web.viewer', station='station1') }}" target="_blank"> <a class="dropdown-item" href="{{ url_for('web.viewer', station='station1') }}"> Station 1 </a> </li> <li> <a class="dropdown-item" href="{{ url_for('web.viewer', station='station2') }}" target="_blank"> <a class="dropdown-item" href="{{ url_for('web.viewer', station='station2') }}"> Station 2 </a> </li> <li> <a class="dropdown-item" href="{{ url_for('web.viewer', station='station3') }}" target="_blank"> <a class="dropdown-item" href="{{ url_for('web.viewer', station='station3') }}"> Station 3 </a> </li> Loading
noctua/web/pages/control.html +23 −21 Original line number Diff line number Diff line Loading @@ -5,9 +5,10 @@ {% block content %} <div class="row g-3"> <!-- LEFT: Telescope & Dome Controls --> <!-- LEFT: Telescope, Dome & Stage --> <section class="col-xl-4 col-lg-6"> {{ ctrl.mount_pointing() }} {{ ctrl.stage_control() }} <div class="bg-dark p-3 rounded border border-secondary shadow-sm mb-3"> {{ w.widget_input({ Loading @@ -21,49 +22,47 @@ </div> <div class="bg-dark p-3 rounded border border-secondary shadow-sm"> <h6 class="text-info mb-3">Dome & Shutter</h6> {{ w.widget_shutter("/dome/shutter", "/dome/shutter/movement", extra_flags=False) }} <aside class="row g-0 mt-2 small font-monospace"> <div class="col-4 text-success">Az: <var data-status="dome-position-azimuth">N/A</var>°</div> <div class="col-4 text-success">T: <var data-status="environment-external-Temperature_meteo_station">N/A</var>°</div> <div class="col-4 text-success text-end">Hum: <var data-status="environment-external-Humidity_meteo_station">N/A</var>%</div> </aside> </div> </section> <!-- CENTER: Camera & Sequencer Expose --> <!-- CENTER: Mode Selection & Camera --> <section class="col-xl-4 col-lg-6"> <!-- The Mode Selector dictates which station/camera is active --> {{ ctrl.observing_mode_selector() }} {{ ctrl.camera_exposure() }} <!-- Quick status of the camera --> <div class="card bg-black border-secondary p-2 small font-monospace text-success"> <div>State: <var data-status="camera-snapshot-state">N/A</var></div> <div>Mode: <span id="current-mode-label" class="text-info fw-bold">Imaging</span></div> <div>Camera State: <var data-status="camera-snapshot-state">N/A</var></div> <div>Cooler: <var data-status="camera-cooler">N/A</var> (<var data-status="camera-temperature">N/A</var>°C)</div> </div> </section> <!-- RIGHT: Monitors (FITS, Webcam, Output) --> <!-- RIGHT: Monitors --> <section class="col-xl-4 col-12"> <div class="card bg-dark border-secondary h-100 shadow-sm"> <div class="card-header p-0 border-secondary"> <div class="card-header p-0 border-secondary d-flex justify-content-between align-items-center"> <ul class="nav nav-tabs border-0" role="tablist"> <li class="nav-item"><button class="nav-link active py-2" data-bs-toggle="tab" data-bs-target="#mon-fits">FITS</button></li> <li class="nav-item"><button class="nav-link active py-2" data-bs-toggle="tab" data-bs-target="#mon-fits">FITS Viewer</button></li> <li class="nav-item"><button class="nav-link py-2" data-bs-toggle="tab" data-bs-target="#mon-webcam">Webcam</button></li> <li class="nav-item"><button class="nav-link py-2" data-bs-toggle="tab" data-bs-target="#mon-output">Output</button></li> </ul> <small class="text-muted px-3" id="active-station-id">STATION 1</small> </div> <div class="card-body p-2 bg-black overflow-auto" style="min-height: 400px;"> <div class="tab-content"> <div class="tab-pane fade show active" id="mon-fits"> <!-- Placeholder for FITS Viewer component --> <div class="text-center text-muted mt-5">FITS Monitor active</div> <div class="card-body p-0 bg-black position-relative" style="min-height: 500px;"> <div class="tab-content h-100"> <div class="tab-pane fade show active h-100" id="mon-fits"> <!-- We will inject the FitsViewer here dynamically --> <div id="fits-viewer-container" class="h-100"></div> </div> <div class="tab-pane fade" id="mon-webcam"> <img id="webcam-snapshot" class="img-fluid w-100" alt="Webcam"> </div> <div class="tab-pane fade" id="mon-output"> <div id="sequencer-output-display" class="p-3 text-info font-monospace small"> Waiting for template output data... Waiting for output data... </div> </div> </div> Loading @@ -71,11 +70,14 @@ </div> </section> {{ ctrl.fits_viewer_blueprint() }} </div> {% endblock %} {% block scripts %} <script src="{{ url_for('web.static', filename='js/control.js') }}"></script> <!-- Include the viewer as a module --> <script type="module" src="{{ url_for('web.static', filename='js/control.js') }}"></script> <script src="{{ url_for('web.static', filename='js/webcam.js') }}"></script> <script src="{{ url_for('web.static', filename='js/status-stream.js') }}"></script> <script src="{{ url_for('web.static', filename='js/actions.js') }}"></script> Loading