First Voltage Value of ESP after deep sleep always 0 (zero)

HI,
I have an E1001 terminal from seeed, and want to show the user the voltage percentage directly after the E1001 coming from deep sleep and I want the Voltage itself in HomeAssistant in the statistics. The view for the user on the ePaper works.
For this reason I put the sensor measurement in the on_boot, wait for the API beeing there and than continue with my program.
My problem is, that on every wakeup after deep sleep the first value HomeAssistant gets is “0” (zero), which “kills” the nicely shown graphs.
See here one cutout of my statistic data:

The IMHO relevant part of my ESPHome yaml:

esphome:
  name: ${rmgr_device_name}
  friendly_name: ${rmgr_device_name}
  project:
    name: rmgr.room_manager
    version: "1.1.7"
  on_boot:
    - priority: -100
      then:
        # make sure, we are connected to HomeAssistant
        - wait_until:
            condition:
              api.connected:
#                state_subscription_only: true
            timeout: 30s
        - lambda: |-
            ESP_LOGI("boot", "API connected");

        - lambda: |-
            auto cause = esp_sleep_get_wakeup_cause();
            if (cause == ESP_SLEEP_WAKEUP_EXT0 ||
                cause == ESP_SLEEP_WAKEUP_EXT1) {
              id(woke_by_button) = true;
              ESP_LOGI("wakeup", "Woke up by BUTTON");
            } else if (cause == ESP_SLEEP_WAKEUP_TIMER) {
              id(woke_by_button) = false;
              ESP_LOGI("wakeup", "Woke up by TIMER");
            } else {
              id(woke_by_button) = false;
              ESP_LOGI("wakeup", "Woke up by OTHER cause (%d)", cause);
            }

        # --- local battery first ---
        - output.turn_on: bsp_battery_enable
        - delay: 100ms
        - component.update: ${rmgr_device_name}_battery_voltage
        # --- read battery three times and to get the correct value
        # - delay: 50ms
        - component.update: ${rmgr_device_name}_battery_voltage
        - delay: 50ms
        - component.update: ${rmgr_device_name}_battery_voltage
        - delay: 50ms
        - component.update: ${rmgr_device_name}_battery_voltage
        - delay: 450ms

        - wait_until:
            condition:
#              lambda: 'return id(${rmgr_device_name}_battery_voltage).has_state() && !isnan(id(${rmgr_device_name}_battery_voltage).state);'
              lambda: 'return id(${rmgr_device_name}_battery_voltage).has_state() && id(${rmgr_device_name}_battery_voltage).state > 2.0;'
#              lambda: 'return id(${rmgr_device_name}_battery_voltage).has_state() && !isnan(id(${rmgr_device_name}_battery_voltage).state) && id(${rmgr_device_name}_battery_voltage).state > 2.0;'              
            timeout: 15s

        - lambda: |-
            ESP_LOGI("battery", "voltage 1 %3.2f V", id(${rmgr_device_name}_battery_voltage).state);


        # make sure at least a part of the calendar data is there
        - script.execute: wait_for_valid_a

        - component.update: ${rmgr_device_name}_battery_level
        - wait_until:
            condition:
              lambda: 'return id(${rmgr_device_name}_battery_level).has_state() && !isnan(id(${rmgr_device_name}_battery_level).state);'
            timeout: 2s

        - wait_until:
            condition:
              lambda: 'return id(ha_time).now().is_valid();'
            timeout: 2s

        - component.update: ${rmgr_device_name}_wifi_strength
        - wait_until:
            condition:
              lambda: 'return id(${rmgr_device_name}_wifi_strength).has_state() && !isnan(id(${rmgr_device_name}_wifi_strength).state);'
            timeout: 2s

        - wait_until:
            condition:
              lambda: |-
                return id(rmgr_today_valid_a).has_state();
            timeout: 2s

        - lambda: |-
            ESP_LOGI("boot", "before screenWrite");

        - component.update: screenWrite

        - lambda: |-
            ESP_LOGI("boot", "after screenWrite");


        - if:
            condition:
              binary_sensor.is_on: ${rmgr_device_name}_connected
            then:
              - if:
                  condition:
                    lambda: 'return id(woke_by_button);'
                  then:
                    - script.execute: beep
                  else:
                    - script.execute: silent_beep

        # 1 minute Wakeup time, where the users can interact
        - lambda: |-
            ESP_LOGI("boot", "before delay 1 min ");
        - delay: 1min
        - lambda: |-
            ESP_LOGI("boot", "before go_to_sleep_screen_then_sleep");
        - script.execute: go_to_sleep_screen_then_sleep

I do not understand why this

lambda: 'return id(${rmgr_device_name}_battery_voltage).has_state() && id(${rmgr_device_name}_battery_voltage).state > 2.0;'

is still delivering values below 2 to HomeAssiant.

Does anyone have any idea what I am doing wrong?
Until now I tried:
1.) more component_update of the voltage
2.) longer wait for the battery component to come up: (500ms)

        - output.turn_on: bsp_battery_enable
        - delay: 100ms

All with no luck. If the ESP is up and the api is there, all the data is coming as expected.

The workaround would be, not to show the battery percentage directly after boot, but only if going to sleep and find a way in HomeAssistant to ignore
${rmgr_device_name}_battery_voltage below let’s say 2.4V as the ESP would not work below this value.
How can I ignore such values in HA from a sensor? Like: I only want to “see” data in HomeAssistant from this sensor between 2 and 5 so say something.

any ideas welcome
thank you
Juergen

I too would like to know the answer.

