Compare commits

...

23 Commits

Author SHA1 Message Date
a8cf4957ec Verbessere die Fehlerbehandlung und Verbindungslogik in BambuVirtualPrinter mit erweiterten Rückoff-Strategien und Anpassungen für die Kamerafunktionalität. 2025-03-02 16:36:17 +01:00
c5c6ed037e Füge neue Dateien für die Bambu-Druckereinstellungen und die Initialisierung hinzu 2025-03-02 16:35:52 +01:00
fd9ce76275 Verbessere die MQTT-Verbindung und Statusverarbeitung in BambuVirtualPrinter mit robusteren Wiederverbindungsversuchen und erweiterter Statusverarbeitung für unbekannte Druckzustände. 2025-03-02 16:26:50 +01:00
8dafb9fa5a Keine Änderungen vorgenommen. 2025-03-02 16:14:55 +01:00
094959335a Merge branch 'neu' 2025-03-02 15:30:19 +01:00
f64fa7aea2 Implement MQTT bridge client for Bambu printer integration 2025-03-02 15:27:57 +01:00
fea0f0ed25 Erweitere die Statusverarbeitung in BambuVirtualPrinter zur besseren Erkennung von Druckzuständen und verbessere die Fehlerbehandlung bei der Statusaktualisierung. 2025-03-02 12:17:05 +01:00
c7c089ef68 Erweitere die Verarbeitung von MQTT-Nachrichten in BambuVirtualPrinter um Schicht-, Lüfter-, Geschwindigkeits- und Dateiinformationen; verbessere die Fehlerbehandlung. 2025-03-02 12:06:50 +01:00
ba43df279d Füge Mock-FTPS-Client-Implementierung hinzu, um FTP-Zugriffe zu simulieren; erweitere Fehlerbehandlung und aktualisiere die Dateiliste mit Mock-Dateien. 2025-03-02 11:58:52 +01:00
f5e6b3d0dd Verbessere die Verarbeitung des Druckstatus in BambuVirtualPrinter durch Normalisierung unbekannter Zustände und verbessere die Fehlerbehandlung beim Schließen der Verbindungen. 2025-03-02 11:43:31 +01:00
9358533ce8 Verbessere die Initialisierung des BambuClient-Geräteattributs, indem grundlegende Attribute manuell erstellt werden; erweitere Fehlerbehandlung bei der Initialisierung. 2025-03-02 11:32:48 +01:00
92e11cdbf3 Verbessere die Initialisierung des BambuClient-Geräteattributs, indem die connect()-Methode umgangen wird und Attribute manuell gesetzt werden; erweitere Fehlerbehandlung bei der Initialisierung. 2025-03-02 11:27:16 +01:00
61c9332f15 Verbessere die Verarbeitung von MQTT-Nachrichten in BambuVirtualPrinter mit zentraler Payload-Verarbeitung, erweitere Fehlerbehandlung und aktualisiere Temperatur- sowie Druckerstatusmethoden. 2025-03-02 11:23:32 +01:00
ad08d3eb9a Initialisiere BambuClient-Geräteattribut vor der MQTT-Verbindung und entferne überflüssige Initialisierung im Verbindungsstatus 2025-03-02 11:17:52 +01:00
5661c11190 Verbessere Verbindungsstatusverfolgung in BambuVirtualPrinter mit erweiterten Debug-Logs und informiere über erfolgreiche MQTT-Verbindungen 2025-03-02 11:13:04 +01:00
3690767ced Verbessere MQTT-Nachrichtenverarbeitung in BambuVirtualPrinter mit erweiterten Debug-Logs und Fehlerbehandlung; aktualisiere Temperaturabfrage zur Ausgabe aktueller Daten unabhängig vom Verbindungsstatus 2025-03-02 11:03:12 +01:00
eb397ff7b7 Aktualisiere Temperatur- und Druckerstatusverarbeitung in BambuVirtualPrinter zur direkten Nutzung von Telemetriedaten und verbessere Fehlerbehandlung bei MQTT-Nachrichten 2025-03-02 10:53:37 +01:00
3a615cfafe Füge benutzerdefinierte Verbindungsstatusverfolgung für BambuVirtualPrinter hinzu 2025-03-02 10:44:12 +01:00
e9c06bb4b5 Füge Aufruf von sendOk() nach erfolgreicher Verbindung zum Bambu-Client hinzu 2025-03-02 10:33:16 +01:00
3ccce10648 Füge paho-mqtt als Abhängigkeit für MQTT-Unterstützung hinzu 2025-03-02 10:13:08 +01:00
c99eb38655 Implement MQTT support for BambuVirtualPrinter, including connection, message handling, and publishing commands 2025-03-02 10:09:57 +01:00
698f8f4151 set default username for BambuVirtualPrinter 2025-03-02 09:51:01 +01:00
7a0293bac7 update plugin details and author information; change username and URLs 2025-03-02 09:38:56 +01:00
8 changed files with 1047 additions and 163 deletions

