#include "DHTesp.h"

#define uS_TO_S_FACTOR 1000000  /* Conversion factor for micro seconds to seconds */

struct Measure{
  enum class Type{TEMPERATURE, MOISTURE, HUMIDITY};
  
  Type type;
  float value;
};

struct Config {
  struct{
    uint32_t dht = 15;
    uint32_t moisture = 34;
  } pin;

  struct{
    uint32_t seconds = 3600;
  } wakeup;
};

Measure readMoisture (const Config& cfg){
  Measure measure;
  measure.type = Measure::Type::MOISTURE;
  measure.value = ((float) analogRead(cfg.pin.moisture))/4096 * 100;

  return measure;
}

void readOutDHT(DHTesp& dhtSensor){
  int tries = 10;
  do{
    (void) dhtSensor.getTempAndHumidity();
    if(dhtSensor.getStatus() != DHTesp::ERROR_NONE) {
      delay(250);
    }
    --tries;
  }while(tries > 0);
}

Measure getTemperature(DHTesp& dhtSensor) {
  Measure measure;
  measure.type = Measure::Type::TEMPERATURE;
  measure.value = dhtSensor.getTemperature();

  return measure;
}

Measure getHumidity(DHTesp& dhtSensor) {
  Measure measure;
  measure.type = Measure::Type::HUMIDITY;
  measure.value = dhtSensor.getHumidity();

  return measure;
}

const char* to_str(Measure::Type type) {
  switch(type){
    case Measure::Type::TEMPERATURE:
      return "Temperature";
    case Measure::Type::MOISTURE:
      return "Moisture";
    case Measure::Type::HUMIDITY:
      return "Humidity";
    default:
      return "?";
  }
}

const char* sufix(Measure::Type type) {
  switch(type){
    case Measure::Type::TEMPERATURE:
      return "*c";
    case Measure::Type::MOISTURE:
      return "%";
    case Measure::Type::HUMIDITY:
      return "%";
    default:
      return "#";
  }
}

void printMeasure(const Measure& measure){
  Serial.println(String(to_str(measure.type)) + ":" + String(measure.value) + String(sufix(measure.type)));
}

String formatJson(Measure measures[3]) {
  String response = "{\"data\":[";

  for(int i = 0; i < 3; ++i) {
    response += "{\"type\": \"";
    response += to_str(measures[i].type);
    response += "\", \"value\": \"";
    response += String(measures[i].value);
    response += "\"}";

    if(i != 2)
      response += ",";
  }

  response += "]}";
  return response;
}

void my_main() {
  Config cfg;
  DHTesp dhtSensor;

  Serial.begin(115200);
  dhtSensor.setup(cfg.pin.dht, DHTesp::DHT22);

  readOutDHT(dhtSensor);

  Measure measures[3];
  measures[0] = readMoisture(cfg);
  measures[1] = getTemperature(dhtSensor);
  measures[2] = getHumidity(dhtSensor);

  String json = formatJson(measures);
  Serial.println(json);
  
  esp_sleep_enable_timer_wakeup(cfg.wakeup.seconds * uS_TO_S_FACTOR);
  Serial.flush(); 
  delay(1000);
  esp_deep_sleep_start();
}

void setup() { my_main(); }

void loop() { }
esp:VIN
esp:GND.2
esp:D13
esp:D12
esp:D14
esp:D27
esp:D26
esp:D25
esp:D33
esp:D32
esp:D35
esp:D34
esp:VN
esp:VP
esp:EN
esp:3V3
esp:GND.1
esp:D15
esp:D2
esp:D4
esp:RX2
esp:TX2
esp:D5
esp:D18
esp:D19
esp:D21
esp:RX0
esp:TX0
esp:D22
esp:D23
dht1:VCC
dht1:SDA
dht1:NC
dht1:GND
pot1:VCC
pot1:SIG
pot1:GND