#include <WiFi.h>
#include <PubSubClient.h>
     
/* ----- Puertos ----- */
const int THERMISTOR_PIN = 33; 

/* ----- Caracteristicas del Termistor -----*/
const double VCC = 3.3;             // NodeMCU on board 3.3v vcc
const double R2 = 10000;            // 10k ohm series resistor
const double adc_resolution = 4096; // 12-bit adc

const double A = 0.001129148;   // thermistor equation parameters
const double B = 0.000234125;
const double C = 0.0000000876741; 


/* ----- Wifi ----- */
const char* ssid = "Wokwi-GUEST";   // name of your WiFi network
const char* password = ""; // password of the WiFi network
WiFiClient wClient;
 
/* ----- MQTT ----- */
const char* mqttBroker = "test.mosquitto.org"; // IP address of your MQTT 
const char *ID = "UdeA_thing-001";  // Name of our device, must be unique
// Topics
const char *topic = "udea_home/room/temperature"; 

// Setup MQTT client

PubSubClient mqttClient(wClient); 

/* ----- Variables del programa ----- */
// Variables y constantes asociadas al programa
const int PORT_SPEED = 9600; 
const int BUF_SIZE = 100;
int adc_value;
double currentTemp;

const long intTimer = 5000;    // Intervalo de publicación (5 seg)
unsigned long prevTimer = 0;   // Marca de tiempo anterior (t - 1)
unsigned long actualTimer = 0; // Marca de tiempo actual (t)
char message[BUF_SIZE];


/* ----- Helper Functions ----- */   
 
float get_Temperature(int acd_value){
  double Vout, Rth, temperature;
  adc_value = adc_resolution - acd_value + 0.5; // switch direction
  Vout = (adc_value * VCC) / adc_resolution; 
  Rth = (VCC * R2 / Vout) - R2; // Formula for R2 as Pull-down: Vcc-Rth-R2-GND

  /*  Steinhart-Hart Thermistor Equation:
   *  Temperature in Kelvin = 1 / (A + B[ln(R)] + C[ln(R)]^3)
  */
  temperature = (1 / (A + (B * log(Rth)) + (C * pow((log(Rth)),3))));   // Temperature in kelvin
  temperature = temperature - 273.15;  // Temperature in degree celsius
  // Serial.print("Rth:");
  // Serial.print(Rth);
  // Serial.print(" Temperature = ");
  // Serial.print(temperature);
  // Serial.println(" degree celsius");
  return temperature;
}
 
// --- MQTT ---
void mqttConnect() {
  // Loop until we're reconnected
  while (!mqttClient.connected()) {
    Serial.print("Attempting MQTT connection...");
    if (mqttClient.connect(ID)) {
      Serial.println("OK");
      // Topic(s) subscription
      // En este ejemplo solo se publica
    } 
    else {     
      // Retry connection
      Serial.print("failed, rc=");
      Serial.print(mqttClient.state());
      Serial.println(" try again in 5 seconds");
      delay(5000);    
    }
  }
}

// --- Wifi ---

// Wifi conection
void setup_wifi() {
  Serial.print("\nConnecting to ");
  Serial.println(ssid);

  // WiFi.begin(ssid, password); // Connect to network
  WiFi.begin(ssid, password, 6);
  while (WiFi.status() != WL_CONNECTED) { // Wait for connection
    delay(500);
    Serial.print(".");
  }

  Serial.println();
  Serial.println("WiFi connected");
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());
}
   
/* ----- Main funtions ----- */
void setup() {
  // Serial setup
  Serial.begin(PORT_SPEED);
  // Setup wifi
  setup_wifi();

  // MQTT setup
  mqttClient.setServer(mqttBroker, 1883);
}
  
// loop
void loop() {
  // Check if we are still connected to the MQTT broker
  if (!mqttClient.connected()) {
    mqttConnect();
  }
  // Let PubSubClient library do his magic
  mqttClient.loop();

  actualTimer = millis();
  // Check if the timer is expired
  if (actualTimer - prevTimer >= intTimer) {
    // save the last timestamp a message was sent
    prevTimer = actualTimer;

    // Read temperature
    adc_value = analogRead(THERMISTOR_PIN);
    currentTemp = get_Temperature(adc_value); 
    String(currentTemp, 2).toCharArray(message, BUF_SIZE);

    // Post some debugging information on serial port
    Serial.print("[MQTT]: Sending message to topic: ");
    Serial.println(topic);
    Serial.println(message);

    // Publish message
    mqttClient.publish(topic, message);

    Serial.println();
  }
}