Wake on Bluetooth Connect (alternatively, power consumption)

I have a hobbyist project build a weather sensor based on Xiao ESP32C6. The sensor will be polled every 5 minutes or so by another device (…actually a repurposed Raspberry Pi Zero2W..) via bluetooth. I poll so infrequently because I need the sensor to have a battery life of weeks or even months from a small 320mAh battery.

My problem is getting the ESP32C6 to wake from light sleep when the Pi connects via bluetooth. After reading posts here, I know the device can’t wake from deep sleep on BT connect, but it also seems it won’t even wake from light sleep on BT connect. So, I have a series of questions:

  1. Is it really not possible to wake the ESP32C6 from any sleep on bluetooth connect?
  2. Do any of the other Xiao devices support both BLE and wake on connect? (I’d happily swap chips for an easier life!)
  3. The problem with using a timer to wake from sleep is getting the timing right with such infrequent polling. Does anyone have any suggestions about best strategy to wake up fopr external polling?

TIA for any helpful suggestions

Steve

Consider posting the values on the Raspberry Pi. The strategy is: sleep as much as reasonable, then make the Xiao establish a connection to the Pi. Note that the Pi (or Xiao) can be both a BLA server and client at the same time.

Ever easier on the battery life: set up a beacon profile on the Xiao and include (up to 32bytes) the sensor data into the beacon payload. If privacy is an issue then you can encode the payload. Note that this way the Xiao will not know if anybody will receive the message.

I used both methods for a soil humidity sensor. I programmed the Xiao to read the sensor every hour but to send the information only if there was a change of 10%, and I have it working on a 18650 for almost a year.

Hi there,

So, The physics and BLE spec don’t really allow that unless you have some always-on external companion chip doing the listening. and Yeah, the instinct about “put the data in the advertisement and keep the Central awake” is actually the most realistic workaround here. Let’s go through the constraints and then talk about what does work in practice.

1. Can ESP32-C6 wake from sleep on BLE connect?

Short answer: no, not the way you’d like.

On the ESP32 family (including C6), BLE activity cannot be used as a wake source from deep sleep, and in practice you also don’t get a clean “wake on connect” from light sleep in the way a low-power peripheral would ideally behave.

  • Deep sleep: only RTC GPIO, timer, ULP / coprocessor, etc., can wake the chip. BLE radio is completely off.
  • Light sleep: Wi-Fi / BT can sometimes be used while napping the CPU, but the radio has to remain in a mode that keeps power higher and requires active stack participation. For ultra-low-duty battery devices (weeks/months on 320 mAh) it’s not suitable.

So: you cannot rely on “Pi connects → C6 wakes from true low-power sleep”. To do that, the radio would already have to be awake and listening, which wipes out your battery budget. Definitely NOT with a coin Cell

2. Other XIAO boards that can “wake on connect”?

Even on Nordic chips (nRF52 / nRF54) used in XIAO boards, the pattern is basically the same:

  • BLE cannot wake from full power-off–style deep sleep (where RAM and radio are off).
  • You can keep the radio in a low-duty connected mode or periodic advertising, and sleep the CPU between events, but that’s not the same as “true deep sleep” – current is usually in the 10s–100s of µA range, not nA.

So swapping to another XIAO (nRF52840, nRF54L15, ESP32-S3, etc.) won’t magically give you “wake from totally dead by BLE connect”.
You can do very efficient always-advertising or always-connected-but-idling on something like nRF52 and still get months of life on a coin cell, but that’s a different operating mode than full deep sleep.

3. Practical strategy for your :index_pointing_at_the_viewer: use case :grin:

Your constraints:

  • Battery: ~320 mAh
  • Poll interval: ~every 5 minutes
  • Central: Raspberry Pi Zero2W
  • Peripheral: XIAO ESP32-C6
  • Desired behavior: Central “asks”, Peripheral wakes, sends data

Given what the hardware can do, the simplest, robust, low-power design is this:

Option A – Broadcast weather in advertisements

