iBeacon orten mit ESP32 Bluetooth RSSI

Hier möchte ich ein Sketch zu Bluetooth Ortung vorstellen. Hiermit lässt sich ein versteckte iBeacon finden. Esp32 scannt nach Bluetooth LE Geräten. Wenn ein Bluetooth Gerät mit bestimmten Namen gefunden wird, wird eine Verbindung aufgebaut. Esp32 frag 10 Mal pro Sekunde nach der Signalstärke RSSI. Ein Messwertfilter filtert die Ausreißer im RSSI Wert. Auf der LCD-Anzeige wird ein Mittelwert 2 Mal pro Sekunde erneuert.mit ESP32 iBeacon nach RSSI Suchen bluetooth Find

Arduino Sketch für esp32 mit Ausgabe über serielle Schnittstelle

/*
   nRF51822 iBeacon Suchgerät mit RSSI Anzeige
   ESP32 Sucht nach einem iBeacon mit bestimmten Namen, Paart und misst RSSI 10 mal pro Sekunde.
   Gleitender Mittelwert Filter (running average) für RSSI glättet Ausreißer. 
   Michael Dworkin https://esp32-server.de/
   Based on Neil Kolban example
*/
#include <BLEDevice.h>

static boolean Verbinde = false;   // Phasen
static boolean Verbunden = false;
static boolean Suche = true;

int scanTime = 10;                // In Bluetooth Scanzeit in secunden
String BuetoothName = "RDL51822"; // Bluetooth Name des iTags

#define FilterFaktor 0.2          //  running average Filter Einstellung
float val_f;                      //  0,05 erhöht die Verspätung bei Änderung, macht aber das Wert stabiler
int zeler=1;

static BLEAddress *pServerAddress;
static BLEClient*  pClient;
static BLEAdvertisedDevice* myDevice;
static BLERemoteCharacteristic* pRemoteCharacteristic;
BLEScan* pBLEScan ;

class MyAdvertisedDeviceCallbacks: public BLEAdvertisedDeviceCallbacks
{
    void onResult(BLEAdvertisedDevice advertisedDevice) // passiert wenn BLE Device ( beacon ) gefunden wurde
    {
      Serial.print(advertisedDevice.getAddress().toString().c_str()); // ibeacon Adresse anzeigen
      if (advertisedDevice.haveName())
        if (advertisedDevice.getName() == BuetoothName.c_str())       // ibeacon Adresse Vergleichen
        {
          Serial.print(" gefunden " + BuetoothName);                  // wenn überwache Adresse gefunden wurde                                    
          BLEDevice::getScan()->stop();                               // Scanvorgang beenden
          myDevice = new BLEAdvertisedDevice(advertisedDevice);
          Verbinde = true;
          Suche = false;
        } 
      Serial.println("");
    }
};

class MyClientCallback : public BLEClientCallbacks {
    void onConnect(BLEClient* pclient) {
      Serial.println("Verbunden");
      Verbunden = true;
      Verbinde = false;
    }

    void onDisconnect(BLEClient* pclient) {
      Verbunden = false;
      Verbinde = false;
      Suche = true;
      Serial.println("Verbindung verloren");
    }
};

void setup()
{
  Serial.begin(115200);
  Serial.println("");
  Serial.println("Starte RSSI Meter für " + BuetoothName);

  BLEDevice::init("");
  pBLEScan = BLEDevice::getScan(); 
  pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks());
  pBLEScan->setActiveScan(true); 
  pBLEScan->setInterval(1349);
  pBLEScan->setWindow(449);
  pBLEScan->start(scanTime);
}

void loop()
{
  if (Suche) pBLEScan->start(scanTime);
  
  if (Verbinde == true)
  {
    Serial.print("Verbinde mit ");
    Serial.println(myDevice->getAddress().toString().c_str());
    pClient = BLEDevice::createClient();
    pClient->setClientCallbacks(new MyClientCallback());
    pClient->connect(myDevice);
  }

  if (Verbunden) // Gepaart
  {
    delay(100);       // RSSI alle 100 mS abfragen
    
    // ----------------- Messwert Filter ------------------    
    val_f = pClient->getRssi() * FilterFaktor + val_f * (1 - FilterFaktor);
    
    if (!zeler)        // Ausgabe jeder 5 durchlauf (2x pro Sekunde)
    {
      Serial.println(int(round(val_f))); // Runden und Ganze Zahl bilden
      zeler = 5;
    }
    else  zeler--;
  }
}

 

iBeacon Suchgerät mit OLED Display

