The Ultimate BLE Presence Detector

25K2638

Intro: The Ultimate BLE Presence Detector

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

36 Comments

Great idea but the code didn't work for me.
i ended up making my own program and grabbing the UUID data from the BLE beacon and used that to trigger a conditional statement.
Everyone else's code didn't work for me so not just you. I had my Big Brain moment.
so i made a stealthy (somewhat) secure BLE trigger for whatever i do with it.

Hi, if you don't mind me asking. How did you edit the code to grab the UUID instead of using the changing mac address for the software Ibeacon? Would it be possible to use your code. I would really appreciate it.
it might have been the mac address not sure why i called it UUID. but mac shouldn't change randomly since its a computer identifier. It stayed the same for me even after no power for weeks.

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
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?
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
Anyway you can show your code on how to use the UUID for auth? I'm having trouble writing it.
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);
}
}
};
Hi, did you ever get your code to work properly? If so would you mind sharing it?
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
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.
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.
Hello, i got a problem, i copied all the code, i've checked in serial monitor and it says:
rst:0x1 (POWERON_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:1044
load:0x40078000,len:10124
load:0x40080400,len:5856
entry 0x400806a8
Done
BLE Scan restarted.....


So it works, but it doesnt see my phone Huawei p30 pro? Any idea what im doing wrong?

Same issue with the p30 pro , it doesn't see my phone, i don't understand... maybe p30 doesn't have BLE but only classic bluetooth...
(https://forum.xda-developers.com/t/need-android-bluetooth-le-protocol-on-my-huawei-p30.3995905/)


However, for the "BLE Scan restarted" issue, the problem is because you call "BLEScanResults scanResults = pBLEScan->start(5);" too many time.

In fact, if you use the callback with the following line :
pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks());

The "pBLEScan->start(5)" will be not blocking... so the loop will continue and will not wait until the scan is finished.

I fixed the problem by removing callback method and use the following strategy in the loop method :

BLEScanResults foundDevices= pBLEScan->start(5);
for (int i = 0; i < foundDevices.getCount(); i++) {

// Check if the device is the device that you are looking for
// Check the RSSI
// if the RSSI is superior as the threshosld then digitalWrite(LED_BUILTIN, HIGH);

}
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
}
};
Hi John,

could you publish your change into code, but not only as snippet, but how it should be completed? I do not really understand how to incorporate proposed change into code... I am not programmer...

thanks in advance
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

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...
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...

More Comments