diff --git a/Arduino/CanGrow/CanGrow.ino b/Arduino/CanGrow/CanGrow.ino index 6a44635..0eebdc5 100644 --- a/Arduino/CanGrow/CanGrow.ino +++ b/Arduino/CanGrow/CanGrow.ino @@ -1,419 +1,17 @@ -/* - * CanGrow - simply DIY automatic plant grow system (for cannabis). - * - */ - -/* - * Includes - * - */ - -// Libraries -// https://github.com/arduino/ArduinoCore-avr/tree/master/libraries/SPI -#include -// https://github.com/arduino/ArduinoCore-avr/tree/master/libraries/Wire -#include -// https://github.com/arduino/ArduinoCore-avr/tree/master/libraries/EEPROM -#include -// https://github.com/esp8266/Arduino/tree/master/libraries/ESP8266WiFi -#include -#include -// https://github.com/esp8266/Arduino/tree/master/libraries/ESP8266WebServer -#include -// OTA update -#include -// https://github.com/adafruit/Adafruit-GFX-Library -#include -// https://github.com/adafruit/Adafruit_SSD1306 -#include -// https://github.com/adafruit/Adafruit_BME280_Library/ -#include -#include -// https://github.com/bblanchon/ArduinoJson -#include -// https://github.com/arduino-libraries/NTPClient -#include -// https://github.com/PaulStoffregen/Time -#include -// DHT support dropped -// https://github.com/adafruit/DHT-sensor-library -// #include "DHT.h" - -/* - * CanGrow header files - */ - -#include "CanGrow_PinAssignments.h" -#include "CanGrow_Init.h" -#include "CanGrow_Logo.h" -#include "CanGrow_Sensors.h" - -#include "CanGrow_Version.h" -#include "CanGrow_HTML.h" -#include "CanGrow_SysFunctions.h" -#include "CanGrow_WebFunctions.h" - - -/* - * Setup - * - */ -void setup() { - - // setup pins - pinMode(PinFAN, OUTPUT); - //pinMode(PINdht, INPUT); - pinMode(PINwaterlevel, OUTPUT); - pinMode(PINsoilmoisture, OUTPUT); - pinMode(PinLED, OUTPUT); - pinMode(PinPUMP, OUTPUT); - pinMode(PinWIPE, OUTPUT); - - - // set all OUTPUT to low - digitalWrite(PinFAN, HIGH); - digitalWrite(PINwaterlevel, LOW); - digitalWrite(PinLED, HIGH); - digitalWrite(PinPUMP, HIGH); - // except PINsoilmoisture - // PINsoilmoisture is always HIGH and gets LOW in moment of waterlevel measurement - digitalWrite(PINsoilmoisture, LOW); - - // set PWM frequency to 13.37KHz - analogWriteFreq(13370); - - // Start EEPROM - EEPROM.begin(512); - - // Start Serial - Serial.begin(115200); - - // Write a line before doing serious output, because before there is some garbage in serial - // whats get the cursor somewhere over the place - Serial.println("420"); - Serial.print(".:: CanGrow firmware v"); - Serial.print(CanGrowVer); - Serial.print(" build "); - Serial.print(CanGrowBuild); - Serial.println(" starting ::."); - - Serial.println(":: initialise I2C ::"); - // initialise Wire for I2C - Wire.begin(); - - Serial.println(":: initialise display ::"); - // initialise I2C display - display.begin(SSD1306_SWITCHCAPVCC, 0x3C); // Address 0x3C for 128x64 - display.clearDisplay(); - display.display(); - - // set display settings - display.setTextSize(1); - display.setTextColor(SSD1306_WHITE, SSD1306_BLACK); - - // display Logo - display.drawBitmap(0, 0, bmpCanGrow_Logo, 128, 32, WHITE); - display.display(); - - Serial.println(":: initialise chirp sensor if present ::"); - // reset chirp - writeI2CRegister8bit(0x20, 6); //TODO: Do only, when configured - - // initialise DHT11 - // dht support dropped - // dht.begin(); //TODO: Do only, when configured - - // initialise BME280 - Serial.println(":: initialise BME280 sensor ::"); - // ToDo: let the user configure somewhere the ID of the BME280 sensor - if(!bme.begin(0x76)) { - Serial.println("!! Cannot find BME280 on I2C bus. Please check connection or ID"); - } - - 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 - // and we can enjoy the boot screen meanwhile :p - // meanwhile blink with the led onboad :) - // 333 * 6 =~ 2 seconds - - display.fillRect(0,36,128,64-36, 0); - display.setCursor(0,36); - display.println("To wipe EEPROM pull"); - display.println("D4 (PinWIPE) to GND"); - display.display(); - - // blink with the onboard LED on D4 (PinWIPE) - for(byte i = 0; i <= 6 ; i++) { - if(i % 2) { - digitalWrite(PinWIPE, LOW); - } else { - digitalWrite(PinWIPE, HIGH); - } - delay(333); - } - // set back to HIGH because thats the default - digitalWrite(PinWIPE, HIGH); - //delay(2000); - - // read status from PinWIPE to WIPE - // when PinWIPE is set to LOW, wipe EEPROM - if(digitalRead(PinWIPE) == LOW) { - // wipe EEPROM - wipeEEPROM(); - } - - /* - * load EEPROM and Setup WiFi - * - * call loadEEPROM() which returns a bool - * When true, CanGrow is already configured and EEPROM values are applied - * When false, CanGrow is unconfigured and we need to run the setup assistant - */ - - - // load stored values from EEPROM and check what var configured is returned - if(loadEEPROM()) { - - // connect to wifi - wifiConnect(); - - // configured is 0, setup Access Point - } else { - - // start an wifi accesspoint - wifiAp(); - - } - // set web handler - WebHandler(); - // start webserver - webserver.begin(); - - Serial.println(".:: CanGrow Ready ::."); - delay(1000); - if(strlen(GrowName) > 0 ) { - display.clearDisplay(); - display.display(); - } -} - - /* * - * - * Loop + * CanGrow - an OpenSource growcontroller firmware (for cannabis) * * - */ -void loop() { - // var definition - unsigned long currentRuntime = millis(); - - - // first we call webserver handle client - webserver.handleClient(); - - - // do every second when everything is configured and grow is started - if( (configured == true) && (strlen(GrowName) > 0) && (currentRuntime - outputPrevTime >= 1000) ){ - - // refresh all sensor values - refreshSensors(); - - // calculate acutal DayOfGrow - DayOfGrow = int(ceil(float((timeClient.getEpochTime() - GrowStart) / 60 / 60 / 24))); - // decide if we are in Veg or Bloom phase of grow - // when DayOfGrow is larger then DaysVeg we must be in Bloom - - // set the actual state of the Grow LED - // when being in Maintenance Mode and UseRelaisLED not true, - // dimm the light - if(MaintenanceMode == true) { - if((currentRuntime - MaintenanceStarted <= MaintenanceDuration * 1000 ) && (UseLEDrelais == false)) { - // in case of being in Maintenance Mode , dimm the grow light when not a relais is used - setOutput(1, 15); - } else { - MaintenanceMode = false; - } - } else { - controlLED(); - } - - controlPUMP(); - - displayScreens(); - - // current time gets previous time for new interval - outputPrevTime = currentRuntime; - } -} - - - - - - - -/* + * MIT License * - * TODO LIST / NOTES + * Copyright (c) 2024 DeltaLima + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - * - * - when PWM for fan is set, set fan speed to regulate humidity and - * temperature, depending on which phase of grow the plant is - * (https://www.royalqueenseeds.de/blog-cannabisanbau-im-grow-room-relative-luftfeuchtigkeit-und-temperaturen-n243) - * - re-organize EEPROM saved values. - * - prevent GrowStart to be in the future - * - maybe let the user configure some screens to display. - * - put EEPROM adresses into DEFINEs -*/ - - - - - - -/* - * Fan control - * - * Vars: - * - FanVent (byte) Fan1 or Fan2 - * - FanExhaust (byte) Fan1 or Fan2 - * - - */ - - - - - - - - - - - -/* - * - * - * PLAYGROUND / TRASH - * - * */ - - /* - - unsigned long currentTime = millis(); - - int valSoilmoisture0 = getSoilmoisture(0); - int valSoilmoisture1 = getSoilmoisture(1); - float valTemperature0 = getTemperature(0); - float valTemperature1 = getTemperature(1); - - float valHumidity = getHumidity(); - - int valWaterlevel = getWaterlevel(); - - switch(valWaterlevel) { - - case 0: - digitalWrite(PinLED, HIGH); - digitalWrite(PinPUMP, LOW); - digitalWrite(PinFAN, LOW); - break; - case 1: - digitalWrite(PinLED, LOW); - digitalWrite(PinPUMP, HIGH); - digitalWrite(PinFAN, LOW); - break; - case 2: - digitalWrite(PinLED, LOW); - digitalWrite(PinPUMP, LOW); - digitalWrite(PinFAN, HIGH); - break; - - } - - -// OUTPUT - if(currentTime - outputPrevTime >= 1000) { - - - // set display cursor to top left - display.setCursor(0,0); - // display text - display.print("I2C: "); - display.print(valSoilmoisture1); - display.print(", "); - display.println(valTemperature1); - - Serial.print("I2C: "); - Serial.print(valSoilmoisture1); - Serial.print(", "); - Serial.println(valTemperature1); - - - display.print("DHT11: "); - display.print(valTemperature0); - display.print(", "); - display.println(valHumidity); - - Serial.print("DHT11: "); - Serial.print(valTemperature0); - Serial.print(", "); - Serial.println(valHumidity); - - - display.print("Water Status: "); - display.println(valWaterlevel); - - Serial.print("Water Status: "); - Serial.println(valWaterlevel); - - display.print("ASM: "); - display.print(valSoilmoisture0); - display.println(", "); - - Serial.print("ASM: "); - Serial.println(valSoilmoisture0); - - // print everything on the display - display.display(); - - Serial.println("Test"); - - outputPrevTime = currentTime; -*/ - - -/* if(D6status == true) { - digitalWrite(PinLED, LOW); - digitalWrite(PinPUMP, LOW); - digitalWrite(PinFAN, LOW); - D6status = false; - Serial.println("D6 is off now"); - } else { - digitalWrite(PinLED, HIGH); - digitalWrite(PinPUMP, HIGH); - digitalWrite(PinFAN, HIGH); - D6status = true; - Serial.println("D6 is ON now"); - } - */ - -/* - for(int dutyCycle = 0; dutyCycle < 255; dutyCycle++){ - // changing the LED brightness with PWM - analogWrite(PinLED, dutyCycle); - delay(1); - } - - // decrease the LED brightness - for(int dutyCycle = 255; dutyCycle > 0; dutyCycle--){ - // changing the LED brightness with PWM - analogWrite(PinLED, dutyCycle); - delay(1); - } -*/ - - diff --git a/Arduino/CanGrow/CanGrow_HTML.h b/Arduino/CanGrow/CanGrow_HTML.h deleted file mode 100644 index 9d4f3e6..0000000 --- a/Arduino/CanGrow/CanGrow_HTML.h +++ /dev/null @@ -1,525 +0,0 @@ - -/* - * HTML constants for header, footer, css, ... - * Note: I know of the existence of SPIFFS and ESPHtmlTemplateProcessor, - * but to keep things simple for compiling and upload for others, I decided - * to not use those. - */ - -// Template: const char HTMLexamplepage[] PROGMEM = R"EOF()EOF"; - -// first part of HTML header stuff -const char HTMLheaderP1[] PROGMEM = R"EOF( - - - - - -)EOF"; - // here comes the page title in returnHTMLheader() - -// second part of HTML header stuff -// Having the whole CSS here ensures it's all the time present -const char HTMLheaderP2[] PROGMEM = R"EOF( - - - - -
"; - - 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 += "

