Battery-powered Matter pool & aquatic temperature sensor Single-SoC design on u-blox NORA-W40 (ESP32-C6, Wi-Fi 6 + Thread + BLE 5.3)
Multi-year battery life. Local Matter connectivity. No cloud, ever.
π Live demo & landing page: stenmo.github.io/AkvaLink (available in English Β· Svenska β connect to a nearby sensor live over Bluetooth, right in your browser)
Pool, spa, aquarium, wine cellar, or cold-storage temperature monitoring β environments where the temperature barely changes, but you want to know immediately if it does.
- π Years on 2Γ AA β adaptive sampling + Matter SED + threshold reporting
- π± Works with Apple Home, Google Home, Alexa β standard Matter sensor
- π No cloud β local Matter over Thread or Wi-Fi
- π§ Waterproof probe β DS18B20 in stainless steel (10 m+ cable possible)
- π Open source β built on esp-matter, Apache-2.0 license
| Component | Part | Why |
|---|---|---|
| Module | NORA-W401 / NORA-W406 | Wi-Fi 6 + Thread + BLE in one tiny module |
| MCU | ESP32-C6 (RISC-V @ 160 MHz) | Inside NORA-W40 |
| Sensor | DS18B20 (stainless probe) | Β±0.5 Β°C, 12-bit (0.0625 Β°C steps), 1-Wire, ~$3 |
| Power | 2Γ AA alkaline (or 18650 Li) | ~5β7 years realistic on 2Γ AA (Thread SED, pool conditions)* |
Schematic (direct GPIO, default build):
ββββββββββββββββββββββββββββββββββββββββββββ
β NORA-W40 / EVK-NORA-W40 β
+3V3 βββββββββ¬ββββββββ β GPIO15 (J15.4) β DS18B20 DQ 1-Wire β
β β β
4.7 kΞ© β GPIO9 (BOOT) β re-provision button β
β β long-press 5 s β β
DS18B20 ββββββββ β erase Wi-Fi, re-prov β
DQ βββββββββββββββββββΊ β β
VDD ββββββββββββββββββ β +3V3 β future: battery ADC β
GND ββββββββββββββββββ β GND β
β ββββββββββββ β
Battery (+) ββββ R1 ββββ€ ADCx (future) βββββββ€ R1 / R2 β β
Battery (-) ββββ GND β β divider β β
βββββββββββββββββββββββ΄βββββββββββ΄ββββββββββ
R1/R2 voltage divider (not yet populated): e.g. 390 kΞ© / 100 kΞ© scales 3.3 V full-charge to β 0.68 V, safely within the ESP32-C6 ADC input range.
For long cable runs (> 5 m), a DS2482-800 I2C-to-1-Wire bridge variant is also
supported (--clickboard build flag).
# One-time setup (installs ESP-IDF + esp-matter in WSL, ~10 GB)
.\akvalink.cmd setup
# Build & flash (Thread variant β needs a Thread Border Router)
.\akvalink.cmd build
.\akvalink.cmd flash COM62
# Or build the Wi-Fi variant (no border router needed)
.\akvalink.cmd --wifi build
# Or the Wi-Fi AP variant β open "AkvaLink" hotspot + captive web page showing
# the temperature. No hub, no app, works on ANY phone (incl. iPhone).
# NOTE: an always-on SoftAP is NOT battery-friendly β this variant needs
# external (mains/USB) power.
.\akvalink.cmd --ap build
# Or the Wi-Fi station variant β joins your home Wi-Fi (provisioned once over
# BLE with the free "ESP BLE Provisioning" app), then serves the temperature
# page at http://akvalink-<last4mac>.local (found via mDNS, unique per device).
# Also publishes to MQTT for Home Assistant autodiscovery (default broker:
# homeassistant.local:1883), plus high/low temperature alerts on
# akvalink/<mac>/alert once you set a threshold (menuconfig β AkvaLink).
.\akvalink.cmd --station build
# Or just bench-test the DS18B20 probe (no Matter/BLE β logs temp every 30 s)
.\akvalink.cmd --sensor build
# Or the e-ink display receiver β listens for --espnow sensors' broadcasts
# and logs them (no e-ink panel driver yet). See docs/EINK_DISPLAY_PLAN.md.
.\akvalink.cmd --display build
# Or the ESP-NOW variant β deep-sleep broadcast, no hub, no provisioning,
# maximum battery life (receiver needs its own ESP32 sketch).
.\akvalink.cmd --espnow build
# Or ESPHome β native Home Assistant API, adopted + OTA-updated straight from
# the ESPHome dashboard. Builds with ESPHome directly, not akvalink.cmd:
esphome compile esphome/akvalink.yamlCommission with the Apple Home, Google Home, or Alexa app β scan the QR code printed on the serial console at first boot.
π Full step-by-step: see GETTING_STARTED.md
A native Flutter app (Windows/Linux/macOS/Android/iOS) shows live
temperature over Bluetooth or Wi-Fi (finds a --station device on the LAN via
mDNS) and one-click OTA-updates the device β same GATT/HTTP contract as the
web page, no browser needed:
.\akvalink.cmd --app --runπ See app_flutter/README.md.
For a heated pool at 28β29 Β°C with 0.25 Β°C report threshold. Leading with the realistic number for each cell: alkaline (AAA/AA) self-discharge and Li-ion (18650) calendar aging cap real-world life at roughly 5β7 years no matter what the draw-limited model alone predicts, so that cap is shown wherever the model overshoots it. CR2477 (lithium primary) has the best shelf life of the four and needs no such cap β its model figure already is the realistic one:
| Battery | Thread SED | Wi-Fi (TWT) | Wi-Fi (disconnect) |
|---|---|---|---|
| CR2477 (1000 mAh) | ~5 years | ~6 months | ~3.3 years |
| 2Γ AAA (1200 mAh) | ~5β6 years | ~8 months | ~4 years |
| 2Γ AA (2800 mAh) | ~5β7 years (model: ~12 years) | ~1.8 years | ~5β7 years (model: ~9 years) |
| 18650 Li-ion (3400 mAh) | years, not decades (model: ~15+ years) | ~2.2 years | years, not decades (model: ~11 years) |
The italic (model: ...) figure is the theoretical, draw-limited ceiling β only shown where it's materially higher than the realistic number. Real measurement (PPK2/Joulescope) to replace "years, not decades" with an actual figure is on the roadmap.
See docs/POWER_AND_HARDWARE.md for the full analysis (DTIM strategies, TWT setup, sensor variants, schematic).
- π GETTING_STARTED.md β clone β build β flash β commission
- πΆ docs/CONNECTIVITY.md β Matter/Thread, Matter/Wi-Fi, BLE-only, Wi-Fi standalone + provisioning
- β‘ docs/POWER_AND_HARDWARE.md β battery math, schematic
- βοΈ docs/WINTER_STORAGE_MODE.md β "drop it in the pool and forget it" mode
- πΊ docs/EINK_DISPLAY_PLAN.md β e-ink panel shortlist + integration plan
- π§ docs/ENCLOSURE_DESIGN.md β Smart Float industrial design + mechanical details
- π‘ docs/RF_AND_ANTENNA.md β NORA-W40 antenna keep-out + over-water RF rules
- β TODO.md β prioritised roadmap (power, smart reporting, e-ink, winter mode)
β οΈ KNOWN_LIMITATIONS.md β what doesn't work yet, honestly
- Matter Temperature Sensor over Thread (single-SoC, NORA-W40)
- Matter Temperature Sensor over Wi-Fi
- Adaptive sampling + threshold reporting
- Light sleep + DFS + flash power-down
- DS2482 Click board (long cable variant)
- BLE firmware update over the air (custom GATT over
esp_ota,--blevariant) - Standalone BLE GATT variant β live temperature direct-to-app, no hub (
--ble) - Live temperature in the browser over Web Bluetooth β on the landing page
- Wi-Fi AP variant (
--ap) β open hotspot + captive web page, any phone incl. iPhone (needs external power) - Wi-Fi station variant (
--station) β BLE-provisioned,akvalink.local, Home Assistant MQTT autodiscovery, no hub - ESP-NOW variant (
--espnow) β deep-sleep broadcast, no hub, no provisioning - ESPHome variant β native Home Assistant API, dashboard-adopted + dashboard OTA
- Native Flutter companion app (Windows/Linux/macOS/Android/iOS) β live temperature + one-click OTA
- Temperature alerts β high/low thresholds set from the browser or the app, stored on the device; the
--stationbuild publishes crossings to Home Assistant over MQTT - 24 h / 7 d history β sparkline on the device's own page and in the app (Wi-Fi path; RAM-only, resets on reboot)
- Matter keepalive report so a dead-flat sensor isn't marked offline
- Real power measurement (Joulescope/PPK2) + deep sleep β see TODO.md
- E-ink display (big-digit, battery, trend) β
--displaybuild variant receives --espnow sensor broadcasts and logs them; e-ink panel driver still to come; see docs/EINK_DISPLAY_PLAN.md - Wi-Fi 6 TWT integration in code (currently DTIM only)
- Battery voltage monitoring β firmware side is in (
CONFIG_AKVALINK_BATTERY_ADC, off by default), but no board has the sense divider fitted, so the level reads as unknown - OTA via Matter
- Production enclosure design (waterproof, IP67)
AkvaLink is a clean-room productisation of the
companion/opencpu/nora-w40-thermometer/ NORA-W40 thermometer reference from
u-blox, tracked at u-blox/u-connectMatter
(that public repo now hosts prebuilt reference binaries; the source tree is
internal to u-blox).
Built on:
- esp-matter (release/v1.5)
- ESP-IDF (v5.5.5)
- connectedhomeip (Matter SDK)
- u-blox NORA-W40 module (product page)
- π€ CONTRIBUTING.md β how to build, test, and submit changes (KISS, battery-first, no cloud)
- π SECURITY.md β report a vulnerability privately (AkvaLink is a networked Matter device)
- π Code signing policy β how the Windows companion app is signed (free signing via SignPath.io)
Apache-2.0 β matches esp-matter and connectedhomeip.