Wait for device to send data to HA before going to deep sleep

I have a keypad connected to an ESP32 that its in deep sleep. With a button i wake it up, and then i type a code with the keypad.
As soon as the code is sent to HA i want to go to deep sleep again (i dont want to extra seconds waiting enough time, as i find it power consuming).
The problem is, with the current code, the ESP32 goes to deep sleep before sending the code. If i wait some seconds before sending the code, it works as expected.
So, what is a reliable way to wait just as much as needed before going to sleep? I tried api.connected, but it looks like its still not enough time to send the message.

I tried to make something out of this but it doesnt work (looks to stuck in wait_until forever):

....
logger:
  level: VERBOSE
  on_message: 
    then:
      - if:
          condition: 
            - lambda: |-
                return tag == "myKeycodeResult";
          then:
            - globals.set: 
                id: is_keycodeResult_sent
                value: "true"  

globals:
  id: is_keycodeResult_sent
  type: bool
  restore_value: no
  initial_value: "false"


key_collector:
  - id: pincode_reader
    source_id: mykeypad
    min_length: 2
    max_length: 4
    end_keys: "#"
    end_key_required: true
    # back_keys: "C"
    clear_keys: "*"
    allowed_keys: "0123456789ABCD"
    timeout: 5s
    on_progress:
      - lambda: id(keycode).publish_state(x.c_str());
    on_result:
      - lambda: id(keycodeResult).publish_state(x.c_str());
      - if:
          condition:
            not:
              api.connected: 
          then:
            - logger.log: "not connected to API*********************************************************************"
            - wait_until:
                condition:
                  - lambda: |-
                      return id(is_keycodeResult_sent);
            - logger.log: "NOW CONNECTED*********************************************************************"

            - deep_sleep.enter:
                id: deep_sleep_1
          else:
            - deep_sleep.enter:
                id: deep_sleep_1
    on_timeout:
      - logger.log:
          format: "input timeout: '%s', started by '%c'"
          args: [ 'x.c_str()', "(start == 0 ? '~' : start)" ]

Any ideas?

#on esphome device
api:
  encryption:
    key: ""
  actions:
    - action: deep_sleep.enter: deep_sleep_1
	
#action on HA in an automation	
action: esphome.nameofyouresp_deep_sleep.enter	

I assume when you type in the digits the state of something changes and that could be used as a trigger to call the deepsleep action on the esphome device from HA. The action above in HA may need adjusted.
I do this with MQTT. When HA receives a payload it publishes a payload to a different topic. The esphome device is subscribed to this subject and on reception of this message it goes straight to deepsleep. It works very well in MQTT.

# on esphome device
mqtt:
  broker: 
  username: 
  password: 
  on_message:
    - topic: weathersmall/sleepearly
      payload: 'ON'
      then:        
        - deep_sleep.enter: deep_sleep_1
		
#in an automation in HA		
trigger:
  - platform: mqtt
    topic: weathersmall/sensor/cell/state
condition: []
action:
  - delay:
      hours: 0
      minutes: 0
      seconds: 0
      milliseconds: 50
  - data:
      qos: 0
      retain: false
      topic: weathersmall/sleepearly
      payload: "ON"
    action: mqtt.publish
mode: single		

This is what it looks like with MQTT.

Thanks for the quick answer, although i didnt use MQTT it helped me through another way.

After a lot of searching, I found this very helpful. This worked fine for me after several adjustments and tests.

In order to help others the solution is:

  1. Create a binary sensor in HA:

Go to Settings, Devices and services, Helpers, Toggle, name: prevent_deep_sleep, icon: mdi:sleep-on. A new helper with entity id: input_boolean.prevent_deep_sleep will be created.

  1. Set this to ON and leave this to ON forever. Also, if you want to do OTA, you can prevent deep sleep by setting temporary to OFF.

The logic, is that the esphome device (i.e. ESP32) will wait forever until it can read this value from HA. This means that when it reads this sensor, it has established communication with HA. After that we can send our valuable data to HA and be sure it will reach it (the keypad code in my example).

  1. In my esphome yaml:
binary_sensor:
  - platform: homeassistant
    id: prevent_deep_sleep
    entity_id: input_boolean.prevent_deep_sleep
    icon: "mdi:sleep-on"
    entity_category: diagnostic
    internal: False
...
key_collector:
  - id: pincode_reader
    source_id: mykeypad
    min_length: 2
    max_length: 4
    end_keys: "#"
    end_key_required: true
    # back_keys: "C"
    clear_keys: "*"
    allowed_keys: "0123456789ABCD"
    timeout: 25s
    on_progress:
      - lambda: id(keycode).publish_state(x.c_str());
    on_result:
      # turn off my display to save energy while waiting to connect to HA
      - lambda: |- 
          id(myDisplay).turn_off();
      # establish connection with HA
      - wait_until: 
          condition:
            - binary_sensor.is_on: prevent_deep_sleep
     # must be after wait_until 
      - lambda: id(keycodeResult).publish_state(x.c_str());
      - deep_sleep.enter:
          id: deep_sleep_1
    on_timeout:
      - logger.log:
          format: "input timeout: '%s', started by '%c'"
          args: [ 'x.c_str()', "(start == 0 ? '~' : start)" ]
  1. Ensure the keypad code is correct.

Go to Developer settings, states in HA (http://HA_IP:8123/developer-tools/state) and see if the myKeycodeResult is correct (i found that the dashboard results are not refreshed immediately).

1 Like