❗ Restarting

"; - body += "
After restart CanGrow will be connected to WiFi SSID
"; - body += WIFIssid; - body += "
You get its IP-Address from the display or serial console.
"; - body += FPSTR(HTMLfooter); - webserver.send(200, "text/html", body); - Serial.println("Restarting... see you soon space cowboy!"); - delay(1000); - ESP.restart(); - } else { - body += "

❗ Restart CanGrow

"; - body += "
Do you want to restart CanGrow?"; - body += "
Please confirm."; - body += "
"; - body += "
"; - body += FPSTR(HTMLfooter); - webserver.send(200, "text/html", body); - } -} - -void SysWipe() { - String body = returnHTMLheader(); - body += "

❗❗ Wiping EEPROM

"; - body += "
All settings will be removed!!
"; - body += "
Please confirm wiping the EEPROM"; - body += "

Please confirm:
"; - body += "
"; - body += FPSTR(HTMLfooter); - webserver.send(200, "text/html", body); - -} - - -void Sys404() { - String body = returnHTMLheader(); - body += "

❗ ️ 404 - not found

"; - body += FPSTR(HTMLfooter); - webserver.send(404, "text/html", body); -} - -void Syslogout() { - String body = returnHTMLheader(); - body += "

you are logged out.

"; - 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 += "
⏸️ On for "; - body += MaintenanceDuration; - body += "s
"; - } else if (webserver.hasArg("off")){ - MaintenanceMode = false; - body += "
⏸️ Off
"; - } - - - body += "

