#include <EthernetServer.h>
#include <Dhcp.h>
#include <Ethernet.h>
#include <EthernetClient.h>
#include <Dns.h>
#include <SoftwareSerial.h>                           //we have to include the SoftwareSerial library, or else we can't use it

#include <OneWire.h>
#include <DallasTemperature.h>

#include <DHT.h>

#include <SPI.h> //Load the SPI Library
#include "DHT.h"
#include <avr/wdt.h>

#define DHTTYPE DHT22

#define DHTPIN 2
#define ONE_WIRE_BUS 9
#define uvlights A5
#define pump 5
#define blower 6
#define sumplow 7
#define sumphigh 8

#define rx A0                                          //define what pin rx is going to be
#define tx A1                                          //define what pin tx is going to be

SoftwareSerial myserial(rx, tx);                      //define how the soft serial port is going to work


String inputstring = "";                              //a string to hold incoming data from the PC
String sensorstring = "";                             //a string to hold the data from the Atlas Scientific product
boolean input_string_complete = false;                //have we received all the data from the PC
boolean sensor_string_complete = false;               //have we received all the data from the Atlas Scientific product
float DO;               


OneWire oneWire(ONE_WIRE_BUS);
DHT dht(DHTPIN, DHTTYPE);
// Pass our oneWire reference to Dallas Temperature.
DallasTemperature sensors(&oneWire);

byte mac[] = { 0xA0, 0xA2, 0xDA, 0xAA, 0xDD, 0xBB };//192.168.0.27.

byte gateway[] = { 192, 168, 0, 254 };
byte subnet[] = { 255, 255, 255, 0 };
EthernetServer server(80);
String readString;


byte depthstatus = 1;
unsigned long previousMillis = 0;
unsigned long blowerOntime = 0;
unsigned long blowerOfftime = 0;
long blowerOninterval = 3000000;
long blowerOffinterval = 590000;
//long blowerOffinterval = 5000;
//long blowerOninterval = 10000;


byte blower_state = 1;
int buttonState1;             // the current reading from the input pin
int lastButtonState1 = HIGH;   // the previous reading from the input pin
int buttonState2;             // the current reading from the input pin
int lastButtonState2 = HIGH;
// the following variables are long's because the time, measured in miliseconds,
// will quickly become a bigger number than can be stored in an int.
long lastDebounceTime1 = 0;
long lastDebounceTime2 = 0; // the last time the output pin was toggled
long debounceDelay = 50;    // the debounce time; increase if the output flickers
unsigned long resetInterval = 210000;
unsigned long resetTimer = 0;
unsigned long previousEthernetMillis = 0;        // will store last time LED was updated

// constants won't change :
const long interval = 600000;           // interval at which to blink (milliseconds)



void setup ()
{
  Serial.begin (19200);
//  Ethernet.hostName("GROWOUT");

  pinMode(sumplow, INPUT_PULLUP);
  pinMode(sumphigh, INPUT_PULLUP);
  pinMode(pump, OUTPUT);
  pinMode(uvlights, OUTPUT);
  pinMode(blower, OUTPUT);
  digitalWrite(blower, LOW);
  sensors.begin();
  dht.begin();
    Serial.print("server is at ");

  Ethernet.begin(mac); //Initialize Ethernet
  Serial.print("server is at ");
  Serial.println(Ethernet.localIP());
   myserial.begin(9600);                               //set baud rate for the software serial port to 9600
  inputstring.reserve(10);                            //set aside some bytes for receiving data from the PC
  sensorstring.reserve(30);                           //set aside some bytes for receiving data from Atlas Scientific product
//  Serial.println(Ethernet.getHostName());

}  // end of setup
// how much serial data we expect before a newline
const unsigned int MAX_INPUT = 100;
// the maximum length of paramters we accept
const int MAX_PARAM = 20;


