/*
  Environment monitor node AttinyZino
  Belkacem BENADDA 30/10/2022 :o{)
*/
#include <Wire.h>
#include "Adafruit_SGP30.h"
#include "Adafruit_SHT4x.h"


//Start Temporisation Class
class Tempo{
 private: 
  unsigned long current_T;
  unsigned long waiting_time;
  
  public: 
    Tempo(unsigned long T){
      current_T = millis();
      waiting_time =T;
    }

    void SetWaitingtime(unsigned long T){
      waiting_time =T;
    }
    
    bool wait_ms(){
      unsigned long tmp_T = millis()- this->current_T;
      bool waiting_finished = false;
        if(tmp_T >= waiting_time){
          current_T = millis();
          waiting_finished = true;
        }
        return  waiting_finished;
    }
};
//End Temporisation Class

//Current Class
class ACS712 {
  private:
    uint8_t Pin;
    Tempo *TempoCurrent;
    uint8_t I;
  public:
    ACS712 (uint8_t P){
      Pin = P;
      TempoCurrent = new Tempo(5);
    }

    ~ACS712 (){
      delete  TempoCurrent;
    }
    
    uint8_t Current(){
      if(TempoCurrent->wait_ms())
        {
          I = analogRead(Pin);
          Serial.print("Current : ");
          Serial.println(I);
          Serial1.print("AT+CIPSENDBUF=3");
          Serial1.println(0x01);
          Serial1.println(Pin);
          Serial1.println(I);
          while(!Serial1.available()){}
          Serial1.readString();
        }
      return I;
    }

    void SetSamplingTime(unsigned long Period){
      TempoCurrent->SetWaitingtime(Period);
    }
};
//End Current
//Moisture Class
class Moisture {
  private:
    uint8_t Pin;
    Tempo *TempoMoisture;
    const uint8_t MaxMoisture  =732;
    const uint8_t interval = 61;
    uint8_t Moisture = 0;

  public:
    Moisture (uint8_t P){
      Pin = P;
      TempoMoisture = new Tempo(1000);
    }

    ~Moisture (){
      delete  TempoMoisture;
    }
    
    uint8_t SoilMoisture(){
      if(TempoMoisture->wait_ms())
        {
          Moisture = analogRead(Pin);
          Serial.print("Moisture : ");
          Serial.println(Moisture);
          Serial1.print("AT+CIPSENDBUF=3");
          Serial1.println(0x02);
          Serial1.println(Pin);
          Serial1.println(Moisture);
          while(!Serial1.available()){}
          Serial1.readString();
        }
      return Moisture;
    }

    void SetSamplingTime(unsigned long Period){
      TempoMoisture->SetWaitingtime(Period);
    }
};
//End Moisture

//Start class Humidity Temperature

class Humidity_Temperature{
  private:
  Adafruit_SHT4x Hum_Temp = Adafruit_SHT4x();
  sensors_event_t Humidity, Temperature;  
  Tempo *TempoHT;
  
  public:
  Humidity_Temperature(){
    if (! Hum_Temp.begin()) Serial.println("Couldn't find Humidity_Temperature Sensor"); else{
    TempoHT = new Tempo(1300);
    Serial.println("Found Humidity_Temperature sensor");
    Serial.print("Serial number 0x");
    Serial.println(Hum_Temp.readSerial(), HEX);
    Hum_Temp.setPrecision(SHT4X_HIGH_PRECISION);
    switch (Hum_Temp.getPrecision()) {
     case SHT4X_HIGH_PRECISION: 
       Serial.println("High precision");
       break;
     case SHT4X_MED_PRECISION: 
       Serial.println("Med precision");
       break;
     case SHT4X_LOW_PRECISION: 
       Serial.println("Low precision");
       break;
  }
  
  Hum_Temp.setHeater(SHT4X_NO_HEATER);
  switch (Hum_Temp.getHeater()) {
     case SHT4X_NO_HEATER: 
       Serial.println("No heater");
       break;
     case SHT4X_HIGH_HEATER_1S: 
       Serial.println("High heat for 1 second");
       break;
     case SHT4X_HIGH_HEATER_100MS: 
       Serial.println("High heat for 0.1 second");
       break;
     case SHT4X_MED_HEATER_1S: 
       Serial.println("Medium heat for 1 second");
       break;
     case SHT4X_MED_HEATER_100MS: 
       Serial.println("Medium heat for 0.1 second");
       break;
     case SHT4X_LOW_HEATER_1S: 
       Serial.println("Low heat for 1 second");
       break;
     case SHT4X_LOW_HEATER_100MS: 
       Serial.println("Low heat for 0.1 second");
       break;
  }
  }  
  }

  ~Humidity_Temperature(){
    delete TempoHT; 
  }

