opentrons 8.3.1a1__py2.py3-none-any.whl → 8.4.0a0__py2.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/calibration_storage/ot2/mark_bad_calibration.py +2 -0
- opentrons/calibration_storage/ot2/tip_length.py +6 -6
- opentrons/config/advanced_settings.py +9 -11
- opentrons/config/feature_flags.py +0 -4
- opentrons/config/reset.py +7 -2
- opentrons/drivers/asyncio/communication/__init__.py +2 -0
- opentrons/drivers/asyncio/communication/async_serial.py +4 -0
- opentrons/drivers/asyncio/communication/errors.py +41 -8
- opentrons/drivers/asyncio/communication/serial_connection.py +36 -10
- opentrons/drivers/flex_stacker/__init__.py +9 -3
- opentrons/drivers/flex_stacker/abstract.py +140 -15
- opentrons/drivers/flex_stacker/driver.py +593 -47
- opentrons/drivers/flex_stacker/errors.py +64 -0
- opentrons/drivers/flex_stacker/simulator.py +222 -24
- opentrons/drivers/flex_stacker/types.py +211 -15
- opentrons/drivers/flex_stacker/utils.py +19 -0
- opentrons/execute.py +4 -2
- opentrons/hardware_control/api.py +5 -0
- opentrons/hardware_control/backends/flex_protocol.py +4 -0
- opentrons/hardware_control/backends/ot3controller.py +12 -1
- opentrons/hardware_control/backends/ot3simulator.py +3 -0
- opentrons/hardware_control/backends/subsystem_manager.py +7 -2
- opentrons/hardware_control/instruments/ot2/instrument_calibration.py +10 -6
- opentrons/hardware_control/instruments/ot3/pipette_handler.py +59 -6
- opentrons/hardware_control/modules/__init__.py +12 -1
- opentrons/hardware_control/modules/absorbance_reader.py +11 -9
- opentrons/hardware_control/modules/flex_stacker.py +498 -0
- opentrons/hardware_control/modules/heater_shaker.py +12 -10
- opentrons/hardware_control/modules/magdeck.py +5 -1
- opentrons/hardware_control/modules/tempdeck.py +5 -1
- opentrons/hardware_control/modules/thermocycler.py +15 -14
- opentrons/hardware_control/modules/types.py +191 -1
- opentrons/hardware_control/modules/utils.py +3 -0
- opentrons/hardware_control/motion_utilities.py +20 -0
- opentrons/hardware_control/ot3api.py +145 -15
- opentrons/hardware_control/protocols/liquid_handler.py +47 -1
- opentrons/hardware_control/types.py +6 -0
- opentrons/legacy_commands/commands.py +19 -3
- opentrons/legacy_commands/helpers.py +15 -0
- opentrons/legacy_commands/types.py +3 -2
- opentrons/protocol_api/__init__.py +2 -0
- opentrons/protocol_api/_liquid.py +39 -8
- opentrons/protocol_api/_liquid_properties.py +20 -19
- opentrons/protocol_api/_transfer_liquid_validation.py +91 -0
- opentrons/protocol_api/core/common.py +3 -1
- opentrons/protocol_api/core/engine/deck_conflict.py +11 -1
- opentrons/protocol_api/core/engine/instrument.py +1233 -65
- opentrons/protocol_api/core/engine/labware.py +8 -4
- opentrons/protocol_api/core/engine/load_labware_params.py +68 -10
- opentrons/protocol_api/core/engine/module_core.py +118 -2
- opentrons/protocol_api/core/engine/protocol.py +253 -11
- opentrons/protocol_api/core/engine/stringify.py +19 -8
- opentrons/protocol_api/core/engine/transfer_components_executor.py +853 -0
- opentrons/protocol_api/core/engine/well.py +60 -5
- opentrons/protocol_api/core/instrument.py +65 -19
- opentrons/protocol_api/core/labware.py +6 -2
- opentrons/protocol_api/core/legacy/labware_offset_provider.py +7 -3
- opentrons/protocol_api/core/legacy/legacy_instrument_core.py +69 -21
- opentrons/protocol_api/core/legacy/legacy_labware_core.py +8 -4
- opentrons/protocol_api/core/legacy/legacy_protocol_core.py +36 -0
- opentrons/protocol_api/core/legacy/legacy_well_core.py +25 -1
- opentrons/protocol_api/core/legacy/load_info.py +4 -12
- opentrons/protocol_api/core/legacy/module_geometry.py +6 -1
- opentrons/protocol_api/core/legacy/well_geometry.py +3 -3
- opentrons/protocol_api/core/legacy_simulator/legacy_instrument_core.py +67 -21
- opentrons/protocol_api/core/module.py +43 -0
- opentrons/protocol_api/core/protocol.py +33 -0
- opentrons/protocol_api/core/well.py +21 -1
- opentrons/protocol_api/instrument_context.py +245 -123
- opentrons/protocol_api/labware.py +75 -11
- opentrons/protocol_api/module_contexts.py +140 -0
- opentrons/protocol_api/protocol_context.py +156 -16
- opentrons/protocol_api/validation.py +51 -41
- opentrons/protocol_engine/__init__.py +21 -2
- opentrons/protocol_engine/actions/actions.py +5 -5
- opentrons/protocol_engine/clients/sync_client.py +6 -0
- opentrons/protocol_engine/commands/__init__.py +30 -0
- opentrons/protocol_engine/commands/absorbance_reader/__init__.py +0 -1
- opentrons/protocol_engine/commands/air_gap_in_place.py +3 -2
- opentrons/protocol_engine/commands/aspirate.py +6 -2
- opentrons/protocol_engine/commands/aspirate_in_place.py +3 -1
- opentrons/protocol_engine/commands/aspirate_while_tracking.py +237 -0
- opentrons/protocol_engine/commands/blow_out.py +2 -0
- opentrons/protocol_engine/commands/blow_out_in_place.py +4 -1
- opentrons/protocol_engine/commands/command_unions.py +69 -0
- opentrons/protocol_engine/commands/configure_for_volume.py +3 -0
- opentrons/protocol_engine/commands/dispense.py +3 -1
- opentrons/protocol_engine/commands/dispense_in_place.py +3 -0
- opentrons/protocol_engine/commands/dispense_while_tracking.py +240 -0
- opentrons/protocol_engine/commands/drop_tip.py +23 -1
- opentrons/protocol_engine/commands/evotip_dispense.py +6 -7
- opentrons/protocol_engine/commands/evotip_seal_pipette.py +2 -9
- opentrons/protocol_engine/commands/evotip_unseal_pipette.py +1 -7
- opentrons/protocol_engine/commands/flex_stacker/__init__.py +106 -0
- opentrons/protocol_engine/commands/flex_stacker/close_latch.py +72 -0
- opentrons/protocol_engine/commands/flex_stacker/common.py +15 -0
- opentrons/protocol_engine/commands/flex_stacker/empty.py +161 -0
- opentrons/protocol_engine/commands/flex_stacker/fill.py +164 -0
- opentrons/protocol_engine/commands/flex_stacker/open_latch.py +70 -0
- opentrons/protocol_engine/commands/flex_stacker/prepare_shuttle.py +112 -0
- opentrons/protocol_engine/commands/flex_stacker/retrieve.py +394 -0
- opentrons/protocol_engine/commands/flex_stacker/set_stored_labware.py +190 -0
- opentrons/protocol_engine/commands/flex_stacker/store.py +288 -0
- opentrons/protocol_engine/commands/generate_command_schema.py +31 -2
- opentrons/protocol_engine/commands/labware_handling_common.py +24 -0
- opentrons/protocol_engine/commands/liquid_probe.py +21 -12
- opentrons/protocol_engine/commands/load_labware.py +42 -39
- opentrons/protocol_engine/commands/load_lid.py +21 -13
- opentrons/protocol_engine/commands/load_lid_stack.py +130 -47
- opentrons/protocol_engine/commands/load_module.py +18 -17
- opentrons/protocol_engine/commands/load_pipette.py +3 -0
- opentrons/protocol_engine/commands/move_labware.py +139 -20
- opentrons/protocol_engine/commands/pick_up_tip.py +5 -2
- opentrons/protocol_engine/commands/pipetting_common.py +154 -7
- opentrons/protocol_engine/commands/prepare_to_aspirate.py +3 -1
- opentrons/protocol_engine/commands/reload_labware.py +6 -19
- opentrons/protocol_engine/commands/unsafe/unsafe_blow_out_in_place.py +3 -1
- opentrons/protocol_engine/errors/__init__.py +8 -0
- opentrons/protocol_engine/errors/exceptions.py +50 -0
- opentrons/protocol_engine/execution/equipment.py +123 -106
- opentrons/protocol_engine/execution/labware_movement.py +8 -6
- opentrons/protocol_engine/execution/pipetting.py +233 -26
- opentrons/protocol_engine/execution/tip_handler.py +14 -5
- opentrons/protocol_engine/labware_offset_standardization.py +173 -0
- opentrons/protocol_engine/protocol_engine.py +22 -13
- opentrons/protocol_engine/resources/deck_configuration_provider.py +94 -2
- opentrons/protocol_engine/resources/deck_data_provider.py +1 -1
- opentrons/protocol_engine/resources/labware_data_provider.py +32 -12
- opentrons/protocol_engine/resources/labware_validation.py +7 -5
- opentrons/protocol_engine/slot_standardization.py +11 -23
- opentrons/protocol_engine/state/addressable_areas.py +84 -46
- opentrons/protocol_engine/state/frustum_helpers.py +26 -10
- opentrons/protocol_engine/state/geometry.py +683 -100
- opentrons/protocol_engine/state/labware.py +252 -55
- opentrons/protocol_engine/state/module_substates/__init__.py +4 -0
- opentrons/protocol_engine/state/module_substates/flex_stacker_substate.py +68 -0
- opentrons/protocol_engine/state/module_substates/heater_shaker_module_substate.py +22 -0
- opentrons/protocol_engine/state/module_substates/temperature_module_substate.py +13 -0
- opentrons/protocol_engine/state/module_substates/thermocycler_module_substate.py +20 -0
- opentrons/protocol_engine/state/modules.py +178 -52
- opentrons/protocol_engine/state/pipettes.py +54 -0
- opentrons/protocol_engine/state/state.py +1 -1
- opentrons/protocol_engine/state/tips.py +14 -0
- opentrons/protocol_engine/state/update_types.py +180 -25
- opentrons/protocol_engine/state/wells.py +54 -8
- opentrons/protocol_engine/types/__init__.py +292 -0
- opentrons/protocol_engine/types/automatic_tip_selection.py +39 -0
- opentrons/protocol_engine/types/command_annotations.py +53 -0
- opentrons/protocol_engine/types/deck_configuration.py +72 -0
- opentrons/protocol_engine/types/execution.py +96 -0
- opentrons/protocol_engine/types/hardware_passthrough.py +25 -0
- opentrons/protocol_engine/types/instrument.py +47 -0
- opentrons/protocol_engine/types/instrument_sensors.py +47 -0
- opentrons/protocol_engine/types/labware.py +110 -0
- opentrons/protocol_engine/types/labware_movement.py +22 -0
- opentrons/protocol_engine/types/labware_offset_location.py +108 -0
- opentrons/protocol_engine/types/labware_offset_vector.py +33 -0
- opentrons/protocol_engine/types/liquid.py +40 -0
- opentrons/protocol_engine/types/liquid_class.py +59 -0
- opentrons/protocol_engine/types/liquid_handling.py +13 -0
- opentrons/protocol_engine/types/liquid_level_detection.py +137 -0
- opentrons/protocol_engine/types/location.py +193 -0
- opentrons/protocol_engine/types/module.py +269 -0
- opentrons/protocol_engine/types/partial_tip_configuration.py +76 -0
- opentrons/protocol_engine/types/run_time_parameters.py +133 -0
- opentrons/protocol_engine/types/tip.py +18 -0
- opentrons/protocol_engine/types/util.py +21 -0
- opentrons/protocol_engine/types/well_position.py +107 -0
- opentrons/protocol_reader/extract_labware_definitions.py +7 -3
- opentrons/protocol_reader/file_format_validator.py +5 -3
- opentrons/protocol_runner/json_translator.py +4 -2
- opentrons/protocol_runner/legacy_command_mapper.py +6 -2
- opentrons/protocol_runner/run_orchestrator.py +4 -1
- opentrons/protocols/advanced_control/transfers/common.py +48 -1
- opentrons/protocols/advanced_control/transfers/transfer_liquid_utils.py +204 -0
- opentrons/protocols/api_support/definitions.py +1 -1
- opentrons/protocols/api_support/instrument.py +16 -3
- opentrons/protocols/labware.py +5 -6
- opentrons/protocols/models/__init__.py +0 -21
- opentrons/simulate.py +4 -2
- opentrons/types.py +15 -6
- {opentrons-8.3.1a1.dist-info → opentrons-8.4.0a0.dist-info}/METADATA +4 -4
- {opentrons-8.3.1a1.dist-info → opentrons-8.4.0a0.dist-info}/RECORD +187 -147
- opentrons/calibration_storage/ot2/models/defaults.py +0 -0
- opentrons/calibration_storage/ot3/models/defaults.py +0 -0
- opentrons/protocol_api/core/legacy/legacy_robot_core.py +0 -0
- opentrons/protocol_engine/types.py +0 -1311
- {opentrons-8.3.1a1.dist-info → opentrons-8.4.0a0.dist-info}/LICENSE +0 -0
- {opentrons-8.3.1a1.dist-info → opentrons-8.4.0a0.dist-info}/WHEEL +0 -0
- {opentrons-8.3.1a1.dist-info → opentrons-8.4.0a0.dist-info}/entry_points.txt +0 -0
- {opentrons-8.3.1a1.dist-info → opentrons-8.4.0a0.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
"""Command models to prepare the stacker shuttle for movement."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
from typing import Literal, Union, TYPE_CHECKING
|
|
7
|
+
from typing_extensions import Type
|
|
8
|
+
|
|
9
|
+
from pydantic import BaseModel, Field
|
|
10
|
+
|
|
11
|
+
from .common import FlexStackerStallOrCollisionError
|
|
12
|
+
from opentrons_shared_data.errors.exceptions import FlexStackerStallError
|
|
13
|
+
|
|
14
|
+
from ..command import (
|
|
15
|
+
AbstractCommandImpl,
|
|
16
|
+
BaseCommand,
|
|
17
|
+
BaseCommandCreate,
|
|
18
|
+
SuccessData,
|
|
19
|
+
DefinedErrorData,
|
|
20
|
+
)
|
|
21
|
+
from ...errors import ErrorOccurrence
|
|
22
|
+
from ...resources import ModelUtils
|
|
23
|
+
|
|
24
|
+
if TYPE_CHECKING:
|
|
25
|
+
from ...state.state import StateView
|
|
26
|
+
from ...execution import EquipmentHandler
|
|
27
|
+
|
|
28
|
+
PrepareShuttleCommandType = Literal["flexStacker/prepareShuttle"]
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class PrepareShuttleParams(BaseModel):
|
|
32
|
+
"""The parameters for a PrepareShuttle command."""
|
|
33
|
+
|
|
34
|
+
moduleId: str = Field(..., description="Unique ID of the Flex Stacker")
|
|
35
|
+
ignoreLatch: bool = Field(
|
|
36
|
+
default=False, description="Ignore the latch state of the shuttle"
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
class PrepareShuttleResult(BaseModel):
|
|
41
|
+
"""Result data from a stacker PrepareShuttle command."""
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
_ExecuteReturn = Union[
|
|
45
|
+
SuccessData[PrepareShuttleResult],
|
|
46
|
+
DefinedErrorData[FlexStackerStallOrCollisionError],
|
|
47
|
+
]
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
class PrepareShuttleImpl(AbstractCommandImpl[PrepareShuttleParams, _ExecuteReturn]):
|
|
51
|
+
"""Implementation of a stacker prepare shuttle command."""
|
|
52
|
+
|
|
53
|
+
def __init__(
|
|
54
|
+
self,
|
|
55
|
+
state_view: StateView,
|
|
56
|
+
equipment: EquipmentHandler,
|
|
57
|
+
model_utils: ModelUtils,
|
|
58
|
+
**kwargs: object,
|
|
59
|
+
) -> None:
|
|
60
|
+
self._state_view = state_view
|
|
61
|
+
self._equipment = equipment
|
|
62
|
+
self._model_utils = model_utils
|
|
63
|
+
|
|
64
|
+
async def execute(self, params: PrepareShuttleParams) -> _ExecuteReturn:
|
|
65
|
+
"""Execute the stacker prepare shuttle command."""
|
|
66
|
+
stacker_state = self._state_view.modules.get_flex_stacker_substate(
|
|
67
|
+
params.moduleId
|
|
68
|
+
)
|
|
69
|
+
# Allow propagation of ModuleNotAttachedError.
|
|
70
|
+
stacker_hw = self._equipment.get_module_hardware_api(stacker_state.module_id)
|
|
71
|
+
|
|
72
|
+
try:
|
|
73
|
+
if stacker_hw is not None:
|
|
74
|
+
await stacker_hw.home_all(params.ignoreLatch)
|
|
75
|
+
except FlexStackerStallError as e:
|
|
76
|
+
return DefinedErrorData(
|
|
77
|
+
public=FlexStackerStallOrCollisionError(
|
|
78
|
+
id=self._model_utils.generate_id(),
|
|
79
|
+
createdAt=self._model_utils.get_timestamp(),
|
|
80
|
+
wrappedErrors=[
|
|
81
|
+
ErrorOccurrence.from_failed(
|
|
82
|
+
id=self._model_utils.generate_id(),
|
|
83
|
+
createdAt=self._model_utils.get_timestamp(),
|
|
84
|
+
error=e,
|
|
85
|
+
)
|
|
86
|
+
],
|
|
87
|
+
),
|
|
88
|
+
)
|
|
89
|
+
# TODO we should also add a check for shuttle not detected error
|
|
90
|
+
|
|
91
|
+
return SuccessData(public=PrepareShuttleResult())
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
class PrepareShuttle(
|
|
95
|
+
BaseCommand[PrepareShuttleParams, PrepareShuttleResult, ErrorOccurrence]
|
|
96
|
+
):
|
|
97
|
+
"""A command to prepare Flex Stacker shuttle."""
|
|
98
|
+
|
|
99
|
+
commandType: PrepareShuttleCommandType = "flexStacker/prepareShuttle"
|
|
100
|
+
params: PrepareShuttleParams
|
|
101
|
+
result: PrepareShuttleResult | None = None
|
|
102
|
+
|
|
103
|
+
_ImplementationCls: Type[PrepareShuttleImpl] = PrepareShuttleImpl
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
class PrepareShuttleCreate(BaseCommandCreate[PrepareShuttleParams]):
|
|
107
|
+
"""A request to execute a Flex Stacker PrepareShuttle command."""
|
|
108
|
+
|
|
109
|
+
commandType: PrepareShuttleCommandType = "flexStacker/prepareShuttle"
|
|
110
|
+
params: PrepareShuttleParams
|
|
111
|
+
|
|
112
|
+
_CommandCls: Type[PrepareShuttle] = PrepareShuttle
|
|
@@ -0,0 +1,394 @@
|
|
|
1
|
+
"""Command models to retrieve a labware from a Flex Stacker."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
from typing import Literal, TYPE_CHECKING, Any, Union
|
|
5
|
+
from typing_extensions import Type
|
|
6
|
+
|
|
7
|
+
from pydantic import BaseModel, Field
|
|
8
|
+
from pydantic.json_schema import SkipJsonSchema
|
|
9
|
+
|
|
10
|
+
from ..command import (
|
|
11
|
+
AbstractCommandImpl,
|
|
12
|
+
BaseCommand,
|
|
13
|
+
BaseCommandCreate,
|
|
14
|
+
SuccessData,
|
|
15
|
+
DefinedErrorData,
|
|
16
|
+
)
|
|
17
|
+
from ..flex_stacker.common import FlexStackerStallOrCollisionError
|
|
18
|
+
from ...errors import (
|
|
19
|
+
ErrorOccurrence,
|
|
20
|
+
CannotPerformModuleAction,
|
|
21
|
+
LocationIsOccupiedError,
|
|
22
|
+
FlexStackerLabwarePoolNotYetDefinedError,
|
|
23
|
+
)
|
|
24
|
+
from ...resources import ModelUtils
|
|
25
|
+
from ...state import update_types
|
|
26
|
+
from ...types import (
|
|
27
|
+
ModuleLocation,
|
|
28
|
+
OnLabwareLocation,
|
|
29
|
+
LabwareLocationSequence,
|
|
30
|
+
LabwareLocation,
|
|
31
|
+
LoadedLabware,
|
|
32
|
+
)
|
|
33
|
+
from opentrons_shared_data.labware.labware_definition import LabwareDefinition
|
|
34
|
+
from opentrons_shared_data.errors.exceptions import FlexStackerStallError
|
|
35
|
+
from opentrons.calibration_storage.helpers import uri_from_details
|
|
36
|
+
|
|
37
|
+
if TYPE_CHECKING:
|
|
38
|
+
from opentrons.protocol_engine.state.state import StateView
|
|
39
|
+
from opentrons.protocol_engine.state.module_substates import FlexStackerSubState
|
|
40
|
+
from opentrons.protocol_engine.execution import EquipmentHandler
|
|
41
|
+
|
|
42
|
+
RetrieveCommandType = Literal["flexStacker/retrieve"]
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def _remove_default(s: dict[str, Any]) -> None:
|
|
46
|
+
s.pop("default", None)
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
class RetrieveParams(BaseModel):
|
|
50
|
+
"""Input parameters for a labware retrieval command."""
|
|
51
|
+
|
|
52
|
+
moduleId: str = Field(
|
|
53
|
+
...,
|
|
54
|
+
description="Unique ID of the Flex Stacker.",
|
|
55
|
+
)
|
|
56
|
+
labwareId: str | SkipJsonSchema[None] = Field(
|
|
57
|
+
None,
|
|
58
|
+
description="An optional ID to assign to this labware. If None, an ID "
|
|
59
|
+
"will be generated.",
|
|
60
|
+
json_schema_extra=_remove_default,
|
|
61
|
+
)
|
|
62
|
+
displayName: str | SkipJsonSchema[None] = Field(
|
|
63
|
+
None,
|
|
64
|
+
description="An optional user-specified display name "
|
|
65
|
+
"or label for this labware.",
|
|
66
|
+
json_schema_extra=_remove_default,
|
|
67
|
+
)
|
|
68
|
+
adapterId: str | SkipJsonSchema[None] = Field(
|
|
69
|
+
None,
|
|
70
|
+
description="An optional ID to assign to an adapter. If None, an ID "
|
|
71
|
+
"will be generated.",
|
|
72
|
+
json_schema_extra=_remove_default,
|
|
73
|
+
)
|
|
74
|
+
lidId: str | SkipJsonSchema[None] = Field(
|
|
75
|
+
None,
|
|
76
|
+
description="An optional ID to assign to a lid. If None, an ID "
|
|
77
|
+
"will be generated.",
|
|
78
|
+
json_schema_extra=_remove_default,
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
class RetrieveResult(BaseModel):
|
|
83
|
+
"""Result data from a labware retrieval command."""
|
|
84
|
+
|
|
85
|
+
labwareId: str = Field(
|
|
86
|
+
...,
|
|
87
|
+
description="The labware ID of the primary retrieved labware.",
|
|
88
|
+
)
|
|
89
|
+
adapterId: str | None = Field(
|
|
90
|
+
None,
|
|
91
|
+
description="The optional Adapter Labware ID of the adapter under a primary labware.",
|
|
92
|
+
)
|
|
93
|
+
lidId: str | None = Field(
|
|
94
|
+
None,
|
|
95
|
+
description="The optional Lid Labware ID of the lid on a primary labware.",
|
|
96
|
+
)
|
|
97
|
+
primaryLocationSequence: LabwareLocationSequence = Field(
|
|
98
|
+
..., description="The origin location of the primary labware."
|
|
99
|
+
)
|
|
100
|
+
lidLocationSequence: LabwareLocationSequence | None = Field(
|
|
101
|
+
None,
|
|
102
|
+
description="The origin location of the adapter labware under a primary labware.",
|
|
103
|
+
)
|
|
104
|
+
adapterLocationSequence: LabwareLocationSequence | None = Field(
|
|
105
|
+
None, description="The origin location of the lid labware on a primary labware."
|
|
106
|
+
)
|
|
107
|
+
primaryLabwareURI: str = Field(
|
|
108
|
+
...,
|
|
109
|
+
description="The labware definition URI of the primary labware.",
|
|
110
|
+
)
|
|
111
|
+
adapterLabwareURI: str | None = Field(
|
|
112
|
+
None,
|
|
113
|
+
description="The labware definition URI of the adapter labware.",
|
|
114
|
+
)
|
|
115
|
+
lidLabwareURI: str | None = Field(
|
|
116
|
+
None,
|
|
117
|
+
description="The labware definition URI of the lid labware.",
|
|
118
|
+
)
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
_ExecuteReturn = Union[
|
|
122
|
+
SuccessData[RetrieveResult],
|
|
123
|
+
DefinedErrorData[FlexStackerStallOrCollisionError],
|
|
124
|
+
]
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
class RetrieveImpl(AbstractCommandImpl[RetrieveParams, _ExecuteReturn]):
|
|
128
|
+
"""Implementation of a labware retrieval command."""
|
|
129
|
+
|
|
130
|
+
def __init__(
|
|
131
|
+
self,
|
|
132
|
+
state_view: StateView,
|
|
133
|
+
equipment: EquipmentHandler,
|
|
134
|
+
model_utils: ModelUtils,
|
|
135
|
+
**kwargs: object,
|
|
136
|
+
) -> None:
|
|
137
|
+
self._state_view = state_view
|
|
138
|
+
self._equipment = equipment
|
|
139
|
+
self._model_utils = model_utils
|
|
140
|
+
|
|
141
|
+
async def _load_labware_from_pool(
|
|
142
|
+
self, params: RetrieveParams, stacker_state: FlexStackerSubState
|
|
143
|
+
) -> tuple[RetrieveResult, update_types.StateUpdate]:
|
|
144
|
+
state_update = update_types.StateUpdate()
|
|
145
|
+
|
|
146
|
+
# If there is an adapter load it
|
|
147
|
+
adapter_lw = None
|
|
148
|
+
lid_lw = None
|
|
149
|
+
definitions_by_id: dict[str, LabwareDefinition] = {}
|
|
150
|
+
offset_ids_by_id: dict[str, str | None] = {}
|
|
151
|
+
display_names_by_id: dict[str, str | None] = {}
|
|
152
|
+
new_locations_by_id: dict[str, LabwareLocation] = {}
|
|
153
|
+
labware_by_id: dict[str, LoadedLabware] = {}
|
|
154
|
+
adapter_uri: str | None = None
|
|
155
|
+
if stacker_state.pool_adapter_definition is not None:
|
|
156
|
+
adapter_location = ModuleLocation(moduleId=params.moduleId)
|
|
157
|
+
adapter_lw = await self._equipment.load_labware_from_definition(
|
|
158
|
+
definition=stacker_state.pool_adapter_definition,
|
|
159
|
+
location=adapter_location,
|
|
160
|
+
labware_id=params.adapterId,
|
|
161
|
+
labware_pending_load=labware_by_id,
|
|
162
|
+
)
|
|
163
|
+
definitions_by_id[adapter_lw.labware_id] = adapter_lw.definition
|
|
164
|
+
offset_ids_by_id[adapter_lw.labware_id] = adapter_lw.offsetId
|
|
165
|
+
display_names_by_id[
|
|
166
|
+
adapter_lw.labware_id
|
|
167
|
+
] = adapter_lw.definition.metadata.displayName
|
|
168
|
+
new_locations_by_id[adapter_lw.labware_id] = adapter_location
|
|
169
|
+
adapter_uri = str(
|
|
170
|
+
uri_from_details(
|
|
171
|
+
namespace=adapter_lw.definition.namespace,
|
|
172
|
+
load_name=adapter_lw.definition.parameters.loadName,
|
|
173
|
+
version=adapter_lw.definition.version,
|
|
174
|
+
)
|
|
175
|
+
)
|
|
176
|
+
labware_by_id[adapter_lw.labware_id] = LoadedLabware.model_construct(
|
|
177
|
+
id=adapter_lw.labware_id,
|
|
178
|
+
location=adapter_location,
|
|
179
|
+
loadName=adapter_lw.definition.parameters.loadName,
|
|
180
|
+
definitionUri=adapter_uri,
|
|
181
|
+
offsetId=None,
|
|
182
|
+
)
|
|
183
|
+
# Always load the primary labware
|
|
184
|
+
if stacker_state.pool_primary_definition is None:
|
|
185
|
+
raise CannotPerformModuleAction(
|
|
186
|
+
f"Flex Stacker {params.moduleId} has no labware to retrieve"
|
|
187
|
+
)
|
|
188
|
+
primary_location: ModuleLocation | OnLabwareLocation = (
|
|
189
|
+
ModuleLocation(moduleId=params.moduleId)
|
|
190
|
+
if adapter_lw is None
|
|
191
|
+
else OnLabwareLocation(labwareId=adapter_lw.labware_id)
|
|
192
|
+
)
|
|
193
|
+
loaded_labware = await self._equipment.load_labware_from_definition(
|
|
194
|
+
definition=stacker_state.pool_primary_definition,
|
|
195
|
+
location=primary_location,
|
|
196
|
+
labware_id=params.labwareId,
|
|
197
|
+
labware_pending_load={lw_id: lw for lw_id, lw in labware_by_id.items()},
|
|
198
|
+
)
|
|
199
|
+
definitions_by_id[loaded_labware.labware_id] = loaded_labware.definition
|
|
200
|
+
offset_ids_by_id[loaded_labware.labware_id] = loaded_labware.offsetId
|
|
201
|
+
display_names_by_id[
|
|
202
|
+
loaded_labware.labware_id
|
|
203
|
+
] = loaded_labware.definition.metadata.displayName
|
|
204
|
+
new_locations_by_id[loaded_labware.labware_id] = primary_location
|
|
205
|
+
primary_uri = str(
|
|
206
|
+
uri_from_details(
|
|
207
|
+
namespace=loaded_labware.definition.namespace,
|
|
208
|
+
load_name=loaded_labware.definition.parameters.loadName,
|
|
209
|
+
version=loaded_labware.definition.version,
|
|
210
|
+
)
|
|
211
|
+
)
|
|
212
|
+
labware_by_id[loaded_labware.labware_id] = LoadedLabware.model_construct(
|
|
213
|
+
id=loaded_labware.labware_id,
|
|
214
|
+
location=primary_location,
|
|
215
|
+
loadName=loaded_labware.definition.parameters.loadName,
|
|
216
|
+
definitionUri=primary_uri,
|
|
217
|
+
)
|
|
218
|
+
|
|
219
|
+
lid_uri: str | None = None
|
|
220
|
+
# If there is a lid load it
|
|
221
|
+
if stacker_state.pool_lid_definition is not None:
|
|
222
|
+
lid_location = OnLabwareLocation(labwareId=loaded_labware.labware_id)
|
|
223
|
+
lid_lw = await self._equipment.load_labware_from_definition(
|
|
224
|
+
definition=stacker_state.pool_lid_definition,
|
|
225
|
+
location=lid_location,
|
|
226
|
+
labware_id=params.lidId,
|
|
227
|
+
labware_pending_load={lw_id: lw for lw_id, lw in labware_by_id.items()},
|
|
228
|
+
)
|
|
229
|
+
lid_uri = str(
|
|
230
|
+
uri_from_details(
|
|
231
|
+
namespace=lid_lw.definition.namespace,
|
|
232
|
+
load_name=lid_lw.definition.parameters.loadName,
|
|
233
|
+
version=lid_lw.definition.version,
|
|
234
|
+
)
|
|
235
|
+
)
|
|
236
|
+
definitions_by_id[lid_lw.labware_id] = lid_lw.definition
|
|
237
|
+
offset_ids_by_id[lid_lw.labware_id] = lid_lw.offsetId
|
|
238
|
+
display_names_by_id[
|
|
239
|
+
lid_lw.labware_id
|
|
240
|
+
] = lid_lw.definition.metadata.displayName
|
|
241
|
+
new_locations_by_id[lid_lw.labware_id] = lid_location
|
|
242
|
+
labware_by_id[lid_lw.labware_id] = LoadedLabware.model_construct(
|
|
243
|
+
id=lid_lw.labware_id,
|
|
244
|
+
location=lid_location,
|
|
245
|
+
loadName=lid_lw.definition.parameters.loadName,
|
|
246
|
+
definitionUri=lid_uri,
|
|
247
|
+
offsetId=None,
|
|
248
|
+
)
|
|
249
|
+
|
|
250
|
+
# Get the labware dimensions for the labware being retrieved,
|
|
251
|
+
# which is the first one in the hopper labware id list
|
|
252
|
+
primary_location_sequence = (
|
|
253
|
+
self._state_view.geometry.get_predicted_location_sequence(
|
|
254
|
+
new_locations_by_id[loaded_labware.labware_id], labware_by_id
|
|
255
|
+
)
|
|
256
|
+
)
|
|
257
|
+
adapter_location_sequence = (
|
|
258
|
+
self._state_view.geometry.get_predicted_location_sequence(
|
|
259
|
+
new_locations_by_id[adapter_lw.labware_id], labware_by_id
|
|
260
|
+
)
|
|
261
|
+
if adapter_lw is not None
|
|
262
|
+
else None
|
|
263
|
+
)
|
|
264
|
+
lid_location_sequence = (
|
|
265
|
+
self._state_view.geometry.get_predicted_location_sequence(
|
|
266
|
+
new_locations_by_id[lid_lw.labware_id], labware_by_id
|
|
267
|
+
)
|
|
268
|
+
if lid_lw is not None
|
|
269
|
+
else None
|
|
270
|
+
)
|
|
271
|
+
|
|
272
|
+
state_update.set_batch_loaded_labware(
|
|
273
|
+
definitions_by_id=definitions_by_id,
|
|
274
|
+
display_names_by_id=display_names_by_id,
|
|
275
|
+
offset_ids_by_id=offset_ids_by_id,
|
|
276
|
+
new_locations_by_id=new_locations_by_id,
|
|
277
|
+
)
|
|
278
|
+
state_update.update_flex_stacker_labware_pool_count(
|
|
279
|
+
module_id=params.moduleId, count=stacker_state.pool_count - 1
|
|
280
|
+
)
|
|
281
|
+
|
|
282
|
+
if lid_lw is not None:
|
|
283
|
+
state_update.set_lids(
|
|
284
|
+
parent_labware_ids=[loaded_labware.labware_id],
|
|
285
|
+
lid_ids=[lid_lw.labware_id],
|
|
286
|
+
)
|
|
287
|
+
|
|
288
|
+
return (
|
|
289
|
+
RetrieveResult(
|
|
290
|
+
labwareId=loaded_labware.labware_id,
|
|
291
|
+
adapterId=adapter_lw.labware_id if adapter_lw is not None else None,
|
|
292
|
+
lidId=lid_lw.labware_id if lid_lw is not None else None,
|
|
293
|
+
primaryLocationSequence=primary_location_sequence,
|
|
294
|
+
adapterLocationSequence=adapter_location_sequence,
|
|
295
|
+
lidLocationSequence=lid_location_sequence,
|
|
296
|
+
primaryLabwareURI=primary_uri,
|
|
297
|
+
adapterLabwareURI=adapter_uri,
|
|
298
|
+
lidLabwareURI=lid_uri,
|
|
299
|
+
),
|
|
300
|
+
state_update,
|
|
301
|
+
)
|
|
302
|
+
|
|
303
|
+
async def execute(self, params: RetrieveParams) -> _ExecuteReturn:
|
|
304
|
+
"""Execute the labware retrieval command."""
|
|
305
|
+
stacker_state = self._state_view.modules.get_flex_stacker_substate(
|
|
306
|
+
params.moduleId
|
|
307
|
+
)
|
|
308
|
+
|
|
309
|
+
pool_definitions = stacker_state.get_pool_definition_ordered_list()
|
|
310
|
+
if pool_definitions is None:
|
|
311
|
+
location = self._state_view.modules.get_location(params.moduleId)
|
|
312
|
+
raise FlexStackerLabwarePoolNotYetDefinedError(
|
|
313
|
+
message=f"The Flex Stacker in {location} has not been configured yet and cannot be filled."
|
|
314
|
+
)
|
|
315
|
+
|
|
316
|
+
if stacker_state.pool_count == 0:
|
|
317
|
+
raise CannotPerformModuleAction(
|
|
318
|
+
message="Cannot retrieve labware from Flex Stacker because it contains no labware"
|
|
319
|
+
)
|
|
320
|
+
|
|
321
|
+
stacker_loc = ModuleLocation(moduleId=params.moduleId)
|
|
322
|
+
# Allow propagation of ModuleNotAttachedError.
|
|
323
|
+
stacker_hw = self._equipment.get_module_hardware_api(stacker_state.module_id)
|
|
324
|
+
|
|
325
|
+
try:
|
|
326
|
+
self._state_view.labware.raise_if_labware_in_location(stacker_loc)
|
|
327
|
+
except LocationIsOccupiedError:
|
|
328
|
+
raise CannotPerformModuleAction(
|
|
329
|
+
"Cannot retrieve a labware from Flex Stacker if the carriage is occupied"
|
|
330
|
+
)
|
|
331
|
+
|
|
332
|
+
retrieve_result, state_update = await self._load_labware_from_pool(
|
|
333
|
+
params, stacker_state
|
|
334
|
+
)
|
|
335
|
+
|
|
336
|
+
labware_height = self._state_view.geometry.get_height_of_labware_stack(
|
|
337
|
+
definitions=pool_definitions
|
|
338
|
+
)
|
|
339
|
+
|
|
340
|
+
try:
|
|
341
|
+
if stacker_hw is not None:
|
|
342
|
+
await stacker_hw.dispense_labware(labware_height=labware_height)
|
|
343
|
+
except FlexStackerStallError as e:
|
|
344
|
+
return DefinedErrorData(
|
|
345
|
+
public=FlexStackerStallOrCollisionError(
|
|
346
|
+
id=self._model_utils.generate_id(),
|
|
347
|
+
createdAt=self._model_utils.get_timestamp(),
|
|
348
|
+
wrappedErrors=[
|
|
349
|
+
ErrorOccurrence.from_failed(
|
|
350
|
+
id=self._model_utils.generate_id(),
|
|
351
|
+
createdAt=self._model_utils.get_timestamp(),
|
|
352
|
+
error=e,
|
|
353
|
+
)
|
|
354
|
+
],
|
|
355
|
+
),
|
|
356
|
+
)
|
|
357
|
+
|
|
358
|
+
# Update the state to reflect the labware is now in the Flex Stacker slot
|
|
359
|
+
# todo(chb, 2025-02-19): This ModuleLocation piece should probably instead be an AddressableAreaLocation
|
|
360
|
+
# but that has implications for where labware are set by things like module.load_labware(..) and what
|
|
361
|
+
# happens when we move labware.
|
|
362
|
+
stacker_area = (
|
|
363
|
+
self._state_view.modules.ensure_and_convert_module_fixture_location(
|
|
364
|
+
deck_slot=self._state_view.modules.get_location(
|
|
365
|
+
params.moduleId
|
|
366
|
+
).slotName,
|
|
367
|
+
model=self._state_view.modules.get(params.moduleId).model,
|
|
368
|
+
)
|
|
369
|
+
)
|
|
370
|
+
state_update.set_addressable_area_used(stacker_area)
|
|
371
|
+
|
|
372
|
+
return SuccessData(
|
|
373
|
+
public=retrieve_result,
|
|
374
|
+
state_update=state_update,
|
|
375
|
+
)
|
|
376
|
+
|
|
377
|
+
|
|
378
|
+
class Retrieve(BaseCommand[RetrieveParams, RetrieveResult, ErrorOccurrence]):
|
|
379
|
+
"""A command to retrieve a labware from a Flex Stacker."""
|
|
380
|
+
|
|
381
|
+
commandType: RetrieveCommandType = "flexStacker/retrieve"
|
|
382
|
+
params: RetrieveParams
|
|
383
|
+
result: RetrieveResult | None = None
|
|
384
|
+
|
|
385
|
+
_ImplementationCls: Type[RetrieveImpl] = RetrieveImpl
|
|
386
|
+
|
|
387
|
+
|
|
388
|
+
class RetrieveCreate(BaseCommandCreate[RetrieveParams]):
|
|
389
|
+
"""A request to execute a Flex Stacker retrieve command."""
|
|
390
|
+
|
|
391
|
+
commandType: RetrieveCommandType = "flexStacker/retrieve"
|
|
392
|
+
params: RetrieveParams
|
|
393
|
+
|
|
394
|
+
_CommandCls: Type[Retrieve] = Retrieve
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
"""Command models to configure the stored labware pool of a Flex Stacker.."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
from typing import Optional, Literal, TYPE_CHECKING
|
|
5
|
+
from typing_extensions import Type
|
|
6
|
+
|
|
7
|
+
from pydantic import BaseModel, Field
|
|
8
|
+
|
|
9
|
+
from opentrons_shared_data.labware.labware_definition import LabwareDefinition
|
|
10
|
+
|
|
11
|
+
from ..command import AbstractCommandImpl, BaseCommand, BaseCommandCreate, SuccessData
|
|
12
|
+
from ...errors import (
|
|
13
|
+
ErrorOccurrence,
|
|
14
|
+
)
|
|
15
|
+
from ...errors.exceptions import FlexStackerNotLogicallyEmptyError
|
|
16
|
+
from ...state import update_types
|
|
17
|
+
|
|
18
|
+
if TYPE_CHECKING:
|
|
19
|
+
from opentrons.protocol_engine.state.state import StateView
|
|
20
|
+
from opentrons.protocol_engine.execution import EquipmentHandler
|
|
21
|
+
|
|
22
|
+
SetStoredLabwareCommandType = Literal["flexStacker/setStoredLabware"]
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class StackerStoredLabwareDetails(BaseModel):
|
|
26
|
+
"""The parameters defining a labware to be stored in the stacker."""
|
|
27
|
+
|
|
28
|
+
loadName: str = Field(
|
|
29
|
+
..., description="Name used to reference the definition of this labware."
|
|
30
|
+
)
|
|
31
|
+
namespace: str = Field(
|
|
32
|
+
..., description="Namespace of the definition of this labware."
|
|
33
|
+
)
|
|
34
|
+
version: int = Field(..., description="Version of the definition of this labware.")
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class SetStoredLabwareParams(BaseModel):
|
|
38
|
+
"""Input parameters for a setStoredLabware command."""
|
|
39
|
+
|
|
40
|
+
moduleId: str = Field(
|
|
41
|
+
...,
|
|
42
|
+
description="Unique ID of the Flex Stacker.",
|
|
43
|
+
)
|
|
44
|
+
primaryLabware: StackerStoredLabwareDetails = Field(
|
|
45
|
+
...,
|
|
46
|
+
description="The details of the primary labware (i.e. not the lid or adapter, if any) stored in the stacker.",
|
|
47
|
+
)
|
|
48
|
+
lidLabware: StackerStoredLabwareDetails | None = Field(
|
|
49
|
+
default=None,
|
|
50
|
+
description="The details of the lid on the primary labware, if any.",
|
|
51
|
+
)
|
|
52
|
+
adapterLabware: StackerStoredLabwareDetails | None = Field(
|
|
53
|
+
default=None,
|
|
54
|
+
description="The details of the adapter under the primary labware, if any.",
|
|
55
|
+
)
|
|
56
|
+
initialCount: int | None = Field(
|
|
57
|
+
None,
|
|
58
|
+
description=(
|
|
59
|
+
"The number of labware that should be initially stored in the stacker. This number will be silently clamped to "
|
|
60
|
+
"the maximum number of labware that will fit; do not rely on the parameter to know how many labware are in the stacker."
|
|
61
|
+
),
|
|
62
|
+
ge=0,
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
class SetStoredLabwareResult(BaseModel):
|
|
67
|
+
"""Result data from a setstoredlabware command."""
|
|
68
|
+
|
|
69
|
+
primaryLabwareDefinition: LabwareDefinition = Field(
|
|
70
|
+
..., description="The definition of the primary labware."
|
|
71
|
+
)
|
|
72
|
+
lidLabwareDefinition: LabwareDefinition | None = Field(
|
|
73
|
+
..., description="The definition of the lid on the primary labware, if any."
|
|
74
|
+
)
|
|
75
|
+
adapterLabwareDefinition: LabwareDefinition | None = Field(
|
|
76
|
+
...,
|
|
77
|
+
description="The definition of the adapter under the primary labware, if any.",
|
|
78
|
+
)
|
|
79
|
+
count: int = Field(
|
|
80
|
+
..., description="The number of labware loaded into the stacker labware pool."
|
|
81
|
+
)
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
class SetStoredLabwareImpl(
|
|
85
|
+
AbstractCommandImpl[SetStoredLabwareParams, SuccessData[SetStoredLabwareResult]]
|
|
86
|
+
):
|
|
87
|
+
"""Implementation of a setstoredlabware command."""
|
|
88
|
+
|
|
89
|
+
def __init__(
|
|
90
|
+
self,
|
|
91
|
+
state_view: StateView,
|
|
92
|
+
equipment: EquipmentHandler,
|
|
93
|
+
**kwargs: object,
|
|
94
|
+
) -> None:
|
|
95
|
+
self._state_view = state_view
|
|
96
|
+
self._equipment = equipment
|
|
97
|
+
|
|
98
|
+
async def execute(
|
|
99
|
+
self, params: SetStoredLabwareParams
|
|
100
|
+
) -> SuccessData[SetStoredLabwareResult]:
|
|
101
|
+
"""Execute the setstoredlabwarecommand."""
|
|
102
|
+
stacker_state = self._state_view.modules.get_flex_stacker_substate(
|
|
103
|
+
params.moduleId
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
if stacker_state.pool_count != 0:
|
|
107
|
+
# Note: this error catches if the protocol tells us the stacker is not empty, making this command
|
|
108
|
+
# invalid at this point in the protocol. This error is not recoverable and should occur during
|
|
109
|
+
# analysis; the protocol must be changed.
|
|
110
|
+
|
|
111
|
+
raise FlexStackerNotLogicallyEmptyError(
|
|
112
|
+
message=(
|
|
113
|
+
"The Flex Stacker must be known to be empty before reconfiguring its labware pool, but it has "
|
|
114
|
+
f"a pool of {stacker_state.pool_count} labware"
|
|
115
|
+
)
|
|
116
|
+
)
|
|
117
|
+
|
|
118
|
+
labware_def, _ = await self._equipment.load_definition_for_details(
|
|
119
|
+
load_name=params.primaryLabware.loadName,
|
|
120
|
+
namespace=params.primaryLabware.namespace,
|
|
121
|
+
version=params.primaryLabware.version,
|
|
122
|
+
)
|
|
123
|
+
lid_def: LabwareDefinition | None = None
|
|
124
|
+
if params.lidLabware:
|
|
125
|
+
lid_def, _ = await self._equipment.load_definition_for_details(
|
|
126
|
+
load_name=params.lidLabware.loadName,
|
|
127
|
+
namespace=params.lidLabware.namespace,
|
|
128
|
+
version=params.lidLabware.version,
|
|
129
|
+
)
|
|
130
|
+
adapter_def: LabwareDefinition | None = None
|
|
131
|
+
if params.adapterLabware:
|
|
132
|
+
adapter_def, _ = await self._equipment.load_definition_for_details(
|
|
133
|
+
load_name=params.adapterLabware.loadName,
|
|
134
|
+
namespace=params.adapterLabware.namespace,
|
|
135
|
+
version=params.adapterLabware.version,
|
|
136
|
+
)
|
|
137
|
+
|
|
138
|
+
self._state_view.labware.raise_if_stacker_labware_pool_is_not_valid(
|
|
139
|
+
labware_def, lid_def, adapter_def
|
|
140
|
+
)
|
|
141
|
+
|
|
142
|
+
pool_height = self._state_view.geometry.get_height_of_labware_stack(
|
|
143
|
+
[x for x in [lid_def, labware_def, adapter_def] if x is not None]
|
|
144
|
+
)
|
|
145
|
+
max_pool_count = self._state_view.modules.stacker_max_pool_count_by_height(
|
|
146
|
+
params.moduleId, pool_height
|
|
147
|
+
)
|
|
148
|
+
|
|
149
|
+
initial_count = (
|
|
150
|
+
params.initialCount if params.initialCount is not None else max_pool_count
|
|
151
|
+
)
|
|
152
|
+
count = min(initial_count, max_pool_count)
|
|
153
|
+
|
|
154
|
+
state_update = (
|
|
155
|
+
update_types.StateUpdate()
|
|
156
|
+
.update_flex_stacker_labware_pool_definition(
|
|
157
|
+
params.moduleId, max_pool_count, labware_def, adapter_def, lid_def
|
|
158
|
+
)
|
|
159
|
+
.update_flex_stacker_labware_pool_count(params.moduleId, count)
|
|
160
|
+
)
|
|
161
|
+
return SuccessData(
|
|
162
|
+
public=SetStoredLabwareResult.model_construct(
|
|
163
|
+
primaryLabwareDefinition=labware_def,
|
|
164
|
+
lidLabwareDefinition=lid_def,
|
|
165
|
+
adapterLabwareDefinition=adapter_def,
|
|
166
|
+
count=count,
|
|
167
|
+
),
|
|
168
|
+
state_update=state_update,
|
|
169
|
+
)
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
class SetStoredLabware(
|
|
173
|
+
BaseCommand[SetStoredLabwareParams, SetStoredLabwareResult, ErrorOccurrence]
|
|
174
|
+
):
|
|
175
|
+
"""A command to setstoredlabware the Flex Stacker."""
|
|
176
|
+
|
|
177
|
+
commandType: SetStoredLabwareCommandType = "flexStacker/setStoredLabware"
|
|
178
|
+
params: SetStoredLabwareParams
|
|
179
|
+
result: Optional[SetStoredLabwareResult] = None
|
|
180
|
+
|
|
181
|
+
_ImplementationCls: Type[SetStoredLabwareImpl] = SetStoredLabwareImpl
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
class SetStoredLabwareCreate(BaseCommandCreate[SetStoredLabwareParams]):
|
|
185
|
+
"""A request to execute a Flex Stacker SetStoredLabware command."""
|
|
186
|
+
|
|
187
|
+
commandType: SetStoredLabwareCommandType = "flexStacker/setStoredLabware"
|
|
188
|
+
params: SetStoredLabwareParams
|
|
189
|
+
|
|
190
|
+
_CommandCls: Type[SetStoredLabware] = SetStoredLabware
|