Compare commits

..

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

13 changed files with 175 additions and 1184 deletions

3
.github/FUNDING.yml vendored
View File

@ -1,3 +0,0 @@
github: [jneilliii]
patreon: jneilliii
custom: ['https://www.paypal.me/jneilliii']

View File

@ -1,26 +0,0 @@
---
name: Bug report
about: Please make sure to check other issues, including closed ones, prior to submitting a bug report. Debug logs are required and any bug report submitted without them will be ignored and closed.
title: "[BUG]: "
labels: ''
assignees: ''
---
**Describe the Bug**
<!-- A clear and concise description of what the bug is. -->
**Expected Behavior**
<!-- A clear and concise description of what you expected to happen. -->
**Debug Logs**
<!-- If logs are not included in your bug report it will be closed. Enable debug logging for octoprint.plugins.bambu_printer in OctoPrint's logging section of settings and recreate the issue then attach octoprint.log and plugin_bambu_printer_serial.log to this bug report. -->
**Screenshots**
<!-- Please share any relevant screenshots related to the issue. -->
**Printer and Plugin Setting Details**
* Printer model?
* Is your printer connected to Bambu Cloud?
* Is the plugin configured for local access only?

View File

@ -1,20 +0,0 @@
---
name: Feature request
about: Create a feature request for an improvement or change you'd like implemented.
title: "[FR]: "
labels: ''
assignees: ''
---
**Is your feature request related to a problem? Please describe.**
<!-- A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] -->
**Describe the solution you'd like**
<!-- A clear and concise description of what you want to happen. -->
**Describe alternatives you've considered**
<!-- A clear and concise description of any alternative solutions or features you've considered. -->
**Additional context**
<!-- Add any other context or screenshots about the feature request here. -->

16
.github/stale.yml vendored
View File

@ -1,16 +0,0 @@
# Number of days of inactivity before an issue becomes stale
daysUntilStale: 14
# Number of days of inactivity before a stale issue is closed
daysUntilClose: 7
# Issues with these labels will never be considered stale
exemptLabels:
- enhancement
- bug
# Label to use when marking an issue as stale
staleLabel: stale
# Comment to post when marking an issue as stale. Set to `false` to disable
markComment: >
This issue has been automatically marked as stale because it has not had
activity in 14 days. It will be closed if no further activity occurs in 7 days.
# Comment to post when closing a stale issue. Set to `false` to disable
closeComment: false

View File

@ -1,27 +0,0 @@
name: Mark Stale Issues
on:
workflow_dispatch:
schedule:
- cron: "0 0 * * *"
permissions:
actions: write
jobs:
stale:
runs-on: ubuntu-latest
steps:
- uses: actions/stale@v9
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
stale-issue-message: 'This issue has been automatically marked as stale because it has not had activity in 14 days. It will be closed if no further activity occurs in 7 days'
days-before-stale: 14
days-before-close: 7
stale-issue-label: 'stale'
days-before-issue-stale: 14
days-before-pr-stale: -1
days-before-issue-close: 7
days-before-pr-close: -1
exempt-issue-labels: 'bug,enhancement'
- uses: actions/checkout@v4
- uses: gautamkrishnar/keepalive-workflow@v2
with:
use_api: true

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.4"
# 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>