Commit fce177b8 authored by vertighel's avatar vertighel
Browse files

webcam panel: reusable macro, widget_onoff toggle, init.html 3-column layout



- webcam_panel.html: new reusable macro (image + Light/Lamp toggles + PTZ)
- widget_onoff: compact badge + single toggle button (no extra data attrs);
  state derived from data-url by toggle.js
- toggle.js: updates btn-onoff data-value and color from noctua-telemetry
- webcam.html: simplified to macro call
- control.html: webcam tab uses webcam_panel macro
- init.html: 3-column layout — telescope+dome / stage+cameras / webcam

Co-Authored-By: default avatarClaude Sonnet 4.6 <noreply@anthropic.com>
parent 81a61642
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -168,6 +168,7 @@
    <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>
    <script type="module" src="{{ url_for('web.static', filename='js/toggle.js') }}"></script>
    
    <!-- Gli altri script di pagina tradizionali -->
    <script src="{{ url_for('web.static', filename='js/actions.js') }}"></script>
+2 −1
Original line number Diff line number Diff line
{% extends "base.html" %}
{% import "macros/widgets.html" as w %}
{% import "macros/sections/control_panel.html" as ctrl %}
{% import "macros/sections/webcam_panel.html" as webcam %}

{% block content %}
<div class="row g-3">
@@ -60,7 +61,7 @@
                        <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">
                        {{ webcam.webcam_panel() }}
                    </div>
                    <div class="tab-pane fade" id="mon-output">
                         <div id="sequencer-output-display" class="p-3 text-info font-monospace small">