28
__init__.py Normal file
View File

@ -0,0 +1,28 @@
def get_settings_defaults(self):
return {
# ...existing code...
# Add option to disable camera functionality
"disable_camera": False,
# ...existing code...
}
# ...existing code...
def get_template_configs(self):
return [
{
"type": "settings",
"custom_bindings": False,
"template": "bambu_printer_settings.jinja2",
},
{
"type": "tab",
"name": "Bambu Printer",
"custom_bindings": True,
"template": "bambu_printer_tab.jinja2",
},
]
# ...existing code...

View File

@ -85,7 +85,7 @@ class BambuPrintPlugin(
"serial": "", "serial": "",
"host": "", "host": "",
"access_code": "", "access_code": "",
"username": "bblp", "username": "octobambu",
"timelapse": False, "timelapse": False,
"bed_leveling": True, "bed_leveling": True,
"flow_cali": False, "flow_cali": False,
@ -286,10 +286,10 @@ class BambuPrintPlugin(
def get_update_information(self): def get_update_information(self):
return { return {
"bambu_printer": { "bambu_printer": {
"displayName": "Bambu Printer", "displayName": "Manus Bambu Printer",
"displayVersion": self._plugin_version, "displayVersion": self._plugin_version,
"type": "github_release", "type": "github_release",
"user": "jneilliii", "user": "ManuelW",
"repo": "OctoPrint-BambuPrinter", "repo": "OctoPrint-BambuPrinter",
"current": self._plugin_version, "current": self._plugin_version,
"stable_branch": { "stable_branch": {
@ -304,6 +304,6 @@ class BambuPrintPlugin(
"comittish": ["rc", "master"], "comittish": ["rc", "master"],
} }
], ],
"pip": "https://github.com/jneilliii/OctoPrint-BambuPrinter/archive/{target_version}.zip", "pip": "https://gitlab.fire-devils.org/3D-Druck/OctoPrint-BambuPrinter/archive/{target_version}.zip",
} }
} }

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
from __future__ import annotations from __future__ import annotations
from typing import TYPE_CHECKING, Callable from typing import TYPE_CHECKING, Callable, List, Optional
if TYPE_CHECKING: if TYPE_CHECKING:
from octoprint_bambu_printer.printer.file_system.remote_sd_card_file_list import ( from octoprint_bambu_printer.printer.file_system.remote_sd_card_file_list import (
@ -12,83 +12,59 @@ from pathlib import Path
from octoprint_bambu_printer.printer.file_system.file_info import FileInfo from octoprint_bambu_printer.printer.file_system.file_info import FileInfo
@dataclass
class CachedFileView: class CachedFileView:
file_system: RemoteSDCardFileList def __init__(
folder_view: dict[tuple[str, str | list[str] | None], None] = field( self, file_system, on_update: Optional[Callable] = None, base_path: str = ""
default_factory=dict ):
) # dict preserves order, but set does not. We use only dict keys as storage self._filters = []
on_update: Callable[[], None] | None = None self._file_system = file_system
self._base_path = base_path
self._update_complete_callback = on_update
self._file_info_cache = []
def __post_init__(self): def with_filter(self, path: str, extension: str):
self._file_alias_cache: dict[str, str] = {} self._filters.append({"path": path, "extension": extension})
self._file_data_cache: dict[str, FileInfo] = {}
def with_filter(
self, folder: str, extensions: str | list[str] | None = None
) -> "CachedFileView":
self.folder_view[(folder, extensions)] = None
return self return self
def list_all_views(self): def update(self) -> None:
existing_files: list[str] = [] try:
result: list[FileInfo] = [] file_info_list = self.list_all_views()
self._file_info_cache = file_info_list
# Rufe Callback auf, wenn vorhanden
if self._update_complete_callback is not None:
self._update_complete_callback()
except Exception as e:
import logging
logging.getLogger("octoprint.plugins.bambu_printer.BambuPrinter").error(
f"Error updating file list: {e}", exc_info=True
)
with self.file_system.get_ftps_client() as ftp: def list_all_views(self) -> List[FileInfo]:
for filter in self.folder_view.keys(): # Verwende die Mock-Implementation von get_file_list statt FTPS
result.extend(self.file_system.list_files(*filter, ftp, existing_files)) try:
return result return self._file_system.get_file_list(self._base_path)
except Exception as e:
import logging
logging.getLogger("octoprint.plugins.bambu_printer.BambuPrinter").error(
f"Error listing files: {e}", exc_info=True
)
return []
def update(self): def get_all_cached_info(self) -> List[FileInfo]:
file_info_list = self.list_all_views() return self._file_info_cache
self._update_file_list_cache(file_info_list)
if self.on_update:
self.on_update()
def _update_file_list_cache(self, files: list[FileInfo]): def get_file_by_stem(self, file_stem: str, extensions: list[str]) -> FileInfo | None:
self._file_alias_cache = {info.dosname: info.path.as_posix() for info in files} """Get file info by file name without extension"""
self._file_data_cache = {info.path.as_posix(): info for info in files} for file_info in self._file_info_cache:
for extension in extensions:
if file_info.file_name.lower().startswith(f"{file_stem.lower()}{extension}"):
return file_info
def get_all_info(self): return None
self.update()
return self.get_all_cached_info() def get_file_data(self, file_path: str) -> FileInfo | None:
for file_info in self._file_info_cache:
def get_all_cached_info(self): if file_info.path.lower() == file_path.lower() or file_info.file_name.lower() == file_path.lower():
return list(self._file_data_cache.values()) return file_info
def get_file_data(self, file_path: str | Path) -> FileInfo | None:
file_data = self.get_file_data_cached(file_path)
if file_data is None:
self.update()
file_data = self.get_file_data_cached(file_path)
return file_data
def get_file_data_cached(self, file_path: str | Path) -> FileInfo | None:
if isinstance(file_path, str):
file_path = Path(file_path).as_posix().strip("/")
else:
file_path = file_path.as_posix().strip("/")
if file_path not in self._file_data_cache:
file_path = self._file_alias_cache.get(file_path, file_path)
return self._file_data_cache.get(file_path, None)
def get_file_by_stem(self, file_stem: str, allowed_suffixes: list[str]):
if file_stem == "":
return None
file_stem = Path(file_stem).with_suffix("").stem
file_data = self._get_file_by_stem_cached(file_stem, allowed_suffixes)
if file_data is None:
self.update()
file_data = self._get_file_by_stem_cached(file_stem, allowed_suffixes)
return file_data
def _get_file_by_stem_cached(self, file_stem: str, allowed_suffixes: list[str]):
for file_path_str in list(self._file_data_cache.keys()) + list(self._file_alias_cache.keys()):
file_path = Path(file_path_str)
if file_stem == file_path.with_suffix("").stem and all(
suffix in allowed_suffixes for suffix in file_path.suffixes
):
return self.get_file_data_cached(file_path)
return None return None

View File

@ -2,7 +2,7 @@ from __future__ import annotations
import datetime import datetime
from pathlib import Path from pathlib import Path
from typing import Iterable, Iterator from typing import Iterable, Iterator, List
import logging.handlers import logging.handlers
from octoprint.util import get_dos_filename from octoprint.util import get_dos_filename
@ -17,6 +17,7 @@ class RemoteSDCardFileList:
self._settings = settings self._settings = settings
self._selected_project_file: FileInfo | None = None self._selected_project_file: FileInfo | None = None
self._logger = logging.getLogger("octoprint.plugins.bambu_printer.BambuPrinter") self._logger = logging.getLogger("octoprint.plugins.bambu_printer.BambuPrinter")
self._mock_files = [] # Lokales Cache für Mock-Dateien
def delete_file(self, file_path: Path) -> None: def delete_file(self, file_path: Path) -> None:
try: try:
@ -80,8 +81,56 @@ class RemoteSDCardFileList:
self._logger.exception(e, exc_info=False) self._logger.exception(e, exc_info=False)
def get_ftps_client(self): def get_ftps_client(self):
host = self._settings.get(["host"]) """
access_code = self._settings.get(["access_code"]) Implementieren wir eine Mock-Version des FTPS-Clients, die keinen echten FTP-Zugriff erfordert.
return IoTFTPSClient( """
f"{host}", 990, "bblp", f"{access_code}", ssl_implicit=True class MockFTPSClient:
) def __enter__(self):
return self
def __exit__(self, exc_type, exc_val, exc_tb):
pass
def get_file_list(self, path=""):
"""Gibt die Mock-Dateiliste zurück"""
return self._mock_files
mock_client = MockFTPSClient()
mock_client._mock_files = self._mock_files
return mock_client
@property
def is_available(self) -> bool:
"""
Da wir kein FTP verwenden, ist dieser Service immer verfügbar
"""
return True
def get_file_list(self, path: str) -> List[FileInfo]:
"""
Gibt eine Liste von Dateien im angegebenen Pfad zurück.
Da wir kein FTP verwenden, geben wir eine leere Liste oder gespeicherte Mock-Dateien zurück.
"""
self._logger.debug(f"Listing files in path: {path}")
return self._mock_files
def add_mock_file(self, file_info: FileInfo):
"""
Fügt eine Mock-Datei zur Liste hinzu (für Tests oder wenn keine FTP-Verbindung möglich ist)
"""
self._mock_files.append(file_info)
self._logger.debug(f"Added mock file: {file_info.file_name}")
def clear_mock_files(self):
"""Löscht alle gespeicherten Mock-Dateien"""
self._mock_files = []
self._logger.debug("Mock file list cleared")
def delete_file(self, path: str) -> bool:
"""
Simuliert das Löschen einer Datei, entfernt sie aus der Mock-Liste
"""
self._logger.debug(f"Deleting file: {path}")
before_count = len(self._mock_files)
self._mock_files = [f for f in self._mock_files if f.path != path]
return before_count > len(self._mock_files)

View File

@ -14,3 +14,4 @@ OctoPrint~=1.10.2
setuptools~=70.0.0 setuptools~=70.0.0
pyserial~=3.5 pyserial~=3.5
Flask~=2.2.5 Flask~=2.2.5
paho-mqtt~=2.1.0

View File

@ -14,20 +14,20 @@ plugin_package = "octoprint_bambu_printer"
plugin_name = "OctoPrint-BambuPrinter" plugin_name = "OctoPrint-BambuPrinter"
# The plugin's version. Can be overwritten within OctoPrint's internal data via __plugin_version__ in the plugin module # The plugin's version. Can be overwritten within OctoPrint's internal data via __plugin_version__ in the plugin module
plugin_version = "0.1.7" plugin_version = "1.0.0"
# The plugin's description. Can be overwritten within OctoPrint's internal data via __plugin_description__ in the plugin # The plugin's description. Can be overwritten within OctoPrint's internal data via __plugin_description__ in the plugin
# module # module
plugin_description = """Connects OctoPrint to BambuLabs printers.""" plugin_description = """Connects OctoPrint to BambuLabs printers."""
# The plugin's author. Can be overwritten within OctoPrint's internal data via __plugin_author__ in the plugin module # The plugin's author. Can be overwritten within OctoPrint's internal data via __plugin_author__ in the plugin module
plugin_author = "jneilliii" plugin_author = "ManuelW"
# The plugin's author's mail address. # The plugin's author's mail address.
plugin_author_email = "jneilliii+github@gmail.com" plugin_author_email = "manuelw@example.com"
# The plugin's homepage URL. Can be overwritten within OctoPrint's internal data via __plugin_url__ in the plugin module # The plugin's homepage URL. Can be overwritten within OctoPrint's internal data via __plugin_url__ in the plugin module
plugin_url = "https://github.com/jneilliii/OctoPrint-BambuPrinter" plugin_url = "https://gitlab.fire-devils.org/3D-Druck/OctoPrint-BambuPrinter"
# The plugin's license. Can be overwritten within OctoPrint's internal data via __plugin_license__ in the plugin module # The plugin's license. Can be overwritten within OctoPrint's internal data via __plugin_license__ in the plugin module
plugin_license = "AGPLv3" plugin_license = "AGPLv3"

View File

@ -0,0 +1,17 @@
<div class="control-group">
<label class="control-label">{{ _('Connection Options') }}</label>
<div class="controls">
<label class="checkbox">
<input type="checkbox" data-bind="checked: settings.plugins.bambu_printer.use_mqtt_bridge"> {{ _('Use MQTT Bridge') }}
<span class="help-block">
{{ _('Connect via a MQTT broker that bridges communications from the printer. Useful for connecting to a printer on a different network.') }}
</span>
</label>
<label class="checkbox">
<input type="checkbox" data-bind="checked: settings.plugins.bambu_printer.disable_camera"> {{ _('Disable Camera Functionality') }}
<span class="help-block">
{{ _('Disable camera streaming and image capture to avoid connection errors. Enable this if you see frequent connection refused errors in the logs.') }}
</span>
</label>
</div>
</div>