I’d like to share Plenum, a Home Assistant add-on for HVAC zoning that fully runs the heating and cooling in my house, every day. It drives smart vents and thermostats from per-room schedules and motion sensors, with cycle analytics, safety protections, and a full web UI accessible from the HA sidebar.
AI attribution, up front: Plenum’s code, tests, and documentation were developed with substantial help from AI coding assistants — the same disclosure you’ll find at the top of the README. That said, the project is backed by over 2,400 backend tests with coverage gates enforced by CI, 950+ frontend tests, and 42 Playwright end-to-end tests, and I trust it to run my own home’s HVAC. I have been a software engineer for 15 years prior to AI and code coverage is over 99% across the board
Why I built it. Plenum started as a replacement for Flair’s scheduler. Flair’s hardware is great, but their app didn’t have the hooks I wanted. I wanted to factor in extra room temperature sensors, motion sensors, and outdoor conditions. So Plenum does the scheduling and decision-making, then hands actual vent control to the excellent RobertD502/home-assistant-flair HACS integration, which exposes each vent as a cover.* entity. Plenum talks to Home Assistant, never to Flair’s cloud directly.
One honest caveat inherited from that design: for Flair hardware, vent commands still run through the HACS integration’s vendor-API path. The community has rightly flagged that cloud dependency as a concern, and exploring local, ESP32-based control is on the roadmap.
And it’s deliberately not Flair-specific: Plenum only speaks directly to HA cover.* and climate.*, so any smart vent integration works!
Flair via HACS, Keen Home, SmartThings vents, Zigbee/Z-Wave roller shutters, DIY ESP32 covers. If Flair’s price put you off, cheap Zigbee/Z-Wave dampers are a fully first-class, lower-cost way to run Plenum. Any climate.* thermostat can host a zone, any sensor.* can feed a room’s average temperature, and any binary_sensor.* can trigger presence.
What it does
Anti-dead-head protection — keeps a configurable fraction (default ~1/3) of the zone’s registers open at all times so the blower never stalls, plus short-cycle protection, outdoor-temperature cooling lockout, setpoint clamps, and cycle timeouts.
Per-room schedules — time blocks with days, start/end times, and target temperatures; rooms activate automatically.
Presence-based activation — motion sensors activate rooms, with configurable holdover so the HVAC doesn’t chase you around the house.
Temperature holds — hold one room at an exact temperature for 1–8 hours.
Metrics and analytics — heating/cooling hours, duty cycle, cycle length vs. outside temperature, per-room participation, CSV export.
Live event feed — vent opens/closes, cycle transitions, setpoint changes, presence detections, streamed in real time.
MQTT interface — control Plenum from Home Assistant automations; plus an MCP server so AI assistants can query and control it too.
How a cycle works
Resolve active rooms — the room manager picks each room’s active target by priority: manual override, then schedule, then presence holdover; rooms with no active target stay idle.
Infer mode — compare each active room’s average temperature (plus offset) to its target; rooms needing heating run in heat, cooling in cool. Rooms asking for the opposite direction are dropped from the cycle.
Open vents for participating rooms and close idle-room vents (subject to the airflow-floor fraction).
Set the thermostat setpoint past the most demanding room’s target by the overshoot delta, so the HVAC keeps running after the easier rooms are satisfied.
Monitor each room’s average temperature — when a room hits target (within the deadband) its vents close; if a served room drifts a full deadband past target it has live demand again and its vent reopens in the same cycle.
End the cycle once every room is at target — the thermostat setpoint is parked at its own ambient reading nudged by the overshoot delta to the idle side of the cycle direction (cooling parks above ambient, heating below), so the HVAC shuts off and cannot self-restart on its own hysteresis before the engine sees real room demand and starts the next cycle.
Safety. The headline protection, and the one the community asks about most: anti-dead-head by default — an airflow floor keeps about a third of registers open at all times, accounting for passive vents that are always open, so the system never stalls the blower. Backing it up: short-cycle protection (minimum compressor run and off times), outdoor-temperature cooling lockout, in-place cycle updates (mid-cycle changes don’t stop/restart the compressor), setpoint clamps, a force-reopen valve for closed vents, and cycle timeouts. One honest caveat: Plenum assumes a conventional system (furnace/air handler + AC) — heat pumps are not supported.
Active and maintained. The project has 55 releases and counting, CI-gated tests that only ever increase, and real-world usage feeding back into every release — I see every bug in my own house first.
Try it. Plenum installs as a Home Assistant add-on: add the repository URL in Add-on Store → ⋮ → Repositories, install Plenum, set your timezone, and click Start — the UI opens via HA Ingress. Full setup guide, docs, and screenshots are in the README.
Repo: GitHub - dhruvb14/smart-thermostat-with-vents · GitHub
I’d love feedback — and I’m genuinely curious what vent hardware the community is running, especially anyone on cheap Zigbee/Z-Wave dampers or DIY ESP32 covers, since that’s the lowest-cost way to get going and the best way to sanity-check the hardware-agnostic design.
