/***************************************************
  Juni 2025
  myMQTT.ino
  MQTT Broker Verbindung
  Ausgabe am seriellen Monitor
 ****************************************************/

#include <ESP8266WiFi.h>    // für WLAN Verbindung
#include <PubSubClient.h>  // von Nick für MQTT Datenaustausch

#define BUILT_IN_LED 2  // GPIO for D1-mini

WiFiClient espClient;
PubSubClient client(espClient);

// WLAN Zugangsdaten
const char* ssid = "HSB-Gast";
const char* password = "";

// MQTT Zugangsdaten
//const char* mqtt_broker = "test.mosquitto.org";       // Broker-IP
const char* mqtt_broker = "mqtt.eclipseprojects.io";  // Broker-IP
const char* mqtt_username = "";
const char* mqtt_password = "";
const int mqtt_port = 1883;

// MQTT stuff Topic
const char* mqtt_main_Topic = "My_SmartHome/Wohnraum_1/#";           // alle Topic subscribe
const char* mqtt_LWT_Topic = "My_SmartHome/Wohnraum_1/Wifi_Status";  // Last Will & Testament if connection lost

const char* mqtt_TimeStamp_Topic = "My_SmartHome/Wohnraum_1/TimeStamp";
const char* mqtt_debug_Topic = "My_SmartHome/Wohnraum_1/Debug_Info";
const char* mqtt_DHT_Temp_Topic = "My_SmartHome/Wohnraum_1/HTU_Temperatur_°C";
const char* mqtt_DHT_Luft_Topic = "My_SmartHome/Wohnraum_1/HTU_Luftfeuchte_%rel";

const char* mqtt_DeviceName_Topic = "My_SmartHome/Wohnraum_1/DeviceName";
const char* mqtt_DevicePlace_Topic = "My_SmartHome/Wohnraum_1/DevicePlace";

const char* deviceName = "D1mini_HTU_MQTT";
const char* devicePlace = "HTL-Leonding";

uint32_t chipId = ESP.getChipId();
String clientId = "ESP-" + String(chipId) + "-" + String(random(0xffff), HEX);  // eine eindeutige einzigartige ID
String str_WiFi_IP = " -- ";

int qos = 1;         // MQTT Quality of Service
bool retain = true;  // sende diese Message if new Client


//============  Program Code Message income ===================
void callbackMessage(char* topic, byte* payload, unsigned int length) {
  String incommingMessage = "";
  for (int i = 0; i < length; i++) incommingMessage += (char)payload[i];
  //Serial.println("Message arrived \t[" + String(topic) + "]\t" + incommingMessage);   // jede abonnierte Message kommt hier herein

  // MESSAGE RECEPTION HERE 
  if (strcmp(topic, mqtt_DHT_Temp_Topic) == 0) {
    Serial.println("MQTT received: HTU-Temperatur = " + incommingMessage + " °C");
  }
  // hier die nächsten Abfragen auf Topics ....
}

//================ publising as string ====================
void publishMessage(const char* topic, String payload , boolean retained) {
  if (client.publish(topic, payload.c_str(), retained)) {
    //Serial.println("Message publised [" + String(topic) + "]: " + payload);
  }
}

//================ Fehlercode der MQTT Verbindung
void printMQTTError(int state) {
  switch (state) {
    case -4: Serial.println("Timeout (Broker nicht erreichbar)"); break;
    case -3: Serial.println("Verbindung verloren"); break;
    case -2: Serial.println("Connect fehlgeschlagen"); break;
    case -1: Serial.println("Disconnected"); break;
    case 1: Serial.println("Falsches Protokoll"); break;
    case 2: Serial.println("Client-ID abgelehnt"); break;
    case 3: Serial.println("Broker nicht verfügbar"); break;
    case 4: Serial.println("Falscher Benutzername/Passwort"); break;
    case 5: Serial.println("Nicht autorisiert"); break;
    default: Serial.println("Unbekannter Fehler"); break;
  }
}


//================ Prüft die Verbindung zum MQTT Broker und baut diese wieder auf, wenn disconnected
void reconnect() {
  while (!client.connected()) {  // Loop until we're reconnected
    delay(1000);
    Serial.println("MQTT not connected, try to connect...");
    bool clientConnected = client.connect(clientId.c_str(), mqtt_username, mqtt_password, mqtt_LWT_Topic, qos, retain, "offline");
    if (!clientConnected) {
      Serial.print("failed, rc= ");
      //Serial.print(client.state());
      printMQTTError(client.state());             // siehe oben Fehlercode in Klartext
      Serial.println(" try again in 5 seconds");  // Wait 5 seconds before retrying
      delay(5000);
    } else {
      Serial.print("MQTT reconnected to ");
      Serial.print(mqtt_broker);
      Serial.print(" on port: ");
      Serial.print(mqtt_port);

      client.subscribe(mqtt_main_Topic);  //SUBSCRIBE TO TOPIC HERE, wenn Nachrichten empfangen werden sollen.

      publishMessage(mqtt_LWT_Topic, "online", retain);
      publishMessage(mqtt_DeviceName_Topic, deviceName, retain);
      publishMessage(mqtt_DevicePlace_Topic, devicePlace, retain);
      //publishMessage(msgWiFi_topic, String(ssid).c_str(), retain);
      //publishMessage(msgWiFi_ip_topic, str_WiFi_data.c_str(), retain);
    }
  }
}

//==================  MQTT starten und Verbinden =========================
void startMQTT() {
  Serial.print("\nMQTT-Verbindung herstellen mit ");
  Serial.println(clientId);
  
  client.setServer(mqtt_broker, 1883);
  client.setCallback(callbackMessage);   // für einkommende Nachrichten callback Funktion registrieren

  reconnect();    // MQTT Verbindung herstellen  
}
