Licznik wody Apator na ESPHome

Mam licznik wody Apatora i nałożyłem nakładkę mierzącą Apatora. Za pomocą AI wygenerowałem kod na ESP Home, niestety stan licznika odbiega od rzeczywistego stanu wodomierz. AI generowało mi kilkukrotnie kod, ale cały czas licznik nie nadarza za wodomierzem albo wyprzeda wodomierz.

Załączam kod w który licznik wyprzedza wodomierz narastająco:

globals:
  - id: faktyczny_stan_wodomierza
    type: double
    restore_value: true
    initial_value: '0.0'

number:
  - platform: template
    name: "Korekta stanu licznika wody"
    id: korekta_wodomierza
    icon: "mdi:water-sync"
    unit_of_measurement: "m³"
    min_value: 0
    max_value: 999999
    step: 0.001
    mode: BOX
    set_action:
      then:
        - globals.set:
            id: faktyczny_stan_wodomierza
            value: !lambda 'return x;'
        # Zapisujemy aktualny stan licznika impulsów z RAM-u jako bazę
        - lambda: 'id(baza_impulsow_wody) = id(surowe_impulsy_wody).state;'
        - component.update: wodomierz_sensor
sensor:
- platform: pulse_meter
    pin:
      number: GPIO26
      mode: INPUT_PULLUP
      inverted: true
    name: "Bieżący przepływ wody"
    id: przeplyw_wody
    internal: true
    internal_filter: 40ms 
    total:
      id: surowe_impulsy_wody
      internal: true

  # GŁÓWNY SENSOR – Całkowite zużycie wody w m³ (BEZBŁĘDNA MATEMATYKA)
  - platform: template
    name: "Całkowite zużycie wody"
    id: wodomierz_sensor
    icon: "mdi:water"
    unit_of_measurement: "m³"
    accuracy_decimals: 3
    device_class: water
    state_class: total_increasing
    lambda: |-

Prośba o zerknięcie co AI tu stworzył i może uda się znaleźć co jest przyczyną.

Jaką nakładkę, na jaki licznik? Konkretne modele. Domyślam się, że to nakładka z wyjściem impulsowym. Jeśli tak, to jak podłączssz ją (elektrycznie) do urządzenia z ESP?

Przyczyna nie leży w kodzie od AI, ale w jego (jeszcze) braku inteligencji, którą najczęściej definiuje się jako zdolność do odnajdywania odległych analogii (łączeniu kropek). Ja już taką analagię dostrzegam. AI nie widzi drugiej kropki więc i nie może tym bardziej ich łączyć.

Koniecznie umieść cały kod ESPHome dla tego urządzenia.

Jest to nakładka Apator AT-MBUS-NE-02. Licznik tez Apatora.

Licznik jest podłączony dwoma przewodami do ESP32 przez optoizolator i liczy impulsy.

Kod trochę długi ale sporo obsługuje mi to ESP.

esphome:
  name: esp32-2x16
  friendly_name: Skrzynka Piwnica

esp32:
  variant: esp32
  framework:
    type: esp-idf

logger:

api:
  encryption:
    key: "xxxxxxxxxxxxxxxxxx"

ota:
  - platform: esphome

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password
  use_address: 192.168.1.84
  ap:
    ssid: ESP32_2x16 Fallback Hotspot
    password: "xxxxxxxxxxxxxxxxx"

captive_portal:


i2c:
  - scl: 17
    sda: 16
    scan: true

mcp23017:
  - id: mcp23017_hub_0x20
    address: 0x20
  - id: mcp23017_hub_0x21
    address: 0x21

globals:
  - id: faktyczny_stan_wodomierza
    type: double
    restore_value: true
    initial_value: '0.0'

  - id: kierunek_ruchu_bramy
    type: std::string
    restore_value: false
    initial_value: '"Zatrzymana"' 
    
  - id: baza_impulsow_wody
    type: double
    restore_value: true
    initial_value: '0.0'
   
