#include <Homie.h>
#include <ArduinoOTA.h>
#include <OneButton.h>

OneButton lock(D5, true);
OneButton door(D6, true);

#define FW_NAME "ctdoor"
#define FW_VERSION "2.1.5"

unsigned long WiFifix = 0;
unsigned long problemDetected = 0;
int problemCount = 0;
String problemCause;
bool locked = false;
bool closed = false;

HomieNode ctdoor("frontdoor", "commands");

bool fakeHandler(const HomieRange& range, const String& value) {
  return true;
}

bool cmdHandler(const HomieRange& range, const String& value) {
  String cmd = value;
  cmd.toLowerCase();

  if (cmd == "reset") {
    ctdoor.setProperty("cmd/set").send(" ");
    delay(1000);
    Homie.reset();
  }
  else if (cmd == "reboot") {
    ctdoor.setProperty("cmd/set").send(" ");
    delay(1000);
    Homie.reboot();
  }
  else if (cmd == "ota-restart") {
    ctdoor.setProperty("cmd/set").send(" ");
    ArduinoOTA.setHostname(Homie.getConfiguration().deviceId);
    ArduinoOTA.begin();
  }
  ctdoor.setProperty("cmd").send(value);
  return true;
}

void lockactivityClose() {
  if (Homie.getMqttClient().connected()) {
    ctdoor.setProperty("lock").send("locked");
  }
  Homie.getLogger() << "Lockactivity: locked" << endl;
}

void lockactivityOpen() {
  Homie.getLogger() << "Lockactivity triggered" << endl;
  if (Homie.getMqttClient().connected()) {
    ctdoor.setProperty("lock").send("unlocked");
  }
  Homie.getLogger() << "Lockactivity: unlocked" << endl;
}

void dooractivityClose() {
  Homie.getLogger() << "DooractivityClose triggered" << endl;
  if (Homie.getMqttClient().connected()) {
    ctdoor.setProperty("door").send("closed");
  }
  Homie.getLogger() << "Dooractivity: closed" << endl;
}

void dooractivityOpen() {
  Homie.getLogger() << "DooractivityOpen triggered" << endl;
  if (Homie.getMqttClient().connected()) {
    ctdoor.setProperty("door").send("open");
  }
  Homie.getLogger() << "Dooractivity: opened" << endl;
}

void fixWiFi() {
  // Posts every 10 seconds the state of WiFi.status(), Homie.getMqttClient().connected() and Homie.isConfigured()
  // Within this interval the connectivity is checked and logged if a problem is detected
  // Then it disconnects Wifi, if Wifi or MQTT is not connected for 1 Minute (but only if Homie is configured)
  if ( WiFifix == 0 || ((millis() - WiFifix) > 10000)) {
    if (Homie.isConfigured() == 1) {
      float rssi = WiFi.RSSI();
      //activate to enable RSSI to MQTT informations
      //ctdoor.setProperty("quality").send(String(rssi));
      Homie.getLogger() << "Wifi-state:" << WiFi.status() << " | Wi-Fi signal quality: " << rssi << " | MQTT-state:" << Homie.getMqttClient().connected() << " | HomieConfig-state:" << Homie.isConfigured() << endl;

      if (!Homie.getMqttClient().connected() || WiFi.status() != 3) {
        if (0 == problemDetected) {
          if (WiFi.status() != 3) {
            problemCause = "WiFi: Disconnected ";
          }
          if (!Homie.getMqttClient().connected()) {
            problemCause += "MQTT: Disconnected";
          }
          Homie.getLogger() << "Connectivity in problematic state --> " << problemCause << endl;
          problemDetected = millis();
        }
        else if ((millis() - problemDetected) > 120000 && (problemCount >= 5)) {
          Homie.getLogger() << "Connectivity in problematic state --> This remained for 10 minutes. Rebooting!" << endl;
          Homie.reboot();
        }
        else if ((millis() - problemDetected) > 120000 && problemCount < 5) {
          problemCount = (problemCount + 1);
          Homie.getLogger() << "Connectivity in problematic state --> " << problemCause << "/n This remained for 2 minutes. Disconnecting WiFi to start over." << endl;
          problemDetected = 0;
          problemCause = "";
          WiFi.disconnect();
        }
      }
      else if (problemCount != 0 && Homie.getMqttClient().connected() || WiFi.status() == 3) {
        problemCount = 0;
        ArduinoOTA.setHostname(Homie.getConfiguration().deviceId);
        ArduinoOTA.begin();
      }
    }
    WiFifix = millis();
  }
}

void setup() {
  Homie_setBrand(FW_NAME);
  Homie_setFirmware(FW_NAME, FW_VERSION);
  Serial.begin(115200);
  Serial << endl << endl;
  door.attachLongPressStart(lockactivityClose);
  door.attachLongPressStop(lockactivityOpen);
  lock.attachLongPressStart(dooractivityClose);
  lock.attachLongPressStop(dooractivityOpen);
  lock.setPressTicks(250);
  door.setPressTicks(250);
  Homie.setLedPin(LED_BUILTIN, LOW);
  ctdoor.advertise("cmd").settable(cmdHandler);
  ctdoor.advertise("door").settable(fakeHandler);
  ctdoor.advertise("lock").settable(fakeHandler);
  Homie.setup();
  ArduinoOTA.setHostname(Homie.getConfiguration().deviceId);
  ArduinoOTA.begin();
}

void loop() {
  Homie.loop();
  ArduinoOTA.handle();
  door.tick();
  lock.tick();
  fixWiFi();
}