From 6c06302723e4ec9163df8b463765aed7b1f426af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric?= Date: Tue, 2 Jun 2020 12:33:02 +0200 Subject: [PATCH 01/11] change extractHttpCode() signature to remove unusefull body parameter --- OctoPrintAPI.cpp | 17 ++++++++--------- OctoPrintAPI.h | 2 +- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/OctoPrintAPI.cpp b/OctoPrintAPI.cpp index 96ac8a4..4e733b3 100644 --- a/OctoPrintAPI.cpp +++ b/OctoPrintAPI.cpp @@ -92,7 +92,11 @@ String OctoprintApi::sendRequestToOctoprint(String type, String command, const c _client->println(); now = millis(); - while (millis() - now < OPAPI_TIMEOUT) { + if (_debug) { + Serial.print("Request sent. Waiting for the answer:"); + Serial.println(now); + } + while (millis() - now < OPAPI_TIMEOUT || now < millis()) { while (_client->available()) { char c = _client->read(); @@ -147,7 +151,7 @@ String OctoprintApi::sendRequestToOctoprint(String type, String command, const c closeClient(); - int httpCode = extractHttpCode(statusCode, body); + int httpCode = extractHttpCode(statusCode); if (_debug) { Serial.print("\nhttpCode:"); Serial.println(httpCode); @@ -547,7 +551,7 @@ void OctoprintApi::closeClient() { _client->stop(); } * Extract the HTTP header response code. Used for error reporting - will print in serial monitor any non 200 response codes (i.e. if something has gone wrong!). * Thanks Brian for the start of this function, and the chuckle of watching you realise on a live stream that I didn't use the response code at that time! :) * */ -int OctoprintApi::extractHttpCode(String statusCode, String body) { +int OctoprintApi::extractHttpCode(String statusCode) { if (_debug) { Serial.print("\nStatus code to extract: "); Serial.println(statusCode); @@ -558,13 +562,8 @@ int OctoprintApi::extractHttpCode(String statusCode, String body) { String statusCodeALL = statusCode.substring(firstSpace + 1); //"400 BAD REQUEST" String statusCodeExtract = statusCode.substring(firstSpace + 1, lastSpace); //May end up being e.g. "400 BAD" int statusCodeInt = statusCodeExtract.toInt(); //Converts to "400" integer - i.e. strips out rest of text characters "fix" - if (_debug and statusCodeInt != 200 and statusCodeInt != 201 and statusCodeInt != 202 and statusCodeInt != 204) { + if (_debug and statusCodeInt != 200 and statusCodeInt != 201 and statusCodeInt != 202 and statusCodeInt != 204) Serial.print("\nSERVER RESPONSE CODE: " + String(statusCodeALL)); - if (body != "") - Serial.println(" - " + body); - else - Serial.println(); - } return statusCodeInt; } else return -1; diff --git a/OctoPrintAPI.h b/OctoPrintAPI.h index 8db182d..fae88d0 100644 --- a/OctoPrintAPI.h +++ b/OctoPrintAPI.h @@ -136,7 +136,7 @@ class OctoprintApi { int _octoPrintPort; const int maxMessageLength = 1000; void closeClient(); - int extractHttpCode(String statusCode, String body); + int extractHttpCode(String statusCode); String sendRequestToOctoprint(String type, String command, const char *data); }; From e6169c660cb23cd668f801668d92951290622e7c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric?= Date: Tue, 2 Jun 2020 13:02:14 +0200 Subject: [PATCH 02/11] extractHttpCode() refactor to use less memory --- OctoPrintAPI.cpp | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/OctoPrintAPI.cpp b/OctoPrintAPI.cpp index 4e733b3..d2c960d 100644 --- a/OctoPrintAPI.cpp +++ b/OctoPrintAPI.cpp @@ -551,20 +551,14 @@ void OctoprintApi::closeClient() { _client->stop(); } * Extract the HTTP header response code. Used for error reporting - will print in serial monitor any non 200 response codes (i.e. if something has gone wrong!). * Thanks Brian for the start of this function, and the chuckle of watching you realise on a live stream that I didn't use the response code at that time! :) * */ -int OctoprintApi::extractHttpCode(String statusCode) { +int OctoprintApi::extractHttpCode(String statusCode) { // HTTP/1.1 200 OK || HTTP/1.1 400 BAD REQUEST if (_debug) { Serial.print("\nStatus code to extract: "); Serial.println(statusCode); } - int firstSpace = statusCode.indexOf(" "); - int lastSpace = statusCode.lastIndexOf(" "); - if (firstSpace > -1 && lastSpace > -1 && firstSpace != lastSpace) { - String statusCodeALL = statusCode.substring(firstSpace + 1); //"400 BAD REQUEST" - String statusCodeExtract = statusCode.substring(firstSpace + 1, lastSpace); //May end up being e.g. "400 BAD" - int statusCodeInt = statusCodeExtract.toInt(); //Converts to "400" integer - i.e. strips out rest of text characters "fix" - if (_debug and statusCodeInt != 200 and statusCodeInt != 201 and statusCodeInt != 202 and statusCodeInt != 204) - Serial.print("\nSERVER RESPONSE CODE: " + String(statusCodeALL)); - return statusCodeInt; - } else - return -1; + + String statusExtract = statusCode.substring(statusCode.indexOf(" ") + 1); // 200 OK || 400 BAD REQUEST + int statusCodeInt = statusExtract.substring(0, statusExtract.indexOf(" ")).toInt(); // 200 || 400 + + return statusCodeInt ? statusCodeInt : -1; } From 920890c9352b26b3e6b73769825001bcd43604e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric?= Date: Tue, 2 Jun 2020 16:22:27 +0200 Subject: [PATCH 03/11] sendRequestToOctoprint(): - Resole issue https://github.com/chunkysteveo/OctoPrintAPI/issues/28 - Reduce memory footprint with less variables - Split header sending in sendHeader() - Timeout run through all request - Refactor main loop for a better readability WARNING: Only tested with GET (Octoprint up and down with Haproxy, with printer up and down). Not tested yet with POST commands. Reduce variable memory for octoPrintPrintHeadRelativeJog() and remove a potential buffer overflow. Remove unsued maxMessageLength and httpErrorBody --- OctoPrintAPI.cpp | 201 ++++++++++++++++++++++------------------------- OctoPrintAPI.h | 10 ++- 2 files changed, 101 insertions(+), 110 deletions(-) diff --git a/OctoPrintAPI.cpp b/OctoPrintAPI.cpp index d2c960d..e3daf4a 100644 --- a/OctoPrintAPI.cpp +++ b/OctoPrintAPI.cpp @@ -20,6 +20,7 @@ OctoprintApi::OctoprintApi(Client &client, IPAddress octoPrintIp, int octoPrintP _octoPrintIp = octoPrintIp; _octoPrintPort = octoPrintPort; _usingIpAddress = true; + snprintf(_useragent, USER_AGENT_SIZE, "User-Agent: %s", USER_AGENT); } /** OctoprintApi() @@ -31,6 +32,7 @@ OctoprintApi::OctoprintApi(Client &client, char *octoPrintUrl, int octoPrintPort _octoPrintUrl = octoPrintUrl; _octoPrintPort = octoPrintPort; _usingIpAddress = false; + snprintf(_useragent, USER_AGENT_SIZE, "User-Agent: %s", USER_AGENT); } /** GET YOUR ASS TO OCTOPRINT... @@ -46,119 +48,78 @@ String OctoprintApi::sendRequestToOctoprint(String type, String command, const c return ""; } - String statusCode = ""; - String headers = ""; - String body = ""; - bool finishedStatusCode = false; - bool finishedHeaders = false; - bool currentLineIsBlank = true; - int ch_count = 0; - int headerCount = 0; - int headerLineStart = 0; - int bodySize = -1; - unsigned long now; - - bool connected; + String buffer = ""; + char c = 0; + long bodySize = -1; + unsigned long start_waiting = 0; + bool connected = false; if (_usingIpAddress) connected = _client->connect(_octoPrintIp, _octoPrintPort); else connected = _client->connect(_octoPrintUrl, _octoPrintPort); - if (connected) { - if (_debug) - Serial.println(".... connected to server"); - - char useragent[64]; - snprintf(useragent, 64, "User-Agent: %s", USER_AGENT); - - _client->println(type + " " + command + " HTTP/1.1"); - _client->print("Host: "); - if (_usingIpAddress) - _client->println(_octoPrintIp); - else - _client->println(_octoPrintUrl); - _client->print("X-Api-Key: "); - _client->println(_apiKey); - _client->println(useragent); - _client->println("Connection: keep-alive"); - if (data != NULL) { - _client->println("Content-Type: application/json"); - _client->print("Content-Length: "); - _client->println(strlen(data)); // number of bytes in the payload - _client->println(); // important need an empty line here - _client->println(data); // the payload - } else - _client->println(); - - now = millis(); - if (_debug) { - Serial.print("Request sent. Waiting for the answer:"); - Serial.println(now); - } - while (millis() - now < OPAPI_TIMEOUT || now < millis()) { - while (_client->available()) { - char c = _client->read(); - - if (_debug) - Serial.print(c); - - if (!finishedStatusCode) { - if (c == '\n') - finishedStatusCode = true; - else - statusCode = statusCode + c; - } - - if (!finishedHeaders) { - if (c == '\n') { - if (currentLineIsBlank) - finishedHeaders = true; - else { - if (headers.substring(headerLineStart).startsWith("Content-Length: ")) - bodySize = (headers.substring(headerLineStart + 16)).toInt(); - headers = headers + c; - headerCount++; - headerLineStart = headerCount; - } - } else { - headers = headers + c; - headerCount++; - } - } else { - if (ch_count < maxMessageLength) { - body = body + c; - ch_count++; - if (ch_count == bodySize) - break; - } - } - if (c == '\n') - currentLineIsBlank = true; - else if (c != '\r') { - currentLineIsBlank = false; - } - } - if (ch_count == bodySize) - break; - } - } else { - if (_debug) { - Serial.println("connection failed"); - Serial.println(connected); - } + if (!connected) { + if (_debug) Serial.println("connection failed."); + closeClient(); + return ""; } + if (_debug) Serial.println("...connected to server."); - closeClient(); + sendHeader(type, command, data); + + start_waiting = millis(); + if (_debug) Serial.println("Request sent. Waiting for the answer."); + + while (!_client->available() && OPAPI_RUN_TIMEOUT) // wait for a reply + delay(1); + if (!_client->available()) { + if (_debug) Serial.println("Timeout during waiting for a reply"); + closeClient(); + return ""; + } + + // Read Status code + if (_debug) Serial.println("Reading status code"); + while (_client->available() && (c = _client->read()) != '\n' && OPAPI_RUN_TIMEOUT) + buffer = buffer + c; - int httpCode = extractHttpCode(statusCode); + httpStatusCode = extractHttpCode(buffer); if (_debug) { - Serial.print("\nhttpCode:"); - Serial.println(httpCode); + Serial.print("httpCode:"); + Serial.println(httpStatusCode); + } + if (!(200 <= httpStatusCode && httpStatusCode <= 204) && httpStatusCode != 409) { + closeClient(); + return ""; + } + // Read headers + if (_debug) Serial.println("Reading headers"); + for (buffer = ""; _client->available() && OPAPI_RUN_TIMEOUT;) { // read headers + c = _client->read(); + buffer = buffer + c; + if (_debug) Serial.print(c); + if (c == '\n') { + if (buffer.startsWith("Content-Length: ")) + bodySize = buffer.substring(16).toInt(); + else if (buffer == "\n" || buffer == "\r\n") + break; + buffer = ""; + } + } + if (bodySize <= 0) { + if (_debug) Serial.println("Header 'Content-Length' not found"); + closeClient(); + return ""; } - httpStatusCode = httpCode; - return body; + if (_debug) Serial.println("Reading body"); + for (buffer = ""; _client->available() && bodySize-- && OPAPI_RUN_TIMEOUT;) + buffer = buffer + (char)_client->read(); + if (_debug) Serial.println(buffer); + + closeClient(); + return buffer; } String OctoprintApi::sendGetToOctoprint(String command) { @@ -394,25 +355,25 @@ bool OctoprintApi::octoPrintPrintHeadRelativeJog(double x, double y, double z, d // "absolute": false, // "speed": 30 // } - char postData[1024]; - char tmp[128]; + char postData[POSTDATA_SIZE]; + char tmp[TEMPDATA_SIZE]; postData[0] = '\0'; - strcat(postData, "{\"command\": \"jog\""); + strncat(postData, "{\"command\": \"jog\"", POSTDATA_SIZE); if (x != 0) { - snprintf(tmp, 128, ", \"x\": %f", x); + snprintf(tmp, TEMPDATA_SIZE, ", \"x\": %f", x); strcat(postData, tmp); } if (y != 0) { - snprintf(tmp, 128, ", \"y\": %f", y); + snprintf(tmp, TEMPDATA_SIZE, ", \"y\": %f", y); strcat(postData, tmp); } if (z != 0) { - snprintf(tmp, 128, ", \"z\": %f", z); + snprintf(tmp, TEMPDATA_SIZE, ", \"z\": %f", z); strcat(postData, tmp); } if (f != 0) { - snprintf(tmp, 128, ", \"speed\": %f", f); + snprintf(tmp, TEMPDATA_SIZE, ", \"speed\": %f", f); strcat(postData, tmp); } strcat(postData, ", \"absolute\": false"); @@ -562,3 +523,27 @@ int OctoprintApi::extractHttpCode(String statusCode) { // HTTP/1.1 200 OK || H return statusCodeInt ? statusCodeInt : -1; } + +/** + * Send HTTP Headers + * */ +void OctoprintApi::sendHeader(const String type, const String command, const char *data) { + _client->println(type + " " + command + " HTTP/1.1"); + _client->print("Host: "); + if (_usingIpAddress) + _client->println(_octoPrintIp); + else + _client->println(_octoPrintUrl); + _client->print("X-Api-Key: "); + _client->println(_apiKey); + _client->println(_useragent); + _client->println("Connection: keep-alive"); + if (data != NULL) { + _client->println("Content-Type: application/json"); + _client->print("Content-Length: "); + _client->println(strlen(data)); // number of bytes in the payload + _client->println(); // important need an empty line here + _client->println(data); // the payload + } else + _client->println(); +} \ No newline at end of file diff --git a/OctoPrintAPI.h b/OctoPrintAPI.h index fae88d0..b2c98c8 100644 --- a/OctoPrintAPI.h +++ b/OctoPrintAPI.h @@ -14,11 +14,15 @@ #include #include -#define OPAPI_TIMEOUT 3000 +#define OPAPI_TIMEOUT 3000 // 3s timetout +#define OPAPI_RUN_TIMEOUT (millis() - start_waiting < OPAPI_TIMEOUT && start_waiting <= millis()) + #define POSTDATA_SIZE 256 +#define TEMPDATA_SIZE 32 #define POSTDATA_GCODE_SIZE 50 #define JSONDOCUMENT_SIZE 1024 #define USER_AGENT "OctoPrintAPI/1.1.4 (Arduino)" +#define USER_AGENT_SIZE 64 struct printerStatistics { String printerState; @@ -134,10 +138,12 @@ class OctoprintApi { bool _usingIpAddress; char *_octoPrintUrl; int _octoPrintPort; + char _useragent[USER_AGENT_SIZE]; const int maxMessageLength = 1000; void closeClient(); + void sendHeader(const String type, const String command, const char *data); int extractHttpCode(String statusCode); - String sendRequestToOctoprint(String type, String command, const char *data); + String sendRequestToOctoprint(const String type, const String command, const char *data); }; #endif From fd95a14c0f6e85c0a1b844dfabbaa6239e2abbe2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric?= Date: Tue, 2 Jun 2020 16:40:57 +0200 Subject: [PATCH 04/11] minor debug --- OctoPrintAPI.cpp | 12 ++++++------ OctoPrintAPI.h | 6 +++--- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/OctoPrintAPI.cpp b/OctoPrintAPI.cpp index e3daf4a..aad0bd5 100644 --- a/OctoPrintAPI.cpp +++ b/OctoPrintAPI.cpp @@ -362,22 +362,22 @@ bool OctoprintApi::octoPrintPrintHeadRelativeJog(double x, double y, double z, d strncat(postData, "{\"command\": \"jog\"", POSTDATA_SIZE); if (x != 0) { snprintf(tmp, TEMPDATA_SIZE, ", \"x\": %f", x); - strcat(postData, tmp); + strncat(postData, tmp, TEMPDATA_SIZE); } if (y != 0) { snprintf(tmp, TEMPDATA_SIZE, ", \"y\": %f", y); - strcat(postData, tmp); + strncat(postData, tmp, TEMPDATA_SIZE); } if (z != 0) { snprintf(tmp, TEMPDATA_SIZE, ", \"z\": %f", z); - strcat(postData, tmp); + strncat(postData, tmp, TEMPDATA_SIZE); } if (f != 0) { snprintf(tmp, TEMPDATA_SIZE, ", \"speed\": %f", f); - strcat(postData, tmp); + strncat(postData, tmp, TEMPDATA_SIZE); } - strcat(postData, ", \"absolute\": false"); - strcat(postData, " }"); + strncat(postData, ", \"absolute\": false", TEMPDATA_SIZE); + strncat(postData, " }", TEMPDATA_SIZE); if (_debug) Serial.println(postData); diff --git a/OctoPrintAPI.h b/OctoPrintAPI.h index b2c98c8..319d0c2 100644 --- a/OctoPrintAPI.h +++ b/OctoPrintAPI.h @@ -18,7 +18,7 @@ #define OPAPI_RUN_TIMEOUT (millis() - start_waiting < OPAPI_TIMEOUT && start_waiting <= millis()) #define POSTDATA_SIZE 256 -#define TEMPDATA_SIZE 32 +#define TEMPDATA_SIZE 24 #define POSTDATA_GCODE_SIZE 50 #define JSONDOCUMENT_SIZE 1024 #define USER_AGENT "OctoPrintAPI/1.1.4 (Arduino)" @@ -101,7 +101,7 @@ class OctoprintApi { printJobCall printJob; bool _debug = false; int httpStatusCode = 0; - String httpErrorBody = ""; + String sendPostToOctoPrint(String command, const char *postData); bool octoPrintConnectionDisconnect(); bool octoPrintConnectionAutoConnect(); @@ -139,7 +139,7 @@ class OctoprintApi { char *_octoPrintUrl; int _octoPrintPort; char _useragent[USER_AGENT_SIZE]; - const int maxMessageLength = 1000; + void closeClient(); void sendHeader(const String type, const String command, const char *data); int extractHttpCode(String statusCode); From 810ebc7cc4684c85fc3421f43bdd17684d59c0a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric?= Date: Tue, 2 Jun 2020 18:04:25 +0200 Subject: [PATCH 05/11] Minor debugging --- OctoPrintAPI.cpp | 30 +++++++++++++----------------- OctoPrintAPI.h | 16 ++++++++-------- 2 files changed, 21 insertions(+), 25 deletions(-) diff --git a/OctoPrintAPI.cpp b/OctoPrintAPI.cpp index aad0bd5..31fa988 100644 --- a/OctoPrintAPI.cpp +++ b/OctoPrintAPI.cpp @@ -14,7 +14,7 @@ /** OctoprintApi() * IP address version of the client connect function * */ -OctoprintApi::OctoprintApi(Client &client, IPAddress octoPrintIp, int octoPrintPort, String apiKey) { +OctoprintApi::OctoprintApi(Client &client, IPAddress octoPrintIp, uint16_t octoPrintPort, String apiKey) { _client = &client; _apiKey = apiKey; _octoPrintIp = octoPrintIp; @@ -26,7 +26,7 @@ OctoprintApi::OctoprintApi(Client &client, IPAddress octoPrintIp, int octoPrintP /** OctoprintApi() * Hostname version of the client connect function * */ -OctoprintApi::OctoprintApi(Client &client, char *octoPrintUrl, int octoPrintPort, String apiKey) { +OctoprintApi::OctoprintApi(Client &client, char *octoPrintUrl, uint16_t octoPrintPort, String apiKey) { _client = &client; _apiKey = apiKey; _octoPrintUrl = octoPrintUrl; @@ -89,7 +89,7 @@ String OctoprintApi::sendRequestToOctoprint(String type, String command, const c Serial.print("httpCode:"); Serial.println(httpStatusCode); } - if (!(200 <= httpStatusCode && httpStatusCode <= 204) && httpStatusCode != 409) { + if (!(200 <= httpStatusCode && httpStatusCode < 204) && httpStatusCode != 409) { // Code 204 NO CONTENT is ok, we close and return closeClient(); return ""; } @@ -357,23 +357,22 @@ bool OctoprintApi::octoPrintPrintHeadRelativeJog(double x, double y, double z, d // } char postData[POSTDATA_SIZE]; char tmp[TEMPDATA_SIZE]; - postData[0] = '\0'; - strncat(postData, "{\"command\": \"jog\"", POSTDATA_SIZE); + strncpy(postData, "{\"command\": \"jog\"", POSTDATA_SIZE); if (x != 0) { - snprintf(tmp, TEMPDATA_SIZE, ", \"x\": %f", x); + snprintf(tmp, TEMPDATA_SIZE, ", \"x\": %.2f", x); strncat(postData, tmp, TEMPDATA_SIZE); } if (y != 0) { - snprintf(tmp, TEMPDATA_SIZE, ", \"y\": %f", y); + snprintf(tmp, TEMPDATA_SIZE, ", \"y\": %.2f", y); strncat(postData, tmp, TEMPDATA_SIZE); } if (z != 0) { - snprintf(tmp, TEMPDATA_SIZE, ", \"z\": %f", z); + snprintf(tmp, TEMPDATA_SIZE, ", \"z\": %.2f", z); strncat(postData, tmp, TEMPDATA_SIZE); } if (f != 0) { - snprintf(tmp, TEMPDATA_SIZE, ", \"speed\": %f", f); + snprintf(tmp, TEMPDATA_SIZE, ", \"speed\": %.2f", f); strncat(postData, tmp, TEMPDATA_SIZE); } strncat(postData, ", \"absolute\": false", TEMPDATA_SIZE); @@ -387,7 +386,7 @@ bool OctoprintApi::octoPrintPrintHeadRelativeJog(double x, double y, double z, d bool OctoprintApi::octoPrintExtrude(double amount) { char postData[POSTDATA_SIZE]; - snprintf(postData, POSTDATA_SIZE, "{ \"command\": \"extrude\", \"amount\": %f }", amount); + snprintf(postData, POSTDATA_SIZE, "{ \"command\": \"extrude\", \"amount\": %.2f }", amount); sendPostToOctoPrint("/api/printer/tool", postData); return (httpStatusCode == 204); @@ -476,8 +475,7 @@ bool OctoprintApi::octoPrintGetPrinterSD() { StaticJsonDocument root; if (!deserializeJson(root, response)) { - bool printerStatesdReady = root["ready"]; - printerStats.printerStatesdReady = printerStatesdReady; + printerStats.printerStatesdReady = root["ready"]; return true; } return false; @@ -489,13 +487,11 @@ bool OctoprintApi::octoPrintGetPrinterSD() { Sends any command to the printer via the serial interface. Should be used with some care as some commands can interfere with or even stop a running print job. If successful returns a 204 No Content and an empty body. */ -bool OctoprintApi::octoPrintPrinterCommand(char *gcodeCommand) { +bool OctoprintApi::octoPrintPrinterCommand(const char *gcodeCommand) { String command = "/api/printer/command"; char postData[POSTDATA_GCODE_SIZE]; - postData[0] = '\0'; snprintf(postData, POSTDATA_GCODE_SIZE, "{\"command\": \"%s\"}", gcodeCommand); - sendPostToOctoPrint(command, postData); return (httpStatusCode == 204); @@ -512,9 +508,9 @@ void OctoprintApi::closeClient() { _client->stop(); } * Extract the HTTP header response code. Used for error reporting - will print in serial monitor any non 200 response codes (i.e. if something has gone wrong!). * Thanks Brian for the start of this function, and the chuckle of watching you realise on a live stream that I didn't use the response code at that time! :) * */ -int OctoprintApi::extractHttpCode(String statusCode) { // HTTP/1.1 200 OK || HTTP/1.1 400 BAD REQUEST +int OctoprintApi::extractHttpCode(const String statusCode) { // HTTP/1.1 200 OK || HTTP/1.1 400 BAD REQUEST if (_debug) { - Serial.print("\nStatus code to extract: "); + Serial.print("Status code to extract: "); Serial.println(statusCode); } diff --git a/OctoPrintAPI.h b/OctoPrintAPI.h index 319d0c2..75bed1b 100644 --- a/OctoPrintAPI.h +++ b/OctoPrintAPI.h @@ -89,8 +89,8 @@ struct printerBedCall { class OctoprintApi { public: - OctoprintApi(Client &client, IPAddress octoPrintIp, int octoPrintPort, String apiKey); - OctoprintApi(Client &client, char *octoPrintUrl, int octoPrintPort, String apiKey); + OctoprintApi(Client &client, IPAddress octoPrintIp, uint16_t octoPrintPort, String apiKey); + OctoprintApi(Client &client, char *octoPrintUrl, uint16_t octoPrintPort, String apiKey); String sendGetToOctoprint(String command); String getOctoprintEndpointResults(String command); bool getPrinterStatistics(); @@ -99,8 +99,8 @@ class OctoprintApi { octoprintVersion octoprintVer; bool getPrintJob(); printJobCall printJob; - bool _debug = false; - int httpStatusCode = 0; + bool _debug = false; + uint16_t httpStatusCode = 0; String sendPostToOctoPrint(String command, const char *postData); bool octoPrintConnectionDisconnect(); @@ -129,7 +129,7 @@ class OctoprintApi { bool octoPrintJobResume(); bool octoPrintFileSelect(String &path); - bool octoPrintPrinterCommand(char *gcodeCommand); + bool octoPrintPrinterCommand(const char *gcodeCommand); private: Client *_client; @@ -137,12 +137,12 @@ class OctoprintApi { IPAddress _octoPrintIp; bool _usingIpAddress; char *_octoPrintUrl; - int _octoPrintPort; + uint16_t _octoPrintPort; char _useragent[USER_AGENT_SIZE]; - + void closeClient(); void sendHeader(const String type, const String command, const char *data); - int extractHttpCode(String statusCode); + int extractHttpCode(const String statusCode); String sendRequestToOctoprint(const String type, const String command, const char *data); }; From 44dbf3b24713ae988ee879efb376e9ddea194ab4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric?= Date: Tue, 2 Jun 2020 18:12:57 +0200 Subject: [PATCH 06/11] Minor debugging for testing POST commands --- OctoPrintAPI.cpp | 4 ++-- OctoPrintAPI.h | 3 +-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/OctoPrintAPI.cpp b/OctoPrintAPI.cpp index 31fa988..6716767 100644 --- a/OctoPrintAPI.cpp +++ b/OctoPrintAPI.cpp @@ -489,9 +489,9 @@ If successful returns a 204 No Content and an empty body. */ bool OctoprintApi::octoPrintPrinterCommand(const char *gcodeCommand) { String command = "/api/printer/command"; - char postData[POSTDATA_GCODE_SIZE]; + char postData[POSTDATA_SIZE]; - snprintf(postData, POSTDATA_GCODE_SIZE, "{\"command\": \"%s\"}", gcodeCommand); + snprintf(postData, POSTDATA_SIZE, "{\"command\": \"%s\"}", gcodeCommand); sendPostToOctoPrint(command, postData); return (httpStatusCode == 204); diff --git a/OctoPrintAPI.h b/OctoPrintAPI.h index 75bed1b..0a671fe 100644 --- a/OctoPrintAPI.h +++ b/OctoPrintAPI.h @@ -17,9 +17,8 @@ #define OPAPI_TIMEOUT 3000 // 3s timetout #define OPAPI_RUN_TIMEOUT (millis() - start_waiting < OPAPI_TIMEOUT && start_waiting <= millis()) -#define POSTDATA_SIZE 256 +#define POSTDATA_SIZE 128 #define TEMPDATA_SIZE 24 -#define POSTDATA_GCODE_SIZE 50 #define JSONDOCUMENT_SIZE 1024 #define USER_AGENT "OctoPrintAPI/1.1.4 (Arduino)" #define USER_AGENT_SIZE 64 From 9ca7c70c07fccb6c59a604ccc22884918d43b9a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric?= Date: Tue, 2 Jun 2020 18:36:03 +0200 Subject: [PATCH 07/11] Remove the keep alive header as the connexion is open and close each time --- OctoPrintAPI.cpp | 30 +++++++++++------------------- 1 file changed, 11 insertions(+), 19 deletions(-) diff --git a/OctoPrintAPI.cpp b/OctoPrintAPI.cpp index 6716767..65b540c 100644 --- a/OctoPrintAPI.cpp +++ b/OctoPrintAPI.cpp @@ -39,18 +39,16 @@ OctoprintApi::OctoprintApi(Client &client, char *octoPrintUrl, uint16_t octoPrin * * **/ String OctoprintApi::sendRequestToOctoprint(String type, String command, const char *data) { - if (_debug) - Serial.println("OctoprintApi::sendRequestToOctoprint() CALLED"); + if (_debug) Serial.println("OctoprintApi::sendRequestToOctoprint() CALLED"); if ((type != "GET") && (type != "POST")) { - if (_debug) - Serial.println("OctoprintApi::sendRequestToOctoprint() Only GET & POST are supported... exiting."); + if (_debug) Serial.println("OctoprintApi::sendRequestToOctoprint() Only GET & POST are supported... exiting."); return ""; } String buffer = ""; char c = 0; - long bodySize = -1; + uint32_t bodySize = 0; unsigned long start_waiting = 0; bool connected = false; @@ -107,7 +105,7 @@ String OctoprintApi::sendRequestToOctoprint(String type, String command, const c buffer = ""; } } - if (bodySize <= 0) { + if (!bodySize) { if (_debug) Serial.println("Header 'Content-Length' not found"); closeClient(); return ""; @@ -123,8 +121,7 @@ String OctoprintApi::sendRequestToOctoprint(String type, String command, const c } String OctoprintApi::sendGetToOctoprint(String command) { - if (_debug) - Serial.println("OctoprintApi::sendGetToOctoprint() CALLED"); + if (_debug) Serial.println("OctoprintApi::sendGetToOctoprint() CALLED"); return sendRequestToOctoprint("GET", command, NULL); } @@ -271,7 +268,7 @@ bool OctoprintApi::getPrintJob() { printJob.jobFileDate = root["job"]["file"]["date"]; printJob.jobFileName = (const char *)(root["job"]["file"]["name"] | ""); printJob.jobFileOrigin = (const char *)(root["job"]["file"]["origin"] | ""); - printJob.jobFileSize = root["job"]["file"]["size"]; + printJob.jobFileSize = root["job"]["file"]["size"] | 0; printJob.jobFilamentTool0Length = root["job"]["filament"]["tool0"]["length"] | 0; printJob.jobFilamentTool0Volume = root["job"]["filament"]["tool0"]["volume"] | 0.0; @@ -280,9 +277,9 @@ bool OctoprintApi::getPrintJob() { } if (root.containsKey("progress")) { printJob.progressCompletion = root["progress"]["completion"] | 0.0; - printJob.progressFilepos = root["progress"]["filepos"]; - printJob.progressPrintTime = root["progress"]["printTime"]; - printJob.progressPrintTimeLeft = root["progress"]["printTimeLeft"]; + printJob.progressFilepos = root["progress"]["filepos"] | 0; + printJob.progressPrintTime = root["progress"]["printTime"] | 0; + printJob.progressPrintTimeLeft = root["progress"]["printTimeLeft"] | 0; printJob.progressprintTimeLeftOrigin = (const char *)root["progress"]["printTimeLeftOrigin"]; } return true; @@ -294,8 +291,7 @@ bool OctoprintApi::getPrintJob() { * General function to get any GET endpoint of the API and return body as a string for you to format or view as you wish. * */ String OctoprintApi::getOctoprintEndpointResults(String command) { - if (_debug) - Serial.println("OctoprintApi::getOctoprintEndpointResults() CALLED"); + if (_debug) Serial.println("OctoprintApi::getOctoprintEndpointResults() CALLED"); return sendGetToOctoprint("/api/" + command); } @@ -303,8 +299,7 @@ String OctoprintApi::getOctoprintEndpointResults(String command) { * * **/ String OctoprintApi::sendPostToOctoPrint(String command, const char *postData) { - if (_debug) - Serial.println("OctoprintApi::sendPostToOctoPrint() CALLED"); + if (_debug) Serial.println("OctoprintApi::sendPostToOctoPrint() CALLED"); return sendRequestToOctoprint("POST", command, postData); } @@ -377,8 +372,6 @@ bool OctoprintApi::octoPrintPrintHeadRelativeJog(double x, double y, double z, d } strncat(postData, ", \"absolute\": false", TEMPDATA_SIZE); strncat(postData, " }", TEMPDATA_SIZE); - if (_debug) - Serial.println(postData); sendPostToOctoPrint("/api/printer/printhead", postData); return (httpStatusCode == 204); @@ -533,7 +526,6 @@ void OctoprintApi::sendHeader(const String type, const String command, const cha _client->print("X-Api-Key: "); _client->println(_apiKey); _client->println(_useragent); - _client->println("Connection: keep-alive"); if (data != NULL) { _client->println("Content-Type: application/json"); _client->print("Content-Length: "); From 87c7acddbf39ee79f8eac3c7615d3b27b2ad5ab2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric?= Date: Wed, 3 Jun 2020 13:06:53 +0200 Subject: [PATCH 08/11] Minor debugging and cleaning. Remove a potential bug if the server disconnect while waiting or reading data. --- OctoPrintAPI.cpp | 57 ++++++++++++++++++------------------------------ OctoPrintAPI.h | 12 +++++----- 2 files changed, 27 insertions(+), 42 deletions(-) diff --git a/OctoPrintAPI.cpp b/OctoPrintAPI.cpp index 65b540c..1e701d1 100644 --- a/OctoPrintAPI.cpp +++ b/OctoPrintAPI.cpp @@ -4,7 +4,6 @@ | |_| | (__| || (_) | __/| | | | | | | |_ / ___ \| __/| | \___/ \___|\__\___/|_| |_| |_|_| |_|\__/_/ \_\_| |___| .......By Stephen Ludgate https://www.chunkymedia.co.uk....... - */ #include "OctoPrintAPI.h" @@ -13,7 +12,7 @@ /** OctoprintApi() * IP address version of the client connect function - * */ + **/ OctoprintApi::OctoprintApi(Client &client, IPAddress octoPrintIp, uint16_t octoPrintPort, String apiKey) { _client = &client; _apiKey = apiKey; @@ -25,7 +24,7 @@ OctoprintApi::OctoprintApi(Client &client, IPAddress octoPrintIp, uint16_t octoP /** OctoprintApi() * Hostname version of the client connect function - * */ + **/ OctoprintApi::OctoprintApi(Client &client, char *octoPrintUrl, uint16_t octoPrintPort, String apiKey) { _client = &client; _apiKey = apiKey; @@ -35,9 +34,8 @@ OctoprintApi::OctoprintApi(Client &client, char *octoPrintUrl, uint16_t octoPrin snprintf(_useragent, USER_AGENT_SIZE, "User-Agent: %s", USER_AGENT); } -/** GET YOUR ASS TO OCTOPRINT... - * - * **/ +/* GET YOUR ASS TO OCTOPRINT... + */ String OctoprintApi::sendRequestToOctoprint(String type, String command, const char *data) { if (_debug) Serial.println("OctoprintApi::sendRequestToOctoprint() CALLED"); @@ -50,14 +48,13 @@ String OctoprintApi::sendRequestToOctoprint(String type, String command, const c char c = 0; uint32_t bodySize = 0; unsigned long start_waiting = 0; - bool connected = false; if (_usingIpAddress) - connected = _client->connect(_octoPrintIp, _octoPrintPort); + _client->connect(_octoPrintIp, _octoPrintPort); else - connected = _client->connect(_octoPrintUrl, _octoPrintPort); + _client->connect(_octoPrintUrl, _octoPrintPort); - if (!connected) { + if (!_client->connected()) { if (_debug) Serial.println("connection failed."); closeClient(); return ""; @@ -66,34 +63,32 @@ String OctoprintApi::sendRequestToOctoprint(String type, String command, const c sendHeader(type, command, data); - start_waiting = millis(); if (_debug) Serial.println("Request sent. Waiting for the answer."); - - while (!_client->available() && OPAPI_RUN_TIMEOUT) // wait for a reply + start_waiting = millis(); + while (_client->connected() && !_client->available() && OPAPI_RUN_TIMEOUT) // wait for a reply delay(1); - if (!_client->available()) { + if (!_client->connected() || !_client->available()) { if (_debug) Serial.println("Timeout during waiting for a reply"); closeClient(); return ""; } - // Read Status code if (_debug) Serial.println("Reading status code"); - while (_client->available() && (c = _client->read()) != '\n' && OPAPI_RUN_TIMEOUT) + while (_client->connected() && _client->available() && (c = _client->read()) != '\n' && OPAPI_RUN_TIMEOUT) buffer = buffer + c; httpStatusCode = extractHttpCode(buffer); if (_debug) { - Serial.print("httpCode:"); + Serial.print("HTTP code:"); Serial.println(httpStatusCode); } if (!(200 <= httpStatusCode && httpStatusCode < 204) && httpStatusCode != 409) { // Code 204 NO CONTENT is ok, we close and return closeClient(); return ""; } - // Read headers + if (_debug) Serial.println("Reading headers"); - for (buffer = ""; _client->available() && OPAPI_RUN_TIMEOUT;) { // read headers + for (buffer = ""; _client->connected() && _client->available() && OPAPI_RUN_TIMEOUT;) { c = _client->read(); buffer = buffer + c; if (_debug) Serial.print(c); @@ -105,14 +100,9 @@ String OctoprintApi::sendRequestToOctoprint(String type, String command, const c buffer = ""; } } - if (!bodySize) { - if (_debug) Serial.println("Header 'Content-Length' not found"); - closeClient(); - return ""; - } if (_debug) Serial.println("Reading body"); - for (buffer = ""; _client->available() && bodySize-- && OPAPI_RUN_TIMEOUT;) + for (buffer = ""; _client->connected() && _client->available() && bodySize-- && OPAPI_RUN_TIMEOUT;) buffer = buffer + (char)_client->read(); if (_debug) Serial.println(buffer); @@ -122,7 +112,6 @@ String OctoprintApi::sendRequestToOctoprint(String type, String command, const c String OctoprintApi::sendGetToOctoprint(String command) { if (_debug) Serial.println("OctoprintApi::sendGetToOctoprint() CALLED"); - return sendRequestToOctoprint("GET", command, NULL); } @@ -296,7 +285,6 @@ String OctoprintApi::getOctoprintEndpointResults(String command) { } /** POST TIME - * * **/ String OctoprintApi::sendPostToOctoPrint(String command, const char *postData) { if (_debug) Serial.println("OctoprintApi::sendPostToOctoPrint() CALLED"); @@ -333,16 +321,16 @@ bool OctoprintApi::octoPrintConnectionFakeAck() { * Upon success, a status code of 204 No Content and an empty body is returned. * */ bool OctoprintApi::octoPrintPrintHeadHome() { - // { - // "command": "home", - // "axes": ["x", "y", "z"] + // { + // "command": "home", + // "axes": ["x", "y", "z"] // } sendPostToOctoPrint("/api/printer/printhead", "{\"command\": \"home\",\"axes\": [\"x\", \"y\"]}"); return (httpStatusCode == 204); } bool OctoprintApi::octoPrintPrintHeadRelativeJog(double x, double y, double z, double f) { - // { + // { // "command": "jog", // "x": 10, // "y": -5, @@ -463,8 +451,7 @@ If SD support has been disabled in OctoPrint’s settings, a 404 Not Found is re Returns a 200 OK with an SD State Response in the body upon success. */ bool OctoprintApi::octoPrintGetPrinterSD() { - String command = "/api/printer/sd"; - String response = sendGetToOctoprint(command); + String response = sendGetToOctoprint("/api/printer/sd"); StaticJsonDocument root; if (!deserializeJson(root, response)) { @@ -481,17 +468,15 @@ Sends any command to the printer via the serial interface. Should be used with s If successful returns a 204 No Content and an empty body. */ bool OctoprintApi::octoPrintPrinterCommand(const char *gcodeCommand) { - String command = "/api/printer/command"; char postData[POSTDATA_SIZE]; snprintf(postData, POSTDATA_SIZE, "{\"command\": \"%s\"}", gcodeCommand); - sendPostToOctoPrint(command, postData); + sendPostToOctoPrint("/api/printer/command", postData); return (httpStatusCode == 204); } /***** GENERAL FUNCTIONS *****/ - /** * Close the client * */ diff --git a/OctoPrintAPI.h b/OctoPrintAPI.h index 0a671fe..4771951 100644 --- a/OctoPrintAPI.h +++ b/OctoPrintAPI.h @@ -15,13 +15,13 @@ #include #define OPAPI_TIMEOUT 3000 // 3s timetout -#define OPAPI_RUN_TIMEOUT (millis() - start_waiting < OPAPI_TIMEOUT && start_waiting <= millis()) +#define OPAPI_RUN_TIMEOUT (millis() - start_waiting < OPAPI_TIMEOUT) && (start_waiting <= millis()) -#define POSTDATA_SIZE 128 -#define TEMPDATA_SIZE 24 -#define JSONDOCUMENT_SIZE 1024 -#define USER_AGENT "OctoPrintAPI/1.1.4 (Arduino)" -#define USER_AGENT_SIZE 64 +#define POSTDATA_SIZE 128 +#define TEMPDATA_SIZE 24 +#define JSONDOCUMENT_SIZE 1024 +#define USER_AGENT "OctoPrintAPI/1.1.4 (Arduino)" +#define USER_AGENT_SIZE 64 struct printerStatistics { String printerState; From 7df595a99a5690bc4b682fea2b42cb868fe4e1d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric?= Date: Thu, 4 Jun 2020 22:54:33 +0200 Subject: [PATCH 09/11] waiting delay has been changed to 100ms. fast calls to available() can cash WifiNINA driver --- OctoPrintAPI.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OctoPrintAPI.cpp b/OctoPrintAPI.cpp index 1e701d1..4a51869 100644 --- a/OctoPrintAPI.cpp +++ b/OctoPrintAPI.cpp @@ -66,7 +66,7 @@ String OctoprintApi::sendRequestToOctoprint(String type, String command, const c if (_debug) Serial.println("Request sent. Waiting for the answer."); start_waiting = millis(); while (_client->connected() && !_client->available() && OPAPI_RUN_TIMEOUT) // wait for a reply - delay(1); + delay(100); if (!_client->connected() || !_client->available()) { if (_debug) Serial.println("Timeout during waiting for a reply"); closeClient(); From bf7b39f5e6d4a7f73d5967450782eac644864de5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric?= Date: Sat, 6 Jun 2020 20:56:16 +0200 Subject: [PATCH 10/11] Add octoPrintSetTemperatures() and octoPrintCoolDown() --- OctoPrintAPI.cpp | 10 ++++++++++ OctoPrintAPI.h | 2 ++ 2 files changed, 12 insertions(+) diff --git a/OctoPrintAPI.cpp b/OctoPrintAPI.cpp index 4a51869..39bc725 100644 --- a/OctoPrintAPI.cpp +++ b/OctoPrintAPI.cpp @@ -397,6 +397,16 @@ bool OctoprintApi::octoPrintSetTool1Temperature(uint16_t t) { return (httpStatusCode == 204); } +bool OctoprintApi::octoPrintSetTemperatures(uint16_t tool0, uint16_t tool1, uint16_t bed) { + char postData[POSTDATA_SIZE]; + snprintf(postData, POSTDATA_SIZE, + "{ \"command\": \"target\", \"targets\": { \"tool0\": %d, \"tool1\": %d, \"bed\": %d } }", + tool0, tool1, bed); + + sendPostToOctoPrint("/api/printer/tool", postData); + return (httpStatusCode == 204); +} + /***** PRINT BED *****/ /** octoPrintGetPrinterBed() * http://docs.octoprint.org/en/master/api/printer.html#retrieve-the-current-bed-state diff --git a/OctoPrintAPI.h b/OctoPrintAPI.h index 4771951..641190d 100644 --- a/OctoPrintAPI.h +++ b/OctoPrintAPI.h @@ -111,6 +111,8 @@ class OctoprintApi { bool octoPrintSetBedTemperature(uint16_t t); bool octoPrintSetTool0Temperature(uint16_t t); bool octoPrintSetTool1Temperature(uint16_t t); + bool octoPrintSetTemperatures(uint16_t tool0 = 0, uint16_t tool1 = 0, uint16_t bed = 0); + bool octoPrintCoolDown() { return octoPrintSetTemperatures(); }; bool octoPrintGetPrinterSD(); bool octoPrintPrinterSDInit(); From c963a348f4e69d8232fcb58c1b01551605d8bed6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric?= Date: Sat, 6 Jun 2020 21:20:13 +0200 Subject: [PATCH 11/11] Add octoPrintGetPrinterChamber() and octoPrintSetChamberTemperature(). Not really tested and I don't have a chamber. --- OctoPrintAPI.cpp | 47 ++++++++++++++++++++++++++++++++++++++++++----- OctoPrintAPI.h | 13 +++++++++++++ 2 files changed, 55 insertions(+), 5 deletions(-) diff --git a/OctoPrintAPI.cpp b/OctoPrintAPI.cpp index 39bc725..d6a13f0 100644 --- a/OctoPrintAPI.cpp +++ b/OctoPrintAPI.cpp @@ -367,46 +367,54 @@ bool OctoprintApi::octoPrintPrintHeadRelativeJog(double x, double y, double z, d bool OctoprintApi::octoPrintExtrude(double amount) { char postData[POSTDATA_SIZE]; + snprintf(postData, POSTDATA_SIZE, "{ \"command\": \"extrude\", \"amount\": %.2f }", amount); - sendPostToOctoPrint("/api/printer/tool", postData); return (httpStatusCode == 204); } bool OctoprintApi::octoPrintSetBedTemperature(uint16_t t) { char postData[POSTDATA_SIZE]; - snprintf(postData, POSTDATA_SIZE, "{ \"command\": \"target\", \"target\": %d }", t); + snprintf(postData, POSTDATA_SIZE, "{ \"command\": \"target\", \"target\": %d }", t); sendPostToOctoPrint("/api/printer/bed", postData); return (httpStatusCode == 204); } bool OctoprintApi::octoPrintSetTool0Temperature(uint16_t t) { char postData[POSTDATA_SIZE]; - snprintf(postData, POSTDATA_SIZE, "{ \"command\": \"target\", \"targets\": { \"tool0\": %d } }", t); + snprintf(postData, POSTDATA_SIZE, "{ \"command\": \"target\", \"targets\": { \"tool0\": %d } }", t); sendPostToOctoPrint("/api/printer/tool", postData); return (httpStatusCode == 204); } bool OctoprintApi::octoPrintSetTool1Temperature(uint16_t t) { char postData[POSTDATA_SIZE]; - snprintf(postData, POSTDATA_SIZE, "{ \"command\": \"target\", \"targets\": { \"tool1\": %d } }", t); + snprintf(postData, POSTDATA_SIZE, "{ \"command\": \"target\", \"targets\": { \"tool1\": %d } }", t); sendPostToOctoPrint("/api/printer/tool", postData); return (httpStatusCode == 204); } bool OctoprintApi::octoPrintSetTemperatures(uint16_t tool0, uint16_t tool1, uint16_t bed) { char postData[POSTDATA_SIZE]; + snprintf(postData, POSTDATA_SIZE, "{ \"command\": \"target\", \"targets\": { \"tool0\": %d, \"tool1\": %d, \"bed\": %d } }", tool0, tool1, bed); - sendPostToOctoPrint("/api/printer/tool", postData); return (httpStatusCode == 204); } +bool OctoprintApi::octoPrintSetChamberTemperature(uint16_t t) { + char postData[POSTDATA_SIZE]; + + snprintf(postData, POSTDATA_SIZE, "{ \"command\": \"target\", \"target\": %d }", t); + sendPostToOctoPrint("/api/printer/chamber", postData); + return (httpStatusCode == 204); +} + /***** PRINT BED *****/ /** octoPrintGetPrinterBed() * http://docs.octoprint.org/en/master/api/printer.html#retrieve-the-current-bed-state @@ -429,6 +437,35 @@ bool OctoprintApi::octoPrintGetPrinterBed() { if (root.containsKey("history")) { printerBed.printerBedTempHistoryTimestamp = root["history"][0]["time"]; printerBed.printerBedTempHistoryActual = root["history"][0]["bed"]["actual"]; + printerBed.printerBedTempHistoryTarget = root["history"][0]["bed"]["target"]; + } + return true; + } + return false; +} +/***** PRINT CHAMBER *****/ +/** octoPrintGetPrinterChamber() + * https://docs.octoprint.org/en/master/api/printer.html#retrieve-the-current-chamber-state + * Retrieves the current temperature data (actual, target and offset) plus optionally a (limited) history (actual, target, timestamp) for the printer’s heated bed. + * It’s also possible to retrieve the temperature history by supplying the history query parameter set to true. + * The amount of returned history data points can be limited using the limit query parameter. + * Returns a 200 OK with a Temperature Response in the body upon success. + * If no heated chamber is configured for the currently selected printer profile, the resource will return an 409 Conflict. + * */ +bool OctoprintApi::octoPrintGetPrinterChamber() { + String response = sendGetToOctoprint("/api/printer/chamber?history=true&limit=2"); + + StaticJsonDocument root; + if (!deserializeJson(root, response)) { + if (root.containsKey("chamber")) { + printerChamber.printerChamberTempActual = root["chamber"]["actual"]; + printerChamber.printerChamberTempOffset = root["chamber"]["offset"]; + printerChamber.printerChamberTempTarget = root["chamber"]["target"]; + } + if (root.containsKey("history")) { + printerChamber.printerChamberTempHistoryTimestamp = root["history"][0]["time"]; + printerChamber.printerChamberTempHistoryActual = root["history"][0]["chamber"]["actual"]; + printerChamber.printerChamberTempHistoryTarget = root["history"][0]["chamber"]["target"]; } return true; } diff --git a/OctoPrintAPI.h b/OctoPrintAPI.h index 641190d..ca35459 100644 --- a/OctoPrintAPI.h +++ b/OctoPrintAPI.h @@ -84,6 +84,15 @@ struct printerBedCall { float printerBedTempTarget; long printerBedTempHistoryTimestamp; float printerBedTempHistoryActual; + float printerBedTempHistoryTarget; +}; +struct printerChamberCall { + float printerChamberTempActual; + float printerChamberTempOffset; + float printerChamberTempTarget; + long printerChamberTempHistoryTimestamp; + float printerChamberTempHistoryActual; + float printerChamberTempHistoryTarget; }; class OctoprintApi { @@ -113,6 +122,7 @@ class OctoprintApi { bool octoPrintSetTool1Temperature(uint16_t t); bool octoPrintSetTemperatures(uint16_t tool0 = 0, uint16_t tool1 = 0, uint16_t bed = 0); bool octoPrintCoolDown() { return octoPrintSetTemperatures(); }; + bool octoPrintSetChamberTemperature(uint16_t t); bool octoPrintGetPrinterSD(); bool octoPrintPrinterSDInit(); @@ -121,6 +131,9 @@ class OctoprintApi { bool octoPrintGetPrinterBed(); printerBedCall printerBed; + + bool octoPrintGetPrinterChamber(); + printerChamberCall printerChamber; bool octoPrintJobStart(); bool octoPrintJobCancel();