IoT DevKit - 18. Central de Monitoramento por Bluetooth

Introdução
Anteriormente aproveitamos todas as funcionalidades do IoT DevKit para criar uma central de monitoramento por Wi-Fi e por LoRaWAN. Porém, por Bluetooth, apenas enviamos a leitura do LDR para o aplicativo Blynk e vimos como receber informações por um terminal para acionar uma carga quando uma determinada mensagem é recebida.
Neste tutorial iremos aproveitar as configurações já feitas no aplicativo anteriormente, juntamente com todas as funcionalidades do IoT DevKit, para criar uma central de monitoramento por Bluetooth.
Lista de Materiais
Configuração do Aplicativo
Para recebermos todas as informações do IoT DevKit e continuar com as funcionalidades que já configuramos anteriormente, teremos que adicionar mais cinco "Widgets" ao painel. Três deles são do modelo "Value Display", para armazenar os valores dos três eixos do acelerômetro. Portanto, pressione o botão para adicionar "Widgets" ao painel e encontre essa opção, como na imagem a seguir.

Após adicionar três deste "Widget", toque sobre cada um deles para configurá-los individualmente. O "Widget" para o eixo "x" deve ser configurado com um nome, para variar entre 0 e 1, e ser atrelado ao pino virtual "V4", como na imagem à esquerda abaixo. Para os eixos "y" e "z" as configurações são basicamente as mesmas, porém com os pinos virtuais "V5" e "V6", respectivamente, como nas outras imagens a seguir.



Assim que esses "Widgets" estiverem configurados corretamente no painel, adicione novamente outros dois "Widgets" ao painel, para as leituras de temperatura e umidade do DHT11. Porém, desta vez, selecione a opção "Labeled Value", como demarcado na próxima imagem.

Feito isso, edite-os individualmente. O "Widget" de temperatura deve ter um nome, variar entre 0 e 50 (o DHT11 só é capaz de ler temperaturas entre 0 e 50 °C), ser atrelado ao pino virtual "V2", e ter a unidade "°C" no campo "label". Já para o "Widget" de umidade, além de ter um nome, ele deve variar entre 0 e 100, ser atrelado ao pino virtual "V3", e ter a unidade "%" no campo "label". As imagens a seguir ilustram essas configurações.


Com tudo configurado, você verá que o painel estará um pouco desorganizado, portanto tome alguns minutos para organizá-lo. Assim, ele pode ficar como o da imagem a seguir, por exemplo.

