Skip to content

Instantly share code, notes, and snippets.

@alexanderscott
Last active December 29, 2015 14:47
Show Gist options
  • Save alexanderscott/f5df9a37fcbabdb4e78c to your computer and use it in GitHub Desktop.
Save alexanderscott/f5df9a37fcbabdb4e78c to your computer and use it in GitHub Desktop.

Revisions

  1. alexanderscott revised this gist Dec 29, 2015. 1 changed file with 0 additions and 1 deletion.
    1 change: 0 additions & 1 deletion RoboGrow.ino
    Original file line number Diff line number Diff line change
    @@ -1,6 +1,5 @@
    #include <LiquidCrystal.h>
    #include "DHT.h"
    #include "SerialReceiver.h"

    #define DHTTYPE DHT11

  2. alexanderscott revised this gist Dec 29, 2015. 1 changed file with 144 additions and 82 deletions.
    226 changes: 144 additions & 82 deletions RoboGrow.ino
    Original file line number Diff line number Diff line change
    @@ -6,6 +6,16 @@

    template<class T> inline Print &operator <<(Print &obj, T arg) { obj.print(arg); return obj; }

    /* Enable/Disable Features */
    bool enableDhtSensor0 = true;
    bool enableDhtSensor1 = false;
    bool enableLightSensor0 = true;
    bool enableLightSensor1 = false;
    bool enableMoistureSensor0 = false;
    bool enableMoistureSensor1 = false;
    bool enablePump0 = true;
    bool enablePump1 = true;

    /* Pin Setup */
    const int DHT_PIN_0 = 6;
    const int DHT_PIN_1 = 7;
    @@ -25,8 +35,13 @@ const int PUMP_BTN_PIN_1 = A5;

    /* Library Initialization */
    LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
    DHT dht0(DHT_PIN_0, DHTTYPE);
    DHT dht1(DHT_PIN_1, DHTTYPE);
    if (enableDhtSensor0) {
    DHT dht0(DHT_PIN_0, DHTTYPE);
    }

    if (enableDhtSensor1) {
    DHT dht1(DHT_PIN_1, DHTTYPE);
    }


    /* Variable Measurements */
    @@ -59,7 +74,6 @@ int pumpBtnState1 = 0;
    long READ_DELAY = 60000;
    const int SAMPLES_PER_READ = 30;
    const int PUMP_WATER_TIME = 10000;
    //const long int PUMP_WATER_WAIT_TIME = 86400000;
    const int SERIAL_PORT = 9600;


    @@ -72,20 +86,34 @@ void setup() {
    lcd.setCursor(0, 2);
    lcd << "Initializing sensors";

    dht0.begin();
    dht1.begin();
    if (enableDhtSensor0) {
    dht0.begin();
    }

    if (enableDhtSensor1) {
    dht1.begin();
    }

    if (enableLightSensor0) {
    pinMode(LIGHT_PIN_0, INPUT);
    }
    if (enableLightSensor1) {
    pinMode(LIGHT_PIN_1, INPUT);
    }

    if (enablePump0) {
    pinMode(PUMP_BTN_PIN_0, INPUT);
    pinMode(PUMP_PIN_ANODE_0, OUTPUT);
    pinMode(PUMP_PIN_CATHODE_0, OUTPUT);
    }

    pinMode(LIGHT_PIN_0, INPUT);
    pinMode(LIGHT_PIN_1, INPUT);
    pinMode(PUMP_BTN_PIN_0, INPUT);
    pinMode(PUMP_BTN_PIN_1, INPUT);
    pinMode(PUMP_PIN_ANODE_0, OUTPUT);
    pinMode(PUMP_PIN_ANODE_1, OUTPUT);
    pinMode(PUMP_PIN_CATHODE_0, OUTPUT);
    pinMode(PUMP_PIN_CATHODE_1, OUTPUT);
    if (enablePump1) {
    pinMode(PUMP_BTN_PIN_1, INPUT);
    pinMode(PUMP_PIN_ANODE_1, OUTPUT);
    pinMode(PUMP_PIN_CATHODE_1, OUTPUT);
    }

    Serial.begin(SERIAL_PORT);
    IncomingCommand::reset();

    delay(500);
    }
    @@ -110,55 +138,59 @@ void loop() {
    }

    void readSerialEvents() {
    IncomingCommand::reset();
    long beginTime = millis();
    unsigned long currentTime = millis();

    while (currentTime - beginTime < READ_DELAY) {
    char inChar = (char) Serial.read();
    IncomingCommand::append(inChar);
    if (IncomingCommand::isReady) {
    executeSerialCommand(IncomingCommand::command, IncomingCommand::payload);
    IncomingCommand::reset();
    long beginTime = millis();
    unsigned long currentTime = millis();

    while (currentTime - beginTime < READ_DELAY) {
    if(Serial.available() > 0)
    {
    String command = Serial.readStringUntil(' ');
    String payload = Serial.readStringUntil('\n');
    executeSerialCommand(command, payload);
    }
    delay(50);
    currentTime = millis();
    }
    delay(50);
    currentTime = millis();
    }
    }

    void executeSerialCommand(String cmd, String payload) {
    Serial << "Command: " << cmd << ", payload: " << payload << "\r\n";
    if (cmd == "WATER_0") {
    if (cmd == "WATER_0" && enablePump0) {
    int waterTime = payload.toInt();
    pumpWater0(waterTime);
    } else if (cmd == "WATER_1") {
    } else if (cmd == "WATER_1" && enablePump1) {
    int waterTime = payload.toInt();
    pumpWater1(waterTime);
    } else if(cmd == "WATER") {
    int waterTime = payload.toInt();
    pumpWater0(waterTime);
    delay(waterTime);
    pumpWater1(waterTime);
    if (enablePump0) {
    pumpWater0(waterTime);
    delay(waterTime);
    }
    if (enablePump1) {
    pumpWater1(waterTime);
    }
    }
    }

    void checkPumpButtons() {
    pumpBtnState0 = digitalRead(PUMP_BTN_PIN_0);
    pumpBtnState1 = digitalRead(PUMP_BTN_PIN_1);

    if (pumpBtnState0 == LOW) {
    Serial.println("Pump0 button press");
    pumpWater0(PUMP_WATER_TIME);
    if (enablePump0) {
    pumpBtnState0 = digitalRead(PUMP_BTN_PIN_0);
    if (pumpBtnState0 == LOW) {
    Serial.println("Pump0 button press");
    pumpWater0(PUMP_WATER_TIME);
    }
    }

    if (pumpBtnState1 == LOW) {
    Serial.println("Pump1 button press");
    pumpWater1(PUMP_WATER_TIME);
    if (enablePump1) {
    pumpBtnState1 = digitalRead(PUMP_BTN_PIN_1);
    if (pumpBtnState1 == LOW) {
    Serial.println("Pump1 button press");
    pumpWater1(PUMP_WATER_TIME);
    }
    }
    }



    // Reset readings back to 0 for next loop
    void resetReadings() {
    moistureValue0 = 0;
    @@ -191,53 +223,70 @@ void computeLightMoisture() {
    for(int i = 0; i < SAMPLES_PER_READ; i++) {

    // Read moisture
    moistureSum0 = moistureSum0 + analogRead(MOISTURE_PIN_0);
    moistureSum1 = moistureSum1 + analogRead(MOISTURE_PIN_1);
    if (enableMoistureSensor0) {
    moistureSum0 = moistureSum0 + analogRead(MOISTURE_PIN_0);
    }
    if (enableMoistureSensor1) {
    moistureSum1 = moistureSum1 + analogRead(MOISTURE_PIN_1);
    }

    // Read light
    lightSum0 = lightSum0 + analogRead(LIGHT_PIN_0);
    lightSum1 = lightSum1 + analogRead(LIGHT_PIN_1);
    if (enableLightSensor0) {
    lightSum0 = lightSum0 + analogRead(LIGHT_PIN_0);
    }
    if (enableLightSensor1) {
    lightSum1 = lightSum1 + analogRead(LIGHT_PIN_1);
    }

    delay(100);
    }

    moistureValue0 = moistureSum0 / SAMPLES_PER_READ;
    moistureValue1 = moistureSum1 / SAMPLES_PER_READ;

    float lightValue0Tmp = lightSum0 / SAMPLES_PER_READ;
    lightValue0 = voltageToLux(lightValue0Tmp);
    if (enableLightSensor0) {
    float lightValue0Tmp = lightSum0 / SAMPLES_PER_READ;
    lightValue0 = voltageToLux(lightValue0Tmp);
    }

    float lightValue1Tmp = lightSum1 / SAMPLES_PER_READ;
    lightValue1 = voltageToLux(lightValue1Tmp);
    if (enableLightSensor1) {
    float lightValue1Tmp = lightSum1 / SAMPLES_PER_READ;
    lightValue1 = voltageToLux(lightValue1Tmp);
    }
    }


    // Reading temperature or humidity takes about 250 milliseconds!
    // Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)
    void computeTemp() {
    humidityValue0 = dht0.readHumidity();
    tempValue0 = dht0.readTemperature();
    tempFahrValue0 = dht0.readTemperature(true); // Read temperature as Fahrenheit

    humidityValue1 = dht1.readHumidity();
    tempValue1 = dht1.readTemperature();
    tempFahrValue1 = dht1.readTemperature(true); // Read temperature as Fahrenheit

    // Check if any reads failed and exit early (to try again).
    if (isnan(humidityValue0) || isnan(tempValue0) || isnan(tempFahrValue0)) {
    Serial.println("Failed to read from DHT0 sensor!");
    dht0operational = false;
    } else {
    heatValue0 = dht0.computeHeatIndex(tempFahrValue0, humidityValue0);
    dht0operational = true;
    if (enableDhtSensor0) {
    humidityValue0 = dht0.readHumidity();
    tempValue0 = dht0.readTemperature();
    tempFahrValue0 = dht0.readTemperature(true); // Read temperature as Fahrenheit

    // Check if any reads failed and exit early (to try again).
    if (isnan(humidityValue0) || isnan(tempValue0) || isnan(tempFahrValue0)) {
    Serial.println("Failed to read from DHT0 sensor!");
    dht0operational = false;
    } else {
    heatValue0 = dht0.computeHeatIndex(tempFahrValue0, humidityValue0);
    dht0operational = true;
    }
    }

    if (isnan(humidityValue1) || isnan(tempValue1) || isnan(tempFahrValue1)) {
    Serial.println("Failed to read from DHT1 sensor!");
    dht1operational = false;
    } else {
    heatValue1 = dht1.computeHeatIndex(tempFahrValue1, humidityValue1);
    dht1operational = true;
    if (enableDhtSensor1) {
    humidityValue1 = dht1.readHumidity();
    tempValue1 = dht1.readTemperature();
    tempFahrValue1 = dht1.readTemperature(true); // Read temperature as Fahrenheit

    // Check if any reads failed and exit early (to try again).
    if (isnan(humidityValue1) || isnan(tempValue1) || isnan(tempFahrValue1)) {
    Serial.println("Failed to read from DHT1 sensor!");
    dht1operational = false;
    } else {
    heatValue1 = dht1.computeHeatIndex(tempFahrValue1, humidityValue1);
    dht1operational = true;
    }
    }
    }

    @@ -285,19 +334,29 @@ void pumpWater1(int waterTime) {
    */
    void printSerial() {

    Serial << "light_0," << lightValue0 << "\r\n";
    Serial << "light_1," << lightValue1 << "\r\n";
    if (enableLightSensor0) {
    Serial << "light_0," << lightValue0 << "\r\n";
    }

    if (enableLightSensor1) {
    Serial << "light_1," << lightValue1 << "\r\n";
    }

    if (enableMoistureSensor0) {
    Serial << "moisture_0," << moistureValue0 << "\r\n";
    }

    Serial << "moisture_0," << moistureValue0 << "\r\n";
    Serial << "moisture_1," << moistureValue1 << "\r\n";
    if (enableMoistureSensor1) {
    Serial << "moisture_1," << moistureValue1 << "\r\n";
    }

    if (dht0operational == true) {
    if (enableDhtSensor0 && dht0operational == true) {
    Serial << "humidity_0," << humidityValue0 << "\r\n";
    Serial << "temperature_0," << tempFahrValue0 << "\r\n";
    Serial << "heat_0," << heatValue0 << "\r\n";
    }

    if (dht1operational == true) {
    if (enableDhtSensor1 && dht1operational == true) {
    Serial << "humidity_1," << humidityValue1 << "\r\n";
    Serial << "temperature_1," << tempFahrValue1 << "\r\n";
    Serial << "heat_1," << heatValue1 << "\r\n";
    @@ -318,18 +377,21 @@ void printLCD() {
    delay(200);

    lcd.setCursor(0, 0);
    lcd << "M0: " << moistureValue0 << " M1: " << moistureValue1;
    lcd << "MSTR 0:" << moistureValue0 << " 1:" << moistureValue1;

    lcd.setCursor(0, 1);
    lcd << "T0: " << t0 << "*F T1: " << t1 << "*F";
    lcd << "TEMP 0:" << t0 << "*F 1:" << t1 << "*F";

    lcd.setCursor(0, 2);
    lcd << "HU0: " << hu0 << "% H01: " << hu1 << "%";
    lcd << "HUM 0:" << hu0 << "% 1:" << hu1 << "%";

    lcd.setCursor(0, 3);
    lcd << "L0: " << l0 << " L1: " << l1;
    lcd << "LIT 0:" << l0 << " 1:" << l1;
    }

    /*
    Conversion Functions
    */
    float voltageToLux(float photocellReading) {
    // Calculating the voltage in the input of the ADC
    float voltage = 5.0 * (photocellReading / 1024.0);
  3. alexanderscott revised this gist Apr 8, 2015. 1 changed file with 24 additions and 9 deletions.
    33 changes: 24 additions & 9 deletions RoboGrow.ino
    Original file line number Diff line number Diff line change
    @@ -18,6 +18,7 @@ const int PUMP_PIN_CATHODE_1 = 13;
    const int MOISTURE_PIN_0 = A0;
    const int MOISTURE_PIN_1 = A1;
    const int LIGHT_PIN_0 = A2;
    const int LIGHT_PIN_1 = A3;
    const int PUMP_BTN_PIN_0 = A4;
    const int PUMP_BTN_PIN_1 = A5;

    @@ -31,6 +32,8 @@ DHT dht1(DHT_PIN_1, DHTTYPE);
    /* Variable Measurements */
    float lightValue0 = 0;
    long int lightSum0 = 0;
    float lightValue1 = 0;
    long int lightSum1 = 0;

    int moistureValue0 = 0;
    long int moistureSum0 = 0;
    @@ -53,7 +56,7 @@ int pumpBtnState0 = 0;
    int pumpBtnState1 = 0;

    /* Constants / Configuration */
    const int READ_DELAY = 30000;
    long READ_DELAY = 60000;
    const int SAMPLES_PER_READ = 30;
    const int PUMP_WATER_TIME = 10000;
    //const long int PUMP_WATER_WAIT_TIME = 86400000;
    @@ -73,6 +76,7 @@ void setup() {
    dht1.begin();

    pinMode(LIGHT_PIN_0, INPUT);
    pinMode(LIGHT_PIN_1, INPUT);
    pinMode(PUMP_BTN_PIN_0, INPUT);
    pinMode(PUMP_BTN_PIN_1, INPUT);
    pinMode(PUMP_PIN_ANODE_0, OUTPUT);
    @@ -107,15 +111,18 @@ void loop() {

    void readSerialEvents() {
    IncomingCommand::reset();
    unsigned long beginTime = millis();
    while (Serial.available() && ((millis() - beginTime) < READ_DELAY)) {
    long beginTime = millis();
    unsigned long currentTime = millis();

    while (currentTime - beginTime < READ_DELAY) {
    char inChar = (char) Serial.read();
    IncomingCommand::append(inChar);
    if (IncomingCommand::isReady) {
    executeSerialCommand(IncomingCommand::command, IncomingCommand::payload);
    IncomingCommand::reset();
    }
    IncomingCommand::append(inChar);
    if (IncomingCommand::isReady) {
    executeSerialCommand(IncomingCommand::command, IncomingCommand::payload);
    IncomingCommand::reset();
    }
    delay(50);
    currentTime = millis();
    }
    }

    @@ -171,6 +178,8 @@ void resetReadings() {

    lightValue0 = 0;
    lightSum0 = 0;
    lightValue1 = 0;
    lightSum1 = 0;

    pumpBtnState0 = 0;
    pumpBtnState1 = 0;
    @@ -187,6 +196,7 @@ void computeLightMoisture() {

    // Read light
    lightSum0 = lightSum0 + analogRead(LIGHT_PIN_0);
    lightSum1 = lightSum1 + analogRead(LIGHT_PIN_1);

    delay(100);
    }
    @@ -196,6 +206,9 @@ void computeLightMoisture() {

    float lightValue0Tmp = lightSum0 / SAMPLES_PER_READ;
    lightValue0 = voltageToLux(lightValue0Tmp);

    float lightValue1Tmp = lightSum1 / SAMPLES_PER_READ;
    lightValue1 = voltageToLux(lightValue1Tmp);
    }


    @@ -273,6 +286,7 @@ void pumpWater1(int waterTime) {
    void printSerial() {

    Serial << "light_0," << lightValue0 << "\r\n";
    Serial << "light_1," << lightValue1 << "\r\n";

    Serial << "moisture_0," << moistureValue0 << "\r\n";
    Serial << "moisture_1," << moistureValue1 << "\r\n";
    @@ -296,6 +310,7 @@ void printLCD() {
    int t0 = (int) tempFahrValue0;
    int t1 = (int) tempFahrValue1;
    int l0 = (int) lightValue0;
    int l1 = (int) lightValue1;
    int he0 = (int) heatValue0;
    int he1 = (int) heatValue1;

    @@ -312,7 +327,7 @@ void printLCD() {
    lcd << "HU0: " << hu0 << "% H01: " << hu1 << "%";

    lcd.setCursor(0, 3);
    lcd << "L1: " << l0;
    lcd << "L0: " << l0 << " L1: " << l1;
    }

    float voltageToLux(float photocellReading) {
  4. alexanderscott revised this gist Mar 23, 2015. 1 changed file with 20 additions and 23 deletions.
    43 changes: 20 additions & 23 deletions RoboGrow.ino
    Original file line number Diff line number Diff line change
    @@ -1,8 +1,6 @@
    /* Imports & Definitions */
    #include <LiquidCrystal.h>
    #include "DHT.h"
    #include <MemoryFree.h>
    #include <SerialReceiver.h>
    #include "SerialReceiver.h"

    #define DHTTYPE DHT11

    @@ -12,8 +10,10 @@ template<class T> inline Print &operator <<(Print &obj, T arg) { obj.print(arg);
    const int DHT_PIN_0 = 6;
    const int DHT_PIN_1 = 7;

    const int PUMP_PIN_0 = 9;
    const int PUMP_PIN_1 = 10;
    const int PUMP_PIN_CATHODE_0 = 8;
    const int PUMP_PIN_ANODE_0 = 9;
    const int PUMP_PIN_ANODE_1 = 10;
    const int PUMP_PIN_CATHODE_1 = 13;

    const int MOISTURE_PIN_0 = A0;
    const int MOISTURE_PIN_1 = A1;
    @@ -53,7 +53,7 @@ int pumpBtnState0 = 0;
    int pumpBtnState1 = 0;

    /* Constants / Configuration */
    const int READ_DELAY = 10000;
    const int READ_DELAY = 30000;
    const int SAMPLES_PER_READ = 30;
    const int PUMP_WATER_TIME = 10000;
    //const long int PUMP_WATER_WAIT_TIME = 86400000;
    @@ -65,19 +65,20 @@ void setup() {
    delay(2000); //allow lcd to wake up.

    lcd.begin(20, 4);
    lcd.setCursor(0, 0);
    lcd << ".:: roboGrow ::.";
    lcd << ".:: RoboGrow ::.";
    lcd.setCursor(0, 2);
    lcd << "Initializing sensors...";
    lcd << "Initializing sensors";

    dht0.begin();
    dht1.begin();

    pinMode(LIGHT_PIN_0, INPUT);
    pinMode(PUMP_BTN_PIN_0, INPUT);
    pinMode(PUMP_BTN_PIN_1, INPUT);
    pinMode(PUMP_PIN_0, OUTPUT);
    pinMode(PUMP_PIN_1, OUTPUT);
    pinMode(PUMP_PIN_ANODE_0, OUTPUT);
    pinMode(PUMP_PIN_ANODE_1, OUTPUT);
    pinMode(PUMP_PIN_CATHODE_0, OUTPUT);
    pinMode(PUMP_PIN_CATHODE_1, OUTPUT);

    Serial.begin(SERIAL_PORT);
    IncomingCommand::reset();
    @@ -232,15 +233,15 @@ void pumpWater0(int waterTime) {
    //delay(200);
    Serial.println("Activating pump0");

    //analogWrite(PUMP_PIN_0, 255);
    digitalWrite(PUMP_PIN_0, HIGH);
    digitalWrite(PUMP_PIN_ANODE_0, HIGH);
    digitalWrite(PUMP_PIN_CATHODE_0, LOW);

    delay(waterTime);

    Serial.println("Deactivating pump0");

    //analogWrite(PUMP_PIN_0, 0);
    digitalWrite(PUMP_PIN_0, LOW);
    digitalWrite(PUMP_PIN_ANODE_0, LOW);
    digitalWrite(PUMP_PIN_CATHODE_0, LOW);

    //lcd.display();
    delay(1000);
    @@ -251,29 +252,25 @@ void pumpWater1(int waterTime) {
    //delay(200);
    Serial.println("Activating pump1");

    //analogWrite(PUMP_PIN_1, 255);
    digitalWrite(PUMP_PIN_1, HIGH);
    digitalWrite(PUMP_PIN_ANODE_1, HIGH);
    digitalWrite(PUMP_PIN_CATHODE_1, LOW);

    delay(waterTime);

    Serial.println("Deactivating pump1");

    //analogWrite(PUMP_PIN_1, 0);
    digitalWrite(PUMP_PIN_1, LOW);
    digitalWrite(PUMP_PIN_ANODE_1, LOW);
    digitalWrite(PUMP_PIN_CATHODE_1, LOW);

    //lcd.display();
    delay(1000);
    }



    /*
    Display Functions
    */
    void printSerial() {
    // print how much RAM is available.
    Serial.print("Free RAM: ");
    Serial.println(freeMemory(), DEC);

    Serial << "light_0," << lightValue0 << "\r\n";

  5. alexanderscott created this gist Mar 20, 2015.
    336 changes: 336 additions & 0 deletions RoboGrow.ino
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,336 @@
    /* Imports & Definitions */
    #include <LiquidCrystal.h>
    #include "DHT.h"
    #include <MemoryFree.h>
    #include <SerialReceiver.h>

    #define DHTTYPE DHT11

    template<class T> inline Print &operator <<(Print &obj, T arg) { obj.print(arg); return obj; }

    /* Pin Setup */
    const int DHT_PIN_0 = 6;
    const int DHT_PIN_1 = 7;

    const int PUMP_PIN_0 = 9;
    const int PUMP_PIN_1 = 10;

    const int MOISTURE_PIN_0 = A0;
    const int MOISTURE_PIN_1 = A1;
    const int LIGHT_PIN_0 = A2;
    const int PUMP_BTN_PIN_0 = A4;
    const int PUMP_BTN_PIN_1 = A5;


    /* Library Initialization */
    LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
    DHT dht0(DHT_PIN_0, DHTTYPE);
    DHT dht1(DHT_PIN_1, DHTTYPE);


    /* Variable Measurements */
    float lightValue0 = 0;
    long int lightSum0 = 0;

    int moistureValue0 = 0;
    long int moistureSum0 = 0;
    int moistureValue1 = 0;
    long int moistureSum1 = 0;

    bool dht0operational = true;
    float humidityValue0 = 0;
    float tempValue0 = 0;
    float tempFahrValue0 = 0;
    float heatValue0 = 0;

    bool dht1operational = true;
    float humidityValue1 = 0;
    float tempValue1 = 0;
    float tempFahrValue1 = 0;
    float heatValue1 = 0;

    int pumpBtnState0 = 0;
    int pumpBtnState1 = 0;

    /* Constants / Configuration */
    const int READ_DELAY = 10000;
    const int SAMPLES_PER_READ = 30;
    const int PUMP_WATER_TIME = 10000;
    //const long int PUMP_WATER_WAIT_TIME = 86400000;
    const int SERIAL_PORT = 9600;


    void setup() {

    delay(2000); //allow lcd to wake up.

    lcd.begin(20, 4);
    lcd.setCursor(0, 0);
    lcd << ".:: roboGrow ::.";
    lcd.setCursor(0, 2);
    lcd << "Initializing sensors...";

    dht0.begin();
    dht1.begin();

    pinMode(LIGHT_PIN_0, INPUT);
    pinMode(PUMP_BTN_PIN_0, INPUT);
    pinMode(PUMP_BTN_PIN_1, INPUT);
    pinMode(PUMP_PIN_0, OUTPUT);
    pinMode(PUMP_PIN_1, OUTPUT);

    Serial.begin(SERIAL_PORT);
    IncomingCommand::reset();

    delay(500);
    }


    void loop() {
    resetReadings();

    computeLightMoisture();

    computeTemp();

    printSerial();

    printLCD();

    checkPumpButtons();

    readSerialEvents();

    readSerialEvents();
    }

    void readSerialEvents() {
    IncomingCommand::reset();
    unsigned long beginTime = millis();
    while (Serial.available() && ((millis() - beginTime) < READ_DELAY)) {
    char inChar = (char) Serial.read();
    IncomingCommand::append(inChar);
    if (IncomingCommand::isReady) {
    executeSerialCommand(IncomingCommand::command, IncomingCommand::payload);
    IncomingCommand::reset();
    }
    delay(50);
    }
    }

    void executeSerialCommand(String cmd, String payload) {
    Serial << "Command: " << cmd << ", payload: " << payload << "\r\n";
    if (cmd == "WATER_0") {
    int waterTime = payload.toInt();
    pumpWater0(waterTime);
    } else if (cmd == "WATER_1") {
    int waterTime = payload.toInt();
    pumpWater1(waterTime);
    } else if(cmd == "WATER") {
    int waterTime = payload.toInt();
    pumpWater0(waterTime);
    delay(waterTime);
    pumpWater1(waterTime);
    }
    }

    void checkPumpButtons() {
    pumpBtnState0 = digitalRead(PUMP_BTN_PIN_0);
    pumpBtnState1 = digitalRead(PUMP_BTN_PIN_1);

    if (pumpBtnState0 == LOW) {
    Serial.println("Pump0 button press");
    pumpWater0(PUMP_WATER_TIME);
    }

    if (pumpBtnState1 == LOW) {
    Serial.println("Pump1 button press");
    pumpWater1(PUMP_WATER_TIME);
    }
    }



    // Reset readings back to 0 for next loop
    void resetReadings() {
    moistureValue0 = 0;
    moistureSum0 = 0;
    moistureValue1 = 0;
    moistureSum1 = 0;

    humidityValue0 = 0;
    tempValue0 = 0;
    tempFahrValue0 = 0;
    heatValue0 = 0;

    humidityValue1 = 0;
    tempValue1= 0;
    tempFahrValue1 = 0;
    heatValue1 = 0;

    lightValue0 = 0;
    lightSum0 = 0;

    pumpBtnState0 = 0;
    pumpBtnState1 = 0;
    }


    // Calculate light & moisture readings from sample avg
    void computeLightMoisture() {
    for(int i = 0; i < SAMPLES_PER_READ; i++) {

    // Read moisture
    moistureSum0 = moistureSum0 + analogRead(MOISTURE_PIN_0);
    moistureSum1 = moistureSum1 + analogRead(MOISTURE_PIN_1);

    // Read light
    lightSum0 = lightSum0 + analogRead(LIGHT_PIN_0);

    delay(100);
    }

    moistureValue0 = moistureSum0 / SAMPLES_PER_READ;
    moistureValue1 = moistureSum1 / SAMPLES_PER_READ;

    float lightValue0Tmp = lightSum0 / SAMPLES_PER_READ;
    lightValue0 = voltageToLux(lightValue0Tmp);
    }


    // Reading temperature or humidity takes about 250 milliseconds!
    // Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)
    void computeTemp() {
    humidityValue0 = dht0.readHumidity();
    tempValue0 = dht0.readTemperature();
    tempFahrValue0 = dht0.readTemperature(true); // Read temperature as Fahrenheit

    humidityValue1 = dht1.readHumidity();
    tempValue1 = dht1.readTemperature();
    tempFahrValue1 = dht1.readTemperature(true); // Read temperature as Fahrenheit

    // Check if any reads failed and exit early (to try again).
    if (isnan(humidityValue0) || isnan(tempValue0) || isnan(tempFahrValue0)) {
    Serial.println("Failed to read from DHT0 sensor!");
    dht0operational = false;
    } else {
    heatValue0 = dht0.computeHeatIndex(tempFahrValue0, humidityValue0);
    dht0operational = true;
    }

    if (isnan(humidityValue1) || isnan(tempValue1) || isnan(tempFahrValue1)) {
    Serial.println("Failed to read from DHT1 sensor!");
    dht1operational = false;
    } else {
    heatValue1 = dht1.computeHeatIndex(tempFahrValue1, humidityValue1);
    dht1operational = true;
    }
    }

    void pumpWater0(int waterTime) {
    //lcd.noDisplay();
    //delay(200);
    Serial.println("Activating pump0");

    //analogWrite(PUMP_PIN_0, 255);
    digitalWrite(PUMP_PIN_0, HIGH);

    delay(waterTime);

    Serial.println("Deactivating pump0");

    //analogWrite(PUMP_PIN_0, 0);
    digitalWrite(PUMP_PIN_0, LOW);

    //lcd.display();
    delay(1000);
    }

    void pumpWater1(int waterTime) {
    //lcd.noDisplay();
    //delay(200);
    Serial.println("Activating pump1");

    //analogWrite(PUMP_PIN_1, 255);
    digitalWrite(PUMP_PIN_1, HIGH);

    delay(waterTime);

    Serial.println("Deactivating pump1");

    //analogWrite(PUMP_PIN_1, 0);
    digitalWrite(PUMP_PIN_1, LOW);

    //lcd.display();
    delay(1000);
    }



    /*
    Display Functions
    */
    void printSerial() {
    // print how much RAM is available.
    Serial.print("Free RAM: ");
    Serial.println(freeMemory(), DEC);

    Serial << "light_0," << lightValue0 << "\r\n";

    Serial << "moisture_0," << moistureValue0 << "\r\n";
    Serial << "moisture_1," << moistureValue1 << "\r\n";

    if (dht0operational == true) {
    Serial << "humidity_0," << humidityValue0 << "\r\n";
    Serial << "temperature_0," << tempFahrValue0 << "\r\n";
    Serial << "heat_0," << heatValue0 << "\r\n";
    }

    if (dht1operational == true) {
    Serial << "humidity_1," << humidityValue1 << "\r\n";
    Serial << "temperature_1," << tempFahrValue1 << "\r\n";
    Serial << "heat_1," << heatValue1 << "\r\n";
    }
    }

    void printLCD() {
    int hu0 = (int) humidityValue0;
    int hu1 = (int) humidityValue1;
    int t0 = (int) tempFahrValue0;
    int t1 = (int) tempFahrValue1;
    int l0 = (int) lightValue0;
    int he0 = (int) heatValue0;
    int he1 = (int) heatValue1;

    lcd.clear();
    delay(200);

    lcd.setCursor(0, 0);
    lcd << "M0: " << moistureValue0 << " M1: " << moistureValue1;

    lcd.setCursor(0, 1);
    lcd << "T0: " << t0 << "*F T1: " << t1 << "*F";

    lcd.setCursor(0, 2);
    lcd << "HU0: " << hu0 << "% H01: " << hu1 << "%";

    lcd.setCursor(0, 3);
    lcd << "L1: " << l0;
    }

    float voltageToLux(float photocellReading) {
    // Calculating the voltage in the input of the ADC
    float voltage = 5.0 * (photocellReading / 1024.0);

    // Calculating the resistance of the photoresistor
    // in the voltage divider
    float resistance = (10.0 * 5.0) / voltage - 10.0;

    // Calculating the intensity of light in lux
    float illuminance = 255.84 * pow(resistance, -10/9);

    // Converting the intensity of light to text
    //sprintf(text, "%0.1f lux ", illuminance);
    return illuminance;
    }