opentrons 8.7.0a2__py3-none-any.whl → 8.7.0a4__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/thermocycler/abstract.py +0 -1
- opentrons/drivers/thermocycler/driver.py +4 -33
- opentrons/drivers/thermocycler/simulator.py +0 -2
- opentrons/hardware_control/api.py +5 -24
- opentrons/hardware_control/backends/controller.py +2 -8
- opentrons/hardware_control/backends/ot3controller.py +0 -3
- opentrons/hardware_control/backends/ot3simulator.py +1 -2
- opentrons/hardware_control/backends/simulator.py +1 -2
- opentrons/hardware_control/backends/subsystem_manager.py +2 -5
- 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 -30
- 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 +10 -56
- 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 +5 -26
- opentrons/hardware_control/scripts/update_module_fw.py +0 -5
- opentrons/hardware_control/types.py +2 -31
- opentrons/legacy_commands/protocol_commands.py +0 -20
- opentrons/legacy_commands/types.py +0 -42
- opentrons/motion_planning/waypoints.py +29 -15
- opentrons/protocol_api/__init__.py +0 -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 +0 -4
- opentrons/protocol_api/core/engine/protocol.py +43 -23
- opentrons/protocol_api/core/legacy/legacy_module_core.py +0 -2
- opentrons/protocol_api/core/legacy/legacy_protocol_core.py +1 -11
- opentrons/protocol_api/core/legacy_simulator/legacy_protocol_core.py +2 -14
- opentrons/protocol_api/core/module.py +0 -1
- opentrons/protocol_api/core/protocol.py +2 -11
- opentrons/protocol_api/module_contexts.py +0 -1
- 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 -6
- 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 -39
- opentrons/protocol_engine/commands/dispense.py +0 -1
- opentrons/protocol_engine/commands/drop_tip.py +8 -32
- opentrons/protocol_engine/commands/movement_common.py +0 -2
- opentrons/protocol_engine/commands/pick_up_tip.py +11 -21
- 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 +1 -17
- 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 +12 -9
- 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 +33 -67
- 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 +7 -7
- opentrons/protocol_engine/state/geometry.py +374 -204
- 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.0a2.dist-info → opentrons-8.7.0a4.dist-info}/METADATA +4 -4
- {opentrons-8.7.0a2.dist-info → opentrons-8.7.0a4.dist-info}/RECORD +105 -118
- opentrons/protocol_api/core/engine/tasks.py +0 -35
- 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/set_tip_state.py +0 -97
- 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.0a2.dist-info → opentrons-8.7.0a4.dist-info}/WHEEL +0 -0
- {opentrons-8.7.0a2.dist-info → opentrons-8.7.0a4.dist-info}/entry_points.txt +0 -0
- {opentrons-8.7.0a2.dist-info → opentrons-8.7.0a4.dist-info}/licenses/LICENSE +0 -0
|
@@ -2,7 +2,7 @@ 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
|
|
@@ -15,7 +15,6 @@ from opentrons.hardware_control.poller import Reader, Poller
|
|
|
15
15
|
from opentrons.hardware_control.modules import mod_abc, update
|
|
16
16
|
from opentrons.hardware_control.modules.types import (
|
|
17
17
|
ModuleDisconnectedCallback,
|
|
18
|
-
ModuleErrorCallback,
|
|
19
18
|
ModuleType,
|
|
20
19
|
TemperatureStatus,
|
|
21
20
|
SpeedStatus,
|
|
@@ -48,13 +47,12 @@ class HeaterShaker(mod_abc.AbstractModule):
|
|
|
48
47
|
port: str,
|
|
49
48
|
usb_port: USBPort,
|
|
50
49
|
hw_control_loop: asyncio.AbstractEventLoop,
|
|
51
|
-
execution_manager: ExecutionManager,
|
|
52
|
-
disconnected_callback: ModuleDisconnectedCallback,
|
|
53
|
-
error_callback: ModuleErrorCallback,
|
|
50
|
+
execution_manager: Optional[ExecutionManager] = None,
|
|
54
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
|
) -> "HeaterShaker":
|
|
59
57
|
"""
|
|
60
58
|
Build a HeaterShaker
|
|
@@ -69,7 +67,6 @@ class HeaterShaker(mod_abc.AbstractModule):
|
|
|
69
67
|
loop: Loop
|
|
70
68
|
sim_model: The model name used by simulator
|
|
71
69
|
disconnected_callback: Callback to inform the module controller that the device was disconnected
|
|
72
|
-
error_callback: Callback to inform the module controller of an asynchronous error
|
|
73
70
|
|
|
74
71
|
Returns:
|
|
75
72
|
HeaterShaker instance
|
|
@@ -94,7 +91,6 @@ class HeaterShaker(mod_abc.AbstractModule):
|
|
|
94
91
|
hw_control_loop=hw_control_loop,
|
|
95
92
|
execution_manager=execution_manager,
|
|
96
93
|
disconnected_callback=disconnected_callback,
|
|
97
|
-
error_callback=error_callback,
|
|
98
94
|
)
|
|
99
95
|
|
|
100
96
|
try:
|
|
@@ -113,9 +109,8 @@ class HeaterShaker(mod_abc.AbstractModule):
|
|
|
113
109
|
poller: Poller,
|
|
114
110
|
device_info: Mapping[str, str],
|
|
115
111
|
hw_control_loop: asyncio.AbstractEventLoop,
|
|
116
|
-
execution_manager: ExecutionManager,
|
|
117
|
-
disconnected_callback: ModuleDisconnectedCallback,
|
|
118
|
-
error_callback: ModuleErrorCallback,
|
|
112
|
+
execution_manager: Optional[ExecutionManager] = None,
|
|
113
|
+
disconnected_callback: ModuleDisconnectedCallback = None,
|
|
119
114
|
):
|
|
120
115
|
super().__init__(
|
|
121
116
|
port=port,
|
|
@@ -123,22 +118,14 @@ class HeaterShaker(mod_abc.AbstractModule):
|
|
|
123
118
|
hw_control_loop=hw_control_loop,
|
|
124
119
|
execution_manager=execution_manager,
|
|
125
120
|
disconnected_callback=disconnected_callback,
|
|
126
|
-
error_callback=error_callback,
|
|
127
121
|
)
|
|
128
122
|
self._device_info = device_info
|
|
129
123
|
self._driver = driver
|
|
130
124
|
self._reader = reader
|
|
131
125
|
self._poller = poller
|
|
132
|
-
self._unsubscribe_reader = self._reader.register_error_handler(
|
|
133
|
-
self._handle_error
|
|
134
|
-
)
|
|
135
|
-
|
|
136
|
-
def _handle_error(self, error: Exception) -> None:
|
|
137
|
-
self.error_callback(error)
|
|
138
126
|
|
|
139
127
|
async def cleanup(self) -> None:
|
|
140
128
|
"""Stop the poller task"""
|
|
141
|
-
self._unsubscribe_reader()
|
|
142
129
|
await self._poller.stop()
|
|
143
130
|
await self._driver.disconnect()
|
|
144
131
|
|
|
@@ -410,16 +397,6 @@ class HeaterShakerReader(Reader):
|
|
|
410
397
|
self.labware_latch = HeaterShakerLabwareLatchStatus.IDLE_UNKNOWN
|
|
411
398
|
self.error: Optional[str] = None
|
|
412
399
|
self._driver = driver
|
|
413
|
-
self._handle_error: Callable[[Exception], None] | None = None
|
|
414
|
-
|
|
415
|
-
def register_error_handler(
|
|
416
|
-
self, handle_error: Callable[[Exception], None]
|
|
417
|
-
) -> Callable[[], None]:
|
|
418
|
-
self._handle_error = handle_error
|
|
419
|
-
return self._unsubscribe_error_handler
|
|
420
|
-
|
|
421
|
-
def _unsubscribe_error_handler(self) -> None:
|
|
422
|
-
self._handle_error = None
|
|
423
400
|
|
|
424
401
|
async def read(self) -> None:
|
|
425
402
|
await self.read_temperature()
|
|
@@ -443,8 +420,6 @@ class HeaterShakerReader(Reader):
|
|
|
443
420
|
if exception is None:
|
|
444
421
|
self.error = None
|
|
445
422
|
else:
|
|
446
|
-
if self._handle_error:
|
|
447
|
-
self._handle_error(exception)
|
|
448
423
|
try:
|
|
449
424
|
self.error = str(exception.args[0])
|
|
450
425
|
except Exception:
|
|
@@ -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
|
|
@@ -37,8 +36,6 @@ DFU_PID = "df11"
|
|
|
37
36
|
_TC_PLATE_LIFT_OPEN_DEGREES = 20
|
|
38
37
|
_TC_PLATE_LIFT_RETURN_DEGREES = 23
|
|
39
38
|
|
|
40
|
-
_TC_RAMP_RATE_ADDED_VERSION = (1, 0, 8) # v1.0.8
|
|
41
|
-
|
|
42
39
|
|
|
43
40
|
class ThermocyclerError(Exception):
|
|
44
41
|
pass
|
|
@@ -65,13 +62,12 @@ class Thermocycler(mod_abc.AbstractModule):
|
|
|
65
62
|
port: str,
|
|
66
63
|
usb_port: USBPort,
|
|
67
64
|
hw_control_loop: asyncio.AbstractEventLoop,
|
|
68
|
-
execution_manager: ExecutionManager,
|
|
69
|
-
disconnected_callback: ModuleDisconnectedCallback,
|
|
70
|
-
error_callback: ModuleErrorCallback,
|
|
65
|
+
execution_manager: Optional[ExecutionManager] = None,
|
|
71
66
|
poll_interval_seconds: Optional[float] = None,
|
|
72
67
|
simulating: bool = False,
|
|
73
68
|
sim_model: Optional[str] = None,
|
|
74
69
|
sim_serial_number: Optional[str] = None,
|
|
70
|
+
disconnected_callback: ModuleDisconnectedCallback = None,
|
|
75
71
|
) -> "Thermocycler":
|
|
76
72
|
"""
|
|
77
73
|
Build and connect to a Thermocycler
|
|
@@ -112,7 +108,6 @@ class Thermocycler(mod_abc.AbstractModule):
|
|
|
112
108
|
hw_control_loop=hw_control_loop,
|
|
113
109
|
execution_manager=execution_manager,
|
|
114
110
|
disconnected_callback=disconnected_callback,
|
|
115
|
-
error_callback=error_callback,
|
|
116
111
|
)
|
|
117
112
|
|
|
118
113
|
try:
|
|
@@ -131,9 +126,8 @@ class Thermocycler(mod_abc.AbstractModule):
|
|
|
131
126
|
poller: Poller,
|
|
132
127
|
device_info: Dict[str, str],
|
|
133
128
|
hw_control_loop: asyncio.AbstractEventLoop,
|
|
134
|
-
execution_manager: ExecutionManager,
|
|
135
|
-
disconnected_callback: ModuleDisconnectedCallback,
|
|
136
|
-
error_callback: ModuleErrorCallback,
|
|
129
|
+
execution_manager: Optional[ExecutionManager] = None,
|
|
130
|
+
disconnected_callback: ModuleDisconnectedCallback = None,
|
|
137
131
|
) -> None:
|
|
138
132
|
"""
|
|
139
133
|
Constructor
|
|
@@ -156,7 +150,6 @@ class Thermocycler(mod_abc.AbstractModule):
|
|
|
156
150
|
hw_control_loop=hw_control_loop,
|
|
157
151
|
execution_manager=execution_manager,
|
|
158
152
|
disconnected_callback=disconnected_callback,
|
|
159
|
-
error_callback=error_callback,
|
|
160
153
|
)
|
|
161
154
|
self._device_info = device_info
|
|
162
155
|
self._reader = reader
|
|
@@ -166,13 +159,10 @@ class Thermocycler(mod_abc.AbstractModule):
|
|
|
166
159
|
self._total_step_count: Optional[int] = None
|
|
167
160
|
self._current_step_index: Optional[int] = None
|
|
168
161
|
self._error: Optional[str] = None
|
|
169
|
-
self.
|
|
170
|
-
self._enter_error_state
|
|
171
|
-
)
|
|
162
|
+
self._reader.register_error_handler(self._enter_error_state)
|
|
172
163
|
|
|
173
164
|
async def cleanup(self) -> None:
|
|
174
165
|
"""Stop the poller task."""
|
|
175
|
-
self._unsubscribe_reader()
|
|
176
166
|
await self._poller.stop()
|
|
177
167
|
await self._driver.disconnect()
|
|
178
168
|
|
|
@@ -275,19 +265,6 @@ class Thermocycler(mod_abc.AbstractModule):
|
|
|
275
265
|
await self.open()
|
|
276
266
|
await self._wait_for_lid_status(ThermocyclerLidStatus.OPEN)
|
|
277
267
|
|
|
278
|
-
def can_use_ramp_rate(self) -> bool:
|
|
279
|
-
version_string = self._device_info.get("version", "v")
|
|
280
|
-
if version_string.startswith("v"):
|
|
281
|
-
version_string = version_string[1:]
|
|
282
|
-
try:
|
|
283
|
-
version_tuple = tuple(int(c) for c in version_string.split("."))
|
|
284
|
-
return version_tuple >= _TC_RAMP_RATE_ADDED_VERSION
|
|
285
|
-
except (ValueError, IndexError):
|
|
286
|
-
log.error(
|
|
287
|
-
f"Invalid version from device: {self._device_info.get('version', '')}"
|
|
288
|
-
)
|
|
289
|
-
return False
|
|
290
|
-
|
|
291
268
|
async def set_temperature(
|
|
292
269
|
self,
|
|
293
270
|
temperature: float,
|
|
@@ -313,11 +290,6 @@ class Thermocycler(mod_abc.AbstractModule):
|
|
|
313
290
|
|
|
314
291
|
Returns: None
|
|
315
292
|
"""
|
|
316
|
-
if ramp_rate and not self.can_use_ramp_rate():
|
|
317
|
-
raise ThermocyclerError(
|
|
318
|
-
"Ramp rate is not supported by this thermocycler's firmware version, please update."
|
|
319
|
-
)
|
|
320
|
-
|
|
321
293
|
await self.wait_for_is_running()
|
|
322
294
|
await self._set_temperature_no_pause(
|
|
323
295
|
temperature=temperature,
|
|
@@ -340,13 +312,11 @@ class Thermocycler(mod_abc.AbstractModule):
|
|
|
340
312
|
total_seconds = seconds + (minutes * 60)
|
|
341
313
|
hold_time = total_seconds if total_seconds > 0 else 0
|
|
342
314
|
|
|
343
|
-
if ramp_rate
|
|
344
|
-
|
|
345
|
-
"Ramp rate is not supported by this thermocycler's firmware version, please update."
|
|
346
|
-
)
|
|
315
|
+
if ramp_rate is not None:
|
|
316
|
+
await self._driver.set_ramp_rate(ramp_rate=ramp_rate)
|
|
347
317
|
|
|
348
318
|
await self._driver.set_plate_temperature(
|
|
349
|
-
temp=temperature, hold_time=hold_time, volume=volume
|
|
319
|
+
temp=temperature, hold_time=hold_time, volume=volume
|
|
350
320
|
)
|
|
351
321
|
|
|
352
322
|
task = self._loop.create_task(self._wait_for_block_target())
|
|
@@ -449,7 +419,6 @@ class Thermocycler(mod_abc.AbstractModule):
|
|
|
449
419
|
celsius: float,
|
|
450
420
|
hold_time_seconds: Optional[float] = None,
|
|
451
421
|
volume: Optional[float] = None,
|
|
452
|
-
ramp_rate: Optional[float] = None,
|
|
453
422
|
) -> None:
|
|
454
423
|
"""Set the Thermocycler's target block temperature.
|
|
455
424
|
|
|
@@ -459,17 +428,10 @@ class Thermocycler(mod_abc.AbstractModule):
|
|
|
459
428
|
celsius: The target block temperature, in degrees celsius.
|
|
460
429
|
"""
|
|
461
430
|
await self.wait_for_is_running()
|
|
462
|
-
|
|
463
|
-
if ramp_rate and not self.can_use_ramp_rate():
|
|
464
|
-
raise ThermocyclerError(
|
|
465
|
-
"Ramp rate is not supported by this thermocycler's firmware version, please update."
|
|
466
|
-
)
|
|
467
|
-
|
|
468
431
|
await self._driver.set_plate_temperature(
|
|
469
432
|
temp=celsius,
|
|
470
433
|
hold_time=hold_time_seconds,
|
|
471
434
|
volume=volume,
|
|
472
|
-
ramp_rate=ramp_rate,
|
|
473
435
|
)
|
|
474
436
|
await self._reader.read_block_temperature()
|
|
475
437
|
|
|
@@ -634,12 +596,11 @@ class Thermocycler(mod_abc.AbstractModule):
|
|
|
634
596
|
temperature = step.get("temperature")
|
|
635
597
|
hold_time_minutes = step.get("hold_time_minutes", None)
|
|
636
598
|
hold_time_seconds = step.get("hold_time_seconds", None)
|
|
637
|
-
ramp_rate = step.get("ramp_rate", None)
|
|
638
599
|
await self._set_temperature_no_pause(
|
|
639
600
|
temperature=temperature, # type: ignore
|
|
640
601
|
hold_time_minutes=hold_time_minutes,
|
|
641
602
|
hold_time_seconds=hold_time_seconds,
|
|
642
|
-
ramp_rate=
|
|
603
|
+
ramp_rate=None,
|
|
643
604
|
volume=volume,
|
|
644
605
|
)
|
|
645
606
|
|
|
@@ -712,7 +673,6 @@ class Thermocycler(mod_abc.AbstractModule):
|
|
|
712
673
|
f" for troubleshooting."
|
|
713
674
|
)
|
|
714
675
|
asyncio.run_coroutine_threadsafe(self.cleanup(), self._loop)
|
|
715
|
-
self.error_callback(error)
|
|
716
676
|
|
|
717
677
|
|
|
718
678
|
class ThermocyclerReader(Reader):
|
|
@@ -750,14 +710,8 @@ 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."""
|
|
@@ -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
|
|
@@ -74,7 +74,6 @@ from .types import (
|
|
|
74
74
|
DoorStateNotification,
|
|
75
75
|
ErrorMessageNotification,
|
|
76
76
|
HardwareEvent,
|
|
77
|
-
AsynchronousModuleErrorNotification,
|
|
78
77
|
HardwareEventHandler,
|
|
79
78
|
HardwareAction,
|
|
80
79
|
HepaFanState,
|
|
@@ -368,21 +367,6 @@ class OT3API(
|
|
|
368
367
|
|
|
369
368
|
return futures
|
|
370
369
|
|
|
371
|
-
def _send_module_notification(self, event: HardwareEvent) -> None:
|
|
372
|
-
if not isinstance(
|
|
373
|
-
event,
|
|
374
|
-
AsynchronousModuleErrorNotification,
|
|
375
|
-
):
|
|
376
|
-
return
|
|
377
|
-
mod_log.info(
|
|
378
|
-
f"Forwarding module event {event.event} for {event.module_model} {event.module_serial} at {event.port}"
|
|
379
|
-
)
|
|
380
|
-
for cb in self._callbacks:
|
|
381
|
-
try:
|
|
382
|
-
cb(event)
|
|
383
|
-
except Exception:
|
|
384
|
-
mod_log.exception("Errored during module asynchronous callback")
|
|
385
|
-
|
|
386
370
|
def _reset_last_mount(self) -> None:
|
|
387
371
|
self._last_moved_mount = None
|
|
388
372
|
|
|
@@ -438,9 +422,7 @@ class OT3API(
|
|
|
438
422
|
|
|
439
423
|
await api_instance.set_status_bar_enabled(status_bar_enabled)
|
|
440
424
|
module_controls = await AttachedModulesControl.build(
|
|
441
|
-
api_instance,
|
|
442
|
-
board_revision=backend.board_revision,
|
|
443
|
-
event_callback=api_instance._send_module_notification,
|
|
425
|
+
api_instance, board_revision=backend.board_revision
|
|
444
426
|
)
|
|
445
427
|
backend.module_controls = module_controls
|
|
446
428
|
await backend.build_estop_detector()
|
|
@@ -502,9 +484,7 @@ class OT3API(
|
|
|
502
484
|
)
|
|
503
485
|
await api_instance.cache_instruments()
|
|
504
486
|
module_controls = await AttachedModulesControl.build(
|
|
505
|
-
api_instance,
|
|
506
|
-
board_revision=backend.board_revision,
|
|
507
|
-
event_callback=api_instance._send_module_notification,
|
|
487
|
+
api_instance, board_revision=backend.board_revision
|
|
508
488
|
)
|
|
509
489
|
backend.module_controls = module_controls
|
|
510
490
|
await backend.watch(api_instance.loop)
|
|
@@ -647,10 +627,9 @@ class OT3API(
|
|
|
647
627
|
self.is_simulator
|
|
648
628
|
), "Cannot build simulating module from non-simulating hardware control API"
|
|
649
629
|
|
|
650
|
-
return await self._backend.module_controls.
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
),
|
|
630
|
+
return await self._backend.module_controls.build_module(
|
|
631
|
+
port="",
|
|
632
|
+
usb_port=USBPort(name="", port_number=1, port_group=PortGroup.LEFT),
|
|
654
633
|
type=modules.ModuleType.from_model(model),
|
|
655
634
|
sim_model=model.value,
|
|
656
635
|
)
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
"""Module Firmware update script."""
|
|
2
|
-
|
|
3
2
|
import argparse
|
|
4
3
|
import asyncio
|
|
5
4
|
from glob import glob
|
|
@@ -15,7 +14,6 @@ from opentrons.hardware_control import modules
|
|
|
15
14
|
from opentrons.hardware_control.modules.mod_abc import AbstractModule
|
|
16
15
|
from opentrons.hardware_control.modules.update import update_firmware
|
|
17
16
|
from opentrons.hardware_control.types import BoardRevision
|
|
18
|
-
from opentrons.hardware_control.execution_manager import ExecutionManager
|
|
19
17
|
|
|
20
18
|
|
|
21
19
|
# Constants for checking if module is back online
|
|
@@ -86,9 +84,6 @@ async def build_module(
|
|
|
86
84
|
port=port,
|
|
87
85
|
usb_port=mod.usb_port,
|
|
88
86
|
type=modules.MODULE_TYPE_BY_NAME[mod.name],
|
|
89
|
-
execution_manager=ExecutionManager(),
|
|
90
|
-
disconnected_callback=lambda *args: None,
|
|
91
|
-
error_callback=lambda *args: None,
|
|
92
87
|
simulating=False,
|
|
93
88
|
hw_control_loop=loop,
|
|
94
89
|
)
|