Introduction: Multiple ITags With ESP32

About: Do you like technology? Follow my channel on Youtube and my Blog. In them I put videos every week of microcontrollers, arduinos, networks, among other subjects.

Let's return to talking about iTag today, which is this Bluetooth key ring. I have already discussed this subject in this video: Presence Sensor with iTag Bluetooth BLE. This time, we will use THREE devices. Let's link a relay to each iTag, and by pressing the specific iTag button, we'll turn on / off the relay bound to it. I find all this to be an example of very useful automation.

Step 1: Demonstration

I made an example using a humidifier and two lamps.

Step 2: Change BLE Library

Go to and download the multi-client BLE library zip made by nsamala, and replace it at:

C: \ Users \ \ Documents \ Arduino \ hardware \ espressif \ esp32 \ libraries.

Back up the old folder before replacing, because if this other lib gives you a problem with a project that you already have and is working, you can change back. Open the file:

C: \ Users \ \ Documents \ Arduino \ hardware \ espressif \ esp32 \ libraries \ BLE \ src \ BLERemoteCharacteristic.cpp

Comment on the lines 500 and 501. At the moment they create problems with the iTag (considering that we do not need these lines in this project), it is safe to comment them.

Step 3: ITag_Multi.ino

Let's include the BLEDevice library. Here, we have the customer ID that will be incremented each time a new client connects, in addition to the UUID of the service we want from iTag and the UUID of the service characteristic (iTag button).

#include <BLEDevice.h>
//Id dos clientes. É incrementado toda vez que se conecta um novo cliente static uint16_t appId = 3; //UUID do serviço que queremos do iTag static const BLEUUID serviceUUID("0000ffe0-0000-1000-8000-00805f9b34fb"); //UUID da característica do serviço (botão do iTag) static const BLEUUID characteristicUUID("0000ffe1-0000-1000-8000-00805f9b34fb");

Step 4: ITag_Multi.ino - ITag Class

We create a class responsible for controlling each iTag. We define the number linked to each device, status, client of the connection to iTag, and the address to connect it to.

//Classe responsável por controlar cada iTag
class ITag : public BLENotifier { public: int pinNumber; //número do pino vinculado a este iTag int pinStatus = HIGH; //status autal do pino (HIGH ou LOW) BLEClient* client; //cliente da conexão com o iTag std::string address; //endereço do iTag ao qual irá se conectar

We linked the values of address, pin number, and we put it as output and with a state of LOW.

ITag(std::string addrs, int pNum)
{ //Vinculamos os valores do endereço, número do pino, colocamos como saída address = addrs; pinNumber = pNum; pinMode(pinNumber, OUTPUT); digitalWrite(pinNumber, pinStatus); }

We checked if there was a client before, and we disconnect it in such a situation. We create the client with a new ID, and connect to iTag. If the connection is successful, we get the service and feature of the iTag button and link the onData function to respond when the button is pressed.

void connect()
{ //Verificamos se já havia um cliente antes e desconectamos caso afirmativo if(client != NULL) { client->disconnect(); delete client; } //Criamos o cliente com uma nova id e conectamos ao iTag client = BLEDevice::createClient(appId++); BLEAddress bleAddress(address); boolean connected = client->connect(bleAddress); //Se a conexão foi bem sucedida if(connected) { //Obtemos o serviço e característica do botão do iTag e vinculamos a função onData //para responder o pressionar de botão BLERemoteService* remoteService = client->getService(serviceUUID); BLERemoteCharacteristic* remoteCharacteristic = remoteService->getCharacteristic(characteristicUUID); remoteCharacteristic->registerForNotify(this); } }

The onData function will be called every time the iTag button is pressed. We reverse the current state of the pin (from HIGH to LOW or from LOW to HIGH) and send the new state to the output of the pin. We finish the iTag class.

//Função chamada toda vez que o botão do iTag é pressionado
void onData(BLERemoteCharacteristic* pBLERemoteCharacteristic, uint8_t* pData, size_t length, bool isNotify) { //Invertemos o estado atual do pino (de HIGH para LOW ou de LOW para HIGH) //e mandamos o novo estado para saída do pino pinStatus = !pinStatus; digitalWrite(pinNumber, pinStatus); } };

Step 5: ITag_Multi.ino

We determine the interval between each scan and the amount of iTag we have (change according to how many iTags you have). We then execute the definition of the iTags that we will use. For each iTag, we will link its address (obtained through a scan), and the pin whose state will be changed when the iTag button is pressed. We also check the variable that will save the scan, and we also check when the last scan occurred.

//Intervalo entre cada scan
#define SCAN_INTERVAL 3000 //Quantidade de iTag que temos (altere de acordo com a quantidade de iTags que tiver) #define ITAG_COUNT 3 //Definição dos iTags que iremos utilizar //Para cada iTag vinculamos o endereço dele (obtido através de um scan) //e o pino cujo o estado será alterado quando o botão do iTag for pressionado ITag iTags[ITAG_COUNT] = { ITag("ff:ff:c2:07:ab:16", 25), ITag("ff:ff:c2:07:9d:b6", 26), ITag("ff:ff:c2:07:8f:bf", 27) }; //Variável que irá guardar o scan BLEScan* pBLEScan; //Quando ocorreu o último scan uint32_t lastScanTime = 0;

iTag_Multi.ino - setup

We start the BLE and save the object responsible for the scan.

void setup()
{ Serial.begin(115200); //Iniciamos o BLE BLEDevice::init(""); //Guardamos o objeto responsável pelo scan pBLEScan = BLEDevice::getScan(); pBLEScan->setActiveScan(true); }

iTag_Multi.ino - loop

Using the time in milliseconds since boot, we check the time required to scan. We check when the last scan occurred, and we start the scan.

void loop()
{ //Tempo em milissegundos desde o boot uint32_t now = millis(); //Se está no tempo de fazer scan if(now - lastScanTime > SCAN_INTERVAL) { //Marca quando ocorreu o último scan e começa o scan lastScanTime = now; scan(); } }

iTag_Multi.ino - scan

We performed the scan for 2 seconds. For each device found by the scan, we save the reference to the device and show it on the serial monitor. For every iTag we have, let's look at whether it is from our scanned devices. If so, send it on.

void scan()
{ //Realiza o scan por 2 segundos BLEScanResults results = pBLEScan->start(2); pBLEScan->stop(); //Para cada dispositivo encontrado pelo scan for(int i=0; i

Step 6: Files

Download the files