#include "Firebase_Arduino_WiFiNINA.h"
#include <DFRobot_PH.h>
#include <EEPROM.h>
#include <OneWire.h>
#include <WiFiNINA.h>

#define DATABASE_URL "aquaponics-monitoring-d2616-default-rtdb.firebaseio.com" //<databaseName>.firebaseio.com or <databaseName>.<region>.firebasedatabase.app
#define DATABASE_SECRET "In0NSnndHfSemzmeMMd8uYGaLFZAsK6cKexcHJFV"
//ENTER THE WIFI SSID AND PASSWORD OF THE NETWORK YOU ARE CONNECTING THE ARDUINO TO HERE
#define WIFI_SSID ""
#define WIFI_PASSWORD ""

#define SensorPin A0 
#define PH_PIN A3

float voltage,phValue,temperature = 25;
DFRobot_PH ph;
float moistureValue = 0; 
int liquidLevelValue = 0;
int lightValue = 0;

int DS18S20_Pin = 2; //DS18S20 (temp sensor) Signal pin on digital 2
//Temperature chip i/o
OneWire ds(DS18S20_Pin);  // on digital pin 2

String path = "/0001";
String jsonData = "";
String jsonDataHistory = "";


//Define Firebase data object
FirebaseData fbdo;

void setup()
{

  //Serial.begin(115200);
  Serial.begin(9600);
  delay(100);
  Serial.println();

  Serial.print("Connecting to Wi-Fi");
  int status = WL_IDLE_STATUS;
  while (status != WL_CONNECTED)
  {
    status = WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
    Serial.print(".");
    delay(100);
  }
  Serial.println();
  Serial.print("Connected with IP: ");
  Serial.println(WiFi.localIP());
  Serial.println();

  //Provide the authentication data
  Firebase.begin(DATABASE_URL, DATABASE_SECRET, WIFI_SSID, WIFI_PASSWORD);
  Firebase.reconnectWiFi(true);
  pinMode(5,INPUT);

/*  //push empty data
  jsonData = "{\"Light\":" + String(lightValue) + ", \"Liquid Level\":" + liquidLevelValue + ", \"Soil Moisture\":" + moistureValue + "}";
  if (Firebase.pushJSON(fbdo, path + "/Current Data", jsonData))
  {
    Serial.println("ok");
    Serial.println("path: " + fbdo.dataPath());
    //Serial.print("push name: ");
    //Serial.println(fbdo.pushName());
  }
  else
  {
    Serial.println("error, " + fbdo.errorReason());
  }*/
  ph.begin();
}

