diff --git a/README.md b/README.md index ed5b586..922da86 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,16 @@ # Marquee Scroller (Clock, Weather, News, and More) +## NOTICE +The latest version of Marquee Scroller 3.0 works with **ESP8266 Core 3.0.2** -- if you are upgrading from Marquee Scroller 2.X version this may require you to enter in all your API Keys and settings. Always meake sure you have coppied all your API keys somewhere before updating. The ESP8266 Core 3.0.2 uses the newer FS (file system) that may require a fresh start on the configuration. +Make sure you update to the latest version of WifiManager library (link below). +* Removed Bitcoin features in 3.0 + ## Features include: * Accurate Clock refresh off Internet Time Servers * Local Weather and conditions (refreshed every 10 - 30 minutes) * News Headlines from all the major sources * Configured through Web Interface * Display 3D print progress from your OctoPrint Server -* Option to display Bitcoin current value * Option to display Pi-hole status and graph (each pixel accross is 10 minutes) * Basic Authorization around Configuration web interface * Support for OTA (loading firmware over WiFi) @@ -19,7 +23,7 @@ * Build Video by Chris Riley: https://youtu.be/KqBiqJT9_lE ## Required Parts: -* Wemos D1 Mini: https://amzn.to/2qLyKJd +* Wemos D1 Mini: https://amzn.to/3tMl81U * Dot Matrix Module: https://amzn.to/2HtnQlD Note: Using the links provided here help to support these types of projects. Thank you for the support. @@ -38,27 +42,23 @@ Original Single Panel version: https://www.thingiverse.com/thing:2867294 Double Wide LED version: https://www.thingiverse.com/thing:2989552 ## Upgrading from version 2.5 or Higher -Version 2.5 introduced the ability to upgrade pre-compiled firmware from a binary file. In version 2.6 and on you should find binary files that can be uploaded to your marque scrolling clock via the web interface. From the main menu in the web interface select "Firmware Update" and follow the prompts. -* **marquee.ino.d1_mini_2.18.bin** - compiled for Wemos D1 Mini and standard 4x1 LED (default) -* **marquee.ino.d1_mini_wide_2.18.bin** - compiled for Wemos D1 Mini and double wide 8x1 LED display +In version 2.6 and higher, the binary files that can be uploaded to your marque scrolling clock via the web interface. From the main menu in the web interface select "Firmware Update" and follow the prompts. +* **marquee.ino.d1_mini_3.0.bin** - compiled for Wemos D1 Mini and standard 4x1 LED (default) +* **marquee.ino.d1_mini_wide_3.0.bin** - compiled for Wemos D1 Mini and double wide 8x1 LED display ## Compiling and Loading to Wemos D1 It is recommended to use Arduino IDE. You will need to configure Arduino IDE to work with the Wemos board and USB port and installed the required USB drivers etc. * USB CH340G drivers: https://sparks.gogo.co.nz/ch340.html * Enter http://arduino.esp8266.com/stable/package_esp8266com_index.json into Additional Board Manager URLs field. You can add multiple URLs, separating them with commas. This will add support for the Wemos D1 Mini to Arduino IDE. -* Open Boards Manager from Tools > Board menu and install esp8266 Core platform version **2.5.2** -* Select Board: "LOLIN(WEMOS) D1 R2 & mini" -* Set Flash Size to 1M SPIFFS -- **this project requires SPIFFS for saving and reading configuration settings.** +* Open Boards Manager from Tools > Board menu and install esp8266 Core platform version Latest **3.0.2** +* Select Board: "ESP8266 Boards (3.0.2)" --> "LOLIN(WEMOS) D1 R2 & mini" +* Set Flash Size: 4MB (FS:1MB OTA:~1019KB) -- **this project requires FS for saving and reading configuration settings.** * Select the **Port** from the tools menu. ## Loading Supporting Library Files in Arduino Use the Arduino guide for details on how to installing and manage libraries https://www.arduino.cc/en/Guide/Libraries **Packages** -- the following packages and libraries are used (download and install): - - - --> https://github.com/tzapu/WiFiManager -"FS.h" - + --> https://github.com/tzapu/WiFiManager (latest) --> https://github.com/PaulStoffregen/Time --> https://github.com/adafruit/Adafruit-GFX-Library --> https://github.com/markruys/arduino-Max72xxPanel @@ -67,12 +67,12 @@ Use the Arduino guide for details on how to installing and manage libraries http Note ArduinoJson (version 5.13.1) is now included as a library file in version 2.7 and later. ## Initial Configuration -Starting with version 2.0 editing the **Settings.h** file is optional. All API Keys are now managed in the Web Interface except for the GeoNames Key. It is not required to edit the Settings.h file before loading and running the code. +Editing the **Settings.h** file is totally optional and not required. All API Keys are now managed in the Web Interface. It is not required to edit the Settings.h file before loading and running the code. * Open Weather Map free API key: http://openweathermap.org/ -- this is used to get weather data and the latitude and longitude for the current time zone. Weather API key is required for correct time. * TimeZoneDB free registration for API key: https://timezonedb.com/register -- this is used for setting the time and getting the correct time zone as well as managing time changes due to Day Light Savings time by regions. This key is set and managed only through the web interface and added in version 2.10 of Marquee Scroller. TimeZoneDB key is required for correct time display. * News API key (free): https://newsapi.org/ -- Optional if you want to get current news headlines. * Your OctoPrint API Key -- optional if you use the OctoPrint status. -* Version 2.0 supports Chained 4x1 LED displays -- configure in the Settings.h file. +* Version 2.0 supports Chained 4x1 LED displays -- configure up to 16x1 in the Settings.h file. NOTE: The settings in the Settings.h are the default settings for the first loading. After loading you will manage changes to the settings via the Web Interface. If you want to change settings again in the settings.h, you will need to erase the file system on the Wemos or use the “Reset Settings” option in the Web Interface. diff --git a/marquee.ino.d1_mini_2.19.bin b/marquee.ino.d1_mini_2.19.bin deleted file mode 100644 index c16e2b9..0000000 Binary files a/marquee.ino.d1_mini_2.19.bin and /dev/null differ diff --git a/marquee.ino.d1_mini_3.0.bin b/marquee.ino.d1_mini_3.0.bin new file mode 100644 index 0000000..8acc9d8 Binary files /dev/null and b/marquee.ino.d1_mini_3.0.bin differ diff --git a/marquee.ino.d1_mini_wide_2.19.bin b/marquee.ino.d1_mini_wide_2.19.bin deleted file mode 100644 index 166c897..0000000 Binary files a/marquee.ino.d1_mini_wide_2.19.bin and /dev/null differ diff --git a/marquee.ino.d1_mini_wide_3.0.bin b/marquee.ino.d1_mini_wide_3.0.bin new file mode 100644 index 0000000..5cc2d2f Binary files /dev/null and b/marquee.ino.d1_mini_wide_3.0.bin differ diff --git a/marquee/BitcoinApiClient.cpp b/marquee/BitcoinApiClient.cpp deleted file mode 100644 index 102f083..0000000 --- a/marquee/BitcoinApiClient.cpp +++ /dev/null @@ -1,130 +0,0 @@ -/** The MIT License (MIT) - -Copyright (c) 2018 David Payne - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. -*/ - -#include "BitcoinApiClient.h" - -BitcoinApiClient::BitcoinApiClient() { - //Constructor -} - -void BitcoinApiClient::updateBitcoinData(String currencyCode) { - if (currencyCode == "" || currencyCode == "NONE") { - bpiData.code = ""; - bpiData.rate = ""; - bpiData.description = ""; - bpiData.rate_float = 0; - return; // nothing to do here - } - HTTPClient http; - - String apiGetData = "http://" + String(servername) + "/v1/bpi/currentprice/" + currencyCode + ".json"; - - Serial.println("Getting Bitcoin Data"); - Serial.println(apiGetData); - http.begin(apiGetData); - int httpCode = http.GET(); - - String result = ""; - - if (httpCode > 0) { // checks for connection - Serial.printf("[HTTP] GET... code: %d\n", httpCode); - if(httpCode == HTTP_CODE_OK) { - // get length of document (is -1 when Server sends no Content-Length header) - int len = http.getSize(); - // create buffer for read - char buff[128] = { 0 }; - // get tcp stream - WiFiClient * stream = http.getStreamPtr(); - // read all data from server - Serial.println("Start reading..."); - while(http.connected() && (len > 0 || len == -1)) { - // get available data size - size_t size = stream->available(); - if(size) { - // read up to 128 byte - int c = stream->readBytes(buff, ((size > sizeof(buff)) ? sizeof(buff) : size)); - for(int i=0;i 0) - len -= c; - } - delay(1); - } - } - http.end(); - } else { - Serial.println("connection for BitCoin data failed: " + String(apiGetData)); //error message if no client connect - Serial.println(); - return; - } - //Clean dirty results - result.remove(0, result.indexOf("{")); - result.remove(result.lastIndexOf("}") + 1); - Serial.println("Results:"); - Serial.println(result); - Serial.println("End"); - - char jsonArray [result.length()+1]; - result.toCharArray(jsonArray,sizeof(jsonArray)); - //jsonArray[result.length() + 1] = '\0'; - DynamicJsonBuffer json_buf; - JsonObject& root = json_buf.parseObject(jsonArray); - - if (!root.success()) { - Serial.println(F("Bitcoin Data Parsing failed!")); - return; - } - - bpiData.code = (const char*)root["bpi"][String(currencyCode)]["code"]; - bpiData.rate = (const char*)root["bpi"][String(currencyCode)]["rate"]; - bpiData.description = (const char*)root["bpi"][String(currencyCode)]["description"]; - bpiData.rate_float = String((const char*)root["bpi"][String(currencyCode)]["rate_float"]).toFloat(); - - Serial.println("code: " + bpiData.code); - Serial.println("rate: " + bpiData.rate); - Serial.println("description: " + bpiData.description); - Serial.println("rate_float: " + String(bpiData.rate_float)); - - Serial.println(); -} - -String BitcoinApiClient::getCode() { - return bpiData.code; -} - -String BitcoinApiClient::getRate() { - String rate = bpiData.rate; - rate.remove(rate.indexOf(".") + 3); - return rate; -} - -String BitcoinApiClient::getDescription() { - return bpiData.description; -} - -float BitcoinApiClient::getRateFloat() { - return bpiData.rate_float; -} - diff --git a/marquee/BitcoinApiClient.h b/marquee/BitcoinApiClient.h deleted file mode 100644 index 38f0ca1..0000000 --- a/marquee/BitcoinApiClient.h +++ /dev/null @@ -1,54 +0,0 @@ -/** The MIT License (MIT) - -Copyright (c) 2018 David Payne - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. -*/ - -#pragma once -#include -#include -#include "libs/ArduinoJson/ArduinoJson.h" - -class BitcoinApiClient { - -private: - - String myCurrency = ""; - - const char* servername = "api.coindesk.com"; // remote server we will connect to https://www.coindesk.com/api/ - - typedef struct { - String code; - String rate; - String description; - float rate_float; - } bpi; - - bpi bpiData; - -public: - BitcoinApiClient(); - void updateBitcoinData(String currencyCode); - - String getCode(); - String getRate(); - String getDescription(); - float getRateFloat(); -}; diff --git a/marquee/NewsApiClient.cpp b/marquee/NewsApiClient.cpp index bb0d106..d9beb57 100644 --- a/marquee/NewsApiClient.cpp +++ b/marquee/NewsApiClient.cpp @@ -40,13 +40,19 @@ void NewsApiClient::updateNewsClient(String ApiKey, String NewsSource) { void NewsApiClient::updateNews() { JsonStreamingParser parser; parser.setListener(this); + WiFiClient wifiClient; HTTPClient http; + if (myApiKey == "") { + Serial.println("Please provide an API key for the News."); + return; + } + String apiGetData = "http://" + String(servername) + "/v2/top-headlines?sources=" + mySource + "&apiKey=" + myApiKey; Serial.println("Getting News Data"); Serial.println(apiGetData); - http.begin(apiGetData); + http.begin(wifiClient, apiGetData); int httpCode = http.GET(); if (httpCode > 0) { // checks for connection diff --git a/marquee/NewsApiClient.h b/marquee/NewsApiClient.h index 420ad72..0af9b9b 100644 --- a/marquee/NewsApiClient.h +++ b/marquee/NewsApiClient.h @@ -24,6 +24,7 @@ SOFTWARE. #pragma once #include #include +#include #include #include // --> https://github.com/squix78/json-streaming-parser diff --git a/marquee/OpenWeatherMapClient.cpp b/marquee/OpenWeatherMapClient.cpp index ed3f79d..72b59df 100644 --- a/marquee/OpenWeatherMapClient.cpp +++ b/marquee/OpenWeatherMapClient.cpp @@ -36,6 +36,11 @@ void OpenWeatherMapClient::updateWeatherApiKey(String ApiKey) { void OpenWeatherMapClient::updateWeather() { WiFiClient weatherClient; + if (myApiKey == "") { + weathers[0].error = "Please provide an API key for weather."; + Serial.println(weathers[0].error); + return; + } String apiGetData = "GET /data/2.5/group?id=" + myCityIDs + "&units=" + units + "&cnt=1&APPID=" + myApiKey + " HTTP/1.1"; Serial.println("Getting Weather Data"); diff --git a/marquee/PiHoleClient.cpp b/marquee/PiHoleClient.cpp index 0a64af7..dad4a15 100644 --- a/marquee/PiHoleClient.cpp +++ b/marquee/PiHoleClient.cpp @@ -29,13 +29,14 @@ PiHoleClient::PiHoleClient() { void PiHoleClient::getPiHoleData(String server, int port) { + WiFiClient wifiClient; errorMessage = ""; String response = ""; String apiGetData = "http://" + server + ":" + String(port) + "/admin/api.php?summary"; Serial.println("Sending: " + apiGetData); HTTPClient http; //Object of class HTTPClient - http.begin(apiGetData);// get the result + http.begin(wifiClient, apiGetData);// get the result int httpCode = http.GET(); //Check the returning code if (httpCode > 0) { @@ -89,6 +90,7 @@ void PiHoleClient::getPiHoleData(String server, int port) { } void PiHoleClient::getTopClientsBlocked(String server, int port, String apiKey) { + WiFiClient wifiClient; errorMessage = ""; resetClientsBlocked(); @@ -102,7 +104,7 @@ void PiHoleClient::getTopClientsBlocked(String server, int port, String apiKey) String apiGetData = "http://" + server + ":" + String(port) + "/admin/api.php?topClientsBlocked=3&auth=" + apiKey; Serial.println("Sending: " + apiGetData); HTTPClient http; //Object of class HTTPClient - http.begin(apiGetData);// get the result + http.begin(wifiClient, apiGetData);// get the result int httpCode = http.GET(); //Check the returning code if (httpCode > 0) { @@ -145,14 +147,14 @@ void PiHoleClient::getTopClientsBlocked(String server, int port, String apiKey) } void PiHoleClient::getGraphData(String server, int port) { - + WiFiClient wifiClient; HTTPClient http; String apiGetData = "http://" + server + ":" + String(port) + "/admin/api.php?overTimeData10mins"; resetBlockedGraphData(); Serial.println("Getting Pi-Hole Graph Data"); Serial.println(apiGetData); - http.begin(apiGetData); + http.begin(wifiClient, apiGetData); int httpCode = http.GET(); String result = ""; diff --git a/marquee/PiHoleClient.h b/marquee/PiHoleClient.h index be5bb0a..cecc42b 100644 --- a/marquee/PiHoleClient.h +++ b/marquee/PiHoleClient.h @@ -24,6 +24,7 @@ SOFTWARE. #pragma once #include #include +#include #include "libs/ArduinoJson/ArduinoJson.h" class PiHoleClient { diff --git a/marquee/Settings.h b/marquee/Settings.h index fc88628..87cceba 100644 --- a/marquee/Settings.h +++ b/marquee/Settings.h @@ -50,7 +50,6 @@ SOFTWARE. #include "TimeDB.h" #include "NewsApiClient.h" #include "OctoPrintClient.h" -#include "BitcoinApiClient.h" #include "PiHoleClient.h" //****************************** @@ -107,9 +106,6 @@ int OctoPrintPort = 80; // the port you are running your OctoPrint server String OctoAuthUser = ""; // only used if you have haproxy or basic athentintication turned on (not default) String OctoAuthPass = ""; // only used with haproxy or basic auth (only needed if you must authenticate) -// Bitcoin Client - NONE or empty is off -String BitcoinCurrencyCode = "NONE"; // Change to USD, GBD, EUR, or NONE -- this can be managed in the Web Interface - // Pi-hole Client -- monitor basic stats from your Pi-hole server (see http://pi-hole.net) boolean USE_PIHOLE = false; // Set true to display your Pi-hole details String PiHoleServer = ""; // IP or Address only (DO NOT include http://) diff --git a/marquee/marquee.ino b/marquee/marquee.ino index 5759611..ec70e20 100644 --- a/marquee/marquee.ino +++ b/marquee/marquee.ino @@ -27,7 +27,7 @@ #include "Settings.h" -#define VERSION "2.19" +#define VERSION "3.0" #define HOSTNAME "CLOCK-" #define CONFIG "/conf.txt" @@ -90,9 +90,6 @@ int printerCount = 0; // Pi-hole Client PiHoleClient piholeClient; -// Bitcoin Client -BitcoinApiClient bitcoinClient; - ESP8266WebServer server(WEBSERVER_PORT); ESP8266HTTPUpdateServer serverUpdater; @@ -101,8 +98,7 @@ static const char WEB_ACTIONS1[] PROGMEM = " News" " OctoPrint"; -static const char WEB_ACTIONS2[] PROGMEM = " Bitcoin" - " Pi-hole" +static const char WEB_ACTIONS2[] PROGMEM = " Pi-hole" " Refresh Data" ""; @@ -144,21 +140,6 @@ static const char CHANGE_FORM3[] PROGMEM = "

