ESPHome: Cannot connect to ESP32-S3 when deep sleep configured

I’m trying to configure a TinyS3 (ESP32-S3FN8) with deep sleep using ESPHome. When the deep sleep configuration in commented out, HA reads the temperature fine. When the deep sleep configuration is not commented out, HA cannot connect to the board. It is not possible to read board logs, let alone the temperature.

This board has a single Dallas temperature sensor wired to I/O. I have a helper boolean defined in HA (tinys3_temp_prevent_deep_sleep) to prevent deep sleep and allow OTA updates. When disabled, my intention is that the board updates a sensor template with temperature sensor value every 5 min, and sleeps in between. When enabled, my intention is that the board never sleeps.

However the value of tinys3_temp_prevent_deep_sleep make no difference to the ability of HA to connect to the board.

Can someone please explain where I’m going wrong?

ESPHome yaml is below.

Esphome:
  name: tinys3-test
  friendly_name: TinyS3 Temperature Sensor
  on_boot:
    priority: -100
    then:
      - script.execute: check_for_sleep_prevention

esp32:
  board: esp32-s3-devkitc-1
  framework:
    type: arduino

logger:
#  level: INFO

api:
  encryption:
    key: "<key>"

ota:
  password: !secret ota_password

mdns:
  disabled: true

wifi:
  domain: .main.home
  ssid: !secret wifi_ssid
  password: !secret wifi_password

  manual_ip:
    static_ip: 192.168.2.48
    gateway: 192.168.2.1
    subnet: 255.255.255.0

dallas:
  - pin: GPIO1
    update_interval: 60s

sensor:
  - platform: dallas
    name: "DS18B20 Temperature Internal"
    id: ds18b20_int
    address: 0x8d0000075beae528
    internal: true
  - platform: template
    name: "DS18B20 Temperature"
    id: ds18b20
    update_interval: never

binary_sensor:
  - platform: homeassistant
    id: prevent_deep_sleep
    entity_id: input_boolean.tinys3_temp_prevent_deep_sleep

deep_sleep:
  id: deep_sleep_control

script:
  - id: check_for_sleep_prevention
    mode: queued
    then:
      # shouldn't need the following line?
      - deep_sleep.prevent: deep_sleep_control
      - sensor.template.publish:
          id: ds18b20
          state: !lambda 'return id(ds18b20_int).state;'
      - if:
          condition:
            binary_sensor.is_off: prevent_deep_sleep
          then:
            - deep_sleep.enter:
                id: deep_sleep_control
                sleep_duration: 300s
          else:
            - delay: 300s
      - script.execute: check_for_sleep_prevention
Esphome:
  name: tinys3-test
  friendly_name: TinyS3 Temperature Sensor


esp32:
  board: esp32-s3-devkitc-1
  framework:
    type: arduino

logger:
  level: DEBUG

api:
  encryption:
    key: "<key>"

ota:
  password: !secret ota_password

mdns:
  disabled: true

wifi:
  domain: .main.home
  ssid: !secret wifi_ssid
  password: !secret wifi_password

  manual_ip:
    static_ip: 192.168.2.48
    gateway: 192.168.2.1
    subnet: 255.255.255.0
	fast_connect: true

dallas:
  - pin: GPIO1
    update_interval: 10s

sensor:
  - platform: dallas
    name: "DS18B20 Temperature"
    id: ds18b20
    address: 0x8d0000075beae528

deep_sleep:
  id: deep_sleep_1
  run_duration: 60s
  sleep_duration: 1min 

What about starting off with simpler code to get deep sleep and a few sensor readings.

There’s only one sensor. You can’t get simpler than that.

Why did you make it internal then expose it as a template with never update? :thinking:
Just to check on your hardware, you did connect GPIO16 to RST? Easy to get caught out on that one. Perhaps that step is only needed on ESP8266 to wake.

I’m 87% sure it’s only required for ESP8266…

1 Like

Possibly your deep sleep prevent binary sensor isn’t being imported before it does the check, and so it goes to sleep. Can you see it going to sleep in the logs? Sometimes it’s hard to see logs close to boot.

If you add a ~ 15sec delay to the start of (or before your) check_for_sleep_prevention script you should be able to test this behaviour a bit more.

I’m 77% sure deep_sleep.prevent only prevents the auto deep sleeps ( ie run_duration:) and not manual ones like you’ve got there

