L'inglese è la lingua sorgente delle stringhe; l'italiano sta nel catalogo translations/harbour-aira-it.ts (99 stringhe), che lupdate aggiorna e lrelease compila in build. Di serie la lingua del sistema, con ripiego sull'inglese. - nuova classe Translator: risolve la lingua prima di createView e allinea QLocale::setDefault, così anche i numeri seguono la lingua (23,0 °C in italiano, 23.0 °C in inglese) — le temperature passano da formatValue, non più dal toFixed() di JavaScript che metteva sempre il punto - Qt 5.6 non ha QQmlEngine::retranslate(): al cambio di lingua la radice QML viene ricaricata (setSource ricrea il componente anche a url invariata) - le etichette di stato in airajson.cpp usano QCoreApplication::translate per esteso: lupdate non riconosce una funzione wrapper e le avrebbe perse - selettore della lingua in Impostazioni (Sistema / English / Italiano) - test: 41/41, carica il .qm vero come fa main.cpp e verifica entrambe le lingue, il ripiego e i formati numerici - anteprime bilingui (docs/anteprima/ inglese, it/ italiano), README e PIANO aggiornati, spec RPM con i cataloghi in %files
190 lines
8.0 KiB
Markdown
190 lines
8.0 KiB
Markdown
# harbour-aira
|
||
|
||
Native Sailfish OS app to monitor and control an **Aira Home** heat pump: plant
|
||
status, domestic hot water, and the house target temperature per zone.
|
||
|
||
*Versione italiana: [README.it.md](README.it.md)*
|
||
|
||