" ""; -static const char BITCOIN_FORM[] PROGMEM = "

Bitcoin Configuration:

" - "

Select Bitcoin Currency

" - "
"; - -static const char CURRENCY_OPTIONS[] PROGMEM = "" - "" - "" - "" - "" - "" - "" - "" - "" - ""; - static const char WIDECLOCK_FORM[] PROGMEM = "

Wide Clock Configuration:

" "

Wide Clock Display Format

" "
"; @@ -166,7 +147,7 @@ static const char WIDECLOCK_FORM[] PROGMEM = "
Show Pi-hole Statistics

" "" - "" + "" "

" "
" ""; @@ -308,7 +289,6 @@ void setup() { server.on("/", displayWeatherData); server.on("/pull", handlePull); server.on("/locations", handleLocations); - server.on("/savebitcoin", handleSaveBitcoin); server.on("/savewideclock", handleSaveWideClock); server.on("/savenews", handleSaveNews); server.on("/saveoctoprint", handleSaveOctoprint); @@ -316,7 +296,6 @@ void setup() { server.on("/systemreset", handleSystemReset); server.on("/forgetwifi", handleForgetWifi); server.on("/configure", handleConfigure); - server.on("/configurebitcoin", handleBitcoinConfigure); server.on("/configurewideclock", handleWideClockConfigure); server.on("/configurenews", handleNewsConfigure); server.on("/configureoctoprint", handleOctoprintConfigure); @@ -423,9 +402,6 @@ void loop() { msg += " " + printerClient.getFileName() + " "; msg += "(" + printerClient.getProgressCompletion() + "%) "; } - if (BitcoinCurrencyCode != "NONE" && BitcoinCurrencyCode != "") { - msg += " Bitcoin: " + bitcoinClient.getRate() + " " + bitcoinClient.getCode() + " "; - } if (USE_PIHOLE) { piholeClient.getPiHoleData(PiHoleServer, PiHolePort); piholeClient.getGraphData(PiHoleServer, PiHolePort); @@ -448,7 +424,7 @@ void loop() { currentTime += " " + currentTemp + getTempSymbol(); } if (Wide_Clock_Style == "2") { - currentTime += secondsIndicator(false) + TimeDB.zeroPad(second()); + currentTime = currentTime + secondsIndicator(false) + TimeDB.zeroPad(second()); matrix.fillScreen(LOW); // show black } if (Wide_Clock_Style == "3") { @@ -466,11 +442,19 @@ void loop() { } } +String zeroPad(int value) { + String rtnValue = String(value); + if (value < 10) { + rtnValue = "0" + rtnValue; + } + return rtnValue; +} + String hourMinutes(boolean isRefresh) { if (IS_24HOUR) { return hour() + secondsIndicator(isRefresh) + TimeDB.zeroPad(minute()); } else { - return hourFormat12() + secondsIndicator(isRefresh) + TimeDB.zeroPad(minute()); + return String(hourFormat12()) + secondsIndicator(isRefresh) + TimeDB.zeroPad(minute()); } } @@ -494,16 +478,6 @@ void handlePull() { displayWeatherData(); } -void handleSaveBitcoin() { - if (!athentication()) { - return server.requestAuthentication(); - } - BitcoinCurrencyCode = server.arg("bitcoincurrency"); - writeCityIds(); - bitcoinClient.updateBitcoinData(BitcoinCurrencyCode); // does nothing if BitCoinCurrencyCode is "NONE" or empty - redirectHome(); -} - void handleSaveWideClock() { if (!athentication()) { return server.requestAuthentication(); @@ -623,34 +597,6 @@ void handleForgetWifi() { ESP.restart(); } -void handleBitcoinConfigure() { - if (!athentication()) { - return server.requestAuthentication(); - } - digitalWrite(externalLight, LOW); - String html = ""; - - server.sendHeader("Cache-Control", "no-cache, no-store"); - server.sendHeader("Pragma", "no-cache"); - server.sendHeader("Expires", "-1"); - server.setContentLength(CONTENT_LENGTH_UNKNOWN); - server.send(200, "text/html", ""); - - sendHeader(); - - String form = FPSTR(BITCOIN_FORM); - String bitcoinOptions = FPSTR(CURRENCY_OPTIONS); - bitcoinOptions.replace(BitcoinCurrencyCode + "'", BitcoinCurrencyCode + "' selected"); - form.replace("%BITCOINOPTIONS%", bitcoinOptions); - server.sendContent(form); //Send another Chunk of form - - sendFooter(); - - server.sendContent(""); - server.client().stop(); - digitalWrite(externalLight, HIGH); -} - void handleWideClockConfigure() { if (!athentication()) { return server.requestAuthentication(); @@ -973,10 +919,6 @@ void getWeatherData() //client function to send/receive GET request data. newsClient.updateNews(); } - if (displayOn) { - bitcoinClient.updateBitcoinData(BitcoinCurrencyCode); // does nothing if BitCoinCurrencyCode is "NONE" or empty - } - Serial.println("Version: " + String(VERSION)); Serial.println(); digitalWrite(externalLight, HIGH); @@ -1123,9 +1065,22 @@ void displayWeatherData() { if (OCTOPRINT_ENABLED) { - html = "
OctoPrint Status: "; + html = "
OctoPrint Status: "; if (printerClient.isPrinting()) { - html += printerClient.getState() + " " + printerClient.getFileName() + " (" + printerClient.getProgressCompletion() + "%)"; + int val = printerClient.getProgressPrintTimeLeft().toInt(); + int hours = numberOfHours(val); + int minutes = numberOfMinutes(val); + int seconds = numberOfSeconds(val); + html += "Online and Printing
Est. Print Time Left: " + zeroPad(hours) + ":" + zeroPad(minutes) + ":" + zeroPad(seconds) + "
"; + + val = printerClient.getProgressPrintTime().toInt(); + hours = numberOfHours(val); + minutes = numberOfMinutes(val); + seconds = numberOfSeconds(val); + html += "Printing Time: " + zeroPad(hours) + ":" + zeroPad(minutes) + ":" + zeroPad(seconds) + "
"; + html += printerClient.getState() + " " + printerClient.getFileName() + "
"; + html += ""; + html += "
" + printerClient.getProgressCompletion() + "%
"; } else if (printerClient.isOperational()) { html += printerClient.getState(); } else if (printerClient.getError() != "") { @@ -1138,12 +1093,6 @@ void displayWeatherData() { html = ""; } - if (BitcoinCurrencyCode != "NONE" && BitcoinCurrencyCode != "") { - html = "
Bitcoin value: " + bitcoinClient.getRate() + " " + bitcoinClient.getCode() + "