OP said no logs so I’m not sure its even loading up or just wifi not connecting.

1 Like

It may have already gone to sleep! But I see your point.

Why did you make it internal then expose it as a template with never update? :thinking:

Yeah good question - this gets to the heart of my (flawed) ESPHome code. There are two sensors - one for the hardware sensor (internal) and one template. As far as I can tell, it is not possible in ESPHome to force a hardware sensor to update. You can only set the update interval. I wanted to wake from sleep, immediately read the hardware sensor, and have that communicated to the HA frontend. The template sensor is an attempt to do that - after waking, the template sensor is updated with the internal sensor value (publish command).

you did connect GPIO16 to RST?

There is no IO16 pin on the schematic for this board (Introducing the TinyS3 by Unexpected Maker). The temperature sensor works fine when the deep sleep logic is commented out.

When the board first loads up it should get a temperature reading straight away. When you say there is no log , have you only tried wireless or also by usb? The usb log will show up before wifi.
Perhaps your device never wakes or the script is sending it back to sleep before wifi has a chance to connect. It may take the lack of the Binary_sensor saying prevent deep sleep as permission to sleep. Try to run the script on_value from the sensor.

Thanks for the suggestions - particularly the logging via USB.

I inverted the logic of prevent_deep_sleep, i.e. changed it to allow_deep_sleep so that it was false on boot up. This seemed to ensure that a wireless connection was established with the front end. I could see debug log statements etc.

But when allow_deep_sleep was set to On, the board would go to sleep and the connection was lost. The board seems to wake up but does not establish a connection with the frontend. I added a 60 sec delay after waking up. This helped but would still not reliably reconnect to the frontend.

Any ideas on forcing a reconnect on wake?

Post your latest ESPhome yaml.

1 Like

Did you try the fast_connect: suggested earlier along with waiting until your HA sensor is imported per earlier suggestion?

Latest ESPHome test yaml (with debug logs etc) is below. This has fast connect enabled (not sure if this makes any difference) and also the while loop “trick” to test for HA connection. Deep sleep is only for 60 sec.

This “works” but is not reliable. I’m not yet convinced of the value of the while loop - I’m still testing. When deep sleep is not allowed, all is good. When deep sleep is allowed, sensor readings in HA are intermittent. I don’t get a consistent update every 60 sec. It will swap between deep sleep allowed and not allowed OK - but again, sometimes it takes multiples of 60 sec.

I’m also finding that the asynchronous nature of ESPHome coding makes it difficult (but intriguing) for me to understand what is going on! That and the fact that logs appear to get queued so you can get a burst of them which may not reflect when they are created?

esphome:
  # host name for DNS
  name: tinys3-test
  friendly_name: TinyS3 Temperature Sensor
  on_boot:
    priority: -100
    then:
      - logger.log: "=======> Booting..."
      - script.execute: check_for_sleep_prevention

esp32:
  board: esp32-s3-devkitc-1
  framework:
    type: arduino

# Enable logging
logger:
#  level: INFO

# Enable Home Assistant API
api:
  encryption:
    key: "<key>"

ota:
  password: !secret ota_password

mdns:
  disabled: true

wifi:
  domain: .main.home
  ssid: !secret wifi_ssid
  password: !secret wifi_password
  fast_connect: true
  on_connect:
    - logger.log: "=======> Wifi connected."

  manual_ip:
    static_ip: 192.168.2.48
    gateway: 192.168.2.1
    subnet: 255.255.255.0

# I/O
light:
  - platform: neopixelbus
    type: GRB
    variant: WS2812
    pin: GPIO18
    num_leds: 1
    name: "Onboard RGB"
    id: rgb_led

switch:
  - platform: gpio
    pin: GPIO17
    name: "Onboard RGB Power"
    id: rgb_power

dallas:
  - pin: GPIO1
# don't set to 'never' because it will then never update
    update_interval: 30s

sensor:
#  - platform: adc
#    pin: GPIO10
#    name: "Battery Voltage"
#    update_interval: 60s
  - platform: dallas
    name: "DS18B20 Temperature Internal"
    id: ds18b20_int
    #index: 0
    address: 0x8d0000075beae528
    internal: true
