diff --git a/src/Clients/BasePrinterClient.h b/src/Clients/BasePrinterClient.h index 4985ff5..82b8456 100644 --- a/src/Clients/BasePrinterClient.h +++ b/src/Clients/BasePrinterClient.h @@ -5,6 +5,13 @@ #include "Debug.h" #include "../Network/JsonRequestClient.h" +#define PRINTER_STATE_OFFLINE (int)-2 +#define PRINTER_STATE_ERROR (int)-1 +#define PRINTER_STATE_STANDBY (int)0 +#define PRINTER_STATE_PRINTING (int)1 +#define PRINTER_STATE_PAUSED (int)2 +#define PRINTER_STATE_COMPLETED (int)3 + class BasePrinterClient { public: virtual void getPrinterJobResults(); @@ -20,7 +27,8 @@ public: virtual String getProgressFilepos() = 0; virtual String getProgressPrintTime() = 0; virtual String getProgressPrintTimeLeft() = 0; - virtual String getState() = 0; + virtual int getState() = 0; + virtual String getStateAsText() = 0; virtual boolean isPrinting() = 0; virtual boolean isOperational() = 0; virtual boolean isPSUoff() = 0; diff --git a/src/Clients/BasePrinterClientImpl.cpp b/src/Clients/BasePrinterClientImpl.cpp index 441e2bf..ac4cb32 100644 --- a/src/Clients/BasePrinterClientImpl.cpp +++ b/src/Clients/BasePrinterClientImpl.cpp @@ -23,7 +23,7 @@ void BasePrinterClientImpl::resetPrintData() { this->printerData.progressFilepos = ""; this->printerData.progressPrintTime = ""; this->printerData.progressPrintTimeLeft = ""; - this->printerData.state = ""; + this->printerData.state = PRINTER_STATE_OFFLINE; this->printerData.toolTemp = ""; this->printerData.toolTargetTemp = ""; this->printerData.filamentLength = ""; @@ -74,10 +74,28 @@ String BasePrinterClientImpl::getProgressPrintTimeLeft() { return rtnValue; } -String BasePrinterClientImpl::getState() { +int BasePrinterClientImpl::getState() { return printerData.state; } +String BasePrinterClientImpl::getStateAsText() { + switch (this->getState()) + { + case PRINTER_STATE_ERROR: + return "Error"; + case PRINTER_STATE_STANDBY: + return "Standby"; + case PRINTER_STATE_PRINTING: + return "Printing"; + case PRINTER_STATE_PAUSED: + return "Paused"; + case PRINTER_STATE_COMPLETED: + return "Completed"; + default: + return "Offline"; + } +} + boolean BasePrinterClientImpl::isPrinting() { return printerData.isPrinting; } @@ -88,7 +106,7 @@ boolean BasePrinterClientImpl::isPSUoff() { boolean BasePrinterClientImpl::isOperational() { boolean operational = false; - if (printerData.state == "I" || isPrinting()) { + if ((printerData.state != PRINTER_STATE_OFFLINE) || isPrinting()) { operational = true; } return operational; diff --git a/src/Clients/BasePrinterClientImpl.h b/src/Clients/BasePrinterClientImpl.h index 4c2ec9d..b373f48 100644 --- a/src/Clients/BasePrinterClientImpl.h +++ b/src/Clients/BasePrinterClientImpl.h @@ -20,7 +20,7 @@ protected: String progressFilepos; String progressPrintTime; String progressPrintTimeLeft; - String state; + int state; String toolTemp; String toolTargetTemp; String filamentLength; @@ -53,7 +53,8 @@ public: String getProgressFilepos(); String getProgressPrintTime(); String getProgressPrintTimeLeft(); - String getState(); + int getState(); + String getStateAsText(); boolean isPrinting(); boolean isOperational(); boolean isPSUoff(); @@ -69,6 +70,7 @@ public: String getPrinterName(); void setPrinterName(String printer); + protected: String getInstanceServerTarget(); int getInstanceServerPort(); diff --git a/src/Clients/DuetClient.cpp b/src/Clients/DuetClient.cpp index 6f7099f..c73407a 100644 --- a/src/Clients/DuetClient.cpp +++ b/src/Clients/DuetClient.cpp @@ -1,4 +1,4 @@ -// Moonraker API: https://github.com/Arksine/moonraker/blob/master/docs/web_api.md +// DUET API: https://reprap.org/wiki/RepRap_Firmware_Status_responses // ArduinoJSON Assistant: https://arduinojson.org/v6/assistant/ #include "DuetClient.h" @@ -30,9 +30,6 @@ boolean DuetClient::validate() { return rtnValue; } - - - void DuetClient::getPrinterJobResults() { // const size_t bufferSize = JSON_ARRAY_SIZE(4) + JSON_OBJECT_SIZE(1) + 4*JSON_OBJECT_SIZE(2) + JSON_OBJECT_SIZE(3) + JSON_OBJECT_SIZE(4) + JSON_OBJECT_SIZE(6) + JSON_OBJECT_SIZE(7) + JSON_OBJECT_SIZE(9) + 426; const size_t bufferSize = 2048; // according to ArduinoJson assistant @@ -56,7 +53,7 @@ void DuetClient::getPrinterJobResults() { if (this->jsonRequestClient->getLastError() != "") { this->debugController->printLn(this->jsonRequestClient->getLastError()); printerData.error = this->jsonRequestClient->getLastError(); - printerData.state = ""; + printerData.state = PRINTER_STATE_OFFLINE; printerData.isPrinting = false; printerData.toolTemp = ""; printerData.toolTargetTemp = ""; @@ -65,22 +62,25 @@ void DuetClient::getPrinterJobResults() { return; } - printerData.state = (const char*)(*jsonDoc)["status"]; - - if (printerData.state == "P") { - printerData.isPrinting = true; - } else { - printerData.isPrinting = false; - } + printerData.state = this->translateState((const char*)(*jsonDoc)["status"]); + if (BasePrinterClientImpl::isOperational()) { this->debugController->printLn("Status: " + printerData.state); } else { this->debugController->printLn("Printer Not Operational"); } + if (printerData.state == PRINTER_STATE_PRINTING) { + printerData.isPrinting = true; + } else { + // We dont printing, so abort function here + printerData.isPrinting = false; + return; + } + + // Req 2 - if (printerData.state == "P") { - jsonDoc = this->jsonRequestClient->requestJson( + jsonDoc = this->jsonRequestClient->requestJson( PRINTER_REQUEST_GET, this->getInstanceServerTarget(), this->getInstanceServerPort(), @@ -93,7 +93,7 @@ void DuetClient::getPrinterJobResults() { if (this->jsonRequestClient->getLastError() != "") { this->debugController->printLn(this->jsonRequestClient->getLastError()); printerData.error = this->jsonRequestClient->getLastError(); - printerData.state = ""; + printerData.state = PRINTER_STATE_OFFLINE; printerData.isPrinting = false; printerData.toolTemp = ""; printerData.toolTargetTemp = ""; @@ -119,100 +119,9 @@ void DuetClient::getPrinterJobResults() { */ float totalPrintTime = printerData.progressPrintTime.toFloat() / fileProgress; printerData.progressPrintTimeLeft = String(totalPrintTime - printerData.progressPrintTime.toFloat()); - - } - - // // Req 3 - // jsonDoc = this->jsonRequestClient->requestJson( - // PRINTER_REQUEST_GET, - // this->getInstanceServerTarget(), - // this->getInstanceServerPort(), - // this->encodedAuth, - // "/printer/objects/query?toolhead&virtual_sdcard", - // "", - // bufferSize, - // true - // ); - // if (this->jsonRequestClient->getLastError() != "") { - // this->debugController->printLn(this->jsonRequestClient->getLastError()); - // printerData.error = this->jsonRequestClient->getLastError(); - // printerData.state = ""; - // printerData.isPrinting = false; - // printerData.toolTemp = ""; - // printerData.toolTargetTemp = ""; - // printerData.bedTemp = ""; - // printerData.bedTargetTemp = ""; - // return; - // } - - // float fileProgress = (float)(*jsonDoc)["result"]["status"]["virtual_sdcard"]["progress"]; - // printerData.progressFilepos = (const char*)(*jsonDoc)["result"]["status"]["virtual_sdcard"]["file_position"]; - // printerData.estimatedPrintTime = (float)(*jsonDoc)["result"]["status"]["toolhead"]["estimated_print_time"]; - - // /* - // printerData.progressPrintTimeLeft : No metadata is available, print duration and progress can be used to calculate the ETA: - // */ - // float totalPrintTime = printerData.progressPrintTime.toFloat() / fileProgress; - // printerData.progressPrintTimeLeft = String(totalPrintTime - printerData.progressPrintTime.toFloat()); - - - - - -// // &webhooks&virtual_sdcard&print_stats - - - /* - - printerData.averagePrintTime = (int)jsonBuffer["result"]["status"]["toolhead"]["averagePrintTime"]; - // printerData.fileSize = (const char*)jsonBuffer["job"]["file"]["size"]; - printerData.lastPrintTime = (const char*)jsonBuffer["job"]["lastPrintTime"]; - ; - - - */ -/** -printerData.progressPrintTimeLeft : -If no metadata is available, print duration and progress can be used to calculate the ETA: - -// assume "result" is the response from the status query -let vsd = result.status.virtual_sdcard; -let pstats = result.status.print_stats; -let total_time = pstats.print_duration / vsd.progress; -let eta = total_time - pstats.print_duration; */ - - - /* - - // get the fileseize - apiGetData = "GET /server/files/metadata?filename=" + printerData.fileName; - printClient = getSubmitRequest(apiGetData); - if (printerData.error != "") { - return; - } - const size_t bufferSize2 = JSON_OBJECT_SIZE(1) + JSON_OBJECT_SIZE(8) + 128; - DynamicJsonDocument jsonBuffer2(bufferSize2); - - // Parse JSON object - DeserializationError error2 = deserializeJson(jsonBuffer2, printClient); - if (error2) { - printerData.isPrinting = false; - printerData.toolTemp = ""; - printerData.toolTargetTemp = ""; - printerData.bedTemp = ""; - printerData.bedTargetTemp = (int)jsonBuffer["result"]["status"]["heater_bed"]["target"]; - return; - } - - String printing = (const char*)jsonBuffer["result"]["status"]["print_stats"]["state"]; - - - printerData.fileSize = (long)jsonBuffer2["result"]["size"]; - - */ if (BasePrinterClientImpl::isOperational()) { - this->debugController->printLn("Status: " + printerData.state + " " + printerData.fileName + "(" + printerData.progressCompletion + "%)"); + this->debugController->printLn("Status: " + this->getStateAsText() + " " + printerData.fileName + "(" + printerData.progressCompletion + "%)"); } } @@ -251,3 +160,35 @@ void DuetClient::getPrinterPsuState() { printerData.isPSUoff = false; // we are not checking PSU state, so assume on } */ } + + +/** + * We translate the avail states + * - C (configuration file is being processed) + * - I (idle, no movement or code is being performed) + * - B (busy, live movement is in progress or a macro file is being run) + * - P (printing a file) + * - D (decelerating, pausing a running print) + * - S (stopped, live print has been paused) + * - R (resuming a paused print) + * - H (halted, after emergency stop) + * - F (flashing new firmware) + * - T (changing tool, new in 1.17b) + */ +int DuetClient::translateState(String stateText) { + stateText.toLowerCase(); + stateText.trim(); + if (stateText == "i" || stateText == "t" || stateText == "b" || stateText == "c" || stateText == "f" || stateText == "t") { + return PRINTER_STATE_STANDBY; + } + if (stateText == "p" || stateText == "r") { + return PRINTER_STATE_PRINTING; + } + if (stateText == "d" || stateText == "s") { + return PRINTER_STATE_PAUSED; + } + if (stateText == "h") { + return PRINTER_STATE_ERROR; + } + return PRINTER_STATE_OFFLINE; +} diff --git a/src/Clients/DuetClient.h b/src/Clients/DuetClient.h index 4095a81..8b0cddb 100644 --- a/src/Clients/DuetClient.h +++ b/src/Clients/DuetClient.h @@ -18,4 +18,6 @@ public: void getPrinterJobResults() override; void getPrinterPsuState() override; void updatePrintClient() override; + + int translateState(String stateText); }; \ No newline at end of file diff --git a/src/Clients/KlipperClient.cpp b/src/Clients/KlipperClient.cpp index c8816b7..69a407d 100644 --- a/src/Clients/KlipperClient.cpp +++ b/src/Clients/KlipperClient.cpp @@ -30,9 +30,6 @@ boolean KlipperClient::validate() { return rtnValue; } - - - void KlipperClient::getPrinterJobResults() { // const size_t bufferSize = JSON_ARRAY_SIZE(4) + JSON_OBJECT_SIZE(1) + 4*JSON_OBJECT_SIZE(2) + JSON_OBJECT_SIZE(3) + JSON_OBJECT_SIZE(4) + JSON_OBJECT_SIZE(6) + JSON_OBJECT_SIZE(7) + JSON_OBJECT_SIZE(9) + 426; const size_t bufferSize = 1536; // according to ArduinoJson assistant @@ -56,7 +53,7 @@ void KlipperClient::getPrinterJobResults() { if (this->jsonRequestClient->getLastError() != "") { this->debugController->printLn(this->jsonRequestClient->getLastError()); printerData.error = this->jsonRequestClient->getLastError(); - printerData.state = ""; + printerData.state = PRINTER_STATE_OFFLINE; printerData.isPrinting = false; printerData.toolTemp = ""; printerData.toolTargetTemp = ""; @@ -65,25 +62,27 @@ void KlipperClient::getPrinterJobResults() { return; } - printerData.state = (const char*)(*jsonDoc)["result"]["status"]["print_stats"]["state"]; + printerData.state = this->translateState((const char*)(*jsonDoc)["result"]["status"]["print_stats"]["state"]); printerData.filamentLength = (const char*)(*jsonDoc)["result"]["status"]["job"]["print_stats"]["filament_used"]; printerData.progressPrintTime = (const char*)(*jsonDoc)["result"]["status"]["print_stats"]["print_duration"]; printerData.fileName = (const char*)(*jsonDoc)["result"]["status"]["print_stats"]["filename"]; - if (printerData.state == "printing") { - printerData.isPrinting = true; - } else { - printerData.isPrinting = false; - } if (BasePrinterClientImpl::isOperational()) { this->debugController->printLn("Status: " + printerData.state); } else { this->debugController->printLn("Printer Not Operational"); } + if (printerData.state == PRINTER_STATE_PRINTING) { + printerData.isPrinting = true; + } else { + // We dont printing, so abort function here + printerData.isPrinting = false; + return; + } + // Req 2 - if (printerData.state == "printing") { - jsonDoc = this->jsonRequestClient->requestJson( + jsonDoc = this->jsonRequestClient->requestJson( PRINTER_REQUEST_GET, this->getInstanceServerTarget(), this->getInstanceServerPort(), @@ -96,7 +95,7 @@ void KlipperClient::getPrinterJobResults() { if (this->jsonRequestClient->getLastError() != "") { this->debugController->printLn(this->jsonRequestClient->getLastError()); printerData.error = this->jsonRequestClient->getLastError(); - printerData.state = ""; + printerData.state = PRINTER_STATE_OFFLINE; printerData.isPrinting = false; printerData.toolTemp = ""; printerData.toolTargetTemp = ""; @@ -120,99 +119,8 @@ void KlipperClient::getPrinterJobResults() { float totalPrintTime = printerData.progressPrintTime.toFloat() / fileProgress; printerData.progressPrintTimeLeft = String(totalPrintTime - printerData.progressPrintTime.toFloat()); - } - - // // Req 3 - // jsonDoc = this->jsonRequestClient->requestJson( - // PRINTER_REQUEST_GET, - // this->getInstanceServerTarget(), - // this->getInstanceServerPort(), - // this->encodedAuth, - // "/printer/objects/query?toolhead&virtual_sdcard", - // "", - // bufferSize, - // true - // ); - // if (this->jsonRequestClient->getLastError() != "") { - // this->debugController->printLn(this->jsonRequestClient->getLastError()); - // printerData.error = this->jsonRequestClient->getLastError(); - // printerData.state = ""; - // printerData.isPrinting = false; - // printerData.toolTemp = ""; - // printerData.toolTargetTemp = ""; - // printerData.bedTemp = ""; - // printerData.bedTargetTemp = ""; - // return; - // } - - // float fileProgress = (float)(*jsonDoc)["result"]["status"]["virtual_sdcard"]["progress"]; - // printerData.progressFilepos = (const char*)(*jsonDoc)["result"]["status"]["virtual_sdcard"]["file_position"]; - // printerData.estimatedPrintTime = (float)(*jsonDoc)["result"]["status"]["toolhead"]["estimated_print_time"]; - - // /* - // printerData.progressPrintTimeLeft : No metadata is available, print duration and progress can be used to calculate the ETA: - // */ - // float totalPrintTime = printerData.progressPrintTime.toFloat() / fileProgress; - // printerData.progressPrintTimeLeft = String(totalPrintTime - printerData.progressPrintTime.toFloat()); - - - - - -// // &webhooks&virtual_sdcard&print_stats - - - /* - - printerData.averagePrintTime = (int)jsonBuffer["result"]["status"]["toolhead"]["averagePrintTime"]; - // printerData.fileSize = (const char*)jsonBuffer["job"]["file"]["size"]; - printerData.lastPrintTime = (const char*)jsonBuffer["job"]["lastPrintTime"]; - ; - - - */ -/** -printerData.progressPrintTimeLeft : -If no metadata is available, print duration and progress can be used to calculate the ETA: - -// assume "result" is the response from the status query -let vsd = result.status.virtual_sdcard; -let pstats = result.status.print_stats; -let total_time = pstats.print_duration / vsd.progress; -let eta = total_time - pstats.print_duration; */ - - - /* - - // get the fileseize - apiGetData = "GET /server/files/metadata?filename=" + printerData.fileName; - printClient = getSubmitRequest(apiGetData); - if (printerData.error != "") { - return; - } - const size_t bufferSize2 = JSON_OBJECT_SIZE(1) + JSON_OBJECT_SIZE(8) + 128; - DynamicJsonDocument jsonBuffer2(bufferSize2); - - // Parse JSON object - DeserializationError error2 = deserializeJson(jsonBuffer2, printClient); - if (error2) { - printerData.isPrinting = false; - printerData.toolTemp = ""; - printerData.toolTargetTemp = ""; - printerData.bedTemp = ""; - printerData.bedTargetTemp = (int)jsonBuffer["result"]["status"]["heater_bed"]["target"]; - return; - } - - String printing = (const char*)jsonBuffer["result"]["status"]["print_stats"]["state"]; - - - printerData.fileSize = (long)jsonBuffer2["result"]["size"]; - - */ - if (BasePrinterClientImpl::isOperational()) { - this->debugController->printLn("Status: " + printerData.state + " " + printerData.fileName + "(" + printerData.progressCompletion + "%)"); + this->debugController->printLn("Status: " + this->getStateAsText() + " " + printerData.fileName + "(" + printerData.progressCompletion + "%)"); } } @@ -251,3 +159,32 @@ void KlipperClient::getPrinterPsuState() { printerData.isPSUoff = false; // we are not checking PSU state, so assume on } */ } + +/** + * We translate the avail states + * - "standby": No print in progress + * - "printing": The printer is currently printing + * - "paused": A print in progress has been paused + * - "error": The print exited with an error. print_stats.message contains a related error message + * - "complete": The last print has completed + */ +int KlipperClient::translateState(String stateText) { + stateText.toLowerCase(); + stateText.trim(); + if (stateText == "standby") { + return PRINTER_STATE_STANDBY; + } + if (stateText == "printing") { + return PRINTER_STATE_PRINTING; + } + if (stateText == "paused") { + return PRINTER_STATE_PAUSED; + } + if (stateText == "complete") { + return PRINTER_STATE_COMPLETED; + } + if (stateText == "error") { + return PRINTER_STATE_ERROR; + } + return PRINTER_STATE_OFFLINE; +} diff --git a/src/Clients/KlipperClient.h b/src/Clients/KlipperClient.h index 028be62..96d9b6b 100644 --- a/src/Clients/KlipperClient.h +++ b/src/Clients/KlipperClient.h @@ -18,4 +18,6 @@ public: void getPrinterJobResults() override; void getPrinterPsuState() override; void updatePrintClient() override; + + int translateState(String stateText); }; \ No newline at end of file diff --git a/src/Display/OledDisplay.cpp b/src/Display/OledDisplay.cpp index 52ba8a2..3210010 100644 --- a/src/Display/OledDisplay.cpp +++ b/src/Display/OledDisplay.cpp @@ -339,7 +339,7 @@ void OledDisplay::drawClockHeaderOverlay(OLEDDisplay *display, OLEDDisplayUiStat } if (printerClient->isPSUoff()) { display->drawString(printerStateDrawXPos, 47, "psu off"); - } else if (printerClient->getState() == "Operational") { + } else if (printerClient->getState() != PRINTER_STATE_OFFLINE) { display->drawString(printerStateDrawXPos, 47, "online"); } else { display->drawString(printerStateDrawXPos, 47, "offline"); diff --git a/src/Network/WebServer.cpp b/src/Network/WebServer.cpp index e8146b8..29c330b 100644 --- a/src/Network/WebServer.cpp +++ b/src/Network/WebServer.cpp @@ -182,7 +182,7 @@ void WebServer::displayPrinterStatus() { html += "Status: Offline
"; html += "Reason: " + printerClient->getError() + "
"; } else { - html += "Status: " + printerClient->getState(); + html += "Status: " + printerClient->getStateAsText(); if (printerClient->isPSUoff() && this->globalDataController->hasPrinterPsu()) { html += ", PSU off"; }