diff --git a/README.md b/README.md index 3e7f920..a69a89c 100644 --- a/README.md +++ b/README.md @@ -41,6 +41,7 @@ SOFTWARE. * Supports OTA (loading firmware over WiFi connection on same LAN) * Basic Authentication to protect your settings * Version 2.2 added the ability to update firmware through web interface from a compiled binary +* Can query the Octoprint [PSU Control plugin](https://plugins.octoprint.org/plugins/psucontrol/) to enter clock or blank mode when PSU is off * Video: https://youtu.be/niRv9SCgAPk * Detailed build video by Chris Riley: https://youtu.be/Rm-l1FSuJpI @@ -114,9 +115,10 @@ Please do not feel obligated, but donations and tips are warmly welcomed. I hav [![paypal](https://www.paypalobjects.com/en_US/i/btn/btn_donateCC_LG.gif)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=6VPMTLASLSKWE) ## Contributors -David Payne +David Payne -- Principal developer and architect Daniel Eichhorn -- Author of the TimeClient class and OLEDDisplayUi Florian Schütte -- added flip display to web interface +Owen Carter -- Added psu control setting (v2.4) Contributing to this software is warmly welcomed. You can do this basically by forking from master, committing modifications and then making a pulling requests to be reviewed (follow the links above diff --git a/printermonitor.ino.d1_mini_SH1106-2.4.bin b/printermonitor.ino.d1_mini_SH1106-2.4.bin new file mode 100644 index 0000000..a5b3a39 Binary files /dev/null and b/printermonitor.ino.d1_mini_SH1106-2.4.bin differ diff --git a/printermonitor.ino.d1_mini_SH1106.bin b/printermonitor.ino.d1_mini_SH1106.bin deleted file mode 100644 index f2233b9..0000000 Binary files a/printermonitor.ino.d1_mini_SH1106.bin and /dev/null differ diff --git a/printermonitor.ino.d1_mini_SSD1306-2.4.bin b/printermonitor.ino.d1_mini_SSD1306-2.4.bin new file mode 100644 index 0000000..4025bbb Binary files /dev/null and b/printermonitor.ino.d1_mini_SSD1306-2.4.bin differ diff --git a/printermonitor.ino.d1_mini_SSD1306.bin b/printermonitor.ino.d1_mini_SSD1306.bin deleted file mode 100644 index 5067f0f..0000000 Binary files a/printermonitor.ino.d1_mini_SSD1306.bin and /dev/null differ diff --git a/printermonitor/OctoPrintClient.cpp b/printermonitor/OctoPrintClient.cpp index b2879ca..7d19d2c 100644 --- a/printermonitor/OctoPrintClient.cpp +++ b/printermonitor/OctoPrintClient.cpp @@ -1,295 +1,396 @@ -/** 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 "OctoPrintClient.h" - -OctoPrintClient::OctoPrintClient(String ApiKey, String server, int port, String user, String pass) { - updateOctoPrintClient(ApiKey, server, port, user, pass); -} - -void OctoPrintClient::updateOctoPrintClient(String ApiKey, String server, int port, String user, String pass) { - server.toCharArray(myServer, 100); - myApiKey = ApiKey; - myPort = port; - encodedAuth = ""; - if (user != "") { - String userpass = user + ":" + pass; - base64 b64; - encodedAuth = b64.encode(userpass, true); - } -} - -boolean OctoPrintClient::validate() { - boolean rtnValue = false; - printerData.error = ""; - if (String(myServer) == "") { - printerData.error += "Server address is required; "; - } - if (myApiKey == "") { - printerData.error += "ApiKey is required; "; - } - if (printerData.error == "") { - rtnValue = true; - } - return rtnValue; -} - -WiFiClient OctoPrintClient::getSubmitRequest(String apiGetData) { - WiFiClient printClient; - printClient.setTimeout(5000); - - Serial.println("Getting Octoprint Data"); - Serial.println(apiGetData); - result = ""; - if (printClient.connect(myServer, myPort)) { //starts client connection, checks for connection - printClient.println(apiGetData); - printClient.println("Host: " + String(myServer) + ":" + String(myPort)); - printClient.println("X-Api-Key: " + myApiKey); - if (encodedAuth != "") { - printClient.print("Authorization: "); - printClient.println("Basic " + encodedAuth); - } - printClient.println("User-Agent: ArduinoWiFi/1.1"); - printClient.println("Connection: close"); - if (printClient.println() == 0) { - Serial.println("Connection to " + String(myServer) + ":" + String(myPort) + " failed."); - Serial.println(); - resetPrintData(); - printerData.error = "Connection to " + String(myServer) + ":" + String(myPort) + " failed."; - return printClient; - } - } - else { - Serial.println("Connection to OctoPrint failed: " + String(myServer) + ":" + String(myPort)); //error message if no client connect - Serial.println(); - resetPrintData(); - printerData.error = "Connection to OctoPrint failed: " + String(myServer) + ":" + String(myPort); - return printClient; - } - - // Check HTTP status - char status[32] = {0}; - printClient.readBytesUntil('\r', status, sizeof(status)); - if (strcmp(status, "HTTP/1.1 200 OK") != 0 && strcmp(status, "HTTP/1.1 409 CONFLICT") != 0) { - Serial.print(F("Unexpected response: ")); - Serial.println(status); - printerData.state = ""; - printerData.error = "Response: " + String(status); - return printClient; - } - - // Skip HTTP headers - char endOfHeaders[] = "\r\n\r\n"; - if (!printClient.find(endOfHeaders)) { - Serial.println(F("Invalid response")); - printerData.error = "Invalid response from " + String(myServer) + ":" + String(myPort); - printerData.state = ""; - } - - return printClient; -} - -void OctoPrintClient::getPrinterJobResults() { - if (!validate()) { - return; - } - String apiGetData = "GET /api/job HTTP/1.1"; - - WiFiClient printClient = getSubmitRequest(apiGetData); - - if (printerData.error != "") { - return; - } - - const size_t bufferSize = JSON_OBJECT_SIZE(1) + JSON_OBJECT_SIZE(2) + JSON_OBJECT_SIZE(3) + 2*JSON_OBJECT_SIZE(5) + JSON_OBJECT_SIZE(6) + 710; - DynamicJsonBuffer jsonBuffer(bufferSize); - - // Parse JSON object - JsonObject& root = jsonBuffer.parseObject(printClient); - if (!root.success()) { - Serial.println("OctoPrint Data Parsing failed: " + String(myServer) + ":" + String(myPort)); - printerData.error = "OctoPrint Data Parsing failed: " + String(myServer) + ":" + String(myPort); - printerData.state = ""; - return; - } - - printerData.averagePrintTime = (const char*)root["job"]["averagePrintTime"]; - printerData.estimatedPrintTime = (const char*)root["job"]["estimatedPrintTime"]; - printerData.fileName = (const char*)root["job"]["file"]["name"]; - printerData.fileSize = (const char*)root["job"]["file"]["size"]; - printerData.lastPrintTime = (const char*)root["job"]["lastPrintTime"]; - printerData.progressCompletion = (const char*)root["progress"]["completion"]; - printerData.progressFilepos = (const char*)root["progress"]["filepos"]; - printerData.progressPrintTime = (const char*)root["progress"]["printTime"]; - printerData.progressPrintTimeLeft = (const char*)root["progress"]["printTimeLeft"]; - printerData.filamentLength = (const char*)root["job"]["filament"]["tool0"]["length"]; - printerData.state = (const char*)root["state"]; - - if (isOperational()) { - Serial.println("Status: " + printerData.state); - } else { - Serial.println("Printer Not Opperational"); - } - - //**** get the Printer Temps and Stat - apiGetData = "GET /api/printer?exclude=sd,history HTTP/1.1"; - printClient = getSubmitRequest(apiGetData); - if (printerData.error != "") { - return; - } - const size_t bufferSize2 = 3*JSON_OBJECT_SIZE(2) + 2*JSON_OBJECT_SIZE(3) + JSON_OBJECT_SIZE(9) + 300; - DynamicJsonBuffer jsonBuffer2(bufferSize2); - - // Parse JSON object - JsonObject& root2 = jsonBuffer2.parseObject(printClient); - if (!root2.success()) { - printerData.isPrinting = false; - printerData.toolTemp = ""; - printerData.toolTargetTemp = ""; - printerData.bedTemp = ""; - printerData.bedTargetTemp = (const char*)root2["temperature"]["bed"]["target"]; - return; - } - - String printing = (const char*)root2["state"]["flags"]["printing"]; - if (printing == "true") { - printerData.isPrinting = true; - } - printerData.toolTemp = (const char*)root2["temperature"]["tool0"]["actual"]; - printerData.toolTargetTemp = (const char*)root2["temperature"]["tool0"]["target"]; - printerData.bedTemp = (const char*)root2["temperature"]["bed"]["actual"]; - printerData.bedTargetTemp = (const char*)root2["temperature"]["bed"]["target"]; - - if (isPrinting()) { - Serial.println("Status: " + printerData.state + " " + printerData.fileName + "(" + printerData.progressCompletion + "%)"); - } - - printClient.stop(); //stop client -} - -// Reset all PrinterData -void OctoPrintClient::resetPrintData() { - printerData.averagePrintTime = ""; - printerData.estimatedPrintTime = ""; - printerData.fileName = ""; - printerData.fileSize = ""; - printerData.lastPrintTime = ""; - printerData.progressCompletion = ""; - printerData.progressFilepos = ""; - printerData.progressPrintTime = ""; - printerData.progressPrintTimeLeft = ""; - printerData.state = ""; - printerData.toolTemp = ""; - printerData.toolTargetTemp = ""; - printerData.filamentLength = ""; - printerData.bedTemp = ""; - printerData.bedTargetTemp = ""; - printerData.isPrinting = false; - printerData.error = ""; -} - -String OctoPrintClient::getAveragePrintTime(){ - return printerData.averagePrintTime; -} - -String OctoPrintClient::getEstimatedPrintTime() { - return printerData.estimatedPrintTime; -} - -String OctoPrintClient::getFileName() { - return printerData.fileName; -} - -String OctoPrintClient::getFileSize() { - return printerData.fileSize; -} - -String OctoPrintClient::getLastPrintTime(){ - return printerData.lastPrintTime; -} - -String OctoPrintClient::getProgressCompletion() { - return String(printerData.progressCompletion.toInt()); -} - -String OctoPrintClient::getProgressFilepos() { - return printerData.progressFilepos; -} - -String OctoPrintClient::getProgressPrintTime() { - return printerData.progressPrintTime; -} - -String OctoPrintClient::getProgressPrintTimeLeft() { - String rtnValue = printerData.progressPrintTimeLeft; - if (getProgressCompletion() == "100") { - rtnValue = "0"; // Print is done so this should be 0 this is a fix for OctoPrint - } - return rtnValue; -} - -String OctoPrintClient::getState() { - return printerData.state; -} - -boolean OctoPrintClient::isPrinting() { - return printerData.isPrinting; -} - -boolean OctoPrintClient::isOperational() { - boolean operational = false; - if (printerData.state == "Operational" || isPrinting()) { - operational = true; - } - return operational; -} - -String OctoPrintClient::getTempBedActual() { - return printerData.bedTemp; -} - -String OctoPrintClient::getTempBedTarget() { - return printerData.bedTargetTemp; -} - -String OctoPrintClient::getTempToolActual() { - return printerData.toolTemp; -} - -String OctoPrintClient::getTempToolTarget() { - return printerData.toolTargetTemp; -} - -String OctoPrintClient::getFilamentLength() { - return printerData.filamentLength; -} - -String OctoPrintClient::getError() { - return printerData.error; -} - -String OctoPrintClient::getValueRounded(String value) { - float f = value.toFloat(); - int rounded = (int)(f+0.5f); - return String(rounded); +/** 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. +*/ + +// Additional Contributions: +/* 15 Jan 2019 : Owen Carter : Add psucontrol query via POST api call */ + +#include "OctoPrintClient.h" + +OctoPrintClient::OctoPrintClient(String ApiKey, String server, int port, String user, String pass, boolean psu) { + updateOctoPrintClient(ApiKey, server, port, user, pass, psu); +} + +void OctoPrintClient::updateOctoPrintClient(String ApiKey, String server, int port, String user, String pass, boolean psu) { + server.toCharArray(myServer, 100); + myApiKey = ApiKey; + myPort = port; + encodedAuth = ""; + if (user != "") { + String userpass = user + ":" + pass; + base64 b64; + encodedAuth = b64.encode(userpass, true); + } + pollPsu = psu; +} + +boolean OctoPrintClient::validate() { + boolean rtnValue = false; + printerData.error = ""; + if (String(myServer) == "") { + printerData.error += "Server address is required; "; + } + if (myApiKey == "") { + printerData.error += "ApiKey is required; "; + } + if (printerData.error == "") { + rtnValue = true; + } + return rtnValue; +} + +WiFiClient OctoPrintClient::getSubmitRequest(String apiGetData) { + WiFiClient printClient; + printClient.setTimeout(5000); + + Serial.println("Getting Octoprint Data via GET"); + Serial.println(apiGetData); + result = ""; + if (printClient.connect(myServer, myPort)) { //starts client connection, checks for connection + printClient.println(apiGetData); + printClient.println("Host: " + String(myServer) + ":" + String(myPort)); + printClient.println("X-Api-Key: " + myApiKey); + if (encodedAuth != "") { + printClient.print("Authorization: "); + printClient.println("Basic " + encodedAuth); + } + printClient.println("User-Agent: ArduinoWiFi/1.1"); + printClient.println("Connection: close"); + if (printClient.println() == 0) { + Serial.println("Connection to " + String(myServer) + ":" + String(myPort) + " failed."); + Serial.println(); + resetPrintData(); + printerData.error = "Connection to " + String(myServer) + ":" + String(myPort) + " failed."; + return printClient; + } + } + else { + Serial.println("Connection to OctoPrint failed: " + String(myServer) + ":" + String(myPort)); //error message if no client connect + Serial.println(); + resetPrintData(); + printerData.error = "Connection to OctoPrint failed: " + String(myServer) + ":" + String(myPort); + return printClient; + } + + // Check HTTP status + char status[32] = {0}; + printClient.readBytesUntil('\r', status, sizeof(status)); + if (strcmp(status, "HTTP/1.1 200 OK") != 0 && strcmp(status, "HTTP/1.1 409 CONFLICT") != 0) { + Serial.print(F("Unexpected response: ")); + Serial.println(status); + printerData.state = ""; + printerData.error = "Response: " + String(status); + return printClient; + } + + // Skip HTTP headers + char endOfHeaders[] = "\r\n\r\n"; + if (!printClient.find(endOfHeaders)) { + Serial.println(F("Invalid response")); + printerData.error = "Invalid response from " + String(myServer) + ":" + String(myPort); + printerData.state = ""; + } + + return printClient; +} + +WiFiClient OctoPrintClient::getPostRequest(String apiPostData, String apiPostBody) { + WiFiClient printClient; + printClient.setTimeout(5000); + + Serial.println("Getting Octoprint Data via POST"); + Serial.println(apiPostData + " | " + apiPostBody); + result = ""; + if (printClient.connect(myServer, myPort)) { //starts client connection, checks for connection + printClient.println(apiPostData); + printClient.println("Host: " + String(myServer) + ":" + String(myPort)); + printClient.println("Connection: close"); + printClient.println("X-Api-Key: " + myApiKey); + if (encodedAuth != "") { + printClient.print("Authorization: "); + printClient.println("Basic " + encodedAuth); + } + printClient.println("User-Agent: ArduinoWiFi/1.1"); + printClient.println("Content-Type: application/json"); + printClient.print("Content-Length: "); + printClient.println(apiPostBody.length()); + printClient.println(); + printClient.println(apiPostBody); + if (printClient.println() == 0) { + Serial.println("Connection to " + String(myServer) + ":" + String(myPort) + " failed."); + Serial.println(); + resetPrintData(); + printerData.error = "Connection to " + String(myServer) + ":" + String(myPort) + " failed."; + return printClient; + } + } + else { + Serial.println("Connection to OctoPrint failed: " + String(myServer) + ":" + String(myPort)); //error message if no client connect + Serial.println(); + resetPrintData(); + printerData.error = "Connection to OctoPrint failed: " + String(myServer) + ":" + String(myPort); + return printClient; + } + + // Check HTTP status + char status[32] = {0}; + printClient.readBytesUntil('\r', status, sizeof(status)); + if (strcmp(status, "HTTP/1.1 200 OK") != 0 && strcmp(status, "HTTP/1.1 409 CONFLICT") != 0) { + Serial.print(F("Unexpected response: ")); + Serial.println(status); + printerData.state = ""; + printerData.error = "Response: " + String(status); + return printClient; + } + + // Skip HTTP headers + char endOfHeaders[] = "\r\n\r\n"; + if (!printClient.find(endOfHeaders)) { + Serial.println(F("Invalid response")); + printerData.error = "Invalid response from " + String(myServer) + ":" + String(myPort); + printerData.state = ""; + } + + return printClient; +} + +void OctoPrintClient::getPrinterJobResults() { + if (!validate()) { + return; + } + //**** get the Printer Job status + String apiGetData = "GET /api/job HTTP/1.1"; + WiFiClient printClient = getSubmitRequest(apiGetData); + if (printerData.error != "") { + return; + } + const size_t bufferSize = JSON_OBJECT_SIZE(1) + JSON_OBJECT_SIZE(2) + JSON_OBJECT_SIZE(3) + 2*JSON_OBJECT_SIZE(5) + JSON_OBJECT_SIZE(6) + 710; + DynamicJsonBuffer jsonBuffer(bufferSize); + + // Parse JSON object + JsonObject& root = jsonBuffer.parseObject(printClient); + if (!root.success()) { + Serial.println("OctoPrint Data Parsing failed: " + String(myServer) + ":" + String(myPort)); + printerData.error = "OctoPrint Data Parsing failed: " + String(myServer) + ":" + String(myPort); + printerData.state = ""; + return; + } + + printerData.averagePrintTime = (const char*)root["job"]["averagePrintTime"]; + printerData.estimatedPrintTime = (const char*)root["job"]["estimatedPrintTime"]; + printerData.fileName = (const char*)root["job"]["file"]["name"]; + printerData.fileSize = (const char*)root["job"]["file"]["size"]; + printerData.lastPrintTime = (const char*)root["job"]["lastPrintTime"]; + printerData.progressCompletion = (const char*)root["progress"]["completion"]; + printerData.progressFilepos = (const char*)root["progress"]["filepos"]; + printerData.progressPrintTime = (const char*)root["progress"]["printTime"]; + printerData.progressPrintTimeLeft = (const char*)root["progress"]["printTimeLeft"]; + printerData.filamentLength = (const char*)root["job"]["filament"]["tool0"]["length"]; + printerData.state = (const char*)root["state"]; + + if (isOperational()) { + Serial.println("Status: " + printerData.state); + } else { + Serial.println("Printer Not Operational"); + } + + //**** get the Printer Temps and Stat + apiGetData = "GET /api/printer?exclude=sd,history HTTP/1.1"; + printClient = getSubmitRequest(apiGetData); + if (printerData.error != "") { + return; + } + const size_t bufferSize2 = 3*JSON_OBJECT_SIZE(2) + 2*JSON_OBJECT_SIZE(3) + JSON_OBJECT_SIZE(9) + 300; + DynamicJsonBuffer jsonBuffer2(bufferSize2); + + // Parse JSON object + JsonObject& root2 = jsonBuffer2.parseObject(printClient); + if (!root2.success()) { + printerData.isPrinting = false; + printerData.toolTemp = ""; + printerData.toolTargetTemp = ""; + printerData.bedTemp = ""; + printerData.bedTargetTemp = (const char*)root2["temperature"]["bed"]["target"]; + return; + } + + String printing = (const char*)root2["state"]["flags"]["printing"]; + if (printing == "true") { + printerData.isPrinting = true; + } + printerData.toolTemp = (const char*)root2["temperature"]["tool0"]["actual"]; + printerData.toolTargetTemp = (const char*)root2["temperature"]["tool0"]["target"]; + printerData.bedTemp = (const char*)root2["temperature"]["bed"]["actual"]; + printerData.bedTargetTemp = (const char*)root2["temperature"]["bed"]["target"]; + + if (isPrinting()) { + Serial.println("Status: " + printerData.state + " " + printerData.fileName + "(" + printerData.progressCompletion + "%)"); + } +} + +void OctoPrintClient::getPrinterPsuState() { + //**** get the PSU state (if enabled and printer operational) + if (pollPsu && isOperational()) { + if (!validate()) { + printerData.isPSUoff = false; // we do not know PSU state, so assume on. + return; + } + String apiPostData = "POST /api/plugin/psucontrol HTTP/1.1"; + String apiPostBody = "{\"command\":\"getPSUState\"}"; + WiFiClient printClient = getPostRequest(apiPostData,apiPostBody); + if (printerData.error != "") { + printerData.isPSUoff = false; // we do not know PSU state, so assume on. + return; + } + const size_t bufferSize3 = JSON_OBJECT_SIZE(2) + 300; + DynamicJsonBuffer jsonBuffer3(bufferSize3); + + // Parse JSON object + JsonObject& root3 = jsonBuffer3.parseObject(printClient); + if (!root3.success()) { + printerData.isPSUoff = false; // we do not know PSU state, so assume on + return; + } + + String psu = (const char*)root3["isPSUOn"]; + if (psu == "true") { + printerData.isPSUoff = false; // PSU checked and is on + } else { + printerData.isPSUoff = true; // PSU checked and is off, set flag + } + printClient.stop(); //stop client + } else { + printerData.isPSUoff = false; // we are not checking PSU state, so assume on + } +} + +// Reset all PrinterData +void OctoPrintClient::resetPrintData() { + printerData.averagePrintTime = ""; + printerData.estimatedPrintTime = ""; + printerData.fileName = ""; + printerData.fileSize = ""; + printerData.lastPrintTime = ""; + printerData.progressCompletion = ""; + printerData.progressFilepos = ""; + printerData.progressPrintTime = ""; + printerData.progressPrintTimeLeft = ""; + printerData.state = ""; + printerData.toolTemp = ""; + printerData.toolTargetTemp = ""; + printerData.filamentLength = ""; + printerData.bedTemp = ""; + printerData.bedTargetTemp = ""; + printerData.isPrinting = false; + printerData.isPSUoff = false; + printerData.error = ""; +} + +String OctoPrintClient::getAveragePrintTime(){ + return printerData.averagePrintTime; +} + +String OctoPrintClient::getEstimatedPrintTime() { + return printerData.estimatedPrintTime; +} + +String OctoPrintClient::getFileName() { + return printerData.fileName; +} + +String OctoPrintClient::getFileSize() { + return printerData.fileSize; +} + +String OctoPrintClient::getLastPrintTime(){ + return printerData.lastPrintTime; +} + +String OctoPrintClient::getProgressCompletion() { + return String(printerData.progressCompletion.toInt()); +} + +String OctoPrintClient::getProgressFilepos() { + return printerData.progressFilepos; +} + +String OctoPrintClient::getProgressPrintTime() { + return printerData.progressPrintTime; +} + +String OctoPrintClient::getProgressPrintTimeLeft() { + String rtnValue = printerData.progressPrintTimeLeft; + if (getProgressCompletion() == "100") { + rtnValue = "0"; // Print is done so this should be 0 this is a fix for OctoPrint + } + return rtnValue; +} + +String OctoPrintClient::getState() { + return printerData.state; +} + +boolean OctoPrintClient::isPrinting() { + return printerData.isPrinting; +} + +boolean OctoPrintClient::isPSUoff() { + return printerData.isPSUoff; +} + +boolean OctoPrintClient::isOperational() { + boolean operational = false; + if (printerData.state == "Operational" || isPrinting()) { + operational = true; + } + return operational; +} + +String OctoPrintClient::getTempBedActual() { + return printerData.bedTemp; +} + +String OctoPrintClient::getTempBedTarget() { + return printerData.bedTargetTemp; +} + +String OctoPrintClient::getTempToolActual() { + return printerData.toolTemp; +} + +String OctoPrintClient::getTempToolTarget() { + return printerData.toolTargetTemp; +} + +String OctoPrintClient::getFilamentLength() { + return printerData.filamentLength; +} + +String OctoPrintClient::getError() { + return printerData.error; +} + +String OctoPrintClient::getValueRounded(String value) { + float f = value.toFloat(); + int rounded = (int)(f+0.5f); + return String(rounded); } diff --git a/printermonitor/OctoPrintClient.h b/printermonitor/OctoPrintClient.h index 1d02836..c32358a 100644 --- a/printermonitor/OctoPrintClient.h +++ b/printermonitor/OctoPrintClient.h @@ -1,91 +1,98 @@ -/** 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 - -class OctoPrintClient { - -private: - char myServer[100]; - int myPort = 80; - String myApiKey = ""; - String encodedAuth = ""; - - void resetPrintData(); - boolean validate(); - WiFiClient getSubmitRequest(String apiGetData); - - String result; - - typedef struct { - String averagePrintTime; - String estimatedPrintTime; - String fileName; - String fileSize; - String lastPrintTime; - String progressCompletion; - String progressFilepos; - String progressPrintTime; - String progressPrintTimeLeft; - String state; - String toolTemp; - String toolTargetTemp; - String filamentLength; - String bedTemp; - String bedTargetTemp; - boolean isPrinting; - String error; - } PrinterStruct; - - PrinterStruct printerData; - - -public: - OctoPrintClient(String ApiKey, String server, int port, String user, String pass); - void getPrinterJobResults(); - void updateOctoPrintClient(String ApiKey, String server, int port, String user, String pass); - - String getAveragePrintTime(); - String getEstimatedPrintTime(); - String getFileName(); - String getFileSize(); - String getLastPrintTime(); - String getProgressCompletion(); - String getProgressFilepos(); - String getProgressPrintTime(); - String getProgressPrintTimeLeft(); - String getState(); - boolean isPrinting(); - boolean isOperational(); - String getTempBedActual(); - String getTempBedTarget(); - String getTempToolActual(); - String getTempToolTarget(); - String getFilamentLength(); - String getValueRounded(String value); - String getError(); -}; +/** 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. +*/ + +// Additional Contributions: +/* 15 Jan 2019 : Owen Carter : Add psucontrol query via POST api call */ + +#pragma once +#include +#include +#include + +class OctoPrintClient { + +private: + char myServer[100]; + int myPort = 80; + String myApiKey = ""; + String encodedAuth = ""; + boolean pollPsu; + + void resetPrintData(); + boolean validate(); + WiFiClient getSubmitRequest(String apiGetData); + WiFiClient getPostRequest(String apiPostData, String apiPostBody); + + String result; + + typedef struct { + String averagePrintTime; + String estimatedPrintTime; + String fileName; + String fileSize; + String lastPrintTime; + String progressCompletion; + String progressFilepos; + String progressPrintTime; + String progressPrintTimeLeft; + String state; + String toolTemp; + String toolTargetTemp; + String filamentLength; + String bedTemp; + String bedTargetTemp; + boolean isPrinting; + boolean isPSUoff; + String error; + } PrinterStruct; + + PrinterStruct printerData; + + +public: + OctoPrintClient(String ApiKey, String server, int port, String user, String pass, boolean psu); + void getPrinterJobResults(); + void getPrinterPsuState(); + void updateOctoPrintClient(String ApiKey, String server, int port, String user, String pass, boolean psu); + + String getAveragePrintTime(); + String getEstimatedPrintTime(); + String getFileName(); + String getFileSize(); + String getLastPrintTime(); + String getProgressCompletion(); + String getProgressFilepos(); + String getProgressPrintTime(); + String getProgressPrintTimeLeft(); + String getState(); + boolean isPrinting(); + boolean isOperational(); + boolean isPSUoff(); + String getTempBedActual(); + String getTempBedTarget(); + String getTempToolActual(); + String getTempToolTarget(); + String getFilamentLength(); + String getValueRounded(String value); + String getError(); +}; diff --git a/printermonitor/Settings.h b/printermonitor/Settings.h index c064400..d478fec 100644 --- a/printermonitor/Settings.h +++ b/printermonitor/Settings.h @@ -1,100 +1,111 @@ -/** 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. -*/ - -/****************************************************************************** - * Printer Monitor is designed for the Wemos D1 ESP8266 - * Wemos D1 Mini: https://amzn.to/2qLyKJd - * 0.96" OLED I2C 128x64 Display (12864) SSD1306 - * OLED Display: https://amzn.to/2JDEAUF - ******************************************************************************/ -/****************************************************************************** - * NOTE: The settings here 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. - ******************************************************************************/ - -#include -#include -#include -#include -#include -#include -#include "TimeClient.h" -#include "OctoPrintClient.h" -#include "OpenWeatherMapClient.h" -#include "WeatherStationFonts.h" -#include "FS.h" -#include "SH1106Wire.h" -#include "SSD1306Wire.h" -#include "OLEDDisplayUi.h" - -//****************************** -// Start Settings -//****************************** - -// OctoPrint Monitoring -- Monitor your 3D printer OctoPrint Server -String OctoPrintApiKey = ""; // ApiKey from your User Account on OctoPrint -String OctoPrintHostName = "octopi";// Default 'octopi' -- or hostname if different (optional if your IP changes) -String OctoPrintServer = ""; // IP or Address of your OctoPrint Server (DO NOT include http://) -int OctoPrintPort = 80; // the port you are running your OctoPrint server on (usually 80); -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) - -// Weather Configuration -boolean DISPLAYWEATHER = true; // true = show weather when not printing / false = no weather -String WeatherApiKey = ""; // Your API Key from http://openweathermap.org/ -// Default City Location (use http://openweathermap.org/find to find city ID) -int CityIDs[] = { 5304391 }; //Only USE ONE for weather marquee -boolean IS_METRIC = false; // false = Imperial and true = Metric -// Languages: ar, bg, ca, cz, de, el, en, fa, fi, fr, gl, hr, hu, it, ja, kr, la, lt, mk, nl, pl, pt, ro, ru, se, sk, sl, es, tr, ua, vi, zh_cn, zh_tw -String WeatherLanguage = "en"; //Default (en) English - -const int WEBSERVER_PORT = 80; // The port you can access this device on over HTTP -const boolean WEBSERVER_ENABLED = true; // Device will provide a web interface via http://[ip]:[port]/ -boolean IS_BASIC_AUTH = true; // true = require athentication to change configuration settings / false = no auth -char* www_username = "admin"; // User account for the Web Interface -char* www_password = "password"; // Password for the Web Interface -float UtcOffset = -7; // Hour offset from GMT for your timezone -boolean IS_24HOUR = false; // 23:00 millitary 24 hour clock -int minutesBetweenDataRefresh = 15; -boolean DISPLAYCLOCK = true; // true = Show Clock when not printing / false = turn off display when not printing - -// Display Settings -const int I2C_DISPLAY_ADDRESS = 0x3c; // I2C Address of your Display (usually 0x3c or 0x3d) -const int SDA_PIN = D2; -const int SCL_PIN = D5; -boolean INVERT_DISPLAY = false; // true = pins at top | false = pins at the bottom -//#define DISPLAY_SH1106 // Uncomment this line to use the SH1106 display -- SSD1306 is used by default and is most common - -// LED Settings -const int externalLight = LED_BUILTIN; // Set to unused pin, like D1, to disable use of built-in LED (LED_BUILTIN) - -boolean ENABLE_OTA = true; // this will allow you to load firmware to the device over WiFi (see OTA for ESP8266) -String OTA_Password = ""; // Set an OTA password here -- leave blank if you don't want to be prompted for password -//****************************** -// End Settings -//****************************** - -String themeColor = "light-green"; // this can be changed later in the web interface. +/** 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. +*/ + +// Additional Contributions: +/* 15 Jan 2019 : Owen Carter : Add psucontrol setting */ + +/****************************************************************************** + * Printer Monitor is designed for the Wemos D1 ESP8266 + * Wemos D1 Mini: https://amzn.to/2qLyKJd + * 0.96" OLED I2C 128x64 Display (12864) SSD1306 + * OLED Display: https://amzn.to/2JDEAUF + ******************************************************************************/ +/****************************************************************************** + * NOTE: The settings here 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. + ******************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include "TimeClient.h" +#include "OctoPrintClient.h" +#include "OpenWeatherMapClient.h" +#include "WeatherStationFonts.h" +#include "FS.h" +#include "SH1106Wire.h" +#include "SSD1306Wire.h" +#include "OLEDDisplayUi.h" + +//****************************** +// Start Settings +//****************************** + +// OctoPrint Monitoring -- Monitor your 3D printer OctoPrint Server +String OctoPrintApiKey = ""; // ApiKey from your User Account on OctoPrint +String OctoPrintHostName = "octopi";// Default 'octopi' -- or hostname if different (optional if your IP changes) +String OctoPrintServer = ""; // IP or Address of your OctoPrint Server (DO NOT include http://) +int OctoPrintPort = 80; // the port you are running your OctoPrint server on (usually 80); +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) + +// Weather Configuration +boolean DISPLAYWEATHER = true; // true = show weather when not printing / false = no weather +String WeatherApiKey = ""; // Your API Key from http://openweathermap.org/ +// Default City Location (use http://openweathermap.org/find to find city ID) +int CityIDs[] = { 5304391 }; //Only USE ONE for weather marquee +boolean IS_METRIC = false; // false = Imperial and true = Metric +// Languages: ar, bg, ca, cz, de, el, en, fa, fi, fr, gl, hr, hu, it, ja, kr, la, lt, mk, nl, pl, pt, ro, ru, se, sk, sl, es, tr, ua, vi, zh_cn, zh_tw +String WeatherLanguage = "en"; //Default (en) English + +// Webserver +const int WEBSERVER_PORT = 80; // The port you can access this device on over HTTP +const boolean WEBSERVER_ENABLED = true; // Device will provide a web interface via http://[ip]:[port]/ +boolean IS_BASIC_AUTH = true; // true = require athentication to change configuration settings / false = no auth +char* www_username = "admin"; // User account for the Web Interface +char* www_password = "password"; // Password for the Web Interface + +// Date and Time +float UtcOffset = -7; // Hour offset from GMT for your timezone +boolean IS_24HOUR = false; // 23:00 millitary 24 hour clock +int minutesBetweenDataRefresh = 15; +boolean DISPLAYCLOCK = true; // true = Show Clock when not printing / false = turn off display when not printing + +// Display Settings +const int I2C_DISPLAY_ADDRESS = 0x3c; // I2C Address of your Display (usually 0x3c or 0x3d) +const int SDA_PIN = D2; +const int SCL_PIN = D5; +boolean INVERT_DISPLAY = false; // true = pins at top | false = pins at the bottom +//#define DISPLAY_SH1106 // Uncomment this line to use the SH1106 display -- SSD1306 is used by default and is most common + +// LED Settings +const int externalLight = LED_BUILTIN; // Set to unused pin, like D1, to disable use of built-in LED (LED_BUILTIN) + +// PSU Control +boolean HAS_PSU = false; // Set to true if https://github.com/kantlivelong/OctoPrint-PSUControl/ in use + +// OTA Updates +boolean ENABLE_OTA = true; // this will allow you to load firmware to the device over WiFi (see OTA for ESP8266) +String OTA_Password = ""; // Set an OTA password here -- leave blank if you don't want to be prompted for password + +//****************************** +// End Settings +//****************************** + +String themeColor = "light-green"; // this can be changed later in the web interface. diff --git a/printermonitor/printermonitor.ino b/printermonitor/printermonitor.ino index 21e201b..428f36a 100644 --- a/printermonitor/printermonitor.ino +++ b/printermonitor/printermonitor.ino @@ -1,1209 +1,1248 @@ -/** 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. -*/ - - /********************************************** - * Edit Settings.h for personalization - ***********************************************/ - -#include "Settings.h" - -#define VERSION "2.3" - -#define HOSTNAME "OctMon-" -#define CONFIG "/conf.txt" - -/* Useful Constants */ -#define SECS_PER_MIN (60UL) -#define SECS_PER_HOUR (3600UL) - -/* Useful Macros for getting elapsed time */ -#define numberOfSeconds(_time_) (_time_ % SECS_PER_MIN) -#define numberOfMinutes(_time_) ((_time_ / SECS_PER_MIN) % SECS_PER_MIN) -#define numberOfHours(_time_) (_time_ / SECS_PER_HOUR) - -// Initialize the oled display for I2C_DISPLAY_ADDRESS -// SDA_PIN and SCL_PIN -#if defined(DISPLAY_SH1106) - SH1106Wire display(I2C_DISPLAY_ADDRESS, SDA_PIN, SCL_PIN); -#else - SSD1306Wire display(I2C_DISPLAY_ADDRESS, SDA_PIN, SCL_PIN); // this is the default -#endif - -OLEDDisplayUi ui( &display ); - -void drawProgress(OLEDDisplay *display, int percentage, String label); -void drawOtaProgress(unsigned int, unsigned int); -void drawScreen1(OLEDDisplay *display, OLEDDisplayUiState* state, int16_t x, int16_t y); -void drawScreen2(OLEDDisplay *display, OLEDDisplayUiState* state, int16_t x, int16_t y); -void drawScreen3(OLEDDisplay *display, OLEDDisplayUiState* state, int16_t x, int16_t y); -void drawHeaderOverlay(OLEDDisplay *display, OLEDDisplayUiState* state); -void drawClock(OLEDDisplay *display, OLEDDisplayUiState* state, int16_t x, int16_t y); -void drawWeather(OLEDDisplay *display, OLEDDisplayUiState* state, int16_t x, int16_t y); -void drawClockHeaderOverlay(OLEDDisplay *display, OLEDDisplayUiState* state); - -// Set the number of Frames supported -const int numberOfFrames = 3; -FrameCallback frames[numberOfFrames]; -FrameCallback clockFrame[2]; -boolean isClockOn = false; - -OverlayCallback overlays[] = { drawHeaderOverlay }; -OverlayCallback clockOverlay[] = { drawClockHeaderOverlay }; -int numberOfOverlays = 1; - -// Time -TimeClient timeClient(UtcOffset); -long lastEpoch = 0; -long firstEpoch = 0; -long displayOffEpoch = 0; -String lastMinute = "xx"; -String lastSecond = "xx"; -String lastReportStatus = ""; -boolean displayOn = true; - -// OctoPrint Client -OctoPrintClient printerClient(OctoPrintApiKey, OctoPrintServer, OctoPrintPort, OctoAuthUser, OctoAuthPass); -int printerCount = 0; - -// Weather Client -OpenWeatherMapClient weatherClient(WeatherApiKey, CityIDs, 1, IS_METRIC, WeatherLanguage); - -//declairing prototypes -void configModeCallback (WiFiManager *myWiFiManager); -int8_t getWifiQuality(); - -ESP8266WebServer server(WEBSERVER_PORT); -ESP8266HTTPUpdateServer serverUpdater; - -String WEB_ACTIONS = " Home" - " Configure" - " Weather" - " Reset Settings" - " Forget WiFi" - " Firmware Update" - " About"; - -String CHANGE_FORM = "

Station Config:

" - "

" - "

" - "

" - "

" - "

" - "


" - "

Display Clock when printer is off

" - "

Use 24 Hour Clock (military time)

" - "

Flip display orientation

" - "

Clock Sync / Weather Refresh (minutes)

" - "

Theme Color

" - "


" - "

Use Security Credentials for Configuration Changes

" - "

" - "

" - "
"; - -String WEATHER_FORM = "

Weather Config:

" - "

Display Weather when printer is off

" - "" - "" - "

" - "

" - "

Use Metric (Celsius)

" - "

Weather Language

" - "
" - ""; - -String LANG_OPTIONS = "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - ""; - -String COLOR_THEMES = "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - ""; - - -void setup() { - Serial.begin(115200); - SPIFFS.begin(); - delay(10); - - //New Line to clear from start garbage - Serial.println(); - - // Initialize digital pin for LED (little blue light on the Wemos D1 Mini) - pinMode(externalLight, OUTPUT); - - readSettings(); - - // initialize dispaly - display.init(); - if (INVERT_DISPLAY) { - display.flipScreenVertically(); // connections at top of OLED display - } - display.clear(); - display.display(); - - //display.flipScreenVertically(); - display.setFont(ArialMT_Plain_16); - display.setTextAlignment(TEXT_ALIGN_CENTER); - display.setContrast(255); // default is 255 - display.drawString(64, 5, "Printer Monitor\nBy Qrome\nV" + String(VERSION)); - display.display(); - - //WiFiManager - //Local intialization. Once its business is done, there is no need to keep it around - WiFiManager wifiManager; - - // Uncomment for testing wifi manager - //wifiManager.resetSettings(); - wifiManager.setAPCallback(configModeCallback); - - String hostname(HOSTNAME); - hostname += String(ESP.getChipId(), HEX); - if (!wifiManager.autoConnect((const char *)hostname.c_str())) {// new addition - delay(3000); - WiFi.disconnect(true); - ESP.reset(); - delay(5000); - } - - // You can change the transition that is used - // SLIDE_LEFT, SLIDE_RIGHT, SLIDE_TOP, SLIDE_DOWN - ui.setFrameAnimation(SLIDE_LEFT); - ui.setTargetFPS(30); - ui.disableAllIndicators(); - ui.setFrames(frames, (numberOfFrames)); - frames[0] = drawScreen1; - frames[1] = drawScreen2; - frames[2] = drawScreen3; - clockFrame[0] = drawClock; - clockFrame[1] = drawWeather; - ui.setOverlays(overlays, numberOfOverlays); - - // Inital UI takes care of initalising the display too. - ui.init(); - if (INVERT_DISPLAY) { - display.flipScreenVertically(); //connections at top of OLED display - } - - // print the received signal strength: - Serial.print("Signal Strength (RSSI): "); - Serial.print(getWifiQuality()); - Serial.println("%"); - - if (ENABLE_OTA) { - 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.setHostname((const char *)hostname.c_str()); - if (OTA_Password != "") { - ArduinoOTA.setPassword(((const char *)OTA_Password.c_str())); - } - ArduinoOTA.begin(); - } - - if (WEBSERVER_ENABLED) { - server.on("/", displayPrinterStatus); - server.on("/systemreset", handleSystemReset); - server.on("/forgetwifi", handleWifiReset); - server.on("/updateconfig", handleUpdateConfig); - server.on("/updateweatherconfig", handleUpdateWeather); - server.on("/configure", handleConfigure); - server.on("/configureweather", handleWeatherConfigure); - server.onNotFound(redirectHome); - serverUpdater.setup(&server, "/update", www_username, www_password); - // Start the server - server.begin(); - Serial.println("Server started"); - // Print the IP address - String webAddress = "http://" + WiFi.localIP().toString() + ":" + String(WEBSERVER_PORT) + "/"; - Serial.println("Use this URL : " + webAddress); - display.clear(); - display.setTextAlignment(TEXT_ALIGN_CENTER); - display.setFont(ArialMT_Plain_10); - display.drawString(64, 10, "Web Interface On"); - display.drawString(64, 20, "You May Connect to IP"); - display.setFont(ArialMT_Plain_16); - display.drawString(64, 30, WiFi.localIP().toString()); - display.drawString(64, 46, "Port: " + String(WEBSERVER_PORT)); - display.display(); - } else { - Serial.println("Web Interface is Disabled"); - display.clear(); - display.setTextAlignment(TEXT_ALIGN_CENTER); - display.setFont(ArialMT_Plain_10); - display.drawString(64, 10, "Web Interface is Off"); - display.drawString(64, 20, "Enable in Settings.h"); - display.display(); - } - flashLED(5, 500); - findMDNS(); //go find Octoprint Server by the hostname - Serial.println("*** Leaving setup()"); -} - -void findMDNS() { - if (OctoPrintHostName == "" || ENABLE_OTA == false) { - return; // nothing to do here - } - // We now query our network for 'web servers' service - // over tcp, and get the number of available devices - int n = MDNS.queryService("http", "tcp"); - if (n == 0) { - Serial.println("no services found - make sure OctoPrint server is turned on"); - return; - } - Serial.println("*** Looking for " + OctoPrintHostName + " over mDNS"); - for (int i = 0; i < n; ++i) { - // Going through every available service, - // we're searching for the one whose hostname - // matches what we want, and then get its IP - Serial.println("Found: " + MDNS.hostname(i)); - if (MDNS.hostname(i) == OctoPrintHostName) { - IPAddress serverIp = MDNS.IP(i); - OctoPrintServer = serverIp.toString(); - OctoPrintPort = MDNS.port(i); // save the port - Serial.println("*** Found OctoPrint Server " + OctoPrintHostName + " http://" + OctoPrintServer + ":" + OctoPrintPort); - writeSettings(); // update the settings - } - } -} - -//************************************************************ -// Main Looop -//************************************************************ -void loop() { - - //Get Time Update - if((getMinutesFromLastRefresh() >= minutesBetweenDataRefresh) || lastEpoch == 0) { - getUpdateTime(); - } - - if (lastMinute != timeClient.getMinutes() && !printerClient.isPrinting()) { - // Check status every 60 seconds - digitalWrite(externalLight, LOW); - lastMinute = timeClient.getMinutes(); // reset the check value - printerClient.getPrinterJobResults(); - digitalWrite(externalLight, HIGH); - } else if (printerClient.isPrinting()) { - if (lastSecond != timeClient.getSeconds() && timeClient.getSeconds().endsWith("0")) { - lastSecond = timeClient.getSeconds(); - // every 10 seconds while printing get an update - digitalWrite(externalLight, LOW); - printerClient.getPrinterJobResults(); - digitalWrite(externalLight, HIGH); - } - } - - checkDisplay(); // Check to see if the printer is on or offline and change display. - - ui.update(); - - if (WEBSERVER_ENABLED) { - server.handleClient(); - } - if (ENABLE_OTA) { - ArduinoOTA.handle(); - } -} - -void getUpdateTime() { - digitalWrite(externalLight, LOW); // turn on the LED - Serial.println(); - - if (displayOn && DISPLAYWEATHER) { - Serial.println("Getting Weather Data..."); - weatherClient.updateWeather(); - } - - Serial.println("Updating Time..."); - //Update the Time - timeClient.updateTime(); - lastEpoch = timeClient.getCurrentEpoch(); - Serial.println("Local time: " + timeClient.getAmPmFormattedTime()); - - digitalWrite(externalLight, HIGH); // turn off the LED -} - -boolean authentication() { - if (IS_BASIC_AUTH && (strlen(www_username) >= 1 && strlen(www_password) >= 1)) { - return server.authenticate(www_username, www_password); - } - return true; // Authentication not required -} - -void handleSystemReset() { - if (!authentication()) { - return server.requestAuthentication(); - } - Serial.println("Reset System Configuration"); - if (SPIFFS.remove(CONFIG)) { - redirectHome(); - ESP.restart(); - } -} - -void handleUpdateWeather() { - if (!authentication()) { - return server.requestAuthentication(); - } - DISPLAYWEATHER = server.hasArg("isWeatherEnabled"); - WeatherApiKey = server.arg("openWeatherMapApiKey"); - CityIDs[0] = server.arg("city1").toInt(); - IS_METRIC = server.hasArg("metric"); - WeatherLanguage = server.arg("language"); - writeSettings(); - isClockOn = false; // this will force a check for the display - checkDisplay(); - lastEpoch = 0; - redirectHome(); -} - -void handleUpdateConfig() { - boolean flipOld = INVERT_DISPLAY; - if (!authentication()) { - return server.requestAuthentication(); - } - OctoPrintApiKey = server.arg("octoPrintApiKey"); - OctoPrintHostName = server.arg("octoPrintHostName"); - OctoPrintServer = server.arg("octoPrintAddress"); - OctoPrintPort = server.arg("octoPrintPort").toInt(); - OctoAuthUser = server.arg("octoUser"); - OctoAuthPass = server.arg("octoPass"); - DISPLAYCLOCK = server.hasArg("isClockEnabled"); - IS_24HOUR = server.hasArg("is24hour"); - INVERT_DISPLAY = server.hasArg("invDisp"); - minutesBetweenDataRefresh = server.arg("refresh").toInt(); - themeColor = server.arg("theme"); - UtcOffset = server.arg("utcoffset").toFloat(); - String temp = server.arg("userid"); - temp.toCharArray(www_username, sizeof(temp)); - temp = server.arg("stationpassword"); - temp.toCharArray(www_password, sizeof(temp)); - writeSettings(); - findMDNS(); - printerClient.getPrinterJobResults(); - if (INVERT_DISPLAY != flipOld) { - ui.init(); - if(INVERT_DISPLAY) - display.flipScreenVertically(); - ui.update(); - } - checkDisplay(); - lastEpoch = 0; - redirectHome(); -} - -void handleWifiReset() { - if (!authentication()) { - return server.requestAuthentication(); - } - //WiFiManager - //Local intialization. Once its business is done, there is no need to keep it around - redirectHome(); - WiFiManager wifiManager; - wifiManager.resetSettings(); - ESP.restart(); -} - -void handleWeatherConfigure() { - if (!authentication()) { - 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", ""); - - html = getHeader(); - server.sendContent(html); - - String form = WEATHER_FORM; - String isWeatherChecked = ""; - if (DISPLAYWEATHER) { - isWeatherChecked = "checked='checked'"; - } - form.replace("%IS_WEATHER_CHECKED%", isWeatherChecked); - form.replace("%WEATHERKEY%", WeatherApiKey); - form.replace("%CITYNAME1%", weatherClient.getCity(0)); - form.replace("%CITY1%", String(CityIDs[0])); - String checked = ""; - if (IS_METRIC) { - checked = "checked='checked'"; - } - form.replace("%METRIC%", checked); - String options = LANG_OPTIONS; - options.replace(">"+String(WeatherLanguage)+"<", " selected>"+String(WeatherLanguage)+"<"); - form.replace("%LANGUAGEOPTIONS%", options); - server.sendContent(form); - - html = getFooter(); - server.sendContent(html); - server.sendContent(""); - server.client().stop(); - digitalWrite(externalLight, HIGH); -} - -void handleConfigure() { - if (!authentication()) { - 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", ""); - - html = getHeader(); - server.sendContent(html); - - String form = CHANGE_FORM; - - form.replace("%OCTOKEY%", OctoPrintApiKey); - form.replace("%OCTOHOST%", OctoPrintHostName); - form.replace("%OCTOADDRESS%", OctoPrintServer); - form.replace("%OCTOPORT%", String(OctoPrintPort)); - form.replace("%OCTOUSER%", OctoAuthUser); - form.replace("%OCTOPASS%", OctoAuthPass); - String isClockChecked = ""; - if (DISPLAYCLOCK) { - isClockChecked = "checked='checked'"; - } - form.replace("%IS_CLOCK_CHECKED%", isClockChecked); - String is24hourChecked = ""; - if (IS_24HOUR) { - is24hourChecked = "checked='checked'"; - } - form.replace("%IS_24HOUR_CHECKED%", is24hourChecked); - String isInvDisp = ""; - if (INVERT_DISPLAY) { - isInvDisp = "checked='checked'"; - } - form.replace("%IS_INVDISP_CHECKED%", isInvDisp); - String options = ""; - options.replace(">"+String(minutesBetweenDataRefresh)+"<", " selected>"+String(minutesBetweenDataRefresh)+"<"); - form.replace("%OPTIONS%", options); - String themeOptions = COLOR_THEMES; - themeOptions.replace(">"+String(themeColor)+"<", " selected>"+String(themeColor)+"<"); - form.replace("%THEME_OPTIONS%", themeOptions); - form.replace("%UTCOFFSET%", String(UtcOffset)); - String isUseSecurityChecked = ""; - if (IS_BASIC_AUTH) { - isUseSecurityChecked = "checked='checked'"; - } - form.replace("%IS_BASICAUTH_CHECKED%", isUseSecurityChecked); - form.replace("%USERID%", String(www_username)); - form.replace("%STATIONPASSWORD%", String(www_password)); - - server.sendContent(form); - - html = getFooter(); - server.sendContent(html); - server.sendContent(""); - server.client().stop(); - digitalWrite(externalLight, HIGH); -} - -void displayMessage(String message) { - digitalWrite(externalLight, LOW); - - 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", ""); - String html = getHeader(); - server.sendContent(String(html)); - server.sendContent(String(message)); - html = getFooter(); - server.sendContent(String(html)); - server.sendContent(""); - server.client().stop(); - - digitalWrite(externalLight, HIGH); -} - -void redirectHome() { - // Send them back to the Root Directory - server.sendHeader("Location", String("/"), true); - server.sendHeader("Cache-Control", "no-cache, no-store"); - server.sendHeader("Pragma", "no-cache"); - server.sendHeader("Expires", "-1"); - server.send(302, "text/plain", ""); - server.client().stop(); -} - -String getHeader() { - return getHeader(false); -} - -String getHeader(boolean refresh) { - String menu = WEB_ACTIONS; - - String html = ""; - html += "Printer Monitor"; - html += ""; - html += ""; - if (refresh) { - html += ""; - } - html += ""; - html += ""; - html += ""; - html += ""; - html += ""; - html += "

Printer Monitor

"; - html += ""; - html += "
"; - return html; -} - -String getFooter() { - int8_t rssi = getWifiQuality(); - Serial.print("Signal Strength (RSSI): "); - Serial.print(rssi); - Serial.println("%"); - String html = "


"; - html += "
"; - html += "
"; - if (lastReportStatus != "") { - html += " Report Status: " + lastReportStatus + "
"; - } - html += " Version: " + String(VERSION) + "
"; - html += " Signal Strength: "; - html += String(rssi) + "%"; - html += "
"; - html += ""; - return html; -} - -void displayPrinterStatus() { - 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", ""); - server.sendContent(String(getHeader(true))); - - String displayTime = timeClient.getAmPmHours() + ":" + timeClient.getMinutes() + ":" + timeClient.getSeconds() + " " + timeClient.getAmPm(); - if (IS_24HOUR) { - displayTime = timeClient.getHours() + ":" + timeClient.getMinutes() + ":" + timeClient.getSeconds(); - } - - html += "