Código
Com as configurações do painel finalizadas, carregue o código a seguir para a sua placa. Lembre-se apenas de alterar a variável CHAVE_AUTENTICACAO
com a chave de autenticação do seu projeto, antes de carregar o código para a placa.
/*******************************************************************************
* IoT DevKit - Central de Monitoramento Bluetooth (v1.0)
*
* Codigo utilizado para realizar a leitura de todos os sensores do IoT DevKit,
* e entao enviar essas leituras para o aplicativo Blynk do celular que estiver
* conectado ao ESP32 do kit.
*
* Copyright 2020 RoboCore.
* Escrito por Giovanni de Castro (15/09/2020).
* Creditos - @francois - RoboCore
* - @bijilbaji - Solucao proposta no topico #102 do GitHub
* - (https://github.com/espressif/arduino-esp32/issues/102#issuecomment-611307887)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version (<https://www.gnu.org/licenses/>).
*******************************************************************************/
//Definicao das funcoes auxiliares para o Blynk
#define BLYNK_PRINT Serial
#define BLYNK_USE_DIRECT_CONNECT
//Inclusao das bibliotecas
#include <BlynkSimpleEsp32_BLE.h>
#include <BLEDevice.h>
#include <BLEServer.h>
#include <DHT.h>
#include "RoboCore_MMA8452Q.h"
#include <soc/sens_reg.h> //Biblioteca para a leitura dos registradores
//Declaracao da variavel que armazena a chave de autenticacao do aplicativo
const char CHAVE_AUTENTICACAO[] = "SUA-CHAVE-AUTENTICACAO-AQUI"; //Altere essa variavel com a chave de seu projeto
//Criacao do timer para a leitura do LDR, do DHT e do acelerometro
BlynkTimer timerLDR;
BlynkTimer timerDHT;
BlynkTimer timerACELEROMETRO;
// Attach virtual serial terminal to Virtual Pin "V1"
WidgetTerminal terminal(V1);
//Criacao do objeto "acelerometro" pela biblioteca "MMA8452Q"
MMA8452Q acelerometro;
//Definicao do pino conectado ao LDR
const int PINO_LDR = 15;
//Declaracao do pino conectado ao LED do kit
const int PINO_LED = 13;
//Declaracao do pino conectado ao sensor DHT no IoT DevKit
const int PINO_DHT = 12;
//Criacao do objeto DHT de acordo com o pino que ele esta conectado, e o seu modelo
DHT dht(PINO_DHT, DHT11); //Modelo de fabrica do IoT DevKit - DHT11
//Declaracao da variavel e da funcao para leitura do LDR
uint32_t adc_register; //Variavel para o registrador
int customARead(int); //Funcao para a leitura do sensor
//---------------------------------------------------------------------------------------
//Funcao para ler o LDR e enviar a leitura para o Blynk
void lerLDR(){
//Realiza a leitura e entao a mapeia entre 0 e 100
int leitura_LDR = customARead(PINO_LDR);
leitura_LDR = map(leitura_LDR, 0, 4095, 100, 0);
//Escreve o valor lido no pino virtual "V0" do aplicativo
Blynk.virtualWrite(V0, leitura_LDR);
}
//---------------------------------------------------------------------------------------
//Funcao do Terminal
BLYNK_WRITE(V1){
terminal.clear(); //Limpa o terminal do aplicativo
if (String("HIGH") == param.asStr()) { //Verifica se a mensagem enviada no terminal e igual a "HIGH"
Serial.println("'HIGH' Recebido! Acendendo LED");
terminal.println("'HIGH' Enviado! Acendendo LED");
digitalWrite(PINO_LED, HIGH); //Acende o LED
//Se a mensagem nao for "HIGH"
} else if(String("LOW") == param.asStr()) { //Verifica se a mensagem enviada no terminal e igual a "LOW"
Serial.println("'LOW' Recebido! Apagando LED");
terminal.println("'LOW' Enviado! Apagando LED");
digitalWrite(PINO_LED, LOW); //Apaga o LED
} else { //Caso contrario
terminal.print("Mensagem Enviada: ");
terminal.println(param.asStr());
Serial.print("Mensagem Recebida: ");
Serial.println(param.asStr());
}
terminal.flush(); //Garante o envio da mensagem
}
//---------------------------------------------------------------------------------------
//Funcao para ler o DHT e enviar as leituras para o Blynk
void lerDHT(){
//Declaracao das variaveis que armazenam as leituras do sensor
float temperatura;
float umidade;
//Realiza a leitura de temperatura e umidade do sensor
temperatura = dht.readTemperature();
umidade = dht.readHumidity();
//Verifica se a leitura foi feita corretamente
if (isnan(umidade) || isnan(temperatura)) {
Serial.println("Falha na leitura do Sensor DHT!");
} else {
//Escreve os valores lidos nos pinos virtuais do aplicativo
Blynk.virtualWrite(V2, temperatura);
Blynk.virtualWrite(V3, umidade);
}
}
//---------------------------------------------------------------------------------------
//Funcao para ler o acelerometro e enviar as leituras para o Blynk
void lerAcelerometro(){
//Realiza a leitura do acelerometro
acelerometro.read();
//Escreve os valores lidos nos pinos virtuais do aplicativo
Blynk.virtualWrite(V4, acelerometro.x);
Blynk.virtualWrite(V5, acelerometro.y);
Blynk.virtualWrite(V6, acelerometro.z);
}
//---------------------------------------------------------------------------------------
void setup(){
//Inicializacao do monitor serial
Serial.begin(115200);
Serial.println("Waiting for connections...");
//Define "PINO_LDR" como uma entrada
pinMode(PINO_LDR, INPUT);
adc_register = READ_PERI_REG(SENS_SAR_READ_CTRL2_REG); //Estado atual do registrador
//Definicao do pino do LED como uma saida do sistema
pinMode(PINO_LED, OUTPUT);
//Inicializacao do Blynk com a chave de autenticacao
Blynk.begin(CHAVE_AUTENTICACAO);
//Inicializacao do sensor DHT
dht.begin();
//Inicializacao do acelerometro
acelerometro.init();
//Configura o timer do LDR com intervalo de 1 segundo
timerLDR.setInterval(1000L, lerLDR);
//Configura o timer do DHT com intervalo de 10 segundos
timerDHT.setInterval(10000L, lerDHT);
//Configura o timer do acelerometro com intervalo de 100 milissegundos
timerACELEROMETRO.setInterval(100L, lerAcelerometro);
}
//---------------------------------------------------------------------------------------
void loop(){
Blynk.run(); //Mantem a conexao ativa com o aplicativo e processa comandos recebidos ou enviados
timerLDR.run(); //Execucao do timer do LDR
timerDHT.run(); //Execucao do timer do DHT
timerACELEROMETRO.run(); //Execucao do timer do acelerometro
}
//---------------------------------------------------------------------------------------
//Funcao responsavel por ler o ADC conectado ao LDR
int customARead(int pin){
uint32_t wifi_register = READ_PERI_REG(SENS_SAR_READ_CTRL2_REG);
WRITE_PERI_REG(SENS_SAR_READ_CTRL2_REG, adc_register);
SET_PERI_REG_MASK(SENS_SAR_READ_CTRL2_REG, SENS_SAR2_DATA_INV);
int value = analogRead(pin); //Realiza a leitura
WRITE_PERI_REG(SENS_SAR_READ_CTRL2_REG, wifi_register);
return value; //Retorna o valor lido
}
Entendendo o Código
O código deste projeto é basicamente uma mescla dos códigos dos tutoriais anteriores, porém com algumas funções adicionais. Nas declarações globais do código, nós adicionamos as bibliotecas para ler o sensor DHT11 e o acelerômetro do IoT DevKit. Em seguida criamos os objetos timerDHT
e timerAcelerometro
em função da biblioteca de timers do aplicativo Blynk. Por fim, criamos o objeto acelerometro
a partir da biblioteca "RoboCore_MMA8452Q" e o objeto dht
a partir da biblioteca "DHT", de acordo com o pino conectado ao sensor (declarado na variável PINO_DHT
) e com o seu modelo ("DHT11" é o modelo padrão do kit).
xxxxxxxxxx
//Criacao do timer para a leitura do LDR, do DHT e do acelerometro
BlynkTimer timerLDR;
BlynkTimer timerDHT;
BlynkTimer timerACELEROMETRO;
//Criacao do objeto "acelerometro" pela biblioteca "MMA8452Q"
MMA8452Q acelerometro;
//Declaracao do pino conectado ao sensor DHT no IoT DevKit
const int PINO_DHT = 12;
//Criacao do objeto DHT de acordo com o pino que ele esta conectado, e o seu modelo
DHT dht(PINO_DHT, DHT11); //Modelo de fabrica do IoT DevKit - DHT11
Na função lerDHT()
declaramos as variáveis temperatura
e umidade
, que recebem, em seguida, as leituras do sensor através dos comandos temperatura = dht.readTemperature()
e umidade = dht.readHumidity()
, respectivamente. Feito isso, através da condição if (isnan(umidade) || isnan(temperatura))
, verificamos se uma das variáveis (temperatura
ou umidade
) não foi lida corretamente. Se essa condição for verdadeira, ou seja, se o sensor não for lido corretamente, nós informamos isso no monitor serial. Entretanto, caso essa condição seja falsa, nós enviamos as leituras para o aplicativo através dos comandos Blynk.virtualWrite(V2, temperatura)
e Blynk.virtualWrite(V3, umidade)
.
xxxxxxxxxx
//Funcao para ler o DHT e enviar as leituras para o Blynk
void lerDHT(){
//Declaracao das variaveis que armazenam as leituras do sensor
float temperatura;
float umidade;
//Realiza a leitura de temperatura e umidade do sensor
temperatura = dht.readTemperature();
umidade = dht.readHumidity();
//Verifica se a leitura foi feita corretamente
if (isnan(umidade) || isnan(temperatura)) {
Serial.println("Falha na leitura do Sensor DHT!");
} else {
//Escreve os valores lidos nos pinos virtuais do aplicativo
Blynk.virtualWrite(V2, temperatura);
Blynk.virtualWrite(V3, umidade);
}
}
A função lerAcelerometro()
, por sua vez, é iniciada com a leitura do acelerômetro por meio do comando acelerometro.read()
. Feito isso, nós escrevemos os membros do objeto (acelerometro.x
, acelerometro.y
e acelerometro.z
) nos respectivos pinos virtuais do aplicativo utilizando os comandos Blynk.virtualWrite(V4, acelerometro.x)
, Blynk.virtualWrite(V5, acelerometro.y)
e Blynk.virtualWrite(V6, acelerometro.z)
.
xxxxxxxxxx
//Funcao para ler o acelerometro e enviar as leituras para o Blynk
void lerAcelerometro(){
//Realiza a leitura do acelerometro
acelerometro.read();
//Escreve os valores lidos nos pinos virtuais do aplicativo
Blynk.virtualWrite(V4, acelerometro.x);
Blynk.virtualWrite(V5, acelerometro.y);
Blynk.virtualWrite(V6, acelerometro.z);
}
Nas configurações do código, inicializamos o sensor DHT11 com o comando dht.begin()
e o acelerômetro com o comando acelerometro.init()
. Por fim, configuramos os timers do DHT11 e do acelerômetro com com intervalos de 10 segundos e 100 milissegundos, respectivamente, graças aos comandos timerDHT.setInterval(10000L, lerDHT)
e timerAcelerometro.setInterval(100L, lerAcelerometro)
.
A repetição do código possui apenas dois comandos adicionais, o timerDHT.run()
e o timerAcelerometro.run()
, que executam os timers do DHT11 e do acelerômetro, respectivamente.
O Que Deve Acontecer
Após executar o código na placa, inicie a execução do painel do aplicativo, assim você verá que os valores dos "Widgets" começarão a variar com intervalos distintos, exibindo os valores lidos pelos sensores, como na imagem a seguir.

