Hello, I would like to share my experience with building low power alert sensor based on ESPHome. I achieved deep sleep current 12μA with plain ESP8266 module ESP-12F. Full code is below.
I wanted to build a sensor, that regularly (every 10min) checks if the LED on my washing mashine turns ON so I know when it ended washing cycle end then notify me over telegram. The automation and telegram integration are pretty standard things so I will not describe it here. I have solved following challenges:
- Sleep between measurements: this is easily achievable, as the ESPHome directly support deep sleep. I used mqtt and disabled ESPHome api.
- Use WiFi only if alert is needed, otherwise do not attemp to start wifi. This shortens wake time to fraction of second. This was a bit tricky, because ESPHome always turns wifi ON. However, there is a moment when sensor is initialized, but wifi not started. I had to use that moment to check the sensor and go to deep sleep before wifi is started. I tried to use
on_boot:
with various priorities, but it did not work because priorities did not catch the right moment. However,on_loop:
worked. It looks like before starting the loop sensor is initialized and wifi starts only after first loop. If you put sensor condition toon_loop:
, then you can check sensor and send ESPhome to sleep before wifi. - No residual current in voltage divider: I check light by photo resistor. To check its value, I needed to create voltage divider from one resistor and photo resistor, put it between 3.3V and GND and then measure voltage on junction of resistors. However, this schema will create permanent current draw. So I connected the voltage divider beween GPIOs and I create the voltage difference only during measurement.
There were few catches. After I turn on voltage on GPIO, I had to add 100ms delay. Also, when I send ESPHome to deep sleep before it does it on its own, the ESPHome thinks it crashed and after 10 such reboots it would start OTA access point and discharge the battery. Luckily, this behavior can be turned off by safe_mode: false
. I want to turn GPIO power up as early as possible, so I give it priority 900.
Sensor works fine. When wasing mashine LED is off, it measures less than 0.5V, when LED is on, it measures more than 0.5V and only in that case it connects to wifi and reports the value to Home Assistant. There you can catch it with automation and perform actions.
The code:
esphome:
name: mqtt_pracka
platform: esp8266
board: esp12e
on_boot:
priority: 900
then:
- lambda: |-
pinMode(14, OUTPUT);
pinMode(12, OUTPUT);
digitalWrite(14, HIGH);
digitalWrite(12, LOW);
delay(100);
on_loop:
then:
- lambda: |-
if (id(pracka2_pr).state < 0.5) {
ESP.deepSleep(600*1E6, RF_DISABLED);
}
wifi:
ssid: "IoT"
password: "...."
manual_ip:
static_ip: 10.0.0.46
gateway: 10.0.0.138
subnet: 255.255.255.0
dns1: 8.8.8.8
dns2: 8.8.4.4
ap:
ssid: "MQTT Pracka Hotspot"
password: ""
fast_connect: on
captive_portal:
logger:
# Do not enable Home Assistant API
#api:
ota:
safe_mode: false
sensor:
- platform: adc
id: pracka2_pr
pin: A0
name: "Pracka2 Photo Resistor"
retain: true
update_interval: 30s
accuracy_decimals: 3
deep_sleep:
id: deep_sleep_1
run_duration: 4s
sleep_duration: 10min
mqtt:
broker: 10.0.0.54
username: ...
password: ...
birth_message:
topic: mqtt_pracka2/status
payload:
qos: 2
will_message:
topic: mqtt_pracka2/status
payload:
on_message:
- topic: mqtt_pracka2/ota_mode
payload: 'ON'
then:
- deep_sleep.prevent: deep_sleep_1
- topic: mqtt_pracka2/sleep_mode
payload: 'ON'
then:
- deep_sleep.enter: deep_sleep_1
The only last challenge I have is how to measure analog input on A0 pin and battery VCC. It looks like ESPHome only supports one or other method, but not both together. There is only one mqtt message received when I create two adc sensors, one on A0 pin and second on VCC pin. When I had older version that I programmed completely in C++, I could use both and send message based on critical battery level.
It s possible to OTA flash the sensor even if it goes to deep sleep before wifi. I just need to force it to think that light is on - by shortening the photo resistor, and restart it. Then it turns on wifi for 3 seconds and in that moment I can trigger OTA from PC.
An improvement! You do not need external resistor to create voltage divider. You can use internal pullup resistor! You need to program/create digital pin input_pullup, then connect that digital pin to analog and connect photoresistor between analog and ground. Then you can measure voltage on analog pin. I tested in on breadboard and it works well. I will use that approach when building next version of photosensor.