# Vaillant eBUS — `vaillant_ebus` setup guide

Customer-facing instructions for adding a Vaillant gas boiler **or
heat pump** to your Otonomo install. One driver covers both via two
config axes:

| Axis | Values | Picks what |
|---|---|---|
| `device_class` | `gas_boiler` / `heat_pump` | Which message dictionary + canonical metric namespace |
| `mode` | `active` / `passive` | Transport — `active` via local ebusd master, `passive` via eBUS Adapter Shield TCP tap (read-only) |

Tested matrix:

| Combination | Tested device | Status |
|---|---|---|
| `gas_boiler` + `active` | ecoTEC plus VC 376/5-5 + ebusd 23.x | ✅ stable (home box) |
| `heat_pump` + `passive` | flexoTHERM exclusive + sensoCOMFORT VRC 720 + eBUS Adapter Shield v3 | ✅ live (prospect box) |
| `heat_pump` + `active` | Decoder ready; not yet validated on a live install | ⏳ beta |
| `gas_boiler` + `passive` | Decoder ready; not yet validated on a live install | ⏳ beta |

---

## Which mode am I?

* **`mode: active`** — when *you* (your Otonomo box) are the room
  thermostat. The installer's controller has been physically removed
  (e.g. vSMART unplugged, sensoCOMFORT detached) and a local `ebusd`
  daemon arbitrates on the eBUS pair at master address `0x31` by
  default. Full reads + writes. This is the gas-boiler use case below.
* **`mode: passive`** — when the customer's installer controller
  (VRC 700 / multiMATIC / sensoCOMFORT) is still in charge of the
  boiler or heat pump. We tap the bus through the [eBUS Adapter
  Shield](https://adapter.ebusd.eu/) at TCP `:9999` and decode whatever
  flows passively. **Zero bus writes.** Required for any install where
  you are not the bus master.

Pick the section below that matches your install.

---

## Heat pump (passive mode) — fast path

If you have a **Vaillant heat pump** (flexoTHERM, aroTHERM, aroSTOR or
similar) and the installer's controller (sensoCOMFORT, multiMATIC,
VRC 700) is still running it, use this path. Read-only by design — we
observe the bus, the installer's controller stays in charge of all
control decisions.

### Hardware

1. **eBUS Adapter Shield** from [adapter.ebusd.eu](https://adapter.ebusd.eu/)
   (~€87). It's a small board with WiFi/Ethernet that taps the eBUS pair
   and exposes the byte stream over TCP `:9999` in the enhanced
   protocol. Plug it into mains or PoE; connect the eBUS pair from the
   heat-pump's eBUS terminals (polarity-insensitive).
2. **No serial cable, no ebusd install, no software on the heat-pump
   side.** The Shield is a passive tap when no host issues commands.
3. Note the adapter's LAN IP (DHCP-assigned; the Shield's web UI on
   port 80 shows it).

### Configuring the driver

Add this block to your site manifest (`/etc/otonomo/site_manifest.yaml`):

```yaml
- instance: vaillant_hp
  driver: vaillant_ebus
  version: ">=0.2.0,<0.3.0"
  config:
    device_class: heat_pump
    mode: passive
    adapter_host: 192.168.x.y   # Shield IP on your LAN
    adapter_port: 9999          # default; rarely overridden
    passive_window_s: 8.0       # capture window per poll
```

Restart the SDK publisher; within ~60 s the cloud dashboard's heat-pump
tab populates.

### What you get (heat pump, passive)

