ESPhome API with Deep_sleep MQTT

Can any more experienced types with IoT confirm my understanding. I am very new to esphome.

The project (my very first) is to measure 5x12v Flooded Battery voltages and send these to HA. This all works completely fine.

The next step is:
deep_sleep mode would save pointless recharge cycles occurring from powering the esp32 and the buck convertor.

The context:
The batteries are remote and “alone” for 6 months or more and hold charge enough for starts when the time comes. This is purely an assurance project.

A solution:
I would like to use long deep_sleep cycles of 7 days or more followed by just enough up time to communicate a single update and then sleep again. This desire generates the firmware update problem.

What I have read up on:
I have read that an MQTT message can be used to prevent deep sleep, so I have started to read up on and configure MQTT.

I have installed MQTT mosquito and the HA integration and all seems to be fine. I have yet to get the board to connect to MQTT broker, I keep getting unauthorised which is something I have not yet fixed. Same password and username in the device.yaml as in the mosquito config. Integration restarted. etc. no dice. Secondary issue at the moment.

Primary issue:
What I have noticed though on my test board, is that all OTA logging stops once the MQTT config block is written into the config and flashed to the device. Also my voltage sensor goes offline.

I think what is going on is that I can’t have MQTT and the API running on the same device at the same time. So what we are then saying is that it’s EITHER native API or MQTT not both?

For test purposes I rely on the API logging feature which gives me allot of useful info really quickly. Once MQTT is enabled all that seems to disappear. Am I missing something obvious with regards to that logging “swapping” over to MQTT if this is the route I am required to go?

I am including the test config yaml in case something in that helps the answers I need.

esphome:
  name: tractor-battery
  friendly_name: "Tractor Battery"

esp32:
  board: esp32-c3-devkitm-1
  framework:
    type: arduino

# Voltage Sensor - short for testing
sensor:
  - platform: adc
    pin: GPIO1
    name: "Tractor Battery Voltage"
    attenuation: auto
    update_interval: 5s

# Sleep Settings - short for testing
deep_sleep:
  run_duration: 2min
  sleep_duration: 10s
  id: deep_sleep_1


# Sleep Prevention - logging for testing
#mqtt:
#  broker: Ip_address
#  username: the_user
#  password: the_password
#  port: 1883
#  on_message:
#    - topic: tractor-battery/deep_sleep
#      payload: 'DISABLED'
#      then:
#        - deep_sleep.prevent: deep_sleep_1
#        - logger.log: "deepSleep is OFF"
#    - topic: tractor-battery/deep_sleep
#      payload: 'ENABLED'
#      then:
#        - deep_sleep.allow: deep_sleep_1
#        - logger.log: "deepSleep is ON"

# Reboot Switch
switch:
  - platform: restart
    name: "Tractor Battery restart switch"

# Presence Sensor
binary_sensor:
  - platform: status
    name: "Tractor Battery Status"

# SNTP Config
time:
  - platform: sntp
    id: sntp_time
    timezone: "Europe/London"
    servers: "192.168.1.1"

# Enable logging
logger:

# Enable Home Assistant API
api:
  reboot_timeout: 0s
  encryption:
    key: "VDMtXkqwakp+kVYaifWTEK/1tH2QivlKqHNa/L/sVBU="

ota:
  - platform: esphome
    password: "adc2d4dae0efe00a4cb933c5a27b4a7c"

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

  # Enable fallback hotspot (captive portal) in case wifi connection fails
  ap:
    ssid: "Tractor-Battery Fallback Hotspot"
    password: "vDIRZ1R0rOIM"

captive_portal:

Finally, are all the sensors exposed in the same way via MQTT, or is that too vague a question?

  1. Can you run MQTT and native API simultaneously on an esp32-c3 board?
  2. Can I get the same friendly logging over MQTT like I get from the API [once I get it to connect]
  3. Is sensor configuration largely the same in MQTT, if I do have to go MQTT entirely.

