From e9ae7c34c7bba07399d1c74cb13040556a65c736 Mon Sep 17 00:00:00 2001 From: cschwinne Date: Sun, 15 Jan 2017 00:24:28 +0100 Subject: [PATCH] Added (highly unstable and experimental) NTP time support Added timezones library (CET for now, you can easily adapt it to your timezone however) Added overlays to support both digital and analog clockfaces, basic countdown Improved serial debug Included license notes in settings file Added a bit of guides to readme file Warning! Using NTP usually results in a complete system crash after 1-48 hours. Please only enable it if you are willing to experiment with it. To get a proper WLED experience, make sure the checkbox for NTP is disabled in settings! --- readme.md | 64 ++++++++++++++++++++++++++++++++++++++++ wled00/data/settings.htm | 9 +++++- wled00/wled00.ino | 62 +++++++++++++++++++++++++++++++------- wled00/wled02_xml.ino | 8 ++--- wled00/wled03_set.ino | 2 +- wled00/wled04_file.ino | 14 ++++----- wled00/wled05_init.ino | 32 ++++++++++---------- wled00/wled10_ntp.ino | 29 ++++++++++++++---- wled00/wled11_ol.ino | 24 +++++++-------- 9 files changed, 188 insertions(+), 56 deletions(-) diff --git a/readme.md b/readme.md index 2186d953..93666cde 100644 --- a/readme.md +++ b/readme.md @@ -16,3 +16,67 @@ Additions for V0.3 (nearly complete!) - Support for power pushbutton - Full OTA software update capability - Password protected OTA page for added security (OTA lock) + +Compile settings: +Board: WeMos D1 mini +CPU frequency: 80 MHz +Flash size : 4MB (1MB settings) +Upload speed: 115200 + + +Quick start guide: + +1. Make sure your ESP module has a min. 4MB SPI flash module. (currently working on supporting 1MB modules) +Connect a WS2812B RGB led strip to GPIO2. Optionally connect a NO-pushbutton to GPIO0 (internal pull-up) and ground. + +2. Follow a guide to setup your Arduino client (I am using version 1.6.9) with the ESP8266 libraries. +For current compiles I use an old version from 15th August 2016. + +3. You will also need the ESP8266 SPIFFS sketch data uploader. (currently working on making this step unnecessary) + +4. In file "wled00.ino", change the LED count to the amount you connected. Proceed to flash the sketch and the SPIFFS data. +You should also change the access point and OTA update passphrases for added security (you can change them later, this is just the "factory default"). + +5. Connect to automatically started WiFi access point "WLED-AP" using default passwort "wled1234". Go to the IP "192.168.4.1". + +6. Click on the wrench icon to edit settings like connecting the module to your home WiFi. + +7. Have fun with the software! + + +Advanced module control via HTTP requests: + +Base URL scheme: "/ajax_in". This will return a XML file with some current values. +Add one or multiple of the following parameters after the base url to change values: +"&A=<0-255>" set LED brightness (yellow slider) +"&R=<0-255>" set LED red value (red slider) +"&G=<0-255>" set LED green value (green slider) +"&B=<0-255>" set LED blue value (blue slider) +"&FX=<0-47>" set LED effect (refer to WS2812FX library) +"&SX=<0-255>" set LED effect speed (refer to WS2812FX library) +"&NR=<0 or 1>" receive notifications on or off +"&NS=<0 or 1>" send (direct) notifications on or off +"&NL=<0 or 1>" turns nightlight function on or off +("&OL=<0, 1, 3 or 5>" experimental clock overlays) +("&I=<0-255>" experimental individual LED control) +("&I=<0-255>&I2=<0-255>" experimental individual LED range control) + + +Software update procedure: + +Method 1: Reflash the new update source via USB. + +Method 2: The software has an integrated OTA software update capability. +First you have to enable it by typing in the correct OTA passphrase (default: "wledota") in the settings menu. +Remove the tick in the checkbox "OTA locked". Then save settings and reboot the ESP. +Now you can go to "/update" to update binary firmware. +To edit flash content (images and HTML), go to "/edit". +After you are done, it is recommended to lock the OTA function again. +To do so, tick the checkbox again (you can change the passphrase by typing in a new one now). Reboot. +If you try to access the update page now, you should see the message "OTA lock active". + + + + + + diff --git a/wled00/data/settings.htm b/wled00/data/settings.htm index 6e120863..2961b750 100644 --- a/wled00/data/settings.htm +++ b/wled00/data/settings.htm @@ -139,6 +139,8 @@ Send notifications on button press:
Send nightlight notifications:

Time

+ Warning! Using NTP usually results in a complete system crash after 1-48 hours.
+ Please only enable it if you are willing to experiment with it.

Get time from NTP server:
Current local time is unknown

Security

@@ -156,7 +158,12 @@ HTTP traffic is not encrypted. An attacker in the same network could intercept form data!

About

WLED version 0.3pd
- (c) 2016 Christian Schwinne
+ (c) 2016-2017 Christian Schwinne
+ Licensed under the MIT license
+ Uses libraries:
+ ESP8266 Arduino Core
+ WS2812FX by kitesurfer1404 (Aircoookie fork)
+ Timezone library by JChristensen
Server message: XML response error!

diff --git a/wled00/wled00.ino b/wled00/wled00.ino index 6472a3bc..79c44fb6 100644 --- a/wled00/wled00.ino +++ b/wled00/wled00.ino @@ -16,15 +16,32 @@ #include #include +//to toggle usb serial debug (un)comment following line +#define DEBUG + +#ifdef DEBUG + #define DEBUG_PRINT(x) Serial.print (x) + #define DEBUG_PRINTLN(x) Serial.println (x) + #define DEBUG_PRINTF(x) Serial.printf (x) +#else + #define DEBUG_PRINT(x) + #define DEBUG_PRINTLN(x) + #define DEBUG_PRINTF(x) +#endif + /* * @title WLED project sketch * @version 0.3pd * @author Christian Schwinne */ //Hardware-settings (only changeble via code) -uint8_t led_amount = 10; +uint8_t led_amount = 84; uint8_t buttonPin = 0; //needs pull-up +//AP and OTA default passwords (change them!) +String appass = "wled1234"; +String otapass = "wledota"; + TimeChangeRule CEST = {"CEST", Last, Sun, Mar, 2, 120}; //Central European Summer Time TimeChangeRule CET = {"CET ", Last, Sun, Oct, 3, 60}; //Central European Standard Time Timezone TZ(CEST, CET); @@ -37,7 +54,6 @@ String clientssid = "Your_Network_Here"; String clientpass = "Dummy_Pass"; String cmdns = "led"; String apssid = "WLED-AP"; -String appass = "wled1234"; uint8_t apchannel = 1; uint8_t aphide = 0; boolean useap = true; @@ -51,7 +67,6 @@ boolean fadeTransition = true; boolean seqTransition = false; uint16_t transitionDelay = 1500; boolean ota_lock = true; -String otapass = "wledota"; boolean only_ap = false; boolean buttonEnabled = true; boolean notifyDirect = true, notifyButton = true, notifyNightlight = false, notifyMaster = true; @@ -62,15 +77,15 @@ boolean nightlightFade = true; uint16_t udpPort = 21324; uint8_t effectDefault = 0; uint8_t effectSpeedDefault = 75; -boolean ntpEnabled = true; +boolean ntpEnabled = false; const char* ntpServerName = "time.nist.gov"; -long ntpRetryMs = 12000; -long ntpResyncMs = 72000000; +long ntpRetryMs = 9600; +long ntpResyncMs = 72000000L; int overlayMin = 0, overlayMax = 9; int analogClock12pixel = 25; boolean analogClockSecondsTrail = false; boolean analogClock5MinuteMarks = true; -boolean nixieClockDisplaySeconds = true; +boolean nixieClockDisplaySeconds = false; boolean nixieClock12HourFormat = false; boolean overlayReverse = true; uint8_t overlaySpeed = 200; @@ -107,7 +122,7 @@ boolean ntpConnected = false; boolean ntpSyncNeeded = true; boolean ntpPacketSent = false; long ntpPacketSentTime, ntpSyncTime; -uint8_t overlayCurrent = 5; +uint8_t overlayCurrent = 0; long overlayRefreshMs = 200; long overlayRefreshedTime; int overlayArr[6]; @@ -126,11 +141,17 @@ WS2812FX strip = WS2812FX(led_amount, 2, NEO_GRB + NEO_KHZ800); File fsUploadFile; +#ifdef DEBUG +int debugIndex = 0; +int lastWifiState = 3; +long wifiStateChangedTime = 0; +#endif + void down() { bri_t = 0; setAllLeds(); - Serial.println("MODULE TERMINATED"); + DEBUG_PRINTLN("MODULE TERMINATED"); while (1) {delay(1000);} } @@ -138,7 +159,7 @@ void reset() { bri_t = 0; setAllLeds(); - Serial.println("MODULE RESET"); + DEBUG_PRINTLN("MODULE RESET"); ESP.reset(); } @@ -161,6 +182,27 @@ void loop() { handleNetworkTime(); handleOverlays(); strip.service(); + + //DEBUG + #ifdef DEBUG + debugIndex ++; + if (debugIndex > 99999) + { + debugIndex = 0; + DEBUG_PRINTLN("---MODULE DEBUG INFO---"); + DEBUG_PRINT("Runtime: "); DEBUG_PRINTLN(millis()); + DEBUG_PRINT("Unix time: "); DEBUG_PRINTLN(now()); + DEBUG_PRINT("Wifi state: "); DEBUG_PRINTLN(WiFi.status()); + if (WiFi.status() != lastWifiState) + { + wifiStateChangedTime = millis(); + } + lastWifiState = WiFi.status(); + DEBUG_PRINT("Wifi state: "); DEBUG_PRINTLN(wifiStateChangedTime); + DEBUG_PRINT("NTP sync needed: "); DEBUG_PRINTLN(ntpSyncNeeded); + DEBUG_PRINT("Client IP: "); DEBUG_PRINTLN(WiFi.localIP()); + } + #endif } diff --git a/wled00/wled02_xml.ino b/wled00/wled02_xml.ino index 12ce0436..c7af90c1 100644 --- a/wled00/wled02_xml.ino +++ b/wled00/wled02_xml.ino @@ -48,7 +48,7 @@ void XML_response() void XML_response_settings() { - Serial.println("XML settings response"); + DEBUG_PRINTLN("XML settings response"); String resp; resp = resp + ""; resp = resp + ""; @@ -148,11 +148,11 @@ void XML_response_settings() resp = resp + ""; resp = resp + bool2int(ntpEnabled); resp = resp + ""; - Serial.println("pretime"); + DEBUG_PRINTLN("pretime"); resp = resp + ""; resp = resp + getTimeString(); resp = resp + ""; - Serial.println("posttime"); + DEBUG_PRINTLN("posttime"); resp = resp + ""; resp = resp + bool2int(ota_lock); resp = resp +""; @@ -188,6 +188,6 @@ void XML_response_settings() resp = resp + ""; resp = resp + "WLED 0.3pd OK"; resp = resp + ""; - Serial.println(resp); + DEBUG_PRINTLN(resp); server.send(200, "text/xml", resp); } diff --git a/wled00/wled03_set.ino b/wled00/wled03_set.ino index 4ba134be..8d99086e 100644 --- a/wled00/wled03_set.ino +++ b/wled00/wled03_set.ino @@ -9,7 +9,7 @@ void handleSettingsSet() { if (!server.arg("CPASS").indexOf('*') == 0) { - Serial.println("Setting pass"); + DEBUG_PRINTLN("Setting pass"); clientpass = server.arg("CPASS"); } } diff --git a/wled00/wled04_file.ino b/wled00/wled04_file.ino index 9dee4f7c..2b4b704c 100644 --- a/wled00/wled04_file.ino +++ b/wled00/wled04_file.ino @@ -32,7 +32,7 @@ String getContentType(String filename){ } bool handleFileRead(String path){ - Serial.println("handleFileRead: " + path); + DEBUG_PRINTLN("handleFileRead: " + path); if(path.endsWith("/")) path += "index.htm"; String contentType = getContentType(path); String pathWithGz = path + ".gz"; @@ -53,24 +53,24 @@ void handleFileUpload(){ if(upload.status == UPLOAD_FILE_START){ String filename = upload.filename; if(!filename.startsWith("/")) filename = "/"+filename; - Serial.print("handleFileUpload Name: "); Serial.println(filename); + DEBUG_PRINT("handleFileUpload Name: "); DEBUG_PRINTLN(filename); fsUploadFile = SPIFFS.open(filename, "w"); filename = String(); } else if(upload.status == UPLOAD_FILE_WRITE){ - //Serial.print("handleFileUpload Data: "); Serial.println(upload.currentSize); + //DEBUG_PRINT("handleFileUpload Data: "); DEBUG_PRINTLN(upload.currentSize); if(fsUploadFile) fsUploadFile.write(upload.buf, upload.currentSize); } else if(upload.status == UPLOAD_FILE_END){ if(fsUploadFile) fsUploadFile.close(); - Serial.print("handleFileUpload Size: "); Serial.println(upload.totalSize); + DEBUG_PRINT("handleFileUpload Size: "); DEBUG_PRINTLN(upload.totalSize); } } void handleFileDelete(){ if(server.args() == 0) return server.send(500, "text/plain", "BAD ARGS"); String path = server.arg(0); - Serial.println("handleFileDelete: " + path); + DEBUG_PRINTLN("handleFileDelete: " + path); if(path == "/") return server.send(500, "text/plain", "BAD PATH"); if(!SPIFFS.exists(path)) @@ -84,7 +84,7 @@ void handleFileList() { if(!server.hasArg("dir")) {server.send(500, "text/plain", "BAD ARGS"); return;} String path = server.arg("dir"); - Serial.println("handleFileList: " + path); + DEBUG_PRINTLN("handleFileList: " + path); Dir dir = SPIFFS.openDir(path); path = String(); @@ -109,7 +109,7 @@ void handleFileCreate(){ if(server.args() == 0) return server.send(500, "text/plain", "BAD ARGS"); String path = server.arg(0); - Serial.println("handleFileCreate: " + path); + DEBUG_PRINTLN("handleFileCreate: " + path); if(path == "/") return server.send(500, "text/plain", "BAD PATH"); if(SPIFFS.exists(path)) diff --git a/wled00/wled05_init.ino b/wled00/wled05_init.ino index ef79516c..313eb6cb 100644 --- a/wled00/wled05_init.ino +++ b/wled00/wled05_init.ino @@ -12,15 +12,17 @@ void wledInit() while (dir.next()) { String fileName = dir.fileName(); size_t fileSize = dir.fileSize(); + #ifdef DEBUG Serial.printf("FS File: %s, size: %s\n", fileName.c_str(), formatBytes(fileSize).c_str()); + #endif } - Serial.printf("\n"); + DEBUG_PRINTF("\n"); } - Serial.println("Init EEPROM"); + DEBUG_PRINTLN("Init EEPROM"); EEPROM.begin(1024); loadSettingsFromEEPROM(); - Serial.print("CC: SSID: "); - Serial.print(clientssid); + DEBUG_PRINT("CC: SSID: "); + DEBUG_PRINT(clientssid); WiFi.disconnect(); //close old connections @@ -34,27 +36,27 @@ void wledInit() if (apssid.length()>0) { - Serial.print("USING AP"); - Serial.println(apssid.length()); + DEBUG_PRINT("USING AP"); + DEBUG_PRINTLN(apssid.length()); initAP(); } else { - Serial.println("NO AP"); + DEBUG_PRINTLN("NO AP"); WiFi.softAPdisconnect(true); } initCon(); - Serial.println(""); - Serial.print("Connected! IP address: "); - Serial.println(WiFi.localIP()); + DEBUG_PRINTLN(""); + DEBUG_PRINT("Connected! IP address: "); + DEBUG_PRINTLN(WiFi.localIP()); // Set up mDNS responder: if (cmdns != NULL && !only_ap && !MDNS.begin(cmdns.c_str())) { - Serial.println("Error setting up MDNS responder!"); + DEBUG_PRINTLN("Error setting up MDNS responder!"); down(); } - Serial.println("mDNS responder started"); + DEBUG_PRINTLN("mDNS responder started"); if (udpPort > 0 && udpPort != 123) { @@ -128,7 +130,7 @@ void wledInit() }); server.begin(); - Serial.println("HTTP server started"); + DEBUG_PRINTLN("HTTP server started"); // Add service to MDNS MDNS.addService("http", "tcp", 80); // Initialize NeoPixel Strip @@ -153,12 +155,12 @@ void initCon() WiFi.begin(clientssid.c_str(), clientpass.c_str()); while(WiFi.status() != WL_CONNECTED) { delay(500); - Serial.println("C_NC"); + DEBUG_PRINTLN("C_NC"); fail_count++; if (fail_count > 32) { WiFi.disconnect(); - Serial.println("Can't connect to network. Opening AP..."); + DEBUG_PRINTLN("Can't connect to network. Opening AP..."); String save = apssid; only_ap = true; if (apssid.length() <1) apssid = "WLED-AP"; diff --git a/wled00/wled10_ntp.ino b/wled00/wled10_ntp.ino index a78ef5d4..4c70f563 100644 --- a/wled00/wled10_ntp.ino +++ b/wled00/wled10_ntp.ino @@ -15,8 +15,8 @@ void handleNetworkTime() ntpSyncNeeded = false; ntpPacketSent = false; ntpSyncTime = millis(); - Serial.print("Time: "); - Serial.println(now()); + DEBUG_PRINT("Time: "); + DEBUG_PRINTLN(now()); } else { if (millis() - ntpPacketSentTime > ntpRetryMs) @@ -29,7 +29,7 @@ void handleNetworkTime() WiFi.hostByName(ntpServerName, ntpIp); if (ntpIp[0] == 0) { - Serial.println("DNS f!"); + DEBUG_PRINTLN("DNS f!"); ntpIp = ntpBackupIp; } sendNTPpacket(); @@ -45,9 +45,25 @@ void handleNetworkTime() bool getNtpTime() { - int size = ntpUdp.parsePacket(); - if (size >= 48) { + if (ntpUdp.parsePacket()) { ntpUdp.read(ntpBuffer, 48); // read packet into the buffer + + #ifdef DEBUG + int i= 0; + while (i < 48) + { + Serial.print(ntpBuffer[i], HEX); + Serial.print("."); + i++; + if ((i % 4) ==0) Serial.println(); + } + #endif + if (ntpBuffer[40] == 0 && ntpBuffer[41] == 0 && ntpBuffer[42] == 0 && ntpBuffer[43] == 0) + { + DEBUG_PRINTLN("Bad NTP response!"); + return false; + } + unsigned long secsSince1900; // convert four bytes starting at location 40 to a long integer secsSince1900 = (unsigned long)ntpBuffer[40] << 24; @@ -63,7 +79,8 @@ bool getNtpTime() void sendNTPpacket() { while (ntpUdp.parsePacket()>0); - Serial.println("Sending NTP packet"); + ntpUdp.flush(); //discard old packets + DEBUG_PRINTLN("Sending NTP packet"); memset(ntpBuffer, 0, 48); ntpBuffer[0] = 0b11100011; // LI, Version, Mode ntpBuffer[1] = 0; // Stratum, or type of clock diff --git a/wled00/wled11_ol.ino b/wled00/wled11_ol.ino index 0a4973ff..c6350157 100644 --- a/wled00/wled11_ol.ino +++ b/wled00/wled11_ol.ino @@ -32,7 +32,7 @@ void nixieNumber(int number, int dur) { if (nixieClockI < 0) { - Serial.print(number); + DEBUG_PRINT(number); int digitCnt = -1; int digits[4]; digits[3] = number/1000; @@ -51,15 +51,15 @@ void nixieNumber(int number, int dur) } else { //single digit digitCnt = 1; } - Serial.print(" "); + DEBUG_PRINT(" "); for (int i = 0; i < digitCnt; i++) { - Serial.print(digits[i]); + DEBUG_PRINT(digits[i]); overlayArr[digitCnt-1-i] = digits[i]; overlayDur[digitCnt-1-i] = ((dur/4)*3)/digitCnt; overlayPauseDur[digitCnt-1-i] = 0; } - Serial.println(" "); + DEBUG_PRINTLN(" "); for (int i = 1; i < digitCnt; i++) { if (overlayArr[i] == overlayArr[i-1]) @@ -86,14 +86,14 @@ void nixieNumber(int number, int dur) } for (int i = 0; i <6; i++) { - Serial.print(overlayArr[i]); - Serial.print(" "); - Serial.print(overlayDur[i]); - Serial.print(" "); - Serial.print(overlayPauseDur[i]); - Serial.print(" "); + DEBUG_PRINT(overlayArr[i]); + DEBUG_PRINT(" "); + DEBUG_PRINT(overlayDur[i]); + DEBUG_PRINT(" "); + DEBUG_PRINT(overlayPauseDur[i]); + DEBUG_PRINT(" "); } - Serial.println(" "); + DEBUG_PRINTLN(" "); nixieClockI = 0; } else { nixieDisplay(overlayArr, overlayDur, overlayPauseDur, 6); @@ -237,7 +237,7 @@ void handleOverlays() { nixieDisplay(overlayArr, overlayDur, overlayPauseDur, 6); } - } + } break; case 5: {//countdown if (now() >= countdownTime) {