"; - server.sendContent(String(html)); - html = ""; - } - if (USE_PIHOLE) { if (piholeClient.getError() == "") { html = "
Pi-hole
" @@ -1361,7 +1310,6 @@ String writeCityIds() { f.println("www_username=" + String(www_username)); f.println("www_password=" + String(www_password)); f.println("IS_BASIC_AUTH=" + String(IS_BASIC_AUTH)); - f.println("BitcoinCurrencyCode=" + BitcoinCurrencyCode); f.println("SHOW_CITY=" + String(SHOW_CITY)); f.println("SHOW_CONDITION=" + String(SHOW_CONDITION)); f.println("SHOW_HUMIDITY=" + String(SHOW_HUMIDITY)); @@ -1522,11 +1470,6 @@ void readCityIds() { IS_BASIC_AUTH = line.substring(line.lastIndexOf("IS_BASIC_AUTH=") + 14).toInt(); Serial.println("IS_BASIC_AUTH=" + String(IS_BASIC_AUTH)); } - if (line.indexOf("BitcoinCurrencyCode=") >= 0) { - BitcoinCurrencyCode = line.substring(line.lastIndexOf("BitcoinCurrencyCode=") + 20); - BitcoinCurrencyCode.trim(); - Serial.println("BitcoinCurrencyCode=" + BitcoinCurrencyCode); - } if (line.indexOf("SHOW_CITY=") >= 0) { SHOW_CITY = line.substring(line.lastIndexOf("SHOW_CITY=") + 10).toInt(); Serial.println("SHOW_CITY=" + String(SHOW_CITY)); @@ -1547,12 +1490,10 @@ void readCityIds() { SHOW_PRESSURE = line.substring(line.lastIndexOf("SHOW_PRESSURE=") + 14).toInt(); Serial.println("SHOW_PRESSURE=" + String(SHOW_PRESSURE)); } - if (line.indexOf("SHOW_HIGHLOW=") >= 0) { SHOW_HIGHLOW = line.substring(line.lastIndexOf("SHOW_HIGHLOW=") + 13).toInt(); Serial.println("SHOW_HIGHLOW=" + String(SHOW_HIGHLOW)); } - if (line.indexOf("SHOW_DATE=") >= 0) { SHOW_DATE = line.substring(line.lastIndexOf("SHOW_DATE=") + 10).toInt(); Serial.println("SHOW_DATE=" + String(SHOW_DATE)); @@ -1564,7 +1505,7 @@ void readCityIds() { if (line.indexOf("PiHoleServer=") >= 0) { PiHoleServer = line.substring(line.lastIndexOf("PiHoleServer=") + 13); PiHoleServer.trim(); - Serial.println("PiHoleServer=" + PiHoleServer); + Serial.println("PiHoleServer=" + String(PiHoleServer)); } if (line.indexOf("PiHolePort=") >= 0) { PiHolePort = line.substring(line.lastIndexOf("PiHolePort=") + 11).toInt();