Page 1 of 1

Controlling ESP32 Deep Sleep Mode Awake Time

Posted: Thu May 16, 2024 1:46 pm
by mi2024
I created an app that monitors my car battery's voltage, plus current from a trickle charger, via a Bluetooth LE connection to a XIAO ESP32S3 and power sensor. I plan to check the readings every 24 hours for about a minute or so. Ideally, the ESP32 would be in deep sleep mode for 23 hours and 59 minutes. However, given that the only way to wake the ESP32 from deep sleep mode remotely is to use a Timer, my desire is to wake the device for 30 seconds, following by 60 seconds of deep sleep. That means at most I'd be waiting 60 seconds for the device to wake up and begin advertising its BLE signal for connection to my phone app. I've tried including this deep sleep code in my sketch for the ESP32:

#define uS_TO_S_FACTOR 1000000ULL //Conversion factor for micro seconds to seconds
#define TIME_TO_SLEEP 60 //Time ESP32 will go to sleep (in seconds)
esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP* uS_TO_S_FACTOR);
Serial.flush();
esp_deep_sleep_start();

The device does enter deep sleep and then awakes on its own after the 60 second time interval. However, the awake time is very brief before it returns to deep sleep. I tried introducing delay(30000) at various points in my code to try to control the awake time, but I suspect that's not how to properly accomplish my goal. Can anyone provide some guidance as to where the Serial.flush(); and esp_deep_sleep_start(); commands should be inserted, and how to control the awake time? Here's my entire sketch:

Code: Select all

#include <BLEDevice.h>
#include <BLEServer.h>
#include <BLEUtils.h>
#include <BLE2902.h>
#include <Adafruit_INA260.h>

Adafruit_INA260 ina260 = Adafruit_INA260();

BLEServer* pServer = NULL;
BLECharacteristic* pVoltsCharacteristic = NULL;
BLECharacteristic* pAmpsCharacteristic = NULL;
bool deviceConnected = false;
bool oldDeviceConnected = false;

// See the following for generating UUIDs:
// https://www.uuidgenerator.net/

static BLEUUID BLESERVICE_UUID("4fafc201-1fb5-459e-8fcc-c5c9c331914b");
#define SERVICE_UUID "4fafc201-1fb5-459e-8fcc-c5c9c331914b"
#define VOLTS_CHARACTERISTIC_UUID "7dd120c3-5d28-4264-88f9-f62233315f45"
#define AMPS_CHARACTERISTIC_UUID "3e37576d-9603-4637-b7b7-1d703e113268"

class MyServerCallbacks : public BLEServerCallbacks {
  void onConnect(BLEServer* pServer) {
    deviceConnected = true;
  };

  void onDisconnect(BLEServer* pServer) {
    deviceConnected = false;
  }
};

void setup() {
  Serial.begin(115200);
  ina260.begin();

  // Create the BLE Device
  BLEDevice::init("XIAO ESP32S3");

  // Create the BLE Server
  pServer = BLEDevice::createServer();
  pServer->setCallbacks(new MyServerCallbacks());

  // Create the BLE Services
  //BLEService* pService = pServer->createService(SERVICE_UUID);
  BLEService* pService = pServer->createService(BLESERVICE_UUID, 7, 0);  //Can specify the number of characteristics (minimum 7)

  // Create a BLE Characteristics
  pVoltsCharacteristic = pService->createCharacteristic(
    VOLTS_CHARACTERISTIC_UUID,
    BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_NOTIFY);
  pAmpsCharacteristic = pService->createCharacteristic(
    AMPS_CHARACTERISTIC_UUID,
    BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_NOTIFY);

  // https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.descriptor.gatt.client_characteristic_configuration.xml
  // Create a BLE Descriptor
  pVoltsCharacteristic->addDescriptor(new BLE2902());
  pAmpsCharacteristic->addDescriptor(new BLE2902());

  // Start the service
  pService->start();

  // Start advertising
  BLEAdvertising* pAdvertising = BLEDevice::getAdvertising();
  pAdvertising->addServiceUUID(SERVICE_UUID);
  pAdvertising->setScanResponse(false);
  pAdvertising->setMinPreferred(0x0);  // set value to 0x00 to not advertise this parameter
  BLEDevice::startAdvertising();
  //Serial.println("Waiting for client connection...");
}

void loop() {
  // notify changed value
  float voltsValue = (ina260.readBusVoltage() / 1000);
  float ampsValue = (ina260.readCurrent() / 1000);
  Serial.println(voltsValue, 3);
  Serial.println(ampsValue, 3);

  if (deviceConnected) {
    pVoltsCharacteristic->setValue(voltsValue);
    pVoltsCharacteristic->notify();
    pAmpsCharacteristic->setValue(ampsValue);
    pAmpsCharacteristic->notify();
    delay(2000);  // bluetooth stack will go into congestion, if too many packets are sent, in 6 hours test i was able to go as low as 3ms
  }
  // disconnecting
  if (!deviceConnected && oldDeviceConnected) {
    delay(500);                   // give the bluetooth stack the chance to get things ready
    pServer->startAdvertising();  // restart advertising
    Serial.println("Start advertising...");
    oldDeviceConnected = deviceConnected;
  }
  // connecting
  if (deviceConnected && !oldDeviceConnected) {
    // do stuff here on connecting
    oldDeviceConnected = deviceConnected;
  }
}

Re: Controlling ESP32 Deep Sleep Mode Awake Time

