Releases: StuckAtPrototype/AirCube
Release list
AirCube Firmware v2.0.3
The first release since v2.0.1, carrying the 2.0.2 sensor-reliability work as
well. Two themes run through it: a sensor that has failed should read as failed,
and the USB link should be fast and impossible to wedge.
What you will notice
- Temperature reads about 0.8 °C (1.5 °F) higher than 2.0.1 on the same
cube. That is a calibration correction, not a regression. Humidity is
unchanged. - Pulling history takes about 5 seconds instead of about 30.
- A broken sensor now shows as broken rather than reporting plausible
nonsense and burying it in the history record. - The cube keeps answering commands. Earlier firmware could stop responding
until it was power-cycled. - A browser flasher and dashboard at
https://stuckatprototype.github.io/AirCube/ — no install, no drivers.
Measurement changes (Pro)
The SCD41 now runs in low-power periodic mode at roughly a 30-second cadence
instead of being commanded into a forced one-shot every 30 seconds, and the
driver polls the sensor's data-ready register rather than trusting fixed delays.
Periodic mode has different thermal behaviour, so the software temperature trim
was recalibrated against a reference: +1.36 °C, up from +0.53 °C. The
on-chip offset stays at the 4.0 °C factory default deliberately — the SCD4x uses
that same offset to compensate humidity, so correcting temperature there would
have dragged humidity with it.
A failed sensor now reads as failed
Earlier firmware could decode a zeroed I2C buffer or a frozen sensor register as
a real measurement, average it into history, and — on a Pro whose SCD41 had died
— quietly re-detect the cube as a Base.
- I2C errors propagate out of the ENS210 and ENS16X drivers instead of being
swallowed and the zeroed buffer decoded as a reading. - Stuck readings are detected. Ten consecutive identical raw temperature and
humidity words, about five minutes at this cadence, latch a fault. A genuinely
new reading clears it. - Recovery is bounded. After repeated failed reads the driver tries
stop_periodic→reinit→ re-apply the temperature offset → restart
periodic mode, capped and paced so a dead sensor is not hammered forever. - History records gaps, not guesses. Windows average valid samples only, and
a window with no valid sample writes an impossible sentinel (INT16_MIN/
0xFFFF) so a reader can draw a gap instead of a flat line. - The model is latched in NVS. A Pro whose SCD41 stops answering stays a
Pro. Useredetect_modelto force a re-probe after a repair.
History sync is about six times faster
Replies used to be written with printf, which sent them to the primary console
(UART0) first and only copied them to USB afterwards. Every byte of a history
transfer was paced by a serial port that nothing on the cube is connected to —
10.6 KB/s, which is 115200 baud once framing is accounted for.
Protocol output now goes straight to the USB-Serial-JTAG driver the firmware was
already using for receive. Measured on hardware the same transfer runs at
62–67 KB/s, taking a full 2016-slot sync from about 30 seconds to about 5.
Raising the console baud rate was never the answer, because the old USB path was
also lossy: the secondary console sink pushes one byte at a time and silently
discards data once its buffer stays full for 50 ms. The slow UART write was the
only thing holding the producer below the rate where that happened. The driver
path blocks instead of dropping, so a slow host now slows the transfer rather
than corrupting it. A 1.16 MB stress transfer produced no malformed frames.
Log output goes through the same writer, so it stays visible over USB and can no
longer interleave into the middle of a response. One side effect: lines end with
a bare newline rather than CRLF, since the console is no longer converting them.
Both the desktop and web clients accept either.
The command path can no longer be wedged
Commands were read one per 10 ms poll, and an over-full receive buffer was reset
only inside the branch that runs when a read returns data. Those two facts
combined into a dead end: once the buffer filled, the next read asked the driver
for zero bytes, which returns zero without touching the buffer, so the reset was
unreachable. The cube then ignored every command until it was power-cycled —
while live readings kept streaming, which made it look like a client bug rather
than a stuck cube.
The loop now drains every complete command a read delivers, and clears an
unterminated full buffer before reading rather than after. A burst of 2000
commands leaves the cube responsive.
Serial protocol
Additions only. Nothing was renamed or removed, so existing clients keep working
untouched.
- The periodic sensor frame carries a
healthobject:ok,temp_valid,
hum_valid,co2_valid,etvoc_valid,sensor_missing. - New in 2.0.3: the frame also carries
fw, the running firmware version,
so a client can display it without flashing the cube first or guessing. - New commands for field triage:
get_sensor_health,get_model,
redetect_model,scd41_raw,scd41_selftest,scd41_reinit.
AirCube Firmware v2.0.4
AirCube firmware v2.0.4
This release keeps the LED display stable through brief Zigbee radio recovery.
What changed
- Removed the green LED blink when Zigbee reconnects after a parent link failure.
- Preserved the current air-quality color, brightness, hue, and auto-dim state
across warm MCU restarts. - Resumed the Pro model's running SCD41 measurement cycle after a warm restart
instead of restarting the sensor. - Kept the existing blue pairing-mode indication unchanged.
AirCube Firmware v2.0.1
AirCube Firmware v2.0.1
A major release. It brings Bluetooth support, the first public firmware for
AirCube Pro, and companion app compatibility. It supersedes 2.0.0.
Upgrading from 1.5.x is safe and preserves your settings.
New: Bluetooth (BLE)
AirCube now has a full Bluetooth radio mode, so a Zigbee dongle is no longer
required to get readings off the device.
- Works with Home Assistant with no pairing. The cube broadcasts standard
BTHome v2 data — temperature, humidity, CO2, and TVOC. Any HA instance with
a Bluetooth adapter or an ESPHome Bluetooth proxy nearby can pick these up
passively, with no pairing step and no Zigbee hardware. - Connectable GATT service for apps: live readings notified about once per
second, brightness that can be read and written remotely, and full history
download. - History sync over Bluetooth. Up to 7 days of 5-minute summaries stream to a
connected app in a couple of seconds, with incremental sync so reconnecting
only transfers what's new. - Brightness stays in sync everywhere. Changing brightness by button, over
Bluetooth, or over Zigbee notifies connected clients of the confirmed value.
Building your own client? See the
BLE GATT Protocol reference.
How the radio mode is chosen. The ESP32-H2 shares a single radio between
Bluetooth and Zigbee, so AirCube runs exactly one at a time, decided at boot. An
un-paired cube boots into Bluetooth mode. Long-pressing to pair moves it to
Zigbee, and if your hub later removes it, it returns to Bluetooth on its own.
Cubes already paired to Zigbee keep working exactly as before and stay on Zigbee
after the update.
New: AirCube Pro support
Pro adds two sensors Base doesn't have, and this firmware drives both:
- True CO2 from a Sensirion SCD41 (direct NDIR, 400–5,000 ppm) — a real
measurement rather than the eCO2 figure estimated from VOCs. On Pro the SCD41
also supplies temperature and humidity. - Ambient light sensing via a VCNL4040, reported in lux.
- Automatic night dimming. The LED dims itself in a dark room and returns to
your chosen brightness when the lights come back on.
LED reflects the worse of two readings on Pro. Color is driven by VOC Level
or CO2 Level — a 0–500 score derived from true CO2 on the same band scale —
whichever is worse. On Base, CO2 Level is always 0, so VOC Level drives the LED
exactly as it did in 1.5.x.
Two new Home Assistant entities on Pro: Carbon Dioxide Measurement (cluster
0x040D) and Illuminance Measurement (cluster 0x0400).
App compatibility
The USB serial feed now reports the hardware model alongside true CO2 and ambient
light readings. The additions are backward compatible — existing fields keep
their old names and positions, so older tools continue to work and simply won't
show the new values.
Use the current desktop app and AirCube Tray release to see CO2, ambient light,
and the Base/Pro model indicator.
Fixed
LED no longer cycles between bright and dim (Pro). Auto-dim decides day
versus night from the ambient light reading, which has the cube's own LED glow
subtracted out. That subtraction was overstated by roughly 4x — enough to push
the reading across a threshold every time brightness changed. Dimming made the
room look brighter, brightening made it look darker, and the cube oscillated
every few seconds under perfectly steady lighting.
Ambient light readings are more accurate (Pro). The same overstated
correction made reported lux read about 10 lux low whenever the LED was bright.
If you graph AirCube's light sensor in Home Assistant, expect higher values that
no longer swing with LED brightness.
Changed
- Auto-dim thresholds are now night below 2 lux, day above 10 lux. Devices
carrying older stored values are migrated automatically on first boot. - Day/night switching is limited to once every 30 seconds, and light readings are
ignored for 3 seconds after a brightness change so the LED ramp and the sensor's
integration window can settle. - Day/night thresholds set too close together are widened automatically to keep
the cube stable, and this is now reported in the serial log instead of being
applied silently.
Notes for Base owners
Base hardware has no CO2 sensor, no light sensor, and no automatic dimming, so
the Pro items above don't apply and your configured brightness passes through
unchanged. Bluetooth support and app compatibility apply to both models. LED
behavior, VOC Level, and the 0–500 scale are unchanged from 1.5.x.
Upgrade notes
- Settings are preserved: brightness, Zigbee pairing, and stored history all
survive the update. - AQI-S remains deprecated and reports 0 over USB serial, unchanged since
1.5.0. Use VOC Level, eCO2/eTVOC, or true CO2 on Pro. - Bluetooth and Zigbee cannot run at the same time — this is a hardware limit of
the radio, not a configuration choice. - Ambient light compensation is still tuned for a single LED color, so accuracy
varies slightly as the cube moves along the green-to-red gradient. A
color-aware correction is planned.
Release_V1.5.2
First release since v1.4.3. New absolute AQI, AQI-driven LED, and Zigbee brightness control.
Highlights
- Canonical AQI (0–500): new absolute, TVOC-derived air-quality score (replaces reliance on the relative AQI-S).
- AQI-driven LED: smooth green → yellow → red gradient tied to fixed indoor-air thresholds.
- Zigbee brightness control: set/read LED brightness from Home Assistant; reports on startup and button press.
- Updated HA integrations: refreshed ZHA quirk and Zigbee2MQTT converters (1.x
.js+ 2.x.mjs), backward compatible.
Improvements
- Zigbee stability: rejoin flap watchdog, exponential backoff, relaxed keep-alive (3 s → 7 s), bounded locks.
- Documentation: new AQI/TVOC/color reference tables and updated setup guides.
Breaking changes
- Serial:
aqiis now the TVOC-derived AQI (0–500); the old relative value moved toaqi_s. - Zigbee: custom cluster
0xFC01attr0x0002now carries the TVOC-derived AQI (0–500). Use the updated ZHA/Z2M converter.
Bug fixes
- Fixed Zigbee rejoin/lockup edge cases and merge artifacts (reboot handler, init-fail watchdog, pairing lock).
Flashing
Download AirCube_firmware_v1.5.2.bin, flash at 0x0 via ESP Launchpad (DIY mode). See FIRMWARE_UPDATE.md. Settings are preserved.
AirCube Firmware v1.4.3
Zigbee stability fixes.
What's new
- Rejoin flap watchdog. After 10 rejoins in 5 minutes, AirCube reboots itself cleanly instead of letting the Zigbee MAC assert.
- Smarter rejoin backoff. The 1 s → 5 min backoff only resets after 60 s of stable uptime, so a flapping parent no longer pins us to
NETWORK_STEERINGevery second. - Keep-alive 3 s → 7 s. Two missed polls used to trip
PARENT_LINK_FAILUREon marginal RF. - Default TX power 10 → 20 dBm (ESP32-H2 max). Configurable in menuconfig.
- Overflow-safe history readout over USB serial; the reply reports slots actually emitted so the desktop app's cursor stays correct.
AirCube Firmware v1.4.2
Fixed
- Zigbee silent disconnect after 48–72 h runtime (#27). After a parent link failure triggered a rejoin, the internal
s_rejoiningflag was never cleared on the subsequentDEVICE_REBOOTsuccess path. The device would stay "rejoining" forever, skip further rejoin scheduling, and appear offline in Home Assistant / ZHA with the red LED on. The flag and backoff timer are now properly reset whenever the stack reports a successful reboot into an already-commissioned network. - Sensor task could block forever on a stuck Zigbee stack.
zigbee_update_sensors()andzigbee_start_pairing()now acquire the Zigbee lock with a bounded timeout (2 s / 5 s). On timeout the cycle is skipped or pairing is aborted instead of deadlocking the sensor pipeline.
Added
- Task watchdog on the sensor task.
sensor_taskis now registered with the ESP-IDF Task Watchdog Timer and feeds it each loop, so any future hang is caught and recovered automatically via reset. - Auto-recovery from stale radio state. If Zigbee stack initialization fails 5 times in a row (e.g. after a soft reset leaves the 802.15.4 radio in a bad state), the device now calls
esp_restart()to force a clean hardware reset instead of retrying forever.
AirCube Firmware v1.4.0
Added
- Remote brightness control — LED brightness (0–100%) now controllable from Home Assistant, Zigbee2MQTT, and SmartThings via Zigbee Analog Output cluster (0x000D)
- SmartThings Edge driver — Full Lua driver with setup guide (
SMARTTHINGS.md) - Configurable Zigbee TX power — New Kconfig option, default 10 dBm
- Firmware update guide — Browser-based flashing via ESP Launchpad (
FIRMWARE_UPDATE.md) - Partition table tracked in git — Deterministic 2 MB flash builds
Changed
- Zigbee attribute updates throttled to every 10 seconds (was every sensor cycle)
- Button task stack doubled to 4096 words to prevent overflow during pairing
- ZHA quirk updated to v2 imports for Home Assistant 2026 compatibility
- Explicit attribute reports now sent for temperature and humidity clusters, not just custom cluster
Fixed
- HA 2026 configuration path trailing slash
- AQI-to-LED color mapping correction
Docs
- README expanded with sensor measurement details and official vs. community extension distinction
- HOME_ASSISTANT.md rewritten for 2025/2026 differences and brightness control
Release_V1.3_HA Home Assistant Integration
This is a huge one! I have added a lot of functionality into the AirCubes, the biggest one being Home Assistant integration via Zigbee!
AirCube Firmware v1.3.0
Sensors: ENS210 (temperature, humidity) + ENS16X (eCO2, eTVOC, AQI) over I2C.
3-minute warm-up for stable air quality readings.
LED: Smooth green-to-red gradient based on AQI. Blue flash during pairing.
5 brightness levels (button cycles through them), saved across reboots.
Zigbee: Home Assistant integration over 802.15.4 (ESP32-H2 native radio).
- Standard temp/humidity clusters + custom cluster (0xFC01) for eCO2, eTVOC, AQI
- Works with ZHA and Zigbee2MQTT (custom quirk/converter included)
- Pairing is on-demand only -- hold button 3s to start, times out after 60s
- Previously paired devices auto-reconnect on reboot
Serial: JSON sensor output over USB at 1 Hz (configurable).
Commands for config, history retrieval, and CSV export.
History: 7-day ring buffer on flash, 5-minute intervals, min/avg/max.
Platform: ESP-IDF v5.5.1, 4 MB flash, custom partition table.
AirCube Tray v1.0.2
Windows system tray app -- puts your AQI right in the taskbar.
- Tray icon changes color with AQI (green → red, gray when disconnected)
- Click to open dashboard: live readings, charts, and device history
- Charts for AQI, temp, humidity, eCO2, eTVOC with selectable time ranges
- Device history viewer -- browse 7 days of data stored on the device, export to CSV
- Alerts when AQI exceeds your threshold (configurable, default 100)
- Settings: serial port, °F/°C, alert threshold, autostart with Windows
- No install required -- single .exe, runs from anywhere
Built with Python, PyQt6, Matplotlib, pyserial.
Windows_App_v1.0
AirCube v1.0
Desktop app for real-time air quality monitoring from your AirCube sensor.
Features
- Live display of Temperature, Humidity, AQI, eCO2, and eTVOC
- Color-coded AQI (green → yellow → orange → red)
- Historical charts with adjustable history length
- Optional CSV logging for data export
Usage
- Connect AirCube via USB
- Run
AirCube.exe - Select COM port → Click Connect
Debug
If the device is not listed, flip the physical USB C cable and plug it in again.
Notes
- Windows 10+ required
- Close other serial monitors before connecting
- First run may trigger SmartScreen warning - click "Run anyway"