| Metric | Source | When it lands |
|---|---|---|
| Flow / return / Δ-T | B511 Status01 | Every poll (live) |
| DHW tank top temperature | B511 Status01 | Every poll (live) |
| Source temperature (brine / air inlet) | B511 Status01 | Every poll (live) |
| HC pump state | B511 Status01 | Every poll (live) |
| Operating state (`ready` / `heating` / `cooling` / `heating_water` / `error`) | B511 ID=07 | When controller polls it |
| Controller intent — plain-English summary of the most recent SetMode write | B510 passive observation | Every poll once the controller writes (sub-minute) |
| `appears_parked` flag (HC + DHW load both disabled) | derived from SetMode | Every poll |
| HMU clock (ISO) | B504 / B516 broadcasts | Every 5–30 min |
| Outdoor air temperature (broadcast) | B516 broadcast | Every 10–30 min |
| Live electrical input / thermal output / compressor modulation | B51A | Only on controllers that poll it |
| Compressor on / demand | B509 ID=1D / 0x54 | Controller-poll-dependent |
| Backup heater on | B509 ID=5F | Controller-poll-dependent (CRITICAL — backup heater = peak-hour budget killer) |
| HC water pressure | B509 ID=12 | Controller-poll-dependent |
| eBUS bus health (telegrams/min, CRC error %) | Self-measured | Every poll |

All values land in fleet-db's `hp_local_*` columns and render
automatically on `/pro/heat_pump`.

### What you can NOT do (today)

* **Write to the eBUS pair.** Passive mode is read-only by
  construction — `execute()` refuses every command type with a clear
  "passive mode is read-only" message. The customer's controller owns
  the wire; us becoming a second master would risk arbitration
  collisions and boiler lockouts.
* **Set the heat curve, force a DHW boost, or change operating mode**
  via this driver. For power-limit control, use the companion
  `vaillant_eebus` driver (LPC over EEBUS via sensoNET — different bus
  entirely, designed for §14a-style power caps; see
  `docs/drivers/vaillant_eebus.md`).

---

## Gas boiler (active mode) — the original path

If you have a **Vaillant gas boiler** AND you've removed the
installer's thermostat (so we become the room thermostat), use this
path.

### Prerequisites

1. **A Vaillant boiler with an eBUS port.** This is almost every
   Vaillant gas boiler made since ~2010. Look for two unmarked screw
   terminals on the boiler's electronics board, sometimes labelled
   `+` / `-` or `1` / `2`. Consult your installation manual.
2. **A USB-to-eBUS adapter.** The most popular options:
   - **eBUS Coupler II** (eservice-online.de, ~€80)
   - **DIY Adapter** (instructables/eBus open-hardware designs, ~€20)
   - **vbus-USB** (Resol-style)
   The Otonomo agent talks to whichever via ebusd, so any
   ebusd-compatible adapter works.
3. **`ebusd` running on the same machine as the Otonomo agent.**
   Install with `sudo apt-get install ebusd` (Debian/Ubuntu) or build
   from source. Default config exposes a TCP API on `:8888` which is
   what our driver connects to.

---

## Wiring

1. Power off the boiler at the breaker.
2. Locate the eBUS terminals on the boiler's PCB. Polarity DOES NOT
   matter — eBUS is differential.
3. Connect two wires from those terminals to the adapter's eBUS pins.
   Total cable length up to ~100 m, any gauge ≥ 0.5 mm² works.
4. Plug the adapter into a USB port on your Otonomo box.
5. Power the boiler back on.

Within 30 seconds, ebusd should detect the boiler and start polling.
Verify with:

```bash
ebusctl find
# Should list: bai (your boiler), broadcast, and possibly others
ebusctl read -c bai FlowTemp
# Should return the current flow temperature in °C
```

---

## Configuring the driver in Otonomo

1. Open your local UI at `http://<your-box-ip>:8080/drivers`.
2. Find **vaillant_ebus** under "Gas Boiler" and click **Install**.
   Otonomo pip-installs the driver into the venv (~5 s).
3. Once installed, click **Add instance**. Fill in:

   | Field | Value | Why |
   |-------|-------|-----|
   | Instance ID | `vaillant_ebus.boiler` | Unique on this box |
   | `ebusd_host` | `127.0.0.1` | ebusd runs on the same machine |
   | `ebusd_port` | `8888` | ebusd default |
   | `circuit` | `bai` | Vaillant boiler-automation interface; most installs |
   | `timeout_s` | `3.0` | Vaillant responds within 1 s typically |

