The Ultimate BLE Presence Detector

Introduction: The Ultimate BLE Presence Detector

About: Photonics Engineer

Hi there,

In this instructable I will show how I made a really simple Bluetooth Low Energy presence detector, using my smart wristband and a relay I was able to control the ligths of my room;

Everytime I go in, turn the light on and if I left the room or cut the bluetooth connection, the lights turn off.

Step 1: Parts

I'm using a ESP32 Feather but any other will work

1 5v Relay

1 TIP31C Transsitor

1 BLE Server device (Any beacon device)

The TIP31C its ment to control the relay, beacuse the 3V3 digital outputs of the ESP32 are not enough in voltage and current

The relay to control the 120V lights and the wristband to detect the presence of the person.

Step 2: Circuit

This is really simple, the pin number 33 of the ESP32 goes to the base of the transistor, with this we can add the 5V VCC signal and control a bigger voltage with the 3V3 voltage output, then, with the relay we can controll then the 120V of the light.

Step 3: Code

#include "BLEDevice.h"
int Lampara = 33;
int Contador = 0;
static BLEAddress *pServerAddress;
BLEScan* pBLEScan;
BLEClient*  pClient;
bool deviceFound = false;
bool Encendida = false;
bool BotonOff = false;
String knownAddresses[] = { "your:device:mac:address"};
unsigned long entry;
static void notifyCallback(
  BLERemoteCharacteristic* pBLERemoteCharacteristic,
  uint8_t* pData,
  size_t length,
  bool isNotify) {
  Serial.print("Notify callback for characteristic ");
  Serial.print(pBLERemoteCharacteristic->getUUID().toString().c_str());
  Serial.print(" of data length ");
  Serial.println(length);
}
class MyAdvertisedDeviceCallbacks: public BLEAdvertisedDeviceCallbacks {
    void onResult(BLEAdvertisedDevice Device){
      //Serial.print("BLE Advertised Device found: ");
      //Serial.println(Device.toString().c_str());
      pServerAddress = new BLEAddress(Device.getAddress()); 
      bool known = false;
      bool Master = false;
      for (int i = 0; i < (sizeof(knownAddresses) / sizeof(knownAddresses[0])); i++) {
        if (strcmp(pServerAddress->toString().c_str(), knownAddresses[i].c_str()) == 0) 
          known = true;
      }
      if (known) {
        Serial.print("Device found: ");
        Serial.println(Device.getRSSI());
        if (Device.getRSSI() > -85) {
          deviceFound = true;
        }
        else {
          deviceFound = false;
        }
        Device.getScan()->stop();
        delay(100);
      }
    }
};
void setup() {
  Serial.begin(115200);
  pinMode(Lampara,OUTPUT);
  digitalWrite(Lampara,LOW);
  BLEDevice::init("");
  pClient  = BLEDevice::createClient();
  pBLEScan = BLEDevice::getScan();
  pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks());
  pBLEScan->setActiveScan(true);
  Serial.println("Done");
}
void Bluetooth() {
  Serial.println();
  Serial.println("BLE Scan restarted.....");
  deviceFound = false;
  BLEScanResults scanResults = pBLEScan->start(5);
  if (deviceFound) {
    Serial.println("Encender Lamara");
    Encendida = true;
    digitalWrite(Lampara,HIGH);
    Contador = 0;
    delay(10000);
  }
  else{
    digitalWrite(Lampara,LOW);
    delay(1000);
  }
}
void loop() { 
  Bluetooth();
}

Step 4: PCB for Light Control

I made this circtuit on a protoype pcb to make things cleaner.

Step 5: Done

And you are done!

You can use this code to open doors instead, or to control different things

I hope you like my instructable, and if you have any question make me a comment or send me an inbox, I'll be happy to answer

