fix(ams): log rejected multiColorBox setInfo with the triggering request
The printer's failure payload for a rejected slot assignment carries
no slot/type/color info of its own, only an opaque
["multi_color_box", [{"filaments": {"id": N}, "id": box_id}]] shape -
useless for diagnosing why an assignment was rejected.
Remember the last setInfo request (_last_ams_set_request) and log it
alongside the failure so bridge logs alone can answer "what exact
type/color was sent, and to which slot" without asking the user to
dig it out manually or run extra reproduction steps.
This commit is contained in:
@@ -3,4 +3,4 @@
|
||||
- Fix: on printers with multiple daisy-chained ACE units and no toolhead buffer (e.g. Kobra S1 with 2 ACE Pro), only the first unit's 4 slots were ever shown on the dashboard or synced to OrcaSlicer — the bridge silently discarded every ACE unit after the first. All units now show up correctly (Issue #95, thanks @hoovercl for the detailed report and logs)
|
||||
- Feat: the GCode browser now supports multi-select and bulk delete — click any file's checkbox to enter select mode, use "Select All" to grab everything currently visible (respecting your active search/filter), then delete the selection with one confirmation instead of one-by-one (Issue #94, thanks @Blaim)
|
||||
- Fix: **printing via OrcaSlicer "Upload and print" failed (or fed the wrong spool) when a slot below the used filament was empty** — e.g. printing with Filament 4 while slot 3 was empty. The generated AMS slot mapping inserted a placeholder pointing at the physically empty tray, which the printer rejects. Placeholders now point at a loaded tray instead. Printing with all slots full already worked and is unchanged.
|
||||
- Fix: manually assigning a filament profile to an ACE slot could crash the MQTT callback (`'list' object has no attribute 'get'`) when the printer rejected the assignment, e.g. for custom-RFID/third-party filament. The bridge now handles the printer's failure response cleanly instead of crashing (Issue #100, thanks @Blaim)
|
||||
- Fix: manually assigning a filament profile to an ACE slot could crash the MQTT callback (`'list' object has no attribute 'get'`) when the printer rejected the assignment, e.g. for custom-RFID/third-party filament. The bridge now handles the printer's failure response cleanly instead of crashing, and the log now correlates a rejected assignment with the request that triggered it (slot/type/color) so a rejection reason can be diagnosed from bridge logs alone (Issue #100, thanks @Blaim)
|
||||
|
||||
@@ -989,6 +989,7 @@ class KobraXBridge:
|
||||
except Exception:
|
||||
self._visible_vendors = []
|
||||
self._last_state: dict = {}
|
||||
self._last_ams_set_request: dict | None = None
|
||||
self._state = {
|
||||
"nozzle_temp": 0.0,
|
||||
"nozzle_target": 0.0,
|
||||
@@ -1880,7 +1881,10 @@ class KobraXBridge:
|
||||
|
||||
def _on_multicolor_box(self, payload: dict):
|
||||
if payload.get("state") == "failed":
|
||||
log.warning(f"multiColorBox/report failed: {payload.get('data')}")
|
||||
req = getattr(self, "_last_ams_set_request", None)
|
||||
log.warning(
|
||||
f"multiColorBox setInfo rejected by printer: request={req} raw_response={payload.get('data')}"
|
||||
)
|
||||
self._state["last_ams_set_error"] = True
|
||||
return
|
||||
data = payload.get("data") or {}
|
||||
@@ -4046,6 +4050,10 @@ class KobraXBridge:
|
||||
box_id, local_slot = self._global_to_box_slot(index)
|
||||
loop = asyncio.get_event_loop()
|
||||
self._state["last_ams_set_error"] = False
|
||||
# Remembered so a later state="failed" report (which carries no slot
|
||||
# info of its own, see _on_multicolor_box) can be logged alongside the
|
||||
# request that triggered it - otherwise the failure is unattributable.
|
||||
self._last_ams_set_request = {"global": index, "box": box_id, "local_slot": local_slot, "type": mat, "color": color}
|
||||
# setInfo goes via the web/printer topic (like tempature/set). Verified via
|
||||
# Workbench-Vue mqtt_setInfo verifiziert — via slicer/printer/ wurden
|
||||
# slot changes are ignored by the printer and overwritten with the old
|
||||
|
||||
@@ -67,3 +67,15 @@ def test_non_dict_data_without_failed_state_does_not_crash():
|
||||
even if the printer doesn't set state="failed" for it."""
|
||||
b = _bridge()
|
||||
b._on_multicolor_box({"state": "success", "data": ["multi_color_box", []]})
|
||||
|
||||
|
||||
def test_failed_report_is_logged_with_the_triggering_request(caplog):
|
||||
"""The failure payload alone carries no slot/type/color info - the log
|
||||
must correlate it with the setInfo request that triggered it, otherwise
|
||||
the failure reason can't be diagnosed from bridge logs alone."""
|
||||
import logging
|
||||
b = _bridge()
|
||||
b._last_ams_set_request = {"global": 6, "box": 0, "local_slot": 3, "type": "PLA", "color": [33, 39, 33]}
|
||||
with caplog.at_level(logging.WARNING):
|
||||
b._on_multicolor_box(FAILED_PAYLOAD)
|
||||
assert any("global" in r.message and "6" in r.message for r in caplog.records)
|
||||
|
||||
Reference in New Issue
Block a user