Skip to content

Repository files navigation

toon-esphomeair

A QML app for the Eneco Toon thermostat display that shows live air-quality data from local ESPHome devices: CO₂, PM2.5 (indoor and outdoor) and fan speed.

Everything is polled straight from the ESPHome web server over your LAN — no cloud, no broker, no Home Assistant required.

The tile

The tile renders up to three rows, each shown only when the matching device is configured:

CO₂ (ppm):      612
PM2.5 (µg/m³):  4|11        ← indoor|outdoor
🌀 (%):         35

Tapping the tile opens the settings screen. The app also adds a Luchtkwaliteit menu item that opens the same screen.

Requirements

  • A rooted Toon running the ToonStore client (tsc). Settings are stored in /mnt/data/tsc/, which is the ToonStore data directory.

  • One or more ESPHome devices with the web server component enabled:

    web_server:
        port: 80
        version: 2

    The app reads http://<ip>/<sensor path> and expects a JSON body with a numeric value field, which is what the ESPHome web server returns for a sensor:

    { "id": "sensor-carbon_dioxide", "value": 612, "state": "612 ppm" }
  • The Toon and the ESPHome devices must be on the same network, reachable by plain HTTP (no TLS, no authentication — the app sends unauthenticated GET requests).

Installation

Copy the repository contents into an esphomeair directory under the Toon's apps directory and restart the UI:

scp -r *.qml qmldir version.txt root@<toon-ip>:/qmf/qml/apps/esphomeair/

The exact apps path depends on your firmware and root method — check where your other ToonStore apps live and use the same parent directory. After restarting the Toon UI, add the tile via the tile screen's + button (category general, label Luchtkwaliteit).

Configuration

Open the settings screen from the tile or the menu. All fields are optional; a row disappears from the tile when its device is left blank.

Setting Default Description
ESPHome sensor IP (empty) Device serving indoor CO₂ and PM2.5
CO2 sensor sensor/Carbon Dioxide Path for the CO₂ reading on that device
PM2.5 sensor sensor/PM2.5 Path for the indoor PM2.5 reading
Buiten PM2.5 IP (empty) Second device serving an outdoor PM2.5 reading
Buiten PM2.5 sensor sensor/PM2.5 Path for the outdoor PM2.5 reading
ESPHome ventilator IP (empty) Device serving the fan speed
Ventilator pad sensor/Fan Speed Path for the fan speed reading
Verversing (s) 60 Poll interval, clamped to 10–300 seconds

Press Opslaan to save. Settings are written to /mnt/data/tsc/esphomeair.userSettings.json and reloaded on startup; saving also triggers an immediate refresh.

Finding the right sensor path

Open http://<device-ip>/ in a browser and look at the entity rows, or check the id:/name: of the sensor in your ESPHome YAML. The defaults above match the author's devices — yours will likely differ, which is why every path is editable.

How it works

EsphomeairApp.qml runs a Timer at the configured interval and walks a chain of XMLHttpRequest calls — CO₂ → indoor PM2.5 → outdoor PM2.5 → fan speed — each step invoking the next from its readyState handler, so at most one request is in flight at a time. Steps whose device is left blank fall through to the next one. A response that fails, times out or does not contain a number resets that reading to , so an unreachable device is visible rather than frozen on its last value.

File Role
EsphomeairApp.qml App root: settings persistence, fetch chain, refresh timer
EsphomeairTile.qml The tile — three label/value rows plus a drawn fan icon
EsphomeairSettingsScreen.qml Settings screen with on-screen keyboard input
EsphomeairMenu.qml Menu entry that opens the settings screen
EditTextLabel4421.qml Editable label control, copied from the TSC buienradar app
qmldir Declares the apps.esphomeair module

The UI is in Dutch, matching the rest of the Toon interface.

Development

Formatting and linting run through pre-commit:

pip install pre-commit
pre-commit install
pre-commit run --all-files

That runs prettier on JSON/YAML/Markdown and pyside6-qmlformat / pyside6-qmllint (from PySide6) on the QML. The same checks run on pull requests via .github/workflows/pr-lint.yml; qmllint is advisory, since the Toon's qb.components types are not available outside the device.

There is no way to run the app off-device: it depends on Toon-private QML modules (qb.components, qb.base, FileIO, BasicUIControls). Test on a real Toon.

Tile dimensions

A tile is 142 × 60 px in the grid (~2.4 : 1), drawn in a scaled-up coordinate space. Content must stay compact horizontally — a wide label (unit): value row runs into the right edge and clips. isNxt selects the larger font/width values for Toon 2 (NXT) hardware.

Known limitations

  • Temperature is not displayed. The app used to fetch it and throw it away; the request was removed rather than squeezing a fourth row into the tile.
  • Sensor readings are rounded to whole numbers.
  • lastUpdated is tracked on every refresh but no tile row shows it yet.

License

MIT, with one exception: EditTextLabel4421.qml is copied from the Toon Software Collective buienradar app and is not covered by that grant. That project declares no license of its own.

About

Air-quality tile for the Eneco Toon — live CO₂, PM2.5 and fan speed from local ESPHome devices

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Used by

Contributors

Languages