ESP32-C3 not receiving data with ESP-NOW after initialising NimBLE
Hi,
I'm using two ESP32-C3, the first one to turn on is the one who becomes the master after 3 seconds. The master should initialise NimBLE and then broadcast every second or so a packet called ACK for other ESP32s with esp now. The problem is that when the slave device receives the packet it tries to reply back to the master but the attempt fails. I know for sure that this kind of communication works because I tried it without initialising NimBLE.
(Note: after initialising NimBLE the master ESP is correctly seen by the phone) (I already tried to ask on Arduino-ESP32 core but didn't replied and I need to finish this code before friday)
I can't figure out what's the problem.
This is the code
#include <NimBLEDevice.h>
#include "ESP32_NOW.h"
#include "WiFi.h"
#include "structs.cpp"
#include <esp_mac.h> // For the MAC2STR and MACSTR macros
/* Definitions */
#define ESPNOW_WIFI_CHANNEL 6
#define BATTERY_PIN 3
/* Global Variables */
uint32_t msg_count = 0;
bool inGroup = false;
bool isMaster = false;
long startupTime, lastBatteryCheckSent, lastACKSent, lastAliveCheck;
bool connectedBLE = false;
/* Functions */
int getCurrentBatterySOT() {
int batteria = map(analogReadMilliVolts(BATTERY_PIN) * 2, 3150, 4150, 0, 100);
batteria = max(1, min(batteria, 100));
return batteria;
}
/* Classes */
// Creating a new class that inherits from the ESP_NOW_Peer class is required.
class ESP_NOW_Broadcast_Peer : public ESP_NOW_Peer {
public:
// Constructor of the class using the broadcast address
ESP_NOW_Broadcast_Peer(uint8_t channel, wifi_interface_t iface, const uint8_t *lmk) : ESP_NOW_Peer(ESP_NOW.BROADCAST_ADDR, channel, iface, lmk) {}
// Destructor of the class
~ESP_NOW_Broadcast_Peer() {
remove();
}
// Function to properly initialize the ESP-NOW and register the broadcast peer
bool begin() {
if (!ESP_NOW.begin() || !add()) {
log_e("Failed to initialize ESP-NOW or register the broadcast peer");
return false;
}
return true;
}
// Function to send a message to all devices within the network
bool send_message(const uint8_t *data, size_t len) {
if (!send(data, len)) {
log_e("Failed to broadcast message");
return false;
}
return true;
}
};
class ESP_NOW_Peer_Class : public ESP_NOW_Peer {
public:
// Constructor of the class
ESP_NOW_Peer_Class(const uint8_t *mac_addr, uint8_t channel, wifi_interface_t iface, const uint8_t *lmk) : ESP_NOW_Peer(mac_addr, channel, iface, lmk) {}
// Destructor of the class
~ESP_NOW_Peer_Class() {}
// Function to register the master peer
bool add_peer() {
if (!add()) {
log_e("Failed to register the peer");
return false;
}
return true;
}
// Function to print the received messages from the master
void onReceive(const uint8_t *data, size_t len, bool broadcast) {
Serial.println("The peer received a packet");
if (*data == ACK_PACK_TYPE) return;
if (*data == BATTERY_PACK_TYPE) {
Serial.println("Sending battery information to the master");
BATTERY response = BATTERY(getCurrentBatterySOT());
send_message((uint8_t *)&response, sizeof(BATTERY));
}
Serial.printf("Received a message from master " MACSTR " (%s)\n", MAC2STR(addr()), broadcast ? "broadcast" : "unicast");
Serial.printf(" Message: %s\n", (char *)data);
}
// Function to send a message to the peer
bool send_message(const uint8_t *data, size_t len) {
if (!send(data, len)) {
log_e("Failed to send message to peer %s", MAC2STR(addr()));
return false;
}
return true;
}
};
class ESP_NOW_Slave_Class : public ESP_NOW_Peer {
public:
bool isAlive = true;
int battery = 0;
// Constructor of the class
ESP_NOW_Slave_Class(const uint8_t *mac_addr, uint8_t channel, wifi_interface_t iface, const uint8_t *lmk) : ESP_NOW_Peer(mac_addr, channel, iface, lmk) {}
// Destructor of the class
~ESP_NOW_Slave_Class() {}
// Function to register the master peer
bool add_peer() {
if (!add()) {
log_e("Failed to register the peer");
return false;
}
return true;
}
// Function to print the received messages from the master
void onReceive(const uint8_t *data, size_t len, bool broadcast) {
isAlive = true;
//Serial.printf("Received message from: (%s), data*: %d\n", MAC2STR(addr()), *data);
if (*data == ACK_PACK_TYPE) return;
if (*data == BATTERY_PACK_TYPE) {
BATTERY *packet = (BATTERY *) data;
battery = packet->batt;
}
}
void onSent(bool success) {
isAlive = success;
Serial.printf("onSent(), %d\n\n", isAlive);
}
bool deinitialise() {
Serial.printf("I'm removing the peer\n");
return remove();
}
// Function to send a message to the peer
bool send_message(const uint8_t *data, size_t len) {
if (!send(data, len)) {
log_e("Failed to broadcast message");
return false;
}
return true;
}
};
// Create a broadcast peer object
ESP_NOW_Broadcast_Peer broadcast_peer(ESPNOW_WIFI_CHANNEL, WIFI_IF_STA, NULL);
std::vector<ESP_NOW_Slave_Class> devices;
ESP_NOW_Peer_Class* master = NULL;
// Callback called when an unknown peer sends a message
void register_new_master(const esp_now_recv_info_t *info, const uint8_t *data, int len, void *arg) {
if (memcmp(info->des_addr, ESP_NOW.BROADCAST_ADDR, 6) == 0) {
Serial.printf("Unknown peer " MACSTR " sent a broadcast message\n", MAC2STR(info->src_addr));
if (*data == ACK_PACK_TYPE && !inGroup) {
inGroup = true;
Serial.println("Registering the peer as a master");
master = new ESP_NOW_Peer_Class(info->src_addr, ESPNOW_WIFI_CHANNEL, WIFI_IF_STA, NULL);
if (!master->add_peer()) {
Serial.println("Failed to register the new master");
return;
}
OK_PACK okPack = OK_PACK();
master->send_message((uint8_t *)&okPack, sizeof(OK_PACK));
}
} else {
if (isMaster) {
log_v("Received a unicast message from " MACSTR, MAC2STR(info->src_addr));
Serial.printf("%d\n", *data);
if (*data == OK_PACK_TYPE) {
ESP_NOW_Slave_Class new_device(info->src_addr, ESPNOW_WIFI_CHANNEL, WIFI_IF_STA, NULL);
devices.push_back(new_device);
if(!devices.back().add_peer()){
Serial.println("\n\nFailed to add the new peer to the device list\n\n");
}
}
} else {
// The slave will only receive broadcast messages
log_v("Received a unicast message from " MACSTR, MAC2STR(info->src_addr));
log_v("Igorning the message");
}
}
}
NimBLEServer* pServer = NULL;
NimBLEService *serviceBattery = NULL;
NimBLECharacteristic *batteryLevelChar = NULL;
#define SERVICE_BATTERY_UUID "180f" //batteria
#define BATTERY_LEVEL_CHARACTERISTIC_UUID "492c2d04-f173-4814-9630-e12aedc4f7f6"
//livello batteria tutti i sensori, 1byte per sensore, max 10 sensori, se sensore non connesso: 0xFF
class ServerCallbacks: public NimBLEServerCallbacks {
void onConnect(NimBLEServer* pServer) {
Serial.println("Device connected");
connectedBLE = true;
};
void onDisconnect(NimBLEServer* pServer) {
Serial.println("Device disconnected");
connectedBLE = false;
//resart the advertising
BLEDevice::startAdvertising();
}
};
void initBLE() {
NimBLEDevice::init("B_Rainbow");
pServer = NimBLEDevice::createServer();
pServer->setCallbacks(new ServerCallbacks());
serviceBattery = pServer->createService(SERVICE_BATTERY_UUID);
batteryLevelChar = serviceBattery->createCharacteristic(
BATTERY_LEVEL_CHARACTERISTIC_UUID,
NIMBLE_PROPERTY::NOTIFY | NIMBLE_PROPERTY::READ
);
serviceBattery->start();
BLEAdvertising *pAdvertising = NimBLEDevice::getAdvertising();
pAdvertising->addServiceUUID(SERVICE_BATTERY_UUID);
// pAdvertising->setScanResponse(true);
pAdvertising->setPreferredParams(0x06, 0x12);
NimBLEDevice::startAdvertising();
Serial.println("Finished BLE init");
}
void updateBLEData() {
uint8_t *data = (uint8_t*) malloc(devices.size() + 1);
data[0] = devices.size()+1;
for (int i = 0; i < devices.size(); i++) {
data[i] = devices[i].battery;
}
batteryLevelChar->setValue(data, devices.size()+1);
batteryLevelChar->notify();
free(data);
data = NULL;
}
/* Main */
void setup() {
Serial.begin(115200);
// Initialize the Wi-Fi module
WiFi.mode(WIFI_STA);
WiFi.setChannel(ESPNOW_WIFI_CHANNEL);
while (!WiFi.STA.started()) {
delay(100);
}
// Register the broadcast peer
if (!broadcast_peer.begin()) {
Serial.println("Failed to initialize broadcast peer");
Serial.println("Reebooting in 5 seconds...");
delay(5000);
ESP.restart();
}
ESP_NOW.onNewPeer(register_new_master, NULL);
startupTime = millis();
}
void loop() {
// Broadcast a message to all devices within the network
if (!inGroup && startupTime + 3000 < millis() && !isMaster) {
//diventa il master
isMaster = true;
Serial.println("\n\n\nIM THE MASTER \n\n\n");
initBLE();
}
if (isMaster && lastACKSent + 1000 < millis()) {
ACK pack = ACK();
broadcast_peer.send_message((uint8_t *)&pack, sizeof(ACK));
lastACKSent = millis();
}
if (isMaster && lastBatteryCheckSent + 2000 < millis()) {
BATTERY pack = BATTERY(255);
for (int i = devices.size() - 1; i >= 0; i--) {
devices[i].send_message((uint8_t *)&pack, sizeof(BATTERY));
}
lastBatteryCheckSent = millis();
}
if (isMaster && lastAliveCheck + 1000 < millis()) {
for (int i = devices.size() - 1; i >= 0; i--) {
if (!devices[i].isAlive) {
devices[i].deinitialise();
devices.erase(devices.begin() + i);
}
}
lastAliveCheck = millis();
}
delay(100);
}
Try initializing BLE at startup, but not advertising until you need to, for some reason it seem to help sometimes.
Other than that I would need to see a debug log to start with.
Thank you for your answer
Ok, I put initBLE in the setup function just after Serial.begin, then moved NimBLEDevice::startAdvertising(); inside the loop right after IM THE MASTER println. But still there is the same problem.
These are the logs:
Master
============ Before Setup End ============
[ 484][I][esp32-hal-periman.c:141] perimanSetPinBus(): Pin 18 already has type USB_DM (38) with bus 0x3fc98ed0
[ 485][I][esp32-hal-periman.c:141] perimanSetPinBus(): Pin 19 already has type USB_DP (39) with bus 0x3fc98ed0
I NimBLEDevice: BLE Host Task Started
I NimBLEDevice: NimBle host synced.
D NimBLEService: >> start(): Starting service: UUID: 0x180f, handle: 0x0000
D NimBLEService: Adding 1 characteristics for service UUID: 0x180f, handle: 0x0000
D NimBLEService: << start()
Finished BLE init
[ 577][V][NetworkEvents.cpp:113] _checkForEvent(): Network Event: 101 - WIFI_READY
[ 581][V][STA.cpp:186] _onStaEvent(): STA Started
[ 581][V][NetworkEvents.cpp:113] _checkForEvent(): Network Event: 110 - STA_START
[ 582][V][STA.cpp:110] _onStaArduinoEvent(): Arduino STA Event: 110 - STA_START
[ 584][V][ESP32_NOW.cpp:18] _esp_now_add_peer(): ff:ff:ff:ff:ff:ff
[ 585][V][ESP32_NOW.cpp:311] add(): Peer added - ff:ff:ff:ff:ff:ff
=========== After Setup Start ============
IM THE MASTER
D NimBLEAdvertising: >> Advertising start: duration=0, dirAddr=NULL
primary service
uuid 0x1800
handle 1
end_handle 5
characteristic
uuid 0x2a00
def_handle 2
val_handle 3
min_key_size 0
flags [READ]
characteristic
uuid 0x2a01
def_handle 4
val_handle 5
min_key_size 0
flags [READ]
primary service
uuid 0x1801
handle 6
end_handle 13
characteristic
uuid 0x2a05
def_handle 7
val_handle 8
min_key_size 0
flags [INDICATE]
ccc descriptor
uuid 0x2902
handle 9
min_key_size 0
flags [READ|WRITE]
characteristic
uuid 0x2b3a
def_handle 10
val_handle 11
min_key_size 0
flags [READ]
characteristic
uuid 0x2b29
def_handle 12
val_handle 13
min_key_size 0
flags [READ|WRITE]
primary service
uuid 0x180f
handle 14
end_handle 17
characteristic
uuid 492c2d04-f173-4814-9630-e12aedc4f7f6
def_handle 15
val_handle 16
min_key_size 0
flags [READ|NOTIFY]
ccc descriptor
uuid 0x2902
handle 17
min_key_size 0
flags [READ|WRITE]
D NimBLEAdvertising: setAdvertisementData: 02 01 06 03 03 0f 18 05 12 06 00 12 00
D NimBLEAdvertising: << Advertising start
Started Advertising
[ 3727][V][ESP32_NOW.cpp:384] send(): ff:ff:ff:ff:ff:ff, data length 1
[ 3829][V][ESP32_NOW.cpp:133] _esp_now_tx_cb(): ff:ff:ff:ff:ff:ff : SUCCESS
[ 3830][I][ESP32_NOW.h:78] onSent(): Message transmission to peer ff:ff:ff:ff:ff:ff successful
.....
Slave
00:00:27.572 ============ Before Setup End ============
00:00:27.676 [ 2279][I][esp32-hal-periman.c:141] perimanSetPinBus(): Pin 18 already has type USB_DM (38) with bus 0x3fc98ed0
00:00:27.676 [ 2280][I][esp32-hal-periman.c:141] perimanSetPinBus(): Pin 19 already has type USB_DP (39) with bus 0x3fc98ed0
00:00:27.725 I NimBLEDevice: BLE Host Task Started
00:00:27.728 I NimBLEDevice: NimBle host synced.
00:00:27.730 D NimBLEService: >> start(): Starting service: UUID: 0x180f, handle: 0x0000
00:00:27.735 D NimBLEService: Adding 1 characteristics for service UUID: 0x180f, handle: 0x0000
00:00:27.737 D NimBLEService: << start()
00:00:27.739 Finished BLE init
00:00:27.749 [ 2352][V][NetworkEvents.cpp:113] _checkForEvent(): Network Event: 101 - WIFI_READY
00:00:27.749 [ 2356][V][STA.cpp:186] _onStaEvent(): STA Started
00:00:27.750 [ 2356][V][NetworkEvents.cpp:113] _checkForEvent(): Network Event: 110 - STA_START
00:00:27.750 [ 2357][V][STA.cpp:110] _onStaArduinoEvent(): Arduino STA Event: 110 - STA_START
00:00:27.753 [ 2359][V][ESP32_NOW.cpp:18] _esp_now_add_peer(): ff:ff:ff:ff:ff:ff
00:00:27.754 [ 2359][V][ESP32_NOW.cpp:311] add(): Peer added - ff:ff:ff:ff:ff:ff
00:00:27.754 =========== After Setup Start ============
00:00:27.754 INTERNAL Memory Info:
00:00:27.755 ------------------------------------------
00:00:27.755 Total Size : 272580 B ( 266.2 KB)
00:00:27.755 Free Bytes : 131276 B ( 128.2 KB)
00:00:27.755 Allocated Bytes : 133592 B ( 130.5 KB)
00:00:27.755 Minimum Free Bytes: 131172 B ( 128.1 KB)
00:00:27.755 Largest Free Block: 110580 B ( 108.0 KB)
00:00:27.755 ------------------------------------------
00:00:27.755 GPIO Info:
00:00:27.755 ------------------------------------------
00:00:27.755 GPIO : BUS_TYPE[bus/unit][chan]
00:00:27.755 --------------------------------------
00:00:27.755 18 : USB_DM
00:00:27.755 19 : USB_DP
00:00:27.755 20 : UART_RX[0]
00:00:27.756 21 : UART_TX[0]
00:00:27.756 ============ After Setup End =============
00:00:28.247 [ 2850][V][ESP32_NOW.cpp:112] _esp_now_rx_cb(): Broadcast from d8:3b:da:e3:1c:cc, data length : 1
00:00:28.248 0x00, // .
00:00:28.248 [ 2850][V][ESP32_NOW.cpp:115] _esp_now_rx_cb(): Calling new_cb, peer not found.
00:00:28.248 Unknown peer d8:3b:da:e3:1c:cc sent a broadcast message
00:00:28.248 Registering the peer as a master
00:00:28.248 [ 2853][V][ESP32_NOW.cpp:18] _esp_now_add_peer(): d8:3b:da:e3:1c:cc
00:00:28.248 [ 2856][V][ESP32_NOW.cpp:311] add(): Peer added - d8:3b:da:e3:1c:cc
00:00:28.248 [ 2856][V][ESP32_NOW.cpp:384] send(): d8:3b:da:e3:1c:cc, data length 1
00:00:28.288 [ 2894][V][ESP32_NOW.cpp:133] _esp_now_tx_cb(): d8:3b:da:e3:1c:cc : FAILED
00:00:28.289 [ 2895][I][ESP32_NOW.h:78] onSent(): Message transmission to peer d8:3b:da:e3:1c:cc failed
00:00:29.245 [ 3850][V][ESP32_NOW.cpp:112] _esp_now_rx_cb(): Broadcast from d8:3b:da:e3:1c:cc, data length : 1
00:00:29.245 0x00, // .
00:00:29.245 [ 3851][V][ESP32_NOW.cpp:122] _esp_now_rx_cb(): Checking peer ff:ff:ff:ff:ff:ff
00:00:29.246 [ 3851][V][ESP32_NOW.cpp:122] _esp_now_rx_cb(): Checking peer d8:3b:da:e3:1c:cc
00:00:29.246 [ 3851][V][ESP32_NOW.cpp:125] _esp_now_rx_cb(): Calling onReceive
00:00:29.246 The peer received a packet
00:00:30.345 [ 4950][V][ESP32_NOW.cpp:112] _esp_now_rx_cb(): Broadcast from d8:3b:da:e3:1c:cc, data length : 1
00:00:30.346 0x00, // .
00:00:30.346 [ 4951][V][ESP32_NOW.cpp:122] _esp_now_rx_cb(): Checking peer ff:ff:ff:ff:ff:ff
00:00:30.346 [ 4951][V][ESP32_NOW.cpp:122] _esp_now_rx_cb(): Checking peer d8:3b:da:e3:1c:cc
00:00:30.346 [ 4952][V][ESP32_NOW.cpp:125] _esp_now_rx_cb(): Calling onReceive
00:00:30.346 The peer received a packet
I can see that it's successfully advertising, your slave device doesn't scan for BLE advertisements though but it is receiving the esp now messages. What am I missing here?
Yes what you described works, the problem js that the master device doesn't receive back the message from the slave after pairing.
You can see in the slave log I copied here
00:00:28.248 [ 2850][V][ESP32_NOW.cpp:115] _esp_now_rx_cb(): Calling new_cb, peer not found.
00:00:28.248 Unknown peer d8:3b:da:e3:1c:cc sent a broadcast message
00:00:28.248 Registering the peer as a master
00:00:28.248 [ 2853][V][ESP32_NOW.cpp:18] _esp_now_add_peer(): d8:3b:da:e3:1c:cc
00:00:28.248 [ 2856][V][ESP32_NOW.cpp:311] add(): Peer added - d8:3b:da:e3:1c:cc
00:00:28.248 [ 2856][V][ESP32_NOW.cpp:384] send(): d8:3b:da:e3:1c:cc, data length 1
00:00:28.288 [ 2894][V][ESP32_NOW.cpp:133] _esp_now_tx_cb(): d8:3b:da:e3:1c:cc : FAILED
00:00:28.289 [ 2895][I][ESP32_NOW.h:78] onSent(): Message transmission to peer d8:3b:da:e3:1c:cc failed
00
Ahh okay, in that case the only thing I can think of is since the master device is advertising BLE the antenna is in use and the coexist functions may not work well with esp now, hard to say for sure, never tried this.
It seems it should be working according to this page https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/coexist.html
I don't know what to try next
Does it work if you do not start advertising?
Some info here : https://esp32.com/viewtopic.php?t=23406
check this example.
#include <NimBLEDevice.h>
#include <esp_sleep.h>
#include <WiFi.h>
#include "ESP32_NOW.h" // We use the new ESP32_NOW library
#include <esp_mac.h>
// =============================================
// DEFINES
// =============================================
#define SERVICE_UUID "4fafc201-1fb5-459e-8fcc-c5c9c331914b"
#define CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a8"
#define BLE_WAIT_TIME 5000 // 5 seconds for BLE connection
#define SLEEP_TIME_SEC 5 // Sleep time in seconds
#define ESPNOW_WIFI_CHANNEL 6 // Wi-Fi channel for ESP-NOW
// Structure for ESP-NOW data
typedef struct struct_message {
uint32_t counter; // We use the same format as BLE
} struct_message;
// =============================================
// GLOBAL VARIABLES
// =============================================
RTC_DATA_ATTR uint32_t count = 0; // Persistent counter in RTC memory
struct_message myData;
// BLE objects
NimBLEServer* pServer = nullptr;
NimBLECharacteristic* pCharacteristic = nullptr;
bool deviceConnected = false;
// Class to handle ESP-NOW broadcast
class ESP_NOW_Broadcast_Peer : public ESP_NOW_Peer {
public:
// Constructor of the class using the broadcast address
ESP_NOW_Broadcast_Peer(uint8_t channel, wifi_interface_t iface, const uint8_t *lmk)
: ESP_NOW_Peer(ESP_NOW.BROADCAST_ADDR, channel, iface, lmk) {}
// Destructor of the class
~ESP_NOW_Broadcast_Peer() {
remove();
}
// Function to properly initialize ESP-NOW and register the broadcast peer
bool begin() {
if (!ESP_NOW.begin() || !add()) {
log_e("Failed to initialize ESP-NOW or register the broadcast peer");
return false;
}
return true;
}
// Function to send a message to all devices on the network
bool send_message(const uint8_t *data, size_t len) {
if (!send(data, len)) {
log_e("Failed to broadcast message");
return false;
}
return true;
}
};
// Instance of the broadcast peer
ESP_NOW_Broadcast_Peer broadcast_peer(ESPNOW_WIFI_CHANNEL, WIFI_IF_STA, NULL);
// =============================================
// CALLBACKS & CLASSES
// =============================================
// BLE server callbacks
class ServerCallbacks: public NimBLEServerCallbacks {
void onConnect(NimBLEServer* pServer, NimBLEConnInfo& connInfo) override {
Serial.printf("Client address: %s\n", connInfo.getAddress().toString().c_str());
deviceConnected = true;
/**
* We can use the connection handle here to ask for different connection parameters.
* Args: connection handle, min connection interval, max connection interval
* latency, supervision timeout.
* Units; Min/Max Intervals: 1.25 millisecond increments.
* Latency: number of intervals allowed to skip.
* Timeout: 10 millisecond increments.
*/
pServer->updateConnParams(connInfo.getConnHandle(), 24, 48, 0, 180);
}
void onDisconnect(NimBLEServer* pServer, NimBLEConnInfo& connInfo, int reason) override {
Serial.printf("Client disconnected\n");
deviceConnected = false;
}
}serverCallbacks;
// =============================================
// FUNCTIONS
// =============================================
void configBle() {
// Initialize BLE
NimBLEDevice::init("ble"); // BLE device name
Serial.println("Initializing BLE...");
// Create BLE server
pServer = NimBLEDevice::createServer();
pServer->setCallbacks(&serverCallbacks);
// Create service and characteristic
NimBLEService* pService = pServer->createService(SERVICE_UUID);
pCharacteristic = pService->createCharacteristic(
CHARACTERISTIC_UUID,
NIMBLE_PROPERTY::NOTIFY | NIMBLE_PROPERTY::WRITE
);
// Start service
pService->start();
// Configure BLE advertising to include the service
NimBLEAdvertising* pAdvertising = NimBLEDevice::getAdvertising();
pAdvertising->addServiceUUID(SERVICE_UUID);
//pAdvertising->setMinInterval(160); // 100 ms
//pAdvertising->setMaxInterval(320); // 200 ms
pAdvertising->enableScanResponse(false);
pAdvertising->start();
Serial.println("BLE started and advertising enabled.");
}
void disableBle() {
NimBLEDevice::deinit(true);
Serial.println("BLE disabled");
}
void sendDataBle() {
Serial.print("Sending via BLE: ");
Serial.println(count);
pCharacteristic->setValue((uint8_t*)&count, sizeof(count));
pCharacteristic->notify();
}
void sendDataEspNow() {
myData.counter = count;
Serial.print("Sending via ESP-NOW: ");
Serial.println(myData.counter);
if (!broadcast_peer.send_message((uint8_t*)&myData, sizeof(myData))) {
Serial.println("Error sending data via ESP-NOW");
}
}
void goToSleep(int seconds) {
Serial.println("Entering sleep mode...");
delay(100); // Small delay to finish operations
esp_sleep_enable_timer_wakeup(seconds * 1000000LL);
esp_deep_sleep_start();
}
// =============================================
// SETUP & LOOP
// =============================================
void setup() {
Serial.begin(115200);
setCpuFrequencyMhz(80); // Reduce frequency to save power
count++; // Increment counter upon waking up
// Configure and wait for BLE connection
configBle();
unsigned long startTime = millis();
while (millis() - startTime < BLE_WAIT_TIME) {
if (deviceConnected) break;
delay(100); // Non-blocking wait
}
// If no BLE connection, send via ESP-NOW
if (!deviceConnected) {
//disableBle();
// Configure Wi-Fi for ESP-NOW
WiFi.mode(WIFI_STA);
WiFi.setChannel(ESPNOW_WIFI_CHANNEL);
while (!WiFi.STA.started()) {
delay(100);
}
// Register the broadcast peer
if (!broadcast_peer.begin()) {
Serial.println("Failed to initialize broadcast peer");
Serial.println("Rebooting in 5 seconds...");
delay(5000);
ESP.restart();
}
sendDataEspNow();
goToSleep(SLEEP_TIME_SEC);
}
}
void loop() {
if (deviceConnected) {
sendDataBle();
count++; // Increment after sending
delay(1000); // Wait 1 second between sends
} else {
goToSleep(SLEEP_TIME_SEC);
}
}