From fd9ce76275e235726c6acc4c7e8c21320c539f48 Mon Sep 17 00:00:00 2001 From: Manuel Weiser Date: Sun, 2 Mar 2025 16:26:50 +0100 Subject: [PATCH] =?UTF-8?q?Verbessere=20die=20MQTT-Verbindung=20und=20Stat?= =?UTF-8?q?usverarbeitung=20in=20BambuVirtualPrinter=20mit=20robusteren=20?= =?UTF-8?q?Wiederverbindungsversuchen=20und=20erweiterter=20Statusverarbei?= =?UTF-8?q?tung=20f=C3=BCr=20unbekannte=20Druckzust=C3=A4nde.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../printer/bambu_virtual_printer.py | 86 ++++++++++++++++--- 1 file changed, 73 insertions(+), 13 deletions(-) diff --git a/octoprint_bambu_printer/printer/bambu_virtual_printer.py b/octoprint_bambu_printer/printer/bambu_virtual_printer.py index a8b7964..c4ca1b8 100644 --- a/octoprint_bambu_printer/printer/bambu_virtual_printer.py +++ b/octoprint_bambu_printer/printer/bambu_virtual_printer.py @@ -114,6 +114,14 @@ class BambuMqttBridgeClient: self._log.warning(f"Disconnected from MQTT broker with code: {rc}") self.connected = False + # Add reconnection attempt + if rc != 0: # Non-zero means unexpected disconnect + self._log.info("Attempting to reconnect to MQTT broker...") + try: + self._mqtt_client.reconnect() + except Exception as e: + self._log.error(f"Failed to reconnect to MQTT broker: {str(e)}", exc_info=True) + if hasattr(self, 'on_disconnect') and callable(self.on_disconnect): self.on_disconnect(client, userdata, rc) @@ -217,6 +225,16 @@ class BambuMqttBridgeClient: # Wait a bit for the connection to establish time.sleep(1) + + # If not connected after waiting, try again + if not self.connected: + self._log.warning("Initial connection attempt failed, retrying...") + try: + self._mqtt_client.reconnect() + time.sleep(2) # Wait a bit longer for retry + except Exception as e: + self._log.error(f"Reconnection failed: {str(e)}", exc_info=True) + return self.connected except Exception as e: self._log.error(f"Failed to connect to MQTT broker: {str(e)}", exc_info=True) @@ -392,14 +410,13 @@ class BambuVirtualPrinter: self._log.debug(f"Current temperatures - Nozzle: {self._telemetry.temp[0]}/{self._telemetry.targetTemp[0]}, " + f"Bed: {self._telemetry.bedTemp}/{self._telemetry.bedTargetTemp}, " + f"Chamber: {self._telemetry.chamberTemp}") - if print_job_state == "IDLE" or print_job_state == "FAILED": - self.change_state(self._state_idle) - elif print_job_state == "RUNNING" or print_job_state == "PREPARE": - self.change_state(self._state_printing) - elif print_job_state == "PAUSE": - self.change_state(self._state_paused) + + # Process the printer state even if it's "unknown" + if print_job_state: + self._process_print_state(print_job_state) else: - self._log.warn(f"Unknown print job state: {print_job_state}") + self._log.debug("No printer state received, skipping state processing") + elif event_type == "event_hms_errors": self._log.debug("Received event_hms_errors") bambu_printer = self.bambu_client.get_device() @@ -643,8 +660,9 @@ class BambuVirtualPrinter: # oder andere Werte haben als die, die wir erwarten print_job_state = print_job_state.upper() if print_job_state else "UNKNOWN" - # Normalisieren des Status, falls er 'unknown' ist oder nicht erkannt wird - if print_job_state in ["UNKNOWN", ""]: + # Explicitly handle "unknown" state (both upper and lowercase) + if print_job_state in ["UNKNOWN", ""] or print_job_state.upper() == "UNKNOWN": + self._log.debug("Detected 'unknown' printer state, trying to determine actual state") # Wenn wir keinen erkannten Status haben, versuchen wir ihn aus anderen Daten abzuleiten # Prüfe ob Druckfortschritt vorhanden ist if self.current_print_job and self.current_print_job.print_percentage > 0: @@ -654,6 +672,9 @@ class BambuVirtualPrinter: elif self._telemetry.targetTemp[0] > 150 or self._telemetry.bedTargetTemp > 40: print_job_state = "PREPARE" self._log.debug(f"Changed unknown state to PREPARE based on target temperatures") + else: + self._log.debug("Keeping state as IDLE since no indicators for print activity were found") + print_job_state = "IDLE" # Default to IDLE if we can't determine state # Status im PrintJob aktualisieren if self.current_print_job is None and print_job_state in ["RUNNING", "PREPARE", "PAUSE"]: @@ -704,6 +725,8 @@ class BambuVirtualPrinter: self._bambu_client.device.print_job.gcode_state = print_job_state except Exception as e: self._log.error(f"Error processing print state: {e}", exc_info=True) + # Default to a safe state in case of errors + self.change_state(self._state_idle) def _process_direct_temperature_data(self, print_data): """Verarbeitet Temperaturdaten direkt aus dem print-Objekt""" @@ -866,8 +889,33 @@ class BambuVirtualPrinter: bambu_client.on_disconnect = self.on_disconnect(bambu_client.on_disconnect) bambu_client.on_connect = self.on_connect(bambu_client.on_connect) - bambu_client.connect(callback=self.new_update) - self._log.info(f"bambu connection status: {bambu_client.connected}") + + # Add more robust connection retry logic + connection_attempts = 0 + max_attempts = 3 + retry_delay = 2 + + while connection_attempts < max_attempts: + try: + self._log.info(f"Connection attempt {connection_attempts + 1}/{max_attempts}...") + bambu_client.connect(callback=self.new_update) + + # Wait a moment to verify connection + time.sleep(retry_delay) + + if bambu_client.connected: + self._log.info(f"Bambu connection successful: {bambu_client.connected}") + break + + self._log.warning("Connection attempt failed, retrying...") + connection_attempts += 1 + time.sleep(retry_delay) + except Exception as e: + self._log.error(f"Error during connection attempt {connection_attempts + 1}: {str(e)}", exc_info=True) + connection_attempts += 1 + if connection_attempts < max_attempts: + time.sleep(retry_delay) + self.sendOk() self._bambu_client = bambu_client @@ -1272,32 +1320,44 @@ class BambuVirtualPrinter: def close(self): """Safely close all connections.""" try: + # Log that we're starting to close connections + self._log.debug("Starting to close all connections...") + if self._mqtt_client and self._mqtt_connected: + self._log.debug("Stopping MQTT client loop and disconnecting...") self._mqtt_client.loop_stop() self._mqtt_client.disconnect() self._mqtt_connected = False self._custom_connected = False + self._log.debug("MQTT client disconnected") + # Sicherstellen, dass wir keinen AttributError bekommen, wenn wir den BambuClient trennen if self._bambu_client: + self._log.debug("Disconnecting BambuClient...") try: self._bambu_client.disconnect() + self._log.debug("BambuClient disconnected successfully") except AttributeError: # BambuClient hat keinen client-Attribut oder die disconnect-Methode funktioniert nicht wie erwartet self._log.warning("BambuClient disconnect failed, cleaning up manually") # Manuell aufräumen if hasattr(self._bambu_client, '_mqtt_client') and self._bambu_client._mqtt_client: try: + self._log.debug("Manually stopping BambuClient's MQTT client...") self._bambu_client._mqtt_client.loop_stop() self._bambu_client._mqtt_client.disconnect() - except: - pass + self._log.debug("BambuClient's MQTT client manually disconnected") + except Exception as ex: + self._log.error(f"Error during manual MQTT client cleanup: {str(ex)}") except Exception as e: self._log.error(f"Error during close: {e}", exc_info=True) finally: # Immer in einen sicheren Zustand zurückkehren + self._log.debug("Final cleanup in close() method") self.change_state(self._state_idle) self._serial_io.close() self.stop() + self._log.debug("Connection cleanup completed") def stop(self): self._running = False