diff --git a/OctoPrintAPI.cpp b/OctoPrintAPI.cpp index 96ac8a4..d6a13f0 100644 --- a/OctoPrintAPI.cpp +++ b/OctoPrintAPI.cpp @@ -4,7 +4,6 @@ | |_| | (__| || (_) | __/| | | | | | | |_ / ___ \| __/| | \___/ \___|\__\___/|_| |_| |_|_| |_|\__/_/ \_\_| |___| .......By Stephen Ludgate https://www.chunkymedia.co.uk....... - */ #include "OctoPrintAPI.h" @@ -13,154 +12,106 @@ /** 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; _octoPrintPort = octoPrintPort; _usingIpAddress = true; + snprintf(_useragent, USER_AGENT_SIZE, "User-Agent: %s", USER_AGENT); } /** 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; _octoPrintPort = octoPrintPort; _usingIpAddress = false; + 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"); + 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 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; + uint32_t bodySize = 0; + unsigned long start_waiting = 0; if (_usingIpAddress) - connected = _client->connect(_octoPrintIp, _octoPrintPort); + _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(); - while (millis() - now < OPAPI_TIMEOUT) { - 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); - } + _client->connect(_octoPrintUrl, _octoPrintPort); + + if (!_client->connected()) { + if (_debug) Serial.println("connection failed."); + closeClient(); + return ""; } + if (_debug) Serial.println("...connected to server."); - closeClient(); + sendHeader(type, command, data); - int httpCode = extractHttpCode(statusCode, body); + 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(100); + if (!_client->connected() || !_client->available()) { + if (_debug) Serial.println("Timeout during waiting for a reply"); + closeClient(); + return ""; + } + + if (_debug) Serial.println("Reading status code"); + while (_client->connected() && _client->available() && (c = _client->read()) != '\n' && OPAPI_RUN_TIMEOUT) + buffer = buffer + c; + + httpStatusCode = extractHttpCode(buffer); if (_debug) { - Serial.print("\nhttpCode:"); - Serial.println(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 ""; + } + + if (_debug) Serial.println("Reading headers"); + for (buffer = ""; _client->connected() && _client->available() && OPAPI_RUN_TIMEOUT;) { + 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 = ""; + } } - httpStatusCode = httpCode; - return body; + if (_debug) Serial.println("Reading body"); + for (buffer = ""; _client->connected() && _client->available() && bodySize-- && OPAPI_RUN_TIMEOUT;) + buffer = buffer + (char)_client->read(); + if (_debug) Serial.println(buffer); + + closeClient(); + return buffer; } String OctoprintApi::sendGetToOctoprint(String command) { - if (_debug) - Serial.println("OctoprintApi::sendGetToOctoprint() CALLED"); - + if (_debug) Serial.println("OctoprintApi::sendGetToOctoprint() CALLED"); return sendRequestToOctoprint("GET", command, NULL); } @@ -306,7 +257,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; @@ -315,9 +266,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; @@ -329,17 +280,14 @@ 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); } /** POST TIME - * * **/ 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); } @@ -373,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, @@ -390,31 +338,28 @@ bool OctoprintApi::octoPrintPrintHeadRelativeJog(double x, double y, double z, d // "absolute": false, // "speed": 30 // } - char postData[1024]; - char tmp[128]; - postData[0] = '\0'; + char postData[POSTDATA_SIZE]; + char tmp[TEMPDATA_SIZE]; - strcat(postData, "{\"command\": \"jog\""); + strncpy(postData, "{\"command\": \"jog\"", POSTDATA_SIZE); if (x != 0) { - snprintf(tmp, 128, ", \"x\": %f", x); - strcat(postData, tmp); + snprintf(tmp, TEMPDATA_SIZE, ", \"x\": %.2f", x); + strncat(postData, tmp, TEMPDATA_SIZE); } if (y != 0) { - snprintf(tmp, 128, ", \"y\": %f", y); - strcat(postData, tmp); + snprintf(tmp, TEMPDATA_SIZE, ", \"y\": %.2f", y); + strncat(postData, tmp, TEMPDATA_SIZE); } if (z != 0) { - snprintf(tmp, 128, ", \"z\": %f", z); - strcat(postData, tmp); + snprintf(tmp, TEMPDATA_SIZE, ", \"z\": %.2f", z); + strncat(postData, tmp, TEMPDATA_SIZE); } if (f != 0) { - snprintf(tmp, 128, ", \"speed\": %f", f); - strcat(postData, tmp); + snprintf(tmp, TEMPDATA_SIZE, ", \"speed\": %.2f", f); + strncat(postData, tmp, TEMPDATA_SIZE); } - strcat(postData, ", \"absolute\": false"); - strcat(postData, " }"); - if (_debug) - Serial.println(postData); + strncat(postData, ", \"absolute\": false", TEMPDATA_SIZE); + strncat(postData, " }", TEMPDATA_SIZE); sendPostToOctoPrint("/api/printer/printhead", postData); return (httpStatusCode == 204); @@ -422,36 +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\": %f }", amount); - + + 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); + 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 @@ -474,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; } @@ -506,13 +498,11 @@ 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)) { - bool printerStatesdReady = root["ready"]; - printerStats.printerStatesdReady = printerStatesdReady; + printerStats.printerStatesdReady = root["ready"]; return true; } return false; @@ -524,20 +514,16 @@ 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) { - String command = "/api/printer/command"; - char postData[POSTDATA_GCODE_SIZE]; - - postData[0] = '\0'; - snprintf(postData, POSTDATA_GCODE_SIZE, "{\"command\": \"%s\"}", gcodeCommand); +bool OctoprintApi::octoPrintPrinterCommand(const char *gcodeCommand) { + char postData[POSTDATA_SIZE]; - sendPostToOctoPrint(command, postData); + snprintf(postData, POSTDATA_SIZE, "{\"command\": \"%s\"}", gcodeCommand); + sendPostToOctoPrint("/api/printer/command", postData); return (httpStatusCode == 204); } /***** GENERAL FUNCTIONS *****/ - /** * Close the client * */ @@ -547,25 +533,37 @@ 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(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); } - 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)); - if (body != "") - Serial.println(" - " + body); - else - Serial.println(); - } - 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; } + +/** + * 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); + 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 8db182d..ca35459 100644 --- a/OctoPrintAPI.h +++ b/OctoPrintAPI.h @@ -14,11 +14,14 @@ #include #include -#define OPAPI_TIMEOUT 3000 -#define POSTDATA_SIZE 256 -#define POSTDATA_GCODE_SIZE 50 -#define JSONDOCUMENT_SIZE 1024 -#define USER_AGENT "OctoPrintAPI/1.1.4 (Arduino)" +#define OPAPI_TIMEOUT 3000 // 3s timetout +#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 struct printerStatistics { String printerState; @@ -81,12 +84,21 @@ 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 { 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(); @@ -95,9 +107,9 @@ class OctoprintApi { octoprintVersion octoprintVer; bool getPrintJob(); printJobCall printJob; - bool _debug = false; - int httpStatusCode = 0; - String httpErrorBody = ""; + bool _debug = false; + uint16_t httpStatusCode = 0; + String sendPostToOctoPrint(String command, const char *postData); bool octoPrintConnectionDisconnect(); bool octoPrintConnectionAutoConnect(); @@ -108,6 +120,9 @@ 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 octoPrintSetChamberTemperature(uint16_t t); bool octoPrintGetPrinterSD(); bool octoPrintPrinterSDInit(); @@ -116,6 +131,9 @@ class OctoprintApi { bool octoPrintGetPrinterBed(); printerBedCall printerBed; + + bool octoPrintGetPrinterChamber(); + printerChamberCall printerChamber; bool octoPrintJobStart(); bool octoPrintJobCancel(); @@ -125,7 +143,7 @@ class OctoprintApi { bool octoPrintJobResume(); bool octoPrintFileSelect(String &path); - bool octoPrintPrinterCommand(char *gcodeCommand); + bool octoPrintPrinterCommand(const char *gcodeCommand); private: Client *_client; @@ -133,11 +151,13 @@ class OctoprintApi { IPAddress _octoPrintIp; bool _usingIpAddress; char *_octoPrintUrl; - int _octoPrintPort; - const int maxMessageLength = 1000; + uint16_t _octoPrintPort; + char _useragent[USER_AGENT_SIZE]; + void closeClient(); - int extractHttpCode(String statusCode, String body); - String sendRequestToOctoprint(String type, String command, const char *data); + void sendHeader(const String type, const String command, const char *data); + int extractHttpCode(const String statusCode); + String sendRequestToOctoprint(const String type, const String command, const char *data); }; #endif