# harbour-aira — app Sailfish per la pompa di calore Aira Piano scritto il 9 ottobre 2026, prima di scrivere la UI (convenzione di lavoro). ## 1. Stato verificato sul campo | Cosa | Esito | |---|---| | Accesso cloud Aira | **funziona** — `pyairahome` 2.3.0, pool Cognito `eu-north-1_cnqyjWtbz` (indice 0), token salvati in `~/.hermes/profiles/carlo/aira_tokens.json` (600) | | Lettura impianto | **funziona** — esterna, interna, ACS attuale/obiettivo, modalità, curve zone, firmware, errori | | Bridge HTTP sul server | **scritto e provato** — `~/workspace/Carlo/Aira/aira_bridge.py`, v0.1.0 | | Bluetooth sul server | **assente** — nessun adattatore HCI (esclude la via locale BLE su questa macchina) | | SDK Sailfish (`sfdk`) | **assente qui** — build e deploy li fa Carlo dal suo PC | | Jolla Phone 2026 | non raggiungibile dalla rete del server: deploy solo dal PC | ## 2. Perché serve un bridge e non una chiamata diretta Il cloud Aira espone **gRPC su HTTP/2**. Qt 5.6 — il toolkit su cui gira Sailfish — **non ha HTTP/2**, quindi un'app nativa non può parlarci direttamente. Vie alternative valutate e scartate: - **PyOtherSide + pyairahome dentro l'app**: servirebbe impacchettare `grpcio` e `bleak` compilati per aarch64/SFOS, con l'RPM che diventa fragile a ogni aggiornamento. - **Cognito + gRPC riscritti in C++**: HTTP/2 e protobuf da zero. Molto lavoro, molto rischio. Scelta: **la logica resta sul server** (dove Python e i token già funzionano), l'app è un client sottile. Vantaggio collaterale: credenziali e token non stanno mai sul telefono. ``` Jolla (QML/C++ Qt 5.6) --HTTP/1.1 + JSON--> bridge sul server --gRPC--> cloud Aira (pyairahome + token) ``` ## 3. Protocollo del bridge (v1 — già implementato) Autenticazione: `Authorization: Bearer ` su tutto tranne `/health`. Token generato al primo avvio in `~/.hermes/profiles/carlo/aira_bridge.json` (600). | Metodo | Rotta | Risposta | |---|---|---| | GET | `/health` | `{ok, version}` — nessuna auth, per la diagnostica | | GET | `/summary` | valori leggibili: temperature, ACS, modalità, flag, errori | | GET | `/state` | stato completo grezzo (42 campi) | | GET | `/commands` | elenco comandi ammessi + parametri | | POST | `/command` | `{"id": "...", "value": ...}` | Comandi ammessi in v1: `ping`, `set_hot_water_target` (45–60 °C), `hot_water_boost_on/off`, `hot_water_heating_on/off`, `away_mode_on/off`, `night_mode_1h`, `force_heating_on/off`, `heating_on/off`, `legionella_cycle`. **Whitelist voluta**: la libreria espone ~90 comandi, inclusi `FactoryReset`, `InstallFirmware`, `RebootDevice`, `RotateCertificate`. Quelli restano fuori di proposito: un client mobile non deve poter riformattare l'impianto per un tap sbagliato. ## 4. Architettura dell'app - `harbour-aira.pro` / `rpm/` / `icons/` dai template consolidati della skill. - **C++ minimo**: `Settings` (QSettings su `AppConfigLocation`, obbligatorio per la sandbox SailJail) e `ApiClient` (QNetworkAccessManager + watchdog di timeout 15 s, JSON parsing). Esposti come context properties: `appSettings`, `api`. - **QML**: `MainPage` (dashboard), `SettingsPage` (indirizzo bridge + token), `CoverPage`. - Nessun dato personale nel binario: indirizzo e token si configurano nell'app (le repo sono pubbliche su Gitea). ## 5. Fasi - **F0 — ponte (fatto)**: bridge scritto, provato su `/health`, `/summary`, `/commands`, errori 400/401 verificati. Nessun comando inviato all'impianto. - **F1 — v0.1 in sola lettura**: dashboard con esterna/interna/ACS, modalità, stato ACS, pull-to-refresh, copertina con le temperature. È già utile e non può fare danni. - **F2 — comandi**: ACS obiettivo (slider 45–60), boost, away, night mode. Conferme con `RemorseItem`/`RemorsePopup` per le azioni che durano. - **F3 — servizio e rete**: unità systemd per il bridge (avvio automatico), poi la via di accesso dal telefono (VPN WireGuard già attiva, oppure sottodominio HTTPS dietro reverse proxy: in quel caso servono DNS e certificato, che Carlo applica dal pannello). ## 6. Rischi noti - **Dipendenza dal server**: se il bridge è spento, l'app non vede nulla. Mitigazione: unità systemd con riavvio automatico (F3). - **Scadenza credenziali**: i token Cognito si rinnovano da soli per settimane; quando il refresh token scade serve rilanciare `setup_creds.py` sul server. L'app deve mostrare un errore chiaro, non un retry infinito. - **Assenza di test sulla UI**: senza SDK né device raggiungibile da qui, la UI Silica si verifica solo sul telefono di Carlo (ciclo consolidato: io consegno il tarball, lui compila e incolla i log). - **Token del bridge**: è l'unica credenziale sul telefono; va trattato come una password e revocabile rigenerando `aira_bridge.json`. ## 7. Decisioni aperte 1. **Come raggiungere il bridge dal telefono**: VPN WireGuard (già attiva, zero configurazione nuova) oppure sottodominio HTTPS pubblico con reverse proxy. 2. **Ambito della v0.1**: sola lettura (consigliata) oppure lettura + comandi ACS subito. 3. **Nome visibile dell'app**: default proposto "Aira" (pacchetto `harbour-aira`).