Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 12 additions & 4 deletions BlocksScreen/lib/klipper_message_filter.py
Original file line number Diff line number Diff line change
Expand Up @@ -285,18 +285,26 @@ def _re(pattern: str) -> Callable[[str], bool]:
hint="Replace the empty spool",
severity=Severity.ERROR,
),
# Same clog/tangle word Happy Hare reports and Mainsail's FlowGuard meter shows.
MessageRule(
source=MessageSource.GCODE_ERROR,
matcher=_sub("flowguard detected a clog"),
matcher=_sub("clog/tangle has been detected"),
display="Filament Clog or Tangle",
hint="Check the nozzle and filament path",
severity=Severity.ERROR,
),
MessageRule(
source=MessageSource.GCODE_ERROR,
matcher=_re(r"flowguard detected a clog|a clog has been detected"),
display="Filament Clog Detected",
hint="Check the extruder for a clog",
hint="Check the nozzle and extruder",
severity=Severity.ERROR,
),
MessageRule(
source=MessageSource.GCODE_ERROR,
matcher=_sub("flowguard detected a tangle"),
matcher=_re(r"flowguard detected a tangle|a tangle has been detected"),
display="Filament Tangle Detected",
hint="Clear the tangle",
hint="Check the spool and the feed into the MMU",
severity=Severity.ERROR,
),
# ── Gcode errors — heater / temperature ───────────────────────────────────
Expand Down
7 changes: 2 additions & 5 deletions BlocksScreen/lib/moonrakerComm.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,6 @@ def __init__(self, parent: QtCore.QObject) -> None:
self.daemon = True

self.connected = False
self.disconnected = False
self._reconnect_count = 0
self._klippy_state: str | None = None
self.callback_table: dict = {}
Expand Down Expand Up @@ -185,10 +184,8 @@ def on_error(self, *args) -> None:
"""Websocket error callback"""
# First argument is ws second is error message
_error = args[1] if len(args) == 2 else args[0]
logger.error("Websocket error, disconnected: %s", _error)
with self._state_lock:
self.connected = False
self.disconnected = True
# Raising callbacks land here with the socket open; real drops end in on_close.
logger.error("Websocket error: %s", _error)

def on_close(self, *args) -> None:
"""Websocket on close callback
Expand Down
25 changes: 24 additions & 1 deletion tests/lib/test_klipper_message_filter.py
Original file line number Diff line number Diff line change
Expand Up @@ -265,10 +265,33 @@ def test_re_no_match() -> None:
),
(
MessageSource.GCODE_ERROR,
"FlowGuard detected a tangle.\nReason for trip: Tension stuck",
"FlowGuard detected a tangle.\nReason for trip: Tension stuck after "
"38.20 mm motion and 20.00 mm relief "
"(triggering parameter: flowguard_max_relief)",
"Filament Tangle Detected",
Severity.ERROR,
),
(
MessageSource.GCODE_ERROR,
"MMU issue detected. Print will be paused\nReason: A tangle has been "
"detected on filament_tension and requires manual intervention",
"Filament Tangle Detected",
Severity.ERROR,
),
(
MessageSource.GCODE_ERROR,
"MMU issue detected. Print will be paused\nReason: A clog has been "
"detected on filament_compression and requires manual intervention",
"Filament Clog Detected",
Severity.ERROR,
),
(
MessageSource.GCODE_ERROR,
"MMU issue: A clog/tangle has been detected and requires manual "
"intervention",
"Filament Clog or Tangle",
Severity.ERROR,
),
# Gcode Echo
(
MessageSource.GCODE_ECHO,
Expand Down
8 changes: 8 additions & 0 deletions tests/lib/test_moonraker_comm_unit.py
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,14 @@ def close_then_fail(_packet):
qtbot.wait(20)
assert got == [{"error": {"code": -1, "message": "disconnected"}}]

def test_callback_error_keeps_socket_usable(self, ws):
"""A raising callback reaches on_error but the socket stays open."""
ws.connected = True
ws.ws = MagicMock()
ws.on_error(ws.ws, AttributeError("'FilamentTab' has no '_material_filter'"))
assert ws.send_request("server.info") is True
ws.ws.close.assert_not_called()

def test_send_while_disconnected_never_calls_back(self, ws, qtbot):
callback = MagicMock()
assert ws.send_request("server.info", callback=callback) is False
Expand Down