ESP32C3 super mini Wi-Fi Fails to Reconnect After Deep Sleep

Hi everyone,

I’m working on an ESP32 project with ESPHome, and I’m having trouble with Wi-Fi not reconnecting after the device wakes from deep sleep. The device uses both Wi-Fi and BLE, along with MQTT over SSL, and it should go into deep sleep after publishing sensor data. Here’s my configuration:

Key Parts of Config:

  • Device: ESP32C3, using ESP-IDF framework
  • Deep Sleep: Configured with a 30-second duration (deep_sleep: sleep_duration: 30s)
  • Wi-Fi Output Power: Set to 10
  • MQTT over SSL: With skip_cert_cn_check: true
  • BLE Tracking Enabled: Using esp32_ble_tracker
  • Global Variables: Using allow_sleep with restore_value: yes

Issues Encountered

After the device enters deep sleep, it often fails to reconnect to Wi-Fi when it wakes up. Here are some adjustments I’ve tried without success:

  • Added delays in on_boot to give the device time to reconnect
  • Adjusted output_power for Wi-Fi
  • Temporarily disabled BLE to test if Wi-Fi reconnects more reliably

Does anyone know if there’s a specific setting I need to ensure Wi-Fi reconnects after deep sleep? Any suggestions on further tweaks or troubleshooting steps would be much appreciated!

Thanks in advance for your help!

here is my config

substitutions:
  devicename: florasensordevicenew
  sleep_duration: 30s
# Declare a global variable
globals:
  - id: allow_sleep
    type: bool
    restore_value: yes
    initial_value: "true"  # Set initial value to false
  - id: miflora1_temperature_published
    type: bool
    restore_value: no
    initial_value: "true"
  - id: miflora1_moisture_published
    type: bool
    restore_value: no
    initial_value: "true"
  - id: miflora1_illuminance_published
    type: bool
    restore_value: no
    initial_value: "true"
  - id: miflora1_conductivity_published
    type: bool
    restore_value: no
    initial_value: "true"
  - id: miflora3_temperature_published
    type: bool
    restore_value: no
    initial_value: "true"
  - id: miflora3_moisture_published
    type: bool
    restore_value: no
    initial_value: "true"
  - id: miflora3_illuminance_published
    type: bool
    restore_value: no
    initial_value: "true"
  - id: miflora3_conductivity_published
    type: bool
    restore_value: no
    initial_value: "true"
    
esphome:
  name: $devicename
  #platformio_options:
    #build_flags: "-DBOARD_HAS_PSRAM"  
    #board_build.flash_mode: dio
    #board_build.f_flash: 40000000L
    #board_build.flash_size: 4MB
  platformio_options:
    board_build.f_flash: 40000000L
    board_build.flash_mode: dio
    board_build.flash_size: 4MB
  on_boot:
    priority: -100  # Ensures this action runs after other initializations
    then:
      - switch.turn_on: sleep_allowed
       
          
#esp32:
#  board: esp32dev
#  framework:
#    type: esp-idf

#esp32:
#  board: az-delivery-devkit-v4
#  framework:
#     type: esp-idf
#    type: arduino 

esp32:
  variant: ESP32C3
  board: esp32-c3-devkitm-1
  framework:
    type: esp-idf
    version: recommended

#esp32:
#  board: esp32-s3-devkitc-1
#  variant: ESP32S3
#  framework:
#    type: esp-idf
#    version: recommended
#    sdkconfig_options:
#      CONFIG_ESP32_S3_BOX_BOARD: "y"
#      COMPILER_OPTIMIZATION_SIZE: "y"
#    advanced:
#      ignore_efuse_mac_crc: false      
  
#psram:
#  mode: quad
#  speed: 80MHz  
  
deep_sleep:
  id: deep_sleep_1
  sleep_duration: $sleep_duration

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

  # Enable fallback hotspot (captive portal) in case wifi connection fails
 # ap:
 #   ssid: $devicename
 #   password: !secret ap_password

