From 687e68a17b0e4ab1c96014e5585559f4617cccc9 Mon Sep 17 00:00:00 2001 From: Camillo Moschner Date: Fri, 27 Mar 2026 18:10:14 +0000 Subject: [PATCH 01/38] Scale backend: rename to MTSICSBackend, add cancel commands, response validation, device discovery, and chatterbox simulator --- .../scales/mettler-toledo-WXS205SDU.ipynb | 261 +++++++++++---- pylabrobot/scales/__init__.py | 2 +- pylabrobot/scales/chatterbox.py | 58 +++- pylabrobot/scales/mettler_toledo_backend.py | 306 +++++++++++++++--- pylabrobot/scales/mt_sics_commands.md | 276 ++++++++++++++++ pylabrobot/scales/scale.py | 4 + pylabrobot/scales/scale_backend.py | 5 + 7 files changed, 788 insertions(+), 124 deletions(-) create mode 100644 pylabrobot/scales/mt_sics_commands.md diff --git a/docs/user_guide/02_analytical/scales/mettler-toledo-WXS205SDU.ipynb b/docs/user_guide/02_analytical/scales/mettler-toledo-WXS205SDU.ipynb index 483ee4079ce..1cc4ba0c065 100644 --- a/docs/user_guide/02_analytical/scales/mettler-toledo-WXS205SDU.ipynb +++ b/docs/user_guide/02_analytical/scales/mettler-toledo-WXS205SDU.ipynb @@ -51,48 +51,63 @@ "---\n", "## Setup (Programmatic)\n", "\n", - "Import the necessary classes:" + "Select a protocol mode:" ] }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, + "execution_count": 1, + "metadata": { + "execution": { + "iopub.execute_input": "2026-03-27T15:53:13.146987Z", + "iopub.status.busy": "2026-03-27T15:53:13.146777Z", + "iopub.status.idle": "2026-03-27T15:53:13.150980Z", + "shell.execute_reply": "2026-03-27T15:53:13.150542Z" + } + }, "outputs": [], "source": [ - "from pylabrobot.scales import Scale\n", - "from pylabrobot.scales.mettler_toledo_backend import MettlerToledoWXS205SDUBackend\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Initialize the scale backend and create a scale instance.\n", - "You'll need to specify the serial port where your scale is connected:" + "protocol_mode = \"simulation\" # \"execution\" or \"simulation\"" ] }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, + "execution_count": 2, + "metadata": { + "execution": { + "iopub.execute_input": "2026-03-27T15:53:13.153037Z", + "iopub.status.busy": "2026-03-27T15:53:13.152879Z", + "iopub.status.idle": "2026-03-27T15:53:13.245300Z", + "shell.execute_reply": "2026-03-27T15:53:13.245082Z" + } + }, "outputs": [ { - "data": { - "text/plain": [ - "0.00148" - ] - }, - "execution_count": 3, - "metadata": {}, - "output_type": "execute_result" + "name": "stdout", + "output_type": "stream", + "text": [ + "Setting up the scale.\n" + ] } ], "source": [ - "backend = MettlerToledoWXS205SDUBackend(port=\"/dev/cu.usbserial-110\")\n", + "from pylabrobot.scales import Scale\n", + "\n", + "if protocol_mode == \"execution\":\n", + "\n", + " from pylabrobot.scales.mettler_toledo_backend import MTSICSBackend\n", + "\n", + " backend = MTSICSBackend(port=\"/dev/cu.usbserial-110\")\n", + "\n", + "elif protocol_mode == \"simulation\":\n", + "\n", + " from pylabrobot.scales.chatterbox import ScaleChatterboxBackend\n", + "\n", + " backend = ScaleChatterboxBackend()\n", + "\n", "scale = Scale(name=\"scale\", backend=backend, size_x=0, size_y=0, size_z=0)\n", "\n", - "await scale.setup()\n" + "await scale.setup()" ] }, { @@ -135,11 +150,26 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "execution_count": 3, + "metadata": { + "execution": { + "iopub.execute_input": "2026-03-27T15:53:13.259538Z", + "iopub.status.busy": "2026-03-27T15:53:13.259428Z", + "iopub.status.idle": "2026-03-27T15:53:13.261100Z", + "shell.execute_reply": "2026-03-27T15:53:13.260918Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Zeroing the scale\n" + ] + } + ], "source": [ - "await scale.zero(timeout=5)\n" + "await scale.zero(timeout=5)" ] }, { @@ -165,11 +195,29 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "execution_count": 4, + "metadata": { + "execution": { + "iopub.execute_input": "2026-03-27T15:53:13.262148Z", + "iopub.status.busy": "2026-03-27T15:53:13.262089Z", + "iopub.status.idle": "2026-03-27T15:53:13.263750Z", + "shell.execute_reply": "2026-03-27T15:53:13.263577Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Taring the scale\n" + ] + } + ], "source": [ - "await scale.tare(timeout=5)\n" + "if protocol_mode == \"simulation\":\n", + " backend.platform_weight = 50.0 # simulate placing a 50g beaker\n", + "\n", + "await scale.tare(timeout=5)" ] }, { @@ -181,11 +229,36 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "execution_count": 5, + "metadata": { + "execution": { + "iopub.execute_input": "2026-03-27T15:53:13.264636Z", + "iopub.status.busy": "2026-03-27T15:53:13.264581Z", + "iopub.status.idle": "2026-03-27T15:53:13.266917Z", + "shell.execute_reply": "2026-03-27T15:53:13.266768Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Requesting tare weight\n" + ] + }, + { + "data": { + "text/plain": [ + "50.0" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ - "await scale.request_tare_weight()\n" + "await scale.request_tare_weight()" ] }, { @@ -200,22 +273,39 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, + "execution_count": 6, + "metadata": { + "execution": { + "iopub.execute_input": "2026-03-27T15:53:13.267802Z", + "iopub.status.busy": "2026-03-27T15:53:13.267744Z", + "iopub.status.idle": "2026-03-27T15:53:13.269598Z", + "shell.execute_reply": "2026-03-27T15:53:13.269439Z" + } + }, "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Reading the weight\n" + ] + }, { "data": { "text/plain": [ - "0.00148" + "0.010599999999996612" ] }, - "execution_count": 4, + "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "await scale.read_weight(timeout=0)\n" + "if protocol_mode == \"simulation\":\n", + " backend.sample_weight = 0.0106 # simulate dispensing ~10 uL of liquid\n", + "\n", + "await scale.read_weight(timeout=0)" ] }, { @@ -230,9 +320,33 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "execution_count": 7, + "metadata": { + "execution": { + "iopub.execute_input": "2026-03-27T15:53:13.270492Z", + "iopub.status.busy": "2026-03-27T15:53:13.270436Z", + "iopub.status.idle": "2026-03-27T15:53:14.275293Z", + "shell.execute_reply": "2026-03-27T15:53:14.274778Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Zeroing the scale\n", + "Taring the scale\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Reading the weight\n", + "Dispensed 10.60 mg (10.00 uL)\n" + ] + } + ], "source": [ "import asyncio\n", "\n", @@ -240,15 +354,22 @@ "await scale.zero(timeout=\"stable\")\n", "\n", "# 2. Place container with liquid on scale\n", + "if protocol_mode == \"simulation\":\n", + " backend.platform_weight = 45.0 # 45g container\n", + " backend.sample_weight = 1.06 # ~1 mL of liquid (1000 uL)\n", "\n", "# 3. Aspirate liquid from container (on scale)\n", "# (your liquid handling code here)\n", + "if protocol_mode == \"simulation\":\n", + " backend.sample_weight = 1.06 - 0.0106 # aspirated ~10 uL\n", "\n", "# 4. Tare the scale (ignore weight loss from aspiration)\n", "await scale.tare(timeout=5)\n", "\n", "# 5. Dispense liquid back into same container (on scale)\n", "# (your liquid handling code here)\n", + "if protocol_mode == \"simulation\":\n", + " backend.sample_weight = 1.06 # dispensed ~10 uL back\n", "\n", "# 6. Brief pause to allow scale to settle\n", "await asyncio.sleep(1) # Allow 1 second for settling after dispense\n", @@ -258,10 +379,10 @@ "\n", "# 8. Convert weight to volume\n", "weight_mg = weight_g * 1000\n", - "liquid_density = 1.06 # mg/µL for 50% v/v glycerol at ~25°C, 1 atm\n", + "liquid_density = 1.06 # mg/uL for 50% v/v glycerol at ~25C, 1 atm\n", "volume_uL = weight_mg / liquid_density\n", "\n", - "print(f\"Dispensed {weight_mg:.2f} mg or ({volume_uL:.2f} µL)\")\n" + "print(f\"Dispensed {weight_mg:.2f} mg ({volume_uL:.2f} uL)\")" ] }, { @@ -278,35 +399,35 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "100.44 ms ± 6.78 ms\n" - ] + "execution_count": 8, + "metadata": { + "execution": { + "iopub.execute_input": "2026-03-27T15:53:14.277735Z", + "iopub.status.busy": "2026-03-27T15:53:14.277525Z", + "iopub.status.idle": "2026-03-27T15:53:14.280442Z", + "shell.execute_reply": "2026-03-27T15:53:14.280087Z" } - ], + }, + "outputs": [], "source": [ - "import time\n", - "import numpy as np\n", - "\n", - "times = []\n", - "for i in range(10):\n", - " t0 = time.monotonic_ns()\n", - " await scale.read_weight(timeout=\"stable\")\n", - " t1 = time.monotonic_ns()\n", - " times.append((t1 - t0) / 1e6)\n", - "\n", - "print(f\"{np.mean(times):.2f} ms ± {np.std(times):.2f} ms\")\n" + "if protocol_mode == \"execution\":\n", + " import time\n", + " import numpy as np\n", + "\n", + " times = []\n", + " for i in range(10):\n", + " t0 = time.monotonic_ns()\n", + " await scale.read_weight(timeout=\"stable\")\n", + " t1 = time.monotonic_ns()\n", + " times.append((t1 - t0) / 1e6)\n", + "\n", + " print(f\"{np.mean(times):.2f} ms +/- {np.std(times):.2f} ms\")" ] } ], "metadata": { "kernelspec": { - "display_name": "env", + "display_name": "plr", "language": "python", "name": "python3" }, @@ -320,7 +441,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.10.12" + "version": "3.12.11" } }, "nbformat": 4, diff --git a/pylabrobot/scales/__init__.py b/pylabrobot/scales/__init__.py index 5e798de1388..f8fd737e95b 100644 --- a/pylabrobot/scales/__init__.py +++ b/pylabrobot/scales/__init__.py @@ -1,7 +1,7 @@ from pylabrobot.scales.chatterbox import ScaleChatterboxBackend from pylabrobot.scales.mettler_toledo_backend import ( - MettlerToledoWXS205SDU, MettlerToledoWXS205SDUBackend, + MTSICSBackend, ) from pylabrobot.scales.scale import Scale from pylabrobot.scales.scale_backend import ScaleBackend diff --git a/pylabrobot/scales/chatterbox.py b/pylabrobot/scales/chatterbox.py index 9ffb5a68e05..7cbd05c8f3f 100644 --- a/pylabrobot/scales/chatterbox.py +++ b/pylabrobot/scales/chatterbox.py @@ -2,10 +2,44 @@ class ScaleChatterboxBackend(ScaleBackend): - """Chatter box backend for device-free testing. Prints out all operations.""" + """Chatter box backend for device-free testing. - def __init__(self, dummy_weight: float = 0.0) -> None: - self._dummy_weight = dummy_weight + Simulates scale behavior: tracks zero offset, tare weight, and platform load. + The total sensor reading is ``platform_weight + sample_weight``. + ``read_weight`` returns the net: ``platform_weight + sample_weight - zero_offset - tare_weight``. + + Set ``platform_weight`` to simulate a container or vessel on the scale. + Set ``sample_weight`` to simulate material added to the container. + + Example - zero:: + + backend = ScaleChatterboxBackend() + backend.platform_weight = 2.0 # residue on empty platform + await scale.zero() # zero_offset = 2.0 + await scale.read_weight() # returns 0.0 + backend.platform_weight = 52.0 # place a 50g beaker + await scale.read_weight() # returns 50.0 + + Example - tare:: + + backend = ScaleChatterboxBackend() + backend.platform_weight = 50.0 # place a 50g beaker + await scale.tare() # tare_weight = 50.0 + backend.sample_weight = 10.0 # add 10g of liquid + await scale.read_weight() # returns 10.0 + await scale.request_tare_weight() # returns 50.0 + """ + + def __init__(self) -> None: + super().__init__() + self.platform_weight: float = 0.0 + self.sample_weight: float = 0.0 + self.zero_offset: float = 0.0 + self.tare_weight: float = 0.0 + + @property + def _sensor_reading(self) -> float: + return self.platform_weight + self.sample_weight async def setup(self) -> None: print("Setting up the scale.") @@ -13,12 +47,18 @@ async def setup(self) -> None: async def stop(self) -> None: print("Stopping the scale.") - async def tare(self): + async def zero(self, **kwargs): + print("Zeroing the scale") + self.zero_offset = self._sensor_reading + + async def tare(self, **kwargs): print("Taring the scale") + self.tare_weight = self._sensor_reading - self.zero_offset - async def read_weight(self) -> float: - print("Reading the weight") - return self._dummy_weight + async def request_tare_weight(self, **kwargs) -> float: + print("Requesting tare weight") + return self.tare_weight - async def zero(self): - print("Zeroing the scale") + async def read_weight(self, **kwargs) -> float: + print("Reading the weight") + return self._sensor_reading - self.zero_offset - self.tare_weight diff --git a/pylabrobot/scales/mettler_toledo_backend.py b/pylabrobot/scales/mettler_toledo_backend.py index ae73eb114df..baa6852db6e 100644 --- a/pylabrobot/scales/mettler_toledo_backend.py +++ b/pylabrobot/scales/mettler_toledo_backend.py @@ -1,10 +1,13 @@ +"""Mettler Toledo scale backend using the MT-SICS (Mettler Toledo Standard Interface Command Set) serial protocol.""" + # similar library: https://github.com/janelia-pypi/mettler_toledo_device_python import asyncio +import functools import logging import time import warnings -from typing import List, Literal, Optional, Union +from typing import Any, Callable, List, Literal, Optional, Set, TypeVar, Union from pylabrobot.io.serial import Serial from pylabrobot.scales.scale_backend import ScaleBackend @@ -143,16 +146,63 @@ def adjustment_needed(from_terminal: bool) -> "MettlerToledoError": MettlerToledoResponse = List[str] -class MettlerToledoWXS205SDUBackend(ScaleBackend): - """Backend for the Mettler Toledo WXS205SDU scale. +F = TypeVar("F", bound=Callable[..., Any]) - This scale is used by Hamilton in the liquid verification kit (LVK). - Documentation: https://web.archive.org/web/20240208213802/https://www.mt.com/dam/ - product_organizations/industry/apw/generic/11781363_N_MAN_RM_MT-SICS_APW_en.pdf +def requires_mt_sics_level(level: int) -> Callable[[F], F]: + """Decorator that gates a method on the connected device supporting the required MT-SICS level. + + During setup(), the backend queries I1 to discover which levels the connected device supports. + Methods decorated with a level higher than what the device reports will raise MettlerToledoError. + See the class docstring of MTSICSBackend for level descriptions. + """ + + def decorator(func: F) -> F: + func._mt_sics_level = level # type: ignore[attr-defined] + + @functools.wraps(func) + async def wrapper(self: Any, *args: Any, **kwargs: Any) -> Any: + if hasattr(self, "_mt_sics_levels") and self._mt_sics_levels is not None: + if level not in self._mt_sics_levels: + raise MettlerToledoError( + title="Command not supported", + message=f"'{func.__name__}' requires MT-SICS level {level}, " + f"but device supports levels: {sorted(self._mt_sics_levels)}", + ) + return await func(self, *args, **kwargs) + + return wrapper # type: ignore[return-value] + + return decorator + + +class MTSICSBackend(ScaleBackend): + """Backend for Mettler Toledo scales using the MT-SICS protocol. + + MT-SICS (Mettler Toledo Standard Interface Command Set) is the serial communication + protocol used by Mettler Toledo's Automated Precision Weigh Modules. This backend is + compatible with any MT-SICS device, including the WXS, WMS, and WX series. During + setup(), this backend queries the device to discover its identity, capacity, and + supported MT-SICS levels. + + MT-SICS levels: + - Level 0: Basic set - identification (I0-I4), basic weighing (S, SI), zero (Z, ZI), + tare (T, TI), cancel (@). Always available on every MT-SICS device. + - Level 1: Elementary commands - display (D, DW), tare memory (TA, TAC), timed + weighing (SC), timed zero/tare (ZC, TC). Always available. + - Level 2: Extended command list - configuration (M21, COM), device info (I50, I47, + I48). Model-dependent, not guaranteed on every device. + - Level 3: Application-specific command set. Model-dependent. + + Methods requiring Level 2+ are decorated with ``@requires_mt_sics_level`` and will + raise ``MettlerToledoError`` if the connected device does not support the required level. + + Tested on the WXS205SDU (used by Hamilton in the Liquid Verification Kit). - From the docs: + Spec: https://web.archive.org/web/20240208213802/https://www.mt.com/dam/ + product_organizations/industry/apw/generic/11781363_N_MAN_RM_MT-SICS_APW_en.pdf + From the spec (Section 2.2): "If several commands are sent in succession without waiting for the corresponding responses, it is possible that the weigh module/balance confuses the sequence of command processing or ignores entire commands." @@ -173,15 +223,28 @@ def __init__(self, port: Optional[str] = None, vid: int = 0x0403, pid: int = 0x6 ) async def setup(self) -> None: - # Core state await self.io.setup() - # set output unit to grams - await self.send_command("M21 0 0") + # Reset device to clean state (spec Section 2.2) + # cancel() clears the input buffer and sends @, which returns the serial number + self.serial_number = await self.cancel() + + # Device discovery (Level 0 - always available) + self._mt_sics_levels: Set[int] = await self._query_mt_sics_levels() + self.device_type = await self.request_device_type() + self.capacity = await self.request_capacity() + + logger.info( + "[scale] Connected: %s (S/N: %s, capacity: %.1f g, MT-SICS levels: %s)", + self.device_type, + self.serial_number, + self.capacity, + sorted(self._mt_sics_levels), + ) - # Handshake: parse requested serial number - self.serial_number = await self.request_serial_number() - # TODO: verify serial number pattern + # Set output unit to grams + if 2 in self._mt_sics_levels: + await self.set_host_unit_grams() async def stop(self) -> None: await self.io.stop() @@ -189,8 +252,48 @@ async def stop(self) -> None: def serialize(self) -> dict: return {**super().serialize(), "port": self.io.port} + # === Device discovery === + + async def _query_mt_sics_levels(self) -> Set[int]: + """Query supported MT-SICS levels via I1 command (Level 0 - always available). + + Returns a set of integers representing the supported levels (e.g. {0, 1, 2, 3}). + """ + response = await self.send_command("I1") + # I1 A "0123" "2.00" "2.20" "1.00" "1.50" + self._validate_response(response, 3, "I1") + level_string = response[2].replace('"', "") + return {int(c) for c in level_string} + # === Response parsing === + @staticmethod + def _validate_response(response: List[str], min_length: int, command: str) -> None: + """Validate that a parsed response has the expected minimum number of fields. + + Raises: + MettlerToledoError: if the response is too short. + """ + if len(response) < min_length: + raise MettlerToledoError( + title="Unexpected response", + message=f"Expected at least {min_length} fields for '{command}', " + f"got {len(response)}: {' '.join(response)}", + ) + + @staticmethod + def _validate_unit(unit: str, command: str) -> None: + """Validate that the unit in a response is grams. + + Raises: + MettlerToledoError: if the unit is not 'g'. + """ + if unit != "g": + raise MettlerToledoError( + title="Unexpected unit", + message=f"Expected 'g' for '{command}', got '{unit}'", + ) + def _parse_basic_errors(self, response: List[str]) -> None: """Helper function for parsing basic errors that are common to many commands. If an error is detected, a 'MettlerToledoError' exception is raised. @@ -210,11 +313,18 @@ def _parse_basic_errors(self, response: List[str]) -> None: - +: Balance in overload range - -: Balance in underload range - TODO: handle 'B' status — multi-response commands (e.g. C1 adjustment) send 'B' first, + TODO: handle 'B' status - multi-response commands (e.g. C1 adjustment) send 'B' first, then additional responses, then 'A' on completion. Currently send_command returns after the first response, so 'B' responses are not followed up. """ + if len(response) == 0: + raise MettlerToledoError( + title="Empty response", + message="Received empty response from scale", + ) + + # General error messages are single-token: ES, ET, EL if response[0] == "ES": raise MettlerToledoError.syntax_error() if response[0] == "ET": @@ -222,6 +332,12 @@ def _parse_basic_errors(self, response: List[str]) -> None: if response[0] == "EL": raise MettlerToledoError.logical_error() + if len(response) < 2: + raise MettlerToledoError( + title="Unexpected response", + message=f"Expected at least 2 fields, got: {' '.join(response)}", + ) + if response[1] == "I": raise MettlerToledoError.executing_another_command() if response[1] == "L": @@ -231,7 +347,7 @@ def _parse_basic_errors(self, response: List[str]) -> None: if response[1] == "-": raise MettlerToledoError.underload() - if response[0] == "S" and response[1] == "S" and response[2] == "Error": + if len(response) >= 4 and response[0] == "S" and response[1] == "S" and response[2] == "Error": error_code = response[3] code, source = error_code[:-1], error_code[-1] from_terminal = source == "t" @@ -285,12 +401,117 @@ async def send_command(self, command: str, timeout: int = 60) -> MettlerToledoRe # === Public high-level API === + # # Cancel commands # # + + async def cancel(self) -> str: + """@ - Reset the device to a determined state (spec Section 2.2). + + Equivalent to a power cycle: empties volatile memories, cancels all pending + commands, resets key control to default. Tare memory is NOT reset. + The cancel command is always executed, even when the device is busy. + + Returns the serial number from the I4-style response. + """ + await self.io.reset_input_buffer() + response = await self.send_command("@") + # @ responds with I4-style: I4 A "" + self._validate_response(response, 3, "@") + return response[2].replace('"', "") + + async def cancel_all(self) -> None: + """C - Cancel all active and pending interface commands. + + Unlike cancel() (@), this does not reset the device - it only cancels + commands that were requested via this interface. Typically used to stop + repeating commands (SIR, SR) or abort adjustment procedures. + + This is a multi-response command: the device sends C B (started) then + C A (complete). Both responses are consumed to keep the serial buffer clean. + """ + response = await self.send_command("C") + # First response: C B (cancel started) + self._validate_response(response, 2, "C") + if response[1] == "E": + raise MettlerToledoError( + title="Error while canceling", + message=f"C command returned error: {response}", + ) + + # Second response: C A (cancel complete) - must read to clear buffer + raw_followup = b"" + timeout_time = time.time() + 10 + while True: + raw_followup = await self.io.readline() + await asyncio.sleep(0.001) + if time.time() > timeout_time: + logger.warning("[scale] Timeout waiting for C A followup") + break + if raw_followup != b"": + break + logger.debug("[scale] Cancel followup: %s", raw_followup) + + # # Identification commands # # + async def request_serial_number(self) -> str: - """Get the serial number of the scale. (MEM-READ command)""" + """Get the serial number of the scale. (I4 command)""" response = await self.send_command("I4") - serial_number = response[2] - serial_number = serial_number.replace('"', "") - return serial_number + self._validate_response(response, 3, "I4") + return response[2].replace('"', "") + + async def request_device_type(self) -> str: + """Query the device type string. (I2 command)""" + response = await self.send_command("I2") + # After split(): ["I2", "A", '"WXS205SDU"', "220.0000", "g"] + self._validate_response(response, 5, "I2") + return response[2].replace('"', "") + + async def request_capacity(self) -> float: + """Query the maximum weighing capacity in grams. (I2 command)""" + response = await self.send_command("I2") + # After split(): ["I2", "A", '"WXS205SDU"', "220.0000", "g"] + self._validate_response(response, 5, "I2") + self._validate_unit(response[4], "I2") + return float(response[3]) + + @requires_mt_sics_level(2) + async def request_remaining_weighing_range(self) -> float: + """Query remaining maximum weighing range in grams. (I50 command) + + Returns the remaining capacity accounting for all loads currently on the + weighing platform (pre-load, tare, net load). A negative value means the + maximum weighing range has been exceeded. + + I50 is a multi-response command: the device sends up to 3 lines + (RangeNo 0 with B, RangeNo 1 with B, RangeNo 2 with A). We extract the + value from the first response and drain the remaining ones. + """ + response = await self.send_command("I50") + # First response line: I50 B 0 (RangeNo 0 = max weighing range) + # After split(): ["I50", "B", "0", "535.141", "g"] + self._validate_response(response, 5, "I50") + self._validate_unit(response[4], "I50") + remaining = float(response[3]) + + # Drain follow-up responses (RangeNo 1 and 2) to keep the serial buffer clean + timeout_time = time.time() + 10 + while True: + raw_followup = b"" + while True: + raw_followup = await self.io.readline() + await asyncio.sleep(0.001) + if time.time() > timeout_time: + break + if raw_followup != b"": + break + if raw_followup == b"" or time.time() > timeout_time: + break + followup = raw_followup.decode("utf-8").strip().split() + logger.debug("[scale] I50 followup: %s", raw_followup) + # Stop after the final response (status A) + if len(followup) >= 2 and followup[1] == "A": + break + + return remaining # # Zero commands # # @@ -384,10 +605,9 @@ async def request_tare_weight(self) -> float: """ response = await self.send_command("TA") - tare = float(response[2]) - unit = response[3] - assert unit == "g" # this is the format we expect - return tare + self._validate_response(response, 4, "TA") + self._validate_unit(response[3], "TA") + return float(response[2]) async def clear_tare(self) -> MettlerToledoResponse: """TAC - Clear tare weight value (MEM-WRITE command)""" @@ -405,10 +625,9 @@ async def read_stable_weight(self) -> float: """ response = await self.send_command("S") - weight = float(response[2]) - unit = response[3] - assert unit == "g" # this is the format we expect - return weight + self._validate_response(response, 4, "S") + self._validate_unit(response[3], "S") + return float(response[2]) async def read_dynamic_weight(self, timeout: float) -> float: """Read a stable weight value from the machine within a given timeout, or @@ -421,10 +640,9 @@ async def read_dynamic_weight(self, timeout: float) -> float: timeout = int(timeout * 1000) # convert to milliseconds response = await self.send_command(f"SC {timeout}") - weight = float(response[2]) - unit = response[3] - assert unit == "g" # this is the format we expect - return weight + self._validate_response(response, 4, "SC") + self._validate_unit(response[3], "SC") + return float(response[2]) async def read_weight_value_immediately(self) -> float: """Read a weight value immediately from the scale. (MEASUREMENT command) @@ -434,9 +652,9 @@ async def read_weight_value_immediately(self) -> float: """ response = await self.send_command("SI") - weight = float(response[2]) - assert response[3] == "g" # this is the format we expect - return weight + self._validate_response(response, 4, "SI") + self._validate_unit(response[3], "SI") + return float(response[2]) async def read_weight(self, timeout: Union[Literal["stable"], float, int] = "stable") -> float: """High level function to read a weight value from the scale. (MEASUREMENT command) @@ -472,9 +690,16 @@ async def set_weight_display(self) -> MettlerToledoResponse: """Return the display to the normal weight display.""" return await self.send_command("DW") + # # Configuration commands # # + + @requires_mt_sics_level(2) + async def set_host_unit_grams(self) -> MettlerToledoResponse: + """Set the host output unit to grams. (M21 command)""" + return await self.send_command("M21 0 0") + # # # Deprecated alias with warning # # # - # # TODO: remove 2026-03 (giving people >2 months to update) + # TODO: remove after 2026-03 async def get_serial_number(self) -> str: """Deprecated: Use request_serial_number() instead.""" @@ -536,12 +761,5 @@ async def get_weight(self, timeout: Union[Literal["stable"], float, int] = "stab return await self.read_weight(timeout) -# Deprecated alias with warning # TODO: remove mid May 2025 (giving people 1 month to update) -# https://github.com/PyLabRobot/pylabrobot/issues/466 - - -class MettlerToledoWXS205SDU: - def __init__(self, *args, **kwargs): - raise RuntimeError( - "`MettlerToledoWXS205SDU` is deprecated. Please use `MettlerToledoWXS205SDUBackend` instead." - ) +# Deprecated alias - TODO: remove after 2026-07 +MettlerToledoWXS205SDUBackend = MTSICSBackend diff --git a/pylabrobot/scales/mt_sics_commands.md b/pylabrobot/scales/mt_sics_commands.md new file mode 100644 index 00000000000..4d1d3dc5db9 --- /dev/null +++ b/pylabrobot/scales/mt_sics_commands.md @@ -0,0 +1,276 @@ +# MT-SICS Command Reference + +MT-SICS = Mettler Toledo Standard Interface Command Set + +Commands organized by level and ranked by utility for PyLabRobot integration. +Source: MT-SICS Interface Command Set for Automated Precision Weigh Modules (spec doc). + +Status key: +- DONE = implemented in mettler_toledo_backend.py +- HIGH = high priority for implementation +- MED = medium priority +- LOW = low priority / niche use case +- N/A = not applicable to automation use case + +## Level 0 - Basic Set (always available) + +| Command | Description | Spec Page | Status | Notes | +|---------|------------------------------------------|-----------|--------|-------| +| @ | Cancel / reset to determined state | 16 | HIGH | Spec recommends sending on connect (Section 2.2). Response is I4-style. | +| I0 | List all implemented commands + levels | 96 | MED | Useful for runtime capability discovery. Multi-response (B status). | +| I1 | MT-SICS level and level versions | 97 | DONE | Queried during setup(). | +| I2 | Device data (type and capacity) | 98 | DONE | Split into request_device_type() and request_capacity(). | +| I3 | Software version and type definition | 99 | MED | Useful for diagnostics/logging. | +| I4 | Serial number | 100 | DONE | request_serial_number(). | +| I5 | Software material number | 101 | LOW | | +| S | Stable weight value | 223 | DONE | read_stable_weight(). | +| SI | Weight value immediately | 225 | DONE | read_weight_value_immediately(). | +| Z | Zero (wait for stable) | 272 | DONE | zero_stable(). | +| ZI | Zero immediately | 274 | DONE | zero_immediately(). | +| T | Tare (wait for stable) | 252 | DONE | tare_stable(). | +| TI | Tare immediately | 257 | DONE | tare_immediately(). | + +## Level 1 - Elementary Commands (always available) + +| Command | Description | Spec Page | Status | Notes | +|---------|------------------------------------------|-----------|--------|-------| +| C | Cancel all pending commands | 23 | HIGH | Like @ but doesn't reset state. | +| D | Write text to display | 52 | DONE | set_display_text(). | +| DW | Show weight on display | 61 | DONE | set_weight_display(). | +| K | Keys control | 153 | LOW | Lock/unlock terminal keys. | +| SC | Stable or dynamic value after timeout | 224 | DONE | read_dynamic_weight(). | +| SIR | Weight immediately + repeat | 232 | MED | Continuous streaming. Needs multi-response support. | +| SIRU | Weight immediately + repeat (display unit)| 233 | LOW | | +| SNR | Stable weight + repeat on stable change | 241 | LOW | | +| SR | Stable weight + repeat on any change | 245 | MED | Continuous streaming. Needs multi-response support. | +| SRU | Stable weight + repeat (display unit) | 247 | LOW | | +| TA | Tare weight value (query/set) | 253 | DONE | request_tare_weight(). | +| TAC | Clear tare weight value | 254 | DONE | clear_tare(). | +| TC | Tare with timeout | 255 | DONE | tare_timeout(). | +| ZC | Zero with timeout | 273 | DONE | zero_timeout(). | + +## Level 2 - Extended Commands (model-dependent) + +### Device Information (query) + +| Command | Description | Spec Page | Status | Notes | +|---------|------------------------------------------|-----------|--------|-------| +| I10 | Device identification | 102 | MED | | +| I11 | Model designation | 103 | MED | | +| I14 | Device information (detailed) | 104 | MED | | +| I15 | Uptime | 106 | MED | | +| I16 | Date of next service | 107 | LOW | | +| I29 | Filter configuration | 111 | LOW | | +| I32 | Voltage monitoring | 112 | MED | Health check. | +| I43 | Selectable units for host unit | 113 | LOW | | +| I44 | Selectable units for display unit | 114 | LOW | | +| I45 | Selectable environment filter settings | 115 | LOW | | +| I46 | Selectable weighing modes | 117 | LOW | | +| I47 | Switch-on range | 118 | LOW | | +| I48 | Initial zero range | 119 | LOW | | +| I50 | Remaining weighing ranges | 120 | DONE | request_remaining_weighing_range(). Multi-response. | +| I51 | Power-on time | 121 | MED | | +| I52 | Auto zero activation settings | 122 | LOW | | +| I54 | Adjustment loads | 125 | LOW | | +| I55 | Menu version | 126 | LOW | | +| I59 | Initial zero information | 129 | LOW | | +| I62 | Timeout setting | 131 | LOW | | +| I65 | Total operating time | 132 | MED | Maintenance tracking. | +| I66 | Total load weighed | 133 | MED | Maintenance tracking. | +| I67 | Total number of weighings | 134 | MED | Maintenance tracking. | +| I69 | Service provider address | 135 | LOW | | +| I71 | One time adjustment status | 136 | LOW | | +| I73 | Sign off | 137 | LOW | | +| I74 | GEO code at calibration point (HighRes) | 138 | LOW | | +| I75 | GEO code at point of use (HighRes) | 139 | LOW | | +| I76 | Total voltage exceeds | 140 | LOW | | +| I77 | Total load cycles | 141 | MED | Maintenance tracking. | +| I78 | Zero deviation | 143 | LOW | | +| I79 | Total zero deviation exceeds | 144 | LOW | | +| I80 | Total temperature exceeds | 145 | LOW | | +| I81 | Temperature gradient | 147 | LOW | | +| I82 | Total temperature gradient exceeds | 148 | LOW | | +| I83 | Software identification | 149 | LOW | | +| I100 | Active stability criteria | 151 | LOW | | +| I101 | Humidity value | 152 | LOW | | + +### Configuration (read/write) + +| Command | Description | Spec Page | Status | Notes | +|---------|------------------------------------------|-----------|--------|-------| +| M01 | Weighing mode | 157 | MED | | +| M02 | Environment condition | 158 | MED | Affects filter/stability. | +| M03 | Auto zero function | 159 | MED | | +| M21 | Unit (host/display) | 165 | DONE | set_host_unit_grams(). | +| M23 | Readability (1d/xd) | 169 | LOW | | +| M28 | Temperature value | 172 | MED | | +| M35 | Zeroing mode at startup | 178 | LOW | | +| M49 | Permanent tare mode | 188 | LOW | | +| M67 | Timeout | 191 | LOW | | +| M68 | Behavior of serial interfaces | 192 | LOW | | +| COM | Serial interface parameters | 46 | LOW | Baud rate, parity, etc. | +| ECHO | Echo mode | 66 | LOW | | +| LST | Current user settings | 156 | LOW | | +| PROT | Protocol mode | 220 | LOW | | + +### Adjustment / Calibration + +| Command | Description | Spec Page | Status | Notes | +|---------|------------------------------------------|-----------|--------|-------| +| C0 | Adjustment setting | 24 | LOW | | +| C1 | Start adjustment (current settings) | 26 | MED | Multi-response (B status). | +| C2 | Start adjustment (external weight) | 28 | LOW | | +| C3 | Start adjustment (built-in weight) | 30 | MED | Internal calibration. Multi-response. | +| C4 | Standard / initial adjustment | 31 | LOW | | +| C5 | Enable/disable step control | 33 | LOW | | +| C6 | Customer linearization + sensitivity | 34 | LOW | | +| C7 | Customer standard calibration | 37 | LOW | | +| C8 | Sensitivity adjustment | 40 | LOW | | +| C9 | Scale placement sensitivity adjustment | 43 | LOW | | +| M19 | Adjustment weight | 163 | LOW | | +| M27 | Adjustment history | 171 | MED | | + +### Testing + +| Command | Description | Spec Page | Status | Notes | +|---------|------------------------------------------|-----------|--------|-------| +| TST0 | Query/set test function settings | 259 | LOW | | +| TST1 | Test according to current settings | 260 | LOW | | +| TST2 | Test with external weight | 262 | LOW | | +| TST3 | Test with built-in weight | 264 | LOW | | +| TST5 | Module test with built-in weights | 265 | LOW | | + +### Weight Variants (alternative read commands) + +| Command | Description | Spec Page | Status | Notes | +|---------|------------------------------------------|-----------|--------|-------| +| SIC1 | Weight with CRC16 immediately | 226 | LOW | Data integrity. | +| SIC2 | HighRes weight with CRC16 immediately | 227 | LOW | | +| SIS | Net weight with unit + weighing status | 234 | MED | More info than S/SI. | +| SIU | Weight in display unit immediately | 237 | LOW | | +| SIUM | Weight + MinWeigh info immediately | 238 | LOW | | +| SIX1 | Current gross, net, and tare values | 239 | HIGH | All three values in one call. | +| ST | Stable weight on Transfer key press | 249 | N/A | Manual operation. | +| SU | Stable weight in display unit | 250 | LOW | | +| SUM | Stable weight + MinWeigh info | 251 | LOW | | + +### Stored Weight + +| Command | Description | Spec Page | Status | Notes | +|---------|------------------------------------------|-----------|--------|-------| +| SIMC | Clear stored weight value | 228 | LOW | | +| SIMR | Recall stored weight value | 229 | LOW | | +| SIMRC | Recall and clear stored weight value | 230 | LOW | | +| SIMS | Store weight immediately | 231 | LOW | | + +### Date/Time + +| Command | Description | Spec Page | Status | Notes | +|---------|------------------------------------------|-----------|--------|-------| +| DAT | Date | 53 | LOW | | +| DATI | Date and time | 54 | MED | | +| TIM | Time | 258 | LOW | | + +### Digital I/O + +| Command | Description | Spec Page | Status | Notes | +|---------|------------------------------------------|-----------|--------|-------| +| DIN | Configuration for digital inputs | 55 | LOW | | +| DIS | Digital input status | 56 | LOW | | +| DOS | Digital output status | 57 | LOW | | +| DOT | Configuration for digital outputs | 58 | LOW | | +| DOTC | Configurable digital outputs (weight) | 59 | LOW | | + +### System / Lifecycle + +| Command | Description | Spec Page | Status | Notes | +|---------|------------------------------------------|-----------|--------|-------| +| E01 | Current system error state | 62 | HIGH | Error monitoring. | +| E02 | Weighing device errors and warnings | 63 | HIGH | Error monitoring. | +| E03 | Current system errors and warnings | 65 | HIGH | Error monitoring. | +| FSET | Reset all settings to factory defaults | 95 | LOW | Destructive. | +| RO1 | Restart device | 221 | MED | | +| RDB | Readability | 222 | LOW | | +| UPD | Update rate for SIR/SIRU | 267 | LOW | | +| USTB | User defined stability criteria | 268 | LOW | | + +### Network (not relevant for serial) + +| Command | Description | Spec Page | Status | Notes | +|---------|------------------------------------------|-----------|--------|-------| +| I53 | IPv4 runtime network config | 123 | N/A | Ethernet only. | +| M69 | IPv4 network configuration mode | 193 | N/A | | +| M70 | IPv4 host address + netmask | 195 | N/A | | +| M71 | IPv4 default gateway | 197 | N/A | | +| M72 | IPv4 DNS server | 199 | N/A | | +| M109 | IPv4 managed network config | 204 | N/A | | +| M117 | TCP port number | 209 | N/A | | +| M118 | Fieldbus network stack type | 211 | N/A | | +| NID | Node identification | 218 | N/A | | +| NID2 | Device node ID | 219 | N/A | | + +### Application-Specific (Level 3, filling/dosing) + +| Command | Description | Spec Page | Status | Notes | +|---------|------------------------------------------|-----------|--------|-------| +| A01 | Percent weighing reference | 17 | N/A | Application mode. | +| A02 | Sample identification | 18 | N/A | | +| A03 | Sample name | 19 | N/A | | +| A06 | Dynamic weighing behavior | 20 | N/A | | +| A10 | Nominal, +Tolerance, -Tolerance | 21 | N/A | | +| A30 | Internal loads | 22 | N/A | | +| CW02 | Time for weighing | 48 | N/A | | +| CW03 | Triggered weight value | 50 | N/A | | +| CW11 | Check weighing: weight calculation mode | 51 | N/A | | +| F01-F16 | Filling functions (16 commands) | 69-91 | N/A | Filling/dosing application. | +| FCUT | Filter cut-off frequency | 92 | N/A | | +| FCUT2 | Alt weight path cut-off frequency | 93 | N/A | | +| WMCF | Weight monitoring functions | 270 | N/A | | +| M17 | ProFACT: Single time criteria | 160 | N/A | | +| M18 | ProFACT/FACT: Temperature criterion | 162 | N/A | | +| M22 | Custom unit definitions | 168 | N/A | | +| M31 | Operating mode after restart | 174 | N/A | | +| M32 | ProFACT: Time criteria | 175 | N/A | | +| M33 | ProFACT: Day of the week | 176 | N/A | | +| M34 | MinWeigh: Method | 177 | N/A | | +| M38 | Selective parameter reset | 179 | N/A | | +| M39 | SmartTrac: Graphic | 180 | N/A | | +| M43 | Custom unit | 181 | N/A | | +| M44 | Command after startup response | 182 | N/A | | +| M45 | RS422/485 line termination | 183 | N/A | | +| M47 | Frequently changed test weight settings | 184 | N/A | | +| M48 | Infrequently changed test weight settings| 186 | N/A | | +| M66 | GWP: Certified test weight settings | 189 | N/A | | +| M89 | Interface command set | 201 | N/A | | +| M103 | RS422/485 driver mode | 202 | N/A | | +| M110 | Change display resolution | 205 | N/A | | +| M111 | SAI Cyclic data format | 207 | N/A | | +| M116 | Ignore Ethernet initial parametrization | 208 | N/A | | +| M119 | Byte order mode for automation | 212 | N/A | | +| M124 | Power supply for daisy chain | 214 | N/A | | +| MOD | Various user modes | 215 | N/A | | +| MONH | Monitor on interface | 217 | N/A | | +| SNRU | Stable weight (display unit) + repeat | 243 | N/A | | + +## Priority Summary + +### HIGH (should implement next) +- @ (cancel) - spec-recommended for setup +- C (cancel all) - Level 1 +- E01/E02/E03 (error monitoring) - Level 2 +- SIX1 (gross, net, tare in one call) - Level 2 + +### MED (useful but not urgent) +- I0 (command discovery) +- I3 (software version) +- I11 (model designation) +- I14/I15/I51 (device info, uptime, power-on time) +- I65/I66/I67/I77 (maintenance tracking) +- SIR/SR (continuous streaming - blocked by multi-response TODO) +- SIS (net weight + status) +- C1/C3 (adjustment - blocked by multi-response TODO) +- M01/M02/M03 (weighing mode, environment, auto-zero) +- M27 (adjustment history) +- M28 (temperature) +- DATI (date/time) +- RO1 (restart) diff --git a/pylabrobot/scales/scale.py b/pylabrobot/scales/scale.py index 5fbbc1e4a37..6c38881d070 100644 --- a/pylabrobot/scales/scale.py +++ b/pylabrobot/scales/scale.py @@ -54,6 +54,10 @@ async def tare(self, **backend_kwargs) -> None: """ await self.backend.tare(**backend_kwargs) + async def request_tare_weight(self, **backend_kwargs) -> float: + """Query the current tare weight value stored in the scale, in grams.""" + return await self.backend.request_tare_weight(**backend_kwargs) + async def read_weight(self, **backend_kwargs) -> float: """Read the current weight in grams. diff --git a/pylabrobot/scales/scale_backend.py b/pylabrobot/scales/scale_backend.py index 85894aea7c7..047a129937a 100644 --- a/pylabrobot/scales/scale_backend.py +++ b/pylabrobot/scales/scale_backend.py @@ -17,6 +17,11 @@ async def read_weight(self) -> float: """Read the weight in grams""" ... + @abstractmethod + async def request_tare_weight(self) -> float: + """Request the current tare weight value in grams.""" + ... + # Deprecated: for backward compatibility async def get_weight(self) -> float: """Deprecated: Use read_weight() instead. From 5d62be8f046f774f5eeda73d4c7785405a7afdc9 Mon Sep 17 00:00:00 2001 From: Camillo Moschner Date: Fri, 27 Mar 2026 23:16:59 +0000 Subject: [PATCH 02/38] Reorder send_command response loop: check non-empty before timeout A valid response arriving just past the timeout threshold was being discarded because the timeout check preceded the non-empty check. Sleep moved to only occur between empty reads. Co-Authored-By: Claude Opus 4.6 (1M context) --- pylabrobot/scales/mettler_toledo_backend.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/pylabrobot/scales/mettler_toledo_backend.py b/pylabrobot/scales/mettler_toledo_backend.py index baa6852db6e..2826ec4139a 100644 --- a/pylabrobot/scales/mettler_toledo_backend.py +++ b/pylabrobot/scales/mettler_toledo_backend.py @@ -381,15 +381,14 @@ async def send_command(self, command: str, timeout: int = 60) -> MettlerToledoRe await self.io.write(command.encode() + b"\r\n") - raw_response = b"" timeout_time = time.time() + timeout while True: raw_response = await self.io.readline() - await asyncio.sleep(0.001) - if time.time() > timeout_time: - raise TimeoutError("Timeout while waiting for response from scale.") if raw_response != b"": break + if time.time() > timeout_time: + raise TimeoutError("Timeout while waiting for response from scale.") + await asyncio.sleep(0.001) logger.debug("[scale] Received response: %s", raw_response) response = raw_response.decode("utf-8").strip().split() From 3936cccfa18e0d785bf87a39dee8021e64a1ebe7 Mon Sep 17 00:00:00 2001 From: Camillo Moschner Date: Fri, 27 Mar 2026 23:46:54 +0000 Subject: [PATCH 03/38] Scale notebook: correct warm-up time, method count, typo, add teardown, gate execution-only code; round chatterbox to 0.01mg --- .../scales/mettler-toledo-WXS205SDU.ipynb | 119 +++++++----- pylabrobot/scales/__init__.py | 1 + pylabrobot/scales/chatterbox.py | 4 +- pylabrobot/scales/mettler_toledo_backend.py | 181 +++--------------- .../scales/mettler_toledo_sics_errors.py | 137 +++++++++++++ 5 files changed, 237 insertions(+), 205 deletions(-) create mode 100644 pylabrobot/scales/mettler_toledo_sics_errors.py diff --git a/docs/user_guide/02_analytical/scales/mettler-toledo-WXS205SDU.ipynb b/docs/user_guide/02_analytical/scales/mettler-toledo-WXS205SDU.ipynb index 1cc4ba0c065..22da9ce9e80 100644 --- a/docs/user_guide/02_analytical/scales/mettler-toledo-WXS205SDU.ipynb +++ b/docs/user_guide/02_analytical/scales/mettler-toledo-WXS205SDU.ipynb @@ -59,10 +59,10 @@ "execution_count": 1, "metadata": { "execution": { - "iopub.execute_input": "2026-03-27T15:53:13.146987Z", - "iopub.status.busy": "2026-03-27T15:53:13.146777Z", - "iopub.status.idle": "2026-03-27T15:53:13.150980Z", - "shell.execute_reply": "2026-03-27T15:53:13.150542Z" + "iopub.execute_input": "2026-03-27T23:44:33.840008Z", + "iopub.status.busy": "2026-03-27T23:44:33.839755Z", + "iopub.status.idle": "2026-03-27T23:44:33.844785Z", + "shell.execute_reply": "2026-03-27T23:44:33.844432Z" } }, "outputs": [], @@ -75,10 +75,10 @@ "execution_count": 2, "metadata": { "execution": { - "iopub.execute_input": "2026-03-27T15:53:13.153037Z", - "iopub.status.busy": "2026-03-27T15:53:13.152879Z", - "iopub.status.idle": "2026-03-27T15:53:13.245300Z", - "shell.execute_reply": "2026-03-27T15:53:13.245082Z" + "iopub.execute_input": "2026-03-27T23:44:33.846776Z", + "iopub.status.busy": "2026-03-27T23:44:33.846597Z", + "iopub.status.idle": "2026-03-27T23:44:33.966730Z", + "shell.execute_reply": "2026-03-27T23:44:33.966521Z" } }, "outputs": [ @@ -97,6 +97,7 @@ "\n", " from pylabrobot.scales.mettler_toledo_backend import MTSICSBackend\n", "\n", + " # Platform-specific port: Mac: /dev/cu.usbserial-*, Linux: /dev/ttyUSB*, Windows: COM*\n", " backend = MTSICSBackend(port=\"/dev/cu.usbserial-110\")\n", "\n", "elif protocol_mode == \"simulation\":\n", @@ -117,7 +118,7 @@ "```{Warning}\n", "### Warm-up Time Required\n", "\n", - "This scale requires a **warm-up period** after being powered on. Mettler Toledo documentation specifies 60-90 minutes, though in practice 30 minutes is often sufficient.\n", + "This scale requires a **warm-up period** after being powered on. Mettler Toledo documentation specifies 60 minutes, though in practice 30 minutes is often sufficient.\n", "\n", "If you attempt measurements before the scale has warmed up, you'll likely encounter an error: *\"Command understood but currently not executable (balance is currently executing another command)\"*.\n", "\n", @@ -137,7 +138,7 @@ "---\n", "## Usage\n", "\n", - "The scale implements the three core methods required for all PyLabRobot scales.\n", + "The scale implements four core methods required for all PyLabRobot scales.\n", "\n", "They are presented here in typical workflow order:\n", "\n", @@ -153,10 +154,10 @@ "execution_count": 3, "metadata": { "execution": { - "iopub.execute_input": "2026-03-27T15:53:13.259538Z", - "iopub.status.busy": "2026-03-27T15:53:13.259428Z", - "iopub.status.idle": "2026-03-27T15:53:13.261100Z", - "shell.execute_reply": "2026-03-27T15:53:13.260918Z" + "iopub.execute_input": "2026-03-27T23:44:33.981019Z", + "iopub.status.busy": "2026-03-27T23:44:33.980919Z", + "iopub.status.idle": "2026-03-27T23:44:33.982494Z", + "shell.execute_reply": "2026-03-27T23:44:33.982309Z" } }, "outputs": [ @@ -198,10 +199,10 @@ "execution_count": 4, "metadata": { "execution": { - "iopub.execute_input": "2026-03-27T15:53:13.262148Z", - "iopub.status.busy": "2026-03-27T15:53:13.262089Z", - "iopub.status.idle": "2026-03-27T15:53:13.263750Z", - "shell.execute_reply": "2026-03-27T15:53:13.263577Z" + "iopub.execute_input": "2026-03-27T23:44:33.983493Z", + "iopub.status.busy": "2026-03-27T23:44:33.983429Z", + "iopub.status.idle": "2026-03-27T23:44:33.985035Z", + "shell.execute_reply": "2026-03-27T23:44:33.984885Z" } }, "outputs": [ @@ -224,7 +225,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "The difference between load at `scale.zero()` and load at `scale.tare()` is stored in and can be retrieved from the scales's memory:" + "The difference between load at `scale.zero()` and load at `scale.tare()` is stored in and can be retrieved from the scale's memory:" ] }, { @@ -232,10 +233,10 @@ "execution_count": 5, "metadata": { "execution": { - "iopub.execute_input": "2026-03-27T15:53:13.264636Z", - "iopub.status.busy": "2026-03-27T15:53:13.264581Z", - "iopub.status.idle": "2026-03-27T15:53:13.266917Z", - "shell.execute_reply": "2026-03-27T15:53:13.266768Z" + "iopub.execute_input": "2026-03-27T23:44:33.985945Z", + "iopub.status.busy": "2026-03-27T23:44:33.985891Z", + "iopub.status.idle": "2026-03-27T23:44:33.988165Z", + "shell.execute_reply": "2026-03-27T23:44:33.988008Z" } }, "outputs": [ @@ -276,10 +277,10 @@ "execution_count": 6, "metadata": { "execution": { - "iopub.execute_input": "2026-03-27T15:53:13.267802Z", - "iopub.status.busy": "2026-03-27T15:53:13.267744Z", - "iopub.status.idle": "2026-03-27T15:53:13.269598Z", - "shell.execute_reply": "2026-03-27T15:53:13.269439Z" + "iopub.execute_input": "2026-03-27T23:44:33.989108Z", + "iopub.status.busy": "2026-03-27T23:44:33.989050Z", + "iopub.status.idle": "2026-03-27T23:44:33.991326Z", + "shell.execute_reply": "2026-03-27T23:44:33.991175Z" } }, "outputs": [ @@ -293,7 +294,7 @@ { "data": { "text/plain": [ - "0.010599999999996612" + "0.0106" ] }, "execution_count": 6, @@ -323,10 +324,10 @@ "execution_count": 7, "metadata": { "execution": { - "iopub.execute_input": "2026-03-27T15:53:13.270492Z", - "iopub.status.busy": "2026-03-27T15:53:13.270436Z", - "iopub.status.idle": "2026-03-27T15:53:14.275293Z", - "shell.execute_reply": "2026-03-27T15:53:14.274778Z" + "iopub.execute_input": "2026-03-27T23:44:33.992285Z", + "iopub.status.busy": "2026-03-27T23:44:33.992222Z", + "iopub.status.idle": "2026-03-27T23:44:33.994182Z", + "shell.execute_reply": "2026-03-27T23:44:33.994020Z" } }, "outputs": [ @@ -335,13 +336,7 @@ "output_type": "stream", "text": [ "Zeroing the scale\n", - "Taring the scale\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ + "Taring the scale\n", "Reading the weight\n", "Dispensed 10.60 mg (10.00 uL)\n" ] @@ -372,7 +367,8 @@ " backend.sample_weight = 1.06 # dispensed ~10 uL back\n", "\n", "# 6. Brief pause to allow scale to settle\n", - "await asyncio.sleep(1) # Allow 1 second for settling after dispense\n", + "if protocol_mode == \"execution\":\n", + " await asyncio.sleep(1)\n", "\n", "# 7. Read the weight of dispensed liquid\n", "weight_g = await scale.read_weight(timeout=5)\n", @@ -394,7 +390,8 @@ "\n", "#### Example: Measuring Read Time\n", "\n", - "You can easily benchmark the scale's performance using standard Python timing:" + "You can benchmark the scale's read latency using standard Python timing.\n", + "This section only runs in execution mode (requires a physical scale)." ] }, { @@ -402,10 +399,10 @@ "execution_count": 8, "metadata": { "execution": { - "iopub.execute_input": "2026-03-27T15:53:14.277735Z", - "iopub.status.busy": "2026-03-27T15:53:14.277525Z", - "iopub.status.idle": "2026-03-27T15:53:14.280442Z", - "shell.execute_reply": "2026-03-27T15:53:14.280087Z" + "iopub.execute_input": "2026-03-27T23:44:33.995029Z", + "iopub.status.busy": "2026-03-27T23:44:33.994977Z", + "iopub.status.idle": "2026-03-27T23:44:33.996425Z", + "shell.execute_reply": "2026-03-27T23:44:33.996254Z" } }, "outputs": [], @@ -423,6 +420,38 @@ "\n", " print(f\"{np.mean(times):.2f} ms +/- {np.std(times):.2f} ms\")" ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "---\n", + "### Teardown" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": { + "execution": { + "iopub.execute_input": "2026-03-27T23:44:33.997350Z", + "iopub.status.busy": "2026-03-27T23:44:33.997300Z", + "iopub.status.idle": "2026-03-27T23:44:33.998694Z", + "shell.execute_reply": "2026-03-27T23:44:33.998555Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Stopping the scale.\n" + ] + } + ], + "source": [ + "await scale.stop()" + ] } ], "metadata": { diff --git a/pylabrobot/scales/__init__.py b/pylabrobot/scales/__init__.py index f8fd737e95b..3a69c89e1a6 100644 --- a/pylabrobot/scales/__init__.py +++ b/pylabrobot/scales/__init__.py @@ -3,5 +3,6 @@ MettlerToledoWXS205SDUBackend, MTSICSBackend, ) +from pylabrobot.scales.mettler_toledo_sics_errors import MettlerToledoError from pylabrobot.scales.scale import Scale from pylabrobot.scales.scale_backend import ScaleBackend diff --git a/pylabrobot/scales/chatterbox.py b/pylabrobot/scales/chatterbox.py index 7cbd05c8f3f..9d3e2b68252 100644 --- a/pylabrobot/scales/chatterbox.py +++ b/pylabrobot/scales/chatterbox.py @@ -57,8 +57,8 @@ async def tare(self, **kwargs): async def request_tare_weight(self, **kwargs) -> float: print("Requesting tare weight") - return self.tare_weight + return round(self.tare_weight, 5) async def read_weight(self, **kwargs) -> float: print("Reading the weight") - return self._sensor_reading - self.zero_offset - self.tare_weight + return round(self._sensor_reading - self.zero_offset - self.tare_weight, 5) diff --git a/pylabrobot/scales/mettler_toledo_backend.py b/pylabrobot/scales/mettler_toledo_backend.py index 2826ec4139a..ffced5559cf 100644 --- a/pylabrobot/scales/mettler_toledo_backend.py +++ b/pylabrobot/scales/mettler_toledo_backend.py @@ -10,139 +10,11 @@ from typing import Any, Callable, List, Literal, Optional, Set, TypeVar, Union from pylabrobot.io.serial import Serial +from pylabrobot.scales.mettler_toledo_sics_errors import MettlerToledoError from pylabrobot.scales.scale_backend import ScaleBackend logger = logging.getLogger("pylabrobot") - -class MettlerToledoError(Exception): - """Exceptions raised by a Mettler Toledo scale.""" - - def __init__(self, title: str, message: Optional[str] = None) -> None: - self.title = title - self.message = message - - def __str__(self) -> str: - return f"{self.title}: {self.message}" - - @staticmethod - def unknown_error() -> "MettlerToledoError": - return MettlerToledoError(title="Unknown error", message="An unknown error occurred") - - @staticmethod - def executing_another_command() -> "MettlerToledoError": - return MettlerToledoError( - title="Command not understood, not executable at present", - message=( - "Command understood but currently not executable (balance is " - "currently executing another command)." - ), - ) - - @staticmethod - def incorrect_parameter() -> "MettlerToledoError": - return MettlerToledoError( - title="Command understood but not executable", - message="(incorrect parameter).", - ) - - @staticmethod - def overload() -> "MettlerToledoError": - return MettlerToledoError(title="Balance in overload range.", message=None) - - @staticmethod - def underload() -> "MettlerToledoError": - return MettlerToledoError(title="Balance in underload range.", message=None) - - @staticmethod - def syntax_error() -> "MettlerToledoError": - return MettlerToledoError( - title="Syntax error", - message="The weigh module/balance has not recognized the received command or the command is " - "not allowed", - ) - - @staticmethod - def transmission_error() -> "MettlerToledoError": - return MettlerToledoError( - title="Transmission error", - message="The weigh module/balance has received a 'faulty' command, e.g. owing to a parity " - "error or interface break", - ) - - @staticmethod - def logical_error() -> "MettlerToledoError": - return MettlerToledoError( - title="Logical error", - message="The weigh module/balance can not execute the received command", - ) - - @staticmethod - def boot_error(from_terminal: bool) -> "MettlerToledoError": - return MettlerToledoError( - title="Boot error", - message="from terminal" if from_terminal else "from electronics", - ) - - @staticmethod - def brand_error(from_terminal: bool) -> "MettlerToledoError": - return MettlerToledoError( - title="Brand error", - message="from terminal" if from_terminal else "from electronics", - ) - - @staticmethod - def checksum_error(from_terminal: bool) -> "MettlerToledoError": - return MettlerToledoError( - title="Checksum error", - message="from terminal" if from_terminal else "from electronics", - ) - - @staticmethod - def option_fail(from_terminal: bool) -> "MettlerToledoError": - return MettlerToledoError( - title="Option fail", - message="from terminal" if from_terminal else "from electronics", - ) - - @staticmethod - def eeprom_error(from_terminal: bool) -> "MettlerToledoError": - return MettlerToledoError( - title="EEPROM error", - message="from terminal" if from_terminal else "from electronics", - ) - - @staticmethod - def device_mismatch(from_terminal: bool) -> "MettlerToledoError": - return MettlerToledoError( - title="Device mismatch", - message="from terminal" if from_terminal else "from electronics", - ) - - @staticmethod - def hot_plug_out(from_terminal: bool) -> "MettlerToledoError": - return MettlerToledoError( - title="Hot plug out", - message="from terminal" if from_terminal else "from electronics", - ) - - @staticmethod - def weight_module_electronic_mismatch( - from_terminal: bool, - ) -> "MettlerToledoError": - return MettlerToledoError( - title="Weight module / electronic mismatch", - message="from terminal" if from_terminal else "from electronics", - ) - - @staticmethod - def adjustment_needed(from_terminal: bool) -> "MettlerToledoError": - return MettlerToledoError( - title="Adjustment needed", - message="from terminal" if from_terminal else "from electronics", - ) - - MettlerToledoResponse = List[str] @@ -398,6 +270,25 @@ async def send_command(self, command: str, timeout: int = 60) -> MettlerToledoRe # mypy doesn't understand this return response # type: ignore + async def _drain_followup_responses(self, command: str, timeout: float = 10) -> None: + """Read and discard follow-up responses from multi-response commands. + + Multi-response commands (B status) send additional lines after the first response. + This method reads lines until it sees status A (final) or times out. + """ + timeout_time = time.time() + timeout + while True: + raw_followup = await self.io.readline() + if raw_followup != b"": + followup = raw_followup.decode("utf-8").strip().split() + logger.debug("[scale] %s followup: %s", command, raw_followup) + if len(followup) >= 2 and followup[1] == "A": + break + if time.time() > timeout_time: + logger.warning("[scale] Timeout waiting for %s followup", command) + break + await asyncio.sleep(0.001) + # === Public high-level API === # # Cancel commands # # @@ -436,18 +327,8 @@ async def cancel_all(self) -> None: message=f"C command returned error: {response}", ) - # Second response: C A (cancel complete) - must read to clear buffer - raw_followup = b"" - timeout_time = time.time() + 10 - while True: - raw_followup = await self.io.readline() - await asyncio.sleep(0.001) - if time.time() > timeout_time: - logger.warning("[scale] Timeout waiting for C A followup") - break - if raw_followup != b"": - break - logger.debug("[scale] Cancel followup: %s", raw_followup) + # Second response: C A (cancel complete) + await self._drain_followup_responses("C") # # Identification commands # # @@ -492,23 +373,7 @@ async def request_remaining_weighing_range(self) -> float: remaining = float(response[3]) # Drain follow-up responses (RangeNo 1 and 2) to keep the serial buffer clean - timeout_time = time.time() + 10 - while True: - raw_followup = b"" - while True: - raw_followup = await self.io.readline() - await asyncio.sleep(0.001) - if time.time() > timeout_time: - break - if raw_followup != b"": - break - if raw_followup == b"" or time.time() > timeout_time: - break - followup = raw_followup.decode("utf-8").strip().split() - logger.debug("[scale] I50 followup: %s", raw_followup) - # Stop after the final response (status A) - if len(followup) >= 2 and followup[1] == "A": - break + await self._drain_followup_responses("I50") return remaining diff --git a/pylabrobot/scales/mettler_toledo_sics_errors.py b/pylabrobot/scales/mettler_toledo_sics_errors.py new file mode 100644 index 00000000000..59ee3a38d9d --- /dev/null +++ b/pylabrobot/scales/mettler_toledo_sics_errors.py @@ -0,0 +1,137 @@ +"""MT-SICS error types and response codes (spec Sections 2.1.3.1 - 2.1.3.3).""" + +from typing import Optional + + +class MettlerToledoError(Exception): + """Exceptions raised by a Mettler Toledo scale.""" + + def __init__(self, title: str, message: Optional[str] = None) -> None: + self.title = title + self.message = message + + def __str__(self) -> str: + return f"{self.title}: {self.message}" + + # -- General errors (spec Section 2.1.3.2) -- + + @staticmethod + def unknown_error() -> "MettlerToledoError": + return MettlerToledoError(title="Unknown error", message="An unknown error occurred") + + @staticmethod + def syntax_error() -> "MettlerToledoError": + return MettlerToledoError( + title="Syntax error", + message="The weigh module/balance has not recognized the received command or the command is " + "not allowed", + ) + + @staticmethod + def transmission_error() -> "MettlerToledoError": + return MettlerToledoError( + title="Transmission error", + message="The weigh module/balance has received a 'faulty' command, e.g. owing to a parity " + "error or interface break", + ) + + @staticmethod + def logical_error() -> "MettlerToledoError": + return MettlerToledoError( + title="Logical error", + message="The weigh module/balance can not execute the received command", + ) + + # -- Command-specific status codes (spec Section 2.1.3.1) -- + + @staticmethod + def executing_another_command() -> "MettlerToledoError": + return MettlerToledoError( + title="Command not understood, not executable at present", + message=( + "Command understood but currently not executable (balance is " + "currently executing another command)." + ), + ) + + @staticmethod + def incorrect_parameter() -> "MettlerToledoError": + return MettlerToledoError( + title="Command understood but not executable", + message="(incorrect parameter).", + ) + + @staticmethod + def overload() -> "MettlerToledoError": + return MettlerToledoError(title="Balance in overload range.", message=None) + + @staticmethod + def underload() -> "MettlerToledoError": + return MettlerToledoError(title="Balance in underload range.", message=None) + + # -- Weight response error codes (spec Section 2.1.3.3) -- + + @staticmethod + def boot_error(from_terminal: bool) -> "MettlerToledoError": + return MettlerToledoError( + title="Boot error", + message="from terminal" if from_terminal else "from electronics", + ) + + @staticmethod + def brand_error(from_terminal: bool) -> "MettlerToledoError": + return MettlerToledoError( + title="Brand error", + message="from terminal" if from_terminal else "from electronics", + ) + + @staticmethod + def checksum_error(from_terminal: bool) -> "MettlerToledoError": + return MettlerToledoError( + title="Checksum error", + message="from terminal" if from_terminal else "from electronics", + ) + + @staticmethod + def option_fail(from_terminal: bool) -> "MettlerToledoError": + return MettlerToledoError( + title="Option fail", + message="from terminal" if from_terminal else "from electronics", + ) + + @staticmethod + def eeprom_error(from_terminal: bool) -> "MettlerToledoError": + return MettlerToledoError( + title="EEPROM error", + message="from terminal" if from_terminal else "from electronics", + ) + + @staticmethod + def device_mismatch(from_terminal: bool) -> "MettlerToledoError": + return MettlerToledoError( + title="Device mismatch", + message="from terminal" if from_terminal else "from electronics", + ) + + @staticmethod + def hot_plug_out(from_terminal: bool) -> "MettlerToledoError": + return MettlerToledoError( + title="Hot plug out", + message="from terminal" if from_terminal else "from electronics", + ) + + @staticmethod + def weight_module_electronic_mismatch( + from_terminal: bool, + ) -> "MettlerToledoError": + return MettlerToledoError( + title="Weight module / electronic mismatch", + message="from terminal" if from_terminal else "from electronics", + ) + + @staticmethod + def adjustment_needed(from_terminal: bool) -> "MettlerToledoError": + return MettlerToledoError( + title="Adjustment needed", + message="from terminal" if from_terminal else "from electronics", + ) From 0de2b016de7a9e4ad144f95b243f092a2094ec46 Mon Sep 17 00:00:00 2001 From: Camillo Moschner Date: Sat, 28 Mar 2026 21:24:07 +0000 Subject: [PATCH 04/38] Mettler Toledo backend into subpackage, split tests into generic scale and MT-SICS response parsing --- .../scales/mettler-toledo-WXS205SDU.ipynb | 129 ++-- pylabrobot/scales/__init__.py | 8 +- pylabrobot/scales/chatterbox.py | 2 + pylabrobot/scales/mettler_toledo/__init__.py | 4 + pylabrobot/scales/mettler_toledo/backend.py | 626 +++++++++++++++++ .../scales/mettler_toledo/backend_tests.py | 75 +++ .../errors.py} | 0 .../{ => mettler_toledo}/mt_sics_commands.md | 6 +- pylabrobot/scales/mettler_toledo_backend.py | 631 +----------------- pylabrobot/scales/scale_backend.py | 6 +- pylabrobot/scales/scales_tests.py | 78 +++ 11 files changed, 878 insertions(+), 687 deletions(-) create mode 100644 pylabrobot/scales/mettler_toledo/__init__.py create mode 100644 pylabrobot/scales/mettler_toledo/backend.py create mode 100644 pylabrobot/scales/mettler_toledo/backend_tests.py rename pylabrobot/scales/{mettler_toledo_sics_errors.py => mettler_toledo/errors.py} (100%) rename pylabrobot/scales/{ => mettler_toledo}/mt_sics_commands.md (98%) create mode 100644 pylabrobot/scales/scales_tests.py diff --git a/docs/user_guide/02_analytical/scales/mettler-toledo-WXS205SDU.ipynb b/docs/user_guide/02_analytical/scales/mettler-toledo-WXS205SDU.ipynb index 22da9ce9e80..e6506759238 100644 --- a/docs/user_guide/02_analytical/scales/mettler-toledo-WXS205SDU.ipynb +++ b/docs/user_guide/02_analytical/scales/mettler-toledo-WXS205SDU.ipynb @@ -59,10 +59,10 @@ "execution_count": 1, "metadata": { "execution": { - "iopub.execute_input": "2026-03-27T23:44:33.840008Z", - "iopub.status.busy": "2026-03-27T23:44:33.839755Z", - "iopub.status.idle": "2026-03-27T23:44:33.844785Z", - "shell.execute_reply": "2026-03-27T23:44:33.844432Z" + "iopub.execute_input": "2026-03-28T08:00:05.295576Z", + "iopub.status.busy": "2026-03-28T08:00:05.295363Z", + "iopub.status.idle": "2026-03-28T08:00:05.299272Z", + "shell.execute_reply": "2026-03-28T08:00:05.298929Z" } }, "outputs": [], @@ -75,10 +75,10 @@ "execution_count": 2, "metadata": { "execution": { - "iopub.execute_input": "2026-03-27T23:44:33.846776Z", - "iopub.status.busy": "2026-03-27T23:44:33.846597Z", - "iopub.status.idle": "2026-03-27T23:44:33.966730Z", - "shell.execute_reply": "2026-03-27T23:44:33.966521Z" + "iopub.execute_input": "2026-03-28T08:00:05.300973Z", + "iopub.status.busy": "2026-03-28T08:00:05.300861Z", + "iopub.status.idle": "2026-03-28T08:00:05.394300Z", + "shell.execute_reply": "2026-03-28T08:00:05.394113Z" } }, "outputs": [ @@ -95,10 +95,10 @@ "\n", "if protocol_mode == \"execution\":\n", "\n", - " from pylabrobot.scales.mettler_toledo_backend import MTSICSBackend\n", + " from pylabrobot.scales.mettler_toledo import MettlerToledoWXS205SDUBackend\n", "\n", " # Platform-specific port: Mac: /dev/cu.usbserial-*, Linux: /dev/ttyUSB*, Windows: COM*\n", - " backend = MTSICSBackend(port=\"/dev/cu.usbserial-110\")\n", + " backend = MettlerToledoWXS205SDUBackend(port=\"/dev/cu.usbserial-110\")\n", "\n", "elif protocol_mode == \"simulation\":\n", "\n", @@ -131,6 +131,39 @@ "```" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Logging\n", + "\n", + "In Jupyter, PyLabRobot automatically shows INFO-level log messages (including device\n", + "identity discovered during `setup()`). To also save logs to disk (including raw serial\n", + "bytes), set up file logging:\n", + "\n", + "See the [Logging documentation](../../machine-agnostic-features/logging-and-validation/logging.rst) for details." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "execution": { + "iopub.execute_input": "2026-03-28T08:00:05.408855Z", + "iopub.status.busy": "2026-03-28T08:00:05.408720Z", + "iopub.status.idle": "2026-03-28T08:00:05.410912Z", + "shell.execute_reply": "2026-03-28T08:00:05.410692Z" + } + }, + "outputs": [], + "source": [ + "import logging\n", + "from pylabrobot.io import LOG_LEVEL_IO\n", + "import pylabrobot\n", + "\n", + "pylabrobot.setup_logger(log_dir=\"./logs\", level=LOG_LEVEL_IO)" + ] + }, { "cell_type": "markdown", "metadata": {}, @@ -151,13 +184,13 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 4, "metadata": { "execution": { - "iopub.execute_input": "2026-03-27T23:44:33.981019Z", - "iopub.status.busy": "2026-03-27T23:44:33.980919Z", - "iopub.status.idle": "2026-03-27T23:44:33.982494Z", - "shell.execute_reply": "2026-03-27T23:44:33.982309Z" + "iopub.execute_input": "2026-03-28T08:00:05.411920Z", + "iopub.status.busy": "2026-03-28T08:00:05.411838Z", + "iopub.status.idle": "2026-03-28T08:00:05.413356Z", + "shell.execute_reply": "2026-03-28T08:00:05.413204Z" } }, "outputs": [ @@ -196,13 +229,13 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 5, "metadata": { "execution": { - "iopub.execute_input": "2026-03-27T23:44:33.983493Z", - "iopub.status.busy": "2026-03-27T23:44:33.983429Z", - "iopub.status.idle": "2026-03-27T23:44:33.985035Z", - "shell.execute_reply": "2026-03-27T23:44:33.984885Z" + "iopub.execute_input": "2026-03-28T08:00:05.414381Z", + "iopub.status.busy": "2026-03-28T08:00:05.414297Z", + "iopub.status.idle": "2026-03-28T08:00:05.415828Z", + "shell.execute_reply": "2026-03-28T08:00:05.415664Z" } }, "outputs": [ @@ -230,13 +263,13 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 6, "metadata": { "execution": { - "iopub.execute_input": "2026-03-27T23:44:33.985945Z", - "iopub.status.busy": "2026-03-27T23:44:33.985891Z", - "iopub.status.idle": "2026-03-27T23:44:33.988165Z", - "shell.execute_reply": "2026-03-27T23:44:33.988008Z" + "iopub.execute_input": "2026-03-28T08:00:05.416811Z", + "iopub.status.busy": "2026-03-28T08:00:05.416752Z", + "iopub.status.idle": "2026-03-28T08:00:05.419071Z", + "shell.execute_reply": "2026-03-28T08:00:05.418914Z" } }, "outputs": [ @@ -253,7 +286,7 @@ "50.0" ] }, - "execution_count": 5, + "execution_count": 6, "metadata": {}, "output_type": "execute_result" } @@ -267,20 +300,20 @@ "metadata": {}, "source": [ "\n", - "### `read_weight()`\n", + "### `.read_weight()`\n", "\n", "Retrieves the current weight measurement from the scale **in grams**." ] }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 7, "metadata": { "execution": { - "iopub.execute_input": "2026-03-27T23:44:33.989108Z", - "iopub.status.busy": "2026-03-27T23:44:33.989050Z", - "iopub.status.idle": "2026-03-27T23:44:33.991326Z", - "shell.execute_reply": "2026-03-27T23:44:33.991175Z" + "iopub.execute_input": "2026-03-28T08:00:05.419965Z", + "iopub.status.busy": "2026-03-28T08:00:05.419889Z", + "iopub.status.idle": "2026-03-28T08:00:05.421714Z", + "shell.execute_reply": "2026-03-28T08:00:05.421540Z" } }, "outputs": [ @@ -297,7 +330,7 @@ "0.0106" ] }, - "execution_count": 6, + "execution_count": 7, "metadata": {}, "output_type": "execute_result" } @@ -321,13 +354,13 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 8, "metadata": { "execution": { - "iopub.execute_input": "2026-03-27T23:44:33.992285Z", - "iopub.status.busy": "2026-03-27T23:44:33.992222Z", - "iopub.status.idle": "2026-03-27T23:44:33.994182Z", - "shell.execute_reply": "2026-03-27T23:44:33.994020Z" + "iopub.execute_input": "2026-03-28T08:00:05.422600Z", + "iopub.status.busy": "2026-03-28T08:00:05.422547Z", + "iopub.status.idle": "2026-03-28T08:00:05.424896Z", + "shell.execute_reply": "2026-03-28T08:00:05.424713Z" } }, "outputs": [ @@ -396,13 +429,13 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 9, "metadata": { "execution": { - "iopub.execute_input": "2026-03-27T23:44:33.995029Z", - "iopub.status.busy": "2026-03-27T23:44:33.994977Z", - "iopub.status.idle": "2026-03-27T23:44:33.996425Z", - "shell.execute_reply": "2026-03-27T23:44:33.996254Z" + "iopub.execute_input": "2026-03-28T08:00:05.425832Z", + "iopub.status.busy": "2026-03-28T08:00:05.425771Z", + "iopub.status.idle": "2026-03-28T08:00:05.427451Z", + "shell.execute_reply": "2026-03-28T08:00:05.427255Z" } }, "outputs": [], @@ -431,13 +464,13 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": 10, "metadata": { "execution": { - "iopub.execute_input": "2026-03-27T23:44:33.997350Z", - "iopub.status.busy": "2026-03-27T23:44:33.997300Z", - "iopub.status.idle": "2026-03-27T23:44:33.998694Z", - "shell.execute_reply": "2026-03-27T23:44:33.998555Z" + "iopub.execute_input": "2026-03-28T08:00:05.428404Z", + "iopub.status.busy": "2026-03-28T08:00:05.428333Z", + "iopub.status.idle": "2026-03-28T08:00:05.429738Z", + "shell.execute_reply": "2026-03-28T08:00:05.429590Z" } }, "outputs": [ diff --git a/pylabrobot/scales/__init__.py b/pylabrobot/scales/__init__.py index 3a69c89e1a6..67416b5f5a3 100644 --- a/pylabrobot/scales/__init__.py +++ b/pylabrobot/scales/__init__.py @@ -1,8 +1,6 @@ +"""PyLabRobot scales package - frontend, backends, and error types.""" + from pylabrobot.scales.chatterbox import ScaleChatterboxBackend -from pylabrobot.scales.mettler_toledo_backend import ( - MettlerToledoWXS205SDUBackend, - MTSICSBackend, -) -from pylabrobot.scales.mettler_toledo_sics_errors import MettlerToledoError +from pylabrobot.scales.mettler_toledo import MettlerToledoError, MettlerToledoWXS205SDUBackend from pylabrobot.scales.scale import Scale from pylabrobot.scales.scale_backend import ScaleBackend diff --git a/pylabrobot/scales/chatterbox.py b/pylabrobot/scales/chatterbox.py index 9d3e2b68252..d92b9654cae 100644 --- a/pylabrobot/scales/chatterbox.py +++ b/pylabrobot/scales/chatterbox.py @@ -1,3 +1,5 @@ +"""Chatterbox scale backend for device-free testing and simulation.""" + from pylabrobot.scales.scale_backend import ScaleBackend diff --git a/pylabrobot/scales/mettler_toledo/__init__.py b/pylabrobot/scales/mettler_toledo/__init__.py new file mode 100644 index 00000000000..17e2ddd79f9 --- /dev/null +++ b/pylabrobot/scales/mettler_toledo/__init__.py @@ -0,0 +1,4 @@ +"""Mettler Toledo scale backend using the MT-SICS protocol.""" + +from pylabrobot.scales.mettler_toledo.backend import MettlerToledoWXS205SDUBackend +from pylabrobot.scales.mettler_toledo.errors import MettlerToledoError diff --git a/pylabrobot/scales/mettler_toledo/backend.py b/pylabrobot/scales/mettler_toledo/backend.py new file mode 100644 index 00000000000..aa4759c9ffb --- /dev/null +++ b/pylabrobot/scales/mettler_toledo/backend.py @@ -0,0 +1,626 @@ +"""Mettler Toledo scale backend using the MT-SICS (Mettler Toledo Standard Interface Command Set) serial protocol.""" + +# similar library: https://github.com/janelia-pypi/mettler_toledo_device_python + +import asyncio +import functools +import logging +import time +import warnings +from typing import Any, Callable, List, Literal, Optional, Set, TypeVar, Union + +from pylabrobot.io.serial import Serial +from pylabrobot.scales.mettler_toledo.errors import MettlerToledoError +from pylabrobot.scales.scale_backend import ScaleBackend + +logger = logging.getLogger("pylabrobot") + +MettlerToledoResponse = List[str] + + +F = TypeVar("F", bound=Callable[..., Any]) + + +def requires_mt_sics_level(level: int) -> Callable[[F], F]: + """Decorator that gates a method on the connected device supporting the required MT-SICS level. + + During setup(), the backend queries I1 to discover which levels the connected device supports. + Methods decorated with a level higher than what the device reports will raise MettlerToledoError. + See the class docstring of MettlerToledoWXS205SDUBackend for level descriptions. + """ + + def decorator(func: F) -> F: + func._mt_sics_level = level # type: ignore[attr-defined] + + @functools.wraps(func) + async def wrapper(self: Any, *args: Any, **kwargs: Any) -> Any: + if hasattr(self, "_mt_sics_levels") and self._mt_sics_levels is not None: + if level not in self._mt_sics_levels: + raise MettlerToledoError( + title="Command not supported", + message=f"'{func.__name__}' requires MT-SICS level {level}, " + f"but device supports levels: {sorted(self._mt_sics_levels)}", + ) + return await func(self, *args, **kwargs) + + return wrapper # type: ignore[return-value] + + return decorator + + +# TODO: rename to MTSICSDriver in v1.0.0-beta +class MettlerToledoWXS205SDUBackend(ScaleBackend): + """Backend for Mettler Toledo scales using the MT-SICS protocol. + + MT-SICS (Mettler Toledo Standard Interface Command Set) is the serial communication + protocol used by Mettler Toledo's Automated Precision Weigh Modules. This backend is + compatible with any MT-SICS device, including the WXS, WMS, and WX series. During + setup(), this backend queries the device to discover its identity, capacity, and + supported MT-SICS levels. + + MT-SICS levels: + - Level 0: Basic set - identification (I0-I4), basic weighing (S, SI), zero (Z, ZI), + tare (T, TI), cancel (@). Always available on every MT-SICS device. + - Level 1: Elementary commands - display (D, DW), tare memory (TA, TAC), timed + weighing (SC), timed zero/tare (ZC, TC). Always available. + - Level 2: Extended command list - configuration (M21, COM), device info (I50, I47, + I48). Model-dependent, not guaranteed on every device. + - Level 3: Application-specific command set. Model-dependent. + + Methods requiring Level 2+ are decorated with ``@requires_mt_sics_level`` and will + raise ``MettlerToledoError`` if the connected device does not support the required level. + + Tested on the WXS205SDU (used by Hamilton in the Liquid Verification Kit). + + Spec: https://web.archive.org/web/20240208213802/https://www.mt.com/dam/ + product_organizations/industry/apw/generic/11781363_N_MAN_RM_MT-SICS_APW_en.pdf + + From the spec (Section 2.2): + "If several commands are sent in succession without waiting for the corresponding + responses, it is possible that the weigh module/balance confuses the sequence of + command processing or ignores entire commands." + """ + + # === Constructor === + + def __init__(self, port: Optional[str] = None, vid: int = 0x0403, pid: int = 0x6001): + super().__init__() + + self.io = Serial( + human_readable_device_name="Mettler Toledo Scale", + port=port, + vid=vid, + pid=pid, + baudrate=9600, + timeout=1, + ) + + async def setup(self) -> None: + await self.io.setup() + + # Reset device to clean state (spec Section 2.2) + # cancel() clears the input buffer and sends @, which returns the serial number + self.serial_number = await self.cancel() + + # Device discovery (Level 0 - always available) + self._mt_sics_levels: Set[int] = await self._query_mt_sics_levels() + self.device_type = await self.request_device_type() + self.capacity = await self.request_capacity() + + logger.info( + "[scale] Connected: %s (S/N: %s, capacity: %.1f g, MT-SICS levels: %s)", + self.device_type, + self.serial_number, + self.capacity, + sorted(self._mt_sics_levels), + ) + + # Set output unit to grams + if 2 in self._mt_sics_levels: + await self.set_host_unit_grams() + + async def stop(self) -> None: + await self.io.stop() + + def serialize(self) -> dict: + return {**super().serialize(), "port": self.io.port} + + # === Device discovery === + + async def _query_mt_sics_levels(self) -> Set[int]: + """Query supported MT-SICS levels via I1 command (Level 0 - always available). + + Returns a set of integers representing the supported levels (e.g. {0, 1, 2, 3}). + """ + response = await self.send_command("I1") + # I1 A "0123" "2.00" "2.20" "1.00" "1.50" + self._validate_response(response, 3, "I1") + level_string = response[2].replace('"', "") + return {int(c) for c in level_string} + + # === Response parsing === + + @staticmethod + def _validate_response(response: List[str], min_length: int, command: str) -> None: + """Validate that a parsed response has the expected minimum number of fields. + + Raises: + MettlerToledoError: if the response is too short. + """ + if len(response) < min_length: + raise MettlerToledoError( + title="Unexpected response", + message=f"Expected at least {min_length} fields for '{command}', " + f"got {len(response)}: {' '.join(response)}", + ) + + @staticmethod + def _validate_unit(unit: str, command: str) -> None: + """Validate that the unit in a response is grams. + + Raises: + MettlerToledoError: if the unit is not 'g'. + """ + if unit != "g": + raise MettlerToledoError( + title="Unexpected unit", + message=f"Expected 'g' for '{command}', got '{unit}'", + ) + + def _parse_basic_errors(self, response: List[str]) -> None: + """Helper function for parsing basic errors that are common to many commands. If an error is + detected, a 'MettlerToledoError' exception is raised. + + These are in the first place of the response: + - ES: syntax error: The weigh module/balance has not recognized the received command or the + command is not allowed + - ET: transmission error: The weigh module/balance has received a "faulty" command, e.g. owing + to a parity error or interface break + - EL: logical error: The weigh module/balance can not execute the received command + + These are in the second place of the response (MT-SICS spec p.10, sec 2.1.3.1): + - A: Command executed successfully + - B: Command not yet terminated, additional responses following + - I: Internal error (e.g. balance not ready yet) + - L: Logical error (e.g. parameter not allowed) + - +: Balance in overload range + - -: Balance in underload range + + TODO: handle 'B' status - multi-response commands (e.g. C1 adjustment) send 'B' first, + then additional responses, then 'A' on completion. Currently send_command returns after + the first response, so 'B' responses are not followed up. + """ + + if len(response) == 0: + raise MettlerToledoError( + title="Empty response", + message="Received empty response from scale", + ) + + # General error messages are single-token: ES, ET, EL + if response[0] == "ES": + raise MettlerToledoError.syntax_error() + if response[0] == "ET": + raise MettlerToledoError.transmission_error() + if response[0] == "EL": + raise MettlerToledoError.logical_error() + + if len(response) < 2: + raise MettlerToledoError( + title="Unexpected response", + message=f"Expected at least 2 fields, got: {' '.join(response)}", + ) + + if response[1] == "I": + raise MettlerToledoError.executing_another_command() + if response[1] == "L": + raise MettlerToledoError.incorrect_parameter() + if response[1] == "+": + raise MettlerToledoError.overload() + if response[1] == "-": + raise MettlerToledoError.underload() + + if len(response) >= 4 and response[0] == "S" and response[1] == "S" and response[2] == "Error": + error_code = response[3] + code, source = error_code[:-1], error_code[-1] + from_terminal = source == "t" + if code == "1": + raise MettlerToledoError.boot_error(from_terminal=from_terminal) + if code == "2": + raise MettlerToledoError.brand_error(from_terminal=from_terminal) + if code == "3": + raise MettlerToledoError.checksum_error(from_terminal=from_terminal) + if code == "9": + raise MettlerToledoError.option_fail(from_terminal=from_terminal) + if code == "10": + raise MettlerToledoError.eeprom_error(from_terminal=from_terminal) + if code == "11": + raise MettlerToledoError.device_mismatch(from_terminal=from_terminal) + if code == "12": + raise MettlerToledoError.hot_plug_out(from_terminal=from_terminal) + if code == "14": + raise MettlerToledoError.weight_module_electronic_mismatch(from_terminal=from_terminal) + if code == "15": + raise MettlerToledoError.adjustment_needed(from_terminal=from_terminal) + + # === Command Layer === + + async def send_command(self, command: str, timeout: int = 60) -> MettlerToledoResponse: + """Send a command to the scale and receive the response. + + Args: + timeout: The timeout in seconds. + """ + + await self.io.write(command.encode() + b"\r\n") + + timeout_time = time.time() + timeout + while True: + raw_response = await self.io.readline() + if raw_response != b"": + break + if time.time() > timeout_time: + raise TimeoutError("Timeout while waiting for response from scale.") + await asyncio.sleep(0.001) + logger.debug("[scale] Received response: %s", raw_response) + response = raw_response.decode("utf-8").strip().split() + + # parse basic errors + self._parse_basic_errors(response) + + # mypy doesn't understand this + return response # type: ignore + + async def _drain_followup_responses(self, command: str, timeout: float = 10) -> None: + """Read and discard follow-up responses from multi-response commands. + + Multi-response commands (B status) send additional lines after the first response. + This method reads lines until it sees status A (final) or times out. + """ + timeout_time = time.time() + timeout + while True: + raw_followup = await self.io.readline() + if raw_followup != b"": + followup = raw_followup.decode("utf-8").strip().split() + logger.debug("[scale] %s followup: %s", command, raw_followup) + if len(followup) >= 2 and followup[1] == "A": + break + if time.time() > timeout_time: + logger.warning("[scale] Timeout waiting for %s followup", command) + break + await asyncio.sleep(0.001) + + # === Public high-level API === + + # # Cancel commands # # + + async def cancel(self) -> str: + """@ - Reset the device to a determined state (spec Section 2.2). + + Equivalent to a power cycle: empties volatile memories, cancels all pending + commands, resets key control to default. Tare memory is NOT reset. + The cancel command is always executed, even when the device is busy. + + Returns the serial number from the I4-style response. + """ + await self.io.reset_input_buffer() + response = await self.send_command("@") + # @ responds with I4-style: I4 A "" + self._validate_response(response, 3, "@") + return response[2].replace('"', "") + + async def cancel_all(self) -> None: + """C - Cancel all active and pending interface commands. + + Unlike cancel() (@), this does not reset the device - it only cancels + commands that were requested via this interface. Typically used to stop + repeating commands (SIR, SR) or abort adjustment procedures. + + This is a multi-response command: the device sends C B (started) then + C A (complete). Both responses are consumed to keep the serial buffer clean. + """ + response = await self.send_command("C") + # First response: C B (cancel started) + self._validate_response(response, 2, "C") + if response[1] == "E": + raise MettlerToledoError( + title="Error while canceling", + message=f"C command returned error: {response}", + ) + + # Second response: C A (cancel complete) + await self._drain_followup_responses("C") + + # # Identification commands # # + + async def request_serial_number(self) -> str: + """Get the serial number of the scale. (I4 command)""" + response = await self.send_command("I4") + self._validate_response(response, 3, "I4") + return response[2].replace('"', "") + + async def request_device_type(self) -> str: + """Query the device type string. (I2 command)""" + response = await self.send_command("I2") + # After split(): ["I2", "A", '"WXS205SDU"', "220.0000", "g"] + self._validate_response(response, 5, "I2") + return response[2].replace('"', "") + + async def request_capacity(self) -> float: + """Query the maximum weighing capacity in grams. (I2 command)""" + response = await self.send_command("I2") + # After split(): ["I2", "A", '"WXS205SDU"', "220.0000", "g"] + self._validate_response(response, 5, "I2") + self._validate_unit(response[4], "I2") + return float(response[3]) + + @requires_mt_sics_level(2) + async def request_remaining_weighing_range(self) -> float: + """Query remaining maximum weighing range in grams. (I50 command) + + Returns the remaining capacity accounting for all loads currently on the + weighing platform (pre-load, tare, net load). A negative value means the + maximum weighing range has been exceeded. + + I50 is a multi-response command: the device sends up to 3 lines + (RangeNo 0 with B, RangeNo 1 with B, RangeNo 2 with A). We extract the + value from the first response and drain the remaining ones. + """ + response = await self.send_command("I50") + # First response line: I50 B 0 (RangeNo 0 = max weighing range) + # After split(): ["I50", "B", "0", "535.141", "g"] + self._validate_response(response, 5, "I50") + self._validate_unit(response[4], "I50") + remaining = float(response[3]) + + # Drain follow-up responses (RangeNo 1 and 2) to keep the serial buffer clean + await self._drain_followup_responses("I50") + + return remaining + + # # Zero commands # # + + async def zero_immediately(self) -> MettlerToledoResponse: + """Zero the scale immediately. (ACTION command)""" + return await self.send_command("ZI") + + async def zero_stable(self) -> MettlerToledoResponse: + """Zero the scale when the weight is stable. (ACTION command)""" + return await self.send_command("Z") + + async def zero_timeout(self, timeout: float) -> MettlerToledoResponse: + """Zero the scale after a given timeout. (ACTION command)""" + # For some reason, this will always return a syntax error (ES), even though it should be allowed + # according to the docs. + timeout = int(timeout * 1000) + return await self.send_command(f"ZC {timeout}") + + async def zero( + self, timeout: Union[Literal["stable"], float, int] = "stable" + ) -> MettlerToledoResponse: + """High level function to zero the scale. (ACTION command) + + Args: + timeout: The timeout in seconds. If "stable", the scale will zero when the weight is stable. + If 0, the scale will zero immediately. If a float/int, the scale will zero after the given + timeout (in seconds). + """ + + if timeout == "stable": + return await self.zero_stable() + + if not isinstance(timeout, (float, int)): + raise TypeError("timeout must be a float or 'stable'") + + if timeout < 0: + raise ValueError("timeout must be greater than or equal to 0") + + if timeout == 0: + return await self.zero_immediately() + + return await self.zero_timeout(timeout) + + # # Tare commands # # + + async def tare_stable(self) -> MettlerToledoResponse: + """Tare the scale when the weight is stable. (ACTION command)""" + return await self.send_command("T") + + async def tare_immediately(self) -> MettlerToledoResponse: + """Tare the scale immediately. (ACTION command)""" + return await self.send_command("TI") + + async def tare_timeout(self, timeout: float) -> MettlerToledoResponse: + """Tare the scale after a given timeout. (ACTION command)""" + # For some reason, this will always return a syntax error (ES), even though it should be allowed + # according to the docs. + timeout = int(timeout * 1000) # convert to milliseconds + return await self.send_command(f"TC {timeout}") + + async def tare( + self, timeout: Union[Literal["stable"], float, int] = "stable" + ) -> MettlerToledoResponse: + """High level function to tare the scale. (ACTION command) + + Args: + timeout: The timeout in seconds. If "stable", the scale will tare when the weight is stable. + If 0, the scale will tare immediately. If a float/int, the scale will tare after the given + timeout (in seconds). + """ + + if timeout == "stable": + # "Use T to tare the balance. The next stable weight value will be saved in the tare memory." + return await self.tare_stable() + + if not isinstance(timeout, (float, int)): + raise TypeError("timeout must be a float or 'stable'") + + if timeout < 0: + raise ValueError("timeout must be greater than or equal to 0") + + if timeout == 0: + return await self.tare_immediately() + return await self.tare_timeout(timeout) + + # # Weight reading commands # # + + async def request_tare_weight(self) -> float: + """Request tare weight value from scale's memory. (MEM-READ command) + "Use TA to query the current tare value or preset a known tare value." + """ + + response = await self.send_command("TA") + self._validate_response(response, 4, "TA") + self._validate_unit(response[3], "TA") + return float(response[2]) + + async def clear_tare(self) -> MettlerToledoResponse: + """TAC - Clear tare weight value (MEM-WRITE command)""" + return await self.send_command("TAC") + + async def read_stable_weight(self) -> float: + """Read a stable weight value from the scale. (MEASUREMENT command) + + from the docs: + + "Use S to send a stable weight value, along with the host unit, from the balance to + the connected communication partner via the interface. If the automatic door function + is enabled and a stable weight is requested the balance will open and close the balance's + doors to achieve a stable weight." + """ + + response = await self.send_command("S") + self._validate_response(response, 4, "S") + self._validate_unit(response[3], "S") + return float(response[2]) + + async def read_dynamic_weight(self, timeout: float) -> float: + """Read a stable weight value from the machine within a given timeout, or + return the current weight value if not possible. (MEASUREMENT command) + + Args: + timeout: The timeout in seconds. + """ + + timeout = int(timeout * 1000) # convert to milliseconds + + response = await self.send_command(f"SC {timeout}") + self._validate_response(response, 4, "SC") + self._validate_unit(response[3], "SC") + return float(response[2]) + + async def read_weight_value_immediately(self) -> float: + """Read a weight value immediately from the scale. (MEASUREMENT command) + + "Use SI to immediately send the current weight value, along with the host unit, from the + balance to the connected communication partner via the interface." + """ + + response = await self.send_command("SI") + self._validate_response(response, 4, "SI") + self._validate_unit(response[3], "SI") + return float(response[2]) + + async def read_weight(self, timeout: Union[Literal["stable"], float, int] = "stable") -> float: + """High level function to read a weight value from the scale. (MEASUREMENT command) + + Args: + timeout: The timeout in seconds. If "stable", the scale will return a weight value when the + weight is stable. If 0, the scale will return a weight value immediately. If a float/int, + the scale will return a weight value after the given timeout (in seconds). + """ + + if timeout == "stable": + return await self.read_stable_weight() + + if not isinstance(timeout, (float, int)): + raise TypeError("timeout must be a float or 'stable'") + + if timeout < 0: + raise ValueError("timeout must be greater than or equal to 0") + + if timeout == 0: + return await self.read_weight_value_immediately() + + return await self.read_dynamic_weight(timeout) + + # Commands for (optional) display manipulation + + async def set_display_text(self, text: str) -> MettlerToledoResponse: + """Set the display text of the scale. Return to the normal weight display with + self.set_weight_display().""" + return await self.send_command(f'D "{text}"') + + async def set_weight_display(self) -> MettlerToledoResponse: + """Return the display to the normal weight display.""" + return await self.send_command("DW") + + # # Configuration commands # # + + @requires_mt_sics_level(2) + async def set_host_unit_grams(self) -> MettlerToledoResponse: + """Set the host output unit to grams. (M21 command)""" + return await self.send_command("M21 0 0") + + # # # Deprecated alias with warning # # # + + # TODO: remove after 2026-03 + + async def get_serial_number(self) -> str: + """Deprecated: Use request_serial_number() instead.""" + warnings.warn( + "get_serial_number() is deprecated and will be removed in 2026-03. " + "Use request_serial_number() instead.", + DeprecationWarning, + stacklevel=2, + ) + return await self.request_serial_number() + + async def get_tare_weight(self) -> float: + """Deprecated: Use request_tare_weight() instead.""" + warnings.warn( + "get_tare_weight() is deprecated and will be removed in 2026-03. " + "Use request_tare_weight() instead.", + DeprecationWarning, + stacklevel=2, + ) + return await self.request_tare_weight() + + async def get_stable_weight(self) -> float: + """Deprecated: Use read_stable_weight() instead.""" + warnings.warn( + "get_stable_weight() is deprecated and will be removed in 2026-03. " + "Use read_stable_weight() instead.", + DeprecationWarning, + stacklevel=2, + ) + return await self.read_stable_weight() + + async def get_dynamic_weight(self, timeout: float) -> float: + """Deprecated: Use read_dynamic_weight() instead.""" + warnings.warn( + "get_dynamic_weight() is deprecated and will be removed in 2026-03. " + "Use read_dynamic_weight() instead.", + DeprecationWarning, + stacklevel=2, + ) + return await self.read_dynamic_weight(timeout) + + async def get_weight_value_immediately(self) -> float: + """Deprecated: Use read_weight_value_immediately() instead.""" + warnings.warn( + "get_weight_value_immediately() is deprecated and will be removed in 2026-03. " + "Use read_weight_value_immediately() instead.", + DeprecationWarning, + stacklevel=2, + ) + return await self.read_weight_value_immediately() + + async def get_weight(self, timeout: Union[Literal["stable"], float, int] = "stable") -> float: + """Deprecated: Use read_weight() instead.""" + warnings.warn( + "get_weight() is deprecated and will be removed in 2026-03. Use read_weight() instead.", + DeprecationWarning, + stacklevel=2, + ) + return await self.read_weight(timeout) diff --git a/pylabrobot/scales/mettler_toledo/backend_tests.py b/pylabrobot/scales/mettler_toledo/backend_tests.py new file mode 100644 index 00000000000..bbad21a53d1 --- /dev/null +++ b/pylabrobot/scales/mettler_toledo/backend_tests.py @@ -0,0 +1,75 @@ +"""Tests for MT-SICS response parsing and validation.""" + +import unittest + +from pylabrobot.scales.mettler_toledo.backend import MettlerToledoWXS205SDUBackend +from pylabrobot.scales.mettler_toledo.errors import MettlerToledoError + + +class MTSICSResponseParsingTests(unittest.TestCase): + """Tests for MT-SICS response parsing - no hardware needed.""" + + def setUp(self): + self.backend = MettlerToledoWXS205SDUBackend.__new__(MettlerToledoWXS205SDUBackend) + + def test_parse_errors_ES_ET_EL(self): + with self.assertRaises(MettlerToledoError) as ctx: + self.backend._parse_basic_errors(["ES"]) + self.assertIn("Syntax error", str(ctx.exception)) + + with self.assertRaises(MettlerToledoError) as ctx: + self.backend._parse_basic_errors(["ET"]) + self.assertIn("Transmission error", str(ctx.exception)) + + with self.assertRaises(MettlerToledoError) as ctx: + self.backend._parse_basic_errors(["EL"]) + self.assertIn("Logical error", str(ctx.exception)) + + def test_parse_errors_status_codes(self): + with self.assertRaises(MettlerToledoError) as ctx: + self.backend._parse_basic_errors(["S", "I"]) + self.assertIn("not executable at present", str(ctx.exception)) + + with self.assertRaises(MettlerToledoError) as ctx: + self.backend._parse_basic_errors(["S", "L"]) + self.assertIn("incorrect parameter", str(ctx.exception)) + + with self.assertRaises(MettlerToledoError) as ctx: + self.backend._parse_basic_errors(["S", "+"]) + self.assertIn("overload", str(ctx.exception)) + + with self.assertRaises(MettlerToledoError) as ctx: + self.backend._parse_basic_errors(["S", "-"]) + self.assertIn("underload", str(ctx.exception)) + + def test_validate_response_rejects_short(self): + with self.assertRaises(MettlerToledoError): + MettlerToledoWXS205SDUBackend._validate_response(["I4", "A"], 3, "I4") + + # should not raise + MettlerToledoWXS205SDUBackend._validate_response(["I4", "A", '"B207696838"'], 3, "I4") + + def test_validate_unit_rejects_wrong(self): + with self.assertRaises(MettlerToledoError): + MettlerToledoWXS205SDUBackend._validate_unit("kg", "S") + + # should not raise + MettlerToledoWXS205SDUBackend._validate_unit("g", "S") + + def test_parse_errors_handles_edge_cases(self): + # empty response + with self.assertRaises(MettlerToledoError) as ctx: + self.backend._parse_basic_errors([]) + self.assertIn("Empty response", str(ctx.exception)) + + # single non-error token + with self.assertRaises(MettlerToledoError) as ctx: + self.backend._parse_basic_errors(["Z"]) + self.assertIn("Expected at least 2 fields", str(ctx.exception)) + + # valid success - should not raise + self.backend._parse_basic_errors(["Z", "A"]) + + +if __name__ == "__main__": + unittest.main() diff --git a/pylabrobot/scales/mettler_toledo_sics_errors.py b/pylabrobot/scales/mettler_toledo/errors.py similarity index 100% rename from pylabrobot/scales/mettler_toledo_sics_errors.py rename to pylabrobot/scales/mettler_toledo/errors.py diff --git a/pylabrobot/scales/mt_sics_commands.md b/pylabrobot/scales/mettler_toledo/mt_sics_commands.md similarity index 98% rename from pylabrobot/scales/mt_sics_commands.md rename to pylabrobot/scales/mettler_toledo/mt_sics_commands.md index 4d1d3dc5db9..2d374d17276 100644 --- a/pylabrobot/scales/mt_sics_commands.md +++ b/pylabrobot/scales/mettler_toledo/mt_sics_commands.md @@ -16,7 +16,7 @@ Status key: | Command | Description | Spec Page | Status | Notes | |---------|------------------------------------------|-----------|--------|-------| -| @ | Cancel / reset to determined state | 16 | HIGH | Spec recommends sending on connect (Section 2.2). Response is I4-style. | +| @ | Cancel / reset to determined state | 16 | DONE | cancel(). Sent during setup(). Response is I4-style. | | I0 | List all implemented commands + levels | 96 | MED | Useful for runtime capability discovery. Multi-response (B status). | | I1 | MT-SICS level and level versions | 97 | DONE | Queried during setup(). | | I2 | Device data (type and capacity) | 98 | DONE | Split into request_device_type() and request_capacity(). | @@ -34,7 +34,7 @@ Status key: | Command | Description | Spec Page | Status | Notes | |---------|------------------------------------------|-----------|--------|-------| -| C | Cancel all pending commands | 23 | HIGH | Like @ but doesn't reset state. | +| C | Cancel all pending commands | 23 | DONE | cancel_all(). Multi-response (B then A). | | D | Write text to display | 52 | DONE | set_display_text(). | | DW | Show weight on display | 61 | DONE | set_weight_display(). | | K | Keys control | 153 | LOW | Lock/unlock terminal keys. | @@ -255,8 +255,6 @@ Status key: ## Priority Summary ### HIGH (should implement next) -- @ (cancel) - spec-recommended for setup -- C (cancel all) - Level 1 - E01/E02/E03 (error monitoring) - Level 2 - SIX1 (gross, net, tare in one call) - Level 2 diff --git a/pylabrobot/scales/mettler_toledo_backend.py b/pylabrobot/scales/mettler_toledo_backend.py index ffced5559cf..82847c8a478 100644 --- a/pylabrobot/scales/mettler_toledo_backend.py +++ b/pylabrobot/scales/mettler_toledo_backend.py @@ -1,629 +1,4 @@ -"""Mettler Toledo scale backend using the MT-SICS (Mettler Toledo Standard Interface Command Set) serial protocol.""" +"""Backwards-compatible import shim. Use pylabrobot.scales.mettler_toledo instead.""" -# similar library: https://github.com/janelia-pypi/mettler_toledo_device_python - -import asyncio -import functools -import logging -import time -import warnings -from typing import Any, Callable, List, Literal, Optional, Set, TypeVar, Union - -from pylabrobot.io.serial import Serial -from pylabrobot.scales.mettler_toledo_sics_errors import MettlerToledoError -from pylabrobot.scales.scale_backend import ScaleBackend - -logger = logging.getLogger("pylabrobot") - -MettlerToledoResponse = List[str] - - -F = TypeVar("F", bound=Callable[..., Any]) - - -def requires_mt_sics_level(level: int) -> Callable[[F], F]: - """Decorator that gates a method on the connected device supporting the required MT-SICS level. - - During setup(), the backend queries I1 to discover which levels the connected device supports. - Methods decorated with a level higher than what the device reports will raise MettlerToledoError. - See the class docstring of MTSICSBackend for level descriptions. - """ - - def decorator(func: F) -> F: - func._mt_sics_level = level # type: ignore[attr-defined] - - @functools.wraps(func) - async def wrapper(self: Any, *args: Any, **kwargs: Any) -> Any: - if hasattr(self, "_mt_sics_levels") and self._mt_sics_levels is not None: - if level not in self._mt_sics_levels: - raise MettlerToledoError( - title="Command not supported", - message=f"'{func.__name__}' requires MT-SICS level {level}, " - f"but device supports levels: {sorted(self._mt_sics_levels)}", - ) - return await func(self, *args, **kwargs) - - return wrapper # type: ignore[return-value] - - return decorator - - -class MTSICSBackend(ScaleBackend): - """Backend for Mettler Toledo scales using the MT-SICS protocol. - - MT-SICS (Mettler Toledo Standard Interface Command Set) is the serial communication - protocol used by Mettler Toledo's Automated Precision Weigh Modules. This backend is - compatible with any MT-SICS device, including the WXS, WMS, and WX series. During - setup(), this backend queries the device to discover its identity, capacity, and - supported MT-SICS levels. - - MT-SICS levels: - - Level 0: Basic set - identification (I0-I4), basic weighing (S, SI), zero (Z, ZI), - tare (T, TI), cancel (@). Always available on every MT-SICS device. - - Level 1: Elementary commands - display (D, DW), tare memory (TA, TAC), timed - weighing (SC), timed zero/tare (ZC, TC). Always available. - - Level 2: Extended command list - configuration (M21, COM), device info (I50, I47, - I48). Model-dependent, not guaranteed on every device. - - Level 3: Application-specific command set. Model-dependent. - - Methods requiring Level 2+ are decorated with ``@requires_mt_sics_level`` and will - raise ``MettlerToledoError`` if the connected device does not support the required level. - - Tested on the WXS205SDU (used by Hamilton in the Liquid Verification Kit). - - Spec: https://web.archive.org/web/20240208213802/https://www.mt.com/dam/ - product_organizations/industry/apw/generic/11781363_N_MAN_RM_MT-SICS_APW_en.pdf - - From the spec (Section 2.2): - "If several commands are sent in succession without waiting for the corresponding - responses, it is possible that the weigh module/balance confuses the sequence of - command processing or ignores entire commands." - """ - - # === Constructor === - - def __init__(self, port: Optional[str] = None, vid: int = 0x0403, pid: int = 0x6001): - super().__init__() - - self.io = Serial( - human_readable_device_name="Mettler Toledo Scale", - port=port, - vid=vid, - pid=pid, - baudrate=9600, - timeout=1, - ) - - async def setup(self) -> None: - await self.io.setup() - - # Reset device to clean state (spec Section 2.2) - # cancel() clears the input buffer and sends @, which returns the serial number - self.serial_number = await self.cancel() - - # Device discovery (Level 0 - always available) - self._mt_sics_levels: Set[int] = await self._query_mt_sics_levels() - self.device_type = await self.request_device_type() - self.capacity = await self.request_capacity() - - logger.info( - "[scale] Connected: %s (S/N: %s, capacity: %.1f g, MT-SICS levels: %s)", - self.device_type, - self.serial_number, - self.capacity, - sorted(self._mt_sics_levels), - ) - - # Set output unit to grams - if 2 in self._mt_sics_levels: - await self.set_host_unit_grams() - - async def stop(self) -> None: - await self.io.stop() - - def serialize(self) -> dict: - return {**super().serialize(), "port": self.io.port} - - # === Device discovery === - - async def _query_mt_sics_levels(self) -> Set[int]: - """Query supported MT-SICS levels via I1 command (Level 0 - always available). - - Returns a set of integers representing the supported levels (e.g. {0, 1, 2, 3}). - """ - response = await self.send_command("I1") - # I1 A "0123" "2.00" "2.20" "1.00" "1.50" - self._validate_response(response, 3, "I1") - level_string = response[2].replace('"', "") - return {int(c) for c in level_string} - - # === Response parsing === - - @staticmethod - def _validate_response(response: List[str], min_length: int, command: str) -> None: - """Validate that a parsed response has the expected minimum number of fields. - - Raises: - MettlerToledoError: if the response is too short. - """ - if len(response) < min_length: - raise MettlerToledoError( - title="Unexpected response", - message=f"Expected at least {min_length} fields for '{command}', " - f"got {len(response)}: {' '.join(response)}", - ) - - @staticmethod - def _validate_unit(unit: str, command: str) -> None: - """Validate that the unit in a response is grams. - - Raises: - MettlerToledoError: if the unit is not 'g'. - """ - if unit != "g": - raise MettlerToledoError( - title="Unexpected unit", - message=f"Expected 'g' for '{command}', got '{unit}'", - ) - - def _parse_basic_errors(self, response: List[str]) -> None: - """Helper function for parsing basic errors that are common to many commands. If an error is - detected, a 'MettlerToledoError' exception is raised. - - These are in the first place of the response: - - ES: syntax error: The weigh module/balance has not recognized the received command or the - command is not allowed - - ET: transmission error: The weigh module/balance has received a "faulty" command, e.g. owing - to a parity error or interface break - - EL: logical error: The weigh module/balance can not execute the received command - - These are in the second place of the response (MT-SICS spec p.10, sec 2.1.3.1): - - A: Command executed successfully - - B: Command not yet terminated, additional responses following - - I: Internal error (e.g. balance not ready yet) - - L: Logical error (e.g. parameter not allowed) - - +: Balance in overload range - - -: Balance in underload range - - TODO: handle 'B' status - multi-response commands (e.g. C1 adjustment) send 'B' first, - then additional responses, then 'A' on completion. Currently send_command returns after - the first response, so 'B' responses are not followed up. - """ - - if len(response) == 0: - raise MettlerToledoError( - title="Empty response", - message="Received empty response from scale", - ) - - # General error messages are single-token: ES, ET, EL - if response[0] == "ES": - raise MettlerToledoError.syntax_error() - if response[0] == "ET": - raise MettlerToledoError.transmission_error() - if response[0] == "EL": - raise MettlerToledoError.logical_error() - - if len(response) < 2: - raise MettlerToledoError( - title="Unexpected response", - message=f"Expected at least 2 fields, got: {' '.join(response)}", - ) - - if response[1] == "I": - raise MettlerToledoError.executing_another_command() - if response[1] == "L": - raise MettlerToledoError.incorrect_parameter() - if response[1] == "+": - raise MettlerToledoError.overload() - if response[1] == "-": - raise MettlerToledoError.underload() - - if len(response) >= 4 and response[0] == "S" and response[1] == "S" and response[2] == "Error": - error_code = response[3] - code, source = error_code[:-1], error_code[-1] - from_terminal = source == "t" - if code == "1": - raise MettlerToledoError.boot_error(from_terminal=from_terminal) - if code == "2": - raise MettlerToledoError.brand_error(from_terminal=from_terminal) - if code == "3": - raise MettlerToledoError.checksum_error(from_terminal=from_terminal) - if code == "9": - raise MettlerToledoError.option_fail(from_terminal=from_terminal) - if code == "10": - raise MettlerToledoError.eeprom_error(from_terminal=from_terminal) - if code == "11": - raise MettlerToledoError.device_mismatch(from_terminal=from_terminal) - if code == "12": - raise MettlerToledoError.hot_plug_out(from_terminal=from_terminal) - if code == "14": - raise MettlerToledoError.weight_module_electronic_mismatch(from_terminal=from_terminal) - if code == "15": - raise MettlerToledoError.adjustment_needed(from_terminal=from_terminal) - - # === Command Layer === - - async def send_command(self, command: str, timeout: int = 60) -> MettlerToledoResponse: - """Send a command to the scale and receive the response. - - Args: - timeout: The timeout in seconds. - """ - - await self.io.write(command.encode() + b"\r\n") - - timeout_time = time.time() + timeout - while True: - raw_response = await self.io.readline() - if raw_response != b"": - break - if time.time() > timeout_time: - raise TimeoutError("Timeout while waiting for response from scale.") - await asyncio.sleep(0.001) - logger.debug("[scale] Received response: %s", raw_response) - response = raw_response.decode("utf-8").strip().split() - - # parse basic errors - self._parse_basic_errors(response) - - # mypy doesn't understand this - return response # type: ignore - - async def _drain_followup_responses(self, command: str, timeout: float = 10) -> None: - """Read and discard follow-up responses from multi-response commands. - - Multi-response commands (B status) send additional lines after the first response. - This method reads lines until it sees status A (final) or times out. - """ - timeout_time = time.time() + timeout - while True: - raw_followup = await self.io.readline() - if raw_followup != b"": - followup = raw_followup.decode("utf-8").strip().split() - logger.debug("[scale] %s followup: %s", command, raw_followup) - if len(followup) >= 2 and followup[1] == "A": - break - if time.time() > timeout_time: - logger.warning("[scale] Timeout waiting for %s followup", command) - break - await asyncio.sleep(0.001) - - # === Public high-level API === - - # # Cancel commands # # - - async def cancel(self) -> str: - """@ - Reset the device to a determined state (spec Section 2.2). - - Equivalent to a power cycle: empties volatile memories, cancels all pending - commands, resets key control to default. Tare memory is NOT reset. - The cancel command is always executed, even when the device is busy. - - Returns the serial number from the I4-style response. - """ - await self.io.reset_input_buffer() - response = await self.send_command("@") - # @ responds with I4-style: I4 A "" - self._validate_response(response, 3, "@") - return response[2].replace('"', "") - - async def cancel_all(self) -> None: - """C - Cancel all active and pending interface commands. - - Unlike cancel() (@), this does not reset the device - it only cancels - commands that were requested via this interface. Typically used to stop - repeating commands (SIR, SR) or abort adjustment procedures. - - This is a multi-response command: the device sends C B (started) then - C A (complete). Both responses are consumed to keep the serial buffer clean. - """ - response = await self.send_command("C") - # First response: C B (cancel started) - self._validate_response(response, 2, "C") - if response[1] == "E": - raise MettlerToledoError( - title="Error while canceling", - message=f"C command returned error: {response}", - ) - - # Second response: C A (cancel complete) - await self._drain_followup_responses("C") - - # # Identification commands # # - - async def request_serial_number(self) -> str: - """Get the serial number of the scale. (I4 command)""" - response = await self.send_command("I4") - self._validate_response(response, 3, "I4") - return response[2].replace('"', "") - - async def request_device_type(self) -> str: - """Query the device type string. (I2 command)""" - response = await self.send_command("I2") - # After split(): ["I2", "A", '"WXS205SDU"', "220.0000", "g"] - self._validate_response(response, 5, "I2") - return response[2].replace('"', "") - - async def request_capacity(self) -> float: - """Query the maximum weighing capacity in grams. (I2 command)""" - response = await self.send_command("I2") - # After split(): ["I2", "A", '"WXS205SDU"', "220.0000", "g"] - self._validate_response(response, 5, "I2") - self._validate_unit(response[4], "I2") - return float(response[3]) - - @requires_mt_sics_level(2) - async def request_remaining_weighing_range(self) -> float: - """Query remaining maximum weighing range in grams. (I50 command) - - Returns the remaining capacity accounting for all loads currently on the - weighing platform (pre-load, tare, net load). A negative value means the - maximum weighing range has been exceeded. - - I50 is a multi-response command: the device sends up to 3 lines - (RangeNo 0 with B, RangeNo 1 with B, RangeNo 2 with A). We extract the - value from the first response and drain the remaining ones. - """ - response = await self.send_command("I50") - # First response line: I50 B 0 (RangeNo 0 = max weighing range) - # After split(): ["I50", "B", "0", "535.141", "g"] - self._validate_response(response, 5, "I50") - self._validate_unit(response[4], "I50") - remaining = float(response[3]) - - # Drain follow-up responses (RangeNo 1 and 2) to keep the serial buffer clean - await self._drain_followup_responses("I50") - - return remaining - - # # Zero commands # # - - async def zero_immediately(self) -> MettlerToledoResponse: - """Zero the scale immediately. (ACTION command)""" - return await self.send_command("ZI") - - async def zero_stable(self) -> MettlerToledoResponse: - """Zero the scale when the weight is stable. (ACTION command)""" - return await self.send_command("Z") - - async def zero_timeout(self, timeout: float) -> MettlerToledoResponse: - """Zero the scale after a given timeout. (ACTION command)""" - # For some reason, this will always return a syntax error (ES), even though it should be allowed - # according to the docs. - timeout = int(timeout * 1000) - return await self.send_command(f"ZC {timeout}") - - async def zero( - self, timeout: Union[Literal["stable"], float, int] = "stable" - ) -> MettlerToledoResponse: - """High level function to zero the scale. (ACTION command) - - Args: - timeout: The timeout in seconds. If "stable", the scale will zero when the weight is stable. - If 0, the scale will zero immediately. If a float/int, the scale will zero after the given - timeout (in seconds). - """ - - if timeout == "stable": - return await self.zero_stable() - - if not isinstance(timeout, (float, int)): - raise TypeError("timeout must be a float or 'stable'") - - if timeout < 0: - raise ValueError("timeout must be greater than or equal to 0") - - if timeout == 0: - return await self.zero_immediately() - - return await self.zero_timeout(timeout) - - # # Tare commands # # - - async def tare_stable(self) -> MettlerToledoResponse: - """Tare the scale when the weight is stable. (ACTION command)""" - return await self.send_command("T") - - async def tare_immediately(self) -> MettlerToledoResponse: - """Tare the scale immediately. (ACTION command)""" - return await self.send_command("TI") - - async def tare_timeout(self, timeout: float) -> MettlerToledoResponse: - """Tare the scale after a given timeout. (ACTION command)""" - # For some reason, this will always return a syntax error (ES), even though it should be allowed - # according to the docs. - timeout = int(timeout * 1000) # convert to milliseconds - return await self.send_command(f"TC {timeout}") - - async def tare( - self, timeout: Union[Literal["stable"], float, int] = "stable" - ) -> MettlerToledoResponse: - """High level function to tare the scale. (ACTION command) - - Args: - timeout: The timeout in seconds. If "stable", the scale will tare when the weight is stable. - If 0, the scale will tare immediately. If a float/int, the scale will tare after the given - timeout (in seconds). - """ - - if timeout == "stable": - # "Use T to tare the balance. The next stable weight value will be saved in the tare memory." - return await self.tare_stable() - - if not isinstance(timeout, (float, int)): - raise TypeError("timeout must be a float or 'stable'") - - if timeout < 0: - raise ValueError("timeout must be greater than or equal to 0") - - if timeout == 0: - return await self.tare_immediately() - return await self.tare_timeout(timeout) - - # # Weight reading commands # # - - async def request_tare_weight(self) -> float: - """Request tare weight value from scale's memory. (MEM-READ command) - "Use TA to query the current tare value or preset a known tare value." - """ - - response = await self.send_command("TA") - self._validate_response(response, 4, "TA") - self._validate_unit(response[3], "TA") - return float(response[2]) - - async def clear_tare(self) -> MettlerToledoResponse: - """TAC - Clear tare weight value (MEM-WRITE command)""" - return await self.send_command("TAC") - - async def read_stable_weight(self) -> float: - """Read a stable weight value from the scale. (MEASUREMENT command) - - from the docs: - - "Use S to send a stable weight value, along with the host unit, from the balance to - the connected communication partner via the interface. If the automatic door function - is enabled and a stable weight is requested the balance will open and close the balance's - doors to achieve a stable weight." - """ - - response = await self.send_command("S") - self._validate_response(response, 4, "S") - self._validate_unit(response[3], "S") - return float(response[2]) - - async def read_dynamic_weight(self, timeout: float) -> float: - """Read a stable weight value from the machine within a given timeout, or - return the current weight value if not possible. (MEASUREMENT command) - - Args: - timeout: The timeout in seconds. - """ - - timeout = int(timeout * 1000) # convert to milliseconds - - response = await self.send_command(f"SC {timeout}") - self._validate_response(response, 4, "SC") - self._validate_unit(response[3], "SC") - return float(response[2]) - - async def read_weight_value_immediately(self) -> float: - """Read a weight value immediately from the scale. (MEASUREMENT command) - - "Use SI to immediately send the current weight value, along with the host unit, from the - balance to the connected communication partner via the interface." - """ - - response = await self.send_command("SI") - self._validate_response(response, 4, "SI") - self._validate_unit(response[3], "SI") - return float(response[2]) - - async def read_weight(self, timeout: Union[Literal["stable"], float, int] = "stable") -> float: - """High level function to read a weight value from the scale. (MEASUREMENT command) - - Args: - timeout: The timeout in seconds. If "stable", the scale will return a weight value when the - weight is stable. If 0, the scale will return a weight value immediately. If a float/int, - the scale will return a weight value after the given timeout (in seconds). - """ - - if timeout == "stable": - return await self.read_stable_weight() - - if not isinstance(timeout, (float, int)): - raise TypeError("timeout must be a float or 'stable'") - - if timeout < 0: - raise ValueError("timeout must be greater than or equal to 0") - - if timeout == 0: - return await self.read_weight_value_immediately() - - return await self.read_dynamic_weight(timeout) - - # Commands for (optional) display manipulation - - async def set_display_text(self, text: str) -> MettlerToledoResponse: - """Set the display text of the scale. Return to the normal weight display with - self.set_weight_display().""" - return await self.send_command(f'D "{text}"') - - async def set_weight_display(self) -> MettlerToledoResponse: - """Return the display to the normal weight display.""" - return await self.send_command("DW") - - # # Configuration commands # # - - @requires_mt_sics_level(2) - async def set_host_unit_grams(self) -> MettlerToledoResponse: - """Set the host output unit to grams. (M21 command)""" - return await self.send_command("M21 0 0") - - # # # Deprecated alias with warning # # # - - # TODO: remove after 2026-03 - - async def get_serial_number(self) -> str: - """Deprecated: Use request_serial_number() instead.""" - warnings.warn( - "get_serial_number() is deprecated and will be removed in 2026-03. " - "Use request_serial_number() instead.", - DeprecationWarning, - stacklevel=2, - ) - return await self.request_serial_number() - - async def get_tare_weight(self) -> float: - """Deprecated: Use request_tare_weight() instead.""" - warnings.warn( - "get_tare_weight() is deprecated and will be removed in 2026-03. " - "Use request_tare_weight() instead.", - DeprecationWarning, - stacklevel=2, - ) - return await self.request_tare_weight() - - async def get_stable_weight(self) -> float: - """Deprecated: Use read_stable_weight() instead.""" - warnings.warn( - "get_stable_weight() is deprecated and will be removed in 2026-03. " - "Use read_stable_weight() instead.", - DeprecationWarning, - stacklevel=2, - ) - return await self.read_stable_weight() - - async def get_dynamic_weight(self, timeout: float) -> float: - """Deprecated: Use read_dynamic_weight() instead.""" - warnings.warn( - "get_dynamic_weight() is deprecated and will be removed in 2026-03. " - "Use read_dynamic_weight() instead.", - DeprecationWarning, - stacklevel=2, - ) - return await self.read_dynamic_weight(timeout) - - async def get_weight_value_immediately(self) -> float: - """Deprecated: Use read_weight_value_immediately() instead.""" - warnings.warn( - "get_weight_value_immediately() is deprecated and will be removed in 2026-03. " - "Use read_weight_value_immediately() instead.", - DeprecationWarning, - stacklevel=2, - ) - return await self.read_weight_value_immediately() - - async def get_weight(self, timeout: Union[Literal["stable"], float, int] = "stable") -> float: - """Deprecated: Use read_weight() instead.""" - warnings.warn( - "get_weight() is deprecated and will be removed in 2026-03. Use read_weight() instead.", - DeprecationWarning, - stacklevel=2, - ) - return await self.read_weight(timeout) - - -# Deprecated alias - TODO: remove after 2026-07 -MettlerToledoWXS205SDUBackend = MTSICSBackend +# TODO: remove after 2026-09 +from pylabrobot.scales.mettler_toledo.backend import MettlerToledoWXS205SDUBackend # noqa: F401 diff --git a/pylabrobot/scales/scale_backend.py b/pylabrobot/scales/scale_backend.py index 047a129937a..6e8caea4fdf 100644 --- a/pylabrobot/scales/scale_backend.py +++ b/pylabrobot/scales/scale_backend.py @@ -1,3 +1,5 @@ +"""Abstract base class for scale backends.""" + from abc import ABCMeta, abstractmethod from pylabrobot.machines.backend import MachineBackend @@ -7,10 +9,10 @@ class ScaleBackend(MachineBackend, metaclass=ABCMeta): """Backend for a scale""" @abstractmethod - async def zero(self): ... + async def zero(self) -> None: ... @abstractmethod - async def tare(self): ... + async def tare(self) -> None: ... @abstractmethod async def read_weight(self) -> float: diff --git a/pylabrobot/scales/scales_tests.py b/pylabrobot/scales/scales_tests.py new file mode 100644 index 00000000000..40c14ed6de3 --- /dev/null +++ b/pylabrobot/scales/scales_tests.py @@ -0,0 +1,78 @@ +"""Tests for generic scale behavior via the chatterbox physics simulation.""" + +import unittest + +from pylabrobot.scales.chatterbox import ScaleChatterboxBackend +from pylabrobot.scales.scale import Scale + + +class ScaleChatterboxTests(unittest.IsolatedAsyncioTestCase): + """Tests for the chatterbox physics simulation via the Scale frontend.""" + + async def asyncSetUp(self): + self.backend = ScaleChatterboxBackend() + self.scale = Scale( + name="test_scale", + backend=self.backend, + size_x=0, + size_y=0, + size_z=0, + ) + await self.scale.setup() + + async def asyncTearDown(self): + await self.scale.stop() + + async def test_zero_then_read_returns_zero(self): + self.backend.platform_weight = 5.0 + await self.scale.zero() + weight = await self.scale.read_weight() + self.assertEqual(weight, 0.0) + + async def test_tare_workflow(self): + self.backend.platform_weight = 50.0 # container + await self.scale.tare() + self.backend.sample_weight = 0.0106 # ~10 uL liquid + weight = await self.scale.read_weight() + self.assertEqual(weight, 0.0106) + + async def test_zero_and_tare_compose(self): + # preload on platform + self.backend.platform_weight = 2.0 + await self.scale.zero() + + # place container + self.backend.platform_weight = 52.0 # 2g preload + 50g container + await self.scale.tare() + + # add sample + self.backend.sample_weight = 1.06 + weight = await self.scale.read_weight() + self.assertEqual(weight, 1.06) + + async def test_request_tare_weight_accuracy(self): + self.backend.platform_weight = 45.0 + await self.scale.tare() + tare = await self.scale.request_tare_weight() + self.assertEqual(tare, 45.0) + + async def test_re_tare_resets(self): + # first tare with 50g container + self.backend.platform_weight = 50.0 + await self.scale.tare() + + # re-tare with 30g container + self.backend.platform_weight = 30.0 + await self.scale.tare() + + # add sample + self.backend.sample_weight = 5.0 + weight = await self.scale.read_weight() + self.assertEqual(weight, 5.0) + + tare = await self.scale.request_tare_weight() + self.assertEqual(tare, 30.0) + + +if __name__ == "__main__": + unittest.main() From d110f0f45a554ec02ed4ca1f59ff8738916b5090 Mon Sep 17 00:00:00 2001 From: Camillo Moschner Date: Sat, 28 Mar 2026 22:37:48 +0000 Subject: [PATCH 05/38] Adaptive multi-response send_command, MT-SICS protocol chatterbox, LOG_LEVEL_IO logging --- .../scales/mettler-toledo-WXS205SDU.ipynb | 138 +++++++------ pylabrobot/scales/mettler_toledo/__init__.py | 1 + pylabrobot/scales/mettler_toledo/backend.py | 183 ++++++++---------- .../scales/mettler_toledo/chatterbox.py | 159 +++++++++++++++ 4 files changed, 312 insertions(+), 169 deletions(-) create mode 100644 pylabrobot/scales/mettler_toledo/chatterbox.py diff --git a/docs/user_guide/02_analytical/scales/mettler-toledo-WXS205SDU.ipynb b/docs/user_guide/02_analytical/scales/mettler-toledo-WXS205SDU.ipynb index e6506759238..ad7220de788 100644 --- a/docs/user_guide/02_analytical/scales/mettler-toledo-WXS205SDU.ipynb +++ b/docs/user_guide/02_analytical/scales/mettler-toledo-WXS205SDU.ipynb @@ -59,10 +59,10 @@ "execution_count": 1, "metadata": { "execution": { - "iopub.execute_input": "2026-03-28T08:00:05.295576Z", - "iopub.status.busy": "2026-03-28T08:00:05.295363Z", - "iopub.status.idle": "2026-03-28T08:00:05.299272Z", - "shell.execute_reply": "2026-03-28T08:00:05.298929Z" + "iopub.execute_input": "2026-03-28T22:34:36.965927Z", + "iopub.status.busy": "2026-03-28T22:34:36.965655Z", + "iopub.status.idle": "2026-03-28T22:34:36.969442Z", + "shell.execute_reply": "2026-03-28T22:34:36.969135Z" } }, "outputs": [], @@ -75,18 +75,18 @@ "execution_count": 2, "metadata": { "execution": { - "iopub.execute_input": "2026-03-28T08:00:05.300973Z", - "iopub.status.busy": "2026-03-28T08:00:05.300861Z", - "iopub.status.idle": "2026-03-28T08:00:05.394300Z", - "shell.execute_reply": "2026-03-28T08:00:05.394113Z" + "iopub.execute_input": "2026-03-28T22:34:36.971120Z", + "iopub.status.busy": "2026-03-28T22:34:36.971017Z", + "iopub.status.idle": "2026-03-28T22:34:37.085801Z", + "shell.execute_reply": "2026-03-28T22:34:37.085619Z" } }, "outputs": [ { - "name": "stdout", + "name": "stderr", "output_type": "stream", "text": [ - "Setting up the scale.\n" + "2026-03-28 22:35:44,775 - pylabrobot - INFO - [scale] Connected (simulation): WXS205SDU (S/N: SIM0000001, capacity: 220.0 g, MT-SICS levels: [0, 1, 2, 3])\n" ] } ], @@ -102,9 +102,9 @@ "\n", "elif protocol_mode == \"simulation\":\n", "\n", - " from pylabrobot.scales.chatterbox import ScaleChatterboxBackend\n", + " from pylabrobot.scales.mettler_toledo.chatterbox import MettlerToledoChatterboxBackend\n", "\n", - " backend = ScaleChatterboxBackend()\n", + " backend = MettlerToledoChatterboxBackend()\n", "\n", "scale = Scale(name=\"scale\", backend=backend, size_x=0, size_y=0, size_z=0)\n", "\n", @@ -149,10 +149,10 @@ "execution_count": 3, "metadata": { "execution": { - "iopub.execute_input": "2026-03-28T08:00:05.408855Z", - "iopub.status.busy": "2026-03-28T08:00:05.408720Z", - "iopub.status.idle": "2026-03-28T08:00:05.410912Z", - "shell.execute_reply": "2026-03-28T08:00:05.410692Z" + "iopub.execute_input": "2026-03-28T22:34:37.100920Z", + "iopub.status.busy": "2026-03-28T22:34:37.100805Z", + "iopub.status.idle": "2026-03-28T22:34:37.103218Z", + "shell.execute_reply": "2026-03-28T22:34:37.102982Z" } }, "outputs": [], @@ -161,6 +161,7 @@ "from pylabrobot.io import LOG_LEVEL_IO\n", "import pylabrobot\n", "\n", + "pylabrobot.verbose(True, level=LOG_LEVEL_IO)\n", "pylabrobot.setup_logger(log_dir=\"./logs\", level=LOG_LEVEL_IO)" ] }, @@ -187,18 +188,18 @@ "execution_count": 4, "metadata": { "execution": { - "iopub.execute_input": "2026-03-28T08:00:05.411920Z", - "iopub.status.busy": "2026-03-28T08:00:05.411838Z", - "iopub.status.idle": "2026-03-28T08:00:05.413356Z", - "shell.execute_reply": "2026-03-28T08:00:05.413204Z" + "iopub.execute_input": "2026-03-28T22:34:37.104277Z", + "iopub.status.busy": "2026-03-28T22:34:37.104206Z", + "iopub.status.idle": "2026-03-28T22:34:37.105851Z", + "shell.execute_reply": "2026-03-28T22:34:37.105696Z" } }, "outputs": [ { - "name": "stdout", + "name": "stderr", "output_type": "stream", "text": [ - "Zeroing the scale\n" + "2026-03-28 22:35:44,785 - pylabrobot - IO - [scale] Sent command: ZC 5000\n" ] } ], @@ -232,24 +233,24 @@ "execution_count": 5, "metadata": { "execution": { - "iopub.execute_input": "2026-03-28T08:00:05.414381Z", - "iopub.status.busy": "2026-03-28T08:00:05.414297Z", - "iopub.status.idle": "2026-03-28T08:00:05.415828Z", - "shell.execute_reply": "2026-03-28T08:00:05.415664Z" + "iopub.execute_input": "2026-03-28T22:34:37.106803Z", + "iopub.status.busy": "2026-03-28T22:34:37.106740Z", + "iopub.status.idle": "2026-03-28T22:34:37.108332Z", + "shell.execute_reply": "2026-03-28T22:34:37.108168Z" } }, "outputs": [ { - "name": "stdout", + "name": "stderr", "output_type": "stream", "text": [ - "Taring the scale\n" + "2026-03-28 22:35:44,791 - pylabrobot - IO - [scale] Sent command: TC 5000\n" ] } ], "source": [ "if protocol_mode == \"simulation\":\n", - " backend.platform_weight = 50.0 # simulate placing a 50g beaker\n", + " backend._mock_weight = 50.0 # simulate placing a 50g beaker\n", "\n", "await scale.tare(timeout=5)" ] @@ -266,18 +267,18 @@ "execution_count": 6, "metadata": { "execution": { - "iopub.execute_input": "2026-03-28T08:00:05.416811Z", - "iopub.status.busy": "2026-03-28T08:00:05.416752Z", - "iopub.status.idle": "2026-03-28T08:00:05.419071Z", - "shell.execute_reply": "2026-03-28T08:00:05.418914Z" + "iopub.execute_input": "2026-03-28T22:34:37.109251Z", + "iopub.status.busy": "2026-03-28T22:34:37.109178Z", + "iopub.status.idle": "2026-03-28T22:34:37.111739Z", + "shell.execute_reply": "2026-03-28T22:34:37.111550Z" } }, "outputs": [ { - "name": "stdout", + "name": "stderr", "output_type": "stream", "text": [ - "Requesting tare weight\n" + "2026-03-28 22:35:44,797 - pylabrobot - IO - [scale] Sent command: TA\n" ] }, { @@ -310,18 +311,18 @@ "execution_count": 7, "metadata": { "execution": { - "iopub.execute_input": "2026-03-28T08:00:05.419965Z", - "iopub.status.busy": "2026-03-28T08:00:05.419889Z", - "iopub.status.idle": "2026-03-28T08:00:05.421714Z", - "shell.execute_reply": "2026-03-28T08:00:05.421540Z" + "iopub.execute_input": "2026-03-28T22:34:37.112671Z", + "iopub.status.busy": "2026-03-28T22:34:37.112616Z", + "iopub.status.idle": "2026-03-28T22:34:37.114623Z", + "shell.execute_reply": "2026-03-28T22:34:37.114461Z" } }, "outputs": [ { - "name": "stdout", + "name": "stderr", "output_type": "stream", "text": [ - "Reading the weight\n" + "2026-03-28 22:35:44,803 - pylabrobot - IO - [scale] Sent command: SI\n" ] }, { @@ -337,7 +338,7 @@ ], "source": [ "if protocol_mode == \"simulation\":\n", - " backend.sample_weight = 0.0106 # simulate dispensing ~10 uL of liquid\n", + " backend._mock_weight = 50.0106 # simulate dispensing ~10 uL of liquid on top of beaker\n", "\n", "await scale.read_weight(timeout=0)" ] @@ -357,20 +358,26 @@ "execution_count": 8, "metadata": { "execution": { - "iopub.execute_input": "2026-03-28T08:00:05.422600Z", - "iopub.status.busy": "2026-03-28T08:00:05.422547Z", - "iopub.status.idle": "2026-03-28T08:00:05.424896Z", - "shell.execute_reply": "2026-03-28T08:00:05.424713Z" + "iopub.execute_input": "2026-03-28T22:34:37.115535Z", + "iopub.status.busy": "2026-03-28T22:34:37.115478Z", + "iopub.status.idle": "2026-03-28T22:34:37.117931Z", + "shell.execute_reply": "2026-03-28T22:34:37.117770Z" } }, "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2026-03-28 22:35:44,814 - pylabrobot - IO - [scale] Sent command: Z\n", + "2026-03-28 22:35:44,815 - pylabrobot - IO - [scale] Sent command: TC 5000\n", + "2026-03-28 22:35:44,815 - pylabrobot - IO - [scale] Sent command: SC 5000\n" + ] + }, { "name": "stdout", "output_type": "stream", "text": [ - "Zeroing the scale\n", - "Taring the scale\n", - "Reading the weight\n", "Dispensed 10.60 mg (10.00 uL)\n" ] } @@ -383,13 +390,12 @@ "\n", "# 2. Place container with liquid on scale\n", "if protocol_mode == \"simulation\":\n", - " backend.platform_weight = 45.0 # 45g container\n", - " backend.sample_weight = 1.06 # ~1 mL of liquid (1000 uL)\n", + " backend._mock_weight = 45.0 + 1.06 # 45g container + ~1 mL of liquid (1000 uL)\n", "\n", "# 3. Aspirate liquid from container (on scale)\n", "# (your liquid handling code here)\n", "if protocol_mode == \"simulation\":\n", - " backend.sample_weight = 1.06 - 0.0106 # aspirated ~10 uL\n", + " backend._mock_weight = 45.0 + 1.06 - 0.0106 # aspirated ~10 uL\n", "\n", "# 4. Tare the scale (ignore weight loss from aspiration)\n", "await scale.tare(timeout=5)\n", @@ -397,7 +403,7 @@ "# 5. Dispense liquid back into same container (on scale)\n", "# (your liquid handling code here)\n", "if protocol_mode == \"simulation\":\n", - " backend.sample_weight = 1.06 # dispensed ~10 uL back\n", + " backend._mock_weight = 45.0 + 1.06 # dispensed ~10 uL back\n", "\n", "# 6. Brief pause to allow scale to settle\n", "if protocol_mode == \"execution\":\n", @@ -432,10 +438,10 @@ "execution_count": 9, "metadata": { "execution": { - "iopub.execute_input": "2026-03-28T08:00:05.425832Z", - "iopub.status.busy": "2026-03-28T08:00:05.425771Z", - "iopub.status.idle": "2026-03-28T08:00:05.427451Z", - "shell.execute_reply": "2026-03-28T08:00:05.427255Z" + "iopub.execute_input": "2026-03-28T22:34:37.118810Z", + "iopub.status.busy": "2026-03-28T22:34:37.118755Z", + "iopub.status.idle": "2026-03-28T22:34:37.120238Z", + "shell.execute_reply": "2026-03-28T22:34:37.120055Z" } }, "outputs": [], @@ -467,21 +473,13 @@ "execution_count": 10, "metadata": { "execution": { - "iopub.execute_input": "2026-03-28T08:00:05.428404Z", - "iopub.status.busy": "2026-03-28T08:00:05.428333Z", - "iopub.status.idle": "2026-03-28T08:00:05.429738Z", - "shell.execute_reply": "2026-03-28T08:00:05.429590Z" + "iopub.execute_input": "2026-03-28T22:34:37.121064Z", + "iopub.status.busy": "2026-03-28T22:34:37.121015Z", + "iopub.status.idle": "2026-03-28T22:34:37.122384Z", + "shell.execute_reply": "2026-03-28T22:34:37.122211Z" } }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Stopping the scale.\n" - ] - } - ], + "outputs": [], "source": [ "await scale.stop()" ] diff --git a/pylabrobot/scales/mettler_toledo/__init__.py b/pylabrobot/scales/mettler_toledo/__init__.py index 17e2ddd79f9..1204bc7a54b 100644 --- a/pylabrobot/scales/mettler_toledo/__init__.py +++ b/pylabrobot/scales/mettler_toledo/__init__.py @@ -1,4 +1,5 @@ """Mettler Toledo scale backend using the MT-SICS protocol.""" from pylabrobot.scales.mettler_toledo.backend import MettlerToledoWXS205SDUBackend +from pylabrobot.scales.mettler_toledo.chatterbox import MettlerToledoChatterboxBackend from pylabrobot.scales.mettler_toledo.errors import MettlerToledoError diff --git a/pylabrobot/scales/mettler_toledo/backend.py b/pylabrobot/scales/mettler_toledo/backend.py index aa4759c9ffb..2efe60af4b3 100644 --- a/pylabrobot/scales/mettler_toledo/backend.py +++ b/pylabrobot/scales/mettler_toledo/backend.py @@ -10,6 +10,7 @@ from typing import Any, Callable, List, Literal, Optional, Set, TypeVar, Union from pylabrobot.io.serial import Serial +from pylabrobot.io.validation_utils import LOG_LEVEL_IO from pylabrobot.scales.mettler_toledo.errors import MettlerToledoError from pylabrobot.scales.scale_backend import ScaleBackend @@ -103,6 +104,8 @@ async def setup(self) -> None: self.serial_number = await self.cancel() # Device discovery (Level 0 - always available) + # Note: device_type and capacity both use I2 but are separate methods intentionally - + # single-responsibility per method, the duplicate I2 round-trip during one-time setup is fine. self._mt_sics_levels: Set[int] = await self._query_mt_sics_levels() self.device_type = await self.request_device_type() self.capacity = await self.request_capacity() @@ -132,10 +135,10 @@ async def _query_mt_sics_levels(self) -> Set[int]: Returns a set of integers representing the supported levels (e.g. {0, 1, 2, 3}). """ - response = await self.send_command("I1") + responses = await self.send_command("I1") # I1 A "0123" "2.00" "2.20" "1.00" "1.50" - self._validate_response(response, 3, "I1") - level_string = response[2].replace('"', "") + self._validate_response(responses[0], 3, "I1") + level_string = responses[0][2].replace('"', "") return {int(c) for c in level_string} # === Response parsing === @@ -186,9 +189,8 @@ def _parse_basic_errors(self, response: List[str]) -> None: - +: Balance in overload range - -: Balance in underload range - TODO: handle 'B' status - multi-response commands (e.g. C1 adjustment) send 'B' first, - then additional responses, then 'A' on completion. Currently send_command returns after - the first response, so 'B' responses are not followed up. + Note: B status (multi-response) is handled by send_command, which reads all lines + until status A. Each line is validated through this method individually. """ if len(response) == 0: @@ -245,50 +247,40 @@ def _parse_basic_errors(self, response: List[str]) -> None: # === Command Layer === - async def send_command(self, command: str, timeout: int = 60) -> MettlerToledoResponse: - """Send a command to the scale and receive the response. + async def send_command(self, command: str, timeout: int = 60) -> List[MettlerToledoResponse]: + """Send a command to the scale and read all response lines. + + Single-response commands (status A) return a list of one parsed line. + Multi-response commands (status B) return all lines, reading until status A. Args: - timeout: The timeout in seconds. + timeout: The timeout in seconds (applies across all response lines). """ + logger.log(LOG_LEVEL_IO, "[scale] Sent command: %s", command) await self.io.write(command.encode() + b"\r\n") + responses: List[MettlerToledoResponse] = [] timeout_time = time.time() + timeout while True: - raw_response = await self.io.readline() - if raw_response != b"": - break - if time.time() > timeout_time: - raise TimeoutError("Timeout while waiting for response from scale.") - await asyncio.sleep(0.001) - logger.debug("[scale] Received response: %s", raw_response) - response = raw_response.decode("utf-8").strip().split() - - # parse basic errors - self._parse_basic_errors(response) - - # mypy doesn't understand this - return response # type: ignore + while True: + raw_response = await self.io.readline() + if raw_response != b"": + break + if time.time() > timeout_time: + raise TimeoutError("Timeout while waiting for response from scale.") + await asyncio.sleep(0.001) - async def _drain_followup_responses(self, command: str, timeout: float = 10) -> None: - """Read and discard follow-up responses from multi-response commands. + logger.log(LOG_LEVEL_IO, "[scale] Received response: %s", raw_response) + response = raw_response.decode("utf-8").strip().split() + self._parse_basic_errors(response) + responses.append(response) # type: ignore[arg-type] - Multi-response commands (B status) send additional lines after the first response. - This method reads lines until it sees status A (final) or times out. - """ - timeout_time = time.time() + timeout - while True: - raw_followup = await self.io.readline() - if raw_followup != b"": - followup = raw_followup.decode("utf-8").strip().split() - logger.debug("[scale] %s followup: %s", command, raw_followup) - if len(followup) >= 2 and followup[1] == "A": - break - if time.time() > timeout_time: - logger.warning("[scale] Timeout waiting for %s followup", command) + # Status B means more responses follow; anything else (A, etc.) is final + if len(response) < 2 or response[1] != "B": break - await asyncio.sleep(0.001) + + return responses # === Public high-level API === @@ -304,10 +296,10 @@ async def cancel(self) -> str: Returns the serial number from the I4-style response. """ await self.io.reset_input_buffer() - response = await self.send_command("@") + responses = await self.send_command("@") # @ responds with I4-style: I4 A "" - self._validate_response(response, 3, "@") - return response[2].replace('"', "") + self._validate_response(responses[0], 3, "@") + return responses[0][2].replace('"', "") async def cancel_all(self) -> None: """C - Cancel all active and pending interface commands. @@ -319,40 +311,37 @@ async def cancel_all(self) -> None: This is a multi-response command: the device sends C B (started) then C A (complete). Both responses are consumed to keep the serial buffer clean. """ - response = await self.send_command("C") - # First response: C B (cancel started) - self._validate_response(response, 2, "C") - if response[1] == "E": + responses = await self.send_command("C") + # send_command reads both C B (started) and C A (complete) automatically + self._validate_response(responses[0], 2, "C") + if responses[0][1] == "E": raise MettlerToledoError( title="Error while canceling", - message=f"C command returned error: {response}", + message=f"C command returned error: {responses[0]}", ) - # Second response: C A (cancel complete) - await self._drain_followup_responses("C") - # # Identification commands # # async def request_serial_number(self) -> str: """Get the serial number of the scale. (I4 command)""" - response = await self.send_command("I4") - self._validate_response(response, 3, "I4") - return response[2].replace('"', "") + responses = await self.send_command("I4") + self._validate_response(responses[0], 3, "I4") + return responses[0][2].replace('"', "") async def request_device_type(self) -> str: """Query the device type string. (I2 command)""" - response = await self.send_command("I2") + responses = await self.send_command("I2") # After split(): ["I2", "A", '"WXS205SDU"', "220.0000", "g"] - self._validate_response(response, 5, "I2") - return response[2].replace('"', "") + self._validate_response(responses[0], 5, "I2") + return responses[0][2].replace('"', "") async def request_capacity(self) -> float: """Query the maximum weighing capacity in grams. (I2 command)""" - response = await self.send_command("I2") + responses = await self.send_command("I2") # After split(): ["I2", "A", '"WXS205SDU"', "220.0000", "g"] - self._validate_response(response, 5, "I2") - self._validate_unit(response[4], "I2") - return float(response[3]) + self._validate_response(responses[0], 5, "I2") + self._validate_unit(responses[0][4], "I2") + return float(responses[0][3]) @requires_mt_sics_level(2) async def request_remaining_weighing_range(self) -> float: @@ -366,29 +355,25 @@ async def request_remaining_weighing_range(self) -> float: (RangeNo 0 with B, RangeNo 1 with B, RangeNo 2 with A). We extract the value from the first response and drain the remaining ones. """ - response = await self.send_command("I50") - # First response line: I50 B 0 (RangeNo 0 = max weighing range) - # After split(): ["I50", "B", "0", "535.141", "g"] - self._validate_response(response, 5, "I50") - self._validate_unit(response[4], "I50") - remaining = float(response[3]) - - # Drain follow-up responses (RangeNo 1 and 2) to keep the serial buffer clean - await self._drain_followup_responses("I50") - - return remaining + responses = await self.send_command("I50") + # responses[0]: I50 B 0 (RangeNo 0 = max weighing range) + # responses[1]: I50 B 1 (RangeNo 1 = internal adjustment range) + # responses[2]: I50 A 2 (RangeNo 2 = external adjustment range) + self._validate_response(responses[0], 5, "I50") + self._validate_unit(responses[0][4], "I50") + return float(responses[0][3]) # # Zero commands # # - async def zero_immediately(self) -> MettlerToledoResponse: + async def zero_immediately(self) -> List[MettlerToledoResponse]: """Zero the scale immediately. (ACTION command)""" return await self.send_command("ZI") - async def zero_stable(self) -> MettlerToledoResponse: + async def zero_stable(self) -> List[MettlerToledoResponse]: """Zero the scale when the weight is stable. (ACTION command)""" return await self.send_command("Z") - async def zero_timeout(self, timeout: float) -> MettlerToledoResponse: + async def zero_timeout(self, timeout: float) -> List[MettlerToledoResponse]: """Zero the scale after a given timeout. (ACTION command)""" # For some reason, this will always return a syntax error (ES), even though it should be allowed # according to the docs. @@ -397,7 +382,7 @@ async def zero_timeout(self, timeout: float) -> MettlerToledoResponse: async def zero( self, timeout: Union[Literal["stable"], float, int] = "stable" - ) -> MettlerToledoResponse: + ) -> List[MettlerToledoResponse]: """High level function to zero the scale. (ACTION command) Args: @@ -422,15 +407,15 @@ async def zero( # # Tare commands # # - async def tare_stable(self) -> MettlerToledoResponse: + async def tare_stable(self) -> List[MettlerToledoResponse]: """Tare the scale when the weight is stable. (ACTION command)""" return await self.send_command("T") - async def tare_immediately(self) -> MettlerToledoResponse: + async def tare_immediately(self) -> List[MettlerToledoResponse]: """Tare the scale immediately. (ACTION command)""" return await self.send_command("TI") - async def tare_timeout(self, timeout: float) -> MettlerToledoResponse: + async def tare_timeout(self, timeout: float) -> List[MettlerToledoResponse]: """Tare the scale after a given timeout. (ACTION command)""" # For some reason, this will always return a syntax error (ES), even though it should be allowed # according to the docs. @@ -439,7 +424,7 @@ async def tare_timeout(self, timeout: float) -> MettlerToledoResponse: async def tare( self, timeout: Union[Literal["stable"], float, int] = "stable" - ) -> MettlerToledoResponse: + ) -> List[MettlerToledoResponse]: """High level function to tare the scale. (ACTION command) Args: @@ -469,12 +454,12 @@ async def request_tare_weight(self) -> float: "Use TA to query the current tare value or preset a known tare value." """ - response = await self.send_command("TA") - self._validate_response(response, 4, "TA") - self._validate_unit(response[3], "TA") - return float(response[2]) + responses = await self.send_command("TA") + self._validate_response(responses[0], 4, "TA") + self._validate_unit(responses[0][3], "TA") + return float(responses[0][2]) - async def clear_tare(self) -> MettlerToledoResponse: + async def clear_tare(self) -> List[MettlerToledoResponse]: """TAC - Clear tare weight value (MEM-WRITE command)""" return await self.send_command("TAC") @@ -489,10 +474,10 @@ async def read_stable_weight(self) -> float: doors to achieve a stable weight." """ - response = await self.send_command("S") - self._validate_response(response, 4, "S") - self._validate_unit(response[3], "S") - return float(response[2]) + responses = await self.send_command("S") + self._validate_response(responses[0], 4, "S") + self._validate_unit(responses[0][3], "S") + return float(responses[0][2]) async def read_dynamic_weight(self, timeout: float) -> float: """Read a stable weight value from the machine within a given timeout, or @@ -504,10 +489,10 @@ async def read_dynamic_weight(self, timeout: float) -> float: timeout = int(timeout * 1000) # convert to milliseconds - response = await self.send_command(f"SC {timeout}") - self._validate_response(response, 4, "SC") - self._validate_unit(response[3], "SC") - return float(response[2]) + responses = await self.send_command(f"SC {timeout}") + self._validate_response(responses[0], 4, "SC") + self._validate_unit(responses[0][3], "SC") + return float(responses[0][2]) async def read_weight_value_immediately(self) -> float: """Read a weight value immediately from the scale. (MEASUREMENT command) @@ -516,10 +501,10 @@ async def read_weight_value_immediately(self) -> float: balance to the connected communication partner via the interface." """ - response = await self.send_command("SI") - self._validate_response(response, 4, "SI") - self._validate_unit(response[3], "SI") - return float(response[2]) + responses = await self.send_command("SI") + self._validate_response(responses[0], 4, "SI") + self._validate_unit(responses[0][3], "SI") + return float(responses[0][2]) async def read_weight(self, timeout: Union[Literal["stable"], float, int] = "stable") -> float: """High level function to read a weight value from the scale. (MEASUREMENT command) @@ -546,19 +531,19 @@ async def read_weight(self, timeout: Union[Literal["stable"], float, int] = "sta # Commands for (optional) display manipulation - async def set_display_text(self, text: str) -> MettlerToledoResponse: + async def set_display_text(self, text: str) -> List[MettlerToledoResponse]: """Set the display text of the scale. Return to the normal weight display with self.set_weight_display().""" return await self.send_command(f'D "{text}"') - async def set_weight_display(self) -> MettlerToledoResponse: + async def set_weight_display(self) -> List[MettlerToledoResponse]: """Return the display to the normal weight display.""" return await self.send_command("DW") # # Configuration commands # # @requires_mt_sics_level(2) - async def set_host_unit_grams(self) -> MettlerToledoResponse: + async def set_host_unit_grams(self) -> List[MettlerToledoResponse]: """Set the host output unit to grams. (M21 command)""" return await self.send_command("M21 0 0") diff --git a/pylabrobot/scales/mettler_toledo/chatterbox.py b/pylabrobot/scales/mettler_toledo/chatterbox.py new file mode 100644 index 00000000000..af901263844 --- /dev/null +++ b/pylabrobot/scales/mettler_toledo/chatterbox.py @@ -0,0 +1,159 @@ +"""MT-SICS protocol-level chatterbox for device-free testing. + +Unlike the generic ScaleChatterboxBackend (which simulates scale physics), +this chatterbox inherits from MettlerToledoWXS205SDUBackend and overrides +send_command to return mock MT-SICS responses. All high-level methods +(zero, tare, read_weight, request_capacity, etc.) work unchanged because +they call send_command which is intercepted here. + +This follows the same pattern as STARChatterboxBackend, which inherits from +STARBackend and overrides _write_and_read_command. +""" + +import logging +from typing import List, Optional, Set + +from pylabrobot.io.validation_utils import LOG_LEVEL_IO +from pylabrobot.scales.mettler_toledo.backend import MettlerToledoWXS205SDUBackend, MettlerToledoResponse +from pylabrobot.scales.scale_backend import ScaleBackend + +logger = logging.getLogger("pylabrobot") + + +class MettlerToledoChatterboxBackend(MettlerToledoWXS205SDUBackend): + """MT-SICS protocol simulator for testing without hardware. + + Inherits all high-level methods from MettlerToledoWXS205SDUBackend. + Overrides send_command to return mock MT-SICS responses, so response + parsing and validation code is exercised during tests. + + Set ``_mock_weight`` to simulate the total load on the weighing platform. + + Example:: + + backend = MettlerToledoChatterboxBackend() + scale = Scale(name="scale", backend=backend, size_x=0, size_y=0, size_z=0) + await scale.setup() + # backend.device_type == "WXS205SDU", backend.capacity == 220.0 + + backend._mock_weight = 50.0 # place 50g container + await scale.tare() + backend._mock_weight = 60.0 # add 10g + weight = await scale.read_weight() # returns 10.0 + """ + + def __init__( + self, + device_type: str = "WXS205SDU", + serial_number: str = "SIM0000001", + capacity: float = 220.0, + mt_sics_levels: Optional[Set[int]] = None, + ) -> None: + # Skip MettlerToledoWXS205SDUBackend.__init__ (which creates a Serial object) + ScaleBackend.__init__(self) + self._mock_weight: float = 0.0 + self._mock_tare: float = 0.0 + self._mock_zero_offset: float = 0.0 + self._mock_device_type = device_type + self._mock_serial_number = serial_number + self._mock_capacity = capacity + self._mock_mt_sics_levels = mt_sics_levels or {0, 1, 2, 3} + + async def setup(self) -> None: + self.serial_number = self._mock_serial_number + self._mt_sics_levels = self._mock_mt_sics_levels + self.device_type = self._mock_device_type + self.capacity = self._mock_capacity + logger.info( + "[scale] Connected (simulation): %s (S/N: %s, capacity: %.1f g, MT-SICS levels: %s)", + self.device_type, + self.serial_number, + self.capacity, + sorted(self._mt_sics_levels), + ) + + async def stop(self) -> None: + pass + + async def cancel(self) -> str: + responses = await self.send_command("@") + self._validate_response(responses[0], 3, "@") + return responses[0][2].replace('"', "") + + async def send_command( + self, command: str, timeout: int = 60 + ) -> List[MettlerToledoResponse]: + logger.log(LOG_LEVEL_IO, "[scale] Sent command: %s", command) + cmd = command.split()[0] + net = self._mock_weight - self._mock_zero_offset - self._mock_tare + + if cmd == "@": + return [["I4", "A", f'"{self._mock_serial_number}"']] + if cmd == "I1": + levels = "".join(str(l) for l in sorted(self._mock_mt_sics_levels)) + return [["I1", "A", f'"{levels}"']] + if cmd == "I2": + return [["I2", "A", f'"{self._mock_device_type}"', f"{self._mock_capacity:.4f}", "g"]] + if cmd == "I4": + return [["I4", "A", f'"{self._mock_serial_number}"']] + + # Zero + if cmd == "Z": + self._mock_zero_offset = self._mock_weight + return [["Z", "A"]] + if cmd == "ZI": + self._mock_zero_offset = self._mock_weight + return [["ZI", "A"]] + if cmd == "ZC": + self._mock_zero_offset = self._mock_weight + return [["ZC", "A"]] + + # Tare + if cmd == "T": + self._mock_tare = self._mock_weight - self._mock_zero_offset + return [["T", "S", f"{self._mock_tare:.5f}", "g"]] + if cmd == "TI": + self._mock_tare = self._mock_weight - self._mock_zero_offset + return [["TI", "S", f"{self._mock_tare:.5f}", "g"]] + if cmd == "TC": + self._mock_tare = self._mock_weight - self._mock_zero_offset + return [["TC", "S", f"{self._mock_tare:.5f}", "g"]] + if cmd == "TA": + return [["TA", "A", f"{self._mock_tare:.5f}", "g"]] + if cmd == "TAC": + self._mock_tare = 0.0 + return [["TAC", "A"]] + + # Weight reading + if cmd == "S": + return [["S", "S", f"{net:.5f}", "g"]] + if cmd == "SI": + return [["SI", "S", f"{net:.5f}", "g"]] + if cmd == "SC": + return [["SC", "S", f"{net:.5f}", "g"]] + + # Cancel + if cmd == "C": + return [["C", "B"], ["C", "A"]] + + # Display + if cmd == "D": + return [["D", "A"]] + if cmd == "DW": + return [["DW", "A"]] + + # Configuration + if cmd == "M21": + return [["M21", "A"]] + + # Remaining weighing range + if cmd == "I50": + remaining = self._mock_capacity - self._mock_weight + return [ + ["I50", "B", "0", f"{remaining:.3f}", "g"], + ["I50", "B", "1", "0.000", "g"], + ["I50", "A", "2", f"{remaining:.3f}", "g"], + ] + + # Unknown command + return [["ES"]] From aaa9fca05a23ac03cc2d9a002f9d7d84a49e4a49 Mon Sep 17 00:00:00 2001 From: Camillo Moschner Date: Sat, 28 Mar 2026 22:53:42 +0000 Subject: [PATCH 06/38] MT-SICS chatterbox: self-contained physics, inherit from backend only (matching STAR pattern) --- .../scales/mettler-toledo-WXS205SDU.ipynb | 107 +++++++-------- .../scales/mettler_toledo/chatterbox.py | 125 +++++++++--------- 2 files changed, 113 insertions(+), 119 deletions(-) diff --git a/docs/user_guide/02_analytical/scales/mettler-toledo-WXS205SDU.ipynb b/docs/user_guide/02_analytical/scales/mettler-toledo-WXS205SDU.ipynb index ad7220de788..549617e7cde 100644 --- a/docs/user_guide/02_analytical/scales/mettler-toledo-WXS205SDU.ipynb +++ b/docs/user_guide/02_analytical/scales/mettler-toledo-WXS205SDU.ipynb @@ -59,10 +59,10 @@ "execution_count": 1, "metadata": { "execution": { - "iopub.execute_input": "2026-03-28T22:34:36.965927Z", - "iopub.status.busy": "2026-03-28T22:34:36.965655Z", - "iopub.status.idle": "2026-03-28T22:34:36.969442Z", - "shell.execute_reply": "2026-03-28T22:34:36.969135Z" + "iopub.execute_input": "2026-03-28T22:45:48.998781Z", + "iopub.status.busy": "2026-03-28T22:45:48.998662Z", + "iopub.status.idle": "2026-03-28T22:45:49.003172Z", + "shell.execute_reply": "2026-03-28T22:45:49.002860Z" } }, "outputs": [], @@ -75,10 +75,10 @@ "execution_count": 2, "metadata": { "execution": { - "iopub.execute_input": "2026-03-28T22:34:36.971120Z", - "iopub.status.busy": "2026-03-28T22:34:36.971017Z", - "iopub.status.idle": "2026-03-28T22:34:37.085801Z", - "shell.execute_reply": "2026-03-28T22:34:37.085619Z" + "iopub.execute_input": "2026-03-28T22:45:49.005211Z", + "iopub.status.busy": "2026-03-28T22:45:49.005086Z", + "iopub.status.idle": "2026-03-28T22:45:49.103735Z", + "shell.execute_reply": "2026-03-28T22:45:49.103532Z" } }, "outputs": [ @@ -86,7 +86,7 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-28 22:35:44,775 - pylabrobot - INFO - [scale] Connected (simulation): WXS205SDU (S/N: SIM0000001, capacity: 220.0 g, MT-SICS levels: [0, 1, 2, 3])\n" + "2026-03-28 22:52:55,695 - pylabrobot - INFO - [scale] Connected (simulation): WXS205SDU (S/N: SIM0000001, capacity: 220.0 g, MT-SICS levels: [0, 1, 2, 3])\n" ] } ], @@ -149,10 +149,10 @@ "execution_count": 3, "metadata": { "execution": { - "iopub.execute_input": "2026-03-28T22:34:37.100920Z", - "iopub.status.busy": "2026-03-28T22:34:37.100805Z", - "iopub.status.idle": "2026-03-28T22:34:37.103218Z", - "shell.execute_reply": "2026-03-28T22:34:37.102982Z" + "iopub.execute_input": "2026-03-28T22:45:49.117755Z", + "iopub.status.busy": "2026-03-28T22:45:49.117656Z", + "iopub.status.idle": "2026-03-28T22:45:49.119949Z", + "shell.execute_reply": "2026-03-28T22:45:49.119750Z" } }, "outputs": [], @@ -188,10 +188,10 @@ "execution_count": 4, "metadata": { "execution": { - "iopub.execute_input": "2026-03-28T22:34:37.104277Z", - "iopub.status.busy": "2026-03-28T22:34:37.104206Z", - "iopub.status.idle": "2026-03-28T22:34:37.105851Z", - "shell.execute_reply": "2026-03-28T22:34:37.105696Z" + "iopub.execute_input": "2026-03-28T22:45:49.120938Z", + "iopub.status.busy": "2026-03-28T22:45:49.120869Z", + "iopub.status.idle": "2026-03-28T22:45:49.122671Z", + "shell.execute_reply": "2026-03-28T22:45:49.122454Z" } }, "outputs": [ @@ -199,7 +199,7 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-28 22:35:44,785 - pylabrobot - IO - [scale] Sent command: ZC 5000\n" + "2026-03-28 22:52:55,705 - pylabrobot - IO - [scale] Sent command: ZC 5000\n" ] } ], @@ -233,10 +233,10 @@ "execution_count": 5, "metadata": { "execution": { - "iopub.execute_input": "2026-03-28T22:34:37.106803Z", - "iopub.status.busy": "2026-03-28T22:34:37.106740Z", - "iopub.status.idle": "2026-03-28T22:34:37.108332Z", - "shell.execute_reply": "2026-03-28T22:34:37.108168Z" + "iopub.execute_input": "2026-03-28T22:45:49.123690Z", + "iopub.status.busy": "2026-03-28T22:45:49.123624Z", + "iopub.status.idle": "2026-03-28T22:45:49.125305Z", + "shell.execute_reply": "2026-03-28T22:45:49.125104Z" } }, "outputs": [ @@ -244,13 +244,13 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-28 22:35:44,791 - pylabrobot - IO - [scale] Sent command: TC 5000\n" + "2026-03-28 22:52:55,711 - pylabrobot - IO - [scale] Sent command: TC 5000\n" ] } ], "source": [ "if protocol_mode == \"simulation\":\n", - " backend._mock_weight = 50.0 # simulate placing a 50g beaker\n", + " backend.platform_weight = 50.0 # simulate placing a 50g beaker\n", "\n", "await scale.tare(timeout=5)" ] @@ -267,10 +267,10 @@ "execution_count": 6, "metadata": { "execution": { - "iopub.execute_input": "2026-03-28T22:34:37.109251Z", - "iopub.status.busy": "2026-03-28T22:34:37.109178Z", - "iopub.status.idle": "2026-03-28T22:34:37.111739Z", - "shell.execute_reply": "2026-03-28T22:34:37.111550Z" + "iopub.execute_input": "2026-03-28T22:45:49.126326Z", + "iopub.status.busy": "2026-03-28T22:45:49.126265Z", + "iopub.status.idle": "2026-03-28T22:45:49.128638Z", + "shell.execute_reply": "2026-03-28T22:45:49.128465Z" } }, "outputs": [ @@ -278,7 +278,7 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-28 22:35:44,797 - pylabrobot - IO - [scale] Sent command: TA\n" + "2026-03-28 22:52:55,716 - pylabrobot - IO - [scale] Sent command: TA\n" ] }, { @@ -311,10 +311,10 @@ "execution_count": 7, "metadata": { "execution": { - "iopub.execute_input": "2026-03-28T22:34:37.112671Z", - "iopub.status.busy": "2026-03-28T22:34:37.112616Z", - "iopub.status.idle": "2026-03-28T22:34:37.114623Z", - "shell.execute_reply": "2026-03-28T22:34:37.114461Z" + "iopub.execute_input": "2026-03-28T22:45:49.129562Z", + "iopub.status.busy": "2026-03-28T22:45:49.129500Z", + "iopub.status.idle": "2026-03-28T22:45:49.131420Z", + "shell.execute_reply": "2026-03-28T22:45:49.131265Z" } }, "outputs": [ @@ -322,7 +322,7 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-28 22:35:44,803 - pylabrobot - IO - [scale] Sent command: SI\n" + "2026-03-28 22:52:55,724 - pylabrobot - IO - [scale] Sent command: SI\n" ] }, { @@ -338,7 +338,7 @@ ], "source": [ "if protocol_mode == \"simulation\":\n", - " backend._mock_weight = 50.0106 # simulate dispensing ~10 uL of liquid on top of beaker\n", + " backend.sample_weight = 0.0106 # simulate dispensing ~10 uL of liquid\n", "\n", "await scale.read_weight(timeout=0)" ] @@ -358,10 +358,10 @@ "execution_count": 8, "metadata": { "execution": { - "iopub.execute_input": "2026-03-28T22:34:37.115535Z", - "iopub.status.busy": "2026-03-28T22:34:37.115478Z", - "iopub.status.idle": "2026-03-28T22:34:37.117931Z", - "shell.execute_reply": "2026-03-28T22:34:37.117770Z" + "iopub.execute_input": "2026-03-28T22:45:49.132319Z", + "iopub.status.busy": "2026-03-28T22:45:49.132258Z", + "iopub.status.idle": "2026-03-28T22:45:49.135149Z", + "shell.execute_reply": "2026-03-28T22:45:49.134973Z" } }, "outputs": [ @@ -369,9 +369,9 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-28 22:35:44,814 - pylabrobot - IO - [scale] Sent command: Z\n", - "2026-03-28 22:35:44,815 - pylabrobot - IO - [scale] Sent command: TC 5000\n", - "2026-03-28 22:35:44,815 - pylabrobot - IO - [scale] Sent command: SC 5000\n" + "2026-03-28 22:52:55,736 - pylabrobot - IO - [scale] Sent command: Z\n", + "2026-03-28 22:52:55,737 - pylabrobot - IO - [scale] Sent command: TC 5000\n", + "2026-03-28 22:52:55,737 - pylabrobot - IO - [scale] Sent command: SC 5000\n" ] }, { @@ -390,12 +390,13 @@ "\n", "# 2. Place container with liquid on scale\n", "if protocol_mode == \"simulation\":\n", - " backend._mock_weight = 45.0 + 1.06 # 45g container + ~1 mL of liquid (1000 uL)\n", + " backend.platform_weight = 45.0 # 45g container\n", + " backend.sample_weight = 1.06 # ~1 mL of liquid (1000 uL)\n", "\n", "# 3. Aspirate liquid from container (on scale)\n", "# (your liquid handling code here)\n", "if protocol_mode == \"simulation\":\n", - " backend._mock_weight = 45.0 + 1.06 - 0.0106 # aspirated ~10 uL\n", + " backend.sample_weight = 1.06 - 0.0106 # aspirated ~10 uL\n", "\n", "# 4. Tare the scale (ignore weight loss from aspiration)\n", "await scale.tare(timeout=5)\n", @@ -403,7 +404,7 @@ "# 5. Dispense liquid back into same container (on scale)\n", "# (your liquid handling code here)\n", "if protocol_mode == \"simulation\":\n", - " backend._mock_weight = 45.0 + 1.06 # dispensed ~10 uL back\n", + " backend.sample_weight = 1.06 # dispensed ~10 uL back\n", "\n", "# 6. Brief pause to allow scale to settle\n", "if protocol_mode == \"execution\":\n", @@ -438,10 +439,10 @@ "execution_count": 9, "metadata": { "execution": { - "iopub.execute_input": "2026-03-28T22:34:37.118810Z", - "iopub.status.busy": "2026-03-28T22:34:37.118755Z", - "iopub.status.idle": "2026-03-28T22:34:37.120238Z", - "shell.execute_reply": "2026-03-28T22:34:37.120055Z" + "iopub.execute_input": "2026-03-28T22:45:49.136064Z", + "iopub.status.busy": "2026-03-28T22:45:49.136011Z", + "iopub.status.idle": "2026-03-28T22:45:49.137502Z", + "shell.execute_reply": "2026-03-28T22:45:49.137323Z" } }, "outputs": [], @@ -473,10 +474,10 @@ "execution_count": 10, "metadata": { "execution": { - "iopub.execute_input": "2026-03-28T22:34:37.121064Z", - "iopub.status.busy": "2026-03-28T22:34:37.121015Z", - "iopub.status.idle": "2026-03-28T22:34:37.122384Z", - "shell.execute_reply": "2026-03-28T22:34:37.122211Z" + "iopub.execute_input": "2026-03-28T22:45:49.138367Z", + "iopub.status.busy": "2026-03-28T22:45:49.138316Z", + "iopub.status.idle": "2026-03-28T22:45:49.139644Z", + "shell.execute_reply": "2026-03-28T22:45:49.139462Z" } }, "outputs": [], diff --git a/pylabrobot/scales/mettler_toledo/chatterbox.py b/pylabrobot/scales/mettler_toledo/chatterbox.py index af901263844..14bb3b2cfa0 100644 --- a/pylabrobot/scales/mettler_toledo/chatterbox.py +++ b/pylabrobot/scales/mettler_toledo/chatterbox.py @@ -1,20 +1,21 @@ """MT-SICS protocol-level chatterbox for device-free testing. -Unlike the generic ScaleChatterboxBackend (which simulates scale physics), -this chatterbox inherits from MettlerToledoWXS205SDUBackend and overrides -send_command to return mock MT-SICS responses. All high-level methods -(zero, tare, read_weight, request_capacity, etc.) work unchanged because -they call send_command which is intercepted here. - -This follows the same pattern as STARChatterboxBackend, which inherits from -STARBackend and overrides _write_and_read_command. +Inherits from MettlerToledoWXS205SDUBackend and overrides send_command to return +mock MT-SICS responses. All high-level methods (zero, tare, read_weight, etc.) +work unchanged because they call send_command which is intercepted here. + +This follows the same pattern as STARChatterboxBackend (inherits from STARBackend +and overrides the low-level command transmission). """ import logging from typing import List, Optional, Set from pylabrobot.io.validation_utils import LOG_LEVEL_IO -from pylabrobot.scales.mettler_toledo.backend import MettlerToledoWXS205SDUBackend, MettlerToledoResponse +from pylabrobot.scales.mettler_toledo.backend import ( + MettlerToledoResponse, + MettlerToledoWXS205SDUBackend, +) from pylabrobot.scales.scale_backend import ScaleBackend logger = logging.getLogger("pylabrobot") @@ -23,11 +24,11 @@ class MettlerToledoChatterboxBackend(MettlerToledoWXS205SDUBackend): """MT-SICS protocol simulator for testing without hardware. - Inherits all high-level methods from MettlerToledoWXS205SDUBackend. - Overrides send_command to return mock MT-SICS responses, so response - parsing and validation code is exercised during tests. + Inherits all MT-SICS methods from MettlerToledoWXS205SDUBackend. + Overrides send_command to return mock MT-SICS responses. - Set ``_mock_weight`` to simulate the total load on the weighing platform. + Set ``platform_weight`` and ``sample_weight`` to simulate placing items + on the scale. The total sensor reading is ``platform_weight + sample_weight``. Example:: @@ -36,10 +37,10 @@ class MettlerToledoChatterboxBackend(MettlerToledoWXS205SDUBackend): await scale.setup() # backend.device_type == "WXS205SDU", backend.capacity == 220.0 - backend._mock_weight = 50.0 # place 50g container + backend.platform_weight = 50.0 # place 50g container await scale.tare() - backend._mock_weight = 60.0 # add 10g - weight = await scale.read_weight() # returns 10.0 + backend.sample_weight = 10.0 # add 10g + weight = await scale.read_weight() # returns 10.0 """ def __init__( @@ -51,19 +52,28 @@ def __init__( ) -> None: # Skip MettlerToledoWXS205SDUBackend.__init__ (which creates a Serial object) ScaleBackend.__init__(self) - self._mock_weight: float = 0.0 - self._mock_tare: float = 0.0 - self._mock_zero_offset: float = 0.0 - self._mock_device_type = device_type - self._mock_serial_number = serial_number - self._mock_capacity = capacity - self._mock_mt_sics_levels = mt_sics_levels or {0, 1, 2, 3} + + # Physics state + self.platform_weight: float = 0.0 + self.sample_weight: float = 0.0 + self.zero_offset: float = 0.0 + self.tare_weight: float = 0.0 + + # Simulated device identity + self._simulated_device_type = device_type + self._simulated_serial_number = serial_number + self._simulated_capacity = capacity + self._simulated_mt_sics_levels = mt_sics_levels or {0, 1, 2, 3} + + @property + def _sensor_reading(self) -> float: + return self.platform_weight + self.sample_weight async def setup(self) -> None: - self.serial_number = self._mock_serial_number - self._mt_sics_levels = self._mock_mt_sics_levels - self.device_type = self._mock_device_type - self.capacity = self._mock_capacity + self.serial_number = self._simulated_serial_number + self._mt_sics_levels = self._simulated_mt_sics_levels + self.device_type = self._simulated_device_type + self.capacity = self._simulated_capacity logger.info( "[scale] Connected (simulation): %s (S/N: %s, capacity: %.1f g, MT-SICS levels: %s)", self.device_type, @@ -80,67 +90,50 @@ async def cancel(self) -> str: self._validate_response(responses[0], 3, "@") return responses[0][2].replace('"', "") - async def send_command( - self, command: str, timeout: int = 60 - ) -> List[MettlerToledoResponse]: + async def send_command(self, command: str, timeout: int = 60) -> List[MettlerToledoResponse]: logger.log(LOG_LEVEL_IO, "[scale] Sent command: %s", command) cmd = command.split()[0] - net = self._mock_weight - self._mock_zero_offset - self._mock_tare + net = round(self._sensor_reading - self.zero_offset - self.tare_weight, 5) + # Identification if cmd == "@": - return [["I4", "A", f'"{self._mock_serial_number}"']] + return [["I4", "A", f'"{self._simulated_serial_number}"']] if cmd == "I1": - levels = "".join(str(l) for l in sorted(self._mock_mt_sics_levels)) + levels = "".join(str(lvl) for lvl in sorted(self._simulated_mt_sics_levels)) return [["I1", "A", f'"{levels}"']] if cmd == "I2": - return [["I2", "A", f'"{self._mock_device_type}"', f"{self._mock_capacity:.4f}", "g"]] + return [ + ["I2", "A", f'"{self._simulated_device_type}"', f"{self._simulated_capacity:.4f}", "g"] + ] if cmd == "I4": - return [["I4", "A", f'"{self._mock_serial_number}"']] + return [["I4", "A", f'"{self._simulated_serial_number}"']] # Zero - if cmd == "Z": - self._mock_zero_offset = self._mock_weight - return [["Z", "A"]] - if cmd == "ZI": - self._mock_zero_offset = self._mock_weight - return [["ZI", "A"]] - if cmd == "ZC": - self._mock_zero_offset = self._mock_weight - return [["ZC", "A"]] + if cmd in ("Z", "ZI", "ZC"): + self.zero_offset = self._sensor_reading + return [[cmd, "A"]] # Tare - if cmd == "T": - self._mock_tare = self._mock_weight - self._mock_zero_offset - return [["T", "S", f"{self._mock_tare:.5f}", "g"]] - if cmd == "TI": - self._mock_tare = self._mock_weight - self._mock_zero_offset - return [["TI", "S", f"{self._mock_tare:.5f}", "g"]] - if cmd == "TC": - self._mock_tare = self._mock_weight - self._mock_zero_offset - return [["TC", "S", f"{self._mock_tare:.5f}", "g"]] + if cmd in ("T", "TI", "TC"): + self.tare_weight = self._sensor_reading - self.zero_offset + return [[cmd, "S", f"{self.tare_weight:.5f}", "g"]] if cmd == "TA": - return [["TA", "A", f"{self._mock_tare:.5f}", "g"]] + return [["TA", "A", f"{self.tare_weight:.5f}", "g"]] if cmd == "TAC": - self._mock_tare = 0.0 + self.tare_weight = 0.0 return [["TAC", "A"]] # Weight reading - if cmd == "S": - return [["S", "S", f"{net:.5f}", "g"]] - if cmd == "SI": - return [["SI", "S", f"{net:.5f}", "g"]] - if cmd == "SC": - return [["SC", "S", f"{net:.5f}", "g"]] + if cmd in ("S", "SI", "SC"): + return [[cmd, "S", f"{net:.5f}", "g"]] # Cancel if cmd == "C": return [["C", "B"], ["C", "A"]] # Display - if cmd == "D": - return [["D", "A"]] - if cmd == "DW": - return [["DW", "A"]] + if cmd in ("D", "DW"): + return [[cmd, "A"]] # Configuration if cmd == "M21": @@ -148,7 +141,7 @@ async def send_command( # Remaining weighing range if cmd == "I50": - remaining = self._mock_capacity - self._mock_weight + remaining = self._simulated_capacity - self._sensor_reading return [ ["I50", "B", "0", f"{remaining:.3f}", "g"], ["I50", "B", "1", "0.000", "g"], From dde0ff3c3016c39dea95a3c7528fe0d6dcc9e7a3 Mon Sep 17 00:00:00 2001 From: Camillo Moschner Date: Sun, 29 Mar 2026 19:34:46 +0100 Subject: [PATCH 07/38] Rich setup logging, LOG_LEVEL_IO for command/response, protocol documentation, notebook logging before setup --- .../scales/mettler-toledo-WXS205SDU.ipynb | 330 +++++++++++++----- pylabrobot/scales/mettler_toledo/backend.py | 11 +- .../scales/mettler_toledo/chatterbox.py | 14 +- pylabrobot/scales/mettler_toledo/protocol.md | 128 +++++++ 4 files changed, 392 insertions(+), 91 deletions(-) create mode 100644 pylabrobot/scales/mettler_toledo/protocol.md diff --git a/docs/user_guide/02_analytical/scales/mettler-toledo-WXS205SDU.ipynb b/docs/user_guide/02_analytical/scales/mettler-toledo-WXS205SDU.ipynb index 549617e7cde..d205718946e 100644 --- a/docs/user_guide/02_analytical/scales/mettler-toledo-WXS205SDU.ipynb +++ b/docs/user_guide/02_analytical/scales/mettler-toledo-WXS205SDU.ipynb @@ -59,10 +59,10 @@ "execution_count": 1, "metadata": { "execution": { - "iopub.execute_input": "2026-03-28T22:45:48.998781Z", - "iopub.status.busy": "2026-03-28T22:45:48.998662Z", - "iopub.status.idle": "2026-03-28T22:45:49.003172Z", - "shell.execute_reply": "2026-03-28T22:45:49.002860Z" + "iopub.execute_input": "2026-03-29T18:25:47.826146Z", + "iopub.status.busy": "2026-03-29T18:25:47.825636Z", + "iopub.status.idle": "2026-03-29T18:25:47.829961Z", + "shell.execute_reply": "2026-03-29T18:25:47.829623Z" } }, "outputs": [], @@ -70,15 +70,64 @@ "protocol_mode = \"simulation\" # \"execution\" or \"simulation\"" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Logging\n", + "\n", + "In Jupyter, PyLabRobot automatically shows INFO-level log messages (including device identity discovered during `setup()`).\n", + "\n", + "To decrease the log level and save logs to disk, set up file logging:\n", + "\n", + "See the [Logging documentation](../../machine-agnostic-features/logging-and-validation/logging.rst) for details." + ] + }, { "cell_type": "code", "execution_count": 2, "metadata": { "execution": { - "iopub.execute_input": "2026-03-28T22:45:49.005211Z", - "iopub.status.busy": "2026-03-28T22:45:49.005086Z", - "iopub.status.idle": "2026-03-28T22:45:49.103735Z", - "shell.execute_reply": "2026-03-28T22:45:49.103532Z" + "iopub.execute_input": "2026-03-29T18:25:47.832128Z", + "iopub.status.busy": "2026-03-29T18:25:47.831971Z", + "iopub.status.idle": "2026-03-29T18:25:47.897021Z", + "shell.execute_reply": "2026-03-29T18:25:47.896801Z" + } + }, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2026-03-29 19:25:47,895 - pylabrobot - INFO - === MT Scale tutorial started ===\n" + ] + } + ], + "source": [ + "import logging\n", + "from pylabrobot.io import LOG_LEVEL_IO\n", + "import pylabrobot\n", + "from datetime import datetime\n", + "\n", + "timestamp = datetime.now().strftime('%Y-%m-%d_%H-%M-%S')\n", + "log_file = f\"./logs/{protocol_mode}/{timestamp}_mt_scale_tutorial.log\"\n", + "\n", + "pylabrobot.verbose(True, level=LOG_LEVEL_IO)\n", + "pylabrobot.setup_logger(log_dir=log_file, level=LOG_LEVEL_IO)\n", + "\n", + "plr_logger = logging.getLogger(\"pylabrobot\")\n", + "plr_logger.info(\"=== MT Scale tutorial started ===\")" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "execution": { + "iopub.execute_input": "2026-03-29T18:25:47.926232Z", + "iopub.status.busy": "2026-03-29T18:25:47.925976Z", + "iopub.status.idle": "2026-03-29T18:25:47.979124Z", + "shell.execute_reply": "2026-03-29T18:25:47.978926Z" } }, "outputs": [ @@ -86,7 +135,11 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-28 22:52:55,695 - pylabrobot - INFO - [scale] Connected (simulation): WXS205SDU (S/N: SIM0000001, capacity: 220.0 g, MT-SICS levels: [0, 1, 2, 3])\n" + "2026-03-29 19:25:47,977 - pylabrobot - INFO - [MT Scale] Connected to Mettler Toledo scale (simulation)\n", + "Device type: WXS205SDU\n", + "Serial number: SIM0000001\n", + "Capacity: 220.0 g\n", + "MT-SICS levels: [0, 1, 2, 3]\n" ] } ], @@ -131,40 +184,6 @@ "```" ] }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Logging\n", - "\n", - "In Jupyter, PyLabRobot automatically shows INFO-level log messages (including device\n", - "identity discovered during `setup()`). To also save logs to disk (including raw serial\n", - "bytes), set up file logging:\n", - "\n", - "See the [Logging documentation](../../machine-agnostic-features/logging-and-validation/logging.rst) for details." - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": { - "execution": { - "iopub.execute_input": "2026-03-28T22:45:49.117755Z", - "iopub.status.busy": "2026-03-28T22:45:49.117656Z", - "iopub.status.idle": "2026-03-28T22:45:49.119949Z", - "shell.execute_reply": "2026-03-28T22:45:49.119750Z" - } - }, - "outputs": [], - "source": [ - "import logging\n", - "from pylabrobot.io import LOG_LEVEL_IO\n", - "import pylabrobot\n", - "\n", - "pylabrobot.verbose(True, level=LOG_LEVEL_IO)\n", - "pylabrobot.setup_logger(log_dir=\"./logs\", level=LOG_LEVEL_IO)" - ] - }, { "cell_type": "markdown", "metadata": {}, @@ -188,10 +207,10 @@ "execution_count": 4, "metadata": { "execution": { - "iopub.execute_input": "2026-03-28T22:45:49.120938Z", - "iopub.status.busy": "2026-03-28T22:45:49.120869Z", - "iopub.status.idle": "2026-03-28T22:45:49.122671Z", - "shell.execute_reply": "2026-03-28T22:45:49.122454Z" + "iopub.execute_input": "2026-03-29T18:25:47.980318Z", + "iopub.status.busy": "2026-03-29T18:25:47.980238Z", + "iopub.status.idle": "2026-03-29T18:25:47.982065Z", + "shell.execute_reply": "2026-03-29T18:25:47.981926Z" } }, "outputs": [ @@ -199,7 +218,14 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-28 22:52:55,705 - pylabrobot - IO - [scale] Sent command: ZC 5000\n" + "2026-03-29 19:25:47,980 - pylabrobot - IO - [MT Scale] Sent command: ZC 5000\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2026-03-29 19:25:47,980 - pylabrobot - IO - [MT Scale] Received response: ZC A\n" ] } ], @@ -233,10 +259,10 @@ "execution_count": 5, "metadata": { "execution": { - "iopub.execute_input": "2026-03-28T22:45:49.123690Z", - "iopub.status.busy": "2026-03-28T22:45:49.123624Z", - "iopub.status.idle": "2026-03-28T22:45:49.125305Z", - "shell.execute_reply": "2026-03-28T22:45:49.125104Z" + "iopub.execute_input": "2026-03-29T18:25:47.983260Z", + "iopub.status.busy": "2026-03-29T18:25:47.983134Z", + "iopub.status.idle": "2026-03-29T18:25:47.985887Z", + "shell.execute_reply": "2026-03-29T18:25:47.985717Z" } }, "outputs": [ @@ -244,7 +270,14 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-28 22:52:55,711 - pylabrobot - IO - [scale] Sent command: TC 5000\n" + "2026-03-29 19:25:47,983 - pylabrobot - IO - [MT Scale] Sent command: TC 5000\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2026-03-29 19:25:47,984 - pylabrobot - IO - [MT Scale] Received response: TC S 50.00000 g\n" ] } ], @@ -267,10 +300,10 @@ "execution_count": 6, "metadata": { "execution": { - "iopub.execute_input": "2026-03-28T22:45:49.126326Z", - "iopub.status.busy": "2026-03-28T22:45:49.126265Z", - "iopub.status.idle": "2026-03-28T22:45:49.128638Z", - "shell.execute_reply": "2026-03-28T22:45:49.128465Z" + "iopub.execute_input": "2026-03-29T18:25:47.986918Z", + "iopub.status.busy": "2026-03-29T18:25:47.986848Z", + "iopub.status.idle": "2026-03-29T18:25:47.989648Z", + "shell.execute_reply": "2026-03-29T18:25:47.989482Z" } }, "outputs": [ @@ -278,7 +311,14 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-28 22:52:55,716 - pylabrobot - IO - [scale] Sent command: TA\n" + "2026-03-29 19:25:47,987 - pylabrobot - IO - [MT Scale] Sent command: TA\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2026-03-29 19:25:47,987 - pylabrobot - IO - [MT Scale] Received response: TA A 50.00000 g\n" ] }, { @@ -311,10 +351,10 @@ "execution_count": 7, "metadata": { "execution": { - "iopub.execute_input": "2026-03-28T22:45:49.129562Z", - "iopub.status.busy": "2026-03-28T22:45:49.129500Z", - "iopub.status.idle": "2026-03-28T22:45:49.131420Z", - "shell.execute_reply": "2026-03-28T22:45:49.131265Z" + "iopub.execute_input": "2026-03-29T18:25:47.990651Z", + "iopub.status.busy": "2026-03-29T18:25:47.990576Z", + "iopub.status.idle": "2026-03-29T18:25:47.994064Z", + "shell.execute_reply": "2026-03-29T18:25:47.993837Z" } }, "outputs": [ @@ -322,7 +362,14 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-28 22:52:55,724 - pylabrobot - IO - [scale] Sent command: SI\n" + "2026-03-29 19:25:47,991 - pylabrobot - IO - [MT Scale] Sent command: SI\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2026-03-29 19:25:47,991 - pylabrobot - IO - [MT Scale] Received response: SI S 0.01060 g\n" ] }, { @@ -358,10 +405,10 @@ "execution_count": 8, "metadata": { "execution": { - "iopub.execute_input": "2026-03-28T22:45:49.132319Z", - "iopub.status.busy": "2026-03-28T22:45:49.132258Z", - "iopub.status.idle": "2026-03-28T22:45:49.135149Z", - "shell.execute_reply": "2026-03-28T22:45:49.134973Z" + "iopub.execute_input": "2026-03-29T18:25:47.995107Z", + "iopub.status.busy": "2026-03-29T18:25:47.995042Z", + "iopub.status.idle": "2026-03-29T18:25:47.998224Z", + "shell.execute_reply": "2026-03-29T18:25:47.998070Z" } }, "outputs": [ @@ -369,9 +416,42 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-28 22:52:55,736 - pylabrobot - IO - [scale] Sent command: Z\n", - "2026-03-28 22:52:55,737 - pylabrobot - IO - [scale] Sent command: TC 5000\n", - "2026-03-28 22:52:55,737 - pylabrobot - IO - [scale] Sent command: SC 5000\n" + "2026-03-29 19:25:47,995 - pylabrobot - IO - [MT Scale] Sent command: Z\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2026-03-29 19:25:47,996 - pylabrobot - IO - [MT Scale] Received response: Z A\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2026-03-29 19:25:47,996 - pylabrobot - IO - [MT Scale] Sent command: TC 5000\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2026-03-29 19:25:47,996 - pylabrobot - IO - [MT Scale] Received response: TC S -0.01060 g\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2026-03-29 19:25:47,996 - pylabrobot - IO - [MT Scale] Sent command: SC 5000\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2026-03-29 19:25:47,996 - pylabrobot - IO - [MT Scale] Received response: SC S 0.01060 g\n" ] }, { @@ -385,14 +465,14 @@ "source": [ "import asyncio\n", "\n", - "# 1. Zero the scale\n", - "await scale.zero(timeout=\"stable\")\n", - "\n", - "# 2. Place container with liquid on scale\n", + "# 1. Place container with liquid on the weighing pan\n", "if protocol_mode == \"simulation\":\n", - " backend.platform_weight = 45.0 # 45g container\n", + " backend.platform_weight = 45.0 # 45g container on weighing pan\n", " backend.sample_weight = 1.06 # ~1 mL of liquid (1000 uL)\n", "\n", + "# 2. Zero the scale (zeroes out container + liquid)\n", + "await scale.zero(timeout=\"stable\")\n", + "\n", "# 3. Aspirate liquid from container (on scale)\n", "# (your liquid handling code here)\n", "if protocol_mode == \"simulation\":\n", @@ -421,6 +501,75 @@ "print(f\"Dispensed {weight_mg:.2f} mg ({volume_uL:.2f} uL)\")" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "---\n", + "### Backend-Specific Methods\n", + "\n", + "The MT-SICS backend exposes additional methods beyond the core scale interface.\n", + "\n", + "#### Remaining weighing range\n", + "\n", + "Query how much capacity is left on the scale, accounting for all current loads\n", + "(pre-load, tare, net). Useful for checking whether adding more weight would\n", + "exceed the scale's maximum capacity. Requires MT-SICS Level 2." + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": { + "execution": { + "iopub.execute_input": "2026-03-29T18:25:47.999162Z", + "iopub.status.busy": "2026-03-29T18:25:47.999104Z", + "iopub.status.idle": "2026-03-29T18:25:48.001562Z", + "shell.execute_reply": "2026-03-29T18:25:48.001322Z" + } + }, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2026-03-29 19:25:47,999 - pylabrobot - IO - [MT Scale] Sent command: I50\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2026-03-29 19:25:47,999 - pylabrobot - IO - [MT Scale] Received response: I50 B 0 173.940 g\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2026-03-29 19:25:47,999 - pylabrobot - IO - [MT Scale] Received response: I50 B 1 0.000 g\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2026-03-29 19:25:48,000 - pylabrobot - IO - [MT Scale] Received response: I50 A 2 173.940 g\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Remaining capacity: 173.9 g\n" + ] + } + ], + "source": [ + "remaining_g = await backend.request_remaining_weighing_range()\n", + "print(f\"Remaining capacity: {remaining_g:.1f} g\")" + ] + }, { "cell_type": "markdown", "metadata": {}, @@ -436,13 +585,13 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": 10, "metadata": { "execution": { - "iopub.execute_input": "2026-03-28T22:45:49.136064Z", - "iopub.status.busy": "2026-03-28T22:45:49.136011Z", - "iopub.status.idle": "2026-03-28T22:45:49.137502Z", - "shell.execute_reply": "2026-03-28T22:45:49.137323Z" + "iopub.execute_input": "2026-03-29T18:25:48.002943Z", + "iopub.status.busy": "2026-03-29T18:25:48.002884Z", + "iopub.status.idle": "2026-03-29T18:25:48.004857Z", + "shell.execute_reply": "2026-03-29T18:25:48.004702Z" } }, "outputs": [], @@ -471,17 +620,26 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": 11, "metadata": { "execution": { - "iopub.execute_input": "2026-03-28T22:45:49.138367Z", - "iopub.status.busy": "2026-03-28T22:45:49.138316Z", - "iopub.status.idle": "2026-03-28T22:45:49.139644Z", - "shell.execute_reply": "2026-03-28T22:45:49.139462Z" + "iopub.execute_input": "2026-03-29T18:25:48.005762Z", + "iopub.status.busy": "2026-03-29T18:25:48.005699Z", + "iopub.status.idle": "2026-03-29T18:25:48.007373Z", + "shell.execute_reply": "2026-03-29T18:25:48.007180Z" } }, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2026-03-29 19:25:48,006 - pylabrobot - INFO - === MT Scale tutorial ended ===\n" + ] + } + ], "source": [ + "plr_logger.info(\"=== MT Scale tutorial ended ===\")\n", "await scale.stop()" ] } diff --git a/pylabrobot/scales/mettler_toledo/backend.py b/pylabrobot/scales/mettler_toledo/backend.py index 2efe60af4b3..dd1e73e86dc 100644 --- a/pylabrobot/scales/mettler_toledo/backend.py +++ b/pylabrobot/scales/mettler_toledo/backend.py @@ -111,7 +111,12 @@ async def setup(self) -> None: self.capacity = await self.request_capacity() logger.info( - "[scale] Connected: %s (S/N: %s, capacity: %.1f g, MT-SICS levels: %s)", + "[MT Scale] Connected to Mettler Toledo scale on %s\n" + "Device type: %s\n" + "Serial number: %s\n" + "Capacity: %.1f g\n" + "MT-SICS levels: %s", + self.io.port, self.device_type, self.serial_number, self.capacity, @@ -257,7 +262,7 @@ async def send_command(self, command: str, timeout: int = 60) -> List[MettlerTol timeout: The timeout in seconds (applies across all response lines). """ - logger.log(LOG_LEVEL_IO, "[scale] Sent command: %s", command) + logger.log(LOG_LEVEL_IO, "[MT Scale] Sent command: %s", command) await self.io.write(command.encode() + b"\r\n") responses: List[MettlerToledoResponse] = [] @@ -271,7 +276,7 @@ async def send_command(self, command: str, timeout: int = 60) -> List[MettlerTol raise TimeoutError("Timeout while waiting for response from scale.") await asyncio.sleep(0.001) - logger.log(LOG_LEVEL_IO, "[scale] Received response: %s", raw_response) + logger.log(LOG_LEVEL_IO, "[MT Scale] Received response: %s", raw_response) response = raw_response.decode("utf-8").strip().split() self._parse_basic_errors(response) responses.append(response) # type: ignore[arg-type] diff --git a/pylabrobot/scales/mettler_toledo/chatterbox.py b/pylabrobot/scales/mettler_toledo/chatterbox.py index 14bb3b2cfa0..8a9142be3f8 100644 --- a/pylabrobot/scales/mettler_toledo/chatterbox.py +++ b/pylabrobot/scales/mettler_toledo/chatterbox.py @@ -75,7 +75,11 @@ async def setup(self) -> None: self.device_type = self._simulated_device_type self.capacity = self._simulated_capacity logger.info( - "[scale] Connected (simulation): %s (S/N: %s, capacity: %.1f g, MT-SICS levels: %s)", + "[MT Scale] Connected to Mettler Toledo scale (simulation)\n" + "Device type: %s\n" + "Serial number: %s\n" + "Capacity: %.1f g\n" + "MT-SICS levels: %s", self.device_type, self.serial_number, self.capacity, @@ -91,7 +95,13 @@ async def cancel(self) -> str: return responses[0][2].replace('"', "") async def send_command(self, command: str, timeout: int = 60) -> List[MettlerToledoResponse]: - logger.log(LOG_LEVEL_IO, "[scale] Sent command: %s", command) + logger.log(LOG_LEVEL_IO, "[MT Scale] Sent command: %s", command) + responses = self._build_response(command) + for resp in responses: + logger.log(LOG_LEVEL_IO, "[MT Scale] Received response: %s", " ".join(resp)) + return responses + + def _build_response(self, command: str) -> List[MettlerToledoResponse]: cmd = command.split()[0] net = round(self._sensor_reading - self.zero_offset - self.tare_weight, 5) diff --git a/pylabrobot/scales/mettler_toledo/protocol.md b/pylabrobot/scales/mettler_toledo/protocol.md new file mode 100644 index 00000000000..53c862b4f6c --- /dev/null +++ b/pylabrobot/scales/mettler_toledo/protocol.md @@ -0,0 +1,128 @@ +# Protocol: MT-SICS (Mettler Toledo Standard Interface Command Set) + + + +## Overview + +| Property | Value | +|----------|-------| +| Protocol name | MT-SICS (Mettler Toledo Standard Interface Command Set) | +| Transport | Serial (RS-232) via USB-to-serial adapter | +| Encoding | ASCII text | +| Baud rate | 9600 | +| Line terminator | CR LF (`\r\n`, 0x0D 0x0A) | +| Direction | Half-duplex (send command, wait for response) | +| Spec document | [MT-SICS Reference Manual](https://web.archive.org/web/20240208213802/https://www.mt.com/dam/product_organizations/industry/apw/generic/11781363_N_MAN_RM_MT-SICS_APW_en.pdf) | + +## Command format (PLR to device) + +``` + [ ...] CR LF +``` + +- Commands are uppercase ASCII +- Parameters separated by spaces +- Quoted strings use `"text"` +- Each command must be followed by CR LF + +Examples: +``` +S\r\n -- read stable weight +ZI\r\n -- zero immediately +M21 0 0\r\n -- set host unit to grams +D "Hello"\r\n -- write text to display +``` + +## Response format (device to PLR) + +### Standard response (single line) + +``` + [ ...] [] CR LF +``` + +The response echoes the command name, followed by a status character, optional data fields, and an optional unit. + +### Status codes + +| Status | Meaning | +|--------|---------| +| `A` | Command executed successfully (final response) | +| `B` | Command not yet terminated, additional responses follow | +| `S` | Stable weight value | +| `D` | Dynamic (unstable) weight value | +| `I` | Command understood but not executable (device busy) | +| `L` | Logical error (parameter not allowed) | +| `+` | Overload (weighing range exceeded) | +| `-` | Underload (weighing pan not in place) | + +### Error responses (no status field) + +``` +ES CR LF -- syntax error (command not recognized) +ET CR LF -- transmission error (parity/break) +EL CR LF -- logical error (command cannot execute) +``` + +These are 2-character responses with no status field or data. + +### Weight response errors + +``` +S S Error CR LF +``` + +The weight value field is replaced with an error code when the device detects a hardware fault. See spec Section 2.1.3.3. + +## Multi-response commands + +Commands that return status `B` send multiple lines. The final line has status `A`. + +Example - I50 (remaining weighing ranges): +``` +PLR sends: I50\r\n +Device sends: I50 B 0 535.141 g\r\n -- RangeNo 0, more lines follow + I50 B 1 -18.973 g\r\n -- RangeNo 1, more lines follow + I50 A 2 335.465 g\r\n -- RangeNo 2, final response +``` + +Example - C (cancel all): +``` +PLR sends: C\r\n +Device sends: C B\r\n -- cancel started + C A\r\n -- cancel complete +``` + +`send_command()` reads all lines until it sees status `A` (or non-`B`). + +## Exceptions to the standard format + +### @ (cancel) response echoes I4, not @ + +``` +PLR sends: @\r\n +Device sends: I4 A "B207696838"\r\n +``` + +The @ command resets the device and responds with the serial number using the I4 response format, not the @ command name. + +### Commands that always fail on WXS205SDU + +`ZC` (zero with timeout) and `TC` (tare with timeout) return `ES` (syntax error) on the WXS205SDU despite being listed in the MT-SICS spec. These commands may work on other MT-SICS devices. + +## Command levels + +MT-SICS commands are grouped into levels. The device reports which levels it supports via the I1 command. + +| Level | Description | Availability | +|-------|-------------|-------------| +| 0 | Basic set: identification, weighing, zero, tare, cancel | Always available | +| 1 | Elementary: display, tare memory, timed commands | Always available | +| 2 | Extended: configuration, device info, diagnostics | Model-dependent | +| 3 | Application-specific: filling, dosing, calibration | Model-dependent | + +See `mt_sics_commands.md` for the full command reference with implementation status. From bc2b08e97446d008a5e0a512c8bed475b1ed7509 Mon Sep 17 00:00:00 2001 From: Camillo Moschner Date: Sun, 29 Mar 2026 21:38:04 +0100 Subject: [PATCH 08/38] MettlerToledoResponse dataclass, measure_temperature M28 command, 15 backend and chatterbox tests --- .../scales/mettler-toledo-WXS205SDU.ipynb | 183 ++++-- pylabrobot/scales/mettler_toledo/__init__.py | 5 +- pylabrobot/scales/mettler_toledo/backend.py | 149 +++-- .../scales/mettler_toledo/backend_tests.py | 145 ++++- .../scales/mettler_toledo/chatterbox.py | 48 +- .../mettler_toledo/hardware_validation.ipynb | 580 ++++++++++++++++++ 6 files changed, 936 insertions(+), 174 deletions(-) create mode 100644 pylabrobot/scales/mettler_toledo/hardware_validation.ipynb diff --git a/docs/user_guide/02_analytical/scales/mettler-toledo-WXS205SDU.ipynb b/docs/user_guide/02_analytical/scales/mettler-toledo-WXS205SDU.ipynb index d205718946e..9e5dda86565 100644 --- a/docs/user_guide/02_analytical/scales/mettler-toledo-WXS205SDU.ipynb +++ b/docs/user_guide/02_analytical/scales/mettler-toledo-WXS205SDU.ipynb @@ -59,10 +59,10 @@ "execution_count": 1, "metadata": { "execution": { - "iopub.execute_input": "2026-03-29T18:25:47.826146Z", - "iopub.status.busy": "2026-03-29T18:25:47.825636Z", - "iopub.status.idle": "2026-03-29T18:25:47.829961Z", - "shell.execute_reply": "2026-03-29T18:25:47.829623Z" + "iopub.execute_input": "2026-03-29T20:12:31.193145Z", + "iopub.status.busy": "2026-03-29T20:12:31.192918Z", + "iopub.status.idle": "2026-03-29T20:12:31.196990Z", + "shell.execute_reply": "2026-03-29T20:12:31.196619Z" } }, "outputs": [], @@ -88,10 +88,10 @@ "execution_count": 2, "metadata": { "execution": { - "iopub.execute_input": "2026-03-29T18:25:47.832128Z", - "iopub.status.busy": "2026-03-29T18:25:47.831971Z", - "iopub.status.idle": "2026-03-29T18:25:47.897021Z", - "shell.execute_reply": "2026-03-29T18:25:47.896801Z" + "iopub.execute_input": "2026-03-29T20:12:31.199055Z", + "iopub.status.busy": "2026-03-29T20:12:31.198866Z", + "iopub.status.idle": "2026-03-29T20:12:31.246756Z", + "shell.execute_reply": "2026-03-29T20:12:31.246514Z" } }, "outputs": [ @@ -99,7 +99,7 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-29 19:25:47,895 - pylabrobot - INFO - === MT Scale tutorial started ===\n" + "2026-03-29 21:12:31,245 - pylabrobot - INFO - === MT Scale tutorial started ===\n" ] } ], @@ -124,10 +124,10 @@ "execution_count": 3, "metadata": { "execution": { - "iopub.execute_input": "2026-03-29T18:25:47.926232Z", - "iopub.status.busy": "2026-03-29T18:25:47.925976Z", - "iopub.status.idle": "2026-03-29T18:25:47.979124Z", - "shell.execute_reply": "2026-03-29T18:25:47.978926Z" + "iopub.execute_input": "2026-03-29T20:12:31.263340Z", + "iopub.status.busy": "2026-03-29T20:12:31.263227Z", + "iopub.status.idle": "2026-03-29T20:12:31.321905Z", + "shell.execute_reply": "2026-03-29T20:12:31.321698Z" } }, "outputs": [ @@ -135,7 +135,7 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-29 19:25:47,977 - pylabrobot - INFO - [MT Scale] Connected to Mettler Toledo scale (simulation)\n", + "2026-03-29 21:12:31,320 - pylabrobot - INFO - [MT Scale] Connected to Mettler Toledo scale (simulation)\n", "Device type: WXS205SDU\n", "Serial number: SIM0000001\n", "Capacity: 220.0 g\n", @@ -207,10 +207,10 @@ "execution_count": 4, "metadata": { "execution": { - "iopub.execute_input": "2026-03-29T18:25:47.980318Z", - "iopub.status.busy": "2026-03-29T18:25:47.980238Z", - "iopub.status.idle": "2026-03-29T18:25:47.982065Z", - "shell.execute_reply": "2026-03-29T18:25:47.981926Z" + "iopub.execute_input": "2026-03-29T20:12:31.323067Z", + "iopub.status.busy": "2026-03-29T20:12:31.322981Z", + "iopub.status.idle": "2026-03-29T20:12:31.324940Z", + "shell.execute_reply": "2026-03-29T20:12:31.324759Z" } }, "outputs": [ @@ -218,14 +218,14 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-29 19:25:47,980 - pylabrobot - IO - [MT Scale] Sent command: ZC 5000\n" + "2026-03-29 21:12:31,323 - pylabrobot - IO - [MT Scale] Sent command: ZC 5000\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ - "2026-03-29 19:25:47,980 - pylabrobot - IO - [MT Scale] Received response: ZC A\n" + "2026-03-29 21:12:31,323 - pylabrobot - IO - [MT Scale] Received response: ZC A \n" ] } ], @@ -259,10 +259,10 @@ "execution_count": 5, "metadata": { "execution": { - "iopub.execute_input": "2026-03-29T18:25:47.983260Z", - "iopub.status.busy": "2026-03-29T18:25:47.983134Z", - "iopub.status.idle": "2026-03-29T18:25:47.985887Z", - "shell.execute_reply": "2026-03-29T18:25:47.985717Z" + "iopub.execute_input": "2026-03-29T20:12:31.325966Z", + "iopub.status.busy": "2026-03-29T20:12:31.325894Z", + "iopub.status.idle": "2026-03-29T20:12:31.327635Z", + "shell.execute_reply": "2026-03-29T20:12:31.327454Z" } }, "outputs": [ @@ -270,14 +270,14 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-29 19:25:47,983 - pylabrobot - IO - [MT Scale] Sent command: TC 5000\n" + "2026-03-29 21:12:31,326 - pylabrobot - IO - [MT Scale] Sent command: TC 5000\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ - "2026-03-29 19:25:47,984 - pylabrobot - IO - [MT Scale] Received response: TC S 50.00000 g\n" + "2026-03-29 21:12:31,326 - pylabrobot - IO - [MT Scale] Received response: TC S 50.00000 g\n" ] } ], @@ -300,10 +300,10 @@ "execution_count": 6, "metadata": { "execution": { - "iopub.execute_input": "2026-03-29T18:25:47.986918Z", - "iopub.status.busy": "2026-03-29T18:25:47.986848Z", - "iopub.status.idle": "2026-03-29T18:25:47.989648Z", - "shell.execute_reply": "2026-03-29T18:25:47.989482Z" + "iopub.execute_input": "2026-03-29T20:12:31.328605Z", + "iopub.status.busy": "2026-03-29T20:12:31.328533Z", + "iopub.status.idle": "2026-03-29T20:12:31.331657Z", + "shell.execute_reply": "2026-03-29T20:12:31.331493Z" } }, "outputs": [ @@ -311,14 +311,14 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-29 19:25:47,987 - pylabrobot - IO - [MT Scale] Sent command: TA\n" + "2026-03-29 21:12:31,328 - pylabrobot - IO - [MT Scale] Sent command: TA\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ - "2026-03-29 19:25:47,987 - pylabrobot - IO - [MT Scale] Received response: TA A 50.00000 g\n" + "2026-03-29 21:12:31,329 - pylabrobot - IO - [MT Scale] Received response: TA A 50.00000 g\n" ] }, { @@ -351,10 +351,10 @@ "execution_count": 7, "metadata": { "execution": { - "iopub.execute_input": "2026-03-29T18:25:47.990651Z", - "iopub.status.busy": "2026-03-29T18:25:47.990576Z", - "iopub.status.idle": "2026-03-29T18:25:47.994064Z", - "shell.execute_reply": "2026-03-29T18:25:47.993837Z" + "iopub.execute_input": "2026-03-29T20:12:31.332589Z", + "iopub.status.busy": "2026-03-29T20:12:31.332525Z", + "iopub.status.idle": "2026-03-29T20:12:31.334570Z", + "shell.execute_reply": "2026-03-29T20:12:31.334415Z" } }, "outputs": [ @@ -362,14 +362,14 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-29 19:25:47,991 - pylabrobot - IO - [MT Scale] Sent command: SI\n" + "2026-03-29 21:12:31,332 - pylabrobot - IO - [MT Scale] Sent command: SI\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ - "2026-03-29 19:25:47,991 - pylabrobot - IO - [MT Scale] Received response: SI S 0.01060 g\n" + "2026-03-29 21:12:31,333 - pylabrobot - IO - [MT Scale] Received response: SI S 0.01060 g\n" ] }, { @@ -405,10 +405,10 @@ "execution_count": 8, "metadata": { "execution": { - "iopub.execute_input": "2026-03-29T18:25:47.995107Z", - "iopub.status.busy": "2026-03-29T18:25:47.995042Z", - "iopub.status.idle": "2026-03-29T18:25:47.998224Z", - "shell.execute_reply": "2026-03-29T18:25:47.998070Z" + "iopub.execute_input": "2026-03-29T20:12:31.335599Z", + "iopub.status.busy": "2026-03-29T20:12:31.335545Z", + "iopub.status.idle": "2026-03-29T20:12:31.338458Z", + "shell.execute_reply": "2026-03-29T20:12:31.338291Z" } }, "outputs": [ @@ -416,42 +416,42 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-29 19:25:47,995 - pylabrobot - IO - [MT Scale] Sent command: Z\n" + "2026-03-29 21:12:31,336 - pylabrobot - IO - [MT Scale] Sent command: Z\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ - "2026-03-29 19:25:47,996 - pylabrobot - IO - [MT Scale] Received response: Z A\n" + "2026-03-29 21:12:31,336 - pylabrobot - IO - [MT Scale] Received response: Z A \n" ] }, { "name": "stderr", "output_type": "stream", "text": [ - "2026-03-29 19:25:47,996 - pylabrobot - IO - [MT Scale] Sent command: TC 5000\n" + "2026-03-29 21:12:31,336 - pylabrobot - IO - [MT Scale] Sent command: TC 5000\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ - "2026-03-29 19:25:47,996 - pylabrobot - IO - [MT Scale] Received response: TC S -0.01060 g\n" + "2026-03-29 21:12:31,336 - pylabrobot - IO - [MT Scale] Received response: TC S -0.01060 g\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ - "2026-03-29 19:25:47,996 - pylabrobot - IO - [MT Scale] Sent command: SC 5000\n" + "2026-03-29 21:12:31,337 - pylabrobot - IO - [MT Scale] Sent command: SC 5000\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ - "2026-03-29 19:25:47,996 - pylabrobot - IO - [MT Scale] Received response: SC S 0.01060 g\n" + "2026-03-29 21:12:31,337 - pylabrobot - IO - [MT Scale] Received response: SC S 0.01060 g\n" ] }, { @@ -522,10 +522,10 @@ "execution_count": 9, "metadata": { "execution": { - "iopub.execute_input": "2026-03-29T18:25:47.999162Z", - "iopub.status.busy": "2026-03-29T18:25:47.999104Z", - "iopub.status.idle": "2026-03-29T18:25:48.001562Z", - "shell.execute_reply": "2026-03-29T18:25:48.001322Z" + "iopub.execute_input": "2026-03-29T20:12:31.339353Z", + "iopub.status.busy": "2026-03-29T20:12:31.339299Z", + "iopub.status.idle": "2026-03-29T20:12:31.341336Z", + "shell.execute_reply": "2026-03-29T20:12:31.341172Z" } }, "outputs": [ @@ -533,28 +533,28 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-29 19:25:47,999 - pylabrobot - IO - [MT Scale] Sent command: I50\n" + "2026-03-29 21:12:31,339 - pylabrobot - IO - [MT Scale] Sent command: I50\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ - "2026-03-29 19:25:47,999 - pylabrobot - IO - [MT Scale] Received response: I50 B 0 173.940 g\n" + "2026-03-29 21:12:31,339 - pylabrobot - IO - [MT Scale] Received response: I50 B 0 173.940 g\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ - "2026-03-29 19:25:47,999 - pylabrobot - IO - [MT Scale] Received response: I50 B 1 0.000 g\n" + "2026-03-29 21:12:31,340 - pylabrobot - IO - [MT Scale] Received response: I50 B 1 0.000 g\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ - "2026-03-29 19:25:48,000 - pylabrobot - IO - [MT Scale] Received response: I50 A 2 173.940 g\n" + "2026-03-29 21:12:31,340 - pylabrobot - IO - [MT Scale] Received response: I50 A 2 173.940 g\n" ] }, { @@ -570,6 +570,55 @@ "print(f\"Remaining capacity: {remaining_g:.1f} g\")" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Temperature\n", + "\n", + "Read the current temperature from the scale's internal sensor. Useful for gravimetric\n", + "verification where temperature affects liquid density and evaporation rate. Requires MT-SICS Level 2." + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": { + "execution": { + "iopub.execute_input": "2026-03-29T20:12:31.342219Z", + "iopub.status.busy": "2026-03-29T20:12:31.342163Z", + "iopub.status.idle": "2026-03-29T20:12:31.343978Z", + "shell.execute_reply": "2026-03-29T20:12:31.343829Z" + } + }, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2026-03-29 21:12:31,342 - pylabrobot - IO - [MT Scale] Sent command: M28\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2026-03-29 21:12:31,342 - pylabrobot - IO - [MT Scale] Received response: M28 A 1 22.5\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Scale temperature: 22.5 C\n" + ] + } + ], + "source": [ + "temp_c = await backend.measure_temperature()\n", + "print(f\"Scale temperature: {temp_c} C\")" + ] + }, { "cell_type": "markdown", "metadata": {}, @@ -585,13 +634,13 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": 11, "metadata": { "execution": { - "iopub.execute_input": "2026-03-29T18:25:48.002943Z", - "iopub.status.busy": "2026-03-29T18:25:48.002884Z", - "iopub.status.idle": "2026-03-29T18:25:48.004857Z", - "shell.execute_reply": "2026-03-29T18:25:48.004702Z" + "iopub.execute_input": "2026-03-29T20:12:31.344856Z", + "iopub.status.busy": "2026-03-29T20:12:31.344801Z", + "iopub.status.idle": "2026-03-29T20:12:31.346476Z", + "shell.execute_reply": "2026-03-29T20:12:31.346247Z" } }, "outputs": [], @@ -620,13 +669,13 @@ }, { "cell_type": "code", - "execution_count": 11, + "execution_count": 12, "metadata": { "execution": { - "iopub.execute_input": "2026-03-29T18:25:48.005762Z", - "iopub.status.busy": "2026-03-29T18:25:48.005699Z", - "iopub.status.idle": "2026-03-29T18:25:48.007373Z", - "shell.execute_reply": "2026-03-29T18:25:48.007180Z" + "iopub.execute_input": "2026-03-29T20:12:31.347367Z", + "iopub.status.busy": "2026-03-29T20:12:31.347314Z", + "iopub.status.idle": "2026-03-29T20:12:31.348820Z", + "shell.execute_reply": "2026-03-29T20:12:31.348661Z" } }, "outputs": [ @@ -634,7 +683,7 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-29 19:25:48,006 - pylabrobot - INFO - === MT Scale tutorial ended ===\n" + "2026-03-29 21:12:31,347 - pylabrobot - INFO - === MT Scale tutorial ended ===\n" ] } ], diff --git a/pylabrobot/scales/mettler_toledo/__init__.py b/pylabrobot/scales/mettler_toledo/__init__.py index 1204bc7a54b..5c43e63a1c9 100644 --- a/pylabrobot/scales/mettler_toledo/__init__.py +++ b/pylabrobot/scales/mettler_toledo/__init__.py @@ -1,5 +1,8 @@ """Mettler Toledo scale backend using the MT-SICS protocol.""" -from pylabrobot.scales.mettler_toledo.backend import MettlerToledoWXS205SDUBackend +from pylabrobot.scales.mettler_toledo.backend import ( + MettlerToledoResponse, + MettlerToledoWXS205SDUBackend, +) from pylabrobot.scales.mettler_toledo.chatterbox import MettlerToledoChatterboxBackend from pylabrobot.scales.mettler_toledo.errors import MettlerToledoError diff --git a/pylabrobot/scales/mettler_toledo/backend.py b/pylabrobot/scales/mettler_toledo/backend.py index dd1e73e86dc..028befe7f4e 100644 --- a/pylabrobot/scales/mettler_toledo/backend.py +++ b/pylabrobot/scales/mettler_toledo/backend.py @@ -7,6 +7,7 @@ import logging import time import warnings +from dataclasses import dataclass, field from typing import Any, Callable, List, Literal, Optional, Set, TypeVar, Union from pylabrobot.io.serial import Serial @@ -16,7 +17,18 @@ logger = logging.getLogger("pylabrobot") -MettlerToledoResponse = List[str] + +@dataclass +class MettlerToledoResponse: + """A single parsed MT-SICS response line. + + Format: [ ...] CR LF + See protocol.md for full format description. + """ + + command: str + status: str + data: List[str] = field(default_factory=list) F = TypeVar("F", bound=Callable[..., Any]) @@ -143,23 +155,26 @@ async def _query_mt_sics_levels(self) -> Set[int]: responses = await self.send_command("I1") # I1 A "0123" "2.00" "2.20" "1.00" "1.50" self._validate_response(responses[0], 3, "I1") - level_string = responses[0][2].replace('"', "") + level_string = responses[0].data[0].replace('"', "") return {int(c) for c in level_string} # === Response parsing === @staticmethod - def _validate_response(response: List[str], min_length: int, command: str) -> None: - """Validate that a parsed response has the expected minimum number of fields. + def _validate_response(response: MettlerToledoResponse, min_fields: int, command: str) -> None: + """Validate that a parsed response has the expected minimum total field count. + + min_fields counts all fields (command + status + data). For example, + a weight response "S S 0.00006 g" has 4 fields total. Raises: - MettlerToledoError: if the response is too short. + MettlerToledoError: if the response has fewer fields than expected. """ - if len(response) < min_length: + total = 1 + (1 if response.status else 0) + len(response.data) + if total < min_fields: raise MettlerToledoError( title="Unexpected response", - message=f"Expected at least {min_length} fields for '{command}', " - f"got {len(response)}: {' '.join(response)}", + message=f"Expected at least {min_fields} fields for '{command}', got {total}: {response}", ) @staticmethod @@ -175,60 +190,43 @@ def _validate_unit(unit: str, command: str) -> None: message=f"Expected 'g' for '{command}', got '{unit}'", ) - def _parse_basic_errors(self, response: List[str]) -> None: + def _parse_basic_errors(self, response: MettlerToledoResponse) -> None: """Helper function for parsing basic errors that are common to many commands. If an error is detected, a 'MettlerToledoError' exception is raised. - These are in the first place of the response: - - ES: syntax error: The weigh module/balance has not recognized the received command or the - command is not allowed - - ET: transmission error: The weigh module/balance has received a "faulty" command, e.g. owing - to a parity error or interface break - - EL: logical error: The weigh module/balance can not execute the received command - - These are in the second place of the response (MT-SICS spec p.10, sec 2.1.3.1): - - A: Command executed successfully - - B: Command not yet terminated, additional responses following - - I: Internal error (e.g. balance not ready yet) - - L: Logical error (e.g. parameter not allowed) - - +: Balance in overload range - - -: Balance in underload range + Error commands (ES, ET, EL) have status="" and no data. + Status codes I, L, +, - indicate command-specific errors. Note: B status (multi-response) is handled by send_command, which reads all lines until status A. Each line is validated through this method individually. """ - if len(response) == 0: - raise MettlerToledoError( - title="Empty response", - message="Received empty response from scale", - ) - - # General error messages are single-token: ES, ET, EL - if response[0] == "ES": + # General error messages: ES, ET, EL (status is "" for these) + if response.command == "ES": raise MettlerToledoError.syntax_error() - if response[0] == "ET": + if response.command == "ET": raise MettlerToledoError.transmission_error() - if response[0] == "EL": + if response.command == "EL": raise MettlerToledoError.logical_error() - if len(response) < 2: - raise MettlerToledoError( - title="Unexpected response", - message=f"Expected at least 2 fields, got: {' '.join(response)}", - ) - - if response[1] == "I": + # Status code errors + if response.status == "I": raise MettlerToledoError.executing_another_command() - if response[1] == "L": + if response.status == "L": raise MettlerToledoError.incorrect_parameter() - if response[1] == "+": + if response.status == "+": raise MettlerToledoError.overload() - if response[1] == "-": + if response.status == "-": raise MettlerToledoError.underload() - if len(response) >= 4 and response[0] == "S" and response[1] == "S" and response[2] == "Error": - error_code = response[3] + # Weight response error: S S Error + if ( + response.command == "S" + and response.status == "S" + and len(response.data) >= 2 + and response.data[0] == "Error" + ): + error_code = response.data[1] code, source = error_code[:-1], error_code[-1] from_terminal = source == "t" if code == "1": @@ -277,12 +275,18 @@ async def send_command(self, command: str, timeout: int = 60) -> List[MettlerTol await asyncio.sleep(0.001) logger.log(LOG_LEVEL_IO, "[MT Scale] Received response: %s", raw_response) - response = raw_response.decode("utf-8").strip().split() + fields = raw_response.decode("utf-8").strip().split() + if len(fields) >= 2: + response = MettlerToledoResponse(command=fields[0], status=fields[1], data=fields[2:]) + elif len(fields) == 1: + response = MettlerToledoResponse(command=fields[0], status="", data=[]) + else: + response = MettlerToledoResponse(command="", status="", data=[]) self._parse_basic_errors(response) - responses.append(response) # type: ignore[arg-type] + responses.append(response) # Status B means more responses follow; anything else (A, etc.) is final - if len(response) < 2 or response[1] != "B": + if response.status != "B": break return responses @@ -304,7 +308,7 @@ async def cancel(self) -> str: responses = await self.send_command("@") # @ responds with I4-style: I4 A "" self._validate_response(responses[0], 3, "@") - return responses[0][2].replace('"', "") + return responses[0].data[0].replace('"', "") async def cancel_all(self) -> None: """C - Cancel all active and pending interface commands. @@ -319,7 +323,7 @@ async def cancel_all(self) -> None: responses = await self.send_command("C") # send_command reads both C B (started) and C A (complete) automatically self._validate_response(responses[0], 2, "C") - if responses[0][1] == "E": + if responses[0].status == "E": raise MettlerToledoError( title="Error while canceling", message=f"C command returned error: {responses[0]}", @@ -331,22 +335,22 @@ async def request_serial_number(self) -> str: """Get the serial number of the scale. (I4 command)""" responses = await self.send_command("I4") self._validate_response(responses[0], 3, "I4") - return responses[0][2].replace('"', "") + return responses[0].data[0].replace('"', "") async def request_device_type(self) -> str: """Query the device type string. (I2 command)""" responses = await self.send_command("I2") - # After split(): ["I2", "A", '"WXS205SDU"', "220.0000", "g"] + # data: ['"WXS205SDU"', "220.0000", "g"] self._validate_response(responses[0], 5, "I2") - return responses[0][2].replace('"', "") + return responses[0].data[0].replace('"', "") async def request_capacity(self) -> float: """Query the maximum weighing capacity in grams. (I2 command)""" responses = await self.send_command("I2") - # After split(): ["I2", "A", '"WXS205SDU"', "220.0000", "g"] + # data: ['"WXS205SDU"', "220.0000", "g"] self._validate_response(responses[0], 5, "I2") - self._validate_unit(responses[0][4], "I2") - return float(responses[0][3]) + self._validate_unit(responses[0].data[2], "I2") + return float(responses[0].data[1]) @requires_mt_sics_level(2) async def request_remaining_weighing_range(self) -> float: @@ -365,8 +369,8 @@ async def request_remaining_weighing_range(self) -> float: # responses[1]: I50 B 1 (RangeNo 1 = internal adjustment range) # responses[2]: I50 A 2 (RangeNo 2 = external adjustment range) self._validate_response(responses[0], 5, "I50") - self._validate_unit(responses[0][4], "I50") - return float(responses[0][3]) + self._validate_unit(responses[0].data[2], "I50") + return float(responses[0].data[1]) # # Zero commands # # @@ -461,8 +465,8 @@ async def request_tare_weight(self) -> float: responses = await self.send_command("TA") self._validate_response(responses[0], 4, "TA") - self._validate_unit(responses[0][3], "TA") - return float(responses[0][2]) + self._validate_unit(responses[0].data[1], "TA") + return float(responses[0].data[0]) async def clear_tare(self) -> List[MettlerToledoResponse]: """TAC - Clear tare weight value (MEM-WRITE command)""" @@ -481,8 +485,8 @@ async def read_stable_weight(self) -> float: responses = await self.send_command("S") self._validate_response(responses[0], 4, "S") - self._validate_unit(responses[0][3], "S") - return float(responses[0][2]) + self._validate_unit(responses[0].data[1], "S") + return float(responses[0].data[0]) async def read_dynamic_weight(self, timeout: float) -> float: """Read a stable weight value from the machine within a given timeout, or @@ -496,8 +500,8 @@ async def read_dynamic_weight(self, timeout: float) -> float: responses = await self.send_command(f"SC {timeout}") self._validate_response(responses[0], 4, "SC") - self._validate_unit(responses[0][3], "SC") - return float(responses[0][2]) + self._validate_unit(responses[0].data[1], "SC") + return float(responses[0].data[0]) async def read_weight_value_immediately(self) -> float: """Read a weight value immediately from the scale. (MEASUREMENT command) @@ -508,8 +512,8 @@ async def read_weight_value_immediately(self) -> float: responses = await self.send_command("SI") self._validate_response(responses[0], 4, "SI") - self._validate_unit(responses[0][3], "SI") - return float(responses[0][2]) + self._validate_unit(responses[0].data[1], "SI") + return float(responses[0].data[0]) async def read_weight(self, timeout: Union[Literal["stable"], float, int] = "stable") -> float: """High level function to read a weight value from the scale. (MEASUREMENT command) @@ -552,6 +556,19 @@ async def set_host_unit_grams(self) -> List[MettlerToledoResponse]: """Set the host output unit to grams. (M21 command)""" return await self.send_command("M21 0 0") + @requires_mt_sics_level(2) + async def measure_temperature(self) -> float: + """Query the current temperature from the scale's internal sensor in degrees C. (M28 command) + + The number of temperature sensors depends on the product. This method returns + the value from the first sensor. Useful for gravimetric verification where + temperature affects liquid density and evaporation rate. + """ + responses = await self.send_command("M28") + # M28 A 1 22.5 (single sensor) or M28 B 1 22.5 ... M28 A 2 23.0 (multi-sensor) + self._validate_response(responses[0], 4, "M28") + return float(responses[0].data[1]) + # # # Deprecated alias with warning # # # # TODO: remove after 2026-03 diff --git a/pylabrobot/scales/mettler_toledo/backend_tests.py b/pylabrobot/scales/mettler_toledo/backend_tests.py index bbad21a53d1..72b85464f19 100644 --- a/pylabrobot/scales/mettler_toledo/backend_tests.py +++ b/pylabrobot/scales/mettler_toledo/backend_tests.py @@ -1,74 +1,175 @@ -"""Tests for MT-SICS response parsing and validation.""" +"""Tests for MT-SICS response parsing, validation, and chatterbox protocol simulation.""" import unittest -from pylabrobot.scales.mettler_toledo.backend import MettlerToledoWXS205SDUBackend +from pylabrobot.scales.mettler_toledo.backend import ( + MettlerToledoResponse, + MettlerToledoWXS205SDUBackend, +) +from pylabrobot.scales.mettler_toledo.chatterbox import MettlerToledoChatterboxBackend from pylabrobot.scales.mettler_toledo.errors import MettlerToledoError +from pylabrobot.scales.scale import Scale + +R = MettlerToledoResponse class MTSICSResponseParsingTests(unittest.TestCase): - """Tests for MT-SICS response parsing - no hardware needed.""" + """Tests for response parsing helpers - no hardware or chatterbox needed.""" def setUp(self): self.backend = MettlerToledoWXS205SDUBackend.__new__(MettlerToledoWXS205SDUBackend) def test_parse_errors_ES_ET_EL(self): + """General error codes (ES, ET, EL) must raise the correct MettlerToledoError. + These are the first line of defense against protocol-level failures.""" with self.assertRaises(MettlerToledoError) as ctx: - self.backend._parse_basic_errors(["ES"]) + self.backend._parse_basic_errors(R("ES", "")) self.assertIn("Syntax error", str(ctx.exception)) with self.assertRaises(MettlerToledoError) as ctx: - self.backend._parse_basic_errors(["ET"]) + self.backend._parse_basic_errors(R("ET", "")) self.assertIn("Transmission error", str(ctx.exception)) with self.assertRaises(MettlerToledoError) as ctx: - self.backend._parse_basic_errors(["EL"]) + self.backend._parse_basic_errors(R("EL", "")) self.assertIn("Logical error", str(ctx.exception)) def test_parse_errors_status_codes(self): + """Command-specific status codes (I, L, +, -) must raise descriptive errors. + These catch device-busy, bad parameters, and overload/underload conditions.""" with self.assertRaises(MettlerToledoError) as ctx: - self.backend._parse_basic_errors(["S", "I"]) + self.backend._parse_basic_errors(R("S", "I")) self.assertIn("not executable at present", str(ctx.exception)) with self.assertRaises(MettlerToledoError) as ctx: - self.backend._parse_basic_errors(["S", "L"]) + self.backend._parse_basic_errors(R("S", "L")) self.assertIn("incorrect parameter", str(ctx.exception)) with self.assertRaises(MettlerToledoError) as ctx: - self.backend._parse_basic_errors(["S", "+"]) + self.backend._parse_basic_errors(R("S", "+")) self.assertIn("overload", str(ctx.exception)) with self.assertRaises(MettlerToledoError) as ctx: - self.backend._parse_basic_errors(["S", "-"]) + self.backend._parse_basic_errors(R("S", "-")) self.assertIn("underload", str(ctx.exception)) def test_validate_response_rejects_short(self): + """Responses with fewer fields than expected must be rejected. + Prevents silent IndexError when accessing data fields.""" with self.assertRaises(MettlerToledoError): - MettlerToledoWXS205SDUBackend._validate_response(["I4", "A"], 3, "I4") + MettlerToledoWXS205SDUBackend._validate_response(R("I4", "A"), 3, "I4") # should not raise - MettlerToledoWXS205SDUBackend._validate_response(["I4", "A", '"B207696838"'], 3, "I4") + MettlerToledoWXS205SDUBackend._validate_response(R("I4", "A", ['"B207696838"']), 3, "I4") def test_validate_unit_rejects_wrong(self): + """Non-gram unit responses must be rejected. + The backend assumes grams throughout - a wrong unit would produce wrong values.""" with self.assertRaises(MettlerToledoError): MettlerToledoWXS205SDUBackend._validate_unit("kg", "S") # should not raise MettlerToledoWXS205SDUBackend._validate_unit("g", "S") - def test_parse_errors_handles_edge_cases(self): - # empty response - with self.assertRaises(MettlerToledoError) as ctx: - self.backend._parse_basic_errors([]) - self.assertIn("Empty response", str(ctx.exception)) + def test_parse_errors_passes_valid_success(self): + """A valid success response (status A) must not raise. + Ensures the happy path is not accidentally blocked.""" + self.backend._parse_basic_errors(R("Z", "A")) - # single non-error token + def test_parse_errors_weight_response_error(self): + """S S Error responses (hardware faults detected during weighing) must raise. + These indicate boot errors, EEPROM failures, etc. on the physical device.""" with self.assertRaises(MettlerToledoError) as ctx: - self.backend._parse_basic_errors(["Z"]) - self.assertIn("Expected at least 2 fields", str(ctx.exception)) + self.backend._parse_basic_errors(R("S", "S", ["Error", "10b"])) + self.assertIn("EEPROM error", str(ctx.exception)) + + def test_dataclass_construction(self): + """MettlerToledoResponse dataclass must correctly separate command, status, and data. + This is the foundation for all response access throughout the backend.""" + resp = R("S", "S", ["0.00006", "g"]) + self.assertEqual(resp.command, "S") + self.assertEqual(resp.status, "S") + self.assertEqual(resp.data, ["0.00006", "g"]) + + # Error-only response (no status) + resp = R("ES", "") + self.assertEqual(resp.command, "ES") + self.assertEqual(resp.status, "") + self.assertEqual(resp.data, []) + + +class MTSICSChatterboxTests(unittest.IsolatedAsyncioTestCase): + """Tests for the MT-SICS protocol chatterbox. + These exercise the full stack: send_command -> mock response -> parse -> validate -> return. + Catches dataclass construction bugs, index mapping errors, and response format mismatches.""" + + async def asyncSetUp(self): + self.backend = MettlerToledoChatterboxBackend() + self.scale = Scale( + name="test_scale", + backend=self.backend, + size_x=0, + size_y=0, + size_z=0, + ) + await self.scale.setup() + + async def test_setup_populates_device_identity(self): + """setup() must populate device_type, serial_number, capacity, and MT-SICS levels. + If any of these are missing, downstream methods that depend on them will fail.""" + self.assertEqual(self.backend.device_type, "WXS205SDU") + self.assertEqual(self.backend.serial_number, "SIM0000001") + self.assertEqual(self.backend.capacity, 220.0) + self.assertIn(0, self.backend._mt_sics_levels) + + async def test_tare_workflow_through_protocol(self): + """Full tare workflow through the MT-SICS protocol layer. + Verifies that mock responses are correctly constructed, parsed through + _parse_basic_errors, and returned as the right value.""" + self.backend.platform_weight = 50.0 + await self.scale.tare() + self.backend.sample_weight = 10.0 + weight = await self.scale.read_weight() + self.assertEqual(weight, 10.0) + + async def test_read_weight_returns_correct_value(self): + """read_weight must return the net weight (sensor - zero_offset - tare). + Tests the data[0] index mapping after the dataclass change.""" + self.backend.platform_weight = 25.0 + weight = await self.scale.read_weight(timeout=0) + self.assertEqual(weight, 25.0) + + async def test_request_capacity_from_i2(self): + """request_capacity must parse the capacity from the I2 response data[1] field. + Wrong index mapping would return the device type string instead of a float.""" + capacity = await self.backend.request_capacity() + self.assertEqual(capacity, 220.0) + + async def test_i50_multi_response(self): + """I50 returns 3 response lines (B, B, A). send_command must read all of them + and return the correct remaining range from the first line.""" + self.backend.platform_weight = 50.0 + remaining = await self.backend.request_remaining_weighing_range() + self.assertEqual(remaining, 170.0) + + async def test_cancel_returns_serial_number(self): + """cancel() sends @ which responds with I4-style (command echo is I4, not @). + Must correctly parse the serial number despite the unusual response format.""" + sn = await self.backend.cancel() + self.assertEqual(sn, "SIM0000001") + + async def test_unknown_command_returns_syntax_error(self): + """Unknown commands must return ES (syntax error) response. + Ensures the chatterbox correctly simulates the device rejecting invalid commands.""" + with self.assertRaises(MettlerToledoError) as ctx: + await self.backend.send_command("XYZNOTREAL") + self.assertIn("Syntax error", str(ctx.exception)) - # valid success - should not raise - self.backend._parse_basic_errors(["Z", "A"]) + async def test_measure_temperature(self): + """measure_temperature must return a float from the M28 response. + Requires Level 2 decorator to not block the call.""" + temp = await self.backend.measure_temperature() + self.assertEqual(temp, 22.5) if __name__ == "__main__": diff --git a/pylabrobot/scales/mettler_toledo/chatterbox.py b/pylabrobot/scales/mettler_toledo/chatterbox.py index 8a9142be3f8..3222835b208 100644 --- a/pylabrobot/scales/mettler_toledo/chatterbox.py +++ b/pylabrobot/scales/mettler_toledo/chatterbox.py @@ -92,71 +92,83 @@ async def stop(self) -> None: async def cancel(self) -> str: responses = await self.send_command("@") self._validate_response(responses[0], 3, "@") - return responses[0][2].replace('"', "") + return responses[0].data[0].replace('"', "") async def send_command(self, command: str, timeout: int = 60) -> List[MettlerToledoResponse]: logger.log(LOG_LEVEL_IO, "[MT Scale] Sent command: %s", command) responses = self._build_response(command) for resp in responses: - logger.log(LOG_LEVEL_IO, "[MT Scale] Received response: %s", " ".join(resp)) + logger.log( + LOG_LEVEL_IO, + "[MT Scale] Received response: %s %s %s", + resp.command, + resp.status, + " ".join(resp.data), + ) + self._parse_basic_errors(resp) return responses def _build_response(self, command: str) -> List[MettlerToledoResponse]: + R = MettlerToledoResponse cmd = command.split()[0] net = round(self._sensor_reading - self.zero_offset - self.tare_weight, 5) # Identification if cmd == "@": - return [["I4", "A", f'"{self._simulated_serial_number}"']] + return [R("I4", "A", [f'"{self._simulated_serial_number}"'])] if cmd == "I1": levels = "".join(str(lvl) for lvl in sorted(self._simulated_mt_sics_levels)) - return [["I1", "A", f'"{levels}"']] + return [R("I1", "A", [f'"{levels}"'])] if cmd == "I2": return [ - ["I2", "A", f'"{self._simulated_device_type}"', f"{self._simulated_capacity:.4f}", "g"] + R("I2", "A", [f'"{self._simulated_device_type}"', f"{self._simulated_capacity:.4f}", "g"]) ] if cmd == "I4": - return [["I4", "A", f'"{self._simulated_serial_number}"']] + return [R("I4", "A", [f'"{self._simulated_serial_number}"'])] # Zero if cmd in ("Z", "ZI", "ZC"): self.zero_offset = self._sensor_reading - return [[cmd, "A"]] + return [R(cmd, "A")] # Tare if cmd in ("T", "TI", "TC"): self.tare_weight = self._sensor_reading - self.zero_offset - return [[cmd, "S", f"{self.tare_weight:.5f}", "g"]] + return [R(cmd, "S", [f"{self.tare_weight:.5f}", "g"])] if cmd == "TA": - return [["TA", "A", f"{self.tare_weight:.5f}", "g"]] + return [R("TA", "A", [f"{self.tare_weight:.5f}", "g"])] if cmd == "TAC": self.tare_weight = 0.0 - return [["TAC", "A"]] + return [R("TAC", "A")] # Weight reading if cmd in ("S", "SI", "SC"): - return [[cmd, "S", f"{net:.5f}", "g"]] + return [R(cmd, "S", [f"{net:.5f}", "g"])] # Cancel if cmd == "C": - return [["C", "B"], ["C", "A"]] + return [R("C", "B"), R("C", "A")] # Display if cmd in ("D", "DW"): - return [[cmd, "A"]] + return [R(cmd, "A")] # Configuration if cmd == "M21": - return [["M21", "A"]] + return [R("M21", "A")] + + # Temperature + if cmd == "M28": + return [R("M28", "A", ["1", "22.5"])] # Remaining weighing range if cmd == "I50": remaining = self._simulated_capacity - self._sensor_reading return [ - ["I50", "B", "0", f"{remaining:.3f}", "g"], - ["I50", "B", "1", "0.000", "g"], - ["I50", "A", "2", f"{remaining:.3f}", "g"], + R("I50", "B", ["0", f"{remaining:.3f}", "g"]), + R("I50", "B", ["1", "0.000", "g"]), + R("I50", "A", ["2", f"{remaining:.3f}", "g"]), ] # Unknown command - return [["ES"]] + return [R("ES", "")] diff --git a/pylabrobot/scales/mettler_toledo/hardware_validation.ipynb b/pylabrobot/scales/mettler_toledo/hardware_validation.ipynb new file mode 100644 index 00000000000..0acc7a3b2c4 --- /dev/null +++ b/pylabrobot/scales/mettler_toledo/hardware_validation.ipynb @@ -0,0 +1,580 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# MT-SICS Backend Hardware Validation\n", + "\n", + "Run this notebook connected to a physical Mettler Toledo scale to validate\n", + "every implemented backend method. Each cell tests one method and logs the\n", + "raw MT-SICS command/response.\n", + "\n", + "**Requirements:**\n", + "- Physical Mettler Toledo scale connected via USB-to-serial\n", + "- Scale powered on and warmed up (60 min)\n", + "- Weighing pan empty at start" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "---\n", + "## 1. Setup and Logging" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import logging\n", + "from datetime import datetime\n", + "\n", + "import pylabrobot\n", + "from pylabrobot.io import LOG_LEVEL_IO\n", + "from pylabrobot.scales import Scale\n", + "from pylabrobot.scales.mettler_toledo import MettlerToledoWXS205SDUBackend\n", + "\n", + "timestamp = datetime.now().strftime('%Y-%m-%d_%H-%M-%S')\n", + "log_file = f\"./logs/hardware_validation/{timestamp}_validation.log\"\n", + "\n", + "pylabrobot.verbose(True, level=LOG_LEVEL_IO)\n", + "pylabrobot.setup_logger(log_dir=log_file, level=LOG_LEVEL_IO)\n", + "\n", + "plr_logger = logging.getLogger(\"pylabrobot\")\n", + "plr_logger.info(\"=== Hardware validation started ===\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Update port for your system\n", + "backend = MettlerToledoWXS205SDUBackend(port=\"/dev/ttyUSB2\")\n", + "scale = Scale(name=\"validation_scale\", backend=backend, size_x=0, size_y=0, size_z=0)\n", + "\n", + "await scale.setup()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Verify setup populated device identity" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "print(f\"Device type: {backend.device_type}\")\n", + "print(f\"Serial number: {backend.serial_number}\")\n", + "print(f\"Capacity: {backend.capacity} g\")\n", + "print(f\"MT-SICS levels: {sorted(backend._mt_sics_levels)}\")\n", + "\n", + "assert backend.device_type is not None\n", + "assert backend.serial_number is not None\n", + "assert backend.capacity > 0\n", + "assert 0 in backend._mt_sics_levels\n", + "print(\"PASS: setup populated all identity fields\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "---\n", + "## 2. Level 0 Commands (Basic Set)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### @ - Cancel (reset to determined state)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "serial_number = await backend.cancel()\n", + "print(f\"Cancel returned serial number: {serial_number}\")\n", + "assert serial_number == backend.serial_number\n", + "print(\"PASS: cancel returns correct serial number\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### I4 - Serial number" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "sn = await backend.request_serial_number()\n", + "print(f\"Serial number: {sn}\")\n", + "assert len(sn) > 0\n", + "print(\"PASS: serial number is non-empty\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### I2 - Device type and capacity" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "device_type = await backend.request_device_type()\n", + "capacity = await backend.request_capacity()\n", + "print(f\"Device type: {device_type}\")\n", + "print(f\"Capacity: {capacity} g\")\n", + "assert len(device_type) > 0\n", + "assert capacity > 0\n", + "print(\"PASS: device type and capacity valid\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### I1 - MT-SICS levels" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "levels = await backend._query_mt_sics_levels()\n", + "print(f\"Supported levels: {sorted(levels)}\")\n", + "assert 0 in levels\n", + "assert 1 in levels\n", + "print(\"PASS: levels 0 and 1 present (always required)\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### S - Stable weight (ensure pan is empty)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "weight = await backend.read_stable_weight()\n", + "print(f\"Stable weight (empty pan): {weight} g\")\n", + "assert isinstance(weight, float)\n", + "print(\"PASS: stable weight returns float\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### SI - Weight immediately" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "weight = await backend.read_weight_value_immediately()\n", + "print(f\"Immediate weight: {weight} g\")\n", + "assert isinstance(weight, float)\n", + "print(\"PASS: immediate weight returns float\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Z - Zero (stable)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "await scale.zero(timeout=\"stable\")\n", + "weight = await backend.read_weight_value_immediately()\n", + "print(f\"Weight after zero: {weight} g\")\n", + "assert abs(weight) < 0.001, f\"Expected ~0 after zero, got {weight}\"\n", + "print(\"PASS: zero sets weight to ~0\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### ZI - Zero immediately" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "await scale.zero(timeout=0)\n", + "weight = await backend.read_weight_value_immediately()\n", + "print(f\"Weight after zero immediately: {weight} g\")\n", + "assert abs(weight) < 0.01\n", + "print(\"PASS: zero immediately sets weight to ~0\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "---\n", + "## 3. Level 1 Commands (Elementary)\n", + "\n", + "**Place a known weight on the scale for tare tests.**" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### T - Tare (stable)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "input(\"Place a container on the scale and press Enter...\")\n", + "await scale.zero(timeout=\"stable\")\n", + "await scale.tare(timeout=\"stable\")\n", + "tare = await scale.request_tare_weight()\n", + "print(f\"Tare weight: {tare} g\")\n", + "assert tare > 0, f\"Expected positive tare, got {tare}\"\n", + "print(\"PASS: tare stores container weight\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### TA - Request tare weight" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "tare = await scale.request_tare_weight()\n", + "print(f\"Tare weight from memory: {tare} g\")\n", + "assert isinstance(tare, float)\n", + "print(\"PASS: tare weight readable from memory\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### TAC - Clear tare" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "await backend.clear_tare()\n", + "tare_after_clear = await scale.request_tare_weight()\n", + "print(f\"Tare after clear: {tare_after_clear} g\")\n", + "assert abs(tare_after_clear) < 0.001, f\"Expected ~0 after clear, got {tare_after_clear}\"\n", + "print(\"PASS: clear tare resets tare to 0\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### SC - Dynamic weight (timed read)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "weight = await backend.read_dynamic_weight(timeout=3.0)\n", + "print(f\"Dynamic weight (3s timeout): {weight} g\")\n", + "assert isinstance(weight, float)\n", + "print(\"PASS: dynamic weight returns float\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### C - Cancel all" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "await backend.cancel_all()\n", + "print(\"PASS: cancel_all completed without error\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### D / DW - Display text" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "await backend.set_display_text(\"PLR TEST\")\n", + "import asyncio\n", + "await asyncio.sleep(2)\n", + "await backend.set_weight_display()\n", + "print(\"PASS: display text set and restored (check terminal if connected)\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### ZC / TC - Timed zero and tare\n", + "\n", + "These are known to return ES (syntax error) on the WXS205SDU despite being in the spec." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from pylabrobot.scales.mettler_toledo.errors import MettlerToledoError\n", + "\n", + "for cmd_name, cmd in [(\"ZC\", \"ZC 5000\"), (\"TC\", \"TC 5000\")]:\n", + " try:\n", + " await backend.send_command(cmd)\n", + " print(f\"{cmd_name}: supported on this device\")\n", + " except MettlerToledoError as e:\n", + " if \"Syntax error\" in str(e):\n", + " print(f\"{cmd_name}: not supported (ES) - expected for WXS205SDU\")\n", + " else:\n", + " print(f\"{cmd_name}: unexpected error: {e}\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "---\n", + "## 4. Level 2 Commands (Extended)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### M21 - Set host unit to grams" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "if 2 in backend._mt_sics_levels:\n", + " await backend.set_host_unit_grams()\n", + " print(\"PASS: host unit set to grams\")\n", + "else:\n", + " print(\"SKIP: Level 2 not supported\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### I50 - Remaining weighing range (multi-response)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "if 2 in backend._mt_sics_levels:\n", + " remaining = await backend.request_remaining_weighing_range()\n", + " print(f\"Remaining weighing range: {remaining} g\")\n", + " assert remaining > 0\n", + " assert remaining <= backend.capacity\n", + " print(\"PASS: remaining range is positive and within capacity\")\n", + "else:\n", + " print(\"SKIP: Level 2 not supported\")" + ] + }, + { + "cell_type": "markdown", + "source": "### M28 - Temperature sensor", + "metadata": {} + }, + { + "cell_type": "code", + "source": "if 2 in backend._mt_sics_levels:\n temp = await backend.measure_temperature()\n print(f\"Scale temperature: {temp} C\")\n assert 5 < temp < 50, f\"Temperature {temp} C outside reasonable range\"\n print(\"PASS: temperature sensor returns reasonable value\")\nelse:\n print(\"SKIP: Level 2 not supported\")", + "metadata": {}, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "---\n", + "## 5. Frontend Integration\n", + "\n", + "Test the Scale frontend methods that delegate to the backend." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Zero via frontend\n", + "await scale.zero(timeout=\"stable\")\n", + "w = await scale.read_weight(timeout=0)\n", + "print(f\"Frontend zero + read: {w} g\")\n", + "assert abs(w) < 0.001\n", + "\n", + "# Tare via frontend\n", + "input(\"Place a container on the scale and press Enter...\")\n", + "await scale.tare(timeout=\"stable\")\n", + "tare = await scale.request_tare_weight()\n", + "print(f\"Frontend tare weight: {tare} g\")\n", + "assert tare > 0\n", + "\n", + "# Read via frontend\n", + "w = await scale.read_weight(timeout=\"stable\")\n", + "print(f\"Frontend read (should be ~0 with container tared): {w} g\")\n", + "assert abs(w) < 0.1\n", + "\n", + "print(\"PASS: all frontend methods delegate correctly\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "---\n", + "## 6. Performance" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import time\n", + "import numpy as np\n", + "\n", + "# Stable read latency\n", + "times_stable = []\n", + "for _ in range(10):\n", + " t0 = time.monotonic_ns()\n", + " await scale.read_weight(timeout=\"stable\")\n", + " t1 = time.monotonic_ns()\n", + " times_stable.append((t1 - t0) / 1e6)\n", + "\n", + "# Immediate read latency\n", + "times_immediate = []\n", + "for _ in range(10):\n", + " t0 = time.monotonic_ns()\n", + " await scale.read_weight(timeout=0)\n", + " t1 = time.monotonic_ns()\n", + " times_immediate.append((t1 - t0) / 1e6)\n", + "\n", + "print(f\"Stable read: {np.mean(times_stable):.2f} +/- {np.std(times_stable):.2f} ms\")\n", + "print(f\"Immediate read: {np.mean(times_immediate):.2f} +/- {np.std(times_immediate):.2f} ms\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "---\n", + "## 7. Teardown" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "plr_logger.info(\"=== Hardware validation ended ===\")\n", + "await scale.stop()\n", + "print(f\"Log file: {log_file}\")" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "name": "python", + "version": "3.13.0" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file From a7f06fb8f1dcab518824e9ad29ab1d622aec3dfc Mon Sep 17 00:00:00 2001 From: Camillo Moschner Date: Mon, 30 Mar 2026 10:29:43 +0100 Subject: [PATCH 09/38] troubleshooting setup --- .../mettler_toledo/hardware_validation.ipynb | 94 ++++++++++++++++--- 1 file changed, 80 insertions(+), 14 deletions(-) diff --git a/pylabrobot/scales/mettler_toledo/hardware_validation.ipynb b/pylabrobot/scales/mettler_toledo/hardware_validation.ipynb index 0acc7a3b2c4..a69faaa870a 100644 --- a/pylabrobot/scales/mettler_toledo/hardware_validation.ipynb +++ b/pylabrobot/scales/mettler_toledo/hardware_validation.ipynb @@ -26,9 +26,17 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2026-03-30 10:26:02,921 - pylabrobot - INFO - === Hardware validation started ===\n" + ] + } + ], "source": [ "import logging\n", "from datetime import datetime\n", @@ -50,9 +58,49 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2026-03-30 10:26:06,539 - pylabrobot.io.serial - INFO - Using explicitly provided port: /dev/ttyUSB2 (for VID=1027, PID=24577)\n", + "2026-03-30 10:26:06,543 - pylabrobot.io.serial - IO - [/dev/ttyUSB2] reset_input_buffer\n", + "2026-03-30 10:26:06,543 - pylabrobot - IO - [MT Scale] Sent command: @\n", + "2026-03-30 10:26:06,546 - pylabrobot.io.serial - IO - [/dev/ttyUSB2] write b'@\\r\\n'\n", + "2026-03-30 10:26:06,606 - pylabrobot.io.serial - IO - [/dev/ttyUSB2] readline b'I4 A \"B207696838\"\\r\\n'\n", + "2026-03-30 10:26:06,607 - pylabrobot - IO - [MT Scale] Received response: b'I4 A \"B207696838\"\\r\\n'\n", + "2026-03-30 10:26:06,607 - pylabrobot - IO - [MT Scale] Sent command: I1\n", + "2026-03-30 10:26:06,609 - pylabrobot.io.serial - IO - [/dev/ttyUSB2] write b'I1\\r\\n'\n", + "2026-03-30 10:26:06,654 - pylabrobot.io.serial - IO - [/dev/ttyUSB2] readline b'I1 A \"01\" \"2.30\" \"2.22\" \"\" \"\"\\r\\n'\n", + "2026-03-30 10:26:06,655 - pylabrobot - IO - [MT Scale] Received response: b'I1 A \"01\" \"2.30\" \"2.22\" \"\" \"\"\\r\\n'\n", + "2026-03-30 10:26:06,655 - pylabrobot - IO - [MT Scale] Sent command: I2\n", + "2026-03-30 10:26:06,656 - pylabrobot.io.serial - IO - [/dev/ttyUSB2] write b'I2\\r\\n'\n", + "2026-03-30 10:26:06,798 - pylabrobot.io.serial - IO - [/dev/ttyUSB2] readline b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", + "2026-03-30 10:26:06,799 - pylabrobot - IO - [MT Scale] Received response: b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", + "2026-03-30 10:26:06,799 - pylabrobot - IO - [MT Scale] Sent command: I2\n", + "2026-03-30 10:26:06,800 - pylabrobot.io.serial - IO - [/dev/ttyUSB2] write b'I2\\r\\n'\n", + "2026-03-30 10:26:06,862 - pylabrobot.io.serial - IO - [/dev/ttyUSB2] readline b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", + "2026-03-30 10:26:06,863 - pylabrobot - IO - [MT Scale] Received response: b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n" + ] + }, + { + "ename": "MettlerToledoError", + "evalue": "Unexpected unit: Expected 'g' for 'I2', got '220.00900'", + "output_type": "error", + "traceback": [ + "\u001b[31m---------------------------------------------------------------------------\u001b[39m", + "\u001b[31mMettlerToledoError\u001b[39m Traceback (most recent call last)", + "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[2]\u001b[39m\u001b[32m, line 5\u001b[39m\n\u001b[32m 2\u001b[39m backend = MettlerToledoWXS205SDUBackend(port=\u001b[33m\"\u001b[39m\u001b[33m/dev/ttyUSB2\u001b[39m\u001b[33m\"\u001b[39m)\n\u001b[32m 3\u001b[39m scale = Scale(name=\u001b[33m\"\u001b[39m\u001b[33mvalidation_scale\u001b[39m\u001b[33m\"\u001b[39m, backend=backend, size_x=\u001b[32m0\u001b[39m, size_y=\u001b[32m0\u001b[39m, size_z=\u001b[32m0\u001b[39m)\n\u001b[32m----> \u001b[39m\u001b[32m5\u001b[39m \u001b[38;5;28;01mawait\u001b[39;00m scale.setup()\n", + "\u001b[36mFile \u001b[39m\u001b[32m~/Desktop/GitHub/pylabrobot/pylabrobot/machines/machine.py:64\u001b[39m, in \u001b[36mMachine.setup\u001b[39m\u001b[34m(self, **backend_kwargs)\u001b[39m\n\u001b[32m 63\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[34msetup\u001b[39m(\u001b[38;5;28mself\u001b[39m, **backend_kwargs):\n\u001b[32m---> \u001b[39m\u001b[32m64\u001b[39m \u001b[38;5;28;01mawait\u001b[39;00m \u001b[38;5;28mself\u001b[39m.backend.setup(**backend_kwargs)\n\u001b[32m 65\u001b[39m \u001b[38;5;28mself\u001b[39m._setup_finished = \u001b[38;5;28;01mTrue\u001b[39;00m\n", + "\u001b[36mFile \u001b[39m\u001b[32m~/Desktop/GitHub/pylabrobot/pylabrobot/scales/mettler_toledo/backend.py:123\u001b[39m, in \u001b[36mMettlerToledoWXS205SDUBackend.setup\u001b[39m\u001b[34m(self)\u001b[39m\n\u001b[32m 121\u001b[39m \u001b[38;5;28mself\u001b[39m._mt_sics_levels: Set[\u001b[38;5;28mint\u001b[39m] = \u001b[38;5;28;01mawait\u001b[39;00m \u001b[38;5;28mself\u001b[39m._query_mt_sics_levels()\n\u001b[32m 122\u001b[39m \u001b[38;5;28mself\u001b[39m.device_type = \u001b[38;5;28;01mawait\u001b[39;00m \u001b[38;5;28mself\u001b[39m.request_device_type()\n\u001b[32m--> \u001b[39m\u001b[32m123\u001b[39m \u001b[38;5;28mself\u001b[39m.capacity = \u001b[38;5;28;01mawait\u001b[39;00m \u001b[38;5;28mself\u001b[39m.request_capacity()\n\u001b[32m 125\u001b[39m logger.info(\n\u001b[32m 126\u001b[39m \u001b[33m\"\u001b[39m\u001b[33m[MT Scale] Connected to Mettler Toledo scale on \u001b[39m\u001b[38;5;132;01m%s\u001b[39;00m\u001b[38;5;130;01m\\n\u001b[39;00m\u001b[33m\"\u001b[39m\n\u001b[32m 127\u001b[39m \u001b[33m\"\u001b[39m\u001b[33mDevice type: \u001b[39m\u001b[38;5;132;01m%s\u001b[39;00m\u001b[38;5;130;01m\\n\u001b[39;00m\u001b[33m\"\u001b[39m\n\u001b[32m (...)\u001b[39m\u001b[32m 135\u001b[39m \u001b[38;5;28msorted\u001b[39m(\u001b[38;5;28mself\u001b[39m._mt_sics_levels),\n\u001b[32m 136\u001b[39m )\n\u001b[32m 138\u001b[39m \u001b[38;5;66;03m# Set output unit to grams\u001b[39;00m\n", + "\u001b[36mFile \u001b[39m\u001b[32m~/Desktop/GitHub/pylabrobot/pylabrobot/scales/mettler_toledo/backend.py:352\u001b[39m, in \u001b[36mMettlerToledoWXS205SDUBackend.request_capacity\u001b[39m\u001b[34m(self)\u001b[39m\n\u001b[32m 350\u001b[39m \u001b[38;5;66;03m# data: ['\"WXS205SDU\"', \"220.0000\", \"g\"]\u001b[39;00m\n\u001b[32m 351\u001b[39m \u001b[38;5;28mself\u001b[39m._validate_response(responses[\u001b[32m0\u001b[39m], \u001b[32m5\u001b[39m, \u001b[33m\"\u001b[39m\u001b[33mI2\u001b[39m\u001b[33m\"\u001b[39m)\n\u001b[32m--> \u001b[39m\u001b[32m352\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[43m.\u001b[49m\u001b[43m_validate_unit\u001b[49m\u001b[43m(\u001b[49m\u001b[43mresponses\u001b[49m\u001b[43m[\u001b[49m\u001b[32;43m0\u001b[39;49m\u001b[43m]\u001b[49m\u001b[43m.\u001b[49m\u001b[43mdata\u001b[49m\u001b[43m[\u001b[49m\u001b[32;43m2\u001b[39;49m\u001b[43m]\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[33;43m\"\u001b[39;49m\u001b[33;43mI2\u001b[39;49m\u001b[33;43m\"\u001b[39;49m\u001b[43m)\u001b[49m\n\u001b[32m 353\u001b[39m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28mfloat\u001b[39m(responses[\u001b[32m0\u001b[39m].data[\u001b[32m1\u001b[39m])\n", + "\u001b[36mFile \u001b[39m\u001b[32m~/Desktop/GitHub/pylabrobot/pylabrobot/scales/mettler_toledo/backend.py:188\u001b[39m, in \u001b[36mMettlerToledoWXS205SDUBackend._validate_unit\u001b[39m\u001b[34m(unit, command)\u001b[39m\n\u001b[32m 182\u001b[39m \u001b[38;5;250m\u001b[39m\u001b[33;03m\"\"\"Validate that the unit in a response is grams.\u001b[39;00m\n\u001b[32m 183\u001b[39m \n\u001b[32m 184\u001b[39m \u001b[33;03mRaises:\u001b[39;00m\n\u001b[32m 185\u001b[39m \u001b[33;03m MettlerToledoError: if the unit is not 'g'.\u001b[39;00m\n\u001b[32m 186\u001b[39m \u001b[33;03m\"\"\"\u001b[39;00m\n\u001b[32m 187\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m unit != \u001b[33m\"\u001b[39m\u001b[33mg\u001b[39m\u001b[33m\"\u001b[39m:\n\u001b[32m--> \u001b[39m\u001b[32m188\u001b[39m \u001b[38;5;28;01mraise\u001b[39;00m MettlerToledoError(\n\u001b[32m 189\u001b[39m title=\u001b[33m\"\u001b[39m\u001b[33mUnexpected unit\u001b[39m\u001b[33m\"\u001b[39m,\n\u001b[32m 190\u001b[39m message=\u001b[33mf\u001b[39m\u001b[33m\"\u001b[39m\u001b[33mExpected \u001b[39m\u001b[33m'\u001b[39m\u001b[33mg\u001b[39m\u001b[33m'\u001b[39m\u001b[33m for \u001b[39m\u001b[33m'\u001b[39m\u001b[38;5;132;01m{\u001b[39;00mcommand\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m'\u001b[39m\u001b[33m, got \u001b[39m\u001b[33m'\u001b[39m\u001b[38;5;132;01m{\u001b[39;00munit\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m'\u001b[39m\u001b[33m\"\u001b[39m,\n\u001b[32m 191\u001b[39m )\n", + "\u001b[31mMettlerToledoError\u001b[39m: Unexpected unit: Expected 'g' for 'I2', got '220.00900'" + ] + } + ], "source": [ "# Update port for your system\n", "backend = MettlerToledoWXS205SDUBackend(port=\"/dev/ttyUSB2\")\n", @@ -460,15 +508,25 @@ }, { "cell_type": "markdown", - "source": "### M28 - Temperature sensor", - "metadata": {} + "metadata": {}, + "source": [ + "### M28 - Temperature sensor" + ] }, { "cell_type": "code", - "source": "if 2 in backend._mt_sics_levels:\n temp = await backend.measure_temperature()\n print(f\"Scale temperature: {temp} C\")\n assert 5 < temp < 50, f\"Temperature {temp} C outside reasonable range\"\n print(\"PASS: temperature sensor returns reasonable value\")\nelse:\n print(\"SKIP: Level 2 not supported\")", - "metadata": {}, "execution_count": null, - "outputs": [] + "metadata": {}, + "outputs": [], + "source": [ + "if 2 in backend._mt_sics_levels:\n", + " temp = await backend.measure_temperature()\n", + " print(f\"Scale temperature: {temp} C\")\n", + " assert 5 < temp < 50, f\"Temperature {temp} C outside reasonable range\"\n", + " print(\"PASS: temperature sensor returns reasonable value\")\n", + "else:\n", + " print(\"SKIP: Level 2 not supported\")" + ] }, { "cell_type": "markdown", @@ -566,15 +624,23 @@ ], "metadata": { "kernelspec": { - "display_name": "Python 3", + "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", "name": "python", - "version": "3.13.0" + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.12.11" } }, "nbformat": 4, "nbformat_minor": 4 -} \ No newline at end of file +} From 187850a3f80970b3c4c16cbfb3baab39578ede1a Mon Sep 17 00:00:00 2001 From: Camillo Moschner Date: Mon, 30 Mar 2026 11:27:55 +0100 Subject: [PATCH 10/38] Quote-aware response parsing with shlex, measure_temperature M28, 15 MT-SICS chatterbox and parsing tests --- pylabrobot/scales/chatterbox.py | 7 +- pylabrobot/scales/mettler_toledo/backend.py | 37 ++++++---- .../scales/mettler_toledo/backend_tests.py | 2 +- .../scales/mettler_toledo/chatterbox.py | 14 ++-- .../mettler_toledo/hardware_validation.ipynb | 73 +++++++++---------- 5 files changed, 71 insertions(+), 62 deletions(-) diff --git a/pylabrobot/scales/chatterbox.py b/pylabrobot/scales/chatterbox.py index d92b9654cae..1d8cd4609d2 100644 --- a/pylabrobot/scales/chatterbox.py +++ b/pylabrobot/scales/chatterbox.py @@ -1,4 +1,9 @@ -"""Chatterbox scale backend for device-free testing and simulation.""" +"""Generic scale chatterbox for testing the Scale frontend and ScaleBackend interface. + +This chatterbox is protocol-agnostic - it tests the abstract scale contract (zero, tare, +read_weight, request_tare_weight) without any device-specific protocol. For MT-SICS +protocol-level simulation, use MettlerToledoChatterboxBackend instead. +""" from pylabrobot.scales.scale_backend import ScaleBackend diff --git a/pylabrobot/scales/mettler_toledo/backend.py b/pylabrobot/scales/mettler_toledo/backend.py index 028befe7f4e..3347ecba8b8 100644 --- a/pylabrobot/scales/mettler_toledo/backend.py +++ b/pylabrobot/scales/mettler_toledo/backend.py @@ -5,6 +5,7 @@ import asyncio import functools import logging +import shlex import time import warnings from dataclasses import dataclass, field @@ -155,7 +156,7 @@ async def _query_mt_sics_levels(self) -> Set[int]: responses = await self.send_command("I1") # I1 A "0123" "2.00" "2.20" "1.00" "1.50" self._validate_response(responses[0], 3, "I1") - level_string = responses[0].data[0].replace('"', "") + level_string = responses[0].data[0] return {int(c) for c in level_string} # === Response parsing === @@ -275,7 +276,7 @@ async def send_command(self, command: str, timeout: int = 60) -> List[MettlerTol await asyncio.sleep(0.001) logger.log(LOG_LEVEL_IO, "[MT Scale] Received response: %s", raw_response) - fields = raw_response.decode("utf-8").strip().split() + fields = shlex.split(raw_response.decode("utf-8").strip()) if len(fields) >= 2: response = MettlerToledoResponse(command=fields[0], status=fields[1], data=fields[2:]) elif len(fields) == 1: @@ -308,7 +309,7 @@ async def cancel(self) -> str: responses = await self.send_command("@") # @ responds with I4-style: I4 A "" self._validate_response(responses[0], 3, "@") - return responses[0].data[0].replace('"', "") + return responses[0].data[0] async def cancel_all(self) -> None: """C - Cancel all active and pending interface commands. @@ -335,22 +336,32 @@ async def request_serial_number(self) -> str: """Get the serial number of the scale. (I4 command)""" responses = await self.send_command("I4") self._validate_response(responses[0], 3, "I4") - return responses[0].data[0].replace('"', "") + return responses[0].data[0] async def request_device_type(self) -> str: - """Query the device type string. (I2 command)""" + """Query the device type string. (I2 command) + + The I2 response packs type, capacity, and unit into a single quoted string: + I2 A "WXS205SDU WXA-Bridge 220.00900 g" + The type is everything before the last two tokens (capacity and unit). + """ responses = await self.send_command("I2") - # data: ['"WXS205SDU"', "220.0000", "g"] - self._validate_response(responses[0], 5, "I2") - return responses[0].data[0].replace('"', "") + self._validate_response(responses[0], 3, "I2") + parts = responses[0].data[0].split() + return " ".join(parts[:-2]) async def request_capacity(self) -> float: - """Query the maximum weighing capacity in grams. (I2 command)""" + """Query the maximum weighing capacity in grams. (I2 command) + + The I2 response packs type, capacity, and unit into a single quoted string: + I2 A "WXS205SDU WXA-Bridge 220.00900 g" + Capacity is the second-to-last token, unit is the last. + """ responses = await self.send_command("I2") - # data: ['"WXS205SDU"', "220.0000", "g"] - self._validate_response(responses[0], 5, "I2") - self._validate_unit(responses[0].data[2], "I2") - return float(responses[0].data[1]) + self._validate_response(responses[0], 3, "I2") + parts = responses[0].data[0].split() + self._validate_unit(parts[-1], "I2") + return float(parts[-2]) @requires_mt_sics_level(2) async def request_remaining_weighing_range(self) -> float: diff --git a/pylabrobot/scales/mettler_toledo/backend_tests.py b/pylabrobot/scales/mettler_toledo/backend_tests.py index 72b85464f19..1dff2cd4974 100644 --- a/pylabrobot/scales/mettler_toledo/backend_tests.py +++ b/pylabrobot/scales/mettler_toledo/backend_tests.py @@ -60,7 +60,7 @@ def test_validate_response_rejects_short(self): MettlerToledoWXS205SDUBackend._validate_response(R("I4", "A"), 3, "I4") # should not raise - MettlerToledoWXS205SDUBackend._validate_response(R("I4", "A", ['"B207696838"']), 3, "I4") + MettlerToledoWXS205SDUBackend._validate_response(R("I4", "A", ["B207696838"]), 3, "I4") def test_validate_unit_rejects_wrong(self): """Non-gram unit responses must be rejected. diff --git a/pylabrobot/scales/mettler_toledo/chatterbox.py b/pylabrobot/scales/mettler_toledo/chatterbox.py index 3222835b208..6292a7b16af 100644 --- a/pylabrobot/scales/mettler_toledo/chatterbox.py +++ b/pylabrobot/scales/mettler_toledo/chatterbox.py @@ -92,7 +92,7 @@ async def stop(self) -> None: async def cancel(self) -> str: responses = await self.send_command("@") self._validate_response(responses[0], 3, "@") - return responses[0].data[0].replace('"', "") + return responses[0].data[0] async def send_command(self, command: str, timeout: int = 60) -> List[MettlerToledoResponse]: logger.log(LOG_LEVEL_IO, "[MT Scale] Sent command: %s", command) @@ -113,18 +113,16 @@ def _build_response(self, command: str) -> List[MettlerToledoResponse]: cmd = command.split()[0] net = round(self._sensor_reading - self.zero_offset - self.tare_weight, 5) - # Identification + # Identification (shlex strips quotes, so mock responses should not include them) if cmd == "@": - return [R("I4", "A", [f'"{self._simulated_serial_number}"'])] + return [R("I4", "A", [self._simulated_serial_number])] if cmd == "I1": levels = "".join(str(lvl) for lvl in sorted(self._simulated_mt_sics_levels)) - return [R("I1", "A", [f'"{levels}"'])] + return [R("I1", "A", [levels])] if cmd == "I2": - return [ - R("I2", "A", [f'"{self._simulated_device_type}"', f"{self._simulated_capacity:.4f}", "g"]) - ] + return [R("I2", "A", [f"{self._simulated_device_type} {self._simulated_capacity:.5f} g"])] if cmd == "I4": - return [R("I4", "A", [f'"{self._simulated_serial_number}"'])] + return [R("I4", "A", [self._simulated_serial_number])] # Zero if cmd in ("Z", "ZI", "ZC"): diff --git a/pylabrobot/scales/mettler_toledo/hardware_validation.ipynb b/pylabrobot/scales/mettler_toledo/hardware_validation.ipynb index a69faaa870a..3d7f41b27b3 100644 --- a/pylabrobot/scales/mettler_toledo/hardware_validation.ipynb +++ b/pylabrobot/scales/mettler_toledo/hardware_validation.ipynb @@ -46,7 +46,7 @@ "from pylabrobot.scales import Scale\n", "from pylabrobot.scales.mettler_toledo import MettlerToledoWXS205SDUBackend\n", "\n", - "timestamp = datetime.now().strftime('%Y-%m-%d_%H-%M-%S')\n", + "timestamp = datetime.now().strftime(\"%Y-%m-%d_%H-%M-%S\")\n", "log_file = f\"./logs/hardware_validation/{timestamp}_validation.log\"\n", "\n", "pylabrobot.verbose(True, level=LOG_LEVEL_IO)\n", @@ -419,13 +419,7 @@ "execution_count": null, "metadata": {}, "outputs": [], - "source": [ - "await backend.set_display_text(\"PLR TEST\")\n", - "import asyncio\n", - "await asyncio.sleep(2)\n", - "await backend.set_weight_display()\n", - "print(\"PASS: display text set and restored (check terminal if connected)\")" - ] + "source": "import asyncio\n\nawait backend.set_display_text(\"PLR TEST\")\nawait asyncio.sleep(2)\nawait backend.set_weight_display()\nprint(\"PASS: display text set and restored (check terminal if connected)\")" }, { "cell_type": "markdown", @@ -445,14 +439,14 @@ "from pylabrobot.scales.mettler_toledo.errors import MettlerToledoError\n", "\n", "for cmd_name, cmd in [(\"ZC\", \"ZC 5000\"), (\"TC\", \"TC 5000\")]:\n", - " try:\n", - " await backend.send_command(cmd)\n", - " print(f\"{cmd_name}: supported on this device\")\n", - " except MettlerToledoError as e:\n", - " if \"Syntax error\" in str(e):\n", - " print(f\"{cmd_name}: not supported (ES) - expected for WXS205SDU\")\n", - " else:\n", - " print(f\"{cmd_name}: unexpected error: {e}\")" + " try:\n", + " await backend.send_command(cmd)\n", + " print(f\"{cmd_name}: supported on this device\")\n", + " except MettlerToledoError as e:\n", + " if \"Syntax error\" in str(e):\n", + " print(f\"{cmd_name}: not supported (ES) - expected for WXS205SDU\")\n", + " else:\n", + " print(f\"{cmd_name}: unexpected error: {e}\")" ] }, { @@ -477,10 +471,10 @@ "outputs": [], "source": [ "if 2 in backend._mt_sics_levels:\n", - " await backend.set_host_unit_grams()\n", - " print(\"PASS: host unit set to grams\")\n", + " await backend.set_host_unit_grams()\n", + " print(\"PASS: host unit set to grams\")\n", "else:\n", - " print(\"SKIP: Level 2 not supported\")" + " print(\"SKIP: Level 2 not supported\")" ] }, { @@ -497,13 +491,13 @@ "outputs": [], "source": [ "if 2 in backend._mt_sics_levels:\n", - " remaining = await backend.request_remaining_weighing_range()\n", - " print(f\"Remaining weighing range: {remaining} g\")\n", - " assert remaining > 0\n", - " assert remaining <= backend.capacity\n", - " print(\"PASS: remaining range is positive and within capacity\")\n", + " remaining = await backend.request_remaining_weighing_range()\n", + " print(f\"Remaining weighing range: {remaining} g\")\n", + " assert remaining > 0\n", + " assert remaining <= backend.capacity\n", + " print(\"PASS: remaining range is positive and within capacity\")\n", "else:\n", - " print(\"SKIP: Level 2 not supported\")" + " print(\"SKIP: Level 2 not supported\")" ] }, { @@ -520,12 +514,12 @@ "outputs": [], "source": [ "if 2 in backend._mt_sics_levels:\n", - " temp = await backend.measure_temperature()\n", - " print(f\"Scale temperature: {temp} C\")\n", - " assert 5 < temp < 50, f\"Temperature {temp} C outside reasonable range\"\n", - " print(\"PASS: temperature sensor returns reasonable value\")\n", + " temp = await backend.measure_temperature()\n", + " print(f\"Scale temperature: {temp} C\")\n", + " assert 5 < temp < 50, f\"Temperature {temp} C outside reasonable range\"\n", + " print(\"PASS: temperature sensor returns reasonable value\")\n", "else:\n", - " print(\"SKIP: Level 2 not supported\")" + " print(\"SKIP: Level 2 not supported\")" ] }, { @@ -580,23 +574,24 @@ "outputs": [], "source": [ "import time\n", + "\n", "import numpy as np\n", "\n", "# Stable read latency\n", "times_stable = []\n", "for _ in range(10):\n", - " t0 = time.monotonic_ns()\n", - " await scale.read_weight(timeout=\"stable\")\n", - " t1 = time.monotonic_ns()\n", - " times_stable.append((t1 - t0) / 1e6)\n", + " t0 = time.monotonic_ns()\n", + " await scale.read_weight(timeout=\"stable\")\n", + " t1 = time.monotonic_ns()\n", + " times_stable.append((t1 - t0) / 1e6)\n", "\n", "# Immediate read latency\n", "times_immediate = []\n", "for _ in range(10):\n", - " t0 = time.monotonic_ns()\n", - " await scale.read_weight(timeout=0)\n", - " t1 = time.monotonic_ns()\n", - " times_immediate.append((t1 - t0) / 1e6)\n", + " t0 = time.monotonic_ns()\n", + " await scale.read_weight(timeout=0)\n", + " t1 = time.monotonic_ns()\n", + " times_immediate.append((t1 - t0) / 1e6)\n", "\n", "print(f\"Stable read: {np.mean(times_stable):.2f} +/- {np.std(times_stable):.2f} ms\")\n", "print(f\"Immediate read: {np.mean(times_immediate):.2f} +/- {np.std(times_immediate):.2f} ms\")" @@ -643,4 +638,4 @@ }, "nbformat": 4, "nbformat_minor": 4 -} +} \ No newline at end of file From 6f635114472abca6ed18e3c0862c79278bdc7741 Mon Sep 17 00:00:00 2001 From: Camillo Moschner Date: Mon, 30 Mar 2026 11:31:14 +0100 Subject: [PATCH 11/38] testing --- .../mettler_toledo/hardware_validation.ipynb | 725 ++++++++++++++++-- 1 file changed, 643 insertions(+), 82 deletions(-) diff --git a/pylabrobot/scales/mettler_toledo/hardware_validation.ipynb b/pylabrobot/scales/mettler_toledo/hardware_validation.ipynb index 3d7f41b27b3..47f5706bf91 100644 --- a/pylabrobot/scales/mettler_toledo/hardware_validation.ipynb +++ b/pylabrobot/scales/mettler_toledo/hardware_validation.ipynb @@ -33,7 +33,7 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 10:26:02,921 - pylabrobot - INFO - === Hardware validation started ===\n" + "2026-03-30 11:28:29,103 - pylabrobot - INFO - === Hardware validation started ===\n" ] } ], @@ -58,52 +58,42 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": 3, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 10:26:06,539 - pylabrobot.io.serial - INFO - Using explicitly provided port: /dev/ttyUSB2 (for VID=1027, PID=24577)\n", - "2026-03-30 10:26:06,543 - pylabrobot.io.serial - IO - [/dev/ttyUSB2] reset_input_buffer\n", - "2026-03-30 10:26:06,543 - pylabrobot - IO - [MT Scale] Sent command: @\n", - "2026-03-30 10:26:06,546 - pylabrobot.io.serial - IO - [/dev/ttyUSB2] write b'@\\r\\n'\n", - "2026-03-30 10:26:06,606 - pylabrobot.io.serial - IO - [/dev/ttyUSB2] readline b'I4 A \"B207696838\"\\r\\n'\n", - "2026-03-30 10:26:06,607 - pylabrobot - IO - [MT Scale] Received response: b'I4 A \"B207696838\"\\r\\n'\n", - "2026-03-30 10:26:06,607 - pylabrobot - IO - [MT Scale] Sent command: I1\n", - "2026-03-30 10:26:06,609 - pylabrobot.io.serial - IO - [/dev/ttyUSB2] write b'I1\\r\\n'\n", - "2026-03-30 10:26:06,654 - pylabrobot.io.serial - IO - [/dev/ttyUSB2] readline b'I1 A \"01\" \"2.30\" \"2.22\" \"\" \"\"\\r\\n'\n", - "2026-03-30 10:26:06,655 - pylabrobot - IO - [MT Scale] Received response: b'I1 A \"01\" \"2.30\" \"2.22\" \"\" \"\"\\r\\n'\n", - "2026-03-30 10:26:06,655 - pylabrobot - IO - [MT Scale] Sent command: I2\n", - "2026-03-30 10:26:06,656 - pylabrobot.io.serial - IO - [/dev/ttyUSB2] write b'I2\\r\\n'\n", - "2026-03-30 10:26:06,798 - pylabrobot.io.serial - IO - [/dev/ttyUSB2] readline b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", - "2026-03-30 10:26:06,799 - pylabrobot - IO - [MT Scale] Received response: b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", - "2026-03-30 10:26:06,799 - pylabrobot - IO - [MT Scale] Sent command: I2\n", - "2026-03-30 10:26:06,800 - pylabrobot.io.serial - IO - [/dev/ttyUSB2] write b'I2\\r\\n'\n", - "2026-03-30 10:26:06,862 - pylabrobot.io.serial - IO - [/dev/ttyUSB2] readline b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", - "2026-03-30 10:26:06,863 - pylabrobot - IO - [MT Scale] Received response: b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n" - ] - }, - { - "ename": "MettlerToledoError", - "evalue": "Unexpected unit: Expected 'g' for 'I2', got '220.00900'", - "output_type": "error", - "traceback": [ - "\u001b[31m---------------------------------------------------------------------------\u001b[39m", - "\u001b[31mMettlerToledoError\u001b[39m Traceback (most recent call last)", - "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[2]\u001b[39m\u001b[32m, line 5\u001b[39m\n\u001b[32m 2\u001b[39m backend = MettlerToledoWXS205SDUBackend(port=\u001b[33m\"\u001b[39m\u001b[33m/dev/ttyUSB2\u001b[39m\u001b[33m\"\u001b[39m)\n\u001b[32m 3\u001b[39m scale = Scale(name=\u001b[33m\"\u001b[39m\u001b[33mvalidation_scale\u001b[39m\u001b[33m\"\u001b[39m, backend=backend, size_x=\u001b[32m0\u001b[39m, size_y=\u001b[32m0\u001b[39m, size_z=\u001b[32m0\u001b[39m)\n\u001b[32m----> \u001b[39m\u001b[32m5\u001b[39m \u001b[38;5;28;01mawait\u001b[39;00m scale.setup()\n", - "\u001b[36mFile \u001b[39m\u001b[32m~/Desktop/GitHub/pylabrobot/pylabrobot/machines/machine.py:64\u001b[39m, in \u001b[36mMachine.setup\u001b[39m\u001b[34m(self, **backend_kwargs)\u001b[39m\n\u001b[32m 63\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[34msetup\u001b[39m(\u001b[38;5;28mself\u001b[39m, **backend_kwargs):\n\u001b[32m---> \u001b[39m\u001b[32m64\u001b[39m \u001b[38;5;28;01mawait\u001b[39;00m \u001b[38;5;28mself\u001b[39m.backend.setup(**backend_kwargs)\n\u001b[32m 65\u001b[39m \u001b[38;5;28mself\u001b[39m._setup_finished = \u001b[38;5;28;01mTrue\u001b[39;00m\n", - "\u001b[36mFile \u001b[39m\u001b[32m~/Desktop/GitHub/pylabrobot/pylabrobot/scales/mettler_toledo/backend.py:123\u001b[39m, in \u001b[36mMettlerToledoWXS205SDUBackend.setup\u001b[39m\u001b[34m(self)\u001b[39m\n\u001b[32m 121\u001b[39m \u001b[38;5;28mself\u001b[39m._mt_sics_levels: Set[\u001b[38;5;28mint\u001b[39m] = \u001b[38;5;28;01mawait\u001b[39;00m \u001b[38;5;28mself\u001b[39m._query_mt_sics_levels()\n\u001b[32m 122\u001b[39m \u001b[38;5;28mself\u001b[39m.device_type = \u001b[38;5;28;01mawait\u001b[39;00m \u001b[38;5;28mself\u001b[39m.request_device_type()\n\u001b[32m--> \u001b[39m\u001b[32m123\u001b[39m \u001b[38;5;28mself\u001b[39m.capacity = \u001b[38;5;28;01mawait\u001b[39;00m \u001b[38;5;28mself\u001b[39m.request_capacity()\n\u001b[32m 125\u001b[39m logger.info(\n\u001b[32m 126\u001b[39m \u001b[33m\"\u001b[39m\u001b[33m[MT Scale] Connected to Mettler Toledo scale on \u001b[39m\u001b[38;5;132;01m%s\u001b[39;00m\u001b[38;5;130;01m\\n\u001b[39;00m\u001b[33m\"\u001b[39m\n\u001b[32m 127\u001b[39m \u001b[33m\"\u001b[39m\u001b[33mDevice type: \u001b[39m\u001b[38;5;132;01m%s\u001b[39;00m\u001b[38;5;130;01m\\n\u001b[39;00m\u001b[33m\"\u001b[39m\n\u001b[32m (...)\u001b[39m\u001b[32m 135\u001b[39m \u001b[38;5;28msorted\u001b[39m(\u001b[38;5;28mself\u001b[39m._mt_sics_levels),\n\u001b[32m 136\u001b[39m )\n\u001b[32m 138\u001b[39m \u001b[38;5;66;03m# Set output unit to grams\u001b[39;00m\n", - "\u001b[36mFile \u001b[39m\u001b[32m~/Desktop/GitHub/pylabrobot/pylabrobot/scales/mettler_toledo/backend.py:352\u001b[39m, in \u001b[36mMettlerToledoWXS205SDUBackend.request_capacity\u001b[39m\u001b[34m(self)\u001b[39m\n\u001b[32m 350\u001b[39m \u001b[38;5;66;03m# data: ['\"WXS205SDU\"', \"220.0000\", \"g\"]\u001b[39;00m\n\u001b[32m 351\u001b[39m \u001b[38;5;28mself\u001b[39m._validate_response(responses[\u001b[32m0\u001b[39m], \u001b[32m5\u001b[39m, \u001b[33m\"\u001b[39m\u001b[33mI2\u001b[39m\u001b[33m\"\u001b[39m)\n\u001b[32m--> \u001b[39m\u001b[32m352\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[43m.\u001b[49m\u001b[43m_validate_unit\u001b[49m\u001b[43m(\u001b[49m\u001b[43mresponses\u001b[49m\u001b[43m[\u001b[49m\u001b[32;43m0\u001b[39;49m\u001b[43m]\u001b[49m\u001b[43m.\u001b[49m\u001b[43mdata\u001b[49m\u001b[43m[\u001b[49m\u001b[32;43m2\u001b[39;49m\u001b[43m]\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[33;43m\"\u001b[39;49m\u001b[33;43mI2\u001b[39;49m\u001b[33;43m\"\u001b[39;49m\u001b[43m)\u001b[49m\n\u001b[32m 353\u001b[39m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28mfloat\u001b[39m(responses[\u001b[32m0\u001b[39m].data[\u001b[32m1\u001b[39m])\n", - "\u001b[36mFile \u001b[39m\u001b[32m~/Desktop/GitHub/pylabrobot/pylabrobot/scales/mettler_toledo/backend.py:188\u001b[39m, in \u001b[36mMettlerToledoWXS205SDUBackend._validate_unit\u001b[39m\u001b[34m(unit, command)\u001b[39m\n\u001b[32m 182\u001b[39m \u001b[38;5;250m\u001b[39m\u001b[33;03m\"\"\"Validate that the unit in a response is grams.\u001b[39;00m\n\u001b[32m 183\u001b[39m \n\u001b[32m 184\u001b[39m \u001b[33;03mRaises:\u001b[39;00m\n\u001b[32m 185\u001b[39m \u001b[33;03m MettlerToledoError: if the unit is not 'g'.\u001b[39;00m\n\u001b[32m 186\u001b[39m \u001b[33;03m\"\"\"\u001b[39;00m\n\u001b[32m 187\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m unit != \u001b[33m\"\u001b[39m\u001b[33mg\u001b[39m\u001b[33m\"\u001b[39m:\n\u001b[32m--> \u001b[39m\u001b[32m188\u001b[39m \u001b[38;5;28;01mraise\u001b[39;00m MettlerToledoError(\n\u001b[32m 189\u001b[39m title=\u001b[33m\"\u001b[39m\u001b[33mUnexpected unit\u001b[39m\u001b[33m\"\u001b[39m,\n\u001b[32m 190\u001b[39m message=\u001b[33mf\u001b[39m\u001b[33m\"\u001b[39m\u001b[33mExpected \u001b[39m\u001b[33m'\u001b[39m\u001b[33mg\u001b[39m\u001b[33m'\u001b[39m\u001b[33m for \u001b[39m\u001b[33m'\u001b[39m\u001b[38;5;132;01m{\u001b[39;00mcommand\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m'\u001b[39m\u001b[33m, got \u001b[39m\u001b[33m'\u001b[39m\u001b[38;5;132;01m{\u001b[39;00munit\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m'\u001b[39m\u001b[33m\"\u001b[39m,\n\u001b[32m 191\u001b[39m )\n", - "\u001b[31mMettlerToledoError\u001b[39m: Unexpected unit: Expected 'g' for 'I2', got '220.00900'" + "2026-03-30 11:29:07,453 - pylabrobot.io.serial - INFO - Using explicitly provided port: /dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0 (for VID=1027, PID=24577)\n", + "2026-03-30 11:29:07,456 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] reset_input_buffer\n", + "2026-03-30 11:29:07,457 - pylabrobot - IO - [MT Scale] Sent command: @\n", + "2026-03-30 11:29:07,459 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'@\\r\\n'\n", + "2026-03-30 11:29:07,520 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I4 A \"B207696838\"\\r\\n'\n", + "2026-03-30 11:29:07,522 - pylabrobot - IO - [MT Scale] Received response: b'I4 A \"B207696838\"\\r\\n'\n", + "2026-03-30 11:29:07,523 - pylabrobot - IO - [MT Scale] Sent command: I1\n", + "2026-03-30 11:29:07,525 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I1\\r\\n'\n", + "2026-03-30 11:29:07,569 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I1 A \"01\" \"2.30\" \"2.22\" \"\" \"\"\\r\\n'\n", + "2026-03-30 11:29:07,572 - pylabrobot - IO - [MT Scale] Received response: b'I1 A \"01\" \"2.30\" \"2.22\" \"\" \"\"\\r\\n'\n", + "2026-03-30 11:29:07,573 - pylabrobot - IO - [MT Scale] Sent command: I2\n", + "2026-03-30 11:29:07,581 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I2\\r\\n'\n", + "2026-03-30 11:29:07,649 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", + "2026-03-30 11:29:07,651 - pylabrobot - IO - [MT Scale] Received response: b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", + "2026-03-30 11:29:07,662 - pylabrobot - IO - [MT Scale] Sent command: I2\n", + "2026-03-30 11:29:07,663 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I2\\r\\n'\n", + "2026-03-30 11:29:07,729 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", + "2026-03-30 11:29:07,730 - pylabrobot - IO - [MT Scale] Received response: b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", + "2026-03-30 11:29:07,731 - pylabrobot - INFO - [MT Scale] Connected to Mettler Toledo scale on /dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0\n", + "Device type: WXS205SDU WXA-Bridge\n", + "Serial number: B207696838\n", + "Capacity: 220.0 g\n", + "MT-SICS levels: [0, 1]\n" ] } ], "source": [ "# Update port for your system\n", - "backend = MettlerToledoWXS205SDUBackend(port=\"/dev/ttyUSB2\")\n", + "backend = MettlerToledoWXS205SDUBackend(port=\"/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0\")\n", "scale = Scale(name=\"validation_scale\", backend=backend, size_x=0, size_y=0, size_z=0)\n", "\n", "await scale.setup()" @@ -118,9 +108,21 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 4, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Device type: WXS205SDU WXA-Bridge\n", + "Serial number: B207696838\n", + "Capacity: 220.009 g\n", + "MT-SICS levels: [0, 1]\n", + "PASS: setup populated all identity fields\n" + ] + } + ], "source": [ "print(f\"Device type: {backend.device_type}\")\n", "print(f\"Serial number: {backend.serial_number}\")\n", @@ -151,9 +153,29 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 5, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2026-03-30 11:29:22,637 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] reset_input_buffer\n", + "2026-03-30 11:29:22,638 - pylabrobot - IO - [MT Scale] Sent command: @\n", + "2026-03-30 11:29:22,639 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'@\\r\\n'\n", + "2026-03-30 11:29:22,693 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I4 A \"B207696838\"\\r\\n'\n", + "2026-03-30 11:29:22,694 - pylabrobot - IO - [MT Scale] Received response: b'I4 A \"B207696838\"\\r\\n'\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Cancel returned serial number: B207696838\n", + "PASS: cancel returns correct serial number\n" + ] + } + ], "source": [ "serial_number = await backend.cancel()\n", "print(f\"Cancel returned serial number: {serial_number}\")\n", @@ -170,9 +192,28 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 6, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2026-03-30 11:29:29,649 - pylabrobot - IO - [MT Scale] Sent command: I4\n", + "2026-03-30 11:29:29,651 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I4\\r\\n'\n", + "2026-03-30 11:29:29,694 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I4 A \"B207696838\"\\r\\n'\n", + "2026-03-30 11:29:29,696 - pylabrobot - IO - [MT Scale] Received response: b'I4 A \"B207696838\"\\r\\n'\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Serial number: B207696838\n", + "PASS: serial number is non-empty\n" + ] + } + ], "source": [ "sn = await backend.request_serial_number()\n", "print(f\"Serial number: {sn}\")\n", @@ -189,9 +230,33 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 7, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2026-03-30 11:29:32,001 - pylabrobot - IO - [MT Scale] Sent command: I2\n", + "2026-03-30 11:29:32,005 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I2\\r\\n'\n", + "2026-03-30 11:29:32,061 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", + "2026-03-30 11:29:32,062 - pylabrobot - IO - [MT Scale] Received response: b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", + "2026-03-30 11:29:32,064 - pylabrobot - IO - [MT Scale] Sent command: I2\n", + "2026-03-30 11:29:32,065 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I2\\r\\n'\n", + "2026-03-30 11:29:32,124 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", + "2026-03-30 11:29:32,125 - pylabrobot - IO - [MT Scale] Received response: b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Device type: WXS205SDU WXA-Bridge\n", + "Capacity: 220.009 g\n", + "PASS: device type and capacity valid\n" + ] + } + ], "source": [ "device_type = await backend.request_device_type()\n", "capacity = await backend.request_capacity()\n", @@ -211,9 +276,28 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 8, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2026-03-30 11:29:34,955 - pylabrobot - IO - [MT Scale] Sent command: I1\n", + "2026-03-30 11:29:34,959 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I1\\r\\n'\n", + "2026-03-30 11:29:35,002 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I1 A \"01\" \"2.30\" \"2.22\" \"\" \"\"\\r\\n'\n", + "2026-03-30 11:29:35,004 - pylabrobot - IO - [MT Scale] Received response: b'I1 A \"01\" \"2.30\" \"2.22\" \"\" \"\"\\r\\n'\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Supported levels: [0, 1]\n", + "PASS: levels 0 and 1 present (always required)\n" + ] + } + ], "source": [ "levels = await backend._query_mt_sics_levels()\n", "print(f\"Supported levels: {sorted(levels)}\")\n", @@ -231,9 +315,28 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 9, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2026-03-30 11:29:40,982 - pylabrobot - IO - [MT Scale] Sent command: S\n", + "2026-03-30 11:29:40,987 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", + "2026-03-30 11:29:41,078 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S -0.00102 g\\r\\n'\n", + "2026-03-30 11:29:41,079 - pylabrobot - IO - [MT Scale] Received response: b'S S -0.00102 g\\r\\n'\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Stable weight (empty pan): -0.00102 g\n", + "PASS: stable weight returns float\n" + ] + } + ], "source": [ "weight = await backend.read_stable_weight()\n", "print(f\"Stable weight (empty pan): {weight} g\")\n", @@ -250,9 +353,28 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 10, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2026-03-30 11:29:44,419 - pylabrobot - IO - [MT Scale] Sent command: SI\n", + "2026-03-30 11:29:44,422 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", + "2026-03-30 11:29:44,466 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S -0.00102 g\\r\\n'\n", + "2026-03-30 11:29:44,469 - pylabrobot - IO - [MT Scale] Received response: b'S S -0.00102 g\\r\\n'\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Immediate weight: -0.00102 g\n", + "PASS: immediate weight returns float\n" + ] + } + ], "source": [ "weight = await backend.read_weight_value_immediately()\n", "print(f\"Immediate weight: {weight} g\")\n", @@ -269,9 +391,32 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 11, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2026-03-30 11:29:47,415 - pylabrobot - IO - [MT Scale] Sent command: Z\n", + "2026-03-30 11:29:47,419 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'Z\\r\\n'\n", + "2026-03-30 11:29:47,647 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'Z A\\r\\n'\n", + "2026-03-30 11:29:47,648 - pylabrobot - IO - [MT Scale] Received response: b'Z A\\r\\n'\n", + "2026-03-30 11:29:47,648 - pylabrobot - IO - [MT Scale] Sent command: SI\n", + "2026-03-30 11:29:47,650 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", + "2026-03-30 11:29:47,680 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 11:29:47,682 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Weight after zero: 0.0 g\n", + "PASS: zero sets weight to ~0\n" + ] + } + ], "source": [ "await scale.zero(timeout=\"stable\")\n", "weight = await backend.read_weight_value_immediately()\n", @@ -289,9 +434,32 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 12, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2026-03-30 11:29:51,308 - pylabrobot - IO - [MT Scale] Sent command: ZI\n", + "2026-03-30 11:29:51,312 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'ZI\\r\\n'\n", + "2026-03-30 11:29:51,341 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'ZI S\\r\\n'\n", + "2026-03-30 11:29:51,341 - pylabrobot - IO - [MT Scale] Received response: b'ZI S\\r\\n'\n", + "2026-03-30 11:29:51,342 - pylabrobot - IO - [MT Scale] Sent command: SI\n", + "2026-03-30 11:29:51,344 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", + "2026-03-30 11:29:51,373 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 11:29:51,374 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Weight after zero immediately: 0.0 g\n", + "PASS: zero immediately sets weight to ~0\n" + ] + } + ], "source": [ "await scale.zero(timeout=0)\n", "weight = await backend.read_weight_value_immediately()\n", @@ -319,9 +487,53 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 13, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdin", + "output_type": "stream", + "text": [ + "Place a container on the scale and press Enter... \n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2026-03-30 11:30:01,504 - pylabrobot - IO - [MT Scale] Sent command: Z\n", + "2026-03-30 11:30:01,506 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'Z\\r\\n'\n", + "2026-03-30 11:30:01,796 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'Z A\\r\\n'\n", + "2026-03-30 11:30:01,797 - pylabrobot - IO - [MT Scale] Received response: b'Z A\\r\\n'\n", + "2026-03-30 11:30:01,799 - pylabrobot - IO - [MT Scale] Sent command: T\n", + "2026-03-30 11:30:01,801 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'T\\r\\n'\n", + "2026-03-30 11:30:02,211 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'T S 0.00000 g\\r\\n'\n", + "2026-03-30 11:30:02,212 - pylabrobot - IO - [MT Scale] Received response: b'T S 0.00000 g\\r\\n'\n", + "2026-03-30 11:30:02,213 - pylabrobot - IO - [MT Scale] Sent command: TA\n", + "2026-03-30 11:30:02,214 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'TA\\r\\n'\n", + "2026-03-30 11:30:02,307 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'TA A 0.00000 g\\r\\n'\n", + "2026-03-30 11:30:02,308 - pylabrobot - IO - [MT Scale] Received response: b'TA A 0.00000 g\\r\\n'\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Tare weight: 0.0 g\n" + ] + }, + { + "ename": "AssertionError", + "evalue": "Expected positive tare, got 0.0", + "output_type": "error", + "traceback": [ + "\u001b[31m---------------------------------------------------------------------------\u001b[39m", + "\u001b[31mAssertionError\u001b[39m Traceback (most recent call last)", + "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[13]\u001b[39m\u001b[32m, line 6\u001b[39m\n\u001b[32m 4\u001b[39m tare = \u001b[38;5;28;01mawait\u001b[39;00m scale.request_tare_weight()\n\u001b[32m 5\u001b[39m \u001b[38;5;28mprint\u001b[39m(\u001b[33mf\u001b[39m\u001b[33m\"\u001b[39m\u001b[33mTare weight: \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mtare\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m g\u001b[39m\u001b[33m\"\u001b[39m)\n\u001b[32m----> \u001b[39m\u001b[32m6\u001b[39m \u001b[38;5;28;01massert\u001b[39;00m tare > \u001b[32m0\u001b[39m, \u001b[33mf\u001b[39m\u001b[33m\"\u001b[39m\u001b[33mExpected positive tare, got \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mtare\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m\"\u001b[39m\n\u001b[32m 7\u001b[39m \u001b[38;5;28mprint\u001b[39m(\u001b[33m\"\u001b[39m\u001b[33mPASS: tare stores container weight\u001b[39m\u001b[33m\"\u001b[39m)\n", + "\u001b[31mAssertionError\u001b[39m: Expected positive tare, got 0.0" + ] + } + ], "source": [ "input(\"Place a container on the scale and press Enter...\")\n", "await scale.zero(timeout=\"stable\")\n", @@ -341,9 +553,28 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 14, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2026-03-30 11:30:08,454 - pylabrobot - IO - [MT Scale] Sent command: TA\n", + "2026-03-30 11:30:08,463 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'TA\\r\\n'\n", + "2026-03-30 11:30:08,511 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'TA A 0.00000 g\\r\\n'\n", + "2026-03-30 11:30:08,517 - pylabrobot - IO - [MT Scale] Received response: b'TA A 0.00000 g\\r\\n'\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Tare weight from memory: 0.0 g\n", + "PASS: tare weight readable from memory\n" + ] + } + ], "source": [ "tare = await scale.request_tare_weight()\n", "print(f\"Tare weight from memory: {tare} g\")\n", @@ -360,9 +591,32 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 15, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2026-03-30 11:30:10,949 - pylabrobot - IO - [MT Scale] Sent command: TAC\n", + "2026-03-30 11:30:10,950 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'TAC\\r\\n'\n", + "2026-03-30 11:30:10,972 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'TAC A\\r\\n'\n", + "2026-03-30 11:30:10,973 - pylabrobot - IO - [MT Scale] Received response: b'TAC A\\r\\n'\n", + "2026-03-30 11:30:10,973 - pylabrobot - IO - [MT Scale] Sent command: TA\n", + "2026-03-30 11:30:10,975 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'TA\\r\\n'\n", + "2026-03-30 11:30:11,054 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'TA A 0.00000 g\\r\\n'\n", + "2026-03-30 11:30:11,056 - pylabrobot - IO - [MT Scale] Received response: b'TA A 0.00000 g\\r\\n'\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Tare after clear: 0.0 g\n", + "PASS: clear tare resets tare to 0\n" + ] + } + ], "source": [ "await backend.clear_tare()\n", "tare_after_clear = await scale.request_tare_weight()\n", @@ -380,9 +634,34 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 16, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2026-03-30 11:30:12,434 - pylabrobot - IO - [MT Scale] Sent command: SC 3000\n", + "2026-03-30 11:30:12,438 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SC 3000\\r\\n'\n", + "2026-03-30 11:30:12,459 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'ES\\r\\n'\n", + "2026-03-30 11:30:12,461 - pylabrobot - IO - [MT Scale] Received response: b'ES\\r\\n'\n" + ] + }, + { + "ename": "MettlerToledoError", + "evalue": "Syntax error: The weigh module/balance has not recognized the received command or the command is not allowed", + "output_type": "error", + "traceback": [ + "\u001b[31m---------------------------------------------------------------------------\u001b[39m", + "\u001b[31mMettlerToledoError\u001b[39m Traceback (most recent call last)", + "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[16]\u001b[39m\u001b[32m, line 1\u001b[39m\n\u001b[32m----> \u001b[39m\u001b[32m1\u001b[39m weight = \u001b[38;5;28;01mawait\u001b[39;00m backend.read_dynamic_weight(timeout=\u001b[32m3.0\u001b[39m)\n\u001b[32m 2\u001b[39m \u001b[38;5;28mprint\u001b[39m(\u001b[33mf\u001b[39m\u001b[33m\"\u001b[39m\u001b[33mDynamic weight (3s timeout): \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mweight\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m g\u001b[39m\u001b[33m\"\u001b[39m)\n\u001b[32m 3\u001b[39m \u001b[38;5;28;01massert\u001b[39;00m \u001b[38;5;28misinstance\u001b[39m(weight, \u001b[38;5;28mfloat\u001b[39m)\n", + "\u001b[36mFile \u001b[39m\u001b[32m~/Desktop/GitHub/pylabrobot/pylabrobot/scales/mettler_toledo/backend.py:512\u001b[39m, in \u001b[36mMettlerToledoWXS205SDUBackend.read_dynamic_weight\u001b[39m\u001b[34m(self, timeout)\u001b[39m\n\u001b[32m 503\u001b[39m \u001b[38;5;250m\u001b[39m\u001b[33;03m\"\"\"Read a stable weight value from the machine within a given timeout, or\u001b[39;00m\n\u001b[32m 504\u001b[39m \u001b[33;03mreturn the current weight value if not possible. (MEASUREMENT command)\u001b[39;00m\n\u001b[32m 505\u001b[39m \n\u001b[32m 506\u001b[39m \u001b[33;03mArgs:\u001b[39;00m\n\u001b[32m 507\u001b[39m \u001b[33;03m timeout: The timeout in seconds.\u001b[39;00m\n\u001b[32m 508\u001b[39m \u001b[33;03m\"\"\"\u001b[39;00m\n\u001b[32m 510\u001b[39m timeout = \u001b[38;5;28mint\u001b[39m(timeout * \u001b[32m1000\u001b[39m) \u001b[38;5;66;03m# convert to milliseconds\u001b[39;00m\n\u001b[32m--> \u001b[39m\u001b[32m512\u001b[39m responses = \u001b[38;5;28;01mawait\u001b[39;00m \u001b[38;5;28mself\u001b[39m.send_command(\u001b[33mf\u001b[39m\u001b[33m\"\u001b[39m\u001b[33mSC \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mtimeout\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m\"\u001b[39m)\n\u001b[32m 513\u001b[39m \u001b[38;5;28mself\u001b[39m._validate_response(responses[\u001b[32m0\u001b[39m], \u001b[32m4\u001b[39m, \u001b[33m\"\u001b[39m\u001b[33mSC\u001b[39m\u001b[33m\"\u001b[39m)\n\u001b[32m 514\u001b[39m \u001b[38;5;28mself\u001b[39m._validate_unit(responses[\u001b[32m0\u001b[39m].data[\u001b[32m1\u001b[39m], \u001b[33m\"\u001b[39m\u001b[33mSC\u001b[39m\u001b[33m\"\u001b[39m)\n", + "\u001b[36mFile \u001b[39m\u001b[32m~/Desktop/GitHub/pylabrobot/pylabrobot/scales/mettler_toledo/backend.py:286\u001b[39m, in \u001b[36mMettlerToledoWXS205SDUBackend.send_command\u001b[39m\u001b[34m(self, command, timeout)\u001b[39m\n\u001b[32m 284\u001b[39m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[32m 285\u001b[39m response = MettlerToledoResponse(command=\u001b[33m\"\u001b[39m\u001b[33m\"\u001b[39m, status=\u001b[33m\"\u001b[39m\u001b[33m\"\u001b[39m, data=[])\n\u001b[32m--> \u001b[39m\u001b[32m286\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[43m.\u001b[49m\u001b[43m_parse_basic_errors\u001b[49m\u001b[43m(\u001b[49m\u001b[43mresponse\u001b[49m\u001b[43m)\u001b[49m\n\u001b[32m 287\u001b[39m responses.append(response)\n\u001b[32m 289\u001b[39m \u001b[38;5;66;03m# Status B means more responses follow; anything else (A, etc.) is final\u001b[39;00m\n", + "\u001b[36mFile \u001b[39m\u001b[32m~/Desktop/GitHub/pylabrobot/pylabrobot/scales/mettler_toledo/backend.py:207\u001b[39m, in \u001b[36mMettlerToledoWXS205SDUBackend._parse_basic_errors\u001b[39m\u001b[34m(self, response)\u001b[39m\n\u001b[32m 205\u001b[39m \u001b[38;5;66;03m# General error messages: ES, ET, EL (status is \"\" for these)\u001b[39;00m\n\u001b[32m 206\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m response.command == \u001b[33m\"\u001b[39m\u001b[33mES\u001b[39m\u001b[33m\"\u001b[39m:\n\u001b[32m--> \u001b[39m\u001b[32m207\u001b[39m \u001b[38;5;28;01mraise\u001b[39;00m MettlerToledoError.syntax_error()\n\u001b[32m 208\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m response.command == \u001b[33m\"\u001b[39m\u001b[33mET\u001b[39m\u001b[33m\"\u001b[39m:\n\u001b[32m 209\u001b[39m \u001b[38;5;28;01mraise\u001b[39;00m MettlerToledoError.transmission_error()\n", + "\u001b[31mMettlerToledoError\u001b[39m: Syntax error: The weigh module/balance has not recognized the received command or the command is not allowed" + ] + } + ], "source": [ "weight = await backend.read_dynamic_weight(timeout=3.0)\n", "print(f\"Dynamic weight (3s timeout): {weight} g\")\n", @@ -399,9 +678,34 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 17, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2026-03-30 11:30:22,642 - pylabrobot - IO - [MT Scale] Sent command: C\n", + "2026-03-30 11:30:22,646 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'C\\r\\n'\n", + "2026-03-30 11:30:22,659 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'ES\\r\\n'\n", + "2026-03-30 11:30:22,660 - pylabrobot - IO - [MT Scale] Received response: b'ES\\r\\n'\n" + ] + }, + { + "ename": "MettlerToledoError", + "evalue": "Syntax error: The weigh module/balance has not recognized the received command or the command is not allowed", + "output_type": "error", + "traceback": [ + "\u001b[31m---------------------------------------------------------------------------\u001b[39m", + "\u001b[31mMettlerToledoError\u001b[39m Traceback (most recent call last)", + "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[17]\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 backend.cancel_all()\n\u001b[32m 2\u001b[39m \u001b[38;5;28mprint\u001b[39m(\u001b[33m\"\u001b[39m\u001b[33mPASS: cancel_all completed without error\u001b[39m\u001b[33m\"\u001b[39m)\n", + "\u001b[36mFile \u001b[39m\u001b[32m~/Desktop/GitHub/pylabrobot/pylabrobot/scales/mettler_toledo/backend.py:324\u001b[39m, in \u001b[36mMettlerToledoWXS205SDUBackend.cancel_all\u001b[39m\u001b[34m(self)\u001b[39m\n\u001b[32m 314\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[34mcancel_all\u001b[39m(\u001b[38;5;28mself\u001b[39m) -> \u001b[38;5;28;01mNone\u001b[39;00m:\n\u001b[32m 315\u001b[39m \u001b[38;5;250m \u001b[39m\u001b[33;03m\"\"\"C - Cancel all active and pending interface commands.\u001b[39;00m\n\u001b[32m 316\u001b[39m \n\u001b[32m 317\u001b[39m \u001b[33;03m Unlike cancel() (@), this does not reset the device - it only cancels\u001b[39;00m\n\u001b[32m (...)\u001b[39m\u001b[32m 322\u001b[39m \u001b[33;03m C A (complete). Both responses are consumed to keep the serial buffer clean.\u001b[39;00m\n\u001b[32m 323\u001b[39m \u001b[33;03m \"\"\"\u001b[39;00m\n\u001b[32m--> \u001b[39m\u001b[32m324\u001b[39m responses = \u001b[38;5;28;01mawait\u001b[39;00m \u001b[38;5;28mself\u001b[39m.send_command(\u001b[33m\"\u001b[39m\u001b[33mC\u001b[39m\u001b[33m\"\u001b[39m)\n\u001b[32m 325\u001b[39m \u001b[38;5;66;03m# send_command reads both C B (started) and C A (complete) automatically\u001b[39;00m\n\u001b[32m 326\u001b[39m \u001b[38;5;28mself\u001b[39m._validate_response(responses[\u001b[32m0\u001b[39m], \u001b[32m2\u001b[39m, \u001b[33m\"\u001b[39m\u001b[33mC\u001b[39m\u001b[33m\"\u001b[39m)\n", + "\u001b[36mFile \u001b[39m\u001b[32m~/Desktop/GitHub/pylabrobot/pylabrobot/scales/mettler_toledo/backend.py:286\u001b[39m, in \u001b[36mMettlerToledoWXS205SDUBackend.send_command\u001b[39m\u001b[34m(self, command, timeout)\u001b[39m\n\u001b[32m 284\u001b[39m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[32m 285\u001b[39m response = MettlerToledoResponse(command=\u001b[33m\"\u001b[39m\u001b[33m\"\u001b[39m, status=\u001b[33m\"\u001b[39m\u001b[33m\"\u001b[39m, data=[])\n\u001b[32m--> \u001b[39m\u001b[32m286\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[43m.\u001b[49m\u001b[43m_parse_basic_errors\u001b[49m\u001b[43m(\u001b[49m\u001b[43mresponse\u001b[49m\u001b[43m)\u001b[49m\n\u001b[32m 287\u001b[39m responses.append(response)\n\u001b[32m 289\u001b[39m \u001b[38;5;66;03m# Status B means more responses follow; anything else (A, etc.) is final\u001b[39;00m\n", + "\u001b[36mFile \u001b[39m\u001b[32m~/Desktop/GitHub/pylabrobot/pylabrobot/scales/mettler_toledo/backend.py:207\u001b[39m, in \u001b[36mMettlerToledoWXS205SDUBackend._parse_basic_errors\u001b[39m\u001b[34m(self, response)\u001b[39m\n\u001b[32m 205\u001b[39m \u001b[38;5;66;03m# General error messages: ES, ET, EL (status is \"\" for these)\u001b[39;00m\n\u001b[32m 206\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m response.command == \u001b[33m\"\u001b[39m\u001b[33mES\u001b[39m\u001b[33m\"\u001b[39m:\n\u001b[32m--> \u001b[39m\u001b[32m207\u001b[39m \u001b[38;5;28;01mraise\u001b[39;00m MettlerToledoError.syntax_error()\n\u001b[32m 208\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m response.command == \u001b[33m\"\u001b[39m\u001b[33mET\u001b[39m\u001b[33m\"\u001b[39m:\n\u001b[32m 209\u001b[39m \u001b[38;5;28;01mraise\u001b[39;00m MettlerToledoError.transmission_error()\n", + "\u001b[31mMettlerToledoError\u001b[39m: Syntax error: The weigh module/balance has not recognized the received command or the command is not allowed" + ] + } + ], "source": [ "await backend.cancel_all()\n", "print(\"PASS: cancel_all completed without error\")" @@ -416,10 +720,42 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 18, "metadata": {}, - "outputs": [], - "source": "import asyncio\n\nawait backend.set_display_text(\"PLR TEST\")\nawait asyncio.sleep(2)\nawait backend.set_weight_display()\nprint(\"PASS: display text set and restored (check terminal if connected)\")" + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2026-03-30 11:30:25,587 - pylabrobot - IO - [MT Scale] Sent command: D \"PLR TEST\"\n", + "2026-03-30 11:30:25,590 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'D \"PLR TEST\"\\r\\n'\n", + "2026-03-30 11:30:25,617 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'ES\\r\\n'\n", + "2026-03-30 11:30:25,618 - pylabrobot - IO - [MT Scale] Received response: b'ES\\r\\n'\n" + ] + }, + { + "ename": "MettlerToledoError", + "evalue": "Syntax error: The weigh module/balance has not recognized the received command or the command is not allowed", + "output_type": "error", + "traceback": [ + "\u001b[31m---------------------------------------------------------------------------\u001b[39m", + "\u001b[31mMettlerToledoError\u001b[39m Traceback (most recent call last)", + "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[18]\u001b[39m\u001b[32m, line 3\u001b[39m\n\u001b[32m 1\u001b[39m \u001b[38;5;28;01mimport\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[34;01masyncio\u001b[39;00m\n\u001b[32m----> \u001b[39m\u001b[32m3\u001b[39m \u001b[38;5;28;01mawait\u001b[39;00m backend.set_display_text(\u001b[33m\"\u001b[39m\u001b[33mPLR TEST\u001b[39m\u001b[33m\"\u001b[39m)\n\u001b[32m 4\u001b[39m \u001b[38;5;28;01mawait\u001b[39;00m asyncio.sleep(\u001b[32m2\u001b[39m)\n\u001b[32m 5\u001b[39m \u001b[38;5;28;01mawait\u001b[39;00m backend.set_weight_display()\n", + "\u001b[36mFile \u001b[39m\u001b[32m~/Desktop/GitHub/pylabrobot/pylabrobot/scales/mettler_toledo/backend.py:557\u001b[39m, in \u001b[36mMettlerToledoWXS205SDUBackend.set_display_text\u001b[39m\u001b[34m(self, text)\u001b[39m\n\u001b[32m 554\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[34mset_display_text\u001b[39m(\u001b[38;5;28mself\u001b[39m, text: \u001b[38;5;28mstr\u001b[39m) -> List[MettlerToledoResponse]:\n\u001b[32m 555\u001b[39m \u001b[38;5;250m \u001b[39m\u001b[33;03m\"\"\"Set the display text of the scale. Return to the normal weight display with\u001b[39;00m\n\u001b[32m 556\u001b[39m \u001b[33;03m self.set_weight_display().\"\"\"\u001b[39;00m\n\u001b[32m--> \u001b[39m\u001b[32m557\u001b[39m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;01mawait\u001b[39;00m \u001b[38;5;28mself\u001b[39m.send_command(\u001b[33mf\u001b[39m\u001b[33m'\u001b[39m\u001b[33mD \u001b[39m\u001b[33m\"\u001b[39m\u001b[38;5;132;01m{\u001b[39;00mtext\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m\"\u001b[39m\u001b[33m'\u001b[39m)\n", + "\u001b[36mFile \u001b[39m\u001b[32m~/Desktop/GitHub/pylabrobot/pylabrobot/scales/mettler_toledo/backend.py:286\u001b[39m, in \u001b[36mMettlerToledoWXS205SDUBackend.send_command\u001b[39m\u001b[34m(self, command, timeout)\u001b[39m\n\u001b[32m 284\u001b[39m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[32m 285\u001b[39m response = MettlerToledoResponse(command=\u001b[33m\"\u001b[39m\u001b[33m\"\u001b[39m, status=\u001b[33m\"\u001b[39m\u001b[33m\"\u001b[39m, data=[])\n\u001b[32m--> \u001b[39m\u001b[32m286\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[43m.\u001b[49m\u001b[43m_parse_basic_errors\u001b[49m\u001b[43m(\u001b[49m\u001b[43mresponse\u001b[49m\u001b[43m)\u001b[49m\n\u001b[32m 287\u001b[39m responses.append(response)\n\u001b[32m 289\u001b[39m \u001b[38;5;66;03m# Status B means more responses follow; anything else (A, etc.) is final\u001b[39;00m\n", + "\u001b[36mFile \u001b[39m\u001b[32m~/Desktop/GitHub/pylabrobot/pylabrobot/scales/mettler_toledo/backend.py:207\u001b[39m, in \u001b[36mMettlerToledoWXS205SDUBackend._parse_basic_errors\u001b[39m\u001b[34m(self, response)\u001b[39m\n\u001b[32m 205\u001b[39m \u001b[38;5;66;03m# General error messages: ES, ET, EL (status is \"\" for these)\u001b[39;00m\n\u001b[32m 206\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m response.command == \u001b[33m\"\u001b[39m\u001b[33mES\u001b[39m\u001b[33m\"\u001b[39m:\n\u001b[32m--> \u001b[39m\u001b[32m207\u001b[39m \u001b[38;5;28;01mraise\u001b[39;00m MettlerToledoError.syntax_error()\n\u001b[32m 208\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m response.command == \u001b[33m\"\u001b[39m\u001b[33mET\u001b[39m\u001b[33m\"\u001b[39m:\n\u001b[32m 209\u001b[39m \u001b[38;5;28;01mraise\u001b[39;00m MettlerToledoError.transmission_error()\n", + "\u001b[31mMettlerToledoError\u001b[39m: Syntax error: The weigh module/balance has not recognized the received command or the command is not allowed" + ] + } + ], + "source": [ + "import asyncio\n", + "\n", + "await backend.set_display_text(\"PLR TEST\")\n", + "await asyncio.sleep(2)\n", + "await backend.set_weight_display()\n", + "print(\"PASS: display text set and restored (check terminal if connected)\")" + ] }, { "cell_type": "markdown", @@ -432,9 +768,32 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 19, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2026-03-30 11:30:28,230 - pylabrobot - IO - [MT Scale] Sent command: ZC 5000\n", + "2026-03-30 11:30:28,233 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'ZC 5000\\r\\n'\n", + "2026-03-30 11:30:28,270 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'ES\\r\\n'\n", + "2026-03-30 11:30:28,271 - pylabrobot - IO - [MT Scale] Received response: b'ES\\r\\n'\n", + "2026-03-30 11:30:28,275 - pylabrobot - IO - [MT Scale] Sent command: TC 5000\n", + "2026-03-30 11:30:28,279 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'TC 5000\\r\\n'\n", + "2026-03-30 11:30:28,302 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'ES\\r\\n'\n", + "2026-03-30 11:30:28,306 - pylabrobot - IO - [MT Scale] Received response: b'ES\\r\\n'\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "ZC: not supported (ES) - expected for WXS205SDU\n", + "TC: not supported (ES) - expected for WXS205SDU\n" + ] + } + ], "source": [ "from pylabrobot.scales.mettler_toledo.errors import MettlerToledoError\n", "\n", @@ -466,9 +825,17 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 20, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "SKIP: Level 2 not supported\n" + ] + } + ], "source": [ "if 2 in backend._mt_sics_levels:\n", " await backend.set_host_unit_grams()\n", @@ -486,9 +853,17 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 21, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "SKIP: Level 2 not supported\n" + ] + } + ], "source": [ "if 2 in backend._mt_sics_levels:\n", " remaining = await backend.request_remaining_weighing_range()\n", @@ -509,9 +884,17 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 22, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "SKIP: Level 2 not supported\n" + ] + } + ], "source": [ "if 2 in backend._mt_sics_levels:\n", " temp = await backend.measure_temperature()\n", @@ -534,9 +917,70 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 23, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2026-03-30 11:30:52,063 - pylabrobot - IO - [MT Scale] Sent command: Z\n", + "2026-03-30 11:30:52,066 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'Z\\r\\n'\n", + "2026-03-30 11:30:52,331 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'Z A\\r\\n'\n", + "2026-03-30 11:30:52,332 - pylabrobot - IO - [MT Scale] Received response: b'Z A\\r\\n'\n", + "2026-03-30 11:30:52,333 - pylabrobot - IO - [MT Scale] Sent command: SI\n", + "2026-03-30 11:30:52,335 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", + "2026-03-30 11:30:52,364 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 11:30:52,367 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Frontend zero + read: 0.0 g\n" + ] + }, + { + "name": "stdin", + "output_type": "stream", + "text": [ + "Place a container on the scale and press Enter... \n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2026-03-30 11:30:54,533 - pylabrobot - IO - [MT Scale] Sent command: T\n", + "2026-03-30 11:30:54,534 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'T\\r\\n'\n", + "2026-03-30 11:30:54,904 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'T S 0.00000 g\\r\\n'\n", + "2026-03-30 11:30:54,905 - pylabrobot - IO - [MT Scale] Received response: b'T S 0.00000 g\\r\\n'\n", + "2026-03-30 11:30:54,906 - pylabrobot - IO - [MT Scale] Sent command: TA\n", + "2026-03-30 11:30:54,907 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'TA\\r\\n'\n", + "2026-03-30 11:30:55,000 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'TA A 0.00000 g\\r\\n'\n", + "2026-03-30 11:30:55,001 - pylabrobot - IO - [MT Scale] Received response: b'TA A 0.00000 g\\r\\n'\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Frontend tare weight: 0.0 g\n" + ] + }, + { + "ename": "AssertionError", + "evalue": "", + "output_type": "error", + "traceback": [ + "\u001b[31m---------------------------------------------------------------------------\u001b[39m", + "\u001b[31mAssertionError\u001b[39m Traceback (most recent call last)", + "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[23]\u001b[39m\u001b[32m, line 12\u001b[39m\n\u001b[32m 10\u001b[39m tare = \u001b[38;5;28;01mawait\u001b[39;00m scale.request_tare_weight()\n\u001b[32m 11\u001b[39m \u001b[38;5;28mprint\u001b[39m(\u001b[33mf\u001b[39m\u001b[33m\"\u001b[39m\u001b[33mFrontend tare weight: \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mtare\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m g\u001b[39m\u001b[33m\"\u001b[39m)\n\u001b[32m---> \u001b[39m\u001b[32m12\u001b[39m \u001b[38;5;28;01massert\u001b[39;00m tare > \u001b[32m0\u001b[39m\n\u001b[32m 14\u001b[39m \u001b[38;5;66;03m# Read via frontend\u001b[39;00m\n\u001b[32m 15\u001b[39m w = \u001b[38;5;28;01mawait\u001b[39;00m scale.read_weight(timeout=\u001b[33m\"\u001b[39m\u001b[33mstable\u001b[39m\u001b[33m\"\u001b[39m)\n", + "\u001b[31mAssertionError\u001b[39m: " + ] + } + ], "source": [ "# Zero via frontend\n", "await scale.zero(timeout=\"stable\")\n", @@ -569,9 +1013,104 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 24, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2026-03-30 11:31:00,849 - pylabrobot - IO - [MT Scale] Sent command: S\n", + "2026-03-30 11:31:00,850 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", + "2026-03-30 11:31:00,884 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 11:31:00,886 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 11:31:00,888 - pylabrobot - IO - [MT Scale] Sent command: S\n", + "2026-03-30 11:31:00,890 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", + "2026-03-30 11:31:00,980 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 11:31:00,980 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 11:31:00,981 - pylabrobot - IO - [MT Scale] Sent command: S\n", + "2026-03-30 11:31:00,985 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", + "2026-03-30 11:31:01,092 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 11:31:01,093 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 11:31:01,093 - pylabrobot - IO - [MT Scale] Sent command: S\n", + "2026-03-30 11:31:01,096 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", + "2026-03-30 11:31:01,188 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 11:31:01,188 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 11:31:01,191 - pylabrobot - IO - [MT Scale] Sent command: S\n", + "2026-03-30 11:31:01,192 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", + "2026-03-30 11:31:01,284 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 11:31:01,285 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 11:31:01,287 - pylabrobot - IO - [MT Scale] Sent command: S\n", + "2026-03-30 11:31:01,288 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", + "2026-03-30 11:31:01,380 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 11:31:01,381 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 11:31:01,381 - pylabrobot - IO - [MT Scale] Sent command: S\n", + "2026-03-30 11:31:01,383 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", + "2026-03-30 11:31:01,475 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 11:31:01,476 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 11:31:01,477 - pylabrobot - IO - [MT Scale] Sent command: S\n", + "2026-03-30 11:31:01,478 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", + "2026-03-30 11:31:01,572 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 11:31:01,573 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 11:31:01,574 - pylabrobot - IO - [MT Scale] Sent command: S\n", + "2026-03-30 11:31:01,575 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", + "2026-03-30 11:31:01,667 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 11:31:01,668 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 11:31:01,668 - pylabrobot - IO - [MT Scale] Sent command: S\n", + "2026-03-30 11:31:01,669 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", + "2026-03-30 11:31:01,780 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 11:31:01,780 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 11:31:01,781 - pylabrobot - IO - [MT Scale] Sent command: SI\n", + "2026-03-30 11:31:01,782 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", + "2026-03-30 11:31:01,812 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 11:31:01,813 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 11:31:01,815 - pylabrobot - IO - [MT Scale] Sent command: SI\n", + "2026-03-30 11:31:01,817 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", + "2026-03-30 11:31:01,860 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 11:31:01,861 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 11:31:01,862 - pylabrobot - IO - [MT Scale] Sent command: SI\n", + "2026-03-30 11:31:01,865 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", + "2026-03-30 11:31:01,907 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 11:31:01,907 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 11:31:01,908 - pylabrobot - IO - [MT Scale] Sent command: SI\n", + "2026-03-30 11:31:01,913 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", + "2026-03-30 11:31:01,955 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 11:31:01,959 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 11:31:01,962 - pylabrobot - IO - [MT Scale] Sent command: SI\n", + "2026-03-30 11:31:01,966 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", + "2026-03-30 11:31:02,003 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 11:31:02,004 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 11:31:02,004 - pylabrobot - IO - [MT Scale] Sent command: SI\n", + "2026-03-30 11:31:02,006 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", + "2026-03-30 11:31:02,035 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 11:31:02,037 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 11:31:02,040 - pylabrobot - IO - [MT Scale] Sent command: SI\n", + "2026-03-30 11:31:02,043 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", + "2026-03-30 11:31:02,085 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 11:31:02,087 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 11:31:02,089 - pylabrobot - IO - [MT Scale] Sent command: SI\n", + "2026-03-30 11:31:02,094 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", + "2026-03-30 11:31:02,137 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 11:31:02,139 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 11:31:02,141 - pylabrobot - IO - [MT Scale] Sent command: SI\n", + "2026-03-30 11:31:02,149 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", + "2026-03-30 11:31:02,196 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 11:31:02,198 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 11:31:02,200 - pylabrobot - IO - [MT Scale] Sent command: SI\n", + "2026-03-30 11:31:02,204 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", + "2026-03-30 11:31:02,243 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 11:31:02,254 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Stable read: 93.20 +/- 19.10 ms\n", + "Immediate read: 47.39 +/- 7.81 ms\n" + ] + } + ], "source": [ "import time\n", "\n", @@ -607,14 +1146,36 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 25, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2026-03-30 11:31:07,091 - pylabrobot - INFO - === Hardware validation ended ===\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Log file: ./logs/hardware_validation/2026-03-30_11-28-29_validation.log\n" + ] + } + ], "source": [ "plr_logger.info(\"=== Hardware validation ended ===\")\n", "await scale.stop()\n", "print(f\"Log file: {log_file}\")" ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] } ], "metadata": { @@ -638,4 +1199,4 @@ }, "nbformat": 4, "nbformat_minor": 4 -} \ No newline at end of file +} From 5041343a0f47059608c4346a6b34f3a72d7955b0 Mon Sep 17 00:00:00 2001 From: Camillo Moschner Date: Mon, 30 Mar 2026 11:42:05 +0100 Subject: [PATCH 12/38] enhanced testing design --- .../mettler_toledo/hardware_validation.ipynb | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/pylabrobot/scales/mettler_toledo/hardware_validation.ipynb b/pylabrobot/scales/mettler_toledo/hardware_validation.ipynb index 47f5706bf91..6f8a3f008bc 100644 --- a/pylabrobot/scales/mettler_toledo/hardware_validation.ipynb +++ b/pylabrobot/scales/mettler_toledo/hardware_validation.ipynb @@ -136,6 +136,18 @@ "print(\"PASS: setup populated all identity fields\")" ] }, + { + "cell_type": "markdown", + "source": "### I0 - Discover all implemented commands\n\nThis tells us exactly which MT-SICS commands this specific device supports,\nresolving whether SC, C, D are truly unsupported or just miscategorized by level.", + "metadata": {} + }, + { + "cell_type": "code", + "source": "from collections import defaultdict\n\n# I0 is a multi-response command (B status for each command, A for the last)\nresponses = await backend.send_command(\"I0\")\n\nprint(f\"Total commands implemented: {len(responses)}\")\nprint()\n\n# Group by level\nby_level = defaultdict(list)\nfor resp in responses:\n # Format: I0 B/A <\"command\">\n if len(resp.data) >= 2:\n level = resp.data[0]\n cmd_name = resp.data[1]\n by_level[level].append(cmd_name)\n\nfor level in sorted(by_level.keys()):\n cmds = sorted(by_level[level])\n print(f\"Level {level} ({len(cmds)} commands): {', '.join(cmds)}\")\n\n# Check which commands we use that might not be supported\nour_commands = [\"@\", \"C\", \"D\", \"DW\", \"I0\", \"I1\", \"I2\", \"I4\", \"I50\",\n \"M21\", \"M28\", \"S\", \"SC\", \"SI\", \"T\", \"TA\", \"TAC\",\n \"TI\", \"Z\", \"ZC\", \"ZI\", \"TC\"]\nall_device_cmds = set()\nfor cmds in by_level.values():\n all_device_cmds.update(cmds)\n\nprint()\nprint(\"Commands we use vs device support:\")\nfor cmd in sorted(our_commands):\n status = \"supported\" if cmd in all_device_cmds else \"NOT SUPPORTED\"\n print(f\" {cmd}: {status}\")", + "metadata": {}, + "execution_count": null, + "outputs": [] + }, { "cell_type": "markdown", "metadata": {}, @@ -1199,4 +1211,4 @@ }, "nbformat": 4, "nbformat_minor": 4 -} +} \ No newline at end of file From 92f748ac30466f155d9d8f05bcfd3583c93dd5c4 Mon Sep 17 00:00:00 2001 From: Camillo Moschner Date: Mon, 30 Mar 2026 11:43:56 +0100 Subject: [PATCH 13/38] testing results --- .../mettler_toledo/hardware_validation.ipynb | 647 ++++++++++++------ 1 file changed, 428 insertions(+), 219 deletions(-) diff --git a/pylabrobot/scales/mettler_toledo/hardware_validation.ipynb b/pylabrobot/scales/mettler_toledo/hardware_validation.ipynb index 6f8a3f008bc..7c2076c935e 100644 --- a/pylabrobot/scales/mettler_toledo/hardware_validation.ipynb +++ b/pylabrobot/scales/mettler_toledo/hardware_validation.ipynb @@ -33,7 +33,7 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 11:28:29,103 - pylabrobot - INFO - === Hardware validation started ===\n" + "2026-03-30 11:42:26,797 - pylabrobot - INFO - === Hardware validation started ===\n" ] } ], @@ -58,32 +58,32 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 2, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 11:29:07,453 - pylabrobot.io.serial - INFO - Using explicitly provided port: /dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0 (for VID=1027, PID=24577)\n", - "2026-03-30 11:29:07,456 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] reset_input_buffer\n", - "2026-03-30 11:29:07,457 - pylabrobot - IO - [MT Scale] Sent command: @\n", - "2026-03-30 11:29:07,459 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'@\\r\\n'\n", - "2026-03-30 11:29:07,520 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I4 A \"B207696838\"\\r\\n'\n", - "2026-03-30 11:29:07,522 - pylabrobot - IO - [MT Scale] Received response: b'I4 A \"B207696838\"\\r\\n'\n", - "2026-03-30 11:29:07,523 - pylabrobot - IO - [MT Scale] Sent command: I1\n", - "2026-03-30 11:29:07,525 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I1\\r\\n'\n", - "2026-03-30 11:29:07,569 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I1 A \"01\" \"2.30\" \"2.22\" \"\" \"\"\\r\\n'\n", - "2026-03-30 11:29:07,572 - pylabrobot - IO - [MT Scale] Received response: b'I1 A \"01\" \"2.30\" \"2.22\" \"\" \"\"\\r\\n'\n", - "2026-03-30 11:29:07,573 - pylabrobot - IO - [MT Scale] Sent command: I2\n", - "2026-03-30 11:29:07,581 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I2\\r\\n'\n", - "2026-03-30 11:29:07,649 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", - "2026-03-30 11:29:07,651 - pylabrobot - IO - [MT Scale] Received response: b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", - "2026-03-30 11:29:07,662 - pylabrobot - IO - [MT Scale] Sent command: I2\n", - "2026-03-30 11:29:07,663 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I2\\r\\n'\n", - "2026-03-30 11:29:07,729 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", - "2026-03-30 11:29:07,730 - pylabrobot - IO - [MT Scale] Received response: b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", - "2026-03-30 11:29:07,731 - pylabrobot - INFO - [MT Scale] Connected to Mettler Toledo scale on /dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0\n", + "2026-03-30 11:42:26,828 - pylabrobot.io.serial - INFO - Using explicitly provided port: /dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0 (for VID=1027, PID=24577)\n", + "2026-03-30 11:42:26,837 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] reset_input_buffer\n", + "2026-03-30 11:42:26,840 - pylabrobot - IO - [MT Scale] Sent command: @\n", + "2026-03-30 11:42:26,868 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'@\\r\\n'\n", + "2026-03-30 11:42:26,931 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I4 A \"B207696838\"\\r\\n'\n", + "2026-03-30 11:42:26,932 - pylabrobot - IO - [MT Scale] Received response: b'I4 A \"B207696838\"\\r\\n'\n", + "2026-03-30 11:42:26,932 - pylabrobot - IO - [MT Scale] Sent command: I1\n", + "2026-03-30 11:42:26,933 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I1\\r\\n'\n", + "2026-03-30 11:42:26,981 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I1 A \"01\" \"2.30\" \"2.22\" \"\" \"\"\\r\\n'\n", + "2026-03-30 11:42:26,982 - pylabrobot - IO - [MT Scale] Received response: b'I1 A \"01\" \"2.30\" \"2.22\" \"\" \"\"\\r\\n'\n", + "2026-03-30 11:42:26,983 - pylabrobot - IO - [MT Scale] Sent command: I2\n", + "2026-03-30 11:42:26,986 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I2\\r\\n'\n", + "2026-03-30 11:42:27,042 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", + "2026-03-30 11:42:27,043 - pylabrobot - IO - [MT Scale] Received response: b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", + "2026-03-30 11:42:27,044 - pylabrobot - IO - [MT Scale] Sent command: I2\n", + "2026-03-30 11:42:27,045 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I2\\r\\n'\n", + "2026-03-30 11:42:27,106 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", + "2026-03-30 11:42:27,108 - pylabrobot - IO - [MT Scale] Received response: b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", + "2026-03-30 11:42:27,108 - pylabrobot - INFO - [MT Scale] Connected to Mettler Toledo scale on /dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0\n", "Device type: WXS205SDU WXA-Bridge\n", "Serial number: B207696838\n", "Capacity: 220.0 g\n", @@ -108,7 +108,7 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 3, "metadata": {}, "outputs": [ { @@ -138,15 +138,224 @@ }, { "cell_type": "markdown", - "source": "### I0 - Discover all implemented commands\n\nThis tells us exactly which MT-SICS commands this specific device supports,\nresolving whether SC, C, D are truly unsupported or just miscategorized by level.", - "metadata": {} + "metadata": {}, + "source": [ + "### I0 - Discover all implemented commands\n", + "\n", + "This tells us exactly which MT-SICS commands this specific device supports,\n", + "resolving whether SC, C, D are truly unsupported or just miscategorized by level." + ] }, { "cell_type": "code", - "source": "from collections import defaultdict\n\n# I0 is a multi-response command (B status for each command, A for the last)\nresponses = await backend.send_command(\"I0\")\n\nprint(f\"Total commands implemented: {len(responses)}\")\nprint()\n\n# Group by level\nby_level = defaultdict(list)\nfor resp in responses:\n # Format: I0 B/A <\"command\">\n if len(resp.data) >= 2:\n level = resp.data[0]\n cmd_name = resp.data[1]\n by_level[level].append(cmd_name)\n\nfor level in sorted(by_level.keys()):\n cmds = sorted(by_level[level])\n print(f\"Level {level} ({len(cmds)} commands): {', '.join(cmds)}\")\n\n# Check which commands we use that might not be supported\nour_commands = [\"@\", \"C\", \"D\", \"DW\", \"I0\", \"I1\", \"I2\", \"I4\", \"I50\",\n \"M21\", \"M28\", \"S\", \"SC\", \"SI\", \"T\", \"TA\", \"TAC\",\n \"TI\", \"Z\", \"ZC\", \"ZI\", \"TC\"]\nall_device_cmds = set()\nfor cmds in by_level.values():\n all_device_cmds.update(cmds)\n\nprint()\nprint(\"Commands we use vs device support:\")\nfor cmd in sorted(our_commands):\n status = \"supported\" if cmd in all_device_cmds else \"NOT SUPPORTED\"\n print(f\" {cmd}: {status}\")", + "execution_count": 4, "metadata": {}, - "execution_count": null, - "outputs": [] + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2026-03-30 11:42:27,143 - pylabrobot - IO - [MT Scale] Sent command: I0\n", + "2026-03-30 11:42:27,152 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I0\\r\\n'\n", + "2026-03-30 11:42:27,189 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I0\"\\r\\n'\n", + "2026-03-30 11:42:27,192 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I0\"\\r\\n'\n", + "2026-03-30 11:42:27,203 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I1\"\\r\\n'\n", + "2026-03-30 11:42:27,207 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I1\"\\r\\n'\n", + "2026-03-30 11:42:27,211 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I2\"\\r\\n'\n", + "2026-03-30 11:42:27,212 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I2\"\\r\\n'\n", + "2026-03-30 11:42:27,219 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I3\"\\r\\n'\n", + "2026-03-30 11:42:27,220 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I3\"\\r\\n'\n", + "2026-03-30 11:42:27,235 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I4\"\\r\\n'\n", + "2026-03-30 11:42:27,237 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I4\"\\r\\n'\n", + "2026-03-30 11:42:27,251 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I5\"\\r\\n'\n", + "2026-03-30 11:42:27,253 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I5\"\\r\\n'\n", + "2026-03-30 11:42:27,267 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"S\"\\r\\n'\n", + "2026-03-30 11:42:27,268 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"S\"\\r\\n'\n", + "2026-03-30 11:42:27,283 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"SI\"\\r\\n'\n", + "2026-03-30 11:42:27,284 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"SI\"\\r\\n'\n", + "2026-03-30 11:42:27,299 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"SIR\"\\r\\n'\n", + "2026-03-30 11:42:27,300 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"SIR\"\\r\\n'\n", + "2026-03-30 11:42:27,301 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"Z\"\\r\\n'\n", + "2026-03-30 11:42:27,302 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"Z\"\\r\\n'\n", + "2026-03-30 11:42:27,314 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"ZI\"\\r\\n'\n", + "2026-03-30 11:42:27,316 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"ZI\"\\r\\n'\n", + "2026-03-30 11:42:27,331 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"@\"\\r\\n'\n", + "2026-03-30 11:42:27,332 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"@\"\\r\\n'\n", + "2026-03-30 11:42:27,350 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"SR\"\\r\\n'\n", + "2026-03-30 11:42:27,352 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"SR\"\\r\\n'\n", + "2026-03-30 11:42:27,363 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"T\"\\r\\n'\n", + "2026-03-30 11:42:27,364 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"T\"\\r\\n'\n", + "2026-03-30 11:42:27,365 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"TA\"\\r\\n'\n", + "2026-03-30 11:42:27,368 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"TA\"\\r\\n'\n", + "2026-03-30 11:42:27,380 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"TAC\"\\r\\n'\n", + "2026-03-30 11:42:27,384 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"TAC\"\\r\\n'\n", + "2026-03-30 11:42:27,395 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"TI\"\\r\\n'\n", + "2026-03-30 11:42:27,396 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"TI\"\\r\\n'\n", + "2026-03-30 11:42:27,410 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C0\"\\r\\n'\n", + "2026-03-30 11:42:27,412 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"C0\"\\r\\n'\n", + "2026-03-30 11:42:27,428 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C1\"\\r\\n'\n", + "2026-03-30 11:42:27,429 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"C1\"\\r\\n'\n", + "2026-03-30 11:42:27,443 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C2\"\\r\\n'\n", + "2026-03-30 11:42:27,447 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"C2\"\\r\\n'\n", + "2026-03-30 11:42:27,459 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C3\"\\r\\n'\n", + "2026-03-30 11:42:27,461 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"C3\"\\r\\n'\n", + "2026-03-30 11:42:27,474 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"COM\"\\r\\n'\n", + "2026-03-30 11:42:27,476 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"COM\"\\r\\n'\n", + "2026-03-30 11:42:27,481 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"DAT\"\\r\\n'\n", + "2026-03-30 11:42:27,482 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"DAT\"\\r\\n'\n", + "2026-03-30 11:42:27,491 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I10\"\\r\\n'\n", + "2026-03-30 11:42:27,492 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I10\"\\r\\n'\n", + "2026-03-30 11:42:27,506 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I11\"\\r\\n'\n", + "2026-03-30 11:42:27,507 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I11\"\\r\\n'\n", + "2026-03-30 11:42:27,523 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I14\"\\r\\n'\n", + "2026-03-30 11:42:27,523 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I14\"\\r\\n'\n", + "2026-03-30 11:42:27,538 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I15\"\\r\\n'\n", + "2026-03-30 11:42:27,539 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I15\"\\r\\n'\n", + "2026-03-30 11:42:27,554 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I16\"\\r\\n'\n", + "2026-03-30 11:42:27,555 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I16\"\\r\\n'\n", + "2026-03-30 11:42:27,571 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I21\"\\r\\n'\n", + "2026-03-30 11:42:27,571 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I21\"\\r\\n'\n", + "2026-03-30 11:42:27,586 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I22\"\\r\\n'\n", + "2026-03-30 11:42:27,587 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I22\"\\r\\n'\n", + "2026-03-30 11:42:27,602 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I23\"\\r\\n'\n", + "2026-03-30 11:42:27,603 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I23\"\\r\\n'\n", + "2026-03-30 11:42:27,618 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I24\"\\r\\n'\n", + "2026-03-30 11:42:27,619 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I24\"\\r\\n'\n", + "2026-03-30 11:42:27,634 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I25\"\\r\\n'\n", + "2026-03-30 11:42:27,634 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I25\"\\r\\n'\n", + "2026-03-30 11:42:27,650 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I26\"\\r\\n'\n", + "2026-03-30 11:42:27,651 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I26\"\\r\\n'\n", + "2026-03-30 11:42:27,652 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M01\"\\r\\n'\n", + "2026-03-30 11:42:27,652 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M01\"\\r\\n'\n", + "2026-03-30 11:42:27,666 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M02\"\\r\\n'\n", + "2026-03-30 11:42:27,667 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M02\"\\r\\n'\n", + "2026-03-30 11:42:27,682 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M03\"\\r\\n'\n", + "2026-03-30 11:42:27,683 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M03\"\\r\\n'\n", + "2026-03-30 11:42:27,698 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M17\"\\r\\n'\n", + "2026-03-30 11:42:27,699 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M17\"\\r\\n'\n", + "2026-03-30 11:42:27,714 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M18\"\\r\\n'\n", + "2026-03-30 11:42:27,715 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M18\"\\r\\n'\n", + "2026-03-30 11:42:27,730 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M19\"\\r\\n'\n", + "2026-03-30 11:42:27,730 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M19\"\\r\\n'\n", + "2026-03-30 11:42:27,746 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M20\"\\r\\n'\n", + "2026-03-30 11:42:27,747 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M20\"\\r\\n'\n", + "2026-03-30 11:42:27,762 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M21\"\\r\\n'\n", + "2026-03-30 11:42:27,763 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M21\"\\r\\n'\n", + "2026-03-30 11:42:27,778 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M27\"\\r\\n'\n", + "2026-03-30 11:42:27,778 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M27\"\\r\\n'\n", + "2026-03-30 11:42:27,794 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M28\"\\r\\n'\n", + "2026-03-30 11:42:27,795 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M28\"\\r\\n'\n", + "2026-03-30 11:42:27,810 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M29\"\\r\\n'\n", + "2026-03-30 11:42:27,812 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M29\"\\r\\n'\n", + "2026-03-30 11:42:27,813 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M31\"\\r\\n'\n", + "2026-03-30 11:42:27,813 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M31\"\\r\\n'\n", + "2026-03-30 11:42:27,826 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M32\"\\r\\n'\n", + "2026-03-30 11:42:27,827 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M32\"\\r\\n'\n", + "2026-03-30 11:42:27,843 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M33\"\\r\\n'\n", + "2026-03-30 11:42:27,844 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M33\"\\r\\n'\n", + "2026-03-30 11:42:27,857 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M35\"\\r\\n'\n", + "2026-03-30 11:42:27,858 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M35\"\\r\\n'\n", + "2026-03-30 11:42:27,874 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"SIS\"\\r\\n'\n", + "2026-03-30 11:42:27,875 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"SIS\"\\r\\n'\n", + "2026-03-30 11:42:27,890 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"SNR\"\\r\\n'\n", + "2026-03-30 11:42:27,891 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"SNR\"\\r\\n'\n", + "2026-03-30 11:42:27,906 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TIM\"\\r\\n'\n", + "2026-03-30 11:42:27,908 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TIM\"\\r\\n'\n", + "2026-03-30 11:42:27,922 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST0\"\\r\\n'\n", + "2026-03-30 11:42:27,923 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TST0\"\\r\\n'\n", + "2026-03-30 11:42:27,938 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST1\"\\r\\n'\n", + "2026-03-30 11:42:27,939 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TST1\"\\r\\n'\n", + "2026-03-30 11:42:27,953 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST2\"\\r\\n'\n", + "2026-03-30 11:42:27,954 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TST2\"\\r\\n'\n", + "2026-03-30 11:42:27,970 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST3\"\\r\\n'\n", + "2026-03-30 11:42:27,971 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TST3\"\\r\\n'\n", + "2026-03-30 11:42:27,985 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"UPD\"\\r\\n'\n", + "2026-03-30 11:42:27,986 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"UPD\"\\r\\n'\n", + "2026-03-30 11:42:28,002 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"FCUT\"\\r\\n'\n", + "2026-03-30 11:42:28,002 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 3 \"FCUT\"\\r\\n'\n", + "2026-03-30 11:42:28,018 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"FSET\"\\r\\n'\n", + "2026-03-30 11:42:28,020 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 3 \"FSET\"\\r\\n'\n", + "2026-03-30 11:42:28,033 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"LST\"\\r\\n'\n", + "2026-03-30 11:42:28,034 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 3 \"LST\"\\r\\n'\n", + "2026-03-30 11:42:28,050 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"RDB\"\\r\\n'\n", + "2026-03-30 11:42:28,052 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 3 \"RDB\"\\r\\n'\n", + "2026-03-30 11:42:28,066 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 A 3 \"USTB\"\\r\\n'\n", + "2026-03-30 11:42:28,067 - pylabrobot - IO - [MT Scale] Received response: b'I0 A 3 \"USTB\"\\r\\n'\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Total commands implemented: 62\n", + "\n", + "Level 0 (12 commands): @, I0, I1, I2, I3, I4, I5, S, SI, SIR, Z, ZI\n", + "Level 1 (5 commands): SR, T, TA, TAC, TI\n", + "Level 2 (40 commands): C0, C1, C2, C3, COM, DAT, I10, I11, I14, I15, I16, I21, I22, I23, I24, I25, I26, M01, M02, M03, M17, M18, M19, M20, M21, M27, M28, M29, M31, M32, M33, M35, SIS, SNR, TIM, TST0, TST1, TST2, TST3, UPD\n", + "Level 3 (5 commands): FCUT, FSET, LST, RDB, USTB\n", + "\n", + "Commands we use vs device support:\n", + " @: supported\n", + " C: NOT SUPPORTED\n", + " D: NOT SUPPORTED\n", + " DW: NOT SUPPORTED\n", + " I0: supported\n", + " I1: supported\n", + " I2: supported\n", + " I4: supported\n", + " I50: NOT SUPPORTED\n", + " M21: supported\n", + " M28: supported\n", + " S: supported\n", + " SC: NOT SUPPORTED\n", + " SI: supported\n", + " T: supported\n", + " TA: supported\n", + " TAC: supported\n", + " TC: NOT SUPPORTED\n", + " TI: supported\n", + " Z: supported\n", + " ZC: NOT SUPPORTED\n", + " ZI: supported\n" + ] + } + ], + "source": [ + "from collections import defaultdict\n", + "\n", + "# I0 is a multi-response command (B status for each command, A for the last)\n", + "responses = await backend.send_command(\"I0\")\n", + "\n", + "print(f\"Total commands implemented: {len(responses)}\")\n", + "print()\n", + "\n", + "# Group by level\n", + "by_level = defaultdict(list)\n", + "for resp in responses:\n", + " # Format: I0 B/A <\"command\">\n", + " if len(resp.data) >= 2:\n", + " level = resp.data[0]\n", + " cmd_name = resp.data[1]\n", + " by_level[level].append(cmd_name)\n", + "\n", + "for level in sorted(by_level.keys()):\n", + " cmds = sorted(by_level[level])\n", + " print(f\"Level {level} ({len(cmds)} commands): {', '.join(cmds)}\")\n", + "\n", + "# Check which commands we use that might not be supported\n", + "our_commands = [\"@\", \"C\", \"D\", \"DW\", \"I0\", \"I1\", \"I2\", \"I4\", \"I50\",\n", + " \"M21\", \"M28\", \"S\", \"SC\", \"SI\", \"T\", \"TA\", \"TAC\",\n", + " \"TI\", \"Z\", \"ZC\", \"ZI\", \"TC\"]\n", + "all_device_cmds = set()\n", + "for cmds in by_level.values():\n", + " all_device_cmds.update(cmds)\n", + "\n", + "print()\n", + "print(\"Commands we use vs device support:\")\n", + "for cmd in sorted(our_commands):\n", + " status = \"supported\" if cmd in all_device_cmds else \"NOT SUPPORTED\"\n", + " print(f\" {cmd}: {status}\")" + ] }, { "cell_type": "markdown", @@ -172,11 +381,11 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 11:29:22,637 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] reset_input_buffer\n", - "2026-03-30 11:29:22,638 - pylabrobot - IO - [MT Scale] Sent command: @\n", - "2026-03-30 11:29:22,639 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'@\\r\\n'\n", - "2026-03-30 11:29:22,693 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I4 A \"B207696838\"\\r\\n'\n", - "2026-03-30 11:29:22,694 - pylabrobot - IO - [MT Scale] Received response: b'I4 A \"B207696838\"\\r\\n'\n" + "2026-03-30 11:42:28,079 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] reset_input_buffer\n", + "2026-03-30 11:42:28,080 - pylabrobot - IO - [MT Scale] Sent command: @\n", + "2026-03-30 11:42:28,083 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'@\\r\\n'\n", + "2026-03-30 11:42:28,130 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I4 A \"B207696838\"\\r\\n'\n", + "2026-03-30 11:42:28,131 - pylabrobot - IO - [MT Scale] Received response: b'I4 A \"B207696838\"\\r\\n'\n" ] }, { @@ -211,10 +420,10 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 11:29:29,649 - pylabrobot - IO - [MT Scale] Sent command: I4\n", - "2026-03-30 11:29:29,651 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I4\\r\\n'\n", - "2026-03-30 11:29:29,694 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I4 A \"B207696838\"\\r\\n'\n", - "2026-03-30 11:29:29,696 - pylabrobot - IO - [MT Scale] Received response: b'I4 A \"B207696838\"\\r\\n'\n" + "2026-03-30 11:42:28,143 - pylabrobot - IO - [MT Scale] Sent command: I4\n", + "2026-03-30 11:42:28,147 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I4\\r\\n'\n", + "2026-03-30 11:42:28,180 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I4 A \"B207696838\"\\r\\n'\n", + "2026-03-30 11:42:28,183 - pylabrobot - IO - [MT Scale] Received response: b'I4 A \"B207696838\"\\r\\n'\n" ] }, { @@ -249,14 +458,14 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 11:29:32,001 - pylabrobot - IO - [MT Scale] Sent command: I2\n", - "2026-03-30 11:29:32,005 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I2\\r\\n'\n", - "2026-03-30 11:29:32,061 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", - "2026-03-30 11:29:32,062 - pylabrobot - IO - [MT Scale] Received response: b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", - "2026-03-30 11:29:32,064 - pylabrobot - IO - [MT Scale] Sent command: I2\n", - "2026-03-30 11:29:32,065 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I2\\r\\n'\n", - "2026-03-30 11:29:32,124 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", - "2026-03-30 11:29:32,125 - pylabrobot - IO - [MT Scale] Received response: b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n" + "2026-03-30 11:42:28,190 - pylabrobot - IO - [MT Scale] Sent command: I2\n", + "2026-03-30 11:42:28,195 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I2\\r\\n'\n", + "2026-03-30 11:42:28,257 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", + "2026-03-30 11:42:28,257 - pylabrobot - IO - [MT Scale] Received response: b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", + "2026-03-30 11:42:28,258 - pylabrobot - IO - [MT Scale] Sent command: I2\n", + "2026-03-30 11:42:28,260 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I2\\r\\n'\n", + "2026-03-30 11:42:28,321 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", + "2026-03-30 11:42:28,322 - pylabrobot - IO - [MT Scale] Received response: b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n" ] }, { @@ -295,10 +504,10 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 11:29:34,955 - pylabrobot - IO - [MT Scale] Sent command: I1\n", - "2026-03-30 11:29:34,959 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I1\\r\\n'\n", - "2026-03-30 11:29:35,002 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I1 A \"01\" \"2.30\" \"2.22\" \"\" \"\"\\r\\n'\n", - "2026-03-30 11:29:35,004 - pylabrobot - IO - [MT Scale] Received response: b'I1 A \"01\" \"2.30\" \"2.22\" \"\" \"\"\\r\\n'\n" + "2026-03-30 11:42:28,329 - pylabrobot - IO - [MT Scale] Sent command: I1\n", + "2026-03-30 11:42:28,332 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I1\\r\\n'\n", + "2026-03-30 11:42:28,386 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I1 A \"01\" \"2.30\" \"2.22\" \"\" \"\"\\r\\n'\n", + "2026-03-30 11:42:28,386 - pylabrobot - IO - [MT Scale] Received response: b'I1 A \"01\" \"2.30\" \"2.22\" \"\" \"\"\\r\\n'\n" ] }, { @@ -334,17 +543,17 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 11:29:40,982 - pylabrobot - IO - [MT Scale] Sent command: S\n", - "2026-03-30 11:29:40,987 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", - "2026-03-30 11:29:41,078 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S -0.00102 g\\r\\n'\n", - "2026-03-30 11:29:41,079 - pylabrobot - IO - [MT Scale] Received response: b'S S -0.00102 g\\r\\n'\n" + "2026-03-30 11:42:28,394 - pylabrobot - IO - [MT Scale] Sent command: S\n", + "2026-03-30 11:42:28,399 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", + "2026-03-30 11:42:28,627 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S -0.00009 g\\r\\n'\n", + "2026-03-30 11:42:28,628 - pylabrobot - IO - [MT Scale] Received response: b'S S -0.00009 g\\r\\n'\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ - "Stable weight (empty pan): -0.00102 g\n", + "Stable weight (empty pan): -9e-05 g\n", "PASS: stable weight returns float\n" ] } @@ -372,17 +581,17 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 11:29:44,419 - pylabrobot - IO - [MT Scale] Sent command: SI\n", - "2026-03-30 11:29:44,422 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", - "2026-03-30 11:29:44,466 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S -0.00102 g\\r\\n'\n", - "2026-03-30 11:29:44,469 - pylabrobot - IO - [MT Scale] Received response: b'S S -0.00102 g\\r\\n'\n" + "2026-03-30 11:42:28,636 - pylabrobot - IO - [MT Scale] Sent command: SI\n", + "2026-03-30 11:42:28,643 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", + "2026-03-30 11:42:28,674 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S -0.00009 g\\r\\n'\n", + "2026-03-30 11:42:28,680 - pylabrobot - IO - [MT Scale] Received response: b'S S -0.00009 g\\r\\n'\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ - "Immediate weight: -0.00102 g\n", + "Immediate weight: -9e-05 g\n", "PASS: immediate weight returns float\n" ] } @@ -410,14 +619,14 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 11:29:47,415 - pylabrobot - IO - [MT Scale] Sent command: Z\n", - "2026-03-30 11:29:47,419 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'Z\\r\\n'\n", - "2026-03-30 11:29:47,647 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'Z A\\r\\n'\n", - "2026-03-30 11:29:47,648 - pylabrobot - IO - [MT Scale] Received response: b'Z A\\r\\n'\n", - "2026-03-30 11:29:47,648 - pylabrobot - IO - [MT Scale] Sent command: SI\n", - "2026-03-30 11:29:47,650 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", - "2026-03-30 11:29:47,680 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 11:29:47,682 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n" + "2026-03-30 11:42:28,694 - pylabrobot - IO - [MT Scale] Sent command: Z\n", + "2026-03-30 11:42:28,697 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'Z\\r\\n'\n", + "2026-03-30 11:42:29,009 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'Z A\\r\\n'\n", + "2026-03-30 11:42:29,010 - pylabrobot - IO - [MT Scale] Received response: b'Z A\\r\\n'\n", + "2026-03-30 11:42:29,011 - pylabrobot - IO - [MT Scale] Sent command: SI\n", + "2026-03-30 11:42:29,012 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", + "2026-03-30 11:42:29,041 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 11:42:29,042 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n" ] }, { @@ -453,14 +662,14 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 11:29:51,308 - pylabrobot - IO - [MT Scale] Sent command: ZI\n", - "2026-03-30 11:29:51,312 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'ZI\\r\\n'\n", - "2026-03-30 11:29:51,341 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'ZI S\\r\\n'\n", - "2026-03-30 11:29:51,341 - pylabrobot - IO - [MT Scale] Received response: b'ZI S\\r\\n'\n", - "2026-03-30 11:29:51,342 - pylabrobot - IO - [MT Scale] Sent command: SI\n", - "2026-03-30 11:29:51,344 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", - "2026-03-30 11:29:51,373 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 11:29:51,374 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n" + "2026-03-30 11:42:29,048 - pylabrobot - IO - [MT Scale] Sent command: ZI\n", + "2026-03-30 11:42:29,051 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'ZI\\r\\n'\n", + "2026-03-30 11:42:29,073 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'ZI S\\r\\n'\n", + "2026-03-30 11:42:29,074 - pylabrobot - IO - [MT Scale] Received response: b'ZI S\\r\\n'\n", + "2026-03-30 11:42:29,075 - pylabrobot - IO - [MT Scale] Sent command: SI\n", + "2026-03-30 11:42:29,077 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", + "2026-03-30 11:42:29,106 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 11:42:29,106 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n" ] }, { @@ -513,18 +722,18 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 11:30:01,504 - pylabrobot - IO - [MT Scale] Sent command: Z\n", - "2026-03-30 11:30:01,506 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'Z\\r\\n'\n", - "2026-03-30 11:30:01,796 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'Z A\\r\\n'\n", - "2026-03-30 11:30:01,797 - pylabrobot - IO - [MT Scale] Received response: b'Z A\\r\\n'\n", - "2026-03-30 11:30:01,799 - pylabrobot - IO - [MT Scale] Sent command: T\n", - "2026-03-30 11:30:01,801 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'T\\r\\n'\n", - "2026-03-30 11:30:02,211 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'T S 0.00000 g\\r\\n'\n", - "2026-03-30 11:30:02,212 - pylabrobot - IO - [MT Scale] Received response: b'T S 0.00000 g\\r\\n'\n", - "2026-03-30 11:30:02,213 - pylabrobot - IO - [MT Scale] Sent command: TA\n", - "2026-03-30 11:30:02,214 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'TA\\r\\n'\n", - "2026-03-30 11:30:02,307 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'TA A 0.00000 g\\r\\n'\n", - "2026-03-30 11:30:02,308 - pylabrobot - IO - [MT Scale] Received response: b'TA A 0.00000 g\\r\\n'\n" + "2026-03-30 11:43:16,169 - pylabrobot - IO - [MT Scale] Sent command: Z\n", + "2026-03-30 11:43:16,174 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'Z\\r\\n'\n", + "2026-03-30 11:43:16,584 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'Z A\\r\\n'\n", + "2026-03-30 11:43:16,585 - pylabrobot - IO - [MT Scale] Received response: b'Z A\\r\\n'\n", + "2026-03-30 11:43:16,586 - pylabrobot - IO - [MT Scale] Sent command: T\n", + "2026-03-30 11:43:16,587 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'T\\r\\n'\n", + "2026-03-30 11:43:17,000 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'T S 0.00000 g\\r\\n'\n", + "2026-03-30 11:43:17,001 - pylabrobot - IO - [MT Scale] Received response: b'T S 0.00000 g\\r\\n'\n", + "2026-03-30 11:43:17,001 - pylabrobot - IO - [MT Scale] Sent command: TA\n", + "2026-03-30 11:43:17,002 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'TA\\r\\n'\n", + "2026-03-30 11:43:17,098 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'TA A 0.00000 g\\r\\n'\n", + "2026-03-30 11:43:17,105 - pylabrobot - IO - [MT Scale] Received response: b'TA A 0.00000 g\\r\\n'\n" ] }, { @@ -572,10 +781,10 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 11:30:08,454 - pylabrobot - IO - [MT Scale] Sent command: TA\n", - "2026-03-30 11:30:08,463 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'TA\\r\\n'\n", - "2026-03-30 11:30:08,511 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'TA A 0.00000 g\\r\\n'\n", - "2026-03-30 11:30:08,517 - pylabrobot - IO - [MT Scale] Received response: b'TA A 0.00000 g\\r\\n'\n" + "2026-03-30 11:43:21,054 - pylabrobot - IO - [MT Scale] Sent command: TA\n", + "2026-03-30 11:43:21,059 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'TA\\r\\n'\n", + "2026-03-30 11:43:21,126 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'TA A 0.00000 g\\r\\n'\n", + "2026-03-30 11:43:21,127 - pylabrobot - IO - [MT Scale] Received response: b'TA A 0.00000 g\\r\\n'\n" ] }, { @@ -610,14 +819,14 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 11:30:10,949 - pylabrobot - IO - [MT Scale] Sent command: TAC\n", - "2026-03-30 11:30:10,950 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'TAC\\r\\n'\n", - "2026-03-30 11:30:10,972 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'TAC A\\r\\n'\n", - "2026-03-30 11:30:10,973 - pylabrobot - IO - [MT Scale] Received response: b'TAC A\\r\\n'\n", - "2026-03-30 11:30:10,973 - pylabrobot - IO - [MT Scale] Sent command: TA\n", - "2026-03-30 11:30:10,975 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'TA\\r\\n'\n", - "2026-03-30 11:30:11,054 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'TA A 0.00000 g\\r\\n'\n", - "2026-03-30 11:30:11,056 - pylabrobot - IO - [MT Scale] Received response: b'TA A 0.00000 g\\r\\n'\n" + "2026-03-30 11:43:22,224 - pylabrobot - IO - [MT Scale] Sent command: TAC\n", + "2026-03-30 11:43:22,227 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'TAC\\r\\n'\n", + "2026-03-30 11:43:22,259 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'TAC A\\r\\n'\n", + "2026-03-30 11:43:22,262 - pylabrobot - IO - [MT Scale] Received response: b'TAC A\\r\\n'\n", + "2026-03-30 11:43:22,265 - pylabrobot - IO - [MT Scale] Sent command: TA\n", + "2026-03-30 11:43:22,267 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'TA\\r\\n'\n", + "2026-03-30 11:43:22,403 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'TA A 0.00000 g\\r\\n'\n", + "2026-03-30 11:43:22,404 - pylabrobot - IO - [MT Scale] Received response: b'TA A 0.00000 g\\r\\n'\n" ] }, { @@ -653,10 +862,10 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 11:30:12,434 - pylabrobot - IO - [MT Scale] Sent command: SC 3000\n", - "2026-03-30 11:30:12,438 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SC 3000\\r\\n'\n", - "2026-03-30 11:30:12,459 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'ES\\r\\n'\n", - "2026-03-30 11:30:12,461 - pylabrobot - IO - [MT Scale] Received response: b'ES\\r\\n'\n" + "2026-03-30 11:43:23,301 - pylabrobot - IO - [MT Scale] Sent command: SC 3000\n", + "2026-03-30 11:43:23,305 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SC 3000\\r\\n'\n", + "2026-03-30 11:43:23,329 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'ES\\r\\n'\n", + "2026-03-30 11:43:23,330 - pylabrobot - IO - [MT Scale] Received response: b'ES\\r\\n'\n" ] }, { @@ -697,10 +906,10 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 11:30:22,642 - pylabrobot - IO - [MT Scale] Sent command: C\n", - "2026-03-30 11:30:22,646 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'C\\r\\n'\n", - "2026-03-30 11:30:22,659 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'ES\\r\\n'\n", - "2026-03-30 11:30:22,660 - pylabrobot - IO - [MT Scale] Received response: b'ES\\r\\n'\n" + "2026-03-30 11:43:25,106 - pylabrobot - IO - [MT Scale] Sent command: C\n", + "2026-03-30 11:43:25,109 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'C\\r\\n'\n", + "2026-03-30 11:43:25,136 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'ES\\r\\n'\n", + "2026-03-30 11:43:25,138 - pylabrobot - IO - [MT Scale] Received response: b'ES\\r\\n'\n" ] }, { @@ -739,10 +948,10 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 11:30:25,587 - pylabrobot - IO - [MT Scale] Sent command: D \"PLR TEST\"\n", - "2026-03-30 11:30:25,590 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'D \"PLR TEST\"\\r\\n'\n", - "2026-03-30 11:30:25,617 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'ES\\r\\n'\n", - "2026-03-30 11:30:25,618 - pylabrobot - IO - [MT Scale] Received response: b'ES\\r\\n'\n" + "2026-03-30 11:43:26,590 - pylabrobot - IO - [MT Scale] Sent command: D \"PLR TEST\"\n", + "2026-03-30 11:43:26,594 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'D \"PLR TEST\"\\r\\n'\n", + "2026-03-30 11:43:26,622 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'ES\\r\\n'\n", + "2026-03-30 11:43:26,624 - pylabrobot - IO - [MT Scale] Received response: b'ES\\r\\n'\n" ] }, { @@ -787,14 +996,14 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 11:30:28,230 - pylabrobot - IO - [MT Scale] Sent command: ZC 5000\n", - "2026-03-30 11:30:28,233 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'ZC 5000\\r\\n'\n", - "2026-03-30 11:30:28,270 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'ES\\r\\n'\n", - "2026-03-30 11:30:28,271 - pylabrobot - IO - [MT Scale] Received response: b'ES\\r\\n'\n", - "2026-03-30 11:30:28,275 - pylabrobot - IO - [MT Scale] Sent command: TC 5000\n", - "2026-03-30 11:30:28,279 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'TC 5000\\r\\n'\n", - "2026-03-30 11:30:28,302 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'ES\\r\\n'\n", - "2026-03-30 11:30:28,306 - pylabrobot - IO - [MT Scale] Received response: b'ES\\r\\n'\n" + "2026-03-30 11:43:27,897 - pylabrobot - IO - [MT Scale] Sent command: ZC 5000\n", + "2026-03-30 11:43:27,901 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'ZC 5000\\r\\n'\n", + "2026-03-30 11:43:27,933 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'ES\\r\\n'\n", + "2026-03-30 11:43:27,934 - pylabrobot - IO - [MT Scale] Received response: b'ES\\r\\n'\n", + "2026-03-30 11:43:27,935 - pylabrobot - IO - [MT Scale] Sent command: TC 5000\n", + "2026-03-30 11:43:27,939 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'TC 5000\\r\\n'\n", + "2026-03-30 11:43:27,965 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'ES\\r\\n'\n", + "2026-03-30 11:43:27,966 - pylabrobot - IO - [MT Scale] Received response: b'ES\\r\\n'\n" ] }, { @@ -936,14 +1145,14 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 11:30:52,063 - pylabrobot - IO - [MT Scale] Sent command: Z\n", - "2026-03-30 11:30:52,066 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'Z\\r\\n'\n", - "2026-03-30 11:30:52,331 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'Z A\\r\\n'\n", - "2026-03-30 11:30:52,332 - pylabrobot - IO - [MT Scale] Received response: b'Z A\\r\\n'\n", - "2026-03-30 11:30:52,333 - pylabrobot - IO - [MT Scale] Sent command: SI\n", - "2026-03-30 11:30:52,335 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", - "2026-03-30 11:30:52,364 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 11:30:52,367 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n" + "2026-03-30 11:43:32,567 - pylabrobot - IO - [MT Scale] Sent command: Z\n", + "2026-03-30 11:43:32,569 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'Z\\r\\n'\n", + "2026-03-30 11:43:32,905 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'Z A\\r\\n'\n", + "2026-03-30 11:43:32,906 - pylabrobot - IO - [MT Scale] Received response: b'Z A\\r\\n'\n", + "2026-03-30 11:43:32,908 - pylabrobot - IO - [MT Scale] Sent command: SI\n", + "2026-03-30 11:43:32,909 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", + "2026-03-30 11:43:32,952 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 11:43:32,954 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n" ] }, { @@ -964,14 +1173,14 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 11:30:54,533 - pylabrobot - IO - [MT Scale] Sent command: T\n", - "2026-03-30 11:30:54,534 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'T\\r\\n'\n", - "2026-03-30 11:30:54,904 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'T S 0.00000 g\\r\\n'\n", - "2026-03-30 11:30:54,905 - pylabrobot - IO - [MT Scale] Received response: b'T S 0.00000 g\\r\\n'\n", - "2026-03-30 11:30:54,906 - pylabrobot - IO - [MT Scale] Sent command: TA\n", - "2026-03-30 11:30:54,907 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'TA\\r\\n'\n", - "2026-03-30 11:30:55,000 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'TA A 0.00000 g\\r\\n'\n", - "2026-03-30 11:30:55,001 - pylabrobot - IO - [MT Scale] Received response: b'TA A 0.00000 g\\r\\n'\n" + "2026-03-30 11:43:33,030 - pylabrobot - IO - [MT Scale] Sent command: T\n", + "2026-03-30 11:43:33,033 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'T\\r\\n'\n", + "2026-03-30 11:43:33,321 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'T S 0.00000 g\\r\\n'\n", + "2026-03-30 11:43:33,321 - pylabrobot - IO - [MT Scale] Received response: b'T S 0.00000 g\\r\\n'\n", + "2026-03-30 11:43:33,324 - pylabrobot - IO - [MT Scale] Sent command: TA\n", + "2026-03-30 11:43:33,326 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'TA\\r\\n'\n", + "2026-03-30 11:43:33,400 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'TA A 0.00000 g\\r\\n'\n", + "2026-03-30 11:43:33,401 - pylabrobot - IO - [MT Scale] Received response: b'TA A 0.00000 g\\r\\n'\n" ] }, { @@ -1032,94 +1241,94 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 11:31:00,849 - pylabrobot - IO - [MT Scale] Sent command: S\n", - "2026-03-30 11:31:00,850 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", - "2026-03-30 11:31:00,884 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 11:31:00,886 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 11:31:00,888 - pylabrobot - IO - [MT Scale] Sent command: S\n", - "2026-03-30 11:31:00,890 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", - "2026-03-30 11:31:00,980 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 11:31:00,980 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 11:31:00,981 - pylabrobot - IO - [MT Scale] Sent command: S\n", - "2026-03-30 11:31:00,985 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", - "2026-03-30 11:31:01,092 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 11:31:01,093 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 11:31:01,093 - pylabrobot - IO - [MT Scale] Sent command: S\n", - "2026-03-30 11:31:01,096 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", - "2026-03-30 11:31:01,188 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 11:31:01,188 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 11:31:01,191 - pylabrobot - IO - [MT Scale] Sent command: S\n", - "2026-03-30 11:31:01,192 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", - "2026-03-30 11:31:01,284 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 11:31:01,285 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 11:31:01,287 - pylabrobot - IO - [MT Scale] Sent command: S\n", - "2026-03-30 11:31:01,288 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", - "2026-03-30 11:31:01,380 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 11:31:01,381 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 11:31:01,381 - pylabrobot - IO - [MT Scale] Sent command: S\n", - "2026-03-30 11:31:01,383 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", - "2026-03-30 11:31:01,475 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 11:31:01,476 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 11:31:01,477 - pylabrobot - IO - [MT Scale] Sent command: S\n", - "2026-03-30 11:31:01,478 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", - "2026-03-30 11:31:01,572 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 11:31:01,573 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 11:31:01,574 - pylabrobot - IO - [MT Scale] Sent command: S\n", - "2026-03-30 11:31:01,575 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", - "2026-03-30 11:31:01,667 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 11:31:01,668 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 11:31:01,668 - pylabrobot - IO - [MT Scale] Sent command: S\n", - "2026-03-30 11:31:01,669 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", - "2026-03-30 11:31:01,780 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 11:31:01,780 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 11:31:01,781 - pylabrobot - IO - [MT Scale] Sent command: SI\n", - "2026-03-30 11:31:01,782 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", - "2026-03-30 11:31:01,812 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 11:31:01,813 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 11:31:01,815 - pylabrobot - IO - [MT Scale] Sent command: SI\n", - "2026-03-30 11:31:01,817 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", - "2026-03-30 11:31:01,860 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 11:31:01,861 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 11:31:01,862 - pylabrobot - IO - [MT Scale] Sent command: SI\n", - "2026-03-30 11:31:01,865 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", - "2026-03-30 11:31:01,907 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 11:31:01,907 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 11:31:01,908 - pylabrobot - IO - [MT Scale] Sent command: SI\n", - "2026-03-30 11:31:01,913 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", - "2026-03-30 11:31:01,955 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 11:31:01,959 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 11:31:01,962 - pylabrobot - IO - [MT Scale] Sent command: SI\n", - "2026-03-30 11:31:01,966 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", - "2026-03-30 11:31:02,003 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 11:31:02,004 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 11:31:02,004 - pylabrobot - IO - [MT Scale] Sent command: SI\n", - "2026-03-30 11:31:02,006 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", - "2026-03-30 11:31:02,035 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 11:31:02,037 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 11:31:02,040 - pylabrobot - IO - [MT Scale] Sent command: SI\n", - "2026-03-30 11:31:02,043 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", - "2026-03-30 11:31:02,085 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 11:31:02,087 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 11:31:02,089 - pylabrobot - IO - [MT Scale] Sent command: SI\n", - "2026-03-30 11:31:02,094 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", - "2026-03-30 11:31:02,137 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 11:31:02,139 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 11:31:02,141 - pylabrobot - IO - [MT Scale] Sent command: SI\n", - "2026-03-30 11:31:02,149 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", - "2026-03-30 11:31:02,196 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 11:31:02,198 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 11:31:02,200 - pylabrobot - IO - [MT Scale] Sent command: SI\n", - "2026-03-30 11:31:02,204 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", - "2026-03-30 11:31:02,243 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 11:31:02,254 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n" + "2026-03-30 11:43:40,458 - pylabrobot - IO - [MT Scale] Sent command: S\n", + "2026-03-30 11:43:40,459 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", + "2026-03-30 11:43:40,577 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 11:43:40,578 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 11:43:40,579 - pylabrobot - IO - [MT Scale] Sent command: S\n", + "2026-03-30 11:43:40,583 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", + "2026-03-30 11:43:40,673 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 11:43:40,674 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 11:43:40,675 - pylabrobot - IO - [MT Scale] Sent command: S\n", + "2026-03-30 11:43:40,677 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", + "2026-03-30 11:43:40,769 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 11:43:40,770 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 11:43:40,771 - pylabrobot - IO - [MT Scale] Sent command: S\n", + "2026-03-30 11:43:40,772 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", + "2026-03-30 11:43:40,881 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 11:43:40,882 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 11:43:40,883 - pylabrobot - IO - [MT Scale] Sent command: S\n", + "2026-03-30 11:43:40,884 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", + "2026-03-30 11:43:40,977 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 11:43:40,978 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 11:43:40,979 - pylabrobot - IO - [MT Scale] Sent command: S\n", + "2026-03-30 11:43:40,980 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", + "2026-03-30 11:43:41,073 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 11:43:41,074 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 11:43:41,075 - pylabrobot - IO - [MT Scale] Sent command: S\n", + "2026-03-30 11:43:41,076 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", + "2026-03-30 11:43:41,169 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 11:43:41,170 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 11:43:41,170 - pylabrobot - IO - [MT Scale] Sent command: S\n", + "2026-03-30 11:43:41,171 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", + "2026-03-30 11:43:41,265 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 11:43:41,266 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 11:43:41,267 - pylabrobot - IO - [MT Scale] Sent command: S\n", + "2026-03-30 11:43:41,268 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", + "2026-03-30 11:43:41,361 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 11:43:41,362 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 11:43:41,363 - pylabrobot - IO - [MT Scale] Sent command: S\n", + "2026-03-30 11:43:41,364 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", + "2026-03-30 11:43:41,456 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 11:43:41,457 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 11:43:41,458 - pylabrobot - IO - [MT Scale] Sent command: SI\n", + "2026-03-30 11:43:41,460 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", + "2026-03-30 11:43:41,489 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 11:43:41,490 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 11:43:41,491 - pylabrobot - IO - [MT Scale] Sent command: SI\n", + "2026-03-30 11:43:41,494 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", + "2026-03-30 11:43:41,537 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 11:43:41,542 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 11:43:41,544 - pylabrobot - IO - [MT Scale] Sent command: SI\n", + "2026-03-30 11:43:41,548 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", + "2026-03-30 11:43:41,584 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 11:43:41,585 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 11:43:41,586 - pylabrobot - IO - [MT Scale] Sent command: SI\n", + "2026-03-30 11:43:41,588 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", + "2026-03-30 11:43:41,633 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 11:43:41,637 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 11:43:41,641 - pylabrobot - IO - [MT Scale] Sent command: SI\n", + "2026-03-30 11:43:41,644 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", + "2026-03-30 11:43:41,682 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 11:43:41,684 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 11:43:41,686 - pylabrobot - IO - [MT Scale] Sent command: SI\n", + "2026-03-30 11:43:41,690 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", + "2026-03-30 11:43:41,729 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 11:43:41,730 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 11:43:41,731 - pylabrobot - IO - [MT Scale] Sent command: SI\n", + "2026-03-30 11:43:41,736 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", + "2026-03-30 11:43:41,777 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 11:43:41,778 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 11:43:41,780 - pylabrobot - IO - [MT Scale] Sent command: SI\n", + "2026-03-30 11:43:41,782 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", + "2026-03-30 11:43:41,825 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 11:43:41,828 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 11:43:41,832 - pylabrobot - IO - [MT Scale] Sent command: SI\n", + "2026-03-30 11:43:41,834 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", + "2026-03-30 11:43:41,872 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 11:43:41,873 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 11:43:41,873 - pylabrobot - IO - [MT Scale] Sent command: SI\n", + "2026-03-30 11:43:41,877 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", + "2026-03-30 11:43:41,905 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 11:43:41,906 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ - "Stable read: 93.20 +/- 19.10 ms\n", - "Immediate read: 47.39 +/- 7.81 ms\n" + "Stable read: 100.00 +/- 8.72 ms\n", + "Immediate read: 44.89 +/- 7.16 ms\n" ] } ], @@ -1165,14 +1374,14 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 11:31:07,091 - pylabrobot - INFO - === Hardware validation ended ===\n" + "2026-03-30 11:43:46,384 - pylabrobot - INFO - === Hardware validation ended ===\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ - "Log file: ./logs/hardware_validation/2026-03-30_11-28-29_validation.log\n" + "Log file: ./logs/hardware_validation/2026-03-30_11-42-26_validation.log\n" ] } ], @@ -1211,4 +1420,4 @@ }, "nbformat": 4, "nbformat_minor": 4 -} \ No newline at end of file +} From edda0ef003a8eef2a577a738c3ec887ef17db8f0 Mon Sep 17 00:00:00 2001 From: Camillo Moschner Date: Mon, 30 Mar 2026 11:57:43 +0100 Subject: [PATCH 14/38] remove dependency on inaccurate level retrieval --- .../scales/mettler-toledo-WXS205SDU.ipynb | 144 ++++++++-------- pylabrobot/scales/mettler_toledo/backend.py | 83 ++++----- .../scales/mettler_toledo/backend_tests.py | 18 +- .../scales/mettler_toledo/chatterbox.py | 44 ++++- .../mettler_toledo/hardware_validation.ipynb | 159 +++++++----------- 5 files changed, 232 insertions(+), 216 deletions(-) diff --git a/docs/user_guide/02_analytical/scales/mettler-toledo-WXS205SDU.ipynb b/docs/user_guide/02_analytical/scales/mettler-toledo-WXS205SDU.ipynb index 9e5dda86565..c9f0476bb19 100644 --- a/docs/user_guide/02_analytical/scales/mettler-toledo-WXS205SDU.ipynb +++ b/docs/user_guide/02_analytical/scales/mettler-toledo-WXS205SDU.ipynb @@ -59,10 +59,10 @@ "execution_count": 1, "metadata": { "execution": { - "iopub.execute_input": "2026-03-29T20:12:31.193145Z", - "iopub.status.busy": "2026-03-29T20:12:31.192918Z", - "iopub.status.idle": "2026-03-29T20:12:31.196990Z", - "shell.execute_reply": "2026-03-29T20:12:31.196619Z" + "iopub.execute_input": "2026-03-30T10:54:11.646811Z", + "iopub.status.busy": "2026-03-30T10:54:11.646321Z", + "iopub.status.idle": "2026-03-30T10:54:11.651777Z", + "shell.execute_reply": "2026-03-30T10:54:11.651148Z" } }, "outputs": [], @@ -88,10 +88,10 @@ "execution_count": 2, "metadata": { "execution": { - "iopub.execute_input": "2026-03-29T20:12:31.199055Z", - "iopub.status.busy": "2026-03-29T20:12:31.198866Z", - "iopub.status.idle": "2026-03-29T20:12:31.246756Z", - "shell.execute_reply": "2026-03-29T20:12:31.246514Z" + "iopub.execute_input": "2026-03-30T10:54:11.654817Z", + "iopub.status.busy": "2026-03-30T10:54:11.654591Z", + "iopub.status.idle": "2026-03-30T10:54:11.709745Z", + "shell.execute_reply": "2026-03-30T10:54:11.709469Z" } }, "outputs": [ @@ -99,7 +99,7 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-29 21:12:31,245 - pylabrobot - INFO - === MT Scale tutorial started ===\n" + "2026-03-30 11:54:11,708 - pylabrobot - INFO - === MT Scale tutorial started ===\n" ] } ], @@ -124,10 +124,10 @@ "execution_count": 3, "metadata": { "execution": { - "iopub.execute_input": "2026-03-29T20:12:31.263340Z", - "iopub.status.busy": "2026-03-29T20:12:31.263227Z", - "iopub.status.idle": "2026-03-29T20:12:31.321905Z", - "shell.execute_reply": "2026-03-29T20:12:31.321698Z" + "iopub.execute_input": "2026-03-30T10:54:11.726612Z", + "iopub.status.busy": "2026-03-30T10:54:11.726495Z", + "iopub.status.idle": "2026-03-30T10:54:11.786787Z", + "shell.execute_reply": "2026-03-30T10:54:11.786614Z" } }, "outputs": [ @@ -135,11 +135,11 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-29 21:12:31,320 - pylabrobot - INFO - [MT Scale] Connected to Mettler Toledo scale (simulation)\n", + "2026-03-30 11:54:11,785 - pylabrobot - INFO - [MT Scale] Connected to Mettler Toledo scale (simulation)\n", "Device type: WXS205SDU\n", "Serial number: SIM0000001\n", "Capacity: 220.0 g\n", - "MT-SICS levels: [0, 1, 2, 3]\n" + "Supported commands: ['@', 'C', 'D', 'DW', 'I0', 'I1', 'I2', 'I4', 'I50', 'M21', 'M28', 'S', 'SC', 'SI', 'SIR', 'SR', 'T', 'TA', 'TAC', 'TC', 'TI', 'Z', 'ZC', 'ZI']\n" ] } ], @@ -207,10 +207,10 @@ "execution_count": 4, "metadata": { "execution": { - "iopub.execute_input": "2026-03-29T20:12:31.323067Z", - "iopub.status.busy": "2026-03-29T20:12:31.322981Z", - "iopub.status.idle": "2026-03-29T20:12:31.324940Z", - "shell.execute_reply": "2026-03-29T20:12:31.324759Z" + "iopub.execute_input": "2026-03-30T10:54:11.787937Z", + "iopub.status.busy": "2026-03-30T10:54:11.787864Z", + "iopub.status.idle": "2026-03-30T10:54:11.789730Z", + "shell.execute_reply": "2026-03-30T10:54:11.789532Z" } }, "outputs": [ @@ -218,14 +218,14 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-29 21:12:31,323 - pylabrobot - IO - [MT Scale] Sent command: ZC 5000\n" + "2026-03-30 11:54:11,788 - pylabrobot - IO - [MT Scale] Sent command: ZC 5000\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ - "2026-03-29 21:12:31,323 - pylabrobot - IO - [MT Scale] Received response: ZC A \n" + "2026-03-30 11:54:11,788 - pylabrobot - IO - [MT Scale] Received response: ZC A \n" ] } ], @@ -259,10 +259,10 @@ "execution_count": 5, "metadata": { "execution": { - "iopub.execute_input": "2026-03-29T20:12:31.325966Z", - "iopub.status.busy": "2026-03-29T20:12:31.325894Z", - "iopub.status.idle": "2026-03-29T20:12:31.327635Z", - "shell.execute_reply": "2026-03-29T20:12:31.327454Z" + "iopub.execute_input": "2026-03-30T10:54:11.790705Z", + "iopub.status.busy": "2026-03-30T10:54:11.790629Z", + "iopub.status.idle": "2026-03-30T10:54:11.792444Z", + "shell.execute_reply": "2026-03-30T10:54:11.792307Z" } }, "outputs": [ @@ -270,14 +270,14 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-29 21:12:31,326 - pylabrobot - IO - [MT Scale] Sent command: TC 5000\n" + "2026-03-30 11:54:11,791 - pylabrobot - IO - [MT Scale] Sent command: TC 5000\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ - "2026-03-29 21:12:31,326 - pylabrobot - IO - [MT Scale] Received response: TC S 50.00000 g\n" + "2026-03-30 11:54:11,791 - pylabrobot - IO - [MT Scale] Received response: TC S 50.00000 g\n" ] } ], @@ -300,10 +300,10 @@ "execution_count": 6, "metadata": { "execution": { - "iopub.execute_input": "2026-03-29T20:12:31.328605Z", - "iopub.status.busy": "2026-03-29T20:12:31.328533Z", - "iopub.status.idle": "2026-03-29T20:12:31.331657Z", - "shell.execute_reply": "2026-03-29T20:12:31.331493Z" + "iopub.execute_input": "2026-03-30T10:54:11.793343Z", + "iopub.status.busy": "2026-03-30T10:54:11.793295Z", + "iopub.status.idle": "2026-03-30T10:54:11.796330Z", + "shell.execute_reply": "2026-03-30T10:54:11.796162Z" } }, "outputs": [ @@ -311,14 +311,14 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-29 21:12:31,328 - pylabrobot - IO - [MT Scale] Sent command: TA\n" + "2026-03-30 11:54:11,793 - pylabrobot - IO - [MT Scale] Sent command: TA\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ - "2026-03-29 21:12:31,329 - pylabrobot - IO - [MT Scale] Received response: TA A 50.00000 g\n" + "2026-03-30 11:54:11,793 - pylabrobot - IO - [MT Scale] Received response: TA A 50.00000 g\n" ] }, { @@ -351,10 +351,10 @@ "execution_count": 7, "metadata": { "execution": { - "iopub.execute_input": "2026-03-29T20:12:31.332589Z", - "iopub.status.busy": "2026-03-29T20:12:31.332525Z", - "iopub.status.idle": "2026-03-29T20:12:31.334570Z", - "shell.execute_reply": "2026-03-29T20:12:31.334415Z" + "iopub.execute_input": "2026-03-30T10:54:11.797220Z", + "iopub.status.busy": "2026-03-30T10:54:11.797156Z", + "iopub.status.idle": "2026-03-30T10:54:11.799190Z", + "shell.execute_reply": "2026-03-30T10:54:11.799061Z" } }, "outputs": [ @@ -362,14 +362,14 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-29 21:12:31,332 - pylabrobot - IO - [MT Scale] Sent command: SI\n" + "2026-03-30 11:54:11,797 - pylabrobot - IO - [MT Scale] Sent command: SI\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ - "2026-03-29 21:12:31,333 - pylabrobot - IO - [MT Scale] Received response: SI S 0.01060 g\n" + "2026-03-30 11:54:11,797 - pylabrobot - IO - [MT Scale] Received response: SI S 0.01060 g\n" ] }, { @@ -405,10 +405,10 @@ "execution_count": 8, "metadata": { "execution": { - "iopub.execute_input": "2026-03-29T20:12:31.335599Z", - "iopub.status.busy": "2026-03-29T20:12:31.335545Z", - "iopub.status.idle": "2026-03-29T20:12:31.338458Z", - "shell.execute_reply": "2026-03-29T20:12:31.338291Z" + "iopub.execute_input": "2026-03-30T10:54:11.799996Z", + "iopub.status.busy": "2026-03-30T10:54:11.799943Z", + "iopub.status.idle": "2026-03-30T10:54:11.802944Z", + "shell.execute_reply": "2026-03-30T10:54:11.802788Z" } }, "outputs": [ @@ -416,42 +416,42 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-29 21:12:31,336 - pylabrobot - IO - [MT Scale] Sent command: Z\n" + "2026-03-30 11:54:11,800 - pylabrobot - IO - [MT Scale] Sent command: Z\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ - "2026-03-29 21:12:31,336 - pylabrobot - IO - [MT Scale] Received response: Z A \n" + "2026-03-30 11:54:11,800 - pylabrobot - IO - [MT Scale] Received response: Z A \n" ] }, { "name": "stderr", "output_type": "stream", "text": [ - "2026-03-29 21:12:31,336 - pylabrobot - IO - [MT Scale] Sent command: TC 5000\n" + "2026-03-30 11:54:11,801 - pylabrobot - IO - [MT Scale] Sent command: TC 5000\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ - "2026-03-29 21:12:31,336 - pylabrobot - IO - [MT Scale] Received response: TC S -0.01060 g\n" + "2026-03-30 11:54:11,801 - pylabrobot - IO - [MT Scale] Received response: TC S -0.01060 g\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ - "2026-03-29 21:12:31,337 - pylabrobot - IO - [MT Scale] Sent command: SC 5000\n" + "2026-03-30 11:54:11,801 - pylabrobot - IO - [MT Scale] Sent command: SC 5000\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ - "2026-03-29 21:12:31,337 - pylabrobot - IO - [MT Scale] Received response: SC S 0.01060 g\n" + "2026-03-30 11:54:11,801 - pylabrobot - IO - [MT Scale] Received response: SC S 0.01060 g\n" ] }, { @@ -522,10 +522,10 @@ "execution_count": 9, "metadata": { "execution": { - "iopub.execute_input": "2026-03-29T20:12:31.339353Z", - "iopub.status.busy": "2026-03-29T20:12:31.339299Z", - "iopub.status.idle": "2026-03-29T20:12:31.341336Z", - "shell.execute_reply": "2026-03-29T20:12:31.341172Z" + "iopub.execute_input": "2026-03-30T10:54:11.803846Z", + "iopub.status.busy": "2026-03-30T10:54:11.803791Z", + "iopub.status.idle": "2026-03-30T10:54:11.805840Z", + "shell.execute_reply": "2026-03-30T10:54:11.805684Z" } }, "outputs": [ @@ -533,28 +533,28 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-29 21:12:31,339 - pylabrobot - IO - [MT Scale] Sent command: I50\n" + "2026-03-30 11:54:11,804 - pylabrobot - IO - [MT Scale] Sent command: I50\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ - "2026-03-29 21:12:31,339 - pylabrobot - IO - [MT Scale] Received response: I50 B 0 173.940 g\n" + "2026-03-30 11:54:11,804 - pylabrobot - IO - [MT Scale] Received response: I50 B 0 173.940 g\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ - "2026-03-29 21:12:31,340 - pylabrobot - IO - [MT Scale] Received response: I50 B 1 0.000 g\n" + "2026-03-30 11:54:11,804 - pylabrobot - IO - [MT Scale] Received response: I50 B 1 0.000 g\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ - "2026-03-29 21:12:31,340 - pylabrobot - IO - [MT Scale] Received response: I50 A 2 173.940 g\n" + "2026-03-30 11:54:11,804 - pylabrobot - IO - [MT Scale] Received response: I50 A 2 173.940 g\n" ] }, { @@ -585,10 +585,10 @@ "execution_count": 10, "metadata": { "execution": { - "iopub.execute_input": "2026-03-29T20:12:31.342219Z", - "iopub.status.busy": "2026-03-29T20:12:31.342163Z", - "iopub.status.idle": "2026-03-29T20:12:31.343978Z", - "shell.execute_reply": "2026-03-29T20:12:31.343829Z" + "iopub.execute_input": "2026-03-30T10:54:11.806709Z", + "iopub.status.busy": "2026-03-30T10:54:11.806653Z", + "iopub.status.idle": "2026-03-30T10:54:11.808466Z", + "shell.execute_reply": "2026-03-30T10:54:11.808296Z" } }, "outputs": [ @@ -596,14 +596,14 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-29 21:12:31,342 - pylabrobot - IO - [MT Scale] Sent command: M28\n" + "2026-03-30 11:54:11,806 - pylabrobot - IO - [MT Scale] Sent command: M28\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ - "2026-03-29 21:12:31,342 - pylabrobot - IO - [MT Scale] Received response: M28 A 1 22.5\n" + "2026-03-30 11:54:11,807 - pylabrobot - IO - [MT Scale] Received response: M28 A 1 22.5\n" ] }, { @@ -637,10 +637,10 @@ "execution_count": 11, "metadata": { "execution": { - "iopub.execute_input": "2026-03-29T20:12:31.344856Z", - "iopub.status.busy": "2026-03-29T20:12:31.344801Z", - "iopub.status.idle": "2026-03-29T20:12:31.346476Z", - "shell.execute_reply": "2026-03-29T20:12:31.346247Z" + "iopub.execute_input": "2026-03-30T10:54:11.809365Z", + "iopub.status.busy": "2026-03-30T10:54:11.809315Z", + "iopub.status.idle": "2026-03-30T10:54:11.810851Z", + "shell.execute_reply": "2026-03-30T10:54:11.810695Z" } }, "outputs": [], @@ -672,10 +672,10 @@ "execution_count": 12, "metadata": { "execution": { - "iopub.execute_input": "2026-03-29T20:12:31.347367Z", - "iopub.status.busy": "2026-03-29T20:12:31.347314Z", - "iopub.status.idle": "2026-03-29T20:12:31.348820Z", - "shell.execute_reply": "2026-03-29T20:12:31.348661Z" + "iopub.execute_input": "2026-03-30T10:54:11.811707Z", + "iopub.status.busy": "2026-03-30T10:54:11.811657Z", + "iopub.status.idle": "2026-03-30T10:54:11.813231Z", + "shell.execute_reply": "2026-03-30T10:54:11.813084Z" } }, "outputs": [ @@ -683,7 +683,7 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-29 21:12:31,347 - pylabrobot - INFO - === MT Scale tutorial ended ===\n" + "2026-03-30 11:54:11,811 - pylabrobot - INFO - === MT Scale tutorial ended ===\n" ] } ], diff --git a/pylabrobot/scales/mettler_toledo/backend.py b/pylabrobot/scales/mettler_toledo/backend.py index 3347ecba8b8..3c8405836ad 100644 --- a/pylabrobot/scales/mettler_toledo/backend.py +++ b/pylabrobot/scales/mettler_toledo/backend.py @@ -35,25 +35,27 @@ class MettlerToledoResponse: F = TypeVar("F", bound=Callable[..., Any]) -def requires_mt_sics_level(level: int) -> Callable[[F], F]: - """Decorator that gates a method on the connected device supporting the required MT-SICS level. +def requires_mt_sics_command(mt_sics_command: str) -> Callable[[F], F]: + """Decorator that gates a method on the connected device supporting a specific MT-SICS command. - During setup(), the backend queries I1 to discover which levels the connected device supports. - Methods decorated with a level higher than what the device reports will raise MettlerToledoError. - See the class docstring of MettlerToledoWXS205SDUBackend for level descriptions. + During setup(), the backend queries I0 to discover the full list of implemented commands. + Methods decorated with a command not in that list will raise MettlerToledoError. + + I0 is the definitive source of command support - I1 only reports which standardized + level sets are fully implemented, but individual commands may exist outside those levels. """ def decorator(func: F) -> F: - func._mt_sics_level = level # type: ignore[attr-defined] + func._mt_sics_command = mt_sics_command # type: ignore[attr-defined] @functools.wraps(func) async def wrapper(self: Any, *args: Any, **kwargs: Any) -> Any: - if hasattr(self, "_mt_sics_levels") and self._mt_sics_levels is not None: - if level not in self._mt_sics_levels: + if hasattr(self, "_supported_commands") and self._supported_commands is not None: + if mt_sics_command not in self._supported_commands: raise MettlerToledoError( title="Command not supported", - message=f"'{func.__name__}' requires MT-SICS level {level}, " - f"but device supports levels: {sorted(self._mt_sics_levels)}", + message=f"'{func.__name__}' requires MT-SICS command '{mt_sics_command}', " + f"which is not implemented on this device.", ) return await func(self, *args, **kwargs) @@ -68,21 +70,12 @@ class MettlerToledoWXS205SDUBackend(ScaleBackend): MT-SICS (Mettler Toledo Standard Interface Command Set) is the serial communication protocol used by Mettler Toledo's Automated Precision Weigh Modules. This backend is - compatible with any MT-SICS device, including the WXS, WMS, and WX series. During - setup(), this backend queries the device to discover its identity, capacity, and - supported MT-SICS levels. - - MT-SICS levels: - - Level 0: Basic set - identification (I0-I4), basic weighing (S, SI), zero (Z, ZI), - tare (T, TI), cancel (@). Always available on every MT-SICS device. - - Level 1: Elementary commands - display (D, DW), tare memory (TA, TAC), timed - weighing (SC), timed zero/tare (ZC, TC). Always available. - - Level 2: Extended command list - configuration (M21, COM), device info (I50, I47, - I48). Model-dependent, not guaranteed on every device. - - Level 3: Application-specific command set. Model-dependent. - - Methods requiring Level 2+ are decorated with ``@requires_mt_sics_level`` and will - raise ``MettlerToledoError`` if the connected device does not support the required level. + compatible with any MT-SICS device, including the WXS, WMS, and WX series. + + During setup(), the backend queries I0 to discover which commands the connected device + supports, then queries I1/I2/I4 for device identity. Methods decorated with + ``@requires_mt_sics_command`` will raise ``MettlerToledoError`` if the required command + is not in the device's I0 command list. Tested on the WXS205SDU (used by Hamilton in the Liquid Verification Kit). @@ -116,10 +109,12 @@ async def setup(self) -> None: # cancel() clears the input buffer and sends @, which returns the serial number self.serial_number = await self.cancel() - # Device discovery (Level 0 - always available) + # Discover supported commands via I0 (the definitive source per spec Section 2.2) + self._supported_commands: Set[str] = await self._query_supported_commands() + + # Device identity (Level 0 - always available) # Note: device_type and capacity both use I2 but are separate methods intentionally - # single-responsibility per method, the duplicate I2 round-trip during one-time setup is fine. - self._mt_sics_levels: Set[int] = await self._query_mt_sics_levels() self.device_type = await self.request_device_type() self.capacity = await self.request_capacity() @@ -128,16 +123,16 @@ async def setup(self) -> None: "Device type: %s\n" "Serial number: %s\n" "Capacity: %.1f g\n" - "MT-SICS levels: %s", + "Supported commands: %s", self.io.port, self.device_type, self.serial_number, self.capacity, - sorted(self._mt_sics_levels), + sorted(self._supported_commands), ) # Set output unit to grams - if 2 in self._mt_sics_levels: + if "M21" in self._supported_commands: await self.set_host_unit_grams() async def stop(self) -> None: @@ -148,16 +143,22 @@ def serialize(self) -> dict: # === Device discovery === - async def _query_mt_sics_levels(self) -> Set[int]: - """Query supported MT-SICS levels via I1 command (Level 0 - always available). + async def _query_supported_commands(self) -> Set[str]: + """Query all implemented commands via I0 (Level 0 - always available). + + I0 is the definitive source of command support per spec Section 2.2. + I1 only reports which standardized level sets are fully implemented, + but individual commands may exist outside those levels. - Returns a set of integers representing the supported levels (e.g. {0, 1, 2, 3}). + Returns a set of command strings (e.g. {"@", "S", "SI", "Z", "M21", "M28"}). """ - responses = await self.send_command("I1") - # I1 A "0123" "2.00" "2.20" "1.00" "1.50" - self._validate_response(responses[0], 3, "I1") - level_string = responses[0].data[0] - return {int(c) for c in level_string} + responses = await self.send_command("I0") + commands: Set[str] = set() + for resp in responses: + # Format: I0 B/A + if len(resp.data) >= 2: + commands.add(resp.data[1]) + return commands # === Response parsing === @@ -363,7 +364,7 @@ async def request_capacity(self) -> float: self._validate_unit(parts[-1], "I2") return float(parts[-2]) - @requires_mt_sics_level(2) + @requires_mt_sics_command("I50") async def request_remaining_weighing_range(self) -> float: """Query remaining maximum weighing range in grams. (I50 command) @@ -562,12 +563,12 @@ async def set_weight_display(self) -> List[MettlerToledoResponse]: # # Configuration commands # # - @requires_mt_sics_level(2) + @requires_mt_sics_command("M21") async def set_host_unit_grams(self) -> List[MettlerToledoResponse]: """Set the host output unit to grams. (M21 command)""" return await self.send_command("M21 0 0") - @requires_mt_sics_level(2) + @requires_mt_sics_command("M28") async def measure_temperature(self) -> float: """Query the current temperature from the scale's internal sensor in degrees C. (M28 command) diff --git a/pylabrobot/scales/mettler_toledo/backend_tests.py b/pylabrobot/scales/mettler_toledo/backend_tests.py index 1dff2cd4974..e893367eee6 100644 --- a/pylabrobot/scales/mettler_toledo/backend_tests.py +++ b/pylabrobot/scales/mettler_toledo/backend_tests.py @@ -120,7 +120,8 @@ async def test_setup_populates_device_identity(self): self.assertEqual(self.backend.device_type, "WXS205SDU") self.assertEqual(self.backend.serial_number, "SIM0000001") self.assertEqual(self.backend.capacity, 220.0) - self.assertIn(0, self.backend._mt_sics_levels) + self.assertIn("S", self.backend._supported_commands) + self.assertIn("M28", self.backend._supported_commands) async def test_tare_workflow_through_protocol(self): """Full tare workflow through the MT-SICS protocol layer. @@ -167,10 +168,23 @@ async def test_unknown_command_returns_syntax_error(self): async def test_measure_temperature(self): """measure_temperature must return a float from the M28 response. - Requires Level 2 decorator to not block the call.""" + Requires M28 in the device's I0 command list.""" temp = await self.backend.measure_temperature() self.assertEqual(temp, 22.5) + async def test_measure_temperature_blocked_when_unsupported(self): + """measure_temperature must raise when M28 is not in the device's command list. + Validates that I0-based command gating works correctly.""" + backend = MettlerToledoChatterboxBackend( + supported_commands={"@", "I0", "I2", "I4", "S", "SI", "Z", "ZI", "T", "TI", "TA", "TAC"}, + ) + scale = Scale(name="limited_scale", backend=backend, size_x=0, size_y=0, size_z=0) + await scale.setup() + with self.assertRaises(MettlerToledoError) as ctx: + await backend.measure_temperature() + self.assertIn("M28", str(ctx.exception)) + self.assertIn("not implemented", str(ctx.exception)) + if __name__ == "__main__": unittest.main() diff --git a/pylabrobot/scales/mettler_toledo/chatterbox.py b/pylabrobot/scales/mettler_toledo/chatterbox.py index 6292a7b16af..4bc9930aea2 100644 --- a/pylabrobot/scales/mettler_toledo/chatterbox.py +++ b/pylabrobot/scales/mettler_toledo/chatterbox.py @@ -48,7 +48,7 @@ def __init__( device_type: str = "WXS205SDU", serial_number: str = "SIM0000001", capacity: float = 220.0, - mt_sics_levels: Optional[Set[int]] = None, + supported_commands: Optional[Set[str]] = None, ) -> None: # Skip MettlerToledoWXS205SDUBackend.__init__ (which creates a Serial object) ScaleBackend.__init__(self) @@ -63,7 +63,33 @@ def __init__( self._simulated_device_type = device_type self._simulated_serial_number = serial_number self._simulated_capacity = capacity - self._simulated_mt_sics_levels = mt_sics_levels or {0, 1, 2, 3} + # Default: all commands the chatterbox can mock + self._simulated_supported_commands = supported_commands or { + "@", + "I0", + "I1", + "I2", + "I4", + "S", + "SI", + "Z", + "ZI", + "ZC", + "T", + "TI", + "TC", + "TA", + "TAC", + "SC", + "C", + "D", + "DW", + "M21", + "M28", + "I50", + "SR", + "SIR", + } @property def _sensor_reading(self) -> float: @@ -71,7 +97,7 @@ def _sensor_reading(self) -> float: async def setup(self) -> None: self.serial_number = self._simulated_serial_number - self._mt_sics_levels = self._simulated_mt_sics_levels + self._supported_commands = self._simulated_supported_commands self.device_type = self._simulated_device_type self.capacity = self._simulated_capacity logger.info( @@ -79,11 +105,11 @@ async def setup(self) -> None: "Device type: %s\n" "Serial number: %s\n" "Capacity: %.1f g\n" - "MT-SICS levels: %s", + "Supported commands: %s", self.device_type, self.serial_number, self.capacity, - sorted(self._mt_sics_levels), + sorted(self._supported_commands), ) async def stop(self) -> None: @@ -116,9 +142,13 @@ def _build_response(self, command: str) -> List[MettlerToledoResponse]: # Identification (shlex strips quotes, so mock responses should not include them) if cmd == "@": return [R("I4", "A", [self._simulated_serial_number])] + if cmd == "I0": + cmds = sorted(self._simulated_supported_commands) + responses = [R("I0", "B", ["0", c]) for c in cmds[:-1]] + responses.append(R("I0", "A", ["0", cmds[-1]])) + return responses if cmd == "I1": - levels = "".join(str(lvl) for lvl in sorted(self._simulated_mt_sics_levels)) - return [R("I1", "A", [levels])] + return [R("I1", "A", ["01"])] if cmd == "I2": return [R("I2", "A", [f"{self._simulated_device_type} {self._simulated_capacity:.5f} g"])] if cmd == "I4": diff --git a/pylabrobot/scales/mettler_toledo/hardware_validation.ipynb b/pylabrobot/scales/mettler_toledo/hardware_validation.ipynb index 7c2076c935e..da46b97ccc4 100644 --- a/pylabrobot/scales/mettler_toledo/hardware_validation.ipynb +++ b/pylabrobot/scales/mettler_toledo/hardware_validation.ipynb @@ -93,7 +93,9 @@ ], "source": [ "# Update port for your system\n", - "backend = MettlerToledoWXS205SDUBackend(port=\"/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0\")\n", + "backend = MettlerToledoWXS205SDUBackend(\n", + " port=\"/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0\"\n", + ")\n", "scale = Scale(name=\"validation_scale\", backend=backend, size_x=0, size_y=0, size_z=0)\n", "\n", "await scale.setup()" @@ -108,31 +110,21 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Device type: WXS205SDU WXA-Bridge\n", - "Serial number: B207696838\n", - "Capacity: 220.009 g\n", - "MT-SICS levels: [0, 1]\n", - "PASS: setup populated all identity fields\n" - ] - } - ], + "outputs": [], "source": [ "print(f\"Device type: {backend.device_type}\")\n", "print(f\"Serial number: {backend.serial_number}\")\n", "print(f\"Capacity: {backend.capacity} g\")\n", - "print(f\"MT-SICS levels: {sorted(backend._mt_sics_levels)}\")\n", + "print(\n", + " f\"Supported commands ({len(backend._supported_commands)}): {sorted(backend._supported_commands)}\"\n", + ")\n", "\n", "assert backend.device_type is not None\n", "assert backend.serial_number is not None\n", "assert backend.capacity > 0\n", - "assert 0 in backend._mt_sics_levels\n", + "assert \"S\" in backend._supported_commands\n", "print(\"PASS: setup populated all identity fields\")" ] }, @@ -332,29 +324,50 @@ "# Group by level\n", "by_level = defaultdict(list)\n", "for resp in responses:\n", - " # Format: I0 B/A <\"command\">\n", - " if len(resp.data) >= 2:\n", - " level = resp.data[0]\n", - " cmd_name = resp.data[1]\n", - " by_level[level].append(cmd_name)\n", + " # Format: I0 B/A <\"command\">\n", + " if len(resp.data) >= 2:\n", + " level = resp.data[0]\n", + " cmd_name = resp.data[1]\n", + " by_level[level].append(cmd_name)\n", "\n", "for level in sorted(by_level.keys()):\n", - " cmds = sorted(by_level[level])\n", - " print(f\"Level {level} ({len(cmds)} commands): {', '.join(cmds)}\")\n", + " cmds = sorted(by_level[level])\n", + " print(f\"Level {level} ({len(cmds)} commands): {', '.join(cmds)}\")\n", "\n", "# Check which commands we use that might not be supported\n", - "our_commands = [\"@\", \"C\", \"D\", \"DW\", \"I0\", \"I1\", \"I2\", \"I4\", \"I50\",\n", - " \"M21\", \"M28\", \"S\", \"SC\", \"SI\", \"T\", \"TA\", \"TAC\",\n", - " \"TI\", \"Z\", \"ZC\", \"ZI\", \"TC\"]\n", + "our_commands = [\n", + " \"@\",\n", + " \"C\",\n", + " \"D\",\n", + " \"DW\",\n", + " \"I0\",\n", + " \"I1\",\n", + " \"I2\",\n", + " \"I4\",\n", + " \"I50\",\n", + " \"M21\",\n", + " \"M28\",\n", + " \"S\",\n", + " \"SC\",\n", + " \"SI\",\n", + " \"T\",\n", + " \"TA\",\n", + " \"TAC\",\n", + " \"TI\",\n", + " \"Z\",\n", + " \"ZC\",\n", + " \"ZI\",\n", + " \"TC\",\n", + "]\n", "all_device_cmds = set()\n", "for cmds in by_level.values():\n", - " all_device_cmds.update(cmds)\n", + " all_device_cmds.update(cmds)\n", "\n", "print()\n", "print(\"Commands we use vs device support:\")\n", "for cmd in sorted(our_commands):\n", - " status = \"supported\" if cmd in all_device_cmds else \"NOT SUPPORTED\"\n", - " print(f\" {cmd}: {status}\")" + " status = \"supported\" if cmd in all_device_cmds else \"NOT SUPPORTED\"\n", + " print(f\" {cmd}: {status}\")" ] }, { @@ -497,34 +510,16 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2026-03-30 11:42:28,329 - pylabrobot - IO - [MT Scale] Sent command: I1\n", - "2026-03-30 11:42:28,332 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I1\\r\\n'\n", - "2026-03-30 11:42:28,386 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I1 A \"01\" \"2.30\" \"2.22\" \"\" \"\"\\r\\n'\n", - "2026-03-30 11:42:28,386 - pylabrobot - IO - [MT Scale] Received response: b'I1 A \"01\" \"2.30\" \"2.22\" \"\" \"\"\\r\\n'\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Supported levels: [0, 1]\n", - "PASS: levels 0 and 1 present (always required)\n" - ] - } - ], + "outputs": [], "source": [ - "levels = await backend._query_mt_sics_levels()\n", - "print(f\"Supported levels: {sorted(levels)}\")\n", - "assert 0 in levels\n", - "assert 1 in levels\n", - "print(\"PASS: levels 0 and 1 present (always required)\")" + "# I1 reports standardized level sets (may not reflect all available commands)\n", + "# I0 is the definitive source (already queried during setup)\n", + "responses = await backend.send_command(\"I1\")\n", + "print(f\"I1 reported levels: {responses[0].data}\")\n", + "print(f\"I0 discovered {len(backend._supported_commands)} commands\")\n", + "print(\"Note: I1 may underreport - I0 is the authoritative source\")" ] }, { @@ -1046,23 +1041,15 @@ }, { "cell_type": "code", - "execution_count": 20, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "SKIP: Level 2 not supported\n" - ] - } - ], + "outputs": [], "source": [ - "if 2 in backend._mt_sics_levels:\n", + "if \"M21\" in backend._supported_commands:\n", " await backend.set_host_unit_grams()\n", " print(\"PASS: host unit set to grams\")\n", "else:\n", - " print(\"SKIP: Level 2 not supported\")" + " print(\"SKIP: M21 not supported on this device\")" ] }, { @@ -1074,26 +1061,18 @@ }, { "cell_type": "code", - "execution_count": 21, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "SKIP: Level 2 not supported\n" - ] - } - ], + "outputs": [], "source": [ - "if 2 in backend._mt_sics_levels:\n", + "if \"I50\" in backend._supported_commands:\n", " remaining = await backend.request_remaining_weighing_range()\n", " print(f\"Remaining weighing range: {remaining} g\")\n", " assert remaining > 0\n", " assert remaining <= backend.capacity\n", " print(\"PASS: remaining range is positive and within capacity\")\n", "else:\n", - " print(\"SKIP: Level 2 not supported\")" + " print(\"SKIP: I50 not supported on this device\")" ] }, { @@ -1105,25 +1084,17 @@ }, { "cell_type": "code", - "execution_count": 22, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "SKIP: Level 2 not supported\n" - ] - } - ], + "outputs": [], "source": [ - "if 2 in backend._mt_sics_levels:\n", + "if \"M28\" in backend._supported_commands:\n", " temp = await backend.measure_temperature()\n", " print(f\"Scale temperature: {temp} C\")\n", " assert 5 < temp < 50, f\"Temperature {temp} C outside reasonable range\"\n", - " print(\"PASS: temperature sensor returns reasonable value\")\n", + " print(\"PASS: measure_temperature works - I0 correctly predicted M28 support\")\n", "else:\n", - " print(\"SKIP: Level 2 not supported\")" + " print(\"SKIP: M28 not supported on this device\")" ] }, { @@ -1420,4 +1391,4 @@ }, "nbformat": 4, "nbformat_minor": 4 -} +} \ No newline at end of file From bbdc8fae72d6865aba6f69cc56690ab6476fd2d2 Mon Sep 17 00:00:00 2001 From: Camillo Moschner Date: Mon, 30 Mar 2026 11:59:47 +0100 Subject: [PATCH 15/38] testing direct command list retrieval --- .../mettler_toledo/hardware_validation.ipynb | 913 +++++++++++------- 1 file changed, 559 insertions(+), 354 deletions(-) diff --git a/pylabrobot/scales/mettler_toledo/hardware_validation.ipynb b/pylabrobot/scales/mettler_toledo/hardware_validation.ipynb index da46b97ccc4..7c568c7698e 100644 --- a/pylabrobot/scales/mettler_toledo/hardware_validation.ipynb +++ b/pylabrobot/scales/mettler_toledo/hardware_validation.ipynb @@ -33,7 +33,7 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 11:42:26,797 - pylabrobot - INFO - === Hardware validation started ===\n" + "2026-03-30 11:58:03,533 - pylabrobot - INFO - === Hardware validation started ===\n" ] } ], @@ -65,29 +65,155 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 11:42:26,828 - pylabrobot.io.serial - INFO - Using explicitly provided port: /dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0 (for VID=1027, PID=24577)\n", - "2026-03-30 11:42:26,837 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] reset_input_buffer\n", - "2026-03-30 11:42:26,840 - pylabrobot - IO - [MT Scale] Sent command: @\n", - "2026-03-30 11:42:26,868 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'@\\r\\n'\n", - "2026-03-30 11:42:26,931 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I4 A \"B207696838\"\\r\\n'\n", - "2026-03-30 11:42:26,932 - pylabrobot - IO - [MT Scale] Received response: b'I4 A \"B207696838\"\\r\\n'\n", - "2026-03-30 11:42:26,932 - pylabrobot - IO - [MT Scale] Sent command: I1\n", - "2026-03-30 11:42:26,933 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I1\\r\\n'\n", - "2026-03-30 11:42:26,981 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I1 A \"01\" \"2.30\" \"2.22\" \"\" \"\"\\r\\n'\n", - "2026-03-30 11:42:26,982 - pylabrobot - IO - [MT Scale] Received response: b'I1 A \"01\" \"2.30\" \"2.22\" \"\" \"\"\\r\\n'\n", - "2026-03-30 11:42:26,983 - pylabrobot - IO - [MT Scale] Sent command: I2\n", - "2026-03-30 11:42:26,986 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I2\\r\\n'\n", - "2026-03-30 11:42:27,042 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", - "2026-03-30 11:42:27,043 - pylabrobot - IO - [MT Scale] Received response: b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", - "2026-03-30 11:42:27,044 - pylabrobot - IO - [MT Scale] Sent command: I2\n", - "2026-03-30 11:42:27,045 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I2\\r\\n'\n", - "2026-03-30 11:42:27,106 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", - "2026-03-30 11:42:27,108 - pylabrobot - IO - [MT Scale] Received response: b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", - "2026-03-30 11:42:27,108 - pylabrobot - INFO - [MT Scale] Connected to Mettler Toledo scale on /dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0\n", + "2026-03-30 11:58:03,553 - pylabrobot.io.serial - INFO - Using explicitly provided port: /dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0 (for VID=1027, PID=24577)\n", + "2026-03-30 11:58:03,562 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] reset_input_buffer\n", + "2026-03-30 11:58:03,566 - pylabrobot - IO - [MT Scale] Sent command: @\n", + "2026-03-30 11:58:03,570 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'@\\r\\n'\n", + "2026-03-30 11:58:03,636 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I4 A \"B207696838\"\\r\\n'\n", + "2026-03-30 11:58:03,637 - pylabrobot - IO - [MT Scale] Received response: b'I4 A \"B207696838\"\\r\\n'\n", + "2026-03-30 11:58:03,642 - pylabrobot - IO - [MT Scale] Sent command: I0\n", + "2026-03-30 11:58:03,644 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I0\\r\\n'\n", + "2026-03-30 11:58:03,683 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I0\"\\r\\n'\n", + "2026-03-30 11:58:03,684 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I0\"\\r\\n'\n", + "2026-03-30 11:58:03,685 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I1\"\\r\\n'\n", + "2026-03-30 11:58:03,686 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I1\"\\r\\n'\n", + "2026-03-30 11:58:03,699 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I2\"\\r\\n'\n", + "2026-03-30 11:58:03,699 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I2\"\\r\\n'\n", + "2026-03-30 11:58:03,715 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I3\"\\r\\n'\n", + "2026-03-30 11:58:03,716 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I3\"\\r\\n'\n", + "2026-03-30 11:58:03,732 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I4\"\\r\\n'\n", + "2026-03-30 11:58:03,737 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I4\"\\r\\n'\n", + "2026-03-30 11:58:03,747 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I5\"\\r\\n'\n", + "2026-03-30 11:58:03,748 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I5\"\\r\\n'\n", + "2026-03-30 11:58:03,763 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"S\"\\r\\n'\n", + "2026-03-30 11:58:03,764 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"S\"\\r\\n'\n", + "2026-03-30 11:58:03,767 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"SI\"\\r\\n'\n", + "2026-03-30 11:58:03,767 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"SI\"\\r\\n'\n", + "2026-03-30 11:58:03,780 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"SIR\"\\r\\n'\n", + "2026-03-30 11:58:03,780 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"SIR\"\\r\\n'\n", + "2026-03-30 11:58:03,795 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"Z\"\\r\\n'\n", + "2026-03-30 11:58:03,796 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"Z\"\\r\\n'\n", + "2026-03-30 11:58:03,811 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"ZI\"\\r\\n'\n", + "2026-03-30 11:58:03,812 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"ZI\"\\r\\n'\n", + "2026-03-30 11:58:03,828 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"@\"\\r\\n'\n", + "2026-03-30 11:58:03,829 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"@\"\\r\\n'\n", + "2026-03-30 11:58:03,843 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"SR\"\\r\\n'\n", + "2026-03-30 11:58:03,844 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"SR\"\\r\\n'\n", + "2026-03-30 11:58:03,847 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"T\"\\r\\n'\n", + "2026-03-30 11:58:03,848 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"T\"\\r\\n'\n", + "2026-03-30 11:58:03,860 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"TA\"\\r\\n'\n", + "2026-03-30 11:58:03,861 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"TA\"\\r\\n'\n", + "2026-03-30 11:58:03,878 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"TAC\"\\r\\n'\n", + "2026-03-30 11:58:03,890 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"TAC\"\\r\\n'\n", + "2026-03-30 11:58:03,892 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"TI\"\\r\\n'\n", + "2026-03-30 11:58:03,893 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"TI\"\\r\\n'\n", + "2026-03-30 11:58:03,908 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C0\"\\r\\n'\n", + "2026-03-30 11:58:03,910 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"C0\"\\r\\n'\n", + "2026-03-30 11:58:03,924 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C1\"\\r\\n'\n", + "2026-03-30 11:58:03,929 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"C1\"\\r\\n'\n", + "2026-03-30 11:58:03,941 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C2\"\\r\\n'\n", + "2026-03-30 11:58:03,946 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"C2\"\\r\\n'\n", + "2026-03-30 11:58:03,950 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C3\"\\r\\n'\n", + "2026-03-30 11:58:03,951 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"C3\"\\r\\n'\n", + "2026-03-30 11:58:03,958 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"COM\"\\r\\n'\n", + "2026-03-30 11:58:03,959 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"COM\"\\r\\n'\n", + "2026-03-30 11:58:03,973 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"DAT\"\\r\\n'\n", + "2026-03-30 11:58:03,976 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"DAT\"\\r\\n'\n", + "2026-03-30 11:58:03,988 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I10\"\\r\\n'\n", + "2026-03-30 11:58:03,990 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I10\"\\r\\n'\n", + "2026-03-30 11:58:04,003 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I11\"\\r\\n'\n", + "2026-03-30 11:58:04,005 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I11\"\\r\\n'\n", + "2026-03-30 11:58:04,019 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I14\"\\r\\n'\n", + "2026-03-30 11:58:04,023 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I14\"\\r\\n'\n", + "2026-03-30 11:58:04,035 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I15\"\\r\\n'\n", + "2026-03-30 11:58:04,037 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I15\"\\r\\n'\n", + "2026-03-30 11:58:04,055 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I16\"\\r\\n'\n", + "2026-03-30 11:58:04,064 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I16\"\\r\\n'\n", + "2026-03-30 11:58:04,069 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I21\"\\r\\n'\n", + "2026-03-30 11:58:04,070 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I21\"\\r\\n'\n", + "2026-03-30 11:58:04,082 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I22\"\\r\\n'\n", + "2026-03-30 11:58:04,083 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I22\"\\r\\n'\n", + "2026-03-30 11:58:04,099 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I23\"\\r\\n'\n", + "2026-03-30 11:58:04,101 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I23\"\\r\\n'\n", + "2026-03-30 11:58:04,103 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I24\"\\r\\n'\n", + "2026-03-30 11:58:04,109 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I24\"\\r\\n'\n", + "2026-03-30 11:58:04,116 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I25\"\\r\\n'\n", + "2026-03-30 11:58:04,118 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I25\"\\r\\n'\n", + "2026-03-30 11:58:04,131 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I26\"\\r\\n'\n", + "2026-03-30 11:58:04,135 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I26\"\\r\\n'\n", + "2026-03-30 11:58:04,150 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M01\"\\r\\n'\n", + "2026-03-30 11:58:04,157 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M01\"\\r\\n'\n", + "2026-03-30 11:58:04,163 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M02\"\\r\\n'\n", + "2026-03-30 11:58:04,166 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M02\"\\r\\n'\n", + "2026-03-30 11:58:04,179 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M03\"\\r\\n'\n", + "2026-03-30 11:58:04,181 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M03\"\\r\\n'\n", + "2026-03-30 11:58:04,195 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M17\"\\r\\n'\n", + "2026-03-30 11:58:04,196 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M17\"\\r\\n'\n", + "2026-03-30 11:58:04,211 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M18\"\\r\\n'\n", + "2026-03-30 11:58:04,212 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M18\"\\r\\n'\n", + "2026-03-30 11:58:04,227 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M19\"\\r\\n'\n", + "2026-03-30 11:58:04,229 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M19\"\\r\\n'\n", + "2026-03-30 11:58:04,245 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M20\"\\r\\n'\n", + "2026-03-30 11:58:04,249 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M20\"\\r\\n'\n", + "2026-03-30 11:58:04,259 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M21\"\\r\\n'\n", + "2026-03-30 11:58:04,260 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M21\"\\r\\n'\n", + "2026-03-30 11:58:04,263 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M27\"\\r\\n'\n", + "2026-03-30 11:58:04,264 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M27\"\\r\\n'\n", + "2026-03-30 11:58:04,274 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M28\"\\r\\n'\n", + "2026-03-30 11:58:04,275 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M28\"\\r\\n'\n", + "2026-03-30 11:58:04,291 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M29\"\\r\\n'\n", + "2026-03-30 11:58:04,292 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M29\"\\r\\n'\n", + "2026-03-30 11:58:04,307 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M31\"\\r\\n'\n", + "2026-03-30 11:58:04,308 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M31\"\\r\\n'\n", + "2026-03-30 11:58:04,322 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M32\"\\r\\n'\n", + "2026-03-30 11:58:04,323 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M32\"\\r\\n'\n", + "2026-03-30 11:58:04,339 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M33\"\\r\\n'\n", + "2026-03-30 11:58:04,339 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M33\"\\r\\n'\n", + "2026-03-30 11:58:04,355 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M35\"\\r\\n'\n", + "2026-03-30 11:58:04,356 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M35\"\\r\\n'\n", + "2026-03-30 11:58:04,370 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"SIS\"\\r\\n'\n", + "2026-03-30 11:58:04,371 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"SIS\"\\r\\n'\n", + "2026-03-30 11:58:04,387 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"SNR\"\\r\\n'\n", + "2026-03-30 11:58:04,387 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"SNR\"\\r\\n'\n", + "2026-03-30 11:58:04,403 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TIM\"\\r\\n'\n", + "2026-03-30 11:58:04,404 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TIM\"\\r\\n'\n", + "2026-03-30 11:58:04,418 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST0\"\\r\\n'\n", + "2026-03-30 11:58:04,419 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TST0\"\\r\\n'\n", + "2026-03-30 11:58:04,435 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST1\"\\r\\n'\n", + "2026-03-30 11:58:04,436 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TST1\"\\r\\n'\n", + "2026-03-30 11:58:04,451 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST2\"\\r\\n'\n", + "2026-03-30 11:58:04,452 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TST2\"\\r\\n'\n", + "2026-03-30 11:58:04,466 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST3\"\\r\\n'\n", + "2026-03-30 11:58:04,468 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TST3\"\\r\\n'\n", + "2026-03-30 11:58:04,483 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"UPD\"\\r\\n'\n", + "2026-03-30 11:58:04,483 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"UPD\"\\r\\n'\n", + "2026-03-30 11:58:04,498 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"FCUT\"\\r\\n'\n", + "2026-03-30 11:58:04,499 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 3 \"FCUT\"\\r\\n'\n", + "2026-03-30 11:58:04,514 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"FSET\"\\r\\n'\n", + "2026-03-30 11:58:04,515 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 3 \"FSET\"\\r\\n'\n", + "2026-03-30 11:58:04,519 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"LST\"\\r\\n'\n", + "2026-03-30 11:58:04,520 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 3 \"LST\"\\r\\n'\n", + "2026-03-30 11:58:04,531 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"RDB\"\\r\\n'\n", + "2026-03-30 11:58:04,532 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 3 \"RDB\"\\r\\n'\n", + "2026-03-30 11:58:04,546 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 A 3 \"USTB\"\\r\\n'\n", + "2026-03-30 11:58:04,547 - pylabrobot - IO - [MT Scale] Received response: b'I0 A 3 \"USTB\"\\r\\n'\n", + "2026-03-30 11:58:04,548 - pylabrobot - IO - [MT Scale] Sent command: I2\n", + "2026-03-30 11:58:04,551 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I2\\r\\n'\n", + "2026-03-30 11:58:04,610 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", + "2026-03-30 11:58:04,611 - pylabrobot - IO - [MT Scale] Received response: b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", + "2026-03-30 11:58:04,612 - pylabrobot - IO - [MT Scale] Sent command: I2\n", + "2026-03-30 11:58:04,614 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I2\\r\\n'\n", + "2026-03-30 11:58:04,675 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", + "2026-03-30 11:58:04,675 - pylabrobot - IO - [MT Scale] Received response: b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", + "2026-03-30 11:58:04,677 - pylabrobot - INFO - [MT Scale] Connected to Mettler Toledo scale on /dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0\n", "Device type: WXS205SDU WXA-Bridge\n", "Serial number: B207696838\n", "Capacity: 220.0 g\n", - "MT-SICS levels: [0, 1]\n" + "Supported commands: ['@', 'C0', 'C1', 'C2', 'C3', 'COM', 'DAT', 'FCUT', 'FSET', 'I0', 'I1', 'I10', 'I11', 'I14', 'I15', 'I16', 'I2', 'I21', 'I22', 'I23', 'I24', 'I25', 'I26', 'I3', 'I4', 'I5', 'LST', 'M01', 'M02', 'M03', 'M17', 'M18', 'M19', 'M20', 'M21', 'M27', 'M28', 'M29', 'M31', 'M32', 'M33', 'M35', 'RDB', 'S', 'SI', 'SIR', 'SIS', 'SNR', 'SR', 'T', 'TA', 'TAC', 'TI', 'TIM', 'TST0', 'TST1', 'TST2', 'TST3', 'UPD', 'USTB', 'Z', 'ZI']\n", + "2026-03-30 11:58:04,678 - pylabrobot - IO - [MT Scale] Sent command: M21 0 0\n", + "2026-03-30 11:58:04,680 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'M21 0 0\\r\\n'\n", + "2026-03-30 11:58:04,706 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M21 A\\r\\n'\n", + "2026-03-30 11:58:04,707 - pylabrobot - IO - [MT Scale] Received response: b'M21 A\\r\\n'\n" ] } ], @@ -110,9 +236,21 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 3, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Device type: WXS205SDU WXA-Bridge\n", + "Serial number: B207696838\n", + "Capacity: 220.009 g\n", + "Supported commands (62): ['@', 'C0', 'C1', 'C2', 'C3', 'COM', 'DAT', 'FCUT', 'FSET', 'I0', 'I1', 'I10', 'I11', 'I14', 'I15', 'I16', 'I2', 'I21', 'I22', 'I23', 'I24', 'I25', 'I26', 'I3', 'I4', 'I5', 'LST', 'M01', 'M02', 'M03', 'M17', 'M18', 'M19', 'M20', 'M21', 'M27', 'M28', 'M29', 'M31', 'M32', 'M33', 'M35', 'RDB', 'S', 'SI', 'SIR', 'SIS', 'SNR', 'SR', 'T', 'TA', 'TAC', 'TI', 'TIM', 'TST0', 'TST1', 'TST2', 'TST3', 'UPD', 'USTB', 'Z', 'ZI']\n", + "PASS: setup populated all identity fields\n" + ] + } + ], "source": [ "print(f\"Device type: {backend.device_type}\")\n", "print(f\"Serial number: {backend.serial_number}\")\n", @@ -147,132 +285,132 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 11:42:27,143 - pylabrobot - IO - [MT Scale] Sent command: I0\n", - "2026-03-30 11:42:27,152 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I0\\r\\n'\n", - "2026-03-30 11:42:27,189 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I0\"\\r\\n'\n", - "2026-03-30 11:42:27,192 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I0\"\\r\\n'\n", - "2026-03-30 11:42:27,203 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I1\"\\r\\n'\n", - "2026-03-30 11:42:27,207 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I1\"\\r\\n'\n", - "2026-03-30 11:42:27,211 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I2\"\\r\\n'\n", - "2026-03-30 11:42:27,212 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I2\"\\r\\n'\n", - "2026-03-30 11:42:27,219 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I3\"\\r\\n'\n", - "2026-03-30 11:42:27,220 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I3\"\\r\\n'\n", - "2026-03-30 11:42:27,235 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I4\"\\r\\n'\n", - "2026-03-30 11:42:27,237 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I4\"\\r\\n'\n", - "2026-03-30 11:42:27,251 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I5\"\\r\\n'\n", - "2026-03-30 11:42:27,253 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I5\"\\r\\n'\n", - "2026-03-30 11:42:27,267 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"S\"\\r\\n'\n", - "2026-03-30 11:42:27,268 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"S\"\\r\\n'\n", - "2026-03-30 11:42:27,283 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"SI\"\\r\\n'\n", - "2026-03-30 11:42:27,284 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"SI\"\\r\\n'\n", - "2026-03-30 11:42:27,299 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"SIR\"\\r\\n'\n", - "2026-03-30 11:42:27,300 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"SIR\"\\r\\n'\n", - "2026-03-30 11:42:27,301 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"Z\"\\r\\n'\n", - "2026-03-30 11:42:27,302 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"Z\"\\r\\n'\n", - "2026-03-30 11:42:27,314 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"ZI\"\\r\\n'\n", - "2026-03-30 11:42:27,316 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"ZI\"\\r\\n'\n", - "2026-03-30 11:42:27,331 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"@\"\\r\\n'\n", - "2026-03-30 11:42:27,332 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"@\"\\r\\n'\n", - "2026-03-30 11:42:27,350 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"SR\"\\r\\n'\n", - "2026-03-30 11:42:27,352 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"SR\"\\r\\n'\n", - "2026-03-30 11:42:27,363 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"T\"\\r\\n'\n", - "2026-03-30 11:42:27,364 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"T\"\\r\\n'\n", - "2026-03-30 11:42:27,365 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"TA\"\\r\\n'\n", - "2026-03-30 11:42:27,368 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"TA\"\\r\\n'\n", - "2026-03-30 11:42:27,380 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"TAC\"\\r\\n'\n", - "2026-03-30 11:42:27,384 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"TAC\"\\r\\n'\n", - "2026-03-30 11:42:27,395 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"TI\"\\r\\n'\n", - "2026-03-30 11:42:27,396 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"TI\"\\r\\n'\n", - "2026-03-30 11:42:27,410 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C0\"\\r\\n'\n", - "2026-03-30 11:42:27,412 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"C0\"\\r\\n'\n", - "2026-03-30 11:42:27,428 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C1\"\\r\\n'\n", - "2026-03-30 11:42:27,429 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"C1\"\\r\\n'\n", - "2026-03-30 11:42:27,443 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C2\"\\r\\n'\n", - "2026-03-30 11:42:27,447 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"C2\"\\r\\n'\n", - "2026-03-30 11:42:27,459 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C3\"\\r\\n'\n", - "2026-03-30 11:42:27,461 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"C3\"\\r\\n'\n", - "2026-03-30 11:42:27,474 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"COM\"\\r\\n'\n", - "2026-03-30 11:42:27,476 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"COM\"\\r\\n'\n", - "2026-03-30 11:42:27,481 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"DAT\"\\r\\n'\n", - "2026-03-30 11:42:27,482 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"DAT\"\\r\\n'\n", - "2026-03-30 11:42:27,491 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I10\"\\r\\n'\n", - "2026-03-30 11:42:27,492 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I10\"\\r\\n'\n", - "2026-03-30 11:42:27,506 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I11\"\\r\\n'\n", - "2026-03-30 11:42:27,507 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I11\"\\r\\n'\n", - "2026-03-30 11:42:27,523 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I14\"\\r\\n'\n", - "2026-03-30 11:42:27,523 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I14\"\\r\\n'\n", - "2026-03-30 11:42:27,538 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I15\"\\r\\n'\n", - "2026-03-30 11:42:27,539 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I15\"\\r\\n'\n", - "2026-03-30 11:42:27,554 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I16\"\\r\\n'\n", - "2026-03-30 11:42:27,555 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I16\"\\r\\n'\n", - "2026-03-30 11:42:27,571 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I21\"\\r\\n'\n", - "2026-03-30 11:42:27,571 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I21\"\\r\\n'\n", - "2026-03-30 11:42:27,586 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I22\"\\r\\n'\n", - "2026-03-30 11:42:27,587 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I22\"\\r\\n'\n", - "2026-03-30 11:42:27,602 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I23\"\\r\\n'\n", - "2026-03-30 11:42:27,603 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I23\"\\r\\n'\n", - "2026-03-30 11:42:27,618 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I24\"\\r\\n'\n", - "2026-03-30 11:42:27,619 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I24\"\\r\\n'\n", - "2026-03-30 11:42:27,634 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I25\"\\r\\n'\n", - "2026-03-30 11:42:27,634 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I25\"\\r\\n'\n", - "2026-03-30 11:42:27,650 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I26\"\\r\\n'\n", - "2026-03-30 11:42:27,651 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I26\"\\r\\n'\n", - "2026-03-30 11:42:27,652 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M01\"\\r\\n'\n", - "2026-03-30 11:42:27,652 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M01\"\\r\\n'\n", - "2026-03-30 11:42:27,666 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M02\"\\r\\n'\n", - "2026-03-30 11:42:27,667 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M02\"\\r\\n'\n", - "2026-03-30 11:42:27,682 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M03\"\\r\\n'\n", - "2026-03-30 11:42:27,683 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M03\"\\r\\n'\n", - "2026-03-30 11:42:27,698 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M17\"\\r\\n'\n", - "2026-03-30 11:42:27,699 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M17\"\\r\\n'\n", - "2026-03-30 11:42:27,714 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M18\"\\r\\n'\n", - "2026-03-30 11:42:27,715 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M18\"\\r\\n'\n", - "2026-03-30 11:42:27,730 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M19\"\\r\\n'\n", - "2026-03-30 11:42:27,730 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M19\"\\r\\n'\n", - "2026-03-30 11:42:27,746 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M20\"\\r\\n'\n", - "2026-03-30 11:42:27,747 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M20\"\\r\\n'\n", - "2026-03-30 11:42:27,762 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M21\"\\r\\n'\n", - "2026-03-30 11:42:27,763 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M21\"\\r\\n'\n", - "2026-03-30 11:42:27,778 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M27\"\\r\\n'\n", - "2026-03-30 11:42:27,778 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M27\"\\r\\n'\n", - "2026-03-30 11:42:27,794 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M28\"\\r\\n'\n", - "2026-03-30 11:42:27,795 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M28\"\\r\\n'\n", - "2026-03-30 11:42:27,810 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M29\"\\r\\n'\n", - "2026-03-30 11:42:27,812 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M29\"\\r\\n'\n", - "2026-03-30 11:42:27,813 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M31\"\\r\\n'\n", - "2026-03-30 11:42:27,813 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M31\"\\r\\n'\n", - "2026-03-30 11:42:27,826 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M32\"\\r\\n'\n", - "2026-03-30 11:42:27,827 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M32\"\\r\\n'\n", - "2026-03-30 11:42:27,843 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M33\"\\r\\n'\n", - "2026-03-30 11:42:27,844 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M33\"\\r\\n'\n", - "2026-03-30 11:42:27,857 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M35\"\\r\\n'\n", - "2026-03-30 11:42:27,858 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M35\"\\r\\n'\n", - "2026-03-30 11:42:27,874 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"SIS\"\\r\\n'\n", - "2026-03-30 11:42:27,875 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"SIS\"\\r\\n'\n", - "2026-03-30 11:42:27,890 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"SNR\"\\r\\n'\n", - "2026-03-30 11:42:27,891 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"SNR\"\\r\\n'\n", - "2026-03-30 11:42:27,906 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TIM\"\\r\\n'\n", - "2026-03-30 11:42:27,908 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TIM\"\\r\\n'\n", - "2026-03-30 11:42:27,922 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST0\"\\r\\n'\n", - "2026-03-30 11:42:27,923 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TST0\"\\r\\n'\n", - "2026-03-30 11:42:27,938 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST1\"\\r\\n'\n", - "2026-03-30 11:42:27,939 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TST1\"\\r\\n'\n", - "2026-03-30 11:42:27,953 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST2\"\\r\\n'\n", - "2026-03-30 11:42:27,954 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TST2\"\\r\\n'\n", - "2026-03-30 11:42:27,970 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST3\"\\r\\n'\n", - "2026-03-30 11:42:27,971 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TST3\"\\r\\n'\n", - "2026-03-30 11:42:27,985 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"UPD\"\\r\\n'\n", - "2026-03-30 11:42:27,986 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"UPD\"\\r\\n'\n", - "2026-03-30 11:42:28,002 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"FCUT\"\\r\\n'\n", - "2026-03-30 11:42:28,002 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 3 \"FCUT\"\\r\\n'\n", - "2026-03-30 11:42:28,018 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"FSET\"\\r\\n'\n", - "2026-03-30 11:42:28,020 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 3 \"FSET\"\\r\\n'\n", - "2026-03-30 11:42:28,033 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"LST\"\\r\\n'\n", - "2026-03-30 11:42:28,034 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 3 \"LST\"\\r\\n'\n", - "2026-03-30 11:42:28,050 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"RDB\"\\r\\n'\n", - "2026-03-30 11:42:28,052 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 3 \"RDB\"\\r\\n'\n", - "2026-03-30 11:42:28,066 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 A 3 \"USTB\"\\r\\n'\n", - "2026-03-30 11:42:28,067 - pylabrobot - IO - [MT Scale] Received response: b'I0 A 3 \"USTB\"\\r\\n'\n" + "2026-03-30 11:58:04,736 - pylabrobot - IO - [MT Scale] Sent command: I0\n", + "2026-03-30 11:58:04,740 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I0\\r\\n'\n", + "2026-03-30 11:58:04,772 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I0\"\\r\\n'\n", + "2026-03-30 11:58:04,773 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I0\"\\r\\n'\n", + "2026-03-30 11:58:04,786 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I1\"\\r\\n'\n", + "2026-03-30 11:58:04,792 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I1\"\\r\\n'\n", + "2026-03-30 11:58:04,803 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I2\"\\r\\n'\n", + "2026-03-30 11:58:04,804 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I2\"\\r\\n'\n", + "2026-03-30 11:58:04,806 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I3\"\\r\\n'\n", + "2026-03-30 11:58:04,808 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I3\"\\r\\n'\n", + "2026-03-30 11:58:04,818 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I4\"\\r\\n'\n", + "2026-03-30 11:58:04,820 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I4\"\\r\\n'\n", + "2026-03-30 11:58:04,837 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I5\"\\r\\n'\n", + "2026-03-30 11:58:04,838 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I5\"\\r\\n'\n", + "2026-03-30 11:58:04,851 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"S\"\\r\\n'\n", + "2026-03-30 11:58:04,855 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"S\"\\r\\n'\n", + "2026-03-30 11:58:04,867 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"SI\"\\r\\n'\n", + "2026-03-30 11:58:04,868 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"SI\"\\r\\n'\n", + "2026-03-30 11:58:04,883 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"SIR\"\\r\\n'\n", + "2026-03-30 11:58:04,884 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"SIR\"\\r\\n'\n", + "2026-03-30 11:58:04,898 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"Z\"\\r\\n'\n", + "2026-03-30 11:58:04,899 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"Z\"\\r\\n'\n", + "2026-03-30 11:58:04,903 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"ZI\"\\r\\n'\n", + "2026-03-30 11:58:04,905 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"ZI\"\\r\\n'\n", + "2026-03-30 11:58:04,915 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"@\"\\r\\n'\n", + "2026-03-30 11:58:04,918 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"@\"\\r\\n'\n", + "2026-03-30 11:58:04,930 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"SR\"\\r\\n'\n", + "2026-03-30 11:58:04,932 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"SR\"\\r\\n'\n", + "2026-03-30 11:58:04,946 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"T\"\\r\\n'\n", + "2026-03-30 11:58:04,947 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"T\"\\r\\n'\n", + "2026-03-30 11:58:04,963 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"TA\"\\r\\n'\n", + "2026-03-30 11:58:04,964 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"TA\"\\r\\n'\n", + "2026-03-30 11:58:04,978 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"TAC\"\\r\\n'\n", + "2026-03-30 11:58:04,982 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"TAC\"\\r\\n'\n", + "2026-03-30 11:58:04,984 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"TI\"\\r\\n'\n", + "2026-03-30 11:58:04,986 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"TI\"\\r\\n'\n", + "2026-03-30 11:58:04,994 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C0\"\\r\\n'\n", + "2026-03-30 11:58:04,995 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"C0\"\\r\\n'\n", + "2026-03-30 11:58:05,010 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C1\"\\r\\n'\n", + "2026-03-30 11:58:05,011 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"C1\"\\r\\n'\n", + "2026-03-30 11:58:05,028 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C2\"\\r\\n'\n", + "2026-03-30 11:58:05,029 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"C2\"\\r\\n'\n", + "2026-03-30 11:58:05,043 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C3\"\\r\\n'\n", + "2026-03-30 11:58:05,044 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"C3\"\\r\\n'\n", + "2026-03-30 11:58:05,058 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"COM\"\\r\\n'\n", + "2026-03-30 11:58:05,059 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"COM\"\\r\\n'\n", + "2026-03-30 11:58:05,076 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"DAT\"\\r\\n'\n", + "2026-03-30 11:58:05,078 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"DAT\"\\r\\n'\n", + "2026-03-30 11:58:05,091 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I10\"\\r\\n'\n", + "2026-03-30 11:58:05,092 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I10\"\\r\\n'\n", + "2026-03-30 11:58:05,096 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I11\"\\r\\n'\n", + "2026-03-30 11:58:05,097 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I11\"\\r\\n'\n", + "2026-03-30 11:58:05,106 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I14\"\\r\\n'\n", + "2026-03-30 11:58:05,107 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I14\"\\r\\n'\n", + "2026-03-30 11:58:05,122 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I15\"\\r\\n'\n", + "2026-03-30 11:58:05,124 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I15\"\\r\\n'\n", + "2026-03-30 11:58:05,138 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I16\"\\r\\n'\n", + "2026-03-30 11:58:05,139 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I16\"\\r\\n'\n", + "2026-03-30 11:58:05,159 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I21\"\\r\\n'\n", + "2026-03-30 11:58:05,163 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I21\"\\r\\n'\n", + "2026-03-30 11:58:05,171 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I22\"\\r\\n'\n", + "2026-03-30 11:58:05,173 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I22\"\\r\\n'\n", + "2026-03-30 11:58:05,190 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I23\"\\r\\n'\n", + "2026-03-30 11:58:05,192 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I23\"\\r\\n'\n", + "2026-03-30 11:58:05,210 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I24\"\\r\\n'\n", + "2026-03-30 11:58:05,211 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I24\"\\r\\n'\n", + "2026-03-30 11:58:05,218 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I25\"\\r\\n'\n", + "2026-03-30 11:58:05,221 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I25\"\\r\\n'\n", + "2026-03-30 11:58:05,234 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I26\"\\r\\n'\n", + "2026-03-30 11:58:05,238 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I26\"\\r\\n'\n", + "2026-03-30 11:58:05,250 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M01\"\\r\\n'\n", + "2026-03-30 11:58:05,251 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M01\"\\r\\n'\n", + "2026-03-30 11:58:05,270 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M02\"\\r\\n'\n", + "2026-03-30 11:58:05,271 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M02\"\\r\\n'\n", + "2026-03-30 11:58:05,276 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M03\"\\r\\n'\n", + "2026-03-30 11:58:05,277 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M03\"\\r\\n'\n", + "2026-03-30 11:58:05,282 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M17\"\\r\\n'\n", + "2026-03-30 11:58:05,285 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M17\"\\r\\n'\n", + "2026-03-30 11:58:05,298 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M18\"\\r\\n'\n", + "2026-03-30 11:58:05,299 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M18\"\\r\\n'\n", + "2026-03-30 11:58:05,314 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M19\"\\r\\n'\n", + "2026-03-30 11:58:05,316 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M19\"\\r\\n'\n", + "2026-03-30 11:58:05,330 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M20\"\\r\\n'\n", + "2026-03-30 11:58:05,331 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M20\"\\r\\n'\n", + "2026-03-30 11:58:05,347 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M21\"\\r\\n'\n", + "2026-03-30 11:58:05,348 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M21\"\\r\\n'\n", + "2026-03-30 11:58:05,362 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M27\"\\r\\n'\n", + "2026-03-30 11:58:05,363 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M27\"\\r\\n'\n", + "2026-03-30 11:58:05,380 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M28\"\\r\\n'\n", + "2026-03-30 11:58:05,382 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M28\"\\r\\n'\n", + "2026-03-30 11:58:05,399 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M29\"\\r\\n'\n", + "2026-03-30 11:58:05,401 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M29\"\\r\\n'\n", + "2026-03-30 11:58:05,410 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M31\"\\r\\n'\n", + "2026-03-30 11:58:05,412 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M31\"\\r\\n'\n", + "2026-03-30 11:58:05,426 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M32\"\\r\\n'\n", + "2026-03-30 11:58:05,427 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M32\"\\r\\n'\n", + "2026-03-30 11:58:05,429 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M33\"\\r\\n'\n", + "2026-03-30 11:58:05,430 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M33\"\\r\\n'\n", + "2026-03-30 11:58:05,442 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M35\"\\r\\n'\n", + "2026-03-30 11:58:05,443 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M35\"\\r\\n'\n", + "2026-03-30 11:58:05,458 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"SIS\"\\r\\n'\n", + "2026-03-30 11:58:05,459 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"SIS\"\\r\\n'\n", + "2026-03-30 11:58:05,474 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"SNR\"\\r\\n'\n", + "2026-03-30 11:58:05,475 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"SNR\"\\r\\n'\n", + "2026-03-30 11:58:05,490 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TIM\"\\r\\n'\n", + "2026-03-30 11:58:05,491 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TIM\"\\r\\n'\n", + "2026-03-30 11:58:05,506 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST0\"\\r\\n'\n", + "2026-03-30 11:58:05,512 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TST0\"\\r\\n'\n", + "2026-03-30 11:58:05,521 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST1\"\\r\\n'\n", + "2026-03-30 11:58:05,522 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TST1\"\\r\\n'\n", + "2026-03-30 11:58:05,538 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST2\"\\r\\n'\n", + "2026-03-30 11:58:05,539 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TST2\"\\r\\n'\n", + "2026-03-30 11:58:05,553 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST3\"\\r\\n'\n", + "2026-03-30 11:58:05,556 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TST3\"\\r\\n'\n", + "2026-03-30 11:58:05,569 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"UPD\"\\r\\n'\n", + "2026-03-30 11:58:05,570 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"UPD\"\\r\\n'\n", + "2026-03-30 11:58:05,588 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"FCUT\"\\r\\n'\n", + "2026-03-30 11:58:05,589 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 3 \"FCUT\"\\r\\n'\n", + "2026-03-30 11:58:05,601 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"FSET\"\\r\\n'\n", + "2026-03-30 11:58:05,602 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 3 \"FSET\"\\r\\n'\n", + "2026-03-30 11:58:05,621 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"LST\"\\r\\n'\n", + "2026-03-30 11:58:05,622 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 3 \"LST\"\\r\\n'\n", + "2026-03-30 11:58:05,634 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"RDB\"\\r\\n'\n", + "2026-03-30 11:58:05,635 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 3 \"RDB\"\\r\\n'\n", + "2026-03-30 11:58:05,649 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 A 3 \"USTB\"\\r\\n'\n", + "2026-03-30 11:58:05,650 - pylabrobot - IO - [MT Scale] Received response: b'I0 A 3 \"USTB\"\\r\\n'\n" ] }, { @@ -394,11 +532,11 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 11:42:28,079 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] reset_input_buffer\n", - "2026-03-30 11:42:28,080 - pylabrobot - IO - [MT Scale] Sent command: @\n", - "2026-03-30 11:42:28,083 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'@\\r\\n'\n", - "2026-03-30 11:42:28,130 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I4 A \"B207696838\"\\r\\n'\n", - "2026-03-30 11:42:28,131 - pylabrobot - IO - [MT Scale] Received response: b'I4 A \"B207696838\"\\r\\n'\n" + "2026-03-30 11:58:05,659 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] reset_input_buffer\n", + "2026-03-30 11:58:05,661 - pylabrobot - IO - [MT Scale] Sent command: @\n", + "2026-03-30 11:58:05,663 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'@\\r\\n'\n", + "2026-03-30 11:58:05,714 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I4 A \"B207696838\"\\r\\n'\n", + "2026-03-30 11:58:05,715 - pylabrobot - IO - [MT Scale] Received response: b'I4 A \"B207696838\"\\r\\n'\n" ] }, { @@ -433,10 +571,10 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 11:42:28,143 - pylabrobot - IO - [MT Scale] Sent command: I4\n", - "2026-03-30 11:42:28,147 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I4\\r\\n'\n", - "2026-03-30 11:42:28,180 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I4 A \"B207696838\"\\r\\n'\n", - "2026-03-30 11:42:28,183 - pylabrobot - IO - [MT Scale] Received response: b'I4 A \"B207696838\"\\r\\n'\n" + "2026-03-30 11:58:05,730 - pylabrobot - IO - [MT Scale] Sent command: I4\n", + "2026-03-30 11:58:05,735 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I4\\r\\n'\n", + "2026-03-30 11:58:05,777 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I4 A \"B207696838\"\\r\\n'\n", + "2026-03-30 11:58:05,779 - pylabrobot - IO - [MT Scale] Received response: b'I4 A \"B207696838\"\\r\\n'\n" ] }, { @@ -471,14 +609,14 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 11:42:28,190 - pylabrobot - IO - [MT Scale] Sent command: I2\n", - "2026-03-30 11:42:28,195 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I2\\r\\n'\n", - "2026-03-30 11:42:28,257 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", - "2026-03-30 11:42:28,257 - pylabrobot - IO - [MT Scale] Received response: b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", - "2026-03-30 11:42:28,258 - pylabrobot - IO - [MT Scale] Sent command: I2\n", - "2026-03-30 11:42:28,260 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I2\\r\\n'\n", - "2026-03-30 11:42:28,321 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", - "2026-03-30 11:42:28,322 - pylabrobot - IO - [MT Scale] Received response: b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n" + "2026-03-30 11:58:05,798 - pylabrobot - IO - [MT Scale] Sent command: I2\n", + "2026-03-30 11:58:05,806 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I2\\r\\n'\n", + "2026-03-30 11:58:05,873 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", + "2026-03-30 11:58:05,874 - pylabrobot - IO - [MT Scale] Received response: b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", + "2026-03-30 11:58:05,878 - pylabrobot - IO - [MT Scale] Sent command: I2\n", + "2026-03-30 11:58:05,881 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I2\\r\\n'\n", + "2026-03-30 11:58:05,938 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", + "2026-03-30 11:58:05,938 - pylabrobot - IO - [MT Scale] Received response: b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n" ] }, { @@ -510,9 +648,29 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 8, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2026-03-30 11:58:05,945 - pylabrobot - IO - [MT Scale] Sent command: I1\n", + "2026-03-30 11:58:05,947 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I1\\r\\n'\n", + "2026-03-30 11:58:06,001 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I1 A \"01\" \"2.30\" \"2.22\" \"\" \"\"\\r\\n'\n", + "2026-03-30 11:58:06,002 - pylabrobot - IO - [MT Scale] Received response: b'I1 A \"01\" \"2.30\" \"2.22\" \"\" \"\"\\r\\n'\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "I1 reported levels: ['01', '2.30', '2.22', '', '']\n", + "I0 discovered 62 commands\n", + "Note: I1 may underreport - I0 is the authoritative source\n" + ] + } + ], "source": [ "# I1 reports standardized level sets (may not reflect all available commands)\n", "# I0 is the definitive source (already queried during setup)\n", @@ -538,17 +696,17 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 11:42:28,394 - pylabrobot - IO - [MT Scale] Sent command: S\n", - "2026-03-30 11:42:28,399 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", - "2026-03-30 11:42:28,627 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S -0.00009 g\\r\\n'\n", - "2026-03-30 11:42:28,628 - pylabrobot - IO - [MT Scale] Received response: b'S S -0.00009 g\\r\\n'\n" + "2026-03-30 11:58:06,016 - pylabrobot - IO - [MT Scale] Sent command: S\n", + "2026-03-30 11:58:06,020 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", + "2026-03-30 11:58:06,226 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00003 g\\r\\n'\n", + "2026-03-30 11:58:06,226 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00003 g\\r\\n'\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ - "Stable weight (empty pan): -9e-05 g\n", + "Stable weight (empty pan): 3e-05 g\n", "PASS: stable weight returns float\n" ] } @@ -576,17 +734,17 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 11:42:28,636 - pylabrobot - IO - [MT Scale] Sent command: SI\n", - "2026-03-30 11:42:28,643 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", - "2026-03-30 11:42:28,674 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S -0.00009 g\\r\\n'\n", - "2026-03-30 11:42:28,680 - pylabrobot - IO - [MT Scale] Received response: b'S S -0.00009 g\\r\\n'\n" + "2026-03-30 11:58:06,232 - pylabrobot - IO - [MT Scale] Sent command: SI\n", + "2026-03-30 11:58:06,233 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", + "2026-03-30 11:58:06,275 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00003 g\\r\\n'\n", + "2026-03-30 11:58:06,276 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00003 g\\r\\n'\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ - "Immediate weight: -9e-05 g\n", + "Immediate weight: 3e-05 g\n", "PASS: immediate weight returns float\n" ] } @@ -614,14 +772,14 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 11:42:28,694 - pylabrobot - IO - [MT Scale] Sent command: Z\n", - "2026-03-30 11:42:28,697 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'Z\\r\\n'\n", - "2026-03-30 11:42:29,009 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'Z A\\r\\n'\n", - "2026-03-30 11:42:29,010 - pylabrobot - IO - [MT Scale] Received response: b'Z A\\r\\n'\n", - "2026-03-30 11:42:29,011 - pylabrobot - IO - [MT Scale] Sent command: SI\n", - "2026-03-30 11:42:29,012 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", - "2026-03-30 11:42:29,041 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 11:42:29,042 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n" + "2026-03-30 11:58:06,281 - pylabrobot - IO - [MT Scale] Sent command: Z\n", + "2026-03-30 11:58:06,284 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'Z\\r\\n'\n", + "2026-03-30 11:58:06,513 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'Z A\\r\\n'\n", + "2026-03-30 11:58:06,514 - pylabrobot - IO - [MT Scale] Received response: b'Z A\\r\\n'\n", + "2026-03-30 11:58:06,516 - pylabrobot - IO - [MT Scale] Sent command: SI\n", + "2026-03-30 11:58:06,519 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", + "2026-03-30 11:58:06,561 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 11:58:06,562 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n" ] }, { @@ -657,14 +815,14 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 11:42:29,048 - pylabrobot - IO - [MT Scale] Sent command: ZI\n", - "2026-03-30 11:42:29,051 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'ZI\\r\\n'\n", - "2026-03-30 11:42:29,073 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'ZI S\\r\\n'\n", - "2026-03-30 11:42:29,074 - pylabrobot - IO - [MT Scale] Received response: b'ZI S\\r\\n'\n", - "2026-03-30 11:42:29,075 - pylabrobot - IO - [MT Scale] Sent command: SI\n", - "2026-03-30 11:42:29,077 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", - "2026-03-30 11:42:29,106 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 11:42:29,106 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n" + "2026-03-30 11:58:06,571 - pylabrobot - IO - [MT Scale] Sent command: ZI\n", + "2026-03-30 11:58:06,578 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'ZI\\r\\n'\n", + "2026-03-30 11:58:06,610 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'ZI S\\r\\n'\n", + "2026-03-30 11:58:06,611 - pylabrobot - IO - [MT Scale] Received response: b'ZI S\\r\\n'\n", + "2026-03-30 11:58:06,612 - pylabrobot - IO - [MT Scale] Sent command: SI\n", + "2026-03-30 11:58:06,615 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", + "2026-03-30 11:58:06,657 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 11:58:06,661 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n" ] }, { @@ -717,18 +875,18 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 11:43:16,169 - pylabrobot - IO - [MT Scale] Sent command: Z\n", - "2026-03-30 11:43:16,174 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'Z\\r\\n'\n", - "2026-03-30 11:43:16,584 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'Z A\\r\\n'\n", - "2026-03-30 11:43:16,585 - pylabrobot - IO - [MT Scale] Received response: b'Z A\\r\\n'\n", - "2026-03-30 11:43:16,586 - pylabrobot - IO - [MT Scale] Sent command: T\n", - "2026-03-30 11:43:16,587 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'T\\r\\n'\n", - "2026-03-30 11:43:17,000 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'T S 0.00000 g\\r\\n'\n", - "2026-03-30 11:43:17,001 - pylabrobot - IO - [MT Scale] Received response: b'T S 0.00000 g\\r\\n'\n", - "2026-03-30 11:43:17,001 - pylabrobot - IO - [MT Scale] Sent command: TA\n", - "2026-03-30 11:43:17,002 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'TA\\r\\n'\n", - "2026-03-30 11:43:17,098 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'TA A 0.00000 g\\r\\n'\n", - "2026-03-30 11:43:17,105 - pylabrobot - IO - [MT Scale] Received response: b'TA A 0.00000 g\\r\\n'\n" + "2026-03-30 11:58:15,260 - pylabrobot - IO - [MT Scale] Sent command: Z\n", + "2026-03-30 11:58:15,262 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'Z\\r\\n'\n", + "2026-03-30 11:58:15,561 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'Z A\\r\\n'\n", + "2026-03-30 11:58:15,562 - pylabrobot - IO - [MT Scale] Received response: b'Z A\\r\\n'\n", + "2026-03-30 11:58:15,564 - pylabrobot - IO - [MT Scale] Sent command: T\n", + "2026-03-30 11:58:15,569 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'T\\r\\n'\n", + "2026-03-30 11:58:15,976 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'T S 0.00000 g\\r\\n'\n", + "2026-03-30 11:58:15,977 - pylabrobot - IO - [MT Scale] Received response: b'T S 0.00000 g\\r\\n'\n", + "2026-03-30 11:58:15,979 - pylabrobot - IO - [MT Scale] Sent command: TA\n", + "2026-03-30 11:58:15,981 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'TA\\r\\n'\n", + "2026-03-30 11:58:16,056 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'TA A 0.00000 g\\r\\n'\n", + "2026-03-30 11:58:16,058 - pylabrobot - IO - [MT Scale] Received response: b'TA A 0.00000 g\\r\\n'\n" ] }, { @@ -776,10 +934,10 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 11:43:21,054 - pylabrobot - IO - [MT Scale] Sent command: TA\n", - "2026-03-30 11:43:21,059 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'TA\\r\\n'\n", - "2026-03-30 11:43:21,126 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'TA A 0.00000 g\\r\\n'\n", - "2026-03-30 11:43:21,127 - pylabrobot - IO - [MT Scale] Received response: b'TA A 0.00000 g\\r\\n'\n" + "2026-03-30 11:58:19,372 - pylabrobot - IO - [MT Scale] Sent command: TA\n", + "2026-03-30 11:58:19,377 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'TA\\r\\n'\n", + "2026-03-30 11:58:19,494 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'TA A 0.00000 g\\r\\n'\n", + "2026-03-30 11:58:19,505 - pylabrobot - IO - [MT Scale] Received response: b'TA A 0.00000 g\\r\\n'\n" ] }, { @@ -814,14 +972,14 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 11:43:22,224 - pylabrobot - IO - [MT Scale] Sent command: TAC\n", - "2026-03-30 11:43:22,227 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'TAC\\r\\n'\n", - "2026-03-30 11:43:22,259 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'TAC A\\r\\n'\n", - "2026-03-30 11:43:22,262 - pylabrobot - IO - [MT Scale] Received response: b'TAC A\\r\\n'\n", - "2026-03-30 11:43:22,265 - pylabrobot - IO - [MT Scale] Sent command: TA\n", - "2026-03-30 11:43:22,267 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'TA\\r\\n'\n", - "2026-03-30 11:43:22,403 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'TA A 0.00000 g\\r\\n'\n", - "2026-03-30 11:43:22,404 - pylabrobot - IO - [MT Scale] Received response: b'TA A 0.00000 g\\r\\n'\n" + "2026-03-30 11:58:20,342 - pylabrobot - IO - [MT Scale] Sent command: TAC\n", + "2026-03-30 11:58:20,346 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'TAC\\r\\n'\n", + "2026-03-30 11:58:20,372 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'TAC A\\r\\n'\n", + "2026-03-30 11:58:20,373 - pylabrobot - IO - [MT Scale] Received response: b'TAC A\\r\\n'\n", + "2026-03-30 11:58:20,375 - pylabrobot - IO - [MT Scale] Sent command: TA\n", + "2026-03-30 11:58:20,379 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'TA\\r\\n'\n", + "2026-03-30 11:58:20,485 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'TA A 0.00000 g\\r\\n'\n", + "2026-03-30 11:58:20,486 - pylabrobot - IO - [MT Scale] Received response: b'TA A 0.00000 g\\r\\n'\n" ] }, { @@ -857,10 +1015,10 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 11:43:23,301 - pylabrobot - IO - [MT Scale] Sent command: SC 3000\n", - "2026-03-30 11:43:23,305 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SC 3000\\r\\n'\n", - "2026-03-30 11:43:23,329 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'ES\\r\\n'\n", - "2026-03-30 11:43:23,330 - pylabrobot - IO - [MT Scale] Received response: b'ES\\r\\n'\n" + "2026-03-30 11:58:21,318 - pylabrobot - IO - [MT Scale] Sent command: SC 3000\n", + "2026-03-30 11:58:21,320 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SC 3000\\r\\n'\n", + "2026-03-30 11:58:21,348 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'ES\\r\\n'\n", + "2026-03-30 11:58:21,349 - pylabrobot - IO - [MT Scale] Received response: b'ES\\r\\n'\n" ] }, { @@ -871,9 +1029,9 @@ "\u001b[31m---------------------------------------------------------------------------\u001b[39m", "\u001b[31mMettlerToledoError\u001b[39m Traceback (most recent call last)", "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[16]\u001b[39m\u001b[32m, line 1\u001b[39m\n\u001b[32m----> \u001b[39m\u001b[32m1\u001b[39m weight = \u001b[38;5;28;01mawait\u001b[39;00m backend.read_dynamic_weight(timeout=\u001b[32m3.0\u001b[39m)\n\u001b[32m 2\u001b[39m \u001b[38;5;28mprint\u001b[39m(\u001b[33mf\u001b[39m\u001b[33m\"\u001b[39m\u001b[33mDynamic weight (3s timeout): \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mweight\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m g\u001b[39m\u001b[33m\"\u001b[39m)\n\u001b[32m 3\u001b[39m \u001b[38;5;28;01massert\u001b[39;00m \u001b[38;5;28misinstance\u001b[39m(weight, \u001b[38;5;28mfloat\u001b[39m)\n", - "\u001b[36mFile \u001b[39m\u001b[32m~/Desktop/GitHub/pylabrobot/pylabrobot/scales/mettler_toledo/backend.py:512\u001b[39m, in \u001b[36mMettlerToledoWXS205SDUBackend.read_dynamic_weight\u001b[39m\u001b[34m(self, timeout)\u001b[39m\n\u001b[32m 503\u001b[39m \u001b[38;5;250m\u001b[39m\u001b[33;03m\"\"\"Read a stable weight value from the machine within a given timeout, or\u001b[39;00m\n\u001b[32m 504\u001b[39m \u001b[33;03mreturn the current weight value if not possible. (MEASUREMENT command)\u001b[39;00m\n\u001b[32m 505\u001b[39m \n\u001b[32m 506\u001b[39m \u001b[33;03mArgs:\u001b[39;00m\n\u001b[32m 507\u001b[39m \u001b[33;03m timeout: The timeout in seconds.\u001b[39;00m\n\u001b[32m 508\u001b[39m \u001b[33;03m\"\"\"\u001b[39;00m\n\u001b[32m 510\u001b[39m timeout = \u001b[38;5;28mint\u001b[39m(timeout * \u001b[32m1000\u001b[39m) \u001b[38;5;66;03m# convert to milliseconds\u001b[39;00m\n\u001b[32m--> \u001b[39m\u001b[32m512\u001b[39m responses = \u001b[38;5;28;01mawait\u001b[39;00m \u001b[38;5;28mself\u001b[39m.send_command(\u001b[33mf\u001b[39m\u001b[33m\"\u001b[39m\u001b[33mSC \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mtimeout\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m\"\u001b[39m)\n\u001b[32m 513\u001b[39m \u001b[38;5;28mself\u001b[39m._validate_response(responses[\u001b[32m0\u001b[39m], \u001b[32m4\u001b[39m, \u001b[33m\"\u001b[39m\u001b[33mSC\u001b[39m\u001b[33m\"\u001b[39m)\n\u001b[32m 514\u001b[39m \u001b[38;5;28mself\u001b[39m._validate_unit(responses[\u001b[32m0\u001b[39m].data[\u001b[32m1\u001b[39m], \u001b[33m\"\u001b[39m\u001b[33mSC\u001b[39m\u001b[33m\"\u001b[39m)\n", - "\u001b[36mFile \u001b[39m\u001b[32m~/Desktop/GitHub/pylabrobot/pylabrobot/scales/mettler_toledo/backend.py:286\u001b[39m, in \u001b[36mMettlerToledoWXS205SDUBackend.send_command\u001b[39m\u001b[34m(self, command, timeout)\u001b[39m\n\u001b[32m 284\u001b[39m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[32m 285\u001b[39m response = MettlerToledoResponse(command=\u001b[33m\"\u001b[39m\u001b[33m\"\u001b[39m, status=\u001b[33m\"\u001b[39m\u001b[33m\"\u001b[39m, data=[])\n\u001b[32m--> \u001b[39m\u001b[32m286\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[43m.\u001b[49m\u001b[43m_parse_basic_errors\u001b[49m\u001b[43m(\u001b[49m\u001b[43mresponse\u001b[49m\u001b[43m)\u001b[49m\n\u001b[32m 287\u001b[39m responses.append(response)\n\u001b[32m 289\u001b[39m \u001b[38;5;66;03m# Status B means more responses follow; anything else (A, etc.) is final\u001b[39;00m\n", - "\u001b[36mFile \u001b[39m\u001b[32m~/Desktop/GitHub/pylabrobot/pylabrobot/scales/mettler_toledo/backend.py:207\u001b[39m, in \u001b[36mMettlerToledoWXS205SDUBackend._parse_basic_errors\u001b[39m\u001b[34m(self, response)\u001b[39m\n\u001b[32m 205\u001b[39m \u001b[38;5;66;03m# General error messages: ES, ET, EL (status is \"\" for these)\u001b[39;00m\n\u001b[32m 206\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m response.command == \u001b[33m\"\u001b[39m\u001b[33mES\u001b[39m\u001b[33m\"\u001b[39m:\n\u001b[32m--> \u001b[39m\u001b[32m207\u001b[39m \u001b[38;5;28;01mraise\u001b[39;00m MettlerToledoError.syntax_error()\n\u001b[32m 208\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m response.command == \u001b[33m\"\u001b[39m\u001b[33mET\u001b[39m\u001b[33m\"\u001b[39m:\n\u001b[32m 209\u001b[39m \u001b[38;5;28;01mraise\u001b[39;00m MettlerToledoError.transmission_error()\n", + "\u001b[36mFile \u001b[39m\u001b[32m~/Desktop/GitHub/pylabrobot/pylabrobot/scales/mettler_toledo/backend.py:513\u001b[39m, in \u001b[36mMettlerToledoWXS205SDUBackend.read_dynamic_weight\u001b[39m\u001b[34m(self, timeout)\u001b[39m\n\u001b[32m 504\u001b[39m \u001b[38;5;250m\u001b[39m\u001b[33;03m\"\"\"Read a stable weight value from the machine within a given timeout, or\u001b[39;00m\n\u001b[32m 505\u001b[39m \u001b[33;03mreturn the current weight value if not possible. (MEASUREMENT command)\u001b[39;00m\n\u001b[32m 506\u001b[39m \n\u001b[32m 507\u001b[39m \u001b[33;03mArgs:\u001b[39;00m\n\u001b[32m 508\u001b[39m \u001b[33;03m timeout: The timeout in seconds.\u001b[39;00m\n\u001b[32m 509\u001b[39m \u001b[33;03m\"\"\"\u001b[39;00m\n\u001b[32m 511\u001b[39m timeout = \u001b[38;5;28mint\u001b[39m(timeout * \u001b[32m1000\u001b[39m) \u001b[38;5;66;03m# convert to milliseconds\u001b[39;00m\n\u001b[32m--> \u001b[39m\u001b[32m513\u001b[39m responses = \u001b[38;5;28;01mawait\u001b[39;00m \u001b[38;5;28mself\u001b[39m.send_command(\u001b[33mf\u001b[39m\u001b[33m\"\u001b[39m\u001b[33mSC \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mtimeout\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m\"\u001b[39m)\n\u001b[32m 514\u001b[39m \u001b[38;5;28mself\u001b[39m._validate_response(responses[\u001b[32m0\u001b[39m], \u001b[32m4\u001b[39m, \u001b[33m\"\u001b[39m\u001b[33mSC\u001b[39m\u001b[33m\"\u001b[39m)\n\u001b[32m 515\u001b[39m \u001b[38;5;28mself\u001b[39m._validate_unit(responses[\u001b[32m0\u001b[39m].data[\u001b[32m1\u001b[39m], \u001b[33m\"\u001b[39m\u001b[33mSC\u001b[39m\u001b[33m\"\u001b[39m)\n", + "\u001b[36mFile \u001b[39m\u001b[32m~/Desktop/GitHub/pylabrobot/pylabrobot/scales/mettler_toledo/backend.py:287\u001b[39m, in \u001b[36mMettlerToledoWXS205SDUBackend.send_command\u001b[39m\u001b[34m(self, command, timeout)\u001b[39m\n\u001b[32m 285\u001b[39m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[32m 286\u001b[39m response = MettlerToledoResponse(command=\u001b[33m\"\u001b[39m\u001b[33m\"\u001b[39m, status=\u001b[33m\"\u001b[39m\u001b[33m\"\u001b[39m, data=[])\n\u001b[32m--> \u001b[39m\u001b[32m287\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[43m.\u001b[49m\u001b[43m_parse_basic_errors\u001b[49m\u001b[43m(\u001b[49m\u001b[43mresponse\u001b[49m\u001b[43m)\u001b[49m\n\u001b[32m 288\u001b[39m responses.append(response)\n\u001b[32m 290\u001b[39m \u001b[38;5;66;03m# Status B means more responses follow; anything else (A, etc.) is final\u001b[39;00m\n", + "\u001b[36mFile \u001b[39m\u001b[32m~/Desktop/GitHub/pylabrobot/pylabrobot/scales/mettler_toledo/backend.py:208\u001b[39m, in \u001b[36mMettlerToledoWXS205SDUBackend._parse_basic_errors\u001b[39m\u001b[34m(self, response)\u001b[39m\n\u001b[32m 206\u001b[39m \u001b[38;5;66;03m# General error messages: ES, ET, EL (status is \"\" for these)\u001b[39;00m\n\u001b[32m 207\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m response.command == \u001b[33m\"\u001b[39m\u001b[33mES\u001b[39m\u001b[33m\"\u001b[39m:\n\u001b[32m--> \u001b[39m\u001b[32m208\u001b[39m \u001b[38;5;28;01mraise\u001b[39;00m MettlerToledoError.syntax_error()\n\u001b[32m 209\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m response.command == \u001b[33m\"\u001b[39m\u001b[33mET\u001b[39m\u001b[33m\"\u001b[39m:\n\u001b[32m 210\u001b[39m \u001b[38;5;28;01mraise\u001b[39;00m MettlerToledoError.transmission_error()\n", "\u001b[31mMettlerToledoError\u001b[39m: Syntax error: The weigh module/balance has not recognized the received command or the command is not allowed" ] } @@ -901,10 +1059,10 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 11:43:25,106 - pylabrobot - IO - [MT Scale] Sent command: C\n", - "2026-03-30 11:43:25,109 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'C\\r\\n'\n", - "2026-03-30 11:43:25,136 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'ES\\r\\n'\n", - "2026-03-30 11:43:25,138 - pylabrobot - IO - [MT Scale] Received response: b'ES\\r\\n'\n" + "2026-03-30 11:58:22,758 - pylabrobot - IO - [MT Scale] Sent command: C\n", + "2026-03-30 11:58:22,760 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'C\\r\\n'\n", + "2026-03-30 11:58:22,786 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'ES\\r\\n'\n", + "2026-03-30 11:58:22,787 - pylabrobot - IO - [MT Scale] Received response: b'ES\\r\\n'\n" ] }, { @@ -915,9 +1073,9 @@ "\u001b[31m---------------------------------------------------------------------------\u001b[39m", "\u001b[31mMettlerToledoError\u001b[39m Traceback (most recent call last)", "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[17]\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 backend.cancel_all()\n\u001b[32m 2\u001b[39m \u001b[38;5;28mprint\u001b[39m(\u001b[33m\"\u001b[39m\u001b[33mPASS: cancel_all completed without error\u001b[39m\u001b[33m\"\u001b[39m)\n", - "\u001b[36mFile \u001b[39m\u001b[32m~/Desktop/GitHub/pylabrobot/pylabrobot/scales/mettler_toledo/backend.py:324\u001b[39m, in \u001b[36mMettlerToledoWXS205SDUBackend.cancel_all\u001b[39m\u001b[34m(self)\u001b[39m\n\u001b[32m 314\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[34mcancel_all\u001b[39m(\u001b[38;5;28mself\u001b[39m) -> \u001b[38;5;28;01mNone\u001b[39;00m:\n\u001b[32m 315\u001b[39m \u001b[38;5;250m \u001b[39m\u001b[33;03m\"\"\"C - Cancel all active and pending interface commands.\u001b[39;00m\n\u001b[32m 316\u001b[39m \n\u001b[32m 317\u001b[39m \u001b[33;03m Unlike cancel() (@), this does not reset the device - it only cancels\u001b[39;00m\n\u001b[32m (...)\u001b[39m\u001b[32m 322\u001b[39m \u001b[33;03m C A (complete). Both responses are consumed to keep the serial buffer clean.\u001b[39;00m\n\u001b[32m 323\u001b[39m \u001b[33;03m \"\"\"\u001b[39;00m\n\u001b[32m--> \u001b[39m\u001b[32m324\u001b[39m responses = \u001b[38;5;28;01mawait\u001b[39;00m \u001b[38;5;28mself\u001b[39m.send_command(\u001b[33m\"\u001b[39m\u001b[33mC\u001b[39m\u001b[33m\"\u001b[39m)\n\u001b[32m 325\u001b[39m \u001b[38;5;66;03m# send_command reads both C B (started) and C A (complete) automatically\u001b[39;00m\n\u001b[32m 326\u001b[39m \u001b[38;5;28mself\u001b[39m._validate_response(responses[\u001b[32m0\u001b[39m], \u001b[32m2\u001b[39m, \u001b[33m\"\u001b[39m\u001b[33mC\u001b[39m\u001b[33m\"\u001b[39m)\n", - "\u001b[36mFile \u001b[39m\u001b[32m~/Desktop/GitHub/pylabrobot/pylabrobot/scales/mettler_toledo/backend.py:286\u001b[39m, in \u001b[36mMettlerToledoWXS205SDUBackend.send_command\u001b[39m\u001b[34m(self, command, timeout)\u001b[39m\n\u001b[32m 284\u001b[39m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[32m 285\u001b[39m response = MettlerToledoResponse(command=\u001b[33m\"\u001b[39m\u001b[33m\"\u001b[39m, status=\u001b[33m\"\u001b[39m\u001b[33m\"\u001b[39m, data=[])\n\u001b[32m--> \u001b[39m\u001b[32m286\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[43m.\u001b[49m\u001b[43m_parse_basic_errors\u001b[49m\u001b[43m(\u001b[49m\u001b[43mresponse\u001b[49m\u001b[43m)\u001b[49m\n\u001b[32m 287\u001b[39m responses.append(response)\n\u001b[32m 289\u001b[39m \u001b[38;5;66;03m# Status B means more responses follow; anything else (A, etc.) is final\u001b[39;00m\n", - "\u001b[36mFile \u001b[39m\u001b[32m~/Desktop/GitHub/pylabrobot/pylabrobot/scales/mettler_toledo/backend.py:207\u001b[39m, in \u001b[36mMettlerToledoWXS205SDUBackend._parse_basic_errors\u001b[39m\u001b[34m(self, response)\u001b[39m\n\u001b[32m 205\u001b[39m \u001b[38;5;66;03m# General error messages: ES, ET, EL (status is \"\" for these)\u001b[39;00m\n\u001b[32m 206\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m response.command == \u001b[33m\"\u001b[39m\u001b[33mES\u001b[39m\u001b[33m\"\u001b[39m:\n\u001b[32m--> \u001b[39m\u001b[32m207\u001b[39m \u001b[38;5;28;01mraise\u001b[39;00m MettlerToledoError.syntax_error()\n\u001b[32m 208\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m response.command == \u001b[33m\"\u001b[39m\u001b[33mET\u001b[39m\u001b[33m\"\u001b[39m:\n\u001b[32m 209\u001b[39m \u001b[38;5;28;01mraise\u001b[39;00m MettlerToledoError.transmission_error()\n", + "\u001b[36mFile \u001b[39m\u001b[32m~/Desktop/GitHub/pylabrobot/pylabrobot/scales/mettler_toledo/backend.py:325\u001b[39m, in \u001b[36mMettlerToledoWXS205SDUBackend.cancel_all\u001b[39m\u001b[34m(self)\u001b[39m\n\u001b[32m 315\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[34mcancel_all\u001b[39m(\u001b[38;5;28mself\u001b[39m) -> \u001b[38;5;28;01mNone\u001b[39;00m:\n\u001b[32m 316\u001b[39m \u001b[38;5;250m \u001b[39m\u001b[33;03m\"\"\"C - Cancel all active and pending interface commands.\u001b[39;00m\n\u001b[32m 317\u001b[39m \n\u001b[32m 318\u001b[39m \u001b[33;03m Unlike cancel() (@), this does not reset the device - it only cancels\u001b[39;00m\n\u001b[32m (...)\u001b[39m\u001b[32m 323\u001b[39m \u001b[33;03m C A (complete). Both responses are consumed to keep the serial buffer clean.\u001b[39;00m\n\u001b[32m 324\u001b[39m \u001b[33;03m \"\"\"\u001b[39;00m\n\u001b[32m--> \u001b[39m\u001b[32m325\u001b[39m responses = \u001b[38;5;28;01mawait\u001b[39;00m \u001b[38;5;28mself\u001b[39m.send_command(\u001b[33m\"\u001b[39m\u001b[33mC\u001b[39m\u001b[33m\"\u001b[39m)\n\u001b[32m 326\u001b[39m \u001b[38;5;66;03m# send_command reads both C B (started) and C A (complete) automatically\u001b[39;00m\n\u001b[32m 327\u001b[39m \u001b[38;5;28mself\u001b[39m._validate_response(responses[\u001b[32m0\u001b[39m], \u001b[32m2\u001b[39m, \u001b[33m\"\u001b[39m\u001b[33mC\u001b[39m\u001b[33m\"\u001b[39m)\n", + "\u001b[36mFile \u001b[39m\u001b[32m~/Desktop/GitHub/pylabrobot/pylabrobot/scales/mettler_toledo/backend.py:287\u001b[39m, in \u001b[36mMettlerToledoWXS205SDUBackend.send_command\u001b[39m\u001b[34m(self, command, timeout)\u001b[39m\n\u001b[32m 285\u001b[39m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[32m 286\u001b[39m response = MettlerToledoResponse(command=\u001b[33m\"\u001b[39m\u001b[33m\"\u001b[39m, status=\u001b[33m\"\u001b[39m\u001b[33m\"\u001b[39m, data=[])\n\u001b[32m--> \u001b[39m\u001b[32m287\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[43m.\u001b[49m\u001b[43m_parse_basic_errors\u001b[49m\u001b[43m(\u001b[49m\u001b[43mresponse\u001b[49m\u001b[43m)\u001b[49m\n\u001b[32m 288\u001b[39m responses.append(response)\n\u001b[32m 290\u001b[39m \u001b[38;5;66;03m# Status B means more responses follow; anything else (A, etc.) is final\u001b[39;00m\n", + "\u001b[36mFile \u001b[39m\u001b[32m~/Desktop/GitHub/pylabrobot/pylabrobot/scales/mettler_toledo/backend.py:208\u001b[39m, in \u001b[36mMettlerToledoWXS205SDUBackend._parse_basic_errors\u001b[39m\u001b[34m(self, response)\u001b[39m\n\u001b[32m 206\u001b[39m \u001b[38;5;66;03m# General error messages: ES, ET, EL (status is \"\" for these)\u001b[39;00m\n\u001b[32m 207\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m response.command == \u001b[33m\"\u001b[39m\u001b[33mES\u001b[39m\u001b[33m\"\u001b[39m:\n\u001b[32m--> \u001b[39m\u001b[32m208\u001b[39m \u001b[38;5;28;01mraise\u001b[39;00m MettlerToledoError.syntax_error()\n\u001b[32m 209\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m response.command == \u001b[33m\"\u001b[39m\u001b[33mET\u001b[39m\u001b[33m\"\u001b[39m:\n\u001b[32m 210\u001b[39m \u001b[38;5;28;01mraise\u001b[39;00m MettlerToledoError.transmission_error()\n", "\u001b[31mMettlerToledoError\u001b[39m: Syntax error: The weigh module/balance has not recognized the received command or the command is not allowed" ] } @@ -943,10 +1101,10 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 11:43:26,590 - pylabrobot - IO - [MT Scale] Sent command: D \"PLR TEST\"\n", - "2026-03-30 11:43:26,594 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'D \"PLR TEST\"\\r\\n'\n", - "2026-03-30 11:43:26,622 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'ES\\r\\n'\n", - "2026-03-30 11:43:26,624 - pylabrobot - IO - [MT Scale] Received response: b'ES\\r\\n'\n" + "2026-03-30 11:58:28,969 - pylabrobot - IO - [MT Scale] Sent command: D \"PLR TEST\"\n", + "2026-03-30 11:58:28,973 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'D \"PLR TEST\"\\r\\n'\n", + "2026-03-30 11:58:29,004 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'ES\\r\\n'\n", + "2026-03-30 11:58:29,006 - pylabrobot - IO - [MT Scale] Received response: b'ES\\r\\n'\n" ] }, { @@ -957,9 +1115,9 @@ "\u001b[31m---------------------------------------------------------------------------\u001b[39m", "\u001b[31mMettlerToledoError\u001b[39m Traceback (most recent call last)", "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[18]\u001b[39m\u001b[32m, line 3\u001b[39m\n\u001b[32m 1\u001b[39m \u001b[38;5;28;01mimport\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[34;01masyncio\u001b[39;00m\n\u001b[32m----> \u001b[39m\u001b[32m3\u001b[39m \u001b[38;5;28;01mawait\u001b[39;00m backend.set_display_text(\u001b[33m\"\u001b[39m\u001b[33mPLR TEST\u001b[39m\u001b[33m\"\u001b[39m)\n\u001b[32m 4\u001b[39m \u001b[38;5;28;01mawait\u001b[39;00m asyncio.sleep(\u001b[32m2\u001b[39m)\n\u001b[32m 5\u001b[39m \u001b[38;5;28;01mawait\u001b[39;00m backend.set_weight_display()\n", - "\u001b[36mFile \u001b[39m\u001b[32m~/Desktop/GitHub/pylabrobot/pylabrobot/scales/mettler_toledo/backend.py:557\u001b[39m, in \u001b[36mMettlerToledoWXS205SDUBackend.set_display_text\u001b[39m\u001b[34m(self, text)\u001b[39m\n\u001b[32m 554\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[34mset_display_text\u001b[39m(\u001b[38;5;28mself\u001b[39m, text: \u001b[38;5;28mstr\u001b[39m) -> List[MettlerToledoResponse]:\n\u001b[32m 555\u001b[39m \u001b[38;5;250m \u001b[39m\u001b[33;03m\"\"\"Set the display text of the scale. Return to the normal weight display with\u001b[39;00m\n\u001b[32m 556\u001b[39m \u001b[33;03m self.set_weight_display().\"\"\"\u001b[39;00m\n\u001b[32m--> \u001b[39m\u001b[32m557\u001b[39m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;01mawait\u001b[39;00m \u001b[38;5;28mself\u001b[39m.send_command(\u001b[33mf\u001b[39m\u001b[33m'\u001b[39m\u001b[33mD \u001b[39m\u001b[33m\"\u001b[39m\u001b[38;5;132;01m{\u001b[39;00mtext\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m\"\u001b[39m\u001b[33m'\u001b[39m)\n", - "\u001b[36mFile \u001b[39m\u001b[32m~/Desktop/GitHub/pylabrobot/pylabrobot/scales/mettler_toledo/backend.py:286\u001b[39m, in \u001b[36mMettlerToledoWXS205SDUBackend.send_command\u001b[39m\u001b[34m(self, command, timeout)\u001b[39m\n\u001b[32m 284\u001b[39m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[32m 285\u001b[39m response = MettlerToledoResponse(command=\u001b[33m\"\u001b[39m\u001b[33m\"\u001b[39m, status=\u001b[33m\"\u001b[39m\u001b[33m\"\u001b[39m, data=[])\n\u001b[32m--> \u001b[39m\u001b[32m286\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[43m.\u001b[49m\u001b[43m_parse_basic_errors\u001b[49m\u001b[43m(\u001b[49m\u001b[43mresponse\u001b[49m\u001b[43m)\u001b[49m\n\u001b[32m 287\u001b[39m responses.append(response)\n\u001b[32m 289\u001b[39m \u001b[38;5;66;03m# Status B means more responses follow; anything else (A, etc.) is final\u001b[39;00m\n", - "\u001b[36mFile \u001b[39m\u001b[32m~/Desktop/GitHub/pylabrobot/pylabrobot/scales/mettler_toledo/backend.py:207\u001b[39m, in \u001b[36mMettlerToledoWXS205SDUBackend._parse_basic_errors\u001b[39m\u001b[34m(self, response)\u001b[39m\n\u001b[32m 205\u001b[39m \u001b[38;5;66;03m# General error messages: ES, ET, EL (status is \"\" for these)\u001b[39;00m\n\u001b[32m 206\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m response.command == \u001b[33m\"\u001b[39m\u001b[33mES\u001b[39m\u001b[33m\"\u001b[39m:\n\u001b[32m--> \u001b[39m\u001b[32m207\u001b[39m \u001b[38;5;28;01mraise\u001b[39;00m MettlerToledoError.syntax_error()\n\u001b[32m 208\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m response.command == \u001b[33m\"\u001b[39m\u001b[33mET\u001b[39m\u001b[33m\"\u001b[39m:\n\u001b[32m 209\u001b[39m \u001b[38;5;28;01mraise\u001b[39;00m MettlerToledoError.transmission_error()\n", + "\u001b[36mFile \u001b[39m\u001b[32m~/Desktop/GitHub/pylabrobot/pylabrobot/scales/mettler_toledo/backend.py:558\u001b[39m, in \u001b[36mMettlerToledoWXS205SDUBackend.set_display_text\u001b[39m\u001b[34m(self, text)\u001b[39m\n\u001b[32m 555\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[34mset_display_text\u001b[39m(\u001b[38;5;28mself\u001b[39m, text: \u001b[38;5;28mstr\u001b[39m) -> List[MettlerToledoResponse]:\n\u001b[32m 556\u001b[39m \u001b[38;5;250m \u001b[39m\u001b[33;03m\"\"\"Set the display text of the scale. Return to the normal weight display with\u001b[39;00m\n\u001b[32m 557\u001b[39m \u001b[33;03m self.set_weight_display().\"\"\"\u001b[39;00m\n\u001b[32m--> \u001b[39m\u001b[32m558\u001b[39m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;01mawait\u001b[39;00m \u001b[38;5;28mself\u001b[39m.send_command(\u001b[33mf\u001b[39m\u001b[33m'\u001b[39m\u001b[33mD \u001b[39m\u001b[33m\"\u001b[39m\u001b[38;5;132;01m{\u001b[39;00mtext\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m\"\u001b[39m\u001b[33m'\u001b[39m)\n", + "\u001b[36mFile \u001b[39m\u001b[32m~/Desktop/GitHub/pylabrobot/pylabrobot/scales/mettler_toledo/backend.py:287\u001b[39m, in \u001b[36mMettlerToledoWXS205SDUBackend.send_command\u001b[39m\u001b[34m(self, command, timeout)\u001b[39m\n\u001b[32m 285\u001b[39m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[32m 286\u001b[39m response = MettlerToledoResponse(command=\u001b[33m\"\u001b[39m\u001b[33m\"\u001b[39m, status=\u001b[33m\"\u001b[39m\u001b[33m\"\u001b[39m, data=[])\n\u001b[32m--> \u001b[39m\u001b[32m287\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[43m.\u001b[49m\u001b[43m_parse_basic_errors\u001b[49m\u001b[43m(\u001b[49m\u001b[43mresponse\u001b[49m\u001b[43m)\u001b[49m\n\u001b[32m 288\u001b[39m responses.append(response)\n\u001b[32m 290\u001b[39m \u001b[38;5;66;03m# Status B means more responses follow; anything else (A, etc.) is final\u001b[39;00m\n", + "\u001b[36mFile \u001b[39m\u001b[32m~/Desktop/GitHub/pylabrobot/pylabrobot/scales/mettler_toledo/backend.py:208\u001b[39m, in \u001b[36mMettlerToledoWXS205SDUBackend._parse_basic_errors\u001b[39m\u001b[34m(self, response)\u001b[39m\n\u001b[32m 206\u001b[39m \u001b[38;5;66;03m# General error messages: ES, ET, EL (status is \"\" for these)\u001b[39;00m\n\u001b[32m 207\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m response.command == \u001b[33m\"\u001b[39m\u001b[33mES\u001b[39m\u001b[33m\"\u001b[39m:\n\u001b[32m--> \u001b[39m\u001b[32m208\u001b[39m \u001b[38;5;28;01mraise\u001b[39;00m MettlerToledoError.syntax_error()\n\u001b[32m 209\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m response.command == \u001b[33m\"\u001b[39m\u001b[33mET\u001b[39m\u001b[33m\"\u001b[39m:\n\u001b[32m 210\u001b[39m \u001b[38;5;28;01mraise\u001b[39;00m MettlerToledoError.transmission_error()\n", "\u001b[31mMettlerToledoError\u001b[39m: Syntax error: The weigh module/balance has not recognized the received command or the command is not allowed" ] } @@ -991,14 +1149,14 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 11:43:27,897 - pylabrobot - IO - [MT Scale] Sent command: ZC 5000\n", - "2026-03-30 11:43:27,901 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'ZC 5000\\r\\n'\n", - "2026-03-30 11:43:27,933 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'ES\\r\\n'\n", - "2026-03-30 11:43:27,934 - pylabrobot - IO - [MT Scale] Received response: b'ES\\r\\n'\n", - "2026-03-30 11:43:27,935 - pylabrobot - IO - [MT Scale] Sent command: TC 5000\n", - "2026-03-30 11:43:27,939 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'TC 5000\\r\\n'\n", - "2026-03-30 11:43:27,965 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'ES\\r\\n'\n", - "2026-03-30 11:43:27,966 - pylabrobot - IO - [MT Scale] Received response: b'ES\\r\\n'\n" + "2026-03-30 11:58:30,097 - pylabrobot - IO - [MT Scale] Sent command: ZC 5000\n", + "2026-03-30 11:58:30,101 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'ZC 5000\\r\\n'\n", + "2026-03-30 11:58:30,123 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'ES\\r\\n'\n", + "2026-03-30 11:58:30,124 - pylabrobot - IO - [MT Scale] Received response: b'ES\\r\\n'\n", + "2026-03-30 11:58:30,125 - pylabrobot - IO - [MT Scale] Sent command: TC 5000\n", + "2026-03-30 11:58:30,126 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'TC 5000\\r\\n'\n", + "2026-03-30 11:58:30,156 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'ES\\r\\n'\n", + "2026-03-30 11:58:30,157 - pylabrobot - IO - [MT Scale] Received response: b'ES\\r\\n'\n" ] }, { @@ -1041,9 +1199,27 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 20, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2026-03-30 11:58:31,651 - pylabrobot - IO - [MT Scale] Sent command: M21 0 0\n", + "2026-03-30 11:58:31,653 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'M21 0 0\\r\\n'\n", + "2026-03-30 11:58:31,691 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M21 A\\r\\n'\n", + "2026-03-30 11:58:31,692 - pylabrobot - IO - [MT Scale] Received response: b'M21 A\\r\\n'\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "PASS: host unit set to grams\n" + ] + } + ], "source": [ "if \"M21\" in backend._supported_commands:\n", " await backend.set_host_unit_grams()\n", @@ -1061,9 +1237,17 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 21, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "SKIP: I50 not supported on this device\n" + ] + } + ], "source": [ "if \"I50\" in backend._supported_commands:\n", " remaining = await backend.request_remaining_weighing_range()\n", @@ -1084,9 +1268,30 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 22, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2026-03-30 11:58:41,437 - pylabrobot - IO - [MT Scale] Sent command: M28\n", + "2026-03-30 11:58:41,440 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'M28\\r\\n'\n", + "2026-03-30 11:58:41,473 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M28 B 1 19.8\\r\\n'\n", + "2026-03-30 11:58:41,474 - pylabrobot - IO - [MT Scale] Received response: b'M28 B 1 19.8\\r\\n'\n", + "2026-03-30 11:58:41,488 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M28 A 2 19.3\\r\\n'\n", + "2026-03-30 11:58:41,491 - pylabrobot - IO - [MT Scale] Received response: b'M28 A 2 19.3\\r\\n'\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Scale temperature: 19.8 C\n", + "PASS: measure_temperature works - I0 correctly predicted M28 support\n" + ] + } + ], "source": [ "if \"M28\" in backend._supported_commands:\n", " temp = await backend.measure_temperature()\n", @@ -1116,14 +1321,14 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 11:43:32,567 - pylabrobot - IO - [MT Scale] Sent command: Z\n", - "2026-03-30 11:43:32,569 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'Z\\r\\n'\n", - "2026-03-30 11:43:32,905 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'Z A\\r\\n'\n", - "2026-03-30 11:43:32,906 - pylabrobot - IO - [MT Scale] Received response: b'Z A\\r\\n'\n", - "2026-03-30 11:43:32,908 - pylabrobot - IO - [MT Scale] Sent command: SI\n", - "2026-03-30 11:43:32,909 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", - "2026-03-30 11:43:32,952 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 11:43:32,954 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n" + "2026-03-30 11:59:03,913 - pylabrobot - IO - [MT Scale] Sent command: Z\n", + "2026-03-30 11:59:03,916 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'Z\\r\\n'\n", + "2026-03-30 11:59:04,299 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'Z A\\r\\n'\n", + "2026-03-30 11:59:04,300 - pylabrobot - IO - [MT Scale] Received response: b'Z A\\r\\n'\n", + "2026-03-30 11:59:04,301 - pylabrobot - IO - [MT Scale] Sent command: SI\n", + "2026-03-30 11:59:04,303 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", + "2026-03-30 11:59:04,347 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 11:59:04,348 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n" ] }, { @@ -1144,14 +1349,14 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 11:43:33,030 - pylabrobot - IO - [MT Scale] Sent command: T\n", - "2026-03-30 11:43:33,033 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'T\\r\\n'\n", - "2026-03-30 11:43:33,321 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'T S 0.00000 g\\r\\n'\n", - "2026-03-30 11:43:33,321 - pylabrobot - IO - [MT Scale] Received response: b'T S 0.00000 g\\r\\n'\n", - "2026-03-30 11:43:33,324 - pylabrobot - IO - [MT Scale] Sent command: TA\n", - "2026-03-30 11:43:33,326 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'TA\\r\\n'\n", - "2026-03-30 11:43:33,400 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'TA A 0.00000 g\\r\\n'\n", - "2026-03-30 11:43:33,401 - pylabrobot - IO - [MT Scale] Received response: b'TA A 0.00000 g\\r\\n'\n" + "2026-03-30 11:59:05,364 - pylabrobot - IO - [MT Scale] Sent command: T\n", + "2026-03-30 11:59:05,365 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'T\\r\\n'\n", + "2026-03-30 11:59:05,706 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'T S 0.00000 g\\r\\n'\n", + "2026-03-30 11:59:05,706 - pylabrobot - IO - [MT Scale] Received response: b'T S 0.00000 g\\r\\n'\n", + "2026-03-30 11:59:05,708 - pylabrobot - IO - [MT Scale] Sent command: TA\n", + "2026-03-30 11:59:05,709 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'TA\\r\\n'\n", + "2026-03-30 11:59:05,801 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'TA A 0.00000 g\\r\\n'\n", + "2026-03-30 11:59:05,802 - pylabrobot - IO - [MT Scale] Received response: b'TA A 0.00000 g\\r\\n'\n" ] }, { @@ -1212,94 +1417,94 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 11:43:40,458 - pylabrobot - IO - [MT Scale] Sent command: S\n", - "2026-03-30 11:43:40,459 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", - "2026-03-30 11:43:40,577 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 11:43:40,578 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 11:43:40,579 - pylabrobot - IO - [MT Scale] Sent command: S\n", - "2026-03-30 11:43:40,583 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", - "2026-03-30 11:43:40,673 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 11:43:40,674 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 11:43:40,675 - pylabrobot - IO - [MT Scale] Sent command: S\n", - "2026-03-30 11:43:40,677 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", - "2026-03-30 11:43:40,769 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 11:43:40,770 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 11:43:40,771 - pylabrobot - IO - [MT Scale] Sent command: S\n", - "2026-03-30 11:43:40,772 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", - "2026-03-30 11:43:40,881 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 11:43:40,882 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 11:43:40,883 - pylabrobot - IO - [MT Scale] Sent command: S\n", - "2026-03-30 11:43:40,884 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", - "2026-03-30 11:43:40,977 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 11:43:40,978 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 11:43:40,979 - pylabrobot - IO - [MT Scale] Sent command: S\n", - "2026-03-30 11:43:40,980 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", - "2026-03-30 11:43:41,073 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 11:43:41,074 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 11:43:41,075 - pylabrobot - IO - [MT Scale] Sent command: S\n", - "2026-03-30 11:43:41,076 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", - "2026-03-30 11:43:41,169 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 11:43:41,170 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 11:43:41,170 - pylabrobot - IO - [MT Scale] Sent command: S\n", - "2026-03-30 11:43:41,171 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", - "2026-03-30 11:43:41,265 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 11:43:41,266 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 11:43:41,267 - pylabrobot - IO - [MT Scale] Sent command: S\n", - "2026-03-30 11:43:41,268 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", - "2026-03-30 11:43:41,361 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 11:43:41,362 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 11:43:41,363 - pylabrobot - IO - [MT Scale] Sent command: S\n", - "2026-03-30 11:43:41,364 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", - "2026-03-30 11:43:41,456 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 11:43:41,457 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 11:43:41,458 - pylabrobot - IO - [MT Scale] Sent command: SI\n", - "2026-03-30 11:43:41,460 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", - "2026-03-30 11:43:41,489 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 11:43:41,490 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 11:43:41,491 - pylabrobot - IO - [MT Scale] Sent command: SI\n", - "2026-03-30 11:43:41,494 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", - "2026-03-30 11:43:41,537 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 11:43:41,542 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 11:43:41,544 - pylabrobot - IO - [MT Scale] Sent command: SI\n", - "2026-03-30 11:43:41,548 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", - "2026-03-30 11:43:41,584 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 11:43:41,585 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 11:43:41,586 - pylabrobot - IO - [MT Scale] Sent command: SI\n", - "2026-03-30 11:43:41,588 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", - "2026-03-30 11:43:41,633 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 11:43:41,637 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 11:43:41,641 - pylabrobot - IO - [MT Scale] Sent command: SI\n", - "2026-03-30 11:43:41,644 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", - "2026-03-30 11:43:41,682 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 11:43:41,684 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 11:43:41,686 - pylabrobot - IO - [MT Scale] Sent command: SI\n", - "2026-03-30 11:43:41,690 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", - "2026-03-30 11:43:41,729 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 11:43:41,730 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 11:43:41,731 - pylabrobot - IO - [MT Scale] Sent command: SI\n", - "2026-03-30 11:43:41,736 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", - "2026-03-30 11:43:41,777 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 11:43:41,778 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 11:43:41,780 - pylabrobot - IO - [MT Scale] Sent command: SI\n", - "2026-03-30 11:43:41,782 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", - "2026-03-30 11:43:41,825 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 11:43:41,828 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 11:43:41,832 - pylabrobot - IO - [MT Scale] Sent command: SI\n", - "2026-03-30 11:43:41,834 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", - "2026-03-30 11:43:41,872 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 11:43:41,873 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 11:43:41,873 - pylabrobot - IO - [MT Scale] Sent command: SI\n", - "2026-03-30 11:43:41,877 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", - "2026-03-30 11:43:41,905 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 11:43:41,906 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n" + "2026-03-30 11:59:20,456 - pylabrobot - IO - [MT Scale] Sent command: S\n", + "2026-03-30 11:59:20,459 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", + "2026-03-30 11:59:20,541 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 11:59:20,542 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 11:59:20,544 - pylabrobot - IO - [MT Scale] Sent command: S\n", + "2026-03-30 11:59:20,545 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", + "2026-03-30 11:59:20,638 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 11:59:20,638 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 11:59:20,639 - pylabrobot - IO - [MT Scale] Sent command: S\n", + "2026-03-30 11:59:20,641 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", + "2026-03-30 11:59:20,733 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 11:59:20,734 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 11:59:20,735 - pylabrobot - IO - [MT Scale] Sent command: S\n", + "2026-03-30 11:59:20,737 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", + "2026-03-30 11:59:20,829 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 11:59:20,830 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 11:59:20,831 - pylabrobot - IO - [MT Scale] Sent command: S\n", + "2026-03-30 11:59:20,834 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", + "2026-03-30 11:59:20,926 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 11:59:20,927 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 11:59:20,927 - pylabrobot - IO - [MT Scale] Sent command: S\n", + "2026-03-30 11:59:20,929 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", + "2026-03-30 11:59:21,021 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 11:59:21,024 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 11:59:21,027 - pylabrobot - IO - [MT Scale] Sent command: S\n", + "2026-03-30 11:59:21,031 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", + "2026-03-30 11:59:21,118 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 11:59:21,120 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 11:59:21,120 - pylabrobot - IO - [MT Scale] Sent command: S\n", + "2026-03-30 11:59:21,125 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", + "2026-03-30 11:59:21,229 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 11:59:21,232 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 11:59:21,234 - pylabrobot - IO - [MT Scale] Sent command: S\n", + "2026-03-30 11:59:21,236 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", + "2026-03-30 11:59:21,325 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 11:59:21,326 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 11:59:21,329 - pylabrobot - IO - [MT Scale] Sent command: S\n", + "2026-03-30 11:59:21,331 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", + "2026-03-30 11:59:21,420 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 11:59:21,421 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 11:59:21,425 - pylabrobot - IO - [MT Scale] Sent command: SI\n", + "2026-03-30 11:59:21,427 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", + "2026-03-30 11:59:21,473 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 11:59:21,475 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 11:59:21,475 - pylabrobot - IO - [MT Scale] Sent command: SI\n", + "2026-03-30 11:59:21,477 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", + "2026-03-30 11:59:21,517 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 11:59:21,520 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 11:59:21,521 - pylabrobot - IO - [MT Scale] Sent command: SI\n", + "2026-03-30 11:59:21,526 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", + "2026-03-30 11:59:21,564 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 11:59:21,567 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 11:59:21,568 - pylabrobot - IO - [MT Scale] Sent command: SI\n", + "2026-03-30 11:59:21,571 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", + "2026-03-30 11:59:21,613 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 11:59:21,614 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 11:59:21,617 - pylabrobot - IO - [MT Scale] Sent command: SI\n", + "2026-03-30 11:59:21,625 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", + "2026-03-30 11:59:21,662 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 11:59:21,663 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 11:59:21,664 - pylabrobot - IO - [MT Scale] Sent command: SI\n", + "2026-03-30 11:59:21,667 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", + "2026-03-30 11:59:21,709 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 11:59:21,712 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 11:59:21,716 - pylabrobot - IO - [MT Scale] Sent command: SI\n", + "2026-03-30 11:59:21,725 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", + "2026-03-30 11:59:21,757 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 11:59:21,758 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 11:59:21,760 - pylabrobot - IO - [MT Scale] Sent command: SI\n", + "2026-03-30 11:59:21,761 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", + "2026-03-30 11:59:21,793 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 11:59:21,794 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 11:59:21,795 - pylabrobot - IO - [MT Scale] Sent command: SI\n", + "2026-03-30 11:59:21,796 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", + "2026-03-30 11:59:21,836 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 11:59:21,837 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 11:59:21,838 - pylabrobot - IO - [MT Scale] Sent command: SI\n", + "2026-03-30 11:59:21,846 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", + "2026-03-30 11:59:21,885 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 11:59:21,887 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ - "Stable read: 100.00 +/- 8.72 ms\n", - "Immediate read: 44.89 +/- 7.16 ms\n" + "Stable read: 96.83 +/- 6.21 ms\n", + "Immediate read: 46.27 +/- 4.63 ms\n" ] } ], @@ -1345,14 +1550,14 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 11:43:46,384 - pylabrobot - INFO - === Hardware validation ended ===\n" + "2026-03-30 11:59:21,899 - pylabrobot - INFO - === Hardware validation ended ===\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ - "Log file: ./logs/hardware_validation/2026-03-30_11-42-26_validation.log\n" + "Log file: ./logs/hardware_validation/2026-03-30_11-58-03_validation.log\n" ] } ], @@ -1391,4 +1596,4 @@ }, "nbformat": 4, "nbformat_minor": 4 -} \ No newline at end of file +} From ef8826df10f5d65389875189b8454f63ba47e88e Mon Sep 17 00:00:00 2001 From: Camillo Moschner Date: Mon, 30 Mar 2026 12:07:03 +0100 Subject: [PATCH 16/38] use `request_supported_commands` to retrieve possible commands during runtime --- pylabrobot/scales/mettler_toledo/backend.py | 33 ++++++++++++++++--- .../mettler_toledo/hardware_validation.ipynb | 14 +++++++- 2 files changed, 42 insertions(+), 5 deletions(-) diff --git a/pylabrobot/scales/mettler_toledo/backend.py b/pylabrobot/scales/mettler_toledo/backend.py index 3c8405836ad..6fbf5023b48 100644 --- a/pylabrobot/scales/mettler_toledo/backend.py +++ b/pylabrobot/scales/mettler_toledo/backend.py @@ -110,7 +110,7 @@ async def setup(self) -> None: self.serial_number = await self.cancel() # Discover supported commands via I0 (the definitive source per spec Section 2.2) - self._supported_commands: Set[str] = await self._query_supported_commands() + self._supported_commands: Set[str] = await self._request_supported_commands() # Device identity (Level 0 - always available) # Note: device_type and capacity both use I2 but are separate methods intentionally - @@ -143,14 +143,14 @@ def serialize(self) -> dict: # === Device discovery === - async def _query_supported_commands(self) -> Set[str]: - """Query all implemented commands via I0 (Level 0 - always available). + async def _request_supported_commands(self) -> Set[str]: + """Query all implemented MT-SICS commands via I0 (Level 0 - always available). I0 is the definitive source of command support per spec Section 2.2. I1 only reports which standardized level sets are fully implemented, but individual commands may exist outside those levels. - Returns a set of command strings (e.g. {"@", "S", "SI", "Z", "M21", "M28"}). + Returns a set of MT-SICS command strings (e.g. {"@", "S", "SI", "Z", "M21", "M28"}). """ responses = await self.send_command("I0") commands: Set[str] = set() @@ -160,6 +160,31 @@ async def _query_supported_commands(self) -> Set[str]: commands.add(resp.data[1]) return commands + def request_supported_methods(self) -> List[str]: + """Return the names of all backend methods supported by the connected device. + + Uses the I0 command list (populated during setup) to determine which + decorated methods can be called without raising MettlerToledoError. + Undecorated methods (Level 0/1) are always included. + """ + supported: List[str] = [] + for name in dir(self): + if name.startswith("_"): + continue + attr = getattr(type(self), name, None) + if not callable(attr): + continue + # Check if the method has a command gate + mt_cmd = getattr(attr, "_mt_sics_command", None) + if mt_cmd is not None: + if hasattr(self, "_supported_commands") and mt_cmd in self._supported_commands: + supported.append(name) + # If _supported_commands not yet populated (before setup), skip + else: + # Undecorated public methods are always available + supported.append(name) + return sorted(supported) + # === Response parsing === @staticmethod diff --git a/pylabrobot/scales/mettler_toledo/hardware_validation.ipynb b/pylabrobot/scales/mettler_toledo/hardware_validation.ipynb index 7c568c7698e..99d8e58d97c 100644 --- a/pylabrobot/scales/mettler_toledo/hardware_validation.ipynb +++ b/pylabrobot/scales/mettler_toledo/hardware_validation.ipynb @@ -266,6 +266,18 @@ "print(\"PASS: setup populated all identity fields\")" ] }, + { + "cell_type": "markdown", + "source": "### Supported Python methods on this device", + "metadata": {} + }, + { + "cell_type": "code", + "source": "methods = backend.request_supported_methods()\nprint(f\"{len(methods)} methods available on this device:\")\nfor m in methods:\n print(f\" {m}\")", + "metadata": {}, + "execution_count": null, + "outputs": [] + }, { "cell_type": "markdown", "metadata": {}, @@ -1596,4 +1608,4 @@ }, "nbformat": 4, "nbformat_minor": 4 -} +} \ No newline at end of file From d5b174baf387930eebc391be2dc5913122f200c4 Mon Sep 17 00:00:00 2001 From: Camillo Moschner Date: Mon, 30 Mar 2026 12:08:40 +0100 Subject: [PATCH 17/38] retrieving commands results --- .../mettler_toledo/hardware_validation.ipynb | 1083 +++++++++-------- 1 file changed, 567 insertions(+), 516 deletions(-) diff --git a/pylabrobot/scales/mettler_toledo/hardware_validation.ipynb b/pylabrobot/scales/mettler_toledo/hardware_validation.ipynb index 99d8e58d97c..676c5d96a30 100644 --- a/pylabrobot/scales/mettler_toledo/hardware_validation.ipynb +++ b/pylabrobot/scales/mettler_toledo/hardware_validation.ipynb @@ -33,7 +33,7 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 11:58:03,533 - pylabrobot - INFO - === Hardware validation started ===\n" + "2026-03-30 12:07:26,881 - pylabrobot - INFO - === Hardware validation started ===\n" ] } ], @@ -65,155 +65,155 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 11:58:03,553 - pylabrobot.io.serial - INFO - Using explicitly provided port: /dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0 (for VID=1027, PID=24577)\n", - "2026-03-30 11:58:03,562 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] reset_input_buffer\n", - "2026-03-30 11:58:03,566 - pylabrobot - IO - [MT Scale] Sent command: @\n", - "2026-03-30 11:58:03,570 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'@\\r\\n'\n", - "2026-03-30 11:58:03,636 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I4 A \"B207696838\"\\r\\n'\n", - "2026-03-30 11:58:03,637 - pylabrobot - IO - [MT Scale] Received response: b'I4 A \"B207696838\"\\r\\n'\n", - "2026-03-30 11:58:03,642 - pylabrobot - IO - [MT Scale] Sent command: I0\n", - "2026-03-30 11:58:03,644 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I0\\r\\n'\n", - "2026-03-30 11:58:03,683 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I0\"\\r\\n'\n", - "2026-03-30 11:58:03,684 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I0\"\\r\\n'\n", - "2026-03-30 11:58:03,685 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I1\"\\r\\n'\n", - "2026-03-30 11:58:03,686 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I1\"\\r\\n'\n", - "2026-03-30 11:58:03,699 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I2\"\\r\\n'\n", - "2026-03-30 11:58:03,699 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I2\"\\r\\n'\n", - "2026-03-30 11:58:03,715 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I3\"\\r\\n'\n", - "2026-03-30 11:58:03,716 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I3\"\\r\\n'\n", - "2026-03-30 11:58:03,732 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I4\"\\r\\n'\n", - "2026-03-30 11:58:03,737 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I4\"\\r\\n'\n", - "2026-03-30 11:58:03,747 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I5\"\\r\\n'\n", - "2026-03-30 11:58:03,748 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I5\"\\r\\n'\n", - "2026-03-30 11:58:03,763 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"S\"\\r\\n'\n", - "2026-03-30 11:58:03,764 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"S\"\\r\\n'\n", - "2026-03-30 11:58:03,767 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"SI\"\\r\\n'\n", - "2026-03-30 11:58:03,767 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"SI\"\\r\\n'\n", - "2026-03-30 11:58:03,780 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"SIR\"\\r\\n'\n", - "2026-03-30 11:58:03,780 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"SIR\"\\r\\n'\n", - "2026-03-30 11:58:03,795 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"Z\"\\r\\n'\n", - "2026-03-30 11:58:03,796 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"Z\"\\r\\n'\n", - "2026-03-30 11:58:03,811 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"ZI\"\\r\\n'\n", - "2026-03-30 11:58:03,812 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"ZI\"\\r\\n'\n", - "2026-03-30 11:58:03,828 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"@\"\\r\\n'\n", - "2026-03-30 11:58:03,829 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"@\"\\r\\n'\n", - "2026-03-30 11:58:03,843 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"SR\"\\r\\n'\n", - "2026-03-30 11:58:03,844 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"SR\"\\r\\n'\n", - "2026-03-30 11:58:03,847 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"T\"\\r\\n'\n", - "2026-03-30 11:58:03,848 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"T\"\\r\\n'\n", - "2026-03-30 11:58:03,860 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"TA\"\\r\\n'\n", - "2026-03-30 11:58:03,861 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"TA\"\\r\\n'\n", - "2026-03-30 11:58:03,878 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"TAC\"\\r\\n'\n", - "2026-03-30 11:58:03,890 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"TAC\"\\r\\n'\n", - "2026-03-30 11:58:03,892 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"TI\"\\r\\n'\n", - "2026-03-30 11:58:03,893 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"TI\"\\r\\n'\n", - "2026-03-30 11:58:03,908 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C0\"\\r\\n'\n", - "2026-03-30 11:58:03,910 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"C0\"\\r\\n'\n", - "2026-03-30 11:58:03,924 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C1\"\\r\\n'\n", - "2026-03-30 11:58:03,929 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"C1\"\\r\\n'\n", - "2026-03-30 11:58:03,941 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C2\"\\r\\n'\n", - "2026-03-30 11:58:03,946 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"C2\"\\r\\n'\n", - "2026-03-30 11:58:03,950 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C3\"\\r\\n'\n", - "2026-03-30 11:58:03,951 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"C3\"\\r\\n'\n", - "2026-03-30 11:58:03,958 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"COM\"\\r\\n'\n", - "2026-03-30 11:58:03,959 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"COM\"\\r\\n'\n", - "2026-03-30 11:58:03,973 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"DAT\"\\r\\n'\n", - "2026-03-30 11:58:03,976 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"DAT\"\\r\\n'\n", - "2026-03-30 11:58:03,988 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I10\"\\r\\n'\n", - "2026-03-30 11:58:03,990 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I10\"\\r\\n'\n", - "2026-03-30 11:58:04,003 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I11\"\\r\\n'\n", - "2026-03-30 11:58:04,005 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I11\"\\r\\n'\n", - "2026-03-30 11:58:04,019 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I14\"\\r\\n'\n", - "2026-03-30 11:58:04,023 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I14\"\\r\\n'\n", - "2026-03-30 11:58:04,035 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I15\"\\r\\n'\n", - "2026-03-30 11:58:04,037 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I15\"\\r\\n'\n", - "2026-03-30 11:58:04,055 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I16\"\\r\\n'\n", - "2026-03-30 11:58:04,064 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I16\"\\r\\n'\n", - "2026-03-30 11:58:04,069 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I21\"\\r\\n'\n", - "2026-03-30 11:58:04,070 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I21\"\\r\\n'\n", - "2026-03-30 11:58:04,082 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I22\"\\r\\n'\n", - "2026-03-30 11:58:04,083 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I22\"\\r\\n'\n", - "2026-03-30 11:58:04,099 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I23\"\\r\\n'\n", - "2026-03-30 11:58:04,101 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I23\"\\r\\n'\n", - "2026-03-30 11:58:04,103 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I24\"\\r\\n'\n", - "2026-03-30 11:58:04,109 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I24\"\\r\\n'\n", - "2026-03-30 11:58:04,116 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I25\"\\r\\n'\n", - "2026-03-30 11:58:04,118 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I25\"\\r\\n'\n", - "2026-03-30 11:58:04,131 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I26\"\\r\\n'\n", - "2026-03-30 11:58:04,135 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I26\"\\r\\n'\n", - "2026-03-30 11:58:04,150 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M01\"\\r\\n'\n", - "2026-03-30 11:58:04,157 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M01\"\\r\\n'\n", - "2026-03-30 11:58:04,163 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M02\"\\r\\n'\n", - "2026-03-30 11:58:04,166 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M02\"\\r\\n'\n", - "2026-03-30 11:58:04,179 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M03\"\\r\\n'\n", - "2026-03-30 11:58:04,181 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M03\"\\r\\n'\n", - "2026-03-30 11:58:04,195 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M17\"\\r\\n'\n", - "2026-03-30 11:58:04,196 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M17\"\\r\\n'\n", - "2026-03-30 11:58:04,211 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M18\"\\r\\n'\n", - "2026-03-30 11:58:04,212 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M18\"\\r\\n'\n", - "2026-03-30 11:58:04,227 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M19\"\\r\\n'\n", - "2026-03-30 11:58:04,229 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M19\"\\r\\n'\n", - "2026-03-30 11:58:04,245 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M20\"\\r\\n'\n", - "2026-03-30 11:58:04,249 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M20\"\\r\\n'\n", - "2026-03-30 11:58:04,259 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M21\"\\r\\n'\n", - "2026-03-30 11:58:04,260 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M21\"\\r\\n'\n", - "2026-03-30 11:58:04,263 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M27\"\\r\\n'\n", - "2026-03-30 11:58:04,264 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M27\"\\r\\n'\n", - "2026-03-30 11:58:04,274 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M28\"\\r\\n'\n", - "2026-03-30 11:58:04,275 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M28\"\\r\\n'\n", - "2026-03-30 11:58:04,291 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M29\"\\r\\n'\n", - "2026-03-30 11:58:04,292 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M29\"\\r\\n'\n", - "2026-03-30 11:58:04,307 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M31\"\\r\\n'\n", - "2026-03-30 11:58:04,308 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M31\"\\r\\n'\n", - "2026-03-30 11:58:04,322 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M32\"\\r\\n'\n", - "2026-03-30 11:58:04,323 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M32\"\\r\\n'\n", - "2026-03-30 11:58:04,339 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M33\"\\r\\n'\n", - "2026-03-30 11:58:04,339 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M33\"\\r\\n'\n", - "2026-03-30 11:58:04,355 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M35\"\\r\\n'\n", - "2026-03-30 11:58:04,356 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M35\"\\r\\n'\n", - "2026-03-30 11:58:04,370 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"SIS\"\\r\\n'\n", - "2026-03-30 11:58:04,371 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"SIS\"\\r\\n'\n", - "2026-03-30 11:58:04,387 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"SNR\"\\r\\n'\n", - "2026-03-30 11:58:04,387 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"SNR\"\\r\\n'\n", - "2026-03-30 11:58:04,403 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TIM\"\\r\\n'\n", - "2026-03-30 11:58:04,404 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TIM\"\\r\\n'\n", - "2026-03-30 11:58:04,418 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST0\"\\r\\n'\n", - "2026-03-30 11:58:04,419 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TST0\"\\r\\n'\n", - "2026-03-30 11:58:04,435 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST1\"\\r\\n'\n", - "2026-03-30 11:58:04,436 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TST1\"\\r\\n'\n", - "2026-03-30 11:58:04,451 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST2\"\\r\\n'\n", - "2026-03-30 11:58:04,452 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TST2\"\\r\\n'\n", - "2026-03-30 11:58:04,466 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST3\"\\r\\n'\n", - "2026-03-30 11:58:04,468 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TST3\"\\r\\n'\n", - "2026-03-30 11:58:04,483 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"UPD\"\\r\\n'\n", - "2026-03-30 11:58:04,483 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"UPD\"\\r\\n'\n", - "2026-03-30 11:58:04,498 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"FCUT\"\\r\\n'\n", - "2026-03-30 11:58:04,499 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 3 \"FCUT\"\\r\\n'\n", - "2026-03-30 11:58:04,514 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"FSET\"\\r\\n'\n", - "2026-03-30 11:58:04,515 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 3 \"FSET\"\\r\\n'\n", - "2026-03-30 11:58:04,519 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"LST\"\\r\\n'\n", - "2026-03-30 11:58:04,520 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 3 \"LST\"\\r\\n'\n", - "2026-03-30 11:58:04,531 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"RDB\"\\r\\n'\n", - "2026-03-30 11:58:04,532 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 3 \"RDB\"\\r\\n'\n", - "2026-03-30 11:58:04,546 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 A 3 \"USTB\"\\r\\n'\n", - "2026-03-30 11:58:04,547 - pylabrobot - IO - [MT Scale] Received response: b'I0 A 3 \"USTB\"\\r\\n'\n", - "2026-03-30 11:58:04,548 - pylabrobot - IO - [MT Scale] Sent command: I2\n", - "2026-03-30 11:58:04,551 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I2\\r\\n'\n", - "2026-03-30 11:58:04,610 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", - "2026-03-30 11:58:04,611 - pylabrobot - IO - [MT Scale] Received response: b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", - "2026-03-30 11:58:04,612 - pylabrobot - IO - [MT Scale] Sent command: I2\n", - "2026-03-30 11:58:04,614 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I2\\r\\n'\n", - "2026-03-30 11:58:04,675 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", - "2026-03-30 11:58:04,675 - pylabrobot - IO - [MT Scale] Received response: b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", - "2026-03-30 11:58:04,677 - pylabrobot - INFO - [MT Scale] Connected to Mettler Toledo scale on /dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0\n", + "2026-03-30 12:07:26,905 - pylabrobot.io.serial - INFO - Using explicitly provided port: /dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0 (for VID=1027, PID=24577)\n", + "2026-03-30 12:07:26,921 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] reset_input_buffer\n", + "2026-03-30 12:07:26,923 - pylabrobot - IO - [MT Scale] Sent command: @\n", + "2026-03-30 12:07:26,927 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'@\\r\\n'\n", + "2026-03-30 12:07:26,992 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I4 A \"B207696838\"\\r\\n'\n", + "2026-03-30 12:07:26,993 - pylabrobot - IO - [MT Scale] Received response: b'I4 A \"B207696838\"\\r\\n'\n", + "2026-03-30 12:07:26,994 - pylabrobot - IO - [MT Scale] Sent command: I0\n", + "2026-03-30 12:07:26,995 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I0\\r\\n'\n", + "2026-03-30 12:07:27,025 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I0\"\\r\\n'\n", + "2026-03-30 12:07:27,026 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I0\"\\r\\n'\n", + "2026-03-30 12:07:27,040 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I1\"\\r\\n'\n", + "2026-03-30 12:07:27,041 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I1\"\\r\\n'\n", + "2026-03-30 12:07:27,056 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I2\"\\r\\n'\n", + "2026-03-30 12:07:27,057 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I2\"\\r\\n'\n", + "2026-03-30 12:07:27,073 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I3\"\\r\\n'\n", + "2026-03-30 12:07:27,074 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I3\"\\r\\n'\n", + "2026-03-30 12:07:27,077 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I4\"\\r\\n'\n", + "2026-03-30 12:07:27,078 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I4\"\\r\\n'\n", + "2026-03-30 12:07:27,089 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I5\"\\r\\n'\n", + "2026-03-30 12:07:27,092 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I5\"\\r\\n'\n", + "2026-03-30 12:07:27,104 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"S\"\\r\\n'\n", + "2026-03-30 12:07:27,106 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"S\"\\r\\n'\n", + "2026-03-30 12:07:27,120 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"SI\"\\r\\n'\n", + "2026-03-30 12:07:27,121 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"SI\"\\r\\n'\n", + "2026-03-30 12:07:27,136 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"SIR\"\\r\\n'\n", + "2026-03-30 12:07:27,137 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"SIR\"\\r\\n'\n", + "2026-03-30 12:07:27,153 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"Z\"\\r\\n'\n", + "2026-03-30 12:07:27,154 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"Z\"\\r\\n'\n", + "2026-03-30 12:07:27,156 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"ZI\"\\r\\n'\n", + "2026-03-30 12:07:27,158 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"ZI\"\\r\\n'\n", + "2026-03-30 12:07:27,168 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"@\"\\r\\n'\n", + "2026-03-30 12:07:27,170 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"@\"\\r\\n'\n", + "2026-03-30 12:07:27,184 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"SR\"\\r\\n'\n", + "2026-03-30 12:07:27,186 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"SR\"\\r\\n'\n", + "2026-03-30 12:07:27,200 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"T\"\\r\\n'\n", + "2026-03-30 12:07:27,203 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"T\"\\r\\n'\n", + "2026-03-30 12:07:27,217 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"TA\"\\r\\n'\n", + "2026-03-30 12:07:27,220 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"TA\"\\r\\n'\n", + "2026-03-30 12:07:27,232 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"TAC\"\\r\\n'\n", + "2026-03-30 12:07:27,235 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"TAC\"\\r\\n'\n", + "2026-03-30 12:07:27,248 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"TI\"\\r\\n'\n", + "2026-03-30 12:07:27,251 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"TI\"\\r\\n'\n", + "2026-03-30 12:07:27,264 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C0\"\\r\\n'\n", + "2026-03-30 12:07:27,270 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"C0\"\\r\\n'\n", + "2026-03-30 12:07:27,276 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C1\"\\r\\n'\n", + "2026-03-30 12:07:27,278 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"C1\"\\r\\n'\n", + "2026-03-30 12:07:27,281 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C2\"\\r\\n'\n", + "2026-03-30 12:07:27,282 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"C2\"\\r\\n'\n", + "2026-03-30 12:07:27,296 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C3\"\\r\\n'\n", + "2026-03-30 12:07:27,297 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"C3\"\\r\\n'\n", + "2026-03-30 12:07:27,312 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"COM\"\\r\\n'\n", + "2026-03-30 12:07:27,314 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"COM\"\\r\\n'\n", + "2026-03-30 12:07:27,328 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"DAT\"\\r\\n'\n", + "2026-03-30 12:07:27,330 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"DAT\"\\r\\n'\n", + "2026-03-30 12:07:27,346 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I10\"\\r\\n'\n", + "2026-03-30 12:07:27,350 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I10\"\\r\\n'\n", + "2026-03-30 12:07:27,360 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I11\"\\r\\n'\n", + "2026-03-30 12:07:27,362 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I11\"\\r\\n'\n", + "2026-03-30 12:07:27,377 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I14\"\\r\\n'\n", + "2026-03-30 12:07:27,380 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I14\"\\r\\n'\n", + "2026-03-30 12:07:27,386 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I15\"\\r\\n'\n", + "2026-03-30 12:07:27,389 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I15\"\\r\\n'\n", + "2026-03-30 12:07:27,391 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I16\"\\r\\n'\n", + "2026-03-30 12:07:27,393 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I16\"\\r\\n'\n", + "2026-03-30 12:07:27,408 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I21\"\\r\\n'\n", + "2026-03-30 12:07:27,410 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I21\"\\r\\n'\n", + "2026-03-30 12:07:27,424 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I22\"\\r\\n'\n", + "2026-03-30 12:07:27,428 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I22\"\\r\\n'\n", + "2026-03-30 12:07:27,440 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I23\"\\r\\n'\n", + "2026-03-30 12:07:27,441 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I23\"\\r\\n'\n", + "2026-03-30 12:07:27,457 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I24\"\\r\\n'\n", + "2026-03-30 12:07:27,459 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I24\"\\r\\n'\n", + "2026-03-30 12:07:27,472 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I25\"\\r\\n'\n", + "2026-03-30 12:07:27,477 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I25\"\\r\\n'\n", + "2026-03-30 12:07:27,488 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I26\"\\r\\n'\n", + "2026-03-30 12:07:27,490 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I26\"\\r\\n'\n", + "2026-03-30 12:07:27,504 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M01\"\\r\\n'\n", + "2026-03-30 12:07:27,505 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M01\"\\r\\n'\n", + "2026-03-30 12:07:27,520 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M02\"\\r\\n'\n", + "2026-03-30 12:07:27,520 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M02\"\\r\\n'\n", + "2026-03-30 12:07:27,536 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M03\"\\r\\n'\n", + "2026-03-30 12:07:27,537 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M03\"\\r\\n'\n", + "2026-03-30 12:07:27,538 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M17\"\\r\\n'\n", + "2026-03-30 12:07:27,539 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M17\"\\r\\n'\n", + "2026-03-30 12:07:27,551 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M18\"\\r\\n'\n", + "2026-03-30 12:07:27,552 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M18\"\\r\\n'\n", + "2026-03-30 12:07:27,568 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M19\"\\r\\n'\n", + "2026-03-30 12:07:27,568 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M19\"\\r\\n'\n", + "2026-03-30 12:07:27,584 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M20\"\\r\\n'\n", + "2026-03-30 12:07:27,585 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M20\"\\r\\n'\n", + "2026-03-30 12:07:27,599 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M21\"\\r\\n'\n", + "2026-03-30 12:07:27,600 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M21\"\\r\\n'\n", + "2026-03-30 12:07:27,616 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M27\"\\r\\n'\n", + "2026-03-30 12:07:27,617 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M27\"\\r\\n'\n", + "2026-03-30 12:07:27,631 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M28\"\\r\\n'\n", + "2026-03-30 12:07:27,632 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M28\"\\r\\n'\n", + "2026-03-30 12:07:27,647 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M29\"\\r\\n'\n", + "2026-03-30 12:07:27,648 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M29\"\\r\\n'\n", + "2026-03-30 12:07:27,664 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M31\"\\r\\n'\n", + "2026-03-30 12:07:27,665 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M31\"\\r\\n'\n", + "2026-03-30 12:07:27,679 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M32\"\\r\\n'\n", + "2026-03-30 12:07:27,680 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M32\"\\r\\n'\n", + "2026-03-30 12:07:27,695 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M33\"\\r\\n'\n", + "2026-03-30 12:07:27,696 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M33\"\\r\\n'\n", + "2026-03-30 12:07:27,698 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M35\"\\r\\n'\n", + "2026-03-30 12:07:27,698 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M35\"\\r\\n'\n", + "2026-03-30 12:07:27,712 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"SIS\"\\r\\n'\n", + "2026-03-30 12:07:27,713 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"SIS\"\\r\\n'\n", + "2026-03-30 12:07:27,727 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"SNR\"\\r\\n'\n", + "2026-03-30 12:07:27,728 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"SNR\"\\r\\n'\n", + "2026-03-30 12:07:27,743 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TIM\"\\r\\n'\n", + "2026-03-30 12:07:27,744 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TIM\"\\r\\n'\n", + "2026-03-30 12:07:27,760 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST0\"\\r\\n'\n", + "2026-03-30 12:07:27,760 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TST0\"\\r\\n'\n", + "2026-03-30 12:07:27,775 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST1\"\\r\\n'\n", + "2026-03-30 12:07:27,776 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TST1\"\\r\\n'\n", + "2026-03-30 12:07:27,791 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST2\"\\r\\n'\n", + "2026-03-30 12:07:27,792 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TST2\"\\r\\n'\n", + "2026-03-30 12:07:27,808 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST3\"\\r\\n'\n", + "2026-03-30 12:07:27,809 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TST3\"\\r\\n'\n", + "2026-03-30 12:07:27,823 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"UPD\"\\r\\n'\n", + "2026-03-30 12:07:27,824 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"UPD\"\\r\\n'\n", + "2026-03-30 12:07:27,839 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"FCUT\"\\r\\n'\n", + "2026-03-30 12:07:27,840 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 3 \"FCUT\"\\r\\n'\n", + "2026-03-30 12:07:27,856 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"FSET\"\\r\\n'\n", + "2026-03-30 12:07:27,856 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 3 \"FSET\"\\r\\n'\n", + "2026-03-30 12:07:27,871 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"LST\"\\r\\n'\n", + "2026-03-30 12:07:27,872 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 3 \"LST\"\\r\\n'\n", + "2026-03-30 12:07:27,895 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"RDB\"\\r\\n'\n", + "2026-03-30 12:07:27,898 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 3 \"RDB\"\\r\\n'\n", + "2026-03-30 12:07:27,912 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 A 3 \"USTB\"\\r\\n'\n", + "2026-03-30 12:07:27,921 - pylabrobot - IO - [MT Scale] Received response: b'I0 A 3 \"USTB\"\\r\\n'\n", + "2026-03-30 12:07:27,926 - pylabrobot - IO - [MT Scale] Sent command: I2\n", + "2026-03-30 12:07:27,930 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I2\\r\\n'\n", + "2026-03-30 12:07:28,000 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", + "2026-03-30 12:07:28,002 - pylabrobot - IO - [MT Scale] Received response: b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", + "2026-03-30 12:07:28,005 - pylabrobot - IO - [MT Scale] Sent command: I2\n", + "2026-03-30 12:07:28,013 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I2\\r\\n'\n", + "2026-03-30 12:07:28,080 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", + "2026-03-30 12:07:28,084 - pylabrobot - IO - [MT Scale] Received response: b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", + "2026-03-30 12:07:28,087 - pylabrobot - INFO - [MT Scale] Connected to Mettler Toledo scale on /dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0\n", "Device type: WXS205SDU WXA-Bridge\n", "Serial number: B207696838\n", "Capacity: 220.0 g\n", "Supported commands: ['@', 'C0', 'C1', 'C2', 'C3', 'COM', 'DAT', 'FCUT', 'FSET', 'I0', 'I1', 'I10', 'I11', 'I14', 'I15', 'I16', 'I2', 'I21', 'I22', 'I23', 'I24', 'I25', 'I26', 'I3', 'I4', 'I5', 'LST', 'M01', 'M02', 'M03', 'M17', 'M18', 'M19', 'M20', 'M21', 'M27', 'M28', 'M29', 'M31', 'M32', 'M33', 'M35', 'RDB', 'S', 'SI', 'SIR', 'SIS', 'SNR', 'SR', 'T', 'TA', 'TAC', 'TI', 'TIM', 'TST0', 'TST1', 'TST2', 'TST3', 'UPD', 'USTB', 'Z', 'ZI']\n", - "2026-03-30 11:58:04,678 - pylabrobot - IO - [MT Scale] Sent command: M21 0 0\n", - "2026-03-30 11:58:04,680 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'M21 0 0\\r\\n'\n", - "2026-03-30 11:58:04,706 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M21 A\\r\\n'\n", - "2026-03-30 11:58:04,707 - pylabrobot - IO - [MT Scale] Received response: b'M21 A\\r\\n'\n" + "2026-03-30 12:07:28,088 - pylabrobot - IO - [MT Scale] Sent command: M21 0 0\n", + "2026-03-30 12:07:28,092 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'M21 0 0\\r\\n'\n", + "2026-03-30 12:07:28,127 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M21 A\\r\\n'\n", + "2026-03-30 12:07:28,131 - pylabrobot - IO - [MT Scale] Received response: b'M21 A\\r\\n'\n" ] } ], @@ -268,15 +268,66 @@ }, { "cell_type": "markdown", - "source": "### Supported Python methods on this device", - "metadata": {} + "metadata": {}, + "source": [ + "### Supported Python methods on this device" + ] }, { "cell_type": "code", - "source": "methods = backend.request_supported_methods()\nprint(f\"{len(methods)} methods available on this device:\")\nfor m in methods:\n print(f\" {m}\")", + "execution_count": 4, "metadata": {}, - "execution_count": null, - "outputs": [] + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "36 methods available on this device:\n", + " cancel\n", + " cancel_all\n", + " clear_tare\n", + " deserialize\n", + " get_all_instances\n", + " get_dynamic_weight\n", + " get_serial_number\n", + " get_stable_weight\n", + " get_tare_weight\n", + " get_weight\n", + " get_weight_value_immediately\n", + " measure_temperature\n", + " read_dynamic_weight\n", + " read_stable_weight\n", + " read_weight\n", + " read_weight_value_immediately\n", + " request_capacity\n", + " request_device_type\n", + " request_serial_number\n", + " request_supported_methods\n", + " request_tare_weight\n", + " send_command\n", + " serialize\n", + " set_display_text\n", + " set_host_unit_grams\n", + " set_weight_display\n", + " setup\n", + " stop\n", + " tare\n", + " tare_immediately\n", + " tare_stable\n", + " tare_timeout\n", + " zero\n", + " zero_immediately\n", + " zero_stable\n", + " zero_timeout\n" + ] + } + ], + "source": [ + "methods = backend.request_supported_methods()\n", + "print(f\"{len(methods)} methods available on this device:\")\n", + "for m in methods:\n", + " print(f\" {m}\")" + ] }, { "cell_type": "markdown", @@ -290,139 +341,139 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 5, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 11:58:04,736 - pylabrobot - IO - [MT Scale] Sent command: I0\n", - "2026-03-30 11:58:04,740 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I0\\r\\n'\n", - "2026-03-30 11:58:04,772 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I0\"\\r\\n'\n", - "2026-03-30 11:58:04,773 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I0\"\\r\\n'\n", - "2026-03-30 11:58:04,786 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I1\"\\r\\n'\n", - "2026-03-30 11:58:04,792 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I1\"\\r\\n'\n", - "2026-03-30 11:58:04,803 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I2\"\\r\\n'\n", - "2026-03-30 11:58:04,804 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I2\"\\r\\n'\n", - "2026-03-30 11:58:04,806 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I3\"\\r\\n'\n", - "2026-03-30 11:58:04,808 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I3\"\\r\\n'\n", - "2026-03-30 11:58:04,818 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I4\"\\r\\n'\n", - "2026-03-30 11:58:04,820 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I4\"\\r\\n'\n", - "2026-03-30 11:58:04,837 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I5\"\\r\\n'\n", - "2026-03-30 11:58:04,838 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I5\"\\r\\n'\n", - "2026-03-30 11:58:04,851 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"S\"\\r\\n'\n", - "2026-03-30 11:58:04,855 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"S\"\\r\\n'\n", - "2026-03-30 11:58:04,867 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"SI\"\\r\\n'\n", - "2026-03-30 11:58:04,868 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"SI\"\\r\\n'\n", - "2026-03-30 11:58:04,883 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"SIR\"\\r\\n'\n", - "2026-03-30 11:58:04,884 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"SIR\"\\r\\n'\n", - "2026-03-30 11:58:04,898 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"Z\"\\r\\n'\n", - "2026-03-30 11:58:04,899 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"Z\"\\r\\n'\n", - "2026-03-30 11:58:04,903 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"ZI\"\\r\\n'\n", - "2026-03-30 11:58:04,905 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"ZI\"\\r\\n'\n", - "2026-03-30 11:58:04,915 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"@\"\\r\\n'\n", - "2026-03-30 11:58:04,918 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"@\"\\r\\n'\n", - "2026-03-30 11:58:04,930 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"SR\"\\r\\n'\n", - "2026-03-30 11:58:04,932 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"SR\"\\r\\n'\n", - "2026-03-30 11:58:04,946 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"T\"\\r\\n'\n", - "2026-03-30 11:58:04,947 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"T\"\\r\\n'\n", - "2026-03-30 11:58:04,963 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"TA\"\\r\\n'\n", - "2026-03-30 11:58:04,964 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"TA\"\\r\\n'\n", - "2026-03-30 11:58:04,978 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"TAC\"\\r\\n'\n", - "2026-03-30 11:58:04,982 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"TAC\"\\r\\n'\n", - "2026-03-30 11:58:04,984 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"TI\"\\r\\n'\n", - "2026-03-30 11:58:04,986 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"TI\"\\r\\n'\n", - "2026-03-30 11:58:04,994 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C0\"\\r\\n'\n", - "2026-03-30 11:58:04,995 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"C0\"\\r\\n'\n", - "2026-03-30 11:58:05,010 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C1\"\\r\\n'\n", - "2026-03-30 11:58:05,011 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"C1\"\\r\\n'\n", - "2026-03-30 11:58:05,028 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C2\"\\r\\n'\n", - "2026-03-30 11:58:05,029 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"C2\"\\r\\n'\n", - "2026-03-30 11:58:05,043 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C3\"\\r\\n'\n", - "2026-03-30 11:58:05,044 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"C3\"\\r\\n'\n", - "2026-03-30 11:58:05,058 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"COM\"\\r\\n'\n", - "2026-03-30 11:58:05,059 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"COM\"\\r\\n'\n", - "2026-03-30 11:58:05,076 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"DAT\"\\r\\n'\n", - "2026-03-30 11:58:05,078 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"DAT\"\\r\\n'\n", - "2026-03-30 11:58:05,091 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I10\"\\r\\n'\n", - "2026-03-30 11:58:05,092 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I10\"\\r\\n'\n", - "2026-03-30 11:58:05,096 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I11\"\\r\\n'\n", - "2026-03-30 11:58:05,097 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I11\"\\r\\n'\n", - "2026-03-30 11:58:05,106 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I14\"\\r\\n'\n", - "2026-03-30 11:58:05,107 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I14\"\\r\\n'\n", - "2026-03-30 11:58:05,122 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I15\"\\r\\n'\n", - "2026-03-30 11:58:05,124 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I15\"\\r\\n'\n", - "2026-03-30 11:58:05,138 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I16\"\\r\\n'\n", - "2026-03-30 11:58:05,139 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I16\"\\r\\n'\n", - "2026-03-30 11:58:05,159 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I21\"\\r\\n'\n", - "2026-03-30 11:58:05,163 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I21\"\\r\\n'\n", - "2026-03-30 11:58:05,171 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I22\"\\r\\n'\n", - "2026-03-30 11:58:05,173 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I22\"\\r\\n'\n", - "2026-03-30 11:58:05,190 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I23\"\\r\\n'\n", - "2026-03-30 11:58:05,192 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I23\"\\r\\n'\n", - "2026-03-30 11:58:05,210 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I24\"\\r\\n'\n", - "2026-03-30 11:58:05,211 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I24\"\\r\\n'\n", - "2026-03-30 11:58:05,218 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I25\"\\r\\n'\n", - "2026-03-30 11:58:05,221 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I25\"\\r\\n'\n", - "2026-03-30 11:58:05,234 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I26\"\\r\\n'\n", - "2026-03-30 11:58:05,238 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I26\"\\r\\n'\n", - "2026-03-30 11:58:05,250 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M01\"\\r\\n'\n", - "2026-03-30 11:58:05,251 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M01\"\\r\\n'\n", - "2026-03-30 11:58:05,270 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M02\"\\r\\n'\n", - "2026-03-30 11:58:05,271 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M02\"\\r\\n'\n", - "2026-03-30 11:58:05,276 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M03\"\\r\\n'\n", - "2026-03-30 11:58:05,277 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M03\"\\r\\n'\n", - "2026-03-30 11:58:05,282 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M17\"\\r\\n'\n", - "2026-03-30 11:58:05,285 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M17\"\\r\\n'\n", - "2026-03-30 11:58:05,298 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M18\"\\r\\n'\n", - "2026-03-30 11:58:05,299 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M18\"\\r\\n'\n", - "2026-03-30 11:58:05,314 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M19\"\\r\\n'\n", - "2026-03-30 11:58:05,316 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M19\"\\r\\n'\n", - "2026-03-30 11:58:05,330 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M20\"\\r\\n'\n", - "2026-03-30 11:58:05,331 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M20\"\\r\\n'\n", - "2026-03-30 11:58:05,347 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M21\"\\r\\n'\n", - "2026-03-30 11:58:05,348 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M21\"\\r\\n'\n", - "2026-03-30 11:58:05,362 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M27\"\\r\\n'\n", - "2026-03-30 11:58:05,363 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M27\"\\r\\n'\n", - "2026-03-30 11:58:05,380 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M28\"\\r\\n'\n", - "2026-03-30 11:58:05,382 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M28\"\\r\\n'\n", - "2026-03-30 11:58:05,399 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M29\"\\r\\n'\n", - "2026-03-30 11:58:05,401 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M29\"\\r\\n'\n", - "2026-03-30 11:58:05,410 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M31\"\\r\\n'\n", - "2026-03-30 11:58:05,412 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M31\"\\r\\n'\n", - "2026-03-30 11:58:05,426 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M32\"\\r\\n'\n", - "2026-03-30 11:58:05,427 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M32\"\\r\\n'\n", - "2026-03-30 11:58:05,429 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M33\"\\r\\n'\n", - "2026-03-30 11:58:05,430 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M33\"\\r\\n'\n", - "2026-03-30 11:58:05,442 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M35\"\\r\\n'\n", - "2026-03-30 11:58:05,443 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M35\"\\r\\n'\n", - "2026-03-30 11:58:05,458 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"SIS\"\\r\\n'\n", - "2026-03-30 11:58:05,459 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"SIS\"\\r\\n'\n", - "2026-03-30 11:58:05,474 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"SNR\"\\r\\n'\n", - "2026-03-30 11:58:05,475 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"SNR\"\\r\\n'\n", - "2026-03-30 11:58:05,490 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TIM\"\\r\\n'\n", - "2026-03-30 11:58:05,491 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TIM\"\\r\\n'\n", - "2026-03-30 11:58:05,506 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST0\"\\r\\n'\n", - "2026-03-30 11:58:05,512 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TST0\"\\r\\n'\n", - "2026-03-30 11:58:05,521 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST1\"\\r\\n'\n", - "2026-03-30 11:58:05,522 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TST1\"\\r\\n'\n", - "2026-03-30 11:58:05,538 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST2\"\\r\\n'\n", - "2026-03-30 11:58:05,539 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TST2\"\\r\\n'\n", - "2026-03-30 11:58:05,553 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST3\"\\r\\n'\n", - "2026-03-30 11:58:05,556 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TST3\"\\r\\n'\n", - "2026-03-30 11:58:05,569 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"UPD\"\\r\\n'\n", - "2026-03-30 11:58:05,570 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"UPD\"\\r\\n'\n", - "2026-03-30 11:58:05,588 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"FCUT\"\\r\\n'\n", - "2026-03-30 11:58:05,589 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 3 \"FCUT\"\\r\\n'\n", - "2026-03-30 11:58:05,601 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"FSET\"\\r\\n'\n", - "2026-03-30 11:58:05,602 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 3 \"FSET\"\\r\\n'\n", - "2026-03-30 11:58:05,621 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"LST\"\\r\\n'\n", - "2026-03-30 11:58:05,622 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 3 \"LST\"\\r\\n'\n", - "2026-03-30 11:58:05,634 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"RDB\"\\r\\n'\n", - "2026-03-30 11:58:05,635 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 3 \"RDB\"\\r\\n'\n", - "2026-03-30 11:58:05,649 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 A 3 \"USTB\"\\r\\n'\n", - "2026-03-30 11:58:05,650 - pylabrobot - IO - [MT Scale] Received response: b'I0 A 3 \"USTB\"\\r\\n'\n" + "2026-03-30 12:07:28,202 - pylabrobot - IO - [MT Scale] Sent command: I0\n", + "2026-03-30 12:07:28,210 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I0\\r\\n'\n", + "2026-03-30 12:07:28,239 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I0\"\\r\\n'\n", + "2026-03-30 12:07:28,242 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I0\"\\r\\n'\n", + "2026-03-30 12:07:28,255 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I1\"\\r\\n'\n", + "2026-03-30 12:07:28,256 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I1\"\\r\\n'\n", + "2026-03-30 12:07:28,270 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I2\"\\r\\n'\n", + "2026-03-30 12:07:28,271 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I2\"\\r\\n'\n", + "2026-03-30 12:07:28,287 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I3\"\\r\\n'\n", + "2026-03-30 12:07:28,288 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I3\"\\r\\n'\n", + "2026-03-30 12:07:28,291 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I4\"\\r\\n'\n", + "2026-03-30 12:07:28,292 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I4\"\\r\\n'\n", + "2026-03-30 12:07:28,305 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I5\"\\r\\n'\n", + "2026-03-30 12:07:28,307 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I5\"\\r\\n'\n", + "2026-03-30 12:07:28,321 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"S\"\\r\\n'\n", + "2026-03-30 12:07:28,322 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"S\"\\r\\n'\n", + "2026-03-30 12:07:28,336 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"SI\"\\r\\n'\n", + "2026-03-30 12:07:28,337 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"SI\"\\r\\n'\n", + "2026-03-30 12:07:28,350 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"SIR\"\\r\\n'\n", + "2026-03-30 12:07:28,351 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"SIR\"\\r\\n'\n", + "2026-03-30 12:07:28,367 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"Z\"\\r\\n'\n", + "2026-03-30 12:07:28,369 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"Z\"\\r\\n'\n", + "2026-03-30 12:07:28,371 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"ZI\"\\r\\n'\n", + "2026-03-30 12:07:28,372 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"ZI\"\\r\\n'\n", + "2026-03-30 12:07:28,383 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"@\"\\r\\n'\n", + "2026-03-30 12:07:28,386 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"@\"\\r\\n'\n", + "2026-03-30 12:07:28,399 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"SR\"\\r\\n'\n", + "2026-03-30 12:07:28,403 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"SR\"\\r\\n'\n", + "2026-03-30 12:07:28,416 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"T\"\\r\\n'\n", + "2026-03-30 12:07:28,418 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"T\"\\r\\n'\n", + "2026-03-30 12:07:28,431 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"TA\"\\r\\n'\n", + "2026-03-30 12:07:28,433 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"TA\"\\r\\n'\n", + "2026-03-30 12:07:28,448 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"TAC\"\\r\\n'\n", + "2026-03-30 12:07:28,453 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"TAC\"\\r\\n'\n", + "2026-03-30 12:07:28,460 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"TI\"\\r\\n'\n", + "2026-03-30 12:07:28,462 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"TI\"\\r\\n'\n", + "2026-03-30 12:07:28,464 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C0\"\\r\\n'\n", + "2026-03-30 12:07:28,465 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"C0\"\\r\\n'\n", + "2026-03-30 12:07:28,480 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C1\"\\r\\n'\n", + "2026-03-30 12:07:28,484 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"C1\"\\r\\n'\n", + "2026-03-30 12:07:28,496 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C2\"\\r\\n'\n", + "2026-03-30 12:07:28,499 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"C2\"\\r\\n'\n", + "2026-03-30 12:07:28,511 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C3\"\\r\\n'\n", + "2026-03-30 12:07:28,514 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"C3\"\\r\\n'\n", + "2026-03-30 12:07:28,527 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"COM\"\\r\\n'\n", + "2026-03-30 12:07:28,532 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"COM\"\\r\\n'\n", + "2026-03-30 12:07:28,545 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"DAT\"\\r\\n'\n", + "2026-03-30 12:07:28,549 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"DAT\"\\r\\n'\n", + "2026-03-30 12:07:28,559 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I10\"\\r\\n'\n", + "2026-03-30 12:07:28,561 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I10\"\\r\\n'\n", + "2026-03-30 12:07:28,576 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I11\"\\r\\n'\n", + "2026-03-30 12:07:28,581 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I11\"\\r\\n'\n", + "2026-03-30 12:07:28,583 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I14\"\\r\\n'\n", + "2026-03-30 12:07:28,584 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I14\"\\r\\n'\n", + "2026-03-30 12:07:28,591 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I15\"\\r\\n'\n", + "2026-03-30 12:07:28,594 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I15\"\\r\\n'\n", + "2026-03-30 12:07:28,609 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I16\"\\r\\n'\n", + "2026-03-30 12:07:28,610 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I16\"\\r\\n'\n", + "2026-03-30 12:07:28,622 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I21\"\\r\\n'\n", + "2026-03-30 12:07:28,623 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I21\"\\r\\n'\n", + "2026-03-30 12:07:28,638 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I22\"\\r\\n'\n", + "2026-03-30 12:07:28,639 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I22\"\\r\\n'\n", + "2026-03-30 12:07:28,655 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I23\"\\r\\n'\n", + "2026-03-30 12:07:28,656 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I23\"\\r\\n'\n", + "2026-03-30 12:07:28,672 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I24\"\\r\\n'\n", + "2026-03-30 12:07:28,673 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I24\"\\r\\n'\n", + "2026-03-30 12:07:28,687 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I25\"\\r\\n'\n", + "2026-03-30 12:07:28,688 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I25\"\\r\\n'\n", + "2026-03-30 12:07:28,702 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I26\"\\r\\n'\n", + "2026-03-30 12:07:28,705 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I26\"\\r\\n'\n", + "2026-03-30 12:07:28,719 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M01\"\\r\\n'\n", + "2026-03-30 12:07:28,722 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M01\"\\r\\n'\n", + "2026-03-30 12:07:28,735 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M02\"\\r\\n'\n", + "2026-03-30 12:07:28,737 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M02\"\\r\\n'\n", + "2026-03-30 12:07:28,740 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M03\"\\r\\n'\n", + "2026-03-30 12:07:28,748 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M03\"\\r\\n'\n", + "2026-03-30 12:07:28,753 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M17\"\\r\\n'\n", + "2026-03-30 12:07:28,754 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M17\"\\r\\n'\n", + "2026-03-30 12:07:28,767 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M18\"\\r\\n'\n", + "2026-03-30 12:07:28,768 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M18\"\\r\\n'\n", + "2026-03-30 12:07:28,782 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M19\"\\r\\n'\n", + "2026-03-30 12:07:28,785 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M19\"\\r\\n'\n", + "2026-03-30 12:07:28,799 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M20\"\\r\\n'\n", + "2026-03-30 12:07:28,801 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M20\"\\r\\n'\n", + "2026-03-30 12:07:28,814 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M21\"\\r\\n'\n", + "2026-03-30 12:07:28,818 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M21\"\\r\\n'\n", + "2026-03-30 12:07:28,830 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M27\"\\r\\n'\n", + "2026-03-30 12:07:28,833 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M27\"\\r\\n'\n", + "2026-03-30 12:07:28,847 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M28\"\\r\\n'\n", + "2026-03-30 12:07:28,848 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M28\"\\r\\n'\n", + "2026-03-30 12:07:28,862 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M29\"\\r\\n'\n", + "2026-03-30 12:07:28,864 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M29\"\\r\\n'\n", + "2026-03-30 12:07:28,879 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M31\"\\r\\n'\n", + "2026-03-30 12:07:28,880 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M31\"\\r\\n'\n", + "2026-03-30 12:07:28,894 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M32\"\\r\\n'\n", + "2026-03-30 12:07:28,895 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M32\"\\r\\n'\n", + "2026-03-30 12:07:28,911 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M33\"\\r\\n'\n", + "2026-03-30 12:07:28,912 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M33\"\\r\\n'\n", + "2026-03-30 12:07:28,925 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M35\"\\r\\n'\n", + "2026-03-30 12:07:28,926 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M35\"\\r\\n'\n", + "2026-03-30 12:07:28,929 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"SIS\"\\r\\n'\n", + "2026-03-30 12:07:28,931 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"SIS\"\\r\\n'\n", + "2026-03-30 12:07:28,942 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"SNR\"\\r\\n'\n", + "2026-03-30 12:07:28,948 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"SNR\"\\r\\n'\n", + "2026-03-30 12:07:28,961 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TIM\"\\r\\n'\n", + "2026-03-30 12:07:28,962 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TIM\"\\r\\n'\n", + "2026-03-30 12:07:28,974 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST0\"\\r\\n'\n", + "2026-03-30 12:07:28,978 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TST0\"\\r\\n'\n", + "2026-03-30 12:07:28,991 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST1\"\\r\\n'\n", + "2026-03-30 12:07:28,992 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TST1\"\\r\\n'\n", + "2026-03-30 12:07:29,008 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST2\"\\r\\n'\n", + "2026-03-30 12:07:29,009 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TST2\"\\r\\n'\n", + "2026-03-30 12:07:29,022 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST3\"\\r\\n'\n", + "2026-03-30 12:07:29,023 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TST3\"\\r\\n'\n", + "2026-03-30 12:07:29,039 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"UPD\"\\r\\n'\n", + "2026-03-30 12:07:29,040 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"UPD\"\\r\\n'\n", + "2026-03-30 12:07:29,062 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"FCUT\"\\r\\n'\n", + "2026-03-30 12:07:29,063 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 3 \"FCUT\"\\r\\n'\n", + "2026-03-30 12:07:29,071 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"FSET\"\\r\\n'\n", + "2026-03-30 12:07:29,073 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 3 \"FSET\"\\r\\n'\n", + "2026-03-30 12:07:29,087 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"LST\"\\r\\n'\n", + "2026-03-30 12:07:29,088 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 3 \"LST\"\\r\\n'\n", + "2026-03-30 12:07:29,102 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"RDB\"\\r\\n'\n", + "2026-03-30 12:07:29,106 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 3 \"RDB\"\\r\\n'\n", + "2026-03-30 12:07:29,119 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 A 3 \"USTB\"\\r\\n'\n", + "2026-03-30 12:07:29,122 - pylabrobot - IO - [MT Scale] Received response: b'I0 A 3 \"USTB\"\\r\\n'\n" ] }, { @@ -537,18 +588,18 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 6, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 11:58:05,659 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] reset_input_buffer\n", - "2026-03-30 11:58:05,661 - pylabrobot - IO - [MT Scale] Sent command: @\n", - "2026-03-30 11:58:05,663 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'@\\r\\n'\n", - "2026-03-30 11:58:05,714 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I4 A \"B207696838\"\\r\\n'\n", - "2026-03-30 11:58:05,715 - pylabrobot - IO - [MT Scale] Received response: b'I4 A \"B207696838\"\\r\\n'\n" + "2026-03-30 12:07:29,155 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] reset_input_buffer\n", + "2026-03-30 12:07:29,157 - pylabrobot - IO - [MT Scale] Sent command: @\n", + "2026-03-30 12:07:29,160 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'@\\r\\n'\n", + "2026-03-30 12:07:29,214 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I4 A \"B207696838\"\\r\\n'\n", + "2026-03-30 12:07:29,215 - pylabrobot - IO - [MT Scale] Received response: b'I4 A \"B207696838\"\\r\\n'\n" ] }, { @@ -576,17 +627,17 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 7, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 11:58:05,730 - pylabrobot - IO - [MT Scale] Sent command: I4\n", - "2026-03-30 11:58:05,735 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I4\\r\\n'\n", - "2026-03-30 11:58:05,777 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I4 A \"B207696838\"\\r\\n'\n", - "2026-03-30 11:58:05,779 - pylabrobot - IO - [MT Scale] Received response: b'I4 A \"B207696838\"\\r\\n'\n" + "2026-03-30 12:07:29,220 - pylabrobot - IO - [MT Scale] Sent command: I4\n", + "2026-03-30 12:07:29,222 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I4\\r\\n'\n", + "2026-03-30 12:07:29,263 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I4 A \"B207696838\"\\r\\n'\n", + "2026-03-30 12:07:29,265 - pylabrobot - IO - [MT Scale] Received response: b'I4 A \"B207696838\"\\r\\n'\n" ] }, { @@ -614,21 +665,21 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 8, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 11:58:05,798 - pylabrobot - IO - [MT Scale] Sent command: I2\n", - "2026-03-30 11:58:05,806 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I2\\r\\n'\n", - "2026-03-30 11:58:05,873 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", - "2026-03-30 11:58:05,874 - pylabrobot - IO - [MT Scale] Received response: b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", - "2026-03-30 11:58:05,878 - pylabrobot - IO - [MT Scale] Sent command: I2\n", - "2026-03-30 11:58:05,881 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I2\\r\\n'\n", - "2026-03-30 11:58:05,938 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", - "2026-03-30 11:58:05,938 - pylabrobot - IO - [MT Scale] Received response: b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n" + "2026-03-30 12:07:29,286 - pylabrobot - IO - [MT Scale] Sent command: I2\n", + "2026-03-30 12:07:29,292 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I2\\r\\n'\n", + "2026-03-30 12:07:29,360 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", + "2026-03-30 12:07:29,361 - pylabrobot - IO - [MT Scale] Received response: b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", + "2026-03-30 12:07:29,363 - pylabrobot - IO - [MT Scale] Sent command: I2\n", + "2026-03-30 12:07:29,364 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I2\\r\\n'\n", + "2026-03-30 12:07:29,422 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", + "2026-03-30 12:07:29,423 - pylabrobot - IO - [MT Scale] Received response: b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n" ] }, { @@ -660,17 +711,17 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 9, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 11:58:05,945 - pylabrobot - IO - [MT Scale] Sent command: I1\n", - "2026-03-30 11:58:05,947 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I1\\r\\n'\n", - "2026-03-30 11:58:06,001 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I1 A \"01\" \"2.30\" \"2.22\" \"\" \"\"\\r\\n'\n", - "2026-03-30 11:58:06,002 - pylabrobot - IO - [MT Scale] Received response: b'I1 A \"01\" \"2.30\" \"2.22\" \"\" \"\"\\r\\n'\n" + "2026-03-30 12:07:29,431 - pylabrobot - IO - [MT Scale] Sent command: I1\n", + "2026-03-30 12:07:29,434 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I1\\r\\n'\n", + "2026-03-30 12:07:29,486 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I1 A \"01\" \"2.30\" \"2.22\" \"\" \"\"\\r\\n'\n", + "2026-03-30 12:07:29,487 - pylabrobot - IO - [MT Scale] Received response: b'I1 A \"01\" \"2.30\" \"2.22\" \"\" \"\"\\r\\n'\n" ] }, { @@ -701,24 +752,24 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": 10, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 11:58:06,016 - pylabrobot - IO - [MT Scale] Sent command: S\n", - "2026-03-30 11:58:06,020 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", - "2026-03-30 11:58:06,226 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00003 g\\r\\n'\n", - "2026-03-30 11:58:06,226 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00003 g\\r\\n'\n" + "2026-03-30 12:07:29,495 - pylabrobot - IO - [MT Scale] Sent command: S\n", + "2026-03-30 12:07:29,499 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", + "2026-03-30 12:07:29,726 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00009 g\\r\\n'\n", + "2026-03-30 12:07:29,728 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00009 g\\r\\n'\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ - "Stable weight (empty pan): 3e-05 g\n", + "Stable weight (empty pan): 9e-05 g\n", "PASS: stable weight returns float\n" ] } @@ -739,24 +790,24 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": 11, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 11:58:06,232 - pylabrobot - IO - [MT Scale] Sent command: SI\n", - "2026-03-30 11:58:06,233 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", - "2026-03-30 11:58:06,275 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00003 g\\r\\n'\n", - "2026-03-30 11:58:06,276 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00003 g\\r\\n'\n" + "2026-03-30 12:07:29,746 - pylabrobot - IO - [MT Scale] Sent command: SI\n", + "2026-03-30 12:07:29,751 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", + "2026-03-30 12:07:29,790 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00009 g\\r\\n'\n", + "2026-03-30 12:07:29,791 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00009 g\\r\\n'\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ - "Immediate weight: 3e-05 g\n", + "Immediate weight: 9e-05 g\n", "PASS: immediate weight returns float\n" ] } @@ -777,21 +828,21 @@ }, { "cell_type": "code", - "execution_count": 11, + "execution_count": 12, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 11:58:06,281 - pylabrobot - IO - [MT Scale] Sent command: Z\n", - "2026-03-30 11:58:06,284 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'Z\\r\\n'\n", - "2026-03-30 11:58:06,513 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'Z A\\r\\n'\n", - "2026-03-30 11:58:06,514 - pylabrobot - IO - [MT Scale] Received response: b'Z A\\r\\n'\n", - "2026-03-30 11:58:06,516 - pylabrobot - IO - [MT Scale] Sent command: SI\n", - "2026-03-30 11:58:06,519 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", - "2026-03-30 11:58:06,561 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 11:58:06,562 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n" + "2026-03-30 12:07:29,802 - pylabrobot - IO - [MT Scale] Sent command: Z\n", + "2026-03-30 12:07:29,806 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'Z\\r\\n'\n", + "2026-03-30 12:07:30,109 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'Z A\\r\\n'\n", + "2026-03-30 12:07:30,110 - pylabrobot - IO - [MT Scale] Received response: b'Z A\\r\\n'\n", + "2026-03-30 12:07:30,111 - pylabrobot - IO - [MT Scale] Sent command: SI\n", + "2026-03-30 12:07:30,112 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", + "2026-03-30 12:07:30,141 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 12:07:30,142 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n" ] }, { @@ -820,21 +871,21 @@ }, { "cell_type": "code", - "execution_count": 12, + "execution_count": 13, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 11:58:06,571 - pylabrobot - IO - [MT Scale] Sent command: ZI\n", - "2026-03-30 11:58:06,578 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'ZI\\r\\n'\n", - "2026-03-30 11:58:06,610 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'ZI S\\r\\n'\n", - "2026-03-30 11:58:06,611 - pylabrobot - IO - [MT Scale] Received response: b'ZI S\\r\\n'\n", - "2026-03-30 11:58:06,612 - pylabrobot - IO - [MT Scale] Sent command: SI\n", - "2026-03-30 11:58:06,615 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", - "2026-03-30 11:58:06,657 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 11:58:06,661 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n" + "2026-03-30 12:07:30,149 - pylabrobot - IO - [MT Scale] Sent command: ZI\n", + "2026-03-30 12:07:30,151 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'ZI\\r\\n'\n", + "2026-03-30 12:07:30,173 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'ZI S\\r\\n'\n", + "2026-03-30 12:07:30,175 - pylabrobot - IO - [MT Scale] Received response: b'ZI S\\r\\n'\n", + "2026-03-30 12:07:30,176 - pylabrobot - IO - [MT Scale] Sent command: SI\n", + "2026-03-30 12:07:30,178 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", + "2026-03-30 12:07:30,206 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 12:07:30,207 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n" ] }, { @@ -873,7 +924,7 @@ }, { "cell_type": "code", - "execution_count": 13, + "execution_count": 14, "metadata": {}, "outputs": [ { @@ -887,18 +938,18 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 11:58:15,260 - pylabrobot - IO - [MT Scale] Sent command: Z\n", - "2026-03-30 11:58:15,262 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'Z\\r\\n'\n", - "2026-03-30 11:58:15,561 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'Z A\\r\\n'\n", - "2026-03-30 11:58:15,562 - pylabrobot - IO - [MT Scale] Received response: b'Z A\\r\\n'\n", - "2026-03-30 11:58:15,564 - pylabrobot - IO - [MT Scale] Sent command: T\n", - "2026-03-30 11:58:15,569 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'T\\r\\n'\n", - "2026-03-30 11:58:15,976 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'T S 0.00000 g\\r\\n'\n", - "2026-03-30 11:58:15,977 - pylabrobot - IO - [MT Scale] Received response: b'T S 0.00000 g\\r\\n'\n", - "2026-03-30 11:58:15,979 - pylabrobot - IO - [MT Scale] Sent command: TA\n", - "2026-03-30 11:58:15,981 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'TA\\r\\n'\n", - "2026-03-30 11:58:16,056 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'TA A 0.00000 g\\r\\n'\n", - "2026-03-30 11:58:16,058 - pylabrobot - IO - [MT Scale] Received response: b'TA A 0.00000 g\\r\\n'\n" + "2026-03-30 12:08:02,193 - pylabrobot - IO - [MT Scale] Sent command: Z\n", + "2026-03-30 12:08:02,196 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'Z\\r\\n'\n", + "2026-03-30 12:08:02,545 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'Z A\\r\\n'\n", + "2026-03-30 12:08:02,545 - pylabrobot - IO - [MT Scale] Received response: b'Z A\\r\\n'\n", + "2026-03-30 12:08:02,546 - pylabrobot - IO - [MT Scale] Sent command: T\n", + "2026-03-30 12:08:02,548 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'T\\r\\n'\n", + "2026-03-30 12:08:02,960 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'T S 0.00000 g\\r\\n'\n", + "2026-03-30 12:08:02,961 - pylabrobot - IO - [MT Scale] Received response: b'T S 0.00000 g\\r\\n'\n", + "2026-03-30 12:08:02,962 - pylabrobot - IO - [MT Scale] Sent command: TA\n", + "2026-03-30 12:08:02,965 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'TA\\r\\n'\n", + "2026-03-30 12:08:03,056 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'TA A 0.00000 g\\r\\n'\n", + "2026-03-30 12:08:03,057 - pylabrobot - IO - [MT Scale] Received response: b'TA A 0.00000 g\\r\\n'\n" ] }, { @@ -915,7 +966,7 @@ "traceback": [ "\u001b[31m---------------------------------------------------------------------------\u001b[39m", "\u001b[31mAssertionError\u001b[39m Traceback (most recent call last)", - "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[13]\u001b[39m\u001b[32m, line 6\u001b[39m\n\u001b[32m 4\u001b[39m tare = \u001b[38;5;28;01mawait\u001b[39;00m scale.request_tare_weight()\n\u001b[32m 5\u001b[39m \u001b[38;5;28mprint\u001b[39m(\u001b[33mf\u001b[39m\u001b[33m\"\u001b[39m\u001b[33mTare weight: \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mtare\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m g\u001b[39m\u001b[33m\"\u001b[39m)\n\u001b[32m----> \u001b[39m\u001b[32m6\u001b[39m \u001b[38;5;28;01massert\u001b[39;00m tare > \u001b[32m0\u001b[39m, \u001b[33mf\u001b[39m\u001b[33m\"\u001b[39m\u001b[33mExpected positive tare, got \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mtare\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m\"\u001b[39m\n\u001b[32m 7\u001b[39m \u001b[38;5;28mprint\u001b[39m(\u001b[33m\"\u001b[39m\u001b[33mPASS: tare stores container weight\u001b[39m\u001b[33m\"\u001b[39m)\n", + "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[14]\u001b[39m\u001b[32m, line 6\u001b[39m\n\u001b[32m 4\u001b[39m tare = \u001b[38;5;28;01mawait\u001b[39;00m scale.request_tare_weight()\n\u001b[32m 5\u001b[39m \u001b[38;5;28mprint\u001b[39m(\u001b[33mf\u001b[39m\u001b[33m\"\u001b[39m\u001b[33mTare weight: \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mtare\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m g\u001b[39m\u001b[33m\"\u001b[39m)\n\u001b[32m----> \u001b[39m\u001b[32m6\u001b[39m \u001b[38;5;28;01massert\u001b[39;00m tare > \u001b[32m0\u001b[39m, \u001b[33mf\u001b[39m\u001b[33m\"\u001b[39m\u001b[33mExpected positive tare, got \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mtare\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m\"\u001b[39m\n\u001b[32m 7\u001b[39m \u001b[38;5;28mprint\u001b[39m(\u001b[33m\"\u001b[39m\u001b[33mPASS: tare stores container weight\u001b[39m\u001b[33m\"\u001b[39m)\n", "\u001b[31mAssertionError\u001b[39m: Expected positive tare, got 0.0" ] } @@ -939,17 +990,17 @@ }, { "cell_type": "code", - "execution_count": 14, + "execution_count": 15, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 11:58:19,372 - pylabrobot - IO - [MT Scale] Sent command: TA\n", - "2026-03-30 11:58:19,377 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'TA\\r\\n'\n", - "2026-03-30 11:58:19,494 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'TA A 0.00000 g\\r\\n'\n", - "2026-03-30 11:58:19,505 - pylabrobot - IO - [MT Scale] Received response: b'TA A 0.00000 g\\r\\n'\n" + "2026-03-30 12:08:06,275 - pylabrobot - IO - [MT Scale] Sent command: TA\n", + "2026-03-30 12:08:06,277 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'TA\\r\\n'\n", + "2026-03-30 12:08:06,397 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'TA A 0.00000 g\\r\\n'\n", + "2026-03-30 12:08:06,398 - pylabrobot - IO - [MT Scale] Received response: b'TA A 0.00000 g\\r\\n'\n" ] }, { @@ -977,21 +1028,21 @@ }, { "cell_type": "code", - "execution_count": 15, + "execution_count": 16, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 11:58:20,342 - pylabrobot - IO - [MT Scale] Sent command: TAC\n", - "2026-03-30 11:58:20,346 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'TAC\\r\\n'\n", - "2026-03-30 11:58:20,372 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'TAC A\\r\\n'\n", - "2026-03-30 11:58:20,373 - pylabrobot - IO - [MT Scale] Received response: b'TAC A\\r\\n'\n", - "2026-03-30 11:58:20,375 - pylabrobot - IO - [MT Scale] Sent command: TA\n", - "2026-03-30 11:58:20,379 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'TA\\r\\n'\n", - "2026-03-30 11:58:20,485 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'TA A 0.00000 g\\r\\n'\n", - "2026-03-30 11:58:20,486 - pylabrobot - IO - [MT Scale] Received response: b'TA A 0.00000 g\\r\\n'\n" + "2026-03-30 12:08:07,124 - pylabrobot - IO - [MT Scale] Sent command: TAC\n", + "2026-03-30 12:08:07,130 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'TAC\\r\\n'\n", + "2026-03-30 12:08:07,148 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'TAC A\\r\\n'\n", + "2026-03-30 12:08:07,149 - pylabrobot - IO - [MT Scale] Received response: b'TAC A\\r\\n'\n", + "2026-03-30 12:08:07,150 - pylabrobot - IO - [MT Scale] Sent command: TA\n", + "2026-03-30 12:08:07,150 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'TA\\r\\n'\n", + "2026-03-30 12:08:07,276 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'TA A 0.00000 g\\r\\n'\n", + "2026-03-30 12:08:07,278 - pylabrobot - IO - [MT Scale] Received response: b'TA A 0.00000 g\\r\\n'\n" ] }, { @@ -1020,17 +1071,17 @@ }, { "cell_type": "code", - "execution_count": 16, + "execution_count": 17, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 11:58:21,318 - pylabrobot - IO - [MT Scale] Sent command: SC 3000\n", - "2026-03-30 11:58:21,320 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SC 3000\\r\\n'\n", - "2026-03-30 11:58:21,348 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'ES\\r\\n'\n", - "2026-03-30 11:58:21,349 - pylabrobot - IO - [MT Scale] Received response: b'ES\\r\\n'\n" + "2026-03-30 12:08:07,873 - pylabrobot - IO - [MT Scale] Sent command: SC 3000\n", + "2026-03-30 12:08:07,875 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SC 3000\\r\\n'\n", + "2026-03-30 12:08:07,900 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'ES\\r\\n'\n", + "2026-03-30 12:08:07,901 - pylabrobot - IO - [MT Scale] Received response: b'ES\\r\\n'\n" ] }, { @@ -1040,10 +1091,10 @@ "traceback": [ "\u001b[31m---------------------------------------------------------------------------\u001b[39m", "\u001b[31mMettlerToledoError\u001b[39m Traceback (most recent call last)", - "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[16]\u001b[39m\u001b[32m, line 1\u001b[39m\n\u001b[32m----> \u001b[39m\u001b[32m1\u001b[39m weight = \u001b[38;5;28;01mawait\u001b[39;00m backend.read_dynamic_weight(timeout=\u001b[32m3.0\u001b[39m)\n\u001b[32m 2\u001b[39m \u001b[38;5;28mprint\u001b[39m(\u001b[33mf\u001b[39m\u001b[33m\"\u001b[39m\u001b[33mDynamic weight (3s timeout): \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mweight\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m g\u001b[39m\u001b[33m\"\u001b[39m)\n\u001b[32m 3\u001b[39m \u001b[38;5;28;01massert\u001b[39;00m \u001b[38;5;28misinstance\u001b[39m(weight, \u001b[38;5;28mfloat\u001b[39m)\n", - "\u001b[36mFile \u001b[39m\u001b[32m~/Desktop/GitHub/pylabrobot/pylabrobot/scales/mettler_toledo/backend.py:513\u001b[39m, in \u001b[36mMettlerToledoWXS205SDUBackend.read_dynamic_weight\u001b[39m\u001b[34m(self, timeout)\u001b[39m\n\u001b[32m 504\u001b[39m \u001b[38;5;250m\u001b[39m\u001b[33;03m\"\"\"Read a stable weight value from the machine within a given timeout, or\u001b[39;00m\n\u001b[32m 505\u001b[39m \u001b[33;03mreturn the current weight value if not possible. (MEASUREMENT command)\u001b[39;00m\n\u001b[32m 506\u001b[39m \n\u001b[32m 507\u001b[39m \u001b[33;03mArgs:\u001b[39;00m\n\u001b[32m 508\u001b[39m \u001b[33;03m timeout: The timeout in seconds.\u001b[39;00m\n\u001b[32m 509\u001b[39m \u001b[33;03m\"\"\"\u001b[39;00m\n\u001b[32m 511\u001b[39m timeout = \u001b[38;5;28mint\u001b[39m(timeout * \u001b[32m1000\u001b[39m) \u001b[38;5;66;03m# convert to milliseconds\u001b[39;00m\n\u001b[32m--> \u001b[39m\u001b[32m513\u001b[39m responses = \u001b[38;5;28;01mawait\u001b[39;00m \u001b[38;5;28mself\u001b[39m.send_command(\u001b[33mf\u001b[39m\u001b[33m\"\u001b[39m\u001b[33mSC \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mtimeout\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m\"\u001b[39m)\n\u001b[32m 514\u001b[39m \u001b[38;5;28mself\u001b[39m._validate_response(responses[\u001b[32m0\u001b[39m], \u001b[32m4\u001b[39m, \u001b[33m\"\u001b[39m\u001b[33mSC\u001b[39m\u001b[33m\"\u001b[39m)\n\u001b[32m 515\u001b[39m \u001b[38;5;28mself\u001b[39m._validate_unit(responses[\u001b[32m0\u001b[39m].data[\u001b[32m1\u001b[39m], \u001b[33m\"\u001b[39m\u001b[33mSC\u001b[39m\u001b[33m\"\u001b[39m)\n", - "\u001b[36mFile \u001b[39m\u001b[32m~/Desktop/GitHub/pylabrobot/pylabrobot/scales/mettler_toledo/backend.py:287\u001b[39m, in \u001b[36mMettlerToledoWXS205SDUBackend.send_command\u001b[39m\u001b[34m(self, command, timeout)\u001b[39m\n\u001b[32m 285\u001b[39m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[32m 286\u001b[39m response = MettlerToledoResponse(command=\u001b[33m\"\u001b[39m\u001b[33m\"\u001b[39m, status=\u001b[33m\"\u001b[39m\u001b[33m\"\u001b[39m, data=[])\n\u001b[32m--> \u001b[39m\u001b[32m287\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[43m.\u001b[49m\u001b[43m_parse_basic_errors\u001b[49m\u001b[43m(\u001b[49m\u001b[43mresponse\u001b[49m\u001b[43m)\u001b[49m\n\u001b[32m 288\u001b[39m responses.append(response)\n\u001b[32m 290\u001b[39m \u001b[38;5;66;03m# Status B means more responses follow; anything else (A, etc.) is final\u001b[39;00m\n", - "\u001b[36mFile \u001b[39m\u001b[32m~/Desktop/GitHub/pylabrobot/pylabrobot/scales/mettler_toledo/backend.py:208\u001b[39m, in \u001b[36mMettlerToledoWXS205SDUBackend._parse_basic_errors\u001b[39m\u001b[34m(self, response)\u001b[39m\n\u001b[32m 206\u001b[39m \u001b[38;5;66;03m# General error messages: ES, ET, EL (status is \"\" for these)\u001b[39;00m\n\u001b[32m 207\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m response.command == \u001b[33m\"\u001b[39m\u001b[33mES\u001b[39m\u001b[33m\"\u001b[39m:\n\u001b[32m--> \u001b[39m\u001b[32m208\u001b[39m \u001b[38;5;28;01mraise\u001b[39;00m MettlerToledoError.syntax_error()\n\u001b[32m 209\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m response.command == \u001b[33m\"\u001b[39m\u001b[33mET\u001b[39m\u001b[33m\"\u001b[39m:\n\u001b[32m 210\u001b[39m \u001b[38;5;28;01mraise\u001b[39;00m MettlerToledoError.transmission_error()\n", + "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[17]\u001b[39m\u001b[32m, line 1\u001b[39m\n\u001b[32m----> \u001b[39m\u001b[32m1\u001b[39m weight = \u001b[38;5;28;01mawait\u001b[39;00m backend.read_dynamic_weight(timeout=\u001b[32m3.0\u001b[39m)\n\u001b[32m 2\u001b[39m \u001b[38;5;28mprint\u001b[39m(\u001b[33mf\u001b[39m\u001b[33m\"\u001b[39m\u001b[33mDynamic weight (3s timeout): \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mweight\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m g\u001b[39m\u001b[33m\"\u001b[39m)\n\u001b[32m 3\u001b[39m \u001b[38;5;28;01massert\u001b[39;00m \u001b[38;5;28misinstance\u001b[39m(weight, \u001b[38;5;28mfloat\u001b[39m)\n", + "\u001b[36mFile \u001b[39m\u001b[32m~/Desktop/GitHub/pylabrobot/pylabrobot/scales/mettler_toledo/backend.py:538\u001b[39m, in \u001b[36mMettlerToledoWXS205SDUBackend.read_dynamic_weight\u001b[39m\u001b[34m(self, timeout)\u001b[39m\n\u001b[32m 529\u001b[39m \u001b[38;5;250m\u001b[39m\u001b[33;03m\"\"\"Read a stable weight value from the machine within a given timeout, or\u001b[39;00m\n\u001b[32m 530\u001b[39m \u001b[33;03mreturn the current weight value if not possible. (MEASUREMENT command)\u001b[39;00m\n\u001b[32m 531\u001b[39m \n\u001b[32m 532\u001b[39m \u001b[33;03mArgs:\u001b[39;00m\n\u001b[32m 533\u001b[39m \u001b[33;03m timeout: The timeout in seconds.\u001b[39;00m\n\u001b[32m 534\u001b[39m \u001b[33;03m\"\"\"\u001b[39;00m\n\u001b[32m 536\u001b[39m timeout = \u001b[38;5;28mint\u001b[39m(timeout * \u001b[32m1000\u001b[39m) \u001b[38;5;66;03m# convert to milliseconds\u001b[39;00m\n\u001b[32m--> \u001b[39m\u001b[32m538\u001b[39m responses = \u001b[38;5;28;01mawait\u001b[39;00m \u001b[38;5;28mself\u001b[39m.send_command(\u001b[33mf\u001b[39m\u001b[33m\"\u001b[39m\u001b[33mSC \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mtimeout\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m\"\u001b[39m)\n\u001b[32m 539\u001b[39m \u001b[38;5;28mself\u001b[39m._validate_response(responses[\u001b[32m0\u001b[39m], \u001b[32m4\u001b[39m, \u001b[33m\"\u001b[39m\u001b[33mSC\u001b[39m\u001b[33m\"\u001b[39m)\n\u001b[32m 540\u001b[39m \u001b[38;5;28mself\u001b[39m._validate_unit(responses[\u001b[32m0\u001b[39m].data[\u001b[32m1\u001b[39m], \u001b[33m\"\u001b[39m\u001b[33mSC\u001b[39m\u001b[33m\"\u001b[39m)\n", + "\u001b[36mFile \u001b[39m\u001b[32m~/Desktop/GitHub/pylabrobot/pylabrobot/scales/mettler_toledo/backend.py:312\u001b[39m, in \u001b[36mMettlerToledoWXS205SDUBackend.send_command\u001b[39m\u001b[34m(self, command, timeout)\u001b[39m\n\u001b[32m 310\u001b[39m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[32m 311\u001b[39m response = MettlerToledoResponse(command=\u001b[33m\"\u001b[39m\u001b[33m\"\u001b[39m, status=\u001b[33m\"\u001b[39m\u001b[33m\"\u001b[39m, data=[])\n\u001b[32m--> \u001b[39m\u001b[32m312\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[43m.\u001b[49m\u001b[43m_parse_basic_errors\u001b[49m\u001b[43m(\u001b[49m\u001b[43mresponse\u001b[49m\u001b[43m)\u001b[49m\n\u001b[32m 313\u001b[39m responses.append(response)\n\u001b[32m 315\u001b[39m \u001b[38;5;66;03m# Status B means more responses follow; anything else (A, etc.) is final\u001b[39;00m\n", + "\u001b[36mFile \u001b[39m\u001b[32m~/Desktop/GitHub/pylabrobot/pylabrobot/scales/mettler_toledo/backend.py:233\u001b[39m, in \u001b[36mMettlerToledoWXS205SDUBackend._parse_basic_errors\u001b[39m\u001b[34m(self, response)\u001b[39m\n\u001b[32m 231\u001b[39m \u001b[38;5;66;03m# General error messages: ES, ET, EL (status is \"\" for these)\u001b[39;00m\n\u001b[32m 232\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m response.command == \u001b[33m\"\u001b[39m\u001b[33mES\u001b[39m\u001b[33m\"\u001b[39m:\n\u001b[32m--> \u001b[39m\u001b[32m233\u001b[39m \u001b[38;5;28;01mraise\u001b[39;00m MettlerToledoError.syntax_error()\n\u001b[32m 234\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m response.command == \u001b[33m\"\u001b[39m\u001b[33mET\u001b[39m\u001b[33m\"\u001b[39m:\n\u001b[32m 235\u001b[39m \u001b[38;5;28;01mraise\u001b[39;00m MettlerToledoError.transmission_error()\n", "\u001b[31mMettlerToledoError\u001b[39m: Syntax error: The weigh module/balance has not recognized the received command or the command is not allowed" ] } @@ -1064,17 +1115,17 @@ }, { "cell_type": "code", - "execution_count": 17, + "execution_count": 18, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 11:58:22,758 - pylabrobot - IO - [MT Scale] Sent command: C\n", - "2026-03-30 11:58:22,760 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'C\\r\\n'\n", - "2026-03-30 11:58:22,786 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'ES\\r\\n'\n", - "2026-03-30 11:58:22,787 - pylabrobot - IO - [MT Scale] Received response: b'ES\\r\\n'\n" + "2026-03-30 12:08:08,895 - pylabrobot - IO - [MT Scale] Sent command: C\n", + "2026-03-30 12:08:08,897 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'C\\r\\n'\n", + "2026-03-30 12:08:08,924 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'ES\\r\\n'\n", + "2026-03-30 12:08:08,924 - pylabrobot - IO - [MT Scale] Received response: b'ES\\r\\n'\n" ] }, { @@ -1084,10 +1135,10 @@ "traceback": [ "\u001b[31m---------------------------------------------------------------------------\u001b[39m", "\u001b[31mMettlerToledoError\u001b[39m Traceback (most recent call last)", - "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[17]\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 backend.cancel_all()\n\u001b[32m 2\u001b[39m \u001b[38;5;28mprint\u001b[39m(\u001b[33m\"\u001b[39m\u001b[33mPASS: cancel_all completed without error\u001b[39m\u001b[33m\"\u001b[39m)\n", - "\u001b[36mFile \u001b[39m\u001b[32m~/Desktop/GitHub/pylabrobot/pylabrobot/scales/mettler_toledo/backend.py:325\u001b[39m, in \u001b[36mMettlerToledoWXS205SDUBackend.cancel_all\u001b[39m\u001b[34m(self)\u001b[39m\n\u001b[32m 315\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[34mcancel_all\u001b[39m(\u001b[38;5;28mself\u001b[39m) -> \u001b[38;5;28;01mNone\u001b[39;00m:\n\u001b[32m 316\u001b[39m \u001b[38;5;250m \u001b[39m\u001b[33;03m\"\"\"C - Cancel all active and pending interface commands.\u001b[39;00m\n\u001b[32m 317\u001b[39m \n\u001b[32m 318\u001b[39m \u001b[33;03m Unlike cancel() (@), this does not reset the device - it only cancels\u001b[39;00m\n\u001b[32m (...)\u001b[39m\u001b[32m 323\u001b[39m \u001b[33;03m C A (complete). Both responses are consumed to keep the serial buffer clean.\u001b[39;00m\n\u001b[32m 324\u001b[39m \u001b[33;03m \"\"\"\u001b[39;00m\n\u001b[32m--> \u001b[39m\u001b[32m325\u001b[39m responses = \u001b[38;5;28;01mawait\u001b[39;00m \u001b[38;5;28mself\u001b[39m.send_command(\u001b[33m\"\u001b[39m\u001b[33mC\u001b[39m\u001b[33m\"\u001b[39m)\n\u001b[32m 326\u001b[39m \u001b[38;5;66;03m# send_command reads both C B (started) and C A (complete) automatically\u001b[39;00m\n\u001b[32m 327\u001b[39m \u001b[38;5;28mself\u001b[39m._validate_response(responses[\u001b[32m0\u001b[39m], \u001b[32m2\u001b[39m, \u001b[33m\"\u001b[39m\u001b[33mC\u001b[39m\u001b[33m\"\u001b[39m)\n", - "\u001b[36mFile \u001b[39m\u001b[32m~/Desktop/GitHub/pylabrobot/pylabrobot/scales/mettler_toledo/backend.py:287\u001b[39m, in \u001b[36mMettlerToledoWXS205SDUBackend.send_command\u001b[39m\u001b[34m(self, command, timeout)\u001b[39m\n\u001b[32m 285\u001b[39m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[32m 286\u001b[39m response = MettlerToledoResponse(command=\u001b[33m\"\u001b[39m\u001b[33m\"\u001b[39m, status=\u001b[33m\"\u001b[39m\u001b[33m\"\u001b[39m, data=[])\n\u001b[32m--> \u001b[39m\u001b[32m287\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[43m.\u001b[49m\u001b[43m_parse_basic_errors\u001b[49m\u001b[43m(\u001b[49m\u001b[43mresponse\u001b[49m\u001b[43m)\u001b[49m\n\u001b[32m 288\u001b[39m responses.append(response)\n\u001b[32m 290\u001b[39m \u001b[38;5;66;03m# Status B means more responses follow; anything else (A, etc.) is final\u001b[39;00m\n", - "\u001b[36mFile \u001b[39m\u001b[32m~/Desktop/GitHub/pylabrobot/pylabrobot/scales/mettler_toledo/backend.py:208\u001b[39m, in \u001b[36mMettlerToledoWXS205SDUBackend._parse_basic_errors\u001b[39m\u001b[34m(self, response)\u001b[39m\n\u001b[32m 206\u001b[39m \u001b[38;5;66;03m# General error messages: ES, ET, EL (status is \"\" for these)\u001b[39;00m\n\u001b[32m 207\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m response.command == \u001b[33m\"\u001b[39m\u001b[33mES\u001b[39m\u001b[33m\"\u001b[39m:\n\u001b[32m--> \u001b[39m\u001b[32m208\u001b[39m \u001b[38;5;28;01mraise\u001b[39;00m MettlerToledoError.syntax_error()\n\u001b[32m 209\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m response.command == \u001b[33m\"\u001b[39m\u001b[33mET\u001b[39m\u001b[33m\"\u001b[39m:\n\u001b[32m 210\u001b[39m \u001b[38;5;28;01mraise\u001b[39;00m MettlerToledoError.transmission_error()\n", + "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[18]\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 backend.cancel_all()\n\u001b[32m 2\u001b[39m \u001b[38;5;28mprint\u001b[39m(\u001b[33m\"\u001b[39m\u001b[33mPASS: cancel_all completed without error\u001b[39m\u001b[33m\"\u001b[39m)\n", + "\u001b[36mFile \u001b[39m\u001b[32m~/Desktop/GitHub/pylabrobot/pylabrobot/scales/mettler_toledo/backend.py:350\u001b[39m, in \u001b[36mMettlerToledoWXS205SDUBackend.cancel_all\u001b[39m\u001b[34m(self)\u001b[39m\n\u001b[32m 340\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[34mcancel_all\u001b[39m(\u001b[38;5;28mself\u001b[39m) -> \u001b[38;5;28;01mNone\u001b[39;00m:\n\u001b[32m 341\u001b[39m \u001b[38;5;250m \u001b[39m\u001b[33;03m\"\"\"C - Cancel all active and pending interface commands.\u001b[39;00m\n\u001b[32m 342\u001b[39m \n\u001b[32m 343\u001b[39m \u001b[33;03m Unlike cancel() (@), this does not reset the device - it only cancels\u001b[39;00m\n\u001b[32m (...)\u001b[39m\u001b[32m 348\u001b[39m \u001b[33;03m C A (complete). Both responses are consumed to keep the serial buffer clean.\u001b[39;00m\n\u001b[32m 349\u001b[39m \u001b[33;03m \"\"\"\u001b[39;00m\n\u001b[32m--> \u001b[39m\u001b[32m350\u001b[39m responses = \u001b[38;5;28;01mawait\u001b[39;00m \u001b[38;5;28mself\u001b[39m.send_command(\u001b[33m\"\u001b[39m\u001b[33mC\u001b[39m\u001b[33m\"\u001b[39m)\n\u001b[32m 351\u001b[39m \u001b[38;5;66;03m# send_command reads both C B (started) and C A (complete) automatically\u001b[39;00m\n\u001b[32m 352\u001b[39m \u001b[38;5;28mself\u001b[39m._validate_response(responses[\u001b[32m0\u001b[39m], \u001b[32m2\u001b[39m, \u001b[33m\"\u001b[39m\u001b[33mC\u001b[39m\u001b[33m\"\u001b[39m)\n", + "\u001b[36mFile \u001b[39m\u001b[32m~/Desktop/GitHub/pylabrobot/pylabrobot/scales/mettler_toledo/backend.py:312\u001b[39m, in \u001b[36mMettlerToledoWXS205SDUBackend.send_command\u001b[39m\u001b[34m(self, command, timeout)\u001b[39m\n\u001b[32m 310\u001b[39m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[32m 311\u001b[39m response = MettlerToledoResponse(command=\u001b[33m\"\u001b[39m\u001b[33m\"\u001b[39m, status=\u001b[33m\"\u001b[39m\u001b[33m\"\u001b[39m, data=[])\n\u001b[32m--> \u001b[39m\u001b[32m312\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[43m.\u001b[49m\u001b[43m_parse_basic_errors\u001b[49m\u001b[43m(\u001b[49m\u001b[43mresponse\u001b[49m\u001b[43m)\u001b[49m\n\u001b[32m 313\u001b[39m responses.append(response)\n\u001b[32m 315\u001b[39m \u001b[38;5;66;03m# Status B means more responses follow; anything else (A, etc.) is final\u001b[39;00m\n", + "\u001b[36mFile \u001b[39m\u001b[32m~/Desktop/GitHub/pylabrobot/pylabrobot/scales/mettler_toledo/backend.py:233\u001b[39m, in \u001b[36mMettlerToledoWXS205SDUBackend._parse_basic_errors\u001b[39m\u001b[34m(self, response)\u001b[39m\n\u001b[32m 231\u001b[39m \u001b[38;5;66;03m# General error messages: ES, ET, EL (status is \"\" for these)\u001b[39;00m\n\u001b[32m 232\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m response.command == \u001b[33m\"\u001b[39m\u001b[33mES\u001b[39m\u001b[33m\"\u001b[39m:\n\u001b[32m--> \u001b[39m\u001b[32m233\u001b[39m \u001b[38;5;28;01mraise\u001b[39;00m MettlerToledoError.syntax_error()\n\u001b[32m 234\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m response.command == \u001b[33m\"\u001b[39m\u001b[33mET\u001b[39m\u001b[33m\"\u001b[39m:\n\u001b[32m 235\u001b[39m \u001b[38;5;28;01mraise\u001b[39;00m MettlerToledoError.transmission_error()\n", "\u001b[31mMettlerToledoError\u001b[39m: Syntax error: The weigh module/balance has not recognized the received command or the command is not allowed" ] } @@ -1106,17 +1157,17 @@ }, { "cell_type": "code", - "execution_count": 18, + "execution_count": 19, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 11:58:28,969 - pylabrobot - IO - [MT Scale] Sent command: D \"PLR TEST\"\n", - "2026-03-30 11:58:28,973 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'D \"PLR TEST\"\\r\\n'\n", - "2026-03-30 11:58:29,004 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'ES\\r\\n'\n", - "2026-03-30 11:58:29,006 - pylabrobot - IO - [MT Scale] Received response: b'ES\\r\\n'\n" + "2026-03-30 12:08:09,775 - pylabrobot - IO - [MT Scale] Sent command: D \"PLR TEST\"\n", + "2026-03-30 12:08:09,778 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'D \"PLR TEST\"\\r\\n'\n", + "2026-03-30 12:08:09,803 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'ES\\r\\n'\n", + "2026-03-30 12:08:09,804 - pylabrobot - IO - [MT Scale] Received response: b'ES\\r\\n'\n" ] }, { @@ -1126,10 +1177,10 @@ "traceback": [ "\u001b[31m---------------------------------------------------------------------------\u001b[39m", "\u001b[31mMettlerToledoError\u001b[39m Traceback (most recent call last)", - "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[18]\u001b[39m\u001b[32m, line 3\u001b[39m\n\u001b[32m 1\u001b[39m \u001b[38;5;28;01mimport\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[34;01masyncio\u001b[39;00m\n\u001b[32m----> \u001b[39m\u001b[32m3\u001b[39m \u001b[38;5;28;01mawait\u001b[39;00m backend.set_display_text(\u001b[33m\"\u001b[39m\u001b[33mPLR TEST\u001b[39m\u001b[33m\"\u001b[39m)\n\u001b[32m 4\u001b[39m \u001b[38;5;28;01mawait\u001b[39;00m asyncio.sleep(\u001b[32m2\u001b[39m)\n\u001b[32m 5\u001b[39m \u001b[38;5;28;01mawait\u001b[39;00m backend.set_weight_display()\n", - "\u001b[36mFile \u001b[39m\u001b[32m~/Desktop/GitHub/pylabrobot/pylabrobot/scales/mettler_toledo/backend.py:558\u001b[39m, in \u001b[36mMettlerToledoWXS205SDUBackend.set_display_text\u001b[39m\u001b[34m(self, text)\u001b[39m\n\u001b[32m 555\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[34mset_display_text\u001b[39m(\u001b[38;5;28mself\u001b[39m, text: \u001b[38;5;28mstr\u001b[39m) -> List[MettlerToledoResponse]:\n\u001b[32m 556\u001b[39m \u001b[38;5;250m \u001b[39m\u001b[33;03m\"\"\"Set the display text of the scale. Return to the normal weight display with\u001b[39;00m\n\u001b[32m 557\u001b[39m \u001b[33;03m self.set_weight_display().\"\"\"\u001b[39;00m\n\u001b[32m--> \u001b[39m\u001b[32m558\u001b[39m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;01mawait\u001b[39;00m \u001b[38;5;28mself\u001b[39m.send_command(\u001b[33mf\u001b[39m\u001b[33m'\u001b[39m\u001b[33mD \u001b[39m\u001b[33m\"\u001b[39m\u001b[38;5;132;01m{\u001b[39;00mtext\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m\"\u001b[39m\u001b[33m'\u001b[39m)\n", - "\u001b[36mFile \u001b[39m\u001b[32m~/Desktop/GitHub/pylabrobot/pylabrobot/scales/mettler_toledo/backend.py:287\u001b[39m, in \u001b[36mMettlerToledoWXS205SDUBackend.send_command\u001b[39m\u001b[34m(self, command, timeout)\u001b[39m\n\u001b[32m 285\u001b[39m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[32m 286\u001b[39m response = MettlerToledoResponse(command=\u001b[33m\"\u001b[39m\u001b[33m\"\u001b[39m, status=\u001b[33m\"\u001b[39m\u001b[33m\"\u001b[39m, data=[])\n\u001b[32m--> \u001b[39m\u001b[32m287\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[43m.\u001b[49m\u001b[43m_parse_basic_errors\u001b[49m\u001b[43m(\u001b[49m\u001b[43mresponse\u001b[49m\u001b[43m)\u001b[49m\n\u001b[32m 288\u001b[39m responses.append(response)\n\u001b[32m 290\u001b[39m \u001b[38;5;66;03m# Status B means more responses follow; anything else (A, etc.) is final\u001b[39;00m\n", - "\u001b[36mFile \u001b[39m\u001b[32m~/Desktop/GitHub/pylabrobot/pylabrobot/scales/mettler_toledo/backend.py:208\u001b[39m, in \u001b[36mMettlerToledoWXS205SDUBackend._parse_basic_errors\u001b[39m\u001b[34m(self, response)\u001b[39m\n\u001b[32m 206\u001b[39m \u001b[38;5;66;03m# General error messages: ES, ET, EL (status is \"\" for these)\u001b[39;00m\n\u001b[32m 207\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m response.command == \u001b[33m\"\u001b[39m\u001b[33mES\u001b[39m\u001b[33m\"\u001b[39m:\n\u001b[32m--> \u001b[39m\u001b[32m208\u001b[39m \u001b[38;5;28;01mraise\u001b[39;00m MettlerToledoError.syntax_error()\n\u001b[32m 209\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m response.command == \u001b[33m\"\u001b[39m\u001b[33mET\u001b[39m\u001b[33m\"\u001b[39m:\n\u001b[32m 210\u001b[39m \u001b[38;5;28;01mraise\u001b[39;00m MettlerToledoError.transmission_error()\n", + "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[19]\u001b[39m\u001b[32m, line 3\u001b[39m\n\u001b[32m 1\u001b[39m \u001b[38;5;28;01mimport\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[34;01masyncio\u001b[39;00m\n\u001b[32m----> \u001b[39m\u001b[32m3\u001b[39m \u001b[38;5;28;01mawait\u001b[39;00m backend.set_display_text(\u001b[33m\"\u001b[39m\u001b[33mPLR TEST\u001b[39m\u001b[33m\"\u001b[39m)\n\u001b[32m 4\u001b[39m \u001b[38;5;28;01mawait\u001b[39;00m asyncio.sleep(\u001b[32m2\u001b[39m)\n\u001b[32m 5\u001b[39m \u001b[38;5;28;01mawait\u001b[39;00m backend.set_weight_display()\n", + "\u001b[36mFile \u001b[39m\u001b[32m~/Desktop/GitHub/pylabrobot/pylabrobot/scales/mettler_toledo/backend.py:583\u001b[39m, in \u001b[36mMettlerToledoWXS205SDUBackend.set_display_text\u001b[39m\u001b[34m(self, text)\u001b[39m\n\u001b[32m 580\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[34mset_display_text\u001b[39m(\u001b[38;5;28mself\u001b[39m, text: \u001b[38;5;28mstr\u001b[39m) -> List[MettlerToledoResponse]:\n\u001b[32m 581\u001b[39m \u001b[38;5;250m \u001b[39m\u001b[33;03m\"\"\"Set the display text of the scale. Return to the normal weight display with\u001b[39;00m\n\u001b[32m 582\u001b[39m \u001b[33;03m self.set_weight_display().\"\"\"\u001b[39;00m\n\u001b[32m--> \u001b[39m\u001b[32m583\u001b[39m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;01mawait\u001b[39;00m \u001b[38;5;28mself\u001b[39m.send_command(\u001b[33mf\u001b[39m\u001b[33m'\u001b[39m\u001b[33mD \u001b[39m\u001b[33m\"\u001b[39m\u001b[38;5;132;01m{\u001b[39;00mtext\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m\"\u001b[39m\u001b[33m'\u001b[39m)\n", + "\u001b[36mFile \u001b[39m\u001b[32m~/Desktop/GitHub/pylabrobot/pylabrobot/scales/mettler_toledo/backend.py:312\u001b[39m, in \u001b[36mMettlerToledoWXS205SDUBackend.send_command\u001b[39m\u001b[34m(self, command, timeout)\u001b[39m\n\u001b[32m 310\u001b[39m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[32m 311\u001b[39m response = MettlerToledoResponse(command=\u001b[33m\"\u001b[39m\u001b[33m\"\u001b[39m, status=\u001b[33m\"\u001b[39m\u001b[33m\"\u001b[39m, data=[])\n\u001b[32m--> \u001b[39m\u001b[32m312\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[43m.\u001b[49m\u001b[43m_parse_basic_errors\u001b[49m\u001b[43m(\u001b[49m\u001b[43mresponse\u001b[49m\u001b[43m)\u001b[49m\n\u001b[32m 313\u001b[39m responses.append(response)\n\u001b[32m 315\u001b[39m \u001b[38;5;66;03m# Status B means more responses follow; anything else (A, etc.) is final\u001b[39;00m\n", + "\u001b[36mFile \u001b[39m\u001b[32m~/Desktop/GitHub/pylabrobot/pylabrobot/scales/mettler_toledo/backend.py:233\u001b[39m, in \u001b[36mMettlerToledoWXS205SDUBackend._parse_basic_errors\u001b[39m\u001b[34m(self, response)\u001b[39m\n\u001b[32m 231\u001b[39m \u001b[38;5;66;03m# General error messages: ES, ET, EL (status is \"\" for these)\u001b[39;00m\n\u001b[32m 232\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m response.command == \u001b[33m\"\u001b[39m\u001b[33mES\u001b[39m\u001b[33m\"\u001b[39m:\n\u001b[32m--> \u001b[39m\u001b[32m233\u001b[39m \u001b[38;5;28;01mraise\u001b[39;00m MettlerToledoError.syntax_error()\n\u001b[32m 234\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m response.command == \u001b[33m\"\u001b[39m\u001b[33mET\u001b[39m\u001b[33m\"\u001b[39m:\n\u001b[32m 235\u001b[39m \u001b[38;5;28;01mraise\u001b[39;00m MettlerToledoError.transmission_error()\n", "\u001b[31mMettlerToledoError\u001b[39m: Syntax error: The weigh module/balance has not recognized the received command or the command is not allowed" ] } @@ -1154,21 +1205,21 @@ }, { "cell_type": "code", - "execution_count": 19, + "execution_count": 20, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 11:58:30,097 - pylabrobot - IO - [MT Scale] Sent command: ZC 5000\n", - "2026-03-30 11:58:30,101 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'ZC 5000\\r\\n'\n", - "2026-03-30 11:58:30,123 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'ES\\r\\n'\n", - "2026-03-30 11:58:30,124 - pylabrobot - IO - [MT Scale] Received response: b'ES\\r\\n'\n", - "2026-03-30 11:58:30,125 - pylabrobot - IO - [MT Scale] Sent command: TC 5000\n", - "2026-03-30 11:58:30,126 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'TC 5000\\r\\n'\n", - "2026-03-30 11:58:30,156 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'ES\\r\\n'\n", - "2026-03-30 11:58:30,157 - pylabrobot - IO - [MT Scale] Received response: b'ES\\r\\n'\n" + "2026-03-30 12:08:11,168 - pylabrobot - IO - [MT Scale] Sent command: ZC 5000\n", + "2026-03-30 12:08:11,172 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'ZC 5000\\r\\n'\n", + "2026-03-30 12:08:11,193 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'ES\\r\\n'\n", + "2026-03-30 12:08:11,194 - pylabrobot - IO - [MT Scale] Received response: b'ES\\r\\n'\n", + "2026-03-30 12:08:11,195 - pylabrobot - IO - [MT Scale] Sent command: TC 5000\n", + "2026-03-30 12:08:11,196 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'TC 5000\\r\\n'\n", + "2026-03-30 12:08:11,225 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'ES\\r\\n'\n", + "2026-03-30 12:08:11,227 - pylabrobot - IO - [MT Scale] Received response: b'ES\\r\\n'\n" ] }, { @@ -1211,17 +1262,17 @@ }, { "cell_type": "code", - "execution_count": 20, + "execution_count": 21, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 11:58:31,651 - pylabrobot - IO - [MT Scale] Sent command: M21 0 0\n", - "2026-03-30 11:58:31,653 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'M21 0 0\\r\\n'\n", - "2026-03-30 11:58:31,691 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M21 A\\r\\n'\n", - "2026-03-30 11:58:31,692 - pylabrobot - IO - [MT Scale] Received response: b'M21 A\\r\\n'\n" + "2026-03-30 12:08:12,987 - pylabrobot - IO - [MT Scale] Sent command: M21 0 0\n", + "2026-03-30 12:08:12,990 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'M21 0 0\\r\\n'\n", + "2026-03-30 12:08:13,016 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M21 A\\r\\n'\n", + "2026-03-30 12:08:13,016 - pylabrobot - IO - [MT Scale] Received response: b'M21 A\\r\\n'\n" ] }, { @@ -1249,7 +1300,7 @@ }, { "cell_type": "code", - "execution_count": 21, + "execution_count": 22, "metadata": {}, "outputs": [ { @@ -1280,26 +1331,26 @@ }, { "cell_type": "code", - "execution_count": 22, + "execution_count": 23, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 11:58:41,437 - pylabrobot - IO - [MT Scale] Sent command: M28\n", - "2026-03-30 11:58:41,440 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'M28\\r\\n'\n", - "2026-03-30 11:58:41,473 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M28 B 1 19.8\\r\\n'\n", - "2026-03-30 11:58:41,474 - pylabrobot - IO - [MT Scale] Received response: b'M28 B 1 19.8\\r\\n'\n", - "2026-03-30 11:58:41,488 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M28 A 2 19.3\\r\\n'\n", - "2026-03-30 11:58:41,491 - pylabrobot - IO - [MT Scale] Received response: b'M28 A 2 19.3\\r\\n'\n" + "2026-03-30 12:08:14,914 - pylabrobot - IO - [MT Scale] Sent command: M28\n", + "2026-03-30 12:08:14,917 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'M28\\r\\n'\n", + "2026-03-30 12:08:14,950 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M28 B 1 19.9\\r\\n'\n", + "2026-03-30 12:08:14,950 - pylabrobot - IO - [MT Scale] Received response: b'M28 B 1 19.9\\r\\n'\n", + "2026-03-30 12:08:14,966 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M28 A 2 19.4\\r\\n'\n", + "2026-03-30 12:08:14,967 - pylabrobot - IO - [MT Scale] Received response: b'M28 A 2 19.4\\r\\n'\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ - "Scale temperature: 19.8 C\n", + "Scale temperature: 19.9 C\n", "PASS: measure_temperature works - I0 correctly predicted M28 support\n" ] } @@ -1326,21 +1377,21 @@ }, { "cell_type": "code", - "execution_count": 23, + "execution_count": 24, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 11:59:03,913 - pylabrobot - IO - [MT Scale] Sent command: Z\n", - "2026-03-30 11:59:03,916 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'Z\\r\\n'\n", - "2026-03-30 11:59:04,299 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'Z A\\r\\n'\n", - "2026-03-30 11:59:04,300 - pylabrobot - IO - [MT Scale] Received response: b'Z A\\r\\n'\n", - "2026-03-30 11:59:04,301 - pylabrobot - IO - [MT Scale] Sent command: SI\n", - "2026-03-30 11:59:04,303 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", - "2026-03-30 11:59:04,347 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 11:59:04,348 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n" + "2026-03-30 12:08:16,449 - pylabrobot - IO - [MT Scale] Sent command: Z\n", + "2026-03-30 12:08:16,453 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'Z\\r\\n'\n", + "2026-03-30 12:08:16,693 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'Z A\\r\\n'\n", + "2026-03-30 12:08:16,694 - pylabrobot - IO - [MT Scale] Received response: b'Z A\\r\\n'\n", + "2026-03-30 12:08:16,694 - pylabrobot - IO - [MT Scale] Sent command: SI\n", + "2026-03-30 12:08:16,696 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", + "2026-03-30 12:08:16,741 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 12:08:16,749 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n" ] }, { @@ -1361,14 +1412,14 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 11:59:05,364 - pylabrobot - IO - [MT Scale] Sent command: T\n", - "2026-03-30 11:59:05,365 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'T\\r\\n'\n", - "2026-03-30 11:59:05,706 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'T S 0.00000 g\\r\\n'\n", - "2026-03-30 11:59:05,706 - pylabrobot - IO - [MT Scale] Received response: b'T S 0.00000 g\\r\\n'\n", - "2026-03-30 11:59:05,708 - pylabrobot - IO - [MT Scale] Sent command: TA\n", - "2026-03-30 11:59:05,709 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'TA\\r\\n'\n", - "2026-03-30 11:59:05,801 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'TA A 0.00000 g\\r\\n'\n", - "2026-03-30 11:59:05,802 - pylabrobot - IO - [MT Scale] Received response: b'TA A 0.00000 g\\r\\n'\n" + "2026-03-30 12:08:17,727 - pylabrobot - IO - [MT Scale] Sent command: T\n", + "2026-03-30 12:08:17,729 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'T\\r\\n'\n", + "2026-03-30 12:08:18,099 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'T S 0.00000 g\\r\\n'\n", + "2026-03-30 12:08:18,100 - pylabrobot - IO - [MT Scale] Received response: b'T S 0.00000 g\\r\\n'\n", + "2026-03-30 12:08:18,101 - pylabrobot - IO - [MT Scale] Sent command: TA\n", + "2026-03-30 12:08:18,103 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'TA\\r\\n'\n", + "2026-03-30 12:08:18,195 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'TA A 0.00000 g\\r\\n'\n", + "2026-03-30 12:08:18,196 - pylabrobot - IO - [MT Scale] Received response: b'TA A 0.00000 g\\r\\n'\n" ] }, { @@ -1385,7 +1436,7 @@ "traceback": [ "\u001b[31m---------------------------------------------------------------------------\u001b[39m", "\u001b[31mAssertionError\u001b[39m Traceback (most recent call last)", - "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[23]\u001b[39m\u001b[32m, line 12\u001b[39m\n\u001b[32m 10\u001b[39m tare = \u001b[38;5;28;01mawait\u001b[39;00m scale.request_tare_weight()\n\u001b[32m 11\u001b[39m \u001b[38;5;28mprint\u001b[39m(\u001b[33mf\u001b[39m\u001b[33m\"\u001b[39m\u001b[33mFrontend tare weight: \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mtare\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m g\u001b[39m\u001b[33m\"\u001b[39m)\n\u001b[32m---> \u001b[39m\u001b[32m12\u001b[39m \u001b[38;5;28;01massert\u001b[39;00m tare > \u001b[32m0\u001b[39m\n\u001b[32m 14\u001b[39m \u001b[38;5;66;03m# Read via frontend\u001b[39;00m\n\u001b[32m 15\u001b[39m w = \u001b[38;5;28;01mawait\u001b[39;00m scale.read_weight(timeout=\u001b[33m\"\u001b[39m\u001b[33mstable\u001b[39m\u001b[33m\"\u001b[39m)\n", + "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[24]\u001b[39m\u001b[32m, line 12\u001b[39m\n\u001b[32m 10\u001b[39m tare = \u001b[38;5;28;01mawait\u001b[39;00m scale.request_tare_weight()\n\u001b[32m 11\u001b[39m \u001b[38;5;28mprint\u001b[39m(\u001b[33mf\u001b[39m\u001b[33m\"\u001b[39m\u001b[33mFrontend tare weight: \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mtare\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m g\u001b[39m\u001b[33m\"\u001b[39m)\n\u001b[32m---> \u001b[39m\u001b[32m12\u001b[39m \u001b[38;5;28;01massert\u001b[39;00m tare > \u001b[32m0\u001b[39m\n\u001b[32m 14\u001b[39m \u001b[38;5;66;03m# Read via frontend\u001b[39;00m\n\u001b[32m 15\u001b[39m w = \u001b[38;5;28;01mawait\u001b[39;00m scale.read_weight(timeout=\u001b[33m\"\u001b[39m\u001b[33mstable\u001b[39m\u001b[33m\"\u001b[39m)\n", "\u001b[31mAssertionError\u001b[39m: " ] } @@ -1422,101 +1473,101 @@ }, { "cell_type": "code", - "execution_count": 24, + "execution_count": 25, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 11:59:20,456 - pylabrobot - IO - [MT Scale] Sent command: S\n", - "2026-03-30 11:59:20,459 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", - "2026-03-30 11:59:20,541 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 11:59:20,542 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 11:59:20,544 - pylabrobot - IO - [MT Scale] Sent command: S\n", - "2026-03-30 11:59:20,545 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", - "2026-03-30 11:59:20,638 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 11:59:20,638 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 11:59:20,639 - pylabrobot - IO - [MT Scale] Sent command: S\n", - "2026-03-30 11:59:20,641 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", - "2026-03-30 11:59:20,733 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 11:59:20,734 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 11:59:20,735 - pylabrobot - IO - [MT Scale] Sent command: S\n", - "2026-03-30 11:59:20,737 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", - "2026-03-30 11:59:20,829 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 11:59:20,830 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 11:59:20,831 - pylabrobot - IO - [MT Scale] Sent command: S\n", - "2026-03-30 11:59:20,834 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", - "2026-03-30 11:59:20,926 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 11:59:20,927 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 11:59:20,927 - pylabrobot - IO - [MT Scale] Sent command: S\n", - "2026-03-30 11:59:20,929 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", - "2026-03-30 11:59:21,021 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 11:59:21,024 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 11:59:21,027 - pylabrobot - IO - [MT Scale] Sent command: S\n", - "2026-03-30 11:59:21,031 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", - "2026-03-30 11:59:21,118 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 11:59:21,120 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 11:59:21,120 - pylabrobot - IO - [MT Scale] Sent command: S\n", - "2026-03-30 11:59:21,125 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", - "2026-03-30 11:59:21,229 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 11:59:21,232 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 11:59:21,234 - pylabrobot - IO - [MT Scale] Sent command: S\n", - "2026-03-30 11:59:21,236 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", - "2026-03-30 11:59:21,325 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 11:59:21,326 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 11:59:21,329 - pylabrobot - IO - [MT Scale] Sent command: S\n", - "2026-03-30 11:59:21,331 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", - "2026-03-30 11:59:21,420 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 11:59:21,421 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 11:59:21,425 - pylabrobot - IO - [MT Scale] Sent command: SI\n", - "2026-03-30 11:59:21,427 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", - "2026-03-30 11:59:21,473 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 11:59:21,475 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 11:59:21,475 - pylabrobot - IO - [MT Scale] Sent command: SI\n", - "2026-03-30 11:59:21,477 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", - "2026-03-30 11:59:21,517 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 11:59:21,520 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 11:59:21,521 - pylabrobot - IO - [MT Scale] Sent command: SI\n", - "2026-03-30 11:59:21,526 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", - "2026-03-30 11:59:21,564 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 11:59:21,567 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 11:59:21,568 - pylabrobot - IO - [MT Scale] Sent command: SI\n", - "2026-03-30 11:59:21,571 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", - "2026-03-30 11:59:21,613 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 11:59:21,614 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 11:59:21,617 - pylabrobot - IO - [MT Scale] Sent command: SI\n", - "2026-03-30 11:59:21,625 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", - "2026-03-30 11:59:21,662 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 11:59:21,663 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 11:59:21,664 - pylabrobot - IO - [MT Scale] Sent command: SI\n", - "2026-03-30 11:59:21,667 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", - "2026-03-30 11:59:21,709 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 11:59:21,712 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 11:59:21,716 - pylabrobot - IO - [MT Scale] Sent command: SI\n", - "2026-03-30 11:59:21,725 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", - "2026-03-30 11:59:21,757 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 11:59:21,758 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 11:59:21,760 - pylabrobot - IO - [MT Scale] Sent command: SI\n", - "2026-03-30 11:59:21,761 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", - "2026-03-30 11:59:21,793 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 11:59:21,794 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 11:59:21,795 - pylabrobot - IO - [MT Scale] Sent command: SI\n", - "2026-03-30 11:59:21,796 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", - "2026-03-30 11:59:21,836 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 11:59:21,837 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 11:59:21,838 - pylabrobot - IO - [MT Scale] Sent command: SI\n", - "2026-03-30 11:59:21,846 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", - "2026-03-30 11:59:21,885 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 11:59:21,887 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n" + "2026-03-30 12:08:20,929 - pylabrobot - IO - [MT Scale] Sent command: S\n", + "2026-03-30 12:08:20,930 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", + "2026-03-30 12:08:21,040 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 12:08:21,041 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 12:08:21,042 - pylabrobot - IO - [MT Scale] Sent command: S\n", + "2026-03-30 12:08:21,044 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", + "2026-03-30 12:08:21,136 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 12:08:21,137 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 12:08:21,138 - pylabrobot - IO - [MT Scale] Sent command: S\n", + "2026-03-30 12:08:21,139 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", + "2026-03-30 12:08:21,232 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 12:08:21,233 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 12:08:21,234 - pylabrobot - IO - [MT Scale] Sent command: S\n", + "2026-03-30 12:08:21,235 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", + "2026-03-30 12:08:21,328 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 12:08:21,329 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 12:08:21,330 - pylabrobot - IO - [MT Scale] Sent command: S\n", + "2026-03-30 12:08:21,332 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", + "2026-03-30 12:08:21,424 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 12:08:21,425 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 12:08:21,426 - pylabrobot - IO - [MT Scale] Sent command: S\n", + "2026-03-30 12:08:21,427 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", + "2026-03-30 12:08:21,520 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 12:08:21,521 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 12:08:21,522 - pylabrobot - IO - [MT Scale] Sent command: S\n", + "2026-03-30 12:08:21,524 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", + "2026-03-30 12:08:21,632 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 12:08:21,632 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 12:08:21,633 - pylabrobot - IO - [MT Scale] Sent command: S\n", + "2026-03-30 12:08:21,634 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", + "2026-03-30 12:08:21,727 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 12:08:21,729 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 12:08:21,731 - pylabrobot - IO - [MT Scale] Sent command: S\n", + "2026-03-30 12:08:21,733 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", + "2026-03-30 12:08:21,824 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 12:08:21,824 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 12:08:21,825 - pylabrobot - IO - [MT Scale] Sent command: S\n", + "2026-03-30 12:08:21,827 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", + "2026-03-30 12:08:21,920 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 12:08:21,921 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 12:08:21,922 - pylabrobot - IO - [MT Scale] Sent command: SI\n", + "2026-03-30 12:08:21,923 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", + "2026-03-30 12:08:21,952 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 12:08:21,953 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 12:08:21,957 - pylabrobot - IO - [MT Scale] Sent command: SI\n", + "2026-03-30 12:08:21,959 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", + "2026-03-30 12:08:22,001 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 12:08:22,002 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 12:08:22,009 - pylabrobot - IO - [MT Scale] Sent command: SI\n", + "2026-03-30 12:08:22,011 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", + "2026-03-30 12:08:22,048 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 12:08:22,049 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 12:08:22,049 - pylabrobot - IO - [MT Scale] Sent command: SI\n", + "2026-03-30 12:08:22,051 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", + "2026-03-30 12:08:22,080 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 12:08:22,081 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 12:08:22,082 - pylabrobot - IO - [MT Scale] Sent command: SI\n", + "2026-03-30 12:08:22,082 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", + "2026-03-30 12:08:22,112 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 12:08:22,114 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 12:08:22,115 - pylabrobot - IO - [MT Scale] Sent command: SI\n", + "2026-03-30 12:08:22,117 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", + "2026-03-30 12:08:22,160 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 12:08:22,162 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 12:08:22,166 - pylabrobot - IO - [MT Scale] Sent command: SI\n", + "2026-03-30 12:08:22,177 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", + "2026-03-30 12:08:22,225 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 12:08:22,227 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 12:08:22,229 - pylabrobot - IO - [MT Scale] Sent command: SI\n", + "2026-03-30 12:08:22,233 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", + "2026-03-30 12:08:22,272 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 12:08:22,274 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 12:08:22,275 - pylabrobot - IO - [MT Scale] Sent command: SI\n", + "2026-03-30 12:08:22,277 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", + "2026-03-30 12:08:22,321 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 12:08:22,324 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 12:08:22,325 - pylabrobot - IO - [MT Scale] Sent command: SI\n", + "2026-03-30 12:08:22,327 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", + "2026-03-30 12:08:22,367 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 12:08:22,368 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ - "Stable read: 96.83 +/- 6.21 ms\n", - "Immediate read: 46.27 +/- 4.63 ms\n" + "Stable read: 99.29 +/- 6.59 ms\n", + "Immediate read: 44.73 +/- 9.15 ms\n" ] } ], @@ -1555,21 +1606,21 @@ }, { "cell_type": "code", - "execution_count": 25, + "execution_count": 26, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 11:59:21,899 - pylabrobot - INFO - === Hardware validation ended ===\n" + "2026-03-30 12:08:23,324 - pylabrobot - INFO - === Hardware validation ended ===\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ - "Log file: ./logs/hardware_validation/2026-03-30_11-58-03_validation.log\n" + "Log file: ./logs/hardware_validation/2026-03-30_12-07-26_validation.log\n" ] } ], @@ -1608,4 +1659,4 @@ }, "nbformat": 4, "nbformat_minor": 4 -} \ No newline at end of file +} From 674d16e690cfd21f811477bc41db7fdb73ba75a4 Mon Sep 17 00:00:00 2001 From: Camillo Moschner Date: Mon, 30 Mar 2026 12:32:06 +0100 Subject: [PATCH 18/38] I0 command discovery, shlex parsing, MettlerToledoResponse dataclass, measure_temperature, robust stop, rename chatterbox to simulator, remove deprecated methods --- .../scales/mettler-toledo-WXS205SDU.ipynb | 201 ++++---- pylabrobot/scales/__init__.py | 2 +- pylabrobot/scales/mettler_toledo/__init__.py | 2 +- pylabrobot/scales/mettler_toledo/backend.py | 75 +-- .../scales/mettler_toledo/backend_tests.py | 16 +- .../mettler_toledo/hardware_validation.ipynb | 2 +- .../scales/mettler_toledo/mt_sics_commands.md | 437 +++++++++--------- .../{chatterbox.py => simulator.py} | 14 +- pylabrobot/scales/scales_tests.py | 10 +- .../scales/{chatterbox.py => simulator.py} | 14 +- 10 files changed, 358 insertions(+), 415 deletions(-) rename pylabrobot/scales/mettler_toledo/{chatterbox.py => simulator.py} (93%) rename pylabrobot/scales/{chatterbox.py => simulator.py} (83%) diff --git a/docs/user_guide/02_analytical/scales/mettler-toledo-WXS205SDU.ipynb b/docs/user_guide/02_analytical/scales/mettler-toledo-WXS205SDU.ipynb index c9f0476bb19..1256104c032 100644 --- a/docs/user_guide/02_analytical/scales/mettler-toledo-WXS205SDU.ipynb +++ b/docs/user_guide/02_analytical/scales/mettler-toledo-WXS205SDU.ipynb @@ -59,10 +59,10 @@ "execution_count": 1, "metadata": { "execution": { - "iopub.execute_input": "2026-03-30T10:54:11.646811Z", - "iopub.status.busy": "2026-03-30T10:54:11.646321Z", - "iopub.status.idle": "2026-03-30T10:54:11.651777Z", - "shell.execute_reply": "2026-03-30T10:54:11.651148Z" + "iopub.execute_input": "2026-03-30T11:19:55.511513Z", + "iopub.status.busy": "2026-03-30T11:19:55.511349Z", + "iopub.status.idle": "2026-03-30T11:19:55.514962Z", + "shell.execute_reply": "2026-03-30T11:19:55.514665Z" } }, "outputs": [], @@ -88,10 +88,10 @@ "execution_count": 2, "metadata": { "execution": { - "iopub.execute_input": "2026-03-30T10:54:11.654817Z", - "iopub.status.busy": "2026-03-30T10:54:11.654591Z", - "iopub.status.idle": "2026-03-30T10:54:11.709745Z", - "shell.execute_reply": "2026-03-30T10:54:11.709469Z" + "iopub.execute_input": "2026-03-30T11:19:55.516796Z", + "iopub.status.busy": "2026-03-30T11:19:55.516684Z", + "iopub.status.idle": "2026-03-30T11:19:55.563409Z", + "shell.execute_reply": "2026-03-30T11:19:55.563159Z" } }, "outputs": [ @@ -99,7 +99,7 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 11:54:11,708 - pylabrobot - INFO - === MT Scale tutorial started ===\n" + "2026-03-30 12:19:55,561 - pylabrobot - INFO - === MT Scale tutorial started ===\n" ] } ], @@ -121,48 +121,17 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": null, "metadata": { "execution": { - "iopub.execute_input": "2026-03-30T10:54:11.726612Z", - "iopub.status.busy": "2026-03-30T10:54:11.726495Z", - "iopub.status.idle": "2026-03-30T10:54:11.786787Z", - "shell.execute_reply": "2026-03-30T10:54:11.786614Z" + "iopub.execute_input": "2026-03-30T11:19:55.578724Z", + "iopub.status.busy": "2026-03-30T11:19:55.578630Z", + "iopub.status.idle": "2026-03-30T11:19:55.636352Z", + "shell.execute_reply": "2026-03-30T11:19:55.636056Z" } }, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2026-03-30 11:54:11,785 - pylabrobot - INFO - [MT Scale] Connected to Mettler Toledo scale (simulation)\n", - "Device type: WXS205SDU\n", - "Serial number: SIM0000001\n", - "Capacity: 220.0 g\n", - "Supported commands: ['@', 'C', 'D', 'DW', 'I0', 'I1', 'I2', 'I4', 'I50', 'M21', 'M28', 'S', 'SC', 'SI', 'SIR', 'SR', 'T', 'TA', 'TAC', 'TC', 'TI', 'Z', 'ZC', 'ZI']\n" - ] - } - ], - "source": [ - "from pylabrobot.scales import Scale\n", - "\n", - "if protocol_mode == \"execution\":\n", - "\n", - " from pylabrobot.scales.mettler_toledo import MettlerToledoWXS205SDUBackend\n", - "\n", - " # Platform-specific port: Mac: /dev/cu.usbserial-*, Linux: /dev/ttyUSB*, Windows: COM*\n", - " backend = MettlerToledoWXS205SDUBackend(port=\"/dev/cu.usbserial-110\")\n", - "\n", - "elif protocol_mode == \"simulation\":\n", - "\n", - " from pylabrobot.scales.mettler_toledo.chatterbox import MettlerToledoChatterboxBackend\n", - "\n", - " backend = MettlerToledoChatterboxBackend()\n", - "\n", - "scale = Scale(name=\"scale\", backend=backend, size_x=0, size_y=0, size_z=0)\n", - "\n", - "await scale.setup()" - ] + "outputs": [], + "source": "from pylabrobot.scales import Scale\n\nif protocol_mode == \"execution\":\n\n from pylabrobot.scales.mettler_toledo import MettlerToledoWXS205SDUBackend\n\n # Platform-specific port: Mac: /dev/cu.usbserial-*, Linux: /dev/ttyUSB*, Windows: COM*\n backend = MettlerToledoWXS205SDUBackend(port=\"/dev/cu.usbserial-110\")\n\nelif protocol_mode == \"simulation\":\n\n from pylabrobot.scales.mettler_toledo.simulator import MettlerToledoSICSSimulator\n\n backend = MettlerToledoSICSSimulator()\n\nscale = Scale(name=\"scale\", backend=backend, size_x=0, size_y=0, size_z=0)\n\nawait scale.setup()" }, { "cell_type": "markdown", @@ -207,10 +176,10 @@ "execution_count": 4, "metadata": { "execution": { - "iopub.execute_input": "2026-03-30T10:54:11.787937Z", - "iopub.status.busy": "2026-03-30T10:54:11.787864Z", - "iopub.status.idle": "2026-03-30T10:54:11.789730Z", - "shell.execute_reply": "2026-03-30T10:54:11.789532Z" + "iopub.execute_input": "2026-03-30T11:19:55.637514Z", + "iopub.status.busy": "2026-03-30T11:19:55.637424Z", + "iopub.status.idle": "2026-03-30T11:19:55.639309Z", + "shell.execute_reply": "2026-03-30T11:19:55.639148Z" } }, "outputs": [ @@ -218,14 +187,14 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 11:54:11,788 - pylabrobot - IO - [MT Scale] Sent command: ZC 5000\n" + "2026-03-30 12:19:55,637 - pylabrobot - IO - [MT Scale] Sent command: ZC 5000\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 11:54:11,788 - pylabrobot - IO - [MT Scale] Received response: ZC A \n" + "2026-03-30 12:19:55,638 - pylabrobot - IO - [MT Scale] Received response: ZC A \n" ] } ], @@ -259,10 +228,10 @@ "execution_count": 5, "metadata": { "execution": { - "iopub.execute_input": "2026-03-30T10:54:11.790705Z", - "iopub.status.busy": "2026-03-30T10:54:11.790629Z", - "iopub.status.idle": "2026-03-30T10:54:11.792444Z", - "shell.execute_reply": "2026-03-30T10:54:11.792307Z" + "iopub.execute_input": "2026-03-30T11:19:55.640331Z", + "iopub.status.busy": "2026-03-30T11:19:55.640257Z", + "iopub.status.idle": "2026-03-30T11:19:55.642042Z", + "shell.execute_reply": "2026-03-30T11:19:55.641892Z" } }, "outputs": [ @@ -270,14 +239,14 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 11:54:11,791 - pylabrobot - IO - [MT Scale] Sent command: TC 5000\n" + "2026-03-30 12:19:55,640 - pylabrobot - IO - [MT Scale] Sent command: TC 5000\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 11:54:11,791 - pylabrobot - IO - [MT Scale] Received response: TC S 50.00000 g\n" + "2026-03-30 12:19:55,640 - pylabrobot - IO - [MT Scale] Received response: TC S 50.00000 g\n" ] } ], @@ -300,10 +269,10 @@ "execution_count": 6, "metadata": { "execution": { - "iopub.execute_input": "2026-03-30T10:54:11.793343Z", - "iopub.status.busy": "2026-03-30T10:54:11.793295Z", - "iopub.status.idle": "2026-03-30T10:54:11.796330Z", - "shell.execute_reply": "2026-03-30T10:54:11.796162Z" + "iopub.execute_input": "2026-03-30T11:19:55.642990Z", + "iopub.status.busy": "2026-03-30T11:19:55.642926Z", + "iopub.status.idle": "2026-03-30T11:19:55.646014Z", + "shell.execute_reply": "2026-03-30T11:19:55.645844Z" } }, "outputs": [ @@ -311,14 +280,14 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 11:54:11,793 - pylabrobot - IO - [MT Scale] Sent command: TA\n" + "2026-03-30 12:19:55,643 - pylabrobot - IO - [MT Scale] Sent command: TA\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 11:54:11,793 - pylabrobot - IO - [MT Scale] Received response: TA A 50.00000 g\n" + "2026-03-30 12:19:55,643 - pylabrobot - IO - [MT Scale] Received response: TA A 50.00000 g\n" ] }, { @@ -351,10 +320,10 @@ "execution_count": 7, "metadata": { "execution": { - "iopub.execute_input": "2026-03-30T10:54:11.797220Z", - "iopub.status.busy": "2026-03-30T10:54:11.797156Z", - "iopub.status.idle": "2026-03-30T10:54:11.799190Z", - "shell.execute_reply": "2026-03-30T10:54:11.799061Z" + "iopub.execute_input": "2026-03-30T11:19:55.646916Z", + "iopub.status.busy": "2026-03-30T11:19:55.646865Z", + "iopub.status.idle": "2026-03-30T11:19:55.648964Z", + "shell.execute_reply": "2026-03-30T11:19:55.648791Z" } }, "outputs": [ @@ -362,14 +331,14 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 11:54:11,797 - pylabrobot - IO - [MT Scale] Sent command: SI\n" + "2026-03-30 12:19:55,647 - pylabrobot - IO - [MT Scale] Sent command: SI\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 11:54:11,797 - pylabrobot - IO - [MT Scale] Received response: SI S 0.01060 g\n" + "2026-03-30 12:19:55,647 - pylabrobot - IO - [MT Scale] Received response: SI S 0.01060 g\n" ] }, { @@ -405,10 +374,10 @@ "execution_count": 8, "metadata": { "execution": { - "iopub.execute_input": "2026-03-30T10:54:11.799996Z", - "iopub.status.busy": "2026-03-30T10:54:11.799943Z", - "iopub.status.idle": "2026-03-30T10:54:11.802944Z", - "shell.execute_reply": "2026-03-30T10:54:11.802788Z" + "iopub.execute_input": "2026-03-30T11:19:55.649859Z", + "iopub.status.busy": "2026-03-30T11:19:55.649803Z", + "iopub.status.idle": "2026-03-30T11:19:55.652854Z", + "shell.execute_reply": "2026-03-30T11:19:55.652695Z" } }, "outputs": [ @@ -416,42 +385,42 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 11:54:11,800 - pylabrobot - IO - [MT Scale] Sent command: Z\n" + "2026-03-30 12:19:55,650 - pylabrobot - IO - [MT Scale] Sent command: Z\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 11:54:11,800 - pylabrobot - IO - [MT Scale] Received response: Z A \n" + "2026-03-30 12:19:55,650 - pylabrobot - IO - [MT Scale] Received response: Z A \n" ] }, { "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 11:54:11,801 - pylabrobot - IO - [MT Scale] Sent command: TC 5000\n" + "2026-03-30 12:19:55,651 - pylabrobot - IO - [MT Scale] Sent command: TC 5000\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 11:54:11,801 - pylabrobot - IO - [MT Scale] Received response: TC S -0.01060 g\n" + "2026-03-30 12:19:55,651 - pylabrobot - IO - [MT Scale] Received response: TC S -0.01060 g\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 11:54:11,801 - pylabrobot - IO - [MT Scale] Sent command: SC 5000\n" + "2026-03-30 12:19:55,651 - pylabrobot - IO - [MT Scale] Sent command: SC 5000\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 11:54:11,801 - pylabrobot - IO - [MT Scale] Received response: SC S 0.01060 g\n" + "2026-03-30 12:19:55,651 - pylabrobot - IO - [MT Scale] Received response: SC S 0.01060 g\n" ] }, { @@ -522,10 +491,10 @@ "execution_count": 9, "metadata": { "execution": { - "iopub.execute_input": "2026-03-30T10:54:11.803846Z", - "iopub.status.busy": "2026-03-30T10:54:11.803791Z", - "iopub.status.idle": "2026-03-30T10:54:11.805840Z", - "shell.execute_reply": "2026-03-30T10:54:11.805684Z" + "iopub.execute_input": "2026-03-30T11:19:55.653828Z", + "iopub.status.busy": "2026-03-30T11:19:55.653770Z", + "iopub.status.idle": "2026-03-30T11:19:55.656072Z", + "shell.execute_reply": "2026-03-30T11:19:55.655903Z" } }, "outputs": [ @@ -533,28 +502,28 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 11:54:11,804 - pylabrobot - IO - [MT Scale] Sent command: I50\n" + "2026-03-30 12:19:55,654 - pylabrobot - IO - [MT Scale] Sent command: I50\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 11:54:11,804 - pylabrobot - IO - [MT Scale] Received response: I50 B 0 173.940 g\n" + "2026-03-30 12:19:55,654 - pylabrobot - IO - [MT Scale] Received response: I50 B 0 173.940 g\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 11:54:11,804 - pylabrobot - IO - [MT Scale] Received response: I50 B 1 0.000 g\n" + "2026-03-30 12:19:55,654 - pylabrobot - IO - [MT Scale] Received response: I50 B 1 0.000 g\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 11:54:11,804 - pylabrobot - IO - [MT Scale] Received response: I50 A 2 173.940 g\n" + "2026-03-30 12:19:55,654 - pylabrobot - IO - [MT Scale] Received response: I50 A 2 173.940 g\n" ] }, { @@ -585,10 +554,10 @@ "execution_count": 10, "metadata": { "execution": { - "iopub.execute_input": "2026-03-30T10:54:11.806709Z", - "iopub.status.busy": "2026-03-30T10:54:11.806653Z", - "iopub.status.idle": "2026-03-30T10:54:11.808466Z", - "shell.execute_reply": "2026-03-30T10:54:11.808296Z" + "iopub.execute_input": "2026-03-30T11:19:55.657043Z", + "iopub.status.busy": "2026-03-30T11:19:55.656982Z", + "iopub.status.idle": "2026-03-30T11:19:55.658865Z", + "shell.execute_reply": "2026-03-30T11:19:55.658709Z" } }, "outputs": [ @@ -596,14 +565,14 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 11:54:11,806 - pylabrobot - IO - [MT Scale] Sent command: M28\n" + "2026-03-30 12:19:55,657 - pylabrobot - IO - [MT Scale] Sent command: M28\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 11:54:11,807 - pylabrobot - IO - [MT Scale] Received response: M28 A 1 22.5\n" + "2026-03-30 12:19:55,657 - pylabrobot - IO - [MT Scale] Received response: M28 A 1 22.5\n" ] }, { @@ -637,10 +606,10 @@ "execution_count": 11, "metadata": { "execution": { - "iopub.execute_input": "2026-03-30T10:54:11.809365Z", - "iopub.status.busy": "2026-03-30T10:54:11.809315Z", - "iopub.status.idle": "2026-03-30T10:54:11.810851Z", - "shell.execute_reply": "2026-03-30T10:54:11.810695Z" + "iopub.execute_input": "2026-03-30T11:19:55.659692Z", + "iopub.status.busy": "2026-03-30T11:19:55.659637Z", + "iopub.status.idle": "2026-03-30T11:19:55.661156Z", + "shell.execute_reply": "2026-03-30T11:19:55.661018Z" } }, "outputs": [], @@ -664,7 +633,20 @@ "metadata": {}, "source": [ "---\n", - "### Teardown" + "### Teardown\n", + "\n", + "The scale resets the device to a clean state before disconnecting. If the serial\n", + "port is already broken (e.g. kernel crash), the reset is skipped gracefully.\n", + "\n", + "For scripts and automated protocols, use `async with` to guarantee cleanup even\n", + "if an error occurs:\n", + "\n", + "```python\n", + "async with Scale(name=\"scale\", backend=backend, size_x=0, size_y=0, size_z=0) as scale:\n", + " await scale.zero()\n", + " weight = await scale.read_weight()\n", + " # scale.stop() is called automatically, even on exceptions\n", + "```" ] }, { @@ -672,10 +654,10 @@ "execution_count": 12, "metadata": { "execution": { - "iopub.execute_input": "2026-03-30T10:54:11.811707Z", - "iopub.status.busy": "2026-03-30T10:54:11.811657Z", - "iopub.status.idle": "2026-03-30T10:54:11.813231Z", - "shell.execute_reply": "2026-03-30T10:54:11.813084Z" + "iopub.execute_input": "2026-03-30T11:19:55.661985Z", + "iopub.status.busy": "2026-03-30T11:19:55.661936Z", + "iopub.status.idle": "2026-03-30T11:19:55.663573Z", + "shell.execute_reply": "2026-03-30T11:19:55.663414Z" } }, "outputs": [ @@ -683,7 +665,14 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 11:54:11,811 - pylabrobot - INFO - === MT Scale tutorial ended ===\n" + "2026-03-30 12:19:55,662 - pylabrobot - INFO - === MT Scale tutorial ended ===\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2026-03-30 12:19:55,662 - pylabrobot - INFO - [MT Scale] Disconnected (simulation)\n" ] } ], @@ -714,4 +703,4 @@ }, "nbformat": 4, "nbformat_minor": 2 -} +} \ No newline at end of file diff --git a/pylabrobot/scales/__init__.py b/pylabrobot/scales/__init__.py index 67416b5f5a3..0a7bbb1deb3 100644 --- a/pylabrobot/scales/__init__.py +++ b/pylabrobot/scales/__init__.py @@ -1,6 +1,6 @@ """PyLabRobot scales package - frontend, backends, and error types.""" -from pylabrobot.scales.chatterbox import ScaleChatterboxBackend from pylabrobot.scales.mettler_toledo import MettlerToledoError, MettlerToledoWXS205SDUBackend from pylabrobot.scales.scale import Scale from pylabrobot.scales.scale_backend import ScaleBackend +from pylabrobot.scales.simulator import ScaleSimulator diff --git a/pylabrobot/scales/mettler_toledo/__init__.py b/pylabrobot/scales/mettler_toledo/__init__.py index 5c43e63a1c9..8e5b02db052 100644 --- a/pylabrobot/scales/mettler_toledo/__init__.py +++ b/pylabrobot/scales/mettler_toledo/__init__.py @@ -4,5 +4,5 @@ MettlerToledoResponse, MettlerToledoWXS205SDUBackend, ) -from pylabrobot.scales.mettler_toledo.chatterbox import MettlerToledoChatterboxBackend from pylabrobot.scales.mettler_toledo.errors import MettlerToledoError +from pylabrobot.scales.mettler_toledo.simulator import MettlerToledoSICSSimulator diff --git a/pylabrobot/scales/mettler_toledo/backend.py b/pylabrobot/scales/mettler_toledo/backend.py index 6fbf5023b48..8e8eaa513d0 100644 --- a/pylabrobot/scales/mettler_toledo/backend.py +++ b/pylabrobot/scales/mettler_toledo/backend.py @@ -7,7 +7,6 @@ import logging import shlex import time -import warnings from dataclasses import dataclass, field from typing import Any, Callable, List, Literal, Optional, Set, TypeVar, Union @@ -136,6 +135,17 @@ async def setup(self) -> None: await self.set_host_unit_grams() async def stop(self) -> None: + """Reset the device to a clean state and close the serial connection. + + Sends @ to cancel any pending commands before disconnecting. If the + serial port is already broken (e.g. kernel crash), the reset is skipped + and the port is closed anyway. + """ + try: + await self.cancel() + except Exception: + logger.warning("[MT Scale] Could not reset device before disconnecting") + logger.info("[MT Scale] Disconnected from %s", self.io.port) await self.io.stop() def serialize(self) -> dict: @@ -605,66 +615,3 @@ async def measure_temperature(self) -> float: # M28 A 1 22.5 (single sensor) or M28 B 1 22.5 ... M28 A 2 23.0 (multi-sensor) self._validate_response(responses[0], 4, "M28") return float(responses[0].data[1]) - - # # # Deprecated alias with warning # # # - - # TODO: remove after 2026-03 - - async def get_serial_number(self) -> str: - """Deprecated: Use request_serial_number() instead.""" - warnings.warn( - "get_serial_number() is deprecated and will be removed in 2026-03. " - "Use request_serial_number() instead.", - DeprecationWarning, - stacklevel=2, - ) - return await self.request_serial_number() - - async def get_tare_weight(self) -> float: - """Deprecated: Use request_tare_weight() instead.""" - warnings.warn( - "get_tare_weight() is deprecated and will be removed in 2026-03. " - "Use request_tare_weight() instead.", - DeprecationWarning, - stacklevel=2, - ) - return await self.request_tare_weight() - - async def get_stable_weight(self) -> float: - """Deprecated: Use read_stable_weight() instead.""" - warnings.warn( - "get_stable_weight() is deprecated and will be removed in 2026-03. " - "Use read_stable_weight() instead.", - DeprecationWarning, - stacklevel=2, - ) - return await self.read_stable_weight() - - async def get_dynamic_weight(self, timeout: float) -> float: - """Deprecated: Use read_dynamic_weight() instead.""" - warnings.warn( - "get_dynamic_weight() is deprecated and will be removed in 2026-03. " - "Use read_dynamic_weight() instead.", - DeprecationWarning, - stacklevel=2, - ) - return await self.read_dynamic_weight(timeout) - - async def get_weight_value_immediately(self) -> float: - """Deprecated: Use read_weight_value_immediately() instead.""" - warnings.warn( - "get_weight_value_immediately() is deprecated and will be removed in 2026-03. " - "Use read_weight_value_immediately() instead.", - DeprecationWarning, - stacklevel=2, - ) - return await self.read_weight_value_immediately() - - async def get_weight(self, timeout: Union[Literal["stable"], float, int] = "stable") -> float: - """Deprecated: Use read_weight() instead.""" - warnings.warn( - "get_weight() is deprecated and will be removed in 2026-03. Use read_weight() instead.", - DeprecationWarning, - stacklevel=2, - ) - return await self.read_weight(timeout) diff --git a/pylabrobot/scales/mettler_toledo/backend_tests.py b/pylabrobot/scales/mettler_toledo/backend_tests.py index e893367eee6..da4c54006c7 100644 --- a/pylabrobot/scales/mettler_toledo/backend_tests.py +++ b/pylabrobot/scales/mettler_toledo/backend_tests.py @@ -1,4 +1,4 @@ -"""Tests for MT-SICS response parsing, validation, and chatterbox protocol simulation.""" +"""Tests for MT-SICS response parsing, validation, and protocol simulation.""" import unittest @@ -6,15 +6,15 @@ MettlerToledoResponse, MettlerToledoWXS205SDUBackend, ) -from pylabrobot.scales.mettler_toledo.chatterbox import MettlerToledoChatterboxBackend from pylabrobot.scales.mettler_toledo.errors import MettlerToledoError +from pylabrobot.scales.mettler_toledo.simulator import MettlerToledoSICSSimulator from pylabrobot.scales.scale import Scale R = MettlerToledoResponse class MTSICSResponseParsingTests(unittest.TestCase): - """Tests for response parsing helpers - no hardware or chatterbox needed.""" + """Tests for response parsing helpers - no hardware or simulator needed.""" def setUp(self): self.backend = MettlerToledoWXS205SDUBackend.__new__(MettlerToledoWXS205SDUBackend) @@ -98,13 +98,13 @@ def test_dataclass_construction(self): self.assertEqual(resp.data, []) -class MTSICSChatterboxTests(unittest.IsolatedAsyncioTestCase): - """Tests for the MT-SICS protocol chatterbox. +class MTSICSSimulatorTests(unittest.IsolatedAsyncioTestCase): + """Tests for the MT-SICS protocol simulator. These exercise the full stack: send_command -> mock response -> parse -> validate -> return. Catches dataclass construction bugs, index mapping errors, and response format mismatches.""" async def asyncSetUp(self): - self.backend = MettlerToledoChatterboxBackend() + self.backend = MettlerToledoSICSSimulator() self.scale = Scale( name="test_scale", backend=self.backend, @@ -161,7 +161,7 @@ async def test_cancel_returns_serial_number(self): async def test_unknown_command_returns_syntax_error(self): """Unknown commands must return ES (syntax error) response. - Ensures the chatterbox correctly simulates the device rejecting invalid commands.""" + Ensures the simulator correctly simulates the device rejecting invalid commands.""" with self.assertRaises(MettlerToledoError) as ctx: await self.backend.send_command("XYZNOTREAL") self.assertIn("Syntax error", str(ctx.exception)) @@ -175,7 +175,7 @@ async def test_measure_temperature(self): async def test_measure_temperature_blocked_when_unsupported(self): """measure_temperature must raise when M28 is not in the device's command list. Validates that I0-based command gating works correctly.""" - backend = MettlerToledoChatterboxBackend( + backend = MettlerToledoSICSSimulator( supported_commands={"@", "I0", "I2", "I4", "S", "SI", "Z", "ZI", "T", "TI", "TA", "TAC"}, ) scale = Scale(name="limited_scale", backend=backend, size_x=0, size_y=0, size_z=0) diff --git a/pylabrobot/scales/mettler_toledo/hardware_validation.ipynb b/pylabrobot/scales/mettler_toledo/hardware_validation.ipynb index 676c5d96a30..b1b92495f7c 100644 --- a/pylabrobot/scales/mettler_toledo/hardware_validation.ipynb +++ b/pylabrobot/scales/mettler_toledo/hardware_validation.ipynb @@ -326,7 +326,7 @@ "methods = backend.request_supported_methods()\n", "print(f\"{len(methods)} methods available on this device:\")\n", "for m in methods:\n", - " print(f\" {m}\")" + " print(f\" {m}\")" ] }, { diff --git a/pylabrobot/scales/mettler_toledo/mt_sics_commands.md b/pylabrobot/scales/mettler_toledo/mt_sics_commands.md index 2d374d17276..179e0c65f98 100644 --- a/pylabrobot/scales/mettler_toledo/mt_sics_commands.md +++ b/pylabrobot/scales/mettler_toledo/mt_sics_commands.md @@ -5,270 +5,277 @@ MT-SICS = Mettler Toledo Standard Interface Command Set Commands organized by level and ranked by utility for PyLabRobot integration. Source: MT-SICS Interface Command Set for Automated Precision Weigh Modules (spec doc). +**Important:** I1 reports which standardized level sets are fully implemented, but +individual commands may exist outside those levels. I0 is the definitive source of +command support. During setup(), the backend queries I0 to discover all available +commands and gates methods via `@requires_mt_sics_command`. + +**Hardware-validated on WXS205SDU WXA-Bridge (S/N: B207696838):** +I1 reports levels [0, 1] but I0 discovers 62 commands across levels 0-3. +Commands not in I0 (C, D, DW, SC, ZC, TC, I50) return ES (syntax error). + Status key: -- DONE = implemented in mettler_toledo_backend.py +- DONE = implemented in backend.py - HIGH = high priority for implementation - MED = medium priority - LOW = low priority / niche use case - N/A = not applicable to automation use case +- WXS205SDU column: supported/not supported on our test device ## Level 0 - Basic Set (always available) -| Command | Description | Spec Page | Status | Notes | -|---------|------------------------------------------|-----------|--------|-------| -| @ | Cancel / reset to determined state | 16 | DONE | cancel(). Sent during setup(). Response is I4-style. | -| I0 | List all implemented commands + levels | 96 | MED | Useful for runtime capability discovery. Multi-response (B status). | -| I1 | MT-SICS level and level versions | 97 | DONE | Queried during setup(). | -| I2 | Device data (type and capacity) | 98 | DONE | Split into request_device_type() and request_capacity(). | -| I3 | Software version and type definition | 99 | MED | Useful for diagnostics/logging. | -| I4 | Serial number | 100 | DONE | request_serial_number(). | -| I5 | Software material number | 101 | LOW | | -| S | Stable weight value | 223 | DONE | read_stable_weight(). | -| SI | Weight value immediately | 225 | DONE | read_weight_value_immediately(). | -| Z | Zero (wait for stable) | 272 | DONE | zero_stable(). | -| ZI | Zero immediately | 274 | DONE | zero_immediately(). | -| T | Tare (wait for stable) | 252 | DONE | tare_stable(). | -| TI | Tare immediately | 257 | DONE | tare_immediately(). | +| Command | Description | Spec Page | Status | WXS205SDU | Notes | +|---------|------------------------------------------|-----------|--------|-----------|-------| +| @ | Cancel / reset to determined state | 16 | DONE | yes | cancel(). Sent during setup(). Response is I4-style. | +| I0 | List all implemented commands + levels | 96 | DONE | yes | _request_supported_commands(). Queried during setup(). | +| I1 | MT-SICS level and level versions | 97 | DONE | yes | Not used for gating - I0 is authoritative. | +| I2 | Device data (type and capacity) | 98 | DONE | yes | request_device_type() and request_capacity(). Response is one quoted string parsed with shlex. | +| I3 | Software version and type definition | 99 | MED | yes | | +| I4 | Serial number | 100 | DONE | yes | request_serial_number(). | +| I5 | Software material number | 101 | LOW | yes | | +| S | Stable weight value | 223 | DONE | yes | read_stable_weight(). | +| SI | Weight value immediately | 225 | DONE | yes | read_weight_value_immediately(). | +| SIR | Weight immediately + repeat | 232 | MED | yes | Continuous streaming. | +| Z | Zero (wait for stable) | 272 | DONE | yes | zero_stable(). | +| ZI | Zero immediately | 274 | DONE | yes | zero_immediately(). | ## Level 1 - Elementary Commands (always available) -| Command | Description | Spec Page | Status | Notes | -|---------|------------------------------------------|-----------|--------|-------| -| C | Cancel all pending commands | 23 | DONE | cancel_all(). Multi-response (B then A). | -| D | Write text to display | 52 | DONE | set_display_text(). | -| DW | Show weight on display | 61 | DONE | set_weight_display(). | -| K | Keys control | 153 | LOW | Lock/unlock terminal keys. | -| SC | Stable or dynamic value after timeout | 224 | DONE | read_dynamic_weight(). | -| SIR | Weight immediately + repeat | 232 | MED | Continuous streaming. Needs multi-response support. | -| SIRU | Weight immediately + repeat (display unit)| 233 | LOW | | -| SNR | Stable weight + repeat on stable change | 241 | LOW | | -| SR | Stable weight + repeat on any change | 245 | MED | Continuous streaming. Needs multi-response support. | -| SRU | Stable weight + repeat (display unit) | 247 | LOW | | -| TA | Tare weight value (query/set) | 253 | DONE | request_tare_weight(). | -| TAC | Clear tare weight value | 254 | DONE | clear_tare(). | -| TC | Tare with timeout | 255 | DONE | tare_timeout(). | -| ZC | Zero with timeout | 273 | DONE | zero_timeout(). | +| Command | Description | Spec Page | Status | WXS205SDU | Notes | +|---------|------------------------------------------|-----------|--------|-----------|-------| +| C | Cancel all pending commands | 23 | DONE | **no** | cancel_all(). Not supported on WXS205SDU bridge. | +| D | Write text to display | 52 | DONE | **no** | set_display_text(). Not supported in bridge mode (no terminal). | +| DW | Show weight on display | 61 | DONE | **no** | set_weight_display(). Not supported in bridge mode. | +| K | Keys control | 153 | LOW | - | Lock/unlock terminal keys. | +| SC | Stable or dynamic value after timeout | 224 | DONE | **no** | read_dynamic_weight(). Not supported on WXS205SDU. | +| SR | Stable weight + repeat on any change | 245 | MED | yes | Continuous streaming. | +| SRU | Stable weight + repeat (display unit) | 247 | LOW | - | | +| T | Tare (wait for stable) | 252 | DONE | yes | tare_stable(). | +| TA | Tare weight value (query/set) | 253 | DONE | yes | request_tare_weight(). | +| TAC | Clear tare weight value | 254 | DONE | yes | clear_tare(). | +| TC | Tare with timeout | 255 | DONE | **no** | tare_timeout(). Not supported on WXS205SDU. | +| TI | Tare immediately | 257 | DONE | yes | tare_immediately(). | +| ZC | Zero with timeout | 273 | DONE | **no** | zero_timeout(). Not supported on WXS205SDU. | ## Level 2 - Extended Commands (model-dependent) ### Device Information (query) -| Command | Description | Spec Page | Status | Notes | -|---------|------------------------------------------|-----------|--------|-------| -| I10 | Device identification | 102 | MED | | -| I11 | Model designation | 103 | MED | | -| I14 | Device information (detailed) | 104 | MED | | -| I15 | Uptime | 106 | MED | | -| I16 | Date of next service | 107 | LOW | | -| I29 | Filter configuration | 111 | LOW | | -| I32 | Voltage monitoring | 112 | MED | Health check. | -| I43 | Selectable units for host unit | 113 | LOW | | -| I44 | Selectable units for display unit | 114 | LOW | | -| I45 | Selectable environment filter settings | 115 | LOW | | -| I46 | Selectable weighing modes | 117 | LOW | | -| I47 | Switch-on range | 118 | LOW | | -| I48 | Initial zero range | 119 | LOW | | -| I50 | Remaining weighing ranges | 120 | DONE | request_remaining_weighing_range(). Multi-response. | -| I51 | Power-on time | 121 | MED | | -| I52 | Auto zero activation settings | 122 | LOW | | -| I54 | Adjustment loads | 125 | LOW | | -| I55 | Menu version | 126 | LOW | | -| I59 | Initial zero information | 129 | LOW | | -| I62 | Timeout setting | 131 | LOW | | -| I65 | Total operating time | 132 | MED | Maintenance tracking. | -| I66 | Total load weighed | 133 | MED | Maintenance tracking. | -| I67 | Total number of weighings | 134 | MED | Maintenance tracking. | -| I69 | Service provider address | 135 | LOW | | -| I71 | One time adjustment status | 136 | LOW | | -| I73 | Sign off | 137 | LOW | | -| I74 | GEO code at calibration point (HighRes) | 138 | LOW | | -| I75 | GEO code at point of use (HighRes) | 139 | LOW | | -| I76 | Total voltage exceeds | 140 | LOW | | -| I77 | Total load cycles | 141 | MED | Maintenance tracking. | -| I78 | Zero deviation | 143 | LOW | | -| I79 | Total zero deviation exceeds | 144 | LOW | | -| I80 | Total temperature exceeds | 145 | LOW | | -| I81 | Temperature gradient | 147 | LOW | | -| I82 | Total temperature gradient exceeds | 148 | LOW | | -| I83 | Software identification | 149 | LOW | | -| I100 | Active stability criteria | 151 | LOW | | -| I101 | Humidity value | 152 | LOW | | +| Command | Description | Spec Page | Status | WXS205SDU | Notes | +|---------|------------------------------------------|-----------|--------|-----------|-------| +| I10 | Device identification | 102 | MED | yes | | +| I11 | Model designation | 103 | MED | yes | | +| I14 | Device information (detailed) | 104 | MED | yes | | +| I15 | Uptime | 106 | MED | yes | | +| I16 | Date of next service | 107 | LOW | yes | | +| I21 | Revision of assortment type tolerances | 108 | LOW | yes | | +| I29 | Filter configuration | 111 | LOW | - | | +| I32 | Voltage monitoring | 112 | MED | - | | +| I43 | Selectable units for host unit | 113 | LOW | - | | +| I44 | Selectable units for display unit | 114 | LOW | - | | +| I45 | Selectable environment filter settings | 115 | LOW | - | | +| I46 | Selectable weighing modes | 117 | LOW | - | | +| I47 | Switch-on range | 118 | LOW | - | | +| I48 | Initial zero range | 119 | LOW | - | | +| I50 | Remaining weighing ranges | 120 | DONE | **no** | request_remaining_weighing_range(). Not on WXS205SDU. | +| I51 | Power-on time | 121 | MED | - | | +| I52 | Auto zero activation settings | 122 | LOW | - | | +| I54 | Adjustment loads | 125 | LOW | - | | +| I55 | Menu version | 126 | LOW | - | | +| I59 | Initial zero information | 129 | LOW | - | | +| I62 | Timeout setting | 131 | LOW | - | | +| I65 | Total operating time | 132 | MED | - | | +| I66 | Total load weighed | 133 | MED | - | | +| I67 | Total number of weighings | 134 | MED | - | | +| I69 | Service provider address | 135 | LOW | - | | +| I71 | One time adjustment status | 136 | LOW | - | | +| I73 | Sign off | 137 | LOW | - | | +| I74 | GEO code at calibration point (HighRes) | 138 | LOW | - | | +| I75 | GEO code at point of use (HighRes) | 139 | LOW | - | | +| I76 | Total voltage exceeds | 140 | LOW | - | | +| I77 | Total load cycles | 141 | MED | - | | +| I78 | Zero deviation | 143 | LOW | - | | +| I79 | Total zero deviation exceeds | 144 | LOW | - | | +| I80 | Total temperature exceeds | 145 | LOW | - | | +| I81 | Temperature gradient | 147 | LOW | - | | +| I82 | Total temperature gradient exceeds | 148 | LOW | - | | +| I83 | Software identification | 149 | LOW | - | | +| I100 | Active stability criteria | 151 | LOW | - | | +| I101 | Humidity value | 152 | LOW | - | | ### Configuration (read/write) -| Command | Description | Spec Page | Status | Notes | -|---------|------------------------------------------|-----------|--------|-------| -| M01 | Weighing mode | 157 | MED | | -| M02 | Environment condition | 158 | MED | Affects filter/stability. | -| M03 | Auto zero function | 159 | MED | | -| M21 | Unit (host/display) | 165 | DONE | set_host_unit_grams(). | -| M23 | Readability (1d/xd) | 169 | LOW | | -| M28 | Temperature value | 172 | MED | | -| M35 | Zeroing mode at startup | 178 | LOW | | -| M49 | Permanent tare mode | 188 | LOW | | -| M67 | Timeout | 191 | LOW | | -| M68 | Behavior of serial interfaces | 192 | LOW | | -| COM | Serial interface parameters | 46 | LOW | Baud rate, parity, etc. | -| ECHO | Echo mode | 66 | LOW | | -| LST | Current user settings | 156 | LOW | | -| PROT | Protocol mode | 220 | LOW | | +| Command | Description | Spec Page | Status | WXS205SDU | Notes | +|---------|------------------------------------------|-----------|--------|-----------|-------| +| M01 | Weighing mode | 157 | MED | yes | | +| M02 | Environment condition | 158 | MED | yes | Affects filter/stability. | +| M03 | Auto zero function | 159 | MED | yes | | +| M21 | Unit (host/display) | 165 | DONE | yes | set_host_unit_grams(). | +| M23 | Readability (1d/xd) | 169 | LOW | - | | +| M28 | Temperature value | 172 | DONE | yes | measure_temperature(). Returns 19.8-19.9 C on test device. | +| M35 | Zeroing mode at startup | 178 | LOW | yes | | +| M49 | Permanent tare mode | 188 | LOW | - | | +| M67 | Timeout | 191 | LOW | - | | +| M68 | Behavior of serial interfaces | 192 | LOW | - | | +| COM | Serial interface parameters | 46 | LOW | yes | Baud rate, parity, etc. | +| ECHO | Echo mode | 66 | LOW | - | | +| LST | Current user settings | 156 | LOW | yes | Level 3 on WXS205SDU. | +| PROT | Protocol mode | 220 | LOW | - | | ### Adjustment / Calibration -| Command | Description | Spec Page | Status | Notes | -|---------|------------------------------------------|-----------|--------|-------| -| C0 | Adjustment setting | 24 | LOW | | -| C1 | Start adjustment (current settings) | 26 | MED | Multi-response (B status). | -| C2 | Start adjustment (external weight) | 28 | LOW | | -| C3 | Start adjustment (built-in weight) | 30 | MED | Internal calibration. Multi-response. | -| C4 | Standard / initial adjustment | 31 | LOW | | -| C5 | Enable/disable step control | 33 | LOW | | -| C6 | Customer linearization + sensitivity | 34 | LOW | | -| C7 | Customer standard calibration | 37 | LOW | | -| C8 | Sensitivity adjustment | 40 | LOW | | -| C9 | Scale placement sensitivity adjustment | 43 | LOW | | -| M19 | Adjustment weight | 163 | LOW | | -| M27 | Adjustment history | 171 | MED | | +| Command | Description | Spec Page | Status | WXS205SDU | Notes | +|---------|------------------------------------------|-----------|--------|-----------|-------| +| C0 | Adjustment setting | 24 | LOW | yes | | +| C1 | Start adjustment (current settings) | 26 | MED | yes | Multi-response (B status). | +| C2 | Start adjustment (external weight) | 28 | LOW | yes | | +| C3 | Start adjustment (built-in weight) | 30 | MED | yes | Internal calibration. Multi-response. | +| C4 | Standard / initial adjustment | 31 | LOW | - | | +| C5 | Enable/disable step control | 33 | LOW | - | | +| C6 | Customer linearization + sensitivity | 34 | LOW | - | | +| C7 | Customer standard calibration | 37 | LOW | - | | +| C8 | Sensitivity adjustment | 40 | LOW | - | | +| C9 | Scale placement sensitivity adjustment | 43 | LOW | - | | +| M19 | Adjustment weight | 163 | LOW | yes | | +| M27 | Adjustment history | 171 | MED | yes | | ### Testing -| Command | Description | Spec Page | Status | Notes | -|---------|------------------------------------------|-----------|--------|-------| -| TST0 | Query/set test function settings | 259 | LOW | | -| TST1 | Test according to current settings | 260 | LOW | | -| TST2 | Test with external weight | 262 | LOW | | -| TST3 | Test with built-in weight | 264 | LOW | | -| TST5 | Module test with built-in weights | 265 | LOW | | +| Command | Description | Spec Page | Status | WXS205SDU | Notes | +|---------|------------------------------------------|-----------|--------|-----------|-------| +| TST0 | Query/set test function settings | 259 | LOW | yes | | +| TST1 | Test according to current settings | 260 | LOW | yes | | +| TST2 | Test with external weight | 262 | LOW | yes | | +| TST3 | Test with built-in weight | 264 | LOW | yes | | +| TST5 | Module test with built-in weights | 265 | LOW | - | | ### Weight Variants (alternative read commands) -| Command | Description | Spec Page | Status | Notes | -|---------|------------------------------------------|-----------|--------|-------| -| SIC1 | Weight with CRC16 immediately | 226 | LOW | Data integrity. | -| SIC2 | HighRes weight with CRC16 immediately | 227 | LOW | | -| SIS | Net weight with unit + weighing status | 234 | MED | More info than S/SI. | -| SIU | Weight in display unit immediately | 237 | LOW | | -| SIUM | Weight + MinWeigh info immediately | 238 | LOW | | -| SIX1 | Current gross, net, and tare values | 239 | HIGH | All three values in one call. | -| ST | Stable weight on Transfer key press | 249 | N/A | Manual operation. | -| SU | Stable weight in display unit | 250 | LOW | | -| SUM | Stable weight + MinWeigh info | 251 | LOW | | +| Command | Description | Spec Page | Status | WXS205SDU | Notes | +|---------|------------------------------------------|-----------|--------|-----------|-------| +| SIC1 | Weight with CRC16 immediately | 226 | LOW | - | | +| SIC2 | HighRes weight with CRC16 immediately | 227 | LOW | - | | +| SIS | Net weight with unit + weighing status | 234 | MED | yes | | +| SIU | Weight in display unit immediately | 237 | LOW | - | | +| SIUM | Weight + MinWeigh info immediately | 238 | LOW | - | | +| SIX1 | Current gross, net, and tare values | 239 | HIGH | - | Not on WXS205SDU. | +| SNR | Stable weight + repeat on stable change | 241 | LOW | yes | | +| ST | Stable weight on Transfer key press | 249 | N/A | - | Manual operation. | +| SU | Stable weight in display unit | 250 | LOW | - | | +| SUM | Stable weight + MinWeigh info | 251 | LOW | - | | ### Stored Weight -| Command | Description | Spec Page | Status | Notes | -|---------|------------------------------------------|-----------|--------|-------| -| SIMC | Clear stored weight value | 228 | LOW | | -| SIMR | Recall stored weight value | 229 | LOW | | -| SIMRC | Recall and clear stored weight value | 230 | LOW | | -| SIMS | Store weight immediately | 231 | LOW | | +| Command | Description | Spec Page | Status | WXS205SDU | Notes | +|---------|------------------------------------------|-----------|--------|-----------|-------| +| SIMC | Clear stored weight value | 228 | LOW | - | | +| SIMR | Recall stored weight value | 229 | LOW | - | | +| SIMRC | Recall and clear stored weight value | 230 | LOW | - | | +| SIMS | Store weight immediately | 231 | LOW | - | | ### Date/Time -| Command | Description | Spec Page | Status | Notes | -|---------|------------------------------------------|-----------|--------|-------| -| DAT | Date | 53 | LOW | | -| DATI | Date and time | 54 | MED | | -| TIM | Time | 258 | LOW | | +| Command | Description | Spec Page | Status | WXS205SDU | Notes | +|---------|------------------------------------------|-----------|--------|-----------|-------| +| DAT | Date | 53 | LOW | yes | | +| DATI | Date and time | 54 | MED | - | | +| TIM | Time | 258 | LOW | yes | | ### Digital I/O -| Command | Description | Spec Page | Status | Notes | -|---------|------------------------------------------|-----------|--------|-------| -| DIN | Configuration for digital inputs | 55 | LOW | | -| DIS | Digital input status | 56 | LOW | | -| DOS | Digital output status | 57 | LOW | | -| DOT | Configuration for digital outputs | 58 | LOW | | -| DOTC | Configurable digital outputs (weight) | 59 | LOW | | +| Command | Description | Spec Page | Status | WXS205SDU | Notes | +|---------|------------------------------------------|-----------|--------|-----------|-------| +| DIN | Configuration for digital inputs | 55 | LOW | - | | +| DIS | Digital input status | 56 | LOW | - | | +| DOS | Digital output status | 57 | LOW | - | | +| DOT | Configuration for digital outputs | 58 | LOW | - | | +| DOTC | Configurable digital outputs (weight) | 59 | LOW | - | | ### System / Lifecycle -| Command | Description | Spec Page | Status | Notes | -|---------|------------------------------------------|-----------|--------|-------| -| E01 | Current system error state | 62 | HIGH | Error monitoring. | -| E02 | Weighing device errors and warnings | 63 | HIGH | Error monitoring. | -| E03 | Current system errors and warnings | 65 | HIGH | Error monitoring. | -| FSET | Reset all settings to factory defaults | 95 | LOW | Destructive. | -| RO1 | Restart device | 221 | MED | | -| RDB | Readability | 222 | LOW | | -| UPD | Update rate for SIR/SIRU | 267 | LOW | | -| USTB | User defined stability criteria | 268 | LOW | | +| Command | Description | Spec Page | Status | WXS205SDU | Notes | +|---------|------------------------------------------|-----------|--------|-----------|-------| +| E01 | Current system error state | 62 | HIGH | - | Not on WXS205SDU. | +| E02 | Weighing device errors and warnings | 63 | HIGH | - | Not on WXS205SDU. | +| E03 | Current system errors and warnings | 65 | HIGH | - | Not on WXS205SDU. | +| FSET | Reset all settings to factory defaults | 95 | LOW | yes | Level 3 on WXS205SDU. Destructive. | +| RO1 | Restart device | 221 | MED | - | | +| RDB | Readability | 222 | LOW | yes | Level 3 on WXS205SDU. | +| UPD | Update rate for SIR/SIRU | 267 | LOW | yes | | +| USTB | User defined stability criteria | 268 | LOW | yes | Level 3 on WXS205SDU. | ### Network (not relevant for serial) -| Command | Description | Spec Page | Status | Notes | -|---------|------------------------------------------|-----------|--------|-------| -| I53 | IPv4 runtime network config | 123 | N/A | Ethernet only. | -| M69 | IPv4 network configuration mode | 193 | N/A | | -| M70 | IPv4 host address + netmask | 195 | N/A | | -| M71 | IPv4 default gateway | 197 | N/A | | -| M72 | IPv4 DNS server | 199 | N/A | | -| M109 | IPv4 managed network config | 204 | N/A | | -| M117 | TCP port number | 209 | N/A | | -| M118 | Fieldbus network stack type | 211 | N/A | | -| NID | Node identification | 218 | N/A | | -| NID2 | Device node ID | 219 | N/A | | +| Command | Description | Spec Page | Status | WXS205SDU | Notes | +|---------|------------------------------------------|-----------|--------|-----------|-------| +| I53 | IPv4 runtime network config | 123 | N/A | - | Ethernet only. | +| M69 | IPv4 network configuration mode | 193 | N/A | - | | +| M70 | IPv4 host address + netmask | 195 | N/A | - | | +| M71 | IPv4 default gateway | 197 | N/A | - | | +| M72 | IPv4 DNS server | 199 | N/A | - | | +| M109 | IPv4 managed network config | 204 | N/A | - | | +| M117 | TCP port number | 209 | N/A | - | | +| M118 | Fieldbus network stack type | 211 | N/A | - | | +| NID | Node identification | 218 | N/A | - | | +| NID2 | Device node ID | 219 | N/A | - | | ### Application-Specific (Level 3, filling/dosing) -| Command | Description | Spec Page | Status | Notes | -|---------|------------------------------------------|-----------|--------|-------| -| A01 | Percent weighing reference | 17 | N/A | Application mode. | -| A02 | Sample identification | 18 | N/A | | -| A03 | Sample name | 19 | N/A | | -| A06 | Dynamic weighing behavior | 20 | N/A | | -| A10 | Nominal, +Tolerance, -Tolerance | 21 | N/A | | -| A30 | Internal loads | 22 | N/A | | -| CW02 | Time for weighing | 48 | N/A | | -| CW03 | Triggered weight value | 50 | N/A | | -| CW11 | Check weighing: weight calculation mode | 51 | N/A | | -| F01-F16 | Filling functions (16 commands) | 69-91 | N/A | Filling/dosing application. | -| FCUT | Filter cut-off frequency | 92 | N/A | | -| FCUT2 | Alt weight path cut-off frequency | 93 | N/A | | -| WMCF | Weight monitoring functions | 270 | N/A | | -| M17 | ProFACT: Single time criteria | 160 | N/A | | -| M18 | ProFACT/FACT: Temperature criterion | 162 | N/A | | -| M22 | Custom unit definitions | 168 | N/A | | -| M31 | Operating mode after restart | 174 | N/A | | -| M32 | ProFACT: Time criteria | 175 | N/A | | -| M33 | ProFACT: Day of the week | 176 | N/A | | -| M34 | MinWeigh: Method | 177 | N/A | | -| M38 | Selective parameter reset | 179 | N/A | | -| M39 | SmartTrac: Graphic | 180 | N/A | | -| M43 | Custom unit | 181 | N/A | | -| M44 | Command after startup response | 182 | N/A | | -| M45 | RS422/485 line termination | 183 | N/A | | -| M47 | Frequently changed test weight settings | 184 | N/A | | -| M48 | Infrequently changed test weight settings| 186 | N/A | | -| M66 | GWP: Certified test weight settings | 189 | N/A | | -| M89 | Interface command set | 201 | N/A | | -| M103 | RS422/485 driver mode | 202 | N/A | | -| M110 | Change display resolution | 205 | N/A | | -| M111 | SAI Cyclic data format | 207 | N/A | | -| M116 | Ignore Ethernet initial parametrization | 208 | N/A | | -| M119 | Byte order mode for automation | 212 | N/A | | -| M124 | Power supply for daisy chain | 214 | N/A | | -| MOD | Various user modes | 215 | N/A | | -| MONH | Monitor on interface | 217 | N/A | | -| SNRU | Stable weight (display unit) + repeat | 243 | N/A | | +| Command | Description | Spec Page | Status | WXS205SDU | Notes | +|---------|------------------------------------------|-----------|--------|-----------|-------| +| A01 | Percent weighing reference | 17 | N/A | - | Application mode. | +| A02 | Sample identification | 18 | N/A | - | | +| A03 | Sample name | 19 | N/A | - | | +| A06 | Dynamic weighing behavior | 20 | N/A | - | | +| A10 | Nominal, +Tolerance, -Tolerance | 21 | N/A | - | | +| A30 | Internal loads | 22 | N/A | - | | +| CW02 | Time for weighing | 48 | N/A | - | | +| CW03 | Triggered weight value | 50 | N/A | - | | +| CW11 | Check weighing: weight calculation mode | 51 | N/A | - | | +| F01-F16 | Filling functions (16 commands) | 69-91 | N/A | - | Filling/dosing application. | +| FCUT | Filter cut-off frequency | 92 | N/A | yes | Level 3 on WXS205SDU. | +| FCUT2 | Alt weight path cut-off frequency | 93 | N/A | - | | +| WMCF | Weight monitoring functions | 270 | N/A | - | | +| M17 | ProFACT: Single time criteria | 160 | N/A | yes | Level 2 on WXS205SDU. | +| M18 | ProFACT/FACT: Temperature criterion | 162 | N/A | yes | Level 2 on WXS205SDU. | +| M22 | Custom unit definitions | 168 | N/A | - | | +| M31 | Operating mode after restart | 174 | N/A | yes | Level 2 on WXS205SDU. | +| M32 | ProFACT: Time criteria | 175 | N/A | yes | Level 2 on WXS205SDU. | +| M33 | ProFACT: Day of the week | 176 | N/A | yes | Level 2 on WXS205SDU. | +| M34 | MinWeigh: Method | 177 | N/A | - | | +| M38 | Selective parameter reset | 179 | N/A | - | | +| M39 | SmartTrac: Graphic | 180 | N/A | - | | +| M43 | Custom unit | 181 | N/A | - | | +| M44 | Command after startup response | 182 | N/A | - | | +| M45 | RS422/485 line termination | 183 | N/A | - | | +| M47 | Frequently changed test weight settings | 184 | N/A | - | | +| M48 | Infrequently changed test weight settings| 186 | N/A | - | | +| M66 | GWP: Certified test weight settings | 189 | N/A | - | | +| M89 | Interface command set | 201 | N/A | - | | +| M103 | RS422/485 driver mode | 202 | N/A | - | | +| M110 | Change display resolution | 205 | N/A | - | | +| M111 | SAI Cyclic data format | 207 | N/A | - | | +| M116 | Ignore Ethernet initial parametrization | 208 | N/A | - | | +| M119 | Byte order mode for automation | 212 | N/A | - | | +| M124 | Power supply for daisy chain | 214 | N/A | - | | +| MOD | Various user modes | 215 | N/A | - | | +| MONH | Monitor on interface | 217 | N/A | - | | +| SNRU | Stable weight (display unit) + repeat | 243 | N/A | - | | ## Priority Summary ### HIGH (should implement next) -- E01/E02/E03 (error monitoring) - Level 2 -- SIX1 (gross, net, tare in one call) - Level 2 +- E01/E02/E03 (error monitoring) - not available on WXS205SDU +- SIX1 (gross, net, tare in one call) - not available on WXS205SDU ### MED (useful but not urgent) -- I0 (command discovery) -- I3 (software version) -- I11 (model designation) -- I14/I15/I51 (device info, uptime, power-on time) -- I65/I66/I67/I77 (maintenance tracking) -- SIR/SR (continuous streaming - blocked by multi-response TODO) -- SIS (net weight + status) -- C1/C3 (adjustment - blocked by multi-response TODO) -- M01/M02/M03 (weighing mode, environment, auto-zero) -- M27 (adjustment history) -- M28 (temperature) -- DATI (date/time) -- RO1 (restart) +- I3 (software version) - available on WXS205SDU +- I11 (model designation) - available on WXS205SDU +- I14/I15 (device info, uptime) - available on WXS205SDU +- SIR/SR (continuous streaming) +- SIS (net weight + status) - available on WXS205SDU +- C1/C3 (adjustment) - available on WXS205SDU +- M01/M02/M03 (weighing mode, environment, auto-zero) - available on WXS205SDU +- M27 (adjustment history) - available on WXS205SDU +- DATI (date/time) - not on WXS205SDU +- RO1 (restart) - not on WXS205SDU diff --git a/pylabrobot/scales/mettler_toledo/chatterbox.py b/pylabrobot/scales/mettler_toledo/simulator.py similarity index 93% rename from pylabrobot/scales/mettler_toledo/chatterbox.py rename to pylabrobot/scales/mettler_toledo/simulator.py index 4bc9930aea2..ac0be88576b 100644 --- a/pylabrobot/scales/mettler_toledo/chatterbox.py +++ b/pylabrobot/scales/mettler_toledo/simulator.py @@ -1,11 +1,11 @@ -"""MT-SICS protocol-level chatterbox for device-free testing. +"""MT-SICS protocol-level simulator for device-free testing. Inherits from MettlerToledoWXS205SDUBackend and overrides send_command to return mock MT-SICS responses. All high-level methods (zero, tare, read_weight, etc.) work unchanged because they call send_command which is intercepted here. -This follows the same pattern as STARChatterboxBackend (inherits from STARBackend -and overrides the low-level command transmission). +This follows the same pattern as STARChatterboxBackend in PLR (inherits from +the hardware backend and overrides the low-level command transmission). """ import logging @@ -21,7 +21,7 @@ logger = logging.getLogger("pylabrobot") -class MettlerToledoChatterboxBackend(MettlerToledoWXS205SDUBackend): +class MettlerToledoSICSSimulator(MettlerToledoWXS205SDUBackend): """MT-SICS protocol simulator for testing without hardware. Inherits all MT-SICS methods from MettlerToledoWXS205SDUBackend. @@ -32,7 +32,7 @@ class MettlerToledoChatterboxBackend(MettlerToledoWXS205SDUBackend): Example:: - backend = MettlerToledoChatterboxBackend() + backend = MettlerToledoSICSSimulator() scale = Scale(name="scale", backend=backend, size_x=0, size_y=0, size_z=0) await scale.setup() # backend.device_type == "WXS205SDU", backend.capacity == 220.0 @@ -63,7 +63,7 @@ def __init__( self._simulated_device_type = device_type self._simulated_serial_number = serial_number self._simulated_capacity = capacity - # Default: all commands the chatterbox can mock + # Default: all commands the simulator can mock self._simulated_supported_commands = supported_commands or { "@", "I0", @@ -113,7 +113,7 @@ async def setup(self) -> None: ) async def stop(self) -> None: - pass + logger.info("[MT Scale] Disconnected (simulation)") async def cancel(self) -> str: responses = await self.send_command("@") diff --git a/pylabrobot/scales/scales_tests.py b/pylabrobot/scales/scales_tests.py index 40c14ed6de3..e1318c25e0a 100644 --- a/pylabrobot/scales/scales_tests.py +++ b/pylabrobot/scales/scales_tests.py @@ -1,16 +1,16 @@ -"""Tests for generic scale behavior via the chatterbox physics simulation.""" +"""Tests for generic scale behavior via the scale physics simulation.""" import unittest -from pylabrobot.scales.chatterbox import ScaleChatterboxBackend from pylabrobot.scales.scale import Scale +from pylabrobot.scales.simulator import ScaleSimulator -class ScaleChatterboxTests(unittest.IsolatedAsyncioTestCase): - """Tests for the chatterbox physics simulation via the Scale frontend.""" +class ScaleSimulatorTests(unittest.IsolatedAsyncioTestCase): + """Tests for the physics simulation via the Scale frontend.""" async def asyncSetUp(self): - self.backend = ScaleChatterboxBackend() + self.backend = ScaleSimulator() self.scale = Scale( name="test_scale", backend=self.backend, diff --git a/pylabrobot/scales/chatterbox.py b/pylabrobot/scales/simulator.py similarity index 83% rename from pylabrobot/scales/chatterbox.py rename to pylabrobot/scales/simulator.py index 1d8cd4609d2..186e06f102a 100644 --- a/pylabrobot/scales/chatterbox.py +++ b/pylabrobot/scales/simulator.py @@ -1,15 +1,15 @@ -"""Generic scale chatterbox for testing the Scale frontend and ScaleBackend interface. +"""Generic scale simulator for testing the Scale frontend and ScaleBackend interface. -This chatterbox is protocol-agnostic - it tests the abstract scale contract (zero, tare, +This simulator is protocol-agnostic - it tests the abstract scale contract (zero, tare, read_weight, request_tare_weight) without any device-specific protocol. For MT-SICS -protocol-level simulation, use MettlerToledoChatterboxBackend instead. +protocol-level simulation, use MettlerToledoSICSSimulator instead. """ from pylabrobot.scales.scale_backend import ScaleBackend -class ScaleChatterboxBackend(ScaleBackend): - """Chatter box backend for device-free testing. +class ScaleSimulator(ScaleBackend): + """Generic scale simulator for device-free testing. Simulates scale behavior: tracks zero offset, tare weight, and platform load. The total sensor reading is ``platform_weight + sample_weight``. @@ -20,7 +20,7 @@ class ScaleChatterboxBackend(ScaleBackend): Example - zero:: - backend = ScaleChatterboxBackend() + backend = ScaleSimulator() backend.platform_weight = 2.0 # residue on empty platform await scale.zero() # zero_offset = 2.0 await scale.read_weight() # returns 0.0 @@ -29,7 +29,7 @@ class ScaleChatterboxBackend(ScaleBackend): Example - tare:: - backend = ScaleChatterboxBackend() + backend = ScaleSimulator() backend.platform_weight = 50.0 # place a 50g beaker await scale.tare() # tare_weight = 50.0 backend.sample_weight = 10.0 # add 10g of liquid From 6d97ba8d27c7bd252e3838fd47b985a17a6970e6 Mon Sep 17 00:00:00 2001 From: Camillo Moschner Date: Mon, 30 Mar 2026 12:40:39 +0100 Subject: [PATCH 19/38] command extension batch 1 --- .../scales/mettler-toledo-WXS205SDU.ipynb | 181 ++++++++++-------- pylabrobot/scales/mettler_toledo/backend.py | 99 ++++++++++ .../mettler_toledo/hardware_validation.ipynb | 14 +- pylabrobot/scales/mettler_toledo/simulator.py | 33 +++- 4 files changed, 250 insertions(+), 77 deletions(-) diff --git a/docs/user_guide/02_analytical/scales/mettler-toledo-WXS205SDU.ipynb b/docs/user_guide/02_analytical/scales/mettler-toledo-WXS205SDU.ipynb index 1256104c032..df645975032 100644 --- a/docs/user_guide/02_analytical/scales/mettler-toledo-WXS205SDU.ipynb +++ b/docs/user_guide/02_analytical/scales/mettler-toledo-WXS205SDU.ipynb @@ -59,10 +59,10 @@ "execution_count": 1, "metadata": { "execution": { - "iopub.execute_input": "2026-03-30T11:19:55.511513Z", - "iopub.status.busy": "2026-03-30T11:19:55.511349Z", - "iopub.status.idle": "2026-03-30T11:19:55.514962Z", - "shell.execute_reply": "2026-03-30T11:19:55.514665Z" + "iopub.execute_input": "2026-03-30T11:39:54.007551Z", + "iopub.status.busy": "2026-03-30T11:39:54.007435Z", + "iopub.status.idle": "2026-03-30T11:39:54.011117Z", + "shell.execute_reply": "2026-03-30T11:39:54.010830Z" } }, "outputs": [], @@ -88,10 +88,10 @@ "execution_count": 2, "metadata": { "execution": { - "iopub.execute_input": "2026-03-30T11:19:55.516796Z", - "iopub.status.busy": "2026-03-30T11:19:55.516684Z", - "iopub.status.idle": "2026-03-30T11:19:55.563409Z", - "shell.execute_reply": "2026-03-30T11:19:55.563159Z" + "iopub.execute_input": "2026-03-30T11:39:54.012846Z", + "iopub.status.busy": "2026-03-30T11:39:54.012717Z", + "iopub.status.idle": "2026-03-30T11:39:54.061748Z", + "shell.execute_reply": "2026-03-30T11:39:54.061557Z" } }, "outputs": [ @@ -99,7 +99,7 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 12:19:55,561 - pylabrobot - INFO - === MT Scale tutorial started ===\n" + "2026-03-30 12:39:54,060 - pylabrobot - INFO - === MT Scale tutorial started ===\n" ] } ], @@ -121,17 +121,48 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 3, "metadata": { "execution": { - "iopub.execute_input": "2026-03-30T11:19:55.578724Z", - "iopub.status.busy": "2026-03-30T11:19:55.578630Z", - "iopub.status.idle": "2026-03-30T11:19:55.636352Z", - "shell.execute_reply": "2026-03-30T11:19:55.636056Z" + "iopub.execute_input": "2026-03-30T11:39:54.077280Z", + "iopub.status.busy": "2026-03-30T11:39:54.077180Z", + "iopub.status.idle": "2026-03-30T11:39:54.139082Z", + "shell.execute_reply": "2026-03-30T11:39:54.138910Z" } }, - "outputs": [], - "source": "from pylabrobot.scales import Scale\n\nif protocol_mode == \"execution\":\n\n from pylabrobot.scales.mettler_toledo import MettlerToledoWXS205SDUBackend\n\n # Platform-specific port: Mac: /dev/cu.usbserial-*, Linux: /dev/ttyUSB*, Windows: COM*\n backend = MettlerToledoWXS205SDUBackend(port=\"/dev/cu.usbserial-110\")\n\nelif protocol_mode == \"simulation\":\n\n from pylabrobot.scales.mettler_toledo.simulator import MettlerToledoSICSSimulator\n\n backend = MettlerToledoSICSSimulator()\n\nscale = Scale(name=\"scale\", backend=backend, size_x=0, size_y=0, size_z=0)\n\nawait scale.setup()" + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2026-03-30 12:39:54,137 - pylabrobot - INFO - [MT Scale] Connected to Mettler Toledo scale (simulation)\n", + "Device type: WXS205SDU\n", + "Serial number: SIM0000001\n", + "Capacity: 220.0 g\n", + "Supported commands: ['@', 'C', 'D', 'DAT', 'DW', 'I0', 'I1', 'I10', 'I11', 'I14', 'I15', 'I2', 'I3', 'I4', 'I5', 'I50', 'M21', 'M28', 'S', 'SC', 'SI', 'SIR', 'SR', 'T', 'TA', 'TAC', 'TC', 'TI', 'TIM', 'Z', 'ZC', 'ZI']\n" + ] + } + ], + "source": [ + "from pylabrobot.scales import Scale\n", + "\n", + "if protocol_mode == \"execution\":\n", + "\n", + " from pylabrobot.scales.mettler_toledo import MettlerToledoWXS205SDUBackend\n", + "\n", + " # Platform-specific port: Mac: /dev/cu.usbserial-*, Linux: /dev/ttyUSB*, Windows: COM*\n", + " backend = MettlerToledoWXS205SDUBackend(port=\"/dev/cu.usbserial-110\")\n", + "\n", + "elif protocol_mode == \"simulation\":\n", + "\n", + " from pylabrobot.scales.mettler_toledo.simulator import MettlerToledoSICSSimulator\n", + "\n", + " backend = MettlerToledoSICSSimulator()\n", + "\n", + "scale = Scale(name=\"scale\", backend=backend, size_x=0, size_y=0, size_z=0)\n", + "\n", + "await scale.setup()" + ] }, { "cell_type": "markdown", @@ -176,10 +207,10 @@ "execution_count": 4, "metadata": { "execution": { - "iopub.execute_input": "2026-03-30T11:19:55.637514Z", - "iopub.status.busy": "2026-03-30T11:19:55.637424Z", - "iopub.status.idle": "2026-03-30T11:19:55.639309Z", - "shell.execute_reply": "2026-03-30T11:19:55.639148Z" + "iopub.execute_input": "2026-03-30T11:39:54.140106Z", + "iopub.status.busy": "2026-03-30T11:39:54.140043Z", + "iopub.status.idle": "2026-03-30T11:39:54.141851Z", + "shell.execute_reply": "2026-03-30T11:39:54.141688Z" } }, "outputs": [ @@ -187,14 +218,14 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 12:19:55,637 - pylabrobot - IO - [MT Scale] Sent command: ZC 5000\n" + "2026-03-30 12:39:54,140 - pylabrobot - IO - [MT Scale] Sent command: ZC 5000\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 12:19:55,638 - pylabrobot - IO - [MT Scale] Received response: ZC A \n" + "2026-03-30 12:39:54,140 - pylabrobot - IO - [MT Scale] Received response: ZC A \n" ] } ], @@ -228,10 +259,10 @@ "execution_count": 5, "metadata": { "execution": { - "iopub.execute_input": "2026-03-30T11:19:55.640331Z", - "iopub.status.busy": "2026-03-30T11:19:55.640257Z", - "iopub.status.idle": "2026-03-30T11:19:55.642042Z", - "shell.execute_reply": "2026-03-30T11:19:55.641892Z" + "iopub.execute_input": "2026-03-30T11:39:54.142831Z", + "iopub.status.busy": "2026-03-30T11:39:54.142766Z", + "iopub.status.idle": "2026-03-30T11:39:54.144510Z", + "shell.execute_reply": "2026-03-30T11:39:54.144357Z" } }, "outputs": [ @@ -239,14 +270,14 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 12:19:55,640 - pylabrobot - IO - [MT Scale] Sent command: TC 5000\n" + "2026-03-30 12:39:54,143 - pylabrobot - IO - [MT Scale] Sent command: TC 5000\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 12:19:55,640 - pylabrobot - IO - [MT Scale] Received response: TC S 50.00000 g\n" + "2026-03-30 12:39:54,143 - pylabrobot - IO - [MT Scale] Received response: TC S 50.00000 g\n" ] } ], @@ -269,10 +300,10 @@ "execution_count": 6, "metadata": { "execution": { - "iopub.execute_input": "2026-03-30T11:19:55.642990Z", - "iopub.status.busy": "2026-03-30T11:19:55.642926Z", - "iopub.status.idle": "2026-03-30T11:19:55.646014Z", - "shell.execute_reply": "2026-03-30T11:19:55.645844Z" + "iopub.execute_input": "2026-03-30T11:39:54.145365Z", + "iopub.status.busy": "2026-03-30T11:39:54.145307Z", + "iopub.status.idle": "2026-03-30T11:39:54.147713Z", + "shell.execute_reply": "2026-03-30T11:39:54.147548Z" } }, "outputs": [ @@ -280,14 +311,14 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 12:19:55,643 - pylabrobot - IO - [MT Scale] Sent command: TA\n" + "2026-03-30 12:39:54,145 - pylabrobot - IO - [MT Scale] Sent command: TA\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 12:19:55,643 - pylabrobot - IO - [MT Scale] Received response: TA A 50.00000 g\n" + "2026-03-30 12:39:54,145 - pylabrobot - IO - [MT Scale] Received response: TA A 50.00000 g\n" ] }, { @@ -320,10 +351,10 @@ "execution_count": 7, "metadata": { "execution": { - "iopub.execute_input": "2026-03-30T11:19:55.646916Z", - "iopub.status.busy": "2026-03-30T11:19:55.646865Z", - "iopub.status.idle": "2026-03-30T11:19:55.648964Z", - "shell.execute_reply": "2026-03-30T11:19:55.648791Z" + "iopub.execute_input": "2026-03-30T11:39:54.148612Z", + "iopub.status.busy": "2026-03-30T11:39:54.148553Z", + "iopub.status.idle": "2026-03-30T11:39:54.150500Z", + "shell.execute_reply": "2026-03-30T11:39:54.150349Z" } }, "outputs": [ @@ -331,14 +362,14 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 12:19:55,647 - pylabrobot - IO - [MT Scale] Sent command: SI\n" + "2026-03-30 12:39:54,148 - pylabrobot - IO - [MT Scale] Sent command: SI\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 12:19:55,647 - pylabrobot - IO - [MT Scale] Received response: SI S 0.01060 g\n" + "2026-03-30 12:39:54,149 - pylabrobot - IO - [MT Scale] Received response: SI S 0.01060 g\n" ] }, { @@ -374,10 +405,10 @@ "execution_count": 8, "metadata": { "execution": { - "iopub.execute_input": "2026-03-30T11:19:55.649859Z", - "iopub.status.busy": "2026-03-30T11:19:55.649803Z", - "iopub.status.idle": "2026-03-30T11:19:55.652854Z", - "shell.execute_reply": "2026-03-30T11:19:55.652695Z" + "iopub.execute_input": "2026-03-30T11:39:54.151381Z", + "iopub.status.busy": "2026-03-30T11:39:54.151322Z", + "iopub.status.idle": "2026-03-30T11:39:54.154524Z", + "shell.execute_reply": "2026-03-30T11:39:54.154304Z" } }, "outputs": [ @@ -385,42 +416,42 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 12:19:55,650 - pylabrobot - IO - [MT Scale] Sent command: Z\n" + "2026-03-30 12:39:54,152 - pylabrobot - IO - [MT Scale] Sent command: Z\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 12:19:55,650 - pylabrobot - IO - [MT Scale] Received response: Z A \n" + "2026-03-30 12:39:54,152 - pylabrobot - IO - [MT Scale] Received response: Z A \n" ] }, { "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 12:19:55,651 - pylabrobot - IO - [MT Scale] Sent command: TC 5000\n" + "2026-03-30 12:39:54,152 - pylabrobot - IO - [MT Scale] Sent command: TC 5000\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 12:19:55,651 - pylabrobot - IO - [MT Scale] Received response: TC S -0.01060 g\n" + "2026-03-30 12:39:54,152 - pylabrobot - IO - [MT Scale] Received response: TC S -0.01060 g\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 12:19:55,651 - pylabrobot - IO - [MT Scale] Sent command: SC 5000\n" + "2026-03-30 12:39:54,153 - pylabrobot - IO - [MT Scale] Sent command: SC 5000\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 12:19:55,651 - pylabrobot - IO - [MT Scale] Received response: SC S 0.01060 g\n" + "2026-03-30 12:39:54,153 - pylabrobot - IO - [MT Scale] Received response: SC S 0.01060 g\n" ] }, { @@ -491,10 +522,10 @@ "execution_count": 9, "metadata": { "execution": { - "iopub.execute_input": "2026-03-30T11:19:55.653828Z", - "iopub.status.busy": "2026-03-30T11:19:55.653770Z", - "iopub.status.idle": "2026-03-30T11:19:55.656072Z", - "shell.execute_reply": "2026-03-30T11:19:55.655903Z" + "iopub.execute_input": "2026-03-30T11:39:54.155465Z", + "iopub.status.busy": "2026-03-30T11:39:54.155403Z", + "iopub.status.idle": "2026-03-30T11:39:54.157630Z", + "shell.execute_reply": "2026-03-30T11:39:54.157421Z" } }, "outputs": [ @@ -502,28 +533,28 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 12:19:55,654 - pylabrobot - IO - [MT Scale] Sent command: I50\n" + "2026-03-30 12:39:54,155 - pylabrobot - IO - [MT Scale] Sent command: I50\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 12:19:55,654 - pylabrobot - IO - [MT Scale] Received response: I50 B 0 173.940 g\n" + "2026-03-30 12:39:54,156 - pylabrobot - IO - [MT Scale] Received response: I50 B 0 173.940 g\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 12:19:55,654 - pylabrobot - IO - [MT Scale] Received response: I50 B 1 0.000 g\n" + "2026-03-30 12:39:54,156 - pylabrobot - IO - [MT Scale] Received response: I50 B 1 0.000 g\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 12:19:55,654 - pylabrobot - IO - [MT Scale] Received response: I50 A 2 173.940 g\n" + "2026-03-30 12:39:54,156 - pylabrobot - IO - [MT Scale] Received response: I50 A 2 173.940 g\n" ] }, { @@ -554,10 +585,10 @@ "execution_count": 10, "metadata": { "execution": { - "iopub.execute_input": "2026-03-30T11:19:55.657043Z", - "iopub.status.busy": "2026-03-30T11:19:55.656982Z", - "iopub.status.idle": "2026-03-30T11:19:55.658865Z", - "shell.execute_reply": "2026-03-30T11:19:55.658709Z" + "iopub.execute_input": "2026-03-30T11:39:54.158514Z", + "iopub.status.busy": "2026-03-30T11:39:54.158456Z", + "iopub.status.idle": "2026-03-30T11:39:54.160205Z", + "shell.execute_reply": "2026-03-30T11:39:54.160072Z" } }, "outputs": [ @@ -565,14 +596,14 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 12:19:55,657 - pylabrobot - IO - [MT Scale] Sent command: M28\n" + "2026-03-30 12:39:54,158 - pylabrobot - IO - [MT Scale] Sent command: M28\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 12:19:55,657 - pylabrobot - IO - [MT Scale] Received response: M28 A 1 22.5\n" + "2026-03-30 12:39:54,158 - pylabrobot - IO - [MT Scale] Received response: M28 A 1 22.5\n" ] }, { @@ -606,10 +637,10 @@ "execution_count": 11, "metadata": { "execution": { - "iopub.execute_input": "2026-03-30T11:19:55.659692Z", - "iopub.status.busy": "2026-03-30T11:19:55.659637Z", - "iopub.status.idle": "2026-03-30T11:19:55.661156Z", - "shell.execute_reply": "2026-03-30T11:19:55.661018Z" + "iopub.execute_input": "2026-03-30T11:39:54.161093Z", + "iopub.status.busy": "2026-03-30T11:39:54.161022Z", + "iopub.status.idle": "2026-03-30T11:39:54.162575Z", + "shell.execute_reply": "2026-03-30T11:39:54.162432Z" } }, "outputs": [], @@ -654,10 +685,10 @@ "execution_count": 12, "metadata": { "execution": { - "iopub.execute_input": "2026-03-30T11:19:55.661985Z", - "iopub.status.busy": "2026-03-30T11:19:55.661936Z", - "iopub.status.idle": "2026-03-30T11:19:55.663573Z", - "shell.execute_reply": "2026-03-30T11:19:55.663414Z" + "iopub.execute_input": "2026-03-30T11:39:54.163442Z", + "iopub.status.busy": "2026-03-30T11:39:54.163385Z", + "iopub.status.idle": "2026-03-30T11:39:54.165227Z", + "shell.execute_reply": "2026-03-30T11:39:54.165070Z" } }, "outputs": [ @@ -665,14 +696,14 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 12:19:55,662 - pylabrobot - INFO - === MT Scale tutorial ended ===\n" + "2026-03-30 12:39:54,163 - pylabrobot - INFO - === MT Scale tutorial ended ===\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 12:19:55,662 - pylabrobot - INFO - [MT Scale] Disconnected (simulation)\n" + "2026-03-30 12:39:54,164 - pylabrobot - INFO - [MT Scale] Disconnected (simulation)\n" ] } ], @@ -703,4 +734,4 @@ }, "nbformat": 4, "nbformat_minor": 2 -} \ No newline at end of file +} diff --git a/pylabrobot/scales/mettler_toledo/backend.py b/pylabrobot/scales/mettler_toledo/backend.py index 8e8eaa513d0..ed119414805 100644 --- a/pylabrobot/scales/mettler_toledo/backend.py +++ b/pylabrobot/scales/mettler_toledo/backend.py @@ -399,6 +399,105 @@ async def request_capacity(self) -> float: self._validate_unit(parts[-1], "I2") return float(parts[-2]) + async def request_software_version(self) -> str: + """Query the software version and type definition number. (I3 command) + + Returns the version string (e.g. "2.10 10.28.0.493.142"). + For bridge mode (no terminal), returns the bridge software version. + """ + responses = await self.send_command("I3") + self._validate_response(responses[0], 3, "I3") + return responses[0].data[0] + + async def request_software_material_number(self) -> str: + """Query the software material number (SW-ID). (I5 command) + + Unique per software release: 8-digit number + alphabetic index. + For bridge mode (no terminal), returns the bridge SW-ID. + """ + responses = await self.send_command("I5") + self._validate_response(responses[0], 3, "I5") + return responses[0].data[0] + + @requires_mt_sics_command("I10") + async def request_device_id(self) -> str: + """Query the user-assigned device identification string. (I10 command) + + This is a user-configurable name (max 20 chars) to identify + individual scales in multi-device setups. Retained after @ cancel. + """ + responses = await self.send_command("I10") + self._validate_response(responses[0], 3, "I10") + return responses[0].data[0] + + @requires_mt_sics_command("I10") + async def set_device_id(self, device_id: str) -> None: + """Set the user-assigned device identification string. (I10 command) + + Max 20 alphanumeric characters. Retained after @ cancel. + Useful for labeling individual scales in multi-device setups. + """ + await self.send_command(f'I10 "{device_id}"') + + @requires_mt_sics_command("I11") + async def request_model_designation(self) -> str: + """Query the model designation string. (I11 command) + + Returns the weigh module model type (e.g. "WMS404C-L/10"). + Abbreviations: DR=Delta Range, DU=Dual Range, /M or /A=Approved. + """ + responses = await self.send_command("I11") + self._validate_response(responses[0], 3, "I11") + return responses[0].data[0] + + @requires_mt_sics_command("I14") + async def request_device_info(self) -> List[MettlerToledoResponse]: + """Query detailed device information including all components. (I14 command) + + Returns multi-response with instrument configuration (No=0), + descriptions (No=1), SW identification numbers (No=2), + SW versions (No=3), serial numbers (No=4), and TDNR numbers (No=5). + Each category reports data for bridge, terminal, options, etc. + """ + return await self.send_command("I14") + + @requires_mt_sics_command("I15") + async def request_uptime(self) -> dict: + """Query the device uptime. (I15 command) + + Returns a dict with keys "days", "hours", "minutes", "seconds". + Counts time since last power-on, including short interruptions. + Not reset by @ cancel or restart. + """ + responses = await self.send_command("I15") + self._validate_response(responses[0], 6, "I15") + return { + "days": int(responses[0].data[0]), + "hours": int(responses[0].data[1]), + "minutes": int(responses[0].data[2]), + "seconds": int(responses[0].data[3]), + } + + @requires_mt_sics_command("DAT") + async def request_date(self) -> str: + """Query the current date from the device. (DAT command) + + Returns the date string as reported by the device. + """ + responses = await self.send_command("DAT") + self._validate_response(responses[0], 3, "DAT") + return responses[0].data[0] + + @requires_mt_sics_command("TIM") + async def request_time(self) -> str: + """Query the current time from the device. (TIM command) + + Returns the time string as reported by the device. + """ + responses = await self.send_command("TIM") + self._validate_response(responses[0], 3, "TIM") + return responses[0].data[0] + @requires_mt_sics_command("I50") async def request_remaining_weighing_range(self) -> float: """Query remaining maximum weighing range in grams. (I50 command) diff --git a/pylabrobot/scales/mettler_toledo/hardware_validation.ipynb b/pylabrobot/scales/mettler_toledo/hardware_validation.ipynb index b1b92495f7c..258026d4a72 100644 --- a/pylabrobot/scales/mettler_toledo/hardware_validation.ipynb +++ b/pylabrobot/scales/mettler_toledo/hardware_validation.ipynb @@ -571,6 +571,18 @@ " print(f\" {cmd}: {status}\")" ] }, + { + "cell_type": "markdown", + "source": "### Device identity and diagnostics (Batch 1)\n\nThese commands complete the device identity picture beyond I2/I4.", + "metadata": {} + }, + { + "cell_type": "code", + "source": "# I3 - Software version (Level 0, always available)\nsw_version = await backend.request_software_version()\nprint(f\"Software version: {sw_version}\")\n\n# I5 - Software material number (Level 0, always available)\nsw_material = await backend.request_software_material_number()\nprint(f\"Software material number: {sw_material}\")\n\n# I10 - Device ID (user-assignable name)\nif \"I10\" in backend._supported_commands:\n device_id = await backend.request_device_id()\n print(f\"Device ID: '{device_id}'\")\nelse:\n print(\"SKIP: I10 not supported\")\n\n# I11 - Model designation\nif \"I11\" in backend._supported_commands:\n model = await backend.request_model_designation()\n print(f\"Model designation: {model}\")\nelse:\n print(\"SKIP: I11 not supported\")\n\n# I15 - Uptime\nif \"I15\" in backend._supported_commands:\n uptime = await backend.request_uptime()\n print(f\"Uptime: {uptime['days']}d {uptime['hours']}h {uptime['minutes']}m {uptime['seconds']}s\")\nelse:\n print(\"SKIP: I15 not supported\")\n\n# DAT - Date\nif \"DAT\" in backend._supported_commands:\n date = await backend.request_date()\n print(f\"Device date: {date}\")\nelse:\n print(\"SKIP: DAT not supported\")\n\n# TIM - Time\nif \"TIM\" in backend._supported_commands:\n time_str = await backend.request_time()\n print(f\"Device time: {time_str}\")\nelse:\n print(\"SKIP: TIM not supported\")\n\n# I14 - Comprehensive device info (multi-response)\nif \"I14\" in backend._supported_commands:\n info_responses = await backend.request_device_info()\n print(f\"\\nDevice info ({len(info_responses)} response lines):\")\n for resp in info_responses:\n print(f\" {resp.command} {resp.status} {' '.join(resp.data)}\")\nelse:\n print(\"SKIP: I14 not supported\")\n\nprint(\"\\nPASS: Batch 1 device identity commands completed\")", + "metadata": {}, + "execution_count": null, + "outputs": [] + }, { "cell_type": "markdown", "metadata": {}, @@ -1659,4 +1671,4 @@ }, "nbformat": 4, "nbformat_minor": 4 -} +} \ No newline at end of file diff --git a/pylabrobot/scales/mettler_toledo/simulator.py b/pylabrobot/scales/mettler_toledo/simulator.py index ac0be88576b..d39a61322a3 100644 --- a/pylabrobot/scales/mettler_toledo/simulator.py +++ b/pylabrobot/scales/mettler_toledo/simulator.py @@ -69,7 +69,14 @@ def __init__( "I0", "I1", "I2", + "I3", "I4", + "I5", + "I10", + "I11", + "I14", + "I15", + "I50", "S", "SI", "Z", @@ -84,9 +91,10 @@ def __init__( "C", "D", "DW", + "DAT", + "TIM", "M21", "M28", - "I50", "SR", "SIR", } @@ -153,6 +161,29 @@ def _build_response(self, command: str) -> List[MettlerToledoResponse]: return [R("I2", "A", [f"{self._simulated_device_type} {self._simulated_capacity:.5f} g"])] if cmd == "I4": return [R("I4", "A", [self._simulated_serial_number])] + if cmd == "I3": + return [R("I3", "A", ["2.10 10.28.0.493.142"])] + if cmd == "I5": + return [R("I5", "A", ["12121306C"])] + if cmd == "I10": + # I10 can be query or set + parts = command.split(maxsplit=1) + if len(parts) > 1: + return [R("I10", "A")] + return [R("I10", "A", ["SimScale"])] + if cmd == "I11": + return [R("I11", "A", [self._simulated_device_type])] + if cmd == "I14": + return [ + R("I14", "B", ["0", "1", "Bridge"]), + R("I14", "A", ["1", "1", self._simulated_device_type]), + ] + if cmd == "I15": + return [R("I15", "A", ["42", "3", "15", "30"])] + if cmd == "DAT": + return [R("DAT", "A", ["30.03.2026"])] + if cmd == "TIM": + return [R("TIM", "A", ["12:00:00"])] # Zero if cmd in ("Z", "ZI", "ZC"): From d614c844c8a9b0cb09be493e414b5b112e31b2c5 Mon Sep 17 00:00:00 2001 From: Camillo Moschner Date: Mon, 30 Mar 2026 12:42:58 +0100 Subject: [PATCH 20/38] results batch 1 --- .../mettler_toledo/hardware_validation.ipynb | 1179 +++++++++-------- 1 file changed, 658 insertions(+), 521 deletions(-) diff --git a/pylabrobot/scales/mettler_toledo/hardware_validation.ipynb b/pylabrobot/scales/mettler_toledo/hardware_validation.ipynb index 258026d4a72..8e43b1b5775 100644 --- a/pylabrobot/scales/mettler_toledo/hardware_validation.ipynb +++ b/pylabrobot/scales/mettler_toledo/hardware_validation.ipynb @@ -33,7 +33,7 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 12:07:26,881 - pylabrobot - INFO - === Hardware validation started ===\n" + "2026-03-30 12:40:59,695 - pylabrobot - INFO - === Hardware validation started ===\n" ] } ], @@ -65,155 +65,155 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 12:07:26,905 - pylabrobot.io.serial - INFO - Using explicitly provided port: /dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0 (for VID=1027, PID=24577)\n", - "2026-03-30 12:07:26,921 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] reset_input_buffer\n", - "2026-03-30 12:07:26,923 - pylabrobot - IO - [MT Scale] Sent command: @\n", - "2026-03-30 12:07:26,927 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'@\\r\\n'\n", - "2026-03-30 12:07:26,992 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I4 A \"B207696838\"\\r\\n'\n", - "2026-03-30 12:07:26,993 - pylabrobot - IO - [MT Scale] Received response: b'I4 A \"B207696838\"\\r\\n'\n", - "2026-03-30 12:07:26,994 - pylabrobot - IO - [MT Scale] Sent command: I0\n", - "2026-03-30 12:07:26,995 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I0\\r\\n'\n", - "2026-03-30 12:07:27,025 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I0\"\\r\\n'\n", - "2026-03-30 12:07:27,026 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I0\"\\r\\n'\n", - "2026-03-30 12:07:27,040 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I1\"\\r\\n'\n", - "2026-03-30 12:07:27,041 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I1\"\\r\\n'\n", - "2026-03-30 12:07:27,056 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I2\"\\r\\n'\n", - "2026-03-30 12:07:27,057 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I2\"\\r\\n'\n", - "2026-03-30 12:07:27,073 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I3\"\\r\\n'\n", - "2026-03-30 12:07:27,074 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I3\"\\r\\n'\n", - "2026-03-30 12:07:27,077 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I4\"\\r\\n'\n", - "2026-03-30 12:07:27,078 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I4\"\\r\\n'\n", - "2026-03-30 12:07:27,089 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I5\"\\r\\n'\n", - "2026-03-30 12:07:27,092 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I5\"\\r\\n'\n", - "2026-03-30 12:07:27,104 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"S\"\\r\\n'\n", - "2026-03-30 12:07:27,106 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"S\"\\r\\n'\n", - "2026-03-30 12:07:27,120 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"SI\"\\r\\n'\n", - "2026-03-30 12:07:27,121 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"SI\"\\r\\n'\n", - "2026-03-30 12:07:27,136 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"SIR\"\\r\\n'\n", - "2026-03-30 12:07:27,137 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"SIR\"\\r\\n'\n", - "2026-03-30 12:07:27,153 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"Z\"\\r\\n'\n", - "2026-03-30 12:07:27,154 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"Z\"\\r\\n'\n", - "2026-03-30 12:07:27,156 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"ZI\"\\r\\n'\n", - "2026-03-30 12:07:27,158 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"ZI\"\\r\\n'\n", - "2026-03-30 12:07:27,168 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"@\"\\r\\n'\n", - "2026-03-30 12:07:27,170 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"@\"\\r\\n'\n", - "2026-03-30 12:07:27,184 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"SR\"\\r\\n'\n", - "2026-03-30 12:07:27,186 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"SR\"\\r\\n'\n", - "2026-03-30 12:07:27,200 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"T\"\\r\\n'\n", - "2026-03-30 12:07:27,203 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"T\"\\r\\n'\n", - "2026-03-30 12:07:27,217 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"TA\"\\r\\n'\n", - "2026-03-30 12:07:27,220 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"TA\"\\r\\n'\n", - "2026-03-30 12:07:27,232 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"TAC\"\\r\\n'\n", - "2026-03-30 12:07:27,235 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"TAC\"\\r\\n'\n", - "2026-03-30 12:07:27,248 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"TI\"\\r\\n'\n", - "2026-03-30 12:07:27,251 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"TI\"\\r\\n'\n", - "2026-03-30 12:07:27,264 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C0\"\\r\\n'\n", - "2026-03-30 12:07:27,270 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"C0\"\\r\\n'\n", - "2026-03-30 12:07:27,276 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C1\"\\r\\n'\n", - "2026-03-30 12:07:27,278 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"C1\"\\r\\n'\n", - "2026-03-30 12:07:27,281 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C2\"\\r\\n'\n", - "2026-03-30 12:07:27,282 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"C2\"\\r\\n'\n", - "2026-03-30 12:07:27,296 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C3\"\\r\\n'\n", - "2026-03-30 12:07:27,297 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"C3\"\\r\\n'\n", - "2026-03-30 12:07:27,312 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"COM\"\\r\\n'\n", - "2026-03-30 12:07:27,314 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"COM\"\\r\\n'\n", - "2026-03-30 12:07:27,328 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"DAT\"\\r\\n'\n", - "2026-03-30 12:07:27,330 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"DAT\"\\r\\n'\n", - "2026-03-30 12:07:27,346 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I10\"\\r\\n'\n", - "2026-03-30 12:07:27,350 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I10\"\\r\\n'\n", - "2026-03-30 12:07:27,360 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I11\"\\r\\n'\n", - "2026-03-30 12:07:27,362 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I11\"\\r\\n'\n", - "2026-03-30 12:07:27,377 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I14\"\\r\\n'\n", - "2026-03-30 12:07:27,380 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I14\"\\r\\n'\n", - "2026-03-30 12:07:27,386 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I15\"\\r\\n'\n", - "2026-03-30 12:07:27,389 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I15\"\\r\\n'\n", - "2026-03-30 12:07:27,391 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I16\"\\r\\n'\n", - "2026-03-30 12:07:27,393 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I16\"\\r\\n'\n", - "2026-03-30 12:07:27,408 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I21\"\\r\\n'\n", - "2026-03-30 12:07:27,410 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I21\"\\r\\n'\n", - "2026-03-30 12:07:27,424 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I22\"\\r\\n'\n", - "2026-03-30 12:07:27,428 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I22\"\\r\\n'\n", - "2026-03-30 12:07:27,440 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I23\"\\r\\n'\n", - "2026-03-30 12:07:27,441 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I23\"\\r\\n'\n", - "2026-03-30 12:07:27,457 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I24\"\\r\\n'\n", - "2026-03-30 12:07:27,459 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I24\"\\r\\n'\n", - "2026-03-30 12:07:27,472 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I25\"\\r\\n'\n", - "2026-03-30 12:07:27,477 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I25\"\\r\\n'\n", - "2026-03-30 12:07:27,488 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I26\"\\r\\n'\n", - "2026-03-30 12:07:27,490 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I26\"\\r\\n'\n", - "2026-03-30 12:07:27,504 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M01\"\\r\\n'\n", - "2026-03-30 12:07:27,505 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M01\"\\r\\n'\n", - "2026-03-30 12:07:27,520 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M02\"\\r\\n'\n", - "2026-03-30 12:07:27,520 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M02\"\\r\\n'\n", - "2026-03-30 12:07:27,536 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M03\"\\r\\n'\n", - "2026-03-30 12:07:27,537 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M03\"\\r\\n'\n", - "2026-03-30 12:07:27,538 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M17\"\\r\\n'\n", - "2026-03-30 12:07:27,539 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M17\"\\r\\n'\n", - "2026-03-30 12:07:27,551 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M18\"\\r\\n'\n", - "2026-03-30 12:07:27,552 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M18\"\\r\\n'\n", - "2026-03-30 12:07:27,568 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M19\"\\r\\n'\n", - "2026-03-30 12:07:27,568 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M19\"\\r\\n'\n", - "2026-03-30 12:07:27,584 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M20\"\\r\\n'\n", - "2026-03-30 12:07:27,585 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M20\"\\r\\n'\n", - "2026-03-30 12:07:27,599 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M21\"\\r\\n'\n", - "2026-03-30 12:07:27,600 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M21\"\\r\\n'\n", - "2026-03-30 12:07:27,616 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M27\"\\r\\n'\n", - "2026-03-30 12:07:27,617 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M27\"\\r\\n'\n", - "2026-03-30 12:07:27,631 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M28\"\\r\\n'\n", - "2026-03-30 12:07:27,632 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M28\"\\r\\n'\n", - "2026-03-30 12:07:27,647 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M29\"\\r\\n'\n", - "2026-03-30 12:07:27,648 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M29\"\\r\\n'\n", - "2026-03-30 12:07:27,664 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M31\"\\r\\n'\n", - "2026-03-30 12:07:27,665 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M31\"\\r\\n'\n", - "2026-03-30 12:07:27,679 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M32\"\\r\\n'\n", - "2026-03-30 12:07:27,680 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M32\"\\r\\n'\n", - "2026-03-30 12:07:27,695 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M33\"\\r\\n'\n", - "2026-03-30 12:07:27,696 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M33\"\\r\\n'\n", - "2026-03-30 12:07:27,698 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M35\"\\r\\n'\n", - "2026-03-30 12:07:27,698 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M35\"\\r\\n'\n", - "2026-03-30 12:07:27,712 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"SIS\"\\r\\n'\n", - "2026-03-30 12:07:27,713 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"SIS\"\\r\\n'\n", - "2026-03-30 12:07:27,727 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"SNR\"\\r\\n'\n", - "2026-03-30 12:07:27,728 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"SNR\"\\r\\n'\n", - "2026-03-30 12:07:27,743 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TIM\"\\r\\n'\n", - "2026-03-30 12:07:27,744 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TIM\"\\r\\n'\n", - "2026-03-30 12:07:27,760 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST0\"\\r\\n'\n", - "2026-03-30 12:07:27,760 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TST0\"\\r\\n'\n", - "2026-03-30 12:07:27,775 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST1\"\\r\\n'\n", - "2026-03-30 12:07:27,776 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TST1\"\\r\\n'\n", - "2026-03-30 12:07:27,791 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST2\"\\r\\n'\n", - "2026-03-30 12:07:27,792 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TST2\"\\r\\n'\n", - "2026-03-30 12:07:27,808 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST3\"\\r\\n'\n", - "2026-03-30 12:07:27,809 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TST3\"\\r\\n'\n", - "2026-03-30 12:07:27,823 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"UPD\"\\r\\n'\n", - "2026-03-30 12:07:27,824 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"UPD\"\\r\\n'\n", - "2026-03-30 12:07:27,839 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"FCUT\"\\r\\n'\n", - "2026-03-30 12:07:27,840 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 3 \"FCUT\"\\r\\n'\n", - "2026-03-30 12:07:27,856 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"FSET\"\\r\\n'\n", - "2026-03-30 12:07:27,856 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 3 \"FSET\"\\r\\n'\n", - "2026-03-30 12:07:27,871 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"LST\"\\r\\n'\n", - "2026-03-30 12:07:27,872 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 3 \"LST\"\\r\\n'\n", - "2026-03-30 12:07:27,895 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"RDB\"\\r\\n'\n", - "2026-03-30 12:07:27,898 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 3 \"RDB\"\\r\\n'\n", - "2026-03-30 12:07:27,912 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 A 3 \"USTB\"\\r\\n'\n", - "2026-03-30 12:07:27,921 - pylabrobot - IO - [MT Scale] Received response: b'I0 A 3 \"USTB\"\\r\\n'\n", - "2026-03-30 12:07:27,926 - pylabrobot - IO - [MT Scale] Sent command: I2\n", - "2026-03-30 12:07:27,930 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I2\\r\\n'\n", - "2026-03-30 12:07:28,000 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", - "2026-03-30 12:07:28,002 - pylabrobot - IO - [MT Scale] Received response: b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", - "2026-03-30 12:07:28,005 - pylabrobot - IO - [MT Scale] Sent command: I2\n", - "2026-03-30 12:07:28,013 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I2\\r\\n'\n", - "2026-03-30 12:07:28,080 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", - "2026-03-30 12:07:28,084 - pylabrobot - IO - [MT Scale] Received response: b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", - "2026-03-30 12:07:28,087 - pylabrobot - INFO - [MT Scale] Connected to Mettler Toledo scale on /dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0\n", + "2026-03-30 12:40:59,710 - pylabrobot.io.serial - INFO - Using explicitly provided port: /dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0 (for VID=1027, PID=24577)\n", + "2026-03-30 12:40:59,718 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] reset_input_buffer\n", + "2026-03-30 12:40:59,720 - pylabrobot - IO - [MT Scale] Sent command: @\n", + "2026-03-30 12:40:59,723 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'@\\r\\n'\n", + "2026-03-30 12:40:59,780 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I4 A \"B207696838\"\\r\\n'\n", + "2026-03-30 12:40:59,781 - pylabrobot - IO - [MT Scale] Received response: b'I4 A \"B207696838\"\\r\\n'\n", + "2026-03-30 12:40:59,781 - pylabrobot - IO - [MT Scale] Sent command: I0\n", + "2026-03-30 12:40:59,783 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I0\\r\\n'\n", + "2026-03-30 12:40:59,812 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I0\"\\r\\n'\n", + "2026-03-30 12:40:59,813 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I0\"\\r\\n'\n", + "2026-03-30 12:40:59,828 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I1\"\\r\\n'\n", + "2026-03-30 12:40:59,829 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I1\"\\r\\n'\n", + "2026-03-30 12:40:59,843 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I2\"\\r\\n'\n", + "2026-03-30 12:40:59,844 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I2\"\\r\\n'\n", + "2026-03-30 12:40:59,859 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I3\"\\r\\n'\n", + "2026-03-30 12:40:59,860 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I3\"\\r\\n'\n", + "2026-03-30 12:40:59,876 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I4\"\\r\\n'\n", + "2026-03-30 12:40:59,877 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I4\"\\r\\n'\n", + "2026-03-30 12:40:59,878 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I5\"\\r\\n'\n", + "2026-03-30 12:40:59,878 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I5\"\\r\\n'\n", + "2026-03-30 12:40:59,891 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"S\"\\r\\n'\n", + "2026-03-30 12:40:59,892 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"S\"\\r\\n'\n", + "2026-03-30 12:40:59,908 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"SI\"\\r\\n'\n", + "2026-03-30 12:40:59,908 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"SI\"\\r\\n'\n", + "2026-03-30 12:40:59,923 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"SIR\"\\r\\n'\n", + "2026-03-30 12:40:59,924 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"SIR\"\\r\\n'\n", + "2026-03-30 12:40:59,939 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"Z\"\\r\\n'\n", + "2026-03-30 12:40:59,940 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"Z\"\\r\\n'\n", + "2026-03-30 12:40:59,956 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"ZI\"\\r\\n'\n", + "2026-03-30 12:40:59,956 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"ZI\"\\r\\n'\n", + "2026-03-30 12:40:59,958 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"@\"\\r\\n'\n", + "2026-03-30 12:40:59,958 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"@\"\\r\\n'\n", + "2026-03-30 12:40:59,971 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"SR\"\\r\\n'\n", + "2026-03-30 12:40:59,972 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"SR\"\\r\\n'\n", + "2026-03-30 12:40:59,987 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"T\"\\r\\n'\n", + "2026-03-30 12:40:59,988 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"T\"\\r\\n'\n", + "2026-03-30 12:41:00,004 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"TA\"\\r\\n'\n", + "2026-03-30 12:41:00,004 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"TA\"\\r\\n'\n", + "2026-03-30 12:41:00,019 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"TAC\"\\r\\n'\n", + "2026-03-30 12:41:00,020 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"TAC\"\\r\\n'\n", + "2026-03-30 12:41:00,035 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"TI\"\\r\\n'\n", + "2026-03-30 12:41:00,036 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"TI\"\\r\\n'\n", + "2026-03-30 12:41:00,037 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C0\"\\r\\n'\n", + "2026-03-30 12:41:00,038 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"C0\"\\r\\n'\n", + "2026-03-30 12:41:00,052 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C1\"\\r\\n'\n", + "2026-03-30 12:41:00,052 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"C1\"\\r\\n'\n", + "2026-03-30 12:41:00,067 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C2\"\\r\\n'\n", + "2026-03-30 12:41:00,068 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"C2\"\\r\\n'\n", + "2026-03-30 12:41:00,083 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C3\"\\r\\n'\n", + "2026-03-30 12:41:00,084 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"C3\"\\r\\n'\n", + "2026-03-30 12:41:00,100 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"COM\"\\r\\n'\n", + "2026-03-30 12:41:00,101 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"COM\"\\r\\n'\n", + "2026-03-30 12:41:00,115 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"DAT\"\\r\\n'\n", + "2026-03-30 12:41:00,116 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"DAT\"\\r\\n'\n", + "2026-03-30 12:41:00,131 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I10\"\\r\\n'\n", + "2026-03-30 12:41:00,132 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I10\"\\r\\n'\n", + "2026-03-30 12:41:00,147 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I11\"\\r\\n'\n", + "2026-03-30 12:41:00,147 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I11\"\\r\\n'\n", + "2026-03-30 12:41:00,163 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I14\"\\r\\n'\n", + "2026-03-30 12:41:00,164 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I14\"\\r\\n'\n", + "2026-03-30 12:41:00,179 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I15\"\\r\\n'\n", + "2026-03-30 12:41:00,180 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I15\"\\r\\n'\n", + "2026-03-30 12:41:00,181 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I16\"\\r\\n'\n", + "2026-03-30 12:41:00,182 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I16\"\\r\\n'\n", + "2026-03-30 12:41:00,195 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I21\"\\r\\n'\n", + "2026-03-30 12:41:00,195 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I21\"\\r\\n'\n", + "2026-03-30 12:41:00,211 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I22\"\\r\\n'\n", + "2026-03-30 12:41:00,212 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I22\"\\r\\n'\n", + "2026-03-30 12:41:00,227 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I23\"\\r\\n'\n", + "2026-03-30 12:41:00,228 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I23\"\\r\\n'\n", + "2026-03-30 12:41:00,243 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I24\"\\r\\n'\n", + "2026-03-30 12:41:00,243 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I24\"\\r\\n'\n", + "2026-03-30 12:41:00,259 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I25\"\\r\\n'\n", + "2026-03-30 12:41:00,260 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I25\"\\r\\n'\n", + "2026-03-30 12:41:00,275 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I26\"\\r\\n'\n", + "2026-03-30 12:41:00,276 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I26\"\\r\\n'\n", + "2026-03-30 12:41:00,291 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M01\"\\r\\n'\n", + "2026-03-30 12:41:00,291 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M01\"\\r\\n'\n", + "2026-03-30 12:41:00,307 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M02\"\\r\\n'\n", + "2026-03-30 12:41:00,308 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M02\"\\r\\n'\n", + "2026-03-30 12:41:00,323 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M03\"\\r\\n'\n", + "2026-03-30 12:41:00,324 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M03\"\\r\\n'\n", + "2026-03-30 12:41:00,339 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M17\"\\r\\n'\n", + "2026-03-30 12:41:00,340 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M17\"\\r\\n'\n", + "2026-03-30 12:41:00,341 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M18\"\\r\\n'\n", + "2026-03-30 12:41:00,342 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M18\"\\r\\n'\n", + "2026-03-30 12:41:00,355 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M19\"\\r\\n'\n", + "2026-03-30 12:41:00,356 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M19\"\\r\\n'\n", + "2026-03-30 12:41:00,372 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M20\"\\r\\n'\n", + "2026-03-30 12:41:00,372 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M20\"\\r\\n'\n", + "2026-03-30 12:41:00,387 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M21\"\\r\\n'\n", + "2026-03-30 12:41:00,387 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M21\"\\r\\n'\n", + "2026-03-30 12:41:00,403 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M27\"\\r\\n'\n", + "2026-03-30 12:41:00,404 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M27\"\\r\\n'\n", + "2026-03-30 12:41:00,420 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M28\"\\r\\n'\n", + "2026-03-30 12:41:00,420 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M28\"\\r\\n'\n", + "2026-03-30 12:41:00,435 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M29\"\\r\\n'\n", + "2026-03-30 12:41:00,435 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M29\"\\r\\n'\n", + "2026-03-30 12:41:00,451 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M31\"\\r\\n'\n", + "2026-03-30 12:41:00,452 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M31\"\\r\\n'\n", + "2026-03-30 12:41:00,467 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M32\"\\r\\n'\n", + "2026-03-30 12:41:00,468 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M32\"\\r\\n'\n", + "2026-03-30 12:41:00,483 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M33\"\\r\\n'\n", + "2026-03-30 12:41:00,484 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M33\"\\r\\n'\n", + "2026-03-30 12:41:00,499 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M35\"\\r\\n'\n", + "2026-03-30 12:41:00,500 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M35\"\\r\\n'\n", + "2026-03-30 12:41:00,501 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"SIS\"\\r\\n'\n", + "2026-03-30 12:41:00,502 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"SIS\"\\r\\n'\n", + "2026-03-30 12:41:00,515 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"SNR\"\\r\\n'\n", + "2026-03-30 12:41:00,515 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"SNR\"\\r\\n'\n", + "2026-03-30 12:41:00,531 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TIM\"\\r\\n'\n", + "2026-03-30 12:41:00,532 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TIM\"\\r\\n'\n", + "2026-03-30 12:41:00,546 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST0\"\\r\\n'\n", + "2026-03-30 12:41:00,547 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TST0\"\\r\\n'\n", + "2026-03-30 12:41:00,563 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST1\"\\r\\n'\n", + "2026-03-30 12:41:00,563 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TST1\"\\r\\n'\n", + "2026-03-30 12:41:00,579 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST2\"\\r\\n'\n", + "2026-03-30 12:41:00,580 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TST2\"\\r\\n'\n", + "2026-03-30 12:41:00,595 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST3\"\\r\\n'\n", + "2026-03-30 12:41:00,595 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TST3\"\\r\\n'\n", + "2026-03-30 12:41:00,611 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"UPD\"\\r\\n'\n", + "2026-03-30 12:41:00,612 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"UPD\"\\r\\n'\n", + "2026-03-30 12:41:00,627 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"FCUT\"\\r\\n'\n", + "2026-03-30 12:41:00,628 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 3 \"FCUT\"\\r\\n'\n", + "2026-03-30 12:41:00,643 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"FSET\"\\r\\n'\n", + "2026-03-30 12:41:00,644 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 3 \"FSET\"\\r\\n'\n", + "2026-03-30 12:41:00,659 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"LST\"\\r\\n'\n", + "2026-03-30 12:41:00,659 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 3 \"LST\"\\r\\n'\n", + "2026-03-30 12:41:00,675 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"RDB\"\\r\\n'\n", + "2026-03-30 12:41:00,676 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 3 \"RDB\"\\r\\n'\n", + "2026-03-30 12:41:00,690 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 A 3 \"USTB\"\\r\\n'\n", + "2026-03-30 12:41:00,691 - pylabrobot - IO - [MT Scale] Received response: b'I0 A 3 \"USTB\"\\r\\n'\n", + "2026-03-30 12:41:00,692 - pylabrobot - IO - [MT Scale] Sent command: I2\n", + "2026-03-30 12:41:00,693 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I2\\r\\n'\n", + "2026-03-30 12:41:00,755 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", + "2026-03-30 12:41:00,756 - pylabrobot - IO - [MT Scale] Received response: b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", + "2026-03-30 12:41:00,756 - pylabrobot - IO - [MT Scale] Sent command: I2\n", + "2026-03-30 12:41:00,757 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I2\\r\\n'\n", + "2026-03-30 12:41:00,818 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", + "2026-03-30 12:41:00,819 - pylabrobot - IO - [MT Scale] Received response: b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", + "2026-03-30 12:41:00,819 - pylabrobot - INFO - [MT Scale] Connected to Mettler Toledo scale on /dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0\n", "Device type: WXS205SDU WXA-Bridge\n", "Serial number: B207696838\n", "Capacity: 220.0 g\n", "Supported commands: ['@', 'C0', 'C1', 'C2', 'C3', 'COM', 'DAT', 'FCUT', 'FSET', 'I0', 'I1', 'I10', 'I11', 'I14', 'I15', 'I16', 'I2', 'I21', 'I22', 'I23', 'I24', 'I25', 'I26', 'I3', 'I4', 'I5', 'LST', 'M01', 'M02', 'M03', 'M17', 'M18', 'M19', 'M20', 'M21', 'M27', 'M28', 'M29', 'M31', 'M32', 'M33', 'M35', 'RDB', 'S', 'SI', 'SIR', 'SIS', 'SNR', 'SR', 'T', 'TA', 'TAC', 'TI', 'TIM', 'TST0', 'TST1', 'TST2', 'TST3', 'UPD', 'USTB', 'Z', 'ZI']\n", - "2026-03-30 12:07:28,088 - pylabrobot - IO - [MT Scale] Sent command: M21 0 0\n", - "2026-03-30 12:07:28,092 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'M21 0 0\\r\\n'\n", - "2026-03-30 12:07:28,127 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M21 A\\r\\n'\n", - "2026-03-30 12:07:28,131 - pylabrobot - IO - [MT Scale] Received response: b'M21 A\\r\\n'\n" + "2026-03-30 12:41:00,820 - pylabrobot - IO - [MT Scale] Sent command: M21 0 0\n", + "2026-03-30 12:41:00,821 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'M21 0 0\\r\\n'\n", + "2026-03-30 12:41:00,851 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M21 A\\r\\n'\n", + "2026-03-30 12:41:00,852 - pylabrobot - IO - [MT Scale] Received response: b'M21 A\\r\\n'\n" ] } ], @@ -282,30 +282,34 @@ "name": "stdout", "output_type": "stream", "text": [ - "36 methods available on this device:\n", + "40 methods available on this device:\n", " cancel\n", " cancel_all\n", " clear_tare\n", " deserialize\n", " get_all_instances\n", - " get_dynamic_weight\n", - " get_serial_number\n", - " get_stable_weight\n", - " get_tare_weight\n", " get_weight\n", - " get_weight_value_immediately\n", " measure_temperature\n", " read_dynamic_weight\n", " read_stable_weight\n", " read_weight\n", " read_weight_value_immediately\n", " request_capacity\n", + " request_date\n", + " request_device_id\n", + " request_device_info\n", " request_device_type\n", + " request_model_designation\n", " request_serial_number\n", + " request_software_material_number\n", + " request_software_version\n", " request_supported_methods\n", " request_tare_weight\n", + " request_time\n", + " request_uptime\n", " send_command\n", " serialize\n", + " set_device_id\n", " set_display_text\n", " set_host_unit_grams\n", " set_weight_display\n", @@ -348,132 +352,132 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 12:07:28,202 - pylabrobot - IO - [MT Scale] Sent command: I0\n", - "2026-03-30 12:07:28,210 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I0\\r\\n'\n", - "2026-03-30 12:07:28,239 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I0\"\\r\\n'\n", - "2026-03-30 12:07:28,242 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I0\"\\r\\n'\n", - "2026-03-30 12:07:28,255 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I1\"\\r\\n'\n", - "2026-03-30 12:07:28,256 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I1\"\\r\\n'\n", - "2026-03-30 12:07:28,270 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I2\"\\r\\n'\n", - "2026-03-30 12:07:28,271 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I2\"\\r\\n'\n", - "2026-03-30 12:07:28,287 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I3\"\\r\\n'\n", - "2026-03-30 12:07:28,288 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I3\"\\r\\n'\n", - "2026-03-30 12:07:28,291 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I4\"\\r\\n'\n", - "2026-03-30 12:07:28,292 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I4\"\\r\\n'\n", - "2026-03-30 12:07:28,305 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I5\"\\r\\n'\n", - "2026-03-30 12:07:28,307 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I5\"\\r\\n'\n", - "2026-03-30 12:07:28,321 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"S\"\\r\\n'\n", - "2026-03-30 12:07:28,322 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"S\"\\r\\n'\n", - "2026-03-30 12:07:28,336 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"SI\"\\r\\n'\n", - "2026-03-30 12:07:28,337 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"SI\"\\r\\n'\n", - "2026-03-30 12:07:28,350 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"SIR\"\\r\\n'\n", - "2026-03-30 12:07:28,351 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"SIR\"\\r\\n'\n", - "2026-03-30 12:07:28,367 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"Z\"\\r\\n'\n", - "2026-03-30 12:07:28,369 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"Z\"\\r\\n'\n", - "2026-03-30 12:07:28,371 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"ZI\"\\r\\n'\n", - "2026-03-30 12:07:28,372 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"ZI\"\\r\\n'\n", - "2026-03-30 12:07:28,383 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"@\"\\r\\n'\n", - "2026-03-30 12:07:28,386 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"@\"\\r\\n'\n", - "2026-03-30 12:07:28,399 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"SR\"\\r\\n'\n", - "2026-03-30 12:07:28,403 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"SR\"\\r\\n'\n", - "2026-03-30 12:07:28,416 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"T\"\\r\\n'\n", - "2026-03-30 12:07:28,418 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"T\"\\r\\n'\n", - "2026-03-30 12:07:28,431 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"TA\"\\r\\n'\n", - "2026-03-30 12:07:28,433 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"TA\"\\r\\n'\n", - "2026-03-30 12:07:28,448 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"TAC\"\\r\\n'\n", - "2026-03-30 12:07:28,453 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"TAC\"\\r\\n'\n", - "2026-03-30 12:07:28,460 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"TI\"\\r\\n'\n", - "2026-03-30 12:07:28,462 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"TI\"\\r\\n'\n", - "2026-03-30 12:07:28,464 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C0\"\\r\\n'\n", - "2026-03-30 12:07:28,465 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"C0\"\\r\\n'\n", - "2026-03-30 12:07:28,480 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C1\"\\r\\n'\n", - "2026-03-30 12:07:28,484 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"C1\"\\r\\n'\n", - "2026-03-30 12:07:28,496 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C2\"\\r\\n'\n", - "2026-03-30 12:07:28,499 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"C2\"\\r\\n'\n", - "2026-03-30 12:07:28,511 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C3\"\\r\\n'\n", - "2026-03-30 12:07:28,514 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"C3\"\\r\\n'\n", - "2026-03-30 12:07:28,527 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"COM\"\\r\\n'\n", - "2026-03-30 12:07:28,532 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"COM\"\\r\\n'\n", - "2026-03-30 12:07:28,545 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"DAT\"\\r\\n'\n", - "2026-03-30 12:07:28,549 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"DAT\"\\r\\n'\n", - "2026-03-30 12:07:28,559 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I10\"\\r\\n'\n", - "2026-03-30 12:07:28,561 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I10\"\\r\\n'\n", - "2026-03-30 12:07:28,576 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I11\"\\r\\n'\n", - "2026-03-30 12:07:28,581 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I11\"\\r\\n'\n", - "2026-03-30 12:07:28,583 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I14\"\\r\\n'\n", - "2026-03-30 12:07:28,584 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I14\"\\r\\n'\n", - "2026-03-30 12:07:28,591 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I15\"\\r\\n'\n", - "2026-03-30 12:07:28,594 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I15\"\\r\\n'\n", - "2026-03-30 12:07:28,609 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I16\"\\r\\n'\n", - "2026-03-30 12:07:28,610 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I16\"\\r\\n'\n", - "2026-03-30 12:07:28,622 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I21\"\\r\\n'\n", - "2026-03-30 12:07:28,623 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I21\"\\r\\n'\n", - "2026-03-30 12:07:28,638 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I22\"\\r\\n'\n", - "2026-03-30 12:07:28,639 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I22\"\\r\\n'\n", - "2026-03-30 12:07:28,655 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I23\"\\r\\n'\n", - "2026-03-30 12:07:28,656 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I23\"\\r\\n'\n", - "2026-03-30 12:07:28,672 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I24\"\\r\\n'\n", - "2026-03-30 12:07:28,673 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I24\"\\r\\n'\n", - "2026-03-30 12:07:28,687 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I25\"\\r\\n'\n", - "2026-03-30 12:07:28,688 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I25\"\\r\\n'\n", - "2026-03-30 12:07:28,702 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I26\"\\r\\n'\n", - "2026-03-30 12:07:28,705 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I26\"\\r\\n'\n", - "2026-03-30 12:07:28,719 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M01\"\\r\\n'\n", - "2026-03-30 12:07:28,722 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M01\"\\r\\n'\n", - "2026-03-30 12:07:28,735 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M02\"\\r\\n'\n", - "2026-03-30 12:07:28,737 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M02\"\\r\\n'\n", - "2026-03-30 12:07:28,740 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M03\"\\r\\n'\n", - "2026-03-30 12:07:28,748 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M03\"\\r\\n'\n", - "2026-03-30 12:07:28,753 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M17\"\\r\\n'\n", - "2026-03-30 12:07:28,754 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M17\"\\r\\n'\n", - "2026-03-30 12:07:28,767 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M18\"\\r\\n'\n", - "2026-03-30 12:07:28,768 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M18\"\\r\\n'\n", - "2026-03-30 12:07:28,782 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M19\"\\r\\n'\n", - "2026-03-30 12:07:28,785 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M19\"\\r\\n'\n", - "2026-03-30 12:07:28,799 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M20\"\\r\\n'\n", - "2026-03-30 12:07:28,801 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M20\"\\r\\n'\n", - "2026-03-30 12:07:28,814 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M21\"\\r\\n'\n", - "2026-03-30 12:07:28,818 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M21\"\\r\\n'\n", - "2026-03-30 12:07:28,830 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M27\"\\r\\n'\n", - "2026-03-30 12:07:28,833 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M27\"\\r\\n'\n", - "2026-03-30 12:07:28,847 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M28\"\\r\\n'\n", - "2026-03-30 12:07:28,848 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M28\"\\r\\n'\n", - "2026-03-30 12:07:28,862 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M29\"\\r\\n'\n", - "2026-03-30 12:07:28,864 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M29\"\\r\\n'\n", - "2026-03-30 12:07:28,879 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M31\"\\r\\n'\n", - "2026-03-30 12:07:28,880 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M31\"\\r\\n'\n", - "2026-03-30 12:07:28,894 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M32\"\\r\\n'\n", - "2026-03-30 12:07:28,895 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M32\"\\r\\n'\n", - "2026-03-30 12:07:28,911 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M33\"\\r\\n'\n", - "2026-03-30 12:07:28,912 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M33\"\\r\\n'\n", - "2026-03-30 12:07:28,925 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M35\"\\r\\n'\n", - "2026-03-30 12:07:28,926 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M35\"\\r\\n'\n", - "2026-03-30 12:07:28,929 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"SIS\"\\r\\n'\n", - "2026-03-30 12:07:28,931 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"SIS\"\\r\\n'\n", - "2026-03-30 12:07:28,942 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"SNR\"\\r\\n'\n", - "2026-03-30 12:07:28,948 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"SNR\"\\r\\n'\n", - "2026-03-30 12:07:28,961 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TIM\"\\r\\n'\n", - "2026-03-30 12:07:28,962 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TIM\"\\r\\n'\n", - "2026-03-30 12:07:28,974 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST0\"\\r\\n'\n", - "2026-03-30 12:07:28,978 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TST0\"\\r\\n'\n", - "2026-03-30 12:07:28,991 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST1\"\\r\\n'\n", - "2026-03-30 12:07:28,992 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TST1\"\\r\\n'\n", - "2026-03-30 12:07:29,008 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST2\"\\r\\n'\n", - "2026-03-30 12:07:29,009 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TST2\"\\r\\n'\n", - "2026-03-30 12:07:29,022 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST3\"\\r\\n'\n", - "2026-03-30 12:07:29,023 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TST3\"\\r\\n'\n", - "2026-03-30 12:07:29,039 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"UPD\"\\r\\n'\n", - "2026-03-30 12:07:29,040 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"UPD\"\\r\\n'\n", - "2026-03-30 12:07:29,062 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"FCUT\"\\r\\n'\n", - "2026-03-30 12:07:29,063 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 3 \"FCUT\"\\r\\n'\n", - "2026-03-30 12:07:29,071 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"FSET\"\\r\\n'\n", - "2026-03-30 12:07:29,073 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 3 \"FSET\"\\r\\n'\n", - "2026-03-30 12:07:29,087 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"LST\"\\r\\n'\n", - "2026-03-30 12:07:29,088 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 3 \"LST\"\\r\\n'\n", - "2026-03-30 12:07:29,102 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"RDB\"\\r\\n'\n", - "2026-03-30 12:07:29,106 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 3 \"RDB\"\\r\\n'\n", - "2026-03-30 12:07:29,119 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 A 3 \"USTB\"\\r\\n'\n", - "2026-03-30 12:07:29,122 - pylabrobot - IO - [MT Scale] Received response: b'I0 A 3 \"USTB\"\\r\\n'\n" + "2026-03-30 12:41:00,902 - pylabrobot - IO - [MT Scale] Sent command: I0\n", + "2026-03-30 12:41:00,912 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I0\\r\\n'\n", + "2026-03-30 12:41:00,948 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I0\"\\r\\n'\n", + "2026-03-30 12:41:00,951 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I0\"\\r\\n'\n", + "2026-03-30 12:41:00,954 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I1\"\\r\\n'\n", + "2026-03-30 12:41:00,959 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I1\"\\r\\n'\n", + "2026-03-30 12:41:00,965 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I2\"\\r\\n'\n", + "2026-03-30 12:41:00,970 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I2\"\\r\\n'\n", + "2026-03-30 12:41:00,981 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I3\"\\r\\n'\n", + "2026-03-30 12:41:00,984 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I3\"\\r\\n'\n", + "2026-03-30 12:41:00,995 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I4\"\\r\\n'\n", + "2026-03-30 12:41:00,996 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I4\"\\r\\n'\n", + "2026-03-30 12:41:01,010 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I5\"\\r\\n'\n", + "2026-03-30 12:41:01,011 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I5\"\\r\\n'\n", + "2026-03-30 12:41:01,026 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"S\"\\r\\n'\n", + "2026-03-30 12:41:01,027 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"S\"\\r\\n'\n", + "2026-03-30 12:41:01,043 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"SI\"\\r\\n'\n", + "2026-03-30 12:41:01,044 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"SI\"\\r\\n'\n", + "2026-03-30 12:41:01,045 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"SIR\"\\r\\n'\n", + "2026-03-30 12:41:01,046 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"SIR\"\\r\\n'\n", + "2026-03-30 12:41:01,058 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"Z\"\\r\\n'\n", + "2026-03-30 12:41:01,059 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"Z\"\\r\\n'\n", + "2026-03-30 12:41:01,075 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"ZI\"\\r\\n'\n", + "2026-03-30 12:41:01,075 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"ZI\"\\r\\n'\n", + "2026-03-30 12:41:01,091 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"@\"\\r\\n'\n", + "2026-03-30 12:41:01,092 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"@\"\\r\\n'\n", + "2026-03-30 12:41:01,106 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"SR\"\\r\\n'\n", + "2026-03-30 12:41:01,107 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"SR\"\\r\\n'\n", + "2026-03-30 12:41:01,109 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"T\"\\r\\n'\n", + "2026-03-30 12:41:01,110 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"T\"\\r\\n'\n", + "2026-03-30 12:41:01,123 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"TA\"\\r\\n'\n", + "2026-03-30 12:41:01,124 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"TA\"\\r\\n'\n", + "2026-03-30 12:41:01,139 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"TAC\"\\r\\n'\n", + "2026-03-30 12:41:01,140 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"TAC\"\\r\\n'\n", + "2026-03-30 12:41:01,155 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"TI\"\\r\\n'\n", + "2026-03-30 12:41:01,155 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"TI\"\\r\\n'\n", + "2026-03-30 12:41:01,171 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C0\"\\r\\n'\n", + "2026-03-30 12:41:01,172 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"C0\"\\r\\n'\n", + "2026-03-30 12:41:01,187 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C1\"\\r\\n'\n", + "2026-03-30 12:41:01,188 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"C1\"\\r\\n'\n", + "2026-03-30 12:41:01,202 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C2\"\\r\\n'\n", + "2026-03-30 12:41:01,203 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"C2\"\\r\\n'\n", + "2026-03-30 12:41:01,205 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C3\"\\r\\n'\n", + "2026-03-30 12:41:01,206 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"C3\"\\r\\n'\n", + "2026-03-30 12:41:01,219 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"COM\"\\r\\n'\n", + "2026-03-30 12:41:01,220 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"COM\"\\r\\n'\n", + "2026-03-30 12:41:01,234 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"DAT\"\\r\\n'\n", + "2026-03-30 12:41:01,235 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"DAT\"\\r\\n'\n", + "2026-03-30 12:41:01,250 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I10\"\\r\\n'\n", + "2026-03-30 12:41:01,251 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I10\"\\r\\n'\n", + "2026-03-30 12:41:01,267 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I11\"\\r\\n'\n", + "2026-03-30 12:41:01,268 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I11\"\\r\\n'\n", + "2026-03-30 12:41:01,282 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I14\"\\r\\n'\n", + "2026-03-30 12:41:01,283 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I14\"\\r\\n'\n", + "2026-03-30 12:41:01,298 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I15\"\\r\\n'\n", + "2026-03-30 12:41:01,299 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I15\"\\r\\n'\n", + "2026-03-30 12:41:01,315 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I16\"\\r\\n'\n", + "2026-03-30 12:41:01,315 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I16\"\\r\\n'\n", + "2026-03-30 12:41:01,330 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I21\"\\r\\n'\n", + "2026-03-30 12:41:01,331 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I21\"\\r\\n'\n", + "2026-03-30 12:41:01,346 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I22\"\\r\\n'\n", + "2026-03-30 12:41:01,347 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I22\"\\r\\n'\n", + "2026-03-30 12:41:01,362 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I23\"\\r\\n'\n", + "2026-03-30 12:41:01,363 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I23\"\\r\\n'\n", + "2026-03-30 12:41:01,378 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I24\"\\r\\n'\n", + "2026-03-30 12:41:01,379 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I24\"\\r\\n'\n", + "2026-03-30 12:41:01,381 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I25\"\\r\\n'\n", + "2026-03-30 12:41:01,382 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I25\"\\r\\n'\n", + "2026-03-30 12:41:01,395 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I26\"\\r\\n'\n", + "2026-03-30 12:41:01,395 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I26\"\\r\\n'\n", + "2026-03-30 12:41:01,410 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M01\"\\r\\n'\n", + "2026-03-30 12:41:01,411 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M01\"\\r\\n'\n", + "2026-03-30 12:41:01,426 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M02\"\\r\\n'\n", + "2026-03-30 12:41:01,427 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M02\"\\r\\n'\n", + "2026-03-30 12:41:01,443 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M03\"\\r\\n'\n", + "2026-03-30 12:41:01,443 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M03\"\\r\\n'\n", + "2026-03-30 12:41:01,458 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M17\"\\r\\n'\n", + "2026-03-30 12:41:01,459 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M17\"\\r\\n'\n", + "2026-03-30 12:41:01,474 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M18\"\\r\\n'\n", + "2026-03-30 12:41:01,475 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M18\"\\r\\n'\n", + "2026-03-30 12:41:01,491 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M19\"\\r\\n'\n", + "2026-03-30 12:41:01,491 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M19\"\\r\\n'\n", + "2026-03-30 12:41:01,506 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M20\"\\r\\n'\n", + "2026-03-30 12:41:01,507 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M20\"\\r\\n'\n", + "2026-03-30 12:41:01,522 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M21\"\\r\\n'\n", + "2026-03-30 12:41:01,523 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M21\"\\r\\n'\n", + "2026-03-30 12:41:01,539 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M27\"\\r\\n'\n", + "2026-03-30 12:41:01,539 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M27\"\\r\\n'\n", + "2026-03-30 12:41:01,541 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M28\"\\r\\n'\n", + "2026-03-30 12:41:01,542 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M28\"\\r\\n'\n", + "2026-03-30 12:41:01,554 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M29\"\\r\\n'\n", + "2026-03-30 12:41:01,555 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M29\"\\r\\n'\n", + "2026-03-30 12:41:01,570 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M31\"\\r\\n'\n", + "2026-03-30 12:41:01,571 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M31\"\\r\\n'\n", + "2026-03-30 12:41:01,586 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M32\"\\r\\n'\n", + "2026-03-30 12:41:01,587 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M32\"\\r\\n'\n", + "2026-03-30 12:41:01,602 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M33\"\\r\\n'\n", + "2026-03-30 12:41:01,603 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M33\"\\r\\n'\n", + "2026-03-30 12:41:01,618 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M35\"\\r\\n'\n", + "2026-03-30 12:41:01,619 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M35\"\\r\\n'\n", + "2026-03-30 12:41:01,634 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"SIS\"\\r\\n'\n", + "2026-03-30 12:41:01,635 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"SIS\"\\r\\n'\n", + "2026-03-30 12:41:01,650 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"SNR\"\\r\\n'\n", + "2026-03-30 12:41:01,651 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"SNR\"\\r\\n'\n", + "2026-03-30 12:41:01,666 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TIM\"\\r\\n'\n", + "2026-03-30 12:41:01,667 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TIM\"\\r\\n'\n", + "2026-03-30 12:41:01,682 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST0\"\\r\\n'\n", + "2026-03-30 12:41:01,683 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TST0\"\\r\\n'\n", + "2026-03-30 12:41:01,698 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST1\"\\r\\n'\n", + "2026-03-30 12:41:01,699 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TST1\"\\r\\n'\n", + "2026-03-30 12:41:01,713 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST2\"\\r\\n'\n", + "2026-03-30 12:41:01,714 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TST2\"\\r\\n'\n", + "2026-03-30 12:41:01,730 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST3\"\\r\\n'\n", + "2026-03-30 12:41:01,731 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TST3\"\\r\\n'\n", + "2026-03-30 12:41:01,746 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"UPD\"\\r\\n'\n", + "2026-03-30 12:41:01,747 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"UPD\"\\r\\n'\n", + "2026-03-30 12:41:01,762 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"FCUT\"\\r\\n'\n", + "2026-03-30 12:41:01,762 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 3 \"FCUT\"\\r\\n'\n", + "2026-03-30 12:41:01,778 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"FSET\"\\r\\n'\n", + "2026-03-30 12:41:01,779 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 3 \"FSET\"\\r\\n'\n", + "2026-03-30 12:41:01,780 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"LST\"\\r\\n'\n", + "2026-03-30 12:41:01,781 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 3 \"LST\"\\r\\n'\n", + "2026-03-30 12:41:01,794 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"RDB\"\\r\\n'\n", + "2026-03-30 12:41:01,795 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 3 \"RDB\"\\r\\n'\n", + "2026-03-30 12:41:01,810 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 A 3 \"USTB\"\\r\\n'\n", + "2026-03-30 12:41:01,811 - pylabrobot - IO - [MT Scale] Received response: b'I0 A 3 \"USTB\"\\r\\n'\n" ] }, { @@ -573,15 +577,142 @@ }, { "cell_type": "markdown", - "source": "### Device identity and diagnostics (Batch 1)\n\nThese commands complete the device identity picture beyond I2/I4.", - "metadata": {} + "metadata": {}, + "source": [ + "### Device identity and diagnostics (Batch 1)\n", + "\n", + "These commands complete the device identity picture beyond I2/I4." + ] }, { "cell_type": "code", - "source": "# I3 - Software version (Level 0, always available)\nsw_version = await backend.request_software_version()\nprint(f\"Software version: {sw_version}\")\n\n# I5 - Software material number (Level 0, always available)\nsw_material = await backend.request_software_material_number()\nprint(f\"Software material number: {sw_material}\")\n\n# I10 - Device ID (user-assignable name)\nif \"I10\" in backend._supported_commands:\n device_id = await backend.request_device_id()\n print(f\"Device ID: '{device_id}'\")\nelse:\n print(\"SKIP: I10 not supported\")\n\n# I11 - Model designation\nif \"I11\" in backend._supported_commands:\n model = await backend.request_model_designation()\n print(f\"Model designation: {model}\")\nelse:\n print(\"SKIP: I11 not supported\")\n\n# I15 - Uptime\nif \"I15\" in backend._supported_commands:\n uptime = await backend.request_uptime()\n print(f\"Uptime: {uptime['days']}d {uptime['hours']}h {uptime['minutes']}m {uptime['seconds']}s\")\nelse:\n print(\"SKIP: I15 not supported\")\n\n# DAT - Date\nif \"DAT\" in backend._supported_commands:\n date = await backend.request_date()\n print(f\"Device date: {date}\")\nelse:\n print(\"SKIP: DAT not supported\")\n\n# TIM - Time\nif \"TIM\" in backend._supported_commands:\n time_str = await backend.request_time()\n print(f\"Device time: {time_str}\")\nelse:\n print(\"SKIP: TIM not supported\")\n\n# I14 - Comprehensive device info (multi-response)\nif \"I14\" in backend._supported_commands:\n info_responses = await backend.request_device_info()\n print(f\"\\nDevice info ({len(info_responses)} response lines):\")\n for resp in info_responses:\n print(f\" {resp.command} {resp.status} {' '.join(resp.data)}\")\nelse:\n print(\"SKIP: I14 not supported\")\n\nprint(\"\\nPASS: Batch 1 device identity commands completed\")", + "execution_count": 6, "metadata": {}, - "execution_count": null, - "outputs": [] + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2026-03-30 12:41:01,821 - pylabrobot - IO - [MT Scale] Sent command: I3\n", + "2026-03-30 12:41:01,824 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I3\\r\\n'\n", + "2026-03-30 12:41:01,874 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I3 A \"1.10 18.6.4.1361.772\"\\r\\n'\n", + "2026-03-30 12:41:01,875 - pylabrobot - IO - [MT Scale] Received response: b'I3 A \"1.10 18.6.4.1361.772\"\\r\\n'\n", + "2026-03-30 12:41:01,876 - pylabrobot - IO - [MT Scale] Sent command: I5\n", + "2026-03-30 12:41:01,880 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I5\\r\\n'\n", + "2026-03-30 12:41:01,906 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I5 A \"11671158C\"\\r\\n'\n", + "2026-03-30 12:41:01,974 - pylabrobot - IO - [MT Scale] Received response: b'I5 A \"11671158C\"\\r\\n'\n", + "2026-03-30 12:41:01,975 - pylabrobot - IO - [MT Scale] Sent command: I10\n", + "2026-03-30 12:41:01,976 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I10\\r\\n'\n", + "2026-03-30 12:41:02,002 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I10 A \"\"\\r\\n'\n", + "2026-03-30 12:41:02,002 - pylabrobot - IO - [MT Scale] Received response: b'I10 A \"\"\\r\\n'\n", + "2026-03-30 12:41:02,003 - pylabrobot - IO - [MT Scale] Sent command: I11\n", + "2026-03-30 12:41:02,004 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I11\\r\\n'\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Software version: 1.10 18.6.4.1361.772\n", + "Software material number: 11671158C\n", + "Device ID: ''\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2026-03-30 12:41:02,050 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I11 A \"WXS205SDU\"\\r\\n'\n", + "2026-03-30 12:41:02,051 - pylabrobot - IO - [MT Scale] Received response: b'I11 A \"WXS205SDU\"\\r\\n'\n", + "2026-03-30 12:41:02,052 - pylabrobot - IO - [MT Scale] Sent command: I15\n", + "2026-03-30 12:41:02,054 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I15\\r\\n'\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Model designation: WXS205SDU\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2026-03-30 12:41:02,081 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I15 A 193\\r\\n'\n", + "2026-03-30 12:41:02,082 - pylabrobot - IO - [MT Scale] Received response: b'I15 A 193\\r\\n'\n" + ] + }, + { + "ename": "MettlerToledoError", + "evalue": "Unexpected response: Expected at least 6 fields for 'I15', got 3: MettlerToledoResponse(command='I15', status='A', data=['193'])", + "output_type": "error", + "traceback": [ + "\u001b[31m---------------------------------------------------------------------------\u001b[39m", + "\u001b[31mMettlerToledoError\u001b[39m Traceback (most recent call last)", + "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[6]\u001b[39m\u001b[32m, line 25\u001b[39m\n\u001b[32m 23\u001b[39m \u001b[38;5;66;03m# I15 - Uptime\u001b[39;00m\n\u001b[32m 24\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m \u001b[33m\"\u001b[39m\u001b[33mI15\u001b[39m\u001b[33m\"\u001b[39m \u001b[38;5;129;01min\u001b[39;00m backend._supported_commands:\n\u001b[32m---> \u001b[39m\u001b[32m25\u001b[39m uptime = \u001b[38;5;28;01mawait\u001b[39;00m backend.request_uptime()\n\u001b[32m 26\u001b[39m \u001b[38;5;28mprint\u001b[39m(\u001b[33mf\u001b[39m\u001b[33m\"\u001b[39m\u001b[33mUptime: \u001b[39m\u001b[38;5;132;01m{\u001b[39;00muptime[\u001b[33m'\u001b[39m\u001b[33mdays\u001b[39m\u001b[33m'\u001b[39m]\u001b[38;5;132;01m}\u001b[39;00m\u001b[33md \u001b[39m\u001b[38;5;132;01m{\u001b[39;00muptime[\u001b[33m'\u001b[39m\u001b[33mhours\u001b[39m\u001b[33m'\u001b[39m]\u001b[38;5;132;01m}\u001b[39;00m\u001b[33mh \u001b[39m\u001b[38;5;132;01m{\u001b[39;00muptime[\u001b[33m'\u001b[39m\u001b[33mminutes\u001b[39m\u001b[33m'\u001b[39m]\u001b[38;5;132;01m}\u001b[39;00m\u001b[33mm \u001b[39m\u001b[38;5;132;01m{\u001b[39;00muptime[\u001b[33m'\u001b[39m\u001b[33mseconds\u001b[39m\u001b[33m'\u001b[39m]\u001b[38;5;132;01m}\u001b[39;00m\u001b[33ms\u001b[39m\u001b[33m\"\u001b[39m)\n\u001b[32m 27\u001b[39m \u001b[38;5;28;01melse\u001b[39;00m:\n", + "\u001b[36mFile \u001b[39m\u001b[32m~/Desktop/GitHub/pylabrobot/pylabrobot/scales/mettler_toledo/backend.py:59\u001b[39m, in \u001b[36mrequires_mt_sics_command..decorator..wrapper\u001b[39m\u001b[34m(self, *args, **kwargs)\u001b[39m\n\u001b[32m 53\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m mt_sics_command \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;129;01min\u001b[39;00m \u001b[38;5;28mself\u001b[39m._supported_commands:\n\u001b[32m 54\u001b[39m \u001b[38;5;28;01mraise\u001b[39;00m MettlerToledoError(\n\u001b[32m 55\u001b[39m title=\u001b[33m\"\u001b[39m\u001b[33mCommand not supported\u001b[39m\u001b[33m\"\u001b[39m,\n\u001b[32m 56\u001b[39m message=\u001b[33mf\u001b[39m\u001b[33m\"\u001b[39m\u001b[33m'\u001b[39m\u001b[38;5;132;01m{\u001b[39;00mfunc.\u001b[34m__name__\u001b[39m\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m'\u001b[39m\u001b[33m requires MT-SICS command \u001b[39m\u001b[33m'\u001b[39m\u001b[38;5;132;01m{\u001b[39;00mmt_sics_command\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m'\u001b[39m\u001b[33m, \u001b[39m\u001b[33m\"\u001b[39m\n\u001b[32m 57\u001b[39m \u001b[33mf\u001b[39m\u001b[33m\"\u001b[39m\u001b[33mwhich is not implemented on this device.\u001b[39m\u001b[33m\"\u001b[39m,\n\u001b[32m 58\u001b[39m )\n\u001b[32m---> \u001b[39m\u001b[32m59\u001b[39m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;01mawait\u001b[39;00m func(\u001b[38;5;28mself\u001b[39m, *args, **kwargs)\n", + "\u001b[36mFile \u001b[39m\u001b[32m~/Desktop/GitHub/pylabrobot/pylabrobot/scales/mettler_toledo/backend.py:473\u001b[39m, in \u001b[36mMettlerToledoWXS205SDUBackend.request_uptime\u001b[39m\u001b[34m(self)\u001b[39m\n\u001b[32m 466\u001b[39m \u001b[38;5;250m\u001b[39m\u001b[33;03m\"\"\"Query the device uptime. (I15 command)\u001b[39;00m\n\u001b[32m 467\u001b[39m \n\u001b[32m 468\u001b[39m \u001b[33;03mReturns a dict with keys \"days\", \"hours\", \"minutes\", \"seconds\".\u001b[39;00m\n\u001b[32m 469\u001b[39m \u001b[33;03mCounts time since last power-on, including short interruptions.\u001b[39;00m\n\u001b[32m 470\u001b[39m \u001b[33;03mNot reset by @ cancel or restart.\u001b[39;00m\n\u001b[32m 471\u001b[39m \u001b[33;03m\"\"\"\u001b[39;00m\n\u001b[32m 472\u001b[39m responses = \u001b[38;5;28;01mawait\u001b[39;00m \u001b[38;5;28mself\u001b[39m.send_command(\u001b[33m\"\u001b[39m\u001b[33mI15\u001b[39m\u001b[33m\"\u001b[39m)\n\u001b[32m--> \u001b[39m\u001b[32m473\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[43m.\u001b[49m\u001b[43m_validate_response\u001b[49m\u001b[43m(\u001b[49m\u001b[43mresponses\u001b[49m\u001b[43m[\u001b[49m\u001b[32;43m0\u001b[39;49m\u001b[43m]\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[32;43m6\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[33;43m\"\u001b[39;49m\u001b[33;43mI15\u001b[39;49m\u001b[33;43m\"\u001b[39;49m\u001b[43m)\u001b[49m\n\u001b[32m 474\u001b[39m \u001b[38;5;28;01mreturn\u001b[39;00m {\n\u001b[32m 475\u001b[39m \u001b[33m\"\u001b[39m\u001b[33mdays\u001b[39m\u001b[33m\"\u001b[39m: \u001b[38;5;28mint\u001b[39m(responses[\u001b[32m0\u001b[39m].data[\u001b[32m0\u001b[39m]),\n\u001b[32m 476\u001b[39m \u001b[33m\"\u001b[39m\u001b[33mhours\u001b[39m\u001b[33m\"\u001b[39m: \u001b[38;5;28mint\u001b[39m(responses[\u001b[32m0\u001b[39m].data[\u001b[32m1\u001b[39m]),\n\u001b[32m 477\u001b[39m \u001b[33m\"\u001b[39m\u001b[33mminutes\u001b[39m\u001b[33m\"\u001b[39m: \u001b[38;5;28mint\u001b[39m(responses[\u001b[32m0\u001b[39m].data[\u001b[32m2\u001b[39m]),\n\u001b[32m 478\u001b[39m \u001b[33m\"\u001b[39m\u001b[33mseconds\u001b[39m\u001b[33m\"\u001b[39m: \u001b[38;5;28mint\u001b[39m(responses[\u001b[32m0\u001b[39m].data[\u001b[32m3\u001b[39m]),\n\u001b[32m 479\u001b[39m }\n", + "\u001b[36mFile \u001b[39m\u001b[32m~/Desktop/GitHub/pylabrobot/pylabrobot/scales/mettler_toledo/backend.py:212\u001b[39m, in \u001b[36mMettlerToledoWXS205SDUBackend._validate_response\u001b[39m\u001b[34m(response, min_fields, command)\u001b[39m\n\u001b[32m 210\u001b[39m total = \u001b[32m1\u001b[39m + (\u001b[32m1\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m response.status \u001b[38;5;28;01melse\u001b[39;00m \u001b[32m0\u001b[39m) + \u001b[38;5;28mlen\u001b[39m(response.data)\n\u001b[32m 211\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m total < min_fields:\n\u001b[32m--> \u001b[39m\u001b[32m212\u001b[39m \u001b[38;5;28;01mraise\u001b[39;00m MettlerToledoError(\n\u001b[32m 213\u001b[39m title=\u001b[33m\"\u001b[39m\u001b[33mUnexpected response\u001b[39m\u001b[33m\"\u001b[39m,\n\u001b[32m 214\u001b[39m message=\u001b[33mf\u001b[39m\u001b[33m\"\u001b[39m\u001b[33mExpected at least \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mmin_fields\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m fields for \u001b[39m\u001b[33m'\u001b[39m\u001b[38;5;132;01m{\u001b[39;00mcommand\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m'\u001b[39m\u001b[33m, got \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mtotal\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m: \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mresponse\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m\"\u001b[39m,\n\u001b[32m 215\u001b[39m )\n", + "\u001b[31mMettlerToledoError\u001b[39m: Unexpected response: Expected at least 6 fields for 'I15', got 3: MettlerToledoResponse(command='I15', status='A', data=['193'])" + ] + } + ], + "source": [ + "# I3 - Software version (Level 0, always available)\n", + "sw_version = await backend.request_software_version()\n", + "print(f\"Software version: {sw_version}\")\n", + "\n", + "# I5 - Software material number (Level 0, always available)\n", + "sw_material = await backend.request_software_material_number()\n", + "print(f\"Software material number: {sw_material}\")\n", + "\n", + "# I10 - Device ID (user-assignable name)\n", + "if \"I10\" in backend._supported_commands:\n", + " device_id = await backend.request_device_id()\n", + " print(f\"Device ID: '{device_id}'\")\n", + "else:\n", + " print(\"SKIP: I10 not supported\")\n", + "\n", + "# I11 - Model designation\n", + "if \"I11\" in backend._supported_commands:\n", + " model = await backend.request_model_designation()\n", + " print(f\"Model designation: {model}\")\n", + "else:\n", + " print(\"SKIP: I11 not supported\")\n", + "\n", + "# I15 - Uptime\n", + "if \"I15\" in backend._supported_commands:\n", + " uptime = await backend.request_uptime()\n", + " print(f\"Uptime: {uptime['days']}d {uptime['hours']}h {uptime['minutes']}m {uptime['seconds']}s\")\n", + "else:\n", + " print(\"SKIP: I15 not supported\")\n", + "\n", + "# DAT - Date\n", + "if \"DAT\" in backend._supported_commands:\n", + " date = await backend.request_date()\n", + " print(f\"Device date: {date}\")\n", + "else:\n", + " print(\"SKIP: DAT not supported\")\n", + "\n", + "# TIM - Time\n", + "if \"TIM\" in backend._supported_commands:\n", + " time_str = await backend.request_time()\n", + " print(f\"Device time: {time_str}\")\n", + "else:\n", + " print(\"SKIP: TIM not supported\")\n", + "\n", + "# I14 - Comprehensive device info (multi-response)\n", + "if \"I14\" in backend._supported_commands:\n", + " info_responses = await backend.request_device_info()\n", + " print(f\"\\nDevice info ({len(info_responses)} response lines):\")\n", + " for resp in info_responses:\n", + " print(f\" {resp.command} {resp.status} {' '.join(resp.data)}\")\n", + "else:\n", + " print(\"SKIP: I14 not supported\")\n", + "\n", + "print(\"\\nPASS: Batch 1 device identity commands completed\")" + ] }, { "cell_type": "markdown", @@ -600,18 +731,18 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 7, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 12:07:29,155 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] reset_input_buffer\n", - "2026-03-30 12:07:29,157 - pylabrobot - IO - [MT Scale] Sent command: @\n", - "2026-03-30 12:07:29,160 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'@\\r\\n'\n", - "2026-03-30 12:07:29,214 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I4 A \"B207696838\"\\r\\n'\n", - "2026-03-30 12:07:29,215 - pylabrobot - IO - [MT Scale] Received response: b'I4 A \"B207696838\"\\r\\n'\n" + "2026-03-30 12:41:20,576 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] reset_input_buffer\n", + "2026-03-30 12:41:20,577 - pylabrobot - IO - [MT Scale] Sent command: @\n", + "2026-03-30 12:41:20,579 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'@\\r\\n'\n", + "2026-03-30 12:41:20,641 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I4 A \"B207696838\"\\r\\n'\n", + "2026-03-30 12:41:20,642 - pylabrobot - IO - [MT Scale] Received response: b'I4 A \"B207696838\"\\r\\n'\n" ] }, { @@ -639,17 +770,17 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 8, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 12:07:29,220 - pylabrobot - IO - [MT Scale] Sent command: I4\n", - "2026-03-30 12:07:29,222 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I4\\r\\n'\n", - "2026-03-30 12:07:29,263 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I4 A \"B207696838\"\\r\\n'\n", - "2026-03-30 12:07:29,265 - pylabrobot - IO - [MT Scale] Received response: b'I4 A \"B207696838\"\\r\\n'\n" + "2026-03-30 12:41:22,391 - pylabrobot - IO - [MT Scale] Sent command: I4\n", + "2026-03-30 12:41:22,399 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I4\\r\\n'\n", + "2026-03-30 12:41:22,447 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I4 A \"B207696838\"\\r\\n'\n", + "2026-03-30 12:41:22,448 - pylabrobot - IO - [MT Scale] Received response: b'I4 A \"B207696838\"\\r\\n'\n" ] }, { @@ -677,21 +808,21 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 9, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 12:07:29,286 - pylabrobot - IO - [MT Scale] Sent command: I2\n", - "2026-03-30 12:07:29,292 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I2\\r\\n'\n", - "2026-03-30 12:07:29,360 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", - "2026-03-30 12:07:29,361 - pylabrobot - IO - [MT Scale] Received response: b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", - "2026-03-30 12:07:29,363 - pylabrobot - IO - [MT Scale] Sent command: I2\n", - "2026-03-30 12:07:29,364 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I2\\r\\n'\n", - "2026-03-30 12:07:29,422 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", - "2026-03-30 12:07:29,423 - pylabrobot - IO - [MT Scale] Received response: b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n" + "2026-03-30 12:41:24,197 - pylabrobot - IO - [MT Scale] Sent command: I2\n", + "2026-03-30 12:41:24,198 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I2\\r\\n'\n", + "2026-03-30 12:41:24,255 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", + "2026-03-30 12:41:24,257 - pylabrobot - IO - [MT Scale] Received response: b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", + "2026-03-30 12:41:24,258 - pylabrobot - IO - [MT Scale] Sent command: I2\n", + "2026-03-30 12:41:24,260 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I2\\r\\n'\n", + "2026-03-30 12:41:24,318 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", + "2026-03-30 12:41:24,322 - pylabrobot - IO - [MT Scale] Received response: b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n" ] }, { @@ -723,17 +854,17 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": 10, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 12:07:29,431 - pylabrobot - IO - [MT Scale] Sent command: I1\n", - "2026-03-30 12:07:29,434 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I1\\r\\n'\n", - "2026-03-30 12:07:29,486 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I1 A \"01\" \"2.30\" \"2.22\" \"\" \"\"\\r\\n'\n", - "2026-03-30 12:07:29,487 - pylabrobot - IO - [MT Scale] Received response: b'I1 A \"01\" \"2.30\" \"2.22\" \"\" \"\"\\r\\n'\n" + "2026-03-30 12:41:30,722 - pylabrobot - IO - [MT Scale] Sent command: I1\n", + "2026-03-30 12:41:30,724 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I1\\r\\n'\n", + "2026-03-30 12:41:30,777 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I1 A \"01\" \"2.30\" \"2.22\" \"\" \"\"\\r\\n'\n", + "2026-03-30 12:41:30,779 - pylabrobot - IO - [MT Scale] Received response: b'I1 A \"01\" \"2.30\" \"2.22\" \"\" \"\"\\r\\n'\n" ] }, { @@ -764,24 +895,24 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": 11, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 12:07:29,495 - pylabrobot - IO - [MT Scale] Sent command: S\n", - "2026-03-30 12:07:29,499 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", - "2026-03-30 12:07:29,726 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00009 g\\r\\n'\n", - "2026-03-30 12:07:29,728 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00009 g\\r\\n'\n" + "2026-03-30 12:41:31,585 - pylabrobot - IO - [MT Scale] Sent command: S\n", + "2026-03-30 12:41:31,588 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", + "2026-03-30 12:41:31,624 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S -0.00008 g\\r\\n'\n", + "2026-03-30 12:41:31,624 - pylabrobot - IO - [MT Scale] Received response: b'S S -0.00008 g\\r\\n'\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ - "Stable weight (empty pan): 9e-05 g\n", + "Stable weight (empty pan): -8e-05 g\n", "PASS: stable weight returns float\n" ] } @@ -802,24 +933,24 @@ }, { "cell_type": "code", - "execution_count": 11, + "execution_count": 12, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 12:07:29,746 - pylabrobot - IO - [MT Scale] Sent command: SI\n", - "2026-03-30 12:07:29,751 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", - "2026-03-30 12:07:29,790 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00009 g\\r\\n'\n", - "2026-03-30 12:07:29,791 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00009 g\\r\\n'\n" + "2026-03-30 12:41:32,417 - pylabrobot - IO - [MT Scale] Sent command: SI\n", + "2026-03-30 12:41:32,421 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", + "2026-03-30 12:41:32,455 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S -0.00008 g\\r\\n'\n", + "2026-03-30 12:41:32,457 - pylabrobot - IO - [MT Scale] Received response: b'S S -0.00008 g\\r\\n'\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ - "Immediate weight: 9e-05 g\n", + "Immediate weight: -8e-05 g\n", "PASS: immediate weight returns float\n" ] } @@ -840,21 +971,21 @@ }, { "cell_type": "code", - "execution_count": 12, + "execution_count": 13, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 12:07:29,802 - pylabrobot - IO - [MT Scale] Sent command: Z\n", - "2026-03-30 12:07:29,806 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'Z\\r\\n'\n", - "2026-03-30 12:07:30,109 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'Z A\\r\\n'\n", - "2026-03-30 12:07:30,110 - pylabrobot - IO - [MT Scale] Received response: b'Z A\\r\\n'\n", - "2026-03-30 12:07:30,111 - pylabrobot - IO - [MT Scale] Sent command: SI\n", - "2026-03-30 12:07:30,112 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", - "2026-03-30 12:07:30,141 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 12:07:30,142 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n" + "2026-03-30 12:41:33,234 - pylabrobot - IO - [MT Scale] Sent command: Z\n", + "2026-03-30 12:41:33,236 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'Z\\r\\n'\n", + "2026-03-30 12:41:33,574 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'Z A\\r\\n'\n", + "2026-03-30 12:41:33,574 - pylabrobot - IO - [MT Scale] Received response: b'Z A\\r\\n'\n", + "2026-03-30 12:41:33,576 - pylabrobot - IO - [MT Scale] Sent command: SI\n", + "2026-03-30 12:41:33,577 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", + "2026-03-30 12:41:33,608 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 12:41:33,612 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n" ] }, { @@ -883,21 +1014,21 @@ }, { "cell_type": "code", - "execution_count": 13, + "execution_count": 14, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 12:07:30,149 - pylabrobot - IO - [MT Scale] Sent command: ZI\n", - "2026-03-30 12:07:30,151 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'ZI\\r\\n'\n", - "2026-03-30 12:07:30,173 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'ZI S\\r\\n'\n", - "2026-03-30 12:07:30,175 - pylabrobot - IO - [MT Scale] Received response: b'ZI S\\r\\n'\n", - "2026-03-30 12:07:30,176 - pylabrobot - IO - [MT Scale] Sent command: SI\n", - "2026-03-30 12:07:30,178 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", - "2026-03-30 12:07:30,206 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 12:07:30,207 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n" + "2026-03-30 12:41:34,275 - pylabrobot - IO - [MT Scale] Sent command: ZI\n", + "2026-03-30 12:41:34,277 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'ZI\\r\\n'\n", + "2026-03-30 12:41:34,294 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'ZI S\\r\\n'\n", + "2026-03-30 12:41:34,295 - pylabrobot - IO - [MT Scale] Received response: b'ZI S\\r\\n'\n", + "2026-03-30 12:41:34,295 - pylabrobot - IO - [MT Scale] Sent command: SI\n", + "2026-03-30 12:41:34,297 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", + "2026-03-30 12:41:34,326 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 12:41:34,329 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n" ] }, { @@ -936,7 +1067,7 @@ }, { "cell_type": "code", - "execution_count": 14, + "execution_count": 15, "metadata": {}, "outputs": [ { @@ -950,18 +1081,18 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 12:08:02,193 - pylabrobot - IO - [MT Scale] Sent command: Z\n", - "2026-03-30 12:08:02,196 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'Z\\r\\n'\n", - "2026-03-30 12:08:02,545 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'Z A\\r\\n'\n", - "2026-03-30 12:08:02,545 - pylabrobot - IO - [MT Scale] Received response: b'Z A\\r\\n'\n", - "2026-03-30 12:08:02,546 - pylabrobot - IO - [MT Scale] Sent command: T\n", - "2026-03-30 12:08:02,548 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'T\\r\\n'\n", - "2026-03-30 12:08:02,960 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'T S 0.00000 g\\r\\n'\n", - "2026-03-30 12:08:02,961 - pylabrobot - IO - [MT Scale] Received response: b'T S 0.00000 g\\r\\n'\n", - "2026-03-30 12:08:02,962 - pylabrobot - IO - [MT Scale] Sent command: TA\n", - "2026-03-30 12:08:02,965 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'TA\\r\\n'\n", - "2026-03-30 12:08:03,056 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'TA A 0.00000 g\\r\\n'\n", - "2026-03-30 12:08:03,057 - pylabrobot - IO - [MT Scale] Received response: b'TA A 0.00000 g\\r\\n'\n" + "2026-03-30 12:41:38,890 - pylabrobot - IO - [MT Scale] Sent command: Z\n", + "2026-03-30 12:41:38,892 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'Z\\r\\n'\n", + "2026-03-30 12:41:39,281 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'Z A\\r\\n'\n", + "2026-03-30 12:41:39,282 - pylabrobot - IO - [MT Scale] Received response: b'Z A\\r\\n'\n", + "2026-03-30 12:41:39,283 - pylabrobot - IO - [MT Scale] Sent command: T\n", + "2026-03-30 12:41:39,284 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'T\\r\\n'\n", + "2026-03-30 12:41:39,696 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'T S 0.00000 g\\r\\n'\n", + "2026-03-30 12:41:39,697 - pylabrobot - IO - [MT Scale] Received response: b'T S 0.00000 g\\r\\n'\n", + "2026-03-30 12:41:39,699 - pylabrobot - IO - [MT Scale] Sent command: TA\n", + "2026-03-30 12:41:39,701 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'TA\\r\\n'\n", + "2026-03-30 12:41:39,793 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'TA A 0.00000 g\\r\\n'\n", + "2026-03-30 12:41:39,793 - pylabrobot - IO - [MT Scale] Received response: b'TA A 0.00000 g\\r\\n'\n" ] }, { @@ -978,7 +1109,7 @@ "traceback": [ "\u001b[31m---------------------------------------------------------------------------\u001b[39m", "\u001b[31mAssertionError\u001b[39m Traceback (most recent call last)", - "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[14]\u001b[39m\u001b[32m, line 6\u001b[39m\n\u001b[32m 4\u001b[39m tare = \u001b[38;5;28;01mawait\u001b[39;00m scale.request_tare_weight()\n\u001b[32m 5\u001b[39m \u001b[38;5;28mprint\u001b[39m(\u001b[33mf\u001b[39m\u001b[33m\"\u001b[39m\u001b[33mTare weight: \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mtare\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m g\u001b[39m\u001b[33m\"\u001b[39m)\n\u001b[32m----> \u001b[39m\u001b[32m6\u001b[39m \u001b[38;5;28;01massert\u001b[39;00m tare > \u001b[32m0\u001b[39m, \u001b[33mf\u001b[39m\u001b[33m\"\u001b[39m\u001b[33mExpected positive tare, got \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mtare\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m\"\u001b[39m\n\u001b[32m 7\u001b[39m \u001b[38;5;28mprint\u001b[39m(\u001b[33m\"\u001b[39m\u001b[33mPASS: tare stores container weight\u001b[39m\u001b[33m\"\u001b[39m)\n", + "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[15]\u001b[39m\u001b[32m, line 6\u001b[39m\n\u001b[32m 4\u001b[39m tare = \u001b[38;5;28;01mawait\u001b[39;00m scale.request_tare_weight()\n\u001b[32m 5\u001b[39m \u001b[38;5;28mprint\u001b[39m(\u001b[33mf\u001b[39m\u001b[33m\"\u001b[39m\u001b[33mTare weight: \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mtare\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m g\u001b[39m\u001b[33m\"\u001b[39m)\n\u001b[32m----> \u001b[39m\u001b[32m6\u001b[39m \u001b[38;5;28;01massert\u001b[39;00m tare > \u001b[32m0\u001b[39m, \u001b[33mf\u001b[39m\u001b[33m\"\u001b[39m\u001b[33mExpected positive tare, got \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mtare\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m\"\u001b[39m\n\u001b[32m 7\u001b[39m \u001b[38;5;28mprint\u001b[39m(\u001b[33m\"\u001b[39m\u001b[33mPASS: tare stores container weight\u001b[39m\u001b[33m\"\u001b[39m)\n", "\u001b[31mAssertionError\u001b[39m: Expected positive tare, got 0.0" ] } @@ -1002,17 +1133,17 @@ }, { "cell_type": "code", - "execution_count": 15, + "execution_count": 16, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 12:08:06,275 - pylabrobot - IO - [MT Scale] Sent command: TA\n", - "2026-03-30 12:08:06,277 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'TA\\r\\n'\n", - "2026-03-30 12:08:06,397 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'TA A 0.00000 g\\r\\n'\n", - "2026-03-30 12:08:06,398 - pylabrobot - IO - [MT Scale] Received response: b'TA A 0.00000 g\\r\\n'\n" + "2026-03-30 12:41:42,457 - pylabrobot - IO - [MT Scale] Sent command: TA\n", + "2026-03-30 12:41:42,459 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'TA\\r\\n'\n", + "2026-03-30 12:41:42,542 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'TA A 0.00000 g\\r\\n'\n", + "2026-03-30 12:41:42,543 - pylabrobot - IO - [MT Scale] Received response: b'TA A 0.00000 g\\r\\n'\n" ] }, { @@ -1040,21 +1171,21 @@ }, { "cell_type": "code", - "execution_count": 16, + "execution_count": 17, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 12:08:07,124 - pylabrobot - IO - [MT Scale] Sent command: TAC\n", - "2026-03-30 12:08:07,130 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'TAC\\r\\n'\n", - "2026-03-30 12:08:07,148 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'TAC A\\r\\n'\n", - "2026-03-30 12:08:07,149 - pylabrobot - IO - [MT Scale] Received response: b'TAC A\\r\\n'\n", - "2026-03-30 12:08:07,150 - pylabrobot - IO - [MT Scale] Sent command: TA\n", - "2026-03-30 12:08:07,150 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'TA\\r\\n'\n", - "2026-03-30 12:08:07,276 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'TA A 0.00000 g\\r\\n'\n", - "2026-03-30 12:08:07,278 - pylabrobot - IO - [MT Scale] Received response: b'TA A 0.00000 g\\r\\n'\n" + "2026-03-30 12:41:43,768 - pylabrobot - IO - [MT Scale] Sent command: TAC\n", + "2026-03-30 12:41:43,770 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'TAC\\r\\n'\n", + "2026-03-30 12:41:43,805 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'TAC A\\r\\n'\n", + "2026-03-30 12:41:43,806 - pylabrobot - IO - [MT Scale] Received response: b'TAC A\\r\\n'\n", + "2026-03-30 12:41:43,807 - pylabrobot - IO - [MT Scale] Sent command: TA\n", + "2026-03-30 12:41:43,809 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'TA\\r\\n'\n", + "2026-03-30 12:41:43,916 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'TA A 0.00000 g\\r\\n'\n", + "2026-03-30 12:41:43,918 - pylabrobot - IO - [MT Scale] Received response: b'TA A 0.00000 g\\r\\n'\n" ] }, { @@ -1083,17 +1214,17 @@ }, { "cell_type": "code", - "execution_count": 17, + "execution_count": 18, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 12:08:07,873 - pylabrobot - IO - [MT Scale] Sent command: SC 3000\n", - "2026-03-30 12:08:07,875 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SC 3000\\r\\n'\n", - "2026-03-30 12:08:07,900 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'ES\\r\\n'\n", - "2026-03-30 12:08:07,901 - pylabrobot - IO - [MT Scale] Received response: b'ES\\r\\n'\n" + "2026-03-30 12:41:44,525 - pylabrobot - IO - [MT Scale] Sent command: SC 3000\n", + "2026-03-30 12:41:44,526 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SC 3000\\r\\n'\n", + "2026-03-30 12:41:44,556 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'ES\\r\\n'\n", + "2026-03-30 12:41:44,557 - pylabrobot - IO - [MT Scale] Received response: b'ES\\r\\n'\n" ] }, { @@ -1103,10 +1234,10 @@ "traceback": [ "\u001b[31m---------------------------------------------------------------------------\u001b[39m", "\u001b[31mMettlerToledoError\u001b[39m Traceback (most recent call last)", - "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[17]\u001b[39m\u001b[32m, line 1\u001b[39m\n\u001b[32m----> \u001b[39m\u001b[32m1\u001b[39m weight = \u001b[38;5;28;01mawait\u001b[39;00m backend.read_dynamic_weight(timeout=\u001b[32m3.0\u001b[39m)\n\u001b[32m 2\u001b[39m \u001b[38;5;28mprint\u001b[39m(\u001b[33mf\u001b[39m\u001b[33m\"\u001b[39m\u001b[33mDynamic weight (3s timeout): \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mweight\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m g\u001b[39m\u001b[33m\"\u001b[39m)\n\u001b[32m 3\u001b[39m \u001b[38;5;28;01massert\u001b[39;00m \u001b[38;5;28misinstance\u001b[39m(weight, \u001b[38;5;28mfloat\u001b[39m)\n", - "\u001b[36mFile \u001b[39m\u001b[32m~/Desktop/GitHub/pylabrobot/pylabrobot/scales/mettler_toledo/backend.py:538\u001b[39m, in \u001b[36mMettlerToledoWXS205SDUBackend.read_dynamic_weight\u001b[39m\u001b[34m(self, timeout)\u001b[39m\n\u001b[32m 529\u001b[39m \u001b[38;5;250m\u001b[39m\u001b[33;03m\"\"\"Read a stable weight value from the machine within a given timeout, or\u001b[39;00m\n\u001b[32m 530\u001b[39m \u001b[33;03mreturn the current weight value if not possible. (MEASUREMENT command)\u001b[39;00m\n\u001b[32m 531\u001b[39m \n\u001b[32m 532\u001b[39m \u001b[33;03mArgs:\u001b[39;00m\n\u001b[32m 533\u001b[39m \u001b[33;03m timeout: The timeout in seconds.\u001b[39;00m\n\u001b[32m 534\u001b[39m \u001b[33;03m\"\"\"\u001b[39;00m\n\u001b[32m 536\u001b[39m timeout = \u001b[38;5;28mint\u001b[39m(timeout * \u001b[32m1000\u001b[39m) \u001b[38;5;66;03m# convert to milliseconds\u001b[39;00m\n\u001b[32m--> \u001b[39m\u001b[32m538\u001b[39m responses = \u001b[38;5;28;01mawait\u001b[39;00m \u001b[38;5;28mself\u001b[39m.send_command(\u001b[33mf\u001b[39m\u001b[33m\"\u001b[39m\u001b[33mSC \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mtimeout\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m\"\u001b[39m)\n\u001b[32m 539\u001b[39m \u001b[38;5;28mself\u001b[39m._validate_response(responses[\u001b[32m0\u001b[39m], \u001b[32m4\u001b[39m, \u001b[33m\"\u001b[39m\u001b[33mSC\u001b[39m\u001b[33m\"\u001b[39m)\n\u001b[32m 540\u001b[39m \u001b[38;5;28mself\u001b[39m._validate_unit(responses[\u001b[32m0\u001b[39m].data[\u001b[32m1\u001b[39m], \u001b[33m\"\u001b[39m\u001b[33mSC\u001b[39m\u001b[33m\"\u001b[39m)\n", - "\u001b[36mFile \u001b[39m\u001b[32m~/Desktop/GitHub/pylabrobot/pylabrobot/scales/mettler_toledo/backend.py:312\u001b[39m, in \u001b[36mMettlerToledoWXS205SDUBackend.send_command\u001b[39m\u001b[34m(self, command, timeout)\u001b[39m\n\u001b[32m 310\u001b[39m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[32m 311\u001b[39m response = MettlerToledoResponse(command=\u001b[33m\"\u001b[39m\u001b[33m\"\u001b[39m, status=\u001b[33m\"\u001b[39m\u001b[33m\"\u001b[39m, data=[])\n\u001b[32m--> \u001b[39m\u001b[32m312\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[43m.\u001b[49m\u001b[43m_parse_basic_errors\u001b[49m\u001b[43m(\u001b[49m\u001b[43mresponse\u001b[49m\u001b[43m)\u001b[49m\n\u001b[32m 313\u001b[39m responses.append(response)\n\u001b[32m 315\u001b[39m \u001b[38;5;66;03m# Status B means more responses follow; anything else (A, etc.) is final\u001b[39;00m\n", - "\u001b[36mFile \u001b[39m\u001b[32m~/Desktop/GitHub/pylabrobot/pylabrobot/scales/mettler_toledo/backend.py:233\u001b[39m, in \u001b[36mMettlerToledoWXS205SDUBackend._parse_basic_errors\u001b[39m\u001b[34m(self, response)\u001b[39m\n\u001b[32m 231\u001b[39m \u001b[38;5;66;03m# General error messages: ES, ET, EL (status is \"\" for these)\u001b[39;00m\n\u001b[32m 232\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m response.command == \u001b[33m\"\u001b[39m\u001b[33mES\u001b[39m\u001b[33m\"\u001b[39m:\n\u001b[32m--> \u001b[39m\u001b[32m233\u001b[39m \u001b[38;5;28;01mraise\u001b[39;00m MettlerToledoError.syntax_error()\n\u001b[32m 234\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m response.command == \u001b[33m\"\u001b[39m\u001b[33mET\u001b[39m\u001b[33m\"\u001b[39m:\n\u001b[32m 235\u001b[39m \u001b[38;5;28;01mraise\u001b[39;00m MettlerToledoError.transmission_error()\n", + "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[18]\u001b[39m\u001b[32m, line 1\u001b[39m\n\u001b[32m----> \u001b[39m\u001b[32m1\u001b[39m weight = \u001b[38;5;28;01mawait\u001b[39;00m backend.read_dynamic_weight(timeout=\u001b[32m3.0\u001b[39m)\n\u001b[32m 2\u001b[39m \u001b[38;5;28mprint\u001b[39m(\u001b[33mf\u001b[39m\u001b[33m\"\u001b[39m\u001b[33mDynamic weight (3s timeout): \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mweight\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m g\u001b[39m\u001b[33m\"\u001b[39m)\n\u001b[32m 3\u001b[39m \u001b[38;5;28;01massert\u001b[39;00m \u001b[38;5;28misinstance\u001b[39m(weight, \u001b[38;5;28mfloat\u001b[39m)\n", + "\u001b[36mFile \u001b[39m\u001b[32m~/Desktop/GitHub/pylabrobot/pylabrobot/scales/mettler_toledo/backend.py:647\u001b[39m, in \u001b[36mMettlerToledoWXS205SDUBackend.read_dynamic_weight\u001b[39m\u001b[34m(self, timeout)\u001b[39m\n\u001b[32m 638\u001b[39m \u001b[38;5;250m\u001b[39m\u001b[33;03m\"\"\"Read a stable weight value from the machine within a given timeout, or\u001b[39;00m\n\u001b[32m 639\u001b[39m \u001b[33;03mreturn the current weight value if not possible. (MEASUREMENT command)\u001b[39;00m\n\u001b[32m 640\u001b[39m \n\u001b[32m 641\u001b[39m \u001b[33;03mArgs:\u001b[39;00m\n\u001b[32m 642\u001b[39m \u001b[33;03m timeout: The timeout in seconds.\u001b[39;00m\n\u001b[32m 643\u001b[39m \u001b[33;03m\"\"\"\u001b[39;00m\n\u001b[32m 645\u001b[39m timeout = \u001b[38;5;28mint\u001b[39m(timeout * \u001b[32m1000\u001b[39m) \u001b[38;5;66;03m# convert to milliseconds\u001b[39;00m\n\u001b[32m--> \u001b[39m\u001b[32m647\u001b[39m responses = \u001b[38;5;28;01mawait\u001b[39;00m \u001b[38;5;28mself\u001b[39m.send_command(\u001b[33mf\u001b[39m\u001b[33m\"\u001b[39m\u001b[33mSC \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mtimeout\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m\"\u001b[39m)\n\u001b[32m 648\u001b[39m \u001b[38;5;28mself\u001b[39m._validate_response(responses[\u001b[32m0\u001b[39m], \u001b[32m4\u001b[39m, \u001b[33m\"\u001b[39m\u001b[33mSC\u001b[39m\u001b[33m\"\u001b[39m)\n\u001b[32m 649\u001b[39m \u001b[38;5;28mself\u001b[39m._validate_unit(responses[\u001b[32m0\u001b[39m].data[\u001b[32m1\u001b[39m], \u001b[33m\"\u001b[39m\u001b[33mSC\u001b[39m\u001b[33m\"\u001b[39m)\n", + "\u001b[36mFile \u001b[39m\u001b[32m~/Desktop/GitHub/pylabrobot/pylabrobot/scales/mettler_toledo/backend.py:322\u001b[39m, in \u001b[36mMettlerToledoWXS205SDUBackend.send_command\u001b[39m\u001b[34m(self, command, timeout)\u001b[39m\n\u001b[32m 320\u001b[39m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[32m 321\u001b[39m response = MettlerToledoResponse(command=\u001b[33m\"\u001b[39m\u001b[33m\"\u001b[39m, status=\u001b[33m\"\u001b[39m\u001b[33m\"\u001b[39m, data=[])\n\u001b[32m--> \u001b[39m\u001b[32m322\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[43m.\u001b[49m\u001b[43m_parse_basic_errors\u001b[49m\u001b[43m(\u001b[49m\u001b[43mresponse\u001b[49m\u001b[43m)\u001b[49m\n\u001b[32m 323\u001b[39m responses.append(response)\n\u001b[32m 325\u001b[39m \u001b[38;5;66;03m# Status B means more responses follow; anything else (A, etc.) is final\u001b[39;00m\n", + "\u001b[36mFile \u001b[39m\u001b[32m~/Desktop/GitHub/pylabrobot/pylabrobot/scales/mettler_toledo/backend.py:243\u001b[39m, in \u001b[36mMettlerToledoWXS205SDUBackend._parse_basic_errors\u001b[39m\u001b[34m(self, response)\u001b[39m\n\u001b[32m 241\u001b[39m \u001b[38;5;66;03m# General error messages: ES, ET, EL (status is \"\" for these)\u001b[39;00m\n\u001b[32m 242\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m response.command == \u001b[33m\"\u001b[39m\u001b[33mES\u001b[39m\u001b[33m\"\u001b[39m:\n\u001b[32m--> \u001b[39m\u001b[32m243\u001b[39m \u001b[38;5;28;01mraise\u001b[39;00m MettlerToledoError.syntax_error()\n\u001b[32m 244\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m response.command == \u001b[33m\"\u001b[39m\u001b[33mET\u001b[39m\u001b[33m\"\u001b[39m:\n\u001b[32m 245\u001b[39m \u001b[38;5;28;01mraise\u001b[39;00m MettlerToledoError.transmission_error()\n", "\u001b[31mMettlerToledoError\u001b[39m: Syntax error: The weigh module/balance has not recognized the received command or the command is not allowed" ] } @@ -1127,17 +1258,17 @@ }, { "cell_type": "code", - "execution_count": 18, + "execution_count": 19, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 12:08:08,895 - pylabrobot - IO - [MT Scale] Sent command: C\n", - "2026-03-30 12:08:08,897 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'C\\r\\n'\n", - "2026-03-30 12:08:08,924 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'ES\\r\\n'\n", - "2026-03-30 12:08:08,924 - pylabrobot - IO - [MT Scale] Received response: b'ES\\r\\n'\n" + "2026-03-30 12:41:45,645 - pylabrobot - IO - [MT Scale] Sent command: C\n", + "2026-03-30 12:41:45,647 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'C\\r\\n'\n", + "2026-03-30 12:41:45,675 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'ES\\r\\n'\n", + "2026-03-30 12:41:45,676 - pylabrobot - IO - [MT Scale] Received response: b'ES\\r\\n'\n" ] }, { @@ -1147,10 +1278,10 @@ "traceback": [ "\u001b[31m---------------------------------------------------------------------------\u001b[39m", "\u001b[31mMettlerToledoError\u001b[39m Traceback (most recent call last)", - "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[18]\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 backend.cancel_all()\n\u001b[32m 2\u001b[39m \u001b[38;5;28mprint\u001b[39m(\u001b[33m\"\u001b[39m\u001b[33mPASS: cancel_all completed without error\u001b[39m\u001b[33m\"\u001b[39m)\n", - "\u001b[36mFile \u001b[39m\u001b[32m~/Desktop/GitHub/pylabrobot/pylabrobot/scales/mettler_toledo/backend.py:350\u001b[39m, in \u001b[36mMettlerToledoWXS205SDUBackend.cancel_all\u001b[39m\u001b[34m(self)\u001b[39m\n\u001b[32m 340\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[34mcancel_all\u001b[39m(\u001b[38;5;28mself\u001b[39m) -> \u001b[38;5;28;01mNone\u001b[39;00m:\n\u001b[32m 341\u001b[39m \u001b[38;5;250m \u001b[39m\u001b[33;03m\"\"\"C - Cancel all active and pending interface commands.\u001b[39;00m\n\u001b[32m 342\u001b[39m \n\u001b[32m 343\u001b[39m \u001b[33;03m Unlike cancel() (@), this does not reset the device - it only cancels\u001b[39;00m\n\u001b[32m (...)\u001b[39m\u001b[32m 348\u001b[39m \u001b[33;03m C A (complete). Both responses are consumed to keep the serial buffer clean.\u001b[39;00m\n\u001b[32m 349\u001b[39m \u001b[33;03m \"\"\"\u001b[39;00m\n\u001b[32m--> \u001b[39m\u001b[32m350\u001b[39m responses = \u001b[38;5;28;01mawait\u001b[39;00m \u001b[38;5;28mself\u001b[39m.send_command(\u001b[33m\"\u001b[39m\u001b[33mC\u001b[39m\u001b[33m\"\u001b[39m)\n\u001b[32m 351\u001b[39m \u001b[38;5;66;03m# send_command reads both C B (started) and C A (complete) automatically\u001b[39;00m\n\u001b[32m 352\u001b[39m \u001b[38;5;28mself\u001b[39m._validate_response(responses[\u001b[32m0\u001b[39m], \u001b[32m2\u001b[39m, \u001b[33m\"\u001b[39m\u001b[33mC\u001b[39m\u001b[33m\"\u001b[39m)\n", - "\u001b[36mFile \u001b[39m\u001b[32m~/Desktop/GitHub/pylabrobot/pylabrobot/scales/mettler_toledo/backend.py:312\u001b[39m, in \u001b[36mMettlerToledoWXS205SDUBackend.send_command\u001b[39m\u001b[34m(self, command, timeout)\u001b[39m\n\u001b[32m 310\u001b[39m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[32m 311\u001b[39m response = MettlerToledoResponse(command=\u001b[33m\"\u001b[39m\u001b[33m\"\u001b[39m, status=\u001b[33m\"\u001b[39m\u001b[33m\"\u001b[39m, data=[])\n\u001b[32m--> \u001b[39m\u001b[32m312\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[43m.\u001b[49m\u001b[43m_parse_basic_errors\u001b[49m\u001b[43m(\u001b[49m\u001b[43mresponse\u001b[49m\u001b[43m)\u001b[49m\n\u001b[32m 313\u001b[39m responses.append(response)\n\u001b[32m 315\u001b[39m \u001b[38;5;66;03m# Status B means more responses follow; anything else (A, etc.) is final\u001b[39;00m\n", - "\u001b[36mFile \u001b[39m\u001b[32m~/Desktop/GitHub/pylabrobot/pylabrobot/scales/mettler_toledo/backend.py:233\u001b[39m, in \u001b[36mMettlerToledoWXS205SDUBackend._parse_basic_errors\u001b[39m\u001b[34m(self, response)\u001b[39m\n\u001b[32m 231\u001b[39m \u001b[38;5;66;03m# General error messages: ES, ET, EL (status is \"\" for these)\u001b[39;00m\n\u001b[32m 232\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m response.command == \u001b[33m\"\u001b[39m\u001b[33mES\u001b[39m\u001b[33m\"\u001b[39m:\n\u001b[32m--> \u001b[39m\u001b[32m233\u001b[39m \u001b[38;5;28;01mraise\u001b[39;00m MettlerToledoError.syntax_error()\n\u001b[32m 234\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m response.command == \u001b[33m\"\u001b[39m\u001b[33mET\u001b[39m\u001b[33m\"\u001b[39m:\n\u001b[32m 235\u001b[39m \u001b[38;5;28;01mraise\u001b[39;00m MettlerToledoError.transmission_error()\n", + "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[19]\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 backend.cancel_all()\n\u001b[32m 2\u001b[39m \u001b[38;5;28mprint\u001b[39m(\u001b[33m\"\u001b[39m\u001b[33mPASS: cancel_all completed without error\u001b[39m\u001b[33m\"\u001b[39m)\n", + "\u001b[36mFile \u001b[39m\u001b[32m~/Desktop/GitHub/pylabrobot/pylabrobot/scales/mettler_toledo/backend.py:360\u001b[39m, in \u001b[36mMettlerToledoWXS205SDUBackend.cancel_all\u001b[39m\u001b[34m(self)\u001b[39m\n\u001b[32m 350\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[34mcancel_all\u001b[39m(\u001b[38;5;28mself\u001b[39m) -> \u001b[38;5;28;01mNone\u001b[39;00m:\n\u001b[32m 351\u001b[39m \u001b[38;5;250m \u001b[39m\u001b[33;03m\"\"\"C - Cancel all active and pending interface commands.\u001b[39;00m\n\u001b[32m 352\u001b[39m \n\u001b[32m 353\u001b[39m \u001b[33;03m Unlike cancel() (@), this does not reset the device - it only cancels\u001b[39;00m\n\u001b[32m (...)\u001b[39m\u001b[32m 358\u001b[39m \u001b[33;03m C A (complete). Both responses are consumed to keep the serial buffer clean.\u001b[39;00m\n\u001b[32m 359\u001b[39m \u001b[33;03m \"\"\"\u001b[39;00m\n\u001b[32m--> \u001b[39m\u001b[32m360\u001b[39m responses = \u001b[38;5;28;01mawait\u001b[39;00m \u001b[38;5;28mself\u001b[39m.send_command(\u001b[33m\"\u001b[39m\u001b[33mC\u001b[39m\u001b[33m\"\u001b[39m)\n\u001b[32m 361\u001b[39m \u001b[38;5;66;03m# send_command reads both C B (started) and C A (complete) automatically\u001b[39;00m\n\u001b[32m 362\u001b[39m \u001b[38;5;28mself\u001b[39m._validate_response(responses[\u001b[32m0\u001b[39m], \u001b[32m2\u001b[39m, \u001b[33m\"\u001b[39m\u001b[33mC\u001b[39m\u001b[33m\"\u001b[39m)\n", + "\u001b[36mFile \u001b[39m\u001b[32m~/Desktop/GitHub/pylabrobot/pylabrobot/scales/mettler_toledo/backend.py:322\u001b[39m, in \u001b[36mMettlerToledoWXS205SDUBackend.send_command\u001b[39m\u001b[34m(self, command, timeout)\u001b[39m\n\u001b[32m 320\u001b[39m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[32m 321\u001b[39m response = MettlerToledoResponse(command=\u001b[33m\"\u001b[39m\u001b[33m\"\u001b[39m, status=\u001b[33m\"\u001b[39m\u001b[33m\"\u001b[39m, data=[])\n\u001b[32m--> \u001b[39m\u001b[32m322\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[43m.\u001b[49m\u001b[43m_parse_basic_errors\u001b[49m\u001b[43m(\u001b[49m\u001b[43mresponse\u001b[49m\u001b[43m)\u001b[49m\n\u001b[32m 323\u001b[39m responses.append(response)\n\u001b[32m 325\u001b[39m \u001b[38;5;66;03m# Status B means more responses follow; anything else (A, etc.) is final\u001b[39;00m\n", + "\u001b[36mFile \u001b[39m\u001b[32m~/Desktop/GitHub/pylabrobot/pylabrobot/scales/mettler_toledo/backend.py:243\u001b[39m, in \u001b[36mMettlerToledoWXS205SDUBackend._parse_basic_errors\u001b[39m\u001b[34m(self, response)\u001b[39m\n\u001b[32m 241\u001b[39m \u001b[38;5;66;03m# General error messages: ES, ET, EL (status is \"\" for these)\u001b[39;00m\n\u001b[32m 242\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m response.command == \u001b[33m\"\u001b[39m\u001b[33mES\u001b[39m\u001b[33m\"\u001b[39m:\n\u001b[32m--> \u001b[39m\u001b[32m243\u001b[39m \u001b[38;5;28;01mraise\u001b[39;00m MettlerToledoError.syntax_error()\n\u001b[32m 244\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m response.command == \u001b[33m\"\u001b[39m\u001b[33mET\u001b[39m\u001b[33m\"\u001b[39m:\n\u001b[32m 245\u001b[39m \u001b[38;5;28;01mraise\u001b[39;00m MettlerToledoError.transmission_error()\n", "\u001b[31mMettlerToledoError\u001b[39m: Syntax error: The weigh module/balance has not recognized the received command or the command is not allowed" ] } @@ -1169,17 +1300,17 @@ }, { "cell_type": "code", - "execution_count": 19, + "execution_count": 20, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 12:08:09,775 - pylabrobot - IO - [MT Scale] Sent command: D \"PLR TEST\"\n", - "2026-03-30 12:08:09,778 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'D \"PLR TEST\"\\r\\n'\n", - "2026-03-30 12:08:09,803 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'ES\\r\\n'\n", - "2026-03-30 12:08:09,804 - pylabrobot - IO - [MT Scale] Received response: b'ES\\r\\n'\n" + "2026-03-30 12:41:46,696 - pylabrobot - IO - [MT Scale] Sent command: D \"PLR TEST\"\n", + "2026-03-30 12:41:46,698 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'D \"PLR TEST\"\\r\\n'\n", + "2026-03-30 12:41:46,730 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'ES\\r\\n'\n", + "2026-03-30 12:41:46,733 - pylabrobot - IO - [MT Scale] Received response: b'ES\\r\\n'\n" ] }, { @@ -1189,10 +1320,10 @@ "traceback": [ "\u001b[31m---------------------------------------------------------------------------\u001b[39m", "\u001b[31mMettlerToledoError\u001b[39m Traceback (most recent call last)", - "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[19]\u001b[39m\u001b[32m, line 3\u001b[39m\n\u001b[32m 1\u001b[39m \u001b[38;5;28;01mimport\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[34;01masyncio\u001b[39;00m\n\u001b[32m----> \u001b[39m\u001b[32m3\u001b[39m \u001b[38;5;28;01mawait\u001b[39;00m backend.set_display_text(\u001b[33m\"\u001b[39m\u001b[33mPLR TEST\u001b[39m\u001b[33m\"\u001b[39m)\n\u001b[32m 4\u001b[39m \u001b[38;5;28;01mawait\u001b[39;00m asyncio.sleep(\u001b[32m2\u001b[39m)\n\u001b[32m 5\u001b[39m \u001b[38;5;28;01mawait\u001b[39;00m backend.set_weight_display()\n", - "\u001b[36mFile \u001b[39m\u001b[32m~/Desktop/GitHub/pylabrobot/pylabrobot/scales/mettler_toledo/backend.py:583\u001b[39m, in \u001b[36mMettlerToledoWXS205SDUBackend.set_display_text\u001b[39m\u001b[34m(self, text)\u001b[39m\n\u001b[32m 580\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[34mset_display_text\u001b[39m(\u001b[38;5;28mself\u001b[39m, text: \u001b[38;5;28mstr\u001b[39m) -> List[MettlerToledoResponse]:\n\u001b[32m 581\u001b[39m \u001b[38;5;250m \u001b[39m\u001b[33;03m\"\"\"Set the display text of the scale. Return to the normal weight display with\u001b[39;00m\n\u001b[32m 582\u001b[39m \u001b[33;03m self.set_weight_display().\"\"\"\u001b[39;00m\n\u001b[32m--> \u001b[39m\u001b[32m583\u001b[39m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;01mawait\u001b[39;00m \u001b[38;5;28mself\u001b[39m.send_command(\u001b[33mf\u001b[39m\u001b[33m'\u001b[39m\u001b[33mD \u001b[39m\u001b[33m\"\u001b[39m\u001b[38;5;132;01m{\u001b[39;00mtext\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m\"\u001b[39m\u001b[33m'\u001b[39m)\n", - "\u001b[36mFile \u001b[39m\u001b[32m~/Desktop/GitHub/pylabrobot/pylabrobot/scales/mettler_toledo/backend.py:312\u001b[39m, in \u001b[36mMettlerToledoWXS205SDUBackend.send_command\u001b[39m\u001b[34m(self, command, timeout)\u001b[39m\n\u001b[32m 310\u001b[39m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[32m 311\u001b[39m response = MettlerToledoResponse(command=\u001b[33m\"\u001b[39m\u001b[33m\"\u001b[39m, status=\u001b[33m\"\u001b[39m\u001b[33m\"\u001b[39m, data=[])\n\u001b[32m--> \u001b[39m\u001b[32m312\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[43m.\u001b[49m\u001b[43m_parse_basic_errors\u001b[49m\u001b[43m(\u001b[49m\u001b[43mresponse\u001b[49m\u001b[43m)\u001b[49m\n\u001b[32m 313\u001b[39m responses.append(response)\n\u001b[32m 315\u001b[39m \u001b[38;5;66;03m# Status B means more responses follow; anything else (A, etc.) is final\u001b[39;00m\n", - "\u001b[36mFile \u001b[39m\u001b[32m~/Desktop/GitHub/pylabrobot/pylabrobot/scales/mettler_toledo/backend.py:233\u001b[39m, in \u001b[36mMettlerToledoWXS205SDUBackend._parse_basic_errors\u001b[39m\u001b[34m(self, response)\u001b[39m\n\u001b[32m 231\u001b[39m \u001b[38;5;66;03m# General error messages: ES, ET, EL (status is \"\" for these)\u001b[39;00m\n\u001b[32m 232\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m response.command == \u001b[33m\"\u001b[39m\u001b[33mES\u001b[39m\u001b[33m\"\u001b[39m:\n\u001b[32m--> \u001b[39m\u001b[32m233\u001b[39m \u001b[38;5;28;01mraise\u001b[39;00m MettlerToledoError.syntax_error()\n\u001b[32m 234\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m response.command == \u001b[33m\"\u001b[39m\u001b[33mET\u001b[39m\u001b[33m\"\u001b[39m:\n\u001b[32m 235\u001b[39m \u001b[38;5;28;01mraise\u001b[39;00m MettlerToledoError.transmission_error()\n", + "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[20]\u001b[39m\u001b[32m, line 3\u001b[39m\n\u001b[32m 1\u001b[39m \u001b[38;5;28;01mimport\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[34;01masyncio\u001b[39;00m\n\u001b[32m----> \u001b[39m\u001b[32m3\u001b[39m \u001b[38;5;28;01mawait\u001b[39;00m backend.set_display_text(\u001b[33m\"\u001b[39m\u001b[33mPLR TEST\u001b[39m\u001b[33m\"\u001b[39m)\n\u001b[32m 4\u001b[39m \u001b[38;5;28;01mawait\u001b[39;00m asyncio.sleep(\u001b[32m2\u001b[39m)\n\u001b[32m 5\u001b[39m \u001b[38;5;28;01mawait\u001b[39;00m backend.set_weight_display()\n", + "\u001b[36mFile \u001b[39m\u001b[32m~/Desktop/GitHub/pylabrobot/pylabrobot/scales/mettler_toledo/backend.py:692\u001b[39m, in \u001b[36mMettlerToledoWXS205SDUBackend.set_display_text\u001b[39m\u001b[34m(self, text)\u001b[39m\n\u001b[32m 689\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[34mset_display_text\u001b[39m(\u001b[38;5;28mself\u001b[39m, text: \u001b[38;5;28mstr\u001b[39m) -> List[MettlerToledoResponse]:\n\u001b[32m 690\u001b[39m \u001b[38;5;250m \u001b[39m\u001b[33;03m\"\"\"Set the display text of the scale. Return to the normal weight display with\u001b[39;00m\n\u001b[32m 691\u001b[39m \u001b[33;03m self.set_weight_display().\"\"\"\u001b[39;00m\n\u001b[32m--> \u001b[39m\u001b[32m692\u001b[39m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;01mawait\u001b[39;00m \u001b[38;5;28mself\u001b[39m.send_command(\u001b[33mf\u001b[39m\u001b[33m'\u001b[39m\u001b[33mD \u001b[39m\u001b[33m\"\u001b[39m\u001b[38;5;132;01m{\u001b[39;00mtext\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m\"\u001b[39m\u001b[33m'\u001b[39m)\n", + "\u001b[36mFile \u001b[39m\u001b[32m~/Desktop/GitHub/pylabrobot/pylabrobot/scales/mettler_toledo/backend.py:322\u001b[39m, in \u001b[36mMettlerToledoWXS205SDUBackend.send_command\u001b[39m\u001b[34m(self, command, timeout)\u001b[39m\n\u001b[32m 320\u001b[39m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[32m 321\u001b[39m response = MettlerToledoResponse(command=\u001b[33m\"\u001b[39m\u001b[33m\"\u001b[39m, status=\u001b[33m\"\u001b[39m\u001b[33m\"\u001b[39m, data=[])\n\u001b[32m--> \u001b[39m\u001b[32m322\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[43m.\u001b[49m\u001b[43m_parse_basic_errors\u001b[49m\u001b[43m(\u001b[49m\u001b[43mresponse\u001b[49m\u001b[43m)\u001b[49m\n\u001b[32m 323\u001b[39m responses.append(response)\n\u001b[32m 325\u001b[39m \u001b[38;5;66;03m# Status B means more responses follow; anything else (A, etc.) is final\u001b[39;00m\n", + "\u001b[36mFile \u001b[39m\u001b[32m~/Desktop/GitHub/pylabrobot/pylabrobot/scales/mettler_toledo/backend.py:243\u001b[39m, in \u001b[36mMettlerToledoWXS205SDUBackend._parse_basic_errors\u001b[39m\u001b[34m(self, response)\u001b[39m\n\u001b[32m 241\u001b[39m \u001b[38;5;66;03m# General error messages: ES, ET, EL (status is \"\" for these)\u001b[39;00m\n\u001b[32m 242\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m response.command == \u001b[33m\"\u001b[39m\u001b[33mES\u001b[39m\u001b[33m\"\u001b[39m:\n\u001b[32m--> \u001b[39m\u001b[32m243\u001b[39m \u001b[38;5;28;01mraise\u001b[39;00m MettlerToledoError.syntax_error()\n\u001b[32m 244\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m response.command == \u001b[33m\"\u001b[39m\u001b[33mET\u001b[39m\u001b[33m\"\u001b[39m:\n\u001b[32m 245\u001b[39m \u001b[38;5;28;01mraise\u001b[39;00m MettlerToledoError.transmission_error()\n", "\u001b[31mMettlerToledoError\u001b[39m: Syntax error: The weigh module/balance has not recognized the received command or the command is not allowed" ] } @@ -1217,21 +1348,21 @@ }, { "cell_type": "code", - "execution_count": 20, + "execution_count": 21, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 12:08:11,168 - pylabrobot - IO - [MT Scale] Sent command: ZC 5000\n", - "2026-03-30 12:08:11,172 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'ZC 5000\\r\\n'\n", - "2026-03-30 12:08:11,193 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'ES\\r\\n'\n", - "2026-03-30 12:08:11,194 - pylabrobot - IO - [MT Scale] Received response: b'ES\\r\\n'\n", - "2026-03-30 12:08:11,195 - pylabrobot - IO - [MT Scale] Sent command: TC 5000\n", - "2026-03-30 12:08:11,196 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'TC 5000\\r\\n'\n", - "2026-03-30 12:08:11,225 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'ES\\r\\n'\n", - "2026-03-30 12:08:11,227 - pylabrobot - IO - [MT Scale] Received response: b'ES\\r\\n'\n" + "2026-03-30 12:41:47,619 - pylabrobot - IO - [MT Scale] Sent command: ZC 5000\n", + "2026-03-30 12:41:47,621 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'ZC 5000\\r\\n'\n", + "2026-03-30 12:41:47,641 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'ES\\r\\n'\n", + "2026-03-30 12:41:47,642 - pylabrobot - IO - [MT Scale] Received response: b'ES\\r\\n'\n", + "2026-03-30 12:41:47,642 - pylabrobot - IO - [MT Scale] Sent command: TC 5000\n", + "2026-03-30 12:41:47,644 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'TC 5000\\r\\n'\n", + "2026-03-30 12:41:47,674 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'ES\\r\\n'\n", + "2026-03-30 12:41:47,676 - pylabrobot - IO - [MT Scale] Received response: b'ES\\r\\n'\n" ] }, { @@ -1274,17 +1405,17 @@ }, { "cell_type": "code", - "execution_count": 21, + "execution_count": 22, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 12:08:12,987 - pylabrobot - IO - [MT Scale] Sent command: M21 0 0\n", - "2026-03-30 12:08:12,990 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'M21 0 0\\r\\n'\n", - "2026-03-30 12:08:13,016 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M21 A\\r\\n'\n", - "2026-03-30 12:08:13,016 - pylabrobot - IO - [MT Scale] Received response: b'M21 A\\r\\n'\n" + "2026-03-30 12:41:49,217 - pylabrobot - IO - [MT Scale] Sent command: M21 0 0\n", + "2026-03-30 12:41:49,219 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'M21 0 0\\r\\n'\n", + "2026-03-30 12:41:49,256 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M21 A\\r\\n'\n", + "2026-03-30 12:41:49,258 - pylabrobot - IO - [MT Scale] Received response: b'M21 A\\r\\n'\n" ] }, { @@ -1312,7 +1443,7 @@ }, { "cell_type": "code", - "execution_count": 22, + "execution_count": 23, "metadata": {}, "outputs": [ { @@ -1343,26 +1474,26 @@ }, { "cell_type": "code", - "execution_count": 23, + "execution_count": 24, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 12:08:14,914 - pylabrobot - IO - [MT Scale] Sent command: M28\n", - "2026-03-30 12:08:14,917 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'M28\\r\\n'\n", - "2026-03-30 12:08:14,950 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M28 B 1 19.9\\r\\n'\n", - "2026-03-30 12:08:14,950 - pylabrobot - IO - [MT Scale] Received response: b'M28 B 1 19.9\\r\\n'\n", - "2026-03-30 12:08:14,966 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M28 A 2 19.4\\r\\n'\n", - "2026-03-30 12:08:14,967 - pylabrobot - IO - [MT Scale] Received response: b'M28 A 2 19.4\\r\\n'\n" + "2026-03-30 12:41:53,996 - pylabrobot - IO - [MT Scale] Sent command: M28\n", + "2026-03-30 12:41:53,999 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'M28\\r\\n'\n", + "2026-03-30 12:41:54,035 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M28 B 1 20.0\\r\\n'\n", + "2026-03-30 12:41:54,036 - pylabrobot - IO - [MT Scale] Received response: b'M28 B 1 20.0\\r\\n'\n", + "2026-03-30 12:41:54,052 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M28 A 2 19.5\\r\\n'\n", + "2026-03-30 12:41:54,053 - pylabrobot - IO - [MT Scale] Received response: b'M28 A 2 19.5\\r\\n'\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ - "Scale temperature: 19.9 C\n", + "Scale temperature: 20.0 C\n", "PASS: measure_temperature works - I0 correctly predicted M28 support\n" ] } @@ -1389,21 +1520,21 @@ }, { "cell_type": "code", - "execution_count": 24, + "execution_count": 27, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 12:08:16,449 - pylabrobot - IO - [MT Scale] Sent command: Z\n", - "2026-03-30 12:08:16,453 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'Z\\r\\n'\n", - "2026-03-30 12:08:16,693 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'Z A\\r\\n'\n", - "2026-03-30 12:08:16,694 - pylabrobot - IO - [MT Scale] Received response: b'Z A\\r\\n'\n", - "2026-03-30 12:08:16,694 - pylabrobot - IO - [MT Scale] Sent command: SI\n", - "2026-03-30 12:08:16,696 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", - "2026-03-30 12:08:16,741 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 12:08:16,749 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n" + "2026-03-30 12:41:58,382 - pylabrobot - IO - [MT Scale] Sent command: Z\n", + "2026-03-30 12:41:58,384 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'Z\\r\\n'\n", + "2026-03-30 12:41:58,735 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'Z A\\r\\n'\n", + "2026-03-30 12:41:58,736 - pylabrobot - IO - [MT Scale] Received response: b'Z A\\r\\n'\n", + "2026-03-30 12:41:58,737 - pylabrobot - IO - [MT Scale] Sent command: SI\n", + "2026-03-30 12:41:58,738 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", + "2026-03-30 12:41:58,767 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 12:41:58,769 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n" ] }, { @@ -1424,14 +1555,14 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 12:08:17,727 - pylabrobot - IO - [MT Scale] Sent command: T\n", - "2026-03-30 12:08:17,729 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'T\\r\\n'\n", - "2026-03-30 12:08:18,099 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'T S 0.00000 g\\r\\n'\n", - "2026-03-30 12:08:18,100 - pylabrobot - IO - [MT Scale] Received response: b'T S 0.00000 g\\r\\n'\n", - "2026-03-30 12:08:18,101 - pylabrobot - IO - [MT Scale] Sent command: TA\n", - "2026-03-30 12:08:18,103 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'TA\\r\\n'\n", - "2026-03-30 12:08:18,195 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'TA A 0.00000 g\\r\\n'\n", - "2026-03-30 12:08:18,196 - pylabrobot - IO - [MT Scale] Received response: b'TA A 0.00000 g\\r\\n'\n" + "2026-03-30 12:41:59,512 - pylabrobot - IO - [MT Scale] Sent command: T\n", + "2026-03-30 12:41:59,514 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'T\\r\\n'\n", + "2026-03-30 12:41:59,934 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'T S 0.00000 g\\r\\n'\n", + "2026-03-30 12:41:59,935 - pylabrobot - IO - [MT Scale] Received response: b'T S 0.00000 g\\r\\n'\n", + "2026-03-30 12:41:59,936 - pylabrobot - IO - [MT Scale] Sent command: TA\n", + "2026-03-30 12:41:59,938 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'TA\\r\\n'\n", + "2026-03-30 12:42:00,032 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'TA A 0.00000 g\\r\\n'\n", + "2026-03-30 12:42:00,033 - pylabrobot - IO - [MT Scale] Received response: b'TA A 0.00000 g\\r\\n'\n" ] }, { @@ -1448,7 +1579,7 @@ "traceback": [ "\u001b[31m---------------------------------------------------------------------------\u001b[39m", "\u001b[31mAssertionError\u001b[39m Traceback (most recent call last)", - "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[24]\u001b[39m\u001b[32m, line 12\u001b[39m\n\u001b[32m 10\u001b[39m tare = \u001b[38;5;28;01mawait\u001b[39;00m scale.request_tare_weight()\n\u001b[32m 11\u001b[39m \u001b[38;5;28mprint\u001b[39m(\u001b[33mf\u001b[39m\u001b[33m\"\u001b[39m\u001b[33mFrontend tare weight: \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mtare\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m g\u001b[39m\u001b[33m\"\u001b[39m)\n\u001b[32m---> \u001b[39m\u001b[32m12\u001b[39m \u001b[38;5;28;01massert\u001b[39;00m tare > \u001b[32m0\u001b[39m\n\u001b[32m 14\u001b[39m \u001b[38;5;66;03m# Read via frontend\u001b[39;00m\n\u001b[32m 15\u001b[39m w = \u001b[38;5;28;01mawait\u001b[39;00m scale.read_weight(timeout=\u001b[33m\"\u001b[39m\u001b[33mstable\u001b[39m\u001b[33m\"\u001b[39m)\n", + "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[27]\u001b[39m\u001b[32m, line 12\u001b[39m\n\u001b[32m 10\u001b[39m tare = \u001b[38;5;28;01mawait\u001b[39;00m scale.request_tare_weight()\n\u001b[32m 11\u001b[39m \u001b[38;5;28mprint\u001b[39m(\u001b[33mf\u001b[39m\u001b[33m\"\u001b[39m\u001b[33mFrontend tare weight: \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mtare\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m g\u001b[39m\u001b[33m\"\u001b[39m)\n\u001b[32m---> \u001b[39m\u001b[32m12\u001b[39m \u001b[38;5;28;01massert\u001b[39;00m tare > \u001b[32m0\u001b[39m\n\u001b[32m 14\u001b[39m \u001b[38;5;66;03m# Read via frontend\u001b[39;00m\n\u001b[32m 15\u001b[39m w = \u001b[38;5;28;01mawait\u001b[39;00m scale.read_weight(timeout=\u001b[33m\"\u001b[39m\u001b[33mstable\u001b[39m\u001b[33m\"\u001b[39m)\n", "\u001b[31mAssertionError\u001b[39m: " ] } @@ -1485,101 +1616,101 @@ }, { "cell_type": "code", - "execution_count": 25, + "execution_count": 28, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 12:08:20,929 - pylabrobot - IO - [MT Scale] Sent command: S\n", - "2026-03-30 12:08:20,930 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", - "2026-03-30 12:08:21,040 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 12:08:21,041 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 12:08:21,042 - pylabrobot - IO - [MT Scale] Sent command: S\n", - "2026-03-30 12:08:21,044 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", - "2026-03-30 12:08:21,136 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 12:08:21,137 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 12:08:21,138 - pylabrobot - IO - [MT Scale] Sent command: S\n", - "2026-03-30 12:08:21,139 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", - "2026-03-30 12:08:21,232 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 12:08:21,233 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 12:08:21,234 - pylabrobot - IO - [MT Scale] Sent command: S\n", - "2026-03-30 12:08:21,235 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", - "2026-03-30 12:08:21,328 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 12:08:21,329 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 12:08:21,330 - pylabrobot - IO - [MT Scale] Sent command: S\n", - "2026-03-30 12:08:21,332 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", - "2026-03-30 12:08:21,424 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 12:08:21,425 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 12:08:21,426 - pylabrobot - IO - [MT Scale] Sent command: S\n", - "2026-03-30 12:08:21,427 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", - "2026-03-30 12:08:21,520 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 12:08:21,521 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 12:08:21,522 - pylabrobot - IO - [MT Scale] Sent command: S\n", - "2026-03-30 12:08:21,524 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", - "2026-03-30 12:08:21,632 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 12:08:21,632 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 12:08:21,633 - pylabrobot - IO - [MT Scale] Sent command: S\n", - "2026-03-30 12:08:21,634 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", - "2026-03-30 12:08:21,727 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 12:08:21,729 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 12:08:21,731 - pylabrobot - IO - [MT Scale] Sent command: S\n", - "2026-03-30 12:08:21,733 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", - "2026-03-30 12:08:21,824 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 12:08:21,824 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 12:08:21,825 - pylabrobot - IO - [MT Scale] Sent command: S\n", - "2026-03-30 12:08:21,827 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", - "2026-03-30 12:08:21,920 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 12:08:21,921 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 12:08:21,922 - pylabrobot - IO - [MT Scale] Sent command: SI\n", - "2026-03-30 12:08:21,923 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", - "2026-03-30 12:08:21,952 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 12:08:21,953 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 12:08:21,957 - pylabrobot - IO - [MT Scale] Sent command: SI\n", - "2026-03-30 12:08:21,959 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", - "2026-03-30 12:08:22,001 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 12:08:22,002 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 12:08:22,009 - pylabrobot - IO - [MT Scale] Sent command: SI\n", - "2026-03-30 12:08:22,011 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", - "2026-03-30 12:08:22,048 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 12:08:22,049 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 12:08:22,049 - pylabrobot - IO - [MT Scale] Sent command: SI\n", - "2026-03-30 12:08:22,051 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", - "2026-03-30 12:08:22,080 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 12:08:22,081 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 12:08:22,082 - pylabrobot - IO - [MT Scale] Sent command: SI\n", - "2026-03-30 12:08:22,082 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", - "2026-03-30 12:08:22,112 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 12:08:22,114 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 12:08:22,115 - pylabrobot - IO - [MT Scale] Sent command: SI\n", - "2026-03-30 12:08:22,117 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", - "2026-03-30 12:08:22,160 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 12:08:22,162 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 12:08:22,166 - pylabrobot - IO - [MT Scale] Sent command: SI\n", - "2026-03-30 12:08:22,177 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", - "2026-03-30 12:08:22,225 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 12:08:22,227 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 12:08:22,229 - pylabrobot - IO - [MT Scale] Sent command: SI\n", - "2026-03-30 12:08:22,233 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", - "2026-03-30 12:08:22,272 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 12:08:22,274 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 12:08:22,275 - pylabrobot - IO - [MT Scale] Sent command: SI\n", - "2026-03-30 12:08:22,277 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", - "2026-03-30 12:08:22,321 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 12:08:22,324 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 12:08:22,325 - pylabrobot - IO - [MT Scale] Sent command: SI\n", - "2026-03-30 12:08:22,327 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", - "2026-03-30 12:08:22,367 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 12:08:22,368 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n" + "2026-03-30 12:42:01,466 - pylabrobot - IO - [MT Scale] Sent command: S\n", + "2026-03-30 12:42:01,471 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", + "2026-03-30 12:42:01,605 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 12:42:01,614 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 12:42:01,622 - pylabrobot - IO - [MT Scale] Sent command: S\n", + "2026-03-30 12:42:01,628 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", + "2026-03-30 12:42:01,693 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 12:42:01,694 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 12:42:01,695 - pylabrobot - IO - [MT Scale] Sent command: S\n", + "2026-03-30 12:42:01,699 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", + "2026-03-30 12:42:01,804 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 12:42:01,805 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 12:42:01,807 - pylabrobot - IO - [MT Scale] Sent command: S\n", + "2026-03-30 12:42:01,810 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", + "2026-03-30 12:42:01,900 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 12:42:01,901 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 12:42:01,903 - pylabrobot - IO - [MT Scale] Sent command: S\n", + "2026-03-30 12:42:01,904 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", + "2026-03-30 12:42:01,996 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 12:42:01,997 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 12:42:01,998 - pylabrobot - IO - [MT Scale] Sent command: S\n", + "2026-03-30 12:42:01,999 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", + "2026-03-30 12:42:02,093 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 12:42:02,093 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 12:42:02,095 - pylabrobot - IO - [MT Scale] Sent command: S\n", + "2026-03-30 12:42:02,096 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", + "2026-03-30 12:42:02,188 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 12:42:02,189 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 12:42:02,190 - pylabrobot - IO - [MT Scale] Sent command: S\n", + "2026-03-30 12:42:02,192 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", + "2026-03-30 12:42:02,286 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 12:42:02,288 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 12:42:02,289 - pylabrobot - IO - [MT Scale] Sent command: S\n", + "2026-03-30 12:42:02,293 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", + "2026-03-30 12:42:02,397 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 12:42:02,400 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 12:42:02,401 - pylabrobot - IO - [MT Scale] Sent command: S\n", + "2026-03-30 12:42:02,403 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", + "2026-03-30 12:42:02,492 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 12:42:02,493 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 12:42:02,494 - pylabrobot - IO - [MT Scale] Sent command: SI\n", + "2026-03-30 12:42:02,497 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", + "2026-03-30 12:42:02,540 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 12:42:02,541 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 12:42:02,542 - pylabrobot - IO - [MT Scale] Sent command: SI\n", + "2026-03-30 12:42:02,545 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", + "2026-03-30 12:42:02,588 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 12:42:02,591 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 12:42:02,592 - pylabrobot - IO - [MT Scale] Sent command: SI\n", + "2026-03-30 12:42:02,597 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", + "2026-03-30 12:42:02,636 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 12:42:02,637 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 12:42:02,638 - pylabrobot - IO - [MT Scale] Sent command: SI\n", + "2026-03-30 12:42:02,640 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", + "2026-03-30 12:42:02,686 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 12:42:02,691 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 12:42:02,700 - pylabrobot - IO - [MT Scale] Sent command: SI\n", + "2026-03-30 12:42:02,704 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", + "2026-03-30 12:42:02,733 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 12:42:02,735 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 12:42:02,736 - pylabrobot - IO - [MT Scale] Sent command: SI\n", + "2026-03-30 12:42:02,738 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", + "2026-03-30 12:42:02,779 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 12:42:02,780 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 12:42:02,782 - pylabrobot - IO - [MT Scale] Sent command: SI\n", + "2026-03-30 12:42:02,784 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", + "2026-03-30 12:42:02,814 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 12:42:02,815 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 12:42:02,816 - pylabrobot - IO - [MT Scale] Sent command: SI\n", + "2026-03-30 12:42:02,818 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", + "2026-03-30 12:42:02,859 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 12:42:02,860 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 12:42:02,862 - pylabrobot - IO - [MT Scale] Sent command: SI\n", + "2026-03-30 12:42:02,866 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", + "2026-03-30 12:42:02,907 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 12:42:02,908 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 12:42:02,922 - pylabrobot - IO - [MT Scale] Sent command: SI\n", + "2026-03-30 12:42:02,929 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", + "2026-03-30 12:42:02,971 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 12:42:02,973 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ - "Stable read: 99.29 +/- 6.59 ms\n", - "Immediate read: 44.73 +/- 9.15 ms\n" + "Stable read: 102.77 +/- 20.34 ms\n", + "Immediate read: 47.95 +/- 8.21 ms\n" ] } ], @@ -1618,21 +1749,27 @@ }, { "cell_type": "code", - "execution_count": 26, + "execution_count": 29, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 12:08:23,324 - pylabrobot - INFO - === Hardware validation ended ===\n" + "2026-03-30 12:42:03,097 - pylabrobot - INFO - === Hardware validation ended ===\n", + "2026-03-30 12:42:03,101 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] reset_input_buffer\n", + "2026-03-30 12:42:03,109 - pylabrobot - IO - [MT Scale] Sent command: @\n", + "2026-03-30 12:42:03,112 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'@\\r\\n'\n", + "2026-03-30 12:42:03,163 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I4 A \"B207696838\"\\r\\n'\n", + "2026-03-30 12:42:03,164 - pylabrobot - IO - [MT Scale] Received response: b'I4 A \"B207696838\"\\r\\n'\n", + "2026-03-30 12:42:03,167 - pylabrobot - INFO - [MT Scale] Disconnected from /dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ - "Log file: ./logs/hardware_validation/2026-03-30_12-07-26_validation.log\n" + "Log file: ./logs/hardware_validation/2026-03-30_12-40-59_validation.log\n" ] } ], @@ -1671,4 +1808,4 @@ }, "nbformat": 4, "nbformat_minor": 4 -} \ No newline at end of file +} From bb6331bfb4ed5aa5b47a4d16527ddc4bb07ddf0b Mon Sep 17 00:00:00 2001 From: Camillo Moschner Date: Mon, 30 Mar 2026 12:50:21 +0100 Subject: [PATCH 21/38] fix minimum parsing error --- pylabrobot/scales/mettler_toledo/backend.py | 41 +++++++++++++------ .../scales/mettler_toledo/mt_sics_commands.md | 27 ++++++------ 2 files changed, 40 insertions(+), 28 deletions(-) diff --git a/pylabrobot/scales/mettler_toledo/backend.py b/pylabrobot/scales/mettler_toledo/backend.py index ed119414805..a3f294b09e9 100644 --- a/pylabrobot/scales/mettler_toledo/backend.py +++ b/pylabrobot/scales/mettler_toledo/backend.py @@ -430,14 +430,17 @@ async def request_device_id(self) -> str: self._validate_response(responses[0], 3, "I10") return responses[0].data[0] - @requires_mt_sics_command("I10") - async def set_device_id(self, device_id: str) -> None: - """Set the user-assigned device identification string. (I10 command) - - Max 20 alphanumeric characters. Retained after @ cancel. - Useful for labeling individual scales in multi-device setups. - """ - await self.send_command(f'I10 "{device_id}"') + # WARNING: set_device_id writes to EEPROM and permanently changes the stored device name. + # Uncomment only if you need to relabel a scale in a multi-device setup. + # + # @requires_mt_sics_command("I10") + # async def set_device_id(self, device_id: str) -> None: + # """Set the user-assigned device identification string. (I10 command) + # + # Max 20 alphanumeric characters. Retained after @ cancel. + # Useful for labeling individual scales in multi-device setups. + # """ + # await self.send_command(f'I10 "{device_id}"') @requires_mt_sics_command("I11") async def request_model_designation(self) -> str: @@ -468,14 +471,26 @@ async def request_uptime(self) -> dict: Returns a dict with keys "days", "hours", "minutes", "seconds". Counts time since last power-on, including short interruptions. Not reset by @ cancel or restart. + + Some devices return a single value (total days) instead of the + full days/hours/minutes/seconds breakdown. """ responses = await self.send_command("I15") - self._validate_response(responses[0], 6, "I15") + self._validate_response(responses[0], 3, "I15") + data = responses[0].data + if len(data) >= 4: + return { + "days": int(data[0]), + "hours": int(data[1]), + "minutes": int(data[2]), + "seconds": int(data[3]), + } + # Single-value format (some devices return total days only) return { - "days": int(responses[0].data[0]), - "hours": int(responses[0].data[1]), - "minutes": int(responses[0].data[2]), - "seconds": int(responses[0].data[3]), + "days": int(data[0]), + "hours": 0, + "minutes": 0, + "seconds": 0, } @requires_mt_sics_command("DAT") diff --git a/pylabrobot/scales/mettler_toledo/mt_sics_commands.md b/pylabrobot/scales/mettler_toledo/mt_sics_commands.md index 179e0c65f98..db7e42061a2 100644 --- a/pylabrobot/scales/mettler_toledo/mt_sics_commands.md +++ b/pylabrobot/scales/mettler_toledo/mt_sics_commands.md @@ -30,9 +30,9 @@ Status key: | I0 | List all implemented commands + levels | 96 | DONE | yes | _request_supported_commands(). Queried during setup(). | | I1 | MT-SICS level and level versions | 97 | DONE | yes | Not used for gating - I0 is authoritative. | | I2 | Device data (type and capacity) | 98 | DONE | yes | request_device_type() and request_capacity(). Response is one quoted string parsed with shlex. | -| I3 | Software version and type definition | 99 | MED | yes | | +| I3 | Software version and type definition | 99 | DONE | yes | request_software_version(). Returns "1.10 18.6.4.1361.772" on test device. | | I4 | Serial number | 100 | DONE | yes | request_serial_number(). | -| I5 | Software material number | 101 | LOW | yes | | +| I5 | Software material number | 101 | DONE | yes | request_software_material_number(). Returns "11671158C" on test device. | | S | Stable weight value | 223 | DONE | yes | read_stable_weight(). | | SI | Weight value immediately | 225 | DONE | yes | read_weight_value_immediately(). | | SIR | Weight immediately + repeat | 232 | MED | yes | Continuous streaming. | @@ -63,10 +63,10 @@ Status key: | Command | Description | Spec Page | Status | WXS205SDU | Notes | |---------|------------------------------------------|-----------|--------|-----------|-------| -| I10 | Device identification | 102 | MED | yes | | -| I11 | Model designation | 103 | MED | yes | | -| I14 | Device information (detailed) | 104 | MED | yes | | -| I15 | Uptime | 106 | MED | yes | | +| I10 | Device identification | 102 | DONE | yes | request_device_id() (read). set_device_id() commented out (EEPROM write). | +| I11 | Model designation | 103 | DONE | yes | request_model_designation(). Returns "WXS205SDU" on test device. | +| I14 | Device information (detailed) | 104 | DONE | yes | request_device_info(). Multi-response with config, descriptions, SW IDs, serial numbers. | +| I15 | Uptime | 106 | DONE | yes | request_uptime(). WXS205SDU returns single value (days), not days/h/m/s. | | I16 | Date of next service | 107 | LOW | yes | | | I21 | Revision of assortment type tolerances | 108 | LOW | yes | | | I29 | Filter configuration | 111 | LOW | - | | @@ -177,9 +177,9 @@ Status key: | Command | Description | Spec Page | Status | WXS205SDU | Notes | |---------|------------------------------------------|-----------|--------|-----------|-------| -| DAT | Date | 53 | LOW | yes | | +| DAT | Date | 53 | DONE | yes | request_date(). | | DATI | Date and time | 54 | MED | - | | -| TIM | Time | 258 | LOW | yes | | +| TIM | Time | 258 | DONE | yes | request_time(). | ### Digital I/O @@ -269,13 +269,10 @@ Status key: - SIX1 (gross, net, tare in one call) - not available on WXS205SDU ### MED (useful but not urgent) -- I3 (software version) - available on WXS205SDU -- I11 (model designation) - available on WXS205SDU -- I14/I15 (device info, uptime) - available on WXS205SDU -- SIR/SR (continuous streaming) +- SIR/SR (continuous streaming) - available on WXS205SDU - SIS (net weight + status) - available on WXS205SDU -- C1/C3 (adjustment) - available on WXS205SDU +- C1/C3 (adjustment) - available on WXS205SDU, multi-response - M01/M02/M03 (weighing mode, environment, auto-zero) - available on WXS205SDU - M27 (adjustment history) - available on WXS205SDU -- DATI (date/time) - not on WXS205SDU -- RO1 (restart) - not on WXS205SDU +- SNR (stable weight + repeat on change) - available on WXS205SDU +- UPD (update rate) - available on WXS205SDU From a897afe6b15ddbe2abae7150ddb98ac997b0d9b9 Mon Sep 17 00:00:00 2001 From: Camillo Moschner Date: Mon, 30 Mar 2026 12:51:20 +0100 Subject: [PATCH 22/38] not understood parameter --- .../mettler_toledo/hardware_validation.ipynb | 1280 +++++------------ 1 file changed, 363 insertions(+), 917 deletions(-) diff --git a/pylabrobot/scales/mettler_toledo/hardware_validation.ipynb b/pylabrobot/scales/mettler_toledo/hardware_validation.ipynb index 8e43b1b5775..8d5afa546af 100644 --- a/pylabrobot/scales/mettler_toledo/hardware_validation.ipynb +++ b/pylabrobot/scales/mettler_toledo/hardware_validation.ipynb @@ -33,7 +33,7 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 12:40:59,695 - pylabrobot - INFO - === Hardware validation started ===\n" + "2026-03-30 12:50:44,638 - pylabrobot - INFO - === Hardware validation started ===\n" ] } ], @@ -65,155 +65,155 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 12:40:59,710 - pylabrobot.io.serial - INFO - Using explicitly provided port: /dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0 (for VID=1027, PID=24577)\n", - "2026-03-30 12:40:59,718 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] reset_input_buffer\n", - "2026-03-30 12:40:59,720 - pylabrobot - IO - [MT Scale] Sent command: @\n", - "2026-03-30 12:40:59,723 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'@\\r\\n'\n", - "2026-03-30 12:40:59,780 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I4 A \"B207696838\"\\r\\n'\n", - "2026-03-30 12:40:59,781 - pylabrobot - IO - [MT Scale] Received response: b'I4 A \"B207696838\"\\r\\n'\n", - "2026-03-30 12:40:59,781 - pylabrobot - IO - [MT Scale] Sent command: I0\n", - "2026-03-30 12:40:59,783 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I0\\r\\n'\n", - "2026-03-30 12:40:59,812 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I0\"\\r\\n'\n", - "2026-03-30 12:40:59,813 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I0\"\\r\\n'\n", - "2026-03-30 12:40:59,828 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I1\"\\r\\n'\n", - "2026-03-30 12:40:59,829 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I1\"\\r\\n'\n", - "2026-03-30 12:40:59,843 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I2\"\\r\\n'\n", - "2026-03-30 12:40:59,844 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I2\"\\r\\n'\n", - "2026-03-30 12:40:59,859 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I3\"\\r\\n'\n", - "2026-03-30 12:40:59,860 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I3\"\\r\\n'\n", - "2026-03-30 12:40:59,876 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I4\"\\r\\n'\n", - "2026-03-30 12:40:59,877 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I4\"\\r\\n'\n", - "2026-03-30 12:40:59,878 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I5\"\\r\\n'\n", - "2026-03-30 12:40:59,878 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I5\"\\r\\n'\n", - "2026-03-30 12:40:59,891 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"S\"\\r\\n'\n", - "2026-03-30 12:40:59,892 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"S\"\\r\\n'\n", - "2026-03-30 12:40:59,908 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"SI\"\\r\\n'\n", - "2026-03-30 12:40:59,908 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"SI\"\\r\\n'\n", - "2026-03-30 12:40:59,923 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"SIR\"\\r\\n'\n", - "2026-03-30 12:40:59,924 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"SIR\"\\r\\n'\n", - "2026-03-30 12:40:59,939 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"Z\"\\r\\n'\n", - "2026-03-30 12:40:59,940 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"Z\"\\r\\n'\n", - "2026-03-30 12:40:59,956 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"ZI\"\\r\\n'\n", - "2026-03-30 12:40:59,956 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"ZI\"\\r\\n'\n", - "2026-03-30 12:40:59,958 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"@\"\\r\\n'\n", - "2026-03-30 12:40:59,958 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"@\"\\r\\n'\n", - "2026-03-30 12:40:59,971 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"SR\"\\r\\n'\n", - "2026-03-30 12:40:59,972 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"SR\"\\r\\n'\n", - "2026-03-30 12:40:59,987 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"T\"\\r\\n'\n", - "2026-03-30 12:40:59,988 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"T\"\\r\\n'\n", - "2026-03-30 12:41:00,004 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"TA\"\\r\\n'\n", - "2026-03-30 12:41:00,004 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"TA\"\\r\\n'\n", - "2026-03-30 12:41:00,019 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"TAC\"\\r\\n'\n", - "2026-03-30 12:41:00,020 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"TAC\"\\r\\n'\n", - "2026-03-30 12:41:00,035 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"TI\"\\r\\n'\n", - "2026-03-30 12:41:00,036 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"TI\"\\r\\n'\n", - "2026-03-30 12:41:00,037 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C0\"\\r\\n'\n", - "2026-03-30 12:41:00,038 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"C0\"\\r\\n'\n", - "2026-03-30 12:41:00,052 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C1\"\\r\\n'\n", - "2026-03-30 12:41:00,052 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"C1\"\\r\\n'\n", - "2026-03-30 12:41:00,067 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C2\"\\r\\n'\n", - "2026-03-30 12:41:00,068 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"C2\"\\r\\n'\n", - "2026-03-30 12:41:00,083 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C3\"\\r\\n'\n", - "2026-03-30 12:41:00,084 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"C3\"\\r\\n'\n", - "2026-03-30 12:41:00,100 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"COM\"\\r\\n'\n", - "2026-03-30 12:41:00,101 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"COM\"\\r\\n'\n", - "2026-03-30 12:41:00,115 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"DAT\"\\r\\n'\n", - "2026-03-30 12:41:00,116 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"DAT\"\\r\\n'\n", - "2026-03-30 12:41:00,131 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I10\"\\r\\n'\n", - "2026-03-30 12:41:00,132 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I10\"\\r\\n'\n", - "2026-03-30 12:41:00,147 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I11\"\\r\\n'\n", - "2026-03-30 12:41:00,147 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I11\"\\r\\n'\n", - "2026-03-30 12:41:00,163 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I14\"\\r\\n'\n", - "2026-03-30 12:41:00,164 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I14\"\\r\\n'\n", - "2026-03-30 12:41:00,179 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I15\"\\r\\n'\n", - "2026-03-30 12:41:00,180 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I15\"\\r\\n'\n", - "2026-03-30 12:41:00,181 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I16\"\\r\\n'\n", - "2026-03-30 12:41:00,182 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I16\"\\r\\n'\n", - "2026-03-30 12:41:00,195 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I21\"\\r\\n'\n", - "2026-03-30 12:41:00,195 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I21\"\\r\\n'\n", - "2026-03-30 12:41:00,211 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I22\"\\r\\n'\n", - "2026-03-30 12:41:00,212 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I22\"\\r\\n'\n", - "2026-03-30 12:41:00,227 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I23\"\\r\\n'\n", - "2026-03-30 12:41:00,228 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I23\"\\r\\n'\n", - "2026-03-30 12:41:00,243 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I24\"\\r\\n'\n", - "2026-03-30 12:41:00,243 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I24\"\\r\\n'\n", - "2026-03-30 12:41:00,259 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I25\"\\r\\n'\n", - "2026-03-30 12:41:00,260 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I25\"\\r\\n'\n", - "2026-03-30 12:41:00,275 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I26\"\\r\\n'\n", - "2026-03-30 12:41:00,276 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I26\"\\r\\n'\n", - "2026-03-30 12:41:00,291 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M01\"\\r\\n'\n", - "2026-03-30 12:41:00,291 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M01\"\\r\\n'\n", - "2026-03-30 12:41:00,307 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M02\"\\r\\n'\n", - "2026-03-30 12:41:00,308 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M02\"\\r\\n'\n", - "2026-03-30 12:41:00,323 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M03\"\\r\\n'\n", - "2026-03-30 12:41:00,324 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M03\"\\r\\n'\n", - "2026-03-30 12:41:00,339 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M17\"\\r\\n'\n", - "2026-03-30 12:41:00,340 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M17\"\\r\\n'\n", - "2026-03-30 12:41:00,341 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M18\"\\r\\n'\n", - "2026-03-30 12:41:00,342 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M18\"\\r\\n'\n", - "2026-03-30 12:41:00,355 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M19\"\\r\\n'\n", - "2026-03-30 12:41:00,356 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M19\"\\r\\n'\n", - "2026-03-30 12:41:00,372 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M20\"\\r\\n'\n", - "2026-03-30 12:41:00,372 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M20\"\\r\\n'\n", - "2026-03-30 12:41:00,387 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M21\"\\r\\n'\n", - "2026-03-30 12:41:00,387 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M21\"\\r\\n'\n", - "2026-03-30 12:41:00,403 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M27\"\\r\\n'\n", - "2026-03-30 12:41:00,404 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M27\"\\r\\n'\n", - "2026-03-30 12:41:00,420 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M28\"\\r\\n'\n", - "2026-03-30 12:41:00,420 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M28\"\\r\\n'\n", - "2026-03-30 12:41:00,435 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M29\"\\r\\n'\n", - "2026-03-30 12:41:00,435 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M29\"\\r\\n'\n", - "2026-03-30 12:41:00,451 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M31\"\\r\\n'\n", - "2026-03-30 12:41:00,452 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M31\"\\r\\n'\n", - "2026-03-30 12:41:00,467 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M32\"\\r\\n'\n", - "2026-03-30 12:41:00,468 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M32\"\\r\\n'\n", - "2026-03-30 12:41:00,483 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M33\"\\r\\n'\n", - "2026-03-30 12:41:00,484 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M33\"\\r\\n'\n", - "2026-03-30 12:41:00,499 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M35\"\\r\\n'\n", - "2026-03-30 12:41:00,500 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M35\"\\r\\n'\n", - "2026-03-30 12:41:00,501 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"SIS\"\\r\\n'\n", - "2026-03-30 12:41:00,502 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"SIS\"\\r\\n'\n", - "2026-03-30 12:41:00,515 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"SNR\"\\r\\n'\n", - "2026-03-30 12:41:00,515 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"SNR\"\\r\\n'\n", - "2026-03-30 12:41:00,531 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TIM\"\\r\\n'\n", - "2026-03-30 12:41:00,532 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TIM\"\\r\\n'\n", - "2026-03-30 12:41:00,546 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST0\"\\r\\n'\n", - "2026-03-30 12:41:00,547 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TST0\"\\r\\n'\n", - "2026-03-30 12:41:00,563 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST1\"\\r\\n'\n", - "2026-03-30 12:41:00,563 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TST1\"\\r\\n'\n", - "2026-03-30 12:41:00,579 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST2\"\\r\\n'\n", - "2026-03-30 12:41:00,580 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TST2\"\\r\\n'\n", - "2026-03-30 12:41:00,595 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST3\"\\r\\n'\n", - "2026-03-30 12:41:00,595 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TST3\"\\r\\n'\n", - "2026-03-30 12:41:00,611 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"UPD\"\\r\\n'\n", - "2026-03-30 12:41:00,612 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"UPD\"\\r\\n'\n", - "2026-03-30 12:41:00,627 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"FCUT\"\\r\\n'\n", - "2026-03-30 12:41:00,628 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 3 \"FCUT\"\\r\\n'\n", - "2026-03-30 12:41:00,643 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"FSET\"\\r\\n'\n", - "2026-03-30 12:41:00,644 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 3 \"FSET\"\\r\\n'\n", - "2026-03-30 12:41:00,659 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"LST\"\\r\\n'\n", - "2026-03-30 12:41:00,659 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 3 \"LST\"\\r\\n'\n", - "2026-03-30 12:41:00,675 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"RDB\"\\r\\n'\n", - "2026-03-30 12:41:00,676 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 3 \"RDB\"\\r\\n'\n", - "2026-03-30 12:41:00,690 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 A 3 \"USTB\"\\r\\n'\n", - "2026-03-30 12:41:00,691 - pylabrobot - IO - [MT Scale] Received response: b'I0 A 3 \"USTB\"\\r\\n'\n", - "2026-03-30 12:41:00,692 - pylabrobot - IO - [MT Scale] Sent command: I2\n", - "2026-03-30 12:41:00,693 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I2\\r\\n'\n", - "2026-03-30 12:41:00,755 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", - "2026-03-30 12:41:00,756 - pylabrobot - IO - [MT Scale] Received response: b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", - "2026-03-30 12:41:00,756 - pylabrobot - IO - [MT Scale] Sent command: I2\n", - "2026-03-30 12:41:00,757 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I2\\r\\n'\n", - "2026-03-30 12:41:00,818 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", - "2026-03-30 12:41:00,819 - pylabrobot - IO - [MT Scale] Received response: b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", - "2026-03-30 12:41:00,819 - pylabrobot - INFO - [MT Scale] Connected to Mettler Toledo scale on /dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0\n", + "2026-03-30 12:50:44,655 - pylabrobot.io.serial - INFO - Using explicitly provided port: /dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0 (for VID=1027, PID=24577)\n", + "2026-03-30 12:50:44,663 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] reset_input_buffer\n", + "2026-03-30 12:50:44,670 - pylabrobot - IO - [MT Scale] Sent command: @\n", + "2026-03-30 12:50:44,672 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'@\\r\\n'\n", + "2026-03-30 12:50:44,725 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I4 A \"B207696838\"\\r\\n'\n", + "2026-03-30 12:50:44,726 - pylabrobot - IO - [MT Scale] Received response: b'I4 A \"B207696838\"\\r\\n'\n", + "2026-03-30 12:50:44,727 - pylabrobot - IO - [MT Scale] Sent command: I0\n", + "2026-03-30 12:50:44,729 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I0\\r\\n'\n", + "2026-03-30 12:50:44,755 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I0\"\\r\\n'\n", + "2026-03-30 12:50:44,756 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I0\"\\r\\n'\n", + "2026-03-30 12:50:44,771 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I1\"\\r\\n'\n", + "2026-03-30 12:50:44,773 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I1\"\\r\\n'\n", + "2026-03-30 12:50:44,787 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I2\"\\r\\n'\n", + "2026-03-30 12:50:44,789 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I2\"\\r\\n'\n", + "2026-03-30 12:50:44,807 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I3\"\\r\\n'\n", + "2026-03-30 12:50:44,811 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I3\"\\r\\n'\n", + "2026-03-30 12:50:44,819 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I4\"\\r\\n'\n", + "2026-03-30 12:50:44,820 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I4\"\\r\\n'\n", + "2026-03-30 12:50:44,835 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I5\"\\r\\n'\n", + "2026-03-30 12:50:44,837 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I5\"\\r\\n'\n", + "2026-03-30 12:50:44,841 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"S\"\\r\\n'\n", + "2026-03-30 12:50:44,844 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"S\"\\r\\n'\n", + "2026-03-30 12:50:44,851 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"SI\"\\r\\n'\n", + "2026-03-30 12:50:44,853 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"SI\"\\r\\n'\n", + "2026-03-30 12:50:44,867 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"SIR\"\\r\\n'\n", + "2026-03-30 12:50:44,869 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"SIR\"\\r\\n'\n", + "2026-03-30 12:50:44,882 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"Z\"\\r\\n'\n", + "2026-03-30 12:50:44,884 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"Z\"\\r\\n'\n", + "2026-03-30 12:50:44,899 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"ZI\"\\r\\n'\n", + "2026-03-30 12:50:44,900 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"ZI\"\\r\\n'\n", + "2026-03-30 12:50:44,902 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"@\"\\r\\n'\n", + "2026-03-30 12:50:44,904 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"@\"\\r\\n'\n", + "2026-03-30 12:50:44,917 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"SR\"\\r\\n'\n", + "2026-03-30 12:50:44,926 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"SR\"\\r\\n'\n", + "2026-03-30 12:50:44,931 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"T\"\\r\\n'\n", + "2026-03-30 12:50:44,932 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"T\"\\r\\n'\n", + "2026-03-30 12:50:44,947 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"TA\"\\r\\n'\n", + "2026-03-30 12:50:44,948 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"TA\"\\r\\n'\n", + "2026-03-30 12:50:44,963 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"TAC\"\\r\\n'\n", + "2026-03-30 12:50:44,964 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"TAC\"\\r\\n'\n", + "2026-03-30 12:50:44,979 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"TI\"\\r\\n'\n", + "2026-03-30 12:50:44,980 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"TI\"\\r\\n'\n", + "2026-03-30 12:50:44,995 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C0\"\\r\\n'\n", + "2026-03-30 12:50:44,996 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"C0\"\\r\\n'\n", + "2026-03-30 12:50:44,997 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C1\"\\r\\n'\n", + "2026-03-30 12:50:44,999 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"C1\"\\r\\n'\n", + "2026-03-30 12:50:45,013 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C2\"\\r\\n'\n", + "2026-03-30 12:50:45,014 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"C2\"\\r\\n'\n", + "2026-03-30 12:50:45,026 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C3\"\\r\\n'\n", + "2026-03-30 12:50:45,030 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"C3\"\\r\\n'\n", + "2026-03-30 12:50:45,049 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"COM\"\\r\\n'\n", + "2026-03-30 12:50:45,050 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"COM\"\\r\\n'\n", + "2026-03-30 12:50:45,059 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"DAT\"\\r\\n'\n", + "2026-03-30 12:50:45,061 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"DAT\"\\r\\n'\n", + "2026-03-30 12:50:45,075 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I10\"\\r\\n'\n", + "2026-03-30 12:50:45,076 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I10\"\\r\\n'\n", + "2026-03-30 12:50:45,091 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I11\"\\r\\n'\n", + "2026-03-30 12:50:45,094 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I11\"\\r\\n'\n", + "2026-03-30 12:50:45,107 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I14\"\\r\\n'\n", + "2026-03-30 12:50:45,108 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I14\"\\r\\n'\n", + "2026-03-30 12:50:45,125 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I15\"\\r\\n'\n", + "2026-03-30 12:50:45,126 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I15\"\\r\\n'\n", + "2026-03-30 12:50:45,128 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I16\"\\r\\n'\n", + "2026-03-30 12:50:45,128 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I16\"\\r\\n'\n", + "2026-03-30 12:50:45,139 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I21\"\\r\\n'\n", + "2026-03-30 12:50:45,140 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I21\"\\r\\n'\n", + "2026-03-30 12:50:45,155 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I22\"\\r\\n'\n", + "2026-03-30 12:50:45,161 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I22\"\\r\\n'\n", + "2026-03-30 12:50:45,170 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I23\"\\r\\n'\n", + "2026-03-30 12:50:45,172 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I23\"\\r\\n'\n", + "2026-03-30 12:50:45,189 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I24\"\\r\\n'\n", + "2026-03-30 12:50:45,190 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I24\"\\r\\n'\n", + "2026-03-30 12:50:45,203 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I25\"\\r\\n'\n", + "2026-03-30 12:50:45,204 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I25\"\\r\\n'\n", + "2026-03-30 12:50:45,218 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I26\"\\r\\n'\n", + "2026-03-30 12:50:45,220 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I26\"\\r\\n'\n", + "2026-03-30 12:50:45,235 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M01\"\\r\\n'\n", + "2026-03-30 12:50:45,237 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M01\"\\r\\n'\n", + "2026-03-30 12:50:45,254 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M02\"\\r\\n'\n", + "2026-03-30 12:50:45,255 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M02\"\\r\\n'\n", + "2026-03-30 12:50:45,268 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M03\"\\r\\n'\n", + "2026-03-30 12:50:45,271 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M03\"\\r\\n'\n", + "2026-03-30 12:50:45,282 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M17\"\\r\\n'\n", + "2026-03-30 12:50:45,294 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M17\"\\r\\n'\n", + "2026-03-30 12:50:45,299 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M18\"\\r\\n'\n", + "2026-03-30 12:50:45,300 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M18\"\\r\\n'\n", + "2026-03-30 12:50:45,303 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M19\"\\r\\n'\n", + "2026-03-30 12:50:45,304 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M19\"\\r\\n'\n", + "2026-03-30 12:50:45,316 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M20\"\\r\\n'\n", + "2026-03-30 12:50:45,323 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M20\"\\r\\n'\n", + "2026-03-30 12:50:45,331 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M21\"\\r\\n'\n", + "2026-03-30 12:50:45,333 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M21\"\\r\\n'\n", + "2026-03-30 12:50:45,346 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M27\"\\r\\n'\n", + "2026-03-30 12:50:45,348 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M27\"\\r\\n'\n", + "2026-03-30 12:50:45,365 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M28\"\\r\\n'\n", + "2026-03-30 12:50:45,368 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M28\"\\r\\n'\n", + "2026-03-30 12:50:45,378 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M29\"\\r\\n'\n", + "2026-03-30 12:50:45,379 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M29\"\\r\\n'\n", + "2026-03-30 12:50:45,395 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M31\"\\r\\n'\n", + "2026-03-30 12:50:45,396 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M31\"\\r\\n'\n", + "2026-03-30 12:50:45,411 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M32\"\\r\\n'\n", + "2026-03-30 12:50:45,412 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M32\"\\r\\n'\n", + "2026-03-30 12:50:45,426 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M33\"\\r\\n'\n", + "2026-03-30 12:50:45,427 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M33\"\\r\\n'\n", + "2026-03-30 12:50:45,443 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M35\"\\r\\n'\n", + "2026-03-30 12:50:45,444 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M35\"\\r\\n'\n", + "2026-03-30 12:50:45,460 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"SIS\"\\r\\n'\n", + "2026-03-30 12:50:45,462 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"SIS\"\\r\\n'\n", + "2026-03-30 12:50:45,474 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"SNR\"\\r\\n'\n", + "2026-03-30 12:50:45,475 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"SNR\"\\r\\n'\n", + "2026-03-30 12:50:45,476 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TIM\"\\r\\n'\n", + "2026-03-30 12:50:45,477 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TIM\"\\r\\n'\n", + "2026-03-30 12:50:45,493 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST0\"\\r\\n'\n", + "2026-03-30 12:50:45,494 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TST0\"\\r\\n'\n", + "2026-03-30 12:50:45,507 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST1\"\\r\\n'\n", + "2026-03-30 12:50:45,508 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TST1\"\\r\\n'\n", + "2026-03-30 12:50:45,523 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST2\"\\r\\n'\n", + "2026-03-30 12:50:45,523 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TST2\"\\r\\n'\n", + "2026-03-30 12:50:45,538 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST3\"\\r\\n'\n", + "2026-03-30 12:50:45,539 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TST3\"\\r\\n'\n", + "2026-03-30 12:50:45,555 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"UPD\"\\r\\n'\n", + "2026-03-30 12:50:45,558 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"UPD\"\\r\\n'\n", + "2026-03-30 12:50:45,570 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"FCUT\"\\r\\n'\n", + "2026-03-30 12:50:45,572 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 3 \"FCUT\"\\r\\n'\n", + "2026-03-30 12:50:45,587 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"FSET\"\\r\\n'\n", + "2026-03-30 12:50:45,589 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 3 \"FSET\"\\r\\n'\n", + "2026-03-30 12:50:45,602 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"LST\"\\r\\n'\n", + "2026-03-30 12:50:45,603 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 3 \"LST\"\\r\\n'\n", + "2026-03-30 12:50:45,618 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"RDB\"\\r\\n'\n", + "2026-03-30 12:50:45,619 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 3 \"RDB\"\\r\\n'\n", + "2026-03-30 12:50:45,635 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 A 3 \"USTB\"\\r\\n'\n", + "2026-03-30 12:50:45,638 - pylabrobot - IO - [MT Scale] Received response: b'I0 A 3 \"USTB\"\\r\\n'\n", + "2026-03-30 12:50:45,640 - pylabrobot - IO - [MT Scale] Sent command: I2\n", + "2026-03-30 12:50:45,643 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I2\\r\\n'\n", + "2026-03-30 12:50:45,699 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", + "2026-03-30 12:50:45,700 - pylabrobot - IO - [MT Scale] Received response: b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", + "2026-03-30 12:50:45,703 - pylabrobot - IO - [MT Scale] Sent command: I2\n", + "2026-03-30 12:50:45,710 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I2\\r\\n'\n", + "2026-03-30 12:50:45,762 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", + "2026-03-30 12:50:45,762 - pylabrobot - IO - [MT Scale] Received response: b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", + "2026-03-30 12:50:45,763 - pylabrobot - INFO - [MT Scale] Connected to Mettler Toledo scale on /dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0\n", "Device type: WXS205SDU WXA-Bridge\n", "Serial number: B207696838\n", "Capacity: 220.0 g\n", "Supported commands: ['@', 'C0', 'C1', 'C2', 'C3', 'COM', 'DAT', 'FCUT', 'FSET', 'I0', 'I1', 'I10', 'I11', 'I14', 'I15', 'I16', 'I2', 'I21', 'I22', 'I23', 'I24', 'I25', 'I26', 'I3', 'I4', 'I5', 'LST', 'M01', 'M02', 'M03', 'M17', 'M18', 'M19', 'M20', 'M21', 'M27', 'M28', 'M29', 'M31', 'M32', 'M33', 'M35', 'RDB', 'S', 'SI', 'SIR', 'SIS', 'SNR', 'SR', 'T', 'TA', 'TAC', 'TI', 'TIM', 'TST0', 'TST1', 'TST2', 'TST3', 'UPD', 'USTB', 'Z', 'ZI']\n", - "2026-03-30 12:41:00,820 - pylabrobot - IO - [MT Scale] Sent command: M21 0 0\n", - "2026-03-30 12:41:00,821 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'M21 0 0\\r\\n'\n", - "2026-03-30 12:41:00,851 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M21 A\\r\\n'\n", - "2026-03-30 12:41:00,852 - pylabrobot - IO - [MT Scale] Received response: b'M21 A\\r\\n'\n" + "2026-03-30 12:50:45,764 - pylabrobot - IO - [MT Scale] Sent command: M21 0 0\n", + "2026-03-30 12:50:45,768 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'M21 0 0\\r\\n'\n", + "2026-03-30 12:50:45,795 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M21 A\\r\\n'\n", + "2026-03-30 12:50:45,796 - pylabrobot - IO - [MT Scale] Received response: b'M21 A\\r\\n'\n" ] } ], @@ -282,7 +282,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "40 methods available on this device:\n", + "39 methods available on this device:\n", " cancel\n", " cancel_all\n", " clear_tare\n", @@ -309,7 +309,6 @@ " request_uptime\n", " send_command\n", " serialize\n", - " set_device_id\n", " set_display_text\n", " set_host_unit_grams\n", " set_weight_display\n", @@ -352,132 +351,132 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 12:41:00,902 - pylabrobot - IO - [MT Scale] Sent command: I0\n", - "2026-03-30 12:41:00,912 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I0\\r\\n'\n", - "2026-03-30 12:41:00,948 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I0\"\\r\\n'\n", - "2026-03-30 12:41:00,951 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I0\"\\r\\n'\n", - "2026-03-30 12:41:00,954 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I1\"\\r\\n'\n", - "2026-03-30 12:41:00,959 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I1\"\\r\\n'\n", - "2026-03-30 12:41:00,965 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I2\"\\r\\n'\n", - "2026-03-30 12:41:00,970 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I2\"\\r\\n'\n", - "2026-03-30 12:41:00,981 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I3\"\\r\\n'\n", - "2026-03-30 12:41:00,984 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I3\"\\r\\n'\n", - "2026-03-30 12:41:00,995 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I4\"\\r\\n'\n", - "2026-03-30 12:41:00,996 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I4\"\\r\\n'\n", - "2026-03-30 12:41:01,010 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I5\"\\r\\n'\n", - "2026-03-30 12:41:01,011 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I5\"\\r\\n'\n", - "2026-03-30 12:41:01,026 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"S\"\\r\\n'\n", - "2026-03-30 12:41:01,027 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"S\"\\r\\n'\n", - "2026-03-30 12:41:01,043 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"SI\"\\r\\n'\n", - "2026-03-30 12:41:01,044 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"SI\"\\r\\n'\n", - "2026-03-30 12:41:01,045 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"SIR\"\\r\\n'\n", - "2026-03-30 12:41:01,046 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"SIR\"\\r\\n'\n", - "2026-03-30 12:41:01,058 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"Z\"\\r\\n'\n", - "2026-03-30 12:41:01,059 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"Z\"\\r\\n'\n", - "2026-03-30 12:41:01,075 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"ZI\"\\r\\n'\n", - "2026-03-30 12:41:01,075 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"ZI\"\\r\\n'\n", - "2026-03-30 12:41:01,091 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"@\"\\r\\n'\n", - "2026-03-30 12:41:01,092 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"@\"\\r\\n'\n", - "2026-03-30 12:41:01,106 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"SR\"\\r\\n'\n", - "2026-03-30 12:41:01,107 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"SR\"\\r\\n'\n", - "2026-03-30 12:41:01,109 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"T\"\\r\\n'\n", - "2026-03-30 12:41:01,110 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"T\"\\r\\n'\n", - "2026-03-30 12:41:01,123 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"TA\"\\r\\n'\n", - "2026-03-30 12:41:01,124 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"TA\"\\r\\n'\n", - "2026-03-30 12:41:01,139 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"TAC\"\\r\\n'\n", - "2026-03-30 12:41:01,140 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"TAC\"\\r\\n'\n", - "2026-03-30 12:41:01,155 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"TI\"\\r\\n'\n", - "2026-03-30 12:41:01,155 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"TI\"\\r\\n'\n", - "2026-03-30 12:41:01,171 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C0\"\\r\\n'\n", - "2026-03-30 12:41:01,172 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"C0\"\\r\\n'\n", - "2026-03-30 12:41:01,187 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C1\"\\r\\n'\n", - "2026-03-30 12:41:01,188 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"C1\"\\r\\n'\n", - "2026-03-30 12:41:01,202 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C2\"\\r\\n'\n", - "2026-03-30 12:41:01,203 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"C2\"\\r\\n'\n", - "2026-03-30 12:41:01,205 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C3\"\\r\\n'\n", - "2026-03-30 12:41:01,206 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"C3\"\\r\\n'\n", - "2026-03-30 12:41:01,219 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"COM\"\\r\\n'\n", - "2026-03-30 12:41:01,220 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"COM\"\\r\\n'\n", - "2026-03-30 12:41:01,234 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"DAT\"\\r\\n'\n", - "2026-03-30 12:41:01,235 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"DAT\"\\r\\n'\n", - "2026-03-30 12:41:01,250 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I10\"\\r\\n'\n", - "2026-03-30 12:41:01,251 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I10\"\\r\\n'\n", - "2026-03-30 12:41:01,267 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I11\"\\r\\n'\n", - "2026-03-30 12:41:01,268 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I11\"\\r\\n'\n", - "2026-03-30 12:41:01,282 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I14\"\\r\\n'\n", - "2026-03-30 12:41:01,283 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I14\"\\r\\n'\n", - "2026-03-30 12:41:01,298 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I15\"\\r\\n'\n", - "2026-03-30 12:41:01,299 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I15\"\\r\\n'\n", - "2026-03-30 12:41:01,315 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I16\"\\r\\n'\n", - "2026-03-30 12:41:01,315 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I16\"\\r\\n'\n", - "2026-03-30 12:41:01,330 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I21\"\\r\\n'\n", - "2026-03-30 12:41:01,331 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I21\"\\r\\n'\n", - "2026-03-30 12:41:01,346 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I22\"\\r\\n'\n", - "2026-03-30 12:41:01,347 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I22\"\\r\\n'\n", - "2026-03-30 12:41:01,362 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I23\"\\r\\n'\n", - "2026-03-30 12:41:01,363 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I23\"\\r\\n'\n", - "2026-03-30 12:41:01,378 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I24\"\\r\\n'\n", - "2026-03-30 12:41:01,379 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I24\"\\r\\n'\n", - "2026-03-30 12:41:01,381 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I25\"\\r\\n'\n", - "2026-03-30 12:41:01,382 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I25\"\\r\\n'\n", - "2026-03-30 12:41:01,395 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I26\"\\r\\n'\n", - "2026-03-30 12:41:01,395 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I26\"\\r\\n'\n", - "2026-03-30 12:41:01,410 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M01\"\\r\\n'\n", - "2026-03-30 12:41:01,411 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M01\"\\r\\n'\n", - "2026-03-30 12:41:01,426 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M02\"\\r\\n'\n", - "2026-03-30 12:41:01,427 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M02\"\\r\\n'\n", - "2026-03-30 12:41:01,443 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M03\"\\r\\n'\n", - "2026-03-30 12:41:01,443 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M03\"\\r\\n'\n", - "2026-03-30 12:41:01,458 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M17\"\\r\\n'\n", - "2026-03-30 12:41:01,459 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M17\"\\r\\n'\n", - "2026-03-30 12:41:01,474 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M18\"\\r\\n'\n", - "2026-03-30 12:41:01,475 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M18\"\\r\\n'\n", - "2026-03-30 12:41:01,491 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M19\"\\r\\n'\n", - "2026-03-30 12:41:01,491 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M19\"\\r\\n'\n", - "2026-03-30 12:41:01,506 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M20\"\\r\\n'\n", - "2026-03-30 12:41:01,507 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M20\"\\r\\n'\n", - "2026-03-30 12:41:01,522 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M21\"\\r\\n'\n", - "2026-03-30 12:41:01,523 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M21\"\\r\\n'\n", - "2026-03-30 12:41:01,539 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M27\"\\r\\n'\n", - "2026-03-30 12:41:01,539 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M27\"\\r\\n'\n", - "2026-03-30 12:41:01,541 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M28\"\\r\\n'\n", - "2026-03-30 12:41:01,542 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M28\"\\r\\n'\n", - "2026-03-30 12:41:01,554 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M29\"\\r\\n'\n", - "2026-03-30 12:41:01,555 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M29\"\\r\\n'\n", - "2026-03-30 12:41:01,570 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M31\"\\r\\n'\n", - "2026-03-30 12:41:01,571 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M31\"\\r\\n'\n", - "2026-03-30 12:41:01,586 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M32\"\\r\\n'\n", - "2026-03-30 12:41:01,587 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M32\"\\r\\n'\n", - "2026-03-30 12:41:01,602 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M33\"\\r\\n'\n", - "2026-03-30 12:41:01,603 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M33\"\\r\\n'\n", - "2026-03-30 12:41:01,618 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M35\"\\r\\n'\n", - "2026-03-30 12:41:01,619 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M35\"\\r\\n'\n", - "2026-03-30 12:41:01,634 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"SIS\"\\r\\n'\n", - "2026-03-30 12:41:01,635 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"SIS\"\\r\\n'\n", - "2026-03-30 12:41:01,650 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"SNR\"\\r\\n'\n", - "2026-03-30 12:41:01,651 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"SNR\"\\r\\n'\n", - "2026-03-30 12:41:01,666 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TIM\"\\r\\n'\n", - "2026-03-30 12:41:01,667 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TIM\"\\r\\n'\n", - "2026-03-30 12:41:01,682 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST0\"\\r\\n'\n", - "2026-03-30 12:41:01,683 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TST0\"\\r\\n'\n", - "2026-03-30 12:41:01,698 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST1\"\\r\\n'\n", - "2026-03-30 12:41:01,699 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TST1\"\\r\\n'\n", - "2026-03-30 12:41:01,713 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST2\"\\r\\n'\n", - "2026-03-30 12:41:01,714 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TST2\"\\r\\n'\n", - "2026-03-30 12:41:01,730 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST3\"\\r\\n'\n", - "2026-03-30 12:41:01,731 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TST3\"\\r\\n'\n", - "2026-03-30 12:41:01,746 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"UPD\"\\r\\n'\n", - "2026-03-30 12:41:01,747 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"UPD\"\\r\\n'\n", - "2026-03-30 12:41:01,762 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"FCUT\"\\r\\n'\n", - "2026-03-30 12:41:01,762 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 3 \"FCUT\"\\r\\n'\n", - "2026-03-30 12:41:01,778 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"FSET\"\\r\\n'\n", - "2026-03-30 12:41:01,779 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 3 \"FSET\"\\r\\n'\n", - "2026-03-30 12:41:01,780 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"LST\"\\r\\n'\n", - "2026-03-30 12:41:01,781 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 3 \"LST\"\\r\\n'\n", - "2026-03-30 12:41:01,794 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"RDB\"\\r\\n'\n", - "2026-03-30 12:41:01,795 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 3 \"RDB\"\\r\\n'\n", - "2026-03-30 12:41:01,810 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 A 3 \"USTB\"\\r\\n'\n", - "2026-03-30 12:41:01,811 - pylabrobot - IO - [MT Scale] Received response: b'I0 A 3 \"USTB\"\\r\\n'\n" + "2026-03-30 12:50:45,849 - pylabrobot - IO - [MT Scale] Sent command: I0\n", + "2026-03-30 12:50:45,855 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I0\\r\\n'\n", + "2026-03-30 12:50:45,894 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I0\"\\r\\n'\n", + "2026-03-30 12:50:45,897 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I0\"\\r\\n'\n", + "2026-03-30 12:50:45,902 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I1\"\\r\\n'\n", + "2026-03-30 12:50:45,905 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I1\"\\r\\n'\n", + "2026-03-30 12:50:45,911 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I2\"\\r\\n'\n", + "2026-03-30 12:50:45,913 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I2\"\\r\\n'\n", + "2026-03-30 12:50:45,922 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I3\"\\r\\n'\n", + "2026-03-30 12:50:45,923 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I3\"\\r\\n'\n", + "2026-03-30 12:50:45,938 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I4\"\\r\\n'\n", + "2026-03-30 12:50:45,940 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I4\"\\r\\n'\n", + "2026-03-30 12:50:45,954 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I5\"\\r\\n'\n", + "2026-03-30 12:50:45,955 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I5\"\\r\\n'\n", + "2026-03-30 12:50:45,970 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"S\"\\r\\n'\n", + "2026-03-30 12:50:45,971 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"S\"\\r\\n'\n", + "2026-03-30 12:50:45,976 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"SI\"\\r\\n'\n", + "2026-03-30 12:50:45,980 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"SI\"\\r\\n'\n", + "2026-03-30 12:50:45,987 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"SIR\"\\r\\n'\n", + "2026-03-30 12:50:45,988 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"SIR\"\\r\\n'\n", + "2026-03-30 12:50:46,002 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"Z\"\\r\\n'\n", + "2026-03-30 12:50:46,005 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"Z\"\\r\\n'\n", + "2026-03-30 12:50:46,018 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"ZI\"\\r\\n'\n", + "2026-03-30 12:50:46,020 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"ZI\"\\r\\n'\n", + "2026-03-30 12:50:46,035 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"@\"\\r\\n'\n", + "2026-03-30 12:50:46,036 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"@\"\\r\\n'\n", + "2026-03-30 12:50:46,050 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"SR\"\\r\\n'\n", + "2026-03-30 12:50:46,052 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"SR\"\\r\\n'\n", + "2026-03-30 12:50:46,054 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"T\"\\r\\n'\n", + "2026-03-30 12:50:46,057 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"T\"\\r\\n'\n", + "2026-03-30 12:50:46,066 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"TA\"\\r\\n'\n", + "2026-03-30 12:50:46,067 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"TA\"\\r\\n'\n", + "2026-03-30 12:50:46,082 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"TAC\"\\r\\n'\n", + "2026-03-30 12:50:46,085 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"TAC\"\\r\\n'\n", + "2026-03-30 12:50:46,097 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"TI\"\\r\\n'\n", + "2026-03-30 12:50:46,098 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"TI\"\\r\\n'\n", + "2026-03-30 12:50:46,114 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C0\"\\r\\n'\n", + "2026-03-30 12:50:46,115 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"C0\"\\r\\n'\n", + "2026-03-30 12:50:46,130 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C1\"\\r\\n'\n", + "2026-03-30 12:50:46,131 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"C1\"\\r\\n'\n", + "2026-03-30 12:50:46,147 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C2\"\\r\\n'\n", + "2026-03-30 12:50:46,148 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"C2\"\\r\\n'\n", + "2026-03-30 12:50:46,151 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C3\"\\r\\n'\n", + "2026-03-30 12:50:46,152 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"C3\"\\r\\n'\n", + "2026-03-30 12:50:46,162 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"COM\"\\r\\n'\n", + "2026-03-30 12:50:46,163 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"COM\"\\r\\n'\n", + "2026-03-30 12:50:46,177 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"DAT\"\\r\\n'\n", + "2026-03-30 12:50:46,178 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"DAT\"\\r\\n'\n", + "2026-03-30 12:50:46,195 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I10\"\\r\\n'\n", + "2026-03-30 12:50:46,196 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I10\"\\r\\n'\n", + "2026-03-30 12:50:46,210 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I11\"\\r\\n'\n", + "2026-03-30 12:50:46,212 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I11\"\\r\\n'\n", + "2026-03-30 12:50:46,226 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I14\"\\r\\n'\n", + "2026-03-30 12:50:46,227 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I14\"\\r\\n'\n", + "2026-03-30 12:50:46,242 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I15\"\\r\\n'\n", + "2026-03-30 12:50:46,244 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I15\"\\r\\n'\n", + "2026-03-30 12:50:46,258 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I16\"\\r\\n'\n", + "2026-03-30 12:50:46,260 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I16\"\\r\\n'\n", + "2026-03-30 12:50:46,274 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I21\"\\r\\n'\n", + "2026-03-30 12:50:46,274 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I21\"\\r\\n'\n", + "2026-03-30 12:50:46,289 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I22\"\\r\\n'\n", + "2026-03-30 12:50:46,290 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I22\"\\r\\n'\n", + "2026-03-30 12:50:46,305 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I23\"\\r\\n'\n", + "2026-03-30 12:50:46,306 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I23\"\\r\\n'\n", + "2026-03-30 12:50:46,307 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I24\"\\r\\n'\n", + "2026-03-30 12:50:46,308 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I24\"\\r\\n'\n", + "2026-03-30 12:50:46,322 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I25\"\\r\\n'\n", + "2026-03-30 12:50:46,323 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I25\"\\r\\n'\n", + "2026-03-30 12:50:46,337 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I26\"\\r\\n'\n", + "2026-03-30 12:50:46,338 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I26\"\\r\\n'\n", + "2026-03-30 12:50:46,353 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M01\"\\r\\n'\n", + "2026-03-30 12:50:46,354 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M01\"\\r\\n'\n", + "2026-03-30 12:50:46,370 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M02\"\\r\\n'\n", + "2026-03-30 12:50:46,370 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M02\"\\r\\n'\n", + "2026-03-30 12:50:46,385 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M03\"\\r\\n'\n", + "2026-03-30 12:50:46,386 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M03\"\\r\\n'\n", + "2026-03-30 12:50:46,402 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M17\"\\r\\n'\n", + "2026-03-30 12:50:46,403 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M17\"\\r\\n'\n", + "2026-03-30 12:50:46,417 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M18\"\\r\\n'\n", + "2026-03-30 12:50:46,418 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M18\"\\r\\n'\n", + "2026-03-30 12:50:46,433 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M19\"\\r\\n'\n", + "2026-03-30 12:50:46,434 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M19\"\\r\\n'\n", + "2026-03-30 12:50:46,450 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M20\"\\r\\n'\n", + "2026-03-30 12:50:46,451 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M20\"\\r\\n'\n", + "2026-03-30 12:50:46,465 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M21\"\\r\\n'\n", + "2026-03-30 12:50:46,466 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M21\"\\r\\n'\n", + "2026-03-30 12:50:46,481 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M27\"\\r\\n'\n", + "2026-03-30 12:50:46,482 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M27\"\\r\\n'\n", + "2026-03-30 12:50:46,484 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M28\"\\r\\n'\n", + "2026-03-30 12:50:46,485 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M28\"\\r\\n'\n", + "2026-03-30 12:50:46,498 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M29\"\\r\\n'\n", + "2026-03-30 12:50:46,499 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M29\"\\r\\n'\n", + "2026-03-30 12:50:46,513 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M31\"\\r\\n'\n", + "2026-03-30 12:50:46,514 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M31\"\\r\\n'\n", + "2026-03-30 12:50:46,529 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M32\"\\r\\n'\n", + "2026-03-30 12:50:46,530 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M32\"\\r\\n'\n", + "2026-03-30 12:50:46,546 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M33\"\\r\\n'\n", + "2026-03-30 12:50:46,547 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M33\"\\r\\n'\n", + "2026-03-30 12:50:46,561 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M35\"\\r\\n'\n", + "2026-03-30 12:50:46,562 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M35\"\\r\\n'\n", + "2026-03-30 12:50:46,577 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"SIS\"\\r\\n'\n", + "2026-03-30 12:50:46,578 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"SIS\"\\r\\n'\n", + "2026-03-30 12:50:46,594 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"SNR\"\\r\\n'\n", + "2026-03-30 12:50:46,595 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"SNR\"\\r\\n'\n", + "2026-03-30 12:50:46,609 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TIM\"\\r\\n'\n", + "2026-03-30 12:50:46,610 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TIM\"\\r\\n'\n", + "2026-03-30 12:50:46,626 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST0\"\\r\\n'\n", + "2026-03-30 12:50:46,626 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TST0\"\\r\\n'\n", + "2026-03-30 12:50:46,641 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST1\"\\r\\n'\n", + "2026-03-30 12:50:46,642 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TST1\"\\r\\n'\n", + "2026-03-30 12:50:46,657 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST2\"\\r\\n'\n", + "2026-03-30 12:50:46,659 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TST2\"\\r\\n'\n", + "2026-03-30 12:50:46,674 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST3\"\\r\\n'\n", + "2026-03-30 12:50:46,675 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TST3\"\\r\\n'\n", + "2026-03-30 12:50:46,676 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"UPD\"\\r\\n'\n", + "2026-03-30 12:50:46,677 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"UPD\"\\r\\n'\n", + "2026-03-30 12:50:46,705 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"FCUT\"\\r\\n'\n", + "2026-03-30 12:50:46,706 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 3 \"FCUT\"\\r\\n'\n", + "2026-03-30 12:50:46,708 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"FSET\"\\r\\n'\n", + "2026-03-30 12:50:46,709 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 3 \"FSET\"\\r\\n'\n", + "2026-03-30 12:50:46,722 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"LST\"\\r\\n'\n", + "2026-03-30 12:50:46,723 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 3 \"LST\"\\r\\n'\n", + "2026-03-30 12:50:46,737 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"RDB\"\\r\\n'\n", + "2026-03-30 12:50:46,738 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 3 \"RDB\"\\r\\n'\n", + "2026-03-30 12:50:46,753 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 A 3 \"USTB\"\\r\\n'\n", + "2026-03-30 12:50:46,754 - pylabrobot - IO - [MT Scale] Received response: b'I0 A 3 \"USTB\"\\r\\n'\n" ] }, { @@ -593,20 +592,20 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 12:41:01,821 - pylabrobot - IO - [MT Scale] Sent command: I3\n", - "2026-03-30 12:41:01,824 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I3\\r\\n'\n", - "2026-03-30 12:41:01,874 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I3 A \"1.10 18.6.4.1361.772\"\\r\\n'\n", - "2026-03-30 12:41:01,875 - pylabrobot - IO - [MT Scale] Received response: b'I3 A \"1.10 18.6.4.1361.772\"\\r\\n'\n", - "2026-03-30 12:41:01,876 - pylabrobot - IO - [MT Scale] Sent command: I5\n", - "2026-03-30 12:41:01,880 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I5\\r\\n'\n", - "2026-03-30 12:41:01,906 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I5 A \"11671158C\"\\r\\n'\n", - "2026-03-30 12:41:01,974 - pylabrobot - IO - [MT Scale] Received response: b'I5 A \"11671158C\"\\r\\n'\n", - "2026-03-30 12:41:01,975 - pylabrobot - IO - [MT Scale] Sent command: I10\n", - "2026-03-30 12:41:01,976 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I10\\r\\n'\n", - "2026-03-30 12:41:02,002 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I10 A \"\"\\r\\n'\n", - "2026-03-30 12:41:02,002 - pylabrobot - IO - [MT Scale] Received response: b'I10 A \"\"\\r\\n'\n", - "2026-03-30 12:41:02,003 - pylabrobot - IO - [MT Scale] Sent command: I11\n", - "2026-03-30 12:41:02,004 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I11\\r\\n'\n" + "2026-03-30 12:50:46,766 - pylabrobot - IO - [MT Scale] Sent command: I3\n", + "2026-03-30 12:50:46,768 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I3\\r\\n'\n", + "2026-03-30 12:50:46,818 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I3 A \"1.10 18.6.4.1361.772\"\\r\\n'\n", + "2026-03-30 12:50:46,820 - pylabrobot - IO - [MT Scale] Received response: b'I3 A \"1.10 18.6.4.1361.772\"\\r\\n'\n", + "2026-03-30 12:50:46,824 - pylabrobot - IO - [MT Scale] Sent command: I5\n", + "2026-03-30 12:50:46,827 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I5\\r\\n'\n", + "2026-03-30 12:50:46,867 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I5 A \"11671158C\"\\r\\n'\n", + "2026-03-30 12:50:46,870 - pylabrobot - IO - [MT Scale] Received response: b'I5 A \"11671158C\"\\r\\n'\n", + "2026-03-30 12:50:46,876 - pylabrobot - IO - [MT Scale] Sent command: I10\n", + "2026-03-30 12:50:46,882 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I10\\r\\n'\n", + "2026-03-30 12:50:46,913 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I10 A \"\"\\r\\n'\n", + "2026-03-30 12:50:46,918 - pylabrobot - IO - [MT Scale] Received response: b'I10 A \"\"\\r\\n'\n", + "2026-03-30 12:50:46,919 - pylabrobot - IO - [MT Scale] Sent command: I11\n", + "2026-03-30 12:50:46,923 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I11\\r\\n'\n" ] }, { @@ -622,39 +621,61 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 12:41:02,050 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I11 A \"WXS205SDU\"\\r\\n'\n", - "2026-03-30 12:41:02,051 - pylabrobot - IO - [MT Scale] Received response: b'I11 A \"WXS205SDU\"\\r\\n'\n", - "2026-03-30 12:41:02,052 - pylabrobot - IO - [MT Scale] Sent command: I15\n", - "2026-03-30 12:41:02,054 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I15\\r\\n'\n" + "2026-03-30 12:50:46,961 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I11 A \"WXS205SDU\"\\r\\n'\n", + "2026-03-30 12:50:46,962 - pylabrobot - IO - [MT Scale] Received response: b'I11 A \"WXS205SDU\"\\r\\n'\n", + "2026-03-30 12:50:46,963 - pylabrobot - IO - [MT Scale] Sent command: I15\n", + "2026-03-30 12:50:46,971 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I15\\r\\n'\n", + "2026-03-30 12:50:47,009 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I15 A 203\\r\\n'\n", + "2026-03-30 12:50:47,010 - pylabrobot - IO - [MT Scale] Received response: b'I15 A 203\\r\\n'\n", + "2026-03-30 12:50:47,012 - pylabrobot - IO - [MT Scale] Sent command: DAT\n", + "2026-03-30 12:50:47,014 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'DAT\\r\\n'\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ - "Model designation: WXS205SDU\n" + "Model designation: WXS205SDU\n", + "Uptime: 203d 0h 0m 0s\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 12:41:02,081 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I15 A 193\\r\\n'\n", - "2026-03-30 12:41:02,082 - pylabrobot - IO - [MT Scale] Received response: b'I15 A 193\\r\\n'\n" + "2026-03-30 12:50:47,057 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'DAT A 04 01 2000\\r\\n'\n", + "2026-03-30 12:50:47,058 - pylabrobot - IO - [MT Scale] Received response: b'DAT A 04 01 2000\\r\\n'\n", + "2026-03-30 12:50:47,059 - pylabrobot - IO - [MT Scale] Sent command: TIM\n", + "2026-03-30 12:50:47,061 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'TIM\\r\\n'\n", + "2026-03-30 12:50:47,089 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'TIM A 19 56 13\\r\\n'\n", + "2026-03-30 12:50:47,090 - pylabrobot - IO - [MT Scale] Received response: b'TIM A 19 56 13\\r\\n'\n", + "2026-03-30 12:50:47,091 - pylabrobot - IO - [MT Scale] Sent command: I14\n", + "2026-03-30 12:50:47,092 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I14\\r\\n'\n", + "2026-03-30 12:50:47,121 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I14 L\\r\\n'\n", + "2026-03-30 12:50:47,121 - pylabrobot - IO - [MT Scale] Received response: b'I14 L\\r\\n'\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Device date: 04\n", + "Device time: 19\n" ] }, { "ename": "MettlerToledoError", - "evalue": "Unexpected response: Expected at least 6 fields for 'I15', got 3: MettlerToledoResponse(command='I15', status='A', data=['193'])", + "evalue": "Command understood but not executable: (incorrect parameter).", "output_type": "error", "traceback": [ "\u001b[31m---------------------------------------------------------------------------\u001b[39m", "\u001b[31mMettlerToledoError\u001b[39m Traceback (most recent call last)", - "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[6]\u001b[39m\u001b[32m, line 25\u001b[39m\n\u001b[32m 23\u001b[39m \u001b[38;5;66;03m# I15 - Uptime\u001b[39;00m\n\u001b[32m 24\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m \u001b[33m\"\u001b[39m\u001b[33mI15\u001b[39m\u001b[33m\"\u001b[39m \u001b[38;5;129;01min\u001b[39;00m backend._supported_commands:\n\u001b[32m---> \u001b[39m\u001b[32m25\u001b[39m uptime = \u001b[38;5;28;01mawait\u001b[39;00m backend.request_uptime()\n\u001b[32m 26\u001b[39m \u001b[38;5;28mprint\u001b[39m(\u001b[33mf\u001b[39m\u001b[33m\"\u001b[39m\u001b[33mUptime: \u001b[39m\u001b[38;5;132;01m{\u001b[39;00muptime[\u001b[33m'\u001b[39m\u001b[33mdays\u001b[39m\u001b[33m'\u001b[39m]\u001b[38;5;132;01m}\u001b[39;00m\u001b[33md \u001b[39m\u001b[38;5;132;01m{\u001b[39;00muptime[\u001b[33m'\u001b[39m\u001b[33mhours\u001b[39m\u001b[33m'\u001b[39m]\u001b[38;5;132;01m}\u001b[39;00m\u001b[33mh \u001b[39m\u001b[38;5;132;01m{\u001b[39;00muptime[\u001b[33m'\u001b[39m\u001b[33mminutes\u001b[39m\u001b[33m'\u001b[39m]\u001b[38;5;132;01m}\u001b[39;00m\u001b[33mm \u001b[39m\u001b[38;5;132;01m{\u001b[39;00muptime[\u001b[33m'\u001b[39m\u001b[33mseconds\u001b[39m\u001b[33m'\u001b[39m]\u001b[38;5;132;01m}\u001b[39;00m\u001b[33ms\u001b[39m\u001b[33m\"\u001b[39m)\n\u001b[32m 27\u001b[39m \u001b[38;5;28;01melse\u001b[39;00m:\n", + "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[6]\u001b[39m\u001b[32m, line 46\u001b[39m\n\u001b[32m 44\u001b[39m \u001b[38;5;66;03m# I14 - Comprehensive device info (multi-response)\u001b[39;00m\n\u001b[32m 45\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m \u001b[33m\"\u001b[39m\u001b[33mI14\u001b[39m\u001b[33m\"\u001b[39m \u001b[38;5;129;01min\u001b[39;00m backend._supported_commands:\n\u001b[32m---> \u001b[39m\u001b[32m46\u001b[39m info_responses = \u001b[38;5;28;01mawait\u001b[39;00m backend.request_device_info()\n\u001b[32m 47\u001b[39m \u001b[38;5;28mprint\u001b[39m(\u001b[33mf\u001b[39m\u001b[33m\"\u001b[39m\u001b[38;5;130;01m\\n\u001b[39;00m\u001b[33mDevice info (\u001b[39m\u001b[38;5;132;01m{\u001b[39;00m\u001b[38;5;28mlen\u001b[39m(info_responses)\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m response lines):\u001b[39m\u001b[33m\"\u001b[39m)\n\u001b[32m 48\u001b[39m \u001b[38;5;28;01mfor\u001b[39;00m resp \u001b[38;5;129;01min\u001b[39;00m info_responses:\n", "\u001b[36mFile \u001b[39m\u001b[32m~/Desktop/GitHub/pylabrobot/pylabrobot/scales/mettler_toledo/backend.py:59\u001b[39m, in \u001b[36mrequires_mt_sics_command..decorator..wrapper\u001b[39m\u001b[34m(self, *args, **kwargs)\u001b[39m\n\u001b[32m 53\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m mt_sics_command \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;129;01min\u001b[39;00m \u001b[38;5;28mself\u001b[39m._supported_commands:\n\u001b[32m 54\u001b[39m \u001b[38;5;28;01mraise\u001b[39;00m MettlerToledoError(\n\u001b[32m 55\u001b[39m title=\u001b[33m\"\u001b[39m\u001b[33mCommand not supported\u001b[39m\u001b[33m\"\u001b[39m,\n\u001b[32m 56\u001b[39m message=\u001b[33mf\u001b[39m\u001b[33m\"\u001b[39m\u001b[33m'\u001b[39m\u001b[38;5;132;01m{\u001b[39;00mfunc.\u001b[34m__name__\u001b[39m\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m'\u001b[39m\u001b[33m requires MT-SICS command \u001b[39m\u001b[33m'\u001b[39m\u001b[38;5;132;01m{\u001b[39;00mmt_sics_command\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m'\u001b[39m\u001b[33m, \u001b[39m\u001b[33m\"\u001b[39m\n\u001b[32m 57\u001b[39m \u001b[33mf\u001b[39m\u001b[33m\"\u001b[39m\u001b[33mwhich is not implemented on this device.\u001b[39m\u001b[33m\"\u001b[39m,\n\u001b[32m 58\u001b[39m )\n\u001b[32m---> \u001b[39m\u001b[32m59\u001b[39m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;01mawait\u001b[39;00m func(\u001b[38;5;28mself\u001b[39m, *args, **kwargs)\n", - "\u001b[36mFile \u001b[39m\u001b[32m~/Desktop/GitHub/pylabrobot/pylabrobot/scales/mettler_toledo/backend.py:473\u001b[39m, in \u001b[36mMettlerToledoWXS205SDUBackend.request_uptime\u001b[39m\u001b[34m(self)\u001b[39m\n\u001b[32m 466\u001b[39m \u001b[38;5;250m\u001b[39m\u001b[33;03m\"\"\"Query the device uptime. (I15 command)\u001b[39;00m\n\u001b[32m 467\u001b[39m \n\u001b[32m 468\u001b[39m \u001b[33;03mReturns a dict with keys \"days\", \"hours\", \"minutes\", \"seconds\".\u001b[39;00m\n\u001b[32m 469\u001b[39m \u001b[33;03mCounts time since last power-on, including short interruptions.\u001b[39;00m\n\u001b[32m 470\u001b[39m \u001b[33;03mNot reset by @ cancel or restart.\u001b[39;00m\n\u001b[32m 471\u001b[39m \u001b[33;03m\"\"\"\u001b[39;00m\n\u001b[32m 472\u001b[39m responses = \u001b[38;5;28;01mawait\u001b[39;00m \u001b[38;5;28mself\u001b[39m.send_command(\u001b[33m\"\u001b[39m\u001b[33mI15\u001b[39m\u001b[33m\"\u001b[39m)\n\u001b[32m--> \u001b[39m\u001b[32m473\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[43m.\u001b[49m\u001b[43m_validate_response\u001b[49m\u001b[43m(\u001b[49m\u001b[43mresponses\u001b[49m\u001b[43m[\u001b[49m\u001b[32;43m0\u001b[39;49m\u001b[43m]\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[32;43m6\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[33;43m\"\u001b[39;49m\u001b[33;43mI15\u001b[39;49m\u001b[33;43m\"\u001b[39;49m\u001b[43m)\u001b[49m\n\u001b[32m 474\u001b[39m \u001b[38;5;28;01mreturn\u001b[39;00m {\n\u001b[32m 475\u001b[39m \u001b[33m\"\u001b[39m\u001b[33mdays\u001b[39m\u001b[33m\"\u001b[39m: \u001b[38;5;28mint\u001b[39m(responses[\u001b[32m0\u001b[39m].data[\u001b[32m0\u001b[39m]),\n\u001b[32m 476\u001b[39m \u001b[33m\"\u001b[39m\u001b[33mhours\u001b[39m\u001b[33m\"\u001b[39m: \u001b[38;5;28mint\u001b[39m(responses[\u001b[32m0\u001b[39m].data[\u001b[32m1\u001b[39m]),\n\u001b[32m 477\u001b[39m \u001b[33m\"\u001b[39m\u001b[33mminutes\u001b[39m\u001b[33m\"\u001b[39m: \u001b[38;5;28mint\u001b[39m(responses[\u001b[32m0\u001b[39m].data[\u001b[32m2\u001b[39m]),\n\u001b[32m 478\u001b[39m \u001b[33m\"\u001b[39m\u001b[33mseconds\u001b[39m\u001b[33m\"\u001b[39m: \u001b[38;5;28mint\u001b[39m(responses[\u001b[32m0\u001b[39m].data[\u001b[32m3\u001b[39m]),\n\u001b[32m 479\u001b[39m }\n", - "\u001b[36mFile \u001b[39m\u001b[32m~/Desktop/GitHub/pylabrobot/pylabrobot/scales/mettler_toledo/backend.py:212\u001b[39m, in \u001b[36mMettlerToledoWXS205SDUBackend._validate_response\u001b[39m\u001b[34m(response, min_fields, command)\u001b[39m\n\u001b[32m 210\u001b[39m total = \u001b[32m1\u001b[39m + (\u001b[32m1\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m response.status \u001b[38;5;28;01melse\u001b[39;00m \u001b[32m0\u001b[39m) + \u001b[38;5;28mlen\u001b[39m(response.data)\n\u001b[32m 211\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m total < min_fields:\n\u001b[32m--> \u001b[39m\u001b[32m212\u001b[39m \u001b[38;5;28;01mraise\u001b[39;00m MettlerToledoError(\n\u001b[32m 213\u001b[39m title=\u001b[33m\"\u001b[39m\u001b[33mUnexpected response\u001b[39m\u001b[33m\"\u001b[39m,\n\u001b[32m 214\u001b[39m message=\u001b[33mf\u001b[39m\u001b[33m\"\u001b[39m\u001b[33mExpected at least \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mmin_fields\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m fields for \u001b[39m\u001b[33m'\u001b[39m\u001b[38;5;132;01m{\u001b[39;00mcommand\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m'\u001b[39m\u001b[33m, got \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mtotal\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m: \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mresponse\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m\"\u001b[39m,\n\u001b[32m 215\u001b[39m )\n", - "\u001b[31mMettlerToledoError\u001b[39m: Unexpected response: Expected at least 6 fields for 'I15', got 3: MettlerToledoResponse(command='I15', status='A', data=['193'])" + "\u001b[36mFile \u001b[39m\u001b[32m~/Desktop/GitHub/pylabrobot/pylabrobot/scales/mettler_toledo/backend.py:465\u001b[39m, in \u001b[36mMettlerToledoWXS205SDUBackend.request_device_info\u001b[39m\u001b[34m(self)\u001b[39m\n\u001b[32m 456\u001b[39m \u001b[38;5;129m@requires_mt_sics_command\u001b[39m(\u001b[33m\"\u001b[39m\u001b[33mI14\u001b[39m\u001b[33m\"\u001b[39m)\n\u001b[32m 457\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[34mrequest_device_info\u001b[39m(\u001b[38;5;28mself\u001b[39m) -> List[MettlerToledoResponse]:\n\u001b[32m 458\u001b[39m \u001b[38;5;250m \u001b[39m\u001b[33;03m\"\"\"Query detailed device information including all components. (I14 command)\u001b[39;00m\n\u001b[32m 459\u001b[39m \n\u001b[32m 460\u001b[39m \u001b[33;03m Returns multi-response with instrument configuration (No=0),\u001b[39;00m\n\u001b[32m (...)\u001b[39m\u001b[32m 463\u001b[39m \u001b[33;03m Each category reports data for bridge, terminal, options, etc.\u001b[39;00m\n\u001b[32m 464\u001b[39m \u001b[33;03m \"\"\"\u001b[39;00m\n\u001b[32m--> \u001b[39m\u001b[32m465\u001b[39m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;01mawait\u001b[39;00m \u001b[38;5;28mself\u001b[39m.send_command(\u001b[33m\"\u001b[39m\u001b[33mI14\u001b[39m\u001b[33m\"\u001b[39m)\n", + "\u001b[36mFile \u001b[39m\u001b[32m~/Desktop/GitHub/pylabrobot/pylabrobot/scales/mettler_toledo/backend.py:322\u001b[39m, in \u001b[36mMettlerToledoWXS205SDUBackend.send_command\u001b[39m\u001b[34m(self, command, timeout)\u001b[39m\n\u001b[32m 320\u001b[39m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[32m 321\u001b[39m response = MettlerToledoResponse(command=\u001b[33m\"\u001b[39m\u001b[33m\"\u001b[39m, status=\u001b[33m\"\u001b[39m\u001b[33m\"\u001b[39m, data=[])\n\u001b[32m--> \u001b[39m\u001b[32m322\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[43m.\u001b[49m\u001b[43m_parse_basic_errors\u001b[49m\u001b[43m(\u001b[49m\u001b[43mresponse\u001b[49m\u001b[43m)\u001b[49m\n\u001b[32m 323\u001b[39m responses.append(response)\n\u001b[32m 325\u001b[39m \u001b[38;5;66;03m# Status B means more responses follow; anything else (A, etc.) is final\u001b[39;00m\n", + "\u001b[36mFile \u001b[39m\u001b[32m~/Desktop/GitHub/pylabrobot/pylabrobot/scales/mettler_toledo/backend.py:253\u001b[39m, in \u001b[36mMettlerToledoWXS205SDUBackend._parse_basic_errors\u001b[39m\u001b[34m(self, response)\u001b[39m\n\u001b[32m 251\u001b[39m \u001b[38;5;28;01mraise\u001b[39;00m MettlerToledoError.executing_another_command()\n\u001b[32m 252\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m response.status == \u001b[33m\"\u001b[39m\u001b[33mL\u001b[39m\u001b[33m\"\u001b[39m:\n\u001b[32m--> \u001b[39m\u001b[32m253\u001b[39m \u001b[38;5;28;01mraise\u001b[39;00m MettlerToledoError.incorrect_parameter()\n\u001b[32m 254\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m response.status == \u001b[33m\"\u001b[39m\u001b[33m+\u001b[39m\u001b[33m\"\u001b[39m:\n\u001b[32m 255\u001b[39m \u001b[38;5;28;01mraise\u001b[39;00m MettlerToledoError.overload()\n", + "\u001b[31mMettlerToledoError\u001b[39m: Command understood but not executable: (incorrect parameter)." ] } ], @@ -731,29 +752,9 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2026-03-30 12:41:20,576 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] reset_input_buffer\n", - "2026-03-30 12:41:20,577 - pylabrobot - IO - [MT Scale] Sent command: @\n", - "2026-03-30 12:41:20,579 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'@\\r\\n'\n", - "2026-03-30 12:41:20,641 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I4 A \"B207696838\"\\r\\n'\n", - "2026-03-30 12:41:20,642 - pylabrobot - IO - [MT Scale] Received response: b'I4 A \"B207696838\"\\r\\n'\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Cancel returned serial number: B207696838\n", - "PASS: cancel returns correct serial number\n" - ] - } - ], + "outputs": [], "source": [ "serial_number = await backend.cancel()\n", "print(f\"Cancel returned serial number: {serial_number}\")\n", @@ -770,28 +771,9 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2026-03-30 12:41:22,391 - pylabrobot - IO - [MT Scale] Sent command: I4\n", - "2026-03-30 12:41:22,399 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I4\\r\\n'\n", - "2026-03-30 12:41:22,447 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I4 A \"B207696838\"\\r\\n'\n", - "2026-03-30 12:41:22,448 - pylabrobot - IO - [MT Scale] Received response: b'I4 A \"B207696838\"\\r\\n'\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Serial number: B207696838\n", - "PASS: serial number is non-empty\n" - ] - } - ], + "outputs": [], "source": [ "sn = await backend.request_serial_number()\n", "print(f\"Serial number: {sn}\")\n", @@ -808,33 +790,9 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2026-03-30 12:41:24,197 - pylabrobot - IO - [MT Scale] Sent command: I2\n", - "2026-03-30 12:41:24,198 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I2\\r\\n'\n", - "2026-03-30 12:41:24,255 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", - "2026-03-30 12:41:24,257 - pylabrobot - IO - [MT Scale] Received response: b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", - "2026-03-30 12:41:24,258 - pylabrobot - IO - [MT Scale] Sent command: I2\n", - "2026-03-30 12:41:24,260 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I2\\r\\n'\n", - "2026-03-30 12:41:24,318 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", - "2026-03-30 12:41:24,322 - pylabrobot - IO - [MT Scale] Received response: b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Device type: WXS205SDU WXA-Bridge\n", - "Capacity: 220.009 g\n", - "PASS: device type and capacity valid\n" - ] - } - ], + "outputs": [], "source": [ "device_type = await backend.request_device_type()\n", "capacity = await backend.request_capacity()\n", @@ -854,29 +812,9 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2026-03-30 12:41:30,722 - pylabrobot - IO - [MT Scale] Sent command: I1\n", - "2026-03-30 12:41:30,724 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I1\\r\\n'\n", - "2026-03-30 12:41:30,777 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I1 A \"01\" \"2.30\" \"2.22\" \"\" \"\"\\r\\n'\n", - "2026-03-30 12:41:30,779 - pylabrobot - IO - [MT Scale] Received response: b'I1 A \"01\" \"2.30\" \"2.22\" \"\" \"\"\\r\\n'\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "I1 reported levels: ['01', '2.30', '2.22', '', '']\n", - "I0 discovered 62 commands\n", - "Note: I1 may underreport - I0 is the authoritative source\n" - ] - } - ], + "outputs": [], "source": [ "# I1 reports standardized level sets (may not reflect all available commands)\n", "# I0 is the definitive source (already queried during setup)\n", @@ -895,28 +833,9 @@ }, { "cell_type": "code", - "execution_count": 11, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2026-03-30 12:41:31,585 - pylabrobot - IO - [MT Scale] Sent command: S\n", - "2026-03-30 12:41:31,588 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", - "2026-03-30 12:41:31,624 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S -0.00008 g\\r\\n'\n", - "2026-03-30 12:41:31,624 - pylabrobot - IO - [MT Scale] Received response: b'S S -0.00008 g\\r\\n'\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Stable weight (empty pan): -8e-05 g\n", - "PASS: stable weight returns float\n" - ] - } - ], + "outputs": [], "source": [ "weight = await backend.read_stable_weight()\n", "print(f\"Stable weight (empty pan): {weight} g\")\n", @@ -933,28 +852,9 @@ }, { "cell_type": "code", - "execution_count": 12, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2026-03-30 12:41:32,417 - pylabrobot - IO - [MT Scale] Sent command: SI\n", - "2026-03-30 12:41:32,421 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", - "2026-03-30 12:41:32,455 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S -0.00008 g\\r\\n'\n", - "2026-03-30 12:41:32,457 - pylabrobot - IO - [MT Scale] Received response: b'S S -0.00008 g\\r\\n'\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Immediate weight: -8e-05 g\n", - "PASS: immediate weight returns float\n" - ] - } - ], + "outputs": [], "source": [ "weight = await backend.read_weight_value_immediately()\n", "print(f\"Immediate weight: {weight} g\")\n", @@ -971,32 +871,9 @@ }, { "cell_type": "code", - "execution_count": 13, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2026-03-30 12:41:33,234 - pylabrobot - IO - [MT Scale] Sent command: Z\n", - "2026-03-30 12:41:33,236 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'Z\\r\\n'\n", - "2026-03-30 12:41:33,574 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'Z A\\r\\n'\n", - "2026-03-30 12:41:33,574 - pylabrobot - IO - [MT Scale] Received response: b'Z A\\r\\n'\n", - "2026-03-30 12:41:33,576 - pylabrobot - IO - [MT Scale] Sent command: SI\n", - "2026-03-30 12:41:33,577 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", - "2026-03-30 12:41:33,608 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 12:41:33,612 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Weight after zero: 0.0 g\n", - "PASS: zero sets weight to ~0\n" - ] - } - ], + "outputs": [], "source": [ "await scale.zero(timeout=\"stable\")\n", "weight = await backend.read_weight_value_immediately()\n", @@ -1014,32 +891,9 @@ }, { "cell_type": "code", - "execution_count": 14, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2026-03-30 12:41:34,275 - pylabrobot - IO - [MT Scale] Sent command: ZI\n", - "2026-03-30 12:41:34,277 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'ZI\\r\\n'\n", - "2026-03-30 12:41:34,294 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'ZI S\\r\\n'\n", - "2026-03-30 12:41:34,295 - pylabrobot - IO - [MT Scale] Received response: b'ZI S\\r\\n'\n", - "2026-03-30 12:41:34,295 - pylabrobot - IO - [MT Scale] Sent command: SI\n", - "2026-03-30 12:41:34,297 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", - "2026-03-30 12:41:34,326 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 12:41:34,329 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Weight after zero immediately: 0.0 g\n", - "PASS: zero immediately sets weight to ~0\n" - ] - } - ], + "outputs": [], "source": [ "await scale.zero(timeout=0)\n", "weight = await backend.read_weight_value_immediately()\n", @@ -1067,53 +921,9 @@ }, { "cell_type": "code", - "execution_count": 15, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stdin", - "output_type": "stream", - "text": [ - "Place a container on the scale and press Enter... \n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2026-03-30 12:41:38,890 - pylabrobot - IO - [MT Scale] Sent command: Z\n", - "2026-03-30 12:41:38,892 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'Z\\r\\n'\n", - "2026-03-30 12:41:39,281 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'Z A\\r\\n'\n", - "2026-03-30 12:41:39,282 - pylabrobot - IO - [MT Scale] Received response: b'Z A\\r\\n'\n", - "2026-03-30 12:41:39,283 - pylabrobot - IO - [MT Scale] Sent command: T\n", - "2026-03-30 12:41:39,284 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'T\\r\\n'\n", - "2026-03-30 12:41:39,696 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'T S 0.00000 g\\r\\n'\n", - "2026-03-30 12:41:39,697 - pylabrobot - IO - [MT Scale] Received response: b'T S 0.00000 g\\r\\n'\n", - "2026-03-30 12:41:39,699 - pylabrobot - IO - [MT Scale] Sent command: TA\n", - "2026-03-30 12:41:39,701 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'TA\\r\\n'\n", - "2026-03-30 12:41:39,793 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'TA A 0.00000 g\\r\\n'\n", - "2026-03-30 12:41:39,793 - pylabrobot - IO - [MT Scale] Received response: b'TA A 0.00000 g\\r\\n'\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Tare weight: 0.0 g\n" - ] - }, - { - "ename": "AssertionError", - "evalue": "Expected positive tare, got 0.0", - "output_type": "error", - "traceback": [ - "\u001b[31m---------------------------------------------------------------------------\u001b[39m", - "\u001b[31mAssertionError\u001b[39m Traceback (most recent call last)", - "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[15]\u001b[39m\u001b[32m, line 6\u001b[39m\n\u001b[32m 4\u001b[39m tare = \u001b[38;5;28;01mawait\u001b[39;00m scale.request_tare_weight()\n\u001b[32m 5\u001b[39m \u001b[38;5;28mprint\u001b[39m(\u001b[33mf\u001b[39m\u001b[33m\"\u001b[39m\u001b[33mTare weight: \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mtare\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m g\u001b[39m\u001b[33m\"\u001b[39m)\n\u001b[32m----> \u001b[39m\u001b[32m6\u001b[39m \u001b[38;5;28;01massert\u001b[39;00m tare > \u001b[32m0\u001b[39m, \u001b[33mf\u001b[39m\u001b[33m\"\u001b[39m\u001b[33mExpected positive tare, got \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mtare\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m\"\u001b[39m\n\u001b[32m 7\u001b[39m \u001b[38;5;28mprint\u001b[39m(\u001b[33m\"\u001b[39m\u001b[33mPASS: tare stores container weight\u001b[39m\u001b[33m\"\u001b[39m)\n", - "\u001b[31mAssertionError\u001b[39m: Expected positive tare, got 0.0" - ] - } - ], + "outputs": [], "source": [ "input(\"Place a container on the scale and press Enter...\")\n", "await scale.zero(timeout=\"stable\")\n", @@ -1133,28 +943,9 @@ }, { "cell_type": "code", - "execution_count": 16, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2026-03-30 12:41:42,457 - pylabrobot - IO - [MT Scale] Sent command: TA\n", - "2026-03-30 12:41:42,459 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'TA\\r\\n'\n", - "2026-03-30 12:41:42,542 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'TA A 0.00000 g\\r\\n'\n", - "2026-03-30 12:41:42,543 - pylabrobot - IO - [MT Scale] Received response: b'TA A 0.00000 g\\r\\n'\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Tare weight from memory: 0.0 g\n", - "PASS: tare weight readable from memory\n" - ] - } - ], + "outputs": [], "source": [ "tare = await scale.request_tare_weight()\n", "print(f\"Tare weight from memory: {tare} g\")\n", @@ -1171,32 +962,9 @@ }, { "cell_type": "code", - "execution_count": 17, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2026-03-30 12:41:43,768 - pylabrobot - IO - [MT Scale] Sent command: TAC\n", - "2026-03-30 12:41:43,770 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'TAC\\r\\n'\n", - "2026-03-30 12:41:43,805 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'TAC A\\r\\n'\n", - "2026-03-30 12:41:43,806 - pylabrobot - IO - [MT Scale] Received response: b'TAC A\\r\\n'\n", - "2026-03-30 12:41:43,807 - pylabrobot - IO - [MT Scale] Sent command: TA\n", - "2026-03-30 12:41:43,809 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'TA\\r\\n'\n", - "2026-03-30 12:41:43,916 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'TA A 0.00000 g\\r\\n'\n", - "2026-03-30 12:41:43,918 - pylabrobot - IO - [MT Scale] Received response: b'TA A 0.00000 g\\r\\n'\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Tare after clear: 0.0 g\n", - "PASS: clear tare resets tare to 0\n" - ] - } - ], + "outputs": [], "source": [ "await backend.clear_tare()\n", "tare_after_clear = await scale.request_tare_weight()\n", @@ -1214,34 +982,9 @@ }, { "cell_type": "code", - "execution_count": 18, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2026-03-30 12:41:44,525 - pylabrobot - IO - [MT Scale] Sent command: SC 3000\n", - "2026-03-30 12:41:44,526 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SC 3000\\r\\n'\n", - "2026-03-30 12:41:44,556 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'ES\\r\\n'\n", - "2026-03-30 12:41:44,557 - pylabrobot - IO - [MT Scale] Received response: b'ES\\r\\n'\n" - ] - }, - { - "ename": "MettlerToledoError", - "evalue": "Syntax error: The weigh module/balance has not recognized the received command or the command is not allowed", - "output_type": "error", - "traceback": [ - "\u001b[31m---------------------------------------------------------------------------\u001b[39m", - "\u001b[31mMettlerToledoError\u001b[39m Traceback (most recent call last)", - "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[18]\u001b[39m\u001b[32m, line 1\u001b[39m\n\u001b[32m----> \u001b[39m\u001b[32m1\u001b[39m weight = \u001b[38;5;28;01mawait\u001b[39;00m backend.read_dynamic_weight(timeout=\u001b[32m3.0\u001b[39m)\n\u001b[32m 2\u001b[39m \u001b[38;5;28mprint\u001b[39m(\u001b[33mf\u001b[39m\u001b[33m\"\u001b[39m\u001b[33mDynamic weight (3s timeout): \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mweight\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m g\u001b[39m\u001b[33m\"\u001b[39m)\n\u001b[32m 3\u001b[39m \u001b[38;5;28;01massert\u001b[39;00m \u001b[38;5;28misinstance\u001b[39m(weight, \u001b[38;5;28mfloat\u001b[39m)\n", - "\u001b[36mFile \u001b[39m\u001b[32m~/Desktop/GitHub/pylabrobot/pylabrobot/scales/mettler_toledo/backend.py:647\u001b[39m, in \u001b[36mMettlerToledoWXS205SDUBackend.read_dynamic_weight\u001b[39m\u001b[34m(self, timeout)\u001b[39m\n\u001b[32m 638\u001b[39m \u001b[38;5;250m\u001b[39m\u001b[33;03m\"\"\"Read a stable weight value from the machine within a given timeout, or\u001b[39;00m\n\u001b[32m 639\u001b[39m \u001b[33;03mreturn the current weight value if not possible. (MEASUREMENT command)\u001b[39;00m\n\u001b[32m 640\u001b[39m \n\u001b[32m 641\u001b[39m \u001b[33;03mArgs:\u001b[39;00m\n\u001b[32m 642\u001b[39m \u001b[33;03m timeout: The timeout in seconds.\u001b[39;00m\n\u001b[32m 643\u001b[39m \u001b[33;03m\"\"\"\u001b[39;00m\n\u001b[32m 645\u001b[39m timeout = \u001b[38;5;28mint\u001b[39m(timeout * \u001b[32m1000\u001b[39m) \u001b[38;5;66;03m# convert to milliseconds\u001b[39;00m\n\u001b[32m--> \u001b[39m\u001b[32m647\u001b[39m responses = \u001b[38;5;28;01mawait\u001b[39;00m \u001b[38;5;28mself\u001b[39m.send_command(\u001b[33mf\u001b[39m\u001b[33m\"\u001b[39m\u001b[33mSC \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mtimeout\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m\"\u001b[39m)\n\u001b[32m 648\u001b[39m \u001b[38;5;28mself\u001b[39m._validate_response(responses[\u001b[32m0\u001b[39m], \u001b[32m4\u001b[39m, \u001b[33m\"\u001b[39m\u001b[33mSC\u001b[39m\u001b[33m\"\u001b[39m)\n\u001b[32m 649\u001b[39m \u001b[38;5;28mself\u001b[39m._validate_unit(responses[\u001b[32m0\u001b[39m].data[\u001b[32m1\u001b[39m], \u001b[33m\"\u001b[39m\u001b[33mSC\u001b[39m\u001b[33m\"\u001b[39m)\n", - "\u001b[36mFile \u001b[39m\u001b[32m~/Desktop/GitHub/pylabrobot/pylabrobot/scales/mettler_toledo/backend.py:322\u001b[39m, in \u001b[36mMettlerToledoWXS205SDUBackend.send_command\u001b[39m\u001b[34m(self, command, timeout)\u001b[39m\n\u001b[32m 320\u001b[39m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[32m 321\u001b[39m response = MettlerToledoResponse(command=\u001b[33m\"\u001b[39m\u001b[33m\"\u001b[39m, status=\u001b[33m\"\u001b[39m\u001b[33m\"\u001b[39m, data=[])\n\u001b[32m--> \u001b[39m\u001b[32m322\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[43m.\u001b[49m\u001b[43m_parse_basic_errors\u001b[49m\u001b[43m(\u001b[49m\u001b[43mresponse\u001b[49m\u001b[43m)\u001b[49m\n\u001b[32m 323\u001b[39m responses.append(response)\n\u001b[32m 325\u001b[39m \u001b[38;5;66;03m# Status B means more responses follow; anything else (A, etc.) is final\u001b[39;00m\n", - "\u001b[36mFile \u001b[39m\u001b[32m~/Desktop/GitHub/pylabrobot/pylabrobot/scales/mettler_toledo/backend.py:243\u001b[39m, in \u001b[36mMettlerToledoWXS205SDUBackend._parse_basic_errors\u001b[39m\u001b[34m(self, response)\u001b[39m\n\u001b[32m 241\u001b[39m \u001b[38;5;66;03m# General error messages: ES, ET, EL (status is \"\" for these)\u001b[39;00m\n\u001b[32m 242\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m response.command == \u001b[33m\"\u001b[39m\u001b[33mES\u001b[39m\u001b[33m\"\u001b[39m:\n\u001b[32m--> \u001b[39m\u001b[32m243\u001b[39m \u001b[38;5;28;01mraise\u001b[39;00m MettlerToledoError.syntax_error()\n\u001b[32m 244\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m response.command == \u001b[33m\"\u001b[39m\u001b[33mET\u001b[39m\u001b[33m\"\u001b[39m:\n\u001b[32m 245\u001b[39m \u001b[38;5;28;01mraise\u001b[39;00m MettlerToledoError.transmission_error()\n", - "\u001b[31mMettlerToledoError\u001b[39m: Syntax error: The weigh module/balance has not recognized the received command or the command is not allowed" - ] - } - ], + "outputs": [], "source": [ "weight = await backend.read_dynamic_weight(timeout=3.0)\n", "print(f\"Dynamic weight (3s timeout): {weight} g\")\n", @@ -1258,34 +1001,9 @@ }, { "cell_type": "code", - "execution_count": 19, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2026-03-30 12:41:45,645 - pylabrobot - IO - [MT Scale] Sent command: C\n", - "2026-03-30 12:41:45,647 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'C\\r\\n'\n", - "2026-03-30 12:41:45,675 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'ES\\r\\n'\n", - "2026-03-30 12:41:45,676 - pylabrobot - IO - [MT Scale] Received response: b'ES\\r\\n'\n" - ] - }, - { - "ename": "MettlerToledoError", - "evalue": "Syntax error: The weigh module/balance has not recognized the received command or the command is not allowed", - "output_type": "error", - "traceback": [ - "\u001b[31m---------------------------------------------------------------------------\u001b[39m", - "\u001b[31mMettlerToledoError\u001b[39m Traceback (most recent call last)", - "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[19]\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 backend.cancel_all()\n\u001b[32m 2\u001b[39m \u001b[38;5;28mprint\u001b[39m(\u001b[33m\"\u001b[39m\u001b[33mPASS: cancel_all completed without error\u001b[39m\u001b[33m\"\u001b[39m)\n", - "\u001b[36mFile \u001b[39m\u001b[32m~/Desktop/GitHub/pylabrobot/pylabrobot/scales/mettler_toledo/backend.py:360\u001b[39m, in \u001b[36mMettlerToledoWXS205SDUBackend.cancel_all\u001b[39m\u001b[34m(self)\u001b[39m\n\u001b[32m 350\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[34mcancel_all\u001b[39m(\u001b[38;5;28mself\u001b[39m) -> \u001b[38;5;28;01mNone\u001b[39;00m:\n\u001b[32m 351\u001b[39m \u001b[38;5;250m \u001b[39m\u001b[33;03m\"\"\"C - Cancel all active and pending interface commands.\u001b[39;00m\n\u001b[32m 352\u001b[39m \n\u001b[32m 353\u001b[39m \u001b[33;03m Unlike cancel() (@), this does not reset the device - it only cancels\u001b[39;00m\n\u001b[32m (...)\u001b[39m\u001b[32m 358\u001b[39m \u001b[33;03m C A (complete). Both responses are consumed to keep the serial buffer clean.\u001b[39;00m\n\u001b[32m 359\u001b[39m \u001b[33;03m \"\"\"\u001b[39;00m\n\u001b[32m--> \u001b[39m\u001b[32m360\u001b[39m responses = \u001b[38;5;28;01mawait\u001b[39;00m \u001b[38;5;28mself\u001b[39m.send_command(\u001b[33m\"\u001b[39m\u001b[33mC\u001b[39m\u001b[33m\"\u001b[39m)\n\u001b[32m 361\u001b[39m \u001b[38;5;66;03m# send_command reads both C B (started) and C A (complete) automatically\u001b[39;00m\n\u001b[32m 362\u001b[39m \u001b[38;5;28mself\u001b[39m._validate_response(responses[\u001b[32m0\u001b[39m], \u001b[32m2\u001b[39m, \u001b[33m\"\u001b[39m\u001b[33mC\u001b[39m\u001b[33m\"\u001b[39m)\n", - "\u001b[36mFile \u001b[39m\u001b[32m~/Desktop/GitHub/pylabrobot/pylabrobot/scales/mettler_toledo/backend.py:322\u001b[39m, in \u001b[36mMettlerToledoWXS205SDUBackend.send_command\u001b[39m\u001b[34m(self, command, timeout)\u001b[39m\n\u001b[32m 320\u001b[39m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[32m 321\u001b[39m response = MettlerToledoResponse(command=\u001b[33m\"\u001b[39m\u001b[33m\"\u001b[39m, status=\u001b[33m\"\u001b[39m\u001b[33m\"\u001b[39m, data=[])\n\u001b[32m--> \u001b[39m\u001b[32m322\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[43m.\u001b[49m\u001b[43m_parse_basic_errors\u001b[49m\u001b[43m(\u001b[49m\u001b[43mresponse\u001b[49m\u001b[43m)\u001b[49m\n\u001b[32m 323\u001b[39m responses.append(response)\n\u001b[32m 325\u001b[39m \u001b[38;5;66;03m# Status B means more responses follow; anything else (A, etc.) is final\u001b[39;00m\n", - "\u001b[36mFile \u001b[39m\u001b[32m~/Desktop/GitHub/pylabrobot/pylabrobot/scales/mettler_toledo/backend.py:243\u001b[39m, in \u001b[36mMettlerToledoWXS205SDUBackend._parse_basic_errors\u001b[39m\u001b[34m(self, response)\u001b[39m\n\u001b[32m 241\u001b[39m \u001b[38;5;66;03m# General error messages: ES, ET, EL (status is \"\" for these)\u001b[39;00m\n\u001b[32m 242\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m response.command == \u001b[33m\"\u001b[39m\u001b[33mES\u001b[39m\u001b[33m\"\u001b[39m:\n\u001b[32m--> \u001b[39m\u001b[32m243\u001b[39m \u001b[38;5;28;01mraise\u001b[39;00m MettlerToledoError.syntax_error()\n\u001b[32m 244\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m response.command == \u001b[33m\"\u001b[39m\u001b[33mET\u001b[39m\u001b[33m\"\u001b[39m:\n\u001b[32m 245\u001b[39m \u001b[38;5;28;01mraise\u001b[39;00m MettlerToledoError.transmission_error()\n", - "\u001b[31mMettlerToledoError\u001b[39m: Syntax error: The weigh module/balance has not recognized the received command or the command is not allowed" - ] - } - ], + "outputs": [], "source": [ "await backend.cancel_all()\n", "print(\"PASS: cancel_all completed without error\")" @@ -1300,34 +1018,9 @@ }, { "cell_type": "code", - "execution_count": 20, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2026-03-30 12:41:46,696 - pylabrobot - IO - [MT Scale] Sent command: D \"PLR TEST\"\n", - "2026-03-30 12:41:46,698 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'D \"PLR TEST\"\\r\\n'\n", - "2026-03-30 12:41:46,730 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'ES\\r\\n'\n", - "2026-03-30 12:41:46,733 - pylabrobot - IO - [MT Scale] Received response: b'ES\\r\\n'\n" - ] - }, - { - "ename": "MettlerToledoError", - "evalue": "Syntax error: The weigh module/balance has not recognized the received command or the command is not allowed", - "output_type": "error", - "traceback": [ - "\u001b[31m---------------------------------------------------------------------------\u001b[39m", - "\u001b[31mMettlerToledoError\u001b[39m Traceback (most recent call last)", - "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[20]\u001b[39m\u001b[32m, line 3\u001b[39m\n\u001b[32m 1\u001b[39m \u001b[38;5;28;01mimport\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[34;01masyncio\u001b[39;00m\n\u001b[32m----> \u001b[39m\u001b[32m3\u001b[39m \u001b[38;5;28;01mawait\u001b[39;00m backend.set_display_text(\u001b[33m\"\u001b[39m\u001b[33mPLR TEST\u001b[39m\u001b[33m\"\u001b[39m)\n\u001b[32m 4\u001b[39m \u001b[38;5;28;01mawait\u001b[39;00m asyncio.sleep(\u001b[32m2\u001b[39m)\n\u001b[32m 5\u001b[39m \u001b[38;5;28;01mawait\u001b[39;00m backend.set_weight_display()\n", - "\u001b[36mFile \u001b[39m\u001b[32m~/Desktop/GitHub/pylabrobot/pylabrobot/scales/mettler_toledo/backend.py:692\u001b[39m, in \u001b[36mMettlerToledoWXS205SDUBackend.set_display_text\u001b[39m\u001b[34m(self, text)\u001b[39m\n\u001b[32m 689\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[34mset_display_text\u001b[39m(\u001b[38;5;28mself\u001b[39m, text: \u001b[38;5;28mstr\u001b[39m) -> List[MettlerToledoResponse]:\n\u001b[32m 690\u001b[39m \u001b[38;5;250m \u001b[39m\u001b[33;03m\"\"\"Set the display text of the scale. Return to the normal weight display with\u001b[39;00m\n\u001b[32m 691\u001b[39m \u001b[33;03m self.set_weight_display().\"\"\"\u001b[39;00m\n\u001b[32m--> \u001b[39m\u001b[32m692\u001b[39m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;01mawait\u001b[39;00m \u001b[38;5;28mself\u001b[39m.send_command(\u001b[33mf\u001b[39m\u001b[33m'\u001b[39m\u001b[33mD \u001b[39m\u001b[33m\"\u001b[39m\u001b[38;5;132;01m{\u001b[39;00mtext\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m\"\u001b[39m\u001b[33m'\u001b[39m)\n", - "\u001b[36mFile \u001b[39m\u001b[32m~/Desktop/GitHub/pylabrobot/pylabrobot/scales/mettler_toledo/backend.py:322\u001b[39m, in \u001b[36mMettlerToledoWXS205SDUBackend.send_command\u001b[39m\u001b[34m(self, command, timeout)\u001b[39m\n\u001b[32m 320\u001b[39m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[32m 321\u001b[39m response = MettlerToledoResponse(command=\u001b[33m\"\u001b[39m\u001b[33m\"\u001b[39m, status=\u001b[33m\"\u001b[39m\u001b[33m\"\u001b[39m, data=[])\n\u001b[32m--> \u001b[39m\u001b[32m322\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[43m.\u001b[49m\u001b[43m_parse_basic_errors\u001b[49m\u001b[43m(\u001b[49m\u001b[43mresponse\u001b[49m\u001b[43m)\u001b[49m\n\u001b[32m 323\u001b[39m responses.append(response)\n\u001b[32m 325\u001b[39m \u001b[38;5;66;03m# Status B means more responses follow; anything else (A, etc.) is final\u001b[39;00m\n", - "\u001b[36mFile \u001b[39m\u001b[32m~/Desktop/GitHub/pylabrobot/pylabrobot/scales/mettler_toledo/backend.py:243\u001b[39m, in \u001b[36mMettlerToledoWXS205SDUBackend._parse_basic_errors\u001b[39m\u001b[34m(self, response)\u001b[39m\n\u001b[32m 241\u001b[39m \u001b[38;5;66;03m# General error messages: ES, ET, EL (status is \"\" for these)\u001b[39;00m\n\u001b[32m 242\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m response.command == \u001b[33m\"\u001b[39m\u001b[33mES\u001b[39m\u001b[33m\"\u001b[39m:\n\u001b[32m--> \u001b[39m\u001b[32m243\u001b[39m \u001b[38;5;28;01mraise\u001b[39;00m MettlerToledoError.syntax_error()\n\u001b[32m 244\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m response.command == \u001b[33m\"\u001b[39m\u001b[33mET\u001b[39m\u001b[33m\"\u001b[39m:\n\u001b[32m 245\u001b[39m \u001b[38;5;28;01mraise\u001b[39;00m MettlerToledoError.transmission_error()\n", - "\u001b[31mMettlerToledoError\u001b[39m: Syntax error: The weigh module/balance has not recognized the received command or the command is not allowed" - ] - } - ], + "outputs": [], "source": [ "import asyncio\n", "\n", @@ -1348,32 +1041,9 @@ }, { "cell_type": "code", - "execution_count": 21, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2026-03-30 12:41:47,619 - pylabrobot - IO - [MT Scale] Sent command: ZC 5000\n", - "2026-03-30 12:41:47,621 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'ZC 5000\\r\\n'\n", - "2026-03-30 12:41:47,641 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'ES\\r\\n'\n", - "2026-03-30 12:41:47,642 - pylabrobot - IO - [MT Scale] Received response: b'ES\\r\\n'\n", - "2026-03-30 12:41:47,642 - pylabrobot - IO - [MT Scale] Sent command: TC 5000\n", - "2026-03-30 12:41:47,644 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'TC 5000\\r\\n'\n", - "2026-03-30 12:41:47,674 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'ES\\r\\n'\n", - "2026-03-30 12:41:47,676 - pylabrobot - IO - [MT Scale] Received response: b'ES\\r\\n'\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "ZC: not supported (ES) - expected for WXS205SDU\n", - "TC: not supported (ES) - expected for WXS205SDU\n" - ] - } - ], + "outputs": [], "source": [ "from pylabrobot.scales.mettler_toledo.errors import MettlerToledoError\n", "\n", @@ -1405,27 +1075,9 @@ }, { "cell_type": "code", - "execution_count": 22, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2026-03-30 12:41:49,217 - pylabrobot - IO - [MT Scale] Sent command: M21 0 0\n", - "2026-03-30 12:41:49,219 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'M21 0 0\\r\\n'\n", - "2026-03-30 12:41:49,256 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M21 A\\r\\n'\n", - "2026-03-30 12:41:49,258 - pylabrobot - IO - [MT Scale] Received response: b'M21 A\\r\\n'\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "PASS: host unit set to grams\n" - ] - } - ], + "outputs": [], "source": [ "if \"M21\" in backend._supported_commands:\n", " await backend.set_host_unit_grams()\n", @@ -1443,17 +1095,9 @@ }, { "cell_type": "code", - "execution_count": 23, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "SKIP: I50 not supported on this device\n" - ] - } - ], + "outputs": [], "source": [ "if \"I50\" in backend._supported_commands:\n", " remaining = await backend.request_remaining_weighing_range()\n", @@ -1474,30 +1118,9 @@ }, { "cell_type": "code", - "execution_count": 24, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2026-03-30 12:41:53,996 - pylabrobot - IO - [MT Scale] Sent command: M28\n", - "2026-03-30 12:41:53,999 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'M28\\r\\n'\n", - "2026-03-30 12:41:54,035 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M28 B 1 20.0\\r\\n'\n", - "2026-03-30 12:41:54,036 - pylabrobot - IO - [MT Scale] Received response: b'M28 B 1 20.0\\r\\n'\n", - "2026-03-30 12:41:54,052 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M28 A 2 19.5\\r\\n'\n", - "2026-03-30 12:41:54,053 - pylabrobot - IO - [MT Scale] Received response: b'M28 A 2 19.5\\r\\n'\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Scale temperature: 20.0 C\n", - "PASS: measure_temperature works - I0 correctly predicted M28 support\n" - ] - } - ], + "outputs": [], "source": [ "if \"M28\" in backend._supported_commands:\n", " temp = await backend.measure_temperature()\n", @@ -1520,70 +1143,9 @@ }, { "cell_type": "code", - "execution_count": 27, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2026-03-30 12:41:58,382 - pylabrobot - IO - [MT Scale] Sent command: Z\n", - "2026-03-30 12:41:58,384 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'Z\\r\\n'\n", - "2026-03-30 12:41:58,735 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'Z A\\r\\n'\n", - "2026-03-30 12:41:58,736 - pylabrobot - IO - [MT Scale] Received response: b'Z A\\r\\n'\n", - "2026-03-30 12:41:58,737 - pylabrobot - IO - [MT Scale] Sent command: SI\n", - "2026-03-30 12:41:58,738 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", - "2026-03-30 12:41:58,767 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 12:41:58,769 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Frontend zero + read: 0.0 g\n" - ] - }, - { - "name": "stdin", - "output_type": "stream", - "text": [ - "Place a container on the scale and press Enter... \n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2026-03-30 12:41:59,512 - pylabrobot - IO - [MT Scale] Sent command: T\n", - "2026-03-30 12:41:59,514 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'T\\r\\n'\n", - "2026-03-30 12:41:59,934 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'T S 0.00000 g\\r\\n'\n", - "2026-03-30 12:41:59,935 - pylabrobot - IO - [MT Scale] Received response: b'T S 0.00000 g\\r\\n'\n", - "2026-03-30 12:41:59,936 - pylabrobot - IO - [MT Scale] Sent command: TA\n", - "2026-03-30 12:41:59,938 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'TA\\r\\n'\n", - "2026-03-30 12:42:00,032 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'TA A 0.00000 g\\r\\n'\n", - "2026-03-30 12:42:00,033 - pylabrobot - IO - [MT Scale] Received response: b'TA A 0.00000 g\\r\\n'\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Frontend tare weight: 0.0 g\n" - ] - }, - { - "ename": "AssertionError", - "evalue": "", - "output_type": "error", - "traceback": [ - "\u001b[31m---------------------------------------------------------------------------\u001b[39m", - "\u001b[31mAssertionError\u001b[39m Traceback (most recent call last)", - "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[27]\u001b[39m\u001b[32m, line 12\u001b[39m\n\u001b[32m 10\u001b[39m tare = \u001b[38;5;28;01mawait\u001b[39;00m scale.request_tare_weight()\n\u001b[32m 11\u001b[39m \u001b[38;5;28mprint\u001b[39m(\u001b[33mf\u001b[39m\u001b[33m\"\u001b[39m\u001b[33mFrontend tare weight: \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mtare\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m g\u001b[39m\u001b[33m\"\u001b[39m)\n\u001b[32m---> \u001b[39m\u001b[32m12\u001b[39m \u001b[38;5;28;01massert\u001b[39;00m tare > \u001b[32m0\u001b[39m\n\u001b[32m 14\u001b[39m \u001b[38;5;66;03m# Read via frontend\u001b[39;00m\n\u001b[32m 15\u001b[39m w = \u001b[38;5;28;01mawait\u001b[39;00m scale.read_weight(timeout=\u001b[33m\"\u001b[39m\u001b[33mstable\u001b[39m\u001b[33m\"\u001b[39m)\n", - "\u001b[31mAssertionError\u001b[39m: " - ] - } - ], + "outputs": [], "source": [ "# Zero via frontend\n", "await scale.zero(timeout=\"stable\")\n", @@ -1616,104 +1178,9 @@ }, { "cell_type": "code", - "execution_count": 28, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2026-03-30 12:42:01,466 - pylabrobot - IO - [MT Scale] Sent command: S\n", - "2026-03-30 12:42:01,471 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", - "2026-03-30 12:42:01,605 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 12:42:01,614 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 12:42:01,622 - pylabrobot - IO - [MT Scale] Sent command: S\n", - "2026-03-30 12:42:01,628 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", - "2026-03-30 12:42:01,693 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 12:42:01,694 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 12:42:01,695 - pylabrobot - IO - [MT Scale] Sent command: S\n", - "2026-03-30 12:42:01,699 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", - "2026-03-30 12:42:01,804 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 12:42:01,805 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 12:42:01,807 - pylabrobot - IO - [MT Scale] Sent command: S\n", - "2026-03-30 12:42:01,810 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", - "2026-03-30 12:42:01,900 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 12:42:01,901 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 12:42:01,903 - pylabrobot - IO - [MT Scale] Sent command: S\n", - "2026-03-30 12:42:01,904 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", - "2026-03-30 12:42:01,996 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 12:42:01,997 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 12:42:01,998 - pylabrobot - IO - [MT Scale] Sent command: S\n", - "2026-03-30 12:42:01,999 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", - "2026-03-30 12:42:02,093 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 12:42:02,093 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 12:42:02,095 - pylabrobot - IO - [MT Scale] Sent command: S\n", - "2026-03-30 12:42:02,096 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", - "2026-03-30 12:42:02,188 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 12:42:02,189 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 12:42:02,190 - pylabrobot - IO - [MT Scale] Sent command: S\n", - "2026-03-30 12:42:02,192 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", - "2026-03-30 12:42:02,286 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 12:42:02,288 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 12:42:02,289 - pylabrobot - IO - [MT Scale] Sent command: S\n", - "2026-03-30 12:42:02,293 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", - "2026-03-30 12:42:02,397 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 12:42:02,400 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 12:42:02,401 - pylabrobot - IO - [MT Scale] Sent command: S\n", - "2026-03-30 12:42:02,403 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", - "2026-03-30 12:42:02,492 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 12:42:02,493 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 12:42:02,494 - pylabrobot - IO - [MT Scale] Sent command: SI\n", - "2026-03-30 12:42:02,497 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", - "2026-03-30 12:42:02,540 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 12:42:02,541 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 12:42:02,542 - pylabrobot - IO - [MT Scale] Sent command: SI\n", - "2026-03-30 12:42:02,545 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", - "2026-03-30 12:42:02,588 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 12:42:02,591 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 12:42:02,592 - pylabrobot - IO - [MT Scale] Sent command: SI\n", - "2026-03-30 12:42:02,597 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", - "2026-03-30 12:42:02,636 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 12:42:02,637 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 12:42:02,638 - pylabrobot - IO - [MT Scale] Sent command: SI\n", - "2026-03-30 12:42:02,640 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", - "2026-03-30 12:42:02,686 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 12:42:02,691 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 12:42:02,700 - pylabrobot - IO - [MT Scale] Sent command: SI\n", - "2026-03-30 12:42:02,704 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", - "2026-03-30 12:42:02,733 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 12:42:02,735 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 12:42:02,736 - pylabrobot - IO - [MT Scale] Sent command: SI\n", - "2026-03-30 12:42:02,738 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", - "2026-03-30 12:42:02,779 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 12:42:02,780 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 12:42:02,782 - pylabrobot - IO - [MT Scale] Sent command: SI\n", - "2026-03-30 12:42:02,784 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", - "2026-03-30 12:42:02,814 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 12:42:02,815 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 12:42:02,816 - pylabrobot - IO - [MT Scale] Sent command: SI\n", - "2026-03-30 12:42:02,818 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", - "2026-03-30 12:42:02,859 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 12:42:02,860 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 12:42:02,862 - pylabrobot - IO - [MT Scale] Sent command: SI\n", - "2026-03-30 12:42:02,866 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", - "2026-03-30 12:42:02,907 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 12:42:02,908 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 12:42:02,922 - pylabrobot - IO - [MT Scale] Sent command: SI\n", - "2026-03-30 12:42:02,929 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", - "2026-03-30 12:42:02,971 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 12:42:02,973 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Stable read: 102.77 +/- 20.34 ms\n", - "Immediate read: 47.95 +/- 8.21 ms\n" - ] - } - ], + "outputs": [], "source": [ "import time\n", "\n", @@ -1749,30 +1216,9 @@ }, { "cell_type": "code", - "execution_count": 29, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2026-03-30 12:42:03,097 - pylabrobot - INFO - === Hardware validation ended ===\n", - "2026-03-30 12:42:03,101 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] reset_input_buffer\n", - "2026-03-30 12:42:03,109 - pylabrobot - IO - [MT Scale] Sent command: @\n", - "2026-03-30 12:42:03,112 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'@\\r\\n'\n", - "2026-03-30 12:42:03,163 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I4 A \"B207696838\"\\r\\n'\n", - "2026-03-30 12:42:03,164 - pylabrobot - IO - [MT Scale] Received response: b'I4 A \"B207696838\"\\r\\n'\n", - "2026-03-30 12:42:03,167 - pylabrobot - INFO - [MT Scale] Disconnected from /dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Log file: ./logs/hardware_validation/2026-03-30_12-40-59_validation.log\n" - ] - } - ], + "outputs": [], "source": [ "plr_logger.info(\"=== Hardware validation ended ===\")\n", "await scale.stop()\n", From 46696bb77dc1b3ec75e183e948d403691d1b2218 Mon Sep 17 00:00:00 2001 From: Camillo Moschner Date: Mon, 30 Mar 2026 13:11:46 +0100 Subject: [PATCH 23/38] create batch 2 and 3 commandshave --- .../scales/mettler-toledo-WXS205SDU.ipynb | 146 +++++++------- pylabrobot/scales/mettler_toledo/backend.py | 184 +++++++++++++++++- .../scales/mettler_toledo/backend_tests.py | 86 ++++++++ .../confirmed_firmware_versions.py | 15 ++ .../mettler_toledo/hardware_validation.ipynb | 165 ++-------------- pylabrobot/scales/mettler_toledo/simulator.py | 32 +++ 6 files changed, 400 insertions(+), 228 deletions(-) create mode 100644 pylabrobot/scales/mettler_toledo/confirmed_firmware_versions.py diff --git a/docs/user_guide/02_analytical/scales/mettler-toledo-WXS205SDU.ipynb b/docs/user_guide/02_analytical/scales/mettler-toledo-WXS205SDU.ipynb index df645975032..40724404423 100644 --- a/docs/user_guide/02_analytical/scales/mettler-toledo-WXS205SDU.ipynb +++ b/docs/user_guide/02_analytical/scales/mettler-toledo-WXS205SDU.ipynb @@ -59,10 +59,10 @@ "execution_count": 1, "metadata": { "execution": { - "iopub.execute_input": "2026-03-30T11:39:54.007551Z", - "iopub.status.busy": "2026-03-30T11:39:54.007435Z", - "iopub.status.idle": "2026-03-30T11:39:54.011117Z", - "shell.execute_reply": "2026-03-30T11:39:54.010830Z" + "iopub.execute_input": "2026-03-30T12:01:11.722108Z", + "iopub.status.busy": "2026-03-30T12:01:11.721949Z", + "iopub.status.idle": "2026-03-30T12:01:11.725764Z", + "shell.execute_reply": "2026-03-30T12:01:11.725399Z" } }, "outputs": [], @@ -88,10 +88,10 @@ "execution_count": 2, "metadata": { "execution": { - "iopub.execute_input": "2026-03-30T11:39:54.012846Z", - "iopub.status.busy": "2026-03-30T11:39:54.012717Z", - "iopub.status.idle": "2026-03-30T11:39:54.061748Z", - "shell.execute_reply": "2026-03-30T11:39:54.061557Z" + "iopub.execute_input": "2026-03-30T12:01:11.727610Z", + "iopub.status.busy": "2026-03-30T12:01:11.727461Z", + "iopub.status.idle": "2026-03-30T12:01:11.778818Z", + "shell.execute_reply": "2026-03-30T12:01:11.778624Z" } }, "outputs": [ @@ -99,7 +99,7 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 12:39:54,060 - pylabrobot - INFO - === MT Scale tutorial started ===\n" + "2026-03-30 13:01:11,777 - pylabrobot - INFO - === MT Scale tutorial started ===\n" ] } ], @@ -124,10 +124,10 @@ "execution_count": 3, "metadata": { "execution": { - "iopub.execute_input": "2026-03-30T11:39:54.077280Z", - "iopub.status.busy": "2026-03-30T11:39:54.077180Z", - "iopub.status.idle": "2026-03-30T11:39:54.139082Z", - "shell.execute_reply": "2026-03-30T11:39:54.138910Z" + "iopub.execute_input": "2026-03-30T12:01:11.795670Z", + "iopub.status.busy": "2026-03-30T12:01:11.795553Z", + "iopub.status.idle": "2026-03-30T12:01:11.848893Z", + "shell.execute_reply": "2026-03-30T12:01:11.848711Z" } }, "outputs": [ @@ -135,9 +135,11 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 12:39:54,137 - pylabrobot - INFO - [MT Scale] Connected to Mettler Toledo scale (simulation)\n", + "2026-03-30 13:01:11,847 - pylabrobot - INFO - [MT Scale] Connected to Mettler Toledo scale (simulation)\n", "Device type: WXS205SDU\n", + "Configuration: Balance\n", "Serial number: SIM0000001\n", + "Firmware: 1.10 18.6.4.1361.772\n", "Capacity: 220.0 g\n", "Supported commands: ['@', 'C', 'D', 'DAT', 'DW', 'I0', 'I1', 'I10', 'I11', 'I14', 'I15', 'I2', 'I3', 'I4', 'I5', 'I50', 'M21', 'M28', 'S', 'SC', 'SI', 'SIR', 'SR', 'T', 'TA', 'TAC', 'TC', 'TI', 'TIM', 'Z', 'ZC', 'ZI']\n" ] @@ -207,10 +209,10 @@ "execution_count": 4, "metadata": { "execution": { - "iopub.execute_input": "2026-03-30T11:39:54.140106Z", - "iopub.status.busy": "2026-03-30T11:39:54.140043Z", - "iopub.status.idle": "2026-03-30T11:39:54.141851Z", - "shell.execute_reply": "2026-03-30T11:39:54.141688Z" + "iopub.execute_input": "2026-03-30T12:01:11.850228Z", + "iopub.status.busy": "2026-03-30T12:01:11.850139Z", + "iopub.status.idle": "2026-03-30T12:01:11.852160Z", + "shell.execute_reply": "2026-03-30T12:01:11.851968Z" } }, "outputs": [ @@ -218,14 +220,14 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 12:39:54,140 - pylabrobot - IO - [MT Scale] Sent command: ZC 5000\n" + "2026-03-30 13:01:11,850 - pylabrobot - IO - [MT Scale] Sent command: ZC 5000\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 12:39:54,140 - pylabrobot - IO - [MT Scale] Received response: ZC A \n" + "2026-03-30 13:01:11,850 - pylabrobot - IO - [MT Scale] Received response: ZC A \n" ] } ], @@ -259,10 +261,10 @@ "execution_count": 5, "metadata": { "execution": { - "iopub.execute_input": "2026-03-30T11:39:54.142831Z", - "iopub.status.busy": "2026-03-30T11:39:54.142766Z", - "iopub.status.idle": "2026-03-30T11:39:54.144510Z", - "shell.execute_reply": "2026-03-30T11:39:54.144357Z" + "iopub.execute_input": "2026-03-30T12:01:11.853205Z", + "iopub.status.busy": "2026-03-30T12:01:11.853148Z", + "iopub.status.idle": "2026-03-30T12:01:11.855046Z", + "shell.execute_reply": "2026-03-30T12:01:11.854876Z" } }, "outputs": [ @@ -270,14 +272,14 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 12:39:54,143 - pylabrobot - IO - [MT Scale] Sent command: TC 5000\n" + "2026-03-30 13:01:11,853 - pylabrobot - IO - [MT Scale] Sent command: TC 5000\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 12:39:54,143 - pylabrobot - IO - [MT Scale] Received response: TC S 50.00000 g\n" + "2026-03-30 13:01:11,853 - pylabrobot - IO - [MT Scale] Received response: TC S 50.00000 g\n" ] } ], @@ -300,10 +302,10 @@ "execution_count": 6, "metadata": { "execution": { - "iopub.execute_input": "2026-03-30T11:39:54.145365Z", - "iopub.status.busy": "2026-03-30T11:39:54.145307Z", - "iopub.status.idle": "2026-03-30T11:39:54.147713Z", - "shell.execute_reply": "2026-03-30T11:39:54.147548Z" + "iopub.execute_input": "2026-03-30T12:01:11.855951Z", + "iopub.status.busy": "2026-03-30T12:01:11.855881Z", + "iopub.status.idle": "2026-03-30T12:01:11.858966Z", + "shell.execute_reply": "2026-03-30T12:01:11.858798Z" } }, "outputs": [ @@ -311,14 +313,14 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 12:39:54,145 - pylabrobot - IO - [MT Scale] Sent command: TA\n" + "2026-03-30 13:01:11,856 - pylabrobot - IO - [MT Scale] Sent command: TA\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 12:39:54,145 - pylabrobot - IO - [MT Scale] Received response: TA A 50.00000 g\n" + "2026-03-30 13:01:11,856 - pylabrobot - IO - [MT Scale] Received response: TA A 50.00000 g\n" ] }, { @@ -351,10 +353,10 @@ "execution_count": 7, "metadata": { "execution": { - "iopub.execute_input": "2026-03-30T11:39:54.148612Z", - "iopub.status.busy": "2026-03-30T11:39:54.148553Z", - "iopub.status.idle": "2026-03-30T11:39:54.150500Z", - "shell.execute_reply": "2026-03-30T11:39:54.150349Z" + "iopub.execute_input": "2026-03-30T12:01:11.859830Z", + "iopub.status.busy": "2026-03-30T12:01:11.859763Z", + "iopub.status.idle": "2026-03-30T12:01:11.861851Z", + "shell.execute_reply": "2026-03-30T12:01:11.861685Z" } }, "outputs": [ @@ -362,14 +364,14 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 12:39:54,148 - pylabrobot - IO - [MT Scale] Sent command: SI\n" + "2026-03-30 13:01:11,860 - pylabrobot - IO - [MT Scale] Sent command: SI\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 12:39:54,149 - pylabrobot - IO - [MT Scale] Received response: SI S 0.01060 g\n" + "2026-03-30 13:01:11,860 - pylabrobot - IO - [MT Scale] Received response: SI S 0.01060 g\n" ] }, { @@ -405,10 +407,10 @@ "execution_count": 8, "metadata": { "execution": { - "iopub.execute_input": "2026-03-30T11:39:54.151381Z", - "iopub.status.busy": "2026-03-30T11:39:54.151322Z", - "iopub.status.idle": "2026-03-30T11:39:54.154524Z", - "shell.execute_reply": "2026-03-30T11:39:54.154304Z" + "iopub.execute_input": "2026-03-30T12:01:11.862744Z", + "iopub.status.busy": "2026-03-30T12:01:11.862691Z", + "iopub.status.idle": "2026-03-30T12:01:11.865675Z", + "shell.execute_reply": "2026-03-30T12:01:11.865501Z" } }, "outputs": [ @@ -416,42 +418,42 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 12:39:54,152 - pylabrobot - IO - [MT Scale] Sent command: Z\n" + "2026-03-30 13:01:11,863 - pylabrobot - IO - [MT Scale] Sent command: Z\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 12:39:54,152 - pylabrobot - IO - [MT Scale] Received response: Z A \n" + "2026-03-30 13:01:11,863 - pylabrobot - IO - [MT Scale] Received response: Z A \n" ] }, { "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 12:39:54,152 - pylabrobot - IO - [MT Scale] Sent command: TC 5000\n" + "2026-03-30 13:01:11,863 - pylabrobot - IO - [MT Scale] Sent command: TC 5000\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 12:39:54,152 - pylabrobot - IO - [MT Scale] Received response: TC S -0.01060 g\n" + "2026-03-30 13:01:11,864 - pylabrobot - IO - [MT Scale] Received response: TC S -0.01060 g\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 12:39:54,153 - pylabrobot - IO - [MT Scale] Sent command: SC 5000\n" + "2026-03-30 13:01:11,864 - pylabrobot - IO - [MT Scale] Sent command: SC 5000\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 12:39:54,153 - pylabrobot - IO - [MT Scale] Received response: SC S 0.01060 g\n" + "2026-03-30 13:01:11,864 - pylabrobot - IO - [MT Scale] Received response: SC S 0.01060 g\n" ] }, { @@ -522,10 +524,10 @@ "execution_count": 9, "metadata": { "execution": { - "iopub.execute_input": "2026-03-30T11:39:54.155465Z", - "iopub.status.busy": "2026-03-30T11:39:54.155403Z", - "iopub.status.idle": "2026-03-30T11:39:54.157630Z", - "shell.execute_reply": "2026-03-30T11:39:54.157421Z" + "iopub.execute_input": "2026-03-30T12:01:11.866619Z", + "iopub.status.busy": "2026-03-30T12:01:11.866564Z", + "iopub.status.idle": "2026-03-30T12:01:11.868851Z", + "shell.execute_reply": "2026-03-30T12:01:11.868707Z" } }, "outputs": [ @@ -533,28 +535,28 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 12:39:54,155 - pylabrobot - IO - [MT Scale] Sent command: I50\n" + "2026-03-30 13:01:11,866 - pylabrobot - IO - [MT Scale] Sent command: I50\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 12:39:54,156 - pylabrobot - IO - [MT Scale] Received response: I50 B 0 173.940 g\n" + "2026-03-30 13:01:11,867 - pylabrobot - IO - [MT Scale] Received response: I50 B 0 173.940 g\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 12:39:54,156 - pylabrobot - IO - [MT Scale] Received response: I50 B 1 0.000 g\n" + "2026-03-30 13:01:11,867 - pylabrobot - IO - [MT Scale] Received response: I50 B 1 0.000 g\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 12:39:54,156 - pylabrobot - IO - [MT Scale] Received response: I50 A 2 173.940 g\n" + "2026-03-30 13:01:11,867 - pylabrobot - IO - [MT Scale] Received response: I50 A 2 173.940 g\n" ] }, { @@ -585,10 +587,10 @@ "execution_count": 10, "metadata": { "execution": { - "iopub.execute_input": "2026-03-30T11:39:54.158514Z", - "iopub.status.busy": "2026-03-30T11:39:54.158456Z", - "iopub.status.idle": "2026-03-30T11:39:54.160205Z", - "shell.execute_reply": "2026-03-30T11:39:54.160072Z" + "iopub.execute_input": "2026-03-30T12:01:11.869863Z", + "iopub.status.busy": "2026-03-30T12:01:11.869812Z", + "iopub.status.idle": "2026-03-30T12:01:11.871621Z", + "shell.execute_reply": "2026-03-30T12:01:11.871465Z" } }, "outputs": [ @@ -596,14 +598,14 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 12:39:54,158 - pylabrobot - IO - [MT Scale] Sent command: M28\n" + "2026-03-30 13:01:11,870 - pylabrobot - IO - [MT Scale] Sent command: M28\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 12:39:54,158 - pylabrobot - IO - [MT Scale] Received response: M28 A 1 22.5\n" + "2026-03-30 13:01:11,870 - pylabrobot - IO - [MT Scale] Received response: M28 A 1 22.5\n" ] }, { @@ -637,10 +639,10 @@ "execution_count": 11, "metadata": { "execution": { - "iopub.execute_input": "2026-03-30T11:39:54.161093Z", - "iopub.status.busy": "2026-03-30T11:39:54.161022Z", - "iopub.status.idle": "2026-03-30T11:39:54.162575Z", - "shell.execute_reply": "2026-03-30T11:39:54.162432Z" + "iopub.execute_input": "2026-03-30T12:01:11.872604Z", + "iopub.status.busy": "2026-03-30T12:01:11.872550Z", + "iopub.status.idle": "2026-03-30T12:01:11.874253Z", + "shell.execute_reply": "2026-03-30T12:01:11.874029Z" } }, "outputs": [], @@ -685,10 +687,10 @@ "execution_count": 12, "metadata": { "execution": { - "iopub.execute_input": "2026-03-30T11:39:54.163442Z", - "iopub.status.busy": "2026-03-30T11:39:54.163385Z", - "iopub.status.idle": "2026-03-30T11:39:54.165227Z", - "shell.execute_reply": "2026-03-30T11:39:54.165070Z" + "iopub.execute_input": "2026-03-30T12:01:11.875149Z", + "iopub.status.busy": "2026-03-30T12:01:11.875093Z", + "iopub.status.idle": "2026-03-30T12:01:11.876950Z", + "shell.execute_reply": "2026-03-30T12:01:11.876744Z" } }, "outputs": [ @@ -696,14 +698,14 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 12:39:54,163 - pylabrobot - INFO - === MT Scale tutorial ended ===\n" + "2026-03-30 13:01:11,875 - pylabrobot - INFO - === MT Scale tutorial ended ===\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 12:39:54,164 - pylabrobot - INFO - [MT Scale] Disconnected (simulation)\n" + "2026-03-30 13:01:11,875 - pylabrobot - INFO - [MT Scale] Disconnected (simulation)\n" ] } ], diff --git a/pylabrobot/scales/mettler_toledo/backend.py b/pylabrobot/scales/mettler_toledo/backend.py index a3f294b09e9..688850c2266 100644 --- a/pylabrobot/scales/mettler_toledo/backend.py +++ b/pylabrobot/scales/mettler_toledo/backend.py @@ -12,6 +12,7 @@ from pylabrobot.io.serial import Serial from pylabrobot.io.validation_utils import LOG_LEVEL_IO +from pylabrobot.scales.mettler_toledo.confirmed_firmware_versions import CONFIRMED_FIRMWARE_VERSIONS from pylabrobot.scales.mettler_toledo.errors import MettlerToledoError from pylabrobot.scales.scale_backend import ScaleBackend @@ -117,19 +118,38 @@ async def setup(self) -> None: self.device_type = await self.request_device_type() self.capacity = await self.request_capacity() + # Firmware version and configuration + self.firmware_version = await self.request_software_version() + # I2 device_type encodes the configuration: "WXS205SDU WXA-Bridge" = bridge only + self.configuration = "Bridge" if "Bridge" in self.device_type else "Balance" + logger.info( "[MT Scale] Connected to Mettler Toledo scale on %s\n" "Device type: %s\n" + "Configuration: %s\n" "Serial number: %s\n" + "Firmware: %s\n" "Capacity: %.1f g\n" "Supported commands: %s", self.io.port, self.device_type, + self.configuration, self.serial_number, + self.firmware_version, self.capacity, sorted(self._supported_commands), ) + # Check major.minor version only (TDNR varies by hardware revision) + fw_version_short = self.firmware_version.split()[0] if self.firmware_version else "" + if fw_version_short not in CONFIRMED_FIRMWARE_VERSIONS: + logger.warning( + "[MT Scale] Firmware version %r has not been tested with this driver. " + "Confirmed versions: %s. Proceed with caution.", + self.firmware_version, + ", ".join(sorted(CONFIRMED_FIRMWARE_VERSIONS)), + ) + # Set output unit to grams if "M21" in self._supported_commands: await self.set_host_unit_grams() @@ -454,15 +474,21 @@ async def request_model_designation(self) -> str: return responses[0].data[0] @requires_mt_sics_command("I14") - async def request_device_info(self) -> List[MettlerToledoResponse]: - """Query detailed device information including all components. (I14 command) + async def request_device_info(self, category: int = 0) -> List[MettlerToledoResponse]: + """Query detailed device information for a specific category. (I14 command) - Returns multi-response with instrument configuration (No=0), - descriptions (No=1), SW identification numbers (No=2), - SW versions (No=3), serial numbers (No=4), and TDNR numbers (No=5). - Each category reports data for bridge, terminal, options, etc. + Args: + category: Information category to query: + 0 = instrument configuration (Bridge, Terminal, Option) + 1 = instrument descriptions (model names) + 2 = SW identification numbers + 3 = SW versions + 4 = serial numbers + 5 = TDNR (type definition) numbers + + Returns multi-response with data for each component (bridge, terminal, etc.). """ - return await self.send_command("I14") + return await self.send_command(f"I14 {category}") @requires_mt_sics_command("I15") async def request_uptime(self) -> dict: @@ -729,3 +755,147 @@ async def measure_temperature(self) -> float: # M28 A 1 22.5 (single sensor) or M28 B 1 22.5 ... M28 A 2 23.0 (multi-sensor) self._validate_response(responses[0], 4, "M28") return float(responses[0].data[1]) + + # # Batch 2 - Configuration queries (read-only) # # + + @requires_mt_sics_command("M01") + async def request_weighing_mode(self) -> int: + """Query the current weighing mode. (M01 command) + + Returns: 0=Normal/Universal, 1=Dosing, 2=Sensor, 3=Check weighing, 6=Raw/No filter. + """ + responses = await self.send_command("M01") + self._validate_response(responses[0], 3, "M01") + return int(responses[0].data[0]) + + @requires_mt_sics_command("M02") + async def request_environment_condition(self) -> int: + """Query the current environment condition setting. (M02 command) + + Returns: 0=Very stable, 1=Stable, 2=Standard, 3=Unstable, 4=Very unstable, 5=Automatic. + Affects the scale's internal filter and stability detection. + """ + responses = await self.send_command("M02") + self._validate_response(responses[0], 3, "M02") + return int(responses[0].data[0]) + + @requires_mt_sics_command("M03") + async def request_auto_zero(self) -> int: + """Query the current auto zero setting. (M03 command) + + Returns: 0=off, 1=on. Auto zero compensates for slow drift + (e.g. evaporation, temperature changes) by automatically + re-zeroing when the weight is near zero and stable. + """ + responses = await self.send_command("M03") + self._validate_response(responses[0], 3, "M03") + return int(responses[0].data[0]) + + @requires_mt_sics_command("M27") + async def request_adjustment_history(self) -> List[MettlerToledoResponse]: + """Query the adjustment (calibration) history. (M27 command) + + Returns multi-response with each adjustment entry containing: + entry number, date, time, mode (0=built-in, 1=external), and weight used. + """ + return await self.send_command("M27") + + @requires_mt_sics_command("SIS") + async def request_net_weight_with_status(self) -> MettlerToledoResponse: + """Query net weight with unit and weighing status. (SIS command) + + Returns a single response with weight value, unit, and additional + status information (actual unit and weighing status) in one call. + """ + responses = await self.send_command("SIS") + return responses[0] + + @requires_mt_sics_command("SNR") + async def read_stable_weight_repeat_on_change(self) -> List[MettlerToledoResponse]: + """Start sending stable weight values on every stable weight change. (SNR command) + + The device will send a new weight value each time the weight changes + and stabilizes. Use cancel() or cancel_all() to stop. + """ + return await self.send_command("SNR") + + @requires_mt_sics_command("UPD") + async def request_update_rate(self) -> float: + """Query the current update rate for SIR/SIRU streaming commands. (UPD command) + + Returns the update rate in values per second. + """ + responses = await self.send_command("UPD") + self._validate_response(responses[0], 3, "UPD") + return float(responses[0].data[0]) + + # WARNING: The following set commands permanently modify device settings. + # They persist across power cycles and cannot be undone with @ cancel. + # The only way to reset is via FSET (factory reset) or terminal menu. + # + # @requires_mt_sics_command("M01") + # async def set_weighing_mode(self, mode: int) -> None: + # """Set the weighing mode. (M01 command) WRITES TO DEVICE MEMORY. + # 0=Normal, 1=Dosing, 2=Sensor, 3=Check weighing, 6=Raw/No filter.""" + # await self.send_command(f"M01 {mode}") + # + # @requires_mt_sics_command("M02") + # async def set_environment_condition(self, condition: int) -> None: + # """Set the environment condition. (M02 command) WRITES TO DEVICE MEMORY. + # 0=Very stable, 1=Stable, 2=Standard, 3=Unstable, 4=Very unstable, 5=Automatic.""" + # await self.send_command(f"M02 {condition}") + # + # @requires_mt_sics_command("M03") + # async def set_auto_zero(self, enabled: int) -> None: + # """Set the auto zero function. (M03 command) WRITES TO DEVICE MEMORY. + # 0=off, 1=on.""" + # await self.send_command(f"M03 {enabled}") + # + # @requires_mt_sics_command("UPD") + # async def set_update_rate(self, rate: float) -> None: + # """Set the update rate for SIR/SIRU. (UPD command) WRITES TO DEVICE MEMORY.""" + # await self.send_command(f"UPD {rate}") + # + # @requires_mt_sics_command("COM") + # async def set_serial_parameters(self, ...) -> None: + # """Set serial port parameters. (COM command) WRITES TO DEVICE MEMORY. + # WARNING: changing baud rate will lose communication.""" + # ... + # + # @requires_mt_sics_command("FSET") + # async def factory_reset(self, exclusion: int = 0) -> None: + # """Reset ALL settings to factory defaults. (FSET command) DESTRUCTIVE. + # 0=reset all, 1=keep comm params, 2=keep comm+adjustment.""" + # await self.send_command(f"FSET {exclusion}") + + # # Batch 3 - Calibration and streaming (require physical interaction or architecture changes) # # + + # WARNING: Adjustment commands move internal calibration weights. + # Do not run during a weighing protocol. + # + # @requires_mt_sics_command("C1") + # async def start_adjustment(self) -> List[MettlerToledoResponse]: + # """Start adjustment according to current settings. (C1 command) + # Multi-response: sends progress updates until complete.""" + # return await self.send_command("C1") + # + # @requires_mt_sics_command("C3") + # async def start_adjustment_builtin_weight(self) -> List[MettlerToledoResponse]: + # """Start adjustment with built-in weight. (C3 command) + # Multi-response: sends progress updates until complete.""" + # return await self.send_command("C3") + + # NOTE: SIR and SR streaming commands require an async iterator or callback + # architecture to handle continuous responses. Not yet implemented. + # + # @requires_mt_sics_command("SIR") + # async def read_weight_immediately_repeat(self) -> ...: + # """Start streaming weight values at the update rate. (SIR command) + # Use cancel() to stop.""" + # ... + # + # @requires_mt_sics_command("SR") + # async def read_stable_weight_repeat(self) -> ...: + # """Start sending stable weight on any weight change. (SR command) + # Use cancel() to stop.""" + # ... diff --git a/pylabrobot/scales/mettler_toledo/backend_tests.py b/pylabrobot/scales/mettler_toledo/backend_tests.py index da4c54006c7..f1ea0396773 100644 --- a/pylabrobot/scales/mettler_toledo/backend_tests.py +++ b/pylabrobot/scales/mettler_toledo/backend_tests.py @@ -185,6 +185,92 @@ async def test_measure_temperature_blocked_when_unsupported(self): self.assertIn("M28", str(ctx.exception)) self.assertIn("not implemented", str(ctx.exception)) + async def test_uptime_single_value_format(self): + """Some devices return uptime as a single number (total days) instead of + days/hours/minutes/seconds. The parser must handle both formats.""" + # Default simulator returns multi-value format + uptime = await self.backend.request_uptime() + self.assertEqual(uptime["days"], 42) + self.assertEqual(uptime["hours"], 3) + + async def test_uptime_single_value_fallback(self): + """When the device returns a single uptime value, hours/minutes/seconds + must default to 0. This format was discovered on the WXS205SDU hardware.""" + backend = MettlerToledoSICSSimulator() + scale = Scale(name="s", backend=backend, size_x=0, size_y=0, size_z=0) + await scale.setup() + # Patch the simulator to return single-value format + original = backend._build_response + + def patched(command): + if command.split()[0] == "I15": + return [MettlerToledoResponse("I15", "A", ["203"])] + return original(command) + + backend._build_response = patched + uptime = await backend.request_uptime() + self.assertEqual(uptime["days"], 203) + self.assertEqual(uptime["hours"], 0) + + async def test_configuration_bridge_detection(self): + """Device type containing 'Bridge' must set configuration to 'Bridge'. + This determines which commands are expected to work (no display commands + in bridge mode).""" + backend = MettlerToledoSICSSimulator(device_type="WXS205SDU WXA-Bridge") + scale = Scale(name="s", backend=backend, size_x=0, size_y=0, size_z=0) + await scale.setup() + self.assertEqual(backend.configuration, "Bridge") + + async def test_shlex_preserves_quoted_strings_with_spaces(self): + """The I2 response packs type, capacity, and unit into one quoted string. + shlex must keep the quoted content as a single token. This bug broke + hardware validation before the shlex fix.""" + # The simulator returns I2 as a single data field (matching shlex behavior) + device_type = await self.backend.request_device_type() + self.assertIsInstance(device_type, str) + capacity = await self.backend.request_capacity() + self.assertEqual(capacity, 220.0) + + async def test_multi_response_terminates_on_status_a(self): + """send_command must keep reading while status is B and stop on A. + I50 returns 3 lines (B, B, A). All must be captured.""" + responses = await self.backend.send_command("I50") + self.assertEqual(len(responses), 3) + self.assertEqual(responses[0].status, "B") + self.assertEqual(responses[1].status, "B") + self.assertEqual(responses[2].status, "A") + + async def test_zero_stable_dispatches_to_z(self): + """zero(timeout='stable') must send the Z command (wait for stable), + not ZI (immediate) or ZC (timed).""" + self.backend.platform_weight = 5.0 + await self.scale.zero(timeout="stable") + # After zeroing, reading should return 0 + weight = await self.scale.read_weight(timeout=0) + self.assertEqual(weight, 0.0) + + async def test_clear_tare_resets_to_zero(self): + """clear_tare (TAC) must reset the stored tare value to zero. + After clearing, request_tare_weight must return 0.""" + self.backend.platform_weight = 50.0 + await self.scale.tare() + tare = await self.scale.request_tare_weight() + self.assertEqual(tare, 50.0) + await self.backend.clear_tare() + tare_after = await self.scale.request_tare_weight() + self.assertEqual(tare_after, 0.0) + + async def test_b_status_does_not_raise(self): + """Status B (more responses follow) must not be treated as an error. + If _parse_basic_errors raises on B, all multi-response commands break.""" + self.backend._parse_basic_errors(R("I50", "B", ["0", "535.141", "g"])) + + async def test_request_weighing_mode(self): + """request_weighing_mode must return an integer from the M01 response. + Verifies Batch 2 M01 query parsing.""" + mode = await self.backend.request_weighing_mode() + self.assertEqual(mode, 0) # Normal weighing mode + if __name__ == "__main__": unittest.main() diff --git a/pylabrobot/scales/mettler_toledo/confirmed_firmware_versions.py b/pylabrobot/scales/mettler_toledo/confirmed_firmware_versions.py new file mode 100644 index 00000000000..f248236a7ea --- /dev/null +++ b/pylabrobot/scales/mettler_toledo/confirmed_firmware_versions.py @@ -0,0 +1,15 @@ +"""Firmware versions confirmed to work with this driver. + +If the connected device runs a firmware version not in this list, +a warning is emitted during setup(). Please report untested versions +that work so they can be added. + +Only the major.minor version is checked (e.g. "1.10"), not the full +string (e.g. "1.10 18.6.4.1361.772"), because the second part is +a type definition number that varies by hardware revision and model +while the firmware behavior is determined by the version number. +""" + +CONFIRMED_FIRMWARE_VERSIONS = [ + "1.10", +] diff --git a/pylabrobot/scales/mettler_toledo/hardware_validation.ipynb b/pylabrobot/scales/mettler_toledo/hardware_validation.ipynb index 8d5afa546af..ff10803350f 100644 --- a/pylabrobot/scales/mettler_toledo/hardware_validation.ipynb +++ b/pylabrobot/scales/mettler_toledo/hardware_validation.ipynb @@ -585,155 +585,10 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2026-03-30 12:50:46,766 - pylabrobot - IO - [MT Scale] Sent command: I3\n", - "2026-03-30 12:50:46,768 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I3\\r\\n'\n", - "2026-03-30 12:50:46,818 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I3 A \"1.10 18.6.4.1361.772\"\\r\\n'\n", - "2026-03-30 12:50:46,820 - pylabrobot - IO - [MT Scale] Received response: b'I3 A \"1.10 18.6.4.1361.772\"\\r\\n'\n", - "2026-03-30 12:50:46,824 - pylabrobot - IO - [MT Scale] Sent command: I5\n", - "2026-03-30 12:50:46,827 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I5\\r\\n'\n", - "2026-03-30 12:50:46,867 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I5 A \"11671158C\"\\r\\n'\n", - "2026-03-30 12:50:46,870 - pylabrobot - IO - [MT Scale] Received response: b'I5 A \"11671158C\"\\r\\n'\n", - "2026-03-30 12:50:46,876 - pylabrobot - IO - [MT Scale] Sent command: I10\n", - "2026-03-30 12:50:46,882 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I10\\r\\n'\n", - "2026-03-30 12:50:46,913 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I10 A \"\"\\r\\n'\n", - "2026-03-30 12:50:46,918 - pylabrobot - IO - [MT Scale] Received response: b'I10 A \"\"\\r\\n'\n", - "2026-03-30 12:50:46,919 - pylabrobot - IO - [MT Scale] Sent command: I11\n", - "2026-03-30 12:50:46,923 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I11\\r\\n'\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Software version: 1.10 18.6.4.1361.772\n", - "Software material number: 11671158C\n", - "Device ID: ''\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2026-03-30 12:50:46,961 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I11 A \"WXS205SDU\"\\r\\n'\n", - "2026-03-30 12:50:46,962 - pylabrobot - IO - [MT Scale] Received response: b'I11 A \"WXS205SDU\"\\r\\n'\n", - "2026-03-30 12:50:46,963 - pylabrobot - IO - [MT Scale] Sent command: I15\n", - "2026-03-30 12:50:46,971 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I15\\r\\n'\n", - "2026-03-30 12:50:47,009 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I15 A 203\\r\\n'\n", - "2026-03-30 12:50:47,010 - pylabrobot - IO - [MT Scale] Received response: b'I15 A 203\\r\\n'\n", - "2026-03-30 12:50:47,012 - pylabrobot - IO - [MT Scale] Sent command: DAT\n", - "2026-03-30 12:50:47,014 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'DAT\\r\\n'\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Model designation: WXS205SDU\n", - "Uptime: 203d 0h 0m 0s\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2026-03-30 12:50:47,057 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'DAT A 04 01 2000\\r\\n'\n", - "2026-03-30 12:50:47,058 - pylabrobot - IO - [MT Scale] Received response: b'DAT A 04 01 2000\\r\\n'\n", - "2026-03-30 12:50:47,059 - pylabrobot - IO - [MT Scale] Sent command: TIM\n", - "2026-03-30 12:50:47,061 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'TIM\\r\\n'\n", - "2026-03-30 12:50:47,089 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'TIM A 19 56 13\\r\\n'\n", - "2026-03-30 12:50:47,090 - pylabrobot - IO - [MT Scale] Received response: b'TIM A 19 56 13\\r\\n'\n", - "2026-03-30 12:50:47,091 - pylabrobot - IO - [MT Scale] Sent command: I14\n", - "2026-03-30 12:50:47,092 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I14\\r\\n'\n", - "2026-03-30 12:50:47,121 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I14 L\\r\\n'\n", - "2026-03-30 12:50:47,121 - pylabrobot - IO - [MT Scale] Received response: b'I14 L\\r\\n'\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Device date: 04\n", - "Device time: 19\n" - ] - }, - { - "ename": "MettlerToledoError", - "evalue": "Command understood but not executable: (incorrect parameter).", - "output_type": "error", - "traceback": [ - "\u001b[31m---------------------------------------------------------------------------\u001b[39m", - "\u001b[31mMettlerToledoError\u001b[39m Traceback (most recent call last)", - "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[6]\u001b[39m\u001b[32m, line 46\u001b[39m\n\u001b[32m 44\u001b[39m \u001b[38;5;66;03m# I14 - Comprehensive device info (multi-response)\u001b[39;00m\n\u001b[32m 45\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m \u001b[33m\"\u001b[39m\u001b[33mI14\u001b[39m\u001b[33m\"\u001b[39m \u001b[38;5;129;01min\u001b[39;00m backend._supported_commands:\n\u001b[32m---> \u001b[39m\u001b[32m46\u001b[39m info_responses = \u001b[38;5;28;01mawait\u001b[39;00m backend.request_device_info()\n\u001b[32m 47\u001b[39m \u001b[38;5;28mprint\u001b[39m(\u001b[33mf\u001b[39m\u001b[33m\"\u001b[39m\u001b[38;5;130;01m\\n\u001b[39;00m\u001b[33mDevice info (\u001b[39m\u001b[38;5;132;01m{\u001b[39;00m\u001b[38;5;28mlen\u001b[39m(info_responses)\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m response lines):\u001b[39m\u001b[33m\"\u001b[39m)\n\u001b[32m 48\u001b[39m \u001b[38;5;28;01mfor\u001b[39;00m resp \u001b[38;5;129;01min\u001b[39;00m info_responses:\n", - "\u001b[36mFile \u001b[39m\u001b[32m~/Desktop/GitHub/pylabrobot/pylabrobot/scales/mettler_toledo/backend.py:59\u001b[39m, in \u001b[36mrequires_mt_sics_command..decorator..wrapper\u001b[39m\u001b[34m(self, *args, **kwargs)\u001b[39m\n\u001b[32m 53\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m mt_sics_command \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;129;01min\u001b[39;00m \u001b[38;5;28mself\u001b[39m._supported_commands:\n\u001b[32m 54\u001b[39m \u001b[38;5;28;01mraise\u001b[39;00m MettlerToledoError(\n\u001b[32m 55\u001b[39m title=\u001b[33m\"\u001b[39m\u001b[33mCommand not supported\u001b[39m\u001b[33m\"\u001b[39m,\n\u001b[32m 56\u001b[39m message=\u001b[33mf\u001b[39m\u001b[33m\"\u001b[39m\u001b[33m'\u001b[39m\u001b[38;5;132;01m{\u001b[39;00mfunc.\u001b[34m__name__\u001b[39m\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m'\u001b[39m\u001b[33m requires MT-SICS command \u001b[39m\u001b[33m'\u001b[39m\u001b[38;5;132;01m{\u001b[39;00mmt_sics_command\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m'\u001b[39m\u001b[33m, \u001b[39m\u001b[33m\"\u001b[39m\n\u001b[32m 57\u001b[39m \u001b[33mf\u001b[39m\u001b[33m\"\u001b[39m\u001b[33mwhich is not implemented on this device.\u001b[39m\u001b[33m\"\u001b[39m,\n\u001b[32m 58\u001b[39m )\n\u001b[32m---> \u001b[39m\u001b[32m59\u001b[39m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;01mawait\u001b[39;00m func(\u001b[38;5;28mself\u001b[39m, *args, **kwargs)\n", - "\u001b[36mFile \u001b[39m\u001b[32m~/Desktop/GitHub/pylabrobot/pylabrobot/scales/mettler_toledo/backend.py:465\u001b[39m, in \u001b[36mMettlerToledoWXS205SDUBackend.request_device_info\u001b[39m\u001b[34m(self)\u001b[39m\n\u001b[32m 456\u001b[39m \u001b[38;5;129m@requires_mt_sics_command\u001b[39m(\u001b[33m\"\u001b[39m\u001b[33mI14\u001b[39m\u001b[33m\"\u001b[39m)\n\u001b[32m 457\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[34mrequest_device_info\u001b[39m(\u001b[38;5;28mself\u001b[39m) -> List[MettlerToledoResponse]:\n\u001b[32m 458\u001b[39m \u001b[38;5;250m \u001b[39m\u001b[33;03m\"\"\"Query detailed device information including all components. (I14 command)\u001b[39;00m\n\u001b[32m 459\u001b[39m \n\u001b[32m 460\u001b[39m \u001b[33;03m Returns multi-response with instrument configuration (No=0),\u001b[39;00m\n\u001b[32m (...)\u001b[39m\u001b[32m 463\u001b[39m \u001b[33;03m Each category reports data for bridge, terminal, options, etc.\u001b[39;00m\n\u001b[32m 464\u001b[39m \u001b[33;03m \"\"\"\u001b[39;00m\n\u001b[32m--> \u001b[39m\u001b[32m465\u001b[39m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;01mawait\u001b[39;00m \u001b[38;5;28mself\u001b[39m.send_command(\u001b[33m\"\u001b[39m\u001b[33mI14\u001b[39m\u001b[33m\"\u001b[39m)\n", - "\u001b[36mFile \u001b[39m\u001b[32m~/Desktop/GitHub/pylabrobot/pylabrobot/scales/mettler_toledo/backend.py:322\u001b[39m, in \u001b[36mMettlerToledoWXS205SDUBackend.send_command\u001b[39m\u001b[34m(self, command, timeout)\u001b[39m\n\u001b[32m 320\u001b[39m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[32m 321\u001b[39m response = MettlerToledoResponse(command=\u001b[33m\"\u001b[39m\u001b[33m\"\u001b[39m, status=\u001b[33m\"\u001b[39m\u001b[33m\"\u001b[39m, data=[])\n\u001b[32m--> \u001b[39m\u001b[32m322\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[43m.\u001b[49m\u001b[43m_parse_basic_errors\u001b[49m\u001b[43m(\u001b[49m\u001b[43mresponse\u001b[49m\u001b[43m)\u001b[49m\n\u001b[32m 323\u001b[39m responses.append(response)\n\u001b[32m 325\u001b[39m \u001b[38;5;66;03m# Status B means more responses follow; anything else (A, etc.) is final\u001b[39;00m\n", - "\u001b[36mFile \u001b[39m\u001b[32m~/Desktop/GitHub/pylabrobot/pylabrobot/scales/mettler_toledo/backend.py:253\u001b[39m, in \u001b[36mMettlerToledoWXS205SDUBackend._parse_basic_errors\u001b[39m\u001b[34m(self, response)\u001b[39m\n\u001b[32m 251\u001b[39m \u001b[38;5;28;01mraise\u001b[39;00m MettlerToledoError.executing_another_command()\n\u001b[32m 252\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m response.status == \u001b[33m\"\u001b[39m\u001b[33mL\u001b[39m\u001b[33m\"\u001b[39m:\n\u001b[32m--> \u001b[39m\u001b[32m253\u001b[39m \u001b[38;5;28;01mraise\u001b[39;00m MettlerToledoError.incorrect_parameter()\n\u001b[32m 254\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m response.status == \u001b[33m\"\u001b[39m\u001b[33m+\u001b[39m\u001b[33m\"\u001b[39m:\n\u001b[32m 255\u001b[39m \u001b[38;5;28;01mraise\u001b[39;00m MettlerToledoError.overload()\n", - "\u001b[31mMettlerToledoError\u001b[39m: Command understood but not executable: (incorrect parameter)." - ] - } - ], - "source": [ - "# I3 - Software version (Level 0, always available)\n", - "sw_version = await backend.request_software_version()\n", - "print(f\"Software version: {sw_version}\")\n", - "\n", - "# I5 - Software material number (Level 0, always available)\n", - "sw_material = await backend.request_software_material_number()\n", - "print(f\"Software material number: {sw_material}\")\n", - "\n", - "# I10 - Device ID (user-assignable name)\n", - "if \"I10\" in backend._supported_commands:\n", - " device_id = await backend.request_device_id()\n", - " print(f\"Device ID: '{device_id}'\")\n", - "else:\n", - " print(\"SKIP: I10 not supported\")\n", - "\n", - "# I11 - Model designation\n", - "if \"I11\" in backend._supported_commands:\n", - " model = await backend.request_model_designation()\n", - " print(f\"Model designation: {model}\")\n", - "else:\n", - " print(\"SKIP: I11 not supported\")\n", - "\n", - "# I15 - Uptime\n", - "if \"I15\" in backend._supported_commands:\n", - " uptime = await backend.request_uptime()\n", - " print(f\"Uptime: {uptime['days']}d {uptime['hours']}h {uptime['minutes']}m {uptime['seconds']}s\")\n", - "else:\n", - " print(\"SKIP: I15 not supported\")\n", - "\n", - "# DAT - Date\n", - "if \"DAT\" in backend._supported_commands:\n", - " date = await backend.request_date()\n", - " print(f\"Device date: {date}\")\n", - "else:\n", - " print(\"SKIP: DAT not supported\")\n", - "\n", - "# TIM - Time\n", - "if \"TIM\" in backend._supported_commands:\n", - " time_str = await backend.request_time()\n", - " print(f\"Device time: {time_str}\")\n", - "else:\n", - " print(\"SKIP: TIM not supported\")\n", - "\n", - "# I14 - Comprehensive device info (multi-response)\n", - "if \"I14\" in backend._supported_commands:\n", - " info_responses = await backend.request_device_info()\n", - " print(f\"\\nDevice info ({len(info_responses)} response lines):\")\n", - " for resp in info_responses:\n", - " print(f\" {resp.command} {resp.status} {' '.join(resp.data)}\")\n", - "else:\n", - " print(\"SKIP: I14 not supported\")\n", - "\n", - "print(\"\\nPASS: Batch 1 device identity commands completed\")" - ] + "outputs": [], + "source": "# I3 - Software version (Level 0, always available)\nsw_version = await backend.request_software_version()\nprint(f\"Software version: {sw_version}\")\n\n# I5 - Software material number (Level 0, always available)\nsw_material = await backend.request_software_material_number()\nprint(f\"Software material number: {sw_material}\")\n\n# I10 - Device ID (user-assignable name)\nif \"I10\" in backend._supported_commands:\n device_id = await backend.request_device_id()\n print(f\"Device ID: '{device_id}'\")\nelse:\n print(\"SKIP: I10 not supported\")\n\n# I11 - Model designation\nif \"I11\" in backend._supported_commands:\n model = await backend.request_model_designation()\n print(f\"Model designation: {model}\")\nelse:\n print(\"SKIP: I11 not supported\")\n\n# I15 - Uptime\nif \"I15\" in backend._supported_commands:\n uptime = await backend.request_uptime()\n print(f\"Uptime: {uptime['days']}d {uptime['hours']}h {uptime['minutes']}m {uptime['seconds']}s\")\nelse:\n print(\"SKIP: I15 not supported\")\n\n# DAT - Date\nif \"DAT\" in backend._supported_commands:\n date = await backend.request_date()\n print(f\"Device date: {date}\")\nelse:\n print(\"SKIP: DAT not supported\")\n\n# TIM - Time\nif \"TIM\" in backend._supported_commands:\n time_str = await backend.request_time()\n print(f\"Device time: {time_str}\")\nelse:\n print(\"SKIP: TIM not supported\")\n\n# I14 - Comprehensive device info (query each category separately)\nif \"I14\" in backend._supported_commands:\n category_names = {\n 0: \"Instrument configuration\",\n 1: \"Instrument descriptions\",\n 2: \"SW identification numbers\",\n 3: \"SW versions\",\n 4: \"Serial numbers\",\n 5: \"TDNR numbers\",\n }\n print(\"\\nDevice info (I14):\")\n for cat, name in category_names.items():\n try:\n info = await backend.request_device_info(category=cat)\n print(f\" Category {cat} ({name}):\")\n for resp in info:\n print(f\" {resp.command} {resp.status} {' '.join(resp.data)}\")\n except Exception as e:\n print(f\" Category {cat} ({name}): {e}\")\nelse:\n print(\"SKIP: I14 not supported\")\n\nprint(\"\\nPASS: Batch 1 device identity commands completed\")" }, { "cell_type": "markdown", @@ -1131,6 +986,18 @@ " print(\"SKIP: M28 not supported on this device\")" ] }, + { + "cell_type": "markdown", + "source": "### Batch 2 - Configuration queries (read-only)\n\nThese commands read device configuration without modifying anything.", + "metadata": {} + }, + { + "cell_type": "code", + "source": "# M01 - Weighing mode (read-only query)\nif \"M01\" in backend._supported_commands:\n mode = await backend.request_weighing_mode()\n mode_names = {0: \"Normal/Universal\", 1: \"Dosing\", 2: \"Sensor\", 3: \"Check weighing\", 6: \"Raw/No filter\"}\n print(f\"Weighing mode: {mode} ({mode_names.get(mode, 'unknown')})\")\nelse:\n print(\"SKIP: M01 not supported\")\n\n# M02 - Environment condition (read-only query)\nif \"M02\" in backend._supported_commands:\n env = await backend.request_environment_condition()\n env_names = {0: \"Very stable\", 1: \"Stable\", 2: \"Standard\", 3: \"Unstable\", 4: \"Very unstable\", 5: \"Automatic\"}\n print(f\"Environment condition: {env} ({env_names.get(env, 'unknown')})\")\nelse:\n print(\"SKIP: M02 not supported\")\n\n# M03 - Auto zero (read-only query)\nif \"M03\" in backend._supported_commands:\n auto_zero = await backend.request_auto_zero()\n print(f\"Auto zero: {auto_zero} ({'on' if auto_zero else 'off'})\")\nelse:\n print(\"SKIP: M03 not supported\")\n\n# M27 - Adjustment history (read-only query)\nif \"M27\" in backend._supported_commands:\n history = await backend.request_adjustment_history()\n print(f\"\\nAdjustment history ({len(history)} entries):\")\n for resp in history:\n print(f\" {resp.command} {resp.status} {' '.join(resp.data)}\")\nelse:\n print(\"SKIP: M27 not supported\")\n\n# UPD - Update rate (read-only query)\nif \"UPD\" in backend._supported_commands:\n rate = await backend.request_update_rate()\n print(f\"\\nUpdate rate: {rate} values/s\")\nelse:\n print(\"SKIP: UPD not supported\")\n\n# SIS - Net weight with status (read-only query)\nif \"SIS\" in backend._supported_commands:\n sis_resp = await backend.request_net_weight_with_status()\n print(f\"\\nNet weight with status: {sis_resp.command} {sis_resp.status} {' '.join(sis_resp.data)}\")\nelse:\n print(\"SKIP: SIS not supported\")\n\n# LST - Current user settings (read-only, lists all configurable settings)\nif \"LST\" in backend._supported_commands:\n try:\n lst_responses = await backend.send_command(\"LST\")\n print(f\"\\nCurrent user settings ({len(lst_responses)} lines):\")\n for resp in lst_responses[:10]:\n print(f\" {resp.command} {resp.status} {' '.join(resp.data)}\")\n if len(lst_responses) > 10:\n print(f\" ... ({len(lst_responses)} lines total)\")\n except Exception as e:\n print(f\"LST: {e}\")\nelse:\n print(\"SKIP: LST not supported\")\n\n# RDB - Readability (read-only)\nif \"RDB\" in backend._supported_commands:\n try:\n rdb_responses = await backend.send_command(\"RDB\")\n print(f\"\\nReadability: {rdb_responses[0].command} {rdb_responses[0].status} {' '.join(rdb_responses[0].data)}\")\n except Exception as e:\n print(f\"RDB: {e}\")\nelse:\n print(\"SKIP: RDB not supported\")\n\n# USTB - User defined stability criteria (read-only query)\nif \"USTB\" in backend._supported_commands:\n try:\n ustb_responses = await backend.send_command(\"USTB\")\n print(f\"Stability criteria: {ustb_responses[0].command} {ustb_responses[0].status} {' '.join(ustb_responses[0].data)}\")\n except Exception as e:\n print(f\"USTB: {e}\")\nelse:\n print(\"SKIP: USTB not supported\")\n\n# FCUT - Filter cut-off frequency (read-only query)\nif \"FCUT\" in backend._supported_commands:\n try:\n fcut_responses = await backend.send_command(\"FCUT\")\n print(f\"Filter cut-off: {fcut_responses[0].command} {fcut_responses[0].status} {' '.join(fcut_responses[0].data)}\")\n except Exception as e:\n print(f\"FCUT: {e}\")\nelse:\n print(\"SKIP: FCUT not supported\")\n\nprint(\"\\nPASS: Batch 2+3 read-only configuration queries completed\")", + "metadata": {}, + "execution_count": null, + "outputs": [] + }, { "cell_type": "markdown", "metadata": {}, @@ -1254,4 +1121,4 @@ }, "nbformat": 4, "nbformat_minor": 4 -} +} \ No newline at end of file diff --git a/pylabrobot/scales/mettler_toledo/simulator.py b/pylabrobot/scales/mettler_toledo/simulator.py index d39a61322a3..8d4e659f325 100644 --- a/pylabrobot/scales/mettler_toledo/simulator.py +++ b/pylabrobot/scales/mettler_toledo/simulator.py @@ -93,10 +93,17 @@ def __init__( "DW", "DAT", "TIM", + "M01", + "M02", + "M03", "M21", + "M27", "M28", + "SIS", + "SNR", "SR", "SIR", + "UPD", } @property @@ -108,14 +115,20 @@ async def setup(self) -> None: self._supported_commands = self._simulated_supported_commands self.device_type = self._simulated_device_type self.capacity = self._simulated_capacity + self.firmware_version = "1.10 18.6.4.1361.772" + self.configuration = "Bridge" if "Bridge" in self.device_type else "Balance" logger.info( "[MT Scale] Connected to Mettler Toledo scale (simulation)\n" "Device type: %s\n" + "Configuration: %s\n" "Serial number: %s\n" + "Firmware: %s\n" "Capacity: %.1f g\n" "Supported commands: %s", self.device_type, + self.configuration, self.serial_number, + self.firmware_version, self.capacity, sorted(self._supported_commands), ) @@ -185,6 +198,25 @@ def _build_response(self, command: str) -> List[MettlerToledoResponse]: if cmd == "TIM": return [R("TIM", "A", ["12:00:00"])] + # Configuration queries + if cmd == "M01": + return [R("M01", "A", ["0"])] # Normal weighing mode + if cmd == "M02": + return [R("M02", "A", ["2"])] # Standard environment + if cmd == "M03": + return [R("M03", "A", ["1"])] # Auto zero on + if cmd == "M27": + return [ + R("M27", "B", ["1", "1", "1", "2026", "8", "0", "0", ""]), + R("M27", "A", ["2", "15", "3", "2026", "10", "30", "1", "200.1234 g"]), + ] + if cmd == "SIS": + return [R("SIS", "S", [f"{net:.5f}", "g", "S"])] + if cmd == "SNR": + return [R("SNR", "S", [f"{net:.5f}", "g"])] + if cmd == "UPD": + return [R("UPD", "A", ["18.3"])] + # Zero if cmd in ("Z", "ZI", "ZC"): self.zero_offset = self._sensor_reading From 4d28e049ee3537928f91afb211d476387b57acdb Mon Sep 17 00:00:00 2001 From: Camillo Moschner Date: Mon, 30 Mar 2026 13:13:33 +0100 Subject: [PATCH 24/38] tested batch 2 and 3 results --- .../mettler_toledo/hardware_validation.ipynb | 1850 ++++++++++++++--- 1 file changed, 1526 insertions(+), 324 deletions(-) diff --git a/pylabrobot/scales/mettler_toledo/hardware_validation.ipynb b/pylabrobot/scales/mettler_toledo/hardware_validation.ipynb index ff10803350f..9eea3793983 100644 --- a/pylabrobot/scales/mettler_toledo/hardware_validation.ipynb +++ b/pylabrobot/scales/mettler_toledo/hardware_validation.ipynb @@ -33,7 +33,7 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 12:50:44,638 - pylabrobot - INFO - === Hardware validation started ===\n" + "2026-03-30 13:12:14,770 - pylabrobot - INFO - === Hardware validation started ===\n" ] } ], @@ -65,155 +65,161 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 12:50:44,655 - pylabrobot.io.serial - INFO - Using explicitly provided port: /dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0 (for VID=1027, PID=24577)\n", - "2026-03-30 12:50:44,663 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] reset_input_buffer\n", - "2026-03-30 12:50:44,670 - pylabrobot - IO - [MT Scale] Sent command: @\n", - "2026-03-30 12:50:44,672 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'@\\r\\n'\n", - "2026-03-30 12:50:44,725 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I4 A \"B207696838\"\\r\\n'\n", - "2026-03-30 12:50:44,726 - pylabrobot - IO - [MT Scale] Received response: b'I4 A \"B207696838\"\\r\\n'\n", - "2026-03-30 12:50:44,727 - pylabrobot - IO - [MT Scale] Sent command: I0\n", - "2026-03-30 12:50:44,729 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I0\\r\\n'\n", - "2026-03-30 12:50:44,755 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I0\"\\r\\n'\n", - "2026-03-30 12:50:44,756 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I0\"\\r\\n'\n", - "2026-03-30 12:50:44,771 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I1\"\\r\\n'\n", - "2026-03-30 12:50:44,773 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I1\"\\r\\n'\n", - "2026-03-30 12:50:44,787 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I2\"\\r\\n'\n", - "2026-03-30 12:50:44,789 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I2\"\\r\\n'\n", - "2026-03-30 12:50:44,807 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I3\"\\r\\n'\n", - "2026-03-30 12:50:44,811 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I3\"\\r\\n'\n", - "2026-03-30 12:50:44,819 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I4\"\\r\\n'\n", - "2026-03-30 12:50:44,820 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I4\"\\r\\n'\n", - "2026-03-30 12:50:44,835 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I5\"\\r\\n'\n", - "2026-03-30 12:50:44,837 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I5\"\\r\\n'\n", - "2026-03-30 12:50:44,841 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"S\"\\r\\n'\n", - "2026-03-30 12:50:44,844 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"S\"\\r\\n'\n", - "2026-03-30 12:50:44,851 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"SI\"\\r\\n'\n", - "2026-03-30 12:50:44,853 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"SI\"\\r\\n'\n", - "2026-03-30 12:50:44,867 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"SIR\"\\r\\n'\n", - "2026-03-30 12:50:44,869 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"SIR\"\\r\\n'\n", - "2026-03-30 12:50:44,882 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"Z\"\\r\\n'\n", - "2026-03-30 12:50:44,884 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"Z\"\\r\\n'\n", - "2026-03-30 12:50:44,899 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"ZI\"\\r\\n'\n", - "2026-03-30 12:50:44,900 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"ZI\"\\r\\n'\n", - "2026-03-30 12:50:44,902 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"@\"\\r\\n'\n", - "2026-03-30 12:50:44,904 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"@\"\\r\\n'\n", - "2026-03-30 12:50:44,917 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"SR\"\\r\\n'\n", - "2026-03-30 12:50:44,926 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"SR\"\\r\\n'\n", - "2026-03-30 12:50:44,931 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"T\"\\r\\n'\n", - "2026-03-30 12:50:44,932 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"T\"\\r\\n'\n", - "2026-03-30 12:50:44,947 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"TA\"\\r\\n'\n", - "2026-03-30 12:50:44,948 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"TA\"\\r\\n'\n", - "2026-03-30 12:50:44,963 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"TAC\"\\r\\n'\n", - "2026-03-30 12:50:44,964 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"TAC\"\\r\\n'\n", - "2026-03-30 12:50:44,979 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"TI\"\\r\\n'\n", - "2026-03-30 12:50:44,980 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"TI\"\\r\\n'\n", - "2026-03-30 12:50:44,995 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C0\"\\r\\n'\n", - "2026-03-30 12:50:44,996 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"C0\"\\r\\n'\n", - "2026-03-30 12:50:44,997 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C1\"\\r\\n'\n", - "2026-03-30 12:50:44,999 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"C1\"\\r\\n'\n", - "2026-03-30 12:50:45,013 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C2\"\\r\\n'\n", - "2026-03-30 12:50:45,014 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"C2\"\\r\\n'\n", - "2026-03-30 12:50:45,026 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C3\"\\r\\n'\n", - "2026-03-30 12:50:45,030 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"C3\"\\r\\n'\n", - "2026-03-30 12:50:45,049 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"COM\"\\r\\n'\n", - "2026-03-30 12:50:45,050 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"COM\"\\r\\n'\n", - "2026-03-30 12:50:45,059 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"DAT\"\\r\\n'\n", - "2026-03-30 12:50:45,061 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"DAT\"\\r\\n'\n", - "2026-03-30 12:50:45,075 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I10\"\\r\\n'\n", - "2026-03-30 12:50:45,076 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I10\"\\r\\n'\n", - "2026-03-30 12:50:45,091 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I11\"\\r\\n'\n", - "2026-03-30 12:50:45,094 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I11\"\\r\\n'\n", - "2026-03-30 12:50:45,107 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I14\"\\r\\n'\n", - "2026-03-30 12:50:45,108 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I14\"\\r\\n'\n", - "2026-03-30 12:50:45,125 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I15\"\\r\\n'\n", - "2026-03-30 12:50:45,126 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I15\"\\r\\n'\n", - "2026-03-30 12:50:45,128 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I16\"\\r\\n'\n", - "2026-03-30 12:50:45,128 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I16\"\\r\\n'\n", - "2026-03-30 12:50:45,139 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I21\"\\r\\n'\n", - "2026-03-30 12:50:45,140 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I21\"\\r\\n'\n", - "2026-03-30 12:50:45,155 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I22\"\\r\\n'\n", - "2026-03-30 12:50:45,161 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I22\"\\r\\n'\n", - "2026-03-30 12:50:45,170 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I23\"\\r\\n'\n", - "2026-03-30 12:50:45,172 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I23\"\\r\\n'\n", - "2026-03-30 12:50:45,189 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I24\"\\r\\n'\n", - "2026-03-30 12:50:45,190 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I24\"\\r\\n'\n", - "2026-03-30 12:50:45,203 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I25\"\\r\\n'\n", - "2026-03-30 12:50:45,204 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I25\"\\r\\n'\n", - "2026-03-30 12:50:45,218 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I26\"\\r\\n'\n", - "2026-03-30 12:50:45,220 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I26\"\\r\\n'\n", - "2026-03-30 12:50:45,235 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M01\"\\r\\n'\n", - "2026-03-30 12:50:45,237 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M01\"\\r\\n'\n", - "2026-03-30 12:50:45,254 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M02\"\\r\\n'\n", - "2026-03-30 12:50:45,255 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M02\"\\r\\n'\n", - "2026-03-30 12:50:45,268 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M03\"\\r\\n'\n", - "2026-03-30 12:50:45,271 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M03\"\\r\\n'\n", - "2026-03-30 12:50:45,282 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M17\"\\r\\n'\n", - "2026-03-30 12:50:45,294 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M17\"\\r\\n'\n", - "2026-03-30 12:50:45,299 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M18\"\\r\\n'\n", - "2026-03-30 12:50:45,300 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M18\"\\r\\n'\n", - "2026-03-30 12:50:45,303 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M19\"\\r\\n'\n", - "2026-03-30 12:50:45,304 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M19\"\\r\\n'\n", - "2026-03-30 12:50:45,316 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M20\"\\r\\n'\n", - "2026-03-30 12:50:45,323 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M20\"\\r\\n'\n", - "2026-03-30 12:50:45,331 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M21\"\\r\\n'\n", - "2026-03-30 12:50:45,333 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M21\"\\r\\n'\n", - "2026-03-30 12:50:45,346 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M27\"\\r\\n'\n", - "2026-03-30 12:50:45,348 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M27\"\\r\\n'\n", - "2026-03-30 12:50:45,365 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M28\"\\r\\n'\n", - "2026-03-30 12:50:45,368 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M28\"\\r\\n'\n", - "2026-03-30 12:50:45,378 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M29\"\\r\\n'\n", - "2026-03-30 12:50:45,379 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M29\"\\r\\n'\n", - "2026-03-30 12:50:45,395 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M31\"\\r\\n'\n", - "2026-03-30 12:50:45,396 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M31\"\\r\\n'\n", - "2026-03-30 12:50:45,411 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M32\"\\r\\n'\n", - "2026-03-30 12:50:45,412 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M32\"\\r\\n'\n", - "2026-03-30 12:50:45,426 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M33\"\\r\\n'\n", - "2026-03-30 12:50:45,427 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M33\"\\r\\n'\n", - "2026-03-30 12:50:45,443 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M35\"\\r\\n'\n", - "2026-03-30 12:50:45,444 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M35\"\\r\\n'\n", - "2026-03-30 12:50:45,460 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"SIS\"\\r\\n'\n", - "2026-03-30 12:50:45,462 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"SIS\"\\r\\n'\n", - "2026-03-30 12:50:45,474 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"SNR\"\\r\\n'\n", - "2026-03-30 12:50:45,475 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"SNR\"\\r\\n'\n", - "2026-03-30 12:50:45,476 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TIM\"\\r\\n'\n", - "2026-03-30 12:50:45,477 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TIM\"\\r\\n'\n", - "2026-03-30 12:50:45,493 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST0\"\\r\\n'\n", - "2026-03-30 12:50:45,494 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TST0\"\\r\\n'\n", - "2026-03-30 12:50:45,507 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST1\"\\r\\n'\n", - "2026-03-30 12:50:45,508 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TST1\"\\r\\n'\n", - "2026-03-30 12:50:45,523 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST2\"\\r\\n'\n", - "2026-03-30 12:50:45,523 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TST2\"\\r\\n'\n", - "2026-03-30 12:50:45,538 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST3\"\\r\\n'\n", - "2026-03-30 12:50:45,539 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TST3\"\\r\\n'\n", - "2026-03-30 12:50:45,555 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"UPD\"\\r\\n'\n", - "2026-03-30 12:50:45,558 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"UPD\"\\r\\n'\n", - "2026-03-30 12:50:45,570 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"FCUT\"\\r\\n'\n", - "2026-03-30 12:50:45,572 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 3 \"FCUT\"\\r\\n'\n", - "2026-03-30 12:50:45,587 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"FSET\"\\r\\n'\n", - "2026-03-30 12:50:45,589 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 3 \"FSET\"\\r\\n'\n", - "2026-03-30 12:50:45,602 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"LST\"\\r\\n'\n", - "2026-03-30 12:50:45,603 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 3 \"LST\"\\r\\n'\n", - "2026-03-30 12:50:45,618 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"RDB\"\\r\\n'\n", - "2026-03-30 12:50:45,619 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 3 \"RDB\"\\r\\n'\n", - "2026-03-30 12:50:45,635 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 A 3 \"USTB\"\\r\\n'\n", - "2026-03-30 12:50:45,638 - pylabrobot - IO - [MT Scale] Received response: b'I0 A 3 \"USTB\"\\r\\n'\n", - "2026-03-30 12:50:45,640 - pylabrobot - IO - [MT Scale] Sent command: I2\n", - "2026-03-30 12:50:45,643 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I2\\r\\n'\n", - "2026-03-30 12:50:45,699 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", - "2026-03-30 12:50:45,700 - pylabrobot - IO - [MT Scale] Received response: b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", - "2026-03-30 12:50:45,703 - pylabrobot - IO - [MT Scale] Sent command: I2\n", - "2026-03-30 12:50:45,710 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I2\\r\\n'\n", - "2026-03-30 12:50:45,762 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", - "2026-03-30 12:50:45,762 - pylabrobot - IO - [MT Scale] Received response: b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", - "2026-03-30 12:50:45,763 - pylabrobot - INFO - [MT Scale] Connected to Mettler Toledo scale on /dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0\n", + "2026-03-30 13:12:14,791 - pylabrobot.io.serial - INFO - Using explicitly provided port: /dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0 (for VID=1027, PID=24577)\n", + "2026-03-30 13:12:14,799 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] reset_input_buffer\n", + "2026-03-30 13:12:14,800 - pylabrobot - IO - [MT Scale] Sent command: @\n", + "2026-03-30 13:12:14,803 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'@\\r\\n'\n", + "2026-03-30 13:12:14,862 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I4 A \"B207696838\"\\r\\n'\n", + "2026-03-30 13:12:14,863 - pylabrobot - IO - [MT Scale] Received response: b'I4 A \"B207696838\"\\r\\n'\n", + "2026-03-30 13:12:14,864 - pylabrobot - IO - [MT Scale] Sent command: I0\n", + "2026-03-30 13:12:14,865 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I0\\r\\n'\n", + "2026-03-30 13:12:14,893 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I0\"\\r\\n'\n", + "2026-03-30 13:12:14,894 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I0\"\\r\\n'\n", + "2026-03-30 13:12:14,910 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I1\"\\r\\n'\n", + "2026-03-30 13:12:14,911 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I1\"\\r\\n'\n", + "2026-03-30 13:12:14,925 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I2\"\\r\\n'\n", + "2026-03-30 13:12:14,926 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I2\"\\r\\n'\n", + "2026-03-30 13:12:14,942 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I3\"\\r\\n'\n", + "2026-03-30 13:12:14,942 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I3\"\\r\\n'\n", + "2026-03-30 13:12:14,959 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I4\"\\r\\n'\n", + "2026-03-30 13:12:14,962 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I4\"\\r\\n'\n", + "2026-03-30 13:12:14,974 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I5\"\\r\\n'\n", + "2026-03-30 13:12:14,975 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I5\"\\r\\n'\n", + "2026-03-30 13:12:14,977 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"S\"\\r\\n'\n", + "2026-03-30 13:12:14,978 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"S\"\\r\\n'\n", + "2026-03-30 13:12:14,990 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"SI\"\\r\\n'\n", + "2026-03-30 13:12:14,991 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"SI\"\\r\\n'\n", + "2026-03-30 13:12:15,005 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"SIR\"\\r\\n'\n", + "2026-03-30 13:12:15,006 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"SIR\"\\r\\n'\n", + "2026-03-30 13:12:15,022 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"Z\"\\r\\n'\n", + "2026-03-30 13:12:15,022 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"Z\"\\r\\n'\n", + "2026-03-30 13:12:15,038 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"ZI\"\\r\\n'\n", + "2026-03-30 13:12:15,039 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"ZI\"\\r\\n'\n", + "2026-03-30 13:12:15,053 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"@\"\\r\\n'\n", + "2026-03-30 13:12:15,055 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"@\"\\r\\n'\n", + "2026-03-30 13:12:15,056 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"SR\"\\r\\n'\n", + "2026-03-30 13:12:15,057 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"SR\"\\r\\n'\n", + "2026-03-30 13:12:15,070 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"T\"\\r\\n'\n", + "2026-03-30 13:12:15,071 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"T\"\\r\\n'\n", + "2026-03-30 13:12:15,085 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"TA\"\\r\\n'\n", + "2026-03-30 13:12:15,086 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"TA\"\\r\\n'\n", + "2026-03-30 13:12:15,101 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"TAC\"\\r\\n'\n", + "2026-03-30 13:12:15,102 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"TAC\"\\r\\n'\n", + "2026-03-30 13:12:15,118 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"TI\"\\r\\n'\n", + "2026-03-30 13:12:15,119 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"TI\"\\r\\n'\n", + "2026-03-30 13:12:15,134 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C0\"\\r\\n'\n", + "2026-03-30 13:12:15,135 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"C0\"\\r\\n'\n", + "2026-03-30 13:12:15,141 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C1\"\\r\\n'\n", + "2026-03-30 13:12:15,142 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"C1\"\\r\\n'\n", + "2026-03-30 13:12:15,150 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C2\"\\r\\n'\n", + "2026-03-30 13:12:15,151 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"C2\"\\r\\n'\n", + "2026-03-30 13:12:15,166 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C3\"\\r\\n'\n", + "2026-03-30 13:12:15,167 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"C3\"\\r\\n'\n", + "2026-03-30 13:12:15,181 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"COM\"\\r\\n'\n", + "2026-03-30 13:12:15,182 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"COM\"\\r\\n'\n", + "2026-03-30 13:12:15,198 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"DAT\"\\r\\n'\n", + "2026-03-30 13:12:15,199 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"DAT\"\\r\\n'\n", + "2026-03-30 13:12:15,213 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I10\"\\r\\n'\n", + "2026-03-30 13:12:15,214 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I10\"\\r\\n'\n", + "2026-03-30 13:12:15,229 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I11\"\\r\\n'\n", + "2026-03-30 13:12:15,230 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I11\"\\r\\n'\n", + "2026-03-30 13:12:15,246 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I14\"\\r\\n'\n", + "2026-03-30 13:12:15,248 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I14\"\\r\\n'\n", + "2026-03-30 13:12:15,262 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I15\"\\r\\n'\n", + "2026-03-30 13:12:15,263 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I15\"\\r\\n'\n", + "2026-03-30 13:12:15,277 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I16\"\\r\\n'\n", + "2026-03-30 13:12:15,278 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I16\"\\r\\n'\n", + "2026-03-30 13:12:15,279 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I21\"\\r\\n'\n", + "2026-03-30 13:12:15,280 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I21\"\\r\\n'\n", + "2026-03-30 13:12:15,294 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I22\"\\r\\n'\n", + "2026-03-30 13:12:15,295 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I22\"\\r\\n'\n", + "2026-03-30 13:12:15,309 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I23\"\\r\\n'\n", + "2026-03-30 13:12:15,310 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I23\"\\r\\n'\n", + "2026-03-30 13:12:15,326 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I24\"\\r\\n'\n", + "2026-03-30 13:12:15,326 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I24\"\\r\\n'\n", + "2026-03-30 13:12:15,341 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I25\"\\r\\n'\n", + "2026-03-30 13:12:15,342 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I25\"\\r\\n'\n", + "2026-03-30 13:12:15,357 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I26\"\\r\\n'\n", + "2026-03-30 13:12:15,358 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I26\"\\r\\n'\n", + "2026-03-30 13:12:15,374 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M01\"\\r\\n'\n", + "2026-03-30 13:12:15,374 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M01\"\\r\\n'\n", + "2026-03-30 13:12:15,389 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M02\"\\r\\n'\n", + "2026-03-30 13:12:15,390 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M02\"\\r\\n'\n", + "2026-03-30 13:12:15,405 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M03\"\\r\\n'\n", + "2026-03-30 13:12:15,406 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M03\"\\r\\n'\n", + "2026-03-30 13:12:15,422 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M17\"\\r\\n'\n", + "2026-03-30 13:12:15,422 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M17\"\\r\\n'\n", + "2026-03-30 13:12:15,437 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M18\"\\r\\n'\n", + "2026-03-30 13:12:15,438 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M18\"\\r\\n'\n", + "2026-03-30 13:12:15,453 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M19\"\\r\\n'\n", + "2026-03-30 13:12:15,454 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M19\"\\r\\n'\n", + "2026-03-30 13:12:15,456 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M20\"\\r\\n'\n", + "2026-03-30 13:12:15,456 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M20\"\\r\\n'\n", + "2026-03-30 13:12:15,470 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M21\"\\r\\n'\n", + "2026-03-30 13:12:15,470 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M21\"\\r\\n'\n", + "2026-03-30 13:12:15,485 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M27\"\\r\\n'\n", + "2026-03-30 13:12:15,486 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M27\"\\r\\n'\n", + "2026-03-30 13:12:15,501 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M28\"\\r\\n'\n", + "2026-03-30 13:12:15,503 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M28\"\\r\\n'\n", + "2026-03-30 13:12:15,518 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M29\"\\r\\n'\n", + "2026-03-30 13:12:15,519 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M29\"\\r\\n'\n", + "2026-03-30 13:12:15,533 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M31\"\\r\\n'\n", + "2026-03-30 13:12:15,534 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M31\"\\r\\n'\n", + "2026-03-30 13:12:15,549 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M32\"\\r\\n'\n", + "2026-03-30 13:12:15,550 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M32\"\\r\\n'\n", + "2026-03-30 13:12:15,566 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M33\"\\r\\n'\n", + "2026-03-30 13:12:15,567 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M33\"\\r\\n'\n", + "2026-03-30 13:12:15,581 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M35\"\\r\\n'\n", + "2026-03-30 13:12:15,582 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M35\"\\r\\n'\n", + "2026-03-30 13:12:15,598 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"SIS\"\\r\\n'\n", + "2026-03-30 13:12:15,600 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"SIS\"\\r\\n'\n", + "2026-03-30 13:12:15,613 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"SNR\"\\r\\n'\n", + "2026-03-30 13:12:15,614 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"SNR\"\\r\\n'\n", + "2026-03-30 13:12:15,616 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TIM\"\\r\\n'\n", + "2026-03-30 13:12:15,617 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TIM\"\\r\\n'\n", + "2026-03-30 13:12:15,633 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST0\"\\r\\n'\n", + "2026-03-30 13:12:15,634 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TST0\"\\r\\n'\n", + "2026-03-30 13:12:15,646 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST1\"\\r\\n'\n", + "2026-03-30 13:12:15,648 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TST1\"\\r\\n'\n", + "2026-03-30 13:12:15,661 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST2\"\\r\\n'\n", + "2026-03-30 13:12:15,662 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TST2\"\\r\\n'\n", + "2026-03-30 13:12:15,678 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST3\"\\r\\n'\n", + "2026-03-30 13:12:15,679 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TST3\"\\r\\n'\n", + "2026-03-30 13:12:15,693 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"UPD\"\\r\\n'\n", + "2026-03-30 13:12:15,694 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"UPD\"\\r\\n'\n", + "2026-03-30 13:12:15,712 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"FCUT\"\\r\\n'\n", + "2026-03-30 13:12:15,713 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 3 \"FCUT\"\\r\\n'\n", + "2026-03-30 13:12:15,726 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"FSET\"\\r\\n'\n", + "2026-03-30 13:12:15,727 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 3 \"FSET\"\\r\\n'\n", + "2026-03-30 13:12:15,741 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"LST\"\\r\\n'\n", + "2026-03-30 13:12:15,742 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 3 \"LST\"\\r\\n'\n", + "2026-03-30 13:12:15,758 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"RDB\"\\r\\n'\n", + "2026-03-30 13:12:15,758 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 3 \"RDB\"\\r\\n'\n", + "2026-03-30 13:12:15,773 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 A 3 \"USTB\"\\r\\n'\n", + "2026-03-30 13:12:15,774 - pylabrobot - IO - [MT Scale] Received response: b'I0 A 3 \"USTB\"\\r\\n'\n", + "2026-03-30 13:12:15,774 - pylabrobot - IO - [MT Scale] Sent command: I2\n", + "2026-03-30 13:12:15,780 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I2\\r\\n'\n", + "2026-03-30 13:12:15,837 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", + "2026-03-30 13:12:15,838 - pylabrobot - IO - [MT Scale] Received response: b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", + "2026-03-30 13:12:15,839 - pylabrobot - IO - [MT Scale] Sent command: I2\n", + "2026-03-30 13:12:15,841 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I2\\r\\n'\n", + "2026-03-30 13:12:15,901 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", + "2026-03-30 13:12:15,901 - pylabrobot - IO - [MT Scale] Received response: b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", + "2026-03-30 13:12:15,902 - pylabrobot - IO - [MT Scale] Sent command: I3\n", + "2026-03-30 13:12:15,903 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I3\\r\\n'\n", + "2026-03-30 13:12:15,949 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I3 A \"1.10 18.6.4.1361.772\"\\r\\n'\n", + "2026-03-30 13:12:15,950 - pylabrobot - IO - [MT Scale] Received response: b'I3 A \"1.10 18.6.4.1361.772\"\\r\\n'\n", + "2026-03-30 13:12:15,954 - pylabrobot - INFO - [MT Scale] Connected to Mettler Toledo scale on /dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0\n", "Device type: WXS205SDU WXA-Bridge\n", + "Configuration: Bridge\n", "Serial number: B207696838\n", + "Firmware: 1.10 18.6.4.1361.772\n", "Capacity: 220.0 g\n", "Supported commands: ['@', 'C0', 'C1', 'C2', 'C3', 'COM', 'DAT', 'FCUT', 'FSET', 'I0', 'I1', 'I10', 'I11', 'I14', 'I15', 'I16', 'I2', 'I21', 'I22', 'I23', 'I24', 'I25', 'I26', 'I3', 'I4', 'I5', 'LST', 'M01', 'M02', 'M03', 'M17', 'M18', 'M19', 'M20', 'M21', 'M27', 'M28', 'M29', 'M31', 'M32', 'M33', 'M35', 'RDB', 'S', 'SI', 'SIR', 'SIS', 'SNR', 'SR', 'T', 'TA', 'TAC', 'TI', 'TIM', 'TST0', 'TST1', 'TST2', 'TST3', 'UPD', 'USTB', 'Z', 'ZI']\n", - "2026-03-30 12:50:45,764 - pylabrobot - IO - [MT Scale] Sent command: M21 0 0\n", - "2026-03-30 12:50:45,768 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'M21 0 0\\r\\n'\n", - "2026-03-30 12:50:45,795 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M21 A\\r\\n'\n", - "2026-03-30 12:50:45,796 - pylabrobot - IO - [MT Scale] Received response: b'M21 A\\r\\n'\n" + "2026-03-30 13:12:15,954 - pylabrobot - IO - [MT Scale] Sent command: M21 0 0\n", + "2026-03-30 13:12:15,960 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'M21 0 0\\r\\n'\n", + "2026-03-30 13:12:15,997 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M21 A\\r\\n'\n", + "2026-03-30 13:12:15,998 - pylabrobot - IO - [MT Scale] Received response: b'M21 A\\r\\n'\n" ] } ], @@ -282,7 +288,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "39 methods available on this device:\n", + "46 methods available on this device:\n", " cancel\n", " cancel_all\n", " clear_tare\n", @@ -292,21 +298,28 @@ " measure_temperature\n", " read_dynamic_weight\n", " read_stable_weight\n", + " read_stable_weight_repeat_on_change\n", " read_weight\n", " read_weight_value_immediately\n", + " request_adjustment_history\n", + " request_auto_zero\n", " request_capacity\n", " request_date\n", " request_device_id\n", " request_device_info\n", " request_device_type\n", + " request_environment_condition\n", " request_model_designation\n", + " request_net_weight_with_status\n", " request_serial_number\n", " request_software_material_number\n", " request_software_version\n", " request_supported_methods\n", " request_tare_weight\n", " request_time\n", + " request_update_rate\n", " request_uptime\n", + " request_weighing_mode\n", " send_command\n", " serialize\n", " set_display_text\n", @@ -351,132 +364,132 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 12:50:45,849 - pylabrobot - IO - [MT Scale] Sent command: I0\n", - "2026-03-30 12:50:45,855 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I0\\r\\n'\n", - "2026-03-30 12:50:45,894 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I0\"\\r\\n'\n", - "2026-03-30 12:50:45,897 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I0\"\\r\\n'\n", - "2026-03-30 12:50:45,902 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I1\"\\r\\n'\n", - "2026-03-30 12:50:45,905 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I1\"\\r\\n'\n", - "2026-03-30 12:50:45,911 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I2\"\\r\\n'\n", - "2026-03-30 12:50:45,913 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I2\"\\r\\n'\n", - "2026-03-30 12:50:45,922 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I3\"\\r\\n'\n", - "2026-03-30 12:50:45,923 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I3\"\\r\\n'\n", - "2026-03-30 12:50:45,938 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I4\"\\r\\n'\n", - "2026-03-30 12:50:45,940 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I4\"\\r\\n'\n", - "2026-03-30 12:50:45,954 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I5\"\\r\\n'\n", - "2026-03-30 12:50:45,955 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I5\"\\r\\n'\n", - "2026-03-30 12:50:45,970 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"S\"\\r\\n'\n", - "2026-03-30 12:50:45,971 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"S\"\\r\\n'\n", - "2026-03-30 12:50:45,976 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"SI\"\\r\\n'\n", - "2026-03-30 12:50:45,980 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"SI\"\\r\\n'\n", - "2026-03-30 12:50:45,987 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"SIR\"\\r\\n'\n", - "2026-03-30 12:50:45,988 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"SIR\"\\r\\n'\n", - "2026-03-30 12:50:46,002 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"Z\"\\r\\n'\n", - "2026-03-30 12:50:46,005 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"Z\"\\r\\n'\n", - "2026-03-30 12:50:46,018 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"ZI\"\\r\\n'\n", - "2026-03-30 12:50:46,020 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"ZI\"\\r\\n'\n", - "2026-03-30 12:50:46,035 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"@\"\\r\\n'\n", - "2026-03-30 12:50:46,036 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"@\"\\r\\n'\n", - "2026-03-30 12:50:46,050 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"SR\"\\r\\n'\n", - "2026-03-30 12:50:46,052 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"SR\"\\r\\n'\n", - "2026-03-30 12:50:46,054 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"T\"\\r\\n'\n", - "2026-03-30 12:50:46,057 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"T\"\\r\\n'\n", - "2026-03-30 12:50:46,066 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"TA\"\\r\\n'\n", - "2026-03-30 12:50:46,067 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"TA\"\\r\\n'\n", - "2026-03-30 12:50:46,082 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"TAC\"\\r\\n'\n", - "2026-03-30 12:50:46,085 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"TAC\"\\r\\n'\n", - "2026-03-30 12:50:46,097 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"TI\"\\r\\n'\n", - "2026-03-30 12:50:46,098 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"TI\"\\r\\n'\n", - "2026-03-30 12:50:46,114 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C0\"\\r\\n'\n", - "2026-03-30 12:50:46,115 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"C0\"\\r\\n'\n", - "2026-03-30 12:50:46,130 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C1\"\\r\\n'\n", - "2026-03-30 12:50:46,131 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"C1\"\\r\\n'\n", - "2026-03-30 12:50:46,147 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C2\"\\r\\n'\n", - "2026-03-30 12:50:46,148 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"C2\"\\r\\n'\n", - "2026-03-30 12:50:46,151 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C3\"\\r\\n'\n", - "2026-03-30 12:50:46,152 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"C3\"\\r\\n'\n", - "2026-03-30 12:50:46,162 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"COM\"\\r\\n'\n", - "2026-03-30 12:50:46,163 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"COM\"\\r\\n'\n", - "2026-03-30 12:50:46,177 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"DAT\"\\r\\n'\n", - "2026-03-30 12:50:46,178 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"DAT\"\\r\\n'\n", - "2026-03-30 12:50:46,195 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I10\"\\r\\n'\n", - "2026-03-30 12:50:46,196 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I10\"\\r\\n'\n", - "2026-03-30 12:50:46,210 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I11\"\\r\\n'\n", - "2026-03-30 12:50:46,212 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I11\"\\r\\n'\n", - "2026-03-30 12:50:46,226 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I14\"\\r\\n'\n", - "2026-03-30 12:50:46,227 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I14\"\\r\\n'\n", - "2026-03-30 12:50:46,242 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I15\"\\r\\n'\n", - "2026-03-30 12:50:46,244 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I15\"\\r\\n'\n", - "2026-03-30 12:50:46,258 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I16\"\\r\\n'\n", - "2026-03-30 12:50:46,260 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I16\"\\r\\n'\n", - "2026-03-30 12:50:46,274 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I21\"\\r\\n'\n", - "2026-03-30 12:50:46,274 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I21\"\\r\\n'\n", - "2026-03-30 12:50:46,289 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I22\"\\r\\n'\n", - "2026-03-30 12:50:46,290 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I22\"\\r\\n'\n", - "2026-03-30 12:50:46,305 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I23\"\\r\\n'\n", - "2026-03-30 12:50:46,306 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I23\"\\r\\n'\n", - "2026-03-30 12:50:46,307 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I24\"\\r\\n'\n", - "2026-03-30 12:50:46,308 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I24\"\\r\\n'\n", - "2026-03-30 12:50:46,322 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I25\"\\r\\n'\n", - "2026-03-30 12:50:46,323 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I25\"\\r\\n'\n", - "2026-03-30 12:50:46,337 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I26\"\\r\\n'\n", - "2026-03-30 12:50:46,338 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I26\"\\r\\n'\n", - "2026-03-30 12:50:46,353 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M01\"\\r\\n'\n", - "2026-03-30 12:50:46,354 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M01\"\\r\\n'\n", - "2026-03-30 12:50:46,370 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M02\"\\r\\n'\n", - "2026-03-30 12:50:46,370 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M02\"\\r\\n'\n", - "2026-03-30 12:50:46,385 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M03\"\\r\\n'\n", - "2026-03-30 12:50:46,386 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M03\"\\r\\n'\n", - "2026-03-30 12:50:46,402 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M17\"\\r\\n'\n", - "2026-03-30 12:50:46,403 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M17\"\\r\\n'\n", - "2026-03-30 12:50:46,417 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M18\"\\r\\n'\n", - "2026-03-30 12:50:46,418 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M18\"\\r\\n'\n", - "2026-03-30 12:50:46,433 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M19\"\\r\\n'\n", - "2026-03-30 12:50:46,434 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M19\"\\r\\n'\n", - "2026-03-30 12:50:46,450 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M20\"\\r\\n'\n", - "2026-03-30 12:50:46,451 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M20\"\\r\\n'\n", - "2026-03-30 12:50:46,465 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M21\"\\r\\n'\n", - "2026-03-30 12:50:46,466 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M21\"\\r\\n'\n", - "2026-03-30 12:50:46,481 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M27\"\\r\\n'\n", - "2026-03-30 12:50:46,482 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M27\"\\r\\n'\n", - "2026-03-30 12:50:46,484 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M28\"\\r\\n'\n", - "2026-03-30 12:50:46,485 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M28\"\\r\\n'\n", - "2026-03-30 12:50:46,498 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M29\"\\r\\n'\n", - "2026-03-30 12:50:46,499 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M29\"\\r\\n'\n", - "2026-03-30 12:50:46,513 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M31\"\\r\\n'\n", - "2026-03-30 12:50:46,514 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M31\"\\r\\n'\n", - "2026-03-30 12:50:46,529 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M32\"\\r\\n'\n", - "2026-03-30 12:50:46,530 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M32\"\\r\\n'\n", - "2026-03-30 12:50:46,546 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M33\"\\r\\n'\n", - "2026-03-30 12:50:46,547 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M33\"\\r\\n'\n", - "2026-03-30 12:50:46,561 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M35\"\\r\\n'\n", - "2026-03-30 12:50:46,562 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M35\"\\r\\n'\n", - "2026-03-30 12:50:46,577 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"SIS\"\\r\\n'\n", - "2026-03-30 12:50:46,578 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"SIS\"\\r\\n'\n", - "2026-03-30 12:50:46,594 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"SNR\"\\r\\n'\n", - "2026-03-30 12:50:46,595 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"SNR\"\\r\\n'\n", - "2026-03-30 12:50:46,609 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TIM\"\\r\\n'\n", - "2026-03-30 12:50:46,610 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TIM\"\\r\\n'\n", - "2026-03-30 12:50:46,626 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST0\"\\r\\n'\n", - "2026-03-30 12:50:46,626 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TST0\"\\r\\n'\n", - "2026-03-30 12:50:46,641 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST1\"\\r\\n'\n", - "2026-03-30 12:50:46,642 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TST1\"\\r\\n'\n", - "2026-03-30 12:50:46,657 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST2\"\\r\\n'\n", - "2026-03-30 12:50:46,659 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TST2\"\\r\\n'\n", - "2026-03-30 12:50:46,674 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST3\"\\r\\n'\n", - "2026-03-30 12:50:46,675 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TST3\"\\r\\n'\n", - "2026-03-30 12:50:46,676 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"UPD\"\\r\\n'\n", - "2026-03-30 12:50:46,677 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"UPD\"\\r\\n'\n", - "2026-03-30 12:50:46,705 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"FCUT\"\\r\\n'\n", - "2026-03-30 12:50:46,706 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 3 \"FCUT\"\\r\\n'\n", - "2026-03-30 12:50:46,708 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"FSET\"\\r\\n'\n", - "2026-03-30 12:50:46,709 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 3 \"FSET\"\\r\\n'\n", - "2026-03-30 12:50:46,722 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"LST\"\\r\\n'\n", - "2026-03-30 12:50:46,723 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 3 \"LST\"\\r\\n'\n", - "2026-03-30 12:50:46,737 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"RDB\"\\r\\n'\n", - "2026-03-30 12:50:46,738 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 3 \"RDB\"\\r\\n'\n", - "2026-03-30 12:50:46,753 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 A 3 \"USTB\"\\r\\n'\n", - "2026-03-30 12:50:46,754 - pylabrobot - IO - [MT Scale] Received response: b'I0 A 3 \"USTB\"\\r\\n'\n" + "2026-03-30 13:12:16,056 - pylabrobot - IO - [MT Scale] Sent command: I0\n", + "2026-03-30 13:12:16,058 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I0\\r\\n'\n", + "2026-03-30 13:12:16,093 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I0\"\\r\\n'\n", + "2026-03-30 13:12:16,094 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I0\"\\r\\n'\n", + "2026-03-30 13:12:16,109 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I1\"\\r\\n'\n", + "2026-03-30 13:12:16,109 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I1\"\\r\\n'\n", + "2026-03-30 13:12:16,125 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I2\"\\r\\n'\n", + "2026-03-30 13:12:16,126 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I2\"\\r\\n'\n", + "2026-03-30 13:12:16,127 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I3\"\\r\\n'\n", + "2026-03-30 13:12:16,128 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I3\"\\r\\n'\n", + "2026-03-30 13:12:16,141 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I4\"\\r\\n'\n", + "2026-03-30 13:12:16,142 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I4\"\\r\\n'\n", + "2026-03-30 13:12:16,157 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I5\"\\r\\n'\n", + "2026-03-30 13:12:16,158 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I5\"\\r\\n'\n", + "2026-03-30 13:12:16,173 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"S\"\\r\\n'\n", + "2026-03-30 13:12:16,174 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"S\"\\r\\n'\n", + "2026-03-30 13:12:16,189 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"SI\"\\r\\n'\n", + "2026-03-30 13:12:16,192 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"SI\"\\r\\n'\n", + "2026-03-30 13:12:16,207 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"SIR\"\\r\\n'\n", + "2026-03-30 13:12:16,208 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"SIR\"\\r\\n'\n", + "2026-03-30 13:12:16,217 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"Z\"\\r\\n'\n", + "2026-03-30 13:12:16,218 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"Z\"\\r\\n'\n", + "2026-03-30 13:12:16,221 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"ZI\"\\r\\n'\n", + "2026-03-30 13:12:16,222 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"ZI\"\\r\\n'\n", + "2026-03-30 13:12:16,237 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"@\"\\r\\n'\n", + "2026-03-30 13:12:16,239 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"@\"\\r\\n'\n", + "2026-03-30 13:12:16,253 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"SR\"\\r\\n'\n", + "2026-03-30 13:12:16,254 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"SR\"\\r\\n'\n", + "2026-03-30 13:12:16,269 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"T\"\\r\\n'\n", + "2026-03-30 13:12:16,271 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"T\"\\r\\n'\n", + "2026-03-30 13:12:16,284 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"TA\"\\r\\n'\n", + "2026-03-30 13:12:16,285 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"TA\"\\r\\n'\n", + "2026-03-30 13:12:16,287 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"TAC\"\\r\\n'\n", + "2026-03-30 13:12:16,288 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"TAC\"\\r\\n'\n", + "2026-03-30 13:12:16,301 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"TI\"\\r\\n'\n", + "2026-03-30 13:12:16,306 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"TI\"\\r\\n'\n", + "2026-03-30 13:12:16,318 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C0\"\\r\\n'\n", + "2026-03-30 13:12:16,319 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"C0\"\\r\\n'\n", + "2026-03-30 13:12:16,333 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C1\"\\r\\n'\n", + "2026-03-30 13:12:16,334 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"C1\"\\r\\n'\n", + "2026-03-30 13:12:16,349 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C2\"\\r\\n'\n", + "2026-03-30 13:12:16,353 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"C2\"\\r\\n'\n", + "2026-03-30 13:12:16,365 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C3\"\\r\\n'\n", + "2026-03-30 13:12:16,368 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"C3\"\\r\\n'\n", + "2026-03-30 13:12:16,381 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"COM\"\\r\\n'\n", + "2026-03-30 13:12:16,384 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"COM\"\\r\\n'\n", + "2026-03-30 13:12:16,389 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"DAT\"\\r\\n'\n", + "2026-03-30 13:12:16,391 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"DAT\"\\r\\n'\n", + "2026-03-30 13:12:16,396 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I10\"\\r\\n'\n", + "2026-03-30 13:12:16,399 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I10\"\\r\\n'\n", + "2026-03-30 13:12:16,413 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I11\"\\r\\n'\n", + "2026-03-30 13:12:16,417 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I11\"\\r\\n'\n", + "2026-03-30 13:12:16,429 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I14\"\\r\\n'\n", + "2026-03-30 13:12:16,433 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I14\"\\r\\n'\n", + "2026-03-30 13:12:16,445 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I15\"\\r\\n'\n", + "2026-03-30 13:12:16,446 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I15\"\\r\\n'\n", + "2026-03-30 13:12:16,460 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I16\"\\r\\n'\n", + "2026-03-30 13:12:16,461 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I16\"\\r\\n'\n", + "2026-03-30 13:12:16,477 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I21\"\\r\\n'\n", + "2026-03-30 13:12:16,477 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I21\"\\r\\n'\n", + "2026-03-30 13:12:16,493 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I22\"\\r\\n'\n", + "2026-03-30 13:12:16,494 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I22\"\\r\\n'\n", + "2026-03-30 13:12:16,508 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I23\"\\r\\n'\n", + "2026-03-30 13:12:16,509 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I23\"\\r\\n'\n", + "2026-03-30 13:12:16,525 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I24\"\\r\\n'\n", + "2026-03-30 13:12:16,525 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I24\"\\r\\n'\n", + "2026-03-30 13:12:16,540 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I25\"\\r\\n'\n", + "2026-03-30 13:12:16,540 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I25\"\\r\\n'\n", + "2026-03-30 13:12:16,556 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I26\"\\r\\n'\n", + "2026-03-30 13:12:16,557 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I26\"\\r\\n'\n", + "2026-03-30 13:12:16,558 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M01\"\\r\\n'\n", + "2026-03-30 13:12:16,559 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M01\"\\r\\n'\n", + "2026-03-30 13:12:16,573 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M02\"\\r\\n'\n", + "2026-03-30 13:12:16,573 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M02\"\\r\\n'\n", + "2026-03-30 13:12:16,588 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M03\"\\r\\n'\n", + "2026-03-30 13:12:16,589 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M03\"\\r\\n'\n", + "2026-03-30 13:12:16,604 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M17\"\\r\\n'\n", + "2026-03-30 13:12:16,605 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M17\"\\r\\n'\n", + "2026-03-30 13:12:16,621 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M18\"\\r\\n'\n", + "2026-03-30 13:12:16,621 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M18\"\\r\\n'\n", + "2026-03-30 13:12:16,636 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M19\"\\r\\n'\n", + "2026-03-30 13:12:16,637 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M19\"\\r\\n'\n", + "2026-03-30 13:12:16,652 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M20\"\\r\\n'\n", + "2026-03-30 13:12:16,653 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M20\"\\r\\n'\n", + "2026-03-30 13:12:16,669 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M21\"\\r\\n'\n", + "2026-03-30 13:12:16,669 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M21\"\\r\\n'\n", + "2026-03-30 13:12:16,684 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M27\"\\r\\n'\n", + "2026-03-30 13:12:16,685 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M27\"\\r\\n'\n", + "2026-03-30 13:12:16,700 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M28\"\\r\\n'\n", + "2026-03-30 13:12:16,701 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M28\"\\r\\n'\n", + "2026-03-30 13:12:16,717 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M29\"\\r\\n'\n", + "2026-03-30 13:12:16,717 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M29\"\\r\\n'\n", + "2026-03-30 13:12:16,718 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M31\"\\r\\n'\n", + "2026-03-30 13:12:16,719 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M31\"\\r\\n'\n", + "2026-03-30 13:12:16,732 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M32\"\\r\\n'\n", + "2026-03-30 13:12:16,733 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M32\"\\r\\n'\n", + "2026-03-30 13:12:16,748 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M33\"\\r\\n'\n", + "2026-03-30 13:12:16,749 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M33\"\\r\\n'\n", + "2026-03-30 13:12:16,765 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M35\"\\r\\n'\n", + "2026-03-30 13:12:16,765 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M35\"\\r\\n'\n", + "2026-03-30 13:12:16,780 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"SIS\"\\r\\n'\n", + "2026-03-30 13:12:16,781 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"SIS\"\\r\\n'\n", + "2026-03-30 13:12:16,796 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"SNR\"\\r\\n'\n", + "2026-03-30 13:12:16,797 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"SNR\"\\r\\n'\n", + "2026-03-30 13:12:16,813 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TIM\"\\r\\n'\n", + "2026-03-30 13:12:16,814 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TIM\"\\r\\n'\n", + "2026-03-30 13:12:16,828 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST0\"\\r\\n'\n", + "2026-03-30 13:12:16,829 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TST0\"\\r\\n'\n", + "2026-03-30 13:12:16,845 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST1\"\\r\\n'\n", + "2026-03-30 13:12:16,845 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TST1\"\\r\\n'\n", + "2026-03-30 13:12:16,860 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST2\"\\r\\n'\n", + "2026-03-30 13:12:16,861 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TST2\"\\r\\n'\n", + "2026-03-30 13:12:16,876 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST3\"\\r\\n'\n", + "2026-03-30 13:12:16,877 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TST3\"\\r\\n'\n", + "2026-03-30 13:12:16,892 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"UPD\"\\r\\n'\n", + "2026-03-30 13:12:16,893 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"UPD\"\\r\\n'\n", + "2026-03-30 13:12:16,908 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"FCUT\"\\r\\n'\n", + "2026-03-30 13:12:16,909 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 3 \"FCUT\"\\r\\n'\n", + "2026-03-30 13:12:16,924 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"FSET\"\\r\\n'\n", + "2026-03-30 13:12:16,925 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 3 \"FSET\"\\r\\n'\n", + "2026-03-30 13:12:16,941 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"LST\"\\r\\n'\n", + "2026-03-30 13:12:16,941 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 3 \"LST\"\\r\\n'\n", + "2026-03-30 13:12:16,956 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"RDB\"\\r\\n'\n", + "2026-03-30 13:12:16,956 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 3 \"RDB\"\\r\\n'\n", + "2026-03-30 13:12:16,972 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 A 3 \"USTB\"\\r\\n'\n", + "2026-03-30 13:12:16,973 - pylabrobot - IO - [MT Scale] Received response: b'I0 A 3 \"USTB\"\\r\\n'\n" ] }, { @@ -585,10 +598,213 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 6, "metadata": {}, - "outputs": [], - "source": "# I3 - Software version (Level 0, always available)\nsw_version = await backend.request_software_version()\nprint(f\"Software version: {sw_version}\")\n\n# I5 - Software material number (Level 0, always available)\nsw_material = await backend.request_software_material_number()\nprint(f\"Software material number: {sw_material}\")\n\n# I10 - Device ID (user-assignable name)\nif \"I10\" in backend._supported_commands:\n device_id = await backend.request_device_id()\n print(f\"Device ID: '{device_id}'\")\nelse:\n print(\"SKIP: I10 not supported\")\n\n# I11 - Model designation\nif \"I11\" in backend._supported_commands:\n model = await backend.request_model_designation()\n print(f\"Model designation: {model}\")\nelse:\n print(\"SKIP: I11 not supported\")\n\n# I15 - Uptime\nif \"I15\" in backend._supported_commands:\n uptime = await backend.request_uptime()\n print(f\"Uptime: {uptime['days']}d {uptime['hours']}h {uptime['minutes']}m {uptime['seconds']}s\")\nelse:\n print(\"SKIP: I15 not supported\")\n\n# DAT - Date\nif \"DAT\" in backend._supported_commands:\n date = await backend.request_date()\n print(f\"Device date: {date}\")\nelse:\n print(\"SKIP: DAT not supported\")\n\n# TIM - Time\nif \"TIM\" in backend._supported_commands:\n time_str = await backend.request_time()\n print(f\"Device time: {time_str}\")\nelse:\n print(\"SKIP: TIM not supported\")\n\n# I14 - Comprehensive device info (query each category separately)\nif \"I14\" in backend._supported_commands:\n category_names = {\n 0: \"Instrument configuration\",\n 1: \"Instrument descriptions\",\n 2: \"SW identification numbers\",\n 3: \"SW versions\",\n 4: \"Serial numbers\",\n 5: \"TDNR numbers\",\n }\n print(\"\\nDevice info (I14):\")\n for cat, name in category_names.items():\n try:\n info = await backend.request_device_info(category=cat)\n print(f\" Category {cat} ({name}):\")\n for resp in info:\n print(f\" {resp.command} {resp.status} {' '.join(resp.data)}\")\n except Exception as e:\n print(f\" Category {cat} ({name}): {e}\")\nelse:\n print(\"SKIP: I14 not supported\")\n\nprint(\"\\nPASS: Batch 1 device identity commands completed\")" + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2026-03-30 13:12:16,984 - pylabrobot - IO - [MT Scale] Sent command: I3\n", + "2026-03-30 13:12:16,986 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I3\\r\\n'\n", + "2026-03-30 13:12:17,036 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I3 A \"1.10 18.6.4.1361.772\"\\r\\n'\n", + "2026-03-30 13:12:17,038 - pylabrobot - IO - [MT Scale] Received response: b'I3 A \"1.10 18.6.4.1361.772\"\\r\\n'\n", + "2026-03-30 13:12:17,038 - pylabrobot - IO - [MT Scale] Sent command: I5\n", + "2026-03-30 13:12:17,041 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I5\\r\\n'\n", + "2026-03-30 13:12:17,084 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I5 A \"11671158C\"\\r\\n'\n", + "2026-03-30 13:12:17,084 - pylabrobot - IO - [MT Scale] Received response: b'I5 A \"11671158C\"\\r\\n'\n", + "2026-03-30 13:12:17,085 - pylabrobot - IO - [MT Scale] Sent command: I10\n", + "2026-03-30 13:12:17,087 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I10\\r\\n'\n", + "2026-03-30 13:12:17,116 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I10 A \"\"\\r\\n'\n", + "2026-03-30 13:12:17,117 - pylabrobot - IO - [MT Scale] Received response: b'I10 A \"\"\\r\\n'\n", + "2026-03-30 13:12:17,118 - pylabrobot - IO - [MT Scale] Sent command: I11\n", + "2026-03-30 13:12:17,120 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I11\\r\\n'\n", + "2026-03-30 13:12:17,164 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I11 A \"WXS205SDU\"\\r\\n'\n", + "2026-03-30 13:12:17,166 - pylabrobot - IO - [MT Scale] Received response: b'I11 A \"WXS205SDU\"\\r\\n'\n", + "2026-03-30 13:12:17,167 - pylabrobot - IO - [MT Scale] Sent command: I15\n", + "2026-03-30 13:12:17,168 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I15\\r\\n'\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Software version: 1.10 18.6.4.1361.772\n", + "Software material number: 11671158C\n", + "Device ID: ''\n", + "Model designation: WXS205SDU\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2026-03-30 13:12:17,196 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I15 A 224\\r\\n'\n", + "2026-03-30 13:12:17,197 - pylabrobot - IO - [MT Scale] Received response: b'I15 A 224\\r\\n'\n", + "2026-03-30 13:12:17,201 - pylabrobot - IO - [MT Scale] Sent command: DAT\n", + "2026-03-30 13:12:17,202 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'DAT\\r\\n'\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Uptime: 224d 0h 0m 0s\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2026-03-30 13:12:17,244 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'DAT A 04 01 2000\\r\\n'\n", + "2026-03-30 13:12:17,245 - pylabrobot - IO - [MT Scale] Received response: b'DAT A 04 01 2000\\r\\n'\n", + "2026-03-30 13:12:17,247 - pylabrobot - IO - [MT Scale] Sent command: TIM\n", + "2026-03-30 13:12:17,248 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'TIM\\r\\n'\n", + "2026-03-30 13:12:17,276 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'TIM A 20 17 43\\r\\n'\n", + "2026-03-30 13:12:17,277 - pylabrobot - IO - [MT Scale] Received response: b'TIM A 20 17 43\\r\\n'\n", + "2026-03-30 13:12:17,278 - pylabrobot - IO - [MT Scale] Sent command: I14 0\n", + "2026-03-30 13:12:17,279 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I14 0\\r\\n'\n", + "2026-03-30 13:12:17,324 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I14 A 0 1 \"Bridge\"\\r\\n'\n", + "2026-03-30 13:12:17,324 - pylabrobot - IO - [MT Scale] Received response: b'I14 A 0 1 \"Bridge\"\\r\\n'\n", + "2026-03-30 13:12:17,325 - pylabrobot - IO - [MT Scale] Sent command: I14 1\n", + "2026-03-30 13:12:17,326 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I14 1\\r\\n'\n", + "2026-03-30 13:12:17,372 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I14 A 1 1 \"WXS205SDU\"\\r\\n'\n", + "2026-03-30 13:12:17,373 - pylabrobot - IO - [MT Scale] Received response: b'I14 A 1 1 \"WXS205SDU\"\\r\\n'\n", + "2026-03-30 13:12:17,373 - pylabrobot - IO - [MT Scale] Sent command: I14 2\n", + "2026-03-30 13:12:17,374 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I14 2\\r\\n'\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Device date: 04\n", + "Device time: 20\n", + "\n", + "Device info (I14):\n", + " Category 0 (Instrument configuration):\n", + " I14 A 0 1 Bridge\n", + " Category 1 (Instrument descriptions):\n", + " I14 A 1 1 WXS205SDU\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2026-03-30 13:12:17,420 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I14 A 2 1 \"11671158C\"\\r\\n'\n", + "2026-03-30 13:12:17,421 - pylabrobot - IO - [MT Scale] Received response: b'I14 A 2 1 \"11671158C\"\\r\\n'\n", + "2026-03-30 13:12:17,421 - pylabrobot - IO - [MT Scale] Sent command: I14 3\n", + "2026-03-30 13:12:17,422 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I14 3\\r\\n'\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Category 2 (SW identification numbers):\n", + " I14 A 2 1 11671158C\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2026-03-30 13:12:17,468 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I14 A 3 1 \"1.10\"\\r\\n'\n", + "2026-03-30 13:12:17,468 - pylabrobot - IO - [MT Scale] Received response: b'I14 A 3 1 \"1.10\"\\r\\n'\n", + "2026-03-30 13:12:17,469 - pylabrobot - IO - [MT Scale] Sent command: I14 4\n", + "2026-03-30 13:12:17,470 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I14 4\\r\\n'\n", + "2026-03-30 13:12:17,516 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I14 A 4 1 \"B207696838\"\\r\\n'\n", + "2026-03-30 13:12:17,517 - pylabrobot - IO - [MT Scale] Received response: b'I14 A 4 1 \"B207696838\"\\r\\n'\n", + "2026-03-30 13:12:17,517 - pylabrobot - IO - [MT Scale] Sent command: I14 5\n", + "2026-03-30 13:12:17,518 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I14 5\\r\\n'\n", + "2026-03-30 13:12:17,564 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I14 A 5 1 \"18.6.4.1361.772\"\\r\\n'\n", + "2026-03-30 13:12:17,565 - pylabrobot - IO - [MT Scale] Received response: b'I14 A 5 1 \"18.6.4.1361.772\"\\r\\n'\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Category 3 (SW versions):\n", + " I14 A 3 1 1.10\n", + " Category 4 (Serial numbers):\n", + " I14 A 4 1 B207696838\n", + " Category 5 (TDNR numbers):\n", + " I14 A 5 1 18.6.4.1361.772\n", + "\n", + "PASS: Batch 1 device identity commands completed\n" + ] + } + ], + "source": [ + "# I3 - Software version (Level 0, always available)\n", + "sw_version = await backend.request_software_version()\n", + "print(f\"Software version: {sw_version}\")\n", + "\n", + "# I5 - Software material number (Level 0, always available)\n", + "sw_material = await backend.request_software_material_number()\n", + "print(f\"Software material number: {sw_material}\")\n", + "\n", + "# I10 - Device ID (user-assignable name)\n", + "if \"I10\" in backend._supported_commands:\n", + " device_id = await backend.request_device_id()\n", + " print(f\"Device ID: '{device_id}'\")\n", + "else:\n", + " print(\"SKIP: I10 not supported\")\n", + "\n", + "# I11 - Model designation\n", + "if \"I11\" in backend._supported_commands:\n", + " model = await backend.request_model_designation()\n", + " print(f\"Model designation: {model}\")\n", + "else:\n", + " print(\"SKIP: I11 not supported\")\n", + "\n", + "# I15 - Uptime\n", + "if \"I15\" in backend._supported_commands:\n", + " uptime = await backend.request_uptime()\n", + " print(f\"Uptime: {uptime['days']}d {uptime['hours']}h {uptime['minutes']}m {uptime['seconds']}s\")\n", + "else:\n", + " print(\"SKIP: I15 not supported\")\n", + "\n", + "# DAT - Date\n", + "if \"DAT\" in backend._supported_commands:\n", + " date = await backend.request_date()\n", + " print(f\"Device date: {date}\")\n", + "else:\n", + " print(\"SKIP: DAT not supported\")\n", + "\n", + "# TIM - Time\n", + "if \"TIM\" in backend._supported_commands:\n", + " time_str = await backend.request_time()\n", + " print(f\"Device time: {time_str}\")\n", + "else:\n", + " print(\"SKIP: TIM not supported\")\n", + "\n", + "# I14 - Comprehensive device info (query each category separately)\n", + "if \"I14\" in backend._supported_commands:\n", + " category_names = {\n", + " 0: \"Instrument configuration\",\n", + " 1: \"Instrument descriptions\",\n", + " 2: \"SW identification numbers\",\n", + " 3: \"SW versions\",\n", + " 4: \"Serial numbers\",\n", + " 5: \"TDNR numbers\",\n", + " }\n", + " print(\"\\nDevice info (I14):\")\n", + " for cat, name in category_names.items():\n", + " try:\n", + " info = await backend.request_device_info(category=cat)\n", + " print(f\" Category {cat} ({name}):\")\n", + " for resp in info:\n", + " print(f\" {resp.command} {resp.status} {' '.join(resp.data)}\")\n", + " except Exception as e:\n", + " print(f\" Category {cat} ({name}): {e}\")\n", + "else:\n", + " print(\"SKIP: I14 not supported\")\n", + "\n", + "print(\"\\nPASS: Batch 1 device identity commands completed\")" + ] }, { "cell_type": "markdown", @@ -607,9 +823,29 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 7, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2026-03-30 13:12:17,574 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] reset_input_buffer\n", + "2026-03-30 13:12:17,575 - pylabrobot - IO - [MT Scale] Sent command: @\n", + "2026-03-30 13:12:17,577 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'@\\r\\n'\n", + "2026-03-30 13:12:17,628 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I4 A \"B207696838\"\\r\\n'\n", + "2026-03-30 13:12:17,629 - pylabrobot - IO - [MT Scale] Received response: b'I4 A \"B207696838\"\\r\\n'\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Cancel returned serial number: B207696838\n", + "PASS: cancel returns correct serial number\n" + ] + } + ], "source": [ "serial_number = await backend.cancel()\n", "print(f\"Cancel returned serial number: {serial_number}\")\n", @@ -626,9 +862,28 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 8, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2026-03-30 13:12:17,637 - pylabrobot - IO - [MT Scale] Sent command: I4\n", + "2026-03-30 13:12:17,640 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I4\\r\\n'\n", + "2026-03-30 13:12:17,676 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I4 A \"B207696838\"\\r\\n'\n", + "2026-03-30 13:12:17,676 - pylabrobot - IO - [MT Scale] Received response: b'I4 A \"B207696838\"\\r\\n'\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Serial number: B207696838\n", + "PASS: serial number is non-empty\n" + ] + } + ], "source": [ "sn = await backend.request_serial_number()\n", "print(f\"Serial number: {sn}\")\n", @@ -645,9 +900,33 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 9, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2026-03-30 13:12:17,683 - pylabrobot - IO - [MT Scale] Sent command: I2\n", + "2026-03-30 13:12:17,686 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I2\\r\\n'\n", + "2026-03-30 13:12:17,756 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", + "2026-03-30 13:12:17,756 - pylabrobot - IO - [MT Scale] Received response: b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", + "2026-03-30 13:12:17,757 - pylabrobot - IO - [MT Scale] Sent command: I2\n", + "2026-03-30 13:12:17,760 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I2\\r\\n'\n", + "2026-03-30 13:12:17,819 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", + "2026-03-30 13:12:17,820 - pylabrobot - IO - [MT Scale] Received response: b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Device type: WXS205SDU WXA-Bridge\n", + "Capacity: 220.009 g\n", + "PASS: device type and capacity valid\n" + ] + } + ], "source": [ "device_type = await backend.request_device_type()\n", "capacity = await backend.request_capacity()\n", @@ -667,9 +946,29 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 10, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2026-03-30 13:12:17,829 - pylabrobot - IO - [MT Scale] Sent command: I1\n", + "2026-03-30 13:12:17,831 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I1\\r\\n'\n", + "2026-03-30 13:12:17,884 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I1 A \"01\" \"2.30\" \"2.22\" \"\" \"\"\\r\\n'\n", + "2026-03-30 13:12:17,885 - pylabrobot - IO - [MT Scale] Received response: b'I1 A \"01\" \"2.30\" \"2.22\" \"\" \"\"\\r\\n'\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "I1 reported levels: ['01', '2.30', '2.22', '', '']\n", + "I0 discovered 62 commands\n", + "Note: I1 may underreport - I0 is the authoritative source\n" + ] + } + ], "source": [ "# I1 reports standardized level sets (may not reflect all available commands)\n", "# I0 is the definitive source (already queried during setup)\n", @@ -688,9 +987,28 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 11, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2026-03-30 13:12:17,899 - pylabrobot - IO - [MT Scale] Sent command: S\n", + "2026-03-30 13:12:17,907 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", + "2026-03-30 13:12:18,123 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00003 g\\r\\n'\n", + "2026-03-30 13:12:18,124 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00003 g\\r\\n'\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Stable weight (empty pan): 3e-05 g\n", + "PASS: stable weight returns float\n" + ] + } + ], "source": [ "weight = await backend.read_stable_weight()\n", "print(f\"Stable weight (empty pan): {weight} g\")\n", @@ -707,9 +1025,28 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 12, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2026-03-30 13:12:18,134 - pylabrobot - IO - [MT Scale] Sent command: SI\n", + "2026-03-30 13:12:18,140 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", + "2026-03-30 13:12:18,171 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00003 g\\r\\n'\n", + "2026-03-30 13:12:18,173 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00003 g\\r\\n'\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Immediate weight: 3e-05 g\n", + "PASS: immediate weight returns float\n" + ] + } + ], "source": [ "weight = await backend.read_weight_value_immediately()\n", "print(f\"Immediate weight: {weight} g\")\n", @@ -726,9 +1063,32 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 13, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2026-03-30 13:12:18,180 - pylabrobot - IO - [MT Scale] Sent command: Z\n", + "2026-03-30 13:12:18,184 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'Z\\r\\n'\n", + "2026-03-30 13:12:18,491 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'Z A\\r\\n'\n", + "2026-03-30 13:12:18,492 - pylabrobot - IO - [MT Scale] Received response: b'Z A\\r\\n'\n", + "2026-03-30 13:12:18,493 - pylabrobot - IO - [MT Scale] Sent command: SI\n", + "2026-03-30 13:12:18,496 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", + "2026-03-30 13:12:18,523 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 13:12:18,524 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Weight after zero: 0.0 g\n", + "PASS: zero sets weight to ~0\n" + ] + } + ], "source": [ "await scale.zero(timeout=\"stable\")\n", "weight = await backend.read_weight_value_immediately()\n", @@ -746,9 +1106,32 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 14, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2026-03-30 13:12:18,531 - pylabrobot - IO - [MT Scale] Sent command: ZI\n", + "2026-03-30 13:12:18,534 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'ZI\\r\\n'\n", + "2026-03-30 13:12:18,554 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'ZI S\\r\\n'\n", + "2026-03-30 13:12:18,555 - pylabrobot - IO - [MT Scale] Received response: b'ZI S\\r\\n'\n", + "2026-03-30 13:12:18,556 - pylabrobot - IO - [MT Scale] Sent command: SI\n", + "2026-03-30 13:12:18,558 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", + "2026-03-30 13:12:18,602 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 13:12:18,603 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Weight after zero immediately: 0.0 g\n", + "PASS: zero immediately sets weight to ~0\n" + ] + } + ], "source": [ "await scale.zero(timeout=0)\n", "weight = await backend.read_weight_value_immediately()\n", @@ -776,9 +1159,53 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 15, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdin", + "output_type": "stream", + "text": [ + "Place a container on the scale and press Enter... \n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2026-03-30 13:12:23,026 - pylabrobot - IO - [MT Scale] Sent command: Z\n", + "2026-03-30 13:12:23,028 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'Z\\r\\n'\n", + "2026-03-30 13:12:23,414 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'Z A\\r\\n'\n", + "2026-03-30 13:12:23,415 - pylabrobot - IO - [MT Scale] Received response: b'Z A\\r\\n'\n", + "2026-03-30 13:12:23,416 - pylabrobot - IO - [MT Scale] Sent command: T\n", + "2026-03-30 13:12:23,417 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'T\\r\\n'\n", + "2026-03-30 13:12:23,830 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'T S 0.00000 g\\r\\n'\n", + "2026-03-30 13:12:23,831 - pylabrobot - IO - [MT Scale] Received response: b'T S 0.00000 g\\r\\n'\n", + "2026-03-30 13:12:23,831 - pylabrobot - IO - [MT Scale] Sent command: TA\n", + "2026-03-30 13:12:23,833 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'TA\\r\\n'\n", + "2026-03-30 13:12:23,926 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'TA A 0.00000 g\\r\\n'\n", + "2026-03-30 13:12:23,927 - pylabrobot - IO - [MT Scale] Received response: b'TA A 0.00000 g\\r\\n'\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Tare weight: 0.0 g\n" + ] + }, + { + "ename": "AssertionError", + "evalue": "Expected positive tare, got 0.0", + "output_type": "error", + "traceback": [ + "\u001b[31m---------------------------------------------------------------------------\u001b[39m", + "\u001b[31mAssertionError\u001b[39m Traceback (most recent call last)", + "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[15]\u001b[39m\u001b[32m, line 6\u001b[39m\n\u001b[32m 4\u001b[39m tare = \u001b[38;5;28;01mawait\u001b[39;00m scale.request_tare_weight()\n\u001b[32m 5\u001b[39m \u001b[38;5;28mprint\u001b[39m(\u001b[33mf\u001b[39m\u001b[33m\"\u001b[39m\u001b[33mTare weight: \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mtare\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m g\u001b[39m\u001b[33m\"\u001b[39m)\n\u001b[32m----> \u001b[39m\u001b[32m6\u001b[39m \u001b[38;5;28;01massert\u001b[39;00m tare > \u001b[32m0\u001b[39m, \u001b[33mf\u001b[39m\u001b[33m\"\u001b[39m\u001b[33mExpected positive tare, got \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mtare\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m\"\u001b[39m\n\u001b[32m 7\u001b[39m \u001b[38;5;28mprint\u001b[39m(\u001b[33m\"\u001b[39m\u001b[33mPASS: tare stores container weight\u001b[39m\u001b[33m\"\u001b[39m)\n", + "\u001b[31mAssertionError\u001b[39m: Expected positive tare, got 0.0" + ] + } + ], "source": [ "input(\"Place a container on the scale and press Enter...\")\n", "await scale.zero(timeout=\"stable\")\n", @@ -798,9 +1225,28 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 16, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2026-03-30 13:12:26,003 - pylabrobot - IO - [MT Scale] Sent command: TA\n", + "2026-03-30 13:12:26,006 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'TA\\r\\n'\n", + "2026-03-30 13:12:26,084 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'TA A 0.00000 g\\r\\n'\n", + "2026-03-30 13:12:26,086 - pylabrobot - IO - [MT Scale] Received response: b'TA A 0.00000 g\\r\\n'\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Tare weight from memory: 0.0 g\n", + "PASS: tare weight readable from memory\n" + ] + } + ], "source": [ "tare = await scale.request_tare_weight()\n", "print(f\"Tare weight from memory: {tare} g\")\n", @@ -817,9 +1263,32 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 17, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2026-03-30 13:12:26,799 - pylabrobot - IO - [MT Scale] Sent command: TAC\n", + "2026-03-30 13:12:26,801 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'TAC\\r\\n'\n", + "2026-03-30 13:12:26,836 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'TAC A\\r\\n'\n", + "2026-03-30 13:12:26,837 - pylabrobot - IO - [MT Scale] Received response: b'TAC A\\r\\n'\n", + "2026-03-30 13:12:26,839 - pylabrobot - IO - [MT Scale] Sent command: TA\n", + "2026-03-30 13:12:26,841 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'TA\\r\\n'\n", + "2026-03-30 13:12:26,964 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'TA A 0.00000 g\\r\\n'\n", + "2026-03-30 13:12:26,965 - pylabrobot - IO - [MT Scale] Received response: b'TA A 0.00000 g\\r\\n'\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Tare after clear: 0.0 g\n", + "PASS: clear tare resets tare to 0\n" + ] + } + ], "source": [ "await backend.clear_tare()\n", "tare_after_clear = await scale.request_tare_weight()\n", @@ -837,9 +1306,34 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 18, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2026-03-30 13:12:27,748 - pylabrobot - IO - [MT Scale] Sent command: SC 3000\n", + "2026-03-30 13:12:27,750 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SC 3000\\r\\n'\n", + "2026-03-30 13:12:27,779 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'ES\\r\\n'\n", + "2026-03-30 13:12:27,780 - pylabrobot - IO - [MT Scale] Received response: b'ES\\r\\n'\n" + ] + }, + { + "ename": "MettlerToledoError", + "evalue": "Syntax error: The weigh module/balance has not recognized the received command or the command is not allowed", + "output_type": "error", + "traceback": [ + "\u001b[31m---------------------------------------------------------------------------\u001b[39m", + "\u001b[31mMettlerToledoError\u001b[39m Traceback (most recent call last)", + "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[18]\u001b[39m\u001b[32m, line 1\u001b[39m\n\u001b[32m----> \u001b[39m\u001b[32m1\u001b[39m weight = \u001b[38;5;28;01mawait\u001b[39;00m backend.read_dynamic_weight(timeout=\u001b[32m3.0\u001b[39m)\n\u001b[32m 2\u001b[39m \u001b[38;5;28mprint\u001b[39m(\u001b[33mf\u001b[39m\u001b[33m\"\u001b[39m\u001b[33mDynamic weight (3s timeout): \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mweight\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m g\u001b[39m\u001b[33m\"\u001b[39m)\n\u001b[32m 3\u001b[39m \u001b[38;5;28;01massert\u001b[39;00m \u001b[38;5;28misinstance\u001b[39m(weight, \u001b[38;5;28mfloat\u001b[39m)\n", + "\u001b[36mFile \u001b[39m\u001b[32m~/Desktop/GitHub/pylabrobot/pylabrobot/scales/mettler_toledo/backend.py:688\u001b[39m, in \u001b[36mMettlerToledoWXS205SDUBackend.read_dynamic_weight\u001b[39m\u001b[34m(self, timeout)\u001b[39m\n\u001b[32m 679\u001b[39m \u001b[38;5;250m\u001b[39m\u001b[33;03m\"\"\"Read a stable weight value from the machine within a given timeout, or\u001b[39;00m\n\u001b[32m 680\u001b[39m \u001b[33;03mreturn the current weight value if not possible. (MEASUREMENT command)\u001b[39;00m\n\u001b[32m 681\u001b[39m \n\u001b[32m 682\u001b[39m \u001b[33;03mArgs:\u001b[39;00m\n\u001b[32m 683\u001b[39m \u001b[33;03m timeout: The timeout in seconds.\u001b[39;00m\n\u001b[32m 684\u001b[39m \u001b[33;03m\"\"\"\u001b[39;00m\n\u001b[32m 686\u001b[39m timeout = \u001b[38;5;28mint\u001b[39m(timeout * \u001b[32m1000\u001b[39m) \u001b[38;5;66;03m# convert to milliseconds\u001b[39;00m\n\u001b[32m--> \u001b[39m\u001b[32m688\u001b[39m responses = \u001b[38;5;28;01mawait\u001b[39;00m \u001b[38;5;28mself\u001b[39m.send_command(\u001b[33mf\u001b[39m\u001b[33m\"\u001b[39m\u001b[33mSC \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mtimeout\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m\"\u001b[39m)\n\u001b[32m 689\u001b[39m \u001b[38;5;28mself\u001b[39m._validate_response(responses[\u001b[32m0\u001b[39m], \u001b[32m4\u001b[39m, \u001b[33m\"\u001b[39m\u001b[33mSC\u001b[39m\u001b[33m\"\u001b[39m)\n\u001b[32m 690\u001b[39m \u001b[38;5;28mself\u001b[39m._validate_unit(responses[\u001b[32m0\u001b[39m].data[\u001b[32m1\u001b[39m], \u001b[33m\"\u001b[39m\u001b[33mSC\u001b[39m\u001b[33m\"\u001b[39m)\n", + "\u001b[36mFile \u001b[39m\u001b[32m~/Desktop/GitHub/pylabrobot/pylabrobot/scales/mettler_toledo/backend.py:342\u001b[39m, in \u001b[36mMettlerToledoWXS205SDUBackend.send_command\u001b[39m\u001b[34m(self, command, timeout)\u001b[39m\n\u001b[32m 340\u001b[39m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[32m 341\u001b[39m response = MettlerToledoResponse(command=\u001b[33m\"\u001b[39m\u001b[33m\"\u001b[39m, status=\u001b[33m\"\u001b[39m\u001b[33m\"\u001b[39m, data=[])\n\u001b[32m--> \u001b[39m\u001b[32m342\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[43m.\u001b[49m\u001b[43m_parse_basic_errors\u001b[49m\u001b[43m(\u001b[49m\u001b[43mresponse\u001b[49m\u001b[43m)\u001b[49m\n\u001b[32m 343\u001b[39m responses.append(response)\n\u001b[32m 345\u001b[39m \u001b[38;5;66;03m# Status B means more responses follow; anything else (A, etc.) is final\u001b[39;00m\n", + "\u001b[36mFile \u001b[39m\u001b[32m~/Desktop/GitHub/pylabrobot/pylabrobot/scales/mettler_toledo/backend.py:263\u001b[39m, in \u001b[36mMettlerToledoWXS205SDUBackend._parse_basic_errors\u001b[39m\u001b[34m(self, response)\u001b[39m\n\u001b[32m 261\u001b[39m \u001b[38;5;66;03m# General error messages: ES, ET, EL (status is \"\" for these)\u001b[39;00m\n\u001b[32m 262\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m response.command == \u001b[33m\"\u001b[39m\u001b[33mES\u001b[39m\u001b[33m\"\u001b[39m:\n\u001b[32m--> \u001b[39m\u001b[32m263\u001b[39m \u001b[38;5;28;01mraise\u001b[39;00m MettlerToledoError.syntax_error()\n\u001b[32m 264\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m response.command == \u001b[33m\"\u001b[39m\u001b[33mET\u001b[39m\u001b[33m\"\u001b[39m:\n\u001b[32m 265\u001b[39m \u001b[38;5;28;01mraise\u001b[39;00m MettlerToledoError.transmission_error()\n", + "\u001b[31mMettlerToledoError\u001b[39m: Syntax error: The weigh module/balance has not recognized the received command or the command is not allowed" + ] + } + ], "source": [ "weight = await backend.read_dynamic_weight(timeout=3.0)\n", "print(f\"Dynamic weight (3s timeout): {weight} g\")\n", @@ -856,9 +1350,34 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 19, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2026-03-30 13:12:28,895 - pylabrobot - IO - [MT Scale] Sent command: C\n", + "2026-03-30 13:12:28,899 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'C\\r\\n'\n", + "2026-03-30 13:12:28,929 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'ES\\r\\n'\n", + "2026-03-30 13:12:28,930 - pylabrobot - IO - [MT Scale] Received response: b'ES\\r\\n'\n" + ] + }, + { + "ename": "MettlerToledoError", + "evalue": "Syntax error: The weigh module/balance has not recognized the received command or the command is not allowed", + "output_type": "error", + "traceback": [ + "\u001b[31m---------------------------------------------------------------------------\u001b[39m", + "\u001b[31mMettlerToledoError\u001b[39m Traceback (most recent call last)", + "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[19]\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 backend.cancel_all()\n\u001b[32m 2\u001b[39m \u001b[38;5;28mprint\u001b[39m(\u001b[33m\"\u001b[39m\u001b[33mPASS: cancel_all completed without error\u001b[39m\u001b[33m\"\u001b[39m)\n", + "\u001b[36mFile \u001b[39m\u001b[32m~/Desktop/GitHub/pylabrobot/pylabrobot/scales/mettler_toledo/backend.py:380\u001b[39m, in \u001b[36mMettlerToledoWXS205SDUBackend.cancel_all\u001b[39m\u001b[34m(self)\u001b[39m\n\u001b[32m 370\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[34mcancel_all\u001b[39m(\u001b[38;5;28mself\u001b[39m) -> \u001b[38;5;28;01mNone\u001b[39;00m:\n\u001b[32m 371\u001b[39m \u001b[38;5;250m \u001b[39m\u001b[33;03m\"\"\"C - Cancel all active and pending interface commands.\u001b[39;00m\n\u001b[32m 372\u001b[39m \n\u001b[32m 373\u001b[39m \u001b[33;03m Unlike cancel() (@), this does not reset the device - it only cancels\u001b[39;00m\n\u001b[32m (...)\u001b[39m\u001b[32m 378\u001b[39m \u001b[33;03m C A (complete). Both responses are consumed to keep the serial buffer clean.\u001b[39;00m\n\u001b[32m 379\u001b[39m \u001b[33;03m \"\"\"\u001b[39;00m\n\u001b[32m--> \u001b[39m\u001b[32m380\u001b[39m responses = \u001b[38;5;28;01mawait\u001b[39;00m \u001b[38;5;28mself\u001b[39m.send_command(\u001b[33m\"\u001b[39m\u001b[33mC\u001b[39m\u001b[33m\"\u001b[39m)\n\u001b[32m 381\u001b[39m \u001b[38;5;66;03m# send_command reads both C B (started) and C A (complete) automatically\u001b[39;00m\n\u001b[32m 382\u001b[39m \u001b[38;5;28mself\u001b[39m._validate_response(responses[\u001b[32m0\u001b[39m], \u001b[32m2\u001b[39m, \u001b[33m\"\u001b[39m\u001b[33mC\u001b[39m\u001b[33m\"\u001b[39m)\n", + "\u001b[36mFile \u001b[39m\u001b[32m~/Desktop/GitHub/pylabrobot/pylabrobot/scales/mettler_toledo/backend.py:342\u001b[39m, in \u001b[36mMettlerToledoWXS205SDUBackend.send_command\u001b[39m\u001b[34m(self, command, timeout)\u001b[39m\n\u001b[32m 340\u001b[39m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[32m 341\u001b[39m response = MettlerToledoResponse(command=\u001b[33m\"\u001b[39m\u001b[33m\"\u001b[39m, status=\u001b[33m\"\u001b[39m\u001b[33m\"\u001b[39m, data=[])\n\u001b[32m--> \u001b[39m\u001b[32m342\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[43m.\u001b[49m\u001b[43m_parse_basic_errors\u001b[49m\u001b[43m(\u001b[49m\u001b[43mresponse\u001b[49m\u001b[43m)\u001b[49m\n\u001b[32m 343\u001b[39m responses.append(response)\n\u001b[32m 345\u001b[39m \u001b[38;5;66;03m# Status B means more responses follow; anything else (A, etc.) is final\u001b[39;00m\n", + "\u001b[36mFile \u001b[39m\u001b[32m~/Desktop/GitHub/pylabrobot/pylabrobot/scales/mettler_toledo/backend.py:263\u001b[39m, in \u001b[36mMettlerToledoWXS205SDUBackend._parse_basic_errors\u001b[39m\u001b[34m(self, response)\u001b[39m\n\u001b[32m 261\u001b[39m \u001b[38;5;66;03m# General error messages: ES, ET, EL (status is \"\" for these)\u001b[39;00m\n\u001b[32m 262\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m response.command == \u001b[33m\"\u001b[39m\u001b[33mES\u001b[39m\u001b[33m\"\u001b[39m:\n\u001b[32m--> \u001b[39m\u001b[32m263\u001b[39m \u001b[38;5;28;01mraise\u001b[39;00m MettlerToledoError.syntax_error()\n\u001b[32m 264\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m response.command == \u001b[33m\"\u001b[39m\u001b[33mET\u001b[39m\u001b[33m\"\u001b[39m:\n\u001b[32m 265\u001b[39m \u001b[38;5;28;01mraise\u001b[39;00m MettlerToledoError.transmission_error()\n", + "\u001b[31mMettlerToledoError\u001b[39m: Syntax error: The weigh module/balance has not recognized the received command or the command is not allowed" + ] + } + ], "source": [ "await backend.cancel_all()\n", "print(\"PASS: cancel_all completed without error\")" @@ -873,9 +1392,34 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 20, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2026-03-30 13:12:29,871 - pylabrobot - IO - [MT Scale] Sent command: D \"PLR TEST\"\n", + "2026-03-30 13:12:29,879 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'D \"PLR TEST\"\\r\\n'\n", + "2026-03-30 13:12:29,906 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'ES\\r\\n'\n", + "2026-03-30 13:12:29,907 - pylabrobot - IO - [MT Scale] Received response: b'ES\\r\\n'\n" + ] + }, + { + "ename": "MettlerToledoError", + "evalue": "Syntax error: The weigh module/balance has not recognized the received command or the command is not allowed", + "output_type": "error", + "traceback": [ + "\u001b[31m---------------------------------------------------------------------------\u001b[39m", + "\u001b[31mMettlerToledoError\u001b[39m Traceback (most recent call last)", + "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[20]\u001b[39m\u001b[32m, line 3\u001b[39m\n\u001b[32m 1\u001b[39m \u001b[38;5;28;01mimport\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[34;01masyncio\u001b[39;00m\n\u001b[32m----> \u001b[39m\u001b[32m3\u001b[39m \u001b[38;5;28;01mawait\u001b[39;00m backend.set_display_text(\u001b[33m\"\u001b[39m\u001b[33mPLR TEST\u001b[39m\u001b[33m\"\u001b[39m)\n\u001b[32m 4\u001b[39m \u001b[38;5;28;01mawait\u001b[39;00m asyncio.sleep(\u001b[32m2\u001b[39m)\n\u001b[32m 5\u001b[39m \u001b[38;5;28;01mawait\u001b[39;00m backend.set_weight_display()\n", + "\u001b[36mFile \u001b[39m\u001b[32m~/Desktop/GitHub/pylabrobot/pylabrobot/scales/mettler_toledo/backend.py:733\u001b[39m, in \u001b[36mMettlerToledoWXS205SDUBackend.set_display_text\u001b[39m\u001b[34m(self, text)\u001b[39m\n\u001b[32m 730\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[34mset_display_text\u001b[39m(\u001b[38;5;28mself\u001b[39m, text: \u001b[38;5;28mstr\u001b[39m) -> List[MettlerToledoResponse]:\n\u001b[32m 731\u001b[39m \u001b[38;5;250m \u001b[39m\u001b[33;03m\"\"\"Set the display text of the scale. Return to the normal weight display with\u001b[39;00m\n\u001b[32m 732\u001b[39m \u001b[33;03m self.set_weight_display().\"\"\"\u001b[39;00m\n\u001b[32m--> \u001b[39m\u001b[32m733\u001b[39m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;01mawait\u001b[39;00m \u001b[38;5;28mself\u001b[39m.send_command(\u001b[33mf\u001b[39m\u001b[33m'\u001b[39m\u001b[33mD \u001b[39m\u001b[33m\"\u001b[39m\u001b[38;5;132;01m{\u001b[39;00mtext\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m\"\u001b[39m\u001b[33m'\u001b[39m)\n", + "\u001b[36mFile \u001b[39m\u001b[32m~/Desktop/GitHub/pylabrobot/pylabrobot/scales/mettler_toledo/backend.py:342\u001b[39m, in \u001b[36mMettlerToledoWXS205SDUBackend.send_command\u001b[39m\u001b[34m(self, command, timeout)\u001b[39m\n\u001b[32m 340\u001b[39m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[32m 341\u001b[39m response = MettlerToledoResponse(command=\u001b[33m\"\u001b[39m\u001b[33m\"\u001b[39m, status=\u001b[33m\"\u001b[39m\u001b[33m\"\u001b[39m, data=[])\n\u001b[32m--> \u001b[39m\u001b[32m342\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[43m.\u001b[49m\u001b[43m_parse_basic_errors\u001b[49m\u001b[43m(\u001b[49m\u001b[43mresponse\u001b[49m\u001b[43m)\u001b[49m\n\u001b[32m 343\u001b[39m responses.append(response)\n\u001b[32m 345\u001b[39m \u001b[38;5;66;03m# Status B means more responses follow; anything else (A, etc.) is final\u001b[39;00m\n", + "\u001b[36mFile \u001b[39m\u001b[32m~/Desktop/GitHub/pylabrobot/pylabrobot/scales/mettler_toledo/backend.py:263\u001b[39m, in \u001b[36mMettlerToledoWXS205SDUBackend._parse_basic_errors\u001b[39m\u001b[34m(self, response)\u001b[39m\n\u001b[32m 261\u001b[39m \u001b[38;5;66;03m# General error messages: ES, ET, EL (status is \"\" for these)\u001b[39;00m\n\u001b[32m 262\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m response.command == \u001b[33m\"\u001b[39m\u001b[33mES\u001b[39m\u001b[33m\"\u001b[39m:\n\u001b[32m--> \u001b[39m\u001b[32m263\u001b[39m \u001b[38;5;28;01mraise\u001b[39;00m MettlerToledoError.syntax_error()\n\u001b[32m 264\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m response.command == \u001b[33m\"\u001b[39m\u001b[33mET\u001b[39m\u001b[33m\"\u001b[39m:\n\u001b[32m 265\u001b[39m \u001b[38;5;28;01mraise\u001b[39;00m MettlerToledoError.transmission_error()\n", + "\u001b[31mMettlerToledoError\u001b[39m: Syntax error: The weigh module/balance has not recognized the received command or the command is not allowed" + ] + } + ], "source": [ "import asyncio\n", "\n", @@ -896,9 +1440,32 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 21, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2026-03-30 13:12:32,605 - pylabrobot - IO - [MT Scale] Sent command: ZC 5000\n", + "2026-03-30 13:12:32,608 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'ZC 5000\\r\\n'\n", + "2026-03-30 13:12:32,639 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'ES\\r\\n'\n", + "2026-03-30 13:12:32,641 - pylabrobot - IO - [MT Scale] Received response: b'ES\\r\\n'\n", + "2026-03-30 13:12:32,645 - pylabrobot - IO - [MT Scale] Sent command: TC 5000\n", + "2026-03-30 13:12:32,646 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'TC 5000\\r\\n'\n", + "2026-03-30 13:12:32,671 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'ES\\r\\n'\n", + "2026-03-30 13:12:32,673 - pylabrobot - IO - [MT Scale] Received response: b'ES\\r\\n'\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "ZC: not supported (ES) - expected for WXS205SDU\n", + "TC: not supported (ES) - expected for WXS205SDU\n" + ] + } + ], "source": [ "from pylabrobot.scales.mettler_toledo.errors import MettlerToledoError\n", "\n", @@ -930,9 +1497,27 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 22, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2026-03-30 13:12:34,916 - pylabrobot - IO - [MT Scale] Sent command: M21 0 0\n", + "2026-03-30 13:12:34,918 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'M21 0 0\\r\\n'\n", + "2026-03-30 13:12:34,957 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M21 A\\r\\n'\n", + "2026-03-30 13:12:34,958 - pylabrobot - IO - [MT Scale] Received response: b'M21 A\\r\\n'\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "PASS: host unit set to grams\n" + ] + } + ], "source": [ "if \"M21\" in backend._supported_commands:\n", " await backend.set_host_unit_grams()\n", @@ -950,9 +1535,17 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 23, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "SKIP: I50 not supported on this device\n" + ] + } + ], "source": [ "if \"I50\" in backend._supported_commands:\n", " remaining = await backend.request_remaining_weighing_range()\n", @@ -973,9 +1566,30 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 24, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2026-03-30 13:12:38,030 - pylabrobot - IO - [MT Scale] Sent command: M28\n", + "2026-03-30 13:12:38,034 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'M28\\r\\n'\n", + "2026-03-30 13:12:38,072 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M28 B 1 20.1\\r\\n'\n", + "2026-03-30 13:12:38,073 - pylabrobot - IO - [MT Scale] Received response: b'M28 B 1 20.1\\r\\n'\n", + "2026-03-30 13:12:38,089 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M28 A 2 19.6\\r\\n'\n", + "2026-03-30 13:12:38,094 - pylabrobot - IO - [MT Scale] Received response: b'M28 A 2 19.6\\r\\n'\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Scale temperature: 20.1 C\n", + "PASS: measure_temperature works - I0 correctly predicted M28 support\n" + ] + } + ], "source": [ "if \"M28\" in backend._supported_commands:\n", " temp = await backend.measure_temperature()\n", @@ -988,15 +1602,426 @@ }, { "cell_type": "markdown", - "source": "### Batch 2 - Configuration queries (read-only)\n\nThese commands read device configuration without modifying anything.", - "metadata": {} + "metadata": {}, + "source": [ + "### Batch 2 - Configuration queries (read-only)\n", + "\n", + "These commands read device configuration without modifying anything." + ] }, { "cell_type": "code", - "source": "# M01 - Weighing mode (read-only query)\nif \"M01\" in backend._supported_commands:\n mode = await backend.request_weighing_mode()\n mode_names = {0: \"Normal/Universal\", 1: \"Dosing\", 2: \"Sensor\", 3: \"Check weighing\", 6: \"Raw/No filter\"}\n print(f\"Weighing mode: {mode} ({mode_names.get(mode, 'unknown')})\")\nelse:\n print(\"SKIP: M01 not supported\")\n\n# M02 - Environment condition (read-only query)\nif \"M02\" in backend._supported_commands:\n env = await backend.request_environment_condition()\n env_names = {0: \"Very stable\", 1: \"Stable\", 2: \"Standard\", 3: \"Unstable\", 4: \"Very unstable\", 5: \"Automatic\"}\n print(f\"Environment condition: {env} ({env_names.get(env, 'unknown')})\")\nelse:\n print(\"SKIP: M02 not supported\")\n\n# M03 - Auto zero (read-only query)\nif \"M03\" in backend._supported_commands:\n auto_zero = await backend.request_auto_zero()\n print(f\"Auto zero: {auto_zero} ({'on' if auto_zero else 'off'})\")\nelse:\n print(\"SKIP: M03 not supported\")\n\n# M27 - Adjustment history (read-only query)\nif \"M27\" in backend._supported_commands:\n history = await backend.request_adjustment_history()\n print(f\"\\nAdjustment history ({len(history)} entries):\")\n for resp in history:\n print(f\" {resp.command} {resp.status} {' '.join(resp.data)}\")\nelse:\n print(\"SKIP: M27 not supported\")\n\n# UPD - Update rate (read-only query)\nif \"UPD\" in backend._supported_commands:\n rate = await backend.request_update_rate()\n print(f\"\\nUpdate rate: {rate} values/s\")\nelse:\n print(\"SKIP: UPD not supported\")\n\n# SIS - Net weight with status (read-only query)\nif \"SIS\" in backend._supported_commands:\n sis_resp = await backend.request_net_weight_with_status()\n print(f\"\\nNet weight with status: {sis_resp.command} {sis_resp.status} {' '.join(sis_resp.data)}\")\nelse:\n print(\"SKIP: SIS not supported\")\n\n# LST - Current user settings (read-only, lists all configurable settings)\nif \"LST\" in backend._supported_commands:\n try:\n lst_responses = await backend.send_command(\"LST\")\n print(f\"\\nCurrent user settings ({len(lst_responses)} lines):\")\n for resp in lst_responses[:10]:\n print(f\" {resp.command} {resp.status} {' '.join(resp.data)}\")\n if len(lst_responses) > 10:\n print(f\" ... ({len(lst_responses)} lines total)\")\n except Exception as e:\n print(f\"LST: {e}\")\nelse:\n print(\"SKIP: LST not supported\")\n\n# RDB - Readability (read-only)\nif \"RDB\" in backend._supported_commands:\n try:\n rdb_responses = await backend.send_command(\"RDB\")\n print(f\"\\nReadability: {rdb_responses[0].command} {rdb_responses[0].status} {' '.join(rdb_responses[0].data)}\")\n except Exception as e:\n print(f\"RDB: {e}\")\nelse:\n print(\"SKIP: RDB not supported\")\n\n# USTB - User defined stability criteria (read-only query)\nif \"USTB\" in backend._supported_commands:\n try:\n ustb_responses = await backend.send_command(\"USTB\")\n print(f\"Stability criteria: {ustb_responses[0].command} {ustb_responses[0].status} {' '.join(ustb_responses[0].data)}\")\n except Exception as e:\n print(f\"USTB: {e}\")\nelse:\n print(\"SKIP: USTB not supported\")\n\n# FCUT - Filter cut-off frequency (read-only query)\nif \"FCUT\" in backend._supported_commands:\n try:\n fcut_responses = await backend.send_command(\"FCUT\")\n print(f\"Filter cut-off: {fcut_responses[0].command} {fcut_responses[0].status} {' '.join(fcut_responses[0].data)}\")\n except Exception as e:\n print(f\"FCUT: {e}\")\nelse:\n print(\"SKIP: FCUT not supported\")\n\nprint(\"\\nPASS: Batch 2+3 read-only configuration queries completed\")", + "execution_count": 25, "metadata": {}, - "execution_count": null, - "outputs": [] + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2026-03-30 13:12:42,172 - pylabrobot - IO - [MT Scale] Sent command: M01\n", + "2026-03-30 13:12:42,174 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'M01\\r\\n'\n", + "2026-03-30 13:12:42,198 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M01 A 0\\r\\n'\n", + "2026-03-30 13:12:42,199 - pylabrobot - IO - [MT Scale] Received response: b'M01 A 0\\r\\n'\n", + "2026-03-30 13:12:42,201 - pylabrobot - IO - [MT Scale] Sent command: M02\n", + "2026-03-30 13:12:42,202 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'M02\\r\\n'\n", + "2026-03-30 13:12:42,230 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M02 A 2\\r\\n'\n", + "2026-03-30 13:12:42,230 - pylabrobot - IO - [MT Scale] Received response: b'M02 A 2\\r\\n'\n", + "2026-03-30 13:12:42,231 - pylabrobot - IO - [MT Scale] Sent command: M03\n", + "2026-03-30 13:12:42,232 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'M03\\r\\n'\n", + "2026-03-30 13:12:42,262 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M03 A 0\\r\\n'\n", + "2026-03-30 13:12:42,263 - pylabrobot - IO - [MT Scale] Received response: b'M03 A 0\\r\\n'\n", + "2026-03-30 13:12:42,265 - pylabrobot - IO - [MT Scale] Sent command: M27\n", + "2026-03-30 13:12:42,267 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'M27\\r\\n'\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Weighing mode: 0 (Normal/Universal)\n", + "Environment condition: 2 (Standard)\n", + "Auto zero: 0 (off)\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2026-03-30 13:12:43,061 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 1 13 05 2020 17 17 0 \"\"\\r\\n'\n", + "2026-03-30 13:12:43,062 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 1 13 05 2020 17 17 0 \"\"\\r\\n'\n", + "2026-03-30 13:12:43,094 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 2 02 12 2019 20 02 0 \"\"\\r\\n'\n", + "2026-03-30 13:12:43,096 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 2 02 12 2019 20 02 0 \"\"\\r\\n'\n", + "2026-03-30 13:12:43,128 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 3 11 10 2019 17 05 0 \"\"\\r\\n'\n", + "2026-03-30 13:12:43,130 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 3 11 10 2019 17 05 0 \"\"\\r\\n'\n", + "2026-03-30 13:12:43,158 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 4 11 10 2019 17 01 0 \"\"\\r\\n'\n", + "2026-03-30 13:12:43,159 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 4 11 10 2019 17 01 0 \"\"\\r\\n'\n", + "2026-03-30 13:12:43,190 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 5 14 03 2019 20 22 0 \"\"\\r\\n'\n", + "2026-03-30 13:12:43,193 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 5 14 03 2019 20 22 0 \"\"\\r\\n'\n", + "2026-03-30 13:12:43,222 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 6 14 03 2019 20 18 0 \"\"\\r\\n'\n", + "2026-03-30 13:12:43,223 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 6 14 03 2019 20 18 0 \"\"\\r\\n'\n", + "2026-03-30 13:12:43,253 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 7 17 10 2018 17 38 0 \"\"\\r\\n'\n", + "2026-03-30 13:12:43,255 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 7 17 10 2018 17 38 0 \"\"\\r\\n'\n", + "2026-03-30 13:12:43,286 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 8 17 10 2018 17 37 0 \"\"\\r\\n'\n", + "2026-03-30 13:12:43,288 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 8 17 10 2018 17 37 0 \"\"\\r\\n'\n", + "2026-03-30 13:12:43,318 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 9 17 10 2018 17 35 0 \"\"\\r\\n'\n", + "2026-03-30 13:12:43,319 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 9 17 10 2018 17 35 0 \"\"\\r\\n'\n", + "2026-03-30 13:12:43,349 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 10 20 09 2018 21 23 0 \"\"\\r\\n'\n", + "2026-03-30 13:12:43,350 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 10 20 09 2018 21 23 0 \"\"\\r\\n'\n", + "2026-03-30 13:12:43,381 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 11 15 03 2018 23 51 0 \"\"\\r\\n'\n", + "2026-03-30 13:12:43,382 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 11 15 03 2018 23 51 0 \"\"\\r\\n'\n", + "2026-03-30 13:12:43,429 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 12 16 12 2017 00 20 0 \"\"\\r\\n'\n", + "2026-03-30 13:12:43,431 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 12 16 12 2017 00 20 0 \"\"\\r\\n'\n", + "2026-03-30 13:12:43,461 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 13 16 12 2017 00 18 0 \"\"\\r\\n'\n", + "2026-03-30 13:12:43,462 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 13 16 12 2017 00 18 0 \"\"\\r\\n'\n", + "2026-03-30 13:12:43,493 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 14 18 10 2017 12 06 0 \"\"\\r\\n'\n", + "2026-03-30 13:12:43,494 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 14 18 10 2017 12 06 0 \"\"\\r\\n'\n", + "2026-03-30 13:12:43,526 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 15 18 10 2017 11 58 0 \"\"\\r\\n'\n", + "2026-03-30 13:12:43,526 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 15 18 10 2017 11 58 0 \"\"\\r\\n'\n", + "2026-03-30 13:12:43,557 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 16 05 09 2017 22 40 0 \"\"\\r\\n'\n", + "2026-03-30 13:12:43,558 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 16 05 09 2017 22 40 0 \"\"\\r\\n'\n", + "2026-03-30 13:12:43,589 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 17 21 06 2017 18 39 0 \"\"\\r\\n'\n", + "2026-03-30 13:12:43,590 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 17 21 06 2017 18 39 0 \"\"\\r\\n'\n", + "2026-03-30 13:12:43,621 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 18 30 03 2017 19 24 0 \"\"\\r\\n'\n", + "2026-03-30 13:12:43,628 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 18 30 03 2017 19 24 0 \"\"\\r\\n'\n", + "2026-03-30 13:12:43,655 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 19 09 03 2017 23 21 0 \"\"\\r\\n'\n", + "2026-03-30 13:12:43,656 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 19 09 03 2017 23 21 0 \"\"\\r\\n'\n", + "2026-03-30 13:12:43,685 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 20 09 03 2017 23 19 0 \"\"\\r\\n'\n", + "2026-03-30 13:12:43,689 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 20 09 03 2017 23 19 0 \"\"\\r\\n'\n", + "2026-03-30 13:12:43,717 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 21 20 12 2016 21 55 0 \"\"\\r\\n'\n", + "2026-03-30 13:12:43,718 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 21 20 12 2016 21 55 0 \"\"\\r\\n'\n", + "2026-03-30 13:12:43,753 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 22 19 10 2016 17 36 0 \"\"\\r\\n'\n", + "2026-03-30 13:12:43,754 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 22 19 10 2016 17 36 0 \"\"\\r\\n'\n", + "2026-03-30 13:12:43,781 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 23 19 10 2016 17 33 0 \"\"\\r\\n'\n", + "2026-03-30 13:12:43,790 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 23 19 10 2016 17 33 0 \"\"\\r\\n'\n", + "2026-03-30 13:12:43,829 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 24 18 10 2016 21 00 0 \"\"\\r\\n'\n", + "2026-03-30 13:12:43,831 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 24 18 10 2016 21 00 0 \"\"\\r\\n'\n", + "2026-03-30 13:12:43,861 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 25 18 10 2016 18 47 0 \"\"\\r\\n'\n", + "2026-03-30 13:12:43,863 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 25 18 10 2016 18 47 0 \"\"\\r\\n'\n", + "2026-03-30 13:12:43,893 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 26 18 10 2016 15 33 0 \"\"\\r\\n'\n", + "2026-03-30 13:12:43,895 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 26 18 10 2016 15 33 0 \"\"\\r\\n'\n", + "2026-03-30 13:12:43,925 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 27 18 10 2016 14 32 0 \"\"\\r\\n'\n", + "2026-03-30 13:12:43,926 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 27 18 10 2016 14 32 0 \"\"\\r\\n'\n", + "2026-03-30 13:12:43,957 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 28 18 10 2016 14 28 0 \"\"\\r\\n'\n", + "2026-03-30 13:12:43,958 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 28 18 10 2016 14 28 0 \"\"\\r\\n'\n", + "2026-03-30 13:12:43,989 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 29 18 10 2016 13 41 0 \"\"\\r\\n'\n", + "2026-03-30 13:12:43,990 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 29 18 10 2016 13 41 0 \"\"\\r\\n'\n", + "2026-03-30 13:12:44,025 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 30 21 09 2016 15 15 0 \"\"\\r\\n'\n", + "2026-03-30 13:12:44,027 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 30 21 09 2016 15 15 0 \"\"\\r\\n'\n", + "2026-03-30 13:12:44,053 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 31 04 03 2016 22 28 0 \"\"\\r\\n'\n", + "2026-03-30 13:12:44,055 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 31 04 03 2016 22 28 0 \"\"\\r\\n'\n", + "2026-03-30 13:12:44,089 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 32 01 10 2015 19 06 0 \"\"\\r\\n'\n", + "2026-03-30 13:12:44,090 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 32 01 10 2015 19 06 0 \"\"\\r\\n'\n", + "2026-03-30 13:12:44,117 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 33 01 10 2015 18 56 0 \"\"\\r\\n'\n", + "2026-03-30 13:12:44,121 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 33 01 10 2015 18 56 0 \"\"\\r\\n'\n", + "2026-03-30 13:12:44,152 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 34 03 09 2015 22 11 0 \"\"\\r\\n'\n", + "2026-03-30 13:12:44,156 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 34 03 09 2015 22 11 0 \"\"\\r\\n'\n", + "2026-03-30 13:12:44,196 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 35 11 03 2015 13 20 0 \"\"\\r\\n'\n", + "2026-03-30 13:12:44,199 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 35 11 03 2015 13 20 0 \"\"\\r\\n'\n", + "2026-03-30 13:12:44,229 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 36 11 03 2015 13 18 0 \"\"\\r\\n'\n", + "2026-03-30 13:12:44,230 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 36 11 03 2015 13 18 0 \"\"\\r\\n'\n", + "2026-03-30 13:12:44,260 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 37 11 03 2015 13 15 0 \"\"\\r\\n'\n", + "2026-03-30 13:12:44,261 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 37 11 03 2015 13 15 0 \"\"\\r\\n'\n", + "2026-03-30 13:12:44,292 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 38 11 03 2015 13 13 0 \"\"\\r\\n'\n", + "2026-03-30 13:12:44,293 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 38 11 03 2015 13 13 0 \"\"\\r\\n'\n", + "2026-03-30 13:12:44,330 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 39 22 01 2015 03 17 0 \"\"\\r\\n'\n", + "2026-03-30 13:12:44,330 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 39 22 01 2015 03 17 0 \"\"\\r\\n'\n", + "2026-03-30 13:12:44,358 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 40 22 01 2015 03 15 0 \"\"\\r\\n'\n", + "2026-03-30 13:12:44,360 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 40 22 01 2015 03 15 0 \"\"\\r\\n'\n", + "2026-03-30 13:12:44,389 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 41 06 11 2014 17 08 0 \"\"\\r\\n'\n", + "2026-03-30 13:12:44,391 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 41 06 11 2014 17 08 0 \"\"\\r\\n'\n", + "2026-03-30 13:12:44,421 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 42 06 11 2014 16 22 0 \"\"\\r\\n'\n", + "2026-03-30 13:12:44,422 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 42 06 11 2014 16 22 0 \"\"\\r\\n'\n", + "2026-03-30 13:12:44,453 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 43 06 11 2014 16 20 0 \"\"\\r\\n'\n", + "2026-03-30 13:12:44,454 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 43 06 11 2014 16 20 0 \"\"\\r\\n'\n", + "2026-03-30 13:12:44,485 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 44 06 11 2014 15 57 0 \"\"\\r\\n'\n", + "2026-03-30 13:12:44,486 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 44 06 11 2014 15 57 0 \"\"\\r\\n'\n", + "2026-03-30 13:12:44,517 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 45 18 09 2014 20 23 0 \"\"\\r\\n'\n", + "2026-03-30 13:12:44,523 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 45 18 09 2014 20 23 0 \"\"\\r\\n'\n", + "2026-03-30 13:12:44,565 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 46 18 09 2014 19 54 0 \"\"\\r\\n'\n", + "2026-03-30 13:12:44,566 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 46 18 09 2014 19 54 0 \"\"\\r\\n'\n", + "2026-03-30 13:12:44,596 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 47 18 09 2014 19 44 0 \"\"\\r\\n'\n", + "2026-03-30 13:12:44,598 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 47 18 09 2014 19 44 0 \"\"\\r\\n'\n", + "2026-03-30 13:12:44,629 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 48 18 09 2014 19 35 0 \"\"\\r\\n'\n", + "2026-03-30 13:12:44,631 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 48 18 09 2014 19 35 0 \"\"\\r\\n'\n", + "2026-03-30 13:12:44,660 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 49 15 09 2014 20 08 0 \"\"\\r\\n'\n", + "2026-03-30 13:12:44,662 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 49 15 09 2014 20 08 0 \"\"\\r\\n'\n", + "2026-03-30 13:12:44,693 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 A 50 15 09 2014 19 39 0 \"\"\\r\\n'\n", + "2026-03-30 13:12:44,695 - pylabrobot - IO - [MT Scale] Received response: b'M27 A 50 15 09 2014 19 39 0 \"\"\\r\\n'\n", + "2026-03-30 13:12:44,697 - pylabrobot - IO - [MT Scale] Sent command: UPD\n", + "2026-03-30 13:12:44,700 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'UPD\\r\\n'\n", + "2026-03-30 13:12:44,740 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'UPD A 10.173\\r\\n'\n", + "2026-03-30 13:12:44,742 - pylabrobot - IO - [MT Scale] Received response: b'UPD A 10.173\\r\\n'\n", + "2026-03-30 13:12:44,743 - pylabrobot - IO - [MT Scale] Sent command: SIS\n", + "2026-03-30 13:12:44,746 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SIS\\r\\n'\n", + "2026-03-30 13:12:44,804 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'SIS A 0 \"0.00000\" 0 5 1 0 0\\r\\n'\n", + "2026-03-30 13:12:44,805 - pylabrobot - IO - [MT Scale] Received response: b'SIS A 0 \"0.00000\" 0 5 1 0 0\\r\\n'\n", + "2026-03-30 13:12:44,807 - pylabrobot - IO - [MT Scale] Sent command: LST\n", + "2026-03-30 13:12:44,812 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'LST\\r\\n'\n", + "2026-03-30 13:12:44,852 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B C0 0 0 \"\"\\r\\n'\n", + "2026-03-30 13:12:44,853 - pylabrobot - IO - [MT Scale] Received response: b'LST B C0 0 0 \"\"\\r\\n'\n", + "2026-03-30 13:12:44,868 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B FCUT 0.000\\r\\n'\n", + "2026-03-30 13:12:44,869 - pylabrobot - IO - [MT Scale] Received response: b'LST B FCUT 0.000\\r\\n'\n", + "2026-03-30 13:12:44,884 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B I10 \"\"\\r\\n'\n", + "2026-03-30 13:12:44,885 - pylabrobot - IO - [MT Scale] Received response: b'LST B I10 \"\"\\r\\n'\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "Adjustment history (50 entries):\n", + " M27 B 1 13 05 2020 17 17 0 \n", + " M27 B 2 02 12 2019 20 02 0 \n", + " M27 B 3 11 10 2019 17 05 0 \n", + " M27 B 4 11 10 2019 17 01 0 \n", + " M27 B 5 14 03 2019 20 22 0 \n", + " M27 B 6 14 03 2019 20 18 0 \n", + " M27 B 7 17 10 2018 17 38 0 \n", + " M27 B 8 17 10 2018 17 37 0 \n", + " M27 B 9 17 10 2018 17 35 0 \n", + " M27 B 10 20 09 2018 21 23 0 \n", + " M27 B 11 15 03 2018 23 51 0 \n", + " M27 B 12 16 12 2017 00 20 0 \n", + " M27 B 13 16 12 2017 00 18 0 \n", + " M27 B 14 18 10 2017 12 06 0 \n", + " M27 B 15 18 10 2017 11 58 0 \n", + " M27 B 16 05 09 2017 22 40 0 \n", + " M27 B 17 21 06 2017 18 39 0 \n", + " M27 B 18 30 03 2017 19 24 0 \n", + " M27 B 19 09 03 2017 23 21 0 \n", + " M27 B 20 09 03 2017 23 19 0 \n", + " M27 B 21 20 12 2016 21 55 0 \n", + " M27 B 22 19 10 2016 17 36 0 \n", + " M27 B 23 19 10 2016 17 33 0 \n", + " M27 B 24 18 10 2016 21 00 0 \n", + " M27 B 25 18 10 2016 18 47 0 \n", + " M27 B 26 18 10 2016 15 33 0 \n", + " M27 B 27 18 10 2016 14 32 0 \n", + " M27 B 28 18 10 2016 14 28 0 \n", + " M27 B 29 18 10 2016 13 41 0 \n", + " M27 B 30 21 09 2016 15 15 0 \n", + " M27 B 31 04 03 2016 22 28 0 \n", + " M27 B 32 01 10 2015 19 06 0 \n", + " M27 B 33 01 10 2015 18 56 0 \n", + " M27 B 34 03 09 2015 22 11 0 \n", + " M27 B 35 11 03 2015 13 20 0 \n", + " M27 B 36 11 03 2015 13 18 0 \n", + " M27 B 37 11 03 2015 13 15 0 \n", + " M27 B 38 11 03 2015 13 13 0 \n", + " M27 B 39 22 01 2015 03 17 0 \n", + " M27 B 40 22 01 2015 03 15 0 \n", + " M27 B 41 06 11 2014 17 08 0 \n", + " M27 B 42 06 11 2014 16 22 0 \n", + " M27 B 43 06 11 2014 16 20 0 \n", + " M27 B 44 06 11 2014 15 57 0 \n", + " M27 B 45 18 09 2014 20 23 0 \n", + " M27 B 46 18 09 2014 19 54 0 \n", + " M27 B 47 18 09 2014 19 44 0 \n", + " M27 B 48 18 09 2014 19 35 0 \n", + " M27 B 49 15 09 2014 20 08 0 \n", + " M27 A 50 15 09 2014 19 39 0 \n", + "\n", + "Update rate: 10.173 values/s\n", + "\n", + "Net weight with status: SIS A 0 0.00000 0 5 1 0 0\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2026-03-30 13:12:44,900 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B M01 0\\r\\n'\n", + "2026-03-30 13:12:44,902 - pylabrobot - IO - [MT Scale] Received response: b'LST B M01 0\\r\\n'\n", + "2026-03-30 13:12:44,918 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B M02 2\\r\\n'\n", + "2026-03-30 13:12:44,921 - pylabrobot - IO - [MT Scale] Received response: b'LST B M02 2\\r\\n'\n", + "2026-03-30 13:12:44,932 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B M03 0\\r\\n'\n", + "2026-03-30 13:12:44,933 - pylabrobot - IO - [MT Scale] Received response: b'LST B M03 0\\r\\n'\n", + "2026-03-30 13:12:44,948 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B M17 00 00 00 0\\r\\n'\n", + "2026-03-30 13:12:44,949 - pylabrobot - IO - [MT Scale] Received response: b'LST B M17 00 00 00 0\\r\\n'\n", + "2026-03-30 13:12:44,964 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B M18 1\\r\\n'\n", + "2026-03-30 13:12:44,965 - pylabrobot - IO - [MT Scale] Received response: b'LST B M18 1\\r\\n'\n", + "2026-03-30 13:12:44,996 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B M19 10.00000 g\\r\\n'\n", + "2026-03-30 13:12:44,999 - pylabrobot - IO - [MT Scale] Received response: b'LST B M19 10.00000 g\\r\\n'\n", + "2026-03-30 13:12:45,012 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B M20 200.00000 g\\r\\n'\n", + "2026-03-30 13:12:45,012 - pylabrobot - IO - [MT Scale] Received response: b'LST B M20 200.00000 g\\r\\n'\n", + "2026-03-30 13:12:45,028 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B M21 0 0\\r\\n'\n", + "2026-03-30 13:12:45,030 - pylabrobot - IO - [MT Scale] Received response: b'LST B M21 0 0\\r\\n'\n", + "2026-03-30 13:12:45,043 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B M29 1\\r\\n'\n", + "2026-03-30 13:12:45,044 - pylabrobot - IO - [MT Scale] Received response: b'LST B M29 1\\r\\n'\n", + "2026-03-30 13:12:45,065 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B M31 0\\r\\n'\n", + "2026-03-30 13:12:45,066 - pylabrobot - IO - [MT Scale] Received response: b'LST B M31 0\\r\\n'\n", + "2026-03-30 13:12:45,077 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B M32 1 00 00 0\\r\\n'\n", + "2026-03-30 13:12:45,082 - pylabrobot - IO - [MT Scale] Received response: b'LST B M32 1 00 00 0\\r\\n'\n", + "2026-03-30 13:12:45,092 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B M32 2 00 00 0\\r\\n'\n", + "2026-03-30 13:12:45,094 - pylabrobot - IO - [MT Scale] Received response: b'LST B M32 2 00 00 0\\r\\n'\n", + "2026-03-30 13:12:45,127 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B M32 3 00 00 0\\r\\n'\n", + "2026-03-30 13:12:45,132 - pylabrobot - IO - [MT Scale] Received response: b'LST B M32 3 00 00 0\\r\\n'\n", + "2026-03-30 13:12:45,140 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B M33 0\\r\\n'\n", + "2026-03-30 13:12:45,142 - pylabrobot - IO - [MT Scale] Received response: b'LST B M33 0\\r\\n'\n", + "2026-03-30 13:12:45,156 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B M35 0\\r\\n'\n", + "2026-03-30 13:12:45,157 - pylabrobot - IO - [MT Scale] Received response: b'LST B M35 0\\r\\n'\n", + "2026-03-30 13:12:45,160 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B RDB 5\\r\\n'\n", + "2026-03-30 13:12:45,160 - pylabrobot - IO - [MT Scale] Received response: b'LST B RDB 5\\r\\n'\n", + "2026-03-30 13:12:45,173 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B TST0 0 \"\"\\r\\n'\n", + "2026-03-30 13:12:45,174 - pylabrobot - IO - [MT Scale] Received response: b'LST B TST0 0 \"\"\\r\\n'\n", + "2026-03-30 13:12:45,204 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B UPD 10.173\\r\\n'\n", + "2026-03-30 13:12:45,206 - pylabrobot - IO - [MT Scale] Received response: b'LST B UPD 10.173\\r\\n'\n", + "2026-03-30 13:12:45,220 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B USTB 0 3.600 1.100\\r\\n'\n", + "2026-03-30 13:12:45,221 - pylabrobot - IO - [MT Scale] Received response: b'LST B USTB 0 3.600 1.100\\r\\n'\n", + "2026-03-30 13:12:45,252 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B USTB 1 0.000 0.000\\r\\n'\n", + "2026-03-30 13:12:45,253 - pylabrobot - IO - [MT Scale] Received response: b'LST B USTB 1 0.000 0.000\\r\\n'\n", + "2026-03-30 13:12:45,284 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST A USTB 2 0.000 0.000\\r\\n'\n", + "2026-03-30 13:12:45,287 - pylabrobot - IO - [MT Scale] Received response: b'LST A USTB 2 0.000 0.000\\r\\n'\n", + "2026-03-30 13:12:45,291 - pylabrobot - IO - [MT Scale] Sent command: RDB\n", + "2026-03-30 13:12:45,297 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'RDB\\r\\n'\n", + "2026-03-30 13:12:45,332 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'RDB A 5\\r\\n'\n", + "2026-03-30 13:12:45,339 - pylabrobot - IO - [MT Scale] Received response: b'RDB A 5\\r\\n'\n", + "2026-03-30 13:12:45,340 - pylabrobot - IO - [MT Scale] Sent command: USTB\n", + "2026-03-30 13:12:45,344 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'USTB\\r\\n'\n", + "2026-03-30 13:12:45,397 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'USTB B 0 3.600 1.100\\r\\n'\n", + "2026-03-30 13:12:45,399 - pylabrobot - IO - [MT Scale] Received response: b'USTB B 0 3.600 1.100\\r\\n'\n", + "2026-03-30 13:12:45,412 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'USTB B 1 0.000 0.000\\r\\n'\n", + "2026-03-30 13:12:45,413 - pylabrobot - IO - [MT Scale] Received response: b'USTB B 1 0.000 0.000\\r\\n'\n", + "2026-03-30 13:12:45,444 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'USTB A 2 0.000 0.000\\r\\n'\n", + "2026-03-30 13:12:45,446 - pylabrobot - IO - [MT Scale] Received response: b'USTB A 2 0.000 0.000\\r\\n'\n", + "2026-03-30 13:12:45,449 - pylabrobot - IO - [MT Scale] Sent command: FCUT\n", + "2026-03-30 13:12:45,452 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'FCUT\\r\\n'\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "Current user settings (24 lines):\n", + " LST B C0 0 0 \n", + " LST B FCUT 0.000\n", + " LST B I10 \n", + " LST B M01 0\n", + " LST B M02 2\n", + " LST B M03 0\n", + " LST B M17 00 00 00 0\n", + " LST B M18 1\n", + " LST B M19 10.00000 g\n", + " LST B M20 200.00000 g\n", + " ... (24 lines total)\n", + "\n", + "Readability: RDB A 5\n", + "Stability criteria: USTB B 0 3.600 1.100\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2026-03-30 13:12:45,493 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'FCUT A 0.000\\r\\n'\n", + "2026-03-30 13:12:45,494 - pylabrobot - IO - [MT Scale] Received response: b'FCUT A 0.000\\r\\n'\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Filter cut-off: FCUT A 0.000\n", + "\n", + "PASS: Batch 2+3 read-only configuration queries completed\n" + ] + } + ], + "source": [ + "# M01 - Weighing mode (read-only query)\n", + "if \"M01\" in backend._supported_commands:\n", + " mode = await backend.request_weighing_mode()\n", + " mode_names = {0: \"Normal/Universal\", 1: \"Dosing\", 2: \"Sensor\", 3: \"Check weighing\", 6: \"Raw/No filter\"}\n", + " print(f\"Weighing mode: {mode} ({mode_names.get(mode, 'unknown')})\")\n", + "else:\n", + " print(\"SKIP: M01 not supported\")\n", + "\n", + "# M02 - Environment condition (read-only query)\n", + "if \"M02\" in backend._supported_commands:\n", + " env = await backend.request_environment_condition()\n", + " env_names = {0: \"Very stable\", 1: \"Stable\", 2: \"Standard\", 3: \"Unstable\", 4: \"Very unstable\", 5: \"Automatic\"}\n", + " print(f\"Environment condition: {env} ({env_names.get(env, 'unknown')})\")\n", + "else:\n", + " print(\"SKIP: M02 not supported\")\n", + "\n", + "# M03 - Auto zero (read-only query)\n", + "if \"M03\" in backend._supported_commands:\n", + " auto_zero = await backend.request_auto_zero()\n", + " print(f\"Auto zero: {auto_zero} ({'on' if auto_zero else 'off'})\")\n", + "else:\n", + " print(\"SKIP: M03 not supported\")\n", + "\n", + "# M27 - Adjustment history (read-only query)\n", + "if \"M27\" in backend._supported_commands:\n", + " history = await backend.request_adjustment_history()\n", + " print(f\"\\nAdjustment history ({len(history)} entries):\")\n", + " for resp in history:\n", + " print(f\" {resp.command} {resp.status} {' '.join(resp.data)}\")\n", + "else:\n", + " print(\"SKIP: M27 not supported\")\n", + "\n", + "# UPD - Update rate (read-only query)\n", + "if \"UPD\" in backend._supported_commands:\n", + " rate = await backend.request_update_rate()\n", + " print(f\"\\nUpdate rate: {rate} values/s\")\n", + "else:\n", + " print(\"SKIP: UPD not supported\")\n", + "\n", + "# SIS - Net weight with status (read-only query)\n", + "if \"SIS\" in backend._supported_commands:\n", + " sis_resp = await backend.request_net_weight_with_status()\n", + " print(f\"\\nNet weight with status: {sis_resp.command} {sis_resp.status} {' '.join(sis_resp.data)}\")\n", + "else:\n", + " print(\"SKIP: SIS not supported\")\n", + "\n", + "# LST - Current user settings (read-only, lists all configurable settings)\n", + "if \"LST\" in backend._supported_commands:\n", + " try:\n", + " lst_responses = await backend.send_command(\"LST\")\n", + " print(f\"\\nCurrent user settings ({len(lst_responses)} lines):\")\n", + " for resp in lst_responses[:10]:\n", + " print(f\" {resp.command} {resp.status} {' '.join(resp.data)}\")\n", + " if len(lst_responses) > 10:\n", + " print(f\" ... ({len(lst_responses)} lines total)\")\n", + " except Exception as e:\n", + " print(f\"LST: {e}\")\n", + "else:\n", + " print(\"SKIP: LST not supported\")\n", + "\n", + "# RDB - Readability (read-only)\n", + "if \"RDB\" in backend._supported_commands:\n", + " try:\n", + " rdb_responses = await backend.send_command(\"RDB\")\n", + " print(f\"\\nReadability: {rdb_responses[0].command} {rdb_responses[0].status} {' '.join(rdb_responses[0].data)}\")\n", + " except Exception as e:\n", + " print(f\"RDB: {e}\")\n", + "else:\n", + " print(\"SKIP: RDB not supported\")\n", + "\n", + "# USTB - User defined stability criteria (read-only query)\n", + "if \"USTB\" in backend._supported_commands:\n", + " try:\n", + " ustb_responses = await backend.send_command(\"USTB\")\n", + " print(f\"Stability criteria: {ustb_responses[0].command} {ustb_responses[0].status} {' '.join(ustb_responses[0].data)}\")\n", + " except Exception as e:\n", + " print(f\"USTB: {e}\")\n", + "else:\n", + " print(\"SKIP: USTB not supported\")\n", + "\n", + "# FCUT - Filter cut-off frequency (read-only query)\n", + "if \"FCUT\" in backend._supported_commands:\n", + " try:\n", + " fcut_responses = await backend.send_command(\"FCUT\")\n", + " print(f\"Filter cut-off: {fcut_responses[0].command} {fcut_responses[0].status} {' '.join(fcut_responses[0].data)}\")\n", + " except Exception as e:\n", + " print(f\"FCUT: {e}\")\n", + "else:\n", + " print(\"SKIP: FCUT not supported\")\n", + "\n", + "print(\"\\nPASS: Batch 2+3 read-only configuration queries completed\")" + ] }, { "cell_type": "markdown", @@ -1010,9 +2035,70 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 26, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2026-03-30 13:12:45,621 - pylabrobot - IO - [MT Scale] Sent command: Z\n", + "2026-03-30 13:12:45,625 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'Z\\r\\n'\n", + "2026-03-30 13:12:46,019 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'Z A\\r\\n'\n", + "2026-03-30 13:12:46,020 - pylabrobot - IO - [MT Scale] Received response: b'Z A\\r\\n'\n", + "2026-03-30 13:12:46,022 - pylabrobot - IO - [MT Scale] Sent command: SI\n", + "2026-03-30 13:12:46,024 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", + "2026-03-30 13:12:46,067 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 13:12:46,069 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Frontend zero + read: 0.0 g\n" + ] + }, + { + "name": "stdin", + "output_type": "stream", + "text": [ + "Place a container on the scale and press Enter... \n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2026-03-30 13:12:47,098 - pylabrobot - IO - [MT Scale] Sent command: T\n", + "2026-03-30 13:12:47,100 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'T\\r\\n'\n", + "2026-03-30 13:12:47,409 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'T S 0.00000 g\\r\\n'\n", + "2026-03-30 13:12:47,410 - pylabrobot - IO - [MT Scale] Received response: b'T S 0.00000 g\\r\\n'\n", + "2026-03-30 13:12:47,411 - pylabrobot - IO - [MT Scale] Sent command: TA\n", + "2026-03-30 13:12:47,412 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'TA\\r\\n'\n", + "2026-03-30 13:12:47,505 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'TA A 0.00000 g\\r\\n'\n", + "2026-03-30 13:12:47,506 - pylabrobot - IO - [MT Scale] Received response: b'TA A 0.00000 g\\r\\n'\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Frontend tare weight: 0.0 g\n" + ] + }, + { + "ename": "AssertionError", + "evalue": "", + "output_type": "error", + "traceback": [ + "\u001b[31m---------------------------------------------------------------------------\u001b[39m", + "\u001b[31mAssertionError\u001b[39m Traceback (most recent call last)", + "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[26]\u001b[39m\u001b[32m, line 12\u001b[39m\n\u001b[32m 10\u001b[39m tare = \u001b[38;5;28;01mawait\u001b[39;00m scale.request_tare_weight()\n\u001b[32m 11\u001b[39m \u001b[38;5;28mprint\u001b[39m(\u001b[33mf\u001b[39m\u001b[33m\"\u001b[39m\u001b[33mFrontend tare weight: \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mtare\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m g\u001b[39m\u001b[33m\"\u001b[39m)\n\u001b[32m---> \u001b[39m\u001b[32m12\u001b[39m \u001b[38;5;28;01massert\u001b[39;00m tare > \u001b[32m0\u001b[39m\n\u001b[32m 14\u001b[39m \u001b[38;5;66;03m# Read via frontend\u001b[39;00m\n\u001b[32m 15\u001b[39m w = \u001b[38;5;28;01mawait\u001b[39;00m scale.read_weight(timeout=\u001b[33m\"\u001b[39m\u001b[33mstable\u001b[39m\u001b[33m\"\u001b[39m)\n", + "\u001b[31mAssertionError\u001b[39m: " + ] + } + ], "source": [ "# Zero via frontend\n", "await scale.zero(timeout=\"stable\")\n", @@ -1045,9 +2131,104 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 27, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2026-03-30 13:12:49,989 - pylabrobot - IO - [MT Scale] Sent command: S\n", + "2026-03-30 13:12:49,991 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", + "2026-03-30 13:12:50,064 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 13:12:50,065 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 13:12:50,065 - pylabrobot - IO - [MT Scale] Sent command: S\n", + "2026-03-30 13:12:50,067 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", + "2026-03-30 13:12:50,159 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 13:12:50,159 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 13:12:50,160 - pylabrobot - IO - [MT Scale] Sent command: S\n", + "2026-03-30 13:12:50,161 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", + "2026-03-30 13:12:50,255 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 13:12:50,256 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 13:12:50,257 - pylabrobot - IO - [MT Scale] Sent command: S\n", + "2026-03-30 13:12:50,258 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", + "2026-03-30 13:12:50,351 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 13:12:50,352 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 13:12:50,353 - pylabrobot - IO - [MT Scale] Sent command: S\n", + "2026-03-30 13:12:50,356 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", + "2026-03-30 13:12:50,447 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 13:12:50,448 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 13:12:50,453 - pylabrobot - IO - [MT Scale] Sent command: S\n", + "2026-03-30 13:12:50,455 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", + "2026-03-30 13:12:50,561 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 13:12:50,563 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 13:12:50,569 - pylabrobot - IO - [MT Scale] Sent command: S\n", + "2026-03-30 13:12:50,574 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", + "2026-03-30 13:12:50,657 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 13:12:50,659 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 13:12:50,664 - pylabrobot - IO - [MT Scale] Sent command: S\n", + "2026-03-30 13:12:50,668 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", + "2026-03-30 13:12:50,751 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 13:12:50,752 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 13:12:50,753 - pylabrobot - IO - [MT Scale] Sent command: S\n", + "2026-03-30 13:12:50,759 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", + "2026-03-30 13:12:50,847 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 13:12:50,848 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 13:12:50,850 - pylabrobot - IO - [MT Scale] Sent command: S\n", + "2026-03-30 13:12:50,857 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", + "2026-03-30 13:12:50,943 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 13:12:50,944 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 13:12:50,947 - pylabrobot - IO - [MT Scale] Sent command: SI\n", + "2026-03-30 13:12:50,951 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", + "2026-03-30 13:12:50,991 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 13:12:50,994 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 13:12:50,999 - pylabrobot - IO - [MT Scale] Sent command: SI\n", + "2026-03-30 13:12:51,006 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", + "2026-03-30 13:12:51,041 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 13:12:51,043 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 13:12:51,046 - pylabrobot - IO - [MT Scale] Sent command: SI\n", + "2026-03-30 13:12:51,051 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", + "2026-03-30 13:12:51,086 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 13:12:51,087 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 13:12:51,088 - pylabrobot - IO - [MT Scale] Sent command: SI\n", + "2026-03-30 13:12:51,091 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", + "2026-03-30 13:12:51,119 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 13:12:51,120 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 13:12:51,125 - pylabrobot - IO - [MT Scale] Sent command: SI\n", + "2026-03-30 13:12:51,126 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", + "2026-03-30 13:12:51,168 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 13:12:51,169 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 13:12:51,177 - pylabrobot - IO - [MT Scale] Sent command: SI\n", + "2026-03-30 13:12:51,181 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", + "2026-03-30 13:12:51,215 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 13:12:51,216 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 13:12:51,216 - pylabrobot - IO - [MT Scale] Sent command: SI\n", + "2026-03-30 13:12:51,218 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", + "2026-03-30 13:12:51,246 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 13:12:51,247 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 13:12:51,249 - pylabrobot - IO - [MT Scale] Sent command: SI\n", + "2026-03-30 13:12:51,252 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", + "2026-03-30 13:12:51,278 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 13:12:51,279 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 13:12:51,280 - pylabrobot - IO - [MT Scale] Sent command: SI\n", + "2026-03-30 13:12:51,284 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", + "2026-03-30 13:12:51,326 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 13:12:51,327 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 13:12:51,328 - pylabrobot - IO - [MT Scale] Sent command: SI\n", + "2026-03-30 13:12:51,331 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", + "2026-03-30 13:12:51,375 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 13:12:51,376 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Stable read: 95.74 +/- 9.23 ms\n", + "Immediate read: 42.95 +/- 7.21 ms\n" + ] + } + ], "source": [ "import time\n", "\n", @@ -1083,9 +2264,30 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 28, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2026-03-30 13:12:51,402 - pylabrobot - INFO - === Hardware validation ended ===\n", + "2026-03-30 13:12:51,413 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] reset_input_buffer\n", + "2026-03-30 13:12:51,420 - pylabrobot - IO - [MT Scale] Sent command: @\n", + "2026-03-30 13:12:51,423 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'@\\r\\n'\n", + "2026-03-30 13:12:51,488 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I4 A \"B207696838\"\\r\\n'\n", + "2026-03-30 13:12:51,491 - pylabrobot - IO - [MT Scale] Received response: b'I4 A \"B207696838\"\\r\\n'\n", + "2026-03-30 13:12:51,493 - pylabrobot - INFO - [MT Scale] Disconnected from /dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Log file: ./logs/hardware_validation/2026-03-30_13-12-14_validation.log\n" + ] + } + ], "source": [ "plr_logger.info(\"=== Hardware validation ended ===\")\n", "await scale.stop()\n", @@ -1121,4 +2323,4 @@ }, "nbformat": 4, "nbformat_minor": 4 -} \ No newline at end of file +} From db7cfab974adce9743ebfe101a9a0c83af947f2c Mon Sep 17 00:00:00 2001 From: Camillo Moschner Date: Mon, 30 Mar 2026 13:21:40 +0100 Subject: [PATCH 25/38] clean up testing notebook --- .../mettler_toledo/hardware_validation.ipynb | 515 +----------------- .../scales/mettler_toledo/mt_sics_commands.md | 28 +- pylabrobot/scales/mettler_toledo/protocol.md | 49 +- 3 files changed, 62 insertions(+), 530 deletions(-) diff --git a/pylabrobot/scales/mettler_toledo/hardware_validation.ipynb b/pylabrobot/scales/mettler_toledo/hardware_validation.ipynb index 9eea3793983..9e464825c38 100644 --- a/pylabrobot/scales/mettler_toledo/hardware_validation.ipynb +++ b/pylabrobot/scales/mettler_toledo/hardware_validation.ipynb @@ -809,336 +809,14 @@ { "cell_type": "markdown", "metadata": {}, - "source": [ - "---\n", - "## 2. Level 0 Commands (Basic Set)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### @ - Cancel (reset to determined state)" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2026-03-30 13:12:17,574 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] reset_input_buffer\n", - "2026-03-30 13:12:17,575 - pylabrobot - IO - [MT Scale] Sent command: @\n", - "2026-03-30 13:12:17,577 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'@\\r\\n'\n", - "2026-03-30 13:12:17,628 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I4 A \"B207696838\"\\r\\n'\n", - "2026-03-30 13:12:17,629 - pylabrobot - IO - [MT Scale] Received response: b'I4 A \"B207696838\"\\r\\n'\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Cancel returned serial number: B207696838\n", - "PASS: cancel returns correct serial number\n" - ] - } - ], - "source": [ - "serial_number = await backend.cancel()\n", - "print(f\"Cancel returned serial number: {serial_number}\")\n", - "assert serial_number == backend.serial_number\n", - "print(\"PASS: cancel returns correct serial number\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### I4 - Serial number" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2026-03-30 13:12:17,637 - pylabrobot - IO - [MT Scale] Sent command: I4\n", - "2026-03-30 13:12:17,640 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I4\\r\\n'\n", - "2026-03-30 13:12:17,676 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I4 A \"B207696838\"\\r\\n'\n", - "2026-03-30 13:12:17,676 - pylabrobot - IO - [MT Scale] Received response: b'I4 A \"B207696838\"\\r\\n'\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Serial number: B207696838\n", - "PASS: serial number is non-empty\n" - ] - } - ], - "source": [ - "sn = await backend.request_serial_number()\n", - "print(f\"Serial number: {sn}\")\n", - "assert len(sn) > 0\n", - "print(\"PASS: serial number is non-empty\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### I2 - Device type and capacity" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2026-03-30 13:12:17,683 - pylabrobot - IO - [MT Scale] Sent command: I2\n", - "2026-03-30 13:12:17,686 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I2\\r\\n'\n", - "2026-03-30 13:12:17,756 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", - "2026-03-30 13:12:17,756 - pylabrobot - IO - [MT Scale] Received response: b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", - "2026-03-30 13:12:17,757 - pylabrobot - IO - [MT Scale] Sent command: I2\n", - "2026-03-30 13:12:17,760 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I2\\r\\n'\n", - "2026-03-30 13:12:17,819 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", - "2026-03-30 13:12:17,820 - pylabrobot - IO - [MT Scale] Received response: b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Device type: WXS205SDU WXA-Bridge\n", - "Capacity: 220.009 g\n", - "PASS: device type and capacity valid\n" - ] - } - ], - "source": [ - "device_type = await backend.request_device_type()\n", - "capacity = await backend.request_capacity()\n", - "print(f\"Device type: {device_type}\")\n", - "print(f\"Capacity: {capacity} g\")\n", - "assert len(device_type) > 0\n", - "assert capacity > 0\n", - "print(\"PASS: device type and capacity valid\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### I1 - MT-SICS levels" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2026-03-30 13:12:17,829 - pylabrobot - IO - [MT Scale] Sent command: I1\n", - "2026-03-30 13:12:17,831 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I1\\r\\n'\n", - "2026-03-30 13:12:17,884 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I1 A \"01\" \"2.30\" \"2.22\" \"\" \"\"\\r\\n'\n", - "2026-03-30 13:12:17,885 - pylabrobot - IO - [MT Scale] Received response: b'I1 A \"01\" \"2.30\" \"2.22\" \"\" \"\"\\r\\n'\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "I1 reported levels: ['01', '2.30', '2.22', '', '']\n", - "I0 discovered 62 commands\n", - "Note: I1 may underreport - I0 is the authoritative source\n" - ] - } - ], - "source": [ - "# I1 reports standardized level sets (may not reflect all available commands)\n", - "# I0 is the definitive source (already queried during setup)\n", - "responses = await backend.send_command(\"I1\")\n", - "print(f\"I1 reported levels: {responses[0].data}\")\n", - "print(f\"I0 discovered {len(backend._supported_commands)} commands\")\n", - "print(\"Note: I1 may underreport - I0 is the authoritative source\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### S - Stable weight (ensure pan is empty)" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2026-03-30 13:12:17,899 - pylabrobot - IO - [MT Scale] Sent command: S\n", - "2026-03-30 13:12:17,907 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", - "2026-03-30 13:12:18,123 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00003 g\\r\\n'\n", - "2026-03-30 13:12:18,124 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00003 g\\r\\n'\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Stable weight (empty pan): 3e-05 g\n", - "PASS: stable weight returns float\n" - ] - } - ], - "source": [ - "weight = await backend.read_stable_weight()\n", - "print(f\"Stable weight (empty pan): {weight} g\")\n", - "assert isinstance(weight, float)\n", - "print(\"PASS: stable weight returns float\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### SI - Weight immediately" - ] + "source": "---\n## 2. Core Protocol Validation\n\nThese Level 0/1 commands have been validated across multiple hardware runs.\nThis cell consolidates them into a single pass/fail check." }, { "cell_type": "code", - "execution_count": 12, "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2026-03-30 13:12:18,134 - pylabrobot - IO - [MT Scale] Sent command: SI\n", - "2026-03-30 13:12:18,140 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", - "2026-03-30 13:12:18,171 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00003 g\\r\\n'\n", - "2026-03-30 13:12:18,173 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00003 g\\r\\n'\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Immediate weight: 3e-05 g\n", - "PASS: immediate weight returns float\n" - ] - } - ], - "source": [ - "weight = await backend.read_weight_value_immediately()\n", - "print(f\"Immediate weight: {weight} g\")\n", - "assert isinstance(weight, float)\n", - "print(\"PASS: immediate weight returns float\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Z - Zero (stable)" - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2026-03-30 13:12:18,180 - pylabrobot - IO - [MT Scale] Sent command: Z\n", - "2026-03-30 13:12:18,184 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'Z\\r\\n'\n", - "2026-03-30 13:12:18,491 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'Z A\\r\\n'\n", - "2026-03-30 13:12:18,492 - pylabrobot - IO - [MT Scale] Received response: b'Z A\\r\\n'\n", - "2026-03-30 13:12:18,493 - pylabrobot - IO - [MT Scale] Sent command: SI\n", - "2026-03-30 13:12:18,496 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", - "2026-03-30 13:12:18,523 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 13:12:18,524 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Weight after zero: 0.0 g\n", - "PASS: zero sets weight to ~0\n" - ] - } - ], - "source": [ - "await scale.zero(timeout=\"stable\")\n", - "weight = await backend.read_weight_value_immediately()\n", - "print(f\"Weight after zero: {weight} g\")\n", - "assert abs(weight) < 0.001, f\"Expected ~0 after zero, got {weight}\"\n", - "print(\"PASS: zero sets weight to ~0\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### ZI - Zero immediately" - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2026-03-30 13:12:18,531 - pylabrobot - IO - [MT Scale] Sent command: ZI\n", - "2026-03-30 13:12:18,534 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'ZI\\r\\n'\n", - "2026-03-30 13:12:18,554 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'ZI S\\r\\n'\n", - "2026-03-30 13:12:18,555 - pylabrobot - IO - [MT Scale] Received response: b'ZI S\\r\\n'\n", - "2026-03-30 13:12:18,556 - pylabrobot - IO - [MT Scale] Sent command: SI\n", - "2026-03-30 13:12:18,558 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", - "2026-03-30 13:12:18,602 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 13:12:18,603 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Weight after zero immediately: 0.0 g\n", - "PASS: zero immediately sets weight to ~0\n" - ] - } - ], - "source": [ - "await scale.zero(timeout=0)\n", - "weight = await backend.read_weight_value_immediately()\n", - "print(f\"Weight after zero immediately: {weight} g\")\n", - "assert abs(weight) < 0.01\n", - "print(\"PASS: zero immediately sets weight to ~0\")" - ] + "source": "# @ - Cancel (returns serial number)\nsn = await backend.cancel()\nassert sn == backend.serial_number, f\"cancel() returned {sn}, expected {backend.serial_number}\"\n\n# I4 - Serial number\nsn2 = await backend.request_serial_number()\nassert sn2 == sn\n\n# I2 - Device type and capacity\ndt = await backend.request_device_type()\nassert len(dt) > 0\ncap = await backend.request_capacity()\nassert cap > 0\n\n# S - Stable weight\nw_stable = await backend.read_stable_weight()\nassert isinstance(w_stable, float)\n\n# SI - Weight immediately\nw_imm = await backend.read_weight_value_immediately()\nassert isinstance(w_imm, float)\n\n# Z - Zero (stable) then read\nawait scale.zero(timeout=\"stable\")\nw_after_zero = await backend.read_weight_value_immediately()\nassert abs(w_after_zero) < 0.001, f\"Expected ~0 after zero, got {w_after_zero}\"\n\n# ZI - Zero immediately then read\nawait scale.zero(timeout=0)\nw_after_zi = await backend.read_weight_value_immediately()\nassert abs(w_after_zi) < 0.01\n\n# TA - Request tare weight\ntare = await scale.request_tare_weight()\nassert isinstance(tare, float)\n\n# TAC - Clear tare\nawait backend.clear_tare()\ntare_after = await scale.request_tare_weight()\nassert abs(tare_after) < 0.001\n\nprint(\"PASS: all core Level 0/1 commands validated\")", + "outputs": [], + "execution_count": null }, { "cell_type": "markdown", @@ -1297,189 +975,6 @@ "print(\"PASS: clear tare resets tare to 0\")" ] }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### SC - Dynamic weight (timed read)" - ] - }, - { - "cell_type": "code", - "execution_count": 18, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2026-03-30 13:12:27,748 - pylabrobot - IO - [MT Scale] Sent command: SC 3000\n", - "2026-03-30 13:12:27,750 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SC 3000\\r\\n'\n", - "2026-03-30 13:12:27,779 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'ES\\r\\n'\n", - "2026-03-30 13:12:27,780 - pylabrobot - IO - [MT Scale] Received response: b'ES\\r\\n'\n" - ] - }, - { - "ename": "MettlerToledoError", - "evalue": "Syntax error: The weigh module/balance has not recognized the received command or the command is not allowed", - "output_type": "error", - "traceback": [ - "\u001b[31m---------------------------------------------------------------------------\u001b[39m", - "\u001b[31mMettlerToledoError\u001b[39m Traceback (most recent call last)", - "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[18]\u001b[39m\u001b[32m, line 1\u001b[39m\n\u001b[32m----> \u001b[39m\u001b[32m1\u001b[39m weight = \u001b[38;5;28;01mawait\u001b[39;00m backend.read_dynamic_weight(timeout=\u001b[32m3.0\u001b[39m)\n\u001b[32m 2\u001b[39m \u001b[38;5;28mprint\u001b[39m(\u001b[33mf\u001b[39m\u001b[33m\"\u001b[39m\u001b[33mDynamic weight (3s timeout): \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mweight\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m g\u001b[39m\u001b[33m\"\u001b[39m)\n\u001b[32m 3\u001b[39m \u001b[38;5;28;01massert\u001b[39;00m \u001b[38;5;28misinstance\u001b[39m(weight, \u001b[38;5;28mfloat\u001b[39m)\n", - "\u001b[36mFile \u001b[39m\u001b[32m~/Desktop/GitHub/pylabrobot/pylabrobot/scales/mettler_toledo/backend.py:688\u001b[39m, in \u001b[36mMettlerToledoWXS205SDUBackend.read_dynamic_weight\u001b[39m\u001b[34m(self, timeout)\u001b[39m\n\u001b[32m 679\u001b[39m \u001b[38;5;250m\u001b[39m\u001b[33;03m\"\"\"Read a stable weight value from the machine within a given timeout, or\u001b[39;00m\n\u001b[32m 680\u001b[39m \u001b[33;03mreturn the current weight value if not possible. (MEASUREMENT command)\u001b[39;00m\n\u001b[32m 681\u001b[39m \n\u001b[32m 682\u001b[39m \u001b[33;03mArgs:\u001b[39;00m\n\u001b[32m 683\u001b[39m \u001b[33;03m timeout: The timeout in seconds.\u001b[39;00m\n\u001b[32m 684\u001b[39m \u001b[33;03m\"\"\"\u001b[39;00m\n\u001b[32m 686\u001b[39m timeout = \u001b[38;5;28mint\u001b[39m(timeout * \u001b[32m1000\u001b[39m) \u001b[38;5;66;03m# convert to milliseconds\u001b[39;00m\n\u001b[32m--> \u001b[39m\u001b[32m688\u001b[39m responses = \u001b[38;5;28;01mawait\u001b[39;00m \u001b[38;5;28mself\u001b[39m.send_command(\u001b[33mf\u001b[39m\u001b[33m\"\u001b[39m\u001b[33mSC \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mtimeout\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m\"\u001b[39m)\n\u001b[32m 689\u001b[39m \u001b[38;5;28mself\u001b[39m._validate_response(responses[\u001b[32m0\u001b[39m], \u001b[32m4\u001b[39m, \u001b[33m\"\u001b[39m\u001b[33mSC\u001b[39m\u001b[33m\"\u001b[39m)\n\u001b[32m 690\u001b[39m \u001b[38;5;28mself\u001b[39m._validate_unit(responses[\u001b[32m0\u001b[39m].data[\u001b[32m1\u001b[39m], \u001b[33m\"\u001b[39m\u001b[33mSC\u001b[39m\u001b[33m\"\u001b[39m)\n", - "\u001b[36mFile \u001b[39m\u001b[32m~/Desktop/GitHub/pylabrobot/pylabrobot/scales/mettler_toledo/backend.py:342\u001b[39m, in \u001b[36mMettlerToledoWXS205SDUBackend.send_command\u001b[39m\u001b[34m(self, command, timeout)\u001b[39m\n\u001b[32m 340\u001b[39m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[32m 341\u001b[39m response = MettlerToledoResponse(command=\u001b[33m\"\u001b[39m\u001b[33m\"\u001b[39m, status=\u001b[33m\"\u001b[39m\u001b[33m\"\u001b[39m, data=[])\n\u001b[32m--> \u001b[39m\u001b[32m342\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[43m.\u001b[49m\u001b[43m_parse_basic_errors\u001b[49m\u001b[43m(\u001b[49m\u001b[43mresponse\u001b[49m\u001b[43m)\u001b[49m\n\u001b[32m 343\u001b[39m responses.append(response)\n\u001b[32m 345\u001b[39m \u001b[38;5;66;03m# Status B means more responses follow; anything else (A, etc.) is final\u001b[39;00m\n", - "\u001b[36mFile \u001b[39m\u001b[32m~/Desktop/GitHub/pylabrobot/pylabrobot/scales/mettler_toledo/backend.py:263\u001b[39m, in \u001b[36mMettlerToledoWXS205SDUBackend._parse_basic_errors\u001b[39m\u001b[34m(self, response)\u001b[39m\n\u001b[32m 261\u001b[39m \u001b[38;5;66;03m# General error messages: ES, ET, EL (status is \"\" for these)\u001b[39;00m\n\u001b[32m 262\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m response.command == \u001b[33m\"\u001b[39m\u001b[33mES\u001b[39m\u001b[33m\"\u001b[39m:\n\u001b[32m--> \u001b[39m\u001b[32m263\u001b[39m \u001b[38;5;28;01mraise\u001b[39;00m MettlerToledoError.syntax_error()\n\u001b[32m 264\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m response.command == \u001b[33m\"\u001b[39m\u001b[33mET\u001b[39m\u001b[33m\"\u001b[39m:\n\u001b[32m 265\u001b[39m \u001b[38;5;28;01mraise\u001b[39;00m MettlerToledoError.transmission_error()\n", - "\u001b[31mMettlerToledoError\u001b[39m: Syntax error: The weigh module/balance has not recognized the received command or the command is not allowed" - ] - } - ], - "source": [ - "weight = await backend.read_dynamic_weight(timeout=3.0)\n", - "print(f\"Dynamic weight (3s timeout): {weight} g\")\n", - "assert isinstance(weight, float)\n", - "print(\"PASS: dynamic weight returns float\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### C - Cancel all" - ] - }, - { - "cell_type": "code", - "execution_count": 19, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2026-03-30 13:12:28,895 - pylabrobot - IO - [MT Scale] Sent command: C\n", - "2026-03-30 13:12:28,899 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'C\\r\\n'\n", - "2026-03-30 13:12:28,929 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'ES\\r\\n'\n", - "2026-03-30 13:12:28,930 - pylabrobot - IO - [MT Scale] Received response: b'ES\\r\\n'\n" - ] - }, - { - "ename": "MettlerToledoError", - "evalue": "Syntax error: The weigh module/balance has not recognized the received command or the command is not allowed", - "output_type": "error", - "traceback": [ - "\u001b[31m---------------------------------------------------------------------------\u001b[39m", - "\u001b[31mMettlerToledoError\u001b[39m Traceback (most recent call last)", - "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[19]\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 backend.cancel_all()\n\u001b[32m 2\u001b[39m \u001b[38;5;28mprint\u001b[39m(\u001b[33m\"\u001b[39m\u001b[33mPASS: cancel_all completed without error\u001b[39m\u001b[33m\"\u001b[39m)\n", - "\u001b[36mFile \u001b[39m\u001b[32m~/Desktop/GitHub/pylabrobot/pylabrobot/scales/mettler_toledo/backend.py:380\u001b[39m, in \u001b[36mMettlerToledoWXS205SDUBackend.cancel_all\u001b[39m\u001b[34m(self)\u001b[39m\n\u001b[32m 370\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[34mcancel_all\u001b[39m(\u001b[38;5;28mself\u001b[39m) -> \u001b[38;5;28;01mNone\u001b[39;00m:\n\u001b[32m 371\u001b[39m \u001b[38;5;250m \u001b[39m\u001b[33;03m\"\"\"C - Cancel all active and pending interface commands.\u001b[39;00m\n\u001b[32m 372\u001b[39m \n\u001b[32m 373\u001b[39m \u001b[33;03m Unlike cancel() (@), this does not reset the device - it only cancels\u001b[39;00m\n\u001b[32m (...)\u001b[39m\u001b[32m 378\u001b[39m \u001b[33;03m C A (complete). Both responses are consumed to keep the serial buffer clean.\u001b[39;00m\n\u001b[32m 379\u001b[39m \u001b[33;03m \"\"\"\u001b[39;00m\n\u001b[32m--> \u001b[39m\u001b[32m380\u001b[39m responses = \u001b[38;5;28;01mawait\u001b[39;00m \u001b[38;5;28mself\u001b[39m.send_command(\u001b[33m\"\u001b[39m\u001b[33mC\u001b[39m\u001b[33m\"\u001b[39m)\n\u001b[32m 381\u001b[39m \u001b[38;5;66;03m# send_command reads both C B (started) and C A (complete) automatically\u001b[39;00m\n\u001b[32m 382\u001b[39m \u001b[38;5;28mself\u001b[39m._validate_response(responses[\u001b[32m0\u001b[39m], \u001b[32m2\u001b[39m, \u001b[33m\"\u001b[39m\u001b[33mC\u001b[39m\u001b[33m\"\u001b[39m)\n", - "\u001b[36mFile \u001b[39m\u001b[32m~/Desktop/GitHub/pylabrobot/pylabrobot/scales/mettler_toledo/backend.py:342\u001b[39m, in \u001b[36mMettlerToledoWXS205SDUBackend.send_command\u001b[39m\u001b[34m(self, command, timeout)\u001b[39m\n\u001b[32m 340\u001b[39m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[32m 341\u001b[39m response = MettlerToledoResponse(command=\u001b[33m\"\u001b[39m\u001b[33m\"\u001b[39m, status=\u001b[33m\"\u001b[39m\u001b[33m\"\u001b[39m, data=[])\n\u001b[32m--> \u001b[39m\u001b[32m342\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[43m.\u001b[49m\u001b[43m_parse_basic_errors\u001b[49m\u001b[43m(\u001b[49m\u001b[43mresponse\u001b[49m\u001b[43m)\u001b[49m\n\u001b[32m 343\u001b[39m responses.append(response)\n\u001b[32m 345\u001b[39m \u001b[38;5;66;03m# Status B means more responses follow; anything else (A, etc.) is final\u001b[39;00m\n", - "\u001b[36mFile \u001b[39m\u001b[32m~/Desktop/GitHub/pylabrobot/pylabrobot/scales/mettler_toledo/backend.py:263\u001b[39m, in \u001b[36mMettlerToledoWXS205SDUBackend._parse_basic_errors\u001b[39m\u001b[34m(self, response)\u001b[39m\n\u001b[32m 261\u001b[39m \u001b[38;5;66;03m# General error messages: ES, ET, EL (status is \"\" for these)\u001b[39;00m\n\u001b[32m 262\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m response.command == \u001b[33m\"\u001b[39m\u001b[33mES\u001b[39m\u001b[33m\"\u001b[39m:\n\u001b[32m--> \u001b[39m\u001b[32m263\u001b[39m \u001b[38;5;28;01mraise\u001b[39;00m MettlerToledoError.syntax_error()\n\u001b[32m 264\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m response.command == \u001b[33m\"\u001b[39m\u001b[33mET\u001b[39m\u001b[33m\"\u001b[39m:\n\u001b[32m 265\u001b[39m \u001b[38;5;28;01mraise\u001b[39;00m MettlerToledoError.transmission_error()\n", - "\u001b[31mMettlerToledoError\u001b[39m: Syntax error: The weigh module/balance has not recognized the received command or the command is not allowed" - ] - } - ], - "source": [ - "await backend.cancel_all()\n", - "print(\"PASS: cancel_all completed without error\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### D / DW - Display text" - ] - }, - { - "cell_type": "code", - "execution_count": 20, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2026-03-30 13:12:29,871 - pylabrobot - IO - [MT Scale] Sent command: D \"PLR TEST\"\n", - "2026-03-30 13:12:29,879 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'D \"PLR TEST\"\\r\\n'\n", - "2026-03-30 13:12:29,906 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'ES\\r\\n'\n", - "2026-03-30 13:12:29,907 - pylabrobot - IO - [MT Scale] Received response: b'ES\\r\\n'\n" - ] - }, - { - "ename": "MettlerToledoError", - "evalue": "Syntax error: The weigh module/balance has not recognized the received command or the command is not allowed", - "output_type": "error", - "traceback": [ - "\u001b[31m---------------------------------------------------------------------------\u001b[39m", - "\u001b[31mMettlerToledoError\u001b[39m Traceback (most recent call last)", - "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[20]\u001b[39m\u001b[32m, line 3\u001b[39m\n\u001b[32m 1\u001b[39m \u001b[38;5;28;01mimport\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[34;01masyncio\u001b[39;00m\n\u001b[32m----> \u001b[39m\u001b[32m3\u001b[39m \u001b[38;5;28;01mawait\u001b[39;00m backend.set_display_text(\u001b[33m\"\u001b[39m\u001b[33mPLR TEST\u001b[39m\u001b[33m\"\u001b[39m)\n\u001b[32m 4\u001b[39m \u001b[38;5;28;01mawait\u001b[39;00m asyncio.sleep(\u001b[32m2\u001b[39m)\n\u001b[32m 5\u001b[39m \u001b[38;5;28;01mawait\u001b[39;00m backend.set_weight_display()\n", - "\u001b[36mFile \u001b[39m\u001b[32m~/Desktop/GitHub/pylabrobot/pylabrobot/scales/mettler_toledo/backend.py:733\u001b[39m, in \u001b[36mMettlerToledoWXS205SDUBackend.set_display_text\u001b[39m\u001b[34m(self, text)\u001b[39m\n\u001b[32m 730\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[34mset_display_text\u001b[39m(\u001b[38;5;28mself\u001b[39m, text: \u001b[38;5;28mstr\u001b[39m) -> List[MettlerToledoResponse]:\n\u001b[32m 731\u001b[39m \u001b[38;5;250m \u001b[39m\u001b[33;03m\"\"\"Set the display text of the scale. Return to the normal weight display with\u001b[39;00m\n\u001b[32m 732\u001b[39m \u001b[33;03m self.set_weight_display().\"\"\"\u001b[39;00m\n\u001b[32m--> \u001b[39m\u001b[32m733\u001b[39m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;01mawait\u001b[39;00m \u001b[38;5;28mself\u001b[39m.send_command(\u001b[33mf\u001b[39m\u001b[33m'\u001b[39m\u001b[33mD \u001b[39m\u001b[33m\"\u001b[39m\u001b[38;5;132;01m{\u001b[39;00mtext\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m\"\u001b[39m\u001b[33m'\u001b[39m)\n", - "\u001b[36mFile \u001b[39m\u001b[32m~/Desktop/GitHub/pylabrobot/pylabrobot/scales/mettler_toledo/backend.py:342\u001b[39m, in \u001b[36mMettlerToledoWXS205SDUBackend.send_command\u001b[39m\u001b[34m(self, command, timeout)\u001b[39m\n\u001b[32m 340\u001b[39m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[32m 341\u001b[39m response = MettlerToledoResponse(command=\u001b[33m\"\u001b[39m\u001b[33m\"\u001b[39m, status=\u001b[33m\"\u001b[39m\u001b[33m\"\u001b[39m, data=[])\n\u001b[32m--> \u001b[39m\u001b[32m342\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[43m.\u001b[49m\u001b[43m_parse_basic_errors\u001b[49m\u001b[43m(\u001b[49m\u001b[43mresponse\u001b[49m\u001b[43m)\u001b[49m\n\u001b[32m 343\u001b[39m responses.append(response)\n\u001b[32m 345\u001b[39m \u001b[38;5;66;03m# Status B means more responses follow; anything else (A, etc.) is final\u001b[39;00m\n", - "\u001b[36mFile \u001b[39m\u001b[32m~/Desktop/GitHub/pylabrobot/pylabrobot/scales/mettler_toledo/backend.py:263\u001b[39m, in \u001b[36mMettlerToledoWXS205SDUBackend._parse_basic_errors\u001b[39m\u001b[34m(self, response)\u001b[39m\n\u001b[32m 261\u001b[39m \u001b[38;5;66;03m# General error messages: ES, ET, EL (status is \"\" for these)\u001b[39;00m\n\u001b[32m 262\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m response.command == \u001b[33m\"\u001b[39m\u001b[33mES\u001b[39m\u001b[33m\"\u001b[39m:\n\u001b[32m--> \u001b[39m\u001b[32m263\u001b[39m \u001b[38;5;28;01mraise\u001b[39;00m MettlerToledoError.syntax_error()\n\u001b[32m 264\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m response.command == \u001b[33m\"\u001b[39m\u001b[33mET\u001b[39m\u001b[33m\"\u001b[39m:\n\u001b[32m 265\u001b[39m \u001b[38;5;28;01mraise\u001b[39;00m MettlerToledoError.transmission_error()\n", - "\u001b[31mMettlerToledoError\u001b[39m: Syntax error: The weigh module/balance has not recognized the received command or the command is not allowed" - ] - } - ], - "source": [ - "import asyncio\n", - "\n", - "await backend.set_display_text(\"PLR TEST\")\n", - "await asyncio.sleep(2)\n", - "await backend.set_weight_display()\n", - "print(\"PASS: display text set and restored (check terminal if connected)\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### ZC / TC - Timed zero and tare\n", - "\n", - "These are known to return ES (syntax error) on the WXS205SDU despite being in the spec." - ] - }, - { - "cell_type": "code", - "execution_count": 21, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2026-03-30 13:12:32,605 - pylabrobot - IO - [MT Scale] Sent command: ZC 5000\n", - "2026-03-30 13:12:32,608 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'ZC 5000\\r\\n'\n", - "2026-03-30 13:12:32,639 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'ES\\r\\n'\n", - "2026-03-30 13:12:32,641 - pylabrobot - IO - [MT Scale] Received response: b'ES\\r\\n'\n", - "2026-03-30 13:12:32,645 - pylabrobot - IO - [MT Scale] Sent command: TC 5000\n", - "2026-03-30 13:12:32,646 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'TC 5000\\r\\n'\n", - "2026-03-30 13:12:32,671 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'ES\\r\\n'\n", - "2026-03-30 13:12:32,673 - pylabrobot - IO - [MT Scale] Received response: b'ES\\r\\n'\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "ZC: not supported (ES) - expected for WXS205SDU\n", - "TC: not supported (ES) - expected for WXS205SDU\n" - ] - } - ], - "source": [ - "from pylabrobot.scales.mettler_toledo.errors import MettlerToledoError\n", - "\n", - "for cmd_name, cmd in [(\"ZC\", \"ZC 5000\"), (\"TC\", \"TC 5000\")]:\n", - " try:\n", - " await backend.send_command(cmd)\n", - " print(f\"{cmd_name}: supported on this device\")\n", - " except MettlerToledoError as e:\n", - " if \"Syntax error\" in str(e):\n", - " print(f\"{cmd_name}: not supported (ES) - expected for WXS205SDU\")\n", - " else:\n", - " print(f\"{cmd_name}: unexpected error: {e}\")" - ] - }, { "cell_type": "markdown", "metadata": {}, @@ -2323,4 +1818,4 @@ }, "nbformat": 4, "nbformat_minor": 4 -} +} \ No newline at end of file diff --git a/pylabrobot/scales/mettler_toledo/mt_sics_commands.md b/pylabrobot/scales/mettler_toledo/mt_sics_commands.md index db7e42061a2..56ec1b8f1e2 100644 --- a/pylabrobot/scales/mettler_toledo/mt_sics_commands.md +++ b/pylabrobot/scales/mettler_toledo/mt_sics_commands.md @@ -107,9 +107,9 @@ Status key: | Command | Description | Spec Page | Status | WXS205SDU | Notes | |---------|------------------------------------------|-----------|--------|-----------|-------| -| M01 | Weighing mode | 157 | MED | yes | | -| M02 | Environment condition | 158 | MED | yes | Affects filter/stability. | -| M03 | Auto zero function | 159 | MED | yes | | +| M01 | Weighing mode | 157 | DONE | yes | request_weighing_mode() (read). set commented out (persists to memory). | +| M02 | Environment condition | 158 | DONE | yes | request_environment_condition() (read). set commented out (persists to memory). | +| M03 | Auto zero function | 159 | DONE | yes | request_auto_zero() (read). set commented out (persists to memory). | | M21 | Unit (host/display) | 165 | DONE | yes | set_host_unit_grams(). | | M23 | Readability (1d/xd) | 169 | LOW | - | | | M28 | Temperature value | 172 | DONE | yes | measure_temperature(). Returns 19.8-19.9 C on test device. | @@ -127,9 +127,9 @@ Status key: | Command | Description | Spec Page | Status | WXS205SDU | Notes | |---------|------------------------------------------|-----------|--------|-----------|-------| | C0 | Adjustment setting | 24 | LOW | yes | | -| C1 | Start adjustment (current settings) | 26 | MED | yes | Multi-response (B status). | +| C1 | Start adjustment (current settings) | 26 | STUB | yes | Commented out (moves internal weights). Multi-response. | | C2 | Start adjustment (external weight) | 28 | LOW | yes | | -| C3 | Start adjustment (built-in weight) | 30 | MED | yes | Internal calibration. Multi-response. | +| C3 | Start adjustment (built-in weight) | 30 | STUB | yes | Commented out (moves internal weights). Multi-response. | | C4 | Standard / initial adjustment | 31 | LOW | - | | | C5 | Enable/disable step control | 33 | LOW | - | | | C6 | Customer linearization + sensitivity | 34 | LOW | - | | @@ -137,7 +137,7 @@ Status key: | C8 | Sensitivity adjustment | 40 | LOW | - | | | C9 | Scale placement sensitivity adjustment | 43 | LOW | - | | | M19 | Adjustment weight | 163 | LOW | yes | | -| M27 | Adjustment history | 171 | MED | yes | | +| M27 | Adjustment history | 171 | DONE | yes | request_adjustment_history(). Multi-response. | ### Testing @@ -155,11 +155,11 @@ Status key: |---------|------------------------------------------|-----------|--------|-----------|-------| | SIC1 | Weight with CRC16 immediately | 226 | LOW | - | | | SIC2 | HighRes weight with CRC16 immediately | 227 | LOW | - | | -| SIS | Net weight with unit + weighing status | 234 | MED | yes | | +| SIS | Net weight with unit + weighing status | 234 | DONE | yes | request_net_weight_with_status(). | | SIU | Weight in display unit immediately | 237 | LOW | - | | | SIUM | Weight + MinWeigh info immediately | 238 | LOW | - | | | SIX1 | Current gross, net, and tare values | 239 | HIGH | - | Not on WXS205SDU. | -| SNR | Stable weight + repeat on stable change | 241 | LOW | yes | | +| SNR | Stable weight + repeat on stable change | 241 | DONE | yes | read_stable_weight_repeat_on_change(). Use cancel() to stop. | | ST | Stable weight on Transfer key press | 249 | N/A | - | Manual operation. | | SU | Stable weight in display unit | 250 | LOW | - | | | SUM | Stable weight + MinWeigh info | 251 | LOW | - | | @@ -201,7 +201,7 @@ Status key: | FSET | Reset all settings to factory defaults | 95 | LOW | yes | Level 3 on WXS205SDU. Destructive. | | RO1 | Restart device | 221 | MED | - | | | RDB | Readability | 222 | LOW | yes | Level 3 on WXS205SDU. | -| UPD | Update rate for SIR/SIRU | 267 | LOW | yes | | +| UPD | Update rate for SIR/SIRU | 267 | DONE | yes | request_update_rate() (read). set commented out (persists to memory). | | USTB | User defined stability criteria | 268 | LOW | yes | Level 3 on WXS205SDU. | ### Network (not relevant for serial) @@ -269,10 +269,6 @@ Status key: - SIX1 (gross, net, tare in one call) - not available on WXS205SDU ### MED (useful but not urgent) -- SIR/SR (continuous streaming) - available on WXS205SDU -- SIS (net weight + status) - available on WXS205SDU -- C1/C3 (adjustment) - available on WXS205SDU, multi-response -- M01/M02/M03 (weighing mode, environment, auto-zero) - available on WXS205SDU -- M27 (adjustment history) - available on WXS205SDU -- SNR (stable weight + repeat on change) - available on WXS205SDU -- UPD (update rate) - available on WXS205SDU +- SIR/SR (continuous streaming) - needs async iterator architecture +- C1/C3 (adjustment) - commented out, needs physical interaction +- DATI (date + time combined) - not on WXS205SDU diff --git a/pylabrobot/scales/mettler_toledo/protocol.md b/pylabrobot/scales/mettler_toledo/protocol.md index 53c862b4f6c..b7a19772c8d 100644 --- a/pylabrobot/scales/mettler_toledo/protocol.md +++ b/pylabrobot/scales/mettler_toledo/protocol.md @@ -110,19 +110,60 @@ Device sends: I4 A "B207696838"\r\n The @ command resets the device and responds with the serial number using the I4 response format, not the @ command name. -### Commands that always fail on WXS205SDU +### Commands not supported on WXS205SDU (bridge mode) -`ZC` (zero with timeout) and `TC` (tare with timeout) return `ES` (syntax error) on the WXS205SDU despite being listed in the MT-SICS spec. These commands may work on other MT-SICS devices. +The following commands return `ES` (syntax error) on the WXS205SDU WXA-Bridge +despite being listed in the MT-SICS spec. They may work on other MT-SICS devices +or on the same model with a terminal attached. + +- `C` (cancel all), `SC` (timed read), `ZC` (timed zero), `TC` (timed tare) +- `D`, `DW` (display commands - no terminal in bridge mode) +- `I50` (remaining weighing range) + +### I2 response format + +The I2 response packs type, capacity, and unit into a single quoted string: +``` +I2 A "WXS205SDU WXA-Bridge 220.00900 g" +``` +The device type can contain spaces. Parse from the right: unit is the last +token, capacity is second-to-last, type is everything before. +`shlex.split` is used to handle quoted strings correctly. + +### I15 uptime format varies + +Some devices return `I15 A ` (4 values). +The WXS205SDU returns `I15 A ` (single value). The parser handles both. + +## Command discovery + +**I0 is the definitive source of command support**, not I1. + +I1 reports which standardized level sets are fully implemented. However, a device +can have individual commands from levels it does not fully support. The WXS205SDU +reports I1 levels [0, 1] but I0 discovers 62 commands across levels 0-3, including +M21, M28, and many other Level 2 commands. + +During `setup()`, the backend queries I0 to discover all available commands. +Methods decorated with `@requires_mt_sics_command("CMD")` check against this list. ## Command levels -MT-SICS commands are grouped into levels. The device reports which levels it supports via the I1 command. +MT-SICS commands are grouped into levels. I1 reports level compliance but I0 is +the authoritative list of implemented commands. | Level | Description | Availability | |-------|-------------|-------------| | 0 | Basic set: identification, weighing, zero, tare, cancel | Always available | -| 1 | Elementary: display, tare memory, timed commands | Always available | +| 1 | Elementary: tare memory, timed commands, repeat | Always available | | 2 | Extended: configuration, device info, diagnostics | Model-dependent | | 3 | Application-specific: filling, dosing, calibration | Model-dependent | +## Write safety + +Commands that modify device settings (M01 set, M02 set, M03 set, etc.) persist +to memory and survive power cycles. They cannot be undone with @ cancel - only +via FSET (factory reset) or the terminal menu. Write methods are commented out +in the backend to prevent accidental modification. + See `mt_sics_commands.md` for the full command reference with implementation status. From a25937a2095d234f0f81a7f437a0cf874dc99345 Mon Sep 17 00:00:00 2001 From: Camillo Moschner Date: Mon, 30 Mar 2026 13:23:46 +0100 Subject: [PATCH 26/38] testing remaining batch 2 and 3 --- .../mettler_toledo/hardware_validation.ipynb | 1488 +++++++++-------- 1 file changed, 796 insertions(+), 692 deletions(-) diff --git a/pylabrobot/scales/mettler_toledo/hardware_validation.ipynb b/pylabrobot/scales/mettler_toledo/hardware_validation.ipynb index 9e464825c38..8cb923b2ece 100644 --- a/pylabrobot/scales/mettler_toledo/hardware_validation.ipynb +++ b/pylabrobot/scales/mettler_toledo/hardware_validation.ipynb @@ -33,7 +33,7 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 13:12:14,770 - pylabrobot - INFO - === Hardware validation started ===\n" + "2026-03-30 13:22:09,309 - pylabrobot - INFO - === Hardware validation started ===\n" ] } ], @@ -65,161 +65,161 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 13:12:14,791 - pylabrobot.io.serial - INFO - Using explicitly provided port: /dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0 (for VID=1027, PID=24577)\n", - "2026-03-30 13:12:14,799 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] reset_input_buffer\n", - "2026-03-30 13:12:14,800 - pylabrobot - IO - [MT Scale] Sent command: @\n", - "2026-03-30 13:12:14,803 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'@\\r\\n'\n", - "2026-03-30 13:12:14,862 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I4 A \"B207696838\"\\r\\n'\n", - "2026-03-30 13:12:14,863 - pylabrobot - IO - [MT Scale] Received response: b'I4 A \"B207696838\"\\r\\n'\n", - "2026-03-30 13:12:14,864 - pylabrobot - IO - [MT Scale] Sent command: I0\n", - "2026-03-30 13:12:14,865 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I0\\r\\n'\n", - "2026-03-30 13:12:14,893 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I0\"\\r\\n'\n", - "2026-03-30 13:12:14,894 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I0\"\\r\\n'\n", - "2026-03-30 13:12:14,910 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I1\"\\r\\n'\n", - "2026-03-30 13:12:14,911 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I1\"\\r\\n'\n", - "2026-03-30 13:12:14,925 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I2\"\\r\\n'\n", - "2026-03-30 13:12:14,926 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I2\"\\r\\n'\n", - "2026-03-30 13:12:14,942 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I3\"\\r\\n'\n", - "2026-03-30 13:12:14,942 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I3\"\\r\\n'\n", - "2026-03-30 13:12:14,959 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I4\"\\r\\n'\n", - "2026-03-30 13:12:14,962 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I4\"\\r\\n'\n", - "2026-03-30 13:12:14,974 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I5\"\\r\\n'\n", - "2026-03-30 13:12:14,975 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I5\"\\r\\n'\n", - "2026-03-30 13:12:14,977 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"S\"\\r\\n'\n", - "2026-03-30 13:12:14,978 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"S\"\\r\\n'\n", - "2026-03-30 13:12:14,990 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"SI\"\\r\\n'\n", - "2026-03-30 13:12:14,991 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"SI\"\\r\\n'\n", - "2026-03-30 13:12:15,005 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"SIR\"\\r\\n'\n", - "2026-03-30 13:12:15,006 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"SIR\"\\r\\n'\n", - "2026-03-30 13:12:15,022 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"Z\"\\r\\n'\n", - "2026-03-30 13:12:15,022 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"Z\"\\r\\n'\n", - "2026-03-30 13:12:15,038 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"ZI\"\\r\\n'\n", - "2026-03-30 13:12:15,039 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"ZI\"\\r\\n'\n", - "2026-03-30 13:12:15,053 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"@\"\\r\\n'\n", - "2026-03-30 13:12:15,055 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"@\"\\r\\n'\n", - "2026-03-30 13:12:15,056 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"SR\"\\r\\n'\n", - "2026-03-30 13:12:15,057 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"SR\"\\r\\n'\n", - "2026-03-30 13:12:15,070 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"T\"\\r\\n'\n", - "2026-03-30 13:12:15,071 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"T\"\\r\\n'\n", - "2026-03-30 13:12:15,085 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"TA\"\\r\\n'\n", - "2026-03-30 13:12:15,086 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"TA\"\\r\\n'\n", - "2026-03-30 13:12:15,101 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"TAC\"\\r\\n'\n", - "2026-03-30 13:12:15,102 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"TAC\"\\r\\n'\n", - "2026-03-30 13:12:15,118 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"TI\"\\r\\n'\n", - "2026-03-30 13:12:15,119 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"TI\"\\r\\n'\n", - "2026-03-30 13:12:15,134 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C0\"\\r\\n'\n", - "2026-03-30 13:12:15,135 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"C0\"\\r\\n'\n", - "2026-03-30 13:12:15,141 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C1\"\\r\\n'\n", - "2026-03-30 13:12:15,142 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"C1\"\\r\\n'\n", - "2026-03-30 13:12:15,150 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C2\"\\r\\n'\n", - "2026-03-30 13:12:15,151 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"C2\"\\r\\n'\n", - "2026-03-30 13:12:15,166 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C3\"\\r\\n'\n", - "2026-03-30 13:12:15,167 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"C3\"\\r\\n'\n", - "2026-03-30 13:12:15,181 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"COM\"\\r\\n'\n", - "2026-03-30 13:12:15,182 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"COM\"\\r\\n'\n", - "2026-03-30 13:12:15,198 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"DAT\"\\r\\n'\n", - "2026-03-30 13:12:15,199 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"DAT\"\\r\\n'\n", - "2026-03-30 13:12:15,213 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I10\"\\r\\n'\n", - "2026-03-30 13:12:15,214 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I10\"\\r\\n'\n", - "2026-03-30 13:12:15,229 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I11\"\\r\\n'\n", - "2026-03-30 13:12:15,230 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I11\"\\r\\n'\n", - "2026-03-30 13:12:15,246 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I14\"\\r\\n'\n", - "2026-03-30 13:12:15,248 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I14\"\\r\\n'\n", - "2026-03-30 13:12:15,262 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I15\"\\r\\n'\n", - "2026-03-30 13:12:15,263 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I15\"\\r\\n'\n", - "2026-03-30 13:12:15,277 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I16\"\\r\\n'\n", - "2026-03-30 13:12:15,278 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I16\"\\r\\n'\n", - "2026-03-30 13:12:15,279 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I21\"\\r\\n'\n", - "2026-03-30 13:12:15,280 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I21\"\\r\\n'\n", - "2026-03-30 13:12:15,294 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I22\"\\r\\n'\n", - "2026-03-30 13:12:15,295 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I22\"\\r\\n'\n", - "2026-03-30 13:12:15,309 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I23\"\\r\\n'\n", - "2026-03-30 13:12:15,310 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I23\"\\r\\n'\n", - "2026-03-30 13:12:15,326 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I24\"\\r\\n'\n", - "2026-03-30 13:12:15,326 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I24\"\\r\\n'\n", - "2026-03-30 13:12:15,341 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I25\"\\r\\n'\n", - "2026-03-30 13:12:15,342 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I25\"\\r\\n'\n", - "2026-03-30 13:12:15,357 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I26\"\\r\\n'\n", - "2026-03-30 13:12:15,358 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I26\"\\r\\n'\n", - "2026-03-30 13:12:15,374 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M01\"\\r\\n'\n", - "2026-03-30 13:12:15,374 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M01\"\\r\\n'\n", - "2026-03-30 13:12:15,389 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M02\"\\r\\n'\n", - "2026-03-30 13:12:15,390 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M02\"\\r\\n'\n", - "2026-03-30 13:12:15,405 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M03\"\\r\\n'\n", - "2026-03-30 13:12:15,406 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M03\"\\r\\n'\n", - "2026-03-30 13:12:15,422 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M17\"\\r\\n'\n", - "2026-03-30 13:12:15,422 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M17\"\\r\\n'\n", - "2026-03-30 13:12:15,437 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M18\"\\r\\n'\n", - "2026-03-30 13:12:15,438 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M18\"\\r\\n'\n", - "2026-03-30 13:12:15,453 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M19\"\\r\\n'\n", - "2026-03-30 13:12:15,454 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M19\"\\r\\n'\n", - "2026-03-30 13:12:15,456 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M20\"\\r\\n'\n", - "2026-03-30 13:12:15,456 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M20\"\\r\\n'\n", - "2026-03-30 13:12:15,470 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M21\"\\r\\n'\n", - "2026-03-30 13:12:15,470 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M21\"\\r\\n'\n", - "2026-03-30 13:12:15,485 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M27\"\\r\\n'\n", - "2026-03-30 13:12:15,486 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M27\"\\r\\n'\n", - "2026-03-30 13:12:15,501 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M28\"\\r\\n'\n", - "2026-03-30 13:12:15,503 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M28\"\\r\\n'\n", - "2026-03-30 13:12:15,518 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M29\"\\r\\n'\n", - "2026-03-30 13:12:15,519 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M29\"\\r\\n'\n", - "2026-03-30 13:12:15,533 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M31\"\\r\\n'\n", - "2026-03-30 13:12:15,534 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M31\"\\r\\n'\n", - "2026-03-30 13:12:15,549 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M32\"\\r\\n'\n", - "2026-03-30 13:12:15,550 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M32\"\\r\\n'\n", - "2026-03-30 13:12:15,566 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M33\"\\r\\n'\n", - "2026-03-30 13:12:15,567 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M33\"\\r\\n'\n", - "2026-03-30 13:12:15,581 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M35\"\\r\\n'\n", - "2026-03-30 13:12:15,582 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M35\"\\r\\n'\n", - "2026-03-30 13:12:15,598 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"SIS\"\\r\\n'\n", - "2026-03-30 13:12:15,600 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"SIS\"\\r\\n'\n", - "2026-03-30 13:12:15,613 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"SNR\"\\r\\n'\n", - "2026-03-30 13:12:15,614 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"SNR\"\\r\\n'\n", - "2026-03-30 13:12:15,616 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TIM\"\\r\\n'\n", - "2026-03-30 13:12:15,617 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TIM\"\\r\\n'\n", - "2026-03-30 13:12:15,633 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST0\"\\r\\n'\n", - "2026-03-30 13:12:15,634 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TST0\"\\r\\n'\n", - "2026-03-30 13:12:15,646 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST1\"\\r\\n'\n", - "2026-03-30 13:12:15,648 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TST1\"\\r\\n'\n", - "2026-03-30 13:12:15,661 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST2\"\\r\\n'\n", - "2026-03-30 13:12:15,662 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TST2\"\\r\\n'\n", - "2026-03-30 13:12:15,678 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST3\"\\r\\n'\n", - "2026-03-30 13:12:15,679 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TST3\"\\r\\n'\n", - "2026-03-30 13:12:15,693 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"UPD\"\\r\\n'\n", - "2026-03-30 13:12:15,694 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"UPD\"\\r\\n'\n", - "2026-03-30 13:12:15,712 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"FCUT\"\\r\\n'\n", - "2026-03-30 13:12:15,713 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 3 \"FCUT\"\\r\\n'\n", - "2026-03-30 13:12:15,726 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"FSET\"\\r\\n'\n", - "2026-03-30 13:12:15,727 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 3 \"FSET\"\\r\\n'\n", - "2026-03-30 13:12:15,741 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"LST\"\\r\\n'\n", - "2026-03-30 13:12:15,742 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 3 \"LST\"\\r\\n'\n", - "2026-03-30 13:12:15,758 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"RDB\"\\r\\n'\n", - "2026-03-30 13:12:15,758 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 3 \"RDB\"\\r\\n'\n", - "2026-03-30 13:12:15,773 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 A 3 \"USTB\"\\r\\n'\n", - "2026-03-30 13:12:15,774 - pylabrobot - IO - [MT Scale] Received response: b'I0 A 3 \"USTB\"\\r\\n'\n", - "2026-03-30 13:12:15,774 - pylabrobot - IO - [MT Scale] Sent command: I2\n", - "2026-03-30 13:12:15,780 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I2\\r\\n'\n", - "2026-03-30 13:12:15,837 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", - "2026-03-30 13:12:15,838 - pylabrobot - IO - [MT Scale] Received response: b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", - "2026-03-30 13:12:15,839 - pylabrobot - IO - [MT Scale] Sent command: I2\n", - "2026-03-30 13:12:15,841 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I2\\r\\n'\n", - "2026-03-30 13:12:15,901 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", - "2026-03-30 13:12:15,901 - pylabrobot - IO - [MT Scale] Received response: b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", - "2026-03-30 13:12:15,902 - pylabrobot - IO - [MT Scale] Sent command: I3\n", - "2026-03-30 13:12:15,903 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I3\\r\\n'\n", - "2026-03-30 13:12:15,949 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I3 A \"1.10 18.6.4.1361.772\"\\r\\n'\n", - "2026-03-30 13:12:15,950 - pylabrobot - IO - [MT Scale] Received response: b'I3 A \"1.10 18.6.4.1361.772\"\\r\\n'\n", - "2026-03-30 13:12:15,954 - pylabrobot - INFO - [MT Scale] Connected to Mettler Toledo scale on /dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0\n", + "2026-03-30 13:22:09,329 - pylabrobot.io.serial - INFO - Using explicitly provided port: /dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0 (for VID=1027, PID=24577)\n", + "2026-03-30 13:22:09,336 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] reset_input_buffer\n", + "2026-03-30 13:22:09,337 - pylabrobot - IO - [MT Scale] Sent command: @\n", + "2026-03-30 13:22:09,340 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'@\\r\\n'\n", + "2026-03-30 13:22:09,400 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I4 A \"B207696838\"\\r\\n'\n", + "2026-03-30 13:22:09,402 - pylabrobot - IO - [MT Scale] Received response: b'I4 A \"B207696838\"\\r\\n'\n", + "2026-03-30 13:22:09,405 - pylabrobot - IO - [MT Scale] Sent command: I0\n", + "2026-03-30 13:22:09,406 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I0\\r\\n'\n", + "2026-03-30 13:22:09,445 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I0\"\\r\\n'\n", + "2026-03-30 13:22:09,447 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I0\"\\r\\n'\n", + "2026-03-30 13:22:09,452 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I1\"\\r\\n'\n", + "2026-03-30 13:22:09,453 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I1\"\\r\\n'\n", + "2026-03-30 13:22:09,462 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I2\"\\r\\n'\n", + "2026-03-30 13:22:09,464 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I2\"\\r\\n'\n", + "2026-03-30 13:22:09,478 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I3\"\\r\\n'\n", + "2026-03-30 13:22:09,480 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I3\"\\r\\n'\n", + "2026-03-30 13:22:09,497 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I4\"\\r\\n'\n", + "2026-03-30 13:22:09,499 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I4\"\\r\\n'\n", + "2026-03-30 13:22:09,510 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I5\"\\r\\n'\n", + "2026-03-30 13:22:09,511 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I5\"\\r\\n'\n", + "2026-03-30 13:22:09,526 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"S\"\\r\\n'\n", + "2026-03-30 13:22:09,528 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"S\"\\r\\n'\n", + "2026-03-30 13:22:09,531 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"SI\"\\r\\n'\n", + "2026-03-30 13:22:09,532 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"SI\"\\r\\n'\n", + "2026-03-30 13:22:09,544 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"SIR\"\\r\\n'\n", + "2026-03-30 13:22:09,545 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"SIR\"\\r\\n'\n", + "2026-03-30 13:22:09,560 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"Z\"\\r\\n'\n", + "2026-03-30 13:22:09,562 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"Z\"\\r\\n'\n", + "2026-03-30 13:22:09,574 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"ZI\"\\r\\n'\n", + "2026-03-30 13:22:09,578 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"ZI\"\\r\\n'\n", + "2026-03-30 13:22:09,589 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"@\"\\r\\n'\n", + "2026-03-30 13:22:09,594 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"@\"\\r\\n'\n", + "2026-03-30 13:22:09,609 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"SR\"\\r\\n'\n", + "2026-03-30 13:22:09,611 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"SR\"\\r\\n'\n", + "2026-03-30 13:22:09,614 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"T\"\\r\\n'\n", + "2026-03-30 13:22:09,615 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"T\"\\r\\n'\n", + "2026-03-30 13:22:09,621 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"TA\"\\r\\n'\n", + "2026-03-30 13:22:09,622 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"TA\"\\r\\n'\n", + "2026-03-30 13:22:09,638 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"TAC\"\\r\\n'\n", + "2026-03-30 13:22:09,642 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"TAC\"\\r\\n'\n", + "2026-03-30 13:22:09,653 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"TI\"\\r\\n'\n", + "2026-03-30 13:22:09,654 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"TI\"\\r\\n'\n", + "2026-03-30 13:22:09,673 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C0\"\\r\\n'\n", + "2026-03-30 13:22:09,674 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"C0\"\\r\\n'\n", + "2026-03-30 13:22:09,686 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C1\"\\r\\n'\n", + "2026-03-30 13:22:09,687 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"C1\"\\r\\n'\n", + "2026-03-30 13:22:09,702 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C2\"\\r\\n'\n", + "2026-03-30 13:22:09,709 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"C2\"\\r\\n'\n", + "2026-03-30 13:22:09,713 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C3\"\\r\\n'\n", + "2026-03-30 13:22:09,714 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"C3\"\\r\\n'\n", + "2026-03-30 13:22:09,718 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"COM\"\\r\\n'\n", + "2026-03-30 13:22:09,720 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"COM\"\\r\\n'\n", + "2026-03-30 13:22:09,734 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"DAT\"\\r\\n'\n", + "2026-03-30 13:22:09,735 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"DAT\"\\r\\n'\n", + "2026-03-30 13:22:09,751 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I10\"\\r\\n'\n", + "2026-03-30 13:22:09,753 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I10\"\\r\\n'\n", + "2026-03-30 13:22:09,769 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I11\"\\r\\n'\n", + "2026-03-30 13:22:09,771 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I11\"\\r\\n'\n", + "2026-03-30 13:22:09,782 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I14\"\\r\\n'\n", + "2026-03-30 13:22:09,783 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I14\"\\r\\n'\n", + "2026-03-30 13:22:09,797 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I15\"\\r\\n'\n", + "2026-03-30 13:22:09,798 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I15\"\\r\\n'\n", + "2026-03-30 13:22:09,814 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I16\"\\r\\n'\n", + "2026-03-30 13:22:09,816 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I16\"\\r\\n'\n", + "2026-03-30 13:22:09,830 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I21\"\\r\\n'\n", + "2026-03-30 13:22:09,832 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I21\"\\r\\n'\n", + "2026-03-30 13:22:09,845 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I22\"\\r\\n'\n", + "2026-03-30 13:22:09,846 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I22\"\\r\\n'\n", + "2026-03-30 13:22:09,861 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I23\"\\r\\n'\n", + "2026-03-30 13:22:09,863 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I23\"\\r\\n'\n", + "2026-03-30 13:22:09,867 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I24\"\\r\\n'\n", + "2026-03-30 13:22:09,872 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I24\"\\r\\n'\n", + "2026-03-30 13:22:09,877 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I25\"\\r\\n'\n", + "2026-03-30 13:22:09,878 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I25\"\\r\\n'\n", + "2026-03-30 13:22:09,893 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I26\"\\r\\n'\n", + "2026-03-30 13:22:09,894 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I26\"\\r\\n'\n", + "2026-03-30 13:22:09,909 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M01\"\\r\\n'\n", + "2026-03-30 13:22:09,910 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M01\"\\r\\n'\n", + "2026-03-30 13:22:09,925 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M02\"\\r\\n'\n", + "2026-03-30 13:22:09,926 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M02\"\\r\\n'\n", + "2026-03-30 13:22:09,945 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M03\"\\r\\n'\n", + "2026-03-30 13:22:09,946 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M03\"\\r\\n'\n", + "2026-03-30 13:22:09,957 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M17\"\\r\\n'\n", + "2026-03-30 13:22:09,958 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M17\"\\r\\n'\n", + "2026-03-30 13:22:09,973 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M18\"\\r\\n'\n", + "2026-03-30 13:22:09,975 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M18\"\\r\\n'\n", + "2026-03-30 13:22:09,989 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M19\"\\r\\n'\n", + "2026-03-30 13:22:09,989 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M19\"\\r\\n'\n", + "2026-03-30 13:22:10,006 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M20\"\\r\\n'\n", + "2026-03-30 13:22:10,007 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M20\"\\r\\n'\n", + "2026-03-30 13:22:10,021 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M21\"\\r\\n'\n", + "2026-03-30 13:22:10,021 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M21\"\\r\\n'\n", + "2026-03-30 13:22:10,037 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M27\"\\r\\n'\n", + "2026-03-30 13:22:10,038 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M27\"\\r\\n'\n", + "2026-03-30 13:22:10,041 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M28\"\\r\\n'\n", + "2026-03-30 13:22:10,042 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M28\"\\r\\n'\n", + "2026-03-30 13:22:10,053 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M29\"\\r\\n'\n", + "2026-03-30 13:22:10,054 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M29\"\\r\\n'\n", + "2026-03-30 13:22:10,069 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M31\"\\r\\n'\n", + "2026-03-30 13:22:10,069 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M31\"\\r\\n'\n", + "2026-03-30 13:22:10,085 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M32\"\\r\\n'\n", + "2026-03-30 13:22:10,087 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M32\"\\r\\n'\n", + "2026-03-30 13:22:10,101 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M33\"\\r\\n'\n", + "2026-03-30 13:22:10,101 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M33\"\\r\\n'\n", + "2026-03-30 13:22:10,117 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M35\"\\r\\n'\n", + "2026-03-30 13:22:10,118 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M35\"\\r\\n'\n", + "2026-03-30 13:22:10,134 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"SIS\"\\r\\n'\n", + "2026-03-30 13:22:10,136 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"SIS\"\\r\\n'\n", + "2026-03-30 13:22:10,149 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"SNR\"\\r\\n'\n", + "2026-03-30 13:22:10,154 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"SNR\"\\r\\n'\n", + "2026-03-30 13:22:10,169 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TIM\"\\r\\n'\n", + "2026-03-30 13:22:10,170 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TIM\"\\r\\n'\n", + "2026-03-30 13:22:10,180 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST0\"\\r\\n'\n", + "2026-03-30 13:22:10,182 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TST0\"\\r\\n'\n", + "2026-03-30 13:22:10,197 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST1\"\\r\\n'\n", + "2026-03-30 13:22:10,198 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TST1\"\\r\\n'\n", + "2026-03-30 13:22:10,213 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST2\"\\r\\n'\n", + "2026-03-30 13:22:10,217 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TST2\"\\r\\n'\n", + "2026-03-30 13:22:10,229 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST3\"\\r\\n'\n", + "2026-03-30 13:22:10,230 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TST3\"\\r\\n'\n", + "2026-03-30 13:22:10,245 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"UPD\"\\r\\n'\n", + "2026-03-30 13:22:10,246 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"UPD\"\\r\\n'\n", + "2026-03-30 13:22:10,248 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"FCUT\"\\r\\n'\n", + "2026-03-30 13:22:10,249 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 3 \"FCUT\"\\r\\n'\n", + "2026-03-30 13:22:10,261 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"FSET\"\\r\\n'\n", + "2026-03-30 13:22:10,261 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 3 \"FSET\"\\r\\n'\n", + "2026-03-30 13:22:10,279 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"LST\"\\r\\n'\n", + "2026-03-30 13:22:10,280 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 3 \"LST\"\\r\\n'\n", + "2026-03-30 13:22:10,292 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"RDB\"\\r\\n'\n", + "2026-03-30 13:22:10,293 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 3 \"RDB\"\\r\\n'\n", + "2026-03-30 13:22:10,309 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 A 3 \"USTB\"\\r\\n'\n", + "2026-03-30 13:22:10,311 - pylabrobot - IO - [MT Scale] Received response: b'I0 A 3 \"USTB\"\\r\\n'\n", + "2026-03-30 13:22:10,314 - pylabrobot - IO - [MT Scale] Sent command: I2\n", + "2026-03-30 13:22:10,317 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I2\\r\\n'\n", + "2026-03-30 13:22:10,373 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", + "2026-03-30 13:22:10,374 - pylabrobot - IO - [MT Scale] Received response: b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", + "2026-03-30 13:22:10,385 - pylabrobot - IO - [MT Scale] Sent command: I2\n", + "2026-03-30 13:22:10,387 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I2\\r\\n'\n", + "2026-03-30 13:22:10,453 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", + "2026-03-30 13:22:10,455 - pylabrobot - IO - [MT Scale] Received response: b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", + "2026-03-30 13:22:10,457 - pylabrobot - IO - [MT Scale] Sent command: I3\n", + "2026-03-30 13:22:10,464 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I3\\r\\n'\n", + "2026-03-30 13:22:10,516 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I3 A \"1.10 18.6.4.1361.772\"\\r\\n'\n", + "2026-03-30 13:22:10,518 - pylabrobot - IO - [MT Scale] Received response: b'I3 A \"1.10 18.6.4.1361.772\"\\r\\n'\n", + "2026-03-30 13:22:10,521 - pylabrobot - INFO - [MT Scale] Connected to Mettler Toledo scale on /dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0\n", "Device type: WXS205SDU WXA-Bridge\n", "Configuration: Bridge\n", "Serial number: B207696838\n", "Firmware: 1.10 18.6.4.1361.772\n", "Capacity: 220.0 g\n", "Supported commands: ['@', 'C0', 'C1', 'C2', 'C3', 'COM', 'DAT', 'FCUT', 'FSET', 'I0', 'I1', 'I10', 'I11', 'I14', 'I15', 'I16', 'I2', 'I21', 'I22', 'I23', 'I24', 'I25', 'I26', 'I3', 'I4', 'I5', 'LST', 'M01', 'M02', 'M03', 'M17', 'M18', 'M19', 'M20', 'M21', 'M27', 'M28', 'M29', 'M31', 'M32', 'M33', 'M35', 'RDB', 'S', 'SI', 'SIR', 'SIS', 'SNR', 'SR', 'T', 'TA', 'TAC', 'TI', 'TIM', 'TST0', 'TST1', 'TST2', 'TST3', 'UPD', 'USTB', 'Z', 'ZI']\n", - "2026-03-30 13:12:15,954 - pylabrobot - IO - [MT Scale] Sent command: M21 0 0\n", - "2026-03-30 13:12:15,960 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'M21 0 0\\r\\n'\n", - "2026-03-30 13:12:15,997 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M21 A\\r\\n'\n", - "2026-03-30 13:12:15,998 - pylabrobot - IO - [MT Scale] Received response: b'M21 A\\r\\n'\n" + "2026-03-30 13:22:10,522 - pylabrobot - IO - [MT Scale] Sent command: M21 0 0\n", + "2026-03-30 13:22:10,526 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'M21 0 0\\r\\n'\n", + "2026-03-30 13:22:10,565 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M21 A\\r\\n'\n", + "2026-03-30 13:22:10,566 - pylabrobot - IO - [MT Scale] Received response: b'M21 A\\r\\n'\n" ] } ], @@ -364,132 +364,132 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 13:12:16,056 - pylabrobot - IO - [MT Scale] Sent command: I0\n", - "2026-03-30 13:12:16,058 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I0\\r\\n'\n", - "2026-03-30 13:12:16,093 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I0\"\\r\\n'\n", - "2026-03-30 13:12:16,094 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I0\"\\r\\n'\n", - "2026-03-30 13:12:16,109 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I1\"\\r\\n'\n", - "2026-03-30 13:12:16,109 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I1\"\\r\\n'\n", - "2026-03-30 13:12:16,125 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I2\"\\r\\n'\n", - "2026-03-30 13:12:16,126 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I2\"\\r\\n'\n", - "2026-03-30 13:12:16,127 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I3\"\\r\\n'\n", - "2026-03-30 13:12:16,128 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I3\"\\r\\n'\n", - "2026-03-30 13:12:16,141 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I4\"\\r\\n'\n", - "2026-03-30 13:12:16,142 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I4\"\\r\\n'\n", - "2026-03-30 13:12:16,157 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I5\"\\r\\n'\n", - "2026-03-30 13:12:16,158 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I5\"\\r\\n'\n", - "2026-03-30 13:12:16,173 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"S\"\\r\\n'\n", - "2026-03-30 13:12:16,174 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"S\"\\r\\n'\n", - "2026-03-30 13:12:16,189 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"SI\"\\r\\n'\n", - "2026-03-30 13:12:16,192 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"SI\"\\r\\n'\n", - "2026-03-30 13:12:16,207 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"SIR\"\\r\\n'\n", - "2026-03-30 13:12:16,208 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"SIR\"\\r\\n'\n", - "2026-03-30 13:12:16,217 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"Z\"\\r\\n'\n", - "2026-03-30 13:12:16,218 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"Z\"\\r\\n'\n", - "2026-03-30 13:12:16,221 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"ZI\"\\r\\n'\n", - "2026-03-30 13:12:16,222 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"ZI\"\\r\\n'\n", - "2026-03-30 13:12:16,237 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"@\"\\r\\n'\n", - "2026-03-30 13:12:16,239 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"@\"\\r\\n'\n", - "2026-03-30 13:12:16,253 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"SR\"\\r\\n'\n", - "2026-03-30 13:12:16,254 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"SR\"\\r\\n'\n", - "2026-03-30 13:12:16,269 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"T\"\\r\\n'\n", - "2026-03-30 13:12:16,271 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"T\"\\r\\n'\n", - "2026-03-30 13:12:16,284 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"TA\"\\r\\n'\n", - "2026-03-30 13:12:16,285 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"TA\"\\r\\n'\n", - "2026-03-30 13:12:16,287 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"TAC\"\\r\\n'\n", - "2026-03-30 13:12:16,288 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"TAC\"\\r\\n'\n", - "2026-03-30 13:12:16,301 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"TI\"\\r\\n'\n", - "2026-03-30 13:12:16,306 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"TI\"\\r\\n'\n", - "2026-03-30 13:12:16,318 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C0\"\\r\\n'\n", - "2026-03-30 13:12:16,319 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"C0\"\\r\\n'\n", - "2026-03-30 13:12:16,333 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C1\"\\r\\n'\n", - "2026-03-30 13:12:16,334 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"C1\"\\r\\n'\n", - "2026-03-30 13:12:16,349 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C2\"\\r\\n'\n", - "2026-03-30 13:12:16,353 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"C2\"\\r\\n'\n", - "2026-03-30 13:12:16,365 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C3\"\\r\\n'\n", - "2026-03-30 13:12:16,368 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"C3\"\\r\\n'\n", - "2026-03-30 13:12:16,381 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"COM\"\\r\\n'\n", - "2026-03-30 13:12:16,384 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"COM\"\\r\\n'\n", - "2026-03-30 13:12:16,389 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"DAT\"\\r\\n'\n", - "2026-03-30 13:12:16,391 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"DAT\"\\r\\n'\n", - "2026-03-30 13:12:16,396 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I10\"\\r\\n'\n", - "2026-03-30 13:12:16,399 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I10\"\\r\\n'\n", - "2026-03-30 13:12:16,413 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I11\"\\r\\n'\n", - "2026-03-30 13:12:16,417 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I11\"\\r\\n'\n", - "2026-03-30 13:12:16,429 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I14\"\\r\\n'\n", - "2026-03-30 13:12:16,433 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I14\"\\r\\n'\n", - "2026-03-30 13:12:16,445 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I15\"\\r\\n'\n", - "2026-03-30 13:12:16,446 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I15\"\\r\\n'\n", - "2026-03-30 13:12:16,460 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I16\"\\r\\n'\n", - "2026-03-30 13:12:16,461 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I16\"\\r\\n'\n", - "2026-03-30 13:12:16,477 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I21\"\\r\\n'\n", - "2026-03-30 13:12:16,477 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I21\"\\r\\n'\n", - "2026-03-30 13:12:16,493 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I22\"\\r\\n'\n", - "2026-03-30 13:12:16,494 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I22\"\\r\\n'\n", - "2026-03-30 13:12:16,508 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I23\"\\r\\n'\n", - "2026-03-30 13:12:16,509 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I23\"\\r\\n'\n", - "2026-03-30 13:12:16,525 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I24\"\\r\\n'\n", - "2026-03-30 13:12:16,525 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I24\"\\r\\n'\n", - "2026-03-30 13:12:16,540 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I25\"\\r\\n'\n", - "2026-03-30 13:12:16,540 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I25\"\\r\\n'\n", - "2026-03-30 13:12:16,556 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I26\"\\r\\n'\n", - "2026-03-30 13:12:16,557 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I26\"\\r\\n'\n", - "2026-03-30 13:12:16,558 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M01\"\\r\\n'\n", - "2026-03-30 13:12:16,559 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M01\"\\r\\n'\n", - "2026-03-30 13:12:16,573 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M02\"\\r\\n'\n", - "2026-03-30 13:12:16,573 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M02\"\\r\\n'\n", - "2026-03-30 13:12:16,588 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M03\"\\r\\n'\n", - "2026-03-30 13:12:16,589 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M03\"\\r\\n'\n", - "2026-03-30 13:12:16,604 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M17\"\\r\\n'\n", - "2026-03-30 13:12:16,605 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M17\"\\r\\n'\n", - "2026-03-30 13:12:16,621 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M18\"\\r\\n'\n", - "2026-03-30 13:12:16,621 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M18\"\\r\\n'\n", - "2026-03-30 13:12:16,636 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M19\"\\r\\n'\n", - "2026-03-30 13:12:16,637 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M19\"\\r\\n'\n", - "2026-03-30 13:12:16,652 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M20\"\\r\\n'\n", - "2026-03-30 13:12:16,653 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M20\"\\r\\n'\n", - "2026-03-30 13:12:16,669 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M21\"\\r\\n'\n", - "2026-03-30 13:12:16,669 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M21\"\\r\\n'\n", - "2026-03-30 13:12:16,684 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M27\"\\r\\n'\n", - "2026-03-30 13:12:16,685 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M27\"\\r\\n'\n", - "2026-03-30 13:12:16,700 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M28\"\\r\\n'\n", - "2026-03-30 13:12:16,701 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M28\"\\r\\n'\n", - "2026-03-30 13:12:16,717 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M29\"\\r\\n'\n", - "2026-03-30 13:12:16,717 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M29\"\\r\\n'\n", - "2026-03-30 13:12:16,718 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M31\"\\r\\n'\n", - "2026-03-30 13:12:16,719 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M31\"\\r\\n'\n", - "2026-03-30 13:12:16,732 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M32\"\\r\\n'\n", - "2026-03-30 13:12:16,733 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M32\"\\r\\n'\n", - "2026-03-30 13:12:16,748 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M33\"\\r\\n'\n", - "2026-03-30 13:12:16,749 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M33\"\\r\\n'\n", - "2026-03-30 13:12:16,765 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M35\"\\r\\n'\n", - "2026-03-30 13:12:16,765 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M35\"\\r\\n'\n", - "2026-03-30 13:12:16,780 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"SIS\"\\r\\n'\n", - "2026-03-30 13:12:16,781 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"SIS\"\\r\\n'\n", - "2026-03-30 13:12:16,796 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"SNR\"\\r\\n'\n", - "2026-03-30 13:12:16,797 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"SNR\"\\r\\n'\n", - "2026-03-30 13:12:16,813 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TIM\"\\r\\n'\n", - "2026-03-30 13:12:16,814 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TIM\"\\r\\n'\n", - "2026-03-30 13:12:16,828 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST0\"\\r\\n'\n", - "2026-03-30 13:12:16,829 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TST0\"\\r\\n'\n", - "2026-03-30 13:12:16,845 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST1\"\\r\\n'\n", - "2026-03-30 13:12:16,845 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TST1\"\\r\\n'\n", - "2026-03-30 13:12:16,860 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST2\"\\r\\n'\n", - "2026-03-30 13:12:16,861 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TST2\"\\r\\n'\n", - "2026-03-30 13:12:16,876 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST3\"\\r\\n'\n", - "2026-03-30 13:12:16,877 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TST3\"\\r\\n'\n", - "2026-03-30 13:12:16,892 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"UPD\"\\r\\n'\n", - "2026-03-30 13:12:16,893 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"UPD\"\\r\\n'\n", - "2026-03-30 13:12:16,908 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"FCUT\"\\r\\n'\n", - "2026-03-30 13:12:16,909 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 3 \"FCUT\"\\r\\n'\n", - "2026-03-30 13:12:16,924 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"FSET\"\\r\\n'\n", - "2026-03-30 13:12:16,925 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 3 \"FSET\"\\r\\n'\n", - "2026-03-30 13:12:16,941 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"LST\"\\r\\n'\n", - "2026-03-30 13:12:16,941 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 3 \"LST\"\\r\\n'\n", - "2026-03-30 13:12:16,956 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"RDB\"\\r\\n'\n", - "2026-03-30 13:12:16,956 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 3 \"RDB\"\\r\\n'\n", - "2026-03-30 13:12:16,972 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 A 3 \"USTB\"\\r\\n'\n", - "2026-03-30 13:12:16,973 - pylabrobot - IO - [MT Scale] Received response: b'I0 A 3 \"USTB\"\\r\\n'\n" + "2026-03-30 13:22:10,635 - pylabrobot - IO - [MT Scale] Sent command: I0\n", + "2026-03-30 13:22:10,637 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I0\\r\\n'\n", + "2026-03-30 13:22:10,663 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I0\"\\r\\n'\n", + "2026-03-30 13:22:10,667 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I0\"\\r\\n'\n", + "2026-03-30 13:22:10,678 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I1\"\\r\\n'\n", + "2026-03-30 13:22:10,681 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I1\"\\r\\n'\n", + "2026-03-30 13:22:10,693 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I2\"\\r\\n'\n", + "2026-03-30 13:22:10,695 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I2\"\\r\\n'\n", + "2026-03-30 13:22:10,708 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I3\"\\r\\n'\n", + "2026-03-30 13:22:10,714 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I3\"\\r\\n'\n", + "2026-03-30 13:22:10,725 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I4\"\\r\\n'\n", + "2026-03-30 13:22:10,728 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I4\"\\r\\n'\n", + "2026-03-30 13:22:10,740 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I5\"\\r\\n'\n", + "2026-03-30 13:22:10,742 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I5\"\\r\\n'\n", + "2026-03-30 13:22:10,746 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"S\"\\r\\n'\n", + "2026-03-30 13:22:10,751 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"S\"\\r\\n'\n", + "2026-03-30 13:22:10,757 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"SI\"\\r\\n'\n", + "2026-03-30 13:22:10,758 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"SI\"\\r\\n'\n", + "2026-03-30 13:22:10,772 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"SIR\"\\r\\n'\n", + "2026-03-30 13:22:10,773 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"SIR\"\\r\\n'\n", + "2026-03-30 13:22:10,788 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"Z\"\\r\\n'\n", + "2026-03-30 13:22:10,789 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"Z\"\\r\\n'\n", + "2026-03-30 13:22:10,805 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"ZI\"\\r\\n'\n", + "2026-03-30 13:22:10,805 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"ZI\"\\r\\n'\n", + "2026-03-30 13:22:10,820 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"@\"\\r\\n'\n", + "2026-03-30 13:22:10,821 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"@\"\\r\\n'\n", + "2026-03-30 13:22:10,822 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"SR\"\\r\\n'\n", + "2026-03-30 13:22:10,822 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"SR\"\\r\\n'\n", + "2026-03-30 13:22:10,836 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"T\"\\r\\n'\n", + "2026-03-30 13:22:10,837 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"T\"\\r\\n'\n", + "2026-03-30 13:22:10,853 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"TA\"\\r\\n'\n", + "2026-03-30 13:22:10,853 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"TA\"\\r\\n'\n", + "2026-03-30 13:22:10,868 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"TAC\"\\r\\n'\n", + "2026-03-30 13:22:10,870 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"TAC\"\\r\\n'\n", + "2026-03-30 13:22:10,885 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"TI\"\\r\\n'\n", + "2026-03-30 13:22:10,886 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"TI\"\\r\\n'\n", + "2026-03-30 13:22:10,900 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C0\"\\r\\n'\n", + "2026-03-30 13:22:10,900 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"C0\"\\r\\n'\n", + "2026-03-30 13:22:10,916 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C1\"\\r\\n'\n", + "2026-03-30 13:22:10,917 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"C1\"\\r\\n'\n", + "2026-03-30 13:22:10,919 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C2\"\\r\\n'\n", + "2026-03-30 13:22:10,921 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"C2\"\\r\\n'\n", + "2026-03-30 13:22:10,932 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C3\"\\r\\n'\n", + "2026-03-30 13:22:10,933 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"C3\"\\r\\n'\n", + "2026-03-30 13:22:10,948 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"COM\"\\r\\n'\n", + "2026-03-30 13:22:10,949 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"COM\"\\r\\n'\n", + "2026-03-30 13:22:10,964 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"DAT\"\\r\\n'\n", + "2026-03-30 13:22:10,966 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"DAT\"\\r\\n'\n", + "2026-03-30 13:22:10,982 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I10\"\\r\\n'\n", + "2026-03-30 13:22:10,983 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I10\"\\r\\n'\n", + "2026-03-30 13:22:10,996 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I11\"\\r\\n'\n", + "2026-03-30 13:22:10,998 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I11\"\\r\\n'\n", + "2026-03-30 13:22:11,013 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I14\"\\r\\n'\n", + "2026-03-30 13:22:11,015 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I14\"\\r\\n'\n", + "2026-03-30 13:22:11,030 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I15\"\\r\\n'\n", + "2026-03-30 13:22:11,033 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I15\"\\r\\n'\n", + "2026-03-30 13:22:11,045 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I16\"\\r\\n'\n", + "2026-03-30 13:22:11,048 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I16\"\\r\\n'\n", + "2026-03-30 13:22:11,061 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I21\"\\r\\n'\n", + "2026-03-30 13:22:11,065 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I21\"\\r\\n'\n", + "2026-03-30 13:22:11,068 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I22\"\\r\\n'\n", + "2026-03-30 13:22:11,070 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I22\"\\r\\n'\n", + "2026-03-30 13:22:11,077 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I23\"\\r\\n'\n", + "2026-03-30 13:22:11,079 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I23\"\\r\\n'\n", + "2026-03-30 13:22:11,093 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I24\"\\r\\n'\n", + "2026-03-30 13:22:11,097 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I24\"\\r\\n'\n", + "2026-03-30 13:22:11,109 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I25\"\\r\\n'\n", + "2026-03-30 13:22:11,110 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I25\"\\r\\n'\n", + "2026-03-30 13:22:11,125 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I26\"\\r\\n'\n", + "2026-03-30 13:22:11,133 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I26\"\\r\\n'\n", + "2026-03-30 13:22:11,142 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M01\"\\r\\n'\n", + "2026-03-30 13:22:11,143 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M01\"\\r\\n'\n", + "2026-03-30 13:22:11,156 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M02\"\\r\\n'\n", + "2026-03-30 13:22:11,159 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M02\"\\r\\n'\n", + "2026-03-30 13:22:11,173 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M03\"\\r\\n'\n", + "2026-03-30 13:22:11,179 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M03\"\\r\\n'\n", + "2026-03-30 13:22:11,189 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M17\"\\r\\n'\n", + "2026-03-30 13:22:11,192 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M17\"\\r\\n'\n", + "2026-03-30 13:22:11,205 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M18\"\\r\\n'\n", + "2026-03-30 13:22:11,206 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M18\"\\r\\n'\n", + "2026-03-30 13:22:11,220 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M19\"\\r\\n'\n", + "2026-03-30 13:22:11,221 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M19\"\\r\\n'\n", + "2026-03-30 13:22:11,237 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M20\"\\r\\n'\n", + "2026-03-30 13:22:11,238 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M20\"\\r\\n'\n", + "2026-03-30 13:22:11,241 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M21\"\\r\\n'\n", + "2026-03-30 13:22:11,243 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M21\"\\r\\n'\n", + "2026-03-30 13:22:11,252 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M27\"\\r\\n'\n", + "2026-03-30 13:22:11,257 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M27\"\\r\\n'\n", + "2026-03-30 13:22:11,268 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M28\"\\r\\n'\n", + "2026-03-30 13:22:11,269 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M28\"\\r\\n'\n", + "2026-03-30 13:22:11,284 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M29\"\\r\\n'\n", + "2026-03-30 13:22:11,286 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M29\"\\r\\n'\n", + "2026-03-30 13:22:11,300 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M31\"\\r\\n'\n", + "2026-03-30 13:22:11,300 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M31\"\\r\\n'\n", + "2026-03-30 13:22:11,316 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M32\"\\r\\n'\n", + "2026-03-30 13:22:11,317 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M32\"\\r\\n'\n", + "2026-03-30 13:22:11,332 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M33\"\\r\\n'\n", + "2026-03-30 13:22:11,333 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M33\"\\r\\n'\n", + "2026-03-30 13:22:11,347 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M35\"\\r\\n'\n", + "2026-03-30 13:22:11,348 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M35\"\\r\\n'\n", + "2026-03-30 13:22:11,364 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"SIS\"\\r\\n'\n", + "2026-03-30 13:22:11,364 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"SIS\"\\r\\n'\n", + "2026-03-30 13:22:11,380 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"SNR\"\\r\\n'\n", + "2026-03-30 13:22:11,381 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"SNR\"\\r\\n'\n", + "2026-03-30 13:22:11,396 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TIM\"\\r\\n'\n", + "2026-03-30 13:22:11,396 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TIM\"\\r\\n'\n", + "2026-03-30 13:22:11,412 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST0\"\\r\\n'\n", + "2026-03-30 13:22:11,413 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TST0\"\\r\\n'\n", + "2026-03-30 13:22:11,428 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST1\"\\r\\n'\n", + "2026-03-30 13:22:11,429 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TST1\"\\r\\n'\n", + "2026-03-30 13:22:11,431 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST2\"\\r\\n'\n", + "2026-03-30 13:22:11,432 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TST2\"\\r\\n'\n", + "2026-03-30 13:22:11,444 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST3\"\\r\\n'\n", + "2026-03-30 13:22:11,445 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TST3\"\\r\\n'\n", + "2026-03-30 13:22:11,460 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"UPD\"\\r\\n'\n", + "2026-03-30 13:22:11,463 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"UPD\"\\r\\n'\n", + "2026-03-30 13:22:11,476 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"FCUT\"\\r\\n'\n", + "2026-03-30 13:22:11,477 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 3 \"FCUT\"\\r\\n'\n", + "2026-03-30 13:22:11,492 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"FSET\"\\r\\n'\n", + "2026-03-30 13:22:11,493 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 3 \"FSET\"\\r\\n'\n", + "2026-03-30 13:22:11,508 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"LST\"\\r\\n'\n", + "2026-03-30 13:22:11,509 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 3 \"LST\"\\r\\n'\n", + "2026-03-30 13:22:11,524 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"RDB\"\\r\\n'\n", + "2026-03-30 13:22:11,525 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 3 \"RDB\"\\r\\n'\n", + "2026-03-30 13:22:11,540 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 A 3 \"USTB\"\\r\\n'\n", + "2026-03-30 13:22:11,541 - pylabrobot - IO - [MT Scale] Received response: b'I0 A 3 \"USTB\"\\r\\n'\n" ] }, { @@ -605,24 +605,20 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 13:12:16,984 - pylabrobot - IO - [MT Scale] Sent command: I3\n", - "2026-03-30 13:12:16,986 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I3\\r\\n'\n", - "2026-03-30 13:12:17,036 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I3 A \"1.10 18.6.4.1361.772\"\\r\\n'\n", - "2026-03-30 13:12:17,038 - pylabrobot - IO - [MT Scale] Received response: b'I3 A \"1.10 18.6.4.1361.772\"\\r\\n'\n", - "2026-03-30 13:12:17,038 - pylabrobot - IO - [MT Scale] Sent command: I5\n", - "2026-03-30 13:12:17,041 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I5\\r\\n'\n", - "2026-03-30 13:12:17,084 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I5 A \"11671158C\"\\r\\n'\n", - "2026-03-30 13:12:17,084 - pylabrobot - IO - [MT Scale] Received response: b'I5 A \"11671158C\"\\r\\n'\n", - "2026-03-30 13:12:17,085 - pylabrobot - IO - [MT Scale] Sent command: I10\n", - "2026-03-30 13:12:17,087 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I10\\r\\n'\n", - "2026-03-30 13:12:17,116 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I10 A \"\"\\r\\n'\n", - "2026-03-30 13:12:17,117 - pylabrobot - IO - [MT Scale] Received response: b'I10 A \"\"\\r\\n'\n", - "2026-03-30 13:12:17,118 - pylabrobot - IO - [MT Scale] Sent command: I11\n", - "2026-03-30 13:12:17,120 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I11\\r\\n'\n", - "2026-03-30 13:12:17,164 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I11 A \"WXS205SDU\"\\r\\n'\n", - "2026-03-30 13:12:17,166 - pylabrobot - IO - [MT Scale] Received response: b'I11 A \"WXS205SDU\"\\r\\n'\n", - "2026-03-30 13:12:17,167 - pylabrobot - IO - [MT Scale] Sent command: I15\n", - "2026-03-30 13:12:17,168 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I15\\r\\n'\n" + "2026-03-30 13:22:11,575 - pylabrobot - IO - [MT Scale] Sent command: I3\n", + "2026-03-30 13:22:11,583 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I3\\r\\n'\n", + "2026-03-30 13:22:11,637 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I3 A \"1.10 18.6.4.1361.772\"\\r\\n'\n", + "2026-03-30 13:22:11,642 - pylabrobot - IO - [MT Scale] Received response: b'I3 A \"1.10 18.6.4.1361.772\"\\r\\n'\n", + "2026-03-30 13:22:11,643 - pylabrobot - IO - [MT Scale] Sent command: I5\n", + "2026-03-30 13:22:11,648 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I5\\r\\n'\n", + "2026-03-30 13:22:11,684 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I5 A \"11671158C\"\\r\\n'\n", + "2026-03-30 13:22:11,684 - pylabrobot - IO - [MT Scale] Received response: b'I5 A \"11671158C\"\\r\\n'\n", + "2026-03-30 13:22:11,687 - pylabrobot - IO - [MT Scale] Sent command: I10\n", + "2026-03-30 13:22:11,688 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I10\\r\\n'\n", + "2026-03-30 13:22:11,716 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I10 A \"\"\\r\\n'\n", + "2026-03-30 13:22:11,718 - pylabrobot - IO - [MT Scale] Received response: b'I10 A \"\"\\r\\n'\n", + "2026-03-30 13:22:11,720 - pylabrobot - IO - [MT Scale] Sent command: I11\n", + "2026-03-30 13:22:11,726 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I11\\r\\n'\n" ] }, { @@ -631,47 +627,47 @@ "text": [ "Software version: 1.10 18.6.4.1361.772\n", "Software material number: 11671158C\n", - "Device ID: ''\n", - "Model designation: WXS205SDU\n" + "Device ID: ''\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 13:12:17,196 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I15 A 224\\r\\n'\n", - "2026-03-30 13:12:17,197 - pylabrobot - IO - [MT Scale] Received response: b'I15 A 224\\r\\n'\n", - "2026-03-30 13:12:17,201 - pylabrobot - IO - [MT Scale] Sent command: DAT\n", - "2026-03-30 13:12:17,202 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'DAT\\r\\n'\n" + "2026-03-30 13:22:11,764 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I11 A \"WXS205SDU\"\\r\\n'\n", + "2026-03-30 13:22:11,764 - pylabrobot - IO - [MT Scale] Received response: b'I11 A \"WXS205SDU\"\\r\\n'\n", + "2026-03-30 13:22:11,765 - pylabrobot - IO - [MT Scale] Sent command: I15\n", + "2026-03-30 13:22:11,767 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I15\\r\\n'\n", + "2026-03-30 13:22:11,796 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I15 A 234\\r\\n'\n", + "2026-03-30 13:22:11,797 - pylabrobot - IO - [MT Scale] Received response: b'I15 A 234\\r\\n'\n", + "2026-03-30 13:22:11,800 - pylabrobot - IO - [MT Scale] Sent command: DAT\n", + "2026-03-30 13:22:11,803 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'DAT\\r\\n'\n", + "2026-03-30 13:22:11,843 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'DAT A 04 01 2000\\r\\n'\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ - "Uptime: 224d 0h 0m 0s\n" + "Model designation: WXS205SDU\n", + "Uptime: 234d 0h 0m 0s\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 13:12:17,244 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'DAT A 04 01 2000\\r\\n'\n", - "2026-03-30 13:12:17,245 - pylabrobot - IO - [MT Scale] Received response: b'DAT A 04 01 2000\\r\\n'\n", - "2026-03-30 13:12:17,247 - pylabrobot - IO - [MT Scale] Sent command: TIM\n", - "2026-03-30 13:12:17,248 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'TIM\\r\\n'\n", - "2026-03-30 13:12:17,276 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'TIM A 20 17 43\\r\\n'\n", - "2026-03-30 13:12:17,277 - pylabrobot - IO - [MT Scale] Received response: b'TIM A 20 17 43\\r\\n'\n", - "2026-03-30 13:12:17,278 - pylabrobot - IO - [MT Scale] Sent command: I14 0\n", - "2026-03-30 13:12:17,279 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I14 0\\r\\n'\n", - "2026-03-30 13:12:17,324 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I14 A 0 1 \"Bridge\"\\r\\n'\n", - "2026-03-30 13:12:17,324 - pylabrobot - IO - [MT Scale] Received response: b'I14 A 0 1 \"Bridge\"\\r\\n'\n", - "2026-03-30 13:12:17,325 - pylabrobot - IO - [MT Scale] Sent command: I14 1\n", - "2026-03-30 13:12:17,326 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I14 1\\r\\n'\n", - "2026-03-30 13:12:17,372 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I14 A 1 1 \"WXS205SDU\"\\r\\n'\n", - "2026-03-30 13:12:17,373 - pylabrobot - IO - [MT Scale] Received response: b'I14 A 1 1 \"WXS205SDU\"\\r\\n'\n", - "2026-03-30 13:12:17,373 - pylabrobot - IO - [MT Scale] Sent command: I14 2\n", - "2026-03-30 13:12:17,374 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I14 2\\r\\n'\n" + "2026-03-30 13:22:11,844 - pylabrobot - IO - [MT Scale] Received response: b'DAT A 04 01 2000\\r\\n'\n", + "2026-03-30 13:22:11,846 - pylabrobot - IO - [MT Scale] Sent command: TIM\n", + "2026-03-30 13:22:11,847 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'TIM\\r\\n'\n", + "2026-03-30 13:22:11,876 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'TIM A 20 27 38\\r\\n'\n", + "2026-03-30 13:22:11,876 - pylabrobot - IO - [MT Scale] Received response: b'TIM A 20 27 38\\r\\n'\n", + "2026-03-30 13:22:11,877 - pylabrobot - IO - [MT Scale] Sent command: I14 0\n", + "2026-03-30 13:22:11,879 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I14 0\\r\\n'\n", + "2026-03-30 13:22:11,924 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I14 A 0 1 \"Bridge\"\\r\\n'\n", + "2026-03-30 13:22:11,924 - pylabrobot - IO - [MT Scale] Received response: b'I14 A 0 1 \"Bridge\"\\r\\n'\n", + "2026-03-30 13:22:11,925 - pylabrobot - IO - [MT Scale] Sent command: I14 1\n", + "2026-03-30 13:22:11,926 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I14 1\\r\\n'\n" ] }, { @@ -683,25 +679,29 @@ "\n", "Device info (I14):\n", " Category 0 (Instrument configuration):\n", - " I14 A 0 1 Bridge\n", - " Category 1 (Instrument descriptions):\n", - " I14 A 1 1 WXS205SDU\n" + " I14 A 0 1 Bridge\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 13:12:17,420 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I14 A 2 1 \"11671158C\"\\r\\n'\n", - "2026-03-30 13:12:17,421 - pylabrobot - IO - [MT Scale] Received response: b'I14 A 2 1 \"11671158C\"\\r\\n'\n", - "2026-03-30 13:12:17,421 - pylabrobot - IO - [MT Scale] Sent command: I14 3\n", - "2026-03-30 13:12:17,422 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I14 3\\r\\n'\n" + "2026-03-30 13:22:11,972 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I14 A 1 1 \"WXS205SDU\"\\r\\n'\n", + "2026-03-30 13:22:11,972 - pylabrobot - IO - [MT Scale] Received response: b'I14 A 1 1 \"WXS205SDU\"\\r\\n'\n", + "2026-03-30 13:22:11,973 - pylabrobot - IO - [MT Scale] Sent command: I14 2\n", + "2026-03-30 13:22:11,974 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I14 2\\r\\n'\n", + "2026-03-30 13:22:12,020 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I14 A 2 1 \"11671158C\"\\r\\n'\n", + "2026-03-30 13:22:12,020 - pylabrobot - IO - [MT Scale] Received response: b'I14 A 2 1 \"11671158C\"\\r\\n'\n", + "2026-03-30 13:22:12,021 - pylabrobot - IO - [MT Scale] Sent command: I14 3\n", + "2026-03-30 13:22:12,022 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I14 3\\r\\n'\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ + " Category 1 (Instrument descriptions):\n", + " I14 A 1 1 WXS205SDU\n", " Category 2 (SW identification numbers):\n", " I14 A 2 1 11671158C\n" ] @@ -710,16 +710,16 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 13:12:17,468 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I14 A 3 1 \"1.10\"\\r\\n'\n", - "2026-03-30 13:12:17,468 - pylabrobot - IO - [MT Scale] Received response: b'I14 A 3 1 \"1.10\"\\r\\n'\n", - "2026-03-30 13:12:17,469 - pylabrobot - IO - [MT Scale] Sent command: I14 4\n", - "2026-03-30 13:12:17,470 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I14 4\\r\\n'\n", - "2026-03-30 13:12:17,516 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I14 A 4 1 \"B207696838\"\\r\\n'\n", - "2026-03-30 13:12:17,517 - pylabrobot - IO - [MT Scale] Received response: b'I14 A 4 1 \"B207696838\"\\r\\n'\n", - "2026-03-30 13:12:17,517 - pylabrobot - IO - [MT Scale] Sent command: I14 5\n", - "2026-03-30 13:12:17,518 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I14 5\\r\\n'\n", - "2026-03-30 13:12:17,564 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I14 A 5 1 \"18.6.4.1361.772\"\\r\\n'\n", - "2026-03-30 13:12:17,565 - pylabrobot - IO - [MT Scale] Received response: b'I14 A 5 1 \"18.6.4.1361.772\"\\r\\n'\n" + "2026-03-30 13:22:12,068 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I14 A 3 1 \"1.10\"\\r\\n'\n", + "2026-03-30 13:22:12,068 - pylabrobot - IO - [MT Scale] Received response: b'I14 A 3 1 \"1.10\"\\r\\n'\n", + "2026-03-30 13:22:12,069 - pylabrobot - IO - [MT Scale] Sent command: I14 4\n", + "2026-03-30 13:22:12,071 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I14 4\\r\\n'\n", + "2026-03-30 13:22:12,116 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I14 A 4 1 \"B207696838\"\\r\\n'\n", + "2026-03-30 13:22:12,116 - pylabrobot - IO - [MT Scale] Received response: b'I14 A 4 1 \"B207696838\"\\r\\n'\n", + "2026-03-30 13:22:12,117 - pylabrobot - IO - [MT Scale] Sent command: I14 5\n", + "2026-03-30 13:22:12,118 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I14 5\\r\\n'\n", + "2026-03-30 13:22:12,166 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I14 A 5 1 \"18.6.4.1361.772\"\\r\\n'\n", + "2026-03-30 13:22:12,172 - pylabrobot - IO - [MT Scale] Received response: b'I14 A 5 1 \"18.6.4.1361.772\"\\r\\n'\n" ] }, { @@ -809,14 +809,130 @@ { "cell_type": "markdown", "metadata": {}, - "source": "---\n## 2. Core Protocol Validation\n\nThese Level 0/1 commands have been validated across multiple hardware runs.\nThis cell consolidates them into a single pass/fail check." + "source": [ + "---\n", + "## 2. Core Protocol Validation\n", + "\n", + "These Level 0/1 commands have been validated across multiple hardware runs.\n", + "This cell consolidates them into a single pass/fail check." + ] }, { "cell_type": "code", + "execution_count": 7, "metadata": {}, - "source": "# @ - Cancel (returns serial number)\nsn = await backend.cancel()\nassert sn == backend.serial_number, f\"cancel() returned {sn}, expected {backend.serial_number}\"\n\n# I4 - Serial number\nsn2 = await backend.request_serial_number()\nassert sn2 == sn\n\n# I2 - Device type and capacity\ndt = await backend.request_device_type()\nassert len(dt) > 0\ncap = await backend.request_capacity()\nassert cap > 0\n\n# S - Stable weight\nw_stable = await backend.read_stable_weight()\nassert isinstance(w_stable, float)\n\n# SI - Weight immediately\nw_imm = await backend.read_weight_value_immediately()\nassert isinstance(w_imm, float)\n\n# Z - Zero (stable) then read\nawait scale.zero(timeout=\"stable\")\nw_after_zero = await backend.read_weight_value_immediately()\nassert abs(w_after_zero) < 0.001, f\"Expected ~0 after zero, got {w_after_zero}\"\n\n# ZI - Zero immediately then read\nawait scale.zero(timeout=0)\nw_after_zi = await backend.read_weight_value_immediately()\nassert abs(w_after_zi) < 0.01\n\n# TA - Request tare weight\ntare = await scale.request_tare_weight()\nassert isinstance(tare, float)\n\n# TAC - Clear tare\nawait backend.clear_tare()\ntare_after = await scale.request_tare_weight()\nassert abs(tare_after) < 0.001\n\nprint(\"PASS: all core Level 0/1 commands validated\")", - "outputs": [], - "execution_count": null + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2026-03-30 13:22:12,193 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] reset_input_buffer\n", + "2026-03-30 13:22:12,196 - pylabrobot - IO - [MT Scale] Sent command: @\n", + "2026-03-30 13:22:12,207 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'@\\r\\n'\n", + "2026-03-30 13:22:12,262 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I4 A \"B207696838\"\\r\\n'\n", + "2026-03-30 13:22:12,264 - pylabrobot - IO - [MT Scale] Received response: b'I4 A \"B207696838\"\\r\\n'\n", + "2026-03-30 13:22:12,267 - pylabrobot - IO - [MT Scale] Sent command: I4\n", + "2026-03-30 13:22:12,273 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I4\\r\\n'\n", + "2026-03-30 13:22:12,308 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I4 A \"B207696838\"\\r\\n'\n", + "2026-03-30 13:22:12,312 - pylabrobot - IO - [MT Scale] Received response: b'I4 A \"B207696838\"\\r\\n'\n", + "2026-03-30 13:22:12,314 - pylabrobot - IO - [MT Scale] Sent command: I2\n", + "2026-03-30 13:22:12,315 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I2\\r\\n'\n", + "2026-03-30 13:22:12,371 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", + "2026-03-30 13:22:12,372 - pylabrobot - IO - [MT Scale] Received response: b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", + "2026-03-30 13:22:12,374 - pylabrobot - IO - [MT Scale] Sent command: I2\n", + "2026-03-30 13:22:12,377 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I2\\r\\n'\n", + "2026-03-30 13:22:12,435 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", + "2026-03-30 13:22:12,437 - pylabrobot - IO - [MT Scale] Received response: b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", + "2026-03-30 13:22:12,440 - pylabrobot - IO - [MT Scale] Sent command: S\n", + "2026-03-30 13:22:12,446 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", + "2026-03-30 13:22:12,771 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00005 g\\r\\n'\n", + "2026-03-30 13:22:12,772 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00005 g\\r\\n'\n", + "2026-03-30 13:22:12,773 - pylabrobot - IO - [MT Scale] Sent command: SI\n", + "2026-03-30 13:22:12,777 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", + "2026-03-30 13:22:12,819 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00005 g\\r\\n'\n", + "2026-03-30 13:22:12,820 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00005 g\\r\\n'\n", + "2026-03-30 13:22:12,821 - pylabrobot - IO - [MT Scale] Sent command: Z\n", + "2026-03-30 13:22:12,823 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'Z\\r\\n'\n", + "2026-03-30 13:22:13,155 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'Z A\\r\\n'\n", + "2026-03-30 13:22:13,155 - pylabrobot - IO - [MT Scale] Received response: b'Z A\\r\\n'\n", + "2026-03-30 13:22:13,156 - pylabrobot - IO - [MT Scale] Sent command: SI\n", + "2026-03-30 13:22:13,157 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", + "2026-03-30 13:22:13,186 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 13:22:13,187 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 13:22:13,188 - pylabrobot - IO - [MT Scale] Sent command: ZI\n", + "2026-03-30 13:22:13,190 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'ZI\\r\\n'\n", + "2026-03-30 13:22:13,218 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'ZI S\\r\\n'\n", + "2026-03-30 13:22:13,219 - pylabrobot - IO - [MT Scale] Received response: b'ZI S\\r\\n'\n", + "2026-03-30 13:22:13,219 - pylabrobot - IO - [MT Scale] Sent command: SI\n", + "2026-03-30 13:22:13,221 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", + "2026-03-30 13:22:13,251 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 13:22:13,251 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 13:22:13,252 - pylabrobot - IO - [MT Scale] Sent command: TA\n", + "2026-03-30 13:22:13,253 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'TA\\r\\n'\n", + "2026-03-30 13:22:13,363 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'TA A 0.00000 g\\r\\n'\n", + "2026-03-30 13:22:13,363 - pylabrobot - IO - [MT Scale] Received response: b'TA A 0.00000 g\\r\\n'\n", + "2026-03-30 13:22:13,364 - pylabrobot - IO - [MT Scale] Sent command: TAC\n", + "2026-03-30 13:22:13,366 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'TAC\\r\\n'\n", + "2026-03-30 13:22:13,394 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'TAC A\\r\\n'\n", + "2026-03-30 13:22:13,395 - pylabrobot - IO - [MT Scale] Received response: b'TAC A\\r\\n'\n", + "2026-03-30 13:22:13,396 - pylabrobot - IO - [MT Scale] Sent command: TA\n", + "2026-03-30 13:22:13,397 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'TA\\r\\n'\n", + "2026-03-30 13:22:13,474 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'TA A 0.00000 g\\r\\n'\n", + "2026-03-30 13:22:13,475 - pylabrobot - IO - [MT Scale] Received response: b'TA A 0.00000 g\\r\\n'\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "PASS: all core Level 0/1 commands validated\n" + ] + } + ], + "source": [ + "# @ - Cancel (returns serial number)\n", + "sn = await backend.cancel()\n", + "assert sn == backend.serial_number, f\"cancel() returned {sn}, expected {backend.serial_number}\"\n", + "\n", + "# I4 - Serial number\n", + "sn2 = await backend.request_serial_number()\n", + "assert sn2 == sn\n", + "\n", + "# I2 - Device type and capacity\n", + "dt = await backend.request_device_type()\n", + "assert len(dt) > 0\n", + "cap = await backend.request_capacity()\n", + "assert cap > 0\n", + "\n", + "# S - Stable weight\n", + "w_stable = await backend.read_stable_weight()\n", + "assert isinstance(w_stable, float)\n", + "\n", + "# SI - Weight immediately\n", + "w_imm = await backend.read_weight_value_immediately()\n", + "assert isinstance(w_imm, float)\n", + "\n", + "# Z - Zero (stable) then read\n", + "await scale.zero(timeout=\"stable\")\n", + "w_after_zero = await backend.read_weight_value_immediately()\n", + "assert abs(w_after_zero) < 0.001, f\"Expected ~0 after zero, got {w_after_zero}\"\n", + "\n", + "# ZI - Zero immediately then read\n", + "await scale.zero(timeout=0)\n", + "w_after_zi = await backend.read_weight_value_immediately()\n", + "assert abs(w_after_zi) < 0.01\n", + "\n", + "# TA - Request tare weight\n", + "tare = await scale.request_tare_weight()\n", + "assert isinstance(tare, float)\n", + "\n", + "# TAC - Clear tare\n", + "await backend.clear_tare()\n", + "tare_after = await scale.request_tare_weight()\n", + "assert abs(tare_after) < 0.001\n", + "\n", + "print(\"PASS: all core Level 0/1 commands validated\")" + ] }, { "cell_type": "markdown", @@ -837,7 +953,7 @@ }, { "cell_type": "code", - "execution_count": 15, + "execution_count": 8, "metadata": {}, "outputs": [ { @@ -851,18 +967,18 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 13:12:23,026 - pylabrobot - IO - [MT Scale] Sent command: Z\n", - "2026-03-30 13:12:23,028 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'Z\\r\\n'\n", - "2026-03-30 13:12:23,414 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'Z A\\r\\n'\n", - "2026-03-30 13:12:23,415 - pylabrobot - IO - [MT Scale] Received response: b'Z A\\r\\n'\n", - "2026-03-30 13:12:23,416 - pylabrobot - IO - [MT Scale] Sent command: T\n", - "2026-03-30 13:12:23,417 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'T\\r\\n'\n", - "2026-03-30 13:12:23,830 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'T S 0.00000 g\\r\\n'\n", - "2026-03-30 13:12:23,831 - pylabrobot - IO - [MT Scale] Received response: b'T S 0.00000 g\\r\\n'\n", - "2026-03-30 13:12:23,831 - pylabrobot - IO - [MT Scale] Sent command: TA\n", - "2026-03-30 13:12:23,833 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'TA\\r\\n'\n", - "2026-03-30 13:12:23,926 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'TA A 0.00000 g\\r\\n'\n", - "2026-03-30 13:12:23,927 - pylabrobot - IO - [MT Scale] Received response: b'TA A 0.00000 g\\r\\n'\n" + "2026-03-30 13:22:27,132 - pylabrobot - IO - [MT Scale] Sent command: Z\n", + "2026-03-30 13:22:27,134 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'Z\\r\\n'\n", + "2026-03-30 13:22:27,509 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'Z A\\r\\n'\n", + "2026-03-30 13:22:27,510 - pylabrobot - IO - [MT Scale] Received response: b'Z A\\r\\n'\n", + "2026-03-30 13:22:27,511 - pylabrobot - IO - [MT Scale] Sent command: T\n", + "2026-03-30 13:22:27,512 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'T\\r\\n'\n", + "2026-03-30 13:22:27,925 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'T S 0.00000 g\\r\\n'\n", + "2026-03-30 13:22:27,925 - pylabrobot - IO - [MT Scale] Received response: b'T S 0.00000 g\\r\\n'\n", + "2026-03-30 13:22:27,926 - pylabrobot - IO - [MT Scale] Sent command: TA\n", + "2026-03-30 13:22:27,927 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'TA\\r\\n'\n", + "2026-03-30 13:22:28,021 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'TA A 0.00000 g\\r\\n'\n", + "2026-03-30 13:22:28,022 - pylabrobot - IO - [MT Scale] Received response: b'TA A 0.00000 g\\r\\n'\n" ] }, { @@ -879,7 +995,7 @@ "traceback": [ "\u001b[31m---------------------------------------------------------------------------\u001b[39m", "\u001b[31mAssertionError\u001b[39m Traceback (most recent call last)", - "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[15]\u001b[39m\u001b[32m, line 6\u001b[39m\n\u001b[32m 4\u001b[39m tare = \u001b[38;5;28;01mawait\u001b[39;00m scale.request_tare_weight()\n\u001b[32m 5\u001b[39m \u001b[38;5;28mprint\u001b[39m(\u001b[33mf\u001b[39m\u001b[33m\"\u001b[39m\u001b[33mTare weight: \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mtare\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m g\u001b[39m\u001b[33m\"\u001b[39m)\n\u001b[32m----> \u001b[39m\u001b[32m6\u001b[39m \u001b[38;5;28;01massert\u001b[39;00m tare > \u001b[32m0\u001b[39m, \u001b[33mf\u001b[39m\u001b[33m\"\u001b[39m\u001b[33mExpected positive tare, got \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mtare\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m\"\u001b[39m\n\u001b[32m 7\u001b[39m \u001b[38;5;28mprint\u001b[39m(\u001b[33m\"\u001b[39m\u001b[33mPASS: tare stores container weight\u001b[39m\u001b[33m\"\u001b[39m)\n", + "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[8]\u001b[39m\u001b[32m, line 6\u001b[39m\n\u001b[32m 4\u001b[39m tare = \u001b[38;5;28;01mawait\u001b[39;00m scale.request_tare_weight()\n\u001b[32m 5\u001b[39m \u001b[38;5;28mprint\u001b[39m(\u001b[33mf\u001b[39m\u001b[33m\"\u001b[39m\u001b[33mTare weight: \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mtare\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m g\u001b[39m\u001b[33m\"\u001b[39m)\n\u001b[32m----> \u001b[39m\u001b[32m6\u001b[39m \u001b[38;5;28;01massert\u001b[39;00m tare > \u001b[32m0\u001b[39m, \u001b[33mf\u001b[39m\u001b[33m\"\u001b[39m\u001b[33mExpected positive tare, got \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mtare\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m\"\u001b[39m\n\u001b[32m 7\u001b[39m \u001b[38;5;28mprint\u001b[39m(\u001b[33m\"\u001b[39m\u001b[33mPASS: tare stores container weight\u001b[39m\u001b[33m\"\u001b[39m)\n", "\u001b[31mAssertionError\u001b[39m: Expected positive tare, got 0.0" ] } @@ -903,17 +1019,17 @@ }, { "cell_type": "code", - "execution_count": 16, + "execution_count": 9, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 13:12:26,003 - pylabrobot - IO - [MT Scale] Sent command: TA\n", - "2026-03-30 13:12:26,006 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'TA\\r\\n'\n", - "2026-03-30 13:12:26,084 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'TA A 0.00000 g\\r\\n'\n", - "2026-03-30 13:12:26,086 - pylabrobot - IO - [MT Scale] Received response: b'TA A 0.00000 g\\r\\n'\n" + "2026-03-30 13:22:31,147 - pylabrobot - IO - [MT Scale] Sent command: TA\n", + "2026-03-30 13:22:31,151 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'TA\\r\\n'\n", + "2026-03-30 13:22:31,251 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'TA A 0.00000 g\\r\\n'\n", + "2026-03-30 13:22:31,252 - pylabrobot - IO - [MT Scale] Received response: b'TA A 0.00000 g\\r\\n'\n" ] }, { @@ -941,21 +1057,21 @@ }, { "cell_type": "code", - "execution_count": 17, + "execution_count": 10, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 13:12:26,799 - pylabrobot - IO - [MT Scale] Sent command: TAC\n", - "2026-03-30 13:12:26,801 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'TAC\\r\\n'\n", - "2026-03-30 13:12:26,836 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'TAC A\\r\\n'\n", - "2026-03-30 13:12:26,837 - pylabrobot - IO - [MT Scale] Received response: b'TAC A\\r\\n'\n", - "2026-03-30 13:12:26,839 - pylabrobot - IO - [MT Scale] Sent command: TA\n", - "2026-03-30 13:12:26,841 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'TA\\r\\n'\n", - "2026-03-30 13:12:26,964 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'TA A 0.00000 g\\r\\n'\n", - "2026-03-30 13:12:26,965 - pylabrobot - IO - [MT Scale] Received response: b'TA A 0.00000 g\\r\\n'\n" + "2026-03-30 13:22:32,399 - pylabrobot - IO - [MT Scale] Sent command: TAC\n", + "2026-03-30 13:22:32,401 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'TAC\\r\\n'\n", + "2026-03-30 13:22:32,434 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'TAC A\\r\\n'\n", + "2026-03-30 13:22:32,435 - pylabrobot - IO - [MT Scale] Received response: b'TAC A\\r\\n'\n", + "2026-03-30 13:22:32,436 - pylabrobot - IO - [MT Scale] Sent command: TA\n", + "2026-03-30 13:22:32,440 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'TA\\r\\n'\n", + "2026-03-30 13:22:32,532 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'TA A 0.00000 g\\r\\n'\n", + "2026-03-30 13:22:32,533 - pylabrobot - IO - [MT Scale] Received response: b'TA A 0.00000 g\\r\\n'\n" ] }, { @@ -992,17 +1108,17 @@ }, { "cell_type": "code", - "execution_count": 22, + "execution_count": 11, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 13:12:34,916 - pylabrobot - IO - [MT Scale] Sent command: M21 0 0\n", - "2026-03-30 13:12:34,918 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'M21 0 0\\r\\n'\n", - "2026-03-30 13:12:34,957 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M21 A\\r\\n'\n", - "2026-03-30 13:12:34,958 - pylabrobot - IO - [MT Scale] Received response: b'M21 A\\r\\n'\n" + "2026-03-30 13:22:34,042 - pylabrobot - IO - [MT Scale] Sent command: M21 0 0\n", + "2026-03-30 13:22:34,044 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'M21 0 0\\r\\n'\n", + "2026-03-30 13:22:34,082 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M21 A\\r\\n'\n", + "2026-03-30 13:22:34,085 - pylabrobot - IO - [MT Scale] Received response: b'M21 A\\r\\n'\n" ] }, { @@ -1030,7 +1146,7 @@ }, { "cell_type": "code", - "execution_count": 23, + "execution_count": 12, "metadata": {}, "outputs": [ { @@ -1061,19 +1177,19 @@ }, { "cell_type": "code", - "execution_count": 24, + "execution_count": 13, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 13:12:38,030 - pylabrobot - IO - [MT Scale] Sent command: M28\n", - "2026-03-30 13:12:38,034 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'M28\\r\\n'\n", - "2026-03-30 13:12:38,072 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M28 B 1 20.1\\r\\n'\n", - "2026-03-30 13:12:38,073 - pylabrobot - IO - [MT Scale] Received response: b'M28 B 1 20.1\\r\\n'\n", - "2026-03-30 13:12:38,089 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M28 A 2 19.6\\r\\n'\n", - "2026-03-30 13:12:38,094 - pylabrobot - IO - [MT Scale] Received response: b'M28 A 2 19.6\\r\\n'\n" + "2026-03-30 13:22:37,302 - pylabrobot - IO - [MT Scale] Sent command: M28\n", + "2026-03-30 13:22:37,305 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'M28\\r\\n'\n", + "2026-03-30 13:22:37,341 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M28 B 1 20.1\\r\\n'\n", + "2026-03-30 13:22:37,342 - pylabrobot - IO - [MT Scale] Received response: b'M28 B 1 20.1\\r\\n'\n", + "2026-03-30 13:22:37,359 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M28 A 2 19.6\\r\\n'\n", + "2026-03-30 13:22:37,360 - pylabrobot - IO - [MT Scale] Received response: b'M28 A 2 19.6\\r\\n'\n" ] }, { @@ -1106,27 +1222,33 @@ }, { "cell_type": "code", - "execution_count": 25, + "execution_count": 14, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 13:12:42,172 - pylabrobot - IO - [MT Scale] Sent command: M01\n", - "2026-03-30 13:12:42,174 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'M01\\r\\n'\n", - "2026-03-30 13:12:42,198 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M01 A 0\\r\\n'\n", - "2026-03-30 13:12:42,199 - pylabrobot - IO - [MT Scale] Received response: b'M01 A 0\\r\\n'\n", - "2026-03-30 13:12:42,201 - pylabrobot - IO - [MT Scale] Sent command: M02\n", - "2026-03-30 13:12:42,202 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'M02\\r\\n'\n", - "2026-03-30 13:12:42,230 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M02 A 2\\r\\n'\n", - "2026-03-30 13:12:42,230 - pylabrobot - IO - [MT Scale] Received response: b'M02 A 2\\r\\n'\n", - "2026-03-30 13:12:42,231 - pylabrobot - IO - [MT Scale] Sent command: M03\n", - "2026-03-30 13:12:42,232 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'M03\\r\\n'\n", - "2026-03-30 13:12:42,262 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M03 A 0\\r\\n'\n", - "2026-03-30 13:12:42,263 - pylabrobot - IO - [MT Scale] Received response: b'M03 A 0\\r\\n'\n", - "2026-03-30 13:12:42,265 - pylabrobot - IO - [MT Scale] Sent command: M27\n", - "2026-03-30 13:12:42,267 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'M27\\r\\n'\n" + "2026-03-30 13:22:39,846 - pylabrobot - IO - [MT Scale] Sent command: M01\n", + "2026-03-30 13:22:39,848 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'M01\\r\\n'\n", + "2026-03-30 13:22:39,883 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M01 A 0\\r\\n'\n", + "2026-03-30 13:22:39,883 - pylabrobot - IO - [MT Scale] Received response: b'M01 A 0\\r\\n'\n", + "2026-03-30 13:22:39,885 - pylabrobot - IO - [MT Scale] Sent command: M02\n", + "2026-03-30 13:22:39,887 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'M02\\r\\n'\n", + "2026-03-30 13:22:39,915 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M02 A 2\\r\\n'\n", + "2026-03-30 13:22:39,917 - pylabrobot - IO - [MT Scale] Received response: b'M02 A 2\\r\\n'\n", + "2026-03-30 13:22:39,918 - pylabrobot - IO - [MT Scale] Sent command: M03\n", + "2026-03-30 13:22:39,920 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'M03\\r\\n'\n", + "2026-03-30 13:22:39,947 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M03 A 0\\r\\n'\n", + "2026-03-30 13:22:39,949 - pylabrobot - IO - [MT Scale] Received response: b'M03 A 0\\r\\n'\n", + "2026-03-30 13:22:39,951 - pylabrobot - IO - [MT Scale] Sent command: M27\n", + "2026-03-30 13:22:39,953 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'M27\\r\\n'\n", + "2026-03-30 13:22:40,013 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 1 13 05 2020 17 17 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:40,018 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 1 13 05 2020 17 17 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:40,043 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 2 02 12 2019 20 02 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:40,044 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 2 02 12 2019 20 02 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:40,075 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 3 11 10 2019 17 05 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:40,076 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 3 11 10 2019 17 05 0 \"\"\\r\\n'\n" ] }, { @@ -1142,122 +1264,118 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 13:12:43,061 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 1 13 05 2020 17 17 0 \"\"\\r\\n'\n", - "2026-03-30 13:12:43,062 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 1 13 05 2020 17 17 0 \"\"\\r\\n'\n", - "2026-03-30 13:12:43,094 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 2 02 12 2019 20 02 0 \"\"\\r\\n'\n", - "2026-03-30 13:12:43,096 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 2 02 12 2019 20 02 0 \"\"\\r\\n'\n", - "2026-03-30 13:12:43,128 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 3 11 10 2019 17 05 0 \"\"\\r\\n'\n", - "2026-03-30 13:12:43,130 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 3 11 10 2019 17 05 0 \"\"\\r\\n'\n", - "2026-03-30 13:12:43,158 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 4 11 10 2019 17 01 0 \"\"\\r\\n'\n", - "2026-03-30 13:12:43,159 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 4 11 10 2019 17 01 0 \"\"\\r\\n'\n", - "2026-03-30 13:12:43,190 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 5 14 03 2019 20 22 0 \"\"\\r\\n'\n", - "2026-03-30 13:12:43,193 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 5 14 03 2019 20 22 0 \"\"\\r\\n'\n", - "2026-03-30 13:12:43,222 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 6 14 03 2019 20 18 0 \"\"\\r\\n'\n", - "2026-03-30 13:12:43,223 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 6 14 03 2019 20 18 0 \"\"\\r\\n'\n", - "2026-03-30 13:12:43,253 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 7 17 10 2018 17 38 0 \"\"\\r\\n'\n", - "2026-03-30 13:12:43,255 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 7 17 10 2018 17 38 0 \"\"\\r\\n'\n", - "2026-03-30 13:12:43,286 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 8 17 10 2018 17 37 0 \"\"\\r\\n'\n", - "2026-03-30 13:12:43,288 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 8 17 10 2018 17 37 0 \"\"\\r\\n'\n", - "2026-03-30 13:12:43,318 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 9 17 10 2018 17 35 0 \"\"\\r\\n'\n", - "2026-03-30 13:12:43,319 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 9 17 10 2018 17 35 0 \"\"\\r\\n'\n", - "2026-03-30 13:12:43,349 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 10 20 09 2018 21 23 0 \"\"\\r\\n'\n", - "2026-03-30 13:12:43,350 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 10 20 09 2018 21 23 0 \"\"\\r\\n'\n", - "2026-03-30 13:12:43,381 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 11 15 03 2018 23 51 0 \"\"\\r\\n'\n", - "2026-03-30 13:12:43,382 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 11 15 03 2018 23 51 0 \"\"\\r\\n'\n", - "2026-03-30 13:12:43,429 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 12 16 12 2017 00 20 0 \"\"\\r\\n'\n", - "2026-03-30 13:12:43,431 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 12 16 12 2017 00 20 0 \"\"\\r\\n'\n", - "2026-03-30 13:12:43,461 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 13 16 12 2017 00 18 0 \"\"\\r\\n'\n", - "2026-03-30 13:12:43,462 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 13 16 12 2017 00 18 0 \"\"\\r\\n'\n", - "2026-03-30 13:12:43,493 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 14 18 10 2017 12 06 0 \"\"\\r\\n'\n", - "2026-03-30 13:12:43,494 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 14 18 10 2017 12 06 0 \"\"\\r\\n'\n", - "2026-03-30 13:12:43,526 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 15 18 10 2017 11 58 0 \"\"\\r\\n'\n", - "2026-03-30 13:12:43,526 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 15 18 10 2017 11 58 0 \"\"\\r\\n'\n", - "2026-03-30 13:12:43,557 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 16 05 09 2017 22 40 0 \"\"\\r\\n'\n", - "2026-03-30 13:12:43,558 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 16 05 09 2017 22 40 0 \"\"\\r\\n'\n", - "2026-03-30 13:12:43,589 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 17 21 06 2017 18 39 0 \"\"\\r\\n'\n", - "2026-03-30 13:12:43,590 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 17 21 06 2017 18 39 0 \"\"\\r\\n'\n", - "2026-03-30 13:12:43,621 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 18 30 03 2017 19 24 0 \"\"\\r\\n'\n", - "2026-03-30 13:12:43,628 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 18 30 03 2017 19 24 0 \"\"\\r\\n'\n", - "2026-03-30 13:12:43,655 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 19 09 03 2017 23 21 0 \"\"\\r\\n'\n", - "2026-03-30 13:12:43,656 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 19 09 03 2017 23 21 0 \"\"\\r\\n'\n", - "2026-03-30 13:12:43,685 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 20 09 03 2017 23 19 0 \"\"\\r\\n'\n", - "2026-03-30 13:12:43,689 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 20 09 03 2017 23 19 0 \"\"\\r\\n'\n", - "2026-03-30 13:12:43,717 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 21 20 12 2016 21 55 0 \"\"\\r\\n'\n", - "2026-03-30 13:12:43,718 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 21 20 12 2016 21 55 0 \"\"\\r\\n'\n", - "2026-03-30 13:12:43,753 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 22 19 10 2016 17 36 0 \"\"\\r\\n'\n", - "2026-03-30 13:12:43,754 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 22 19 10 2016 17 36 0 \"\"\\r\\n'\n", - "2026-03-30 13:12:43,781 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 23 19 10 2016 17 33 0 \"\"\\r\\n'\n", - "2026-03-30 13:12:43,790 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 23 19 10 2016 17 33 0 \"\"\\r\\n'\n", - "2026-03-30 13:12:43,829 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 24 18 10 2016 21 00 0 \"\"\\r\\n'\n", - "2026-03-30 13:12:43,831 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 24 18 10 2016 21 00 0 \"\"\\r\\n'\n", - "2026-03-30 13:12:43,861 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 25 18 10 2016 18 47 0 \"\"\\r\\n'\n", - "2026-03-30 13:12:43,863 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 25 18 10 2016 18 47 0 \"\"\\r\\n'\n", - "2026-03-30 13:12:43,893 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 26 18 10 2016 15 33 0 \"\"\\r\\n'\n", - "2026-03-30 13:12:43,895 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 26 18 10 2016 15 33 0 \"\"\\r\\n'\n", - "2026-03-30 13:12:43,925 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 27 18 10 2016 14 32 0 \"\"\\r\\n'\n", - "2026-03-30 13:12:43,926 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 27 18 10 2016 14 32 0 \"\"\\r\\n'\n", - "2026-03-30 13:12:43,957 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 28 18 10 2016 14 28 0 \"\"\\r\\n'\n", - "2026-03-30 13:12:43,958 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 28 18 10 2016 14 28 0 \"\"\\r\\n'\n", - "2026-03-30 13:12:43,989 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 29 18 10 2016 13 41 0 \"\"\\r\\n'\n", - "2026-03-30 13:12:43,990 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 29 18 10 2016 13 41 0 \"\"\\r\\n'\n", - "2026-03-30 13:12:44,025 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 30 21 09 2016 15 15 0 \"\"\\r\\n'\n", - "2026-03-30 13:12:44,027 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 30 21 09 2016 15 15 0 \"\"\\r\\n'\n", - "2026-03-30 13:12:44,053 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 31 04 03 2016 22 28 0 \"\"\\r\\n'\n", - "2026-03-30 13:12:44,055 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 31 04 03 2016 22 28 0 \"\"\\r\\n'\n", - "2026-03-30 13:12:44,089 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 32 01 10 2015 19 06 0 \"\"\\r\\n'\n", - "2026-03-30 13:12:44,090 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 32 01 10 2015 19 06 0 \"\"\\r\\n'\n", - "2026-03-30 13:12:44,117 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 33 01 10 2015 18 56 0 \"\"\\r\\n'\n", - "2026-03-30 13:12:44,121 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 33 01 10 2015 18 56 0 \"\"\\r\\n'\n", - "2026-03-30 13:12:44,152 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 34 03 09 2015 22 11 0 \"\"\\r\\n'\n", - "2026-03-30 13:12:44,156 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 34 03 09 2015 22 11 0 \"\"\\r\\n'\n", - "2026-03-30 13:12:44,196 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 35 11 03 2015 13 20 0 \"\"\\r\\n'\n", - "2026-03-30 13:12:44,199 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 35 11 03 2015 13 20 0 \"\"\\r\\n'\n", - "2026-03-30 13:12:44,229 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 36 11 03 2015 13 18 0 \"\"\\r\\n'\n", - "2026-03-30 13:12:44,230 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 36 11 03 2015 13 18 0 \"\"\\r\\n'\n", - "2026-03-30 13:12:44,260 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 37 11 03 2015 13 15 0 \"\"\\r\\n'\n", - "2026-03-30 13:12:44,261 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 37 11 03 2015 13 15 0 \"\"\\r\\n'\n", - "2026-03-30 13:12:44,292 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 38 11 03 2015 13 13 0 \"\"\\r\\n'\n", - "2026-03-30 13:12:44,293 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 38 11 03 2015 13 13 0 \"\"\\r\\n'\n", - "2026-03-30 13:12:44,330 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 39 22 01 2015 03 17 0 \"\"\\r\\n'\n", - "2026-03-30 13:12:44,330 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 39 22 01 2015 03 17 0 \"\"\\r\\n'\n", - "2026-03-30 13:12:44,358 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 40 22 01 2015 03 15 0 \"\"\\r\\n'\n", - "2026-03-30 13:12:44,360 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 40 22 01 2015 03 15 0 \"\"\\r\\n'\n", - "2026-03-30 13:12:44,389 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 41 06 11 2014 17 08 0 \"\"\\r\\n'\n", - "2026-03-30 13:12:44,391 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 41 06 11 2014 17 08 0 \"\"\\r\\n'\n", - "2026-03-30 13:12:44,421 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 42 06 11 2014 16 22 0 \"\"\\r\\n'\n", - "2026-03-30 13:12:44,422 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 42 06 11 2014 16 22 0 \"\"\\r\\n'\n", - "2026-03-30 13:12:44,453 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 43 06 11 2014 16 20 0 \"\"\\r\\n'\n", - "2026-03-30 13:12:44,454 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 43 06 11 2014 16 20 0 \"\"\\r\\n'\n", - "2026-03-30 13:12:44,485 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 44 06 11 2014 15 57 0 \"\"\\r\\n'\n", - "2026-03-30 13:12:44,486 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 44 06 11 2014 15 57 0 \"\"\\r\\n'\n", - "2026-03-30 13:12:44,517 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 45 18 09 2014 20 23 0 \"\"\\r\\n'\n", - "2026-03-30 13:12:44,523 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 45 18 09 2014 20 23 0 \"\"\\r\\n'\n", - "2026-03-30 13:12:44,565 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 46 18 09 2014 19 54 0 \"\"\\r\\n'\n", - "2026-03-30 13:12:44,566 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 46 18 09 2014 19 54 0 \"\"\\r\\n'\n", - "2026-03-30 13:12:44,596 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 47 18 09 2014 19 44 0 \"\"\\r\\n'\n", - "2026-03-30 13:12:44,598 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 47 18 09 2014 19 44 0 \"\"\\r\\n'\n", - "2026-03-30 13:12:44,629 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 48 18 09 2014 19 35 0 \"\"\\r\\n'\n", - "2026-03-30 13:12:44,631 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 48 18 09 2014 19 35 0 \"\"\\r\\n'\n", - "2026-03-30 13:12:44,660 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 49 15 09 2014 20 08 0 \"\"\\r\\n'\n", - "2026-03-30 13:12:44,662 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 49 15 09 2014 20 08 0 \"\"\\r\\n'\n", - "2026-03-30 13:12:44,693 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 A 50 15 09 2014 19 39 0 \"\"\\r\\n'\n", - "2026-03-30 13:12:44,695 - pylabrobot - IO - [MT Scale] Received response: b'M27 A 50 15 09 2014 19 39 0 \"\"\\r\\n'\n", - "2026-03-30 13:12:44,697 - pylabrobot - IO - [MT Scale] Sent command: UPD\n", - "2026-03-30 13:12:44,700 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'UPD\\r\\n'\n", - "2026-03-30 13:12:44,740 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'UPD A 10.173\\r\\n'\n", - "2026-03-30 13:12:44,742 - pylabrobot - IO - [MT Scale] Received response: b'UPD A 10.173\\r\\n'\n", - "2026-03-30 13:12:44,743 - pylabrobot - IO - [MT Scale] Sent command: SIS\n", - "2026-03-30 13:12:44,746 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SIS\\r\\n'\n", - "2026-03-30 13:12:44,804 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'SIS A 0 \"0.00000\" 0 5 1 0 0\\r\\n'\n", - "2026-03-30 13:12:44,805 - pylabrobot - IO - [MT Scale] Received response: b'SIS A 0 \"0.00000\" 0 5 1 0 0\\r\\n'\n", - "2026-03-30 13:12:44,807 - pylabrobot - IO - [MT Scale] Sent command: LST\n", - "2026-03-30 13:12:44,812 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'LST\\r\\n'\n", - "2026-03-30 13:12:44,852 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B C0 0 0 \"\"\\r\\n'\n", - "2026-03-30 13:12:44,853 - pylabrobot - IO - [MT Scale] Received response: b'LST B C0 0 0 \"\"\\r\\n'\n", - "2026-03-30 13:12:44,868 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B FCUT 0.000\\r\\n'\n", - "2026-03-30 13:12:44,869 - pylabrobot - IO - [MT Scale] Received response: b'LST B FCUT 0.000\\r\\n'\n", - "2026-03-30 13:12:44,884 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B I10 \"\"\\r\\n'\n", - "2026-03-30 13:12:44,885 - pylabrobot - IO - [MT Scale] Received response: b'LST B I10 \"\"\\r\\n'\n" + "2026-03-30 13:22:40,106 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 4 11 10 2019 17 01 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:40,110 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 4 11 10 2019 17 01 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:40,138 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 5 14 03 2019 20 22 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:40,140 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 5 14 03 2019 20 22 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:40,171 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 6 14 03 2019 20 18 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:40,172 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 6 14 03 2019 20 18 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:40,203 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 7 17 10 2018 17 38 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:40,204 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 7 17 10 2018 17 38 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:40,235 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 8 17 10 2018 17 37 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:40,240 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 8 17 10 2018 17 37 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:40,267 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 9 17 10 2018 17 35 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:40,269 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 9 17 10 2018 17 35 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:40,298 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 10 20 09 2018 21 23 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:40,302 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 10 20 09 2018 21 23 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:40,332 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 11 15 03 2018 23 51 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:40,333 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 11 15 03 2018 23 51 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:40,364 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 12 16 12 2017 00 20 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:40,368 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 12 16 12 2017 00 20 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:40,394 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 13 16 12 2017 00 18 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:40,397 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 13 16 12 2017 00 18 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:40,428 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 14 18 10 2017 12 06 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:40,430 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 14 18 10 2017 12 06 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:40,458 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 15 18 10 2017 11 58 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:40,460 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 15 18 10 2017 11 58 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:40,491 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 16 05 09 2017 22 40 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:40,492 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 16 05 09 2017 22 40 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:40,540 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 17 21 06 2017 18 39 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:40,544 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 17 21 06 2017 18 39 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:40,572 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 18 30 03 2017 19 24 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:40,578 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 18 30 03 2017 19 24 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:40,602 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 19 09 03 2017 23 21 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:40,605 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 19 09 03 2017 23 21 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:40,636 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 20 09 03 2017 23 19 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:40,637 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 20 09 03 2017 23 19 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:40,667 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 21 20 12 2016 21 55 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:40,668 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 21 20 12 2016 21 55 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:40,700 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 22 19 10 2016 17 36 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:40,701 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 22 19 10 2016 17 36 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:40,731 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 23 19 10 2016 17 33 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:40,732 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 23 19 10 2016 17 33 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:40,762 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 24 18 10 2016 21 00 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:40,764 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 24 18 10 2016 21 00 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:40,794 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 25 18 10 2016 18 47 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:40,796 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 25 18 10 2016 18 47 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:40,826 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 26 18 10 2016 15 33 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:40,827 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 26 18 10 2016 15 33 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:40,858 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 27 18 10 2016 14 32 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:40,859 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 27 18 10 2016 14 32 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:40,907 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 28 18 10 2016 14 28 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:40,910 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 28 18 10 2016 14 28 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:40,938 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 29 18 10 2016 13 41 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:40,939 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 29 18 10 2016 13 41 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:40,970 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 30 21 09 2016 15 15 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:40,971 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 30 21 09 2016 15 15 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:41,003 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 31 04 03 2016 22 28 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:41,006 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 31 04 03 2016 22 28 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:41,036 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 32 01 10 2015 19 06 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:41,037 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 32 01 10 2015 19 06 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:41,067 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 33 01 10 2015 18 56 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:41,068 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 33 01 10 2015 18 56 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:41,099 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 34 03 09 2015 22 11 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:41,101 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 34 03 09 2015 22 11 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:41,130 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 35 11 03 2015 13 20 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:41,132 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 35 11 03 2015 13 20 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:41,162 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 36 11 03 2015 13 18 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:41,163 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 36 11 03 2015 13 18 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:41,195 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 37 11 03 2015 13 15 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:41,197 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 37 11 03 2015 13 15 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:41,228 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 38 11 03 2015 13 13 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:41,229 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 38 11 03 2015 13 13 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:41,260 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 39 22 01 2015 03 17 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:41,261 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 39 22 01 2015 03 17 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:41,306 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 40 22 01 2015 03 15 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:41,306 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 40 22 01 2015 03 15 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:41,337 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 41 06 11 2014 17 08 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:41,338 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 41 06 11 2014 17 08 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:41,370 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 42 06 11 2014 16 22 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:41,371 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 42 06 11 2014 16 22 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:41,402 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 43 06 11 2014 16 20 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:41,402 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 43 06 11 2014 16 20 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:41,434 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 44 06 11 2014 15 57 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:41,435 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 44 06 11 2014 15 57 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:41,466 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 45 18 09 2014 20 23 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:41,467 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 45 18 09 2014 20 23 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:41,501 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 46 18 09 2014 19 54 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:41,503 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 46 18 09 2014 19 54 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:41,532 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 47 18 09 2014 19 44 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:41,533 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 47 18 09 2014 19 44 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:41,562 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 48 18 09 2014 19 35 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:41,563 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 48 18 09 2014 19 35 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:41,594 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 49 15 09 2014 20 08 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:41,595 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 49 15 09 2014 20 08 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:41,627 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 A 50 15 09 2014 19 39 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:41,628 - pylabrobot - IO - [MT Scale] Received response: b'M27 A 50 15 09 2014 19 39 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:41,632 - pylabrobot - IO - [MT Scale] Sent command: UPD\n", + "2026-03-30 13:22:41,636 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'UPD\\r\\n'\n", + "2026-03-30 13:22:41,674 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'UPD A 10.173\\r\\n'\n", + "2026-03-30 13:22:41,674 - pylabrobot - IO - [MT Scale] Received response: b'UPD A 10.173\\r\\n'\n", + "2026-03-30 13:22:41,676 - pylabrobot - IO - [MT Scale] Sent command: SIS\n", + "2026-03-30 13:22:41,680 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SIS\\r\\n'\n", + "2026-03-30 13:22:41,722 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'SIS A 0 \"0.00000\" 0 5 1 0 0\\r\\n'\n", + "2026-03-30 13:22:41,723 - pylabrobot - IO - [MT Scale] Received response: b'SIS A 0 \"0.00000\" 0 5 1 0 0\\r\\n'\n", + "2026-03-30 13:22:41,724 - pylabrobot - IO - [MT Scale] Sent command: LST\n", + "2026-03-30 13:22:41,728 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'LST\\r\\n'\n", + "2026-03-30 13:22:41,770 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B C0 0 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:41,770 - pylabrobot - IO - [MT Scale] Received response: b'LST B C0 0 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:41,785 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B FCUT 0.000\\r\\n'\n", + "2026-03-30 13:22:41,786 - pylabrobot - IO - [MT Scale] Received response: b'LST B FCUT 0.000\\r\\n'\n", + "2026-03-30 13:22:41,802 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B I10 \"\"\\r\\n'\n", + "2026-03-30 13:22:41,803 - pylabrobot - IO - [MT Scale] Received response: b'LST B I10 \"\"\\r\\n'\n", + "2026-03-30 13:22:41,817 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B M01 0\\r\\n'\n", + "2026-03-30 13:22:41,818 - pylabrobot - IO - [MT Scale] Received response: b'LST B M01 0\\r\\n'\n" ] }, { @@ -1326,62 +1444,62 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 13:12:44,900 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B M01 0\\r\\n'\n", - "2026-03-30 13:12:44,902 - pylabrobot - IO - [MT Scale] Received response: b'LST B M01 0\\r\\n'\n", - "2026-03-30 13:12:44,918 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B M02 2\\r\\n'\n", - "2026-03-30 13:12:44,921 - pylabrobot - IO - [MT Scale] Received response: b'LST B M02 2\\r\\n'\n", - "2026-03-30 13:12:44,932 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B M03 0\\r\\n'\n", - "2026-03-30 13:12:44,933 - pylabrobot - IO - [MT Scale] Received response: b'LST B M03 0\\r\\n'\n", - "2026-03-30 13:12:44,948 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B M17 00 00 00 0\\r\\n'\n", - "2026-03-30 13:12:44,949 - pylabrobot - IO - [MT Scale] Received response: b'LST B M17 00 00 00 0\\r\\n'\n", - "2026-03-30 13:12:44,964 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B M18 1\\r\\n'\n", - "2026-03-30 13:12:44,965 - pylabrobot - IO - [MT Scale] Received response: b'LST B M18 1\\r\\n'\n", - "2026-03-30 13:12:44,996 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B M19 10.00000 g\\r\\n'\n", - "2026-03-30 13:12:44,999 - pylabrobot - IO - [MT Scale] Received response: b'LST B M19 10.00000 g\\r\\n'\n", - "2026-03-30 13:12:45,012 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B M20 200.00000 g\\r\\n'\n", - "2026-03-30 13:12:45,012 - pylabrobot - IO - [MT Scale] Received response: b'LST B M20 200.00000 g\\r\\n'\n", - "2026-03-30 13:12:45,028 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B M21 0 0\\r\\n'\n", - "2026-03-30 13:12:45,030 - pylabrobot - IO - [MT Scale] Received response: b'LST B M21 0 0\\r\\n'\n", - "2026-03-30 13:12:45,043 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B M29 1\\r\\n'\n", - "2026-03-30 13:12:45,044 - pylabrobot - IO - [MT Scale] Received response: b'LST B M29 1\\r\\n'\n", - "2026-03-30 13:12:45,065 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B M31 0\\r\\n'\n", - "2026-03-30 13:12:45,066 - pylabrobot - IO - [MT Scale] Received response: b'LST B M31 0\\r\\n'\n", - "2026-03-30 13:12:45,077 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B M32 1 00 00 0\\r\\n'\n", - "2026-03-30 13:12:45,082 - pylabrobot - IO - [MT Scale] Received response: b'LST B M32 1 00 00 0\\r\\n'\n", - "2026-03-30 13:12:45,092 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B M32 2 00 00 0\\r\\n'\n", - "2026-03-30 13:12:45,094 - pylabrobot - IO - [MT Scale] Received response: b'LST B M32 2 00 00 0\\r\\n'\n", - "2026-03-30 13:12:45,127 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B M32 3 00 00 0\\r\\n'\n", - "2026-03-30 13:12:45,132 - pylabrobot - IO - [MT Scale] Received response: b'LST B M32 3 00 00 0\\r\\n'\n", - "2026-03-30 13:12:45,140 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B M33 0\\r\\n'\n", - "2026-03-30 13:12:45,142 - pylabrobot - IO - [MT Scale] Received response: b'LST B M33 0\\r\\n'\n", - "2026-03-30 13:12:45,156 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B M35 0\\r\\n'\n", - "2026-03-30 13:12:45,157 - pylabrobot - IO - [MT Scale] Received response: b'LST B M35 0\\r\\n'\n", - "2026-03-30 13:12:45,160 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B RDB 5\\r\\n'\n", - "2026-03-30 13:12:45,160 - pylabrobot - IO - [MT Scale] Received response: b'LST B RDB 5\\r\\n'\n", - "2026-03-30 13:12:45,173 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B TST0 0 \"\"\\r\\n'\n", - "2026-03-30 13:12:45,174 - pylabrobot - IO - [MT Scale] Received response: b'LST B TST0 0 \"\"\\r\\n'\n", - "2026-03-30 13:12:45,204 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B UPD 10.173\\r\\n'\n", - "2026-03-30 13:12:45,206 - pylabrobot - IO - [MT Scale] Received response: b'LST B UPD 10.173\\r\\n'\n", - "2026-03-30 13:12:45,220 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B USTB 0 3.600 1.100\\r\\n'\n", - "2026-03-30 13:12:45,221 - pylabrobot - IO - [MT Scale] Received response: b'LST B USTB 0 3.600 1.100\\r\\n'\n", - "2026-03-30 13:12:45,252 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B USTB 1 0.000 0.000\\r\\n'\n", - "2026-03-30 13:12:45,253 - pylabrobot - IO - [MT Scale] Received response: b'LST B USTB 1 0.000 0.000\\r\\n'\n", - "2026-03-30 13:12:45,284 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST A USTB 2 0.000 0.000\\r\\n'\n", - "2026-03-30 13:12:45,287 - pylabrobot - IO - [MT Scale] Received response: b'LST A USTB 2 0.000 0.000\\r\\n'\n", - "2026-03-30 13:12:45,291 - pylabrobot - IO - [MT Scale] Sent command: RDB\n", - "2026-03-30 13:12:45,297 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'RDB\\r\\n'\n", - "2026-03-30 13:12:45,332 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'RDB A 5\\r\\n'\n", - "2026-03-30 13:12:45,339 - pylabrobot - IO - [MT Scale] Received response: b'RDB A 5\\r\\n'\n", - "2026-03-30 13:12:45,340 - pylabrobot - IO - [MT Scale] Sent command: USTB\n", - "2026-03-30 13:12:45,344 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'USTB\\r\\n'\n", - "2026-03-30 13:12:45,397 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'USTB B 0 3.600 1.100\\r\\n'\n", - "2026-03-30 13:12:45,399 - pylabrobot - IO - [MT Scale] Received response: b'USTB B 0 3.600 1.100\\r\\n'\n", - "2026-03-30 13:12:45,412 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'USTB B 1 0.000 0.000\\r\\n'\n", - "2026-03-30 13:12:45,413 - pylabrobot - IO - [MT Scale] Received response: b'USTB B 1 0.000 0.000\\r\\n'\n", - "2026-03-30 13:12:45,444 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'USTB A 2 0.000 0.000\\r\\n'\n", - "2026-03-30 13:12:45,446 - pylabrobot - IO - [MT Scale] Received response: b'USTB A 2 0.000 0.000\\r\\n'\n", - "2026-03-30 13:12:45,449 - pylabrobot - IO - [MT Scale] Sent command: FCUT\n", - "2026-03-30 13:12:45,452 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'FCUT\\r\\n'\n" + "2026-03-30 13:22:41,833 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B M02 2\\r\\n'\n", + "2026-03-30 13:22:41,834 - pylabrobot - IO - [MT Scale] Received response: b'LST B M02 2\\r\\n'\n", + "2026-03-30 13:22:41,839 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B M03 0\\r\\n'\n", + "2026-03-30 13:22:41,841 - pylabrobot - IO - [MT Scale] Received response: b'LST B M03 0\\r\\n'\n", + "2026-03-30 13:22:41,865 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B M17 00 00 00 0\\r\\n'\n", + "2026-03-30 13:22:41,867 - pylabrobot - IO - [MT Scale] Received response: b'LST B M17 00 00 00 0\\r\\n'\n", + "2026-03-30 13:22:41,883 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B M18 1\\r\\n'\n", + "2026-03-30 13:22:41,884 - pylabrobot - IO - [MT Scale] Received response: b'LST B M18 1\\r\\n'\n", + "2026-03-30 13:22:41,897 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B M19 10.00000 g\\r\\n'\n", + "2026-03-30 13:22:41,898 - pylabrobot - IO - [MT Scale] Received response: b'LST B M19 10.00000 g\\r\\n'\n", + "2026-03-30 13:22:41,929 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B M20 200.00000 g\\r\\n'\n", + "2026-03-30 13:22:41,930 - pylabrobot - IO - [MT Scale] Received response: b'LST B M20 200.00000 g\\r\\n'\n", + "2026-03-30 13:22:41,945 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B M21 0 0\\r\\n'\n", + "2026-03-30 13:22:41,946 - pylabrobot - IO - [MT Scale] Received response: b'LST B M21 0 0\\r\\n'\n", + "2026-03-30 13:22:41,948 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B M29 1\\r\\n'\n", + "2026-03-30 13:22:41,949 - pylabrobot - IO - [MT Scale] Received response: b'LST B M29 1\\r\\n'\n", + "2026-03-30 13:22:41,961 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B M31 0\\r\\n'\n", + "2026-03-30 13:22:41,962 - pylabrobot - IO - [MT Scale] Received response: b'LST B M31 0\\r\\n'\n", + "2026-03-30 13:22:41,994 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B M32 1 00 00 0\\r\\n'\n", + "2026-03-30 13:22:41,996 - pylabrobot - IO - [MT Scale] Received response: b'LST B M32 1 00 00 0\\r\\n'\n", + "2026-03-30 13:22:42,010 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B M32 2 00 00 0\\r\\n'\n", + "2026-03-30 13:22:42,011 - pylabrobot - IO - [MT Scale] Received response: b'LST B M32 2 00 00 0\\r\\n'\n", + "2026-03-30 13:22:42,027 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B M32 3 00 00 0\\r\\n'\n", + "2026-03-30 13:22:42,029 - pylabrobot - IO - [MT Scale] Received response: b'LST B M32 3 00 00 0\\r\\n'\n", + "2026-03-30 13:22:42,043 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B M33 0\\r\\n'\n", + "2026-03-30 13:22:42,045 - pylabrobot - IO - [MT Scale] Received response: b'LST B M33 0\\r\\n'\n", + "2026-03-30 13:22:42,057 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B M35 0\\r\\n'\n", + "2026-03-30 13:22:42,058 - pylabrobot - IO - [MT Scale] Received response: b'LST B M35 0\\r\\n'\n", + "2026-03-30 13:22:42,073 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B RDB 5\\r\\n'\n", + "2026-03-30 13:22:42,074 - pylabrobot - IO - [MT Scale] Received response: b'LST B RDB 5\\r\\n'\n", + "2026-03-30 13:22:42,089 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B TST0 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:42,090 - pylabrobot - IO - [MT Scale] Received response: b'LST B TST0 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:42,107 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B UPD 10.173\\r\\n'\n", + "2026-03-30 13:22:42,114 - pylabrobot - IO - [MT Scale] Received response: b'LST B UPD 10.173\\r\\n'\n", + "2026-03-30 13:22:42,137 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B USTB 0 3.600 1.100\\r\\n'\n", + "2026-03-30 13:22:42,139 - pylabrobot - IO - [MT Scale] Received response: b'LST B USTB 0 3.600 1.100\\r\\n'\n", + "2026-03-30 13:22:42,169 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B USTB 1 0.000 0.000\\r\\n'\n", + "2026-03-30 13:22:42,170 - pylabrobot - IO - [MT Scale] Received response: b'LST B USTB 1 0.000 0.000\\r\\n'\n", + "2026-03-30 13:22:42,187 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST A USTB 2 0.000 0.000\\r\\n'\n", + "2026-03-30 13:22:42,189 - pylabrobot - IO - [MT Scale] Received response: b'LST A USTB 2 0.000 0.000\\r\\n'\n", + "2026-03-30 13:22:42,195 - pylabrobot - IO - [MT Scale] Sent command: RDB\n", + "2026-03-30 13:22:42,204 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'RDB\\r\\n'\n", + "2026-03-30 13:22:42,234 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'RDB A 5\\r\\n'\n", + "2026-03-30 13:22:42,235 - pylabrobot - IO - [MT Scale] Received response: b'RDB A 5\\r\\n'\n", + "2026-03-30 13:22:42,237 - pylabrobot - IO - [MT Scale] Sent command: USTB\n", + "2026-03-30 13:22:42,243 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'USTB\\r\\n'\n", + "2026-03-30 13:22:42,282 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'USTB B 0 3.600 1.100\\r\\n'\n", + "2026-03-30 13:22:42,283 - pylabrobot - IO - [MT Scale] Received response: b'USTB B 0 3.600 1.100\\r\\n'\n", + "2026-03-30 13:22:42,314 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'USTB B 1 0.000 0.000\\r\\n'\n", + "2026-03-30 13:22:42,315 - pylabrobot - IO - [MT Scale] Received response: b'USTB B 1 0.000 0.000\\r\\n'\n", + "2026-03-30 13:22:42,329 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'USTB A 2 0.000 0.000\\r\\n'\n", + "2026-03-30 13:22:42,331 - pylabrobot - IO - [MT Scale] Received response: b'USTB A 2 0.000 0.000\\r\\n'\n", + "2026-03-30 13:22:42,332 - pylabrobot - IO - [MT Scale] Sent command: FCUT\n", + "2026-03-30 13:22:42,338 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'FCUT\\r\\n'\n", + "2026-03-30 13:22:42,377 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'FCUT A 0.000\\r\\n'\n", + "2026-03-30 13:22:42,379 - pylabrobot - IO - [MT Scale] Received response: b'FCUT A 0.000\\r\\n'\n" ] }, { @@ -1403,21 +1521,7 @@ " ... (24 lines total)\n", "\n", "Readability: RDB A 5\n", - "Stability criteria: USTB B 0 3.600 1.100\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2026-03-30 13:12:45,493 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'FCUT A 0.000\\r\\n'\n", - "2026-03-30 13:12:45,494 - pylabrobot - IO - [MT Scale] Received response: b'FCUT A 0.000\\r\\n'\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ + "Stability criteria: USTB B 0 3.600 1.100\n", "Filter cut-off: FCUT A 0.000\n", "\n", "PASS: Batch 2+3 read-only configuration queries completed\n" @@ -1530,21 +1634,21 @@ }, { "cell_type": "code", - "execution_count": 26, + "execution_count": 15, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 13:12:45,621 - pylabrobot - IO - [MT Scale] Sent command: Z\n", - "2026-03-30 13:12:45,625 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'Z\\r\\n'\n", - "2026-03-30 13:12:46,019 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'Z A\\r\\n'\n", - "2026-03-30 13:12:46,020 - pylabrobot - IO - [MT Scale] Received response: b'Z A\\r\\n'\n", - "2026-03-30 13:12:46,022 - pylabrobot - IO - [MT Scale] Sent command: SI\n", - "2026-03-30 13:12:46,024 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", - "2026-03-30 13:12:46,067 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 13:12:46,069 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n" + "2026-03-30 13:23:14,769 - pylabrobot - IO - [MT Scale] Sent command: Z\n", + "2026-03-30 13:23:14,772 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'Z\\r\\n'\n", + "2026-03-30 13:23:15,084 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'Z A\\r\\n'\n", + "2026-03-30 13:23:15,085 - pylabrobot - IO - [MT Scale] Received response: b'Z A\\r\\n'\n", + "2026-03-30 13:23:15,087 - pylabrobot - IO - [MT Scale] Sent command: SI\n", + "2026-03-30 13:23:15,091 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", + "2026-03-30 13:23:15,132 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 13:23:15,139 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n" ] }, { @@ -1565,14 +1669,14 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 13:12:47,098 - pylabrobot - IO - [MT Scale] Sent command: T\n", - "2026-03-30 13:12:47,100 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'T\\r\\n'\n", - "2026-03-30 13:12:47,409 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'T S 0.00000 g\\r\\n'\n", - "2026-03-30 13:12:47,410 - pylabrobot - IO - [MT Scale] Received response: b'T S 0.00000 g\\r\\n'\n", - "2026-03-30 13:12:47,411 - pylabrobot - IO - [MT Scale] Sent command: TA\n", - "2026-03-30 13:12:47,412 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'TA\\r\\n'\n", - "2026-03-30 13:12:47,505 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'TA A 0.00000 g\\r\\n'\n", - "2026-03-30 13:12:47,506 - pylabrobot - IO - [MT Scale] Received response: b'TA A 0.00000 g\\r\\n'\n" + "2026-03-30 13:23:16,272 - pylabrobot - IO - [MT Scale] Sent command: T\n", + "2026-03-30 13:23:16,274 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'T\\r\\n'\n", + "2026-03-30 13:23:16,668 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'T S 0.00000 g\\r\\n'\n", + "2026-03-30 13:23:16,669 - pylabrobot - IO - [MT Scale] Received response: b'T S 0.00000 g\\r\\n'\n", + "2026-03-30 13:23:16,671 - pylabrobot - IO - [MT Scale] Sent command: TA\n", + "2026-03-30 13:23:16,672 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'TA\\r\\n'\n", + "2026-03-30 13:23:16,763 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'TA A 0.00000 g\\r\\n'\n", + "2026-03-30 13:23:16,763 - pylabrobot - IO - [MT Scale] Received response: b'TA A 0.00000 g\\r\\n'\n" ] }, { @@ -1589,7 +1693,7 @@ "traceback": [ "\u001b[31m---------------------------------------------------------------------------\u001b[39m", "\u001b[31mAssertionError\u001b[39m Traceback (most recent call last)", - "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[26]\u001b[39m\u001b[32m, line 12\u001b[39m\n\u001b[32m 10\u001b[39m tare = \u001b[38;5;28;01mawait\u001b[39;00m scale.request_tare_weight()\n\u001b[32m 11\u001b[39m \u001b[38;5;28mprint\u001b[39m(\u001b[33mf\u001b[39m\u001b[33m\"\u001b[39m\u001b[33mFrontend tare weight: \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mtare\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m g\u001b[39m\u001b[33m\"\u001b[39m)\n\u001b[32m---> \u001b[39m\u001b[32m12\u001b[39m \u001b[38;5;28;01massert\u001b[39;00m tare > \u001b[32m0\u001b[39m\n\u001b[32m 14\u001b[39m \u001b[38;5;66;03m# Read via frontend\u001b[39;00m\n\u001b[32m 15\u001b[39m w = \u001b[38;5;28;01mawait\u001b[39;00m scale.read_weight(timeout=\u001b[33m\"\u001b[39m\u001b[33mstable\u001b[39m\u001b[33m\"\u001b[39m)\n", + "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[15]\u001b[39m\u001b[32m, line 12\u001b[39m\n\u001b[32m 10\u001b[39m tare = \u001b[38;5;28;01mawait\u001b[39;00m scale.request_tare_weight()\n\u001b[32m 11\u001b[39m \u001b[38;5;28mprint\u001b[39m(\u001b[33mf\u001b[39m\u001b[33m\"\u001b[39m\u001b[33mFrontend tare weight: \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mtare\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m g\u001b[39m\u001b[33m\"\u001b[39m)\n\u001b[32m---> \u001b[39m\u001b[32m12\u001b[39m \u001b[38;5;28;01massert\u001b[39;00m tare > \u001b[32m0\u001b[39m\n\u001b[32m 14\u001b[39m \u001b[38;5;66;03m# Read via frontend\u001b[39;00m\n\u001b[32m 15\u001b[39m w = \u001b[38;5;28;01mawait\u001b[39;00m scale.read_weight(timeout=\u001b[33m\"\u001b[39m\u001b[33mstable\u001b[39m\u001b[33m\"\u001b[39m)\n", "\u001b[31mAssertionError\u001b[39m: " ] } @@ -1626,101 +1730,101 @@ }, { "cell_type": "code", - "execution_count": 27, + "execution_count": 16, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 13:12:49,989 - pylabrobot - IO - [MT Scale] Sent command: S\n", - "2026-03-30 13:12:49,991 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", - "2026-03-30 13:12:50,064 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 13:12:50,065 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 13:12:50,065 - pylabrobot - IO - [MT Scale] Sent command: S\n", - "2026-03-30 13:12:50,067 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", - "2026-03-30 13:12:50,159 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 13:12:50,159 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 13:12:50,160 - pylabrobot - IO - [MT Scale] Sent command: S\n", - "2026-03-30 13:12:50,161 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", - "2026-03-30 13:12:50,255 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 13:12:50,256 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 13:12:50,257 - pylabrobot - IO - [MT Scale] Sent command: S\n", - "2026-03-30 13:12:50,258 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", - "2026-03-30 13:12:50,351 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 13:12:50,352 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 13:12:50,353 - pylabrobot - IO - [MT Scale] Sent command: S\n", - "2026-03-30 13:12:50,356 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", - "2026-03-30 13:12:50,447 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 13:12:50,448 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 13:12:50,453 - pylabrobot - IO - [MT Scale] Sent command: S\n", - "2026-03-30 13:12:50,455 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", - "2026-03-30 13:12:50,561 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 13:12:50,563 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 13:12:50,569 - pylabrobot - IO - [MT Scale] Sent command: S\n", - "2026-03-30 13:12:50,574 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", - "2026-03-30 13:12:50,657 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 13:12:50,659 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 13:12:50,664 - pylabrobot - IO - [MT Scale] Sent command: S\n", - "2026-03-30 13:12:50,668 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", - "2026-03-30 13:12:50,751 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 13:12:50,752 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 13:12:50,753 - pylabrobot - IO - [MT Scale] Sent command: S\n", - "2026-03-30 13:12:50,759 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", - "2026-03-30 13:12:50,847 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 13:12:50,848 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 13:12:50,850 - pylabrobot - IO - [MT Scale] Sent command: S\n", - "2026-03-30 13:12:50,857 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", - "2026-03-30 13:12:50,943 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 13:12:50,944 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 13:12:50,947 - pylabrobot - IO - [MT Scale] Sent command: SI\n", - "2026-03-30 13:12:50,951 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", - "2026-03-30 13:12:50,991 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 13:12:50,994 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 13:12:50,999 - pylabrobot - IO - [MT Scale] Sent command: SI\n", - "2026-03-30 13:12:51,006 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", - "2026-03-30 13:12:51,041 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 13:12:51,043 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 13:12:51,046 - pylabrobot - IO - [MT Scale] Sent command: SI\n", - "2026-03-30 13:12:51,051 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", - "2026-03-30 13:12:51,086 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 13:12:51,087 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 13:12:51,088 - pylabrobot - IO - [MT Scale] Sent command: SI\n", - "2026-03-30 13:12:51,091 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", - "2026-03-30 13:12:51,119 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 13:12:51,120 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 13:12:51,125 - pylabrobot - IO - [MT Scale] Sent command: SI\n", - "2026-03-30 13:12:51,126 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", - "2026-03-30 13:12:51,168 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 13:12:51,169 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 13:12:51,177 - pylabrobot - IO - [MT Scale] Sent command: SI\n", - "2026-03-30 13:12:51,181 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", - "2026-03-30 13:12:51,215 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 13:12:51,216 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 13:12:51,216 - pylabrobot - IO - [MT Scale] Sent command: SI\n", - "2026-03-30 13:12:51,218 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", - "2026-03-30 13:12:51,246 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 13:12:51,247 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 13:12:51,249 - pylabrobot - IO - [MT Scale] Sent command: SI\n", - "2026-03-30 13:12:51,252 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", - "2026-03-30 13:12:51,278 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 13:12:51,279 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 13:12:51,280 - pylabrobot - IO - [MT Scale] Sent command: SI\n", - "2026-03-30 13:12:51,284 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", - "2026-03-30 13:12:51,326 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 13:12:51,327 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 13:12:51,328 - pylabrobot - IO - [MT Scale] Sent command: SI\n", - "2026-03-30 13:12:51,331 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", - "2026-03-30 13:12:51,375 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 13:12:51,376 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n" + "2026-03-30 13:23:25,471 - pylabrobot - IO - [MT Scale] Sent command: S\n", + "2026-03-30 13:23:25,473 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", + "2026-03-30 13:23:25,508 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00001 g\\r\\n'\n", + "2026-03-30 13:23:25,509 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00001 g\\r\\n'\n", + "2026-03-30 13:23:25,509 - pylabrobot - IO - [MT Scale] Sent command: S\n", + "2026-03-30 13:23:25,511 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", + "2026-03-30 13:23:25,604 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00001 g\\r\\n'\n", + "2026-03-30 13:23:25,605 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00001 g\\r\\n'\n", + "2026-03-30 13:23:25,605 - pylabrobot - IO - [MT Scale] Sent command: S\n", + "2026-03-30 13:23:25,606 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", + "2026-03-30 13:23:25,699 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00001 g\\r\\n'\n", + "2026-03-30 13:23:25,700 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00001 g\\r\\n'\n", + "2026-03-30 13:23:25,700 - pylabrobot - IO - [MT Scale] Sent command: S\n", + "2026-03-30 13:23:25,701 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", + "2026-03-30 13:23:25,811 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00001 g\\r\\n'\n", + "2026-03-30 13:23:25,812 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00001 g\\r\\n'\n", + "2026-03-30 13:23:25,813 - pylabrobot - IO - [MT Scale] Sent command: S\n", + "2026-03-30 13:23:25,815 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", + "2026-03-30 13:23:25,908 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00001 g\\r\\n'\n", + "2026-03-30 13:23:25,908 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00001 g\\r\\n'\n", + "2026-03-30 13:23:25,909 - pylabrobot - IO - [MT Scale] Sent command: S\n", + "2026-03-30 13:23:25,910 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", + "2026-03-30 13:23:26,004 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00001 g\\r\\n'\n", + "2026-03-30 13:23:26,004 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00001 g\\r\\n'\n", + "2026-03-30 13:23:26,005 - pylabrobot - IO - [MT Scale] Sent command: S\n", + "2026-03-30 13:23:26,006 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", + "2026-03-30 13:23:26,099 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00001 g\\r\\n'\n", + "2026-03-30 13:23:26,100 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00001 g\\r\\n'\n", + "2026-03-30 13:23:26,100 - pylabrobot - IO - [MT Scale] Sent command: S\n", + "2026-03-30 13:23:26,101 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", + "2026-03-30 13:23:26,195 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00001 g\\r\\n'\n", + "2026-03-30 13:23:26,196 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00001 g\\r\\n'\n", + "2026-03-30 13:23:26,196 - pylabrobot - IO - [MT Scale] Sent command: S\n", + "2026-03-30 13:23:26,197 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", + "2026-03-30 13:23:26,291 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00001 g\\r\\n'\n", + "2026-03-30 13:23:26,292 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00001 g\\r\\n'\n", + "2026-03-30 13:23:26,293 - pylabrobot - IO - [MT Scale] Sent command: S\n", + "2026-03-30 13:23:26,293 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", + "2026-03-30 13:23:26,388 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00001 g\\r\\n'\n", + "2026-03-30 13:23:26,388 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00001 g\\r\\n'\n", + "2026-03-30 13:23:26,389 - pylabrobot - IO - [MT Scale] Sent command: SI\n", + "2026-03-30 13:23:26,390 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", + "2026-03-30 13:23:26,435 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00001 g\\r\\n'\n", + "2026-03-30 13:23:26,436 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00001 g\\r\\n'\n", + "2026-03-30 13:23:26,437 - pylabrobot - IO - [MT Scale] Sent command: SI\n", + "2026-03-30 13:23:26,445 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", + "2026-03-30 13:23:26,483 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00001 g\\r\\n'\n", + "2026-03-30 13:23:26,485 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00001 g\\r\\n'\n", + "2026-03-30 13:23:26,487 - pylabrobot - IO - [MT Scale] Sent command: SI\n", + "2026-03-30 13:23:26,488 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", + "2026-03-30 13:23:26,531 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00001 g\\r\\n'\n", + "2026-03-30 13:23:26,532 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00001 g\\r\\n'\n", + "2026-03-30 13:23:26,533 - pylabrobot - IO - [MT Scale] Sent command: SI\n", + "2026-03-30 13:23:26,535 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", + "2026-03-30 13:23:26,563 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00001 g\\r\\n'\n", + "2026-03-30 13:23:26,564 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00001 g\\r\\n'\n", + "2026-03-30 13:23:26,566 - pylabrobot - IO - [MT Scale] Sent command: SI\n", + "2026-03-30 13:23:26,568 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", + "2026-03-30 13:23:26,611 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00001 g\\r\\n'\n", + "2026-03-30 13:23:26,614 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00001 g\\r\\n'\n", + "2026-03-30 13:23:26,617 - pylabrobot - IO - [MT Scale] Sent command: SI\n", + "2026-03-30 13:23:26,619 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", + "2026-03-30 13:23:26,659 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00001 g\\r\\n'\n", + "2026-03-30 13:23:26,661 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00001 g\\r\\n'\n", + "2026-03-30 13:23:26,664 - pylabrobot - IO - [MT Scale] Sent command: SI\n", + "2026-03-30 13:23:26,665 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", + "2026-03-30 13:23:26,708 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00001 g\\r\\n'\n", + "2026-03-30 13:23:26,709 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00001 g\\r\\n'\n", + "2026-03-30 13:23:26,711 - pylabrobot - IO - [MT Scale] Sent command: SI\n", + "2026-03-30 13:23:26,717 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", + "2026-03-30 13:23:26,755 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00001 g\\r\\n'\n", + "2026-03-30 13:23:26,757 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00001 g\\r\\n'\n", + "2026-03-30 13:23:26,758 - pylabrobot - IO - [MT Scale] Sent command: SI\n", + "2026-03-30 13:23:26,759 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", + "2026-03-30 13:23:26,806 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00001 g\\r\\n'\n", + "2026-03-30 13:23:26,807 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00001 g\\r\\n'\n", + "2026-03-30 13:23:26,808 - pylabrobot - IO - [MT Scale] Sent command: SI\n", + "2026-03-30 13:23:26,811 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", + "2026-03-30 13:23:26,851 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00001 g\\r\\n'\n", + "2026-03-30 13:23:26,852 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00001 g\\r\\n'\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ - "Stable read: 95.74 +/- 9.23 ms\n", - "Immediate read: 42.95 +/- 7.21 ms\n" + "Stable read: 91.79 +/- 18.42 ms\n", + "Immediate read: 46.44 +/- 4.92 ms\n" ] } ], @@ -1759,27 +1863,27 @@ }, { "cell_type": "code", - "execution_count": 28, + "execution_count": 17, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 13:12:51,402 - pylabrobot - INFO - === Hardware validation ended ===\n", - "2026-03-30 13:12:51,413 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] reset_input_buffer\n", - "2026-03-30 13:12:51,420 - pylabrobot - IO - [MT Scale] Sent command: @\n", - "2026-03-30 13:12:51,423 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'@\\r\\n'\n", - "2026-03-30 13:12:51,488 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I4 A \"B207696838\"\\r\\n'\n", - "2026-03-30 13:12:51,491 - pylabrobot - IO - [MT Scale] Received response: b'I4 A \"B207696838\"\\r\\n'\n", - "2026-03-30 13:12:51,493 - pylabrobot - INFO - [MT Scale] Disconnected from /dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0\n" + "2026-03-30 13:23:31,221 - pylabrobot - INFO - === Hardware validation ended ===\n", + "2026-03-30 13:23:31,225 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] reset_input_buffer\n", + "2026-03-30 13:23:31,230 - pylabrobot - IO - [MT Scale] Sent command: @\n", + "2026-03-30 13:23:31,234 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'@\\r\\n'\n", + "2026-03-30 13:23:31,297 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I4 A \"B207696838\"\\r\\n'\n", + "2026-03-30 13:23:31,300 - pylabrobot - IO - [MT Scale] Received response: b'I4 A \"B207696838\"\\r\\n'\n", + "2026-03-30 13:23:31,302 - pylabrobot - INFO - [MT Scale] Disconnected from /dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ - "Log file: ./logs/hardware_validation/2026-03-30_13-12-14_validation.log\n" + "Log file: ./logs/hardware_validation/2026-03-30_13-22-09_validation.log\n" ] } ], @@ -1818,4 +1922,4 @@ }, "nbformat": 4, "nbformat_minor": 4 -} \ No newline at end of file +} From 9e4316f2d6108538cf0b5da67aa6ddfc5b8b15d5 Mon Sep 17 00:00:00 2001 From: Camillo Moschner Date: Mon, 30 Mar 2026 13:30:48 +0100 Subject: [PATCH 27/38] updated test for net weight --- .../mettler_toledo/hardware_validation.ipynb | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/pylabrobot/scales/mettler_toledo/hardware_validation.ipynb b/pylabrobot/scales/mettler_toledo/hardware_validation.ipynb index 8cb923b2ece..02211d422cd 100644 --- a/pylabrobot/scales/mettler_toledo/hardware_validation.ipynb +++ b/pylabrobot/scales/mettler_toledo/hardware_validation.ipynb @@ -1622,6 +1622,18 @@ "print(\"\\nPASS: Batch 2+3 read-only configuration queries completed\")" ] }, + { + "cell_type": "markdown", + "source": "### SIS unit code verification (exploratory)\n\nTests whether field index 4 in the SIS response is the unit code by temporarily\nchanging the host unit via M21, reading SIS, then restoring grams.\n\n**WARNING:** Temporarily writes a non-gram unit to device memory via M21.\nIf the cell fails mid-execution, run `await backend.set_host_unit_grams()`\nmanually to restore grams. setup() also restores grams on next connection.", + "metadata": {} + }, + { + "cell_type": "code", + "source": "# Read SIS in grams (current state)\nsis_grams = await backend.request_net_weight_with_status()\nprint(f\"SIS in grams: {sis_grams.data}\")\n\n# Temporarily set unit to milligrams (M21 1 0 = mg host unit)\ntry:\n await backend.send_command(\"M21 1 0\")\n sis_mg = await backend.request_net_weight_with_status()\n print(f\"SIS in milligrams: {sis_mg.data}\")\n\n # Compare the unit code field (index 4 in the data)\n if len(sis_grams.data) > 4 and len(sis_mg.data) > 4:\n print(f\"\\nUnit code in grams mode: {sis_grams.data[4]}\")\n print(f\"Unit code in mg mode: {sis_mg.data[4]}\")\n if sis_grams.data[4] != sis_mg.data[4]:\n print(\"PASS: unit code changes with M21 - confirms field is unit identifier\")\n else:\n print(\"INFO: unit code did not change - field may not be the unit identifier\")\n else:\n print(\"INFO: SIS response too short to compare unit codes\")\n\nfinally:\n # Always restore grams\n await backend.set_host_unit_grams()\n print(\"\\nRestored host unit to grams\")", + "metadata": {}, + "execution_count": null, + "outputs": [] + }, { "cell_type": "markdown", "metadata": {}, @@ -1922,4 +1934,4 @@ }, "nbformat": 4, "nbformat_minor": 4 -} +} \ No newline at end of file From 76136e43b981162c5de316ce17403e2506214b74 Mon Sep 17 00:00:00 2001 From: Camillo Moschner Date: Mon, 30 Mar 2026 13:32:00 +0100 Subject: [PATCH 28/38] error in SIS troubleshooting --- .../mettler_toledo/hardware_validation.ipynb | 1466 ++++++++--------- 1 file changed, 713 insertions(+), 753 deletions(-) diff --git a/pylabrobot/scales/mettler_toledo/hardware_validation.ipynb b/pylabrobot/scales/mettler_toledo/hardware_validation.ipynb index 02211d422cd..a81080acb00 100644 --- a/pylabrobot/scales/mettler_toledo/hardware_validation.ipynb +++ b/pylabrobot/scales/mettler_toledo/hardware_validation.ipynb @@ -33,7 +33,7 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 13:22:09,309 - pylabrobot - INFO - === Hardware validation started ===\n" + "2026-03-30 13:31:06,771 - pylabrobot - INFO - === Hardware validation started ===\n" ] } ], @@ -65,161 +65,161 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 13:22:09,329 - pylabrobot.io.serial - INFO - Using explicitly provided port: /dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0 (for VID=1027, PID=24577)\n", - "2026-03-30 13:22:09,336 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] reset_input_buffer\n", - "2026-03-30 13:22:09,337 - pylabrobot - IO - [MT Scale] Sent command: @\n", - "2026-03-30 13:22:09,340 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'@\\r\\n'\n", - "2026-03-30 13:22:09,400 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I4 A \"B207696838\"\\r\\n'\n", - "2026-03-30 13:22:09,402 - pylabrobot - IO - [MT Scale] Received response: b'I4 A \"B207696838\"\\r\\n'\n", - "2026-03-30 13:22:09,405 - pylabrobot - IO - [MT Scale] Sent command: I0\n", - "2026-03-30 13:22:09,406 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I0\\r\\n'\n", - "2026-03-30 13:22:09,445 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I0\"\\r\\n'\n", - "2026-03-30 13:22:09,447 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I0\"\\r\\n'\n", - "2026-03-30 13:22:09,452 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I1\"\\r\\n'\n", - "2026-03-30 13:22:09,453 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I1\"\\r\\n'\n", - "2026-03-30 13:22:09,462 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I2\"\\r\\n'\n", - "2026-03-30 13:22:09,464 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I2\"\\r\\n'\n", - "2026-03-30 13:22:09,478 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I3\"\\r\\n'\n", - "2026-03-30 13:22:09,480 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I3\"\\r\\n'\n", - "2026-03-30 13:22:09,497 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I4\"\\r\\n'\n", - "2026-03-30 13:22:09,499 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I4\"\\r\\n'\n", - "2026-03-30 13:22:09,510 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I5\"\\r\\n'\n", - "2026-03-30 13:22:09,511 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I5\"\\r\\n'\n", - "2026-03-30 13:22:09,526 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"S\"\\r\\n'\n", - "2026-03-30 13:22:09,528 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"S\"\\r\\n'\n", - "2026-03-30 13:22:09,531 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"SI\"\\r\\n'\n", - "2026-03-30 13:22:09,532 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"SI\"\\r\\n'\n", - "2026-03-30 13:22:09,544 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"SIR\"\\r\\n'\n", - "2026-03-30 13:22:09,545 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"SIR\"\\r\\n'\n", - "2026-03-30 13:22:09,560 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"Z\"\\r\\n'\n", - "2026-03-30 13:22:09,562 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"Z\"\\r\\n'\n", - "2026-03-30 13:22:09,574 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"ZI\"\\r\\n'\n", - "2026-03-30 13:22:09,578 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"ZI\"\\r\\n'\n", - "2026-03-30 13:22:09,589 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"@\"\\r\\n'\n", - "2026-03-30 13:22:09,594 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"@\"\\r\\n'\n", - "2026-03-30 13:22:09,609 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"SR\"\\r\\n'\n", - "2026-03-30 13:22:09,611 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"SR\"\\r\\n'\n", - "2026-03-30 13:22:09,614 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"T\"\\r\\n'\n", - "2026-03-30 13:22:09,615 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"T\"\\r\\n'\n", - "2026-03-30 13:22:09,621 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"TA\"\\r\\n'\n", - "2026-03-30 13:22:09,622 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"TA\"\\r\\n'\n", - "2026-03-30 13:22:09,638 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"TAC\"\\r\\n'\n", - "2026-03-30 13:22:09,642 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"TAC\"\\r\\n'\n", - "2026-03-30 13:22:09,653 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"TI\"\\r\\n'\n", - "2026-03-30 13:22:09,654 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"TI\"\\r\\n'\n", - "2026-03-30 13:22:09,673 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C0\"\\r\\n'\n", - "2026-03-30 13:22:09,674 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"C0\"\\r\\n'\n", - "2026-03-30 13:22:09,686 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C1\"\\r\\n'\n", - "2026-03-30 13:22:09,687 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"C1\"\\r\\n'\n", - "2026-03-30 13:22:09,702 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C2\"\\r\\n'\n", - "2026-03-30 13:22:09,709 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"C2\"\\r\\n'\n", - "2026-03-30 13:22:09,713 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C3\"\\r\\n'\n", - "2026-03-30 13:22:09,714 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"C3\"\\r\\n'\n", - "2026-03-30 13:22:09,718 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"COM\"\\r\\n'\n", - "2026-03-30 13:22:09,720 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"COM\"\\r\\n'\n", - "2026-03-30 13:22:09,734 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"DAT\"\\r\\n'\n", - "2026-03-30 13:22:09,735 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"DAT\"\\r\\n'\n", - "2026-03-30 13:22:09,751 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I10\"\\r\\n'\n", - "2026-03-30 13:22:09,753 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I10\"\\r\\n'\n", - "2026-03-30 13:22:09,769 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I11\"\\r\\n'\n", - "2026-03-30 13:22:09,771 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I11\"\\r\\n'\n", - "2026-03-30 13:22:09,782 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I14\"\\r\\n'\n", - "2026-03-30 13:22:09,783 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I14\"\\r\\n'\n", - "2026-03-30 13:22:09,797 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I15\"\\r\\n'\n", - "2026-03-30 13:22:09,798 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I15\"\\r\\n'\n", - "2026-03-30 13:22:09,814 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I16\"\\r\\n'\n", - "2026-03-30 13:22:09,816 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I16\"\\r\\n'\n", - "2026-03-30 13:22:09,830 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I21\"\\r\\n'\n", - "2026-03-30 13:22:09,832 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I21\"\\r\\n'\n", - "2026-03-30 13:22:09,845 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I22\"\\r\\n'\n", - "2026-03-30 13:22:09,846 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I22\"\\r\\n'\n", - "2026-03-30 13:22:09,861 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I23\"\\r\\n'\n", - "2026-03-30 13:22:09,863 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I23\"\\r\\n'\n", - "2026-03-30 13:22:09,867 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I24\"\\r\\n'\n", - "2026-03-30 13:22:09,872 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I24\"\\r\\n'\n", - "2026-03-30 13:22:09,877 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I25\"\\r\\n'\n", - "2026-03-30 13:22:09,878 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I25\"\\r\\n'\n", - "2026-03-30 13:22:09,893 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I26\"\\r\\n'\n", - "2026-03-30 13:22:09,894 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I26\"\\r\\n'\n", - "2026-03-30 13:22:09,909 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M01\"\\r\\n'\n", - "2026-03-30 13:22:09,910 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M01\"\\r\\n'\n", - "2026-03-30 13:22:09,925 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M02\"\\r\\n'\n", - "2026-03-30 13:22:09,926 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M02\"\\r\\n'\n", - "2026-03-30 13:22:09,945 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M03\"\\r\\n'\n", - "2026-03-30 13:22:09,946 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M03\"\\r\\n'\n", - "2026-03-30 13:22:09,957 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M17\"\\r\\n'\n", - "2026-03-30 13:22:09,958 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M17\"\\r\\n'\n", - "2026-03-30 13:22:09,973 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M18\"\\r\\n'\n", - "2026-03-30 13:22:09,975 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M18\"\\r\\n'\n", - "2026-03-30 13:22:09,989 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M19\"\\r\\n'\n", - "2026-03-30 13:22:09,989 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M19\"\\r\\n'\n", - "2026-03-30 13:22:10,006 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M20\"\\r\\n'\n", - "2026-03-30 13:22:10,007 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M20\"\\r\\n'\n", - "2026-03-30 13:22:10,021 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M21\"\\r\\n'\n", - "2026-03-30 13:22:10,021 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M21\"\\r\\n'\n", - "2026-03-30 13:22:10,037 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M27\"\\r\\n'\n", - "2026-03-30 13:22:10,038 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M27\"\\r\\n'\n", - "2026-03-30 13:22:10,041 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M28\"\\r\\n'\n", - "2026-03-30 13:22:10,042 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M28\"\\r\\n'\n", - "2026-03-30 13:22:10,053 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M29\"\\r\\n'\n", - "2026-03-30 13:22:10,054 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M29\"\\r\\n'\n", - "2026-03-30 13:22:10,069 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M31\"\\r\\n'\n", - "2026-03-30 13:22:10,069 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M31\"\\r\\n'\n", - "2026-03-30 13:22:10,085 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M32\"\\r\\n'\n", - "2026-03-30 13:22:10,087 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M32\"\\r\\n'\n", - "2026-03-30 13:22:10,101 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M33\"\\r\\n'\n", - "2026-03-30 13:22:10,101 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M33\"\\r\\n'\n", - "2026-03-30 13:22:10,117 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M35\"\\r\\n'\n", - "2026-03-30 13:22:10,118 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M35\"\\r\\n'\n", - "2026-03-30 13:22:10,134 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"SIS\"\\r\\n'\n", - "2026-03-30 13:22:10,136 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"SIS\"\\r\\n'\n", - "2026-03-30 13:22:10,149 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"SNR\"\\r\\n'\n", - "2026-03-30 13:22:10,154 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"SNR\"\\r\\n'\n", - "2026-03-30 13:22:10,169 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TIM\"\\r\\n'\n", - "2026-03-30 13:22:10,170 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TIM\"\\r\\n'\n", - "2026-03-30 13:22:10,180 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST0\"\\r\\n'\n", - "2026-03-30 13:22:10,182 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TST0\"\\r\\n'\n", - "2026-03-30 13:22:10,197 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST1\"\\r\\n'\n", - "2026-03-30 13:22:10,198 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TST1\"\\r\\n'\n", - "2026-03-30 13:22:10,213 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST2\"\\r\\n'\n", - "2026-03-30 13:22:10,217 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TST2\"\\r\\n'\n", - "2026-03-30 13:22:10,229 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST3\"\\r\\n'\n", - "2026-03-30 13:22:10,230 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TST3\"\\r\\n'\n", - "2026-03-30 13:22:10,245 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"UPD\"\\r\\n'\n", - "2026-03-30 13:22:10,246 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"UPD\"\\r\\n'\n", - "2026-03-30 13:22:10,248 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"FCUT\"\\r\\n'\n", - "2026-03-30 13:22:10,249 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 3 \"FCUT\"\\r\\n'\n", - "2026-03-30 13:22:10,261 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"FSET\"\\r\\n'\n", - "2026-03-30 13:22:10,261 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 3 \"FSET\"\\r\\n'\n", - "2026-03-30 13:22:10,279 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"LST\"\\r\\n'\n", - "2026-03-30 13:22:10,280 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 3 \"LST\"\\r\\n'\n", - "2026-03-30 13:22:10,292 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"RDB\"\\r\\n'\n", - "2026-03-30 13:22:10,293 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 3 \"RDB\"\\r\\n'\n", - "2026-03-30 13:22:10,309 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 A 3 \"USTB\"\\r\\n'\n", - "2026-03-30 13:22:10,311 - pylabrobot - IO - [MT Scale] Received response: b'I0 A 3 \"USTB\"\\r\\n'\n", - "2026-03-30 13:22:10,314 - pylabrobot - IO - [MT Scale] Sent command: I2\n", - "2026-03-30 13:22:10,317 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I2\\r\\n'\n", - "2026-03-30 13:22:10,373 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", - "2026-03-30 13:22:10,374 - pylabrobot - IO - [MT Scale] Received response: b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", - "2026-03-30 13:22:10,385 - pylabrobot - IO - [MT Scale] Sent command: I2\n", - "2026-03-30 13:22:10,387 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I2\\r\\n'\n", - "2026-03-30 13:22:10,453 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", - "2026-03-30 13:22:10,455 - pylabrobot - IO - [MT Scale] Received response: b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", - "2026-03-30 13:22:10,457 - pylabrobot - IO - [MT Scale] Sent command: I3\n", - "2026-03-30 13:22:10,464 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I3\\r\\n'\n", - "2026-03-30 13:22:10,516 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I3 A \"1.10 18.6.4.1361.772\"\\r\\n'\n", - "2026-03-30 13:22:10,518 - pylabrobot - IO - [MT Scale] Received response: b'I3 A \"1.10 18.6.4.1361.772\"\\r\\n'\n", - "2026-03-30 13:22:10,521 - pylabrobot - INFO - [MT Scale] Connected to Mettler Toledo scale on /dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0\n", + "2026-03-30 13:31:06,791 - pylabrobot.io.serial - INFO - Using explicitly provided port: /dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0 (for VID=1027, PID=24577)\n", + "2026-03-30 13:31:06,798 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] reset_input_buffer\n", + "2026-03-30 13:31:06,800 - pylabrobot - IO - [MT Scale] Sent command: @\n", + "2026-03-30 13:31:06,803 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'@\\r\\n'\n", + "2026-03-30 13:31:06,860 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I4 A \"B207696838\"\\r\\n'\n", + "2026-03-30 13:31:06,861 - pylabrobot - IO - [MT Scale] Received response: b'I4 A \"B207696838\"\\r\\n'\n", + "2026-03-30 13:31:06,862 - pylabrobot - IO - [MT Scale] Sent command: I0\n", + "2026-03-30 13:31:06,863 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I0\\r\\n'\n", + "2026-03-30 13:31:06,891 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I0\"\\r\\n'\n", + "2026-03-30 13:31:06,892 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I0\"\\r\\n'\n", + "2026-03-30 13:31:06,908 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I1\"\\r\\n'\n", + "2026-03-30 13:31:06,909 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I1\"\\r\\n'\n", + "2026-03-30 13:31:06,924 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I2\"\\r\\n'\n", + "2026-03-30 13:31:06,925 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I2\"\\r\\n'\n", + "2026-03-30 13:31:06,939 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I3\"\\r\\n'\n", + "2026-03-30 13:31:06,940 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I3\"\\r\\n'\n", + "2026-03-30 13:31:06,956 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I4\"\\r\\n'\n", + "2026-03-30 13:31:06,956 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I4\"\\r\\n'\n", + "2026-03-30 13:31:06,958 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I5\"\\r\\n'\n", + "2026-03-30 13:31:06,959 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I5\"\\r\\n'\n", + "2026-03-30 13:31:06,972 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"S\"\\r\\n'\n", + "2026-03-30 13:31:06,973 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"S\"\\r\\n'\n", + "2026-03-30 13:31:06,988 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"SI\"\\r\\n'\n", + "2026-03-30 13:31:06,988 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"SI\"\\r\\n'\n", + "2026-03-30 13:31:07,004 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"SIR\"\\r\\n'\n", + "2026-03-30 13:31:07,004 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"SIR\"\\r\\n'\n", + "2026-03-30 13:31:07,020 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"Z\"\\r\\n'\n", + "2026-03-30 13:31:07,021 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"Z\"\\r\\n'\n", + "2026-03-30 13:31:07,022 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"ZI\"\\r\\n'\n", + "2026-03-30 13:31:07,023 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"ZI\"\\r\\n'\n", + "2026-03-30 13:31:07,036 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"@\"\\r\\n'\n", + "2026-03-30 13:31:07,036 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"@\"\\r\\n'\n", + "2026-03-30 13:31:07,052 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"SR\"\\r\\n'\n", + "2026-03-30 13:31:07,053 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"SR\"\\r\\n'\n", + "2026-03-30 13:31:07,067 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"T\"\\r\\n'\n", + "2026-03-30 13:31:07,068 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"T\"\\r\\n'\n", + "2026-03-30 13:31:07,084 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"TA\"\\r\\n'\n", + "2026-03-30 13:31:07,084 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"TA\"\\r\\n'\n", + "2026-03-30 13:31:07,100 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"TAC\"\\r\\n'\n", + "2026-03-30 13:31:07,101 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"TAC\"\\r\\n'\n", + "2026-03-30 13:31:07,115 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"TI\"\\r\\n'\n", + "2026-03-30 13:31:07,116 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"TI\"\\r\\n'\n", + "2026-03-30 13:31:07,117 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C0\"\\r\\n'\n", + "2026-03-30 13:31:07,118 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"C0\"\\r\\n'\n", + "2026-03-30 13:31:07,132 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C1\"\\r\\n'\n", + "2026-03-30 13:31:07,132 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"C1\"\\r\\n'\n", + "2026-03-30 13:31:07,148 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C2\"\\r\\n'\n", + "2026-03-30 13:31:07,149 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"C2\"\\r\\n'\n", + "2026-03-30 13:31:07,163 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C3\"\\r\\n'\n", + "2026-03-30 13:31:07,164 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"C3\"\\r\\n'\n", + "2026-03-30 13:31:07,180 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"COM\"\\r\\n'\n", + "2026-03-30 13:31:07,180 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"COM\"\\r\\n'\n", + "2026-03-30 13:31:07,195 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"DAT\"\\r\\n'\n", + "2026-03-30 13:31:07,196 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"DAT\"\\r\\n'\n", + "2026-03-30 13:31:07,212 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I10\"\\r\\n'\n", + "2026-03-30 13:31:07,213 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I10\"\\r\\n'\n", + "2026-03-30 13:31:07,228 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I11\"\\r\\n'\n", + "2026-03-30 13:31:07,228 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I11\"\\r\\n'\n", + "2026-03-30 13:31:07,230 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I14\"\\r\\n'\n", + "2026-03-30 13:31:07,231 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I14\"\\r\\n'\n", + "2026-03-30 13:31:07,243 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I15\"\\r\\n'\n", + "2026-03-30 13:31:07,244 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I15\"\\r\\n'\n", + "2026-03-30 13:31:07,260 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I16\"\\r\\n'\n", + "2026-03-30 13:31:07,260 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I16\"\\r\\n'\n", + "2026-03-30 13:31:07,276 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I21\"\\r\\n'\n", + "2026-03-30 13:31:07,277 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I21\"\\r\\n'\n", + "2026-03-30 13:31:07,291 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I22\"\\r\\n'\n", + "2026-03-30 13:31:07,292 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I22\"\\r\\n'\n", + "2026-03-30 13:31:07,307 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I23\"\\r\\n'\n", + "2026-03-30 13:31:07,308 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I23\"\\r\\n'\n", + "2026-03-30 13:31:07,324 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I24\"\\r\\n'\n", + "2026-03-30 13:31:07,324 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I24\"\\r\\n'\n", + "2026-03-30 13:31:07,339 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I25\"\\r\\n'\n", + "2026-03-30 13:31:07,340 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I25\"\\r\\n'\n", + "2026-03-30 13:31:07,355 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I26\"\\r\\n'\n", + "2026-03-30 13:31:07,356 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I26\"\\r\\n'\n", + "2026-03-30 13:31:07,371 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M01\"\\r\\n'\n", + "2026-03-30 13:31:07,371 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M01\"\\r\\n'\n", + "2026-03-30 13:31:07,387 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M02\"\\r\\n'\n", + "2026-03-30 13:31:07,388 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M02\"\\r\\n'\n", + "2026-03-30 13:31:07,403 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M03\"\\r\\n'\n", + "2026-03-30 13:31:07,404 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M03\"\\r\\n'\n", + "2026-03-30 13:31:07,405 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M17\"\\r\\n'\n", + "2026-03-30 13:31:07,407 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M17\"\\r\\n'\n", + "2026-03-30 13:31:07,419 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M18\"\\r\\n'\n", + "2026-03-30 13:31:07,420 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M18\"\\r\\n'\n", + "2026-03-30 13:31:07,435 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M19\"\\r\\n'\n", + "2026-03-30 13:31:07,436 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M19\"\\r\\n'\n", + "2026-03-30 13:31:07,452 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M20\"\\r\\n'\n", + "2026-03-30 13:31:07,452 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M20\"\\r\\n'\n", + "2026-03-30 13:31:07,467 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M21\"\\r\\n'\n", + "2026-03-30 13:31:07,468 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M21\"\\r\\n'\n", + "2026-03-30 13:31:07,483 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M27\"\\r\\n'\n", + "2026-03-30 13:31:07,484 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M27\"\\r\\n'\n", + "2026-03-30 13:31:07,500 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M28\"\\r\\n'\n", + "2026-03-30 13:31:07,500 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M28\"\\r\\n'\n", + "2026-03-30 13:31:07,515 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M29\"\\r\\n'\n", + "2026-03-30 13:31:07,516 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M29\"\\r\\n'\n", + "2026-03-30 13:31:07,531 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M31\"\\r\\n'\n", + "2026-03-30 13:31:07,532 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M31\"\\r\\n'\n", + "2026-03-30 13:31:07,547 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M32\"\\r\\n'\n", + "2026-03-30 13:31:07,547 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M32\"\\r\\n'\n", + "2026-03-30 13:31:07,563 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M33\"\\r\\n'\n", + "2026-03-30 13:31:07,564 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M33\"\\r\\n'\n", + "2026-03-30 13:31:07,565 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M35\"\\r\\n'\n", + "2026-03-30 13:31:07,566 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M35\"\\r\\n'\n", + "2026-03-30 13:31:07,579 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"SIS\"\\r\\n'\n", + "2026-03-30 13:31:07,580 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"SIS\"\\r\\n'\n", + "2026-03-30 13:31:07,595 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"SNR\"\\r\\n'\n", + "2026-03-30 13:31:07,595 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"SNR\"\\r\\n'\n", + "2026-03-30 13:31:07,611 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TIM\"\\r\\n'\n", + "2026-03-30 13:31:07,612 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TIM\"\\r\\n'\n", + "2026-03-30 13:31:07,628 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST0\"\\r\\n'\n", + "2026-03-30 13:31:07,629 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TST0\"\\r\\n'\n", + "2026-03-30 13:31:07,643 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST1\"\\r\\n'\n", + "2026-03-30 13:31:07,646 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TST1\"\\r\\n'\n", + "2026-03-30 13:31:07,659 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST2\"\\r\\n'\n", + "2026-03-30 13:31:07,662 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TST2\"\\r\\n'\n", + "2026-03-30 13:31:07,675 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST3\"\\r\\n'\n", + "2026-03-30 13:31:07,676 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TST3\"\\r\\n'\n", + "2026-03-30 13:31:07,693 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"UPD\"\\r\\n'\n", + "2026-03-30 13:31:07,698 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"UPD\"\\r\\n'\n", + "2026-03-30 13:31:07,707 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"FCUT\"\\r\\n'\n", + "2026-03-30 13:31:07,709 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 3 \"FCUT\"\\r\\n'\n", + "2026-03-30 13:31:07,723 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"FSET\"\\r\\n'\n", + "2026-03-30 13:31:07,726 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 3 \"FSET\"\\r\\n'\n", + "2026-03-30 13:31:07,739 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"LST\"\\r\\n'\n", + "2026-03-30 13:31:07,740 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 3 \"LST\"\\r\\n'\n", + "2026-03-30 13:31:07,755 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"RDB\"\\r\\n'\n", + "2026-03-30 13:31:07,758 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 3 \"RDB\"\\r\\n'\n", + "2026-03-30 13:31:07,772 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 A 3 \"USTB\"\\r\\n'\n", + "2026-03-30 13:31:07,773 - pylabrobot - IO - [MT Scale] Received response: b'I0 A 3 \"USTB\"\\r\\n'\n", + "2026-03-30 13:31:07,773 - pylabrobot - IO - [MT Scale] Sent command: I2\n", + "2026-03-30 13:31:07,775 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I2\\r\\n'\n", + "2026-03-30 13:31:07,835 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", + "2026-03-30 13:31:07,836 - pylabrobot - IO - [MT Scale] Received response: b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", + "2026-03-30 13:31:07,837 - pylabrobot - IO - [MT Scale] Sent command: I2\n", + "2026-03-30 13:31:07,839 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I2\\r\\n'\n", + "2026-03-30 13:31:07,898 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", + "2026-03-30 13:31:07,899 - pylabrobot - IO - [MT Scale] Received response: b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", + "2026-03-30 13:31:07,900 - pylabrobot - IO - [MT Scale] Sent command: I3\n", + "2026-03-30 13:31:07,901 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I3\\r\\n'\n", + "2026-03-30 13:31:07,946 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I3 A \"1.10 18.6.4.1361.772\"\\r\\n'\n", + "2026-03-30 13:31:07,947 - pylabrobot - IO - [MT Scale] Received response: b'I3 A \"1.10 18.6.4.1361.772\"\\r\\n'\n", + "2026-03-30 13:31:07,948 - pylabrobot - INFO - [MT Scale] Connected to Mettler Toledo scale on /dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0\n", "Device type: WXS205SDU WXA-Bridge\n", "Configuration: Bridge\n", "Serial number: B207696838\n", "Firmware: 1.10 18.6.4.1361.772\n", "Capacity: 220.0 g\n", "Supported commands: ['@', 'C0', 'C1', 'C2', 'C3', 'COM', 'DAT', 'FCUT', 'FSET', 'I0', 'I1', 'I10', 'I11', 'I14', 'I15', 'I16', 'I2', 'I21', 'I22', 'I23', 'I24', 'I25', 'I26', 'I3', 'I4', 'I5', 'LST', 'M01', 'M02', 'M03', 'M17', 'M18', 'M19', 'M20', 'M21', 'M27', 'M28', 'M29', 'M31', 'M32', 'M33', 'M35', 'RDB', 'S', 'SI', 'SIR', 'SIS', 'SNR', 'SR', 'T', 'TA', 'TAC', 'TI', 'TIM', 'TST0', 'TST1', 'TST2', 'TST3', 'UPD', 'USTB', 'Z', 'ZI']\n", - "2026-03-30 13:22:10,522 - pylabrobot - IO - [MT Scale] Sent command: M21 0 0\n", - "2026-03-30 13:22:10,526 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'M21 0 0\\r\\n'\n", - "2026-03-30 13:22:10,565 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M21 A\\r\\n'\n", - "2026-03-30 13:22:10,566 - pylabrobot - IO - [MT Scale] Received response: b'M21 A\\r\\n'\n" + "2026-03-30 13:31:07,948 - pylabrobot - IO - [MT Scale] Sent command: M21 0 0\n", + "2026-03-30 13:31:07,950 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'M21 0 0\\r\\n'\n", + "2026-03-30 13:31:07,980 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M21 A\\r\\n'\n", + "2026-03-30 13:31:07,983 - pylabrobot - IO - [MT Scale] Received response: b'M21 A\\r\\n'\n" ] } ], @@ -364,132 +364,132 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 13:22:10,635 - pylabrobot - IO - [MT Scale] Sent command: I0\n", - "2026-03-30 13:22:10,637 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I0\\r\\n'\n", - "2026-03-30 13:22:10,663 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I0\"\\r\\n'\n", - "2026-03-30 13:22:10,667 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I0\"\\r\\n'\n", - "2026-03-30 13:22:10,678 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I1\"\\r\\n'\n", - "2026-03-30 13:22:10,681 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I1\"\\r\\n'\n", - "2026-03-30 13:22:10,693 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I2\"\\r\\n'\n", - "2026-03-30 13:22:10,695 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I2\"\\r\\n'\n", - "2026-03-30 13:22:10,708 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I3\"\\r\\n'\n", - "2026-03-30 13:22:10,714 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I3\"\\r\\n'\n", - "2026-03-30 13:22:10,725 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I4\"\\r\\n'\n", - "2026-03-30 13:22:10,728 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I4\"\\r\\n'\n", - "2026-03-30 13:22:10,740 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I5\"\\r\\n'\n", - "2026-03-30 13:22:10,742 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I5\"\\r\\n'\n", - "2026-03-30 13:22:10,746 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"S\"\\r\\n'\n", - "2026-03-30 13:22:10,751 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"S\"\\r\\n'\n", - "2026-03-30 13:22:10,757 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"SI\"\\r\\n'\n", - "2026-03-30 13:22:10,758 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"SI\"\\r\\n'\n", - "2026-03-30 13:22:10,772 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"SIR\"\\r\\n'\n", - "2026-03-30 13:22:10,773 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"SIR\"\\r\\n'\n", - "2026-03-30 13:22:10,788 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"Z\"\\r\\n'\n", - "2026-03-30 13:22:10,789 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"Z\"\\r\\n'\n", - "2026-03-30 13:22:10,805 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"ZI\"\\r\\n'\n", - "2026-03-30 13:22:10,805 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"ZI\"\\r\\n'\n", - "2026-03-30 13:22:10,820 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"@\"\\r\\n'\n", - "2026-03-30 13:22:10,821 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"@\"\\r\\n'\n", - "2026-03-30 13:22:10,822 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"SR\"\\r\\n'\n", - "2026-03-30 13:22:10,822 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"SR\"\\r\\n'\n", - "2026-03-30 13:22:10,836 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"T\"\\r\\n'\n", - "2026-03-30 13:22:10,837 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"T\"\\r\\n'\n", - "2026-03-30 13:22:10,853 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"TA\"\\r\\n'\n", - "2026-03-30 13:22:10,853 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"TA\"\\r\\n'\n", - "2026-03-30 13:22:10,868 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"TAC\"\\r\\n'\n", - "2026-03-30 13:22:10,870 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"TAC\"\\r\\n'\n", - "2026-03-30 13:22:10,885 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"TI\"\\r\\n'\n", - "2026-03-30 13:22:10,886 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"TI\"\\r\\n'\n", - "2026-03-30 13:22:10,900 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C0\"\\r\\n'\n", - "2026-03-30 13:22:10,900 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"C0\"\\r\\n'\n", - "2026-03-30 13:22:10,916 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C1\"\\r\\n'\n", - "2026-03-30 13:22:10,917 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"C1\"\\r\\n'\n", - "2026-03-30 13:22:10,919 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C2\"\\r\\n'\n", - "2026-03-30 13:22:10,921 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"C2\"\\r\\n'\n", - "2026-03-30 13:22:10,932 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C3\"\\r\\n'\n", - "2026-03-30 13:22:10,933 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"C3\"\\r\\n'\n", - "2026-03-30 13:22:10,948 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"COM\"\\r\\n'\n", - "2026-03-30 13:22:10,949 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"COM\"\\r\\n'\n", - "2026-03-30 13:22:10,964 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"DAT\"\\r\\n'\n", - "2026-03-30 13:22:10,966 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"DAT\"\\r\\n'\n", - "2026-03-30 13:22:10,982 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I10\"\\r\\n'\n", - "2026-03-30 13:22:10,983 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I10\"\\r\\n'\n", - "2026-03-30 13:22:10,996 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I11\"\\r\\n'\n", - "2026-03-30 13:22:10,998 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I11\"\\r\\n'\n", - "2026-03-30 13:22:11,013 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I14\"\\r\\n'\n", - "2026-03-30 13:22:11,015 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I14\"\\r\\n'\n", - "2026-03-30 13:22:11,030 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I15\"\\r\\n'\n", - "2026-03-30 13:22:11,033 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I15\"\\r\\n'\n", - "2026-03-30 13:22:11,045 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I16\"\\r\\n'\n", - "2026-03-30 13:22:11,048 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I16\"\\r\\n'\n", - "2026-03-30 13:22:11,061 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I21\"\\r\\n'\n", - "2026-03-30 13:22:11,065 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I21\"\\r\\n'\n", - "2026-03-30 13:22:11,068 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I22\"\\r\\n'\n", - "2026-03-30 13:22:11,070 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I22\"\\r\\n'\n", - "2026-03-30 13:22:11,077 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I23\"\\r\\n'\n", - "2026-03-30 13:22:11,079 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I23\"\\r\\n'\n", - "2026-03-30 13:22:11,093 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I24\"\\r\\n'\n", - "2026-03-30 13:22:11,097 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I24\"\\r\\n'\n", - "2026-03-30 13:22:11,109 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I25\"\\r\\n'\n", - "2026-03-30 13:22:11,110 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I25\"\\r\\n'\n", - "2026-03-30 13:22:11,125 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I26\"\\r\\n'\n", - "2026-03-30 13:22:11,133 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I26\"\\r\\n'\n", - "2026-03-30 13:22:11,142 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M01\"\\r\\n'\n", - "2026-03-30 13:22:11,143 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M01\"\\r\\n'\n", - "2026-03-30 13:22:11,156 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M02\"\\r\\n'\n", - "2026-03-30 13:22:11,159 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M02\"\\r\\n'\n", - "2026-03-30 13:22:11,173 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M03\"\\r\\n'\n", - "2026-03-30 13:22:11,179 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M03\"\\r\\n'\n", - "2026-03-30 13:22:11,189 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M17\"\\r\\n'\n", - "2026-03-30 13:22:11,192 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M17\"\\r\\n'\n", - "2026-03-30 13:22:11,205 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M18\"\\r\\n'\n", - "2026-03-30 13:22:11,206 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M18\"\\r\\n'\n", - "2026-03-30 13:22:11,220 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M19\"\\r\\n'\n", - "2026-03-30 13:22:11,221 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M19\"\\r\\n'\n", - "2026-03-30 13:22:11,237 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M20\"\\r\\n'\n", - "2026-03-30 13:22:11,238 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M20\"\\r\\n'\n", - "2026-03-30 13:22:11,241 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M21\"\\r\\n'\n", - "2026-03-30 13:22:11,243 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M21\"\\r\\n'\n", - "2026-03-30 13:22:11,252 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M27\"\\r\\n'\n", - "2026-03-30 13:22:11,257 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M27\"\\r\\n'\n", - "2026-03-30 13:22:11,268 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M28\"\\r\\n'\n", - "2026-03-30 13:22:11,269 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M28\"\\r\\n'\n", - "2026-03-30 13:22:11,284 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M29\"\\r\\n'\n", - "2026-03-30 13:22:11,286 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M29\"\\r\\n'\n", - "2026-03-30 13:22:11,300 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M31\"\\r\\n'\n", - "2026-03-30 13:22:11,300 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M31\"\\r\\n'\n", - "2026-03-30 13:22:11,316 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M32\"\\r\\n'\n", - "2026-03-30 13:22:11,317 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M32\"\\r\\n'\n", - "2026-03-30 13:22:11,332 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M33\"\\r\\n'\n", - "2026-03-30 13:22:11,333 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M33\"\\r\\n'\n", - "2026-03-30 13:22:11,347 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M35\"\\r\\n'\n", - "2026-03-30 13:22:11,348 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M35\"\\r\\n'\n", - "2026-03-30 13:22:11,364 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"SIS\"\\r\\n'\n", - "2026-03-30 13:22:11,364 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"SIS\"\\r\\n'\n", - "2026-03-30 13:22:11,380 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"SNR\"\\r\\n'\n", - "2026-03-30 13:22:11,381 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"SNR\"\\r\\n'\n", - "2026-03-30 13:22:11,396 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TIM\"\\r\\n'\n", - "2026-03-30 13:22:11,396 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TIM\"\\r\\n'\n", - "2026-03-30 13:22:11,412 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST0\"\\r\\n'\n", - "2026-03-30 13:22:11,413 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TST0\"\\r\\n'\n", - "2026-03-30 13:22:11,428 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST1\"\\r\\n'\n", - "2026-03-30 13:22:11,429 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TST1\"\\r\\n'\n", - "2026-03-30 13:22:11,431 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST2\"\\r\\n'\n", - "2026-03-30 13:22:11,432 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TST2\"\\r\\n'\n", - "2026-03-30 13:22:11,444 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST3\"\\r\\n'\n", - "2026-03-30 13:22:11,445 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TST3\"\\r\\n'\n", - "2026-03-30 13:22:11,460 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"UPD\"\\r\\n'\n", - "2026-03-30 13:22:11,463 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"UPD\"\\r\\n'\n", - "2026-03-30 13:22:11,476 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"FCUT\"\\r\\n'\n", - "2026-03-30 13:22:11,477 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 3 \"FCUT\"\\r\\n'\n", - "2026-03-30 13:22:11,492 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"FSET\"\\r\\n'\n", - "2026-03-30 13:22:11,493 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 3 \"FSET\"\\r\\n'\n", - "2026-03-30 13:22:11,508 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"LST\"\\r\\n'\n", - "2026-03-30 13:22:11,509 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 3 \"LST\"\\r\\n'\n", - "2026-03-30 13:22:11,524 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"RDB\"\\r\\n'\n", - "2026-03-30 13:22:11,525 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 3 \"RDB\"\\r\\n'\n", - "2026-03-30 13:22:11,540 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 A 3 \"USTB\"\\r\\n'\n", - "2026-03-30 13:22:11,541 - pylabrobot - IO - [MT Scale] Received response: b'I0 A 3 \"USTB\"\\r\\n'\n" + "2026-03-30 13:31:08,036 - pylabrobot - IO - [MT Scale] Sent command: I0\n", + "2026-03-30 13:31:08,041 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I0\\r\\n'\n", + "2026-03-30 13:31:08,078 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I0\"\\r\\n'\n", + "2026-03-30 13:31:08,085 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I0\"\\r\\n'\n", + "2026-03-30 13:31:08,091 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I1\"\\r\\n'\n", + "2026-03-30 13:31:08,097 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I1\"\\r\\n'\n", + "2026-03-30 13:31:08,107 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I2\"\\r\\n'\n", + "2026-03-30 13:31:08,108 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I2\"\\r\\n'\n", + "2026-03-30 13:31:08,110 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I3\"\\r\\n'\n", + "2026-03-30 13:31:08,111 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I3\"\\r\\n'\n", + "2026-03-30 13:31:08,123 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I4\"\\r\\n'\n", + "2026-03-30 13:31:08,124 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I4\"\\r\\n'\n", + "2026-03-30 13:31:08,139 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I5\"\\r\\n'\n", + "2026-03-30 13:31:08,139 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I5\"\\r\\n'\n", + "2026-03-30 13:31:08,155 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"S\"\\r\\n'\n", + "2026-03-30 13:31:08,155 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"S\"\\r\\n'\n", + "2026-03-30 13:31:08,171 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"SI\"\\r\\n'\n", + "2026-03-30 13:31:08,172 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"SI\"\\r\\n'\n", + "2026-03-30 13:31:08,186 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"SIR\"\\r\\n'\n", + "2026-03-30 13:31:08,187 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"SIR\"\\r\\n'\n", + "2026-03-30 13:31:08,188 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"Z\"\\r\\n'\n", + "2026-03-30 13:31:08,189 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"Z\"\\r\\n'\n", + "2026-03-30 13:31:08,203 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"ZI\"\\r\\n'\n", + "2026-03-30 13:31:08,204 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"ZI\"\\r\\n'\n", + "2026-03-30 13:31:08,218 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"@\"\\r\\n'\n", + "2026-03-30 13:31:08,219 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"@\"\\r\\n'\n", + "2026-03-30 13:31:08,235 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"SR\"\\r\\n'\n", + "2026-03-30 13:31:08,235 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"SR\"\\r\\n'\n", + "2026-03-30 13:31:08,251 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"T\"\\r\\n'\n", + "2026-03-30 13:31:08,252 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"T\"\\r\\n'\n", + "2026-03-30 13:31:08,266 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"TA\"\\r\\n'\n", + "2026-03-30 13:31:08,267 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"TA\"\\r\\n'\n", + "2026-03-30 13:31:08,270 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"TAC\"\\r\\n'\n", + "2026-03-30 13:31:08,271 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"TAC\"\\r\\n'\n", + "2026-03-30 13:31:08,283 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"TI\"\\r\\n'\n", + "2026-03-30 13:31:08,284 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"TI\"\\r\\n'\n", + "2026-03-30 13:31:08,298 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C0\"\\r\\n'\n", + "2026-03-30 13:31:08,299 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"C0\"\\r\\n'\n", + "2026-03-30 13:31:08,315 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C1\"\\r\\n'\n", + "2026-03-30 13:31:08,315 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"C1\"\\r\\n'\n", + "2026-03-30 13:31:08,331 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C2\"\\r\\n'\n", + "2026-03-30 13:31:08,332 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"C2\"\\r\\n'\n", + "2026-03-30 13:31:08,346 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C3\"\\r\\n'\n", + "2026-03-30 13:31:08,347 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"C3\"\\r\\n'\n", + "2026-03-30 13:31:08,362 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"COM\"\\r\\n'\n", + "2026-03-30 13:31:08,363 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"COM\"\\r\\n'\n", + "2026-03-30 13:31:08,378 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"DAT\"\\r\\n'\n", + "2026-03-30 13:31:08,379 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"DAT\"\\r\\n'\n", + "2026-03-30 13:31:08,381 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I10\"\\r\\n'\n", + "2026-03-30 13:31:08,382 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I10\"\\r\\n'\n", + "2026-03-30 13:31:08,394 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I11\"\\r\\n'\n", + "2026-03-30 13:31:08,395 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I11\"\\r\\n'\n", + "2026-03-30 13:31:08,412 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I14\"\\r\\n'\n", + "2026-03-30 13:31:08,413 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I14\"\\r\\n'\n", + "2026-03-30 13:31:08,426 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I15\"\\r\\n'\n", + "2026-03-30 13:31:08,427 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I15\"\\r\\n'\n", + "2026-03-30 13:31:08,443 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I16\"\\r\\n'\n", + "2026-03-30 13:31:08,444 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I16\"\\r\\n'\n", + "2026-03-30 13:31:08,458 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I21\"\\r\\n'\n", + "2026-03-30 13:31:08,459 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I21\"\\r\\n'\n", + "2026-03-30 13:31:08,474 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I22\"\\r\\n'\n", + "2026-03-30 13:31:08,475 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I22\"\\r\\n'\n", + "2026-03-30 13:31:08,491 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I23\"\\r\\n'\n", + "2026-03-30 13:31:08,491 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I23\"\\r\\n'\n", + "2026-03-30 13:31:08,506 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I24\"\\r\\n'\n", + "2026-03-30 13:31:08,507 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I24\"\\r\\n'\n", + "2026-03-30 13:31:08,522 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I25\"\\r\\n'\n", + "2026-03-30 13:31:08,523 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I25\"\\r\\n'\n", + "2026-03-30 13:31:08,538 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I26\"\\r\\n'\n", + "2026-03-30 13:31:08,538 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I26\"\\r\\n'\n", + "2026-03-30 13:31:08,540 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M01\"\\r\\n'\n", + "2026-03-30 13:31:08,540 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M01\"\\r\\n'\n", + "2026-03-30 13:31:08,554 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M02\"\\r\\n'\n", + "2026-03-30 13:31:08,555 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M02\"\\r\\n'\n", + "2026-03-30 13:31:08,570 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M03\"\\r\\n'\n", + "2026-03-30 13:31:08,571 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M03\"\\r\\n'\n", + "2026-03-30 13:31:08,586 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M17\"\\r\\n'\n", + "2026-03-30 13:31:08,587 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M17\"\\r\\n'\n", + "2026-03-30 13:31:08,602 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M18\"\\r\\n'\n", + "2026-03-30 13:31:08,603 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M18\"\\r\\n'\n", + "2026-03-30 13:31:08,619 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M19\"\\r\\n'\n", + "2026-03-30 13:31:08,619 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M19\"\\r\\n'\n", + "2026-03-30 13:31:08,634 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M20\"\\r\\n'\n", + "2026-03-30 13:31:08,635 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M20\"\\r\\n'\n", + "2026-03-30 13:31:08,650 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M21\"\\r\\n'\n", + "2026-03-30 13:31:08,651 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M21\"\\r\\n'\n", + "2026-03-30 13:31:08,666 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M27\"\\r\\n'\n", + "2026-03-30 13:31:08,666 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M27\"\\r\\n'\n", + "2026-03-30 13:31:08,682 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M28\"\\r\\n'\n", + "2026-03-30 13:31:08,683 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M28\"\\r\\n'\n", + "2026-03-30 13:31:08,698 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M29\"\\r\\n'\n", + "2026-03-30 13:31:08,699 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M29\"\\r\\n'\n", + "2026-03-30 13:31:08,700 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M31\"\\r\\n'\n", + "2026-03-30 13:31:08,701 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M31\"\\r\\n'\n", + "2026-03-30 13:31:08,717 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M32\"\\r\\n'\n", + "2026-03-30 13:31:08,718 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M32\"\\r\\n'\n", + "2026-03-30 13:31:08,730 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M33\"\\r\\n'\n", + "2026-03-30 13:31:08,731 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M33\"\\r\\n'\n", + "2026-03-30 13:31:08,747 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M35\"\\r\\n'\n", + "2026-03-30 13:31:08,747 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M35\"\\r\\n'\n", + "2026-03-30 13:31:08,762 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"SIS\"\\r\\n'\n", + "2026-03-30 13:31:08,763 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"SIS\"\\r\\n'\n", + "2026-03-30 13:31:08,779 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"SNR\"\\r\\n'\n", + "2026-03-30 13:31:08,780 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"SNR\"\\r\\n'\n", + "2026-03-30 13:31:08,794 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TIM\"\\r\\n'\n", + "2026-03-30 13:31:08,795 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TIM\"\\r\\n'\n", + "2026-03-30 13:31:08,810 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST0\"\\r\\n'\n", + "2026-03-30 13:31:08,812 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TST0\"\\r\\n'\n", + "2026-03-30 13:31:08,825 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST1\"\\r\\n'\n", + "2026-03-30 13:31:08,827 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TST1\"\\r\\n'\n", + "2026-03-30 13:31:08,842 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST2\"\\r\\n'\n", + "2026-03-30 13:31:08,843 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TST2\"\\r\\n'\n", + "2026-03-30 13:31:08,858 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST3\"\\r\\n'\n", + "2026-03-30 13:31:08,859 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TST3\"\\r\\n'\n", + "2026-03-30 13:31:08,873 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"UPD\"\\r\\n'\n", + "2026-03-30 13:31:08,875 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"UPD\"\\r\\n'\n", + "2026-03-30 13:31:08,890 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"FCUT\"\\r\\n'\n", + "2026-03-30 13:31:08,891 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 3 \"FCUT\"\\r\\n'\n", + "2026-03-30 13:31:08,906 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"FSET\"\\r\\n'\n", + "2026-03-30 13:31:08,907 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 3 \"FSET\"\\r\\n'\n", + "2026-03-30 13:31:08,922 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"LST\"\\r\\n'\n", + "2026-03-30 13:31:08,922 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 3 \"LST\"\\r\\n'\n", + "2026-03-30 13:31:08,938 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"RDB\"\\r\\n'\n", + "2026-03-30 13:31:08,939 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 3 \"RDB\"\\r\\n'\n", + "2026-03-30 13:31:08,953 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 A 3 \"USTB\"\\r\\n'\n", + "2026-03-30 13:31:08,954 - pylabrobot - IO - [MT Scale] Received response: b'I0 A 3 \"USTB\"\\r\\n'\n" ] }, { @@ -605,20 +605,24 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 13:22:11,575 - pylabrobot - IO - [MT Scale] Sent command: I3\n", - "2026-03-30 13:22:11,583 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I3\\r\\n'\n", - "2026-03-30 13:22:11,637 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I3 A \"1.10 18.6.4.1361.772\"\\r\\n'\n", - "2026-03-30 13:22:11,642 - pylabrobot - IO - [MT Scale] Received response: b'I3 A \"1.10 18.6.4.1361.772\"\\r\\n'\n", - "2026-03-30 13:22:11,643 - pylabrobot - IO - [MT Scale] Sent command: I5\n", - "2026-03-30 13:22:11,648 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I5\\r\\n'\n", - "2026-03-30 13:22:11,684 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I5 A \"11671158C\"\\r\\n'\n", - "2026-03-30 13:22:11,684 - pylabrobot - IO - [MT Scale] Received response: b'I5 A \"11671158C\"\\r\\n'\n", - "2026-03-30 13:22:11,687 - pylabrobot - IO - [MT Scale] Sent command: I10\n", - "2026-03-30 13:22:11,688 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I10\\r\\n'\n", - "2026-03-30 13:22:11,716 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I10 A \"\"\\r\\n'\n", - "2026-03-30 13:22:11,718 - pylabrobot - IO - [MT Scale] Received response: b'I10 A \"\"\\r\\n'\n", - "2026-03-30 13:22:11,720 - pylabrobot - IO - [MT Scale] Sent command: I11\n", - "2026-03-30 13:22:11,726 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I11\\r\\n'\n" + "2026-03-30 13:31:08,965 - pylabrobot - IO - [MT Scale] Sent command: I3\n", + "2026-03-30 13:31:08,967 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I3\\r\\n'\n", + "2026-03-30 13:31:09,018 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I3 A \"1.10 18.6.4.1361.772\"\\r\\n'\n", + "2026-03-30 13:31:09,021 - pylabrobot - IO - [MT Scale] Received response: b'I3 A \"1.10 18.6.4.1361.772\"\\r\\n'\n", + "2026-03-30 13:31:09,023 - pylabrobot - IO - [MT Scale] Sent command: I5\n", + "2026-03-30 13:31:09,025 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I5\\r\\n'\n", + "2026-03-30 13:31:09,066 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I5 A \"11671158C\"\\r\\n'\n", + "2026-03-30 13:31:09,066 - pylabrobot - IO - [MT Scale] Received response: b'I5 A \"11671158C\"\\r\\n'\n", + "2026-03-30 13:31:09,067 - pylabrobot - IO - [MT Scale] Sent command: I10\n", + "2026-03-30 13:31:09,069 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I10\\r\\n'\n", + "2026-03-30 13:31:09,097 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I10 A \"\"\\r\\n'\n", + "2026-03-30 13:31:09,098 - pylabrobot - IO - [MT Scale] Received response: b'I10 A \"\"\\r\\n'\n", + "2026-03-30 13:31:09,099 - pylabrobot - IO - [MT Scale] Sent command: I11\n", + "2026-03-30 13:31:09,101 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I11\\r\\n'\n", + "2026-03-30 13:31:09,145 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I11 A \"WXS205SDU\"\\r\\n'\n", + "2026-03-30 13:31:09,146 - pylabrobot - IO - [MT Scale] Received response: b'I11 A \"WXS205SDU\"\\r\\n'\n", + "2026-03-30 13:31:09,147 - pylabrobot - IO - [MT Scale] Sent command: I15\n", + "2026-03-30 13:31:09,149 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I15\\r\\n'\n" ] }, { @@ -627,47 +631,47 @@ "text": [ "Software version: 1.10 18.6.4.1361.772\n", "Software material number: 11671158C\n", - "Device ID: ''\n" + "Device ID: ''\n", + "Model designation: WXS205SDU\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 13:22:11,764 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I11 A \"WXS205SDU\"\\r\\n'\n", - "2026-03-30 13:22:11,764 - pylabrobot - IO - [MT Scale] Received response: b'I11 A \"WXS205SDU\"\\r\\n'\n", - "2026-03-30 13:22:11,765 - pylabrobot - IO - [MT Scale] Sent command: I15\n", - "2026-03-30 13:22:11,767 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I15\\r\\n'\n", - "2026-03-30 13:22:11,796 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I15 A 234\\r\\n'\n", - "2026-03-30 13:22:11,797 - pylabrobot - IO - [MT Scale] Received response: b'I15 A 234\\r\\n'\n", - "2026-03-30 13:22:11,800 - pylabrobot - IO - [MT Scale] Sent command: DAT\n", - "2026-03-30 13:22:11,803 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'DAT\\r\\n'\n", - "2026-03-30 13:22:11,843 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'DAT A 04 01 2000\\r\\n'\n" + "2026-03-30 13:31:09,178 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I15 A 243\\r\\n'\n", + "2026-03-30 13:31:09,179 - pylabrobot - IO - [MT Scale] Received response: b'I15 A 243\\r\\n'\n", + "2026-03-30 13:31:09,180 - pylabrobot - IO - [MT Scale] Sent command: DAT\n", + "2026-03-30 13:31:09,182 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'DAT\\r\\n'\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ - "Model designation: WXS205SDU\n", - "Uptime: 234d 0h 0m 0s\n" + "Uptime: 243d 0h 0m 0s\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 13:22:11,844 - pylabrobot - IO - [MT Scale] Received response: b'DAT A 04 01 2000\\r\\n'\n", - "2026-03-30 13:22:11,846 - pylabrobot - IO - [MT Scale] Sent command: TIM\n", - "2026-03-30 13:22:11,847 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'TIM\\r\\n'\n", - "2026-03-30 13:22:11,876 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'TIM A 20 27 38\\r\\n'\n", - "2026-03-30 13:22:11,876 - pylabrobot - IO - [MT Scale] Received response: b'TIM A 20 27 38\\r\\n'\n", - "2026-03-30 13:22:11,877 - pylabrobot - IO - [MT Scale] Sent command: I14 0\n", - "2026-03-30 13:22:11,879 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I14 0\\r\\n'\n", - "2026-03-30 13:22:11,924 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I14 A 0 1 \"Bridge\"\\r\\n'\n", - "2026-03-30 13:22:11,924 - pylabrobot - IO - [MT Scale] Received response: b'I14 A 0 1 \"Bridge\"\\r\\n'\n", - "2026-03-30 13:22:11,925 - pylabrobot - IO - [MT Scale] Sent command: I14 1\n", - "2026-03-30 13:22:11,926 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I14 1\\r\\n'\n" + "2026-03-30 13:31:09,225 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'DAT A 04 01 2000\\r\\n'\n", + "2026-03-30 13:31:09,226 - pylabrobot - IO - [MT Scale] Received response: b'DAT A 04 01 2000\\r\\n'\n", + "2026-03-30 13:31:09,228 - pylabrobot - IO - [MT Scale] Sent command: TIM\n", + "2026-03-30 13:31:09,230 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'TIM\\r\\n'\n", + "2026-03-30 13:31:09,273 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'TIM A 20 36 35\\r\\n'\n", + "2026-03-30 13:31:09,274 - pylabrobot - IO - [MT Scale] Received response: b'TIM A 20 36 35\\r\\n'\n", + "2026-03-30 13:31:09,275 - pylabrobot - IO - [MT Scale] Sent command: I14 0\n", + "2026-03-30 13:31:09,278 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I14 0\\r\\n'\n", + "2026-03-30 13:31:09,321 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I14 A 0 1 \"Bridge\"\\r\\n'\n", + "2026-03-30 13:31:09,322 - pylabrobot - IO - [MT Scale] Received response: b'I14 A 0 1 \"Bridge\"\\r\\n'\n", + "2026-03-30 13:31:09,323 - pylabrobot - IO - [MT Scale] Sent command: I14 1\n", + "2026-03-30 13:31:09,325 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I14 1\\r\\n'\n", + "2026-03-30 13:31:09,369 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I14 A 1 1 \"WXS205SDU\"\\r\\n'\n", + "2026-03-30 13:31:09,370 - pylabrobot - IO - [MT Scale] Received response: b'I14 A 1 1 \"WXS205SDU\"\\r\\n'\n", + "2026-03-30 13:31:09,371 - pylabrobot - IO - [MT Scale] Sent command: I14 2\n", + "2026-03-30 13:31:09,372 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I14 2\\r\\n'\n" ] }, { @@ -679,29 +683,25 @@ "\n", "Device info (I14):\n", " Category 0 (Instrument configuration):\n", - " I14 A 0 1 Bridge\n" + " I14 A 0 1 Bridge\n", + " Category 1 (Instrument descriptions):\n", + " I14 A 1 1 WXS205SDU\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 13:22:11,972 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I14 A 1 1 \"WXS205SDU\"\\r\\n'\n", - "2026-03-30 13:22:11,972 - pylabrobot - IO - [MT Scale] Received response: b'I14 A 1 1 \"WXS205SDU\"\\r\\n'\n", - "2026-03-30 13:22:11,973 - pylabrobot - IO - [MT Scale] Sent command: I14 2\n", - "2026-03-30 13:22:11,974 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I14 2\\r\\n'\n", - "2026-03-30 13:22:12,020 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I14 A 2 1 \"11671158C\"\\r\\n'\n", - "2026-03-30 13:22:12,020 - pylabrobot - IO - [MT Scale] Received response: b'I14 A 2 1 \"11671158C\"\\r\\n'\n", - "2026-03-30 13:22:12,021 - pylabrobot - IO - [MT Scale] Sent command: I14 3\n", - "2026-03-30 13:22:12,022 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I14 3\\r\\n'\n" + "2026-03-30 13:31:09,417 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I14 A 2 1 \"11671158C\"\\r\\n'\n", + "2026-03-30 13:31:09,418 - pylabrobot - IO - [MT Scale] Received response: b'I14 A 2 1 \"11671158C\"\\r\\n'\n", + "2026-03-30 13:31:09,419 - pylabrobot - IO - [MT Scale] Sent command: I14 3\n", + "2026-03-30 13:31:09,420 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I14 3\\r\\n'\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ - " Category 1 (Instrument descriptions):\n", - " I14 A 1 1 WXS205SDU\n", " Category 2 (SW identification numbers):\n", " I14 A 2 1 11671158C\n" ] @@ -710,16 +710,16 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 13:22:12,068 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I14 A 3 1 \"1.10\"\\r\\n'\n", - "2026-03-30 13:22:12,068 - pylabrobot - IO - [MT Scale] Received response: b'I14 A 3 1 \"1.10\"\\r\\n'\n", - "2026-03-30 13:22:12,069 - pylabrobot - IO - [MT Scale] Sent command: I14 4\n", - "2026-03-30 13:22:12,071 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I14 4\\r\\n'\n", - "2026-03-30 13:22:12,116 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I14 A 4 1 \"B207696838\"\\r\\n'\n", - "2026-03-30 13:22:12,116 - pylabrobot - IO - [MT Scale] Received response: b'I14 A 4 1 \"B207696838\"\\r\\n'\n", - "2026-03-30 13:22:12,117 - pylabrobot - IO - [MT Scale] Sent command: I14 5\n", - "2026-03-30 13:22:12,118 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I14 5\\r\\n'\n", - "2026-03-30 13:22:12,166 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I14 A 5 1 \"18.6.4.1361.772\"\\r\\n'\n", - "2026-03-30 13:22:12,172 - pylabrobot - IO - [MT Scale] Received response: b'I14 A 5 1 \"18.6.4.1361.772\"\\r\\n'\n" + "2026-03-30 13:31:09,465 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I14 A 3 1 \"1.10\"\\r\\n'\n", + "2026-03-30 13:31:09,466 - pylabrobot - IO - [MT Scale] Received response: b'I14 A 3 1 \"1.10\"\\r\\n'\n", + "2026-03-30 13:31:09,467 - pylabrobot - IO - [MT Scale] Sent command: I14 4\n", + "2026-03-30 13:31:09,468 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I14 4\\r\\n'\n", + "2026-03-30 13:31:09,513 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I14 A 4 1 \"B207696838\"\\r\\n'\n", + "2026-03-30 13:31:09,514 - pylabrobot - IO - [MT Scale] Received response: b'I14 A 4 1 \"B207696838\"\\r\\n'\n", + "2026-03-30 13:31:09,515 - pylabrobot - IO - [MT Scale] Sent command: I14 5\n", + "2026-03-30 13:31:09,516 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I14 5\\r\\n'\n", + "2026-03-30 13:31:09,561 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I14 A 5 1 \"18.6.4.1361.772\"\\r\\n'\n", + "2026-03-30 13:31:09,562 - pylabrobot - IO - [MT Scale] Received response: b'I14 A 5 1 \"18.6.4.1361.772\"\\r\\n'\n" ] }, { @@ -826,59 +826,59 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 13:22:12,193 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] reset_input_buffer\n", - "2026-03-30 13:22:12,196 - pylabrobot - IO - [MT Scale] Sent command: @\n", - "2026-03-30 13:22:12,207 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'@\\r\\n'\n", - "2026-03-30 13:22:12,262 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I4 A \"B207696838\"\\r\\n'\n", - "2026-03-30 13:22:12,264 - pylabrobot - IO - [MT Scale] Received response: b'I4 A \"B207696838\"\\r\\n'\n", - "2026-03-30 13:22:12,267 - pylabrobot - IO - [MT Scale] Sent command: I4\n", - "2026-03-30 13:22:12,273 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I4\\r\\n'\n", - "2026-03-30 13:22:12,308 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I4 A \"B207696838\"\\r\\n'\n", - "2026-03-30 13:22:12,312 - pylabrobot - IO - [MT Scale] Received response: b'I4 A \"B207696838\"\\r\\n'\n", - "2026-03-30 13:22:12,314 - pylabrobot - IO - [MT Scale] Sent command: I2\n", - "2026-03-30 13:22:12,315 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I2\\r\\n'\n", - "2026-03-30 13:22:12,371 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", - "2026-03-30 13:22:12,372 - pylabrobot - IO - [MT Scale] Received response: b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", - "2026-03-30 13:22:12,374 - pylabrobot - IO - [MT Scale] Sent command: I2\n", - "2026-03-30 13:22:12,377 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I2\\r\\n'\n", - "2026-03-30 13:22:12,435 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", - "2026-03-30 13:22:12,437 - pylabrobot - IO - [MT Scale] Received response: b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", - "2026-03-30 13:22:12,440 - pylabrobot - IO - [MT Scale] Sent command: S\n", - "2026-03-30 13:22:12,446 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", - "2026-03-30 13:22:12,771 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00005 g\\r\\n'\n", - "2026-03-30 13:22:12,772 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00005 g\\r\\n'\n", - "2026-03-30 13:22:12,773 - pylabrobot - IO - [MT Scale] Sent command: SI\n", - "2026-03-30 13:22:12,777 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", - "2026-03-30 13:22:12,819 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00005 g\\r\\n'\n", - "2026-03-30 13:22:12,820 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00005 g\\r\\n'\n", - "2026-03-30 13:22:12,821 - pylabrobot - IO - [MT Scale] Sent command: Z\n", - "2026-03-30 13:22:12,823 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'Z\\r\\n'\n", - "2026-03-30 13:22:13,155 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'Z A\\r\\n'\n", - "2026-03-30 13:22:13,155 - pylabrobot - IO - [MT Scale] Received response: b'Z A\\r\\n'\n", - "2026-03-30 13:22:13,156 - pylabrobot - IO - [MT Scale] Sent command: SI\n", - "2026-03-30 13:22:13,157 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", - "2026-03-30 13:22:13,186 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 13:22:13,187 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 13:22:13,188 - pylabrobot - IO - [MT Scale] Sent command: ZI\n", - "2026-03-30 13:22:13,190 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'ZI\\r\\n'\n", - "2026-03-30 13:22:13,218 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'ZI S\\r\\n'\n", - "2026-03-30 13:22:13,219 - pylabrobot - IO - [MT Scale] Received response: b'ZI S\\r\\n'\n", - "2026-03-30 13:22:13,219 - pylabrobot - IO - [MT Scale] Sent command: SI\n", - "2026-03-30 13:22:13,221 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", - "2026-03-30 13:22:13,251 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 13:22:13,251 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 13:22:13,252 - pylabrobot - IO - [MT Scale] Sent command: TA\n", - "2026-03-30 13:22:13,253 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'TA\\r\\n'\n", - "2026-03-30 13:22:13,363 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'TA A 0.00000 g\\r\\n'\n", - "2026-03-30 13:22:13,363 - pylabrobot - IO - [MT Scale] Received response: b'TA A 0.00000 g\\r\\n'\n", - "2026-03-30 13:22:13,364 - pylabrobot - IO - [MT Scale] Sent command: TAC\n", - "2026-03-30 13:22:13,366 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'TAC\\r\\n'\n", - "2026-03-30 13:22:13,394 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'TAC A\\r\\n'\n", - "2026-03-30 13:22:13,395 - pylabrobot - IO - [MT Scale] Received response: b'TAC A\\r\\n'\n", - "2026-03-30 13:22:13,396 - pylabrobot - IO - [MT Scale] Sent command: TA\n", - "2026-03-30 13:22:13,397 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'TA\\r\\n'\n", - "2026-03-30 13:22:13,474 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'TA A 0.00000 g\\r\\n'\n", - "2026-03-30 13:22:13,475 - pylabrobot - IO - [MT Scale] Received response: b'TA A 0.00000 g\\r\\n'\n" + "2026-03-30 13:31:09,573 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] reset_input_buffer\n", + "2026-03-30 13:31:09,575 - pylabrobot - IO - [MT Scale] Sent command: @\n", + "2026-03-30 13:31:09,577 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'@\\r\\n'\n", + "2026-03-30 13:31:09,641 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I4 A \"B207696838\"\\r\\n'\n", + "2026-03-30 13:31:09,642 - pylabrobot - IO - [MT Scale] Received response: b'I4 A \"B207696838\"\\r\\n'\n", + "2026-03-30 13:31:09,643 - pylabrobot - IO - [MT Scale] Sent command: I4\n", + "2026-03-30 13:31:09,645 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I4\\r\\n'\n", + "2026-03-30 13:31:09,689 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I4 A \"B207696838\"\\r\\n'\n", + "2026-03-30 13:31:09,690 - pylabrobot - IO - [MT Scale] Received response: b'I4 A \"B207696838\"\\r\\n'\n", + "2026-03-30 13:31:09,691 - pylabrobot - IO - [MT Scale] Sent command: I2\n", + "2026-03-30 13:31:09,693 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I2\\r\\n'\n", + "2026-03-30 13:31:09,753 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", + "2026-03-30 13:31:09,753 - pylabrobot - IO - [MT Scale] Received response: b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", + "2026-03-30 13:31:09,754 - pylabrobot - IO - [MT Scale] Sent command: I2\n", + "2026-03-30 13:31:09,756 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I2\\r\\n'\n", + "2026-03-30 13:31:09,817 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", + "2026-03-30 13:31:09,818 - pylabrobot - IO - [MT Scale] Received response: b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", + "2026-03-30 13:31:09,820 - pylabrobot - IO - [MT Scale] Sent command: S\n", + "2026-03-30 13:31:09,821 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", + "2026-03-30 13:31:10,136 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S -0.00005 g\\r\\n'\n", + "2026-03-30 13:31:10,137 - pylabrobot - IO - [MT Scale] Received response: b'S S -0.00005 g\\r\\n'\n", + "2026-03-30 13:31:10,138 - pylabrobot - IO - [MT Scale] Sent command: SI\n", + "2026-03-30 13:31:10,139 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", + "2026-03-30 13:31:10,168 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S -0.00005 g\\r\\n'\n", + "2026-03-30 13:31:10,169 - pylabrobot - IO - [MT Scale] Received response: b'S S -0.00005 g\\r\\n'\n", + "2026-03-30 13:31:10,170 - pylabrobot - IO - [MT Scale] Sent command: Z\n", + "2026-03-30 13:31:10,171 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'Z\\r\\n'\n", + "2026-03-30 13:31:10,408 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'Z A\\r\\n'\n", + "2026-03-30 13:31:10,409 - pylabrobot - IO - [MT Scale] Received response: b'Z A\\r\\n'\n", + "2026-03-30 13:31:10,411 - pylabrobot - IO - [MT Scale] Sent command: SI\n", + "2026-03-30 13:31:10,414 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", + "2026-03-30 13:31:10,456 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 13:31:10,457 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 13:31:10,458 - pylabrobot - IO - [MT Scale] Sent command: ZI\n", + "2026-03-30 13:31:10,461 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'ZI\\r\\n'\n", + "2026-03-30 13:31:10,488 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'ZI S\\r\\n'\n", + "2026-03-30 13:31:10,489 - pylabrobot - IO - [MT Scale] Received response: b'ZI S\\r\\n'\n", + "2026-03-30 13:31:10,489 - pylabrobot - IO - [MT Scale] Sent command: SI\n", + "2026-03-30 13:31:10,491 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", + "2026-03-30 13:31:10,521 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 13:31:10,521 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 13:31:10,522 - pylabrobot - IO - [MT Scale] Sent command: TA\n", + "2026-03-30 13:31:10,524 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'TA\\r\\n'\n", + "2026-03-30 13:31:10,632 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'TA A 0.00000 g\\r\\n'\n", + "2026-03-30 13:31:10,633 - pylabrobot - IO - [MT Scale] Received response: b'TA A 0.00000 g\\r\\n'\n", + "2026-03-30 13:31:10,634 - pylabrobot - IO - [MT Scale] Sent command: TAC\n", + "2026-03-30 13:31:10,635 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'TAC\\r\\n'\n", + "2026-03-30 13:31:10,664 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'TAC A\\r\\n'\n", + "2026-03-30 13:31:10,665 - pylabrobot - IO - [MT Scale] Received response: b'TAC A\\r\\n'\n", + "2026-03-30 13:31:10,666 - pylabrobot - IO - [MT Scale] Sent command: TA\n", + "2026-03-30 13:31:10,667 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'TA\\r\\n'\n", + "2026-03-30 13:31:10,728 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'TA A 0.00000 g\\r\\n'\n", + "2026-03-30 13:31:10,728 - pylabrobot - IO - [MT Scale] Received response: b'TA A 0.00000 g\\r\\n'\n" ] }, { @@ -967,18 +967,18 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 13:22:27,132 - pylabrobot - IO - [MT Scale] Sent command: Z\n", - "2026-03-30 13:22:27,134 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'Z\\r\\n'\n", - "2026-03-30 13:22:27,509 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'Z A\\r\\n'\n", - "2026-03-30 13:22:27,510 - pylabrobot - IO - [MT Scale] Received response: b'Z A\\r\\n'\n", - "2026-03-30 13:22:27,511 - pylabrobot - IO - [MT Scale] Sent command: T\n", - "2026-03-30 13:22:27,512 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'T\\r\\n'\n", - "2026-03-30 13:22:27,925 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'T S 0.00000 g\\r\\n'\n", - "2026-03-30 13:22:27,925 - pylabrobot - IO - [MT Scale] Received response: b'T S 0.00000 g\\r\\n'\n", - "2026-03-30 13:22:27,926 - pylabrobot - IO - [MT Scale] Sent command: TA\n", - "2026-03-30 13:22:27,927 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'TA\\r\\n'\n", - "2026-03-30 13:22:28,021 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'TA A 0.00000 g\\r\\n'\n", - "2026-03-30 13:22:28,022 - pylabrobot - IO - [MT Scale] Received response: b'TA A 0.00000 g\\r\\n'\n" + "2026-03-30 13:31:19,963 - pylabrobot - IO - [MT Scale] Sent command: Z\n", + "2026-03-30 13:31:19,967 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'Z\\r\\n'\n", + "2026-03-30 13:31:20,240 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'Z A\\r\\n'\n", + "2026-03-30 13:31:20,240 - pylabrobot - IO - [MT Scale] Received response: b'Z A\\r\\n'\n", + "2026-03-30 13:31:20,242 - pylabrobot - IO - [MT Scale] Sent command: T\n", + "2026-03-30 13:31:20,243 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'T\\r\\n'\n", + "2026-03-30 13:31:20,657 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'T S 0.00000 g\\r\\n'\n", + "2026-03-30 13:31:20,661 - pylabrobot - IO - [MT Scale] Received response: b'T S 0.00000 g\\r\\n'\n", + "2026-03-30 13:31:20,664 - pylabrobot - IO - [MT Scale] Sent command: TA\n", + "2026-03-30 13:31:20,667 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'TA\\r\\n'\n", + "2026-03-30 13:31:20,751 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'TA A 0.00000 g\\r\\n'\n", + "2026-03-30 13:31:20,751 - pylabrobot - IO - [MT Scale] Received response: b'TA A 0.00000 g\\r\\n'\n" ] }, { @@ -1026,10 +1026,10 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 13:22:31,147 - pylabrobot - IO - [MT Scale] Sent command: TA\n", - "2026-03-30 13:22:31,151 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'TA\\r\\n'\n", - "2026-03-30 13:22:31,251 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'TA A 0.00000 g\\r\\n'\n", - "2026-03-30 13:22:31,252 - pylabrobot - IO - [MT Scale] Received response: b'TA A 0.00000 g\\r\\n'\n" + "2026-03-30 13:31:22,655 - pylabrobot - IO - [MT Scale] Sent command: TA\n", + "2026-03-30 13:31:22,658 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'TA\\r\\n'\n", + "2026-03-30 13:31:22,717 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'TA A 0.00000 g\\r\\n'\n", + "2026-03-30 13:31:22,719 - pylabrobot - IO - [MT Scale] Received response: b'TA A 0.00000 g\\r\\n'\n" ] }, { @@ -1064,14 +1064,14 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 13:22:32,399 - pylabrobot - IO - [MT Scale] Sent command: TAC\n", - "2026-03-30 13:22:32,401 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'TAC\\r\\n'\n", - "2026-03-30 13:22:32,434 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'TAC A\\r\\n'\n", - "2026-03-30 13:22:32,435 - pylabrobot - IO - [MT Scale] Received response: b'TAC A\\r\\n'\n", - "2026-03-30 13:22:32,436 - pylabrobot - IO - [MT Scale] Sent command: TA\n", - "2026-03-30 13:22:32,440 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'TA\\r\\n'\n", - "2026-03-30 13:22:32,532 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'TA A 0.00000 g\\r\\n'\n", - "2026-03-30 13:22:32,533 - pylabrobot - IO - [MT Scale] Received response: b'TA A 0.00000 g\\r\\n'\n" + "2026-03-30 13:31:23,482 - pylabrobot - IO - [MT Scale] Sent command: TAC\n", + "2026-03-30 13:31:23,485 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'TAC\\r\\n'\n", + "2026-03-30 13:31:23,517 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'TAC A\\r\\n'\n", + "2026-03-30 13:31:23,518 - pylabrobot - IO - [MT Scale] Received response: b'TAC A\\r\\n'\n", + "2026-03-30 13:31:23,519 - pylabrobot - IO - [MT Scale] Sent command: TA\n", + "2026-03-30 13:31:23,522 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'TA\\r\\n'\n", + "2026-03-30 13:31:23,597 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'TA A 0.00000 g\\r\\n'\n", + "2026-03-30 13:31:23,599 - pylabrobot - IO - [MT Scale] Received response: b'TA A 0.00000 g\\r\\n'\n" ] }, { @@ -1115,10 +1115,10 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 13:22:34,042 - pylabrobot - IO - [MT Scale] Sent command: M21 0 0\n", - "2026-03-30 13:22:34,044 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'M21 0 0\\r\\n'\n", - "2026-03-30 13:22:34,082 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M21 A\\r\\n'\n", - "2026-03-30 13:22:34,085 - pylabrobot - IO - [MT Scale] Received response: b'M21 A\\r\\n'\n" + "2026-03-30 13:31:24,453 - pylabrobot - IO - [MT Scale] Sent command: M21 0 0\n", + "2026-03-30 13:31:24,457 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'M21 0 0\\r\\n'\n", + "2026-03-30 13:31:24,492 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M21 A\\r\\n'\n", + "2026-03-30 13:31:24,493 - pylabrobot - IO - [MT Scale] Received response: b'M21 A\\r\\n'\n" ] }, { @@ -1184,12 +1184,12 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 13:22:37,302 - pylabrobot - IO - [MT Scale] Sent command: M28\n", - "2026-03-30 13:22:37,305 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'M28\\r\\n'\n", - "2026-03-30 13:22:37,341 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M28 B 1 20.1\\r\\n'\n", - "2026-03-30 13:22:37,342 - pylabrobot - IO - [MT Scale] Received response: b'M28 B 1 20.1\\r\\n'\n", - "2026-03-30 13:22:37,359 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M28 A 2 19.6\\r\\n'\n", - "2026-03-30 13:22:37,360 - pylabrobot - IO - [MT Scale] Received response: b'M28 A 2 19.6\\r\\n'\n" + "2026-03-30 13:31:26,300 - pylabrobot - IO - [MT Scale] Sent command: M28\n", + "2026-03-30 13:31:26,303 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'M28\\r\\n'\n", + "2026-03-30 13:31:26,330 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M28 B 1 20.1\\r\\n'\n", + "2026-03-30 13:31:26,331 - pylabrobot - IO - [MT Scale] Received response: b'M28 B 1 20.1\\r\\n'\n", + "2026-03-30 13:31:26,347 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M28 A 2 19.6\\r\\n'\n", + "2026-03-30 13:31:26,348 - pylabrobot - IO - [MT Scale] Received response: b'M28 A 2 19.6\\r\\n'\n" ] }, { @@ -1229,26 +1229,26 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 13:22:39,846 - pylabrobot - IO - [MT Scale] Sent command: M01\n", - "2026-03-30 13:22:39,848 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'M01\\r\\n'\n", - "2026-03-30 13:22:39,883 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M01 A 0\\r\\n'\n", - "2026-03-30 13:22:39,883 - pylabrobot - IO - [MT Scale] Received response: b'M01 A 0\\r\\n'\n", - "2026-03-30 13:22:39,885 - pylabrobot - IO - [MT Scale] Sent command: M02\n", - "2026-03-30 13:22:39,887 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'M02\\r\\n'\n", - "2026-03-30 13:22:39,915 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M02 A 2\\r\\n'\n", - "2026-03-30 13:22:39,917 - pylabrobot - IO - [MT Scale] Received response: b'M02 A 2\\r\\n'\n", - "2026-03-30 13:22:39,918 - pylabrobot - IO - [MT Scale] Sent command: M03\n", - "2026-03-30 13:22:39,920 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'M03\\r\\n'\n", - "2026-03-30 13:22:39,947 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M03 A 0\\r\\n'\n", - "2026-03-30 13:22:39,949 - pylabrobot - IO - [MT Scale] Received response: b'M03 A 0\\r\\n'\n", - "2026-03-30 13:22:39,951 - pylabrobot - IO - [MT Scale] Sent command: M27\n", - "2026-03-30 13:22:39,953 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'M27\\r\\n'\n", - "2026-03-30 13:22:40,013 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 1 13 05 2020 17 17 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:40,018 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 1 13 05 2020 17 17 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:40,043 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 2 02 12 2019 20 02 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:40,044 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 2 02 12 2019 20 02 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:40,075 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 3 11 10 2019 17 05 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:40,076 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 3 11 10 2019 17 05 0 \"\"\\r\\n'\n" + "2026-03-30 13:31:27,946 - pylabrobot - IO - [MT Scale] Sent command: M01\n", + "2026-03-30 13:31:27,951 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'M01\\r\\n'\n", + "2026-03-30 13:31:27,976 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M01 A 0\\r\\n'\n", + "2026-03-30 13:31:27,978 - pylabrobot - IO - [MT Scale] Received response: b'M01 A 0\\r\\n'\n", + "2026-03-30 13:31:27,979 - pylabrobot - IO - [MT Scale] Sent command: M02\n", + "2026-03-30 13:31:27,981 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'M02\\r\\n'\n", + "2026-03-30 13:31:28,009 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M02 A 2\\r\\n'\n", + "2026-03-30 13:31:28,010 - pylabrobot - IO - [MT Scale] Received response: b'M02 A 2\\r\\n'\n", + "2026-03-30 13:31:28,012 - pylabrobot - IO - [MT Scale] Sent command: M03\n", + "2026-03-30 13:31:28,014 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'M03\\r\\n'\n", + "2026-03-30 13:31:28,041 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M03 A 0\\r\\n'\n", + "2026-03-30 13:31:28,042 - pylabrobot - IO - [MT Scale] Received response: b'M03 A 0\\r\\n'\n", + "2026-03-30 13:31:28,044 - pylabrobot - IO - [MT Scale] Sent command: M27\n", + "2026-03-30 13:31:28,048 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'M27\\r\\n'\n", + "2026-03-30 13:31:28,104 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 1 13 05 2020 17 17 0 \"\"\\r\\n'\n", + "2026-03-30 13:31:28,105 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 1 13 05 2020 17 17 0 \"\"\\r\\n'\n", + "2026-03-30 13:31:28,136 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 2 02 12 2019 20 02 0 \"\"\\r\\n'\n", + "2026-03-30 13:31:28,142 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 2 02 12 2019 20 02 0 \"\"\\r\\n'\n", + "2026-03-30 13:31:28,168 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 3 11 10 2019 17 05 0 \"\"\\r\\n'\n", + "2026-03-30 13:31:28,169 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 3 11 10 2019 17 05 0 \"\"\\r\\n'\n" ] }, { @@ -1264,118 +1264,116 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 13:22:40,106 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 4 11 10 2019 17 01 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:40,110 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 4 11 10 2019 17 01 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:40,138 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 5 14 03 2019 20 22 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:40,140 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 5 14 03 2019 20 22 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:40,171 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 6 14 03 2019 20 18 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:40,172 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 6 14 03 2019 20 18 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:40,203 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 7 17 10 2018 17 38 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:40,204 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 7 17 10 2018 17 38 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:40,235 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 8 17 10 2018 17 37 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:40,240 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 8 17 10 2018 17 37 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:40,267 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 9 17 10 2018 17 35 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:40,269 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 9 17 10 2018 17 35 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:40,298 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 10 20 09 2018 21 23 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:40,302 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 10 20 09 2018 21 23 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:40,332 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 11 15 03 2018 23 51 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:40,333 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 11 15 03 2018 23 51 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:40,364 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 12 16 12 2017 00 20 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:40,368 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 12 16 12 2017 00 20 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:40,394 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 13 16 12 2017 00 18 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:40,397 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 13 16 12 2017 00 18 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:40,428 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 14 18 10 2017 12 06 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:40,430 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 14 18 10 2017 12 06 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:40,458 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 15 18 10 2017 11 58 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:40,460 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 15 18 10 2017 11 58 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:40,491 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 16 05 09 2017 22 40 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:40,492 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 16 05 09 2017 22 40 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:40,540 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 17 21 06 2017 18 39 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:40,544 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 17 21 06 2017 18 39 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:40,572 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 18 30 03 2017 19 24 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:40,578 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 18 30 03 2017 19 24 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:40,602 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 19 09 03 2017 23 21 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:40,605 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 19 09 03 2017 23 21 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:40,636 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 20 09 03 2017 23 19 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:40,637 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 20 09 03 2017 23 19 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:40,667 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 21 20 12 2016 21 55 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:40,668 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 21 20 12 2016 21 55 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:40,700 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 22 19 10 2016 17 36 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:40,701 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 22 19 10 2016 17 36 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:40,731 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 23 19 10 2016 17 33 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:40,732 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 23 19 10 2016 17 33 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:40,762 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 24 18 10 2016 21 00 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:40,764 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 24 18 10 2016 21 00 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:40,794 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 25 18 10 2016 18 47 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:40,796 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 25 18 10 2016 18 47 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:40,826 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 26 18 10 2016 15 33 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:40,827 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 26 18 10 2016 15 33 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:40,858 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 27 18 10 2016 14 32 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:40,859 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 27 18 10 2016 14 32 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:40,907 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 28 18 10 2016 14 28 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:40,910 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 28 18 10 2016 14 28 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:40,938 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 29 18 10 2016 13 41 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:40,939 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 29 18 10 2016 13 41 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:40,970 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 30 21 09 2016 15 15 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:40,971 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 30 21 09 2016 15 15 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:41,003 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 31 04 03 2016 22 28 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:41,006 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 31 04 03 2016 22 28 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:41,036 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 32 01 10 2015 19 06 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:41,037 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 32 01 10 2015 19 06 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:41,067 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 33 01 10 2015 18 56 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:41,068 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 33 01 10 2015 18 56 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:41,099 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 34 03 09 2015 22 11 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:41,101 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 34 03 09 2015 22 11 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:41,130 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 35 11 03 2015 13 20 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:41,132 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 35 11 03 2015 13 20 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:41,162 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 36 11 03 2015 13 18 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:41,163 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 36 11 03 2015 13 18 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:41,195 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 37 11 03 2015 13 15 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:41,197 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 37 11 03 2015 13 15 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:41,228 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 38 11 03 2015 13 13 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:41,229 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 38 11 03 2015 13 13 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:41,260 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 39 22 01 2015 03 17 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:41,261 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 39 22 01 2015 03 17 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:41,306 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 40 22 01 2015 03 15 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:41,306 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 40 22 01 2015 03 15 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:41,337 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 41 06 11 2014 17 08 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:41,338 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 41 06 11 2014 17 08 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:41,370 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 42 06 11 2014 16 22 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:41,371 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 42 06 11 2014 16 22 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:41,402 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 43 06 11 2014 16 20 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:41,402 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 43 06 11 2014 16 20 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:41,434 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 44 06 11 2014 15 57 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:41,435 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 44 06 11 2014 15 57 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:41,466 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 45 18 09 2014 20 23 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:41,467 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 45 18 09 2014 20 23 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:41,501 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 46 18 09 2014 19 54 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:41,503 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 46 18 09 2014 19 54 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:41,532 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 47 18 09 2014 19 44 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:41,533 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 47 18 09 2014 19 44 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:41,562 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 48 18 09 2014 19 35 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:41,563 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 48 18 09 2014 19 35 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:41,594 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 49 15 09 2014 20 08 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:41,595 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 49 15 09 2014 20 08 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:41,627 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 A 50 15 09 2014 19 39 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:41,628 - pylabrobot - IO - [MT Scale] Received response: b'M27 A 50 15 09 2014 19 39 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:41,632 - pylabrobot - IO - [MT Scale] Sent command: UPD\n", - "2026-03-30 13:22:41,636 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'UPD\\r\\n'\n", - "2026-03-30 13:22:41,674 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'UPD A 10.173\\r\\n'\n", - "2026-03-30 13:22:41,674 - pylabrobot - IO - [MT Scale] Received response: b'UPD A 10.173\\r\\n'\n", - "2026-03-30 13:22:41,676 - pylabrobot - IO - [MT Scale] Sent command: SIS\n", - "2026-03-30 13:22:41,680 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SIS\\r\\n'\n", - "2026-03-30 13:22:41,722 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'SIS A 0 \"0.00000\" 0 5 1 0 0\\r\\n'\n", - "2026-03-30 13:22:41,723 - pylabrobot - IO - [MT Scale] Received response: b'SIS A 0 \"0.00000\" 0 5 1 0 0\\r\\n'\n", - "2026-03-30 13:22:41,724 - pylabrobot - IO - [MT Scale] Sent command: LST\n", - "2026-03-30 13:22:41,728 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'LST\\r\\n'\n", - "2026-03-30 13:22:41,770 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B C0 0 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:41,770 - pylabrobot - IO - [MT Scale] Received response: b'LST B C0 0 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:41,785 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B FCUT 0.000\\r\\n'\n", - "2026-03-30 13:22:41,786 - pylabrobot - IO - [MT Scale] Received response: b'LST B FCUT 0.000\\r\\n'\n", - "2026-03-30 13:22:41,802 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B I10 \"\"\\r\\n'\n", - "2026-03-30 13:22:41,803 - pylabrobot - IO - [MT Scale] Received response: b'LST B I10 \"\"\\r\\n'\n", - "2026-03-30 13:22:41,817 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B M01 0\\r\\n'\n", - "2026-03-30 13:22:41,818 - pylabrobot - IO - [MT Scale] Received response: b'LST B M01 0\\r\\n'\n" + "2026-03-30 13:31:28,201 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 4 11 10 2019 17 01 0 \"\"\\r\\n'\n", + "2026-03-30 13:31:28,202 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 4 11 10 2019 17 01 0 \"\"\\r\\n'\n", + "2026-03-30 13:31:28,233 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 5 14 03 2019 20 22 0 \"\"\\r\\n'\n", + "2026-03-30 13:31:28,233 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 5 14 03 2019 20 22 0 \"\"\\r\\n'\n", + "2026-03-30 13:31:28,265 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 6 14 03 2019 20 18 0 \"\"\\r\\n'\n", + "2026-03-30 13:31:28,267 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 6 14 03 2019 20 18 0 \"\"\\r\\n'\n", + "2026-03-30 13:31:28,298 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 7 17 10 2018 17 38 0 \"\"\\r\\n'\n", + "2026-03-30 13:31:28,300 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 7 17 10 2018 17 38 0 \"\"\\r\\n'\n", + "2026-03-30 13:31:28,328 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 8 17 10 2018 17 37 0 \"\"\\r\\n'\n", + "2026-03-30 13:31:28,331 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 8 17 10 2018 17 37 0 \"\"\\r\\n'\n", + "2026-03-30 13:31:28,361 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 9 17 10 2018 17 35 0 \"\"\\r\\n'\n", + "2026-03-30 13:31:28,362 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 9 17 10 2018 17 35 0 \"\"\\r\\n'\n", + "2026-03-30 13:31:28,394 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 10 20 09 2018 21 23 0 \"\"\\r\\n'\n", + "2026-03-30 13:31:28,401 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 10 20 09 2018 21 23 0 \"\"\\r\\n'\n", + "2026-03-30 13:31:28,429 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 11 15 03 2018 23 51 0 \"\"\\r\\n'\n", + "2026-03-30 13:31:28,431 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 11 15 03 2018 23 51 0 \"\"\\r\\n'\n", + "2026-03-30 13:31:28,456 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 12 16 12 2017 00 20 0 \"\"\\r\\n'\n", + "2026-03-30 13:31:28,458 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 12 16 12 2017 00 20 0 \"\"\\r\\n'\n", + "2026-03-30 13:31:28,490 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 13 16 12 2017 00 18 0 \"\"\\r\\n'\n", + "2026-03-30 13:31:28,492 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 13 16 12 2017 00 18 0 \"\"\\r\\n'\n", + "2026-03-30 13:31:28,520 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 14 18 10 2017 12 06 0 \"\"\\r\\n'\n", + "2026-03-30 13:31:28,522 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 14 18 10 2017 12 06 0 \"\"\\r\\n'\n", + "2026-03-30 13:31:28,552 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 15 18 10 2017 11 58 0 \"\"\\r\\n'\n", + "2026-03-30 13:31:28,553 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 15 18 10 2017 11 58 0 \"\"\\r\\n'\n", + "2026-03-30 13:31:28,600 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 16 05 09 2017 22 40 0 \"\"\\r\\n'\n", + "2026-03-30 13:31:28,602 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 16 05 09 2017 22 40 0 \"\"\\r\\n'\n", + "2026-03-30 13:31:28,632 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 17 21 06 2017 18 39 0 \"\"\\r\\n'\n", + "2026-03-30 13:31:28,635 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 17 21 06 2017 18 39 0 \"\"\\r\\n'\n", + "2026-03-30 13:31:28,664 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 18 30 03 2017 19 24 0 \"\"\\r\\n'\n", + "2026-03-30 13:31:28,667 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 18 30 03 2017 19 24 0 \"\"\\r\\n'\n", + "2026-03-30 13:31:28,696 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 19 09 03 2017 23 21 0 \"\"\\r\\n'\n", + "2026-03-30 13:31:28,698 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 19 09 03 2017 23 21 0 \"\"\\r\\n'\n", + "2026-03-30 13:31:28,729 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 20 09 03 2017 23 19 0 \"\"\\r\\n'\n", + "2026-03-30 13:31:28,734 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 20 09 03 2017 23 19 0 \"\"\\r\\n'\n", + "2026-03-30 13:31:28,760 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 21 20 12 2016 21 55 0 \"\"\\r\\n'\n", + "2026-03-30 13:31:28,762 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 21 20 12 2016 21 55 0 \"\"\\r\\n'\n", + "2026-03-30 13:31:28,792 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 22 19 10 2016 17 36 0 \"\"\\r\\n'\n", + "2026-03-30 13:31:28,799 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 22 19 10 2016 17 36 0 \"\"\\r\\n'\n", + "2026-03-30 13:31:28,824 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 23 19 10 2016 17 33 0 \"\"\\r\\n'\n", + "2026-03-30 13:31:28,825 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 23 19 10 2016 17 33 0 \"\"\\r\\n'\n", + "2026-03-30 13:31:28,857 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 24 18 10 2016 21 00 0 \"\"\\r\\n'\n", + "2026-03-30 13:31:28,859 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 24 18 10 2016 21 00 0 \"\"\\r\\n'\n", + "2026-03-30 13:31:28,888 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 25 18 10 2016 18 47 0 \"\"\\r\\n'\n", + "2026-03-30 13:31:28,889 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 25 18 10 2016 18 47 0 \"\"\\r\\n'\n", + "2026-03-30 13:31:28,921 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 26 18 10 2016 15 33 0 \"\"\\r\\n'\n", + "2026-03-30 13:31:28,923 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 26 18 10 2016 15 33 0 \"\"\\r\\n'\n", + "2026-03-30 13:31:28,969 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 27 18 10 2016 14 32 0 \"\"\\r\\n'\n", + "2026-03-30 13:31:28,974 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 27 18 10 2016 14 32 0 \"\"\\r\\n'\n", + "2026-03-30 13:31:29,000 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 28 18 10 2016 14 28 0 \"\"\\r\\n'\n", + "2026-03-30 13:31:29,006 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 28 18 10 2016 14 28 0 \"\"\\r\\n'\n", + "2026-03-30 13:31:29,032 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 29 18 10 2016 13 41 0 \"\"\\r\\n'\n", + "2026-03-30 13:31:29,034 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 29 18 10 2016 13 41 0 \"\"\\r\\n'\n", + "2026-03-30 13:31:29,064 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 30 21 09 2016 15 15 0 \"\"\\r\\n'\n", + "2026-03-30 13:31:29,065 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 30 21 09 2016 15 15 0 \"\"\\r\\n'\n", + "2026-03-30 13:31:29,096 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 31 04 03 2016 22 28 0 \"\"\\r\\n'\n", + "2026-03-30 13:31:29,099 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 31 04 03 2016 22 28 0 \"\"\\r\\n'\n", + "2026-03-30 13:31:29,128 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 32 01 10 2015 19 06 0 \"\"\\r\\n'\n", + "2026-03-30 13:31:29,134 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 32 01 10 2015 19 06 0 \"\"\\r\\n'\n", + "2026-03-30 13:31:29,169 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 33 01 10 2015 18 56 0 \"\"\\r\\n'\n", + "2026-03-30 13:31:29,172 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 33 01 10 2015 18 56 0 \"\"\\r\\n'\n", + "2026-03-30 13:31:29,192 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 34 03 09 2015 22 11 0 \"\"\\r\\n'\n", + "2026-03-30 13:31:29,193 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 34 03 09 2015 22 11 0 \"\"\\r\\n'\n", + "2026-03-30 13:31:29,226 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 35 11 03 2015 13 20 0 \"\"\\r\\n'\n", + "2026-03-30 13:31:29,227 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 35 11 03 2015 13 20 0 \"\"\\r\\n'\n", + "2026-03-30 13:31:29,256 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 36 11 03 2015 13 18 0 \"\"\\r\\n'\n", + "2026-03-30 13:31:29,257 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 36 11 03 2015 13 18 0 \"\"\\r\\n'\n", + "2026-03-30 13:31:29,288 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 37 11 03 2015 13 15 0 \"\"\\r\\n'\n", + "2026-03-30 13:31:29,294 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 37 11 03 2015 13 15 0 \"\"\\r\\n'\n", + "2026-03-30 13:31:29,320 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 38 11 03 2015 13 13 0 \"\"\\r\\n'\n", + "2026-03-30 13:31:29,321 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 38 11 03 2015 13 13 0 \"\"\\r\\n'\n", + "2026-03-30 13:31:29,367 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 39 22 01 2015 03 17 0 \"\"\\r\\n'\n", + "2026-03-30 13:31:29,369 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 39 22 01 2015 03 17 0 \"\"\\r\\n'\n", + "2026-03-30 13:31:29,404 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 40 22 01 2015 03 15 0 \"\"\\r\\n'\n", + "2026-03-30 13:31:29,406 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 40 22 01 2015 03 15 0 \"\"\\r\\n'\n", + "2026-03-30 13:31:29,432 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 41 06 11 2014 17 08 0 \"\"\\r\\n'\n", + "2026-03-30 13:31:29,434 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 41 06 11 2014 17 08 0 \"\"\\r\\n'\n", + "2026-03-30 13:31:29,464 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 42 06 11 2014 16 22 0 \"\"\\r\\n'\n", + "2026-03-30 13:31:29,464 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 42 06 11 2014 16 22 0 \"\"\\r\\n'\n", + "2026-03-30 13:31:29,499 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 43 06 11 2014 16 20 0 \"\"\\r\\n'\n", + "2026-03-30 13:31:29,503 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 43 06 11 2014 16 20 0 \"\"\\r\\n'\n", + "2026-03-30 13:31:29,528 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 44 06 11 2014 15 57 0 \"\"\\r\\n'\n", + "2026-03-30 13:31:29,532 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 44 06 11 2014 15 57 0 \"\"\\r\\n'\n", + "2026-03-30 13:31:29,560 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 45 18 09 2014 20 23 0 \"\"\\r\\n'\n", + "2026-03-30 13:31:29,564 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 45 18 09 2014 20 23 0 \"\"\\r\\n'\n", + "2026-03-30 13:31:29,592 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 46 18 09 2014 19 54 0 \"\"\\r\\n'\n", + "2026-03-30 13:31:29,596 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 46 18 09 2014 19 54 0 \"\"\\r\\n'\n", + "2026-03-30 13:31:29,629 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 47 18 09 2014 19 44 0 \"\"\\r\\n'\n", + "2026-03-30 13:31:29,632 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 47 18 09 2014 19 44 0 \"\"\\r\\n'\n", + "2026-03-30 13:31:29,655 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 48 18 09 2014 19 35 0 \"\"\\r\\n'\n", + "2026-03-30 13:31:29,655 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 48 18 09 2014 19 35 0 \"\"\\r\\n'\n", + "2026-03-30 13:31:29,687 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 49 15 09 2014 20 08 0 \"\"\\r\\n'\n", + "2026-03-30 13:31:29,687 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 49 15 09 2014 20 08 0 \"\"\\r\\n'\n", + "2026-03-30 13:31:29,721 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 A 50 15 09 2014 19 39 0 \"\"\\r\\n'\n", + "2026-03-30 13:31:29,722 - pylabrobot - IO - [MT Scale] Received response: b'M27 A 50 15 09 2014 19 39 0 \"\"\\r\\n'\n", + "2026-03-30 13:31:29,724 - pylabrobot - IO - [MT Scale] Sent command: UPD\n", + "2026-03-30 13:31:29,726 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'UPD\\r\\n'\n", + "2026-03-30 13:31:29,767 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'UPD A 10.173\\r\\n'\n", + "2026-03-30 13:31:29,768 - pylabrobot - IO - [MT Scale] Received response: b'UPD A 10.173\\r\\n'\n", + "2026-03-30 13:31:29,770 - pylabrobot - IO - [MT Scale] Sent command: SIS\n", + "2026-03-30 13:31:29,772 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SIS\\r\\n'\n", + "2026-03-30 13:31:29,831 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'SIS A 0 \"0.00000\" 0 5 1 0 0\\r\\n'\n", + "2026-03-30 13:31:29,833 - pylabrobot - IO - [MT Scale] Received response: b'SIS A 0 \"0.00000\" 0 5 1 0 0\\r\\n'\n", + "2026-03-30 13:31:29,835 - pylabrobot - IO - [MT Scale] Sent command: LST\n", + "2026-03-30 13:31:29,837 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'LST\\r\\n'\n", + "2026-03-30 13:31:29,879 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B C0 0 0 \"\"\\r\\n'\n", + "2026-03-30 13:31:29,880 - pylabrobot - IO - [MT Scale] Received response: b'LST B C0 0 0 \"\"\\r\\n'\n", + "2026-03-30 13:31:29,896 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B FCUT 0.000\\r\\n'\n", + "2026-03-30 13:31:29,897 - pylabrobot - IO - [MT Scale] Received response: b'LST B FCUT 0.000\\r\\n'\n", + "2026-03-30 13:31:29,911 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B I10 \"\"\\r\\n'\n", + "2026-03-30 13:31:29,913 - pylabrobot - IO - [MT Scale] Received response: b'LST B I10 \"\"\\r\\n'\n" ] }, { @@ -1444,62 +1442,64 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 13:22:41,833 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B M02 2\\r\\n'\n", - "2026-03-30 13:22:41,834 - pylabrobot - IO - [MT Scale] Received response: b'LST B M02 2\\r\\n'\n", - "2026-03-30 13:22:41,839 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B M03 0\\r\\n'\n", - "2026-03-30 13:22:41,841 - pylabrobot - IO - [MT Scale] Received response: b'LST B M03 0\\r\\n'\n", - "2026-03-30 13:22:41,865 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B M17 00 00 00 0\\r\\n'\n", - "2026-03-30 13:22:41,867 - pylabrobot - IO - [MT Scale] Received response: b'LST B M17 00 00 00 0\\r\\n'\n", - "2026-03-30 13:22:41,883 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B M18 1\\r\\n'\n", - "2026-03-30 13:22:41,884 - pylabrobot - IO - [MT Scale] Received response: b'LST B M18 1\\r\\n'\n", - "2026-03-30 13:22:41,897 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B M19 10.00000 g\\r\\n'\n", - "2026-03-30 13:22:41,898 - pylabrobot - IO - [MT Scale] Received response: b'LST B M19 10.00000 g\\r\\n'\n", - "2026-03-30 13:22:41,929 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B M20 200.00000 g\\r\\n'\n", - "2026-03-30 13:22:41,930 - pylabrobot - IO - [MT Scale] Received response: b'LST B M20 200.00000 g\\r\\n'\n", - "2026-03-30 13:22:41,945 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B M21 0 0\\r\\n'\n", - "2026-03-30 13:22:41,946 - pylabrobot - IO - [MT Scale] Received response: b'LST B M21 0 0\\r\\n'\n", - "2026-03-30 13:22:41,948 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B M29 1\\r\\n'\n", - "2026-03-30 13:22:41,949 - pylabrobot - IO - [MT Scale] Received response: b'LST B M29 1\\r\\n'\n", - "2026-03-30 13:22:41,961 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B M31 0\\r\\n'\n", - "2026-03-30 13:22:41,962 - pylabrobot - IO - [MT Scale] Received response: b'LST B M31 0\\r\\n'\n", - "2026-03-30 13:22:41,994 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B M32 1 00 00 0\\r\\n'\n", - "2026-03-30 13:22:41,996 - pylabrobot - IO - [MT Scale] Received response: b'LST B M32 1 00 00 0\\r\\n'\n", - "2026-03-30 13:22:42,010 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B M32 2 00 00 0\\r\\n'\n", - "2026-03-30 13:22:42,011 - pylabrobot - IO - [MT Scale] Received response: b'LST B M32 2 00 00 0\\r\\n'\n", - "2026-03-30 13:22:42,027 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B M32 3 00 00 0\\r\\n'\n", - "2026-03-30 13:22:42,029 - pylabrobot - IO - [MT Scale] Received response: b'LST B M32 3 00 00 0\\r\\n'\n", - "2026-03-30 13:22:42,043 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B M33 0\\r\\n'\n", - "2026-03-30 13:22:42,045 - pylabrobot - IO - [MT Scale] Received response: b'LST B M33 0\\r\\n'\n", - "2026-03-30 13:22:42,057 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B M35 0\\r\\n'\n", - "2026-03-30 13:22:42,058 - pylabrobot - IO - [MT Scale] Received response: b'LST B M35 0\\r\\n'\n", - "2026-03-30 13:22:42,073 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B RDB 5\\r\\n'\n", - "2026-03-30 13:22:42,074 - pylabrobot - IO - [MT Scale] Received response: b'LST B RDB 5\\r\\n'\n", - "2026-03-30 13:22:42,089 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B TST0 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:42,090 - pylabrobot - IO - [MT Scale] Received response: b'LST B TST0 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:42,107 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B UPD 10.173\\r\\n'\n", - "2026-03-30 13:22:42,114 - pylabrobot - IO - [MT Scale] Received response: b'LST B UPD 10.173\\r\\n'\n", - "2026-03-30 13:22:42,137 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B USTB 0 3.600 1.100\\r\\n'\n", - "2026-03-30 13:22:42,139 - pylabrobot - IO - [MT Scale] Received response: b'LST B USTB 0 3.600 1.100\\r\\n'\n", - "2026-03-30 13:22:42,169 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B USTB 1 0.000 0.000\\r\\n'\n", - "2026-03-30 13:22:42,170 - pylabrobot - IO - [MT Scale] Received response: b'LST B USTB 1 0.000 0.000\\r\\n'\n", - "2026-03-30 13:22:42,187 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST A USTB 2 0.000 0.000\\r\\n'\n", - "2026-03-30 13:22:42,189 - pylabrobot - IO - [MT Scale] Received response: b'LST A USTB 2 0.000 0.000\\r\\n'\n", - "2026-03-30 13:22:42,195 - pylabrobot - IO - [MT Scale] Sent command: RDB\n", - "2026-03-30 13:22:42,204 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'RDB\\r\\n'\n", - "2026-03-30 13:22:42,234 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'RDB A 5\\r\\n'\n", - "2026-03-30 13:22:42,235 - pylabrobot - IO - [MT Scale] Received response: b'RDB A 5\\r\\n'\n", - "2026-03-30 13:22:42,237 - pylabrobot - IO - [MT Scale] Sent command: USTB\n", - "2026-03-30 13:22:42,243 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'USTB\\r\\n'\n", - "2026-03-30 13:22:42,282 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'USTB B 0 3.600 1.100\\r\\n'\n", - "2026-03-30 13:22:42,283 - pylabrobot - IO - [MT Scale] Received response: b'USTB B 0 3.600 1.100\\r\\n'\n", - "2026-03-30 13:22:42,314 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'USTB B 1 0.000 0.000\\r\\n'\n", - "2026-03-30 13:22:42,315 - pylabrobot - IO - [MT Scale] Received response: b'USTB B 1 0.000 0.000\\r\\n'\n", - "2026-03-30 13:22:42,329 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'USTB A 2 0.000 0.000\\r\\n'\n", - "2026-03-30 13:22:42,331 - pylabrobot - IO - [MT Scale] Received response: b'USTB A 2 0.000 0.000\\r\\n'\n", - "2026-03-30 13:22:42,332 - pylabrobot - IO - [MT Scale] Sent command: FCUT\n", - "2026-03-30 13:22:42,338 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'FCUT\\r\\n'\n", - "2026-03-30 13:22:42,377 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'FCUT A 0.000\\r\\n'\n", - "2026-03-30 13:22:42,379 - pylabrobot - IO - [MT Scale] Received response: b'FCUT A 0.000\\r\\n'\n" + "2026-03-30 13:31:29,927 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B M01 0\\r\\n'\n", + "2026-03-30 13:31:29,930 - pylabrobot - IO - [MT Scale] Received response: b'LST B M01 0\\r\\n'\n", + "2026-03-30 13:31:29,943 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B M02 2\\r\\n'\n", + "2026-03-30 13:31:29,944 - pylabrobot - IO - [MT Scale] Received response: b'LST B M02 2\\r\\n'\n", + "2026-03-30 13:31:29,959 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B M03 0\\r\\n'\n", + "2026-03-30 13:31:29,961 - pylabrobot - IO - [MT Scale] Received response: b'LST B M03 0\\r\\n'\n", + "2026-03-30 13:31:29,975 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B M17 00 00 00 0\\r\\n'\n", + "2026-03-30 13:31:29,977 - pylabrobot - IO - [MT Scale] Received response: b'LST B M17 00 00 00 0\\r\\n'\n", + "2026-03-30 13:31:29,994 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B M18 1\\r\\n'\n", + "2026-03-30 13:31:29,996 - pylabrobot - IO - [MT Scale] Received response: b'LST B M18 1\\r\\n'\n", + "2026-03-30 13:31:30,007 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B M19 10.00000 g\\r\\n'\n", + "2026-03-30 13:31:30,008 - pylabrobot - IO - [MT Scale] Received response: b'LST B M19 10.00000 g\\r\\n'\n", + "2026-03-30 13:31:30,040 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B M20 200.00000 g\\r\\n'\n", + "2026-03-30 13:31:30,045 - pylabrobot - IO - [MT Scale] Received response: b'LST B M20 200.00000 g\\r\\n'\n", + "2026-03-30 13:31:30,054 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B M21 0 0\\r\\n'\n", + "2026-03-30 13:31:30,055 - pylabrobot - IO - [MT Scale] Received response: b'LST B M21 0 0\\r\\n'\n", + "2026-03-30 13:31:30,072 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B M29 1\\r\\n'\n", + "2026-03-30 13:31:30,073 - pylabrobot - IO - [MT Scale] Received response: b'LST B M29 1\\r\\n'\n", + "2026-03-30 13:31:30,078 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B M31 0\\r\\n'\n", + "2026-03-30 13:31:30,082 - pylabrobot - IO - [MT Scale] Received response: b'LST B M31 0\\r\\n'\n", + "2026-03-30 13:31:30,103 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B M32 1 00 00 0\\r\\n'\n", + "2026-03-30 13:31:30,105 - pylabrobot - IO - [MT Scale] Received response: b'LST B M32 1 00 00 0\\r\\n'\n", + "2026-03-30 13:31:30,119 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B M32 2 00 00 0\\r\\n'\n", + "2026-03-30 13:31:30,120 - pylabrobot - IO - [MT Scale] Received response: b'LST B M32 2 00 00 0\\r\\n'\n", + "2026-03-30 13:31:30,151 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B M32 3 00 00 0\\r\\n'\n", + "2026-03-30 13:31:30,152 - pylabrobot - IO - [MT Scale] Received response: b'LST B M32 3 00 00 0\\r\\n'\n", + "2026-03-30 13:31:30,156 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B M33 0\\r\\n'\n", + "2026-03-30 13:31:30,158 - pylabrobot - IO - [MT Scale] Received response: b'LST B M33 0\\r\\n'\n", + "2026-03-30 13:31:30,167 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B M35 0\\r\\n'\n", + "2026-03-30 13:31:30,170 - pylabrobot - IO - [MT Scale] Received response: b'LST B M35 0\\r\\n'\n", + "2026-03-30 13:31:30,183 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B RDB 5\\r\\n'\n", + "2026-03-30 13:31:30,185 - pylabrobot - IO - [MT Scale] Received response: b'LST B RDB 5\\r\\n'\n", + "2026-03-30 13:31:30,199 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B TST0 0 \"\"\\r\\n'\n", + "2026-03-30 13:31:30,203 - pylabrobot - IO - [MT Scale] Received response: b'LST B TST0 0 \"\"\\r\\n'\n", + "2026-03-30 13:31:30,215 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B UPD 10.173\\r\\n'\n", + "2026-03-30 13:31:30,217 - pylabrobot - IO - [MT Scale] Received response: b'LST B UPD 10.173\\r\\n'\n", + "2026-03-30 13:31:30,247 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B USTB 0 3.600 1.100\\r\\n'\n", + "2026-03-30 13:31:30,248 - pylabrobot - IO - [MT Scale] Received response: b'LST B USTB 0 3.600 1.100\\r\\n'\n", + "2026-03-30 13:31:30,281 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B USTB 1 0.000 0.000\\r\\n'\n", + "2026-03-30 13:31:30,283 - pylabrobot - IO - [MT Scale] Received response: b'LST B USTB 1 0.000 0.000\\r\\n'\n", + "2026-03-30 13:31:30,296 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST A USTB 2 0.000 0.000\\r\\n'\n", + "2026-03-30 13:31:30,300 - pylabrobot - IO - [MT Scale] Received response: b'LST A USTB 2 0.000 0.000\\r\\n'\n", + "2026-03-30 13:31:30,303 - pylabrobot - IO - [MT Scale] Sent command: RDB\n", + "2026-03-30 13:31:30,307 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'RDB\\r\\n'\n", + "2026-03-30 13:31:30,342 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'RDB A 5\\r\\n'\n", + "2026-03-30 13:31:30,344 - pylabrobot - IO - [MT Scale] Received response: b'RDB A 5\\r\\n'\n", + "2026-03-30 13:31:30,347 - pylabrobot - IO - [MT Scale] Sent command: USTB\n", + "2026-03-30 13:31:30,350 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'USTB\\r\\n'\n", + "2026-03-30 13:31:30,391 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'USTB B 0 3.600 1.100\\r\\n'\n", + "2026-03-30 13:31:30,396 - pylabrobot - IO - [MT Scale] Received response: b'USTB B 0 3.600 1.100\\r\\n'\n", + "2026-03-30 13:31:30,426 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'USTB B 1 0.000 0.000\\r\\n'\n", + "2026-03-30 13:31:30,428 - pylabrobot - IO - [MT Scale] Received response: b'USTB B 1 0.000 0.000\\r\\n'\n", + "2026-03-30 13:31:30,439 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'USTB A 2 0.000 0.000\\r\\n'\n", + "2026-03-30 13:31:30,443 - pylabrobot - IO - [MT Scale] Received response: b'USTB A 2 0.000 0.000\\r\\n'\n", + "2026-03-30 13:31:30,449 - pylabrobot - IO - [MT Scale] Sent command: FCUT\n", + "2026-03-30 13:31:30,452 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'FCUT\\r\\n'\n", + "2026-03-30 13:31:30,486 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'FCUT A 0.000\\r\\n'\n", + "2026-03-30 13:31:30,487 - pylabrobot - IO - [MT Scale] Received response: b'FCUT A 0.000\\r\\n'\n" ] }, { @@ -1624,15 +1624,91 @@ }, { "cell_type": "markdown", - "source": "### SIS unit code verification (exploratory)\n\nTests whether field index 4 in the SIS response is the unit code by temporarily\nchanging the host unit via M21, reading SIS, then restoring grams.\n\n**WARNING:** Temporarily writes a non-gram unit to device memory via M21.\nIf the cell fails mid-execution, run `await backend.set_host_unit_grams()`\nmanually to restore grams. setup() also restores grams on next connection.", - "metadata": {} + "metadata": {}, + "source": [ + "### SIS unit code verification (exploratory)\n", + "\n", + "Tests whether field index 4 in the SIS response is the unit code by temporarily\n", + "changing the host unit via M21, reading SIS, then restoring grams.\n", + "\n", + "**WARNING:** Temporarily writes a non-gram unit to device memory via M21.\n", + "If the cell fails mid-execution, run `await backend.set_host_unit_grams()`\n", + "manually to restore grams. setup() also restores grams on next connection." + ] }, { "cell_type": "code", - "source": "# Read SIS in grams (current state)\nsis_grams = await backend.request_net_weight_with_status()\nprint(f\"SIS in grams: {sis_grams.data}\")\n\n# Temporarily set unit to milligrams (M21 1 0 = mg host unit)\ntry:\n await backend.send_command(\"M21 1 0\")\n sis_mg = await backend.request_net_weight_with_status()\n print(f\"SIS in milligrams: {sis_mg.data}\")\n\n # Compare the unit code field (index 4 in the data)\n if len(sis_grams.data) > 4 and len(sis_mg.data) > 4:\n print(f\"\\nUnit code in grams mode: {sis_grams.data[4]}\")\n print(f\"Unit code in mg mode: {sis_mg.data[4]}\")\n if sis_grams.data[4] != sis_mg.data[4]:\n print(\"PASS: unit code changes with M21 - confirms field is unit identifier\")\n else:\n print(\"INFO: unit code did not change - field may not be the unit identifier\")\n else:\n print(\"INFO: SIS response too short to compare unit codes\")\n\nfinally:\n # Always restore grams\n await backend.set_host_unit_grams()\n print(\"\\nRestored host unit to grams\")", + "execution_count": 15, "metadata": {}, - "execution_count": null, - "outputs": [] + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2026-03-30 13:31:34,078 - pylabrobot - IO - [MT Scale] Sent command: SIS\n", + "2026-03-30 13:31:34,081 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SIS\\r\\n'\n", + "2026-03-30 13:31:34,132 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'SIS A 0 \"0.00000\" 0 5 1 0 0\\r\\n'\n", + "2026-03-30 13:31:34,133 - pylabrobot - IO - [MT Scale] Received response: b'SIS A 0 \"0.00000\" 0 5 1 0 0\\r\\n'\n", + "2026-03-30 13:31:34,136 - pylabrobot - IO - [MT Scale] Sent command: M21 1 0\n", + "2026-03-30 13:31:34,139 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'M21 1 0\\r\\n'\n", + "2026-03-30 13:31:34,165 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M21 L\\r\\n'\n", + "2026-03-30 13:31:34,167 - pylabrobot - IO - [MT Scale] Received response: b'M21 L\\r\\n'\n", + "2026-03-30 13:31:34,168 - pylabrobot - IO - [MT Scale] Sent command: M21 0 0\n", + "2026-03-30 13:31:34,171 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'M21 0 0\\r\\n'\n", + "2026-03-30 13:31:34,212 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M21 A\\r\\n'\n", + "2026-03-30 13:31:34,214 - pylabrobot - IO - [MT Scale] Received response: b'M21 A\\r\\n'\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "SIS in grams: ['0', '0.00000', '0', '5', '1', '0', '0']\n", + "\n", + "Restored host unit to grams\n" + ] + }, + { + "ename": "MettlerToledoError", + "evalue": "Command understood but not executable: (incorrect parameter).", + "output_type": "error", + "traceback": [ + "\u001b[31m---------------------------------------------------------------------------\u001b[39m", + "\u001b[31mMettlerToledoError\u001b[39m Traceback (most recent call last)", + "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[15]\u001b[39m\u001b[32m, line 7\u001b[39m\n\u001b[32m 5\u001b[39m \u001b[38;5;66;03m# Temporarily set unit to milligrams (M21 1 0 = mg host unit)\u001b[39;00m\n\u001b[32m 6\u001b[39m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[32m----> \u001b[39m\u001b[32m7\u001b[39m \u001b[38;5;28;01mawait\u001b[39;00m backend.send_command(\u001b[33m\"\u001b[39m\u001b[33mM21 1 0\u001b[39m\u001b[33m\"\u001b[39m)\n\u001b[32m 8\u001b[39m sis_mg = \u001b[38;5;28;01mawait\u001b[39;00m backend.request_net_weight_with_status()\n\u001b[32m 9\u001b[39m \u001b[38;5;28mprint\u001b[39m(\u001b[33mf\u001b[39m\u001b[33m\"\u001b[39m\u001b[33mSIS in milligrams: \u001b[39m\u001b[38;5;132;01m{\u001b[39;00msis_mg.data\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m\"\u001b[39m)\n", + "\u001b[36mFile \u001b[39m\u001b[32m~/Desktop/GitHub/pylabrobot/pylabrobot/scales/mettler_toledo/backend.py:342\u001b[39m, in \u001b[36mMettlerToledoWXS205SDUBackend.send_command\u001b[39m\u001b[34m(self, command, timeout)\u001b[39m\n\u001b[32m 340\u001b[39m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[32m 341\u001b[39m response = MettlerToledoResponse(command=\u001b[33m\"\u001b[39m\u001b[33m\"\u001b[39m, status=\u001b[33m\"\u001b[39m\u001b[33m\"\u001b[39m, data=[])\n\u001b[32m--> \u001b[39m\u001b[32m342\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[43m.\u001b[49m\u001b[43m_parse_basic_errors\u001b[49m\u001b[43m(\u001b[49m\u001b[43mresponse\u001b[49m\u001b[43m)\u001b[49m\n\u001b[32m 343\u001b[39m responses.append(response)\n\u001b[32m 345\u001b[39m \u001b[38;5;66;03m# Status B means more responses follow; anything else (A, etc.) is final\u001b[39;00m\n", + "\u001b[36mFile \u001b[39m\u001b[32m~/Desktop/GitHub/pylabrobot/pylabrobot/scales/mettler_toledo/backend.py:273\u001b[39m, in \u001b[36mMettlerToledoWXS205SDUBackend._parse_basic_errors\u001b[39m\u001b[34m(self, response)\u001b[39m\n\u001b[32m 271\u001b[39m \u001b[38;5;28;01mraise\u001b[39;00m MettlerToledoError.executing_another_command()\n\u001b[32m 272\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m response.status == \u001b[33m\"\u001b[39m\u001b[33mL\u001b[39m\u001b[33m\"\u001b[39m:\n\u001b[32m--> \u001b[39m\u001b[32m273\u001b[39m \u001b[38;5;28;01mraise\u001b[39;00m MettlerToledoError.incorrect_parameter()\n\u001b[32m 274\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m response.status == \u001b[33m\"\u001b[39m\u001b[33m+\u001b[39m\u001b[33m\"\u001b[39m:\n\u001b[32m 275\u001b[39m \u001b[38;5;28;01mraise\u001b[39;00m MettlerToledoError.overload()\n", + "\u001b[31mMettlerToledoError\u001b[39m: Command understood but not executable: (incorrect parameter)." + ] + } + ], + "source": [ + "# Read SIS in grams (current state)\n", + "sis_grams = await backend.request_net_weight_with_status()\n", + "print(f\"SIS in grams: {sis_grams.data}\")\n", + "\n", + "# Temporarily set unit to milligrams (M21 1 0 = mg host unit)\n", + "try:\n", + " await backend.send_command(\"M21 1 0\")\n", + " sis_mg = await backend.request_net_weight_with_status()\n", + " print(f\"SIS in milligrams: {sis_mg.data}\")\n", + "\n", + " # Compare the unit code field (index 4 in the data)\n", + " if len(sis_grams.data) > 4 and len(sis_mg.data) > 4:\n", + " print(f\"\\nUnit code in grams mode: {sis_grams.data[4]}\")\n", + " print(f\"Unit code in mg mode: {sis_mg.data[4]}\")\n", + " if sis_grams.data[4] != sis_mg.data[4]:\n", + " print(\"PASS: unit code changes with M21 - confirms field is unit identifier\")\n", + " else:\n", + " print(\"INFO: unit code did not change - field may not be the unit identifier\")\n", + " else:\n", + " print(\"INFO: SIS response too short to compare unit codes\")\n", + "\n", + "finally:\n", + " # Always restore grams\n", + " await backend.set_host_unit_grams()\n", + " print(\"\\nRestored host unit to grams\")" + ] }, { "cell_type": "markdown", @@ -1646,21 +1722,21 @@ }, { "cell_type": "code", - "execution_count": 15, + "execution_count": 16, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 13:23:14,769 - pylabrobot - IO - [MT Scale] Sent command: Z\n", - "2026-03-30 13:23:14,772 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'Z\\r\\n'\n", - "2026-03-30 13:23:15,084 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'Z A\\r\\n'\n", - "2026-03-30 13:23:15,085 - pylabrobot - IO - [MT Scale] Received response: b'Z A\\r\\n'\n", - "2026-03-30 13:23:15,087 - pylabrobot - IO - [MT Scale] Sent command: SI\n", - "2026-03-30 13:23:15,091 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", - "2026-03-30 13:23:15,132 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 13:23:15,139 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n" + "2026-03-30 13:31:46,782 - pylabrobot - IO - [MT Scale] Sent command: Z\n", + "2026-03-30 13:31:46,787 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'Z\\r\\n'\n", + "2026-03-30 13:31:47,177 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'Z A\\r\\n'\n", + "2026-03-30 13:31:47,178 - pylabrobot - IO - [MT Scale] Received response: b'Z A\\r\\n'\n", + "2026-03-30 13:31:47,180 - pylabrobot - IO - [MT Scale] Sent command: SI\n", + "2026-03-30 13:31:47,182 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", + "2026-03-30 13:31:47,225 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 13:31:47,229 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n" ] }, { @@ -1681,14 +1757,14 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 13:23:16,272 - pylabrobot - IO - [MT Scale] Sent command: T\n", - "2026-03-30 13:23:16,274 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'T\\r\\n'\n", - "2026-03-30 13:23:16,668 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'T S 0.00000 g\\r\\n'\n", - "2026-03-30 13:23:16,669 - pylabrobot - IO - [MT Scale] Received response: b'T S 0.00000 g\\r\\n'\n", - "2026-03-30 13:23:16,671 - pylabrobot - IO - [MT Scale] Sent command: TA\n", - "2026-03-30 13:23:16,672 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'TA\\r\\n'\n", - "2026-03-30 13:23:16,763 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'TA A 0.00000 g\\r\\n'\n", - "2026-03-30 13:23:16,763 - pylabrobot - IO - [MT Scale] Received response: b'TA A 0.00000 g\\r\\n'\n" + "2026-03-30 13:31:47,782 - pylabrobot - IO - [MT Scale] Sent command: T\n", + "2026-03-30 13:31:47,786 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'T\\r\\n'\n", + "2026-03-30 13:31:48,184 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'T S 0.00000 g\\r\\n'\n", + "2026-03-30 13:31:48,185 - pylabrobot - IO - [MT Scale] Received response: b'T S 0.00000 g\\r\\n'\n", + "2026-03-30 13:31:48,186 - pylabrobot - IO - [MT Scale] Sent command: TA\n", + "2026-03-30 13:31:48,188 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'TA\\r\\n'\n", + "2026-03-30 13:31:48,264 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'TA A 0.00000 g\\r\\n'\n", + "2026-03-30 13:31:48,266 - pylabrobot - IO - [MT Scale] Received response: b'TA A 0.00000 g\\r\\n'\n" ] }, { @@ -1705,7 +1781,7 @@ "traceback": [ "\u001b[31m---------------------------------------------------------------------------\u001b[39m", "\u001b[31mAssertionError\u001b[39m Traceback (most recent call last)", - "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[15]\u001b[39m\u001b[32m, line 12\u001b[39m\n\u001b[32m 10\u001b[39m tare = \u001b[38;5;28;01mawait\u001b[39;00m scale.request_tare_weight()\n\u001b[32m 11\u001b[39m \u001b[38;5;28mprint\u001b[39m(\u001b[33mf\u001b[39m\u001b[33m\"\u001b[39m\u001b[33mFrontend tare weight: \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mtare\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m g\u001b[39m\u001b[33m\"\u001b[39m)\n\u001b[32m---> \u001b[39m\u001b[32m12\u001b[39m \u001b[38;5;28;01massert\u001b[39;00m tare > \u001b[32m0\u001b[39m\n\u001b[32m 14\u001b[39m \u001b[38;5;66;03m# Read via frontend\u001b[39;00m\n\u001b[32m 15\u001b[39m w = \u001b[38;5;28;01mawait\u001b[39;00m scale.read_weight(timeout=\u001b[33m\"\u001b[39m\u001b[33mstable\u001b[39m\u001b[33m\"\u001b[39m)\n", + "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[16]\u001b[39m\u001b[32m, line 12\u001b[39m\n\u001b[32m 10\u001b[39m tare = \u001b[38;5;28;01mawait\u001b[39;00m scale.request_tare_weight()\n\u001b[32m 11\u001b[39m \u001b[38;5;28mprint\u001b[39m(\u001b[33mf\u001b[39m\u001b[33m\"\u001b[39m\u001b[33mFrontend tare weight: \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mtare\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m g\u001b[39m\u001b[33m\"\u001b[39m)\n\u001b[32m---> \u001b[39m\u001b[32m12\u001b[39m \u001b[38;5;28;01massert\u001b[39;00m tare > \u001b[32m0\u001b[39m\n\u001b[32m 14\u001b[39m \u001b[38;5;66;03m# Read via frontend\u001b[39;00m\n\u001b[32m 15\u001b[39m w = \u001b[38;5;28;01mawait\u001b[39;00m scale.read_weight(timeout=\u001b[33m\"\u001b[39m\u001b[33mstable\u001b[39m\u001b[33m\"\u001b[39m)\n", "\u001b[31mAssertionError\u001b[39m: " ] } @@ -1742,104 +1818,9 @@ }, { "cell_type": "code", - "execution_count": 16, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2026-03-30 13:23:25,471 - pylabrobot - IO - [MT Scale] Sent command: S\n", - "2026-03-30 13:23:25,473 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", - "2026-03-30 13:23:25,508 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00001 g\\r\\n'\n", - "2026-03-30 13:23:25,509 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00001 g\\r\\n'\n", - "2026-03-30 13:23:25,509 - pylabrobot - IO - [MT Scale] Sent command: S\n", - "2026-03-30 13:23:25,511 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", - "2026-03-30 13:23:25,604 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00001 g\\r\\n'\n", - "2026-03-30 13:23:25,605 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00001 g\\r\\n'\n", - "2026-03-30 13:23:25,605 - pylabrobot - IO - [MT Scale] Sent command: S\n", - "2026-03-30 13:23:25,606 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", - "2026-03-30 13:23:25,699 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00001 g\\r\\n'\n", - "2026-03-30 13:23:25,700 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00001 g\\r\\n'\n", - "2026-03-30 13:23:25,700 - pylabrobot - IO - [MT Scale] Sent command: S\n", - "2026-03-30 13:23:25,701 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", - "2026-03-30 13:23:25,811 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00001 g\\r\\n'\n", - "2026-03-30 13:23:25,812 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00001 g\\r\\n'\n", - "2026-03-30 13:23:25,813 - pylabrobot - IO - [MT Scale] Sent command: S\n", - "2026-03-30 13:23:25,815 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", - "2026-03-30 13:23:25,908 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00001 g\\r\\n'\n", - "2026-03-30 13:23:25,908 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00001 g\\r\\n'\n", - "2026-03-30 13:23:25,909 - pylabrobot - IO - [MT Scale] Sent command: S\n", - "2026-03-30 13:23:25,910 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", - "2026-03-30 13:23:26,004 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00001 g\\r\\n'\n", - "2026-03-30 13:23:26,004 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00001 g\\r\\n'\n", - "2026-03-30 13:23:26,005 - pylabrobot - IO - [MT Scale] Sent command: S\n", - "2026-03-30 13:23:26,006 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", - "2026-03-30 13:23:26,099 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00001 g\\r\\n'\n", - "2026-03-30 13:23:26,100 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00001 g\\r\\n'\n", - "2026-03-30 13:23:26,100 - pylabrobot - IO - [MT Scale] Sent command: S\n", - "2026-03-30 13:23:26,101 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", - "2026-03-30 13:23:26,195 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00001 g\\r\\n'\n", - "2026-03-30 13:23:26,196 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00001 g\\r\\n'\n", - "2026-03-30 13:23:26,196 - pylabrobot - IO - [MT Scale] Sent command: S\n", - "2026-03-30 13:23:26,197 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", - "2026-03-30 13:23:26,291 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00001 g\\r\\n'\n", - "2026-03-30 13:23:26,292 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00001 g\\r\\n'\n", - "2026-03-30 13:23:26,293 - pylabrobot - IO - [MT Scale] Sent command: S\n", - "2026-03-30 13:23:26,293 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", - "2026-03-30 13:23:26,388 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00001 g\\r\\n'\n", - "2026-03-30 13:23:26,388 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00001 g\\r\\n'\n", - "2026-03-30 13:23:26,389 - pylabrobot - IO - [MT Scale] Sent command: SI\n", - "2026-03-30 13:23:26,390 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", - "2026-03-30 13:23:26,435 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00001 g\\r\\n'\n", - "2026-03-30 13:23:26,436 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00001 g\\r\\n'\n", - "2026-03-30 13:23:26,437 - pylabrobot - IO - [MT Scale] Sent command: SI\n", - "2026-03-30 13:23:26,445 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", - "2026-03-30 13:23:26,483 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00001 g\\r\\n'\n", - "2026-03-30 13:23:26,485 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00001 g\\r\\n'\n", - "2026-03-30 13:23:26,487 - pylabrobot - IO - [MT Scale] Sent command: SI\n", - "2026-03-30 13:23:26,488 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", - "2026-03-30 13:23:26,531 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00001 g\\r\\n'\n", - "2026-03-30 13:23:26,532 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00001 g\\r\\n'\n", - "2026-03-30 13:23:26,533 - pylabrobot - IO - [MT Scale] Sent command: SI\n", - "2026-03-30 13:23:26,535 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", - "2026-03-30 13:23:26,563 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00001 g\\r\\n'\n", - "2026-03-30 13:23:26,564 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00001 g\\r\\n'\n", - "2026-03-30 13:23:26,566 - pylabrobot - IO - [MT Scale] Sent command: SI\n", - "2026-03-30 13:23:26,568 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", - "2026-03-30 13:23:26,611 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00001 g\\r\\n'\n", - "2026-03-30 13:23:26,614 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00001 g\\r\\n'\n", - "2026-03-30 13:23:26,617 - pylabrobot - IO - [MT Scale] Sent command: SI\n", - "2026-03-30 13:23:26,619 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", - "2026-03-30 13:23:26,659 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00001 g\\r\\n'\n", - "2026-03-30 13:23:26,661 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00001 g\\r\\n'\n", - "2026-03-30 13:23:26,664 - pylabrobot - IO - [MT Scale] Sent command: SI\n", - "2026-03-30 13:23:26,665 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", - "2026-03-30 13:23:26,708 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00001 g\\r\\n'\n", - "2026-03-30 13:23:26,709 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00001 g\\r\\n'\n", - "2026-03-30 13:23:26,711 - pylabrobot - IO - [MT Scale] Sent command: SI\n", - "2026-03-30 13:23:26,717 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", - "2026-03-30 13:23:26,755 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00001 g\\r\\n'\n", - "2026-03-30 13:23:26,757 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00001 g\\r\\n'\n", - "2026-03-30 13:23:26,758 - pylabrobot - IO - [MT Scale] Sent command: SI\n", - "2026-03-30 13:23:26,759 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", - "2026-03-30 13:23:26,806 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00001 g\\r\\n'\n", - "2026-03-30 13:23:26,807 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00001 g\\r\\n'\n", - "2026-03-30 13:23:26,808 - pylabrobot - IO - [MT Scale] Sent command: SI\n", - "2026-03-30 13:23:26,811 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", - "2026-03-30 13:23:26,851 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00001 g\\r\\n'\n", - "2026-03-30 13:23:26,852 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00001 g\\r\\n'\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Stable read: 91.79 +/- 18.42 ms\n", - "Immediate read: 46.44 +/- 4.92 ms\n" - ] - } - ], + "outputs": [], "source": [ "import time\n", "\n", @@ -1875,30 +1856,9 @@ }, { "cell_type": "code", - "execution_count": 17, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2026-03-30 13:23:31,221 - pylabrobot - INFO - === Hardware validation ended ===\n", - "2026-03-30 13:23:31,225 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] reset_input_buffer\n", - "2026-03-30 13:23:31,230 - pylabrobot - IO - [MT Scale] Sent command: @\n", - "2026-03-30 13:23:31,234 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'@\\r\\n'\n", - "2026-03-30 13:23:31,297 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I4 A \"B207696838\"\\r\\n'\n", - "2026-03-30 13:23:31,300 - pylabrobot - IO - [MT Scale] Received response: b'I4 A \"B207696838\"\\r\\n'\n", - "2026-03-30 13:23:31,302 - pylabrobot - INFO - [MT Scale] Disconnected from /dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Log file: ./logs/hardware_validation/2026-03-30_13-22-09_validation.log\n" - ] - } - ], + "outputs": [], "source": [ "plr_logger.info(\"=== Hardware validation ended ===\")\n", "await scale.stop()\n", @@ -1934,4 +1894,4 @@ }, "nbformat": 4, "nbformat_minor": 4 -} \ No newline at end of file +} From db13bf47067b9ed21f2432242f1c143d02aa8baf Mon Sep 17 00:00:00 2001 From: Camillo Moschner Date: Mon, 30 Mar 2026 16:17:23 +0100 Subject: [PATCH 29/38] integrate further commands --- pylabrobot/scales/__init__.py | 1 + pylabrobot/scales/chatterbox.py | 4 + pylabrobot/scales/mettler_toledo/backend.py | 528 ++++-- .../scales/mettler_toledo/backend_tests.py | 152 +- .../confirmed_firmware_versions.py | 13 +- .../mettler_toledo/hardware_validation.ipynb | 1601 +++++++++-------- .../scales/mettler_toledo/mt_sics_commands.md | 60 +- pylabrobot/scales/mettler_toledo/protocol.md | 14 +- pylabrobot/scales/mettler_toledo/simulator.py | 11 +- pylabrobot/scales/scale_backend.py | 8 +- 10 files changed, 1338 insertions(+), 1054 deletions(-) create mode 100644 pylabrobot/scales/chatterbox.py diff --git a/pylabrobot/scales/__init__.py b/pylabrobot/scales/__init__.py index 0a7bbb1deb3..e82615e20f3 100644 --- a/pylabrobot/scales/__init__.py +++ b/pylabrobot/scales/__init__.py @@ -1,5 +1,6 @@ """PyLabRobot scales package - frontend, backends, and error types.""" +from pylabrobot.scales.chatterbox import ScaleChatterboxBackend # backwards compat from pylabrobot.scales.mettler_toledo import MettlerToledoError, MettlerToledoWXS205SDUBackend from pylabrobot.scales.scale import Scale from pylabrobot.scales.scale_backend import ScaleBackend diff --git a/pylabrobot/scales/chatterbox.py b/pylabrobot/scales/chatterbox.py new file mode 100644 index 00000000000..4cb22ea4810 --- /dev/null +++ b/pylabrobot/scales/chatterbox.py @@ -0,0 +1,4 @@ +"""Backwards-compatible import shim. Use pylabrobot.scales.simulator instead.""" + +# TODO: remove after 2026-09 +from pylabrobot.scales.simulator import ScaleSimulator as ScaleChatterboxBackend # noqa: F401 diff --git a/pylabrobot/scales/mettler_toledo/backend.py b/pylabrobot/scales/mettler_toledo/backend.py index 688850c2266..6f4cc48d1b8 100644 --- a/pylabrobot/scales/mettler_toledo/backend.py +++ b/pylabrobot/scales/mettler_toledo/backend.py @@ -91,6 +91,13 @@ class MettlerToledoWXS205SDUBackend(ScaleBackend): # === Constructor === def __init__(self, port: Optional[str] = None, vid: int = 0x0403, pid: int = 0x6001): + """Create a new MT-SICS backend. + + Args: + port: Serial port path. If None, auto-detected by VID:PID. + vid: USB vendor ID (default 0x0403 = FTDI). + pid: USB product ID (default 0x6001 = FT232R). + """ super().__init__() self.io = Serial( @@ -103,11 +110,12 @@ def __init__(self, port: Optional[str] = None, vid: int = 0x0403, pid: int = 0x6 ) async def setup(self) -> None: + """Connect to the scale, reset to clean state, discover identity and supported commands.""" await self.io.setup() # Reset device to clean state (spec Section 2.2) - # cancel() clears the input buffer and sends @, which returns the serial number - self.serial_number = await self.cancel() + # reset() clears the input buffer and sends @, which returns the serial number + self.serial_number = await self.reset() # Discover supported commands via I0 (the definitive source per spec Section 2.2) self._supported_commands: Set[str] = await self._request_supported_commands() @@ -119,7 +127,7 @@ async def setup(self) -> None: self.capacity = await self.request_capacity() # Firmware version and configuration - self.firmware_version = await self.request_software_version() + self.firmware_version = await self.request_firmware_version() # I2 device_type encodes the configuration: "WXS205SDU WXA-Bridge" = bridge only self.configuration = "Bridge" if "Bridge" in self.device_type else "Balance" @@ -145,7 +153,9 @@ async def setup(self) -> None: if fw_version_short not in CONFIRMED_FIRMWARE_VERSIONS: logger.warning( "[MT Scale] Firmware version %r has not been tested with this driver. " - "Confirmed versions: %s. Proceed with caution.", + "Confirmed versions: %s. " + "If this version works correctly, please contribute it to " + "confirmed_firmware_versions.py so others can benefit.", self.firmware_version, ", ".join(sorted(CONFIRMED_FIRMWARE_VERSIONS)), ) @@ -162,7 +172,7 @@ async def stop(self) -> None: and the port is closed anyway. """ try: - await self.cancel() + await self.reset() except Exception: logger.warning("[MT Scale] Could not reset device before disconnecting") logger.info("[MT Scale] Disconnected from %s", self.io.port) @@ -304,6 +314,10 @@ def _parse_basic_errors(self, response: MettlerToledoResponse) -> None: raise MettlerToledoError.weight_module_electronic_mismatch(from_terminal=from_terminal) if code == "15": raise MettlerToledoError.adjustment_needed(from_terminal=from_terminal) + raise MettlerToledoError( + title="Unknown weight error", + message=f"Unrecognized error code '{error_code}' in weight response", + ) # === Command Layer === @@ -348,16 +362,17 @@ async def send_command(self, command: str, timeout: int = 60) -> List[MettlerTol return responses - # === Public high-level API === + # === Public API === + # Organized by function: cancel, identity, zero, tare, weight, measurement, + # configuration (read), display, configuration (write). - # # Cancel commands # # + # # Reset and cancel # # - async def cancel(self) -> str: + async def reset(self) -> str: """@ - Reset the device to a determined state (spec Section 2.2). - Equivalent to a power cycle: empties volatile memories, cancels all pending - commands, resets key control to default. Tare memory is NOT reset. - The cancel command is always executed, even when the device is busy. + Equivalent to a power cycle: empties volatile memories, resets key control + to default. Tare memory is NOT reset. Always executed, even when busy. Returns the serial number from the I4-style response. """ @@ -370,7 +385,7 @@ async def cancel(self) -> str: async def cancel_all(self) -> None: """C - Cancel all active and pending interface commands. - Unlike cancel() (@), this does not reset the device - it only cancels + Unlike reset() (@), this does not reset the device - it only cancels commands that were requested via this interface. Typically used to stop repeating commands (SIR, SR) or abort adjustment procedures. @@ -386,7 +401,7 @@ async def cancel_all(self) -> None: message=f"C command returned error: {responses[0]}", ) - # # Identification commands # # + # # Device identity # # async def request_serial_number(self) -> str: """Get the serial number of the scale. (I4 command)""" @@ -419,11 +434,11 @@ async def request_capacity(self) -> float: self._validate_unit(parts[-1], "I2") return float(parts[-2]) - async def request_software_version(self) -> str: - """Query the software version and type definition number. (I3 command) + async def request_firmware_version(self) -> str: + """Query the firmware version and type definition number. (I3 command) - Returns the version string (e.g. "2.10 10.28.0.493.142"). - For bridge mode (no terminal), returns the bridge software version. + Returns the version string (e.g. "1.10 18.6.4.1361.772"). + For bridge mode (no terminal), returns the bridge firmware version. """ responses = await self.send_command("I3") self._validate_response(responses[0], 3, "I3") @@ -491,33 +506,15 @@ async def request_device_info(self, category: int = 0) -> List[MettlerToledoResp return await self.send_command(f"I14 {category}") @requires_mt_sics_command("I15") - async def request_uptime(self) -> dict: - """Query the device uptime. (I15 command) - - Returns a dict with keys "days", "hours", "minutes", "seconds". - Counts time since last power-on, including short interruptions. - Not reset by @ cancel or restart. + async def request_uptime_minutes(self) -> int: + """Query the uptime in minutes since last start or restart. (I15 command) - Some devices return a single value (total days) instead of the - full days/hours/minutes/seconds breakdown. + Returns the number of minutes the device has been running since + the last power-on, start, or reset. Accuracy +/- 5%. """ responses = await self.send_command("I15") self._validate_response(responses[0], 3, "I15") - data = responses[0].data - if len(data) >= 4: - return { - "days": int(data[0]), - "hours": int(data[1]), - "minutes": int(data[2]), - "seconds": int(data[3]), - } - # Single-value format (some devices return total days only) - return { - "days": int(data[0]), - "hours": 0, - "minutes": 0, - "seconds": 0, - } + return int(responses[0].data[0]) @requires_mt_sics_command("DAT") async def request_date(self) -> str: @@ -539,126 +536,112 @@ async def request_time(self) -> str: self._validate_response(responses[0], 3, "TIM") return responses[0].data[0] - @requires_mt_sics_command("I50") - async def request_remaining_weighing_range(self) -> float: - """Query remaining maximum weighing range in grams. (I50 command) - - Returns the remaining capacity accounting for all loads currently on the - weighing platform (pre-load, tare, net load). A negative value means the - maximum weighing range has been exceeded. + @requires_mt_sics_command("I16") + async def request_next_service_date(self) -> str: + """Query the date when the balance is next due to be serviced. (I16 command)""" + responses = await self.send_command("I16") + self._validate_response(responses[0], 3, "I16") + return " ".join(responses[0].data) + + @requires_mt_sics_command("I21") + async def request_assortment_type_revision(self) -> str: + """Query the revision of assortment type tolerances. (I21 command)""" + responses = await self.send_command("I21") + self._validate_response(responses[0], 3, "I21") + return responses[0].data[0] - I50 is a multi-response command: the device sends up to 3 lines - (RangeNo 0 with B, RangeNo 1 with B, RangeNo 2 with A). We extract the - value from the first response and drain the remaining ones. - """ - responses = await self.send_command("I50") - # responses[0]: I50 B 0 (RangeNo 0 = max weighing range) - # responses[1]: I50 B 1 (RangeNo 1 = internal adjustment range) - # responses[2]: I50 A 2 (RangeNo 2 = external adjustment range) - self._validate_response(responses[0], 5, "I50") - self._validate_unit(responses[0].data[2], "I50") - return float(responses[0].data[1]) + @requires_mt_sics_command("I26") + async def request_operating_mode_after_restart(self) -> List[MettlerToledoResponse]: + """Query the operating mode after restart. (I26 command)""" + return await self.send_command("I26") - # # Zero commands # # + # # Zero # # async def zero_immediately(self) -> List[MettlerToledoResponse]: - """Zero the scale immediately. (ACTION command)""" + """Zero the scale immediately. (ZI command)""" return await self.send_command("ZI") async def zero_stable(self) -> List[MettlerToledoResponse]: - """Zero the scale when the weight is stable. (ACTION command)""" + """Zero the scale when the weight is stable. (Z command)""" return await self.send_command("Z") async def zero_timeout(self, timeout: float) -> List[MettlerToledoResponse]: - """Zero the scale after a given timeout. (ACTION command)""" - # For some reason, this will always return a syntax error (ES), even though it should be allowed - # according to the docs. + """Zero the scale after a given timeout. (ZC command) + + Not supported on WXS205SDU (returns ES despite being in the spec). + """ timeout = int(timeout * 1000) return await self.send_command(f"ZC {timeout}") async def zero( self, timeout: Union[Literal["stable"], float, int] = "stable" ) -> List[MettlerToledoResponse]: - """High level function to zero the scale. (ACTION command) + """Zero the scale. Args: - timeout: The timeout in seconds. If "stable", the scale will zero when the weight is stable. - If 0, the scale will zero immediately. If a float/int, the scale will zero after the given - timeout (in seconds). + timeout: "stable" waits for stable reading, 0 zeros immediately, + float/int zeros after that many seconds. """ - if timeout == "stable": return await self.zero_stable() - if not isinstance(timeout, (float, int)): raise TypeError("timeout must be a float or 'stable'") - if timeout < 0: raise ValueError("timeout must be greater than or equal to 0") - if timeout == 0: return await self.zero_immediately() - return await self.zero_timeout(timeout) - # # Tare commands # # + # # Tare # # async def tare_stable(self) -> List[MettlerToledoResponse]: - """Tare the scale when the weight is stable. (ACTION command)""" + """Tare the scale when the weight is stable. (T command)""" return await self.send_command("T") async def tare_immediately(self) -> List[MettlerToledoResponse]: - """Tare the scale immediately. (ACTION command)""" + """Tare the scale immediately. (TI command)""" return await self.send_command("TI") async def tare_timeout(self, timeout: float) -> List[MettlerToledoResponse]: - """Tare the scale after a given timeout. (ACTION command)""" - # For some reason, this will always return a syntax error (ES), even though it should be allowed - # according to the docs. + """Tare the scale after a given timeout. (TC command) + + Not supported on WXS205SDU (returns ES despite being in the spec). + """ timeout = int(timeout * 1000) # convert to milliseconds return await self.send_command(f"TC {timeout}") async def tare( self, timeout: Union[Literal["stable"], float, int] = "stable" ) -> List[MettlerToledoResponse]: - """High level function to tare the scale. (ACTION command) + """Tare the scale. Args: - timeout: The timeout in seconds. If "stable", the scale will tare when the weight is stable. - If 0, the scale will tare immediately. If a float/int, the scale will tare after the given - timeout (in seconds). + timeout: "stable" waits for stable reading, 0 tares immediately, + float/int tares after that many seconds. """ - if timeout == "stable": - # "Use T to tare the balance. The next stable weight value will be saved in the tare memory." return await self.tare_stable() - if not isinstance(timeout, (float, int)): raise TypeError("timeout must be a float or 'stable'") - if timeout < 0: raise ValueError("timeout must be greater than or equal to 0") - if timeout == 0: return await self.tare_immediately() return await self.tare_timeout(timeout) - # # Weight reading commands # # - async def request_tare_weight(self) -> float: - """Request tare weight value from scale's memory. (MEM-READ command) - "Use TA to query the current tare value or preset a known tare value." - """ - + """Query tare weight value from scale's memory. (TA command)""" responses = await self.send_command("TA") self._validate_response(responses[0], 4, "TA") self._validate_unit(responses[0].data[1], "TA") return float(responses[0].data[0]) async def clear_tare(self) -> List[MettlerToledoResponse]: - """TAC - Clear tare weight value (MEM-WRITE command)""" + """Clear tare weight value. (TAC command)""" return await self.send_command("TAC") + # # Weight measurement # # + async def read_stable_weight(self) -> float: """Read a stable weight value from the scale. (MEASUREMENT command) @@ -725,38 +708,45 @@ async def read_weight(self, timeout: Union[Literal["stable"], float, int] = "sta return await self.read_dynamic_weight(timeout) - # Commands for (optional) display manipulation - - async def set_display_text(self, text: str) -> List[MettlerToledoResponse]: - """Set the display text of the scale. Return to the normal weight display with - self.set_weight_display().""" - return await self.send_command(f'D "{text}"') - - async def set_weight_display(self) -> List[MettlerToledoResponse]: - """Return the display to the normal weight display.""" - return await self.send_command("DW") - - # # Configuration commands # # - - @requires_mt_sics_command("M21") - async def set_host_unit_grams(self) -> List[MettlerToledoResponse]: - """Set the host output unit to grams. (M21 command)""" - return await self.send_command("M21 0 0") - @requires_mt_sics_command("M28") async def measure_temperature(self) -> float: - """Query the current temperature from the scale's internal sensor in degrees C. (M28 command) + """Read the current temperature from the scale's internal sensor in degrees C. (M28 command) The number of temperature sensors depends on the product. This method returns the value from the first sensor. Useful for gravimetric verification where temperature affects liquid density and evaporation rate. """ responses = await self.send_command("M28") - # M28 A 1 22.5 (single sensor) or M28 B 1 22.5 ... M28 A 2 23.0 (multi-sensor) self._validate_response(responses[0], 4, "M28") return float(responses[0].data[1]) - # # Batch 2 - Configuration queries (read-only) # # + @requires_mt_sics_command("SIS") + async def request_net_weight_with_status(self) -> MettlerToledoResponse: + """Query net weight with unit and weighing status in one call. (SIS command) + + Response data fields: + data[0] = State: 0=stable, 1=dynamic, 2=stable inaccurate (MinWeigh), + 3=dynamic inaccurate, 4=overload, 5=underload, 6=error + data[1] = Net weight value + data[2] = Unit code: 0=g, 1=kg, 3=mg, 4=ug, 5=ct, 7=lb, 8=oz, etc. + data[3] = Readability (number of decimal places, 0-6) + data[4] = Step: 1, 2, 5, 10, 20, 50, or 100 + data[5] = Approval: 0=standard (not approved), 1=e=d, 10=e=10d, 100=e=100d, -1=unapproved + data[6] = Info: 0=without tare, 1=net with weighed tare, 2=net with stored tare + """ + responses = await self.send_command("SIS") + return responses[0] + + @requires_mt_sics_command("SNR") + async def read_stable_weight_repeat_on_change(self) -> List[MettlerToledoResponse]: + """Start sending stable weight values on every stable weight change. (SNR command) + + The device sends a new value each time the weight changes and stabilizes. + Use reset() to stop. + """ + return await self.send_command("SNR") + + # # Device configuration (read-only) # # @requires_mt_sics_command("M01") async def request_weighing_mode(self) -> int: @@ -768,6 +758,11 @@ async def request_weighing_mode(self) -> int: self._validate_response(responses[0], 3, "M01") return int(responses[0].data[0]) + # @requires_mt_sics_command("M01") + # async def set_weighing_mode(self, mode: int) -> None: + # """Set weighing mode. (M01) WRITES TO DEVICE MEMORY.""" + # await self.send_command(f"M01 {mode}") + @requires_mt_sics_command("M02") async def request_environment_condition(self) -> int: """Query the current environment condition setting. (M02 command) @@ -779,6 +774,11 @@ async def request_environment_condition(self) -> int: self._validate_response(responses[0], 3, "M02") return int(responses[0].data[0]) + # @requires_mt_sics_command("M02") + # async def set_environment_condition(self, condition: int) -> None: + # """Set environment condition. (M02) WRITES TO DEVICE MEMORY.""" + # await self.send_command(f"M02 {condition}") + @requires_mt_sics_command("M03") async def request_auto_zero(self) -> int: """Query the current auto zero setting. (M03 command) @@ -791,37 +791,104 @@ async def request_auto_zero(self) -> int: self._validate_response(responses[0], 3, "M03") return int(responses[0].data[0]) - @requires_mt_sics_command("M27") - async def request_adjustment_history(self) -> List[MettlerToledoResponse]: - """Query the adjustment (calibration) history. (M27 command) + # @requires_mt_sics_command("M03") + # async def set_auto_zero(self, enabled: int) -> None: + # """Set auto zero. (M03) WRITES TO DEVICE MEMORY.""" + # await self.send_command(f"M03 {enabled}") - Returns multi-response with each adjustment entry containing: - entry number, date, time, mode (0=built-in, 1=external), and weight used. - """ - return await self.send_command("M27") + @requires_mt_sics_command("M17") + async def request_profact_time_criteria(self) -> List[MettlerToledoResponse]: + """Query ProFACT single time criteria. (M17 command)""" + return await self.send_command("M17") - @requires_mt_sics_command("SIS") - async def request_net_weight_with_status(self) -> MettlerToledoResponse: - """Query net weight with unit and weighing status. (SIS command) + # @requires_mt_sics_command("M17") + # async def set_profact_time_criteria(self, ...) -> None: + # """Set ProFACT time criteria. (M17) WRITES TO DEVICE MEMORY.""" + # ... - Returns a single response with weight value, unit, and additional - status information (actual unit and weighing status) in one call. - """ - responses = await self.send_command("SIS") - return responses[0] + @requires_mt_sics_command("M18") + async def request_profact_temperature_criterion(self) -> List[MettlerToledoResponse]: + """Query ProFACT/FACT temperature criterion. (M18 command)""" + return await self.send_command("M18") - @requires_mt_sics_command("SNR") - async def read_stable_weight_repeat_on_change(self) -> List[MettlerToledoResponse]: - """Start sending stable weight values on every stable weight change. (SNR command) + # @requires_mt_sics_command("M18") + # async def set_profact_temperature_criterion(self, ...) -> None: + # """Set ProFACT temperature criterion. (M18) WRITES TO DEVICE MEMORY.""" + # ... - The device will send a new weight value each time the weight changes - and stabilizes. Use cancel() or cancel_all() to stop. - """ - return await self.send_command("SNR") + @requires_mt_sics_command("M19") + async def request_adjustment_weight(self) -> List[MettlerToledoResponse]: + """Query the adjustment weight setting. (M19 command)""" + return await self.send_command("M19") + + # @requires_mt_sics_command("M19") + # async def set_adjustment_weight(self, ...) -> None: + # """Set adjustment weight. (M19) WRITES TO DEVICE MEMORY.""" + # ... + + @requires_mt_sics_command("M20") + async def request_test_weight(self) -> List[MettlerToledoResponse]: + """Query the test weight setting. (M20 command)""" + return await self.send_command("M20") + + # @requires_mt_sics_command("M20") + # async def set_test_weight(self, ...) -> None: + # """Set test weight. (M20) WRITES TO DEVICE MEMORY.""" + # ... + + @requires_mt_sics_command("M29") + async def request_weighing_value_release(self) -> List[MettlerToledoResponse]: + """Query the weighing value release setting. (M29 command)""" + return await self.send_command("M29") + + # @requires_mt_sics_command("M29") + # async def set_weighing_value_release(self, ...) -> None: + # """Set weighing value release. (M29) WRITES TO DEVICE MEMORY.""" + # ... + + @requires_mt_sics_command("M31") + async def request_operating_mode(self) -> List[MettlerToledoResponse]: + """Query the operating mode after restart. (M31 command)""" + return await self.send_command("M31") + + # @requires_mt_sics_command("M31") + # async def set_operating_mode(self, ...) -> None: + # """Set operating mode after restart. (M31) WRITES TO DEVICE MEMORY.""" + # ... + + @requires_mt_sics_command("M32") + async def request_profact_time(self) -> List[MettlerToledoResponse]: + """Query ProFACT time criteria. (M32 command)""" + return await self.send_command("M32") + + # @requires_mt_sics_command("M32") + # async def set_profact_time(self, ...) -> None: + # """Set ProFACT time. (M32) WRITES TO DEVICE MEMORY.""" + # ... + + @requires_mt_sics_command("M33") + async def request_profact_day(self) -> List[MettlerToledoResponse]: + """Query ProFACT day of the week. (M33 command)""" + return await self.send_command("M33") + + # @requires_mt_sics_command("M33") + # async def set_profact_day(self, ...) -> None: + # """Set ProFACT day of the week. (M33) WRITES TO DEVICE MEMORY.""" + # ... + + @requires_mt_sics_command("M35") + async def request_zeroing_mode(self) -> List[MettlerToledoResponse]: + """Query the zeroing mode at startup. (M35 command)""" + return await self.send_command("M35") + + # @requires_mt_sics_command("M35") + # async def set_zeroing_mode(self, ...) -> None: + # """Set zeroing mode at startup. (M35) WRITES TO DEVICE MEMORY.""" + # ... @requires_mt_sics_command("UPD") async def request_update_rate(self) -> float: - """Query the current update rate for SIR/SIRU streaming commands. (UPD command) + """Query the current update rate for SIR/SIRU streaming. (UPD command) Returns the update rate in values per second. """ @@ -829,73 +896,172 @@ async def request_update_rate(self) -> float: self._validate_response(responses[0], 3, "UPD") return float(responses[0].data[0]) - # WARNING: The following set commands permanently modify device settings. - # They persist across power cycles and cannot be undone with @ cancel. - # The only way to reset is via FSET (factory reset) or terminal menu. - # - # @requires_mt_sics_command("M01") - # async def set_weighing_mode(self, mode: int) -> None: - # """Set the weighing mode. (M01 command) WRITES TO DEVICE MEMORY. - # 0=Normal, 1=Dosing, 2=Sensor, 3=Check weighing, 6=Raw/No filter.""" - # await self.send_command(f"M01 {mode}") - # - # @requires_mt_sics_command("M02") - # async def set_environment_condition(self, condition: int) -> None: - # """Set the environment condition. (M02 command) WRITES TO DEVICE MEMORY. - # 0=Very stable, 1=Stable, 2=Standard, 3=Unstable, 4=Very unstable, 5=Automatic.""" - # await self.send_command(f"M02 {condition}") - # - # @requires_mt_sics_command("M03") - # async def set_auto_zero(self, enabled: int) -> None: - # """Set the auto zero function. (M03 command) WRITES TO DEVICE MEMORY. - # 0=off, 1=on.""" - # await self.send_command(f"M03 {enabled}") - # # @requires_mt_sics_command("UPD") # async def set_update_rate(self, rate: float) -> None: - # """Set the update rate for SIR/SIRU. (UPD command) WRITES TO DEVICE MEMORY.""" + # """Set streaming update rate. (UPD) WRITES TO DEVICE MEMORY.""" # await self.send_command(f"UPD {rate}") - # + + @requires_mt_sics_command("C0") + async def request_adjustment_setting(self) -> List[MettlerToledoResponse]: + """Query the current adjustment setting. (C0 command)""" + return await self.send_command("C0") + + # @requires_mt_sics_command("C0") + # async def set_adjustment_setting(self, ...) -> None: + # """Set adjustment setting. (C0) WRITES TO DEVICE MEMORY.""" + # ... + + @requires_mt_sics_command("COM") + async def request_serial_parameters(self) -> List[MettlerToledoResponse]: + """Query current serial interface parameters. (COM command)""" + return await self.send_command("COM") + # @requires_mt_sics_command("COM") # async def set_serial_parameters(self, ...) -> None: - # """Set serial port parameters. (COM command) WRITES TO DEVICE MEMORY. + # """Set serial port parameters. (COM) WRITES TO DEVICE MEMORY. # WARNING: changing baud rate will lose communication.""" # ... + + @requires_mt_sics_command("FCUT") + async def request_filter_cutoff(self) -> List[MettlerToledoResponse]: + """Query the filter cut-off frequency. (FCUT command)""" + return await self.send_command("FCUT") + + # @requires_mt_sics_command("FCUT") + # async def set_filter_cutoff(self, frequency: float) -> None: + # """Set filter cut-off frequency. (FCUT) WRITES TO DEVICE MEMORY.""" + # await self.send_command(f"FCUT {frequency}") + + @requires_mt_sics_command("USTB") + async def request_stability_criteria(self) -> List[MettlerToledoResponse]: + """Query the user-defined stability criteria. (USTB command)""" + return await self.send_command("USTB") + + # @requires_mt_sics_command("USTB") + # async def set_stability_criteria(self, ...) -> None: + # """Set stability criteria. (USTB) WRITES TO DEVICE MEMORY.""" + # ... + + @requires_mt_sics_command("TST0") + async def request_test_settings(self) -> List[MettlerToledoResponse]: + """Query current test function settings. (TST0 command)""" + return await self.send_command("TST0") + + # @requires_mt_sics_command("TST0") + # async def set_test_settings(self, ...) -> None: + # """Set test function settings. (TST0) WRITES TO DEVICE MEMORY.""" + # ... + + @requires_mt_sics_command("I50") + async def request_remaining_weighing_range(self) -> float: + """Query remaining maximum weighing range in grams. (I50 command) + + Returns the remaining capacity accounting for all loads currently on the + weighing platform (pre-load, tare, net load). A negative value means the + maximum weighing range has been exceeded. + + Multi-response: the device sends up to 3 lines (B, B, A). + """ + responses = await self.send_command("I50") + self._validate_response(responses[0], 5, "I50") + self._validate_unit(responses[0].data[2], "I50") + return float(responses[0].data[1]) + + @requires_mt_sics_command("M27") + async def request_adjustment_history(self) -> List[MettlerToledoResponse]: + """Query the adjustment (calibration) history. (M27 command) + + Returns multi-response with each adjustment entry containing: + entry number, date, time, mode (0=built-in, 1=external), and weight used. + """ + return await self.send_command("M27") + + @requires_mt_sics_command("LST") + async def request_user_settings(self) -> List[MettlerToledoResponse]: + """Query all current user-configurable settings. (LST command) + + Returns a multi-response listing every configurable parameter and its value. + """ + return await self.send_command("LST") + + @requires_mt_sics_command("RDB") + async def request_readability(self) -> List[MettlerToledoResponse]: + """Query the readability setting. (RDB command)""" + return await self.send_command("RDB") + + # # Display # # + + async def set_display_text(self, text: str) -> List[MettlerToledoResponse]: + """Write text to the display. (D command) Not available in bridge mode. + + Use set_weight_display() to restore the normal weight display. + """ + return await self.send_command(f'D "{text}"') + + async def set_weight_display(self) -> List[MettlerToledoResponse]: + """Restore the normal weight display. (DW command)""" + return await self.send_command("DW") + + # # Configuration (write - no corresponding query) # # + + @requires_mt_sics_command("M21") + async def set_host_unit_grams(self) -> List[MettlerToledoResponse]: + """Set the host output unit to grams. (M21 command) + + Called automatically during setup() if supported. + """ + return await self.send_command("M21 0 0") + + # # Commented out - standalone write commands # # + # + # @requires_mt_sics_command("I10") + # async def set_device_id(self, device_id: str) -> None: + # """Set device name. (I10) WRITES TO EEPROM. Max 20 chars.""" + # await self.send_command(f'I10 "{device_id}"') # # @requires_mt_sics_command("FSET") # async def factory_reset(self, exclusion: int = 0) -> None: - # """Reset ALL settings to factory defaults. (FSET command) DESTRUCTIVE. - # 0=reset all, 1=keep comm params, 2=keep comm+adjustment.""" + # """Reset ALL settings to factory defaults. (FSET) DESTRUCTIVE.""" # await self.send_command(f"FSET {exclusion}") - # # Batch 3 - Calibration and streaming (require physical interaction or architecture changes) # # - - # WARNING: Adjustment commands move internal calibration weights. - # Do not run during a weighing protocol. + # # Commented out - require physical interaction or architecture changes # # # # @requires_mt_sics_command("C1") # async def start_adjustment(self) -> List[MettlerToledoResponse]: - # """Start adjustment according to current settings. (C1 command) - # Multi-response: sends progress updates until complete.""" + # """Start adjustment. (C1) Moves internal calibration weights.""" # return await self.send_command("C1") # + # @requires_mt_sics_command("C2") + # async def start_adjustment_external_weight(self) -> List[MettlerToledoResponse]: + # """Adjust with external weight. (C2) Requires placing calibration weight.""" + # return await self.send_command("C2") + # # @requires_mt_sics_command("C3") # async def start_adjustment_builtin_weight(self) -> List[MettlerToledoResponse]: - # """Start adjustment with built-in weight. (C3 command) - # Multi-response: sends progress updates until complete.""" + # """Adjust with built-in weight. (C3) Moves internal weights.""" # return await self.send_command("C3") - - # NOTE: SIR and SR streaming commands require an async iterator or callback - # architecture to handle continuous responses. Not yet implemented. + # + # @requires_mt_sics_command("TST1") + # async def start_test(self) -> List[MettlerToledoResponse]: + # """Run test according to current settings. (TST1) Moves internal weights.""" + # return await self.send_command("TST1") + # + # @requires_mt_sics_command("TST2") + # async def start_test_external_weight(self) -> List[MettlerToledoResponse]: + # """Run test with external weight. (TST2) Requires placing test weight.""" + # return await self.send_command("TST2") + # + # @requires_mt_sics_command("TST3") + # async def start_test_builtin_weight(self) -> List[MettlerToledoResponse]: + # """Run test with built-in weight. (TST3) Moves internal weights.""" + # return await self.send_command("TST3") # # @requires_mt_sics_command("SIR") # async def read_weight_immediately_repeat(self) -> ...: - # """Start streaming weight values at the update rate. (SIR command) - # Use cancel() to stop.""" + # """Stream weight values at update rate. (SIR) Needs async iterator.""" # ... # # @requires_mt_sics_command("SR") # async def read_stable_weight_repeat(self) -> ...: - # """Start sending stable weight on any weight change. (SR command) - # Use cancel() to stop.""" + # """Stream stable weight on change. (SR) Needs async iterator.""" # ... diff --git a/pylabrobot/scales/mettler_toledo/backend_tests.py b/pylabrobot/scales/mettler_toledo/backend_tests.py index f1ea0396773..0f14497ff48 100644 --- a/pylabrobot/scales/mettler_toledo/backend_tests.py +++ b/pylabrobot/scales/mettler_toledo/backend_tests.py @@ -154,9 +154,9 @@ async def test_i50_multi_response(self): self.assertEqual(remaining, 170.0) async def test_cancel_returns_serial_number(self): - """cancel() sends @ which responds with I4-style (command echo is I4, not @). + """reset() sends @ which responds with I4-style (command echo is I4, not @). Must correctly parse the serial number despite the unusual response format.""" - sn = await self.backend.cancel() + sn = await self.backend.reset() self.assertEqual(sn, "SIM0000001") async def test_unknown_command_returns_syntax_error(self): @@ -185,32 +185,11 @@ async def test_measure_temperature_blocked_when_unsupported(self): self.assertIn("M28", str(ctx.exception)) self.assertIn("not implemented", str(ctx.exception)) - async def test_uptime_single_value_format(self): - """Some devices return uptime as a single number (total days) instead of - days/hours/minutes/seconds. The parser must handle both formats.""" - # Default simulator returns multi-value format - uptime = await self.backend.request_uptime() - self.assertEqual(uptime["days"], 42) - self.assertEqual(uptime["hours"], 3) - - async def test_uptime_single_value_fallback(self): - """When the device returns a single uptime value, hours/minutes/seconds - must default to 0. This format was discovered on the WXS205SDU hardware.""" - backend = MettlerToledoSICSSimulator() - scale = Scale(name="s", backend=backend, size_x=0, size_y=0, size_z=0) - await scale.setup() - # Patch the simulator to return single-value format - original = backend._build_response - - def patched(command): - if command.split()[0] == "I15": - return [MettlerToledoResponse("I15", "A", ["203"])] - return original(command) - - backend._build_response = patched - uptime = await backend.request_uptime() - self.assertEqual(uptime["days"], 203) - self.assertEqual(uptime["hours"], 0) + async def test_uptime_returns_minutes(self): + """I15 returns uptime in minutes since last start or restart. + The spec shows I15 A with accuracy +/- 5%.""" + minutes = await self.backend.request_uptime_minutes() + self.assertEqual(minutes, 1440) # Simulator returns 24 hours async def test_configuration_bridge_detection(self): """Device type containing 'Bridge' must set configuration to 'Bridge'. @@ -271,6 +250,123 @@ async def test_request_weighing_mode(self): mode = await self.backend.request_weighing_mode() self.assertEqual(mode, 0) # Normal weighing mode + # -- Identity and diagnostics -- + + async def test_request_firmware_version(self): + """Firmware version must return a non-empty string. + Hardware returns '1.10 18.6.4.1361.772' - validates I3 parsing.""" + version = await self.backend.request_firmware_version() + self.assertIsInstance(version, str) + self.assertGreater(len(version), 0) + + async def test_request_model_designation(self): + """Model designation must return the device type string. + Hardware returns 'WXS205SDU' - validates I11 parsing.""" + model = await self.backend.request_model_designation() + self.assertEqual(model, "WXS205SDU") + + # -- Setup and teardown -- + + async def test_setup_populates_firmware_version(self): + """setup() must query I3 and store the firmware version. + The firmware check is new and untested - if it breaks, the + firmware warning logic fails silently.""" + self.assertIsNotNone(self.backend.firmware_version) + self.assertGreater(len(self.backend.firmware_version), 0) + + async def test_setup_populates_configuration(self): + """setup() must detect 'Balance' for default simulator (no 'Bridge' in type). + Drives which commands are expected to work on the device.""" + self.assertEqual(self.backend.configuration, "Balance") + + # -- Weight dispatch -- + + async def test_read_weight_timeout_zero_dispatches_to_si(self): + """read_weight(timeout=0) must use SI (immediate read). + If it dispatches to S (stable) instead, the call blocks waiting + for stability that may never come.""" + self.backend.platform_weight = 7.5 + weight = await self.scale.read_weight(timeout=0) + self.assertEqual(weight, 7.5) + + async def test_read_weight_rejects_negative_timeout(self): + """Negative timeout must raise ValueError. + Without this guard, a negative timeout would be converted to + a negative millisecond value and sent to the device.""" + with self.assertRaises(ValueError): + await self.scale.read_weight(timeout=-1) + + async def test_tare_timeout_zero_dispatches_to_ti(self): + """tare(timeout=0) must use TI (immediate tare). + Validates the timeout dispatcher sends the right MT-SICS command.""" + self.backend.platform_weight = 30.0 + await self.scale.tare(timeout=0) + tare = await self.scale.request_tare_weight() + self.assertEqual(tare, 30.0) + + # -- Batch 2 configuration queries -- + + async def test_request_environment_condition(self): + """Environment condition must return an integer. + Hardware returned 2 (Standard) - validates M02 parsing.""" + env = await self.backend.request_environment_condition() + self.assertEqual(env, 2) + + async def test_request_auto_zero(self): + """Auto zero setting must return an integer. + Hardware returned 0 (off) - validates M03 parsing.""" + auto_zero = await self.backend.request_auto_zero() + self.assertEqual(auto_zero, 1) # Simulator default is on + + async def test_request_update_rate(self): + """Update rate must return a float in values per second. + Hardware returned 10.173 - validates UPD parsing.""" + rate = await self.backend.request_update_rate() + self.assertEqual(rate, 18.3) # Simulator default + + # -- SIS response format -- + + async def test_sis_response_has_seven_fields(self): + """SIS must return 7 data fields: state, weight, unit, readability, + step, approval, info. Format confirmed from spec p.234-235 and + hardware validation.""" + resp = await self.backend.request_net_weight_with_status() + self.assertEqual(len(resp.data), 7) + self.assertEqual(resp.data[2], "0") # unit code 0 = grams + self.assertEqual(resp.data[3], "5") # readability = 5 decimal places + + async def test_sis_tare_info_field_tracks_state(self): + """SIS data[6] must be '0' without tare, '1' with weighed tare. + Validates the simulator correctly tracks tare state in the SIS response.""" + resp_no_tare = await self.backend.request_net_weight_with_status() + self.assertEqual(resp_no_tare.data[6], "0") # no tare + + self.backend.platform_weight = 50.0 + await self.scale.tare() + resp_with_tare = await self.backend.request_net_weight_with_status() + self.assertEqual(resp_with_tare.data[6], "1") # weighed tare + + # -- I50 physics simulation -- + + async def test_i50_remaining_range_computed_from_capacity(self): + """I50 remaining range must equal capacity minus total sensor reading. + Validates the simulator computes this correctly.""" + self.backend.platform_weight = 50.0 + self.backend.sample_weight = 10.0 + remaining = await self.backend.request_remaining_weighing_range() + self.assertEqual(remaining, 160.0) # 220 - 60 + + # -- I0 command discovery -- + + async def test_i0_returns_supported_commands_set(self): + """_request_supported_commands must parse I0 multi-response into a Set[str]. + This is the foundation of all command gating.""" + commands = await self.backend._request_supported_commands() + self.assertIsInstance(commands, set) + self.assertIn("S", commands) + self.assertIn("M28", commands) + self.assertNotIn("NONEXISTENT", commands) + if __name__ == "__main__": unittest.main() diff --git a/pylabrobot/scales/mettler_toledo/confirmed_firmware_versions.py b/pylabrobot/scales/mettler_toledo/confirmed_firmware_versions.py index f248236a7ea..a34f346e35c 100644 --- a/pylabrobot/scales/mettler_toledo/confirmed_firmware_versions.py +++ b/pylabrobot/scales/mettler_toledo/confirmed_firmware_versions.py @@ -1,13 +1,14 @@ """Firmware versions confirmed to work with this driver. -If the connected device runs a firmware version not in this list, -a warning is emitted during setup(). Please report untested versions -that work so they can be added. +The firmware version is queried via the I3 command (request_firmware_version) during setup(). +If the connected device runs a version not in this list, a warning +is logged. Please report untested versions that work so they can +be added. Only the major.minor version is checked (e.g. "1.10"), not the full -string (e.g. "1.10 18.6.4.1361.772"), because the second part is -a type definition number that varies by hardware revision and model -while the firmware behavior is determined by the version number. +I3 response string (e.g. "1.10 18.6.4.1361.772"), because the second +part is a type definition number that varies by hardware revision and +model while the firmware behavior is determined by the version number. """ CONFIRMED_FIRMWARE_VERSIONS = [ diff --git a/pylabrobot/scales/mettler_toledo/hardware_validation.ipynb b/pylabrobot/scales/mettler_toledo/hardware_validation.ipynb index a81080acb00..385f1351e95 100644 --- a/pylabrobot/scales/mettler_toledo/hardware_validation.ipynb +++ b/pylabrobot/scales/mettler_toledo/hardware_validation.ipynb @@ -33,7 +33,7 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 13:31:06,771 - pylabrobot - INFO - === Hardware validation started ===\n" + "2026-03-30 13:22:09,309 - pylabrobot - INFO - === Hardware validation started ===\n" ] } ], @@ -65,161 +65,161 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 13:31:06,791 - pylabrobot.io.serial - INFO - Using explicitly provided port: /dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0 (for VID=1027, PID=24577)\n", - "2026-03-30 13:31:06,798 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] reset_input_buffer\n", - "2026-03-30 13:31:06,800 - pylabrobot - IO - [MT Scale] Sent command: @\n", - "2026-03-30 13:31:06,803 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'@\\r\\n'\n", - "2026-03-30 13:31:06,860 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I4 A \"B207696838\"\\r\\n'\n", - "2026-03-30 13:31:06,861 - pylabrobot - IO - [MT Scale] Received response: b'I4 A \"B207696838\"\\r\\n'\n", - "2026-03-30 13:31:06,862 - pylabrobot - IO - [MT Scale] Sent command: I0\n", - "2026-03-30 13:31:06,863 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I0\\r\\n'\n", - "2026-03-30 13:31:06,891 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I0\"\\r\\n'\n", - "2026-03-30 13:31:06,892 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I0\"\\r\\n'\n", - "2026-03-30 13:31:06,908 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I1\"\\r\\n'\n", - "2026-03-30 13:31:06,909 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I1\"\\r\\n'\n", - "2026-03-30 13:31:06,924 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I2\"\\r\\n'\n", - "2026-03-30 13:31:06,925 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I2\"\\r\\n'\n", - "2026-03-30 13:31:06,939 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I3\"\\r\\n'\n", - "2026-03-30 13:31:06,940 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I3\"\\r\\n'\n", - "2026-03-30 13:31:06,956 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I4\"\\r\\n'\n", - "2026-03-30 13:31:06,956 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I4\"\\r\\n'\n", - "2026-03-30 13:31:06,958 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I5\"\\r\\n'\n", - "2026-03-30 13:31:06,959 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I5\"\\r\\n'\n", - "2026-03-30 13:31:06,972 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"S\"\\r\\n'\n", - "2026-03-30 13:31:06,973 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"S\"\\r\\n'\n", - "2026-03-30 13:31:06,988 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"SI\"\\r\\n'\n", - "2026-03-30 13:31:06,988 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"SI\"\\r\\n'\n", - "2026-03-30 13:31:07,004 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"SIR\"\\r\\n'\n", - "2026-03-30 13:31:07,004 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"SIR\"\\r\\n'\n", - "2026-03-30 13:31:07,020 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"Z\"\\r\\n'\n", - "2026-03-30 13:31:07,021 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"Z\"\\r\\n'\n", - "2026-03-30 13:31:07,022 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"ZI\"\\r\\n'\n", - "2026-03-30 13:31:07,023 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"ZI\"\\r\\n'\n", - "2026-03-30 13:31:07,036 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"@\"\\r\\n'\n", - "2026-03-30 13:31:07,036 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"@\"\\r\\n'\n", - "2026-03-30 13:31:07,052 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"SR\"\\r\\n'\n", - "2026-03-30 13:31:07,053 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"SR\"\\r\\n'\n", - "2026-03-30 13:31:07,067 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"T\"\\r\\n'\n", - "2026-03-30 13:31:07,068 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"T\"\\r\\n'\n", - "2026-03-30 13:31:07,084 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"TA\"\\r\\n'\n", - "2026-03-30 13:31:07,084 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"TA\"\\r\\n'\n", - "2026-03-30 13:31:07,100 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"TAC\"\\r\\n'\n", - "2026-03-30 13:31:07,101 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"TAC\"\\r\\n'\n", - "2026-03-30 13:31:07,115 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"TI\"\\r\\n'\n", - "2026-03-30 13:31:07,116 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"TI\"\\r\\n'\n", - "2026-03-30 13:31:07,117 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C0\"\\r\\n'\n", - "2026-03-30 13:31:07,118 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"C0\"\\r\\n'\n", - "2026-03-30 13:31:07,132 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C1\"\\r\\n'\n", - "2026-03-30 13:31:07,132 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"C1\"\\r\\n'\n", - "2026-03-30 13:31:07,148 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C2\"\\r\\n'\n", - "2026-03-30 13:31:07,149 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"C2\"\\r\\n'\n", - "2026-03-30 13:31:07,163 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C3\"\\r\\n'\n", - "2026-03-30 13:31:07,164 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"C3\"\\r\\n'\n", - "2026-03-30 13:31:07,180 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"COM\"\\r\\n'\n", - "2026-03-30 13:31:07,180 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"COM\"\\r\\n'\n", - "2026-03-30 13:31:07,195 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"DAT\"\\r\\n'\n", - "2026-03-30 13:31:07,196 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"DAT\"\\r\\n'\n", - "2026-03-30 13:31:07,212 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I10\"\\r\\n'\n", - "2026-03-30 13:31:07,213 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I10\"\\r\\n'\n", - "2026-03-30 13:31:07,228 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I11\"\\r\\n'\n", - "2026-03-30 13:31:07,228 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I11\"\\r\\n'\n", - "2026-03-30 13:31:07,230 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I14\"\\r\\n'\n", - "2026-03-30 13:31:07,231 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I14\"\\r\\n'\n", - "2026-03-30 13:31:07,243 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I15\"\\r\\n'\n", - "2026-03-30 13:31:07,244 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I15\"\\r\\n'\n", - "2026-03-30 13:31:07,260 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I16\"\\r\\n'\n", - "2026-03-30 13:31:07,260 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I16\"\\r\\n'\n", - "2026-03-30 13:31:07,276 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I21\"\\r\\n'\n", - "2026-03-30 13:31:07,277 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I21\"\\r\\n'\n", - "2026-03-30 13:31:07,291 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I22\"\\r\\n'\n", - "2026-03-30 13:31:07,292 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I22\"\\r\\n'\n", - "2026-03-30 13:31:07,307 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I23\"\\r\\n'\n", - "2026-03-30 13:31:07,308 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I23\"\\r\\n'\n", - "2026-03-30 13:31:07,324 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I24\"\\r\\n'\n", - "2026-03-30 13:31:07,324 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I24\"\\r\\n'\n", - "2026-03-30 13:31:07,339 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I25\"\\r\\n'\n", - "2026-03-30 13:31:07,340 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I25\"\\r\\n'\n", - "2026-03-30 13:31:07,355 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I26\"\\r\\n'\n", - "2026-03-30 13:31:07,356 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I26\"\\r\\n'\n", - "2026-03-30 13:31:07,371 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M01\"\\r\\n'\n", - "2026-03-30 13:31:07,371 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M01\"\\r\\n'\n", - "2026-03-30 13:31:07,387 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M02\"\\r\\n'\n", - "2026-03-30 13:31:07,388 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M02\"\\r\\n'\n", - "2026-03-30 13:31:07,403 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M03\"\\r\\n'\n", - "2026-03-30 13:31:07,404 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M03\"\\r\\n'\n", - "2026-03-30 13:31:07,405 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M17\"\\r\\n'\n", - "2026-03-30 13:31:07,407 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M17\"\\r\\n'\n", - "2026-03-30 13:31:07,419 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M18\"\\r\\n'\n", - "2026-03-30 13:31:07,420 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M18\"\\r\\n'\n", - "2026-03-30 13:31:07,435 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M19\"\\r\\n'\n", - "2026-03-30 13:31:07,436 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M19\"\\r\\n'\n", - "2026-03-30 13:31:07,452 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M20\"\\r\\n'\n", - "2026-03-30 13:31:07,452 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M20\"\\r\\n'\n", - "2026-03-30 13:31:07,467 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M21\"\\r\\n'\n", - "2026-03-30 13:31:07,468 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M21\"\\r\\n'\n", - "2026-03-30 13:31:07,483 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M27\"\\r\\n'\n", - "2026-03-30 13:31:07,484 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M27\"\\r\\n'\n", - "2026-03-30 13:31:07,500 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M28\"\\r\\n'\n", - "2026-03-30 13:31:07,500 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M28\"\\r\\n'\n", - "2026-03-30 13:31:07,515 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M29\"\\r\\n'\n", - "2026-03-30 13:31:07,516 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M29\"\\r\\n'\n", - "2026-03-30 13:31:07,531 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M31\"\\r\\n'\n", - "2026-03-30 13:31:07,532 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M31\"\\r\\n'\n", - "2026-03-30 13:31:07,547 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M32\"\\r\\n'\n", - "2026-03-30 13:31:07,547 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M32\"\\r\\n'\n", - "2026-03-30 13:31:07,563 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M33\"\\r\\n'\n", - "2026-03-30 13:31:07,564 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M33\"\\r\\n'\n", - "2026-03-30 13:31:07,565 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M35\"\\r\\n'\n", - "2026-03-30 13:31:07,566 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M35\"\\r\\n'\n", - "2026-03-30 13:31:07,579 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"SIS\"\\r\\n'\n", - "2026-03-30 13:31:07,580 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"SIS\"\\r\\n'\n", - "2026-03-30 13:31:07,595 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"SNR\"\\r\\n'\n", - "2026-03-30 13:31:07,595 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"SNR\"\\r\\n'\n", - "2026-03-30 13:31:07,611 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TIM\"\\r\\n'\n", - "2026-03-30 13:31:07,612 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TIM\"\\r\\n'\n", - "2026-03-30 13:31:07,628 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST0\"\\r\\n'\n", - "2026-03-30 13:31:07,629 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TST0\"\\r\\n'\n", - "2026-03-30 13:31:07,643 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST1\"\\r\\n'\n", - "2026-03-30 13:31:07,646 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TST1\"\\r\\n'\n", - "2026-03-30 13:31:07,659 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST2\"\\r\\n'\n", - "2026-03-30 13:31:07,662 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TST2\"\\r\\n'\n", - "2026-03-30 13:31:07,675 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST3\"\\r\\n'\n", - "2026-03-30 13:31:07,676 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TST3\"\\r\\n'\n", - "2026-03-30 13:31:07,693 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"UPD\"\\r\\n'\n", - "2026-03-30 13:31:07,698 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"UPD\"\\r\\n'\n", - "2026-03-30 13:31:07,707 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"FCUT\"\\r\\n'\n", - "2026-03-30 13:31:07,709 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 3 \"FCUT\"\\r\\n'\n", - "2026-03-30 13:31:07,723 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"FSET\"\\r\\n'\n", - "2026-03-30 13:31:07,726 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 3 \"FSET\"\\r\\n'\n", - "2026-03-30 13:31:07,739 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"LST\"\\r\\n'\n", - "2026-03-30 13:31:07,740 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 3 \"LST\"\\r\\n'\n", - "2026-03-30 13:31:07,755 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"RDB\"\\r\\n'\n", - "2026-03-30 13:31:07,758 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 3 \"RDB\"\\r\\n'\n", - "2026-03-30 13:31:07,772 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 A 3 \"USTB\"\\r\\n'\n", - "2026-03-30 13:31:07,773 - pylabrobot - IO - [MT Scale] Received response: b'I0 A 3 \"USTB\"\\r\\n'\n", - "2026-03-30 13:31:07,773 - pylabrobot - IO - [MT Scale] Sent command: I2\n", - "2026-03-30 13:31:07,775 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I2\\r\\n'\n", - "2026-03-30 13:31:07,835 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", - "2026-03-30 13:31:07,836 - pylabrobot - IO - [MT Scale] Received response: b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", - "2026-03-30 13:31:07,837 - pylabrobot - IO - [MT Scale] Sent command: I2\n", - "2026-03-30 13:31:07,839 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I2\\r\\n'\n", - "2026-03-30 13:31:07,898 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", - "2026-03-30 13:31:07,899 - pylabrobot - IO - [MT Scale] Received response: b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", - "2026-03-30 13:31:07,900 - pylabrobot - IO - [MT Scale] Sent command: I3\n", - "2026-03-30 13:31:07,901 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I3\\r\\n'\n", - "2026-03-30 13:31:07,946 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I3 A \"1.10 18.6.4.1361.772\"\\r\\n'\n", - "2026-03-30 13:31:07,947 - pylabrobot - IO - [MT Scale] Received response: b'I3 A \"1.10 18.6.4.1361.772\"\\r\\n'\n", - "2026-03-30 13:31:07,948 - pylabrobot - INFO - [MT Scale] Connected to Mettler Toledo scale on /dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0\n", + "2026-03-30 13:22:09,329 - pylabrobot.io.serial - INFO - Using explicitly provided port: /dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0 (for VID=1027, PID=24577)\n", + "2026-03-30 13:22:09,336 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] reset_input_buffer\n", + "2026-03-30 13:22:09,337 - pylabrobot - IO - [MT Scale] Sent command: @\n", + "2026-03-30 13:22:09,340 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'@\\r\\n'\n", + "2026-03-30 13:22:09,400 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I4 A \"B207696838\"\\r\\n'\n", + "2026-03-30 13:22:09,402 - pylabrobot - IO - [MT Scale] Received response: b'I4 A \"B207696838\"\\r\\n'\n", + "2026-03-30 13:22:09,405 - pylabrobot - IO - [MT Scale] Sent command: I0\n", + "2026-03-30 13:22:09,406 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I0\\r\\n'\n", + "2026-03-30 13:22:09,445 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I0\"\\r\\n'\n", + "2026-03-30 13:22:09,447 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I0\"\\r\\n'\n", + "2026-03-30 13:22:09,452 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I1\"\\r\\n'\n", + "2026-03-30 13:22:09,453 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I1\"\\r\\n'\n", + "2026-03-30 13:22:09,462 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I2\"\\r\\n'\n", + "2026-03-30 13:22:09,464 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I2\"\\r\\n'\n", + "2026-03-30 13:22:09,478 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I3\"\\r\\n'\n", + "2026-03-30 13:22:09,480 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I3\"\\r\\n'\n", + "2026-03-30 13:22:09,497 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I4\"\\r\\n'\n", + "2026-03-30 13:22:09,499 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I4\"\\r\\n'\n", + "2026-03-30 13:22:09,510 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I5\"\\r\\n'\n", + "2026-03-30 13:22:09,511 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I5\"\\r\\n'\n", + "2026-03-30 13:22:09,526 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"S\"\\r\\n'\n", + "2026-03-30 13:22:09,528 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"S\"\\r\\n'\n", + "2026-03-30 13:22:09,531 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"SI\"\\r\\n'\n", + "2026-03-30 13:22:09,532 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"SI\"\\r\\n'\n", + "2026-03-30 13:22:09,544 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"SIR\"\\r\\n'\n", + "2026-03-30 13:22:09,545 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"SIR\"\\r\\n'\n", + "2026-03-30 13:22:09,560 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"Z\"\\r\\n'\n", + "2026-03-30 13:22:09,562 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"Z\"\\r\\n'\n", + "2026-03-30 13:22:09,574 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"ZI\"\\r\\n'\n", + "2026-03-30 13:22:09,578 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"ZI\"\\r\\n'\n", + "2026-03-30 13:22:09,589 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"@\"\\r\\n'\n", + "2026-03-30 13:22:09,594 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"@\"\\r\\n'\n", + "2026-03-30 13:22:09,609 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"SR\"\\r\\n'\n", + "2026-03-30 13:22:09,611 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"SR\"\\r\\n'\n", + "2026-03-30 13:22:09,614 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"T\"\\r\\n'\n", + "2026-03-30 13:22:09,615 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"T\"\\r\\n'\n", + "2026-03-30 13:22:09,621 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"TA\"\\r\\n'\n", + "2026-03-30 13:22:09,622 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"TA\"\\r\\n'\n", + "2026-03-30 13:22:09,638 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"TAC\"\\r\\n'\n", + "2026-03-30 13:22:09,642 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"TAC\"\\r\\n'\n", + "2026-03-30 13:22:09,653 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"TI\"\\r\\n'\n", + "2026-03-30 13:22:09,654 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"TI\"\\r\\n'\n", + "2026-03-30 13:22:09,673 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C0\"\\r\\n'\n", + "2026-03-30 13:22:09,674 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"C0\"\\r\\n'\n", + "2026-03-30 13:22:09,686 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C1\"\\r\\n'\n", + "2026-03-30 13:22:09,687 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"C1\"\\r\\n'\n", + "2026-03-30 13:22:09,702 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C2\"\\r\\n'\n", + "2026-03-30 13:22:09,709 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"C2\"\\r\\n'\n", + "2026-03-30 13:22:09,713 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C3\"\\r\\n'\n", + "2026-03-30 13:22:09,714 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"C3\"\\r\\n'\n", + "2026-03-30 13:22:09,718 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"COM\"\\r\\n'\n", + "2026-03-30 13:22:09,720 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"COM\"\\r\\n'\n", + "2026-03-30 13:22:09,734 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"DAT\"\\r\\n'\n", + "2026-03-30 13:22:09,735 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"DAT\"\\r\\n'\n", + "2026-03-30 13:22:09,751 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I10\"\\r\\n'\n", + "2026-03-30 13:22:09,753 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I10\"\\r\\n'\n", + "2026-03-30 13:22:09,769 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I11\"\\r\\n'\n", + "2026-03-30 13:22:09,771 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I11\"\\r\\n'\n", + "2026-03-30 13:22:09,782 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I14\"\\r\\n'\n", + "2026-03-30 13:22:09,783 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I14\"\\r\\n'\n", + "2026-03-30 13:22:09,797 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I15\"\\r\\n'\n", + "2026-03-30 13:22:09,798 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I15\"\\r\\n'\n", + "2026-03-30 13:22:09,814 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I16\"\\r\\n'\n", + "2026-03-30 13:22:09,816 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I16\"\\r\\n'\n", + "2026-03-30 13:22:09,830 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I21\"\\r\\n'\n", + "2026-03-30 13:22:09,832 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I21\"\\r\\n'\n", + "2026-03-30 13:22:09,845 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I22\"\\r\\n'\n", + "2026-03-30 13:22:09,846 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I22\"\\r\\n'\n", + "2026-03-30 13:22:09,861 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I23\"\\r\\n'\n", + "2026-03-30 13:22:09,863 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I23\"\\r\\n'\n", + "2026-03-30 13:22:09,867 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I24\"\\r\\n'\n", + "2026-03-30 13:22:09,872 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I24\"\\r\\n'\n", + "2026-03-30 13:22:09,877 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I25\"\\r\\n'\n", + "2026-03-30 13:22:09,878 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I25\"\\r\\n'\n", + "2026-03-30 13:22:09,893 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I26\"\\r\\n'\n", + "2026-03-30 13:22:09,894 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I26\"\\r\\n'\n", + "2026-03-30 13:22:09,909 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M01\"\\r\\n'\n", + "2026-03-30 13:22:09,910 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M01\"\\r\\n'\n", + "2026-03-30 13:22:09,925 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M02\"\\r\\n'\n", + "2026-03-30 13:22:09,926 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M02\"\\r\\n'\n", + "2026-03-30 13:22:09,945 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M03\"\\r\\n'\n", + "2026-03-30 13:22:09,946 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M03\"\\r\\n'\n", + "2026-03-30 13:22:09,957 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M17\"\\r\\n'\n", + "2026-03-30 13:22:09,958 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M17\"\\r\\n'\n", + "2026-03-30 13:22:09,973 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M18\"\\r\\n'\n", + "2026-03-30 13:22:09,975 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M18\"\\r\\n'\n", + "2026-03-30 13:22:09,989 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M19\"\\r\\n'\n", + "2026-03-30 13:22:09,989 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M19\"\\r\\n'\n", + "2026-03-30 13:22:10,006 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M20\"\\r\\n'\n", + "2026-03-30 13:22:10,007 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M20\"\\r\\n'\n", + "2026-03-30 13:22:10,021 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M21\"\\r\\n'\n", + "2026-03-30 13:22:10,021 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M21\"\\r\\n'\n", + "2026-03-30 13:22:10,037 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M27\"\\r\\n'\n", + "2026-03-30 13:22:10,038 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M27\"\\r\\n'\n", + "2026-03-30 13:22:10,041 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M28\"\\r\\n'\n", + "2026-03-30 13:22:10,042 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M28\"\\r\\n'\n", + "2026-03-30 13:22:10,053 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M29\"\\r\\n'\n", + "2026-03-30 13:22:10,054 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M29\"\\r\\n'\n", + "2026-03-30 13:22:10,069 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M31\"\\r\\n'\n", + "2026-03-30 13:22:10,069 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M31\"\\r\\n'\n", + "2026-03-30 13:22:10,085 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M32\"\\r\\n'\n", + "2026-03-30 13:22:10,087 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M32\"\\r\\n'\n", + "2026-03-30 13:22:10,101 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M33\"\\r\\n'\n", + "2026-03-30 13:22:10,101 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M33\"\\r\\n'\n", + "2026-03-30 13:22:10,117 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M35\"\\r\\n'\n", + "2026-03-30 13:22:10,118 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M35\"\\r\\n'\n", + "2026-03-30 13:22:10,134 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"SIS\"\\r\\n'\n", + "2026-03-30 13:22:10,136 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"SIS\"\\r\\n'\n", + "2026-03-30 13:22:10,149 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"SNR\"\\r\\n'\n", + "2026-03-30 13:22:10,154 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"SNR\"\\r\\n'\n", + "2026-03-30 13:22:10,169 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TIM\"\\r\\n'\n", + "2026-03-30 13:22:10,170 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TIM\"\\r\\n'\n", + "2026-03-30 13:22:10,180 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST0\"\\r\\n'\n", + "2026-03-30 13:22:10,182 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TST0\"\\r\\n'\n", + "2026-03-30 13:22:10,197 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST1\"\\r\\n'\n", + "2026-03-30 13:22:10,198 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TST1\"\\r\\n'\n", + "2026-03-30 13:22:10,213 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST2\"\\r\\n'\n", + "2026-03-30 13:22:10,217 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TST2\"\\r\\n'\n", + "2026-03-30 13:22:10,229 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST3\"\\r\\n'\n", + "2026-03-30 13:22:10,230 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TST3\"\\r\\n'\n", + "2026-03-30 13:22:10,245 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"UPD\"\\r\\n'\n", + "2026-03-30 13:22:10,246 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"UPD\"\\r\\n'\n", + "2026-03-30 13:22:10,248 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"FCUT\"\\r\\n'\n", + "2026-03-30 13:22:10,249 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 3 \"FCUT\"\\r\\n'\n", + "2026-03-30 13:22:10,261 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"FSET\"\\r\\n'\n", + "2026-03-30 13:22:10,261 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 3 \"FSET\"\\r\\n'\n", + "2026-03-30 13:22:10,279 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"LST\"\\r\\n'\n", + "2026-03-30 13:22:10,280 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 3 \"LST\"\\r\\n'\n", + "2026-03-30 13:22:10,292 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"RDB\"\\r\\n'\n", + "2026-03-30 13:22:10,293 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 3 \"RDB\"\\r\\n'\n", + "2026-03-30 13:22:10,309 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 A 3 \"USTB\"\\r\\n'\n", + "2026-03-30 13:22:10,311 - pylabrobot - IO - [MT Scale] Received response: b'I0 A 3 \"USTB\"\\r\\n'\n", + "2026-03-30 13:22:10,314 - pylabrobot - IO - [MT Scale] Sent command: I2\n", + "2026-03-30 13:22:10,317 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I2\\r\\n'\n", + "2026-03-30 13:22:10,373 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", + "2026-03-30 13:22:10,374 - pylabrobot - IO - [MT Scale] Received response: b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", + "2026-03-30 13:22:10,385 - pylabrobot - IO - [MT Scale] Sent command: I2\n", + "2026-03-30 13:22:10,387 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I2\\r\\n'\n", + "2026-03-30 13:22:10,453 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", + "2026-03-30 13:22:10,455 - pylabrobot - IO - [MT Scale] Received response: b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", + "2026-03-30 13:22:10,457 - pylabrobot - IO - [MT Scale] Sent command: I3\n", + "2026-03-30 13:22:10,464 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I3\\r\\n'\n", + "2026-03-30 13:22:10,516 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I3 A \"1.10 18.6.4.1361.772\"\\r\\n'\n", + "2026-03-30 13:22:10,518 - pylabrobot - IO - [MT Scale] Received response: b'I3 A \"1.10 18.6.4.1361.772\"\\r\\n'\n", + "2026-03-30 13:22:10,521 - pylabrobot - INFO - [MT Scale] Connected to Mettler Toledo scale on /dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0\n", "Device type: WXS205SDU WXA-Bridge\n", "Configuration: Bridge\n", "Serial number: B207696838\n", "Firmware: 1.10 18.6.4.1361.772\n", "Capacity: 220.0 g\n", "Supported commands: ['@', 'C0', 'C1', 'C2', 'C3', 'COM', 'DAT', 'FCUT', 'FSET', 'I0', 'I1', 'I10', 'I11', 'I14', 'I15', 'I16', 'I2', 'I21', 'I22', 'I23', 'I24', 'I25', 'I26', 'I3', 'I4', 'I5', 'LST', 'M01', 'M02', 'M03', 'M17', 'M18', 'M19', 'M20', 'M21', 'M27', 'M28', 'M29', 'M31', 'M32', 'M33', 'M35', 'RDB', 'S', 'SI', 'SIR', 'SIS', 'SNR', 'SR', 'T', 'TA', 'TAC', 'TI', 'TIM', 'TST0', 'TST1', 'TST2', 'TST3', 'UPD', 'USTB', 'Z', 'ZI']\n", - "2026-03-30 13:31:07,948 - pylabrobot - IO - [MT Scale] Sent command: M21 0 0\n", - "2026-03-30 13:31:07,950 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'M21 0 0\\r\\n'\n", - "2026-03-30 13:31:07,980 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M21 A\\r\\n'\n", - "2026-03-30 13:31:07,983 - pylabrobot - IO - [MT Scale] Received response: b'M21 A\\r\\n'\n" + "2026-03-30 13:22:10,522 - pylabrobot - IO - [MT Scale] Sent command: M21 0 0\n", + "2026-03-30 13:22:10,526 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'M21 0 0\\r\\n'\n", + "2026-03-30 13:22:10,565 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M21 A\\r\\n'\n", + "2026-03-30 13:22:10,566 - pylabrobot - IO - [MT Scale] Received response: b'M21 A\\r\\n'\n" ] } ], @@ -364,132 +364,132 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 13:31:08,036 - pylabrobot - IO - [MT Scale] Sent command: I0\n", - "2026-03-30 13:31:08,041 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I0\\r\\n'\n", - "2026-03-30 13:31:08,078 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I0\"\\r\\n'\n", - "2026-03-30 13:31:08,085 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I0\"\\r\\n'\n", - "2026-03-30 13:31:08,091 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I1\"\\r\\n'\n", - "2026-03-30 13:31:08,097 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I1\"\\r\\n'\n", - "2026-03-30 13:31:08,107 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I2\"\\r\\n'\n", - "2026-03-30 13:31:08,108 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I2\"\\r\\n'\n", - "2026-03-30 13:31:08,110 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I3\"\\r\\n'\n", - "2026-03-30 13:31:08,111 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I3\"\\r\\n'\n", - "2026-03-30 13:31:08,123 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I4\"\\r\\n'\n", - "2026-03-30 13:31:08,124 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I4\"\\r\\n'\n", - "2026-03-30 13:31:08,139 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I5\"\\r\\n'\n", - "2026-03-30 13:31:08,139 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I5\"\\r\\n'\n", - "2026-03-30 13:31:08,155 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"S\"\\r\\n'\n", - "2026-03-30 13:31:08,155 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"S\"\\r\\n'\n", - "2026-03-30 13:31:08,171 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"SI\"\\r\\n'\n", - "2026-03-30 13:31:08,172 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"SI\"\\r\\n'\n", - "2026-03-30 13:31:08,186 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"SIR\"\\r\\n'\n", - "2026-03-30 13:31:08,187 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"SIR\"\\r\\n'\n", - "2026-03-30 13:31:08,188 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"Z\"\\r\\n'\n", - "2026-03-30 13:31:08,189 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"Z\"\\r\\n'\n", - "2026-03-30 13:31:08,203 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"ZI\"\\r\\n'\n", - "2026-03-30 13:31:08,204 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"ZI\"\\r\\n'\n", - "2026-03-30 13:31:08,218 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"@\"\\r\\n'\n", - "2026-03-30 13:31:08,219 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"@\"\\r\\n'\n", - "2026-03-30 13:31:08,235 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"SR\"\\r\\n'\n", - "2026-03-30 13:31:08,235 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"SR\"\\r\\n'\n", - "2026-03-30 13:31:08,251 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"T\"\\r\\n'\n", - "2026-03-30 13:31:08,252 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"T\"\\r\\n'\n", - "2026-03-30 13:31:08,266 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"TA\"\\r\\n'\n", - "2026-03-30 13:31:08,267 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"TA\"\\r\\n'\n", - "2026-03-30 13:31:08,270 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"TAC\"\\r\\n'\n", - "2026-03-30 13:31:08,271 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"TAC\"\\r\\n'\n", - "2026-03-30 13:31:08,283 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"TI\"\\r\\n'\n", - "2026-03-30 13:31:08,284 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"TI\"\\r\\n'\n", - "2026-03-30 13:31:08,298 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C0\"\\r\\n'\n", - "2026-03-30 13:31:08,299 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"C0\"\\r\\n'\n", - "2026-03-30 13:31:08,315 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C1\"\\r\\n'\n", - "2026-03-30 13:31:08,315 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"C1\"\\r\\n'\n", - "2026-03-30 13:31:08,331 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C2\"\\r\\n'\n", - "2026-03-30 13:31:08,332 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"C2\"\\r\\n'\n", - "2026-03-30 13:31:08,346 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C3\"\\r\\n'\n", - "2026-03-30 13:31:08,347 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"C3\"\\r\\n'\n", - "2026-03-30 13:31:08,362 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"COM\"\\r\\n'\n", - "2026-03-30 13:31:08,363 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"COM\"\\r\\n'\n", - "2026-03-30 13:31:08,378 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"DAT\"\\r\\n'\n", - "2026-03-30 13:31:08,379 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"DAT\"\\r\\n'\n", - "2026-03-30 13:31:08,381 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I10\"\\r\\n'\n", - "2026-03-30 13:31:08,382 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I10\"\\r\\n'\n", - "2026-03-30 13:31:08,394 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I11\"\\r\\n'\n", - "2026-03-30 13:31:08,395 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I11\"\\r\\n'\n", - "2026-03-30 13:31:08,412 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I14\"\\r\\n'\n", - "2026-03-30 13:31:08,413 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I14\"\\r\\n'\n", - "2026-03-30 13:31:08,426 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I15\"\\r\\n'\n", - "2026-03-30 13:31:08,427 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I15\"\\r\\n'\n", - "2026-03-30 13:31:08,443 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I16\"\\r\\n'\n", - "2026-03-30 13:31:08,444 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I16\"\\r\\n'\n", - "2026-03-30 13:31:08,458 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I21\"\\r\\n'\n", - "2026-03-30 13:31:08,459 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I21\"\\r\\n'\n", - "2026-03-30 13:31:08,474 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I22\"\\r\\n'\n", - "2026-03-30 13:31:08,475 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I22\"\\r\\n'\n", - "2026-03-30 13:31:08,491 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I23\"\\r\\n'\n", - "2026-03-30 13:31:08,491 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I23\"\\r\\n'\n", - "2026-03-30 13:31:08,506 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I24\"\\r\\n'\n", - "2026-03-30 13:31:08,507 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I24\"\\r\\n'\n", - "2026-03-30 13:31:08,522 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I25\"\\r\\n'\n", - "2026-03-30 13:31:08,523 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I25\"\\r\\n'\n", - "2026-03-30 13:31:08,538 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I26\"\\r\\n'\n", - "2026-03-30 13:31:08,538 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I26\"\\r\\n'\n", - "2026-03-30 13:31:08,540 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M01\"\\r\\n'\n", - "2026-03-30 13:31:08,540 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M01\"\\r\\n'\n", - "2026-03-30 13:31:08,554 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M02\"\\r\\n'\n", - "2026-03-30 13:31:08,555 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M02\"\\r\\n'\n", - "2026-03-30 13:31:08,570 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M03\"\\r\\n'\n", - "2026-03-30 13:31:08,571 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M03\"\\r\\n'\n", - "2026-03-30 13:31:08,586 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M17\"\\r\\n'\n", - "2026-03-30 13:31:08,587 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M17\"\\r\\n'\n", - "2026-03-30 13:31:08,602 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M18\"\\r\\n'\n", - "2026-03-30 13:31:08,603 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M18\"\\r\\n'\n", - "2026-03-30 13:31:08,619 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M19\"\\r\\n'\n", - "2026-03-30 13:31:08,619 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M19\"\\r\\n'\n", - "2026-03-30 13:31:08,634 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M20\"\\r\\n'\n", - "2026-03-30 13:31:08,635 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M20\"\\r\\n'\n", - "2026-03-30 13:31:08,650 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M21\"\\r\\n'\n", - "2026-03-30 13:31:08,651 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M21\"\\r\\n'\n", - "2026-03-30 13:31:08,666 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M27\"\\r\\n'\n", - "2026-03-30 13:31:08,666 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M27\"\\r\\n'\n", - "2026-03-30 13:31:08,682 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M28\"\\r\\n'\n", - "2026-03-30 13:31:08,683 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M28\"\\r\\n'\n", - "2026-03-30 13:31:08,698 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M29\"\\r\\n'\n", - "2026-03-30 13:31:08,699 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M29\"\\r\\n'\n", - "2026-03-30 13:31:08,700 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M31\"\\r\\n'\n", - "2026-03-30 13:31:08,701 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M31\"\\r\\n'\n", - "2026-03-30 13:31:08,717 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M32\"\\r\\n'\n", - "2026-03-30 13:31:08,718 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M32\"\\r\\n'\n", - "2026-03-30 13:31:08,730 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M33\"\\r\\n'\n", - "2026-03-30 13:31:08,731 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M33\"\\r\\n'\n", - "2026-03-30 13:31:08,747 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M35\"\\r\\n'\n", - "2026-03-30 13:31:08,747 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M35\"\\r\\n'\n", - "2026-03-30 13:31:08,762 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"SIS\"\\r\\n'\n", - "2026-03-30 13:31:08,763 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"SIS\"\\r\\n'\n", - "2026-03-30 13:31:08,779 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"SNR\"\\r\\n'\n", - "2026-03-30 13:31:08,780 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"SNR\"\\r\\n'\n", - "2026-03-30 13:31:08,794 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TIM\"\\r\\n'\n", - "2026-03-30 13:31:08,795 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TIM\"\\r\\n'\n", - "2026-03-30 13:31:08,810 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST0\"\\r\\n'\n", - "2026-03-30 13:31:08,812 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TST0\"\\r\\n'\n", - "2026-03-30 13:31:08,825 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST1\"\\r\\n'\n", - "2026-03-30 13:31:08,827 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TST1\"\\r\\n'\n", - "2026-03-30 13:31:08,842 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST2\"\\r\\n'\n", - "2026-03-30 13:31:08,843 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TST2\"\\r\\n'\n", - "2026-03-30 13:31:08,858 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST3\"\\r\\n'\n", - "2026-03-30 13:31:08,859 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TST3\"\\r\\n'\n", - "2026-03-30 13:31:08,873 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"UPD\"\\r\\n'\n", - "2026-03-30 13:31:08,875 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"UPD\"\\r\\n'\n", - "2026-03-30 13:31:08,890 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"FCUT\"\\r\\n'\n", - "2026-03-30 13:31:08,891 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 3 \"FCUT\"\\r\\n'\n", - "2026-03-30 13:31:08,906 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"FSET\"\\r\\n'\n", - "2026-03-30 13:31:08,907 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 3 \"FSET\"\\r\\n'\n", - "2026-03-30 13:31:08,922 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"LST\"\\r\\n'\n", - "2026-03-30 13:31:08,922 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 3 \"LST\"\\r\\n'\n", - "2026-03-30 13:31:08,938 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"RDB\"\\r\\n'\n", - "2026-03-30 13:31:08,939 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 3 \"RDB\"\\r\\n'\n", - "2026-03-30 13:31:08,953 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 A 3 \"USTB\"\\r\\n'\n", - "2026-03-30 13:31:08,954 - pylabrobot - IO - [MT Scale] Received response: b'I0 A 3 \"USTB\"\\r\\n'\n" + "2026-03-30 13:22:10,635 - pylabrobot - IO - [MT Scale] Sent command: I0\n", + "2026-03-30 13:22:10,637 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I0\\r\\n'\n", + "2026-03-30 13:22:10,663 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I0\"\\r\\n'\n", + "2026-03-30 13:22:10,667 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I0\"\\r\\n'\n", + "2026-03-30 13:22:10,678 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I1\"\\r\\n'\n", + "2026-03-30 13:22:10,681 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I1\"\\r\\n'\n", + "2026-03-30 13:22:10,693 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I2\"\\r\\n'\n", + "2026-03-30 13:22:10,695 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I2\"\\r\\n'\n", + "2026-03-30 13:22:10,708 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I3\"\\r\\n'\n", + "2026-03-30 13:22:10,714 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I3\"\\r\\n'\n", + "2026-03-30 13:22:10,725 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I4\"\\r\\n'\n", + "2026-03-30 13:22:10,728 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I4\"\\r\\n'\n", + "2026-03-30 13:22:10,740 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I5\"\\r\\n'\n", + "2026-03-30 13:22:10,742 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I5\"\\r\\n'\n", + "2026-03-30 13:22:10,746 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"S\"\\r\\n'\n", + "2026-03-30 13:22:10,751 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"S\"\\r\\n'\n", + "2026-03-30 13:22:10,757 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"SI\"\\r\\n'\n", + "2026-03-30 13:22:10,758 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"SI\"\\r\\n'\n", + "2026-03-30 13:22:10,772 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"SIR\"\\r\\n'\n", + "2026-03-30 13:22:10,773 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"SIR\"\\r\\n'\n", + "2026-03-30 13:22:10,788 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"Z\"\\r\\n'\n", + "2026-03-30 13:22:10,789 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"Z\"\\r\\n'\n", + "2026-03-30 13:22:10,805 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"ZI\"\\r\\n'\n", + "2026-03-30 13:22:10,805 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"ZI\"\\r\\n'\n", + "2026-03-30 13:22:10,820 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"@\"\\r\\n'\n", + "2026-03-30 13:22:10,821 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"@\"\\r\\n'\n", + "2026-03-30 13:22:10,822 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"SR\"\\r\\n'\n", + "2026-03-30 13:22:10,822 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"SR\"\\r\\n'\n", + "2026-03-30 13:22:10,836 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"T\"\\r\\n'\n", + "2026-03-30 13:22:10,837 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"T\"\\r\\n'\n", + "2026-03-30 13:22:10,853 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"TA\"\\r\\n'\n", + "2026-03-30 13:22:10,853 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"TA\"\\r\\n'\n", + "2026-03-30 13:22:10,868 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"TAC\"\\r\\n'\n", + "2026-03-30 13:22:10,870 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"TAC\"\\r\\n'\n", + "2026-03-30 13:22:10,885 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"TI\"\\r\\n'\n", + "2026-03-30 13:22:10,886 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"TI\"\\r\\n'\n", + "2026-03-30 13:22:10,900 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C0\"\\r\\n'\n", + "2026-03-30 13:22:10,900 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"C0\"\\r\\n'\n", + "2026-03-30 13:22:10,916 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C1\"\\r\\n'\n", + "2026-03-30 13:22:10,917 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"C1\"\\r\\n'\n", + "2026-03-30 13:22:10,919 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C2\"\\r\\n'\n", + "2026-03-30 13:22:10,921 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"C2\"\\r\\n'\n", + "2026-03-30 13:22:10,932 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C3\"\\r\\n'\n", + "2026-03-30 13:22:10,933 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"C3\"\\r\\n'\n", + "2026-03-30 13:22:10,948 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"COM\"\\r\\n'\n", + "2026-03-30 13:22:10,949 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"COM\"\\r\\n'\n", + "2026-03-30 13:22:10,964 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"DAT\"\\r\\n'\n", + "2026-03-30 13:22:10,966 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"DAT\"\\r\\n'\n", + "2026-03-30 13:22:10,982 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I10\"\\r\\n'\n", + "2026-03-30 13:22:10,983 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I10\"\\r\\n'\n", + "2026-03-30 13:22:10,996 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I11\"\\r\\n'\n", + "2026-03-30 13:22:10,998 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I11\"\\r\\n'\n", + "2026-03-30 13:22:11,013 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I14\"\\r\\n'\n", + "2026-03-30 13:22:11,015 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I14\"\\r\\n'\n", + "2026-03-30 13:22:11,030 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I15\"\\r\\n'\n", + "2026-03-30 13:22:11,033 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I15\"\\r\\n'\n", + "2026-03-30 13:22:11,045 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I16\"\\r\\n'\n", + "2026-03-30 13:22:11,048 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I16\"\\r\\n'\n", + "2026-03-30 13:22:11,061 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I21\"\\r\\n'\n", + "2026-03-30 13:22:11,065 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I21\"\\r\\n'\n", + "2026-03-30 13:22:11,068 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I22\"\\r\\n'\n", + "2026-03-30 13:22:11,070 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I22\"\\r\\n'\n", + "2026-03-30 13:22:11,077 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I23\"\\r\\n'\n", + "2026-03-30 13:22:11,079 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I23\"\\r\\n'\n", + "2026-03-30 13:22:11,093 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I24\"\\r\\n'\n", + "2026-03-30 13:22:11,097 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I24\"\\r\\n'\n", + "2026-03-30 13:22:11,109 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I25\"\\r\\n'\n", + "2026-03-30 13:22:11,110 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I25\"\\r\\n'\n", + "2026-03-30 13:22:11,125 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I26\"\\r\\n'\n", + "2026-03-30 13:22:11,133 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I26\"\\r\\n'\n", + "2026-03-30 13:22:11,142 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M01\"\\r\\n'\n", + "2026-03-30 13:22:11,143 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M01\"\\r\\n'\n", + "2026-03-30 13:22:11,156 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M02\"\\r\\n'\n", + "2026-03-30 13:22:11,159 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M02\"\\r\\n'\n", + "2026-03-30 13:22:11,173 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M03\"\\r\\n'\n", + "2026-03-30 13:22:11,179 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M03\"\\r\\n'\n", + "2026-03-30 13:22:11,189 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M17\"\\r\\n'\n", + "2026-03-30 13:22:11,192 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M17\"\\r\\n'\n", + "2026-03-30 13:22:11,205 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M18\"\\r\\n'\n", + "2026-03-30 13:22:11,206 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M18\"\\r\\n'\n", + "2026-03-30 13:22:11,220 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M19\"\\r\\n'\n", + "2026-03-30 13:22:11,221 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M19\"\\r\\n'\n", + "2026-03-30 13:22:11,237 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M20\"\\r\\n'\n", + "2026-03-30 13:22:11,238 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M20\"\\r\\n'\n", + "2026-03-30 13:22:11,241 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M21\"\\r\\n'\n", + "2026-03-30 13:22:11,243 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M21\"\\r\\n'\n", + "2026-03-30 13:22:11,252 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M27\"\\r\\n'\n", + "2026-03-30 13:22:11,257 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M27\"\\r\\n'\n", + "2026-03-30 13:22:11,268 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M28\"\\r\\n'\n", + "2026-03-30 13:22:11,269 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M28\"\\r\\n'\n", + "2026-03-30 13:22:11,284 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M29\"\\r\\n'\n", + "2026-03-30 13:22:11,286 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M29\"\\r\\n'\n", + "2026-03-30 13:22:11,300 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M31\"\\r\\n'\n", + "2026-03-30 13:22:11,300 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M31\"\\r\\n'\n", + "2026-03-30 13:22:11,316 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M32\"\\r\\n'\n", + "2026-03-30 13:22:11,317 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M32\"\\r\\n'\n", + "2026-03-30 13:22:11,332 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M33\"\\r\\n'\n", + "2026-03-30 13:22:11,333 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M33\"\\r\\n'\n", + "2026-03-30 13:22:11,347 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M35\"\\r\\n'\n", + "2026-03-30 13:22:11,348 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M35\"\\r\\n'\n", + "2026-03-30 13:22:11,364 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"SIS\"\\r\\n'\n", + "2026-03-30 13:22:11,364 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"SIS\"\\r\\n'\n", + "2026-03-30 13:22:11,380 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"SNR\"\\r\\n'\n", + "2026-03-30 13:22:11,381 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"SNR\"\\r\\n'\n", + "2026-03-30 13:22:11,396 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TIM\"\\r\\n'\n", + "2026-03-30 13:22:11,396 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TIM\"\\r\\n'\n", + "2026-03-30 13:22:11,412 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST0\"\\r\\n'\n", + "2026-03-30 13:22:11,413 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TST0\"\\r\\n'\n", + "2026-03-30 13:22:11,428 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST1\"\\r\\n'\n", + "2026-03-30 13:22:11,429 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TST1\"\\r\\n'\n", + "2026-03-30 13:22:11,431 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST2\"\\r\\n'\n", + "2026-03-30 13:22:11,432 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TST2\"\\r\\n'\n", + "2026-03-30 13:22:11,444 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST3\"\\r\\n'\n", + "2026-03-30 13:22:11,445 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TST3\"\\r\\n'\n", + "2026-03-30 13:22:11,460 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"UPD\"\\r\\n'\n", + "2026-03-30 13:22:11,463 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"UPD\"\\r\\n'\n", + "2026-03-30 13:22:11,476 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"FCUT\"\\r\\n'\n", + "2026-03-30 13:22:11,477 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 3 \"FCUT\"\\r\\n'\n", + "2026-03-30 13:22:11,492 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"FSET\"\\r\\n'\n", + "2026-03-30 13:22:11,493 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 3 \"FSET\"\\r\\n'\n", + "2026-03-30 13:22:11,508 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"LST\"\\r\\n'\n", + "2026-03-30 13:22:11,509 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 3 \"LST\"\\r\\n'\n", + "2026-03-30 13:22:11,524 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"RDB\"\\r\\n'\n", + "2026-03-30 13:22:11,525 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 3 \"RDB\"\\r\\n'\n", + "2026-03-30 13:22:11,540 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 A 3 \"USTB\"\\r\\n'\n", + "2026-03-30 13:22:11,541 - pylabrobot - IO - [MT Scale] Received response: b'I0 A 3 \"USTB\"\\r\\n'\n" ] }, { @@ -605,24 +605,20 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 13:31:08,965 - pylabrobot - IO - [MT Scale] Sent command: I3\n", - "2026-03-30 13:31:08,967 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I3\\r\\n'\n", - "2026-03-30 13:31:09,018 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I3 A \"1.10 18.6.4.1361.772\"\\r\\n'\n", - "2026-03-30 13:31:09,021 - pylabrobot - IO - [MT Scale] Received response: b'I3 A \"1.10 18.6.4.1361.772\"\\r\\n'\n", - "2026-03-30 13:31:09,023 - pylabrobot - IO - [MT Scale] Sent command: I5\n", - "2026-03-30 13:31:09,025 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I5\\r\\n'\n", - "2026-03-30 13:31:09,066 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I5 A \"11671158C\"\\r\\n'\n", - "2026-03-30 13:31:09,066 - pylabrobot - IO - [MT Scale] Received response: b'I5 A \"11671158C\"\\r\\n'\n", - "2026-03-30 13:31:09,067 - pylabrobot - IO - [MT Scale] Sent command: I10\n", - "2026-03-30 13:31:09,069 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I10\\r\\n'\n", - "2026-03-30 13:31:09,097 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I10 A \"\"\\r\\n'\n", - "2026-03-30 13:31:09,098 - pylabrobot - IO - [MT Scale] Received response: b'I10 A \"\"\\r\\n'\n", - "2026-03-30 13:31:09,099 - pylabrobot - IO - [MT Scale] Sent command: I11\n", - "2026-03-30 13:31:09,101 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I11\\r\\n'\n", - "2026-03-30 13:31:09,145 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I11 A \"WXS205SDU\"\\r\\n'\n", - "2026-03-30 13:31:09,146 - pylabrobot - IO - [MT Scale] Received response: b'I11 A \"WXS205SDU\"\\r\\n'\n", - "2026-03-30 13:31:09,147 - pylabrobot - IO - [MT Scale] Sent command: I15\n", - "2026-03-30 13:31:09,149 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I15\\r\\n'\n" + "2026-03-30 13:22:11,575 - pylabrobot - IO - [MT Scale] Sent command: I3\n", + "2026-03-30 13:22:11,583 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I3\\r\\n'\n", + "2026-03-30 13:22:11,637 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I3 A \"1.10 18.6.4.1361.772\"\\r\\n'\n", + "2026-03-30 13:22:11,642 - pylabrobot - IO - [MT Scale] Received response: b'I3 A \"1.10 18.6.4.1361.772\"\\r\\n'\n", + "2026-03-30 13:22:11,643 - pylabrobot - IO - [MT Scale] Sent command: I5\n", + "2026-03-30 13:22:11,648 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I5\\r\\n'\n", + "2026-03-30 13:22:11,684 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I5 A \"11671158C\"\\r\\n'\n", + "2026-03-30 13:22:11,684 - pylabrobot - IO - [MT Scale] Received response: b'I5 A \"11671158C\"\\r\\n'\n", + "2026-03-30 13:22:11,687 - pylabrobot - IO - [MT Scale] Sent command: I10\n", + "2026-03-30 13:22:11,688 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I10\\r\\n'\n", + "2026-03-30 13:22:11,716 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I10 A \"\"\\r\\n'\n", + "2026-03-30 13:22:11,718 - pylabrobot - IO - [MT Scale] Received response: b'I10 A \"\"\\r\\n'\n", + "2026-03-30 13:22:11,720 - pylabrobot - IO - [MT Scale] Sent command: I11\n", + "2026-03-30 13:22:11,726 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I11\\r\\n'\n" ] }, { @@ -631,47 +627,47 @@ "text": [ "Software version: 1.10 18.6.4.1361.772\n", "Software material number: 11671158C\n", - "Device ID: ''\n", - "Model designation: WXS205SDU\n" + "Device ID: ''\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 13:31:09,178 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I15 A 243\\r\\n'\n", - "2026-03-30 13:31:09,179 - pylabrobot - IO - [MT Scale] Received response: b'I15 A 243\\r\\n'\n", - "2026-03-30 13:31:09,180 - pylabrobot - IO - [MT Scale] Sent command: DAT\n", - "2026-03-30 13:31:09,182 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'DAT\\r\\n'\n" + "2026-03-30 13:22:11,764 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I11 A \"WXS205SDU\"\\r\\n'\n", + "2026-03-30 13:22:11,764 - pylabrobot - IO - [MT Scale] Received response: b'I11 A \"WXS205SDU\"\\r\\n'\n", + "2026-03-30 13:22:11,765 - pylabrobot - IO - [MT Scale] Sent command: I15\n", + "2026-03-30 13:22:11,767 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I15\\r\\n'\n", + "2026-03-30 13:22:11,796 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I15 A 234\\r\\n'\n", + "2026-03-30 13:22:11,797 - pylabrobot - IO - [MT Scale] Received response: b'I15 A 234\\r\\n'\n", + "2026-03-30 13:22:11,800 - pylabrobot - IO - [MT Scale] Sent command: DAT\n", + "2026-03-30 13:22:11,803 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'DAT\\r\\n'\n", + "2026-03-30 13:22:11,843 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'DAT A 04 01 2000\\r\\n'\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ - "Uptime: 243d 0h 0m 0s\n" + "Model designation: WXS205SDU\n", + "Uptime: 234d 0h 0m 0s\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 13:31:09,225 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'DAT A 04 01 2000\\r\\n'\n", - "2026-03-30 13:31:09,226 - pylabrobot - IO - [MT Scale] Received response: b'DAT A 04 01 2000\\r\\n'\n", - "2026-03-30 13:31:09,228 - pylabrobot - IO - [MT Scale] Sent command: TIM\n", - "2026-03-30 13:31:09,230 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'TIM\\r\\n'\n", - "2026-03-30 13:31:09,273 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'TIM A 20 36 35\\r\\n'\n", - "2026-03-30 13:31:09,274 - pylabrobot - IO - [MT Scale] Received response: b'TIM A 20 36 35\\r\\n'\n", - "2026-03-30 13:31:09,275 - pylabrobot - IO - [MT Scale] Sent command: I14 0\n", - "2026-03-30 13:31:09,278 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I14 0\\r\\n'\n", - "2026-03-30 13:31:09,321 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I14 A 0 1 \"Bridge\"\\r\\n'\n", - "2026-03-30 13:31:09,322 - pylabrobot - IO - [MT Scale] Received response: b'I14 A 0 1 \"Bridge\"\\r\\n'\n", - "2026-03-30 13:31:09,323 - pylabrobot - IO - [MT Scale] Sent command: I14 1\n", - "2026-03-30 13:31:09,325 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I14 1\\r\\n'\n", - "2026-03-30 13:31:09,369 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I14 A 1 1 \"WXS205SDU\"\\r\\n'\n", - "2026-03-30 13:31:09,370 - pylabrobot - IO - [MT Scale] Received response: b'I14 A 1 1 \"WXS205SDU\"\\r\\n'\n", - "2026-03-30 13:31:09,371 - pylabrobot - IO - [MT Scale] Sent command: I14 2\n", - "2026-03-30 13:31:09,372 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I14 2\\r\\n'\n" + "2026-03-30 13:22:11,844 - pylabrobot - IO - [MT Scale] Received response: b'DAT A 04 01 2000\\r\\n'\n", + "2026-03-30 13:22:11,846 - pylabrobot - IO - [MT Scale] Sent command: TIM\n", + "2026-03-30 13:22:11,847 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'TIM\\r\\n'\n", + "2026-03-30 13:22:11,876 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'TIM A 20 27 38\\r\\n'\n", + "2026-03-30 13:22:11,876 - pylabrobot - IO - [MT Scale] Received response: b'TIM A 20 27 38\\r\\n'\n", + "2026-03-30 13:22:11,877 - pylabrobot - IO - [MT Scale] Sent command: I14 0\n", + "2026-03-30 13:22:11,879 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I14 0\\r\\n'\n", + "2026-03-30 13:22:11,924 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I14 A 0 1 \"Bridge\"\\r\\n'\n", + "2026-03-30 13:22:11,924 - pylabrobot - IO - [MT Scale] Received response: b'I14 A 0 1 \"Bridge\"\\r\\n'\n", + "2026-03-30 13:22:11,925 - pylabrobot - IO - [MT Scale] Sent command: I14 1\n", + "2026-03-30 13:22:11,926 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I14 1\\r\\n'\n" ] }, { @@ -683,25 +679,29 @@ "\n", "Device info (I14):\n", " Category 0 (Instrument configuration):\n", - " I14 A 0 1 Bridge\n", - " Category 1 (Instrument descriptions):\n", - " I14 A 1 1 WXS205SDU\n" + " I14 A 0 1 Bridge\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 13:31:09,417 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I14 A 2 1 \"11671158C\"\\r\\n'\n", - "2026-03-30 13:31:09,418 - pylabrobot - IO - [MT Scale] Received response: b'I14 A 2 1 \"11671158C\"\\r\\n'\n", - "2026-03-30 13:31:09,419 - pylabrobot - IO - [MT Scale] Sent command: I14 3\n", - "2026-03-30 13:31:09,420 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I14 3\\r\\n'\n" + "2026-03-30 13:22:11,972 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I14 A 1 1 \"WXS205SDU\"\\r\\n'\n", + "2026-03-30 13:22:11,972 - pylabrobot - IO - [MT Scale] Received response: b'I14 A 1 1 \"WXS205SDU\"\\r\\n'\n", + "2026-03-30 13:22:11,973 - pylabrobot - IO - [MT Scale] Sent command: I14 2\n", + "2026-03-30 13:22:11,974 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I14 2\\r\\n'\n", + "2026-03-30 13:22:12,020 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I14 A 2 1 \"11671158C\"\\r\\n'\n", + "2026-03-30 13:22:12,020 - pylabrobot - IO - [MT Scale] Received response: b'I14 A 2 1 \"11671158C\"\\r\\n'\n", + "2026-03-30 13:22:12,021 - pylabrobot - IO - [MT Scale] Sent command: I14 3\n", + "2026-03-30 13:22:12,022 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I14 3\\r\\n'\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ + " Category 1 (Instrument descriptions):\n", + " I14 A 1 1 WXS205SDU\n", " Category 2 (SW identification numbers):\n", " I14 A 2 1 11671158C\n" ] @@ -710,16 +710,16 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 13:31:09,465 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I14 A 3 1 \"1.10\"\\r\\n'\n", - "2026-03-30 13:31:09,466 - pylabrobot - IO - [MT Scale] Received response: b'I14 A 3 1 \"1.10\"\\r\\n'\n", - "2026-03-30 13:31:09,467 - pylabrobot - IO - [MT Scale] Sent command: I14 4\n", - "2026-03-30 13:31:09,468 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I14 4\\r\\n'\n", - "2026-03-30 13:31:09,513 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I14 A 4 1 \"B207696838\"\\r\\n'\n", - "2026-03-30 13:31:09,514 - pylabrobot - IO - [MT Scale] Received response: b'I14 A 4 1 \"B207696838\"\\r\\n'\n", - "2026-03-30 13:31:09,515 - pylabrobot - IO - [MT Scale] Sent command: I14 5\n", - "2026-03-30 13:31:09,516 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I14 5\\r\\n'\n", - "2026-03-30 13:31:09,561 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I14 A 5 1 \"18.6.4.1361.772\"\\r\\n'\n", - "2026-03-30 13:31:09,562 - pylabrobot - IO - [MT Scale] Received response: b'I14 A 5 1 \"18.6.4.1361.772\"\\r\\n'\n" + "2026-03-30 13:22:12,068 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I14 A 3 1 \"1.10\"\\r\\n'\n", + "2026-03-30 13:22:12,068 - pylabrobot - IO - [MT Scale] Received response: b'I14 A 3 1 \"1.10\"\\r\\n'\n", + "2026-03-30 13:22:12,069 - pylabrobot - IO - [MT Scale] Sent command: I14 4\n", + "2026-03-30 13:22:12,071 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I14 4\\r\\n'\n", + "2026-03-30 13:22:12,116 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I14 A 4 1 \"B207696838\"\\r\\n'\n", + "2026-03-30 13:22:12,116 - pylabrobot - IO - [MT Scale] Received response: b'I14 A 4 1 \"B207696838\"\\r\\n'\n", + "2026-03-30 13:22:12,117 - pylabrobot - IO - [MT Scale] Sent command: I14 5\n", + "2026-03-30 13:22:12,118 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I14 5\\r\\n'\n", + "2026-03-30 13:22:12,166 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I14 A 5 1 \"18.6.4.1361.772\"\\r\\n'\n", + "2026-03-30 13:22:12,172 - pylabrobot - IO - [MT Scale] Received response: b'I14 A 5 1 \"18.6.4.1361.772\"\\r\\n'\n" ] }, { @@ -738,72 +738,7 @@ } ], "source": [ - "# I3 - Software version (Level 0, always available)\n", - "sw_version = await backend.request_software_version()\n", - "print(f\"Software version: {sw_version}\")\n", - "\n", - "# I5 - Software material number (Level 0, always available)\n", - "sw_material = await backend.request_software_material_number()\n", - "print(f\"Software material number: {sw_material}\")\n", - "\n", - "# I10 - Device ID (user-assignable name)\n", - "if \"I10\" in backend._supported_commands:\n", - " device_id = await backend.request_device_id()\n", - " print(f\"Device ID: '{device_id}'\")\n", - "else:\n", - " print(\"SKIP: I10 not supported\")\n", - "\n", - "# I11 - Model designation\n", - "if \"I11\" in backend._supported_commands:\n", - " model = await backend.request_model_designation()\n", - " print(f\"Model designation: {model}\")\n", - "else:\n", - " print(\"SKIP: I11 not supported\")\n", - "\n", - "# I15 - Uptime\n", - "if \"I15\" in backend._supported_commands:\n", - " uptime = await backend.request_uptime()\n", - " print(f\"Uptime: {uptime['days']}d {uptime['hours']}h {uptime['minutes']}m {uptime['seconds']}s\")\n", - "else:\n", - " print(\"SKIP: I15 not supported\")\n", - "\n", - "# DAT - Date\n", - "if \"DAT\" in backend._supported_commands:\n", - " date = await backend.request_date()\n", - " print(f\"Device date: {date}\")\n", - "else:\n", - " print(\"SKIP: DAT not supported\")\n", - "\n", - "# TIM - Time\n", - "if \"TIM\" in backend._supported_commands:\n", - " time_str = await backend.request_time()\n", - " print(f\"Device time: {time_str}\")\n", - "else:\n", - " print(\"SKIP: TIM not supported\")\n", - "\n", - "# I14 - Comprehensive device info (query each category separately)\n", - "if \"I14\" in backend._supported_commands:\n", - " category_names = {\n", - " 0: \"Instrument configuration\",\n", - " 1: \"Instrument descriptions\",\n", - " 2: \"SW identification numbers\",\n", - " 3: \"SW versions\",\n", - " 4: \"Serial numbers\",\n", - " 5: \"TDNR numbers\",\n", - " }\n", - " print(\"\\nDevice info (I14):\")\n", - " for cat, name in category_names.items():\n", - " try:\n", - " info = await backend.request_device_info(category=cat)\n", - " print(f\" Category {cat} ({name}):\")\n", - " for resp in info:\n", - " print(f\" {resp.command} {resp.status} {' '.join(resp.data)}\")\n", - " except Exception as e:\n", - " print(f\" Category {cat} ({name}): {e}\")\n", - "else:\n", - " print(\"SKIP: I14 not supported\")\n", - "\n", - "print(\"\\nPASS: Batch 1 device identity commands completed\")" + "# I3 - Software version (Level 0, always available)\nsw_version = await backend.request_firmware_version()\nprint(f\"Software version: {sw_version}\")\n\n# I5 - Software material number (Level 0, always available)\nsw_material = await backend.request_software_material_number()\nprint(f\"Software material number: {sw_material}\")\n\n# I10 - Device ID (user-assignable name)\nif \"I10\" in backend._supported_commands:\n device_id = await backend.request_device_id()\n print(f\"Device ID: '{device_id}'\")\nelse:\n print(\"SKIP: I10 not supported\")\n\n# I11 - Model designation\nif \"I11\" in backend._supported_commands:\n model = await backend.request_model_designation()\n print(f\"Model designation: {model}\")\nelse:\n print(\"SKIP: I11 not supported\")\n\n# I15 - Uptime\nif \"I15\" in backend._supported_commands:\n uptime = await backend.request_uptime()\n print(f\"Uptime: {uptime['days']}d {uptime['hours']}h {uptime['minutes']}m {uptime['seconds']}s\")\nelse:\n print(\"SKIP: I15 not supported\")\n\n# DAT - Date\nif \"DAT\" in backend._supported_commands:\n date = await backend.request_date()\n print(f\"Device date: {date}\")\nelse:\n print(\"SKIP: DAT not supported\")\n\n# TIM - Time\nif \"TIM\" in backend._supported_commands:\n time_str = await backend.request_time()\n print(f\"Device time: {time_str}\")\nelse:\n print(\"SKIP: TIM not supported\")\n\n# I14 - Comprehensive device info (query each category separately)\nif \"I14\" in backend._supported_commands:\n category_names = {\n 0: \"Instrument configuration\",\n 1: \"Instrument descriptions\",\n 2: \"SW identification numbers\",\n 3: \"SW versions\",\n 4: \"Serial numbers\",\n 5: \"TDNR numbers\",\n }\n print(\"\\nDevice info (I14):\")\n for cat, name in category_names.items():\n try:\n info = await backend.request_device_info(category=cat)\n print(f\" Category {cat} ({name}):\")\n for resp in info:\n print(f\" {resp.command} {resp.status} {' '.join(resp.data)}\")\n except Exception as e:\n print(f\" Category {cat} ({name}): {e}\")\nelse:\n print(\"SKIP: I14 not supported\")\n\nprint(\"\\nPASS: Batch 1 device identity commands completed\")" ] }, { @@ -826,59 +761,59 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 13:31:09,573 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] reset_input_buffer\n", - "2026-03-30 13:31:09,575 - pylabrobot - IO - [MT Scale] Sent command: @\n", - "2026-03-30 13:31:09,577 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'@\\r\\n'\n", - "2026-03-30 13:31:09,641 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I4 A \"B207696838\"\\r\\n'\n", - "2026-03-30 13:31:09,642 - pylabrobot - IO - [MT Scale] Received response: b'I4 A \"B207696838\"\\r\\n'\n", - "2026-03-30 13:31:09,643 - pylabrobot - IO - [MT Scale] Sent command: I4\n", - "2026-03-30 13:31:09,645 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I4\\r\\n'\n", - "2026-03-30 13:31:09,689 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I4 A \"B207696838\"\\r\\n'\n", - "2026-03-30 13:31:09,690 - pylabrobot - IO - [MT Scale] Received response: b'I4 A \"B207696838\"\\r\\n'\n", - "2026-03-30 13:31:09,691 - pylabrobot - IO - [MT Scale] Sent command: I2\n", - "2026-03-30 13:31:09,693 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I2\\r\\n'\n", - "2026-03-30 13:31:09,753 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", - "2026-03-30 13:31:09,753 - pylabrobot - IO - [MT Scale] Received response: b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", - "2026-03-30 13:31:09,754 - pylabrobot - IO - [MT Scale] Sent command: I2\n", - "2026-03-30 13:31:09,756 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I2\\r\\n'\n", - "2026-03-30 13:31:09,817 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", - "2026-03-30 13:31:09,818 - pylabrobot - IO - [MT Scale] Received response: b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", - "2026-03-30 13:31:09,820 - pylabrobot - IO - [MT Scale] Sent command: S\n", - "2026-03-30 13:31:09,821 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", - "2026-03-30 13:31:10,136 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S -0.00005 g\\r\\n'\n", - "2026-03-30 13:31:10,137 - pylabrobot - IO - [MT Scale] Received response: b'S S -0.00005 g\\r\\n'\n", - "2026-03-30 13:31:10,138 - pylabrobot - IO - [MT Scale] Sent command: SI\n", - "2026-03-30 13:31:10,139 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", - "2026-03-30 13:31:10,168 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S -0.00005 g\\r\\n'\n", - "2026-03-30 13:31:10,169 - pylabrobot - IO - [MT Scale] Received response: b'S S -0.00005 g\\r\\n'\n", - "2026-03-30 13:31:10,170 - pylabrobot - IO - [MT Scale] Sent command: Z\n", - "2026-03-30 13:31:10,171 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'Z\\r\\n'\n", - "2026-03-30 13:31:10,408 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'Z A\\r\\n'\n", - "2026-03-30 13:31:10,409 - pylabrobot - IO - [MT Scale] Received response: b'Z A\\r\\n'\n", - "2026-03-30 13:31:10,411 - pylabrobot - IO - [MT Scale] Sent command: SI\n", - "2026-03-30 13:31:10,414 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", - "2026-03-30 13:31:10,456 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 13:31:10,457 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 13:31:10,458 - pylabrobot - IO - [MT Scale] Sent command: ZI\n", - "2026-03-30 13:31:10,461 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'ZI\\r\\n'\n", - "2026-03-30 13:31:10,488 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'ZI S\\r\\n'\n", - "2026-03-30 13:31:10,489 - pylabrobot - IO - [MT Scale] Received response: b'ZI S\\r\\n'\n", - "2026-03-30 13:31:10,489 - pylabrobot - IO - [MT Scale] Sent command: SI\n", - "2026-03-30 13:31:10,491 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", - "2026-03-30 13:31:10,521 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 13:31:10,521 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 13:31:10,522 - pylabrobot - IO - [MT Scale] Sent command: TA\n", - "2026-03-30 13:31:10,524 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'TA\\r\\n'\n", - "2026-03-30 13:31:10,632 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'TA A 0.00000 g\\r\\n'\n", - "2026-03-30 13:31:10,633 - pylabrobot - IO - [MT Scale] Received response: b'TA A 0.00000 g\\r\\n'\n", - "2026-03-30 13:31:10,634 - pylabrobot - IO - [MT Scale] Sent command: TAC\n", - "2026-03-30 13:31:10,635 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'TAC\\r\\n'\n", - "2026-03-30 13:31:10,664 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'TAC A\\r\\n'\n", - "2026-03-30 13:31:10,665 - pylabrobot - IO - [MT Scale] Received response: b'TAC A\\r\\n'\n", - "2026-03-30 13:31:10,666 - pylabrobot - IO - [MT Scale] Sent command: TA\n", - "2026-03-30 13:31:10,667 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'TA\\r\\n'\n", - "2026-03-30 13:31:10,728 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'TA A 0.00000 g\\r\\n'\n", - "2026-03-30 13:31:10,728 - pylabrobot - IO - [MT Scale] Received response: b'TA A 0.00000 g\\r\\n'\n" + "2026-03-30 13:22:12,193 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] reset_input_buffer\n", + "2026-03-30 13:22:12,196 - pylabrobot - IO - [MT Scale] Sent command: @\n", + "2026-03-30 13:22:12,207 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'@\\r\\n'\n", + "2026-03-30 13:22:12,262 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I4 A \"B207696838\"\\r\\n'\n", + "2026-03-30 13:22:12,264 - pylabrobot - IO - [MT Scale] Received response: b'I4 A \"B207696838\"\\r\\n'\n", + "2026-03-30 13:22:12,267 - pylabrobot - IO - [MT Scale] Sent command: I4\n", + "2026-03-30 13:22:12,273 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I4\\r\\n'\n", + "2026-03-30 13:22:12,308 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I4 A \"B207696838\"\\r\\n'\n", + "2026-03-30 13:22:12,312 - pylabrobot - IO - [MT Scale] Received response: b'I4 A \"B207696838\"\\r\\n'\n", + "2026-03-30 13:22:12,314 - pylabrobot - IO - [MT Scale] Sent command: I2\n", + "2026-03-30 13:22:12,315 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I2\\r\\n'\n", + "2026-03-30 13:22:12,371 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", + "2026-03-30 13:22:12,372 - pylabrobot - IO - [MT Scale] Received response: b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", + "2026-03-30 13:22:12,374 - pylabrobot - IO - [MT Scale] Sent command: I2\n", + "2026-03-30 13:22:12,377 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I2\\r\\n'\n", + "2026-03-30 13:22:12,435 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", + "2026-03-30 13:22:12,437 - pylabrobot - IO - [MT Scale] Received response: b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", + "2026-03-30 13:22:12,440 - pylabrobot - IO - [MT Scale] Sent command: S\n", + "2026-03-30 13:22:12,446 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", + "2026-03-30 13:22:12,771 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00005 g\\r\\n'\n", + "2026-03-30 13:22:12,772 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00005 g\\r\\n'\n", + "2026-03-30 13:22:12,773 - pylabrobot - IO - [MT Scale] Sent command: SI\n", + "2026-03-30 13:22:12,777 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", + "2026-03-30 13:22:12,819 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00005 g\\r\\n'\n", + "2026-03-30 13:22:12,820 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00005 g\\r\\n'\n", + "2026-03-30 13:22:12,821 - pylabrobot - IO - [MT Scale] Sent command: Z\n", + "2026-03-30 13:22:12,823 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'Z\\r\\n'\n", + "2026-03-30 13:22:13,155 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'Z A\\r\\n'\n", + "2026-03-30 13:22:13,155 - pylabrobot - IO - [MT Scale] Received response: b'Z A\\r\\n'\n", + "2026-03-30 13:22:13,156 - pylabrobot - IO - [MT Scale] Sent command: SI\n", + "2026-03-30 13:22:13,157 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", + "2026-03-30 13:22:13,186 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 13:22:13,187 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 13:22:13,188 - pylabrobot - IO - [MT Scale] Sent command: ZI\n", + "2026-03-30 13:22:13,190 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'ZI\\r\\n'\n", + "2026-03-30 13:22:13,218 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'ZI S\\r\\n'\n", + "2026-03-30 13:22:13,219 - pylabrobot - IO - [MT Scale] Received response: b'ZI S\\r\\n'\n", + "2026-03-30 13:22:13,219 - pylabrobot - IO - [MT Scale] Sent command: SI\n", + "2026-03-30 13:22:13,221 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", + "2026-03-30 13:22:13,251 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 13:22:13,251 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 13:22:13,252 - pylabrobot - IO - [MT Scale] Sent command: TA\n", + "2026-03-30 13:22:13,253 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'TA\\r\\n'\n", + "2026-03-30 13:22:13,363 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'TA A 0.00000 g\\r\\n'\n", + "2026-03-30 13:22:13,363 - pylabrobot - IO - [MT Scale] Received response: b'TA A 0.00000 g\\r\\n'\n", + "2026-03-30 13:22:13,364 - pylabrobot - IO - [MT Scale] Sent command: TAC\n", + "2026-03-30 13:22:13,366 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'TAC\\r\\n'\n", + "2026-03-30 13:22:13,394 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'TAC A\\r\\n'\n", + "2026-03-30 13:22:13,395 - pylabrobot - IO - [MT Scale] Received response: b'TAC A\\r\\n'\n", + "2026-03-30 13:22:13,396 - pylabrobot - IO - [MT Scale] Sent command: TA\n", + "2026-03-30 13:22:13,397 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'TA\\r\\n'\n", + "2026-03-30 13:22:13,474 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'TA A 0.00000 g\\r\\n'\n", + "2026-03-30 13:22:13,475 - pylabrobot - IO - [MT Scale] Received response: b'TA A 0.00000 g\\r\\n'\n" ] }, { @@ -890,48 +825,7 @@ } ], "source": [ - "# @ - Cancel (returns serial number)\n", - "sn = await backend.cancel()\n", - "assert sn == backend.serial_number, f\"cancel() returned {sn}, expected {backend.serial_number}\"\n", - "\n", - "# I4 - Serial number\n", - "sn2 = await backend.request_serial_number()\n", - "assert sn2 == sn\n", - "\n", - "# I2 - Device type and capacity\n", - "dt = await backend.request_device_type()\n", - "assert len(dt) > 0\n", - "cap = await backend.request_capacity()\n", - "assert cap > 0\n", - "\n", - "# S - Stable weight\n", - "w_stable = await backend.read_stable_weight()\n", - "assert isinstance(w_stable, float)\n", - "\n", - "# SI - Weight immediately\n", - "w_imm = await backend.read_weight_value_immediately()\n", - "assert isinstance(w_imm, float)\n", - "\n", - "# Z - Zero (stable) then read\n", - "await scale.zero(timeout=\"stable\")\n", - "w_after_zero = await backend.read_weight_value_immediately()\n", - "assert abs(w_after_zero) < 0.001, f\"Expected ~0 after zero, got {w_after_zero}\"\n", - "\n", - "# ZI - Zero immediately then read\n", - "await scale.zero(timeout=0)\n", - "w_after_zi = await backend.read_weight_value_immediately()\n", - "assert abs(w_after_zi) < 0.01\n", - "\n", - "# TA - Request tare weight\n", - "tare = await scale.request_tare_weight()\n", - "assert isinstance(tare, float)\n", - "\n", - "# TAC - Clear tare\n", - "await backend.clear_tare()\n", - "tare_after = await scale.request_tare_weight()\n", - "assert abs(tare_after) < 0.001\n", - "\n", - "print(\"PASS: all core Level 0/1 commands validated\")" + "# @ - Cancel (returns serial number)\nsn = await backend.reset()\nassert sn == backend.serial_number, f\"reset() returned {sn}, expected {backend.serial_number}\"\n\n# I4 - Serial number\nsn2 = await backend.request_serial_number()\nassert sn2 == sn\n\n# I2 - Device type and capacity\ndt = await backend.request_device_type()\nassert len(dt) > 0\ncap = await backend.request_capacity()\nassert cap > 0\n\n# S - Stable weight\nw_stable = await backend.read_stable_weight()\nassert isinstance(w_stable, float)\n\n# SI - Weight immediately\nw_imm = await backend.read_weight_value_immediately()\nassert isinstance(w_imm, float)\n\n# Z - Zero (stable) then read\nawait scale.zero(timeout=\"stable\")\nw_after_zero = await backend.read_weight_value_immediately()\nassert abs(w_after_zero) < 0.001, f\"Expected ~0 after zero, got {w_after_zero}\"\n\n# ZI - Zero immediately then read\nawait scale.zero(timeout=0)\nw_after_zi = await backend.read_weight_value_immediately()\nassert abs(w_after_zi) < 0.01\n\n# TA - Request tare weight\ntare = await scale.request_tare_weight()\nassert isinstance(tare, float)\n\n# TAC - Clear tare\nawait backend.clear_tare()\ntare_after = await scale.request_tare_weight()\nassert abs(tare_after) < 0.001\n\nprint(\"PASS: all core Level 0/1 commands validated\")" ] }, { @@ -967,18 +861,18 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 13:31:19,963 - pylabrobot - IO - [MT Scale] Sent command: Z\n", - "2026-03-30 13:31:19,967 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'Z\\r\\n'\n", - "2026-03-30 13:31:20,240 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'Z A\\r\\n'\n", - "2026-03-30 13:31:20,240 - pylabrobot - IO - [MT Scale] Received response: b'Z A\\r\\n'\n", - "2026-03-30 13:31:20,242 - pylabrobot - IO - [MT Scale] Sent command: T\n", - "2026-03-30 13:31:20,243 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'T\\r\\n'\n", - "2026-03-30 13:31:20,657 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'T S 0.00000 g\\r\\n'\n", - "2026-03-30 13:31:20,661 - pylabrobot - IO - [MT Scale] Received response: b'T S 0.00000 g\\r\\n'\n", - "2026-03-30 13:31:20,664 - pylabrobot - IO - [MT Scale] Sent command: TA\n", - "2026-03-30 13:31:20,667 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'TA\\r\\n'\n", - "2026-03-30 13:31:20,751 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'TA A 0.00000 g\\r\\n'\n", - "2026-03-30 13:31:20,751 - pylabrobot - IO - [MT Scale] Received response: b'TA A 0.00000 g\\r\\n'\n" + "2026-03-30 13:22:27,132 - pylabrobot - IO - [MT Scale] Sent command: Z\n", + "2026-03-30 13:22:27,134 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'Z\\r\\n'\n", + "2026-03-30 13:22:27,509 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'Z A\\r\\n'\n", + "2026-03-30 13:22:27,510 - pylabrobot - IO - [MT Scale] Received response: b'Z A\\r\\n'\n", + "2026-03-30 13:22:27,511 - pylabrobot - IO - [MT Scale] Sent command: T\n", + "2026-03-30 13:22:27,512 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'T\\r\\n'\n", + "2026-03-30 13:22:27,925 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'T S 0.00000 g\\r\\n'\n", + "2026-03-30 13:22:27,925 - pylabrobot - IO - [MT Scale] Received response: b'T S 0.00000 g\\r\\n'\n", + "2026-03-30 13:22:27,926 - pylabrobot - IO - [MT Scale] Sent command: TA\n", + "2026-03-30 13:22:27,927 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'TA\\r\\n'\n", + "2026-03-30 13:22:28,021 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'TA A 0.00000 g\\r\\n'\n", + "2026-03-30 13:22:28,022 - pylabrobot - IO - [MT Scale] Received response: b'TA A 0.00000 g\\r\\n'\n" ] }, { @@ -1026,10 +920,10 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 13:31:22,655 - pylabrobot - IO - [MT Scale] Sent command: TA\n", - "2026-03-30 13:31:22,658 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'TA\\r\\n'\n", - "2026-03-30 13:31:22,717 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'TA A 0.00000 g\\r\\n'\n", - "2026-03-30 13:31:22,719 - pylabrobot - IO - [MT Scale] Received response: b'TA A 0.00000 g\\r\\n'\n" + "2026-03-30 13:22:31,147 - pylabrobot - IO - [MT Scale] Sent command: TA\n", + "2026-03-30 13:22:31,151 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'TA\\r\\n'\n", + "2026-03-30 13:22:31,251 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'TA A 0.00000 g\\r\\n'\n", + "2026-03-30 13:22:31,252 - pylabrobot - IO - [MT Scale] Received response: b'TA A 0.00000 g\\r\\n'\n" ] }, { @@ -1064,14 +958,14 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 13:31:23,482 - pylabrobot - IO - [MT Scale] Sent command: TAC\n", - "2026-03-30 13:31:23,485 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'TAC\\r\\n'\n", - "2026-03-30 13:31:23,517 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'TAC A\\r\\n'\n", - "2026-03-30 13:31:23,518 - pylabrobot - IO - [MT Scale] Received response: b'TAC A\\r\\n'\n", - "2026-03-30 13:31:23,519 - pylabrobot - IO - [MT Scale] Sent command: TA\n", - "2026-03-30 13:31:23,522 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'TA\\r\\n'\n", - "2026-03-30 13:31:23,597 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'TA A 0.00000 g\\r\\n'\n", - "2026-03-30 13:31:23,599 - pylabrobot - IO - [MT Scale] Received response: b'TA A 0.00000 g\\r\\n'\n" + "2026-03-30 13:22:32,399 - pylabrobot - IO - [MT Scale] Sent command: TAC\n", + "2026-03-30 13:22:32,401 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'TAC\\r\\n'\n", + "2026-03-30 13:22:32,434 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'TAC A\\r\\n'\n", + "2026-03-30 13:22:32,435 - pylabrobot - IO - [MT Scale] Received response: b'TAC A\\r\\n'\n", + "2026-03-30 13:22:32,436 - pylabrobot - IO - [MT Scale] Sent command: TA\n", + "2026-03-30 13:22:32,440 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'TA\\r\\n'\n", + "2026-03-30 13:22:32,532 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'TA A 0.00000 g\\r\\n'\n", + "2026-03-30 13:22:32,533 - pylabrobot - IO - [MT Scale] Received response: b'TA A 0.00000 g\\r\\n'\n" ] }, { @@ -1115,10 +1009,10 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 13:31:24,453 - pylabrobot - IO - [MT Scale] Sent command: M21 0 0\n", - "2026-03-30 13:31:24,457 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'M21 0 0\\r\\n'\n", - "2026-03-30 13:31:24,492 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M21 A\\r\\n'\n", - "2026-03-30 13:31:24,493 - pylabrobot - IO - [MT Scale] Received response: b'M21 A\\r\\n'\n" + "2026-03-30 13:22:34,042 - pylabrobot - IO - [MT Scale] Sent command: M21 0 0\n", + "2026-03-30 13:22:34,044 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'M21 0 0\\r\\n'\n", + "2026-03-30 13:22:34,082 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M21 A\\r\\n'\n", + "2026-03-30 13:22:34,085 - pylabrobot - IO - [MT Scale] Received response: b'M21 A\\r\\n'\n" ] }, { @@ -1184,12 +1078,12 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 13:31:26,300 - pylabrobot - IO - [MT Scale] Sent command: M28\n", - "2026-03-30 13:31:26,303 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'M28\\r\\n'\n", - "2026-03-30 13:31:26,330 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M28 B 1 20.1\\r\\n'\n", - "2026-03-30 13:31:26,331 - pylabrobot - IO - [MT Scale] Received response: b'M28 B 1 20.1\\r\\n'\n", - "2026-03-30 13:31:26,347 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M28 A 2 19.6\\r\\n'\n", - "2026-03-30 13:31:26,348 - pylabrobot - IO - [MT Scale] Received response: b'M28 A 2 19.6\\r\\n'\n" + "2026-03-30 13:22:37,302 - pylabrobot - IO - [MT Scale] Sent command: M28\n", + "2026-03-30 13:22:37,305 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'M28\\r\\n'\n", + "2026-03-30 13:22:37,341 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M28 B 1 20.1\\r\\n'\n", + "2026-03-30 13:22:37,342 - pylabrobot - IO - [MT Scale] Received response: b'M28 B 1 20.1\\r\\n'\n", + "2026-03-30 13:22:37,359 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M28 A 2 19.6\\r\\n'\n", + "2026-03-30 13:22:37,360 - pylabrobot - IO - [MT Scale] Received response: b'M28 A 2 19.6\\r\\n'\n" ] }, { @@ -1229,26 +1123,26 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 13:31:27,946 - pylabrobot - IO - [MT Scale] Sent command: M01\n", - "2026-03-30 13:31:27,951 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'M01\\r\\n'\n", - "2026-03-30 13:31:27,976 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M01 A 0\\r\\n'\n", - "2026-03-30 13:31:27,978 - pylabrobot - IO - [MT Scale] Received response: b'M01 A 0\\r\\n'\n", - "2026-03-30 13:31:27,979 - pylabrobot - IO - [MT Scale] Sent command: M02\n", - "2026-03-30 13:31:27,981 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'M02\\r\\n'\n", - "2026-03-30 13:31:28,009 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M02 A 2\\r\\n'\n", - "2026-03-30 13:31:28,010 - pylabrobot - IO - [MT Scale] Received response: b'M02 A 2\\r\\n'\n", - "2026-03-30 13:31:28,012 - pylabrobot - IO - [MT Scale] Sent command: M03\n", - "2026-03-30 13:31:28,014 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'M03\\r\\n'\n", - "2026-03-30 13:31:28,041 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M03 A 0\\r\\n'\n", - "2026-03-30 13:31:28,042 - pylabrobot - IO - [MT Scale] Received response: b'M03 A 0\\r\\n'\n", - "2026-03-30 13:31:28,044 - pylabrobot - IO - [MT Scale] Sent command: M27\n", - "2026-03-30 13:31:28,048 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'M27\\r\\n'\n", - "2026-03-30 13:31:28,104 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 1 13 05 2020 17 17 0 \"\"\\r\\n'\n", - "2026-03-30 13:31:28,105 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 1 13 05 2020 17 17 0 \"\"\\r\\n'\n", - "2026-03-30 13:31:28,136 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 2 02 12 2019 20 02 0 \"\"\\r\\n'\n", - "2026-03-30 13:31:28,142 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 2 02 12 2019 20 02 0 \"\"\\r\\n'\n", - "2026-03-30 13:31:28,168 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 3 11 10 2019 17 05 0 \"\"\\r\\n'\n", - "2026-03-30 13:31:28,169 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 3 11 10 2019 17 05 0 \"\"\\r\\n'\n" + "2026-03-30 13:22:39,846 - pylabrobot - IO - [MT Scale] Sent command: M01\n", + "2026-03-30 13:22:39,848 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'M01\\r\\n'\n", + "2026-03-30 13:22:39,883 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M01 A 0\\r\\n'\n", + "2026-03-30 13:22:39,883 - pylabrobot - IO - [MT Scale] Received response: b'M01 A 0\\r\\n'\n", + "2026-03-30 13:22:39,885 - pylabrobot - IO - [MT Scale] Sent command: M02\n", + "2026-03-30 13:22:39,887 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'M02\\r\\n'\n", + "2026-03-30 13:22:39,915 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M02 A 2\\r\\n'\n", + "2026-03-30 13:22:39,917 - pylabrobot - IO - [MT Scale] Received response: b'M02 A 2\\r\\n'\n", + "2026-03-30 13:22:39,918 - pylabrobot - IO - [MT Scale] Sent command: M03\n", + "2026-03-30 13:22:39,920 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'M03\\r\\n'\n", + "2026-03-30 13:22:39,947 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M03 A 0\\r\\n'\n", + "2026-03-30 13:22:39,949 - pylabrobot - IO - [MT Scale] Received response: b'M03 A 0\\r\\n'\n", + "2026-03-30 13:22:39,951 - pylabrobot - IO - [MT Scale] Sent command: M27\n", + "2026-03-30 13:22:39,953 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'M27\\r\\n'\n", + "2026-03-30 13:22:40,013 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 1 13 05 2020 17 17 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:40,018 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 1 13 05 2020 17 17 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:40,043 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 2 02 12 2019 20 02 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:40,044 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 2 02 12 2019 20 02 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:40,075 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 3 11 10 2019 17 05 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:40,076 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 3 11 10 2019 17 05 0 \"\"\\r\\n'\n" ] }, { @@ -1264,116 +1158,118 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 13:31:28,201 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 4 11 10 2019 17 01 0 \"\"\\r\\n'\n", - "2026-03-30 13:31:28,202 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 4 11 10 2019 17 01 0 \"\"\\r\\n'\n", - "2026-03-30 13:31:28,233 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 5 14 03 2019 20 22 0 \"\"\\r\\n'\n", - "2026-03-30 13:31:28,233 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 5 14 03 2019 20 22 0 \"\"\\r\\n'\n", - "2026-03-30 13:31:28,265 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 6 14 03 2019 20 18 0 \"\"\\r\\n'\n", - "2026-03-30 13:31:28,267 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 6 14 03 2019 20 18 0 \"\"\\r\\n'\n", - "2026-03-30 13:31:28,298 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 7 17 10 2018 17 38 0 \"\"\\r\\n'\n", - "2026-03-30 13:31:28,300 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 7 17 10 2018 17 38 0 \"\"\\r\\n'\n", - "2026-03-30 13:31:28,328 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 8 17 10 2018 17 37 0 \"\"\\r\\n'\n", - "2026-03-30 13:31:28,331 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 8 17 10 2018 17 37 0 \"\"\\r\\n'\n", - "2026-03-30 13:31:28,361 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 9 17 10 2018 17 35 0 \"\"\\r\\n'\n", - "2026-03-30 13:31:28,362 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 9 17 10 2018 17 35 0 \"\"\\r\\n'\n", - "2026-03-30 13:31:28,394 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 10 20 09 2018 21 23 0 \"\"\\r\\n'\n", - "2026-03-30 13:31:28,401 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 10 20 09 2018 21 23 0 \"\"\\r\\n'\n", - "2026-03-30 13:31:28,429 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 11 15 03 2018 23 51 0 \"\"\\r\\n'\n", - "2026-03-30 13:31:28,431 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 11 15 03 2018 23 51 0 \"\"\\r\\n'\n", - "2026-03-30 13:31:28,456 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 12 16 12 2017 00 20 0 \"\"\\r\\n'\n", - "2026-03-30 13:31:28,458 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 12 16 12 2017 00 20 0 \"\"\\r\\n'\n", - "2026-03-30 13:31:28,490 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 13 16 12 2017 00 18 0 \"\"\\r\\n'\n", - "2026-03-30 13:31:28,492 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 13 16 12 2017 00 18 0 \"\"\\r\\n'\n", - "2026-03-30 13:31:28,520 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 14 18 10 2017 12 06 0 \"\"\\r\\n'\n", - "2026-03-30 13:31:28,522 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 14 18 10 2017 12 06 0 \"\"\\r\\n'\n", - "2026-03-30 13:31:28,552 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 15 18 10 2017 11 58 0 \"\"\\r\\n'\n", - "2026-03-30 13:31:28,553 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 15 18 10 2017 11 58 0 \"\"\\r\\n'\n", - "2026-03-30 13:31:28,600 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 16 05 09 2017 22 40 0 \"\"\\r\\n'\n", - "2026-03-30 13:31:28,602 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 16 05 09 2017 22 40 0 \"\"\\r\\n'\n", - "2026-03-30 13:31:28,632 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 17 21 06 2017 18 39 0 \"\"\\r\\n'\n", - "2026-03-30 13:31:28,635 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 17 21 06 2017 18 39 0 \"\"\\r\\n'\n", - "2026-03-30 13:31:28,664 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 18 30 03 2017 19 24 0 \"\"\\r\\n'\n", - "2026-03-30 13:31:28,667 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 18 30 03 2017 19 24 0 \"\"\\r\\n'\n", - "2026-03-30 13:31:28,696 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 19 09 03 2017 23 21 0 \"\"\\r\\n'\n", - "2026-03-30 13:31:28,698 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 19 09 03 2017 23 21 0 \"\"\\r\\n'\n", - "2026-03-30 13:31:28,729 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 20 09 03 2017 23 19 0 \"\"\\r\\n'\n", - "2026-03-30 13:31:28,734 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 20 09 03 2017 23 19 0 \"\"\\r\\n'\n", - "2026-03-30 13:31:28,760 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 21 20 12 2016 21 55 0 \"\"\\r\\n'\n", - "2026-03-30 13:31:28,762 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 21 20 12 2016 21 55 0 \"\"\\r\\n'\n", - "2026-03-30 13:31:28,792 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 22 19 10 2016 17 36 0 \"\"\\r\\n'\n", - "2026-03-30 13:31:28,799 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 22 19 10 2016 17 36 0 \"\"\\r\\n'\n", - "2026-03-30 13:31:28,824 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 23 19 10 2016 17 33 0 \"\"\\r\\n'\n", - "2026-03-30 13:31:28,825 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 23 19 10 2016 17 33 0 \"\"\\r\\n'\n", - "2026-03-30 13:31:28,857 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 24 18 10 2016 21 00 0 \"\"\\r\\n'\n", - "2026-03-30 13:31:28,859 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 24 18 10 2016 21 00 0 \"\"\\r\\n'\n", - "2026-03-30 13:31:28,888 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 25 18 10 2016 18 47 0 \"\"\\r\\n'\n", - "2026-03-30 13:31:28,889 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 25 18 10 2016 18 47 0 \"\"\\r\\n'\n", - "2026-03-30 13:31:28,921 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 26 18 10 2016 15 33 0 \"\"\\r\\n'\n", - "2026-03-30 13:31:28,923 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 26 18 10 2016 15 33 0 \"\"\\r\\n'\n", - "2026-03-30 13:31:28,969 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 27 18 10 2016 14 32 0 \"\"\\r\\n'\n", - "2026-03-30 13:31:28,974 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 27 18 10 2016 14 32 0 \"\"\\r\\n'\n", - "2026-03-30 13:31:29,000 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 28 18 10 2016 14 28 0 \"\"\\r\\n'\n", - "2026-03-30 13:31:29,006 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 28 18 10 2016 14 28 0 \"\"\\r\\n'\n", - "2026-03-30 13:31:29,032 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 29 18 10 2016 13 41 0 \"\"\\r\\n'\n", - "2026-03-30 13:31:29,034 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 29 18 10 2016 13 41 0 \"\"\\r\\n'\n", - "2026-03-30 13:31:29,064 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 30 21 09 2016 15 15 0 \"\"\\r\\n'\n", - "2026-03-30 13:31:29,065 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 30 21 09 2016 15 15 0 \"\"\\r\\n'\n", - "2026-03-30 13:31:29,096 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 31 04 03 2016 22 28 0 \"\"\\r\\n'\n", - "2026-03-30 13:31:29,099 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 31 04 03 2016 22 28 0 \"\"\\r\\n'\n", - "2026-03-30 13:31:29,128 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 32 01 10 2015 19 06 0 \"\"\\r\\n'\n", - "2026-03-30 13:31:29,134 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 32 01 10 2015 19 06 0 \"\"\\r\\n'\n", - "2026-03-30 13:31:29,169 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 33 01 10 2015 18 56 0 \"\"\\r\\n'\n", - "2026-03-30 13:31:29,172 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 33 01 10 2015 18 56 0 \"\"\\r\\n'\n", - "2026-03-30 13:31:29,192 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 34 03 09 2015 22 11 0 \"\"\\r\\n'\n", - "2026-03-30 13:31:29,193 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 34 03 09 2015 22 11 0 \"\"\\r\\n'\n", - "2026-03-30 13:31:29,226 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 35 11 03 2015 13 20 0 \"\"\\r\\n'\n", - "2026-03-30 13:31:29,227 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 35 11 03 2015 13 20 0 \"\"\\r\\n'\n", - "2026-03-30 13:31:29,256 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 36 11 03 2015 13 18 0 \"\"\\r\\n'\n", - "2026-03-30 13:31:29,257 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 36 11 03 2015 13 18 0 \"\"\\r\\n'\n", - "2026-03-30 13:31:29,288 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 37 11 03 2015 13 15 0 \"\"\\r\\n'\n", - "2026-03-30 13:31:29,294 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 37 11 03 2015 13 15 0 \"\"\\r\\n'\n", - "2026-03-30 13:31:29,320 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 38 11 03 2015 13 13 0 \"\"\\r\\n'\n", - "2026-03-30 13:31:29,321 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 38 11 03 2015 13 13 0 \"\"\\r\\n'\n", - "2026-03-30 13:31:29,367 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 39 22 01 2015 03 17 0 \"\"\\r\\n'\n", - "2026-03-30 13:31:29,369 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 39 22 01 2015 03 17 0 \"\"\\r\\n'\n", - "2026-03-30 13:31:29,404 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 40 22 01 2015 03 15 0 \"\"\\r\\n'\n", - "2026-03-30 13:31:29,406 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 40 22 01 2015 03 15 0 \"\"\\r\\n'\n", - "2026-03-30 13:31:29,432 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 41 06 11 2014 17 08 0 \"\"\\r\\n'\n", - "2026-03-30 13:31:29,434 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 41 06 11 2014 17 08 0 \"\"\\r\\n'\n", - "2026-03-30 13:31:29,464 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 42 06 11 2014 16 22 0 \"\"\\r\\n'\n", - "2026-03-30 13:31:29,464 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 42 06 11 2014 16 22 0 \"\"\\r\\n'\n", - "2026-03-30 13:31:29,499 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 43 06 11 2014 16 20 0 \"\"\\r\\n'\n", - "2026-03-30 13:31:29,503 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 43 06 11 2014 16 20 0 \"\"\\r\\n'\n", - "2026-03-30 13:31:29,528 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 44 06 11 2014 15 57 0 \"\"\\r\\n'\n", - "2026-03-30 13:31:29,532 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 44 06 11 2014 15 57 0 \"\"\\r\\n'\n", - "2026-03-30 13:31:29,560 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 45 18 09 2014 20 23 0 \"\"\\r\\n'\n", - "2026-03-30 13:31:29,564 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 45 18 09 2014 20 23 0 \"\"\\r\\n'\n", - "2026-03-30 13:31:29,592 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 46 18 09 2014 19 54 0 \"\"\\r\\n'\n", - "2026-03-30 13:31:29,596 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 46 18 09 2014 19 54 0 \"\"\\r\\n'\n", - "2026-03-30 13:31:29,629 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 47 18 09 2014 19 44 0 \"\"\\r\\n'\n", - "2026-03-30 13:31:29,632 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 47 18 09 2014 19 44 0 \"\"\\r\\n'\n", - "2026-03-30 13:31:29,655 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 48 18 09 2014 19 35 0 \"\"\\r\\n'\n", - "2026-03-30 13:31:29,655 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 48 18 09 2014 19 35 0 \"\"\\r\\n'\n", - "2026-03-30 13:31:29,687 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 49 15 09 2014 20 08 0 \"\"\\r\\n'\n", - "2026-03-30 13:31:29,687 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 49 15 09 2014 20 08 0 \"\"\\r\\n'\n", - "2026-03-30 13:31:29,721 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 A 50 15 09 2014 19 39 0 \"\"\\r\\n'\n", - "2026-03-30 13:31:29,722 - pylabrobot - IO - [MT Scale] Received response: b'M27 A 50 15 09 2014 19 39 0 \"\"\\r\\n'\n", - "2026-03-30 13:31:29,724 - pylabrobot - IO - [MT Scale] Sent command: UPD\n", - "2026-03-30 13:31:29,726 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'UPD\\r\\n'\n", - "2026-03-30 13:31:29,767 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'UPD A 10.173\\r\\n'\n", - "2026-03-30 13:31:29,768 - pylabrobot - IO - [MT Scale] Received response: b'UPD A 10.173\\r\\n'\n", - "2026-03-30 13:31:29,770 - pylabrobot - IO - [MT Scale] Sent command: SIS\n", - "2026-03-30 13:31:29,772 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SIS\\r\\n'\n", - "2026-03-30 13:31:29,831 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'SIS A 0 \"0.00000\" 0 5 1 0 0\\r\\n'\n", - "2026-03-30 13:31:29,833 - pylabrobot - IO - [MT Scale] Received response: b'SIS A 0 \"0.00000\" 0 5 1 0 0\\r\\n'\n", - "2026-03-30 13:31:29,835 - pylabrobot - IO - [MT Scale] Sent command: LST\n", - "2026-03-30 13:31:29,837 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'LST\\r\\n'\n", - "2026-03-30 13:31:29,879 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B C0 0 0 \"\"\\r\\n'\n", - "2026-03-30 13:31:29,880 - pylabrobot - IO - [MT Scale] Received response: b'LST B C0 0 0 \"\"\\r\\n'\n", - "2026-03-30 13:31:29,896 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B FCUT 0.000\\r\\n'\n", - "2026-03-30 13:31:29,897 - pylabrobot - IO - [MT Scale] Received response: b'LST B FCUT 0.000\\r\\n'\n", - "2026-03-30 13:31:29,911 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B I10 \"\"\\r\\n'\n", - "2026-03-30 13:31:29,913 - pylabrobot - IO - [MT Scale] Received response: b'LST B I10 \"\"\\r\\n'\n" + "2026-03-30 13:22:40,106 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 4 11 10 2019 17 01 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:40,110 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 4 11 10 2019 17 01 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:40,138 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 5 14 03 2019 20 22 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:40,140 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 5 14 03 2019 20 22 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:40,171 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 6 14 03 2019 20 18 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:40,172 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 6 14 03 2019 20 18 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:40,203 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 7 17 10 2018 17 38 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:40,204 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 7 17 10 2018 17 38 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:40,235 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 8 17 10 2018 17 37 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:40,240 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 8 17 10 2018 17 37 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:40,267 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 9 17 10 2018 17 35 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:40,269 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 9 17 10 2018 17 35 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:40,298 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 10 20 09 2018 21 23 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:40,302 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 10 20 09 2018 21 23 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:40,332 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 11 15 03 2018 23 51 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:40,333 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 11 15 03 2018 23 51 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:40,364 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 12 16 12 2017 00 20 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:40,368 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 12 16 12 2017 00 20 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:40,394 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 13 16 12 2017 00 18 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:40,397 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 13 16 12 2017 00 18 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:40,428 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 14 18 10 2017 12 06 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:40,430 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 14 18 10 2017 12 06 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:40,458 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 15 18 10 2017 11 58 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:40,460 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 15 18 10 2017 11 58 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:40,491 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 16 05 09 2017 22 40 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:40,492 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 16 05 09 2017 22 40 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:40,540 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 17 21 06 2017 18 39 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:40,544 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 17 21 06 2017 18 39 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:40,572 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 18 30 03 2017 19 24 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:40,578 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 18 30 03 2017 19 24 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:40,602 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 19 09 03 2017 23 21 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:40,605 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 19 09 03 2017 23 21 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:40,636 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 20 09 03 2017 23 19 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:40,637 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 20 09 03 2017 23 19 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:40,667 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 21 20 12 2016 21 55 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:40,668 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 21 20 12 2016 21 55 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:40,700 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 22 19 10 2016 17 36 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:40,701 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 22 19 10 2016 17 36 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:40,731 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 23 19 10 2016 17 33 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:40,732 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 23 19 10 2016 17 33 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:40,762 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 24 18 10 2016 21 00 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:40,764 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 24 18 10 2016 21 00 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:40,794 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 25 18 10 2016 18 47 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:40,796 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 25 18 10 2016 18 47 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:40,826 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 26 18 10 2016 15 33 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:40,827 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 26 18 10 2016 15 33 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:40,858 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 27 18 10 2016 14 32 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:40,859 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 27 18 10 2016 14 32 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:40,907 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 28 18 10 2016 14 28 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:40,910 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 28 18 10 2016 14 28 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:40,938 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 29 18 10 2016 13 41 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:40,939 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 29 18 10 2016 13 41 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:40,970 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 30 21 09 2016 15 15 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:40,971 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 30 21 09 2016 15 15 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:41,003 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 31 04 03 2016 22 28 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:41,006 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 31 04 03 2016 22 28 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:41,036 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 32 01 10 2015 19 06 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:41,037 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 32 01 10 2015 19 06 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:41,067 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 33 01 10 2015 18 56 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:41,068 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 33 01 10 2015 18 56 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:41,099 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 34 03 09 2015 22 11 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:41,101 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 34 03 09 2015 22 11 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:41,130 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 35 11 03 2015 13 20 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:41,132 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 35 11 03 2015 13 20 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:41,162 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 36 11 03 2015 13 18 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:41,163 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 36 11 03 2015 13 18 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:41,195 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 37 11 03 2015 13 15 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:41,197 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 37 11 03 2015 13 15 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:41,228 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 38 11 03 2015 13 13 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:41,229 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 38 11 03 2015 13 13 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:41,260 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 39 22 01 2015 03 17 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:41,261 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 39 22 01 2015 03 17 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:41,306 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 40 22 01 2015 03 15 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:41,306 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 40 22 01 2015 03 15 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:41,337 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 41 06 11 2014 17 08 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:41,338 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 41 06 11 2014 17 08 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:41,370 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 42 06 11 2014 16 22 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:41,371 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 42 06 11 2014 16 22 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:41,402 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 43 06 11 2014 16 20 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:41,402 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 43 06 11 2014 16 20 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:41,434 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 44 06 11 2014 15 57 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:41,435 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 44 06 11 2014 15 57 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:41,466 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 45 18 09 2014 20 23 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:41,467 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 45 18 09 2014 20 23 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:41,501 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 46 18 09 2014 19 54 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:41,503 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 46 18 09 2014 19 54 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:41,532 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 47 18 09 2014 19 44 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:41,533 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 47 18 09 2014 19 44 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:41,562 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 48 18 09 2014 19 35 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:41,563 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 48 18 09 2014 19 35 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:41,594 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 49 15 09 2014 20 08 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:41,595 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 49 15 09 2014 20 08 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:41,627 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 A 50 15 09 2014 19 39 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:41,628 - pylabrobot - IO - [MT Scale] Received response: b'M27 A 50 15 09 2014 19 39 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:41,632 - pylabrobot - IO - [MT Scale] Sent command: UPD\n", + "2026-03-30 13:22:41,636 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'UPD\\r\\n'\n", + "2026-03-30 13:22:41,674 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'UPD A 10.173\\r\\n'\n", + "2026-03-30 13:22:41,674 - pylabrobot - IO - [MT Scale] Received response: b'UPD A 10.173\\r\\n'\n", + "2026-03-30 13:22:41,676 - pylabrobot - IO - [MT Scale] Sent command: SIS\n", + "2026-03-30 13:22:41,680 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SIS\\r\\n'\n", + "2026-03-30 13:22:41,722 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'SIS A 0 \"0.00000\" 0 5 1 0 0\\r\\n'\n", + "2026-03-30 13:22:41,723 - pylabrobot - IO - [MT Scale] Received response: b'SIS A 0 \"0.00000\" 0 5 1 0 0\\r\\n'\n", + "2026-03-30 13:22:41,724 - pylabrobot - IO - [MT Scale] Sent command: LST\n", + "2026-03-30 13:22:41,728 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'LST\\r\\n'\n", + "2026-03-30 13:22:41,770 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B C0 0 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:41,770 - pylabrobot - IO - [MT Scale] Received response: b'LST B C0 0 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:41,785 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B FCUT 0.000\\r\\n'\n", + "2026-03-30 13:22:41,786 - pylabrobot - IO - [MT Scale] Received response: b'LST B FCUT 0.000\\r\\n'\n", + "2026-03-30 13:22:41,802 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B I10 \"\"\\r\\n'\n", + "2026-03-30 13:22:41,803 - pylabrobot - IO - [MT Scale] Received response: b'LST B I10 \"\"\\r\\n'\n", + "2026-03-30 13:22:41,817 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B M01 0\\r\\n'\n", + "2026-03-30 13:22:41,818 - pylabrobot - IO - [MT Scale] Received response: b'LST B M01 0\\r\\n'\n" ] }, { @@ -1442,64 +1338,62 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 13:31:29,927 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B M01 0\\r\\n'\n", - "2026-03-30 13:31:29,930 - pylabrobot - IO - [MT Scale] Received response: b'LST B M01 0\\r\\n'\n", - "2026-03-30 13:31:29,943 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B M02 2\\r\\n'\n", - "2026-03-30 13:31:29,944 - pylabrobot - IO - [MT Scale] Received response: b'LST B M02 2\\r\\n'\n", - "2026-03-30 13:31:29,959 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B M03 0\\r\\n'\n", - "2026-03-30 13:31:29,961 - pylabrobot - IO - [MT Scale] Received response: b'LST B M03 0\\r\\n'\n", - "2026-03-30 13:31:29,975 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B M17 00 00 00 0\\r\\n'\n", - "2026-03-30 13:31:29,977 - pylabrobot - IO - [MT Scale] Received response: b'LST B M17 00 00 00 0\\r\\n'\n", - "2026-03-30 13:31:29,994 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B M18 1\\r\\n'\n", - "2026-03-30 13:31:29,996 - pylabrobot - IO - [MT Scale] Received response: b'LST B M18 1\\r\\n'\n", - "2026-03-30 13:31:30,007 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B M19 10.00000 g\\r\\n'\n", - "2026-03-30 13:31:30,008 - pylabrobot - IO - [MT Scale] Received response: b'LST B M19 10.00000 g\\r\\n'\n", - "2026-03-30 13:31:30,040 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B M20 200.00000 g\\r\\n'\n", - "2026-03-30 13:31:30,045 - pylabrobot - IO - [MT Scale] Received response: b'LST B M20 200.00000 g\\r\\n'\n", - "2026-03-30 13:31:30,054 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B M21 0 0\\r\\n'\n", - "2026-03-30 13:31:30,055 - pylabrobot - IO - [MT Scale] Received response: b'LST B M21 0 0\\r\\n'\n", - "2026-03-30 13:31:30,072 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B M29 1\\r\\n'\n", - "2026-03-30 13:31:30,073 - pylabrobot - IO - [MT Scale] Received response: b'LST B M29 1\\r\\n'\n", - "2026-03-30 13:31:30,078 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B M31 0\\r\\n'\n", - "2026-03-30 13:31:30,082 - pylabrobot - IO - [MT Scale] Received response: b'LST B M31 0\\r\\n'\n", - "2026-03-30 13:31:30,103 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B M32 1 00 00 0\\r\\n'\n", - "2026-03-30 13:31:30,105 - pylabrobot - IO - [MT Scale] Received response: b'LST B M32 1 00 00 0\\r\\n'\n", - "2026-03-30 13:31:30,119 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B M32 2 00 00 0\\r\\n'\n", - "2026-03-30 13:31:30,120 - pylabrobot - IO - [MT Scale] Received response: b'LST B M32 2 00 00 0\\r\\n'\n", - "2026-03-30 13:31:30,151 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B M32 3 00 00 0\\r\\n'\n", - "2026-03-30 13:31:30,152 - pylabrobot - IO - [MT Scale] Received response: b'LST B M32 3 00 00 0\\r\\n'\n", - "2026-03-30 13:31:30,156 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B M33 0\\r\\n'\n", - "2026-03-30 13:31:30,158 - pylabrobot - IO - [MT Scale] Received response: b'LST B M33 0\\r\\n'\n", - "2026-03-30 13:31:30,167 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B M35 0\\r\\n'\n", - "2026-03-30 13:31:30,170 - pylabrobot - IO - [MT Scale] Received response: b'LST B M35 0\\r\\n'\n", - "2026-03-30 13:31:30,183 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B RDB 5\\r\\n'\n", - "2026-03-30 13:31:30,185 - pylabrobot - IO - [MT Scale] Received response: b'LST B RDB 5\\r\\n'\n", - "2026-03-30 13:31:30,199 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B TST0 0 \"\"\\r\\n'\n", - "2026-03-30 13:31:30,203 - pylabrobot - IO - [MT Scale] Received response: b'LST B TST0 0 \"\"\\r\\n'\n", - "2026-03-30 13:31:30,215 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B UPD 10.173\\r\\n'\n", - "2026-03-30 13:31:30,217 - pylabrobot - IO - [MT Scale] Received response: b'LST B UPD 10.173\\r\\n'\n", - "2026-03-30 13:31:30,247 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B USTB 0 3.600 1.100\\r\\n'\n", - "2026-03-30 13:31:30,248 - pylabrobot - IO - [MT Scale] Received response: b'LST B USTB 0 3.600 1.100\\r\\n'\n", - "2026-03-30 13:31:30,281 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B USTB 1 0.000 0.000\\r\\n'\n", - "2026-03-30 13:31:30,283 - pylabrobot - IO - [MT Scale] Received response: b'LST B USTB 1 0.000 0.000\\r\\n'\n", - "2026-03-30 13:31:30,296 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST A USTB 2 0.000 0.000\\r\\n'\n", - "2026-03-30 13:31:30,300 - pylabrobot - IO - [MT Scale] Received response: b'LST A USTB 2 0.000 0.000\\r\\n'\n", - "2026-03-30 13:31:30,303 - pylabrobot - IO - [MT Scale] Sent command: RDB\n", - "2026-03-30 13:31:30,307 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'RDB\\r\\n'\n", - "2026-03-30 13:31:30,342 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'RDB A 5\\r\\n'\n", - "2026-03-30 13:31:30,344 - pylabrobot - IO - [MT Scale] Received response: b'RDB A 5\\r\\n'\n", - "2026-03-30 13:31:30,347 - pylabrobot - IO - [MT Scale] Sent command: USTB\n", - "2026-03-30 13:31:30,350 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'USTB\\r\\n'\n", - "2026-03-30 13:31:30,391 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'USTB B 0 3.600 1.100\\r\\n'\n", - "2026-03-30 13:31:30,396 - pylabrobot - IO - [MT Scale] Received response: b'USTB B 0 3.600 1.100\\r\\n'\n", - "2026-03-30 13:31:30,426 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'USTB B 1 0.000 0.000\\r\\n'\n", - "2026-03-30 13:31:30,428 - pylabrobot - IO - [MT Scale] Received response: b'USTB B 1 0.000 0.000\\r\\n'\n", - "2026-03-30 13:31:30,439 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'USTB A 2 0.000 0.000\\r\\n'\n", - "2026-03-30 13:31:30,443 - pylabrobot - IO - [MT Scale] Received response: b'USTB A 2 0.000 0.000\\r\\n'\n", - "2026-03-30 13:31:30,449 - pylabrobot - IO - [MT Scale] Sent command: FCUT\n", - "2026-03-30 13:31:30,452 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'FCUT\\r\\n'\n", - "2026-03-30 13:31:30,486 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'FCUT A 0.000\\r\\n'\n", - "2026-03-30 13:31:30,487 - pylabrobot - IO - [MT Scale] Received response: b'FCUT A 0.000\\r\\n'\n" + "2026-03-30 13:22:41,833 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B M02 2\\r\\n'\n", + "2026-03-30 13:22:41,834 - pylabrobot - IO - [MT Scale] Received response: b'LST B M02 2\\r\\n'\n", + "2026-03-30 13:22:41,839 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B M03 0\\r\\n'\n", + "2026-03-30 13:22:41,841 - pylabrobot - IO - [MT Scale] Received response: b'LST B M03 0\\r\\n'\n", + "2026-03-30 13:22:41,865 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B M17 00 00 00 0\\r\\n'\n", + "2026-03-30 13:22:41,867 - pylabrobot - IO - [MT Scale] Received response: b'LST B M17 00 00 00 0\\r\\n'\n", + "2026-03-30 13:22:41,883 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B M18 1\\r\\n'\n", + "2026-03-30 13:22:41,884 - pylabrobot - IO - [MT Scale] Received response: b'LST B M18 1\\r\\n'\n", + "2026-03-30 13:22:41,897 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B M19 10.00000 g\\r\\n'\n", + "2026-03-30 13:22:41,898 - pylabrobot - IO - [MT Scale] Received response: b'LST B M19 10.00000 g\\r\\n'\n", + "2026-03-30 13:22:41,929 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B M20 200.00000 g\\r\\n'\n", + "2026-03-30 13:22:41,930 - pylabrobot - IO - [MT Scale] Received response: b'LST B M20 200.00000 g\\r\\n'\n", + "2026-03-30 13:22:41,945 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B M21 0 0\\r\\n'\n", + "2026-03-30 13:22:41,946 - pylabrobot - IO - [MT Scale] Received response: b'LST B M21 0 0\\r\\n'\n", + "2026-03-30 13:22:41,948 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B M29 1\\r\\n'\n", + "2026-03-30 13:22:41,949 - pylabrobot - IO - [MT Scale] Received response: b'LST B M29 1\\r\\n'\n", + "2026-03-30 13:22:41,961 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B M31 0\\r\\n'\n", + "2026-03-30 13:22:41,962 - pylabrobot - IO - [MT Scale] Received response: b'LST B M31 0\\r\\n'\n", + "2026-03-30 13:22:41,994 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B M32 1 00 00 0\\r\\n'\n", + "2026-03-30 13:22:41,996 - pylabrobot - IO - [MT Scale] Received response: b'LST B M32 1 00 00 0\\r\\n'\n", + "2026-03-30 13:22:42,010 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B M32 2 00 00 0\\r\\n'\n", + "2026-03-30 13:22:42,011 - pylabrobot - IO - [MT Scale] Received response: b'LST B M32 2 00 00 0\\r\\n'\n", + "2026-03-30 13:22:42,027 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B M32 3 00 00 0\\r\\n'\n", + "2026-03-30 13:22:42,029 - pylabrobot - IO - [MT Scale] Received response: b'LST B M32 3 00 00 0\\r\\n'\n", + "2026-03-30 13:22:42,043 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B M33 0\\r\\n'\n", + "2026-03-30 13:22:42,045 - pylabrobot - IO - [MT Scale] Received response: b'LST B M33 0\\r\\n'\n", + "2026-03-30 13:22:42,057 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B M35 0\\r\\n'\n", + "2026-03-30 13:22:42,058 - pylabrobot - IO - [MT Scale] Received response: b'LST B M35 0\\r\\n'\n", + "2026-03-30 13:22:42,073 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B RDB 5\\r\\n'\n", + "2026-03-30 13:22:42,074 - pylabrobot - IO - [MT Scale] Received response: b'LST B RDB 5\\r\\n'\n", + "2026-03-30 13:22:42,089 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B TST0 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:42,090 - pylabrobot - IO - [MT Scale] Received response: b'LST B TST0 0 \"\"\\r\\n'\n", + "2026-03-30 13:22:42,107 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B UPD 10.173\\r\\n'\n", + "2026-03-30 13:22:42,114 - pylabrobot - IO - [MT Scale] Received response: b'LST B UPD 10.173\\r\\n'\n", + "2026-03-30 13:22:42,137 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B USTB 0 3.600 1.100\\r\\n'\n", + "2026-03-30 13:22:42,139 - pylabrobot - IO - [MT Scale] Received response: b'LST B USTB 0 3.600 1.100\\r\\n'\n", + "2026-03-30 13:22:42,169 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B USTB 1 0.000 0.000\\r\\n'\n", + "2026-03-30 13:22:42,170 - pylabrobot - IO - [MT Scale] Received response: b'LST B USTB 1 0.000 0.000\\r\\n'\n", + "2026-03-30 13:22:42,187 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST A USTB 2 0.000 0.000\\r\\n'\n", + "2026-03-30 13:22:42,189 - pylabrobot - IO - [MT Scale] Received response: b'LST A USTB 2 0.000 0.000\\r\\n'\n", + "2026-03-30 13:22:42,195 - pylabrobot - IO - [MT Scale] Sent command: RDB\n", + "2026-03-30 13:22:42,204 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'RDB\\r\\n'\n", + "2026-03-30 13:22:42,234 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'RDB A 5\\r\\n'\n", + "2026-03-30 13:22:42,235 - pylabrobot - IO - [MT Scale] Received response: b'RDB A 5\\r\\n'\n", + "2026-03-30 13:22:42,237 - pylabrobot - IO - [MT Scale] Sent command: USTB\n", + "2026-03-30 13:22:42,243 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'USTB\\r\\n'\n", + "2026-03-30 13:22:42,282 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'USTB B 0 3.600 1.100\\r\\n'\n", + "2026-03-30 13:22:42,283 - pylabrobot - IO - [MT Scale] Received response: b'USTB B 0 3.600 1.100\\r\\n'\n", + "2026-03-30 13:22:42,314 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'USTB B 1 0.000 0.000\\r\\n'\n", + "2026-03-30 13:22:42,315 - pylabrobot - IO - [MT Scale] Received response: b'USTB B 1 0.000 0.000\\r\\n'\n", + "2026-03-30 13:22:42,329 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'USTB A 2 0.000 0.000\\r\\n'\n", + "2026-03-30 13:22:42,331 - pylabrobot - IO - [MT Scale] Received response: b'USTB A 2 0.000 0.000\\r\\n'\n", + "2026-03-30 13:22:42,332 - pylabrobot - IO - [MT Scale] Sent command: FCUT\n", + "2026-03-30 13:22:42,338 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'FCUT\\r\\n'\n", + "2026-03-30 13:22:42,377 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'FCUT A 0.000\\r\\n'\n", + "2026-03-30 13:22:42,379 - pylabrobot - IO - [MT Scale] Received response: b'FCUT A 0.000\\r\\n'\n" ] }, { @@ -1532,7 +1426,13 @@ "# M01 - Weighing mode (read-only query)\n", "if \"M01\" in backend._supported_commands:\n", " mode = await backend.request_weighing_mode()\n", - " mode_names = {0: \"Normal/Universal\", 1: \"Dosing\", 2: \"Sensor\", 3: \"Check weighing\", 6: \"Raw/No filter\"}\n", + " mode_names = {\n", + " 0: \"Normal/Universal\",\n", + " 1: \"Dosing\",\n", + " 2: \"Sensor\",\n", + " 3: \"Check weighing\",\n", + " 6: \"Raw/No filter\",\n", + " }\n", " print(f\"Weighing mode: {mode} ({mode_names.get(mode, 'unknown')})\")\n", "else:\n", " print(\"SKIP: M01 not supported\")\n", @@ -1540,7 +1440,14 @@ "# M02 - Environment condition (read-only query)\n", "if \"M02\" in backend._supported_commands:\n", " env = await backend.request_environment_condition()\n", - " env_names = {0: \"Very stable\", 1: \"Stable\", 2: \"Standard\", 3: \"Unstable\", 4: \"Very unstable\", 5: \"Automatic\"}\n", + " env_names = {\n", + " 0: \"Very stable\",\n", + " 1: \"Stable\",\n", + " 2: \"Standard\",\n", + " 3: \"Unstable\",\n", + " 4: \"Very unstable\",\n", + " 5: \"Automatic\",\n", + " }\n", " print(f\"Environment condition: {env} ({env_names.get(env, 'unknown')})\")\n", "else:\n", " print(\"SKIP: M02 not supported\")\n", @@ -1593,7 +1500,9 @@ "if \"RDB\" in backend._supported_commands:\n", " try:\n", " rdb_responses = await backend.send_command(\"RDB\")\n", - " print(f\"\\nReadability: {rdb_responses[0].command} {rdb_responses[0].status} {' '.join(rdb_responses[0].data)}\")\n", + " print(\n", + " f\"\\nReadability: {rdb_responses[0].command} {rdb_responses[0].status} {' '.join(rdb_responses[0].data)}\"\n", + " )\n", " except Exception as e:\n", " print(f\"RDB: {e}\")\n", "else:\n", @@ -1603,7 +1512,9 @@ "if \"USTB\" in backend._supported_commands:\n", " try:\n", " ustb_responses = await backend.send_command(\"USTB\")\n", - " print(f\"Stability criteria: {ustb_responses[0].command} {ustb_responses[0].status} {' '.join(ustb_responses[0].data)}\")\n", + " print(\n", + " f\"Stability criteria: {ustb_responses[0].command} {ustb_responses[0].status} {' '.join(ustb_responses[0].data)}\"\n", + " )\n", " except Exception as e:\n", " print(f\"USTB: {e}\")\n", "else:\n", @@ -1613,7 +1524,9 @@ "if \"FCUT\" in backend._supported_commands:\n", " try:\n", " fcut_responses = await backend.send_command(\"FCUT\")\n", - " print(f\"Filter cut-off: {fcut_responses[0].command} {fcut_responses[0].status} {' '.join(fcut_responses[0].data)}\")\n", + " print(\n", + " f\"Filter cut-off: {fcut_responses[0].command} {fcut_responses[0].status} {' '.join(fcut_responses[0].data)}\"\n", + " )\n", " except Exception as e:\n", " print(f\"FCUT: {e}\")\n", "else:\n", @@ -1625,63 +1538,13 @@ { "cell_type": "markdown", "metadata": {}, - "source": [ - "### SIS unit code verification (exploratory)\n", - "\n", - "Tests whether field index 4 in the SIS response is the unit code by temporarily\n", - "changing the host unit via M21, reading SIS, then restoring grams.\n", - "\n", - "**WARNING:** Temporarily writes a non-gram unit to device memory via M21.\n", - "If the cell fails mid-execution, run `await backend.set_host_unit_grams()`\n", - "manually to restore grams. setup() also restores grams on next connection." - ] + "source": "### SIS unit code verification (exploratory)\n\nTests whether field index 4 in the SIS response is the unit code by temporarily\nchanging the host unit via M21, reading SIS, then restoring grams.\n\n**WARNING:** Temporarily writes a non-gram unit to device memory via M21.\nIf the cell fails mid-execution, run `await backend.set_host_unit_grams()`\nmanually to restore grams. setup() also restores grams on next connection." }, { "cell_type": "code", - "execution_count": 15, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2026-03-30 13:31:34,078 - pylabrobot - IO - [MT Scale] Sent command: SIS\n", - "2026-03-30 13:31:34,081 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SIS\\r\\n'\n", - "2026-03-30 13:31:34,132 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'SIS A 0 \"0.00000\" 0 5 1 0 0\\r\\n'\n", - "2026-03-30 13:31:34,133 - pylabrobot - IO - [MT Scale] Received response: b'SIS A 0 \"0.00000\" 0 5 1 0 0\\r\\n'\n", - "2026-03-30 13:31:34,136 - pylabrobot - IO - [MT Scale] Sent command: M21 1 0\n", - "2026-03-30 13:31:34,139 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'M21 1 0\\r\\n'\n", - "2026-03-30 13:31:34,165 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M21 L\\r\\n'\n", - "2026-03-30 13:31:34,167 - pylabrobot - IO - [MT Scale] Received response: b'M21 L\\r\\n'\n", - "2026-03-30 13:31:34,168 - pylabrobot - IO - [MT Scale] Sent command: M21 0 0\n", - "2026-03-30 13:31:34,171 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'M21 0 0\\r\\n'\n", - "2026-03-30 13:31:34,212 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M21 A\\r\\n'\n", - "2026-03-30 13:31:34,214 - pylabrobot - IO - [MT Scale] Received response: b'M21 A\\r\\n'\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "SIS in grams: ['0', '0.00000', '0', '5', '1', '0', '0']\n", - "\n", - "Restored host unit to grams\n" - ] - }, - { - "ename": "MettlerToledoError", - "evalue": "Command understood but not executable: (incorrect parameter).", - "output_type": "error", - "traceback": [ - "\u001b[31m---------------------------------------------------------------------------\u001b[39m", - "\u001b[31mMettlerToledoError\u001b[39m Traceback (most recent call last)", - "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[15]\u001b[39m\u001b[32m, line 7\u001b[39m\n\u001b[32m 5\u001b[39m \u001b[38;5;66;03m# Temporarily set unit to milligrams (M21 1 0 = mg host unit)\u001b[39;00m\n\u001b[32m 6\u001b[39m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[32m----> \u001b[39m\u001b[32m7\u001b[39m \u001b[38;5;28;01mawait\u001b[39;00m backend.send_command(\u001b[33m\"\u001b[39m\u001b[33mM21 1 0\u001b[39m\u001b[33m\"\u001b[39m)\n\u001b[32m 8\u001b[39m sis_mg = \u001b[38;5;28;01mawait\u001b[39;00m backend.request_net_weight_with_status()\n\u001b[32m 9\u001b[39m \u001b[38;5;28mprint\u001b[39m(\u001b[33mf\u001b[39m\u001b[33m\"\u001b[39m\u001b[33mSIS in milligrams: \u001b[39m\u001b[38;5;132;01m{\u001b[39;00msis_mg.data\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m\"\u001b[39m)\n", - "\u001b[36mFile \u001b[39m\u001b[32m~/Desktop/GitHub/pylabrobot/pylabrobot/scales/mettler_toledo/backend.py:342\u001b[39m, in \u001b[36mMettlerToledoWXS205SDUBackend.send_command\u001b[39m\u001b[34m(self, command, timeout)\u001b[39m\n\u001b[32m 340\u001b[39m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[32m 341\u001b[39m response = MettlerToledoResponse(command=\u001b[33m\"\u001b[39m\u001b[33m\"\u001b[39m, status=\u001b[33m\"\u001b[39m\u001b[33m\"\u001b[39m, data=[])\n\u001b[32m--> \u001b[39m\u001b[32m342\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[43m.\u001b[49m\u001b[43m_parse_basic_errors\u001b[49m\u001b[43m(\u001b[49m\u001b[43mresponse\u001b[49m\u001b[43m)\u001b[49m\n\u001b[32m 343\u001b[39m responses.append(response)\n\u001b[32m 345\u001b[39m \u001b[38;5;66;03m# Status B means more responses follow; anything else (A, etc.) is final\u001b[39;00m\n", - "\u001b[36mFile \u001b[39m\u001b[32m~/Desktop/GitHub/pylabrobot/pylabrobot/scales/mettler_toledo/backend.py:273\u001b[39m, in \u001b[36mMettlerToledoWXS205SDUBackend._parse_basic_errors\u001b[39m\u001b[34m(self, response)\u001b[39m\n\u001b[32m 271\u001b[39m \u001b[38;5;28;01mraise\u001b[39;00m MettlerToledoError.executing_another_command()\n\u001b[32m 272\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m response.status == \u001b[33m\"\u001b[39m\u001b[33mL\u001b[39m\u001b[33m\"\u001b[39m:\n\u001b[32m--> \u001b[39m\u001b[32m273\u001b[39m \u001b[38;5;28;01mraise\u001b[39;00m MettlerToledoError.incorrect_parameter()\n\u001b[32m 274\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m response.status == \u001b[33m\"\u001b[39m\u001b[33m+\u001b[39m\u001b[33m\"\u001b[39m:\n\u001b[32m 275\u001b[39m \u001b[38;5;28;01mraise\u001b[39;00m MettlerToledoError.overload()\n", - "\u001b[31mMettlerToledoError\u001b[39m: Command understood but not executable: (incorrect parameter)." - ] - } - ], + "outputs": [], "source": [ "# Read SIS in grams (current state)\n", "sis_grams = await backend.request_net_weight_with_status()\n", @@ -1722,21 +1585,21 @@ }, { "cell_type": "code", - "execution_count": 16, + "execution_count": 15, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 13:31:46,782 - pylabrobot - IO - [MT Scale] Sent command: Z\n", - "2026-03-30 13:31:46,787 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'Z\\r\\n'\n", - "2026-03-30 13:31:47,177 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'Z A\\r\\n'\n", - "2026-03-30 13:31:47,178 - pylabrobot - IO - [MT Scale] Received response: b'Z A\\r\\n'\n", - "2026-03-30 13:31:47,180 - pylabrobot - IO - [MT Scale] Sent command: SI\n", - "2026-03-30 13:31:47,182 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", - "2026-03-30 13:31:47,225 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 13:31:47,229 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n" + "2026-03-30 13:23:14,769 - pylabrobot - IO - [MT Scale] Sent command: Z\n", + "2026-03-30 13:23:14,772 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'Z\\r\\n'\n", + "2026-03-30 13:23:15,084 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'Z A\\r\\n'\n", + "2026-03-30 13:23:15,085 - pylabrobot - IO - [MT Scale] Received response: b'Z A\\r\\n'\n", + "2026-03-30 13:23:15,087 - pylabrobot - IO - [MT Scale] Sent command: SI\n", + "2026-03-30 13:23:15,091 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", + "2026-03-30 13:23:15,132 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 13:23:15,139 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n" ] }, { @@ -1757,14 +1620,14 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 13:31:47,782 - pylabrobot - IO - [MT Scale] Sent command: T\n", - "2026-03-30 13:31:47,786 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'T\\r\\n'\n", - "2026-03-30 13:31:48,184 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'T S 0.00000 g\\r\\n'\n", - "2026-03-30 13:31:48,185 - pylabrobot - IO - [MT Scale] Received response: b'T S 0.00000 g\\r\\n'\n", - "2026-03-30 13:31:48,186 - pylabrobot - IO - [MT Scale] Sent command: TA\n", - "2026-03-30 13:31:48,188 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'TA\\r\\n'\n", - "2026-03-30 13:31:48,264 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'TA A 0.00000 g\\r\\n'\n", - "2026-03-30 13:31:48,266 - pylabrobot - IO - [MT Scale] Received response: b'TA A 0.00000 g\\r\\n'\n" + "2026-03-30 13:23:16,272 - pylabrobot - IO - [MT Scale] Sent command: T\n", + "2026-03-30 13:23:16,274 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'T\\r\\n'\n", + "2026-03-30 13:23:16,668 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'T S 0.00000 g\\r\\n'\n", + "2026-03-30 13:23:16,669 - pylabrobot - IO - [MT Scale] Received response: b'T S 0.00000 g\\r\\n'\n", + "2026-03-30 13:23:16,671 - pylabrobot - IO - [MT Scale] Sent command: TA\n", + "2026-03-30 13:23:16,672 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'TA\\r\\n'\n", + "2026-03-30 13:23:16,763 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'TA A 0.00000 g\\r\\n'\n", + "2026-03-30 13:23:16,763 - pylabrobot - IO - [MT Scale] Received response: b'TA A 0.00000 g\\r\\n'\n" ] }, { @@ -1781,7 +1644,7 @@ "traceback": [ "\u001b[31m---------------------------------------------------------------------------\u001b[39m", "\u001b[31mAssertionError\u001b[39m Traceback (most recent call last)", - "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[16]\u001b[39m\u001b[32m, line 12\u001b[39m\n\u001b[32m 10\u001b[39m tare = \u001b[38;5;28;01mawait\u001b[39;00m scale.request_tare_weight()\n\u001b[32m 11\u001b[39m \u001b[38;5;28mprint\u001b[39m(\u001b[33mf\u001b[39m\u001b[33m\"\u001b[39m\u001b[33mFrontend tare weight: \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mtare\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m g\u001b[39m\u001b[33m\"\u001b[39m)\n\u001b[32m---> \u001b[39m\u001b[32m12\u001b[39m \u001b[38;5;28;01massert\u001b[39;00m tare > \u001b[32m0\u001b[39m\n\u001b[32m 14\u001b[39m \u001b[38;5;66;03m# Read via frontend\u001b[39;00m\n\u001b[32m 15\u001b[39m w = \u001b[38;5;28;01mawait\u001b[39;00m scale.read_weight(timeout=\u001b[33m\"\u001b[39m\u001b[33mstable\u001b[39m\u001b[33m\"\u001b[39m)\n", + "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[15]\u001b[39m\u001b[32m, line 12\u001b[39m\n\u001b[32m 10\u001b[39m tare = \u001b[38;5;28;01mawait\u001b[39;00m scale.request_tare_weight()\n\u001b[32m 11\u001b[39m \u001b[38;5;28mprint\u001b[39m(\u001b[33mf\u001b[39m\u001b[33m\"\u001b[39m\u001b[33mFrontend tare weight: \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mtare\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m g\u001b[39m\u001b[33m\"\u001b[39m)\n\u001b[32m---> \u001b[39m\u001b[32m12\u001b[39m \u001b[38;5;28;01massert\u001b[39;00m tare > \u001b[32m0\u001b[39m\n\u001b[32m 14\u001b[39m \u001b[38;5;66;03m# Read via frontend\u001b[39;00m\n\u001b[32m 15\u001b[39m w = \u001b[38;5;28;01mawait\u001b[39;00m scale.read_weight(timeout=\u001b[33m\"\u001b[39m\u001b[33mstable\u001b[39m\u001b[33m\"\u001b[39m)\n", "\u001b[31mAssertionError\u001b[39m: " ] } @@ -1808,6 +1671,32 @@ "print(\"PASS: all frontend methods delegate correctly\")" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### I22-I25 - Undocumented information commands\n", + "\n", + "These commands appear in the I0 discovery but are not documented in the MT-SICS spec.\n", + "All I-commands are read-only queries, so these are safe to probe." + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "for cmd in [\"I22\", \"I23\", \"I24\", \"I25\"]:\n", + " try:\n", + " responses = await backend.send_command(cmd)\n", + " for r in responses:\n", + " print(f\"{cmd}: status={r.status} data={r.data}\")\n", + " except Exception as e:\n", + " print(f\"{cmd}: {type(e).__name__}: {e}\")\n", + " print()" + ], + "outputs": [], + "execution_count": null + }, { "cell_type": "markdown", "metadata": {}, @@ -1818,9 +1707,104 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 16, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2026-03-30 13:23:25,471 - pylabrobot - IO - [MT Scale] Sent command: S\n", + "2026-03-30 13:23:25,473 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", + "2026-03-30 13:23:25,508 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00001 g\\r\\n'\n", + "2026-03-30 13:23:25,509 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00001 g\\r\\n'\n", + "2026-03-30 13:23:25,509 - pylabrobot - IO - [MT Scale] Sent command: S\n", + "2026-03-30 13:23:25,511 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", + "2026-03-30 13:23:25,604 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00001 g\\r\\n'\n", + "2026-03-30 13:23:25,605 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00001 g\\r\\n'\n", + "2026-03-30 13:23:25,605 - pylabrobot - IO - [MT Scale] Sent command: S\n", + "2026-03-30 13:23:25,606 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", + "2026-03-30 13:23:25,699 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00001 g\\r\\n'\n", + "2026-03-30 13:23:25,700 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00001 g\\r\\n'\n", + "2026-03-30 13:23:25,700 - pylabrobot - IO - [MT Scale] Sent command: S\n", + "2026-03-30 13:23:25,701 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", + "2026-03-30 13:23:25,811 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00001 g\\r\\n'\n", + "2026-03-30 13:23:25,812 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00001 g\\r\\n'\n", + "2026-03-30 13:23:25,813 - pylabrobot - IO - [MT Scale] Sent command: S\n", + "2026-03-30 13:23:25,815 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", + "2026-03-30 13:23:25,908 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00001 g\\r\\n'\n", + "2026-03-30 13:23:25,908 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00001 g\\r\\n'\n", + "2026-03-30 13:23:25,909 - pylabrobot - IO - [MT Scale] Sent command: S\n", + "2026-03-30 13:23:25,910 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", + "2026-03-30 13:23:26,004 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00001 g\\r\\n'\n", + "2026-03-30 13:23:26,004 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00001 g\\r\\n'\n", + "2026-03-30 13:23:26,005 - pylabrobot - IO - [MT Scale] Sent command: S\n", + "2026-03-30 13:23:26,006 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", + "2026-03-30 13:23:26,099 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00001 g\\r\\n'\n", + "2026-03-30 13:23:26,100 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00001 g\\r\\n'\n", + "2026-03-30 13:23:26,100 - pylabrobot - IO - [MT Scale] Sent command: S\n", + "2026-03-30 13:23:26,101 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", + "2026-03-30 13:23:26,195 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00001 g\\r\\n'\n", + "2026-03-30 13:23:26,196 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00001 g\\r\\n'\n", + "2026-03-30 13:23:26,196 - pylabrobot - IO - [MT Scale] Sent command: S\n", + "2026-03-30 13:23:26,197 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", + "2026-03-30 13:23:26,291 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00001 g\\r\\n'\n", + "2026-03-30 13:23:26,292 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00001 g\\r\\n'\n", + "2026-03-30 13:23:26,293 - pylabrobot - IO - [MT Scale] Sent command: S\n", + "2026-03-30 13:23:26,293 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", + "2026-03-30 13:23:26,388 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00001 g\\r\\n'\n", + "2026-03-30 13:23:26,388 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00001 g\\r\\n'\n", + "2026-03-30 13:23:26,389 - pylabrobot - IO - [MT Scale] Sent command: SI\n", + "2026-03-30 13:23:26,390 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", + "2026-03-30 13:23:26,435 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00001 g\\r\\n'\n", + "2026-03-30 13:23:26,436 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00001 g\\r\\n'\n", + "2026-03-30 13:23:26,437 - pylabrobot - IO - [MT Scale] Sent command: SI\n", + "2026-03-30 13:23:26,445 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", + "2026-03-30 13:23:26,483 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00001 g\\r\\n'\n", + "2026-03-30 13:23:26,485 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00001 g\\r\\n'\n", + "2026-03-30 13:23:26,487 - pylabrobot - IO - [MT Scale] Sent command: SI\n", + "2026-03-30 13:23:26,488 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", + "2026-03-30 13:23:26,531 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00001 g\\r\\n'\n", + "2026-03-30 13:23:26,532 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00001 g\\r\\n'\n", + "2026-03-30 13:23:26,533 - pylabrobot - IO - [MT Scale] Sent command: SI\n", + "2026-03-30 13:23:26,535 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", + "2026-03-30 13:23:26,563 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00001 g\\r\\n'\n", + "2026-03-30 13:23:26,564 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00001 g\\r\\n'\n", + "2026-03-30 13:23:26,566 - pylabrobot - IO - [MT Scale] Sent command: SI\n", + "2026-03-30 13:23:26,568 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", + "2026-03-30 13:23:26,611 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00001 g\\r\\n'\n", + "2026-03-30 13:23:26,614 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00001 g\\r\\n'\n", + "2026-03-30 13:23:26,617 - pylabrobot - IO - [MT Scale] Sent command: SI\n", + "2026-03-30 13:23:26,619 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", + "2026-03-30 13:23:26,659 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00001 g\\r\\n'\n", + "2026-03-30 13:23:26,661 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00001 g\\r\\n'\n", + "2026-03-30 13:23:26,664 - pylabrobot - IO - [MT Scale] Sent command: SI\n", + "2026-03-30 13:23:26,665 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", + "2026-03-30 13:23:26,708 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00001 g\\r\\n'\n", + "2026-03-30 13:23:26,709 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00001 g\\r\\n'\n", + "2026-03-30 13:23:26,711 - pylabrobot - IO - [MT Scale] Sent command: SI\n", + "2026-03-30 13:23:26,717 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", + "2026-03-30 13:23:26,755 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00001 g\\r\\n'\n", + "2026-03-30 13:23:26,757 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00001 g\\r\\n'\n", + "2026-03-30 13:23:26,758 - pylabrobot - IO - [MT Scale] Sent command: SI\n", + "2026-03-30 13:23:26,759 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", + "2026-03-30 13:23:26,806 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00001 g\\r\\n'\n", + "2026-03-30 13:23:26,807 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00001 g\\r\\n'\n", + "2026-03-30 13:23:26,808 - pylabrobot - IO - [MT Scale] Sent command: SI\n", + "2026-03-30 13:23:26,811 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", + "2026-03-30 13:23:26,851 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00001 g\\r\\n'\n", + "2026-03-30 13:23:26,852 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00001 g\\r\\n'\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Stable read: 91.79 +/- 18.42 ms\n", + "Immediate read: 46.44 +/- 4.92 ms\n" + ] + } + ], "source": [ "import time\n", "\n", @@ -1856,9 +1840,30 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 17, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2026-03-30 13:23:31,221 - pylabrobot - INFO - === Hardware validation ended ===\n", + "2026-03-30 13:23:31,225 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] reset_input_buffer\n", + "2026-03-30 13:23:31,230 - pylabrobot - IO - [MT Scale] Sent command: @\n", + "2026-03-30 13:23:31,234 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'@\\r\\n'\n", + "2026-03-30 13:23:31,297 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I4 A \"B207696838\"\\r\\n'\n", + "2026-03-30 13:23:31,300 - pylabrobot - IO - [MT Scale] Received response: b'I4 A \"B207696838\"\\r\\n'\n", + "2026-03-30 13:23:31,302 - pylabrobot - INFO - [MT Scale] Disconnected from /dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Log file: ./logs/hardware_validation/2026-03-30_13-22-09_validation.log\n" + ] + } + ], "source": [ "plr_logger.info(\"=== Hardware validation ended ===\")\n", "await scale.stop()\n", @@ -1894,4 +1899,4 @@ }, "nbformat": 4, "nbformat_minor": 4 -} +} \ No newline at end of file diff --git a/pylabrobot/scales/mettler_toledo/mt_sics_commands.md b/pylabrobot/scales/mettler_toledo/mt_sics_commands.md index 56ec1b8f1e2..d7304bce550 100644 --- a/pylabrobot/scales/mettler_toledo/mt_sics_commands.md +++ b/pylabrobot/scales/mettler_toledo/mt_sics_commands.md @@ -26,11 +26,11 @@ Status key: | Command | Description | Spec Page | Status | WXS205SDU | Notes | |---------|------------------------------------------|-----------|--------|-----------|-------| -| @ | Cancel / reset to determined state | 16 | DONE | yes | cancel(). Sent during setup(). Response is I4-style. | +| @ | Reset device to determined state | 16 | DONE | yes | reset(). Sent during setup(). Response is I4-style. | | I0 | List all implemented commands + levels | 96 | DONE | yes | _request_supported_commands(). Queried during setup(). | | I1 | MT-SICS level and level versions | 97 | DONE | yes | Not used for gating - I0 is authoritative. | | I2 | Device data (type and capacity) | 98 | DONE | yes | request_device_type() and request_capacity(). Response is one quoted string parsed with shlex. | -| I3 | Software version and type definition | 99 | DONE | yes | request_software_version(). Returns "1.10 18.6.4.1361.772" on test device. | +| I3 | Firmware version and type definition | 99 | DONE | yes | request_firmware_version(). Returns "1.10 18.6.4.1361.772" on test device. | | I4 | Serial number | 100 | DONE | yes | request_serial_number(). | | I5 | Software material number | 101 | DONE | yes | request_software_material_number(). Returns "11671158C" on test device. | | S | Stable weight value | 223 | DONE | yes | read_stable_weight(). | @@ -66,9 +66,9 @@ Status key: | I10 | Device identification | 102 | DONE | yes | request_device_id() (read). set_device_id() commented out (EEPROM write). | | I11 | Model designation | 103 | DONE | yes | request_model_designation(). Returns "WXS205SDU" on test device. | | I14 | Device information (detailed) | 104 | DONE | yes | request_device_info(). Multi-response with config, descriptions, SW IDs, serial numbers. | -| I15 | Uptime | 106 | DONE | yes | request_uptime(). WXS205SDU returns single value (days), not days/h/m/s. | -| I16 | Date of next service | 107 | LOW | yes | | -| I21 | Revision of assortment type tolerances | 108 | LOW | yes | | +| I15 | Uptime in minutes since start/restart | 106 | DONE | yes | request_uptime_minutes(). Returns minutes, accuracy +/- 5%. | +| I16 | Date of next service | 107 | DONE | yes | request_next_service_date(). | +| I21 | Revision of assortment type tolerances | 108 | DONE | yes | request_assortment_type_revision(). | | I29 | Filter configuration | 111 | LOW | - | | | I32 | Voltage monitoring | 112 | MED | - | | | I43 | Selectable units for host unit | 113 | LOW | - | | @@ -113,22 +113,22 @@ Status key: | M21 | Unit (host/display) | 165 | DONE | yes | set_host_unit_grams(). | | M23 | Readability (1d/xd) | 169 | LOW | - | | | M28 | Temperature value | 172 | DONE | yes | measure_temperature(). Returns 19.8-19.9 C on test device. | -| M35 | Zeroing mode at startup | 178 | LOW | yes | | +| M35 | Zeroing mode at startup | 178 | DONE | yes | request_zeroing_mode() (read). set commented out (persists to memory). | | M49 | Permanent tare mode | 188 | LOW | - | | | M67 | Timeout | 191 | LOW | - | | | M68 | Behavior of serial interfaces | 192 | LOW | - | | -| COM | Serial interface parameters | 46 | LOW | yes | Baud rate, parity, etc. | +| COM | Serial interface parameters | 46 | DONE | yes | request_serial_parameters(). set commented out (persists to memory). | | ECHO | Echo mode | 66 | LOW | - | | -| LST | Current user settings | 156 | LOW | yes | Level 3 on WXS205SDU. | +| LST | Current user settings | 156 | DONE | yes | request_user_settings(). Level 3 on WXS205SDU. | | PROT | Protocol mode | 220 | LOW | - | | ### Adjustment / Calibration | Command | Description | Spec Page | Status | WXS205SDU | Notes | |---------|------------------------------------------|-----------|--------|-----------|-------| -| C0 | Adjustment setting | 24 | LOW | yes | | +| C0 | Adjustment setting | 24 | DONE | yes | request_adjustment_setting() (read). set commented out (persists to memory). | | C1 | Start adjustment (current settings) | 26 | STUB | yes | Commented out (moves internal weights). Multi-response. | -| C2 | Start adjustment (external weight) | 28 | LOW | yes | | +| C2 | Start adjustment (external weight) | 28 | STUB | yes | Commented out (requires placing external weight). | | C3 | Start adjustment (built-in weight) | 30 | STUB | yes | Commented out (moves internal weights). Multi-response. | | C4 | Standard / initial adjustment | 31 | LOW | - | | | C5 | Enable/disable step control | 33 | LOW | - | | @@ -136,17 +136,17 @@ Status key: | C7 | Customer standard calibration | 37 | LOW | - | | | C8 | Sensitivity adjustment | 40 | LOW | - | | | C9 | Scale placement sensitivity adjustment | 43 | LOW | - | | -| M19 | Adjustment weight | 163 | LOW | yes | | +| M19 | Adjustment weight | 163 | DONE | yes | request_adjustment_weight() (read). set commented out (persists to memory). | | M27 | Adjustment history | 171 | DONE | yes | request_adjustment_history(). Multi-response. | ### Testing | Command | Description | Spec Page | Status | WXS205SDU | Notes | |---------|------------------------------------------|-----------|--------|-----------|-------| -| TST0 | Query/set test function settings | 259 | LOW | yes | | -| TST1 | Test according to current settings | 260 | LOW | yes | | -| TST2 | Test with external weight | 262 | LOW | yes | | -| TST3 | Test with built-in weight | 264 | LOW | yes | | +| TST0 | Query/set test function settings | 259 | DONE | yes | request_test_settings() (read). set commented out (persists to memory). | +| TST1 | Test according to current settings | 260 | STUB | yes | Commented out (moves internal weights). | +| TST2 | Test with external weight | 262 | STUB | yes | Commented out (requires placing test weight). | +| TST3 | Test with built-in weight | 264 | STUB | yes | Commented out (moves internal weights). | | TST5 | Module test with built-in weights | 265 | LOW | - | | ### Weight Variants (alternative read commands) @@ -159,7 +159,7 @@ Status key: | SIU | Weight in display unit immediately | 237 | LOW | - | | | SIUM | Weight + MinWeigh info immediately | 238 | LOW | - | | | SIX1 | Current gross, net, and tare values | 239 | HIGH | - | Not on WXS205SDU. | -| SNR | Stable weight + repeat on stable change | 241 | DONE | yes | read_stable_weight_repeat_on_change(). Use cancel() to stop. | +| SNR | Stable weight + repeat on stable change | 241 | DONE | yes | read_stable_weight_repeat_on_change(). Use reset() to stop. | | ST | Stable weight on Transfer key press | 249 | N/A | - | Manual operation. | | SU | Stable weight in display unit | 250 | LOW | - | | | SUM | Stable weight + MinWeigh info | 251 | LOW | - | | @@ -200,9 +200,9 @@ Status key: | E03 | Current system errors and warnings | 65 | HIGH | - | Not on WXS205SDU. | | FSET | Reset all settings to factory defaults | 95 | LOW | yes | Level 3 on WXS205SDU. Destructive. | | RO1 | Restart device | 221 | MED | - | | -| RDB | Readability | 222 | LOW | yes | Level 3 on WXS205SDU. | +| RDB | Readability | 222 | DONE | yes | request_readability(). Level 3 on WXS205SDU. | | UPD | Update rate for SIR/SIRU | 267 | DONE | yes | request_update_rate() (read). set commented out (persists to memory). | -| USTB | User defined stability criteria | 268 | LOW | yes | Level 3 on WXS205SDU. | +| USTB | User defined stability criteria | 268 | DONE | yes | request_stability_criteria() (read). set commented out. Level 3 on WXS205SDU. | ### Network (not relevant for serial) @@ -233,15 +233,15 @@ Status key: | CW03 | Triggered weight value | 50 | N/A | - | | | CW11 | Check weighing: weight calculation mode | 51 | N/A | - | | | F01-F16 | Filling functions (16 commands) | 69-91 | N/A | - | Filling/dosing application. | -| FCUT | Filter cut-off frequency | 92 | N/A | yes | Level 3 on WXS205SDU. | +| FCUT | Filter cut-off frequency | 92 | DONE | yes | request_filter_cutoff() (read). set commented out. Level 3 on WXS205SDU. | | FCUT2 | Alt weight path cut-off frequency | 93 | N/A | - | | | WMCF | Weight monitoring functions | 270 | N/A | - | | -| M17 | ProFACT: Single time criteria | 160 | N/A | yes | Level 2 on WXS205SDU. | -| M18 | ProFACT/FACT: Temperature criterion | 162 | N/A | yes | Level 2 on WXS205SDU. | +| M17 | ProFACT: Single time criteria | 160 | DONE | yes | request_profact_time_criteria() (read). set commented out. Level 2 on WXS205SDU. | +| M18 | ProFACT/FACT: Temperature criterion | 162 | DONE | yes | request_profact_temperature_criterion() (read). set commented out. Level 2 on WXS205SDU. | | M22 | Custom unit definitions | 168 | N/A | - | | -| M31 | Operating mode after restart | 174 | N/A | yes | Level 2 on WXS205SDU. | -| M32 | ProFACT: Time criteria | 175 | N/A | yes | Level 2 on WXS205SDU. | -| M33 | ProFACT: Day of the week | 176 | N/A | yes | Level 2 on WXS205SDU. | +| M31 | Operating mode after restart | 174 | DONE | yes | request_operating_mode() (read). set commented out. Level 2 on WXS205SDU. | +| M32 | ProFACT: Time criteria | 175 | DONE | yes | request_profact_time() (read). set commented out. Level 2 on WXS205SDU. | +| M33 | ProFACT: Day of the week | 176 | DONE | yes | request_profact_day() (read). set commented out. Level 2 on WXS205SDU. | | M34 | MinWeigh: Method | 177 | N/A | - | | | M38 | Selective parameter reset | 179 | N/A | - | | | M39 | SmartTrac: Graphic | 180 | N/A | - | | @@ -264,11 +264,15 @@ Status key: ## Priority Summary -### HIGH (should implement next) -- E01/E02/E03 (error monitoring) - not available on WXS205SDU -- SIX1 (gross, net, tare in one call) - not available on WXS205SDU +### HIGH (not available on WXS205SDU) +- E01/E02/E03 (error monitoring) +- SIX1 (gross, net, tare in one call) ### MED (useful but not urgent) - SIR/SR (continuous streaming) - needs async iterator architecture -- C1/C3 (adjustment) - commented out, needs physical interaction - DATI (date + time combined) - not on WXS205SDU + +### STUB (commented out, require physical interaction) +- C1/C3 (internal weight adjustment) +- C2 (external weight adjustment) +- TST1-TST3 (test procedures) diff --git a/pylabrobot/scales/mettler_toledo/protocol.md b/pylabrobot/scales/mettler_toledo/protocol.md index b7a19772c8d..eedf3cad21e 100644 --- a/pylabrobot/scales/mettler_toledo/protocol.md +++ b/pylabrobot/scales/mettler_toledo/protocol.md @@ -101,14 +101,14 @@ Device sends: C B\r\n -- cancel started ## Exceptions to the standard format -### @ (cancel) response echoes I4, not @ +### @ (reset) response echoes I4, not @ ``` PLR sends: @\r\n Device sends: I4 A "B207696838"\r\n ``` -The @ command resets the device and responds with the serial number using the I4 response format, not the @ command name. +The @ command resets the device to its power-on state and responds with the serial number using the I4 response format, not the @ command name. ### Commands not supported on WXS205SDU (bridge mode) @@ -130,10 +130,10 @@ The device type can contain spaces. Parse from the right: unit is the last token, capacity is second-to-last, type is everything before. `shlex.split` is used to handle quoted strings correctly. -### I15 uptime format varies +### I15 uptime is in minutes -Some devices return `I15 A ` (4 values). -The WXS205SDU returns `I15 A ` (single value). The parser handles both. +I15 returns uptime in minutes since last start or restart, with +/- 5% accuracy. +Response: `I15 A `. Example: `I15 A 123014` = ~85 days. ## Command discovery @@ -154,7 +154,7 @@ the authoritative list of implemented commands. | Level | Description | Availability | |-------|-------------|-------------| -| 0 | Basic set: identification, weighing, zero, tare, cancel | Always available | +| 0 | Basic set: identification, weighing, zero, tare, reset (@) | Always available | | 1 | Elementary: tare memory, timed commands, repeat | Always available | | 2 | Extended: configuration, device info, diagnostics | Model-dependent | | 3 | Application-specific: filling, dosing, calibration | Model-dependent | @@ -162,7 +162,7 @@ the authoritative list of implemented commands. ## Write safety Commands that modify device settings (M01 set, M02 set, M03 set, etc.) persist -to memory and survive power cycles. They cannot be undone with @ cancel - only +to memory and survive power cycles. They cannot be undone with @ reset - only via FSET (factory reset) or the terminal menu. Write methods are commented out in the backend to prevent accidental modification. diff --git a/pylabrobot/scales/mettler_toledo/simulator.py b/pylabrobot/scales/mettler_toledo/simulator.py index 8d4e659f325..58e9af6af84 100644 --- a/pylabrobot/scales/mettler_toledo/simulator.py +++ b/pylabrobot/scales/mettler_toledo/simulator.py @@ -136,7 +136,7 @@ async def setup(self) -> None: async def stop(self) -> None: logger.info("[MT Scale] Disconnected (simulation)") - async def cancel(self) -> str: + async def reset(self) -> str: responses = await self.send_command("@") self._validate_response(responses[0], 3, "@") return responses[0].data[0] @@ -175,7 +175,7 @@ def _build_response(self, command: str) -> List[MettlerToledoResponse]: if cmd == "I4": return [R("I4", "A", [self._simulated_serial_number])] if cmd == "I3": - return [R("I3", "A", ["2.10 10.28.0.493.142"])] + return [R("I3", "A", [self.firmware_version])] if cmd == "I5": return [R("I5", "A", ["12121306C"])] if cmd == "I10": @@ -192,7 +192,7 @@ def _build_response(self, command: str) -> List[MettlerToledoResponse]: R("I14", "A", ["1", "1", self._simulated_device_type]), ] if cmd == "I15": - return [R("I15", "A", ["42", "3", "15", "30"])] + return [R("I15", "A", ["1440"])] # 1440 minutes = 24 hours if cmd == "DAT": return [R("DAT", "A", ["30.03.2026"])] if cmd == "TIM": @@ -211,7 +211,10 @@ def _build_response(self, command: str) -> List[MettlerToledoResponse]: R("M27", "A", ["2", "15", "3", "2026", "10", "30", "1", "200.1234 g"]), ] if cmd == "SIS": - return [R("SIS", "S", [f"{net:.5f}", "g", "S"])] + # State, NetWeight, Unit(0=g), Readability, Step, Approval, Info(0=no tare, 1=weighed tare) + state = "0" # stable + info = "0" if self.tare_weight == 0 else "1" + return [R("SIS", "A", [state, f"{net:.5f}", "0", "5", "1", "0", info])] if cmd == "SNR": return [R("SNR", "S", [f"{net:.5f}", "g"])] if cmd == "UPD": diff --git a/pylabrobot/scales/scale_backend.py b/pylabrobot/scales/scale_backend.py index 6e8caea4fdf..46b844e71f2 100644 --- a/pylabrobot/scales/scale_backend.py +++ b/pylabrobot/scales/scale_backend.py @@ -9,10 +9,14 @@ class ScaleBackend(MachineBackend, metaclass=ABCMeta): """Backend for a scale""" @abstractmethod - async def zero(self) -> None: ... + async def zero(self) -> None: + """Zero the scale.""" + ... @abstractmethod - async def tare(self) -> None: ... + async def tare(self) -> None: + """Tare the scale.""" + ... @abstractmethod async def read_weight(self) -> float: From 4337254ae99f2184588e2d1f30672d2e0b69d032 Mon Sep 17 00:00:00 2001 From: Camillo Moschner Date: Mon, 30 Mar 2026 16:24:36 +0100 Subject: [PATCH 30/38] request_uptime error --- .../mettler_toledo/hardware_validation.ipynb | 1576 +++++------------ 1 file changed, 469 insertions(+), 1107 deletions(-) diff --git a/pylabrobot/scales/mettler_toledo/hardware_validation.ipynb b/pylabrobot/scales/mettler_toledo/hardware_validation.ipynb index 385f1351e95..f1d37766ed5 100644 --- a/pylabrobot/scales/mettler_toledo/hardware_validation.ipynb +++ b/pylabrobot/scales/mettler_toledo/hardware_validation.ipynb @@ -33,7 +33,7 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 13:22:09,309 - pylabrobot - INFO - === Hardware validation started ===\n" + "2026-03-30 16:23:59,420 - pylabrobot - INFO - === Hardware validation started ===\n" ] } ], @@ -65,161 +65,161 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 13:22:09,329 - pylabrobot.io.serial - INFO - Using explicitly provided port: /dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0 (for VID=1027, PID=24577)\n", - "2026-03-30 13:22:09,336 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] reset_input_buffer\n", - "2026-03-30 13:22:09,337 - pylabrobot - IO - [MT Scale] Sent command: @\n", - "2026-03-30 13:22:09,340 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'@\\r\\n'\n", - "2026-03-30 13:22:09,400 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I4 A \"B207696838\"\\r\\n'\n", - "2026-03-30 13:22:09,402 - pylabrobot - IO - [MT Scale] Received response: b'I4 A \"B207696838\"\\r\\n'\n", - "2026-03-30 13:22:09,405 - pylabrobot - IO - [MT Scale] Sent command: I0\n", - "2026-03-30 13:22:09,406 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I0\\r\\n'\n", - "2026-03-30 13:22:09,445 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I0\"\\r\\n'\n", - "2026-03-30 13:22:09,447 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I0\"\\r\\n'\n", - "2026-03-30 13:22:09,452 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I1\"\\r\\n'\n", - "2026-03-30 13:22:09,453 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I1\"\\r\\n'\n", - "2026-03-30 13:22:09,462 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I2\"\\r\\n'\n", - "2026-03-30 13:22:09,464 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I2\"\\r\\n'\n", - "2026-03-30 13:22:09,478 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I3\"\\r\\n'\n", - "2026-03-30 13:22:09,480 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I3\"\\r\\n'\n", - "2026-03-30 13:22:09,497 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I4\"\\r\\n'\n", - "2026-03-30 13:22:09,499 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I4\"\\r\\n'\n", - "2026-03-30 13:22:09,510 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I5\"\\r\\n'\n", - "2026-03-30 13:22:09,511 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I5\"\\r\\n'\n", - "2026-03-30 13:22:09,526 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"S\"\\r\\n'\n", - "2026-03-30 13:22:09,528 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"S\"\\r\\n'\n", - "2026-03-30 13:22:09,531 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"SI\"\\r\\n'\n", - "2026-03-30 13:22:09,532 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"SI\"\\r\\n'\n", - "2026-03-30 13:22:09,544 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"SIR\"\\r\\n'\n", - "2026-03-30 13:22:09,545 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"SIR\"\\r\\n'\n", - "2026-03-30 13:22:09,560 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"Z\"\\r\\n'\n", - "2026-03-30 13:22:09,562 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"Z\"\\r\\n'\n", - "2026-03-30 13:22:09,574 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"ZI\"\\r\\n'\n", - "2026-03-30 13:22:09,578 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"ZI\"\\r\\n'\n", - "2026-03-30 13:22:09,589 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"@\"\\r\\n'\n", - "2026-03-30 13:22:09,594 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"@\"\\r\\n'\n", - "2026-03-30 13:22:09,609 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"SR\"\\r\\n'\n", - "2026-03-30 13:22:09,611 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"SR\"\\r\\n'\n", - "2026-03-30 13:22:09,614 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"T\"\\r\\n'\n", - "2026-03-30 13:22:09,615 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"T\"\\r\\n'\n", - "2026-03-30 13:22:09,621 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"TA\"\\r\\n'\n", - "2026-03-30 13:22:09,622 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"TA\"\\r\\n'\n", - "2026-03-30 13:22:09,638 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"TAC\"\\r\\n'\n", - "2026-03-30 13:22:09,642 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"TAC\"\\r\\n'\n", - "2026-03-30 13:22:09,653 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"TI\"\\r\\n'\n", - "2026-03-30 13:22:09,654 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"TI\"\\r\\n'\n", - "2026-03-30 13:22:09,673 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C0\"\\r\\n'\n", - "2026-03-30 13:22:09,674 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"C0\"\\r\\n'\n", - "2026-03-30 13:22:09,686 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C1\"\\r\\n'\n", - "2026-03-30 13:22:09,687 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"C1\"\\r\\n'\n", - "2026-03-30 13:22:09,702 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C2\"\\r\\n'\n", - "2026-03-30 13:22:09,709 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"C2\"\\r\\n'\n", - "2026-03-30 13:22:09,713 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C3\"\\r\\n'\n", - "2026-03-30 13:22:09,714 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"C3\"\\r\\n'\n", - "2026-03-30 13:22:09,718 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"COM\"\\r\\n'\n", - "2026-03-30 13:22:09,720 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"COM\"\\r\\n'\n", - "2026-03-30 13:22:09,734 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"DAT\"\\r\\n'\n", - "2026-03-30 13:22:09,735 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"DAT\"\\r\\n'\n", - "2026-03-30 13:22:09,751 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I10\"\\r\\n'\n", - "2026-03-30 13:22:09,753 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I10\"\\r\\n'\n", - "2026-03-30 13:22:09,769 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I11\"\\r\\n'\n", - "2026-03-30 13:22:09,771 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I11\"\\r\\n'\n", - "2026-03-30 13:22:09,782 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I14\"\\r\\n'\n", - "2026-03-30 13:22:09,783 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I14\"\\r\\n'\n", - "2026-03-30 13:22:09,797 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I15\"\\r\\n'\n", - "2026-03-30 13:22:09,798 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I15\"\\r\\n'\n", - "2026-03-30 13:22:09,814 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I16\"\\r\\n'\n", - "2026-03-30 13:22:09,816 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I16\"\\r\\n'\n", - "2026-03-30 13:22:09,830 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I21\"\\r\\n'\n", - "2026-03-30 13:22:09,832 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I21\"\\r\\n'\n", - "2026-03-30 13:22:09,845 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I22\"\\r\\n'\n", - "2026-03-30 13:22:09,846 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I22\"\\r\\n'\n", - "2026-03-30 13:22:09,861 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I23\"\\r\\n'\n", - "2026-03-30 13:22:09,863 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I23\"\\r\\n'\n", - "2026-03-30 13:22:09,867 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I24\"\\r\\n'\n", - "2026-03-30 13:22:09,872 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I24\"\\r\\n'\n", - "2026-03-30 13:22:09,877 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I25\"\\r\\n'\n", - "2026-03-30 13:22:09,878 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I25\"\\r\\n'\n", - "2026-03-30 13:22:09,893 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I26\"\\r\\n'\n", - "2026-03-30 13:22:09,894 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I26\"\\r\\n'\n", - "2026-03-30 13:22:09,909 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M01\"\\r\\n'\n", - "2026-03-30 13:22:09,910 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M01\"\\r\\n'\n", - "2026-03-30 13:22:09,925 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M02\"\\r\\n'\n", - "2026-03-30 13:22:09,926 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M02\"\\r\\n'\n", - "2026-03-30 13:22:09,945 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M03\"\\r\\n'\n", - "2026-03-30 13:22:09,946 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M03\"\\r\\n'\n", - "2026-03-30 13:22:09,957 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M17\"\\r\\n'\n", - "2026-03-30 13:22:09,958 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M17\"\\r\\n'\n", - "2026-03-30 13:22:09,973 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M18\"\\r\\n'\n", - "2026-03-30 13:22:09,975 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M18\"\\r\\n'\n", - "2026-03-30 13:22:09,989 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M19\"\\r\\n'\n", - "2026-03-30 13:22:09,989 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M19\"\\r\\n'\n", - "2026-03-30 13:22:10,006 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M20\"\\r\\n'\n", - "2026-03-30 13:22:10,007 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M20\"\\r\\n'\n", - "2026-03-30 13:22:10,021 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M21\"\\r\\n'\n", - "2026-03-30 13:22:10,021 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M21\"\\r\\n'\n", - "2026-03-30 13:22:10,037 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M27\"\\r\\n'\n", - "2026-03-30 13:22:10,038 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M27\"\\r\\n'\n", - "2026-03-30 13:22:10,041 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M28\"\\r\\n'\n", - "2026-03-30 13:22:10,042 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M28\"\\r\\n'\n", - "2026-03-30 13:22:10,053 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M29\"\\r\\n'\n", - "2026-03-30 13:22:10,054 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M29\"\\r\\n'\n", - "2026-03-30 13:22:10,069 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M31\"\\r\\n'\n", - "2026-03-30 13:22:10,069 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M31\"\\r\\n'\n", - "2026-03-30 13:22:10,085 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M32\"\\r\\n'\n", - "2026-03-30 13:22:10,087 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M32\"\\r\\n'\n", - "2026-03-30 13:22:10,101 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M33\"\\r\\n'\n", - "2026-03-30 13:22:10,101 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M33\"\\r\\n'\n", - "2026-03-30 13:22:10,117 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M35\"\\r\\n'\n", - "2026-03-30 13:22:10,118 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M35\"\\r\\n'\n", - "2026-03-30 13:22:10,134 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"SIS\"\\r\\n'\n", - "2026-03-30 13:22:10,136 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"SIS\"\\r\\n'\n", - "2026-03-30 13:22:10,149 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"SNR\"\\r\\n'\n", - "2026-03-30 13:22:10,154 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"SNR\"\\r\\n'\n", - "2026-03-30 13:22:10,169 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TIM\"\\r\\n'\n", - "2026-03-30 13:22:10,170 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TIM\"\\r\\n'\n", - "2026-03-30 13:22:10,180 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST0\"\\r\\n'\n", - "2026-03-30 13:22:10,182 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TST0\"\\r\\n'\n", - "2026-03-30 13:22:10,197 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST1\"\\r\\n'\n", - "2026-03-30 13:22:10,198 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TST1\"\\r\\n'\n", - "2026-03-30 13:22:10,213 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST2\"\\r\\n'\n", - "2026-03-30 13:22:10,217 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TST2\"\\r\\n'\n", - "2026-03-30 13:22:10,229 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST3\"\\r\\n'\n", - "2026-03-30 13:22:10,230 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TST3\"\\r\\n'\n", - "2026-03-30 13:22:10,245 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"UPD\"\\r\\n'\n", - "2026-03-30 13:22:10,246 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"UPD\"\\r\\n'\n", - "2026-03-30 13:22:10,248 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"FCUT\"\\r\\n'\n", - "2026-03-30 13:22:10,249 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 3 \"FCUT\"\\r\\n'\n", - "2026-03-30 13:22:10,261 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"FSET\"\\r\\n'\n", - "2026-03-30 13:22:10,261 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 3 \"FSET\"\\r\\n'\n", - "2026-03-30 13:22:10,279 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"LST\"\\r\\n'\n", - "2026-03-30 13:22:10,280 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 3 \"LST\"\\r\\n'\n", - "2026-03-30 13:22:10,292 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"RDB\"\\r\\n'\n", - "2026-03-30 13:22:10,293 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 3 \"RDB\"\\r\\n'\n", - "2026-03-30 13:22:10,309 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 A 3 \"USTB\"\\r\\n'\n", - "2026-03-30 13:22:10,311 - pylabrobot - IO - [MT Scale] Received response: b'I0 A 3 \"USTB\"\\r\\n'\n", - "2026-03-30 13:22:10,314 - pylabrobot - IO - [MT Scale] Sent command: I2\n", - "2026-03-30 13:22:10,317 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I2\\r\\n'\n", - "2026-03-30 13:22:10,373 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", - "2026-03-30 13:22:10,374 - pylabrobot - IO - [MT Scale] Received response: b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", - "2026-03-30 13:22:10,385 - pylabrobot - IO - [MT Scale] Sent command: I2\n", - "2026-03-30 13:22:10,387 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I2\\r\\n'\n", - "2026-03-30 13:22:10,453 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", - "2026-03-30 13:22:10,455 - pylabrobot - IO - [MT Scale] Received response: b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", - "2026-03-30 13:22:10,457 - pylabrobot - IO - [MT Scale] Sent command: I3\n", - "2026-03-30 13:22:10,464 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I3\\r\\n'\n", - "2026-03-30 13:22:10,516 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I3 A \"1.10 18.6.4.1361.772\"\\r\\n'\n", - "2026-03-30 13:22:10,518 - pylabrobot - IO - [MT Scale] Received response: b'I3 A \"1.10 18.6.4.1361.772\"\\r\\n'\n", - "2026-03-30 13:22:10,521 - pylabrobot - INFO - [MT Scale] Connected to Mettler Toledo scale on /dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0\n", + "2026-03-30 16:23:59,448 - pylabrobot.io.serial - INFO - Using explicitly provided port: /dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0 (for VID=1027, PID=24577)\n", + "2026-03-30 16:23:59,460 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] reset_input_buffer\n", + "2026-03-30 16:23:59,462 - pylabrobot - IO - [MT Scale] Sent command: @\n", + "2026-03-30 16:23:59,465 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'@\\r\\n'\n", + "2026-03-30 16:23:59,520 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I4 A \"B207696838\"\\r\\n'\n", + "2026-03-30 16:23:59,521 - pylabrobot - IO - [MT Scale] Received response: b'I4 A \"B207696838\"\\r\\n'\n", + "2026-03-30 16:23:59,522 - pylabrobot - IO - [MT Scale] Sent command: I0\n", + "2026-03-30 16:23:59,523 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I0\\r\\n'\n", + "2026-03-30 16:23:59,552 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I0\"\\r\\n'\n", + "2026-03-30 16:23:59,552 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I0\"\\r\\n'\n", + "2026-03-30 16:23:59,568 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I1\"\\r\\n'\n", + "2026-03-30 16:23:59,569 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I1\"\\r\\n'\n", + "2026-03-30 16:23:59,584 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I2\"\\r\\n'\n", + "2026-03-30 16:23:59,585 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I2\"\\r\\n'\n", + "2026-03-30 16:23:59,599 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I3\"\\r\\n'\n", + "2026-03-30 16:23:59,600 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I3\"\\r\\n'\n", + "2026-03-30 16:23:59,616 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I4\"\\r\\n'\n", + "2026-03-30 16:23:59,616 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I4\"\\r\\n'\n", + "2026-03-30 16:23:59,632 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I5\"\\r\\n'\n", + "2026-03-30 16:23:59,633 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I5\"\\r\\n'\n", + "2026-03-30 16:23:59,634 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"S\"\\r\\n'\n", + "2026-03-30 16:23:59,635 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"S\"\\r\\n'\n", + "2026-03-30 16:23:59,647 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"SI\"\\r\\n'\n", + "2026-03-30 16:23:59,649 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"SI\"\\r\\n'\n", + "2026-03-30 16:23:59,664 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"SIR\"\\r\\n'\n", + "2026-03-30 16:23:59,665 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"SIR\"\\r\\n'\n", + "2026-03-30 16:23:59,680 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"Z\"\\r\\n'\n", + "2026-03-30 16:23:59,682 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"Z\"\\r\\n'\n", + "2026-03-30 16:23:59,695 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"ZI\"\\r\\n'\n", + "2026-03-30 16:23:59,696 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"ZI\"\\r\\n'\n", + "2026-03-30 16:23:59,714 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"@\"\\r\\n'\n", + "2026-03-30 16:23:59,715 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"@\"\\r\\n'\n", + "2026-03-30 16:23:59,720 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"SR\"\\r\\n'\n", + "2026-03-30 16:23:59,723 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"SR\"\\r\\n'\n", + "2026-03-30 16:23:59,729 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"T\"\\r\\n'\n", + "2026-03-30 16:23:59,730 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"T\"\\r\\n'\n", + "2026-03-30 16:23:59,743 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"TA\"\\r\\n'\n", + "2026-03-30 16:23:59,744 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"TA\"\\r\\n'\n", + "2026-03-30 16:23:59,759 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"TAC\"\\r\\n'\n", + "2026-03-30 16:23:59,760 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"TAC\"\\r\\n'\n", + "2026-03-30 16:23:59,776 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"TI\"\\r\\n'\n", + "2026-03-30 16:23:59,776 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"TI\"\\r\\n'\n", + "2026-03-30 16:23:59,792 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C0\"\\r\\n'\n", + "2026-03-30 16:23:59,793 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"C0\"\\r\\n'\n", + "2026-03-30 16:23:59,794 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C1\"\\r\\n'\n", + "2026-03-30 16:23:59,794 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"C1\"\\r\\n'\n", + "2026-03-30 16:23:59,807 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C2\"\\r\\n'\n", + "2026-03-30 16:23:59,808 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"C2\"\\r\\n'\n", + "2026-03-30 16:23:59,824 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C3\"\\r\\n'\n", + "2026-03-30 16:23:59,824 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"C3\"\\r\\n'\n", + "2026-03-30 16:23:59,840 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"COM\"\\r\\n'\n", + "2026-03-30 16:23:59,840 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"COM\"\\r\\n'\n", + "2026-03-30 16:23:59,855 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"DAT\"\\r\\n'\n", + "2026-03-30 16:23:59,856 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"DAT\"\\r\\n'\n", + "2026-03-30 16:23:59,871 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I10\"\\r\\n'\n", + "2026-03-30 16:23:59,872 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I10\"\\r\\n'\n", + "2026-03-30 16:23:59,888 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I11\"\\r\\n'\n", + "2026-03-30 16:23:59,888 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I11\"\\r\\n'\n", + "2026-03-30 16:23:59,904 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I14\"\\r\\n'\n", + "2026-03-30 16:23:59,905 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I14\"\\r\\n'\n", + "2026-03-30 16:23:59,920 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I15\"\\r\\n'\n", + "2026-03-30 16:23:59,921 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I15\"\\r\\n'\n", + "2026-03-30 16:23:59,935 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I16\"\\r\\n'\n", + "2026-03-30 16:23:59,936 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I16\"\\r\\n'\n", + "2026-03-30 16:23:59,937 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I21\"\\r\\n'\n", + "2026-03-30 16:23:59,938 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I21\"\\r\\n'\n", + "2026-03-30 16:23:59,952 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I22\"\\r\\n'\n", + "2026-03-30 16:23:59,953 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I22\"\\r\\n'\n", + "2026-03-30 16:23:59,967 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I23\"\\r\\n'\n", + "2026-03-30 16:23:59,968 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I23\"\\r\\n'\n", + "2026-03-30 16:23:59,983 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I24\"\\r\\n'\n", + "2026-03-30 16:23:59,984 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I24\"\\r\\n'\n", + "2026-03-30 16:24:00,000 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I25\"\\r\\n'\n", + "2026-03-30 16:24:00,000 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I25\"\\r\\n'\n", + "2026-03-30 16:24:00,015 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I26\"\\r\\n'\n", + "2026-03-30 16:24:00,015 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I26\"\\r\\n'\n", + "2026-03-30 16:24:00,031 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M01\"\\r\\n'\n", + "2026-03-30 16:24:00,032 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M01\"\\r\\n'\n", + "2026-03-30 16:24:00,047 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M02\"\\r\\n'\n", + "2026-03-30 16:24:00,048 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M02\"\\r\\n'\n", + "2026-03-30 16:24:00,063 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M03\"\\r\\n'\n", + "2026-03-30 16:24:00,063 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M03\"\\r\\n'\n", + "2026-03-30 16:24:00,079 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M17\"\\r\\n'\n", + "2026-03-30 16:24:00,080 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M17\"\\r\\n'\n", + "2026-03-30 16:24:00,095 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M18\"\\r\\n'\n", + "2026-03-30 16:24:00,096 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M18\"\\r\\n'\n", + "2026-03-30 16:24:00,097 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M19\"\\r\\n'\n", + "2026-03-30 16:24:00,098 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M19\"\\r\\n'\n", + "2026-03-30 16:24:00,112 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M20\"\\r\\n'\n", + "2026-03-30 16:24:00,112 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M20\"\\r\\n'\n", + "2026-03-30 16:24:00,127 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M21\"\\r\\n'\n", + "2026-03-30 16:24:00,128 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M21\"\\r\\n'\n", + "2026-03-30 16:24:00,143 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M27\"\\r\\n'\n", + "2026-03-30 16:24:00,144 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M27\"\\r\\n'\n", + "2026-03-30 16:24:00,159 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M28\"\\r\\n'\n", + "2026-03-30 16:24:00,160 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M28\"\\r\\n'\n", + "2026-03-30 16:24:00,175 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M29\"\\r\\n'\n", + "2026-03-30 16:24:00,176 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M29\"\\r\\n'\n", + "2026-03-30 16:24:00,191 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M31\"\\r\\n'\n", + "2026-03-30 16:24:00,192 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M31\"\\r\\n'\n", + "2026-03-30 16:24:00,207 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M32\"\\r\\n'\n", + "2026-03-30 16:24:00,208 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M32\"\\r\\n'\n", + "2026-03-30 16:24:00,223 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M33\"\\r\\n'\n", + "2026-03-30 16:24:00,224 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M33\"\\r\\n'\n", + "2026-03-30 16:24:00,239 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M35\"\\r\\n'\n", + "2026-03-30 16:24:00,240 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M35\"\\r\\n'\n", + "2026-03-30 16:24:00,255 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"SIS\"\\r\\n'\n", + "2026-03-30 16:24:00,256 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"SIS\"\\r\\n'\n", + "2026-03-30 16:24:00,271 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"SNR\"\\r\\n'\n", + "2026-03-30 16:24:00,272 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"SNR\"\\r\\n'\n", + "2026-03-30 16:24:00,273 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TIM\"\\r\\n'\n", + "2026-03-30 16:24:00,274 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TIM\"\\r\\n'\n", + "2026-03-30 16:24:00,287 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST0\"\\r\\n'\n", + "2026-03-30 16:24:00,288 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TST0\"\\r\\n'\n", + "2026-03-30 16:24:00,303 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST1\"\\r\\n'\n", + "2026-03-30 16:24:00,304 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TST1\"\\r\\n'\n", + "2026-03-30 16:24:00,319 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST2\"\\r\\n'\n", + "2026-03-30 16:24:00,320 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TST2\"\\r\\n'\n", + "2026-03-30 16:24:00,336 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST3\"\\r\\n'\n", + "2026-03-30 16:24:00,336 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TST3\"\\r\\n'\n", + "2026-03-30 16:24:00,351 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"UPD\"\\r\\n'\n", + "2026-03-30 16:24:00,352 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"UPD\"\\r\\n'\n", + "2026-03-30 16:24:00,367 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"FCUT\"\\r\\n'\n", + "2026-03-30 16:24:00,368 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 3 \"FCUT\"\\r\\n'\n", + "2026-03-30 16:24:00,383 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"FSET\"\\r\\n'\n", + "2026-03-30 16:24:00,384 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 3 \"FSET\"\\r\\n'\n", + "2026-03-30 16:24:00,399 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"LST\"\\r\\n'\n", + "2026-03-30 16:24:00,399 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 3 \"LST\"\\r\\n'\n", + "2026-03-30 16:24:00,415 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"RDB\"\\r\\n'\n", + "2026-03-30 16:24:00,416 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 3 \"RDB\"\\r\\n'\n", + "2026-03-30 16:24:00,431 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 A 3 \"USTB\"\\r\\n'\n", + "2026-03-30 16:24:00,432 - pylabrobot - IO - [MT Scale] Received response: b'I0 A 3 \"USTB\"\\r\\n'\n", + "2026-03-30 16:24:00,433 - pylabrobot - IO - [MT Scale] Sent command: I2\n", + "2026-03-30 16:24:00,434 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I2\\r\\n'\n", + "2026-03-30 16:24:00,495 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", + "2026-03-30 16:24:00,496 - pylabrobot - IO - [MT Scale] Received response: b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", + "2026-03-30 16:24:00,497 - pylabrobot - IO - [MT Scale] Sent command: I2\n", + "2026-03-30 16:24:00,499 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I2\\r\\n'\n", + "2026-03-30 16:24:00,559 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", + "2026-03-30 16:24:00,560 - pylabrobot - IO - [MT Scale] Received response: b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", + "2026-03-30 16:24:00,561 - pylabrobot - IO - [MT Scale] Sent command: I3\n", + "2026-03-30 16:24:00,562 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I3\\r\\n'\n", + "2026-03-30 16:24:00,607 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I3 A \"1.10 18.6.4.1361.772\"\\r\\n'\n", + "2026-03-30 16:24:00,608 - pylabrobot - IO - [MT Scale] Received response: b'I3 A \"1.10 18.6.4.1361.772\"\\r\\n'\n", + "2026-03-30 16:24:00,609 - pylabrobot - INFO - [MT Scale] Connected to Mettler Toledo scale on /dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0\n", "Device type: WXS205SDU WXA-Bridge\n", "Configuration: Bridge\n", "Serial number: B207696838\n", "Firmware: 1.10 18.6.4.1361.772\n", "Capacity: 220.0 g\n", "Supported commands: ['@', 'C0', 'C1', 'C2', 'C3', 'COM', 'DAT', 'FCUT', 'FSET', 'I0', 'I1', 'I10', 'I11', 'I14', 'I15', 'I16', 'I2', 'I21', 'I22', 'I23', 'I24', 'I25', 'I26', 'I3', 'I4', 'I5', 'LST', 'M01', 'M02', 'M03', 'M17', 'M18', 'M19', 'M20', 'M21', 'M27', 'M28', 'M29', 'M31', 'M32', 'M33', 'M35', 'RDB', 'S', 'SI', 'SIR', 'SIS', 'SNR', 'SR', 'T', 'TA', 'TAC', 'TI', 'TIM', 'TST0', 'TST1', 'TST2', 'TST3', 'UPD', 'USTB', 'Z', 'ZI']\n", - "2026-03-30 13:22:10,522 - pylabrobot - IO - [MT Scale] Sent command: M21 0 0\n", - "2026-03-30 13:22:10,526 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'M21 0 0\\r\\n'\n", - "2026-03-30 13:22:10,565 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M21 A\\r\\n'\n", - "2026-03-30 13:22:10,566 - pylabrobot - IO - [MT Scale] Received response: b'M21 A\\r\\n'\n" + "2026-03-30 16:24:00,610 - pylabrobot - IO - [MT Scale] Sent command: M21 0 0\n", + "2026-03-30 16:24:00,611 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'M21 0 0\\r\\n'\n", + "2026-03-30 16:24:00,639 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M21 A\\r\\n'\n", + "2026-03-30 16:24:00,639 - pylabrobot - IO - [MT Scale] Received response: b'M21 A\\r\\n'\n" ] } ], @@ -288,8 +288,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "46 methods available on this device:\n", - " cancel\n", + "65 methods available on this device:\n", " cancel_all\n", " clear_tare\n", " deserialize\n", @@ -302,6 +301,9 @@ " read_weight\n", " read_weight_value_immediately\n", " request_adjustment_history\n", + " request_adjustment_setting\n", + " request_adjustment_weight\n", + " request_assortment_type_revision\n", " request_auto_zero\n", " request_capacity\n", " request_date\n", @@ -309,17 +311,34 @@ " request_device_info\n", " request_device_type\n", " request_environment_condition\n", + " request_filter_cutoff\n", + " request_firmware_version\n", " request_model_designation\n", " request_net_weight_with_status\n", + " request_next_service_date\n", + " request_operating_mode\n", + " request_operating_mode_after_restart\n", + " request_profact_day\n", + " request_profact_temperature_criterion\n", + " request_profact_time\n", + " request_profact_time_criteria\n", + " request_readability\n", " request_serial_number\n", + " request_serial_parameters\n", " request_software_material_number\n", - " request_software_version\n", + " request_stability_criteria\n", " request_supported_methods\n", " request_tare_weight\n", + " request_test_settings\n", + " request_test_weight\n", " request_time\n", " request_update_rate\n", - " request_uptime\n", + " request_uptime_minutes\n", + " request_user_settings\n", " request_weighing_mode\n", + " request_weighing_value_release\n", + " request_zeroing_mode\n", + " reset\n", " send_command\n", " serialize\n", " set_display_text\n", @@ -364,132 +383,132 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 13:22:10,635 - pylabrobot - IO - [MT Scale] Sent command: I0\n", - "2026-03-30 13:22:10,637 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I0\\r\\n'\n", - "2026-03-30 13:22:10,663 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I0\"\\r\\n'\n", - "2026-03-30 13:22:10,667 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I0\"\\r\\n'\n", - "2026-03-30 13:22:10,678 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I1\"\\r\\n'\n", - "2026-03-30 13:22:10,681 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I1\"\\r\\n'\n", - "2026-03-30 13:22:10,693 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I2\"\\r\\n'\n", - "2026-03-30 13:22:10,695 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I2\"\\r\\n'\n", - "2026-03-30 13:22:10,708 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I3\"\\r\\n'\n", - "2026-03-30 13:22:10,714 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I3\"\\r\\n'\n", - "2026-03-30 13:22:10,725 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I4\"\\r\\n'\n", - "2026-03-30 13:22:10,728 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I4\"\\r\\n'\n", - "2026-03-30 13:22:10,740 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I5\"\\r\\n'\n", - "2026-03-30 13:22:10,742 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I5\"\\r\\n'\n", - "2026-03-30 13:22:10,746 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"S\"\\r\\n'\n", - "2026-03-30 13:22:10,751 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"S\"\\r\\n'\n", - "2026-03-30 13:22:10,757 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"SI\"\\r\\n'\n", - "2026-03-30 13:22:10,758 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"SI\"\\r\\n'\n", - "2026-03-30 13:22:10,772 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"SIR\"\\r\\n'\n", - "2026-03-30 13:22:10,773 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"SIR\"\\r\\n'\n", - "2026-03-30 13:22:10,788 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"Z\"\\r\\n'\n", - "2026-03-30 13:22:10,789 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"Z\"\\r\\n'\n", - "2026-03-30 13:22:10,805 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"ZI\"\\r\\n'\n", - "2026-03-30 13:22:10,805 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"ZI\"\\r\\n'\n", - "2026-03-30 13:22:10,820 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"@\"\\r\\n'\n", - "2026-03-30 13:22:10,821 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"@\"\\r\\n'\n", - "2026-03-30 13:22:10,822 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"SR\"\\r\\n'\n", - "2026-03-30 13:22:10,822 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"SR\"\\r\\n'\n", - "2026-03-30 13:22:10,836 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"T\"\\r\\n'\n", - "2026-03-30 13:22:10,837 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"T\"\\r\\n'\n", - "2026-03-30 13:22:10,853 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"TA\"\\r\\n'\n", - "2026-03-30 13:22:10,853 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"TA\"\\r\\n'\n", - "2026-03-30 13:22:10,868 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"TAC\"\\r\\n'\n", - "2026-03-30 13:22:10,870 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"TAC\"\\r\\n'\n", - "2026-03-30 13:22:10,885 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"TI\"\\r\\n'\n", - "2026-03-30 13:22:10,886 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"TI\"\\r\\n'\n", - "2026-03-30 13:22:10,900 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C0\"\\r\\n'\n", - "2026-03-30 13:22:10,900 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"C0\"\\r\\n'\n", - "2026-03-30 13:22:10,916 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C1\"\\r\\n'\n", - "2026-03-30 13:22:10,917 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"C1\"\\r\\n'\n", - "2026-03-30 13:22:10,919 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C2\"\\r\\n'\n", - "2026-03-30 13:22:10,921 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"C2\"\\r\\n'\n", - "2026-03-30 13:22:10,932 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C3\"\\r\\n'\n", - "2026-03-30 13:22:10,933 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"C3\"\\r\\n'\n", - "2026-03-30 13:22:10,948 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"COM\"\\r\\n'\n", - "2026-03-30 13:22:10,949 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"COM\"\\r\\n'\n", - "2026-03-30 13:22:10,964 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"DAT\"\\r\\n'\n", - "2026-03-30 13:22:10,966 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"DAT\"\\r\\n'\n", - "2026-03-30 13:22:10,982 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I10\"\\r\\n'\n", - "2026-03-30 13:22:10,983 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I10\"\\r\\n'\n", - "2026-03-30 13:22:10,996 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I11\"\\r\\n'\n", - "2026-03-30 13:22:10,998 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I11\"\\r\\n'\n", - "2026-03-30 13:22:11,013 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I14\"\\r\\n'\n", - "2026-03-30 13:22:11,015 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I14\"\\r\\n'\n", - "2026-03-30 13:22:11,030 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I15\"\\r\\n'\n", - "2026-03-30 13:22:11,033 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I15\"\\r\\n'\n", - "2026-03-30 13:22:11,045 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I16\"\\r\\n'\n", - "2026-03-30 13:22:11,048 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I16\"\\r\\n'\n", - "2026-03-30 13:22:11,061 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I21\"\\r\\n'\n", - "2026-03-30 13:22:11,065 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I21\"\\r\\n'\n", - "2026-03-30 13:22:11,068 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I22\"\\r\\n'\n", - "2026-03-30 13:22:11,070 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I22\"\\r\\n'\n", - "2026-03-30 13:22:11,077 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I23\"\\r\\n'\n", - "2026-03-30 13:22:11,079 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I23\"\\r\\n'\n", - "2026-03-30 13:22:11,093 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I24\"\\r\\n'\n", - "2026-03-30 13:22:11,097 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I24\"\\r\\n'\n", - "2026-03-30 13:22:11,109 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I25\"\\r\\n'\n", - "2026-03-30 13:22:11,110 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I25\"\\r\\n'\n", - "2026-03-30 13:22:11,125 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I26\"\\r\\n'\n", - "2026-03-30 13:22:11,133 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I26\"\\r\\n'\n", - "2026-03-30 13:22:11,142 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M01\"\\r\\n'\n", - "2026-03-30 13:22:11,143 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M01\"\\r\\n'\n", - "2026-03-30 13:22:11,156 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M02\"\\r\\n'\n", - "2026-03-30 13:22:11,159 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M02\"\\r\\n'\n", - "2026-03-30 13:22:11,173 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M03\"\\r\\n'\n", - "2026-03-30 13:22:11,179 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M03\"\\r\\n'\n", - "2026-03-30 13:22:11,189 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M17\"\\r\\n'\n", - "2026-03-30 13:22:11,192 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M17\"\\r\\n'\n", - "2026-03-30 13:22:11,205 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M18\"\\r\\n'\n", - "2026-03-30 13:22:11,206 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M18\"\\r\\n'\n", - "2026-03-30 13:22:11,220 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M19\"\\r\\n'\n", - "2026-03-30 13:22:11,221 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M19\"\\r\\n'\n", - "2026-03-30 13:22:11,237 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M20\"\\r\\n'\n", - "2026-03-30 13:22:11,238 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M20\"\\r\\n'\n", - "2026-03-30 13:22:11,241 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M21\"\\r\\n'\n", - "2026-03-30 13:22:11,243 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M21\"\\r\\n'\n", - "2026-03-30 13:22:11,252 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M27\"\\r\\n'\n", - "2026-03-30 13:22:11,257 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M27\"\\r\\n'\n", - "2026-03-30 13:22:11,268 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M28\"\\r\\n'\n", - "2026-03-30 13:22:11,269 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M28\"\\r\\n'\n", - "2026-03-30 13:22:11,284 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M29\"\\r\\n'\n", - "2026-03-30 13:22:11,286 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M29\"\\r\\n'\n", - "2026-03-30 13:22:11,300 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M31\"\\r\\n'\n", - "2026-03-30 13:22:11,300 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M31\"\\r\\n'\n", - "2026-03-30 13:22:11,316 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M32\"\\r\\n'\n", - "2026-03-30 13:22:11,317 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M32\"\\r\\n'\n", - "2026-03-30 13:22:11,332 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M33\"\\r\\n'\n", - "2026-03-30 13:22:11,333 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M33\"\\r\\n'\n", - "2026-03-30 13:22:11,347 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M35\"\\r\\n'\n", - "2026-03-30 13:22:11,348 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M35\"\\r\\n'\n", - "2026-03-30 13:22:11,364 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"SIS\"\\r\\n'\n", - "2026-03-30 13:22:11,364 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"SIS\"\\r\\n'\n", - "2026-03-30 13:22:11,380 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"SNR\"\\r\\n'\n", - "2026-03-30 13:22:11,381 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"SNR\"\\r\\n'\n", - "2026-03-30 13:22:11,396 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TIM\"\\r\\n'\n", - "2026-03-30 13:22:11,396 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TIM\"\\r\\n'\n", - "2026-03-30 13:22:11,412 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST0\"\\r\\n'\n", - "2026-03-30 13:22:11,413 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TST0\"\\r\\n'\n", - "2026-03-30 13:22:11,428 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST1\"\\r\\n'\n", - "2026-03-30 13:22:11,429 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TST1\"\\r\\n'\n", - "2026-03-30 13:22:11,431 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST2\"\\r\\n'\n", - "2026-03-30 13:22:11,432 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TST2\"\\r\\n'\n", - "2026-03-30 13:22:11,444 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST3\"\\r\\n'\n", - "2026-03-30 13:22:11,445 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TST3\"\\r\\n'\n", - "2026-03-30 13:22:11,460 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"UPD\"\\r\\n'\n", - "2026-03-30 13:22:11,463 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"UPD\"\\r\\n'\n", - "2026-03-30 13:22:11,476 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"FCUT\"\\r\\n'\n", - "2026-03-30 13:22:11,477 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 3 \"FCUT\"\\r\\n'\n", - "2026-03-30 13:22:11,492 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"FSET\"\\r\\n'\n", - "2026-03-30 13:22:11,493 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 3 \"FSET\"\\r\\n'\n", - "2026-03-30 13:22:11,508 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"LST\"\\r\\n'\n", - "2026-03-30 13:22:11,509 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 3 \"LST\"\\r\\n'\n", - "2026-03-30 13:22:11,524 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"RDB\"\\r\\n'\n", - "2026-03-30 13:22:11,525 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 3 \"RDB\"\\r\\n'\n", - "2026-03-30 13:22:11,540 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 A 3 \"USTB\"\\r\\n'\n", - "2026-03-30 13:22:11,541 - pylabrobot - IO - [MT Scale] Received response: b'I0 A 3 \"USTB\"\\r\\n'\n" + "2026-03-30 16:24:00,705 - pylabrobot - IO - [MT Scale] Sent command: I0\n", + "2026-03-30 16:24:00,713 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I0\\r\\n'\n", + "2026-03-30 16:24:00,736 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I0\"\\r\\n'\n", + "2026-03-30 16:24:00,737 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I0\"\\r\\n'\n", + "2026-03-30 16:24:00,751 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I1\"\\r\\n'\n", + "2026-03-30 16:24:00,752 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I1\"\\r\\n'\n", + "2026-03-30 16:24:00,767 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I2\"\\r\\n'\n", + "2026-03-30 16:24:00,768 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I2\"\\r\\n'\n", + "2026-03-30 16:24:00,783 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I3\"\\r\\n'\n", + "2026-03-30 16:24:00,784 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I3\"\\r\\n'\n", + "2026-03-30 16:24:00,799 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I4\"\\r\\n'\n", + "2026-03-30 16:24:00,800 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I4\"\\r\\n'\n", + "2026-03-30 16:24:00,815 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I5\"\\r\\n'\n", + "2026-03-30 16:24:00,816 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I5\"\\r\\n'\n", + "2026-03-30 16:24:00,830 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"S\"\\r\\n'\n", + "2026-03-30 16:24:00,831 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"S\"\\r\\n'\n", + "2026-03-30 16:24:00,833 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"SI\"\\r\\n'\n", + "2026-03-30 16:24:00,833 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"SI\"\\r\\n'\n", + "2026-03-30 16:24:00,847 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"SIR\"\\r\\n'\n", + "2026-03-30 16:24:00,848 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"SIR\"\\r\\n'\n", + "2026-03-30 16:24:00,864 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"Z\"\\r\\n'\n", + "2026-03-30 16:24:00,865 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"Z\"\\r\\n'\n", + "2026-03-30 16:24:00,878 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"ZI\"\\r\\n'\n", + "2026-03-30 16:24:00,879 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"ZI\"\\r\\n'\n", + "2026-03-30 16:24:00,895 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"@\"\\r\\n'\n", + "2026-03-30 16:24:00,896 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"@\"\\r\\n'\n", + "2026-03-30 16:24:00,911 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"SR\"\\r\\n'\n", + "2026-03-30 16:24:00,912 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"SR\"\\r\\n'\n", + "2026-03-30 16:24:00,913 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"T\"\\r\\n'\n", + "2026-03-30 16:24:00,914 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"T\"\\r\\n'\n", + "2026-03-30 16:24:00,926 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"TA\"\\r\\n'\n", + "2026-03-30 16:24:00,927 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"TA\"\\r\\n'\n", + "2026-03-30 16:24:00,942 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"TAC\"\\r\\n'\n", + "2026-03-30 16:24:00,943 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"TAC\"\\r\\n'\n", + "2026-03-30 16:24:00,959 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"TI\"\\r\\n'\n", + "2026-03-30 16:24:00,959 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"TI\"\\r\\n'\n", + "2026-03-30 16:24:00,974 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C0\"\\r\\n'\n", + "2026-03-30 16:24:00,975 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"C0\"\\r\\n'\n", + "2026-03-30 16:24:00,990 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C1\"\\r\\n'\n", + "2026-03-30 16:24:00,991 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"C1\"\\r\\n'\n", + "2026-03-30 16:24:00,992 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C2\"\\r\\n'\n", + "2026-03-30 16:24:00,993 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"C2\"\\r\\n'\n", + "2026-03-30 16:24:01,006 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C3\"\\r\\n'\n", + "2026-03-30 16:24:01,007 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"C3\"\\r\\n'\n", + "2026-03-30 16:24:01,023 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"COM\"\\r\\n'\n", + "2026-03-30 16:24:01,024 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"COM\"\\r\\n'\n", + "2026-03-30 16:24:01,038 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"DAT\"\\r\\n'\n", + "2026-03-30 16:24:01,039 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"DAT\"\\r\\n'\n", + "2026-03-30 16:24:01,054 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I10\"\\r\\n'\n", + "2026-03-30 16:24:01,055 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I10\"\\r\\n'\n", + "2026-03-30 16:24:01,071 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I11\"\\r\\n'\n", + "2026-03-30 16:24:01,071 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I11\"\\r\\n'\n", + "2026-03-30 16:24:01,086 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I14\"\\r\\n'\n", + "2026-03-30 16:24:01,086 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I14\"\\r\\n'\n", + "2026-03-30 16:24:01,102 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I15\"\\r\\n'\n", + "2026-03-30 16:24:01,103 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I15\"\\r\\n'\n", + "2026-03-30 16:24:01,118 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I16\"\\r\\n'\n", + "2026-03-30 16:24:01,119 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I16\"\\r\\n'\n", + "2026-03-30 16:24:01,135 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I21\"\\r\\n'\n", + "2026-03-30 16:24:01,135 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I21\"\\r\\n'\n", + "2026-03-30 16:24:01,137 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I22\"\\r\\n'\n", + "2026-03-30 16:24:01,137 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I22\"\\r\\n'\n", + "2026-03-30 16:24:01,150 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I23\"\\r\\n'\n", + "2026-03-30 16:24:01,151 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I23\"\\r\\n'\n", + "2026-03-30 16:24:01,166 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I24\"\\r\\n'\n", + "2026-03-30 16:24:01,167 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I24\"\\r\\n'\n", + "2026-03-30 16:24:01,182 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I25\"\\r\\n'\n", + "2026-03-30 16:24:01,183 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I25\"\\r\\n'\n", + "2026-03-30 16:24:01,198 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I26\"\\r\\n'\n", + "2026-03-30 16:24:01,198 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I26\"\\r\\n'\n", + "2026-03-30 16:24:01,214 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M01\"\\r\\n'\n", + "2026-03-30 16:24:01,215 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M01\"\\r\\n'\n", + "2026-03-30 16:24:01,230 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M02\"\\r\\n'\n", + "2026-03-30 16:24:01,231 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M02\"\\r\\n'\n", + "2026-03-30 16:24:01,247 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M03\"\\r\\n'\n", + "2026-03-30 16:24:01,247 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M03\"\\r\\n'\n", + "2026-03-30 16:24:01,262 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M17\"\\r\\n'\n", + "2026-03-30 16:24:01,262 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M17\"\\r\\n'\n", + "2026-03-30 16:24:01,278 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M18\"\\r\\n'\n", + "2026-03-30 16:24:01,279 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M18\"\\r\\n'\n", + "2026-03-30 16:24:01,294 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M19\"\\r\\n'\n", + "2026-03-30 16:24:01,295 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M19\"\\r\\n'\n", + "2026-03-30 16:24:01,310 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M20\"\\r\\n'\n", + "2026-03-30 16:24:01,310 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M20\"\\r\\n'\n", + "2026-03-30 16:24:01,312 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M21\"\\r\\n'\n", + "2026-03-30 16:24:01,313 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M21\"\\r\\n'\n", + "2026-03-30 16:24:01,326 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M27\"\\r\\n'\n", + "2026-03-30 16:24:01,327 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M27\"\\r\\n'\n", + "2026-03-30 16:24:01,347 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M28\"\\r\\n'\n", + "2026-03-30 16:24:01,352 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M28\"\\r\\n'\n", + "2026-03-30 16:24:01,358 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M29\"\\r\\n'\n", + "2026-03-30 16:24:01,359 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M29\"\\r\\n'\n", + "2026-03-30 16:24:01,375 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M31\"\\r\\n'\n", + "2026-03-30 16:24:01,376 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M31\"\\r\\n'\n", + "2026-03-30 16:24:01,391 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M32\"\\r\\n'\n", + "2026-03-30 16:24:01,395 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M32\"\\r\\n'\n", + "2026-03-30 16:24:01,406 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M33\"\\r\\n'\n", + "2026-03-30 16:24:01,407 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M33\"\\r\\n'\n", + "2026-03-30 16:24:01,422 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M35\"\\r\\n'\n", + "2026-03-30 16:24:01,423 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M35\"\\r\\n'\n", + "2026-03-30 16:24:01,439 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"SIS\"\\r\\n'\n", + "2026-03-30 16:24:01,440 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"SIS\"\\r\\n'\n", + "2026-03-30 16:24:01,454 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"SNR\"\\r\\n'\n", + "2026-03-30 16:24:01,455 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"SNR\"\\r\\n'\n", + "2026-03-30 16:24:01,470 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TIM\"\\r\\n'\n", + "2026-03-30 16:24:01,471 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TIM\"\\r\\n'\n", + "2026-03-30 16:24:01,486 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST0\"\\r\\n'\n", + "2026-03-30 16:24:01,488 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TST0\"\\r\\n'\n", + "2026-03-30 16:24:01,502 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST1\"\\r\\n'\n", + "2026-03-30 16:24:01,503 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TST1\"\\r\\n'\n", + "2026-03-30 16:24:01,523 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST2\"\\r\\n'\n", + "2026-03-30 16:24:01,524 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TST2\"\\r\\n'\n", + "2026-03-30 16:24:01,534 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST3\"\\r\\n'\n", + "2026-03-30 16:24:01,535 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TST3\"\\r\\n'\n", + "2026-03-30 16:24:01,536 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"UPD\"\\r\\n'\n", + "2026-03-30 16:24:01,537 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"UPD\"\\r\\n'\n", + "2026-03-30 16:24:01,550 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"FCUT\"\\r\\n'\n", + "2026-03-30 16:24:01,551 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 3 \"FCUT\"\\r\\n'\n", + "2026-03-30 16:24:01,566 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"FSET\"\\r\\n'\n", + "2026-03-30 16:24:01,567 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 3 \"FSET\"\\r\\n'\n", + "2026-03-30 16:24:01,584 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"LST\"\\r\\n'\n", + "2026-03-30 16:24:01,587 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 3 \"LST\"\\r\\n'\n", + "2026-03-30 16:24:01,599 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"RDB\"\\r\\n'\n", + "2026-03-30 16:24:01,603 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 3 \"RDB\"\\r\\n'\n", + "2026-03-30 16:24:01,614 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 A 3 \"USTB\"\\r\\n'\n", + "2026-03-30 16:24:01,615 - pylabrobot - IO - [MT Scale] Received response: b'I0 A 3 \"USTB\"\\r\\n'\n" ] }, { @@ -605,20 +624,22 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 13:22:11,575 - pylabrobot - IO - [MT Scale] Sent command: I3\n", - "2026-03-30 13:22:11,583 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I3\\r\\n'\n", - "2026-03-30 13:22:11,637 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I3 A \"1.10 18.6.4.1361.772\"\\r\\n'\n", - "2026-03-30 13:22:11,642 - pylabrobot - IO - [MT Scale] Received response: b'I3 A \"1.10 18.6.4.1361.772\"\\r\\n'\n", - "2026-03-30 13:22:11,643 - pylabrobot - IO - [MT Scale] Sent command: I5\n", - "2026-03-30 13:22:11,648 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I5\\r\\n'\n", - "2026-03-30 13:22:11,684 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I5 A \"11671158C\"\\r\\n'\n", - "2026-03-30 13:22:11,684 - pylabrobot - IO - [MT Scale] Received response: b'I5 A \"11671158C\"\\r\\n'\n", - "2026-03-30 13:22:11,687 - pylabrobot - IO - [MT Scale] Sent command: I10\n", - "2026-03-30 13:22:11,688 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I10\\r\\n'\n", - "2026-03-30 13:22:11,716 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I10 A \"\"\\r\\n'\n", - "2026-03-30 13:22:11,718 - pylabrobot - IO - [MT Scale] Received response: b'I10 A \"\"\\r\\n'\n", - "2026-03-30 13:22:11,720 - pylabrobot - IO - [MT Scale] Sent command: I11\n", - "2026-03-30 13:22:11,726 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I11\\r\\n'\n" + "2026-03-30 16:24:01,630 - pylabrobot - IO - [MT Scale] Sent command: I3\n", + "2026-03-30 16:24:01,632 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I3\\r\\n'\n", + "2026-03-30 16:24:01,678 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I3 A \"1.10 18.6.4.1361.772\"\\r\\n'\n", + "2026-03-30 16:24:01,679 - pylabrobot - IO - [MT Scale] Received response: b'I3 A \"1.10 18.6.4.1361.772\"\\r\\n'\n", + "2026-03-30 16:24:01,680 - pylabrobot - IO - [MT Scale] Sent command: I5\n", + "2026-03-30 16:24:01,682 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I5\\r\\n'\n", + "2026-03-30 16:24:01,711 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I5 A \"11671158C\"\\r\\n'\n", + "2026-03-30 16:24:01,712 - pylabrobot - IO - [MT Scale] Received response: b'I5 A \"11671158C\"\\r\\n'\n", + "2026-03-30 16:24:01,714 - pylabrobot - IO - [MT Scale] Sent command: I10\n", + "2026-03-30 16:24:01,718 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I10\\r\\n'\n", + "2026-03-30 16:24:01,743 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I10 A \"\"\\r\\n'\n", + "2026-03-30 16:24:01,744 - pylabrobot - IO - [MT Scale] Received response: b'I10 A \"\"\\r\\n'\n", + "2026-03-30 16:24:01,746 - pylabrobot - IO - [MT Scale] Sent command: I11\n", + "2026-03-30 16:24:01,752 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I11\\r\\n'\n", + "2026-03-30 16:24:01,790 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I11 A \"WXS205SDU\"\\r\\n'\n", + "2026-03-30 16:24:01,791 - pylabrobot - IO - [MT Scale] Received response: b'I11 A \"WXS205SDU\"\\r\\n'\n" ] }, { @@ -627,118 +648,89 @@ "text": [ "Software version: 1.10 18.6.4.1361.772\n", "Software material number: 11671158C\n", - "Device ID: ''\n" + "Device ID: ''\n", + "Model designation: WXS205SDU\n" ] }, { - "name": "stderr", - "output_type": "stream", - "text": [ - "2026-03-30 13:22:11,764 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I11 A \"WXS205SDU\"\\r\\n'\n", - "2026-03-30 13:22:11,764 - pylabrobot - IO - [MT Scale] Received response: b'I11 A \"WXS205SDU\"\\r\\n'\n", - "2026-03-30 13:22:11,765 - pylabrobot - IO - [MT Scale] Sent command: I15\n", - "2026-03-30 13:22:11,767 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I15\\r\\n'\n", - "2026-03-30 13:22:11,796 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I15 A 234\\r\\n'\n", - "2026-03-30 13:22:11,797 - pylabrobot - IO - [MT Scale] Received response: b'I15 A 234\\r\\n'\n", - "2026-03-30 13:22:11,800 - pylabrobot - IO - [MT Scale] Sent command: DAT\n", - "2026-03-30 13:22:11,803 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'DAT\\r\\n'\n", - "2026-03-30 13:22:11,843 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'DAT A 04 01 2000\\r\\n'\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Model designation: WXS205SDU\n", - "Uptime: 234d 0h 0m 0s\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2026-03-30 13:22:11,844 - pylabrobot - IO - [MT Scale] Received response: b'DAT A 04 01 2000\\r\\n'\n", - "2026-03-30 13:22:11,846 - pylabrobot - IO - [MT Scale] Sent command: TIM\n", - "2026-03-30 13:22:11,847 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'TIM\\r\\n'\n", - "2026-03-30 13:22:11,876 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'TIM A 20 27 38\\r\\n'\n", - "2026-03-30 13:22:11,876 - pylabrobot - IO - [MT Scale] Received response: b'TIM A 20 27 38\\r\\n'\n", - "2026-03-30 13:22:11,877 - pylabrobot - IO - [MT Scale] Sent command: I14 0\n", - "2026-03-30 13:22:11,879 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I14 0\\r\\n'\n", - "2026-03-30 13:22:11,924 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I14 A 0 1 \"Bridge\"\\r\\n'\n", - "2026-03-30 13:22:11,924 - pylabrobot - IO - [MT Scale] Received response: b'I14 A 0 1 \"Bridge\"\\r\\n'\n", - "2026-03-30 13:22:11,925 - pylabrobot - IO - [MT Scale] Sent command: I14 1\n", - "2026-03-30 13:22:11,926 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I14 1\\r\\n'\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Device date: 04\n", - "Device time: 20\n", - "\n", - "Device info (I14):\n", - " Category 0 (Instrument configuration):\n", - " I14 A 0 1 Bridge\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2026-03-30 13:22:11,972 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I14 A 1 1 \"WXS205SDU\"\\r\\n'\n", - "2026-03-30 13:22:11,972 - pylabrobot - IO - [MT Scale] Received response: b'I14 A 1 1 \"WXS205SDU\"\\r\\n'\n", - "2026-03-30 13:22:11,973 - pylabrobot - IO - [MT Scale] Sent command: I14 2\n", - "2026-03-30 13:22:11,974 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I14 2\\r\\n'\n", - "2026-03-30 13:22:12,020 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I14 A 2 1 \"11671158C\"\\r\\n'\n", - "2026-03-30 13:22:12,020 - pylabrobot - IO - [MT Scale] Received response: b'I14 A 2 1 \"11671158C\"\\r\\n'\n", - "2026-03-30 13:22:12,021 - pylabrobot - IO - [MT Scale] Sent command: I14 3\n", - "2026-03-30 13:22:12,022 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I14 3\\r\\n'\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - " Category 1 (Instrument descriptions):\n", - " I14 A 1 1 WXS205SDU\n", - " Category 2 (SW identification numbers):\n", - " I14 A 2 1 11671158C\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2026-03-30 13:22:12,068 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I14 A 3 1 \"1.10\"\\r\\n'\n", - "2026-03-30 13:22:12,068 - pylabrobot - IO - [MT Scale] Received response: b'I14 A 3 1 \"1.10\"\\r\\n'\n", - "2026-03-30 13:22:12,069 - pylabrobot - IO - [MT Scale] Sent command: I14 4\n", - "2026-03-30 13:22:12,071 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I14 4\\r\\n'\n", - "2026-03-30 13:22:12,116 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I14 A 4 1 \"B207696838\"\\r\\n'\n", - "2026-03-30 13:22:12,116 - pylabrobot - IO - [MT Scale] Received response: b'I14 A 4 1 \"B207696838\"\\r\\n'\n", - "2026-03-30 13:22:12,117 - pylabrobot - IO - [MT Scale] Sent command: I14 5\n", - "2026-03-30 13:22:12,118 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I14 5\\r\\n'\n", - "2026-03-30 13:22:12,166 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I14 A 5 1 \"18.6.4.1361.772\"\\r\\n'\n", - "2026-03-30 13:22:12,172 - pylabrobot - IO - [MT Scale] Received response: b'I14 A 5 1 \"18.6.4.1361.772\"\\r\\n'\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - " Category 3 (SW versions):\n", - " I14 A 3 1 1.10\n", - " Category 4 (Serial numbers):\n", - " I14 A 4 1 B207696838\n", - " Category 5 (TDNR numbers):\n", - " I14 A 5 1 18.6.4.1361.772\n", - "\n", - "PASS: Batch 1 device identity commands completed\n" + "ename": "AttributeError", + "evalue": "'MettlerToledoWXS205SDUBackend' object has no attribute 'request_uptime'", + "output_type": "error", + "traceback": [ + "\u001b[31m---------------------------------------------------------------------------\u001b[39m", + "\u001b[31mAttributeError\u001b[39m Traceback (most recent call last)", + "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[6]\u001b[39m\u001b[32m, line 25\u001b[39m\n\u001b[32m 23\u001b[39m \u001b[38;5;66;03m# I15 - Uptime\u001b[39;00m\n\u001b[32m 24\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m \u001b[33m\"\u001b[39m\u001b[33mI15\u001b[39m\u001b[33m\"\u001b[39m \u001b[38;5;129;01min\u001b[39;00m backend._supported_commands:\n\u001b[32m---> \u001b[39m\u001b[32m25\u001b[39m uptime = \u001b[38;5;28;01mawait\u001b[39;00m \u001b[43mbackend\u001b[49m\u001b[43m.\u001b[49m\u001b[43mrequest_uptime\u001b[49m()\n\u001b[32m 26\u001b[39m \u001b[38;5;28mprint\u001b[39m(\u001b[33mf\u001b[39m\u001b[33m\"\u001b[39m\u001b[33mUptime: \u001b[39m\u001b[38;5;132;01m{\u001b[39;00muptime[\u001b[33m'\u001b[39m\u001b[33mdays\u001b[39m\u001b[33m'\u001b[39m]\u001b[38;5;132;01m}\u001b[39;00m\u001b[33md \u001b[39m\u001b[38;5;132;01m{\u001b[39;00muptime[\u001b[33m'\u001b[39m\u001b[33mhours\u001b[39m\u001b[33m'\u001b[39m]\u001b[38;5;132;01m}\u001b[39;00m\u001b[33mh \u001b[39m\u001b[38;5;132;01m{\u001b[39;00muptime[\u001b[33m'\u001b[39m\u001b[33mminutes\u001b[39m\u001b[33m'\u001b[39m]\u001b[38;5;132;01m}\u001b[39;00m\u001b[33mm \u001b[39m\u001b[38;5;132;01m{\u001b[39;00muptime[\u001b[33m'\u001b[39m\u001b[33mseconds\u001b[39m\u001b[33m'\u001b[39m]\u001b[38;5;132;01m}\u001b[39;00m\u001b[33ms\u001b[39m\u001b[33m\"\u001b[39m)\n\u001b[32m 27\u001b[39m \u001b[38;5;28;01melse\u001b[39;00m:\n", + "\u001b[31mAttributeError\u001b[39m: 'MettlerToledoWXS205SDUBackend' object has no attribute 'request_uptime'" ] } ], "source": [ - "# I3 - Software version (Level 0, always available)\nsw_version = await backend.request_firmware_version()\nprint(f\"Software version: {sw_version}\")\n\n# I5 - Software material number (Level 0, always available)\nsw_material = await backend.request_software_material_number()\nprint(f\"Software material number: {sw_material}\")\n\n# I10 - Device ID (user-assignable name)\nif \"I10\" in backend._supported_commands:\n device_id = await backend.request_device_id()\n print(f\"Device ID: '{device_id}'\")\nelse:\n print(\"SKIP: I10 not supported\")\n\n# I11 - Model designation\nif \"I11\" in backend._supported_commands:\n model = await backend.request_model_designation()\n print(f\"Model designation: {model}\")\nelse:\n print(\"SKIP: I11 not supported\")\n\n# I15 - Uptime\nif \"I15\" in backend._supported_commands:\n uptime = await backend.request_uptime()\n print(f\"Uptime: {uptime['days']}d {uptime['hours']}h {uptime['minutes']}m {uptime['seconds']}s\")\nelse:\n print(\"SKIP: I15 not supported\")\n\n# DAT - Date\nif \"DAT\" in backend._supported_commands:\n date = await backend.request_date()\n print(f\"Device date: {date}\")\nelse:\n print(\"SKIP: DAT not supported\")\n\n# TIM - Time\nif \"TIM\" in backend._supported_commands:\n time_str = await backend.request_time()\n print(f\"Device time: {time_str}\")\nelse:\n print(\"SKIP: TIM not supported\")\n\n# I14 - Comprehensive device info (query each category separately)\nif \"I14\" in backend._supported_commands:\n category_names = {\n 0: \"Instrument configuration\",\n 1: \"Instrument descriptions\",\n 2: \"SW identification numbers\",\n 3: \"SW versions\",\n 4: \"Serial numbers\",\n 5: \"TDNR numbers\",\n }\n print(\"\\nDevice info (I14):\")\n for cat, name in category_names.items():\n try:\n info = await backend.request_device_info(category=cat)\n print(f\" Category {cat} ({name}):\")\n for resp in info:\n print(f\" {resp.command} {resp.status} {' '.join(resp.data)}\")\n except Exception as e:\n print(f\" Category {cat} ({name}): {e}\")\nelse:\n print(\"SKIP: I14 not supported\")\n\nprint(\"\\nPASS: Batch 1 device identity commands completed\")" + "# I3 - Software version (Level 0, always available)\n", + "sw_version = await backend.request_firmware_version()\n", + "print(f\"Software version: {sw_version}\")\n", + "\n", + "# I5 - Software material number (Level 0, always available)\n", + "sw_material = await backend.request_software_material_number()\n", + "print(f\"Software material number: {sw_material}\")\n", + "\n", + "# I10 - Device ID (user-assignable name)\n", + "if \"I10\" in backend._supported_commands:\n", + " device_id = await backend.request_device_id()\n", + " print(f\"Device ID: '{device_id}'\")\n", + "else:\n", + " print(\"SKIP: I10 not supported\")\n", + "\n", + "# I11 - Model designation\n", + "if \"I11\" in backend._supported_commands:\n", + " model = await backend.request_model_designation()\n", + " print(f\"Model designation: {model}\")\n", + "else:\n", + " print(\"SKIP: I11 not supported\")\n", + "\n", + "# I15 - Uptime\n", + "if \"I15\" in backend._supported_commands:\n", + " uptime = await backend.request_uptime()\n", + " print(f\"Uptime: {uptime['days']}d {uptime['hours']}h {uptime['minutes']}m {uptime['seconds']}s\")\n", + "else:\n", + " print(\"SKIP: I15 not supported\")\n", + "\n", + "# DAT - Date\n", + "if \"DAT\" in backend._supported_commands:\n", + " date = await backend.request_date()\n", + " print(f\"Device date: {date}\")\n", + "else:\n", + " print(\"SKIP: DAT not supported\")\n", + "\n", + "# TIM - Time\n", + "if \"TIM\" in backend._supported_commands:\n", + " time_str = await backend.request_time()\n", + " print(f\"Device time: {time_str}\")\n", + "else:\n", + " print(\"SKIP: TIM not supported\")\n", + "\n", + "# I14 - Comprehensive device info (query each category separately)\n", + "if \"I14\" in backend._supported_commands:\n", + " category_names = {\n", + " 0: \"Instrument configuration\",\n", + " 1: \"Instrument descriptions\",\n", + " 2: \"SW identification numbers\",\n", + " 3: \"SW versions\",\n", + " 4: \"Serial numbers\",\n", + " 5: \"TDNR numbers\",\n", + " }\n", + " print(\"\\nDevice info (I14):\")\n", + " for cat, name in category_names.items():\n", + " try:\n", + " info = await backend.request_device_info(category=cat)\n", + " print(f\" Category {cat} ({name}):\")\n", + " for resp in info:\n", + " print(f\" {resp.command} {resp.status} {' '.join(resp.data)}\")\n", + " except Exception as e:\n", + " print(f\" Category {cat} ({name}): {e}\")\n", + "else:\n", + " print(\"SKIP: I14 not supported\")\n", + "\n", + "print(\"\\nPASS: Batch 1 device identity commands completed\")" ] }, { @@ -754,78 +746,52 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2026-03-30 13:22:12,193 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] reset_input_buffer\n", - "2026-03-30 13:22:12,196 - pylabrobot - IO - [MT Scale] Sent command: @\n", - "2026-03-30 13:22:12,207 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'@\\r\\n'\n", - "2026-03-30 13:22:12,262 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I4 A \"B207696838\"\\r\\n'\n", - "2026-03-30 13:22:12,264 - pylabrobot - IO - [MT Scale] Received response: b'I4 A \"B207696838\"\\r\\n'\n", - "2026-03-30 13:22:12,267 - pylabrobot - IO - [MT Scale] Sent command: I4\n", - "2026-03-30 13:22:12,273 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I4\\r\\n'\n", - "2026-03-30 13:22:12,308 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I4 A \"B207696838\"\\r\\n'\n", - "2026-03-30 13:22:12,312 - pylabrobot - IO - [MT Scale] Received response: b'I4 A \"B207696838\"\\r\\n'\n", - "2026-03-30 13:22:12,314 - pylabrobot - IO - [MT Scale] Sent command: I2\n", - "2026-03-30 13:22:12,315 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I2\\r\\n'\n", - "2026-03-30 13:22:12,371 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", - "2026-03-30 13:22:12,372 - pylabrobot - IO - [MT Scale] Received response: b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", - "2026-03-30 13:22:12,374 - pylabrobot - IO - [MT Scale] Sent command: I2\n", - "2026-03-30 13:22:12,377 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I2\\r\\n'\n", - "2026-03-30 13:22:12,435 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", - "2026-03-30 13:22:12,437 - pylabrobot - IO - [MT Scale] Received response: b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", - "2026-03-30 13:22:12,440 - pylabrobot - IO - [MT Scale] Sent command: S\n", - "2026-03-30 13:22:12,446 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", - "2026-03-30 13:22:12,771 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00005 g\\r\\n'\n", - "2026-03-30 13:22:12,772 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00005 g\\r\\n'\n", - "2026-03-30 13:22:12,773 - pylabrobot - IO - [MT Scale] Sent command: SI\n", - "2026-03-30 13:22:12,777 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", - "2026-03-30 13:22:12,819 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00005 g\\r\\n'\n", - "2026-03-30 13:22:12,820 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00005 g\\r\\n'\n", - "2026-03-30 13:22:12,821 - pylabrobot - IO - [MT Scale] Sent command: Z\n", - "2026-03-30 13:22:12,823 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'Z\\r\\n'\n", - "2026-03-30 13:22:13,155 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'Z A\\r\\n'\n", - "2026-03-30 13:22:13,155 - pylabrobot - IO - [MT Scale] Received response: b'Z A\\r\\n'\n", - "2026-03-30 13:22:13,156 - pylabrobot - IO - [MT Scale] Sent command: SI\n", - "2026-03-30 13:22:13,157 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", - "2026-03-30 13:22:13,186 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 13:22:13,187 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 13:22:13,188 - pylabrobot - IO - [MT Scale] Sent command: ZI\n", - "2026-03-30 13:22:13,190 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'ZI\\r\\n'\n", - "2026-03-30 13:22:13,218 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'ZI S\\r\\n'\n", - "2026-03-30 13:22:13,219 - pylabrobot - IO - [MT Scale] Received response: b'ZI S\\r\\n'\n", - "2026-03-30 13:22:13,219 - pylabrobot - IO - [MT Scale] Sent command: SI\n", - "2026-03-30 13:22:13,221 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", - "2026-03-30 13:22:13,251 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 13:22:13,251 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 13:22:13,252 - pylabrobot - IO - [MT Scale] Sent command: TA\n", - "2026-03-30 13:22:13,253 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'TA\\r\\n'\n", - "2026-03-30 13:22:13,363 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'TA A 0.00000 g\\r\\n'\n", - "2026-03-30 13:22:13,363 - pylabrobot - IO - [MT Scale] Received response: b'TA A 0.00000 g\\r\\n'\n", - "2026-03-30 13:22:13,364 - pylabrobot - IO - [MT Scale] Sent command: TAC\n", - "2026-03-30 13:22:13,366 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'TAC\\r\\n'\n", - "2026-03-30 13:22:13,394 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'TAC A\\r\\n'\n", - "2026-03-30 13:22:13,395 - pylabrobot - IO - [MT Scale] Received response: b'TAC A\\r\\n'\n", - "2026-03-30 13:22:13,396 - pylabrobot - IO - [MT Scale] Sent command: TA\n", - "2026-03-30 13:22:13,397 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'TA\\r\\n'\n", - "2026-03-30 13:22:13,474 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'TA A 0.00000 g\\r\\n'\n", - "2026-03-30 13:22:13,475 - pylabrobot - IO - [MT Scale] Received response: b'TA A 0.00000 g\\r\\n'\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "PASS: all core Level 0/1 commands validated\n" - ] - } - ], + "outputs": [], "source": [ - "# @ - Cancel (returns serial number)\nsn = await backend.reset()\nassert sn == backend.serial_number, f\"reset() returned {sn}, expected {backend.serial_number}\"\n\n# I4 - Serial number\nsn2 = await backend.request_serial_number()\nassert sn2 == sn\n\n# I2 - Device type and capacity\ndt = await backend.request_device_type()\nassert len(dt) > 0\ncap = await backend.request_capacity()\nassert cap > 0\n\n# S - Stable weight\nw_stable = await backend.read_stable_weight()\nassert isinstance(w_stable, float)\n\n# SI - Weight immediately\nw_imm = await backend.read_weight_value_immediately()\nassert isinstance(w_imm, float)\n\n# Z - Zero (stable) then read\nawait scale.zero(timeout=\"stable\")\nw_after_zero = await backend.read_weight_value_immediately()\nassert abs(w_after_zero) < 0.001, f\"Expected ~0 after zero, got {w_after_zero}\"\n\n# ZI - Zero immediately then read\nawait scale.zero(timeout=0)\nw_after_zi = await backend.read_weight_value_immediately()\nassert abs(w_after_zi) < 0.01\n\n# TA - Request tare weight\ntare = await scale.request_tare_weight()\nassert isinstance(tare, float)\n\n# TAC - Clear tare\nawait backend.clear_tare()\ntare_after = await scale.request_tare_weight()\nassert abs(tare_after) < 0.001\n\nprint(\"PASS: all core Level 0/1 commands validated\")" + "# @ - Cancel (returns serial number)\n", + "sn = await backend.reset()\n", + "assert sn == backend.serial_number, f\"reset() returned {sn}, expected {backend.serial_number}\"\n", + "\n", + "# I4 - Serial number\n", + "sn2 = await backend.request_serial_number()\n", + "assert sn2 == sn\n", + "\n", + "# I2 - Device type and capacity\n", + "dt = await backend.request_device_type()\n", + "assert len(dt) > 0\n", + "cap = await backend.request_capacity()\n", + "assert cap > 0\n", + "\n", + "# S - Stable weight\n", + "w_stable = await backend.read_stable_weight()\n", + "assert isinstance(w_stable, float)\n", + "\n", + "# SI - Weight immediately\n", + "w_imm = await backend.read_weight_value_immediately()\n", + "assert isinstance(w_imm, float)\n", + "\n", + "# Z - Zero (stable) then read\n", + "await scale.zero(timeout=\"stable\")\n", + "w_after_zero = await backend.read_weight_value_immediately()\n", + "assert abs(w_after_zero) < 0.001, f\"Expected ~0 after zero, got {w_after_zero}\"\n", + "\n", + "# ZI - Zero immediately then read\n", + "await scale.zero(timeout=0)\n", + "w_after_zi = await backend.read_weight_value_immediately()\n", + "assert abs(w_after_zi) < 0.01\n", + "\n", + "# TA - Request tare weight\n", + "tare = await scale.request_tare_weight()\n", + "assert isinstance(tare, float)\n", + "\n", + "# TAC - Clear tare\n", + "await backend.clear_tare()\n", + "tare_after = await scale.request_tare_weight()\n", + "assert abs(tare_after) < 0.001\n", + "\n", + "print(\"PASS: all core Level 0/1 commands validated\")" ] }, { @@ -847,53 +813,9 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stdin", - "output_type": "stream", - "text": [ - "Place a container on the scale and press Enter... \n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2026-03-30 13:22:27,132 - pylabrobot - IO - [MT Scale] Sent command: Z\n", - "2026-03-30 13:22:27,134 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'Z\\r\\n'\n", - "2026-03-30 13:22:27,509 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'Z A\\r\\n'\n", - "2026-03-30 13:22:27,510 - pylabrobot - IO - [MT Scale] Received response: b'Z A\\r\\n'\n", - "2026-03-30 13:22:27,511 - pylabrobot - IO - [MT Scale] Sent command: T\n", - "2026-03-30 13:22:27,512 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'T\\r\\n'\n", - "2026-03-30 13:22:27,925 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'T S 0.00000 g\\r\\n'\n", - "2026-03-30 13:22:27,925 - pylabrobot - IO - [MT Scale] Received response: b'T S 0.00000 g\\r\\n'\n", - "2026-03-30 13:22:27,926 - pylabrobot - IO - [MT Scale] Sent command: TA\n", - "2026-03-30 13:22:27,927 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'TA\\r\\n'\n", - "2026-03-30 13:22:28,021 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'TA A 0.00000 g\\r\\n'\n", - "2026-03-30 13:22:28,022 - pylabrobot - IO - [MT Scale] Received response: b'TA A 0.00000 g\\r\\n'\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Tare weight: 0.0 g\n" - ] - }, - { - "ename": "AssertionError", - "evalue": "Expected positive tare, got 0.0", - "output_type": "error", - "traceback": [ - "\u001b[31m---------------------------------------------------------------------------\u001b[39m", - "\u001b[31mAssertionError\u001b[39m Traceback (most recent call last)", - "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[8]\u001b[39m\u001b[32m, line 6\u001b[39m\n\u001b[32m 4\u001b[39m tare = \u001b[38;5;28;01mawait\u001b[39;00m scale.request_tare_weight()\n\u001b[32m 5\u001b[39m \u001b[38;5;28mprint\u001b[39m(\u001b[33mf\u001b[39m\u001b[33m\"\u001b[39m\u001b[33mTare weight: \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mtare\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m g\u001b[39m\u001b[33m\"\u001b[39m)\n\u001b[32m----> \u001b[39m\u001b[32m6\u001b[39m \u001b[38;5;28;01massert\u001b[39;00m tare > \u001b[32m0\u001b[39m, \u001b[33mf\u001b[39m\u001b[33m\"\u001b[39m\u001b[33mExpected positive tare, got \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mtare\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m\"\u001b[39m\n\u001b[32m 7\u001b[39m \u001b[38;5;28mprint\u001b[39m(\u001b[33m\"\u001b[39m\u001b[33mPASS: tare stores container weight\u001b[39m\u001b[33m\"\u001b[39m)\n", - "\u001b[31mAssertionError\u001b[39m: Expected positive tare, got 0.0" - ] - } - ], + "outputs": [], "source": [ "input(\"Place a container on the scale and press Enter...\")\n", "await scale.zero(timeout=\"stable\")\n", @@ -913,28 +835,9 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2026-03-30 13:22:31,147 - pylabrobot - IO - [MT Scale] Sent command: TA\n", - "2026-03-30 13:22:31,151 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'TA\\r\\n'\n", - "2026-03-30 13:22:31,251 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'TA A 0.00000 g\\r\\n'\n", - "2026-03-30 13:22:31,252 - pylabrobot - IO - [MT Scale] Received response: b'TA A 0.00000 g\\r\\n'\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Tare weight from memory: 0.0 g\n", - "PASS: tare weight readable from memory\n" - ] - } - ], + "outputs": [], "source": [ "tare = await scale.request_tare_weight()\n", "print(f\"Tare weight from memory: {tare} g\")\n", @@ -951,32 +854,9 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2026-03-30 13:22:32,399 - pylabrobot - IO - [MT Scale] Sent command: TAC\n", - "2026-03-30 13:22:32,401 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'TAC\\r\\n'\n", - "2026-03-30 13:22:32,434 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'TAC A\\r\\n'\n", - "2026-03-30 13:22:32,435 - pylabrobot - IO - [MT Scale] Received response: b'TAC A\\r\\n'\n", - "2026-03-30 13:22:32,436 - pylabrobot - IO - [MT Scale] Sent command: TA\n", - "2026-03-30 13:22:32,440 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'TA\\r\\n'\n", - "2026-03-30 13:22:32,532 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'TA A 0.00000 g\\r\\n'\n", - "2026-03-30 13:22:32,533 - pylabrobot - IO - [MT Scale] Received response: b'TA A 0.00000 g\\r\\n'\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Tare after clear: 0.0 g\n", - "PASS: clear tare resets tare to 0\n" - ] - } - ], + "outputs": [], "source": [ "await backend.clear_tare()\n", "tare_after_clear = await scale.request_tare_weight()\n", @@ -1002,27 +882,9 @@ }, { "cell_type": "code", - "execution_count": 11, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2026-03-30 13:22:34,042 - pylabrobot - IO - [MT Scale] Sent command: M21 0 0\n", - "2026-03-30 13:22:34,044 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'M21 0 0\\r\\n'\n", - "2026-03-30 13:22:34,082 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M21 A\\r\\n'\n", - "2026-03-30 13:22:34,085 - pylabrobot - IO - [MT Scale] Received response: b'M21 A\\r\\n'\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "PASS: host unit set to grams\n" - ] - } - ], + "outputs": [], "source": [ "if \"M21\" in backend._supported_commands:\n", " await backend.set_host_unit_grams()\n", @@ -1040,17 +902,9 @@ }, { "cell_type": "code", - "execution_count": 12, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "SKIP: I50 not supported on this device\n" - ] - } - ], + "outputs": [], "source": [ "if \"I50\" in backend._supported_commands:\n", " remaining = await backend.request_remaining_weighing_range()\n", @@ -1071,30 +925,9 @@ }, { "cell_type": "code", - "execution_count": 13, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2026-03-30 13:22:37,302 - pylabrobot - IO - [MT Scale] Sent command: M28\n", - "2026-03-30 13:22:37,305 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'M28\\r\\n'\n", - "2026-03-30 13:22:37,341 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M28 B 1 20.1\\r\\n'\n", - "2026-03-30 13:22:37,342 - pylabrobot - IO - [MT Scale] Received response: b'M28 B 1 20.1\\r\\n'\n", - "2026-03-30 13:22:37,359 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M28 A 2 19.6\\r\\n'\n", - "2026-03-30 13:22:37,360 - pylabrobot - IO - [MT Scale] Received response: b'M28 A 2 19.6\\r\\n'\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Scale temperature: 20.1 C\n", - "PASS: measure_temperature works - I0 correctly predicted M28 support\n" - ] - } - ], + "outputs": [], "source": [ "if \"M28\" in backend._supported_commands:\n", " temp = await backend.measure_temperature()\n", @@ -1116,312 +949,9 @@ }, { "cell_type": "code", - "execution_count": 14, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2026-03-30 13:22:39,846 - pylabrobot - IO - [MT Scale] Sent command: M01\n", - "2026-03-30 13:22:39,848 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'M01\\r\\n'\n", - "2026-03-30 13:22:39,883 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M01 A 0\\r\\n'\n", - "2026-03-30 13:22:39,883 - pylabrobot - IO - [MT Scale] Received response: b'M01 A 0\\r\\n'\n", - "2026-03-30 13:22:39,885 - pylabrobot - IO - [MT Scale] Sent command: M02\n", - "2026-03-30 13:22:39,887 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'M02\\r\\n'\n", - "2026-03-30 13:22:39,915 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M02 A 2\\r\\n'\n", - "2026-03-30 13:22:39,917 - pylabrobot - IO - [MT Scale] Received response: b'M02 A 2\\r\\n'\n", - "2026-03-30 13:22:39,918 - pylabrobot - IO - [MT Scale] Sent command: M03\n", - "2026-03-30 13:22:39,920 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'M03\\r\\n'\n", - "2026-03-30 13:22:39,947 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M03 A 0\\r\\n'\n", - "2026-03-30 13:22:39,949 - pylabrobot - IO - [MT Scale] Received response: b'M03 A 0\\r\\n'\n", - "2026-03-30 13:22:39,951 - pylabrobot - IO - [MT Scale] Sent command: M27\n", - "2026-03-30 13:22:39,953 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'M27\\r\\n'\n", - "2026-03-30 13:22:40,013 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 1 13 05 2020 17 17 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:40,018 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 1 13 05 2020 17 17 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:40,043 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 2 02 12 2019 20 02 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:40,044 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 2 02 12 2019 20 02 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:40,075 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 3 11 10 2019 17 05 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:40,076 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 3 11 10 2019 17 05 0 \"\"\\r\\n'\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Weighing mode: 0 (Normal/Universal)\n", - "Environment condition: 2 (Standard)\n", - "Auto zero: 0 (off)\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2026-03-30 13:22:40,106 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 4 11 10 2019 17 01 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:40,110 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 4 11 10 2019 17 01 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:40,138 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 5 14 03 2019 20 22 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:40,140 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 5 14 03 2019 20 22 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:40,171 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 6 14 03 2019 20 18 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:40,172 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 6 14 03 2019 20 18 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:40,203 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 7 17 10 2018 17 38 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:40,204 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 7 17 10 2018 17 38 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:40,235 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 8 17 10 2018 17 37 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:40,240 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 8 17 10 2018 17 37 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:40,267 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 9 17 10 2018 17 35 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:40,269 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 9 17 10 2018 17 35 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:40,298 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 10 20 09 2018 21 23 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:40,302 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 10 20 09 2018 21 23 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:40,332 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 11 15 03 2018 23 51 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:40,333 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 11 15 03 2018 23 51 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:40,364 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 12 16 12 2017 00 20 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:40,368 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 12 16 12 2017 00 20 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:40,394 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 13 16 12 2017 00 18 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:40,397 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 13 16 12 2017 00 18 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:40,428 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 14 18 10 2017 12 06 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:40,430 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 14 18 10 2017 12 06 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:40,458 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 15 18 10 2017 11 58 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:40,460 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 15 18 10 2017 11 58 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:40,491 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 16 05 09 2017 22 40 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:40,492 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 16 05 09 2017 22 40 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:40,540 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 17 21 06 2017 18 39 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:40,544 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 17 21 06 2017 18 39 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:40,572 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 18 30 03 2017 19 24 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:40,578 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 18 30 03 2017 19 24 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:40,602 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 19 09 03 2017 23 21 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:40,605 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 19 09 03 2017 23 21 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:40,636 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 20 09 03 2017 23 19 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:40,637 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 20 09 03 2017 23 19 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:40,667 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 21 20 12 2016 21 55 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:40,668 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 21 20 12 2016 21 55 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:40,700 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 22 19 10 2016 17 36 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:40,701 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 22 19 10 2016 17 36 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:40,731 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 23 19 10 2016 17 33 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:40,732 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 23 19 10 2016 17 33 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:40,762 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 24 18 10 2016 21 00 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:40,764 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 24 18 10 2016 21 00 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:40,794 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 25 18 10 2016 18 47 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:40,796 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 25 18 10 2016 18 47 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:40,826 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 26 18 10 2016 15 33 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:40,827 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 26 18 10 2016 15 33 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:40,858 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 27 18 10 2016 14 32 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:40,859 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 27 18 10 2016 14 32 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:40,907 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 28 18 10 2016 14 28 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:40,910 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 28 18 10 2016 14 28 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:40,938 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 29 18 10 2016 13 41 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:40,939 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 29 18 10 2016 13 41 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:40,970 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 30 21 09 2016 15 15 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:40,971 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 30 21 09 2016 15 15 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:41,003 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 31 04 03 2016 22 28 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:41,006 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 31 04 03 2016 22 28 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:41,036 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 32 01 10 2015 19 06 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:41,037 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 32 01 10 2015 19 06 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:41,067 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 33 01 10 2015 18 56 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:41,068 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 33 01 10 2015 18 56 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:41,099 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 34 03 09 2015 22 11 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:41,101 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 34 03 09 2015 22 11 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:41,130 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 35 11 03 2015 13 20 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:41,132 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 35 11 03 2015 13 20 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:41,162 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 36 11 03 2015 13 18 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:41,163 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 36 11 03 2015 13 18 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:41,195 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 37 11 03 2015 13 15 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:41,197 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 37 11 03 2015 13 15 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:41,228 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 38 11 03 2015 13 13 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:41,229 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 38 11 03 2015 13 13 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:41,260 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 39 22 01 2015 03 17 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:41,261 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 39 22 01 2015 03 17 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:41,306 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 40 22 01 2015 03 15 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:41,306 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 40 22 01 2015 03 15 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:41,337 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 41 06 11 2014 17 08 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:41,338 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 41 06 11 2014 17 08 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:41,370 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 42 06 11 2014 16 22 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:41,371 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 42 06 11 2014 16 22 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:41,402 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 43 06 11 2014 16 20 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:41,402 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 43 06 11 2014 16 20 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:41,434 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 44 06 11 2014 15 57 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:41,435 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 44 06 11 2014 15 57 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:41,466 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 45 18 09 2014 20 23 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:41,467 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 45 18 09 2014 20 23 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:41,501 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 46 18 09 2014 19 54 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:41,503 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 46 18 09 2014 19 54 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:41,532 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 47 18 09 2014 19 44 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:41,533 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 47 18 09 2014 19 44 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:41,562 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 48 18 09 2014 19 35 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:41,563 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 48 18 09 2014 19 35 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:41,594 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 49 15 09 2014 20 08 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:41,595 - pylabrobot - IO - [MT Scale] Received response: b'M27 B 49 15 09 2014 20 08 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:41,627 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 A 50 15 09 2014 19 39 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:41,628 - pylabrobot - IO - [MT Scale] Received response: b'M27 A 50 15 09 2014 19 39 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:41,632 - pylabrobot - IO - [MT Scale] Sent command: UPD\n", - "2026-03-30 13:22:41,636 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'UPD\\r\\n'\n", - "2026-03-30 13:22:41,674 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'UPD A 10.173\\r\\n'\n", - "2026-03-30 13:22:41,674 - pylabrobot - IO - [MT Scale] Received response: b'UPD A 10.173\\r\\n'\n", - "2026-03-30 13:22:41,676 - pylabrobot - IO - [MT Scale] Sent command: SIS\n", - "2026-03-30 13:22:41,680 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SIS\\r\\n'\n", - "2026-03-30 13:22:41,722 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'SIS A 0 \"0.00000\" 0 5 1 0 0\\r\\n'\n", - "2026-03-30 13:22:41,723 - pylabrobot - IO - [MT Scale] Received response: b'SIS A 0 \"0.00000\" 0 5 1 0 0\\r\\n'\n", - "2026-03-30 13:22:41,724 - pylabrobot - IO - [MT Scale] Sent command: LST\n", - "2026-03-30 13:22:41,728 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'LST\\r\\n'\n", - "2026-03-30 13:22:41,770 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B C0 0 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:41,770 - pylabrobot - IO - [MT Scale] Received response: b'LST B C0 0 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:41,785 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B FCUT 0.000\\r\\n'\n", - "2026-03-30 13:22:41,786 - pylabrobot - IO - [MT Scale] Received response: b'LST B FCUT 0.000\\r\\n'\n", - "2026-03-30 13:22:41,802 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B I10 \"\"\\r\\n'\n", - "2026-03-30 13:22:41,803 - pylabrobot - IO - [MT Scale] Received response: b'LST B I10 \"\"\\r\\n'\n", - "2026-03-30 13:22:41,817 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B M01 0\\r\\n'\n", - "2026-03-30 13:22:41,818 - pylabrobot - IO - [MT Scale] Received response: b'LST B M01 0\\r\\n'\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "Adjustment history (50 entries):\n", - " M27 B 1 13 05 2020 17 17 0 \n", - " M27 B 2 02 12 2019 20 02 0 \n", - " M27 B 3 11 10 2019 17 05 0 \n", - " M27 B 4 11 10 2019 17 01 0 \n", - " M27 B 5 14 03 2019 20 22 0 \n", - " M27 B 6 14 03 2019 20 18 0 \n", - " M27 B 7 17 10 2018 17 38 0 \n", - " M27 B 8 17 10 2018 17 37 0 \n", - " M27 B 9 17 10 2018 17 35 0 \n", - " M27 B 10 20 09 2018 21 23 0 \n", - " M27 B 11 15 03 2018 23 51 0 \n", - " M27 B 12 16 12 2017 00 20 0 \n", - " M27 B 13 16 12 2017 00 18 0 \n", - " M27 B 14 18 10 2017 12 06 0 \n", - " M27 B 15 18 10 2017 11 58 0 \n", - " M27 B 16 05 09 2017 22 40 0 \n", - " M27 B 17 21 06 2017 18 39 0 \n", - " M27 B 18 30 03 2017 19 24 0 \n", - " M27 B 19 09 03 2017 23 21 0 \n", - " M27 B 20 09 03 2017 23 19 0 \n", - " M27 B 21 20 12 2016 21 55 0 \n", - " M27 B 22 19 10 2016 17 36 0 \n", - " M27 B 23 19 10 2016 17 33 0 \n", - " M27 B 24 18 10 2016 21 00 0 \n", - " M27 B 25 18 10 2016 18 47 0 \n", - " M27 B 26 18 10 2016 15 33 0 \n", - " M27 B 27 18 10 2016 14 32 0 \n", - " M27 B 28 18 10 2016 14 28 0 \n", - " M27 B 29 18 10 2016 13 41 0 \n", - " M27 B 30 21 09 2016 15 15 0 \n", - " M27 B 31 04 03 2016 22 28 0 \n", - " M27 B 32 01 10 2015 19 06 0 \n", - " M27 B 33 01 10 2015 18 56 0 \n", - " M27 B 34 03 09 2015 22 11 0 \n", - " M27 B 35 11 03 2015 13 20 0 \n", - " M27 B 36 11 03 2015 13 18 0 \n", - " M27 B 37 11 03 2015 13 15 0 \n", - " M27 B 38 11 03 2015 13 13 0 \n", - " M27 B 39 22 01 2015 03 17 0 \n", - " M27 B 40 22 01 2015 03 15 0 \n", - " M27 B 41 06 11 2014 17 08 0 \n", - " M27 B 42 06 11 2014 16 22 0 \n", - " M27 B 43 06 11 2014 16 20 0 \n", - " M27 B 44 06 11 2014 15 57 0 \n", - " M27 B 45 18 09 2014 20 23 0 \n", - " M27 B 46 18 09 2014 19 54 0 \n", - " M27 B 47 18 09 2014 19 44 0 \n", - " M27 B 48 18 09 2014 19 35 0 \n", - " M27 B 49 15 09 2014 20 08 0 \n", - " M27 A 50 15 09 2014 19 39 0 \n", - "\n", - "Update rate: 10.173 values/s\n", - "\n", - "Net weight with status: SIS A 0 0.00000 0 5 1 0 0\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2026-03-30 13:22:41,833 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B M02 2\\r\\n'\n", - "2026-03-30 13:22:41,834 - pylabrobot - IO - [MT Scale] Received response: b'LST B M02 2\\r\\n'\n", - "2026-03-30 13:22:41,839 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B M03 0\\r\\n'\n", - "2026-03-30 13:22:41,841 - pylabrobot - IO - [MT Scale] Received response: b'LST B M03 0\\r\\n'\n", - "2026-03-30 13:22:41,865 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B M17 00 00 00 0\\r\\n'\n", - "2026-03-30 13:22:41,867 - pylabrobot - IO - [MT Scale] Received response: b'LST B M17 00 00 00 0\\r\\n'\n", - "2026-03-30 13:22:41,883 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B M18 1\\r\\n'\n", - "2026-03-30 13:22:41,884 - pylabrobot - IO - [MT Scale] Received response: b'LST B M18 1\\r\\n'\n", - "2026-03-30 13:22:41,897 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B M19 10.00000 g\\r\\n'\n", - "2026-03-30 13:22:41,898 - pylabrobot - IO - [MT Scale] Received response: b'LST B M19 10.00000 g\\r\\n'\n", - "2026-03-30 13:22:41,929 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B M20 200.00000 g\\r\\n'\n", - "2026-03-30 13:22:41,930 - pylabrobot - IO - [MT Scale] Received response: b'LST B M20 200.00000 g\\r\\n'\n", - "2026-03-30 13:22:41,945 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B M21 0 0\\r\\n'\n", - "2026-03-30 13:22:41,946 - pylabrobot - IO - [MT Scale] Received response: b'LST B M21 0 0\\r\\n'\n", - "2026-03-30 13:22:41,948 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B M29 1\\r\\n'\n", - "2026-03-30 13:22:41,949 - pylabrobot - IO - [MT Scale] Received response: b'LST B M29 1\\r\\n'\n", - "2026-03-30 13:22:41,961 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B M31 0\\r\\n'\n", - "2026-03-30 13:22:41,962 - pylabrobot - IO - [MT Scale] Received response: b'LST B M31 0\\r\\n'\n", - "2026-03-30 13:22:41,994 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B M32 1 00 00 0\\r\\n'\n", - "2026-03-30 13:22:41,996 - pylabrobot - IO - [MT Scale] Received response: b'LST B M32 1 00 00 0\\r\\n'\n", - "2026-03-30 13:22:42,010 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B M32 2 00 00 0\\r\\n'\n", - "2026-03-30 13:22:42,011 - pylabrobot - IO - [MT Scale] Received response: b'LST B M32 2 00 00 0\\r\\n'\n", - "2026-03-30 13:22:42,027 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B M32 3 00 00 0\\r\\n'\n", - "2026-03-30 13:22:42,029 - pylabrobot - IO - [MT Scale] Received response: b'LST B M32 3 00 00 0\\r\\n'\n", - "2026-03-30 13:22:42,043 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B M33 0\\r\\n'\n", - "2026-03-30 13:22:42,045 - pylabrobot - IO - [MT Scale] Received response: b'LST B M33 0\\r\\n'\n", - "2026-03-30 13:22:42,057 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B M35 0\\r\\n'\n", - "2026-03-30 13:22:42,058 - pylabrobot - IO - [MT Scale] Received response: b'LST B M35 0\\r\\n'\n", - "2026-03-30 13:22:42,073 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B RDB 5\\r\\n'\n", - "2026-03-30 13:22:42,074 - pylabrobot - IO - [MT Scale] Received response: b'LST B RDB 5\\r\\n'\n", - "2026-03-30 13:22:42,089 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B TST0 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:42,090 - pylabrobot - IO - [MT Scale] Received response: b'LST B TST0 0 \"\"\\r\\n'\n", - "2026-03-30 13:22:42,107 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B UPD 10.173\\r\\n'\n", - "2026-03-30 13:22:42,114 - pylabrobot - IO - [MT Scale] Received response: b'LST B UPD 10.173\\r\\n'\n", - "2026-03-30 13:22:42,137 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B USTB 0 3.600 1.100\\r\\n'\n", - "2026-03-30 13:22:42,139 - pylabrobot - IO - [MT Scale] Received response: b'LST B USTB 0 3.600 1.100\\r\\n'\n", - "2026-03-30 13:22:42,169 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B USTB 1 0.000 0.000\\r\\n'\n", - "2026-03-30 13:22:42,170 - pylabrobot - IO - [MT Scale] Received response: b'LST B USTB 1 0.000 0.000\\r\\n'\n", - "2026-03-30 13:22:42,187 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST A USTB 2 0.000 0.000\\r\\n'\n", - "2026-03-30 13:22:42,189 - pylabrobot - IO - [MT Scale] Received response: b'LST A USTB 2 0.000 0.000\\r\\n'\n", - "2026-03-30 13:22:42,195 - pylabrobot - IO - [MT Scale] Sent command: RDB\n", - "2026-03-30 13:22:42,204 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'RDB\\r\\n'\n", - "2026-03-30 13:22:42,234 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'RDB A 5\\r\\n'\n", - "2026-03-30 13:22:42,235 - pylabrobot - IO - [MT Scale] Received response: b'RDB A 5\\r\\n'\n", - "2026-03-30 13:22:42,237 - pylabrobot - IO - [MT Scale] Sent command: USTB\n", - "2026-03-30 13:22:42,243 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'USTB\\r\\n'\n", - "2026-03-30 13:22:42,282 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'USTB B 0 3.600 1.100\\r\\n'\n", - "2026-03-30 13:22:42,283 - pylabrobot - IO - [MT Scale] Received response: b'USTB B 0 3.600 1.100\\r\\n'\n", - "2026-03-30 13:22:42,314 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'USTB B 1 0.000 0.000\\r\\n'\n", - "2026-03-30 13:22:42,315 - pylabrobot - IO - [MT Scale] Received response: b'USTB B 1 0.000 0.000\\r\\n'\n", - "2026-03-30 13:22:42,329 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'USTB A 2 0.000 0.000\\r\\n'\n", - "2026-03-30 13:22:42,331 - pylabrobot - IO - [MT Scale] Received response: b'USTB A 2 0.000 0.000\\r\\n'\n", - "2026-03-30 13:22:42,332 - pylabrobot - IO - [MT Scale] Sent command: FCUT\n", - "2026-03-30 13:22:42,338 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'FCUT\\r\\n'\n", - "2026-03-30 13:22:42,377 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'FCUT A 0.000\\r\\n'\n", - "2026-03-30 13:22:42,379 - pylabrobot - IO - [MT Scale] Received response: b'FCUT A 0.000\\r\\n'\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "Current user settings (24 lines):\n", - " LST B C0 0 0 \n", - " LST B FCUT 0.000\n", - " LST B I10 \n", - " LST B M01 0\n", - " LST B M02 2\n", - " LST B M03 0\n", - " LST B M17 00 00 00 0\n", - " LST B M18 1\n", - " LST B M19 10.00000 g\n", - " LST B M20 200.00000 g\n", - " ... (24 lines total)\n", - "\n", - "Readability: RDB A 5\n", - "Stability criteria: USTB B 0 3.600 1.100\n", - "Filter cut-off: FCUT A 0.000\n", - "\n", - "PASS: Batch 2+3 read-only configuration queries completed\n" - ] - } - ], + "outputs": [], "source": [ "# M01 - Weighing mode (read-only query)\n", "if \"M01\" in backend._supported_commands:\n", @@ -1538,7 +1068,16 @@ { "cell_type": "markdown", "metadata": {}, - "source": "### SIS unit code verification (exploratory)\n\nTests whether field index 4 in the SIS response is the unit code by temporarily\nchanging the host unit via M21, reading SIS, then restoring grams.\n\n**WARNING:** Temporarily writes a non-gram unit to device memory via M21.\nIf the cell fails mid-execution, run `await backend.set_host_unit_grams()`\nmanually to restore grams. setup() also restores grams on next connection." + "source": [ + "### SIS unit code verification (exploratory)\n", + "\n", + "Tests whether field index 4 in the SIS response is the unit code by temporarily\n", + "changing the host unit via M21, reading SIS, then restoring grams.\n", + "\n", + "**WARNING:** Temporarily writes a non-gram unit to device memory via M21.\n", + "If the cell fails mid-execution, run `await backend.set_host_unit_grams()`\n", + "manually to restore grams. setup() also restores grams on next connection." + ] }, { "cell_type": "code", @@ -1585,70 +1124,9 @@ }, { "cell_type": "code", - "execution_count": 15, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2026-03-30 13:23:14,769 - pylabrobot - IO - [MT Scale] Sent command: Z\n", - "2026-03-30 13:23:14,772 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'Z\\r\\n'\n", - "2026-03-30 13:23:15,084 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'Z A\\r\\n'\n", - "2026-03-30 13:23:15,085 - pylabrobot - IO - [MT Scale] Received response: b'Z A\\r\\n'\n", - "2026-03-30 13:23:15,087 - pylabrobot - IO - [MT Scale] Sent command: SI\n", - "2026-03-30 13:23:15,091 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", - "2026-03-30 13:23:15,132 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 13:23:15,139 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00000 g\\r\\n'\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Frontend zero + read: 0.0 g\n" - ] - }, - { - "name": "stdin", - "output_type": "stream", - "text": [ - "Place a container on the scale and press Enter... \n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2026-03-30 13:23:16,272 - pylabrobot - IO - [MT Scale] Sent command: T\n", - "2026-03-30 13:23:16,274 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'T\\r\\n'\n", - "2026-03-30 13:23:16,668 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'T S 0.00000 g\\r\\n'\n", - "2026-03-30 13:23:16,669 - pylabrobot - IO - [MT Scale] Received response: b'T S 0.00000 g\\r\\n'\n", - "2026-03-30 13:23:16,671 - pylabrobot - IO - [MT Scale] Sent command: TA\n", - "2026-03-30 13:23:16,672 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'TA\\r\\n'\n", - "2026-03-30 13:23:16,763 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'TA A 0.00000 g\\r\\n'\n", - "2026-03-30 13:23:16,763 - pylabrobot - IO - [MT Scale] Received response: b'TA A 0.00000 g\\r\\n'\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Frontend tare weight: 0.0 g\n" - ] - }, - { - "ename": "AssertionError", - "evalue": "", - "output_type": "error", - "traceback": [ - "\u001b[31m---------------------------------------------------------------------------\u001b[39m", - "\u001b[31mAssertionError\u001b[39m Traceback (most recent call last)", - "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[15]\u001b[39m\u001b[32m, line 12\u001b[39m\n\u001b[32m 10\u001b[39m tare = \u001b[38;5;28;01mawait\u001b[39;00m scale.request_tare_weight()\n\u001b[32m 11\u001b[39m \u001b[38;5;28mprint\u001b[39m(\u001b[33mf\u001b[39m\u001b[33m\"\u001b[39m\u001b[33mFrontend tare weight: \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mtare\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m g\u001b[39m\u001b[33m\"\u001b[39m)\n\u001b[32m---> \u001b[39m\u001b[32m12\u001b[39m \u001b[38;5;28;01massert\u001b[39;00m tare > \u001b[32m0\u001b[39m\n\u001b[32m 14\u001b[39m \u001b[38;5;66;03m# Read via frontend\u001b[39;00m\n\u001b[32m 15\u001b[39m w = \u001b[38;5;28;01mawait\u001b[39;00m scale.read_weight(timeout=\u001b[33m\"\u001b[39m\u001b[33mstable\u001b[39m\u001b[33m\"\u001b[39m)\n", - "\u001b[31mAssertionError\u001b[39m: " - ] - } - ], + "outputs": [], "source": [ "# Zero via frontend\n", "await scale.zero(timeout=\"stable\")\n", @@ -1683,7 +1161,9 @@ }, { "cell_type": "code", + "execution_count": null, "metadata": {}, + "outputs": [], "source": [ "for cmd in [\"I22\", \"I23\", \"I24\", \"I25\"]:\n", " try:\n", @@ -1693,9 +1173,7 @@ " except Exception as e:\n", " print(f\"{cmd}: {type(e).__name__}: {e}\")\n", " print()" - ], - "outputs": [], - "execution_count": null + ] }, { "cell_type": "markdown", @@ -1707,104 +1185,9 @@ }, { "cell_type": "code", - "execution_count": 16, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2026-03-30 13:23:25,471 - pylabrobot - IO - [MT Scale] Sent command: S\n", - "2026-03-30 13:23:25,473 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", - "2026-03-30 13:23:25,508 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00001 g\\r\\n'\n", - "2026-03-30 13:23:25,509 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00001 g\\r\\n'\n", - "2026-03-30 13:23:25,509 - pylabrobot - IO - [MT Scale] Sent command: S\n", - "2026-03-30 13:23:25,511 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", - "2026-03-30 13:23:25,604 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00001 g\\r\\n'\n", - "2026-03-30 13:23:25,605 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00001 g\\r\\n'\n", - "2026-03-30 13:23:25,605 - pylabrobot - IO - [MT Scale] Sent command: S\n", - "2026-03-30 13:23:25,606 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", - "2026-03-30 13:23:25,699 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00001 g\\r\\n'\n", - "2026-03-30 13:23:25,700 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00001 g\\r\\n'\n", - "2026-03-30 13:23:25,700 - pylabrobot - IO - [MT Scale] Sent command: S\n", - "2026-03-30 13:23:25,701 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", - "2026-03-30 13:23:25,811 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00001 g\\r\\n'\n", - "2026-03-30 13:23:25,812 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00001 g\\r\\n'\n", - "2026-03-30 13:23:25,813 - pylabrobot - IO - [MT Scale] Sent command: S\n", - "2026-03-30 13:23:25,815 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", - "2026-03-30 13:23:25,908 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00001 g\\r\\n'\n", - "2026-03-30 13:23:25,908 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00001 g\\r\\n'\n", - "2026-03-30 13:23:25,909 - pylabrobot - IO - [MT Scale] Sent command: S\n", - "2026-03-30 13:23:25,910 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", - "2026-03-30 13:23:26,004 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00001 g\\r\\n'\n", - "2026-03-30 13:23:26,004 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00001 g\\r\\n'\n", - "2026-03-30 13:23:26,005 - pylabrobot - IO - [MT Scale] Sent command: S\n", - "2026-03-30 13:23:26,006 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", - "2026-03-30 13:23:26,099 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00001 g\\r\\n'\n", - "2026-03-30 13:23:26,100 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00001 g\\r\\n'\n", - "2026-03-30 13:23:26,100 - pylabrobot - IO - [MT Scale] Sent command: S\n", - "2026-03-30 13:23:26,101 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", - "2026-03-30 13:23:26,195 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00001 g\\r\\n'\n", - "2026-03-30 13:23:26,196 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00001 g\\r\\n'\n", - "2026-03-30 13:23:26,196 - pylabrobot - IO - [MT Scale] Sent command: S\n", - "2026-03-30 13:23:26,197 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", - "2026-03-30 13:23:26,291 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00001 g\\r\\n'\n", - "2026-03-30 13:23:26,292 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00001 g\\r\\n'\n", - "2026-03-30 13:23:26,293 - pylabrobot - IO - [MT Scale] Sent command: S\n", - "2026-03-30 13:23:26,293 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", - "2026-03-30 13:23:26,388 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00001 g\\r\\n'\n", - "2026-03-30 13:23:26,388 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00001 g\\r\\n'\n", - "2026-03-30 13:23:26,389 - pylabrobot - IO - [MT Scale] Sent command: SI\n", - "2026-03-30 13:23:26,390 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", - "2026-03-30 13:23:26,435 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00001 g\\r\\n'\n", - "2026-03-30 13:23:26,436 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00001 g\\r\\n'\n", - "2026-03-30 13:23:26,437 - pylabrobot - IO - [MT Scale] Sent command: SI\n", - "2026-03-30 13:23:26,445 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", - "2026-03-30 13:23:26,483 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00001 g\\r\\n'\n", - "2026-03-30 13:23:26,485 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00001 g\\r\\n'\n", - "2026-03-30 13:23:26,487 - pylabrobot - IO - [MT Scale] Sent command: SI\n", - "2026-03-30 13:23:26,488 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", - "2026-03-30 13:23:26,531 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00001 g\\r\\n'\n", - "2026-03-30 13:23:26,532 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00001 g\\r\\n'\n", - "2026-03-30 13:23:26,533 - pylabrobot - IO - [MT Scale] Sent command: SI\n", - "2026-03-30 13:23:26,535 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", - "2026-03-30 13:23:26,563 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00001 g\\r\\n'\n", - "2026-03-30 13:23:26,564 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00001 g\\r\\n'\n", - "2026-03-30 13:23:26,566 - pylabrobot - IO - [MT Scale] Sent command: SI\n", - "2026-03-30 13:23:26,568 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", - "2026-03-30 13:23:26,611 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00001 g\\r\\n'\n", - "2026-03-30 13:23:26,614 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00001 g\\r\\n'\n", - "2026-03-30 13:23:26,617 - pylabrobot - IO - [MT Scale] Sent command: SI\n", - "2026-03-30 13:23:26,619 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", - "2026-03-30 13:23:26,659 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00001 g\\r\\n'\n", - "2026-03-30 13:23:26,661 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00001 g\\r\\n'\n", - "2026-03-30 13:23:26,664 - pylabrobot - IO - [MT Scale] Sent command: SI\n", - "2026-03-30 13:23:26,665 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", - "2026-03-30 13:23:26,708 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00001 g\\r\\n'\n", - "2026-03-30 13:23:26,709 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00001 g\\r\\n'\n", - "2026-03-30 13:23:26,711 - pylabrobot - IO - [MT Scale] Sent command: SI\n", - "2026-03-30 13:23:26,717 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", - "2026-03-30 13:23:26,755 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00001 g\\r\\n'\n", - "2026-03-30 13:23:26,757 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00001 g\\r\\n'\n", - "2026-03-30 13:23:26,758 - pylabrobot - IO - [MT Scale] Sent command: SI\n", - "2026-03-30 13:23:26,759 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", - "2026-03-30 13:23:26,806 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00001 g\\r\\n'\n", - "2026-03-30 13:23:26,807 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00001 g\\r\\n'\n", - "2026-03-30 13:23:26,808 - pylabrobot - IO - [MT Scale] Sent command: SI\n", - "2026-03-30 13:23:26,811 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", - "2026-03-30 13:23:26,851 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00001 g\\r\\n'\n", - "2026-03-30 13:23:26,852 - pylabrobot - IO - [MT Scale] Received response: b'S S 0.00001 g\\r\\n'\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Stable read: 91.79 +/- 18.42 ms\n", - "Immediate read: 46.44 +/- 4.92 ms\n" - ] - } - ], + "outputs": [], "source": [ "import time\n", "\n", @@ -1840,30 +1223,9 @@ }, { "cell_type": "code", - "execution_count": 17, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2026-03-30 13:23:31,221 - pylabrobot - INFO - === Hardware validation ended ===\n", - "2026-03-30 13:23:31,225 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] reset_input_buffer\n", - "2026-03-30 13:23:31,230 - pylabrobot - IO - [MT Scale] Sent command: @\n", - "2026-03-30 13:23:31,234 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'@\\r\\n'\n", - "2026-03-30 13:23:31,297 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I4 A \"B207696838\"\\r\\n'\n", - "2026-03-30 13:23:31,300 - pylabrobot - IO - [MT Scale] Received response: b'I4 A \"B207696838\"\\r\\n'\n", - "2026-03-30 13:23:31,302 - pylabrobot - INFO - [MT Scale] Disconnected from /dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Log file: ./logs/hardware_validation/2026-03-30_13-22-09_validation.log\n" - ] - } - ], + "outputs": [], "source": [ "plr_logger.info(\"=== Hardware validation ended ===\")\n", "await scale.stop()\n", @@ -1899,4 +1261,4 @@ }, "nbformat": 4, "nbformat_minor": 4 -} \ No newline at end of file +} From 282ce29acd9259abebfc6df6e6b5428ee3acded7 Mon Sep 17 00:00:00 2001 From: Camillo Moschner Date: Mon, 30 Mar 2026 16:33:24 +0100 Subject: [PATCH 31/38] Replace getattr with command registry, align log prefix with IO device name, update notebooks --- .../scales/mettler-toledo-WXS205SDU.ipynb | 61 +--- pylabrobot/scales/mettler_toledo/backend.py | 44 +-- .../scales/mettler_toledo/backend_tests.py | 2 +- .../mettler_toledo/hardware_validation.ipynb | 269 ++++++++++-------- pylabrobot/scales/mettler_toledo/simulator.py | 11 +- 5 files changed, 197 insertions(+), 190 deletions(-) diff --git a/docs/user_guide/02_analytical/scales/mettler-toledo-WXS205SDU.ipynb b/docs/user_guide/02_analytical/scales/mettler-toledo-WXS205SDU.ipynb index 40724404423..b0ef1934069 100644 --- a/docs/user_guide/02_analytical/scales/mettler-toledo-WXS205SDU.ipynb +++ b/docs/user_guide/02_analytical/scales/mettler-toledo-WXS205SDU.ipynb @@ -4,11 +4,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "# Mettler Toledo Precision Scales\n", - "\n", - "| Summary | Image |\n", - "|------------|--------|\n", - "|
  • OEM Link
  • Communication Protocol / Hardware: Serial / RS-232
  • Communication Level: Firmware (documentation shared by OEM)
  • Compatibility: This backend has been extensively tested on the WXS205SDU (but according to firmware documentation is applicable to other Mettler Toledo \"Automated Precision Weigh Modules\", including the WX and WMS series)
  • VID:PID: 0x0403:0x6001
  • Description: High-precision fine balance with various adapters available.
  • Load range: 0 - 220 g
  • Readability: 0.1 mg
|
![shaker](img/mettler_toledo_wx_scale.png)
Figure: Mettler Toledo WXS205SDU used for gravimetric liquid transfer verification
|" + "# Mettler Toledo Precision Scales\n\n| Summary | Image |\n|------------|--------|\n|
  • OEM Link
  • Communication Protocol / Hardware: Serial / RS-232
  • Communication Level: Firmware (documentation shared by OEM)
  • Compatibility: This backend has been extensively tested on the WXS205SDU (but according to firmware documentation is applicable to other Mettler Toledo \"Automated Precision Weigh Modules\", including the WX and WMS series)
  • VID:PID: 0x0403:0x6001
  • Description: High-precision fine balance with various adapters available.
  • Load range: 0 - 220 g
  • Readability: 0.1 mg
|
![scale](img/mettler_toledo_wx_scale.png)
Figure: Mettler Toledo WXS205SDU used for gravimetric liquid transfer verification
|" ] }, { @@ -31,8 +27,8 @@ "\n", "| Configuration Name | Has Load Cell | Has Electronics Unit | Has Terminal/Display |\n", "|---------------|---------------|-----------------|---------------------|\n", - "| **Balance** | ✓ | ✓ | ✓ |\n", - "| **Weigh Module** (or \"Bridge\") | ✓ | ✓ | ✗ |\n", + "| **Balance** | \u2713 | \u2713 | \u2713 |\n", + "| **Weigh Module** (or \"Bridge\") | \u2713 | \u2713 | \u2717 |\n", "\n", "**Note:** When used with PyLabRobot, the terminal/display is optional since all control is done programmatically.\n", "\n", @@ -170,20 +166,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "```{Warning}\n", - "### Warm-up Time Required\n", - "\n", - "This scale requires a **warm-up period** after being powered on. Mettler Toledo documentation specifies 60 minutes, though in practice 30 minutes is often sufficient.\n", - "\n", - "If you attempt measurements before the scale has warmed up, you'll likely encounter an error: *\"Command understood but currently not executable (balance is currently executing another command)\"*.\n", - "\n", - "**Tip**: Sometimes power-cycling the scale (unplugging and replugging the power cord) can help resolve initialization issues.\n", - "```\n", - "\n", - "\n", - "```{Note}\n", - "This scale is the same model used in the Hamilton Liquid Verification Kit (LVK).\n", - "```" + "```{Warning}\n### Warm-up Time Required\n\nThis scale requires a **warm-up period** after being powered on. Mettler Toledo documentation specifies 60 minutes, though in practice 30 minutes is often sufficient.\n\nIf you attempt measurements before the scale has warmed up, you may see unstable readings or the scale may return status `I` (command understood but not currently executable).\n\n**Tip**: Sometimes power-cycling the scale (unplugging and replugging the power cord) can help resolve initialization issues.\n```\n\n\n```{Note}\nThis scale is the same model used in the Hamilton Liquid Verification Kit (LVK).\n```" ] }, { @@ -253,7 +236,7 @@ "Resets the scale reading to zero while accounting for the weight of a container already on the platform. Use this when you want to measure only the weight of material being added to a container.\n", "\n", "**Example workflow**:\n", - "Place an empty beaker on the scale → tare → dispense liquid → read only the liquid's weight." + "Place an empty beaker on the scale \u2192 tare \u2192 dispense liquid \u2192 read only the liquid's weight." ] }, { @@ -507,16 +490,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "---\n", - "### Backend-Specific Methods\n", - "\n", - "The MT-SICS backend exposes additional methods beyond the core scale interface.\n", - "\n", - "#### Remaining weighing range\n", - "\n", - "Query how much capacity is left on the scale, accounting for all current loads\n", - "(pre-load, tare, net). Useful for checking whether adding more weight would\n", - "exceed the scale's maximum capacity. Requires MT-SICS Level 2." + "---\n### Backend-Specific Methods\n\nThe MT-SICS backend exposes additional methods beyond the core scale interface.\n\n#### Remaining weighing range\n\nQuery how much capacity is left on the scale, accounting for all current loads\n(pre-load, tare, net). Useful for checking whether adding more weight would\nexceed the scale's maximum capacity." ] }, { @@ -576,10 +550,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "#### Temperature\n", - "\n", - "Read the current temperature from the scale's internal sensor. Useful for gravimetric\n", - "verification where temperature affects liquid density and evaporation rate. Requires MT-SICS Level 2." + "#### Temperature\n\nRead the current temperature from the scale's internal sensor. Useful for gravimetric\nverification where temperature affects liquid density and evaporation rate." ] }, { @@ -665,21 +636,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "---\n", - "### Teardown\n", - "\n", - "The scale resets the device to a clean state before disconnecting. If the serial\n", - "port is already broken (e.g. kernel crash), the reset is skipped gracefully.\n", - "\n", - "For scripts and automated protocols, use `async with` to guarantee cleanup even\n", - "if an error occurs:\n", - "\n", - "```python\n", - "async with Scale(name=\"scale\", backend=backend, size_x=0, size_y=0, size_z=0) as scale:\n", - " await scale.zero()\n", - " weight = await scale.read_weight()\n", - " # scale.stop() is called automatically, even on exceptions\n", - "```" + "---\n### Teardown\n\nThe scale resets the device to a clean state before disconnecting. If the serial\nport is already broken (e.g. unexpected disconnect), the reset is skipped gracefully.\n\nFor scripts and automated protocols, use `async with` to guarantee cleanup even\nif an error occurs:\n\n```python\nasync with Scale(name=\"scale\", backend=backend, size_x=0, size_y=0, size_z=0) as scale:\n await scale.zero()\n weight = await scale.read_weight()\n # scale.stop() is called automatically, even on exceptions\n```" ] }, { @@ -736,4 +693,4 @@ }, "nbformat": 4, "nbformat_minor": 2 -} +} \ No newline at end of file diff --git a/pylabrobot/scales/mettler_toledo/backend.py b/pylabrobot/scales/mettler_toledo/backend.py index 6f4cc48d1b8..022c31749ef 100644 --- a/pylabrobot/scales/mettler_toledo/backend.py +++ b/pylabrobot/scales/mettler_toledo/backend.py @@ -4,6 +4,7 @@ import asyncio import functools +import inspect import logging import shlex import time @@ -46,8 +47,6 @@ def requires_mt_sics_command(mt_sics_command: str) -> Callable[[F], F]: """ def decorator(func: F) -> F: - func._mt_sics_command = mt_sics_command # type: ignore[attr-defined] - @functools.wraps(func) async def wrapper(self: Any, *args: Any, **kwargs: Any) -> Any: if hasattr(self, "_supported_commands") and self._supported_commands is not None: @@ -59,11 +58,17 @@ async def wrapper(self: Any, *args: Any, **kwargs: Any) -> Any: ) return await func(self, *args, **kwargs) + # Register in the class-level command-to-method mapping. + _MT_SICS_COMMAND_REGISTRY[func.__name__] = mt_sics_command return wrapper # type: ignore[return-value] return decorator +# Maps method name -> MT-SICS command string, populated by @requires_mt_sics_command. +_MT_SICS_COMMAND_REGISTRY: dict[str, str] = {} + + # TODO: rename to MTSICSDriver in v1.0.0-beta class MettlerToledoWXS205SDUBackend(ScaleBackend): """Backend for Mettler Toledo scales using the MT-SICS protocol. @@ -132,13 +137,14 @@ async def setup(self) -> None: self.configuration = "Bridge" if "Bridge" in self.device_type else "Balance" logger.info( - "[MT Scale] Connected to Mettler Toledo scale on %s\n" + "[%s] Connected on %s\n" "Device type: %s\n" "Configuration: %s\n" "Serial number: %s\n" "Firmware: %s\n" "Capacity: %.1f g\n" "Supported commands: %s", + self.io._human_readable_device_name, self.io.port, self.device_type, self.configuration, @@ -152,10 +158,11 @@ async def setup(self) -> None: fw_version_short = self.firmware_version.split()[0] if self.firmware_version else "" if fw_version_short not in CONFIRMED_FIRMWARE_VERSIONS: logger.warning( - "[MT Scale] Firmware version %r has not been tested with this driver. " + "[%s] Firmware version %r has not been tested with this driver. " "Confirmed versions: %s. " "If this version works correctly, please contribute it to " "confirmed_firmware_versions.py so others can benefit.", + self.io._human_readable_device_name, self.firmware_version, ", ".join(sorted(CONFIRMED_FIRMWARE_VERSIONS)), ) @@ -174,8 +181,8 @@ async def stop(self) -> None: try: await self.reset() except Exception: - logger.warning("[MT Scale] Could not reset device before disconnecting") - logger.info("[MT Scale] Disconnected from %s", self.io.port) + logger.warning("[%s] Could not reset device before disconnecting", self.io._human_readable_device_name) + logger.info("[%s] Disconnected from %s", self.io._human_readable_device_name, self.io.port) await self.io.stop() def serialize(self) -> dict: @@ -208,22 +215,17 @@ def request_supported_methods(self) -> List[str]: Undecorated methods (Level 0/1) are always included. """ supported: List[str] = [] - for name in dir(self): - if name.startswith("_"): - continue - attr = getattr(type(self), name, None) - if not callable(attr): + for name in sorted(inspect.getmembers(self, predicate=inspect.ismethod), key=lambda m: m[0]): + method_name = name[0] + if method_name.startswith("_"): continue - # Check if the method has a command gate - mt_cmd = getattr(attr, "_mt_sics_command", None) - if mt_cmd is not None: + if method_name in _MT_SICS_COMMAND_REGISTRY: + mt_cmd = _MT_SICS_COMMAND_REGISTRY[method_name] if hasattr(self, "_supported_commands") and mt_cmd in self._supported_commands: - supported.append(name) - # If _supported_commands not yet populated (before setup), skip + supported.append(method_name) else: - # Undecorated public methods are always available - supported.append(name) - return sorted(supported) + supported.append(method_name) + return supported # === Response parsing === @@ -331,7 +333,7 @@ async def send_command(self, command: str, timeout: int = 60) -> List[MettlerTol timeout: The timeout in seconds (applies across all response lines). """ - logger.log(LOG_LEVEL_IO, "[MT Scale] Sent command: %s", command) + logger.log(LOG_LEVEL_IO, "[%s] Sent command: %s", self.io._human_readable_device_name, command) await self.io.write(command.encode() + b"\r\n") responses: List[MettlerToledoResponse] = [] @@ -345,7 +347,7 @@ async def send_command(self, command: str, timeout: int = 60) -> List[MettlerTol raise TimeoutError("Timeout while waiting for response from scale.") await asyncio.sleep(0.001) - logger.log(LOG_LEVEL_IO, "[MT Scale] Received response: %s", raw_response) + logger.log(LOG_LEVEL_IO, "[%s] Received response: %s", self.io._human_readable_device_name, raw_response) fields = shlex.split(raw_response.decode("utf-8").strip()) if len(fields) >= 2: response = MettlerToledoResponse(command=fields[0], status=fields[1], data=fields[2:]) diff --git a/pylabrobot/scales/mettler_toledo/backend_tests.py b/pylabrobot/scales/mettler_toledo/backend_tests.py index 0f14497ff48..fab0f7e83ed 100644 --- a/pylabrobot/scales/mettler_toledo/backend_tests.py +++ b/pylabrobot/scales/mettler_toledo/backend_tests.py @@ -153,7 +153,7 @@ async def test_i50_multi_response(self): remaining = await self.backend.request_remaining_weighing_range() self.assertEqual(remaining, 170.0) - async def test_cancel_returns_serial_number(self): + async def test_reset_returns_serial_number(self): """reset() sends @ which responds with I4-style (command echo is I4, not @). Must correctly parse the serial number despite the unusual response format.""" sn = await self.backend.reset() diff --git a/pylabrobot/scales/mettler_toledo/hardware_validation.ipynb b/pylabrobot/scales/mettler_toledo/hardware_validation.ipynb index f1d37766ed5..3958d0506de 100644 --- a/pylabrobot/scales/mettler_toledo/hardware_validation.ipynb +++ b/pylabrobot/scales/mettler_toledo/hardware_validation.ipynb @@ -560,7 +560,6 @@ "# Group by level\n", "by_level = defaultdict(list)\n", "for resp in responses:\n", - " # Format: I0 B/A <\"command\">\n", " if len(resp.data) >= 2:\n", " level = resp.data[0]\n", " cmd_name = resp.data[1]\n", @@ -568,42 +567,7 @@ "\n", "for level in sorted(by_level.keys()):\n", " cmds = sorted(by_level[level])\n", - " print(f\"Level {level} ({len(cmds)} commands): {', '.join(cmds)}\")\n", - "\n", - "# Check which commands we use that might not be supported\n", - "our_commands = [\n", - " \"@\",\n", - " \"C\",\n", - " \"D\",\n", - " \"DW\",\n", - " \"I0\",\n", - " \"I1\",\n", - " \"I2\",\n", - " \"I4\",\n", - " \"I50\",\n", - " \"M21\",\n", - " \"M28\",\n", - " \"S\",\n", - " \"SC\",\n", - " \"SI\",\n", - " \"T\",\n", - " \"TA\",\n", - " \"TAC\",\n", - " \"TI\",\n", - " \"Z\",\n", - " \"ZC\",\n", - " \"ZI\",\n", - " \"TC\",\n", - "]\n", - "all_device_cmds = set()\n", - "for cmds in by_level.values():\n", - " all_device_cmds.update(cmds)\n", - "\n", - "print()\n", - "print(\"Commands we use vs device support:\")\n", - "for cmd in sorted(our_commands):\n", - " status = \"supported\" if cmd in all_device_cmds else \"NOT SUPPORTED\"\n", - " print(f\" {cmd}: {status}\")" + " print(f\"Level {level} ({len(cmds)} commands): {', '.join(cmds)}\")\n" ] }, { @@ -665,9 +629,9 @@ } ], "source": [ - "# I3 - Software version (Level 0, always available)\n", - "sw_version = await backend.request_firmware_version()\n", - "print(f\"Software version: {sw_version}\")\n", + "# I3 - Firmware version (Level 0, always available)\n", + "fw_version = await backend.request_firmware_version()\n", + "print(f\"Firmware version: {fw_version}\")\n", "\n", "# I5 - Software material number (Level 0, always available)\n", "sw_material = await backend.request_software_material_number()\n", @@ -687,13 +651,35 @@ "else:\n", " print(\"SKIP: I11 not supported\")\n", "\n", - "# I15 - Uptime\n", + "# I15 - Uptime (minutes since start/restart)\n", "if \"I15\" in backend._supported_commands:\n", - " uptime = await backend.request_uptime()\n", - " print(f\"Uptime: {uptime['days']}d {uptime['hours']}h {uptime['minutes']}m {uptime['seconds']}s\")\n", + " uptime_min = await backend.request_uptime_minutes()\n", + " print(f\"Uptime: {uptime_min} minutes ({uptime_min / 60:.1f} hours)\")\n", "else:\n", " print(\"SKIP: I15 not supported\")\n", "\n", + "# I16 - Next service date\n", + "if \"I16\" in backend._supported_commands:\n", + " service_date = await backend.request_next_service_date()\n", + " print(f\"Next service date: {service_date}\")\n", + "else:\n", + " print(\"SKIP: I16 not supported\")\n", + "\n", + "# I21 - Assortment type revision\n", + "if \"I21\" in backend._supported_commands:\n", + " revision = await backend.request_assortment_type_revision()\n", + " print(f\"Assortment type revision: {revision}\")\n", + "else:\n", + " print(\"SKIP: I21 not supported\")\n", + "\n", + "# I26 - Operating mode after restart\n", + "if \"I26\" in backend._supported_commands:\n", + " i26_resp = await backend.request_operating_mode_after_restart()\n", + " for resp in i26_resp:\n", + " print(f\"I26: {resp.command} {resp.status} {\" \".join(resp.data)}\")\n", + "else:\n", + " print(\"SKIP: I26 not supported\")\n", + "\n", "# DAT - Date\n", "if \"DAT\" in backend._supported_commands:\n", " date = await backend.request_date()\n", @@ -724,13 +710,13 @@ " info = await backend.request_device_info(category=cat)\n", " print(f\" Category {cat} ({name}):\")\n", " for resp in info:\n", - " print(f\" {resp.command} {resp.status} {' '.join(resp.data)}\")\n", + " print(f\" {resp.command} {resp.status} {\" \".join(resp.data)}\")\n", " except Exception as e:\n", " print(f\" Category {cat} ({name}): {e}\")\n", "else:\n", " print(\"SKIP: I14 not supported\")\n", "\n", - "print(\"\\nPASS: Batch 1 device identity commands completed\")" + "print(\"\\nPASS: Batch 1 device identity commands completed\")\n" ] }, { @@ -953,7 +939,7 @@ "metadata": {}, "outputs": [], "source": [ - "# M01 - Weighing mode (read-only query)\n", + "# M01 - Weighing mode\n", "if \"M01\" in backend._supported_commands:\n", " mode = await backend.request_weighing_mode()\n", " mode_names = {\n", @@ -967,7 +953,7 @@ "else:\n", " print(\"SKIP: M01 not supported\")\n", "\n", - "# M02 - Environment condition (read-only query)\n", + "# M02 - Environment condition\n", "if \"M02\" in backend._supported_commands:\n", " env = await backend.request_environment_condition()\n", " env_names = {\n", @@ -982,87 +968,153 @@ "else:\n", " print(\"SKIP: M02 not supported\")\n", "\n", - "# M03 - Auto zero (read-only query)\n", + "# M03 - Auto zero\n", "if \"M03\" in backend._supported_commands:\n", " auto_zero = await backend.request_auto_zero()\n", " print(f\"Auto zero: {auto_zero} ({'on' if auto_zero else 'off'})\")\n", "else:\n", " print(\"SKIP: M03 not supported\")\n", "\n", - "# M27 - Adjustment history (read-only query)\n", + "# M17 - ProFACT time criteria\n", + "if \"M17\" in backend._supported_commands:\n", + " resp = await backend.request_profact_time_criteria()\n", + " print(f\"ProFACT time criteria: {resp[0].status} {\" \".join(resp[0].data)}\")\n", + "else:\n", + " print(\"SKIP: M17 not supported\")\n", + "\n", + "# M18 - ProFACT temperature criterion\n", + "if \"M18\" in backend._supported_commands:\n", + " resp = await backend.request_profact_temperature_criterion()\n", + " print(f\"ProFACT temperature criterion: {resp[0].status} {\" \".join(resp[0].data)}\")\n", + "else:\n", + " print(\"SKIP: M18 not supported\")\n", + "\n", + "# M19 - Adjustment weight\n", + "if \"M19\" in backend._supported_commands:\n", + " resp = await backend.request_adjustment_weight()\n", + " print(f\"Adjustment weight: {resp[0].status} {\" \".join(resp[0].data)}\")\n", + "else:\n", + " print(\"SKIP: M19 not supported\")\n", + "\n", + "# M20 - Test weight\n", + "if \"M20\" in backend._supported_commands:\n", + " resp = await backend.request_test_weight()\n", + " print(f\"Test weight: {resp[0].status} {\" \".join(resp[0].data)}\")\n", + "else:\n", + " print(\"SKIP: M20 not supported\")\n", + "\n", + "# M27 - Adjustment history\n", "if \"M27\" in backend._supported_commands:\n", " history = await backend.request_adjustment_history()\n", " print(f\"\\nAdjustment history ({len(history)} entries):\")\n", " for resp in history:\n", - " print(f\" {resp.command} {resp.status} {' '.join(resp.data)}\")\n", + " print(f\" {resp.command} {resp.status} {\" \".join(resp.data)}\")\n", "else:\n", " print(\"SKIP: M27 not supported\")\n", "\n", - "# UPD - Update rate (read-only query)\n", + "# M29 - Weighing value release\n", + "if \"M29\" in backend._supported_commands:\n", + " resp = await backend.request_weighing_value_release()\n", + " print(f\"Weighing value release: {resp[0].status} {\" \".join(resp[0].data)}\")\n", + "else:\n", + " print(\"SKIP: M29 not supported\")\n", + "\n", + "# M31 - Operating mode\n", + "if \"M31\" in backend._supported_commands:\n", + " resp = await backend.request_operating_mode()\n", + " print(f\"Operating mode: {resp[0].status} {\" \".join(resp[0].data)}\")\n", + "else:\n", + " print(\"SKIP: M31 not supported\")\n", + "\n", + "# M32 - ProFACT time\n", + "if \"M32\" in backend._supported_commands:\n", + " resp = await backend.request_profact_time()\n", + " print(f\"ProFACT time: {resp[0].status} {\" \".join(resp[0].data)}\")\n", + "else:\n", + " print(\"SKIP: M32 not supported\")\n", + "\n", + "# M33 - ProFACT day\n", + "if \"M33\" in backend._supported_commands:\n", + " resp = await backend.request_profact_day()\n", + " print(f\"ProFACT day: {resp[0].status} {\" \".join(resp[0].data)}\")\n", + "else:\n", + " print(\"SKIP: M33 not supported\")\n", + "\n", + "# M35 - Zeroing mode\n", + "if \"M35\" in backend._supported_commands:\n", + " resp = await backend.request_zeroing_mode()\n", + " print(f\"Zeroing mode: {resp[0].status} {\" \".join(resp[0].data)}\")\n", + "else:\n", + " print(\"SKIP: M35 not supported\")\n", + "\n", + "# UPD - Update rate\n", "if \"UPD\" in backend._supported_commands:\n", " rate = await backend.request_update_rate()\n", " print(f\"\\nUpdate rate: {rate} values/s\")\n", "else:\n", " print(\"SKIP: UPD not supported\")\n", "\n", - "# SIS - Net weight with status (read-only query)\n", + "# SIS - Net weight with status\n", "if \"SIS\" in backend._supported_commands:\n", " sis_resp = await backend.request_net_weight_with_status()\n", - " print(f\"\\nNet weight with status: {sis_resp.command} {sis_resp.status} {' '.join(sis_resp.data)}\")\n", + " print(f\"Net weight with status: {sis_resp.command} {sis_resp.status} {\" \".join(sis_resp.data)}\")\n", "else:\n", " print(\"SKIP: SIS not supported\")\n", "\n", - "# LST - Current user settings (read-only, lists all configurable settings)\n", + "# C0 - Adjustment setting\n", + "if \"C0\" in backend._supported_commands:\n", + " resp = await backend.request_adjustment_setting()\n", + " print(f\"Adjustment setting: {resp[0].status} {\" \".join(resp[0].data)}\")\n", + "else:\n", + " print(\"SKIP: C0 not supported\")\n", + "\n", + "# COM - Serial parameters\n", + "if \"COM\" in backend._supported_commands:\n", + " resp = await backend.request_serial_parameters()\n", + " print(f\"Serial parameters: {resp[0].status} {\" \".join(resp[0].data)}\")\n", + "else:\n", + " print(\"SKIP: COM not supported\")\n", + "\n", + "# FCUT - Filter cut-off frequency\n", + "if \"FCUT\" in backend._supported_commands:\n", + " resp = await backend.request_filter_cutoff()\n", + " print(f\"Filter cut-off: {resp[0].status} {\" \".join(resp[0].data)}\")\n", + "else:\n", + " print(\"SKIP: FCUT not supported\")\n", + "\n", + "# LST - Current user settings\n", "if \"LST\" in backend._supported_commands:\n", - " try:\n", - " lst_responses = await backend.send_command(\"LST\")\n", - " print(f\"\\nCurrent user settings ({len(lst_responses)} lines):\")\n", - " for resp in lst_responses[:10]:\n", - " print(f\" {resp.command} {resp.status} {' '.join(resp.data)}\")\n", - " if len(lst_responses) > 10:\n", - " print(f\" ... ({len(lst_responses)} lines total)\")\n", - " except Exception as e:\n", - " print(f\"LST: {e}\")\n", + " lst_responses = await backend.request_user_settings()\n", + " print(f\"\\nCurrent user settings ({len(lst_responses)} lines):\")\n", + " for resp in lst_responses[:10]:\n", + " print(f\" {resp.command} {resp.status} {\" \".join(resp.data)}\")\n", + " if len(lst_responses) > 10:\n", + " print(f\" ... ({len(lst_responses)} lines total)\")\n", "else:\n", " print(\"SKIP: LST not supported\")\n", "\n", - "# RDB - Readability (read-only)\n", + "# RDB - Readability\n", "if \"RDB\" in backend._supported_commands:\n", - " try:\n", - " rdb_responses = await backend.send_command(\"RDB\")\n", - " print(\n", - " f\"\\nReadability: {rdb_responses[0].command} {rdb_responses[0].status} {' '.join(rdb_responses[0].data)}\"\n", - " )\n", - " except Exception as e:\n", - " print(f\"RDB: {e}\")\n", + " resp = await backend.request_readability()\n", + " print(f\"Readability: {resp[0].status} {\" \".join(resp[0].data)}\")\n", "else:\n", " print(\"SKIP: RDB not supported\")\n", "\n", - "# USTB - User defined stability criteria (read-only query)\n", + "# USTB - Stability criteria\n", "if \"USTB\" in backend._supported_commands:\n", - " try:\n", - " ustb_responses = await backend.send_command(\"USTB\")\n", - " print(\n", - " f\"Stability criteria: {ustb_responses[0].command} {ustb_responses[0].status} {' '.join(ustb_responses[0].data)}\"\n", - " )\n", - " except Exception as e:\n", - " print(f\"USTB: {e}\")\n", + " resp = await backend.request_stability_criteria()\n", + " print(f\"Stability criteria: {resp[0].status} {\" \".join(resp[0].data)}\")\n", "else:\n", " print(\"SKIP: USTB not supported\")\n", "\n", - "# FCUT - Filter cut-off frequency (read-only query)\n", - "if \"FCUT\" in backend._supported_commands:\n", - " try:\n", - " fcut_responses = await backend.send_command(\"FCUT\")\n", - " print(\n", - " f\"Filter cut-off: {fcut_responses[0].command} {fcut_responses[0].status} {' '.join(fcut_responses[0].data)}\"\n", - " )\n", - " except Exception as e:\n", - " print(f\"FCUT: {e}\")\n", + "# TST0 - Test settings\n", + "if \"TST0\" in backend._supported_commands:\n", + " resp = await backend.request_test_settings()\n", + " print(f\"Test settings: {resp[0].status} {\" \".join(resp[0].data)}\")\n", "else:\n", - " print(\"SKIP: FCUT not supported\")\n", + " print(\"SKIP: TST0 not supported\")\n", "\n", - "print(\"\\nPASS: Batch 2+3 read-only configuration queries completed\")" + "print(\"\\nPASS: All read-only configuration queries completed\")\n" ] }, { @@ -1095,12 +1147,12 @@ " sis_mg = await backend.request_net_weight_with_status()\n", " print(f\"SIS in milligrams: {sis_mg.data}\")\n", "\n", - " # Compare the unit code field (index 4 in the data)\n", - " if len(sis_grams.data) > 4 and len(sis_mg.data) > 4:\n", - " print(f\"\\nUnit code in grams mode: {sis_grams.data[4]}\")\n", - " print(f\"Unit code in mg mode: {sis_mg.data[4]}\")\n", - " if sis_grams.data[4] != sis_mg.data[4]:\n", - " print(\"PASS: unit code changes with M21 - confirms field is unit identifier\")\n", + " # Compare the unit code field (data[2] per SIS spec)\n", + " if len(sis_grams.data) > 2 and len(sis_mg.data) > 2:\n", + " print(f\"\\nUnit code in grams mode: {sis_grams.data[2]}\")\n", + " print(f\"Unit code in mg mode: {sis_mg.data[2]}\")\n", + " if sis_grams.data[2] != sis_mg.data[2]:\n", + " print(\"PASS: unit code changes with M21 - confirms data[2] is unit identifier\")\n", " else:\n", " print(\"INFO: unit code did not change - field may not be the unit identifier\")\n", " else:\n", @@ -1109,7 +1161,7 @@ "finally:\n", " # Always restore grams\n", " await backend.set_host_unit_grams()\n", - " print(\"\\nRestored host unit to grams\")" + " print(\"\\nRestored host unit to grams\")\n" ] }, { @@ -1166,13 +1218,13 @@ "outputs": [], "source": [ "for cmd in [\"I22\", \"I23\", \"I24\", \"I25\"]:\n", - " try:\n", - " responses = await backend.send_command(cmd)\n", - " for r in responses:\n", - " print(f\"{cmd}: status={r.status} data={r.data}\")\n", - " except Exception as e:\n", - " print(f\"{cmd}: {type(e).__name__}: {e}\")\n", - " print()" + " try:\n", + " responses = await backend.send_command(cmd)\n", + " for r in responses:\n", + " print(f\"{cmd}: status={r.status} data={r.data}\")\n", + " except Exception as e:\n", + " print(f\"{cmd}: {type(e).__name__}: {e}\")\n", + " print()\n" ] }, { @@ -1231,13 +1283,6 @@ "await scale.stop()\n", "print(f\"Log file: {log_file}\")" ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] } ], "metadata": { @@ -1261,4 +1306,4 @@ }, "nbformat": 4, "nbformat_minor": 4 -} +} \ No newline at end of file diff --git a/pylabrobot/scales/mettler_toledo/simulator.py b/pylabrobot/scales/mettler_toledo/simulator.py index 58e9af6af84..0e0749bd040 100644 --- a/pylabrobot/scales/mettler_toledo/simulator.py +++ b/pylabrobot/scales/mettler_toledo/simulator.py @@ -60,6 +60,7 @@ def __init__( self.tare_weight: float = 0.0 # Simulated device identity + self._human_readable_device_name = "Mettler Toledo Scale" self._simulated_device_type = device_type self._simulated_serial_number = serial_number self._simulated_capacity = capacity @@ -118,13 +119,14 @@ async def setup(self) -> None: self.firmware_version = "1.10 18.6.4.1361.772" self.configuration = "Bridge" if "Bridge" in self.device_type else "Balance" logger.info( - "[MT Scale] Connected to Mettler Toledo scale (simulation)\n" + "[%s] Connected (simulation)\n" "Device type: %s\n" "Configuration: %s\n" "Serial number: %s\n" "Firmware: %s\n" "Capacity: %.1f g\n" "Supported commands: %s", + self._human_readable_device_name, self.device_type, self.configuration, self.serial_number, @@ -134,7 +136,7 @@ async def setup(self) -> None: ) async def stop(self) -> None: - logger.info("[MT Scale] Disconnected (simulation)") + logger.info("[%s] Disconnected (simulation)", self._human_readable_device_name) async def reset(self) -> str: responses = await self.send_command("@") @@ -142,12 +144,13 @@ async def reset(self) -> str: return responses[0].data[0] async def send_command(self, command: str, timeout: int = 60) -> List[MettlerToledoResponse]: - logger.log(LOG_LEVEL_IO, "[MT Scale] Sent command: %s", command) + logger.log(LOG_LEVEL_IO, "[%s] Sent command: %s", self._human_readable_device_name, command) responses = self._build_response(command) for resp in responses: logger.log( LOG_LEVEL_IO, - "[MT Scale] Received response: %s %s %s", + "[%s] Received response: %s %s %s", + self._human_readable_device_name, resp.command, resp.status, " ".join(resp.data), From c017db79da3efa1e9549267b0f260e8899b12b3c Mon Sep 17 00:00:00 2001 From: Camillo Moschner Date: Mon, 30 Mar 2026 16:35:24 +0100 Subject: [PATCH 32/38] testing undocumented I commnads --- .../mettler_toledo/hardware_validation.ipynb | 1740 +++++++++++++---- 1 file changed, 1385 insertions(+), 355 deletions(-) diff --git a/pylabrobot/scales/mettler_toledo/hardware_validation.ipynb b/pylabrobot/scales/mettler_toledo/hardware_validation.ipynb index 3958d0506de..2d9117f7b07 100644 --- a/pylabrobot/scales/mettler_toledo/hardware_validation.ipynb +++ b/pylabrobot/scales/mettler_toledo/hardware_validation.ipynb @@ -33,7 +33,7 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 16:23:59,420 - pylabrobot - INFO - === Hardware validation started ===\n" + "2026-03-30 16:33:54,376 - pylabrobot - INFO - === Hardware validation started ===\n" ] } ], @@ -65,161 +65,161 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 16:23:59,448 - pylabrobot.io.serial - INFO - Using explicitly provided port: /dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0 (for VID=1027, PID=24577)\n", - "2026-03-30 16:23:59,460 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] reset_input_buffer\n", - "2026-03-30 16:23:59,462 - pylabrobot - IO - [MT Scale] Sent command: @\n", - "2026-03-30 16:23:59,465 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'@\\r\\n'\n", - "2026-03-30 16:23:59,520 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I4 A \"B207696838\"\\r\\n'\n", - "2026-03-30 16:23:59,521 - pylabrobot - IO - [MT Scale] Received response: b'I4 A \"B207696838\"\\r\\n'\n", - "2026-03-30 16:23:59,522 - pylabrobot - IO - [MT Scale] Sent command: I0\n", - "2026-03-30 16:23:59,523 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I0\\r\\n'\n", - "2026-03-30 16:23:59,552 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I0\"\\r\\n'\n", - "2026-03-30 16:23:59,552 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I0\"\\r\\n'\n", - "2026-03-30 16:23:59,568 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I1\"\\r\\n'\n", - "2026-03-30 16:23:59,569 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I1\"\\r\\n'\n", - "2026-03-30 16:23:59,584 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I2\"\\r\\n'\n", - "2026-03-30 16:23:59,585 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I2\"\\r\\n'\n", - "2026-03-30 16:23:59,599 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I3\"\\r\\n'\n", - "2026-03-30 16:23:59,600 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I3\"\\r\\n'\n", - "2026-03-30 16:23:59,616 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I4\"\\r\\n'\n", - "2026-03-30 16:23:59,616 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I4\"\\r\\n'\n", - "2026-03-30 16:23:59,632 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I5\"\\r\\n'\n", - "2026-03-30 16:23:59,633 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I5\"\\r\\n'\n", - "2026-03-30 16:23:59,634 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"S\"\\r\\n'\n", - "2026-03-30 16:23:59,635 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"S\"\\r\\n'\n", - "2026-03-30 16:23:59,647 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"SI\"\\r\\n'\n", - "2026-03-30 16:23:59,649 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"SI\"\\r\\n'\n", - "2026-03-30 16:23:59,664 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"SIR\"\\r\\n'\n", - "2026-03-30 16:23:59,665 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"SIR\"\\r\\n'\n", - "2026-03-30 16:23:59,680 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"Z\"\\r\\n'\n", - "2026-03-30 16:23:59,682 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"Z\"\\r\\n'\n", - "2026-03-30 16:23:59,695 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"ZI\"\\r\\n'\n", - "2026-03-30 16:23:59,696 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"ZI\"\\r\\n'\n", - "2026-03-30 16:23:59,714 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"@\"\\r\\n'\n", - "2026-03-30 16:23:59,715 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"@\"\\r\\n'\n", - "2026-03-30 16:23:59,720 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"SR\"\\r\\n'\n", - "2026-03-30 16:23:59,723 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"SR\"\\r\\n'\n", - "2026-03-30 16:23:59,729 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"T\"\\r\\n'\n", - "2026-03-30 16:23:59,730 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"T\"\\r\\n'\n", - "2026-03-30 16:23:59,743 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"TA\"\\r\\n'\n", - "2026-03-30 16:23:59,744 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"TA\"\\r\\n'\n", - "2026-03-30 16:23:59,759 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"TAC\"\\r\\n'\n", - "2026-03-30 16:23:59,760 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"TAC\"\\r\\n'\n", - "2026-03-30 16:23:59,776 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"TI\"\\r\\n'\n", - "2026-03-30 16:23:59,776 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"TI\"\\r\\n'\n", - "2026-03-30 16:23:59,792 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C0\"\\r\\n'\n", - "2026-03-30 16:23:59,793 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"C0\"\\r\\n'\n", - "2026-03-30 16:23:59,794 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C1\"\\r\\n'\n", - "2026-03-30 16:23:59,794 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"C1\"\\r\\n'\n", - "2026-03-30 16:23:59,807 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C2\"\\r\\n'\n", - "2026-03-30 16:23:59,808 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"C2\"\\r\\n'\n", - "2026-03-30 16:23:59,824 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C3\"\\r\\n'\n", - "2026-03-30 16:23:59,824 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"C3\"\\r\\n'\n", - "2026-03-30 16:23:59,840 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"COM\"\\r\\n'\n", - "2026-03-30 16:23:59,840 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"COM\"\\r\\n'\n", - "2026-03-30 16:23:59,855 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"DAT\"\\r\\n'\n", - "2026-03-30 16:23:59,856 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"DAT\"\\r\\n'\n", - "2026-03-30 16:23:59,871 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I10\"\\r\\n'\n", - "2026-03-30 16:23:59,872 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I10\"\\r\\n'\n", - "2026-03-30 16:23:59,888 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I11\"\\r\\n'\n", - "2026-03-30 16:23:59,888 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I11\"\\r\\n'\n", - "2026-03-30 16:23:59,904 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I14\"\\r\\n'\n", - "2026-03-30 16:23:59,905 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I14\"\\r\\n'\n", - "2026-03-30 16:23:59,920 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I15\"\\r\\n'\n", - "2026-03-30 16:23:59,921 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I15\"\\r\\n'\n", - "2026-03-30 16:23:59,935 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I16\"\\r\\n'\n", - "2026-03-30 16:23:59,936 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I16\"\\r\\n'\n", - "2026-03-30 16:23:59,937 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I21\"\\r\\n'\n", - "2026-03-30 16:23:59,938 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I21\"\\r\\n'\n", - "2026-03-30 16:23:59,952 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I22\"\\r\\n'\n", - "2026-03-30 16:23:59,953 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I22\"\\r\\n'\n", - "2026-03-30 16:23:59,967 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I23\"\\r\\n'\n", - "2026-03-30 16:23:59,968 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I23\"\\r\\n'\n", - "2026-03-30 16:23:59,983 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I24\"\\r\\n'\n", - "2026-03-30 16:23:59,984 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I24\"\\r\\n'\n", - "2026-03-30 16:24:00,000 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I25\"\\r\\n'\n", - "2026-03-30 16:24:00,000 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I25\"\\r\\n'\n", - "2026-03-30 16:24:00,015 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I26\"\\r\\n'\n", - "2026-03-30 16:24:00,015 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I26\"\\r\\n'\n", - "2026-03-30 16:24:00,031 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M01\"\\r\\n'\n", - "2026-03-30 16:24:00,032 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M01\"\\r\\n'\n", - "2026-03-30 16:24:00,047 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M02\"\\r\\n'\n", - "2026-03-30 16:24:00,048 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M02\"\\r\\n'\n", - "2026-03-30 16:24:00,063 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M03\"\\r\\n'\n", - "2026-03-30 16:24:00,063 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M03\"\\r\\n'\n", - "2026-03-30 16:24:00,079 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M17\"\\r\\n'\n", - "2026-03-30 16:24:00,080 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M17\"\\r\\n'\n", - "2026-03-30 16:24:00,095 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M18\"\\r\\n'\n", - "2026-03-30 16:24:00,096 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M18\"\\r\\n'\n", - "2026-03-30 16:24:00,097 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M19\"\\r\\n'\n", - "2026-03-30 16:24:00,098 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M19\"\\r\\n'\n", - "2026-03-30 16:24:00,112 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M20\"\\r\\n'\n", - "2026-03-30 16:24:00,112 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M20\"\\r\\n'\n", - "2026-03-30 16:24:00,127 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M21\"\\r\\n'\n", - "2026-03-30 16:24:00,128 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M21\"\\r\\n'\n", - "2026-03-30 16:24:00,143 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M27\"\\r\\n'\n", - "2026-03-30 16:24:00,144 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M27\"\\r\\n'\n", - "2026-03-30 16:24:00,159 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M28\"\\r\\n'\n", - "2026-03-30 16:24:00,160 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M28\"\\r\\n'\n", - "2026-03-30 16:24:00,175 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M29\"\\r\\n'\n", - "2026-03-30 16:24:00,176 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M29\"\\r\\n'\n", - "2026-03-30 16:24:00,191 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M31\"\\r\\n'\n", - "2026-03-30 16:24:00,192 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M31\"\\r\\n'\n", - "2026-03-30 16:24:00,207 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M32\"\\r\\n'\n", - "2026-03-30 16:24:00,208 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M32\"\\r\\n'\n", - "2026-03-30 16:24:00,223 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M33\"\\r\\n'\n", - "2026-03-30 16:24:00,224 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M33\"\\r\\n'\n", - "2026-03-30 16:24:00,239 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M35\"\\r\\n'\n", - "2026-03-30 16:24:00,240 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M35\"\\r\\n'\n", - "2026-03-30 16:24:00,255 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"SIS\"\\r\\n'\n", - "2026-03-30 16:24:00,256 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"SIS\"\\r\\n'\n", - "2026-03-30 16:24:00,271 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"SNR\"\\r\\n'\n", - "2026-03-30 16:24:00,272 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"SNR\"\\r\\n'\n", - "2026-03-30 16:24:00,273 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TIM\"\\r\\n'\n", - "2026-03-30 16:24:00,274 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TIM\"\\r\\n'\n", - "2026-03-30 16:24:00,287 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST0\"\\r\\n'\n", - "2026-03-30 16:24:00,288 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TST0\"\\r\\n'\n", - "2026-03-30 16:24:00,303 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST1\"\\r\\n'\n", - "2026-03-30 16:24:00,304 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TST1\"\\r\\n'\n", - "2026-03-30 16:24:00,319 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST2\"\\r\\n'\n", - "2026-03-30 16:24:00,320 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TST2\"\\r\\n'\n", - "2026-03-30 16:24:00,336 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST3\"\\r\\n'\n", - "2026-03-30 16:24:00,336 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TST3\"\\r\\n'\n", - "2026-03-30 16:24:00,351 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"UPD\"\\r\\n'\n", - "2026-03-30 16:24:00,352 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"UPD\"\\r\\n'\n", - "2026-03-30 16:24:00,367 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"FCUT\"\\r\\n'\n", - "2026-03-30 16:24:00,368 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 3 \"FCUT\"\\r\\n'\n", - "2026-03-30 16:24:00,383 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"FSET\"\\r\\n'\n", - "2026-03-30 16:24:00,384 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 3 \"FSET\"\\r\\n'\n", - "2026-03-30 16:24:00,399 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"LST\"\\r\\n'\n", - "2026-03-30 16:24:00,399 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 3 \"LST\"\\r\\n'\n", - "2026-03-30 16:24:00,415 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"RDB\"\\r\\n'\n", - "2026-03-30 16:24:00,416 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 3 \"RDB\"\\r\\n'\n", - "2026-03-30 16:24:00,431 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 A 3 \"USTB\"\\r\\n'\n", - "2026-03-30 16:24:00,432 - pylabrobot - IO - [MT Scale] Received response: b'I0 A 3 \"USTB\"\\r\\n'\n", - "2026-03-30 16:24:00,433 - pylabrobot - IO - [MT Scale] Sent command: I2\n", - "2026-03-30 16:24:00,434 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I2\\r\\n'\n", - "2026-03-30 16:24:00,495 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", - "2026-03-30 16:24:00,496 - pylabrobot - IO - [MT Scale] Received response: b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", - "2026-03-30 16:24:00,497 - pylabrobot - IO - [MT Scale] Sent command: I2\n", - "2026-03-30 16:24:00,499 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I2\\r\\n'\n", - "2026-03-30 16:24:00,559 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", - "2026-03-30 16:24:00,560 - pylabrobot - IO - [MT Scale] Received response: b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", - "2026-03-30 16:24:00,561 - pylabrobot - IO - [MT Scale] Sent command: I3\n", - "2026-03-30 16:24:00,562 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I3\\r\\n'\n", - "2026-03-30 16:24:00,607 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I3 A \"1.10 18.6.4.1361.772\"\\r\\n'\n", - "2026-03-30 16:24:00,608 - pylabrobot - IO - [MT Scale] Received response: b'I3 A \"1.10 18.6.4.1361.772\"\\r\\n'\n", - "2026-03-30 16:24:00,609 - pylabrobot - INFO - [MT Scale] Connected to Mettler Toledo scale on /dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0\n", + "2026-03-30 16:33:54,399 - pylabrobot.io.serial - INFO - Using explicitly provided port: /dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0 (for VID=1027, PID=24577)\n", + "2026-03-30 16:33:54,407 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] reset_input_buffer\n", + "2026-03-30 16:33:54,408 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: @\n", + "2026-03-30 16:33:54,410 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'@\\r\\n'\n", + "2026-03-30 16:33:54,468 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I4 A \"B207696838\"\\r\\n'\n", + "2026-03-30 16:33:54,469 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I4 A \"B207696838\"\\r\\n'\n", + "2026-03-30 16:33:54,474 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: I0\n", + "2026-03-30 16:33:54,477 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I0\\r\\n'\n", + "2026-03-30 16:33:54,519 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I0\"\\r\\n'\n", + "2026-03-30 16:33:54,520 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 0 \"I0\"\\r\\n'\n", + "2026-03-30 16:33:54,532 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I1\"\\r\\n'\n", + "2026-03-30 16:33:54,534 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 0 \"I1\"\\r\\n'\n", + "2026-03-30 16:33:54,537 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I2\"\\r\\n'\n", + "2026-03-30 16:33:54,538 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 0 \"I2\"\\r\\n'\n", + "2026-03-30 16:33:54,549 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I3\"\\r\\n'\n", + "2026-03-30 16:33:54,550 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 0 \"I3\"\\r\\n'\n", + "2026-03-30 16:33:54,564 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I4\"\\r\\n'\n", + "2026-03-30 16:33:54,565 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 0 \"I4\"\\r\\n'\n", + "2026-03-30 16:33:54,583 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I5\"\\r\\n'\n", + "2026-03-30 16:33:54,588 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 0 \"I5\"\\r\\n'\n", + "2026-03-30 16:33:54,598 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"S\"\\r\\n'\n", + "2026-03-30 16:33:54,600 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 0 \"S\"\\r\\n'\n", + "2026-03-30 16:33:54,612 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"SI\"\\r\\n'\n", + "2026-03-30 16:33:54,615 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 0 \"SI\"\\r\\n'\n", + "2026-03-30 16:33:54,617 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"SIR\"\\r\\n'\n", + "2026-03-30 16:33:54,624 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 0 \"SIR\"\\r\\n'\n", + "2026-03-30 16:33:54,629 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"Z\"\\r\\n'\n", + "2026-03-30 16:33:54,630 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 0 \"Z\"\\r\\n'\n", + "2026-03-30 16:33:54,645 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"ZI\"\\r\\n'\n", + "2026-03-30 16:33:54,651 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 0 \"ZI\"\\r\\n'\n", + "2026-03-30 16:33:54,660 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"@\"\\r\\n'\n", + "2026-03-30 16:33:54,664 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 0 \"@\"\\r\\n'\n", + "2026-03-30 16:33:54,676 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"SR\"\\r\\n'\n", + "2026-03-30 16:33:54,678 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 1 \"SR\"\\r\\n'\n", + "2026-03-30 16:33:54,693 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"T\"\\r\\n'\n", + "2026-03-30 16:33:54,699 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 1 \"T\"\\r\\n'\n", + "2026-03-30 16:33:54,705 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"TA\"\\r\\n'\n", + "2026-03-30 16:33:54,707 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 1 \"TA\"\\r\\n'\n", + "2026-03-30 16:33:54,717 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"TAC\"\\r\\n'\n", + "2026-03-30 16:33:54,718 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 1 \"TAC\"\\r\\n'\n", + "2026-03-30 16:33:54,724 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"TI\"\\r\\n'\n", + "2026-03-30 16:33:54,726 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 1 \"TI\"\\r\\n'\n", + "2026-03-30 16:33:54,740 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C0\"\\r\\n'\n", + "2026-03-30 16:33:54,741 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"C0\"\\r\\n'\n", + "2026-03-30 16:33:54,756 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C1\"\\r\\n'\n", + "2026-03-30 16:33:54,757 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"C1\"\\r\\n'\n", + "2026-03-30 16:33:54,772 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C2\"\\r\\n'\n", + "2026-03-30 16:33:54,774 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"C2\"\\r\\n'\n", + "2026-03-30 16:33:54,788 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C3\"\\r\\n'\n", + "2026-03-30 16:33:54,789 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"C3\"\\r\\n'\n", + "2026-03-30 16:33:54,791 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"COM\"\\r\\n'\n", + "2026-03-30 16:33:54,792 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"COM\"\\r\\n'\n", + "2026-03-30 16:33:54,804 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"DAT\"\\r\\n'\n", + "2026-03-30 16:33:54,805 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"DAT\"\\r\\n'\n", + "2026-03-30 16:33:54,820 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I10\"\\r\\n'\n", + "2026-03-30 16:33:54,822 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"I10\"\\r\\n'\n", + "2026-03-30 16:33:54,835 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I11\"\\r\\n'\n", + "2026-03-30 16:33:54,836 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"I11\"\\r\\n'\n", + "2026-03-30 16:33:54,852 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I14\"\\r\\n'\n", + "2026-03-30 16:33:54,853 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"I14\"\\r\\n'\n", + "2026-03-30 16:33:54,868 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I15\"\\r\\n'\n", + "2026-03-30 16:33:54,870 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"I15\"\\r\\n'\n", + "2026-03-30 16:33:54,884 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I16\"\\r\\n'\n", + "2026-03-30 16:33:54,885 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"I16\"\\r\\n'\n", + "2026-03-30 16:33:54,900 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I21\"\\r\\n'\n", + "2026-03-30 16:33:54,902 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"I21\"\\r\\n'\n", + "2026-03-30 16:33:54,916 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I22\"\\r\\n'\n", + "2026-03-30 16:33:54,917 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"I22\"\\r\\n'\n", + "2026-03-30 16:33:54,931 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I23\"\\r\\n'\n", + "2026-03-30 16:33:54,932 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"I23\"\\r\\n'\n", + "2026-03-30 16:33:54,948 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I24\"\\r\\n'\n", + "2026-03-30 16:33:54,948 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"I24\"\\r\\n'\n", + "2026-03-30 16:33:54,950 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I25\"\\r\\n'\n", + "2026-03-30 16:33:54,951 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"I25\"\\r\\n'\n", + "2026-03-30 16:33:54,964 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I26\"\\r\\n'\n", + "2026-03-30 16:33:54,965 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"I26\"\\r\\n'\n", + "2026-03-30 16:33:54,981 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M01\"\\r\\n'\n", + "2026-03-30 16:33:54,983 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"M01\"\\r\\n'\n", + "2026-03-30 16:33:54,997 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M02\"\\r\\n'\n", + "2026-03-30 16:33:54,999 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"M02\"\\r\\n'\n", + "2026-03-30 16:33:55,012 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M03\"\\r\\n'\n", + "2026-03-30 16:33:55,013 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"M03\"\\r\\n'\n", + "2026-03-30 16:33:55,027 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M17\"\\r\\n'\n", + "2026-03-30 16:33:55,028 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"M17\"\\r\\n'\n", + "2026-03-30 16:33:55,046 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M18\"\\r\\n'\n", + "2026-03-30 16:33:55,048 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"M18\"\\r\\n'\n", + "2026-03-30 16:33:55,060 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M19\"\\r\\n'\n", + "2026-03-30 16:33:55,061 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"M19\"\\r\\n'\n", + "2026-03-30 16:33:55,075 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M20\"\\r\\n'\n", + "2026-03-30 16:33:55,076 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"M20\"\\r\\n'\n", + "2026-03-30 16:33:55,092 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M21\"\\r\\n'\n", + "2026-03-30 16:33:55,093 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"M21\"\\r\\n'\n", + "2026-03-30 16:33:55,108 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M27\"\\r\\n'\n", + "2026-03-30 16:33:55,112 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"M27\"\\r\\n'\n", + "2026-03-30 16:33:55,113 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M28\"\\r\\n'\n", + "2026-03-30 16:33:55,115 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"M28\"\\r\\n'\n", + "2026-03-30 16:33:55,123 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M29\"\\r\\n'\n", + "2026-03-30 16:33:55,124 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"M29\"\\r\\n'\n", + "2026-03-30 16:33:55,140 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M31\"\\r\\n'\n", + "2026-03-30 16:33:55,140 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"M31\"\\r\\n'\n", + "2026-03-30 16:33:55,156 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M32\"\\r\\n'\n", + "2026-03-30 16:33:55,157 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"M32\"\\r\\n'\n", + "2026-03-30 16:33:55,172 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M33\"\\r\\n'\n", + "2026-03-30 16:33:55,173 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"M33\"\\r\\n'\n", + "2026-03-30 16:33:55,187 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M35\"\\r\\n'\n", + "2026-03-30 16:33:55,188 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"M35\"\\r\\n'\n", + "2026-03-30 16:33:55,204 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"SIS\"\\r\\n'\n", + "2026-03-30 16:33:55,204 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"SIS\"\\r\\n'\n", + "2026-03-30 16:33:55,220 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"SNR\"\\r\\n'\n", + "2026-03-30 16:33:55,221 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"SNR\"\\r\\n'\n", + "2026-03-30 16:33:55,235 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TIM\"\\r\\n'\n", + "2026-03-30 16:33:55,236 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"TIM\"\\r\\n'\n", + "2026-03-30 16:33:55,251 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST0\"\\r\\n'\n", + "2026-03-30 16:33:55,252 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"TST0\"\\r\\n'\n", + "2026-03-30 16:33:55,268 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST1\"\\r\\n'\n", + "2026-03-30 16:33:55,268 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"TST1\"\\r\\n'\n", + "2026-03-30 16:33:55,284 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST2\"\\r\\n'\n", + "2026-03-30 16:33:55,285 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"TST2\"\\r\\n'\n", + "2026-03-30 16:33:55,299 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST3\"\\r\\n'\n", + "2026-03-30 16:33:55,300 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"TST3\"\\r\\n'\n", + "2026-03-30 16:33:55,316 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"UPD\"\\r\\n'\n", + "2026-03-30 16:33:55,316 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"UPD\"\\r\\n'\n", + "2026-03-30 16:33:55,332 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"FCUT\"\\r\\n'\n", + "2026-03-30 16:33:55,333 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 3 \"FCUT\"\\r\\n'\n", + "2026-03-30 16:33:55,347 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"FSET\"\\r\\n'\n", + "2026-03-30 16:33:55,348 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 3 \"FSET\"\\r\\n'\n", + "2026-03-30 16:33:55,364 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"LST\"\\r\\n'\n", + "2026-03-30 16:33:55,365 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 3 \"LST\"\\r\\n'\n", + "2026-03-30 16:33:55,366 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"RDB\"\\r\\n'\n", + "2026-03-30 16:33:55,367 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 3 \"RDB\"\\r\\n'\n", + "2026-03-30 16:33:55,380 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 A 3 \"USTB\"\\r\\n'\n", + "2026-03-30 16:33:55,381 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 A 3 \"USTB\"\\r\\n'\n", + "2026-03-30 16:33:55,382 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: I2\n", + "2026-03-30 16:33:55,383 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I2\\r\\n'\n", + "2026-03-30 16:33:55,444 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", + "2026-03-30 16:33:55,444 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", + "2026-03-30 16:33:55,445 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: I2\n", + "2026-03-30 16:33:55,446 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I2\\r\\n'\n", + "2026-03-30 16:33:55,508 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", + "2026-03-30 16:33:55,509 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", + "2026-03-30 16:33:55,510 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: I3\n", + "2026-03-30 16:33:55,511 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I3\\r\\n'\n", + "2026-03-30 16:33:55,556 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I3 A \"1.10 18.6.4.1361.772\"\\r\\n'\n", + "2026-03-30 16:33:55,556 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I3 A \"1.10 18.6.4.1361.772\"\\r\\n'\n", + "2026-03-30 16:33:55,557 - pylabrobot - INFO - [Mettler Toledo Scale] Connected on /dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0\n", "Device type: WXS205SDU WXA-Bridge\n", "Configuration: Bridge\n", "Serial number: B207696838\n", "Firmware: 1.10 18.6.4.1361.772\n", "Capacity: 220.0 g\n", "Supported commands: ['@', 'C0', 'C1', 'C2', 'C3', 'COM', 'DAT', 'FCUT', 'FSET', 'I0', 'I1', 'I10', 'I11', 'I14', 'I15', 'I16', 'I2', 'I21', 'I22', 'I23', 'I24', 'I25', 'I26', 'I3', 'I4', 'I5', 'LST', 'M01', 'M02', 'M03', 'M17', 'M18', 'M19', 'M20', 'M21', 'M27', 'M28', 'M29', 'M31', 'M32', 'M33', 'M35', 'RDB', 'S', 'SI', 'SIR', 'SIS', 'SNR', 'SR', 'T', 'TA', 'TAC', 'TI', 'TIM', 'TST0', 'TST1', 'TST2', 'TST3', 'UPD', 'USTB', 'Z', 'ZI']\n", - "2026-03-30 16:24:00,610 - pylabrobot - IO - [MT Scale] Sent command: M21 0 0\n", - "2026-03-30 16:24:00,611 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'M21 0 0\\r\\n'\n", - "2026-03-30 16:24:00,639 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M21 A\\r\\n'\n", - "2026-03-30 16:24:00,639 - pylabrobot - IO - [MT Scale] Received response: b'M21 A\\r\\n'\n" + "2026-03-30 16:33:55,558 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: M21 0 0\n", + "2026-03-30 16:33:55,560 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'M21 0 0\\r\\n'\n", + "2026-03-30 16:33:55,587 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M21 A\\r\\n'\n", + "2026-03-30 16:33:55,588 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'M21 A\\r\\n'\n" ] } ], @@ -383,132 +383,132 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 16:24:00,705 - pylabrobot - IO - [MT Scale] Sent command: I0\n", - "2026-03-30 16:24:00,713 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I0\\r\\n'\n", - "2026-03-30 16:24:00,736 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I0\"\\r\\n'\n", - "2026-03-30 16:24:00,737 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I0\"\\r\\n'\n", - "2026-03-30 16:24:00,751 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I1\"\\r\\n'\n", - "2026-03-30 16:24:00,752 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I1\"\\r\\n'\n", - "2026-03-30 16:24:00,767 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I2\"\\r\\n'\n", - "2026-03-30 16:24:00,768 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I2\"\\r\\n'\n", - "2026-03-30 16:24:00,783 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I3\"\\r\\n'\n", - "2026-03-30 16:24:00,784 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I3\"\\r\\n'\n", - "2026-03-30 16:24:00,799 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I4\"\\r\\n'\n", - "2026-03-30 16:24:00,800 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I4\"\\r\\n'\n", - "2026-03-30 16:24:00,815 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I5\"\\r\\n'\n", - "2026-03-30 16:24:00,816 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"I5\"\\r\\n'\n", - "2026-03-30 16:24:00,830 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"S\"\\r\\n'\n", - "2026-03-30 16:24:00,831 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"S\"\\r\\n'\n", - "2026-03-30 16:24:00,833 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"SI\"\\r\\n'\n", - "2026-03-30 16:24:00,833 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"SI\"\\r\\n'\n", - "2026-03-30 16:24:00,847 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"SIR\"\\r\\n'\n", - "2026-03-30 16:24:00,848 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"SIR\"\\r\\n'\n", - "2026-03-30 16:24:00,864 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"Z\"\\r\\n'\n", - "2026-03-30 16:24:00,865 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"Z\"\\r\\n'\n", - "2026-03-30 16:24:00,878 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"ZI\"\\r\\n'\n", - "2026-03-30 16:24:00,879 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"ZI\"\\r\\n'\n", - "2026-03-30 16:24:00,895 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"@\"\\r\\n'\n", - "2026-03-30 16:24:00,896 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 0 \"@\"\\r\\n'\n", - "2026-03-30 16:24:00,911 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"SR\"\\r\\n'\n", - "2026-03-30 16:24:00,912 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"SR\"\\r\\n'\n", - "2026-03-30 16:24:00,913 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"T\"\\r\\n'\n", - "2026-03-30 16:24:00,914 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"T\"\\r\\n'\n", - "2026-03-30 16:24:00,926 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"TA\"\\r\\n'\n", - "2026-03-30 16:24:00,927 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"TA\"\\r\\n'\n", - "2026-03-30 16:24:00,942 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"TAC\"\\r\\n'\n", - "2026-03-30 16:24:00,943 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"TAC\"\\r\\n'\n", - "2026-03-30 16:24:00,959 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"TI\"\\r\\n'\n", - "2026-03-30 16:24:00,959 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 1 \"TI\"\\r\\n'\n", - "2026-03-30 16:24:00,974 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C0\"\\r\\n'\n", - "2026-03-30 16:24:00,975 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"C0\"\\r\\n'\n", - "2026-03-30 16:24:00,990 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C1\"\\r\\n'\n", - "2026-03-30 16:24:00,991 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"C1\"\\r\\n'\n", - "2026-03-30 16:24:00,992 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C2\"\\r\\n'\n", - "2026-03-30 16:24:00,993 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"C2\"\\r\\n'\n", - "2026-03-30 16:24:01,006 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C3\"\\r\\n'\n", - "2026-03-30 16:24:01,007 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"C3\"\\r\\n'\n", - "2026-03-30 16:24:01,023 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"COM\"\\r\\n'\n", - "2026-03-30 16:24:01,024 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"COM\"\\r\\n'\n", - "2026-03-30 16:24:01,038 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"DAT\"\\r\\n'\n", - "2026-03-30 16:24:01,039 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"DAT\"\\r\\n'\n", - "2026-03-30 16:24:01,054 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I10\"\\r\\n'\n", - "2026-03-30 16:24:01,055 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I10\"\\r\\n'\n", - "2026-03-30 16:24:01,071 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I11\"\\r\\n'\n", - "2026-03-30 16:24:01,071 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I11\"\\r\\n'\n", - "2026-03-30 16:24:01,086 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I14\"\\r\\n'\n", - "2026-03-30 16:24:01,086 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I14\"\\r\\n'\n", - "2026-03-30 16:24:01,102 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I15\"\\r\\n'\n", - "2026-03-30 16:24:01,103 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I15\"\\r\\n'\n", - "2026-03-30 16:24:01,118 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I16\"\\r\\n'\n", - "2026-03-30 16:24:01,119 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I16\"\\r\\n'\n", - "2026-03-30 16:24:01,135 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I21\"\\r\\n'\n", - "2026-03-30 16:24:01,135 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I21\"\\r\\n'\n", - "2026-03-30 16:24:01,137 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I22\"\\r\\n'\n", - "2026-03-30 16:24:01,137 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I22\"\\r\\n'\n", - "2026-03-30 16:24:01,150 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I23\"\\r\\n'\n", - "2026-03-30 16:24:01,151 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I23\"\\r\\n'\n", - "2026-03-30 16:24:01,166 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I24\"\\r\\n'\n", - "2026-03-30 16:24:01,167 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I24\"\\r\\n'\n", - "2026-03-30 16:24:01,182 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I25\"\\r\\n'\n", - "2026-03-30 16:24:01,183 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I25\"\\r\\n'\n", - "2026-03-30 16:24:01,198 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I26\"\\r\\n'\n", - "2026-03-30 16:24:01,198 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"I26\"\\r\\n'\n", - "2026-03-30 16:24:01,214 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M01\"\\r\\n'\n", - "2026-03-30 16:24:01,215 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M01\"\\r\\n'\n", - "2026-03-30 16:24:01,230 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M02\"\\r\\n'\n", - "2026-03-30 16:24:01,231 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M02\"\\r\\n'\n", - "2026-03-30 16:24:01,247 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M03\"\\r\\n'\n", - "2026-03-30 16:24:01,247 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M03\"\\r\\n'\n", - "2026-03-30 16:24:01,262 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M17\"\\r\\n'\n", - "2026-03-30 16:24:01,262 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M17\"\\r\\n'\n", - "2026-03-30 16:24:01,278 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M18\"\\r\\n'\n", - "2026-03-30 16:24:01,279 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M18\"\\r\\n'\n", - "2026-03-30 16:24:01,294 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M19\"\\r\\n'\n", - "2026-03-30 16:24:01,295 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M19\"\\r\\n'\n", - "2026-03-30 16:24:01,310 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M20\"\\r\\n'\n", - "2026-03-30 16:24:01,310 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M20\"\\r\\n'\n", - "2026-03-30 16:24:01,312 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M21\"\\r\\n'\n", - "2026-03-30 16:24:01,313 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M21\"\\r\\n'\n", - "2026-03-30 16:24:01,326 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M27\"\\r\\n'\n", - "2026-03-30 16:24:01,327 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M27\"\\r\\n'\n", - "2026-03-30 16:24:01,347 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M28\"\\r\\n'\n", - "2026-03-30 16:24:01,352 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M28\"\\r\\n'\n", - "2026-03-30 16:24:01,358 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M29\"\\r\\n'\n", - "2026-03-30 16:24:01,359 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M29\"\\r\\n'\n", - "2026-03-30 16:24:01,375 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M31\"\\r\\n'\n", - "2026-03-30 16:24:01,376 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M31\"\\r\\n'\n", - "2026-03-30 16:24:01,391 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M32\"\\r\\n'\n", - "2026-03-30 16:24:01,395 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M32\"\\r\\n'\n", - "2026-03-30 16:24:01,406 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M33\"\\r\\n'\n", - "2026-03-30 16:24:01,407 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M33\"\\r\\n'\n", - "2026-03-30 16:24:01,422 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M35\"\\r\\n'\n", - "2026-03-30 16:24:01,423 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"M35\"\\r\\n'\n", - "2026-03-30 16:24:01,439 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"SIS\"\\r\\n'\n", - "2026-03-30 16:24:01,440 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"SIS\"\\r\\n'\n", - "2026-03-30 16:24:01,454 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"SNR\"\\r\\n'\n", - "2026-03-30 16:24:01,455 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"SNR\"\\r\\n'\n", - "2026-03-30 16:24:01,470 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TIM\"\\r\\n'\n", - "2026-03-30 16:24:01,471 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TIM\"\\r\\n'\n", - "2026-03-30 16:24:01,486 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST0\"\\r\\n'\n", - "2026-03-30 16:24:01,488 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TST0\"\\r\\n'\n", - "2026-03-30 16:24:01,502 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST1\"\\r\\n'\n", - "2026-03-30 16:24:01,503 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TST1\"\\r\\n'\n", - "2026-03-30 16:24:01,523 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST2\"\\r\\n'\n", - "2026-03-30 16:24:01,524 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TST2\"\\r\\n'\n", - "2026-03-30 16:24:01,534 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST3\"\\r\\n'\n", - "2026-03-30 16:24:01,535 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"TST3\"\\r\\n'\n", - "2026-03-30 16:24:01,536 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"UPD\"\\r\\n'\n", - "2026-03-30 16:24:01,537 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 2 \"UPD\"\\r\\n'\n", - "2026-03-30 16:24:01,550 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"FCUT\"\\r\\n'\n", - "2026-03-30 16:24:01,551 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 3 \"FCUT\"\\r\\n'\n", - "2026-03-30 16:24:01,566 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"FSET\"\\r\\n'\n", - "2026-03-30 16:24:01,567 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 3 \"FSET\"\\r\\n'\n", - "2026-03-30 16:24:01,584 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"LST\"\\r\\n'\n", - "2026-03-30 16:24:01,587 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 3 \"LST\"\\r\\n'\n", - "2026-03-30 16:24:01,599 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"RDB\"\\r\\n'\n", - "2026-03-30 16:24:01,603 - pylabrobot - IO - [MT Scale] Received response: b'I0 B 3 \"RDB\"\\r\\n'\n", - "2026-03-30 16:24:01,614 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 A 3 \"USTB\"\\r\\n'\n", - "2026-03-30 16:24:01,615 - pylabrobot - IO - [MT Scale] Received response: b'I0 A 3 \"USTB\"\\r\\n'\n" + "2026-03-30 16:33:55,649 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: I0\n", + "2026-03-30 16:33:55,652 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I0\\r\\n'\n", + "2026-03-30 16:33:55,684 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I0\"\\r\\n'\n", + "2026-03-30 16:33:55,686 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 0 \"I0\"\\r\\n'\n", + "2026-03-30 16:33:55,700 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I1\"\\r\\n'\n", + "2026-03-30 16:33:55,703 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 0 \"I1\"\\r\\n'\n", + "2026-03-30 16:33:55,716 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I2\"\\r\\n'\n", + "2026-03-30 16:33:55,721 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 0 \"I2\"\\r\\n'\n", + "2026-03-30 16:33:55,727 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I3\"\\r\\n'\n", + "2026-03-30 16:33:55,729 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 0 \"I3\"\\r\\n'\n", + "2026-03-30 16:33:55,732 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I4\"\\r\\n'\n", + "2026-03-30 16:33:55,734 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 0 \"I4\"\\r\\n'\n", + "2026-03-30 16:33:55,752 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I5\"\\r\\n'\n", + "2026-03-30 16:33:55,755 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 0 \"I5\"\\r\\n'\n", + "2026-03-30 16:33:55,764 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"S\"\\r\\n'\n", + "2026-03-30 16:33:55,765 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 0 \"S\"\\r\\n'\n", + "2026-03-30 16:33:55,779 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"SI\"\\r\\n'\n", + "2026-03-30 16:33:55,780 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 0 \"SI\"\\r\\n'\n", + "2026-03-30 16:33:55,796 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"SIR\"\\r\\n'\n", + "2026-03-30 16:33:55,798 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 0 \"SIR\"\\r\\n'\n", + "2026-03-30 16:33:55,800 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"Z\"\\r\\n'\n", + "2026-03-30 16:33:55,802 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 0 \"Z\"\\r\\n'\n", + "2026-03-30 16:33:55,812 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"ZI\"\\r\\n'\n", + "2026-03-30 16:33:55,814 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 0 \"ZI\"\\r\\n'\n", + "2026-03-30 16:33:55,828 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"@\"\\r\\n'\n", + "2026-03-30 16:33:55,829 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 0 \"@\"\\r\\n'\n", + "2026-03-30 16:33:55,843 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"SR\"\\r\\n'\n", + "2026-03-30 16:33:55,844 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 1 \"SR\"\\r\\n'\n", + "2026-03-30 16:33:55,860 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"T\"\\r\\n'\n", + "2026-03-30 16:33:55,861 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 1 \"T\"\\r\\n'\n", + "2026-03-30 16:33:55,875 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"TA\"\\r\\n'\n", + "2026-03-30 16:33:55,876 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 1 \"TA\"\\r\\n'\n", + "2026-03-30 16:33:55,891 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"TAC\"\\r\\n'\n", + "2026-03-30 16:33:55,892 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 1 \"TAC\"\\r\\n'\n", + "2026-03-30 16:33:55,894 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"TI\"\\r\\n'\n", + "2026-03-30 16:33:55,895 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 1 \"TI\"\\r\\n'\n", + "2026-03-30 16:33:55,908 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C0\"\\r\\n'\n", + "2026-03-30 16:33:55,908 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"C0\"\\r\\n'\n", + "2026-03-30 16:33:55,923 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C1\"\\r\\n'\n", + "2026-03-30 16:33:55,924 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"C1\"\\r\\n'\n", + "2026-03-30 16:33:55,939 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C2\"\\r\\n'\n", + "2026-03-30 16:33:55,940 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"C2\"\\r\\n'\n", + "2026-03-30 16:33:55,955 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C3\"\\r\\n'\n", + "2026-03-30 16:33:55,956 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"C3\"\\r\\n'\n", + "2026-03-30 16:33:55,972 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"COM\"\\r\\n'\n", + "2026-03-30 16:33:55,972 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"COM\"\\r\\n'\n", + "2026-03-30 16:33:55,987 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"DAT\"\\r\\n'\n", + "2026-03-30 16:33:55,988 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"DAT\"\\r\\n'\n", + "2026-03-30 16:33:55,989 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I10\"\\r\\n'\n", + "2026-03-30 16:33:55,990 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"I10\"\\r\\n'\n", + "2026-03-30 16:33:56,003 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I11\"\\r\\n'\n", + "2026-03-30 16:33:56,004 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"I11\"\\r\\n'\n", + "2026-03-30 16:33:56,019 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I14\"\\r\\n'\n", + "2026-03-30 16:33:56,020 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"I14\"\\r\\n'\n", + "2026-03-30 16:33:56,035 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I15\"\\r\\n'\n", + "2026-03-30 16:33:56,036 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"I15\"\\r\\n'\n", + "2026-03-30 16:33:56,051 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I16\"\\r\\n'\n", + "2026-03-30 16:33:56,052 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"I16\"\\r\\n'\n", + "2026-03-30 16:33:56,067 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I21\"\\r\\n'\n", + "2026-03-30 16:33:56,068 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"I21\"\\r\\n'\n", + "2026-03-30 16:33:56,084 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I22\"\\r\\n'\n", + "2026-03-30 16:33:56,084 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"I22\"\\r\\n'\n", + "2026-03-30 16:33:56,099 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I23\"\\r\\n'\n", + "2026-03-30 16:33:56,100 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"I23\"\\r\\n'\n", + "2026-03-30 16:33:56,115 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I24\"\\r\\n'\n", + "2026-03-30 16:33:56,116 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"I24\"\\r\\n'\n", + "2026-03-30 16:33:56,131 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I25\"\\r\\n'\n", + "2026-03-30 16:33:56,132 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"I25\"\\r\\n'\n", + "2026-03-30 16:33:56,147 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I26\"\\r\\n'\n", + "2026-03-30 16:33:56,147 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"I26\"\\r\\n'\n", + "2026-03-30 16:33:56,163 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M01\"\\r\\n'\n", + "2026-03-30 16:33:56,164 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"M01\"\\r\\n'\n", + "2026-03-30 16:33:56,165 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M02\"\\r\\n'\n", + "2026-03-30 16:33:56,165 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"M02\"\\r\\n'\n", + "2026-03-30 16:33:56,179 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M03\"\\r\\n'\n", + "2026-03-30 16:33:56,180 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"M03\"\\r\\n'\n", + "2026-03-30 16:33:56,196 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M17\"\\r\\n'\n", + "2026-03-30 16:33:56,196 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"M17\"\\r\\n'\n", + "2026-03-30 16:33:56,211 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M18\"\\r\\n'\n", + "2026-03-30 16:33:56,211 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"M18\"\\r\\n'\n", + "2026-03-30 16:33:56,227 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M19\"\\r\\n'\n", + "2026-03-30 16:33:56,228 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"M19\"\\r\\n'\n", + "2026-03-30 16:33:56,243 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M20\"\\r\\n'\n", + "2026-03-30 16:33:56,244 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"M20\"\\r\\n'\n", + "2026-03-30 16:33:56,259 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M21\"\\r\\n'\n", + "2026-03-30 16:33:56,259 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"M21\"\\r\\n'\n", + "2026-03-30 16:33:56,275 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M27\"\\r\\n'\n", + "2026-03-30 16:33:56,276 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"M27\"\\r\\n'\n", + "2026-03-30 16:33:56,291 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M28\"\\r\\n'\n", + "2026-03-30 16:33:56,292 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"M28\"\\r\\n'\n", + "2026-03-30 16:33:56,311 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M29\"\\r\\n'\n", + "2026-03-30 16:33:56,312 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"M29\"\\r\\n'\n", + "2026-03-30 16:33:56,323 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M31\"\\r\\n'\n", + "2026-03-30 16:33:56,328 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"M31\"\\r\\n'\n", + "2026-03-30 16:33:56,331 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M32\"\\r\\n'\n", + "2026-03-30 16:33:56,334 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"M32\"\\r\\n'\n", + "2026-03-30 16:33:56,339 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M33\"\\r\\n'\n", + "2026-03-30 16:33:56,344 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"M33\"\\r\\n'\n", + "2026-03-30 16:33:56,355 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M35\"\\r\\n'\n", + "2026-03-30 16:33:56,357 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"M35\"\\r\\n'\n", + "2026-03-30 16:33:56,371 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"SIS\"\\r\\n'\n", + "2026-03-30 16:33:56,374 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"SIS\"\\r\\n'\n", + "2026-03-30 16:33:56,387 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"SNR\"\\r\\n'\n", + "2026-03-30 16:33:56,389 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"SNR\"\\r\\n'\n", + "2026-03-30 16:33:56,403 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TIM\"\\r\\n'\n", + "2026-03-30 16:33:56,404 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"TIM\"\\r\\n'\n", + "2026-03-30 16:33:56,419 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST0\"\\r\\n'\n", + "2026-03-30 16:33:56,420 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"TST0\"\\r\\n'\n", + "2026-03-30 16:33:56,435 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST1\"\\r\\n'\n", + "2026-03-30 16:33:56,436 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"TST1\"\\r\\n'\n", + "2026-03-30 16:33:56,451 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST2\"\\r\\n'\n", + "2026-03-30 16:33:56,452 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"TST2\"\\r\\n'\n", + "2026-03-30 16:33:56,467 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST3\"\\r\\n'\n", + "2026-03-30 16:33:56,468 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"TST3\"\\r\\n'\n", + "2026-03-30 16:33:56,483 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"UPD\"\\r\\n'\n", + "2026-03-30 16:33:56,484 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"UPD\"\\r\\n'\n", + "2026-03-30 16:33:56,498 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"FCUT\"\\r\\n'\n", + "2026-03-30 16:33:56,499 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 3 \"FCUT\"\\r\\n'\n", + "2026-03-30 16:33:56,515 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"FSET\"\\r\\n'\n", + "2026-03-30 16:33:56,516 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 3 \"FSET\"\\r\\n'\n", + "2026-03-30 16:33:56,531 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"LST\"\\r\\n'\n", + "2026-03-30 16:33:56,532 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 3 \"LST\"\\r\\n'\n", + "2026-03-30 16:33:56,547 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"RDB\"\\r\\n'\n", + "2026-03-30 16:33:56,548 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 3 \"RDB\"\\r\\n'\n", + "2026-03-30 16:33:56,563 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 A 3 \"USTB\"\\r\\n'\n", + "2026-03-30 16:33:56,563 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 A 3 \"USTB\"\\r\\n'\n" ] }, { @@ -520,31 +520,7 @@ "Level 0 (12 commands): @, I0, I1, I2, I3, I4, I5, S, SI, SIR, Z, ZI\n", "Level 1 (5 commands): SR, T, TA, TAC, TI\n", "Level 2 (40 commands): C0, C1, C2, C3, COM, DAT, I10, I11, I14, I15, I16, I21, I22, I23, I24, I25, I26, M01, M02, M03, M17, M18, M19, M20, M21, M27, M28, M29, M31, M32, M33, M35, SIS, SNR, TIM, TST0, TST1, TST2, TST3, UPD\n", - "Level 3 (5 commands): FCUT, FSET, LST, RDB, USTB\n", - "\n", - "Commands we use vs device support:\n", - " @: supported\n", - " C: NOT SUPPORTED\n", - " D: NOT SUPPORTED\n", - " DW: NOT SUPPORTED\n", - " I0: supported\n", - " I1: supported\n", - " I2: supported\n", - " I4: supported\n", - " I50: NOT SUPPORTED\n", - " M21: supported\n", - " M28: supported\n", - " S: supported\n", - " SC: NOT SUPPORTED\n", - " SI: supported\n", - " T: supported\n", - " TA: supported\n", - " TAC: supported\n", - " TC: NOT SUPPORTED\n", - " TI: supported\n", - " Z: supported\n", - " ZC: NOT SUPPORTED\n", - " ZI: supported\n" + "Level 3 (5 commands): FCUT, FSET, LST, RDB, USTB\n" ] } ], @@ -588,43 +564,150 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 16:24:01,630 - pylabrobot - IO - [MT Scale] Sent command: I3\n", - "2026-03-30 16:24:01,632 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I3\\r\\n'\n", - "2026-03-30 16:24:01,678 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I3 A \"1.10 18.6.4.1361.772\"\\r\\n'\n", - "2026-03-30 16:24:01,679 - pylabrobot - IO - [MT Scale] Received response: b'I3 A \"1.10 18.6.4.1361.772\"\\r\\n'\n", - "2026-03-30 16:24:01,680 - pylabrobot - IO - [MT Scale] Sent command: I5\n", - "2026-03-30 16:24:01,682 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I5\\r\\n'\n", - "2026-03-30 16:24:01,711 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I5 A \"11671158C\"\\r\\n'\n", - "2026-03-30 16:24:01,712 - pylabrobot - IO - [MT Scale] Received response: b'I5 A \"11671158C\"\\r\\n'\n", - "2026-03-30 16:24:01,714 - pylabrobot - IO - [MT Scale] Sent command: I10\n", - "2026-03-30 16:24:01,718 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I10\\r\\n'\n", - "2026-03-30 16:24:01,743 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I10 A \"\"\\r\\n'\n", - "2026-03-30 16:24:01,744 - pylabrobot - IO - [MT Scale] Received response: b'I10 A \"\"\\r\\n'\n", - "2026-03-30 16:24:01,746 - pylabrobot - IO - [MT Scale] Sent command: I11\n", - "2026-03-30 16:24:01,752 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I11\\r\\n'\n", - "2026-03-30 16:24:01,790 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I11 A \"WXS205SDU\"\\r\\n'\n", - "2026-03-30 16:24:01,791 - pylabrobot - IO - [MT Scale] Received response: b'I11 A \"WXS205SDU\"\\r\\n'\n" + "2026-03-30 16:33:56,576 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: I3\n", + "2026-03-30 16:33:56,579 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I3\\r\\n'\n", + "2026-03-30 16:33:56,630 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I3 A \"1.10 18.6.4.1361.772\"\\r\\n'\n", + "2026-03-30 16:33:56,636 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I3 A \"1.10 18.6.4.1361.772\"\\r\\n'\n", + "2026-03-30 16:33:56,639 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: I5\n", + "2026-03-30 16:33:56,643 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I5\\r\\n'\n", + "2026-03-30 16:33:56,675 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I5 A \"11671158C\"\\r\\n'\n", + "2026-03-30 16:33:56,676 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I5 A \"11671158C\"\\r\\n'\n", + "2026-03-30 16:33:56,680 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: I10\n", + "2026-03-30 16:33:56,688 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I10\\r\\n'\n", + "2026-03-30 16:33:56,723 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I10 A \"\"\\r\\n'\n", + "2026-03-30 16:33:56,727 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I10 A \"\"\\r\\n'\n", + "2026-03-30 16:33:56,728 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: I11\n", + "2026-03-30 16:33:56,737 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I11\\r\\n'\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ - "Software version: 1.10 18.6.4.1361.772\n", + "Firmware version: 1.10 18.6.4.1361.772\n", "Software material number: 11671158C\n", - "Device ID: ''\n", - "Model designation: WXS205SDU\n" + "Device ID: ''\n" ] }, { - "ename": "AttributeError", - "evalue": "'MettlerToledoWXS205SDUBackend' object has no attribute 'request_uptime'", - "output_type": "error", - "traceback": [ - "\u001b[31m---------------------------------------------------------------------------\u001b[39m", - "\u001b[31mAttributeError\u001b[39m Traceback (most recent call last)", - "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[6]\u001b[39m\u001b[32m, line 25\u001b[39m\n\u001b[32m 23\u001b[39m \u001b[38;5;66;03m# I15 - Uptime\u001b[39;00m\n\u001b[32m 24\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m \u001b[33m\"\u001b[39m\u001b[33mI15\u001b[39m\u001b[33m\"\u001b[39m \u001b[38;5;129;01min\u001b[39;00m backend._supported_commands:\n\u001b[32m---> \u001b[39m\u001b[32m25\u001b[39m uptime = \u001b[38;5;28;01mawait\u001b[39;00m \u001b[43mbackend\u001b[49m\u001b[43m.\u001b[49m\u001b[43mrequest_uptime\u001b[49m()\n\u001b[32m 26\u001b[39m \u001b[38;5;28mprint\u001b[39m(\u001b[33mf\u001b[39m\u001b[33m\"\u001b[39m\u001b[33mUptime: \u001b[39m\u001b[38;5;132;01m{\u001b[39;00muptime[\u001b[33m'\u001b[39m\u001b[33mdays\u001b[39m\u001b[33m'\u001b[39m]\u001b[38;5;132;01m}\u001b[39;00m\u001b[33md \u001b[39m\u001b[38;5;132;01m{\u001b[39;00muptime[\u001b[33m'\u001b[39m\u001b[33mhours\u001b[39m\u001b[33m'\u001b[39m]\u001b[38;5;132;01m}\u001b[39;00m\u001b[33mh \u001b[39m\u001b[38;5;132;01m{\u001b[39;00muptime[\u001b[33m'\u001b[39m\u001b[33mminutes\u001b[39m\u001b[33m'\u001b[39m]\u001b[38;5;132;01m}\u001b[39;00m\u001b[33mm \u001b[39m\u001b[38;5;132;01m{\u001b[39;00muptime[\u001b[33m'\u001b[39m\u001b[33mseconds\u001b[39m\u001b[33m'\u001b[39m]\u001b[38;5;132;01m}\u001b[39;00m\u001b[33ms\u001b[39m\u001b[33m\"\u001b[39m)\n\u001b[32m 27\u001b[39m \u001b[38;5;28;01melse\u001b[39;00m:\n", - "\u001b[31mAttributeError\u001b[39m: 'MettlerToledoWXS205SDUBackend' object has no attribute 'request_uptime'" + "name": "stderr", + "output_type": "stream", + "text": [ + "2026-03-30 16:33:56,771 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I11 A \"WXS205SDU\"\\r\\n'\n", + "2026-03-30 16:33:56,772 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I11 A \"WXS205SDU\"\\r\\n'\n", + "2026-03-30 16:33:56,773 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: I15\n", + "2026-03-30 16:33:56,775 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I15\\r\\n'\n", + "2026-03-30 16:33:56,807 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I15 A 424\\r\\n'\n", + "2026-03-30 16:33:56,808 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I15 A 424\\r\\n'\n", + "2026-03-30 16:33:56,810 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: I16\n", + "2026-03-30 16:33:56,818 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I16\\r\\n'\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Model designation: WXS205SDU\n", + "Uptime: 424 minutes (7.1 hours)\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2026-03-30 16:33:57,298 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I16 A 16 03 2013\\r\\n'\n", + "2026-03-30 16:33:57,299 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I16 A 16 03 2013\\r\\n'\n", + "2026-03-30 16:33:57,301 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: I21\n", + "2026-03-30 16:33:57,303 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I21\\r\\n'\n", + "2026-03-30 16:33:57,330 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I21 A \"5\"\\r\\n'\n", + "2026-03-30 16:33:57,332 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I21 A \"5\"\\r\\n'\n", + "2026-03-30 16:33:57,335 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: I26\n", + "2026-03-30 16:33:57,339 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I26\\r\\n'\n", + "2026-03-30 16:33:57,363 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I26 A 0\\r\\n'\n", + "2026-03-30 16:33:57,364 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I26 A 0\\r\\n'\n", + "2026-03-30 16:33:57,366 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: DAT\n", + "2026-03-30 16:33:57,368 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'DAT\\r\\n'\n", + "2026-03-30 16:33:57,411 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'DAT A 04 01 2000\\r\\n'\n", + "2026-03-30 16:33:57,413 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'DAT A 04 01 2000\\r\\n'\n", + "2026-03-30 16:33:57,415 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: TIM\n", + "2026-03-30 16:33:57,417 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'TIM\\r\\n'\n", + "2026-03-30 16:33:57,459 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'TIM A 23 39 23\\r\\n'\n", + "2026-03-30 16:33:57,462 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'TIM A 23 39 23\\r\\n'\n", + "2026-03-30 16:33:57,466 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: I14 0\n", + "2026-03-30 16:33:57,471 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I14 0\\r\\n'\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Next service date: 16 03 2013\n", + "Assortment type revision: 5\n", + "I26: I26 A 0\n", + "Device date: 04\n", + "Device time: 23\n", + "\n", + "Device info (I14):\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2026-03-30 16:33:57,507 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I14 A 0 1 \"Bridge\"\\r\\n'\n", + "2026-03-30 16:33:57,512 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I14 A 0 1 \"Bridge\"\\r\\n'\n", + "2026-03-30 16:33:57,515 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: I14 1\n", + "2026-03-30 16:33:57,517 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I14 1\\r\\n'\n", + "2026-03-30 16:33:57,554 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I14 A 1 1 \"WXS205SDU\"\\r\\n'\n", + "2026-03-30 16:33:57,554 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I14 A 1 1 \"WXS205SDU\"\\r\\n'\n", + "2026-03-30 16:33:57,555 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: I14 2\n", + "2026-03-30 16:33:57,558 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I14 2\\r\\n'\n", + "2026-03-30 16:33:57,603 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I14 A 2 1 \"11671158C\"\\r\\n'\n", + "2026-03-30 16:33:57,604 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I14 A 2 1 \"11671158C\"\\r\\n'\n", + "2026-03-30 16:33:57,605 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: I14 3\n", + "2026-03-30 16:33:57,607 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I14 3\\r\\n'\n", + "2026-03-30 16:33:57,650 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I14 A 3 1 \"1.10\"\\r\\n'\n", + "2026-03-30 16:33:57,651 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I14 A 3 1 \"1.10\"\\r\\n'\n", + "2026-03-30 16:33:57,651 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: I14 4\n", + "2026-03-30 16:33:57,652 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I14 4\\r\\n'\n", + "2026-03-30 16:33:57,698 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I14 A 4 1 \"B207696838\"\\r\\n'\n", + "2026-03-30 16:33:57,698 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I14 A 4 1 \"B207696838\"\\r\\n'\n", + "2026-03-30 16:33:57,699 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: I14 5\n", + "2026-03-30 16:33:57,700 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I14 5\\r\\n'\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Category 0 (Instrument configuration):\n", + " I14 A 0 1 Bridge\n", + " Category 1 (Instrument descriptions):\n", + " I14 A 1 1 WXS205SDU\n", + " Category 2 (SW identification numbers):\n", + " I14 A 2 1 11671158C\n", + " Category 3 (SW versions):\n", + " I14 A 3 1 1.10\n", + " Category 4 (Serial numbers):\n", + " I14 A 4 1 B207696838\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2026-03-30 16:33:57,746 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I14 A 5 1 \"18.6.4.1361.772\"\\r\\n'\n", + "2026-03-30 16:33:57,747 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I14 A 5 1 \"18.6.4.1361.772\"\\r\\n'\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Category 5 (TDNR numbers):\n", + " I14 A 5 1 18.6.4.1361.772\n", + "\n", + "PASS: Batch 1 device identity commands completed\n" ] } ], @@ -732,9 +815,76 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 7, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2026-03-30 16:33:57,762 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] reset_input_buffer\n", + "2026-03-30 16:33:57,766 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: @\n", + "2026-03-30 16:33:57,770 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'@\\r\\n'\n", + "2026-03-30 16:33:57,827 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I4 A \"B207696838\"\\r\\n'\n", + "2026-03-30 16:33:57,828 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I4 A \"B207696838\"\\r\\n'\n", + "2026-03-30 16:33:57,829 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: I4\n", + "2026-03-30 16:33:57,833 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I4\\r\\n'\n", + "2026-03-30 16:33:57,874 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I4 A \"B207696838\"\\r\\n'\n", + "2026-03-30 16:33:57,875 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I4 A \"B207696838\"\\r\\n'\n", + "2026-03-30 16:33:57,876 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: I2\n", + "2026-03-30 16:33:57,878 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I2\\r\\n'\n", + "2026-03-30 16:33:57,937 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", + "2026-03-30 16:33:57,938 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", + "2026-03-30 16:33:57,938 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: I2\n", + "2026-03-30 16:33:57,940 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I2\\r\\n'\n", + "2026-03-30 16:33:58,001 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", + "2026-03-30 16:33:58,002 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", + "2026-03-30 16:33:58,004 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: S\n", + "2026-03-30 16:33:58,005 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", + "2026-03-30 16:33:58,401 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00008 g\\r\\n'\n", + "2026-03-30 16:33:58,403 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'S S 0.00008 g\\r\\n'\n", + "2026-03-30 16:33:58,406 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: SI\n", + "2026-03-30 16:33:58,409 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", + "2026-03-30 16:33:58,449 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00008 g\\r\\n'\n", + "2026-03-30 16:33:58,449 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'S S 0.00008 g\\r\\n'\n", + "2026-03-30 16:33:58,450 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: Z\n", + "2026-03-30 16:33:58,452 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'Z\\r\\n'\n", + "2026-03-30 16:33:58,688 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'Z A\\r\\n'\n", + "2026-03-30 16:33:58,689 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'Z A\\r\\n'\n", + "2026-03-30 16:33:58,690 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: SI\n", + "2026-03-30 16:33:58,691 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", + "2026-03-30 16:33:58,721 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 16:33:58,722 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 16:33:58,722 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: ZI\n", + "2026-03-30 16:33:58,724 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'ZI\\r\\n'\n", + "2026-03-30 16:33:58,752 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'ZI S\\r\\n'\n", + "2026-03-30 16:33:58,753 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'ZI S\\r\\n'\n", + "2026-03-30 16:33:58,754 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: SI\n", + "2026-03-30 16:33:58,755 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", + "2026-03-30 16:33:58,785 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 16:33:58,786 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 16:33:58,786 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: TA\n", + "2026-03-30 16:33:58,788 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'TA\\r\\n'\n", + "2026-03-30 16:33:58,897 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'TA A 0.00000 g\\r\\n'\n", + "2026-03-30 16:33:58,897 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'TA A 0.00000 g\\r\\n'\n", + "2026-03-30 16:33:58,898 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: TAC\n", + "2026-03-30 16:33:58,899 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'TAC\\r\\n'\n", + "2026-03-30 16:33:58,928 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'TAC A\\r\\n'\n", + "2026-03-30 16:33:58,929 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'TAC A\\r\\n'\n", + "2026-03-30 16:33:58,930 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: TA\n", + "2026-03-30 16:33:58,931 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'TA\\r\\n'\n", + "2026-03-30 16:33:58,992 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'TA A 0.00000 g\\r\\n'\n", + "2026-03-30 16:33:58,993 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'TA A 0.00000 g\\r\\n'\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "PASS: all core Level 0/1 commands validated\n" + ] + } + ], "source": [ "# @ - Cancel (returns serial number)\n", "sn = await backend.reset()\n", @@ -799,9 +949,53 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 8, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdin", + "output_type": "stream", + "text": [ + "Place a container on the scale and press Enter... \n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2026-03-30 16:34:04,612 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: Z\n", + "2026-03-30 16:34:04,614 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'Z\\r\\n'\n", + "2026-03-30 16:34:04,988 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'Z A\\r\\n'\n", + "2026-03-30 16:34:04,988 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'Z A\\r\\n'\n", + "2026-03-30 16:34:04,989 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: T\n", + "2026-03-30 16:34:04,992 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'T\\r\\n'\n", + "2026-03-30 16:34:05,388 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'T S 0.00000 g\\r\\n'\n", + "2026-03-30 16:34:05,388 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'T S 0.00000 g\\r\\n'\n", + "2026-03-30 16:34:05,391 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: TA\n", + "2026-03-30 16:34:05,393 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'TA\\r\\n'\n", + "2026-03-30 16:34:05,483 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'TA A 0.00000 g\\r\\n'\n", + "2026-03-30 16:34:05,484 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'TA A 0.00000 g\\r\\n'\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Tare weight: 0.0 g\n" + ] + }, + { + "ename": "AssertionError", + "evalue": "Expected positive tare, got 0.0", + "output_type": "error", + "traceback": [ + "\u001b[31m---------------------------------------------------------------------------\u001b[39m", + "\u001b[31mAssertionError\u001b[39m Traceback (most recent call last)", + "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[8]\u001b[39m\u001b[32m, line 6\u001b[39m\n\u001b[32m 4\u001b[39m tare = \u001b[38;5;28;01mawait\u001b[39;00m scale.request_tare_weight()\n\u001b[32m 5\u001b[39m \u001b[38;5;28mprint\u001b[39m(\u001b[33mf\u001b[39m\u001b[33m\"\u001b[39m\u001b[33mTare weight: \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mtare\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m g\u001b[39m\u001b[33m\"\u001b[39m)\n\u001b[32m----> \u001b[39m\u001b[32m6\u001b[39m \u001b[38;5;28;01massert\u001b[39;00m tare > \u001b[32m0\u001b[39m, \u001b[33mf\u001b[39m\u001b[33m\"\u001b[39m\u001b[33mExpected positive tare, got \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mtare\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m\"\u001b[39m\n\u001b[32m 7\u001b[39m \u001b[38;5;28mprint\u001b[39m(\u001b[33m\"\u001b[39m\u001b[33mPASS: tare stores container weight\u001b[39m\u001b[33m\"\u001b[39m)\n", + "\u001b[31mAssertionError\u001b[39m: Expected positive tare, got 0.0" + ] + } + ], "source": [ "input(\"Place a container on the scale and press Enter...\")\n", "await scale.zero(timeout=\"stable\")\n", @@ -821,9 +1015,28 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 9, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2026-03-30 16:34:12,398 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: TA\n", + "2026-03-30 16:34:12,401 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'TA\\r\\n'\n", + "2026-03-30 16:34:12,469 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'TA A 0.00000 g\\r\\n'\n", + "2026-03-30 16:34:12,472 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'TA A 0.00000 g\\r\\n'\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Tare weight from memory: 0.0 g\n", + "PASS: tare weight readable from memory\n" + ] + } + ], "source": [ "tare = await scale.request_tare_weight()\n", "print(f\"Tare weight from memory: {tare} g\")\n", @@ -840,9 +1053,32 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 10, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2026-03-30 16:34:13,336 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: TAC\n", + "2026-03-30 16:34:13,339 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'TAC\\r\\n'\n", + "2026-03-30 16:34:13,365 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'TAC A\\r\\n'\n", + "2026-03-30 16:34:13,367 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'TAC A\\r\\n'\n", + "2026-03-30 16:34:13,368 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: TA\n", + "2026-03-30 16:34:13,374 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'TA\\r\\n'\n", + "2026-03-30 16:34:13,445 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'TA A 0.00000 g\\r\\n'\n", + "2026-03-30 16:34:13,448 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'TA A 0.00000 g\\r\\n'\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Tare after clear: 0.0 g\n", + "PASS: clear tare resets tare to 0\n" + ] + } + ], "source": [ "await backend.clear_tare()\n", "tare_after_clear = await scale.request_tare_weight()\n", @@ -868,9 +1104,27 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 11, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2026-03-30 16:34:16,488 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: M21 0 0\n", + "2026-03-30 16:34:16,489 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'M21 0 0\\r\\n'\n", + "2026-03-30 16:34:16,529 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M21 A\\r\\n'\n", + "2026-03-30 16:34:16,530 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'M21 A\\r\\n'\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "PASS: host unit set to grams\n" + ] + } + ], "source": [ "if \"M21\" in backend._supported_commands:\n", " await backend.set_host_unit_grams()\n", @@ -888,9 +1142,17 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 12, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "SKIP: I50 not supported on this device\n" + ] + } + ], "source": [ "if \"I50\" in backend._supported_commands:\n", " remaining = await backend.request_remaining_weighing_range()\n", @@ -911,9 +1173,30 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 13, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2026-03-30 16:34:18,754 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: M28\n", + "2026-03-30 16:34:18,756 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'M28\\r\\n'\n", + "2026-03-30 16:34:18,800 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M28 B 1 19.5\\r\\n'\n", + "2026-03-30 16:34:18,804 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'M28 B 1 19.5\\r\\n'\n", + "2026-03-30 16:34:18,808 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M28 A 2 18.9\\r\\n'\n", + "2026-03-30 16:34:18,813 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'M28 A 2 18.9\\r\\n'\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Scale temperature: 19.5 C\n", + "PASS: measure_temperature works - I0 correctly predicted M28 support\n" + ] + } + ], "source": [ "if \"M28\" in backend._supported_commands:\n", " temp = await backend.measure_temperature()\n", @@ -935,9 +1218,410 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 14, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2026-03-30 16:34:20,135 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: M01\n", + "2026-03-30 16:34:20,137 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'M01\\r\\n'\n", + "2026-03-30 16:34:20,158 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M01 A 0\\r\\n'\n", + "2026-03-30 16:34:20,158 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'M01 A 0\\r\\n'\n", + "2026-03-30 16:34:20,161 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: M02\n", + "2026-03-30 16:34:20,162 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'M02\\r\\n'\n", + "2026-03-30 16:34:20,191 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M02 A 2\\r\\n'\n", + "2026-03-30 16:34:20,192 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'M02 A 2\\r\\n'\n", + "2026-03-30 16:34:20,193 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: M03\n", + "2026-03-30 16:34:20,196 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'M03\\r\\n'\n", + "2026-03-30 16:34:20,222 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M03 A 0\\r\\n'\n", + "2026-03-30 16:34:20,224 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'M03 A 0\\r\\n'\n", + "2026-03-30 16:34:20,225 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: M17\n", + "2026-03-30 16:34:20,230 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'M17\\r\\n'\n", + "2026-03-30 16:34:20,271 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M17 A 00 00 00 0\\r\\n'\n", + "2026-03-30 16:34:20,273 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'M17 A 00 00 00 0\\r\\n'\n", + "2026-03-30 16:34:20,275 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: M18\n", + "2026-03-30 16:34:20,278 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'M18\\r\\n'\n", + "2026-03-30 16:34:20,302 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M18 A 1\\r\\n'\n", + "2026-03-30 16:34:20,303 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'M18 A 1\\r\\n'\n", + "2026-03-30 16:34:20,305 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: M19\n", + "2026-03-30 16:34:20,309 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'M19\\r\\n'\n", + "2026-03-30 16:34:20,350 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M19 A 10.00000 g\\r\\n'\n", + "2026-03-30 16:34:20,351 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'M19 A 10.00000 g\\r\\n'\n", + "2026-03-30 16:34:20,352 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: M20\n", + "2026-03-30 16:34:20,356 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'M20\\r\\n'\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Weighing mode: 0 (Normal/Universal)\n", + "Environment condition: 2 (Standard)\n", + "Auto zero: 0 (off)\n", + "ProFACT time criteria: A 00 00 00 0\n", + "ProFACT temperature criterion: A 1\n", + "Adjustment weight: A 10.00000 g\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2026-03-30 16:34:20,398 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M20 A 200.00000 g\\r\\n'\n", + "2026-03-30 16:34:20,399 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'M20 A 200.00000 g\\r\\n'\n", + "2026-03-30 16:34:20,400 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: M27\n", + "2026-03-30 16:34:20,403 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'M27\\r\\n'\n", + "2026-03-30 16:34:20,461 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 1 13 05 2020 17 17 0 \"\"\\r\\n'\n", + "2026-03-30 16:34:20,462 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'M27 B 1 13 05 2020 17 17 0 \"\"\\r\\n'\n", + "2026-03-30 16:34:20,495 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 2 02 12 2019 20 02 0 \"\"\\r\\n'\n", + "2026-03-30 16:34:20,497 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'M27 B 2 02 12 2019 20 02 0 \"\"\\r\\n'\n", + "2026-03-30 16:34:20,526 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 3 11 10 2019 17 05 0 \"\"\\r\\n'\n", + "2026-03-30 16:34:20,527 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'M27 B 3 11 10 2019 17 05 0 \"\"\\r\\n'\n", + "2026-03-30 16:34:20,557 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 4 11 10 2019 17 01 0 \"\"\\r\\n'\n", + "2026-03-30 16:34:20,558 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'M27 B 4 11 10 2019 17 01 0 \"\"\\r\\n'\n", + "2026-03-30 16:34:20,589 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 5 14 03 2019 20 22 0 \"\"\\r\\n'\n", + "2026-03-30 16:34:20,589 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'M27 B 5 14 03 2019 20 22 0 \"\"\\r\\n'\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Test weight: A 200.00000 g\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2026-03-30 16:34:20,621 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 6 14 03 2019 20 18 0 \"\"\\r\\n'\n", + "2026-03-30 16:34:20,623 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'M27 B 6 14 03 2019 20 18 0 \"\"\\r\\n'\n", + "2026-03-30 16:34:20,653 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 7 17 10 2018 17 38 0 \"\"\\r\\n'\n", + "2026-03-30 16:34:20,654 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'M27 B 7 17 10 2018 17 38 0 \"\"\\r\\n'\n", + "2026-03-30 16:34:20,685 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 8 17 10 2018 17 37 0 \"\"\\r\\n'\n", + "2026-03-30 16:34:20,686 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'M27 B 8 17 10 2018 17 37 0 \"\"\\r\\n'\n", + "2026-03-30 16:34:20,717 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 9 17 10 2018 17 35 0 \"\"\\r\\n'\n", + "2026-03-30 16:34:20,718 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'M27 B 9 17 10 2018 17 35 0 \"\"\\r\\n'\n", + "2026-03-30 16:34:20,749 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 10 20 09 2018 21 23 0 \"\"\\r\\n'\n", + "2026-03-30 16:34:20,749 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'M27 B 10 20 09 2018 21 23 0 \"\"\\r\\n'\n", + "2026-03-30 16:34:20,781 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 11 15 03 2018 23 51 0 \"\"\\r\\n'\n", + "2026-03-30 16:34:20,782 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'M27 B 11 15 03 2018 23 51 0 \"\"\\r\\n'\n", + "2026-03-30 16:34:20,813 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 12 16 12 2017 00 20 0 \"\"\\r\\n'\n", + "2026-03-30 16:34:20,814 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'M27 B 12 16 12 2017 00 20 0 \"\"\\r\\n'\n", + "2026-03-30 16:34:20,845 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 13 16 12 2017 00 18 0 \"\"\\r\\n'\n", + "2026-03-30 16:34:20,846 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'M27 B 13 16 12 2017 00 18 0 \"\"\\r\\n'\n", + "2026-03-30 16:34:20,877 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 14 18 10 2017 12 06 0 \"\"\\r\\n'\n", + "2026-03-30 16:34:20,877 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'M27 B 14 18 10 2017 12 06 0 \"\"\\r\\n'\n", + "2026-03-30 16:34:20,924 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 15 18 10 2017 11 58 0 \"\"\\r\\n'\n", + "2026-03-30 16:34:20,925 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'M27 B 15 18 10 2017 11 58 0 \"\"\\r\\n'\n", + "2026-03-30 16:34:20,957 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 16 05 09 2017 22 40 0 \"\"\\r\\n'\n", + "2026-03-30 16:34:20,958 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'M27 B 16 05 09 2017 22 40 0 \"\"\\r\\n'\n", + "2026-03-30 16:34:20,988 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 17 21 06 2017 18 39 0 \"\"\\r\\n'\n", + "2026-03-30 16:34:20,989 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'M27 B 17 21 06 2017 18 39 0 \"\"\\r\\n'\n", + "2026-03-30 16:34:21,021 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 18 30 03 2017 19 24 0 \"\"\\r\\n'\n", + "2026-03-30 16:34:21,022 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'M27 B 18 30 03 2017 19 24 0 \"\"\\r\\n'\n", + "2026-03-30 16:34:21,053 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 19 09 03 2017 23 21 0 \"\"\\r\\n'\n", + "2026-03-30 16:34:21,053 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'M27 B 19 09 03 2017 23 21 0 \"\"\\r\\n'\n", + "2026-03-30 16:34:21,084 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 20 09 03 2017 23 19 0 \"\"\\r\\n'\n", + "2026-03-30 16:34:21,085 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'M27 B 20 09 03 2017 23 19 0 \"\"\\r\\n'\n", + "2026-03-30 16:34:21,117 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 21 20 12 2016 21 55 0 \"\"\\r\\n'\n", + "2026-03-30 16:34:21,117 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'M27 B 21 20 12 2016 21 55 0 \"\"\\r\\n'\n", + "2026-03-30 16:34:21,148 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 22 19 10 2016 17 36 0 \"\"\\r\\n'\n", + "2026-03-30 16:34:21,149 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'M27 B 22 19 10 2016 17 36 0 \"\"\\r\\n'\n", + "2026-03-30 16:34:21,181 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 23 19 10 2016 17 33 0 \"\"\\r\\n'\n", + "2026-03-30 16:34:21,182 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'M27 B 23 19 10 2016 17 33 0 \"\"\\r\\n'\n", + "2026-03-30 16:34:21,212 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 24 18 10 2016 21 00 0 \"\"\\r\\n'\n", + "2026-03-30 16:34:21,214 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'M27 B 24 18 10 2016 21 00 0 \"\"\\r\\n'\n", + "2026-03-30 16:34:21,245 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 25 18 10 2016 18 47 0 \"\"\\r\\n'\n", + "2026-03-30 16:34:21,246 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'M27 B 25 18 10 2016 18 47 0 \"\"\\r\\n'\n", + "2026-03-30 16:34:21,293 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 26 18 10 2016 15 33 0 \"\"\\r\\n'\n", + "2026-03-30 16:34:21,293 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'M27 B 26 18 10 2016 15 33 0 \"\"\\r\\n'\n", + "2026-03-30 16:34:21,324 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 27 18 10 2016 14 32 0 \"\"\\r\\n'\n", + "2026-03-30 16:34:21,325 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'M27 B 27 18 10 2016 14 32 0 \"\"\\r\\n'\n", + "2026-03-30 16:34:21,357 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 28 18 10 2016 14 28 0 \"\"\\r\\n'\n", + "2026-03-30 16:34:21,357 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'M27 B 28 18 10 2016 14 28 0 \"\"\\r\\n'\n", + "2026-03-30 16:34:21,388 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 29 18 10 2016 13 41 0 \"\"\\r\\n'\n", + "2026-03-30 16:34:21,389 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'M27 B 29 18 10 2016 13 41 0 \"\"\\r\\n'\n", + "2026-03-30 16:34:21,422 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 30 21 09 2016 15 15 0 \"\"\\r\\n'\n", + "2026-03-30 16:34:21,423 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'M27 B 30 21 09 2016 15 15 0 \"\"\\r\\n'\n", + "2026-03-30 16:34:21,452 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 31 04 03 2016 22 28 0 \"\"\\r\\n'\n", + "2026-03-30 16:34:21,453 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'M27 B 31 04 03 2016 22 28 0 \"\"\\r\\n'\n", + "2026-03-30 16:34:21,484 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 32 01 10 2015 19 06 0 \"\"\\r\\n'\n", + "2026-03-30 16:34:21,485 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'M27 B 32 01 10 2015 19 06 0 \"\"\\r\\n'\n", + "2026-03-30 16:34:21,517 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 33 01 10 2015 18 56 0 \"\"\\r\\n'\n", + "2026-03-30 16:34:21,517 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'M27 B 33 01 10 2015 18 56 0 \"\"\\r\\n'\n", + "2026-03-30 16:34:21,548 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 34 03 09 2015 22 11 0 \"\"\\r\\n'\n", + "2026-03-30 16:34:21,549 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'M27 B 34 03 09 2015 22 11 0 \"\"\\r\\n'\n", + "2026-03-30 16:34:21,581 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 35 11 03 2015 13 20 0 \"\"\\r\\n'\n", + "2026-03-30 16:34:21,581 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'M27 B 35 11 03 2015 13 20 0 \"\"\\r\\n'\n", + "2026-03-30 16:34:21,612 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 36 11 03 2015 13 18 0 \"\"\\r\\n'\n", + "2026-03-30 16:34:21,613 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'M27 B 36 11 03 2015 13 18 0 \"\"\\r\\n'\n", + "2026-03-30 16:34:21,644 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 37 11 03 2015 13 15 0 \"\"\\r\\n'\n", + "2026-03-30 16:34:21,644 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'M27 B 37 11 03 2015 13 15 0 \"\"\\r\\n'\n", + "2026-03-30 16:34:21,691 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 38 11 03 2015 13 13 0 \"\"\\r\\n'\n", + "2026-03-30 16:34:21,692 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'M27 B 38 11 03 2015 13 13 0 \"\"\\r\\n'\n", + "2026-03-30 16:34:21,724 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 39 22 01 2015 03 17 0 \"\"\\r\\n'\n", + "2026-03-30 16:34:21,725 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'M27 B 39 22 01 2015 03 17 0 \"\"\\r\\n'\n", + "2026-03-30 16:34:21,755 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 40 22 01 2015 03 15 0 \"\"\\r\\n'\n", + "2026-03-30 16:34:21,756 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'M27 B 40 22 01 2015 03 15 0 \"\"\\r\\n'\n", + "2026-03-30 16:34:21,788 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 41 06 11 2014 17 08 0 \"\"\\r\\n'\n", + "2026-03-30 16:34:21,789 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'M27 B 41 06 11 2014 17 08 0 \"\"\\r\\n'\n", + "2026-03-30 16:34:21,823 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 42 06 11 2014 16 22 0 \"\"\\r\\n'\n", + "2026-03-30 16:34:21,824 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'M27 B 42 06 11 2014 16 22 0 \"\"\\r\\n'\n", + "2026-03-30 16:34:21,852 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 43 06 11 2014 16 20 0 \"\"\\r\\n'\n", + "2026-03-30 16:34:21,853 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'M27 B 43 06 11 2014 16 20 0 \"\"\\r\\n'\n", + "2026-03-30 16:34:21,884 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 44 06 11 2014 15 57 0 \"\"\\r\\n'\n", + "2026-03-30 16:34:21,885 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'M27 B 44 06 11 2014 15 57 0 \"\"\\r\\n'\n", + "2026-03-30 16:34:21,915 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 45 18 09 2014 20 23 0 \"\"\\r\\n'\n", + "2026-03-30 16:34:21,916 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'M27 B 45 18 09 2014 20 23 0 \"\"\\r\\n'\n", + "2026-03-30 16:34:21,948 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 46 18 09 2014 19 54 0 \"\"\\r\\n'\n", + "2026-03-30 16:34:21,949 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'M27 B 46 18 09 2014 19 54 0 \"\"\\r\\n'\n", + "2026-03-30 16:34:21,980 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 47 18 09 2014 19 44 0 \"\"\\r\\n'\n", + "2026-03-30 16:34:21,980 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'M27 B 47 18 09 2014 19 44 0 \"\"\\r\\n'\n", + "2026-03-30 16:34:22,012 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 48 18 09 2014 19 35 0 \"\"\\r\\n'\n", + "2026-03-30 16:34:22,013 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'M27 B 48 18 09 2014 19 35 0 \"\"\\r\\n'\n", + "2026-03-30 16:34:22,044 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 49 15 09 2014 20 08 0 \"\"\\r\\n'\n", + "2026-03-30 16:34:22,044 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'M27 B 49 15 09 2014 20 08 0 \"\"\\r\\n'\n", + "2026-03-30 16:34:22,091 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 A 50 15 09 2014 19 39 0 \"\"\\r\\n'\n", + "2026-03-30 16:34:22,092 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'M27 A 50 15 09 2014 19 39 0 \"\"\\r\\n'\n", + "2026-03-30 16:34:22,094 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: M29\n", + "2026-03-30 16:34:22,095 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'M29\\r\\n'\n", + "2026-03-30 16:34:22,124 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M29 A 1\\r\\n'\n", + "2026-03-30 16:34:22,125 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'M29 A 1\\r\\n'\n", + "2026-03-30 16:34:22,126 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: M31\n", + "2026-03-30 16:34:22,127 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'M31\\r\\n'\n", + "2026-03-30 16:34:22,156 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M31 A 0\\r\\n'\n", + "2026-03-30 16:34:22,156 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'M31 A 0\\r\\n'\n", + "2026-03-30 16:34:22,158 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: M32\n", + "2026-03-30 16:34:22,159 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'M32\\r\\n'\n", + "2026-03-30 16:34:22,188 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M32 B 1 00 00 0\\r\\n'\n", + "2026-03-30 16:34:22,189 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'M32 B 1 00 00 0\\r\\n'\n", + "2026-03-30 16:34:22,220 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M32 B 2 00 00 0\\r\\n'\n", + "2026-03-30 16:34:22,221 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'M32 B 2 00 00 0\\r\\n'\n", + "2026-03-30 16:34:22,236 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M32 A 3 00 00 0\\r\\n'\n", + "2026-03-30 16:34:22,237 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'M32 A 3 00 00 0\\r\\n'\n", + "2026-03-30 16:34:22,238 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: M33\n", + "2026-03-30 16:34:22,240 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'M33\\r\\n'\n", + "2026-03-30 16:34:22,268 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M33 A 0\\r\\n'\n", + "2026-03-30 16:34:22,268 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'M33 A 0\\r\\n'\n", + "2026-03-30 16:34:22,269 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: M35\n", + "2026-03-30 16:34:22,271 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'M35\\r\\n'\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "Adjustment history (50 entries):\n", + " M27 B 1 13 05 2020 17 17 0 \n", + " M27 B 2 02 12 2019 20 02 0 \n", + " M27 B 3 11 10 2019 17 05 0 \n", + " M27 B 4 11 10 2019 17 01 0 \n", + " M27 B 5 14 03 2019 20 22 0 \n", + " M27 B 6 14 03 2019 20 18 0 \n", + " M27 B 7 17 10 2018 17 38 0 \n", + " M27 B 8 17 10 2018 17 37 0 \n", + " M27 B 9 17 10 2018 17 35 0 \n", + " M27 B 10 20 09 2018 21 23 0 \n", + " M27 B 11 15 03 2018 23 51 0 \n", + " M27 B 12 16 12 2017 00 20 0 \n", + " M27 B 13 16 12 2017 00 18 0 \n", + " M27 B 14 18 10 2017 12 06 0 \n", + " M27 B 15 18 10 2017 11 58 0 \n", + " M27 B 16 05 09 2017 22 40 0 \n", + " M27 B 17 21 06 2017 18 39 0 \n", + " M27 B 18 30 03 2017 19 24 0 \n", + " M27 B 19 09 03 2017 23 21 0 \n", + " M27 B 20 09 03 2017 23 19 0 \n", + " M27 B 21 20 12 2016 21 55 0 \n", + " M27 B 22 19 10 2016 17 36 0 \n", + " M27 B 23 19 10 2016 17 33 0 \n", + " M27 B 24 18 10 2016 21 00 0 \n", + " M27 B 25 18 10 2016 18 47 0 \n", + " M27 B 26 18 10 2016 15 33 0 \n", + " M27 B 27 18 10 2016 14 32 0 \n", + " M27 B 28 18 10 2016 14 28 0 \n", + " M27 B 29 18 10 2016 13 41 0 \n", + " M27 B 30 21 09 2016 15 15 0 \n", + " M27 B 31 04 03 2016 22 28 0 \n", + " M27 B 32 01 10 2015 19 06 0 \n", + " M27 B 33 01 10 2015 18 56 0 \n", + " M27 B 34 03 09 2015 22 11 0 \n", + " M27 B 35 11 03 2015 13 20 0 \n", + " M27 B 36 11 03 2015 13 18 0 \n", + " M27 B 37 11 03 2015 13 15 0 \n", + " M27 B 38 11 03 2015 13 13 0 \n", + " M27 B 39 22 01 2015 03 17 0 \n", + " M27 B 40 22 01 2015 03 15 0 \n", + " M27 B 41 06 11 2014 17 08 0 \n", + " M27 B 42 06 11 2014 16 22 0 \n", + " M27 B 43 06 11 2014 16 20 0 \n", + " M27 B 44 06 11 2014 15 57 0 \n", + " M27 B 45 18 09 2014 20 23 0 \n", + " M27 B 46 18 09 2014 19 54 0 \n", + " M27 B 47 18 09 2014 19 44 0 \n", + " M27 B 48 18 09 2014 19 35 0 \n", + " M27 B 49 15 09 2014 20 08 0 \n", + " M27 A 50 15 09 2014 19 39 0 \n", + "Weighing value release: A 1\n", + "Operating mode: A 0\n", + "ProFACT time: B 1 00 00 0\n", + "ProFACT day: A 0\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2026-03-30 16:34:22,300 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M35 A 0\\r\\n'\n", + "2026-03-30 16:34:22,301 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'M35 A 0\\r\\n'\n", + "2026-03-30 16:34:22,302 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: UPD\n", + "2026-03-30 16:34:22,304 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'UPD\\r\\n'\n", + "2026-03-30 16:34:22,348 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'UPD A 10.173\\r\\n'\n", + "2026-03-30 16:34:22,349 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'UPD A 10.173\\r\\n'\n", + "2026-03-30 16:34:22,355 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: SIS\n", + "2026-03-30 16:34:22,357 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SIS\\r\\n'\n", + "2026-03-30 16:34:22,411 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'SIS A 0 \"0.00000\" 0 5 1 0 0\\r\\n'\n", + "2026-03-30 16:34:22,415 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'SIS A 0 \"0.00000\" 0 5 1 0 0\\r\\n'\n", + "2026-03-30 16:34:22,420 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: C0\n", + "2026-03-30 16:34:22,423 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'C0\\r\\n'\n", + "2026-03-30 16:34:22,460 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'C0 A 0 0 \"\"\\r\\n'\n", + "2026-03-30 16:34:22,461 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'C0 A 0 0 \"\"\\r\\n'\n", + "2026-03-30 16:34:22,463 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: COM\n", + "2026-03-30 16:34:22,465 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'COM\\r\\n'\n", + "2026-03-30 16:34:22,492 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'COM A 0 6 3 1\\r\\n'\n", + "2026-03-30 16:34:22,495 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'COM A 0 6 3 1\\r\\n'\n", + "2026-03-30 16:34:22,496 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: FCUT\n", + "2026-03-30 16:34:22,502 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'FCUT\\r\\n'\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Zeroing mode: A 0\n", + "\n", + "Update rate: 10.173 values/s\n", + "Net weight with status: SIS A 0 0.00000 0 5 1 0 0\n", + "Adjustment setting: A 0 0 \n", + "Serial parameters: A 0 6 3 1\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2026-03-30 16:34:22,540 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'FCUT A 0.000\\r\\n'\n", + "2026-03-30 16:34:22,541 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'FCUT A 0.000\\r\\n'\n", + "2026-03-30 16:34:22,543 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: LST\n", + "2026-03-30 16:34:22,545 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'LST\\r\\n'\n", + "2026-03-30 16:34:22,588 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B C0 0 0 \"\"\\r\\n'\n", + "2026-03-30 16:34:22,589 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'LST B C0 0 0 \"\"\\r\\n'\n", + "2026-03-30 16:34:22,604 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B FCUT 0.000\\r\\n'\n", + "2026-03-30 16:34:22,605 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'LST B FCUT 0.000\\r\\n'\n", + "2026-03-30 16:34:22,619 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B I10 \"\"\\r\\n'\n", + "2026-03-30 16:34:22,620 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'LST B I10 \"\"\\r\\n'\n", + "2026-03-30 16:34:22,639 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B M01 0\\r\\n'\n", + "2026-03-30 16:34:22,640 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'LST B M01 0\\r\\n'\n", + "2026-03-30 16:34:22,652 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B M02 2\\r\\n'\n", + "2026-03-30 16:34:22,654 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'LST B M02 2\\r\\n'\n", + "2026-03-30 16:34:22,667 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B M03 0\\r\\n'\n", + "2026-03-30 16:34:22,669 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'LST B M03 0\\r\\n'\n", + "2026-03-30 16:34:22,684 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B M17 00 00 00 0\\r\\n'\n", + "2026-03-30 16:34:22,685 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'LST B M17 00 00 00 0\\r\\n'\n", + "2026-03-30 16:34:22,700 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B M18 1\\r\\n'\n", + "2026-03-30 16:34:22,702 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'LST B M18 1\\r\\n'\n", + "2026-03-30 16:34:22,716 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B M19 10.00000 g\\r\\n'\n", + "2026-03-30 16:34:22,717 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'LST B M19 10.00000 g\\r\\n'\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Filter cut-off: A 0.000\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2026-03-30 16:34:22,747 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B M20 200.00000 g\\r\\n'\n", + "2026-03-30 16:34:22,748 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'LST B M20 200.00000 g\\r\\n'\n", + "2026-03-30 16:34:22,767 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B M21 0 0\\r\\n'\n", + "2026-03-30 16:34:22,768 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'LST B M21 0 0\\r\\n'\n", + "2026-03-30 16:34:22,779 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B M29 1\\r\\n'\n", + "2026-03-30 16:34:22,782 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'LST B M29 1\\r\\n'\n", + "2026-03-30 16:34:22,796 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B M31 0\\r\\n'\n", + "2026-03-30 16:34:22,798 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'LST B M31 0\\r\\n'\n", + "2026-03-30 16:34:22,812 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B M32 1 00 00 0\\r\\n'\n", + "2026-03-30 16:34:22,813 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'LST B M32 1 00 00 0\\r\\n'\n", + "2026-03-30 16:34:22,827 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B M32 2 00 00 0\\r\\n'\n", + "2026-03-30 16:34:22,829 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'LST B M32 2 00 00 0\\r\\n'\n", + "2026-03-30 16:34:22,859 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B M32 3 00 00 0\\r\\n'\n", + "2026-03-30 16:34:22,860 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'LST B M32 3 00 00 0\\r\\n'\n", + "2026-03-30 16:34:22,863 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B M33 0\\r\\n'\n", + "2026-03-30 16:34:22,865 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'LST B M33 0\\r\\n'\n", + "2026-03-30 16:34:22,875 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B M35 0\\r\\n'\n", + "2026-03-30 16:34:22,876 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'LST B M35 0\\r\\n'\n", + "2026-03-30 16:34:22,892 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B RDB 5\\r\\n'\n", + "2026-03-30 16:34:22,899 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'LST B RDB 5\\r\\n'\n", + "2026-03-30 16:34:22,907 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B TST0 0 \"\"\\r\\n'\n", + "2026-03-30 16:34:22,910 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'LST B TST0 0 \"\"\\r\\n'\n", + "2026-03-30 16:34:22,924 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B UPD 10.173\\r\\n'\n", + "2026-03-30 16:34:22,925 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'LST B UPD 10.173\\r\\n'\n", + "2026-03-30 16:34:22,955 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B USTB 0 3.600 1.100\\r\\n'\n", + "2026-03-30 16:34:22,957 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'LST B USTB 0 3.600 1.100\\r\\n'\n", + "2026-03-30 16:34:22,987 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B USTB 1 0.000 0.000\\r\\n'\n", + "2026-03-30 16:34:22,988 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'LST B USTB 1 0.000 0.000\\r\\n'\n", + "2026-03-30 16:34:23,003 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST A USTB 2 0.000 0.000\\r\\n'\n", + "2026-03-30 16:34:23,005 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'LST A USTB 2 0.000 0.000\\r\\n'\n", + "2026-03-30 16:34:23,008 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: RDB\n", + "2026-03-30 16:34:23,012 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'RDB\\r\\n'\n", + "2026-03-30 16:34:23,051 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'RDB A 5\\r\\n'\n", + "2026-03-30 16:34:23,053 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'RDB A 5\\r\\n'\n", + "2026-03-30 16:34:23,054 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: USTB\n", + "2026-03-30 16:34:23,057 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'USTB\\r\\n'\n", + "2026-03-30 16:34:23,101 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'USTB B 0 3.600 1.100\\r\\n'\n", + "2026-03-30 16:34:23,104 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'USTB B 0 3.600 1.100\\r\\n'\n", + "2026-03-30 16:34:23,131 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'USTB B 1 0.000 0.000\\r\\n'\n", + "2026-03-30 16:34:23,136 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'USTB B 1 0.000 0.000\\r\\n'\n", + "2026-03-30 16:34:23,147 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'USTB A 2 0.000 0.000\\r\\n'\n", + "2026-03-30 16:34:23,150 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'USTB A 2 0.000 0.000\\r\\n'\n", + "2026-03-30 16:34:23,158 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: TST0\n", + "2026-03-30 16:34:23,161 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'TST0\\r\\n'\n", + "2026-03-30 16:34:23,195 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'TST0 A 0 \"\"\\r\\n'\n", + "2026-03-30 16:34:23,202 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'TST0 A 0 \"\"\\r\\n'\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "Current user settings (24 lines):\n", + " LST B C0 0 0 \n", + " LST B FCUT 0.000\n", + " LST B I10 \n", + " LST B M01 0\n", + " LST B M02 2\n", + " LST B M03 0\n", + " LST B M17 00 00 00 0\n", + " LST B M18 1\n", + " LST B M19 10.00000 g\n", + " LST B M20 200.00000 g\n", + " ... (24 lines total)\n", + "Readability: A 5\n", + "Stability criteria: B 0 3.600 1.100\n", + "Test settings: A 0 \n", + "\n", + "PASS: All read-only configuration queries completed\n" + ] + } + ], "source": [ "# M01 - Weighing mode\n", "if \"M01\" in backend._supported_commands:\n", @@ -1133,9 +1817,50 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 15, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2026-03-30 16:34:35,694 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: SIS\n", + "2026-03-30 16:34:35,697 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SIS\\r\\n'\n", + "2026-03-30 16:34:35,743 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'SIS A 0 \"0.00000\" 0 5 1 0 0\\r\\n'\n", + "2026-03-30 16:34:35,744 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'SIS A 0 \"0.00000\" 0 5 1 0 0\\r\\n'\n", + "2026-03-30 16:34:35,745 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: M21 1 0\n", + "2026-03-30 16:34:35,748 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'M21 1 0\\r\\n'\n", + "2026-03-30 16:34:35,779 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M21 L\\r\\n'\n", + "2026-03-30 16:34:35,781 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'M21 L\\r\\n'\n", + "2026-03-30 16:34:35,783 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: M21 0 0\n", + "2026-03-30 16:34:35,787 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'M21 0 0\\r\\n'\n", + "2026-03-30 16:34:35,827 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M21 A\\r\\n'\n", + "2026-03-30 16:34:35,830 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'M21 A\\r\\n'\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "SIS in grams: ['0', '0.00000', '0', '5', '1', '0', '0']\n", + "\n", + "Restored host unit to grams\n" + ] + }, + { + "ename": "MettlerToledoError", + "evalue": "Command understood but not executable: (incorrect parameter).", + "output_type": "error", + "traceback": [ + "\u001b[31m---------------------------------------------------------------------------\u001b[39m", + "\u001b[31mMettlerToledoError\u001b[39m Traceback (most recent call last)", + "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[15]\u001b[39m\u001b[32m, line 7\u001b[39m\n\u001b[32m 5\u001b[39m \u001b[38;5;66;03m# Temporarily set unit to milligrams (M21 1 0 = mg host unit)\u001b[39;00m\n\u001b[32m 6\u001b[39m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[32m----> \u001b[39m\u001b[32m7\u001b[39m \u001b[38;5;28;01mawait\u001b[39;00m backend.send_command(\u001b[33m\"\u001b[39m\u001b[33mM21 1 0\u001b[39m\u001b[33m\"\u001b[39m)\n\u001b[32m 8\u001b[39m sis_mg = \u001b[38;5;28;01mawait\u001b[39;00m backend.request_net_weight_with_status()\n\u001b[32m 9\u001b[39m \u001b[38;5;28mprint\u001b[39m(\u001b[33mf\u001b[39m\u001b[33m\"\u001b[39m\u001b[33mSIS in milligrams: \u001b[39m\u001b[38;5;132;01m{\u001b[39;00msis_mg.data\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m\"\u001b[39m)\n", + "\u001b[36mFile \u001b[39m\u001b[32m~/Desktop/GitHub/pylabrobot/pylabrobot/scales/mettler_toledo/backend.py:358\u001b[39m, in \u001b[36mMettlerToledoWXS205SDUBackend.send_command\u001b[39m\u001b[34m(self, command, timeout)\u001b[39m\n\u001b[32m 356\u001b[39m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[32m 357\u001b[39m response = MettlerToledoResponse(command=\u001b[33m\"\u001b[39m\u001b[33m\"\u001b[39m, status=\u001b[33m\"\u001b[39m\u001b[33m\"\u001b[39m, data=[])\n\u001b[32m--> \u001b[39m\u001b[32m358\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[43m.\u001b[49m\u001b[43m_parse_basic_errors\u001b[49m\u001b[43m(\u001b[49m\u001b[43mresponse\u001b[49m\u001b[43m)\u001b[49m\n\u001b[32m 359\u001b[39m responses.append(response)\n\u001b[32m 361\u001b[39m \u001b[38;5;66;03m# Status B means more responses follow; anything else (A, etc.) is final\u001b[39;00m\n", + "\u001b[36mFile \u001b[39m\u001b[32m~/Desktop/GitHub/pylabrobot/pylabrobot/scales/mettler_toledo/backend.py:285\u001b[39m, in \u001b[36mMettlerToledoWXS205SDUBackend._parse_basic_errors\u001b[39m\u001b[34m(self, response)\u001b[39m\n\u001b[32m 283\u001b[39m \u001b[38;5;28;01mraise\u001b[39;00m MettlerToledoError.executing_another_command()\n\u001b[32m 284\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m response.status == \u001b[33m\"\u001b[39m\u001b[33mL\u001b[39m\u001b[33m\"\u001b[39m:\n\u001b[32m--> \u001b[39m\u001b[32m285\u001b[39m \u001b[38;5;28;01mraise\u001b[39;00m MettlerToledoError.incorrect_parameter()\n\u001b[32m 286\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m response.status == \u001b[33m\"\u001b[39m\u001b[33m+\u001b[39m\u001b[33m\"\u001b[39m:\n\u001b[32m 287\u001b[39m \u001b[38;5;28;01mraise\u001b[39;00m MettlerToledoError.overload()\n", + "\u001b[31mMettlerToledoError\u001b[39m: Command understood but not executable: (incorrect parameter)." + ] + } + ], "source": [ "# Read SIS in grams (current state)\n", "sis_grams = await backend.request_net_weight_with_status()\n", @@ -1176,9 +1901,70 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 16, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2026-03-30 16:34:46,597 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: Z\n", + "2026-03-30 16:34:46,599 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'Z\\r\\n'\n", + "2026-03-30 16:34:46,854 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'Z A\\r\\n'\n", + "2026-03-30 16:34:46,856 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'Z A\\r\\n'\n", + "2026-03-30 16:34:46,857 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: SI\n", + "2026-03-30 16:34:46,860 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", + "2026-03-30 16:34:46,903 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 16:34:46,904 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'S S 0.00000 g\\r\\n'\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Frontend zero + read: 0.0 g\n" + ] + }, + { + "name": "stdin", + "output_type": "stream", + "text": [ + "Place a container on the scale and press Enter... \n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2026-03-30 16:34:48,056 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: T\n", + "2026-03-30 16:34:48,060 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'T\\r\\n'\n", + "2026-03-30 16:34:48,453 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'T S 0.00000 g\\r\\n'\n", + "2026-03-30 16:34:48,454 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'T S 0.00000 g\\r\\n'\n", + "2026-03-30 16:34:48,455 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: TA\n", + "2026-03-30 16:34:48,456 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'TA\\r\\n'\n", + "2026-03-30 16:34:48,533 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'TA A 0.00000 g\\r\\n'\n", + "2026-03-30 16:34:48,533 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'TA A 0.00000 g\\r\\n'\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Frontend tare weight: 0.0 g\n" + ] + }, + { + "ename": "AssertionError", + "evalue": "", + "output_type": "error", + "traceback": [ + "\u001b[31m---------------------------------------------------------------------------\u001b[39m", + "\u001b[31mAssertionError\u001b[39m Traceback (most recent call last)", + "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[16]\u001b[39m\u001b[32m, line 12\u001b[39m\n\u001b[32m 10\u001b[39m tare = \u001b[38;5;28;01mawait\u001b[39;00m scale.request_tare_weight()\n\u001b[32m 11\u001b[39m \u001b[38;5;28mprint\u001b[39m(\u001b[33mf\u001b[39m\u001b[33m\"\u001b[39m\u001b[33mFrontend tare weight: \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mtare\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m g\u001b[39m\u001b[33m\"\u001b[39m)\n\u001b[32m---> \u001b[39m\u001b[32m12\u001b[39m \u001b[38;5;28;01massert\u001b[39;00m tare > \u001b[32m0\u001b[39m\n\u001b[32m 14\u001b[39m \u001b[38;5;66;03m# Read via frontend\u001b[39;00m\n\u001b[32m 15\u001b[39m w = \u001b[38;5;28;01mawait\u001b[39;00m scale.read_weight(timeout=\u001b[33m\"\u001b[39m\u001b[33mstable\u001b[39m\u001b[33m\"\u001b[39m)\n", + "\u001b[31mAssertionError\u001b[39m: " + ] + } + ], "source": [ "# Zero via frontend\n", "await scale.zero(timeout=\"stable\")\n", @@ -1213,9 +1999,130 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 17, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2026-03-30 16:34:53,926 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: I22\n", + "2026-03-30 16:34:53,932 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I22\\r\\n'\n", + "2026-03-30 16:34:54,319 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I22 B 0 0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 \"\"\\r\\n'\n", + "2026-03-30 16:34:54,320 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I22 B 0 0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 \"\"\\r\\n'\n", + "2026-03-30 16:34:54,400 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I22 B 1 0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 \"\"\\r\\n'\n", + "2026-03-30 16:34:54,401 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I22 B 1 0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 \"\"\\r\\n'\n", + "2026-03-30 16:34:54,480 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I22 B 2 0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 \"\"\\r\\n'\n", + "2026-03-30 16:34:54,481 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I22 B 2 0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 \"\"\\r\\n'\n", + "2026-03-30 16:34:54,544 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I22 B 3 0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 \"\"\\r\\n'\n", + "2026-03-30 16:34:54,548 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I22 B 3 0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 \"\"\\r\\n'\n", + "2026-03-30 16:34:54,623 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I22 A 4 0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 \"\"\\r\\n'\n", + "2026-03-30 16:34:54,624 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I22 A 4 0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 \"\"\\r\\n'\n", + "2026-03-30 16:34:54,627 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: I23\n", + "2026-03-30 16:34:54,628 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I23\\r\\n'\n", + "2026-03-30 16:34:54,723 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I23 B 0 0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 \"\"\\r\\n'\n", + "2026-03-30 16:34:54,725 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I23 B 0 0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 \"\"\\r\\n'\n", + "2026-03-30 16:34:54,800 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I23 B 1 0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 \"\"\\r\\n'\n", + "2026-03-30 16:34:54,802 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I23 B 1 0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 \"\"\\r\\n'\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "I22: status=B data=['0', '0.00000000E+00', '0.00000000E+00', '0.00000000E+00', '0.00000000E+00', '']\n", + "I22: status=B data=['1', '0.00000000E+00', '0.00000000E+00', '0.00000000E+00', '0.00000000E+00', '']\n", + "I22: status=B data=['2', '0.00000000E+00', '0.00000000E+00', '0.00000000E+00', '0.00000000E+00', '']\n", + "I22: status=B data=['3', '0.00000000E+00', '0.00000000E+00', '0.00000000E+00', '0.00000000E+00', '']\n", + "I22: status=A data=['4', '0.00000000E+00', '0.00000000E+00', '0.00000000E+00', '0.00000000E+00', '']\n", + "\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2026-03-30 16:34:54,879 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I23 B 2 0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 \"\"\\r\\n'\n", + "2026-03-30 16:34:54,881 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I23 B 2 0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 \"\"\\r\\n'\n", + "2026-03-30 16:34:54,944 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I23 B 3 0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 \"\"\\r\\n'\n", + "2026-03-30 16:34:54,956 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I23 B 3 0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 \"\"\\r\\n'\n", + "2026-03-30 16:34:55,025 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I23 A 4 0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 \"\"\\r\\n'\n", + "2026-03-30 16:34:55,028 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I23 A 4 0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 \"\"\\r\\n'\n", + "2026-03-30 16:34:55,034 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: I24\n", + "2026-03-30 16:34:55,042 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I24\\r\\n'\n", + "2026-03-30 16:34:55,135 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I24 B 0 0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 \"\"\\r\\n'\n", + "2026-03-30 16:34:55,136 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I24 B 0 0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 \"\"\\r\\n'\n", + "2026-03-30 16:34:55,215 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I24 B 1 0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 \"\"\\r\\n'\n", + "2026-03-30 16:34:55,216 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I24 B 1 0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 \"\"\\r\\n'\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "I23: status=B data=['0', '0.00000000E+00', '0.00000000E+00', '0.00000000E+00', '0.00000000E+00', '']\n", + "I23: status=B data=['1', '0.00000000E+00', '0.00000000E+00', '0.00000000E+00', '0.00000000E+00', '']\n", + "I23: status=B data=['2', '0.00000000E+00', '0.00000000E+00', '0.00000000E+00', '0.00000000E+00', '']\n", + "I23: status=B data=['3', '0.00000000E+00', '0.00000000E+00', '0.00000000E+00', '0.00000000E+00', '']\n", + "I23: status=A data=['4', '0.00000000E+00', '0.00000000E+00', '0.00000000E+00', '0.00000000E+00', '']\n", + "\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2026-03-30 16:34:55,279 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I24 B 2 0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 \"\"\\r\\n'\n", + "2026-03-30 16:34:55,280 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I24 B 2 0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 \"\"\\r\\n'\n", + "2026-03-30 16:34:55,360 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I24 B 3 0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 \"\"\\r\\n'\n", + "2026-03-30 16:34:55,360 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I24 B 3 0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 \"\"\\r\\n'\n", + "2026-03-30 16:34:55,439 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I24 A 4 0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 \"\"\\r\\n'\n", + "2026-03-30 16:34:55,440 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I24 A 4 0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 \"\"\\r\\n'\n", + "2026-03-30 16:34:55,441 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: I25\n", + "2026-03-30 16:34:55,442 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I25\\r\\n'\n", + "2026-03-30 16:34:55,534 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I25 B 0 0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 \"\"\\r\\n'\n", + "2026-03-30 16:34:55,535 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I25 B 0 0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 \"\"\\r\\n'\n", + "2026-03-30 16:34:55,615 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I25 B 1 0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 \"\"\\r\\n'\n", + "2026-03-30 16:34:55,616 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I25 B 1 0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 \"\"\\r\\n'\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "I24: status=B data=['0', '0.00000000E+00', '0.00000000E+00', '0.00000000E+00', '0.00000000E+00', '']\n", + "I24: status=B data=['1', '0.00000000E+00', '0.00000000E+00', '0.00000000E+00', '0.00000000E+00', '']\n", + "I24: status=B data=['2', '0.00000000E+00', '0.00000000E+00', '0.00000000E+00', '0.00000000E+00', '']\n", + "I24: status=B data=['3', '0.00000000E+00', '0.00000000E+00', '0.00000000E+00', '0.00000000E+00', '']\n", + "I24: status=A data=['4', '0.00000000E+00', '0.00000000E+00', '0.00000000E+00', '0.00000000E+00', '']\n", + "\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2026-03-30 16:34:55,695 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I25 B 2 0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 \"\"\\r\\n'\n", + "2026-03-30 16:34:55,696 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I25 B 2 0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 \"\"\\r\\n'\n", + "2026-03-30 16:34:55,759 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I25 B 3 0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 \"\"\\r\\n'\n", + "2026-03-30 16:34:55,760 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I25 B 3 0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 \"\"\\r\\n'\n", + "2026-03-30 16:34:55,839 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I25 A 4 0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 \"\"\\r\\n'\n", + "2026-03-30 16:34:55,839 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I25 A 4 0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 \"\"\\r\\n'\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "I25: status=B data=['0', '0.00000000E+00', '0.00000000E+00', '0.00000000E+00', '0.00000000E+00', '']\n", + "I25: status=B data=['1', '0.00000000E+00', '0.00000000E+00', '0.00000000E+00', '0.00000000E+00', '']\n", + "I25: status=B data=['2', '0.00000000E+00', '0.00000000E+00', '0.00000000E+00', '0.00000000E+00', '']\n", + "I25: status=B data=['3', '0.00000000E+00', '0.00000000E+00', '0.00000000E+00', '0.00000000E+00', '']\n", + "I25: status=A data=['4', '0.00000000E+00', '0.00000000E+00', '0.00000000E+00', '0.00000000E+00', '']\n", + "\n" + ] + } + ], "source": [ "for cmd in [\"I22\", \"I23\", \"I24\", \"I25\"]:\n", " try:\n", @@ -1237,9 +2144,104 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 18, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2026-03-30 16:35:10,903 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: S\n", + "2026-03-30 16:35:10,904 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", + "2026-03-30 16:35:10,948 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 16:35:10,949 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 16:35:10,950 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: S\n", + "2026-03-30 16:35:10,954 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", + "2026-03-30 16:35:11,043 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 16:35:11,044 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 16:35:11,045 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: S\n", + "2026-03-30 16:35:11,051 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", + "2026-03-30 16:35:11,139 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 16:35:11,140 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 16:35:11,143 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: S\n", + "2026-03-30 16:35:11,146 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", + "2026-03-30 16:35:11,234 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 16:35:11,235 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 16:35:11,237 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: S\n", + "2026-03-30 16:35:11,239 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", + "2026-03-30 16:35:11,331 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 16:35:11,332 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 16:35:11,333 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: S\n", + "2026-03-30 16:35:11,334 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", + "2026-03-30 16:35:11,443 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 16:35:11,443 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 16:35:11,444 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: S\n", + "2026-03-30 16:35:11,446 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", + "2026-03-30 16:35:11,539 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 16:35:11,540 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 16:35:11,541 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: S\n", + "2026-03-30 16:35:11,543 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", + "2026-03-30 16:35:11,634 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 16:35:11,635 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 16:35:11,636 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: S\n", + "2026-03-30 16:35:11,637 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", + "2026-03-30 16:35:11,730 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 16:35:11,731 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 16:35:11,731 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: S\n", + "2026-03-30 16:35:11,733 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", + "2026-03-30 16:35:11,826 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 16:35:11,827 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 16:35:11,828 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: SI\n", + "2026-03-30 16:35:11,829 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", + "2026-03-30 16:35:11,859 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 16:35:11,860 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 16:35:11,864 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: SI\n", + "2026-03-30 16:35:11,867 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", + "2026-03-30 16:35:11,907 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 16:35:11,908 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 16:35:11,911 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: SI\n", + "2026-03-30 16:35:11,912 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", + "2026-03-30 16:35:11,955 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 16:35:11,956 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 16:35:11,959 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: SI\n", + "2026-03-30 16:35:11,961 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", + "2026-03-30 16:35:12,003 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 16:35:12,004 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 16:35:12,004 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: SI\n", + "2026-03-30 16:35:12,007 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", + "2026-03-30 16:35:12,035 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 16:35:12,037 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 16:35:12,039 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: SI\n", + "2026-03-30 16:35:12,042 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", + "2026-03-30 16:35:12,082 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 16:35:12,083 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 16:35:12,084 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: SI\n", + "2026-03-30 16:35:12,085 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", + "2026-03-30 16:35:12,130 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 16:35:12,132 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 16:35:12,132 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: SI\n", + "2026-03-30 16:35:12,136 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", + "2026-03-30 16:35:12,187 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 16:35:12,189 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 16:35:12,190 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: SI\n", + "2026-03-30 16:35:12,196 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", + "2026-03-30 16:35:12,231 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 16:35:12,233 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 16:35:12,234 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: SI\n", + "2026-03-30 16:35:12,239 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", + "2026-03-30 16:35:12,274 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", + "2026-03-30 16:35:12,276 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'S S 0.00000 g\\r\\n'\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Stable read: 92.43 +/- 15.88 ms\n", + "Immediate read: 44.97 +/- 6.03 ms\n" + ] + } + ], "source": [ "import time\n", "\n", @@ -1275,14 +2277,42 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 19, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2026-03-30 16:35:13,600 - pylabrobot - INFO - === Hardware validation ended ===\n", + "2026-03-30 16:35:13,602 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] reset_input_buffer\n", + "2026-03-30 16:35:13,603 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: @\n", + "2026-03-30 16:35:13,604 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'@\\r\\n'\n", + "2026-03-30 16:35:13,665 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I4 A \"B207696838\"\\r\\n'\n", + "2026-03-30 16:35:13,667 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I4 A \"B207696838\"\\r\\n'\n", + "2026-03-30 16:35:13,668 - pylabrobot - INFO - [Mettler Toledo Scale] Disconnected from /dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Log file: ./logs/hardware_validation/2026-03-30_16-33-54_validation.log\n" + ] + } + ], "source": [ "plr_logger.info(\"=== Hardware validation ended ===\")\n", "await scale.stop()\n", "print(f\"Log file: {log_file}\")" ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] } ], "metadata": { @@ -1306,4 +2336,4 @@ }, "nbformat": 4, "nbformat_minor": 4 -} \ No newline at end of file +} From 2dfdc0d6190e84ad039e444c4ed5f2130420691f Mon Sep 17 00:00:00 2001 From: Camillo Moschner Date: Mon, 30 Mar 2026 17:36:34 +0100 Subject: [PATCH 33/38] Complete simulator command coverage, correct DAT/TIM parsing, add @requires_mt_sics_command gating to all commands --- .../scales/mettler-toledo-WXS205SDU.ipynb | 122 ++++++----- pylabrobot/scales/mettler_toledo/backend.py | 105 ++++++---- .../mettler_toledo/hardware_validation.ipynb | 68 +++--- .../scales/mettler_toledo/mt_sics_commands.md | 55 ++++- pylabrobot/scales/mettler_toledo/protocol.md | 15 ++ pylabrobot/scales/mettler_toledo/simulator.py | 198 ++++++++++++++---- 6 files changed, 377 insertions(+), 186 deletions(-) diff --git a/docs/user_guide/02_analytical/scales/mettler-toledo-WXS205SDU.ipynb b/docs/user_guide/02_analytical/scales/mettler-toledo-WXS205SDU.ipynb index b0ef1934069..726128550f1 100644 --- a/docs/user_guide/02_analytical/scales/mettler-toledo-WXS205SDU.ipynb +++ b/docs/user_guide/02_analytical/scales/mettler-toledo-WXS205SDU.ipynb @@ -4,7 +4,11 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "# Mettler Toledo Precision Scales\n\n| Summary | Image |\n|------------|--------|\n|
  • OEM Link
  • Communication Protocol / Hardware: Serial / RS-232
  • Communication Level: Firmware (documentation shared by OEM)
  • Compatibility: This backend has been extensively tested on the WXS205SDU (but according to firmware documentation is applicable to other Mettler Toledo \"Automated Precision Weigh Modules\", including the WX and WMS series)
  • VID:PID: 0x0403:0x6001
  • Description: High-precision fine balance with various adapters available.
  • Load range: 0 - 220 g
  • Readability: 0.1 mg
|
![scale](img/mettler_toledo_wx_scale.png)
Figure: Mettler Toledo WXS205SDU used for gravimetric liquid transfer verification
|" + "# Mettler Toledo Precision Scales\n", + "\n", + "| Summary | Image |\n", + "|------------|--------|\n", + "|
  • OEM Link
  • Communication Protocol / Hardware: Serial / RS-232
  • Communication Level: Firmware (documentation shared by OEM)
  • Compatibility: This backend has been extensively tested on the WXS205SDU (but according to firmware documentation is applicable to other Mettler Toledo \"Automated Precision Weigh Modules\", including the WX and WMS series)
  • VID:PID: 0x0403:0x6001
  • Description: High-precision fine balance with various adapters available.
  • Load range: 0 - 220 g
  • Readability: 0.1 mg
|
![scale](img/mettler_toledo_wx_scale.png)
Figure: Mettler Toledo WXS205SDU used for gravimetric liquid transfer verification
|" ] }, { @@ -27,8 +31,8 @@ "\n", "| Configuration Name | Has Load Cell | Has Electronics Unit | Has Terminal/Display |\n", "|---------------|---------------|-----------------|---------------------|\n", - "| **Balance** | \u2713 | \u2713 | \u2713 |\n", - "| **Weigh Module** (or \"Bridge\") | \u2713 | \u2713 | \u2717 |\n", + "| **Balance** | ✓ | ✓ | ✓ |\n", + "| **Weigh Module** (or \"Bridge\") | ✓ | ✓ | ✗ |\n", "\n", "**Note:** When used with PyLabRobot, the terminal/display is optional since all control is done programmatically.\n", "\n", @@ -166,7 +170,41 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "```{Warning}\n### Warm-up Time Required\n\nThis scale requires a **warm-up period** after being powered on. Mettler Toledo documentation specifies 60 minutes, though in practice 30 minutes is often sufficient.\n\nIf you attempt measurements before the scale has warmed up, you may see unstable readings or the scale may return status `I` (command understood but not currently executable).\n\n**Tip**: Sometimes power-cycling the scale (unplugging and replugging the power cord) can help resolve initialization issues.\n```\n\n\n```{Note}\nThis scale is the same model used in the Hamilton Liquid Verification Kit (LVK).\n```" + "```{Warning}\n", + "### Warm-up Time Required\n", + "\n", + "This scale requires a **warm-up period** after being powered on. Mettler Toledo documentation specifies 60 minutes, though in practice 30 minutes is often sufficient.\n", + "\n", + "If you attempt measurements before the scale has warmed up, you may see unstable readings or the scale may return status `I` (command understood but not currently executable).\n", + "\n", + "**Tip**: Sometimes power-cycling the scale (unplugging and replugging the power cord) can help resolve initialization issues.\n", + "```\n", + "\n", + "\n", + "```{Note}\n", + "This scale is the same model used in the Hamilton Liquid Verification Kit (LVK).\n", + "```" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Available methods\n", + "\n", + "Different Mettler Toledo models support different MT-SICS commands. During\n", + "`setup()`, the backend queries the device to discover which commands it\n", + "supports and gates methods accordingly. Use `request_supported_methods()`\n", + "to see what is available on your device:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "backend.request_supported_methods()" ] }, { @@ -236,7 +274,7 @@ "Resets the scale reading to zero while accounting for the weight of a container already on the platform. Use this when you want to measure only the weight of material being added to a container.\n", "\n", "**Example workflow**:\n", - "Place an empty beaker on the scale \u2192 tare \u2192 dispense liquid \u2192 read only the liquid's weight." + "Place an empty beaker on the scale → tare → dispense liquid → read only the liquid's weight." ] }, { @@ -490,12 +528,15 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "---\n### Backend-Specific Methods\n\nThe MT-SICS backend exposes additional methods beyond the core scale interface.\n\n#### Remaining weighing range\n\nQuery how much capacity is left on the scale, accounting for all current loads\n(pre-load, tare, net). Useful for checking whether adding more weight would\nexceed the scale's maximum capacity." + "#### Temperature\n", + "\n", + "Read the current temperature from the scale's internal sensor. Useful for gravimetric\n", + "verification where temperature affects liquid density and evaporation rate." ] }, { "cell_type": "code", - "execution_count": 9, + "execution_count": null, "metadata": { "execution": { "iopub.execute_input": "2026-03-30T12:01:11.866619Z", @@ -542,52 +583,9 @@ } ], "source": [ - "remaining_g = await backend.request_remaining_weighing_range()\n", - "print(f\"Remaining capacity: {remaining_g:.1f} g\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "#### Temperature\n\nRead the current temperature from the scale's internal sensor. Useful for gravimetric\nverification where temperature affects liquid density and evaporation rate." - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": { - "execution": { - "iopub.execute_input": "2026-03-30T12:01:11.869863Z", - "iopub.status.busy": "2026-03-30T12:01:11.869812Z", - "iopub.status.idle": "2026-03-30T12:01:11.871621Z", - "shell.execute_reply": "2026-03-30T12:01:11.871465Z" - } - }, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2026-03-30 13:01:11,870 - pylabrobot - IO - [MT Scale] Sent command: M28\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2026-03-30 13:01:11,870 - pylabrobot - IO - [MT Scale] Received response: M28 A 1 22.5\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Scale temperature: 22.5 C\n" - ] - } - ], - "source": [ + "if protocol_mode == \"simulation\":\n", + " backend.temperature = 21.3\n", + "\n", "temp_c = await backend.measure_temperature()\n", "print(f\"Scale temperature: {temp_c} C\")" ] @@ -636,7 +634,21 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "---\n### Teardown\n\nThe scale resets the device to a clean state before disconnecting. If the serial\nport is already broken (e.g. unexpected disconnect), the reset is skipped gracefully.\n\nFor scripts and automated protocols, use `async with` to guarantee cleanup even\nif an error occurs:\n\n```python\nasync with Scale(name=\"scale\", backend=backend, size_x=0, size_y=0, size_z=0) as scale:\n await scale.zero()\n weight = await scale.read_weight()\n # scale.stop() is called automatically, even on exceptions\n```" + "---\n", + "### Teardown\n", + "\n", + "The scale resets the device to a clean state before disconnecting. If the serial\n", + "port is already broken (e.g. unexpected disconnect), the reset is skipped gracefully.\n", + "\n", + "For scripts and automated protocols, use `async with` to guarantee cleanup even\n", + "if an error occurs:\n", + "\n", + "```python\n", + "async with Scale(name=\"scale\", backend=backend, size_x=0, size_y=0, size_z=0) as scale:\n", + " await scale.zero()\n", + " weight = await scale.read_weight()\n", + " # scale.stop() is called automatically, even on exceptions\n", + "```" ] }, { @@ -693,4 +705,4 @@ }, "nbformat": 4, "nbformat_minor": 2 -} \ No newline at end of file +} diff --git a/pylabrobot/scales/mettler_toledo/backend.py b/pylabrobot/scales/mettler_toledo/backend.py index 022c31749ef..168ecc284d4 100644 --- a/pylabrobot/scales/mettler_toledo/backend.py +++ b/pylabrobot/scales/mettler_toledo/backend.py @@ -181,7 +181,9 @@ async def stop(self) -> None: try: await self.reset() except Exception: - logger.warning("[%s] Could not reset device before disconnecting", self.io._human_readable_device_name) + logger.warning( + "[%s] Could not reset device before disconnecting", self.io._human_readable_device_name + ) logger.info("[%s] Disconnected from %s", self.io._human_readable_device_name, self.io.port) await self.io.stop() @@ -347,7 +349,12 @@ async def send_command(self, command: str, timeout: int = 60) -> List[MettlerTol raise TimeoutError("Timeout while waiting for response from scale.") await asyncio.sleep(0.001) - logger.log(LOG_LEVEL_IO, "[%s] Received response: %s", self.io._human_readable_device_name, raw_response) + logger.log( + LOG_LEVEL_IO, + "[%s] Received response: %s", + self.io._human_readable_device_name, + raw_response, + ) fields = shlex.split(raw_response.decode("utf-8").strip()) if len(fields) >= 2: response = MettlerToledoResponse(command=fields[0], status=fields[1], data=fields[2:]) @@ -384,6 +391,7 @@ async def reset(self) -> str: self._validate_response(responses[0], 3, "@") return responses[0].data[0] + @requires_mt_sics_command("C") async def cancel_all(self) -> None: """C - Cancel all active and pending interface commands. @@ -461,23 +469,20 @@ async def request_device_id(self) -> str: """Query the user-assigned device identification string. (I10 command) This is a user-configurable name (max 20 chars) to identify - individual scales in multi-device setups. Retained after @ cancel. + individual scales in multi-scale setups. Retained after @ cancel. """ responses = await self.send_command("I10") self._validate_response(responses[0], 3, "I10") return responses[0].data[0] - # WARNING: set_device_id writes to EEPROM and permanently changes the stored device name. - # Uncomment only if you need to relabel a scale in a multi-device setup. - # - # @requires_mt_sics_command("I10") - # async def set_device_id(self, device_id: str) -> None: - # """Set the user-assigned device identification string. (I10 command) - # - # Max 20 alphanumeric characters. Retained after @ cancel. - # Useful for labeling individual scales in multi-device setups. - # """ - # await self.send_command(f'I10 "{device_id}"') + @requires_mt_sics_command("I10") + async def set_device_id(self, device_id: str) -> None: + """Set the user-assigned device identification string. (I10 command) + + Max 20 alphanumeric characters. Persists across power cycles. + Useful for labeling individual scales in multi-scale setups. + """ + await self.send_command(f'I10 "{device_id}"') @requires_mt_sics_command("I11") async def request_model_designation(self) -> str: @@ -522,28 +527,60 @@ async def request_uptime_minutes(self) -> int: async def request_date(self) -> str: """Query the current date from the device. (DAT command) - Returns the date string as reported by the device. + Response format: DAT A . + Returns the date as "DD.MM.YYYY". """ responses = await self.send_command("DAT") - self._validate_response(responses[0], 3, "DAT") - return responses[0].data[0] + self._validate_response(responses[0], 5, "DAT") + day, month, year = responses[0].data[0], responses[0].data[1], responses[0].data[2] + return f"{day}.{month}.{year}" + + @requires_mt_sics_command("DAT") + async def set_date(self, day: int, month: int, year: int) -> None: + """Set the device date. (DAT command) + + Args: + day: Day (1-31). + month: Month (1-12). + year: Year (2020-2099, platform-dependent). + """ + await self.send_command(f"DAT {day:02d} {month:02d} {year}") @requires_mt_sics_command("TIM") async def request_time(self) -> str: """Query the current time from the device. (TIM command) - Returns the time string as reported by the device. + Response format: TIM A . + Returns the time as "HH:MM:SS". """ responses = await self.send_command("TIM") - self._validate_response(responses[0], 3, "TIM") - return responses[0].data[0] + self._validate_response(responses[0], 5, "TIM") + hour, minute, second = responses[0].data[0], responses[0].data[1], responses[0].data[2] + return f"{hour}:{minute}:{second}" + + @requires_mt_sics_command("TIM") + async def set_time(self, hour: int, minute: int, second: int) -> None: + """Set the device time. (TIM command) + + Persists across power cycles. Only reset via FSET or terminal menu, not @. + + Args: + hour: Hour (0-23). + minute: Minute (0-59). + second: Second (0-59). + """ + await self.send_command(f"TIM {hour:02d} {minute:02d} {second:02d}") @requires_mt_sics_command("I16") async def request_next_service_date(self) -> str: - """Query the date when the balance is next due to be serviced. (I16 command)""" + """Query the date when the balance is next due to be serviced. (I16 command) + + Returns the date as "DD.MM.YYYY". + """ responses = await self.send_command("I16") - self._validate_response(responses[0], 3, "I16") - return " ".join(responses[0].data) + self._validate_response(responses[0], 5, "I16") + day, month, year = responses[0].data[0], responses[0].data[1], responses[0].data[2] + return f"{day}.{month}.{year}" @requires_mt_sics_command("I21") async def request_assortment_type_revision(self) -> str: @@ -567,11 +604,9 @@ async def zero_stable(self) -> List[MettlerToledoResponse]: """Zero the scale when the weight is stable. (Z command)""" return await self.send_command("Z") + @requires_mt_sics_command("ZC") async def zero_timeout(self, timeout: float) -> List[MettlerToledoResponse]: - """Zero the scale after a given timeout. (ZC command) - - Not supported on WXS205SDU (returns ES despite being in the spec). - """ + """Zero the scale after a given timeout. (ZC command)""" timeout = int(timeout * 1000) return await self.send_command(f"ZC {timeout}") @@ -604,11 +639,9 @@ async def tare_immediately(self) -> List[MettlerToledoResponse]: """Tare the scale immediately. (TI command)""" return await self.send_command("TI") + @requires_mt_sics_command("TC") async def tare_timeout(self, timeout: float) -> List[MettlerToledoResponse]: - """Tare the scale after a given timeout. (TC command) - - Not supported on WXS205SDU (returns ES despite being in the spec). - """ + """Tare the scale after a given timeout. (TC command)""" timeout = int(timeout * 1000) # convert to milliseconds return await self.send_command(f"TC {timeout}") @@ -660,6 +693,7 @@ async def read_stable_weight(self) -> float: self._validate_unit(responses[0].data[1], "S") return float(responses[0].data[0]) + @requires_mt_sics_command("SC") async def read_dynamic_weight(self, timeout: float) -> float: """Read a stable weight value from the machine within a given timeout, or return the current weight value if not possible. (MEASUREMENT command) @@ -993,13 +1027,15 @@ async def request_readability(self) -> List[MettlerToledoResponse]: # # Display # # + @requires_mt_sics_command("D") async def set_display_text(self, text: str) -> List[MettlerToledoResponse]: - """Write text to the display. (D command) Not available in bridge mode. + """Write text to the display. (D command) Use set_weight_display() to restore the normal weight display. """ return await self.send_command(f'D "{text}"') + @requires_mt_sics_command("DW") async def set_weight_display(self) -> List[MettlerToledoResponse]: """Restore the normal weight display. (DW command)""" return await self.send_command("DW") @@ -1016,11 +1052,6 @@ async def set_host_unit_grams(self) -> List[MettlerToledoResponse]: # # Commented out - standalone write commands # # # - # @requires_mt_sics_command("I10") - # async def set_device_id(self, device_id: str) -> None: - # """Set device name. (I10) WRITES TO EEPROM. Max 20 chars.""" - # await self.send_command(f'I10 "{device_id}"') - # # @requires_mt_sics_command("FSET") # async def factory_reset(self, exclusion: int = 0) -> None: # """Reset ALL settings to factory defaults. (FSET) DESTRUCTIVE.""" diff --git a/pylabrobot/scales/mettler_toledo/hardware_validation.ipynb b/pylabrobot/scales/mettler_toledo/hardware_validation.ipynb index 2d9117f7b07..b4be8f574ed 100644 --- a/pylabrobot/scales/mettler_toledo/hardware_validation.ipynb +++ b/pylabrobot/scales/mettler_toledo/hardware_validation.ipynb @@ -543,7 +543,7 @@ "\n", "for level in sorted(by_level.keys()):\n", " cmds = sorted(by_level[level])\n", - " print(f\"Level {level} ({len(cmds)} commands): {', '.join(cmds)}\")\n" + " print(f\"Level {level} ({len(cmds)} commands): {', '.join(cmds)}\")" ] }, { @@ -759,7 +759,7 @@ "if \"I26\" in backend._supported_commands:\n", " i26_resp = await backend.request_operating_mode_after_restart()\n", " for resp in i26_resp:\n", - " print(f\"I26: {resp.command} {resp.status} {\" \".join(resp.data)}\")\n", + " print(f\"I26: {resp.command} {resp.status} {' '.join(resp.data)}\")\n", "else:\n", " print(\"SKIP: I26 not supported\")\n", "\n", @@ -793,13 +793,13 @@ " info = await backend.request_device_info(category=cat)\n", " print(f\" Category {cat} ({name}):\")\n", " for resp in info:\n", - " print(f\" {resp.command} {resp.status} {\" \".join(resp.data)}\")\n", + " print(f\" {resp.command} {resp.status} {' '.join(resp.data)}\")\n", " except Exception as e:\n", " print(f\" Category {cat} ({name}): {e}\")\n", "else:\n", " print(\"SKIP: I14 not supported\")\n", "\n", - "print(\"\\nPASS: Batch 1 device identity commands completed\")\n" + "print(\"\\nPASS: Batch 1 device identity commands completed\")" ] }, { @@ -1662,28 +1662,28 @@ "# M17 - ProFACT time criteria\n", "if \"M17\" in backend._supported_commands:\n", " resp = await backend.request_profact_time_criteria()\n", - " print(f\"ProFACT time criteria: {resp[0].status} {\" \".join(resp[0].data)}\")\n", + " print(f\"ProFACT time criteria: {resp[0].status} {' '.join(resp[0].data)}\")\n", "else:\n", " print(\"SKIP: M17 not supported\")\n", "\n", "# M18 - ProFACT temperature criterion\n", "if \"M18\" in backend._supported_commands:\n", " resp = await backend.request_profact_temperature_criterion()\n", - " print(f\"ProFACT temperature criterion: {resp[0].status} {\" \".join(resp[0].data)}\")\n", + " print(f\"ProFACT temperature criterion: {resp[0].status} {' '.join(resp[0].data)}\")\n", "else:\n", " print(\"SKIP: M18 not supported\")\n", "\n", "# M19 - Adjustment weight\n", "if \"M19\" in backend._supported_commands:\n", " resp = await backend.request_adjustment_weight()\n", - " print(f\"Adjustment weight: {resp[0].status} {\" \".join(resp[0].data)}\")\n", + " print(f\"Adjustment weight: {resp[0].status} {' '.join(resp[0].data)}\")\n", "else:\n", " print(\"SKIP: M19 not supported\")\n", "\n", "# M20 - Test weight\n", "if \"M20\" in backend._supported_commands:\n", " resp = await backend.request_test_weight()\n", - " print(f\"Test weight: {resp[0].status} {\" \".join(resp[0].data)}\")\n", + " print(f\"Test weight: {resp[0].status} {' '.join(resp[0].data)}\")\n", "else:\n", " print(\"SKIP: M20 not supported\")\n", "\n", @@ -1692,42 +1692,42 @@ " history = await backend.request_adjustment_history()\n", " print(f\"\\nAdjustment history ({len(history)} entries):\")\n", " for resp in history:\n", - " print(f\" {resp.command} {resp.status} {\" \".join(resp.data)}\")\n", + " print(f\" {resp.command} {resp.status} {' '.join(resp.data)}\")\n", "else:\n", " print(\"SKIP: M27 not supported\")\n", "\n", "# M29 - Weighing value release\n", "if \"M29\" in backend._supported_commands:\n", " resp = await backend.request_weighing_value_release()\n", - " print(f\"Weighing value release: {resp[0].status} {\" \".join(resp[0].data)}\")\n", + " print(f\"Weighing value release: {resp[0].status} {' '.join(resp[0].data)}\")\n", "else:\n", " print(\"SKIP: M29 not supported\")\n", "\n", "# M31 - Operating mode\n", "if \"M31\" in backend._supported_commands:\n", " resp = await backend.request_operating_mode()\n", - " print(f\"Operating mode: {resp[0].status} {\" \".join(resp[0].data)}\")\n", + " print(f\"Operating mode: {resp[0].status} {' '.join(resp[0].data)}\")\n", "else:\n", " print(\"SKIP: M31 not supported\")\n", "\n", "# M32 - ProFACT time\n", "if \"M32\" in backend._supported_commands:\n", " resp = await backend.request_profact_time()\n", - " print(f\"ProFACT time: {resp[0].status} {\" \".join(resp[0].data)}\")\n", + " print(f\"ProFACT time: {resp[0].status} {' '.join(resp[0].data)}\")\n", "else:\n", " print(\"SKIP: M32 not supported\")\n", "\n", "# M33 - ProFACT day\n", "if \"M33\" in backend._supported_commands:\n", " resp = await backend.request_profact_day()\n", - " print(f\"ProFACT day: {resp[0].status} {\" \".join(resp[0].data)}\")\n", + " print(f\"ProFACT day: {resp[0].status} {' '.join(resp[0].data)}\")\n", "else:\n", " print(\"SKIP: M33 not supported\")\n", "\n", "# M35 - Zeroing mode\n", "if \"M35\" in backend._supported_commands:\n", " resp = await backend.request_zeroing_mode()\n", - " print(f\"Zeroing mode: {resp[0].status} {\" \".join(resp[0].data)}\")\n", + " print(f\"Zeroing mode: {resp[0].status} {' '.join(resp[0].data)}\")\n", "else:\n", " print(\"SKIP: M35 not supported\")\n", "\n", @@ -1741,28 +1741,28 @@ "# SIS - Net weight with status\n", "if \"SIS\" in backend._supported_commands:\n", " sis_resp = await backend.request_net_weight_with_status()\n", - " print(f\"Net weight with status: {sis_resp.command} {sis_resp.status} {\" \".join(sis_resp.data)}\")\n", + " print(f\"Net weight with status: {sis_resp.command} {sis_resp.status} {' '.join(sis_resp.data)}\")\n", "else:\n", " print(\"SKIP: SIS not supported\")\n", "\n", "# C0 - Adjustment setting\n", "if \"C0\" in backend._supported_commands:\n", " resp = await backend.request_adjustment_setting()\n", - " print(f\"Adjustment setting: {resp[0].status} {\" \".join(resp[0].data)}\")\n", + " print(f\"Adjustment setting: {resp[0].status} {' '.join(resp[0].data)}\")\n", "else:\n", " print(\"SKIP: C0 not supported\")\n", "\n", "# COM - Serial parameters\n", "if \"COM\" in backend._supported_commands:\n", " resp = await backend.request_serial_parameters()\n", - " print(f\"Serial parameters: {resp[0].status} {\" \".join(resp[0].data)}\")\n", + " print(f\"Serial parameters: {resp[0].status} {' '.join(resp[0].data)}\")\n", "else:\n", " print(\"SKIP: COM not supported\")\n", "\n", "# FCUT - Filter cut-off frequency\n", "if \"FCUT\" in backend._supported_commands:\n", " resp = await backend.request_filter_cutoff()\n", - " print(f\"Filter cut-off: {resp[0].status} {\" \".join(resp[0].data)}\")\n", + " print(f\"Filter cut-off: {resp[0].status} {' '.join(resp[0].data)}\")\n", "else:\n", " print(\"SKIP: FCUT not supported\")\n", "\n", @@ -1771,7 +1771,7 @@ " lst_responses = await backend.request_user_settings()\n", " print(f\"\\nCurrent user settings ({len(lst_responses)} lines):\")\n", " for resp in lst_responses[:10]:\n", - " print(f\" {resp.command} {resp.status} {\" \".join(resp.data)}\")\n", + " print(f\" {resp.command} {resp.status} {' '.join(resp.data)}\")\n", " if len(lst_responses) > 10:\n", " print(f\" ... ({len(lst_responses)} lines total)\")\n", "else:\n", @@ -1780,39 +1780,32 @@ "# RDB - Readability\n", "if \"RDB\" in backend._supported_commands:\n", " resp = await backend.request_readability()\n", - " print(f\"Readability: {resp[0].status} {\" \".join(resp[0].data)}\")\n", + " print(f\"Readability: {resp[0].status} {' '.join(resp[0].data)}\")\n", "else:\n", " print(\"SKIP: RDB not supported\")\n", "\n", "# USTB - Stability criteria\n", "if \"USTB\" in backend._supported_commands:\n", " resp = await backend.request_stability_criteria()\n", - " print(f\"Stability criteria: {resp[0].status} {\" \".join(resp[0].data)}\")\n", + " print(f\"Stability criteria: {resp[0].status} {' '.join(resp[0].data)}\")\n", "else:\n", " print(\"SKIP: USTB not supported\")\n", "\n", "# TST0 - Test settings\n", "if \"TST0\" in backend._supported_commands:\n", " resp = await backend.request_test_settings()\n", - " print(f\"Test settings: {resp[0].status} {\" \".join(resp[0].data)}\")\n", + " print(f\"Test settings: {resp[0].status} {' '.join(resp[0].data)}\")\n", "else:\n", " print(\"SKIP: TST0 not supported\")\n", "\n", - "print(\"\\nPASS: All read-only configuration queries completed\")\n" + "print(\"\\nPASS: All read-only configuration queries completed\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "### SIS unit code verification (exploratory)\n", - "\n", - "Tests whether field index 4 in the SIS response is the unit code by temporarily\n", - "changing the host unit via M21, reading SIS, then restoring grams.\n", - "\n", - "**WARNING:** Temporarily writes a non-gram unit to device memory via M21.\n", - "If the cell fails mid-execution, run `await backend.set_host_unit_grams()`\n", - "manually to restore grams. setup() also restores grams on next connection." + "### SIS unit code verification (exploratory)\n\nTests whether field data[2] in the SIS response is the unit code by temporarily\nchanging the host unit via M21, reading SIS, then restoring grams.\n\n**WARNING:** Temporarily writes a non-gram unit to device memory via M21.\nIf the cell fails mid-execution, run `await backend.set_host_unit_grams()`\nmanually to restore grams. setup() also restores grams on next connection." ] }, { @@ -1886,7 +1879,7 @@ "finally:\n", " # Always restore grams\n", " await backend.set_host_unit_grams()\n", - " print(\"\\nRestored host unit to grams\")\n" + " print(\"\\nRestored host unit to grams\")" ] }, { @@ -2131,7 +2124,7 @@ " print(f\"{cmd}: status={r.status} data={r.data}\")\n", " except Exception as e:\n", " print(f\"{cmd}: {type(e).__name__}: {e}\")\n", - " print()\n" + " print()" ] }, { @@ -2306,13 +2299,6 @@ "await scale.stop()\n", "print(f\"Log file: {log_file}\")" ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] } ], "metadata": { @@ -2336,4 +2322,4 @@ }, "nbformat": 4, "nbformat_minor": 4 -} +} \ No newline at end of file diff --git a/pylabrobot/scales/mettler_toledo/mt_sics_commands.md b/pylabrobot/scales/mettler_toledo/mt_sics_commands.md index d7304bce550..0ce9260bfa8 100644 --- a/pylabrobot/scales/mettler_toledo/mt_sics_commands.md +++ b/pylabrobot/scales/mettler_toledo/mt_sics_commands.md @@ -10,12 +10,13 @@ individual commands may exist outside those levels. I0 is the definitive source command support. During setup(), the backend queries I0 to discover all available commands and gates methods via `@requires_mt_sics_command`. -**Hardware-validated on WXS205SDU WXA-Bridge (S/N: B207696838):** +**Hardware-validated on WXS205SDU WXA-Bridge (S/N: B207696838, firmware: 1.10):** I1 reports levels [0, 1] but I0 discovers 62 commands across levels 0-3. Commands not in I0 (C, D, DW, SC, ZC, TC, I50) return ES (syntax error). Status key: -- DONE = implemented in backend.py +- DONE = implemented in backend.py (read active; set active or commented out per write safety) +- STUB = commented out entirely (requires physical interaction) - HIGH = high priority for implementation - MED = medium priority - LOW = low priority / niche use case @@ -177,9 +178,9 @@ Status key: | Command | Description | Spec Page | Status | WXS205SDU | Notes | |---------|------------------------------------------|-----------|--------|-----------|-------| -| DAT | Date | 53 | DONE | yes | request_date(). | -| DATI | Date and time | 54 | MED | - | | -| TIM | Time | 258 | DONE | yes | request_time(). | +| DAT | Date (query/set) | 53 | DONE | yes | request_date() and set_date(). Format: DAT A Day Month Year. | +| DATI | Date and time (query/set) | 54 | MED | - | Combined date+time. Not on WXS205SDU. | +| TIM | Time (query/set) | 258 | DONE | yes | request_time() and set_time(). Format: TIM A Hour Minute Second. Persists (not reset by @). | ### Digital I/O @@ -262,17 +263,53 @@ Status key: | MONH | Monitor on interface | 217 | N/A | - | | | SNRU | Stable weight (display unit) + repeat | 243 | N/A | - | | -## Priority Summary +## Implementation Summary -### HIGH (not available on WXS205SDU) +The MT-SICS spec defines **157 commands** (counting F01-F16 as 16 individual commands). + +| Category | Count | Description | +|----------|-------|-------------| +| Backend (active) | 54 | Implemented and callable | +| Backend (commented out) | 28 | Set/write counterparts and physical interaction commands | +| Simulator | 55 | Handled in `_build_response` (all active commands except I0/I1 internal) | +| Not implemented | 75 | Not available on WXS205SDU or not applicable | + +### WXS205SDU coverage + +The WXS205SDU reports **62 commands** via I0. Of these: + +| State | Count | +|-------|-------| +| Active in backend | 49 | +| Commented out (physical/write) | 7 | +| Not implemented (streaming) | 2 (SIR, SR) | +| Undocumented (not in spec) | 4 (I22-I25) | + +### Expanding to other devices + +The remaining ~75 unimplemented spec commands (HIGH/MED/LOW/N/A in the table above) +are not available on the WXS205SDU and could not be validated. Integrating them +requires a developer with physical access to a device that supports the command, +to validate the response format and add a handler to both `backend.py` and +`simulator.py`. The pattern is: + +1. Confirm the command appears in the device's I0 list +2. Send the command and observe the raw response +3. Add a method to `backend.py` with `@requires_mt_sics_command` +4. Add a handler to `simulator.py` with an instance variable for the response value +5. Add a test to `backend_tests.py` + +### Remaining priorities + +**HIGH (not available on WXS205SDU):** - E01/E02/E03 (error monitoring) - SIX1 (gross, net, tare in one call) -### MED (useful but not urgent) +**MED (useful but not urgent):** - SIR/SR (continuous streaming) - needs async iterator architecture - DATI (date + time combined) - not on WXS205SDU -### STUB (commented out, require physical interaction) +**STUB (commented out, require physical interaction):** - C1/C3 (internal weight adjustment) - C2 (external weight adjustment) - TST1-TST3 (test procedures) diff --git a/pylabrobot/scales/mettler_toledo/protocol.md b/pylabrobot/scales/mettler_toledo/protocol.md index eedf3cad21e..88befda66c5 100644 --- a/pylabrobot/scales/mettler_toledo/protocol.md +++ b/pylabrobot/scales/mettler_toledo/protocol.md @@ -159,6 +159,18 @@ the authoritative list of implemented commands. | 2 | Extended: configuration, device info, diagnostics | Model-dependent | | 3 | Application-specific: filling, dosing, calibration | Model-dependent | +## Date/time response format + +DAT and TIM return space-separated fields, not a single string: +``` +DAT A -- e.g. DAT A 01 10 2021 = 1 Oct 2021 +TIM A -- e.g. TIM A 09 56 11 = 09:56:11 +``` + +Both support set variants (`DAT DD MM YYYY`, `TIM HH MM SS`). +DAT set persists only via MT-SICS or FSET, not @. +TIM set also persists; only reset via MT-SICS, FSET, or terminal menu, not @. + ## Write safety Commands that modify device settings (M01 set, M02 set, M03 set, etc.) persist @@ -166,4 +178,7 @@ to memory and survive power cycles. They cannot be undone with @ reset - only via FSET (factory reset) or the terminal menu. Write methods are commented out in the backend to prevent accidental modification. +Exceptions: `set_date()` and `set_time()` are active (not commented out) since +they only set the internal clock, which is easily correctable. + See `mt_sics_commands.md` for the full command reference with implementation status. diff --git a/pylabrobot/scales/mettler_toledo/simulator.py b/pylabrobot/scales/mettler_toledo/simulator.py index 0e0749bd040..8325343c43b 100644 --- a/pylabrobot/scales/mettler_toledo/simulator.py +++ b/pylabrobot/scales/mettler_toledo/simulator.py @@ -58,15 +58,50 @@ def __init__( self.sample_weight: float = 0.0 self.zero_offset: float = 0.0 self.tare_weight: float = 0.0 + self.temperature: float = 22.5 # Simulated device identity self._human_readable_device_name = "Mettler Toledo Scale" - self._simulated_device_type = device_type - self._simulated_serial_number = serial_number - self._simulated_capacity = capacity + self.device_type = device_type + self.serial_number = serial_number + self.capacity = capacity + self.software_material_number: str = "12121306C" + self.device_id: str = "SimScale" + self.next_service_date: str = "16.03.2013" + self.assortment_type_revision: str = "5" + self.operating_mode_after_restart: str = "0" + self.date: str = "30.03.2026" + self.time: str = "12:00:00" + + # Simulated device configuration + self.weighing_mode: str = "0" + self.environment_condition: str = "2" + self.auto_zero: str = "1" + self.update_rate: str = "18.3" + self.adjustment_setting: str = "0 0" + self.serial_parameters: str = "0 6 3 1" + self.filter_cutoff: str = "0.000" + self.readability: str = "5" + self.test_settings: str = "0" + self.weighing_value_release: str = "1" + self.operating_mode: str = "0" + self.profact_time_criteria: str = "00 00 00 0" + self.profact_temperature_criterion: str = "1" + self.adjustment_weight: str = "10.00000 g" + self.test_weight: str = "200.00000 g" + self.profact_day: str = "0" + self.zeroing_mode: str = "0" + self.uptime_minutes: int = 1440 # Default: all commands the simulator can mock - self._simulated_supported_commands = supported_commands or { + self._supported_commands = supported_commands or { "@", + "C", + "C0", + "COM", + "D", + "DAT", + "DW", + "FCUT", "I0", "I1", "I2", @@ -77,34 +112,44 @@ def __init__( "I11", "I14", "I15", + "I16", + "I21", + "I26", "I50", - "S", - "SI", - "Z", - "ZI", - "ZC", - "T", - "TI", - "TC", - "TA", - "TAC", - "SC", - "C", - "D", - "DW", - "DAT", - "TIM", + "LST", "M01", "M02", "M03", + "M17", + "M18", + "M19", + "M20", "M21", "M27", "M28", + "M29", + "M31", + "M32", + "M33", + "M35", + "RDB", + "S", + "SC", + "SI", "SIS", "SNR", - "SR", - "SIR", + "T", + "TA", + "TAC", + "TC", + "TI", + "TIM", + "TST0", "UPD", + "USTB", + "Z", + "ZC", + "ZI", } @property @@ -112,10 +157,10 @@ def _sensor_reading(self) -> float: return self.platform_weight + self.sample_weight async def setup(self) -> None: - self.serial_number = self._simulated_serial_number - self._supported_commands = self._simulated_supported_commands - self.device_type = self._simulated_device_type - self.capacity = self._simulated_capacity + self.serial_number = self.serial_number + self._supported_commands = self._supported_commands + self.device_type = self.device_type + self.capacity = self.capacity self.firmware_version = "1.10 18.6.4.1361.772" self.configuration = "Bridge" if "Bridge" in self.device_type else "Balance" logger.info( @@ -165,49 +210,74 @@ def _build_response(self, command: str) -> List[MettlerToledoResponse]: # Identification (shlex strips quotes, so mock responses should not include them) if cmd == "@": - return [R("I4", "A", [self._simulated_serial_number])] + return [R("I4", "A", [self.serial_number])] if cmd == "I0": - cmds = sorted(self._simulated_supported_commands) + cmds = sorted(self._supported_commands) responses = [R("I0", "B", ["0", c]) for c in cmds[:-1]] responses.append(R("I0", "A", ["0", cmds[-1]])) return responses if cmd == "I1": return [R("I1", "A", ["01"])] if cmd == "I2": - return [R("I2", "A", [f"{self._simulated_device_type} {self._simulated_capacity:.5f} g"])] + return [R("I2", "A", [f"{self.device_type} {self.capacity:.5f} g"])] if cmd == "I4": - return [R("I4", "A", [self._simulated_serial_number])] + return [R("I4", "A", [self.serial_number])] if cmd == "I3": return [R("I3", "A", [self.firmware_version])] if cmd == "I5": - return [R("I5", "A", ["12121306C"])] + return [R("I5", "A", [self.software_material_number])] if cmd == "I10": - # I10 can be query or set parts = command.split(maxsplit=1) if len(parts) > 1: + self.device_id = parts[1].strip('"') return [R("I10", "A")] - return [R("I10", "A", ["SimScale"])] + return [R("I10", "A", [self.device_id])] if cmd == "I11": - return [R("I11", "A", [self._simulated_device_type])] + return [R("I11", "A", [self.device_type])] if cmd == "I14": return [ R("I14", "B", ["0", "1", "Bridge"]), - R("I14", "A", ["1", "1", self._simulated_device_type]), + R("I14", "A", ["1", "1", self.device_type]), ] if cmd == "I15": - return [R("I15", "A", ["1440"])] # 1440 minutes = 24 hours + return [R("I15", "A", [str(self.uptime_minutes)])] + if cmd == "I16": + d, m, y = self.next_service_date.split(".") + return [R("I16", "A", [d, m, y])] + if cmd == "I21": + return [R("I21", "A", [self.assortment_type_revision])] + if cmd == "I26": + return [R("I26", "A", [self.operating_mode_after_restart])] if cmd == "DAT": - return [R("DAT", "A", ["30.03.2026"])] + parts = command.split() + if len(parts) > 1: + self.date = f"{parts[1]}.{parts[2]}.{parts[3]}" + return [R("DAT", "A")] + d, m, y = self.date.split(".") + return [R("DAT", "A", [d, m, y])] if cmd == "TIM": - return [R("TIM", "A", ["12:00:00"])] + parts = command.split() + if len(parts) > 1: + self.time = f"{parts[1]}:{parts[2]}:{parts[3]}" + return [R("TIM", "A")] + h, mi, s = self.time.split(":") + return [R("TIM", "A", [h, mi, s])] # Configuration queries if cmd == "M01": - return [R("M01", "A", ["0"])] # Normal weighing mode + return [R("M01", "A", [self.weighing_mode])] if cmd == "M02": - return [R("M02", "A", ["2"])] # Standard environment + return [R("M02", "A", [self.environment_condition])] if cmd == "M03": - return [R("M03", "A", ["1"])] # Auto zero on + return [R("M03", "A", [self.auto_zero])] + if cmd == "M17": + return [R("M17", "A", self.profact_time_criteria.split())] + if cmd == "M18": + return [R("M18", "A", [self.profact_temperature_criterion])] + if cmd == "M19": + return [R("M19", "A", self.adjustment_weight.split())] + if cmd == "M20": + return [R("M20", "A", self.test_weight.split())] if cmd == "M27": return [ R("M27", "B", ["1", "1", "1", "2026", "8", "0", "0", ""]), @@ -220,8 +290,48 @@ def _build_response(self, command: str) -> List[MettlerToledoResponse]: return [R("SIS", "A", [state, f"{net:.5f}", "0", "5", "1", "0", info])] if cmd == "SNR": return [R("SNR", "S", [f"{net:.5f}", "g"])] + if cmd == "M29": + return [R("M29", "A", [self.weighing_value_release])] + if cmd == "M31": + return [R("M31", "A", [self.operating_mode])] + if cmd == "M32": + return [ + R("M32", "B", ["1", "00", "00", "0"]), + R("M32", "B", ["2", "00", "00", "0"]), + R("M32", "A", ["3", "00", "00", "0"]), + ] + if cmd == "M33": + return [R("M33", "A", [self.profact_day])] + if cmd == "M35": + return [R("M35", "A", [self.zeroing_mode])] if cmd == "UPD": - return [R("UPD", "A", ["18.3"])] + return [R("UPD", "A", [self.update_rate])] + if cmd == "C0": + return [R("C0", "A", self.adjustment_setting.split())] + if cmd == "COM": + return [R("COM", "A", self.serial_parameters.split())] + if cmd == "FCUT": + return [R("FCUT", "A", [self.filter_cutoff])] + if cmd == "RDB": + return [R("RDB", "A", [self.readability])] + if cmd == "USTB": + return [ + R("USTB", "B", ["0", "3.600", "1.100"]), + R("USTB", "B", ["1", "0.000", "0.000"]), + R("USTB", "A", ["2", "0.000", "0.000"]), + ] + if cmd == "TST0": + return [R("TST0", "A", [self.test_settings])] + if cmd == "LST": + return [ + R("LST", "B", ["C0"] + self.adjustment_setting.split()), + R("LST", "B", ["FCUT", self.filter_cutoff]), + R("LST", "B", ["M01", self.weighing_mode]), + R("LST", "B", ["M02", self.environment_condition]), + R("LST", "B", ["M03", self.auto_zero]), + R("LST", "B", ["M21", "0", "0"]), + R("LST", "A", ["UPD", self.update_rate]), + ] # Zero if cmd in ("Z", "ZI", "ZC"): @@ -256,11 +366,11 @@ def _build_response(self, command: str) -> List[MettlerToledoResponse]: # Temperature if cmd == "M28": - return [R("M28", "A", ["1", "22.5"])] + return [R("M28", "A", ["1", str(self.temperature)])] # Remaining weighing range if cmd == "I50": - remaining = self._simulated_capacity - self._sensor_reading + remaining = self.capacity - self._sensor_reading return [ R("I50", "B", ["0", f"{remaining:.3f}", "g"]), R("I50", "B", ["1", "0.000", "g"]), From 660e8686c7b7ef9740bb3a81ab4e9a1ecc990546 Mon Sep 17 00:00:00 2001 From: Camillo Moschner Date: Mon, 30 Mar 2026 18:06:03 +0100 Subject: [PATCH 34/38] Error catching OSError, TimeoutError, MettlerToledoError, KeyboardInterrupt --- .../scales/mettler-toledo-WXS205SDU.ipynb | 203 ++++++++---------- pylabrobot/scales/mettler_toledo/backend.py | 107 +++++---- .../scales/mettler_toledo/backend_tests.py | 14 +- pylabrobot/scales/mettler_toledo/simulator.py | 106 +++++---- 4 files changed, 211 insertions(+), 219 deletions(-) diff --git a/docs/user_guide/02_analytical/scales/mettler-toledo-WXS205SDU.ipynb b/docs/user_guide/02_analytical/scales/mettler-toledo-WXS205SDU.ipynb index 726128550f1..299739c079d 100644 --- a/docs/user_guide/02_analytical/scales/mettler-toledo-WXS205SDU.ipynb +++ b/docs/user_guide/02_analytical/scales/mettler-toledo-WXS205SDU.ipynb @@ -99,7 +99,7 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 13:01:11,777 - pylabrobot - INFO - === MT Scale tutorial started ===\n" + "2026-03-30 17:05:11,973 - pylabrobot - INFO - === MT Scale tutorial started ===\n" ] } ], @@ -135,13 +135,13 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 13:01:11,847 - pylabrobot - INFO - [MT Scale] Connected to Mettler Toledo scale (simulation)\n", + "2026-03-30 17:05:12,021 - pylabrobot - INFO - [Mettler Toledo Scale] Connected (simulation)\n", "Device type: WXS205SDU\n", "Configuration: Balance\n", "Serial number: SIM0000001\n", "Firmware: 1.10 18.6.4.1361.772\n", "Capacity: 220.0 g\n", - "Supported commands: ['@', 'C', 'D', 'DAT', 'DW', 'I0', 'I1', 'I10', 'I11', 'I14', 'I15', 'I2', 'I3', 'I4', 'I5', 'I50', 'M21', 'M28', 'S', 'SC', 'SI', 'SIR', 'SR', 'T', 'TA', 'TAC', 'TC', 'TI', 'TIM', 'Z', 'ZC', 'ZI']\n" + "Supported commands: ['@', 'C', 'D', 'DAT', 'DW', 'I0', 'I1', 'I10', 'I11', 'I14', 'I15', 'I2', 'I3', 'I4', 'I5', 'I50', 'M01', 'M02', 'M03', 'M21', 'M27', 'M28', 'S', 'SC', 'SI', 'SIR', 'SIS', 'SNR', 'SR', 'T', 'TA', 'TAC', 'TC', 'TI', 'TIM', 'UPD', 'Z', 'ZC', 'ZI']\n" ] } ], @@ -200,9 +200,68 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 4, "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "['cancel_all',\n", + " 'clear_tare',\n", + " 'deserialize',\n", + " 'get_all_instances',\n", + " 'get_weight',\n", + " 'measure_temperature',\n", + " 'read_dynamic_weight',\n", + " 'read_stable_weight',\n", + " 'read_stable_weight_repeat_on_change',\n", + " 'read_weight',\n", + " 'read_weight_value_immediately',\n", + " 'request_adjustment_history',\n", + " 'request_auto_zero',\n", + " 'request_capacity',\n", + " 'request_date',\n", + " 'request_device_id',\n", + " 'request_device_info',\n", + " 'request_device_type',\n", + " 'request_environment_condition',\n", + " 'request_firmware_version',\n", + " 'request_model_designation',\n", + " 'request_net_weight_with_status',\n", + " 'request_remaining_weighing_range',\n", + " 'request_serial_number',\n", + " 'request_software_material_number',\n", + " 'request_supported_methods',\n", + " 'request_tare_weight',\n", + " 'request_time',\n", + " 'request_update_rate',\n", + " 'request_uptime_minutes',\n", + " 'request_weighing_mode',\n", + " 'reset',\n", + " 'send_command',\n", + " 'serialize',\n", + " 'set_date',\n", + " 'set_display_text',\n", + " 'set_host_unit_grams',\n", + " 'set_time',\n", + " 'set_weight_display',\n", + " 'setup',\n", + " 'stop',\n", + " 'tare',\n", + " 'tare_immediately',\n", + " 'tare_stable',\n", + " 'tare_timeout',\n", + " 'zero',\n", + " 'zero_immediately',\n", + " 'zero_stable',\n", + " 'zero_timeout']" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "backend.request_supported_methods()" ] @@ -227,7 +286,7 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 5, "metadata": { "execution": { "iopub.execute_input": "2026-03-30T12:01:11.850228Z", @@ -241,14 +300,8 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 13:01:11,850 - pylabrobot - IO - [MT Scale] Sent command: ZC 5000\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2026-03-30 13:01:11,850 - pylabrobot - IO - [MT Scale] Received response: ZC A \n" + "2026-03-30 17:05:12,031 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: ZC 5000\n", + "2026-03-30 17:05:12,031 - pylabrobot - IO - [Mettler Toledo Scale] Received response: ZC A \n" ] } ], @@ -279,7 +332,7 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 6, "metadata": { "execution": { "iopub.execute_input": "2026-03-30T12:01:11.853205Z", @@ -293,14 +346,8 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 13:01:11,853 - pylabrobot - IO - [MT Scale] Sent command: TC 5000\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2026-03-30 13:01:11,853 - pylabrobot - IO - [MT Scale] Received response: TC S 50.00000 g\n" + "2026-03-30 17:05:12,036 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: TC 5000\n", + "2026-03-30 17:05:12,037 - pylabrobot - IO - [Mettler Toledo Scale] Received response: TC S 50.00000 g\n" ] } ], @@ -320,7 +367,7 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 7, "metadata": { "execution": { "iopub.execute_input": "2026-03-30T12:01:11.855951Z", @@ -334,14 +381,8 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 13:01:11,856 - pylabrobot - IO - [MT Scale] Sent command: TA\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2026-03-30 13:01:11,856 - pylabrobot - IO - [MT Scale] Received response: TA A 50.00000 g\n" + "2026-03-30 17:05:12,042 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: TA\n", + "2026-03-30 17:05:12,042 - pylabrobot - IO - [Mettler Toledo Scale] Received response: TA A 50.00000 g\n" ] }, { @@ -350,7 +391,7 @@ "50.0" ] }, - "execution_count": 6, + "execution_count": 7, "metadata": {}, "output_type": "execute_result" } @@ -371,7 +412,7 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 8, "metadata": { "execution": { "iopub.execute_input": "2026-03-30T12:01:11.859830Z", @@ -385,14 +426,8 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 13:01:11,860 - pylabrobot - IO - [MT Scale] Sent command: SI\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2026-03-30 13:01:11,860 - pylabrobot - IO - [MT Scale] Received response: SI S 0.01060 g\n" + "2026-03-30 17:05:12,050 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: SI\n", + "2026-03-30 17:05:12,051 - pylabrobot - IO - [Mettler Toledo Scale] Received response: SI S 0.01060 g\n" ] }, { @@ -401,7 +436,7 @@ "0.0106" ] }, - "execution_count": 7, + "execution_count": 8, "metadata": {}, "output_type": "execute_result" } @@ -425,7 +460,7 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 9, "metadata": { "execution": { "iopub.execute_input": "2026-03-30T12:01:11.862744Z", @@ -439,42 +474,12 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 13:01:11,863 - pylabrobot - IO - [MT Scale] Sent command: Z\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2026-03-30 13:01:11,863 - pylabrobot - IO - [MT Scale] Received response: Z A \n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2026-03-30 13:01:11,863 - pylabrobot - IO - [MT Scale] Sent command: TC 5000\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2026-03-30 13:01:11,864 - pylabrobot - IO - [MT Scale] Received response: TC S -0.01060 g\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2026-03-30 13:01:11,864 - pylabrobot - IO - [MT Scale] Sent command: SC 5000\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2026-03-30 13:01:11,864 - pylabrobot - IO - [MT Scale] Received response: SC S 0.01060 g\n" + "2026-03-30 17:05:12,056 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: Z\n", + "2026-03-30 17:05:12,057 - pylabrobot - IO - [Mettler Toledo Scale] Received response: Z A \n", + "2026-03-30 17:05:12,058 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: TC 5000\n", + "2026-03-30 17:05:12,058 - pylabrobot - IO - [Mettler Toledo Scale] Received response: TC S -0.01060 g\n", + "2026-03-30 17:05:12,059 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: SC 5000\n", + "2026-03-30 17:05:12,059 - pylabrobot - IO - [Mettler Toledo Scale] Received response: SC S 0.01060 g\n" ] }, { @@ -536,7 +541,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 10, "metadata": { "execution": { "iopub.execute_input": "2026-03-30T12:01:11.866619Z", @@ -550,35 +555,15 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 13:01:11,866 - pylabrobot - IO - [MT Scale] Sent command: I50\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2026-03-30 13:01:11,867 - pylabrobot - IO - [MT Scale] Received response: I50 B 0 173.940 g\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2026-03-30 13:01:11,867 - pylabrobot - IO - [MT Scale] Received response: I50 B 1 0.000 g\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2026-03-30 13:01:11,867 - pylabrobot - IO - [MT Scale] Received response: I50 A 2 173.940 g\n" + "2026-03-30 17:05:12,063 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: M28\n", + "2026-03-30 17:05:12,064 - pylabrobot - IO - [Mettler Toledo Scale] Received response: M28 A 1 21.3\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ - "Remaining capacity: 173.9 g\n" + "Scale temperature: 21.3 C\n" ] } ], @@ -667,14 +652,8 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-30 13:01:11,875 - pylabrobot - INFO - === MT Scale tutorial ended ===\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2026-03-30 13:01:11,875 - pylabrobot - INFO - [MT Scale] Disconnected (simulation)\n" + "2026-03-30 17:05:12,076 - pylabrobot - INFO - === MT Scale tutorial ended ===\n", + "2026-03-30 17:05:12,078 - pylabrobot - INFO - [Mettler Toledo Scale] Disconnected (simulation)\n" ] } ], diff --git a/pylabrobot/scales/mettler_toledo/backend.py b/pylabrobot/scales/mettler_toledo/backend.py index 168ecc284d4..7bfe1e13928 100644 --- a/pylabrobot/scales/mettler_toledo/backend.py +++ b/pylabrobot/scales/mettler_toledo/backend.py @@ -143,7 +143,7 @@ async def setup(self) -> None: "Serial number: %s\n" "Firmware: %s\n" "Capacity: %.1f g\n" - "Supported commands: %s", + "Supported commands (%d): %s", self.io._human_readable_device_name, self.io.port, self.device_type, @@ -151,7 +151,8 @@ async def setup(self) -> None: self.serial_number, self.firmware_version, self.capacity, - sorted(self._supported_commands), + len(self._supported_commands), + ", ".join(sorted(self._supported_commands)), ) # Check major.minor version only (TDNR varies by hardware revision) @@ -180,7 +181,7 @@ async def stop(self) -> None: """ try: await self.reset() - except Exception: + except (OSError, TimeoutError, MettlerToledoError): logger.warning( "[%s] Could not reset device before disconnecting", self.io._human_readable_device_name ) @@ -338,38 +339,57 @@ async def send_command(self, command: str, timeout: int = 60) -> List[MettlerTol logger.log(LOG_LEVEL_IO, "[%s] Sent command: %s", self.io._human_readable_device_name, command) await self.io.write(command.encode() + b"\r\n") - responses: List[MettlerToledoResponse] = [] - timeout_time = time.time() + timeout - while True: + try: + responses: List[MettlerToledoResponse] = [] + timeout_time = time.time() + timeout while True: - raw_response = await self.io.readline() - if raw_response != b"": + while True: + raw_response = await self.io.readline() + if raw_response != b"": + break + if time.time() > timeout_time: + raise TimeoutError("Timeout while waiting for response from scale.") + await asyncio.sleep(0.001) + + logger.log( + LOG_LEVEL_IO, + "[%s] Received response: %s", + self.io._human_readable_device_name, + raw_response, + ) + fields = shlex.split(raw_response.decode("utf-8").strip()) + if len(fields) >= 2: + response = MettlerToledoResponse(command=fields[0], status=fields[1], data=fields[2:]) + elif len(fields) == 1: + response = MettlerToledoResponse(command=fields[0], status="", data=[]) + else: + response = MettlerToledoResponse(command="", status="", data=[]) + self._parse_basic_errors(response) + responses.append(response) + + # Status B means more responses follow; anything else (A, etc.) is final + if response.status != "B": break - if time.time() > timeout_time: - raise TimeoutError("Timeout while waiting for response from scale.") - await asyncio.sleep(0.001) - logger.log( - LOG_LEVEL_IO, - "[%s] Received response: %s", - self.io._human_readable_device_name, - raw_response, - ) - fields = shlex.split(raw_response.decode("utf-8").strip()) - if len(fields) >= 2: - response = MettlerToledoResponse(command=fields[0], status=fields[1], data=fields[2:]) - elif len(fields) == 1: - response = MettlerToledoResponse(command=fields[0], status="", data=[]) + return responses + + except (KeyboardInterrupt, asyncio.CancelledError): + # Cancel pending commands without resetting device state (zero/tare). + # Use C (cancel all) if available; otherwise just flush the buffer. + # Never send @ here - it clears zero/tare which the user wants to keep. + if hasattr(self, "_supported_commands") and "C" in self._supported_commands: + logger.warning( + "[%s] Command interrupted, sending C to cancel pending commands", + self.io._human_readable_device_name, + ) + await self.io.write(b"C\r\n") else: - response = MettlerToledoResponse(command="", status="", data=[]) - self._parse_basic_errors(response) - responses.append(response) - - # Status B means more responses follow; anything else (A, etc.) is final - if response.status != "B": - break - - return responses + logger.warning( + "[%s] Command interrupted, flushing serial buffer", + self.io._human_readable_device_name, + ) + await self.io.reset_input_buffer() + raise # === Public API === # Organized by function: cancel, identity, zero, tare, weight, measurement, @@ -607,8 +627,8 @@ async def zero_stable(self) -> List[MettlerToledoResponse]: @requires_mt_sics_command("ZC") async def zero_timeout(self, timeout: float) -> List[MettlerToledoResponse]: """Zero the scale after a given timeout. (ZC command)""" - timeout = int(timeout * 1000) - return await self.send_command(f"ZC {timeout}") + timeout_ms = int(timeout * 1000) + return await self.send_command(f"ZC {timeout_ms}") async def zero( self, timeout: Union[Literal["stable"], float, int] = "stable" @@ -642,8 +662,8 @@ async def tare_immediately(self) -> List[MettlerToledoResponse]: @requires_mt_sics_command("TC") async def tare_timeout(self, timeout: float) -> List[MettlerToledoResponse]: """Tare the scale after a given timeout. (TC command)""" - timeout = int(timeout * 1000) # convert to milliseconds - return await self.send_command(f"TC {timeout}") + timeout_ms = int(timeout * 1000) + return await self.send_command(f"TC {timeout_ms}") async def tare( self, timeout: Union[Literal["stable"], float, int] = "stable" @@ -695,27 +715,20 @@ async def read_stable_weight(self) -> float: @requires_mt_sics_command("SC") async def read_dynamic_weight(self, timeout: float) -> float: - """Read a stable weight value from the machine within a given timeout, or - return the current weight value if not possible. (MEASUREMENT command) + """Read a stable weight value within a given timeout, or return the current + weight value if stability is not reached. (SC command) Args: timeout: The timeout in seconds. """ - - timeout = int(timeout * 1000) # convert to milliseconds - - responses = await self.send_command(f"SC {timeout}") + timeout_ms = int(timeout * 1000) + responses = await self.send_command(f"SC {timeout_ms}") self._validate_response(responses[0], 4, "SC") self._validate_unit(responses[0].data[1], "SC") return float(responses[0].data[0]) async def read_weight_value_immediately(self) -> float: - """Read a weight value immediately from the scale. (MEASUREMENT command) - - "Use SI to immediately send the current weight value, along with the host unit, from the - balance to the connected communication partner via the interface." - """ - + """Read a weight value immediately from the scale. (SI command)""" responses = await self.send_command("SI") self._validate_response(responses[0], 4, "SI") self._validate_unit(responses[0].data[1], "SI") diff --git a/pylabrobot/scales/mettler_toledo/backend_tests.py b/pylabrobot/scales/mettler_toledo/backend_tests.py index fab0f7e83ed..18b510b2364 100644 --- a/pylabrobot/scales/mettler_toledo/backend_tests.py +++ b/pylabrobot/scales/mettler_toledo/backend_tests.py @@ -114,10 +114,13 @@ async def asyncSetUp(self): ) await self.scale.setup() + async def asyncTearDown(self): + await self.scale.stop() + async def test_setup_populates_device_identity(self): """setup() must populate device_type, serial_number, capacity, and MT-SICS levels. If any of these are missing, downstream methods that depend on them will fail.""" - self.assertEqual(self.backend.device_type, "WXS205SDU") + self.assertEqual(self.backend.device_type, "WXS205SDU WXA-Bridge") self.assertEqual(self.backend.serial_number, "SIM0000001") self.assertEqual(self.backend.capacity, 220.0) self.assertIn("S", self.backend._supported_commands) @@ -159,6 +162,11 @@ async def test_reset_returns_serial_number(self): sn = await self.backend.reset() self.assertEqual(sn, "SIM0000001") + async def test_cancel_all(self): + """cancel_all() sends C which returns multi-response (C B, C A). + Must consume both lines without raising.""" + await self.backend.cancel_all() + async def test_unknown_command_returns_syntax_error(self): """Unknown commands must return ES (syntax error) response. Ensures the simulator correctly simulates the device rejecting invalid commands.""" @@ -275,9 +283,9 @@ async def test_setup_populates_firmware_version(self): self.assertGreater(len(self.backend.firmware_version), 0) async def test_setup_populates_configuration(self): - """setup() must detect 'Balance' for default simulator (no 'Bridge' in type). + """setup() must detect 'Bridge' for default simulator (WXS205SDU WXA-Bridge). Drives which commands are expected to work on the device.""" - self.assertEqual(self.backend.configuration, "Balance") + self.assertEqual(self.backend.configuration, "Bridge") # -- Weight dispatch -- diff --git a/pylabrobot/scales/mettler_toledo/simulator.py b/pylabrobot/scales/mettler_toledo/simulator.py index 8325343c43b..d740c45aba6 100644 --- a/pylabrobot/scales/mettler_toledo/simulator.py +++ b/pylabrobot/scales/mettler_toledo/simulator.py @@ -45,7 +45,7 @@ class MettlerToledoSICSSimulator(MettlerToledoWXS205SDUBackend): def __init__( self, - device_type: str = "WXS205SDU", + device_type: str = "WXS205SDU WXA-Bridge", serial_number: str = "SIM0000001", capacity: float = 220.0, supported_commands: Optional[Set[str]] = None, @@ -91,7 +91,7 @@ def __init__( self.test_weight: str = "200.00000 g" self.profact_day: str = "0" self.zeroing_mode: str = "0" - self.uptime_minutes: int = 1440 + self.uptime_minutes: int = 60 * 24 # 1 day in minutes # Default: all commands the simulator can mock self._supported_commands = supported_commands or { "@", @@ -157,10 +157,6 @@ def _sensor_reading(self) -> float: return self.platform_weight + self.sample_weight async def setup(self) -> None: - self.serial_number = self.serial_number - self._supported_commands = self._supported_commands - self.device_type = self.device_type - self.capacity = self.capacity self.firmware_version = "1.10 18.6.4.1361.772" self.configuration = "Bridge" if "Bridge" in self.device_type else "Balance" logger.info( @@ -170,14 +166,15 @@ async def setup(self) -> None: "Serial number: %s\n" "Firmware: %s\n" "Capacity: %.1f g\n" - "Supported commands: %s", + "Supported commands (%d): %s", self._human_readable_device_name, self.device_type, self.configuration, self.serial_number, self.firmware_version, self.capacity, - sorted(self._supported_commands), + len(self._supported_commands), + ", ".join(sorted(self._supported_commands)), ) async def stop(self) -> None: @@ -208,9 +205,13 @@ def _build_response(self, command: str) -> List[MettlerToledoResponse]: cmd = command.split()[0] net = round(self._sensor_reading - self.zero_offset - self.tare_weight, 5) - # Identification (shlex strips quotes, so mock responses should not include them) + # Reset and cancel if cmd == "@": return [R("I4", "A", [self.serial_number])] + if cmd == "C": + return [R("C", "B"), R("C", "A")] + + # Device identity if cmd == "I0": cmds = sorted(self._supported_commands) responses = [R("I0", "B", ["0", c]) for c in cmds[:-1]] @@ -220,10 +221,10 @@ def _build_response(self, command: str) -> List[MettlerToledoResponse]: return [R("I1", "A", ["01"])] if cmd == "I2": return [R("I2", "A", [f"{self.device_type} {self.capacity:.5f} g"])] - if cmd == "I4": - return [R("I4", "A", [self.serial_number])] if cmd == "I3": return [R("I3", "A", [self.firmware_version])] + if cmd == "I4": + return [R("I4", "A", [self.serial_number])] if cmd == "I5": return [R("I5", "A", [self.software_material_number])] if cmd == "I10": @@ -233,7 +234,7 @@ def _build_response(self, command: str) -> List[MettlerToledoResponse]: return [R("I10", "A")] return [R("I10", "A", [self.device_id])] if cmd == "I11": - return [R("I11", "A", [self.device_type])] + return [R("I11", "A", [self.device_type.split()[0]])] if cmd == "I14": return [ R("I14", "B", ["0", "1", "Bridge"]), @@ -263,7 +264,41 @@ def _build_response(self, command: str) -> List[MettlerToledoResponse]: h, mi, s = self.time.split(":") return [R("TIM", "A", [h, mi, s])] - # Configuration queries + # Zero + if cmd in ("Z", "ZI", "ZC"): + self.zero_offset = self._sensor_reading + return [R(cmd, "A")] + + # Tare + if cmd in ("T", "TI", "TC"): + self.tare_weight = self._sensor_reading - self.zero_offset + return [R(cmd, "S", [f"{self.tare_weight:.5f}", "g"])] + if cmd == "TA": + return [R("TA", "A", [f"{self.tare_weight:.5f}", "g"])] + if cmd == "TAC": + self.tare_weight = 0.0 + return [R("TAC", "A")] + + # Weight measurement + if cmd in ("S", "SI", "SC"): + return [R(cmd, "S", [f"{net:.5f}", "g"])] + if cmd == "M28": + return [R("M28", "A", ["1", str(self.temperature)])] + if cmd == "SIS": + state = "0" + info = "0" if self.tare_weight == 0 else "1" + return [R("SIS", "A", [state, f"{net:.5f}", "0", "5", "1", "0", info])] + if cmd == "SNR": + return [R("SNR", "S", [f"{net:.5f}", "g"])] + if cmd == "I50": + remaining = self.capacity - self.platform_weight - self.sample_weight + return [ + R("I50", "B", ["0", f"{remaining:.3f}", "g"]), + R("I50", "B", ["1", "0.000", "g"]), + R("I50", "A", ["2", f"{remaining:.3f}", "g"]), + ] + + # Device configuration (read-only) if cmd == "M01": return [R("M01", "A", [self.weighing_mode])] if cmd == "M02": @@ -283,13 +318,6 @@ def _build_response(self, command: str) -> List[MettlerToledoResponse]: R("M27", "B", ["1", "1", "1", "2026", "8", "0", "0", ""]), R("M27", "A", ["2", "15", "3", "2026", "10", "30", "1", "200.1234 g"]), ] - if cmd == "SIS": - # State, NetWeight, Unit(0=g), Readability, Step, Approval, Info(0=no tare, 1=weighed tare) - state = "0" # stable - info = "0" if self.tare_weight == 0 else "1" - return [R("SIS", "A", [state, f"{net:.5f}", "0", "5", "1", "0", info])] - if cmd == "SNR": - return [R("SNR", "S", [f"{net:.5f}", "g"])] if cmd == "M29": return [R("M29", "A", [self.weighing_value_release])] if cmd == "M31": @@ -333,49 +361,13 @@ def _build_response(self, command: str) -> List[MettlerToledoResponse]: R("LST", "A", ["UPD", self.update_rate]), ] - # Zero - if cmd in ("Z", "ZI", "ZC"): - self.zero_offset = self._sensor_reading - return [R(cmd, "A")] - - # Tare - if cmd in ("T", "TI", "TC"): - self.tare_weight = self._sensor_reading - self.zero_offset - return [R(cmd, "S", [f"{self.tare_weight:.5f}", "g"])] - if cmd == "TA": - return [R("TA", "A", [f"{self.tare_weight:.5f}", "g"])] - if cmd == "TAC": - self.tare_weight = 0.0 - return [R("TAC", "A")] - - # Weight reading - if cmd in ("S", "SI", "SC"): - return [R(cmd, "S", [f"{net:.5f}", "g"])] - - # Cancel - if cmd == "C": - return [R("C", "B"), R("C", "A")] - # Display if cmd in ("D", "DW"): return [R(cmd, "A")] - # Configuration + # Configuration (write) if cmd == "M21": return [R("M21", "A")] - # Temperature - if cmd == "M28": - return [R("M28", "A", ["1", str(self.temperature)])] - - # Remaining weighing range - if cmd == "I50": - remaining = self.capacity - self._sensor_reading - return [ - R("I50", "B", ["0", f"{remaining:.3f}", "g"]), - R("I50", "B", ["1", "0.000", "g"]), - R("I50", "A", ["2", f"{remaining:.3f}", "g"]), - ] - # Unknown command return [R("ES", "")] From d8ac7d970f13908a72b1d00d6694f9718131959d Mon Sep 17 00:00:00 2001 From: Camillo Moschner Date: Mon, 30 Mar 2026 21:52:02 +0100 Subject: [PATCH 35/38] update documentation --- pylabrobot/scales/mettler_toledo/backend.py | 30 +- .../mettler_toledo/hardware_validation.ipynb | 2325 ----------------- .../scales/mettler_toledo/mt_sics_commands.md | 20 +- pylabrobot/scales/mettler_toledo/protocol.md | 15 +- 4 files changed, 40 insertions(+), 2350 deletions(-) delete mode 100644 pylabrobot/scales/mettler_toledo/hardware_validation.ipynb diff --git a/pylabrobot/scales/mettler_toledo/backend.py b/pylabrobot/scales/mettler_toledo/backend.py index 7bfe1e13928..051e2a2e715 100644 --- a/pylabrobot/scales/mettler_toledo/backend.py +++ b/pylabrobot/scales/mettler_toledo/backend.py @@ -632,7 +632,7 @@ async def zero_timeout(self, timeout: float) -> List[MettlerToledoResponse]: async def zero( self, timeout: Union[Literal["stable"], float, int] = "stable" - ) -> List[MettlerToledoResponse]: + ) -> None: """Zero the scale. Args: @@ -640,14 +640,15 @@ async def zero( float/int zeros after that many seconds. """ if timeout == "stable": - return await self.zero_stable() - if not isinstance(timeout, (float, int)): + await self.zero_stable() + elif not isinstance(timeout, (float, int)): raise TypeError("timeout must be a float or 'stable'") - if timeout < 0: + elif timeout < 0: raise ValueError("timeout must be greater than or equal to 0") - if timeout == 0: - return await self.zero_immediately() - return await self.zero_timeout(timeout) + elif timeout == 0: + await self.zero_immediately() + else: + await self.zero_timeout(timeout) # # Tare # # @@ -667,7 +668,7 @@ async def tare_timeout(self, timeout: float) -> List[MettlerToledoResponse]: async def tare( self, timeout: Union[Literal["stable"], float, int] = "stable" - ) -> List[MettlerToledoResponse]: + ) -> None: """Tare the scale. Args: @@ -675,14 +676,15 @@ async def tare( float/int tares after that many seconds. """ if timeout == "stable": - return await self.tare_stable() - if not isinstance(timeout, (float, int)): + await self.tare_stable() + elif not isinstance(timeout, (float, int)): raise TypeError("timeout must be a float or 'stable'") - if timeout < 0: + elif timeout < 0: raise ValueError("timeout must be greater than or equal to 0") - if timeout == 0: - return await self.tare_immediately() - return await self.tare_timeout(timeout) + elif timeout == 0: + await self.tare_immediately() + else: + await self.tare_timeout(timeout) async def request_tare_weight(self) -> float: """Query tare weight value from scale's memory. (TA command)""" diff --git a/pylabrobot/scales/mettler_toledo/hardware_validation.ipynb b/pylabrobot/scales/mettler_toledo/hardware_validation.ipynb deleted file mode 100644 index b4be8f574ed..00000000000 --- a/pylabrobot/scales/mettler_toledo/hardware_validation.ipynb +++ /dev/null @@ -1,2325 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# MT-SICS Backend Hardware Validation\n", - "\n", - "Run this notebook connected to a physical Mettler Toledo scale to validate\n", - "every implemented backend method. Each cell tests one method and logs the\n", - "raw MT-SICS command/response.\n", - "\n", - "**Requirements:**\n", - "- Physical Mettler Toledo scale connected via USB-to-serial\n", - "- Scale powered on and warmed up (60 min)\n", - "- Weighing pan empty at start" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "---\n", - "## 1. Setup and Logging" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2026-03-30 16:33:54,376 - pylabrobot - INFO - === Hardware validation started ===\n" - ] - } - ], - "source": [ - "import logging\n", - "from datetime import datetime\n", - "\n", - "import pylabrobot\n", - "from pylabrobot.io import LOG_LEVEL_IO\n", - "from pylabrobot.scales import Scale\n", - "from pylabrobot.scales.mettler_toledo import MettlerToledoWXS205SDUBackend\n", - "\n", - "timestamp = datetime.now().strftime(\"%Y-%m-%d_%H-%M-%S\")\n", - "log_file = f\"./logs/hardware_validation/{timestamp}_validation.log\"\n", - "\n", - "pylabrobot.verbose(True, level=LOG_LEVEL_IO)\n", - "pylabrobot.setup_logger(log_dir=log_file, level=LOG_LEVEL_IO)\n", - "\n", - "plr_logger = logging.getLogger(\"pylabrobot\")\n", - "plr_logger.info(\"=== Hardware validation started ===\")" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2026-03-30 16:33:54,399 - pylabrobot.io.serial - INFO - Using explicitly provided port: /dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0 (for VID=1027, PID=24577)\n", - "2026-03-30 16:33:54,407 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] reset_input_buffer\n", - "2026-03-30 16:33:54,408 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: @\n", - "2026-03-30 16:33:54,410 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'@\\r\\n'\n", - "2026-03-30 16:33:54,468 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I4 A \"B207696838\"\\r\\n'\n", - "2026-03-30 16:33:54,469 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I4 A \"B207696838\"\\r\\n'\n", - "2026-03-30 16:33:54,474 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: I0\n", - "2026-03-30 16:33:54,477 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I0\\r\\n'\n", - "2026-03-30 16:33:54,519 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I0\"\\r\\n'\n", - "2026-03-30 16:33:54,520 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 0 \"I0\"\\r\\n'\n", - "2026-03-30 16:33:54,532 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I1\"\\r\\n'\n", - "2026-03-30 16:33:54,534 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 0 \"I1\"\\r\\n'\n", - "2026-03-30 16:33:54,537 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I2\"\\r\\n'\n", - "2026-03-30 16:33:54,538 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 0 \"I2\"\\r\\n'\n", - "2026-03-30 16:33:54,549 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I3\"\\r\\n'\n", - "2026-03-30 16:33:54,550 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 0 \"I3\"\\r\\n'\n", - "2026-03-30 16:33:54,564 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I4\"\\r\\n'\n", - "2026-03-30 16:33:54,565 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 0 \"I4\"\\r\\n'\n", - "2026-03-30 16:33:54,583 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I5\"\\r\\n'\n", - "2026-03-30 16:33:54,588 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 0 \"I5\"\\r\\n'\n", - "2026-03-30 16:33:54,598 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"S\"\\r\\n'\n", - "2026-03-30 16:33:54,600 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 0 \"S\"\\r\\n'\n", - "2026-03-30 16:33:54,612 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"SI\"\\r\\n'\n", - "2026-03-30 16:33:54,615 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 0 \"SI\"\\r\\n'\n", - "2026-03-30 16:33:54,617 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"SIR\"\\r\\n'\n", - "2026-03-30 16:33:54,624 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 0 \"SIR\"\\r\\n'\n", - "2026-03-30 16:33:54,629 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"Z\"\\r\\n'\n", - "2026-03-30 16:33:54,630 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 0 \"Z\"\\r\\n'\n", - "2026-03-30 16:33:54,645 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"ZI\"\\r\\n'\n", - "2026-03-30 16:33:54,651 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 0 \"ZI\"\\r\\n'\n", - "2026-03-30 16:33:54,660 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"@\"\\r\\n'\n", - "2026-03-30 16:33:54,664 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 0 \"@\"\\r\\n'\n", - "2026-03-30 16:33:54,676 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"SR\"\\r\\n'\n", - "2026-03-30 16:33:54,678 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 1 \"SR\"\\r\\n'\n", - "2026-03-30 16:33:54,693 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"T\"\\r\\n'\n", - "2026-03-30 16:33:54,699 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 1 \"T\"\\r\\n'\n", - "2026-03-30 16:33:54,705 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"TA\"\\r\\n'\n", - "2026-03-30 16:33:54,707 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 1 \"TA\"\\r\\n'\n", - "2026-03-30 16:33:54,717 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"TAC\"\\r\\n'\n", - "2026-03-30 16:33:54,718 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 1 \"TAC\"\\r\\n'\n", - "2026-03-30 16:33:54,724 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"TI\"\\r\\n'\n", - "2026-03-30 16:33:54,726 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 1 \"TI\"\\r\\n'\n", - "2026-03-30 16:33:54,740 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C0\"\\r\\n'\n", - "2026-03-30 16:33:54,741 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"C0\"\\r\\n'\n", - "2026-03-30 16:33:54,756 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C1\"\\r\\n'\n", - "2026-03-30 16:33:54,757 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"C1\"\\r\\n'\n", - "2026-03-30 16:33:54,772 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C2\"\\r\\n'\n", - "2026-03-30 16:33:54,774 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"C2\"\\r\\n'\n", - "2026-03-30 16:33:54,788 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C3\"\\r\\n'\n", - "2026-03-30 16:33:54,789 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"C3\"\\r\\n'\n", - "2026-03-30 16:33:54,791 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"COM\"\\r\\n'\n", - "2026-03-30 16:33:54,792 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"COM\"\\r\\n'\n", - "2026-03-30 16:33:54,804 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"DAT\"\\r\\n'\n", - "2026-03-30 16:33:54,805 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"DAT\"\\r\\n'\n", - "2026-03-30 16:33:54,820 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I10\"\\r\\n'\n", - "2026-03-30 16:33:54,822 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"I10\"\\r\\n'\n", - "2026-03-30 16:33:54,835 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I11\"\\r\\n'\n", - "2026-03-30 16:33:54,836 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"I11\"\\r\\n'\n", - "2026-03-30 16:33:54,852 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I14\"\\r\\n'\n", - "2026-03-30 16:33:54,853 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"I14\"\\r\\n'\n", - "2026-03-30 16:33:54,868 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I15\"\\r\\n'\n", - "2026-03-30 16:33:54,870 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"I15\"\\r\\n'\n", - "2026-03-30 16:33:54,884 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I16\"\\r\\n'\n", - "2026-03-30 16:33:54,885 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"I16\"\\r\\n'\n", - "2026-03-30 16:33:54,900 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I21\"\\r\\n'\n", - "2026-03-30 16:33:54,902 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"I21\"\\r\\n'\n", - "2026-03-30 16:33:54,916 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I22\"\\r\\n'\n", - "2026-03-30 16:33:54,917 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"I22\"\\r\\n'\n", - "2026-03-30 16:33:54,931 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I23\"\\r\\n'\n", - "2026-03-30 16:33:54,932 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"I23\"\\r\\n'\n", - "2026-03-30 16:33:54,948 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I24\"\\r\\n'\n", - "2026-03-30 16:33:54,948 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"I24\"\\r\\n'\n", - "2026-03-30 16:33:54,950 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I25\"\\r\\n'\n", - "2026-03-30 16:33:54,951 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"I25\"\\r\\n'\n", - "2026-03-30 16:33:54,964 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I26\"\\r\\n'\n", - "2026-03-30 16:33:54,965 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"I26\"\\r\\n'\n", - "2026-03-30 16:33:54,981 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M01\"\\r\\n'\n", - "2026-03-30 16:33:54,983 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"M01\"\\r\\n'\n", - "2026-03-30 16:33:54,997 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M02\"\\r\\n'\n", - "2026-03-30 16:33:54,999 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"M02\"\\r\\n'\n", - "2026-03-30 16:33:55,012 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M03\"\\r\\n'\n", - "2026-03-30 16:33:55,013 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"M03\"\\r\\n'\n", - "2026-03-30 16:33:55,027 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M17\"\\r\\n'\n", - "2026-03-30 16:33:55,028 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"M17\"\\r\\n'\n", - "2026-03-30 16:33:55,046 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M18\"\\r\\n'\n", - "2026-03-30 16:33:55,048 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"M18\"\\r\\n'\n", - "2026-03-30 16:33:55,060 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M19\"\\r\\n'\n", - "2026-03-30 16:33:55,061 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"M19\"\\r\\n'\n", - "2026-03-30 16:33:55,075 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M20\"\\r\\n'\n", - "2026-03-30 16:33:55,076 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"M20\"\\r\\n'\n", - "2026-03-30 16:33:55,092 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M21\"\\r\\n'\n", - "2026-03-30 16:33:55,093 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"M21\"\\r\\n'\n", - "2026-03-30 16:33:55,108 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M27\"\\r\\n'\n", - "2026-03-30 16:33:55,112 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"M27\"\\r\\n'\n", - "2026-03-30 16:33:55,113 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M28\"\\r\\n'\n", - "2026-03-30 16:33:55,115 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"M28\"\\r\\n'\n", - "2026-03-30 16:33:55,123 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M29\"\\r\\n'\n", - "2026-03-30 16:33:55,124 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"M29\"\\r\\n'\n", - "2026-03-30 16:33:55,140 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M31\"\\r\\n'\n", - "2026-03-30 16:33:55,140 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"M31\"\\r\\n'\n", - "2026-03-30 16:33:55,156 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M32\"\\r\\n'\n", - "2026-03-30 16:33:55,157 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"M32\"\\r\\n'\n", - "2026-03-30 16:33:55,172 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M33\"\\r\\n'\n", - "2026-03-30 16:33:55,173 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"M33\"\\r\\n'\n", - "2026-03-30 16:33:55,187 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M35\"\\r\\n'\n", - "2026-03-30 16:33:55,188 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"M35\"\\r\\n'\n", - "2026-03-30 16:33:55,204 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"SIS\"\\r\\n'\n", - "2026-03-30 16:33:55,204 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"SIS\"\\r\\n'\n", - "2026-03-30 16:33:55,220 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"SNR\"\\r\\n'\n", - "2026-03-30 16:33:55,221 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"SNR\"\\r\\n'\n", - "2026-03-30 16:33:55,235 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TIM\"\\r\\n'\n", - "2026-03-30 16:33:55,236 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"TIM\"\\r\\n'\n", - "2026-03-30 16:33:55,251 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST0\"\\r\\n'\n", - "2026-03-30 16:33:55,252 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"TST0\"\\r\\n'\n", - "2026-03-30 16:33:55,268 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST1\"\\r\\n'\n", - "2026-03-30 16:33:55,268 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"TST1\"\\r\\n'\n", - "2026-03-30 16:33:55,284 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST2\"\\r\\n'\n", - "2026-03-30 16:33:55,285 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"TST2\"\\r\\n'\n", - "2026-03-30 16:33:55,299 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST3\"\\r\\n'\n", - "2026-03-30 16:33:55,300 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"TST3\"\\r\\n'\n", - "2026-03-30 16:33:55,316 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"UPD\"\\r\\n'\n", - "2026-03-30 16:33:55,316 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"UPD\"\\r\\n'\n", - "2026-03-30 16:33:55,332 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"FCUT\"\\r\\n'\n", - "2026-03-30 16:33:55,333 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 3 \"FCUT\"\\r\\n'\n", - "2026-03-30 16:33:55,347 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"FSET\"\\r\\n'\n", - "2026-03-30 16:33:55,348 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 3 \"FSET\"\\r\\n'\n", - "2026-03-30 16:33:55,364 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"LST\"\\r\\n'\n", - "2026-03-30 16:33:55,365 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 3 \"LST\"\\r\\n'\n", - "2026-03-30 16:33:55,366 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"RDB\"\\r\\n'\n", - "2026-03-30 16:33:55,367 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 3 \"RDB\"\\r\\n'\n", - "2026-03-30 16:33:55,380 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 A 3 \"USTB\"\\r\\n'\n", - "2026-03-30 16:33:55,381 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 A 3 \"USTB\"\\r\\n'\n", - "2026-03-30 16:33:55,382 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: I2\n", - "2026-03-30 16:33:55,383 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I2\\r\\n'\n", - "2026-03-30 16:33:55,444 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", - "2026-03-30 16:33:55,444 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", - "2026-03-30 16:33:55,445 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: I2\n", - "2026-03-30 16:33:55,446 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I2\\r\\n'\n", - "2026-03-30 16:33:55,508 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", - "2026-03-30 16:33:55,509 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", - "2026-03-30 16:33:55,510 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: I3\n", - "2026-03-30 16:33:55,511 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I3\\r\\n'\n", - "2026-03-30 16:33:55,556 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I3 A \"1.10 18.6.4.1361.772\"\\r\\n'\n", - "2026-03-30 16:33:55,556 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I3 A \"1.10 18.6.4.1361.772\"\\r\\n'\n", - "2026-03-30 16:33:55,557 - pylabrobot - INFO - [Mettler Toledo Scale] Connected on /dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0\n", - "Device type: WXS205SDU WXA-Bridge\n", - "Configuration: Bridge\n", - "Serial number: B207696838\n", - "Firmware: 1.10 18.6.4.1361.772\n", - "Capacity: 220.0 g\n", - "Supported commands: ['@', 'C0', 'C1', 'C2', 'C3', 'COM', 'DAT', 'FCUT', 'FSET', 'I0', 'I1', 'I10', 'I11', 'I14', 'I15', 'I16', 'I2', 'I21', 'I22', 'I23', 'I24', 'I25', 'I26', 'I3', 'I4', 'I5', 'LST', 'M01', 'M02', 'M03', 'M17', 'M18', 'M19', 'M20', 'M21', 'M27', 'M28', 'M29', 'M31', 'M32', 'M33', 'M35', 'RDB', 'S', 'SI', 'SIR', 'SIS', 'SNR', 'SR', 'T', 'TA', 'TAC', 'TI', 'TIM', 'TST0', 'TST1', 'TST2', 'TST3', 'UPD', 'USTB', 'Z', 'ZI']\n", - "2026-03-30 16:33:55,558 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: M21 0 0\n", - "2026-03-30 16:33:55,560 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'M21 0 0\\r\\n'\n", - "2026-03-30 16:33:55,587 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M21 A\\r\\n'\n", - "2026-03-30 16:33:55,588 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'M21 A\\r\\n'\n" - ] - } - ], - "source": [ - "# Update port for your system\n", - "backend = MettlerToledoWXS205SDUBackend(\n", - " port=\"/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0\"\n", - ")\n", - "scale = Scale(name=\"validation_scale\", backend=backend, size_x=0, size_y=0, size_z=0)\n", - "\n", - "await scale.setup()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Verify setup populated device identity" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Device type: WXS205SDU WXA-Bridge\n", - "Serial number: B207696838\n", - "Capacity: 220.009 g\n", - "Supported commands (62): ['@', 'C0', 'C1', 'C2', 'C3', 'COM', 'DAT', 'FCUT', 'FSET', 'I0', 'I1', 'I10', 'I11', 'I14', 'I15', 'I16', 'I2', 'I21', 'I22', 'I23', 'I24', 'I25', 'I26', 'I3', 'I4', 'I5', 'LST', 'M01', 'M02', 'M03', 'M17', 'M18', 'M19', 'M20', 'M21', 'M27', 'M28', 'M29', 'M31', 'M32', 'M33', 'M35', 'RDB', 'S', 'SI', 'SIR', 'SIS', 'SNR', 'SR', 'T', 'TA', 'TAC', 'TI', 'TIM', 'TST0', 'TST1', 'TST2', 'TST3', 'UPD', 'USTB', 'Z', 'ZI']\n", - "PASS: setup populated all identity fields\n" - ] - } - ], - "source": [ - "print(f\"Device type: {backend.device_type}\")\n", - "print(f\"Serial number: {backend.serial_number}\")\n", - "print(f\"Capacity: {backend.capacity} g\")\n", - "print(\n", - " f\"Supported commands ({len(backend._supported_commands)}): {sorted(backend._supported_commands)}\"\n", - ")\n", - "\n", - "assert backend.device_type is not None\n", - "assert backend.serial_number is not None\n", - "assert backend.capacity > 0\n", - "assert \"S\" in backend._supported_commands\n", - "print(\"PASS: setup populated all identity fields\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Supported Python methods on this device" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "65 methods available on this device:\n", - " cancel_all\n", - " clear_tare\n", - " deserialize\n", - " get_all_instances\n", - " get_weight\n", - " measure_temperature\n", - " read_dynamic_weight\n", - " read_stable_weight\n", - " read_stable_weight_repeat_on_change\n", - " read_weight\n", - " read_weight_value_immediately\n", - " request_adjustment_history\n", - " request_adjustment_setting\n", - " request_adjustment_weight\n", - " request_assortment_type_revision\n", - " request_auto_zero\n", - " request_capacity\n", - " request_date\n", - " request_device_id\n", - " request_device_info\n", - " request_device_type\n", - " request_environment_condition\n", - " request_filter_cutoff\n", - " request_firmware_version\n", - " request_model_designation\n", - " request_net_weight_with_status\n", - " request_next_service_date\n", - " request_operating_mode\n", - " request_operating_mode_after_restart\n", - " request_profact_day\n", - " request_profact_temperature_criterion\n", - " request_profact_time\n", - " request_profact_time_criteria\n", - " request_readability\n", - " request_serial_number\n", - " request_serial_parameters\n", - " request_software_material_number\n", - " request_stability_criteria\n", - " request_supported_methods\n", - " request_tare_weight\n", - " request_test_settings\n", - " request_test_weight\n", - " request_time\n", - " request_update_rate\n", - " request_uptime_minutes\n", - " request_user_settings\n", - " request_weighing_mode\n", - " request_weighing_value_release\n", - " request_zeroing_mode\n", - " reset\n", - " send_command\n", - " serialize\n", - " set_display_text\n", - " set_host_unit_grams\n", - " set_weight_display\n", - " setup\n", - " stop\n", - " tare\n", - " tare_immediately\n", - " tare_stable\n", - " tare_timeout\n", - " zero\n", - " zero_immediately\n", - " zero_stable\n", - " zero_timeout\n" - ] - } - ], - "source": [ - "methods = backend.request_supported_methods()\n", - "print(f\"{len(methods)} methods available on this device:\")\n", - "for m in methods:\n", - " print(f\" {m}\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### I0 - Discover all implemented commands\n", - "\n", - "This tells us exactly which MT-SICS commands this specific device supports,\n", - "resolving whether SC, C, D are truly unsupported or just miscategorized by level." - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2026-03-30 16:33:55,649 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: I0\n", - "2026-03-30 16:33:55,652 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I0\\r\\n'\n", - "2026-03-30 16:33:55,684 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I0\"\\r\\n'\n", - "2026-03-30 16:33:55,686 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 0 \"I0\"\\r\\n'\n", - "2026-03-30 16:33:55,700 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I1\"\\r\\n'\n", - "2026-03-30 16:33:55,703 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 0 \"I1\"\\r\\n'\n", - "2026-03-30 16:33:55,716 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I2\"\\r\\n'\n", - "2026-03-30 16:33:55,721 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 0 \"I2\"\\r\\n'\n", - "2026-03-30 16:33:55,727 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I3\"\\r\\n'\n", - "2026-03-30 16:33:55,729 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 0 \"I3\"\\r\\n'\n", - "2026-03-30 16:33:55,732 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I4\"\\r\\n'\n", - "2026-03-30 16:33:55,734 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 0 \"I4\"\\r\\n'\n", - "2026-03-30 16:33:55,752 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"I5\"\\r\\n'\n", - "2026-03-30 16:33:55,755 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 0 \"I5\"\\r\\n'\n", - "2026-03-30 16:33:55,764 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"S\"\\r\\n'\n", - "2026-03-30 16:33:55,765 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 0 \"S\"\\r\\n'\n", - "2026-03-30 16:33:55,779 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"SI\"\\r\\n'\n", - "2026-03-30 16:33:55,780 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 0 \"SI\"\\r\\n'\n", - "2026-03-30 16:33:55,796 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"SIR\"\\r\\n'\n", - "2026-03-30 16:33:55,798 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 0 \"SIR\"\\r\\n'\n", - "2026-03-30 16:33:55,800 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"Z\"\\r\\n'\n", - "2026-03-30 16:33:55,802 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 0 \"Z\"\\r\\n'\n", - "2026-03-30 16:33:55,812 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"ZI\"\\r\\n'\n", - "2026-03-30 16:33:55,814 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 0 \"ZI\"\\r\\n'\n", - "2026-03-30 16:33:55,828 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 0 \"@\"\\r\\n'\n", - "2026-03-30 16:33:55,829 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 0 \"@\"\\r\\n'\n", - "2026-03-30 16:33:55,843 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"SR\"\\r\\n'\n", - "2026-03-30 16:33:55,844 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 1 \"SR\"\\r\\n'\n", - "2026-03-30 16:33:55,860 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"T\"\\r\\n'\n", - "2026-03-30 16:33:55,861 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 1 \"T\"\\r\\n'\n", - "2026-03-30 16:33:55,875 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"TA\"\\r\\n'\n", - "2026-03-30 16:33:55,876 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 1 \"TA\"\\r\\n'\n", - "2026-03-30 16:33:55,891 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"TAC\"\\r\\n'\n", - "2026-03-30 16:33:55,892 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 1 \"TAC\"\\r\\n'\n", - "2026-03-30 16:33:55,894 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 1 \"TI\"\\r\\n'\n", - "2026-03-30 16:33:55,895 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 1 \"TI\"\\r\\n'\n", - "2026-03-30 16:33:55,908 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C0\"\\r\\n'\n", - "2026-03-30 16:33:55,908 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"C0\"\\r\\n'\n", - "2026-03-30 16:33:55,923 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C1\"\\r\\n'\n", - "2026-03-30 16:33:55,924 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"C1\"\\r\\n'\n", - "2026-03-30 16:33:55,939 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C2\"\\r\\n'\n", - "2026-03-30 16:33:55,940 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"C2\"\\r\\n'\n", - "2026-03-30 16:33:55,955 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"C3\"\\r\\n'\n", - "2026-03-30 16:33:55,956 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"C3\"\\r\\n'\n", - "2026-03-30 16:33:55,972 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"COM\"\\r\\n'\n", - "2026-03-30 16:33:55,972 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"COM\"\\r\\n'\n", - "2026-03-30 16:33:55,987 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"DAT\"\\r\\n'\n", - "2026-03-30 16:33:55,988 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"DAT\"\\r\\n'\n", - "2026-03-30 16:33:55,989 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I10\"\\r\\n'\n", - "2026-03-30 16:33:55,990 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"I10\"\\r\\n'\n", - "2026-03-30 16:33:56,003 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I11\"\\r\\n'\n", - "2026-03-30 16:33:56,004 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"I11\"\\r\\n'\n", - "2026-03-30 16:33:56,019 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I14\"\\r\\n'\n", - "2026-03-30 16:33:56,020 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"I14\"\\r\\n'\n", - "2026-03-30 16:33:56,035 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I15\"\\r\\n'\n", - "2026-03-30 16:33:56,036 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"I15\"\\r\\n'\n", - "2026-03-30 16:33:56,051 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I16\"\\r\\n'\n", - "2026-03-30 16:33:56,052 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"I16\"\\r\\n'\n", - "2026-03-30 16:33:56,067 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I21\"\\r\\n'\n", - "2026-03-30 16:33:56,068 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"I21\"\\r\\n'\n", - "2026-03-30 16:33:56,084 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I22\"\\r\\n'\n", - "2026-03-30 16:33:56,084 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"I22\"\\r\\n'\n", - "2026-03-30 16:33:56,099 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I23\"\\r\\n'\n", - "2026-03-30 16:33:56,100 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"I23\"\\r\\n'\n", - "2026-03-30 16:33:56,115 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I24\"\\r\\n'\n", - "2026-03-30 16:33:56,116 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"I24\"\\r\\n'\n", - "2026-03-30 16:33:56,131 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I25\"\\r\\n'\n", - "2026-03-30 16:33:56,132 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"I25\"\\r\\n'\n", - "2026-03-30 16:33:56,147 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"I26\"\\r\\n'\n", - "2026-03-30 16:33:56,147 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"I26\"\\r\\n'\n", - "2026-03-30 16:33:56,163 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M01\"\\r\\n'\n", - "2026-03-30 16:33:56,164 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"M01\"\\r\\n'\n", - "2026-03-30 16:33:56,165 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M02\"\\r\\n'\n", - "2026-03-30 16:33:56,165 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"M02\"\\r\\n'\n", - "2026-03-30 16:33:56,179 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M03\"\\r\\n'\n", - "2026-03-30 16:33:56,180 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"M03\"\\r\\n'\n", - "2026-03-30 16:33:56,196 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M17\"\\r\\n'\n", - "2026-03-30 16:33:56,196 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"M17\"\\r\\n'\n", - "2026-03-30 16:33:56,211 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M18\"\\r\\n'\n", - "2026-03-30 16:33:56,211 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"M18\"\\r\\n'\n", - "2026-03-30 16:33:56,227 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M19\"\\r\\n'\n", - "2026-03-30 16:33:56,228 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"M19\"\\r\\n'\n", - "2026-03-30 16:33:56,243 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M20\"\\r\\n'\n", - "2026-03-30 16:33:56,244 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"M20\"\\r\\n'\n", - "2026-03-30 16:33:56,259 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M21\"\\r\\n'\n", - "2026-03-30 16:33:56,259 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"M21\"\\r\\n'\n", - "2026-03-30 16:33:56,275 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M27\"\\r\\n'\n", - "2026-03-30 16:33:56,276 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"M27\"\\r\\n'\n", - "2026-03-30 16:33:56,291 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M28\"\\r\\n'\n", - "2026-03-30 16:33:56,292 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"M28\"\\r\\n'\n", - "2026-03-30 16:33:56,311 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M29\"\\r\\n'\n", - "2026-03-30 16:33:56,312 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"M29\"\\r\\n'\n", - "2026-03-30 16:33:56,323 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M31\"\\r\\n'\n", - "2026-03-30 16:33:56,328 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"M31\"\\r\\n'\n", - "2026-03-30 16:33:56,331 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M32\"\\r\\n'\n", - "2026-03-30 16:33:56,334 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"M32\"\\r\\n'\n", - "2026-03-30 16:33:56,339 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M33\"\\r\\n'\n", - "2026-03-30 16:33:56,344 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"M33\"\\r\\n'\n", - "2026-03-30 16:33:56,355 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"M35\"\\r\\n'\n", - "2026-03-30 16:33:56,357 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"M35\"\\r\\n'\n", - "2026-03-30 16:33:56,371 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"SIS\"\\r\\n'\n", - "2026-03-30 16:33:56,374 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"SIS\"\\r\\n'\n", - "2026-03-30 16:33:56,387 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"SNR\"\\r\\n'\n", - "2026-03-30 16:33:56,389 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"SNR\"\\r\\n'\n", - "2026-03-30 16:33:56,403 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TIM\"\\r\\n'\n", - "2026-03-30 16:33:56,404 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"TIM\"\\r\\n'\n", - "2026-03-30 16:33:56,419 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST0\"\\r\\n'\n", - "2026-03-30 16:33:56,420 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"TST0\"\\r\\n'\n", - "2026-03-30 16:33:56,435 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST1\"\\r\\n'\n", - "2026-03-30 16:33:56,436 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"TST1\"\\r\\n'\n", - "2026-03-30 16:33:56,451 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST2\"\\r\\n'\n", - "2026-03-30 16:33:56,452 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"TST2\"\\r\\n'\n", - "2026-03-30 16:33:56,467 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"TST3\"\\r\\n'\n", - "2026-03-30 16:33:56,468 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"TST3\"\\r\\n'\n", - "2026-03-30 16:33:56,483 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 2 \"UPD\"\\r\\n'\n", - "2026-03-30 16:33:56,484 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 2 \"UPD\"\\r\\n'\n", - "2026-03-30 16:33:56,498 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"FCUT\"\\r\\n'\n", - "2026-03-30 16:33:56,499 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 3 \"FCUT\"\\r\\n'\n", - "2026-03-30 16:33:56,515 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"FSET\"\\r\\n'\n", - "2026-03-30 16:33:56,516 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 3 \"FSET\"\\r\\n'\n", - "2026-03-30 16:33:56,531 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"LST\"\\r\\n'\n", - "2026-03-30 16:33:56,532 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 3 \"LST\"\\r\\n'\n", - "2026-03-30 16:33:56,547 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 B 3 \"RDB\"\\r\\n'\n", - "2026-03-30 16:33:56,548 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 B 3 \"RDB\"\\r\\n'\n", - "2026-03-30 16:33:56,563 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I0 A 3 \"USTB\"\\r\\n'\n", - "2026-03-30 16:33:56,563 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I0 A 3 \"USTB\"\\r\\n'\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Total commands implemented: 62\n", - "\n", - "Level 0 (12 commands): @, I0, I1, I2, I3, I4, I5, S, SI, SIR, Z, ZI\n", - "Level 1 (5 commands): SR, T, TA, TAC, TI\n", - "Level 2 (40 commands): C0, C1, C2, C3, COM, DAT, I10, I11, I14, I15, I16, I21, I22, I23, I24, I25, I26, M01, M02, M03, M17, M18, M19, M20, M21, M27, M28, M29, M31, M32, M33, M35, SIS, SNR, TIM, TST0, TST1, TST2, TST3, UPD\n", - "Level 3 (5 commands): FCUT, FSET, LST, RDB, USTB\n" - ] - } - ], - "source": [ - "from collections import defaultdict\n", - "\n", - "# I0 is a multi-response command (B status for each command, A for the last)\n", - "responses = await backend.send_command(\"I0\")\n", - "\n", - "print(f\"Total commands implemented: {len(responses)}\")\n", - "print()\n", - "\n", - "# Group by level\n", - "by_level = defaultdict(list)\n", - "for resp in responses:\n", - " if len(resp.data) >= 2:\n", - " level = resp.data[0]\n", - " cmd_name = resp.data[1]\n", - " by_level[level].append(cmd_name)\n", - "\n", - "for level in sorted(by_level.keys()):\n", - " cmds = sorted(by_level[level])\n", - " print(f\"Level {level} ({len(cmds)} commands): {', '.join(cmds)}\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Device identity and diagnostics (Batch 1)\n", - "\n", - "These commands complete the device identity picture beyond I2/I4." - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2026-03-30 16:33:56,576 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: I3\n", - "2026-03-30 16:33:56,579 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I3\\r\\n'\n", - "2026-03-30 16:33:56,630 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I3 A \"1.10 18.6.4.1361.772\"\\r\\n'\n", - "2026-03-30 16:33:56,636 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I3 A \"1.10 18.6.4.1361.772\"\\r\\n'\n", - "2026-03-30 16:33:56,639 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: I5\n", - "2026-03-30 16:33:56,643 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I5\\r\\n'\n", - "2026-03-30 16:33:56,675 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I5 A \"11671158C\"\\r\\n'\n", - "2026-03-30 16:33:56,676 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I5 A \"11671158C\"\\r\\n'\n", - "2026-03-30 16:33:56,680 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: I10\n", - "2026-03-30 16:33:56,688 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I10\\r\\n'\n", - "2026-03-30 16:33:56,723 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I10 A \"\"\\r\\n'\n", - "2026-03-30 16:33:56,727 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I10 A \"\"\\r\\n'\n", - "2026-03-30 16:33:56,728 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: I11\n", - "2026-03-30 16:33:56,737 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I11\\r\\n'\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Firmware version: 1.10 18.6.4.1361.772\n", - "Software material number: 11671158C\n", - "Device ID: ''\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2026-03-30 16:33:56,771 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I11 A \"WXS205SDU\"\\r\\n'\n", - "2026-03-30 16:33:56,772 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I11 A \"WXS205SDU\"\\r\\n'\n", - "2026-03-30 16:33:56,773 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: I15\n", - "2026-03-30 16:33:56,775 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I15\\r\\n'\n", - "2026-03-30 16:33:56,807 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I15 A 424\\r\\n'\n", - "2026-03-30 16:33:56,808 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I15 A 424\\r\\n'\n", - "2026-03-30 16:33:56,810 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: I16\n", - "2026-03-30 16:33:56,818 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I16\\r\\n'\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Model designation: WXS205SDU\n", - "Uptime: 424 minutes (7.1 hours)\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2026-03-30 16:33:57,298 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I16 A 16 03 2013\\r\\n'\n", - "2026-03-30 16:33:57,299 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I16 A 16 03 2013\\r\\n'\n", - "2026-03-30 16:33:57,301 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: I21\n", - "2026-03-30 16:33:57,303 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I21\\r\\n'\n", - "2026-03-30 16:33:57,330 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I21 A \"5\"\\r\\n'\n", - "2026-03-30 16:33:57,332 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I21 A \"5\"\\r\\n'\n", - "2026-03-30 16:33:57,335 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: I26\n", - "2026-03-30 16:33:57,339 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I26\\r\\n'\n", - "2026-03-30 16:33:57,363 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I26 A 0\\r\\n'\n", - "2026-03-30 16:33:57,364 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I26 A 0\\r\\n'\n", - "2026-03-30 16:33:57,366 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: DAT\n", - "2026-03-30 16:33:57,368 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'DAT\\r\\n'\n", - "2026-03-30 16:33:57,411 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'DAT A 04 01 2000\\r\\n'\n", - "2026-03-30 16:33:57,413 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'DAT A 04 01 2000\\r\\n'\n", - "2026-03-30 16:33:57,415 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: TIM\n", - "2026-03-30 16:33:57,417 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'TIM\\r\\n'\n", - "2026-03-30 16:33:57,459 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'TIM A 23 39 23\\r\\n'\n", - "2026-03-30 16:33:57,462 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'TIM A 23 39 23\\r\\n'\n", - "2026-03-30 16:33:57,466 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: I14 0\n", - "2026-03-30 16:33:57,471 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I14 0\\r\\n'\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Next service date: 16 03 2013\n", - "Assortment type revision: 5\n", - "I26: I26 A 0\n", - "Device date: 04\n", - "Device time: 23\n", - "\n", - "Device info (I14):\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2026-03-30 16:33:57,507 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I14 A 0 1 \"Bridge\"\\r\\n'\n", - "2026-03-30 16:33:57,512 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I14 A 0 1 \"Bridge\"\\r\\n'\n", - "2026-03-30 16:33:57,515 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: I14 1\n", - "2026-03-30 16:33:57,517 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I14 1\\r\\n'\n", - "2026-03-30 16:33:57,554 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I14 A 1 1 \"WXS205SDU\"\\r\\n'\n", - "2026-03-30 16:33:57,554 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I14 A 1 1 \"WXS205SDU\"\\r\\n'\n", - "2026-03-30 16:33:57,555 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: I14 2\n", - "2026-03-30 16:33:57,558 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I14 2\\r\\n'\n", - "2026-03-30 16:33:57,603 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I14 A 2 1 \"11671158C\"\\r\\n'\n", - "2026-03-30 16:33:57,604 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I14 A 2 1 \"11671158C\"\\r\\n'\n", - "2026-03-30 16:33:57,605 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: I14 3\n", - "2026-03-30 16:33:57,607 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I14 3\\r\\n'\n", - "2026-03-30 16:33:57,650 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I14 A 3 1 \"1.10\"\\r\\n'\n", - "2026-03-30 16:33:57,651 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I14 A 3 1 \"1.10\"\\r\\n'\n", - "2026-03-30 16:33:57,651 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: I14 4\n", - "2026-03-30 16:33:57,652 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I14 4\\r\\n'\n", - "2026-03-30 16:33:57,698 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I14 A 4 1 \"B207696838\"\\r\\n'\n", - "2026-03-30 16:33:57,698 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I14 A 4 1 \"B207696838\"\\r\\n'\n", - "2026-03-30 16:33:57,699 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: I14 5\n", - "2026-03-30 16:33:57,700 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I14 5\\r\\n'\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - " Category 0 (Instrument configuration):\n", - " I14 A 0 1 Bridge\n", - " Category 1 (Instrument descriptions):\n", - " I14 A 1 1 WXS205SDU\n", - " Category 2 (SW identification numbers):\n", - " I14 A 2 1 11671158C\n", - " Category 3 (SW versions):\n", - " I14 A 3 1 1.10\n", - " Category 4 (Serial numbers):\n", - " I14 A 4 1 B207696838\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2026-03-30 16:33:57,746 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I14 A 5 1 \"18.6.4.1361.772\"\\r\\n'\n", - "2026-03-30 16:33:57,747 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I14 A 5 1 \"18.6.4.1361.772\"\\r\\n'\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - " Category 5 (TDNR numbers):\n", - " I14 A 5 1 18.6.4.1361.772\n", - "\n", - "PASS: Batch 1 device identity commands completed\n" - ] - } - ], - "source": [ - "# I3 - Firmware version (Level 0, always available)\n", - "fw_version = await backend.request_firmware_version()\n", - "print(f\"Firmware version: {fw_version}\")\n", - "\n", - "# I5 - Software material number (Level 0, always available)\n", - "sw_material = await backend.request_software_material_number()\n", - "print(f\"Software material number: {sw_material}\")\n", - "\n", - "# I10 - Device ID (user-assignable name)\n", - "if \"I10\" in backend._supported_commands:\n", - " device_id = await backend.request_device_id()\n", - " print(f\"Device ID: '{device_id}'\")\n", - "else:\n", - " print(\"SKIP: I10 not supported\")\n", - "\n", - "# I11 - Model designation\n", - "if \"I11\" in backend._supported_commands:\n", - " model = await backend.request_model_designation()\n", - " print(f\"Model designation: {model}\")\n", - "else:\n", - " print(\"SKIP: I11 not supported\")\n", - "\n", - "# I15 - Uptime (minutes since start/restart)\n", - "if \"I15\" in backend._supported_commands:\n", - " uptime_min = await backend.request_uptime_minutes()\n", - " print(f\"Uptime: {uptime_min} minutes ({uptime_min / 60:.1f} hours)\")\n", - "else:\n", - " print(\"SKIP: I15 not supported\")\n", - "\n", - "# I16 - Next service date\n", - "if \"I16\" in backend._supported_commands:\n", - " service_date = await backend.request_next_service_date()\n", - " print(f\"Next service date: {service_date}\")\n", - "else:\n", - " print(\"SKIP: I16 not supported\")\n", - "\n", - "# I21 - Assortment type revision\n", - "if \"I21\" in backend._supported_commands:\n", - " revision = await backend.request_assortment_type_revision()\n", - " print(f\"Assortment type revision: {revision}\")\n", - "else:\n", - " print(\"SKIP: I21 not supported\")\n", - "\n", - "# I26 - Operating mode after restart\n", - "if \"I26\" in backend._supported_commands:\n", - " i26_resp = await backend.request_operating_mode_after_restart()\n", - " for resp in i26_resp:\n", - " print(f\"I26: {resp.command} {resp.status} {' '.join(resp.data)}\")\n", - "else:\n", - " print(\"SKIP: I26 not supported\")\n", - "\n", - "# DAT - Date\n", - "if \"DAT\" in backend._supported_commands:\n", - " date = await backend.request_date()\n", - " print(f\"Device date: {date}\")\n", - "else:\n", - " print(\"SKIP: DAT not supported\")\n", - "\n", - "# TIM - Time\n", - "if \"TIM\" in backend._supported_commands:\n", - " time_str = await backend.request_time()\n", - " print(f\"Device time: {time_str}\")\n", - "else:\n", - " print(\"SKIP: TIM not supported\")\n", - "\n", - "# I14 - Comprehensive device info (query each category separately)\n", - "if \"I14\" in backend._supported_commands:\n", - " category_names = {\n", - " 0: \"Instrument configuration\",\n", - " 1: \"Instrument descriptions\",\n", - " 2: \"SW identification numbers\",\n", - " 3: \"SW versions\",\n", - " 4: \"Serial numbers\",\n", - " 5: \"TDNR numbers\",\n", - " }\n", - " print(\"\\nDevice info (I14):\")\n", - " for cat, name in category_names.items():\n", - " try:\n", - " info = await backend.request_device_info(category=cat)\n", - " print(f\" Category {cat} ({name}):\")\n", - " for resp in info:\n", - " print(f\" {resp.command} {resp.status} {' '.join(resp.data)}\")\n", - " except Exception as e:\n", - " print(f\" Category {cat} ({name}): {e}\")\n", - "else:\n", - " print(\"SKIP: I14 not supported\")\n", - "\n", - "print(\"\\nPASS: Batch 1 device identity commands completed\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "---\n", - "## 2. Core Protocol Validation\n", - "\n", - "These Level 0/1 commands have been validated across multiple hardware runs.\n", - "This cell consolidates them into a single pass/fail check." - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2026-03-30 16:33:57,762 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] reset_input_buffer\n", - "2026-03-30 16:33:57,766 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: @\n", - "2026-03-30 16:33:57,770 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'@\\r\\n'\n", - "2026-03-30 16:33:57,827 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I4 A \"B207696838\"\\r\\n'\n", - "2026-03-30 16:33:57,828 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I4 A \"B207696838\"\\r\\n'\n", - "2026-03-30 16:33:57,829 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: I4\n", - "2026-03-30 16:33:57,833 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I4\\r\\n'\n", - "2026-03-30 16:33:57,874 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I4 A \"B207696838\"\\r\\n'\n", - "2026-03-30 16:33:57,875 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I4 A \"B207696838\"\\r\\n'\n", - "2026-03-30 16:33:57,876 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: I2\n", - "2026-03-30 16:33:57,878 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I2\\r\\n'\n", - "2026-03-30 16:33:57,937 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", - "2026-03-30 16:33:57,938 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", - "2026-03-30 16:33:57,938 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: I2\n", - "2026-03-30 16:33:57,940 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I2\\r\\n'\n", - "2026-03-30 16:33:58,001 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", - "2026-03-30 16:33:58,002 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I2 A \"WXS205SDU WXA-Bridge 220.00900 g\"\\r\\n'\n", - "2026-03-30 16:33:58,004 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: S\n", - "2026-03-30 16:33:58,005 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", - "2026-03-30 16:33:58,401 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00008 g\\r\\n'\n", - "2026-03-30 16:33:58,403 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'S S 0.00008 g\\r\\n'\n", - "2026-03-30 16:33:58,406 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: SI\n", - "2026-03-30 16:33:58,409 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", - "2026-03-30 16:33:58,449 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00008 g\\r\\n'\n", - "2026-03-30 16:33:58,449 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'S S 0.00008 g\\r\\n'\n", - "2026-03-30 16:33:58,450 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: Z\n", - "2026-03-30 16:33:58,452 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'Z\\r\\n'\n", - "2026-03-30 16:33:58,688 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'Z A\\r\\n'\n", - "2026-03-30 16:33:58,689 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'Z A\\r\\n'\n", - "2026-03-30 16:33:58,690 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: SI\n", - "2026-03-30 16:33:58,691 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", - "2026-03-30 16:33:58,721 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 16:33:58,722 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 16:33:58,722 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: ZI\n", - "2026-03-30 16:33:58,724 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'ZI\\r\\n'\n", - "2026-03-30 16:33:58,752 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'ZI S\\r\\n'\n", - "2026-03-30 16:33:58,753 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'ZI S\\r\\n'\n", - "2026-03-30 16:33:58,754 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: SI\n", - "2026-03-30 16:33:58,755 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", - "2026-03-30 16:33:58,785 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 16:33:58,786 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 16:33:58,786 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: TA\n", - "2026-03-30 16:33:58,788 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'TA\\r\\n'\n", - "2026-03-30 16:33:58,897 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'TA A 0.00000 g\\r\\n'\n", - "2026-03-30 16:33:58,897 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'TA A 0.00000 g\\r\\n'\n", - "2026-03-30 16:33:58,898 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: TAC\n", - "2026-03-30 16:33:58,899 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'TAC\\r\\n'\n", - "2026-03-30 16:33:58,928 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'TAC A\\r\\n'\n", - "2026-03-30 16:33:58,929 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'TAC A\\r\\n'\n", - "2026-03-30 16:33:58,930 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: TA\n", - "2026-03-30 16:33:58,931 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'TA\\r\\n'\n", - "2026-03-30 16:33:58,992 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'TA A 0.00000 g\\r\\n'\n", - "2026-03-30 16:33:58,993 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'TA A 0.00000 g\\r\\n'\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "PASS: all core Level 0/1 commands validated\n" - ] - } - ], - "source": [ - "# @ - Cancel (returns serial number)\n", - "sn = await backend.reset()\n", - "assert sn == backend.serial_number, f\"reset() returned {sn}, expected {backend.serial_number}\"\n", - "\n", - "# I4 - Serial number\n", - "sn2 = await backend.request_serial_number()\n", - "assert sn2 == sn\n", - "\n", - "# I2 - Device type and capacity\n", - "dt = await backend.request_device_type()\n", - "assert len(dt) > 0\n", - "cap = await backend.request_capacity()\n", - "assert cap > 0\n", - "\n", - "# S - Stable weight\n", - "w_stable = await backend.read_stable_weight()\n", - "assert isinstance(w_stable, float)\n", - "\n", - "# SI - Weight immediately\n", - "w_imm = await backend.read_weight_value_immediately()\n", - "assert isinstance(w_imm, float)\n", - "\n", - "# Z - Zero (stable) then read\n", - "await scale.zero(timeout=\"stable\")\n", - "w_after_zero = await backend.read_weight_value_immediately()\n", - "assert abs(w_after_zero) < 0.001, f\"Expected ~0 after zero, got {w_after_zero}\"\n", - "\n", - "# ZI - Zero immediately then read\n", - "await scale.zero(timeout=0)\n", - "w_after_zi = await backend.read_weight_value_immediately()\n", - "assert abs(w_after_zi) < 0.01\n", - "\n", - "# TA - Request tare weight\n", - "tare = await scale.request_tare_weight()\n", - "assert isinstance(tare, float)\n", - "\n", - "# TAC - Clear tare\n", - "await backend.clear_tare()\n", - "tare_after = await scale.request_tare_weight()\n", - "assert abs(tare_after) < 0.001\n", - "\n", - "print(\"PASS: all core Level 0/1 commands validated\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "---\n", - "## 3. Level 1 Commands (Elementary)\n", - "\n", - "**Place a known weight on the scale for tare tests.**" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### T - Tare (stable)" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": {}, - "outputs": [ - { - "name": "stdin", - "output_type": "stream", - "text": [ - "Place a container on the scale and press Enter... \n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2026-03-30 16:34:04,612 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: Z\n", - "2026-03-30 16:34:04,614 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'Z\\r\\n'\n", - "2026-03-30 16:34:04,988 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'Z A\\r\\n'\n", - "2026-03-30 16:34:04,988 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'Z A\\r\\n'\n", - "2026-03-30 16:34:04,989 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: T\n", - "2026-03-30 16:34:04,992 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'T\\r\\n'\n", - "2026-03-30 16:34:05,388 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'T S 0.00000 g\\r\\n'\n", - "2026-03-30 16:34:05,388 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'T S 0.00000 g\\r\\n'\n", - "2026-03-30 16:34:05,391 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: TA\n", - "2026-03-30 16:34:05,393 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'TA\\r\\n'\n", - "2026-03-30 16:34:05,483 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'TA A 0.00000 g\\r\\n'\n", - "2026-03-30 16:34:05,484 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'TA A 0.00000 g\\r\\n'\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Tare weight: 0.0 g\n" - ] - }, - { - "ename": "AssertionError", - "evalue": "Expected positive tare, got 0.0", - "output_type": "error", - "traceback": [ - "\u001b[31m---------------------------------------------------------------------------\u001b[39m", - "\u001b[31mAssertionError\u001b[39m Traceback (most recent call last)", - "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[8]\u001b[39m\u001b[32m, line 6\u001b[39m\n\u001b[32m 4\u001b[39m tare = \u001b[38;5;28;01mawait\u001b[39;00m scale.request_tare_weight()\n\u001b[32m 5\u001b[39m \u001b[38;5;28mprint\u001b[39m(\u001b[33mf\u001b[39m\u001b[33m\"\u001b[39m\u001b[33mTare weight: \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mtare\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m g\u001b[39m\u001b[33m\"\u001b[39m)\n\u001b[32m----> \u001b[39m\u001b[32m6\u001b[39m \u001b[38;5;28;01massert\u001b[39;00m tare > \u001b[32m0\u001b[39m, \u001b[33mf\u001b[39m\u001b[33m\"\u001b[39m\u001b[33mExpected positive tare, got \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mtare\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m\"\u001b[39m\n\u001b[32m 7\u001b[39m \u001b[38;5;28mprint\u001b[39m(\u001b[33m\"\u001b[39m\u001b[33mPASS: tare stores container weight\u001b[39m\u001b[33m\"\u001b[39m)\n", - "\u001b[31mAssertionError\u001b[39m: Expected positive tare, got 0.0" - ] - } - ], - "source": [ - "input(\"Place a container on the scale and press Enter...\")\n", - "await scale.zero(timeout=\"stable\")\n", - "await scale.tare(timeout=\"stable\")\n", - "tare = await scale.request_tare_weight()\n", - "print(f\"Tare weight: {tare} g\")\n", - "assert tare > 0, f\"Expected positive tare, got {tare}\"\n", - "print(\"PASS: tare stores container weight\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### TA - Request tare weight" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2026-03-30 16:34:12,398 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: TA\n", - "2026-03-30 16:34:12,401 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'TA\\r\\n'\n", - "2026-03-30 16:34:12,469 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'TA A 0.00000 g\\r\\n'\n", - "2026-03-30 16:34:12,472 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'TA A 0.00000 g\\r\\n'\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Tare weight from memory: 0.0 g\n", - "PASS: tare weight readable from memory\n" - ] - } - ], - "source": [ - "tare = await scale.request_tare_weight()\n", - "print(f\"Tare weight from memory: {tare} g\")\n", - "assert isinstance(tare, float)\n", - "print(\"PASS: tare weight readable from memory\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### TAC - Clear tare" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2026-03-30 16:34:13,336 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: TAC\n", - "2026-03-30 16:34:13,339 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'TAC\\r\\n'\n", - "2026-03-30 16:34:13,365 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'TAC A\\r\\n'\n", - "2026-03-30 16:34:13,367 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'TAC A\\r\\n'\n", - "2026-03-30 16:34:13,368 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: TA\n", - "2026-03-30 16:34:13,374 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'TA\\r\\n'\n", - "2026-03-30 16:34:13,445 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'TA A 0.00000 g\\r\\n'\n", - "2026-03-30 16:34:13,448 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'TA A 0.00000 g\\r\\n'\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Tare after clear: 0.0 g\n", - "PASS: clear tare resets tare to 0\n" - ] - } - ], - "source": [ - "await backend.clear_tare()\n", - "tare_after_clear = await scale.request_tare_weight()\n", - "print(f\"Tare after clear: {tare_after_clear} g\")\n", - "assert abs(tare_after_clear) < 0.001, f\"Expected ~0 after clear, got {tare_after_clear}\"\n", - "print(\"PASS: clear tare resets tare to 0\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "---\n", - "## 4. Level 2 Commands (Extended)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### M21 - Set host unit to grams" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2026-03-30 16:34:16,488 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: M21 0 0\n", - "2026-03-30 16:34:16,489 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'M21 0 0\\r\\n'\n", - "2026-03-30 16:34:16,529 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M21 A\\r\\n'\n", - "2026-03-30 16:34:16,530 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'M21 A\\r\\n'\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "PASS: host unit set to grams\n" - ] - } - ], - "source": [ - "if \"M21\" in backend._supported_commands:\n", - " await backend.set_host_unit_grams()\n", - " print(\"PASS: host unit set to grams\")\n", - "else:\n", - " print(\"SKIP: M21 not supported on this device\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### I50 - Remaining weighing range (multi-response)" - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "SKIP: I50 not supported on this device\n" - ] - } - ], - "source": [ - "if \"I50\" in backend._supported_commands:\n", - " remaining = await backend.request_remaining_weighing_range()\n", - " print(f\"Remaining weighing range: {remaining} g\")\n", - " assert remaining > 0\n", - " assert remaining <= backend.capacity\n", - " print(\"PASS: remaining range is positive and within capacity\")\n", - "else:\n", - " print(\"SKIP: I50 not supported on this device\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### M28 - Temperature sensor" - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2026-03-30 16:34:18,754 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: M28\n", - "2026-03-30 16:34:18,756 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'M28\\r\\n'\n", - "2026-03-30 16:34:18,800 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M28 B 1 19.5\\r\\n'\n", - "2026-03-30 16:34:18,804 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'M28 B 1 19.5\\r\\n'\n", - "2026-03-30 16:34:18,808 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M28 A 2 18.9\\r\\n'\n", - "2026-03-30 16:34:18,813 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'M28 A 2 18.9\\r\\n'\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Scale temperature: 19.5 C\n", - "PASS: measure_temperature works - I0 correctly predicted M28 support\n" - ] - } - ], - "source": [ - "if \"M28\" in backend._supported_commands:\n", - " temp = await backend.measure_temperature()\n", - " print(f\"Scale temperature: {temp} C\")\n", - " assert 5 < temp < 50, f\"Temperature {temp} C outside reasonable range\"\n", - " print(\"PASS: measure_temperature works - I0 correctly predicted M28 support\")\n", - "else:\n", - " print(\"SKIP: M28 not supported on this device\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Batch 2 - Configuration queries (read-only)\n", - "\n", - "These commands read device configuration without modifying anything." - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2026-03-30 16:34:20,135 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: M01\n", - "2026-03-30 16:34:20,137 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'M01\\r\\n'\n", - "2026-03-30 16:34:20,158 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M01 A 0\\r\\n'\n", - "2026-03-30 16:34:20,158 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'M01 A 0\\r\\n'\n", - "2026-03-30 16:34:20,161 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: M02\n", - "2026-03-30 16:34:20,162 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'M02\\r\\n'\n", - "2026-03-30 16:34:20,191 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M02 A 2\\r\\n'\n", - "2026-03-30 16:34:20,192 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'M02 A 2\\r\\n'\n", - "2026-03-30 16:34:20,193 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: M03\n", - "2026-03-30 16:34:20,196 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'M03\\r\\n'\n", - "2026-03-30 16:34:20,222 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M03 A 0\\r\\n'\n", - "2026-03-30 16:34:20,224 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'M03 A 0\\r\\n'\n", - "2026-03-30 16:34:20,225 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: M17\n", - "2026-03-30 16:34:20,230 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'M17\\r\\n'\n", - "2026-03-30 16:34:20,271 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M17 A 00 00 00 0\\r\\n'\n", - "2026-03-30 16:34:20,273 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'M17 A 00 00 00 0\\r\\n'\n", - "2026-03-30 16:34:20,275 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: M18\n", - "2026-03-30 16:34:20,278 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'M18\\r\\n'\n", - "2026-03-30 16:34:20,302 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M18 A 1\\r\\n'\n", - "2026-03-30 16:34:20,303 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'M18 A 1\\r\\n'\n", - "2026-03-30 16:34:20,305 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: M19\n", - "2026-03-30 16:34:20,309 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'M19\\r\\n'\n", - "2026-03-30 16:34:20,350 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M19 A 10.00000 g\\r\\n'\n", - "2026-03-30 16:34:20,351 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'M19 A 10.00000 g\\r\\n'\n", - "2026-03-30 16:34:20,352 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: M20\n", - "2026-03-30 16:34:20,356 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'M20\\r\\n'\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Weighing mode: 0 (Normal/Universal)\n", - "Environment condition: 2 (Standard)\n", - "Auto zero: 0 (off)\n", - "ProFACT time criteria: A 00 00 00 0\n", - "ProFACT temperature criterion: A 1\n", - "Adjustment weight: A 10.00000 g\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2026-03-30 16:34:20,398 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M20 A 200.00000 g\\r\\n'\n", - "2026-03-30 16:34:20,399 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'M20 A 200.00000 g\\r\\n'\n", - "2026-03-30 16:34:20,400 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: M27\n", - "2026-03-30 16:34:20,403 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'M27\\r\\n'\n", - "2026-03-30 16:34:20,461 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 1 13 05 2020 17 17 0 \"\"\\r\\n'\n", - "2026-03-30 16:34:20,462 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'M27 B 1 13 05 2020 17 17 0 \"\"\\r\\n'\n", - "2026-03-30 16:34:20,495 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 2 02 12 2019 20 02 0 \"\"\\r\\n'\n", - "2026-03-30 16:34:20,497 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'M27 B 2 02 12 2019 20 02 0 \"\"\\r\\n'\n", - "2026-03-30 16:34:20,526 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 3 11 10 2019 17 05 0 \"\"\\r\\n'\n", - "2026-03-30 16:34:20,527 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'M27 B 3 11 10 2019 17 05 0 \"\"\\r\\n'\n", - "2026-03-30 16:34:20,557 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 4 11 10 2019 17 01 0 \"\"\\r\\n'\n", - "2026-03-30 16:34:20,558 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'M27 B 4 11 10 2019 17 01 0 \"\"\\r\\n'\n", - "2026-03-30 16:34:20,589 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 5 14 03 2019 20 22 0 \"\"\\r\\n'\n", - "2026-03-30 16:34:20,589 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'M27 B 5 14 03 2019 20 22 0 \"\"\\r\\n'\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Test weight: A 200.00000 g\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2026-03-30 16:34:20,621 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 6 14 03 2019 20 18 0 \"\"\\r\\n'\n", - "2026-03-30 16:34:20,623 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'M27 B 6 14 03 2019 20 18 0 \"\"\\r\\n'\n", - "2026-03-30 16:34:20,653 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 7 17 10 2018 17 38 0 \"\"\\r\\n'\n", - "2026-03-30 16:34:20,654 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'M27 B 7 17 10 2018 17 38 0 \"\"\\r\\n'\n", - "2026-03-30 16:34:20,685 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 8 17 10 2018 17 37 0 \"\"\\r\\n'\n", - "2026-03-30 16:34:20,686 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'M27 B 8 17 10 2018 17 37 0 \"\"\\r\\n'\n", - "2026-03-30 16:34:20,717 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 9 17 10 2018 17 35 0 \"\"\\r\\n'\n", - "2026-03-30 16:34:20,718 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'M27 B 9 17 10 2018 17 35 0 \"\"\\r\\n'\n", - "2026-03-30 16:34:20,749 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 10 20 09 2018 21 23 0 \"\"\\r\\n'\n", - "2026-03-30 16:34:20,749 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'M27 B 10 20 09 2018 21 23 0 \"\"\\r\\n'\n", - "2026-03-30 16:34:20,781 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 11 15 03 2018 23 51 0 \"\"\\r\\n'\n", - "2026-03-30 16:34:20,782 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'M27 B 11 15 03 2018 23 51 0 \"\"\\r\\n'\n", - "2026-03-30 16:34:20,813 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 12 16 12 2017 00 20 0 \"\"\\r\\n'\n", - "2026-03-30 16:34:20,814 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'M27 B 12 16 12 2017 00 20 0 \"\"\\r\\n'\n", - "2026-03-30 16:34:20,845 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 13 16 12 2017 00 18 0 \"\"\\r\\n'\n", - "2026-03-30 16:34:20,846 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'M27 B 13 16 12 2017 00 18 0 \"\"\\r\\n'\n", - "2026-03-30 16:34:20,877 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 14 18 10 2017 12 06 0 \"\"\\r\\n'\n", - "2026-03-30 16:34:20,877 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'M27 B 14 18 10 2017 12 06 0 \"\"\\r\\n'\n", - "2026-03-30 16:34:20,924 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 15 18 10 2017 11 58 0 \"\"\\r\\n'\n", - "2026-03-30 16:34:20,925 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'M27 B 15 18 10 2017 11 58 0 \"\"\\r\\n'\n", - "2026-03-30 16:34:20,957 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 16 05 09 2017 22 40 0 \"\"\\r\\n'\n", - "2026-03-30 16:34:20,958 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'M27 B 16 05 09 2017 22 40 0 \"\"\\r\\n'\n", - "2026-03-30 16:34:20,988 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 17 21 06 2017 18 39 0 \"\"\\r\\n'\n", - "2026-03-30 16:34:20,989 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'M27 B 17 21 06 2017 18 39 0 \"\"\\r\\n'\n", - "2026-03-30 16:34:21,021 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 18 30 03 2017 19 24 0 \"\"\\r\\n'\n", - "2026-03-30 16:34:21,022 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'M27 B 18 30 03 2017 19 24 0 \"\"\\r\\n'\n", - "2026-03-30 16:34:21,053 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 19 09 03 2017 23 21 0 \"\"\\r\\n'\n", - "2026-03-30 16:34:21,053 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'M27 B 19 09 03 2017 23 21 0 \"\"\\r\\n'\n", - "2026-03-30 16:34:21,084 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 20 09 03 2017 23 19 0 \"\"\\r\\n'\n", - "2026-03-30 16:34:21,085 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'M27 B 20 09 03 2017 23 19 0 \"\"\\r\\n'\n", - "2026-03-30 16:34:21,117 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 21 20 12 2016 21 55 0 \"\"\\r\\n'\n", - "2026-03-30 16:34:21,117 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'M27 B 21 20 12 2016 21 55 0 \"\"\\r\\n'\n", - "2026-03-30 16:34:21,148 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 22 19 10 2016 17 36 0 \"\"\\r\\n'\n", - "2026-03-30 16:34:21,149 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'M27 B 22 19 10 2016 17 36 0 \"\"\\r\\n'\n", - "2026-03-30 16:34:21,181 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 23 19 10 2016 17 33 0 \"\"\\r\\n'\n", - "2026-03-30 16:34:21,182 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'M27 B 23 19 10 2016 17 33 0 \"\"\\r\\n'\n", - "2026-03-30 16:34:21,212 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 24 18 10 2016 21 00 0 \"\"\\r\\n'\n", - "2026-03-30 16:34:21,214 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'M27 B 24 18 10 2016 21 00 0 \"\"\\r\\n'\n", - "2026-03-30 16:34:21,245 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 25 18 10 2016 18 47 0 \"\"\\r\\n'\n", - "2026-03-30 16:34:21,246 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'M27 B 25 18 10 2016 18 47 0 \"\"\\r\\n'\n", - "2026-03-30 16:34:21,293 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 26 18 10 2016 15 33 0 \"\"\\r\\n'\n", - "2026-03-30 16:34:21,293 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'M27 B 26 18 10 2016 15 33 0 \"\"\\r\\n'\n", - "2026-03-30 16:34:21,324 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 27 18 10 2016 14 32 0 \"\"\\r\\n'\n", - "2026-03-30 16:34:21,325 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'M27 B 27 18 10 2016 14 32 0 \"\"\\r\\n'\n", - "2026-03-30 16:34:21,357 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 28 18 10 2016 14 28 0 \"\"\\r\\n'\n", - "2026-03-30 16:34:21,357 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'M27 B 28 18 10 2016 14 28 0 \"\"\\r\\n'\n", - "2026-03-30 16:34:21,388 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 29 18 10 2016 13 41 0 \"\"\\r\\n'\n", - "2026-03-30 16:34:21,389 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'M27 B 29 18 10 2016 13 41 0 \"\"\\r\\n'\n", - "2026-03-30 16:34:21,422 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 30 21 09 2016 15 15 0 \"\"\\r\\n'\n", - "2026-03-30 16:34:21,423 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'M27 B 30 21 09 2016 15 15 0 \"\"\\r\\n'\n", - "2026-03-30 16:34:21,452 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 31 04 03 2016 22 28 0 \"\"\\r\\n'\n", - "2026-03-30 16:34:21,453 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'M27 B 31 04 03 2016 22 28 0 \"\"\\r\\n'\n", - "2026-03-30 16:34:21,484 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 32 01 10 2015 19 06 0 \"\"\\r\\n'\n", - "2026-03-30 16:34:21,485 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'M27 B 32 01 10 2015 19 06 0 \"\"\\r\\n'\n", - "2026-03-30 16:34:21,517 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 33 01 10 2015 18 56 0 \"\"\\r\\n'\n", - "2026-03-30 16:34:21,517 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'M27 B 33 01 10 2015 18 56 0 \"\"\\r\\n'\n", - "2026-03-30 16:34:21,548 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 34 03 09 2015 22 11 0 \"\"\\r\\n'\n", - "2026-03-30 16:34:21,549 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'M27 B 34 03 09 2015 22 11 0 \"\"\\r\\n'\n", - "2026-03-30 16:34:21,581 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 35 11 03 2015 13 20 0 \"\"\\r\\n'\n", - "2026-03-30 16:34:21,581 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'M27 B 35 11 03 2015 13 20 0 \"\"\\r\\n'\n", - "2026-03-30 16:34:21,612 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 36 11 03 2015 13 18 0 \"\"\\r\\n'\n", - "2026-03-30 16:34:21,613 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'M27 B 36 11 03 2015 13 18 0 \"\"\\r\\n'\n", - "2026-03-30 16:34:21,644 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 37 11 03 2015 13 15 0 \"\"\\r\\n'\n", - "2026-03-30 16:34:21,644 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'M27 B 37 11 03 2015 13 15 0 \"\"\\r\\n'\n", - "2026-03-30 16:34:21,691 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 38 11 03 2015 13 13 0 \"\"\\r\\n'\n", - "2026-03-30 16:34:21,692 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'M27 B 38 11 03 2015 13 13 0 \"\"\\r\\n'\n", - "2026-03-30 16:34:21,724 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 39 22 01 2015 03 17 0 \"\"\\r\\n'\n", - "2026-03-30 16:34:21,725 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'M27 B 39 22 01 2015 03 17 0 \"\"\\r\\n'\n", - "2026-03-30 16:34:21,755 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 40 22 01 2015 03 15 0 \"\"\\r\\n'\n", - "2026-03-30 16:34:21,756 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'M27 B 40 22 01 2015 03 15 0 \"\"\\r\\n'\n", - "2026-03-30 16:34:21,788 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 41 06 11 2014 17 08 0 \"\"\\r\\n'\n", - "2026-03-30 16:34:21,789 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'M27 B 41 06 11 2014 17 08 0 \"\"\\r\\n'\n", - "2026-03-30 16:34:21,823 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 42 06 11 2014 16 22 0 \"\"\\r\\n'\n", - "2026-03-30 16:34:21,824 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'M27 B 42 06 11 2014 16 22 0 \"\"\\r\\n'\n", - "2026-03-30 16:34:21,852 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 43 06 11 2014 16 20 0 \"\"\\r\\n'\n", - "2026-03-30 16:34:21,853 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'M27 B 43 06 11 2014 16 20 0 \"\"\\r\\n'\n", - "2026-03-30 16:34:21,884 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 44 06 11 2014 15 57 0 \"\"\\r\\n'\n", - "2026-03-30 16:34:21,885 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'M27 B 44 06 11 2014 15 57 0 \"\"\\r\\n'\n", - "2026-03-30 16:34:21,915 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 45 18 09 2014 20 23 0 \"\"\\r\\n'\n", - "2026-03-30 16:34:21,916 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'M27 B 45 18 09 2014 20 23 0 \"\"\\r\\n'\n", - "2026-03-30 16:34:21,948 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 46 18 09 2014 19 54 0 \"\"\\r\\n'\n", - "2026-03-30 16:34:21,949 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'M27 B 46 18 09 2014 19 54 0 \"\"\\r\\n'\n", - "2026-03-30 16:34:21,980 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 47 18 09 2014 19 44 0 \"\"\\r\\n'\n", - "2026-03-30 16:34:21,980 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'M27 B 47 18 09 2014 19 44 0 \"\"\\r\\n'\n", - "2026-03-30 16:34:22,012 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 48 18 09 2014 19 35 0 \"\"\\r\\n'\n", - "2026-03-30 16:34:22,013 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'M27 B 48 18 09 2014 19 35 0 \"\"\\r\\n'\n", - "2026-03-30 16:34:22,044 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 B 49 15 09 2014 20 08 0 \"\"\\r\\n'\n", - "2026-03-30 16:34:22,044 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'M27 B 49 15 09 2014 20 08 0 \"\"\\r\\n'\n", - "2026-03-30 16:34:22,091 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M27 A 50 15 09 2014 19 39 0 \"\"\\r\\n'\n", - "2026-03-30 16:34:22,092 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'M27 A 50 15 09 2014 19 39 0 \"\"\\r\\n'\n", - "2026-03-30 16:34:22,094 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: M29\n", - "2026-03-30 16:34:22,095 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'M29\\r\\n'\n", - "2026-03-30 16:34:22,124 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M29 A 1\\r\\n'\n", - "2026-03-30 16:34:22,125 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'M29 A 1\\r\\n'\n", - "2026-03-30 16:34:22,126 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: M31\n", - "2026-03-30 16:34:22,127 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'M31\\r\\n'\n", - "2026-03-30 16:34:22,156 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M31 A 0\\r\\n'\n", - "2026-03-30 16:34:22,156 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'M31 A 0\\r\\n'\n", - "2026-03-30 16:34:22,158 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: M32\n", - "2026-03-30 16:34:22,159 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'M32\\r\\n'\n", - "2026-03-30 16:34:22,188 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M32 B 1 00 00 0\\r\\n'\n", - "2026-03-30 16:34:22,189 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'M32 B 1 00 00 0\\r\\n'\n", - "2026-03-30 16:34:22,220 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M32 B 2 00 00 0\\r\\n'\n", - "2026-03-30 16:34:22,221 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'M32 B 2 00 00 0\\r\\n'\n", - "2026-03-30 16:34:22,236 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M32 A 3 00 00 0\\r\\n'\n", - "2026-03-30 16:34:22,237 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'M32 A 3 00 00 0\\r\\n'\n", - "2026-03-30 16:34:22,238 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: M33\n", - "2026-03-30 16:34:22,240 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'M33\\r\\n'\n", - "2026-03-30 16:34:22,268 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M33 A 0\\r\\n'\n", - "2026-03-30 16:34:22,268 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'M33 A 0\\r\\n'\n", - "2026-03-30 16:34:22,269 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: M35\n", - "2026-03-30 16:34:22,271 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'M35\\r\\n'\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "Adjustment history (50 entries):\n", - " M27 B 1 13 05 2020 17 17 0 \n", - " M27 B 2 02 12 2019 20 02 0 \n", - " M27 B 3 11 10 2019 17 05 0 \n", - " M27 B 4 11 10 2019 17 01 0 \n", - " M27 B 5 14 03 2019 20 22 0 \n", - " M27 B 6 14 03 2019 20 18 0 \n", - " M27 B 7 17 10 2018 17 38 0 \n", - " M27 B 8 17 10 2018 17 37 0 \n", - " M27 B 9 17 10 2018 17 35 0 \n", - " M27 B 10 20 09 2018 21 23 0 \n", - " M27 B 11 15 03 2018 23 51 0 \n", - " M27 B 12 16 12 2017 00 20 0 \n", - " M27 B 13 16 12 2017 00 18 0 \n", - " M27 B 14 18 10 2017 12 06 0 \n", - " M27 B 15 18 10 2017 11 58 0 \n", - " M27 B 16 05 09 2017 22 40 0 \n", - " M27 B 17 21 06 2017 18 39 0 \n", - " M27 B 18 30 03 2017 19 24 0 \n", - " M27 B 19 09 03 2017 23 21 0 \n", - " M27 B 20 09 03 2017 23 19 0 \n", - " M27 B 21 20 12 2016 21 55 0 \n", - " M27 B 22 19 10 2016 17 36 0 \n", - " M27 B 23 19 10 2016 17 33 0 \n", - " M27 B 24 18 10 2016 21 00 0 \n", - " M27 B 25 18 10 2016 18 47 0 \n", - " M27 B 26 18 10 2016 15 33 0 \n", - " M27 B 27 18 10 2016 14 32 0 \n", - " M27 B 28 18 10 2016 14 28 0 \n", - " M27 B 29 18 10 2016 13 41 0 \n", - " M27 B 30 21 09 2016 15 15 0 \n", - " M27 B 31 04 03 2016 22 28 0 \n", - " M27 B 32 01 10 2015 19 06 0 \n", - " M27 B 33 01 10 2015 18 56 0 \n", - " M27 B 34 03 09 2015 22 11 0 \n", - " M27 B 35 11 03 2015 13 20 0 \n", - " M27 B 36 11 03 2015 13 18 0 \n", - " M27 B 37 11 03 2015 13 15 0 \n", - " M27 B 38 11 03 2015 13 13 0 \n", - " M27 B 39 22 01 2015 03 17 0 \n", - " M27 B 40 22 01 2015 03 15 0 \n", - " M27 B 41 06 11 2014 17 08 0 \n", - " M27 B 42 06 11 2014 16 22 0 \n", - " M27 B 43 06 11 2014 16 20 0 \n", - " M27 B 44 06 11 2014 15 57 0 \n", - " M27 B 45 18 09 2014 20 23 0 \n", - " M27 B 46 18 09 2014 19 54 0 \n", - " M27 B 47 18 09 2014 19 44 0 \n", - " M27 B 48 18 09 2014 19 35 0 \n", - " M27 B 49 15 09 2014 20 08 0 \n", - " M27 A 50 15 09 2014 19 39 0 \n", - "Weighing value release: A 1\n", - "Operating mode: A 0\n", - "ProFACT time: B 1 00 00 0\n", - "ProFACT day: A 0\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2026-03-30 16:34:22,300 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M35 A 0\\r\\n'\n", - "2026-03-30 16:34:22,301 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'M35 A 0\\r\\n'\n", - "2026-03-30 16:34:22,302 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: UPD\n", - "2026-03-30 16:34:22,304 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'UPD\\r\\n'\n", - "2026-03-30 16:34:22,348 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'UPD A 10.173\\r\\n'\n", - "2026-03-30 16:34:22,349 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'UPD A 10.173\\r\\n'\n", - "2026-03-30 16:34:22,355 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: SIS\n", - "2026-03-30 16:34:22,357 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SIS\\r\\n'\n", - "2026-03-30 16:34:22,411 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'SIS A 0 \"0.00000\" 0 5 1 0 0\\r\\n'\n", - "2026-03-30 16:34:22,415 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'SIS A 0 \"0.00000\" 0 5 1 0 0\\r\\n'\n", - "2026-03-30 16:34:22,420 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: C0\n", - "2026-03-30 16:34:22,423 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'C0\\r\\n'\n", - "2026-03-30 16:34:22,460 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'C0 A 0 0 \"\"\\r\\n'\n", - "2026-03-30 16:34:22,461 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'C0 A 0 0 \"\"\\r\\n'\n", - "2026-03-30 16:34:22,463 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: COM\n", - "2026-03-30 16:34:22,465 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'COM\\r\\n'\n", - "2026-03-30 16:34:22,492 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'COM A 0 6 3 1\\r\\n'\n", - "2026-03-30 16:34:22,495 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'COM A 0 6 3 1\\r\\n'\n", - "2026-03-30 16:34:22,496 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: FCUT\n", - "2026-03-30 16:34:22,502 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'FCUT\\r\\n'\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Zeroing mode: A 0\n", - "\n", - "Update rate: 10.173 values/s\n", - "Net weight with status: SIS A 0 0.00000 0 5 1 0 0\n", - "Adjustment setting: A 0 0 \n", - "Serial parameters: A 0 6 3 1\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2026-03-30 16:34:22,540 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'FCUT A 0.000\\r\\n'\n", - "2026-03-30 16:34:22,541 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'FCUT A 0.000\\r\\n'\n", - "2026-03-30 16:34:22,543 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: LST\n", - "2026-03-30 16:34:22,545 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'LST\\r\\n'\n", - "2026-03-30 16:34:22,588 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B C0 0 0 \"\"\\r\\n'\n", - "2026-03-30 16:34:22,589 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'LST B C0 0 0 \"\"\\r\\n'\n", - "2026-03-30 16:34:22,604 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B FCUT 0.000\\r\\n'\n", - "2026-03-30 16:34:22,605 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'LST B FCUT 0.000\\r\\n'\n", - "2026-03-30 16:34:22,619 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B I10 \"\"\\r\\n'\n", - "2026-03-30 16:34:22,620 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'LST B I10 \"\"\\r\\n'\n", - "2026-03-30 16:34:22,639 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B M01 0\\r\\n'\n", - "2026-03-30 16:34:22,640 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'LST B M01 0\\r\\n'\n", - "2026-03-30 16:34:22,652 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B M02 2\\r\\n'\n", - "2026-03-30 16:34:22,654 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'LST B M02 2\\r\\n'\n", - "2026-03-30 16:34:22,667 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B M03 0\\r\\n'\n", - "2026-03-30 16:34:22,669 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'LST B M03 0\\r\\n'\n", - "2026-03-30 16:34:22,684 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B M17 00 00 00 0\\r\\n'\n", - "2026-03-30 16:34:22,685 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'LST B M17 00 00 00 0\\r\\n'\n", - "2026-03-30 16:34:22,700 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B M18 1\\r\\n'\n", - "2026-03-30 16:34:22,702 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'LST B M18 1\\r\\n'\n", - "2026-03-30 16:34:22,716 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B M19 10.00000 g\\r\\n'\n", - "2026-03-30 16:34:22,717 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'LST B M19 10.00000 g\\r\\n'\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Filter cut-off: A 0.000\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2026-03-30 16:34:22,747 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B M20 200.00000 g\\r\\n'\n", - "2026-03-30 16:34:22,748 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'LST B M20 200.00000 g\\r\\n'\n", - "2026-03-30 16:34:22,767 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B M21 0 0\\r\\n'\n", - "2026-03-30 16:34:22,768 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'LST B M21 0 0\\r\\n'\n", - "2026-03-30 16:34:22,779 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B M29 1\\r\\n'\n", - "2026-03-30 16:34:22,782 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'LST B M29 1\\r\\n'\n", - "2026-03-30 16:34:22,796 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B M31 0\\r\\n'\n", - "2026-03-30 16:34:22,798 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'LST B M31 0\\r\\n'\n", - "2026-03-30 16:34:22,812 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B M32 1 00 00 0\\r\\n'\n", - "2026-03-30 16:34:22,813 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'LST B M32 1 00 00 0\\r\\n'\n", - "2026-03-30 16:34:22,827 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B M32 2 00 00 0\\r\\n'\n", - "2026-03-30 16:34:22,829 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'LST B M32 2 00 00 0\\r\\n'\n", - "2026-03-30 16:34:22,859 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B M32 3 00 00 0\\r\\n'\n", - "2026-03-30 16:34:22,860 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'LST B M32 3 00 00 0\\r\\n'\n", - "2026-03-30 16:34:22,863 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B M33 0\\r\\n'\n", - "2026-03-30 16:34:22,865 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'LST B M33 0\\r\\n'\n", - "2026-03-30 16:34:22,875 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B M35 0\\r\\n'\n", - "2026-03-30 16:34:22,876 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'LST B M35 0\\r\\n'\n", - "2026-03-30 16:34:22,892 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B RDB 5\\r\\n'\n", - "2026-03-30 16:34:22,899 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'LST B RDB 5\\r\\n'\n", - "2026-03-30 16:34:22,907 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B TST0 0 \"\"\\r\\n'\n", - "2026-03-30 16:34:22,910 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'LST B TST0 0 \"\"\\r\\n'\n", - "2026-03-30 16:34:22,924 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B UPD 10.173\\r\\n'\n", - "2026-03-30 16:34:22,925 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'LST B UPD 10.173\\r\\n'\n", - "2026-03-30 16:34:22,955 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B USTB 0 3.600 1.100\\r\\n'\n", - "2026-03-30 16:34:22,957 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'LST B USTB 0 3.600 1.100\\r\\n'\n", - "2026-03-30 16:34:22,987 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST B USTB 1 0.000 0.000\\r\\n'\n", - "2026-03-30 16:34:22,988 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'LST B USTB 1 0.000 0.000\\r\\n'\n", - "2026-03-30 16:34:23,003 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'LST A USTB 2 0.000 0.000\\r\\n'\n", - "2026-03-30 16:34:23,005 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'LST A USTB 2 0.000 0.000\\r\\n'\n", - "2026-03-30 16:34:23,008 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: RDB\n", - "2026-03-30 16:34:23,012 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'RDB\\r\\n'\n", - "2026-03-30 16:34:23,051 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'RDB A 5\\r\\n'\n", - "2026-03-30 16:34:23,053 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'RDB A 5\\r\\n'\n", - "2026-03-30 16:34:23,054 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: USTB\n", - "2026-03-30 16:34:23,057 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'USTB\\r\\n'\n", - "2026-03-30 16:34:23,101 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'USTB B 0 3.600 1.100\\r\\n'\n", - "2026-03-30 16:34:23,104 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'USTB B 0 3.600 1.100\\r\\n'\n", - "2026-03-30 16:34:23,131 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'USTB B 1 0.000 0.000\\r\\n'\n", - "2026-03-30 16:34:23,136 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'USTB B 1 0.000 0.000\\r\\n'\n", - "2026-03-30 16:34:23,147 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'USTB A 2 0.000 0.000\\r\\n'\n", - "2026-03-30 16:34:23,150 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'USTB A 2 0.000 0.000\\r\\n'\n", - "2026-03-30 16:34:23,158 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: TST0\n", - "2026-03-30 16:34:23,161 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'TST0\\r\\n'\n", - "2026-03-30 16:34:23,195 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'TST0 A 0 \"\"\\r\\n'\n", - "2026-03-30 16:34:23,202 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'TST0 A 0 \"\"\\r\\n'\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "Current user settings (24 lines):\n", - " LST B C0 0 0 \n", - " LST B FCUT 0.000\n", - " LST B I10 \n", - " LST B M01 0\n", - " LST B M02 2\n", - " LST B M03 0\n", - " LST B M17 00 00 00 0\n", - " LST B M18 1\n", - " LST B M19 10.00000 g\n", - " LST B M20 200.00000 g\n", - " ... (24 lines total)\n", - "Readability: A 5\n", - "Stability criteria: B 0 3.600 1.100\n", - "Test settings: A 0 \n", - "\n", - "PASS: All read-only configuration queries completed\n" - ] - } - ], - "source": [ - "# M01 - Weighing mode\n", - "if \"M01\" in backend._supported_commands:\n", - " mode = await backend.request_weighing_mode()\n", - " mode_names = {\n", - " 0: \"Normal/Universal\",\n", - " 1: \"Dosing\",\n", - " 2: \"Sensor\",\n", - " 3: \"Check weighing\",\n", - " 6: \"Raw/No filter\",\n", - " }\n", - " print(f\"Weighing mode: {mode} ({mode_names.get(mode, 'unknown')})\")\n", - "else:\n", - " print(\"SKIP: M01 not supported\")\n", - "\n", - "# M02 - Environment condition\n", - "if \"M02\" in backend._supported_commands:\n", - " env = await backend.request_environment_condition()\n", - " env_names = {\n", - " 0: \"Very stable\",\n", - " 1: \"Stable\",\n", - " 2: \"Standard\",\n", - " 3: \"Unstable\",\n", - " 4: \"Very unstable\",\n", - " 5: \"Automatic\",\n", - " }\n", - " print(f\"Environment condition: {env} ({env_names.get(env, 'unknown')})\")\n", - "else:\n", - " print(\"SKIP: M02 not supported\")\n", - "\n", - "# M03 - Auto zero\n", - "if \"M03\" in backend._supported_commands:\n", - " auto_zero = await backend.request_auto_zero()\n", - " print(f\"Auto zero: {auto_zero} ({'on' if auto_zero else 'off'})\")\n", - "else:\n", - " print(\"SKIP: M03 not supported\")\n", - "\n", - "# M17 - ProFACT time criteria\n", - "if \"M17\" in backend._supported_commands:\n", - " resp = await backend.request_profact_time_criteria()\n", - " print(f\"ProFACT time criteria: {resp[0].status} {' '.join(resp[0].data)}\")\n", - "else:\n", - " print(\"SKIP: M17 not supported\")\n", - "\n", - "# M18 - ProFACT temperature criterion\n", - "if \"M18\" in backend._supported_commands:\n", - " resp = await backend.request_profact_temperature_criterion()\n", - " print(f\"ProFACT temperature criterion: {resp[0].status} {' '.join(resp[0].data)}\")\n", - "else:\n", - " print(\"SKIP: M18 not supported\")\n", - "\n", - "# M19 - Adjustment weight\n", - "if \"M19\" in backend._supported_commands:\n", - " resp = await backend.request_adjustment_weight()\n", - " print(f\"Adjustment weight: {resp[0].status} {' '.join(resp[0].data)}\")\n", - "else:\n", - " print(\"SKIP: M19 not supported\")\n", - "\n", - "# M20 - Test weight\n", - "if \"M20\" in backend._supported_commands:\n", - " resp = await backend.request_test_weight()\n", - " print(f\"Test weight: {resp[0].status} {' '.join(resp[0].data)}\")\n", - "else:\n", - " print(\"SKIP: M20 not supported\")\n", - "\n", - "# M27 - Adjustment history\n", - "if \"M27\" in backend._supported_commands:\n", - " history = await backend.request_adjustment_history()\n", - " print(f\"\\nAdjustment history ({len(history)} entries):\")\n", - " for resp in history:\n", - " print(f\" {resp.command} {resp.status} {' '.join(resp.data)}\")\n", - "else:\n", - " print(\"SKIP: M27 not supported\")\n", - "\n", - "# M29 - Weighing value release\n", - "if \"M29\" in backend._supported_commands:\n", - " resp = await backend.request_weighing_value_release()\n", - " print(f\"Weighing value release: {resp[0].status} {' '.join(resp[0].data)}\")\n", - "else:\n", - " print(\"SKIP: M29 not supported\")\n", - "\n", - "# M31 - Operating mode\n", - "if \"M31\" in backend._supported_commands:\n", - " resp = await backend.request_operating_mode()\n", - " print(f\"Operating mode: {resp[0].status} {' '.join(resp[0].data)}\")\n", - "else:\n", - " print(\"SKIP: M31 not supported\")\n", - "\n", - "# M32 - ProFACT time\n", - "if \"M32\" in backend._supported_commands:\n", - " resp = await backend.request_profact_time()\n", - " print(f\"ProFACT time: {resp[0].status} {' '.join(resp[0].data)}\")\n", - "else:\n", - " print(\"SKIP: M32 not supported\")\n", - "\n", - "# M33 - ProFACT day\n", - "if \"M33\" in backend._supported_commands:\n", - " resp = await backend.request_profact_day()\n", - " print(f\"ProFACT day: {resp[0].status} {' '.join(resp[0].data)}\")\n", - "else:\n", - " print(\"SKIP: M33 not supported\")\n", - "\n", - "# M35 - Zeroing mode\n", - "if \"M35\" in backend._supported_commands:\n", - " resp = await backend.request_zeroing_mode()\n", - " print(f\"Zeroing mode: {resp[0].status} {' '.join(resp[0].data)}\")\n", - "else:\n", - " print(\"SKIP: M35 not supported\")\n", - "\n", - "# UPD - Update rate\n", - "if \"UPD\" in backend._supported_commands:\n", - " rate = await backend.request_update_rate()\n", - " print(f\"\\nUpdate rate: {rate} values/s\")\n", - "else:\n", - " print(\"SKIP: UPD not supported\")\n", - "\n", - "# SIS - Net weight with status\n", - "if \"SIS\" in backend._supported_commands:\n", - " sis_resp = await backend.request_net_weight_with_status()\n", - " print(f\"Net weight with status: {sis_resp.command} {sis_resp.status} {' '.join(sis_resp.data)}\")\n", - "else:\n", - " print(\"SKIP: SIS not supported\")\n", - "\n", - "# C0 - Adjustment setting\n", - "if \"C0\" in backend._supported_commands:\n", - " resp = await backend.request_adjustment_setting()\n", - " print(f\"Adjustment setting: {resp[0].status} {' '.join(resp[0].data)}\")\n", - "else:\n", - " print(\"SKIP: C0 not supported\")\n", - "\n", - "# COM - Serial parameters\n", - "if \"COM\" in backend._supported_commands:\n", - " resp = await backend.request_serial_parameters()\n", - " print(f\"Serial parameters: {resp[0].status} {' '.join(resp[0].data)}\")\n", - "else:\n", - " print(\"SKIP: COM not supported\")\n", - "\n", - "# FCUT - Filter cut-off frequency\n", - "if \"FCUT\" in backend._supported_commands:\n", - " resp = await backend.request_filter_cutoff()\n", - " print(f\"Filter cut-off: {resp[0].status} {' '.join(resp[0].data)}\")\n", - "else:\n", - " print(\"SKIP: FCUT not supported\")\n", - "\n", - "# LST - Current user settings\n", - "if \"LST\" in backend._supported_commands:\n", - " lst_responses = await backend.request_user_settings()\n", - " print(f\"\\nCurrent user settings ({len(lst_responses)} lines):\")\n", - " for resp in lst_responses[:10]:\n", - " print(f\" {resp.command} {resp.status} {' '.join(resp.data)}\")\n", - " if len(lst_responses) > 10:\n", - " print(f\" ... ({len(lst_responses)} lines total)\")\n", - "else:\n", - " print(\"SKIP: LST not supported\")\n", - "\n", - "# RDB - Readability\n", - "if \"RDB\" in backend._supported_commands:\n", - " resp = await backend.request_readability()\n", - " print(f\"Readability: {resp[0].status} {' '.join(resp[0].data)}\")\n", - "else:\n", - " print(\"SKIP: RDB not supported\")\n", - "\n", - "# USTB - Stability criteria\n", - "if \"USTB\" in backend._supported_commands:\n", - " resp = await backend.request_stability_criteria()\n", - " print(f\"Stability criteria: {resp[0].status} {' '.join(resp[0].data)}\")\n", - "else:\n", - " print(\"SKIP: USTB not supported\")\n", - "\n", - "# TST0 - Test settings\n", - "if \"TST0\" in backend._supported_commands:\n", - " resp = await backend.request_test_settings()\n", - " print(f\"Test settings: {resp[0].status} {' '.join(resp[0].data)}\")\n", - "else:\n", - " print(\"SKIP: TST0 not supported\")\n", - "\n", - "print(\"\\nPASS: All read-only configuration queries completed\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### SIS unit code verification (exploratory)\n\nTests whether field data[2] in the SIS response is the unit code by temporarily\nchanging the host unit via M21, reading SIS, then restoring grams.\n\n**WARNING:** Temporarily writes a non-gram unit to device memory via M21.\nIf the cell fails mid-execution, run `await backend.set_host_unit_grams()`\nmanually to restore grams. setup() also restores grams on next connection." - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2026-03-30 16:34:35,694 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: SIS\n", - "2026-03-30 16:34:35,697 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SIS\\r\\n'\n", - "2026-03-30 16:34:35,743 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'SIS A 0 \"0.00000\" 0 5 1 0 0\\r\\n'\n", - "2026-03-30 16:34:35,744 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'SIS A 0 \"0.00000\" 0 5 1 0 0\\r\\n'\n", - "2026-03-30 16:34:35,745 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: M21 1 0\n", - "2026-03-30 16:34:35,748 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'M21 1 0\\r\\n'\n", - "2026-03-30 16:34:35,779 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M21 L\\r\\n'\n", - "2026-03-30 16:34:35,781 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'M21 L\\r\\n'\n", - "2026-03-30 16:34:35,783 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: M21 0 0\n", - "2026-03-30 16:34:35,787 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'M21 0 0\\r\\n'\n", - "2026-03-30 16:34:35,827 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'M21 A\\r\\n'\n", - "2026-03-30 16:34:35,830 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'M21 A\\r\\n'\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "SIS in grams: ['0', '0.00000', '0', '5', '1', '0', '0']\n", - "\n", - "Restored host unit to grams\n" - ] - }, - { - "ename": "MettlerToledoError", - "evalue": "Command understood but not executable: (incorrect parameter).", - "output_type": "error", - "traceback": [ - "\u001b[31m---------------------------------------------------------------------------\u001b[39m", - "\u001b[31mMettlerToledoError\u001b[39m Traceback (most recent call last)", - "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[15]\u001b[39m\u001b[32m, line 7\u001b[39m\n\u001b[32m 5\u001b[39m \u001b[38;5;66;03m# Temporarily set unit to milligrams (M21 1 0 = mg host unit)\u001b[39;00m\n\u001b[32m 6\u001b[39m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[32m----> \u001b[39m\u001b[32m7\u001b[39m \u001b[38;5;28;01mawait\u001b[39;00m backend.send_command(\u001b[33m\"\u001b[39m\u001b[33mM21 1 0\u001b[39m\u001b[33m\"\u001b[39m)\n\u001b[32m 8\u001b[39m sis_mg = \u001b[38;5;28;01mawait\u001b[39;00m backend.request_net_weight_with_status()\n\u001b[32m 9\u001b[39m \u001b[38;5;28mprint\u001b[39m(\u001b[33mf\u001b[39m\u001b[33m\"\u001b[39m\u001b[33mSIS in milligrams: \u001b[39m\u001b[38;5;132;01m{\u001b[39;00msis_mg.data\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m\"\u001b[39m)\n", - "\u001b[36mFile \u001b[39m\u001b[32m~/Desktop/GitHub/pylabrobot/pylabrobot/scales/mettler_toledo/backend.py:358\u001b[39m, in \u001b[36mMettlerToledoWXS205SDUBackend.send_command\u001b[39m\u001b[34m(self, command, timeout)\u001b[39m\n\u001b[32m 356\u001b[39m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[32m 357\u001b[39m response = MettlerToledoResponse(command=\u001b[33m\"\u001b[39m\u001b[33m\"\u001b[39m, status=\u001b[33m\"\u001b[39m\u001b[33m\"\u001b[39m, data=[])\n\u001b[32m--> \u001b[39m\u001b[32m358\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[43m.\u001b[49m\u001b[43m_parse_basic_errors\u001b[49m\u001b[43m(\u001b[49m\u001b[43mresponse\u001b[49m\u001b[43m)\u001b[49m\n\u001b[32m 359\u001b[39m responses.append(response)\n\u001b[32m 361\u001b[39m \u001b[38;5;66;03m# Status B means more responses follow; anything else (A, etc.) is final\u001b[39;00m\n", - "\u001b[36mFile \u001b[39m\u001b[32m~/Desktop/GitHub/pylabrobot/pylabrobot/scales/mettler_toledo/backend.py:285\u001b[39m, in \u001b[36mMettlerToledoWXS205SDUBackend._parse_basic_errors\u001b[39m\u001b[34m(self, response)\u001b[39m\n\u001b[32m 283\u001b[39m \u001b[38;5;28;01mraise\u001b[39;00m MettlerToledoError.executing_another_command()\n\u001b[32m 284\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m response.status == \u001b[33m\"\u001b[39m\u001b[33mL\u001b[39m\u001b[33m\"\u001b[39m:\n\u001b[32m--> \u001b[39m\u001b[32m285\u001b[39m \u001b[38;5;28;01mraise\u001b[39;00m MettlerToledoError.incorrect_parameter()\n\u001b[32m 286\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m response.status == \u001b[33m\"\u001b[39m\u001b[33m+\u001b[39m\u001b[33m\"\u001b[39m:\n\u001b[32m 287\u001b[39m \u001b[38;5;28;01mraise\u001b[39;00m MettlerToledoError.overload()\n", - "\u001b[31mMettlerToledoError\u001b[39m: Command understood but not executable: (incorrect parameter)." - ] - } - ], - "source": [ - "# Read SIS in grams (current state)\n", - "sis_grams = await backend.request_net_weight_with_status()\n", - "print(f\"SIS in grams: {sis_grams.data}\")\n", - "\n", - "# Temporarily set unit to milligrams (M21 1 0 = mg host unit)\n", - "try:\n", - " await backend.send_command(\"M21 1 0\")\n", - " sis_mg = await backend.request_net_weight_with_status()\n", - " print(f\"SIS in milligrams: {sis_mg.data}\")\n", - "\n", - " # Compare the unit code field (data[2] per SIS spec)\n", - " if len(sis_grams.data) > 2 and len(sis_mg.data) > 2:\n", - " print(f\"\\nUnit code in grams mode: {sis_grams.data[2]}\")\n", - " print(f\"Unit code in mg mode: {sis_mg.data[2]}\")\n", - " if sis_grams.data[2] != sis_mg.data[2]:\n", - " print(\"PASS: unit code changes with M21 - confirms data[2] is unit identifier\")\n", - " else:\n", - " print(\"INFO: unit code did not change - field may not be the unit identifier\")\n", - " else:\n", - " print(\"INFO: SIS response too short to compare unit codes\")\n", - "\n", - "finally:\n", - " # Always restore grams\n", - " await backend.set_host_unit_grams()\n", - " print(\"\\nRestored host unit to grams\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "---\n", - "## 5. Frontend Integration\n", - "\n", - "Test the Scale frontend methods that delegate to the backend." - ] - }, - { - "cell_type": "code", - "execution_count": 16, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2026-03-30 16:34:46,597 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: Z\n", - "2026-03-30 16:34:46,599 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'Z\\r\\n'\n", - "2026-03-30 16:34:46,854 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'Z A\\r\\n'\n", - "2026-03-30 16:34:46,856 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'Z A\\r\\n'\n", - "2026-03-30 16:34:46,857 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: SI\n", - "2026-03-30 16:34:46,860 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", - "2026-03-30 16:34:46,903 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 16:34:46,904 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'S S 0.00000 g\\r\\n'\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Frontend zero + read: 0.0 g\n" - ] - }, - { - "name": "stdin", - "output_type": "stream", - "text": [ - "Place a container on the scale and press Enter... \n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2026-03-30 16:34:48,056 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: T\n", - "2026-03-30 16:34:48,060 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'T\\r\\n'\n", - "2026-03-30 16:34:48,453 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'T S 0.00000 g\\r\\n'\n", - "2026-03-30 16:34:48,454 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'T S 0.00000 g\\r\\n'\n", - "2026-03-30 16:34:48,455 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: TA\n", - "2026-03-30 16:34:48,456 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'TA\\r\\n'\n", - "2026-03-30 16:34:48,533 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'TA A 0.00000 g\\r\\n'\n", - "2026-03-30 16:34:48,533 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'TA A 0.00000 g\\r\\n'\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Frontend tare weight: 0.0 g\n" - ] - }, - { - "ename": "AssertionError", - "evalue": "", - "output_type": "error", - "traceback": [ - "\u001b[31m---------------------------------------------------------------------------\u001b[39m", - "\u001b[31mAssertionError\u001b[39m Traceback (most recent call last)", - "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[16]\u001b[39m\u001b[32m, line 12\u001b[39m\n\u001b[32m 10\u001b[39m tare = \u001b[38;5;28;01mawait\u001b[39;00m scale.request_tare_weight()\n\u001b[32m 11\u001b[39m \u001b[38;5;28mprint\u001b[39m(\u001b[33mf\u001b[39m\u001b[33m\"\u001b[39m\u001b[33mFrontend tare weight: \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mtare\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m g\u001b[39m\u001b[33m\"\u001b[39m)\n\u001b[32m---> \u001b[39m\u001b[32m12\u001b[39m \u001b[38;5;28;01massert\u001b[39;00m tare > \u001b[32m0\u001b[39m\n\u001b[32m 14\u001b[39m \u001b[38;5;66;03m# Read via frontend\u001b[39;00m\n\u001b[32m 15\u001b[39m w = \u001b[38;5;28;01mawait\u001b[39;00m scale.read_weight(timeout=\u001b[33m\"\u001b[39m\u001b[33mstable\u001b[39m\u001b[33m\"\u001b[39m)\n", - "\u001b[31mAssertionError\u001b[39m: " - ] - } - ], - "source": [ - "# Zero via frontend\n", - "await scale.zero(timeout=\"stable\")\n", - "w = await scale.read_weight(timeout=0)\n", - "print(f\"Frontend zero + read: {w} g\")\n", - "assert abs(w) < 0.001\n", - "\n", - "# Tare via frontend\n", - "input(\"Place a container on the scale and press Enter...\")\n", - "await scale.tare(timeout=\"stable\")\n", - "tare = await scale.request_tare_weight()\n", - "print(f\"Frontend tare weight: {tare} g\")\n", - "assert tare > 0\n", - "\n", - "# Read via frontend\n", - "w = await scale.read_weight(timeout=\"stable\")\n", - "print(f\"Frontend read (should be ~0 with container tared): {w} g\")\n", - "assert abs(w) < 0.1\n", - "\n", - "print(\"PASS: all frontend methods delegate correctly\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### I22-I25 - Undocumented information commands\n", - "\n", - "These commands appear in the I0 discovery but are not documented in the MT-SICS spec.\n", - "All I-commands are read-only queries, so these are safe to probe." - ] - }, - { - "cell_type": "code", - "execution_count": 17, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2026-03-30 16:34:53,926 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: I22\n", - "2026-03-30 16:34:53,932 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I22\\r\\n'\n", - "2026-03-30 16:34:54,319 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I22 B 0 0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 \"\"\\r\\n'\n", - "2026-03-30 16:34:54,320 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I22 B 0 0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 \"\"\\r\\n'\n", - "2026-03-30 16:34:54,400 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I22 B 1 0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 \"\"\\r\\n'\n", - "2026-03-30 16:34:54,401 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I22 B 1 0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 \"\"\\r\\n'\n", - "2026-03-30 16:34:54,480 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I22 B 2 0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 \"\"\\r\\n'\n", - "2026-03-30 16:34:54,481 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I22 B 2 0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 \"\"\\r\\n'\n", - "2026-03-30 16:34:54,544 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I22 B 3 0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 \"\"\\r\\n'\n", - "2026-03-30 16:34:54,548 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I22 B 3 0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 \"\"\\r\\n'\n", - "2026-03-30 16:34:54,623 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I22 A 4 0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 \"\"\\r\\n'\n", - "2026-03-30 16:34:54,624 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I22 A 4 0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 \"\"\\r\\n'\n", - "2026-03-30 16:34:54,627 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: I23\n", - "2026-03-30 16:34:54,628 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I23\\r\\n'\n", - "2026-03-30 16:34:54,723 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I23 B 0 0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 \"\"\\r\\n'\n", - "2026-03-30 16:34:54,725 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I23 B 0 0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 \"\"\\r\\n'\n", - "2026-03-30 16:34:54,800 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I23 B 1 0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 \"\"\\r\\n'\n", - "2026-03-30 16:34:54,802 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I23 B 1 0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 \"\"\\r\\n'\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "I22: status=B data=['0', '0.00000000E+00', '0.00000000E+00', '0.00000000E+00', '0.00000000E+00', '']\n", - "I22: status=B data=['1', '0.00000000E+00', '0.00000000E+00', '0.00000000E+00', '0.00000000E+00', '']\n", - "I22: status=B data=['2', '0.00000000E+00', '0.00000000E+00', '0.00000000E+00', '0.00000000E+00', '']\n", - "I22: status=B data=['3', '0.00000000E+00', '0.00000000E+00', '0.00000000E+00', '0.00000000E+00', '']\n", - "I22: status=A data=['4', '0.00000000E+00', '0.00000000E+00', '0.00000000E+00', '0.00000000E+00', '']\n", - "\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2026-03-30 16:34:54,879 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I23 B 2 0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 \"\"\\r\\n'\n", - "2026-03-30 16:34:54,881 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I23 B 2 0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 \"\"\\r\\n'\n", - "2026-03-30 16:34:54,944 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I23 B 3 0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 \"\"\\r\\n'\n", - "2026-03-30 16:34:54,956 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I23 B 3 0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 \"\"\\r\\n'\n", - "2026-03-30 16:34:55,025 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I23 A 4 0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 \"\"\\r\\n'\n", - "2026-03-30 16:34:55,028 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I23 A 4 0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 \"\"\\r\\n'\n", - "2026-03-30 16:34:55,034 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: I24\n", - "2026-03-30 16:34:55,042 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I24\\r\\n'\n", - "2026-03-30 16:34:55,135 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I24 B 0 0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 \"\"\\r\\n'\n", - "2026-03-30 16:34:55,136 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I24 B 0 0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 \"\"\\r\\n'\n", - "2026-03-30 16:34:55,215 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I24 B 1 0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 \"\"\\r\\n'\n", - "2026-03-30 16:34:55,216 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I24 B 1 0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 \"\"\\r\\n'\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "I23: status=B data=['0', '0.00000000E+00', '0.00000000E+00', '0.00000000E+00', '0.00000000E+00', '']\n", - "I23: status=B data=['1', '0.00000000E+00', '0.00000000E+00', '0.00000000E+00', '0.00000000E+00', '']\n", - "I23: status=B data=['2', '0.00000000E+00', '0.00000000E+00', '0.00000000E+00', '0.00000000E+00', '']\n", - "I23: status=B data=['3', '0.00000000E+00', '0.00000000E+00', '0.00000000E+00', '0.00000000E+00', '']\n", - "I23: status=A data=['4', '0.00000000E+00', '0.00000000E+00', '0.00000000E+00', '0.00000000E+00', '']\n", - "\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2026-03-30 16:34:55,279 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I24 B 2 0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 \"\"\\r\\n'\n", - "2026-03-30 16:34:55,280 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I24 B 2 0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 \"\"\\r\\n'\n", - "2026-03-30 16:34:55,360 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I24 B 3 0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 \"\"\\r\\n'\n", - "2026-03-30 16:34:55,360 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I24 B 3 0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 \"\"\\r\\n'\n", - "2026-03-30 16:34:55,439 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I24 A 4 0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 \"\"\\r\\n'\n", - "2026-03-30 16:34:55,440 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I24 A 4 0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 \"\"\\r\\n'\n", - "2026-03-30 16:34:55,441 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: I25\n", - "2026-03-30 16:34:55,442 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'I25\\r\\n'\n", - "2026-03-30 16:34:55,534 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I25 B 0 0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 \"\"\\r\\n'\n", - "2026-03-30 16:34:55,535 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I25 B 0 0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 \"\"\\r\\n'\n", - "2026-03-30 16:34:55,615 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I25 B 1 0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 \"\"\\r\\n'\n", - "2026-03-30 16:34:55,616 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I25 B 1 0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 \"\"\\r\\n'\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "I24: status=B data=['0', '0.00000000E+00', '0.00000000E+00', '0.00000000E+00', '0.00000000E+00', '']\n", - "I24: status=B data=['1', '0.00000000E+00', '0.00000000E+00', '0.00000000E+00', '0.00000000E+00', '']\n", - "I24: status=B data=['2', '0.00000000E+00', '0.00000000E+00', '0.00000000E+00', '0.00000000E+00', '']\n", - "I24: status=B data=['3', '0.00000000E+00', '0.00000000E+00', '0.00000000E+00', '0.00000000E+00', '']\n", - "I24: status=A data=['4', '0.00000000E+00', '0.00000000E+00', '0.00000000E+00', '0.00000000E+00', '']\n", - "\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2026-03-30 16:34:55,695 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I25 B 2 0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 \"\"\\r\\n'\n", - "2026-03-30 16:34:55,696 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I25 B 2 0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 \"\"\\r\\n'\n", - "2026-03-30 16:34:55,759 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I25 B 3 0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 \"\"\\r\\n'\n", - "2026-03-30 16:34:55,760 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I25 B 3 0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 \"\"\\r\\n'\n", - "2026-03-30 16:34:55,839 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I25 A 4 0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 \"\"\\r\\n'\n", - "2026-03-30 16:34:55,839 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I25 A 4 0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 \"\"\\r\\n'\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "I25: status=B data=['0', '0.00000000E+00', '0.00000000E+00', '0.00000000E+00', '0.00000000E+00', '']\n", - "I25: status=B data=['1', '0.00000000E+00', '0.00000000E+00', '0.00000000E+00', '0.00000000E+00', '']\n", - "I25: status=B data=['2', '0.00000000E+00', '0.00000000E+00', '0.00000000E+00', '0.00000000E+00', '']\n", - "I25: status=B data=['3', '0.00000000E+00', '0.00000000E+00', '0.00000000E+00', '0.00000000E+00', '']\n", - "I25: status=A data=['4', '0.00000000E+00', '0.00000000E+00', '0.00000000E+00', '0.00000000E+00', '']\n", - "\n" - ] - } - ], - "source": [ - "for cmd in [\"I22\", \"I23\", \"I24\", \"I25\"]:\n", - " try:\n", - " responses = await backend.send_command(cmd)\n", - " for r in responses:\n", - " print(f\"{cmd}: status={r.status} data={r.data}\")\n", - " except Exception as e:\n", - " print(f\"{cmd}: {type(e).__name__}: {e}\")\n", - " print()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "---\n", - "## 6. Performance" - ] - }, - { - "cell_type": "code", - "execution_count": 18, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2026-03-30 16:35:10,903 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: S\n", - "2026-03-30 16:35:10,904 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", - "2026-03-30 16:35:10,948 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 16:35:10,949 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 16:35:10,950 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: S\n", - "2026-03-30 16:35:10,954 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", - "2026-03-30 16:35:11,043 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 16:35:11,044 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 16:35:11,045 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: S\n", - "2026-03-30 16:35:11,051 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", - "2026-03-30 16:35:11,139 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 16:35:11,140 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 16:35:11,143 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: S\n", - "2026-03-30 16:35:11,146 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", - "2026-03-30 16:35:11,234 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 16:35:11,235 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 16:35:11,237 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: S\n", - "2026-03-30 16:35:11,239 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", - "2026-03-30 16:35:11,331 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 16:35:11,332 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 16:35:11,333 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: S\n", - "2026-03-30 16:35:11,334 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", - "2026-03-30 16:35:11,443 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 16:35:11,443 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 16:35:11,444 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: S\n", - "2026-03-30 16:35:11,446 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", - "2026-03-30 16:35:11,539 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 16:35:11,540 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 16:35:11,541 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: S\n", - "2026-03-30 16:35:11,543 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", - "2026-03-30 16:35:11,634 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 16:35:11,635 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 16:35:11,636 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: S\n", - "2026-03-30 16:35:11,637 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", - "2026-03-30 16:35:11,730 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 16:35:11,731 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 16:35:11,731 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: S\n", - "2026-03-30 16:35:11,733 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'S\\r\\n'\n", - "2026-03-30 16:35:11,826 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 16:35:11,827 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 16:35:11,828 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: SI\n", - "2026-03-30 16:35:11,829 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", - "2026-03-30 16:35:11,859 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 16:35:11,860 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 16:35:11,864 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: SI\n", - "2026-03-30 16:35:11,867 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", - "2026-03-30 16:35:11,907 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 16:35:11,908 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 16:35:11,911 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: SI\n", - "2026-03-30 16:35:11,912 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", - "2026-03-30 16:35:11,955 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 16:35:11,956 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 16:35:11,959 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: SI\n", - "2026-03-30 16:35:11,961 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", - "2026-03-30 16:35:12,003 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 16:35:12,004 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 16:35:12,004 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: SI\n", - "2026-03-30 16:35:12,007 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", - "2026-03-30 16:35:12,035 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 16:35:12,037 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 16:35:12,039 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: SI\n", - "2026-03-30 16:35:12,042 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", - "2026-03-30 16:35:12,082 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 16:35:12,083 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 16:35:12,084 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: SI\n", - "2026-03-30 16:35:12,085 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", - "2026-03-30 16:35:12,130 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 16:35:12,132 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 16:35:12,132 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: SI\n", - "2026-03-30 16:35:12,136 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", - "2026-03-30 16:35:12,187 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 16:35:12,189 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 16:35:12,190 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: SI\n", - "2026-03-30 16:35:12,196 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", - "2026-03-30 16:35:12,231 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 16:35:12,233 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 16:35:12,234 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: SI\n", - "2026-03-30 16:35:12,239 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'SI\\r\\n'\n", - "2026-03-30 16:35:12,274 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'S S 0.00000 g\\r\\n'\n", - "2026-03-30 16:35:12,276 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'S S 0.00000 g\\r\\n'\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Stable read: 92.43 +/- 15.88 ms\n", - "Immediate read: 44.97 +/- 6.03 ms\n" - ] - } - ], - "source": [ - "import time\n", - "\n", - "import numpy as np\n", - "\n", - "# Stable read latency\n", - "times_stable = []\n", - "for _ in range(10):\n", - " t0 = time.monotonic_ns()\n", - " await scale.read_weight(timeout=\"stable\")\n", - " t1 = time.monotonic_ns()\n", - " times_stable.append((t1 - t0) / 1e6)\n", - "\n", - "# Immediate read latency\n", - "times_immediate = []\n", - "for _ in range(10):\n", - " t0 = time.monotonic_ns()\n", - " await scale.read_weight(timeout=0)\n", - " t1 = time.monotonic_ns()\n", - " times_immediate.append((t1 - t0) / 1e6)\n", - "\n", - "print(f\"Stable read: {np.mean(times_stable):.2f} +/- {np.std(times_stable):.2f} ms\")\n", - "print(f\"Immediate read: {np.mean(times_immediate):.2f} +/- {np.std(times_immediate):.2f} ms\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "---\n", - "## 7. Teardown" - ] - }, - { - "cell_type": "code", - "execution_count": 19, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2026-03-30 16:35:13,600 - pylabrobot - INFO - === Hardware validation ended ===\n", - "2026-03-30 16:35:13,602 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] reset_input_buffer\n", - "2026-03-30 16:35:13,603 - pylabrobot - IO - [Mettler Toledo Scale] Sent command: @\n", - "2026-03-30 16:35:13,604 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] write b'@\\r\\n'\n", - "2026-03-30 16:35:13,665 - pylabrobot.io.serial - IO - [/dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0] readline b'I4 A \"B207696838\"\\r\\n'\n", - "2026-03-30 16:35:13,667 - pylabrobot - IO - [Mettler Toledo Scale] Received response: b'I4 A \"B207696838\"\\r\\n'\n", - "2026-03-30 16:35:13,668 - pylabrobot - INFO - [Mettler Toledo Scale] Disconnected from /dev/serial/by-id/usb-FTDI_UC232R_FT9NOXXH-if00-port0\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Log file: ./logs/hardware_validation/2026-03-30_16-33-54_validation.log\n" - ] - } - ], - "source": [ - "plr_logger.info(\"=== Hardware validation ended ===\")\n", - "await scale.stop()\n", - "print(f\"Log file: {log_file}\")" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "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.12.11" - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} \ No newline at end of file diff --git a/pylabrobot/scales/mettler_toledo/mt_sics_commands.md b/pylabrobot/scales/mettler_toledo/mt_sics_commands.md index 0ce9260bfa8..a4f2cb7b13d 100644 --- a/pylabrobot/scales/mettler_toledo/mt_sics_commands.md +++ b/pylabrobot/scales/mettler_toledo/mt_sics_commands.md @@ -36,7 +36,8 @@ Status key: | I5 | Software material number | 101 | DONE | yes | request_software_material_number(). Returns "11671158C" on test device. | | S | Stable weight value | 223 | DONE | yes | read_stable_weight(). | | SI | Weight value immediately | 225 | DONE | yes | read_weight_value_immediately(). | -| SIR | Weight immediately + repeat | 232 | MED | yes | Continuous streaming. | +| SIR | Weight immediately + repeat | 232 | MED | yes | Continuous streaming. Needs async iterator architecture. | +| SIRU | Weight immediately + repeat (display unit) | - | LOW | - | Streaming variant in display unit. | | Z | Zero (wait for stable) | 272 | DONE | yes | zero_stable(). | | ZI | Zero immediately | 274 | DONE | yes | zero_immediately(). | @@ -49,7 +50,7 @@ Status key: | DW | Show weight on display | 61 | DONE | **no** | set_weight_display(). Not supported in bridge mode. | | K | Keys control | 153 | LOW | - | Lock/unlock terminal keys. | | SC | Stable or dynamic value after timeout | 224 | DONE | **no** | read_dynamic_weight(). Not supported on WXS205SDU. | -| SR | Stable weight + repeat on any change | 245 | MED | yes | Continuous streaming. | +| SR | Stable weight + repeat on any change | 245 | MED | yes | Continuous streaming. Needs async iterator architecture. | | SRU | Stable weight + repeat (display unit) | 247 | LOW | - | | | T | Tare (wait for stable) | 252 | DONE | yes | tare_stable(). | | TA | Tare weight value (query/set) | 253 | DONE | yes | request_tare_weight(). | @@ -64,12 +65,14 @@ Status key: | Command | Description | Spec Page | Status | WXS205SDU | Notes | |---------|------------------------------------------|-----------|--------|-----------|-------| -| I10 | Device identification | 102 | DONE | yes | request_device_id() (read). set_device_id() commented out (EEPROM write). | +| I10 | Device identification | 102 | DONE | yes | request_device_id() and set_device_id(). Labels individual scales in multi-scale setups. | | I11 | Model designation | 103 | DONE | yes | request_model_designation(). Returns "WXS205SDU" on test device. | | I14 | Device information (detailed) | 104 | DONE | yes | request_device_info(). Multi-response with config, descriptions, SW IDs, serial numbers. | | I15 | Uptime in minutes since start/restart | 106 | DONE | yes | request_uptime_minutes(). Returns minutes, accuracy +/- 5%. | | I16 | Date of next service | 107 | DONE | yes | request_next_service_date(). | | I21 | Revision of assortment type tolerances | 108 | DONE | yes | request_assortment_type_revision(). | +| I26 | Operating mode after restart | - | DONE | yes | request_operating_mode_after_restart(). Not in spec but on WXS205SDU via I0. | +| I27 | Undocumented | - | LOW | - | In spec TOC but no documentation found. | | I29 | Filter configuration | 111 | LOW | - | | | I32 | Voltage monitoring | 112 | MED | - | | | I43 | Selectable units for host unit | 113 | LOW | - | | @@ -83,6 +86,7 @@ Status key: | I52 | Auto zero activation settings | 122 | LOW | - | | | I54 | Adjustment loads | 125 | LOW | - | | | I55 | Menu version | 126 | LOW | - | | +| I56 | Undocumented | - | LOW | - | In spec TOC but no documentation found. | | I59 | Initial zero information | 129 | LOW | - | | | I62 | Timeout setting | 131 | LOW | - | | | I65 | Total operating time | 132 | MED | - | | @@ -114,6 +118,7 @@ Status key: | M21 | Unit (host/display) | 165 | DONE | yes | set_host_unit_grams(). | | M23 | Readability (1d/xd) | 169 | LOW | - | | | M28 | Temperature value | 172 | DONE | yes | measure_temperature(). Returns 19.8-19.9 C on test device. | +| M29 | Weighing value release | - | DONE | yes | request_weighing_value_release() (read). set commented out (persists to memory). | | M35 | Zeroing mode at startup | 178 | DONE | yes | request_zeroing_mode() (read). set commented out (persists to memory). | | M49 | Permanent tare mode | 188 | LOW | - | | | M67 | Timeout | 191 | LOW | - | | @@ -138,6 +143,7 @@ Status key: | C8 | Sensitivity adjustment | 40 | LOW | - | | | C9 | Scale placement sensitivity adjustment | 43 | LOW | - | | | M19 | Adjustment weight | 163 | DONE | yes | request_adjustment_weight() (read). set commented out (persists to memory). | +| M20 | Test weight | - | DONE | yes | request_test_weight() (read). set commented out (persists to memory). | | M27 | Adjustment history | 171 | DONE | yes | request_adjustment_history(). Multi-response. | ### Testing @@ -265,14 +271,14 @@ Status key: ## Implementation Summary -The MT-SICS spec defines **157 commands** (counting F01-F16 as 16 individual commands). +The MT-SICS spec defines **194 commands** (counting F01-F16 as 16 individual commands). | Category | Count | Description | |----------|-------|-------------| | Backend (active) | 54 | Implemented and callable | -| Backend (commented out) | 28 | Set/write counterparts and physical interaction commands | +| Backend (commented out) | 27 | Set/write counterparts and physical interaction commands | | Simulator | 55 | Handled in `_build_response` (all active commands except I0/I1 internal) | -| Not implemented | 75 | Not available on WXS205SDU or not applicable | +| Not implemented | 113 | Not available on WXS205SDU or not applicable | ### WXS205SDU coverage @@ -287,7 +293,7 @@ The WXS205SDU reports **62 commands** via I0. Of these: ### Expanding to other devices -The remaining ~75 unimplemented spec commands (HIGH/MED/LOW/N/A in the table above) +The remaining ~113 unimplemented spec commands (HIGH/MED/LOW/N/A in the table above) are not available on the WXS205SDU and could not be validated. Integrating them requires a developer with physical access to a device that supports the command, to validate the response format and add a handler to both `backend.py` and diff --git a/pylabrobot/scales/mettler_toledo/protocol.md b/pylabrobot/scales/mettler_toledo/protocol.md index 88befda66c5..b9ccb00c0bf 100644 --- a/pylabrobot/scales/mettler_toledo/protocol.md +++ b/pylabrobot/scales/mettler_toledo/protocol.md @@ -113,8 +113,8 @@ The @ command resets the device to its power-on state and responds with the seri ### Commands not supported on WXS205SDU (bridge mode) The following commands return `ES` (syntax error) on the WXS205SDU WXA-Bridge -despite being listed in the MT-SICS spec. They may work on other MT-SICS devices -or on the same model with a terminal attached. +because they are not in the device's I0 command list. They may work on other +MT-SICS devices or on the same model with a terminal attached. - `C` (cancel all), `SC` (timed read), `ZC` (timed zero), `TC` (timed tare) - `D`, `DW` (display commands - no terminal in bridge mode) @@ -178,7 +178,14 @@ to memory and survive power cycles. They cannot be undone with @ reset - only via FSET (factory reset) or the terminal menu. Write methods are commented out in the backend to prevent accidental modification. -Exceptions: `set_date()` and `set_time()` are active (not commented out) since -they only set the internal clock, which is easily correctable. +Exceptions: `set_date()`, `set_time()`, and `set_device_id()` are active (not +commented out) since they do not change weighing behaviour. + +## Interrupt safety + +When a command is interrupted (KeyboardInterrupt or asyncio.CancelledError), +`send_command` sends `C` (cancel all) if the device supports it, otherwise just +flushes the serial buffer. Device state (zero, tare) is never cleared by an +interrupt. See the interrupt-safe command layer pattern. See `mt_sics_commands.md` for the full command reference with implementation status. From 9264b60235303ffaa150fff2076c2691a82abc07 Mon Sep 17 00:00:00 2001 From: Camillo Moschner Date: Mon, 30 Mar 2026 22:05:42 +0100 Subject: [PATCH 36/38] `make format` --- .../thermo_AB_96_plateadapter_MicroAmp.jpg | Bin 0 -> 25057 bytes docs/resources/library/thermo_fisher.md | 5 ++++ .../resources/thermo_fisher/__init__.py | 1 + .../resources/thermo_fisher/plate_adapters.py | 25 ++++++++++++++++++ pylabrobot/scales/mettler_toledo/backend.py | 8 ++---- pylabrobot/scales/mettler_toledo/simulator.py | 2 +- 6 files changed, 34 insertions(+), 7 deletions(-) create mode 100644 docs/resources/library/img/thermo_fisher/thermo_AB_96_plateadapter_MicroAmp.jpg create mode 100644 pylabrobot/resources/thermo_fisher/plate_adapters.py diff --git a/docs/resources/library/img/thermo_fisher/thermo_AB_96_plateadapter_MicroAmp.jpg b/docs/resources/library/img/thermo_fisher/thermo_AB_96_plateadapter_MicroAmp.jpg new file mode 100644 index 0000000000000000000000000000000000000000..9ee6cab58cfb3a3555b5ced6b1b72280a759b1b5 GIT binary patch literal 25057 zcmagGWmFwY(*R)2KMh70QNt4u-B*mZT!C!`bUD|=Qoc?|A(X> zX6iW}>5$JWuizb~Rrp^tqI2=BAHnFdeDD#kcU4wjsTcq6f16l5x3LcRDH(`)f4!~? zaqY5uo(qKkGWoX|EQDF;W(E#@W@fl65}$#oEy1eP^0eo2LBP%FzXEU%z8`#O?fFuN z?(@xUyFKT&Chl1BrB%ls9ePLh_8q5s|A!6&npES>y?;sDEYsx04%KtA;+=kZ+4qdz+5Yrksx$qfTf!v4Ekf>L)|^2n_rR1YR@MXAb{XfG;Gqpl%TlGHReShH(T)924ee=O)UGrqFvi??IJSg2vSP%=|^!y&t&4_l^<=j5>BFw!IZ!=Ge}89g4Ay{1vtPnN z3_#R)wkNxmzd2`oQ=>{c@VaEhSyEg6(MBAcmbLz8%Wo?;_U?m|*h^1UP=28Y`s&>3 z?R+7&*o&69wF%pG!0`(HqA4svka!pZTD^zGbpm*(2U0ae$O-uSVx%2AhBX6~&uslj=U zW1Nz)!}k18^2}afu8zt zH(kWb_ZPDkA5Vu%9fLn@Dr3e!;FctJowYPqTAP3k5+xA#=!*x_h)|u{pRI|c~9Foo7)vz z?xR=+9i6GBCj8UV&W0EJWdN(eRXl4><8otKSbByz)v15pU`|b0$<@ZY3-6znw+mlW z1wKZ42K*yloBbKqy}L^_{DDiGhFI4HJ!jJw>Q4bPgKtM;N4E8WG8l3utCyq8#-pmP zFXAA3%;vIa<6{9t{88wq1-FcO9HhsUH2#Ua6<%}v5aQfI{C9B=h*0TtD+eN4Isn<;J2k{^_Q3bE61{B4Y;2Ue6|+uq>ltHU(oI(^&8A zm-z2rCH1rHb4oUU1JqY62N+={P9LV7TU;4z9hqjjE&1-JHJ7<)viZzy3Jz6!UyXH- zct&^)yy9g9KlzSq&Qo4>1CZznoe%J{4l%pTZ687<5%3?IqOI3U(e_4n`z!^j3S82d z>shnA^j`esjLFO79@crxZGUS@0T6%mcF8N93Ys6ft=m4tOB&QBdFi?wU^5Fgnm!m~ zITf4ZS!eHVJubY+;1RiR+cu>-O?K%u#RNdJ8tBw<-~R;&Uh~=at~(c3FW}bi$IVl@ zZ)We~uIS>Lw;Yw;wW9O6Y}*|1m}WN#jsXA%3Zwcyq)&Od`@Rp`+S)a&R3_71<~~Q{ z`r7r0p2xmKA-Os3)9Y;0TBbSG2POc(kp_;w581OqmczR3i?s-7(D&2wX|3@%-m&hx z-l&1k4mi*LM||Uqr*hk;25T)8d7mGjvu^tGd7obS^D29*+jveUpWcg*n4qNX!?u~z zFLR!W<_bMF001oN<(+dMyXX*8=kD}-Nt|=5(==|f=P~n<)cJyMQ|e^nc=kgEb^hlv zVg%nM?^Cqwvp;@!E>jcdG~zZiaVg{d&&Zv(Iw$k6cgp5Ed1d^wuAxhp=#nO9Nm(lcEANss26tx4l%j8;Zvor9_+`khv{zCvjvNqnA^R%4d zv+Z4-U}(gfv1I$FBR&Bv>ZyH%H3p9jF{g=2{Vd==NC?yd)-YVe4BiP~6X}0207Qv^ zK}5i`_sq$E>i}>8Hx?Fi0;x-Kn}B~&#z4D*nEOO(pZ`HXbJQHVB>#VPfU#yq;sW=7 zHGeXJ#rzNDzY_lc7n0BLh#B=WIs$+LAR(duiIP5>KdWGnP-xJo=opx!WGq-;SlNUX z$qm^#L?{COjhMio!2bfS`S4qod+pIppYjEC&1ti2{Y(C=X0RJXI5SyYL$^-rWR{>g zZ>u^-c7d+xc0FHl!)mJj0wmZ0HM+eN3aC#&kEOPu;-5=1DE@I>OIg_nOe%2#FrF?; zRmi3CWaQD@td!j6FOE1Eljf@ie{}x>=m>w@dxWddC;rx?pPS0iY5p_k#&s~KcQjm( z9NYcu6s)W=w8lXp1=>ke?FU&*OCL0P`w?CnrN&&UoW8D{PG;;8dvjs-%8c65whi&! zB|X=0x)$&kayVu#K?s7nJ%6!lxBmrbwzSuD<~m)rH<6`3(--_!$&5QWS;!ey$B`Ji z8Q=^zcFseYrWUWNsyqMn6Rs+KD5Gs?WrcO`{LJ|A)YBu`x#hb0t+A^kk1BPVkJl;v zVoZIZaQdM+vkBiUNImV((9*<7nS}GMo{UBf%;?Efeh1obiwI7=qy0OUgtKF1{K8)9 zjJYJo*V|K+v%3pWls|K3`=`+gv~796U4Ty7CpWiAuQw8PJeZ-T$TanDgvJKO!;w3D(Zjsdiep86iL`d0w;4nV&*1+>$H}SLDUD51# zBhHMfwU*!e;5{-Ql+zhdPBn)^tqxhKtgrEOuTi47yw}{V=6vKI>juj-#7?>*CrX+G zv8uz9hB#`pe(@g*wkRR0hivhU$VpVExwD(hjxD05B8#nM`tD7CMzNr2{di;cJ~A`8 ziQgQW1c==!50#_(wpC8=48#|gd={wUVb|S-%^Eo4eRz(#wZ6gc@;R$YTAntUYM`fe zg*tbkF^jJCs_u>2(A4Va-|9a4{gjSfbSaY^bC%zNdbAm&x&vxUZGR5;a9#jd>IR=( zD88o7cyh`N*Cov!pExG5{4p8Z$Z!sxRT;8#K-zXjNP*Y4w))kC5T%1>D-tqTd6N{2 zG}YXJK!*doZr8bpRzda83O~}U$T;!(3n;j-*aWg`L^Q=L&79dx&74DdL=UZpwAe4c zUbP;Xw8A}_Vx))@}!sY(3)M^I9o2bH2_hi@}lqjL5gfAN3gM6Maks4d&|5CiN9$X?b3*< ziPv`Y7#o%Oid> z{s{V1lD_!hbYaU*LAhwQSB3Rj`(!YBm3_-6MJ!Dx@`WysLpsZ=5w9pl35y&DdgRauGW+B7D~aCux-B54;q(#_!i& zj>k+&Z%GsT?n~EQ&)`ftR8**;CSRSHJB?+_Do?I&@Y%CgqMf2T8!pZkjWrFfruHAH zr5yPeZe$6RYWzpP6l8kxTV!@iRc3ZFalB*I zsi%}$2PO|K{{=`^b`2J*-UF=6V(h-_8C1|3lRGvT=fr>}d9g}#{IT!VZUk!uvPPU} z2h6B6<<>bGi5|gUx_yFGypt0v)B8)0R;!TRg7e0S<@sH1kZl)mRib|0&e`ZK)#y2` z=Uodt!Y@zSO|R)a(@34Axq7&m-E}5seXWTz@;WPn0zOuqy62ovZxQ4{3zM;a5N)eX zc*OR;ww=0O%=65Z0T(Bp&Q++H^JNnEPxVOf8f$dzdT-X)!i&DP>E~eKYPh@K6J-07 zTN9mp=bP8N#%<2c6>qNgm@`&L`dy7bh0G_-$?M1yOo3foI`GigCZj8CBvCi}U_H6C zw33uGfKPxvSVUfWjx>$}+}sjWQDaXKbvHFrunG5CMp`dO-VnUCo6TyP7>6!S!h2Cb z@s2?{iXn)mqNaRJN}qx>-L8D&ZewHsC1<8)cicJQ>(Hx5Wq8Wbbx&cJMIGE3Gf@Ml z+J!>?0-oFwQONQn*qQ@+nD+=Ybk#fZ;-qo;PqfUoSl8ayHO=ubr4g?7r#2Mc?ZcZ4eTF z7@LI}j^`;*n8FRa$MfB>(j7x3`Z~RQ;LeDpYgRKelD^|?CoJA!$;!&%*Y7;!OrR2x{%mfh*J8)H%Xu4V}Q$rJi14|Iv~HbDZn zDWu-7AH8#`9S){S;yJ7ldu(hz_9Q`@pn{d5^ZoLUX`XG=Vz)~LqFe(SW3h>|s;NmW z{R_6~38sQ(a@V9r@ACDbsKL13J*?|%F5>3A&vY-n%+~6JLV~S7Sy^AxUOi(Eo@Qpl z{oi$7G&hunb94!ebK;4u3di$$vg9DoGw}?WT(4mnR%=w9lR5WfS_Klh);&32GdC!> zRua@U!SrN3>TO__iMiu5yCQzGy=DhhB@ArTD$%tcXzU4QGD(_ydis)i`NpYvsW0Z> zsqWqx4Bc=y3_Du-rV%AmtQ0X0l6DMow$y156gPsY!pYV9c3D6EV>p9XtBPv-CSe2hc6swYY1Is4!n}I&a6)O`H3L^U>1pX z=I!GIwZovfVw!ZxNTkT1hh}jzzJ;z5_Yf5&%wzXR{Z1Y;wNrOz=LuM;Vl}~ZJU6;- zPhi@P!ImRPx6MO8J9YXCfE{<%Ga7Oq>plEJj$*%X$b~7+C3zh~3>!7eZ%^#qw!6X| zKRDb=4*Cm-lCECkcBZ3u^O^5heu%S`>s7#j3zs8MadD02<`c~2t-Qij9!pm-m^bhH zs1xk&3Ncp9feUr+-3bL&S!0JaRQG-cI8A>6{SWsBTK5KCwR)OzBKK*(o1$z8UJm?g zaSjcrM_FN9g`|jv@_Jnd0ztK0aD2e&*?}$g&1-14Zq+KPx33h!Tg3{aoL)`NJ=@I5 z+qqTcWh~5*Ug?{Tm|xx3GW`eB+h zh*F|c%uC+8qV8OUZqz1u*Ha?R$C^EALNr;*@NNu{DjhOvVD>QPuJfBrt77c6E}?1o zr#;jB+@{qS^()Plba>SnqLyR%od=Bc4Wx(`nJ!c>^d@fTU-)}F{sPWlMhYxK<~ug< z*#dLH!^#ZU>PoL3Pxk$`1@+^ofB*PX8X{U-SK)wA-s;OBU_X7M7pN5XMpilz#^a;B z@O>qoG@K)Dt_C02A~*dPpf_~JDldEdtL!>cgBd&S_F5a+YLYJKThad4t>)9cyO*k% z^(}t8N$<7;!#`ls__jRmzj5ySpBsgQNVbb`_3B^LUd?m-lGAS4@9ZxTj<;%e0#guI zpvaV~>Y5C?22D?Pd$*(QYtc2v`U`7dV+g8l2u^5ogn2ual4=;SXBALYtd(#Q65%vR z+YTAdBF78T2KKvw?Vb>BBoT<~tvpk2!)Vbm)VL|ez%trzI9hj{F&61DPoeCzMqf#n ze`r13CzNp0}uS%`Ett#YBLRV-aRfWe50Rzu>E>r&ToulN2jjCf-ct%^R)7XdHc{qIwIer{rE;NJYm4=dzFh8E$YI~U47G2GE_hEpW*jsvHm-1| zo>hz$5fEHpL-Xl}iM9*X63NTB?97ysz$tnxLaIOkxa6wIe{^h5C?9NGcvTWm=D7hD zLW%=`;q9&(J`S6hb(tU184gwpe#q0F9`UUw=h`?LJiSaK9|mt;-ldhJpwn^lMHQ-~ zV{T={NKr^#1nmdARd+kvHS~9=k>aKFMRuUazD%<~6Au(u624sxy`dgdiX>4rV21eb%FfD*N`nb^zMLV` z+2iD3BUxQ(Ec7V+0l}DUyU(yE{+Y1%G;6O%u{@+#y{`RUPjB&b3?A$qXDNtKx`l`c zJz&>-vZXIsNbP)y{WE0?SOWd_$H}*Ae|IJ!D2ts76`AHfn0pkL#W6NrGa)eCe0mU35H)}h7_byRrK4+TZ8Tv-L` z_1jZCoa`o#Gv0NsrKW)b&#zSk;i<8$JojF#{RJ@4#llTE?iPO~%gERUiAiWD(9ZrQf~7Kq0H*5(3E`AE>!^eDn?A z?RcP_d^$BX-xA8|3=ciT^e0s&Y8pr^Rn!!=N>|<-Pvg2<-_0c^J<;<1>|E5@UP%Hc zwqBjuQ&GQIgHi*a@0V%HoWYZkR{kGn8G5R9f@R7F35(RCrW;K!(bE12M}r%eEHd+o z)loz6JLdEO2^D&(7Y4tSGuI~uEp0{zNWZW#(5TT+B31%bDpn@K`h+&g3d<@-bUR!T zsm}5bZZ@3Rhz!Q{6%g&>rw$&rH2} zC??j^4LNGQ#U<6<-Cx5deel7}$LjOd{^_@{&wlfbDH2yxGZ_5EdE^Rf4AjtFLA&og zIR$lBvIw}ApjK7o2s1@*GfM!s6Usr*UICRAY6qWlJ8y2r3h=E*zA$A(_8+m?U%<^r z>hl#8MPX-TD|6&~x9DE}0+50wyp5RRJ3l1q+{o9;PN=qOnzbVM-kS6vF9p@M{~mNEU;9 z#5w|T(eaYnXb$FYxmDLc!@2bfPClQkpUc!#R|6QQ~Ry zzAEHCwVlM)(Zq~6kl_)+M9mU|B?2e*U)$e>QodclGac0nsCxx9)EyI6(uleG%9kv% z#%efc?g=>k38=Jw|MeGOkW_hLKJ>7qk6LT8r`TRSz(H3b@{ikoj>&;4BygB1z^dvc zl_@I5u1uxkbI8?rYH2uBQiqx}F2-M8O1z@X`wNG6i9IDf_zxsIL=f{3!=q0YmiV`inT@sPS0>O##=E#>B z*q4WHi$+z5a=u5Z>2bOV`pQ%oGf=mvtXGH#{O7^-1qBth!&Zo?z1OVFO`L*0INE3K4%IBMx)_T$&x1(T@Z{@P9t)WsBmue%$-@30I?r^o-yhZ%gP)3{LqU=R>s zP|%<0w9kCnXFBck?IRilI@uRU3|1v0R8n#l5l1$5;Xq79Wy2qd6rxT6P+|oQ|K`=8 zg+B9Y#W#ts3onw z*}=!{+$6u|j{r@|zCdb4oJ;OI4L-}jF-9cko)r*0T_et3tGWJ4IY-nm^SPFCdGeBQ zIeex<;)^N~77xiUTP90KcK}Wp!?)5otzikOf$;X~2SfB;1WC3~a$SYW1*H-Wl|hA9 zsI;W|z0m2N9`%Qt6)Ky1%Z|mFkHJ5sK;g@oZs|!9mlYwkH#7nPZjD8k>VY@DyB=X2 zK!a4p+8NSGVOF-TQZYVt=8|G9z08NTwVrj;HzQ zY<~f&@zb2`P`6A1XdCl!B|ItH5QUk*ocEff4qFMKNBs|H%=6)+6QY(u|RSV9HgI~LZgb&PP(^&nQCoS-nYeQ+3^fTg_IGr6zwuwX?y1RYzBf-nXd>d6K5Spr;&v?giMw$yfNMhK%vE zMuF5tOCU|fi>k`q)icyJY|Eh#$c1GcdI<)m@&i>xg7?dji*{~veO@D$TX>jcVeGAH z!<3V^70(n#=&+?HEL(4WUH+{lUk$1XP2Iz%o&b<3PWj5l#169&$^|j zgvfSbgm%{cJf#10 zz~yGFtYzwpnspiX9JGoiJj~~ELqsC%wxsr|ibd{|>a}(2zX0Vg868DS!ssPabXP(x zT^=o`Vh4G}7B0r>; z8SL3YiLSJ*IPz(C%OVj}qRK~q{C2lfe8?R$hSLrNriOD|r&!sju6LhwtCKXwt|wHf z3<6&2GM8L=^X4~gy|ShZzCWUjy-C-=(=>ONo2aNKtlZPPb_aPfqgUt%mtLlifgHcc zK3Ev3G^<-nQqZ>iLO7(lme+wALYCvi3Y1EU;@0^oH*<^9lZ_3KW^LM7q~@^WEdyjNz)}aI>;S8>*4l z*3^xao2z0%uUWnlJl$`<)5qd> zRgIg{ZM)}S;ON*?=cvn6-6SQ`weT8IP19Od!m7OFrMGOHE}zFj5+I|Iv zA^RqyqhJCkZXW1HhNn}usEoFpZ^=!qd-zDOm1f(r_U=V=FBdJaC?D*XV4;nRRvFiH zG{Bm=hr(aXrBx%;E)WKdg*qDgch1`KCz$HFEG^~=^cE?BSyf{yl}gXss3={~yGof_ zl`Bow{>MLa3hN<~HXD8+$jO$bPG1%t)-euz<)ySTBG26MFDcES*VJG|AK_4Y&`STH zgTD4pw#`v;CMmD7MeYjJ@5mKJ=YJd`pe^G0DBIn zE9eeP7(GjA-);E?NYEb|FrOn)I@0zRP^A+oYjRMzL*aG|`C#XkDJrDAWs}8HvE&ic zcGga&KEE7i9o3s$L!+|RoNINMK_r-@^5<-pk(FN0oLar2Drw#p;Rq8-#appXZaE2? zfKEPeS_!MlUT~~6iy@G$&0W|ITTh@Xr$~=|N`4HXEFu)uJjwcu(Lx`IKJA%+o5%>C zk5A0@J~S<ud zwX=6qCz=J1etm*KgkAXa%KFj5HV;x}vA=9UAE@7a3>Gun=B8V2ZT{dQ#x!w$(^S9 zzI#{h_mK>!s<-+Bg0Itai**^q6NkW#HSuuzazU6c?JaWVpN`LA2sNT6FcSMcPO#>M zF8m3o@*yF$SM6^cD@domr(l-GJa}G{_>#CGlktmA#9Fi^g_&?}+oqsCmMAkzhqy}Z zyCQ8;taJ;6t}iz6;z^AmORe*=bm@s*I;@Q2dRY1y=E*`!zXt(F-eNnTGpxzmk6@IMC$H9{S@{t=&0d*}sOJ?P6te_^p5+vq)N6aXU6Ed(@2^}y8 zo8*zZZqRQMp)uz$Q@B%@1*dpb;|-CivG>)B>?kQ>^A5~M{5{1MldOBr7e1e7D`KJM z+fgVYSa9K#XoF(S@=coUI5I zwk0H8ilW z158|8oS~XEf?@ks6-M{MV5u4gAy>QEjXNEX!tNjSiz35NMC=-S>Mq(AOa8bBl{J^H z%+w5GSF@!FyMff-)ZXr-g`@moP|o77Rk1A91x>$r1{PJ}O{#RA)V1N;Rd7Dd`I9Nr zqc$}e3Mpw11#SDg+0wmSse{=ocEU(bF55R@qbnQ=#f~S`F*8p6>@IWZ7Jj9|Kz3cL zHwqMlO{iG9>)@2u=@(kZ_i zskZ_zPpT~t?IpDL*%rOi>idOlu^3N^)v=wGPqILP9w5z+{-p%=`X7 zI8S$e2R`}1R%}DoXD@39P;u}-=Orm5KJ(Ni$_L;P9lcddA^h3yP*i}=C8}Jy&_Bui zO)~vrU|3%CIG8dJFov>s`$k@fHZ|u1Z^J?Mxne zqM}WYmby=Mi{Tx*;89bdPd({dD5yn2^Y@+AGtohrt`NSq2F**>+J&*-$sBdU zt&AilDU0heOKWs;=CouDopmORZil}Mv@RG4sAy@uq`-@8n-*s2JZL$k7_Zd3H>~%Y zcgg+*P=5Z<4%LK)x$n;tirwp-s+~H_t-1U5>qc!0LE=Vl~*IbDyWJ71)#7sd@NIWL)INHlLFlX0sNcdKI`4`|1h!fM*~`;^gEAi^(qV8_bAAr}8OP#W0(6L(UY8%p${iTGU`74F7P{#x=dtlCGN-obD20#KdO%5AMEeyE#aHcSgD{?mhak?R1-aFcROR+{a|9^z^k=d zzrq%7dSM{z;jTlxYt8LhGpFf9&_Ehi;DJS{>XMM@)pt$QO#T%&{AO{!q?Q2`KS_5w zY$wd-8aXJO&h&vV!D9Hmjw-$ris4ZC8@<}d%q=>K;BC#w6+4ZaGBFI#-Q=5AKCg_7 zT8`(S-G5{*x-bVx4~p*oLM665XEF>g1O=h^BM2PZL&ecFY{2vNi1-xt;wlP~51abP zNNEWqA3ABd)FA1q!gR13(HR7^AoMJ!2DJOK2(0T1o+_rk5I^`t-Ya5uKXadrnkAGL z)fiMrd=0Da)PTxk!<|>}A+y54Dhcomp9YO0A6pMq*l8URKVlU#bTxrl(TAJH&bOEv zGCUZA!dQTHQp)ENmWIT3;4`xm-mUFM_B4_9%;d!K*t+dZ2$V)WTPz*bDD+}*+RYVy zg$30RGoYU@JQu&EIm>+qf`hkCw?0kfW53hJm0l{Q{fB}?+%E~+dmSW7TwPB3tVxui zD;WOCepjPKFC#f`WPa?togRLxu1fTWKBO)P8)o*{h)yq{WGyu{@NQLCFc+I|x!rdW zjqy%Mt|ZiYV5z)@5zIkXFh1y0@wmN5%XvcdFRHvbOC#kshUkBox-n}>5@fuGP-C?r zhzlgMN;CAyLI>3G1*6o#XUwq%Z)6!BW39l6CNf(FU~jk?Sn5#g!qj2rc1=ZhpVhrr zIK<}4l;OxzsaM(GI!s}O=f zyU)$>r2-kcLcEE08Jce|lCwspl4lIhj;p}<)m2>~vmJ(Nze!NPme5_(=eC^=^>ds4 z4}d{J0RG*!qmi+SD4`lT1}3ryD;AI%HU#v~UH{Jk7$LI1fB~6+t`7 z#xSX@lNUsp*0X=CO`z+vP zZ?O^Vq>#5PCCy8UVmfHi;=X4$IJS0EgaU2epGDxUiuocOuisESk>|&56AwYu#_|M< zeX`RMg4dS}7!M4XKB^MpL=8^btiVQoF&#Y0ukfmxl-d zY3O&CRd5r*U)4*(t2CTRsW2p)8gV#VA35Jb`=g-RWB$xd&PHUiU*p5`>o$>O&`O58 zvYuwgFnr4qrIk|6%G%VFomB`l;tBSt9`27CEX&X}KTAVV$RsrSCE7pF_J^L)$}N04 zQKx@a)~5j;c#z>Y{K%Bzs3;Z#O`bZ3AoYmau#U9cD7ojzjp#n_Po&Ij%@~!2Ov?@L zs&$OXrHHZ)>d0_E&qkaaMjk>99G-+_DGv;(LqsRGBV)(LHSH*qAK)kA`=Wtz4O`}w z6e%rUQ&+iI3h11~X>A)q(ti25c<~%#uk9Q{Cy&wlup26ybjgDCJcp7Z- zFJLP?auy}Mi$c()L%RySzGjS7XdLyN1Z|Hl*`)t*EPG@#GyL@Q8${lQjHY`=fyF(e zxK)^G<+cXnA-z=(i!OGXiN{+eDZI!r8AYjV4g9**53=Jh3#UJ6-n~?^@fF%)48D1e zOX*fo?%Psb>$fo60-(Jw^?CVbq`K-{jIfg5k^F9U6*de%Fp(Mrl4IgbK;OG$3c?p% z^JWM!HgLD*C0zuseo?36xvGH-UJ*!d@Ea!086SSO2a{vIoSE6`p;{T}y$vY2H$X7# z>P~|(26Ng3Gps38d|Tf!7o%V+F^&PLo<(!Tou{sf7;S@0VO>HTL(18Kcal8uig;<^!AZ>5*S!84po6I`WDfJ-HynN*) z@wi3P;}})FM*B>7i>4aI9wy=YAAV+Ug=tlsrxlX91zBdUwik2yN0@JF2W5eo(5(&7x;2GxsX zjXiB*(mMEhqiKr~Nd}DfS9ZyBbTXa`2au58j?iu<3DJEgZn3ch6p<&2CRBk=0#9yq zhl6g#EKXTlb7A6#nUMtiMmAmE-_ewDS1G3H@EYqTZQow;tvCdU2FjUZmB1Gn?T{o0 z(#@6$`;YMkL*uFJNc{O=u$`)q8EmuNmzE2>JmaeJ9gYJcFT<3!_r?bZ^~p?xLv_HT z!&mtsXy_}^P3D9UvK@N##fd{0MCrSt6IB?Dc~z_gOBw^IG_2N&cEuu4A}omo><4Ug z^|_eaiNKwr1f2vJ1Qr*V)jg8QxQ+R6EQ^!vI8E9tXlA1#z85vy5XlZsI@XpO`zbN) zZuy6{ukkhZukWHDCWBdGmYAPav)C38q@M@P+xeuoXN#p1rwf-Xh^c6e(>;@d9IQ^% z+$O(FnGf~SIYwsddi>CgKB5rL`wJ)};6X6T?0`AT2!0*rT6(0}rrjN4JaLqdcYyL! zGt39%XOTZLzRG3B(^U_%7Pna);w0uw?5bc7p6FC`$Vc{5swEqzzlIGm`w@xO?P2i9 z52l)HGMF0P$thgU1va9TDr%?87uAg7_=*z-WAT)PiH3;&1aEFm?eHU(5o+DA zxQ9ZbuhDqyhAlDHZozb#tki#>&YSXj_d`b^sR$7U{T<;JPWmNrS|uUEk&a}B&@_^( zD&B(w+UA#t&z@=zp$ycwAiYRL9lo+ccwp(i(f6y*Qw~PskT^Tp=?xnF{~KX8L4lNdY zv1vJ-n}4xZp4uWVK;HXS=Zt<1d2Oom=pucsqu6!+rPyd)=m}|{mjD!SgR{qcuiFZa z+u#2KbC0HsJuN~marYH0rnLJ>q;Z9so`m5%5 z1D5ok-;~o|=`N_KZQCGfnDi#Nk!WH37(>8bF`%Kt^aZ%Uxa~6TgBBZx!Pl|}6mJQK ztR)}u8X0yy%p<%a)X-0?BVo3|;WV24#+m2t1^v>{pS`3)-5Ljhu?+Rhh2*W< zkQn8T5TZ33OpU`9;GB-G`Qhl@tWwSn3}{`8fYR)S@bGcs8k7?{yA<&G+mzOqACYcW zD$(hb_R&IGscz5c4}uHW{$DiE?XdaPqS{}DRDCs7`z@pTP6QDd)7DHf5f+QB92CTM zH>}MNRlYXyHt8Bt9!PBx>;mB)z%h;|jd;7i4n!j*YCsnXG-gdU1)Xr>FO{q;8?V=M z2g3+wi{eK|^rNvHsGPZmfX|^RUZx|*vi-3;8dQs4^pVbeK>x|Rjt%EZ61G@~lI|i* z#|n;&Cvl<*AEPIZk&;oA9(4vvqK;0`?@`-Rg;I)I=zH?Zzn?ZaqeHJ?Wn4-fYtaNk zV*Wrrawcq1Q1lp4;l(#H>%1QFoxCa6N~kq2Q8(hNpuD$_Ar>l6bZL%~V-)@{)u&*` z^JSOJfG~|zlUT(-M9PQ;T3pa;_PnOFc#~i39II|zCJX_G2f}{Es}*oK_)&QTvWO|a z!-$8SBo?*ytGKax#Mg@*>nEk~;SeRdGk&J9$UOHg?{RE%hKJmd^rcJhuUlg!H>QZb z@bx>0mi$nuBMxTYG`M+JP-=fqiX>sVAYt2Mg<++Vn%hJ$i$i1Y(?75=sa3Mu;eftL zO^h@14!7xeie;OBFV@!x#gM{j)a&XzZGj=#kqPwzuFxreAE3BSd?i zj`YNy-zV{j9MG7Q=GOFkR$6?5OQX%7qK7?rYNwUZO@5j76s6Az9PeB1>Xt;rfOgDt+^0ybpNI_=`5WC4+w_T&a@%<>LmDko z>Blae3}ftl+EVWKz@ZtZ6~$yUpZ?A=3Jp08hN+%*(I%HT#O zIyC1KsSjp9l>1@nm0gt)8>>i5AE@_Bna7_(qAdif!=XDV^;JeA!_ls((H5OjF7(ZZ zbtX#Ez?(Hj147LBS!JSk1G+jjjvGI~(vN}7r$2+3e`1ogs*`gng~Svg??#!O#!-2m zM@W|n2%D@%QC$nDwo7#ZRmD^Iduv;uLMS(7%x20*>E&tovK|DBRCB$N8-Hs(q6tslaeip*x@*Zi_eN%KO}4Y^M??v zKkMq;lFVZZ`8AsyQ+~}TgEkqEdQVeui*4n)d)VSdzK~Bl?x;>ya*+$Hg*H;}T!n>V zw`c=$?6Ev^N>{ft);4(2lGYDWRpdw17vih18LZ{dDMq4Qu&zx}X`z&?)=tvr3~P8Q zxpZ5hYs3!mC($Xqr#N*(9I$Z7 zC_)`MBB$gvMY=j_svCtM)HA1Ie#FY`%AJ7AE9z;+SqJt@<1}r>Mrjbr5bARpCO^&3 z-J&T8kX?lETNpT;9xCj;v_glX<4d-5PvaBgK6+-_BQESde}9xglATKvdSD)y3dM3e zbgpS#ulV%RWQbK*Ew5Q8+1kW4jhoiEn?+3j{*1;sK-0kkr9zpiRbqN~&!xGDmD;P;i3S5xm=Q~?y z#(TdO^$Ut#El0}$!?-n^@OI&eE7@S@)ZRk}@$8U-D`qY*CM8ZT8x7m3AaNR7mT%sX zzdiOL7LnxWO!2?iRmTB`762D0XuM{J*CY;H@~#=FHe!Y3!g66|3~+wn8bJ*0Ed&Vh z%6-QrYLzSoupS~OC?P?xaPFu1o_tf{yZXH1KZG@=CPK)-3!tZdkl#azN6{ZDmpP~# z%6uJln!(kBA_o6@y)2N5rFyFzO|>5r(=ELLC^~ldmPR*ArT48-bQiXb#fq}Obx^~nBfqb z2*pWQsLS{b&uGsW{0RLu(wXlu05*8B)t0+gNc_Tp1wRi}Oo}(7U!Q-BF82dap!}9A zHnSri8Rt@t-<8r=oq{T*k1h%cr$|QUWO6cl+U2i{MC9?38M)sb5mfXY*FC{X>mHic zQDzcM?1V9I0GS6kRD1=sF^71|fizHm6>tQX15Y=`q~Oq5<0BnuLyu-U^pc^f%Ly^Q z_l9;Y`tn_Mu`xg~rI@%34yK%97?v~u2(DV8T*{WY^Pc`ED-xr>lZ}=yB^tHcY%G5m zwqTe1OS;(tdMO^&77fdjq1wRVpNcb5uOR8C5MpRp5xUZ?Ps#m0VE7of(mxFe70L-o zvxUiah~WdlHG;>aGve3uRgiwD5+kBQvOXco&+P`M=MQ6!Kho*24-yws^5w)ia0nl) zBm5LB*wF~wi93)EMgwMu+lRTekKQe4S5Ksh&i0m|_wpa_K%!ic?G@~^75rop*h_n; zj#IufxksnyhsPb+H-u4K+2Lmip(%_Jb5@Nk^FysQ-2oijtU=`%-WN;uS)Iz*XTCDLu<^fjjz0gL8f8(7M!*hUht- zM&!SDzsZl?G3`e*IQ&REuzRzFrD$isGg((&D$n6nH|j?mY*Z9P4RB;yFZz&8fT9XnO+)Def$z%DcSrbU#jjY3!-512(}y6<40B9u$~1JNAJzfqHI zum--#m!#K-p@iF`_Yb*|f9~PQ-jA>4=87Ve6Qg&D4^$Kik&ODBkrm2`q@Qy0z#t*( zu)sB68lz z2;!TU%}{Y294##^ooYErk@A^MwyTJZq@KVom-*YCrN>-<$#a1^Wl`6 z3Z-m*zal!FAT8MUhXQlMUF^hu2ug#Z1_0IvT35M!k|{97c%E&sPd=2maO7#o-aG#kqnpw!B>uw#`yhYZFY}3lm`yP%SLFNrgaQC>C2F_^ZR7LY zQ7Dj0(FoGC9ss!E^xU90B)kEDZDjJ=#CI#10s!USElCYXc8U=IpX>3rUoo~Q5CF79 z?(gQFDh&<*2wBGsNktv_Qc}RB7Ebc>a)&M^V8y0TE%b-FTrGfMvcN@39<5saCjfpK zb@e9)E;K5{U%*0v%(s3FGk!p8C9kCS|7qjA!kW;Ug`Ge`2|*Hi@1cYisv;^SG^wGt zAU$-XNEPWN^dcQpia@ARqzO_(4{o}Y;D#uuh$x7Fih4NbJLkXpuhx69Zf2gjSo1zJ z>)=Dy6hKb4lv?`V2Kp@xpn+r#H{flFS0GR^to^3)7O!A401<%Qe(Olw-2*UAes*f~ zTgax1qeiP)zTr>ge?AZJRUIKnY+jX$1JG7;-*BdNgscGo70`(%YhRd?008=b&}s_C zQ6DbD-rV(AMh-Y%(rJ%s9<|$lC;H0omRIEcxJv>)nxbu48NMWdIAovY{eJ@hsAgWn z`#%IwG3RRj4?$kXasG#ZD^!C2ApleF*Z(DOQr!O%pjzYqh_&+ni0c2~|8uHeYG#@L zXl5V?2)cC5)R(t_fdA3VF0f0@T!q54k7z6iI`13>#(n*NrWy7Z@KG2$rToK_J%r_; ziFx}Ba+NyrivNp5prMsIb6UoaM~r^~3(E*3SyKkMF|l72;a|9W9@}Bntiuqiuua!s z8Wd6dER1T_Gu!HqS;nX8oANr&>TL;_takGr6FD1Fujiknm8*nv0Y9fp*C>o>{+KnM zcEw5Il;f`duN>O%r4Qwwu_(JTSk7m=(K}IjL+Bqi4M!LfvCQLN$h2u1q2<=+>6MsK z@3NSS?G>4k5O=n6adwu-n40_7C5B7gk|yNYno_&I@k?* zPL*H-A?MlzSPr%@i?Xz*hTVSF#}B*nM!{Y>RTLm~R^eTkz2!Sb?5|fxw71lw`rMxa zg4^h7Dh>W6JEweaKTD1bnnh-P_B+M78?0Ytv$FfzCix){g z$PX@?&!kb5*t$t>V-S~@Gu zsztoL@RXL`71OjQYxQDkQ^OiYgFP+n>y5@&rB#z1{Pb~tFDfXi!$-mWzJ=o#dKws+ zoZiuSi=6XP!(X<}1zXm+C3WMzH;@d@AFF=pv5K`~()??cpmVOF|H8}nFUL{~swWWF z)=pR4HtHm2BQ?+HQ3*w5w$eCxUfI#Lxg=G|*iyIJ*7XO|t~ZRvUvNF#gJuZ~D|0bw zm=2FMb@w9{uJ!*eoA#`oRja^iIlge;Cjq;~T!%z0mm0cjSi-w3L;&N()o(K$8+gLM z5^Nc^oHOPpuP^kOSNq`fvCkUzgYqDeZgUg7Jem5&@0#Dqmx#D*(U_rRgJ>jO0~#eV zsIt;Z8zdyp<7i7{-QbBu)og*g!)|gQ+|+#5_vP5#(V7bDM;l5LaQ8B#URCs%i6PZY z-0Xh!s(_quA}wDV182Z*&Yx^DcYAD)P&GQj(OUgu(oF;CQ>|~IyS~2OmR0R`)RDo^aE;7i;rD#uj^?RA({L~eF~nKZ(%ZKODem;ev1PETzJnfxWN{Y4DFkLbengm)%6<;1wj!}PQUyNTQ-84F0=BQ>+Puu;%cIED;&D^iso+ z{)HmPA7MN&BX_oBv}@cw6gnr1#C&FjrGphRf%#spqR^8uku2{ANCYNg$Gl+apIs6+ zSZLhtFW`j`k`r>CrgeC8Q^M9;f9j;jNqWO>Cx*zG`jk8|$q4EVlnXas9w1K1_#eAb zZu)dcoo^e^lEW&f;6EiPnPLRdtVkj)!rK1S&|#=whsl27tUw>qS|Upvz@JQ5N95-a znJu5&5!q^yT@fH-7fgDbMG=3~qHxbW z;I2_&ZTbHG#}Y%k53IT_2Q*IdT8k#O6)9LRd9BGgGnwX4RKs;29G}BI5r9=y-tw64 zs!`hx`S1Q^;a=aT7%EQD)()wg|=IG#!#(v8=$BXf$#Ypu3^IL}mhthhWlGubJ_ zcaK9J5BEYCS;I&5uD)kS32lJk$Wta5r!!3Y(Z$6Q1zW6#6tjFJdzEy*M1SByr|)yh z8kyQM_bj9JlvBGu-w?Pc4G*O^6{}J4)Cs(pnM|b%kbL6097X5i&o83O+>_BE6;5DR zhj#)j?N*F}tmr&1G#|$Z?>yE>GP;3qsdS^&Zd02$I)E%L(vYc?VECAIVnh-QvwSa`7x47B#pP98 zb}i#^5#D`PzI+!kWw~8VnV)a1LHS7d=S>Y=i%nuO3+K$B#)#34*VJ8T7_1h#MtEs) zq9LO4PrG&0|CAamv^8zu++K<7a7);6UJax^$LYHz z+nTqA`ph&_#`H*Sf{QGO4fSr?OfSm72*w)AWiWXjVa(;#rvX=V`2%bte+vtm_gLCc2qIeu4ypQInh3UHUHiU9z4^&ZLE&+ zI5hv0zhm9e79)09z84f4uH4N@h1UE^b$kPkzId7^DqiA&u9IE?Z~S{KRN62h>&Qls zjs&@vrQ1Ut8nYB>EiCk>Jc&}o&>s(IW;0v$0QQ-<-HiIiXrQw0?D`Yv{j(JF26YS3 zrl<865IA^nmHLg;w&5$wo8V2eFOrGe?$O~imrFM^g(VZcvBdicb`N%?wR!JpRU|W+ z28CyFm{pc{LW0wc+QcMyS$JnhAik)3mtD@a0E&613t(|!c0-uKpo?zqX9~}>A#92B zg?{MmCI(@?U8Y@`6JO?sEVxsnwy{way5rME%RJf;dTrwXWy$YXtRGwN>VI~iVpKV5 z^Yb@?8w?cUmox8@Aq?dyl`m*8dVy*2ownKW$8>3WQ*>9cTN1N@nHLH;B|y8a(0p`N zkaGKTdoi_xK2v5qC z{yIGQ%zo2|uSYoOhvvp4-%!bJd>kw6vXm;*zU>8UD4S6rfUwxF35@Va5n=B50NIgW zZX)_kw#?tvOzi&x00U$mevvyIxxcEG^ZGx_?u~PknBvF#N_jU>nd80fBjmOXs*Xet zna_Zuh_uF}XX+C7(5{Zm4V{US)+nmJ!(7l)2dx2|Hn&+fU)d%r zZ{Ty)eh4IVMT(i1Xk0D>_@7~3OHR4&0{JkE29Kv&AI${p3e|>-zy;8#W9b zHcR$hQZgU1be85f<@?6B1%ZME;A>1f?04*{f~=YR+tX`5^cU;5yTCNLQ=bR+9_JZ% z+cScSMzWd#ifIuq(x;Q4XZ|^J>~p#M;@G*2Ml;I8k$eHe);a5z9-Bh zf8W+ET=aQQzMfL%i|XRS-W{Lc+ZZLshc^aC^-wXU^t`tZ&Ys`}TLO0>Du*+IK1@o= zQc|1fS1uv8G*g(NCZMCiaDuthz6GV=1)G8vPuO|VD(Z-zdK;;Q74>&kL|Z9yW7i2K z;cg-XU?j~qg0!VX>mRXHmk^B%+cKdXLOq6dngKMNus*;0nTAJ3yK77+-iENh_8z`- z%n8r6m|*@P$I*8rZ&$Pu&HyUn6Xw#IF)4Uo;vNa5fhJCTm)@x@*DFzw)KfSw6j4t8 z3qX0xH2#yR!)HGej1c@uOHCJOTwD6~aj8c_G}^)c7M)VcmvEl-7Ob`H%v*`3EquxM zLh42rs*3Ca($_g!<~61moX!w|EE45$J$QUD1fE1+vlmpFG~5tOY%gAoHBS%B;AFJe}%6p?fGbycJ+sSe<~ zU})*3A+x{M>tqV`vuhsQdkjEJ*FyZZvpQCCK^_6q(qze|D>AUpRwT2sF={XTw7seu zy9gJesO)-5hHT0js*d~K7ZjU%gzQS(+zj)%k+y#HB!On}2!jyaOsgzI&?Q+aRxC)G z8}&ORRXv}}1D`xz$WeYNy}TWLw=cGCpSo=3+=DBNLDsdR9(d*2tiQ3weS}U~R-Z7Z z4Ro+^GcwK!M`mG-Fgs+S{HXJ<^fhYHO2SP11x#P5DaDWp*c?C}imfeB@S#ivs7l+r z+hbWKE(wf|)Jo>;dwCFplD9&S{t*dP7p{Esx}$M`{EatZBL1~ytVL6V2w4l5ohxAR z=(m-79EV6miVC%+?DZS7f-zrE$ETky8TXgMNz%NRQ&>TSj1Ae^51#_Fxg~vn6s&YW z?)z{cxa*nvbZS&~f9BB5u-j)m{7Q%~X!Ly}YuM8AlvBicTDxV;wpod${GeEvJU3z&~7hxytJR<9K*eqp=Qy1O7$NPGeIP!;j*bVv*{V!%A~j&l4=2I_4Q za1P&86K$&OvrFUW&J672JaFu?)MZ7+j|vFg-HC>TAEgClH-@iKL5r1-(LW84(?l-P zpp<|j5=YV_Jy4zDIPLwJkK%d^NM7#$j`lFz+*V`4>#06uO$I7c_U(xT#)&PzRc)Et za%Cxn!q&Ar)(s?$mOCa@9EMJGWe%>hIk3&Oz4}Wxk7if;3)tnQPm1Fzr(W~B>&O?E)40vD{ba@(=dV4Z72-a@{L!S z30IxNWWmg_@33=T{HT-q_95<;e2L)8wm8=JaNaV#85^r>Z7XLf)L~5ZA3I+qSXMkE zwP7_Su$9dvlLTsI{*-)Ik5&KFggxZAe5U`+S!*KAVaOb9DJkxAGmb z31b#C<6vZQli3C!uZ7nvcG2X%i$Y0 zd6)fz(mNAn>HBm{&Bh2^uJLXZ8|HpR6mN0*PA(8T7&KXF^A`~06d{{OkoBSl29^3y zeP8A+zAe?#eTWQg##Dv6`?PLf-}X zr%-iS6s6m!jN|86M{XE!zk8ld55mx{P4zNs*yl(SzE>`?sg$B*DLXT$WCN<~Dk#{AI-=j61YTPzs~ z?ln;Td~MmiFk4w`!ME#lH%R|Ng$u2`@YY~&*A`we6FX0IRgv+|BvDym97s=V;i6(DH?O4x9=IBwl zL^HNy20BZ3#M<}5`6SPLCIEP1l?m;Fd}5x@{&I4xEjrt$z#&|u@H7B@^}vwESSqNi z!su7QK~~bJhLG(9eL%%z_Cct$9X(1dZEr%UFrKBL&R<%iL-0pJGtK^(DTk@VBjiKK zc}_985j2iK35(^@$ICGVtfgj-TUXtRoYv%QYzRh?qD$Oz8+>7y|lKU|Bhs) zI9ZGWpZg^9VxePz5R9yIfc==6!jeMyg&zBI4ysoIXWEZP)C%_- zK<*v8BOOXJkJMm98Q_$2#0d(Ok-?TlWJ5p24r{0(%IT8XMLAn5s-n=TCC;#Qg*&3w z-_qKOEY3BHFD;(TnIp2~y1Sb1dIdT_DD;CrjEF{A1S`Ie2bR1oCDH(<@@c7`+e5v`e# zIe<3f*ZD}ZwnZE1LoadI2&NkU5~f=l05#w_aa4Y;6!BYw#C$c|Bb@5BAB<7d%uXU? zkFm>ulJ&8m>vl{=&jxgB+&)aGx`>xLNM|L&NTBaTIk08Z98-f2FcoCc}y&6Y^nrnvKF5q;e};gt`0vKz3v+U8wh#W`WGa8VWj zTD4Rd%6+2M1?oV#j(3Y;Yw|@>=bOXo&B5fmdzPxNJ_dt-X5V|@h(ir#B1*Rm$3a~x zDU@5{Ecv#ftc}SUbRepbDYNuw~sdKXMTJWMOzI* zM$yzK!j?9_V;*JlzR~Ahh;4}9^Mu7?gv%OkEyRxFv9=a2L}cd^bKjbh*K9PS-Jzi5 zp&Le<3h1^&X~rlhsn1lS@xF+iTB#(+o8dYCfsQ}|pfD2W$2Cvt`5{r~cvdY*wQhYX zf@E%{*{e)B^LY7>l)TrY<=5g@IiK6$KZpv>5M2Ybt|@*GE1!H~wZY;1nL+KXiE%Xu0Yu`HwJ%-ET~Gob}Xp3vZ!pZjNXx zOQ5~_Q%3xka2%A7WWvN>F(q}>xcBkha<(SX6(*5A zZqoz{AJB$hJ=!jRqZjlO7H!$)vS0TneCG0N?Lyiqr{~zR5``m81=*0Plt@jSAWM2F zxYwcUJP|JBoudv5rT&KkwAFPw`R0=j61pp`7g}6TVfvsO8(0$?JsevFSojWDRRy}&W=kUeFZ$vw%p%=5zjbfT7MIdT;;!(Cxz%LsKbdhFCr^XM9VKD0$6 zP{Yq{1;aIK|DHd=5=V#We|9K$9Bju~4_zKknA?XyRTxfctj;Qg7!u6)K|ty|DgR&; zCE|0m9~LuCpT&kGe6qS+t5A|~4cc$4bGdB+8c{UbEZlhu18zH~ z?O)NAzsF3i(B~uIBvBf&An`a@Y5_T`{j#q7c2tN}me-?5gqK%ZzOU*u5(%%tGWUjrQ8c|3A%Y%+3VN>_D zFA~rfnqJ=4M;t&lyTYPjOI;Rd1j}?P+|OVrf&%fHx~>S}8|}-nEjq7z3m#lj3<4(2 zgmpC!Cu=oQzoA)A*cJuvaaRl%Jw1f7+e9RI$GB-fMONRR=#^($b1czN5f=-vhSik_ z3fGI$>c5U$zA72MrydUg6WaC^>x?&G z*4PYUfT$aDw*%OY(^(mug~(M*mH4GHcPkxPgcdShF{DKHRaEO4Aq}##k z){F>juxvumjOcbq5L8*wU`}IovkV8|r2d^}U3jGI)+s3y75~FZV;}Q#HFmmrizxCQ z?*h5uBUal<+QLsaq(ZeV%O?cgqrjQn51O5(w5c8mJ$%E*d|Zz2j*NGDE>K)E0|;O> z^G+=fRal@ddNBi~ie$~;ID{&NFc@!AS(reQP?|G|bA~$9dl7=xb&dwT@qz}S*XaZB z$Ru_OEgNt<&5Nhu4su{DU2lMI^)qklGt7ou7^XT0&sDngi$-w|vn@{68cUQ%eN1T6 z(hSmmmy$Mt6MBsRzZ?$xX}8 zPeynR_1`{`UlRbSQd7L?Xpm+fP(>e-#Yd?zH_-~U8gfDJoRV%XM2~cE#;8Y7>%@G( zH@iM%yJ}vHm(iIhNuw|jzee%X@z-}Qba4I!#JPf_c;8d(yWyh}Z%LaMc|u;-d5uN2 z%ItJJ6^6n<;LPejK*=sCgqwR{Hp{xC{S&!!&|g5B6cNd9&hLguqNua=P_r$69eVO+ zgWwx?G0v94S(v@6{Y{D)|KxZYx;4k8C9ZE&K_&e1$-j%caIa@9K{DFQ&Dw=X(FXHI zWb=~{R`OI9> zerHl$TgaImkqyt@Eo~;F5X-lmsF>Part no.: 165218, 140156, 242811, 264728 | ![](img/thermo_fisher/thermo_nunc_1_troughplate_90000uL_Fb_omnitray.jpg.avif) | `thermo_nunc_1_troughplate_90000uL_Fb_omnitray` | | 'ThermoFisherMatrixTrough8094'
Part no.: 8094
[manufacturer website](https://www.thermofisher.com/order/catalog/product/8094) | ![](img/thermo_fisher/ThermoFisherMatrixTrough8094.jpg.avif) | `ThermoFisherMatrixTrough8094` | | 'thermo_TS_nalgene_1_troughplate_300mL_Fb'
Part no.: 12001300 (non-sterile), 12001301 (sterile)
[manufacturer website](https://www.fishersci.com/shop/products/nalgene-disposable-polypropylene-robotic-reservoirs/12565571)| ![](img/thermo_fisher/thermo_TS_nalgene_1_troughplate_300mL_Fb.jpeg) | `thermo_TS_nalgene_1_troughplate_300mL_Fb` | +## Plate Adapters + +| Description | Image | PLR definition | +|--------------------|--------------------|--------------------| +| 'thermo_AB_96_plateadapter_MicroAmp'
Part no.: 4312063
[manufacturer website](https://www.thermofisher.com/order/catalog/product/4312063)| ![](img/thermo_fisher/thermo_AB_96_plateadapter_MicroAmp.jpg) | `thermo_AB_96_plateadapter_MicroAmp` | diff --git a/pylabrobot/resources/thermo_fisher/__init__.py b/pylabrobot/resources/thermo_fisher/__init__.py index 008b938ef84..a190a16dc23 100644 --- a/pylabrobot/resources/thermo_fisher/__init__.py +++ b/pylabrobot/resources/thermo_fisher/__init__.py @@ -1,2 +1,3 @@ +from .plate_adapters import * from .plates import * from .troughs import * diff --git a/pylabrobot/resources/thermo_fisher/plate_adapters.py b/pylabrobot/resources/thermo_fisher/plate_adapters.py new file mode 100644 index 00000000000..c67c5928090 --- /dev/null +++ b/pylabrobot/resources/thermo_fisher/plate_adapters.py @@ -0,0 +1,25 @@ +"""Thermo Fisher plate adapters""" + +from pylabrobot.resources.plate_adapter import PlateAdapter + + +def thermo_AB_96_plateadapter_MicroAmp(name: str) -> PlateAdapter: + """Thermo Fisher Scientific/Fisher Scientific cat. no.: 4312063 + Applied Biosystems™ MicroAmp™ Splash-Free 96-Well Base + Item: https://www.thermofisher.com/order/catalog/product/4312063 + Spec: https://assets.fishersci.com/TFS-Assets/LSG/manuals/cms_042431.pdf + """ + + return PlateAdapter( + name=name, + size_x=127.76, # from spec + size_y=85.85, # from spec + size_z=22.86, # from spec + dx=10.25, # from spec + dy=7.34, # from spec + dz=0, # from spec, just an open hole to the deck + adapter_hole_size_x=8.0, # from spec + adapter_hole_size_y=8.0, # from spec + adapter_hole_size_z=22.86, # from spec, just an open hole to the deck + model="AppliedBiosystems_96_Well_Base", + ) diff --git a/pylabrobot/scales/mettler_toledo/backend.py b/pylabrobot/scales/mettler_toledo/backend.py index 051e2a2e715..78e1590caaf 100644 --- a/pylabrobot/scales/mettler_toledo/backend.py +++ b/pylabrobot/scales/mettler_toledo/backend.py @@ -630,9 +630,7 @@ async def zero_timeout(self, timeout: float) -> List[MettlerToledoResponse]: timeout_ms = int(timeout * 1000) return await self.send_command(f"ZC {timeout_ms}") - async def zero( - self, timeout: Union[Literal["stable"], float, int] = "stable" - ) -> None: + async def zero(self, timeout: Union[Literal["stable"], float, int] = "stable") -> None: """Zero the scale. Args: @@ -666,9 +664,7 @@ async def tare_timeout(self, timeout: float) -> List[MettlerToledoResponse]: timeout_ms = int(timeout * 1000) return await self.send_command(f"TC {timeout_ms}") - async def tare( - self, timeout: Union[Literal["stable"], float, int] = "stable" - ) -> None: + async def tare(self, timeout: Union[Literal["stable"], float, int] = "stable") -> None: """Tare the scale. Args: diff --git a/pylabrobot/scales/mettler_toledo/simulator.py b/pylabrobot/scales/mettler_toledo/simulator.py index d740c45aba6..c3578ce117a 100644 --- a/pylabrobot/scales/mettler_toledo/simulator.py +++ b/pylabrobot/scales/mettler_toledo/simulator.py @@ -91,7 +91,7 @@ def __init__( self.test_weight: str = "200.00000 g" self.profact_day: str = "0" self.zeroing_mode: str = "0" - self.uptime_minutes: int = 60 * 24 # 1 day in minutes + self.uptime_minutes: int = 60 * 24 # 1 day in minutes # Default: all commands the simulator can mock self._supported_commands = supported_commands or { "@", From 6b13ad7aba57b4bf96c8fe2af423a4d588511a00 Mon Sep 17 00:00:00 2001 From: Camillo Moschner Date: Tue, 31 Mar 2026 00:35:30 +0100 Subject: [PATCH 37/38] fix docs cross-reference --- .../scales/mettler-toledo-WXS205SDU.ipynb | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/docs/user_guide/02_analytical/scales/mettler-toledo-WXS205SDU.ipynb b/docs/user_guide/02_analytical/scales/mettler-toledo-WXS205SDU.ipynb index 299739c079d..46ed83fef9c 100644 --- a/docs/user_guide/02_analytical/scales/mettler-toledo-WXS205SDU.ipynb +++ b/docs/user_guide/02_analytical/scales/mettler-toledo-WXS205SDU.ipynb @@ -31,8 +31,8 @@ "\n", "| Configuration Name | Has Load Cell | Has Electronics Unit | Has Terminal/Display |\n", "|---------------|---------------|-----------------|---------------------|\n", - "| **Balance** | ✓ | ✓ | ✓ |\n", - "| **Weigh Module** (or \"Bridge\") | ✓ | ✓ | ✗ |\n", + "| **Balance** | \u2713 | \u2713 | \u2713 |\n", + "| **Weigh Module** (or \"Bridge\") | \u2713 | \u2713 | \u2717 |\n", "\n", "**Note:** When used with PyLabRobot, the terminal/display is optional since all control is done programmatically.\n", "\n", @@ -74,13 +74,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "### Logging\n", - "\n", - "In Jupyter, PyLabRobot automatically shows INFO-level log messages (including device identity discovered during `setup()`).\n", - "\n", - "To decrease the log level and save logs to disk, set up file logging:\n", - "\n", - "See the [Logging documentation](../../machine-agnostic-features/logging-and-validation/logging.rst) for details." + "### Logging\n\nIn Jupyter, PyLabRobot automatically shows INFO-level log messages (including device identity discovered during `setup()`).\n\nTo decrease the log level and save logs to disk, set up file logging:\n\nSee the [Logging documentation](../../machine-agnostic-features/logging-and-validation/logging.ipynb) for details." ] }, { @@ -327,7 +321,7 @@ "Resets the scale reading to zero while accounting for the weight of a container already on the platform. Use this when you want to measure only the weight of material being added to a container.\n", "\n", "**Example workflow**:\n", - "Place an empty beaker on the scale → tare → dispense liquid → read only the liquid's weight." + "Place an empty beaker on the scale \u2192 tare \u2192 dispense liquid \u2192 read only the liquid's weight." ] }, { @@ -684,4 +678,4 @@ }, "nbformat": 4, "nbformat_minor": 2 -} +} \ No newline at end of file From 727d375b28cade09aec0bf92072c4f5580829210 Mon Sep 17 00:00:00 2001 From: Camillo Moschner Date: Tue, 31 Mar 2026 11:00:34 +0100 Subject: [PATCH 38/38] update docs to Backend naming --- docs/api/pylabrobot.scales.rst | 2 +- pylabrobot/scales/mettler_toledo/backend.py | 16 ++++++++-------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/docs/api/pylabrobot.scales.rst b/docs/api/pylabrobot.scales.rst index 2b8346e56ee..5d8d438cea6 100644 --- a/docs/api/pylabrobot.scales.rst +++ b/docs/api/pylabrobot.scales.rst @@ -22,4 +22,4 @@ Backends :recursive: chatterbox.ScaleChatterboxBackend - mettler_toledo_backend.MettlerToledoWXS205SDU + mettler_toledo.backend.MettlerToledoWXS205SDUBackend diff --git a/pylabrobot/scales/mettler_toledo/backend.py b/pylabrobot/scales/mettler_toledo/backend.py index 78e1590caaf..2accae392bc 100644 --- a/pylabrobot/scales/mettler_toledo/backend.py +++ b/pylabrobot/scales/mettler_toledo/backend.py @@ -772,14 +772,14 @@ async def request_net_weight_with_status(self) -> MettlerToledoResponse: """Query net weight with unit and weighing status in one call. (SIS command) Response data fields: - data[0] = State: 0=stable, 1=dynamic, 2=stable inaccurate (MinWeigh), - 3=dynamic inaccurate, 4=overload, 5=underload, 6=error - data[1] = Net weight value - data[2] = Unit code: 0=g, 1=kg, 3=mg, 4=ug, 5=ct, 7=lb, 8=oz, etc. - data[3] = Readability (number of decimal places, 0-6) - data[4] = Step: 1, 2, 5, 10, 20, 50, or 100 - data[5] = Approval: 0=standard (not approved), 1=e=d, 10=e=10d, 100=e=100d, -1=unapproved - data[6] = Info: 0=without tare, 1=net with weighed tare, 2=net with stored tare + + - data[0] = State: 0=stable, 1=dynamic, 2=stable inaccurate (MinWeigh), 3=dynamic inaccurate, 4=overload, 5=underload, 6=error + - data[1] = Net weight value + - data[2] = Unit code: 0=g, 1=kg, 3=mg, 4=ug, 5=ct, 7=lb, 8=oz, etc. + - data[3] = Readability (number of decimal places, 0-6) + - data[4] = Step: 1, 2, 5, 10, 20, 50, or 100 + - data[5] = Approval: 0=standard (not approved), 1=e=d, 10=e=10d, 100=e=100d, -1=unapproved + - data[6] = Info: 0=without tare, 1=net with weighed tare, 2=net with stored tare """ responses = await self.send_command("SIS") return responses[0]