diff --git a/docs/user_guide/02_analytical/plate-reading/byonoy.ipynb b/docs/user_guide/02_analytical/plate-reading/byonoy.ipynb
index 7ed00febadc..620385c5720 100644
--- a/docs/user_guide/02_analytical/plate-reading/byonoy.ipynb
+++ b/docs/user_guide/02_analytical/plate-reading/byonoy.ipynb
@@ -1,53 +1,48 @@
{
"cells": [
{
- "cell_type": "code",
- "execution_count": 1,
- "id": "6aa99372",
+ "cell_type": "markdown",
+ "id": "63d8a7a6-1107-4334-8b73-598aa1ca97c4",
"metadata": {},
- "outputs": [],
"source": [
- "from byonoy import byonoy_absorbance_adapter, byonoy_absorbance96_base_and_reader\n",
- "a = byonoy_absorbance_adapter(name='a')\n",
- "b, r = byonoy_absorbance96_base_and_reader(name='b', assign=True)"
+ "# Byonoy Absorbance 96 Automate\n",
+ "\n",
+ "| Summary | Photo |\n",
+ "|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------------------------------------------------|\n",
+ "| - [OEM Link](https://byonoy.com/absorbance-automate/)
- **Communication Protocol / Hardware**: Serial (HID)/ USB-A
- **Communication Level**: Firmware
- VID:PID 16d0:1199
- Serial: \"BYOMAA00058\"
- |  |"
]
},
{
- "cell_type": "code",
- "execution_count": 2,
- "id": "84949548",
+ "cell_type": "markdown",
+ "id": "840adda3-0ea1-4e7c-b0cb-34dd2244de69",
"metadata": {},
- "outputs": [],
"source": [
- "a.assign_child_resource(b)"
+ "---\n",
+ "## Setup Instructions (Physical)\n",
+ "\n",
+ "The Byonoy Absorbance 96 Automate is a an absorbance plate reader consisting of...\n",
+ "1. a `base` containing the liqht source,\n",
+ "2. a `reader_cap` containing the light detectors, and\n",
+ "3. a `cap_adapter` representing a simple resource_holder for the `reader_cap`\n",
+ "\n",
+ "It requires only one cable connections to be operational:\n",
+ "1. USB cable (USB-C at `base` end; USB-A at control PC end)"
]
},
{
- "cell_type": "code",
- "execution_count": 3,
- "id": "b2e6e986",
+ "cell_type": "markdown",
+ "id": "e4aa8066-9eb5-4f8a-8d69-372712bdb3b5",
"metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "(ResourceHolder(name=a, location=None, size_x=127.76, size_y=85.59, size_z=14.07, category=resource_holder),\n",
- " ByonoyBase(name=b_base, location=Coordinate(-05.120, -05.055, 011.620), size_x=138, size_y=95.7, size_z=27.7, category=None),\n",
- " PlateReader(name=b_reader, location=Coordinate(000.000, 000.000, 010.660), size_x=138, size_y=95.7, size_z=0, category=None))"
- ]
- },
- "execution_count": 3,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
"source": [
- "a, b, r"
+ "---\n",
+ "## Setup Instructions (Programmatic)\n",
+ "\n",
+ "If used with a liquid handler, first setup the liquid handler:"
]
},
{
"cell_type": "code",
- "execution_count": 4,
+ "execution_count": 1,
"id": "1fd4d917",
"metadata": {},
"outputs": [],
@@ -60,7 +55,7 @@
},
{
"cell_type": "code",
- "execution_count": 5,
+ "execution_count": 2,
"id": "abde0e65",
"metadata": {},
"outputs": [
@@ -80,9 +75,17 @@
"await lh.setup()"
]
},
+ {
+ "cell_type": "markdown",
+ "id": "165bd434-5899-4623-ac67-91d2aad55e7c",
+ "metadata": {},
+ "source": [
+ "Then generate a plate definition for the plate you want to read:"
+ ]
+ },
{
"cell_type": "code",
- "execution_count": 6,
+ "execution_count": 3,
"id": "5be9a197",
"metadata": {},
"outputs": [
@@ -103,112 +106,249 @@
"lh.deck.assign_child_resource(plate, location=Coordinate(0, 0, 0))"
]
},
+ {
+ "cell_type": "markdown",
+ "id": "bee933e6-b6df-4de7-aad1-40a2f0ba6721",
+ "metadata": {},
+ "source": [
+ "Now instantiate the Byonoy absorbance plate reader:"
+ ]
+ },
{
"cell_type": "code",
- "execution_count": 7,
- "id": "219becbc",
+ "execution_count": 4,
+ "id": "6aa99372",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
- "Picking up resource: ResourcePickup(resource=PlateReader(name=b_reader, location=Coordinate(000.000, 000.000, 010.660), size_x=138, size_y=95.7, size_z=0, category=None), offset=Coordinate(x=0, y=0, z=0), pickup_distance_from_top=0, direction=)\n",
- "Dropping resource: ResourceDrop(resource=PlateReader(name=b_reader, location=Coordinate(000.000, 000.000, 010.660), size_x=138, size_y=95.7, size_z=0, category=None), destination=Coordinate(x=200, y=0, z=0), destination_absolute_rotation=Rotation(x=0, y=0, z=0), offset=Coordinate(x=0, y=0, z=0), pickup_distance_from_top=0, pickup_direction=, drop_direction=, rotation=0)\n",
- "Resource b_reader was assigned to the liquid handler.\n"
+ "Resource cap_adapter was assigned to the liquid handler.\n"
]
}
],
"source": [
- "# move the reader off the base\n",
- "await lh.move_resource(r, Coordinate(200, 0, 0))"
+ "from pylabrobot.plate_reading.byonoy import (\n",
+ " byonoy_absorbance_adapter,\n",
+ " byonoy_absorbance96_base_and_reader\n",
+ ")\n",
+ "\n",
+ "cap_adapter = byonoy_absorbance_adapter(name='cap_adapter')\n",
+ "\n",
+ "base, reader_cap = byonoy_absorbance96_base_and_reader(name='base', assign=True)\n",
+ "\n",
+ "lh.deck.assign_child_resource(cap_adapter, location=Coordinate(400, 0, 0))"
]
},
{
"cell_type": "code",
- "execution_count": 8,
- "id": "c7f821fd",
+ "execution_count": 5,
+ "id": "a10f9bb9",
"metadata": {},
"outputs": [
{
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "Resource a was assigned to the liquid handler.\n"
- ]
+ "data": {
+ "text/plain": [
+ "True"
+ ]
+ },
+ "execution_count": 5,
+ "metadata": {},
+ "output_type": "execute_result"
}
],
"source": [
- "lh.deck.assign_child_resource(a, location=Coordinate(400, 0, 0))"
+ "await reader_cap.setup()\n",
+ "\n",
+ "reader_cap.setup_finished"
+ ]
+ },
+ {
+ "cell_type": "raw",
+ "id": "860c3830-e2a8-4ae3-a4bb-586ae993d849",
+ "metadata": {},
+ "source": [
+ "## Test Movement for Plate Reading"
+ ]
+ },
+ {
+ "cell_type": "raw",
+ "id": "32de1568-625b-4114-ae55-df1c03ea9230",
+ "metadata": {},
+ "source": [
+ "# move the reader off the base\n",
+ "await lh.move_resource(reader_cap, Coordinate(200, 0, 0))"
+ ]
+ },
+ {
+ "cell_type": "raw",
+ "id": "4199936d-efd1-423c-9714-20b0ae581e10",
+ "metadata": {
+ "scrolled": true
+ },
+ "source": [
+ "await lh.move_resource(plate, base.plate_holder)"
+ ]
+ },
+ {
+ "cell_type": "raw",
+ "id": "b11f154e-2025-4092-9a52-fb14af1a1520",
+ "metadata": {},
+ "source": [
+ "await lh.move_resource(reader_cap, base.reader_holder)"
+ ]
+ },
+ {
+ "cell_type": "raw",
+ "id": "0b975857-6b26-49c9-947d-db25763e332d",
+ "metadata": {},
+ "source": [
+ "adapter.assign_child_resource(base)"
]
},
{
"cell_type": "code",
- "execution_count": 9,
- "id": "134cd064",
+ "execution_count": 6,
+ "id": "b2e6e986",
"metadata": {},
"outputs": [
{
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "Picking up resource: ResourcePickup(resource=Plate(name=plate, size_x=127.6, size_y=85.75, size_z=13.83, location=Coordinate(000.000, 000.000, 000.000)), offset=Coordinate(x=0, y=0, z=0), pickup_distance_from_top=0, direction=)\n",
- "Dropping resource: ResourceDrop(resource=Plate(name=plate, size_x=127.6, size_y=85.75, size_z=13.83, location=Coordinate(000.000, 000.000, 000.000)), destination=Coordinate(x=400.0, y=0.0, z=39.32), destination_absolute_rotation=Rotation(x=0, y=0, z=0), offset=Coordinate(x=0, y=0, z=0), pickup_distance_from_top=0, pickup_direction=, drop_direction=, rotation=0)\n",
- "Resource plate was unassigned from the liquid handler.\n",
- "Resource plate was assigned to the liquid handler.\n"
- ]
+ "data": {
+ "text/plain": [
+ "(ResourceHolder(name='cap_adapter', location=Coordinate(400.000, 000.000, 000.000), size_x=127.76, size_y=85.59, size_z=14.07, category=resource_holder),\n",
+ " ByonoyBase(name='base_base', location=None, size_x=138, size_y=95.7, size_z=27.7, category=None),\n",
+ " PlateReader(name='base_reader', location=Coordinate(000.000, 000.000, 010.660), size_x=138, size_y=95.7, size_z=0, category=None))"
+ ]
+ },
+ "execution_count": 6,
+ "metadata": {},
+ "output_type": "execute_result"
}
],
"source": [
- "await lh.move_resource(plate, b.plate_holder)"
+ "cap_adapter, base, reader_cap"
]
},
{
- "cell_type": "code",
- "execution_count": 10,
- "id": "867ec7d8",
+ "cell_type": "markdown",
+ "id": "1ccafe3d-56c1-405f-b79e-6d4f8930e49d",
+ "metadata": {},
+ "source": [
+ "---\n",
+ "\n",
+ "## Usage / Machine Features"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "30619f34-af58-4a74-b4fd-e2d53033c2de",
"metadata": {},
+ "source": [
+ "### Query Machine Configuration"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 7,
+ "id": "2254228f-2864-4174-a615-9d1aed119ad5",
+ "metadata": {
+ "scrolled": true
+ },
"outputs": [
{
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "Picking up resource: ResourcePickup(resource=PlateReader(name=b_reader, location=Coordinate(200.000, 000.000, 000.000), size_x=138, size_y=95.7, size_z=0, category=None), offset=Coordinate(x=0, y=0, z=0), pickup_distance_from_top=0, direction=)\n",
- "Dropping resource: ResourceDrop(resource=PlateReader(name=b_reader, location=Coordinate(200.000, 000.000, 000.000), size_x=138, size_y=95.7, size_z=0, category=None), destination=Coordinate(x=394.88, y=-5.055, z=22.28), destination_absolute_rotation=Rotation(x=0, y=0, z=0), offset=Coordinate(x=0, y=0, z=0), pickup_distance_from_top=0, pickup_direction=, drop_direction=, rotation=0)\n",
- "Resource b_reader was unassigned from the liquid handler.\n",
- "Resource b_reader was assigned to the liquid handler.\n"
+ "ename": "CancelledError",
+ "evalue": "",
+ "output_type": "error",
+ "traceback": [
+ "\u001b[31m---------------------------------------------------------------------------\u001b[39m",
+ "\u001b[31mCancelledError\u001b[39m Traceback (most recent call last)",
+ "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[7]\u001b[39m\u001b[32m, line 1\u001b[39m\n\u001b[32m----> \u001b[39m\u001b[32m1\u001b[39m \u001b[38;5;28;01mawait\u001b[39;00m reader_cap.backend.get_available_absorbance_wavelengths()\n",
+ "\u001b[36mFile \u001b[39m\u001b[32m~/Desktop/GitHub/pylabrobot/pylabrobot/plate_reading/byonoy/byonoy_backend.py:135\u001b[39m, in \u001b[36mByonoyAbsorbance96AutomateBackend.get_available_absorbance_wavelengths\u001b[39m\u001b[34m(self)\u001b[39m\n\u001b[32m 134\u001b[39m \u001b[38;5;28;01masync\u001b[39;00m \u001b[38;5;28;01mdef\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[34mget_available_absorbance_wavelengths\u001b[39m(\u001b[38;5;28mself\u001b[39m) -> List[\u001b[38;5;28mfloat\u001b[39m]:\n\u001b[32m--> \u001b[39m\u001b[32m135\u001b[39m available_wavelengths_r = \u001b[38;5;28;01mawait\u001b[39;00m \u001b[38;5;28mself\u001b[39m.send_command(\n\u001b[32m 136\u001b[39m report_id=\u001b[32m0x0330\u001b[39m,\n\u001b[32m 137\u001b[39m payload_fmt=\u001b[33m\"\u001b[39m\u001b[33m<30h\u001b[39m\u001b[33m\"\u001b[39m,\n\u001b[32m 138\u001b[39m payload=[\u001b[32m0\u001b[39m] * \u001b[32m30\u001b[39m,\n\u001b[32m 139\u001b[39m wait_for_response=\u001b[38;5;28;01mTrue\u001b[39;00m,\n\u001b[32m 140\u001b[39m )\n\u001b[32m 141\u001b[39m \u001b[38;5;28;01massert\u001b[39;00m available_wavelengths_r \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m, \u001b[33m\"\u001b[39m\u001b[33mFailed to get available wavelengths.\u001b[39m\u001b[33m\"\u001b[39m\n\u001b[32m 142\u001b[39m \u001b[38;5;66;03m# cut out the first 2 bytes, then read the next 2 bytes as an integer\u001b[39;00m\n\u001b[32m 143\u001b[39m \u001b[38;5;66;03m# 64 - 4 = 60. 60/2 = 30 16 bit integers\u001b[39;00m\n",
+ "\u001b[36mFile \u001b[39m\u001b[32m~/Desktop/GitHub/pylabrobot/pylabrobot/plate_reading/byonoy/byonoy_backend.py:80\u001b[39m, in \u001b[36m_ByonoyBase.send_command\u001b[39m\u001b[34m(self, report_id, payload_fmt, payload, wait_for_response)\u001b[39m\n\u001b[32m 77\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m time.time() - t0 > \u001b[32m120\u001b[39m: \u001b[38;5;66;03m# read for 2 minutes max. typical is 1m5s.\u001b[39;00m\n\u001b[32m 78\u001b[39m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mTimeoutError\u001b[39;00m(\u001b[33m\"\u001b[39m\u001b[33mReading luminescence data timed out after 2 minutes.\u001b[39m\u001b[33m\"\u001b[39m)\n\u001b[32m---> \u001b[39m\u001b[32m80\u001b[39m response = \u001b[38;5;28;01mawait\u001b[39;00m \u001b[38;5;28mself\u001b[39m.io.read(\u001b[32m64\u001b[39m, timeout=\u001b[32m30\u001b[39m)\n\u001b[32m 81\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mlen\u001b[39m(response) == \u001b[32m0\u001b[39m:\n\u001b[32m 82\u001b[39m \u001b[38;5;28;01mcontinue\u001b[39;00m\n",
+ "\u001b[36mFile \u001b[39m\u001b[32m~/Desktop/GitHub/pylabrobot/pylabrobot/io/hid.py:109\u001b[39m, in \u001b[36mHID.read\u001b[39m\u001b[34m(self, size, timeout)\u001b[39m\n\u001b[32m 107\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mself\u001b[39m._executor \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m:\n\u001b[32m 108\u001b[39m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mRuntimeError\u001b[39;00m(\u001b[33m\"\u001b[39m\u001b[33mCall setup() first.\u001b[39m\u001b[33m\"\u001b[39m)\n\u001b[32m--> \u001b[39m\u001b[32m109\u001b[39m r = \u001b[38;5;28;01mawait\u001b[39;00m loop.run_in_executor(\u001b[38;5;28mself\u001b[39m._executor, _read)\n\u001b[32m 110\u001b[39m logger.log(LOG_LEVEL_IO, \u001b[33m\"\u001b[39m\u001b[33m[\u001b[39m\u001b[38;5;132;01m%s\u001b[39;00m\u001b[33m] read \u001b[39m\u001b[38;5;132;01m%s\u001b[39;00m\u001b[33m\"\u001b[39m, \u001b[38;5;28mself\u001b[39m._unique_id, r)\n\u001b[32m 111\u001b[39m capturer.record(HIDCommand(device_id=\u001b[38;5;28mself\u001b[39m._unique_id, action=\u001b[33m\"\u001b[39m\u001b[33mread\u001b[39m\u001b[33m\"\u001b[39m, data=r.hex()))\n",
+ "\u001b[31mCancelledError\u001b[39m: "
]
}
],
"source": [
- "await lh.move_resource(r, b.reader_holder)"
+ "await reader_cap.backend.get_available_absorbance_wavelengths()"
]
},
{
"cell_type": "code",
- "execution_count": 11,
- "id": "439663bd",
+ "execution_count": null,
+ "id": "cb5404f7-56c1-4647-b6cb-32606ac470f3",
+ "metadata": {},
+ "outputs": [],
+ "source": []
+ },
+ {
+ "cell_type": "markdown",
+ "id": "fc15c1b4-be77-4180-a5ce-d8a31480d0d4",
+ "metadata": {},
+ "source": [
+ "### Measure Absorbance"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 9,
+ "id": "761a587a-7084-40f8-9820-ef934230fb2f",
"metadata": {},
"outputs": [
{
- "data": {
- "text/plain": [
- "ResourceHolder(name=b_base_reader_holder, location=Coordinate(000.000, 000.000, 000.000), size_x=138, size_y=95.7, size_z=0, category=resource_holder)"
- ]
- },
- "execution_count": 11,
- "metadata": {},
- "output_type": "execute_result"
+ "ename": "TimeoutError",
+ "evalue": "Reading luminescence data timed out after 2 minutes.",
+ "output_type": "error",
+ "traceback": [
+ "\u001b[31m---------------------------------------------------------------------------\u001b[39m",
+ "\u001b[31mTimeoutError\u001b[39m Traceback (most recent call last)",
+ "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[9]\u001b[39m\u001b[32m, line 1\u001b[39m\n\u001b[32m----> \u001b[39m\u001b[32m1\u001b[39m \u001b[38;5;28;01mawait\u001b[39;00m reader_cap.backend.read_absorbance(\n\u001b[32m 2\u001b[39m plate = CellVis_96_wellplate_350uL_Fb,\n\u001b[32m 3\u001b[39m wavelength = \u001b[32m600\u001b[39m\n\u001b[32m 4\u001b[39m )\n",
+ "\u001b[36mFile \u001b[39m\u001b[32m~/Desktop/GitHub/pylabrobot/pylabrobot/plate_reading/byonoy/byonoy_backend.py:152\u001b[39m, in \u001b[36mByonoyAbsorbance96AutomateBackend.read_absorbance\u001b[39m\u001b[34m(self, plate, wavelength)\u001b[39m\n\u001b[32m 148\u001b[39m \u001b[38;5;28;01masync\u001b[39;00m \u001b[38;5;28;01mdef\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[34mread_absorbance\u001b[39m(\u001b[38;5;28mself\u001b[39m, plate: Plate, wavelength: \u001b[38;5;28mint\u001b[39m) -> List[List[\u001b[38;5;28mfloat\u001b[39m]]:\n\u001b[32m 149\u001b[39m \u001b[38;5;250m \u001b[39m\u001b[33;03m\"\"\"Read the absorbance from the plate reader. This should return a list of lists, where the\u001b[39;00m\n\u001b[32m 150\u001b[39m \u001b[33;03m outer list is the columns of the plate and the inner list is the rows of the plate.\"\"\"\u001b[39;00m\n\u001b[32m--> \u001b[39m\u001b[32m152\u001b[39m available_wavelengths = \u001b[38;5;28;01mawait\u001b[39;00m \u001b[38;5;28mself\u001b[39m.get_available_absorbance_wavelengths()\n\u001b[32m 153\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m wavelength \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;129;01min\u001b[39;00m available_wavelengths:\n\u001b[32m 154\u001b[39m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\n\u001b[32m 155\u001b[39m \u001b[33mf\u001b[39m\u001b[33m\"\u001b[39m\u001b[33mWavelength \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mwavelength\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m nm is not supported by this plate reader. \u001b[39m\u001b[33m\"\u001b[39m\n\u001b[32m 156\u001b[39m \u001b[33mf\u001b[39m\u001b[33m\"\u001b[39m\u001b[33mAvailable wavelengths: \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mavailable_wavelengths\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m\"\u001b[39m\n\u001b[32m 157\u001b[39m )\n",
+ "\u001b[36mFile \u001b[39m\u001b[32m~/Desktop/GitHub/pylabrobot/pylabrobot/plate_reading/byonoy/byonoy_backend.py:135\u001b[39m, in \u001b[36mByonoyAbsorbance96AutomateBackend.get_available_absorbance_wavelengths\u001b[39m\u001b[34m(self)\u001b[39m\n\u001b[32m 134\u001b[39m \u001b[38;5;28;01masync\u001b[39;00m \u001b[38;5;28;01mdef\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[34mget_available_absorbance_wavelengths\u001b[39m(\u001b[38;5;28mself\u001b[39m) -> List[\u001b[38;5;28mfloat\u001b[39m]:\n\u001b[32m--> \u001b[39m\u001b[32m135\u001b[39m available_wavelengths_r = \u001b[38;5;28;01mawait\u001b[39;00m \u001b[38;5;28mself\u001b[39m.send_command(\n\u001b[32m 136\u001b[39m report_id=\u001b[32m0x0330\u001b[39m,\n\u001b[32m 137\u001b[39m payload_fmt=\u001b[33m\"\u001b[39m\u001b[33m<30h\u001b[39m\u001b[33m\"\u001b[39m,\n\u001b[32m 138\u001b[39m payload=[\u001b[32m0\u001b[39m] * \u001b[32m30\u001b[39m,\n\u001b[32m 139\u001b[39m wait_for_response=\u001b[38;5;28;01mTrue\u001b[39;00m,\n\u001b[32m 140\u001b[39m )\n\u001b[32m 141\u001b[39m \u001b[38;5;28;01massert\u001b[39;00m available_wavelengths_r \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m, \u001b[33m\"\u001b[39m\u001b[33mFailed to get available wavelengths.\u001b[39m\u001b[33m\"\u001b[39m\n\u001b[32m 142\u001b[39m \u001b[38;5;66;03m# cut out the first 2 bytes, then read the next 2 bytes as an integer\u001b[39;00m\n\u001b[32m 143\u001b[39m \u001b[38;5;66;03m# 64 - 4 = 60. 60/2 = 30 16 bit integers\u001b[39;00m\n",
+ "\u001b[36mFile \u001b[39m\u001b[32m~/Desktop/GitHub/pylabrobot/pylabrobot/plate_reading/byonoy/byonoy_backend.py:78\u001b[39m, in \u001b[36m_ByonoyBase.send_command\u001b[39m\u001b[34m(self, report_id, payload_fmt, payload, wait_for_response)\u001b[39m\n\u001b[32m 76\u001b[39m \u001b[38;5;28;01mwhile\u001b[39;00m \u001b[38;5;28;01mTrue\u001b[39;00m:\n\u001b[32m 77\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m time.time() - t0 > \u001b[32m120\u001b[39m: \u001b[38;5;66;03m# read for 2 minutes max. typical is 1m5s.\u001b[39;00m\n\u001b[32m---> \u001b[39m\u001b[32m78\u001b[39m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mTimeoutError\u001b[39;00m(\u001b[33m\"\u001b[39m\u001b[33mReading luminescence data timed out after 2 minutes.\u001b[39m\u001b[33m\"\u001b[39m)\n\u001b[32m 80\u001b[39m response = \u001b[38;5;28;01mawait\u001b[39;00m \u001b[38;5;28mself\u001b[39m.io.read(\u001b[32m64\u001b[39m, timeout=\u001b[32m30\u001b[39m)\n\u001b[32m 81\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mlen\u001b[39m(response) == \u001b[32m0\u001b[39m:\n",
+ "\u001b[31mTimeoutError\u001b[39m: Reading luminescence data timed out after 2 minutes."
+ ]
}
],
"source": [
- "r.parent"
+ "await reader_cap.backend.read_absorbance(\n",
+ " plate = CellVis_96_wellplate_350uL_Fb,\n",
+ " wavelength = 600 # units: nm\n",
+ ")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "1a33230d-8243-4d21-88e1-4a4eb6cba7c8",
+ "metadata": {},
+ "source": [
+ "## Disconnect from Reader"
]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 11,
+ "id": "21a72488",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "await reader_cap.stop()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "62b8732a-8bd7-427d-85c3-ab900f2a48b6",
+ "metadata": {},
+ "outputs": [],
+ "source": []
}
],
"metadata": {
"kernelspec": {
- "display_name": "env (3.10.15)",
+ "display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
@@ -222,7 +362,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
- "version": "3.10.15"
+ "version": "3.12.11"
}
},
"nbformat": 4,
diff --git a/docs/user_guide/02_analytical/plate-reading/img/byonoy_absorbance_96_automate.png b/docs/user_guide/02_analytical/plate-reading/img/byonoy_absorbance_96_automate.png
new file mode 100644
index 00000000000..dfe4151929b
Binary files /dev/null and b/docs/user_guide/02_analytical/plate-reading/img/byonoy_absorbance_96_automate.png differ