Compare commits

..

No commits in common. "master" and "v1.0.0" have entirely different histories.

8 changed files with 163 additions and 1047 deletions

View File

@ -1,28 +0,0 @@
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": "octobambu", "username": "bblp",
"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": "Manus Bambu Printer", "displayName": "Bambu Printer",
"displayVersion": self._plugin_version, "displayVersion": self._plugin_version,
"type": "github_release", "type": "github_release",
"user": "ManuelW", "user": "jneilliii",
"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://gitlab.fire-devils.org/3D-Druck/OctoPrint-BambuPrinter/archive/{target_version}.zip", "pip": "https://github.com/jneilliii/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, List, Optional from typing import TYPE_CHECKING, Callable
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,59 +12,83 @@ 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:
def __init__( file_system: RemoteSDCardFileList
self, file_system, on_update: Optional[Callable] = None, base_path: str = "" folder_view: dict[tuple[str, str | list[str] | None], None] = field(
): default_factory=dict
self._filters = [] ) # dict preserves order, but set does not. We use only dict keys as storage
self._file_system = file_system on_update: Callable[[], None] | None = None
self._base_path = base_path
self._update_complete_callback = on_update
self._file_info_cache = []
def with_filter(self, path: str, extension: str): def __post_init__(self):
self._filters.append({"path": path, "extension": extension}) self._file_alias_cache: dict[str, str] = {}
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 update(self) -> None: def list_all_views(self):
try: existing_files: list[str] = []
file_info_list = self.list_all_views() result: list[FileInfo] = []
self._file_info_cache = file_info_list
# Rufe Callback auf, wenn vorhanden with self.file_system.get_ftps_client() as ftp:
if self._update_complete_callback is not None: for filter in self.folder_view.keys():
self._update_complete_callback() result.extend(self.file_system.list_files(*filter, ftp, existing_files))
except Exception as e: return result
import logging
logging.getLogger("octoprint.plugins.bambu_printer.BambuPrinter").error(
f"Error updating file list: {e}", exc_info=True
)
def list_all_views(self) -> List[FileInfo]: def update(self):
# Verwende die Mock-Implementation von get_file_list statt FTPS file_info_list = self.list_all_views()
try: self._update_file_list_cache(file_info_list)
return self._file_system.get_file_list(self._base_path) if self.on_update:
except Exception as e: self.on_update()
import logging
logging.getLogger("octoprint.plugins.bambu_printer.BambuPrinter").error(
f"Error listing files: {e}", exc_info=True
)
return []
def get_all_cached_info(self) -> List[FileInfo]: def _update_file_list_cache(self, files: list[FileInfo]):
return self._file_info_cache self._file_alias_cache = {info.dosname: info.path.as_posix() for info in files}
self._file_data_cache = {info.path.as_posix(): info for info in files}
def get_file_by_stem(self, file_stem: str, extensions: list[str]) -> FileInfo | None: def get_all_info(self):
"""Get file info by file name without extension""" self.update()
for file_info in self._file_info_cache: return self.get_all_cached_info()
for extension in extensions:
if file_info.file_name.lower().startswith(f"{file_stem.lower()}{extension}"):
return file_info
return None def get_all_cached_info(self):
return list(self._file_data_cache.values())
def get_file_data(self, file_path: str) -> FileInfo | None:
for file_info in self._file_info_cache: def get_file_data(self, file_path: str | Path) -> FileInfo | None:
if file_info.path.lower() == file_path.lower() or file_info.file_name.lower() == file_path.lower(): file_data = self.get_file_data_cached(file_path)
return file_info 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, List from typing import Iterable, Iterator
import logging.handlers import logging.handlers
from octoprint.util import get_dos_filename from octoprint.util import get_dos_filename
@ -17,7 +17,6 @@ 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:
@ -81,56 +80,8 @@ 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"])
Implementieren wir eine Mock-Version des FTPS-Clients, die keinen echten FTP-Zugriff erfordert. access_code = self._settings.get(["access_code"])
""" return IoTFTPSClient(
class MockFTPSClient: f"{host}", 990, "bblp", f"{access_code}", ssl_implicit=True
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,4 +14,3 @@ 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 = "1.0.0" plugin_version = "0.1.7"
# 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 = "ManuelW" plugin_author = "jneilliii"
# The plugin's author's mail address. # The plugin's author's mail address.
plugin_author_email = "manuelw@example.com" plugin_author_email = "jneilliii+github@gmail.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://gitlab.fire-devils.org/3D-Druck/OctoPrint-BambuPrinter" plugin_url = "https://github.com/jneilliii/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

@ -1,17 +0,0 @@
<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>