Recents in Beach


Receba o meu conteúdo GRATUITAMENTE


ESP32 BLUETOOTH LOW ENERGY



Atendendo aos pedidos de vários seguidores que já sabiam como mexer no Bluetooth com Arduino através de pequenos módulos, hoje vamos falar do Bluetooth Low Energy (BLE) do ESP32, o mais recomendado para a Internet das Coisas. Aquele módulo do Arduino TX RX funciona como serial, já o que vamos tratar hoje é um pouco diferente, pois o  consumo de energia dele é minúsculo. Vamos, portanto, conhecer o BLE e criar um programa para o ESP32 se tornar um “server” Bluetooth. Assim, conectaremos um aplicativo de smartphone para enviar e receber dados.


Na nossa montagem temos o sensor de temperatura, o buzzer e o ESP32. Ligamos o ESP32 e chamamos o BLE scanner, que vai localizar nosso microcontrolador. No vídeo mostro como fazer a conexão entre os dois, bem como a execução de alguns comandos envolvendo o Led e o buzzer.


Introdução


O BLE é um protocolo ligeiramente diferente do Bluetooth tradicional. Ele é mais adequado para aplicações IoT (Internet of Things) de baixo consumo de energia, já que a capacidade dos pacotes de dados é baixa.
Os dispositivos que trabalham com BLE podem ter duas funções diferentes em uma conexão: Dispositivo Central ou Dispositivo Periférico (Central Device or Peripheral Device). Geralmente, os dispositivos centrais são telefones celulares, tablets, computadores, etc. São dispositivos centrais que recebem dados. Já os dispositivos periféricos são sensores e dispositivos low power que se conectam ao dispositivo central. Podemos pensar também como uma estrutura cliente/servidor, onde um celular é o cliente e o sensor é o servidor que “serve” seus dados para o cliente.
GATT (Generic Attribute Profile) é a forma com que os dados são organizados para comunicação entre os dispositivos. GATT é composto por um ou mais serviços que, por sua vez, são compostos de características. Existem especificações padrão de GATT para os tipos de aplicação mais comuns encontradas no mercado. Várias dessas especificações podem ser encontradas no site oficial do Bluetooth. As características, por sua vez, são basicamente os valores em si.

Os serviços e as características são identificados por um UUID (universally unique identifier). Assim podemos customizar nossas próprias ou utilizar as já existentes.

Como dito anteriormente, podemos ter um ou mais serviços rodando no mesmo dispositivo e, cada um deles, com suas próprias características.
Por exemplo, um ESP32 pode estar rodando um serviço de CLIMA, para enviar dados de temperatura e umidade, e um outro serviço de BATERIA, para enviar dados de medição de carga da bateria.


Visão geral


Podemos enviar e receber dados em ambos os lados.

Exemplo: ESP32 pode enviar dados de sensores.
Exemplo 2: Smartphone pode enviar comandos para o ESP32 ligar um relé.


Algumas aplicações do BLE

·         Sensores de batimento cardíaco
·         Comunicação M2M (máquina-a-máquina)
·         Automatização de tarefas em uma residência
·         Controle remoto
·         Notificação de alerta de proximidade
·         dentre outros


Comparativo





WiFi NodeMCU-32S ESP-WROOM-32



Sensor Infravermelho MLX90614

Gosto bastante deste sensor, pois, como já mostrei em outro vídeo, ele consegue medir altas temperaturas, pois funciona por luz infravermelha. Ainda, o MLX90614 tem um sensor de temperatura de ambiente, ou seja, ele mede a temperatura dele próprio e do que ele está vendo por meio de sua câmera.



Montagem

Como já mencionamos acima, a montagem é bastante simples, e dispõe de um buffer ligado no GPIO23 e o sensor i2c ligado no GPIO21 e GPIO22.



Bibliotecas

Adicione a biblioteca “SparkFunMLX90614” para comunicação com o sensor infravermelho.
Acesse o link e faça download da biblioteca.
Descompacte o arquivo e cole na pasta de bibliotecas da IDE do arduino.
C:/Program Files (x86)/Arduino/libraries


Programa

Faremos um programa no qual o ESP32 se tornará um servidor BLE. Quando um dispositivo estiver conectado a ele serão enviados em intervalos de tempo dados de um sensor de temperatura. O ESP32 também poderá receber dados para comandar o Liga/Desliga de um LED e um Buzzer.


Bibliotecas e Variáveis

