781 lines
22 KiB
C
781 lines
22 KiB
C
/*
|
|
*
|
|
*
|
|
* System Functions
|
|
*
|
|
*
|
|
*/
|
|
|
|
void wipeEEPROM() {
|
|
Serial.println(":: wipe EEPROM ::");
|
|
|
|
// wipeMsg is helper variable to know if the Serial.print Message was
|
|
// already sent
|
|
byte wipeMsg = 0;
|
|
while(digitalRead(PinWIPE) == LOW ) {
|
|
// only show the Serial message once
|
|
if(wipeMsg == 0) {
|
|
Serial.println("Please release PinWIPE to erase all data saved in EEPROM");
|
|
Serial.println("LAST CHANCE TO KEEP THE DATA BY RESETTING NOW!!");
|
|
|
|
display.clearDisplay();
|
|
display.setCursor(0,0);
|
|
display.println("!!!!!!!!!!!!!!!!!!!!!");
|
|
display.println("");
|
|
display.println("RELEASE PinWIPE");
|
|
display.println("TO WIPE EEPROM");
|
|
display.display();
|
|
|
|
// increase i to show the serial message only once
|
|
wipeMsg = 1;
|
|
}
|
|
delay(500);
|
|
}
|
|
|
|
// write a 0 to all 512 bytes of the EEPROM
|
|
Serial.print("wiping EEPROM... ");
|
|
display.println("Wiping EEPROM...");
|
|
display.println("Will restart in 3s");
|
|
display.display();
|
|
for (int i = 0; i < 512; i++) { EEPROM.write(i, 0); }
|
|
|
|
// commit everything to EEPROM and end here
|
|
EEPROM.end();
|
|
|
|
Serial.println("DONE");
|
|
|
|
// set D4 PinWIPE internal LED to Output to give feedback WIPE
|
|
// was done
|
|
pinMode(PinWIPE, OUTPUT);
|
|
|
|
Serial.println("!! Device will restart in 3 seconds !!");
|
|
|
|
// let the internal led blink fast to signalize wipe is done
|
|
for(byte i = 0; i <= 24 ; i++) {
|
|
if(i % 2) {
|
|
digitalWrite(PinWIPE, LOW);
|
|
} else {
|
|
digitalWrite(PinWIPE, HIGH);
|
|
}
|
|
delay(125);
|
|
}
|
|
ESP.restart();
|
|
}
|
|
|
|
|
|
bool loadEEPROM() {
|
|
/*
|
|
* EEPROM Save table
|
|
*
|
|
* 0 WIFIssid
|
|
* 32 WIFIpassword
|
|
* 96 WIFIip
|
|
* 112 WIFInetmask
|
|
* 128 WIFIgateway
|
|
* 144 WIFIdns
|
|
* 160 WIFIuseDHCP
|
|
*
|
|
* 161 configured
|
|
* 162 UseFan
|
|
* 163 UsePump
|
|
* 164 PumpOnTime
|
|
* 165 MoistureSensor_Type
|
|
* 166 SoilmoistureLow
|
|
* 167 NtpOffset
|
|
* 169 UseLEDrelais
|
|
*
|
|
* 170 GrowName
|
|
* 202 GrowStart
|
|
* 206 DaysVeg
|
|
* 207 DaysBloom
|
|
* 208 LighthoursVet
|
|
* 209 LighthoursBloom
|
|
* 210 SunriseHour
|
|
* 211 SunriseMinute
|
|
* 212 DayOfGrow
|
|
*
|
|
* -- afterwards added, need to sort --
|
|
*
|
|
* 213 PinLEDPWM
|
|
* 214 TemperatureSensor_Type
|
|
* 215 UseFANrelais
|
|
* 216 PinFANPWM
|
|
* 217 SunFade
|
|
* 218 SunFadeDuration
|
|
* 219 MaintenanceDuration (2 byte)
|
|
* 221 Esp32CamIP (16 byte)
|
|
* 237 PumpLastOn (4 byte)
|
|
* 241 PumpIntervalVeg (1 byte)
|
|
* 242 PumpIntervalBloom (1 byte)
|
|
* 243 OutputInvert (1 byte)
|
|
* 244 ...
|
|
*
|
|
*/
|
|
|
|
Serial.println(":: loading EEPROM ::");
|
|
|
|
display.setCursor(0,36);
|
|
display.fillRect(0,36,128,64-36, 0);
|
|
display.println("loading EEPROM");
|
|
display.display();
|
|
// read var WIFIssid from address 0, 32 byte long
|
|
// read this first, because we decide on the ssid length (>0?) if
|
|
// we run in unconfigured AP mode, nor not
|
|
EEPROM.get(0, WIFIssid);
|
|
|
|
// when length is > 0 then read furter EEPROM config data
|
|
if(strlen(WIFIssid)) {
|
|
/*
|
|
* WIFI settings
|
|
*/
|
|
|
|
// read var WIFIpassword from address 32, 64 byte long
|
|
EEPROM.get(32, WIFIpassword);
|
|
// read var WIFIip from address 96, 16 byte long
|
|
EEPROM.get(96, WIFIip);
|
|
// read var WIFInetmask from address 112, 16 byte long
|
|
EEPROM.get(112, WIFInetmask);
|
|
// read var WIFIgateway from address 128, 16 byte long
|
|
EEPROM.get(128, WIFIgateway);
|
|
// read var WIFIgateway from address 128, 16 byte long
|
|
EEPROM.get(144, WIFIdns);
|
|
// read var WIFIuseDHCP from Address 160, 1 byte long
|
|
EEPROM.get(160, WIFIuseDHCP);
|
|
|
|
|
|
/*
|
|
* System settings
|
|
*/
|
|
|
|
// size is 1 byte
|
|
EEPROM.get(161, configured);
|
|
if(configured == true) {
|
|
// size is 1 byte
|
|
EEPROM.get(162, UseFan);
|
|
// size is 1 byte
|
|
EEPROM.get(163, UsePump);
|
|
// size is 1 byte
|
|
EEPROM.get(164, PumpOnTime);
|
|
// size is 1 byte
|
|
EEPROM.get(165, MoistureSensor_Type);
|
|
// size is 1 byte
|
|
EEPROM.get(166, SoilmoistureLow);
|
|
// size is 2 byte
|
|
EEPROM.get(167, NtpOffset);
|
|
// size is 1 byte
|
|
EEPROM.get(169, UseLEDrelais);
|
|
// size is 1 byte
|
|
EEPROM.get(214, TemperatureSensor_Type);
|
|
// size is 1 byte
|
|
EEPROM.get(215, UseFANrelais);
|
|
// size is 2 byte
|
|
EEPROM.get(219, MaintenanceDuration);
|
|
// size is 16 byte
|
|
EEPROM.get(221, Esp32CamIP);
|
|
// size is 4 byte
|
|
EEPROM.get(237, PumpLastOn);
|
|
// size is 1 byte
|
|
EEPROM.get(243, OutputInvert);
|
|
|
|
}
|
|
// TODO auth does not work atm
|
|
// EEPROM.get(160, WebUiUsername);
|
|
// EEPROM.get(176, WebUiPassword);
|
|
|
|
/*
|
|
* Grow settings
|
|
*/
|
|
|
|
// size is 32 byte
|
|
EEPROM.get(170, GrowName);
|
|
if(strlen(GrowName) > 0) {
|
|
// size is 4 byte
|
|
EEPROM.get(202, GrowStart);
|
|
// size is 1 byte
|
|
EEPROM.get(206, DaysVeg);
|
|
// size is 1 byte
|
|
EEPROM.get(207, DaysBloom);
|
|
// size is 1 byte
|
|
EEPROM.get(208, LighthoursVeg);
|
|
// size is 1 byte
|
|
EEPROM.get(209, LighthoursBloom);
|
|
// size is 1 byte
|
|
EEPROM.get(210, SunriseHour);
|
|
// size is 1 byte
|
|
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);
|
|
// size is 1 byte
|
|
EEPROM.get(241, PumpIntervalVeg);
|
|
// size is 1 byte
|
|
EEPROM.get(242, PumpIntervalBloom);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// print values to Serial output
|
|
Serial.println("---- WiFi values ----");
|
|
Serial.print("WIFIssid: ");
|
|
Serial.println(WIFIssid);
|
|
Serial.print("WIFIpassword: ");
|
|
Serial.println(WIFIpassword);
|
|
Serial.print("Use DHCP: ");
|
|
Serial.println(WIFIuseDHCP);
|
|
|
|
Serial.println("---- System values ----");
|
|
Serial.print("configured: ");
|
|
Serial.println(configured);
|
|
Serial.print("UseFan: ");
|
|
Serial.println(UseFan);
|
|
Serial.print("UsePump: ");
|
|
Serial.println(UsePump);
|
|
Serial.print("PumpOnTime: ");
|
|
Serial.println(PumpOnTime);
|
|
Serial.print("MoistureSensor_Type: ");
|
|
Serial.println(MoistureSensor_Type);
|
|
Serial.print("TemperatureSensor_Type: ");
|
|
Serial.println(TemperatureSensor_Type);
|
|
Serial.print("SoilmoistureLow: ");
|
|
Serial.println(SoilmoistureLow);
|
|
Serial.print("NtpOffset: ");
|
|
Serial.println(NtpOffset);
|
|
Serial.print("UseLEDrelais: ");
|
|
Serial.println(UseLEDrelais);
|
|
Serial.print("UseFANrelais: ");
|
|
Serial.println(UseFANrelais);
|
|
Serial.print("MaintenanceDuration: ");
|
|
Serial.println(MaintenanceDuration);
|
|
Serial.print("PumpLastOn: ");
|
|
Serial.println(PumpLastOn);
|
|
Serial.print("OutputInvert: ");
|
|
Serial.println(OutputInvert);
|
|
|
|
Serial.println("---- Grow values ----");
|
|
Serial.print("GrowName: ");
|
|
Serial.println(GrowName);
|
|
Serial.print("GrowStart: ");
|
|
Serial.println(GrowStart);
|
|
Serial.print("DaysVeg: ");
|
|
Serial.println(DaysVeg);
|
|
Serial.print("DaysBloom: ");
|
|
Serial.println(DaysBloom);
|
|
Serial.print("LighthoursVeg: ");
|
|
Serial.println(LighthoursVeg);
|
|
Serial.print("LighthoursBloom: ");
|
|
Serial.println(LighthoursBloom);
|
|
Serial.print("SunriseHour: ");
|
|
Serial.println(SunriseHour);
|
|
Serial.print("SunriseMinute: ");
|
|
Serial.println(SunriseMinute);
|
|
Serial.print("DayOfGrow: ");
|
|
Serial.println(DayOfGrow);
|
|
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 {
|
|
Serial.println("EEPROM value WIFIssid is empty");
|
|
}
|
|
Serial.println(":: EEPROM loaded ::");
|
|
|
|
display.setCursor(0,42);
|
|
display.println("EEPROM loaded");
|
|
display.display();
|
|
|
|
return(strlen(WIFIssid));
|
|
}
|
|
|
|
void wifiConnect() {
|
|
Serial.println(":: Connecting to WiFi ::");
|
|
FirstRun = false;
|
|
Serial.print("SSID: ");
|
|
Serial.println(WIFIssid);
|
|
|
|
display.fillRect(0,36,128,64-36, 0);
|
|
display.setCursor(0,36);
|
|
display.println("Connecting to WiFi");
|
|
display.println(WIFIssid);
|
|
display.display();
|
|
|
|
// Start WiFi connection
|
|
WiFi.begin(WIFIssid, WIFIpassword);
|
|
if(WIFIuseDHCP == false) {
|
|
WiFi.config(WIFIip, WIFIdns, WIFIgateway, WIFInetmask);
|
|
}
|
|
|
|
// wait until WiFi connection is established
|
|
while (WiFi.status() != WL_CONNECTED) {
|
|
delay(500);
|
|
Serial.print(".");
|
|
}
|
|
Serial.println(" CONNECTED!");
|
|
Serial.print("IP: ");
|
|
Serial.println(WiFi.localIP());
|
|
|
|
Serial.println(":: Getting time from NTP ::");
|
|
display.fillRect(0,36,128,64-36, 0);
|
|
display.setCursor(0,36);
|
|
display.println("Getting NTP time");
|
|
display.display();
|
|
|
|
timeClient.begin();
|
|
timeClient.setTimeOffset(NtpOffset * 60 * 60);
|
|
timeClient.update();
|
|
while ( ! timeClient.isTimeSet()) {
|
|
timeClient.update();
|
|
delay(500);
|
|
Serial.print(".");
|
|
}
|
|
|
|
Serial.println(timeClient.getFormattedTime());
|
|
Serial.println(timeClient.getEpochTime());
|
|
display.println(timeClient.getFormattedTime());
|
|
display.display();
|
|
display.print("IP: ");
|
|
display.print(WiFi.localIP());
|
|
display.display();
|
|
}
|
|
|
|
void wifiAp() {
|
|
Serial.println(":: Creating Accesspoint ::");
|
|
|
|
display.fillRect(0,36,128,64-36, 0);
|
|
display.setCursor(0,36);
|
|
display.println("Creating AccessPoint");
|
|
display.println(APssid);
|
|
display.display();
|
|
|
|
FirstRun = true;
|
|
// configure WiFi Access Point
|
|
WiFi.softAPConfig(WIFIip, WIFIgateway, WIFInetmask);
|
|
// start Access Point
|
|
// TODO make AP with password - does not work atm. idk why.
|
|
WiFi.softAP(APssid);
|
|
Serial.print("SSID: ");
|
|
Serial.println(APssid);
|
|
Serial.print("CanGrow IP address: ");
|
|
Serial.println(WiFi.softAPIP());
|
|
|
|
display.print("IP: ");
|
|
display.println(WiFi.softAPIP());
|
|
display.display();
|
|
// TODO does not work atm, idk why
|
|
//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) {
|
|
/*
|
|
* Output assignments
|
|
*
|
|
* 1 - LED
|
|
* 2 - FAN
|
|
* 3 - PUMP
|
|
*
|
|
*/
|
|
bool UseRelais = true;
|
|
byte OutputPin;
|
|
byte OutputState_tmp;
|
|
|
|
switch(Output) {
|
|
case 1:
|
|
OutputPin = PinLED;
|
|
if(UseLEDrelais == true) {
|
|
UseRelais = true;
|
|
} else {
|
|
UseRelais = false;
|
|
}
|
|
break;
|
|
case 2:
|
|
OutputPin = PinFAN;
|
|
if(UseFANrelais == true) {
|
|
UseRelais = true;
|
|
} else {
|
|
UseRelais = false;
|
|
}
|
|
break;
|
|
// PUMP Pin (D0) does not support PWM, so we do not need to care about
|
|
case 3:
|
|
OutputPin = PinPUMP;
|
|
break;
|
|
}
|
|
|
|
//~ Serial.print("Output: ");
|
|
//~ Serial.println(Output);
|
|
//~ Serial.print("OutputPin: ");
|
|
//~ Serial.println(OutputPin);
|
|
//~ Serial.print("OutputState: ");
|
|
//~ Serial.println(OutputState);
|
|
//~ Serial.print("UseRelais: ");
|
|
//~ Serial.println(UseRelais);
|
|
|
|
// TODO read config for inverted outputs
|
|
|
|
if( (UseRelais == true) || (OutputPin == PinPUMP) ) {
|
|
// convert OutputState to bool when using relais, so we can invert it easy
|
|
bool OutputState_bool = OutputState;
|
|
if(OutputInvert == true) {
|
|
OutputState_tmp = 1 - OutputState_bool;
|
|
} else {
|
|
OutputState_tmp = OutputState_bool;
|
|
}
|
|
digitalWrite(OutputPin, OutputState_tmp);
|
|
} else {
|
|
if(OutputInvert == true) {
|
|
OutputState_tmp = 255 - OutputState;
|
|
} else {
|
|
OutputState_tmp = OutputState;
|
|
}
|
|
analogWrite(OutputPin, OutputState_tmp);
|
|
}
|
|
}
|
|
|
|
|
|
void controlLED() {
|
|
byte lightHours;
|
|
byte PinLEDPWM_tmp;
|
|
unsigned int secondsSunrise = (SunriseHour * 60 * 60) + (SunriseMinute * 60);
|
|
unsigned int secondsToday = (timeClient.getHours() * 60 * 60) + (timeClient.getMinutes() * 60) + timeClient.getSeconds();
|
|
|
|
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))) ) && (growState() < 3) ){
|
|
//Serial.println("light on time");
|
|
|
|
// when SunFade is true, fade LED light. Otherwise just turn on or off
|
|
if( (SunFade == true) && (UseLEDrelais == false) && (secondsSunrise + SunFadeDuration * 60 >= secondsToday) ) {
|
|
// in the first n minutes of lighting (SunFadeDuration), we want
|
|
// to raise the light slowly to prevent stress from the plant
|
|
// convert progress sunrise to PWM value
|
|
PinLEDPWM_tmp = (SunFadeDuration * 60 - ((secondsSunrise + SunFadeDuration * 60) - secondsToday)) * PinLEDPWM / (SunFadeDuration * 60);
|
|
setOutput(1, PinLEDPWM_tmp);
|
|
//Serial.print("sunrise PWM; ");
|
|
//Serial.println(PinLEDPWM_tmp);
|
|
|
|
} else if( (SunFade == true) && (UseLEDrelais == false) && (secondsToday >= ((secondsSunrise + lightHours * 60 * 60) - SunFadeDuration * 60) ) ) {
|
|
// calculate progress sunset to PWM value
|
|
PinLEDPWM_tmp = (secondsSunrise + (lightHours * 60 * 60) - secondsToday) * PinLEDPWM / (SunFadeDuration * 60);
|
|
setOutput(1, PinLEDPWM_tmp);
|
|
//Serial.print("sunset PWM: ");
|
|
//Serial.println(PinLEDPWM_tmp);
|
|
|
|
} else {
|
|
//Serial.println("just turn on the light");
|
|
// no sunrise or sunset, just keep the LED turned on
|
|
setOutput(1, PinLEDPWM);
|
|
}
|
|
|
|
} else {
|
|
//Serial.println("good night time");
|
|
// turn off
|
|
setOutput(1, 0);
|
|
}
|
|
}
|
|
|
|
void refreshSensors() {
|
|
byte soilmoistureAvgSampleCount = 5;
|
|
|
|
valSoilmoisture = getSoilmoisture(MoistureSensor_Type);
|
|
valHumidity = getHumidity();
|
|
valTemperature = getTemperature(TemperatureSensor_Type);
|
|
valWaterlevel = getWaterlevel();
|
|
|
|
// get average of 5 readings for valSoilmoisture
|
|
valSoilmoistureAvg_tmp = valSoilmoistureAvg_tmp + valSoilmoisture;
|
|
if(valSoilmoistureAvg_count < soilmoistureAvgSampleCount - 1) {
|
|
valSoilmoistureAvg_count++;
|
|
} else {
|
|
// build average
|
|
valSoilmoistureAvg = valSoilmoistureAvg_tmp / soilmoistureAvgSampleCount;
|
|
// reset everything
|
|
valSoilmoistureAvg_tmp = 0;
|
|
valSoilmoistureAvg_count = 0;
|
|
|
|
}
|
|
}
|
|
|
|
void displayScreens() {
|
|
/*
|
|
* which screen to display
|
|
* interate through different screens
|
|
*
|
|
*/
|
|
if(ScreenIterationPassed > DisplayScreenDuration){
|
|
ScreenIterationPassed = 0;
|
|
// helper variable, maybe i find a better way in future
|
|
byte LastScreen = 2;
|
|
// when the next screen gets displayed, clear display
|
|
display.clearDisplay();
|
|
display.display();
|
|
// when ScreenToDisplay has reach last number of screens, reset to first (0)
|
|
if(ScreenToDisplay >= LastScreen) {
|
|
ScreenToDisplay = 0;
|
|
} else {
|
|
ScreenToDisplay++;
|
|
}
|
|
}
|
|
|
|
display.setCursor(0,0);
|
|
|
|
if(MaintenanceMode == true) {
|
|
display.drawBitmap(0, 0, bmpCanGrow_Logo, 128, 32, WHITE);
|
|
display.display();
|
|
display.setCursor(0,32);
|
|
display.println("Maintenance mode active");
|
|
display.print("Time left: ");
|
|
display.print(MaintenanceDuration - ((millis() - MaintenanceStarted) / 1000));
|
|
display.println("s");
|
|
} else {
|
|
// in this switch case the single screens gets defined
|
|
//switch(ScreenToDisplay) {
|
|
switch(0) {
|
|
case 0:
|
|
display.print("Humidity: ");
|
|
display.print(valHumidity);
|
|
display.println(" %");
|
|
display.println("");
|
|
display.print("Temperature: ");
|
|
display.print(valTemperature);
|
|
display.println(" C");
|
|
display.println("");
|
|
display.print("Moisture: ");
|
|
display.print(valSoilmoisture);
|
|
display.print(" % ");
|
|
display.println(valSoilmoistureAvg);
|
|
display.println("");
|
|
if(UsePump > 0) {
|
|
display.print("Pump Waterlvl: ");
|
|
switch(valWaterlevel) {
|
|
case 0:
|
|
display.println("OK");
|
|
break;
|
|
case 1:
|
|
display.println("Warn");
|
|
break;
|
|
case 2:
|
|
display.println("Crit");
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 1:
|
|
display.print("LED: ");
|
|
display.print(PinLEDPWM * 100 / 255);
|
|
display.println(" %");
|
|
display.print("State: ");
|
|
display.println(digitalRead(PinLED));
|
|
display.println("");
|
|
display.print("FAN: ");
|
|
display.print(PinFANPWM * 100 / 255);
|
|
display.println(" %");
|
|
display.print("State: ");
|
|
display.println(digitalRead(PinFAN));
|
|
display.println("");
|
|
display.print("Pump state: ");
|
|
display.println(digitalRead(PinPUMP));
|
|
break;
|
|
|
|
case 2:
|
|
// display Logo
|
|
display.drawBitmap(0, 0, bmpCanGrow_Logo, 128, 32, WHITE);
|
|
display.display();
|
|
display.setCursor(0,32);
|
|
display.println(GrowName);
|
|
display.print("DoG: ");
|
|
display.print(DayOfGrow);
|
|
display.print(", ");
|
|
display.println(timeClient.getFormattedTime());
|
|
display.print("IP: ");
|
|
display.println(WiFi.localIP());
|
|
break;
|
|
}
|
|
}
|
|
ScreenIterationPassed++;
|
|
display.display();
|
|
|
|
}
|
|
|
|
|
|
/*
|
|
* Pump control
|
|
*
|
|
* 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
|
|
*
|
|
* - PumpIntervalVeg (byte) in days
|
|
* - PumpIntervalBloom (byte) in days
|
|
*
|
|
*/
|
|
|
|
void controlPUMP() {
|
|
byte PumpInterval;
|
|
|
|
// UsePump true and not in harvest state?
|
|
// dont water within the first 15 sec after startup
|
|
if ( (UsePump > 0) && (growState() < 3) && (millis() > 15000) ) {
|
|
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) {
|
|
setOutput(3, 1);
|
|
//digitalWrite(PinPUMP, HIGH);
|
|
PumpOnTimePassed++;
|
|
} else {
|
|
PumpOnManual = false;
|
|
setOutput(3, 0);
|
|
//digitalWrite(PinPUMP, LOW);
|
|
EEPROM.put(237, PumpLastOn);
|
|
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 * 24 * 60 *60) ) { // PumpInterval to, Days * 24 * 60 * 60
|
|
// only water as long PumpOnTime
|
|
if(PumpOnTimePassed < PumpOnTime) {
|
|
setOutput(3, 1);
|
|
//digitalWrite(PinPUMP, HIGH);
|
|
PumpOnTimePassed++;
|
|
} else {
|
|
setOutput(3, 0);
|
|
//digitalWrite(PinPUMP, LOW);
|
|
PumpLastOn = timeClient.getEpochTime();
|
|
// write the value to EEPROM for the case ESP gets restarted
|
|
EEPROM.put(237, PumpLastOn);
|
|
EEPROM.commit(); //write to EEPROM
|
|
PumpOnTimePassed = 0;
|
|
}
|
|
} else {
|
|
setOutput(3, 0);
|
|
//digitalWrite(PinPUMP, LOW);
|
|
}
|
|
break;
|
|
|
|
case 2:
|
|
// when valSoilmoistureAvg is lower then SoilMoisture low do some watering
|
|
if( (valSoilmoistureAvg < SoilmoistureLow) || ( (valSoilmoistureAvg >= SoilmoistureLow) && ( (PumpOnTimePassed > 0) && (PumpOnTimePassed <= PumpOnTime) ) ) ) {
|
|
// check if we alerady exceeded max PumpOnTime
|
|
if(PumpOnTimePassed < PumpOnTime) {
|
|
setOutput(3, 1);
|
|
//digitalWrite(PinPUMP, HIGH);
|
|
PumpOnTimePassed++;
|
|
} else {
|
|
setOutput(3, 0);
|
|
//digitalWrite(PinPUMP, LOW);
|
|
PumpLastOn = timeClient.getEpochTime();
|
|
PumpOnTimePassed = 0;
|
|
}
|
|
// when valSoilmoistureAvg is greater then the Low value,
|
|
} else {
|
|
setOutput(3, 0);
|
|
//digitalWrite(PinPUMP, LOW);
|
|
}
|
|
break;
|
|
|
|
//
|
|
case 3:
|
|
if( ( (timeClient.getEpochTime() - PumpLastOn) >= (PumpInterval * 24 * 60 *60) ) && // PumpInterval to, Days * 24 * 60 * 60
|
|
( (valSoilmoistureAvg < SoilmoistureLow) ||
|
|
( (valSoilmoistureAvg >= SoilmoistureLow) && ( (PumpOnTimePassed > 0) && (PumpOnTimePassed <= PumpOnTime) ) )
|
|
) ) {
|
|
// check if we alerady exceeded max PumpOnTime
|
|
if(PumpOnTimePassed < PumpOnTime) {
|
|
setOutput(3, 1);
|
|
//digitalWrite(PinPUMP, HIGH);
|
|
PumpOnTimePassed++;
|
|
} else {
|
|
setOutput(3, 0);
|
|
//digitalWrite(PinPUMP, LOW);
|
|
PumpLastOn = timeClient.getEpochTime();
|
|
EEPROM.put(237, PumpLastOn);
|
|
PumpOnTimePassed = 0;
|
|
}
|
|
// when valSoilmoistureAvg is greater then the Low value,
|
|
} else {
|
|
setOutput(3, 0);
|
|
//digitalWrite(PinPUMP, LOW);
|
|
}
|
|
break;
|
|
|
|
}
|
|
}
|
|
} else {
|
|
// ensure pump is off when it should be off
|
|
setOutput(3, 0);
|
|
//digitalWrite(PinPUMP, LOW);
|
|
}
|
|
}
|
|
|
|
|
|
void controlFAN() {
|
|
setOutput(2, PinFANPWM); //inverted pwm
|
|
}
|
|
|