Easy UART Parsing ESPHome Component

ESPHome UART External Component

An external component for ESPHome that allows easy parsing of UART data, enabling users to extract relevant information and efficiently build custom components.

Usage Example

Below is an example YAML configuration:

uart:
  baud_rate: 9600
  data_bits: 8
  parity: NONE
  stop_bits: 1
  rx_pin: GPIO22
  tx_pin: GPIO19

external_components:
  - source: github://eigger/espcomponents/releases/latest
    components: [ uartex ]
    refresh: always

uartex:
  rx_timeout: 10ms
  tx_delay: 50ms
  tx_timeout: 500ms
  tx_retry_cnt: 3

  rx_header: [0x02, 0x01]
  rx_footer: [0x0D, 0x0A]
  tx_header: [0x02, 0x01]
  tx_footer: [0x0D, 0x0A]

  rx_checksum: add
  tx_checksum: add

  version:
    disabled: False
  error:
    disabled: False
  log:
    disabled: False

#packet on) 0x02 0x01 0x02 0x03 0x01 (add)checksum 0x0D 0x0A
#   offset) head head 0    1    2
#packet off) 0x02 0x01 0x02 0x03 0x00 (add)checksum 0x0D 0x0A

binary_sensor:
  - platform: uartex
    name: Binary_Sensor1
    state: [0x02, 0x03]
    state_on:
      offset: 2
      data: [0x01]
    state_off:
      offset: 2
      data: [0x00]

#packet on) 0x02 0x01 0x02 0x03 0x01 (add)checksum 0x0D 0x0A
#   offset) head head 0    1    2
#packet on ack) 0x02 0x01 0x02 0x13 0x01 (add)checksum 0x0D 0x0A
#packet off) 0x02 0x01 0x02 0x03 0x00 (add)checksum 0x0D 0x0A
#packet off ack) 0x02 0x01 0x02 0x03 0x00 (add)checksum 0x0D 0x0A

switch:
  - platform: uartex
    name: "Switch1"
    state: 
      data: [0x02, 0x03]
      mask: [0xff, 0x0f]
    state_on:
      offset: 2
      data: [0x01]
    state_off:
      offset: 2
      data: [0x00]
    command_on:
      data: [0x02, 0x03, 0x01]
      ack: [0x02, 0x13, 0x01]
    command_off: !lambda |-
      return {{0x02, 0x03, 0x00}, {0x02, 0x13, 0x00}};

Detailed Example

For more detailed examples,

3 Likes

Can this be used to replace a ‘Custom’ component based UART Text Sensor:

- platform: custom
  lambda: |-
    auto my_custom_sensor = new UartReadLineSensor(id(uart_bus));
    App.register_component(my_custom_sensor);
    return {my_custom_sensor};

  text_sensors:
    id: uart_readline
    name: "Detected"
    on_value:
      - lambda: if (x == "name1") id(timer1).execute(); if (x == "name2") id(timer2).execute();

If so, could you please help me to understand how to convert my now depreciated UartReadLineSensor into your Custom Sensor?

I’m sorry but someone helped me set this up years ago and until the latest ESPHome update I have never had to make any changes to this setup.


I’m sort of assuming all I need to use from the detailed examples link is:

text_sensor:
  - platform: uartex
    name: "Text Sensor"
    state: [0x02, 0x03]

But, would the value (x) still be applicable in this:

    on_value:
      - lambda: if (x == "name1") id(timer1).execute(); if (x == "name2") id(timer2).execute();

You can try like this.

text_sensor:
  - platform: uartex
    name: "Text Sensor"
    state: "name"
    lambda: |-
      if (data[4] == '1') id(timer1).execute();
      if (data[4] == '2') id(timer2).execute();
      return "OK";

or


text_sensor:
  - platform: uartex
    name: "Text Sensor"
    state: "name1"
    lambda: |-
      id(timer1).execute();
      return "name1 OK";
  - platform: uartex
    name: "Text Sensor"
    state: "name2"
    lambda: |-
      id(timer2).execute();
      return "name2 OK";

Any examples with a number: or sensor: component? I really could have used this on my pellet stove project. I had to do it the hard way…

If you specify the exact packet you want, I can provide more examples. Below, I’ve created an example based on my estimation. Let me know if there are any additional packets you’d like to include.

uartex:
  rx_timeout: 10ms
  tx_delay: 50ms
  tx_timeout: 500ms
  tx_retry_cnt: 3

  rx_header: [0xAA]
  rx_footer: [0xCC, 0x33]
  tx_header: [0xAA]
  tx_footer: [0xCC, 0x33]

  version:
    disabled: False
  error:
    disabled: False
  log:
    disabled: False

