diff --git a/Arduino/CanGrow/CanGrow.ino b/Arduino/CanGrow/CanGrow.ino index f2c9233..edc682c 100644 --- a/Arduino/CanGrow/CanGrow.ino +++ b/Arduino/CanGrow/CanGrow.ino @@ -95,7 +95,7 @@ char WebUiPassword[32] = "cangrow"; // configured - if false, let the user configure system settings first bool configured = false; // NTP Offset -short ntpOffset; +short NtpOffset; // MoistureSensor_Type - contains which moisture sensor to use // 1: analog capacitive sensor // 2: I2C chirp sensor from catnip electronics @@ -138,10 +138,14 @@ byte LighthoursBloom = 12; byte SunriseHour = 7; // SunriseHour - contains to which minute of SunriseHour the growlight turns on byte SunriseMinute = 0; -// PINled_PWM - contains the PWM value for dimming the grow light +// PINledPWM - contains the PWM value for dimming the grow light // default is 255 to ensure it is just on for the case UseLEDrelais is true -byte PINled_PWM = 255; -byte PINfan_PWM = 255; +byte PINledPWM = 255; +byte PINfanPWM = 255; + +// fade in and out sunrise and sunset? +bool SunFade; +byte SunFadeDuration = 30; /* * @@ -354,11 +358,11 @@ function convertDateToEpoch(src, dst) { * * Pin assignments * - * D0 - MOSFET Fan + * D0 - MOSFET Pump * D1, D2 - I2C * D3 - DHT11 * D4 - PIN_WIPE - * D5 - MOSFET Pump + * D5 - MOSFET Fan * D6 - MOSFET Grow LED, PWM * D7 - waterlevel (set HIGH to read value) * D8 - analog soil moisture (set HIGH to read value) @@ -692,7 +696,7 @@ bool loadEEPROM() { * 164 PumpOnTime * 165 MoistureSensor_Type * 166 SoilmoistureLow - * 167 ntpOffset + * 167 NtpOffset * 169 UseLEDrelais * * 170 GrowName @@ -707,10 +711,12 @@ bool loadEEPROM() { * * -- afterwards added, need to sort -- * - * 213 PINled_PWM + * 213 PINledPWM * 214 TemperatureSensor_Type * 215 UseFANrelais - * 216 PINfan_PWM + * 216 PINfanPWM + * 217 SunFade + * 218 SunFadeDuration * */ @@ -763,20 +769,13 @@ bool loadEEPROM() { // size is 1 byte EEPROM.get(166, SoilmoistureLow); // size is 2 byte - EEPROM.get(167, ntpOffset); + EEPROM.get(167, NtpOffset); // size is 1 byte EEPROM.get(169, UseLEDrelais); // size is 1 byte - // I forgot to add TemperatureSensor_Type to EEPROM and noticed it - // quite late in the process of programming. So this value residents - // in 214 and not directly after UseLEDrelais - EEPROM.get(213, PINled_PWM); - // size is 1 byte EEPROM.get(214, TemperatureSensor_Type); // size is 1 byte EEPROM.get(215, UseFANrelais); - // size is 1 byte - EEPROM.get(216, PINfan_PWM); } // TODO auth does not work atm // EEPROM.get(160, WebUiUsername); @@ -805,6 +804,12 @@ bool loadEEPROM() { EEPROM.get(211, SunriseMinute); // size is 1 byte EEPROM.get(212, DayOfGrow); + // size is 1 byte + EEPROM.get(213, PINledPWM); + // size is 1 byte + EEPROM.get(216, PINfanPWM); + EEPROM.get(217, SunFade); + EEPROM.get(218, SunFadeDuration); } @@ -833,8 +838,8 @@ bool loadEEPROM() { Serial.println(MoistureSensor_Type); Serial.print("SoilmoistureLow: "); Serial.println(SoilmoistureLow); - Serial.print("ntpOffset: "); - Serial.println(ntpOffset); + Serial.print("NtpOffset: "); + Serial.println(NtpOffset); Serial.print("UseLEDrelais: "); Serial.println(UseLEDrelais); Serial.print("UseFANrelais: "); @@ -859,10 +864,14 @@ bool loadEEPROM() { Serial.println(SunriseMinute); Serial.print("DayOfGrow: "); Serial.println(DayOfGrow); - Serial.print("PINled_PWM: "); - Serial.println(PINled_PWM); - Serial.print("PINfan_PWM: "); - Serial.println(PINfan_PWM); + Serial.print("PINledPWM: "); + Serial.println(PINledPWM); + Serial.print("PINfanPWM: "); + Serial.println(PINfanPWM); + Serial.print("SunFade: "); + Serial.println(SunFade); + Serial.print("SunFadeDuration: "); + Serial.println(SunFadeDuration); } else { @@ -911,7 +920,7 @@ void wifiConnect() { display.display(); timeClient.begin(); - timeClient.setTimeOffset(ntpOffset * 60 * 60); + timeClient.setTimeOffset(NtpOffset * 60 * 60); timeClient.update(); while ( ! timeClient.isTimeSet()) { timeClient.update(); @@ -951,6 +960,51 @@ void wifiAp() { //Serial.println("The login credentials for the WebUI are 'cangrow' for username and password"); } +void setOutput(byte pin, byte pinState) { + /* + * Pin assignments + * + * 1 - LED + * 2 - FAN + * 3 - PUMP + * + */ + + + switch(pin) { + case 1: + if(pinState > 0) { + if(UseLEDrelais == true) { + digitalWrite(PINled, HIGH); + } else { + analogWrite(PINled, PINledPWM); + } + } else { + digitalWrite(PINled, LOW); + } + break; + case 2: + if(pinState > 0) { + if(UseFANrelais == true) { + digitalWrite(PINfan, HIGH); + } else { + analogWrite(PINfan, PINledPWM); + } + } else { + digitalWrite(PINfan, LOW); + } + break; + // PUMP Pin (D0) does not support PWM, so we do not need to care about + case 3: + if(pinState > 0) { + digitalWrite(PINpump, HIGH); + } else { + digitalWrite(PINpump, LOW); + } + break; + } +} + /* * Setup * @@ -1068,8 +1122,9 @@ void setup() { // set web handler WebHandler(); // start webserver - webserver.begin(); + webserver.begin(); + Serial.println(".:: CanGrow Ready ::."); } @@ -1086,18 +1141,16 @@ void loop() { unsigned int secondsToday = (timeClient.getHours() * 60 * 60) + (timeClient.getMinutes() * 60) + timeClient.getSeconds(); unsigned long currentRuntime = millis(); byte lightHours; + byte PINledPWM_tmp; // first we call webserver handle client webserver.handleClient(); - // do every second when everything is configured + // do every second when everything is configured and grow is started if( (configured == true) && (strlen(GrowName) > 0) && (currentRuntime - outputPrevTime >= 1000) ){ - // debug output - Serial.print("secondsSunrise: "); - Serial.println(secondsSunrise); - Serial.print("secondsToday: "); - Serial.println(secondsToday); - //Serial.println("yolo"); + /* + * LED controlling + */ // calculate acutal DayOfGrow DayOfGrow = int(ceil(float((timeClient.getEpochTime() - GrowStart) / 60 / 60 / 24))); @@ -1109,17 +1162,31 @@ void loop() { lightHours = LighthoursVeg; } - // check if secondsToday is larger then secondsSunrise time AND if secondsToday is smaller then the sum of secondsSunrise + seconds of lightHours - if( (secondsToday >= secondsSunrise) && (secondsToday <= ( secondsSunrise + (lightHours * 60 * 60) ) )){ - // turn on light + // check if secondsToday is larger then secondsSunrise time AND if + // secondsToday is smaller then the sum of secondsSunrise + seconds of lightHours + if( (SunFade == true) && ((secondsToday >= secondsSunrise) && (secondsToday <= ( secondsSunrise + (lightHours * 60 * 60))) ) ){ + + // in the first n minutes of lighting (SunFadeDuration), we want + //to raise the light slowly to prevent stress from the plant + if(secondsSunrise + SunFadeDuration * 60 >= secondsToday) { + // convert progress sunrise to PWM value + PINledPWM_tmp = (SunFadeDuration * 60 - ((secondsSunrise + SunFadeDuration * 60) - secondsToday)) * 255 / (SunFadeDuration * 60); + + } else if( (SunFade == true) && (secondsToday >= ((secondsSunrise + lightHours * 60 * 60) - SunFadeDuration * 60) ) ) { + // calculate progress sunset to PWM value + PINledPWM_tmp = (secondsSunrise + (lightHours * 60 * 60) - secondsToday) * 255 / (SunFadeDuration * 60); + + } else { + // no sunrise or sunset, just keep the LED turned on + setOutput(1, PINledPWM); + } - - // TODO write a LED control function which takes also takes care of UseLEDrelais - analogWrite(PINled, PINled_PWM); } else { // turn off - digitalWrite(PINled, LOW); + setOutput(1, 0); } + + // current time gets previous time for new interval outputPrevTime = currentRuntime; } @@ -1176,7 +1243,7 @@ void WebHandler() { webserver.onNotFound(WEB404); // switching MOSFETs - webserver.on("/switch", HTTP_POST, POSTswitchMOSFET); + webserver.on("/switch", HTTP_POST, POSTsetOutput); // api stuff webserver.on("/api/sensors", HTTP_GET, APIgetSensors); @@ -1433,7 +1500,7 @@ void WEBroot() { } body += "
"; body += "Growlight brightnes: "; - body += ((PINled_PWM * 100) / 255); + body += ((PINledPWM * 100) / 255); body += " %
"; body += "
"; body += "MOSFET
\n"; if(UseFANrelais == false) { - body += "Speed FAN:
\n"; } @@ -1620,9 +1687,9 @@ void WEBsystemSettings() { body += "\n"; body += "
\n"; - // ntpOffset int - body += "NTP offset:
\n"; body += "\n"; @@ -1703,15 +1770,25 @@ void WEBgrowSettings() { body += SunriseMinute; body+= "' required>
\n"; + // SunFade bool + body += "Fade in and out LED?:
\n"; + + body += "Fading duration (minutes):
\n"; + if(UseLEDrelais == false) { - body += "Brightness LED:
\n"; } if(UseFANrelais == false) { - body += "Speed FAN:
\n"; } @@ -1735,18 +1812,18 @@ void POSTgrowSettings() { if(UseLEDrelais == true) { // if a relais is used to turn on grow light, we force PWM to max val - PINled_PWM = 255; + PINledPWM = 255; } else { // otherwise just do PWM - PINled_PWM = webserver.arg("PINled_PWM").toInt(); + PINledPWM = webserver.arg("PINledPWM").toInt(); } if(UseFANrelais == true) { // if a relais is used to turn on grow light, we force PWM to max val - PINfan_PWM = 255; + PINfanPWM = 255; } else { // otherwise just do PWM - PINfan_PWM = webserver.arg("PINfan_PWM").toInt(); + PINfanPWM = webserver.arg("PINfanPWM").toInt(); } String GrowName_tmp = webserver.arg("GrowName"); @@ -1760,6 +1837,8 @@ void POSTgrowSettings() { LighthoursBloom = webserver.arg("LighthoursBloom").toInt(); SunriseHour = webserver.arg("SunriseHour").toInt(); SunriseMinute = webserver.arg("SunriseMinute").toInt(); + SunFade = webserver.arg("SunFade").toInt(); + SunFadeDuration = webserver.arg("SunFadeDuration").toInt(); // size is 32 byte EEPROM.put(170, GrowName); @@ -1778,17 +1857,18 @@ void POSTgrowSettings() { // size is 1 byte EEPROM.put(211, SunriseMinute); // size is 1 byte - EEPROM.put(213, PINled_PWM); + EEPROM.put(213, PINledPWM); // size is 1 byte - EEPROM.put(216, PINfan_PWM); - + EEPROM.put(216, PINfanPWM); + EEPROM.put(217, SunFade); + EEPROM.put(218, SunFadeDuration); EEPROM.commit(); - //analogWrite(PINled, PINled_PWM); + //analogWrite(PINled, PINledPWM); Serial.println(":: POSTgrowSettings ::"); @@ -1808,10 +1888,10 @@ void POSTgrowSettings() { Serial.println(SunriseHour); Serial.print("SunriseMinute: "); Serial.println(SunriseMinute); - Serial.print("PINled_PWM: "); - Serial.println(PINled_PWM); - Serial.print("PINfan_PWM: "); - Serial.println(PINfan_PWM); + Serial.print("PINledPWM: "); + Serial.println(PINledPWM); + Serial.print("PINfanPWM: "); + Serial.println(PINfanPWM); webserver.sendHeader("Location", String("/growSettings?success"), true); webserver.send(302, "text/plain", "growSettings/save: success!\n"); @@ -1819,7 +1899,7 @@ void POSTgrowSettings() { void POSTsystemSettings() { - ntpOffset = webserver.arg("ntpOffset").toInt(); + NtpOffset = webserver.arg("NtpOffset").toInt(); MoistureSensor_Type = webserver.arg("MoistureSensor_Type").toInt(); SoilmoistureLow = webserver.arg("SoilmoistureLow").toInt(); UsePump = webserver.arg("UsePump").toInt(); @@ -1844,7 +1924,7 @@ void POSTsystemSettings() { // size is 1 byte EEPROM.put(166, SoilmoistureLow); // size is 2 byte - EEPROM.put(167, ntpOffset); + EEPROM.put(167, NtpOffset); // size is 1 byte EEPROM.put(169, UseLEDrelais); // size is 1 byte @@ -1858,25 +1938,25 @@ void POSTsystemSettings() { // update time with new offset - timeClient.setTimeOffset(ntpOffset * 60 * 60); + timeClient.setTimeOffset(NtpOffset * 60 * 60); timeClient.update(); Serial.println(":: POSTsystemSettings ::"); - // when user uses an relais for LED control, we force here PINled_PWM to 255 + // when user uses an relais for LED control, we force here PINledPWM to 255 // to ensure nothing bad happens if(UseLEDrelais == true) { - PINled_PWM = 255; - EEPROM.put(213, PINled_PWM); + PINledPWM = 255; + EEPROM.put(213, PINledPWM); EEPROM.commit(); - Serial.println("UseLEDrelais is 1, forcing PINled_PWM to max to prevent relais damage"); + Serial.println("UseLEDrelais is 1, forcing PINledPWM to max to prevent relais damage"); } if(UseFANrelais == true) { - PINfan_PWM = 255; - EEPROM.put(215, PINfan_PWM); + PINfanPWM = 255; + EEPROM.put(215, PINfanPWM); EEPROM.commit(); - Serial.println("UseFANrelais is 1, forcing PINfan_PWM to max to prevent relais damage"); + Serial.println("UseFANrelais is 1, forcing PINfanPWM to max to prevent relais damage"); } Serial.print("configured: "); @@ -1891,8 +1971,8 @@ void POSTsystemSettings() { Serial.println(MoistureSensor_Type); Serial.print("SoilmoistureLow: "); Serial.println(SoilmoistureLow); - Serial.print("ntpOffset: "); - Serial.println(ntpOffset); + Serial.print("NtpOffset: "); + Serial.println(NtpOffset); Serial.print("UseLEDrelais: "); Serial.println(UseLEDrelais); Serial.print("UseFANrelais: "); @@ -1972,53 +2052,26 @@ void POSTwifiSettings() { } -void POSTswitchMOSFET() { - byte MosfetState = webserver.arg("state").toInt(); - byte MosfetNr = webserver.arg("output").toInt(); - byte PINfan_PWM = webserver.arg("PINfan_PWM").toInt(); +void POSTsetOutput() { + byte OutputState = webserver.arg("state").toInt(); + byte OutputNr = webserver.arg("output").toInt(); + PINledPWM = webserver.arg("PINledPWM").toInt(); + PINfanPWM = webserver.arg("PINfanPWM").toInt(); Serial.println(":: GETswitchMOSFET ::"); - Serial.print("MosfetState: "); - Serial.println(MosfetState); - Serial.print("MosfetNr: "); - Serial.println(MosfetNr); + Serial.print("OutputState: "); + Serial.println(OutputState); + Serial.print("OutputNr: "); + Serial.println(OutputNr); - if((MosfetState > 1) || (MosfetState < 0)) { + if((OutputNr > 3) || (OutputNr < 1) || (OutputState > 255) || (OutputState < 255)) { webserver.send(400, "text/plain", "not valid\n"); } else { - switch(MosfetNr) { - case 1: - if(MosfetState == 1) { - if(UseLEDrelais == true) { - digitalWrite(PINled, MosfetState); - } else { - analogWrite(PINled, PINled_PWM); - } - } else { - digitalWrite(PINled, MosfetState); - } - break; - case 2: - digitalWrite(PINpump, MosfetState); - break; - case 3: - if(MosfetState == 1) { - if(UseFANrelais == true) { - digitalWrite(PINfan, MosfetState); - } else { - analogWrite(PINfan, PINfan_PWM); - } - } else { - digitalWrite(PINfan, MosfetState); - } - break; - default: - webserver.send(400, "text/plain", "not valid\n"); - break; + + setOutput(OutputNr, OutputState); + webserver.sendHeader("Location", String("/?success"), true); + webserver.send(302, "text/plain", "switch: success!\n"); } - webserver.sendHeader("Location", String("/?success"), true); - webserver.send(302, "text/plain", "switch: success!\n"); - } } @@ -2065,6 +2118,7 @@ void APIgetSensors() { * - when PWM for fan is set, set fan speed to regulate humidity and * temperature * - re-organize EEPROM saved values. + * - prevent GrowStart to be in the future * * */