one_wire:
  - platform: gpio
    pin: GPIO32
    id: bus_1wire

# =========================================================
# FIZYCZNE MAPOWANIE PINÓW WYJŚCIOWYCH
# =========================================================
output:
  - platform: gpio
    id: wyjscie_mcp_0
    pin: { mcp23xxx: mcp23017_hub_0x21, number: 0 }

  - platform: gpio
    id: wyjscie_mcp_1
    pin: { mcp23xxx: mcp23017_hub_0x21, number: 1 }

  - platform: gpio
    id: wyjscie_mcp_2
    pin: { mcp23xxx: mcp23017_hub_0x21, number: 2 }

  - platform: gpio
    id: wyjscie_mcp_3
    pin: { mcp23xxx: mcp23017_hub_0x21, number: 3 }

  - platform: gpio
    id: wyjscie_mcp_4
    pin: { mcp23xxx: mcp23017_hub_0x21, number: 4 }

  - platform: gpio
    id: wyjscie_mcp_7
    pin: { mcp23xxx: mcp23017_hub_0x21, number: 7 }

  - platform: gpio
    id: wyjscie_mcp_8
    pin: { mcp23xxx: mcp23017_hub_0x21, number: 8 }

  - platform: gpio
    id: wyjscie_mcp_10
    pin: { mcp23xxx: mcp23017_hub_0x21, number: 10 } 
    
    
# =========================================================
# CZAS SYSTEMOWY 
# =========================================================
time:
  - platform: sntp
    id: sntp_time
    timezone: "Europe/Warsaw"
  

    

number:
  - platform: template
    name: "Korekta stanu licznika wody"
    id: korekta_wodomierza
    icon: "mdi:water-sync"
    unit_of_measurement: "m³"
    min_value: 0
    max_value: 999999
    step: 0.001
    mode: BOX
    set_action:
      then:
        - globals.set:
            id: faktyczny_stan_wodomierza
            value: !lambda 'return x;'
        # Zapisujemy aktualny stan licznika impulsów z RAM-u jako bazę
        - lambda: 'id(baza_impulsow_wody) = id(surowe_impulsy_wody).state;'
        - component.update: wodomierz_sensor
sensor:
  - platform: dallas_temp
    one_wire_id: bus_1wire
    name: "Temperatura piwnica"
    id: sensor_dallas_temp_1
    update_interval: 30s

  # =========================================================
  # LICZNIK WODY - ZMIENIONY NA PULSE_METER (GWARANCJA STABILNOŚCI 1:1)
  # =========================================================
  - platform: pulse_meter
    pin:
      number: GPIO26
      mode: INPUT_PULLUP
      inverted: true
    name: "Bieżący przepływ wody"
    id: przeplyw_wody
    internal: true
    # Zwiększamy filtr do 40ms, co bezwzględnie zablokuje nawet najdłuższe drgania blaszek
    internal_filter: 40ms 
    total:
      id: surowe_impulsy_wody
      internal: true

  # GŁÓWNY SENSOR – Całkowite zużycie wody w m³ (BEZBŁĘDNA MATEMATYKA)
  - platform: template
    name: "Całkowite zużycie wody"
    id: wodomierz_sensor
    icon: "mdi:water"
    unit_of_measurement: "m³"
    accuracy_decimals: 3
    device_class: water
    state_class: total_increasing
    lambda: |-
      // Obliczamy realny przyrost impulsów (bieżący stan minus stan z momentu korekty)
      double przyrost_impulsow = id(surowe_impulsy_wody).state - id(baza_impulsow_wody);
      
      // Zwracamy wpisany stan rzeczywisty powiększony o nowo naliczone metry sześcienne
      return id(faktyczny_stan_wodomierza) + (przyrost_impulsow / 1000.0);

