/* #ifdef ESP32 #include #include #include #else #include #include #include #include #include #include "FS.h" #endif */ // WLAN #include #include // WLAN-Zugangsdaten const char* ssid = "MYSSID"; const char* password = "MYPASSWORD"; IPAddress ip(192,168,0,1); IPAddress gateway(192,168,0,1); IPAddress subnet(255,255,255,0); // Hostname of the ESPs -> http://esp8266.local/ const char* espHostname = "adventskranz"; // Webserver #include #include #define PORT 80 // Standard HTTP-Port 80 AsyncWebServer server(PORT); // Filesystem #include // Date and time functions using a DS1307 RTC connected via I2C and Wire lib #include "RTClib.h" RTC_DS1307 rtc; char daysOfTheWeek[7][12] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"}; DateTime now, ChristmasDay, ThreeKingsDayThisYear, ThreeKingsDayNextYear, AdventDay[4], last_day; #define MAX_CANDLES 4 #define DEBUG true #define SER_DEBUG_OUTPUT_INTERVALL 1000 // in milliseconds #define LED_TEST_INTERVALL 5000 // in milliseconds const int CandlePin[] = { // define each candle control gpi/o pin to use 14, // 1. LED Candle @ Pin D5 12, // 2. LED Candle @ Pin D6 13, // 3. LED Candle @ Pin D7 15, // 4. LED Candle @ Pin D8 }; int num_of_candles = 0; int counter = 0; int CandleToUse[] = {0, 0, 0, 0}; // Init CandlesToUse with zeros unsigned long time_start = 0; // Start time periode in milliseconds unsigned long time_stop = 0; // Stop time periode in milliseconds bool maintenance = false; // Set maintenance mode [true|false] void setupServerRoutes(); void setupFilePaths(); // What should happen when page isn't found: void notFound(AsyncWebServerRequest *request) { request->send(404, "text/html", "

404 error - Page not found!

