refactor: 移除局域网发送至打印机功能

This commit is contained in:
2026-07-29 12:22:19 +08:00
parent 116dcfe45f
commit f066ca24fa
4 changed files with 0 additions and 188 deletions
-67
View File
@@ -59,7 +59,6 @@ except ImportError as exc: # pragma: no cover
from . import APP_NAME, APP_TITLE
from .i18n import t, switch as i18n_switch, current_locale
from .printer import PrinterConfig, send_to_printer
from .batch import IndividualBuildTask, individual_batch_worker_count, run_individual_batch_builds
from .core import (
BuildOptions,
@@ -689,35 +688,6 @@ class MainWindow(QMainWindow):
self.output_preview_label_title = QLabel(t("gui.output.preview"))
output_layout.addRow(self.output_preview_label_title, self.output_preview_label)
# ---- 发送至打印机 ----
self.send_to_printer_check = QCheckBox(t("gui.output.printer.send"))
self.send_to_printer_check.setChecked(False)
self.send_to_printer_check.setToolTip(t("gui.output.printer.send.tooltip"))
self.printer_label = QLabel(t("gui.output.printer.send"))
output_layout.addRow(self.printer_label, self.send_to_printer_check)
# 打印机配置行(IP、访问码、序列号)
printer_config_widget = QWidget()
printer_config_layout = QHBoxLayout(printer_config_widget)
printer_config_layout.setContentsMargins(0, 0, 0, 0)
printer_config_layout.setSpacing(6)
self.printer_ip_edit = QLineEdit()
self.printer_ip_edit.setPlaceholderText(t("gui.output.printer.ip"))
self.printer_ip_edit.setMaximumWidth(140)
self.printer_access_code_edit = QLineEdit()
self.printer_access_code_edit.setPlaceholderText(t("gui.output.printer.access_code"))
self.printer_access_code_edit.setMaximumWidth(120)
self.printer_serial_edit = QLineEdit()
self.printer_serial_edit.setPlaceholderText(t("gui.output.printer.serial"))
self.printer_serial_edit.setMaximumWidth(180)
printer_config_layout.addWidget(self.printer_ip_edit)
printer_config_layout.addWidget(self.printer_access_code_edit)
printer_config_layout.addWidget(self.printer_serial_edit)
printer_config_layout.addStretch(1)
output_layout.addRow("", printer_config_widget)
root.addWidget(self.output_group)
# =====================================================================
@@ -778,10 +748,6 @@ class MainWindow(QMainWindow):
self.individual_batch_check.stateChanged.connect(self.on_individual_batch_toggled)
self.clear_after_build_check.stateChanged.connect(self.save_current_settings)
self.skip_duplicates_check.stateChanged.connect(self.save_current_settings)
self.send_to_printer_check.stateChanged.connect(self.save_current_settings)
self.printer_ip_edit.textChanged.connect(self.save_current_settings)
self.printer_access_code_edit.textChanged.connect(self.save_current_settings)
self.printer_serial_edit.textChanged.connect(self.save_current_settings)
self.output_dir_edit.textChanged.connect(self.on_output_rule_changed)
self.output_name_edit.textChanged.connect(self.on_output_rule_changed)
self.language_combo.currentIndexChanged.connect(self.on_language_changed)
@@ -806,10 +772,6 @@ class MainWindow(QMainWindow):
locale_index = self.language_combo.findData(saved_locale)
if locale_index >= 0:
self.language_combo.setCurrentIndex(locale_index)
self.send_to_printer_check.setChecked(bool(options.get("send_to_printer_enabled", False)))
self.printer_ip_edit.setText(str(options.get("printer_ip", "")))
self.printer_access_code_edit.setText(str(options.get("printer_access_code", "")))
self.printer_serial_edit.setText(str(options.get("printer_serial", "")))
self.output_dir_edit.setText(str(options.get("output_directory", "")))
self.output_name_edit.setText(str(options.get("output_filename_rule", DEFAULT_OUTPUT_PATTERN)))
metadata_mode = options.get("metadata_mode", "sum")
@@ -849,10 +811,6 @@ class MainWindow(QMainWindow):
"clear_after_build": self.clear_after_build_check.isChecked(),
"skip_duplicates": self.skip_duplicates_check.isChecked(),
"locale": self.language_combo.currentData() or "zh_CN",
"send_to_printer_enabled": self.send_to_printer_check.isChecked(),
"printer_ip": self.printer_ip_edit.text().strip(),
"printer_access_code": self.printer_access_code_edit.text().strip(),
"printer_serial": self.printer_serial_edit.text().strip(),
"output_directory": self.output_dir_edit.text().strip(),
"output_filename_rule": self.output_name_edit.text().strip() or DEFAULT_OUTPUT_PATTERN,
}
@@ -1402,21 +1360,6 @@ class MainWindow(QMainWindow):
"""显示构建成功的浮动提示条。"""
self.success_toast.show_message(message)
def _send_to_printer(self, file_path: Path) -> None:
"""将构建好的 3MF 文件发送至打印机。"""
config = PrinterConfig(
ip=self.printer_ip_edit.text().strip(),
access_code=self.printer_access_code_edit.text().strip(),
serial=self.printer_serial_edit.text().strip(),
)
try:
send_to_printer(file_path, config)
self.log.append(t("gui.toast.send_success", name=file_path.name))
except ImportError:
self.log.append(t("gui.log.printer_missing"))
except Exception as exc:
self.log.append(t("gui.toast.send_failed", error=str(exc)))
def build_output(self) -> None:
"""主构建入口:根据批处理模式分发到合并构建或独立构建。"""
jobs = self.collect_jobs()
@@ -1440,8 +1383,6 @@ class MainWindow(QMainWindow):
options = self.build_options_for_output(output_path)
result = build_packed_3mf(jobs, options)
self.log_build_result(result)
if self.send_to_printer_check.isChecked():
self._send_to_printer(result.output_3mf)
self.show_success_toast(t("gui.toast.combined_success"))
if self.clear_after_build_check.isChecked():
self.remove_all()
@@ -1471,8 +1412,6 @@ class MainWindow(QMainWindow):
batch_result = run_individual_batch_builds(tasks, max_workers=worker_count)
for result in batch_result.results:
self.log_build_result(result)
if self.send_to_printer_check.isChecked():
self._send_to_printer(result.output_3mf)
success_count = len(batch_result.results)
for failure in batch_result.failures:
errors.append(f"{failure.job.source_3mf.name}: {failure.error}")
@@ -1589,12 +1528,6 @@ class MainWindow(QMainWindow):
self.output_dir_label.setText(t("gui.output.dir.label"))
self.output_filename_rule_label.setText(t("gui.output.filename_rule"))
self.output_preview_label_title.setText(t("gui.output.preview"))
self.printer_label.setText(t("gui.output.printer.send"))
self.send_to_printer_check.setText(t("gui.output.printer.send"))
self.send_to_printer_check.setToolTip(t("gui.output.printer.send.tooltip"))
self.printer_ip_edit.setPlaceholderText(t("gui.output.printer.ip"))
self.printer_access_code_edit.setPlaceholderText(t("gui.output.printer.access_code"))
self.printer_serial_edit.setPlaceholderText(t("gui.output.printer.serial"))
# 语言标签
self.language_label.setText(t("gui.options.language") + ":")
-8
View File
@@ -71,11 +71,6 @@
"gui.output.filename_rule.help.tooltip": "Show filename token help",
"gui.output.preview": "Preview",
"gui.output.batch_preview": "{first} | {count} output file(s)",
"gui.output.printer.send": "Send to printer after build",
"gui.output.printer.ip": "IP Address",
"gui.output.printer.access_code": "Access Code",
"gui.output.printer.serial": "Serial",
"gui.output.printer.send.tooltip": "Send the generated 3MF to an A1 printer over LAN and start printing (LAN only — computer and printer must be on the same local network)",
"gui.dialog.individual_batch.title": "Individual Batch Mode",
"gui.dialog.individual_batch.text": "Individual batch mode treats every input row as a separate build.\n\nExample: if you add 20 single-plate 3MF files and set copies to 5, Build 3MF will create 20 separate packed files. Each output contains only that source file repeated 5 times.\n\nThis is useful for quickly batch-converting many independent 3MF jobs into multi-copy SwapMod packs. It does not combine all input files into one 3MF.",
@@ -93,8 +88,6 @@
"gui.toast.combined_success": "The packed 3MF file was created.",
"gui.toast.batch_success": "Created {count} packed 3MF file(s).",
"gui.toast.send_success": "Sent to printer: {name}",
"gui.toast.send_failed": "Failed to send to printer: {error}",
"gui.log.added_files": "Added {added} input file(s). Skipped {skipped}.",
"gui.log.skipped_file": "Skipped {path}: {reason}",
@@ -106,7 +99,6 @@
"gui.log.filament": "Estimated source filament: {filament}",
"gui.log.md5": "G-code MD5: {md5}",
"gui.log.build_error": "Error building {path}: {error}",
"gui.log.printer_missing": "Error: bambulabs_api not installed, run: pip install bambulabs_api",
"format.unknown": "Unknown"
}
-8
View File
@@ -71,11 +71,6 @@
"gui.output.filename_rule.help.tooltip": "显示文件名标记帮助",
"gui.output.preview": "预览",
"gui.output.batch_preview": "{first} | {count} 个输出文件",
"gui.output.printer.send": "构建后发送至打印机",
"gui.output.printer.ip": "IP 地址",
"gui.output.printer.access_code": "访问码",
"gui.output.printer.serial": "序列号",
"gui.output.printer.send.tooltip": "通过局域网将生成的 3MF 发送到 A1 打印机并开始打印(仅支持本地局域网,电脑与打印机需在同一网络下)",
"gui.dialog.individual_batch.title": "独立批处理模式",
"gui.dialog.individual_batch.text": "独立批处理模式将每一行输入作为独立的构建任务。\n\n示例:如果你添加了 20 个单板 3MF 文件并设置份数为 5,点击\"构建 3MF\"将创建 20 个独立的打包文件。每个输出文件仅包含该源文件重复 5 次的内容。\n\n这个功能适用于快速将大量独立的 3MF 作业批量转换为多份数的 SwapMod 包。它不会将所有输入文件合并到一个 3MF 中。",
@@ -93,8 +88,6 @@
"gui.toast.combined_success": "已创建打包的 3MF 文件。",
"gui.toast.batch_success": "已创建 {count} 个打包的 3MF 文件。",
"gui.toast.send_success": "已发送至打印机:{name}",
"gui.toast.send_failed": "发送至打印机失败:{error}",
"gui.log.added_files": "已添加 {added} 个输入文件。跳过 {skipped} 个。",
"gui.log.skipped_file": "已跳过 {path}{reason}",
@@ -106,7 +99,6 @@
"gui.log.filament": "预估源文件耗材:{filament}",
"gui.log.md5": "G-code MD5{md5}",
"gui.log.build_error": "构建 {path} 时出错:{error}",
"gui.log.printer_missing": "错误:未安装 bambulabs_api,请执行 pip install bambulabs_api",
"format.unknown": "未知"
}
-105
View File
@@ -1,105 +0,0 @@
"""打印机发送模块:通过局域网将 3MF 发送到 Bambu A1 并开始打印。"""
from __future__ import annotations
from pathlib import Path
from dataclasses import dataclass
@dataclass
class PrinterConfig:
"""打印机连接配置。"""
ip: str = "" # 打印机 IP 地址
access_code: str = "" # 局域网访问码
serial: str = "" # 打印机序列号
def check_printer_ready(config: PrinterConfig) -> bool:
"""检查打印机是否空闲可接收新任务。
返回 True 表示打印机空闲False 表示正忙或离线
"""
from bambulabs_api import Printer as BambuPrinter
from bambulabs_api.states_info import GcodeState
printer = BambuPrinter(config.ip, config.access_code, config.serial)
try:
printer.connect()
state = printer.get_state()
return state == GcodeState.IDLE
except Exception:
return False
finally:
printer.disconnect()
def _start_print_for_a1(printer, file_name: str, plate_number: int = 1) -> None:
"""发送打印机开始打印的 MQTT 指令,使用 A1 专用的 sdcard URL 格式。
bambulabs_api start_print 方法硬编码了 ftp:/// 前缀
这对 A1 不生效A1 需要 file:///sdcard/ 前缀
本函数绕过 start_print直接构造正确的 MQTT 载荷
"""
plate_location = f"Metadata/plate_{int(plate_number)}.gcode"
payload = {
"print": {
"command": "project_file",
"param": plate_location,
"file": file_name,
"bed_leveling": True,
"bed_type": "textured_plate",
"flow_cali": True,
"vibration_cali": True,
"url": f"file:///sdcard/{file_name}",
"layer_inspect": False,
"sequence_id": "10000000",
"use_ams": True,
"ams_mapping": [0],
}
}
# 调用名称改写后的私有方法发送原始 JSON 荷载
printer.mqtt_client._PrinterMQTTClient__publish_command(payload)
def send_to_printer(file_path: Path, config: PrinterConfig) -> bool:
"""将 3MF 文件上传至 A1 打印机并通过局域网开始打印。
发送前会检查打印机状态正忙则拒绝发送
仅支持本地局域网电脑与打印机必须在同一网络下
Args:
file_path: 要发送的 3MF 文件路径
config: 打印机连接配置
Returns:
True 表示成功
Raises:
ImportError: bambulabs_api 未安装
RuntimeError: 打印机正忙或上传/打印失败
"""
from bambulabs_api import Printer as BambuPrinter
from bambulabs_api.states_info import GcodeState
printer = BambuPrinter(config.ip, config.access_code, config.serial)
try:
printer.connect()
# 检查打印机是否空闲
state = printer.get_state()
if state != GcodeState.IDLE:
raise RuntimeError(
f"打印机当前状态为 {state.value}"
f"无法开始新任务。请等待当前打印完成。"
)
file_name = file_path.name
with open(file_path, "rb") as f:
import io
result = printer.upload_file(io.BytesIO(f.read()), file_name)
if "226" not in result:
raise RuntimeError(f"上传文件失败: {result}")
# 使用 A1 专用的 MQTT 指令开始打印,而非内置的 start_print
_start_print_for_a1(printer, file_name, plate_number=1)
return True
finally:
printer.disconnect()