#0xAA 0x01 0x48 0x80 0xCC 0x33
sensor:
  - platform: uartex
    name: ECO Value
    state: [0x01, 0x48]
    state_number:
      offset: 2
      length: 1
      precision: 0

Fascinating. Nice work. When I get around to updating my code on these pellet stoves I’ll be sure to test this out! Having this before would have literally saved me days of head banging. Obviously I got there in the end but it’s not pretty.

Yeah, ESPHome is great, but parsing UART isn’t easy without external components. Let me know if you run into any issues during testing.

1 Like

Hey, nice looking components.
I have this config, but I doesn’t work.
Have you any hints.


# RS-232 Übertragungsprotokoll
# Verbindungskabel
# Der Computer wird über das RS-232-Verbindungskabel mit dem ZEWA Wasserstop
# verbunden.
# Schnittstellenparameter
# Bits pro Sekunde: 9600
# Datenbits: 8
# Parität: keine
# Stoppbits: 1
# Verbindungsaufbau
# - ZEWA wartet auf Kennung von Computer
# - Computer sendet Kennungsbyte AAh
# - Computer sendet Aktionsbyte "01h" (Abruf Betriebsdaten)
# Reaktion von ZEWA
# Der ZEWA antwortet auf das Aktionsbyte bzw. führt Befehl aus:
# Aktionsbyte "01h" (Abruf Betriebsdaten)
# Nachdem das Aktionsbyte 01h an den ZEWA gesendet wurde, sendet der ZEWA
# folgende Bytes an den Computer zurück:
# 1. Byte Kennung EEh
# 2. Byte Anzahl der Datenbytes inkl. Checksummenbyte
# 3. Byte Statusbyte 0
# Bit0 Kugelventil 0 – offen 1 – geschlossen
# Bit1 Wassermenge 0 – keine Überschreitung 1 – Überschreitung
# Bit2 Durchfluss 0 – keine Überschreitung 1 – Überschreitung
# Bit3 Entnahmedauer 0 – keine Überschreitung 1 – Überschreitung
# Bit4 Urlaubsmodus 0 – nicht aktiv 1 – aktiv
# Bit5 Standby-Modus 0 – nicht aktiv 1 – aktiv
# Bit6 Störung 0 – keine Störung 1 – Störung
# Bit7 KV-Motor 0 – ausgeschaltet 1 – eingeschaltet
# Seite 3 von 5 1701936 · 2014/084. Byte Statusbyte 1
# Bit0 Spannungsvers. 0 – Netzversorgung 1 – Batterieversorgung
# Bit1 Batteriezustand 0 – Batterie i. O. 1 – Batterie leer
# Bit2 Datenverbindung 0 – Datenverbindung i. O. 1 – keine Datenverbindung
# Bit3 Leckagesensor 0 – keine Abschaltung 1 – Abschaltung
# Bit4 ext. I/O 0 – kein Eingangssignal 1 – Eingangssignal
# Bit5 Rel 1 ext. auf /zu 0 – KV geöffnet 1 – KV geschlossen
# Bit6 Rel 2 Störung 0 – Störung, keine Span. 1 – Betrieb
# Bit7 Rel 3 100 L Imp. 0 – kein Impuls 1 – Impuls nach 100 l
# 5. Byte Batteriespannung (in Volt) = Byte5 * 0.07906
# 6. Byte Ausgangspannung des Notstrommoduls (in Volt)= Byte6 * 0.1556
# 7. Byte gespeicherte Abschaltungen Wassermenge Einstellung1
# 8. Byte gespeicherte Abschaltungen Wassermenge Einstellung2
# 9. Byte gespeicherte Abschaltungen Wassermenge Einstellung3
# 10. Byte gespeicherte Abschaltungen Wassermenge Einstellung4
# 11. Byte gespeicherte Abschaltungen Wassermenge Einstellung5
# 12. Byte gespeicherte Abschaltungen Wassermenge Einstellung6
# 13. Byte gespeicherte Abschaltungen Durchfluss Einstellung1
# 14. Byte gespeicherte Abschaltungen Durchfluss Einstellung2
# 15. Byte gespeicherte Abschaltungen Durchfluss Einstellung3
# 16. Byte gespeicherte Abschaltungen Durchfluss Einstellung4
# 17. Byte gespeicherte Abschaltungen Durchfluss Einstellung5
# 18. Byte gespeicherte Abschaltungen Durchfluss Einstellung6
# 19. Byte gespeicherte Abschaltungen Entnahmezeit Einstellung1
# 20. Byte gespeicherte Abschaltungen Entnahmezeit Einstellung2
# 21. Byte gespeicherte Abschaltungen Entnahmezeit Einstellung3
# 22. Byte gespeicherte Abschaltungen Entnahmezeit Einstellung4
# 23. Byte gespeicherte Abschaltungen Entnahmezeit Einstellung5
# 24. Byte gespeicherte Abschaltungen Entnahmezeit Einstellung6
# 25 Byte Anzahl Abschaltungen im Urlaubsmodus
# 26. Byte Anzahl der Abschaltungen durch Leckagesensor
# 27. Byte Anzahl Störmeldungen Fehler2 (Motor oder Nockenschalter defekt)
# 28. Byte Anzahl Störmeldungen Fehler3 (Verbindungsfehler Notstrom-ZEWA)
# 29. u. 30. Byte aktuelle Einstellung Grenzwert max. Wassermenge [l]
# 31. u. 32. Byte aktuelle Einstellung Grenzwert max. Durchfluss [l/h]
# 33. u. 34. Byte aktuelle Einstellung Grenzwert max. Entnahmezeit [0,5 s]
# 35. u. 36. Byte aktueller Messwert Wassermenge
# 37. u. 38. Byte aktueller Messwert Durchfluss
# 39. u. 40. Byte aktueller Messwert Entnahmezeit
# 41., 42., 43. u. 44. Byte Gesamtwassermenge:
# = (Byte41 + Byte42 * 256 + Byte43 * 2562 + Byte44 * 2563) * 100 Liter
# 45. bis 47. Byte interne Verwendung
# 48. Byte Checksumme