|
||
|
||
## What it does
|
||
|
||
- **Home**: house temperature and room temperature at the top, target with a
|
||
5–30 °C slider (0.5 °C steps) and a confirmation before the command is sent;
|
||
domestic hot water (current, target, boost) in its own section below; plant
|
||
status at the bottom (outdoor and indoor temperature, operating mode,
|
||
away/night/manual mode, inline heater, number of zones, errors, time of the
|
||
last reading)
|
||
- **Other commands** page: away mode, night mode for one hour, force heating,
|
||
heating function on/off, legionella cycle, DHW heating on/off and a plant
|
||
check — with the current state at the top, so nothing is pressed blindly
|
||
- **Cover page** showing the house temperature
|
||
- Address and bridge token live in the app settings (QSettings), never in the
|
||
binary
|
||
- **Languages: English and Italian.** The interface follows the phone language by
|
||
default and falls back to English when there is no catalogue for it. The
|
||
language can also be picked in the settings; the app reloads to apply it, and
|
||
numbers follow the chosen language too (decimal comma in Italian, dot in
|
||
English)
|
||
|
||
Layout previews (rendered with the real values the plant returned, **not**
|
||
screenshots — see *Status*):
|
||
|
||
| Home | Other commands | Settings | Cover |
|
||
|---|---|---|---|
|
||
|  |  |  |  |
|
||
|
||
## Why there is a bridge
|
||
|
||
Aira's cloud API is **gRPC over HTTP/2**. Qt 5.6 — the toolkit every Sailfish
|
||
app runs on — **has no HTTP/2**, so a native client cannot talk to it directly.
|
||
The alternatives (packaging `grpcio` for aarch64 with PyOtherSide, or
|
||
rewriting Cognito + gRPC in C++) are fragile and expensive.
|
||
|
||
So the logic stays **on a server**, where Python and the tokens already work, and
|
||
the app is a thin client speaking HTTP/1.1 + JSON. A side effect worth having:
|
||
credentials and session tokens never leave that machine.
|
||
|
||
```
|
||
Jolla (QML/C++ Qt 5.6) --HTTP/1.1 + JSON--> bridge (Linux, LAN) --gRPC--> cloud Aira
|
||
bridge/aira_bridge.py
|
||
```
|
||
|
||
## Requirements
|
||
|
||
- a Sailfish OS phone
|
||
- an Aira Home heat pump, with an account in the Aira app
|
||
- the bridge running on a machine that stays on, in the same LAN
|
||
(a Raspberry Pi is plenty)
|
||
|
||
## The bridge
|
||
|
||
Sources, systemd user unit and full instructions:
|
||
[`bridge/README.md`](bridge/README.md). Short version:
|
||
|
||
```sh
|
||
cd bridge
|
||
python3 -m venv .venv && . .venv/bin/activate
|
||
pip install -r requirements.txt
|
||
export AIRA_CONFIG_DIR="$HOME/.config/aira"
|
||
python setup_creds.py # Aira email + password, saved in a 600 file
|
||
python aira_bridge.py --port 8790
|
||
```
|
||
|
||
The first start writes a random token to `$AIRA_CONFIG_DIR/aira_bridge.json`
|
||
(mode 600): that value goes in the app settings, together with the LAN address of
|
||
the machine. Full API: [docs/PROTOCOL.md](docs/PROTOCOL.md).
|
||
|
||
## App settings
|
||
|
||
Address and token are configured in the **Settings** page (QSettings in
|
||
`~/.config/harbour/aira/aira.conf`): no personal data in the binary.
|
||
|
||
## Build
|
||
|
||
Requires the Sailfish SDK (`sfdk`) and an aarch64 target (Jolla Phone 2026):
|
||
|
||
```sh
|
||
sfdk target install SailfishOS-5.0.0.62-aarch64
|
||
sfdk target use SailfishOS-5.0.0.62-aarch64
|
||
sfdk build # RPM in RPMS/
|
||
sfdk deploy # to the connected device
|
||
```
|
||
|
||
From a source tarball (`harbour-aira-<version>.tar.gz`, if you were handed one):
|
||
extract it into a **new** directory (never on top of a previous extraction: the
|
||
Makefiles stay stale), or simply clone this repository.
|
||
The app log starts with `harbour-aira v<version> build <date>`, which tells a
|
||
fresh build from a stale one without guessing.
|
||
|
||
### Local checks, no SDK needed
|
||
|
||
```sh
|
||
cd tests && mkdir -p build && cd build
|
||
~/Qt/5.15.2/gcc_64/bin/qmake ../core_test.pro && make && ./core_test
|
||
```
|
||
|
||
Covers the pure logic (`src/airajson.cpp`): address normalisation, summary
|
||
parsing, mode labels, command payloads, error messages.
|
||
**The Silica UI can only be verified on a device.**
|
||
|
||
## Status
|
||
|
||
Verified so far:
|
||
|
||
- **39/39** core checks (`tests/core_test.cpp`), compiled with no warnings
|
||
- **27/27** bridge checks, offline (`bridge/test_bridge_commands.py`) —
|
||
including that a zone command always carries every zone, and that absurd
|
||
values are refused (40 °C, zone 3, text)
|
||
- **99/99** strings translated in the Italian catalogue, checked by loading the
|
||
compiled `.qm` in the test the same way `main.cpp` does: source English in,
|
||
Italian out, and back to English when the catalogue is removed
|
||
- numbers formatted through `QLocale`, so the decimal separator follows the
|
||
language (verified for both)
|
||
- `qmllint` clean on every QML file. Note it validates syntax only: without the
|
||
Silica module an invalid Silica property passes silently
|
||
- read-only queries against one real Aira Home unit, through the bridge
|
||
- the bridge runs as a systemd user unit and comes back by itself after a kill
|
||
|
||
Not verified: **the app has not been built or run on a phone yet** — the first
|
||
build is up to whoever has the Sailfish SDK. The images in `docs/anteprima/` are
|
||
layout previews built from the real plant values, not screenshots.
|
||
|
||
A Qt 5.6 note on the language switch: `QQmlEngine::retranslate()` only exists
|
||
from Qt 5.10, so installing a translator is not enough to re-translate what is
|
||
already on screen. The app therefore reloads the QML root when the language
|
||
changes: the setting applies immediately, at the cost of landing back on the home
|
||
page.
|
||
|
||
Caveats:
|
||
|
||
- **Unofficial client**, not in the Jolla Store: it talks to Aira's API with
|
||
your own account. Terms of service and trademarks remain Aira's business — use
|
||
it at your own risk, on your own pump
|
||
- tested against **one** unit so far (firmware: outdoor unit 1.30.0, system
|
||
6.10.0, climate control 3.9.12); other units and other countries may expose
|
||
different fields
|
||
- cooling is reachable from the bridge but has no UI yet; schedules/curves and
|
||
firmware info are not implemented
|
||
- only a whitelist of commands is exposed: factory reset, firmware updates,
|
||
reboots and Wi-Fi provisioning are deliberately unreachable
|
||
- no command is ever sent to the plant by the tests
|
||
|
||
## Looking for testers
|
||
|
||
If you own an Aira heat pump and a Sailfish phone, and you are willing to run the
|
||
bridge on a machine at home, I would like to hear how it behaves on your unit:
|
||
|
||
- pump model and firmware versions (visible in the Aira app)
|
||
- how many heating zones you have (1 or 2), and whether cooling is configured
|
||
- the output of `python aira_probe.py --json` (it contains no credentials)
|
||
- anything that looks wrong next to what the Aira app shows at the same moment
|
||
- your country, since Aira may not expose the same fields in every market
|
||
|
||
## Layout
|
||
|
||
```
|
||
harbour-aira.pro qmake project (icons, qml, docs)
|
||
src/airajson.{h,cpp} pure logic, testable without the SDK
|
||
src/apiclient.{h,cpp} QNetworkAccessManager + timeout watchdog
|
||
src/settings.{h,cpp} QSettings in AppConfigLocation (SailJail sandbox)
|
||
src/translator.{h,cpp} UI language: system locale, English fallback, reload
|
||
src/main.cpp context properties: appSettings, api, translator
|
||
qml/harbour-aira.qml ApplicationWindow + cover
|
||
qml/pages/MainPage.qml dashboard and water/heating commands
|
||
qml/pages/CommandsPage.qml the other commands, current state on top
|
||
qml/pages/SettingsPage.qml
|
||
qml/components/InfoRow.qml
|
||
qml/components/ActionButton.qml command button, optional confirmation
|
||
tests/core_test.cpp core checks (headless)
|
||
bridge/ local HTTP bridge -> see bridge/README.md
|
||
translations/ harbour-aira-it.ts (English is the source language)
|
||
docs/PIANO.md project plan and decisions (Italian)
|
||
docs/PROTOCOL.md bridge API
|
||
docs/anteprima/ layout previews (English; docs/anteprima/it/ Italian)
|
||
```
|
||
|
||
## License
|
||
|
||
MIT.
|