firmware wip - rename PIN variables to a more equal naming schema

This commit is contained in:
Marcus 2024-05-01 01:29:28 +02:00
parent ee5be296ec
commit 54b551f3df

View file

@ -325,7 +325,7 @@ function convertDateToEpoch(src, dst) {
* D0 - MOSFET Pump * D0 - MOSFET Pump
* D1, D2 - I2C * D1, D2 - I2C
* D3 - DHT11 * D3 - DHT11
* D4 - PIN_WIPE * D4 - PinWIPE
* D5 - MOSFET Fan * 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)
@ -342,7 +342,7 @@ const uint8_t PINdht = D3;
// D4 is HIGH at boot, boot fail if pulled to LOW // D4 is HIGH at boot, boot fail if pulled to LOW
// During Start Screen you can pull D4 to LOW to wipe saved data in EEPROM // During Start Screen you can pull D4 to LOW to wipe saved data in EEPROM
// DO NOT PULL D4 DOWN AT WHEN POWERING ON !!! BOOT WILL FAIL // DO NOT PULL D4 DOWN AT WHEN POWERING ON !!! BOOT WILL FAIL
const uint8_t PIN_WIPE = D4; const uint8_t PinWIPE = D4;
const uint8_t PinFAN = D5; const uint8_t PinFAN = D5;
const uint8_t PinLED = D6; // const uint8_t PinLED = D6; //
const uint8_t PINwaterlevel = D7; const uint8_t PINwaterlevel = D7;
@ -593,14 +593,14 @@ void wipeEEPROM() {
// wipeMsg is helper variable to know if the Serial.print Message was // wipeMsg is helper variable to know if the Serial.print Message was
// already sent // already sent
byte wipeMsg = 0; byte wipeMsg = 0;
while(digitalRead(PIN_WIPE) == LOW ) { while(digitalRead(PinWIPE) == LOW ) {
// only show the Serial message once // only show the Serial message once
if(wipeMsg == 0) { if(wipeMsg == 0) {
Serial.println("Please release PIN_WIPE to erase all data saved in EEPROM"); Serial.println("Please release PinWIPE to erase all data saved in EEPROM");
Serial.println("LAST CHANCE TO KEEP THE DATA BY RESETTING NOW!!"); Serial.println("LAST CHANCE TO KEEP THE DATA BY RESETTING NOW!!");
display.setCursor(0,36); display.setCursor(0,36);
display.println("RELEASE PIN_WIPE"); display.println("RELEASE PinWIPE");
display.println("TO WIPE EEPROM"); display.println("TO WIPE EEPROM");
display.display(); display.display();
@ -623,18 +623,18 @@ void wipeEEPROM() {
Serial.println("DONE"); Serial.println("DONE");
// set D4 PIN_WIPE internal LED to Output to give feedback WIPE // set D4 PinWIPE internal LED to Output to give feedback WIPE
// was done // was done
pinMode(PIN_WIPE, OUTPUT); pinMode(PinWIPE, OUTPUT);
Serial.println("!! Device will restart in 3 seconds !!"); Serial.println("!! Device will restart in 3 seconds !!");
// let the internal led blink fast to signalize wipe is done // let the internal led blink fast to signalize wipe is done
for(byte i = 0; i <= 24 ; i++) { for(byte i = 0; i <= 24 ; i++) {
if(i % 2) { if(i % 2) {
digitalWrite(PIN_WIPE, LOW); digitalWrite(PinWIPE, LOW);
} else { } else {
digitalWrite(PIN_WIPE, HIGH); digitalWrite(PinWIPE, HIGH);
} }
delay(125); delay(125);
} }
@ -1038,8 +1038,6 @@ void refreshSensors() {
* *
*/ */
void setup() { void setup() {
// Start EEPROM
EEPROM.begin(512);
// setup pins // setup pins
pinMode(PinFAN, OUTPUT); pinMode(PinFAN, OUTPUT);
@ -1048,7 +1046,7 @@ void setup() {
pinMode(PINsoilmoisture, OUTPUT); pinMode(PINsoilmoisture, OUTPUT);
pinMode(PinLED, OUTPUT); pinMode(PinLED, OUTPUT);
pinMode(PinPUMP, OUTPUT); pinMode(PinPUMP, OUTPUT);
pinMode(PIN_WIPE, OUTPUT); pinMode(PinWIPE, OUTPUT);
// set all OUTPUT to low // set all OUTPUT to low
@ -1063,12 +1061,14 @@ void setup() {
// 220Hz is note A3 btw. // 220Hz is note A3 btw.
analogWriteFreq(220); analogWriteFreq(220);
// Start EEPROM
EEPROM.begin(512);
// Start Serial // Start Serial
Serial.begin(115200); Serial.begin(115200);
// Write a line before doing serious output, because before there is some garbage in serial // Write a line before doing serious output, because before there is some garbage in serial
// whats get the cursor somewhere over the place // whats get the cursor somewhere over the place
// output
Serial.println("420"); Serial.println("420");
Serial.println(".:: CanGrow Start ::."); Serial.println(".:: CanGrow Start ::.");
@ -1076,7 +1076,7 @@ void setup() {
Wire.begin(); Wire.begin();
// initialise I2C display // initialise I2C display
display.begin(SSD1306_SWITCHCAPVCC, 0x3C); // Address 0x3C for 128x32 display.begin(SSD1306_SWITCHCAPVCC, 0x3C); // Address 0x3C for 128x64
display.clearDisplay(); display.clearDisplay();
display.display(); display.display();
@ -1094,7 +1094,7 @@ void setup() {
// initialise DHT11 // initialise DHT11
dht.begin(); //TODO: Do only, when configured dht.begin(); //TODO: Do only, when configured
Serial.println("To wipe the EEPROM saved data, set D4 (PIN_WIPE) to LOW - NOW! (2 seconds left)"); Serial.println("To wipe the EEPROM saved data, set D4 (PinWIPE) to LOW - NOW! (2 seconds left)");
// wait a few seconds to let the user pull D4 down to wipe EEPROM // wait a few seconds to let the user pull D4 down to wipe EEPROM
// and we can enjoy the boot screen meanwhile :p // and we can enjoy the boot screen meanwhile :p
// meanwhile blink with the led onboad :) // meanwhile blink with the led onboad :)
@ -1103,24 +1103,25 @@ void setup() {
display.fillRect(0,36,128,64-36, 0); display.fillRect(0,36,128,64-36, 0);
display.setCursor(0,36); display.setCursor(0,36);
display.println("To wipe EEPROM pull"); display.println("To wipe EEPROM pull");
display.println("D4 (PIN_WIPE) to GND"); display.println("D4 (PinWIPE) to GND");
display.display(); display.display();
// blink with the onboard LED on D4 (PinWIPE)
for(byte i = 0; i <= 6 ; i++) { for(byte i = 0; i <= 6 ; i++) {
if(i % 2) { if(i % 2) {
digitalWrite(PIN_WIPE, LOW); digitalWrite(PinWIPE, LOW);
} else { } else {
digitalWrite(PIN_WIPE, HIGH); digitalWrite(PinWIPE, HIGH);
} }
delay(333); delay(333);
} }
// set back to HIGH because thats the default // set back to HIGH because thats the default
digitalWrite(PIN_WIPE, HIGH); digitalWrite(PinWIPE, HIGH);
//delay(2000); //delay(2000);
// read status from PIN_WIPE to WIPE // read status from PinWIPE to WIPE
// when PIN_WIPE is set to LOW, wipe EEPROM // when PinWIPE is set to LOW, wipe EEPROM
if(digitalRead(PIN_WIPE) == LOW) { if(digitalRead(PinWIPE) == LOW) {
// wipe EEPROM // wipe EEPROM
wipeEEPROM(); wipeEEPROM();
} }
@ -1190,12 +1191,17 @@ void loop() {
// current time gets previous time for new interval // current time gets previous time for new interval
outputPrevTime = currentRuntime; outputPrevTime = currentRuntime;
} }
//delay(1000);
} }
/*
*
*
* Web related stuff
*
*
*/
/* /*
* Web Handler * Web Handler
*/ */
@ -1241,7 +1247,7 @@ void WebHandler() {
// favicon.ico is a special one, because its requested everytime and i dont wont to deliver the // 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) // 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.on("/favicon.ico", [](){ webserver.send(404, "text/html", "404 - not found"); });
webserver.onNotFound(WEB404); webserver.onNotFound(Sys404);
// switching MOSFETs // switching MOSFETs
webserver.on("/switch", HTTP_POST, POSTsetOutput); webserver.on("/switch", HTTP_POST, POSTsetOutput);
@ -1371,6 +1377,13 @@ String returnStrDateFromEpoch(unsigned long epochTime) {
return dateStr; return dateStr;
} }
/*
*
* System pages like infos, errors
*
*/
void SysRestart() { void SysRestart() {
String body = returnHTMLheader(); String body = returnHTMLheader();
// TODO only debug and development solution, remove this later // TODO only debug and development solution, remove this later
@ -1414,6 +1427,22 @@ void SysWipe() {
} }
} }
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);
}
/* /*
* TODO * TODO
@ -1448,35 +1477,12 @@ void SysWipe() {
/* /*
* *
* Web pages * Main UI pages
* *
*/ */
void WEB404() {
String body = returnHTMLheader();
body += "<div class='warnmsg'><h1>404 - not found</h1></div>";
body += FPSTR(HTMLfooter);
webserver.send(404, "text/html", body);
}
void WEBlogout() {
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 WEBhelp() {
String body = returnHTMLheader("help");
body += FPSTR(HTMLhelp);
body += FPSTR(HTMLfooter);
webserver.send(200, "text/html", body);
}
/* /*
* Root pages * Root page
*/ */
void WEBroot() { void WEBroot() {
@ -1497,19 +1503,19 @@ void WEBroot() {
body += "</h1>"; body += "</h1>";
body += "Grow started: "; body += "Grow started: ";
body += returnStrDateFromEpoch(GrowStart); body += returnStrDateFromEpoch(GrowStart);
body += "<br>"; body += "<br>\n";
body += "Day of Grow: "; body += "Day of Grow: ";
body += DayOfGrow; body += DayOfGrow;
body += "<br>"; body += "<br>\n";
body += "Soil Moisture: "; body += "Soil Moisture: ";
body += valSoilmoisture; body += valSoilmoisture;
body += " %<br>"; body += " %<br>\n";
body += "Humidity: "; body += "Humidity: ";
body += valHumidity; body += valHumidity;
body += " %<br>"; body += " %<br>\n";
body += "Temperature: "; body += "Temperature: ";
body += valTemperature; body += valTemperature;
body += " °C<br>"; body += " °C<br>\n";
if(UsePump == true) { if(UsePump == true) {
body += "Pump water level: "; body += "Pump water level: ";
switch(getWaterlevel()) { switch(getWaterlevel()) {
@ -1524,11 +1530,11 @@ void WEBroot() {
break; break;
} }
} }
body += "<br>"; body += "<br>\n";
body += "Growlight brightnes: "; body += "Growlight brightnes: ";
body += ((PinLEDPWM * 100) / 255); body += ((PinLEDPWM * 100) / 255);
body += " %<br>"; body += " %<br>\n";
body += "<form method='post' action='/switch'>"; body += "<form method='post' action='/switch'>\n";
body += "MOSFET<select id='output' name='output' required>\n"; body += "MOSFET<select id='output' name='output' required>\n";
body += "<option disabled value='' selected hidden>---</option>\n"; body += "<option disabled value='' selected hidden>---</option>\n";
body += "<option value='1'>LED</option>\n"; body += "<option value='1'>LED</option>\n";
@ -1547,10 +1553,6 @@ void WEBroot() {
body += "<input type='submit' value='Save'>\n"; body += "<input type='submit' value='Save'>\n";
body += "</form>"; body += "</form>";
body += FPSTR(HTMLfooter); body += FPSTR(HTMLfooter);
webserver.send(200, "text/html", body); webserver.send(200, "text/html", body);
@ -1558,73 +1560,110 @@ void WEBroot() {
} }
/* /*
* Config pages *
* settings pages
*
*
*/ */
void WEBwifiSettings() { /*
byte ssidsAvail = WiFi.scanNetworks(); * Grow page
String body = returnHTMLheader("wifiSettings"); */
if(FirstRun == true) { void WEBgrowSettings() {
body += "<h1>Welcome!</h1>"; // if system settings are unconfigured, we cannot proceed with growSettings
body += "<p>CanGrow is actually unconfigured. You need to Setup your WiFi first down below.<br>"; if(configured == false) {
body += "<br>After you entered your WiFi connection details, you need to restart and are step closer to your grow &#129382;"; webserver.sendHeader("Location", String("/systemSettings"), true);
body += "<br>"; 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 += "</p>";
}
body += "<h2>WiFi config</h2>\n";
if(NeedRestart == true) {
body += FPSTR(HTMLneedRestart);
}
if(webserver.hasArg("success")) {
body += FPSTR(HTMLsuccess);
}
if(FirstRun == false) { body += "<form method='post' action='/growSettings/save'>\n";
body += "<u>Current Settings:</u><br>";
body += "WiFi SSID: <b>";
body += WIFIssid;
body += "</b><br>\n"; body += "Grow name: <input type='text' name='GrowName' maxlength='32' value='";
body += "Use DHCP: <b>"; body += GrowName;
body += WIFIuseDHCP; body+= "' required><br>\n";
body += "</b><br>\n";
body += "IP address: <b>";
body += WiFi.localIP().toString(); // the input field, which calls javascript convertDateToEpoch() to write data to transmit to id GrowStart
body += "</b><br>\n"; body += "Grow start date: <input type='date' id='GrowStart_sel' onChange='convertDateToEpoch(\"GrowStart_sel\", \"GrowStart\");' value='";
body += "Subnet mask: <b>"; body += returnStrDateFromEpoch(GrowStart);
body += WiFi.subnetMask().toString(); body += "' required><br>\n";
body += "</b><br>\n";
body += "Gateway: <b>"; body += "<input type='hidden' id='GrowStart' name='GrowStart' value='";
body += WiFi.gatewayIP().toString(); body += GrowStart;
body += "</b><br>\n"; body+= "' required>\n";
body += "DNS: <b>";
body += WiFi.dnsIP().toString();
body += "</b><br><br>\n";
body += "Days of vegetation: <input type='number' name='DaysVeg' min='0' max='255' value='";
body += DaysVeg;
body+= "' required><br>\n";
body += "Days of bloom: <input type='number' name='DaysBloom' min='0' max='255' value='";
body += DaysBloom;
body+= "' required><br>\n";
body += "Hours light on vegetation: <input type='number' name='LighthoursVeg' min='0' max='255' value='";
body += LighthoursVeg;
body+= "' required><br>\n";
body += "Hours light on bloom: <input type='number' name='LighthoursBloom' min='0' max='255' value='";
body += LighthoursBloom;
body+= "' required><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 LED on 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 += "Fading duration (minutes): <input type='number' name='SunFadeDuration' min='1' max='255' value='";
body += SunFadeDuration;
body+= "' required><br>\n";
if(UseLEDrelais == false) {
body += "Brightness LED: <input type='range' id='PinLEDPWM' name='PinLEDPWM' min='1' max='255' value='";
body += PinLEDPWM;
body += "'/><br>\n";
}
if(UseFANrelais == false) {
body += "Speed FAN: <input type='range' id='PinFANPWM' name='PinFANPWM' min='1' max='255' value='";
body += PinFANPWM;
body += "'/><br>\n";
}
body += "<input type='submit' value='Save'>\n";
body += "</form>\n";
body += FPSTR(JSconvertDateToEpoch);
body += FPSTR(HTMLfooter);
webserver.send(200, "text/html", body);
} }
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'>\n";
body += "</form>\n";
body += FPSTR(HTMLfooter);
webserver.send(200, "text/html", body);
} }
void WEBsystemSettings() { void WEBsystemSettings() {
@ -1723,104 +1762,77 @@ void WEBsystemSettings() {
} }
} }
/* void WEBwifiSettings() {
* Grow pages byte ssidsAvail = WiFi.scanNetworks();
*/ String body = returnHTMLheader("wifiSettings");
void WEBgrowSettings() { if(FirstRun == true) {
// if system settings are unconfigured, we cannot proceed with growSettings body += "<h1>Welcome!</h1>";
if(configured == false) { body += "<p>CanGrow is actually unconfigured. You need to Setup your WiFi first down below.<br>";
webserver.sendHeader("Location", String("/systemSettings"), true); body += "<br>After you entered your WiFi connection details, you need to restart and are step closer to your grow &#129382;";
webserver.send(302, "text/plain", "please configure systemSettings first"); body += "<br>";
} 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 += "</p>";
body += "<form method='post' action='/growSettings/save'>\n";
body += "Grow name: <input type='text' name='GrowName' maxlength='32' 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 += "Days of vegetation: <input type='number' name='DaysVeg' min='0' max='255' value='";
body += DaysVeg;
body+= "' required><br>\n";
body += "Days of bloom: <input type='number' name='DaysBloom' min='0' max='255' value='";
body += DaysBloom;
body+= "' required><br>\n";
body += "Hours light on vegetation: <input type='number' name='LighthoursVeg' min='0' max='255' value='";
body += LighthoursVeg;
body+= "' required><br>\n";
body += "Hours light on bloom: <input type='number' name='LighthoursBloom' min='0' max='255' value='";
body += LighthoursBloom;
body+= "' required><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 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='1' max='255' value='";
body += SunFadeDuration;
body+= "' required><br>\n";
if(UseLEDrelais == false) {
body += "Brightness LED: <input type='range' id='PinLEDPWM' name='PinLEDPWM' min='1' max='255' value='";
body += PinLEDPWM;
body += "'/><br>\n";
}
if(UseFANrelais == false) {
body += "Speed FAN: <input type='range' id='PinFANPWM' name='PinFANPWM' min='1' max='255' value='";
body += PinFANPWM;
body += "'/><br>\n";
}
body += "<input type='submit' value='Save'>\n";
body += "</form>\n";
body += FPSTR(JSconvertDateToEpoch);
body += FPSTR(HTMLfooter);
webserver.send(200, "text/html", body);
} }
body += "<h2>WiFi config</h2>\n";
if(NeedRestart == true) {
body += FPSTR(HTMLneedRestart);
}
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'>\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);
} }