Time: " + displayTime + "

"; - html += "

"; - html += "Host Name: " + OctoPrintHostName + "
"; - if (printerClient.getError() != "") { - html += "Error: " + printerClient.getError() + "
"; - } - html += "Status: " + printerClient.getState() + "
"; - - if (printerClient.isPrinting()) { - html += "File: " + printerClient.getFileName() + "
"; - float fileSize = printerClient.getFileSize().toFloat(); - if (fileSize > 0) { - fileSize = fileSize / 1024; - html += "File Size: " + String(fileSize) + "KB
"; - } - int filamentLength = printerClient.getFilamentLength().toInt(); - if (filamentLength > 0) { - float fLength = float(filamentLength) / 1000; - html += "Filament: " + String(fLength) + "m
"; - } - - html += "Tool Temperature: " + printerClient.getTempToolActual() + "° C
"; - html += "Bed Temperature: " + printerClient.getTempBedActual() + "° C
"; - - int val = printerClient.getProgressPrintTimeLeft().toInt(); - int hours = numberOfHours(val); - int minutes = numberOfMinutes(val); - int seconds = numberOfSeconds(val); - html += "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 += ""; - html += "

" + printerClient.getProgressCompletion() + "%
"; - } else { - html += "
"; - } - - html += "

"; - - server.sendContent(html); // spit out what we got - html = ""; - - if (DISPLAYWEATHER) { - if (weatherClient.getCity(0) == "") { - html += "

