Hello, I have been struggling for the past day to understand how to make sensors work in combination with deep sleep.
I have two sensors connected to my ESP32 - DHT11 for humidity and BMP280 for temperature and pressure. My goal is to keep the ESP awake for enough time to read and report the values from both sensors and go to sleep after that.
I noticed that especially DHT11 is very inconsistent with reporting values. Based on the logs, it takes from 3s up to 50s between BMP280 and DHT11 reading. So the run_time should be set to at least 1 minute in order to get the readings, but my goal is to enter deep sleep automatically as soon as all the sensors are done sending their data.
My guess is the wanted behavior could be achieved by setting up automation in combination with some scripts. Maybe it could be done with on_value automation on sensor?
Since I have very little experience with ESPHome and setting up automations, I would really appreciate any help on this topic. Has anyone managed to achieve something similar?
Thank you!
The following is my current config:
esphome:
name: "esp32-inside"
esp32:
board: esp32dev
framework:
type: arduino
# Enable logging
logger:
level: DEBUG
# Enable Home Assistant API
api:
ota:
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
# Enable fallback hotspot (captive portal) in case wifi connection fails
ap:
ssid: !secret ap_ssid
password: !secret ap_password
captive_portal:
i2c:
sda: 21
scl: 22
scan: true
id: bus_a
sensor:
- platform: dht
model: DHT11
pin: 15
humidity:
name: "Humidity DHT"
update_interval: 60s
- platform: bmp280
temperature:
name: "Temperature BMP"
oversampling: 16x
filters:
- offset: -2.3
pressure:
name: "Pressure BMP"
address: 0x76
update_interval: 60s
# Update interval has no effect when deep sleep is in use and it is longer than run_duration. Esphome always sends the readings on boot.
deep_sleep:
id: deep_sleep_1
run_duration: 60s
sleep_duration: 60s
mqtt:
broker: !secret mqtt_broker
port: 1883
username: !secret mqtt_username
password: !secret mqtt_password
on_message:
- topic: esp32-inside/ota_mode
payload: 'ON'
then:
- deep_sleep.prevent: deep_sleep_1
- logger.log: "OTA mode enabled - deep sleep mode disabled"
- topic: esp32-inside/sleep_mode
payload: 'ON'
then:
- deep_sleep.enter: deep_sleep_1
- logger.log: "deep sleep mode enabled"
In summary you turn off auto updates for sensors and call them manually on boot. Then you create counters/binary sensors which track updates and user them to sleep when they’re done.
Thank you so much for this! I went through your config and I think I understand how it works. Will try to implement the logic for my use case and report the result once I am done.
I made it! Thanks to your config example I managed to trigger deep sleep after all the sensors send their data. I can’t thank you enough!
Here is the config I have written with the help of your example:
# Huge thanks to user Mahko_Mahko on Home Assistant Community for providing his configuration example. I included his practices in my configuration to make it work.
# https://community.home-assistant.io/t/solar-powered-self-watering-plant-no-plumbing-no-power-wip/464263/14
substitutions:
devicename: esp32-inside
max_run_duration: 60s
sleep_duration: 60s
esp32:
board: esp32dev
framework:
type: arduino
esphome:
name: $devicename
# on_boot documentation and priorities: https://esphome.io/components/esphome.html#on-boot
on_boot:
- priority: -100
then: # At this priority, pretty much everything should already be initialized.
- logger.log: "Starting sensor updates..."
- repeat:
count: 5
then:
#Sensor updates are turned off and manually requested on boot.
#Then the ESP goes back to sleep when they're done (unless told to stay awake)
# Request sensor updates
- component.update: dht_inside
- delay: 2000ms # DHT11 is a really slow sensor
- component.update: bmp_inside
- delay: 100ms
on_shutdown:
priority: -100
then:
- if:
condition:
- binary_sensor.is_on: all_updates_received
then:
- logger.log: "Data from all sensors received"
else:
- logger.log: "One or more sensor updates missing"
# Reset data update sensors states
- binary_sensor.template.publish:
id: inside_temperature_dht_received
state: OFF
- binary_sensor.template.publish:
id: inside_humidity_dht_received
state: OFF
- binary_sensor.template.publish:
id: inside_temperature_bmp_received
state: OFF
- binary_sensor.template.publish:
id: inside_pressure_bmp_received
state: OFF
# Enable logging
logger:
level: DEBUG
# Enable Home Assistant API
api:
ota:
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
# Enable fallback hotspot (captive portal) in case wifi connection fails
ap:
ssid: !secret ap_ssid
password: !secret ap_password
captive_portal:
i2c:
sda: 21
scl: 22
scan: true
id: bus_a
deep_sleep:
id: deep_sleep_1
run_duration: $max_run_duration
sleep_duration: $sleep_duration
mqtt:
broker: 192.168.64.18
port: 1883
username: !secret mqtt_username
password: !secret mqtt_password
birth_message:
will_message:
on_message:
- topic: esp32-inside/ota_mode
payload: 'ON'
then:
- deep_sleep.prevent: deep_sleep_1
- logger.log: "OTA mode enabled - deep sleep mode disabled"
- topic: esp32-inside/sleep_mode
payload: 'ON'
then:
- deep_sleep.enter: deep_sleep_1
- logger.log: "deep sleep mode enabled"
binary_sensor:
# Data update sensors. Implemented as barrier. Again huge thanks to user Mahko_Mahko on Home Assistant Community for providing his configuration example.
# https://community.home-assistant.io/t/solar-powered-self-watering-plant-no-plumbing-no-power-wip/464263/14
# Inside temperature DHT
- platform: template
name: Temperature DHT updated
id: inside_temperature_dht_received
internal: True
# Internal components will not be exposed to the frontend (like Home Assistant).
# Only specifying an id without a name will implicitly set this to true.
# Inside humidity DHT
- platform: template
name: Humidity DHT updated
id: inside_humidity_dht_received
internal: True
# Inside temperature BMP
- platform: template
name: Temperature BMP updated
id: inside_temperature_bmp_received
internal: True
# Inside pressure BMP
- platform: template
name: Pressure BMP updated
id: inside_pressure_bmp_received
internal: True
# All updates
- platform: template
name: Updates from all sensors received
id: all_updates_received
icon: mdi:database-refresh-outline
# entity_category: diagnostic
# If all sensors data is received. Will be false even if only one sensor fails.
lambda: |-
return
id(inside_temperature_dht_received).state &&
id(inside_humidity_dht_received).state &&
id(inside_temperature_bmp_received).state &&
id(inside_pressure_bmp_received).state;
on_press:
# Would this work with on_state as well?
then:
- logger.log:
format: "All sensors updated after %.1f seconds of uptime. Entering deep sleep."
args: ['id(uptime_seconds).state']
- delay: 100ms
- deep_sleep.enter:
id: deep_sleep_1
sensor:
# Uptime sensor
- platform: uptime
id: uptime_seconds
name: Uptime sensor
update_interval: 1s
accuracy_decimals: 1
unit_of_measurement: s
# DHT11 - temperature, humidity
- platform: dht
model: DHT11
pin: 15
id: dht_inside
update_interval: never
temperature:
name: "Temperature DHT"
on_value:
then:
- binary_sensor.template.publish:
id: inside_temperature_dht_received
state: ON
humidity:
name: "Humidity DHT"
on_value:
then:
- binary_sensor.template.publish:
id: inside_humidity_dht_received
state: ON
# BMP280 - temperature, pressure
- platform: bmp280
address: 0x76
id: bmp_inside
update_interval: never
temperature:
name: "Temperature BMP"
oversampling: 16x
filters:
- offset: -2.3
on_value:
then:
- binary_sensor.template.publish:
id: inside_temperature_bmp_received
state: ON
pressure:
name: "Pressure BMP"
on_value:
then:
- binary_sensor.template.publish:
id: inside_pressure_bmp_received
state: ON
I will probably get rid of MQTT for preventing deep sleep and implement a button for this purpose. It is going to be much easier to turn it on and off that way.