firmware wip - add pump control
This commit is contained in:
parent
e1fcb09ae7
commit
54fec62a3e
7 changed files with 205 additions and 70 deletions
|
@ -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
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/*
|
||||
|
@ -294,12 +282,7 @@ void loop() {
|
|||
* -
|
||||
*/
|
||||
|
||||
void controlPUMP() {
|
||||
// UsePump true?
|
||||
if (UsePump == true) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -213,8 +213,8 @@ const char HTMLhelp[] PROGMEM = R"EOF(
|
|||
<h2>❓ Help</h2>
|
||||
Here you will get some helpful help.
|
||||
<h3>API</h3>
|
||||
Sensor data: <code>GET /api/sensors</code>
|
||||
Debug all data: <code>GET /api/debug</code>
|
||||
<a href='/api/sensors' target='_blank'>Sensor data</a>: <code>GET /api/sensors</code><br>
|
||||
<a href='/api/debug' target='_blank'>Debug all data:</a> <code>GET /api/debug</code>
|
||||
)EOF";
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
if(DayOfGrow > (DaysVeg + DaysBloom ) ) {
|
||||
state = 3;
|
||||
} else if(DayOfGrow > DaysVeg ) {
|
||||
state = 2;
|
||||
} else {
|
||||
state = 1;
|
||||
void controlPUMP() {
|
||||
byte PumpInterval;
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
|
|
@ -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";
|
||||
|
||||
|
|
|
@ -363,17 +363,17 @@ void WEBroot() {
|
|||
switch(growState()) {
|
||||
case 1:
|
||||
body += "🌱 vegetation<br>\n";
|
||||
break;
|
||||
break;
|
||||
case 2:
|
||||
body += "🌼 bloom<br>\n";
|
||||
break;
|
||||
break;
|
||||
case 3:
|
||||
body += "🍂 harvest<br>\n";
|
||||
break;
|
||||
body += "🍂 harvest\n";
|
||||
break;
|
||||
}
|
||||
|
||||
if(UsePump == true) {
|
||||
body += "<b>Pump water level:</b> ";
|
||||
if(UsePump > 0) {
|
||||
body += "<br><b>Pump water level:</b> ";
|
||||
switch(getWaterlevel()) {
|
||||
case 0:
|
||||
body += "<span style='color: green;'>OK</span>";
|
||||
|
@ -472,19 +472,19 @@ void WEBgrowSettings() {
|
|||
|
||||
body += "Vegetation duration: <input class='inputShort' type='number' name='DaysVeg' min='0' max='255' value='";
|
||||
body += DaysVeg;
|
||||
body+= "' required>Days<br>\n";
|
||||
body+= "' required>days<br>\n";
|
||||
|
||||
body += "Bloom duration: <input class='inputShort' type='number' name='DaysBloom' min='0' max='255' value='";
|
||||
body += DaysBloom;
|
||||
body+= "' required> Days<br>\n";
|
||||
body+= "' required> days<br>\n";
|
||||
|
||||
body += "Time LED ON vegetation: <input class='inputShort' type='number' name='LighthoursVeg' min='0' max='255' value='";
|
||||
body += LighthoursVeg;
|
||||
body+= "' required> Hours<br>\n";
|
||||
body+= "' required> hours<br>\n";
|
||||
|
||||
body += "Time LED ON bloom: <input class='inputShort' type='number' name='LighthoursBloom' min='0' max='255' value='";
|
||||
body += LighthoursBloom;
|
||||
body+= "' required> Hours<br>\n";
|
||||
body+= "' required> hours<br>\n";
|
||||
|
||||
body += "Sunrise: <input class='inputShort' type='number' name='SunriseHour' min='0' max='23' value='";
|
||||
body += SunriseHour;
|
||||
|
@ -515,6 +515,16 @@ void WEBgrowSettings() {
|
|||
body += "'/> %<br>\n";
|
||||
}
|
||||
|
||||
if(UsePump > 0) {
|
||||
body += "Pump interval vegetation: <input class='inputShort' type='number' name='PumpIntervalVeg' min='0' max='255' value='";
|
||||
body += PumpIntervalVeg;
|
||||
body+= "' required>days<br>\n";
|
||||
|
||||
body += "Pump interval bloom: <input class='inputShort' type='number' name='PumpIntervalBloom' min='0' max='255' value='";
|
||||
body += PumpIntervalBloom;
|
||||
body+= "' required>days<br>\n";
|
||||
}
|
||||
|
||||
body += "<input type='submit' value='💾 Save settings'>\n";
|
||||
body += "</form>\n";
|
||||
body += FPSTR(JSconvertDateToEpoch);
|
||||
|
@ -569,10 +579,10 @@ void WEBsystemSettings() {
|
|||
// PumpMode byte
|
||||
body += "Pump mode: <select id='UsePump' name='UsePump' required>\n";
|
||||
if(configured == false){body += "<option disabled value='' selected hidden>---</option>\n";}
|
||||
body += "<option value='1'" + returnStrSelected(UsePump, 0) + ">Off</option>\n";
|
||||
body += "<option value='0'" + returnStrSelected(UsePump, 0) + ">Off</option>\n";
|
||||
body += "<option value='1'" + returnStrSelected(UsePump, 1) + ">1</option>\n";
|
||||
body += "<option value='1'" + returnStrSelected(UsePump, 2) + ">2</option>\n";
|
||||
body += "<option value='0'" + returnStrSelected(UsePump, 3) + ">3</option>\n";
|
||||
body += "<option value='2'" + returnStrSelected(UsePump, 2) + ">2</option>\n";
|
||||
body += "<option value='3'" + returnStrSelected(UsePump, 3) + ">3</option>\n";
|
||||
body += "</select><br><p class='helpbox'><b>1:</b> Water every few days.<br> \
|
||||
<b>2:</b> Water if the soil moisture falls below <i>Soilmoisture low</i> value<br> \
|
||||
<b>3:</b> Water every few days if the soil moisture falls below <i>Soilmoisture low</i> value.</p>\n";
|
||||
|
@ -593,7 +603,7 @@ void WEBsystemSettings() {
|
|||
|
||||
// TODO ugly. can this done be better?
|
||||
// PumpOnTime int
|
||||
body += "PUMP ON time: <input class='inputShort' type='number' name='PumpOnTime' min='0' max='255' value='";
|
||||
body += "Pump ON time: <input class='inputShort' type='number' name='PumpOnTime' min='0' max='255' value='";
|
||||
body += PumpOnTime;
|
||||
body += "' required> Seconds<br>\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<JsonObject>();
|
||||
|
@ -1071,7 +1091,8 @@ void APIgetDebug() {
|
|||
objGrow["PinLEDPWM"] = PinLEDPWM;
|
||||
objGrow["PinFANPWM"] = PinFANPWM;
|
||||
objGrow["DayOfGrow"] = DayOfGrow;
|
||||
|
||||
objGrow["PumpIntervalVeg"] = PumpIntervalVeg;
|
||||
objGrow["PumpIntervalBloom"] = PumpIntervalBloom;
|
||||
|
||||
|
||||
// Sensors
|
||||
|
|
Loading…
Reference in a new issue