# Aktionsbyte "02h" (Befehl Öffnen / Schließen)
# Nachdem das Aktionsbyte 02h vom Computer an den ZEWA gesendet wurde, antwortet
# der ZEWA mit:
# 1. Byte Kennung EEh
# 2. Byte Quittierung 99h
# Anschließend führt der ZEWA den Befehl zum Öffnen / Schließen aus.
# Berechnung der Checksumme:
# Summe von Byte2 bis Byte47. Das niederwertige Byte der Summe ist die Check
esphome:
  name: esp32-wasserstopgateway
  friendly_name: ESP32-WasserStopGateway

esp32:
  board: esp32dev
  framework:
    type: arduino

logger:
  level: VERBOSE
  baud_rate: 0
  logs:
    display: NONE

api:
  encryption:
    key:="

ota:
  - platform: esphome
    password: ""

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password
  manual_ip:
    static_ip: 192.168.178.111
    gateway: 192.168.178.1
    subnet: 255.255.255.0
  ap:
    ssid: "Wasserstopgateway"
    password: "hEArICVbDKss"

captive_portal:

web_server:
  port: 80

uart:
  id: uart_bus
  tx_pin: GPIO17        # Adjust as needed!
  rx_pin: GPIO16
  baud_rate: 9600
  data_bits: 8
  parity: NONE
  stop_bits: 1

external_components:
  - source: github://eigger/espcomponents/releases/latest
    components: [ uartex ]
    refresh: always

uartex:
  id: zewa_uartex
  uart_id: uart_bus
  rx_timeout: 10ms
  tx_delay: 50ms
  tx_timeout: 500ms
  tx_retry_cnt: 3
  rx_header: [0xEE]
  rx_footer: []
  tx_header: [0xAA]
  tx_footer: []
  rx_checksum: add
  tx_checksum: add

#################################################################
# Binary Sensors – Statusbits from Statusbyte 0 (Byte 2, i.e. data[1])
#################################################################
binary_sensor:
  - platform: uartex
    name: "Kugelventil"
    state:
      data: [0x02]        # Read Statusbyte 0
      mask: [0x01]        # Bit0: 0 = Offen, 1 = Geschlossen
    state_on:
      offset: 0
      data: [0x01]
    state_off:
      offset: 0
      data: [0x00]

  - platform: uartex
    name: "Wassermenge Überschreitung"
    state:
      data: [0x02]
      mask: [0x02]        # Bit1: 1 = Überschreitung
    state_on:
      offset: 0
      data: [0x02]
    state_off:
      offset: 0
      data: [0x00]

  - platform: uartex
    name: "Durchfluss Überschreitung"
    state:
      data: [0x02]
      mask: [0x04]        # Bit2: 1 = Überschreitung
    state_on:
      offset: 0
      data: [0x04]
    state_off:
      offset: 0
      data: [0x00]

  - platform: uartex
    name: "Entnahmedauer Überschreitung"
    state:
      data: [0x02]
      mask: [0x08]        # Bit3: 1 = Überschreitung
    state_on:
      offset: 0
      data: [0x08]
    state_off:
      offset: 0
      data: [0x00]

  - platform: uartex
    name: "Urlaubsmodus aktiv"
    state:
      data: [0x02]
      mask: [0x10]        # Bit4: 1 = Aktiv
    state_on:
      offset: 0
      data: [0x10]
    state_off:
      offset: 0
      data: [0x00]

  - platform: uartex
    name: "Standby aktiv"
    state:
      data: [0x02]
      mask: [0x20]        # Bit5: 1 = Aktiv
    state_on:
      offset: 0
      data: [0x20]
    state_off:
      offset: 0
      data: [0x00]

  - platform: uartex
    name: "Störung"
    state:
      data: [0x02]
      mask: [0x40]        # Bit6: 1 = Störung
    state_on:
      offset: 0
      data: [0x40]
    state_off:
      offset: 0
      data: [0x00]

  - platform: uartex
    name: "KV-Motor"
    state:
      data: [0x02]
      mask: [0x80]        # Bit7: 1 = Ein, 0 = Aus
    state_on:
      offset: 0
      data: [0x80]
    state_off:
      offset: 0
      data: [0x00]

