Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add a4s sealer #304

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
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
86 changes: 86 additions & 0 deletions docs/user_guide/sealer.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Sealers"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## A4S"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"%load_ext autoreload\n",
"%autoreload 2"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"from pylabrobot.sealing import Sealer, A4S\n",
"sealer = Sealer(backend=A4S(port=\"/dev/tty.usbserial-0001\"))"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [],
"source": [
"await sealer.setup()"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [],
"source": [
"await sealer.open_shuttle()"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [],
"source": [
"await sealer.close_shuttle()"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "env",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.9.19"
}
},
"nbformat": 4,
"nbformat_minor": 2
}
2 changes: 2 additions & 0 deletions pylabrobot/sealing/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
from .sealer import Sealer
from .a4s import A4S
71 changes: 71 additions & 0 deletions pylabrobot/sealing/a4s.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import asyncio
import serial
import time
from typing import Optional
from pylabrobot.sealing.backend import SealerBackend


class A4S(SealerBackend):
def __init__(self, port: str, timeout = 10) -> None:
self.port = port
self.dev: Optional[serial.Serial] = None
self.timeout = timeout

async def setup(self):
self.dev = serial.Serial(
port=self.port,
baudrate=19200,
bytesize=serial.EIGHTBITS,
parity=serial.PARITY_NONE,
stopbits=serial.STOPBITS_ONE,
xonxoff=False,
rtscts=False,
dsrdtr=False,
)
await self.system_reset()

async def stop(self):
self.dev.close()

async def send_command(self, command: str):
self.dev.write(command.encode())
await asyncio.sleep(0.1)

start = time.time()
r, x = b"", b""
# TODO: just reads a bunch of bytes??
# while x != b"" or (len(r) == 0 and x == b""):
# r += x
# x = self.dev.read()
# print(" read char", x)
# if time.time() - start > self.timeout:
# raise TimeoutError("Timeout while waiting for response")

return r

async def seal(self, temperature: int, duration: float):
await self.set_temperature(temperature)
await self.set_time(duration)
return await self.send_command("*00GS=zz!") # Command to conduct seal action

async def set_temperature(self, degree: int):
if not (0 <= degree <= 999):
raise ValueError("Temperature out of range. Please enter a value between 0 and 999.")
command = f"*00DH={degree:03d}zz!"
return await self.send_command(command)

async def set_time(self, seconds: float):
deciseconds = seconds * 10
if not (0 <= deciseconds <= 9999):
raise ValueError("Time out of range. Please enter a value between 0 and 9999.")
command = f"*00DT={deciseconds:04d}zz!"
return await self.send_command(command)

async def open_shuttle(self):
return await self.send_command("*00MO=zz!")

async def close_shuttle(self):
return await self.send_command("*00MC=zz!")

async def system_reset(self):
return await self.send_command("*00SR=zz!")
18 changes: 18 additions & 0 deletions pylabrobot/sealing/backend.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
from abc import ABCMeta, abstractmethod
from pylabrobot.machines.backends import MachineBackend


class SealerBackend(MachineBackend, metaclass=ABCMeta):
"""Backend for a sealer machine"""

@abstractmethod
async def seal(self, temperature: int, duration: float):
...

@abstractmethod
async def open_shuttle(self):
...

@abstractmethod
async def close_shuttle(self):
...
22 changes: 22 additions & 0 deletions pylabrobot/sealing/sealer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
from typing import Optional

from pylabrobot.machines import Machine

from .backend import SealerBackend


class Sealer(Machine):
"""A microplate sealer"""

def __init__(self, backend: SealerBackend):
super().__init__(backend=backend)
self.backend: SealerBackend = backend # fix type

async def seal(self, temperature: int, duration: float):
await self.backend.seal(temperature=temperature, duration=duration)

async def open_shuttle(self):
await self.backend.open_shuttle()

async def close_shuttle(self):
await self.backend.close_shuttle()
Loading