Vamos incluir as bibliotecas e instanciar o objeto responsável pela comunicação com o sensor de temperatura infravermelho. Através desse objeto iremos enviar dados para o cliente. Criamos uma variável booleana para controle do dispositivo conectado. Defino, então, os pinos que o Led e o buzzer serão conectados. Por fim, definimos também os IDs que iremos utilizar para o serviço.
#include <Wire.h> //Biblioteca para I2C
#include <SparkFunMLX90614.h> //Biblioteca SparkFunMLX90614 (sensor IR)
#include <BLEDevice.h>
#include <BLEServer.h>
#include <BLEUtils.h>
#include <BLE2902.h>

//objeto responsável pela comunicação com o sensor de temperatura infravermelho
IRTherm sensor;

BLECharacteristic *characteristicTX; //através desse objeto iremos enviar dados para o client

bool deviceConnected = false; //controle de dispositivo conectado

const int LED = 2; //LED interno do ESP32 (esse pino pode variar de placa para placa)
const int BUZZER = 23; //pino d BUZZER

#define SERVICE_UUID   "ab0828b1-198e-4351-b779-901fa0e0371e”
#define CHARACTERISTIC_UUID_RX  "4ac8a682-9736-4e5d-932b-e9b31405049c"
#define CHARACTERISTIC_UUID_TX  "0972EF8C-7613-4075-AD52-756F33D4DA91”



Setup

Definimos nesta etapa o nome do dispositivo Bluetooth como “ESP32-BLE” e criamos um BLE server. Setamos o callback do server porque este se responsabiliza por coletar as informações recebidas. Criamos, então, um serviço, bem como as características do envio de dados.

