Sensors, firmware, rooms

dev-smarthome

· Home Assistant

A Home Assistant integration for a ventilation board

The controller speaks a short serial protocol. A custom integration was less fiction than a pile of template sensors.

The heat recovery unit in the cupboard is a bare board with a TTL header. It was never going to grow an ESPHome port: the vendor firmware already drives the fans, and I only needed to read speeds and set the mode. A USB-serial adapter and a small integration were the whole project.

Why not templates

I started with a command-line sensor and four template entities. That worked until the board answered out of order. Templates have no good place to keep a lock around the serial port, and two automations talking at once produced checksum errors that looked like broken hardware.

The integration owns the port. One asyncio lock, one reader, entities that call async_set_native_value only after a frame comes back intact.

Layout

custom_components/bench_vent/
  manifest.json
  config_flow.py
  coordinator.py
  sensor.py
  select.py
  protocol.py

protocol.py is the only file that knows the wire format: a short header, a command byte, a payload, and a CRC8. Modes are supply, extract, and both, plus an off that the board treats as a minimum rather than a true stop. I expose that as a select, not a switch, because "off" is a lie.

The config flow asks for the device path and a poll interval. I default the poll to 15 seconds. Faster than that and the board starts dropping frames; slower and the bathroom boost feels late.

Failure mode I kept

If three polls fail, the coordinator marks the entities unavailable instead of holding the last fan speed. A stale "high" on the dashboard is how I once left the unit boosting all afternoon while the adapter had simply unplugged. Unavailable is the honest state.

There is still no firmware update path. I am not going to pretend a serial menu is an OTA system. If the vendor image needs replacing, that is a bench session with a clip, not a button in Home Assistant.