From 4e3cace7c176ea6a183e3801b8c2ccc82748b11a Mon Sep 17 00:00:00 2001 From: ben-ray Date: Tue, 11 Mar 2025 17:54:11 -0700 Subject: [PATCH 1/2] make hhs async --- pylabrobot/heating_shaking/hamilton.py | 38 +++++++++++++++----------- 1 file changed, 22 insertions(+), 16 deletions(-) diff --git a/pylabrobot/heating_shaking/hamilton.py b/pylabrobot/heating_shaking/hamilton.py index 7c1688c9d8..3ac84e2b03 100644 --- a/pylabrobot/heating_shaking/hamilton.py +++ b/pylabrobot/heating_shaking/hamilton.py @@ -1,3 +1,4 @@ +import asyncio from enum import Enum from typing import Literal @@ -51,19 +52,24 @@ def serialize(self) -> dict: "shaker_index": self.shaker_index, } - def _send_command(self, command: str, **kwargs): - assert len(command) == 2, "Command must be 2 characters long" - args = "".join([f"{key}{value}" for key, value in kwargs.items()]) - self.io.write(f"T{self.shaker_index}{command}id{str(self.command_id).zfill(4)}{args}".encode()) - - self.command_id = (self.command_id + 1) % 10_000 - return self.io.read() + async def _send_command(self, command: str, **kwargs): + assert len(command) == 2, "Command must be 2 characters long" + args = "".join([f"{key}{value}" for key, value in kwargs.items()]) + + # Run blocking I/O in a separate thread + await asyncio.to_thread(self.io.write, f"T{self.shaker_index}{command}id{str(self.command_id).zfill(4)}{args}".encode()) + + self.command_id = (self.command_id + 1) % 10_000 + + # Read response asynchronously + response = await asyncio.to_thread(self.io.read) + return response async def shake( self, speed: float = 800, direction: Literal[0, 1] = 0, - acceleration: int = 1_000, + acceleration: int = 500, ): """ speed: steps per second @@ -83,7 +89,7 @@ async def stop_shaking(self): await self._wait_for_stop() async def _move_plate_lock(self, position: PlateLockPosition): - return self._send_command("LP", lp=position.value) + return await self._send_command("LP", lp=position.value) async def lock_plate(self): await self._move_plate_lock(PlateLockPosition.LOCKED) @@ -93,34 +99,34 @@ async def unlock_plate(self): async def _initialize_lock(self): """Firmware command initialize lock.""" - result = self._send_command("LI") + result = await self._send_command("LI") return result async def _start_shaking(self, direction: int, speed: int, acceleration: int): """Firmware command for starting shaking.""" speed_str = str(speed).zfill(4) acceleration_str = str(acceleration).zfill(5) - return self._send_command("SB", st=direction, sv=speed_str, sr=acceleration_str) + return await self._send_command("SB", st=direction, sv=speed_str, sr=acceleration_str) async def _stop_shaking(self): """Firmware command for stopping shaking.""" - return self._send_command("SC") + return await self._send_command("SC") async def _wait_for_stop(self): """Firmware command for waiting for shaking to stop.""" - return self._send_command("SW") + return await self._send_command("SW") async def set_temperature(self, temperature: float): """set temperature in Celsius""" temp_str = f"{round(10*temperature):04d}" - return self._send_command("TA", ta=temp_str) + return await self._send_command("TA", ta=temp_str) async def get_current_temperature(self) -> float: """get temperature in Celsius""" - response = self._send_command("RT").decode("ascii") + response = await self._send_command("RT").decode("ascii") temp = str(response).split(" ")[1].strip("+") return float(temp) / 10 async def deactivate(self): """turn off heating""" - return self._send_command("TO") + return await self._send_command("TO") From 98865bb922c9eae5d42e74561bb7a8f339864d1a Mon Sep 17 00:00:00 2001 From: ben-ray Date: Tue, 11 Mar 2025 17:55:32 -0700 Subject: [PATCH 2/2] less yapping --- pylabrobot/heating_shaking/hamilton.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/pylabrobot/heating_shaking/hamilton.py b/pylabrobot/heating_shaking/hamilton.py index 3ac84e2b03..efabb60ebf 100644 --- a/pylabrobot/heating_shaking/hamilton.py +++ b/pylabrobot/heating_shaking/hamilton.py @@ -54,14 +54,11 @@ def serialize(self) -> dict: async def _send_command(self, command: str, **kwargs): assert len(command) == 2, "Command must be 2 characters long" - args = "".join([f"{key}{value}" for key, value in kwargs.items()]) - # Run blocking I/O in a separate thread + args = "".join([f"{key}{value}" for key, value in kwargs.items()]) await asyncio.to_thread(self.io.write, f"T{self.shaker_index}{command}id{str(self.command_id).zfill(4)}{args}".encode()) self.command_id = (self.command_id + 1) % 10_000 - - # Read response asynchronously response = await asyncio.to_thread(self.io.read) return response