Compare commits
No commits in common. "master" and "v1.0.0" have entirely different histories.
28
__init__.py
28
__init__.py
@ -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...
|
|
@ -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
@ -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
|
|
||||||
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
|
|
||||||
)
|
|
||||||
|
|
||||||
def list_all_views(self) -> List[FileInfo]:
|
with self.file_system.get_ftps_client() as ftp:
|
||||||
# Verwende die Mock-Implementation von get_file_list statt FTPS
|
for filter in self.folder_view.keys():
|
||||||
try:
|
result.extend(self.file_system.list_files(*filter, ftp, existing_files))
|
||||||
return self._file_system.get_file_list(self._base_path)
|
return result
|
||||||
except Exception as e:
|
|
||||||
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(self):
|
||||||
return self._file_info_cache
|
file_info_list = self.list_all_views()
|
||||||
|
self._update_file_list_cache(file_info_list)
|
||||||
|
if self.on_update:
|
||||||
|
self.on_update()
|
||||||
|
|
||||||
def get_file_by_stem(self, file_stem: str, extensions: list[str]) -> FileInfo | None:
|
def _update_file_list_cache(self, files: list[FileInfo]):
|
||||||
"""Get file info by file name without extension"""
|
self._file_alias_cache = {info.dosname: info.path.as_posix() for info in files}
|
||||||
for file_info in self._file_info_cache:
|
self._file_data_cache = {info.path.as_posix(): info for info in files}
|
||||||
for extension in extensions:
|
|
||||||
if file_info.file_name.lower().startswith(f"{file_stem.lower()}{extension}"):
|
|
||||||
return file_info
|
|
||||||
|
|
||||||
return None
|
def get_all_info(self):
|
||||||
|
self.update()
|
||||||
def get_file_data(self, file_path: str) -> FileInfo | None:
|
return self.get_all_cached_info()
|
||||||
for file_info in self._file_info_cache:
|
|
||||||
if file_info.path.lower() == file_path.lower() or file_info.file_name.lower() == file_path.lower():
|
def get_all_cached_info(self):
|
||||||
return file_info
|
return list(self._file_data_cache.values())
|
||||||
|
|
||||||
|
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
|
||||||
|
@ -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)
|
|
||||||
|
@ -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
|
|
||||||
|
8
setup.py
8
setup.py
@ -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"
|
||||||
|
@ -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>
|
|
Loading…
x
Reference in New Issue
Block a user