/*=================================================================================
CETEC CAPACITAÇÕES
Capacitação no aplicativo Wokwi.
Coordenador: Professor Luiz Tetsuharu Saito
Professor: Juliano Koichi Tanabe

SETEMBRO DE 2024

Aluno: Carlos Barreira da Silva Farinhas
ETEC Aristóteles Ferrreira - Santos

Projeto 1 – Montar um circuito ESP 32 conectado a um display OLED SSD1306 e um
sensor DHT22 no Wokwi.

A programação (na linguagem C/Arduino) deverá ler a temperatura e umidade
simuladas no DHT22, e exibir os valores medidos de temperatura e umidade no 
display OLED.

Os valores também deverão ser enviados pelo protocolo MQTT ao test.mosquitto.org,
porta 1883 como mensagem de tópico.

Um app deverá ser desenvolvido no App Inventor e deverá conectar-se e consultar
o tópico, no test.mosquitto.org, enviado pelo ESP32, quando este estiver em modo
de simulação no Wokwi, com os dados de temperatura e umidade e exibir as
informações em tela.

=================================================================================*/

//Bibliotecas utilizadas
#include <WiFi.h>
#include <PubSubClient.h>
#include <DHT.h>
#include <Adafruit_SSD1306.h>


//constantes
#define DHTPIN 4
#define DHTTYPE DHT22
#define TOPIC "barPr1" //MUDAR O TÓPICO


//Dados do WiFi
const char* ssid = "Wokwi-GUEST";
const char* password = "";
const char* mqtt_server = "test.mosquitto.org";

//Declarações e classes
WiFiClient espClient;
PubSubClient client(espClient);
DHT dht(DHTPIN, DHTTYPE);

// --- Declaração para o display SSD1306 connectado ao I2C (pinos SDA, SCL) ----

Adafruit_SSD1306 display(128, 64, & Wire, -1);

void setup() {
  //Inicialização do serial
    Serial.begin(115200);

    // Chamada das funções de configuração do WiFi, do MQTT e do sensor
    setup_wifi();
    client.setServer(mqtt_server, 1883);
    dht.begin();

  // --- inicialização do display OLED ---
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);  // Endereço 0x3C para 128x64


  display.clearDisplay(); // garante que o display começa vazio
}

void loop() {

  reconnect();
  
  client.loop();

  // lendo o sensor e guardando dados na variáveis
  float h = dht.readHumidity();
  float t = dht.readTemperature();
  
  // Caso o sensor não envie dados, será mostrada esta mensagem no monitor serial
  if (isnan(h) || isnan(t)) {
    Serial.println("Sem dados do sensor!");
    return;
  }

  Serial.println(h);
  Serial.println(t);


  //Dados que serão enviados ao servidor MQTT
  String payload = "{";
  payload += "\"Umidade  \":";
  payload +=  String(h);
  payload += ",\"Temperatura  \":";
  payload += String(t);
  payload += "}";

  //Envio de dados ao servidor MQTT e mensagem de sucesso ou não
  if (client.publish(TOPIC, (char*) payload.c_str(), true)) {
    Serial.println("Mensagem publicada com sucesso");
  } else {
    Serial.println("Falha na publicação da mensagem");
  }

// configuração do display 
display.setTextSize(1);
display.setTextColor(WHITE);	

// mostrar temperatura
display.setCursor(5,10);
display.print("Temperatura =  ");
display.setCursor(90,10);
display.print(t);

// mostrar umidade
display.setCursor(5,40);
display.print("Umidade =  ");
display.setCursor(90,40);
display.print(h);

// mandar para o display
display.display();
delay(2000);

// limpa o display
display.clearDisplay( );

}

//Funcão para configurar o WiFi
void setup_wifi() {
  delay(10);
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
}

//Função para reconectar ao servidor em caso de desconexão

void reconnect ( void ) {

  if ( ! client.connected ( ) ) {  
    
    while ( ! client.connected ( ) ) {     
      
      Serial.print ( F ( "Conectando novamente ao servidor" ) );

      if ( client.connect ( "Client_test" ) ) {  
        Serial.println ( F ( "Cliente conectado" ) );
      } else {    
        
        Serial.print ( F ( "Falha ao conectar, tipo de erro: " ) );
        Serial.print ( client.state ( ) );     // Tipo de erro de conexão
        Serial.println ( F ( "  Tentando novamente em 5 segundos" ) );
        delay ( 5000 );
      }
    }
  }
}