Może komuś się przyda. Projekt nie jest dokończony. Można włączyć/wyłączyć piec, zmienić mode level/automatic. Nie wiem czemu dane które są odczytywane ze sterownika to jakaś porażka. Albo ten piec tak ma albo coś źle skonfigurowane mam w esphome. Dane są poprostu nieprawdziwe. Niemniej jednak w połączeniu z HA da się to ogarnąć.
Oto kod:
substitutions:
heater_mac: "3C:AB:72:79:77:07"
service_uuid: "0000FFE0-0000-1000-8000-00805F9B34FB"
characteristic_uuid: "0000FFE1-0000-1000-8000-00805F9B34FB"
esphome:
name: vevor
friendly_name: Vevor
on_boot:
priority: -10
then:
- delay: 1s
- ble_client.connect: heater_ble
- delay: 800ms
# pierwszy poll po połączeniu
- ble_client.ble_write:
service_uuid: ${service_uuid}
characteristic_uuid: ${characteristic_uuid}
value: [0xAA, 0x55, 0x0C, 0x22, 0x01, 0x00, 0x00, 0x2F]
esp32:
board: esp32dev
framework:
type: esp-idf
logger:
level: DEBUG
improv_serial:
api:
encryption:
key: "xxxxxxxxxxxxxxxxxxxxxxxxxxx"
ota:
- platform: esphome
password: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
web_server:
port: 80
version: 3
wifi:
networks:
- ssid: !secret wifi_ssid
password: !secret wifi_password
- ssid: "xxxxxxxxxxxxx"
password: !secret wifi_password
ap:
ssid: "VevorBLE Hotspot"
password: "12345678"
captive_portal:
esp32_ble_tracker:
ble_client:
- mac_address: ${heater_mac}
id: heater_ble
on_connect:
then:
- logger.log: "BLE connected – sending poll"
- delay: 400ms
- ble_client.ble_write:
service_uuid: ${service_uuid}
characteristic_uuid: ${characteristic_uuid}
value: [0xAA, 0x55, 0x0C, 0x22, 0x01, 0x00, 0x00, 0x2F]
on_disconnect:
then:
- delay: 2s
- ble_client.connect: heater_ble
# cykliczny poll
interval:
- interval: 10s
then:
- ble_client.ble_write:
service_uuid: ${service_uuid}
characteristic_uuid: ${characteristic_uuid}
value: [0xAA, 0x55, 0x0C, 0x22, 0x01, 0x00, 0x00, 0x2F]
globals:
- id: current_mode
type: int
initial_value: '1'
text_sensor:
- platform: template
name: "Glow Plug Status"
id: Glow_Plug_Status
- platform: template
name: "Heater Mode"
id: Mode_Burner
binary_sensor:
- platform: template
name: "Heater Status"
id: Burner_Status
device_class: power
sensor:
- platform: uptime
name: Uptime
- platform: template
name: "Error Code"
id: Error_Code
accuracy_decimals: 0
- platform: template
name: "Battery Voltage"
id: battery_voltage
unit_of_measurement: "V"
accuracy_decimals: 1
device_class: voltage
icon: "mdi:car-battery"
- platform: template
name: "Altitude"
id: altitude
unit_of_measurement: "m"
accuracy_decimals: 0
icon: "mdi:summit"
- platform: template
name: "Power Level"
id: stato_Potenza
- platform: template
name: "Fan Speed"
id: fan_speed
icon: "mdi:fan"
- platform: template
name: "Room Temperature"
id: room_temperature
unit_of_measurement: "°C"
- platform: template
name: "Heating Temperature"
id: heating_temperature
unit_of_measurement: "°C"
# BLE NOTIFY parser – DA i AA55
- platform: ble_client
type: characteristic
id: my_ble_sensor
ble_client_id: heater_ble
service_uuid: ${service_uuid}
characteristic_uuid: ${characteristic_uuid}
name: "BLE Raw Data"
notify: true
lambda: |-
ESP_LOGD("BLE","RX(%d): %s", x.size(), format_hex_pretty(x).c_str());
// DA format (Twoje nowsze ramki)
if (x.size() >= 20 && (uint8_t)x[0] == 0xDA) {
id(Mode_Burner).publish_state(((uint8_t)x[12]) == 0x02 ? "Automatic" : "Level");
// NIE publikujemy Burner_Status z DA – eliminujemy "odbijanie"
id(fan_speed).publish_state((int)((uint8_t)x[10]));
id(room_temperature).publish_state((int)((uint8_t)x[16]));
id(heating_temperature).publish_state((int)((uint8_t)x[14]));
id(battery_voltage).publish_state(((uint8_t)x[11]) / 10.0f);
id(Error_Code).publish_state(0);
id(altitude).publish_state(0);
id(Glow_Plug_Status).publish_state("Unknown");
return 0;
}
// AA 55 format (legacy – tu kiedyś działało poprawnie)
if (x.size() >= 20 && (uint8_t)x[0] == 0xAA) {
static const char* const states[] = {"Warmup","Self test running","Ignition","Heating","Shutting down"};
id(heating_temperature).publish_state((int16_t)(((uint8_t)x[14])<<8)|((uint8_t)x[13]));
id(Mode_Burner).publish_state(x[8] == 2 ? "Automatic" : "Level");
// Tu wolno publikować Burner_Status (sprawdzone kiedyś)
id(Burner_Status).publish_state(x[3] > 0);
if (x[5] < (sizeof(states)/sizeof(states[0]))) {
id(Glow_Plug_Status).publish_state(states[x[5]]);
}
id(stato_Potenza).publish_state(x[9]);
id(Error_Code).publish_state(x[17]);
id(altitude).publish_state(((x[7])<<8)|x[6]);
id(room_temperature).publish_state((int16_t)(((uint8_t)x[16])<<8)|((uint8_t)x[15]));
id(battery_voltage).publish_state((((x[12])<<8)|x[11])/10.0);
if (id(Glow_Plug_Status).state == "Warmup" && id(Burner_Status).state == 0) {
id(fan_speed).publish_state(0);
} else {
id(fan_speed).publish_state(x[10] + 1);
}
return 0;
}
return 0;
switch:
- platform: template
name: "Heater Power"
id: heater_power
icon: "mdi:radiator"
optimistic: true
turn_on_action:
- logger.log: "Power ON (FFE1)"
# komenda ON dokładnie jak wcześniej
- ble_client.ble_write:
service_uuid: ${service_uuid}
characteristic_uuid: ${characteristic_uuid}
value: [0xAA, 0x55, 0x0C, 0x22, 0x03, 0x01, 0x00, 0x32]
# Lokalnie ustawiamy stan na ON, żeby UI nie odbijało
- lambda: |-
id(Burner_Status).publish_state(true);
# Opóźnij poll o 2 s, by nie nadpisać stanu natychmiast po ON
- delay: 2s
- ble_client.ble_write:
service_uuid: ${service_uuid}
characteristic_uuid: ${characteristic_uuid}
value: [0xAA, 0x55, 0x0C, 0x22, 0x01, 0x00, 0x00, 0x2F]
turn_off_action:
- logger.log: "Power OFF (FFE1)"
- ble_client.ble_write:
service_uuid: ${service_uuid}
characteristic_uuid: ${characteristic_uuid}
value: [0xAA, 0x55, 0x0C, 0x22, 0x03, 0x00, 0x00, 0x31]
# Lokalnie OFF
- lambda: |-
id(Burner_Status).publish_state(false);
lambda: |-
return id(Burner_Status).state;
select:
- platform: template
name: "Heater Mode"
id: heater_mode
options:
- "Level"
- "Automatic"
initial_option: "Level"
optimistic: true
on_value:
then:
- if:
condition:
lambda: |-
return id(heater_mode).state == "Level";
then:
- lambda: |-
id(current_mode) = 1;
- ble_client.ble_write:
service_uuid: ${service_uuid}
characteristic_uuid: ${characteristic_uuid}
value: [0xAA, 0x55, 0x0C, 0x22, 0x02, 0x01, 0x00, 0x31]
else:
- lambda: |-
id(current_mode) = 2;
- ble_client.ble_write:
service_uuid: ${service_uuid}
characteristic_uuid: ${characteristic_uuid}
value: [0xAA, 0x55, 0x0C, 0x22, 0x02, 0x02, 0x00, 0x32]
number:
- platform: template
name: "Heater Temperature"
id: heater_temperature
min_value: 8
max_value: 36
step: 1
unit_of_measurement: "°C"
optimistic: true
set_action:
then:
# tryb auto, potem temperatura
- ble_client.ble_write:
service_uuid: ${service_uuid}
characteristic_uuid: ${characteristic_uuid}
value: [0xAA, 0x55, 0x0C, 0x22, 0x02, 0x02, 0x00, 0x32]
- delay: 1s
- ble_client.ble_write:
service_uuid: ${service_uuid}
characteristic_uuid: ${characteristic_uuid}
value: !lambda |-
uint8_t t = (uint8_t) id(heater_temperature).state;
uint16_t sum = 0xAA + 0x55 + 0x0C + 0x22 + 0x04 + t + 0x00;
uint8_t checksum = (sum + 1) & 0xFF;
return std::vector<uint8_t>{0xAA, 0x55, 0x0C, 0x22, 0x04, t, 0x00, checksum};
- platform: template
name: "Heater Level"
id: heater_level
min_value: 0
max_value: 10
step: 1
unit_of_measurement: "Level"
optimistic: true
set_action:
then:
# tryb level, potem poziom
- ble_client.ble_write:
service_uuid: ${service_uuid}
characteristic_uuid: ${characteristic_uuid}
value: [0xAA, 0x55, 0x0C, 0x22, 0x02, 0x01, 0x00, 0x31]
- delay: 1s
- ble_client.ble_write:
service_uuid: ${service_uuid}
characteristic_uuid: ${characteristic_uuid}
value: !lambda |-
uint8_t lvl = (uint8_t) id(heater_level).state;
uint16_t sum = 0xAA + 0x55 + 0x0C + 0x22 + 0x04 + lvl + 0x00;
uint8_t checksum = (sum + 1) & 0xFF;
return std::vector<uint8_t>{0xAA, 0x55, 0x0C, 0x22, 0x04, lvl, 0x00, checksum};
Testowane na sterowniku za zdjęcia
Źródło: https://github.com/espnomad/ESPHome-BLE-Dieselheater/blob/main/dieselheater-ble.yaml
Może ktoś to dopracuje ![]()