Please Configure Weather API

"; - if (weatherClient.getError() != "") { - html += "

Weather Error: " + weatherClient.getError() + "

"; - } - } else { - html += "

" + weatherClient.getCity(0) + ", " + weatherClient.getCountry(0) + "

"; - html += "
"; - html += "" + weatherClient.getDescription(0) + "
"; - html += weatherClient.getHumidity(0) + "% Humidity
"; - html += weatherClient.getWind(0) + " " + getSpeedSymbol() + " Wind
"; - html += "
"; - html += "

"; - html += weatherClient.getCondition(0) + " (" + weatherClient.getDescription(0) + ")
"; - html += weatherClient.getTempRounded(0) + getTempSymbol(true) + "
"; - html += " Map It!
"; - html += "

"; - } - - server.sendContent(html); // spit out what we got - html = ""; // fresh start - } - - server.sendContent(String(getFooter())); - server.sendContent(""); - server.client().stop(); - digitalWrite(externalLight, HIGH); -} - -void configModeCallback (WiFiManager *myWiFiManager) { - Serial.println("Entered config mode"); - Serial.println(WiFi.softAPIP()); - - display.clear(); - display.setTextAlignment(TEXT_ALIGN_CENTER); - display.setFont(ArialMT_Plain_10); - display.drawString(64, 0, "Wifi Manager"); - display.drawString(64, 10, "Please connect to AP"); - display.setFont(ArialMT_Plain_16); - display.drawString(64, 23, myWiFiManager->getConfigPortalSSID()); - display.setFont(ArialMT_Plain_10); - display.drawString(64, 42, "To setup Wifi connection"); - display.display(); - - Serial.println("Wifi Manager"); - Serial.println("Please connect to AP"); - Serial.println(myWiFiManager->getConfigPortalSSID()); - Serial.println("To setup Wifi Configuration"); - flashLED(20, 50); -} - -void flashLED(int number, int delayTime) { - for (int inx = 0; inx < number; inx++) { - delay(delayTime); - digitalWrite(externalLight, LOW); - delay(delayTime); - digitalWrite(externalLight, HIGH); - delay(delayTime); - } -} - -void drawScreen1(OLEDDisplay *display, OLEDDisplayUiState* state, int16_t x, int16_t y) { - display->setTextAlignment(TEXT_ALIGN_CENTER); - display->setFont(ArialMT_Plain_16); - display->drawString(64 + x, 0 + y, "Bed / Tool Temp"); - display->setTextAlignment(TEXT_ALIGN_LEFT); - display->setFont(ArialMT_Plain_24); - String bed = printerClient.getValueRounded(printerClient.getTempBedActual()); - String tool = printerClient.getValueRounded(printerClient.getTempToolActual()); - display->drawString(2 + x, 14 + y, bed + "°"); - display->drawString(64 + x, 14 + y, tool + "°"); -} - -void drawScreen2(OLEDDisplay *display, OLEDDisplayUiState* state, int16_t x, int16_t y) { - display->setTextAlignment(TEXT_ALIGN_CENTER); - display->setFont(ArialMT_Plain_16); - - display->drawString(64 + x, 0 + y, "Time Remaining"); - //display->setTextAlignment(TEXT_ALIGN_LEFT); - display->setFont(ArialMT_Plain_24); - int val = printerClient.getProgressPrintTimeLeft().toInt(); - int hours = numberOfHours(val); - int minutes = numberOfMinutes(val); - int seconds = numberOfSeconds(val); - - String time = zeroPad(hours) + ":" + zeroPad(minutes) + ":" + zeroPad(seconds); - display->drawString(64 + x, 14 + y, time); -} - -void drawScreen3(OLEDDisplay *display, OLEDDisplayUiState* state, int16_t x, int16_t y) { - display->setTextAlignment(TEXT_ALIGN_CENTER); - display->setFont(ArialMT_Plain_16); - - display->drawString(64 + x, 0 + y, "Printing Time"); - //display->setTextAlignment(TEXT_ALIGN_LEFT); - display->setFont(ArialMT_Plain_24); - int val = printerClient.getProgressPrintTime().toInt(); - int hours = numberOfHours(val); - int minutes = numberOfMinutes(val); - int seconds = numberOfSeconds(val); - - String time = zeroPad(hours) + ":" + zeroPad(minutes) + ":" + zeroPad(seconds); - display->drawString(64 + x, 14 + y, time); -} - -void drawClock(OLEDDisplay *display, OLEDDisplayUiState* state, int16_t x, int16_t y) { - display->setTextAlignment(TEXT_ALIGN_CENTER); - - String displayTime = timeClient.getAmPmHours() + ":" + timeClient.getMinutes() + ":" + timeClient.getSeconds(); - if (IS_24HOUR) { - displayTime = timeClient.getHours() + ":" + timeClient.getMinutes() + ":" + timeClient.getSeconds(); - } - display->setFont(ArialMT_Plain_16); - display->drawString(64 + x, 0 + y, OctoPrintHostName); - display->setFont(ArialMT_Plain_24); - display->drawString(64 + x, 17 + y, displayTime); -} - -void drawWeather(OLEDDisplay *display, OLEDDisplayUiState* state, int16_t x, int16_t y) { - display->setTextAlignment(TEXT_ALIGN_LEFT); - display->setFont(ArialMT_Plain_24); - display->drawString(0 + x, 0 + y, weatherClient.getTempRounded(0) + getTempSymbol()); - display->setTextAlignment(TEXT_ALIGN_LEFT); - display->setFont(ArialMT_Plain_24); - - display->setFont(ArialMT_Plain_16); - display->drawString(0 + x, 24 + y, weatherClient.getCondition(0)); - display->setFont((const uint8_t*)Meteocons_Plain_42); - display->drawString(86 + x, 0 + y, weatherClient.getWeatherIcon(0)); -} - -String getTempSymbol() { - return getTempSymbol(false); -} - -String getTempSymbol(boolean forHTML) { - String rtnValue = "F"; - if (IS_METRIC) { - rtnValue = "C"; - } - if (forHTML) { - rtnValue = "°" + rtnValue; - } else { - rtnValue = "°" + rtnValue; - } - return rtnValue; -} - -String getSpeedSymbol() { - String rtnValue = "mph"; - if (IS_METRIC) { - rtnValue = "kph"; - } - return rtnValue; -} - -String zeroPad(int value) { - String rtnValue = String(value); - if (value < 10) { - rtnValue = "0" + rtnValue; - } - return rtnValue; -} - -void drawHeaderOverlay(OLEDDisplay *display, OLEDDisplayUiState* state) { - display->setColor(WHITE); - display->setFont(ArialMT_Plain_16); - String displayTime = timeClient.getAmPmHours() + ":" + timeClient.getMinutes(); - if (IS_24HOUR) { - displayTime = timeClient.getHours() + ":" + timeClient.getMinutes(); - } - display->setTextAlignment(TEXT_ALIGN_LEFT); - display->drawString(0, 48, displayTime); - - if (!IS_24HOUR) { - String ampm = timeClient.getAmPm(); - display->setFont(ArialMT_Plain_10); - display->drawString(39, 54, ampm); - } - - display->setFont(ArialMT_Plain_16); - display->setTextAlignment(TEXT_ALIGN_LEFT); - String percent = String(printerClient.getProgressCompletion()) + "%"; - display->drawString(64, 48, percent); - - // Draw indicator to show next update - int updatePos = (printerClient.getProgressCompletion().toFloat() / float(100)) * 128; - display->drawRect(0, 41, 128, 6); - display->drawHorizontalLine(0, 42, updatePos); - display->drawHorizontalLine(0, 43, updatePos); - display->drawHorizontalLine(0, 44, updatePos); - display->drawHorizontalLine(0, 45, updatePos); - - drawRssi(display); -} - -void drawClockHeaderOverlay(OLEDDisplay *display, OLEDDisplayUiState* state) { - display->setColor(WHITE); - display->setFont(ArialMT_Plain_16); - display->setTextAlignment(TEXT_ALIGN_LEFT); - if (!IS_24HOUR) { - display->drawString(0, 48, timeClient.getAmPm()); - display->setTextAlignment(TEXT_ALIGN_CENTER); - display->drawString(64, 48, "offline"); - } else { - display->drawString(0,48, "offline"); - } - display->setTextAlignment(TEXT_ALIGN_LEFT); - display->drawRect(0, 43, 128, 2); - - drawRssi(display); -} - -void drawRssi(OLEDDisplay *display) { - - - int8_t quality = getWifiQuality(); - for (int8_t i = 0; i < 4; i++) { - for (int8_t j = 0; j < 3 * (i + 2); j++) { - if (quality > i * 25 || j == 0) { - display->setPixel(114 + 4 * i, 63 - j); - } - } - } -} - -// converts the dBm to a range between 0 and 100% -int8_t getWifiQuality() { - int32_t dbm = WiFi.RSSI(); - if(dbm <= -100) { - return 0; - } else if(dbm >= -50) { - return 100; - } else { - return 2 * (dbm + 100); - } -} - - -void writeSettings() { - // Save decoded message to SPIFFS file for playback on power up. - File f = SPIFFS.open(CONFIG, "w"); - if (!f) { - Serial.println("File open failed!"); - } else { - Serial.println("Saving settings now..."); - f.println("UtcOffset=" + String(UtcOffset)); - f.println("octoKey=" + OctoPrintApiKey); - f.println("octoHost=" + OctoPrintHostName); - f.println("octoServer=" + OctoPrintServer); - f.println("octoPort=" + String(OctoPrintPort)); - f.println("octoUser=" + OctoAuthUser); - f.println("octoPass=" + OctoAuthPass); - f.println("refreshRate=" + String(minutesBetweenDataRefresh)); - f.println("themeColor=" + themeColor); - f.println("IS_BASIC_AUTH=" + String(IS_BASIC_AUTH)); - f.println("www_username=" + String(www_username)); - f.println("www_password=" + String(www_password)); - f.println("DISPLAYCLOCK=" + String(DISPLAYCLOCK)); - f.println("is24hour=" + String(IS_24HOUR)); - f.println("invertDisp=" + String(INVERT_DISPLAY)); - f.println("isWeather=" + String(DISPLAYWEATHER)); - f.println("weatherKey=" + WeatherApiKey); - f.println("CityID=" + String(CityIDs[0])); - f.println("isMetric=" + String(IS_METRIC)); - f.println("language=" + String(WeatherLanguage)); - } - f.close(); - readSettings(); - timeClient.setUtcOffset(UtcOffset); -} - -void readSettings() { - if (SPIFFS.exists(CONFIG) == false) { - Serial.println("Settings File does not yet exists."); - writeSettings(); - return; - } - File fr = SPIFFS.open(CONFIG, "r"); - String line; - while(fr.available()) { - line = fr.readStringUntil('\n'); - - if (line.indexOf("UtcOffset=") >= 0) { - UtcOffset = line.substring(line.lastIndexOf("UtcOffset=") + 10).toFloat(); - Serial.println("UtcOffset=" + String(UtcOffset)); - } - if (line.indexOf("octoKey=") >= 0) { - OctoPrintApiKey = line.substring(line.lastIndexOf("octoKey=") + 8); - OctoPrintApiKey.trim(); - Serial.println("OctoPrintApiKey=" + OctoPrintApiKey); - } - if (line.indexOf("octoHost=") >= 0) { - OctoPrintHostName = line.substring(line.lastIndexOf("octoHost=") + 9); - OctoPrintHostName.trim(); - Serial.println("OctoPrintHostName=" + OctoPrintHostName); - } - if (line.indexOf("octoServer=") >= 0) { - OctoPrintServer = line.substring(line.lastIndexOf("octoServer=") + 11); - OctoPrintServer.trim(); - Serial.println("OctoPrintServer=" + OctoPrintServer); - } - if (line.indexOf("octoPort=") >= 0) { - OctoPrintPort = line.substring(line.lastIndexOf("octoPort=") + 9).toInt(); - Serial.println("OctoPrintPort=" + String(OctoPrintPort)); - } - if (line.indexOf("octoUser=") >= 0) { - OctoAuthUser = line.substring(line.lastIndexOf("octoUser=") + 9); - OctoAuthUser.trim(); - Serial.println("OctoAuthUser=" + OctoAuthUser); - } - if (line.indexOf("octoPass=") >= 0) { - OctoAuthPass = line.substring(line.lastIndexOf("octoPass=") + 9); - OctoAuthPass.trim(); - Serial.println("OctoAuthPass=" + OctoAuthPass); - } - if (line.indexOf("refreshRate=") >= 0) { - minutesBetweenDataRefresh = line.substring(line.lastIndexOf("refreshRate=") + 12).toInt(); - Serial.println("minutesBetweenDataRefresh=" + String(minutesBetweenDataRefresh)); - } - if (line.indexOf("themeColor=") >= 0) { - themeColor = line.substring(line.lastIndexOf("themeColor=") + 11); - themeColor.trim(); - Serial.println("themeColor=" + themeColor); - } - if (line.indexOf("IS_BASIC_AUTH=") >= 0) { - IS_BASIC_AUTH = line.substring(line.lastIndexOf("IS_BASIC_AUTH=") + 14).toInt(); - Serial.println("IS_BASIC_AUTH=" + String(IS_BASIC_AUTH)); - } - if (line.indexOf("www_username=") >= 0) { - String temp = line.substring(line.lastIndexOf("www_username=") + 13); - temp.trim(); - temp.toCharArray(www_username, sizeof(temp)); - Serial.println("www_username=" + String(www_username)); - } - if (line.indexOf("www_password=") >= 0) { - String temp = line.substring(line.lastIndexOf("www_password=") + 13); - temp.trim(); - temp.toCharArray(www_password, sizeof(temp)); - Serial.println("www_password=" + String(www_password)); - } - if (line.indexOf("DISPLAYCLOCK=") >= 0) { - DISPLAYCLOCK = line.substring(line.lastIndexOf("DISPLAYCLOCK=") + 13).toInt(); - Serial.println("DISPLAYCLOCK=" + String(DISPLAYCLOCK)); - } - if (line.indexOf("is24hour=") >= 0) { - IS_24HOUR = line.substring(line.lastIndexOf("is24hour=") + 9).toInt(); - Serial.println("IS_24HOUR=" + String(IS_24HOUR)); - } - if(line.indexOf("invertDisp=") >= 0) { - INVERT_DISPLAY = line.substring(line.lastIndexOf("invertDisp=") + 11).toInt(); - Serial.println("INVERT_DISPLAY=" + String(INVERT_DISPLAY)); - } - if (line.indexOf("isWeather=") >= 0) { - DISPLAYWEATHER = line.substring(line.lastIndexOf("isWeather=") + 10).toInt(); - Serial.println("DISPLAYWEATHER=" + String(DISPLAYWEATHER)); - } - if (line.indexOf("weatherKey=") >= 0) { - WeatherApiKey = line.substring(line.lastIndexOf("weatherKey=") + 11); - WeatherApiKey.trim(); - Serial.println("WeatherApiKey=" + WeatherApiKey); - } - if (line.indexOf("CityID=") >= 0) { - CityIDs[0] = line.substring(line.lastIndexOf("CityID=") + 7).toInt(); - Serial.println("CityID: " + String(CityIDs[0])); - } - if (line.indexOf("isMetric=") >= 0) { - IS_METRIC = line.substring(line.lastIndexOf("isMetric=") + 9).toInt(); - Serial.println("IS_METRIC=" + String(IS_METRIC)); - } - if (line.indexOf("language=") >= 0) { - WeatherLanguage = line.substring(line.lastIndexOf("language=") + 9); - WeatherLanguage.trim(); - Serial.println("WeatherLanguage=" + WeatherLanguage); - } - } - fr.close(); - printerClient.updateOctoPrintClient(OctoPrintApiKey, OctoPrintServer, OctoPrintPort, OctoAuthUser, OctoAuthPass); - weatherClient.updateWeatherApiKey(WeatherApiKey); - weatherClient.updateLanguage(WeatherLanguage); - weatherClient.setMetric(IS_METRIC); - weatherClient.updateCityIdList(CityIDs, 1); - timeClient.setUtcOffset(UtcOffset); -} - -int getMinutesFromLastRefresh() { - int minutes = (timeClient.getCurrentEpoch() - lastEpoch) / 60; - return minutes; -} - -int getMinutesFromLastDisplay() { - int minutes = (timeClient.getCurrentEpoch() - displayOffEpoch) / 60; - return minutes; -} - -// Toggle on and off the display if user defined times -void checkDisplay() { - if (!displayOn && DISPLAYCLOCK) { - enableDisplay(true); - } - if (displayOn && !(printerClient.isOperational() || printerClient.isPrinting()) && !DISPLAYCLOCK) { - // Put Display to sleep - display.clear(); - display.display(); - display.setFont(ArialMT_Plain_16); - display.setTextAlignment(TEXT_ALIGN_CENTER); - display.setContrast(255); // default is 255 - display.drawString(64, 5, "Printer Offline\nSleep Mode..."); - display.display(); - delay(5000); - enableDisplay(false); - Serial.println("Printer is offline going down to sleep..."); - return; - } else if (!displayOn && !DISPLAYCLOCK) { - if (printerClient.isOperational()) { - // Wake the Screen up - enableDisplay(true); - display.clear(); - display.display(); - display.setFont(ArialMT_Plain_16); - display.setTextAlignment(TEXT_ALIGN_CENTER); - display.setContrast(255); // default is 255 - display.drawString(64, 5, "Printer Online\nWake up..."); - display.display(); - Serial.println("Printer is online waking up..."); - delay(5000); - return; - } - } else if (DISPLAYCLOCK) { - if (!printerClient.isOperational() && !isClockOn) { - Serial.println("Clock Mode is turned on."); - if (!DISPLAYWEATHER) { - ui.disableAutoTransition(); - ui.setFrames(clockFrame, 1); - clockFrame[0] = drawClock; - } else { - ui.enableAutoTransition(); - ui.setFrames(clockFrame, 2); - clockFrame[0] = drawClock; - clockFrame[1] = drawWeather; - } - ui.setOverlays(clockOverlay, numberOfOverlays); - isClockOn = true; - } else if (printerClient.isOperational() && isClockOn) { - Serial.println("Printer Monitor is active."); - ui.setFrames(frames, numberOfFrames); - ui.setOverlays(overlays, numberOfOverlays); - ui.enableAutoTransition(); - isClockOn = false; - } - } -} - -void enableDisplay(boolean enable) { - displayOn = enable; - if (enable) { - if (getMinutesFromLastDisplay() >= minutesBetweenDataRefresh) { - // The display has been off longer than the minutes between refresh -- need to get fresh data - lastEpoch = 0; // this should force a data pull - displayOffEpoch = 0; // reset - } - display.displayOn(); - Serial.println("Display was turned ON: " + timeClient.getFormattedTime()); - } else { - display.displayOff(); - Serial.println("Display was turned OFF: " + timeClient.getFormattedTime()); - displayOffEpoch = lastEpoch; - } +/** 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. +*/ + +// Additional Contributions: +/* 15 Jan 2019 : Owen Carter : Add psucontrol option and processing */ + + /********************************************** + * Edit Settings.h for personalization + ***********************************************/ + +#include "Settings.h" + +#define VERSION "2.4" + +#define HOSTNAME "OctMon-" +#define CONFIG "/conf.txt" + +/* Useful Constants */ +#define SECS_PER_MIN (60UL) +#define SECS_PER_HOUR (3600UL) + +/* Useful Macros for getting elapsed time */ +#define numberOfSeconds(_time_) (_time_ % SECS_PER_MIN) +#define numberOfMinutes(_time_) ((_time_ / SECS_PER_MIN) % SECS_PER_MIN) +#define numberOfHours(_time_) (_time_ / SECS_PER_HOUR) + +// Initialize the oled display for I2C_DISPLAY_ADDRESS +// SDA_PIN and SCL_PIN +#if defined(DISPLAY_SH1106) + SH1106Wire display(I2C_DISPLAY_ADDRESS, SDA_PIN, SCL_PIN); +#else + SSD1306Wire display(I2C_DISPLAY_ADDRESS, SDA_PIN, SCL_PIN); // this is the default +#endif + +OLEDDisplayUi ui( &display ); + +void drawProgress(OLEDDisplay *display, int percentage, String label); +void drawOtaProgress(unsigned int, unsigned int); +void drawScreen1(OLEDDisplay *display, OLEDDisplayUiState* state, int16_t x, int16_t y); +void drawScreen2(OLEDDisplay *display, OLEDDisplayUiState* state, int16_t x, int16_t y); +void drawScreen3(OLEDDisplay *display, OLEDDisplayUiState* state, int16_t x, int16_t y); +void drawHeaderOverlay(OLEDDisplay *display, OLEDDisplayUiState* state); +void drawClock(OLEDDisplay *display, OLEDDisplayUiState* state, int16_t x, int16_t y); +void drawWeather(OLEDDisplay *display, OLEDDisplayUiState* state, int16_t x, int16_t y); +void drawClockHeaderOverlay(OLEDDisplay *display, OLEDDisplayUiState* state); + +// Set the number of Frames supported +const int numberOfFrames = 3; +FrameCallback frames[numberOfFrames]; +FrameCallback clockFrame[2]; +boolean isClockOn = false; + +OverlayCallback overlays[] = { drawHeaderOverlay }; +OverlayCallback clockOverlay[] = { drawClockHeaderOverlay }; +int numberOfOverlays = 1; + +// Time +TimeClient timeClient(UtcOffset); +long lastEpoch = 0; +long firstEpoch = 0; +long displayOffEpoch = 0; +String lastMinute = "xx"; +String lastSecond = "xx"; +String lastReportStatus = ""; +boolean displayOn = true; + +// OctoPrint Client +OctoPrintClient printerClient(OctoPrintApiKey, OctoPrintServer, OctoPrintPort, OctoAuthUser, OctoAuthPass, HAS_PSU); +int printerCount = 0; + +// Weather Client +OpenWeatherMapClient weatherClient(WeatherApiKey, CityIDs, 1, IS_METRIC, WeatherLanguage); + +//declairing prototypes +void configModeCallback (WiFiManager *myWiFiManager); +int8_t getWifiQuality(); + +ESP8266WebServer server(WEBSERVER_PORT); +ESP8266HTTPUpdateServer serverUpdater; + +String WEB_ACTIONS = " Home" + " Configure" + " Weather" + " Reset Settings" + " Forget WiFi" + " Firmware Update" + " About"; + +String CHANGE_FORM = "

