Loosing my mind. Esphome, deep sleep and Mqtt won't work together

Hi

Trying to make a weather station for my garden. I would like to be able to send OTA to my node when in deep sleep.

I have made the suggested implementation using Mqtt using an ON and an OFF message. These are controlled by a switch from the UI. I use Node Red and can send the required messages. However, when I want the esp to sleep it never wakes up again to send data, but strangely I can use the Mqtt ON to wake it. If I remove the Mqtt and just do plain deep sleep it works just fine. I am going nuts.

i2c:
  scan: False
  sda: D3
  
mqtt:
  broker: secret
  port: 1883
  username: secret
  password: secret
  topic_prefix: ${devicename}
  birth_message:
  will_message:
  on_message:
    - topic: switch/ude/ota_update
      payload: 'ON'
      then:
        - deep_sleep.prevent: deep_sleep_1
    - topic: switch/ude/ota_update
      payload: 'OFF'
      then:
        - deep_sleep.enter: deep_sleep_1


deep_sleep:
  id: deep_sleep_1
  run_duration: 30s
  sleep_duration: 30s

sensor:
  - platform: bme280
    temperature:
      name: "BME280 Temperature"
    pressure:
      name: "BME280 Pressure"
    humidity:
      name: "BME280 Humidity"
    address: 0x76
    update_interval: 5s


Do you have GPIO16 connected to RST on your board?

Yes.

I think I need to implement a clear of the retained message. I might be stuck in either always on or always off.

I am a total newbie in ESPHome, but here’s how I handle OTA and sleep in my garden. (NOT on ESPHome, but maybe it will give you an idea.)

To go into OTA, I publish a message to the garden ESP command topic with the message “OTA”. When the garden ESP wakes up, it gets the message to set the otaFlag. When the otaFlag is set, ESP.deepSleep is never executed, so the program finishes setup() and drops into loop() where the OTA is handled.

void setup(){
....	
if (!otaFlag) {                //If the otaFlag is set, then drop into loop to wait for the ota upload.
    // ---------- Sleep ----------
    pinMode(D0, WAKEUP_PULLUP);
    ESP.deepSleep(sleepSeconds * 1000000);
  }
}

void loop(void) {
  // We only get here if the otaFlag is true, meaning the ESP never went to sleep.
  ArduinoOTA.handle();
  ArduinoOTA.onEnd([]() {
    otaFlag = false;
  });
}
	

Again, this is not done in ESPHome, but presented as an idea.

1 Like

Hi, i have it like this (complete example below) and it works without any issues. I don’t subscribe to the “off” message within the ESP.

If you can “wake” your ESP with the “ON” message it’s not in deep sleep, the wifi is not active during deep sleep and the ESP can’t receive any messages in that state (that would defeat the purpose of saving battery).

I have a script that I trigger in Home Assistant when I want to update the sensors with something (I have the same for all of them). And when the ESP wakes up it sees the payload “ON” and prevents deep sleep. Then I send the update and when that is complete I send the “OFF” to the MQTT server and reboot the ESP, and everything is then back to normal. I could also monitor the “OFF” payload and reboot automatically I guess.

The only problem is that when you go to update the ESP it is almost always in the beginning of the deep sleep cycle so the wait time is always close to maximum (feels like that anyway :smiley: ).

substitutions:
  devicename: wemos_weather_station
  friendly_devicename: weather station

esphome:
  name: $devicename
  platform: ESP8266
  board: d1_mini_pro

wifi:
  fast_connect: true
  ssid: !secret wifi_ssid
  password: !secret wifi_password
  manual_ip:
    static_ip: 192.168.1.201
    gateway: 192.168.1.1
    subnet: 255.255.255.0

  # Enable fallback hotspot (captive portal) in case wifi connection fails
  ap:
    ssid: "Wemos WS Fallback Hotspot"
    password: !secret ota_password

#NO API when using battery device
#
# api:
#   password: !secret api_password

mqtt:
  broker: '192.168.1.7'
  username: !secret mqtt_username
  password: !secret mqtt_password
  discovery: false
  discovery_retain: false
  birth_message:
  will_message:
  on_message:
    - topic: esp/ota_mode
      payload: 'ON'
      then:
        - deep_sleep.prevent: deep_sleep_1

# Enable logging
logger:
  level: INFO
  # level: DEBUG

ota:
  password: !secret ota_password

dallas:
  - pin: D1

sensor:
  - platform: dallas
    address: 0x9880000027076228
    name: "temp1"
    id: temp1
    filters:
      filter_out: nan

  - platform: dallas
    address: 0x2D80000027110B28
    name: "temp2"
    id: temp2
    filters:
      filter_out: nan

  - platform: wifi_signal
    name: $friendly_devicename signal strength

  - platform: adc
    pin: A0
    name: $friendly_devicename battery voltage
    id: battery_volt
    icon: "mdi:battery"
    unit_of_measurement: "V"
    accuracy_decimals: 2
    filters:
      - multiply: 5.15

  - platform: template
    name: "$friendly_devicename battery"
    unit_of_measurement: "%"
    icon: "mdi:battery"
    accuracy_decimals: 0
    update_interval: 4s
    lambda: |-
      return ((id(battery_volt).state - 3.1) / 1.1 * 100);
    
  - platform: uptime
    name: $friendly_devicename run time
    unit_of_measurement: ms
    update_interval: 500ms
    filters:
      - multiply: 1000