"); } void setup() { Serial.begin(115200); #ifndef ESP8266 while (!Serial); // wait for serial port to connect. Needed for native USB #endif //Serial.println(); Serial.println("Entering setup ..."); // delay(500); if (! rtc.begin()) { Serial.println("Couldn't find RTC"); Serial.flush(); while (1) delay(10); } // Init all candle pins as "output" and switch off relay Serial.println("Init candle control pins ..."); for (int counter = 0; counter < MAX_CANDLES; counter++){ pinMode(CandlePin[counter], OUTPUT); digitalWrite(CandlePin[counter], HIGH); } // Usefull suff for handling the RTC: // if (! rtc.isrunning()) { // Serial.println("RTC is NOT running, let's set the time!"); // When time needs to be set on a new device, or after a power loss, the // following line sets the RTC to the date & time this sketch was compiled // rtc.adjust(DateTime(F(__DATE__), F(__TIME__))); // This line sets the RTC with an explicit date & time, for example to set // January 21, 2014 at 3am you would call: // rtc.adjust(DateTime(2014, 1, 21, 3, 0, 0)); // } // When time needs to be re-set on a previously configured device, the // following line sets the RTC to the date & time this sketch was compiled // rtc.adjust(DateTime(F(__DATE__), F(__TIME__))); // This line sets the RTC with an explicit date & time, for example to set // January 21, 2014 at 3am you would call: // rtc.adjust(DateTime(2022, 10, 9, 14, 20, 0)); if(SPIFFS.begin()){ Serial.println("File system initialized."); } else{ Serial.println("Error initializing file system"); } /* when ESP8266 should act as a WiFi client: WiFi.mode(WIFI_STA); WiFi.begin(ssid, password); if (WiFi.waitForConnectResult() != WL_CONNECTED) { Serial.println("WLAN Verbindung fehlgeschlagen"); return; } Serial.print("Verbunden! IP-Adresse: "); Serial.println(WiFi.localIP()); */ Serial.println("Configuring network parameters ..."); WiFi.softAPConfig(ip, gateway, subnet); Serial.println("Configuring WiFi parameters ... "); WiFi.softAP(ssid, password); // Starting mDNS-Servers if (!MDNS.begin(espHostname)) { Serial.println("Error starting mDNS-Server"); } // Define Server routes in separate function setupServerRoutes(); // Define file routes in separate function setupFilePaths(); // Start HTTP server function: Serial.println("Starting HTTP server ..."); server.begin(); random_candles(); // random all candles Serial.println("Switch OFF all candles..."); set_all_candles(HIGH); // switch all candles off Serial.println("Switch ON all candles..."); set_all_candles(LOW); // switch all candles on delay(LED_TEST_INTERVALL); // wait for LED_TEST_INTERVALL seconds Serial.println("Switch OFF all candles..."); set_all_candles(HIGH); // switch all candles off get_current_timestamp(); // get current timestamp DateTime last_day ((now.year()), (now.month()), (now.day()), 00, 00, 00); // save actual day for later use } // END OF SETUP() void loop() { MDNS.update(); time_stop = millis(); // get current ticks counter // execute every SER_DEBUG_OUTPUT_INTERVALL milliseconds if (((time_stop - time_start) > SER_DEBUG_OUTPUT_INTERVALL) && (maintenance == false)) { time_start = time_stop; get_current_timestamp(); // get current timestamp //Serial.println("Actual time and date: "); printDate(now); //Serial.print("."); if ( last_day.day() != now.day() ) { // check if we have a new day to scramble the candles again //Serial.print("new day!"); set_all_candles(HIGH); // switch all candles off random_candles(); // random all candles } //Serial.println("Calculate celebration dates ..."); DateTime ChristmasDay (now.year(), 12, 24, 00, 00, 00); //Serial.print("Christmas: "); //printDate(ChristmasDay); DateTime ThreeKingsDayThisYear ((now.year()), 01, 06, 23, 59, 59); //Serial.print("Three Kings this year: "); //printDate(ThreeKingsDayThisYear); DateTime ThreeKingsDayNextYear ((now.year()+1), 01, 06, 23, 59, 59); //Serial.print("Three Kings next year: "); //printDate(ThreeKingsDayNextYear); get_advent_days(ChristmasDay); //Serial.println("Check calendar week ..."); if (now.unixtime() <= ThreeKingsDayThisYear.unixtime()) { //Serial.println("we are past New Year's Eve but before Three Kings Day -> all candles on"); num_of_candles = 4; } else if ((now.unixtime() > ThreeKingsDayThisYear.unixtime()) && (now.unixtime() < AdventDay[0].unixtime())) { //Serial.println("we are between Three Kings Day and 1st. advent! -> all candles off"); num_of_candles = 0; } else if ((now.unixtime() >= AdventDay[0].unixtime()) && (now.unixtime() < AdventDay[1].unixtime())) { //Serial.println("we are in 1st. advent week! -> turn 1 candles on"); num_of_candles = 1; } else if ((now.unixtime() >= AdventDay[1].unixtime()) && (now.unixtime() < AdventDay[2].unixtime())) { //Serial.println("we are in 2nd. advent week! -> turn 2 candles on"); num_of_candles = 2; } else if ((now.unixtime() >= AdventDay[2].unixtime()) && (now.unixtime() < AdventDay[3].unixtime())) { //Serial.println("we are in 3rd. advent week! -> turn 3 candles on"); num_of_candles = 3; } else if ((now.unixtime() >= AdventDay[3].unixtime()) && (now.unixtime() <= ChristmasDay.unixtime())) { //Serial.println("we are in 4th. advent week! -> turn all 4 candles on"); num_of_candles = 4; } else if ((now.unixtime() >= ChristmasDay.unixtime())&& (ThreeKingsDayNextYear.unixtime())) { //Serial.println("we are bast Christmas day but before Three Kings day! -> turn all 4 candles on"); num_of_candles = 4; } else { //Serial.println("We should not go here, what's wrong?"); } if (num_of_candles >= 1){ for (int counter = 0; counter < num_of_candles; counter++){ digitalWrite(CandleToUse[counter], LOW); // switch CandleToUse[counter] ON (yes LOW means ON because the relay logic is low active) } } else{ set_all_candles(HIGH); // otherwise switch all candles off } //Serial.println(); } last_day = now; } // END OF LOOP() void setupServerRoutes(){ // Document-Root --> folder "data" // All file path must be defines relative to "data" // Deliver file "index.html" server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){ request->send(SPIFFS, "/index.html", String(), false, processor); //request->send(SPIFFS, "/index.html"); }); server.onNotFound(notFound); } void setupFilePaths(){ server.on("/jquery.mobile-1.4.5.css", HTTP_GET, [](AsyncWebServerRequest *request){ request->send(SPIFFS, "/jquery.mobile-1.4.5.css", "text/css"); }); server.on("/jqm-datebox-1.4.5.all.js", HTTP_GET, [](AsyncWebServerRequest *request){ request->send(SPIFFS, "/jqm-datebox-1.4.5.all.js", "text/javascript"); }); server.on("/jquery.mobile-1.4.5.js", HTTP_GET, [](AsyncWebServerRequest *request){ request->send(SPIFFS, "/jquery.mobile-1.4.5.js", "text/javascript"); }); server.on("/jquery-1.12.4.min.js", HTTP_GET, [](AsyncWebServerRequest *request){ request->send(SPIFFS, "/jquery-1.12.4.min.js", "text/javascript"); }); server.on("/images/ajax-loader.gif", HTTP_GET, [](AsyncWebServerRequest *request){ request->send(SPIFFS, "/ajax-loader.gif", "image/gif"); }); server.on("/favicon.ico", HTTP_GET, [](AsyncWebServerRequest *request){ request->send(SPIFFS, "/favicon.ico", "text/html"); }); server.on("/get", HTTP_GET, [] (AsyncWebServerRequest *request) { String message; String state; if (request->hasParam("pinstate")) { message = request->getParam("pinstate")->value(); state = get_PinState(message.toInt()); //Serial.print("GET Pinstate: "); //Serial.print(message); //Serial.print(" -> "); //Serial.println(state); //request->send(200, "text/plain", "Hello, GET: " + message); //request->send(200, "text/plain", "ON"); request->send(200, "text/plain", state.c_str()); } else if (request->hasParam("maintenance")) { if (maintenance == true){ message = "ON"; } else { message = "OFF"; } //Serial.print("GET Mainenance: "); //Serial.println(message); //request->send(200, "text/plain", "Hello, GET: " + message); //request->send(200, "text/plain", "ON"); request->send(200, "text/plain", message.c_str()); } else if (request->hasParam("time")) { //Serial.print("GET Time: "); //Serial.println(message); //request->send(200, "text/plain", "Hello, GET: " + message); //request->send(200, "text/plain", "ON"); request->send_P(200, "text/plain", getTime().c_str()); } else if (request->hasParam("date")) { //Serial.print("GET Date: "); //Serial.println(message); //request->send(200, "text/plain", "Hello, GET: " + message); //request->send(200, "text/plain", "ON"); request->send_P(200, "text/plain", getDate().c_str()); } else { message = "No message sent"; Serial.print("GET: "); Serial.println(message); } }); server.on("/set", HTTP_GET, [] (AsyncWebServerRequest *request) { String message; if (request->hasParam("pinstate")) { message = request->getParam("pinstate")->value(); //Serial.print("SET Pinstate: "); //Serial.println(message); int candle_number = message.substring(0,message.indexOf(':')).toInt(); String state = message.substring(message.indexOf(':')+1, message.length()); if (state == "ON") { set_candle(candle_number, LOW); } else { set_candle(candle_number, HIGH); } //request->send(200, "text/plain", "Hello, GET: " + message); //request->send(200, "text/plain", "ON"); //request->send(200, "text/plain", get_PinState(message.toInt()).c_str()); request->send(200); } else if (request->hasParam("maintenance")) { message = request->getParam("maintenance")->value(); if (message == "true"){ maintenance = true; // enable maintenance mote set_all_candles(HIGH); // switch all candles off } else { set_all_candles(HIGH); // switch all candles off maintenance = false; // disable maintenance mode } //Serial.print("SET Maintenance: "); //Serial.println(message); //Serial.print(":"); //Serial.println(value); request->send(200); } else if (request->hasParam("reorder_candles")) { //message = request->getParam("reorder_candles")->value(); //Serial.print("SET Reorder Candles: "); //Serial.println(message); reorder_candles(); request->send(200); } else if (request->hasParam("time")) { message = request->getParam("time")->value(); //Serial.print("SET Time to: "); //Serial.println(message); int set_hour = message.substring(0,message.indexOf(':')).toInt(); int set_minute = message.substring(message.indexOf(':')+1, message.length()).toInt(); now = rtc.now(); // get current time and date rtc.adjust(DateTime(now.year(), now.month(), now.day(), set_hour, set_minute, 0)); request->send(200); } else if (request->hasParam("date")) { message = request->getParam("date")->value(); //Serial.print("SET Date to: "); //Serial.println(message); int first = message.indexOf('-'); int second = message.indexOf('-', first + 1 ); int set_year = message.substring(0,first).toInt(); int set_month = message.substring(first+1,second).toInt(); int set_day = message.substring(second+1, message.length()).toInt(); now = rtc.now(); // get current time and date rtc.adjust(DateTime(set_year, set_month, set_day, now.hour(), now.minute(), now.second())); set_all_candles(HIGH); // switch all candles off request->send(200); } else { message = "No message sent"; //Serial.print("SET: "); //Serial.println(message); request->send(200); } }); } String processor(const String& var){ Serial.println(var); /* this function to replace "placeholders (%PLACEHOLDER%) is not used anymore but we keep this strukture maybe for later use ... if (var == "SWITCHSTATE1"){ return get_PinState(0); } else if (var == "SWITCHSTATE2"){ return get_PinState(1); } else if (var == "SWITCHSTATE3"){ return get_PinState(2); } else if (var == "SWITCHSTATE4"){ return get_PinState(3); } else if (var == "MAINTENACESTATE"){ if (maintenance == false){ return ""; } else{ return "checked"; } } */ return ""; // returns nothing ;-) } String getTime() { char actual_time[8]; now = rtc.now(); // get current time and date sprintf(actual_time,"%02u:%02u:%02u", now.hour(), now.minute(), now.second()); //Serial.print("Send system time: "); //Serial.println(actual_time); return String(actual_time); } String getDate() { char actual_date[10]; now = rtc.now(); // get current time and date sprintf(actual_date,"%02u:%02u:%02u", now.day(), now.month(), now.year()); //Serial.print("Send system date: "); //Serial.println(actual_date); return String(actual_date); } void random_candles (){ for (int counter = 0; counter < MAX_CANDLES; counter++){ CandleToUse[counter] = 0; } int buff = 0; if (DEBUG == true) { //Serial.println("Debug: Entering \"random_candles\""); } counter = 0; do { buff = random(0, MAX_CANDLES); if (CandleToUse[buff] == 0 ){ CandleToUse[buff] = CandlePin[counter]; counter+=1; } } while (counter < MAX_CANDLES); /* if (DEBUG == true) { Serial.print("Debug: Candle order today: "); Serial.print(CandleToUse[0], DEC); Serial.print(", "); Serial.print(CandleToUse[1], DEC); Serial.print(", "); Serial.print(CandleToUse[2], DEC); Serial.print(", "); Serial.println(CandleToUse[3], DEC); } */ } void reorder_candles(){ if (maintenance == false){ maintenance = true; // enable maintenance mote set_all_candles(HIGH); // switch all candles off random_candles(); // random all candles maintenance = false; // disable maintenance mode } else { set_all_candles(HIGH); // switch all candles off random_candles(); // random all candles } } void set_candle (int candle_number, bool switch_state){ // switch_state == LOW --> candle on; switch_state == HIGH --> candle off //for (int counter = 0; counter < numberofcandles; counter++){ if(digitalRead(CandlePin[candle_number]) == switch_state){ //Serial.println("no candle state change"); } else { /* if (DEBUG == true) { Serial.print("Debug: Switching candle "); Serial.print(counter, DEC); Serial.print(" to "); Serial.println(switch_state ? "OFF" : "ON"); } */ digitalWrite(CandlePin[candle_number], switch_state); } //} } void set_all_candles(bool switch_state){ // switch_state == LOW --> candle on; switch_state == HIGH --> candle off for (int counter = 0; counter < MAX_CANDLES; counter++){ set_candle(counter, switch_state); /* if (DEBUG == true) { Serial.print("Debug: Switching candle "); Serial.print(counter, DEC); Serial.print(" to "); Serial.println(switch_state ? "OFF" : "ON"); } */ } } String get_PinState(int output){ //Serial.print("Candle "); //Serial.print(output); if(digitalRead(CandlePin[output]) == HIGH){ //Serial.println(" is OFF"); return "OFF"; } else { //Serial.println(" is ON"); return "ON"; } } void get_advent_days (const DateTime& dt){ AdventDay[3] = (dt - TimeSpan(dt.dayOfTheWeek(),0,0,0)); for (int counter = 0; counter <= 2 ; counter++){ AdventDay[counter] = AdventDay[3] - TimeSpan(((3 - counter) * 7), 0, 0, 0); } // print advent days /* if (DEBUG == true) { Serial.print("1st. advent day: "); printDate(AdventDay[0]); //Serial.println(dateToUnix(AdventDay[0])); Serial.print("2nd. advent day: "); printDate(AdventDay[1]); //Serial.println(dateToUnix(AdventDay[1])); Serial.print("3rd. advent day: "); printDate(AdventDay[2]); Serial.print("4th. advent day: "); printDate(AdventDay[3]); } */ } void get_current_timestamp(){ now = (00, 00, 00, 00, 00, 00); now = rtc.now(); // get current time and date delay(50); /* if (DEBUG == true) { printDate(now); } */ } void printDate(const DateTime& dt) { char s[80]; sprintf(s,"Time: %02u:%02u:%02u - Date: %02u.%02u.%04u - Day of Week: %1u",dt.hour(), dt.minute(), dt.second(), dt.day(), dt.month(), dt.year(), dt.dayOfTheWeek()); Serial.println(s); }