void setup() {
    Serial.begin(115200);

    pinMode(LED, OUTPUT);
    pinMode(BUZZER, OUTPUT);

    // Create the BLE Device
    BLEDevice::init("ESP32-BLE"); // nome do dispositivo bluetooth

    // Create the BLE Server
    BLEServer *server = BLEDevice::createServer(); //cria um BLE server 

    server->setCallbacks(new ServerCallbacks()); //seta o callback do server

    // Create the BLE Service
    BLEService *service = server->createService(SERVICE_UUID);

    // Create a BLE Characteristic para envio de dados
    characteristicTX = service->createCharacteristic(
                       CHARACTERISTIC_UUID_TX,
                       BLECharacteristic::PROPERTY_NOTIFY
                     );

    characteristicTX->addDescriptor(new BLE2902());


Já nesta etapa do Setup, criamos as características, desta vez, para o recebimento de dados. Setamos o callback para o recebimento das informações e inicializamos o serviço. Propagamos o sinal do ESP32, inicializamos o sensor de temperatura infravermelho e selecionamos a temperatura em Celsius, a qual poderia ser utilizada também em Fahrenheit ou Kelvin.

    // Create a BLE Characteristic para recebimento de dados
    BLECharacteristic *characteristic = service->createCharacteristic(
                                                      CHARACTERISTIC_UUID_RX,
                                                      BLECharacteristic::PROPERTY_WRITE
                                                    );

    characteristic->setCallbacks(new CharacteristicCallbacks());

    // Start the service
    service->start();

    // Start advertising (descoberta do ESP32)
    server->getAdvertising()->start();

    //Inicializa sensor de temperatura infravermelho 
    sensor.begin(); 

    //Seleciona temperatura em Celsius 
    sensor.setUnit(TEMP_C);//podemos ainda utilizar TEMP_F para Fahrenheit ou TEMP_K para Kelvin 
    Serial.println(“Aguardando algum dispositivo conectar...");

} //fim setup



Loop

No Loop, verificamos que existe algum dispositivo conectado e tentamos fazer a leitura do sensor. Se a ação for concretizada, colhemos a temperatura ambiente. Convertemos o valor para um array de char, setamos este valor e o enviamos para o smartphone.

void loop() {
    //se existe algum dispositivo conectado
    if (deviceConnected) {
        //chamamos o método "read" do sensor para realizar a leitura da temperatura
        //read retornará 1 caso consiga realizar a leitura, ou 0 caso contrário 
        if (sensor.read())
        {
            //recupera a leitura da temperatura do ambiente
            float tempAmbiente = sensor.ambient();
            //recupera a leitura da temperatura do objeto apontado pelo sensor
            //float tempObjeto = sensor.object();

            // abaixo vamos converser o valor para um array de char
            char txString[8]; 
            dtostrf(tempAmbiente, 2, 2, txString); // float_val, min_width, digits_after_decimal, char_buffer

            characteristicTX->setValue(txString); //seta o valor que a caracteristica notificará (enviar) 
            characteristicTX->notify(); // Envia o valor para o smartphone
        }
    }
    delay(1000);
}



Callback - Características

Recordo aqui que a função Callback é chamada sempre que o dispositivo recebe alguma informação. Então, definimos uma classe característica, retornamos o ponteiro para o registrador contendo o valor atual da característica e verificamos se existem dados (tamanho maior que zero). Verifico se o valor de rxValue é L1, que liga o Led, ou L0, que apaga. Também analiso o buzzer: B1 liga o buzzer, enquanto o B0 desliga.

//callback para eventos das características
class CharacteristicCallbacks: public BLECharacteristicCallbacks {
     void onWrite(BLECharacteristic *characteristic) {
          //retorna ponteiro para o registrador contendo o valor atual da caracteristica
          std::string rxValue = characteristic->getValue(); 
          //verifica se existe dados (tamanho maior que zero)
          if (rxValue.length() > 0) {

               for (int i = 0; i < rxValue.length(); i++) {
             Serial.print(rxValue[i]);
               }
               Serial.println();
               //L1 liga o LED | L0 desliga o LED
               if (rxValue.find("L1") != -1) { 
             digitalWrite(LED, HIGH);
               }
               else if (rxValue.find("L0") != -1) {
             digitalWrite(LED, LOW);
               }
               // B1 liga o Buzzer | B0 desliga o Buzzer
               else if (rxValue.find("B1") != -1) { 
             digitalWrite(BUZZER, HIGH);
               }
               else if (rxValue.find("B0") != -1) {
             digitalWrite(BUZZER, LOW);
               }
          }
     }//onWrite
};



Callback Server

Aqui temos o callback para receber os eventos de conexão de dispositivos.

//callback para receber os eventos de conexão de dispositivos
class ServerCallbacks: public BLEServerCallbacks {
    void onConnect(BLEServer* pServer) {
 deviceConnected = true;
    };

    void onDisconnect(BLEServer* pServer) {
 deviceConnected = false;
    }
};



Aplicativo

Utilizaremos o aplicativo BLE Scanner. Você pode fazer o download dele através do link abaixo:


Ao iniciar o aplicativo, ele fará um escaneamento para encontrar dispositivos bluetooth por perto. No nosso ESP32-BLE, clique connect:


Ao conectar veremos essa tela, na qual mostra o status da conexão e também os serviços rodando no ESP32. CUSTOM SERVICE é o serviço que criamos. Repare que o UUID é o mesmo que definimos no código.



Ao clicar no serviço (CUSTOM SERVICE), as características dele serão listadas.


Ao clicar no W, uma caixa de texto será aberta, assim podemos enviar os dados para o ESP32.

Nosso protocolo:
B0 > Desliga o BUZZER
B1 > Liga o BUZZER

L0 > Desliga o LED
L1 > Liga o LED





Faça o download dos arquivos:



Postar um comentário

13 Comentários

  1. Oi Fernando! Estou tendo o seguinte erro: "expected type-specifier before 'ServerCallbacks" na linha server->setCallbacks(new ServerCallbacks()); A mesma coisa na parte do new CharacteristicCallbacks. Inclui todas as bibliotecas, as unicas mudanças que fiz no código foi retirar a parte do sensor de temperatura, pois não tenho. Qual pode ser o erro?

    ResponderExcluir
    Respostas
    1. Coloque as funções na parte superior do código, antes de chamar newserver

      Excluir
  2. olá estou iniciando agora no Esp32, tenho um certo conhecimento em arduino, estou querendo fazer um robô explorador para ajuda no trabalho de escola da minha namorada, este controlado por bluetooth, gostaria de saber se e possível utilizar um sensor ultrassônico hc-sr04, para enviar dados de distancia para o celular utilizando esta programação, fazendo apenas adaptações necessárias?

    ResponderExcluir
  3. Fernando. Não estou conseguindo parear o dispositivo com Esp32. Aparece sempre verifique se o dispositivo esta ligado.
    Pode me ajudar. Agradeço.

    ResponderExcluir
    Respostas
    1. Estou com o mesmo problema. Conseguiu resolver?

      Excluir
  4. boa noite, estou usando um programa para teste do BLE com o dht11, porem na hora de compilar aparece "erro compilando para placa NodeMCU32S" sempre que tento programas com o BLE tenho esse erro com programas sem isso tenho sucesso ao compilar.

    ResponderExcluir
  5. Boa noite! O BLE fica visível para o BLE Scanner, consigo conectar e enviar a string L1 por exemplo. Mas o LED não é aceso e o mais estranho é que nada aparece no monitor Serial. Já alterei a velocidade para 19.200 no .ino e no monitor e nada. Alguma dica? Obrigado.

    ResponderExcluir
    Respostas
    1. Boa tarde.
      Agora a comunicação com o monitor serial está funcionando.
      Coloquei um Serial.print logo no início da função callback onWrite, mas nada chega nunca!
      Alguém pode ajudar? Obrigado.

      Excluir
  6. porque "deviceConnected" não está como um atributo de classe? Ele sendo uma variável global não pode causar problemas na reutilização do código?

    ResponderExcluir
  7. porque "deviceConnected" não está como um atributo de classe? Ele sendo uma variável global não pode causar problemas na reutilização do código?

    ResponderExcluir
  8. Olá. testei BLE a distancia, porem quando fecho o App e volto a liga-lo o mesmo não conecta.
    É algum problema com a lib ou no codigo?

    ResponderExcluir
  9. o meu esta dando um erro

    Esse:
    Arduino: 1.8.19 (Windows 10), Placa:"ESP32 Dev Module, Disabled, Default 4MB with spiffs (1.2MB APP/1.5MB SPIFFS), 240MHz (WiFi/BT), QIO, 80MHz, 4MB (32Mb), 921600, None"





















    In file included from C:\Users\dioge\Documents\Arduino\libraries\SparkFun_MLX90614_Arduino_Library-master\src\SparkFunMLX90614.cpp:17:0:

    C:\Users\dioge\Documents\Arduino\libraries\SparkFun_MLX90614_Arduino_Library-master\src\SparkFunMLX90614.cpp: In member function 'void IRTherm::sleep()':

    C:\Users\dioge\Documents\Arduino\libraries\SparkFun_MLX90614_Arduino_Library-master\src/SparkFunMLX90614.h:30:13: error: 'PIN_WIRE_SCL' was not declared in this scope

    #define SCL PIN_WIRE_SCL

    ^

    C:\Users\dioge\Documents\Arduino\libraries\SparkFun_MLX90614_Arduino_Library-master\src\SparkFunMLX90614.cpp:282:10: note: in expansion of macro 'SCL'

    pinMode(SCL, OUTPUT);

    ^

    C:\Users\dioge\Documents\Arduino\libraries\SparkFun_MLX90614_Arduino_Library-master\src/SparkFunMLX90614.h:27:13: error: 'PIN_WIRE_SDA' was not declared in this scope

    #define SDA PIN_WIRE_SDA

    ^

    C:\Users\dioge\Documents\Arduino\libraries\SparkFun_MLX90614_Arduino_Library-master\src\SparkFunMLX90614.cpp:284:10: note: in expansion of macro 'SDA'

    pinMode(SDA, INPUT);

    ^

    C:\Users\dioge\Documents\Arduino\libraries\SparkFun_MLX90614_Arduino_Library-master\src\SparkFunMLX90614.cpp: In member function 'void IRTherm::wake()':

    C:\Users\dioge\Documents\Arduino\libraries\SparkFun_MLX90614_Arduino_Library-master\src/SparkFunMLX90614.h:30:13: error: 'PIN_WIRE_SCL' was not declared in this scope

    #define SCL PIN_WIRE_SCL

    ^

    C:\Users\dioge\Documents\Arduino\libraries\SparkFun_MLX90614_Arduino_Library-master\src\SparkFunMLX90614.cpp:291:10: note: in expansion of macro 'SCL'

    pinMode(SCL, INPUT); // SCL high

    ^

    C:\Users\dioge\Documents\Arduino\libraries\SparkFun_MLX90614_Arduino_Library-master\src/SparkFunMLX90614.h:27:13: error: 'PIN_WIRE_SDA' was not declared in this scope

    #define SDA PIN_WIRE_SDA

    ^

    C:\Users\dioge\Documents\Arduino\libraries\SparkFun_MLX90614_Arduino_Library-master\src\SparkFunMLX90614.cpp:292:10: note: in expansion of macro 'SDA'

    pinMode(SDA, OUTPUT);

    ^

    Foram encontradas múltiplas bibliotecas para "SparkFunMLX90614.h"

    Usado: C:\Users\dioge\Documents\Arduino\libraries\SparkFun_MLX90614_Arduino_Library-master

    Não usado: C:\Program Files (x86)\Arduino\libraries\SparkFun_MLX90614_Arduino_Library-master

    exit status 1

    Erro compilando para a placa ESP32 Dev Module



    Este relatório teria mais informações com
    "Mostrar a saida detalhada durante a compilação"
    opção pode ser ativada em "Arquivo -> Preferências"

    ResponderExcluir