# Pobieranie tekstowego stanu encji typu cover z Home Assistant
text_sensor:
  - platform: template
    name: "Stan Furtki"
    id: stan_furtki_tekst
    lambda: |-
      if (id(surowy_stan_ha).state) {
        return {"otwarto"};
      } else {
        return {"zamknięto"};
      }

  - platform: template
    name: "Status Bramy Wjazdowej"
    id: status_bramy_tekst
    icon: "mdi:gate"
    lambda: |-
      if (id(krancowka_brama_zamknieta).state) {
        return {"zamknięto"};
      }
      if (id(krancowka_brama_otwarta).state) {
        return {"otwarto"};
      }
      return {id(kierunek_ruchu_bramy)};
    update_interval: 0.5s

# =========================================================
# CZUJNIKI BINARNE I KRAŃCÓWKI
# =========================================================
binary_sensor:
  # Krańcówka: Brama zamknięta
  - platform: gpio
    id: krancowka_brama_zamknieta
    internal: true
    pin: { number: GPIO33, mode: INPUT, inverted: true }
    on_press:
      then:
        - script.stop: stoper_awarii_bramy
    on_release:
      then:
        - lambda: 'id(kierunek_ruchu_bramy) = "otwieranie";'
        - script.execute: stoper_awarii_bramy

  # Krańcówki: Brama otwarta
  - platform: gpio
    id: krancowka_brama_otwarta
    internal: true
    pin: { number: GPIO25, mode: INPUT, inverted: true }
    on_press:
      then:
        - script.stop: stoper_awarii_bramy
    on_release:
      then:
        - lambda: 'id(kierunek_ruchu_bramy) = "zamykanie";'
        - script.execute: stoper_awarii_bramy
    
  - platform: homeassistant
    entity_id: binary_sensor.poczta_gateway_opening_sensor
    id: surowy_stan_ha
    internal: true # Ważne: ukrywa surowy stan "on/off"

  

  # =========================================================
  # 9 PRZYCISKÓW MONOSTABILNYCH (MCP23017 - Adres 0x20)
  # =========================================================
  - platform: gpio
    id: ukryty_przycisk_1
    internal: true
    pin: { mcp23xxx: mcp23017_hub_0x20, number: 0, mode: INPUT, inverted: true }
    filters:
      - delayed_on_off: 20ms
    on_press:
      then:
        - light.toggle: oswietlenie_wjazd
        - homeassistant.event: { event: esphome.przycisk_klik, data: { button: "przycisk_1", action: "single_click" } }

  - platform: gpio
    id: ukryty_przycisk_2
    internal: true
    pin: { mcp23xxx: mcp23017_hub_0x20, number: 1, mode: INPUT, inverted: true }
    filters:
      - delayed_on_off: 20ms
    on_press:
      then:
        - light.toggle: oswietlenie_wjazd_czas
        - homeassistant.event: { event: esphome.przycisk_klik, data: { button: "przycisk_2", action: "single_click" } }

  - platform: gpio
    id: ukryty_przycisk_3
    internal: true
    pin: { mcp23xxx: mcp23017_hub_0x20, number: 2, mode: INPUT, inverted: true }
    filters:
      - delayed_on_off: 20ms
    on_press:
      then:
        - light.toggle: oswietlenie_z_przodu
        - homeassistant.event: { event: esphome.przycisk_klik, data: { button: "przycisk_3", action: "single_click" } }

  - platform: gpio
    id: ukryty_przycisk_4
    internal: true
    pin: { mcp23xxx: mcp23017_hub_0x20, number: 3, mode: INPUT, inverted: true }
    filters:
      - delayed_on_off: 20ms
    on_press:
      then:
        - light.toggle: oswietlenie_z_przodu_czas
        - homeassistant.event: { event: esphome.przycisk_klik, data: { button: "przycisk_4", action: "single_click" } }

  - platform: gpio
    id: ukryty_przycisk_5
    internal: true
    pin: { mcp23xxx: mcp23017_hub_0x20, number: 4, mode: INPUT, inverted: true }
    filters:
      - delayed_on_off: 20ms
    on_press:
      then:
        - light.toggle: oswietlenie_pv
        - homeassistant.event: { event: esphome.przycisk_klik, data: { button: "przycisk_5", action: "single_click" } }

  # Przycisk 6 -> FURTKA (Twardy impuls bezpośrednio na przekaźnik 6)
  - platform: gpio
    id: ukryty_przycisk_6
    internal: true
    pin: { mcp23xxx: mcp23017_hub_0x20, number: 5, mode: INPUT, inverted: true }
    filters:
      - delayed_on_off: 20ms
    on_press:
      then:
        - switch.turn_on: przekaznik_sprzetowy_6
        - delay: 0.5s
        - switch.turn_off: przekaznik_sprzetowy_6
        - homeassistant.event: { event: esphome.przycisk_klik, data: { button: "przycisk_6", action: "single_click" } }

  # Przycisk 7 -> BRAMA WJAZDOWA
  - platform: gpio
    id: ukryty_przycisk_7
    internal: true
    pin: { mcp23xxx: mcp23017_hub_0x20, number: 6, mode: INPUT, inverted: true }
    filters: 
      - delayed_on_off: 20ms
    on_press:
      then:
        - script.execute: impuls_bramy
        - homeassistant.event: { event: esphome.przycisk_klik, data: { button: "przycisk_7", action: "single_click" } }

  - platform: gpio
    id: ukryty_przycisk_8
    internal: true
    pin: { mcp23xxx: mcp23017_hub_0x20, number: 7, mode: INPUT, inverted: true }
    filters:
      - delayed_on_off: 20ms
    on_press:
      then:
        - light.toggle: latarenki_ognisko
        - homeassistant.event: { event: esphome.przycisk_klik, data: { button: "przycisk_8", action: "single_click" } }

  - platform: gpio
    id: ukryty_przycisk_9
    internal: true
    pin: { mcp23xxx: mcp23017_hub_0x20, number: 8, mode: INPUT, inverted: true }
    filters:
      - delayed_on_off: 20ms
    on_press:
      then:
        - light.toggle: wiatrak_swiatlo
        - homeassistant.event: { event: esphome.przycisk_klik, data: { button: "przycisk_9", action: "single_click" } }

  - platform: gpio
    id: ukryty_przycisk_10
    internal: true
    pin: { mcp23xxx: mcp23017_hub_0x20, number: 9, mode: INPUT, inverted: true }
    filters:
      - delayed_on_off: 20ms
    on_press:
      then:
        - switch.turn_on: przekaznik_furtka_tyl
        - delay: 3s # <--- Czas podtrzymania zmieniony na 3 sekundy
        - switch.turn_off: przekaznik_furtka_tyl
        - homeassistant.event: { event: esphome.przycisk_klik, data: { button: "przycisk_10", action: "single_click" } }

         