#################################################################
# Binary Sensors – Statusbits from Statusbyte 1 (Byte 3, i.e. data[2])
#################################################################
  - platform: uartex
    name: "Spannungsversorgung Batteriebetrieb"
    state:
      data: [0x03]        # Read Statusbyte 1
      mask: [0x01]        # Bit0: 1 = Batterieversorgung, 0 = Netz
    state_on:
      offset: 0
      data: [0x01]
    state_off:
      offset: 0
      data: [0x00]

  - platform: uartex
    name: "Batteriezustand leer"
    state:
      data: [0x03]
      mask: [0x02]        # Bit1: 1 = Leer, 0 = OK
    state_on:
      offset: 0
      data: [0x02]
    state_off:
      offset: 0
      data: [0x00]

  - platform: uartex
    name: "Datenverbindung Fehler"
    state:
      data: [0x03]
      mask: [0x04]        # Bit2: 1 = Fehler, 0 = OK
    state_on:
      offset: 0
      data: [0x04]
    state_off:
      offset: 0
      data: [0x00]

  - platform: uartex
    name: "Leckagesensor Abschaltung"
    state:
      data: [0x03]
      mask: [0x08]        # Bit3: 1 = Abschaltung, 0 = OK
    state_on:
      offset: 0
      data: [0x08]
    state_off:
      offset: 0
      data: [0x00]

  - platform: uartex
    name: "Externer I/O Signal"
    state:
      data: [0x03]
      mask: [0x10]        # Bit4: 1 = Signal, 0 = Kein Signal
    state_on:
      offset: 0
      data: [0x10]
    state_off:
      offset: 0
      data: [0x00]

  - platform: uartex
    name: "Relais 1 geschlossen"
    state:
      data: [0x03]
      mask: [0x20]        # Bit5: 1 = Geschlossen
    state_on:
      offset: 0
      data: [0x20]
    state_off:
      offset: 0
      data: [0x00]

  - platform: uartex
    name: "Relais 2 Betrieb"
    state:
      data: [0x03]
      mask: [0x40]        # Bit6: 1 = Betrieb, 0 = Störung
    state_on:
      offset: 0
      data: [0x40]
    state_off:
      offset: 0
      data: [0x00]

  - platform: uartex
    name: "Relais 3 Impuls"
    state:
      data: [0x03]
      mask: [0x80]        # Bit7: 1 = Impuls, 0 = Kein Impuls
    state_on:
      offset: 0
      data: [0x80]
    state_off:
      offset: 0
      data: [0x00]

