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