captive_portal:

web_server:
  port: 80
  
mqtt:
  broker: "*"
  port: 8883
  username: "*"
  password: "*"
  certificate_authority: |
    -----BEGIN CERTIFICATE-----
    ********
    -----END CERTIFICATE-----
  
  # Just use SSL/TLS without client certificates
  skip_cert_cn_check: true
  discovery: false
  will_message:
    topic: $devicename/status
    payload: "offline"
  birth_message:
    topic: $devicename/status
    payload: "online"
  on_json_message:
    topic: "$devicename/sleep"
    then:
      - logger.log: "OTA mode ?"
      - lambda: |-
          if (x.containsKey("sleep")) {
            bool should_sleep = x["sleep"].as<bool>();
            if (should_sleep) {
              id(allow_sleep) = true;   // Set variable to true
              id(sleep_allowed).turn_on();
            } else {
              id(sleep_allowed).turn_off();  // Set variable to false
              id(allow_sleep) = false;   // Set variable to true
            }
          }




# Enable logging
logger:
  level: DEBUG

ota:

esp32_ble_tracker:

xiaomi_ble:

sensor:
  # Uptime sensor
  - platform: uptime
    id: uptime_seconds
    name: Uptime sensor
    update_interval: 1s
    accuracy_decimals: 1
    unit_of_measurement: s
    
  - platform: xiaomi_hhccjcy01
    mac_address: "FC:85:7E:12:ED:CA" # Replace with your sensor's MAC address
    temperature:
      name: "MiFlora1 Temperature"
      id: miflora1_temperature
      on_value:
        then:
          - lambda: |-
              id(miflora1_temperature_published) = true;  
          - script.execute: check_all_published  # Check if all have published
    moisture:
      name: "MiFlora1 Moisture"
      id: miflora1_moisture
      on_value:
        then:
          - lambda: |-
              id(miflora1_moisture_published) = true;  
          - script.execute: check_all_published  # Check if all have published
          
    illuminance:
      name: "MiFlora1 Illuminance"
      id: miflora1_illuminance
      on_value:
        then:
          - lambda: |-
              id(miflora1_illuminance_published) = true;  
          - script.execute: check_all_published  # Check if all have published
          
    conductivity:
      name: "MiFlora1 Soil Conductivity"
      id: miflora1_conductivity
      on_value:
        then:
          - lambda: |-
              id(miflora1_conductivity_published) = true;  
          - script.execute: check_all_published  # Check if all have published
          
    battery_level:
      name: "MiFlora1 Battery Level"
      id: miflora1_battery
  - platform: xiaomi_hhccjcy01
    mac_address: "FC:85:7E:12:ED:AB" # Replace with your sensor's MAC address
    temperature:
      name: "MiFlora2 Temperature"
      id: miflora2_temperature
    moisture:
      name: "MiFlora2 Moisture"
      id: miflora2_moisture
    illuminance:
      name: "MiFlora2 Illuminance"
      id: miflora2_illuminance
    conductivity:
      name: "MiFlora2 Soil Conductivity"
      id: miflora2_conductivity
    battery_level:
      name: "MiFlora2 Battery Level"
      id: miflora2_battery
  - platform: xiaomi_hhccjcy01
    mac_address: "5F:85:7E:13:07:4B" # Replace with your sensor's MAC address
    temperature:
      name: "MiFlora3 Temperature"
      id: miflora3_temperature
      on_value:
        then:
          - lambda: |-
              id(miflora3_temperature_published) = true;  
          - script.execute: check_all_published  # Check if all have published
     
    moisture:
      name: "MiFlora3 Moisture"
      id: miflora3_moisture
      on_value:
        then:
          - lambda: |-
              id(miflora3_moisture_published) = true;  
          - script.execute: check_all_published  # Check if all have published
          
    illuminance:
      name: "MiFlora3 Illuminance"
      id: miflora3_illuminance
      on_value:
        then:
          - lambda: |-
              id(miflora3_illuminance_published) = true;  
          - script.execute: check_all_published  # Check if all have published
          
    conductivity:
      name: "MiFlora3 Soil Conductivity"
      id: miflora3_conductivity
      on_value:
        then:
          - lambda: |-
              id(miflora3_conductivity_published) = true;  
          - script.execute: check_all_published  # Check if all have published
      
    battery_level:
      name: "MiFlora3 Battery Level"
      id: miflora3_battery
 
