mirror of
https://github.com/maziggy/bambuddy.git
synced 2026-10-18 03:54:17 +02:00
Fix A1/A1 Mini showing Printing instead of Idle (Issue #168)
Some A1/A1 Mini firmware versions incorrectly report stg_cur=0 (which maps to "Printing") even when the printer is idle. This is a known firmware bug also observed in the Home Assistant Bambu Lab integration. - Add A1_MODELS constant listing affected model variants - Add has_stg_cur_idle_bug() helper to identify affected models - Update get_derived_status_name() to check gcode_state before stg_cur for A1 models: if IDLE + stg_cur=0, return None to show "Idle" - Fix only applies when all conditions match (A1 model + IDLE + stg_cur=0) - Non-A1 printers and A1 printers without the bug are unaffected Closes #168
This commit is contained in:
@@ -92,6 +92,10 @@ All notable changes to Bambuddy will be documented in this file.
|
||||
- **Multi-Plate Thumbnail in Queue** - Fixed queue items showing wrong thumbnail for multi-plate files (Issue #166):
|
||||
- Queue now displays the correct plate thumbnail based on selected plate
|
||||
- Previously always showed plate 1 thumbnail regardless of selection
|
||||
- **A1/A1 Mini Shows Printing Instead of Idle** - Fixed incorrect status display for A1 series printers (Issue #168):
|
||||
- Some A1/A1 Mini firmware versions incorrectly report stage 0 ("Printing") when idle
|
||||
- Now checks gcode_state to correctly display "Idle" for affected printers
|
||||
- Fix only applies to A1 models with the specific buggy condition
|
||||
- **HMS Error Notifications** - Get notified when printer errors occur (Issue #84):
|
||||
- Automatic notifications for HMS errors (AMS issues, nozzle problems, etc.)
|
||||
- Human-readable error messages (853 error codes translated)
|
||||
|
||||
@@ -408,7 +408,7 @@ async def get_printer_status(printer_id: int, db: AsyncSession = Depends(get_db)
|
||||
nozzles=nozzles,
|
||||
print_options=print_options,
|
||||
stg_cur=state.stg_cur,
|
||||
stg_cur_name=get_derived_status_name(state),
|
||||
stg_cur_name=get_derived_status_name(state, printer.model),
|
||||
stg=state.stg,
|
||||
airduct_mode=state.airduct_mode,
|
||||
speed_level=state.speed_level,
|
||||
|
||||
@@ -33,6 +33,22 @@ CHAMBER_TEMP_SUPPORTED_MODELS = frozenset(
|
||||
]
|
||||
)
|
||||
|
||||
# Models that may incorrectly report stg_cur=0 when idle (firmware bug)
|
||||
# Based on Home Assistant Bambu Lab integration observations
|
||||
# See: https://github.com/greghesp/ha-bambulab/blob/main/custom_components/bambu_lab/pybambu/models.py
|
||||
A1_MODELS = frozenset(
|
||||
[
|
||||
# Display names
|
||||
"A1",
|
||||
"A1 MINI",
|
||||
"A1-MINI",
|
||||
"A1MINI",
|
||||
# Internal codes (from MQTT/SSDP)
|
||||
"N1", # A1 Mini
|
||||
"N2S", # A1
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
def supports_chamber_temp(model: str | None) -> bool:
|
||||
"""Check if a printer model has a real chamber temperature sensor.
|
||||
@@ -47,6 +63,19 @@ def supports_chamber_temp(model: str | None) -> bool:
|
||||
return model_upper in CHAMBER_TEMP_SUPPORTED_MODELS
|
||||
|
||||
|
||||
def has_stg_cur_idle_bug(model: str | None) -> bool:
|
||||
"""Check if a printer model may incorrectly report stg_cur=0 when idle.
|
||||
|
||||
Some A1/A1 Mini firmware versions report stg_cur=0 (which maps to "Printing")
|
||||
even when the printer is idle. This is a known firmware bug that was observed
|
||||
in the Home Assistant Bambu Lab integration.
|
||||
"""
|
||||
if not model:
|
||||
return False
|
||||
model_upper = model.strip().upper()
|
||||
return model_upper in A1_MODELS
|
||||
|
||||
|
||||
class PrinterInfo:
|
||||
"""Basic printer info for callbacks."""
|
||||
|
||||
@@ -373,13 +402,22 @@ class PrinterManager:
|
||||
return result
|
||||
|
||||
|
||||
def get_derived_status_name(state: PrinterState) -> str | None:
|
||||
def get_derived_status_name(state: PrinterState, model: str | None = None) -> str | None:
|
||||
"""
|
||||
Compute a human-readable status name based on printer state.
|
||||
|
||||
Uses stg_cur when available, otherwise derives status from temperature data
|
||||
when the printer is heating before a print starts.
|
||||
|
||||
Args:
|
||||
state: The printer state to analyze
|
||||
model: Optional printer model for model-specific workarounds
|
||||
"""
|
||||
# A1/A1 Mini firmware bug: some versions report stg_cur=0 when idle
|
||||
# Only correct this specific case (IDLE + stg_cur=0) for affected models
|
||||
if state.state == "IDLE" and state.stg_cur == 0 and has_stg_cur_idle_bug(model):
|
||||
return None
|
||||
|
||||
# If we have a valid calibration stage, use it
|
||||
# X1 models use -1 for idle, A1/P1 models use 255 for idle
|
||||
# Valid stage numbers are 0-254
|
||||
@@ -581,7 +619,7 @@ def printer_state_to_dict(state: PrinterState, printer_id: int | None = None, mo
|
||||
"wifi_signal": state.wifi_signal,
|
||||
# Calibration stage tracking
|
||||
"stg_cur": state.stg_cur,
|
||||
"stg_cur_name": get_derived_status_name(state),
|
||||
"stg_cur_name": get_derived_status_name(state, model),
|
||||
# Printable objects count for skip objects feature
|
||||
"printable_objects_count": len(state.printable_objects),
|
||||
# Fan speeds (0-100 percentage, None if not available)
|
||||
|
||||
@@ -12,6 +12,7 @@ import pytest
|
||||
from backend.app.services.printer_manager import (
|
||||
PrinterManager,
|
||||
get_derived_status_name,
|
||||
has_stg_cur_idle_bug,
|
||||
init_printer_connections,
|
||||
printer_state_to_dict,
|
||||
supports_chamber_temp,
|
||||
@@ -901,7 +902,7 @@ class TestGetDerivedStatusName:
|
||||
assert result == "Auto bed leveling"
|
||||
|
||||
def test_stg_cur_zero_returns_printing(self):
|
||||
"""Verify stg_cur=0 returns 'Printing'."""
|
||||
"""Verify stg_cur=0 returns 'Printing' when no model specified."""
|
||||
state = MagicMock()
|
||||
state.stg_cur = 0
|
||||
|
||||
@@ -909,6 +910,72 @@ class TestGetDerivedStatusName:
|
||||
|
||||
assert result == "Printing"
|
||||
|
||||
def test_a1_idle_with_stg_cur_zero_returns_none(self):
|
||||
"""Verify A1 with IDLE state and stg_cur=0 returns None (bug workaround)."""
|
||||
state = MagicMock()
|
||||
state.stg_cur = 0
|
||||
state.state = "IDLE"
|
||||
|
||||
# Test various A1 model names
|
||||
for model in ["A1", "A1 Mini", "A1-Mini", "A1MINI", "N1", "N2S"]:
|
||||
result = get_derived_status_name(state, model)
|
||||
assert result is None, f"Expected None for model {model}"
|
||||
|
||||
def test_a1_running_with_stg_cur_zero_returns_printing(self):
|
||||
"""Verify A1 with RUNNING state and stg_cur=0 still returns 'Printing'."""
|
||||
state = MagicMock()
|
||||
state.stg_cur = 0
|
||||
state.state = "RUNNING"
|
||||
|
||||
result = get_derived_status_name(state, "A1")
|
||||
|
||||
assert result == "Printing"
|
||||
|
||||
def test_non_a1_idle_with_stg_cur_zero_returns_printing(self):
|
||||
"""Verify non-A1 models with IDLE and stg_cur=0 still return 'Printing'."""
|
||||
state = MagicMock()
|
||||
state.stg_cur = 0
|
||||
state.state = "IDLE"
|
||||
|
||||
# X1C should not get the workaround
|
||||
result = get_derived_status_name(state, "X1C")
|
||||
|
||||
assert result == "Printing"
|
||||
|
||||
|
||||
class TestHasStgCurIdleBug:
|
||||
"""Tests for has_stg_cur_idle_bug function."""
|
||||
|
||||
def test_a1_models_return_true(self):
|
||||
"""Verify A1 model variants return True."""
|
||||
assert has_stg_cur_idle_bug("A1") is True
|
||||
assert has_stg_cur_idle_bug("A1 Mini") is True
|
||||
assert has_stg_cur_idle_bug("A1-Mini") is True
|
||||
assert has_stg_cur_idle_bug("A1MINI") is True
|
||||
assert has_stg_cur_idle_bug("a1") is True # case insensitive
|
||||
assert has_stg_cur_idle_bug("a1 mini") is True
|
||||
|
||||
def test_a1_internal_codes_return_true(self):
|
||||
"""Verify A1 internal model codes return True."""
|
||||
assert has_stg_cur_idle_bug("N1") is True # A1 Mini
|
||||
assert has_stg_cur_idle_bug("N2S") is True # A1
|
||||
|
||||
def test_non_a1_models_return_false(self):
|
||||
"""Verify non-A1 models return False."""
|
||||
assert has_stg_cur_idle_bug("X1C") is False
|
||||
assert has_stg_cur_idle_bug("X1") is False
|
||||
assert has_stg_cur_idle_bug("P1P") is False
|
||||
assert has_stg_cur_idle_bug("P1S") is False
|
||||
assert has_stg_cur_idle_bug("H2D") is False
|
||||
|
||||
def test_none_model_returns_false(self):
|
||||
"""Verify None model returns False."""
|
||||
assert has_stg_cur_idle_bug(None) is False
|
||||
|
||||
def test_empty_model_returns_false(self):
|
||||
"""Verify empty model returns False."""
|
||||
assert has_stg_cur_idle_bug("") is False
|
||||
|
||||
|
||||
class TestInitPrinterConnections:
|
||||
"""Tests for init_printer_connections function."""
|
||||
|
||||
Reference in New Issue
Block a user