Station Config:

" + "

" + "

" + "

" + "

" + "

" + "


" + "

Display Clock when printer is off

" + "

Use 24 Hour Clock (military time)

" + "

Flip display orientation

" + "

Use OctoPrint PSU control plugin for clock/blank

" + "

Clock Sync / Weather Refresh (minutes)

"; + +String THEME_FORM = "

Theme Color

" + "


" + "

Use Security Credentials for Configuration Changes

" + "

" + "

" + "
"; + +String WEATHER_FORM = "

Weather Config:

" + "

Display Weather when printer is off

" + "" + "" + "

" + "

" + "

Use Metric (Celsius)

" + "

Weather Language

" + "
" + ""; + +String LANG_OPTIONS = "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + ""; + +String COLOR_THEMES = "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + ""; + + +void setup() { + Serial.begin(115200); + SPIFFS.begin(); + delay(10); + + //New Line to clear from start garbage + Serial.println(); + + // Initialize digital pin for LED (little blue light on the Wemos D1 Mini) + pinMode(externalLight, OUTPUT); + + readSettings(); + + // initialize display + display.init(); + if (INVERT_DISPLAY) { + display.flipScreenVertically(); // connections at top of OLED display + } + display.clear(); + display.display(); + + //display.flipScreenVertically(); + display.setFont(ArialMT_Plain_16); + display.setTextAlignment(TEXT_ALIGN_CENTER); + display.setContrast(255); // default is 255 + display.drawString(64, 5, "Printer Monitor\nBy Qrome\nV" + String(VERSION)); + display.display(); + + //WiFiManager + //Local intialization. Once its business is done, there is no need to keep it around + WiFiManager wifiManager; + + // Uncomment for testing wifi manager + //wifiManager.resetSettings(); + wifiManager.setAPCallback(configModeCallback); + + String hostname(HOSTNAME); + hostname += String(ESP.getChipId(), HEX); + if (!wifiManager.autoConnect((const char *)hostname.c_str())) {// new addition + delay(3000); + WiFi.disconnect(true); + ESP.reset(); + delay(5000); + } + + // You can change the transition that is used + // SLIDE_LEFT, SLIDE_RIGHT, SLIDE_TOP, SLIDE_DOWN + ui.setFrameAnimation(SLIDE_LEFT); + ui.setTargetFPS(30); + ui.disableAllIndicators(); + ui.setFrames(frames, (numberOfFrames)); + frames[0] = drawScreen1; + frames[1] = drawScreen2; + frames[2] = drawScreen3; + clockFrame[0] = drawClock; + clockFrame[1] = drawWeather; + ui.setOverlays(overlays, numberOfOverlays); + + // Inital UI takes care of initalising the display too. + ui.init(); + if (INVERT_DISPLAY) { + display.flipScreenVertically(); //connections at top of OLED display + } + + // print the received signal strength: + Serial.print("Signal Strength (RSSI): "); + Serial.print(getWifiQuality()); + Serial.println("%"); + + if (ENABLE_OTA) { + 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.setHostname((const char *)hostname.c_str()); + if (OTA_Password != "") { + ArduinoOTA.setPassword(((const char *)OTA_Password.c_str())); + } + ArduinoOTA.begin(); + } + + if (WEBSERVER_ENABLED) { + server.on("/", displayPrinterStatus); + server.on("/systemreset", handleSystemReset); + server.on("/forgetwifi", handleWifiReset); + server.on("/updateconfig", handleUpdateConfig); + server.on("/updateweatherconfig", handleUpdateWeather); + server.on("/configure", handleConfigure); + server.on("/configureweather", handleWeatherConfigure); + server.onNotFound(redirectHome); + serverUpdater.setup(&server, "/update", www_username, www_password); + // Start the server + server.begin(); + Serial.println("Server started"); + // Print the IP address + String webAddress = "http://" + WiFi.localIP().toString() + ":" + String(WEBSERVER_PORT) + "/"; + Serial.println("Use this URL : " + webAddress); + display.clear(); + display.setTextAlignment(TEXT_ALIGN_CENTER); + display.setFont(ArialMT_Plain_10); + display.drawString(64, 10, "Web Interface On"); + display.drawString(64, 20, "You May Connect to IP"); + display.setFont(ArialMT_Plain_16); + display.drawString(64, 30, WiFi.localIP().toString()); + display.drawString(64, 46, "Port: " + String(WEBSERVER_PORT)); + display.display(); + } else { + Serial.println("Web Interface is Disabled"); + display.clear(); + display.setTextAlignment(TEXT_ALIGN_CENTER); + display.setFont(ArialMT_Plain_10); + display.drawString(64, 10, "Web Interface is Off"); + display.drawString(64, 20, "Enable in Settings.h"); + display.display(); + } + flashLED(5, 500); + findMDNS(); //go find Octoprint Server by the hostname + Serial.println("*** Leaving setup()"); +} + +void findMDNS() { + if (OctoPrintHostName == "" || ENABLE_OTA == false) { + return; // nothing to do here + } + // We now query our network for 'web servers' service + // over tcp, and get the number of available devices + int n = MDNS.queryService("http", "tcp"); + if (n == 0) { + Serial.println("no services found - make sure OctoPrint server is turned on"); + return; + } + Serial.println("*** Looking for " + OctoPrintHostName + " over mDNS"); + for (int i = 0; i < n; ++i) { + // Going through every available service, + // we're searching for the one whose hostname + // matches what we want, and then get its IP + Serial.println("Found: " + MDNS.hostname(i)); + if (MDNS.hostname(i) == OctoPrintHostName) { + IPAddress serverIp = MDNS.IP(i); + OctoPrintServer = serverIp.toString(); + OctoPrintPort = MDNS.port(i); // save the port + Serial.println("*** Found OctoPrint Server " + OctoPrintHostName + " http://" + OctoPrintServer + ":" + OctoPrintPort); + writeSettings(); // update the settings + } + } +} + +//************************************************************ +// Main Looop +//************************************************************ +void loop() { + + //Get Time Update + if((getMinutesFromLastRefresh() >= minutesBetweenDataRefresh) || lastEpoch == 0) { + getUpdateTime(); + } + + if (lastMinute != timeClient.getMinutes() && !printerClient.isPrinting()) { + // Check status every 60 seconds + digitalWrite(externalLight, LOW); + lastMinute = timeClient.getMinutes(); // reset the check value + printerClient.getPrinterJobResults(); + printerClient.getPrinterPsuState(); + digitalWrite(externalLight, HIGH); + } else if (printerClient.isPrinting()) { + if (lastSecond != timeClient.getSeconds() && timeClient.getSeconds().endsWith("0")) { + lastSecond = timeClient.getSeconds(); + // every 10 seconds while printing get an update + digitalWrite(externalLight, LOW); + printerClient.getPrinterJobResults(); + printerClient.getPrinterPsuState(); + digitalWrite(externalLight, HIGH); + } + } + + checkDisplay(); // Check to see if the printer is on or offline and change display. + + ui.update(); + + if (WEBSERVER_ENABLED) { + server.handleClient(); + } + if (ENABLE_OTA) { + ArduinoOTA.handle(); + } +} + +void getUpdateTime() { + digitalWrite(externalLight, LOW); // turn on the LED + Serial.println(); + + if (displayOn && DISPLAYWEATHER) { + Serial.println("Getting Weather Data..."); + weatherClient.updateWeather(); + } + + Serial.println("Updating Time..."); + //Update the Time + timeClient.updateTime(); + lastEpoch = timeClient.getCurrentEpoch(); + Serial.println("Local time: " + timeClient.getAmPmFormattedTime()); + + digitalWrite(externalLight, HIGH); // turn off the LED +} + +boolean authentication() { + if (IS_BASIC_AUTH && (strlen(www_username) >= 1 && strlen(www_password) >= 1)) { + return server.authenticate(www_username, www_password); + } + return true; // Authentication not required +} + +void handleSystemReset() { + if (!authentication()) { + return server.requestAuthentication(); + } + Serial.println("Reset System Configuration"); + if (SPIFFS.remove(CONFIG)) { + redirectHome(); + ESP.restart(); + } +} + +void handleUpdateWeather() { + if (!authentication()) { + return server.requestAuthentication(); + } + DISPLAYWEATHER = server.hasArg("isWeatherEnabled"); + WeatherApiKey = server.arg("openWeatherMapApiKey"); + CityIDs[0] = server.arg("city1").toInt(); + IS_METRIC = server.hasArg("metric"); + WeatherLanguage = server.arg("language"); + writeSettings(); + isClockOn = false; // this will force a check for the display + checkDisplay(); + lastEpoch = 0; + redirectHome(); +} + +void handleUpdateConfig() { + boolean flipOld = INVERT_DISPLAY; + if (!authentication()) { + return server.requestAuthentication(); + } + OctoPrintApiKey = server.arg("octoPrintApiKey"); + OctoPrintHostName = server.arg("octoPrintHostName"); + OctoPrintServer = server.arg("octoPrintAddress"); + OctoPrintPort = server.arg("octoPrintPort").toInt(); + OctoAuthUser = server.arg("octoUser"); + OctoAuthPass = server.arg("octoPass"); + DISPLAYCLOCK = server.hasArg("isClockEnabled"); + IS_24HOUR = server.hasArg("is24hour"); + INVERT_DISPLAY = server.hasArg("invDisp"); + HAS_PSU = server.hasArg("hasPSU"); + minutesBetweenDataRefresh = server.arg("refresh").toInt(); + themeColor = server.arg("theme"); + UtcOffset = server.arg("utcoffset").toFloat(); + String temp = server.arg("userid"); + temp.toCharArray(www_username, sizeof(temp)); + temp = server.arg("stationpassword"); + temp.toCharArray(www_password, sizeof(temp)); + writeSettings(); + findMDNS(); + printerClient.getPrinterJobResults(); + printerClient.getPrinterPsuState(); + if (INVERT_DISPLAY != flipOld) { + ui.init(); + if(INVERT_DISPLAY) + display.flipScreenVertically(); + ui.update(); + } + checkDisplay(); + lastEpoch = 0; + redirectHome(); +} + +void handleWifiReset() { + if (!authentication()) { + return server.requestAuthentication(); + } + //WiFiManager + //Local intialization. Once its business is done, there is no need to keep it around + redirectHome(); + WiFiManager wifiManager; + wifiManager.resetSettings(); + ESP.restart(); +} + +void handleWeatherConfigure() { + if (!authentication()) { + 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", ""); + + html = getHeader(); + server.sendContent(html); + + String form = WEATHER_FORM; + String isWeatherChecked = ""; + if (DISPLAYWEATHER) { + isWeatherChecked = "checked='checked'"; + } + form.replace("%IS_WEATHER_CHECKED%", isWeatherChecked); + form.replace("%WEATHERKEY%", WeatherApiKey); + form.replace("%CITYNAME1%", weatherClient.getCity(0)); + form.replace("%CITY1%", String(CityIDs[0])); + String checked = ""; + if (IS_METRIC) { + checked = "checked='checked'"; + } + form.replace("%METRIC%", checked); + String options = LANG_OPTIONS; + options.replace(">"+String(WeatherLanguage)+"<", " selected>"+String(WeatherLanguage)+"<"); + form.replace("%LANGUAGEOPTIONS%", options); + server.sendContent(form); + + html = getFooter(); + server.sendContent(html); + server.sendContent(""); + server.client().stop(); + digitalWrite(externalLight, HIGH); +} + +void handleConfigure() { + if (!authentication()) { + 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", ""); + + html = getHeader(); + server.sendContent(html); + + String form = CHANGE_FORM; + + form.replace("%OCTOKEY%", OctoPrintApiKey); + form.replace("%OCTOHOST%", OctoPrintHostName); + form.replace("%OCTOADDRESS%", OctoPrintServer); + form.replace("%OCTOPORT%", String(OctoPrintPort)); + form.replace("%OCTOUSER%", OctoAuthUser); + form.replace("%OCTOPASS%", OctoAuthPass); + String isClockChecked = ""; + if (DISPLAYCLOCK) { + isClockChecked = "checked='checked'"; + } + form.replace("%IS_CLOCK_CHECKED%", isClockChecked); + String is24hourChecked = ""; + if (IS_24HOUR) { + is24hourChecked = "checked='checked'"; + } + form.replace("%IS_24HOUR_CHECKED%", is24hourChecked); + String isInvDisp = ""; + if (INVERT_DISPLAY) { + isInvDisp = "checked='checked'"; + } + form.replace("%IS_INVDISP_CHECKED%", isInvDisp); + String hasPSUchecked = ""; + if (HAS_PSU) { + hasPSUchecked = "checked='checked'"; + } + form.replace("%HAS_PSU_CHECKED%", hasPSUchecked); + + String options = ""; + options.replace(">"+String(minutesBetweenDataRefresh)+"<", " selected>"+String(minutesBetweenDataRefresh)+"<"); + form.replace("%OPTIONS%", options); + + server.sendContent(form); + + form = THEME_FORM; + + String themeOptions = COLOR_THEMES; + themeOptions.replace(">"+String(themeColor)+"<", " selected>"+String(themeColor)+"<"); + form.replace("%THEME_OPTIONS%", themeOptions); + form.replace("%UTCOFFSET%", String(UtcOffset)); + String isUseSecurityChecked = ""; + if (IS_BASIC_AUTH) { + isUseSecurityChecked = "checked='checked'"; + } + form.replace("%IS_BASICAUTH_CHECKED%", isUseSecurityChecked); + form.replace("%USERID%", String(www_username)); + form.replace("%STATIONPASSWORD%", String(www_password)); + + server.sendContent(form); + + html = getFooter(); + server.sendContent(html); + server.sendContent(""); + server.client().stop(); + digitalWrite(externalLight, HIGH); +} + +void displayMessage(String message) { + digitalWrite(externalLight, LOW); + + 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", ""); + String html = getHeader(); + server.sendContent(String(html)); + server.sendContent(String(message)); + html = getFooter(); + server.sendContent(String(html)); + server.sendContent(""); + server.client().stop(); + + digitalWrite(externalLight, HIGH); +} + +void redirectHome() { + // Send them back to the Root Directory + server.sendHeader("Location", String("/"), true); + server.sendHeader("Cache-Control", "no-cache, no-store"); + server.sendHeader("Pragma", "no-cache"); + server.sendHeader("Expires", "-1"); + server.send(302, "text/plain", ""); + server.client().stop(); +} + +String getHeader() { + return getHeader(false); +} + +String getHeader(boolean refresh) { + String menu = WEB_ACTIONS; + + String html = ""; + html += "Printer Monitor"; + html += ""; + html += ""; + if (refresh) { + html += ""; + } + html += ""; + html += ""; + html += ""; + html += ""; + html += ""; + html += "

