fix(printer): 修复A1打印发送,绕过bambulabs_api的ftp URL问题,改用sdcard路径

This commit is contained in:
2026-07-28 16:25:21 +08:00
parent db517b69f7
commit 116dcfe45f
3 changed files with 70 additions and 7 deletions
+1 -1
View File
@@ -75,7 +75,7 @@
"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",
"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.",
+1 -1
View File
@@ -75,7 +75,7 @@
"gui.output.printer.ip": "IP 地址",
"gui.output.printer.access_code": "访问码",
"gui.output.printer.serial": "序列号",
"gui.output.printer.send.tooltip": "通过局域网将生成的 3MF 发送到 A1 打印机并开始打印",
"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 中。",
+68 -5
View File
@@ -4,6 +4,7 @@ from __future__ import annotations
from pathlib import Path
from dataclasses import dataclass
@dataclass
class PrinterConfig:
"""打印机连接配置。"""
@@ -11,32 +12,94 @@ class PrinterConfig:
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 文件上传至打印机并开始打印。
"""将 3MF 文件上传至 A1 打印机并通过局域网开始打印。
发送前会检查打印机状态;正忙则拒绝发送。
⚠️ 仅支持本地局域网,电脑与打印机必须在同一网络下。
Args:
file_path: 要发送的 3MF 文件路径
config: 打印机连接配置
Returns:
True 表示成功False 表示失败
True 表示成功
Raises:
ImportError: bambulabs_api 未安装
Exception: 连接或上传失败
RuntimeError: 打印机正忙或上传/打印失败
"""
# 延迟导入,避免在没有 bambulabs_api 时报错
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}")
printer.start_print(file_name, plate_number=1)
# 使用 A1 专用的 MQTT 指令开始打印,而非内置的 start_print
_start_print_for_a1(printer, file_name, plate_number=1)
return True
finally:
printer.disconnect()