Skip to content

ShadowZZP/esphome-panasonic-erv

Repository files navigation

English · 简体中文

esphome-panasonic-erv

Local Home Assistant and Apple HomeKit control for a Panasonic fresh-air heat exchanger — an energy / heat recovery ventilator (ERV / HRV / 新风 / 全热交换器). No proprietary module, no cloud, no subscription: a single ~US$5 ESP32 takes the place of the OEM module and talks to the unit directly.

License: MIT ESPHome No cloud Cost Verified on hardware

Panasonic sells two optional add-on modules for these units, a Wi-Fi module (app + cloud) and an RS485 module (Modbus for building automation), and both plug into the same CN12 port. This project needs neither. One ESP32-S3 running ESPHome takes that slot and speaks the unit's private CN12 protocol straight to the main board, so everything stays on your LAN.

Compared with the alternatives — wiring dumb relays (on/off and boost only), or keeping the RS485 module and adding a Modbus/TCP gateway — this speaks the protocol natively, so you get full power / mode / fan control with nothing but the ESP.

Highlights

  • 💸 Low cost — the whole build is one ESP32 (about ¥30 / US$5) and a few jumper wires. The OEM Wi-Fi and RS485 modules cost several times more and lock you into the cloud or a building system.
  • 🔌 No OEM module needed — the ESP replaces the Wi-Fi or RS485 module and talks to the unit directly.
  • ☁️ No cloud, no app — control never leaves your network.
  • 🔄 Two-way state — a change at the wall panel shows up in Home Assistant within about a second.
  • 🍎 HomeKit-ready — one Home Assistant package turns it into an Apple Home fan with speeds and modes.

Controlling the ERV from Apple HomeKit
Toggle the unit in Apple Home — the OEM wall controller lights up in response. All local, no cloud.

Apple HomeKit     Home Assistant device page
Same unit in Apple Home (left) and Home Assistant (right).

   ┌────────────┐    CN12     ┌──────────┐   Wi-Fi    ┌────────────────┐     ┌──────────┐
   │  ERV main  │  9600 8N1   │ ESP32-S3 │  native    │ Home Assistant │     │  Apple   │
   │   board    │◄═══════════►│ ESPHome  │◄══════════►│                │◄═══►│ HomeKit  │
   └────────────┘             └──────────┘    API     └────────────────┘     └──────────┘
         ▲ the ESP sits where the OEM Wi-Fi / RS485 module used to, and talks to the board directly

The CN12 protocol is undocumented; it was reverse-engineered with a logic analyzer and verified on a real FY-25ZDP1C. If you just want it working, follow the guide below. If you want to know how it works, jump to How it works and How it was reverse-engineered at the end.

Contents

Repository layout

Path What it is When you use it
panasonic-erv.yaml ESPHome device config (entities, UART, pins) flash this to your ESP32
components/panasonic_erv/ the driver — C++ protocol + Python codegen pulled in by the config; edit to extend the protocol
homeassistant/packages/panasonic_erv.yaml Home Assistant template-fan package copy into HA config/packages/ for HomeKit
tools/decode.py CN12 frame decoder + command builder (pure Python) decode captures or build test commands when adapting a variant
secrets.yaml.example secrets template copy to secrets.yaml, fill Wi-Fi + keys
docs/PROTOCOL.md · 中文 reverse-engineered protocol + official register map to understand or extend the protocol
docs/WIRING.md · 中文 wiring + power guide when connecting the ESP to CN12

What you need

The complete bill of materials:

  • 1 × ESP32-S3 dev board — the example targets the common esp32-s3-devkitc-1. About ¥30 / US$5.
  • A few jumper wires — female-to-female is the easiest onto the CN12 header.
  • A USB-C cable — for the first flash only.
  • A computer running the ESPHome command line, or Home Assistant's ESPHome add-on.

That is the entire cost. No Panasonic Wi-Fi or RS485 module, no hub, no account, no subscription. A soldering iron is only needed later if you want to power the ESP from the unit's own 5 V instead of leaving a USB cable on it.

Compatibility

Verified on the Panasonic FY-25ZDP1C. Both the Wi-Fi module (FY-WF15ZDP1C) and the RS485 module (FY-RS15ZDP2C) plug into the same CN12 port, and Panasonic's manual lists that module across the whole ERV range, so this should work on any unit below regardless of which module yours shipped with. Only the FY-25ZDP1C is physically tested; treat the rest as "should work, untested". Available modes differ by model class (a thin-domestic unit's mode 0x05 is exhaust; on a cold-region unit the same value is severe-cold, see docs/PROTOCOL.md). This component implements the thin-domestic power/mode/fan control; larger units expose extra functions it does not touch yet.