#################################################################
# Numeric Sensors – Measurements and Counters
#################################################################
sensor:
  # Batteriespannung (Byte 5 * 0,07906 V)
  - platform: uartex
    name: "Batteriespannung (Messwert)"
    unit_of_measurement: "V"
    state:
      data: [0x05]
    lambda: |-
      return data[4] * 0.07906;
      
  # Notstrom-Spannung (Byte 6 * 0,1556 V)
  - platform: uartex
    name: "Notstrom-Spannung (Messwert)"
    unit_of_measurement: "V"
    state:
      data: [0x06]
    lambda: |-
      return data[5] * 0.1556;
      
  # Urlaubsmodus Abschaltungen (Byte 28 -> data[27])
  - platform: uartex
    name: "Urlaubsmodus Abschaltungen"
    unit_of_measurement: "count"
    state:
      data: [0x1C]
    state_number:
      offset: 27
      length: 1
      precision: 0
      
  # Fehlermeldungen Fehler2 (Byte 29 -> data[28])
  - platform: uartex
    name: "Fehlermeldungen Fehler2"
    unit_of_measurement: "count"
    state:
      data: [0x1D]
    state_number:
      offset: 28
      length: 1
      precision: 0
      
  # Fehlermeldungen Fehler3 (Byte 30 -> data[29])
  - platform: uartex
    name: "Fehlermeldungen Fehler3"
    unit_of_measurement: "count"
    state:
      data: [0x1E]
    state_number:
      offset: 29
      length: 1
      precision: 0
      
  # Grenzwert max. Wassermenge (Bytes 31-32 -> data[30] and data[31])
  - platform: uartex
    name: "Grenzwert max. Wassermenge"
    unit_of_measurement: "L"
    state:
      data: [0x1F, 0x20]
    state_number:
      offset: 30
      length: 2
      precision: 0
      
  # Grenzwert max. Durchfluss (Bytes 33-34 -> data[32] and data[33])
  - platform: uartex
    name: "Grenzwert max. Durchfluss"
    unit_of_measurement: "L/h"
    state:
      data: [0x21, 0x22]
    state_number:
      offset: 32
      length: 2
      precision: 0
      
  # Grenzwert max. Entnahmezeit (Bytes 35-36 -> data[34] and data[35]), umgerechnet: * 0,5 s
  - platform: uartex
    name: "Grenzwert max. Entnahmezeit"
    unit_of_measurement: "s"
    state:
      data: [0x23, 0x24]
    lambda: |-
      return ( (data[34] + (data[35] << 8)) * 0.5 );
      
  # Aktuelle Wassermenge (Bytes 37-38 -> data[36] and data[37])
  - platform: uartex
    name: "Aktuelle Wassermenge"
    unit_of_measurement: "L"
    state:
      data: [0x25, 0x26]
    state_number:
      offset: 36
      length: 2
      precision: 0
      
  # Aktueller Durchfluss (Bytes 39-40 -> data[38] and data[39])
  - platform: uartex
    name: "Aktueller Durchfluss"
    unit_of_measurement: "L/h"
    state:
      data: [0x27, 0x28]
    state_number:
      offset: 38
      length: 2
      precision: 0
      
  # Aktuelle Entnahmezeit (Bytes 41-42 -> data[40] and data[41]), umgerechnet: * 0,5 s
  - platform: uartex
    name: "Aktuelle Entnahmezeit"
    unit_of_measurement: "s"
    state:
      data: [0x29, 0x2A]
    lambda: |-
      return ( (data[40] + (data[41] << 8)) * 0.5 );
      
  # Gesamtwassermenge (Bytes 43-46 -> data[42] to data[45]), umgerechnet in Liter (Multipliziert mit 100)
  - platform: uartex
    name: "Gesamtwassermenge"
    unit_of_measurement: "L"
    state:
      data: [0x2B, 0x2C, 0x2D, 0x2E]
    lambda: |-
      return (data[42] + (data[43] << 8) + (data[44] << 16) + (data[45] << 24)) * 100;
      
  # Totaler Wasserverbrauch (in m³) unter Berücksichtigung eines Offsets (Bytes 43-46 -> data[42] to data[45])
  - platform: uartex
    name: "Totaler Wasserverbrauch"
    unit_of_measurement: "m³"
    state:
      data: [0x2B, 0x2C, 0x2D, 0x2E]
    lambda: |-
      float measured_total = (data[42] + (data[43] << 8) + (data[44] << 16) + (data[45] << 24)) / 1000.0;
      return measured_total + id(total_water_consumption_offset).state;
      
  # Globaler Offset für den Totalen Wasserverbrauch
  - platform: template
    name: "Totaler Wasserverbrauch Offset"
    id: total_water_consumption_offset
    unit_of_measurement: "m³"
    accuracy_decimals: 2
    lambda: |-
      return 0.0;

interval:
  - interval: 1s
    then:
      - uart.write: [0xAA, 0x01]

time:
  - platform: sntp
    id: sntp_time
    timezone: Europe/Berlin
    servers:
      - 0.pool.ntp.org
      - 1.pool.ntp.org
      - 2.pool.ntp.org

font:
  - file: "gfonts://Roboto"
    id: font_small
    size: 10

i2c:
  scan: true
  id: bus_a


If you provide me with the full packet information, I will create an example for you.

Thank you:
The big comment block describes the rs-232.
Here is the official documentation:
Judo Zewa RS-232

Is this enough?

Okay, I will check the document.

1 Like

I have attached a few examples. Would you like to test them?

uartex:
  rx_timeout: 10ms
  tx_delay: 50ms
  tx_timeout: 500ms
  tx_retry_cnt: 3
  rx_header: [0xEE]
  tx_header: [0xAA]
  # The add checksum option includes the header.
  # So I redefined it using a lambda.
  rx_checksum: !lambda |-
    uint8_t crc = 0;
    for (int i = 0; i < len; i++)
    {
      crc += data[i];
    }
    return crc;