# =========================================================
# OŚWIETLENIE
# =========================================================
light:
  - platform: binary
    name: "Oświetlenie wjazd"
    id: oswietlenie_wjazd
    output: wyjscie_mcp_0

  - platform: binary
    name: "Oświetlenie wjazd czas"
    id: oswietlenie_wjazd_czas
    output: wyjscie_mcp_1
    on_turn_on:
      - delay: 3min
      - light.turn_off: oswietlenie_wjazd_czas

  - platform: binary
    name: "Oświetlenie z przodu"
    id: oswietlenie_z_przodu
    output: wyjscie_mcp_2

  - platform: binary
    name: "Oświetlenie z przodu czas"
    id: oswietlenie_z_przodu_czas
    output: wyjscie_mcp_3
    on_turn_on:
      - delay: 3min
      - light.turn_off: oswietlenie_z_przodu_czas

  - platform: binary
    name: "Oświetlenie PV"
    id: oswietlenie_pv
    output: wyjscie_mcp_4

  - platform: binary
    name: "Latarenki ognisko"
    id: latarenki_ognisko
    output: wyjscie_mcp_7

  - platform: binary
    name: "Wiatrak"
    id: wiatrak_swiatlo
    output: wyjscie_mcp_8

  - platform: binary
    name: "Czujka ośw. wjazd"
    id: czujka_osw_wjazd
    output: wyjscie_mcp_10  