switch:
  - platform: template
    name: "sleep_allowed"
    id: sleep_allowed
    turn_on_action:
      - lambda: |-
          id(allow_sleep) = true;  
    turn_off_action:
      - lambda: |-
          id(allow_sleep) = false;     

# Define a script to check if all sensors have published
script:
  - id: check_all_published
    then:
      - lambda: |-
          if (id(miflora1_temperature_published) && id(miflora1_moisture_published) && id(miflora1_illuminance_published) && id(miflora1_conductivity_published) &&
          id(miflora3_temperature_published) && id(miflora3_moisture_published) && id(miflora3_illuminance_published) && id(miflora3_conductivity_published) &&
          id(allow_sleep)) {
            id(deep_sleep_trigger).execute();  // Trigger deep sleep if all are published
          }

# Define the deep sleep trigger
  - id: deep_sleep_trigger
    then:
      - deep_sleep.enter: deep_sleep_1          

interval:
  - interval: 5min
    then:
      - mqtt.publish:
          topic: "$devicename/sensor1/temperature"
          payload: !lambda |-
            return to_string(id(miflora1_temperature).state);
      - mqtt.publish:
          topic: "$devicename/sensor1/moisture"
          payload: !lambda |-
            return to_string(id(miflora1_moisture).state);
      - mqtt.publish:
          topic: "$devicename/sensor1/illuminance"
          payload: !lambda |-
            return to_string(id(miflora1_illuminance).state);
      - mqtt.publish:
          topic: "$devicename/sensor1/conductivity"
          payload: !lambda |-
            return to_string(id(miflora1_conductivity).state);
      - mqtt.publish:
          topic: "$devicename/sensor1/battery"
          payload: !lambda |-
            return to_string(id(miflora1_battery).state);
      - mqtt.publish:
          topic: "$devicename/sensor2/temperature"
          payload: !lambda |-
            return to_string(id(miflora2_temperature).state);
      - mqtt.publish:
          topic: "$devicename/sensor2/moisture"
          payload: !lambda |-
            return to_string(id(miflora2_moisture).state);
      - mqtt.publish:
          topic: "$devicename/sensor2/illuminance"
          payload: !lambda |-
            return to_string(id(miflora2_illuminance).state);
      - mqtt.publish:
          topic: "$devicename/sensor2/conductivity"
          payload: !lambda |-
            return to_string(id(miflora2_conductivity).state);
      - mqtt.publish:
          topic: "$devicename/sensor2/battery"
          payload: !lambda |-
            return to_string(id(miflora2_battery).state);
      - mqtt.publish:
          topic: "$devicename/sensor3/temperature"
          payload: !lambda |-
            return to_string(id(miflora3_temperature).state);
      - mqtt.publish:
          topic: "$devicename/sensor3/moisture"
          payload: !lambda |-
            return to_string(id(miflora3_moisture).state);
      - mqtt.publish:
          topic: "$devicename/sensor3/illuminance"
          payload: !lambda |-
            return to_string(id(miflora3_illuminance).state);
      - mqtt.publish:
          topic: "$devicename/sensor3/conductivity"
          payload: !lambda |-
            return to_string(id(miflora3_conductivity).state);
      - mqtt.publish:
          topic: "$devicename/sensor3/battery"
          payload: !lambda |-
            return to_string(id(miflora3_battery).state);

What rssi are you getting?

I’d add a sensor for that if you don’t have one…