Skip to content

bugfix: resolve 40+ crashes, threading races, and Klipper protocol issues#200

Open
gmmcosta15 wants to merge 1 commit intodevfrom
bugfix/crash-history
Open

bugfix: resolve 40+ crashes, threading races, and Klipper protocol issues#200
gmmcosta15 wants to merge 1 commit intodevfrom
bugfix/crash-history

Conversation

@gmmcosta15
Copy link
Collaborator

@gmmcosta15 gmmcosta15 commented Mar 19, 2026

Select the type:

  • Feature
  • Bug fix
  • Code refactor
  • Documentation

This PR introduces the following changes:

Threading & concurrency (moonrakerComm.py):

  • Move class-level state vars (connected/connecting/_reconnect_count/callback_table)
    into init to prevent shared state across instances
  • Add _state_lock (RLock) and _request_lock guarding all reads/writes to those vars
  • Fix mutable default dict in send_request (params={} → params=None)
  • Fix unbound super() in OneShotTokenError (init without class arg)
  • Guard _retry_timer with None before stopTimer/startTimer calls; stop existing
    timer in try_connection before creating a new one (prevents orphaned threads)
  • sendEvent → postEvent for cross-thread event delivery
  • Wrap json.loads in try/except; use .get() on all external response dicts
  • Fix dest_dir guard (False → None) in copy/move file; fix machine.update.client
    missing params dict; fix machine.update.rollback method typo (comma → dot)
  • Add klippy startup/disconnected retry cap (30 attempts) to prevent infinite loop
  • Add join(timeout=self.timeout+1) on _wst to avoid indefinite block

RepeatedTimer: fix inverted stopEvent semantics (set=stop, clear=running)

