Configured my ESPHome with MCP2515 CAN-Bus for Stiebel Eltron heating pump

so here is the initialization sequence.
I guess mostly the initialization address is relevant here (idx 00fe) and the traffic from / to CAN-Address 301 - which is the FEK in my case.
If you send from can_id 0x301, I guess you are registered at the respective device.

[18:55:39][D][canbus:070]: received can message (#1) std can_id=0x301 size=7
[18:55:39][I][main:1544]: Antwort von 301 Hex: 36 0 fe 1 0 0 0
[18:55:39][I][main:1545]: Antwort von 301 Float: 0.000000
[18:55:40][I][main:1546]: Antwort von 301 Dez.: 0 0
[18:55:40][I][main:1547]: Antwort klein von 301 Float: 256.000000
[18:55:40][I][main:1548]: Antwort klein von 301 Dez.: 1 0
[18:55:40][D][canbus:070]: received can message (#2) std can_id=0x301 size=7
[18:55:40][I][main:1544]: Antwort von 301 Hex: c6 1 fe 1 0 0 0
[18:55:40][I][main:1545]: Antwort von 301 Float: 0.000000
[18:55:40][I][main:1546]: Antwort von 301 Dez.: 0 0
[18:55:40][I][main:1547]: Antwort klein von 301 Float: 256.000000
[18:55:40][I][main:1548]: Antwort klein von 301 Dez.: 1 0
[18:55:40][D][canbus:070]: received can message (#3) std can_id=0x301 size=7
[18:55:40][I][main:1544]: Antwort von 301 Hex: 31 0 b 0 0 0 0
[18:55:40][I][main:1545]: Antwort von 301 Float: 0.000000
[18:55:40][I][main:1546]: Antwort von 301 Dez.: 0 0
[18:55:40][I][main:1547]: Antwort klein von 301 Float: 0.000000
[18:55:40][I][main:1548]: Antwort klein von 301 Dez.: 0 0

But be careful with this.
The FEK controls a lot of things, like heat curve, room temperatures etc. And you may loose the possibility to set the comfort / eco-settings for the heater on your heat pump, while you register as an FEK.

If it doesn’t work, you may have to power cycle your heat pump to get back into normal mode.

here is the complete log-file

Init Log

@roberreiter
Thank you for the logs. I played a bit around but just changing the can id to 301 and react on the 0xfe call from 0x601 to 0x301 does not seam to be enough to emulate a fek.
I guess it need some deeper research that is hard to to whout having the fek connected and analyse the complete traffic over longer time :frowning:

I´ve got problems with pulling can messages to ESPHome.

I tried to send following data to ESPHome:
h_idx: 0a06 (hotwater heater adjust)
h_val: 0260
h_addr: 3000 (write)

After that I´ve pushed “CAN command send”-button at ESPHome-device.
Hotwater-heater adjustment value won´t change, otherwise changing this value working well with text_input-sensor so problem must be in script that sending data to ESPHome.

esphome1

Script configuration/data:
esphome2

ESPHome-device config:

  services:
    - service: pull_canmsg
      variables:
        idx: int
        addr: int
        val: int
      then:
        - lambda: |-
            int getA = static_cast<int>(addr); //Adresse in Byte 0 u. 1 schreiben
            id(sh_state)[0]=getA>>8;
            id(sh_state)[1]=getA-((getA>>8)<<8);

            getA = static_cast<int>(idx); //Elster-Index Ăźbernehmen
            //Wenn Elster-Index <= 0xff => an Byte-Stelle 2 schreiben
            if( (getA>>8) == 0x00) {
              id(sh_state)[2]=getA-((getA>>8)<<8);

              getA = static_cast<int>(val); //Datenwert Ăźbernehmen und an Stelle 3 u. 4 schreiben, 5 u. 6 ist 0x00
              id(sh_state)[3]=getA>>8;
              id(sh_state)[4]=getA-((getA>>8)<<8);
              id(sh_state)[5]=0x00;
              id(sh_state)[6]=0x00;
            }
            else {
              //Wenn Elster-Index > 0xff kommt 0xfa an Stelle 2, der Index steht dann an Stelle 3 u. 4
              id(sh_state)[2]=0xfa;
              id(sh_state)[3]=getA>>8;
              id(sh_state)[4]=getA-((getA>>8)<<8);

              getA = static_cast<int>(val); //der Datenwert steht dann an Stelle 5 u. 6
              id(sh_state)[5]=getA>>8;
              id(sh_state)[6]=getA-((getA>>8)<<8);
            }

Do you have any suggestions what could be wrong?

I think and hope I can help you.

In my implementation I have three buttons:
image

  1. transmit the CAN message to the ESP-home device
    This button is created to link to a home assistant script:
sequence:
  - service: esphome.esp_sensor_node_hzg_pull_canmsg
    data:
      idx: "{{ states(\"input_text.h_idx\")|int(base=16) }}"
      addr: "{{ states(\"input_text.h_addr\")|int(base=16) }}"
      val: "{{ states(\"input_text.h_val\")|int(base=16) }}"
mode: queued
icon: mdi:play
max: 5
alias: CAN Nachricht an ESP-Home Ăźbertragen

This is only for data transfer from home assistant to ESP and I found no other solution to do it than this.
Home assistant calculates integer values from the hex-values for ESP.
The ESP-device then pulls the integer values, calculates the corresponding hex-values for the CAN-message according to the directive of http://juerg5524.ch/ in the config-sequence you posted and writes it into internal variables.
Nothing is transmitted over CAN here!

  1. show message / Sensorupdate
    This is a button is created by the ESP-home device. If you followed my ESP-yaml, this button has the id “can_befehl_anzeigen”.
    You may have to let it show up in the home assistant lovely interface.
  • Stored CAN-messages are sent to update various sensors.
  • The message that was manually set in home assistant is showed in the log-output of the ESP-device
  • The manually set CAN-message will not be transmitted to the CAN-network
  1. transmit CAN-message
    This is a button created by the ESP-home device. If you followed my ESP-yaml, this button has the id “can_send”
    You may have to let it show up in the home assistant lovely interface.
  • The CAN-message that was set in home-assistant (after pushing button 1) will be sent to the CAN-network.

Your screenshots show only one button - “send to esphome”.
I think you missed to press button 2 or 3
I just updated my readme in the GIT-store to clarify.

Hi!

I pressed both buttons, now also added “send CAN-message” and “request CAN-message”-buttons (translated) to Lovelace-interface.

message

Log output when sending this to ESPHome+heatpump, value not change.

[07:47:24][D][button:010]: 'Send CAN-message' Pressed.
[07:47:24][D][canbus:033]: send standard id=0x680 rtr=FALSE size=7

And for comparison log-output for same elster-index with “input_text.ww_komfort_temp” that successfully changing hotwater reservoir adjust value :

[07:49:04][D][homeassistant.text_sensor:017]: 'input_text.ww_komfort_temp': Got state '480'
[07:49:04][D][text_sensor:064]: 'ww_komfort_temp': Sending state '480'
[07:49:04][D][binary_sensor:036]: 'update_sensor': Sending state ON
[07:49:04][D][canbus:033]: send standard id=0x680 rtr=FALSE size=7
[07:49:04][D][binary_sensor:036]: 'update_sensor': Sending state OFF

With higher logger-level “VERY_VERBOSE” I was able to see sended CAN-messages and HEX values were different.

Manually writed values+sending ESPHome+heatpump (not changing value in pump):

[09:32:59][D][button:010]: 'Send CAN-message' Pressed.
[09:32:59][D][canbus:033]: send standard id=0x680 rtr=FALSE size=7
[09:32:59][VV][canbus:044]:   data[0]=30
[09:32:59][VV][canbus:044]:   data[1]=00
[09:32:59][VV][canbus:044]:   data[2]=13
[09:32:59][VV][canbus:044]:   data[3]=02
[09:32:59][VV][canbus:044]:   data[4]=60
[09:32:59][VV][canbus:044]:   data[5]=00
[09:32:59][VV][canbus:044]:   data[6]=00

Values sent by text_input_ww_komfort_temp (succesfully change value in pump):

[09:41:17][D][text_sensor:064]: 'ww_komfort_temp': Sending state '260'
[09:41:17][D][binary_sensor:036]: 'update_sensor': Sending state ON
[09:41:17][D][canbus:033]: send standard id=0x680 rtr=FALSE size=7
[09:41:17][VV][canbus:044]:   data[0]=30
[09:41:17][VV][canbus:044]:   data[1]=00
[09:41:17][VV][canbus:044]:   data[2]=13
[09:41:17][VV][canbus:044]:   data[3]=01
[09:41:17][VV][canbus:044]:   data[4]=04
[09:41:17][VV][canbus:044]:   data[5]=00
[09:41:17][VV][canbus:044]:   data[6]=00

I don’t see any problem here.
I tried the same CAN message in my send command input fields and the temperature is changed. The update should be shown up immeadiatly on the heat pump. The comfort temperature status in home assistant is updated every 10 minutes (by default setting) and can be manually updated by sending the CAN message 31 00 13 00 00 00

The only thing noteable is, that there is a limit for max / min temperature in the text_input sensors for comfort and eco temperature. But I think this is not the question?

image
image
image
image

Now I figured it out what was the problem:

I assumed that h_val-parameter was 0260 → 26.0c etc.

0260-value was too high and that was reason why not heatpump doesn´t accept command.

Getting it work with testing different values:
h_val 0118 → 28.0c
h_val 0120 → 28.8c
h_val 0200 → 51.2c
etc.

Time to test more parameters and read log, thank you so much for help :slightly_smiling_face:
My goals are at this time to:
-change heating curve and adjust heating circuit temperature
-read heating circuit buffer asking/realtime temperature
-getting hotgas-temp and system pressures

h_val has to be the hex value 260 → 608 → 60,8

	from:  0x180; Elster Index: 0x07a5; et_dec_val; Niederdruck
        from:  0x180; Elster Index: 0x0268; et_dec_val; Hochdruck
        from:  0x180; Elster Index: 0x01d5; et_dec_val; PUFFERSOLL
        from:  0x180; Elster Index: 0x06a2; et_dec_val; WPVORLAUFIST
      //from:  0x180; Elster Index: 0x01d6; et_dec_val; WPVORLAUFIST
        from:  0x180; Elster Index: 0x0016; et_dec_val; RUECKLAUFISTTEMP
        from:  0x180; Elster Index: 0x0c,   et_dec_val; Außentemperatur
        from:  0x180; Elster Index: 0x0265; et_dec_val; Heissgas
        from:  0x601; Elster Index: 0x010e; et_cent_val; Heizkurve
        from:  0x601; Elster Index: 0x4ea7; et_dec_val; Minimaltemperatur
        from:  0x601; Elster Index: 0x05,   et_dec_val; Komforttemperatur
        from:  0x601; Elster Index: 0x08,   et_dec_val; Eco_Temperatur
        from:  0x601; Elster Index: 0xfdb4; et_little_endian; Sommerbetrieb

From my WPM3i maybe it helps you :slight_smile:

Thank you for help, everything now running perfectly and I can change heating circuit temperatures with Home Assistant.

Only values that I was unable to find is source pressure and heating curve adjust.
Elster-table index 0x010e (HEIZKURVE) gives only values that won´t change when adjusting curve from pump control panel. Source pressure I haven´t find in elster-table at all.

[00:37:10][D][button:010]: 'Send CAN-message' Pressed.
[00:37:10][D][canbus:033]: send standard id=0x680 rtr=FALSE size=7
[00:37:10][D][canbus:070]: received can message (#1) std can_id=0x180 size=7
[00:37:10][I][main:1675]: Antwort von 180 Hex: d2 0 fa 1 e 0 0
[00:37:10][I][main:1676]: Antwort von 180 Float: 0.000000
[00:37:10][I][main:1677]: Antwort von 180 Dez.: 0 0
[00:37:10][I][main:1678]: Antwort klein von 180 Float: 270.000000
[00:37:10][I][main:1679]: Antwort klein von 180 Dez.: 1 14

I created also text_input for heating circuit to adjust comfort/eco temperature:

#Lämmitystavoitteen säätÜ mukavuuskäyttÜ
  - platform: homeassistant
    name: "adjust_comfort_temp"
    entity_id: input_text.komfort_temp
    id: adjust_comfort
    filters:
     - lambda: |-
          int eingabe=atoi(x.c_str());
          if (eingabe < 160 or eingabe > 250) {
            //Value error, reading only data from heatpump 
            id(send_state)[0]=id(PumpCANread_id)[0];
            id(send_state)[1]=id(PumpCANread_id)[1];
            id(send_state)[2]=0x05;
            id(send_state)[3]=0x00;
            id(send_state)[4]=0x00;
            id(send_state)[5]=0x00;
            id(send_state)[6]=0x00;
            return x;


          } else {
            //Success, sending data to heatpump
            id(send_state)[0]=id(PumpCANwrite_id)[0];
            id(send_state)[1]=id(PumpCANwrite_id)[1];
            id(send_state)[2]=0x05;
            id(send_state)[3]=eingabe>>8;
            id(send_state)[4]=eingabe-((eingabe>>8)<<8);
            id(send_state)[5]=0x00;
            id(send_state)[6]=0x00;
            return x;
            
          }
    on_value:
          then:
            - lambda: |-
                //Daten senden
                id(update_sensor).publish_state(true);
                id(update_sensor).publish_state(false);

#Lämmitystavoitteen säätÜ eco
  - platform: homeassistant
    name: "adjust_eco_temp"
    entity_id: input_text.eco_temp
    id: adjust_eco
    filters:
     - lambda: |-
          int eingabe=atoi(x.c_str());
          if (eingabe < 160 or eingabe > 250) {
            //Value error, reading only data from heatpump 
            id(send_state)[0]=id(PumpCANread_id)[0];
            id(send_state)[1]=id(PumpCANread_id)[1];
            id(send_state)[2]=0x08;
            id(send_state)[3]=0x00;
            id(send_state)[4]=0x00;
            id(send_state)[5]=0x00;
            id(send_state)[6]=0x00;
            return x;


          } else {
            //Success, sending data to heatpump
            id(send_state)[0]=id(PumpCANwrite_id)[0];
            id(send_state)[1]=id(PumpCANwrite_id)[1];
            id(send_state)[2]=0x08;
            id(send_state)[3]=eingabe>>8;
            id(send_state)[4]=eingabe-((eingabe>>8)<<8);
            id(send_state)[5]=0x00;
            id(send_state)[6]=0x00;
            return x;
            
          }
    on_value:
          then:
            - lambda: |-
                //Daten senden
                id(update_sensor).publish_state(true);
                id(update_sensor).publish_state(false);

Hi everyone,
I’m posting to this topic since it seems to be nearest to my problem. Here’s the deal:
I recently added the FES Comfort display to my Stiebel Eltron LWZ 5 CS Premium to measure the real room temperature and humidity aswell as enabling active cooling, but since I didn’t have any cabling for the bus line I opted for two CAN-bus Wifi gateways which transmit the canbus frames over TCP.
Upon experimenting with HA (I am still fairly new to HA) I tried to read the data from the heat pump. Therefore I used the tcpsensor integration to gather the CAN frames sent between the FES Comfort and the heat pump. I succeeded in gathering the data, but the problem is that there is no interpretation of the can frames.
I tried analyzing the frames manually and comparing them to the ElsterTable.inc, however I can’t make any sense of the ID’s aswell as the data.

Here’s my config (read only between display and controller at this stage):

  - platform: tcpsensor
    name: "Heatpump"
    host: 192.168.178.201
    port: 8881
    payload: "\n"
    payload_is_hex: true
    value_template: "{{ value }}" 

Giving me the whole canbus frames:

For example: 0x 07 80 01 00 00 d2 1f fa 00 0c 00 d7 00

Is there a way to extract the physical values from the frame? As far as I can tell the length is 7 bytes, the ID is 0x8001 and the data is 0xd21ffa000c00d7.

Regards,
Max

d2 1f fa 00 0c 00 d7 00 is the part from the heat pump.
0x 07 80 01 00 00 has nothing to do with the stiebel eltron bus.
Its something your gateways add…
The ID 0x8001 is also not from Stiebel bus.
Reciver of this message is: 69f what is the the FES is guess.
Its an answer from a request to 0x180 from the FES.
Elster-index: 0x0c waht is on my device the outside temperature.
The Value is 215 divided by 10 → 21,5°C
So read the messages should be possible for you with this knowledge.
For sending you have to test what your gateway is accepting…

1 Like

Based on the work of @roberreiter, i have modified my set up over the last months significantly which makes it more maintainable and manageble for me. I was tired of having to deal with Bitshifting and handling CAN-IDs as well as converting units. Thus, i re-used parts of Rob’s code and combined it with the Elstertable Tools of Jürg Müller.

You find the project including instructions how to set it up on GitHub under the GPLv3 license.

However there are still some ToDos open:

  • Add friendly_names to the entities so this doesn’t have to be done in the frontend
  • Add a nice send message option to the GUI and ESPHome for fiddeling around
  • HW Setup instructions
  • Beautify the Log Output even more

Feel free to take a look and contribute. @roberreiter - maybe it makes sense to join forces :slight_smile:

2 Likes

Congrats Bastian, your code looks really great.
I was wondering if you plan to use english language for the friendly_names you plan to add :smile:

Also, I was checking if you collect the errors describes in the ElterTable.h file. The type of field et_err_nr could be used on specific codes to gather errors and a friendly name could be looked up with the ErrorList array.

What do you think?
Thanks sharing your hard work.

PS: Your dash looks amazing.

Hi Tatu,

I’m also looking for the source pressure but also the pressure on the heating circuit with no luck so far.
If you found it in the meantime, please let me know.
At last, I also would like to retrieve error message when they appear.

Kind regards

Hi pestouille

I have no luck with finding source pressure and heating curve values.
Heating circuit pressure in my pump founds:

  - platform: template
    name: "Lämmityspaine"
    id: heat_pressure
    unit_of_measurement: "bar"
    icon: "mdi:gauge"
    device_class: "pressure"
    state_class: "measurement"
    accuracy_decimals: 2
    lambda: |-
      id(send_state)[0]=id(PumpCANread_id)[0];id(send_state)[1]=id(PumpCANread_id)[1];id(send_state)[2]=0xfa;id(send_state)[3]=0x06;id(send_state)[4]=0x74;id(send_state)[5]=0x00;id(send_state)[6]=0x00;
      id(update_sensor).publish_state(true);
      id(update_sensor).publish_state(false);
      return {};
    update_interval: 7min
#Lämmityspaine (bar)
        - lambda: |-
            if(x[0]==id(internalResponse_id)[0] and x[1]==id(internalResponse_id)[1] and x[2]==0xfa and x[3]==0x06 and x[4]==0x74) {
              float pressure =(float((int16_t((x[6])+( (x[5])<<8))))/100);
              id(heat_pressure).publish_state(pressure);
              ESP_LOGD("main", "bar Heating circuit pressure over can is %f", pressure);
            }

I just came across this thread a few weeks ago. Apparently there are some things that Steibel could do better, but maybe not want to, but you find other ways. After reading through the posts and writing on github with @bullitt186. I noticed that not much has been shared about changing values on the can bus.

First of all about my system and my problem. We have a WPM13 (WPM3 controller) with ISGWeb and FEK installed for the cooling function. Unfortunately, the installer has mounted the FEK only afterwards and also in the wrong place (in the dry warm boiler room). The FEK could of course be positioned in a better place, but the problem that the FEK can only monitor one room remains. Since we have a controller (KNX) in each room, my idea was to calculate a kind of average value and pass it on to the heat pump. Of course, Steibel does not allow this. Both for the KNX and via the Modbus interface of the ISG. After a few phone calls with the technical support, they recommended Stiebel’s own newer system with its own room controllers and valve controllers.

In addition, the control of the cooling function is just weird and does not make sense in my opinion. Cooling is activated when a mean outdoor temperature value is exceeded? The room temperature has no influence. Thus, the cooling is deactivated during cold nights, even if the house heats up during the day.

About my solution. Since I noticed that the bus is completely unmonitored. The idea was a MITM “attack” between WPM13 and FEK. So I put a board together and after some programming work, both sides do not know that I adjust room temperature and humidity. I can also adjust the outdoor temperature through a digtal potentiometer. The values I can send the board via TCP modbus or serial interface.

Interesting is that the values are not sent via the way known from the first posts, where the bytes 4 and 5 that indicate which value it is. The FEK sends a can message with CAN-ID 0x602 where the data ID is coded over the 2nd byte. 0x17 is room temperature and 0x117 room humidity. The value itself is coded as Int16 via bytes 3 and 4. Bytes 5 and 6 are 0.

Since the concept works, I’m currently working on designing a custom PCB with ESP32, POE and a few safety features like fallback relays that can be neatly mounted to the heat pump. The code is also getting improved. It will all be published on Github.

Sounds interesting.
Looking forward to complely emulate the FEK after understanding the communication :smiley:

That should be doable. I have found that the startup is important for both WPM3 and FEK. I have also programmed logging for both sides, so you can reverse engineer the communication completely. Also, the FEK just seems to send everything at regular intervals. I can also upload to Github, but would first look to take the ISG out of the communication to simplify it.

looking forward to analyze the can trace.