Be the First to Share

    Recommendations

    • Puzzles Speed Challenge

      Puzzles Speed Challenge
    • "Can't Touch This" Family Contest

      "Can't Touch This" Family Contest
    • CNC Contest 2020

      CNC Contest 2020

    29 Discussions

    0
    richard.klingler
    richard.klingler

    4 months ago

    Just tested with my Samsung SmartWatch....switching Bluetooth off and then on shows on the ESP console:

    BLE Scan restarted.....
    abort() was called at PC 0x40169513 on core 0
    Backtrace: 0x40091448:0x3ffcee20 0x40091679:0x3ffcee40 0x40169513:0x3ffcee60 0x4016955a:0x3ffcee80 0x40169607:0x3ffceea0 0x4016968a:0x3ffceec0 0x400d438e:0x3ffceee0 0x400d324a:0x3ffcefd0 0x40100ced:0x3ffcf020 0x400fbe5e:0x3ffcf040 0x4008e089:0x3ffcf070
    Rebooting...
    ets Jun 8 2016 00:22:57
    rst:0xc (SW_CPU_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
    configsip: 0, SPIWP:0xee
    clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
    mode:DIO, clock div:1
    load:0x3fff0018,len:4
    load:0x3fff001c,len:1216
    ho 0 tail 12 room 4
    load:0x40078000,len:9720
    ho 0 tail 12 room 4
    load:0x40080400,len:6352
    entry 0x400806b8
    Done

    0
    Lindermann95
    Lindermann95

    Reply 4 months ago

    It sounds like your issue is with your computer... I use windows and I never had this kind of problem, the base code it is not mine its from a guy on youtube (I just modified to work with a realy) so I've never seen this kind of messages I'm sorry that I cannot help you more...

    0
    richard.klingler
    richard.klingler

    4 months ago

    Just tried it on my ESP-WROOM-32 module....

    Works for a few minutes and then it just hangs....no more detection...
    furthermore on macOS there is no serial output...

    Also tried the above mentioned if (pServerAddress) delete (pServerAddress); to no joy...

    0
    JohnS944
    JohnS944

    6 months ago

    Hi there great project, I re-used the code for a similar bluetooth detection project. I had memory issues ending in an abort every few hours. These Issues stopped when I deleted the created pServerAddress after using it.

    class MyAdvertisedDeviceCallbacks: public BLEAdvertisedDeviceCallbacks {
    void onResult(BLEAdvertisedDevice Device) {


    //Serial.print("BLE Advertised Device found: ");

    //Serial.println(Device.toString().c_str());


    pServerAddress = new BLEAddress(Device.getAddress()); //create the object
    bool known = false;

    bool Master = false;

    if (known) {
    //do stuff....
    {
    if (pServerAddress) delete (pServerAddress); //delete the object if it exists
    }
    };

    0
    ivanzaster
    ivanzaster

    Question 10 months ago on Introduction

    Great project
    it works perfect.

    Im trying to change a little bit your code in order to include a touch capacitive sensor but i got a problem

    i insert the "if" in the loop but the ESP32 ignore it

    if (digitalRead(touchPin) == HIGH) {
    digitalWrite(Lampara, LOW); // relay ON
    Serial.println("Lampara ON");
    }
    Could you give me some help.

    Thanks for the project

    0
    Lindermann95
    Lindermann95

    Reply 10 months ago

    It is because of the speed of the esp32 you should read the pin several times inside the void loop, also you need yo add a delay inside the if, like a 2sec delay so you can take away your finger before it tries to read it again, also... how are you going to turn it off? You need a flag to know if the lamp is already on, then if you touch it again, turns it off

    0
    ivanzaster
    ivanzaster

    Reply 10 months ago

    Thanks for your answer.
    It doesnt work with th delay.

    I dont have a problem with the switch off . I had modified your sketch in order to switch the light on with the detection of the bluetooth known address or the capacitive touch. i had disable the switch off in both devices ( for my requirements i dont need it)

    My problem is that the void loop dont read my "if" sentence.
    Only works with the bluetooth.

    this is all the void loop

    void loop(){
    {
    Serial.println();
    Serial.println("BLE Scan restarted.....");
    deviceFound = false;
    BLEScanResults scanResults = pBLEScan->start(30);
    if (deviceFound) {
    Serial.println("on");
    digitalWrite(lampara, LOW);
    }
    if ((digitalRead(touchPin) == HIGH)) {
    digitalWrite(lampara, LOW); // relay ON
    Serial.println("lampara ON");
    }
    }
    }

    thanks in advance

    0
    ivanzaster
    ivanzaster

    Reply 10 months ago

    hablo mejor en español
    por si te resulta mas comodo
    gracias

    0
    Lindermann95
    Lindermann95

    Reply 10 months ago

    Jaja bueno! Me hubieras dicho antes,

    Bien, el problema con el if es que el esp32 lo intenta leer demasiado rápido, cuando me refiero a que tienes que leerlo muchas, puedes hacer lo siguiente,

    *dentro del void loop*

    int contador=0;
    while(contador <=10){
    if ((digitalRead(touchPin) == HIGH)) {
    digitalWrite(lampara, LOW); // relay ON
    Serial.println("lampara ON");
    break;
    contador +=1;
    delay(150);
    }

    esto va a hacer que lea el pin touch 10 veces, eso te da tiempo suficiente para que lo alcance a leer, la única desventaja es que busca por dispositivos BLE casi todo el tipo, y eso le toma unos segundos, el esp está ocupado... entonces si tocas el sensor mientras el esp esta ocupado, bueno, no va a detectar nada...

    mandame un inbox y te puedo enviar un código que tal vez solucione este problema

    saludos

    0
    Mike Love
    Mike Love

    10 months ago

    Great Project, Just what i am after but, Is there any way to get this to work with an iPhone X? It doesn't seem to detect the iPhone.

    Thanks,
    Mike.

    0
    Lindermann95
    Lindermann95

    Reply 10 months ago

    Hi Mike,

    This might be very complicated due to the library of the BLE, also, the iPhone does not send the MAC address, the iPhone sends a fake Mac every time, untill you decide yo connect to a device.
    You would need to actually connect to de esp32, and that is not possible with this library

    0
    kebibg
    kebibg

    1 year ago

    That is what i search long time. I am not a professional programmer and project like this help me to create my own projects.What will make from this project?
    From long time ago i have a idea for good car imobiliser. Now is time to realize it. With little adding a code i will make it to work with 3-4 MACs (fitnes bands or ibeacons), will add deep sleep in code too.
    When you come to a car and open it (my is with keyless) CAN-BUS wakeup signal from a car will wakeup ESP32 from a deep sleep and he will check for a deisred MAC Address are inside in a range defined by RSSI. If it a present they will allow starting a car. All this procedure from unlock to allowing start take between 0.8 to 1.5 sec.. For more security and to can work with android phones (because now won't) will take UUID for checking instead of a MAC Address. Who don't work with android units? Because from version 5 or 6 for more security BLE in android start anytime with different random generated MAC Address. UUID are used for identifying different services and are unique.

    Sorry for my bad english :(
    If anyone can help with application for android with widged button who will send specific UUID via BLE are welcome.

    Thanks to Lindermann95.
    Regards

    0
    Lindermann95
    Lindermann95

    Reply 1 year ago

    Hi there, I'm sorry, I haven't been around lately, but this car application is one of my plans too
    That's a good idea, the random generation MAC like the one that apple use on the WiFi connction. Maybe that could be the answer, Using WiFi...
    But I havent work that much with WiFi, BLE would be a suitable option at the moment, I'll work in this project and I'll keep in touch with you, have you already done it?

    0
    kebibg
    kebibg

    Reply 1 year ago

    Hi,
    i made it and he work fine at this time. For Authorization I use UUID, because MAC any time when you start advertising service are different this is in BLE standard. Now I use one application who create GATT server with UUID desired by me. I will write more in few days because this is hobby for me and now I have a many professional work.

    Regards

    0
    L_E_U
    L_E_U

    Reply 11 months ago

    Anyway you can show your code on how to use the UUID for auth? I'm having trouble writing it.

    0
    kebibg
    kebibg

    Reply 11 months ago

    Hi L_E_U,
    If you write any application for android who can give unique UUID and he can start with them please give me.

    0
    kebibg
    kebibg

    Reply 11 months ago

    This is part of my code with check and table with known UUIDs

    String knownUUID[] = {"0000fed8-0000-1000-8000-00805f9b34fb"}; //andoid app
    String knownUUID1[] = {"00001805-0000-1000-8000-00805f9b34fb"};
    String knownUUID2[] = {"1000fee0-0000-1000-8000-00805f9b34fb"};
    String knownMAC[] = {"fb:10:30:b2:9c:aa"};
    String knownUUID3 = String("0000fee0-0000-1000-8000-00805f9b34fb");
    String manifID[] = {"570100bfcd47dc45d81bb67fd08cf6c9f0a4cd02fb1030b29caa"};

    class MyAdvertisedDeviceCallbacks: public BLEAdvertisedDeviceCallbacks {

    void onResult(BLEAdvertisedDevice Device)
    {
    Serial.print("BLE Advertised Device found: ");
    Serial.println(Device.toString().c_str());
    pServerAddress = new BLEAddress(Device.getAddress());
    bool known = false;

    for (int i = 0; i < (sizeof(manifID) / sizeof(manifID[0])); i++) { //check bu defined manifactory data
    if( strcmp(Device.getManufacturerData().c_str(), manifID[i].c_str()) == 0) known = true;
    }
    for (int i = 0; i < (sizeof(knownUUID) / sizeof(knownUUID[0])); i++) { //check bu defined UUID
    if( Device.isAdvertisingService(BLEUUID(knownUUID[0].c_str()) )) known = true;
    }
    for (int i = 0; i < (sizeof(knownUUID1) / sizeof(knownUUID1[0])); i++) {
    if( Device.isAdvertisingService(BLEUUID(knownUUID1[0].c_str()) )) known = true;
    }
    for (int i = 0; i < (sizeof(knownUUID2) / sizeof(knownUUID2[0])); i++) {
    if( Device.isAdvertisingService(BLEUUID(knownUUID2[0].c_str()) )) known = true;
    }

    for (int i = 0; i < (sizeof(knownMAC) / sizeof(knownMAC[0])); i++) { //check by defined MAC Address
    if (strcmp(pServerAddress->toString().c_str(), knownMAC[i].c_str()) == 0) //Only for devices with fixed MAC Addrres
    known = true;
    }
    if (known) {
    Serial.print("Authorized : ");
    Serial.println(Device.getRSSI()); //Print RSSI of your device
    if (Device.getRSSI() > -82) { //Changing the Device RSSI you can control how close do you want it to be to actually turn on
    deviceFound = true; //It can detect the wristband but it is too far then do nothing
    }
    else { deviceFound = false; }
    Device.getScan()->stop(); delay(100);
    }
    }
    };
    0
    Lindermann95
    Lindermann95

    Reply 11 months ago

    Great!
    I think that you can separate the known MAC address with a coma, without making another whole string
    For example:
    String knownAddresses[] = { "your:device:mac:address", “second:device:mac:address”, “another:decive:mac:adress”};

    But if kebibg’s codes works too, then there is no problem, you an use any of them

    0
    kebibg
    kebibg

    Reply 11 months ago

    Hi,
    L_E_U want to know how i use UUID for check not MAC.May be your solution will work too for UUID. I am bad programmer and may be my code is not optimized for speed and size. But my car imobiliser work like a charm.