⏸️ Maintenance Mode

"; - body += "
On  Off"; - - body += FPSTR(HTMLfooter); - webserver.send(200, "text/html", body); -} - -void SysUpdate() { - String body = returnHTMLheader(); - - body += "

🔄 Firmware update

"; - - body += "Version: "; - body += CanGrowVer; - body += "
Build: "; - body += CanGrowBuild; - - 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 += "

Login failed.

"; - * 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 += "

🌱 "; - body += GrowName; - body += "

"; - - // add gauge meter - body += FPSTR(HTMLgauge); - // and give javascript the values - // todo: auto refresh by api call - body += "
\n"; - - // when an ESP32-Cam IP is given, display picture from it - if(strlen(Esp32CamIP) > 0) { - body += "Image capture from ESP32CAM at ";
-      body += Esp32CamIP;
-      body += "\n
\n"; - } - - body += "Grow started: "; - body += returnStrDateFromEpoch(GrowStart); - body += "
\n"; - body += "Day of Grow: "; - body += DayOfGrow; - body += "
\n"; - body += "Grow status: "; - switch(growState()) { - case 1: - body += "🌱 vegetation
\n"; - break; - case 2: - body += "🌼 bloom
\n"; - break; - case 3: - body += "🍂 harvest\n"; - break; - } - - if(UsePump > 0) { - body += "Pump water level: "; - switch(getWaterlevel()) { - case 0: - body += "OK"; - break; - case 1: - body += "Warning"; - break; - case 2: - body += "Critical"; - break; - } - } - body += "
\n"; - body += "Growlight brightness: "; - body += ((PinLEDPWM * 100) / 255); - body += " %
\n"; - body += "
\n"; - body += "MOSFET:
"; - - body += "On/Off:
\n"; - - body += "Intensity:
\n"; - - body += "\n"; - body += "