// Example GET line: GET /?foo=bar HTTP/1.1
void processGet (const char * data)
{
  // find where the parameters start
  const char * paramsPos = strchr (data, '?');
  if (paramsPos == NULL)
    return;  // no parameters
  // find the trailing space
  const char * spacePos = strchr (paramsPos, ' ');
  if (spacePos == NULL)
    return;  // no space found
  // work out how long the parameters are
  int paramLength = spacePos - paramsPos - 1;
  // see if too long
  if (paramLength >= MAX_PARAM)
    return;  // too long for us
  // copy parameters into a buffer
  char param [MAX_PARAM];
  memcpy (param, paramsPos + 1, paramLength);  // skip the "?"
  param [paramLength] = 0;  // null terminator

  // do things depending on argument (GET parameters)

  if (strcmp (param, "blowerOn") == 0)
  {
    Serial.println (F("Activating blower"));
    blower_state = 1;


  } else if (strcmp (param, "blowerOff") == 0)
  {
    Serial.println (F("Deactivating blower"));
    blower_state = 0;
  } else if (strcmp (param, "sumpPumpOn") == 0)
  {
    Serial.println (F("activating pump"));
    depthstatus = 1;
  } else if (strcmp (param, "sumpPumpOff") == 0)
  {
    Serial.println (F("Deactivating pump"));
    depthstatus = 0;
  }
}  // end of processGet

// here to process incoming serial data after a terminator received
void processData (const char * data)
{
  Serial.println (data);
  if (strlen (data) < 4)
    return;

  if (memcmp (data, "GET ", 4) == 0)
    processGet (&data [4]);
}  // end of processData

bool processIncomingByte (const byte inByte)
{
  static char input_line [MAX_INPUT];
  static unsigned int input_pos = 0;
  switch (inByte)
  {
    case '\n':   // end of text
      input_line [input_pos] = 0;  // terminating null byte
      if (input_pos == 0)
        return true;   // got blank line
      // terminator reached! process input_line here ...
      processData (input_line);
      // reset buffer for next time
      input_pos = 0;
      break;

    case '\r':   // discard carriage return
      break;

    default:
      // keep adding if not full ... allow for terminating null byte
      if (input_pos < (MAX_INPUT - 1))
        input_line [input_pos++] = inByte;
      break;
  }  // end of switch
  return false;    // don't have a blank line yet
} // end of processIncomingByte

