String FileName = "WlD02h_OTA"; char GName [10] = "Schalt"; //Names Teil vom Gerät WlanDoseTom WlanDoseTomConfig /* ESP-Anschluß: Reset frei ADC frei EN + GPIO12 SchalterErstes Layout !!!!! dann 16 !!!! GPIO15 0V GPIO0 + (zum Proggen auf Masse */ #include //this needs to be first, or it all crashes and burns... extern "C" { #include "user_interface.h" } #include #include #include #include #include #include #include #include #include #include #include unsigned long myPeriodic = 24 * 60 * 60 * 1000; // in msec | NTP-Prüfung in 24 Std sec unsigned long Thimer; int GPIO_Pin = 12; // what is our longitude (west values negative) and latitude (south values negative) float const LONGITUDE = 22.84; //geoLaenge float const LATITUDE = 45.19; //geoBreite byte today[] = { 0, 0, 12, 27, 10, 2017 - 1970 }; // store today's date (at noon) in an array for TimeLord to use strDateTime dateTime; bool shouldSaveConfig = false; char BGrad [10] = "22.84"; char LGrad [10] = "45.19"; //char GName [10] = "Gang"; //Names Teil vom Gerät WlanDoseTom WlanDoseTomConfig char NTPPfad [20] = "ch.pool.ntp.org"; char SOffset [4] = "18"; //Zeit in Min die VOR Sonnenuntergang und NACH Sonnenaufgang geschaltet werden soll WiFiManagerParameter custom_LGrad("Laengengrad", "LGrad", LGrad, 10); WiFiManagerParameter custom_BGrad("Breitengrad", "BGrad", BGrad, 10); WiFiManagerParameter custom_GName("Name der Dose", "GName", GName, 10); WiFiManagerParameter custom_NTPPfad("NTP-Server-Adresse", "NTPPfad", NTPPfad, 20); WiFiManagerParameter custom_SOffset("Min vor/nach Schaltpunkt", "SOffset", SOffset, 4); WiFiClient client; WiFiServer server(80); String ServerName = "WlanDose"; String APName = "Config"; #define AN true #define AUS false boolean ToDo; //nächster Schaltzustand boolean action; //aktueller Schaltzustand boolean action_alt; //vorheriger Schaltzustand unsigned long Action_Uhrzeit; String sAufgang, sUntergang; unsigned long ulReqcount; unsigned long SunA_ux; unsigned long SunU_ux; //*************************************************************************************** // Neue Parameter nach Config Mode sichern //*************************************************************************************** void saveConfigCallback () { Serial.println("Should save config"); shouldSaveConfig = true; } //*************************************************************************************** // Meldung am TFT wenn Configmode //*************************************************************************************** //gets called before WiFiManager enters configuration mode void configModeCallback (WiFiManager *myWiFiManager) { Serial.println("!"); } //*************************************************************************************** // Steckdose Schalten //*************************************************************************************** void Steckdose_schalten(boolean action) { if (action) { // Licht an Serial.println("I Mach eds an !!"); digitalWrite(GPIO_Pin, 1); // GPIO12 } else { // Licht aus Serial.println("I Mach eds aus !!"); digitalWrite(GPIO_Pin, 0); // GPIO12 } } //*************************************************************************************** // WEB-Fernsteuerung //*************************************************************************************** void Fernsteuerung() { // Check if a client has connected WiFi.hostname(ServerName); WiFiClient client = server.available(); if (!client) { return; } // Wait until the client sends some data Serial.println("new client"); unsigned long ultimeout = millis() + 250; while (!client.available() && (millis() < ultimeout) ) { delay(1); } if (millis() > ultimeout) { Serial.println("client connection time-out!"); return; } // Read the first line of the request String sRequest = client.readStringUntil('\r'); Serial.println(sRequest); client.flush(); // stop client, if request is empty if (sRequest == "") { Serial.println("empty request! - stopping client"); client.stop(); return; } // get path; end of path is either space or ? // Syntax is e.g. GET /?pin=MOTOR1STOP HTTP/1.1 String sPath = "", sParam = "", sCmd = ""; String sGetstart = "GET "; int iStart, iEndSpace, iEndQuest; iStart = sRequest.indexOf(sGetstart); if (iStart >= 0) { iStart += +sGetstart.length(); iEndSpace = sRequest.indexOf(" ", iStart); iEndQuest = sRequest.indexOf("?", iStart); // are there parameters? if (iEndSpace > 0) { if (iEndQuest > 0) { // there are parameters sPath = sRequest.substring(iStart, iEndQuest); sParam = sRequest.substring(iEndQuest, iEndSpace); } else { // NO parameters sPath = sRequest.substring(iStart, iEndSpace); } } } /////////////////////////////////////////////////////////////////////////////// // output parameters to serial, you may connect e.g. an Arduino and react on it /////////////////////////////////////////////////////////////////////////////// if (sParam.length() > 0) { int iEqu = sParam.indexOf("="); if (iEqu >= 0) { sCmd = sParam.substring(iEqu + 1, sParam.length()); Serial.println(sCmd); } } /////////////////////////// // format the html response /////////////////////////// String sResponse, sHeader; //////////////////////////// // 404 for non-matching path //////////////////////////// if (sPath != "/") { sResponse = "404 Not Found

