#include <WiFi.h>
#include <PubSubClient.h>
#include <TimeInterval.h>
#define LED 18
//Conexão com o WiFI
const char *SSID = "Wokwi-GUEST";
const char *PWD = "";
//configurações de conexão MQTT
WiFiClient wifiClient;
PubSubClient mqttClient(wifiClient);
char *mqttServer = "broker.hivemq.com";
int mqttPort = 1883;
// Variáveis globais para controle de publicação e ciclo do LED
TimeInterval intervalTest;
bool triggerOn = false;
unsigned long startCycle = millis();
//função para conectar ao WiFi
void ConectaNoWiFi() {
Serial.print("Conectando ao WiFi");
WiFi.begin(SSID, PWD);
//Caso tenha dificuldades em conectar, imprime um “.”
while (WiFi.status() != WL_CONNECTED) {
Serial.print(".");
delay(500);
}
//Se conectado, imprime “Conectado”
Serial.print("Conectado.");
}
//Realiza as configurações do MQTT
void setupMQTT() {
mqttClient.setServer(mqttServer, mqttPort);
}
//A função callback é responsável por receber as msgs. Toda vez que uma novo msg chega, a função será ativada.
void callback(char* topic, byte* payload, unsigned int length) {
//Como todos os tópicos vão entrar nessa função, é interessante desenvolver um “if” para definir qual tópico você pretende ler.
if (strcmp(topic, "/gkstakaLEDcomando") == 0) {
Serial.println("Mensagem recebida do tópico “/gkstakaLEDcomando");
// faz a leitura do estado atual do LED
int ledUltimoEstado = digitalRead(LED);
//A informação chega em um vetor de bytes. Você pode imprimir direto, ou salvar em outra variável para realizar as conversões desejadas.
//Neste caso, está sendo realizado a impressão direta do vetor de bytes (payload)
char dadosChar[length];
for (int i = 0; i < length; i++) {
dadosChar[i] = ((char)payload[i]);
}
// Converte a mensagem recebida em um comando mais facil para controle de estado
int comando = atoi(dadosChar);
Serial.println("Comando: " + (String)comando);
// Se o comando for diferente do estado atual do LED, irá reiniciar um novo ciclo, e o que controla
// se deve iniciar com ele ligado ou desligado é o triggerOn
if (ledUltimoEstado != comando) {
startCycle = millis();
triggerOn = comando;
}
Serial.print("\n");
}
}
//Realiza a conceção com o Broker MQTT
void conectaBrokerMQTT() {
Serial.println("Conectando ao broker");
//A função mqttClient.connected() verifica se existe uma conexão ativa. Depende do Broker, a conexão pode se manter ativa, ou desativar a cada envio de msg.
while (!mqttClient.connected()) {
//Se entrou aqui, é porque não está conectado. Então será feito uma tentativa de conexão infinita, até ser conectado.
Serial.println("Conectando ao Broker MQTT");
//define o nome da ESP na conexão. Está sendo gerado um nome aleatório, para evitar ter duas ESPs com o mesmo nome. Neste caso, uma derrubaria a outra.
String clientId = "ESP32Client-";
clientId += String(random(0xffff), HEX);
//Realiza a conexão com a função “mqttClient.connect”. Caso seja um sucesso, entra no if e imprime “Conectado ao Broker MQTT.”
if (mqttClient.connect(clientId.c_str())) {
Serial.println("Conectado ao Broker MQTT.");
}
}
}
//setup
void setup() {
Serial.begin(9600);
ConectaNoWiFi();
setupMQTT();
pinMode(LED, OUTPUT);
}
//loop
void loop() {
//Verifica se a conexão está ativa, caso não esteja, tenta conectar novamente.
if (!mqttClient.connected()) {
conectaBrokerMQTT();
//Define quais tópicos vão ser assinados, ou seja, toda vez que alguma informação chegar destes tópicos, receberemos a informação.
//Está adicionado dentro deste if, pois se a cair a conexão com o broker, será possível reativa-la.
mqttClient.subscribe("/gkstakaLEDcomando");
mqttClient.subscribe("/gkstakaLEDinfo");
//Define o nome da função que será o callback, ou seja, toda vez que uma novo msg chegar de um dos tópicos, ela será enviada para a função ‘callback’
mqttClient.setCallback(callback);
}
if (mqttClient.connected()) {
// Caso conectado, o módulo enviará mensagens a cada 1 segundo para informar o estado do LED para que
// a aplicação python consiga ler
if (intervalTest.intervalMillis(1000)) {
// faz a leitura do LED e serializa para poder ser enviado via MQTT protocol
bool ledState = digitalRead(LED);
char message[5];
sprintf(message, "%d", ledState);
mqttClient.publish("/gkstakaLEDinfo", message);
}
}
// As chamadas que verificam a duração do ciclio utiliza millis() para que seja uma chamada não
// Bloqueante, para que sempre o módulo consiga publicar o estado do LED
// Caso fosse utilizado delay(), ficaria todo esse tempo com o módulo inativo para realizar outras
// funções
// Ciclo caso seja para ligar primeiro
if (triggerOn){
if(millis() - startCycle < 5000){
digitalWrite(LED, HIGH);
}
else if (millis() - startCycle < 15000){
digitalWrite(LED, LOW);
}
else{
startCycle = millis();
}
}
// Ciclo caso seja para desligar primeiro
else{
if(millis() - startCycle < 10000){
digitalWrite(LED, LOW);
}
else if (millis() - startCycle < 15000){
digitalWrite(LED, HIGH);
}
else{
startCycle = millis();
}
}
delay(500);
mqttClient.loop();
}
//realiza o sincronismo com o Broker, por exemplo, verifica se existem msgs para ler se estiver inscrito em algum tópico