Vai al contenuto

Parità del midserver v3 con la v2

Cosa deve avere la v3 (refactor/v1) per sostituire la v2 in prod senza rompere box e pannello. Analisi del 27/10/2026, aggiornata con i dati di prod.

1. Endpoint chiamati dai box

Fonte: mdm_installation/app/clients/mid_server_client.py.

Endpoint v2 v3 Azione Priorità
POST installation/new/register ✅ ✅ dal 30/10/2026, da rilasciare era rifiutato con 403: il redirect inoltra a /v1/installation/new/register, che accettava solo il token statico del pannello, mentre i box mandano l'autenticazione Basic (SERVERUSERNAME/SERVERPASS). Riguarda anche la nuova versione: la linea stage si registra allo stesso modo (app/core/clients/mid_server_client.py, register_new), quindi senza correzione nessun box nuovo comparirebbe tra le nuove installazioni. Ora la rotta accetta entrambi (verify_token_or_basic_auth); elenco e configurazione delle nuove installazioni restano solo per il pannello. Modifica non committata su refactor/v1, con test —
POST common/installation/sync_state/{mac} ✅ ✅ redirect — —
POST common/installation/error/{mac} ✅ ✅ redirect — —
POST common/installation/callback/{token} ✅ ✅ redirect — —
POST common/installation/async/callback/{token} ✅ ❌ portare da Flask (app/share/routes.py su dev) bloccante
POST installation/receive_log/{mac} ✅ ❌ portare da Flask (app/installation/installation_routes.py su dev) bloccante
POST chat/snapshot ❌ ❌ non implementare (D17): il topic che lo attiva non è pubblicato da nessuno dal 2024 —

Stato dei box main (3.1.x–3.2.x) nel pannello dev: la lista si rompe (verificato il 30/10/2026 con MDMTESTFRIGATE1, 3.1.9). Il box manda system_load.cpu.total__logical_core (mdm_installation, app/services/installation/system_load.py, anche nella testa di main). La v3 lo legge con validation_alias ma lo riscrive come total_logical_cores anche nel formato legacy (InstallationCpuLoadV1Dto in app/features/installation/data/dtos/state.py, usato da LegacyInstallationStateDto). Il parser legacy del pannello (mdm_web_panel dev, installation.entity.g.dart, _$CpuFromJson) richiede total__logical_core e solleva un'eccezione: #/installations mostra UnexpectedFailure per tutta la lista, non solo per quel box, e resta rotta finché lo stato del box è salvato, anche con il box spento. Correzione pronta il 30/10/2026 su refactor/v1, non ancora committata (test test_installation_state_presenter_returns_legacy_payload_keys): il formato legacy restituisce di nuovo total__logical_core e average_load con le chiavi "1"/"5"/"15" come le manda il box. Da verificare sul pannello dev dopo il deploy su Coolify.

Inserimento/disinserimento dal pannello verso un box main: 503 anche se il comando riesce (verificato il 30/10/2026 con MDMTESTFRIGATE1, 3.1.9). Il box riceve q_security/disarm, esegue il comando (wrapper 2.0.1: detect.enabled: true in config.yaml) e risponde subito con POST common/installation/callback/{token} (provato: 200 in 0,1 s). La v3 valida la risposta con SetDisarmStatusData, che richiede correlation_id: lo mandano solo i box della linea stage. La validazione fallisce, il gestore generico risponde 503 e il pannello segnala un errore su un impianto che in realtà è stato inserito. Correzione pronta su refactor/v1, non ancora committata: correlation_id facoltativo (test test_set_disarm_status_data_accepts_legacy_installation_response_without_correlation_id). Da controllare le altre risposte con campi obbligatori che i box main non mandano.

Nello stesso DTO il valore predefinito di schema_version era scritto "laegcy"; corretto in "legacy" nella stessa modifica (nessun consumatore leggeva il valore sbagliato).

Risposte dei box 3.x ai comandi della v3 (verifica del 30/10/2026)