switch:
  - platform: restart
    name: $friendly_devicename restart switch

deep_sleep:
  id: deep_sleep_1
  sleep_duration: 300s
  run_duration: 1s

Scripts that are on the “ESP-page” in my setup…

alias: ESP OTA mode on
sequence:
  - data:
      payload: 'ON'
      retain: true
      topic: esp/ota_mode
    service: mqtt.publish
mode: single

alias: ESP OTA mode off
sequence:
  - data:
      payload: 'OFF'
      retain: true
      topic: esp/ota_mode
    service: mqtt.publish
mode: single

Thx for the answer. I am not sure I understand what you mean with “esp-page” in my setup. Can you enlighten me?

Hi,

See this note from ESPHome deep sleep component

While in deep sleep mode, the node will not do any work and not respond to any network traffic, even Over The Air updates.

Did you figure this out yet? I finally got mine to work.
I think the “esp page” was a separate view in Home Assistant.

@veirum yes, like @stevemann says, the “esp-page” I was referring to is in HA and just has all of the esphome stuff including a quick way to just activate these scripts :grinning:, that was what I meant.

Thx all. Use I have the pin connected and got it sorta working. I will take a closer look at yours Lasse and see how aĂŤ can improve mine.

might sound very noob but is that a dashboard or it inside esphome or how do you set it up?

No dashboard, just added everything on the same standard Lovelace page. I went to the integration page under Configuration → Integrations. Opened the ESP-boards and added everything were it says “Add to lovelace”.

On the page were everything is added (I mostly use Glance or just Entities-cards) I added a new card with buttons for the script that is in my post above. This way I can then activate the OTA-scripts on and off and see most of the ESP-boards in the same view.

When I need to change something in the ESP code or just update the little things I first go and edit that under the ESPHome dashboard. I then activate the script to send the persistent message for OTA ON. Then we just have to wait for the ESPs that are on battery to wake up, recieve the OTA on that pervent the deept sleep and stay on. From there we just issue the update over the air (OTA) through the ESPHome dashboard, when the compilation is done and the ESP has recied the update I usually check some of the logs, and then activate the other script for OTA Off. After that all the ESPs have to reboot in order to be able to go back to sleep again. I guess you could also active the OTA off script before doing the update through the ESPHome dashboard but I usually wan’t to see that ewverything runs as it should before I let the things go to sleep again. There is of course some battery drain when doing this since the ESP will stay on until you reboot the device again but it’s not that often a new firmware is required.

Long response but I hope it’s helps :slight_smile: .

type: custom:button-card
alias: ESP OTA mode on
sequence:
  - data:
      payload: 'ON'
      retain: true
      topic: esp/ota_mode
    service: mqtt.publish
mode: single

alias: ESP OTA mode off
sequence:
  - data:
      payload: 'OFF'
      retain: true
      topic: esp/ota_mode
    service: mqtt.publish
mode: single

that gives me an error

Configuration errors detected:
duplicated mapping key (11:1)

8 | service: mqtt.publish
9 | mode: single
10 |
11 | alias: ESP OTA mode off
------^
12 | sequence:
13 | - data:

btw… what battery do you use? and how long does it last?

Ah, the scripts are just as it says scripts, not to be added directly on a lovelace card… that needs to be added under Scripts in Configuration, you need to add two scripts, one for on and one for off.

The card then looks like this:

I am using two old 18650 from an old laptop battery I butchered a long time ago. Holds up quite well together with a small solar panel, I never recharge them. My design springs from this one (link) if we are talking about the temperature-station. But I built mine in a blocked off bird house with two 3D-printed Stevenson Screens (Thingiverse) on either side of it. On of the screens have a DS18B20 and the other one houses a BME280.

thanks, i’m trying to build the same as you

one thing i have trouble with is getting the voltage to turn up correctly

  - platform: adc
    pin: A0
    name: $friendly_devicename battery voltage
    id: battery_volt
    icon: "mdi:battery"
    unit_of_measurement: "V"
    accuracy_decimals: 2
    filters:
      - lambda: return x * 2.266666666666667;

i use a voltage divider (680 and 300 ohm) as the ADC on 8266 only goes to 1V
when i messure with voltmeter i get 3.2 before the divider and about 0.95 after

2.266666666666667 is of course the theoretical value to multiply with,

my problem is that i only get 0.73V, i assume i do something to wrong but cant figure out what

that gives me 1.65V

for now i have just set the pin to VCC and not A0

but i wonder what i screwed up

“final” code so far : substitutions: devicename: temperature_sensor_1 friendly_devicename: Tempe - Pastebin.com

EDIT:

for some reason mqtt do not work, i use the chrome app lens to check topics and nothing happens when i execute the scripts

my broker Mosquitto is setup to allow anonymous posting as its not exposed to the outside world anyway

EDIT EDIT:

image

so it do work, i guess the access from outside my raspberry pi (but STILL on local network) is not allowed, its also the first time my local devices need access to home assistant

This will depens on what kind of voltage divider you set up. If you have a Lolin (Wemos) board or something similar (and I believe the NodeMCU also has this) there is a voltage divider already built in so that the A0 accepts 3.3V input at max. Your setup needs to be configured to account for this and your resistors might need to change. You should be fine with having for example R1=300 and R2=1000 to get roughly 3.2V from a max 4.2V battery.

If you are using the VCC on a ESP8266 board you must first remove all connections to A0. There is some useful information here: Analog To Digital Sensor — ESPHome