void loop ()
{
 if (input_string_complete){                         //if a string from the PC has been received in its entirety
    myserial.print(inputstring);                      //send that string to the Atlas Scientific product
    myserial.print('\r');                             //add a <CR> to the end of the string 
    inputstring = "";                                 //clear the string
    input_string_complete = false;                    //reset the flag used to tell if we have received a completed string from the PC
  }

  if (myserial.available() > 0) {                     //if we see that the Atlas Scientific product has sent a character
    char inchar = (char)myserial.read();              //get the char we just received
    sensorstring += inchar;                           //add the char to the var called sensorstring
    if (inchar == '\r') {                             //if the incoming character is a <CR>
      sensor_string_complete = true;                  //set the flag
    }
  }


  if (sensor_string_complete== true) {                //if a string from the Atlas Scientific product has been received in its entirety
    //Serial.println(sensorstring);                     //send that string to the PC's serial monitor
    if (isdigit(sensorstring[0])) {                   //if the first character in the string is a digit
      DO = sensorstring.toFloat();                    //convert the string to a floating point number so it can be evaluated by the Arduino
      if (DO >= 6.0) {                                //if the DO is greater than or equal to 6.0
        //Serial.println("high");                       //print "high" this is demonstrating that the Arduino is evaluating the DO as a number and not as a string
      }
      if (DO <= 5.99) {                               //if the DO is less than or equal to 5.99
        //Serial.println("low");                        //print "low" this is demonstrating that the Arduino is evaluating the DO as a number and not as a string
      }
    }
    sensorstring = "";                                //clear the string
    sensor_string_complete = false;                   //reset the flag used to tell if we have received a completed string from the Atlas Scientific product
  }
Ethernet.maintain();
  //  Serial.println(digitalRead(sumphigh));
  int reading1 = digitalRead(sumplow);

  // check to see if you just pressed the button
  // (i.e. the input went from LOW to HIGH),  and you've waited
  // long enough since the last press to ignore any noise:

  // If the switch changed, due to noise or pressing:
  if (reading1 != lastButtonState1) {
    // reset the debouncing timer
    lastDebounceTime1 = millis();
  }

  if ((millis() - lastDebounceTime1) > debounceDelay) {
    // whatever the reading is at, it's been there for longer
    // than the debounce delay, so take it as the actual current state:

    // if the button state has changed:
    if (reading1 != buttonState1) {
      buttonState1 = reading1;

      // only toggle the LED if the new button state is HIGH
      if (buttonState1 == LOW) {
        depthstatus = 0;
      }
    }
  }

  lastButtonState1 = reading1;
  ///////////////////////
  int reading2 = digitalRead(sumphigh);

  // check to see if you just pressed the button
  // (i.e. the input went from LOW to HIGH),  and you've waited
  // long enough since the last press to ignore any noise:

  // If the switch changed, due to noise or pressing:
  if (reading2 != lastButtonState2) {
    // reset the debouncing timer
    lastDebounceTime2 = millis();
  }

  if ((millis() - lastDebounceTime2) > debounceDelay) {
    // whatever the reading is at, it's been there for longer
    // than the debounce delay, so take it as the actual current state:

    // if the button state has changed:
    if (reading2 != buttonState2) {
      buttonState2 = reading2;

      // only toggle the LED if the new button state is HIGH
      if (buttonState2 == HIGH) {
        depthstatus = 1;
      }
    }
  }

  lastButtonState2 = reading2;

  if (depthstatus == 1)
  {
    digitalWrite(pump, HIGH);
    digitalWrite(uvlights, HIGH);
  } else if (depthstatus == 0)
  {
    digitalWrite(pump, LOW);
    digitalWrite(uvlights, LOW);
  }

  if (blower_state == 1)
  {
    blowerOfftime = millis();
  } else if (blower_state == 0)
  {
    blowerOntime = millis();
  }

  if (millis() - blowerOntime > blowerOninterval)
  {
    blower_state = 0;
    //Serial.println("blower off");
    //Serial.println(blowerOntime);
  } else if (millis() - blowerOfftime > blowerOffinterval)
  {
    blower_state = 1;
    //Serial.println("blower on");
    //Serial.println(blowerOfftime);
  }

  if (blower_state == 1)
  {
    digitalWrite(blower, HIGH);
  } else if (blower_state == 0)
  {
    digitalWrite(blower, LOW);
  }
  EthernetClient client = server.available();
  if (client)
  {
    sensors.requestTemperatures(); // Send the command to get temperatures
      float sumptemp = sensors.getTempCByIndex(0);
      float tanktemp = sensors.getTempCByIndex(1);
      float humidity = dht.readHumidity();
      float airtemp = dht.readTemperature();
 
    Serial.println(F("Client connected"));
    // an http request ends with a blank line
    boolean done = false;
    while (client.connected() && !done)
    {
      while (client.available () > 0 && !done)
        done = processIncomingByte (client.read ());
    }  // end of while client connected

    // send a standard http response header

    client.print(sumptemp);
    client.print(",");
    client.print(tanktemp);
    client.print(",");
    client.print(DO);
    client.print(",");
    client.print(airtemp);
    client.print(",");
    client.print(humidity);
    client.print(",");
    client.print(digitalRead(pump));
    client.print(",");
    client.print(digitalRead(blower));

    // give the web browser time to receive the data
    delay(10);
    // close the connection:
    client.stop();
    Serial.println(F("Client disconnected"));
  }  // end of got a new client
  
 unsigned long currentEthernetMillis = millis();

  
 }