#################################################################
# Binary Sensors – Statusbits from Statusbyte 0 (Byte 2, i.e. data[1])
#################################################################


#Offset starts from 0, excluding the header.
#packet 0xEE 0x00 0x00 0x00 0x00 ...
#offset         0    1    2    3
binary_sensor:
  - platform: uartex
    name: "Kugelventil"
    state:
      data: [0x00]        # Read All
      mask: [0x00]
    state_on:
      offset: 1
      data: [0x01]
      mask: [0x01]        # Bit0: 0 = Offen, 1 = Geschlossen
    state_off:
      offset: 1
      data: [0x00]
      mask: [0x01]        # Bit0: 0 = Offen, 1 = Geschlossen

    update_interval: 1s
    # The header is automatically included."
    # Does the sent data not include a checksum or an end character?
    # 0xAA 0x01
    command_update:
      data: [0x01]

  - platform: uartex
    name: "Wassermenge Überschreitung"
    state:
      data: [0x00]        # Read All
      mask: [0x00]
    state_on:
      offset: 1
      data: [0x02]
      mask: [0x02]        # Bit1: 1 = Überschreitung
    state_off:
      offset: 1
      data: [0x00]
      mask: [0x02]        # Bit1: 1 = Überschreitung


#################################################################
# Binary Sensors – Statusbits from Statusbyte 1 (Byte 3, i.e. data[2])
#################################################################
  - platform: uartex
    name: "Spannungsversorgung Batteriebetrieb"
    state:
      data: [0x00]        # Read All
      mask: [0x00]
    state_on:
      offset: 2
      data: [0x01]
      mask: [0x01]        # Bit0: 1 = Batterieversorgung, 0 = Netz
    state_off:
      offset: 2
      data: [0x00]
      mask: [0x01]        # Bit0: 1 = Batterieversorgung, 0 = Netz


#################################################################
# Numeric Sensors – Measurements and Counters
#################################################################
sensor:
  # Batteriespannung (Byte 5 * 0,07906 V)
  - platform: uartex
    name: "Batteriespannung (Messwert)"
    unit_of_measurement: "V"
    state:
      data: [0x00]        # Read All
      mask: [0x00]
    lambda: |-
      return data[3] * 0.07906;
 
  # Urlaubsmodus Abschaltungen
  - platform: uartex
    name: "Urlaubsmodus Abschaltungen"
    unit_of_measurement: "count"
    state:
      data: [0x00]        # Read All
      mask: [0x00]
    state_number:
      offset: 24
      length: 1
      precision: 0
 

Thank you. I will test it.

i have tested it with the Batteriespannung sensor: HA says unknown e.g. no value. The log from esp32 says

[21:02:27][W][uartex:318]: [Read] Size error: EE(1)

a workin esp8266 sketch as standalone app
My Board: ESP32-Wroom-32, i will try a esp8266 tomorrow
My yaml:

# RS-232 Übertragungsprotokoll
# Verbindungskabel
# Der Computer wird über das RS-232-Verbindungskabel mit dem ZEWA Wasserstop
# verbunden.
# Schnittstellenparameter
# Bits pro Sekunde: 9600
# Datenbits: 8
# Parität: keine
# Stoppbits: 1
# Verbindungsaufbau
# - ZEWA wartet auf Kennung von Computer
# - Computer sendet Kennungsbyte AAh
# - Computer sendet Aktionsbyte "01h" (Abruf Betriebsdaten)
# Reaktion von ZEWA
# Der ZEWA antwortet auf das Aktionsbyte bzw. führt Befehl aus:
# Aktionsbyte "01h" (Abruf Betriebsdaten)
# Nachdem das Aktionsbyte 01h an den ZEWA gesendet wurde, sendet der ZEWA
# folgende Bytes an den Computer zurück:
# 1. Byte Kennung EEh
# 2. Byte Anzahl der Datenbytes inkl. Checksummenbyte
# 3. Byte Statusbyte 0
# Bit0 Kugelventil 0 – offen 1 – geschlossen
# Bit1 Wassermenge 0 – keine Überschreitung 1 – Überschreitung
# Bit2 Durchfluss 0 – keine Überschreitung 1 – Überschreitung
# Bit3 Entnahmedauer 0 – keine Überschreitung 1 – Überschreitung
# Bit4 Urlaubsmodus 0 – nicht aktiv 1 – aktiv
# Bit5 Standby-Modus 0 – nicht aktiv 1 – aktiv
# Bit6 Störung 0 – keine Störung 1 – Störung
# Bit7 KV-Motor 0 – ausgeschaltet 1 – eingeschaltet
# Seite 3 von 5 1701936 · 2014/084. Byte Statusbyte 1
# Bit0 Spannungsvers. 0 – Netzversorgung 1 – Batterieversorgung
# Bit1 Batteriezustand 0 – Batterie i. O. 1 – Batterie leer
# Bit2 Datenverbindung 0 – Datenverbindung i. O. 1 – keine Datenverbindung
# Bit3 Leckagesensor 0 – keine Abschaltung 1 – Abschaltung
# Bit4 ext. I/O 0 – kein Eingangssignal 1 – Eingangssignal
# Bit5 Rel 1 ext. auf /zu 0 – KV geöffnet 1 – KV geschlossen
# Bit6 Rel 2 Störung 0 – Störung, keine Span. 1 – Betrieb
# Bit7 Rel 3 100 L Imp. 0 – kein Impuls 1 – Impuls nach 100 l
# 5. Byte Batteriespannung (in Volt) = Byte5 * 0.07906
# 6. Byte Ausgangspannung des Notstrommoduls (in Volt)= Byte6 * 0.1556
# 7. Byte gespeicherte Abschaltungen Wassermenge Einstellung1
# 8. Byte gespeicherte Abschaltungen Wassermenge Einstellung2
# 9. Byte gespeicherte Abschaltungen Wassermenge Einstellung3
# 10. Byte gespeicherte Abschaltungen Wassermenge Einstellung4
# 11. Byte gespeicherte Abschaltungen Wassermenge Einstellung5
# 12. Byte gespeicherte Abschaltungen Wassermenge Einstellung6
# 13. Byte gespeicherte Abschaltungen Durchfluss Einstellung1
# 14. Byte gespeicherte Abschaltungen Durchfluss Einstellung2
# 15. Byte gespeicherte Abschaltungen Durchfluss Einstellung3
# 16. Byte gespeicherte Abschaltungen Durchfluss Einstellung4
# 17. Byte gespeicherte Abschaltungen Durchfluss Einstellung5
# 18. Byte gespeicherte Abschaltungen Durchfluss Einstellung6
# 19. Byte gespeicherte Abschaltungen Entnahmezeit Einstellung1
# 20. Byte gespeicherte Abschaltungen Entnahmezeit Einstellung2
# 21. Byte gespeicherte Abschaltungen Entnahmezeit Einstellung3
# 22. Byte gespeicherte Abschaltungen Entnahmezeit Einstellung4
# 23. Byte gespeicherte Abschaltungen Entnahmezeit Einstellung5
# 24. Byte gespeicherte Abschaltungen Entnahmezeit Einstellung6
# 25 Byte Anzahl Abschaltungen im Urlaubsmodus
# 26. Byte Anzahl der Abschaltungen durch Leckagesensor
# 27. Byte Anzahl Störmeldungen Fehler2 (Motor oder Nockenschalter defekt)
# 28. Byte Anzahl Störmeldungen Fehler3 (Verbindungsfehler Notstrom-ZEWA)
# 29. u. 30. Byte aktuelle Einstellung Grenzwert max. Wassermenge [l]
# 31. u. 32. Byte aktuelle Einstellung Grenzwert max. Durchfluss [l/h]
# 33. u. 34. Byte aktuelle Einstellung Grenzwert max. Entnahmezeit [0,5 s]
# 35. u. 36. Byte aktueller Messwert Wassermenge
# 37. u. 38. Byte aktueller Messwert Durchfluss
# 39. u. 40. Byte aktueller Messwert Entnahmezeit
# 41., 42., 43. u. 44. Byte Gesamtwassermenge:
# = (Byte41 + Byte42 * 256 + Byte43 * 2562 + Byte44 * 2563) * 100 Liter
# 45. bis 47. Byte interne Verwendung
# 48. Byte Checksumme

# Aktionsbyte "02h" (Befehl Öffnen / Schließen)
# Nachdem das Aktionsbyte 02h vom Computer an den ZEWA gesendet wurde, antwortet
# der ZEWA mit:
# 1. Byte Kennung EEh
# 2. Byte Quittierung 99h
# Anschließend führt der ZEWA den Befehl zum Öffnen / Schließen aus.
# Berechnung der Checksumme:
# Summe von Byte2 bis Byte47. Das niederwertige Byte der Summe ist die Check
esphome:
  name: esp32-wasserstopgateway
  friendly_name: ESP32-WasserStopGateway

esp32:
  board: esp32dev
  framework:
    type: arduino

logger:
  level: DEBUG
  baud_rate: 0
  logs:
    display: NONE

api:
  encryption:
    key: "="

ota:
  - platform: esphome
    password: ""

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password
  manual_ip:
    static_ip: 192.168.178.111
    gateway: 192.168.178.1
    subnet: 255.255.255.0
  ap:
    ssid: "Wasserstopgateway"
    password: "hEArICVbDKss"