# =========================================================
# BRAMY I FURTKI


# =========================================================
# JEDEN PRZYCISK IMPULSOWY DO BRAMY W HOME ASSISTANT
# =========================================================
button:
  - platform: template
    name: "Brama Wjazdowa Krok-po-Kroku"
    id: przycisk_bramy_ha
    icon: "mdi:gate"
    on_press:
      - script.execute: impuls_bramy
        
  - platform: template
    name: "Uruchom Furtkę"
    id: przycisk_furtki_ha
    icon: "mdi:door-gate"
    on_press:
      - script.execute: impuls_furtki
        
  - platform: template
    name: "Uruchom Furtkę Tył"
    id: przycisk_furtki_tyl_ha
    icon: "mdi:door-gate"
    on_press:
      - script.execute: impuls_furtki_tyl     
        
        
# =========================================================
# PRZEŁĄCZNIKI SPRZĘTOWE AUTOMATYKI (Wewnętrzne)
# =========================================================
switch:
  # Przekaźnik furtki (Pin 5 na MCP 0x21)
  - platform: gpio
    id: przekaznik_sprzetowy_6
    internal: true
    pin: { mcp23xxx: mcp23017_hub_0x21, number: 5 }

  # Mapowanie na fizyczny Przekaźnik 7 (czyli sprzętowy numer pinu 6)
  - platform: gpio
    id: brama_przekaznik
    internal: true
    pin:
      mcp23xxx: mcp23017_hub_0x21
      number: 6
      
# NOWOŚĆ: 10. Przekaźnik (Furtka Tył) -> Sprzętowy numer pinu 9 na MCP 0x21
  - platform: gpio
    id: przekaznik_furtka_tyl
    internal: true
    pin:
      mcp23xxx: mcp23017_hub_0x21
      number: 9
      
# =========================================================
# CENTRALNY SKRYPT GENERUJĄCY JEDEN IMPULS 0,5s
# =========================================================
script:
  - id: impuls_bramy
    mode: queued
    then:
      - switch.turn_on: brama_przekaznik
      - delay: 0.5s
      - switch.turn_off: brama_przekaznik
  - id: stoper_awarii_bramy
    mode: restart
    then:
      - delay: 30s
      - lambda: |-
          if (!id(krancowka_brama_zamknieta).state && !id(krancowka_brama_otwarta).state) {
            id(kierunek_ruchu_bramy) = "wstrzymano";
          }
  - id: impuls_furtki
    mode: queued
    then:
      - switch.turn_on: przekaznik_sprzetowy_6
      - delay: 0.5s
      - switch.turn_off: przekaznik_sprzetowy_6
        
  - id: impuls_furtki_tyl
    mode: queued
    then:
      - switch.turn_on: przekaznik_furtka_tyl
      - delay: 3s
      - switch.turn_off: przekaznik_furtka_tyl

          

EDIT 19.09.2026: Ktoś pomorze i zerknie w kod?

Też przy pomocy Gemini programuje. Niestety Gemini czasem wymyśla.

Tu masz kod tylko, musisz go dopasować do swoich potrzeb. Przeliczyć na metry sześcienne. Najprawdopodobniej Twój licznik przelicza że jeden impuls= jeden litr, to musisz sprawdzić.

Nie liczył bym na kod który będzie podawać aktualny stan licznika , otrzymasz encję do śledzenia zużycia w karcie Energii. Każdy zanik napięcia na ESP będzie powodować zerowanie licznika impulsów.

Do aktualnego stanu licznika musisz stworzyć pomocnika w HA