opentrons 8.7.0a7__py3-none-any.whl → 8.7.0a8__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of opentrons might be problematic. Click here for more details.
- opentrons/_version.py +2 -2
- opentrons/drivers/asyncio/communication/serial_connection.py +55 -129
- opentrons/drivers/flex_stacker/driver.py +6 -1
- opentrons/drivers/heater_shaker/abstract.py +0 -5
- opentrons/drivers/heater_shaker/driver.py +0 -10
- opentrons/drivers/heater_shaker/simulator.py +0 -4
- opentrons/drivers/thermocycler/abstract.py +0 -6
- opentrons/drivers/thermocycler/driver.py +10 -61
- opentrons/drivers/thermocycler/simulator.py +0 -6
- opentrons/hardware_control/api.py +5 -24
- opentrons/hardware_control/backends/controller.py +2 -8
- opentrons/hardware_control/backends/flex_protocol.py +1 -0
- opentrons/hardware_control/backends/ot3controller.py +3 -3
- opentrons/hardware_control/backends/ot3simulator.py +2 -2
- opentrons/hardware_control/backends/simulator.py +1 -2
- opentrons/hardware_control/backends/subsystem_manager.py +2 -5
- opentrons/hardware_control/emulation/abstract_emulator.py +4 -6
- opentrons/hardware_control/emulation/connection_handler.py +5 -8
- opentrons/hardware_control/emulation/heater_shaker.py +3 -12
- opentrons/hardware_control/emulation/settings.py +1 -1
- opentrons/hardware_control/emulation/thermocycler.py +15 -67
- opentrons/hardware_control/module_control.py +8 -82
- opentrons/hardware_control/modules/__init__.py +0 -3
- opentrons/hardware_control/modules/absorbance_reader.py +4 -11
- opentrons/hardware_control/modules/flex_stacker.py +9 -38
- opentrons/hardware_control/modules/heater_shaker.py +5 -42
- opentrons/hardware_control/modules/magdeck.py +4 -8
- opentrons/hardware_control/modules/mod_abc.py +5 -13
- opentrons/hardware_control/modules/tempdeck.py +5 -25
- opentrons/hardware_control/modules/thermocycler.py +11 -68
- opentrons/hardware_control/modules/types.py +1 -20
- opentrons/hardware_control/modules/utils.py +4 -11
- opentrons/hardware_control/nozzle_manager.py +0 -3
- opentrons/hardware_control/ot3api.py +7 -26
- opentrons/hardware_control/poller.py +8 -22
- opentrons/hardware_control/protocols/gripper_controller.py +1 -0
- opentrons/hardware_control/scripts/update_module_fw.py +0 -5
- opentrons/hardware_control/types.py +2 -31
- opentrons/legacy_commands/module_commands.py +0 -23
- opentrons/legacy_commands/protocol_commands.py +0 -20
- opentrons/legacy_commands/types.py +0 -80
- opentrons/motion_planning/deck_conflict.py +12 -17
- opentrons/motion_planning/waypoints.py +29 -15
- opentrons/protocol_api/__init__.py +1 -5
- opentrons/protocol_api/_types.py +1 -6
- opentrons/protocol_api/core/common.py +1 -3
- opentrons/protocol_api/core/engine/_default_labware_versions.py +11 -32
- opentrons/protocol_api/core/engine/labware.py +1 -8
- opentrons/protocol_api/core/engine/module_core.py +8 -75
- opentrons/protocol_api/core/engine/protocol.py +1 -18
- opentrons/protocol_api/core/engine/well.py +0 -8
- opentrons/protocol_api/core/legacy/legacy_module_core.py +4 -24
- opentrons/protocol_api/core/legacy/legacy_protocol_core.py +1 -11
- opentrons/protocol_api/core/legacy/legacy_well_core.py +0 -4
- opentrons/protocol_api/core/legacy_simulator/legacy_protocol_core.py +2 -14
- opentrons/protocol_api/core/module.py +4 -37
- opentrons/protocol_api/core/protocol.py +2 -11
- opentrons/protocol_api/core/well.py +0 -4
- opentrons/protocol_api/labware.py +0 -5
- opentrons/protocol_api/module_contexts.py +11 -117
- opentrons/protocol_api/protocol_context.py +4 -26
- opentrons/protocol_api/robot_context.py +21 -38
- opentrons/protocol_api/validation.py +1 -6
- opentrons/protocol_engine/actions/__init__.py +2 -4
- opentrons/protocol_engine/actions/actions.py +9 -22
- opentrons/protocol_engine/clients/sync_client.py +7 -42
- opentrons/protocol_engine/commands/__init__.py +0 -42
- opentrons/protocol_engine/commands/absorbance_reader/close_lid.py +15 -2
- opentrons/protocol_engine/commands/absorbance_reader/open_lid.py +15 -2
- opentrons/protocol_engine/commands/aspirate.py +0 -1
- opentrons/protocol_engine/commands/command.py +0 -1
- opentrons/protocol_engine/commands/command_unions.py +0 -49
- opentrons/protocol_engine/commands/dispense.py +0 -1
- opentrons/protocol_engine/commands/drop_tip.py +8 -32
- opentrons/protocol_engine/commands/heater_shaker/__init__.py +0 -14
- opentrons/protocol_engine/commands/heater_shaker/set_and_wait_for_shake_speed.py +4 -5
- opentrons/protocol_engine/commands/heater_shaker/set_target_temperature.py +5 -31
- opentrons/protocol_engine/commands/movement_common.py +0 -2
- opentrons/protocol_engine/commands/pick_up_tip.py +11 -21
- opentrons/protocol_engine/commands/temperature_module/set_target_temperature.py +7 -38
- opentrons/protocol_engine/commands/thermocycler/__init__.py +0 -16
- opentrons/protocol_engine/commands/thermocycler/run_extended_profile.py +0 -6
- opentrons/protocol_engine/commands/thermocycler/run_profile.py +0 -8
- opentrons/protocol_engine/commands/thermocycler/set_target_block_temperature.py +6 -40
- opentrons/protocol_engine/commands/thermocycler/set_target_lid_temperature.py +5 -29
- opentrons/protocol_engine/commands/touch_tip.py +1 -1
- opentrons/protocol_engine/commands/unsafe/unsafe_place_labware.py +22 -6
- opentrons/protocol_engine/errors/__init__.py +0 -4
- opentrons/protocol_engine/errors/exceptions.py +0 -55
- opentrons/protocol_engine/execution/__init__.py +0 -2
- opentrons/protocol_engine/execution/command_executor.py +0 -8
- opentrons/protocol_engine/execution/create_queue_worker.py +1 -5
- opentrons/protocol_engine/execution/labware_movement.py +21 -10
- opentrons/protocol_engine/execution/movement.py +0 -2
- opentrons/protocol_engine/execution/queue_worker.py +0 -4
- opentrons/protocol_engine/execution/run_control.py +0 -8
- opentrons/protocol_engine/protocol_engine.py +34 -75
- opentrons/protocol_engine/resources/__init__.py +0 -2
- opentrons/protocol_engine/resources/deck_configuration_provider.py +0 -7
- opentrons/protocol_engine/resources/labware_validation.py +6 -10
- opentrons/protocol_engine/state/_labware_origin_math.py +636 -0
- opentrons/protocol_engine/state/_well_math.py +18 -60
- opentrons/protocol_engine/state/addressable_areas.py +0 -2
- opentrons/protocol_engine/state/commands.py +11 -14
- opentrons/protocol_engine/state/geometry.py +374 -213
- opentrons/protocol_engine/state/labware.py +102 -52
- opentrons/protocol_engine/state/module_substates/thermocycler_module_substate.py +0 -37
- opentrons/protocol_engine/state/modules.py +8 -21
- opentrons/protocol_engine/state/motion.py +0 -44
- opentrons/protocol_engine/state/state.py +0 -14
- opentrons/protocol_engine/state/state_summary.py +0 -2
- opentrons/protocol_engine/state/tips.py +258 -177
- opentrons/protocol_engine/state/update_types.py +9 -16
- opentrons/protocol_engine/types/__init__.py +3 -9
- opentrons/protocol_engine/types/deck_configuration.py +1 -5
- opentrons/protocol_engine/types/instrument.py +1 -8
- opentrons/protocol_engine/types/labware.py +13 -1
- opentrons/protocol_engine/types/module.py +0 -10
- opentrons/protocol_engine/types/tip.py +0 -9
- opentrons/protocol_runner/create_simulating_orchestrator.py +2 -29
- opentrons/protocol_runner/run_orchestrator.py +2 -18
- opentrons/protocols/api_support/definitions.py +1 -1
- opentrons/protocols/api_support/types.py +1 -2
- opentrons/simulate.py +15 -48
- opentrons/system/camera.py +1 -1
- {opentrons-8.7.0a7.dist-info → opentrons-8.7.0a8.dist-info}/METADATA +4 -4
- {opentrons-8.7.0a7.dist-info → opentrons-8.7.0a8.dist-info}/RECORD +130 -146
- opentrons/protocol_api/core/engine/tasks.py +0 -48
- opentrons/protocol_api/core/legacy/tasks.py +0 -19
- opentrons/protocol_api/core/legacy_simulator/tasks.py +0 -19
- opentrons/protocol_api/core/tasks.py +0 -31
- opentrons/protocol_api/tasks.py +0 -48
- opentrons/protocol_engine/commands/create_timer.py +0 -83
- opentrons/protocol_engine/commands/heater_shaker/common.py +0 -20
- opentrons/protocol_engine/commands/heater_shaker/set_shake_speed.py +0 -136
- opentrons/protocol_engine/commands/set_tip_state.py +0 -97
- opentrons/protocol_engine/commands/thermocycler/start_run_extended_profile.py +0 -191
- opentrons/protocol_engine/commands/wait_for_tasks.py +0 -98
- opentrons/protocol_engine/execution/task_handler.py +0 -157
- opentrons/protocol_engine/resources/concurrency_provider.py +0 -27
- opentrons/protocol_engine/state/labware_origin_math/errors.py +0 -94
- opentrons/protocol_engine/state/labware_origin_math/stackup_origin_to_labware_origin.py +0 -1331
- opentrons/protocol_engine/state/tasks.py +0 -139
- opentrons/protocol_engine/types/tasks.py +0 -38
- {opentrons-8.7.0a7.dist-info → opentrons-8.7.0a8.dist-info}/WHEEL +0 -0
- {opentrons-8.7.0a7.dist-info → opentrons-8.7.0a8.dist-info}/entry_points.txt +0 -0
- {opentrons-8.7.0a7.dist-info → opentrons-8.7.0a8.dist-info}/licenses/LICENSE +0 -0
|
@@ -2,21 +2,19 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
import asyncio
|
|
4
4
|
import logging
|
|
5
|
-
from typing import Optional, Mapping
|
|
5
|
+
from typing import Optional, Mapping
|
|
6
6
|
from typing_extensions import Final
|
|
7
7
|
|
|
8
8
|
from opentrons.drivers.rpi_drivers.types import USBPort
|
|
9
9
|
from opentrons.drivers.heater_shaker.driver import HeaterShakerDriver
|
|
10
10
|
from opentrons.drivers.heater_shaker.abstract import AbstractHeaterShakerDriver
|
|
11
11
|
from opentrons.drivers.heater_shaker.simulator import SimulatingDriver
|
|
12
|
-
from opentrons.drivers.asyncio.communication.errors import UnhandledGcode
|
|
13
12
|
from opentrons.drivers.types import Temperature, RPM, HeaterShakerLabwareLatchStatus
|
|
14
13
|
from opentrons.hardware_control.execution_manager import ExecutionManager
|
|
15
14
|
from opentrons.hardware_control.poller import Reader, Poller
|
|
16
15
|
from opentrons.hardware_control.modules import mod_abc, update
|
|
17
16
|
from opentrons.hardware_control.modules.types import (
|
|
18
17
|
ModuleDisconnectedCallback,
|
|
19
|
-
ModuleErrorCallback,
|
|
20
18
|
ModuleType,
|
|
21
19
|
TemperatureStatus,
|
|
22
20
|
SpeedStatus,
|
|
@@ -49,13 +47,12 @@ class HeaterShaker(mod_abc.AbstractModule):
|
|
|
49
47
|
port: str,
|
|
50
48
|
usb_port: USBPort,
|
|
51
49
|
hw_control_loop: asyncio.AbstractEventLoop,
|
|
52
|
-
execution_manager: ExecutionManager,
|
|
53
|
-
disconnected_callback: ModuleDisconnectedCallback,
|
|
54
|
-
error_callback: ModuleErrorCallback,
|
|
50
|
+
execution_manager: Optional[ExecutionManager] = None,
|
|
55
51
|
poll_interval_seconds: Optional[float] = None,
|
|
56
52
|
simulating: bool = False,
|
|
57
53
|
sim_model: Optional[str] = None,
|
|
58
54
|
sim_serial_number: Optional[str] = None,
|
|
55
|
+
disconnected_callback: ModuleDisconnectedCallback = None,
|
|
59
56
|
) -> "HeaterShaker":
|
|
60
57
|
"""
|
|
61
58
|
Build a HeaterShaker
|
|
@@ -70,7 +67,6 @@ class HeaterShaker(mod_abc.AbstractModule):
|
|
|
70
67
|
loop: Loop
|
|
71
68
|
sim_model: The model name used by simulator
|
|
72
69
|
disconnected_callback: Callback to inform the module controller that the device was disconnected
|
|
73
|
-
error_callback: Callback to inform the module controller of an asynchronous error
|
|
74
70
|
|
|
75
71
|
Returns:
|
|
76
72
|
HeaterShaker instance
|
|
@@ -95,7 +91,6 @@ class HeaterShaker(mod_abc.AbstractModule):
|
|
|
95
91
|
hw_control_loop=hw_control_loop,
|
|
96
92
|
execution_manager=execution_manager,
|
|
97
93
|
disconnected_callback=disconnected_callback,
|
|
98
|
-
error_callback=error_callback,
|
|
99
94
|
)
|
|
100
95
|
|
|
101
96
|
try:
|
|
@@ -114,9 +109,8 @@ class HeaterShaker(mod_abc.AbstractModule):
|
|
|
114
109
|
poller: Poller,
|
|
115
110
|
device_info: Mapping[str, str],
|
|
116
111
|
hw_control_loop: asyncio.AbstractEventLoop,
|
|
117
|
-
execution_manager: ExecutionManager,
|
|
118
|
-
disconnected_callback: ModuleDisconnectedCallback,
|
|
119
|
-
error_callback: ModuleErrorCallback,
|
|
112
|
+
execution_manager: Optional[ExecutionManager] = None,
|
|
113
|
+
disconnected_callback: ModuleDisconnectedCallback = None,
|
|
120
114
|
):
|
|
121
115
|
super().__init__(
|
|
122
116
|
port=port,
|
|
@@ -124,22 +118,14 @@ class HeaterShaker(mod_abc.AbstractModule):
|
|
|
124
118
|
hw_control_loop=hw_control_loop,
|
|
125
119
|
execution_manager=execution_manager,
|
|
126
120
|
disconnected_callback=disconnected_callback,
|
|
127
|
-
error_callback=error_callback,
|
|
128
121
|
)
|
|
129
122
|
self._device_info = device_info
|
|
130
123
|
self._driver = driver
|
|
131
124
|
self._reader = reader
|
|
132
125
|
self._poller = poller
|
|
133
|
-
self._unsubscribe_reader = self._reader.register_error_handler(
|
|
134
|
-
self._handle_error
|
|
135
|
-
)
|
|
136
|
-
|
|
137
|
-
def _handle_error(self, error: Exception) -> None:
|
|
138
|
-
self.error_callback(error)
|
|
139
126
|
|
|
140
127
|
async def cleanup(self) -> None:
|
|
141
128
|
"""Stop the poller task"""
|
|
142
|
-
self._unsubscribe_reader()
|
|
143
129
|
await self._poller.stop()
|
|
144
130
|
await self._driver.disconnect()
|
|
145
131
|
|
|
@@ -411,22 +397,11 @@ class HeaterShakerReader(Reader):
|
|
|
411
397
|
self.labware_latch = HeaterShakerLabwareLatchStatus.IDLE_UNKNOWN
|
|
412
398
|
self.error: Optional[str] = None
|
|
413
399
|
self._driver = driver
|
|
414
|
-
self._handle_error: Callable[[Exception], None] | None = None
|
|
415
|
-
|
|
416
|
-
def register_error_handler(
|
|
417
|
-
self, handle_error: Callable[[Exception], None]
|
|
418
|
-
) -> Callable[[], None]:
|
|
419
|
-
self._handle_error = handle_error
|
|
420
|
-
return self._unsubscribe_error_handler
|
|
421
|
-
|
|
422
|
-
def _unsubscribe_error_handler(self) -> None:
|
|
423
|
-
self._handle_error = None
|
|
424
400
|
|
|
425
401
|
async def read(self) -> None:
|
|
426
402
|
await self.read_temperature()
|
|
427
403
|
await self.read_rpm()
|
|
428
404
|
await self.read_labware_latch()
|
|
429
|
-
await self._read_errors()
|
|
430
405
|
self._set_error(None)
|
|
431
406
|
|
|
432
407
|
def on_error(self, exception: Exception) -> None:
|
|
@@ -445,19 +420,7 @@ class HeaterShakerReader(Reader):
|
|
|
445
420
|
if exception is None:
|
|
446
421
|
self.error = None
|
|
447
422
|
else:
|
|
448
|
-
if self._handle_error:
|
|
449
|
-
self._handle_error(exception)
|
|
450
423
|
try:
|
|
451
424
|
self.error = str(exception.args[0])
|
|
452
425
|
except Exception:
|
|
453
426
|
self.error = repr(exception)
|
|
454
|
-
|
|
455
|
-
async def _read_errors(self) -> None:
|
|
456
|
-
try:
|
|
457
|
-
await self._driver.get_error_state()
|
|
458
|
-
except UnhandledGcode:
|
|
459
|
-
# This device's firmware cannot accept this command, because it
|
|
460
|
-
# hasn't been updated or because it's a gen1. Ignore the result.
|
|
461
|
-
pass
|
|
462
|
-
# If the error is one we should let pass, raise it so the top level
|
|
463
|
-
# error handler can take it.
|
|
@@ -49,13 +49,12 @@ class MagDeck(mod_abc.AbstractModule):
|
|
|
49
49
|
port: str,
|
|
50
50
|
usb_port: USBPort,
|
|
51
51
|
hw_control_loop: asyncio.AbstractEventLoop,
|
|
52
|
-
execution_manager: ExecutionManager,
|
|
53
|
-
disconnected_callback: types.ModuleDisconnectedCallback,
|
|
54
|
-
error_callback: types.ModuleErrorCallback,
|
|
52
|
+
execution_manager: Optional[ExecutionManager] = None,
|
|
55
53
|
poll_interval_seconds: Optional[float] = None,
|
|
56
54
|
simulating: bool = False,
|
|
57
55
|
sim_model: Optional[str] = None,
|
|
58
56
|
sim_serial_number: Optional[str] = None,
|
|
57
|
+
disconnected_callback: types.ModuleDisconnectedCallback = None,
|
|
59
58
|
) -> "MagDeck":
|
|
60
59
|
"""Factory function."""
|
|
61
60
|
driver: AbstractMagDeckDriver
|
|
@@ -74,7 +73,6 @@ class MagDeck(mod_abc.AbstractModule):
|
|
|
74
73
|
device_info=await driver.get_device_info(),
|
|
75
74
|
driver=driver,
|
|
76
75
|
disconnected_callback=disconnected_callback,
|
|
77
|
-
error_callback=error_callback,
|
|
78
76
|
)
|
|
79
77
|
return mod
|
|
80
78
|
|
|
@@ -85,9 +83,8 @@ class MagDeck(mod_abc.AbstractModule):
|
|
|
85
83
|
hw_control_loop: asyncio.AbstractEventLoop,
|
|
86
84
|
driver: AbstractMagDeckDriver,
|
|
87
85
|
device_info: Dict[str, str],
|
|
88
|
-
execution_manager: ExecutionManager,
|
|
89
|
-
disconnected_callback: types.ModuleDisconnectedCallback,
|
|
90
|
-
error_callback: types.ModuleErrorCallback,
|
|
86
|
+
execution_manager: Optional[ExecutionManager] = None,
|
|
87
|
+
disconnected_callback: types.ModuleDisconnectedCallback = None,
|
|
91
88
|
) -> None:
|
|
92
89
|
"""Constructor"""
|
|
93
90
|
super().__init__(
|
|
@@ -96,7 +93,6 @@ class MagDeck(mod_abc.AbstractModule):
|
|
|
96
93
|
hw_control_loop=hw_control_loop,
|
|
97
94
|
execution_manager=execution_manager,
|
|
98
95
|
disconnected_callback=disconnected_callback,
|
|
99
|
-
error_callback=error_callback,
|
|
100
96
|
)
|
|
101
97
|
self._device_info = device_info
|
|
102
98
|
self._driver = driver
|
|
@@ -11,7 +11,6 @@ from ..execution_manager import ExecutionManager
|
|
|
11
11
|
from .types import (
|
|
12
12
|
BundledFirmware,
|
|
13
13
|
ModuleDisconnectedCallback,
|
|
14
|
-
ModuleErrorCallback,
|
|
15
14
|
UploadFunction,
|
|
16
15
|
LiveData,
|
|
17
16
|
ModuleType,
|
|
@@ -48,13 +47,12 @@ class AbstractModule(abc.ABC):
|
|
|
48
47
|
port: str,
|
|
49
48
|
usb_port: USBPort,
|
|
50
49
|
hw_control_loop: asyncio.AbstractEventLoop,
|
|
51
|
-
execution_manager: ExecutionManager,
|
|
52
|
-
|
|
53
|
-
error_callback: ModuleErrorCallback,
|
|
54
|
-
poll_interval_seconds: float | None = None,
|
|
50
|
+
execution_manager: Optional[ExecutionManager] = None,
|
|
51
|
+
poll_interval_seconds: Optional[float] = None,
|
|
55
52
|
simulating: bool = False,
|
|
56
53
|
sim_model: Optional[str] = None,
|
|
57
54
|
sim_serial_number: Optional[str] = None,
|
|
55
|
+
disconnected_callback: ModuleDisconnectedCallback = None,
|
|
58
56
|
) -> "AbstractModule":
|
|
59
57
|
"""Modules should always be created using this factory.
|
|
60
58
|
|
|
@@ -67,9 +65,8 @@ class AbstractModule(abc.ABC):
|
|
|
67
65
|
port: str,
|
|
68
66
|
usb_port: USBPort,
|
|
69
67
|
hw_control_loop: asyncio.AbstractEventLoop,
|
|
70
|
-
execution_manager: ExecutionManager,
|
|
71
|
-
disconnected_callback: ModuleDisconnectedCallback,
|
|
72
|
-
error_callback: ModuleErrorCallback,
|
|
68
|
+
execution_manager: Optional[ExecutionManager] = None,
|
|
69
|
+
disconnected_callback: ModuleDisconnectedCallback = None,
|
|
73
70
|
) -> None:
|
|
74
71
|
self._port = port
|
|
75
72
|
self._usb_port = usb_port
|
|
@@ -78,7 +75,6 @@ class AbstractModule(abc.ABC):
|
|
|
78
75
|
self._bundled_fw: Optional[BundledFirmware] = self.get_bundled_fw()
|
|
79
76
|
self._disconnected_callback = disconnected_callback
|
|
80
77
|
self._updating = False
|
|
81
|
-
self._error_callback = error_callback
|
|
82
78
|
|
|
83
79
|
@staticmethod
|
|
84
80
|
def sort_key(inst: "AbstractModule") -> int:
|
|
@@ -107,10 +103,6 @@ class AbstractModule(abc.ABC):
|
|
|
107
103
|
if self._disconnected_callback is not None:
|
|
108
104
|
self._disconnected_callback(self.port, self.serial_number)
|
|
109
105
|
|
|
110
|
-
def error_callback(self, exc: Exception) -> None:
|
|
111
|
-
"""Called from within the module object when an asynchronous hardware error occurrs."""
|
|
112
|
-
self._error_callback(exc, self.model(), self.port, self.serial_number)
|
|
113
|
-
|
|
114
106
|
def get_bundled_fw(self) -> Optional[BundledFirmware]:
|
|
115
107
|
"""Get absolute path to bundled version of module fw if available."""
|
|
116
108
|
if not IS_ROBOT:
|
|
@@ -2,11 +2,10 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
import asyncio
|
|
4
4
|
import logging
|
|
5
|
-
from typing import Dict, Optional
|
|
5
|
+
from typing import Dict, Optional
|
|
6
6
|
|
|
7
7
|
from opentrons.hardware_control.modules.types import (
|
|
8
8
|
ModuleDisconnectedCallback,
|
|
9
|
-
ModuleErrorCallback,
|
|
10
9
|
TemperatureStatus,
|
|
11
10
|
)
|
|
12
11
|
from opentrons.hardware_control.poller import Reader, Poller
|
|
@@ -39,13 +38,12 @@ class TempDeck(mod_abc.AbstractModule):
|
|
|
39
38
|
port: str,
|
|
40
39
|
usb_port: USBPort,
|
|
41
40
|
hw_control_loop: asyncio.AbstractEventLoop,
|
|
42
|
-
execution_manager: ExecutionManager,
|
|
43
|
-
disconnected_callback: ModuleDisconnectedCallback,
|
|
44
|
-
error_callback: ModuleErrorCallback,
|
|
41
|
+
execution_manager: Optional[ExecutionManager] = None,
|
|
45
42
|
poll_interval_seconds: Optional[float] = None,
|
|
46
43
|
simulating: bool = False,
|
|
47
44
|
sim_model: Optional[str] = None,
|
|
48
45
|
sim_serial_number: Optional[str] = None,
|
|
46
|
+
disconnected_callback: ModuleDisconnectedCallback = None,
|
|
49
47
|
) -> "TempDeck":
|
|
50
48
|
"""
|
|
51
49
|
Build a TempDeck
|
|
@@ -85,7 +83,6 @@ class TempDeck(mod_abc.AbstractModule):
|
|
|
85
83
|
device_info=await driver.get_device_info(),
|
|
86
84
|
hw_control_loop=hw_control_loop,
|
|
87
85
|
disconnected_callback=disconnected_callback,
|
|
88
|
-
error_callback=error_callback,
|
|
89
86
|
)
|
|
90
87
|
|
|
91
88
|
try:
|
|
@@ -104,9 +101,8 @@ class TempDeck(mod_abc.AbstractModule):
|
|
|
104
101
|
poller: Poller,
|
|
105
102
|
device_info: Dict[str, str],
|
|
106
103
|
hw_control_loop: asyncio.AbstractEventLoop,
|
|
107
|
-
execution_manager: ExecutionManager,
|
|
108
|
-
disconnected_callback: ModuleDisconnectedCallback,
|
|
109
|
-
error_callback: ModuleErrorCallback,
|
|
104
|
+
execution_manager: Optional[ExecutionManager] = None,
|
|
105
|
+
disconnected_callback: ModuleDisconnectedCallback = None,
|
|
110
106
|
) -> None:
|
|
111
107
|
"""Constructor"""
|
|
112
108
|
super().__init__(
|
|
@@ -115,13 +111,11 @@ class TempDeck(mod_abc.AbstractModule):
|
|
|
115
111
|
hw_control_loop=hw_control_loop,
|
|
116
112
|
execution_manager=execution_manager,
|
|
117
113
|
disconnected_callback=disconnected_callback,
|
|
118
|
-
error_callback=error_callback,
|
|
119
114
|
)
|
|
120
115
|
self._device_info = device_info
|
|
121
116
|
self._driver = driver
|
|
122
117
|
self._reader = reader
|
|
123
118
|
self._poller = poller
|
|
124
|
-
self._reader.set_error_callback(self.error_callback)
|
|
125
119
|
|
|
126
120
|
async def cleanup(self) -> None:
|
|
127
121
|
"""Stop the poller task."""
|
|
@@ -299,21 +293,7 @@ class TempDeckReader(Reader):
|
|
|
299
293
|
def __init__(self, driver: AbstractTempDeckDriver) -> None:
|
|
300
294
|
self.temperature = Temperature(current=25, target=None)
|
|
301
295
|
self._driver = driver
|
|
302
|
-
self._error_callback: Optional[Callable[[Exception], None]] = None
|
|
303
296
|
|
|
304
297
|
async def read(self) -> None:
|
|
305
298
|
"""Read the module's current and target temperatures."""
|
|
306
299
|
self.temperature = await self._driver.get_temperature()
|
|
307
|
-
|
|
308
|
-
def set_error_callback(
|
|
309
|
-
self, error_callback: Callable[[Exception], None]
|
|
310
|
-
) -> Callable[[], None]:
|
|
311
|
-
self._error_callback = error_callback
|
|
312
|
-
return self._remove_error_callback
|
|
313
|
-
|
|
314
|
-
def _remove_error_callback(self) -> None:
|
|
315
|
-
self._error_callback = None
|
|
316
|
-
|
|
317
|
-
def on_error(self, exception: Exception) -> None:
|
|
318
|
-
if self._error_callback:
|
|
319
|
-
self._error_callback(exception)
|
|
@@ -9,7 +9,6 @@ from opentrons.hardware_control.modules.lid_temp_status import LidTemperatureSta
|
|
|
9
9
|
from opentrons.hardware_control.modules.plate_temp_status import PlateTemperatureStatus
|
|
10
10
|
from opentrons.hardware_control.modules.types import (
|
|
11
11
|
ModuleDisconnectedCallback,
|
|
12
|
-
ModuleErrorCallback,
|
|
13
12
|
TemperatureStatus,
|
|
14
13
|
)
|
|
15
14
|
from opentrons.hardware_control.poller import Reader, Poller
|
|
@@ -22,7 +21,6 @@ from opentrons.drivers.thermocycler import (
|
|
|
22
21
|
ThermocyclerDriverV2,
|
|
23
22
|
ThermocyclerDriverFactory,
|
|
24
23
|
)
|
|
25
|
-
from opentrons.drivers.asyncio.communication.errors import UnhandledGcode
|
|
26
24
|
|
|
27
25
|
|
|
28
26
|
log = logging.getLogger(__name__)
|
|
@@ -38,8 +36,6 @@ DFU_PID = "df11"
|
|
|
38
36
|
_TC_PLATE_LIFT_OPEN_DEGREES = 20
|
|
39
37
|
_TC_PLATE_LIFT_RETURN_DEGREES = 23
|
|
40
38
|
|
|
41
|
-
_TC_RAMP_RATE_ADDED_VERSION = (1, 0, 8) # v1.0.8
|
|
42
|
-
|
|
43
39
|
|
|
44
40
|
class ThermocyclerError(Exception):
|
|
45
41
|
pass
|
|
@@ -66,13 +62,12 @@ class Thermocycler(mod_abc.AbstractModule):
|
|
|
66
62
|
port: str,
|
|
67
63
|
usb_port: USBPort,
|
|
68
64
|
hw_control_loop: asyncio.AbstractEventLoop,
|
|
69
|
-
execution_manager: ExecutionManager,
|
|
70
|
-
disconnected_callback: ModuleDisconnectedCallback,
|
|
71
|
-
error_callback: ModuleErrorCallback,
|
|
65
|
+
execution_manager: Optional[ExecutionManager] = None,
|
|
72
66
|
poll_interval_seconds: Optional[float] = None,
|
|
73
67
|
simulating: bool = False,
|
|
74
68
|
sim_model: Optional[str] = None,
|
|
75
69
|
sim_serial_number: Optional[str] = None,
|
|
70
|
+
disconnected_callback: ModuleDisconnectedCallback = None,
|
|
76
71
|
) -> "Thermocycler":
|
|
77
72
|
"""
|
|
78
73
|
Build and connect to a Thermocycler
|
|
@@ -113,7 +108,6 @@ class Thermocycler(mod_abc.AbstractModule):
|
|
|
113
108
|
hw_control_loop=hw_control_loop,
|
|
114
109
|
execution_manager=execution_manager,
|
|
115
110
|
disconnected_callback=disconnected_callback,
|
|
116
|
-
error_callback=error_callback,
|
|
117
111
|
)
|
|
118
112
|
|
|
119
113
|
try:
|
|
@@ -132,9 +126,8 @@ class Thermocycler(mod_abc.AbstractModule):
|
|
|
132
126
|
poller: Poller,
|
|
133
127
|
device_info: Dict[str, str],
|
|
134
128
|
hw_control_loop: asyncio.AbstractEventLoop,
|
|
135
|
-
execution_manager: ExecutionManager,
|
|
136
|
-
disconnected_callback: ModuleDisconnectedCallback,
|
|
137
|
-
error_callback: ModuleErrorCallback,
|
|
129
|
+
execution_manager: Optional[ExecutionManager] = None,
|
|
130
|
+
disconnected_callback: ModuleDisconnectedCallback = None,
|
|
138
131
|
) -> None:
|
|
139
132
|
"""
|
|
140
133
|
Constructor
|
|
@@ -157,7 +150,6 @@ class Thermocycler(mod_abc.AbstractModule):
|
|
|
157
150
|
hw_control_loop=hw_control_loop,
|
|
158
151
|
execution_manager=execution_manager,
|
|
159
152
|
disconnected_callback=disconnected_callback,
|
|
160
|
-
error_callback=error_callback,
|
|
161
153
|
)
|
|
162
154
|
self._device_info = device_info
|
|
163
155
|
self._reader = reader
|
|
@@ -167,13 +159,10 @@ class Thermocycler(mod_abc.AbstractModule):
|
|
|
167
159
|
self._total_step_count: Optional[int] = None
|
|
168
160
|
self._current_step_index: Optional[int] = None
|
|
169
161
|
self._error: Optional[str] = None
|
|
170
|
-
self.
|
|
171
|
-
self._enter_error_state
|
|
172
|
-
)
|
|
162
|
+
self._reader.register_error_handler(self._enter_error_state)
|
|
173
163
|
|
|
174
164
|
async def cleanup(self) -> None:
|
|
175
165
|
"""Stop the poller task."""
|
|
176
|
-
self._unsubscribe_reader()
|
|
177
166
|
await self._poller.stop()
|
|
178
167
|
await self._driver.disconnect()
|
|
179
168
|
|
|
@@ -276,19 +265,6 @@ class Thermocycler(mod_abc.AbstractModule):
|
|
|
276
265
|
await self.open()
|
|
277
266
|
await self._wait_for_lid_status(ThermocyclerLidStatus.OPEN)
|
|
278
267
|
|
|
279
|
-
def can_use_ramp_rate(self) -> bool:
|
|
280
|
-
version_string = self._device_info.get("version", "v")
|
|
281
|
-
if version_string.startswith("v"):
|
|
282
|
-
version_string = version_string[1:]
|
|
283
|
-
try:
|
|
284
|
-
version_tuple = tuple(int(c) for c in version_string.split("."))
|
|
285
|
-
return version_tuple >= _TC_RAMP_RATE_ADDED_VERSION
|
|
286
|
-
except (ValueError, IndexError):
|
|
287
|
-
log.error(
|
|
288
|
-
f"Invalid version from device: {self._device_info.get('version', '')}"
|
|
289
|
-
)
|
|
290
|
-
return False
|
|
291
|
-
|
|
292
268
|
async def set_temperature(
|
|
293
269
|
self,
|
|
294
270
|
temperature: float,
|
|
@@ -314,11 +290,6 @@ class Thermocycler(mod_abc.AbstractModule):
|
|
|
314
290
|
|
|
315
291
|
Returns: None
|
|
316
292
|
"""
|
|
317
|
-
if ramp_rate and not self.can_use_ramp_rate():
|
|
318
|
-
raise ThermocyclerError(
|
|
319
|
-
"Ramp rate is not supported by this thermocycler's firmware version, please update."
|
|
320
|
-
)
|
|
321
|
-
|
|
322
293
|
await self.wait_for_is_running()
|
|
323
294
|
await self._set_temperature_no_pause(
|
|
324
295
|
temperature=temperature,
|
|
@@ -341,13 +312,11 @@ class Thermocycler(mod_abc.AbstractModule):
|
|
|
341
312
|
total_seconds = seconds + (minutes * 60)
|
|
342
313
|
hold_time = total_seconds if total_seconds > 0 else 0
|
|
343
314
|
|
|
344
|
-
if ramp_rate
|
|
345
|
-
|
|
346
|
-
"Ramp rate is not supported by this thermocycler's firmware version, please update."
|
|
347
|
-
)
|
|
315
|
+
if ramp_rate is not None:
|
|
316
|
+
await self._driver.set_ramp_rate(ramp_rate=ramp_rate)
|
|
348
317
|
|
|
349
318
|
await self._driver.set_plate_temperature(
|
|
350
|
-
temp=temperature, hold_time=hold_time, volume=volume
|
|
319
|
+
temp=temperature, hold_time=hold_time, volume=volume
|
|
351
320
|
)
|
|
352
321
|
|
|
353
322
|
task = self._loop.create_task(self._wait_for_block_target())
|
|
@@ -450,7 +419,6 @@ class Thermocycler(mod_abc.AbstractModule):
|
|
|
450
419
|
celsius: float,
|
|
451
420
|
hold_time_seconds: Optional[float] = None,
|
|
452
421
|
volume: Optional[float] = None,
|
|
453
|
-
ramp_rate: Optional[float] = None,
|
|
454
422
|
) -> None:
|
|
455
423
|
"""Set the Thermocycler's target block temperature.
|
|
456
424
|
|
|
@@ -460,17 +428,10 @@ class Thermocycler(mod_abc.AbstractModule):
|
|
|
460
428
|
celsius: The target block temperature, in degrees celsius.
|
|
461
429
|
"""
|
|
462
430
|
await self.wait_for_is_running()
|
|
463
|
-
|
|
464
|
-
if ramp_rate and not self.can_use_ramp_rate():
|
|
465
|
-
raise ThermocyclerError(
|
|
466
|
-
"Ramp rate is not supported by this thermocycler's firmware version, please update."
|
|
467
|
-
)
|
|
468
|
-
|
|
469
431
|
await self._driver.set_plate_temperature(
|
|
470
432
|
temp=celsius,
|
|
471
433
|
hold_time=hold_time_seconds,
|
|
472
434
|
volume=volume,
|
|
473
|
-
ramp_rate=ramp_rate,
|
|
474
435
|
)
|
|
475
436
|
await self._reader.read_block_temperature()
|
|
476
437
|
|
|
@@ -635,12 +596,11 @@ class Thermocycler(mod_abc.AbstractModule):
|
|
|
635
596
|
temperature = step.get("temperature")
|
|
636
597
|
hold_time_minutes = step.get("hold_time_minutes", None)
|
|
637
598
|
hold_time_seconds = step.get("hold_time_seconds", None)
|
|
638
|
-
ramp_rate = step.get("ramp_rate", None)
|
|
639
599
|
await self._set_temperature_no_pause(
|
|
640
600
|
temperature=temperature, # type: ignore
|
|
641
601
|
hold_time_minutes=hold_time_minutes,
|
|
642
602
|
hold_time_seconds=hold_time_seconds,
|
|
643
|
-
ramp_rate=
|
|
603
|
+
ramp_rate=None,
|
|
644
604
|
volume=volume,
|
|
645
605
|
)
|
|
646
606
|
|
|
@@ -712,7 +672,7 @@ class Thermocycler(mod_abc.AbstractModule):
|
|
|
712
672
|
f"https://support.opentrons.com/en/articles/3469797-thermocycler-module"
|
|
713
673
|
f" for troubleshooting."
|
|
714
674
|
)
|
|
715
|
-
self.
|
|
675
|
+
asyncio.run_coroutine_threadsafe(self.cleanup(), self._loop)
|
|
716
676
|
|
|
717
677
|
|
|
718
678
|
class ThermocyclerReader(Reader):
|
|
@@ -750,31 +710,14 @@ class ThermocyclerReader(Reader):
|
|
|
750
710
|
if self._handle_error is not None:
|
|
751
711
|
self._handle_error(exception)
|
|
752
712
|
|
|
753
|
-
def register_error_handler(
|
|
754
|
-
self, handle_error: Callable[[Exception], None]
|
|
755
|
-
) -> Callable[[], None]:
|
|
713
|
+
def register_error_handler(self, handle_error: Callable[[Exception], None]) -> None:
|
|
756
714
|
self._handle_error = handle_error
|
|
757
|
-
return self._unsubscribe_error_handler
|
|
758
|
-
|
|
759
|
-
def _unsubscribe_error_handler(self) -> None:
|
|
760
|
-
self._handle_error = None
|
|
761
715
|
|
|
762
716
|
async def read(self) -> None:
|
|
763
717
|
"""Poll the thermocycler."""
|
|
764
718
|
await self.read_lid_status()
|
|
765
719
|
await self.read_lid_temperature()
|
|
766
720
|
await self.read_block_temperature()
|
|
767
|
-
await self._read_errors()
|
|
768
|
-
|
|
769
|
-
async def _read_errors(self) -> None:
|
|
770
|
-
try:
|
|
771
|
-
await self._driver.get_error_state()
|
|
772
|
-
except UnhandledGcode:
|
|
773
|
-
# This device's firmware cannot accept this command, because it
|
|
774
|
-
# hasn't been updated or because it's a gen1. Ignore the result.
|
|
775
|
-
pass
|
|
776
|
-
# If the error is one we should let pass, raise it so the top level
|
|
777
|
-
# error handler can take it.
|
|
778
721
|
|
|
779
722
|
async def read_lid_status(self) -> None:
|
|
780
723
|
self.lid_status = await self._driver.get_lid_status()
|
|
@@ -11,7 +11,6 @@ from typing import (
|
|
|
11
11
|
Awaitable,
|
|
12
12
|
Union,
|
|
13
13
|
Optional,
|
|
14
|
-
Protocol,
|
|
15
14
|
cast,
|
|
16
15
|
TYPE_CHECKING,
|
|
17
16
|
TypeGuard,
|
|
@@ -45,7 +44,6 @@ class ThermocyclerStepBase(TypedDict):
|
|
|
45
44
|
class ThermocyclerStep(ThermocyclerStepBase, total=False):
|
|
46
45
|
hold_time_seconds: float
|
|
47
46
|
hold_time_minutes: float
|
|
48
|
-
ramp_rate: Optional[float]
|
|
49
47
|
|
|
50
48
|
|
|
51
49
|
class ThermocyclerCycle(TypedDict):
|
|
@@ -56,24 +54,7 @@ class ThermocyclerCycle(TypedDict):
|
|
|
56
54
|
UploadFunction = Callable[[str, str, Dict[str, Any]], Awaitable[Tuple[bool, str]]]
|
|
57
55
|
|
|
58
56
|
|
|
59
|
-
|
|
60
|
-
"""Protocol for the callback when the module should be disconnected."""
|
|
61
|
-
|
|
62
|
-
def __call__(self, port: str, serial: str | None) -> None:
|
|
63
|
-
...
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
class ModuleErrorCallback(Protocol):
|
|
67
|
-
"""Protocol for the callback when the module sees a hardware error."""
|
|
68
|
-
|
|
69
|
-
def __call__(
|
|
70
|
-
self,
|
|
71
|
-
exc: Exception,
|
|
72
|
-
model: str,
|
|
73
|
-
port: str,
|
|
74
|
-
serial: str | None,
|
|
75
|
-
) -> None:
|
|
76
|
-
...
|
|
57
|
+
ModuleDisconnectedCallback = Optional[Callable[[str, str | None], None]]
|
|
77
58
|
|
|
78
59
|
|
|
79
60
|
class MagneticModuleData(TypedDict):
|
|
@@ -6,12 +6,7 @@ from opentrons.drivers.rpi_drivers.types import USBPort
|
|
|
6
6
|
|
|
7
7
|
from ..execution_manager import ExecutionManager
|
|
8
8
|
|
|
9
|
-
from .types import
|
|
10
|
-
ModuleDisconnectedCallback,
|
|
11
|
-
ModuleType,
|
|
12
|
-
SpeedStatus,
|
|
13
|
-
ModuleErrorCallback,
|
|
14
|
-
)
|
|
9
|
+
from .types import ModuleDisconnectedCallback, ModuleType, SpeedStatus
|
|
15
10
|
from .mod_abc import AbstractModule
|
|
16
11
|
from .tempdeck import TempDeck
|
|
17
12
|
from .magdeck import MagDeck
|
|
@@ -51,11 +46,10 @@ async def build(
|
|
|
51
46
|
simulating: bool,
|
|
52
47
|
usb_port: USBPort,
|
|
53
48
|
hw_control_loop: asyncio.AbstractEventLoop,
|
|
54
|
-
execution_manager: ExecutionManager,
|
|
55
|
-
disconnected_callback: ModuleDisconnectedCallback,
|
|
56
|
-
error_callback: ModuleErrorCallback,
|
|
49
|
+
execution_manager: Optional[ExecutionManager] = None,
|
|
57
50
|
sim_model: Optional[str] = None,
|
|
58
51
|
sim_serial_number: Optional[str] = None,
|
|
52
|
+
disconnected_callback: ModuleDisconnectedCallback = None,
|
|
59
53
|
) -> AbstractModule:
|
|
60
54
|
return await _MODULE_CLS_BY_TYPE[type].build(
|
|
61
55
|
port=port,
|
|
@@ -63,10 +57,9 @@ async def build(
|
|
|
63
57
|
simulating=simulating,
|
|
64
58
|
hw_control_loop=hw_control_loop,
|
|
65
59
|
execution_manager=execution_manager,
|
|
66
|
-
disconnected_callback=disconnected_callback,
|
|
67
|
-
error_callback=error_callback,
|
|
68
60
|
sim_model=sim_model,
|
|
69
61
|
sim_serial_number=sim_serial_number,
|
|
62
|
+
disconnected_callback=disconnected_callback,
|
|
70
63
|
)
|
|
71
64
|
|
|
72
65
|
|
|
@@ -77,8 +77,6 @@ class NozzleMap:
|
|
|
77
77
|
#: A map of all of the nozzles of an instrument
|
|
78
78
|
full_instrument_rows: Dict[str, List[str]]
|
|
79
79
|
#: A map of all the rows of an instrument
|
|
80
|
-
full_instrument_columns: Dict[str, List[str]]
|
|
81
|
-
#: A map of all the columns of an instrument
|
|
82
80
|
|
|
83
81
|
@classmethod
|
|
84
82
|
def determine_nozzle_configuration(
|
|
@@ -301,7 +299,6 @@ class NozzleMap:
|
|
|
301
299
|
rows=rows,
|
|
302
300
|
full_instrument_map_store=physical_nozzles,
|
|
303
301
|
full_instrument_rows=physical_rows,
|
|
304
|
-
full_instrument_columns=physical_columns,
|
|
305
302
|
columns=columns,
|
|
306
303
|
configuration=cls.determine_nozzle_configuration(
|
|
307
304
|
physical_rows, rows, physical_columns, columns
|