Posted: Thu May 16, 2024 5:57 pm
by liaifat85
You can modify the code like this:

Code: Select all

#include <BLEDevice.h>
#include <BLEServer.h>
#include <BLEUtils.h>
#include <BLE2902.h>
#include <Adafruit_INA260.h>

#define uS_TO_S_FACTOR 1000000ULL // Conversion factor for micro seconds to seconds
#define TIME_TO_SLEEP 60          // Time ESP32 will go to sleep (in seconds)
#define WAKE_UP_TIME 30           // Time ESP32 will stay awake (in seconds)

Adafruit_INA260 ina260 = Adafruit_INA260();

BLEServer* pServer = NULL;
BLECharacteristic* pVoltsCharacteristic = NULL;
BLECharacteristic* pAmpsCharacteristic = NULL;
bool deviceConnected = false;
bool oldDeviceConnected = false;

// See the following for generating UUIDs:
// https://www.uuidgenerator.net/

static BLEUUID BLESERVICE_UUID("4fafc201-1fb5-459e-8fcc-c5c9c331914b");
#define VOLTS_CHARACTERISTIC_UUID "7dd120c3-5d28-4264-88f9-f62233315f45"
#define AMPS_CHARACTERISTIC_UUID "3e37576d-9603-4637-b7b7-1d703e113268"

class MyServerCallbacks : public BLEServerCallbacks {
  void onConnect(BLEServer* pServer) {
    deviceConnected = true;
  }

  void onDisconnect(BLEServer* pServer) {
    deviceConnected = false;
  }
};

void setup() {
  Serial.begin(115200);
  ina260.begin();

  // Create the BLE Device
  BLEDevice::init("XIAO ESP32S3");

  // Create the BLE Server
  pServer = BLEDevice::createServer();
  pServer->setCallbacks(new MyServerCallbacks());

  // Create the BLE Services
  BLEService* pService = pServer->createService(BLESERVICE_UUID, 7, 0);  // Can specify the number of characteristics (minimum 7)

  // Create BLE Characteristics
  pVoltsCharacteristic = pService->createCharacteristic(
    VOLTS_CHARACTERISTIC_UUID,
    BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_NOTIFY
  );
  pAmpsCharacteristic = pService->createCharacteristic(
    AMPS_CHARACTERISTIC_UUID,
    BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_NOTIFY
  );

  // Create BLE Descriptors
  pVoltsCharacteristic->addDescriptor(new BLE2902());
  pAmpsCharacteristic->addDescriptor(new BLE2902());

  // Start the service
  pService->start();

  // Start advertising
  BLEAdvertising* pAdvertising = BLEDevice::getAdvertising();
  pAdvertising->addServiceUUID(BLESERVICE_UUID);
  pAdvertising->setScanResponse(false);
  pAdvertising->setMinPreferred(0x0);  // Set value to 0x00 to not advertise this parameter
  BLEDevice::startAdvertising();

  // Sleep configuration
  esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * uS_TO_S_FACTOR);
  delay(WAKE_UP_TIME * 1000);  // Delay for the specified wake-up time
  Serial.flush();
  esp_deep_sleep_start();
}

void loop() {
  // notify changed value
  float voltsValue = (ina260.readBusVoltage() / 1000);
  float ampsValue = (ina260.readCurrent() / 1000);
  Serial.println(voltsValue, 3);
  Serial.println(ampsValue, 3);

  if (deviceConnected) {
    pVoltsCharacteristic->setValue(voltsValue);
    pVoltsCharacteristic->notify();
    pAmpsCharacteristic->setValue(ampsValue);
    pAmpsCharacteristic->notify();
    delay(2000);  // Bluetooth stack will go into congestion if too many packets are sent
  }

  // Disconnecting
  if (!deviceConnected && oldDeviceConnected) {
    delay(500);  // Give the Bluetooth stack the chance to get things ready
    pServer->startAdvertising();  // Restart advertising
    Serial.println("Start advertising...");
    oldDeviceConnected = deviceConnected;
  }

  // Connecting
  if (deviceConnected && !oldDeviceConnected) {
    // Do stuff here on connecting
    oldDeviceConnected = deviceConnected;
  }
}
Deep Sleep Configuration in setup(): The deep sleep timer is set up, and a delay for the specified wake-up time (WAKE_UP_TIME) is introduced to control how long the ESP32 stays awake before entering deep sleep again.

esp_deep_sleep_start() Placement: This command is placed at the end of the setup() function after all initializations and actions during the wake-up period are complete.

Timer for Wake-Up Duration: The delay(WAKE_UP_TIME * 1000); ensures the ESP32 stays awake for 30 seconds before going back to sleep.

For more info about ESP32 low power modes, you can see here.
https://www.theengineeringprojects.com/ ... modes.html

Re: Controlling ESP32 Deep Sleep Mode Awake Time

Posted: Thu May 16, 2024 6:29 pm
by mi2024
Thank you @liaifat85...I appreciate your help!

Re: Controlling ESP32 Deep Sleep Mode Awake Time

Posted: Fri May 17, 2024 9:44 pm
by mi2024
The code suggested by liaifat85 does not work as intended. The ESP32 enters deep sleep and awakes per the defined time intervals, but it appears the code contained in the loop never gets executed. Therefore, I don't see any volts or amps values displayed either on the serial monitor or on my phone app screen. Does anyone have any suggestions for why that's happening?