Not Found

The requested URL was not found on this server.

"; sHeader = "HTTP/1.1 404 Not found\r\n"; sHeader += "Content-Length: "; sHeader += sResponse.length(); sHeader += "\r\n"; sHeader += "Content-Type: text/html\r\n"; sHeader += "Connection: close\r\n"; sHeader += "\r\n"; } /////////////////////// // format the html page /////////////////////// else { ulReqcount++; sResponse = "Steckdosen-Steuerung"; sResponse += ""; sResponse += "

"; sResponse += ServerName; sResponse += "-Steuerung

Schalter

"; ////////////////////// // react on parameters ////////////////////// if (sCmd.length() > 0) { // write received command to html page if (sCmd.indexOf("EIN") >= 0) { action = AN; Serial.println ("Licht EIN"); } else if (sCmd.indexOf("AUS") >= 0) { action = AUS; Serial.println ("Licht AUS"); } } if (action) { sResponse += "Status: EIN
"; Serial.println ("Status: EIN"); } else { sResponse += "Status: AUS
"; Serial.println ("Status: AUS"); } sResponse += ""; sResponse += "
Aufrufzähler="; sResponse += ulReqcount; sResponse += "
"; sResponse += Zeit(now()); sResponse += "
"; sResponse += sAufgang; sResponse += "
"; sResponse += sUntergang; sResponse += "
"; sResponse += "Offset " ; sResponse += SOffset; sResponse += " Minuten"; sResponse += "
"; sResponse += "
Nächste Schaltzeit: "; sResponse += Zeit(Action_Uhrzeit); sResponse += "
Nächster Sonnen-Schaltzustand: "; if (ToDo) { sResponse += "EIN
"; } else { sResponse += "AUS
"; } sResponse += "
Tomtom 08/2017
"; sResponse += FileName; sResponse += "
"; sHeader = "HTTP/1.1 200 OK\r\n"; sHeader += "Content-Length: "; sHeader += sResponse.length(); sHeader += "\r\n"; sHeader += "Content-Type: text/html\r\n"; sHeader += "Connection: close\r\n"; sHeader += "\r\n"; } // Send the response to the client client.print(sHeader); client.print(sResponse); // and stop the client client.stop(); Serial.println("Client disonnected"); } //*************************************************************************************** // Init SPIFFS "Festplatte" Einrichten //*************************************************************************************** void Init_SPIFFS() { //clean FS, for testing //SPIFFS.format(); //read configuration from FS json Serial.println("mounting FS..."); if (SPIFFS.begin()) { Serial.println("mounted file system"); if (SPIFFS.exists("/config.json")) { //file exists, reading and loading Serial.println("reading config file"); File configFile = SPIFFS.open("/config.json", "r"); if (configFile) { Serial.println("opened config file"); size_t size = configFile.size(); // Allocate a buffer to store contents of the file. std::unique_ptr buf(new char[size]); configFile.readBytes(buf.get(), size); DynamicJsonBuffer jsonBuffer; JsonObject& json = jsonBuffer.parseObject(buf.get()); json.printTo(Serial); if (json.success()) { Serial.println("\nparsed json"); strcpy(LGrad, json["LGrad"]); strcpy(BGrad, json["BGrad"]); strcpy(GName, json["GName"]); strcpy(NTPPfad, json["NTPPfad"]); strcpy(SOffset, json["SOffset"]); } else { Serial.println("failed to load json config"); } } } } else { Serial.println("failed to mount FS"); } //end read // The extra parameters to be configured (can be either global or just in the setup) // After connecting, parameter.getValue() will get you the configured value // id/name placeholder/prompt default length } //*************************************************************************************** // Wifi Manager Initialisieren //*************************************************************************************** void InitWiFiManager() { WiFiManager wifiManager; WiFi.setAutoConnect(true); wifiManager.setSaveConfigCallback(saveConfigCallback); wifiManager.setAPCallback(configModeCallback); wifiManager.addParameter(&custom_LGrad); wifiManager.addParameter(&custom_BGrad); wifiManager.addParameter(&custom_GName); wifiManager.addParameter(&custom_NTPPfad); wifiManager.addParameter(&custom_SOffset); wifiManager.setConfigPortalTimeout(60); //wifiManager.setDebugOutput(true); //reset settings - for testing //wifiManager.resetSettings(); //fetches ssid and pass and tries to connect //if it does not connect it starts an access point with the specified name //here "AutoConnectAP" //and goes into a blocking loop awaiting configuration ServerName += GName; APName += GName; if (!wifiManager.autoConnect((const char*)APName.c_str())) { delay(3000); WiFi.softAPdisconnect(true); //AP Ausschalten //reset and try again, or maybe put it to deep sleep ESP.reset(); delay(5000); } WiFi.softAPdisconnect(true); //AP Ausschalten } //*************************************************************************************** // Arduino OTA Initialisierung //*************************************************************************************** void InitOTA() { ArduinoOTA.onStart([]() { Serial.println("Start"); }); ArduinoOTA.onEnd([]() { Serial.println("\nEnd"); }); ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) { Serial.printf("Progress: %u%%\r", (progress / (total / 100))); }); ArduinoOTA.onError([](ota_error_t error) { Serial.printf("Error[%u]: ", error); if (error == OTA_AUTH_ERROR) Serial.println("Auth Failed"); else if (error == OTA_BEGIN_ERROR) Serial.println("Begin Failed"); else if (error == OTA_CONNECT_ERROR) Serial.println("Connect Failed"); else if (error == OTA_RECEIVE_ERROR) Serial.println("Receive Failed"); else if (error == OTA_END_ERROR) Serial.println("End Failed"); }); ArduinoOTA.begin(); Serial.println("OTA Ready"); Serial.print("IP address: "); Serial.println(WiFi.localIP()); } //*************************************************************************************** // Config Portal Parameter Speichern //*************************************************************************************** void Save_CP_Parameter() { //save the custom parameters to FS if (shouldSaveConfig) { Serial.println("saving config"); strcpy(LGrad, custom_LGrad.getValue()); strcpy(BGrad, custom_BGrad.getValue()); strcpy(GName, custom_GName.getValue()); strcpy(NTPPfad, custom_NTPPfad.getValue()); strcpy(SOffset, custom_SOffset.getValue()); DynamicJsonBuffer jsonBuffer; JsonObject& json = jsonBuffer.createObject(); json["LGrad"] = LGrad; json["BGrad"] = BGrad; json["GName"] = GName; json["NTPPfad"] = NTPPfad; json["SOffset"] = SOffset; File configFile = SPIFFS.open("/config.json", "w"); if (!configFile) { Serial.println("failed to open config file for writing"); } json.printTo(Serial); json.printTo(configFile); configFile.close(); //end save } } //*************************************************************************************** // NTP abrufen //*************************************************************************************** void NTP_SSZeit() { NTPtime NTPch(NTPPfad); dateTime = NTPch.getNTPtime(1.0, 1); setTime(dateTime.hour, dateTime.minute, dateTime.second, dateTime.day, dateTime.month, dateTime.year); tmElements_t SunA; SunA.Hour = 12; SunA.Minute = 0; SunA.Second = 0; SunA.Day = dateTime.day; SunA.Month = dateTime.month; SunA.Year = dateTime.year - 1970; // offset from 1970 TimeLord sonne; sonne.TimeZone(2 * 60); // Zeitzone sonne.DstRules(3, 2, 11, 1, 60); // second sunday in march thru first sunday in november sonne.Position(LATITUDE, LONGITUDE); // Breite und Länge übergeben today[0] = 0; today[1] = 0; today[2] = 12; today[3] = dateTime.day; today[4] = dateTime.month; today[5] = dateTime.year; if (sonne.SunRise(today)) // if the sun will rise today (it might not, in the [ant]arctic) { sAufgang = "Sonnenaufgang: "; sAufgang += String ((int) today[tl_hour]); sAufgang += (":"); if ((int) today[tl_minute] < 10) { sAufgang += "0"; } sAufgang += String ((int) today[tl_minute]); Serial.println(sAufgang); SunA.Minute = today[tl_minute]; SunA.Hour = today[tl_hour]; SunA_ux = makeTime(SunA) + atoi(SOffset) * 60; //Offset damit später ausgeschaltet wird } if (sonne.SunSet(today)) // if the sun will set today (it might not, in the [ant]arctic) { sUntergang = "Sonnenuntergang: "; sUntergang += String ((int) today[tl_hour]); sUntergang += (":"); if ((int) today[tl_minute] < 10) { sUntergang += "0"; } sUntergang += String ((int) today[tl_minute]); Serial.println(sUntergang); SunA.Minute = today[tl_minute]; SunA.Hour = today[tl_hour]; SunU_ux = makeTime(SunA) - atoi(SOffset) * 60; //Offset damit Früher eingeschaltet wird } unsigned long nau = now(); if (nau >= SunA_ux && nau >= SunU_ux) {//Es ist später als Aufgang und später als Untergang Serial.println("Es ist Nacht - Licht an"); Action_Uhrzeit = nau + 24 * 60 * 60; today[0] = 0; today[1] = 0; today[2] = 12; today[3] = day(Action_Uhrzeit); today[4] = month(Action_Uhrzeit); today[5] = year(Action_Uhrzeit); sonne.SunRise(today); sAufgang = "Sonnenaufgang: "; sAufgang += String ((int) today[tl_hour]); sAufgang += (":"); if ((int) today[tl_minute] < 10) { sAufgang += "0"; } sAufgang += String ((int) today[tl_minute]); Serial.println(sAufgang); SunA.Minute = today[tl_minute]; SunA.Hour = today[tl_hour]; SunA.Day = day(Action_Uhrzeit); SunA.Month = month(Action_Uhrzeit); SunA.Year = year(Action_Uhrzeit) - 1970; // offset from 1970 SunA_ux = makeTime(SunA) + atoi(SOffset) * 60; //Offset damit später ausgeschaltet wird Action_Uhrzeit = SunA_ux; ToDo = AUS; } else if (nau <= SunA_ux && nau <= SunU_ux) {//Es ist früher als Aufgang und früher als Untergang Serial.println("Es ist Nacht - Licht an"); Action_Uhrzeit = SunA_ux; ToDo = AUS; } else if (nau >= SunA_ux && nau <= SunU_ux) {//Es ist später als Aufgang und früher als Untergang Serial.println("Es ist Tag - Licht aus"); Action_Uhrzeit = SunU_ux; ToDo = AN; } /* Serial.print("Action_Uhrzeit = "); Serial.println(Action_Uhrzeit); */ } //*************************************************************************************** // Uhrzeit testen //*************************************************************************************** String Zeit(time_t t) { String Z = ""; int x = hour(t); if (x < 10) { Z += "0"; } Z += String(x) + ":"; x = minute(t); if (x < 10) { Z += "0"; } Z += String(x) + ":"; x = second(t); if (x < 10) { Z += "0"; } Z += String(x) + " "; x = day(t); if (x < 10) { Z += "0"; } Z += String(x) + "."; x = month(t); if (x < 10) { Z += "0"; } Z += String(x) + "."; x = year(t); if (x < 10) { Z += "0"; } Z += String(x); return Z; } //*************************************************************************************** // Setup //*************************************************************************************** void setup() { Serial.begin(115200); Serial.println(); Serial.println("\n Starting"); pinMode(GPIO_Pin, OUTPUT); ulReqcount = 0; Init_SPIFFS(); InitWiFiManager(); Save_CP_Parameter(); InitOTA(); server.begin(); NTP_SSZeit(); Thimer = millis(); action = !ToDo; action_alt = !action; } void loop() { ArduinoOTA.handle(); // Schaltzeit erreicht ? if (now() >= Action_Uhrzeit ) { action = ToDo; NTP_SSZeit(); //neueschaltzeit ausrechnen action_alt = !action; } // Schalten if (action != action_alt) { Steckdose_schalten(action); action_alt = action; } // Webseite abfragen Fernsteuerung(); }