Vamos voltar a falar hoje do
iTag, que é esse chaveiro com Bluetooth, que eu já detalhei neste vídeo: Sensor de Presença com iTag Bluetooth BLE. Desta vez, vamos utilizar TRÊS
dispositivos. Vamos vincular um relé para cada iTag, sendo que, ao pressionar o
botão de determinado iTag, vamos ligar/desligar o relé vinculado a ele. Considero
tudo isso um exemplo de automação bastante útil.
Demonstração
Fiz um exemplo usando um
umidificador e duas lâmpadas.
Alterar Biblioteca BLE
Vá até https://github.com/nsamala/ESP32_BLE_Arduino
e baixe o zip da biblioteca BLE com suporte a múltiplos clientes feita pelo
nsamala, e substitua em:
C:\Users\<SEU_USUARIO>\Documents\Arduino\hardware\espressif\esp32\libraries.
Faça backup da pasta antiga
antes de substituir, pois caso essa outra lib der algum problema com algum projeto
que você já tenha e esteja funcionando você pode trocar de volta. Abra o
arquivo:
C:\Users\<SEU_USUARIO>\Documents\Arduino\hardware\espressif\esp32\libraries\BLE\src\BLERemoteCharacteristic.cpp
Comente as linhas 500 e 501.
No momento elas estão dando problema com o iTag e como não precisamos destas
linhas neste projeto é seguro comentá-las.
iTag_Multi.ino
Vamos incluir a biblioteca
BLEDevice. Temos aqui o ID dos clientes que será incrementado toda vez que se
conecta um novo cliente, além do UUID do serviço que queremos do iTag e o UUID
da característica do serviço (botão do iTag).
#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");
iTag_Multi.ino – Classe ITag
Criamos uma classe responsável
por controlar cada iTag. Definimos o número vinculado a cada dispositivo,
status, cliente da conexão com o iTag e o endereço ao qual deverá se conectar.
//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
Vinculamos os valores do endereço, número do pino, colocamos como saída e estado 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);
}
Verificamos se já havia um cliente antes e desconectamos em caso afirmativo. Criamos o cliente com uma nova ID e conectamos ao iTag. Se a conexão for bem sucedida, obtemos o serviço e característica do botão do iTag e vinculamos a função onData para responder quando o botão for pressionado.
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);
}
}
A função onData será chamada toda vez que o botão do iTag for pressionado. 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. Finalizamos a classe iTag.
//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);
}
};
iTag_Multi.ino
Determinamos o intervalo entre
cada scan e a quantidade de iTag que temos (altere de acordo com a quantidade
de iTags que tiver). Executamos, então, a 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. Verificamos
ainda a variável que irá guardar o scan e quando ocorreu o último scan.
//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
Iniciamos o BLE e guardamos o
objeto responsável pelo 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
Utilizando o tempo em
milissegundos desde o boot, verificamos o tempo necessário para fazer scan. Marcamos
quando ocorreu o último scan e iniciamos o 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
Realizamos o scan por 2
segundos. Para cada dispositivo encontrado pelo scan, guardamos a referência
para o dispositivo e mostramos no monitor serial. Para cada iTag que temos,
vamos analisar se se trata dos nossos dispositivos scaneados. Em caso positivo,
mandamos conectar.
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<results.getCount(); i++)
{
//Guardamos a referência para o dispositivo e mostramos no monitor serial
BLEAdvertisedDevice advertisedDevice = results.getDevice(i);
Serial.println("advertisedDevice: " + String(advertisedDevice.toString().c_str()));
//Para cada iTag que temos
for(int j=0; j<ITAG_COUNT; j++)
{
//Se o dispositivo scaneado for um dos nossos iTags
if(advertisedDevice.getAddress().toString() == iTags[j].address)
{
//Mandamos conectar
iTags[j].connect();
}
}
}
}
Faça o download dos arquivos?





9 Comentários
Fernando boa tarde!
ResponderExcluirSabe se existe alguma maneira do iTag ficar ligado sem desligar após 15 minutos?
Obrigado!
Fortalecendo a pergunta. Tenho esta dificuldade também
ExcluirFernando boa tarde,
ResponderExcluirEm em If (connected), aparece a mensagem
"Nenhuma função correspondente para chamar a 'BLURemoteCharacteristic::registrador produto(ITag*)'
A mensagem na verdade é "Nenhuma função correspondente para chamar a 'BLURemoteCharacteristic::registerForNotfy(ITag*)'
ExcluirOla Fernando,
ResponderExcluirVocê saberia dizer qual o limite de conexoes simultaneas para diferentes dispositivos itag?
Segui todos os passos mas da erro ao carregar.
ResponderExcluiressa linha fica vermelha - class ITag : public BLENotifier {
e embaixo aparece "expected class-name before '{' token
podem me ajudar nesse problema ?
O pessoal está tendo problema porque a biblioteca utilizada foi a modificada em 11 de setembro de 2018, em outras bibliotecas pode não funcionar e dar esses erros mesmo, para resolver é só pegar a biblioteca correta nesse link https://github.com/outlandnish/ESP32_BLE_Arduino/tree/74b60fd24ce84a25e16f24430a9aebe90dbb024e
ResponderExcluirCaso ocorra problema com a biblioteca BLE já instala basta excluir a pasta BLE (lembre de fazer backup), na versão 1.8.15 da IDE do Arduino para Windows o local padrão é C:\Users\\AppData\Local\Arduino15\packages\esp32\hardware\esp32\1.0.6\libraries
Hola Fernando,
ResponderExcluirMuy interesante articulo y quiero aplicarlo para hacer algo similar pero con pulseras ( Smartwatches). He probado tu codigo y tan pronto se ejecuta esta linea:
remoteCharacteristic->registerForNotify(this);
El ESP32 se reinicia y marca estos errores:
Guru Meditation Error: Core 1 panic'ed (LoadProhibited). Exception was unhandled.
Core 1 register dump:
PC : 0x400d4d67 PS : 0x00060930 A0 : 0x800d458e A1 : 0x3ffc8080
A2 : 0x00000000 A3 : 0x3ffc80bb A4 : 0x00000002 A5 : 0x00000000
A6 : 0x3ffc807c A7 : 0x00000d1a A8 : 0x800d42d8 A9 : 0x3ffc8030
A10 : 0x3ffc80dc A11 : 0xf6a8348b A12 : 0x3ffc43fc A13 : 0xf6a8348b
A14 : 0x00ff0000 A15 : 0xff000000 SAR : 0x00000008 EXCCAUSE: 0x0000001c
EXCVADDR: 0x00000030 LBEG : 0x4000c349 LEND : 0x4000c36b LCOUNT : 0xffffffff
ELF file SHA256: 0000000000000000
Backtrace: 0x400d4d67:0x3ffc8080 0x400d458b:0x3ffc80b0 0x400d177e:0x3ffc8110 0x400d1a06:0x3ffc8170 0x400d1aca:0x3ffc8280 0x400d7540:0x3ffc82a0 0x4008ff66:0x3ffc82c0
Rebooting...
Me puedas ayudar?
Fernando,
ExcluirGracias, encontŕe el error. Era algo sumamente sencillo. Comenté lineas equivocadas! Saludos desde Mexico.