opentrons 8.7.0a7__py3-none-any.whl → 8.8.0a7__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/cli/analyze.py +4 -1
- opentrons/config/__init__.py +7 -0
- opentrons/drivers/asyncio/communication/serial_connection.py +8 -5
- opentrons/drivers/flex_stacker/driver.py +6 -1
- opentrons/drivers/vacuum_module/__init__.py +5 -0
- opentrons/drivers/vacuum_module/abstract.py +93 -0
- opentrons/drivers/vacuum_module/driver.py +208 -0
- opentrons/drivers/vacuum_module/errors.py +39 -0
- opentrons/drivers/vacuum_module/simulator.py +85 -0
- opentrons/drivers/vacuum_module/types.py +79 -0
- opentrons/execute.py +3 -0
- opentrons/hardware_control/backends/flex_protocol.py +2 -0
- opentrons/hardware_control/backends/ot3controller.py +35 -2
- opentrons/hardware_control/backends/ot3simulator.py +2 -0
- opentrons/hardware_control/backends/ot3utils.py +37 -0
- opentrons/hardware_control/module_control.py +23 -2
- opentrons/hardware_control/modules/mod_abc.py +1 -1
- opentrons/hardware_control/modules/types.py +1 -1
- opentrons/hardware_control/motion_utilities.py +6 -6
- opentrons/hardware_control/ot3api.py +62 -13
- opentrons/hardware_control/protocols/gripper_controller.py +1 -0
- opentrons/hardware_control/protocols/liquid_handler.py +6 -2
- opentrons/hardware_control/types.py +12 -0
- opentrons/legacy_commands/commands.py +58 -5
- opentrons/legacy_commands/module_commands.py +29 -0
- opentrons/legacy_commands/protocol_commands.py +33 -1
- opentrons/legacy_commands/types.py +75 -1
- opentrons/protocol_api/_transfer_liquid_validation.py +17 -2
- opentrons/protocol_api/_types.py +2 -0
- opentrons/protocol_api/core/engine/_default_labware_versions.py +1 -0
- opentrons/protocol_api/core/engine/deck_conflict.py +3 -1
- opentrons/protocol_api/core/engine/instrument.py +109 -26
- opentrons/protocol_api/core/engine/module_core.py +27 -3
- opentrons/protocol_api/core/engine/protocol.py +33 -1
- opentrons/protocol_api/core/engine/stringify.py +2 -0
- opentrons/protocol_api/core/instrument.py +19 -2
- opentrons/protocol_api/core/legacy/legacy_instrument_core.py +19 -2
- opentrons/protocol_api/core/legacy/legacy_module_core.py +15 -4
- opentrons/protocol_api/core/legacy/legacy_protocol_core.py +12 -0
- opentrons/protocol_api/core/legacy_simulator/legacy_instrument_core.py +19 -2
- opentrons/protocol_api/core/module.py +25 -2
- opentrons/protocol_api/core/protocol.py +12 -0
- opentrons/protocol_api/instrument_context.py +388 -2
- opentrons/protocol_api/labware.py +5 -2
- opentrons/protocol_api/module_contexts.py +133 -30
- opentrons/protocol_api/protocol_context.py +61 -17
- opentrons/protocol_api/robot_context.py +3 -4
- opentrons/protocol_api/validation.py +43 -2
- opentrons/protocol_engine/__init__.py +4 -0
- opentrons/protocol_engine/actions/__init__.py +2 -0
- opentrons/protocol_engine/actions/actions.py +9 -0
- opentrons/protocol_engine/commands/__init__.py +14 -0
- opentrons/protocol_engine/commands/absorbance_reader/read.py +22 -23
- opentrons/protocol_engine/commands/aspirate_while_tracking.py +52 -19
- opentrons/protocol_engine/commands/capture_image.py +302 -0
- opentrons/protocol_engine/commands/command.py +1 -0
- opentrons/protocol_engine/commands/command_unions.py +13 -0
- opentrons/protocol_engine/commands/dispense_while_tracking.py +56 -19
- opentrons/protocol_engine/commands/flex_stacker/common.py +35 -0
- opentrons/protocol_engine/commands/flex_stacker/set_stored_labware.py +7 -0
- opentrons/protocol_engine/commands/heater_shaker/set_shake_speed.py +1 -1
- opentrons/protocol_engine/commands/heater_shaker/set_target_temperature.py +1 -1
- opentrons/protocol_engine/commands/move_labware.py +3 -4
- opentrons/protocol_engine/commands/move_to_addressable_area_for_drop_tip.py +1 -1
- opentrons/protocol_engine/commands/movement_common.py +29 -2
- opentrons/protocol_engine/commands/pipetting_common.py +48 -3
- opentrons/protocol_engine/commands/thermocycler/set_target_block_temperature.py +12 -9
- opentrons/protocol_engine/commands/thermocycler/set_target_lid_temperature.py +17 -12
- opentrons/protocol_engine/commands/thermocycler/start_run_extended_profile.py +1 -1
- opentrons/protocol_engine/create_protocol_engine.py +12 -0
- opentrons/protocol_engine/engine_support.py +3 -0
- opentrons/protocol_engine/errors/__init__.py +8 -0
- opentrons/protocol_engine/errors/exceptions.py +64 -0
- opentrons/protocol_engine/execution/__init__.py +2 -0
- opentrons/protocol_engine/execution/command_executor.py +54 -1
- opentrons/protocol_engine/execution/create_queue_worker.py +4 -1
- opentrons/protocol_engine/execution/labware_movement.py +13 -4
- opentrons/protocol_engine/execution/pipetting.py +19 -25
- opentrons/protocol_engine/protocol_engine.py +62 -2
- opentrons/protocol_engine/resources/__init__.py +2 -0
- opentrons/protocol_engine/resources/camera_provider.py +110 -0
- opentrons/protocol_engine/resources/file_provider.py +133 -58
- opentrons/protocol_engine/slot_standardization.py +2 -0
- opentrons/protocol_engine/state/camera.py +54 -0
- opentrons/protocol_engine/state/commands.py +24 -4
- opentrons/protocol_engine/state/geometry.py +68 -10
- opentrons/protocol_engine/state/labware.py +10 -6
- opentrons/protocol_engine/state/labware_origin_math/stackup_origin_to_labware_origin.py +6 -1
- opentrons/protocol_engine/state/modules.py +9 -0
- opentrons/protocol_engine/state/preconditions.py +59 -0
- opentrons/protocol_engine/state/state.py +30 -0
- opentrons/protocol_engine/state/state_summary.py +2 -0
- opentrons/protocol_engine/state/update_types.py +10 -0
- opentrons/protocol_engine/types/__init__.py +14 -1
- opentrons/protocol_engine/types/command_preconditions.py +18 -0
- opentrons/protocol_engine/types/location.py +26 -2
- opentrons/protocol_engine/types/module.py +1 -1
- opentrons/protocol_runner/protocol_runner.py +14 -1
- opentrons/protocol_runner/run_orchestrator.py +31 -0
- opentrons/protocols/advanced_control/transfers/transfer_liquid_utils.py +2 -2
- opentrons/simulate.py +3 -0
- opentrons/system/camera.py +333 -3
- opentrons/system/ffmpeg.py +110 -0
- {opentrons-8.7.0a7.dist-info → opentrons-8.8.0a7.dist-info}/METADATA +4 -4
- {opentrons-8.7.0a7.dist-info → opentrons-8.8.0a7.dist-info}/RECORD +109 -97
- {opentrons-8.7.0a7.dist-info → opentrons-8.8.0a7.dist-info}/WHEEL +0 -0
- {opentrons-8.7.0a7.dist-info → opentrons-8.8.0a7.dist-info}/entry_points.txt +0 -0
- {opentrons-8.7.0a7.dist-info → opentrons-8.8.0a7.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
"""Command precondition state and store resource."""
|
|
2
|
+
from dataclasses import dataclass
|
|
3
|
+
|
|
4
|
+
from opentrons.protocol_engine.actions.get_state_update import get_state_updates
|
|
5
|
+
from opentrons.protocol_engine.state import update_types
|
|
6
|
+
from opentrons.protocol_engine.types import CommandPreconditions, PreconditionTypes
|
|
7
|
+
|
|
8
|
+
from ._abstract_store import HasState, HandlesActions
|
|
9
|
+
from ..actions import Action
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@dataclass
|
|
13
|
+
class CommandPreconditionState:
|
|
14
|
+
"""State of Engine command precondition references."""
|
|
15
|
+
|
|
16
|
+
preconditions: CommandPreconditions
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class CommandPreconditionStore(HasState[CommandPreconditionState], HandlesActions):
|
|
20
|
+
"""Command Precondition container."""
|
|
21
|
+
|
|
22
|
+
_state: CommandPreconditionState
|
|
23
|
+
|
|
24
|
+
def __init__(self) -> None:
|
|
25
|
+
"""Initialize a Command Precondition store and its state."""
|
|
26
|
+
self._state = CommandPreconditionState(
|
|
27
|
+
preconditions=CommandPreconditions(isCameraUsed=False)
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
def handle_action(self, action: Action) -> None:
|
|
31
|
+
"""Modify state in reaction to an action."""
|
|
32
|
+
for state_update in get_state_updates(action):
|
|
33
|
+
self._handle_state_update(state_update)
|
|
34
|
+
|
|
35
|
+
def _handle_state_update(self, state_update: update_types.StateUpdate) -> None:
|
|
36
|
+
if state_update.precondition_update != update_types.NO_CHANGE:
|
|
37
|
+
for key in state_update.precondition_update.preconditions:
|
|
38
|
+
if key == PreconditionTypes.IS_CAMERA_USED:
|
|
39
|
+
self._state.preconditions.isCameraUsed = (
|
|
40
|
+
state_update.precondition_update.preconditions[key]
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
class CommandPreconditionView:
|
|
45
|
+
"""Read-only engine created Command Precondition state view."""
|
|
46
|
+
|
|
47
|
+
_state: CommandPreconditionState
|
|
48
|
+
|
|
49
|
+
def __init__(self, state: CommandPreconditionState) -> None:
|
|
50
|
+
"""Initialize the view of Command Precondition state.
|
|
51
|
+
|
|
52
|
+
Arguments:
|
|
53
|
+
state: Command precondition dataclass used for tracking preconditions used during a protocol.
|
|
54
|
+
"""
|
|
55
|
+
self._state = state
|
|
56
|
+
|
|
57
|
+
def get_precondition(self) -> CommandPreconditions:
|
|
58
|
+
"""Get the Command Preconditions currently set by a protocol."""
|
|
59
|
+
return self._state.preconditions
|
|
@@ -35,6 +35,12 @@ from .config import Config
|
|
|
35
35
|
from .state_summary import StateSummary
|
|
36
36
|
from ..types import DeckConfigurationType
|
|
37
37
|
from .tasks import TaskState, TaskView, TaskStore
|
|
38
|
+
from .preconditions import (
|
|
39
|
+
CommandPreconditionState,
|
|
40
|
+
CommandPreconditionStore,
|
|
41
|
+
CommandPreconditionView,
|
|
42
|
+
)
|
|
43
|
+
from .camera import CameraState, CameraView, CameraStore
|
|
38
44
|
|
|
39
45
|
|
|
40
46
|
_ParamsT = ParamSpec("_ParamsT")
|
|
@@ -56,6 +62,8 @@ class State:
|
|
|
56
62
|
wells: WellState
|
|
57
63
|
files: FileState
|
|
58
64
|
tasks: TaskState
|
|
65
|
+
preconditions: CommandPreconditionState
|
|
66
|
+
camera: CameraState
|
|
59
67
|
|
|
60
68
|
|
|
61
69
|
class StateView(HasState[State]):
|
|
@@ -76,6 +84,8 @@ class StateView(HasState[State]):
|
|
|
76
84
|
_files: FileView
|
|
77
85
|
_config: Config
|
|
78
86
|
_tasks: TaskView
|
|
87
|
+
_preconditions: CommandPreconditionView
|
|
88
|
+
_camera: CameraView
|
|
79
89
|
|
|
80
90
|
@property
|
|
81
91
|
def commands(self) -> CommandView:
|
|
@@ -142,6 +152,16 @@ class StateView(HasState[State]):
|
|
|
142
152
|
"""Get ProtocolEngine configuration."""
|
|
143
153
|
return self._config
|
|
144
154
|
|
|
155
|
+
@property
|
|
156
|
+
def preconditions(self) -> CommandPreconditionView:
|
|
157
|
+
"""Get state view selectors for command preconditions."""
|
|
158
|
+
return self._preconditions
|
|
159
|
+
|
|
160
|
+
@property
|
|
161
|
+
def camera(self) -> CameraView:
|
|
162
|
+
"""Get state view for the Camera."""
|
|
163
|
+
return self._camera
|
|
164
|
+
|
|
145
165
|
@property
|
|
146
166
|
def tasks(self) -> TaskView:
|
|
147
167
|
"""Get state view selectors for task state."""
|
|
@@ -171,6 +191,7 @@ class StateView(HasState[State]):
|
|
|
171
191
|
for liquid_class_id, liquid_class_record in self._liquid_classes.get_all().items()
|
|
172
192
|
],
|
|
173
193
|
tasks=self._tasks.get_summary(),
|
|
194
|
+
cameraSettings=self._camera.get_enablement_settings(),
|
|
174
195
|
)
|
|
175
196
|
|
|
176
197
|
|
|
@@ -241,6 +262,8 @@ class StateStore(StateView, ActionHandler):
|
|
|
241
262
|
self._well_store = WellStore()
|
|
242
263
|
self._file_store = FileStore()
|
|
243
264
|
self._task_store = TaskStore()
|
|
265
|
+
self._precondition_store = CommandPreconditionStore()
|
|
266
|
+
self._camera_store = CameraStore()
|
|
244
267
|
|
|
245
268
|
self._substores: List[HandlesActions] = [
|
|
246
269
|
self._command_store,
|
|
@@ -254,6 +277,8 @@ class StateStore(StateView, ActionHandler):
|
|
|
254
277
|
self._well_store,
|
|
255
278
|
self._file_store,
|
|
256
279
|
self._task_store,
|
|
280
|
+
self._precondition_store,
|
|
281
|
+
self._camera_store,
|
|
257
282
|
]
|
|
258
283
|
self._config = config
|
|
259
284
|
self._change_notifier = change_notifier or ChangeNotifier()
|
|
@@ -378,6 +403,8 @@ class StateStore(StateView, ActionHandler):
|
|
|
378
403
|
wells=self._well_store.state,
|
|
379
404
|
files=self._file_store.state,
|
|
380
405
|
tasks=self._task_store.state,
|
|
406
|
+
preconditions=self._precondition_store.state,
|
|
407
|
+
camera=self._camera_store.state,
|
|
381
408
|
)
|
|
382
409
|
|
|
383
410
|
def _initialize_state(self) -> None:
|
|
@@ -397,6 +424,8 @@ class StateStore(StateView, ActionHandler):
|
|
|
397
424
|
self._wells = WellView(state.wells)
|
|
398
425
|
self._files = FileView(state.files)
|
|
399
426
|
self._tasks = TaskView(state.tasks)
|
|
427
|
+
self._preconditions = CommandPreconditionView(state.preconditions)
|
|
428
|
+
self._camera = CameraView(state.camera)
|
|
400
429
|
|
|
401
430
|
# Derived states
|
|
402
431
|
self._geometry = GeometryView(
|
|
@@ -430,6 +459,7 @@ class StateStore(StateView, ActionHandler):
|
|
|
430
459
|
self._tips._state = next_state.tips
|
|
431
460
|
self._wells._state = next_state.wells
|
|
432
461
|
self._tasks._state = next_state.tasks
|
|
462
|
+
self._camera._state = next_state.camera
|
|
433
463
|
self._change_notifier.notify()
|
|
434
464
|
if self._notify_robot_server is not None:
|
|
435
465
|
self._notify_robot_server()
|
|
@@ -15,6 +15,7 @@ from ..types import (
|
|
|
15
15
|
WellInfoSummary,
|
|
16
16
|
TaskSummary,
|
|
17
17
|
)
|
|
18
|
+
from ..resources.camera_provider import CameraSettings
|
|
18
19
|
|
|
19
20
|
|
|
20
21
|
class StateSummary(BaseModel):
|
|
@@ -36,3 +37,4 @@ class StateSummary(BaseModel):
|
|
|
36
37
|
files: List[str] = Field(default_factory=list)
|
|
37
38
|
liquidClasses: List[LiquidClassRecordWithId] = Field(default_factory=list)
|
|
38
39
|
tasks: List[TaskSummary] = Field(default_factory=list)
|
|
40
|
+
cameraSettings: Optional[CameraSettings] = None
|
|
@@ -24,6 +24,7 @@ from opentrons.protocol_engine.types import (
|
|
|
24
24
|
ModuleModel,
|
|
25
25
|
ModuleDefinition,
|
|
26
26
|
LabwareWellId,
|
|
27
|
+
PreconditionTypes,
|
|
27
28
|
)
|
|
28
29
|
from opentrons.types import MountType, DeckSlotName
|
|
29
30
|
from opentrons_shared_data.labware.labware_definition import LabwareDefinition
|
|
@@ -401,6 +402,13 @@ class FilesAddedUpdate:
|
|
|
401
402
|
file_ids: list[str]
|
|
402
403
|
|
|
403
404
|
|
|
405
|
+
@dataclasses.dataclass
|
|
406
|
+
class PreconditionUpdate:
|
|
407
|
+
"""An update that changes command preconditions flags."""
|
|
408
|
+
|
|
409
|
+
preconditions: dict[PreconditionTypes, bool]
|
|
410
|
+
|
|
411
|
+
|
|
404
412
|
@dataclasses.dataclass
|
|
405
413
|
class AddressableAreaUsedUpdate:
|
|
406
414
|
"""An update that says an addressable area has been used."""
|
|
@@ -477,6 +485,8 @@ class StateUpdate:
|
|
|
477
485
|
|
|
478
486
|
ready_to_aspirate: PipetteAspirateReadyUpdate | NoChangeType = NO_CHANGE
|
|
479
487
|
|
|
488
|
+
precondition_update: PreconditionUpdate | NoChangeType = NO_CHANGE
|
|
489
|
+
|
|
480
490
|
def append(self, other: Self) -> Self:
|
|
481
491
|
"""Apply another `StateUpdate` "on top of" this one.
|
|
482
492
|
|
|
@@ -25,6 +25,10 @@ from .command_annotations import (
|
|
|
25
25
|
CustomCommandAnnotation,
|
|
26
26
|
CommandAnnotation,
|
|
27
27
|
)
|
|
28
|
+
from .command_preconditions import (
|
|
29
|
+
CommandPreconditions,
|
|
30
|
+
PreconditionTypes,
|
|
31
|
+
)
|
|
28
32
|
from .partial_tip_configuration import (
|
|
29
33
|
AllNozzleLayoutConfiguration,
|
|
30
34
|
SingleNozzleLayoutConfiguration,
|
|
@@ -83,6 +87,8 @@ from .location import (
|
|
|
83
87
|
NonStackedLocation,
|
|
84
88
|
DeckPoint,
|
|
85
89
|
InStackerHopperLocation,
|
|
90
|
+
WASTE_CHUTE_LOCATION,
|
|
91
|
+
AccessibleByGripperLocation,
|
|
86
92
|
OnLabwareLocationSequenceComponent,
|
|
87
93
|
OnModuleLocationSequenceComponent,
|
|
88
94
|
OnAddressableAreaLocationSequenceComponent,
|
|
@@ -92,6 +98,7 @@ from .location import (
|
|
|
92
98
|
LoadableLabwareLocation,
|
|
93
99
|
labware_location_is_system,
|
|
94
100
|
labware_location_is_off_deck,
|
|
101
|
+
labware_location_is_in_waste_chute,
|
|
95
102
|
)
|
|
96
103
|
from .labware import (
|
|
97
104
|
OverlapOffset,
|
|
@@ -166,6 +173,9 @@ __all__ = [
|
|
|
166
173
|
"SecondOrderCommandAnnotation",
|
|
167
174
|
"CustomCommandAnnotation",
|
|
168
175
|
"CommandAnnotation",
|
|
176
|
+
# Command preconditions
|
|
177
|
+
"PreconditionTypes",
|
|
178
|
+
"CommandPreconditions",
|
|
169
179
|
# Partial tip handling
|
|
170
180
|
"AllNozzleLayoutConfiguration",
|
|
171
181
|
"SingleNozzleLayoutConfiguration",
|
|
@@ -229,8 +239,10 @@ __all__ = [
|
|
|
229
239
|
"NonStackedLocation",
|
|
230
240
|
"DeckPoint",
|
|
231
241
|
"OffDeckLocationType",
|
|
232
|
-
"SystemLocationType",
|
|
242
|
+
"WasteChuteLocationType" "SystemLocationType",
|
|
233
243
|
"InStackerHopperLocation",
|
|
244
|
+
"WASTE_CHUTE_LOCATION",
|
|
245
|
+
"AccessibleByGripperLocation",
|
|
234
246
|
"OnLabwareLocationSequenceComponent",
|
|
235
247
|
"OnModuleLocationSequenceComponent",
|
|
236
248
|
"OnAddressableAreaLocationSequenceComponent",
|
|
@@ -240,6 +252,7 @@ __all__ = [
|
|
|
240
252
|
"LoadableLabwareLocation",
|
|
241
253
|
"labware_location_is_off_deck",
|
|
242
254
|
"labware_location_is_system",
|
|
255
|
+
"labware_location_is_in_waste_chute",
|
|
243
256
|
# Labware offset location
|
|
244
257
|
"LegacyLabwareOffsetLocation",
|
|
245
258
|
"LabwareOffsetLocationSequence",
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"""Protocol Engine types dealing with command preconditions."""
|
|
2
|
+
from enum import Enum
|
|
3
|
+
from pydantic import Field, BaseModel
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class PreconditionTypes(str, Enum):
|
|
7
|
+
"""Precondition types used for identification during state update."""
|
|
8
|
+
|
|
9
|
+
IS_CAMERA_USED = "isCameraUsed"
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class CommandPreconditions(BaseModel):
|
|
13
|
+
"""Preconditions of commands as described in protocol analysis."""
|
|
14
|
+
|
|
15
|
+
isCameraUsed: bool = Field(
|
|
16
|
+
default=False,
|
|
17
|
+
description="Parameter to determine if a Camera is used in a protocol.",
|
|
18
|
+
)
|
|
@@ -85,8 +85,10 @@ class InStackerHopperLocation(BaseModel):
|
|
|
85
85
|
|
|
86
86
|
_OffDeckLocationType = Literal["offDeck"]
|
|
87
87
|
_SystemLocationType = Literal["systemLocation"]
|
|
88
|
+
_WasteChuteLocationType = Literal["wasteChuteLocation"]
|
|
88
89
|
OFF_DECK_LOCATION: _OffDeckLocationType = "offDeck"
|
|
89
90
|
SYSTEM_LOCATION: _SystemLocationType = "systemLocation"
|
|
91
|
+
WASTE_CHUTE_LOCATION: _WasteChuteLocationType = "wasteChuteLocation"
|
|
90
92
|
|
|
91
93
|
|
|
92
94
|
def labware_location_is_off_deck(
|
|
@@ -103,6 +105,13 @@ def labware_location_is_system(
|
|
|
103
105
|
return isinstance(location, str) and location == SYSTEM_LOCATION
|
|
104
106
|
|
|
105
107
|
|
|
108
|
+
def labware_location_is_in_waste_chute(
|
|
109
|
+
location: LabwareLocation,
|
|
110
|
+
) -> TypeGuard[_WasteChuteLocationType]:
|
|
111
|
+
"""Check if a location is the waste chute."""
|
|
112
|
+
return isinstance(location, str) and location == WASTE_CHUTE_LOCATION
|
|
113
|
+
|
|
114
|
+
|
|
106
115
|
class OnLabwareLocationSequenceComponent(BaseModel):
|
|
107
116
|
"""Labware on another labware."""
|
|
108
117
|
|
|
@@ -137,7 +146,7 @@ class NotOnDeckLocationSequenceComponent(BaseModel):
|
|
|
137
146
|
"""Labware on a system location."""
|
|
138
147
|
|
|
139
148
|
kind: Literal["notOnDeck"] = "notOnDeck"
|
|
140
|
-
logicalLocationName: _OffDeckLocationType | _SystemLocationType
|
|
149
|
+
logicalLocationName: _OffDeckLocationType | _SystemLocationType | _WasteChuteLocationType
|
|
141
150
|
|
|
142
151
|
|
|
143
152
|
LabwareLocationSequence = list[
|
|
@@ -158,6 +167,7 @@ LabwareLocation = Union[
|
|
|
158
167
|
_SystemLocationType,
|
|
159
168
|
AddressableAreaLocation,
|
|
160
169
|
InStackerHopperLocation,
|
|
170
|
+
_WasteChuteLocationType,
|
|
161
171
|
]
|
|
162
172
|
"""Union of all locations where it's legal to keep a labware."""
|
|
163
173
|
|
|
@@ -168,11 +178,15 @@ LoadableLabwareLocation = Union[
|
|
|
168
178
|
_OffDeckLocationType,
|
|
169
179
|
_SystemLocationType,
|
|
170
180
|
AddressableAreaLocation,
|
|
181
|
+
_WasteChuteLocationType,
|
|
171
182
|
]
|
|
172
183
|
"""Union of all locations where it's legal to load a labware."""
|
|
173
184
|
|
|
174
185
|
OnDeckLabwareLocation = Union[
|
|
175
|
-
DeckSlotLocation,
|
|
186
|
+
DeckSlotLocation,
|
|
187
|
+
ModuleLocation,
|
|
188
|
+
OnLabwareLocation,
|
|
189
|
+
AddressableAreaLocation,
|
|
176
190
|
]
|
|
177
191
|
|
|
178
192
|
NonStackedLocation = Union[
|
|
@@ -181,9 +195,19 @@ NonStackedLocation = Union[
|
|
|
181
195
|
ModuleLocation,
|
|
182
196
|
_OffDeckLocationType,
|
|
183
197
|
_SystemLocationType,
|
|
198
|
+
_WasteChuteLocationType,
|
|
184
199
|
]
|
|
185
200
|
"""Union of all locations where it's legal to keep a labware that can't be stacked on another labware"""
|
|
186
201
|
|
|
202
|
+
AccessibleByGripperLocation = Union[
|
|
203
|
+
DeckSlotLocation,
|
|
204
|
+
ModuleLocation,
|
|
205
|
+
OnLabwareLocation,
|
|
206
|
+
AddressableAreaLocation,
|
|
207
|
+
_WasteChuteLocationType,
|
|
208
|
+
]
|
|
209
|
+
"""Union of all locations that a gripper can move things to."""
|
|
210
|
+
|
|
187
211
|
|
|
188
212
|
# TODO(mm, 2022-11-07): Deduplicate with Vec3f.
|
|
189
213
|
class DeckPoint(BaseModel):
|
|
@@ -303,7 +303,7 @@ class StackerStoredLabwareGroup(BaseModel):
|
|
|
303
303
|
|
|
304
304
|
@dataclass
|
|
305
305
|
class StackerPoolDefinition:
|
|
306
|
-
"""Represents an internal
|
|
306
|
+
"""Represents an internal configuration of stored labware."""
|
|
307
307
|
|
|
308
308
|
primaryLabwareDefinition: LabwareDefinition
|
|
309
309
|
adapterLabwareDefinition: LabwareDefinition | SkipJsonSchema[None] = None
|
|
@@ -24,7 +24,7 @@ from opentrons.protocol_engine import (
|
|
|
24
24
|
Command,
|
|
25
25
|
commands as pe_commands,
|
|
26
26
|
)
|
|
27
|
-
from opentrons.protocol_engine.types import CommandAnnotation
|
|
27
|
+
from opentrons.protocol_engine.types import CommandAnnotation, CommandPreconditions
|
|
28
28
|
from opentrons.protocols.parse import PythonParseMode
|
|
29
29
|
from opentrons.util.async_helpers import asyncio_yield
|
|
30
30
|
from opentrons.util.broker import Broker
|
|
@@ -58,6 +58,7 @@ class RunResult(NamedTuple):
|
|
|
58
58
|
state_summary: StateSummary
|
|
59
59
|
parameters: List[RunTimeParameter]
|
|
60
60
|
command_annotations: List[CommandAnnotation]
|
|
61
|
+
command_preconditions: Optional[CommandPreconditions]
|
|
61
62
|
|
|
62
63
|
|
|
63
64
|
class AbstractRunner(ABC):
|
|
@@ -284,11 +285,15 @@ class PythonAndLegacyRunner(AbstractRunner):
|
|
|
284
285
|
run_data = self._protocol_engine.state_view.get_summary()
|
|
285
286
|
commands = self._protocol_engine.state_view.commands.get_all()
|
|
286
287
|
parameters = self.run_time_parameters
|
|
288
|
+
preconditions = (
|
|
289
|
+
self._protocol_engine.state_view.preconditions.get_precondition()
|
|
290
|
+
)
|
|
287
291
|
return RunResult(
|
|
288
292
|
commands=commands,
|
|
289
293
|
state_summary=run_data,
|
|
290
294
|
parameters=parameters,
|
|
291
295
|
command_annotations=[],
|
|
296
|
+
command_preconditions=preconditions,
|
|
292
297
|
)
|
|
293
298
|
|
|
294
299
|
|
|
@@ -403,11 +408,15 @@ class JsonRunner(AbstractRunner):
|
|
|
403
408
|
|
|
404
409
|
run_data = self._protocol_engine.state_view.get_summary()
|
|
405
410
|
commands = self._protocol_engine.state_view.commands.get_all()
|
|
411
|
+
preconditions = (
|
|
412
|
+
self._protocol_engine.state_view.preconditions.get_precondition()
|
|
413
|
+
)
|
|
406
414
|
return RunResult(
|
|
407
415
|
commands=commands,
|
|
408
416
|
state_summary=run_data,
|
|
409
417
|
parameters=[],
|
|
410
418
|
command_annotations=self._command_annotations,
|
|
419
|
+
command_preconditions=preconditions,
|
|
411
420
|
)
|
|
412
421
|
|
|
413
422
|
async def _add_and_execute_commands(self) -> None:
|
|
@@ -479,11 +488,15 @@ class LiveRunner(AbstractRunner):
|
|
|
479
488
|
|
|
480
489
|
run_data = self._protocol_engine.state_view.get_summary()
|
|
481
490
|
commands = self._protocol_engine.state_view.commands.get_all()
|
|
491
|
+
preconditions = (
|
|
492
|
+
self._protocol_engine.state_view.preconditions.get_precondition()
|
|
493
|
+
)
|
|
482
494
|
return RunResult(
|
|
483
495
|
commands=commands,
|
|
484
496
|
state_summary=run_data,
|
|
485
497
|
parameters=[],
|
|
486
498
|
command_annotations=[],
|
|
499
|
+
command_preconditions=preconditions,
|
|
487
500
|
)
|
|
488
501
|
|
|
489
502
|
|
|
@@ -43,7 +43,9 @@ from ..protocol_engine.types import (
|
|
|
43
43
|
CSVRuntimeParamPaths,
|
|
44
44
|
CommandAnnotation,
|
|
45
45
|
ModuleModel,
|
|
46
|
+
CommandPreconditions,
|
|
46
47
|
)
|
|
48
|
+
from ..protocol_engine.resources.camera_provider import CameraProvider, CameraSettings
|
|
47
49
|
from ..protocol_engine.error_recovery_policy import ErrorRecoveryPolicy
|
|
48
50
|
|
|
49
51
|
from ..protocol_reader import JsonProtocolConfig, PythonProtocolConfig, ProtocolSource
|
|
@@ -84,6 +86,7 @@ class RunOrchestrator:
|
|
|
84
86
|
_protocol_live_runner: protocol_runner.LiveRunner
|
|
85
87
|
_hardware_api: HardwareControlAPI
|
|
86
88
|
_protocol_engine: ProtocolEngine
|
|
89
|
+
_camera_provider: Optional[CameraProvider] = None
|
|
87
90
|
|
|
88
91
|
def __init__(
|
|
89
92
|
self,
|
|
@@ -92,6 +95,7 @@ class RunOrchestrator:
|
|
|
92
95
|
fixit_runner: protocol_runner.LiveRunner,
|
|
93
96
|
setup_runner: protocol_runner.LiveRunner,
|
|
94
97
|
protocol_live_runner: protocol_runner.LiveRunner,
|
|
98
|
+
camera_provider: Optional[CameraProvider] = None,
|
|
95
99
|
json_or_python_protocol_runner: Optional[
|
|
96
100
|
Union[protocol_runner.PythonAndLegacyRunner, protocol_runner.JsonRunner]
|
|
97
101
|
] = None,
|
|
@@ -106,6 +110,7 @@ class RunOrchestrator:
|
|
|
106
110
|
setup_runner: LiveRunner for setup commands.
|
|
107
111
|
protocol_live_runner: LiveRunner for protocol commands.
|
|
108
112
|
json_or_python_protocol_runner: JsonRunner/PythonAndLegacyRunner for protocol commands.
|
|
113
|
+
camera_provider: Provides callbacks to Camera interface.
|
|
109
114
|
run_id: run id if any, associated to the runner/engine.
|
|
110
115
|
"""
|
|
111
116
|
self._run_id = run_id
|
|
@@ -114,6 +119,7 @@ class RunOrchestrator:
|
|
|
114
119
|
self._setup_runner = setup_runner
|
|
115
120
|
self._fixit_runner = fixit_runner
|
|
116
121
|
self._protocol_live_runner = protocol_live_runner
|
|
122
|
+
self._camera_provider = camera_provider
|
|
117
123
|
self._fixit_runner.prepare()
|
|
118
124
|
self._setup_runner.prepare()
|
|
119
125
|
self._protocol_engine.set_and_start_queue_worker(self.command_generator)
|
|
@@ -132,6 +138,7 @@ class RunOrchestrator:
|
|
|
132
138
|
cls,
|
|
133
139
|
hardware_api: HardwareControlAPI,
|
|
134
140
|
protocol_engine: ProtocolEngine,
|
|
141
|
+
camera_provider: Optional[CameraProvider] = None,
|
|
135
142
|
protocol_config: Optional[
|
|
136
143
|
Union[JsonProtocolConfig, PythonProtocolConfig]
|
|
137
144
|
] = None,
|
|
@@ -169,6 +176,7 @@ class RunOrchestrator:
|
|
|
169
176
|
hardware_api=hardware_api,
|
|
170
177
|
protocol_engine=protocol_engine,
|
|
171
178
|
protocol_live_runner=protocol_live_runner,
|
|
179
|
+
camera_provider=camera_provider,
|
|
172
180
|
)
|
|
173
181
|
|
|
174
182
|
def play(self, deck_configuration: Optional[DeckConfigurationType] = None) -> None:
|
|
@@ -237,6 +245,10 @@ class RunOrchestrator:
|
|
|
237
245
|
"""Get protocol run data."""
|
|
238
246
|
return self._protocol_engine.state_view.get_summary()
|
|
239
247
|
|
|
248
|
+
def get_preconditions(self) -> CommandPreconditions:
|
|
249
|
+
"""Get the preconditions of a protocol run."""
|
|
250
|
+
return self._protocol_engine.state_view.preconditions.get_precondition()
|
|
251
|
+
|
|
240
252
|
def get_loaded_labware_definitions(self) -> List[LabwareDefinition]:
|
|
241
253
|
"""Get loaded labware definitions."""
|
|
242
254
|
return self._protocol_engine.state_view.labware.get_loaded_labware_definitions()
|
|
@@ -363,6 +375,13 @@ class RunOrchestrator:
|
|
|
363
375
|
"""Add a new labware definition to state."""
|
|
364
376
|
return self._protocol_engine.add_labware_definition(definition)
|
|
365
377
|
|
|
378
|
+
def add_camera_enablement_settings(
|
|
379
|
+
self,
|
|
380
|
+
enablement_settings: CameraSettings,
|
|
381
|
+
) -> CameraSettings:
|
|
382
|
+
"""Add new camera enablement settings."""
|
|
383
|
+
return self._protocol_engine.add_camera_enablement_settings(enablement_settings)
|
|
384
|
+
|
|
366
385
|
async def add_command_and_wait_for_interval(
|
|
367
386
|
self,
|
|
368
387
|
command: CommandCreate,
|
|
@@ -396,6 +415,18 @@ class RunOrchestrator:
|
|
|
396
415
|
module_model=ModuleModel.from_hardware(module_model), serial=module_serial
|
|
397
416
|
)
|
|
398
417
|
|
|
418
|
+
async def module_disconnected(
|
|
419
|
+
self, module_model: HardwareModuleModel, module_serial: str | None
|
|
420
|
+
) -> bool:
|
|
421
|
+
"""Handle an unexpected module disconnection.
|
|
422
|
+
|
|
423
|
+
If this function returns true, the caller should call finish() immediately; if it returns
|
|
424
|
+
False, the caller should not call finish() until it otherwise would.
|
|
425
|
+
"""
|
|
426
|
+
return await self._protocol_engine.module_disconnected(
|
|
427
|
+
module_model=ModuleModel.from_hardware(module_model), serial=module_serial
|
|
428
|
+
)
|
|
429
|
+
|
|
399
430
|
async def use_attached_modules(
|
|
400
431
|
self, modules_by_id: Dict[str, HardwareModuleAPI]
|
|
401
432
|
) -> None:
|
|
@@ -72,7 +72,7 @@ def raise_if_location_inside_liquid(
|
|
|
72
72
|
def group_wells_for_multi_channel_transfer(
|
|
73
73
|
targets: Sequence[Well],
|
|
74
74
|
nozzle_map: NozzleMapInterface,
|
|
75
|
-
target_name: Literal["source", "destination"],
|
|
75
|
+
target_name: Literal["source", "destination", "tip"],
|
|
76
76
|
) -> List[Well]:
|
|
77
77
|
"""Takes a list of wells and a nozzle map and returns a list of target wells to address every well given
|
|
78
78
|
|
|
@@ -108,7 +108,7 @@ def group_wells_for_multi_channel_transfer(
|
|
|
108
108
|
def _group_wells_for_nozzle_configuration( # noqa: C901
|
|
109
109
|
targets: List[Well],
|
|
110
110
|
nozzle_map: NozzleMapInterface,
|
|
111
|
-
target_name: Literal["source", "destination"],
|
|
111
|
+
target_name: Literal["source", "destination", "tip"],
|
|
112
112
|
) -> List[Well]:
|
|
113
113
|
"""Groups wells together for a column, row, or full 96 configuration and returns a reduced list of target wells."""
|
|
114
114
|
grouped_wells = []
|
opentrons/simulate.py
CHANGED
|
@@ -50,6 +50,7 @@ from opentrons.protocol_engine.create_protocol_engine import (
|
|
|
50
50
|
from opentrons.protocol_engine import error_recovery_policy
|
|
51
51
|
from opentrons.protocol_engine.state.config import Config
|
|
52
52
|
from opentrons.protocol_engine.types import DeckType, EngineStatus, PostRunHardwareState
|
|
53
|
+
from opentrons.protocol_engine.resources.camera_provider import CameraProvider
|
|
53
54
|
from opentrons.protocol_reader.protocol_source import ProtocolSource
|
|
54
55
|
from opentrons.protocol_runner.protocol_runner import create_protocol_runner, LiveRunner
|
|
55
56
|
from opentrons.protocol_runner import RunOrchestrator
|
|
@@ -849,6 +850,7 @@ def _create_live_context_pe(
|
|
|
849
850
|
load_fixed_trash=should_load_fixed_trash_labware_for_python_protocol(
|
|
850
851
|
api_version
|
|
851
852
|
),
|
|
853
|
+
camera_provider=CameraProvider(),
|
|
852
854
|
) as (engine, loop):
|
|
853
855
|
yield engine, loop
|
|
854
856
|
finally:
|
|
@@ -982,6 +984,7 @@ def _run_file_pe(
|
|
|
982
984
|
protocol_live_runner=LiveRunner(
|
|
983
985
|
protocol_engine=protocol_engine, hardware_api=hardware_api_wrapped
|
|
984
986
|
),
|
|
987
|
+
camera_provider=CameraProvider(),
|
|
985
988
|
)
|
|
986
989
|
|
|
987
990
|
# TODO(mm, 2024-08-06): This home is theoretically redundant with Protocol
|