Esta é a continuação do vídeo:
Porque você deve entender Socket! Nele, já falei sobre assuntos que considero
muito importantes, como Socket MultiClient, com dois ESP32 enviando dados para
um terceiro, bem como um controle remoto que criei com meu próprio Callback. Agora,
neste vídeo, eu te mostro como fazer a LIB orientada a objeto. Tanto que usei
aqui de referência o Lego porque ele é sempre usado para exemplificar a orientação a objeto, e a
ideia é justamente essa, você reaproveitar objetos que já foram feitos. Resumindo:
vou te mostrar como criar uma lib Orientada a Objeto que vai nos avisar através
de callback sobre a mudança de status de pinos que acontecem em ESPs clientes
conectados a um ESP servidor.
Montagem Client
Montagem Server
Fluxograma Server
Fluxograma Client Loop
Começando pela Lib
Primeiramente vamos construir
nossa lib que será constituída dos arquivos Pin.h, RemoteClient.h,
RemoteClient.cpp, RemoteServer.h e RemoteServer.cpp
A pasta com estes arquivos
deverá ser colocada em:
C:\Users\<SEU_USUARIO>\Documents\Arduino\libraries
Modificadores de acesso
private: apenas a classe pode acessar ou modificar as
variáveis ou métodos deste tipo.
protected: além da própria
classe, as classes que estendem esta classe também possuem acesso.
public: todos possuem acesso
Esse é um exemplo com código
fonte:
Lista de inicialização
Podemos usar uma lista na
frente do construtor para inicializar nossas variáveis.
Exemplo:
Pin.h
#ifndef Remote_Pin_h
#define Remote_Pin_h
//Struct que será enviada entre o client e o server
typedef struct
{
int number;
int status;
} Pin;
#endif
RemoteClient.h
#ifndef RemoteClient_h
#define RemoteClient_h
#include <Arduino.h>
#include <WiFi.h>
#include <vector>
#include "Pin.h"
class RemoteClient
{
public:
RemoteClient(int* pinNumbers, int pinCount);
void loop();
void setServerAddressAndPort(IPAddress serverIpAddress, int serverPort);
int* pinNumbers;
int pinCount;
std::vector<Pin> pins;
IPAddress serverIpAddress;
int serverPort;
private:
boolean hasPinStatusChanged(int i);
void sendPinStatus(int i);
};
#endif
RemoteClient.cpp
Includes
#include "RemoteClient.h"
//pinNumbers - Ponteiro para um array com os números dos pinos que serão verificados
//pinCount - Quantidade de pinos no array pinNumbers
RemoteClient::RemoteClient(int* pN, int pC) : pinNumbers(pN), pinCount(pC)
{
//Para cada pino
for(int i=0; i<pinCount; i++)
{
Pin pin;
//Vinculamos o pino da struct com o recebido por parâmetro
pin.number = pinNumbers[i];
//Colocamos como INPUT
pinMode(pin.number, INPUT);
//Dizemos que o estado está em LOW
pin.status = LOW;
//adicionamos ao vector
pins.push_back(pin);
}
}
RemoteClient::setServerAddressAndPort
//Endereço ip do server e a porta
void RemoteClient::setServerAddressAndPort(IPAddress serverIpAddress, int serverPort)
{
this->serverIpAddress = serverIpAddress;
this->serverPort = serverPort;
}
RemoteClient::loop
void RemoteClient::loop()
{
//Para cada pino
for(int i=0; i<pinCount; i++)
{
//Se o estado foi alterado
if(hasPinStatusChanged(i))
{
//Enviaremos para o server os dados do pino cujo estado foi alterado
sendPinStatus(i);
}
}
}
RemoteClient::hasPinStatusChanged
bool RemoteClient::hasPinStatusChanged(int i)
{
//Faz a leitura do estado do pino na posição 'i' do array de pinos
int status = digitalRead(pins[i].number);
//Se está diferente
if(pins[i].status != status)
{
//Atualizamos os dados do pino e retornamos true
pins[i].status = status;
return true;
}
//Se chegou aqui então o pino não teve seu estado alterado, então retornamos falso
return false;
}
RemoteClient::sendPinStatus
void RemoteClient::sendPinStatus(int i)
{
//Conectamos com o server
WiFiClient client;
client.connect(serverIpAddress, serverPort);
//Enviamos os dados do pino na posição 'i'do array para o server
client.write((uint8_t*) &pins[i], sizeof(Pin));
client.flush();
client.stop();
}
RemoteServer.h
Includes
#ifndef RemoteServer_h
#define RemoteServer_h
#include <Arduino.h>
#include <WiFi.h>
#include <vector>
#include "Pin.h"
typedef void (*OnStatusChangeCallback)(int pinNumber, int pinStatus);
class RemoteServer
{
public:
RemoteServer(int serverPort);
std::vector<WiFiClient> clients;
void begin();
void loop();
void stop();
void onStatusChange(OnStatusChangeCallback callback);
//ou
// void onStatusChange(void (*callback)(int pinNumber, int pinStatus));
//ou
// void onStatusChange(void (*callback)(int, int));
//ou
// void onStatusChange(void (*)(int, int));
private:
void readAndNotify(WiFiClient client);
WiFiServer server;
void (*callback)(int, int); //Variável que irá apontar para função callback
//ou
// void (*callback)(int pinNumber, int pinStatus);
//ou
// OnStatusChangeCallback callback;
};
#endif
RemoteServer.cpp
Includes
#include "RemoteServer.h"
//Construimos o server com o valor de serverPort
RemoteServer::RemoteServer(int serverPort) : server(serverPort)
{
}
RemoteServer::begin
void RemoteServer::begin()
{
//Iniciamos o server para que este possa receber conexões
server.begin();
}
RemoteServer::onStatusChange
void RemoteServer::onStatusChange(OnStatusChangeCallback callback)
{
this->callback = callback;
}
//ou
// void RemoteServer::onStatusChange(void (*callback)(int pinNumber, int pinStatus))
// {
// this->callback = callback;
// }
//ou
// void RemoteServer::onStatusChange(void (*callback)(int, int))
// {
// this->callback = callback;
// }
RemoteServer::loop
void RemoteServer::loop()
{
//Verificamos se temos um client tentando se conectar
WiFiClient client = server.available();
//Se temos
if (client)
{
//Colocamos no final do vector que armazena os clients
clients.push_back(client);
}
for (std::vector<WiFiClient>::iterator it = clients.begin(); it != clients.end();)
{
//O conteúdo apontado pelo iterator é o client
WiFiClient client = *it;
if(client.connected())
{
//Se o client possui algo para nos enviar
if (client.available())
{
readAndNotify(client);
}
//Vamos para o próximo client
it++;
}
//Se não estiver mais conectado
else
{
//Apagamos do vector
clients.erase(it);
}
}
}
readAndNotify
void RemoteServer::readAndNotify(WiFiClient client)
{
//Fazemos a leitura dos dados do client para a variável pin
Pin pin;
client.read((uint8_t*)&pin, sizeof(pin));
//Se possuímos um callback adicionado
if(callback)
{
//Chamamos o callback informando o número do pino que foi alterado e o novo estado
callback(pin.number, pin.status);
}
}
RemoteServer::stop
void RemoteServer::stop()
{
//Paramos o servidor
server.stop();
}
Implementando os arquivos .ino
Após a nossa lib estar
finalizada e no local correto (pasta em
C:\Users\<SEU_USUARIO>\Documents\Arduino\libraries) podemos partir para
os arquivos Client.ino e Server.ino
Client.ino
Includes
#include <WiFi.h>
#include <RemoteClient.h> //Faz parte da nossa lib
//Configurações da rede e porta do socket do outro ESP
//Devem ser iguais nos dois arquivos
#define SSID "ESP32Server"
#define PASSWORD "87654321"
#define SERVER_PORT 5000
//Quantidade de pinos cujo os estados serão verificados
#define PIN_COUNT 2
//Array com os pinos que iremos verificar
int pinNumbers[PIN_COUNT] = {23, 22};
//Objeto que verificará se os pinos mudaram de estado e enviará para o server
RemoteClient remoteClient(pinNumbers, PIN_COUNT);
Setup
void setup()
{
Serial.begin(115200);
//Conecta à rede criada pelo outro ESP
connectWiFi();
remoteClient.setServerAddressAndPort(WiFi.gatewayIP(), SERVER_PORT);
}
ConnectWiFi
void connectWiFi()
{
Serial.print("Connecting to " + String(SSID));
//Conectamos ao Access Point criado pelo outro ESP
WiFi.begin(SSID, PASSWORD);
//Esperamos conectar
while (WiFi.status() != WL_CONNECTED)
{
Serial.print(".");
delay(500);
}
Serial.println();
Serial.println("Connected!");
}
Loop
void loop()
{
//Se não está conectado à rede WiFi
if(WiFi.status() != WL_CONNECTED)
{
//Mandamos conectar
connectWiFi();
}
//Chama o método loop do remoteClient e este verificará se aconteceu mudança no estado dos pinos
//e enviará para o server caso tenha acontecido
remoteClient.loop();
}
Server.ino
Includes
#include <WiFi.h> #include <RemoteServer.h> //Faz parte da nossa lib //Configurações da rede e porta do socket criados por este ESP //Devem ser iguais nos dois arquivos #define SSID "ESP32Server" #define PASSWORD "87654321" #define SERVER_PORT 5000 //Objeto que irá receber por socket informações sobre mudança no estado dos pinos dos ESPs clients RemoteServer remoteServer(SERVER_PORT);
Setup
void setup()
{
Serial.begin(115200);
//Cria uma rede WiFi para os outros ESPs se conectarem
createWiFiAP();
//Inicia o remoteServer para que ele possa receber conexões
remoteServer.begin();
//Passamos a função que será nosso callback quando um pino de um dos clients mudar de estado
remoteServer.onStatusChange(statusChange);
}
CreateWiFiAP
void createWiFiAP()
{
Serial.println("Creating AP " + String(SSID) + "...");
//Coloca este ESP como Access Point
WiFi.mode(WIFI_AP);
//SSID e Senha para se conectarem a este ESP
WiFi.softAP(SSID, PASSWORD);
Serial.println("Created");
}
StatusChange
//Função chamada toda vez que um pino em um dos clients mudar de estado
void statusChange(int pinNumber, int pinStatus)
{
//Aqui vamos apenas replicar o estado no mesmo pino deste ESP
//Colocamos o pino como saída
pinMode(pinNumber, OUTPUT);
//E mudamos o estado para o mesmo que recebemos do client
digitalWrite(pinNumber, pinStatus);
}
Loop
void loop()
{
//Chama a função do remoteServer que irá verificar novas conexões
//e ler os dados dos pinos que os clients enviam quando há mudança de estado
remoteServer.loop();
}









1 Comentários
Boa Tarde Fernando estou tentando compilar o seu código mas ele está dando o seguinte erro: C:\Users\José Tavares\Desktop\ESP8266\Capacete\LibRemote\Server\Server.ino: In function 'void createWiFiAP()':
ResponderExcluirServer:31:14: error: 'class WiFiClass' has no member named 'mode'
Server:31:19: error: 'WIFI_AP_STA' was not declared in this scope
Server:33:14: error: 'class WiFiClass' has no member named 'softAP'
exit status 1
stray '\302' in program