Class Models
Thin domestic FY-15ZDP1C, FY-25ZDP1C ✅, FY-35ZDP1C, FY-50ZDP1C, FY-15GZD1, FY-25GZD1, FY-35GZD1, FY-50GZD1, FY-RZ18DP1, FY-RZ28DP1, FY-RZ38DP1
Thin domestic, cold-region FY-15ZDP1CX, FY-25ZDP1CX, FY-35ZDP1CX
DC-motor FY-15ZJD2C, FY-25ZJD2C, FY-35ZJD2C, FY-15GZJP2, FY-25GZJP2, FY-35GZJP2, FY-15ZJP2C, FY-25ZJP2C, FY-35ZJP2C
Commercial FY-15ZY1C, FY-25ZY1C, FY-35ZY1C, FY-50ZY1C, FY-65ZY1C, FY-80ZY1C, FY-1KZY1C, FY-1HZY1C, FY-2KZY1C
Cabinet FY-50ZR1C, FY-70ZR1C

If you try one that isn't the FY-25ZDP1C, please open an issue with the result — it helps everyone.

Warning. This replaces an OEM part on a mains appliance using an undocumented protocol. You may void your warranty, and you do this at your own risk. Always work with the unit unplugged. An OEM module and the ESP must never be on the bus at the same time. See docs/WIRING.md.

Install and wire it up

You can do the entire software side on the bench first, then wire it into the unit. Step by step:

1. Install ESPHome.

pip install esphome      # or use the ESPHome add-on inside Home Assistant

2. Get the config and set your secrets.

git clone https://github.com/shadowzzp/esphome-panasonic-erv
cd esphome-panasonic-erv
cp secrets.yaml.example secrets.yaml      # then edit your Wi-Fi SSID and password
openssl rand -base64 32                     # paste the output as panasonic_erv_api_key
openssl rand -base64 32                     # paste the output as panasonic_erv_ota_password

The included panasonic-erv.yaml already points at the local components/ folder, so it builds as-is.

3. Flash it over USB. Plug the ESP32 into your computer and run:

esphome run panasonic-erv.yaml --device /dev/ttyACM0

Every later update goes over Wi-Fi instead — no cable, no opening the case:

esphome run panasonic-erv.yaml --device <device-ip>

4. Wire it to the unit. Power off the ERV at the breaker and unplug the OEM module from CN12. Connect three wires (full guide and a wiring diagram in docs/WIRING.md):

ESP32-S3 CN12
GPIO18 line A (board TX)
GPIO17 line B (board RX)
GND GND

Both CN12 lines are 3.3 V on the board's side, so the ESP connects directly — no level shifter. Never leave the OEM module plugged in alongside the ESP.

ESP32 wired into the ERV's CN12 in the ceiling
The ESP32-S3 (lower left) wired into the ERV's CN12 in place of the OEM module.

5. Power up. The example ships with tx_enable_at_boot: true, so the ESP registers itself as the module on boot and the panel's F02 error clears. You are now in control.

Home Assistant and HomeKit

Within a few minutes the device appears in Home Assistant over the ESPHome native API (Settings → Devices & services). Confirm it and paste the panasonic_erv_api_key when asked. You get a Power switch and Mode / Fan selects, plus diagnostic entities.

For Apple Home, add one file. Copy homeassistant/packages/panasonic_erv.yaml into your HA config/packages/ folder, make sure configuration.yaml has:

homeassistant:
  packages: !include_dir_named packages

then reload (Developer Tools → YAML → Template Entities, or restart). It folds the switch and two selects into one fan.panasonic_erv, which the HomeKit Bridge exposes as a fan with on/off, three speeds, and the modes as presets — synced both ways. Keep the underscore in the filename: HA silently ignores package files whose names contain a hyphen.

Entities

Entity Type Notes
switch.panasonic_erv_power switch on / off
select.panasonic_erv_mode select 热交换 / 内循环 / 外循环 (heat-exchange / recirculate / exhaust)
select.panasonic_erv_fan select 1 / 2 / 3
fan.panasonic_erv fan the unified entity from the HA package, for HomeKit
switch.panasonic_erv_tx_enable switch (config) master bus kill-switch; turn off before reinserting an OEM module
switch.panasonic_erv_auto_keepalive switch (config) registration and keepalive loop
button.panasonic_erv_send_registration button (diag) replay the boot handshake
button.panasonic_erv_restart / …_safe_mode_ota_recovery / …_send_poll button (diag) remote recovery
text.panasonic_erv_raw_tx_hex text (config) inject an arbitrary frame for protocol work
number.panasonic_erv_cksum_base number (config) live-tune the checksum base for variants
sensor.panasonic_erv_* sensor (diag) Wi-Fi signal, uptime, RX/TX frame counters

Configuration

panasonic_erv:
  id: erv
  uart_id: erv_uart
  tx_enable_at_boot: true   # default false. true = register + keepalive on boot (OEM module removed)
  cksum_base: 0xC0BA        # checksum base (Σ payload + base); default verified on FY-25ZDP1C

tx_enable_at_boot defaults to false so the component is listen-only until you opt in, which is the safe state while an OEM module is still plugged in and you are sniffing the bus.

Troubleshooting

