#define VERSION "V2.4" // Pins for LED MATRIX #include Ticker display_ticker; #define P_LAT 16 #define P_A 5 #define P_B 4 #define P_C 15 #define P_D 0 //#define P_E 0 #define P_OE 2 //#define PxMATRIX_COLOR_DEPTH 4 // This is how many color levels the display shows - the more the slower the update #define double_buffer // Creates a second buffer for backround drawing (doubles the required RAM) #define MATRIX_WIDTH 64 #define MATRIX_HEIGHT 32 #include "PxMatrix.h" PxMATRIX display(64,32,P_LAT, P_OE,P_A,P_B,P_C,P_D); uint8_t display_draw_time=5; //30-60 is usually fine // This defines the 'on' time of the display is us. The larger this number,// the brighter the display. If too large the ESP will crash //WebService #define TEMPLATE_PLACEHOLDER '`' //-> Damit % in CSS funktioniert ... #include #include #include //#include AsyncWebServer webServer(80); //DNSServer dnsServer; IPAddress ip_local(192, 168, 13, 1); IPAddress ip_gateway(0, 0, 0, 0); IPAddress ip_subnet(255, 255, 255, 0); boolean APEnabled = false; char ssid[30] = "THW Freifunk"; char pass[30] = ""; //WiFiMulti.addAP("THW Freifunk", ""); // THW //WiFiMulti.addAP("ic_lg", "DEADBEEF!aaaa"); //Firma //WiFiMulti.addAP("NTW", "!TJDn@Wb868"); // daheim //permanenter Speicher #include String ChipID = "ERROR"; //i2c #include #include RV3029 rtc; const int PINRTC_CLOCK = 12; boolean rtcEnabled = false; #include long ti_second = 0; String timeColor = "ffffff"; String tacticalTimeColor = "FFFF00"; //4D4DFF String dateColor = "ffffff"; uint8_t timeCr = 0; uint8_t timeCg = 0; uint8_t timeCb = 0; uint8_t tacCr = 0; uint8_t tacCg = 0; uint8_t tacCb = 0; float brightness = 0.80; int8_t lastminutes = -1; boolean iDL = false; uint8_t lastTimeSyncTyp = 0; long lastTimeSyncTime = 0; uint8_t timeIndex = 0; bool EEPROMDataNotSaved = false; // ISR for display refresh void display_updater(){ display.display(display_draw_time); } void display_update_enable(bool is_enable){ if (is_enable) display_ticker.attach(0.001, display_updater); else display_ticker.detach(); } //Led mit Helligkeit setzen void setPixelColor(uint8_t x,uint8_t y, uint8_t red, uint8_t green ,uint8_t blue){ /*red = ceil(red * brightness); green = ceil(green * brightness); blue = ceil(blue * brightness);*/ display.drawPixelRGB888(x, y, red, green, blue); // } //Zeichene eine Linie waagrecht x/y und z als länge void LineH(uint8_t x, uint8_t y, uint8_t z, uint8_t red, uint8_t green ,uint8_t blue){ uint16_t color = display.color565(red, green, blue); display.drawFastHLine(x,y,z,color); //display.display(display_draw_time); /*for(uint8_t c = 0; c 59) x--; x += Out5x7Char((tmp)+0x30,x,y,tacCr,tacCg,tacCb); return x; } void showTimeTactical(time_t t){ uint16_t tmp = 0; uint8_t x = 0; uint8_t y = 0; tmp = minute(t); if(lastminutes != tmp){ lastminutes = tmp; doClearLEDs(); uint8_t x_tactical = drawTactical(t,0,3); if(x_tactical < 63){ x_tactical = ceil((63 - x_tactical)/2); doClearLEDs(); drawTactical(t,x_tactical+1,3); } //Uhrzeit x = 9; y = 15; tmp = hour(t); if((tmp/10 > 0)){ Out10x16Char((tmp/10)+0x30,x,y,timeCr,timeCg,timeCb); tmp -= (tmp/10)*10; } x += 11; Out10x16Char((tmp)+0x30,x,y,timeCr,timeCg,timeCb); Out10x16Char(':',x+11,y,timeCr,timeCg,timeCb); x += 14; tmp = minute(t); Out10x16Char((tmp/10)+0x30,x,y,timeCr,timeCg,timeCb); tmp -= (tmp/10)*10; x += 11; Out10x16Char((tmp)+0x30,x,y,timeCr,timeCg,timeCb); x += 11; }else{ doClearLEDsSeconds(); x = 56; y = 15; } tmp = second(t); Out3x5Char((tmp/10)+0x30,x,y+11,timeCr,timeCg,timeCb); tmp -= (tmp/10)*10; x += 4; Out3x5Char((tmp)+0x30,x,y+11,timeCr,timeCg,timeCb); } void doSetTime(unsigned long t){ rtc.reset(); rtc.setUNIX(t); } void IRAM_ATTR rtc_clock(){ //Interrupt vom RTC if(digitalRead(PINRTC_CLOCK)){ ti_second = millis() - 1020; //display.drawPixelRGB888(4,0,0,255,0); }else{ //display.drawPixelRGB888(4,0,0,0,0); } } uint8_t isDayLight(uint8_t hour, uint8_t day, uint8_t wday, uint8_t month){ if( month < 3 || month > 10 ) // month 1, 2, 11, 12 return 0; // -> Winter if( day - wday >= 25 && (wday || hour >= 2) ){ // after last Sunday 2:00 if( month == 10 ) // October -> Winter return 0; }else{ // before last Sunday 2:00 if( month == 3 ) // March -> Winter return 0; } return 1; } //NTP Update auf ganz lange uint32_t sntp_update_delay_MS_rfc_not_less_than_15000 (){ return 365 * 24 * 60 * 60 * 1000UL; // 365 Tage } //reboot!!! void display_doupdate(void){ display.showBuffer(); display.copyBuffer(); } void setup() { ChipID = String(ESP.getChipId()); display.begin(16); //display.setFlip(true); display.setBrightness(255); //display.setBrightness(ceil(255 * brightness)); display.setFastUpdate(true); doClearLEDs(true); uint32_t color = strtol(timeColor.c_str(), 0, 16); timeCr = color >> 16; timeCg = color >> 8; timeCb = color; color = strtol(tacticalTimeColor.c_str(), 0, 16); tacCr = color >> 16; tacCg = color >> 8; tacCb = color; showOVALZ(); showNTOOLS(); display_update_enable(true); Wire.begin(1,3); //Wire.setClock(400000); //RTC if (rtc.begin() == false) { display.drawPixelRGB888(0,0,255,0,0); display_doupdate(); }else{ display.drawPixelRGB888(0,0,0,255,0); display_doupdate(); rtc.setBackupSwitchoverMode(3); rtcEnabled = true; pinMode(PINRTC_CLOCK, INPUT_PULLUP); setTime(rtc.getUNIX()); long currentUNIXTime = now(); byte Month, Day, Hour, Minute, Second, WDay; Month = month(currentUNIXTime); Day = day(currentUNIXTime); Hour = hour(currentUNIXTime); Minute = minute(currentUNIXTime); Second = second(currentUNIXTime); WDay = weekday(); iDL = isDayLight(Hour,Day,WDay,Month); } String newHostname = "NTUVPx"+String(ChipID); WiFi.begin(ssid,pass); WiFi.hostname(newHostname.c_str()); int xc = 0; while ((WiFi.status() != WL_CONNECTED) && (xc < 10)) { delay(1500); xc++; display.drawPixelRGB888(xc+5,0,255,255,0); display_doupdate(); } if (WiFi.status() == WL_CONNECTED) { display.drawPixelRGB888(1,0,0,255,0); display_doupdate(); configTime("CET-1CEST,M3.5.0,M10.5.0/3", "ptbtime1.ptb.de", "ptbtime2.ptb.de", "ptbtime3.ptb.de"); time_t timenow = time(nullptr); xc = 0; while((timenow < SECS_YR_2000) && (xc < 10)) { delay(1000); timenow = time(nullptr); xc++; display.drawPixelRGB888(xc+16,0,255,255,0); display_doupdate(); } if(timenow > SECS_YR_2000){ timenow += 1; int Year; byte Month, Day, Hour, Minute, Second; setTime(timenow); Year = year(timenow); Month = month(timenow); Day = day(timenow); Hour = hour(timenow); Minute = minute(timenow); Second = second(timenow); if(isDayLight(Hour,Day,weekday(),Month)) timenow += (SECS_PER_HOUR * 2); else timenow += (SECS_PER_HOUR); if(rtcEnabled){ doSetTime(timenow); } lastTimeSyncTyp = 2; lastTimeSyncTime = now(); display.drawPixelRGB888(2,0,0,255,0); display_doupdate(); }else{ display.drawPixelRGB888(2,0,255,0,255); display_doupdate(); } //WiFi.localIP() }else{ display.drawPixelRGB888(1,0,255,0,0); display_doupdate(); WiFi.disconnect(); delay(3000); ESP.eraseConfig(); WiFi.mode(WIFI_OFF); WiFi.mode(WIFI_AP); WiFi.softAPConfig(ip_local, ip_gateway, ip_subnet); APEnabled = WiFi.softAP("NTUhr VPx "+ChipID, "gibteskeins"); } if(!APEnabled) display.drawPixelRGB888(3,0,255,0,0); else display.drawPixelRGB888(3,0,0,255,0); display_doupdate(); //dnsServer.setErrorReplyCode(DNSReplyCode::NoError); //dnsServer.start(53, "*", ip_local); //für die automatische Umleitung /*webServer.on("/generate_204", HTTP_GET, [](AsyncWebServerRequest *request){html_redirect(request);}); //Android captive portal. webServer.on("/fwlink", HTTP_GET, [](AsyncWebServerRequest *request){html_redirect(request);}); //Microsoft captive portal. webServer.on("/favicon.ico", HTTP_GET, [](AsyncWebServerRequest *request){html_redirect(request);}); webServer.on("/connecttest.txt", HTTP_GET, [](AsyncWebServerRequest *request){html_redirect(request);}); //www.msftconnecttest.com webServer.on("/hotspot-detect.html", HTTP_GET, [](AsyncWebServerRequest *request){html_redirect(request);}); //captive.apple.com webServer.on("/success.txt", HTTP_GET, [](AsyncWebServerRequest *request){html_handle_success(request);}); //detectportal.firefox.com/sucess.txt webServer.onNotFound([](AsyncWebServerRequest *request){html_redirect(request);}); */ //eigene Seiten webServer.on("/", HTTP_GET, [](AsyncWebServerRequest *request){html_root(request);}); webServer.on("/do", HTTP_GET, [] (AsyncWebServerRequest *request) {html_do(request);}); webServer.begin(); if(rtcEnabled) attachInterrupt(digitalPinToInterrupt(PINRTC_CLOCK), rtc_clock, CHANGE); delay(3000); doClearLEDsStatus(); } void loop(){ if (millis() - ti_second > 1000) { ti_second = millis(); if((timeStatus() != timeNotSet)){ time_t currentUNIXTime = now(); if(rtcEnabled){ currentUNIXTime = rtc.getUNIX(); setTime(currentUNIXTime); } byte Month, Day, Hour, Minute, Second, WDay; Month = month(currentUNIXTime); Day = day(currentUNIXTime); Hour = hour(currentUNIXTime); Minute = minute(currentUNIXTime); Second = second(currentUNIXTime); WDay = weekday(); if((isDayLight(Hour,Day,WDay,Month) != iDL) && ((Month == 10 & Hour >= 3) | (Month == 3))){ if(iDL){ doSetTime(currentUNIXTime - SECS_PER_HOUR); }else{ doSetTime(currentUNIXTime + SECS_PER_HOUR); } iDL = isDayLight(Hour,Day,WDay,Month); } //Sonntag und NTP = Reset .. if((WDay == 1) && (Hour == 3) && (Minute == 1) && (Second == 0)){ ESP.restart(); } showTimeTactical(currentUNIXTime); display_doupdate(); } } //dnsServer.processNextRequest(); //yield(); //display.copyBuffer(); } //alles was WEB ist ... #include "index_html.h" const char* PARAM_SET = "set"; const char* PARAM_POLL = "poll"; const char* PARAM_SAVE = "save"; const char* PARAM_TO = "to"; const char* PARAM_SHOWWHAT = "showWhat"; const char* PARAM_BRIGHTNESS = "brightness"; const char* PARAM_OPTIONS = "options"; const char* PARAM_SSID = "ssid"; const char* PARAM_PWD = "pwd"; const char* PARAM_RESET = "reset"; void html_root(AsyncWebServerRequest *request) { request->send_P(200, "text/html", html_page_index, html_processor); } void html_do(AsyncWebServerRequest *request) { String s_set,s_value,s_idx,s_value2; uint32_t l_value; if (request->hasParam(PARAM_SET)) { s_set = request->getParam(PARAM_SET)->value(); if((s_set == "time") & (request->hasParam(PARAM_TO))) { s_value = request->getParam(PARAM_TO)->value(); l_value = strtol(s_value.c_str(), NULL, 10); doSetTime(l_value); lastTimeSyncTyp = 3; lastTimeSyncTime = now(); }else if(request->hasParam(PARAM_SHOWWHAT)) { s_value = request->getParam(PARAM_SHOWWHAT)->value(); timeIndex = s_value.toInt(); EEPROM.put(0, timeIndex); }else if(((s_set == "color") | (s_set == "tcolor") | (s_set == "dcolor")) & (request->hasParam(PARAM_TO))) { s_value = request->getParam(PARAM_TO)->value(); uint8_t c[3]; l_value = strtol(s_value.c_str(), NULL, 16); c[0] = l_value >> 16; c[1] = l_value >> 8; c[2] = l_value; if(s_set == "color"){ timeColor[0] = c[0]; timeColor[1] = c[1]; timeColor[2] = c[2]; EEPROM.write(11,timeColor[0]); EEPROM.write(12,timeColor[1]); EEPROM.write(13,timeColor[2]); }else if(s_set == "tcolor"){ tacticalTimeColor[0] = c[0]; tacticalTimeColor[1] = c[1]; tacticalTimeColor[2] = c[2]; EEPROM.write(21,tacticalTimeColor[0]); EEPROM.write(22,tacticalTimeColor[1]); EEPROM.write(23,tacticalTimeColor[2]); }else if(s_set == "dcolor"){ /*dateColor[0] = c[0]; dateColor[1] = c[1]; dateColor[2] = c[2]; EEPROM.write(31,dateColor[0]); EEPROM.write(32,dateColor[1]); EEPROM.write(33,dateColor[2]);*/ } }else if((s_set == "option")) { if(request->hasParam(PARAM_BRIGHTNESS)) { s_value = request->getParam(PARAM_BRIGHTNESS)->value(); brightness = s_value.toFloat(); EEPROM.put(5,brightness); //display.setBrightness(ceil(255 * brightness)); } if(request->hasParam(PARAM_OPTIONS)) { s_value = request->getParam(PARAM_OPTIONS)->value(); //options = s_value.toInt(); //EEPROM.put(1,options); //autobrightness = bitRead(options,0); } }else if((s_set == "wifi")) { if((request->hasParam(PARAM_SSID)) && (request->hasParam(PARAM_PWD))){ s_value = request->getParam(PARAM_SSID)->value(); if(s_value != ssid){ s_value.toCharArray(ssid, 30); s_value = request->getParam(PARAM_PWD )->value(); s_value.toCharArray(pass, 30); EEPROM.put(101,ssid); EEPROM.put(201,pass); } } } request->send(200, "text/plain", "OK"); EEPROMDataNotSaved = true; lastminutes = -1; }else if(request->hasParam(PARAM_POLL)) { long color = 0; String ret = "[" +String(now()); color = timeColor[0] << 16; color += timeColor[1] << 8; color += timeColor[2]; ret += "," + String(color); color = tacticalTimeColor[0] << 16; color += tacticalTimeColor[1] << 8; color += tacticalTimeColor[2]; ret += "," + String(color); color = dateColor[0] << 16; color += dateColor[1] << 8; color += dateColor[2]; ret += "," + String(color); ret += "," + String(timeIndex); ret += "," + String(lastTimeSyncTyp); ret += "," + String(lastTimeSyncTime); ret += ",\"0.0\""; ret += ",\"" + String(brightness)+"\""; ret += "," + String("0"); ret += "," + String(rtcEnabled); ret += "," + String("0"); ret += "," + String("0"); ret += "," + String("0"); ret += "," + String(EEPROMDataNotSaved); ret += ",\"" + String(ssid)+"\""; ret += "]"; request->send(200, "text/plain", ret); }else if (request->hasParam(PARAM_SAVE)){ EEPROM.commit(); EEPROMDataNotSaved = false; request->send(200, "text/plain", "OK"); }else if (request->hasParam(PARAM_RESET)){ request->send(200, "text/plain", "OK"); delay(1000); ESP.restart(); } request->send(200, "text/plain", "NOK"); } // Replaces placeholder with button section in your web page String html_processor(const String& var){ if(var == "VERSION"){ return String(VERSION); }else if(var == "ID"){ return String(ChipID); } return String(); } String toggleState(int toggle){ switch(toggle){ case 0: break; } return ""; } String toStringIp(IPAddress ip) { String res = ""; for (int i = 0; i < 3; i++) { res += String((ip >> (8 * i)) & 0xFF) + "."; } res += String(((ip >> 8 * 3)) & 0xFF); return res; } void redirect(AsyncWebServerRequest *request){ AsyncWebServerResponse *response = request->beginResponse(302, "text/plain", ""); // Empty content inhibits Content-length header so we have to close the socket ourselves. response->addHeader("Location", String("http://") + toStringIp(ip_local)); request->send(response); } void handle_success(AsyncWebServerRequest *request){ request->send(200, "text/plain", "success"); }