opentrons 8.3.0a0__py2.py3-none-any.whl → 8.3.0a2__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.
- opentrons/calibration_storage/deck_configuration.py +3 -3
- opentrons/calibration_storage/file_operators.py +3 -3
- opentrons/calibration_storage/helpers.py +3 -1
- opentrons/calibration_storage/ot2/models/v1.py +16 -29
- opentrons/calibration_storage/ot2/tip_length.py +7 -4
- opentrons/calibration_storage/ot3/models/v1.py +14 -23
- opentrons/cli/analyze.py +18 -6
- opentrons/drivers/asyncio/communication/__init__.py +2 -0
- opentrons/drivers/asyncio/communication/errors.py +16 -3
- opentrons/drivers/asyncio/communication/serial_connection.py +24 -9
- opentrons/drivers/command_builder.py +2 -2
- opentrons/drivers/flex_stacker/__init__.py +9 -0
- opentrons/drivers/flex_stacker/abstract.py +89 -0
- opentrons/drivers/flex_stacker/driver.py +260 -0
- opentrons/drivers/flex_stacker/simulator.py +109 -0
- opentrons/drivers/flex_stacker/types.py +138 -0
- opentrons/drivers/heater_shaker/driver.py +18 -3
- opentrons/drivers/temp_deck/driver.py +13 -3
- opentrons/drivers/thermocycler/driver.py +17 -3
- opentrons/execute.py +3 -1
- opentrons/hardware_control/__init__.py +1 -2
- opentrons/hardware_control/api.py +28 -20
- opentrons/hardware_control/backends/flex_protocol.py +4 -6
- opentrons/hardware_control/backends/ot3controller.py +177 -59
- opentrons/hardware_control/backends/ot3simulator.py +10 -8
- opentrons/hardware_control/backends/ot3utils.py +3 -13
- opentrons/hardware_control/dev_types.py +2 -0
- opentrons/hardware_control/emulation/heater_shaker.py +4 -0
- opentrons/hardware_control/emulation/module_server/client.py +1 -1
- opentrons/hardware_control/emulation/module_server/server.py +5 -3
- opentrons/hardware_control/emulation/settings.py +3 -4
- opentrons/hardware_control/instruments/ot2/instrument_calibration.py +2 -1
- opentrons/hardware_control/instruments/ot2/pipette.py +9 -21
- opentrons/hardware_control/instruments/ot2/pipette_handler.py +8 -1
- opentrons/hardware_control/instruments/ot3/gripper.py +2 -2
- opentrons/hardware_control/instruments/ot3/pipette.py +13 -22
- opentrons/hardware_control/instruments/ot3/pipette_handler.py +10 -1
- opentrons/hardware_control/modules/mod_abc.py +2 -2
- opentrons/hardware_control/motion_utilities.py +68 -0
- opentrons/hardware_control/nozzle_manager.py +39 -41
- opentrons/hardware_control/ot3_calibration.py +1 -1
- opentrons/hardware_control/ot3api.py +34 -22
- opentrons/hardware_control/protocols/gripper_controller.py +3 -0
- opentrons/hardware_control/protocols/hardware_manager.py +5 -1
- opentrons/hardware_control/protocols/liquid_handler.py +18 -0
- opentrons/hardware_control/protocols/motion_controller.py +6 -0
- opentrons/hardware_control/robot_calibration.py +1 -1
- opentrons/hardware_control/types.py +61 -0
- opentrons/protocol_api/__init__.py +20 -1
- opentrons/protocol_api/_liquid.py +24 -49
- opentrons/protocol_api/_liquid_properties.py +754 -0
- opentrons/protocol_api/_types.py +24 -0
- opentrons/protocol_api/core/common.py +2 -0
- opentrons/protocol_api/core/engine/instrument.py +67 -10
- opentrons/protocol_api/core/engine/labware.py +29 -7
- opentrons/protocol_api/core/engine/protocol.py +130 -5
- opentrons/protocol_api/core/engine/robot.py +139 -0
- opentrons/protocol_api/core/engine/well.py +4 -1
- opentrons/protocol_api/core/instrument.py +42 -4
- opentrons/protocol_api/core/labware.py +13 -4
- opentrons/protocol_api/core/legacy/legacy_instrument_core.py +34 -3
- opentrons/protocol_api/core/legacy/legacy_labware_core.py +13 -4
- opentrons/protocol_api/core/legacy/legacy_protocol_core.py +32 -1
- opentrons/protocol_api/core/legacy/legacy_robot_core.py +0 -0
- opentrons/protocol_api/core/legacy_simulator/legacy_instrument_core.py +34 -3
- opentrons/protocol_api/core/protocol.py +34 -1
- opentrons/protocol_api/core/robot.py +51 -0
- opentrons/protocol_api/instrument_context.py +145 -43
- opentrons/protocol_api/labware.py +231 -7
- opentrons/protocol_api/module_contexts.py +21 -17
- opentrons/protocol_api/protocol_context.py +125 -4
- opentrons/protocol_api/robot_context.py +204 -32
- opentrons/protocol_api/validation.py +261 -3
- opentrons/protocol_engine/__init__.py +4 -0
- opentrons/protocol_engine/actions/actions.py +2 -3
- opentrons/protocol_engine/clients/sync_client.py +18 -0
- opentrons/protocol_engine/commands/__init__.py +81 -0
- opentrons/protocol_engine/commands/absorbance_reader/close_lid.py +0 -2
- opentrons/protocol_engine/commands/absorbance_reader/initialize.py +19 -5
- opentrons/protocol_engine/commands/absorbance_reader/open_lid.py +0 -1
- opentrons/protocol_engine/commands/absorbance_reader/read.py +32 -9
- opentrons/protocol_engine/commands/air_gap_in_place.py +160 -0
- opentrons/protocol_engine/commands/aspirate.py +103 -53
- opentrons/protocol_engine/commands/aspirate_in_place.py +55 -51
- opentrons/protocol_engine/commands/blow_out.py +44 -39
- opentrons/protocol_engine/commands/blow_out_in_place.py +21 -32
- opentrons/protocol_engine/commands/calibration/calibrate_gripper.py +13 -6
- opentrons/protocol_engine/commands/calibration/calibrate_module.py +1 -1
- opentrons/protocol_engine/commands/calibration/calibrate_pipette.py +3 -3
- opentrons/protocol_engine/commands/calibration/move_to_maintenance_position.py +1 -1
- opentrons/protocol_engine/commands/command.py +73 -66
- opentrons/protocol_engine/commands/command_unions.py +101 -1
- opentrons/protocol_engine/commands/comment.py +1 -1
- opentrons/protocol_engine/commands/configure_for_volume.py +10 -3
- opentrons/protocol_engine/commands/configure_nozzle_layout.py +6 -4
- opentrons/protocol_engine/commands/custom.py +6 -12
- opentrons/protocol_engine/commands/dispense.py +82 -48
- opentrons/protocol_engine/commands/dispense_in_place.py +71 -51
- opentrons/protocol_engine/commands/drop_tip.py +52 -31
- opentrons/protocol_engine/commands/drop_tip_in_place.py +13 -3
- opentrons/protocol_engine/commands/generate_command_schema.py +4 -11
- opentrons/protocol_engine/commands/get_next_tip.py +134 -0
- opentrons/protocol_engine/commands/get_tip_presence.py +1 -1
- opentrons/protocol_engine/commands/heater_shaker/close_labware_latch.py +1 -1
- opentrons/protocol_engine/commands/heater_shaker/deactivate_heater.py +1 -1
- opentrons/protocol_engine/commands/heater_shaker/deactivate_shaker.py +1 -1
- opentrons/protocol_engine/commands/heater_shaker/open_labware_latch.py +1 -1
- opentrons/protocol_engine/commands/heater_shaker/set_and_wait_for_shake_speed.py +1 -1
- opentrons/protocol_engine/commands/heater_shaker/set_target_temperature.py +1 -1
- opentrons/protocol_engine/commands/heater_shaker/wait_for_temperature.py +10 -4
- opentrons/protocol_engine/commands/home.py +13 -4
- opentrons/protocol_engine/commands/liquid_probe.py +60 -25
- opentrons/protocol_engine/commands/load_labware.py +29 -7
- opentrons/protocol_engine/commands/load_lid.py +146 -0
- opentrons/protocol_engine/commands/load_lid_stack.py +189 -0
- opentrons/protocol_engine/commands/load_liquid.py +12 -4
- opentrons/protocol_engine/commands/load_liquid_class.py +144 -0
- opentrons/protocol_engine/commands/load_module.py +31 -10
- opentrons/protocol_engine/commands/load_pipette.py +19 -8
- opentrons/protocol_engine/commands/magnetic_module/disengage.py +1 -1
- opentrons/protocol_engine/commands/magnetic_module/engage.py +1 -1
- opentrons/protocol_engine/commands/move_labware.py +19 -6
- opentrons/protocol_engine/commands/move_relative.py +35 -25
- opentrons/protocol_engine/commands/move_to_addressable_area.py +40 -27
- opentrons/protocol_engine/commands/move_to_addressable_area_for_drop_tip.py +53 -32
- opentrons/protocol_engine/commands/move_to_coordinates.py +36 -22
- opentrons/protocol_engine/commands/move_to_well.py +40 -24
- opentrons/protocol_engine/commands/movement_common.py +338 -0
- opentrons/protocol_engine/commands/pick_up_tip.py +49 -27
- opentrons/protocol_engine/commands/pipetting_common.py +169 -87
- opentrons/protocol_engine/commands/prepare_to_aspirate.py +24 -33
- opentrons/protocol_engine/commands/reload_labware.py +1 -1
- opentrons/protocol_engine/commands/retract_axis.py +1 -1
- opentrons/protocol_engine/commands/robot/__init__.py +69 -0
- opentrons/protocol_engine/commands/robot/close_gripper_jaw.py +86 -0
- opentrons/protocol_engine/commands/robot/common.py +18 -0
- opentrons/protocol_engine/commands/robot/move_axes_relative.py +101 -0
- opentrons/protocol_engine/commands/robot/move_axes_to.py +100 -0
- opentrons/protocol_engine/commands/robot/move_to.py +94 -0
- opentrons/protocol_engine/commands/robot/open_gripper_jaw.py +77 -0
- opentrons/protocol_engine/commands/save_position.py +14 -5
- opentrons/protocol_engine/commands/set_rail_lights.py +1 -1
- opentrons/protocol_engine/commands/set_status_bar.py +1 -1
- opentrons/protocol_engine/commands/temperature_module/deactivate.py +1 -1
- opentrons/protocol_engine/commands/temperature_module/set_target_temperature.py +1 -1
- opentrons/protocol_engine/commands/temperature_module/wait_for_temperature.py +10 -4
- opentrons/protocol_engine/commands/thermocycler/close_lid.py +1 -1
- opentrons/protocol_engine/commands/thermocycler/deactivate_block.py +1 -1
- opentrons/protocol_engine/commands/thermocycler/deactivate_lid.py +1 -1
- opentrons/protocol_engine/commands/thermocycler/open_lid.py +1 -1
- opentrons/protocol_engine/commands/thermocycler/run_extended_profile.py +8 -2
- opentrons/protocol_engine/commands/thermocycler/run_profile.py +9 -3
- opentrons/protocol_engine/commands/thermocycler/set_target_block_temperature.py +11 -4
- opentrons/protocol_engine/commands/thermocycler/set_target_lid_temperature.py +1 -1
- opentrons/protocol_engine/commands/thermocycler/wait_for_block_temperature.py +1 -1
- opentrons/protocol_engine/commands/thermocycler/wait_for_lid_temperature.py +1 -1
- opentrons/protocol_engine/commands/touch_tip.py +65 -16
- opentrons/protocol_engine/commands/unsafe/unsafe_blow_out_in_place.py +4 -1
- opentrons/protocol_engine/commands/unsafe/unsafe_drop_tip_in_place.py +12 -3
- opentrons/protocol_engine/commands/unsafe/unsafe_engage_axes.py +1 -4
- opentrons/protocol_engine/commands/unsafe/update_position_estimators.py +1 -4
- opentrons/protocol_engine/commands/verify_tip_presence.py +11 -4
- opentrons/protocol_engine/commands/wait_for_duration.py +10 -3
- opentrons/protocol_engine/commands/wait_for_resume.py +10 -3
- opentrons/protocol_engine/errors/__init__.py +8 -0
- opentrons/protocol_engine/errors/error_occurrence.py +19 -20
- opentrons/protocol_engine/errors/exceptions.py +50 -0
- opentrons/protocol_engine/execution/command_executor.py +1 -1
- opentrons/protocol_engine/execution/equipment.py +73 -5
- opentrons/protocol_engine/execution/gantry_mover.py +364 -8
- opentrons/protocol_engine/execution/movement.py +27 -0
- opentrons/protocol_engine/execution/pipetting.py +5 -1
- opentrons/protocol_engine/execution/tip_handler.py +4 -6
- opentrons/protocol_engine/notes/notes.py +1 -1
- opentrons/protocol_engine/protocol_engine.py +7 -6
- opentrons/protocol_engine/resources/labware_data_provider.py +1 -1
- opentrons/protocol_engine/resources/labware_validation.py +5 -0
- opentrons/protocol_engine/resources/module_data_provider.py +1 -1
- opentrons/protocol_engine/resources/pipette_data_provider.py +12 -0
- opentrons/protocol_engine/slot_standardization.py +9 -9
- opentrons/protocol_engine/state/_move_types.py +9 -5
- opentrons/protocol_engine/state/_well_math.py +193 -0
- opentrons/protocol_engine/state/addressable_areas.py +25 -61
- opentrons/protocol_engine/state/command_history.py +12 -0
- opentrons/protocol_engine/state/commands.py +17 -13
- opentrons/protocol_engine/state/files.py +10 -12
- opentrons/protocol_engine/state/fluid_stack.py +138 -0
- opentrons/protocol_engine/state/frustum_helpers.py +57 -32
- opentrons/protocol_engine/state/geometry.py +47 -1
- opentrons/protocol_engine/state/labware.py +79 -25
- opentrons/protocol_engine/state/liquid_classes.py +82 -0
- opentrons/protocol_engine/state/liquids.py +16 -4
- opentrons/protocol_engine/state/modules.py +52 -70
- opentrons/protocol_engine/state/motion.py +6 -1
- opentrons/protocol_engine/state/pipettes.py +135 -58
- opentrons/protocol_engine/state/state.py +21 -2
- opentrons/protocol_engine/state/state_summary.py +4 -2
- opentrons/protocol_engine/state/tips.py +11 -44
- opentrons/protocol_engine/state/update_types.py +343 -48
- opentrons/protocol_engine/state/wells.py +19 -11
- opentrons/protocol_engine/types.py +176 -28
- opentrons/protocol_reader/extract_labware_definitions.py +5 -2
- opentrons/protocol_reader/file_format_validator.py +5 -5
- opentrons/protocol_runner/json_file_reader.py +9 -3
- opentrons/protocol_runner/json_translator.py +51 -25
- opentrons/protocol_runner/legacy_command_mapper.py +66 -64
- opentrons/protocol_runner/protocol_runner.py +35 -4
- opentrons/protocol_runner/python_protocol_wrappers.py +1 -1
- opentrons/protocol_runner/run_orchestrator.py +13 -3
- opentrons/protocols/advanced_control/common.py +38 -0
- opentrons/protocols/advanced_control/mix.py +1 -1
- opentrons/protocols/advanced_control/transfers/__init__.py +0 -0
- opentrons/protocols/advanced_control/transfers/common.py +56 -0
- opentrons/protocols/advanced_control/{transfers.py → transfers/transfer.py} +10 -85
- opentrons/protocols/api_support/definitions.py +1 -1
- opentrons/protocols/api_support/instrument.py +1 -1
- opentrons/protocols/api_support/util.py +10 -0
- opentrons/protocols/labware.py +70 -8
- opentrons/protocols/models/json_protocol.py +5 -9
- opentrons/simulate.py +3 -1
- opentrons/types.py +162 -2
- opentrons/util/entrypoint_util.py +2 -5
- opentrons/util/logging_config.py +1 -1
- {opentrons-8.3.0a0.dist-info → opentrons-8.3.0a2.dist-info}/METADATA +16 -15
- {opentrons-8.3.0a0.dist-info → opentrons-8.3.0a2.dist-info}/RECORD +229 -202
- {opentrons-8.3.0a0.dist-info → opentrons-8.3.0a2.dist-info}/WHEEL +1 -1
- {opentrons-8.3.0a0.dist-info → opentrons-8.3.0a2.dist-info}/LICENSE +0 -0
- {opentrons-8.3.0a0.dist-info → opentrons-8.3.0a2.dist-info}/entry_points.txt +0 -0
- {opentrons-8.3.0a0.dist-info → opentrons-8.3.0a2.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
"""Load lid stack command request, result, and implementation models."""
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
from pydantic import BaseModel, Field
|
|
4
|
+
from typing import TYPE_CHECKING, Optional, Type, List
|
|
5
|
+
from typing_extensions import Literal
|
|
6
|
+
|
|
7
|
+
from opentrons_shared_data.labware.labware_definition import LabwareDefinition
|
|
8
|
+
|
|
9
|
+
from ..errors import LabwareIsNotAllowedInLocationError, ProtocolEngineError
|
|
10
|
+
from ..resources import fixture_validation, labware_validation
|
|
11
|
+
from ..types import (
|
|
12
|
+
LabwareLocation,
|
|
13
|
+
OnLabwareLocation,
|
|
14
|
+
DeckSlotLocation,
|
|
15
|
+
AddressableAreaLocation,
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
from .command import AbstractCommandImpl, BaseCommand, BaseCommandCreate, SuccessData
|
|
19
|
+
from ..errors.error_occurrence import ErrorOccurrence
|
|
20
|
+
from ..state.update_types import StateUpdate
|
|
21
|
+
|
|
22
|
+
if TYPE_CHECKING:
|
|
23
|
+
from ..state.state import StateView
|
|
24
|
+
from ..execution import EquipmentHandler
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
LoadLidStackCommandType = Literal["loadLidStack"]
|
|
28
|
+
|
|
29
|
+
_LID_STACK_PE_LABWARE = "protocol_engine_lid_stack_object"
|
|
30
|
+
_LID_STACK_PE_NAMESPACE = "opentrons"
|
|
31
|
+
_LID_STACK_PE_VERSION = 1
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class LoadLidStackParams(BaseModel):
|
|
35
|
+
"""Payload required to load a lid stack onto a location."""
|
|
36
|
+
|
|
37
|
+
location: LabwareLocation = Field(
|
|
38
|
+
...,
|
|
39
|
+
description="Location the lid stack should be loaded into.",
|
|
40
|
+
)
|
|
41
|
+
loadName: str = Field(
|
|
42
|
+
...,
|
|
43
|
+
description="Name used to reference a lid labware definition.",
|
|
44
|
+
)
|
|
45
|
+
namespace: str = Field(
|
|
46
|
+
...,
|
|
47
|
+
description="The namespace the lid labware definition belongs to.",
|
|
48
|
+
)
|
|
49
|
+
version: int = Field(
|
|
50
|
+
...,
|
|
51
|
+
description="The lid labware definition version.",
|
|
52
|
+
)
|
|
53
|
+
quantity: int = Field(
|
|
54
|
+
...,
|
|
55
|
+
description="The quantity of lids to load.",
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
class LoadLidStackResult(BaseModel):
|
|
60
|
+
"""Result data from the execution of a LoadLidStack command."""
|
|
61
|
+
|
|
62
|
+
stackLabwareId: str = Field(
|
|
63
|
+
...,
|
|
64
|
+
description="An ID to reference the Protocol Engine Labware Lid Stack in subsequent commands.",
|
|
65
|
+
)
|
|
66
|
+
labwareIds: List[str] = Field(
|
|
67
|
+
...,
|
|
68
|
+
description="A list of lid labware IDs to reference the lids in this stack by. The first ID is the bottom of the stack.",
|
|
69
|
+
)
|
|
70
|
+
definition: LabwareDefinition = Field(
|
|
71
|
+
...,
|
|
72
|
+
description="The full definition data for this lid labware.",
|
|
73
|
+
)
|
|
74
|
+
location: LabwareLocation = Field(
|
|
75
|
+
..., description="The Location that the stack of lid labware has been loaded."
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
class LoadLidStackImplementation(
|
|
80
|
+
AbstractCommandImpl[LoadLidStackParams, SuccessData[LoadLidStackResult]]
|
|
81
|
+
):
|
|
82
|
+
"""Load lid stack command implementation."""
|
|
83
|
+
|
|
84
|
+
def __init__(
|
|
85
|
+
self, equipment: EquipmentHandler, state_view: StateView, **kwargs: object
|
|
86
|
+
) -> None:
|
|
87
|
+
self._equipment = equipment
|
|
88
|
+
self._state_view = state_view
|
|
89
|
+
|
|
90
|
+
async def execute(
|
|
91
|
+
self, params: LoadLidStackParams
|
|
92
|
+
) -> SuccessData[LoadLidStackResult]:
|
|
93
|
+
"""Load definition and calibration data necessary for a lid stack."""
|
|
94
|
+
if isinstance(params.location, AddressableAreaLocation):
|
|
95
|
+
area_name = params.location.addressableAreaName
|
|
96
|
+
if not (
|
|
97
|
+
fixture_validation.is_deck_slot(params.location.addressableAreaName)
|
|
98
|
+
or fixture_validation.is_abs_reader(params.location.addressableAreaName)
|
|
99
|
+
):
|
|
100
|
+
raise LabwareIsNotAllowedInLocationError(
|
|
101
|
+
f"Cannot load {params.loadName} onto addressable area {area_name}"
|
|
102
|
+
)
|
|
103
|
+
self._state_view.addressable_areas.raise_if_area_not_in_deck_configuration(
|
|
104
|
+
area_name
|
|
105
|
+
)
|
|
106
|
+
elif isinstance(params.location, DeckSlotLocation):
|
|
107
|
+
self._state_view.addressable_areas.raise_if_area_not_in_deck_configuration(
|
|
108
|
+
params.location.slotName.id
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
verified_location = self._state_view.geometry.ensure_location_not_occupied(
|
|
112
|
+
params.location
|
|
113
|
+
)
|
|
114
|
+
|
|
115
|
+
lid_stack_object = await self._equipment.load_labware(
|
|
116
|
+
load_name=_LID_STACK_PE_LABWARE,
|
|
117
|
+
namespace=_LID_STACK_PE_NAMESPACE,
|
|
118
|
+
version=_LID_STACK_PE_VERSION,
|
|
119
|
+
location=verified_location,
|
|
120
|
+
labware_id=None,
|
|
121
|
+
)
|
|
122
|
+
if not labware_validation.validate_definition_is_system(
|
|
123
|
+
lid_stack_object.definition
|
|
124
|
+
):
|
|
125
|
+
raise ProtocolEngineError(
|
|
126
|
+
message="Lid Stack Labware Object Labware Definition does not contain required allowed role 'system'."
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
loaded_lid_labwares = await self._equipment.load_lids(
|
|
130
|
+
load_name=params.loadName,
|
|
131
|
+
namespace=params.namespace,
|
|
132
|
+
version=params.version,
|
|
133
|
+
location=OnLabwareLocation(labwareId=lid_stack_object.labware_id),
|
|
134
|
+
quantity=params.quantity,
|
|
135
|
+
)
|
|
136
|
+
loaded_lid_locations_by_id = {}
|
|
137
|
+
load_location = OnLabwareLocation(labwareId=lid_stack_object.labware_id)
|
|
138
|
+
for loaded_lid in loaded_lid_labwares:
|
|
139
|
+
loaded_lid_locations_by_id[loaded_lid.labware_id] = load_location
|
|
140
|
+
load_location = OnLabwareLocation(labwareId=loaded_lid.labware_id)
|
|
141
|
+
|
|
142
|
+
state_update = StateUpdate()
|
|
143
|
+
state_update.set_loaded_lid_stack(
|
|
144
|
+
stack_id=lid_stack_object.labware_id,
|
|
145
|
+
stack_object_definition=lid_stack_object.definition,
|
|
146
|
+
stack_location=verified_location,
|
|
147
|
+
labware_ids=list(loaded_lid_locations_by_id.keys()),
|
|
148
|
+
labware_definition=loaded_lid_labwares[0].definition,
|
|
149
|
+
locations=loaded_lid_locations_by_id,
|
|
150
|
+
)
|
|
151
|
+
|
|
152
|
+
if isinstance(verified_location, OnLabwareLocation):
|
|
153
|
+
self._state_view.labware.raise_if_labware_cannot_be_stacked(
|
|
154
|
+
top_labware_definition=loaded_lid_labwares[
|
|
155
|
+
params.quantity - 1
|
|
156
|
+
].definition,
|
|
157
|
+
bottom_labware_id=verified_location.labwareId,
|
|
158
|
+
)
|
|
159
|
+
|
|
160
|
+
return SuccessData(
|
|
161
|
+
public=LoadLidStackResult(
|
|
162
|
+
stackLabwareId=lid_stack_object.labware_id,
|
|
163
|
+
labwareIds=list(loaded_lid_locations_by_id.keys()),
|
|
164
|
+
definition=loaded_lid_labwares[0].definition,
|
|
165
|
+
location=params.location,
|
|
166
|
+
),
|
|
167
|
+
state_update=state_update,
|
|
168
|
+
)
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
class LoadLidStack(
|
|
172
|
+
BaseCommand[LoadLidStackParams, LoadLidStackResult, ErrorOccurrence]
|
|
173
|
+
):
|
|
174
|
+
"""Load lid stack command resource model."""
|
|
175
|
+
|
|
176
|
+
commandType: LoadLidStackCommandType = "loadLidStack"
|
|
177
|
+
params: LoadLidStackParams
|
|
178
|
+
result: Optional[LoadLidStackResult]
|
|
179
|
+
|
|
180
|
+
_ImplementationCls: Type[LoadLidStackImplementation] = LoadLidStackImplementation
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
class LoadLidStackCreate(BaseCommandCreate[LoadLidStackParams]):
|
|
184
|
+
"""Load lid stack command creation request."""
|
|
185
|
+
|
|
186
|
+
commandType: LoadLidStackCommandType = "loadLidStack"
|
|
187
|
+
params: LoadLidStackParams
|
|
188
|
+
|
|
189
|
+
_CommandCls: Type[LoadLidStack] = LoadLidStack
|
|
@@ -5,6 +5,8 @@ from typing import Optional, Type, Dict, TYPE_CHECKING
|
|
|
5
5
|
from typing_extensions import Literal
|
|
6
6
|
|
|
7
7
|
from opentrons.protocol_engine.state.update_types import StateUpdate
|
|
8
|
+
from opentrons.protocol_engine.types import LiquidId
|
|
9
|
+
from opentrons.protocol_engine.errors import InvalidLiquidError
|
|
8
10
|
|
|
9
11
|
from .command import AbstractCommandImpl, BaseCommand, BaseCommandCreate, SuccessData
|
|
10
12
|
from ..errors.error_occurrence import ErrorOccurrence
|
|
@@ -19,9 +21,9 @@ LoadLiquidCommandType = Literal["loadLiquid"]
|
|
|
19
21
|
class LoadLiquidParams(BaseModel):
|
|
20
22
|
"""Payload required to load a liquid into a well."""
|
|
21
23
|
|
|
22
|
-
liquidId:
|
|
24
|
+
liquidId: LiquidId = Field(
|
|
23
25
|
...,
|
|
24
|
-
description="Unique identifier of the liquid to load.",
|
|
26
|
+
description="Unique identifier of the liquid to load. If this is the sentinel value EMPTY, all values of volumeByWell must be 0.",
|
|
25
27
|
)
|
|
26
28
|
labwareId: str = Field(
|
|
27
29
|
...,
|
|
@@ -29,7 +31,7 @@ class LoadLiquidParams(BaseModel):
|
|
|
29
31
|
)
|
|
30
32
|
volumeByWell: Dict[str, float] = Field(
|
|
31
33
|
...,
|
|
32
|
-
description="Volume of liquid, in µL, loaded into each well by name, in this labware.",
|
|
34
|
+
description="Volume of liquid, in µL, loaded into each well by name, in this labware. If the liquid id is the sentinel value EMPTY, all volumes must be 0.",
|
|
33
35
|
)
|
|
34
36
|
|
|
35
37
|
|
|
@@ -57,6 +59,12 @@ class LoadLiquidImplementation(
|
|
|
57
59
|
self._state_view.labware.validate_liquid_allowed_in_labware(
|
|
58
60
|
labware_id=params.labwareId, wells=params.volumeByWell
|
|
59
61
|
)
|
|
62
|
+
if params.liquidId == "EMPTY":
|
|
63
|
+
for well_name, volume in params.volumeByWell.items():
|
|
64
|
+
if volume != 0.0:
|
|
65
|
+
raise InvalidLiquidError(
|
|
66
|
+
'loadLiquid commands that specify the special liquid "EMPTY" must set volume to be 0.0, but the volume for {well_name} is {volume}'
|
|
67
|
+
)
|
|
60
68
|
|
|
61
69
|
state_update = StateUpdate()
|
|
62
70
|
state_update.set_liquid_loaded(
|
|
@@ -73,7 +81,7 @@ class LoadLiquid(BaseCommand[LoadLiquidParams, LoadLiquidResult, ErrorOccurrence
|
|
|
73
81
|
|
|
74
82
|
commandType: LoadLiquidCommandType = "loadLiquid"
|
|
75
83
|
params: LoadLiquidParams
|
|
76
|
-
result: Optional[LoadLiquidResult]
|
|
84
|
+
result: Optional[LoadLiquidResult] = None
|
|
77
85
|
|
|
78
86
|
_ImplementationCls: Type[LoadLiquidImplementation] = LoadLiquidImplementation
|
|
79
87
|
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
"""LoadLiquidClass stores the liquid class settings used for a transfer into the Protocol Engine."""
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
from typing import Optional, Type, TYPE_CHECKING, Any
|
|
5
|
+
|
|
6
|
+
from typing_extensions import Literal
|
|
7
|
+
from pydantic import BaseModel, Field
|
|
8
|
+
from pydantic.json_schema import SkipJsonSchema
|
|
9
|
+
|
|
10
|
+
from .command import AbstractCommandImpl, BaseCommand, BaseCommandCreate, SuccessData
|
|
11
|
+
from ..errors import LiquidClassDoesNotExistError
|
|
12
|
+
from ..errors.error_occurrence import ErrorOccurrence
|
|
13
|
+
from ..errors.exceptions import LiquidClassRedefinitionError
|
|
14
|
+
from ..state.update_types import LiquidClassLoadedUpdate, StateUpdate
|
|
15
|
+
from ..types import LiquidClassRecord
|
|
16
|
+
|
|
17
|
+
if TYPE_CHECKING:
|
|
18
|
+
from ..state.state import StateView
|
|
19
|
+
from ..resources import ModelUtils
|
|
20
|
+
|
|
21
|
+
LoadLiquidClassCommandType = Literal["loadLiquidClass"]
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def _remove_default(s: dict[str, Any]) -> None:
|
|
25
|
+
s.pop("default", None)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class LoadLiquidClassParams(BaseModel):
|
|
29
|
+
"""The liquid class transfer properties to store."""
|
|
30
|
+
|
|
31
|
+
liquidClassId: str | SkipJsonSchema[None] = Field(
|
|
32
|
+
None,
|
|
33
|
+
description="Unique identifier for the liquid class to store. "
|
|
34
|
+
"If you do not supply a liquidClassId, we will generate one.",
|
|
35
|
+
json_schema_extra=_remove_default,
|
|
36
|
+
)
|
|
37
|
+
liquidClassRecord: LiquidClassRecord = Field(
|
|
38
|
+
...,
|
|
39
|
+
description="The liquid class to store.",
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
class LoadLiquidClassResult(BaseModel):
|
|
44
|
+
"""Result from execution of LoadLiquidClass command."""
|
|
45
|
+
|
|
46
|
+
liquidClassId: str = Field(
|
|
47
|
+
...,
|
|
48
|
+
description="The ID for the liquid class that was loaded, either the one you "
|
|
49
|
+
"supplied or the one we generated.",
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
class LoadLiquidClassImplementation(
|
|
54
|
+
AbstractCommandImpl[LoadLiquidClassParams, SuccessData[LoadLiquidClassResult]]
|
|
55
|
+
):
|
|
56
|
+
"""Load Liquid Class command implementation."""
|
|
57
|
+
|
|
58
|
+
def __init__(
|
|
59
|
+
self, state_view: StateView, model_utils: ModelUtils, **kwargs: object
|
|
60
|
+
) -> None:
|
|
61
|
+
self._state_view = state_view
|
|
62
|
+
self._model_utils = model_utils
|
|
63
|
+
|
|
64
|
+
async def execute(
|
|
65
|
+
self, params: LoadLiquidClassParams
|
|
66
|
+
) -> SuccessData[LoadLiquidClassResult]:
|
|
67
|
+
"""Store the liquid class in the Protocol Engine."""
|
|
68
|
+
liquid_class_id: Optional[str]
|
|
69
|
+
already_loaded = False
|
|
70
|
+
|
|
71
|
+
if params.liquidClassId:
|
|
72
|
+
liquid_class_id = params.liquidClassId
|
|
73
|
+
if self._liquid_class_id_already_loaded(
|
|
74
|
+
liquid_class_id, params.liquidClassRecord
|
|
75
|
+
):
|
|
76
|
+
already_loaded = True
|
|
77
|
+
else:
|
|
78
|
+
liquid_class_id = (
|
|
79
|
+
self._state_view.liquid_classes.get_id_for_liquid_class_record(
|
|
80
|
+
params.liquidClassRecord
|
|
81
|
+
) # if liquidClassRecord was already loaded, reuse the existing ID
|
|
82
|
+
)
|
|
83
|
+
if liquid_class_id:
|
|
84
|
+
already_loaded = True
|
|
85
|
+
else:
|
|
86
|
+
liquid_class_id = self._model_utils.generate_id()
|
|
87
|
+
|
|
88
|
+
if already_loaded:
|
|
89
|
+
state_update = StateUpdate() # liquid class already loaded, do nothing
|
|
90
|
+
else:
|
|
91
|
+
state_update = StateUpdate(
|
|
92
|
+
liquid_class_loaded=LiquidClassLoadedUpdate(
|
|
93
|
+
liquid_class_id=liquid_class_id,
|
|
94
|
+
liquid_class_record=params.liquidClassRecord,
|
|
95
|
+
)
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
return SuccessData(
|
|
99
|
+
public=LoadLiquidClassResult(liquidClassId=liquid_class_id),
|
|
100
|
+
state_update=state_update,
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
def _liquid_class_id_already_loaded(
|
|
104
|
+
self, liquid_class_id: str, liquid_class_record: LiquidClassRecord
|
|
105
|
+
) -> bool:
|
|
106
|
+
"""Check if the liquid_class_id has already been loaded.
|
|
107
|
+
|
|
108
|
+
If it has, make sure that liquid_class_record matches the previously loaded definition.
|
|
109
|
+
"""
|
|
110
|
+
try:
|
|
111
|
+
existing_liquid_class_record = self._state_view.liquid_classes.get(
|
|
112
|
+
liquid_class_id
|
|
113
|
+
)
|
|
114
|
+
except LiquidClassDoesNotExistError:
|
|
115
|
+
return False
|
|
116
|
+
|
|
117
|
+
if liquid_class_record != existing_liquid_class_record:
|
|
118
|
+
raise LiquidClassRedefinitionError(
|
|
119
|
+
f"Liquid class {liquid_class_id} conflicts with previously loaded definition."
|
|
120
|
+
)
|
|
121
|
+
return True
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
class LoadLiquidClass(
|
|
125
|
+
BaseCommand[LoadLiquidClassParams, LoadLiquidClassResult, ErrorOccurrence]
|
|
126
|
+
):
|
|
127
|
+
"""Load Liquid Class command resource model."""
|
|
128
|
+
|
|
129
|
+
commandType: LoadLiquidClassCommandType = "loadLiquidClass"
|
|
130
|
+
params: LoadLiquidClassParams
|
|
131
|
+
result: Optional[LoadLiquidClassResult]
|
|
132
|
+
|
|
133
|
+
_ImplementationCls: Type[
|
|
134
|
+
LoadLiquidClassImplementation
|
|
135
|
+
] = LoadLiquidClassImplementation
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
class LoadLiquidClassCreate(BaseCommandCreate[LoadLiquidClassParams]):
|
|
139
|
+
"""Load Liquid Class command creation request."""
|
|
140
|
+
|
|
141
|
+
commandType: LoadLiquidClassCommandType = "loadLiquidClass"
|
|
142
|
+
params: LoadLiquidClassParams
|
|
143
|
+
|
|
144
|
+
_CommandCls: Type[LoadLiquidClass] = LoadLiquidClass
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
"""Implementation, request models, and response models for the load module command."""
|
|
2
2
|
from __future__ import annotations
|
|
3
|
-
from typing import TYPE_CHECKING, Optional, Type
|
|
3
|
+
from typing import TYPE_CHECKING, Optional, Type, Any
|
|
4
4
|
from typing_extensions import Literal
|
|
5
5
|
from pydantic import BaseModel, Field
|
|
6
|
+
from pydantic.json_schema import SkipJsonSchema
|
|
7
|
+
|
|
8
|
+
from opentrons.protocol_engine.state.update_types import StateUpdate
|
|
6
9
|
|
|
7
10
|
from .command import AbstractCommandImpl, BaseCommand, BaseCommandCreate, SuccessData
|
|
8
11
|
from ..errors.error_occurrence import ErrorOccurrence
|
|
@@ -25,6 +28,10 @@ if TYPE_CHECKING:
|
|
|
25
28
|
LoadModuleCommandType = Literal["loadModule"]
|
|
26
29
|
|
|
27
30
|
|
|
31
|
+
def _remove_default(s: dict[str, Any]) -> None:
|
|
32
|
+
s.pop("default", None)
|
|
33
|
+
|
|
34
|
+
|
|
28
35
|
class LoadModuleParams(BaseModel):
|
|
29
36
|
"""Payload required to load a module."""
|
|
30
37
|
|
|
@@ -57,12 +64,13 @@ class LoadModuleParams(BaseModel):
|
|
|
57
64
|
),
|
|
58
65
|
)
|
|
59
66
|
|
|
60
|
-
moduleId:
|
|
67
|
+
moduleId: str | SkipJsonSchema[None] = Field(
|
|
61
68
|
None,
|
|
62
69
|
description=(
|
|
63
70
|
"An optional ID to assign to this module."
|
|
64
71
|
" If None, an ID will be generated."
|
|
65
72
|
),
|
|
73
|
+
json_schema_extra=_remove_default,
|
|
66
74
|
)
|
|
67
75
|
|
|
68
76
|
|
|
@@ -75,7 +83,7 @@ class LoadModuleResult(BaseModel):
|
|
|
75
83
|
|
|
76
84
|
# TODO(mm, 2023-04-13): Remove this field. Jira RSS-221.
|
|
77
85
|
definition: ModuleDefinition = Field(
|
|
78
|
-
deprecated
|
|
86
|
+
json_schema_extra={"deprecated": True},
|
|
79
87
|
description=(
|
|
80
88
|
"The definition of the connected module."
|
|
81
89
|
" This field is an implementation detail. We might change or remove it without warning."
|
|
@@ -116,26 +124,35 @@ class LoadModuleImplementation(
|
|
|
116
124
|
|
|
117
125
|
async def execute(self, params: LoadModuleParams) -> SuccessData[LoadModuleResult]:
|
|
118
126
|
"""Check that the requested module is attached and assign its identifier."""
|
|
127
|
+
state_update = StateUpdate()
|
|
128
|
+
|
|
119
129
|
module_type = params.model.as_type()
|
|
120
130
|
self._ensure_module_location(params.location.slotName, module_type)
|
|
121
131
|
|
|
132
|
+
# todo(mm, 2024-12-03): Theoretically, we should be able to deal with
|
|
133
|
+
# addressable areas and deck configurations the same way between OT-2 and Flex.
|
|
134
|
+
# Can this be simplified?
|
|
122
135
|
if self._state_view.config.robot_type == "OT-2 Standard":
|
|
123
136
|
self._state_view.addressable_areas.raise_if_area_not_in_deck_configuration(
|
|
124
137
|
params.location.slotName.id
|
|
125
138
|
)
|
|
126
139
|
else:
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
140
|
+
addressable_area_provided_by_module = (
|
|
141
|
+
self._state_view.modules.ensure_and_convert_module_fixture_location(
|
|
142
|
+
deck_slot=params.location.slotName,
|
|
143
|
+
model=params.model,
|
|
144
|
+
)
|
|
131
145
|
)
|
|
132
146
|
self._state_view.addressable_areas.raise_if_area_not_in_deck_configuration(
|
|
133
|
-
|
|
147
|
+
addressable_area_provided_by_module
|
|
134
148
|
)
|
|
135
149
|
|
|
136
150
|
verified_location = self._state_view.geometry.ensure_location_not_occupied(
|
|
137
151
|
params.location
|
|
138
152
|
)
|
|
153
|
+
state_update.set_addressable_area_used(
|
|
154
|
+
addressable_area_name=params.location.slotName.id
|
|
155
|
+
)
|
|
139
156
|
|
|
140
157
|
if params.model == ModuleModel.MAGNETIC_BLOCK_V1:
|
|
141
158
|
loaded_module = await self._equipment.load_magnetic_block(
|
|
@@ -157,11 +174,15 @@ class LoadModuleImplementation(
|
|
|
157
174
|
model=loaded_module.definition.model,
|
|
158
175
|
definition=loaded_module.definition,
|
|
159
176
|
),
|
|
177
|
+
state_update=state_update,
|
|
160
178
|
)
|
|
161
179
|
|
|
162
180
|
def _ensure_module_location(
|
|
163
181
|
self, slot: DeckSlotName, module_type: ModuleType
|
|
164
182
|
) -> None:
|
|
183
|
+
# todo(mm, 2024-12-03): Theoretically, we should be able to deal with
|
|
184
|
+
# addressable areas and deck configurations the same way between OT-2 and Flex.
|
|
185
|
+
# Can this be simplified?
|
|
165
186
|
if self._state_view.config.robot_type == "OT-2 Standard":
|
|
166
187
|
slot_def = self._state_view.addressable_areas.get_slot_definition(slot.id)
|
|
167
188
|
compatible_modules = slot_def["compatibleModuleTypes"]
|
|
@@ -173,7 +194,7 @@ class LoadModuleImplementation(
|
|
|
173
194
|
cutout_fixture_id = ModuleType.to_module_fixture_id(module_type)
|
|
174
195
|
module_fixture = deck_configuration_provider.get_cutout_fixture(
|
|
175
196
|
cutout_fixture_id,
|
|
176
|
-
self._state_view.
|
|
197
|
+
self._state_view.labware.get_deck_definition(),
|
|
177
198
|
)
|
|
178
199
|
cutout_id = (
|
|
179
200
|
self._state_view.addressable_areas.get_cutout_id_by_deck_slot_name(slot)
|
|
@@ -189,7 +210,7 @@ class LoadModule(BaseCommand[LoadModuleParams, LoadModuleResult, ErrorOccurrence
|
|
|
189
210
|
|
|
190
211
|
commandType: LoadModuleCommandType = "loadModule"
|
|
191
212
|
params: LoadModuleParams
|
|
192
|
-
result: Optional[LoadModuleResult]
|
|
213
|
+
result: Optional[LoadModuleResult] = None
|
|
193
214
|
|
|
194
215
|
_ImplementationCls: Type[LoadModuleImplementation] = LoadModuleImplementation
|
|
195
216
|
|
|
@@ -1,20 +1,23 @@
|
|
|
1
1
|
"""Load pipette command request, result, and implementation models."""
|
|
2
2
|
from __future__ import annotations
|
|
3
|
+
from typing import TYPE_CHECKING, Optional, Type, Any
|
|
4
|
+
|
|
5
|
+
from pydantic import BaseModel, Field
|
|
6
|
+
from pydantic.json_schema import SkipJsonSchema
|
|
7
|
+
from typing_extensions import Literal
|
|
3
8
|
|
|
4
|
-
from opentrons.protocol_engine.state.update_types import StateUpdate
|
|
5
9
|
from opentrons_shared_data.pipette.pipette_load_name_conversions import (
|
|
6
10
|
convert_to_pipette_name_type,
|
|
7
11
|
)
|
|
8
12
|
from opentrons_shared_data.pipette.types import PipetteGenerationType
|
|
9
13
|
from opentrons_shared_data.robot import user_facing_robot_type
|
|
10
14
|
from opentrons_shared_data.robot.types import RobotTypeEnum
|
|
11
|
-
|
|
12
|
-
from typing import TYPE_CHECKING, Optional, Type
|
|
13
|
-
from typing_extensions import Literal
|
|
15
|
+
|
|
14
16
|
|
|
15
17
|
from opentrons_shared_data.pipette.types import PipetteNameType
|
|
16
18
|
from opentrons.types import MountType
|
|
17
19
|
|
|
20
|
+
from opentrons.protocol_engine.state.update_types import StateUpdate
|
|
18
21
|
from .command import AbstractCommandImpl, BaseCommand, BaseCommandCreate, SuccessData
|
|
19
22
|
from ..errors.error_occurrence import ErrorOccurrence
|
|
20
23
|
from ..errors import InvalidSpecificationForRobotTypeError, InvalidLoadPipetteSpecsError
|
|
@@ -27,6 +30,10 @@ if TYPE_CHECKING:
|
|
|
27
30
|
LoadPipetteCommandType = Literal["loadPipette"]
|
|
28
31
|
|
|
29
32
|
|
|
33
|
+
def _remove_default(s: dict[str, Any]) -> None:
|
|
34
|
+
s.pop("default", None)
|
|
35
|
+
|
|
36
|
+
|
|
30
37
|
class LoadPipetteParams(BaseModel):
|
|
31
38
|
"""Payload needed to load a pipette on to a mount."""
|
|
32
39
|
|
|
@@ -38,21 +45,24 @@ class LoadPipetteParams(BaseModel):
|
|
|
38
45
|
...,
|
|
39
46
|
description="The mount the pipette should be present on.",
|
|
40
47
|
)
|
|
41
|
-
pipetteId:
|
|
48
|
+
pipetteId: str | SkipJsonSchema[None] = Field(
|
|
42
49
|
None,
|
|
43
50
|
description="An optional ID to assign to this pipette. If None, an ID "
|
|
44
51
|
"will be generated.",
|
|
52
|
+
json_schema_extra=_remove_default,
|
|
45
53
|
)
|
|
46
|
-
tipOverlapNotAfterVersion:
|
|
54
|
+
tipOverlapNotAfterVersion: str | SkipJsonSchema[None] = Field(
|
|
47
55
|
None,
|
|
48
56
|
description="A version of tip overlap data to not exceed. The highest-versioned "
|
|
49
57
|
"tip overlap data that does not exceed this version will be used. Versions are "
|
|
50
58
|
"expressed as vN where N is an integer, counting up from v0. If None, the current "
|
|
51
59
|
"highest version will be used.",
|
|
60
|
+
json_schema_extra=_remove_default,
|
|
52
61
|
)
|
|
53
|
-
liquidPresenceDetection:
|
|
62
|
+
liquidPresenceDetection: bool | SkipJsonSchema[None] = Field(
|
|
54
63
|
None,
|
|
55
64
|
description="Enable liquid presence detection for this pipette. Defaults to False.",
|
|
65
|
+
json_schema_extra=_remove_default,
|
|
56
66
|
)
|
|
57
67
|
|
|
58
68
|
|
|
@@ -127,6 +137,7 @@ class LoadPipetteImplementation(
|
|
|
127
137
|
serial_number=loaded_pipette.serial_number,
|
|
128
138
|
config=loaded_pipette.static_config,
|
|
129
139
|
)
|
|
140
|
+
state_update.set_fluid_unknown(pipette_id=loaded_pipette.pipette_id)
|
|
130
141
|
|
|
131
142
|
return SuccessData(
|
|
132
143
|
public=LoadPipetteResult(pipetteId=loaded_pipette.pipette_id),
|
|
@@ -139,7 +150,7 @@ class LoadPipette(BaseCommand[LoadPipetteParams, LoadPipetteResult, ErrorOccurre
|
|
|
139
150
|
|
|
140
151
|
commandType: LoadPipetteCommandType = "loadPipette"
|
|
141
152
|
params: LoadPipetteParams
|
|
142
|
-
result: Optional[LoadPipetteResult]
|
|
153
|
+
result: Optional[LoadPipetteResult] = None
|
|
143
154
|
|
|
144
155
|
_ImplementationCls: Type[LoadPipetteImplementation] = LoadPipetteImplementation
|
|
145
156
|
|
|
@@ -83,7 +83,7 @@ class Disengage(BaseCommand[DisengageParams, DisengageResult, ErrorOccurrence]):
|
|
|
83
83
|
|
|
84
84
|
commandType: DisengageCommandType = "magneticModule/disengage"
|
|
85
85
|
params: DisengageParams
|
|
86
|
-
result: Optional[DisengageResult]
|
|
86
|
+
result: Optional[DisengageResult] = None
|
|
87
87
|
|
|
88
88
|
_ImplementationCls: Type[DisengageImplementation] = DisengageImplementation
|
|
89
89
|
|
|
@@ -105,7 +105,7 @@ class Engage(BaseCommand[EngageParams, EngageResult, ErrorOccurrence]):
|
|
|
105
105
|
|
|
106
106
|
commandType: EngageCommandType = "magneticModule/engage"
|
|
107
107
|
params: EngageParams
|
|
108
|
-
result: Optional[EngageResult]
|
|
108
|
+
result: Optional[EngageResult] = None
|
|
109
109
|
|
|
110
110
|
_ImplementationCls: Type[EngageImplementation] = EngageImplementation
|
|
111
111
|
|
|
@@ -1,14 +1,17 @@
|
|
|
1
1
|
"""Models and implementation for the ``moveLabware`` command."""
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
|
+
from typing import TYPE_CHECKING, Optional, Type, Any
|
|
5
|
+
|
|
6
|
+
from pydantic.json_schema import SkipJsonSchema
|
|
7
|
+
from pydantic import BaseModel, Field
|
|
8
|
+
from typing_extensions import Literal
|
|
9
|
+
|
|
4
10
|
from opentrons_shared_data.errors.exceptions import (
|
|
5
11
|
FailedGripperPickupError,
|
|
6
12
|
LabwareDroppedError,
|
|
7
13
|
StallOrCollisionDetectedError,
|
|
8
14
|
)
|
|
9
|
-
from pydantic import BaseModel, Field
|
|
10
|
-
from typing import TYPE_CHECKING, Optional, Type
|
|
11
|
-
from typing_extensions import Literal
|
|
12
15
|
|
|
13
16
|
from opentrons.protocol_engine.resources.model_utils import ModelUtils
|
|
14
17
|
from opentrons.types import Point
|
|
@@ -49,6 +52,10 @@ if TYPE_CHECKING:
|
|
|
49
52
|
MoveLabwareCommandType = Literal["moveLabware"]
|
|
50
53
|
|
|
51
54
|
|
|
55
|
+
def _remove_default(s: dict[str, Any]) -> None:
|
|
56
|
+
s.pop("default", None)
|
|
57
|
+
|
|
58
|
+
|
|
52
59
|
# Extra buffer on top of minimum distance to move to the right
|
|
53
60
|
_TRASH_CHUTE_DROP_BUFFER_MM = 8
|
|
54
61
|
|
|
@@ -63,15 +70,17 @@ class MoveLabwareParams(BaseModel):
|
|
|
63
70
|
description="Whether to use the gripper to perform the labware movement"
|
|
64
71
|
" or to perform a manual movement with an option to pause.",
|
|
65
72
|
)
|
|
66
|
-
pickUpOffset:
|
|
73
|
+
pickUpOffset: LabwareOffsetVector | SkipJsonSchema[None] = Field(
|
|
67
74
|
None,
|
|
68
75
|
description="Offset to use when picking up labware. "
|
|
69
76
|
"Experimental param, subject to change",
|
|
77
|
+
json_schema_extra=_remove_default,
|
|
70
78
|
)
|
|
71
|
-
dropOffset:
|
|
79
|
+
dropOffset: LabwareOffsetVector | SkipJsonSchema[None] = Field(
|
|
72
80
|
None,
|
|
73
81
|
description="Offset to use when dropping off labware. "
|
|
74
82
|
"Experimental param, subject to change",
|
|
83
|
+
json_schema_extra=_remove_default,
|
|
75
84
|
)
|
|
76
85
|
|
|
77
86
|
|
|
@@ -156,6 +165,7 @@ class MoveLabwareImplementation(AbstractCommandImpl[MoveLabwareParams, _ExecuteR
|
|
|
156
165
|
self._state_view.addressable_areas.raise_if_area_not_in_deck_configuration(
|
|
157
166
|
area_name
|
|
158
167
|
)
|
|
168
|
+
state_update.set_addressable_area_used(addressable_area_name=area_name)
|
|
159
169
|
|
|
160
170
|
if fixture_validation.is_gripper_waste_chute(area_name):
|
|
161
171
|
# When dropping off labware in the waste chute, some bigger pieces
|
|
@@ -201,6 +211,9 @@ class MoveLabwareImplementation(AbstractCommandImpl[MoveLabwareParams, _ExecuteR
|
|
|
201
211
|
self._state_view.addressable_areas.raise_if_area_not_in_deck_configuration(
|
|
202
212
|
params.newLocation.slotName.id
|
|
203
213
|
)
|
|
214
|
+
state_update.set_addressable_area_used(
|
|
215
|
+
addressable_area_name=params.newLocation.slotName.id
|
|
216
|
+
)
|
|
204
217
|
|
|
205
218
|
available_new_location = self._state_view.geometry.ensure_location_not_occupied(
|
|
206
219
|
location=params.newLocation
|
|
@@ -355,7 +368,7 @@ class MoveLabware(
|
|
|
355
368
|
|
|
356
369
|
commandType: MoveLabwareCommandType = "moveLabware"
|
|
357
370
|
params: MoveLabwareParams
|
|
358
|
-
result: Optional[MoveLabwareResult]
|
|
371
|
+
result: Optional[MoveLabwareResult] = None
|
|
359
372
|
|
|
360
373
|
_ImplementationCls: Type[MoveLabwareImplementation] = MoveLabwareImplementation
|
|
361
374
|
|