4. Click **Create instance**.

Within 30 seconds, your local dashboard's Heating page lights up:
DHW temp, flow/return, modulation, burner state.

---

## Verifying it's working

In the local UI:

- **`http://<box-ip>:8080/device/heating`** — six or more cards
  populated (DHW, flow, return, outdoor, burner, modulation).

In the cloud dashboard:

- **`https://app.otonomo.be/pro/heating`** — same metrics, plus
  trailing-day history.

On the command line (advanced):

```bash
mosquitto_sub -h <box-ip> -t 'hems/+/telemetry/vaillant_ebus.boiler' -v
```

You should see JSON messages every ~30 s.

---

## Common pitfalls

### "ERR: not authorized" reading some registers

Some Vaillant fields are gated by ebusd's local ACL (heat curve
parameters, d.xx installer codes). Fix by starting ebusd with
`--accesslevel=*`:

```bash
sudo systemctl edit ebusd
# Add:
[Service]
Environment="EBUSD_OPTS=--accesslevel=*"

sudo systemctl restart ebusd
```

This is safe — ebusd's ACL is local-only; nothing on the bus can
abuse it.

### "Hot water tank: 116.06 °C"

The Vaillant firmware returns `0x0741 = 116.06 °C` when the DHW
sensor isn't installed or is invalid. The Otonomo driver filters
this magic value out automatically. If you still see it on the
dashboard, either:

- Your `dhw_max_temp_c` driver setting is wrong (defaults are fine)
- Your boiler doesn't have a DHW tank sensor at all (combi-only
  configurations — the metric simply won't update)

### Boiler "forgets" DHW target shortly after Otonomo writes it

This is the **vSMART/VR940f setback fight** — a stock Vaillant
thermostat re-broadcasts the previous target every few minutes,
overwriting Otonomo's. Solutions in order of preference:

1. **Remove the vSMART** if you don't use it. Otonomo replaces its
   functionality (room temp via Shelly, weather-compensated curve,
   etc.) and the boiler runs fine without it.
2. **Disconnect the vSMART's eBUS leads** and leave the controller
   itself in place for warranty purposes.
3. **Set a "permanent override" on the vSMART** — most models allow
   pinning a target temp indefinitely. Then Otonomo and the vSMART
   target the same value; no fight.

### Flow temp clipped at 75 °C

The boiler's d.71 parameter sets a hard flow-temp ceiling. Default
on most installs is 75 °C (raised from the factory 55 °C for cold-
morning warmup performance). The Otonomo driver refuses to write
above this ceiling — that's a feature, not a bug. To raise it:

1. Enter installer mode on the boiler control panel
   (long-press the wrench icon).
2. Find parameter d.71 and raise to your desired ceiling
   (max usually 85 °C).
3. Exit installer mode.

Otonomo re-reads the ceiling on the next poll and starts allowing
writes up to the new value.

---

## What Otonomo will do with this driver

In **observe mode** (free trial):
- Reads DHW temp, flow, return, outdoor, modulation, burner state
  every 30 s
- Sends them to the cloud for visualization + the optimization
  shadow run

In **active mode** (€3/mo, opt-in per capability):
- **`Hot water (DHW)` capability**: schedules DHW heating cycles
  for off-peak hours when affordable + when there's PV surplus.
  Pre-charges the tank before predicted high-price evenings.
- **`Heating setpoints` capability**: weather-compensated flow-temp
  control. Falls back to the boiler's built-in curve if the cloud
  is unreachable (cloud-watchdog safe mode).

You can enable / disable each capability independently at
`https://app.otonomo.be/account/control`.

---

## References

- ebusd wiki — https://github.com/john30/ebusd/wiki
- eBUS specification (member-only, ~€50) — https://ebus.io/
- Otonomo driver source — `otonomo_drivers/drivers/vaillant_ebus/`

Otonomo's `vaillant_ebus` is an independent interoperability tool. Not
affiliated with Vaillant Group.
