Releases: rspaargaren/io-rts-esp32
Release list
v2.0.33
First-time flash — ESP-IDF web upload tool
Select the full.bin for your board from the assets above — this is a single merged image (bootloader + partition table + app + web UI) that can be flashed at address 0x0.
| Board | Asset |
|---|---|
| Heltec ESP32 | heltec-<version>-full.bin |
| LilyGo LoRa32 V1.6.1 (ESP32) | lilygo-lora32-<version>-full.bin |
| LilyGo T3-S3 (ESP32-S3) | lilygo-t3s3-<version>-full.bin |
- Open the ESP-IDF web flash tool
- Connect the ESP32 via USB and put it in flash mode (hold BOOT, press EN/RESET, release BOOT)
- Click Connect and select the serial port
- Set address to
0x0 - Choose the
full.binfor your board and click Program — flashing takes about 30 seconds - Press EN/RESET to boot
After the first serial flash, all subsequent updates can be done wirelessly via the device web UI (OTA tab → select the firmware.bin for your board).
First-time WiFi setup
After flashing, the device starts a setup access point when no WiFi credentials are configured or the network is unreachable.
| Setting | Value |
|---|---|
| SSID | io-rts-setup |
| Password | io-rts-esp32 |
Connect to this AP and navigate to http://192.168.4.1 to enter your WiFi credentials. The device reboots and connects to your network automatically.
Full Changelog: v2.0.32...v2.0.33
v2.0.32
First-time flash — ESP-IDF web upload tool
Select the full.bin for your board from the assets above — this is a single merged image (bootloader + partition table + app + web UI) that can be flashed at address 0x0.
| Board | Asset |
|---|---|
| Heltec ESP32 | heltec-<version>-full.bin |
| LilyGo LoRa32 V1.6.1 (ESP32) | lilygo-lora32-<version>-full.bin |
| LilyGo T3-S3 (ESP32-S3) | lilygo-t3s3-<version>-full.bin |
- Open the ESP-IDF web flash tool
- Connect the ESP32 via USB and put it in flash mode (hold BOOT, press EN/RESET, release BOOT)
- Click Connect and select the serial port
- Set address to
0x0 - Choose the
full.binfor your board and click Program — flashing takes about 30 seconds - Press EN/RESET to boot
After the first serial flash, all subsequent updates can be done wirelessly via the device web UI (OTA tab → select the firmware.bin for your board).
First-time WiFi setup
After flashing, the device starts a setup access point when no WiFi credentials are configured or the network is unreachable.
| Setting | Value |
|---|---|
| SSID | io-rts-setup |
| Password | io-rts-esp32 |
Connect to this AP and navigate to http://192.168.4.1 to enter your WiFi credentials. The device reboots and connects to your network automatically.
Full Changelog: v2.0.31...v2.0.32
v2.0.31 — WebSocket session leak fix + web upload fix
What's new
Fix: WebSocket session leak (crash prevention)
ws_send_job_fn and ws_send_str cleared the fd from the local tracking array on send failure but never called httpd_sess_trigger_close(). The underlying httpd session (socket slot + lwIP buffer) stayed allocated until LRU eviction, accumulating over hours of continuous operation until max_open_sockets was exhausted and the server entered ENOMEM — producing the socket error storm observed in logs.
Both send-failure paths now call httpd_sess_trigger_close() immediately after clearing the slot, so the httpd session is released promptly.
Fix: web file upload creates parent directories
api_upload_web_post called fopen(path, "w") without creating intermediate directories. LittleFS does not auto-create them. If the directory tree was missing (e.g. after a failed web UI update), all file uploads returned 500. The handler now walks the path and calls mkdir() for each component before opening the file.
Commits
10d0a1dfix: create parent directories in web upload handler20c7e65fix: close httpd session when WebSocket send fails
Full Changelog: v2.0.30...v2.0.31
First-time flash via ESP-IDF web upload tool
Select the full.bin for your board — this is a single merged image (bootloader + partition table + app + web UI) that can be flashed to address 0x0.
| Board | Full image |
|---|---|
| Heltec ESP32 | heltec-v2.0.31-full.bin |
| LilyGo LoRa32 V1.6.1 (ESP32) | lilygo-lora32-v2.0.31-full.bin |
| LilyGo T3-S3 (ESP32-S3) | lilygo-t3s3-v2.0.31-full.bin |
- Open the ESP-IDF web flash tool
- Connect the ESP32 via USB and put it in flash mode (hold BOOT, press EN/RESET, release BOOT)
- Click Connect and select the serial port
- Set address to
0x0 - Click Choose file and select the
full.binfor your board - Click Program — flashing takes about 30 seconds
- Press EN/RESET to boot
After the first serial flash, all subsequent updates can be done wirelessly via the device web UI (OTA tab → select the firmware.bin for your board).
v2.0.30 — RX frame helper + poll backoff
What's new
ReceiveMatchingFrame helper
Replaces single-shot xQueueReceive patterns in active io-homecontrol exchanges with a deadline-loop helper that drains irrelevant frames rather than aborting on the first non-matching one.
- Ambient RF traffic (frames between other devices) is now silently discarded instead of consuming the exchange slot
- Frames from other peers addressed to us but not part of the current exchange are stashed and re-queued before the mutex is released, so
ProcessReceivedFrameTaskhandles them correctly - Adopted in
SendAndReceive(both receive call sites) andAuthenticateReceivedRequest - Eliminates the spurious "received a response not for current exchange!" log errors
Per-device poll backoff
UpdateDevicesStatusTask now backs off retry intervals for devices that repeatedly fail to respond, instead of always retrying after 60 seconds.
| Consecutive failures | Retry interval |
|---|---|
| 1 | 60 s |
| 2 | 5 min |
| 3 | 30 min |
| 4+ | 1 hour |
This eliminates the double-cluster error pattern (hourly poll fails → all devices retry at 60 s → fail again) seen in logs from unreachable devices.
Commits
c1740abfeat: add ReceiveMatchingFrame and FlushStash helpersf1e6fb2feat: adopt ReceiveMatchingFrame in SendAndReceivef7b1b0dfeat: adopt ReceiveMatchingFrame in AuthenticateReceivedRequestb2d4aaafeat: add per-device poll backoff to UpdateDevicesStatusTask33f475dfix: cap consecutive_poll_failures at 4 to prevent uint8_t wrap-around
Full Changelog: v2.0.29...v2.0.30
v2.0.29
Increase process_iodevicestatus_task stack from 4096 to 8192 bytes to prevent stack overflow when LittleFS, WebSocket, and MQTT operations are invoked in the same callback frame.
Full Changelog: v2.0.28...v2.0.29
v2.0.28
What's changed
New features — OLED display improvements (contributed by @arjenw)
- Combined TX+RX per device — transmit and receive events for the same device are shown on one line instead of separate rows, allowing up to 4 devices to be tracked simultaneously
- 30-second auto-expiry — device lines disappear automatically after 30 seconds of no activity
- WiFi RSSI bars in header — signal strength shown as a 3-bar icon; question-mark icon when no WiFi credentials are configured; RJ45 icon on Ethernet builds
- MQTT connection icon in header — at-a-glance indicator of broker connectivity
- IO logo + "control" branding — replaces the "io-homecontrol" title text
- Firmware version on status row — version string right-aligned on the bottom row at all times
- Screensaver — after 10 seconds of idle the condensed header drifts to a random position every 10 seconds to prevent OLED burn-in; restores the full layout on any new event
- Solid separator lines — replaces the previous dashed-character lines
Code quality fixes (applied post-merge)
- Extracted duplicated logo-rendering code into a shared
draw_logo()helper oled_draw_rssi_bars()now takes a column offset so the condensed screensaver header uses the same helper instead of an inline copy of the threshold logics_version_strbuffer increased from 9 to 16 bytes to safely hold any realistic version stringcompact_dev_lines()now only re-renders the four device rows when a line actually shifted position; previously all four rows were written to the display via I2C every 2 seconds regardless of changes
What's Changed
Full Changelog: v2.0.27...v2.0.28
v2.0.27
What's changed
Fixes critical regressions introduced by PR #7 (streaming JSON parser for Overkiz device import):
Bug fixes
- Silent empty device list on parse error — when the streaming JSON parser encountered an error (e.g. a field exceeding the 256-byte buffer), the error was not propagated and the import returned an empty success response instead of an error message
- HTTP non-200 responses treated as success — a 401/403/500 from the Overkiz API returned
ESP_OKto the caller becauseerrheld the TCP open result, not the HTTP status; the UI silently showed zero importable devices fetch_headers()failure not detected — a TLS or network error during response header reception was ignored;errremainedESP_OKand the same silent-empty-success path was taken- HTTP handler returned non-
ESP_OKafter sending response — caused the httpd framework to abort the connection after the error JSON was already flushed, potentially corrupting the response or breaking keep-alive JsonPathHandlerdangling reference — the returned closure captured the callback parameter by reference; changed to capture by value to avoid undefined behaviourJsonPath::startsWithnull dereference — callingstartsWithon a root-level path (JsonDoc,JsonObject,JsonArray) whoseparentisnullptrwould crash; added the same null guard present inendsWithandcontainsJSON_PARSER_BUFFER_MAX_LENGTHraised 256 → 512 bytes — any string field in the Overkiz response longer than 255 bytes (e.g. in device definition command descriptors) would abort the entire import- Session cookie removed from log —
overkiz_getwas logging the full JSESSIONID value at INFO level
Included fix for importing somfy devices
What's Changed
Full Changelog: v2.0.25...v2.0.26