Das Display ist ein 128X64 1,3 Zoll OLED LCD mit I2C Schnittstelle.

#include <BLEDevice.h>

static boolean Verbinde = false;        // Phasen
static boolean Verbunden = false;
static boolean Suche = true;

int scanTime = 10;                    // In Bluetooth Scanzeit in secunden
String BuetoothName = "RDL51822";     // Bluetooth Name des iTags

#define FilterFaktor 0.1             //  running average Filter Einstellung
float val_f;                    //  0,05 erhöht die Verspätung bei Änderung, macht aber das Wert stabiler
int zeler = 1;

static BLEAddress *pServerAddress;
static BLEClient*  pClient;
static BLEAdvertisedDevice* myDevice;
static BLERemoteCharacteristic* pRemoteCharacteristic;
BLEScan* pBLEScan ;

#include <SPI.h>
#include <Wire.h>
#include "Adafruit_GFX.h"
#include "Adafruit_SH1106.h"
#include <Fonts/FreeSans12pt7b.h>
#include <Fonts/FreeMonoBold24pt7b.h>

#define OLED_SDA 12
#define OLED_SCL 14
Adafruit_SH1106 display(OLED_SDA, OLED_SCL);

class MyAdvertisedDeviceCallbacks: public BLEAdvertisedDeviceCallbacks
{
    void onResult(BLEAdvertisedDevice advertisedDevice) // passiert wenn BLE Device ( beacon ) gefunden wurde
    {
      Serial.print(advertisedDevice.getAddress().toString().c_str()); // ibeacon Adresse anzeigen
      if (advertisedDevice.haveName())
        if (advertisedDevice.getName() == BuetoothName.c_str())    // ibeacon Adresse Vergleichen
        {
          Serial.print(" gefunden " + BuetoothName);                // wenn überwache Adresse gefunden wurde                                    // Ausschaltverzögerung zurücksetzen
          BLEDevice::getScan()->stop();                             // Scanvorgang beenden
          myDevice = new BLEAdvertisedDevice(advertisedDevice);
          Verbinde = true;
          Suche = false;
          display.clearDisplay();
          display.setCursor(0, 32 + 6);
          display.println("Gefunden");
          display.display();
        }
      Serial.println("");
    }
};

class MyClientCallback : public BLEClientCallbacks {
    void onConnect(BLEClient* pclient) {
      Serial.println("Verbunden");
      Verbunden = true;
      Verbinde = false;
      display.setFont(&FreeMonoBold24pt7b);
    }

    void onDisconnect(BLEClient* pclient) {
      Verbunden = false;
      Verbinde = false;
      Suche = true;
      Serial.println("Verbindung verloren");
      display.setFont(&FreeSans12pt7b);
    }
};

void setup()
{
  Serial.begin(115200);
  Serial.println("");
  Serial.println("Starte RSSI Meter für " + BuetoothName);
  display.begin(SH1106_SWITCHCAPVCC, 0x3C);  // initialize with the I2C addr 0x3D (for the 128x64)
  display.clearDisplay();
  display.display();
  display.setTextColor(WHITE);
  display.setCursor(0, 32 + 6);
  display.setFont(&FreeSans12pt7b);
  display.println("START");
  display.display();
  BLEDevice::init("");
  pBLEScan = BLEDevice::getScan();
  pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks());
  pBLEScan->setActiveScan(true);
  pBLEScan->setInterval(1349);
  pBLEScan->setWindow(449);
  pBLEScan->start(scanTime);
}

void loop()
{
  if (Suche)
  {
    display.clearDisplay();
    display.setCursor(0, 32 + 6);
    display.println("Suche");
    display.display();
    pBLEScan->start(scanTime);
  }

  if (Verbinde == true)
  {
    Serial.print("Verbinde mit ");
    Serial.println(myDevice->getAddress().toString().c_str());
    pClient = BLEDevice::createClient();
    pClient->setClientCallbacks(new MyClientCallback());
    pClient->connect(myDevice);
  }

  if (Verbunden) // Gepaart
  {
    delay(100);       // RSSI alle 100 mS abfragen

    // ----------------- Messwert Filter ------------------
    val_f = pClient->getRssi() * FilterFaktor + val_f * (1 - FilterFaktor);

    if (!zeler)        // Ausgabe jeder 5 durchlauf (2x pro Sekunde)
    {
      Serial.println(int(round(val_f))); // Runden und Ganze Zahl bilden
      display.clearDisplay();
      display.setCursor(10, 44);
      display.println(int(round(val_f)));
      display.display();
      zeler = 5;
    }
    else  zeler--;
  }
}