Compare commits

..

28 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.
Some checks failed
Mark Stale Issues / stale (push) Has been cancelled
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
jneilliii
d0fd4a5434 0.1.7
add back missing PREPARE printing state and associate printing status
2024-09-27 09:38:23 -04:00
jneilliii
3c218a548d add issue templates, funding, and stale bot 2024-09-12 19:56:40 -04:00
jneilliii
03af51608d 0.1.6
* replace 0 with 1 bytes during reporting print status to trigger state change in OctoPrint sooner.
2024-09-06 01:39:48 -04:00
jneilliii
c00285b1b2 0.1.5
* adjust M220 feed rate modifier calculations
2024-09-05 22:35:34 -04:00
jneilliii
7f1ae5a24b
0.1.4 (#43)
* fix stuck Printing from SD state when canceled in slicer or on printer, #42
2024-09-04 16:48:16 -04:00
15 changed files with 1193 additions and 177 deletions

3
.github/FUNDING.yml vendored Normal file
View File

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

26
.github/ISSUE_TEMPLATE/bug_report.md vendored Normal file
View File

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

@ -0,0 +1,20 @@
---
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 Normal file
View File

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

27
.github/workflows/stale.yml vendored Normal file
View File

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

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": "",
"host": "",
"access_code": "",
"username": "bblp",
"username": "octobambu",
"timelapse": False,
"bed_leveling": True,
"flow_cali": False,
@ -286,10 +286,10 @@ class BambuPrintPlugin(
def get_update_information(self):
return {
"bambu_printer": {
"displayName": "Bambu Printer",
"displayName": "Manus Bambu Printer",
"displayVersion": self._plugin_version,
"type": "github_release",
"user": "jneilliii",
"user": "ManuelW",
"repo": "OctoPrint-BambuPrinter",
"current": self._plugin_version,
"stable_branch": {
@ -304,6 +304,6 @@ class BambuPrintPlugin(
"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 typing import TYPE_CHECKING, Callable
from typing import TYPE_CHECKING, Callable, List, Optional
if TYPE_CHECKING:
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
@dataclass
class CachedFileView:
file_system: RemoteSDCardFileList
folder_view: dict[tuple[str, str | list[str] | None], None] = field(
default_factory=dict
) # dict preserves order, but set does not. We use only dict keys as storage
on_update: Callable[[], None] | None = None
def __init__(
self, file_system, on_update: Optional[Callable] = None, base_path: str = ""
):
self._filters = []
self._file_system = file_system
self._base_path = base_path
self._update_complete_callback = on_update
self._file_info_cache = []
def __post_init__(self):
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
def with_filter(self, path: str, extension: str):
self._filters.append({"path": path, "extension": extension})
return self
def list_all_views(self):
existing_files: list[str] = []
result: list[FileInfo] = []
def update(self) -> None:
try:
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:
for filter in self.folder_view.keys():
result.extend(self.file_system.list_files(*filter, ftp, existing_files))
return result
def list_all_views(self) -> List[FileInfo]:
# Verwende die Mock-Implementation von get_file_list statt FTPS
try:
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):
file_info_list = self.list_all_views()
self._update_file_list_cache(file_info_list)
if self.on_update:
self.on_update()
def get_all_cached_info(self) -> List[FileInfo]:
return self._file_info_cache
def _update_file_list_cache(self, files: list[FileInfo]):
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:
"""Get file info by file name without extension"""
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):
self.update()
return self.get_all_cached_info()
def get_all_cached_info(self):
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
def get_file_data(self, file_path: str) -> FileInfo | None:
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():
return file_info
return None

View File

@ -2,7 +2,7 @@ from __future__ import annotations
import datetime
from pathlib import Path
from typing import Iterable, Iterator
from typing import Iterable, Iterator, List
import logging.handlers
from octoprint.util import get_dos_filename
@ -17,6 +17,7 @@ class RemoteSDCardFileList:
self._settings = settings
self._selected_project_file: FileInfo | None = None
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:
try:
@ -80,8 +81,56 @@ class RemoteSDCardFileList:
self._logger.exception(e, exc_info=False)
def get_ftps_client(self):
host = self._settings.get(["host"])
access_code = self._settings.get(["access_code"])
return IoTFTPSClient(
f"{host}", 990, "bblp", f"{access_code}", ssl_implicit=True
)
"""
Implementieren wir eine Mock-Version des FTPS-Clients, die keinen echten FTP-Zugriff erfordert.
"""
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

@ -1,8 +1,6 @@
from __future__ import annotations
from pathlib import Path
from octoprint_bambu_printer.printer.file_system.file_info import FileInfo
from octoprint_bambu_printer.printer.print_job import PrintJob
from octoprint_bambu_printer.printer.states.a_printer_state import APrinterState

View File

@ -22,6 +22,7 @@ class PrintingState(APrinterState):
def __init__(self, printer: BambuVirtualPrinter) -> None:
super().__init__(printer)
self._current_print_job = None
self._is_printing = False
self._sd_printing_thread = None
@ -36,6 +37,7 @@ class PrintingState(APrinterState):
self._is_printing = False
self._sd_printing_thread.join()
self._sd_printing_thread = None
self._printer.current_print_job = None
def _start_worker_thread(self):
if self._sd_printing_thread is None:

View File

@ -7,3 +7,11 @@
###
.
pytest~=7.4.4
pybambu~=1.0.1
OctoPrint~=1.10.2
setuptools~=70.0.0
pyserial~=3.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"
# The plugin's version. Can be overwritten within OctoPrint's internal data via __plugin_version__ in the plugin module
plugin_version = "0.1.3"
plugin_version = "1.0.0"
# The plugin's description. Can be overwritten within OctoPrint's internal data via __plugin_description__ in the plugin
# module
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
plugin_author = "jneilliii"
plugin_author = "ManuelW"
# 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
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
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>