v0.2.0 — Fan Timer, restored diagnostics, core follow-ups
Features
- Fan Timer select (
None/ 1 / 2 / 4 / 8 / 12 hours). Every option —Noneincluded — transmits an energizing command: a duration on a stopped fan starts it at LOW (matching the OEM remote), andNonemeans no timer / run continuously, which restarts a fan whose timer expired.Off(stop) is deliberately unrepresentable in the timer vocabulary. Speed-aware: composes from confirmed state against the confirmed speed band, so a two-speed fan can never be sent MED. - Eight restored RF diagnostics, disabled by default: Last TX Command, Last Valid RX Frame, Last Confirmed Fan State, Fan Speed Capability, Remote Sender ID, TX / RX Valid / RX Rejected counters. The rejected counter doubles as a live RF-interference meter (it found a real household interferer during field validation).
Fixes (#35)
- An OEM-set timer that expires unobserved now invalidates its stale display at the observation-time upper bound and re-queries, instead of showing the old program forever.
Controller Faultpublishesofffrom boot (previouslyunknownuntil a fault) and is hardened against mid-setup degradation ordering.- Authority delivery re-checks read a cheap revision accessor instead of constructing full core snapshots twice per delivery.
Verification
Two multi-model adversarial review campaigns (Fable 5, Opus 5, GPT-5.6-sol, Gemini 3.1 Pro): 16 rounds for the timer feature and 3 rounds for the follow-ups, each ending with all four engines clean. Every fix wave landed with named mutation kills; ASan/UBSan clean. Field-validated on two production controllers, including a live timer round-trip (0x91 on → confirmed 11 s → 0x90 off → confirmed 10 s) through active RF interference.
Upgrade notes
Declare the new select platform (see quietcool-cpp-example.yaml) and note AUTO_LOAD now includes select. ESPHome ≥ 2026.7.0; esp-idf with a 16 KB loop-task stack remains REQUIRED.
Installing
Install from your ESPHome Device Builder by sourcing github://joyfulhouse/esphome-quietcool@v0.2.0 — no repo checkout needed. Full steps: INSTALL.md (read it on main; this tag's copy predates the Builder-first rewrite).