Pi runtime crashes:

  • cancelPage: fix AttributeError on file_metadata dict access
  • connectionPage: fix stale slot name
  • inputshaperPage: fix uninitialized currentItem reference
  • mainWindow: fix _handle_notify (dict.popitem → next(iter(items())));
    fix global_back tab-bar gate; fix logger f-string
  • filamentTab: fix slot signature mismatch; fix stale _is_printing state;
    fix bare self.isVisible reference (missing parentheses)
  • jobStatusPage: use separate event_state var (never reassign lstate);
    capture file locals before clearing state; print_finish only on complete;
    layer fallback uses Mainsail ceil formula; layer_fallback flag decoupled
    from total_laye
  • sensorsPanel: removeWidget+deleteLater before clearing tracking dict on
    reconnect to prevent widget stacking
  • babystepPage: label sync with confirmed Klipper value, button reorder,
    code deduplication
  • probeHelperPage: only process is_active when key present in update dict
    (Klipper sends position-only reensaver: guard DPMS calls with hasattr(_dpms_available) check

Python 3.11 typing (20 files):

  • Opional/Union/List/Dict → native syntax; add from future import annotations
  • filament.brand setter: return type None; _spool_type initialized in init
  • files.py: remove duplicate ReceivedFileData import; use events.ReceivedFileData

helper_methods:

  • convert_bytes_to_mb: remove spurious self param; rename bytes → size_bytes
  • calculate_current_layer: Mainsail formula (ceil((z-first)/layer+1)), clamped
  • calculate_max_layers: extracted from calculate_current_layer; max(1,...) guard
  • normalize, check_filepath_permission, check_dir_existence: pathlib + type hints
  • estmate_print_time: modernized variable names and return type annotation
  • Remove unused get_file_loc/digest_hash stubs; remove normalize import from
    controlTab and tunePage

controlTab/tunePage slider split:

  • controlTab.on_slider_change: handles fan_generics only (SET_FAN_SPEED)
  • tunePage: _on_speed_slider_change for print speed (M220) and on_slider_change
    for fan_generics — eliminates collision when fan is named speed

Motivation

  • Fix 40+ bugs causing crashes, UI freezes, and incorrect state on Pi hardware, including thread-race conditions in the WebSocket layer, bad event dispatch between threads, and incorrect Klipper protocol handling
  • Modernise Python typing across 20 files (Optional/Union/List/Dict → native 3.11 syntax) and clean up helper_methods.py (spurious self, shadow of bytes builtin, Mainsail-ported layer formulas)
  • Split fan/speed slider callbacks in controlTab and tunePage to eliminate gcode dispatch errors when a fan_generic is named "speed"

…sues

  Threading & concurrency (moonrakerComm.py):
  - Move class-level state vars (connected/connecting/_reconnect_count/callback_table)
    into __init__ to prevent shared state across instances
  - Add _state_lock (RLock) and _request_lock guarding all reads/writes to those vars
  - Fix mutable default dict in send_request (params={} → params=None)
  - Fix unbound super() in OneShotTokenError (__init__ without class arg)
  - Guard _retry_timer with None before stopTimer/startTimer calls; stop existing
    timer in try_connection before creating a new one (prevents orphaned threads)
  - sendEvent → postEvent for cross-thread event delivery
  - Wrap json.loads in try/except; use .get() on all external response dicts
  - Fix dest_dir guard (False → None) in copy/move file; fix machine.update.client
    missing params dict; fix machine.update.rollback method typo (comma → dot)
  - Add klippy startup/disconnected retry cap (30 attempts) to prevent infinite loop
  - Add join(timeout=self.timeout+1) on _wst to avoid indefinite block

  RepeatedTimer: fix inverted stopEvent semantics (set=stop, clear=running)

  Pi runtime crashes:
  - cancelPage: fix AttributeError on file_metadata dict access
  - connectionPage: fix stale slot name
  - inputshaperPage: fix uninitialized currentItem reference
  - mainWindow: fix _handle_notify (dict.popitem → next(iter(items())));
    fix global_back tab-bar gate; fix logger f-string
  - filamentTab: fix slot signature mismatch; fix stale _is_printing state;
    fix bare self.isVisible reference (missing parentheses)
  - jobStatusPage: use separate event_state var (never reassign lstate);
    capture file locals before clearing state; print_finish only on complete;
    layer fallback uses Mainsail ceil formula; layer_fallback flag decoupled
    from total_layer
  - sensorsPanel: removeWidget+deleteLater before clearing tracking dict on
    reconnect to prevent widget stacking
  - babystepPage: label sync with confirmed Klipper value, button reorder,
    code deduplication
  - probeHelperPage: only process is_active when key present in update dict
    (Klipper sends position-only partial updates after TESTZ)
  - screensaver: guard DPMS calls with hasattr(_dpms_available) check

  Python 3.11 typing (20 files):
  - Optional/Union/List/Dict → native syntax; add from __future__ import annotations
  - filament.brand setter: return type None; _spool_type initialized in __init__
  - files.py: remove duplicate ReceivedFileData import; use events.ReceivedFileData

  helper_methods:
  - convert_bytes_to_mb: remove spurious self param; rename bytes → size_bytes
  - calculate_current_layer: Mainsail formula (ceil((z-first)/layer+1)), clamped
  - calculate_max_layers: extracted from calculate_current_layer; max(1,...) guard
  - normalize, check_filepath_permission, check_dir_existence: pathlib + type hints
  - estimate_print_time: modernized variable names and return type annotation
  - Remove unused get_file_loc/digest_hash stubs; remove normalize import from
    controlTab and tunePage

  controlTab/tunePage slider split:
  - controlTab.on_slider_change: handles fan_generics only (SET_FAN_SPEED)
  - tunePage: _on_speed_slider_change for print speed (M220) and on_slider_change
    for fan_generics — eliminates collision when fan is named speed
@gmmcosta15 gmmcosta15 self-assigned this Mar 19, 2026
@gmmcosta15 gmmcosta15 requested a review from HugoCLSC March 19, 2026 16:16
@gmmcosta15 gmmcosta15 marked this pull request as ready for review March 19, 2026 16:17
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Separate this changes into a new PR

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant