
// pre compiletime config
#define SPIFFS_DBG
#define SPIFFS_USE_MAGIC

#define FIRMWARE_NAME "WiFiPCController"
#define VERSION "1.0.0"
#define COPYRIGHT "Flo Kra"

// default values, can later be overridden via configuration
#define DEVICE_NAME "WiFiPCController-1"
#define MQTT_SERVER "mqtt.lan"
#define MQTT_PORT 1883
#define MQTT_TOPIC_IN "Test/PCController1/cmd"
#define MQTT_TOPIC_OUT "Test/PCController1/status"

#define CLEARCONF_TOKEN "TUES"

#define PIN_OUT_POWERSW 5
#define PIN_OUT_RESETSW 4
#define PIN_IN_PWRLED 14

// default logic levels
#define OUT_POWERSW_ONSTATE HIGH
#define OUT_RESETSW_ONSTATE HIGH
#define IN_PWRLED_ONSTATE LOW

#include "PersWiFiManager.h"
#include <ArduinoJson.h>
#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <ESP8266WebServer.h>
#include <ESP8266mDNS.h>
#include <ESP8266HTTPUpdateServer.h>
#include "PubSubClient.h"
#include <DNSServer.h>
#include <FS.h>

boolean serialdebug = true;
boolean mqttdebug = true;

// config variables - do not change here!
// confWeb
char deviceName[31];
char http_user[31];
char http_pass[31];
boolean http_user_auth = false;
char http_token[31];
char http_user1[31];
char http_pass1[31];
char http_user2[31];
char http_pass2[31];

// confMqtt
char mqtt_server[41];
int mqtt_port = MQTT_PORT;
char mqtt_user[31];
char mqtt_pass[31];
char mqtt_topic_in[51];
char mqtt_topic_out[51];
char mqtt_willTopic[51];
int mqtt_willQos = 2;
boolean mqtt_willRetain = false;
char mqtt_willMsg[31];
char mqtt_connMsg[31];
boolean mqtt_outRetain = false;

char mqtt_topic_in_pcpwr[64];
char mqtt_topic_in_pcpwrh[64];
char mqtt_topic_in_pcrst[64];
char mqtt_topic_in_pconsleep[64];

// global variables
byte mqttMode = 0;
unsigned long mqttLastReconnectAttempt = 0;
int mqttReconnectAttempts = 0;
int mqttReconnects = 0;
boolean mqttConnected = false;
unsigned long mqttLastHeartbeat;
boolean mqttInTopicSubscribed = false;
char cmdPayload[101]; // buffer for commands
boolean cmdInQueue = false; // command is queued and will be processed next loop() run

bool saveConfigWebToFlash = false;
bool saveConfigMqttToFlash = false;
//bool saveConfigHwToFlash = false;


char tmp_topic_pub[51];

boolean pwrSwitchStateOn;
unsigned long pwrSwitchOnAt;
unsigned int pwrSwitchOffAfter;

boolean resSwitchStateOn;
unsigned long resSwitchOnAt;
unsigned int resSwitchOffAfter;

boolean in_pwrled_lastState = LOW;
boolean in_pwrled_currState = LOW;
unsigned long in_pwrled_millis = 0;
unsigned long PC_standby_pending_millis = 0;
int PCstate = 0;
int PCstate_lastPublished = 0;

unsigned int sysUptime_days = 0;
unsigned int sysUptime_hours = 0;
unsigned int sysUptime_mins = 0;
char uptimeStr[15];

WiFiClient espClient;

void mqttCallback(char* topic, byte* payload, unsigned int length);
PubSubClient mqttclient(espClient);

ESP8266WebServer httpServer(80);
DNSServer dnsServer;
PersWiFiManager persWM(httpServer, dnsServer);

ESP8266HTTPUpdateServer httpUpdater;


void setup() {
  Serial.begin(115200);
  delay(500);
  Serial.println();
  Serial.print(FIRMWARE_NAME);
  Serial.print(" v");
  Serial.print(VERSION);
  Serial.println(COPYRIGHT);
  Serial.println("starting...");

  pinMode(PIN_OUT_POWERSW, OUTPUT);
  digitalWrite(PIN_OUT_POWERSW, !OUT_POWERSW_ONSTATE);
  pinMode(PIN_OUT_RESETSW, OUTPUT);
  digitalWrite(PIN_OUT_RESETSW, !OUT_RESETSW_ONSTATE);

  pinMode(PIN_IN_PWRLED, INPUT_PULLUP);
  //delay(50);
  //in_pwrled_lastState=digitalRead(PIN_IN_PWRLED);

  strlcpy(deviceName, DEVICE_NAME, 31);
  strlcpy(mqtt_server, MQTT_SERVER, 41);
  strlcpy(mqtt_topic_in, MQTT_TOPIC_IN, 51);
  strlcpy(mqtt_topic_out, MQTT_TOPIC_OUT, 51);
  Serial.println("default config values loaded..");


  Serial.println("Mounting FS...");
  if (!SPIFFS.begin()) {
    Serial.println("Failed to mount file system");
    return;
  }


  //SPIFFS.format();
  //Serial.print("Format SPIFFS complete.");

  if (!SPIFFS.exists("/formatted")) {
    Serial.println("Please wait 30 secs for SPIFFS to be formatted");
    SPIFFS.format();
    Serial.println("Spiffs formatted");

    File f = SPIFFS.open("/formatted", "w");
    if (!f) {
      Serial.println("file open failed");
    } else {
      f.println("Format Complete");
    }
    f.close();
  } else {
    Serial.println("SPIFFS is formatted. Moving along...");
  }

  Serial.println("files in SPIFFS:");
  Dir dir = SPIFFS.openDir("/");
  while (dir.next()) {
    Serial.print(dir.fileName());
    File f = dir.openFile("r");
    Serial.print("  ");
    Serial.println(f.size());
    f.close();
  }
  Serial.println("---");


  // load config from SPIFFS if files exist
  if (!loadConfigWeb()) {
    Serial.println("Failed to load confWeb.json");
  } else {
    Serial.println("confWeb.json loaded");
  }

  if (!loadConfigMqtt()) {
    Serial.println("Failed to load confWeb.json");
  } else {
    Serial.println("confWeb.json loaded");
  }

  delay(500);

  //optional code handlers to run everytime wifi is connected...
  persWM.onConnect([]() {
    Serial.print("wifi connected to ");
    Serial.print(WiFi.SSID());
    Serial.print(", IP: ");
    Serial.println(WiFi.localIP());
  });
  //...or AP mode is started
  persWM.onAp([]() {
    Serial.print("AP MODE: ");
    Serial.println(persWM.getApSsid());
  });

  //sets network name for AP mode
  persWM.setApCredentials(DEVICE_NAME);
  //persWM.setApCredentials(DEVICE_NAME, "password"); optional password

  //make connecting/disconnecting non-blocking
  persWM.setConnectNonBlock(true);

  //in non-blocking mode, program will continue past this point without waiting
  persWM.begin();
  delay(500);

  httpServerInit();

  mqttPrepareConnection();
  mqttClientInit();

  buildUptimeString();

  Serial.println("setup complete.");
  delay(1000);
} //void setup



void loop() {
  checkMillis();

  persWM.handleWiFi(); //in non-blocking mode, handleWiFi must be called in the main loop

  yield();

  dnsServer.processNextRequest();

  httpServer.handleClient();

  yield();
  mqttHandleConnection();
  yield();
  evalCmd();

  PC_pwrSwitchOffAfterTimeout();
  PC_resSwitchOffAfterTimeout();

  if (Serial.available()) {
    serialEvent();
    yield();
  }

} //void loop
