|
|
@@ -1,6 +1,6 @@
|
|
|
import asyncio
|
|
|
import serial_asyncio
|
|
|
-from typing import List
|
|
|
+from typing import List, Optional
|
|
|
import logging
|
|
|
import datetime
|
|
|
import collections
|
|
|
@@ -21,8 +21,8 @@ class GRBLHandler:
|
|
|
|
|
|
self.controller_active = asyncio.Event()
|
|
|
|
|
|
- self.reader = None
|
|
|
- self.writer = None
|
|
|
+ self.reader : Optional[asyncio.StreamReader] = None
|
|
|
+ self.writer : Optional[asyncio.StreamWriter] = None
|
|
|
self.position_callbacks = []
|
|
|
|
|
|
async def connect(self):
|
|
|
@@ -41,7 +41,7 @@ class GRBLHandler:
|
|
|
raise serial_asyncio.serial.SerialException(f"Failed to connect to robot: {str(e)}")
|
|
|
|
|
|
init_response = await self._process_response()
|
|
|
- if not any(isinstance(response, collections.abc.Iterable) and "Grbl" in response for response in init_response):
|
|
|
+ if not any(isinstance(response, str) and "Grbl" in response for response in init_response):
|
|
|
raise RuntimeError("Failed to connect to GRBL")
|
|
|
|
|
|
logger.info("GRBL connected.")
|
|
|
@@ -87,6 +87,9 @@ class GRBLHandler:
|
|
|
if self.debug:
|
|
|
logger.debug(f"G-Code commands [{*commands,}] not sent in debug mode")
|
|
|
return
|
|
|
+ if not self.writer:
|
|
|
+ logger.error("Writer is not initialized. Cannot send G-Code commands.")
|
|
|
+ return
|
|
|
|
|
|
self.controller_active.set()
|
|
|
try:
|
|
|
@@ -134,7 +137,7 @@ class GRBLHandler:
|
|
|
|
|
|
return response_lines
|
|
|
|
|
|
- async def wait_until_idle(self, timeout_s, position: list[float] = None):
|
|
|
+ async def wait_until_idle(self, timeout_s, position: Optional[tuple[float,float,float]] = None):
|
|
|
"""Wait until GRBL reports idle status
|
|
|
|
|
|
Args:
|
|
|
@@ -167,7 +170,7 @@ class GRBLHandler:
|
|
|
|
|
|
await asyncio.sleep(0.5) # Async delay to prevent flooding
|
|
|
|
|
|
- async def send_and_wait_gcode(self, commands: List[str], timeout_s=60, position: list[float] = None):
|
|
|
+ async def send_and_wait_gcode(self, commands: List[str], timeout_s=60, position: Optional[tuple[float,float,float]] = None):
|
|
|
"""Send GCODE commands and wait until machine is idle"""
|
|
|
await self.send_gcode(commands)
|
|
|
await asyncio.sleep(0.2) # Delay to allow GRBL to process commands
|
|
|
@@ -184,30 +187,33 @@ class GRBLHandler:
|
|
|
for callback in self.position_callbacks:
|
|
|
callback(self.current_position)
|
|
|
|
|
|
- async def _process_response(self, timeout_s=6.0):
|
|
|
+ async def _process_response(self, timeout_s=6.0) -> list[str]:
|
|
|
"""Process GRBL responses"""
|
|
|
- if self.reader:
|
|
|
- response_lines = []
|
|
|
- first = True
|
|
|
- while True:
|
|
|
- try:
|
|
|
- current_timeout = timeout_s if first else 0.1
|
|
|
- line = await asyncio.wait_for(self.reader.readuntil(), timeout=current_timeout)
|
|
|
- decoded = line.strip().decode("utf-8")
|
|
|
- self._check_pos_callbacks(decoded)
|
|
|
- logger.debug(f"G-Code response: {decoded}")
|
|
|
- response_lines.append(decoded)
|
|
|
- first = False
|
|
|
- except asyncio.TimeoutError:
|
|
|
- # No more data available right now
|
|
|
- break
|
|
|
- except Exception as e:
|
|
|
- raise RuntimeError(f"Failed to process response: {e}")
|
|
|
-
|
|
|
- if not response_lines:
|
|
|
- logger.warning(f"No GRBL response received! ({timeout_s}s)")
|
|
|
+ response_lines : list[str] = []
|
|
|
|
|
|
+ if not self.reader:
|
|
|
return response_lines
|
|
|
+
|
|
|
+ first = True
|
|
|
+ while True:
|
|
|
+ try:
|
|
|
+ current_timeout = timeout_s if first else 0.1
|
|
|
+ line = await asyncio.wait_for(self.reader.readuntil(), timeout=current_timeout)
|
|
|
+ decoded = line.strip().decode("utf-8")
|
|
|
+ self._check_pos_callbacks(decoded)
|
|
|
+ logger.debug(f"G-Code response: {decoded}")
|
|
|
+ response_lines.append(decoded)
|
|
|
+ first = False
|
|
|
+ except asyncio.TimeoutError:
|
|
|
+ # No more data available right now
|
|
|
+ break
|
|
|
+ except Exception as e:
|
|
|
+ raise RuntimeError(f"Failed to process response: {e}")
|
|
|
+
|
|
|
+ if not response_lines:
|
|
|
+ logger.warning(f"No GRBL response received! ({timeout_s}s)")
|
|
|
+
|
|
|
+ return response_lines
|
|
|
|
|
|
def register_position_callback(self, callback):
|
|
|
"""Register callback for position updates
|