// psswd's into include/secret.h
// others settings in main.h

#include "main.h"

using namespace std;

DHT sensors[SENSORS_NUMBER] = {DHT(4, DHT22), DHT(5, DHT22), DHT(18, DHT22), DHT(19, DHT22), DHT(21, DHT22)};
float temp[SENSORS_NUMBER];
float hum[SENSORS_NUMBER];

WiFiClient WifiClient;
PubSubClient MqttClient(WifiClient);
WiFiUDP NtpUDP;
NTPClient TimeClient(NtpUDP, "europe.pool.ntp.org", 0, 60000);
Pangodream_18650_CL Battery(ADC_PIN, CONV_FACTOR, READS);

RTC_DS3231 rtc;
//---------------- Réveil --------------------//
int mesure_freq = 600; // temps entre deux réveils en secondes

//--------------------  FONCTIONS  --------------------//

//--------------  Connexion MQTT  --------------//

void setupMQTT(const char *address, int port)
{
  MqttClient.setServer(address, port);
}

void setupWIFI(const char *wifi_name, const char *password)
{
  Serial.println('\n');

  WiFi.begin(wifi_name, password);
  Serial.print("Connecting to ");
  Serial.print(wifi_name);

  while ((WiFi.status() != WL_CONNECTED) && (millis() <= 60000))
  {
    Serial.println("Nouvelle tentative de connexion...");
    delay(500);
    Serial.print('.');
  }
  Serial.println('\n');
  Serial.println("Connection established!");
  Serial.print("IP address:\t");
  Serial.println(WiFi.localIP());
}

void reconnect(void)
{
  Serial.println("Connecting to MQTT Broker...");
  while (!MqttClient.connected())
  {
    Serial.print(".");
    if (MqttClient.connect(ESPNAME, MQTT_USER, MQTT_MDP))
    {
      Serial.println("Connected.");
    }
  }
}

//--------------  Initialisation et lecture des capteurs  --------------//

void initSensors(DHT *sensors, int number)
{
  int i;
  for (i = 0; i < number; i++)
  {
    sensors[i].begin();
  }
}

void readSensors(DHT sensors[], float temp[], float hum[], int number)
{
  int i;
  for (i = 0; i < number; i++)
  {
    *(temp + i) = sensors[i].readTemperature();
    *(hum + i) = sensors[i].readHumidity();
  }
}

//--------------------  Sleep de l'ESP  --------------------//
/*
void sleep()
{
  esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * US_TO_S_FACTOR);
  esp_deep_sleep_start();
}

//exemple d'une triple utilisation de valeur pour une fonction utilise pour la date
std::tuple<int, int, int> getDate()
{
  time_t rawtime = TimeClient.getEpochTime();
  struct tm *ti;
  ti = localtime(&rawtime);
  int year = ti->tm_year + 1900;
  int month = (ti->tm_mon + 1) < 10 ? 0 + (ti->tm_mon + 1) : (ti->tm_mon + 1);
  int day = (ti->tm_mday) < 10 ? 0 + (ti->tm_mday) : (ti->tm_mday);

  return std::make_tuple(year, month, day);
}
*/

//--------------------  Programmation du réveil de l'alimentation  --------------------//

void wakeup(){
   // initializing the rtc
    if(!rtc.begin()) {
        Serial.println("Couldn't find RTC!");
        Serial.flush();
        while (1) delay(10);
    }

    if(rtc.lostPower()) {
        // this will adjust to the date and time at compilation
        rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
    }

    //we don't need the 32K Pin, so disable it
    rtc.disable32K();

    // set alarm 1, 2 flag to false (so alarm 1, 2 didn't happen so far)
    // if not done, this easily leads to problems, as both register aren't reset on reboot/recompile
    rtc.clearAlarm(1);
    rtc.clearAlarm(2);

    // stop oscillating signals at SQW Pin
    // otherwise setAlarm1 will fail
    rtc.writeSqwPinMode(DS3231_OFF);

     // turn off alarm 2 (in case it isn't off already)
    // again, this isn't done at reboot, so a previously set alarm could easily go overlooked
    rtc.disableAlarm(2);

  // schedule an alarm 10 seconds in the future
    if(!rtc.setAlarm1(
            rtc.now() + TimeSpan(mesure_freq),
            DS3231_A1_Second // this mode triggers the alarm when the seconds match. See Doxygen for other options
    )) {
        Serial.println("Error, alarm wasn't set!");
    }else {
        Serial.println("Alarm will happen in 10 seconds!");
    }

}

//--------------------  Création de trames  --------------------//

void writeMessage(char *txt, float *temp, float *hum, int number)
{
  int chargelvl = Battery.getBatteryChargeLevel();
  switch (number)
  {
  case 1:
    sprintf(txt, "|%s|%0.2f|%0.2f", CLUSTER, temp[0], hum[0]);
    break;
  case 2:
    sprintf(txt, "|%s|%0.2f %0.2f|%0.2f %0.2f", CLUSTER, temp[0], temp[1], hum[0], hum[1]);
    break;
  case 3:
    sprintf(txt, "|%s|%0.2f %0.2f %0.2f|%0.2f %0.2f %0.2f", CLUSTER, temp[0], temp[1], temp[2], hum[0], hum[1], hum[2]);
    break;
  case 4:
    sprintf(txt, "|%s|%0.2f %0.2f %0.2f %0.2f|%0.2f %0.2f %0.2f %0.2f", CLUSTER, temp[0], temp[1], temp[2], temp[3], hum[0], hum[1], hum[2], hum[3]);
    break;
  case 5:
    sprintf(txt, "|%s|%0.2f %0.2f %0.2f %0.2f %0.2f|%0.2f %0.2f %0.2f %0.2f %0.2f|%d", CLUSTER, temp[0], temp[1], temp[2], temp[3], temp[4], hum[0], hum[1], hum[2], hum[3], hum[4], chargelvl);
    break;
  case 6:
    sprintf(txt, "|%s|%0.2f %0.2f %0.2f %0.2f %0.2f %0.2f|%0.2f %0.2f %0.2f %0.2f %0.2f %0.2f", CLUSTER, temp[0], temp[1], temp[2], temp[3], temp[4], temp[5], hum[0], hum[1], hum[2], hum[3], hum[4], hum[5]);
    break;
  default:
    Serial.println("Erreur, temp et hum sont trop longs : trop de capteurs");
    break;
  }
}

//--------------------  Initialisation  --------------------//

void setup()
{
  Serial.begin(9600);
  setupWIFI(SSID, SSID_PWD);
  setupMQTT(MQTT_ADDRESS, MQTT_PORT);
  initSensors(sensors, SENSORS_NUMBER);
  TimeClient.begin();
  delay(2000);
}

//--------------------  Boucle pringicipale  --------------------//

void loop()
{
  int year, month, day;
  int lenght;
  char time[30];
  char date[30];
  char msg[70];

  MqttClient.loop();
  if (!MqttClient.connected())
  {
    reconnect();
  }

  readSensors(sensors, temp, hum, SENSORS_NUMBER);
  writeMessage(msg, temp, hum, SENSORS_NUMBER);

  Serial.print("une trame de data : ");
  Serial.println(msg);

  TimeClient.update();
  TimeClient.getFormattedTime().toCharArray(time, 30);

  tie(year, month, day) = getDate();
  lenght = sprintf(date, "%d-%d-%d ", year, month, day);
  sprintf(date + lenght, time);
  sprintf(date + strlen(date), msg);
  MqttClient.publish(TOPIC, date);
  
  delay(2000);
  Serial.println("Extinction de l'ESP ! ");
  wakeup();

}