# Wifi and temp sensor don't play nice https://github.com/espressif/esp-idf/issues/8088
#  - platform: internal_temperature
#    name: "TinyS3 Temp"
#    update_interval: 60s
  - platform: template
    name: "DS18B20 Temperature"
    id: ds18b20
    update_interval: never

binary_sensor:
  - platform: gpio
    pin:
      number: GPIO0
      inverted: true
      mode:
        input: true
        pullup: true
    name: "BOOT"
    id: boot_button
# Will only pick up a value if this device is configured in Home Assistant > Integrations
# If the device isn't configured, or Home Assistant is offline, it'll default to false
#  - platform: homeassistant
#    id: prevent_deep_sleep
#    entity_id: input_boolean.tinys3_temp_prevent_deep_sleep
#    id: allow_deep_sleep
#    entity_id: input_boolean.tinys3_temp_allow_deep_sleep

text_sensor:
  - platform: homeassistant
    name: "Allow TinyS3 to Deep Sleep"
    entity_id: "input_boolean.tinys3_temp_allow_deep_sleep"
    id: allow_deep_sleep

## Deep Sleep
deep_sleep:
  id: deep_sleep_control
#  run_duration: 10s
#  sleep_duration: 30s

script:
  - id: check_for_sleep_prevention
    mode: queued
    then:
      - logger.log: "=======> Start script..."
      - switch.turn_on: rgb_power
      - light.turn_on:
          id: rgb_led
          brightness: 50%
          red: 100%
          blue: 0%
          green: 0%
      - while:
          condition:
            lambda: 'return id(allow_deep_sleep).state == "";'
          then:
            - logger.log: "> No connection to HA, retrying in 5s."
            - delay: 5s
      - light.turn_on:
          id: rgb_led
          brightness: 50%
          red: 0%
          blue: 0%
          green: 100%
      - logger.log:
          format: "> The temperature: <%.1f>"
          args: [ 'id(ds18b20_int).state' ]
      - sensor.template.publish:
          id: ds18b20
          state: !lambda 'return id(ds18b20_int).state;'
      - if:
          condition:
            #binary_sensor.is_on: allow_deep_sleep
            text_sensor.state:
              id: allow_deep_sleep
              state: 'on'
          then:
            - logger.log: "=======> Entering deep sleep"
            - deep_sleep.enter:
                id: deep_sleep_control
                sleep_duration: 60s
          else:
            - logger.log: "=======> Staying awake"
            - deep_sleep.prevent: deep_sleep_control
            - delay: 60s
      - script.execute: check_for_sleep_prevention
1 Like

You could try adding a small delay (1-2 sec) after your publish and before your deep sleep and see if that helps.

Esphome:
  name: tinys3-test
  friendly_name: TinyS3 Temperature Sensor
  on_boot:
    priority: -100
    then:
      - script.execute: check_for_sleep_prevention

esp32:
  board: esp32-s3-devkitc-1
  framework:
    type: arduino

logger:
  level: INFO

api:
  encryption:
    key: "<key>"

ota:
  password: !secret ota_password

mdns:
  disabled: true

wifi:
  domain: .main.home
  ssid: !secret wifi_ssid
  password: !secret wifi_password

  manual_ip:
    static_ip: 192.168.2.48
    gateway: 192.168.2.1
    subnet: 255.255.255.0
	fast_connect: true

dallas:
  - pin: GPIO1
    

sensor:
  - platform: dallas
    name: "DS18B20 Temperature"
	address: 0x8d0000075beae528
    id: ds18b20
    update_interval: 10s


binary_sensor:
  - platform: homeassistant
    id: prevent_deep_sleep
    entity_id: input_boolean.tinys3_temp_prevent_deep_sleep

deep_sleep:
  id: deep_sleep_control
  run_duration: 10s
  sleep_duration: 60s  

script:
  - id: check_for_sleep_prevention
    mode: queued
    then:
      - if:
          condition:
            binary_sensor.is_on: prevent_deep_sleep
          then:
            - deep_sleep.prevent: deep_sleep_control
            - logger.log: 'OTA Mode ON'
          else:
            - deep_sleep.allow: deep_sleep_control
            - logger.log: "OTA Mode OFF"
      - delay: 5s
      - script.execute: check_for_sleep_prevention 

I have tried this on an ESP32 but with a DHT11 sensor which is similar to dallas sensor. It works during deep sleep and OTA modes. It took a while to get OTA mode to work as I hadn’t selected configure new device under discover in integrations.