/* ESP32 MQTT-Beispiel mit 2 Teilnehmern
 *  Benötigt die Bibliothek MQTT (by Joel Gaeswiller)
 *  Der ESP verbindet sich mit einem Broker, der Port kann hier nicht angegeben werden
 *  
 *  Per MQTT werden verschiedenen Nachrichten zwischen 2 ESP32 ausgetauscht
 *  Verbesserte Version: Gerätename und MQTT-Topic werden als String zusammen-
 *  gesetzt, der Client-Name enthält die MAC-Adresse als "zufälligen" Wert.
 *  
 *  Die Simulation wird 2 mal gestartet bzw. ein realer ESP32 und eine Simulation
 *  Ein ESP ist SOURCE, der andere TARGET (auch über Kreuz)
 *  Autor: Spi 
 *  Version: 1.0
 *  Datum: 2024-02-02
 ***************************************************************************/  
#include <WiFi.h>
#include <MQTT.h>

// Update these with values suitable for your network.

const char* ssid = "Wokwi-GUEST";
const char* password = "";
const byte  channel = 6;    // wifi channel only for Wokwi
//#include <credentials.h>

//***** MQTT-Topics hier zentral anpassen
String HOST_NAME_SOURCE = "esp1";
String MQTT_TOPIC1 = "wvss/esp32/" + HOST_NAME_SOURCE;
String HOST_NAME_TARGET = "esp_spi";
String MQTT_TOPIC2 = "wvss/esp32/" + HOST_NAME_TARGET;
//const char* mqtt_server = "192.168.1.1";
const char* mqtt_server = "broker.hivemq.com";

const int LED_rot=32, Taster4=4;

WiFiClient net;
MQTTClient client;

unsigned long lastMillis = 0, lastToggle = 0;
bool Zustand, Taster4_neu, Taster4_alt;
char msg[50];

void connect() {
  Serial.print("Suche WLAN...");
  while (WiFi.status() != WL_CONNECTED) {
    Serial.print(".");
    delay(1000);
  }

  Serial.print("\nverbinde als Client ");
  // generate client-name from ESP32 MAC address
  String Client_Name = HOST_NAME_SOURCE + "::" + WiFi.macAddress();
  Serial.println(Client_Name);
  while (!client.connect(Client_Name.c_str(), "try", "try")) {
    Serial.print(".");
    delay(1000);
  }

  Serial.println("\nverbunden!");
  // subscribe topics
  client.subscribe(MQTT_TOPIC1+"/#");  
  client.subscribe(MQTT_TOPIC2+"/#");  
  // client.unsubscribe("hello/");
}

void messageReceived(String &topic, String &payload) {
  Serial.println("incoming: " + topic + " - " + payload);

  // Switch the LED correct topic was received  
  // and check the first character 
  if (topic == MQTT_TOPIC2 + "/switch") {
    Serial.println("MQTT-Befehl erhalten");
    if ((char)payload[0] == '1') {
      digitalWrite(LED_rot, LOW);   // turn the LED on (low active)
    } else if ((char)payload[0] == '0'){
      digitalWrite(LED_rot, HIGH);  // turn the LED off 
    }
  }
  
}

void setup() {
  Serial.begin(115200);
  //WiFi.begin(ssid, password);   // automatic selsctrion of wifi-channel => use with local AP
  WiFi.begin(ssid, password, channel);
  pinMode(LED_rot, OUTPUT);
  pinMode(Taster4, INPUT_PULLUP);
  
  Zustand = true;

  // start MQTT connection to server
  client.begin(mqtt_server, net);
  // callback-function for received messages
  client.onMessage(messageReceived);

  connect();

  delay(1000);
  // send test message 
  client.publish("wvss/esp32/chat", "hello world from " + MQTT_TOPIC1);
}

void loop() {
  client.loop();  // handle incoming MQTT messages
  
  if (!client.connected()) { // lost MQTT-connection? Reconnect 
    connect();
  }

  // read a button and publish a message on change
  if (millis() - lastMillis > 100) {   // for debouncing
    lastMillis = millis();
    Taster4_neu = digitalRead(Taster4);
    if ( !Taster4_neu && Taster4_alt) {
      client.publish(MQTT_TOPIC1 + "/switch", "1");  
    }
    else if ( Taster4_neu && !Taster4_alt) {
      client.publish(MQTT_TOPIC1 + "/switch", "0");  
    }
    Taster4_alt = Taster4_neu;
  }

  // send toggle-message every 5 seconds (heartbeat)
  if (millis() - lastToggle > 5000) {
    lastToggle = millis();
    Serial.println("Toggle");
    if(Zustand == true) {
      client.publish(MQTT_TOPIC1 + "/toggle", "true");
    }
    else {
      client.publish(MQTT_TOPIC1 + "/toggle", "false");
    }
    Zustand = ! Zustand;
  }
}