A funcionalidade do terminal ainda está ativa neste código, portanto se você enviar "HIGH" nessa interface, como foi feito na imagem acima, o LED do kit irá acender, como na imagem abaixo.

Vale lembrar que você ainda pode apagá-lo enviando a mensagem "LOW", como vimos no tutorial anterior, se quiser.
Conclusão
Neste tutorial aprendemos como desenvolver uma central de monitoramento por Bluetooth, com a leitura de todos os sensores do IoT DevKit para o aplicativo Blynk e o controle remoto do LED pela mesma interface.
Solução de Problemas
Se mesmo seguindo as soluções propostas abaixo você não conseguir solucionar o seu problema, encaminhe um e-mail para suporte@robocore.net para que possamos te ajudar da melhor maneira possível.
Dispositivo "Blynk" não é Apresentado na Lista de Dispositivos Conectáveis
Se mesmo após carregar o código da página o ESP32 não for apresentado com o nome "Blynk" na lista de dispositivos do aplicativo, verifique se a chave de acesso ao seu projeto foi corretamente inserida no código e certifique-se que a conectividade Bluetooth está ativada em seu celular. Além disso, vale lembrar que o celular deve estar desconectado de qualquer outro dispositivo Bluetooth para que ele possa listar dispositivos disponíveis no aplicativo e se conectar ao ESP32.
Dispositivo "Blynk" é Apresentado, mas não se Conecta ao Aplicativo
Se isso ocorrer, verifique a chave de acesso inserida no código, pois ela pode estar incorreta ou incompleta.
Um ou Alguns "Widgets" não estão Funcionando Corretamente
Se um dos "Widgets" não estiver se atualizando com as leituras do respectivo sensor, ou alguns deles estiverem recebendo valores invertidos (valor de umidade sendo exibido no "Widget" de temperatura, e vice versa, por exemplo), verifique a configuração desse "Widget", pois provavelmente o pino virtual dele está configurado incorretamente.