11import logging
22import re
3+ import typing
34from pathlib import Path
45
56from PyQt6 import QtCore
67
8+ from .models import MMUState
9+
710logger : logging .Logger = logging .getLogger (__name__ )
811
912CONFIG_PATH : Path = Path ("~/printer_data/config/printer.cfg" ).expanduser ()
2124class AMUManager (QtCore .QObject ):
2225 """Main manager of the AMU system"""
2326
27+ run_gcode_signal : typing .ClassVar [QtCore .pyqtSignal ] = QtCore .pyqtSignal (
28+ str , name = "run-gcode"
29+ )
30+
31+ mmu_state_changed : typing .ClassVar [QtCore .pyqtSignal ] = QtCore .pyqtSignal (
32+ object , name = "mmu-state-changed"
33+ )
34+
35+ amu_toggled : typing .ClassVar [QtCore .pyqtSignal ] = QtCore .pyqtSignal (
36+ bool , name = "amu-toggled"
37+ )
38+
2439 def __init__ (self , parent : QtCore .QObject | None = None ) -> None :
2540 super ().__init__ (parent )
2641 self ._amu_state = False
42+ self ._mmu_state : MMUState | None = None
2743 self .__setup_configfile ()
2844
2945 def __setup_configfile (self ) -> None :
@@ -44,11 +60,10 @@ def _apply_patterns(self, state: bool) -> bool:
4460 state (bool): True: Uncomment, False: Comment
4561
4662 Returns:
47- bool: True: Sucess , False: Failed
63+ bool: True: Success , False: Failed
4864 """
49- # signal to say that it was changed AMU para mainwindow
5065 if self ._amu_state == state :
51- return
66+ return False
5267
5368 replacement = r"\2"
5469 if not state :
@@ -62,23 +77,114 @@ def _apply_patterns(self, state: bool) -> bool:
6277 return True
6378 except OSError as e :
6479 logger .error (
65- "Failed to apply(state=%s) AMU System: could not read/write %s\n %e " ,
80+ "Failed to apply(state=%s) AMU System: could not read/write %s\n %s " ,
6681 state ,
6782 self ._config_filename ,
6883 e ,
6984 )
7085 return False
7186
72- def toggle_amu_system (self , activate : bool ) -> bool :
73- """Method that comments/uncomments the AMU_FILES from the printer.cfg according with state value
87+ def toggle_amu_system (self , activate : bool ) -> None :
88+ """Enable or disable the AMU system by commenting/uncommenting config includes.
89+
90+ Emits:
91+ amu_toggled (bool): True if the operation succeeded, False otherwise.
7492
7593 Args:
76- state (bool): True: Uncomment, False: Comment
94+ activate (bool): True to enable the AMU, False to disable it.
95+
96+ """
97+ result : bool = self ._apply_patterns (activate )
98+ self .amu_toggled .emit (result )
99+
100+ def get_state (self ) -> MMUState | None :
101+ """Returns current MMU state, None if not yet received.
77102
78103 Returns:
79- bool: True: Sucess, False: Failed
104+ MMUState: Latest state received from Moonraker
105+ None: If no state has been received yet.
106+
107+ """
108+ return self ._mmu_state
109+
110+ def is_amu_active (self ) -> bool :
111+ """Returns whether AMU includes are currently uncommented in printer.cfg"""
112+ return self ._amu_state
113+
114+ def set_gate_info (
115+ self , gate : int , material : str , color : str , spool_id : int
116+ ) -> None :
117+ """Sets all gate attributes for a single MMU_GATE
118+
119+ Args:
120+ gate (int): Gate index (0-based).
121+ material (str): Filament material name, e.g. ``"PLA"``.
122+ color (str): Filament color as hex string, e.g. ``"ff56e0"``.
123+ spool_id (int): Spoolman spool ID, or -1 if not tracked.
124+ """
125+ ...
126+
127+ def set_gate_material (self , gate : int , material : str ) -> None :
128+ """Set the `material` at the gate `gate`
129+
130+ Args:
131+ gate (int): Gate index (0-based).
132+ material (str): Filament material name, e.g. ``"PLA"``.
133+ """
134+
135+ def set_gate_color (self , gate : int , color : str ) -> None :
136+ """Set the `color` at the gate `gate`
137+
138+ Args:
139+ gate (int): Gate index (0-based).
140+ color (str): Filament color, e.g. ``"ff56e0"``.
141+ """
142+
143+ def set_gate_spool (self , gate : int , spool_id : int ) -> None :
144+ """Set the `spool_id` at the gate `gate`
145+
146+ Args:
147+ gate (int): Gate index (0-based).
148+ spool_id (int): Spoolman spool ID, or -1 to clear.
149+ """
150+
151+ def home_mmu (self ) -> None :
152+ """Home the MMU selector by sending MMU_HOME."""
153+
154+ def reset_mmu (self ) -> None :
155+ """Reset the MMU and clear any pause or error state by sending MMU_RESET."""
156+
157+ def load_gate (self , gate : int ) -> None :
158+ """Load filament from the specified gate by sending MMU_LOAD
159+
160+ Args:
161+ gate (int): Gate index to select (0-based)
162+ """
163+
164+ def unload (self ) -> None :
165+ """Unload the currently loaded filament by sending MMU_UNLOAD."""
166+ ...
167+
168+ def select_tool (self , tool : int ) -> None :
169+ """Select a tool, triggering a filament change if needed.
170+
171+ Args:
172+ tool (int): Tool index to select (0-based).
173+ """
174+ ...
175+
176+ @QtCore .pyqtSlot (dict , name = "update_mmu_state" )
177+ def update_mmu_state (self , data : dict ) -> None :
178+ """Receive an MMU status dict from Moonraker and update internal state.
179+
180+ Called with either a full status response (on connect) or a diff
181+ (from notify_status_update). Builds or updates the MMUState and
182+ emits mmu_state_changed
183+
184+ Args:
185+ data (dict): Raw MMU status or diff dict from Moonraker
80186 """
81- return self . _apply_patterns ( activate )
187+ ...
82188
83189
84190if __name__ == "__main__" :
0 commit comments