Panel shows F02. The board is not seeing a registered module. Check that tx_enable_at_boot is true (or toggle TX Enable on), the OEM module is removed, and TX/RX are not swapped. Press Send Registration.

Fan or mode change is ignored while the unit is off. Expected. The board will not change speed or mode while powered off. Turn power on first; the HomeKit fan does this automatically.

No status / nothing on the bus. Confirm a common ground and that rx_pin is on line A (board TX).

Blank panel after many rapid commands. Transient; power-cycle the unit or press a panel button. The command coalescing in the firmware is there to prevent this.


The rest is for the curious. Skip it if your fan already works.

How it works

An OEM module and the main board exchange A5 A5 5A 5A-framed packets over CN12 at 9600 8N1. The ESPHome component takes the module's place and plays its role:

  1. Registration. On boot it replays the module's power-up handshake, then keeps the link alive with a poll every ~2 s and a heartbeat every ~6 s. Without this the panel shows F02.
  2. Reading state. It parses the board's status frames (03 0B … RUN MODE FAN) into power, mode, and fan, so a change made at the wall panel shows up in Home Assistant too.
  3. Sending commands. It builds 66-byte command frames (02 0B) with the correct checksum, using masked writes so it can change one field without disturbing the others.

The full frame-by-frame spec, including the official Modbus register map, is in docs/PROTOCOL.md.

How it was reverse-engineered

The CN12 protocol isn't published, so it was worked out from scratch on the bench with a logic analyzer. The short version:

  1. Find the bus. Unplugging the OEM Wi-Fi module makes the panel show F02 (device-connection error). That confirms the module↔board link is what carries control, and CN12 is that link.
  2. Listen. A logic analyzer on line A — the board's 3.3 V transmit line, read-only and safe — showed 9600 8N1 traffic framed by A5 A5 5A 5A.
  3. Map the fields. Pressing power / mode / fan on the wall panel and watching which bytes changed pinned down RUN, MODE and FAN inside the 36 00 00 00 … payload.
  4. Crack the checksum. Each command carries a 16-bit b5 b6 field. Part of it looked random per boot — a red herring, that turned out to be the board's own status sequence. The command checksum was deterministic: (Σ payload + 0xC0BA) & 0xFFFF, consistent across three captured commands. Synthesizing a power-on command with that checksum and sending it made the unit physically start — the moment it all came together.
  5. Pass as the module. Replaying the module's boot handshake and keepalive cadence makes the board accept the ESP as a genuine module, so the panel never falls back to F02.

Logic analyzer tapping the CN12 bus on the bench
Bench setup: tapping the CN12 bus to capture and decode the protocol.

The full spec is in docs/PROTOCOL.md.

State sync and efficiency

Two design choices keep control snappy without flooding the network or the slow 9600-baud bus.

Slider floods. Dragging the HomeKit speed slider fires a burst of set-percentage calls. The firmware coalesces them and only sends the final, settled value, so the bus and the unit's panel never see the intermediate steps.

Idle traffic. ESPHome's select does not de-duplicate state, so polling one republishes to HA every interval whether or not anything changed. Instead the selects here are optimistic (instant feedback when you tap) and a small interval lambda pushes the board's real state back only when it actually changes, and only after an in-flight command has settled. The result is instant UI, about a one-second sync when something changes at the wall panel, and almost no traffic when idle. The logger runs at INFO and the per-frame hex formatting is compiled out unless you raise it to DEBUG, so a sealed unit can still be deep-debugged over the air without paying for it the rest of the time.

Contributing and feedback

This runs reliably on my own FY-25ZDP1C, and I'm open-sourcing it so nobody else has to reverse-engineer the bus from scratch. Use it directly, or as a reference for your own build.

The protocol is verified on one model. The other units in the compatibility list should work too, but I can't test them all — if yours behaves a little differently, that's expected and usually a small tweak away (the tools/decode.py helper and the protocol spec exist for exactly that).

Issues and pull requests are welcome, especially:

  • "works on model X" — or "needed change Y" — reports, so the compatibility list reflects reality
  • extra registers or features from the larger units
  • fixes and improvements

If it saved you some time, a star helps others find it.

Credits

The "emulate the module" approach was proven by DomiStyle/esphome-panasonic-ac, which does the same for Panasonic air conditioners (the CN-CNT / CZ-TACG1 protocol). The ERV's CN12 framing is different, so this protocol was reversed from scratch, but that project showed it was worth doing. Built on ESPHome.

License

MIT

About

ESPHome local control for Panasonic ERV / fresh-air heat exchangers on the CN12 bus: Home Assistant + HomeKit, no OEM Wi-Fi/RS485 module, no cloud, one ~$5 ESP32 | 松下新风系统(全热交换器)全本地接入 HA + HomeKit:一块 ESP32 顶替原厂 WiFi/485 模块直连主板,免云端免App,超低成本

Topics

Resources

License

Stars

6 stars

Watchers

0 watching

Forks

Packages

 
 
 

Contributors