mirror of
https://github.com/maziggy/bambuddy.git
synced 2026-09-30 03:01:21 +02:00
Two tightly-coupled deliverables in one drop -- a new AMS Filament Backup status/control surface, and the #1766 fix that depends on it. Added -- AMS Filament Backup status + control - Parse bit 18 of top-level print.cfg into PrinterState.ams_filament_backup on every push_status. Verified against OrcaSlicer source (DeviceManager.cpp:4961) and a live H2D ON/OFF capture. Tri-state (None = A1 family / pre-cfg push) preserves today's behaviour. - Hold-timer guard (3 s) prevents stale frames from flickering the badge back to the printer's old cfg after a user-initiated toggle. - POST /printers/{id}/ams-backup toggle, set_ams_filament_backup() client method calling _set_print_option("auto_switch_filament", enabled). - GET /printers/{id}/inventory-remain endpoint exposes the same map the dispatcher uses (internal and Spoolman modes both work uniformly). - Small icon badge in the printer card's "Filaments" section header (placement reads as printer-wide because the cfg bit is printer-wide, not per-AMS). Click to toggle, success toast. - 5 i18n keys x 11 locales for the badge UI. Fixed -- #1766: prefer_lowest didn't pick lowest, ignored backup state - Backend gate in _compute_ams_mapping_for_printer: coerce prefer_lowest to False when status.ams_filament_backup is False; log the skip. - New effectivePreferLowest(setting, backup) helper applied at every frontend sort entry point: single-printer PrintModal, multi-printer hook per-printer, PrinterSelector InlineMappingEditor, FilamentMapping standalone editor (the last had NO preferLowest awareness at all before this change). - New preferLowestSortKey(f, inventoryByTrayId) mirrors backend's two-tier key exactly, including the banding tie-break (regular AMS < AMS-HT < external) so the client-side pre-compute matches the dispatch-time pick. An earlier draft used a flat `amsId * 4 + trayId` priority which gave external slots (ams_id = -1) a NEGATIVE priority -- caught in code review before commit. - Settings -> Filament -> "Prefer lowest remaining filament" gets an explanatory note about the printer-side AMS Backup dependency, with i18n key in all 11 locales.
59 lines
2.4 KiB
Python
59 lines
2.4 KiB
Python
"""Tests for ``parse_ams_filament_backup_from_cfg`` (#1766 prefer_lowest gate).
|
|
|
|
The function extracts bit 18 of Bambu's top-level ``print.cfg`` hex string,
|
|
which OrcaSlicer's DeviceManager.cpp:4961 maps to AMS Filament Backup. These
|
|
tests pin the bit position + cover the absent / malformed cases A1-family
|
|
printers and pre-init pushes produce.
|
|
"""
|
|
|
|
import pytest
|
|
|
|
from backend.app.services.bambu_mqtt import parse_ams_filament_backup_from_cfg
|
|
|
|
|
|
class TestParseAmsFilamentBackupFromCfg:
|
|
def test_h2d_on_capture(self):
|
|
# Captured 2026-06-20 from H2D fw 01.03.00.00 with backup ON.
|
|
# Hex "C0340FC219" has bit 18 set (nibble 5 = F = 0b1111).
|
|
assert parse_ams_filament_backup_from_cfg("C0340FC219") is True
|
|
|
|
def test_h2d_off_capture(self):
|
|
# Same printer, backup toggled OFF — only bit 18 flips:
|
|
# "C0340BC219" — nibble 5 = B = 0b1011.
|
|
assert parse_ams_filament_backup_from_cfg("C0340BC219") is False
|
|
|
|
def test_x1c_short_hex_string_on(self):
|
|
# X1C cfg in the investigation snapshots is short ("FCA09").
|
|
# Bit 18 of 0xFCA09 = 0b1111110010100001001, bit18 set.
|
|
assert parse_ams_filament_backup_from_cfg("FCA09") is True
|
|
|
|
def test_lowercase_hex(self):
|
|
# Robustness: int(s, 16) accepts both cases; check we don't regress.
|
|
assert parse_ams_filament_backup_from_cfg("c0340fc219") is True
|
|
|
|
def test_only_bit_18_isolated(self):
|
|
# Sanity: a value with ONLY bit 18 set must parse as True.
|
|
assert parse_ams_filament_backup_from_cfg(hex(1 << 18)[2:]) is True
|
|
|
|
def test_bit_18_clear_but_others_set(self):
|
|
# Set every bit EXCEPT 18 — must parse as False.
|
|
mask = (~(1 << 18)) & 0xFFFFFFFF
|
|
assert parse_ams_filament_backup_from_cfg(hex(mask)[2:]) is False
|
|
|
|
@pytest.mark.parametrize(
|
|
"value",
|
|
[
|
|
None, # field omitted (A1 family old protocol)
|
|
"", # empty string
|
|
123, # firmware-emitted int instead of hex string (defensive)
|
|
"not_hex", # malformed
|
|
"0xZZ", # invalid hex
|
|
["FCA09"], # wrong shape
|
|
{"cfg": "FCA09"}, # nested by mistake
|
|
],
|
|
)
|
|
def test_invalid_returns_none(self, value):
|
|
# None preserves today's behaviour for callers gating on backup state —
|
|
# NOT False. Treating absent as OFF would regress A1-family scheduling.
|
|
assert parse_ams_filament_backup_from_cfg(value) is None
|