The problem
I have a Daikin MVHR (Mechanical Ventilation with Heat Recovery) unit at home — brings in fresh air without losing indoor heat/coolness, and cuts humidity. My house is already full of temperature/humidity sensors, but the ventilation unit itself only understood button presses on its wall panel. I wanted it driven by those sensors, automatically, through Home Assistant.
Starting point
already reverse-engineers Daikin's P1/P2 bus for heat pumps, and it's a great reference for the electrical/framing side of the bus. But VAM ventilation units are read-only there — no write support. So the write side needed reverse-engineering from scratch.
The discovery
Daikin's P1/P2 bus natively supports two controllers on the same bus: a Master and a Slave, selected by a physical switch on the wall panel (BRC301B61). That turned out to be the whole story: a generic "aux" responder answering on the bus is never offered the writable state channel (packet type 0x32) — only a controller the master recognizes as a genuine second one gets it.
The detail that actually makes it work, and that isn't obvious at all: the real slave panel answers the registration poll (0x30) only on the very first poll. On every poll after that, it goes completely silent. A firmware that keeps answering (which looks like the more "correct" behavior) gets silently downgraded by the master to a read-only channel instead. Once that was nailed down, on/off, fan speed, mode, and fresh-up were all commandable, with closed-loop confirmation read back from the bus.
Full byte-level protocol, packet captures, and the list of things that looked plausible but don't work are in protocol.md in the repo.
Architecture
Two MCUs, on purpose but not by necessity:
- An ATmega328 is the actual P1/P2 slave controller — the core of the project. It registers on the bus, mirrors real-time state, and commands the unit. It works entirely standalone over a simple serial line.
- An ESP32-H2 bridges that serial line to native Zigbee (
esp-zigbee-lib/esp-zboss-lib, no external radio), exposing 6 On/Off endpoints to Home Assistant — power, speed, fresh-up, and 3 mutually-exclusive mode switches — plus a Zigbee OTA client so it can be updated once it's sealed behind the wall panel.
The P1/P2 bus timing (response delays, the silence-after-registration behavior above) was only ever validated on the ATmega — I haven't tried porting that timing-sensitive part to the ESP32-H2. Splitting the two was the path of least resistance, not a claim that it needs two chips: with more testing, the ESP32-H2 could end up handling the bus directly and the second MCU could go away entirely.
Status
Installed behind the wall panel and in daily use for a few weeks now, driven by Home Assistant automations off the house's existing humidity/temperature sensors — working reliably so far, though it's still early days, not validated over months/seasons yet.
The PCB is currently two boards (I validated the P1/P2 transceiver on its own first, then added the ATmega+ESP32 board once the protocol was confirmed) — a single, smaller, more integrated board is a possible next revision if there's interest.
Repo
— code, schematics, and the full protocol write-up.
scavenrage
Jason K
Greg Nuspel
Dave