ESPHome/Home Assistant integration for monitoring and controlling Stiebel Eltron heat pumps via CAN bus interface. Features automatic MQTT discovery for 3800+ signals, writable controls, and intelligent sensor management.
Based on the Elster protocol implementation by Jürg Müller and community work by roberreiters.
- Automatic MQTT Discovery: All 3800+ Elster protocol signals automatically discovered in Home Assistant
- Frequency-Based Polling: Intelligent signal request scheduling (1min/10min/30min intervals)
- Writable Controls: Direct CAN bus write support for temperature setpoints and operating modes
- SG Ready Support: Smart Grid Ready integration for PV surplus utilization (Documentation)
- Calculated Sensors: Automatic computation of COP, Delta-T, compressor status, and betriebsart
- Minimal Configuration: Only 22 essential sensors defined, rest auto-discovered
- Button-Based Datetime Control: Set heat pump time/date via Home Assistant helpers
- Multi-Device Architecture: Separate CAN member devices (Manager, Kessel, Heizmodul)
esphome/
├── heatingpump.yaml # Main device config (board selection, substitutions, includes)
└── ha-stiebel-control/
├── board_esp32s3.yaml # ESP32-S3 board config (16MB flash, OPI PSRAM)
├── board_esp32s2.yaml # ESP32-S2/generic ESP32 board config
├── can_esp32.yaml # Built-in TWAI CAN config (256 RX/64 TX buffers)
├── can_mcp2515.yaml # MCP2515 SPI CAN config (legacy)
├── common.yaml # Board-agnostic: WiFi, MQTT, API, OTA, buttons
├── wpl13e.yaml # Device-specific sensors (template for other models)
├── ha-stiebel-control.h # Main C++ logic: MQTT discovery, CAN write, calculators
├── signal_requests_wpl13e.h # Polling schedule for signals
├── config.h # Blacklist configuration
└── elster/ # Elster protocol library
├── ElsterTable.h # 3800+ signal definitions with metadata
├── KElsterTable.cpp/h # Table lookup functions
└── NUtils.cpp/h/NTypes.h # Utility functions
packages/
└── ha_stiebel_control.yaml # Home Assistant helpers (input_datetime)
Heat Pump CAN Bus (Elster Protocol)
↓
ESP32-S3 (Built-in TWAI) or ESP32-S2 + MCP2515
↓
ESPHome (ha-stiebel-control.h)
- Reads CAN frames
- Parses Elster signals
- Publishes MQTT discovery
- Publishes state updates
↓
MQTT Broker
↓
Home Assistant
- Auto-creates entities
- Updates states
- Provides UI controls
- ESP32 acts as:
PC(0x680) on CAN bus - CAN Members:
KESSEL(0x180): Boiler/storage tankMANAGER(0x480): Main controllerHEIZMODUL(0x500): Heat pump module
- Communication: Universal frame handler processes all CAN IDs with mask 0
- Protocol: Elster index-based read/write operations
This project supports two hardware configurations:
Advantages:
- ✅ No buffer overflows (256 RX queue vs 2 on MCP2515)
- ✅ Faster processing (no SPI overhead)
- ✅ Better timing accuracy (hardware CAN controller)
- ✅ Single board solution
Hardware:
- Waveshare ESP32-S3-RS485-CAN Board (or similar ESP32-S3 with CAN transceiver)
- Specifications: 16MB Flash, OPI PSRAM
- Configuration: Automatically configured for optimal performance
- Connections:
- CAN-H (TXD2/GPIO15) → Heat pump CAN-H
- CAN-L (RXD2/GPIO16) → Heat pump CAN-L
- GND → Heat pump GND
- Power: USB or 5V/3.3V input
Note: May experience buffer overflows on high-traffic CAN buses.
Hardware:
- ESP32 Development Board (ESP32-S2, ESP32 DevKit V1, etc.)
- MCP2515 CAN Transceiver Module
- TJA1050/SN65HVD230 CAN Bus Transceiver (often integrated on MCP2515 board)
- Connections:
- SPI: CLK (GPIO18), MOSI (GPIO23), MISO (GPIO19), CS (GPIO5)
- CAN: H and L to heat pump CAN bus
- Power: 5V or 3.3V depending on module
- Connect to the service port on your Stiebel Eltron heat pump
- Typical CAN pinout: Pin 3 (CAN-H), Pin 5 (CAN-L), Pin 7 (GND)
- Check your heat pump manual for exact pinout
Copy the esphome/ folder contents to your ESPHome config directory:
/config/esphome/
├── heatingpump.yaml
└── ha-stiebel-control/
├── board_esp32s3.yaml
├── board_esp32s2.yaml
├── can_esp32.yaml
├── can_mcp2515.yaml
├── common.yaml
├── wpl13e.yaml
├── ha-stiebel-control.h
├── signal_requests_wpl13e.h
├── config.h
└── elster/
├── ElsterTable.h
├── KElsterTable.cpp
├── KElsterTable.h
├── NTypes.h
├── NUtils.cpp
└── NUtils.h
Edit heatingpump.yaml and select your hardware configuration:
For ESP32-S3 with built-in CAN:
# ESP32-S3 section (uncommented)
substitutions:
device_name: heatingpump
friendly_name: "Stiebel Eltron Wärmepumpe"
can_tx_pin: GPIO15 # TXD2 on Waveshare board
can_rx_pin: GPIO16 # RXD2 on Waveshare board
can_id_pc: "0x680"
packages:
board: !include ha-stiebel-control/board_esp32s3.yaml
can: !include ha-stiebel-control/can_esp32.yaml
base: !include ha-stiebel-control/common.yaml
sensors: !include ha-stiebel-control/wpl13e.yamlFor ESP32-S2 with MCP2515:
# ESP32-S2 section (uncomment this, comment out ESP32-S3)
substitutions:
device_name: heatingpump
friendly_name: "Stiebel Eltron Wärmepumpe"
can_clk_pin: GPIO18
can_mosi_pin: GPIO23
can_miso_pin: GPIO19
can_cs_pin: GPIO5
can_id_pc: "0x680"
packages:
board: !include ha-stiebel-control/board_esp32s2.yaml
can: !include ha-stiebel-control/can_mcp2515.yaml
base: !include ha-stiebel-control/common.yaml
sensors: !include ha-stiebel-control/wpl13e.yamlCreate a secrets.yaml file in your ESPHome directory and enter your credentials
wifi_ssid: "YOUR_WIFI_SSID"
wifi_password: "YOUR_WIFI_PASSWORD"
mqtt_broker: "YOUR_MQTT_BROKER_IP"
mqtt_username: "YOUR_MQTT_USER"
mqtt_password: "YOUR_MQTT_PASSWORD"esphome run esphome/heatingpump.yamlOr use the ESPHome dashboard to compile and upload.
Copy packages/ha_stiebel_control.yaml to your Home Assistant /config/packages/ folder.
Enable packages in /config/configuration.yaml:
homeassistant:
packages: !include_dir_named packagesRestart Home Assistant.
Ensure the MQTT integration is set up in Home Assistant:
- Settings → Devices & Services → Add Integration → MQTT
- Enter your MQTT broker details
- MQTT entities will auto-discover
-
Check ESPHome Logs:
esphome logs esphome/heatingpump.yaml
Look for:
[MQTT_CONN] Connected to MQTT broker[processCanMessage] MANAGER (0x480): ...[MQTT] Discovery published for ...
-
Check Home Assistant:
- Go to Settings → Devices & Services → MQTT
- Look for "Manager", "Kessel", "Heizmodul" devices
- Entities should appear automatically
-
Check MQTT Topics (optional):
mosquitto_sub -h YOUR_BROKER -u USER -P PASS -t "homeassistant/+/heatingpump/#" -v
All sensors are automatically discovered and categorized by CAN member:
- Manager Device: Control signals, operating mode, status
- Kessel Device: Storage tank temperatures, target temps
- Heizmodul Device: Heat pump module temperatures, compressor status
Sensors update based on polling frequency (1min, 10min, or 30min intervals).
Automatically discovered MQTT entities:
- Speicher Soll Temperatur (Storage Target Temp 1):
number.speicher_soll_temperatur - Speicher Soll Temperatur 2 (Storage Target Temp 2):
number.speicher_soll_temperatur_2 - Programmschalter (Operating Mode):
select.programmschalter- Options: Notbetrieb, Bereitschaft, Automatik, Tagbetrieb, Absenkbetrieb, Warmwasser
To change values:
- Use Home Assistant UI
- Call service via automation
- Publish to MQTT command topic
NEW: Intelligent PV surplus utilization using the SG Ready standard.
Control your heat pump based on solar energy availability with 4 operating states:
- State 1: Grid lock - standby mode
- State 2: Normal operation
- State 3: PV surplus available - boost DHW heating
- State 4: High PV surplus - maximum DHW heating
Documentation: See SG_READY.md for complete guide (quick start, configuration, automations, troubleshooting)
Features:
- ✅ ESPHome-native control (fast, reliable)
- ✅ Dropdown select in Home Assistant (
select.manager_sg_ready_zustand) - ✅ Compatible with any PV system (E3DC, SolarEdge, Fronius, etc.)
- ✅ Manual override capability for testing
- ✅ Optional temperature boost automations
- ✅ Replaces hardware EVU lock (e.g., Shelly relays)
- Go to Home Assistant → Settings → Devices & Services → Helpers
- Find
input_datetime.heatingpump_timeandinput_datetime.heatingpump_date - Set desired time/date
- Go to your heat pump device
- Press "Update Uhrzeit" or "Update Datum" button
Auto-published to heatingpump/calculated/ topics:
- Date:
YYYY-MM-DDfrom JAHR, MONAT, TAG signals - Time:
HH:MM:SSfrom STUNDE, MINUTE, SEKUNDE signals - Betriebsart: "Sommer" or "Winter" derived from SOMMERBETRIEB
- Delta T Continuous: Flow - Return temperature (always)
- Delta T Running: Flow - Return temperature (only when compressor active)
- Compressor Active: Binary sensor (on when VERDICHTER > 2)
- COP WW: Coefficient of Performance for hot water
- COP Heizung: Coefficient of Performance for heating
- COP Gesamt: Overall coefficient of performance
To add support for your specific model:
- Copy
esphome/ha-stiebel-control/wpl13e.yamltoesphome/ha-stiebel-control/your_model.yaml - Edit
esphome/heatingpump.yaml:packages: base: !include ha-stiebel-control/common.yaml sensors: !include ha-stiebel-control/your_model.yaml
- Consult PDF manuals in
manuals/folder for signal meanings - Find signal names in
esphome/ha-stiebel-control/elster/ElsterTable.h - Add template sensors following the pattern:
- platform: template name: "SIGNAL_NAME" id: SIGNAL_NAME unit_of_measurement: "°C" device_class: "temperature" state_class: "measurement" accuracy_decimals: 1 update_interval: 1min lambda: |- readSignal(&CanMembers[cm_manager], "SIGNAL_NAME"); return {};
Edit esphome/ha-stiebel-control/signal_requests_wpl13e.h:
static const SignalRequest signalRequests[] = {
{"YOUR_SIGNAL", FREQ_1MIN, cm_manager}, // Poll every 1 minute
{"OTHER_SIGNAL", FREQ_10MIN, cm_kessel}, // Poll every 10 minutes
{"RARE_SIGNAL", FREQ_30MIN, cm_heizmodul} // Poll every 30 minutes
};Edit esphome/ha-stiebel-control/config.h:
static const char* BLACKLISTED_SIGNALS[] = {
"UNWANTED_SIGNAL",
"ANOTHER_SIGNAL"
};Or set isBlacklisted flag in ElsterTable.h entry.
If your heat pump uses different CAN IDs, edit esphome/ha-stiebel-control/ha-stiebel-control.h:
static const CanMember CanMembers[] = {
{"PC", 0x680, {0x00, 0x00}, {0x00, 0x00}, {0xE2, 0x00}},
{"KESSEL", 0x180, {0x31, 0x00}, {0x30, 0x00}, {0x00, 0x00}},
{"MANAGER", 0x480, {0x91, 0x00}, {0x90, 0x00}, {0x00, 0x00}},
{"HEIZMODUL", 0x500, {0xA1, 0x00}, {0xA0, 0x00}, {0x00, 0x00}}
};For MCP2515 (ESP32-S2):
- Check SPI wiring (CLK, MOSI, MISO, CS pins)
- Verify MCP2515 power (3.3V or 5V depending on module)
For ESP32-S3 Built-in CAN:
- Verify GPIO15 (TX) and GPIO16 (RX) connections
- Check CAN transceiver power
Common to both:
- Verify CAN-H and CAN-L connections to heat pump
- Check ESPHome logs for
[canbus] Setup CAN... - Verify heat pump CAN bus is active (should be always on)
- Check CAN bus termination (120Ω resistors at both ends)
- Verify MQTT broker connection
- Check MQTT discovery topics:
homeassistant/+/heatingpump/# - Ensure HA MQTT integration discovery is enabled
- Wait 15 minutes for auto-republish or manually trigger:
mosquitto_pub -h BROKER -u USER -P PASS -t "heatingpump/republish_discoveries" -m ""
- Some signals may not be supported by your heat pump model
- Check signal polling frequency (may need to wait for next poll)
- Verify signal name exists in
ElsterTable.h - Check logs for parse errors or invalid values
- Verify
payloadOnandpayloadOffare set in ElsterTable.h:{ "SIGNAL_NAME", 0x0074, et_bool, "Name", "binary_sensor", "lock", "", "", "mdi:icon", "on", "off", false, true }
- Verify
input_datetimehelpers exist in HA - Check text_sensor entity IDs in
common.yamlmatch helper names - Press buttons after setting helpers (changes don't auto-sync)
- Discovery:
homeassistant/{component}/heatingpump/{unique_id}/config - State:
heatingpump/{CAN_MEMBER}/{SIGNAL_NAME}/state - Command:
heatingpump/command/{signal_name}/set - Availability:
heatingpump/status
From ElsterTable.h:
et_dec_val: Decimal value (0.1 precision)et_cent_val: Centesimal value (0.01 precision)et_mil_val: Millisimal value (0.001 precision)et_bool: Boolean (true/false → on/off)et_little_bool: Inverted booleanet_byte: Single byte valueet_double_val: Two-byte valueet_triple_val: Three-byte value
Write temperature setpoint:
mosquitto_pub -h BROKER -u USER -P PASS -t "heatingpump/command/speichersolltemp/set" -m "55"Change operating mode:
mosquitto_pub -h BROKER -u USER -P PASS -t "heatingpump/command/programmschalter/set" -m "Automatik"- heatingpump.yaml: Main entry point with board selection (comment/uncomment blocks)
- board_esp32s3.yaml: ESP32-S3 configuration (16MB flash, OPI PSRAM, 80MHz)
- board_esp32s2.yaml: ESP32-S2/generic ESP32 configuration
- can_esp32.yaml: Built-in TWAI CAN controller (256 RX queue, 64 TX queue)
- can_mcp2515.yaml: MCP2515 SPI-based CAN controller
- common.yaml: Board-agnostic core (WiFi, MQTT, API, OTA, buttons, text sensors)
- wpl13e.yaml: Device-specific template sensors (22 essential sensors)
- ha-stiebel-control.h: Main C++ implementation (MQTT discovery, calculated sensors, CAN write)
- signal_requests_wpl13e.h: Polling schedule (defines which signals to read and how often)
- config.h: Blacklist configuration
- ElsterTable.h: 3800+ signal definitions with Home Assistant metadata
- KElsterTable.cpp/h: Helper functions for table lookups and value conversions
Pull requests are welcome! For major changes, please open an issue first to discuss what you would like to change.
Areas for contribution:
- Support for additional heat pump models
- Dashboard examples
- Energy monitoring integrations
- Documentation improvements
- Signal metadata enhancements
- Jürg Müller: Original Elster protocol implementation and signal table
- roberreiters: Home Assistant community ESPHome CAN bus setup
- Bastian Stahmer: Original ha-stiebel-control implementation
- ESPHome & Home Assistant Communities: Continuous support and inspiration
This project is not affiliated with or endorsed by Stiebel Eltron. Use at your own risk. Modifying your heat pump settings via CAN bus may void your warranty. Always consult your heat pump manual and follow local regulations.