Confrontati i 48 comandi che la v3 manda ai box (publish_command_and_wait) con le risposte della 3.2.9 (531e6552, app/services/mqtt/handlers/), ricostruite come le costruisce il box (send_sync_success_response_endpoint) e validate con i modelli della v3 nello stesso modo (MQTTBaseResponse, poi il modello, poi to_entity). Configurazione e stato presi dai file reali del box di prova MDMTESTFRIGATE1. Per i box sotto la 10.0.0 la v3 usa i topic classici (q_security/...).

Comando Esito con un box 3.x Stato
disarm set 503: mancava correlation_id corretto (commit 393857d)
disarm get (GET /disarm/status, usato da qAlarm) 503: il box manda la lettura del detector ({"status": <disinserito>} Frigate, {"is_disarmed": …} GANZ), la v3 si aspettava un booleano corretto il 30/10, non committato
camera_live state 503: il box manda {<telecamera>: <token>}, la v3 si aspettava streams (fallisce anche senza live attivi) corretto il 30/10, non committato
installation_topic get_info (configurazione, GET /installation/info/{mac}) e update_configuration (PUT /installation/config/{mac}) la risposta validava, ma la v3 ricostruiva la configurazione con i nomi nuovi e perdeva envirment, sound_url, gpio_usb, webrtc_streams, enable_webRtc, enable_screen_shot, enable_sound: il pannello falliva il parsing (UnexpectedFailure, anche prima di ogni avvio del live) e, in scrittura, il box 3.x avrebbe riscritto config.json/setting.json senza quei campi, perdendo tra l'altro envirment, da cui il suo updater ricava il branch (trovato il 30/10/2026 su MDMTESTFRIGATE1) corretto il 30/10, non committato: per i box senza config_version la configurazione passa invariata nei due sensi
snapshot, snapshots, get_version, real_time_state, privacy, get_info, get_logs, live_stream, alarm-in GANZ, configurazione Frigate e wrapper, comandi che si aspettano solo status_code validi —
salute, volumi tromba, programmazione, cluster, I/O la 3.2.9 non li gestisce: la v3 aspetta 15 s e va in timeout il pannello li nasconde sotto la versione minima (VersionInfo: 3.4.0, 3.8.0, 3.8.1)
programmazione schedule (/schedule/config, /schedule/enable, /schedule/update) da qAlarm timeout di 15 s ed errore: qAlarm non controlla la versione del box corretto il 30/10/2026, non committato, in due punti: qAlarm (qAlarm2_fe) non chiede la programmazione ai box sotto la 3.4.0 e spiega perché, mostrando la versione del box; la v3 rifiuta subito con 409 ogni comando che la versione del box non ha (programmazione, salute, notifiche, volumi da 3.4.0, cluster da 3.8.0, I/O da 3.8.1), senza aspettare il timeout e senza contarlo come richiesta fallita

Script della verifica ricostruibile dai test aggiunti (test_get_disarm_status_data_accepts_legacy_detector_reading, test_installation_live_stream_response_accepts_legacy_camera_token_map). Non verificati: le risposte dei box 3.1.9 e 3.2.2 per i comandi aggiunti dopo (stesso codice dei gestori nella maggior parte dei casi) e il contenuto delle configurazioni Frigate restituite, che il modello della v3 accetta senza controllarle.

Altri requisiti verso i box: - porta 5000 raggiungibile su 172.16.16.253 (la v3 ascolta su 5005: serve una mappatura o un entrypoint del proxy su 5000); - Mosquitto su 1883 con le stesse credenziali; - topic MQTT vecchi per i box sotto la 10.0.0 (già previsto); - formato dello stato 3.2.x accettato e mostrato correttamente dal pannello.

2. Chiamate del pannello

Confronto tra le 56 chiamate del pannello (mdm_web_panel branch dev) e l'OpenAPI della v3 in dev (133 path): 44 esistono. Il login va all'API BSQ. Le altre:

