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

Arnold-n's P1P2MQTT 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

https://github.com/scavenrage/Daikin-VAM-P1P2-SlaveController — code, schematics, and the full protocol write-up.