From 54fec62a3eafdca82bb2d68339638a2e74abbc21 Mon Sep 17 00:00:00 2001 From: Marcus Date: Sun, 16 Jun 2024 20:16:40 +0200 Subject: [PATCH] firmware wip - add pump control --- Arduino/CanGrow/CanGrow.ino | 27 +--- Arduino/CanGrow/CanGrow_HTML.h | 4 +- Arduino/CanGrow/CanGrow_Init.h | 14 +- Arduino/CanGrow/CanGrow_Sensors.h | 8 +- Arduino/CanGrow/CanGrow_SysFunctions.h | 169 +++++++++++++++++++++---- Arduino/CanGrow/CanGrow_Version.h | 2 +- Arduino/CanGrow/CanGrow_WebFunctions.h | 51 +++++--- 7 files changed, 205 insertions(+), 70 deletions(-) diff --git a/Arduino/CanGrow/CanGrow.ino b/Arduino/CanGrow/CanGrow.ino index c6ecf8a..200e578 100644 --- a/Arduino/CanGrow/CanGrow.ino +++ b/Arduino/CanGrow/CanGrow.ino @@ -239,7 +239,7 @@ void loop() { controlLED(); } - + controlPUMP(); displayScreens(); @@ -265,24 +265,12 @@ void loop() { * - re-organize EEPROM saved values. * - prevent GrowStart to be in the future * - maybe let the user configure some screens to display. - * + * - put EEPROM adresses into DEFINEs */ -/* - * Pump control - * - * Vars: - * - UsePump (bool) - * - PumpOnTime (int) in sec - * - PumpInterval (int) in days - * - SoilmoistureLow (int) in % - * - PumpLastOn (long) timestamp - * - PumpMode (short) 1: Pump on every n days, 2: Pump on when Soilmoisture <= SoilmoistureLow, 3: Both - * - * - */ + /* @@ -293,13 +281,8 @@ void loop() { * - FanExhaust (byte) Fan1 or Fan2 * - */ - -void controlPUMP() { - // UsePump true? - if (UsePump == true) { - - } -} + + diff --git a/Arduino/CanGrow/CanGrow_HTML.h b/Arduino/CanGrow/CanGrow_HTML.h index daa8db5..9d4f3e6 100644 --- a/Arduino/CanGrow/CanGrow_HTML.h +++ b/Arduino/CanGrow/CanGrow_HTML.h @@ -213,8 +213,8 @@ const char HTMLhelp[] PROGMEM = R"EOF(

❓ Help

Here you will get some helpful help.

API

-Sensor data: GET /api/sensors -Debug all data: GET /api/debug +Sensor data: GET /api/sensors
+Debug all data: GET /api/debug )EOF"; diff --git a/Arduino/CanGrow/CanGrow_Init.h b/Arduino/CanGrow/CanGrow_Init.h index f862724..d48c1ad 100644 --- a/Arduino/CanGrow/CanGrow_Init.h +++ b/Arduino/CanGrow/CanGrow_Init.h @@ -19,7 +19,7 @@ const bool APhidden = false; */ // valSoilmoisture - contains the value of getSoilmoisture() -byte valSoilmoisture; +unsigned short valSoilmoisture; // valTemperature - contains the value of getTemperature() float valTemperature; // valTemperature - contains the value of getHumidity() @@ -38,6 +38,13 @@ byte ScreenIterationPassed = 0; bool MaintenanceMode = false; unsigned long MaintenanceStarted = 0; +// helper variable to remember how many seconds the pump was +// already on within the actual watering cycle +byte PumpOnTimePassed = 0; +bool PumpOnManual = false; + +//unsigned short + /* * millis timer * @@ -81,6 +88,7 @@ byte MoistureSensor_Type; // SoilmoistureLow - contains the value , when soil moisture is assumed to be low, byte SoilmoistureLow = 80; // UsePump - is the pump used? bool +// PumpMode (short) 1: Pump on every n days, 2: Pump on when Soilmoisture <= SoilmoistureLow, 3: Both byte UsePump; // UseFan - is the fan used? bool // PumpOnTime in seconds @@ -96,8 +104,8 @@ unsigned short MaintenanceDuration = 300; char Esp32CamIP[16]; // PumpLastOn (long) timestamp unsigned long PumpLastOn; -// PumpMode (short) 1: Pump on every n days, 2: Pump on when Soilmoisture <= SoilmoistureLow, 3: Both -byte PumpMode = 1; + + // // Grow Stuff diff --git a/Arduino/CanGrow/CanGrow_Sensors.h b/Arduino/CanGrow/CanGrow_Sensors.h index d0d5031..96fed03 100644 --- a/Arduino/CanGrow/CanGrow_Sensors.h +++ b/Arduino/CanGrow/CanGrow_Sensors.h @@ -187,7 +187,13 @@ int getSoilmoisture(byte moistureSensor, bool returnRAW = false) { if(returnRAW == true) { return soilmoisture; } else { - return map(soilmoisture, wet, dry, 100, 0); + short soilmoistureP = map(soilmoisture, wet, dry, 100, 0); + // dont return negative percentage values + if(soilmoistureP < 0) { + return 0; + } else { + return soilmoistureP; + } } } diff --git a/Arduino/CanGrow/CanGrow_SysFunctions.h b/Arduino/CanGrow/CanGrow_SysFunctions.h index f4ae1d5..933e12a 100644 --- a/Arduino/CanGrow/CanGrow_SysFunctions.h +++ b/Arduino/CanGrow/CanGrow_SysFunctions.h @@ -106,7 +106,7 @@ bool loadEEPROM() { * 221 Esp32CamIP (16 byte) * 237 PumpLastOn (4 byte) * 241 PumpIntervalVeg (1 byte) - * 242 PumpIntervalVeg (1 byte) + * 242 PumpIntervalBloom (1 byte) * 243 ... * */ @@ -173,8 +173,7 @@ bool loadEEPROM() { EEPROM.get(221, Esp32CamIP); // size is 4 byte EEPROM.get(237, PumpLastOn); - // size is 1 byte - EEPROM.get(242, PumpMode); + } // TODO auth does not work atm // EEPROM.get(160, WebUiUsername); @@ -210,7 +209,9 @@ bool loadEEPROM() { EEPROM.get(217, SunFade); EEPROM.get(218, SunFadeDuration); // size is 1 byte - EEPROM.get(237, PumpIntervalVeg); + EEPROM.get(241, PumpIntervalVeg); + // size is 1 byte + EEPROM.get(242, PumpIntervalBloom); } @@ -369,6 +370,30 @@ void wifiAp() { //Serial.println("The login credentials for the WebUI are 'cangrow' for username and password"); } +unsigned short growState() { +/* + * growState() + * + * returns growState as short + * + * 1 - vegetation + * 2 - bloom + * 3 - harvest + * + */ + unsigned short state; + + if(DayOfGrow > (DaysVeg + DaysBloom ) ) { + state = 3; + } else if(DayOfGrow > DaysVeg ) { + state = 2; + } else { + state = 1; + } + + return state; +} + void setOutput(byte Output, byte OutputState) { /* * Pin assignments @@ -427,15 +452,22 @@ void controlLED() { unsigned int secondsSunrise = (SunriseHour * 60 * 60) + (SunriseMinute * 60); unsigned int secondsToday = (timeClient.getHours() * 60 * 60) + (timeClient.getMinutes() * 60) + timeClient.getSeconds(); - if(DayOfGrow > DaysVeg ) { - lightHours = LighthoursBloom; - } else { - lightHours = LighthoursVeg; + switch(growState()) { + case 1: + lightHours = LighthoursVeg; + break; + + case 2: + lightHours = LighthoursBloom; + break; + default: + lightHours = 0; + break; } // 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))) ) ){ + if( ((secondsToday >= secondsSunrise) && (secondsToday <= ( secondsSunrise + (lightHours * 60 * 60))) ) && (growState() < 3) ){ //Serial.println("light on time"); // when SunFade is true, fade LED light. Otherwise just turn on or off @@ -508,7 +540,8 @@ void displayScreens() { display.println("s"); } else { // in this switch case the single screens gets defined - switch(ScreenToDisplay) { + //switch(ScreenToDisplay) { + switch(0) { case 0: display.print("Humidity: "); display.print(valHumidity); @@ -576,26 +609,110 @@ void displayScreens() { } -unsigned short growState() { /* - * growState() + * Pump control * - * returns growState as short + * Vars: + * - UsePump (byte) + * - PumpOnTime (byte) in sec + * - SoilmoistureLow (byte) in % + * - PumpLastOn (long) timestamp + * - PumpMode (byte) 1: Pump on every n days, 2: Pump on when Soilmoisture <= SoilmoistureLow, 3: Both * - * 1 - vegetation - * 2 - bloom - * 3 - harvest + * - PumpIntervalVeg (byte) in days + * - PumpIntervalBloom (byte) in days * - */ - unsigned short state; + */ + +void controlPUMP() { + byte PumpInterval; - if(DayOfGrow > (DaysVeg + DaysBloom ) ) { - state = 3; - } else if(DayOfGrow > DaysVeg ) { - state = 2; - } else { - state = 1; + // UsePump true and not in harvest state? + if ( (UsePump > 0) && (growState() < 3) ) { + switch(growState()) { + case 1: + PumpInterval = PumpIntervalVeg; + break; + case 2: + PumpInterval = PumpIntervalBloom; + break; + default: + PumpInterval = 0; + break; + } + + // when PumpOnManuel is true, turn pump on for PumpOnTime seconds + if(PumpOnManual == true) { + if(PumpOnTimePassed < PumpOnTime) { + digitalWrite(PinPUMP, HIGH); + PumpOnTimePassed++; + } else { + PumpOnManual = false; + digitalWrite(PinPUMP, LOW); + PumpOnTimePassed = 0; + } + // otherwise check which PumpMode to use + } else { + switch(UsePump) { + case 1: + // when diff of time now and time pumpLastOn is greater then PumpInterval, do some watering (Or manual watering) + if( (timeClient.getEpochTime() - PumpLastOn) >= (PumpInterval) ) { // TODO: * 24 * 60 * 60 PumpInterval + // only water as long PumpOnTime + if(PumpOnTimePassed < PumpOnTime) { + digitalWrite(PinPUMP, HIGH); + PumpOnTimePassed++; + } else { + digitalWrite(PinPUMP, LOW); + PumpLastOn = timeClient.getEpochTime(); + // write the value to EEPROM for the case ESP gets restarted + EEPROM.put(237, PumpLastOn); + PumpOnTimePassed = 0; + } + } else { + digitalWrite(PinPUMP, LOW); + } + break; + + case 2: + // when valSoilmoisture is lower then SoilMoisture low do some watering + if( (valSoilmoisture < SoilmoistureLow) || ( (valSoilmoisture >= SoilmoistureLow) && ( (PumpOnTimePassed > 0) && (PumpOnTimePassed <= PumpOnTime) ) ) ) { + // check if we alerady exceeded max PumpOnTime + if(PumpOnTimePassed < PumpOnTime) { + digitalWrite(PinPUMP, HIGH); + PumpOnTimePassed++; + } else { + digitalWrite(PinPUMP, LOW); + PumpLastOn = timeClient.getEpochTime(); + PumpOnTimePassed = 0; + } + // when valSoilmoisture is greater then the Low value, + } else { + digitalWrite(PinPUMP, LOW); + } + break; + + // + case 3: + if( ( (timeClient.getEpochTime() - PumpLastOn) >= (PumpInterval) ) && //TODO calculate PumpInterval into days as well here + ( (valSoilmoisture < SoilmoistureLow) || + ( (valSoilmoisture >= SoilmoistureLow) && ( (PumpOnTimePassed > 0) && (PumpOnTimePassed <= PumpOnTime) ) ) + ) ) { + // check if we alerady exceeded max PumpOnTime + if(PumpOnTimePassed < PumpOnTime) { + digitalWrite(PinPUMP, HIGH); + PumpOnTimePassed++; + } else { + digitalWrite(PinPUMP, LOW); + PumpLastOn = timeClient.getEpochTime(); + PumpOnTimePassed = 0; + } + // when valSoilmoisture is greater then the Low value, + } else { + digitalWrite(PinPUMP, LOW); + } + break; + + } + } } - - return state; } diff --git a/Arduino/CanGrow/CanGrow_Version.h b/Arduino/CanGrow/CanGrow_Version.h index f5a7835..d2b8e33 100644 --- a/Arduino/CanGrow/CanGrow_Version.h +++ b/Arduino/CanGrow/CanGrow_Version.h @@ -1,5 +1,5 @@ /* CanGrow_Version.h gets generated from cangrow.sh */ const char* CanGrowVer = "0.1-dev"; -const char* CanGrowBuild = "d6bd0f7"; +const char* CanGrowBuild = "e1fcb09-20240616201039"; diff --git a/Arduino/CanGrow/CanGrow_WebFunctions.h b/Arduino/CanGrow/CanGrow_WebFunctions.h index 6054d52..5eb2f41 100644 --- a/Arduino/CanGrow/CanGrow_WebFunctions.h +++ b/Arduino/CanGrow/CanGrow_WebFunctions.h @@ -363,17 +363,17 @@ void WEBroot() { switch(growState()) { case 1: body += "🌱 vegetation
\n"; - break; + break; case 2: body += "🌼 bloom
\n"; - break; + break; case 3: - body += "🍂 harvest
\n"; - break; + body += "🍂 harvest\n"; + break; } - if(UsePump == true) { - body += "Pump water level: "; + if(UsePump > 0) { + body += "
Pump water level: "; switch(getWaterlevel()) { case 0: body += "OK"; @@ -472,19 +472,19 @@ void WEBgrowSettings() { body += "Vegetation duration: Days
\n"; + body+= "' required>days
\n"; body += "Bloom duration: Days
\n"; + body+= "' required> days
\n"; body += "Time LED ON vegetation: Hours
\n"; + body+= "' required> hours
\n"; body += "Time LED ON bloom: Hours
\n"; + body+= "' required> hours
\n"; body += "Sunrise: %
\n"; } + if(UsePump > 0) { + body += "Pump interval vegetation: days
\n"; + + body += "Pump interval bloom: days
\n"; + } + body += "\n"; body += "\n"; body += FPSTR(JSconvertDateToEpoch); @@ -569,10 +579,10 @@ void WEBsystemSettings() { // PumpMode byte body += "Pump mode:

1: Water every few days.
\ 2: Water if the soil moisture falls below Soilmoisture low value
\ 3: Water every few days if the soil moisture falls below Soilmoisture low value.

\n"; @@ -593,7 +603,7 @@ void WEBsystemSettings() { // TODO ugly. can this done be better? // PumpOnTime int - body += "PUMP ON time: Seconds
\n"; @@ -755,6 +765,8 @@ void POSTgrowSettings() { SunriseMinute = webserver.arg("SunriseMinute").toInt(); SunFade = webserver.arg("SunFade").toInt(); SunFadeDuration = webserver.arg("SunFadeDuration").toInt(); + PumpIntervalVeg = webserver.arg("PumpIntervalVeg").toInt(); + PumpIntervalBloom = webserver.arg("PumpIntervalBloom").toInt(); // size is 32 byte EEPROM.put(170, GrowName); @@ -778,6 +790,10 @@ void POSTgrowSettings() { EEPROM.put(216, PinFANPWM); EEPROM.put(217, SunFade); EEPROM.put(218, SunFadeDuration); + // size is 1 byte + EEPROM.put(241, PumpIntervalVeg); + // size is 1 byte + EEPROM.put(242, PumpIntervalBloom); EEPROM.commit(); @@ -1054,6 +1070,10 @@ void APIgetDebug() { objSystem["TemperatureSensor_Type"] = TemperatureSensor_Type; objSystem["NtpOffset"] = NtpOffset; objSystem["MaintenanceDuration"] = MaintenanceDuration; + objSystem["PumpOnTime"] = PumpOnTime; + objSystem["PumpOnTimePassed"] = PumpOnTimePassed; + objSystem["PumpOnManual"] = PumpOnManual; + objSystem["PumpLastOn"] = PumpLastOn; // Grow JsonObject objGrow = jsonDebug["grow"].add(); @@ -1071,7 +1091,8 @@ void APIgetDebug() { objGrow["PinLEDPWM"] = PinLEDPWM; objGrow["PinFANPWM"] = PinFANPWM; objGrow["DayOfGrow"] = DayOfGrow; - + objGrow["PumpIntervalVeg"] = PumpIntervalVeg; + objGrow["PumpIntervalBloom"] = PumpIntervalBloom; // Sensors