void loop()
{

  //read Soil Moisture
  //moistureValue = moistureValue + analogRead(SensorPin);
  moistureValue = analogRead(SensorPin);

  //read Liquid Level
  liquidLevelValue = digitalRead(5);

  //read Light Level
  lightValue = analogRead(A1);

  //read temperature and convert to fahrenheit
  float tempCelsius = getTemp();
  float tempFahrenheit = (tempCelsius*9/5)+32;

  static unsigned long timepoint = millis();
  if(millis()-timepoint>1000U){                  //time interval: 1s
        timepoint = millis();
        voltage = analogRead(PH_PIN)/1024.0*5000;
        phValue = ph.readPH(voltage,temperature);  // convert voltage to pH with temperature compensation
        Serial.print("pH:");
        Serial.println(phValue,2);
    }
    ph.calibration(voltage,temperature);   

  //print values to console
  Serial.print("Soil Moisture: ");
  Serial.println(moistureValue);
  Serial.print("Light Level: ");
  Serial.println(lightValue);
  Serial.print("Liquid Level: ");
  Serial.println(liquidLevelValue);
  Serial.print("pH:");
  Serial.println(phValue);
  //Serial.print("Temperature in Celsius: ");
  //Serial.println(tempCelsius);
  Serial.print("Temperature in Fahrenheit: ");
  Serial.println(tempFahrenheit);
  Serial.println("");
  Serial.println("");


  //jsonData = "{\"light\": {\"value: "+String(lightValue)+"\"}, \"liquidLevel\": {\"value\": "+String(liquidLevelValue)+"}, \"pH\": { \"value\": "+String(phValue)+"}, \"soilMoisture\": { \"value\": "+String(moistureValue)+"}, \"temperature\": { \"value\": "+String(tempFahrenheit)+"}";
  //jsonData = "{\"Light\":" + String(lightValue) + ", \"Liquid Level\":" + liquidLevelValue + ", \"Soil Moisture\":" + moistureValue + ", \"pH\":" + String(phValue) + "}";
/*  if (Firebase.setJSON(fbdo, path, jsonData))
  {
    Serial.println("ok");
    Serial.println("path: " + fbdo.dataPath());
    //Serial.print("push name: ");
    //Serial.println(fbdo.pushName());
  }
  else
  {
    Serial.println("error, " + fbdo.errorReason());
  }*/


  if (Firebase.setFloat(fbdo, "/0001/light/value", lightValue)){
  if (fbdo.dataType() == "float")
    Serial.println(fbdo.floatData());
} else {
  //Failed, then print out the error detail
    Serial.println(fbdo.errorReason());
}
  if (Firebase.setFloat(fbdo, "/0001/liquidLevel/value", liquidLevelValue)){
  if (fbdo.dataType() == "float")
    Serial.println(fbdo.floatData());
} else {
  //Failed, then print out the error detail
    Serial.println(fbdo.errorReason());
}
  if (Firebase.setFloat(fbdo, "/0001/pH/value", phValue)){
  if (fbdo.dataType() == "float")
    Serial.println(fbdo.floatData());
} else {
  //Failed, then print out the error detail
    Serial.println(fbdo.errorReason());
}
  if (Firebase.setFloat(fbdo, "/0001/soilMoisture/value", moistureValue)){
  if (fbdo.dataType() == "float")
    Serial.println(fbdo.floatData());
} else {
  //Failed, then print out the error detail
    Serial.println(fbdo.errorReason());
}
  if (Firebase.setFloat(fbdo, "/0001/temperature/value", tempFahrenheit)){
  if (fbdo.dataType() == "float")
    Serial.println(fbdo.floatData());
} else {
  //Failed, then print out the error detail
    Serial.println(fbdo.errorReason());
}  

  int currentTime=WiFi.getTime();
  currentTime=currentTime/10;
  currentTime=currentTime*10;
  jsonData = "{\"light\":" + String(lightValue) + ", \"liquidLevel\":" + String(liquidLevelValue) + ", \"pH\": " + String(phValue) + ", \"soilMoisture\":" + String(moistureValue) + ", \"temperature\":" + String(tempFahrenheit) + "}";
  if (Firebase.setJSON(fbdo, path+"/historical data/"+String(currentTime), jsonData))
  {
    Serial.println("ok");
    Serial.println("path: " + fbdo.dataPath());
    //Serial.print("push name: ");
    //Serial.println(fbdo.pushName());
  }
  else
  {
    Serial.println("error, " + fbdo.errorReason());
  }

  delay(10000);
}

float getTemp(){
  //returns the temperature from one DS18S20 in DEG Celsius
  //from DFRobot wiki page on the DS18B20 sensor

  byte data[12];
  byte addr[8];

  if ( !ds.search(addr)) {
      //no more sensors on chain, reset search
      ds.reset_search();
      return -1000;
  }

  if ( OneWire::crc8( addr, 7) != addr[7]) {
      Serial.println("CRC is not valid!");
      return -1000;
  }

  if ( addr[0] != 0x10 && addr[0] != 0x28) {
      Serial.print("Device is not recognized");
      return -1000;
  }

  ds.reset();
  ds.select(addr);
  ds.write(0x44,1); // start conversion, with parasite power on at the end

  byte present = ds.reset();
  ds.select(addr);
  ds.write(0xBE); // Read Scratchpad


  for (int i = 0; i < 9; i++) { // we need 9 bytes
    data[i] = ds.read();
  }

  ds.reset_search();

  byte MSB = data[1];
  byte LSB = data[0];

  float tempRead = ((MSB << 8) | LSB); //using two's compliment
  float TemperatureSum = tempRead / 16;

  return TemperatureSum;

}