#define BLYNK_PRINT Serial
#define BLYNK_TEMPLATE_ID "YOUR_ID"
#define BLYNK_TEMPLATE_NAME "Hydroponic Home"
#define BLYNK_AUTH_TOKEN "YOUR_TOKEN"

#include <Servo.h>
#include <ESP8266WiFi.h>
#include <BlynkSimpleEsp8266.h>

Servo phServo;

char ssid[] = "MAKER101IO";
char pass[] = "maker101.io";

#define PH_PIN A0
#define LVL_PIN 15
#define LVL_PWR 4
#define WATER_PUMP 12
#define SERVO_PIN 2

#define TIME_RANGE 60000
#define PUMP_TIME 3000

int pos = 170;

/*--------- pH Sensor ---------*/
unsigned long int avgValue;
float b;
int buf[10], temp;

int f;
float val;
char buff2[10];
String valueString = "";
String Value = "";

void PH_Value(){
  for (pos = 170; pos >= 10; pos -= 1) { // goes from 170 degrees to 10 degrees
    // in steps of 1 degree
    phServo.write(pos);              // tell servo to go to position in variable 'pos'
    delay(10);                       // waits 15ms for the servo to reach the position
  }
  delay(2000);
  for(int i=0; i<10; i++){
    buf[i] = analogRead(PH_PIN);
    delay(10);
  }

  for(int i=0; i<9; i++){
    for(int j=i+1; j<10; j++){
      if(buf[i] > buf[j]){
        temp = buf[i];
        buf[i] = buf[j];
        buf[j] = temp;
      }
    }
  }
  avgValue=0;
  for(int i=2; i<8; i++)
  avgValue+=buf[i];
  float phValue = (float) avgValue * 3.3/1024/6;
  phValue = 3.5 * phValue;
  Value = dtostrf(phValue, 4, 2, buff2);
  Serial.print("pH Value: ");
  Serial.print(Value);
  Serial.println("");
  valueString = "";
  delay(500);

  Blynk.virtualWrite(V1, Value);
  delay(2000);

  for (pos = 10; pos <= 170; pos += 1) {    
    phServo.write(pos);
    delay(10);
  }
}

/*--------- Water Level Sensor ---------*/
void readWaterLevel(){
  digitalWrite(LVL_PWR, HIGH);
  delay(1000);
  int waterLevelVal = digitalRead(LVL_PIN);
  if(waterLevelVal == HIGH){
    Serial.print("Water Level: ");
    Serial.print(waterLevelVal);
    Blynk.virtualWrite(V2, "Water Level Good");
  }
  else {
    Blynk.virtualWrite(V2, "Need to Add Some Water");
  }
  delay(2000);
  digitalWrite(LVL_PWR, LOW);
}

/*--------- Water Pump ---------*/
void runWaterPump(){
  digitalWrite(WATER_PUMP, HIGH);
  Blynk.virtualWrite(V3, "Water Pump Started");
  Serial.print("Water Pump: ");
  Serial.print("HIGH");
  delay(PUMP_TIME);
  digitalWrite(WATER_PUMP, LOW);
  Blynk.virtualWrite(V3, "Water Pump Stopped");
  Serial.print("Water Pump: ");
  Serial.print("LOW");
}

/*--------- Time Range ---------*/
/* Define the time range for sensor measurements */
const int measurementInterval = TIME_RANGE;
/* Time variable to keep track of the time range */
unsigned long previousMillis = 0; 

void setup() {
  Serial.begin(9600);
  WiFi.begin(ssid, pass);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.print("Wi-Fi connected: ");

  Blynk.config(BLYNK_AUTH_TOKEN);

  phServo.attach(SERVO_PIN);
  phServo.write(pos);

  pinMode(LVL_PIN, INPUT);
  pinMode(LVL_PWR, OUTPUT);
  pinMode(WATER_PUMP, OUTPUT);

  /* Initially keep the sensors and motor OFF */
  digitalWrite(LVL_PWR, LOW);
  digitalWrite(WATER_PUMP, LOW);
}

void loop() {
  // Run the Blynk app
  Blynk.run();

  /* Get current time. If the defined time range 
  has not passed, terminate the loop */
  unsigned long currentMillis = millis();
  if (currentMillis - previousMillis < measurementInterval) {
    return;
  }
  /* If the defined time range is complete, update the time */
  previousMillis = currentMillis;

  PH_Value();
  delay(2000);
  readWaterLevel();
  delay(2000);
  runWaterPump();
  delay(2000);
}

