Releases: Techposts/TankSync
Release list
TankSync v3.6.10
Fixed: hub firmware updates failed on every S3 hub
Updating a hub from the app, the web UI or Home Assistant failed with
"Download failed" and a progress bar stuck at 0%.
Every ESP32-S3 hub was asking the update server for the plain-ESP32
image, then rejecting it because the binary was built for a different
chip. Nothing was ever written to the hub — it declined the wrong image
and carried on running the firmware it already had, which is why the
failure was harmless but persistent.
The connection, the download URL and the storage partition were all
fine. The hub simply asked for the wrong file.
Also in this release
- Hub OTA failures now name the stage that failed instead of a bare
"Download failed" (from 3.6.9). - Receiver version stamping corrected — the binary now reports the same
version as the release it came from (from 3.6.9). - 3.3 V transmitter board support and correct battery reporting on
transmitters built without an INA219 (from 3.6.8).
Important for existing hubs
A hub already running 3.6.9 or earlier still contains the old, incorrect
request, so it cannot pull this fix over the air — it will keep asking
for the wrong image. Those hubs need one manual USB flash of
3.6.10. After that, over-the-air updates work normally from the app,
the web UI and Home Assistant.
Use the image matching your hub:
tanksync-receiver-esp32s3-v3.6.10-full.bin for the S3 hub.
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.6.9
A diagnostics and correctness release. No behaviour changes to tank
measurement, LoRa, or sleep.
Fixed: hub OTA failures now say what went wrong
The hub reported a bare "Download failed" for three completely different
problems — a transfer error, a truncated image, or a validation failure
at the end. The detail existed but only ever reached the serial console,
so a hub on a shelf could tell you it failed and nothing more.
The status now names the stage and carries the underlying error, so an
OTA problem can be diagnosed over the network.
Fixed: receiver version stamping
Receiver-ESP32-DevKit was still stamped 3.6.7 while shipping inside the
v3.6.8 release, so the hub reported a different version than the release
it came from. Both products now stamp the release version.
Included from v3.6.8
Firmware for the 3.3 V transmitter board, and correct battery reporting
on transmitters built without an INA219. See the v3.6.8 notes for detail
on choosing between the 5 V and 3.3 V images.
Upgrading
Hubs update over the air. Transmitters flash over USB — pick the image
matching your board revision.
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.6.8
Adds firmware for the new 3.3 V transmitter board, and fixes power
reporting for any transmitter built without an INA219.
New: 3.3 V transmitter board support
There are now two transmitter PCBs in service, and they drive the GPIO10
sensor-rail gate with opposite polarity:
- 5 V board — GPIO10 feeds an AO3400 N-FET inverter stage. Active-HIGH.
- 3.3 V board — GPIO10 drives an AO3401 P-FET directly, no inverter.
Active-LOW.
One binary cannot serve both. Flashing the 5 V image onto a 3.3 V board
inverts the gate and leaves the sensor rail powered continuously, which
defeats the sleep budget entirely.
Each release now ships four transmitter images instead of two:
| Asset | Board | Radio |
|---|---|---|
tanksync-transmitter-lora-esp32c3-* |
5 V | LoRa |
tanksync-transmitter-lite-espnow-esp32c3-* |
5 V | ESP-NOW Lite |
tanksync-transmitter-lora-esp32c3-3v3-* |
3.3 V | LoRa |
tanksync-transmitter-lite-espnow-esp32c3-3v3-* |
3.3 V | ESP-NOW Lite |
Pick the image that matches your board. The board axis is independent
of the radio, so both radios get both flavours. Existing 5 V boards are
unaffected — those binaries are built exactly as before.
Fixed: transmitters without an INA219 reported "Mains powered"
A transmitter with no power-monitoring chip fitted reported
POWER_MODE_NONE, which the app rendered as "Mains powered" — on boards
that have no mains input at all. That also suppressed solar charge
reporting, because the charging flag is only published when a battery is
detected.
- On the 3.3 V board, a low bus-voltage reading is now treated as a bad
sample rather than as evidence of mains. This board is fed from the cell
through the TPS63802 and nothing else, so "running on external 5 V" is
not a reachable state. The last good reading is held across deep sleep
instead of reporting 0 %. - The INA219 probe retries instead of latching POWER_MODE_NONE on a single
missed ACK at boot. - Battery protection no longer switches off when a reading fails. The
3.1 V cutoff and low-battery backoff previously shared a flag with
battery presence, so a failed read silently disabled both.
Companion app fix: "Mains powered" is now shown only when the transmitter
actually reports mains, not when power monitoring is simply absent.
Upgrading
Existing 5 V boards can update over the air as usual. If you have a 3.3 V
board, flash the matching -3v3- image — a full-flash -full.bin is
attached for first-time programming at offset 0x0.
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.6.7 — hub RX display redesign + LoRa signal scale
RX-only firmware (display/LED/web) + PWA RSSI scale. TX unchanged. WiFi/LoRa/
reception core byte-for-byte unchanged. Full-circle water, OTA screen (web-UI +
manual + demo) with 24-LED halo progress, flow-state + signal on the hero,
surface-LED breathe, post-reboot '11d ago' -> '--' fix. (esp32/DevKit variant
guarded — no GC9A01 there.)
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.
Hub RX reliability + ACK correctness (receiver-only; TX unchanged)
- ACK-after-accept gate (deleted/orphaned tank no longer falsely ACKed)
- Missed-packet hardening: UART ring 2048, rx_task on core 1, /api/lora health counters
- Reliability-core frozen at this baseline (docs/frozen-core-v3.6.6.md)
Verified: live hub + real tank ~6h + through a floor, zero missed packets.
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.6.5
Receiver fix: the WiFi setup hotspot (TankSync-XXXX) could be completely invisible on v3.6.4 — the setup AP had moved to WiFi channel 1, which does not radiate on some ESP32-S3 hub boards. The setup AP is back on channel 6 and appears within ~2 seconds.
If a hub on v3.6.4 shows the setup QR but the hotspot never appears: flash tanksync-receiver--v3.6.5-full.bin over USB, or update OTA while the hub is still connected to WiFi.
Transmitter: version bump only — no functional changes from v3.6.4.
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.6.4 — WiFi setup reliability + LoRa link self-healing
This release fixes two long-standing reliability problems: a setup Wi-Fi hotspot
that was slow to appear and hard to join, and a LoRa condition that could make a
transmitter silently miss readings for a long stretch. Both are now fixed and
bench-verified end to end.
── Hub (Receiver) ──────────────────────────────────────────────────────────────
• Setup Wi-Fi hotspot is now instant and reliable. The hub's "TankSync-XXXX"
setup network was intermittently invisible, slow to show, or wouldn't accept a
connection. Root cause: Wi-Fi modem power-save was on, so the radio slept
between beacons. It's now disabled (WIFI_PS_NONE) with a standard access-point
configuration — the hotspot appears within a second, stays visible, and the
setup page loads quickly. "Scan networks" and connecting to your home Wi-Fi
work reliably.
• Offline mode: run the hub on its own hotspot with no home Wi-Fi — pair tanks
and see levels locally; the setup QR is hidden and your tanks are shown on the
display instead.
• Round display (camera-module hubs): the screen framebuffer now lives in PSRAM,
freeing internal memory so Wi-Fi association is never starved (fixes a blank
screen / failed-join case on those units).
• LoRa self-healing: if the hub's radio ever gets stuck refusing to transmit
(acknowledgements would silently stop), it now auto-recovers over the wire —
full config rewrite, then a soft reset, then a factory reset if needed, each
verified by a real test transmission.
── Transmitter ────────────────────────────────────────────────────────────────
• LoRa self-healing (the big one). A transmitter's radio module could get into a
stuck state where every send was rejected — and nothing cleared it, so the
device could miss readings for 30 minutes to hours until it happened to reset.
The transmitter now detects that state and recovers automatically on the very
next wake: a full config rewrite, escalating to a soft reset and factory reset
if needed, each confirmed by a real test send. A stuck radio becomes one missed
cycle instead of hours of silence.
• Reliable wake. The command that returns the radio to transmit mode after sleep
could fail (a stray wake byte corrupted it), risking a missed cycle. The wake
sequence is now robust and guarantees transmit mode on every wake.
• Pairing verified end to end: pair in ~2 seconds, then normal
wake → measure → send → acknowledge → sleep cycles deliver reliably.
• Cleaner sleep power handling. The sensor's power gate is driven low on every
sleep entry (ultrasonic off) and high on wake (ultrasonic on) — the simple,
proven scheme — with the LoRa module sleeping via its own firmware sleep mode.
This removes the GPIO deep-sleep "hold" experiments that could leave the
sensor rail partially powered (flickering LED, wasted battery) on some units.
• Default transmit power is now 14 dBm (was 22). Bench links run with ~40 dB of
spare signal margin, and the full-power burst was the peak current draw that
could sag the battery rail and trigger a brown-out backoff (seen as readings
pausing for a stretch, then resuming). 14 dBm still comfortably covers
long-range installs; any individual transmitter can be raised back up from
the hub's settings (LoRa power) if a specific site needs it.
── Notes ───────────────────────────────────────────────────────────────────────
• Device identity uses each transmitter's factory-unique hardware ID, so the hub
always distinguishes and remembers its own transmitters — even across address
or network-ID changes.
• The earlier multi-network Wi-Fi roaming experiment (which caused the hotspot
to disappear) has been removed; the hub uses the proven single-network setup.
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.6.3 — the range & reliability overhaul
This one took a full day of live A/B testing on real walls and real floors, and it was worth it. I traced "it worked at long range in June, now it misses for hours" down to three independent bugs — and fixed all three. A link that delivered zero packets through two concrete floors before this release measures ~80% delivery after it, on the same hardware in the same spots.
What was wrong, and what's fixed
1. Network IDs outside the radio's supported range.
Pairing used to assign LoRa network IDs the RYLR998 doesn't actually support (the datasheet allows 3–15 and 18). Out-of-range IDs put the radio into undefined sync behaviour: packets dropped regardless of signal strength, and ACKs vanished one-way. New pairs now draw only valid IDs, and a transmitter stuck on an old out-of-range ID logs a clear error telling you to re-pair.
2. The radio was assumed ready, not verified.
Since v3.3.0 the transmitter power-gates its radio to save battery — but gave it only 50 ms to wake before sending. A module that wasn't ready meant the whole report cycle vanished silently. The transmitter now probes the radio until it actually answers, verifies its configuration by query, and after any failed delivery checks whether the module is even alive — so the logs finally tell you where a loss happened.
3. ACKs that never left the hub.
The hub fired its ACK and never checked whether the radio accepted it. Under channel congestion the module refuses the send (+ERR) — and the transmitter burned its whole retry ladder waiting for an ACK that was never transmitted. The hub now verifies every ACK transmission, retries once, and logs loudly if its downlink is deaf.
Range and delivery improvements
- Maximum forward-error correction (coding rate 4/5 → 4/8) on both ends. My A/B through two concrete floors: 0% → ~75–80% delivery at −76…−94 dBm. Costs a little airtime; irrelevant at a 5-minute reporting cadence.
- Smarter retries, battery-aware. Five fast retries, then one late retry ~50 s later — because a single fade swallows all back-to-back attempts, but rarely survives a minute. The late retry only runs when energy is free (mains, solar charging, or battery ≥ 30%); a low battery banks the energy instead.
- Transmit power can never silently drop. Power values are validated on both ends (a stale byte could previously leave a radio at 0 dBm — hub hears you, you never hear the hub). Hub power overrides now genuinely reach the transmitter too.
- Radio flash wear eliminated. The RYLR998 persists every config write to flash rated 200K cycles — per-wake rewrites were burning ~1,400/day. Config is now verified by query and written only on real change.
- ~0.5 mA transmitter standby. The radio is hard-gated during deep sleep with its own sleep mode; the boot probe absorbs the cold start on every wake.
- Health you can see.
lora_okin the hub API and on the round display, a radio self-heal loop instead of a deaf-until-reboot hub, the firmware version echoed in every boot and every sleep line, and module error codes surfaced in plain text.
Upgrading
- Update both the hub and your transmitters to v3.6.3 (OTA from the hub UI / app as usual). The new radio parameters propagate to the modules automatically.
- Then remove and re-pair each transmitter once. That single re-pair migrates the pair onto a valid network ID — the core range fix. Until you re-pair, things keep working as they did before.
- Fresh/blank boards: use the
-full.binimage for your board at offset0x0; the plain.binis the OTA app image.
Placement tip from this test day: a large metal surface behind the hub (antenna clear of it) acts as a reflector and measurably extends range — my hub lives on an iron gate and that mounting was worth more than any setting.
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.6.2
Receiver (hub) reliability + UX. Transmitter unchanged (version bumped in lockstep).
Fixes
- Data-loss guard (important): the hub could publish an empty tank manifest after a failed storage read (SPIFFS/OOM/corruption at boot), which the cloud honored by deleting all of a user's tanks. The registry now distinguishes "couldn't read" from "genuinely empty" and withholds the manifest when a load fails — so a transient read error can never wipe your tanks. Legitimate empties (first boot, factory reset, removing your last tank) are unaffected.
- OTA ring animation now actually runs. The full-ring update animation was gated on a status flag that was never set, so it had never displayed on any hub. It now shows during updates.
New
- Whole-ring status animations on the LED ring/strip, each a distinct colour: hub update = orange comet, transmitter update = magenta comet, pairing = cyan comet, first-time setup = blue breathing. Normal tank gauges are unchanged.
Also
- Transmitter: sensor +5V power gate is deferred past boot so sensor inrush can no longer brown out the ESP on battery (carried from the prior fix).
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.6.1 — steadier lights, steadier readings
A hardening release for every hub and sensor I put on the bench this week. No new features — just three classes of "it sometimes misbehaves" hunted down to root cause and fixed for good.
Receiver (hub)
S3 hubs: LED ring/strip moved from RMT to SPI. The ESP32-S3's RMT peripheral has a silicon-level conflict with WiFi softAP cache activity that could crash the hub while it was hosting its setup network — and cause the occasional color glitch during normal use. The WS2812 driver now runs over SPI with DMA on S3 boards: the entire crash class is gone, and dimmed colors no longer shift hue at low brightness. ESP32 DevKit hubs keep their proven RMT path, unchanged.
The setup access point no longer disappears. If your router went down, the hub's fallback setup AP could become invisible or refuse connections — background reconnect attempts were muting the AP's beacons. The hub now probes for your router passively (a scan every 10 minutes) and only leaves setup mode once the router is genuinely back — and it never interrupts you while your phone is connected to the AP.
Round-display hubs: the LED ring now mirrors the screen. The 24-LED ring gauges whichever tank the dial is showing — including through the info screen — instead of splitting into confusing per-tank arcs. The empty portion of the ring stays fully dark. Tank screens rotate every 5 seconds; a tank in alert holds the screen longer.
Transmitter (sensor unit)
JSN-SR04M-2 ultrasonic modules now read reliably. Two real bugs, both found with a live bench rig:
- This sensor variant misses short trigger pulses — measured 17% response at the old 20 µs pulse vs 100% at longer pulses. The trigger is now 200 µs, which every supported sensor variant accepts.
- The trigger line floated during early boot while the sensor was already powered, so electrical noise fired the transducer continuously from the moment of wake (the rapid clicking some of you may have heard). The trigger is now pinned low before the sensor receives power.
Validated the boring way: a 43-burst soak with zero errors, 20 consecutive real deep-sleep wake cycles verified clean at the hub, and physical move-tracking accurate to ±1–2 cm.
Coordinator ("HA stick")
The headless Home Assistant coordinator build now compiles out the LED driver entirely — one less peripheral, zero RMT usage on the stick.
Flashing
- Fresh/blank device: use the
…-full.binfor your board at offset0x0. - Existing devices: update over the air from the hub web UI or the PWA as usual — OTA images are the non-
full.binassets.
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.