1296 lines
42 KiB
C
1296 lines
42 KiB
C
/*
|
|
*
|
|
*
|
|
* Web related stuff
|
|
*
|
|
*
|
|
*/
|
|
|
|
/*
|
|
*
|
|
* return functions, they return things for the web stuff
|
|
*/
|
|
|
|
String returnHTMLheader(String MenuEntry = "") {
|
|
String header;
|
|
String activeMenu = "class='activeMenu'";
|
|
// add first part of the header
|
|
header += FPSTR(HTMLheaderP1);
|
|
// add title tag
|
|
header += "<title>";
|
|
// check if GrowName was set. if yes, its part of the page title.
|
|
if(strlen(GrowName) > 0) {
|
|
header += "CanGrow - ";
|
|
header += GrowName;
|
|
} else {
|
|
header += "CanGrow";
|
|
}
|
|
// close title tag
|
|
header += "</title>\n";
|
|
|
|
// add additional header stuff, like loading guage files
|
|
if(MenuEntry == "root") {
|
|
header += "<link rel='stylesheet' type='text/css' href='gauge.css'>";
|
|
}
|
|
|
|
header += FPSTR(HTMLheaderP2);
|
|
|
|
// first menu entry
|
|
header += "<li><a href='/'>🌱 ";
|
|
if(strlen(GrowName) > 0) {
|
|
header += GrowName;
|
|
} else {
|
|
header += "CanGrow";
|
|
}
|
|
header += "</a></li>\n";
|
|
|
|
// second menu entry
|
|
header += "<li><a href='/growSettings' ";
|
|
if(MenuEntry == "growSettings") {
|
|
header += activeMenu;
|
|
}
|
|
header += ">🔆 Grow settings</a></li>\n";
|
|
|
|
// third menu entry
|
|
header += "<li><a href='/systemSettings' ";
|
|
if(MenuEntry == "systemSettings") {
|
|
header += activeMenu;
|
|
}
|
|
header += ">⚙ System settings</a></li>\n";
|
|
|
|
// fourth menu entry
|
|
header += "<li><a href='/wifiSettings' ";
|
|
if(MenuEntry == "wifiSettings") {
|
|
header += activeMenu;
|
|
}
|
|
header += ">📡 WiFi settings</a></li>\n";
|
|
|
|
// fifth menu entry
|
|
header += "<li><a href='/help' ";
|
|
if(MenuEntry == "help") {
|
|
header += activeMenu;
|
|
}
|
|
header += ">❓ Help</a></li>\n";
|
|
|
|
// sixth menu entry - time and status icons / info
|
|
header += "<li><span class='MenuTime'>";
|
|
header += timeClient.getFormattedTime();
|
|
// status icons and info
|
|
if(MaintenanceMode == true) {
|
|
// status icons
|
|
header += " | ⏸️ ";
|
|
header += MaintenanceDuration - ((millis() - MaintenanceStarted) / 1000);
|
|
header += "s";
|
|
}
|
|
header += "</span></li>\n";
|
|
|
|
|
|
// CanGrow Version
|
|
header += "<li><a href='https://git.la10cy.net/DeltaLima/CanGrow' target='_blank'>CanGrow v";
|
|
header += CANGROW_VER;
|
|
header += "</a></li>\n";
|
|
|
|
// close <ul> and start <div>
|
|
header += "</ul><div class='center'>";
|
|
|
|
if(NeedRestart == true) {
|
|
header += FPSTR(HTMLneedRestart);
|
|
}
|
|
|
|
return header;
|
|
}
|
|
|
|
/*
|
|
* returnSelected(bool)
|
|
* returns char[] "selected" if bool is true
|
|
* useful for html forms, to represet a saved value as selected
|
|
*/
|
|
String returnStrSelected(byte savedValue, byte selectId) {
|
|
String returnStr;
|
|
|
|
if(configured == true) {
|
|
if(savedValue == selectId) {
|
|
returnStr = " selected ";
|
|
} else {
|
|
returnStr = "";
|
|
}
|
|
}
|
|
|
|
return returnStr;
|
|
}
|
|
|
|
String returnStrDateFromEpoch(unsigned long epochTime) {
|
|
String dateStr;
|
|
byte Day = day(epochTime);
|
|
byte Month = month(epochTime);
|
|
unsigned int Year = year(epochTime);
|
|
|
|
dateStr = Year;
|
|
dateStr += "-";
|
|
|
|
if(Month < 10) {
|
|
dateStr += "0";
|
|
dateStr += Month;
|
|
} else {
|
|
dateStr += Month;
|
|
}
|
|
|
|
dateStr += "-";
|
|
|
|
if(Day < 10) {
|
|
dateStr += "0";
|
|
dateStr += Day;
|
|
} else {
|
|
dateStr += Day;
|
|
}
|
|
|
|
return dateStr;
|
|
}
|
|
|
|
|
|
/*
|
|
*
|
|
* System pages like infos, errors
|
|
*
|
|
*/
|
|
|
|
void SysRestart() {
|
|
String body = returnHTMLheader();
|
|
// TODO only debug and development solution, remove this later
|
|
if( (webserver.hasArg("confirmed")) || (NeedRestart == true) ) {
|
|
body += "<h1>❗ Restarting</h1>";
|
|
body += "<div class='infomsg'>After restart CanGrow will be connected to WiFi SSID<br><b>";
|
|
body += WIFIssid;
|
|
body += "</b><br>You get its IP-Address from the display or serial console.</div>";
|
|
body += FPSTR(HTMLfooter);
|
|
webserver.send(200, "text/html", body);
|
|
Serial.println("Restarting... see you soon space cowboy!");
|
|
delay(1000);
|
|
ESP.restart();
|
|
} else {
|
|
body += "<h1>❗ Restart CanGrow</h1>";
|
|
body += "<div class='infomsg'>Do you want to restart CanGrow?";
|
|
body += "<br>Please confirm.";
|
|
body += "<form action='/system/restart'><input type='hidden' name='confirmed' value='true' /><input type='submit' value='Confirm restart' /></form>";
|
|
body += "</div>";
|
|
body += FPSTR(HTMLfooter);
|
|
webserver.send(200, "text/html", body);
|
|
}
|
|
}
|
|
|
|
void SysWipe() {
|
|
String body = returnHTMLheader();
|
|
body += "<h1>❗❗ Wiping EEPROM</h1>";
|
|
body += "<div class='warnmsg'>All settings will be removed!!<br>";
|
|
body += "<br>Please confirm wiping the EEPROM";
|
|
body += "<form action='/system/wipeConfirm' method='post'><br>Please confirm: <input type='checkbox' id='confirm' name='confirm' required /><br><input type='submit' value='Confirm wiping' /></form>";
|
|
body += "</div>";
|
|
body += FPSTR(HTMLfooter);
|
|
webserver.send(200, "text/html", body);
|
|
|
|
}
|
|
|
|
|
|
void Sys404() {
|
|
String body = returnHTMLheader();
|
|
body += "<div class='warnmsg'><h1>❗ ️ 404 - not found</h1></div>";
|
|
body += FPSTR(HTMLfooter);
|
|
webserver.send(404, "text/html", body);
|
|
}
|
|
|
|
void Syslogout() {
|
|
String body = returnHTMLheader();
|
|
body += "<h1>you are logged out.</h1>";
|
|
body += FPSTR(HTMLfooter);
|
|
|
|
// TODO does not work atm
|
|
webserver.send(401, "text/html", body);
|
|
}
|
|
|
|
void SysMaintenance() {
|
|
String body = returnHTMLheader();
|
|
|
|
if( (webserver.hasArg("on")) ) {
|
|
MaintenanceMode = true;
|
|
MaintenanceStarted = millis();
|
|
body += "<div class='infomsg'>⏸️ On for ";
|
|
body += MaintenanceDuration;
|
|
body += "s</div>";
|
|
} else if (webserver.hasArg("off")){
|
|
MaintenanceMode = false;
|
|
body += "<div class='infomsg'>⏸️ Off</div>";
|
|
}
|
|
|
|
|
|
body += "<h2>⏸️ Maintenance Mode</h2>";
|
|
body += "<a class='button' href='/system/maintenance?on=1'>On</a> <a class='button' href='/system/maintenance?off=1'>Off</a>";
|
|
|
|
body += FPSTR(HTMLfooter);
|
|
webserver.send(200, "text/html", body);
|
|
}
|
|
|
|
void SysUpdate() {
|
|
String body = returnHTMLheader();
|
|
|
|
body += "<h2>🔄 Firmware update</h2>";
|
|
|
|
body += "<b>Version:</b> ";
|
|
body += CANGROW_VER;
|
|
body += "<br><b>Build:</b> ";
|
|
body += CANGROW_BUILD;
|
|
|
|
body += FPSTR(HTMLupdate);
|
|
|
|
body += FPSTR(HTMLfooter);
|
|
webserver.send(200, "text/html", body);
|
|
}
|
|
|
|
/*
|
|
* TODO
|
|
* DOES NOT WORK WHEN CONNECTED TO EXISTING WIFI
|
|
* IDK WHY
|
|
*
|
|
|
|
* void WebAuth() {
|
|
*
|
|
* char webAuthRealm[] = "CanGrowRealm";
|
|
* if(!webserver.authenticate(WebUiUsername, WebUiPassword)) {
|
|
* String body = FPSTR(HTMLheader);
|
|
* body += "<h1>Login failed.</h1>";
|
|
* body += FPSTR(HTMLfooter);
|
|
* webserver.requestAuthentication(DIGEST_AUTH, webAuthRealm, body);
|
|
* }
|
|
* }
|
|
*
|
|
* void WebAuthApi() {
|
|
*
|
|
* TODO
|
|
* DOES NOT WORK WHEN CONNECTED TO EXISTING WIFI
|
|
* IDK WHY
|
|
*
|
|
*
|
|
* char webAuthRealm[] = "CanGrowRealm";
|
|
* if(!webserver.authenticate(WebUiUsername, WebUiPassword)) {
|
|
* webserver.requestAuthentication(DIGEST_AUTH, webAuthRealm);
|
|
* }
|
|
* }
|
|
*/
|
|
|
|
/*
|
|
*
|
|
* Main UI pages
|
|
*
|
|
*/
|
|
|
|
/*
|
|
* Gauge meter files
|
|
*/
|
|
void WEBgaugeCss() {
|
|
//String css = CSSgauge;
|
|
webserver.send(200, "text/css", FPSTR(CSSgauge));
|
|
}
|
|
|
|
void WEBgaugeJs() {
|
|
//String javascript = JSgauge;
|
|
webserver.send(200, "text/javascript", FPSTR(JSgauge));
|
|
}
|
|
|
|
/*
|
|
* Root page
|
|
*/
|
|
|
|
void WEBroot() {
|
|
if(FirstRun == true) {
|
|
webserver.sendHeader("Location", String("/wifiSettings"), true);
|
|
webserver.send(302, "text/plain", "please configure wifiSettings first");
|
|
} else if(configured == false){
|
|
webserver.sendHeader("Location", String("/systemSettings"), true);
|
|
webserver.send(302, "text/plain", "please configure systemSettings first");
|
|
} else if(strlen(GrowName) < 1){
|
|
webserver.sendHeader("Location", String("/growSettings"), true);
|
|
webserver.send(302, "text/plain", "please configure growSettings first");
|
|
} else {
|
|
String body = returnHTMLheader("root");
|
|
|
|
body += "<h2>🌱 ";
|
|
body += GrowName;
|
|
body += "</h2>";
|
|
|
|
// add gauge meter
|
|
body += FPSTR(HTMLgauge);
|
|
// and give javascript the values
|
|
// todo: auto refresh by api call
|
|
body += "<script>";
|
|
|
|
body += "gaugeTemperature.value('";
|
|
body += valTemperature;
|
|
body += "', 42, ' °C'); ";
|
|
|
|
body += "gaugeHumidity.value('";
|
|
body += valHumidity;
|
|
body += "'); ";
|
|
|
|
body += "gaugeSoilmoisture.value('";
|
|
body += valSoilmoisture;
|
|
body += "'); ";
|
|
|
|
body += "</script><br>\n";
|
|
|
|
// when an ESP32-Cam IP is given, display picture from it
|
|
if(strlen(Esp32CamIP) > 0) {
|
|
body += "<a href='http://";
|
|
body += Esp32CamIP;
|
|
body += "' target='_blank'><img class='centered' src='http://";
|
|
body += Esp32CamIP;
|
|
body += "/capture' alt='Image capture from ESP32CAM at ";
|
|
body += Esp32CamIP;
|
|
body += "'></a>\n<br>\n";
|
|
}
|
|
|
|
body += "<b>Grow started:</b> ";
|
|
body += returnStrDateFromEpoch(GrowStart);
|
|
body += "<br>\n";
|
|
body += "<b>Day of Grow:</b> ";
|
|
body += DayOfGrow;
|
|
body += "<br>\n";
|
|
body += "<b>Grow status:</b> ";
|
|
switch(growState()) {
|
|
case 1:
|
|
body += "🌱 vegetation<br>\n";
|
|
break;
|
|
case 2:
|
|
body += "🌼 bloom<br>\n";
|
|
break;
|
|
case 3:
|
|
body += "🍂 harvest\n";
|
|
break;
|
|
}
|
|
|
|
if(UsePump > 0) {
|
|
body += "<b>Pump water level:</b> ";
|
|
switch(getWaterlevel()) {
|
|
case 0:
|
|
body += "<span style='color: green;'>OK</span>";
|
|
break;
|
|
case 1:
|
|
body += "<span style='color: yellow;'>Warning</span>";
|
|
break;
|
|
case 2:
|
|
body += "<span style='color: red;'>Critical</span>";
|
|
break;
|
|
}
|
|
}
|
|
body += "<br>\n";
|
|
body += "<b>Growlight brightness:</b> ";
|
|
body += ((PinLEDPWM * 100) / 255);
|
|
body += " %<br>\n";
|
|
//~ body += "<form method='post' action='/switch'>\n";
|
|
//~ body += "<b>MOSFET:</b> <select id='output' name='output' >\n";
|
|
//~ body += "<option disabled value='' selected hidden>---</option>\n";
|
|
//~ body += "<option value='1'>LED</option>\n";
|
|
//~ body += "<option value='2'>FAN</option>\n";
|
|
//~ body += "<option value='3'>PUMP</option>\n";
|
|
//~ body += "</select><br>";
|
|
|
|
//~ body += "<b>On/Off:</b> <select id='state' name='state' >\n";
|
|
//~ body += "<option disabled value='' selected hidden>---</option>\n";
|
|
//~ body += "<option value='1'>On</option>\n";
|
|
//~ body += "<option value='0'>Off</option>\n";
|
|
//~ body += "</select><br>\n";
|
|
|
|
//~ body += "<b>Intensity:</b> <input type='range' id='OutputPWM' name='OutputPWM' min='1' max='255' value='255'/><br>\n";
|
|
|
|
//~ body += "<input type='submit' value='Save'>\n";
|
|
//~ body += "</form><br>\n";
|
|
body += "<a class='button' href='/system/maintenance'>Maintenance Mode</a>";
|
|
|
|
|
|
body += FPSTR(HTMLfooter);
|
|
|
|
webserver.send(200, "text/html", body);
|
|
}
|
|
}
|
|
|
|
/*
|
|
*
|
|
* settings pages
|
|
*
|
|
*
|
|
*/
|
|
|
|
/*
|
|
* Grow page
|
|
*/
|
|
void WEBgrowSettings() {
|
|
// if system settings are unconfigured, we cannot proceed with growSettings
|
|
if(configured == false) {
|
|
webserver.sendHeader("Location", String("/systemSettings"), true);
|
|
webserver.send(302, "text/plain", "please configure systemSettings first");
|
|
} else {
|
|
|
|
String body = returnHTMLheader("growSettings");
|
|
|
|
if(strlen(GrowName) < 1) {
|
|
body += "<h1>Final step: Grow settings</h1>";
|
|
body += "<p>Please configure all settings<br>";
|
|
body += "</p>";
|
|
GrowStart = timeClient.getEpochTime();
|
|
}
|
|
|
|
body += "<h2>🔆 Grow settings</h2>";
|
|
if(webserver.hasArg("success")) {
|
|
body += FPSTR(HTMLsuccess);
|
|
}
|
|
body += "<p>Here you can set everything grow related, like light hours, how much water, LED brightness<br>";
|
|
body += "</p>";
|
|
|
|
body += "<form method='post' action='/growSettings/save'>\n";
|
|
|
|
|
|
|
|
body += "Grow name: <input type='text' name='GrowName' maxlength='31' value='";
|
|
body += GrowName;
|
|
body+= "' required><br>\n";
|
|
|
|
|
|
// the input field, which calls javascript convertDateToEpoch() to write data to transmit to id GrowStart
|
|
body += "Grow start date: <input type='date' id='GrowStart_sel' onChange='convertDateToEpoch(\"GrowStart_sel\", \"GrowStart\");' value='";
|
|
body += returnStrDateFromEpoch(GrowStart);
|
|
body += "' required><br>\n";
|
|
|
|
body += "<input type='hidden' id='GrowStart' name='GrowStart' value='";
|
|
body += GrowStart;
|
|
body+= "' required>\n";
|
|
|
|
|
|
|
|
body += "Vegetation duration: <input class='inputShort' type='number' name='DaysVeg' min='0' max='255' value='";
|
|
body += DaysVeg;
|
|
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 += "Time LED ON vegetation: <input class='inputShort' type='number' name='LighthoursVeg' min='0' max='255' value='";
|
|
body += LighthoursVeg;
|
|
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 += "Sunrise: <input class='inputShort' type='number' name='SunriseHour' min='0' max='23' value='";
|
|
body += SunriseHour;
|
|
body+= "' required>\n";
|
|
body += " <b>:</b> <input class='inputShort' type='number' name='SunriseMinute' min='0' max='59' value='";
|
|
body += SunriseMinute;
|
|
body+= "' required><br>\n";
|
|
|
|
// SunFade bool
|
|
body += "Fade in/out sunrise/sunset?: <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 += "Fade duration: <input class='inputShort' type='number' name='SunFadeDuration' min='1' max='255' value='";
|
|
body += SunFadeDuration;
|
|
body+= "' required> Minutes<br>\n";
|
|
|
|
if(UseLEDrelais == false) {
|
|
body += "LED brightness: <input type='range' id='PinLEDPWM' name='PinLEDPWM' min='0' max='255' value='";
|
|
body += PinLEDPWM;
|
|
body += "'/> %<br>\n";
|
|
} else {
|
|
body += "LED on/off: <select id='PinLEDPWM' name='PinLEDPWM' required>\n";
|
|
body += "<option value='1'" + returnStrSelected(PinLEDPWM, 1) + ">On</option>\n";
|
|
body += "<option value='0'" + returnStrSelected(PinLEDPWM, 0) + ">Off</option>\n";
|
|
body += "</select><br>\n";
|
|
}
|
|
|
|
if(UseFANrelais == false) {
|
|
body += "FAN1 speed: <input type='range' id='PinFANPWM' name='PinFANPWM' min='0' max='255' value='";
|
|
body += PinFANPWM;
|
|
body += "'/> %<br>\n";
|
|
} else {
|
|
body += "FAN1 on/off: <select id='PinFANPWM' name='PinFANPWM' required>\n";
|
|
body += "<option value='1'" + returnStrSelected(PinFANPWM, 1) + ">On</option>\n";
|
|
body += "<option value='0'" + returnStrSelected(PinFANPWM, 0) + ">Off</option>\n";
|
|
body += "</select><br>\n";
|
|
}
|
|
|
|
body += "FAN2 speed: <input type='range' id='PinFAN2PWM' name='PinFAN2PWM' min='0' max='255' value='";
|
|
body += PinFAN2PWM;
|
|
body += "'/> %<br>\n";
|
|
|
|
|
|
body += "Pump interval vegetation: every <input class='inputShort' type='number' name='PumpIntervalVeg' min='0' max='255' value='";
|
|
body += PumpIntervalVeg;
|
|
body += "' required ";
|
|
if( (UsePump != 1) && UsePump != 3) { body += "readonly"; }
|
|
body += "> days<br>\n";
|
|
|
|
body += "Pump interval bloom: every <input class='inputShort' type='number' name='PumpIntervalBloom' min='0' max='255' value='";
|
|
body += PumpIntervalBloom;
|
|
body += "' required ";
|
|
if((UsePump != 1) && (UsePump != 3)) { body += "readonly"; }
|
|
body += "> days<br>\n";
|
|
|
|
|
|
body += "<input type='submit' value='💾 Save settings'>\n";
|
|
body += "</form>\n";
|
|
body += FPSTR(JSconvertDateToEpoch);
|
|
body += FPSTR(HTMLfooter);
|
|
|
|
webserver.send(200, "text/html", body);
|
|
}
|
|
}
|
|
|
|
void WEBsystemSettings() {
|
|
// if wifi settings are unconfigured, we cannot proceed with systemSettings
|
|
if(FirstRun == true) {
|
|
webserver.sendHeader("Location", String("/wifiSettings"), true);
|
|
webserver.send(302, "text/plain", "please configure wifiSettings first");
|
|
} else {
|
|
|
|
String body = returnHTMLheader("systemSettings");
|
|
|
|
if(configured == false) {
|
|
body += "<h1>Step 2: System settings</h1>";
|
|
body += "<p>Please configure all settings<br>";
|
|
body += "</p>";
|
|
}
|
|
|
|
body += "<h2>⚙ System settings</h2>";
|
|
body += FPSTR(HTMLsystemSubNav);
|
|
if(webserver.hasArg("success")) {
|
|
body += FPSTR(HTMLsuccess);
|
|
}
|
|
body += "<p>here you can set which features and sensors you use<br>";
|
|
body += "</p>";
|
|
|
|
// form starts
|
|
body += "<form method='post' action='/systemSettings/save'>\n";
|
|
|
|
// UseFan bool
|
|
//~ body += "Fan mode: <select id='UseFan' name='UseFan' required>\n";
|
|
//~ if(configured == false){body += "<option disabled value='' selected hidden>---</option>\n";}
|
|
//~ body += "<option value='1'" + returnStrSelected(UseFan, 0) + ">Off</option>\n";
|
|
//~ body += "<option value='1'" + returnStrSelected(UseFan, 1) + ">Use</option>\n";
|
|
//~ body += "<option value='0'" + returnStrSelected(UseFan, 2) + ">Do not use</option>\n";
|
|
//~ body += "</select><br>\n";
|
|
|
|
/*
|
|
// UsePump bool
|
|
body += "Use PUMP: <select id='UsePump' name='UsePump' required>\n";
|
|
if(configured == false){body += "<option disabled value='' selected hidden>---</option>\n";}
|
|
body += "<option value='1'" + returnStrSelected(UsePump, 1) + ">Yes</option>\n";
|
|
body += "<option value='0'" + returnStrSelected(UsePump, 0) + ">No</option>\n";
|
|
body += "</select><br>\n";
|
|
*/
|
|
|
|
// OutputInvert bool
|
|
body += "Invert Outputs: <select id='OutputInvert' name='OutputInvert' required>\n";
|
|
if(configured == false){body += "<option disabled value='' selected hidden>---</option>\n";}
|
|
body += "<option value='1'" + returnStrSelected(OutputInvert, 1) + ">Yes</option>\n";
|
|
body += "<option value='0'" + returnStrSelected(OutputInvert, 0) + ">No</option>\n";
|
|
body += "</select><br>\n";
|
|
|
|
// 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='0'" + returnStrSelected(UsePump, 0) + ">Off</option>\n";
|
|
body += "<option value='1'" + returnStrSelected(UsePump, 1) + ">1</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";
|
|
|
|
// UseLEDrelais bool
|
|
body += "Use relais for LED (disable PWM): <select id='UseLEDrelais' name='UseLEDrelais' required>\n";
|
|
if(configured == false){body += "<option disabled value='' selected hidden>---</option>\n";}
|
|
body += "<option value='1'" + returnStrSelected(UseLEDrelais, 1) + ">Yes</option>\n";
|
|
body += "<option value='0'" + returnStrSelected(UseLEDrelais, 0) + ">No</option>\n";
|
|
body += "</select><br>\n";
|
|
|
|
// UseFANrelais bool
|
|
body += "Use relais for FAN (disable PWM): <select id='UseFANrelais' name='UseFANrelais' required>\n";
|
|
if(configured == false){body += "<option disabled value='' selected hidden>---</option>\n";}
|
|
body += "<option value='1'" + returnStrSelected(UseFANrelais, 1) + ">Yes</option>\n";
|
|
body += "<option value='0'" + returnStrSelected(UseFANrelais, 0) + ">No</option>\n";
|
|
body += "</select><br>\n";
|
|
|
|
// 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 += PumpOnTime;
|
|
body += "' required> Seconds<br>\n";
|
|
|
|
// MoistureSensor_Type byte
|
|
body += "Soilmoisture sensor: <select id='SelMoistureSensor_Type' name='MoistureSensor_Type' onchange='MoistureSensorType();' required>\n";
|
|
if(configured == false) {
|
|
body += "<option disabled value='' selected hidden>---</option>\n";
|
|
}
|
|
body += "<option value='1'" + returnStrSelected(MoistureSensor_Type, 1) + ">Analog capacitive</option>\n";
|
|
body += "<option value='2'" + returnStrSelected(MoistureSensor_Type, 2) + ">I2C Chirp</option>\n";
|
|
body += "</select><br>\n";
|
|
|
|
// SoilmoistureLow byte
|
|
body += "Soilmoisture low: <input class='inputShort' type='number' name='SoilmoistureLow' min='0' value='";
|
|
body += SoilmoistureLow;
|
|
body += "' required> %<br>\n";
|
|
|
|
// SoilmoistureWet byte
|
|
body += "Soilmoisture wet: <input type='number' id='iSoilmoistureWet' name='SoilmoistureWet' min='0' value='";
|
|
body += SoilmoistureWet;
|
|
body += "' required>\n";
|
|
body += "<p class='helpbox'><b>Analog capacitive:</b> <i>160</i><br> \
|
|
<b>I2C Chirp:</b> <i>485</i></p>";
|
|
|
|
// SoilmoistureDry byte
|
|
body += "Soilmoisture dry: <input type='number' id='iSoilmoistureDry' name='SoilmoistureDry' min='0' value='";
|
|
body += SoilmoistureDry;
|
|
body += "' required>\n";
|
|
body += "<p class='helpbox'><b>Analog capacitive:</b> <i>360</i><br> \
|
|
<b>I2C Chirp:</b> <i>250</i></p>";
|
|
|
|
|
|
// MoistureSensor_Type Javascript
|
|
body += FPSTR(JSsoilmoistureTypeSelect);
|
|
|
|
|
|
// TemperatureSensor_Type byte
|
|
body += "Temperature sensor: <select id='TemperatureSensor_Type' name='TemperatureSensor_Type' required>\n";
|
|
if(configured == false) {
|
|
body += "<option disabled value='' selected hidden>---</option>\n";
|
|
}
|
|
body += "<option value='1'" + returnStrSelected(TemperatureSensor_Type, 1) + ">I2C BME280</option>\n";
|
|
body += "<option value='2'" + returnStrSelected(TemperatureSensor_Type, 2) + ">I2C Chirp</option>\n";
|
|
body += "<option value='2'" + returnStrSelected(TemperatureSensor_Type, 3) + ">I2C SHT31</option>\n";
|
|
body += "</select><br>\n";
|
|
|
|
// HumiditySensor_Type byte
|
|
body += "Humidity sensor: <select id='HumiditySensor_Type' name='HumiditySensor_Type' required>\n";
|
|
if(configured == false) {
|
|
body += "<option disabled value='' selected hidden>---</option>\n";
|
|
}
|
|
body += "<option value='1'" + returnStrSelected(HumiditySensor_Type, 1) + ">I2C BME280</option>\n";
|
|
body += "<option value='2'" + returnStrSelected(HumiditySensor_Type, 2) + ">I2C SHT31</option>\n";
|
|
body += "</select><br>\n";
|
|
|
|
// NtpOffset int
|
|
body += "NTP offset: <input class='inputShort' type='number' name='NtpOffset' min='-12' max='14' value='";
|
|
body += NtpOffset;
|
|
body+= "' required> Hours<br>\n";
|
|
|
|
body += "Maintenance Duration: <input class='inputShort' type='number' name='MaintenanceDuration' min='0' max='900' value='";
|
|
body += MaintenanceDuration;
|
|
body += "' required> Seconds<br>\n";
|
|
|
|
// PWMFrequency short
|
|
body += "PWM Frequency: <input type='number' name='PWMFrequency' min='0' max='20000' value='";
|
|
body += PWMFrequency;
|
|
body += "' required> Hz<br>\n";
|
|
|
|
// DisplayScreenDuration byte
|
|
body += "Display rotation interval: <input class='inputShort' type='number' name='DisplayScreenDuration' min='0' max='255' value='";
|
|
body += DisplayScreenDuration;
|
|
body += "' required> s<br>\n";
|
|
body += "<p class='helpbox'><b>0</b> will always show sensor value screen</p>";
|
|
|
|
body += "ESP32-Cam IP (optional): <input type='text' name='Esp32CamIP' maxlength='16' value='";
|
|
body += Esp32CamIP;
|
|
body += "' ><br>\n";
|
|
|
|
|
|
body += "<input type='submit' value='💾 Save settings'>\n";
|
|
body += "</form>\n";
|
|
|
|
|
|
body += FPSTR(HTMLfooter);
|
|
|
|
webserver.send(200, "text/html", body);
|
|
}
|
|
}
|
|
|
|
void WEBwifiSettings() {
|
|
byte ssidsAvail = WiFi.scanNetworks();
|
|
String body = returnHTMLheader("wifiSettings");
|
|
if(FirstRun == true) {
|
|
body += "<h1>Welcome!</h1>";
|
|
body += "<p>CanGrow is actually unconfigured. You need to Setup your WiFi first down below.<br>";
|
|
body += "<br>After you entered your WiFi connection details, you need to restart and are step closer to your grow 🥦";
|
|
body += "<br>";
|
|
body += "</p>";
|
|
}
|
|
body += "<h2>📡 WiFi settings</h2>\n";
|
|
|
|
if(webserver.hasArg("success")) {
|
|
body += FPSTR(HTMLsuccess);
|
|
}
|
|
|
|
if(FirstRun == false) {
|
|
body += "<u>Current Settings:</u><br>";
|
|
body += "WiFi SSID: <b>";
|
|
body += WIFIssid;
|
|
body += "</b><br>\n";
|
|
body += "Use DHCP: <b>";
|
|
body += WIFIuseDHCP;
|
|
body += "</b><br>\n";
|
|
body += "IP address: <b>";
|
|
body += WiFi.localIP().toString();
|
|
body += "</b><br>\n";
|
|
body += "Subnet mask: <b>";
|
|
body += WiFi.subnetMask().toString();
|
|
body += "</b><br>\n";
|
|
body += "Gateway: <b>";
|
|
body += WiFi.gatewayIP().toString();
|
|
body += "</b><br>\n";
|
|
body += "DNS: <b>";
|
|
body += WiFi.dnsIP().toString();
|
|
body += "</b><br><br>\n";
|
|
}
|
|
|
|
body += "<p>Select your wifi network from the SSID list.<br>To use DHCP leave IP, Subnet, Gateway and DNS fields blank!</p>";
|
|
body += "<form method='post' action='/wifiSettings/save'>\n";
|
|
body += "SSID: <select id='WIFIssid' name='WIFIssid' required>\n";
|
|
body += "<option disabled value='' selected hidden>-Select your network-</option>";
|
|
|
|
// build option list for selecting wifi
|
|
Serial.println("Available Wifis: ");
|
|
for(int i = 0 ; i < ssidsAvail; i++) {
|
|
String wifiName = WiFi.SSID(i);
|
|
Serial.println(wifiName);
|
|
body += "<option value='" + wifiName + "'>";
|
|
body += wifiName + "</option>\n";
|
|
}
|
|
body += "</select><br>\n";
|
|
body += "Password: <input type='password' name='WIFIpassword'><br>\n";
|
|
body += "IP: <input type='text' name='WIFIip'><br>\n";
|
|
body += "Subnet mask: <input type='text' name='WIFInetmask'><br>\n";
|
|
body += "Gateway: <input type='text' name='WIFIgateway'><br>\n";
|
|
body += "DNS: <input type='text' name='WIFIdns'><br>\n";
|
|
body += "<input type='submit' value='💾 Save settings'>\n";
|
|
body += "</form>\n";
|
|
body += FPSTR(HTMLfooter);
|
|
|
|
webserver.send(200, "text/html", body);
|
|
}
|
|
|
|
void WEBhelp() {
|
|
String body = returnHTMLheader("help");
|
|
body += FPSTR(HTMLhelp);
|
|
body += FPSTR(HTMLfooter);
|
|
webserver.send(200, "text/html", body);
|
|
}
|
|
|
|
|
|
/*
|
|
*
|
|
* POSTs
|
|
*
|
|
*/
|
|
|
|
void POSTgrowSettings() {
|
|
|
|
PinLEDPWM = webserver.arg("PinLEDPWM").toInt();
|
|
PinFANPWM = webserver.arg("PinFANPWM").toInt();
|
|
PinFAN2PWM = webserver.arg("PinFAN2PWM").toInt();
|
|
String GrowName_tmp = webserver.arg("GrowName");
|
|
GrowName_tmp.toCharArray(GrowName, 32);
|
|
|
|
|
|
GrowStart = webserver.arg("GrowStart").toInt();
|
|
DaysVeg = webserver.arg("DaysVeg").toInt();
|
|
DaysBloom = webserver.arg("DaysBloom").toInt();
|
|
LighthoursVeg = webserver.arg("LighthoursVeg").toInt();
|
|
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();
|
|
PumpIntervalVeg = webserver.arg("PumpIntervalVeg").toInt();
|
|
PumpIntervalBloom = webserver.arg("PumpIntervalBloom").toInt();
|
|
|
|
// size is 32 byte
|
|
EEPROM.put(170, GrowName);
|
|
// size is 4 byte
|
|
EEPROM.put(202, GrowStart);
|
|
// size is 1 byte
|
|
EEPROM.put(206, DaysVeg);
|
|
// size is 1 byte
|
|
EEPROM.put(207, DaysBloom);
|
|
// size is 1 byte
|
|
EEPROM.put(208, LighthoursVeg);
|
|
// size is 1 byte
|
|
EEPROM.put(209, LighthoursBloom);
|
|
// size is 1 byte
|
|
EEPROM.put(210, SunriseHour);
|
|
// size is 1 byte
|
|
EEPROM.put(211, SunriseMinute);
|
|
// size is 1 byte
|
|
EEPROM.put(213, PinLEDPWM);
|
|
// size is 1 byte
|
|
EEPROM.put(216, PinFANPWM);
|
|
// size is 1 byte
|
|
EEPROM.put(248, PinFAN2PWM);
|
|
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();
|
|
|
|
|
|
|
|
|
|
//analogWrite(PinLED, PinLEDPWM);
|
|
|
|
Serial.println(":: POSTgrowSettings ::");
|
|
|
|
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("PinLEDPWM: ");
|
|
Serial.println(PinLEDPWM);
|
|
Serial.print("PinFANPWM: ");
|
|
Serial.println(PinFANPWM);
|
|
Serial.print("PinFAN2PWM: ");
|
|
Serial.println(PinFAN2PWM);
|
|
|
|
webserver.sendHeader("Location", String("/growSettings?success"), true);
|
|
webserver.send(302, "text/plain", "growSettings/save: success!\n");
|
|
}
|
|
|
|
|
|
void POSTsystemSettings() {
|
|
|
|
unsigned short UseLEDrelais_old = UseLEDrelais;
|
|
unsigned short UseFANrelais_old = UseFANrelais;
|
|
unsigned short PWMFrequency_old = PWMFrequency;
|
|
|
|
NtpOffset = webserver.arg("NtpOffset").toInt();
|
|
MoistureSensor_Type = webserver.arg("MoistureSensor_Type").toInt();
|
|
SoilmoistureLow = webserver.arg("SoilmoistureLow").toInt();
|
|
UsePump = webserver.arg("UsePump").toInt();
|
|
PumpOnTime = webserver.arg("PumpOnTime").toInt();
|
|
UseFan = webserver.arg("UseFan").toInt();
|
|
UseLEDrelais = webserver.arg("UseLEDrelais").toInt();
|
|
UseFANrelais = webserver.arg("UseFANrelais").toInt();
|
|
TemperatureSensor_Type = webserver.arg("TemperatureSensor_Type").toInt();
|
|
MaintenanceDuration = webserver.arg("MaintenanceDuration").toInt();
|
|
String Esp32CamIP_tmp = webserver.arg("Esp32CamIP");
|
|
Esp32CamIP_tmp.toCharArray(Esp32CamIP, 221);
|
|
OutputInvert = webserver.arg("OutputInvert").toInt();
|
|
SoilmoistureWet = webserver.arg("SoilmoistureWet").toInt();
|
|
SoilmoistureDry = webserver.arg("SoilmoistureDry").toInt();
|
|
HumiditySensor_Type = webserver.arg("HumiditySensor_Type").toInt();
|
|
PWMFrequency = webserver.arg("PWMFrequency").toInt();
|
|
DisplayScreenDuration = webserver.arg("DisplayScreenDuration").toInt();
|
|
|
|
// when configured is false, set it to true and ensure outputs are set
|
|
if(configured == false) {
|
|
configured = true;
|
|
pinMode(PinLED, OUTPUT);
|
|
pinMode(PinPUMP, OUTPUT);
|
|
pinMode(PinFAN, OUTPUT);
|
|
}
|
|
|
|
// size is 1 byte
|
|
EEPROM.put(161, configured);
|
|
// size is 1 byte
|
|
EEPROM.put(162, UseFan);
|
|
// size is 1 byte
|
|
EEPROM.put(163, UsePump);
|
|
// size is 1 byte
|
|
EEPROM.put(164, PumpOnTime);
|
|
// size is 1 byte
|
|
EEPROM.put(165, MoistureSensor_Type);
|
|
// size is 1 byte
|
|
EEPROM.put(166, SoilmoistureLow);
|
|
// size is 2 byte
|
|
EEPROM.put(167, NtpOffset);
|
|
// size is 1 byte
|
|
EEPROM.put(169, UseLEDrelais);
|
|
// size is 1 byte
|
|
EEPROM.put(214, TemperatureSensor_Type);
|
|
// size is 1 byte
|
|
EEPROM.put(215, UseFANrelais);
|
|
EEPROM.put(219, MaintenanceDuration);
|
|
EEPROM.put(221, Esp32CamIP);
|
|
EEPROM.put(243, OutputInvert);
|
|
EEPROM.put(244, SoilmoistureWet);
|
|
EEPROM.put(246, SoilmoistureDry);
|
|
EEPROM.put(249, HumiditySensor_Type);
|
|
EEPROM.put(250, PWMFrequency);
|
|
EEPROM.put(252, DisplayScreenDuration);
|
|
|
|
// write data to EEPROM
|
|
EEPROM.commit();
|
|
|
|
|
|
|
|
// update time with new offset
|
|
timeClient.setTimeOffset(NtpOffset * 60 * 60);
|
|
timeClient.update();
|
|
|
|
Serial.println(":: POSTsystemSettings ::");
|
|
|
|
// when user uses an relais for LED control, we force here PinLEDPWM to 255
|
|
// to ensure nothing bad happens and its turned on
|
|
if( (UseLEDrelais == false) && (UseLEDrelais != UseLEDrelais_old) ) {
|
|
PinLEDPWM = 255;
|
|
EEPROM.put(213, PinLEDPWM);
|
|
EEPROM.commit();
|
|
Serial.println("UseLEDrelais is 0, forcing PinLEDPWM to max to prevent relais damage and ensure its turned on");
|
|
}
|
|
|
|
if( (UseFANrelais == false) && (UseFANrelais != UseFANrelais_old) ) {
|
|
PinFANPWM = 255;
|
|
EEPROM.put(215, PinFANPWM);
|
|
EEPROM.commit();
|
|
Serial.println("UseFANrelais is 0, forcing PinFANPWM to max to prevent relais damage and ensure its turned on");
|
|
}
|
|
|
|
if(PWMFrequency != PWMFrequency_old) {
|
|
// if PWM freq changed, apply new settings
|
|
analogWriteFreq(PWMFrequency);
|
|
}
|
|
|
|
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("SoilmoistureLow: ");
|
|
Serial.println(SoilmoistureLow);
|
|
Serial.print("NtpOffset: ");
|
|
Serial.println(NtpOffset);
|
|
Serial.print("UseLEDrelais: ");
|
|
Serial.println(UseLEDrelais);
|
|
Serial.print("UseFANrelais: ");
|
|
Serial.println(UseFANrelais);
|
|
Serial.print("TemperatureSensor_Type: ");
|
|
Serial.println(TemperatureSensor_Type);
|
|
Serial.print("MaintenanceDuration: ");
|
|
Serial.println(MaintenanceDuration);
|
|
|
|
if(strlen(GrowName) < 1) {
|
|
webserver.sendHeader("Location", String("/growSettings?success"), true);
|
|
} else {
|
|
webserver.sendHeader("Location", String("/systemSettings?success"), true);
|
|
}
|
|
|
|
webserver.send(302, "text/plain", "systemSettings/save: success!\n");
|
|
}
|
|
|
|
|
|
void POSTwifiSettings() {
|
|
String WIFIssid_new = webserver.arg("WIFIssid");
|
|
String WIFIpassword_new = webserver.arg("WIFIpassword");
|
|
String WIFIip_new = webserver.arg("WIFIip");
|
|
String WIFInetmask_new = webserver.arg("WIFInetmask");
|
|
String WIFIgateway_new = webserver.arg("WIFIgateway");
|
|
String WIFIdns_new = webserver.arg("WIFIdns");
|
|
|
|
// convert String we got from webserver.arg to EEPROM friendly char[]
|
|
WIFIssid_new.toCharArray(WIFIssid, 32);
|
|
WIFIpassword_new.toCharArray(WIFIpassword, 64);
|
|
|
|
// if WIFIip_new was not set, we assume DHCP should be used
|
|
if(WIFIip_new.length() > 0) {
|
|
WIFIip.fromString(WIFIip_new);
|
|
WIFInetmask.fromString(WIFInetmask_new);
|
|
WIFIgateway.fromString(WIFIgateway_new);
|
|
WIFIdns.fromString(WIFIdns_new);
|
|
//
|
|
WIFIuseDHCP = false;
|
|
} else {
|
|
WIFIuseDHCP = true;
|
|
}
|
|
|
|
// restart is needed to load the new settings
|
|
NeedRestart = true;
|
|
|
|
EEPROM.put(0, WIFIssid);
|
|
EEPROM.put(32, WIFIpassword);
|
|
EEPROM.put(96, WIFIip);
|
|
EEPROM.put(112, WIFInetmask);
|
|
EEPROM.put(128, WIFIgateway);
|
|
EEPROM.put(144, WIFIdns);
|
|
EEPROM.put(160, WIFIuseDHCP);
|
|
EEPROM.commit();
|
|
|
|
|
|
Serial.println(":: POSTwifiSettings ::");
|
|
|
|
Serial.print("WIFIssid: ");
|
|
Serial.println(WIFIssid_new);
|
|
Serial.println(WIFIssid);
|
|
Serial.print("WIFIpassword: ");
|
|
Serial.println(WIFIpassword_new);
|
|
Serial.println(WIFIpassword);
|
|
Serial.print("WIFIip: ");
|
|
Serial.println(WIFIip_new);
|
|
Serial.print("WIFInetmask: ");
|
|
Serial.println(WIFInetmask_new);
|
|
Serial.print("WIFIgateway: ");
|
|
Serial.println(WIFIgateway_new);
|
|
Serial.print("WIFIdns: ");
|
|
Serial.println(WIFIdns_new);
|
|
Serial.print("WIFIuseDHCP: ");
|
|
Serial.println(WIFIuseDHCP);
|
|
|
|
|
|
webserver.sendHeader("Location", String("/wifiSettings?success"), true);
|
|
webserver.send(302, "text/plain", "wifiSettings/save: success!\n");
|
|
|
|
}
|
|
|
|
void POSTsetOutput() {
|
|
byte OutputState = webserver.arg("state").toInt();
|
|
byte OutputNr = webserver.arg("output").toInt();
|
|
//PinLEDPWM = webserver.arg("PinLEDPWM").toInt();
|
|
byte OutputPWM = webserver.arg("OutputPWM").toInt();
|
|
|
|
Serial.println(":: POSTsetOutput ::");
|
|
Serial.print("OutputState: ");
|
|
Serial.println(OutputState);
|
|
Serial.print("OutputNr: ");
|
|
Serial.println(OutputNr);
|
|
|
|
if((OutputNr > 3) || (OutputNr < 1) || (OutputState > 255) || (OutputState < 0)) {
|
|
webserver.send(400, "text/plain", "not valid\n");
|
|
} else {
|
|
|
|
if(OutputState > 0){
|
|
setOutput(OutputNr, OutputPWM);
|
|
} else {
|
|
setOutput(OutputNr, 0);
|
|
}
|
|
|
|
|
|
webserver.sendHeader("Location", String("/?success"), true);
|
|
webserver.send(302, "text/plain", "switch: success!\n");
|
|
}
|
|
|
|
}
|
|
|
|
|
|
void POSTsetPumpManual() {
|
|
PumpOnManual = webserver.arg("PumpOnManual").toInt();
|
|
webserver.sendHeader("Location", String("/?success"), true);
|
|
webserver.send(302, "text/plain", "switch: success!\n");
|
|
}
|
|
|
|
void POSTwipeConfirm() {
|
|
String body = returnHTMLheader();
|
|
// TODO only debug and development solution, remove this later
|
|
String confirm = webserver.arg("confirm");
|
|
if(confirm == "on") {
|
|
body += "<div class='warnmsg'><h2>!! Wiping CanGrow's EEPROM !!</h2><br>Device will restart in a few seconds.<br>After restart a new WiFi 'CanGrow-unconfigured' will be created. To access the WebUI visit <a href='http://192.168.4.20'>http://192.168.4.20</a></div>";
|
|
body += FPSTR(HTMLfooter);
|
|
webserver.send(200, "text/html", body);
|
|
wipeEEPROM();
|
|
} else {
|
|
webserver.send(400, "text/html", String("Error, 'confirm' missing nor wrong"));
|
|
}
|
|
|
|
}
|
|
|
|
|
|
/*
|
|
* API section
|
|
*
|
|
*/
|
|
|
|
// return as json all sensor readings
|
|
void APIgetSensors() {
|
|
|
|
JsonDocument jsonSensors;
|
|
|
|
jsonSensors["soilmoisture"] = valSoilmoisture;
|
|
jsonSensors["soilmoistureAvg"] = valSoilmoistureAvg;
|
|
jsonSensors["temperature"] = valTemperature;
|
|
jsonSensors["humidity"] = valHumidity;
|
|
jsonSensors["waterlevel"] = valWaterlevel;
|
|
|
|
String body;
|
|
serializeJsonPretty(jsonSensors, body);
|
|
webserver.send(200, "text/json", body);
|
|
|
|
}
|
|
|
|
void APIgetDebug() {
|
|
|
|
JsonDocument jsonDebug;
|
|
|
|
// Runtime vars
|
|
JsonObject objRuntime = jsonDebug["runtime"].add<JsonObject>();
|
|
objRuntime["PumpOnTimePassed"] = PumpOnTimePassed;
|
|
objRuntime["PumpOnManual"] = PumpOnManual;
|
|
objRuntime["valSoilmoistureAvg"] = valSoilmoistureAvg;
|
|
objRuntime["valSoilmoistureAvg_tmp"] = valSoilmoistureAvg_tmp;
|
|
objRuntime["valSoilmoistureAvg_count"] = valSoilmoistureAvg_count;
|
|
|
|
// WiFi
|
|
JsonObject objWiFi = jsonDebug["wifi"].add<JsonObject>();
|
|
objWiFi["ssid"] = WIFIssid;
|
|
objWiFi["dhcp"] = WIFIuseDHCP;
|
|
objWiFi["ip"] = WiFi.localIP().toString();
|
|
objWiFi["netmask"] = WiFi.subnetMask().toString();
|
|
objWiFi["gateway"] = WiFi.gatewayIP().toString();
|
|
objWiFi["dns"] = WiFi.dnsIP().toString();
|
|
|
|
// System
|
|
JsonObject objSystem = jsonDebug["system"].add<JsonObject>();
|
|
objSystem["UseFan"] = UseFan;
|
|
objSystem["UsePump"] = UsePump;
|
|
objSystem["UseLEDrelais"] = UseLEDrelais;
|
|
objSystem["UseFANrelais"] = UseFANrelais;
|
|
objSystem["PumpOnTime"] = PumpOnTime;
|
|
objSystem["MoistureSensor_Type"] = MoistureSensor_Type;
|
|
objSystem["SoilmoistureLow"] = SoilmoistureLow;
|
|
objSystem["TemperatureSensor_Type"] = TemperatureSensor_Type;
|
|
objSystem["NtpOffset"] = NtpOffset;
|
|
objSystem["MaintenanceDuration"] = MaintenanceDuration;
|
|
objSystem["PumpOnTime"] = PumpOnTime;
|
|
objSystem["PumpLastOn"] = PumpLastOn;
|
|
|
|
// Grow
|
|
JsonObject objGrow = jsonDebug["grow"].add<JsonObject>();
|
|
objGrow["GrowName"] = GrowName;
|
|
objGrow["GrowStart"] = GrowStart;
|
|
objGrow["GrowStartDate"] = returnStrDateFromEpoch(GrowStart);
|
|
objGrow["DaysVeg"] = DaysVeg;
|
|
objGrow["DaysBloom"] = DaysBloom;
|
|
objGrow["LighthoursVeg"] = LighthoursVeg;
|
|
objGrow["LighthoursBloom"] = LighthoursBloom;
|
|
objGrow["SunriseHour"] = SunriseHour;
|
|
objGrow["SunriseMinute"] = SunriseMinute;
|
|
objGrow["SunFade"] = SunFade;
|
|
objGrow["SunFadeDuration"] = SunFadeDuration;
|
|
objGrow["PinLEDPWM"] = PinLEDPWM;
|
|
objGrow["PinFANPWM"] = PinFANPWM;
|
|
objGrow["DayOfGrow"] = DayOfGrow;
|
|
objGrow["PumpIntervalVeg"] = PumpIntervalVeg;
|
|
objGrow["PumpIntervalBloom"] = PumpIntervalBloom;
|
|
|
|
|
|
// Sensors
|
|
JsonObject objSensors = jsonDebug["sensors"].add<JsonObject>();
|
|
|
|
// Chirp
|
|
objSensors["chirp"]["temperature"] = getTemperature(2);
|
|
objSensors["chirp"]["soilmoisture"] = getSoilmoisture(2);
|
|
objSensors["chirp"]["soilmoistureRAW"] = getSoilmoisture(2, true);
|
|
objSensors["chirp"]["light"] = getLightchirp();
|
|
|
|
// BME280
|
|
objSensors["bme280"]["temperature"] = getTemperature(1);
|
|
objSensors["bme280"]["humidity"] = getHumidity(1);
|
|
objSensors["bme280"]["preassure"] = bme.readPressure() / 100.0F;
|
|
objSensors["bme280"]["appAltitude"] = bme.readAltitude(SEALEVELPRESSURE_HPA);
|
|
|
|
// Analog
|
|
objSensors["analog"]["soilmoisture"] = getSoilmoisture(1);
|
|
objSensors["analog"]["soilmoistureRAW"] = getSoilmoisture(1, true);
|
|
objSensors["analog"]["waterlevel"] = getWaterlevel();
|
|
|
|
String body;
|
|
|
|
serializeJsonPretty(jsonDebug, body);
|
|
webserver.send(200, "text/json", body);
|
|
|
|
}
|
|
|
|
|
|
/*
|
|
* Web Handler
|
|
*/
|
|
|
|
void WebHandler() {
|
|
/*
|
|
* Webserver handlers
|
|
* here are the generic webserver handlers like 404 not found
|
|
* wifiSettings, ...
|
|
*
|
|
* if you are looking for the single webpages handler, have a look to
|
|
*
|
|
* WebHandler_unconfigured() and WebHandler_configured()
|
|
*/
|
|
// style.css
|
|
//webserver.on("/style.css", HTTP_GET, WEBstyleCSS);
|
|
|
|
// Web root
|
|
webserver.on("/", HTTP_GET, WEBroot);
|
|
|
|
// WiFi Stuff
|
|
webserver.on("/wifiSettings", HTTP_GET, WEBwifiSettings);
|
|
webserver.on("/wifiSettings/save", HTTP_POST, POSTwifiSettings);
|
|
|
|
// System stuff
|
|
webserver.on("/systemSettings", HTTP_GET, WEBsystemSettings);
|
|
webserver.on("/systemSettings/save", HTTP_POST, POSTsystemSettings);
|
|
|
|
// Grow stuff
|
|
webserver.on("/growSettings", HTTP_GET, WEBgrowSettings);
|
|
webserver.on("/growSettings/save", HTTP_POST, POSTgrowSettings);
|
|
// help
|
|
webserver.on("/help", HTTP_GET, WEBhelp);
|
|
|
|
// restart when NeedRestart is true
|
|
webserver.on("/system/restart", HTTP_GET, SysRestart);
|
|
// wipe eeprom triggered from WebGui
|
|
webserver.on("/system/wipe", HTTP_GET, SysWipe);
|
|
// confirm wiping the device
|
|
webserver.on("/system/wipeConfirm", HTTP_POST, POSTwipeConfirm);
|
|
// Maintenance mode
|
|
webserver.on("/system/maintenance", HTTP_GET, SysMaintenance);
|
|
// system update with binary
|
|
// update form
|
|
webserver.on("/system/update", HTTP_GET, SysUpdate);
|
|
// update itself
|
|
webUpdater.setup(&webserver, "/system/applyUpdate");
|
|
// does not work atm TODO
|
|
//webserver.on("/logout", [](){ webserver.send(401, "text/html", "logged out!"); });
|
|
|
|
// 404 handling
|
|
// favicon.ico is a special one, because its requested everytime and i dont wont to deliver the
|
|
// failed whole page every call. we can save up this 0,5kb traffic :o)
|
|
webserver.on("/favicon.ico", [](){ webserver.send(404, "text/html", "404 - not found"); });
|
|
webserver.onNotFound(Sys404);
|
|
|
|
// switching MOSFETs
|
|
webserver.on("/switch", HTTP_POST, POSTsetOutput);
|
|
webserver.on("/pumpManual", HTTP_POST, POSTsetPumpManual);
|
|
|
|
// api stuff
|
|
webserver.on("/api/sensors", HTTP_GET, APIgetSensors);
|
|
webserver.on("/api/debug", HTTP_GET, APIgetDebug);
|
|
|
|
// gauge meter stuff
|
|
webserver.on("/gauge.css", HTTP_GET, WEBgaugeCss);
|
|
webserver.on("/gauge.js", HTTP_GET, WEBgaugeJs);
|
|
}
|