/*
Aluno: José Marques Teixeira dos Ramos Junior
Instituição: Instituto Politécnico de Portalegre - IPP
Caso deseje testar, é necessário Wokwi IoT Gateway,
como explicado no seguinte link:
https://docs.wokwi.com/guides/esp32-wifi#the-private-gateway
Inicie a simulação e abra http://localhost:9080
em outra aba do navegador.
Observe que, para simular pelo Wokwi,
o IoT Gateway requer uma assinatura do Wokwi Club.
Para adquirir uma assinatura do Wokwi Club, acesse https://wokwi.com/club
---------
Após acessar o gateway, na aba do código, pressionar F1,
digitar "Enable Private Wokwi IoT Gateway" e habilitar para uso
---------
Para conectar ao mosquitto MQTT foi necessário baixar e instalar o programa.
Quando rodar o programa, abrir anteriormente o CMD e rodar:
O caminho para a pasta, no meu caso, cd "C:\Program Files\mosquitto"
E então rodar, .\mosquitto_sub.exe -h broker.hivemq.com -p 1883 -t "LStKw7ZPr/temperature"
onde LStKw7ZPr/temperature é o tópico onde a temperatura é enviada.
*/
#include "DHTesp.h"
#include <PubSubClient.h>
#include <WiFi.h>
#include <WiFiClient.h>
#include <WebServer.h>
#include <uri/UriBraces.h>
#define TOPIC_PUBLISH_TEMPERATURE "LStKw7ZPr/temperature" //tópico MQTT onde a temperatura será publicada
#define MAX_BUFFER 200 //tamanho do buffer circular que armazenará as leituras de temperatura.
const char *SSID = "Wokwi-GUEST"; // SSID / nome da rede WI-FI que deseja se conectar
const char *PASSWORD = ""; // Senha da rede WI-FI que deseja se conectar
#define WIFI_CHANNEL 6 // Canal do Wifi
WebServer server(80); // Servidor Web
#define ID_MQTT "esp32_mqtt" // id mqtt (para identificação de sessão)
const int DHT_PIN = 15; // Pino onde o sensor DHT22 está conectado.
int del = 2000; // Intervalo de tempo (em milissegundos) entre as leituras de temperatura e o envio de dados
DHTesp dhtSensor; // Instancia um objeto para interagir com o sensor DHT22.
const char *BROKER_MQTT = "broker.hivemq.com"; //Especificam o endereço do broker MQTT.
int BROKER_PORT = 1883; // Porta do Broker MQTT
unsigned long publishUpdate; // Variável usada para controlar a frequência de publicação.
WiFiClient espClient; // Cria o objeto espClient
PubSubClient MQTT(espClient); // Instancia o Cliente MQTT passando o objeto espClient
int buffer_size = MAX_BUFFER; // Tamanho do buffer circular.
float temperature = 0; // Armazena a média da temperatura calculada.
float buffer[MAX_BUFFER]; // Buffer circular para armazenar as leituras de temperatura.
int L_buffer = 0; // L_buffer e R_buffer índices para a leitura e escrita no buffer circular.
int R_buffer = MAX_BUFFER-1;
// A parte seguinte gera e envia uma página HTML simples para o navegador, mostrando a temperatura e permitindo a alteração do delay.
void sendHtml() {
String response = R"(
<!DOCTYPE html><html>
<head>
<title>ESP32 Web Server Demo</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
html { font-family: sans-serif; text-align: center; }
body { display: inline-flex; flex-direction: column; }
h1 { margin-bottom: 1.2em; }
h2 { margin: 0; }
div { display: grid; grid-template-columns: 1fr 1fr; grid-template-rows: auto auto; grid-auto-flow: column; grid-gap: 1em; }
.btn { background-color: #5B5; border: none; color: #fff; padding: 0.5em 1em;
font-size: 2em; text-decoration: none }
.btn.OFF { background-color: #333; }
</style>
</head>
<body>
<h1>ESP32 Web Server</h1>
<div>
<h2>DELAY</h2>
<form action="/delay" method="get">
<input type="range" name="delay" id="delay" min="500" max="2000">
<button type="submit">DELAY</button>
</form>
<h2>TEMPERATURA</h2>
<p>TEMPERATURE_S °C</p>
</div>
</body>
</html>
)";
response.replace("TEMPERATURE_S", String(temperature, 1));
server.send(200, "text/html", response);
}
// Manipula a mudança do delay enviada pelo formulário na página HTML e atualiza o valor del.
void change_delay(){
Serial.println(server.arg("delay"));
del = server.arg("delay").toInt();
sendHtml();
}
void initWiFi(void); // Inicializa a conexão Wi-Fi e tenta reconectar se necessário.
void initMQTT(void); // Inicializa a conexão com o broker MQTT.
void callbackMQTT(char *topic, byte *payload, unsigned int length);
void reconnectMQTT(void); // Reestabelece a conexão com o broker MQTT em caso de desconexão.
void reconnectWiFi(void); // Reestabelece a conexão com o Wi-Fi em caso de desconexão.
void checkWiFIAndMQTT(void); // Verifica se a conexão Wi-Fi e MQTT estão ativas e tenta reconectar se necessário.
void initWiFi(void)
{
delay(10);
Serial.println("------Conexao WI-FI------");
Serial.print("Conectando-se na rede: ");
Serial.println(SSID);
Serial.println("Aguarde");
reconnectWiFi();
}
void initMQTT(void)
{
MQTT.setServer(BROKER_MQTT, BROKER_PORT); // Informa qual broker e porta deve ser conectado
//MQTT.setCallback(callbackMQTT); // Atribui função de callback (função chamada quando qualquer informação de um dos tópicos subescritos chega)
}
/* Reconecta-se ao broker MQTT (caso ainda não esteja conectado ou em caso de a conexão cair)
em caso de sucesso na conexão ou reconexão, o subscribe dos tópicos é refeito. */
void reconnectMQTT(void)
{
while (!MQTT.connected()) {
Serial.print("* Tentando se conectar ao Broker MQTT: ");
Serial.println(BROKER_MQTT);
if (MQTT.connect(ID_MQTT)) {
Serial.println("Conectado com sucesso ao broker MQTT!");
// MQTT.subscribe(TOPIC_SUBSCRIBE_LED);
} else {
Serial.println("Falha ao reconectar no broker.");
Serial.println("Nova tentativa de conexao em 2 segundos.");
delay(2000);
}
}
}
/* Verifica o estado das conexões WiFI e ao broker MQTT.
Em caso de desconexão (qualquer uma das duas), a conexão é refeita. */
void checkWiFIAndMQTT(void)
{
if (!MQTT.connected())
reconnectMQTT(); // se não há conexão com o Broker, a conexão é refeita
reconnectWiFi(); // se não há conexão com o WiFI, a conexão é refeita
}
void reconnectWiFi(void)
{
// se já está conectado a rede WI-FI, nada é feito.
// Caso contrário, são efetuadas tentativas de conexão
if (WiFi.status() == WL_CONNECTED)
return;
WiFi.begin(SSID, PASSWORD); // Conecta na rede WI-FI
while (WiFi.status() != WL_CONNECTED) {
delay(100);
Serial.print(".");
}
Serial.println();
Serial.print("Conectado com sucesso na rede ");
Serial.print(SSID);
Serial.println("IP obtido: ");
Serial.println(WiFi.localIP());
}
// void setup() a seguir
// Inicializa as comunicações (Serial, Wi-Fi, MQTT),
// configura o sensor DHT22,
// inicia o servidor web e preenche o buffer circular com leituras iniciais do sensor.
void setup() {
Serial.begin(115200);
dhtSensor.setup(DHT_PIN, DHTesp::DHT22);
// Inicializa a conexao Wi-Fi
initWiFi();
// Inicializa a conexao ao broker MQTT
initMQTT();
server.on("/", sendHtml);
server.on("/delay", change_delay);
server.begin();
for (int i = 0; i < MAX_BUFFER; ++i) {
TempAndHumidity data = dhtSensor.getTempAndHumidity();
buffer[i] = data.temperature;
temperature += data.temperature;
delay(10);
}
temperature /= MAX_BUFFER;
Serial.println("HTTP server started");
}
// void loop() a seguir, que é o loop principal
// Verifica as conexões, lê a temperatura,
// atualiza o buffer circular e a média móvel,
// publica a temperatura no broker MQTT e serve a página web.
void loop() {
// Verifica o funcionamento das conexões WiFi e ao broker MQTT
checkWiFIAndMQTT();
TempAndHumidity data = dhtSensor.getTempAndHumidity();
Serial.println("Temp: " + String(data.temperature, 1) + "°C");
Serial.println("---");
//atualiza a média
temperature = temperature - buffer[L_buffer]/MAX_BUFFER + data.temperature/MAX_BUFFER;
//atualiza o buffer
L_buffer = (L_buffer + 1) % MAX_BUFFER;
R_buffer = (R_buffer + 1) % MAX_BUFFER;
buffer[R_buffer] = data.temperature;
MQTT.publish(TOPIC_PUBLISH_TEMPERATURE, String(temperature, 1).c_str());
// Keep-alive da comunicação com broker MQTT
MQTT.loop();
server.handleClient();
delay(del);
}