Printer Monitor

"; + html += ""; + html += "
"; + return html; +} + +String getFooter() { + int8_t rssi = getWifiQuality(); + Serial.print("Signal Strength (RSSI): "); + Serial.print(rssi); + Serial.println("%"); + String html = "


"; + html += "
"; + html += "
"; + if (lastReportStatus != "") { + html += " Report Status: " + lastReportStatus + "
"; + } + html += " Version: " + String(VERSION) + "
"; + html += " Signal Strength: "; + html += String(rssi) + "%"; + html += "
"; + html += ""; + return html; +} + +void displayPrinterStatus() { + 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", ""); + server.sendContent(String(getHeader(true))); + + String displayTime = timeClient.getAmPmHours() + ":" + timeClient.getMinutes() + ":" + timeClient.getSeconds() + " " + timeClient.getAmPm(); + if (IS_24HOUR) { + displayTime = timeClient.getHours() + ":" + timeClient.getMinutes() + ":" + timeClient.getSeconds(); + } + + html += "

Time: " + displayTime + "

"; + html += "

"; + html += "Host Name: " + OctoPrintHostName + "
"; + if (printerClient.getError() != "") { + html += "Status: Offline
"; + html += "Reason: " + printerClient.getError() + "
"; + } else { + html += "Status: " + printerClient.getState(); + if (printerClient.isPSUoff() && HAS_PSU) { + html += ", PSU off"; + } + html += "
"; + } + + if (printerClient.isPrinting()) { + html += "File: " + printerClient.getFileName() + "
"; + float fileSize = printerClient.getFileSize().toFloat(); + if (fileSize > 0) { + fileSize = fileSize / 1024; + html += "File Size: " + String(fileSize) + "KB
"; + } + int filamentLength = printerClient.getFilamentLength().toInt(); + if (filamentLength > 0) { + float fLength = float(filamentLength) / 1000; + html += "Filament: " + String(fLength) + "m
"; + } + + html += "Tool Temperature: " + printerClient.getTempToolActual() + "° C
"; + html += "Bed Temperature: " + printerClient.getTempBedActual() + "° C
"; + + int val = printerClient.getProgressPrintTimeLeft().toInt(); + int hours = numberOfHours(val); + int minutes = numberOfMinutes(val); + int seconds = numberOfSeconds(val); + html += "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 += ""; + html += "

