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.