Take a variable from HA on ESP32 boot and start working from it

Of course:

esphome:
  name: esphome-web-71afe8
  friendly_name: ESPHome Pantalla
#  on_boot:
#    priority: -100
#    then:
#      - lambda: |-
#          id(total_agua).publish_state(id(total_consumo_agua_global).state);

esp32:
  board: esp32dev
  framework:
    type: arduino

# Enable logging
logger:
  level: DEBUG

# Enable Home Assistant API
api:
  encryption:
    key: "****"
  services:
    - service: set_total_agua
      variables:
        value: float
      then:
        - lambda: |-
            id(total_agua).publish_state(value);

    - service: update_total_agua
      then:
        - lambda: |-
            id(total_agua).publish_state(id(total_agua).state);
  on_client_connected:
    - if:
        condition:
          lambda: 'return client_address.c_str() == "192.168.0.128";'
        then:
          - lambda: |-
              id(total_agua).publish_state(id(total_consumo_agua_global).state);

ota:

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password

  # Enable fallback hotspot (captive portal) in case wifi connection fails
  ap:
    ssid: "****"
    password: "****"

captive_portal:

sensor:
  - platform: pulse_counter
    pin: 
      number: 19
      allow_other_uses: true
    update_interval : 6s
    name: "pulso agua"
    id: pulso_agua
    filters:
      - multiply: 0.1

  - platform: pulse_meter
    pin: 
      number: 19
      allow_other_uses: true
    name: "Medidor pulsos agua"
    unit_of_measurement: "litros/min"
    icon: "mdi:water"
    total:
      name: "Total Agua"
      unit_of_measurement: "litros"
    filters:
      - multiply: 0.1

  - platform: template
    name: "Flujo de agua"
    id: flujo_agua
    accuracy_decimals: 1
    unit_of_measurement: "l/min"
    icon: "mdi:water"
    lambda: return (id(pulso_agua).state * 1);
    update_interval: 6s

  - platform: homeassistant
    id: total_agua
    entity_id: sensor.esphome_web_71afe8_total_agua
    on_value:
      then:
        - homeassistant.service:
            service: input_number.set
            data:
              entity_id: input_number.total_consumo_agua_global
              value: !lambda 'return x;'

  - platform: homeassistant
    id: total_consumo_agua_global
    entity_id: input_number.total_consumo_agua_global


  - platform: wifi_signal
    name: "WiFi ESP"
    update_interval: 60s
    id: intensidad_wifi_esp

font:
  - file: "fonts/roboto.ttf"
    id: robotofont
    size: 15

  - file: "fonts/roboto.ttf"
    id: robotofont_large
    size: 25
  - file: "fonts/roboto.ttf"
    id: robotofont_small
    size: 12
    
i2c:
  sda: GPIO21
  scl: GPIO22

# Añadir el componente de pantalla OLED
display:
  - platform: ssd1306_i2c
    model: "SSD1306 128x64"
    address: 0x3C
    reset_pin: GPIO0
    lambda: |-
      // Imprime "Consumo Total:"
      it.print(0, 0, id(robotofont), "Consumo Total:");
      // Imprime el valor del sensor "total_agua"
      if (id(total_agua).has_state()) {
        it.printf(0, 15, id(robotofont_large), "%.0f", id(total_agua).state);
      }
      // Imprime "Wifi:" un poco más arriba
      it.print(0, 50, id(robotofont), "Wifi:  ");
      // Imprime la intensidad de la señal WiFi como una barra horizontal más gruesa
      if (id(intensidad_wifi_esp).has_state()) {
        float signal_strength = min(max(2 * (id(intensidad_wifi_esp).state + 100.0), 0.0), 100.0);
        for (int i = 0; i < signal_strength / 10; i++) {
          it.print(35 + i * 10, 50, id(robotofont_small), "|");
          it.print(35 + i * 10, 55, id(robotofont_small), "|");
        }
      }

Okay I think this part could be causing the problem. I’d try putting a condition on it that the API has to be connected to Home Assistant.

Something like this?:

  - platform: homeassistant
    id: total_agua
    entity_id: sensor.esphome_web_71afe8_total_agua
    on_value:
      then:
        - if:
            condition:
              api.connected:
            then:
              - homeassistant.service:
                  service: input_number.set
                  data:
                    entity_id: input_number.total_consumo_agua_global
                    value: !lambda 'return x;'

Sorry if being too dumb but I don’t dominate this part at all.

Yeah I think that should work!

Also no worries, we all have to start somewhere with learning. We’ll get to a solution eventually:D

Thanks for your help. I entered it and doesn’t work either. It doesn’t get the number from the input number in home assistant at boot, but I don’t know why

hmm that’s odd indeed. This started boggling my mind more than I initially expected, but I think I found a thread that deals with a similar problem:

So the idea is to use global variables, because those can be restored upon boot:

And I think then, if you want to show it in the front end, you can use a template sensor that simply returns the global, or you can use the on_boot automation we discussed before, and publish the value of the global. I thought of something like this for the configuration of the global variable:

globals:
  - id: total_agua_var
    type: float
    restore_value: yes
    initial_value: '0'

And then use use the pulse sensor to update the global:

  - platform: pulse_meter
    pin: 
      number: 19
      allow_other_uses: true
    name: "Medidor pulsos agua"
    unit_of_measurement: "litros/min"
    icon: "mdi:water"
    id: total_agua_meter
    total:
      id: total_agua
      name: "Total Agua"
      unit_of_measurement: "litros"
    filters:
      - multiply: 0.1
    on_value:
      then:
        - lambda: |-
            id(total_agua_var) = id(total_agua).state;
            ESP_LOGD(DEBUG, "Updated water consumption global variable to %f", id(total_agua_var));

And the automation like:

  on_boot:
   then:
    - pulse_meter.set_total_pulses:
                id: total_agua_meter
                value: !lambda 'return id(total_agua_var);'

I hope this works out of the box. It might take some playing around with the configuration though to get everything to play together nicely.

Well, I may be missing something. I cleaned the config and added what you suggested:

esphome:
  name: esphome-web-71afe8
  friendly_name: ESPHome Pantalla
  on_boot:
   then:
    - pulse_meter.set_total_pulses:
                id: total_agua_meter
                value: !lambda 'return id(total_agua_var);'

esp32:
  board: esp32dev
  framework:
    type: arduino

# Enable logging
logger:

# Enable Home Assistant API
api:
  encryption:
    key: "***"

globals:
  - id: total_agua_var
    type: float
    restore_value: yes
    initial_value: '0'

ota:

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password

  # Enable fallback hotspot (captive portal) in case wifi connection fails
  ap:
    ssid: "***"
    password: "***"

captive_portal:

sensor:
  - platform: pulse_counter
    pin: 
      number: 19
      allow_other_uses: true
    update_interval : 6s
    name: "pulso agua"
    id: pulso_agua
    filters:
      - multiply: 0.1

  - platform: pulse_meter
    pin: 
      number: 19
      allow_other_uses: true
    name: "Medidor pulsos agua"
    unit_of_measurement: "litros/min"
    icon: "mdi:water"
    id: total_agua_meter
    total:
      id: total_agua
      name: "Total Agua"
      unit_of_measurement: "litros"
    filters:
      - multiply: 0.1
    on_value:
      then:
        - lambda: |-
            id(total_agua_var) = id(total_agua).state;
            ESP_LOGD(DEBUG, "Updated water consumption global variable to %f", id(total_agua_var));

  - platform: template
    name: "Flujo de agua"
    id: flujo_agua
    accuracy_decimals: 1
    unit_of_measurement: "l/min"
    icon: "mdi:water"
    lambda: return (id(pulso_agua).state * 1);
    update_interval: 6s

  - platform: homeassistant
    id: total_agua_ha
    entity_id: sensor.esphome_web_71afe8_total_agua
    on_value:
      then:
        - homeassistant.service:
            service: input_number.set
            data:
              entity_id: input_number.total_consumo_agua_global
              value: !lambda 'return x;'

  - platform: wifi_signal
    name: "WiFi ESP"
    update_interval: 60s
    id: intensidad_wifi_esp

font:
  - file: "fonts/roboto.ttf"
    id: robotofont
    size: 15

  - file: "fonts/roboto.ttf"
    id: robotofont_large
    size: 25
  - file: "fonts/roboto.ttf"
    id: robotofont_small
    size: 12
    
i2c:
  sda: GPIO21
  scl: GPIO22

# Añadir el componente de pantalla OLED
display:
  - platform: ssd1306_i2c
    model: "SSD1306 128x64"
    address: 0x3C
    reset_pin: GPIO0
    lambda: |-
      // Imprime "Consumo Total:"
      it.print(0, 0, id(robotofont), "Consumo Total:");
      // Imprime el valor del sensor "total_agua"
      if (id(total_agua).has_state()) {
        it.printf(0, 15, id(robotofont_large), "%.0f", id(total_agua).state);
      }
      // Imprime "Wifi:" un poco más arriba
      it.print(0, 50, id(robotofont), "Wifi:  ");
      // Imprime la intensidad de la señal WiFi como una barra horizontal más gruesa
      if (id(intensidad_wifi_esp).has_state()) {
        float signal_strength = min(max(2 * (id(intensidad_wifi_esp).state + 100.0), 0.0), 100.0);
        for (int i = 0; i < signal_strength / 10; i++) {
          it.print(35 + i * 10, 50, id(robotofont_small), "|");
          it.print(35 + i * 10, 55, id(robotofont_small), "|");
        }
      }

