Hi, I am currently learning to use the ESP32's BLE libraries, FreeRTOS and sleep modes so I decided to put these concepts together into a little demo program for myself. I would like to create a very simple LED indication scheme: when the device is powered on it starts advertising (LED blinking) and when connected, the LED remains on. If no client connects within 15 seconds of starting advertising, it goes into deep sleep (with ext0 wakeup at GPIO 33) and starts advertising on wakeup again. The code below is what I could come up with based one examples. This mostly works but I did see some unexpected watchdog resets occassionally.
#include <BLEDevice.h>
#include <BLEServer.h>
#include <BLEUtils.h>
static const uint8_t led_pin = GPIO_NUM_26;
static const uint16_t led_blink_interval_ms = 300;
typedef enum {
BLINKING,
ON,
OFF
} led_state_t;
static volatile led_state_t led_state;
void stateControlTask(void *pvParameter) {
pinMode(led_pin, OUTPUT);
while (true) {
switch (led_state) {
case BLINKING:
digitalWrite(led_pin, HIGH);
vTaskDelay(led_blink_interval_ms/portTICK_PERIOD_MS);
digitalWrite(led_pin, LOW);
vTaskDelay(led_blink_interval_ms/portTICK_PERIOD_MS);
break;
case ON:
digitalWrite(led_pin, HIGH);
break;
case OFF:
// Start deep sleep after turning off Bluetooth peripheral.
BLEDevice::deinit(); // Calls esp_bluedroid_disable()
vTaskDelay(200); // Wireless peripherals (WiFi/BT) must be disabled before Deep Sleep
esp_deep_sleep_start();
break;
}
}
}
static volatile bool device_connected = false;
static bool old_device_connected = false;
static uint32_t adv_last_started;
class MyServerCallbacks : public BLEServerCallbacks {
void onConnect(BLEServer*) override {
device_connected = true;
}
void onDisconnect(BLEServer*) override {
device_connected = false;
}
};
static uint16_t RTC_DATA_ATTR nboots = 0;
static const gpio_num_t wakeup_pin = GPIO_NUM_33;
void setup() {
Serial.begin(115200);
delay(250); // Delay after waking up (needed?)
if (++nboots == 1) {
Serial.println("---BLE Connection LED Indicator---");
}
esp_sleep_enable_ext0_wakeup(wakeup_pin, HIGH);
BLEDevice::init("LED Indicator");
BLEDevice::createServer()->setCallbacks(new MyServerCallbacks());
Serial.printf("[%d] BLE stack started\n", nboots);
BLEDevice::startAdvertising();
adv_last_started = millis();
led_state = BLINKING;
Serial.println("BLE Advertisement started.");
xTaskCreate(stateControlTask, "State Control", 1024, NULL, 1, NULL);
}
void loop() {
if (device_connected) {
Serial.println("Communicating with BLE Client.");
vTaskDelay(5000/portTICK_PERIOD_MS);
}
// Disconnecting...
if (!device_connected && old_device_connected) {
old_device_connected = device_connected;
// Restart advertising...
BLEDevice::startAdvertising();
adv_last_started = millis();
led_state = BLINKING;
}
// Connecting...
if (device_connected && !old_device_connected) {
old_device_connected = device_connected;
led_state = ON;
}
// Advertising...waiting for connection.
if (!device_connected && !old_device_connected) {
if ((millis() - adv_last_started) > 15000) // Wait for 15 seconds after starting adv before putting into sleep mode.
{
adv_last_started = millis(); // Bogus assignment to prevent entering this snippet a second time before Deep Sleep is entered.
Serial.println("Putting into (Deep) Sleep mode!");
led_state = OFF;
vTaskDelay(1000/portTICK_PERIOD_MS);
}
}
}
I would be very grateful if you could provide some feedback on whether I am making correct use of tasks or engaging in bad practices. For example, I debated if I should make the priority of the LED task greater than 1 for more responsiveness but then I was worried it might choke the BT stack in the background and cause crashes (which I have experience quite a bit when working with WiFi). Any advice/review for more complex projects of this nature in the future would be appreciated.