#include <WiFi.h>
#include <ESPAsyncWebServer.h>
#include <AsyncTCP.h>
#include <BLEDevice.h>
// soubor se strankou
#include "stranka.h"
// The remote service we wish to connect to.
static BLEUUID serviceUUID("ebe0ccb0-7a0a-4b0c-8a1a-6ff2997da3a6");
// The characteristic of the remote service we are interested in.
static BLEUUID charUUID("ebe0ccc1-7a0a-4b0c-8a1a-6ff2997da3a6");
// ble client obj
BLEClient *pClient;
// ble scan obj
BLEScan *pBLEScan;
// "Objekt" pro uchovani dat ze sensoru
struct sensor_data {
float temperature = 0;
float humidity = 0;
float voltage = 0;
} sensorData;
// pripojeno na sensor?
bool connected = false;
// mame v planu bt scan?
bool runBleScan = false;
// buffer pro adresy, ktery jsou valid
std::string addresses[10];
int addressCount = 0;
#define SCAN_TIME 10 // seconds
// =======================
// FUNKCE PRO ZAPNUTI WIFI
// =======================
void wifi_setup_ap(const char* ssid, const char* password)
{
WiFi.mode(WIFI_AP);
WiFi.softAP(ssid, password);
Serial.print("AP spustena! Pripoj se na tuhle ip: ");
Serial.println(WiFi.softAPIP());
}
void wifi_setup_local(const char* ssid, const char* password)
{
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
if (WiFi.waitForConnectResult() != WL_CONNECTED) {
Serial.println("Nepovedlo se zapnout WiFi. Mas spravne prihlasovaci udaje?");
return;
}
Serial.print("IP adresa na wifi: ");
Serial.println(WiFi.localIP());
}
// ==========
// BLE FUNKCE
// ==========
class MyClientCallback : public BLEClientCallbacks
{
void onConnect(BLEClient *pclient)
{
connected = true;
Serial.printf(" * Connected %s\n", pclient->getPeerAddress().toString().c_str());
}
void onDisconnect(BLEClient *pclient)
{
connected = false;
Serial.printf(" * Disconnected %s\n", pclient->getPeerAddress().toString().c_str());
}
};
// inicializace ble
void ble_init()
{
Serial.println("Zapinam BLE");
BLEDevice::init("ESP32");
// Vytvor bte klienta
pClient = BLEDevice::createClient();
// priradme callbacky
pClient->setClientCallbacks(new MyClientCallback());
// vytvor scan
pBLEScan = BLEDevice::getScan(); // create new scan
// zalezi
pBLEScan->setActiveScan(true); // active scan uses more power, but get results faster
pBLEScan->setInterval(0x50);
pBLEScan->setWindow(0x30);
}
// ==================
// HTTP SERVER FUNKCE
// ==================
// port 80
AsyncWebServer server(80);
void notFound(AsyncWebServerRequest *request)
{
request->send(404, "text/plain", "Not found");
}
void serverpage_root(AsyncWebServerRequest *request)
{
request->send(200, "text/html", index_html);
}
void serverpage_sensor(AsyncWebServerRequest *request)
{
String reading = "Temperature: ";
reading += sensorData.temperature;
reading += "; Humidity: ";
reading += sensorData.humidity;
reading += "; Voltage: ";
reading += sensorData.voltage;
runBleScan = true;
request->send(200, "text/plain", reading);
}
// =======
// UTILITY
// =======
// borrowed from stackoverflow
char *trimwhitespace(char *str)
{
char*end;
// Trim leading space
while (isspace((unsigned char)*str))
str++;
if (*str == 0) // All spaces?
return str;
// Trim trailing space
end = str + strlen(str) - 1;
while (end > str && isspace((unsigned char)*end))
end--;
// Write new null terminator character
end[1] = '\0';
return str;
}
void setup()
{
Serial.begin(115200);
/* BLE INIT */
ble_init();
// Wifi
const char *ssid = "esp-ap";
const char *password = "";
/* WIFI INIT */
//wifi_setup_local(ssid, password);
wifi_setup_ap(ssid, password);
server.on("/", HTTP_GET, serverpage_root);
server.on("/sensor", HTTP_GET, serverpage_sensor);
// handle 404
server.onNotFound(notFound);
server.begin();
// running ble scan at init
runBleScan = true;
}
////
static void notifyCallback(
BLERemoteCharacteristic *pBLERemoteCharacteristic,
uint8_t *pData,
size_t length,
bool isNotify)
{
// zavolali nas!
Serial.print(" + Notify callback for characteristic ");
Serial.println(pBLERemoteCharacteristic->getUUID().toString().c_str());
// narvi to do do sensorData
sensorData.temperature = (pData[0] | (pData[1] << 8)) * 0.01; // little endian
sensorData.humidity = pData[2];
sensorData.voltage = (pData[3] | (pData[4] << 8)) * 0.001; // little endian
Serial.printf("temp = %.1f C ; humidity = %.1f %% ; voltage = %.3f V\n", sensorData.temperature, sensorData.humidity, sensorData.voltage);
pClient->disconnect();
}
void registerNotification(bool connected)
{
if (!connected) {
Serial.println(" - Premature disconnection");
return;
}
// Obtain a reference to the service we are after in the remote BLE server.
// najdi service, ktera nas zajima
BLERemoteService *pRemoteService = pClient->getService(serviceUUID);
if (pRemoteService == nullptr) {
Serial.print(" - Failed to find our service UUID: ");
Serial.println(serviceUUID.toString().c_str());
pClient->disconnect();
}
Serial.println(" + Found our service");
// Obtain a reference to the characteristic in the service of the remote BLE server.
// v ty najdi charakteristiku co nas zajima
BLERemoteCharacteristic *pRemoteCharacteristic = pRemoteService->getCharacteristic(charUUID);
if (pRemoteCharacteristic == nullptr) {
Serial.print(" - Failed to find our characteristic UUID: ");
Serial.println(charUUID.toString().c_str());
pClient->disconnect();
}
Serial.println(" + Found our characteristic");
// az nas bude notifikovat (asi) tak nahod callback
pRemoteCharacteristic->registerForNotify(notifyCallback);
}
void bleScan()
{
BLEScanResults foundDevices = pBLEScan->start(SCAN_TIME);
int count = foundDevices.getCount();
Serial.printf("+ Found device count : %d\n", count);
// vypis nalezena zarizeni a zjisti, jestli nejaky jsou senzor
for (int i = 0; i < count; i++) {
BLEAdvertisedDevice b = foundDevices.getDevice(i);
Serial.println(b.toString().c_str());
if (!b.getName().compare("LYWSD03MMC")) {
BLEAddress addr = b.getAddress();
addresses[addressCount] = addr.toString();
addressCount++;
}
}
// zjisti, jestli jsou vsechny adresy online
for (int i = 0; i < addressCount; i++) {
std::string curAddr = addresses[i];
bool found = false;
for (int j = 0; j < count; j++) {
if (foundDevices.getDevice(j).getAddress().equals(BLEAddress(curAddr))) {
found = true;
}
}
if (!found) {
Serial.printf("* Remove offline address : %s\n\r", curAddr.c_str());
for (int j = addressCount; j > max(i, 1); j--) {
addresses[j - 1] = addresses[j];
}
continue;
}
// jestli je, tak se pripoj a sezen data
Serial.printf("+ Connect : %s\n\r", curAddr.c_str());
pClient->connect(BLEAddress(curAddr));
registerNotification(connected);
while (connected) {
delay(10);
};
}
}
////
void loop()
{
if (runBleScan) {
runBleScan = false;
bleScan();
}
delay(1000);
}