captive_portal:

web_server:
  port: 80

uart:
  id: uart_bus
  tx_pin: GPIO17        # Adjust as needed!
  rx_pin: GPIO16
  baud_rate: 9600
  data_bits: 8
  parity: NONE
  stop_bits: 1

external_components:
  - source: github://eigger/espcomponents/releases/latest
    components: [ uartex ]
    refresh: always

uartex:
  rx_timeout: 30ms
  tx_delay: 50ms
  tx_timeout: 500ms
  tx_retry_cnt: 3
  rx_header: [0xEE]
  tx_header: [0xAA]
  # The add checksum option includes the header.
  # So I redefined it using a lambda.
  rx_checksum: !lambda |-
    uint8_t crc = 0;
    for (int i = 0; i < len; i++)
    {
      crc += data[i];
    }
    return crc;



#################################################################
# Numeric Sensors – Measurements and Counters
#################################################################
sensor:

  # Batteriespannung (Byte 5 * 0,07906 V)
  - platform: uartex
    name: "Batteriespannung (Messwert)"
    unit_of_measurement: "V"
    state:
      data: [0x00]        # Read All
      mask: [0x00]
    lambda: |-
      return data[3] * 0.07906;

interval:
  - interval: 1s
    then:
      - uart.write: [0xAA, 0x01]

time:
  - platform: sntp
    id: sntp_time
    timezone: Europe/Berlin
    servers:
      - 0.pool.ntp.org
      - 1.pool.ntp.org
      - 2.pool.ntp.org

font:
  - file: "gfonts://Roboto"
    id: font_small
    size: 10

i2c:
  scan: true
  id: bus_a

Could you check the UART logs by adding the debug option?
I want to check whether the data is not being received or not being parsed.

uart:
  id: uart_bus
  tx_pin: GPIO17        # Adjust as needed!
  rx_pin: GPIO16
  baud_rate: 9600
  data_bits: 8
  parity: NONE
  stop_bits: 1
  debug:

or edit logger

logger:
  level: DEBUG
  #baud_rate: 0
  #logs:
  #  display: NONE

Here is a Log Snippet, i revice the Data.

[08:47:51][D][uart_debug:114]: >>> AA:01
[08:47:51][W][uartex:318]: [Read] Size error: EE(1)
[08:47:51][W][component:237]: Component uartex took a long time for an operation (60 ms).
[08:47:51][W][component:238]: Components should block for at most 30 ms.
[08:47:51][D][uart_debug:114]: <<< EE:2E:00:40:DE:DE:00:0A:00:00:00:00:00:00:03:00:00:00:00:00:00:04:00:00:02:00:00:00:E8:03:D0:07:10:0E:00:00:00:00:00:00:E4:13:00:00:00:00:00:14

Try testing it without the checksum for now. I will review the checksum method

uartex:
  rx_timeout: 50ms
  tx_delay: 50ms
  tx_timeout: 500ms
  tx_retry_cnt: 3
  rx_header: [0xEE]
  tx_header: [0xAA]
  # The add checksum option includes the header.
  # So I redefined it using a lambda.
  #rx_checksum: !lambda |-
  # uint8_t crc = 0;
  # for (int i = 0; i < len; i++)
  # {
  #    crc += data[i];
  #  }
  # return crc;

now i have the first Value :slight_smile: it reported 18V, it is possible to change it to 18,00 V?

Now i will test one other Sensor:

EDIT:
It was a one time success. -.-

can you like to test it again? I don’t quite understand your situation.
size error doesn’t seem to be related to the checksum.
I tried modifying another part.

uartex:
  rx_timeout: 100ms
  tx_delay: 50ms
  tx_timeout: 500ms
  tx_retry_cnt: 3
  rx_header: [0xEE]
  rx_checksum: !lambda |-
    uint8_t crc = 0;
    for (int i = 0; i < len; i++)
    {
      crc += data[i];
    }
    return crc;

interval:
  - interval: 1s
    then:
      - uartex.write: [0xAA, 0x01]

logger:
  level: DEBUG

Sure. Now i get a Value.

I have tried

binary_sensor:
  - platform: uartex
    name: "Kugelventil"
    state:
      data: [0x00]        # Read All
      mask: [0x00]
    state_on:
      offset: 1
      data: [0x01]
      mask: [0x01]        # Bit0: 0 = Offen, 1 = Geschlossen
    state_off:
      offset: 1
      data: [0x00]
      mask: [0x01]        # Bit0: 0 = Offen, 1 = Geschlossen

this code. Here i have a value, too. But it says false (Aus) but i think it should be true, because i know i can use the Water in my House :smiley:
I dont understand the data and mask thing and how i chose the right position in the data array in the lambda