Firmware only working well w̶i̶t̶h̶ ̶a̶ ̶w̶e̶l̶l̶ ̶c̶h̶a̶r̶g̶e̶d̶ ̶b̶a̶t̶t̶e̶r̶y̶ with power supplied by microUSB port

Hello,

I am using a very simple fw configuration with ESP32S MCU board - all it does it blinks internal LED, sends a “ping” to HA (to let it know it’s alive), output status message on OLED display then goes to deep sleep from which it can be woken up by PIR sensor.

Everything is working as expected when powered by microUSB cable. But when I use a freshly charged battery (the board has a built-in battery port) it only runs for a few hours. I suspect that when the voltage drops until a certain level, it just blinks - there is a short break between the blinks so it seems like there is a reset loop.

Board: https://robu.in/product/elecrow-esp32s-wifi-ble-board-v1-0/

Do you have any idea what could be the cause or how to further debug the problem?

Thank you,

jose

Do you disconnect the OLED power when The ESP is asleep?

Have you measured the current drawn from the battery when asleep?

What size battery?

Voltage drop? (meter on the ESP32 module pins)
Battery internal resistance? (bigger cell?)
Poor WLAN signal, so a sagging voltage can’t TX enough?

I tried an ESP8266 Wemos D1 mini with battery shield, a “street lithium” cell from a discarded vape, and a WS2812 lasted a day at moderate brightness.

No, it remains on. But only couple pixels are lit. And I’ve seen the same behaviour even without using OLED (actually I added it to get more insight).

No, as currently I am not able to run the code even with a fully charged battery. When the code is running the multimeter jumps from 40 to 90 mA (suggesting a boot loop).

It’s JA-603048P 800 mAh LiPo.

Sorry, I’m confused. Which of these is the true statement?

It would help if you posted your config.

That’s a valid question. Actually it turns out that I was probably just lucky before and it had nothing to with the battery voltage.

Config is below - please bear in mind that I just started digging into EspHome world.

esphome:
  name: esphome-web-82eb3c
  friendly_name: Wroom32
  min_version: 2025.9.0
  name_add_mac_suffix: false

  on_boot:
    priority: -100
    then:
      - lambda: |-
          id(wakeup_cause) = 1;
      - delay: 2s
      - lambda: |-
          id(wakeup_cause) = 0;
      - delay: 5s
      - lambda: |-
          id(status) = "zz..";
      - component.update: lcd
      - deep_sleep.enter:
          id: deep_sleep_1
          sleep_duration: !lambda "return 20 * 60 * 1000;"

font:
  - file: "fonts/COURIER.ttf"
    id: myfont
    size: 10
    bpp: 2

globals:
  - id: wakeup_cause
    type: int
    restore_value: no
    initial_value: '1'
  - id: status
    type: std::string
    initial_value: '"boot"'
    restore_value: no
  - id: countdown
    type: int
    restore_value: no
    initial_value: '12'

i2c:
  sda: GPIO21
  scl: GPIO22

display:
  - platform: ssd1306_i2c
    model: "SSD1306 64x48"
    id: lcd
    address: 0x3C
    lambda: |-
      it.printf(0, 0, id(myfont), "ST %s", id(status).c_str());
      it.printf(0, 15, id(myfont), "CT %d", id(countdown));

esp32:
  variant: esp32
  framework:
    type: esp-idf

logger:
  level: DEBUG

api:

ota:
- platform: esphome

output:
  - platform: gpio
    pin: GPIO16
    id: ledpin

interval:
  - interval: 1s
    then:
      - delay: 500ms
      - output.turn_on: ledpin
      - delay: 500ms
      - output.turn_off: ledpin
  - interval: 1s
    then:
      - delay: 1000ms
      - lambda: |-
          id(countdown) -= 1;

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

deep_sleep:
  id: deep_sleep_1
  wakeup_pin:
    number: GPIO2
    inverted: false

sensor:
  - platform: template
    id: wakeup_cause_sensor
    name: "Wakeup Cause"
    accuracy_decimals: 0
    update_interval: 1s
    lambda: |-
      return id(wakeup_cause);

script:
  - id: publish_wakeup_cause
    then:
      - lambda: |-
          id(wakeup_cause) = 0;
      - lambda: |-
          ESP_LOGD("custom", "Setting wakeup_cause to 0 before shutdown");
      - component.update: wakeup_cause_sensor

One might question the quality of connection/breadboard but… it’s working 100 % when I am pulling the power via microUSB.

Measured voltage on 3.3V and it’s reading 3.27-3.29.

It’s a small 800 mAh LiPo.

The distance to router is ~ 2 meters. But I haven’t actually tried setting a fixed channel and/or using fast_connect

Possible race condition?

Your interval triggers every 1 second. However the actions you have implemented take at least 1 second to complete.

1 Like

Also this pin:

Is connected to the onbard LED on most ESP32 boards. Choose a different GPIO, see the table lower down on this page: ESP32 Pinout Reference: Which GPIO pins should you use? | Random Nerd Tutorials

Final thing I can think of is that 7 seconds may not be enough time for the ESP to connect to wifi. Wifi is inititalised at boot priority 250 but that does not mean it is connected, AFAIK.

I see several potential issues here but they are not related to battery/usb power.
Did you measure your real battery capacity? Or deep sleep current of your setup?
How are pir and display powered? Something from 5V pin? I don’t know your board, but I would guess you only have regulated 3.3V while on battery.

It seems that there is indeed something wrong with the battery. Here’s a very simplified code:

esphome:
  name: esphome-web-82eb3c
  friendly_name: Wroom32
  min_version: 2025.9.0
  name_add_mac_suffix: false

esp32:
  variant: esp32
  framework:
    type: esp-idf

logger:

api:

ota:
- platform: esphome

output:
  - platform: gpio
    pin: GPIO16
    id: ledpin

interval:
  - interval: 1s
    then:
      - delay: 500ms
      - output.turn_on: ledpin
      - delay: 500ms
      - output.turn_off: ledpin

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

With a USB power it pulses as intended. When powered by battery the pulses are way shorter. There is also a loop of 10 regular blinks, then a longer pause (which I think means that the MCU is restarting).

The meter says the battery voltage is 3.9, but perhaps it’s unable to supply a current in bursts? Sadly, I do not have an oscilloscope to monitor the changes in voltage.

What about hardware, only board and the battery?

Correct, for the latest test I unplugged all the components and even removed it from the breadboard.

You could measure boards 3.3V pin voltage for 10s while powered from battery.

It fluctuates between 3.27 and 3.29.

Weird. So battery voltage is 3.9V and 800mAh one generally can provide sufficient current even on “surges”. And stable Esp rail ~3.3V doesn’t really indicate power problem either.

Makes me wonder if they even come from your program. If you change the interval to 2s, does it affect the behavior?

I edited the interval so that the LED is on for 5 seconds and off for a second:

interval:
  - interval: 6s
    then:
      - delay: 5s
      - output.turn_on: ledpin
      - delay: 1s
      - output.turn_off: ledpin

Nothing changed when it comes to blinking frequency while on battery so it seems that the code is not run at all.

Your code seems to tell it to do the opposite. It’s only on for 1 second.

Ok. that approves that the code is not running at all, it likely just blinks on boot loop. @ShadowFist is right for the timing though.
So voltage levels look good with battery, code is working on usb power… It’s getting tricky. Can you find schematic of your board?
Gpio16 on normal esp board shouldn’t be bonded to anything, but your board has LED on it so it likely has some circuit still not clear to me…

Yes, I checked visually though. LED seems to be using inverted logic.