And got this error:

ERROR Circular dependency detected! Please run with -v option to see what functions failed to complete.

Edit: don’t know how to run with -v option as I’m using ESPHome in Home Assistant.

I ran it like that, and it seems like esphome treats total_agua like a variable? I have no clue why however. The logs would simply print the following over and over again:

DEBUG Waiting for variable total_agua
DEBUG Running to_code in esphome.components.pulse_meter.sensor (num 11)

The sensor as defined below would compile. However logic wise you’d have to test if it works. I’m mainly not sure if it would follow the correct state, so you’d have to check that.

  - platform: pulse_meter
    pin: 
      number: 19
      allow_other_uses: true
    name: "Medidor pulsos agua"
    unit_of_measurement: "litros/min"
    icon: "mdi:water"
    id: total_agua_meter
    total:
      #id: total_agua
      name: "Total Agua"
      unit_of_measurement: "litros"
    filters:
      - multiply: 0.1
    on_value:
      then:
        - lambda: |-
            if (id(total_agua_var) != id(total_agua_meter).state) {
              id(total_agua_var) = id(total_agua_meter).state;
              ESP_LOGD("DEBUG", "Updated water consumption global variable to %f", id(total_agua_var));
            }

Yes, this way it compiles but it keeps refusing to restore previous value of the global we set.

What’s more, if I try to use the service I set:

service: esphome.esphome_web_71afe8_set_total_agua
data:
  value: 282648.9

it is sent but as long as I open the water, the value jumps to a number that I don’t know where it came.

Can you post the logs again? It may also be an idea to compile it with

logger:
  level: VERBOSE

It may give more insights in what is going on. I assume somewhere an automation is working back on itself, perhaps. Also, I assume you mean the sensor value is the one that is jumping?

Of course, and thanks again for taking so much time in helping me:

https://justpaste.it/e7ti0

Could you post it again, but this time when opening the water? The pulse meter hasn’t updated here so it’s not possible to figure out what happens with it when it updates.

Best would be to post logs where you first call the service in home assistant, and then open the water so we can inspect the number and its origins.

Absolutely. I have upload both files in this folder:

https://file.io/gUVpAPRNvR2L

It somehow sumed 2.177.719,9 liters in a week, so it is not only reading the variables but suming like a crazy.

I think that is due to something being wrong with the meter itself. There are a couple of entries like 'Medidor pulsos agua': Sending state 2162.94165 litros/min with 2 decimals of accuracy, so over the course of a week that would sum up quite rapidly. Also keep in mind it does not have any filters applied yet (see the documentation: Pulse Meter Sensor — ESPHome)

Aside from that, I found this thread: ESPHome total meter - #7 by danielw
What’s mainly important is that the way we’re currently trying to solve it would likely result in your ESP needing replacement relatively soon.

So, less than ideal, but I think taking a few steps back is best, and configuring the solution mainly using an automation in Home Assistant.
My idea would be having an automation that triggers on a new value of the total water sensor, and writes that to an input number, only if the new value is higher than the previous one (using trigger templates, that’s not too hard. Let me know if you’d need help with that). And on the ESP, you’d want a service that can set the total water value. If the new value of the sensor is lower (i.e. 0, meaning a restart of the ESP), Home Assistant should call the service with the retained value of the input number.

Sounds good to me, but my initial approach was taken of a tutorial, so the latter modifications were thanks to some ideas and mainly by yours, I’m not sure if I would know how to do it (more than asking for help to chatgpt and then by depuring mistakes).

Besides, you have used a lot of your time in helping me and I don’t want to bother you more. I’m gonna take a read to your links, try with chatgpt and then, if I can’t success, will come here again, if you please.

Thanks!!

1 Like

Alright, good luck! And of course you’re free to come back here if you run into new problems you can’t solve!

Well, I created an input_number.total_consumo_agua_global in which I entered the real consumption in this moment.

Then I created an automation in home assistant:

alias: Actualizar consumo total de agua
description: ""
trigger:
  - platform: state
    entity_id:
      - sensor.esphome_web_71afe8_total_agua
condition:
  - condition: template
    value_template: >-
      "{{ trigger.to_state.state | float >
      states('input_number.total_consumo_agua_global') | float }}"
action:
  - service: input_number.set_value
    target:
      entity_id: input_number.total_consumo_agua_global
    data:
      value: "{{ trigger.to_state.state }}"
mode: single

And then added this in espHome:

api:
  services:
    - service: set_total_agua
      variables:
        value: float
      then:
        - lambda: |-
            id(total_agua).publish_state(value);

