firmware wip - add sun fading , some reorganizing

This commit is contained in:
Marcus 2024-04-30 00:54:08 +02:00
parent 7842fadb15
commit eb0f91e313

View file

@ -95,7 +95,7 @@ char WebUiPassword[32] = "cangrow";
// configured - if false, let the user configure system settings first // configured - if false, let the user configure system settings first
bool configured = false; bool configured = false;
// NTP Offset // NTP Offset
short ntpOffset; short NtpOffset;
// MoistureSensor_Type - contains which moisture sensor to use // MoistureSensor_Type - contains which moisture sensor to use
// 1: analog capacitive sensor // 1: analog capacitive sensor
// 2: I2C chirp sensor from catnip electronics // 2: I2C chirp sensor from catnip electronics
@ -138,10 +138,14 @@ byte LighthoursBloom = 12;
byte SunriseHour = 7; byte SunriseHour = 7;
// SunriseHour - contains to which minute of SunriseHour the growlight turns on // SunriseHour - contains to which minute of SunriseHour the growlight turns on
byte SunriseMinute = 0; 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 // default is 255 to ensure it is just on for the case UseLEDrelais is true
byte PINled_PWM = 255; byte PINledPWM = 255;
byte PINfan_PWM = 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 * Pin assignments
* *
* D0 - MOSFET Fan * D0 - MOSFET Pump
* D1, D2 - I2C * D1, D2 - I2C
* D3 - DHT11 * D3 - DHT11
* D4 - PIN_WIPE * D4 - PIN_WIPE
* D5 - MOSFET Pump * D5 - MOSFET Fan
* D6 - MOSFET Grow LED, PWM * D6 - MOSFET Grow LED, PWM
* D7 - waterlevel (set HIGH to read value) * D7 - waterlevel (set HIGH to read value)
* D8 - analog soil moisture (set HIGH to read value) * D8 - analog soil moisture (set HIGH to read value)
@ -692,7 +696,7 @@ bool loadEEPROM() {
* 164 PumpOnTime * 164 PumpOnTime
* 165 MoistureSensor_Type * 165 MoistureSensor_Type
* 166 SoilmoistureLow * 166 SoilmoistureLow
* 167 ntpOffset * 167 NtpOffset
* 169 UseLEDrelais * 169 UseLEDrelais
* *
* 170 GrowName * 170 GrowName
@ -707,10 +711,12 @@ bool loadEEPROM() {
* *
* -- afterwards added, need to sort -- * -- afterwards added, need to sort --
* *
* 213 PINled_PWM * 213 PINledPWM
* 214 TemperatureSensor_Type * 214 TemperatureSensor_Type
* 215 UseFANrelais * 215 UseFANrelais
* 216 PINfan_PWM * 216 PINfanPWM
* 217 SunFade
* 218 SunFadeDuration
* *
*/ */
@ -763,20 +769,13 @@ bool loadEEPROM() {
// size is 1 byte // size is 1 byte
EEPROM.get(166, SoilmoistureLow); EEPROM.get(166, SoilmoistureLow);
// size is 2 byte // size is 2 byte
EEPROM.get(167, ntpOffset); EEPROM.get(167, NtpOffset);
// size is 1 byte // size is 1 byte
EEPROM.get(169, UseLEDrelais); EEPROM.get(169, UseLEDrelais);
// size is 1 byte // 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); EEPROM.get(214, TemperatureSensor_Type);
// size is 1 byte // size is 1 byte
EEPROM.get(215, UseFANrelais); EEPROM.get(215, UseFANrelais);
// size is 1 byte
EEPROM.get(216, PINfan_PWM);
} }
// TODO auth does not work atm // TODO auth does not work atm
// EEPROM.get(160, WebUiUsername); // EEPROM.get(160, WebUiUsername);
@ -805,6 +804,12 @@ bool loadEEPROM() {
EEPROM.get(211, SunriseMinute); EEPROM.get(211, SunriseMinute);
// size is 1 byte // size is 1 byte
EEPROM.get(212, DayOfGrow); 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.println(MoistureSensor_Type);
Serial.print("SoilmoistureLow: "); Serial.print("SoilmoistureLow: ");
Serial.println(SoilmoistureLow); Serial.println(SoilmoistureLow);
Serial.print("ntpOffset: "); Serial.print("NtpOffset: ");
Serial.println(ntpOffset); Serial.println(NtpOffset);
Serial.print("UseLEDrelais: "); Serial.print("UseLEDrelais: ");
Serial.println(UseLEDrelais); Serial.println(UseLEDrelais);
Serial.print("UseFANrelais: "); Serial.print("UseFANrelais: ");
@ -859,10 +864,14 @@ bool loadEEPROM() {
Serial.println(SunriseMinute); Serial.println(SunriseMinute);
Serial.print("DayOfGrow: "); Serial.print("DayOfGrow: ");
Serial.println(DayOfGrow); Serial.println(DayOfGrow);
Serial.print("PINled_PWM: "); Serial.print("PINledPWM: ");
Serial.println(PINled_PWM); Serial.println(PINledPWM);
Serial.print("PINfan_PWM: "); Serial.print("PINfanPWM: ");
Serial.println(PINfan_PWM); Serial.println(PINfanPWM);
Serial.print("SunFade: ");
Serial.println(SunFade);
Serial.print("SunFadeDuration: ");
Serial.println(SunFadeDuration);
} else { } else {
@ -911,7 +920,7 @@ void wifiConnect() {
display.display(); display.display();
timeClient.begin(); timeClient.begin();
timeClient.setTimeOffset(ntpOffset * 60 * 60); timeClient.setTimeOffset(NtpOffset * 60 * 60);
timeClient.update(); timeClient.update();
while ( ! timeClient.isTimeSet()) { while ( ! timeClient.isTimeSet()) {
timeClient.update(); timeClient.update();
@ -951,6 +960,51 @@ void wifiAp() {
//Serial.println("The login credentials for the WebUI are 'cangrow' for username and password"); //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 * Setup
* *
@ -1068,8 +1122,9 @@ void setup() {
// set web handler // set web handler
WebHandler(); WebHandler();
// start webserver // 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 int secondsToday = (timeClient.getHours() * 60 * 60) + (timeClient.getMinutes() * 60) + timeClient.getSeconds();
unsigned long currentRuntime = millis(); unsigned long currentRuntime = millis();
byte lightHours; byte lightHours;
byte PINledPWM_tmp;
// first we call webserver handle client // first we call webserver handle client
webserver.handleClient(); 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) ){ if( (configured == true) && (strlen(GrowName) > 0) && (currentRuntime - outputPrevTime >= 1000) ){
// debug output /*
Serial.print("secondsSunrise: "); * LED controlling
Serial.println(secondsSunrise); */
Serial.print("secondsToday: ");
Serial.println(secondsToday);
//Serial.println("yolo");
// calculate acutal DayOfGrow // calculate acutal DayOfGrow
DayOfGrow = int(ceil(float((timeClient.getEpochTime() - GrowStart) / 60 / 60 / 24))); DayOfGrow = int(ceil(float((timeClient.getEpochTime() - GrowStart) / 60 / 60 / 24)));
@ -1109,17 +1162,31 @@ void loop() {
lightHours = LighthoursVeg; lightHours = LighthoursVeg;
} }
// check if secondsToday is larger then secondsSunrise time AND if secondsToday is smaller then the sum of secondsSunrise + seconds of lightHours // check if secondsToday is larger then secondsSunrise time AND if
if( (secondsToday >= secondsSunrise) && (secondsToday <= ( secondsSunrise + (lightHours * 60 * 60) ) )){ // secondsToday is smaller then the sum of secondsSunrise + seconds of lightHours
// turn on light 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 { } else {
// turn off // turn off
digitalWrite(PINled, LOW); setOutput(1, 0);
} }
// current time gets previous time for new interval
outputPrevTime = currentRuntime; outputPrevTime = currentRuntime;
} }
@ -1176,7 +1243,7 @@ void WebHandler() {
webserver.onNotFound(WEB404); webserver.onNotFound(WEB404);
// switching MOSFETs // switching MOSFETs
webserver.on("/switch", HTTP_POST, POSTswitchMOSFET); webserver.on("/switch", HTTP_POST, POSTsetOutput);
// api stuff // api stuff
webserver.on("/api/sensors", HTTP_GET, APIgetSensors); webserver.on("/api/sensors", HTTP_GET, APIgetSensors);
@ -1433,7 +1500,7 @@ void WEBroot() {
} }
body += "<br>"; body += "<br>";
body += "Growlight brightnes: "; body += "Growlight brightnes: ";
body += ((PINled_PWM * 100) / 255); body += ((PINledPWM * 100) / 255);
body += " %<br>"; body += " %<br>";
body += "<form method='post' action='/switch'>"; body += "<form method='post' action='/switch'>";
body += "MOSFET<select id='output' name='output' required>\n"; body += "MOSFET<select id='output' name='output' required>\n";
@ -1450,8 +1517,8 @@ void WEBroot() {
body += "</select><br>\n"; body += "</select><br>\n";
if(UseFANrelais == false) { if(UseFANrelais == false) {
body += "Speed FAN: <input type='range' id='PINfan_PWM' name='PINfan_PWM' min='1' max='255' value='"; body += "Speed FAN: <input type='range' id='PINfanPWM' name='PINfanPWM' min='1' max='255' value='";
body += PINfan_PWM; body += PINfanPWM;
body += "'/><br>\n"; body += "'/><br>\n";
} }
@ -1620,9 +1687,9 @@ void WEBsystemSettings() {
body += "<option value='2'" + returnStrSelected(TemperatureSensor_Type, 2) + ">I2C chirp</option>\n"; body += "<option value='2'" + returnStrSelected(TemperatureSensor_Type, 2) + ">I2C chirp</option>\n";
body += "</select><br>\n"; body += "</select><br>\n";
// ntpOffset int // NtpOffset int
body += "NTP offset: <input type='number' name='ntpOffset' min='-12' max='14' value='"; body += "NTP offset: <input type='number' name='NtpOffset' min='-12' max='14' value='";
body += ntpOffset; body += NtpOffset;
body+= "' required><br>\n"; body+= "' required><br>\n";
body += "<input type='submit' value='Save'>\n"; body += "<input type='submit' value='Save'>\n";
@ -1703,15 +1770,25 @@ void WEBgrowSettings() {
body += SunriseMinute; body += SunriseMinute;
body+= "' required><br>\n"; body+= "' required><br>\n";
// SunFade bool
body += "Fade in and out LED?: <select id='SunFade' name='SunFade' required>\n";
body += "<option value='1'" + returnStrSelected(SunFade, 1) + ">Yes</option>\n";
body += "<option value='0'" + returnStrSelected(SunFade, 0) + ">No</option>\n";
body += "</select><br>\n";
body += "Fading duration (minutes): <input type='number' name='SunFadeDuration' min='0' max='255' value='";
body += SunFadeDuration;
body+= "' required><br>\n";
if(UseLEDrelais == false) { if(UseLEDrelais == false) {
body += "Brightness LED: <input type='range' id='PINled_PWM' name='PINled_PWM' min='1' max='255' value='"; body += "Brightness LED: <input type='range' id='PINledPWM' name='PINledPWM' min='1' max='255' value='";
body += PINled_PWM; body += PINledPWM;
body += "'/><br>\n"; body += "'/><br>\n";
} }
if(UseFANrelais == false) { if(UseFANrelais == false) {
body += "Speed FAN: <input type='range' id='PINfan_PWM' name='PINfan_PWM' min='1' max='255' value='"; body += "Speed FAN: <input type='range' id='PINfanPWM' name='PINfanPWM' min='1' max='255' value='";
body += PINfan_PWM; body += PINfanPWM;
body += "'/><br>\n"; body += "'/><br>\n";
} }
@ -1735,18 +1812,18 @@ void POSTgrowSettings() {
if(UseLEDrelais == true) { if(UseLEDrelais == true) {
// if a relais is used to turn on grow light, we force PWM to max val // if a relais is used to turn on grow light, we force PWM to max val
PINled_PWM = 255; PINledPWM = 255;
} else { } else {
// otherwise just do PWM // otherwise just do PWM
PINled_PWM = webserver.arg("PINled_PWM").toInt(); PINledPWM = webserver.arg("PINledPWM").toInt();
} }
if(UseFANrelais == true) { if(UseFANrelais == true) {
// if a relais is used to turn on grow light, we force PWM to max val // if a relais is used to turn on grow light, we force PWM to max val
PINfan_PWM = 255; PINfanPWM = 255;
} else { } else {
// otherwise just do PWM // otherwise just do PWM
PINfan_PWM = webserver.arg("PINfan_PWM").toInt(); PINfanPWM = webserver.arg("PINfanPWM").toInt();
} }
String GrowName_tmp = webserver.arg("GrowName"); String GrowName_tmp = webserver.arg("GrowName");
@ -1760,6 +1837,8 @@ void POSTgrowSettings() {
LighthoursBloom = webserver.arg("LighthoursBloom").toInt(); LighthoursBloom = webserver.arg("LighthoursBloom").toInt();
SunriseHour = webserver.arg("SunriseHour").toInt(); SunriseHour = webserver.arg("SunriseHour").toInt();
SunriseMinute = webserver.arg("SunriseMinute").toInt(); SunriseMinute = webserver.arg("SunriseMinute").toInt();
SunFade = webserver.arg("SunFade").toInt();
SunFadeDuration = webserver.arg("SunFadeDuration").toInt();
// size is 32 byte // size is 32 byte
EEPROM.put(170, GrowName); EEPROM.put(170, GrowName);
@ -1778,17 +1857,18 @@ void POSTgrowSettings() {
// size is 1 byte // size is 1 byte
EEPROM.put(211, SunriseMinute); EEPROM.put(211, SunriseMinute);
// size is 1 byte // size is 1 byte
EEPROM.put(213, PINled_PWM); EEPROM.put(213, PINledPWM);
// size is 1 byte // size is 1 byte
EEPROM.put(216, PINfan_PWM); EEPROM.put(216, PINfanPWM);
EEPROM.put(217, SunFade);
EEPROM.put(218, SunFadeDuration);
EEPROM.commit(); EEPROM.commit();
//analogWrite(PINled, PINled_PWM); //analogWrite(PINled, PINledPWM);
Serial.println(":: POSTgrowSettings ::"); Serial.println(":: POSTgrowSettings ::");
@ -1808,10 +1888,10 @@ void POSTgrowSettings() {
Serial.println(SunriseHour); Serial.println(SunriseHour);
Serial.print("SunriseMinute: "); Serial.print("SunriseMinute: ");
Serial.println(SunriseMinute); Serial.println(SunriseMinute);
Serial.print("PINled_PWM: "); Serial.print("PINledPWM: ");
Serial.println(PINled_PWM); Serial.println(PINledPWM);
Serial.print("PINfan_PWM: "); Serial.print("PINfanPWM: ");
Serial.println(PINfan_PWM); Serial.println(PINfanPWM);
webserver.sendHeader("Location", String("/growSettings?success"), true); webserver.sendHeader("Location", String("/growSettings?success"), true);
webserver.send(302, "text/plain", "growSettings/save: success!\n"); webserver.send(302, "text/plain", "growSettings/save: success!\n");
@ -1819,7 +1899,7 @@ void POSTgrowSettings() {
void POSTsystemSettings() { void POSTsystemSettings() {
ntpOffset = webserver.arg("ntpOffset").toInt(); NtpOffset = webserver.arg("NtpOffset").toInt();
MoistureSensor_Type = webserver.arg("MoistureSensor_Type").toInt(); MoistureSensor_Type = webserver.arg("MoistureSensor_Type").toInt();
SoilmoistureLow = webserver.arg("SoilmoistureLow").toInt(); SoilmoistureLow = webserver.arg("SoilmoistureLow").toInt();
UsePump = webserver.arg("UsePump").toInt(); UsePump = webserver.arg("UsePump").toInt();
@ -1844,7 +1924,7 @@ void POSTsystemSettings() {
// size is 1 byte // size is 1 byte
EEPROM.put(166, SoilmoistureLow); EEPROM.put(166, SoilmoistureLow);
// size is 2 byte // size is 2 byte
EEPROM.put(167, ntpOffset); EEPROM.put(167, NtpOffset);
// size is 1 byte // size is 1 byte
EEPROM.put(169, UseLEDrelais); EEPROM.put(169, UseLEDrelais);
// size is 1 byte // size is 1 byte
@ -1858,25 +1938,25 @@ void POSTsystemSettings() {
// update time with new offset // update time with new offset
timeClient.setTimeOffset(ntpOffset * 60 * 60); timeClient.setTimeOffset(NtpOffset * 60 * 60);
timeClient.update(); timeClient.update();
Serial.println(":: POSTsystemSettings ::"); 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 // to ensure nothing bad happens
if(UseLEDrelais == true) { if(UseLEDrelais == true) {
PINled_PWM = 255; PINledPWM = 255;
EEPROM.put(213, PINled_PWM); EEPROM.put(213, PINledPWM);
EEPROM.commit(); 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) { if(UseFANrelais == true) {
PINfan_PWM = 255; PINfanPWM = 255;
EEPROM.put(215, PINfan_PWM); EEPROM.put(215, PINfanPWM);
EEPROM.commit(); 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: "); Serial.print("configured: ");
@ -1891,8 +1971,8 @@ void POSTsystemSettings() {
Serial.println(MoistureSensor_Type); Serial.println(MoistureSensor_Type);
Serial.print("SoilmoistureLow: "); Serial.print("SoilmoistureLow: ");
Serial.println(SoilmoistureLow); Serial.println(SoilmoistureLow);
Serial.print("ntpOffset: "); Serial.print("NtpOffset: ");
Serial.println(ntpOffset); Serial.println(NtpOffset);
Serial.print("UseLEDrelais: "); Serial.print("UseLEDrelais: ");
Serial.println(UseLEDrelais); Serial.println(UseLEDrelais);
Serial.print("UseFANrelais: "); Serial.print("UseFANrelais: ");
@ -1972,53 +2052,26 @@ void POSTwifiSettings() {
} }
void POSTswitchMOSFET() { void POSTsetOutput() {
byte MosfetState = webserver.arg("state").toInt(); byte OutputState = webserver.arg("state").toInt();
byte MosfetNr = webserver.arg("output").toInt(); byte OutputNr = webserver.arg("output").toInt();
byte PINfan_PWM = webserver.arg("PINfan_PWM").toInt(); PINledPWM = webserver.arg("PINledPWM").toInt();
PINfanPWM = webserver.arg("PINfanPWM").toInt();
Serial.println(":: GETswitchMOSFET ::"); Serial.println(":: GETswitchMOSFET ::");
Serial.print("MosfetState: "); Serial.print("OutputState: ");
Serial.println(MosfetState); Serial.println(OutputState);
Serial.print("MosfetNr: "); Serial.print("OutputNr: ");
Serial.println(MosfetNr); 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"); webserver.send(400, "text/plain", "not valid\n");
} else { } else {
switch(MosfetNr) {
case 1: setOutput(OutputNr, OutputState);
if(MosfetState == 1) { webserver.sendHeader("Location", String("/?success"), true);
if(UseLEDrelais == true) { webserver.send(302, "text/plain", "switch: success!\n");
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;
} }
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 * - when PWM for fan is set, set fan speed to regulate humidity and
* temperature * temperature
* - re-organize EEPROM saved values. * - re-organize EEPROM saved values.
* - prevent GrowStart to be in the future
* *
* *
*/ */