Hello everyone🙂
I’m new here and trying to help others with this topic. Even better would be if someone had a good solution for the last few values I need.
I’ve just connected a CAN bus component SN65HVD230 to my Attack SLX Lambda Touch 45 kW wood-fired boiler using an ESP32-S3.
First, I found the correct settings in Arduino and Python and read the CAN bus information. Using this information and the display data, I started reverse engineering and tried to understand how multiplexing works.
I then partially figured out which byte contains which data information in hexadecimal representation.
First, I found out which byte contains which data information in hexadecimal representation. After that, I followed the configuration in Home Assistant to obtain entities and create small automations:
(CAN Bus - ESPHome - Smart Home Made Simple )
I’ve had some difficulties with this device – perhaps this will help someone else and allow us, with a bit of luck, to figure out the latest data.
Currently, I can only read values from the CAN bus, but not all of them.
Can I share my current configuration here in the chat?
SmakBraker008:
canbus:
platform: esp32_can
tx_pin: GPIO17
rx_pin: GPIO18
can_id: 100
bit_rate: 100kbps
on_frame:
can_id: 0x72
then:
lambda: |-
if (x.size() < 8) return;
int block = x[0];
if (block == 0x01) {
uint16_t pair1 = (uint16_t)((x[2] << 8) | x[1]);
if (pair1 == 0) {
float p2_raw = (float)((x[4] << 8) | x[3]);
id(kessel_raw_median).publish_state(p2_raw);
}
else {
float v1 = (float)pair1 / 10.0;
float v2 = (float)((x[4] << 8) | x[3]) / 10.0;
float v3 = (float)((x[6] << 8) | x[5]) / 10.0;
if (v3 > 10.0 && v3 < 100.0) {
id(abgas_temp).publish_state(v2);
id(kessel_temp).publish_state(v1);
id(puffer_mitte).publish_state(v3);
}
else if (v3 > 6000.0 && v1 > 1.0 && v2 < 150.0) {
id(puffer_unten).publish_state(v1);
id(heizkoerper_temp).publish_state(v2);
}
}
}
can_id: 0x73
then:
lambda: |-
if (x.size() < 8) return;
int block = x[0];
if (block == 0x01) {
id(saugzug_fan).publish_state((float)x[5] / 2.55);
// Status Logik inkl. Gluthaltung
int b3 = x[3];
if (b3 == 0x18) {
id(kessel_status).publish_state("Gluthaltung");
} else if ((b3 & 0x08) == 0x08) {
id(kessel_status).publish_state("Heizen");
} else if (b3 == 0x00) {
id(kessel_status).publish_state("Standby");
} else {
id(kessel_status).publish_state("Aktiv");
}
}
if (block == 0x03) {
id(bin_fuellen).publish_state(x[1] == 0x64);
id(bin_mangel).publish_state(x[1] == 0x32);
id(bin_reinigung).publish_state(x[3] == 0x01);
}
sensor:
platform: template
name: “Kessel Rohwert Median”
id: kessel_raw_median
accuracy_decimals: 0
unit_of_measurement: “raw”
filters:
median: { window_size: 10, send_every: 10 }
throttle: 5s
on_value:
then:
lambda: |-
float raw = x;
float o2 = 0;
// — BEREICH 1: 0 (13,84%) bis 63000 —
if (raw <= 63000) {
if (raw <= 19) o2 = 13.84 + (raw - 0) * (13.6 - 13.84) / (19 - 0);
else if (raw <= 134) o2 = 13.6 + (raw - 19) * (12.9 - 13.6) / (134 - 19);
else if (raw <= 379) o2 = 12.9 + (raw - 134) * (11.6 - 12.9) / (379 - 134);
else if (raw <= 583) o2 = 11.6 + (raw - 379) * (10.4 - 11.6) / (583 - 379);
else if (raw <= 750) o2 = 10.4 + (raw - 583) * (9.6 - 10.4) / (750 - 583);
else if (raw <= 860) o2 = 9.6 + (raw - 750) * (9.0 - 9.6) / (860 - 750);
else if (raw <= 888) o2 = 9.0 + (raw - 860) * (8.9 - 9.0) / (888 - 860);
else if (raw <= 1254) o2 = 8.9 + (raw - 888) * (7.2 - 8.9) / (1254 - 888);
else if (raw <= 1300) o2 = 7.2 + (raw - 1254) * (7.0 - 7.2) / (1300 - 1254);
else if (raw <= 1321) o2 = 7.0 + (raw - 1300) * (6.9 - 7.0) / (1321 - 1300);
else if (raw <= 1348) o2 = 6.9 + (raw - 1321) * (6.8 - 6.9) / (1348 - 1321);
else if (raw <= 1409) o2 = 6.8 + (raw - 1348) * (6.6 - 6.8) / (1409 - 1348);
else if (raw <= 1451) o2 = 6.6 + (raw - 1409) * (6.5 - 6.6) / (1451 - 1409);
else if (raw <= 1525) o2 = 6.5 + (raw - 1451) * (6.2 - 6.5) / (1525 - 1451);
else if (raw <= 1596) o2 = 6.2 + (raw - 1525) * (6.0 - 6.2) / (1596 - 1525);
else if (raw <= 1643) o2 = 6.0 + (raw - 1596) * (5.8 - 6.0) / (1643 - 1596);
else if (raw <= 1760) o2 = 5.8 + (raw - 1643) * (5.5 - 5.8) / (1760 - 1643);
else if (raw <= 3000) o2 = 5.5 + (raw - 1760) * (2.6 - 5.5) / (3000 - 1760);
else o2 = 2.6 + (raw - 3000) * (1.2 - 2.6) / (62536 - 3000);
}
// — BEREICH 2: 64800 bis 65535 (13,85%) —
else if (raw >= 64800) {
if (raw <= 65189) o2 = 20.8 + (raw - 64800) * (16.4 - 20.8) / (65189 - 64800);
else if (raw <= 65238) o2 = 16.4 + (raw - 65189) * (16.0 - 16.4) / (65238 - 65189);
else if (raw <= 65323) o2 = 16.0 + (raw - 65238) * (15.3 - 16.0) / (65323 - 65238);
else if (raw <= 65394) o2 = 15.3 + (raw - 65323) * (14.9 - 15.3) / (65394 - 65323);
else if (raw <= 65449) o2 = 14.9 + (raw - 65394) * (14.3 - 14.9) / (65449 - 65394);
else o2 = 14.3 + (raw - 65449) * (13.85 - 14.3) / (65535 - 65449);
}
id(kessel_o2_wert).publish_state(o2);
platform: template
name: “Kessel Sauerstoffwert”
id: kessel_o2_wert
unit_of_measurement: “%”
accuracy_decimals: 1
icon: “mdi:gas-cylinder”
filters: [throttle: 5s, round: 1, clamp: {min_value: 0.0, max_value: 21.0}]
platform: template
name: “Kessel Temperatur”
id: kessel_temp
unit_of_measurement: “°C”
platform: template
name: “Abgas Temperatur”
id: abgas_temp
unit_of_measurement: “°C”
platform: template
name: “Heizkörper Temperatur”
id: heizkoerper_temp
unit_of_measurement: “°C”
platform: template
name: “Puffer Mitte”
id: puffer_mitte
unit_of_measurement: “°C”
platform: template
name: “Puffer Unten”
id: puffer_unten
unit_of_measurement: “°C”
platform: template
name: “Saugzug Gebläse”
id: saugzug_fan
unit_of_measurement: “%”
text_sensor:
platform: template
name: “Kessel Status”
id: kessel_status
binary_sensor:
platform: template
name: “Status Brennstoffmangel”
id: bin_mangel
filters:
platform: template
name: “Status Tür offen”
id: bin_fuellen
filters:
platform: template
name: “Status Reinigung”
id: bin_reinigung
filters: