# 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)* ![architecture](docs/architettura.svg) ## 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 Layout previews (rendered with the real values the plant returned, **not** screenshots — see *Status*): | Home | Other commands | Cover | |---|---|---| | ![home](docs/anteprima/dashboard.png) | ![commands](docs/anteprima/comandi.png) | ![cover](docs/anteprima/copertina.png) | ## 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-.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 build `, 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: - **31/31** 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) - `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. 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/main.cpp context properties: appSettings, api 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 docs/PIANO.md project plan and decisions (Italian) docs/PROTOCOL.md bridge API docs/anteprima/ layout previews ``` ## License MIT.