Thanks, Iāll keep that in mind
Can you share your button code from ha?
Which button do you mean?
I thought you were trying to add a button to the dashboard to stop deepsleep? Iām trying to figure out how to prevent my sensor node from going to sleep too do OTA updates when needed.
yeah my main way is based on this approach. You toggle on a HA control and next time it wakes and connects, it will stay awake.
The HA config is similar to this (think Iāve changed the name).
input_boolean:
keep_esps_awake_switch_ha:
name: "Keep ESPs Awake"
initial: false
icon: mdi:sleep-off
Iāll maintain my master config here. May not maintain it well though.
#Todo:
#Determine night time battery loss.
#More testing insitu
#HA alerts for low water, low battery, data updates not working.
#Check pump runs.
#Monitor review wet/dry/battery thresholds.
#Make debugging sensors internal.
substitutions:
devicename: irrigation-balcony-t7mini32v15
friendly_name: Planty
device_description: Planty | Bedroom Balcony Irrigation
sleep_time: 5min
auto_wake_time: 20s
pump_run_time: 40s
internal_mode: "true"
long_deep_sleep_duration: 24h
bh1750_i2c_scl_blue: GPIO27
bh1750_i2c_sda_green: GPIO25
vl53l0x_i2c_scl_blue: GPIO23
vl53l0x_i2c_sda_green: GPIO05
power_peripheral_pin: GPIO26
pump_switch_pin: GPIO18
batt_voltage_pin: GPIO33
soil_moisture_pin: GPIO34
# G # RST #1 tx # G
# NC # VP #3 rx #@ 27 bh1750 blue scl ${bh1750_i2c_scl_blue}
# VN #@ 26 ${power_peripheral_pin} #22 #@ 25 bh1750 green sda ${bh1750_i2c_sda_green}
# 35 #@ 18 ${pump_switch_pin} #21 #@ 32
#@ 33 ${batt_voltage_pin} #@ 19 #27 # TDI
# 34 ${soil_moisture_pin} #@ 23 ${vl53l0x_i2c_scl_blue} #25 #@ 4
# TMS #@ 5 ${vl53l0x_i2c_sda_green} #G # 0
# NC # 3v3 #5v # 2
# SD2 # TCK #TDO # SD1
# CMD # SD3 #SDO # CLK
esp32:
board: ttgo-t7-v14-mini32 #pinout: https://ae01.alicdn.com/kf/Ha204b20d14d243faa0c1a8760de1b187r.jpg
esphome:
name: $devicename
comment: ${device_description}
on_boot:
# #Try this if sensors don't boot. https://community.home-assistant.io/t/add-sensor-delay-upon-power-on/158567/6?u=mahko_mahko
# https://community.home-assistant.io/t/i2c-bus-scan-after-deep-sleep-recovery/524925/7?u=mahko_mahko
- priority: 900
then:
- lambda: |-
Wire.begin();
delay(500);
- priority: -100
then:
#Reset sensor update counters. These are for debugging.
- lambda: id(count_irrigation_lux).publish_state(0);
- lambda: id(count_batt_voltage).publish_state(0);
- lambda: id(count_irrigation_tof).publish_state(0);
- delay: 1s
#Auto sensor updates are turned off and manually requested on boot. These are multi-sampled and then aggregated.
#The ESP then goes back to sleep when they're done (unless told to stay awake).
#Request sensor updates
- logger.log: "....Starting sensor updates"
- repeat:
count: 5 #Update cycles
then:
- component.update: batt_voltage #Battery level
- delay: 100ms
- component.update: soil_moisture_voltage #Moisture level
- delay: 100ms
- component.update: tof #Water tank level
- delay: 100ms
- component.update: irrigation_lux #Light level
- delay: 100ms
#second pass for ADC based sensors which benefit from more samples.
- component.update: batt_voltage
- delay: 250ms
- component.update: soil_moisture_voltage
- delay: 250ms
on_shutdown: #Includes deep sleep
priority: -100
then:
- script.wait: run_pump_for_pump_run_time #Wait until pump run is done.
- if:
condition:
- binary_sensor.is_on: all_updates_recieved
then:
- logger.log: "Data updates ok..."
else:
- logger.log: "A sensor might be down...missing updates"
- binary_sensor.template.publish:
id: data_update_problem
state: ON
- delay: 1s
- switch.turn_off: pump #Probably not required....
#Turn off 5v peripheral power. It will retore as on when it wakes.
- logger.log: "Turning off peripheral power..."
- switch.turn_off: power_peripherals
#Turn off the "Fresh data recieved sensors"
- binary_sensor.template.publish:
id: water_tank_level_recieved
state: OFF
- binary_sensor.template.publish:
id: irrigation_lux_recieved
state: OFF
- binary_sensor.template.publish:
id: batt_level_recieved
state: OFF
- binary_sensor.template.publish:
id: solar_plant_moisture_level_recieved
state: OFF
- binary_sensor.template.publish:
id: all_updates_recieved
state: OFF
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
fast_connect: true
manual_ip:
static_ip: 192.168.1.123
gateway: 192.168.1.1
subnet: 255.255.255.0
api:
ota:
logger:
level: VERBOSE
baud_rate: 0
i2c:
- id: bh1750_i2c_bus
sda: GPIO25 #data > green wire
scl: GPIO27 #clock > blue wire
scan: true
- id: vl53l0x_i2c_bus
sda: ${vl53l0x_i2c_sda_green} #data > green wire
scl: ${vl53l0x_i2c_scl_blue} #clock > blue wire
scan: true
deep_sleep:
#Auto deep sleep shouldn't actually get used if data updates are happening properly (should sleep sooner).
#But if something is wrong with data updates this will kick-in to protect battery discharge.
id: deep_sleep_1
run_duration: ${auto_wake_time}
sleep_duration: ${sleep_time}
time:
- platform: homeassistant
id: esptime
on_time:
#Deep sleep at 8pm and wake up at 6am.
- hours: 20
then:
#Publish battery level to the end of day sensor since it will be our last update.
- lambda: return id(end_of_day_battery_percent).publish_state(id(batt_level).state);
#Reset culmulative light sensor reset
- sensor.integration.reset: irrigation_cul_lux_hours
- delay: 1s
#Rest up
- deep_sleep.enter:
id: deep_sleep_1
until: "06:00:00"
time_id: esptime
text_sensor:
# Reports the ESPHome Version with compile date
- platform: version
name: ${friendly_name} ESPHome Version
select:
#Watering Mode.
#Watering regime allows plant to become quite dry and then get a good watering,
#as opposed to more frequent bang bang watering cycles.
#TODO: More testing.
- platform: template
name: "Watering Mode"
id: watering_mode
optimistic: true
restore_value: true
options:
- Wetting Mode
- Drying Mode
initial_option: Drying Mode
number:
#Upper mositure target (once dry)
- platform: template
name: Moisture Upper Target ${friendly_name}
id: moisture_upper_target
icon: mdi:arrow-collapse-up
optimistic: true
unit_of_measurement: '%'
min_value: 40.0
max_value: 90.0
step: 5.0
restore_value: true
initial_value: 80.0
#Lower Water threshold (triggers watering regime). Need to establish good values.
- platform: template
name: Moisture Lower Threshold ${friendly_name}
id: moisture_lower_threshold
icon: mdi:arrow-collapse-down
optimistic: true
unit_of_measurement: '%'
min_value: 5.0
max_value: 60.0
step: 5.0
restore_value: true
initial_value: 50.0
#Battery Saving Mode Threshold. Trigger longer sleep cycles if below this and hope for sunlight.
- platform: template
name: Battery Saving Threshold ${friendly_name}
id: battery_saving_mode_threshold
icon: mdi:battery-alert
optimistic: true
unit_of_measurement: '%'
min_value: 10.0
max_value: 80.0
step: 5.0
restore_value: true
initial_value: 20.0
#Low water tank threshold. Don't water if below this.
- platform: template
name: Low tank water threshold ${friendly_name}
id: low_tank_water_threshold
icon: mdi:water-remove-outline
optimistic: true
unit_of_measurement: '%'
min_value: 0.0
max_value: 20.0
step: 5.0
restore_value: true
initial_value: 10.0
button:
#Deep sleep if "allowed".
- platform: template
name: Sleep If Allowed ${friendly_name}
internal: ${internal_mode}
id: sleep_if_allowed
icon: "mdi:sleep"
on_press:
then:
- if:
condition:
- binary_sensor.is_on: stay_awake_sensor
then:
- logger.log: "Sleep requested but STAY AWAKE mode is on. Skipping sleep."
- deep_sleep.prevent: deep_sleep_1
else:
- logger.log: "Sleep requested and ALLOWED. Going to sleep..."
- deep_sleep.enter:
id: deep_sleep_1
sleep_duration: ${sleep_time}
#Force Deep Sleep
- platform: template
name: Force Sleep ${friendly_name}
id: force_deep_sleep
icon: "mdi:bell-sleep"
internal: ${internal_mode}
on_press:
then:
- logger.log: "FORCE SLEEP requested...Going to sleep"
- deep_sleep.enter:
id: deep_sleep_1
sleep_duration: ${sleep_time}
#Long Sleep (part of battery saving mode)
- platform: template
name: Long Sleep ${friendly_name}
id: long_deep_sleep
internal: ${internal_mode}
icon: "mdi:bell-sleep"
on_press:
then:
- logger.log: "LONG SLEEP requested...Going to sleep"
#Publish battery level to the end of day sensor since it will be our last update.
- lambda: return id(end_of_day_battery_percent).publish_state(id(batt_level).state);
- deep_sleep.enter:
id: deep_sleep_1
sleep_duration: ${long_deep_sleep_duration}
#Reset culmulative light sesnor reset
- sensor.integration.reset: irrigation_cul_lux_hours
binary_sensor:
#Low tank water alert
- platform: template
id: tank_water_level_is_ok
name: Tank Level Ok ${friendly_name}
icon: mdi:water-remove-outline
device_class: moisture
lambda: |-
if (id(water_tank_level).state > id(low_tank_water_threshold).state)
{return true;}
else if (id(water_tank_level).state <= id(low_tank_water_threshold).state)
{return false;}
else
return {};
#Data updates alert. I've had the lux/tof playing up. Seems to be when battery < ~ 40%
- platform: template
id: data_update_problem
name: Sensor Problem ${friendly_name}
icon: mdi:database-alert-outline
device_class: problem
entity_category: diagnostic
#Low Battery alert
- platform: template
id: battery_level_is_low
name: Battery Level Is Low ${friendly_name}
icon: mdi:battery-alert
lambda: |-
if (id(batt_level).state < id(battery_saving_mode_threshold).state)
{return true;}
else if (id(batt_level).state >= id(battery_saving_mode_threshold).state)
{return false;}
else
return {};
on_press:
then:
- button.press: long_deep_sleep #Long deep sleep if battery low.
#Pump Sensor.
- platform: template
id: pump_is_on
name: Pump is On ${friendly_name}
icon: mdi:water-pump
device_class: running
lambda: |-
return id(pump).state;
##################################################
#Data Update Sensors.
#These were useful during dev. Might remove in prod.
#All updated via other sensors.
##################################################
#Moisture
- platform: template
name: Moisture updated ${friendly_name}
id: solar_plant_moisture_level_recieved
internal: ${internal_mode}
#Battery Level
- platform: template
name: Battery level updated ${friendly_name}
id: batt_level_recieved
internal: ${internal_mode}
#Light
- platform: template
name: Lux updated ${friendly_name}
id: irrigation_lux_recieved
internal: ${internal_mode}
#Water level
- platform: template
name: water level updated ${friendly_name}
id: water_tank_level_recieved
internal: ${internal_mode}
#All
- platform: template
name: Data updates done ${friendly_name}
id: all_updates_recieved
icon: mdi:database-refresh-outline
entity_category: diagnostic
lambda: |-
return
id(solar_plant_moisture_level_recieved).state &&
id(batt_level_recieved).state &&
id(irrigation_lux_recieved).state &&
id(water_tank_level_recieved).state
;
on_press:
then:
- binary_sensor.template.publish:
id: data_update_problem
state: OFF
#Log that updates are all done
- logger.log:
format: "All sensors updated after %.1f secs of uptime. Checking if watering is required"
args: [ 'id(uptime_sec).state']
- delay: 100ms
#Water if required and allowed then go to sleep. Note watering will only happen if total system is healthy (by design).
- if:
condition:
and:
#Check if our watering regime wants a water dose
- lambda: return (id(watering_mode).state == "Wetting Mode");
- binary_sensor.is_off: battery_level_is_low # Not in battery saving mode.
- binary_sensor.is_on: tank_water_level_is_ok #Tank Water is ok
- binary_sensor.is_on: auto_water_sensor #Auto water is enabled
then:
- logger.log: "Watering required and allowed"
- switch.turn_on: pump
- delay: ${pump_run_time}
- delay: 1s
- button.press: sleep_if_allowed
else:
- logger.log: "Watering not permitted!!.." #todo log reason?
- button.press: sleep_if_allowed
##################################################
#Deep sleep control
##################################################
#A lot of my logic is remashes of:
#https://www.wirewd.com/make/blog/esphome_sleep_modes
#https://tatham.blog/2021/02/06/esphome-batteries-deep-sleep-and-over-the-air-updates/
#Import HA Deep sleep control
- platform: homeassistant
name: "Stay Awake"
internal: false #I want to know that everyone is talking to each other;)
id: "stay_awake_sensor"
entity_id: input_boolean.keep_esps_awake_switch_ha
icon: "mdi:sleep-off"
entity_category: diagnostic
on_press:
then:
- logger.log: "STAY AWAKE requested from HA. Preventing deep sleep"
- deep_sleep.prevent: deep_sleep_1
on_release:
then:
- logger.log: "STAY AWAKE TURNED OFF. Going to sleep..."
- deep_sleep.enter:
id: deep_sleep_1
sleep_duration: ${sleep_time}
#Import Auto Water control
- platform: homeassistant
name: Auto Water ${friendly_name}
internal: false
id: "auto_water_sensor"
entity_id: input_boolean.auto_water_planty
icon: "mdi:auto-fix"
script:
##################################################
#Pump auto off timer
##################################################
- id: run_pump_for_pump_run_time
then:
- logger.log: "Running pump for ${pump_run_time}"
- delay: ${pump_run_time}
- switch.turn_off: pump
switch:
##################################################
#Pump
##################################################
- platform: gpio
pin: ${pump_switch_pin}
id: pump
name: ${friendly_name} Pump
icon: mdi:water-pump
internal: false
restore_mode: ALWAYS_OFF
on_turn_on: #Auto off timer. Flood protection.
- script.stop: run_pump_for_pump_run_time # Stop any existing timers.
- script.execute: run_pump_for_pump_run_time # Start new timer
##################################################
#Control peripheral power (on solar power manager)
##################################################
- platform: gpio
id: power_peripherals
name: Power Peripherals ${friendly_name}
pin: ${power_peripheral_pin}
internal: true
restore_mode: ALWAYS_ON #Power on when waking from sleep.
globals:
#For daily battery level change (below). i.e net energy production or loss.
#Globals survive deep sleep
- id: previous_value
type: float
restore_value: yes
initial_value: '0.0'
sensor:
#Track end of day battery
- platform: template
name: End of Day Battery ${friendly_name}
id: end_of_day_battery_percent
update_interval: never
icon: "mdi:solar-power"
unit_of_measurement: '%'
accuracy_decimals: 3
on_value:
then:
#Calculate change in end of day battery and publish to sensor
- lambda: id(change_in_end_of_day_battery_percent).publish_state(x - id(previous_value));
#Set previous value as current value.
- lambda: |-
id(previous_value) = x;
#Track daily changes in battery (i.e net solar production)
- platform: template
name: Change in End of Day Battery ${friendly_name}
id: change_in_end_of_day_battery_percent
icon: mdi:trending-up
internal: false
unit_of_measurement: '%'
accuracy_decimals: 3
#Uptime sensor
- platform: uptime
id: uptime_sec
name: Uptime Sensor ${friendly_name}
update_interval: 2s
accuracy_decimals: 0
unit_of_measurement: s
##################################################
#For counting data updates recieved for each wake cycle.
#Manually updated via publishing from other sensors.
##################################################
#Track Lux updates
- platform: template
name: "Count Lux Updates"
id: count_irrigation_lux
icon: "mdi:counter"
unit_of_measurement: count
entity_category: diagnostic
#Track ToF updates
- platform: template
name: "Count ToF Updates"
id: count_irrigation_tof
unit_of_measurement: count
entity_category: diagnostic
#Track battery updates
- platform: template
name: "Count Batt V Updates"
id: count_batt_voltage
unit_of_measurement: count
icon: "mdi:counter"
entity_category: diagnostic
##########################################################################################
# Time of Flight sensor - i2c
##########################################################################################
#Powered via 5v
- platform: vl53l0x
id: tof
i2c_id: vl53l0x_i2c_bus
# setup_priority: 300
name: ToF ${friendly_name}
internal: false
address: 0x29
timeout: 300ms
update_interval: never
entity_category: diagnostic
#never
# enable_pin: GPIO17 #Did not work: https://github.com/esphome/issues/issues/3644
accuracy_decimals: 1
unit_of_measurement: 'cm'
filters:
- multiply: 100 #Convert to cm
- median: #Moving median to smooth noise. Sample 5 points then push.
window_size: 5
send_every: 5
send_first_at: 5
on_raw_value:
then: #Push sensor update counter.
- lambda: id(count_irrigation_tof).publish_state(id(count_irrigation_tof).state +1);
#Convert the ToF distance to a water tank level (% full)
- platform: copy
source_id: tof
id: water_tank_level
internal: false
# icon: "mdi:battery"
name: Water Tank Level ${friendly_name}
unit_of_measurement: '%'
accuracy_decimals: 1
entity_category: ''
filters:
# Map from distance to % full. To calibrate.
- calibrate_linear:
- 3 -> 100
- 19.5 -> 0
##Overide values less than 0% and more than 100%. Round to 0.5%.
- lambda: |
if (x > 100) return 100;
else if (x < 0) return 0;
else return ceil(x / 0.5) * 0.5;
on_value:
then:
- binary_sensor.template.publish:
id: water_tank_level_recieved
state: ON
##########################################################################################
# bh1750 Lux/light sensor
##########################################################################################
- platform: bh1750
id: irrigation_lux
i2c_id: bh1750_i2c_bus
# - id: bh1750_i2c_bus
# sda: GPIO25 #data > green wire
# scl: GPIO27 #clock > blue wire
# scan: true
# - id: vl53l0x_i2c_bus
name: Lux ${friendly_name}
address: 0x23
update_interval: never
filters:
- median: #Use moving median to smooth noise. Sample 5 points then send.
window_size: 5
send_every: 5
send_first_at: 5
on_value:
then:
- binary_sensor.template.publish:
id: irrigation_lux_recieved
state: ON
on_raw_value:
then:
#Sensor update counter.
- lambda: id(count_irrigation_lux).publish_state(id(count_irrigation_lux).state +1);
#Measure of total light per day. Poor persons DLI https://en.wikipedia.org/wiki/Daily_light_integral
- platform: integration
name: "Light per day"
id: irrigation_cul_lux_hours
sensor: irrigation_lux
time_unit: s
unit_of_measurement: lux*s
restore: true
accuracy_decimals: 0
#Notes:
#Voltage divider: Used 2 x 300K Ohm resistors
- platform: adc
id: batt_voltage
name: Battery Voltage ${friendly_name}
internal: true
pin: ${batt_voltage_pin} #ADC1
update_interval: never
accuracy_decimals: 2
attenuation: auto
filters:
# #Scale it back up from voltage divided value 2 x 300K > 2.1. 4.2/2.1 = 2.
- multiply: 2
on_raw_value:
then:
#Sensor update counter.
- lambda: id(count_batt_voltage).publish_state(id(count_batt_voltage).state +1);
#Intermediate sensor. Might consolidate them later.
- platform: copy
source_id: batt_voltage
id: batt_voltage_filtered
icon: "mdi:battery"
internal: false
name: Battery Voltage ${friendly_name}
unit_of_measurement: V
accuracy_decimals: 2
filters:
- median: #Use moving median to smooth noise.
window_size: 10
send_every: 10
send_first_at: 10
#Convert the Voltage to a battery level (%)
- platform: copy
source_id: batt_voltage_filtered
id: batt_level
internal: false
icon: "mdi:battery"
name: Battery Percent ${friendly_name}
unit_of_measurement: '%'
accuracy_decimals: 0
filters:
# Map from voltage to Battery level
- calibrate_linear:
- 3.1 -> 0 #Set 3.0 to 0% even though it can go lower (2.4V), for life extention. There's not much capacity below this anyway.
- 4.1 -> 100 #Set 4.05 to 100% even though it can go higher (~4.2V), for life extention.
#Overide values less than 0% and more than 100%
- lambda: |
if (x < 0) return 0;
else if (x > 100) return 100;
else return ceil(x / 5) * 5;
on_value:
then:
#Publish that data is recieved
- binary_sensor.template.publish:
id: batt_level_recieved
state: ON
#Capacitive soil moisture sensor: https://www.aliexpress.com/item/32832538686.html?spm=a2g0o.order_list.0.0.55771802WgNqEA
#Voltage of the Capacitive soil moisture sensor
- platform: adc
name: Soil Moisture Volts ${friendly_name}
id: soil_moisture_voltage
pin: ${soil_moisture_pin}
internal: false
accuracy_decimals: 1
update_interval: never
# never
attenuation: auto
filters:
- median: #Use moving median to deal with noise. Sample 10, push 1.
window_size: 10
send_every: 10
send_first_at: 10
#Convert the Voltage to a moisture level (%)
- platform: copy
source_id: soil_moisture_voltage
id: solar_plant_moisture_level
name: Soil Moisture ${friendly_name}
internal: false
icon: "mdi:water-percent"
unit_of_measurement: '%'
accuracy_decimals: 1
filters:
#max and min values taken from testing with glass of water. Prob need to do in-situ tests.
- calibrate_linear:
- 1.66 -> 100.0
- 2.90 -> 0.0
#Handle/cap boundaries
- lambda: |
if (x < 0) return 0;
else if (x > 100) return 100;
else return (x);
on_value:
then:
#Data update recieved.
- binary_sensor.template.publish:
id: solar_plant_moisture_level_recieved
state: ON
#Help manage the watering mode.
#TODO: Monitor/test
- lambda: |-
if (x < id(moisture_lower_threshold).state)
{ return id(watering_mode).publish_state("Wetting Mode");}
else if (x > id(moisture_upper_target).state)
{ return id(watering_mode).publish_state("Drying Mode");}
on_value_range:
#Help manage the watering mode.
- below: !lambda return id(moisture_lower_threshold).state;
then:
- lambda: return id(watering_mode).publish_state("Wetting Mode");
- above: !lambda return id(moisture_upper_target).state;
then:
- lambda: return id(watering_mode).publish_state("Drying Mode");
This post is for content relating to itās operation.
Iāll start with a high level description. It essentially works very similar to other irrigation and deep sleep projects projects around:
- Wake up from deep sleep periodically and see if the plant needs water. If so, water, if not, back to sleep.
- Donāt water the plant if battery is low, instead, go back to sleep for a long time and hope you get recharged on next wake.
- Donāt water the plant if the tank level is low.
- The watering regime might be described as āincremental drip-feed towards an upper target, followed by drying towards a lower thresholdā. This lets the plant dry out a bit, then āgives it a good water, but slowly rather than all at onceā⦠I still need to monitor that this is working ok.
- The light sensor is handy for checking how much light both the plant and the solar panel is getting.
Basically I built my first voltage divider.
Thereās some details over here for it actually. But itāll try to remember to tidy it up and add something here for it. It was harder to find simple info for it than expected. My final solution changed slightly to whatās in this link.
I moved to using 2 x 300kOhm resistors. Itās a simpler set-up. Thereās also a few comments in my config about the resistors used and scaling/conversions.
Battery Monitoring
Summary:
- I made my first voltage divider. You need two resistors. I landed on 2 x 300kā¦
- Wire them like below. I think itās right. I wanted to keep the diagram simple and didnāt want to draw up my full wiring yet. You just add extra wires for power and ground as you need for your other devices
Longer version and resources:
- Article: ESP8266 battery level meter | ezContents blog 37,
- Thread: ESPHome Battery Level Sensor 48,
- Some help/checks from @ssieb over on Discord ,
From what I could understand the sum of the resistors should be high and the divided voltage should be < 2.4V
Which led me to my 2 x 300k⦠selection. I also like this āsymmetricā design. Doesnāt matter which way you wire it.
Battery sensor snippet
#Notes:
#Voltage divider: Used 2 x 300K Ohm resistors
- platform: adc
id: batt_voltage
name: Battery Voltage
internal: true
pin: ${batt_voltage_pin} #ADC1
update_interval: never
accuracy_decimals: 2
attenuation: auto
filters:
# #Scale it back up from voltage divided value 2 x 300K > 2.1. 4.2/2.1 = 2.
- multiply: 2
on_raw_value:
then:
#Sensor update counter.
- lambda: id(count_batt_voltage).publish_state(id(count_batt_voltage).state +1);
#Intermediate sensor. Might consolidate them later.
- platform: copy
source_id: batt_voltage
id: batt_voltage_filtered
icon: "mdi:battery"
internal: false
name: Battery Voltage
unit_of_measurement: V
accuracy_decimals: 2
filters:
- median: #Use moving median to smooth noise.
window_size: 10
send_every: 10
send_first_at: 10
#Convert the Voltage to a battery level (%)
- platform: copy
source_id: batt_voltage_filtered
id: batt_level
internal: false
icon: "mdi:battery"
name: Battery Percent
unit_of_measurement: '%'
accuracy_decimals: 0
filters:
# Map from voltage to Battery level
- calibrate_linear:
- 3.1 -> 0 #Set 3.0 to 0% even though it can go lower (2.4V), for life extention. There's not much capacity below this anyway.
- 4.1 -> 100 #Set 4.05 to 100% even though it can go higher (~4.2V), for life extention.
#Overide values less than 0% and more than 100%
- lambda: |
if (x < 0) return 0;
else if (x > 100) return 100;
else return ceil(x / 5) * 5;
on_value:
then:
#Publish that data is recieved
- binary_sensor.template.publish:
id: batt_level_recieved
state: ON
@Mahko_Mahko, Iām trying to learn from your code, but I canāt really make it work. Iām focusing on the deep sleep logic and Iām trying to understand how it works.
as you can see my esp is ignoring the button to prevent deep sleep and the fact to sleep during the night, it constantly follows the cycle defined by the variables, in my case 30min sleep, 30min run
run_duration: 30min
sleep_duration: 30min
can you help me to understand what Iām missing?
binary_sensor:
- platform: homeassistant
id: prevent_deep_sleep
entity_id: input_boolean.prevent_deep_sleep
icon: "mdi:sleep-off"
entity_category: diagnostic
on_press:
then:
- logger.log: "STAY AWAKE requested from HA. Preventing deep sleep"
- deep_sleep.prevent: deep_sleep_control
on_release:
then:
- logger.log: "STAY AWAKE TURNED OFF. Going to sleep..."
- deep_sleep.enter:
id: deep_sleep_control
sleep_duration: ${sleep_duration}
time:
- platform: homeassistant
id: homeassistant_time
on_time:
#Deep sleep at 8pm and wake up at 6am.
- hours: 20
then:
#Rest up
- deep_sleep.enter:
id: deep_sleep_control
until: "06:00:00"
time_id: homeassistant_time
deep_sleep:
id: deep_sleep_control
run_duration: ${run_duration}
sleep_duration: ${sleep_duration}
esphome:
on_boot:
- priority: -100
then:
- wait_until:
condition:
api.connected:
- logger.log: "API connected"
- wait_until:
condition:
time.has_time:
- logger.log: "Time has a value from Home Assistant"
- if:
condition:
binary_sensor.is_on: prevent_deep_sleep
then:
- logger.log: "Prevent deep sleep"
- deep_sleep.prevent: deep_sleep_control
else:
- logger.log: "Allow deep sleep"
- deep_sleep.allow: deep_sleep_control
on_shutdown:
priority: -100
then:
- if:
condition:
binary_sensor.is_on: prevent_deep_sleep
then:
- logger.log: "Prevent deep sleep"
- deep_sleep.prevent: deep_sleep_control
else:
- logger.log: "Allow deep sleep"
- deep_sleep.allow: deep_sleep_control
I had to work through some buggyness too at a few points.
Do you have any sensors with a high update_interval (say 1sec). Or are you managing the updates manually?
Try pulling them back to say 5sec for debugging.
Can you see the home assistant sensor being imported in the ESPHOME logs? Try making this NOT internal and check if it comes back re-imported into HA ok. So that it is clear everyone is hearing each other.
I also seem to recall sometimes the input Boolean only seemed to start working once you had toggled it from HA once the esp was online (once). So maybe fiddle with that.
In summary, Iām not sure. Mine is working great but I recall having to work through weird issues.