Still doesn’t update the input number in HA and doesn’t take it at boot. It booted with 734 l., I wasted water for ten seconds and it went up to 1261 l.

image

I’m trying a different approach. This is my new configuration:

substitutions:
  name: esphome-web-71afe8
  friendly_name: ESPHome Pantalla
packages:
  esphome.bluetooth-proxy: github://esphome/firmware/bluetooth-proxy/esp32-generic.yaml@main
esphome:
  name: ${name}
  name_add_mac_suffix: false
  friendly_name: ${friendly_name}
  on_boot:
    priority: -10
    then:
      - while:
          condition:
            not:
              api.connected:
          then:
            - delay: 1s
      - script.execute: get_ha_var

script:
  - id: get_ha_var
    then:
      - lambda: |-
          int new_total = round(id(ha_total_consumo_agua_global).state);
          id(total_agua_meter).set_total_pulses(new_total);

esp32:
  board: esp32dev
  framework:
    type: arduino

logger:
  level: VERBOSE

# Enable Home Assistant
api:
  encryption:
    key: ***
  services:
    - service: set_total_agua
      variables:
        value: int
      then:
        - lambda: |-
            id(total_agua).publish_state(value);
    - service: set_total
      variables:
        new_total: int
      then:
        - pulse_meter.set_total_pulses:
            id: total_agua_meter
            value: !lambda 'return new_total;'

ota:

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password
  manual_ip:
    static_ip: 192.168.0.208
    gateway: 192.168.0.1
    subnet: 255.255.255.0
  ap:
    ssid: "Esphome-Web-71Afe8"
    password: "***"

captive_portal:

sensor:
  - platform: homeassistant
    id: ha_total_consumo_agua_global
    entity_id: input_number.total_consumo_agua_global
  - platform: pulse_counter
    pin: 
      number: 19
      allow_other_uses: true
    update_interval : 6s
    name: "pulso agua"
    id: pulso_agua
    filters:
      - multiply: 1

  - platform: pulse_meter
    pin: 
      number: 19
      allow_other_uses: true
    name: "Medidor pulsos agua"
    unit_of_measurement: "decilitros/min"
    icon: "mdi:water"
    id: total_agua_meter
    total:
      id: total_agua
      name: "Total Agua"
      unit_of_measurement: "decilitros"
    filters:
      - multiply: 1

  - platform: template
    name: "Flujo de agua"
    id: flujo_agua
    accuracy_decimals: 1
    unit_of_measurement: "l/min"
    icon: "mdi:water"
    lambda: return (id(pulso_agua).state * 1);
    update_interval: 6s

  - platform: wifi_signal
    name: "WiFi ESP"
    update_interval: 60s
    id: intensidad_wifi_esp


font:
  - file: "fonts/roboto.ttf"
    id: robotofont
    size: 15

  - file: "fonts/roboto.ttf"
    id: robotofont_large
    size: 25
  - file: "fonts/roboto.ttf"
    id: robotofont_small
    size: 12
i2c:
  sda: GPIO21
  scl: GPIO22
display:
  - platform: ssd1306_i2c
    model: "SSD1306 128x64"
    address: 0x3C
    reset_pin: GPIO0
    lambda: |-
      // Imprime "Consumo Total:"
      it.print(0, 0, id(robotofont), "Consumo Total:");
      // Imprime el valor del sensor "total_agua"
      if (id(total_agua).has_state()) {
        it.printf(0, 15, id(robotofont_large), "%.1f", id(total_agua).state);
      }
      // Imprime "Wifi:" un poco más arriba
      it.print(0, 50, id(robotofont), "Wifi:  ");
      // Imprime la intensidad de la señal WiFi como una barra horizontal más gruesa
      if (id(intensidad_wifi_esp).has_state()) {
        float signal_strength = min(max(2 * (id(intensidad_wifi_esp).state + 100.0), 0.0), 100.0);
        for (int i = 0; i < signal_strength / 10; i++) {
          it.print(35 + i * 10, 50, id(robotofont_small), "I");
          it.print(35 + i * 10, 55, id(robotofont_small), "I");
        }
      }

Besides, it always start with a value of 2147483647 which, according to chatgpt, is the maximum value for a 32 bit number. Any help here?

I think that would have something to do with the on_boot automation, however I am not fully sure why.
My best guess would be it having to do with how you declare the int new_total. It could be that esphome imports it as a float, for example.

You can use ESP_LOGD("DEBUG", "new_total is %i", new_total); after that line to print the value in your logs, that way we could at least see if that’s where the incorrect value happens.

Ok, seems to have gone a little further, I attach my lattest config and the log. It now starts the script, and takes the value from ha, but I think it may be in a wrong order and this is why it doesn’t pass the value to the variable?

The config:
https://justpaste.it/d97y5

The log:

https://justpaste.it/efkvg