Thanks for any pointers.

ESP home warns you not to run API and MQTT together

Not sure what friendly logging means but logging still occurs

MQTT sensors are discovered automatically so you won’t know the difference from API. Instead of finding it in esphome integration it will be in MQTT integration.

1 Like

Nothing gets logged when device is in deepsleep. MQTT will record the sensors as unavailable. To avoid gaps in graphs you can adjust the Last will and testament topics so this isn’t recorded.

  birth_message:
    topic: weathersmall/birth
    payload: 'ON'
  will_message:
    topic: weathersmall/willdisable
    payload: disable

This is how I did it . Payload doesn’t matter just topics must be different

  • publish_nan_as_none (Optional, bool): Publish None instead of NaN to handle Unknown/Unavailable sensor states in Home Assistant. Defaults to false.
  • This may also work but I haven’t tried it. May be in a response to the old problem of unavailable in deep sleep

Thank you Spiro

Actually: I read that link many times today and do not see a warning in there, what am I missing? The statement I am referring to is the one in red which states:

" If you enable MQTT and you do not use the Native API Component, you must remove the api:"

But I do want to use the API so I did not remove the configuration for it and I was expecting it to work.

Are you saying it will not work?

This is the logging which I get by clicking logging.

INFO ESPHome 2025.4.1
INFO Reading configuration /config/esphome/tractor-battery.yaml...
INFO Starting log output from 192.168.1.158 using esphome API
INFO Successfully connected to tractor-battery @ 192.168.1.158 in 0.135s
INFO Successful handshake with tractor-battery @ 192.168.1.158 in 0.092s
[18:23:21][I][app:100]: ESPHome version 2025.4.1 compiled on Apr 30 2025, 16:56:10
[18:23:21][C][wifi:600]: WiFi:
[18:23:21][C][wifi:428]:   Local MAC: redacted
[18:23:21][C][wifi:433]:   SSID: [redacted]
[18:23:21][C][wifi:436]:   IP Address: 192.168.1.158
[18:23:21][C][wifi:440]:   BSSID: [redacted]
[18:23:21][C][wifi:441]:   Hostname: 'tractor-battery'
[18:23:21][C][wifi:443]:   Signal strength: -59 dB ▂▄▆█
[18:23:21][C][wifi:447]:   Channel: 6
[18:23:21][C][wifi:448]:   Subnet: 255.255.255.0
[18:23:21][C][wifi:449]:   Gateway: 192.168.1.1
[18:23:21][C][wifi:450]:   DNS1: 192.168.1.1
[18:23:21][C][wifi:451]:   DNS2: 0.0.0.0
[18:23:21][C][logger:177]: Logger:
[18:23:21][C][logger:178]:   Max Level: DEBUG
[18:23:21][C][logger:179]:   Initial Level: DEBUG
[18:23:21][C][logger:181]:   Log Baud Rate: 115200
[18:23:21][C][logger:182]:   Hardware UART: USB_CDC
[18:23:21][C][adc.esp32:058]: ADC Sensor 'Tractor Battery Voltage'
[18:23:21][C][adc.esp32:058]:   Device Class: 'voltage'
[18:23:21][C][adc.esp32:058]:   State Class: 'measurement'
[18:23:21][C][adc.esp32:058]:   Unit of Measurement: 'V'
[18:23:21][C][adc.esp32:058]:   Accuracy Decimals: 2
[18:23:21][C][adc.esp32:059]:   Pin: GPIO1
[18:23:21][C][adc.esp32:061]:   Attenuation: auto
[18:23:21][C][adc.esp32:080]:   Samples: 1
[18:23:21][C][adc.esp32:081]:   Sampling mode: average
[18:23:21][C][adc.esp32:082]:   Update Interval: 5.0s
[18:23:21][C][restart:068]: Restart Switch '$friendly_name restart switch'
[18:23:21][C][restart:070]:   Icon: 'mdi:restart'
[18:23:21][C][restart:091]:   Restore Mode: always OFF
[18:23:21][C][captive_portal:089]: Captive Portal:
[18:23:21][C][sntp:042]: SNTP Time:
[18:23:21][C][sntp:045]:   Server 0: '192.168.1.1'
[18:23:21][C][mdns:116]: mDNS:
[18:23:21][C][mdns:117]:   Hostname: tractor-battery
[18:23:21][C][esphome.ota:073]: Over-The-Air updates:
[18:23:21][C][esphome.ota:074]:   Address: tractor-battery.local:3232
[18:23:21][C][esphome.ota:075]:   Version: 2
[18:23:21][C][esphome.ota:078]:   Password configured
[18:23:21][C][safe_mode:018]: Safe Mode:
[18:23:21][C][safe_mode:020]:   Boot considered successful after 60 seconds
[18:23:21][C][safe_mode:021]:   Invoke after 10 boot attempts
[18:23:21][C][safe_mode:023]:   Remain in safe mode for 300 seconds
[18:23:21][C][api:140]: API Server:
[18:23:21][C][api:141]:   Address: tractor-battery.local:6053
[18:23:21][C][api:143]:   Using noise encryption: YES
[18:23:21][C][deep_sleep:026]: Setting up Deep Sleep...
[18:23:21][C][deep_sleep:029]:   Sleep Duration: 10000 ms
[18:23:21][C][deep_sleep:032]:   Run Duration: 120000 ms
[18:23:22][D][sensor:094]: 'Tractor Battery Voltage': Sending state 2.93849 V with 2 decimals of accuracy
[18:23:27][D][sensor:094]: 'Tractor Battery Voltage': Sending state 2.93849 V with 2 decimals of accuracy

