Releases: Techposts/TankSync
Release list
TankSync v3.6.0 — the HA coordinator arrives, plus major hub resilience fixes
New: Home Assistant coordinator firmware ("HA stick")
A new receiver SKU turns the S3 round-display hub board into a headless
Home Assistant coordinator — the Zigbee-stick model for the TankSync sensor
network. Plug it into the Home Assistant machine over its native USB port and
the sensor network appears locally: no WiFi, cloud account, or MQTT broker
required.
- Assets:
tanksync-receiver-esp32s3-cam-ha-v3.6.0.bin(OTA) and
…-full.bin(flash at 0x0). Flashing the-haimage onto an S3 CAM board
makes it a coordinator; flashing the display image makes it a display hub
again — same hardware, two products. - Speaks an open NDJSON serial protocol (see docs/coordinator-serial-protocol.md
in this repo): node discovery, live telemetry, pairing, rename, calibration,
and pump control with hub-side safety automation keeping precedence. - Pairs with SmartGhar Home Assistant integration v0.10.0 ("USB coordinator"
connection type), verified end-to-end on a live install. - Coordinator hubs update on their own OTA lane — a coordinator never pulls
the display image and vice versa. - The display build is unchanged and keeps its fast internal-RAM rendering.
Receiver (all hubs)
Fixed: hub could boot-loop while the home router was down
If the WiFi router went offline, the fallback path (setup access point +
captive portal) overflowed the system event task's stack, panicked, and
rebooted every ~13 seconds until the router returned. The event task stack is
now sized for the whole fallback chain, an mDNS startup failure degrades
gracefully instead of cascading, and the CAM moves mDNS to PSRAM entirely.
Improved: calm, reliable setup mode
Previously a hub that lost its router alternated its display between the
setup QR and "Connecting…" forever, and joining the setup AP could be
interrupted by background reconnect attempts. Fallback is now a steady state:
the setup AP and QR stay up, the hub quietly retries the saved network every
30 seconds, defers retries entirely while someone is connected to the setup
AP, and tears the AP down cleanly the moment the home network returns.
Improved: internal-memory robustness (the OOM class is closed)
The MQTT client's task memory is reserved at boot and handed over at start
(its startup can no longer lose the RAM race); every runtime task creation is
checked — reboot and factory-reset always execute, a failed OTA start reports
"reboot and retry" instead of silently doing nothing; and the hub now logs an
internal-RAM budget line at boot, warns when the pool runs low, and exposes
heap_internal_free / heap_internal_largest in /api/system for remote
diagnosis.
Transmitter
No functional changes since v3.5.3 (version moves in lockstep with the
combined release).
Assets
Per-variant OTA app images (…-v3.6.0.bin) and full-flash images
(…-v3.6.0-full.bin, flash at 0x0). Full-flash erases WiFi/pairing settings —
use the OTA image to update a provisioned device.
Downloads (every variant for this firmware version)
Transmitter — ESP32-C3 SuperMini
…-transmitter-lora-esp32c3-<tag>.bin— LoRa SKU (RYLR998 module)…-transmitter-lite-espnow-esp32c3-<tag>.bin— Lite SKU (ESP-NOW, built-in radio, no module)
Receiver / Hub
…-receiver-esp32-<tag>.bin— ESP32 DevKit…-receiver-esp32s3-<tag>.bin— ESP32-S3 SuperMini
Each variant ships two images:
- plain
.bin— OTA app image, flash at0x10000, or use the one-click browser flasher / in-app OTA. …-full.bin— full-flash image for a fresh/blank board, flash at0x0with esptool:esptool.py write_flash 0x0 <file>-full.bin.
TankSync v3.5.3 — hub self-provisioning reliability (S3 CAM) + TX battery-sense fix
Receiver (hub)
Fixed: round-display (S3 CAM) hubs could never link to the cloud
A fresh CAM hub added from the app would show as linked in the app but never
start publishing — it silently never fetched its cloud credentials. Root cause
was two back-to-back out-of-memory failures in internal RAM during startup,
both invisible in the logs:
- The cloud-credentials poll task failed to start (its 8 KB stack could not be
allocated once WiFi + display were up) and the failure was swallowed, so the
hub never asked the cloud for its broker credentials. The task stack is now
reserved at link time (static), the create result is checked, and the poll is
re-kicked on every WiFi connect and every 5 minutes until linked. - Once credentials did arrive, the MQTT client's own task could fail to start
the same way, leaving the hub stuck on "connecting" forever. A failed start
now tears down cleanly and retries automatically.
The CAM build also frees ~12.8 KB of internal RAM (WiFi static TX buffers
16→8) so both tasks have real headroom. Verified on hardware: three
unlink→reboot→fresh-provision cycles, broker-connected within ~10 seconds of
boot each time, plus automatic recovery without a reboot.
Improved: provisioning is now diagnosable from /api/logs
The credentials poll logs its startup (with internal-heap numbers), every
"not claimed yet" poll, and any failure — a hub that won't link now says why.
Transmitter
Fixed: false battery-critical hibernation on mains/bench units
The battery-present threshold rises from 1000 mV to 2000 mV so noise-level
INA219 readings (~36 mV, or spurious ~1 V) on units running without a battery
no longer trigger battery-critical hibernation. Real LiPo packs (3.0-4.2 V)
are unaffected.
App (PWA 1.19.1, deploys separately)
- The "Open hub & connect" one-tap handoff now accepts the hub's IP address
(shown on the hub's display) — Android phones cannot resolve the
tanksync-xxxx.localfallback address, which made the button appear to do
nothing.
Assets
Per-variant OTA app images (…-v3.5.3.bin) and full-flash images
(…-v3.5.3-full.bin, flash at 0x0). Full-flash erases WiFi/pairing settings —
use the OTA image to update a provisioned device.
Downloads (every variant for this firmware version)
Transmitter — ESP32-C3 SuperMini
…-transmitter-lora-esp32c3-<tag>.bin— LoRa SKU (RYLR998 module)…-transmitter-lite-espnow-esp32c3-<tag>.bin— Lite SKU (ESP-NOW, built-in radio, no module)
Receiver / Hub
…-receiver-esp32-<tag>.bin— ESP32 DevKit…-receiver-esp32s3-<tag>.bin— ESP32-S3 SuperMini
Each variant ships two images:
- plain
.bin— OTA app image, flash at0x10000, or use the one-click browser flasher / in-app OTA. …-full.bin— full-flash image for a fresh/blank board, flash at0x0with esptool:esptool.py write_flash 0x0 <file>-full.bin.
TankSync v3.5.2
Two receiver-side fixes on top of v3.5.1. Transmitter and receiver are versioned
together, so both are rebuilt.
What's fixed
- The hub's web server ran out of URI-handler slots (cap 60, but the full API
surface is 62), so two buzzer endpoints failed to register at boot and buzzer
web config/test didn't work. Raised the cap to 72 — all endpoints register now,
with headroom to spare. - The ESP32-S3 CAM hub now has its own over-the-air update channel. It shares the
esp32s3 chip target with the S3 SuperMini, so it was asking for the SuperMini
image on update — which has the wrong pins, PSRAM mode and partitions for the
CAM. The CAM now pulls its own image (and the SuperMini still pulls its own),
so each board self-updates to the correct firmware.
Assets — two images per board (OTA app + full-flash), same set as v3.5.1:
receiver-esp32 (DevKit), receiver-esp32s3 (SuperMini), receiver-esp32s3-cam
(round-display CAM), transmitter-lora-esp32c3, transmitter-lite-espnow-esp32c3.
Flashing a blank board:
esptool.py --chip <esp32|esp32s3> -p write_flash 0x0 <...-full.bin>
Downloads (every variant for this firmware version)
Transmitter — ESP32-C3 SuperMini
…-transmitter-lora-esp32c3-<tag>.bin— LoRa SKU (RYLR998 module)…-transmitter-lite-espnow-esp32c3-<tag>.bin— Lite SKU (ESP-NOW, built-in radio, no module)
Receiver / Hub
…-receiver-esp32-<tag>.bin— ESP32 DevKit…-receiver-esp32s3-<tag>.bin— ESP32-S3 SuperMini
Each variant ships two images:
- plain
.bin— OTA app image, flash at0x10000, or use the one-click browser flasher / in-app OTA. …-full.bin— full-flash image for a fresh/blank board, flash at0x0with esptool:esptool.py write_flash 0x0 <file>-full.bin.
TankSync v3.5.1
A reliability release on top of v3.5.0 — it fixes cloud OTA on the round-display
S3 CAM hub, makes app-to-hub linking dependable again, and promotes the S3 CAM to
a first-class, CI-built board. Transmitter and receiver are versioned together.
What's fixed
- Cloud OTA over HTTPS now works on the ESP32-S3 CAM hub. The TLS handshake was
running out of internal RAM (framebuffer + Wi-Fi already there); mbedTLS now
allocates from PSRAM, so the update check completes instead of failing to
connect. - App-to-hub linking is dependable again. The app now carries the hub's
provisioning token through every path (QR, setup URL, and on-network
discovery), so a freshly added hub actually receives its cloud credentials
instead of showing "added" while staying unlinked. When a hub can't be linked
automatically, the app now says so honestly and offers a one-tap "Open hub &
connect" handoff that fills the broker settings in for you.
What's new
- The ESP32-S3 CAM (N16R8, 16 MB flash / 8 MB octal PSRAM) round-display hub is
now built and published automatically like every other board, with its own
full-flash and OTA images. It carries 90 days of on-device history (10-minute
resolution) and the full display lifecycle (setup → connecting → connected →
tanks).
Assets — two images per board
- ...--v3.5.1.bin OTA app image (what the app/cloud pushes over-the-air)
- ...--v3.5.1-full.bin full-flash image (esptool @ 0x0, for a blank board)
Boards: receiver-esp32 (DevKit), receiver-esp32s3 (SuperMini),
receiver-esp32s3-cam (round-display CAM), transmitter-lora-esp32c3,
transmitter-lite-espnow-esp32c3. Legacy-named aliases are included so already
deployed units keep updating across the naming change.
Flashing a blank board:
esptool.py --chip <esp32|esp32s3> -p write_flash 0x0 <...-full.bin>
Downloads (every variant for this firmware version)
Transmitter — ESP32-C3 SuperMini
…-transmitter-lora-esp32c3-<tag>.bin— LoRa SKU (RYLR998 module)…-transmitter-lite-espnow-esp32c3-<tag>.bin— Lite SKU (ESP-NOW, built-in radio, no module)
Receiver / Hub
…-receiver-esp32-<tag>.bin— ESP32 DevKit…-receiver-esp32s3-<tag>.bin— ESP32-S3 SuperMini
Each variant ships two images:
- plain
.bin— OTA app image, flash at0x10000, or use the one-click browser flasher / in-app OTA. …-full.bin— full-flash image for a fresh/blank board, flash at0x0with esptool:esptool.py write_flash 0x0 <file>-full.bin.
TankSync v3.5.0 — ESP32-S3 CAM hub, on-device history, full display lifecycle
Receiver (RX)
New — ESP32-S3-WROOM N16R8 CAM hub (TankSync V4-RX)
- New round-display production hub board profile (built with
-DBOARD_S3_CAM=1):
8 MB octal PSRAM, 16 MB flash, UART0 console. DevKit + S3 SuperMini unchanged. - The CAM binary is attached here as
tanksync-receiver-esp32s3-cam-v3.5.0[.|-full.]bin.
New — on-device local history (S3)
- 90-day @ 10-min per-tank time series held in PSRAM, snapshotted hourly to an
~11 MB LittleFS partition; survives reboot; keyed by transmitter MAC.
New — full GC9A01 display lifecycle
- Boot → Wi-Fi setup (real SSID + 192.168.4.1 + a Wi-Fi-join QR) → Connecting →
Connected/IP → No-tanks (with hub IP) → tank dials → device-info, plus pairing
and a per-tank 7-day history sparkline. Previously the round display only ever
showed no-tanks / running.
Fixed
- GC9A01 render task could silently fail to start (RGB "TV static") when internal
RAM fragmented late in boot — its 16 KB stack is now reserved early and the task
is created statically.
Transmitter (TX)
- Version-only bump to keep tx + rx aligned (no functional change).
Assets
Every variant ships an OTA app .bin (flash @ 0x10000) and a -full.bin
(flash @ 0x0). RX: esp32 (DevKit), esp32s3 (SuperMini), esp32s3-cam (V4-RX).
TX: esp32c3 lora + lite (ESP-NOW).
Downloads (every variant for this firmware version)
Transmitter — ESP32-C3 SuperMini
…-transmitter-lora-esp32c3-<tag>.bin— LoRa SKU (RYLR998 module)…-transmitter-lite-espnow-esp32c3-<tag>.bin— Lite SKU (ESP-NOW, built-in radio, no module)
Receiver / Hub
…-receiver-esp32-<tag>.bin— ESP32 DevKit…-receiver-esp32s3-<tag>.bin— ESP32-S3 SuperMini
Each variant ships two images:
- plain
.bin— OTA app image, flash at0x10000, or use the one-click browser flasher / in-app OTA. …-full.bin— full-flash image for a fresh/blank board, flash at0x0with esptool:esptool.py write_flash 0x0 <file>-full.bin.
v3.4.0 — unified release: board-named assets, full-flash images, per-chip OTA
First combined transmitter + receiver release under a single version tag.
Device firmware is functionally identical to 3.3.0 (verified booting on
ESP32 DevKit hardware); this version reworks how releases are built, named,
and delivered.
What's new
- Every binary carries its board in the filename:
tanksync-receiver-esp32-v3.4.0.bin (ESP32 DevKit),
tanksync-receiver-esp32s3-v3.4.0.bin (ESP32-S3 SuperMini),
tanksync-transmitter-lora-esp32c3-v3.4.0.bin (LoRa),
tanksync-transmitter-lite-espnow-esp32c3-v3.4.0.bin (Lite / ESP-NOW). - Each variant ships an OTA app image (.bin) AND a full-flash image
(…-full.bin) for blank boards (esptool write_flash 0x0). - The receiver pulls the OTA image matched to its own chip (DevKit vs S3),
so the two never cross-flash.
Compatibility
- Existing hubs and transmitters keep updating: each fielded variant is also
published under its previous asset name (legacy alias), so devices on older
firmware still find their update. Aliases retire in a later release.
Downloads (every variant for this firmware version)
Transmitter — ESP32-C3 SuperMini
…-transmitter-lora-esp32c3-<tag>.bin— LoRa SKU (RYLR998 module)…-transmitter-lite-espnow-esp32c3-<tag>.bin— Lite SKU (ESP-NOW, built-in radio, no module)
Receiver / Hub
…-receiver-esp32-<tag>.bin— ESP32 DevKit…-receiver-esp32s3-<tag>.bin— ESP32-S3 SuperMini
Each variant ships two images:
- plain
.bin— OTA app image, flash at0x10000, or use the one-click browser flasher / in-app OTA. …-full.bin— full-flash image for a fresh/blank board, flash at0x0with esptool:esptool.py write_flash 0x0 <file>-full.bin.
TankSync Transmitter v3.3.0 — deep-sleep current fix (~15x lower standby)
This release fixes the transmitter's deep-sleep power draw, taking standby from
~3 mA down to the chip's floor and turning a ~1-2 week unaided runtime into
multi-month battery life.
What was wrong
- On the ESP32-C3, gpio_deep_sleep_hold_en() keeps the RTC_PERIPH power domain
powered so it can latch GPIO states through sleep — and that domain draws
~2.4 mA continuously. The TX paid that tax the entire time it slept.
The fix
- Drop the deep-sleep GPIO hold entirely. The gates are driven to their OFF
level before sleep; the board's external gate pull-resistors hold the FETs off
once the pads isolate, so loads stay cut without the costly hold. - The wake-side hold-release is kept, so a unit updating from older
(hold-using) firmware cleanly releases any latched holds on its first wake. - Power down the USB-Serial-JTAG PHY before sleep (small extra saving).
Measured
- Deep sleep: ~2.42 mA with the old hold, ~47 uA without it. Whole transmitter
board ~190 uA (the always-on INA219 fuel-gauge + boost idle set that floor). - Overnight soak: both bench tanks stayed online ~17 h with zero faults and the
battery held flat — confirming the drain in practice, not just on a meter.
Battery life now scales with the reporting interval: roughly 2-2.5 months at the
300 s default on a 2900 mAh cell, ~4-6 months at 600-900 s, and effectively
indefinite with modest solar.
Also in this build
- LD2413 24 GHz radar level-sensor driver now reading on hardware (alternative
to the ultrasonic; select per-TX with SENSOR=ld2413).
Pairs with rx-v3.3.0. Update via the TX's WiFi-AP OTA (hold BOOT to enter update
mode) or re-flash over USB.
Downloads (every variant for this firmware version)
…-transmitter-<tag>.bin— Transmitter, LoRa (RYLR998 module)…-transmitter-lite-<tag>.bin— Transmitter, Lite / ESP-NOW (built-in radio, no module)…-receiver-<tag>.bin— Hub, ESP32 DevKit…-receiver-s3-<tag>.bin— Hub, ESP32-S3 SuperMini
Only the variants for this firmware are present. Flash at 0x10000 with esptool, or use the one-click browser flasher.
tx-v3.2.0 — LoRa MAC-echo + 5-minute default sleep
- LoRa MAC-echo: each TANK packet is stamped with the transmitter's MAC so the
hub can reject spoofed addresses. Backward compatible — older hubs simply
ignore the extra field. - Default sleep interval is 5 minutes for longer battery life; adjust it per
tank from the hub or the PWA.
Downloads (every variant for this firmware version)
…-transmitter-<tag>.bin— Transmitter, LoRa (RYLR998 module)…-transmitter-lite-<tag>.bin— Transmitter, Lite / ESP-NOW (built-in radio, no module)…-receiver-<tag>.bin— Hub, ESP32 DevKit…-receiver-s3-<tag>.bin— Hub, ESP32-S3 SuperMini
Only the variants for this firmware are present. Flash at 0x10000 with esptool, or use the one-click browser flasher.
rx-v3.3.0 — Hub holds bad readings instead of alarming on them + Wi-Fi setup scan fix
This Hub release makes tank readings more trustworthy and smooths out
first-time Wi-Fi setup.
Ultrasonic and radar level sensors occasionally throw a single wild
reading — condensation on the sensor face, a splash, or a multipath echo
can make a tank look like it jumped 15–20% in one wake. Until now that
glitch could flash on the dashboard and even trigger a false low-water or
overflow alert.
The Hub now watches the rate of change between readings. A jump too fast
to be real water movement (faster than about 1.5%/min, and at least 6% in
one step) is held back: the Hub keeps showing the last confirmed level and
waits for the next reading to decide. If the level snapped back it was a
spike and is discarded; if it stayed changed it's real and is accepted — so
genuine fast fills and heavy draws still track correctly, just one reading
later. The raw reading is always recorded for diagnostics, and alerts are
suppressed while a reading is held so you never get a phantom alarm.
The app shows a small "reading held" note on a tank while this is happening,
and the cloud applies the same check as a second layer of defence.
During first-time setup the Hub's configuration page sometimes showed an
empty Wi-Fi network list, forcing you to type your network name by hand.
The Hub now runs its access point and Wi-Fi scan at the same time, so nearby
networks reliably show up in the picker.
Open the TankSync app → your Hub → OTA Update, or use the Hub's local web
page. Your paired tanks, names, and settings are preserved across the update.
Downloads (every variant for this firmware version)
…-transmitter-<tag>.bin— Transmitter, LoRa (RYLR998 module)…-transmitter-lite-<tag>.bin— Transmitter, Lite / ESP-NOW (built-in radio, no module)…-receiver-<tag>.bin— Hub, ESP32 DevKit…-receiver-s3-<tag>.bin— Hub, ESP32-S3 SuperMini
Only the variants for this firmware are present. Flash at 0x10000 with esptool, or use the one-click browser flasher.
rx-v3.2.1 — Smart Switch lives in the cloud properly
Smart Switch fixes and full cloud sync, building on 3.2.0:
- A switch's telemetry now republishes to the cloud on every report (5s),
so the app shows it live instead of "waiting for the switch to report"
minutes after the last hub restart. - The pump rule and electrical settings publish to the cloud, and three new
remote commands (rename, rule, settings) let the TankSync app edit them
from anywhere — same validation as the hub's own web UI. - A switch paired from now on gets a unique default name derived from its
hardware address (e.g. "Smart Switch A3F2") instead of "Smart Switch 1". - Renaming a switch in the hub web UI now edits inline — the old dialog was
silently blocked in installed-app browsers. - Physical button presses on the switch are adopted as a manual hold, so a
hand-toggled pump no longer flips back ten seconds later. - Unpairing a switch now tells the switch to forget the hub too (relay off,
pairing cleared), and it waits for a deliberate button hold to re-pair. - New switch settings panel: mains voltage, over-current trip, dry-run
floor — pushed to the switch and persisted.
Pairs with switch firmware ss-v0.1.2. TX firmware unchanged (tx-v3.2.0).
Downloads (every variant for this firmware version)
…-transmitter-<tag>.bin— Transmitter, LoRa (RYLR998 module)…-transmitter-lite-<tag>.bin— Transmitter, Lite / ESP-NOW (built-in radio, no module)…-receiver-<tag>.bin— Hub, ESP32 DevKit…-receiver-s3-<tag>.bin— Hub, ESP32-S3 SuperMini
Only the variants for this firmware are present. Flash at 0x10000 with esptool, or use the one-click browser flasher.