Tutorial - Sensor de Presença com ESP32
04/06/2020
PET - Tecnologia em Eletrônica e Computação
Itajubá, Minas Gerais
Objetivos
Gerar um detector de presença com ESP32, utilizando a tecnologia BLE (Bluetooth Low Energy).
Visão geral
Antes de seguir com o projeto é necessária uma visão sobre a tecnologia BLE presente na placa ESP32.
Bluetooth low energy é uma tecnologia de conectividade bluetooth com um consumo muito menor de energia (10% em relação ao bluetooth clássico). Ela foi desenvolvida em decorrência do grande número de dispositivos que passaram a usar esse tipo de conectividade para troca de informações, visando maximizar o tempo de funcionamento deles.
Um detector de presença que utiliza essa tecnologia possui diversas utilidades. Uma aplicação simples desse conjunto será utilizada como exemplo neste tutorial. Imagine que necessita-se de um portão que irá abrir automaticamente sempre que um funcionário chegar ou sair da empresa e, além disso, irá enviar informações para um servidor sobre qual funcionário é e sobre a hora de entrada e saída desse funcionário. Considere que todo funcionário leva consigo um dispositivo com BLE, como uma pulseira SmartWatch ou um chaveiro iTag por exemplo.
Nesse tutorial iremos mostrar como fazer essa verificação de entrada e saída do dispositivo. Em um próximo tutorial abordaremos como realizar o envio dessas informações através de um JSON.
Para realização desse projeto são necessárias apenas a placa de desenvolvimento ESP32-DevKitC e o dispositivo BLE.
Ambiente de Programação
Para este projeto utilizaremos a Arduino IDE, uma IDE de programação gratuita distribuída pela Arduíno Software, podendo ser baixada no site oficial da Arduino (www.arduino.cc/en/main/software). Além da IDE, utilizaremos as bibliotecas de arduino para ESP32, que podem ser encontradas no repositório da Espressif no GitHub (https://github.com/espressif/arduino-esp32) .
Um tutorial didático de como utilizar a IDE do Arduíno para programação da ESP32 pode ser encontrado no artigo “Programar ESP32 com a IDE do Arduíno - Tutorial completo”, do autor Gustavo Teixeira, Bacharel em Ciência da Computação pela URI. O
artigo encontra-se no link
(https://www.usinainfo.com.br/blog/programar-esp32-com-a-ide-arduino-tutorial-completo /) .
O Código
1. Pacotes e Definições
No início é necessário fazer algumas definições importantes que serão essenciais para o sistema. Primeiramente, é preciso incluir as bibliotecas "String", para facilitar a manipulação dos endereços bluetooth, e a biblioteca "BLEDevice", que irá representar a placa como um dispositivo bluetooth em geral. Além dessas, são necessárias outras inclusões, como as bibliotecas "BLEServer" e "BLEScan", entretanto, essas inserções já são
endereço bluetooth do dispositivo, "address", um booleano que indica se o dispositivo está presente no local no momento, "found", o momento em que o dispositivo foi reconhecido pela primeira vez, "arrivalTime", o momento em que foi reconhecido pela última vez,
"exitTime" e o tempo em que ele esteve presente, "workTime". Além disso, são declaradas três variáveis globais que serão utilizadas: BLEScan, da classe BLEScan que representa o scanner BLE, um vetor de Device, "devices", que guardará as informações de cada dispositivo cadastrado, e a lista de endereços bluetooth que deseja-se reconhecer. Essa lista poderia ser excluída, uma vez que a estrutura Device já guarda uma variável para o endereço, porém, dessa forma seria necessária uma declaração completa de cada estrutura Device, sendo que o único componente que nos interessa é o endereço. Sendo assim, criando uma lista de endereços, é possível chamar uma função que irá passar esses endereços para o vetor de Device, deixando o código de uma forma bem mais didática.
2. Funções Auxiliares
Serão necessárias duas funções que irão auxiliar e facilitar o entendimento do sistema. A primeira delas é a função "fillDevices()", que não precisa de parâmetros e não irá retornar nada. Essa função já foi mencionada anteriormente e irá passar o valores de endereço do vetor "addressList" para os componentes "address" do vetor de Devices
"devices".
A segunda função auxiliar é a "clearNoMoreFound", que também não irá receber entradas e retornar void. Essa função é a responsável por percorrer a lista de dispositivos cadastrados e, para aqueles que estão marcados como presentes, verificar se a última detecção deles foi há tempo o bastante para que ele possa ser considerado ausente. Esse tempo mínimo de ausência para determinar a saída do dispositivo é definido pelo MAX_MISSING_TIME.
3. setup()
A função setup() é a primeira a ser executada pela ESP32 ao ser iniciada. Ela irá fazer os preparativos para que a placa possa entrar em um looping de execução que irá infinitamente detectar os dispositivos que entram e saem do local.
Primeiramente, para auxiliar o debug do algoritmo será necessário indicar uma frequência para que a placa possa enviar mensagens ao computador. No exemplo usa-se a frequência de 115200 Hz, porém pode-se usar qualquer outra que a IDE reconheça. Uma vez que o código já foi debugado e está funcionando, essa linha pode ser retirada.
Em seguida, chama-se a função auxiliar "fillDevices" para que ela configure os endereços do vetor de dispositivos. E então, são necessárias definições relacionadas ao uso da placa como um dispositivo bluetooth. A lista 5 da função setup() irá inicializar o bluetooth da placa com o nome passado como parâmetro. Como nessa aplicação não é necessário que outros dispositivos reconheçam a placa, apenas o inverso, o nome passado
irá passar à variável "pBLEScan" as informações contidas no scanner e a linha
configurará qual o callback que será chamado pelo scanner. Já o "setActiveScan(true)"
apenas define qual o método de busca a ser utilizado para a verificação. Nesse caso, utilizaremos o método ativo que, embora consuma mais energia, irá proporcionar uma resposta mais rápida.
4. CallBack
A classe "MyAdvertisedDeviceCallback" chamada por eventos disparados durante o escaneamento. Elá é uma extensão da classe padrão utilizada para isso
"BLEAdvertisedDeviceCallbacks" e irá descrever o método "onResult" será chamado sempre que o scanner encontrar algum dispositivo e receberá como parâmetro um
"BLEAdvertisedDevice" que contêm informações do dispositivo BLE encontrado, e retornará void.
O método "onResult" então precisa verificar se aquele dispositivo encontrado é algum da lista dos quais ele procura. Para isso, irá percorrer através de uma estrutura for o vetor "devices" e comparar se o endereço do dispositivo encontrado é igual ao do elemento do vetor. Essa verificação será feita para todos os elementos da lista e para todos os dispositivos detectados. Para essa comparação usa-se a função "strcmp" da biblioteca
"String", que receberá como parâmetro duas listas de caracteres e irá compará-las, retornando zero se as duas forem iguais. Dessa forma, um dos parâmetros do "strcmp"
será o endereço do dispositivo encontrado "advertisedDevice.getAddress()" e o outro será o componente "address" da estrutura "Device". Entretanto, essa função compara vetores de caracteres, e não strings, dessa forma, temos que converter ambos os parâmetros para vetores de char. Para o elemento da lista "devices" que já é uma String é necessário apenas a chamada do método "c_str" (string da linguagem C), já para o endereço recebido do dispositivo é necessário antes passar ele para String utilizando o ".toString", uma vez que ele é um elemento do tipo BLEAddress, e depois passá-lo para vetor de caracteres com o
".c_str".
Sendo assim, se um dispositivo da lista cadastrada for encontrado, iremos verificar se ele já consta como 'presente', se não, iremos marcar ele como presente e gravar o tempo atual como seu tempo de chegada. O tempo atual deve ser salvo anteriormente através da chamada "millis()", que irá retornar o tempo em milissegundos contado pela ESP32 a partir do momento em que foi inicializada. Além disso, iremos atualizar o último momento em que aquele dispositivo foi encontrado para o momento atual. Novamente utiliza-se no código uma linha opcional de "Serial.println" para auxiliar o debug.
5. loop()
A função "loop()" é a que será executada infinitamente após o "setup()". Nela iremos então verificar se o último momento de verificação foi a tempo suficiente para que seja necessária outra verificação. Para isso, utiliza-se a subtração do momento atual em milissegundos pelo tempo do último escaneamento e verifica-se se o resultado é maior do que o intervalo definido como máximo entre as verificações, SCAN_INTERVAL.
Se já passou-se o tempo para uma nova verificação, atualiza-se o tempo do último escaneamento e chama-se o método "start", passando como parâmetro a duração do escaneamento e o bool que indicará se os dispositivos encontrados anteriormente devem ser apagados ou não da memória do scanner, sendo false para que esses valores sejam
Após isso, basta chamar a função auxiliar "clearNoMoreFound()" para que aqueles dispositivos que não estão mais presentes sejam atualizados de acordo com o tempo definido para isso.
6. Conclusão
Está é uma aplicação simples da ferramenta de bluetooth low energy existente da placa ESP32, mesmo assim mostra um pouco da eficiência dessa placa, uma vez que seu processamento que funções possam ser realizadas em tempo muito pequeno e mostra que mesmo para uma aplicação a qual é necessária guardar várias informações, a placa suporta isso facilmente, podendo até mesmo processar códigos C++, que é uma linguagem de alto nível e relativamente pesada em comparação a C.