" + printerClient.getProgressCompletion() + "%
"; + } else { + html += "
"; + } + + html += "

"; + + server.sendContent(html); // spit out what we got + html = ""; + + if (DISPLAYWEATHER) { + if (weatherClient.getCity(0) == "") { + html += "

Please Configure Weather API

"; + if (weatherClient.getError() != "") { + html += "

Weather Error: " + weatherClient.getError() + "

"; + } + } else { + html += "

" + weatherClient.getCity(0) + ", " + weatherClient.getCountry(0) + "

"; + html += "
"; + html += "" + weatherClient.getDescription(0) + "
"; + html += weatherClient.getHumidity(0) + "% Humidity
"; + html += weatherClient.getWind(0) + " " + getSpeedSymbol() + " Wind
"; + html += "
"; + html += "

"; + html += weatherClient.getCondition(0) + " (" + weatherClient.getDescription(0) + ")
"; + html += weatherClient.getTempRounded(0) + getTempSymbol(true) + "
"; + html += " Map It!
"; + html += "

"; + } + + server.sendContent(html); // spit out what we got + html = ""; // fresh start + } + + server.sendContent(String(getFooter())); + server.sendContent(""); + server.client().stop(); + digitalWrite(externalLight, HIGH); +} + +void configModeCallback (WiFiManager *myWiFiManager) { + Serial.println("Entered config mode"); + Serial.println(WiFi.softAPIP()); + + display.clear(); + display.setTextAlignment(TEXT_ALIGN_CENTER); + display.setFont(ArialMT_Plain_10); + display.drawString(64, 0, "Wifi Manager"); + display.drawString(64, 10, "Please connect to AP"); + display.setFont(ArialMT_Plain_16); + display.drawString(64, 23, myWiFiManager->getConfigPortalSSID()); + display.setFont(ArialMT_Plain_10); + display.drawString(64, 42, "To setup Wifi connection"); + display.display(); + + Serial.println("Wifi Manager"); + Serial.println("Please connect to AP"); + Serial.println(myWiFiManager->getConfigPortalSSID()); + Serial.println("To setup Wifi Configuration"); + flashLED(20, 50); +} + +void flashLED(int number, int delayTime) { + for (int inx = 0; inx < number; inx++) { + delay(delayTime); + digitalWrite(externalLight, LOW); + delay(delayTime); + digitalWrite(externalLight, HIGH); + delay(delayTime); + } +} + +void drawScreen1(OLEDDisplay *display, OLEDDisplayUiState* state, int16_t x, int16_t y) { + display->setTextAlignment(TEXT_ALIGN_CENTER); + display->setFont(ArialMT_Plain_16); + display->drawString(64 + x, 0 + y, "Bed / Tool Temp"); + display->setTextAlignment(TEXT_ALIGN_LEFT); + display->setFont(ArialMT_Plain_24); + String bed = printerClient.getValueRounded(printerClient.getTempBedActual()); + String tool = printerClient.getValueRounded(printerClient.getTempToolActual()); + display->drawString(2 + x, 14 + y, bed + "°"); + display->drawString(64 + x, 14 + y, tool + "°"); +} + +void drawScreen2(OLEDDisplay *display, OLEDDisplayUiState* state, int16_t x, int16_t y) { + display->setTextAlignment(TEXT_ALIGN_CENTER); + display->setFont(ArialMT_Plain_16); + + display->drawString(64 + x, 0 + y, "Time Remaining"); + //display->setTextAlignment(TEXT_ALIGN_LEFT); + display->setFont(ArialMT_Plain_24); + int val = printerClient.getProgressPrintTimeLeft().toInt(); + int hours = numberOfHours(val); + int minutes = numberOfMinutes(val); + int seconds = numberOfSeconds(val); + + String time = zeroPad(hours) + ":" + zeroPad(minutes) + ":" + zeroPad(seconds); + display->drawString(64 + x, 14 + y, time); +} + +void drawScreen3(OLEDDisplay *display, OLEDDisplayUiState* state, int16_t x, int16_t y) { + display->setTextAlignment(TEXT_ALIGN_CENTER); + display->setFont(ArialMT_Plain_16); + + display->drawString(64 + x, 0 + y, "Printing Time"); + //display->setTextAlignment(TEXT_ALIGN_LEFT); + display->setFont(ArialMT_Plain_24); + int val = printerClient.getProgressPrintTime().toInt(); + int hours = numberOfHours(val); + int minutes = numberOfMinutes(val); + int seconds = numberOfSeconds(val); + + String time = zeroPad(hours) + ":" + zeroPad(minutes) + ":" + zeroPad(seconds); + display->drawString(64 + x, 14 + y, time); +} + +void drawClock(OLEDDisplay *display, OLEDDisplayUiState* state, int16_t x, int16_t y) { + display->setTextAlignment(TEXT_ALIGN_CENTER); + + String displayTime = timeClient.getAmPmHours() + ":" + timeClient.getMinutes() + ":" + timeClient.getSeconds(); + if (IS_24HOUR) { + displayTime = timeClient.getHours() + ":" + timeClient.getMinutes() + ":" + timeClient.getSeconds(); + } + display->setFont(ArialMT_Plain_16); + display->drawString(64 + x, 0 + y, OctoPrintHostName); + display->setFont(ArialMT_Plain_24); + display->drawString(64 + x, 17 + y, displayTime); +} + +void drawWeather(OLEDDisplay *display, OLEDDisplayUiState* state, int16_t x, int16_t y) { + display->setTextAlignment(TEXT_ALIGN_LEFT); + display->setFont(ArialMT_Plain_24); + display->drawString(0 + x, 0 + y, weatherClient.getTempRounded(0) + getTempSymbol()); + display->setTextAlignment(TEXT_ALIGN_LEFT); + display->setFont(ArialMT_Plain_24); + + display->setFont(ArialMT_Plain_16); + display->drawString(0 + x, 24 + y, weatherClient.getCondition(0)); + display->setFont((const uint8_t*)Meteocons_Plain_42); + display->drawString(86 + x, 0 + y, weatherClient.getWeatherIcon(0)); +} + +String getTempSymbol() { + return getTempSymbol(false); +} + +String getTempSymbol(boolean forHTML) { + String rtnValue = "F"; + if (IS_METRIC) { + rtnValue = "C"; + } + if (forHTML) { + rtnValue = "°" + rtnValue; + } else { + rtnValue = "°" + rtnValue; + } + return rtnValue; +} + +String getSpeedSymbol() { + String rtnValue = "mph"; + if (IS_METRIC) { + rtnValue = "kph"; + } + return rtnValue; +} + +String zeroPad(int value) { + String rtnValue = String(value); + if (value < 10) { + rtnValue = "0" + rtnValue; + } + return rtnValue; +} + +void drawHeaderOverlay(OLEDDisplay *display, OLEDDisplayUiState* state) { + display->setColor(WHITE); + display->setFont(ArialMT_Plain_16); + String displayTime = timeClient.getAmPmHours() + ":" + timeClient.getMinutes(); + if (IS_24HOUR) { + displayTime = timeClient.getHours() + ":" + timeClient.getMinutes(); + } + display->setTextAlignment(TEXT_ALIGN_LEFT); + display->drawString(0, 48, displayTime); + + if (!IS_24HOUR) { + String ampm = timeClient.getAmPm(); + display->setFont(ArialMT_Plain_10); + display->drawString(39, 54, ampm); + } + + display->setFont(ArialMT_Plain_16); + display->setTextAlignment(TEXT_ALIGN_LEFT); + String percent = String(printerClient.getProgressCompletion()) + "%"; + display->drawString(64, 48, percent); + + // Draw indicator to show next update + int updatePos = (printerClient.getProgressCompletion().toFloat() / float(100)) * 128; + display->drawRect(0, 41, 128, 6); + display->drawHorizontalLine(0, 42, updatePos); + display->drawHorizontalLine(0, 43, updatePos); + display->drawHorizontalLine(0, 44, updatePos); + display->drawHorizontalLine(0, 45, updatePos); + + drawRssi(display); +} + +void drawClockHeaderOverlay(OLEDDisplay *display, OLEDDisplayUiState* state) { + display->setColor(WHITE); + display->setFont(ArialMT_Plain_16); + display->setTextAlignment(TEXT_ALIGN_LEFT); + if (!IS_24HOUR) { + display->drawString(0, 48, timeClient.getAmPm()); + display->setTextAlignment(TEXT_ALIGN_CENTER); + if (printerClient.isPSUoff()) { + display->drawString(64, 47, "psu off"); + } else { + display->drawString(64, 47, "offline"); + } + } else { + if (printerClient.isPSUoff()) { + display->drawString(0, 47, "psu off"); + } else { + display->drawString(0, 47, "offline"); + } + } + display->setTextAlignment(TEXT_ALIGN_LEFT); + display->drawRect(0, 43, 128, 2); + + drawRssi(display); +} + +void drawRssi(OLEDDisplay *display) { + + + int8_t quality = getWifiQuality(); + for (int8_t i = 0; i < 4; i++) { + for (int8_t j = 0; j < 3 * (i + 2); j++) { + if (quality > i * 25 || j == 0) { + display->setPixel(114 + 4 * i, 63 - j); + } + } + } +} + +// converts the dBm to a range between 0 and 100% +int8_t getWifiQuality() { + int32_t dbm = WiFi.RSSI(); + if(dbm <= -100) { + return 0; + } else if(dbm >= -50) { + return 100; + } else { + return 2 * (dbm + 100); + } +} + + +void writeSettings() { + // Save decoded message to SPIFFS file for playback on power up. + File f = SPIFFS.open(CONFIG, "w"); + if (!f) { + Serial.println("File open failed!"); + } else { + Serial.println("Saving settings now..."); + f.println("UtcOffset=" + String(UtcOffset)); + f.println("octoKey=" + OctoPrintApiKey); + f.println("octoHost=" + OctoPrintHostName); + f.println("octoServer=" + OctoPrintServer); + f.println("octoPort=" + String(OctoPrintPort)); + f.println("octoUser=" + OctoAuthUser); + f.println("octoPass=" + OctoAuthPass); + f.println("refreshRate=" + String(minutesBetweenDataRefresh)); + f.println("themeColor=" + themeColor); + f.println("IS_BASIC_AUTH=" + String(IS_BASIC_AUTH)); + f.println("www_username=" + String(www_username)); + f.println("www_password=" + String(www_password)); + f.println("DISPLAYCLOCK=" + String(DISPLAYCLOCK)); + f.println("is24hour=" + String(IS_24HOUR)); + f.println("invertDisp=" + String(INVERT_DISPLAY)); + f.println("isWeather=" + String(DISPLAYWEATHER)); + f.println("weatherKey=" + WeatherApiKey); + f.println("CityID=" + String(CityIDs[0])); + f.println("isMetric=" + String(IS_METRIC)); + f.println("language=" + String(WeatherLanguage)); + f.println("hasPSU=" + String(HAS_PSU)); + } + f.close(); + readSettings(); + timeClient.setUtcOffset(UtcOffset); +} + +void readSettings() { + if (SPIFFS.exists(CONFIG) == false) { + Serial.println("Settings File does not yet exists."); + writeSettings(); + return; + } + File fr = SPIFFS.open(CONFIG, "r"); + String line; + while(fr.available()) { + line = fr.readStringUntil('\n'); + + if (line.indexOf("UtcOffset=") >= 0) { + UtcOffset = line.substring(line.lastIndexOf("UtcOffset=") + 10).toFloat(); + Serial.println("UtcOffset=" + String(UtcOffset)); + } + if (line.indexOf("octoKey=") >= 0) { + OctoPrintApiKey = line.substring(line.lastIndexOf("octoKey=") + 8); + OctoPrintApiKey.trim(); + Serial.println("OctoPrintApiKey=" + OctoPrintApiKey); + } + if (line.indexOf("octoHost=") >= 0) { + OctoPrintHostName = line.substring(line.lastIndexOf("octoHost=") + 9); + OctoPrintHostName.trim(); + Serial.println("OctoPrintHostName=" + OctoPrintHostName); + } + if (line.indexOf("octoServer=") >= 0) { + OctoPrintServer = line.substring(line.lastIndexOf("octoServer=") + 11); + OctoPrintServer.trim(); + Serial.println("OctoPrintServer=" + OctoPrintServer); + } + if (line.indexOf("octoPort=") >= 0) { + OctoPrintPort = line.substring(line.lastIndexOf("octoPort=") + 9).toInt(); + Serial.println("OctoPrintPort=" + String(OctoPrintPort)); + } + if (line.indexOf("octoUser=") >= 0) { + OctoAuthUser = line.substring(line.lastIndexOf("octoUser=") + 9); + OctoAuthUser.trim(); + Serial.println("OctoAuthUser=" + OctoAuthUser); + } + if (line.indexOf("octoPass=") >= 0) { + OctoAuthPass = line.substring(line.lastIndexOf("octoPass=") + 9); + OctoAuthPass.trim(); + Serial.println("OctoAuthPass=" + OctoAuthPass); + } + if (line.indexOf("refreshRate=") >= 0) { + minutesBetweenDataRefresh = line.substring(line.lastIndexOf("refreshRate=") + 12).toInt(); + Serial.println("minutesBetweenDataRefresh=" + String(minutesBetweenDataRefresh)); + } + if (line.indexOf("themeColor=") >= 0) { + themeColor = line.substring(line.lastIndexOf("themeColor=") + 11); + themeColor.trim(); + Serial.println("themeColor=" + themeColor); + } + if (line.indexOf("IS_BASIC_AUTH=") >= 0) { + IS_BASIC_AUTH = line.substring(line.lastIndexOf("IS_BASIC_AUTH=") + 14).toInt(); + Serial.println("IS_BASIC_AUTH=" + String(IS_BASIC_AUTH)); + } + if (line.indexOf("www_username=") >= 0) { + String temp = line.substring(line.lastIndexOf("www_username=") + 13); + temp.trim(); + temp.toCharArray(www_username, sizeof(temp)); + Serial.println("www_username=" + String(www_username)); + } + if (line.indexOf("www_password=") >= 0) { + String temp = line.substring(line.lastIndexOf("www_password=") + 13); + temp.trim(); + temp.toCharArray(www_password, sizeof(temp)); + Serial.println("www_password=" + String(www_password)); + } + if (line.indexOf("DISPLAYCLOCK=") >= 0) { + DISPLAYCLOCK = line.substring(line.lastIndexOf("DISPLAYCLOCK=") + 13).toInt(); + Serial.println("DISPLAYCLOCK=" + String(DISPLAYCLOCK)); + } + if (line.indexOf("is24hour=") >= 0) { + IS_24HOUR = line.substring(line.lastIndexOf("is24hour=") + 9).toInt(); + Serial.println("IS_24HOUR=" + String(IS_24HOUR)); + } + if(line.indexOf("invertDisp=") >= 0) { + INVERT_DISPLAY = line.substring(line.lastIndexOf("invertDisp=") + 11).toInt(); + Serial.println("INVERT_DISPLAY=" + String(INVERT_DISPLAY)); + } + if (line.indexOf("hasPSU=") >= 0) { + HAS_PSU = line.substring(line.lastIndexOf("hasPSU=") + 7).toInt(); + Serial.println("HAS_PSU=" + String(HAS_PSU)); + } + if (line.indexOf("isWeather=") >= 0) { + DISPLAYWEATHER = line.substring(line.lastIndexOf("isWeather=") + 10).toInt(); + Serial.println("DISPLAYWEATHER=" + String(DISPLAYWEATHER)); + } + if (line.indexOf("weatherKey=") >= 0) { + WeatherApiKey = line.substring(line.lastIndexOf("weatherKey=") + 11); + WeatherApiKey.trim(); + Serial.println("WeatherApiKey=" + WeatherApiKey); + } + if (line.indexOf("CityID=") >= 0) { + CityIDs[0] = line.substring(line.lastIndexOf("CityID=") + 7).toInt(); + Serial.println("CityID: " + String(CityIDs[0])); + } + if (line.indexOf("isMetric=") >= 0) { + IS_METRIC = line.substring(line.lastIndexOf("isMetric=") + 9).toInt(); + Serial.println("IS_METRIC=" + String(IS_METRIC)); + } + if (line.indexOf("language=") >= 0) { + WeatherLanguage = line.substring(line.lastIndexOf("language=") + 9); + WeatherLanguage.trim(); + Serial.println("WeatherLanguage=" + WeatherLanguage); + } + } + fr.close(); + printerClient.updateOctoPrintClient(OctoPrintApiKey, OctoPrintServer, OctoPrintPort, OctoAuthUser, OctoAuthPass, HAS_PSU); + weatherClient.updateWeatherApiKey(WeatherApiKey); + weatherClient.updateLanguage(WeatherLanguage); + weatherClient.setMetric(IS_METRIC); + weatherClient.updateCityIdList(CityIDs, 1); + timeClient.setUtcOffset(UtcOffset); +} + +int getMinutesFromLastRefresh() { + int minutes = (timeClient.getCurrentEpoch() - lastEpoch) / 60; + return minutes; +} + +int getMinutesFromLastDisplay() { + int minutes = (timeClient.getCurrentEpoch() - displayOffEpoch) / 60; + return minutes; +} + +// Toggle on and off the display if user defined times +void checkDisplay() { + if (!displayOn && DISPLAYCLOCK) { + enableDisplay(true); + } + if (displayOn && !(printerClient.isOperational() || printerClient.isPrinting()) && !DISPLAYCLOCK) { + // Put Display to sleep + display.clear(); + display.display(); + display.setFont(ArialMT_Plain_16); + display.setTextAlignment(TEXT_ALIGN_CENTER); + display.setContrast(255); // default is 255 + display.drawString(64, 5, "Printer Offline\nSleep Mode..."); + display.display(); + delay(5000); + enableDisplay(false); + Serial.println("Printer is offline going down to sleep..."); + return; + } else if (!displayOn && !DISPLAYCLOCK) { + if (printerClient.isOperational()) { + // Wake the Screen up + enableDisplay(true); + display.clear(); + display.display(); + display.setFont(ArialMT_Plain_16); + display.setTextAlignment(TEXT_ALIGN_CENTER); + display.setContrast(255); // default is 255 + display.drawString(64, 5, "Printer Online\nWake up..."); + display.display(); + Serial.println("Printer is online waking up..."); + delay(5000); + return; + } + } else if (DISPLAYCLOCK) { + if ((!printerClient.isOperational() || printerClient.isPSUoff()) && !isClockOn) { + Serial.println("Clock Mode is turned on."); + if (!DISPLAYWEATHER) { + ui.disableAutoTransition(); + ui.setFrames(clockFrame, 1); + clockFrame[0] = drawClock; + } else { + ui.enableAutoTransition(); + ui.setFrames(clockFrame, 2); + clockFrame[0] = drawClock; + clockFrame[1] = drawWeather; + } + ui.setOverlays(clockOverlay, numberOfOverlays); + isClockOn = true; + } else if (printerClient.isOperational() && !printerClient.isPSUoff() && isClockOn) { + Serial.println("Printer Monitor is active."); + ui.setFrames(frames, numberOfFrames); + ui.setOverlays(overlays, numberOfOverlays); + ui.enableAutoTransition(); + isClockOn = false; + } + } +} + +void enableDisplay(boolean enable) { + displayOn = enable; + if (enable) { + if (getMinutesFromLastDisplay() >= minutesBetweenDataRefresh) { + // The display has been off longer than the minutes between refresh -- need to get fresh data + lastEpoch = 0; // this should force a data pull + displayOffEpoch = 0; // reset + } + display.displayOn(); + Serial.println("Display was turned ON: " + timeClient.getFormattedTime()); + } else { + display.displayOff(); + Serial.println("Display was turned OFF: " + timeClient.getFormattedTime()); + displayOffEpoch = lastEpoch; + } }