Commit adf7d4cf authored by vertighel's avatar vertighel
Browse files

Frontend refactor: dependency guard, camera2, webcam clock, control panel



- dependency-guard.js: disables widget containers when subsystem root is
  off or unreachable (auto-detected from btn-universal data-url; camera
  cards use explicit data-subsystem set by applyMode)
- webcam.py Clock.get(): returns UTC ISO timestamp from ipcam clock dict
  (Europe/Rome → UTC via zoneinfo)
- api.ini: /webcam/clock as root; stream/snapshot/position depend on it;
  /camera2/* section pointing to Atik (cam2); /telescope/coordinates/resolve
- telescope.py CoordinatesResolve: resolves name/coords to canonical HMS/DMS
- control.js: MODE_CONFIG, applyMode(), Check button, stage relative move,
  EXPOSE payload builder; setInputState in ui.js
- control_panel.html (renamed from control_elements.html): mount_pointing
  with Check/Slew/Stop, camera_exposure, camera_windowing, stage_control
- init.html: camera2 (Atik) and mirror stage sections
- base.html: NoctuaWidget moved to snippet_viewer; dependency-guard loaded
- style.css: .subsystem-offline (opacity 0.4, pointer-events none)

Co-Authored-By: default avatarClaude Sonnet 4.6 <noreply@anthropic.com>
parent 4c4ce118
Loading
Loading
Loading
Loading
+17 −0
Original line number Diff line number Diff line
@@ -114,6 +114,23 @@ class CoordinatesMovement(BaseResource):
        return self.make_response(res)


class CoordinatesResolve(BaseResource):
    '''Resolve a target name or coordinate string to canonical HMS/DMS without moving.'''

    @expects(param_type="string", unit="hms ±dms / id", placeholder="Polaris")
    async def post(self):
        '''Return the resolved canonical coordinate string, or an error if unresolvable.'''
        target = await self.get_payload()
        radec = await self.run_blocking(to_radec, target)

        if radec[0] is None:
            return self.make_response(None, errors=["Cannot resolve target"])

        # to_radec returns [ra_hours, dec_deg]; to_hms_dms expects degrees
        canonical = to_hms_dms([radec[0] * 15.0, radec[1]], join=True)
        return self.make_response(canonical, raw_data=radec)


class CoordinatesMovementRadec(BaseResource):
    '''Point the telescope in Ra, Dec.'''

+14 −0
Original line number Diff line number Diff line

# System modules
import asyncio
from datetime import datetime
from zoneinfo import ZoneInfo

# Third-party modules
from quart import Response, stream_with_context
@@ -28,6 +30,18 @@ class Pointing(BaseResource):
        res = await self.run_blocking(action)
        return self.make_response(res)

class Clock(BaseResource):
    """Timestamp from the webcam."""

    async def get(self):
        """Retrieve the webcam clock as a UTC ISO timestamp."""
        clock = await self.run_blocking(lambda: self.dev.clock)
        local_dt = datetime.strptime(
            f"{clock['date']} {clock['time']}", '%Y-%m-%d %H:%M:%S'
        ).replace(tzinfo=ZoneInfo('Europe/Rome'))
        utc_iso = local_dt.astimezone(ZoneInfo('UTC')).isoformat()
        return self.make_response(utc_iso)

class Snapshot(BaseResource):
    """Image from the webcam."""

+80 −0
Original line number Diff line number Diff line
@@ -137,6 +137,10 @@ resource = Coordinates
device = tel
depends-on = /telescope/clock

[/telescope/coordinates/resolve]
resource = CoordinatesResolve
device = tel

[/telescope/coordinates/movement]
resource = CoordinatesMovement
device = tel
@@ -309,21 +313,97 @@ resource = Settings
device = cam
depends-on = /camera/power

##############
# camera2 (Atik — spectro/echelle station)
##############

[/camera2/power]
resource = State
device = pdu_cam2
depends-on = /telescope/power

[/camera2/frame/binning]
resource = FrameBinning
device = cam2
depends-on = /camera2/power

[/camera2/frame/full]
resource = FrameFull
device = cam2
depends-on = /camera2/power

[/camera2/frame/half]
resource = FrameHalf
device = cam2
depends-on = /camera2/power

[/camera2/frame/small]
resource = FrameSmall
device = cam2
depends-on = /camera2/power

[/camera2/cooler]
resource = Cooler
device = cam2
depends-on = /camera2/power

[/camera2/cooler/temperature/setpoint]
resource = CoolerTemperatureSetpoint
device = cam2
depends-on = /camera2/power

[/camera2/cooler/warmup]
resource = CoolerWarmup
device = cam2
depends-on = /camera2/power

[/camera2/snapshot]
resource = Snapshot
device = cam2
depends-on = /camera2/power

[/camera2/snapshot/state]
resource = SnapshotState
device = cam2
depends-on = /camera2/power

[/camera2/snapshot/recenter]
resource = SnapshotRecenter
device = cam2
depends-on = /camera2/power

[/camera2/settings]
resource = Settings
device = cam2
depends-on = /camera2/power

# [/camera2/snapshot/domeslewing]
# resource = SnapshotDomeslewing
# device = cam2
# depends-on = /camera2/power

##############
# webcam
##############

[/webcam/clock]
resource = Clock
device = ipcam

[/webcam/stream]
resource = VideoStream
device = ipcam
depends-on = /webcam/clock

[/webcam/snapshot]
resource = Snapshot
device = ipcam
depends-on = /webcam/clock

[/webcam/position]
resource = Pointing
device = ipcam
depends-on = /webcam/clock

# ##############
# # environment
+3 −5
Original line number Diff line number Diff line
@@ -20,8 +20,6 @@

<body class="d-flex flex-column" style="padding-bottom: 180px;">

  {% include "macros/widget_blueprints.html" %}

  <!-- ── Navbar ─────────────────────────────────────────────────────────── -->
    <nav class="navbar navbar-expand-sm bg-dark border-bottom border-secondary mb-4 px-3" style="padding-top:6px;padding-bottom:6px;">

@@ -169,10 +167,10 @@
    <script type="module" src="{{ url_for('web.static', filename='js/status-stream.js') }}"></script>
    <script type="module" src="{{ url_for('web.static', filename='js/status-view.js') }}"></script>
    <script type="module" src="{{ url_for('web.static', filename='js/ws-client.js') }}"></script>
    <script type="module" src="{{ url_for('web.static', filename='js/dependency-guard.js') }}"></script>
    
    <!-- Gli altri script di pagina tradizionali e web components -->
    <!-- Gli altri script di pagina tradizionali -->
    <script src="{{ url_for('web.static', filename='js/actions.js') }}"></script>
    <script type="module" src="{{ url_for('web.static', filename='js/components/NoctuaWidget.js') }}"></script>

    {% block scripts %}{% endblock %}
</body>
+1 −1
Original line number Diff line number Diff line
{% extends "base.html" %}
{% import "macros/widgets.html" as w %}
{% import "macros/control_elements.html" as ctrl %}
{% import "macros/sections/control_panel.html" as ctrl %}

{% block content %}
<div class="row g-3">
Loading