class BleWifiConfigInterface
{
protected:
// ESP32
/** BLE Service */
BLEService *pService;
/** BLE Server */
BLEServer *pServer;
/** Characteristic for digital output */
BLECharacteristic *pCharacteristicWiFi;
/** Characteristic for found WiFi list */
BLECharacteristic *pCharacteristicList;
/** Private UUIDs */
std::string _sreviceUuid = DEF_SERVICE_UUID;
std::string _wifiUuid = DEF_WIFI_UUID;
std::string _listUuid = DEF_WIFI_LIST_UUID;
std::string _statusUuid = DEF_WIFI_STATUS_UUID;
public:
// callbacks
void (*_connectedCallback)() = NULL;
void (*_disconnectedCallback)() = NULL;
/** BLE connection status */
bool deviceConnected;
/** descriptor 2902 */
uint8_t *_stat2902;
/** Characteristic for connection status */
BLECharacteristic *pCharacteristicStatus;
BLEDescriptor *pStatusDescriptor;
/** freeRTOS task handle */
TaskHandle_t sendBLEdataTask;
/** freeRTOS mutex handle */
SemaphoreHandle_t connStatSemaphore;
/** BLE Advertiser */
BLEAdvertising *pAdvertising;
/** int representation of connected to primary ssid (1), secondary (2), or disconnected (0) */
uint16_t sendVal = 0x0000;
/** Preferences */
/** SSIDs of local WiFi networks */
String ssidPrim;
String ssidSec;
/** Password for local WiFi network */
String pwPrim;
String pwSec;
/** Unique device name */
String apName = "ESP32-xxxxxxxxxxxx";
protected:
/**
* Create unique device name from MAC address
**/
String createName()
{
String hostString = String((uint32_t)ESP.getEfuseMac(), HEX);
hostString.toUpperCase();
return "ESP32-" + hostString;
}
void _init(std::string _sreviceUuid, std::string _wifiUuid, std::string _listUuid, std::string _statusUuid);
inline bool _begin(const char *deviceName);
void _startTask(void);
static void sendBLEdata(void *parameter);
void notifyFunc(uint16_t val)
{
Serial.println("notify func");
pCharacteristicStatus->setValue(val);
pCharacteristicStatus->notify(); // Send the value to the app!
}
public:
BleWifiConfigInterface() {}
~BleWifiConfigInterface() {}
void onConnected(void (*fptr)())
{
_connectedCallback = fptr;
}
void onDisconnected(void (*fptr)())
{
_disconnectedCallback = fptr;
}
void init()
{
_sreviceUuid = DEF_SERVICE_UUID;
_wifiUuid = DEF_WIFI_UUID;
_listUuid = DEF_WIFI_LIST_UUID;
_statusUuid = DEF_WIFI_STATUS_UUID;
_init(_sreviceUuid, _wifiUuid, _listUuid, _statusUuid);
}
inline bool begin()
{
return _begin(apName.c_str());
}
};
void BleWifiConfigInterface::_init(std::string _sreviceUuid, std::string _wifiUuid, std::string _listUuid, std::string _statusUuid)
{
// Create unique device name
apName = createName();
// start notification task
_startTask();
Preferences BleWiFiPrefs;
BleWiFiPrefs.begin("BleWiFiCred", false);
bool hasPref = BleWiFiPrefs.getBool("valid", false);
if (hasPref)
{
ssidPrim = BleWiFiPrefs.getString("ssidPrim", "");
ssidSec = BleWiFiPrefs.getString("ssidSec", "");
pwPrim = BleWiFiPrefs.getString("pwPrim", "");
pwSec = BleWiFiPrefs.getString("pwSec", "");
Serial.printf("%s,%s,%s,%s\n", ssidPrim.c_str(), pwPrim.c_str(), ssidSec.c_str(), pwSec.c_str());
if (ssidPrim.equals("") || pwPrim.equals("") || ssidSec.equals("") || pwPrim.equals(""))
{
Serial.println("Found credentials but credentials are invalid");
}
else
{
Serial.println("Read from credentials:");
Serial.println("primary SSID: " + ssidPrim + " password: " + pwPrim);
Serial.println("secondary SSID: " + ssidSec + " password: " + pwSec);
hasCredentials = true;
}
}
else
{
Serial.println("Could not find credentials, need send data over BLE");
}
BleWiFiPrefs.end();
}
bool BleWifiConfigInterface::_begin(const char *deviceName)
{
if (BLEDevice::getInitialized())
{
return false;
}
BLEDevice::init(deviceName);
BLEDevice::setPower(ESP_PWR_LVL_P7);
// Create BLE Server
BLEServer *pServer = BLEDevice::createServer();
// Set server callbacks
pServer->setCallbacks(new MyServerCallbacks(this));
// Create BLE Service
BLEService *pService = pServer->createService(BLEUUID(_sreviceUuid), 20);
// Create BLE Characteristic for WiFi settings
BLECharacteristic *pCharacteristicWiFi = pService->createCharacteristic(
BLEUUID(_wifiUuid),
// WIFI_UUID,
BLECharacteristic::PROPERTY_READ |
BLECharacteristic::PROPERTY_WRITE);
pCharacteristicWiFi->setCallbacks(new MyCallbackHandler(this));
// Create BLE characteristic for found SSIDs
BLECharacteristic *pCharacteristicList = pService->createCharacteristic(
BLEUUID(_listUuid),
BLECharacteristic::PROPERTY_READ);
pCharacteristicList->setCallbacks(new ListCallbackHandler(this));
// Create BLE Characteristic for status notifications
BLECharacteristic *pCharacteristicStatus = pService->createCharacteristic(
BLEUUID(_statusUuid),
BLECharacteristic::PROPERTY_NOTIFY);
// pCharacteristicStatus->setCallbacks(new MyCallbacks()); // If only notifications no need for callback?
BLEDescriptor *pStatusDescriptor = new BLE2902();
pCharacteristicStatus->addDescriptor(pStatusDescriptor);
// pCharacteristicStatus->addDescriptor(new BLE2902());
// Start the service
pService->start();
// Start advertising
BLEAdvertising *pAdvertising = pServer->getAdvertising();
pAdvertising->addServiceUUID(pService->getUUID());
pAdvertising->setScanResponse(true);
pAdvertising->start();
// _stat2902 = pStatusDescriptor->getValue();
_stat2902 = pCharacteristicStatus->getDescriptorByUUID((uint16_t)0x2902)->getValue();
return true;
}
void BleWifiConfigInterface::_startTask()
{
// Set up mutex semaphore
connStatSemaphore = xSemaphoreCreateMutex();
if (connStatSemaphore == NULL)
{
Serial.println("Error creating connStatSemaphore");
}
else
{
Serial.println("Created connection status semaphore");
}
// ble task
xTaskCreate(
sendBLEdata,
"sendBLEdataTask",
2048,
this,
1,
&sendBLEdataTask);
vTaskDelay(pdMS_TO_TICKS(500));
}
/** BLE notification task
* works independently from loop(), in a separate freeRTOS task.
* if the esp32 device (server) is connected to a client, update the client every 1 second
* of the wifi connection status.
* in order to not cause interference between the two tasks, a mutex semaphore is used by the
* wifi connection callbacks which update the variable, loop(), and the notification task.
*/
void BleWifiConfigInterface::sendBLEdata(void *parameter)
{
BleWifiConfigInterface *_bleWifiConfigInterface = (BleWifiConfigInterface *)parameter; //static_cast<BleWifiConfigInterface *>(parameter);
TickType_t xLastWakeTime;
TickType_t xPeriod = pdMS_TO_TICKS(1000);
xLastWakeTime = xTaskGetTickCount();
bool notificationFlag = false;
uint8_t *testNotify = &*_bleWifiConfigInterface->_stat2902;
Serial.println("Starting notifiction task");
while (1)
{
Serial.printf("Task loop. Connected: %x\n", _bleWifiConfigInterface->deviceConnected);
// if the device is connected via BLE try to send notifications
if (_bleWifiConfigInterface->deviceConnected)
{
// Take mutex, set value, give mutex
xSemaphoreTake(_bleWifiConfigInterface->connStatSemaphore, 0);
uint16_t localSendVal = _bleWifiConfigInterface->sendVal;
xSemaphoreGive(_bleWifiConfigInterface->connStatSemaphore);
Serial.printf("testNotify: %i sendVal: %i\n", testNotify, localSendVal);
// if enabled, send value over BLE
if (testNotify != 0)
{
_bleWifiConfigInterface->notifyFunc(localSendVal);
if (!notificationFlag)
{
Serial.println("started notification service");
notificationFlag = true;
}
}
else if (notificationFlag)
{
// else print failure message to serial monitor
Serial.print("notify failed, value of 0x2902 descriptor:\t");
notificationFlag = false;
}
}
// sleep task for 1000 ms
vTaskDelayUntil(&xLastWakeTime, xPeriod);
}
}