Chiamata del pannello Nella v3 Azione Priorità
POST /alarm_in/status solo GET; POST /v1/detector_ganz/alarm_in/status redirect POST alta
GET /installation/client_info /client_info, /v1/panel/client_info redirect alta
GET /installation/request/erros/{mac} (refuso) /installation/request/errors/{mac} redirect con il refuso alta
GET /installation/request/logs /installation/request redirect alta
POST /cameras/group_action /frigate/group_action redirect alta
GET/PUT /frigate/pin/config/{mac}, POST /frigate/pin/trigger assente non prioritario: nessun box ha la scheda PIN; il pannello deve solo non rompersi bassa
POST /signaling/* assente non portare: codice morto; rimuovere dal pannello —
POST /request/call /v1/system_request/... (diverso) 0 chiamate in 30 giorni: rimuovere dal pannello o mappare bassa
POST /installation/connect/scp assente 0 chiamate in 30 giorni: rimuovere dal pannello bassa

2b. App Protexia e qAlarm 2

Chiamante Chiamata v2 v3 Azione Priorità
App Protexia Pagina browser /installation/live_stream/<token> delle vecchie app Presente nella v2 Non richiesta dalla nuova app (D27) Rimossa pressione lunga nel codice app; non portare la pagina nella v3. Restano rollout e verifica del player interno; preservare il servizio legacy per i vecchi client. Compatibilità dei client distribuiti da gestire prima del cambio
api.bsq (backend di Protexia, VIDEO_ALARM_API_URL = api.bsqdev.uk; JWT utente inoltrato, lib/apiBSQ/models/api.videoAlarm.lib.php e api.qAlarm.lib.php) 17 chiamate al midserver — 15 presenti; mancano POST /sound/upload (assente anche nella v2: oggi fallisce già) e POST /frigate/pin/trigger (PIN, nessun box con la scheda) Verificare risposte e autenticazione: manca il fallback BSQ checkJwt della v2; modifiche BSQ annullate (D28) Compatibilita JWT aperta
App Protexia, /signaling/create_token definita in lib/features/streaming/data/stream.dts.dart — — non usata: nessuna parte dell'app la chiama. Il live passa da api.bsq (/protexia/createLiveStream) → midserver /live_stream/create → OME —
qAlarm 2 14 chiamate (/disarm/status, /disarm/status/set, /installation/events, /installation/events/{id}/snapshots/presigned, /installation/info/{mac}, /info/current_state/{mac}, /live_stream/create, /live_stream/stop/{token}, /schedule/config, /schedule/enable, /schedule/update, /sound/config, /sound/play, /sound/stop) — ✅ tutte presenti (verificato il 27/10 sull'OpenAPI della v3 in dev) — —

Nota sul commit 6dd5e6b (28/05/2026, branch dev Flask): rende configurabile l'URL del player nella pagina live (prima era scritto wss://ome.bsqdev.uk/app/<token>). In prod (main, 2.2.0) la pagina c'è ma con l'URL scritto nel codice. Nella v3 non c'è né la pagina né il parametro.

3. Requisiti non funzionali (per andare in prod)

Requisito Stato nella v3 Azione
Health check /health presente usarlo in Coolify
Più istanze senza duplicati ❌ subscription MQTT senza $share e senza id; listener delle scadenze in ogni istanza shared subscription + lock Redis (decisione 27/10)
Redis persistente ❌ nel compose dev volume con nome + appendonly yes
Immagini con tag fissi ❌ latest fissare le versioni
Build su ECR ❌ buildspec sul modello del pannello
Sessione MQTT persistente da verificare client id stabile e session expiry
Funzioni ewelink ❌ fase successiva

4. Da verificare ancora

  • Equivalenza di comportamento (non solo di path) per i redirect: stessi campi in risposta?
  • Compatibilità con la nuova versione (cluster, IO config, nuovo formato di stato).

Autenticazione BSQ: differenza verificata il 02/11/2026

La v2 (main:app/middle_ware/auth_middleware.py, jwt_auth_middleware_in_header) validava il token inoltrato mediante JWTAUTHURL / checkJwt con app=qalarm e la credenziale M2M JWTAUTHTOKEN. In v3 verify_token ammette statico/pannello, ma non ripete quel fallback. verify_token_or_basic_auth serve alle credenziali Basic dei box e non risolve il JWT Protexia. La presenza della rotta live non prova quindi la compatibilita del percorso BSQ. Le modifiche BSQ del token di servizio sono state annullate; rimuovere il passaggio BSQ dalla creazione stream e una direzione futura (D28), non una migrazione eseguita.