\n"; - body += "Maintenance Mode"; - - - 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 += "

Final step: Grow settings

"; - body += "

Please configure all settings
"; - body += "

"; - GrowStart = timeClient.getEpochTime(); - } - - body += "

🔆 Grow settings

"; - if(webserver.hasArg("success")) { - body += FPSTR(HTMLsuccess); - } - body += "

Here you can set everything grow related, like light hours, how much water, LED brightness
"; - body += "

"; - - body += "
\n"; - - - - body += "Grow name:
\n"; - - - // the input field, which calls javascript convertDateToEpoch() to write data to transmit to id GrowStart - body += "Grow start date:
\n"; - - body += "\n"; - - - - body += "Vegetation duration: days
\n"; - - body += "Bloom duration: days
\n"; - - body += "Time LED ON vegetation: hours
\n"; - - body += "Time LED ON bloom: hours
\n"; - - body += "Sunrise: \n"; - body += " :
\n"; - - // SunFade bool - body += "Fade in/out sunrise/sunset?:
\n"; - - body += "Fade duration: Minutes
\n"; - - if(UseLEDrelais == false) { - body += "LED brightness: %
\n"; - } - - if(UseFANrelais == false) { - body += "FAN speed: %
\n"; - } - - - body += "Pump interval vegetation: every Off\n"; - body += "\n"; - body += "\n"; - body += "
\n"; - -/* - // UsePump bool - body += "Use PUMP:
\n"; -*/ - // PumpMode byte - body += "Pump mode:

1: Water every few days.
\ -2: Water if the soil moisture falls below Soilmoisture low value
\ -3: Water every few days if the soil moisture falls below Soilmoisture low value.

\n"; - - // UseLEDrelais bool - body += "Use relais for LED:
\n"; - - // UseFANrelais bool - body += "Use relais for FAN:
\n"; - - // TODO ugly. can this done be better? - // PumpOnTime int - body += "Pump ON time: Seconds
\n"; - - - // MoistureSensor_Type byte - body += "Soilmoisture sensor:
\n"; - - // SoilmoistureLow byte - body += "Soilmoisture low: %
\n"; - - // TemperatureSensor_Type byte - body += "Temperature sensor:
\n"; - - // NtpOffset int - body += "NTP offset: Hours
\n"; - - body += "Maintenance Duration: Seconds
\n"; - - - body += "ESP32-Cam IP (optional):
\n"; - - - body += "\n"; - body += "
\n"; - - - body += FPSTR(HTMLfooter); - - webserver.send(200, "text/html", body); - } -} - -void WEBwifiSettings() { - byte ssidsAvail = WiFi.scanNetworks(); - String body = returnHTMLheader("wifiSettings"); - if(FirstRun == true) { - body += "

Welcome!

"; - body += "

CanGrow is actually unconfigured. You need to Setup your WiFi first down below.
"; - body += "
After you entered your WiFi connection details, you need to restart and are step closer to your grow 🥦"; - body += "
"; - body += "

"; - } - body += "

📡 WiFi settings

\n"; - - if(webserver.hasArg("success")) { - body += FPSTR(HTMLsuccess); - } - - if(FirstRun == false) { - body += "Current Settings:
"; - body += "WiFi SSID: "; - body += WIFIssid; - body += "
\n"; - body += "Use DHCP: "; - body += WIFIuseDHCP; - body += "
\n"; - body += "IP address: "; - body += WiFi.localIP().toString(); - body += "
\n"; - body += "Subnet mask: "; - body += WiFi.subnetMask().toString(); - body += "
\n"; - body += "Gateway: "; - body += WiFi.gatewayIP().toString(); - body += "
\n"; - body += "DNS: "; - body += WiFi.dnsIP().toString(); - body += "

\n"; - } - - body += "

Select your wifi network from the SSID list.
To use DHCP leave IP, Subnet, Gateway and DNS fields blank!

"; - body += "
\n"; - body += "SSID:
\n"; - body += "Password:
\n"; - body += "IP:
\n"; - body += "Subnet mask:
\n"; - body += "Gateway:
\n"; - body += "DNS:
\n"; - body += "\n"; - body += "
\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() { - - if(UseLEDrelais == true) { - // if a relais is used to turn on grow light, we force PWM to max val - PinLEDPWM = 255; - } else { - // otherwise just do PWM - PinLEDPWM = webserver.arg("PinLEDPWM").toInt(); - } - - if(UseFANrelais == true) { - // if a relais is used to turn on grow light, we force PWM to max val - PinFANPWM = 255; - } else { - // otherwise just do PWM - PinFANPWM = webserver.arg("PinFANPWM").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); - 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); - - webserver.sendHeader("Location", String("/growSettings?success"), true); - webserver.send(302, "text/plain", "growSettings/save: success!\n"); -} - - -void POSTsystemSettings() { - 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); - - - configured = true; - - // 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); - - // 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 - if(UseLEDrelais == true) { - PinLEDPWM = 255; - EEPROM.put(213, PinLEDPWM); - EEPROM.commit(); - Serial.println("UseLEDrelais is 1, forcing PinLEDPWM to max to prevent relais damage"); - } - - if(UseFANrelais == true) { - PinFANPWM = 255; - EEPROM.put(215, PinFANPWM); - EEPROM.commit(); - Serial.println("UseFANrelais is 1, forcing PinFANPWM to max to prevent relais damage"); - } - - 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 += "

!! Wiping CanGrow's EEPROM !!


Device will restart in a few seconds.
After restart a new WiFi 'CanGrow-unconfigured' will be created. To access the WebUI visit http://192.168.4.20
"; - 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(); - 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(); - 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(); - 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(); - 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(); - - // 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(); - 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); -}