+104 −167
Original line number Diff line number Diff line
{% extends "base.html" %}
{% import "macros/widgets.html" as w %}
{% import "macros/sections/webcam_panel.html" as webcam %}

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

    {# ── LEFT: Telescope + Dome ── #}
    <section class="col-xl-4 col-lg-6">

    <section class="col-xl-6 p-3">
        <div class="bg-dark p-4 rounded shadow mb-4">
            <h5 class="pb-2 mb-4">Telescope Status</h5>

            {{
              w.widget_toggle({
            {{ w.widget_toggle({
                "label": "Is Cabinet On?",
                "info": "/telescope/power",
                "buttons": [
                    {"label": "On",  "endpoint": "/telescope/power", "val": true,  "method": "PUT"},
                    {"label": "Off", "endpoint": "/telescope/power", "val": false, "method": "PUT"}
                ],
              })
            }}
            }) }}

            {{
              w.widget_toggle({
            {{ w.widget_toggle({
                "label": "Is Tel Parked?",
                "info": "/telescope/coordinates/movement/atpark",
                "buttons": [
                    {"label": "Unpark", "endpoint": "/telescope/coordinates/movement/unpark", "method": "POST"},
                    {"label": "Park",   "endpoint": "/telescope/coordinates/movement/park",   "method": "POST"}
                ],
              })
            }}
            }) }}

            {{
              w.widget_toggle({
            {{ w.widget_toggle({
                "label": "Is Tel Tracking?",
                "info": "/telescope/coordinates/tracking",
                "buttons": [
                    {"label": "Point webcam",  "endpoint": "/telescope/coordinates/movement/altaz",  "val": [25, 85],  "method": "POST"},
                    {"label": "Track Polaris", "endpoint": "/telescope/coordinates/movement/radec",  "val": "Polaris", "method": "POST"}
                ],
              })
            }}
            }) }}

            {{
              w.widget_toggle({
            {{ w.widget_toggle({
                "label": "Petals",
                "info": "/telescope/cover",
                "buttons": [
                    {"label": "Open",  "endpoint": "/telescope/cover/movement", "val": true,  "method": "POST"},
                    {"label": "Close", "endpoint": "/telescope/cover/movement", "val": false, "method": "POST"}
                ],
              })
            }}
            }) }}

            {{
              w.widget_input({
            {{ w.widget_input({
                "label": "Global Status",
                "info": "/telescope/error",
                "inputs": [{"value": 2, "placeholder": "Error ID"}],
                "unit": "#",
                "buttons": [{
                    "label": "Clear error", 
                    "endpoint": "/telescope/error", 
                    "method": "DELETE"
                }],
                "buttons": [{"label": "Clear error", "endpoint": "/telescope/error", "method": "DELETE"}],
                "info_list": [{"label": "detail", "status": "telescope-error-details"}]
              })
            }}
            }) }}

            <h5 class="pb-2 mb-4 mt-5">Telescope Offsets</h5>

            {{
              w.widget_input({
            {{ w.widget_input({
                "inputs": [
                    {"label": "Zd", "value": -300},
                    {"label": "Az", "value": -300}
@@ -81,29 +69,21 @@
                    {"label": "alt", "status": "telescope-coordinates-offset-0"},
                    {"label": "az",  "status": "telescope-coordinates-offset-1"}
                ]
              })
            }}
            }) }}

            {{
              w.widget_input({
            {{ w.widget_input({
                "label": "Rotator",
                "inputs": [{"value": 0}],
                "unit": "°",
                "buttons": [{"label": "Set", "endpoint": "/telescope/rotator/movement", "method": "POST"}],
                "info_list": [
                  {"label": "rot", "status": "telescope-rotator"},
                ],
              })
            }}
                "info_list": [{"label": "rot", "status": "telescope-rotator"}]
            }) }}
        </div>
    <!-- </section> -->

    <!-- <section class="col-xl-6 p-3"> -->
        <div class="bg-dark p-4 rounded shadow mb-4">
            <h5 class="pb-2 mb-4">Dome</h5>

            {{
              w.widget_input({
            {{ w.widget_input({
                "label": "Azimuth",
                "inputs": [{"value": 0.1}],
                "unit": "°",
@@ -115,54 +95,83 @@
                    {"label": "slaved", "status": "dome-position-slaved"},
                    {"label": "az",     "status": "dome-position-azimuth"}
                ]
              })
            }}
            }) }}

            {{
              w.widget_toggle({
            {{ w.widget_toggle({
                "label": "Dome Position",
                "buttons": [
                    {"label": "Park", "endpoint": "/dome/position/movement/park", "method": "POST"},
                    {"label": "Stop", "endpoint": "/dome/position/movement",      "method": "DELETE"}
                ],
              })
            }}
            }) }}

            {{
              w.widget_shutter(
            {{ w.widget_shutter(
                get_url  = "/dome/shutter",
                move_url = "/dome/shutter/movement",
              )
            }}
            ) }}
        </div>

    </section>

    {# ── CENTER: Stage + Cameras ── #}
    <section class="col-xl-4 col-lg-6">

        <div class="bg-dark p-4 rounded shadow mb-4">
            <h5 class="pb-2 mb-4">Mirror Stage</h5>

            {{ w.widget_toggle({
                "label": "Connection",
                "info": "/stage/connection",
                "buttons": [
                    {"label": "On",  "endpoint": "/stage/connection", "val": true,  "method": "PUT"},
                    {"label": "Off", "endpoint": "/stage/connection", "val": false, "method": "PUT"}
                ],
            }) }}

            {{ w.widget_toggle({
                "label": "Power",
                "info": "/stage/power",
                "buttons": [
                    {"label": "On",  "endpoint": "/stage/power", "val": true,  "method": "PUT"},
                    {"label": "Off", "endpoint": "/stage/power", "val": false, "method": "PUT"}
                ],
            }) }}

            {{ w.widget_toggle({
                "label": "Init",
                "info": "/stage/status",
                "buttons": [
                    {"label": "Initialize", "endpoint": "/stage/status", "method": "POST"}
                ],
                "info_list": [
                    {"label": "init", "status": "stage-status"},
                    {"label": "pos",  "status": "stage-position"}
                ],
            }) }}
        </div>

        <div class="bg-dark p-4 rounded shadow mb-4">
            <h5 class="pb-2 mb-4">Camera</h5>

            {{
              w.widget_toggle({
            {{ w.widget_toggle({
                "label": "Is Cam On?",
                "info": "/camera/power",
                "buttons": [
                    {"label": "On",  "endpoint": "/camera/power", "val": true,  "method": "PUT"},
                    {"label": "Off", "endpoint": "/camera/power", "val": false, "method": "PUT"}
                ],
              })
            }}
            }) }}

            {{
              w.widget_toggle({
            {{ w.widget_toggle({
                "label": "Cooling",
                "info": "/camera/cooler",
                "buttons": [
                    {"label": "On",  "endpoint": "/camera/cooler", "val": true,  "method": "PUT"},
                    {"label": "Off", "endpoint": "/camera/cooler", "val": false, "method": "PUT"}
                ],
              })
            }}
            }) }}

            {{
              w.widget_input({
            {{ w.widget_input({
                "label": "Temperature",
                "inputs": [{"value": -10}],
                "unit": "°C",
@@ -172,38 +181,31 @@
                    {"label": "set", "status": "camera-settings-setpoint"},
                    {"label": "T",   "status": "camera-settings-temperature"}
                ]
              })
            }}

            }) }}
        </div>

        <div class="bg-dark p-4 rounded shadow mb-4">
            <h5 class="pb-2 mb-4">Camera 2 (Atik)</h5>

            {{
              w.widget_toggle({
            {{ w.widget_toggle({
                "label": "Is Cam2 On?",
                "info": "/camera2/power",
                "buttons": [
                    {"label": "On",  "endpoint": "/camera2/power", "val": true,  "method": "PUT"},
                    {"label": "Off", "endpoint": "/camera2/power", "val": false, "method": "PUT"}
                ],
              })
            }}
            }) }}

            {{
              w.widget_toggle({
            {{ w.widget_toggle({
                "label": "Cooling",
                "info": "/camera2/cooler",
                "buttons": [
                    {"label": "On",  "endpoint": "/camera2/cooler", "val": true,  "method": "PUT"},
                    {"label": "Off", "endpoint": "/camera2/cooler", "val": false, "method": "PUT"}
                ],
              })
            }}
            }) }}

            {{
              w.widget_input({
            {{ w.widget_input({
                "label": "Temperature",
                "inputs": [{"value": -10}],
                "unit": "°C",
@@ -212,84 +214,19 @@
                    {"label": "set", "status": "camera2-settings-setpoint"},
                    {"label": "T",   "status": "camera2-settings-temperature"}
                ]
              })
            }}

            }) }}
        </div>

    </section>

    <section class="col-xl-6 p-3">


        <div class="bg-dark p-4 rounded shadow mb-4">
            <h5 class="pb-2 mb-4">Mirror Stage</h5>

            {{
              w.widget_toggle({
                "label": "Connection",
                "info": "/stage/connection",
                "buttons": [
                    {"label": "On", "endpoint": "/stage/connection", "val": true, "method": "PUT"},
                    {"label": "Off", "endpoint": "/stage/connection", "val": false, "method": "PUT"}
                ],
              })
            }}

            {{
              w.widget_toggle({
                "label": "Power",
                "info": "/stage/power",
                "buttons": [
                    {"label": "On", "endpoint": "/stage/power", "val": true, "method": "PUT"},
                    {"label": "Off", "endpoint": "/stage/power", "val": false, "method": "PUT"}
                ],
              })
            }}

            {{
              w.widget_toggle({
                "label": "Init",
                "info": "/stage/status",
                "buttons": [
                    {"label": "Initialize", "endpoint": "/stage/status", "method": "POST"}
                ],
                "info_list": [
                    {"label": "init", "status": "stage-status"},
                    {"label": "pos",  "status": "stage-position"}
                ],
              })
            }}

        </div>

      
        <div class="bg-dark p-4 rounded shadow mb-4">
            <h5 class="pb-2 mb-4">Dome Webcam</h5>

            {{ w.widget_toggle({
                'label': "Flat Lamp",
                'info': "/telescope/lamp",
                'buttons': [
                    {'label': "On", 'endpoint': "/telescope/lamp", 'val': true, 'method': "PUT"},
                    {'label': "Off", 'endpoint': "/telescope/lamp", 'val': false, 'method': "PUT"}
                ],
            }) }}
            
            {{ w.widget_toggle({
                'label': "Dome Light",
                'info': "/dome/light",
                'buttons': [
                    {'label': "On", 'endpoint': "/dome/light", 'val': true, 'method': "PUT"},
                    {'label': "Off", 'endpoint': "/dome/light", 'val': false, 'method': "PUT"}
                ],
            }) }}
        </div>
    {# ── RIGHT: Webcam ── #}
    <section class="col-xl-4 col-lg-12">
        {{ webcam.webcam_panel() }}
    </section>

            
</div>
{% endblock %}

{% block scripts %}
<script src="{{ url_for('web.static', filename='js/webcam.js') }}"></script>
{% endblock %}
+53 −0
Original line number Diff line number Diff line
{#
    sections/webcam_panel.html
    --------------------------
    Reusable webcam panel: snapshot image, Light/Lamp toggles, PTZ controls.
    Pages that include this macro must load webcam.js in their scripts block.
#}
{% from "macros/widgets.html" import widget_onoff, widget_toggle %}

{% macro webcam_panel() %}
<div class="card bg-dark shadow border-secondary mb-3" id="webcam-card">

    <div class="position-relative bg-black text-center" style="min-height: 200px;">
        <img id="webcam-snapshot" class="img-fluid w-100 object-fit-contain"
             style="max-height: 350px;" alt="Waiting for webcam..." src="">
    </div>

    <div class="card-body">

        <div class="d-flex gap-3 align-items-center mb-3">
            {{ widget_onoff('Light', 'dome-light',      '/dome/light')      }}
            {{ widget_onoff('Lamp',  'telescope-lamp',  '/telescope/lamp')  }}
        </div>

        <hr class="border-secondary my-2">

        <aside class="row align-items-end g-2 mt-1">
            <div class="col">
                <label class="form-label small text-muted">Alt / Az delta</label>
                <div class="input-group input-group-sm">
                    <input id="webcam-position" class="form-control" type="number"
                           value="20" style="max-width: 70px;">
                    <span class="input-group-text">°</span>
                    <button type="button" class="btn btn-secondary btn-webcam-move"
                            data-sign="+1" data-mode="0" title="Up"></button>
                    <button type="button" class="btn btn-secondary btn-webcam-move"
                            data-sign="-1" data-mode="0" title="Down"></button>
                    <button type="button" class="btn btn-secondary btn-webcam-move"
                            data-sign="-1" data-mode="1" title="Left"></button>
                    <button type="button" class="btn btn-secondary btn-webcam-move"
                            data-sign="+1" data-mode="1" title="Right"></button>
                </div>
            </div>
            <div class="col-auto">
                {{ widget_toggle({'buttons': [
                    {'label': "Reset",    'endpoint': "/webcam/position", 'val': [15, 180], 'method': "PUT"},
                    {'label': "Look top", 'endpoint': "/webcam/position", 'val': [55, 170], 'method': "PUT"}
                ]}) }}
            </div>
        </aside>

    </div>
</div>
{% endmacro %}
+15 −0
Original line number Diff line number Diff line
@@ -25,6 +25,21 @@
{% endmacro %}


{# --- WIDGET: On/Off Toggle --- #}
{% macro widget_onoff(label, status, endpoint) %}
{% set safe_id = label | replace(' ', '-') | lower %}
<div class="d-flex align-items-center gap-2" id="onoff-{{ safe_id }}">
    <var class="badge bg-secondary font-monospace" data-status="{{ status }}">N/A</var>
    <button class="btn btn-outline-primary btn-sm btn-universal btn-onoff"
            data-method="PUT"
            data-url="{{ endpoint }}"
            data-value="true">
        {{ label }}
    </button>
</div>
{% endmacro %}


{# --- WIDGET: Toggle --- #}
{% macro widget_toggle(config) %}
{% set safe_id = config.label | replace(' ', '-') | replace('?', '') | lower %}
Loading