Add full nozzle rack metrics and per-slot hover cards for H2C printers

Capture 4 additional fields from MQTT nozzle data (max_temp, serial_number,
filament_color, filament_id) and surface them through REST/WebSocket APIs.
Add per-slot hover popover to the NozzleRackCard showing all metrics, filament
color backgrounds on slots, and i18n labels in all 4 locales.
This commit is contained in:
maziggy
2026-02-09 15:10:49 +01:00
parent d9895aae5b
commit 6661bbf866
14 changed files with 712 additions and 455 deletions
+4
View File
@@ -369,6 +369,10 @@ async def get_printer_status(
nozzle_diameter=n.get("diameter", ""),
wear=n.get("wear"),
stat=n.get("stat"),
max_temp=n.get("max_temp", 0),
serial_number=n.get("serial_number", ""),
filament_color=n.get("filament_color", ""),
filament_id=n.get("filament_id", ""),
)
for n in (state.nozzle_rack or [])
]
+4
View File
@@ -153,6 +153,10 @@ class NozzleRackSlot(BaseModel):
nozzle_diameter: str = ""
wear: int | None = None
stat: int | None = None # Nozzle status (e.g. mounted/docked)
max_temp: int = 0 # Max temperature rating °C (0 = not set)
serial_number: str = "" # Nozzle serial number
filament_color: str = "" # RGBA hex ("00000000" = no filament)
filament_id: str = "" # Bambu filament ID
class PrintOptionsResponse(BaseModel):
+11
View File
@@ -1757,9 +1757,20 @@ class BambuMQTTClient:
"diameter": str(n.get("diameter", "")),
"wear": n.get("wear"),
"stat": n.get("stat"),
"max_temp": n.get("max_temp", 0),
"serial_number": str(n.get("serial_number", "")),
"filament_color": str(n.get("filament_colour", "")),
"filament_id": str(n.get("filament_id", "")),
}
for i, n in enumerate(nozzle_info)
]
if not hasattr(self, "_nozzle_rack_logged") and nozzle_info:
self._nozzle_rack_logged = True
logger.info(
"[%s] Nozzle rack raw keys: %s",
self.serial_number,
[list(n.keys()) for n in nozzle_info[:2]],
)
for nozzle in nozzle_info:
idx = nozzle.get("id", 0)
if idx < len(self.state.nozzles):
+15 -1
View File
@@ -648,7 +648,21 @@ def printer_state_to_dict(state: PrinterState, printer_id: int | None = None, mo
# Active extruder for dual-nozzle printers (0=right, 1=left)
"active_extruder": state.active_extruder,
# H2C nozzle rack (tool-changer dock positions)
"nozzle_rack": state.nozzle_rack or [],
# Map raw MQTT field names (type/diameter) to schema names (nozzle_type/nozzle_diameter)
"nozzle_rack": [
{
"id": n.get("id", 0),
"nozzle_type": n.get("type", ""),
"nozzle_diameter": n.get("diameter", ""),
"wear": n.get("wear"),
"stat": n.get("stat"),
"max_temp": n.get("max_temp", 0),
"serial_number": n.get("serial_number", ""),
"filament_color": n.get("filament_color", ""),
"filament_id": n.get("filament_id", ""),
}
for n in (state.nozzle_rack or [])
],
}
# Add cover URL if there's an active print and printer_id is provided
# Include PAUSE/PAUSED states so skip objects modal can show cover