From 8521664a697a7d127c116d3dc625622f3236f15e Mon Sep 17 00:00:00 2001 From: suchmememanyskill <38142618+suchmememanyskill@users.noreply.github.com> Date: Sat, 16 Nov 2024 22:51:17 +0100 Subject: [PATCH] Fetch data from octoprint --- .../src/core/bambu/bambu_printer_parsers.cpp | 2 +- .../octoprint_printer_integration.cpp | 119 ++++++++++++++++-- .../octoprint_printer_integration.hpp | 13 +- .../octoprint/octoprint_printer_parsers.cpp | 103 ++++++++++++++- CYD-Klipper/src/core/printer_integration.hpp | 2 + CYD-Klipper/src/ui/ip_setup.cpp | 2 +- CYD-Klipper/src/ui/panels/macros_panel.cpp | 11 +- 7 files changed, 236 insertions(+), 16 deletions(-) diff --git a/CYD-Klipper/src/core/bambu/bambu_printer_parsers.cpp b/CYD-Klipper/src/core/bambu/bambu_printer_parsers.cpp index 3add9df..60bed9e 100644 --- a/CYD-Klipper/src/core/bambu/bambu_printer_parsers.cpp +++ b/CYD-Klipper/src/core/bambu/bambu_printer_parsers.cpp @@ -63,7 +63,7 @@ void BambuPrinter::parse_state(JsonDocument& in) if (print.containsKey("nozzle_temper")) { printer_data.temperatures[PrinterTemperatureDeviceIndexNozzle1] = print["nozzle_temper"]; - printer_data.can_extrude = printer_data.temperatures[PrinterTemperatureDeviceIndexNozzle1] > 175; + printer_data.can_extrude = printer_data.temperatures[PrinterTemperatureDeviceIndexNozzle1] >= MIN_EXTRUDER_EXTRUDE_TEMP; } if (print.containsKey("nozzle_target_temper")) diff --git a/CYD-Klipper/src/core/octoprint/octoprint_printer_integration.cpp b/CYD-Klipper/src/core/octoprint/octoprint_printer_integration.cpp index 2a272e3..d8587d8 100644 --- a/CYD-Klipper/src/core/octoprint/octoprint_printer_integration.cpp +++ b/CYD-Klipper/src/core/octoprint/octoprint_printer_integration.cpp @@ -5,6 +5,9 @@ #include #include +const char* COMMAND_CONNECT = "{\"command\":\"connect\"}"; +const char* COMMAND_DISCONNECT = "{\"command\":\"disconnect\"}"; + void configure_http_client(HTTPClient &client, String url_part, bool stream, int timeout, PrinterConfiguration* printer_config) { client.useHTTP10(stream); @@ -21,7 +24,7 @@ void configure_http_client(HTTPClient &client, String url_part, bool stream, int } } -bool OctoPrinter::make_request(const char* endpoint, HttpRequestType requestType, int timeout_ms, bool stream) +bool OctoPrinter::get_request(const char* endpoint, int timeout_ms, bool stream) { HTTPClient client; @@ -35,7 +38,7 @@ bool OctoPrinter::make_request(const char* endpoint, HttpRequestType requestType return result >= 200 && result < 300; } -bool OctoPrinter::make_request(JsonDocument& doc, const char* endpoint, HttpRequestType requestType, int timeout_ms, bool stream) +bool OctoPrinter::post_request(const char* endpoint, const char* body, int timeout_ms, bool stream) { HTTPClient client; @@ -45,14 +48,18 @@ bool OctoPrinter::make_request(JsonDocument& doc, const char* endpoint, HttpRequ } configure_http_client(client, endpoint, stream, timeout_ms, printer_config); - int result = client.GET(); - if (result >= 200 && result < 300) + if (body[0] == '{' || body[0] == '[') { - auto result = deserializeJson(doc, client.getStream()); - return result == DeserializationError::Ok; + client.addHeader("Content-Type", "application/json"); } + int result = client.POST(body); + return result >= 200 && result < 300; +} + +bool OctoPrinter::send_gcode(const char* gcode, bool wait) +{ return false; } @@ -63,17 +70,77 @@ bool OctoPrinter::move_printer(const char* axis, float amount, bool relative) bool OctoPrinter::execute_feature(PrinterFeatures feature) { + switch (feature) + { + case PrinterFeatureRetryError: + if (no_printer) + { + bool a = post_request("/api/connection", COMMAND_CONNECT); + LOG_F(("Retry error: %d\n", a)); + return a; + } + default: + LOG_F(("Unsupported printer feature %d", feature)); + break; + } + return false; } bool OctoPrinter::connect() { - return false; + return connection_test_octoprint(printer_config) == OctoConnectionStatus::OctoConnectOk; } bool OctoPrinter::fetch() { - return false; + HTTPClient client; + HTTPClient client2; + configure_http_client(client, "/api/printer", true, 1000, printer_config); + + int http_code = client.GET(); + + if (http_code == 200) + { + no_printer = false; + request_consecutive_fail_count = 0; + JsonDocument doc; + deserializeJson(doc, client.getStream()); + parse_printer_state(doc); + + doc.clear(); + configure_http_client(client2, "/api/job", true, 1000, printer_config); + if (client2.GET() == 200) + { + deserializeJson(doc, client2.getStream()); + parse_job_state(doc); + } + else + { + printer_data.state = PrinterStateOffline; + return false; + } + } + else if (http_code == 409) + { + no_printer = true; + JsonDocument doc; + deserializeJson(doc, client.getStream()); + parse_error(doc); + } + else + { + request_consecutive_fail_count++; + LOG_LN("Failed to fetch printer data"); + + if (request_consecutive_fail_count >= 5) + { + printer_data.state = PrinterStateOffline; + return false; + } + } + + return true; } PrinterDataMinimal OctoPrinter::fetch_min() @@ -86,18 +153,50 @@ void OctoPrinter::disconnect() } +const char* MACRO_AUTOLEVEL = "Auto-Level (G28+G29)"; +const char* MACRO_DISCONNECT = "Disconnect printer"; + Macros OctoPrinter::get_macros() { - return {}; + if (printer_data.state == PrinterStatePrinting || printer_data.state == PrinterStateOffline) + { + Macros macros = {0}; + macros.success = false; + return macros; + } + + Macros macros = {0}; + macros.count = 2; + macros.macros = (char **)malloc(sizeof(char *) * macros.count); + macros.macros[0] = (char *)malloc(strlen(MACRO_AUTOLEVEL) + 1); + strcpy(macros.macros[0], MACRO_AUTOLEVEL); + macros.macros[1] = (char *)malloc(strlen(MACRO_DISCONNECT) + 1); + strcpy(macros.macros[1], MACRO_DISCONNECT); + macros.success = true; + return macros; } int OctoPrinter::get_macros_count() { - return 0; + return (printer_data.state == PrinterStatePrinting || printer_data.state == PrinterStateOffline) ? 0 : 2; } bool OctoPrinter::execute_macro(const char* macro) { + if (strcmp(macro, MACRO_AUTOLEVEL) == 0) + { + return send_gcode("G28\nG29"); + } + else if (strcmp(macro, MACRO_DISCONNECT) == 0) + { + if (printer_data.state == PrinterStatePrinting || printer_data.state == PrinterStateOffline) + { + return false; + } + + return post_request("/api/connection", COMMAND_DISCONNECT); + } + return false; } diff --git a/CYD-Klipper/src/core/octoprint/octoprint_printer_integration.hpp b/CYD-Klipper/src/core/octoprint/octoprint_printer_integration.hpp index acea923..43f0183 100644 --- a/CYD-Klipper/src/core/octoprint/octoprint_printer_integration.hpp +++ b/CYD-Klipper/src/core/octoprint/octoprint_printer_integration.hpp @@ -5,8 +5,15 @@ class OctoPrinter : public BasePrinter { protected: - bool make_request(const char* endpoint, HttpRequestType requestType = HttpRequestType::HttpGet, int timeout_ms = 1000, bool stream = true); - bool make_request(JsonDocument& doc, const char* endpoint, HttpRequestType requestType = HttpRequestType::HttpGet, int timeout_ms = 1000, bool stream = true); + bool no_printer = false; + unsigned char request_consecutive_fail_count{}; + + void parse_printer_state(JsonDocument& in); + void parse_job_state(JsonDocument& in); + void parse_error(JsonDocument& in); + + bool get_request(const char* endpoint, int timeout_ms = 1000, bool stream = true); + bool post_request(const char* endpoint, const char* body, int timeout_ms = 1000, bool stream = false); public: OctoPrinter(int index) : BasePrinter(index) @@ -47,6 +54,8 @@ class OctoPrinter : public BasePrinter Thumbnail get_32_32_png_image_thumbnail(const char* gcode_filename); bool set_target_temperature(PrinterTemperatureDevice device, unsigned int temperature); + + bool send_gcode(const char* gcode, bool wait = true); }; enum OctoConnectionStatus { diff --git a/CYD-Klipper/src/core/octoprint/octoprint_printer_parsers.cpp b/CYD-Klipper/src/core/octoprint/octoprint_printer_parsers.cpp index c3b716e..1a43415 100644 --- a/CYD-Klipper/src/core/octoprint/octoprint_printer_parsers.cpp +++ b/CYD-Klipper/src/core/octoprint/octoprint_printer_parsers.cpp @@ -1,3 +1,104 @@ #include "../printer_integration.hpp" #include "octoprint_printer_integration.hpp" -#include \ No newline at end of file +#include + +void OctoPrinter::parse_printer_state(JsonDocument& in) +{ + auto flags = in["state"]["flags"]; + auto text = in["state"]["text"]; + + bool cancelling = flags["cancelling"]; + bool closedOrError = flags["closedOrError"]; + bool error = flags["error"]; + bool finishing = flags["finishing"]; + bool operational = flags["operational"]; + bool paused = flags["paused"]; + bool pausing = flags["pausing"]; + bool printing = flags["printing"]; + bool ready = flags["ready"]; + bool resuming = flags["resuming"]; + bool sdReady = flags["sdReady"]; + + if (printing || resuming) + { + printer_data.state = PrinterState::PrinterStatePrinting; + } + else if (pausing || paused) + { + printer_data.state = PrinterState::PrinterStatePaused; + } + else if (cancelling || finishing || ready) + { + printer_data.state = PrinterState::PrinterStateIdle; + } + else + { + if (text != NULL && (printer_data.state_message == NULL || strcmp(printer_data.state_message, text))) + { + printer_data.state_message = (char *)malloc(strlen(text) + 1); + strcpy(printer_data.state_message, text); + } + + printer_data.state = PrinterState::PrinterStateError; + } + + auto temperature = in["temperature"]; + + if (temperature.containsKey("bed")) + { + printer_data.temperatures[PrinterTemperatureDeviceIndexBed] = temperature["bed"]["actual"]; + printer_data.target_temperatures[PrinterTemperatureDeviceIndexBed] = temperature["bed"]["target"]; + } + + if (temperature.containsKey("tool0")) + { + printer_data.temperatures[PrinterTemperatureDeviceIndexNozzle1] = temperature["tool0"]["actual"]; + printer_data.target_temperatures[PrinterTemperatureDeviceIndexNozzle1] = temperature["tool0"]["target"]; + } + + printer_data.can_extrude = printer_data.temperatures[PrinterTemperatureDeviceIndexNozzle1] >= MIN_EXTRUDER_EXTRUDE_TEMP; + printer_data.homed_axis = true; +} + +void OctoPrinter::parse_job_state(JsonDocument& in) +{ + auto job = in["job"]; + + if (job.containsKey("file")) + { + const char* name = job["file"]["name"]; + + if (name != NULL && (printer_data.print_filename == NULL || strcmp(printer_data.print_filename, name))) + { + printer_data.print_filename = (char *)malloc(strlen(name) + 1); + strcpy(printer_data.print_filename, name); + } + } + + if (job.containsKey("filament") && job["filament"] != NULL && job["filament"].containsKey("tool0")) + { + printer_data.filament_used_mm = job["filament"]["tool0"]["length"]; + } + + auto progress = in["progress"]; + float completion = progress["completion"]; + printer_data.print_progress = completion / 100; + printer_data.elapsed_time_s = progress["printTime"]; + printer_data.printed_time_s = progress["printTime"]; + printer_data.remaining_time_s = progress["printTimeLeft"]; +} + +void OctoPrinter::parse_error(JsonDocument& in) +{ + const char* error = in["error"]; + if (error != NULL) + { + printer_data.state = PrinterState::PrinterStateError; + + if (printer_data.state_message == NULL || strcmp(printer_data.state_message, error)) + { + printer_data.state_message = (char *)malloc(strlen(error) + 1); + strcpy(printer_data.state_message, error); + } + } +} \ No newline at end of file diff --git a/CYD-Klipper/src/core/printer_integration.hpp b/CYD-Klipper/src/core/printer_integration.hpp index 058caf5..acab184 100644 --- a/CYD-Klipper/src/core/printer_integration.hpp +++ b/CYD-Klipper/src/core/printer_integration.hpp @@ -2,6 +2,8 @@ #include "../conf/global_config.h" #include +#define MIN_EXTRUDER_EXTRUDE_TEMP 175 + enum PrinterFeatures { PrinterFeatureRestart = BIT(0), PrinterFeatureFirmwareRestart = BIT(1), diff --git a/CYD-Klipper/src/ui/ip_setup.cpp b/CYD-Klipper/src/ui/ip_setup.cpp index ad893ca..32c310d 100644 --- a/CYD-Klipper/src/ui/ip_setup.cpp +++ b/CYD-Klipper/src/ui/ip_setup.cpp @@ -461,7 +461,7 @@ void choose_printer_type() lv_label_set_text(label, "Choose printer type"); create_printer_type_button(root, "Klipper", printer_type_klipper); - create_printer_type_button(root, "Klipper (Serial)", printer_type_serial_klipper, false); + create_printer_type_button(root, "Klipper (Serial/USB)", printer_type_serial_klipper, false); create_printer_type_button(root, "Bambu (Local)", printer_type_bambu_local); create_printer_type_button(root, "Octoprint", printer_type_octoprint); diff --git a/CYD-Klipper/src/ui/panels/macros_panel.cpp b/CYD-Klipper/src/ui/panels/macros_panel.cpp index eaccf58..49f5ded 100644 --- a/CYD-Klipper/src/ui/panels/macros_panel.cpp +++ b/CYD-Klipper/src/ui/panels/macros_panel.cpp @@ -30,7 +30,16 @@ void macros_panel_init(lv_obj_t* panel) { if (macros_count <= 0){ label = lv_label_create(root_panel); - lv_label_set_text(label, "No macros found.\nMacros with the description\n\"CYD_SCREEN_MACRO\"\nwill show up here."); + if (get_current_printer()->printer_config->printer_type == PrinterType::PrinterTypeKlipper + || get_current_printer()->printer_config->printer_type == PrinterType::PrinterTypeKlipper) + { + lv_label_set_text(label, "No macros found.\nMacros with the description\n\"CYD_SCREEN_MACRO\"\nwill show up here."); + } + else + { + lv_label_set_text(label, "No macros found."); + } + if (power_count <= 0){ lv_layout_flex_column(root_panel, LV_FLEX_ALIGN_CENTER);