All the info I need on each component and the sensor output, deep_sleep entry / exit all in one continuous helpful spew.

Cool - that makes sense - thank you so much!

Yep that all makes sense. I would like to have that problem set instead of my current ones! Not “quite” there yet :laughing:

Well then , yes all that log stuff still appears. To reduce energy use you may want to set log level to WARNING or NONE and send the device to sleep again once mqtt gets the sensor readings. Depends how much energy you want to save. I use low capacity cells in my project with small solar panel/ESP8266 and always want to use as little energy as possible. Good luck

Ah ok - purrfect.

So I just need to solve the secondary issue and that should then reveal the way forward with the MQTT side.

Thank you - this has been super helpful!

For anyone reading this in future - I was able to determine the login issue by going into supervisor and restarting mosquito - broker.

This then complained that there was an unknown option “Logins” and then the problem became more obvious in the yaml for the component. The solution was that I had placed the logins in the wrong location in the file and not in the logins: section where they needed to be.
Once I restarted the component ITS log file stated it was setting up a new user with my special username.

I want to do it this way as opposed to using a new user in ha since I don’t want any other username to be present in ha (except my actual family members) as it’s yet another surface for the red team to plug away at.

This method makes the auth entirely internal to MATT my own network only which is what I want.

@ Spiro - thanks again, devices now appearing in MQTT.

Update - also I am getting API logging AS WELL.
So my deduction is that API blocks until MQTT has connected.
Both are working together as per my understanding of the docs!

Now to solve the double sensor problem!

I’m not so sure if you can do that. Do some research.

Good point the docs state the duration parameter is a UINT32 which means we can do 4294 seconds max.

([uint32]::MaxValue) / 1000000 = 4294.967295

However on the esp32 we can also specify a time, within the 24 hour clock to awake, so we could get 23 hours of sleep time that way. Still a way off 7 days though, ho hum…

Thanks for the pointer!

You can make a counter to ten and go back to sleep immediately 9/10. Only at ten you connect and do your MQTT or whatever.

That’s a good idea.

I am really only kicking it around at the moment because testing such long sleep times will require more code and that takes something I don’t have too much of at the moment. More time.

Refinements will come.

Deep sleep is not the most sophisticated element of Esphome…