Without seeing your code it’s difficult to answer.
But sensors are initialized way before API connects and HA gets the value when API connects. Your automations after API are not relevant, make sure you have valid sensor readings before instead.


On ESPhome you can filter out the first or first few readings to avoid this

Hi,
thanks a bunch for the idea. I “somehow” got it to work. I say “somehow”, because I have no real clue why. This works as a battery Voltage that has “smooth” Voltage, not “0” drops, and “seems” to work. I now see graphs I want to see and they show a value, that I “believe”. All for E1001 from seeed, I do not know where it might work for as well.

sensor definition is now:

  - platform: adc
    pin: GPIO1
    id: ${rmgr_device_name}_battery_voltage
    name: "Battery Voltage"
    unit_of_measurement: "V"
    device_class: voltage
    state_class: measurement
    accuracy_decimals: 2
    update_interval: 1s
    attenuation: 12db
    filters:
      - filter_out: 0
      - median:
          window_size: 5
          send_every: 3
      - exponential_moving_average:
          alpha: 0.1
          send_every: 1
      - multiply: 2.0
      - round: 2

first I filter out the drop to “0” than I do the median, then I “easen out the graph”, as I do not want to see every 1/100 up and down, multiply by two because of the values from the sensor, and than I round it to “2”, as if I do not round it, I have three digits, which I do not understand because of the
accuracy_decimals: 2 already set before.

If I only use this, I see a gap in the graph, when the ESP wakes up, if I only read the value once. So this is how I read the value:

        # --- local battery first ---
        - output.turn_on: bsp_battery_enable
        - delay: 500ms
        # --- read battery three times and to get the correct value
        - component.update: ${rmgr_device_name}_battery_voltage
        - delay: 50ms
        - component.update: ${rmgr_device_name}_battery_voltage
        - delay: 50ms
        - component.update: ${rmgr_device_name}_battery_voltage
        - delay: 50ms

If I do not reun it three times there is a noticeable gap of about 4 secs in the HA graph, if I read it, one only notices the gap, if you know it is there. No idea why, but I can now live with the result.

thank you
and all the best
Juergen

You can also use a lambda and kick out every zero value until you get a nonzero, then flip a global boolean to true, and when that boolean is true, you can begin passing values. Succinct and doesn’t muck with your sensor resolution.

FWIW, I am using an INA3221 to do the measuring, but I have also noticed that my first LiPo battery voltage reading after deep_sleep is most often low - sometimes by as much as 0.3V. This doesn’t sound like much, but when it falsely triggers my low_battery_panic automation at 3.6V instead of 3.3V … :slightly_frowning_face:

I also have used filters to skip_initial and median to average out the rest of the readings. Still not ideal, but much better.

I’m just realising that I have thought of power/voltage in large terms - assuming the 240V from the mains power is constant … but now I see that the power in a battery is a limited resource. As the microcontroller does its work it consumes power, which temporarily reduces the voltage. Starting up from deep_sleep involves quite a few processes running in parallel, as well as operating the various connected circuits and devices.

Hi,
back again with my sensor drop to “0”. Now if the ESP connects I see an “unknown” shortly in the device overview. Like half a second “old value”-“unknown”-“old-value”

My guess is, that the HomeAssistant/ESP API is getting something wrong, but I have no clue if I am right.
I also “assume” that this happens since one of the new updates. I am both with ESPHome and HomeAssistand on newest. But this is even a wilder guess.

any ideas how to debug this closer?
Or can I “somehow” in HomeAssistant “deny” values for a filter, that are unkown?

many thanks
Juergen

You can use ESPHome filters to filter out unknowns prior to sending them to HA.

1 Like

Hi,

I had a similar issue, where my energy readings droped to 0 after reboot of the ESP and this resets my utility meter in HomeAssistant.

My solution in this case: persist the data, so that after reboot, it does not start at 0 but a the last known value.

Note: intensive flash write may destroy your flash drive. Make sure to understand, how many write cycles your flash drive is able to take.

1 Like

The ATHOM energy plugs do exactly this! Look at their YAML in their github.

HI. This was a solution, I was considering, but as the ePaper costs about 80.- EUR, I was not sure, if I wanted to risk it, especially as I do not know what would happen. If it breaks, it is not worth it. I was hoping for a software solution, and I minimized the “0” by adding wait and basically trying very early to check and filter, and it seems to work for me.

This is what I am doing right now: and it works for the E1001 from SEEED Studio.

sensor with filter definition:

  - platform: adc
    pin: GPIO1
    id: ${rmgr_device_name}_battery_voltage
    name: "Battery Voltage"
    unit_of_measurement: "V"
    device_class: voltage
    state_class: measurement
    accuracy_decimals: 2
    update_interval: 1s
    attenuation: 12db
    filters:
      - filter_out: 0
      - median:
          window_size: 5
          send_every: 3
      - exponential_moving_average:
          alpha: 0.1
          send_every: 1
      - multiply: 2.0
      - round: 2

in on_boot routine

        # --- local battery first ---
        - output.turn_on: bsp_battery_enable
        - delay: 500ms
        # --- read battery three times and to get the correct value
        - component.update: ${rmgr_device_name}_battery_voltage
        - delay: 50ms
        - component.update: ${rmgr_device_name}_battery_voltage
        - delay: 50ms
        - component.update: ${rmgr_device_name}_battery_voltage
        - delay: 50ms

And this is now very reliable

I do now exactly if this is “perfect” or just adding delays I can live with because it works (which bothers me a little), as it was more or less a “brute force” and trying from my side, with the “filter” tip from above, but I can live with the result.

Up to now, I am happy.

Juergen