  void SetSamplingTime(unsigned long Period){
      TempoHT->SetWaitingtime(Period);
    }
  void readHT(){
    if(TempoHT->wait_ms()){
      Hum_Temp.getEvent(&Humidity, &Temperature);
      Serial.print("Ambiant Temperature :");
      Serial.print(Temperature.temperature);
      Serial.println(" C");

      Serial.print("Ambiant Humidity :");
      Serial.print(Humidity.relative_humidity);
      Serial.println(" %RH");
          
          Serial1.print("AT+CIPSENDBUF=4");
          Serial1.println(0x03);
          Serial1.println(0x40);
          Serial1.println(Temperature.temperature);
          Serial1.println(Humidity.relative_humidity);
          while(!Serial1.available()){}
          Serial1.readString();
        
    }    
  }
};
//End Humidity Temperature

//Class eCO2
class eCO2{
  private:
  Tempo *TempoeCO2;
  Adafruit_SGP30 sgp;
  uint32_t getAbsoluteHumidity(float temperature, float humidity) {
    const float absoluteHumidity = 216.7f * ((humidity / 100.0f) * 6.112f * exp((17.62f * temperature) / (243.12f + temperature)) / (273.15f + temperature)); // [g/m^3]
    const uint32_t absoluteHumidityScaled = static_cast<uint32_t>(1000.0f * absoluteHumidity); // [mg/m^3]
    return absoluteHumidityScaled;
  } 
 
  public:
  eCO2(){
    TempoeCO2 = new Tempo(2300);
    if (! sgp.begin()){
    Serial.println("Sensor not found :(");
  }else{
  Serial.print("Found SGP30 serial #");
  Serial.print(sgp.serialnumber[0], HEX);
  Serial.print(sgp.serialnumber[1], HEX);
  Serial.println(sgp.serialnumber[2], HEX);
  }
  }
  ~eCO2(){
    delete TempoeCO2;
  }

  void SetSamplingTime(unsigned long Period){
      TempoeCO2->SetWaitingtime(Period);
    }

  void readECO2(){
    
    if(TempoeCO2->wait_ms()){ 
    if (! sgp.IAQmeasure()) {
    Serial.println("eCO2 Measurement failed");
    
  } else{
    Serial.print("TVOC "); Serial.print(sgp.TVOC); Serial.print(" ppb\t");
    Serial.print("eCO2 "); Serial.print(sgp.eCO2); Serial.println(" ppm");

          Serial1.print("AT+CIPSENDBUF=4");
          Serial1.println(0x04);
          Serial1.println(0x58);
          Serial1.println(sgp.TVOC);
          Serial1.println(sgp.eCO2);
          while(!Serial1.available()){}
          Serial1.readString();
  }
  
  if (! sgp.IAQmeasureRaw()) {
    Serial.println("eCO2 Raw Measurement failed");
  }else{
    Serial.print("Raw H2 "); Serial.print(sgp.rawH2); Serial.print(" \t");
    Serial.print("Raw Ethanol "); Serial.print(sgp.rawEthanol); Serial.println("");
          Serial1.print("AT+CIPSENDBUF=4");
          Serial1.println(0x05);
          Serial1.println(0x58);
          Serial1.println(sgp.rawH2);
          Serial1.println(sgp.rawEthanol);
          while(!Serial1.available()){}
          Serial1.readString();
  }
  
    uint16_t TVOC_base, eCO2_base;
    if (! sgp.getIAQBaseline(&eCO2_base, &TVOC_base)) {
      Serial.println("Failed to get baseline readings");
    }else{
    Serial.print("****Baseline values: eCO2: 0x"); Serial.print(eCO2_base, HEX);
    Serial.print(" & TVOC: 0x"); Serial.println(TVOC_base, HEX);
          Serial1.print("AT+CIPSENDBUF=6");
          Serial1.println(0x06);
          Serial1.println(0x58);
          Serial1.println(eCO2_base);
          Serial1.println(TVOC_base);
          while(!Serial1.available()){}
          Serial1.readString();
  }
    }
  }
};
//End eCO2
//Object creation
Moisture *M1; 
Humidity_Temperature *HT1;
eCO2 *eCO2Sense;
ACS712 *Light;
ACS712 *Pump;
void setup() {
  Serial.begin(9600);
  
  Serial1.begin(115200);
  Serial1.println("AT");
  while(!Serial1.available()){}
  Serial1.readString();
  
  Serial1.println("AT+CWMODE_CUR=1");
  while(!Serial1.available()){}
  Serial1.readString();

  Serial1.println("AT+CWDHCP_CUR=1,1");
  while(!Serial1.available()){}
  Serial1.readString();

  Serial1.println("AT+CWJAP_CUR=\"bkbenAP\",\"Wizfi360\"");
  while(!Serial1.available()){}
  Serial1.readString();

  Serial1.println("AT+CIPSTART=”TCP”,”192.168.1.101”,4500");
  while(!Serial1.available()){}
  Serial1.readString();

  Light = new ACS712(A1);
  Pump = new ACS712(A2);
  M1 = new Moisture(A0);
  HT1 = new Humidity_Temperature();
  eCO2Sense = new eCO2();
}



void loop() {
  uint8_t tmpM = M1->SoilMoisture();
  uint8_t tmpI1 = Light->Current();
  uint8_t tmpI2 = Pump->Current();
  HT1->readHT();
  eCO2Sense->readECO2();
  }
