harbour-aira 0.1.0: client Sailfish per pompa di calore Aira (bridge HTTP + stato e comandi ACS)

This commit is contained in:
Carlo
2026-10-09 21:00:59 +02:00
commit 15963039ea
27 changed files with 1686 additions and 0 deletions
+95
View File
@@ -0,0 +1,95 @@
# 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 <token>` 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`).