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