Múltiplos assuntos neste vídeo
de hoje: ESP32 LoRa, Gateway e Multi Client. Vamos fazer uma automação para modificar
o estado de relês utilizando ainda o APP Fernando K. A abordagem é simples de
temas que considero mais densos. Confere aí!
RECURSOS USADOS
- Heltec WiFi LoRa 32
- Jumpers
- Relê
- Fonte
MONTAGEM
BIBLIOTECAS
Heltec ESP32 Dev-Boards
TaskScheduler
SELEÇÃO DE PLACA
Ferramentas->Placa->Heltec
WiFi LoRa 32
CÓDIGO GATEWAY APP
Fluxograma
Declarações e variáveis
#include <heltec.h> #include <TaskScheduler.h> #include <vector> #include <WiFi.h> //Frequência #define BAND 433E6 //Pino onde o relê está #define RELAY 13 //SSID e senha do roteador que vc usa em sua casa #define SSID "SSID" #define PASSWORD "PASSWORD" //Objeto que vamos utilizar para guardar o ip recebido IPAddress myIP; // Porta do server que vc vai utilizar para conectar pelo aplicativo const int port = 80; // Objeto WiFi Server, o ESP será o servidor WiFiServer server(port); // Vetor com os clientes que se conectarão no ESP std::vector<WiFiClient> clients; //Tarefas para verificar novos clientes e mensagens enviadas por estes Scheduler scheduler; void taskNewClients(); void taskHandleClients(); //Tarefa para verificar se uma nova conexão feita por aplicativo está sendo feita Task t1(100, TASK_FOREVER, &taskNewClients, &scheduler, true); //Tarefa para verificar se há novas mensagens vindas de aplicativo Task t2(100, TASK_FOREVER, &taskHandleClients, &scheduler, true); //Id e estados deste esp (altere para cada esp) String ID = "LIGHT1"; String ID_ON = ID + " ON"; String ID_OFF = ID + " OFF"; //Variável para guardar o valor do estado atual do relê String currentState = ID_OFF;
setup
void setup() {
//Coloca tudo em maiúsculo
ID_ON.toUpperCase();
ID_OFF.toUpperCase();
//Coloca o pino onde o relê está como saída
pinMode(RELAY, OUTPUT);
Heltec.begin(true /*Ativa o display*/, true /*Ativa lora*/, true /*Ativa informações pela serial*/, true /*Ativa PABOOST*/, BAND /*frequência*/);
//Inicializa o display
setupDisplay();
//Ativa o recebimento de pacotes
LoRa.receive();
//Se conecta à rede WiFi
setupWiFi();
//Inicializa o server ao qual vc vai se conectar utilizando o aplicativo
server.begin(port);
//Modifica o estado do relê para desligado
verifyAndSetRelayState(ID_OFF);
//Inicializa o agendador de tarefas
scheduler.startNow();
}
setupDisplay
//Inicializa o display
void setupDisplay() {
Heltec.display->init();
//Limpa o display
Heltec.display->clear();
//Modifica direcionamento do texto
Heltec.display->flipScreenVertically();
//Alinha o texto à esquerda
Heltec.display->setTextAlignment(TEXT_ALIGN_LEFT);
//Altera a fonte
Heltec.display->setFont(ArialMT_Plain_16);
//Exibe no display
Heltec.display->drawString(0, 0, "Display OK");
Heltec.display->display();
}
setupWiFi
void setupWiFi() {
Serial.print("Conectando");
//Faz o ESP se conectar à rede WiFi
WiFi.begin(SSID, PASSWORD);
//Enquanto o ESP não se conectar à rede
while (WiFi.status() != WL_CONNECTED)
{
//Esperamos 100 milisegundos
delay(100);
Serial.print(".");
}
//Se chegou aqui é porque conectou à rede, então mostramos no monitor serial para termos um feedback
Serial.println("");
Serial.println("Conectou");
//Objeto que vamos utilizar para guardar o ip recebido
myIP = WiFi.localIP();
//Mostra o ip no monitor serial
Serial.println(myIP);
//Atualiza o display para exibir o ip
refreshDisplay();
}
refreshDisplay
void refreshDisplay() {
//Limpa o display
Heltec.display->clear();
//Exibe o estado atual do relê
Heltec.display->drawString(0, 0, currentState);
//Exibe o ip deste esp para ser utilizado no aplicativo
Heltec.display->drawString(0, 15, myIP.toString());
Heltec.display->display();
}
taskNewClients
// Task que insere novos clientes conectados no vector
void taskNewClients(){
// Se existir um novo client atribuimos para a variável
WiFiClient newClient = server.available();
// Se o client for diferente de nulo
if(newClient) {
// Inserimos no vector
clients.push_back(newClient);
// Exibimos na serial indicando novo client e a quantidade atual de clients
Serial.println("New client! size:"+String(clients.size()));
}
}
taskHandleClients
// Função que verifica se o app enviou um comando
void taskHandleClients()
{
// String que receberá o comando vindo do aplicativo
String cmd;
// Atualizamos o vector deixando somente os clientes conectados
refreshConnections();
// Percorremos o vector
for(int i=0; i<clients.size(); i++){
// Se existir dados a serem lidos
if(clients[i].available()){
// Recebemos a String até o '\n'
cmd = clients[i].readStringUntil('\n');
// Verificamos o comando, enviando por parâmetro a String cmd
handleCommand(cmd);
}
}
}
refreshConnections
// Função que verifica se um ou mais clients se desconectaram do server e, se sim, estes clients serão retirados do vector
void refreshConnections(){
// Flag que indica se pelo menos um client ser desconectou
bool flag = false;
// Objeto que receberá apenas os clients conectados
std::vector<WiFiClient> newVector;
// Percorremos o vector
for(int i=0; i<clients.size(); i++){
// Verificamos se o client está desconectado
if(!clients[i].connected()){
// Exibimos na serial que um cliente se desconectou e a posição em que ele está no vector (debug)
Serial.println("Client disconnected! ["+String(i)+"]");
// Desconectamos o client
clients[i].stop();
// Setamos a flag como true indicando que o vector foi alterado
flag = true;
}
else{
newVector.push_back(clients[i]); // Se o client está conectado, adicionamos no newVector
}
}
// Se pelo menos um client se desconectou, atribuimos ao vector "clients" os clients de "newVector"
if(flag) clients = newVector;
}
handleCommand
// Função que verifica o comando vindo do app
void handleCommand(String cmd)
{
// Se a String estiver vazia não precisamos fazer nada
if (cmd.equals(""))
return;
//Coloca todos os caracteres em maiúsculo
cmd.toUpperCase();
// Exibimos o comando recebido no monitor serial
Serial.println("Received from app: " + cmd);
//Verifica se a mensagem é para este esp e modifica o estado do relê de acordo com o que foi enviado
bool forMe = verifyAndSetRelayState(cmd);
//Se a mensagem é para este esp
if(forMe) {
//Envia mensagem de confirmaçao de volta para os aplicativos conectados
String confirmationMessage = currentState + " OK";
sendToClients(confirmationMessage);
Serial.println("Changed Relay status: " + confirmationMessage);
}
//Se não é para este esp
else {
//Envia o comando para os outros esp através de um pacote LoRa
sendLoRaPacket(cmd);
}
}
verifyAndSetRelayState
//Verifica se estado é valido para este esp e modifica o estado do relê de acordo
//Retorna true se a mensagem for para este esp e false caso contrário
bool verifyAndSetRelayState(String state) {
//Se a mudança de estado pertence ao id vinculado a este esp
if (state == ID_ON || state == ID_OFF) {
//Guarda o estado atual
currentState = state;
//Modificamos o estado do relê de acordo com o estado enviado
digitalWrite(RELAY, currentState == ID_ON ? LOW : HIGH);
//Atualizamos o display com o estado atualizado
refreshDisplay();
return true;
}
return false;
}
sendToClients e sendLoRaPacket
//Função que envia mensagem para todos os apps conectados
void sendToClients(String msg) {
for(int i=0; i<clients.size(); i++){
clients[i].print(msg);
}
}
//Envia um pacote LoRa
void sendLoRaPacket(String str) {
//Inicializa o pacote
LoRa.beginPacket();
//Coloca a string no pacote
LoRa.print(str);
//Finaliza e envia o pacote
LoRa.endPacket();
}
loop
void loop() {
//Faz a leitura do pacote
String packet = readLoRaPacket();
//Se uma mensagem chegou
if(!packet.equals("")) {
//As mensagens enviadas dos outros ESPs são apenas de feedback
//Então enviamos a mensagem como confirmação para os aplicativos conectados
sendToClients(packet);
}
//Executa as tarefas que foram adicionadas ao scheduler
scheduler.execute();
}
readLoRaPacket
//Faz a leitura de um pacote (se chegou algum)
String readLoRaPacket() {
String packet = "";
//Verifica o tamanho do pacote
int packetSize = LoRa.parsePacket();
//Lê cada caractere e concatena na string
for (int i = 0; i < packetSize; i++) {
packet += (char) LoRa.read();
}
CÓDIGO RECEIVERS
Fluxograma
Imports e Variáveis
#include "heltec.h" //Frequência #define BAND 433E6 //Pino onde o relê está #define RELAY 13 //Id e estados deste esp (altere para cada esp) String ID = "LIGHT2"; String ID_ON = ID + " ON"; String ID_OFF = ID + " OFF"; //Variável para guardar o valor do estado atual do relê String currentState = ID_OFF;
setup
void setup() {
//Coloca tudo em maiúsculo
ID_ON.toUpperCase();
ID_OFF.toUpperCase();
//Coloca o pino onde o relê está como saída
pinMode(RELAY, OUTPUT);
Heltec.begin(true /*Ativa display*/, true /*Ativa LoRa*/, true /*Ativa informações pela serial*/, true /*Ativa PABOOST*/, BAND /*frequência*/);
//Inicializa o display
setupDisplay();
//Ativa o recebimento de pacotes
LoRa.receive();
//Coloca o estado do relê como desligado
verifyAndSetRelayState(ID_OFF);
}
setupDisplay
//Inicializa o display
void setupDisplay() {
Heltec.display->init();
//Limpa o display
Heltec.display->clear();
//Modifica direcionamento do texto
Heltec.display->flipScreenVertically();
//Alinha o texto à esquerda
Heltec.display->setTextAlignment(TEXT_ALIGN_LEFT);
//Altera a fonte
Heltec.display->setFont(ArialMT_Plain_16);
//Exibe no display
Heltec.display->drawString(0, 0, "Display OK");
Heltec.display->display();
}
verifyAndSetRelayState
//Verifica se estado é valido para este esp e modifica o estado do relê de acordo
//Retorna true se a mensagem for para este esp e false caso contrário
bool verifyAndSetRelayState(String state) {
//Se a mudança de estado pertence ao id vinculado a este esp
if (state == ID_ON || state == ID_OFF) {
//Guarda o estado atual
currentState = state;
//Modificamos o estado do relê de acordo com o estado enviado
digitalWrite(RELAY, currentState == ID_ON ? LOW : HIGH);
//Atualizamos o display com o estado atualizado
refreshDisplay();
return true;
}
return false;
}
refreshDisplay
//Atualiza dados que aparecem no display
void refreshDisplay() {
//Limpa o display
Heltec.display->clear();
//Mostra o estado atual do relê
Heltec.display->drawString(0 , 0 , currentState);
//Mostra os dados
Heltec.display->display();
}
loop
void loop() {
//Faz a leitura do pacote
String packet = readLoRaPacket();
//Se uma mensagem chegou
if(!packet.equals("")) {
//Verifica se a mensagem é para este esp e modifica o estado do relê de acordo com o que foi enviado
bool forMe = verifyAndSetRelayState(packet);
//Se a mensagem é para este esp
if(forMe) {
//Envia de volta um pacote de confirmação
sendLoRaPacket(currentState + " OK");
}
}
}
readLoRaPacket
//Faz a leitura de um pacote (se chegou algum)
String readLoRaPacket() {
String packet = "";
//Verifica o tamanho do pacote
int packetSize = LoRa.parsePacket();
//Lê cada caractere e concatena na string
for (int i = 0; i < packetSize; i++) {
packet += (char) LoRa.read();
}
return packet;
}
sendLoRaPacket
//Envia um pacote LoRa
void sendLoRaPacket(String str) {
//Inicializa o pacote
LoRa.beginPacket();
//Coloca a string no pacote
LoRa.print(str);
//Finaliza e envia o pacote
LoRa.endPacket();
}





















4 Comentários
if (!LoRa.begin(frequency,PABOOST))
ResponderExcluirprofessor porque da este erro ao mandar programa para esp lora
Fernandão faltou dar um return na função readLoRaPacket() . Logo após o código do Loop.
ResponderExcluirAbraço!
For instance, as per the report of AlphaBeta Australia, Australia witnessed a 67% improve in on-line betting in April 2020. Similarly, according to a report by Concordia 점보카지노 University, Great Britain observed a 17.5% rise in internet-based playing. Thus, the shutdown of non-essential services through the pandemic-induced lockdown boosted the adoption of cell playing among users. Thus, through the pandemic crisis, the market witnessed outstanding development price. Moreover, the market is predicted to grow with a major CAGR within the post-pandemic interval.
ResponderExcluirOi Fernado, ao compilar o código na função 'void sendLoRaPacket(String str) {' da erro na linha: LoRa.beginPacket() , que LoRa não foi declarad neste scope. Pode me ajudar??
ResponderExcluir