Have the ESP32-C6 act as a pure advertising beacon: (@Sergio_J 'Idea)
I believe @msfujino did something similar in a project as well..

  1. Every 5 minutes (or whatever interval you like):
  • Wake from deep sleep by timer.
  • Take sensor readings.
  • Encode the latest readings into the advertising payload (or scan response).
  • Advertise for a short window (e.g., 5–10 seconds).
  • Go back to deep sleep.
  1. On the Pi side:
  • Keep BLE scanning always on, or in a periodic scan pattern.
  • When you see your sensor’s advertisements, parse the data and log it.
  • No GATT connection needed at all.

Why this is good:

  • The ESP32-C6 stays in real deep sleep ~99% of the time. Wake → measure → advertise → sleep.
  • You don’t care about “waking on connect” anymore. The Central simply listens for the broadcast.
  • Battery life can reach many weeks/months if you keep the active window short and RTC timer interval long.

Trade-offs:

  • You’re limited to ~31 bytes in the main advertising payload minus overhead, but that’s still plenty for:
    • Temperature, humidity, pressure
    • Battery level
    • A sensor ID / version / flags

For a small weather station, this is absolutely enough.

You can do some other options that work but require more thought.
i.e. Schedule a connection Window
If you really want a connection (for bigger payloads or config), you can do:

  • ESP32-C6 wakes every 5 minutes:
    • Starts advertising and stays up for a fixed window (say 10–20 seconds) waiting for a Pi connection.
  • Pi:
    • Runs a job every 5 minutes that scans and connects during that window.

This still uses RTC timer for wake, not BLE, but from the user’s perspective:

  • “Pi polls every 5 minutes” :white_check_mark:
  • “Sensor is mostly asleep” :white_check_mark:

Downside: requires the Pi and C6 clocks not to drift too much, or you make the window a bit generous (at the cost of some battery life).
or an ALWAYS ON situ
i.e. keep the Central always on and let the Peripheral wake & advertise. That’s actually the best inversion for your topology:

  • The Pi Zero2W is mains-powered or at least has much more battery than 320 mAh.
  • Leave the Pi scanning 24/7.
  • Let the ESP32-C6 do ultra-aggressive sleeping and only pop up briefly to shout weather updates.
    This workaround is not just possible, it’s the correct architecture. :+1:

I have seen * A simple ESP32-C6 Arduino or IDF example: wake via timer every 5 minutes, read BME280/whatever, shove data into manufacturer data field of the advertising packet, advertise for X seconds, then deep sleep.

  • And a Python script on the Pi using bleak to scan and parse those advertisements.
  • Basic’s don’t over think it.

HTH
GL :slight_smile: Pj :v:

You can use the ULP to wake the C6 CPU on reception of a specific BLE signal. I haven’t tried it on ESP32 but have used a similar technique on Silabs’ devices (not XIAO MG24 though).

A beacon sounds good. Thanks for the suggestion.

Wow! Thanks for such a complete and helpful response. I think a beacon is the best approach for me so I’ll look for some example code for that.

1 Like

Thanks for the response. The ESP documentation implies it should work but it seems that the Xiao ESP implementation is somehow incomplete and I’ve tried several different approaches which have all failed. On the advice of other posters, I’m going to switch to a BLE beacon-based approach

1 Like

Folks, can I just say what a pleasant surprise it is to join a forum where people are helpful and polite and not at all condescending. (Yes, I’m looking at you, StackExchange!!!).Thanks for all the help.

1 Like

Hi there,

Yes I would agree , I think it’s a sasquatch :grin: I never seen him in the wild… either
The BLE wake, I have never seen work. SO I’m out …
Crazy good idea though, I’m surprised it’s not a BIGGER thing :+1:

The Beacon tech , that’s a winner!
HTH
GL :slight_smile: PJ :v:

Hi everyone!
I am trying to get along with a similar problem.

I have a project that on paper is relatively simple, but seems to have some issues in practice. Developing with YAML and esphome.

Device: Deep Xiao ESP32 C6. I’ve added RF 433 (TX RX) and an LED.
The project idea is “when I am back home and esp32 ble recognize my phone, esp32 send rf to open the gate.”. The gate is far enough from apartment.

The device must follow this logic:

STARTUP

  • Attempts to connect to the main WiFi.

    • if connection is successful, performs a ping test; if that works, stays connected, do not repeat ping test. No light sleep, no deep sleep. (it means I took esp32 at home for developing).
    • If connection to main wifi or ping fail, trigger start of AP for 30 seconds and waits for connections.
  • AP connection:

    • If no connection to AP within 30 seconds, completely disables WiFi without trying to restart it. Do not attempt connection neither to main wifi.
    • If within 30 seconds at least one client is connected, starts a timer that checks for client presence every 30 seconds; if at the check there are no clients, disables WiFi (and does not reactivate the main connection).
    • Note: AP ON can be triggered by BLE server 2.
  • If connected to main wifi, or bounded device is 0, BLE server 1 accept connection and allow bonding with pin for 60 seconds. This BLE server is used to reverse detect presence (esp32 advertise, smartphone connect).

    • The device that bonds (phone) must be stored so it can connect automatically when in range. (impossible to do with mac of bluetooth as smartphone presents with fake mac).

OPERATIONAL MODE
esp32 advertise its presence, the smartphone find it and connect. This follows a 4 states logic:

  • 0 Away from home: ESP32 advertises every 1.28 seconds (I can increase to 2,56 or 3,84 if this helps).
    • When esp32 is detected by a phone it has bonded with, the phone connects and it switches to State 1.
  • 1 Entering: ESP32 checks BLE connection RSSI signal every 500ms, so it is active, no light sleep or deep sleep. Bluetooth stack active.
    • if the signal is better than -70 for the last 4 check (4x500ms, 2 seconds in total) it means I am close to the gate, and esp32 sends RF signals through RF TX ,and switches to State 2.
    • If the signal hasn’t reached -70 (it means I am far, maybe just passing with car) or the phone disconnects, it returns to State 0.
  • 2 Entered: Once in this state, advertising can be reduced to 5 seconds interval (if this save battery). When the smartphone disconnects, esp32 switches to State 3.
  • 3 Inside home: Phone disconnected.
    • BLE advertising every 3,84 seconds instead of 1.28 if this reduces consumption.
    • When the phone connects back, exit light sleep, system BLE stack activate.
      • If the phone stays connected for at least 3 seconds, esp32 switches to State 4.
      • If the phone disconnects before 3 seconds, reset counter and goes back to light sleep without changing state.
  • 4 Exit: advertising can be now reduced to 5 seconds interval (if this save battery). When the smartphone disconnects, esp32 switches to State 0.

My battery is a 3.7V 18650 3800mah and I will attach to battery pads.

ADDITIONS

  • ESP32 should advertise a Second BLE server for config and other data collection.
    • When a phone that has already bonded to the first BLE server, connects to the BLE config server, it activates AP.
    • When the phone disconnect from the config BLE, deactivate AP.
  • AP should give access through web interface to various sensors and commands:
    • ESP32 Wifi mac, bluetooth mac
    • Available wifi with possibility to connect as main wifi (will this be stored)?
    • button to enable BLE pairing for additional devices.
    • List of all bounded devices with possibility to delete the bound one by one.
    • button to reset the list of all bounded devices.
    • button to check integrated user led (500ms on, 500ms off, x 4 times)
    • button to check additional led (500ms on, 500ms off, x 4 times)
    • A read RX RF , to listen for 5 seconds,get the code of other RF remote command, and show it in the page

Docs from EspressIf say
Wi-Fi/Bluetooth and Sleep Modes

In Deep-sleep and Light-sleep modes, the wireless peripherals are powered down. Before entering Deep-sleep or Light-sleep modes, the application must disable Wi-Fi and Bluetooth using the appropriate calls (i.e., nimble_port_stop(), nimble_port_deinit(), esp_bluedroid_disable(), esp_bluedroid_deinit(), esp_bt_controller_disable(), esp_bt_controller_deinit(), esp_wifi_stop()). Wi-Fi and Bluetooth connections are not maintained in Deep-sleep or Light-sleep mode, even if these functions are not called.

If Wi-Fi/Bluetooth connections need to be maintained, enable Wi-Fi/Bluetooth Modem-sleep mode and automatic Light-sleep feature (see Power Management APIs). This allows the system to wake up from sleep automatically when required by the Wi-Fi/Bluetooth driver, thereby maintaining the connection.

DOUBT

I saw a table where it is reported wifi/BT active in light sleep, and ULP active in deep sleep. This table and it is confusing me enough

Actually I need the advertising still going while in deep or light sleep. The advertising, not the connection or communication. When the phone try to connect, then let’s wake up the board. But this does not seems to happen. I was also considering Modem sleep but seems it has more power consumption (we are considering only bluetooth, wifi is still deactivated)

I do understand that in deep sleep the ULP is active. Is this able to manage to advertising?
Because of the advertising period, by using deep sleep I risk to use more power for the wake up every 1,28-3,84 seconds, than to use light sleep always.
I can also reduce TX power for Bluetooth when in state 0 and 3. The ESP32 would stay in this state for 99% of time.

I can post actual code here if someone is available to give a look and keep it for the community.

Appreciate any suggestion.

Thanks

This is what I found out the hard way:

  1. On the C6, absolutely nothing works in deep sleep except the ULP timer (and maybe GPIO wake-up, which I don’t use).
  2. You can’t BLE advertise in deep sleep.
  3. There is a huge difference between FUNCTIONALLY turned off and POWERED off. You need to do both or devices can continue to draw several mA even in deep sleep mode.
  4. Watch you BLE stacks, There are multiple, similar libraries and you can’t mix-and-match their APIs.

With those points in mind, you need to rethink your design and expectations.

I’m still trying to crack ultra low power (…for a weather station beacon…) but there are lots and lots of gotchas.

“Found the hard way” doesn’t sound promising :slight_smile:
Ok, so deep sleep I take already out of the game. Also if I would put the device in deep sleep for 1,28 seconds (or even 5), it will full wake up and the overhead of loading everything will be more than just keep a light sleep. Of course with a 5 minutes interval the things would be different, but it is not my case.

Let’s go for light sleep. Do you think I can achieve what I was describing, maybe by a bit of tweak? I am using esphome. What library per your knowledge could help me in → light sleep, beacon every 1,28 seconds, wake up only on connection by bounded phone, go back light sleep? Seems for connection and bonding I can go just with the full stack, and it takes energy but only when woken up.
Considering a battery of 3800mah , I would like to be relaxed for at least 2 months (better if 20 months of course, but first function, and later optimization).
Any suggestion appreciated, especially that you already went through it.

It’s more accurate to say that I’m still going through it! I’m still relatively new to ESP32 & Arduino. There are wiser heads here who can advise on BT stacks. I just picked one and my needs (Eddystone beacon) are simple so I didn’t delve further. At the moment, I’m trying to get my device to last longer than 100 hours on a 330mAh battery and that seems to involve a lot of trial and error with various ESP32C6-specific power management calls..

How does yours work? Do you think it can adapts to my project too? I am not evaluating at all deep sleep as it seems waking up from deep sleep costs more than running constantly on light sleep. The question is if with your Eddystone beacon you succeded to advertise 1-2 server BLE and manage a wake up at the connection. Thank you

maybe consider a RTC or syncing the timing so the both wake up at the same time..

Also LoRa.. but not sure it can wake any better

also consider NRF24L01 transcever i think it has a hardware interupt feature… but it also needs power… so probably not a real solution

My device is very simple, It’s just a beacon. It’s not connectable so I don’t have to worry about that side of things. It wakes every 10 seconds for about 100ms.In that time it takes temperature, humidity and pressure readings which it packs into the UID data of an Eddystone UID beacon. I pick up the data from several sensors on a Raspberry Pi Zero 2W and display on a web page. Beacons like this should be able to run for weeks or months on a single battery charge. There are commercial variants that run off CR2032 batteries, just like an airtag, and operate for months.

My approach probably won’t work for you project as you need to connect to the device. You also will find that you can only connect when the device is awake, which would be only 1% of the time.

I just always wonder why you need that information so fast, i mean temp and pressure for weather observations.. every 5 minutes is too fast

I wonder if someone succeeded to be in constant light sleep + ble, and wake up on ble connection. From forums seems no luck with it on this board. But from ESP-IDF references it should be possible

It’s because the beacon is to replace a 20 yr old Oregon Scientific RM300 weather station. This has a USB interface which sends USB packets from an internal and an external sensor about every 5 seconds. The RM300 has issues with odd readings & checksum errors (probably related) so I take 5-minute averages which then got logged. Since my software already works on this cadence, it is just easier to continue to do same with the beacons. Also, beacons are impossible to debug unless they advertise frequently.

1 Like

Hi there,

So bottom line is Both CAN’t be true,…
“Sleep” or “Listening for BLE packet” BLE is not magic. It’s just a radio.

For a device to “hear” a BLE packet, three things must be ON:

  • RF front end (radio hardware)
  • Clock system (timing is everything in BLE)
  • BLE stack / controller

When you put an ESP32 (or most MCUs) into deep sleep, all of that is completely powered down.

:backhand_index_pointing_right: No radio
:backhand_index_pointing_right: No receiver
:backhand_index_pointing_right: No packet detection
:backhand_index_pointing_right: No chance of waking from BLE

Deep sleep exists for one reason:

Ultra-low power (µA range)

Keeping the radio on—even in a “listening” mode—costs orders of magnitude more power.

Typical comparison:

Mode Current Draw
Deep Sleep ~5–20 µA
BLE idle/listen ~1–10 mA

That’s a 100x–1000x difference.

So if BLE wake were allowed in deep sleep, it wouldn’t really be “deep sleep” anymore.
Some chips (not ESP32) have special ultra-low-power radios or “wake-on-radio” features—but even those:

  • don’t run full BLE stacks
  • use simplified detection
  • still consume more power than true deep sleep

I have this diagram I made for the (10) BLE sensor_Node project with 3 concurrent connections and 6 notifies. (demo & code is one here)

I useds the technique # 4 along with the #2 the timer.

https://forum.seeedstudio.com/t/multi-concurrent-ble-connections-with-seeed-round-display/293997

HTH
GL :slight_smile: PJ :v:

1 Like