opentrons 8.1.0a0__py2.py3-none-any.whl → 8.2.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/cli/analyze.py +71 -7
- opentrons/config/__init__.py +9 -0
- opentrons/config/advanced_settings.py +22 -0
- opentrons/config/defaults_ot3.py +14 -36
- opentrons/config/feature_flags.py +4 -0
- opentrons/config/types.py +6 -17
- opentrons/drivers/absorbance_reader/abstract.py +27 -3
- opentrons/drivers/absorbance_reader/async_byonoy.py +207 -154
- opentrons/drivers/absorbance_reader/driver.py +24 -15
- opentrons/drivers/absorbance_reader/hid_protocol.py +79 -50
- opentrons/drivers/absorbance_reader/simulator.py +32 -6
- opentrons/drivers/types.py +23 -1
- opentrons/execute.py +2 -2
- opentrons/hardware_control/api.py +18 -10
- opentrons/hardware_control/backends/controller.py +3 -2
- opentrons/hardware_control/backends/flex_protocol.py +11 -5
- opentrons/hardware_control/backends/ot3controller.py +18 -50
- opentrons/hardware_control/backends/ot3simulator.py +7 -6
- opentrons/hardware_control/instruments/ot2/pipette_handler.py +22 -82
- opentrons/hardware_control/instruments/ot3/pipette_handler.py +10 -2
- opentrons/hardware_control/module_control.py +43 -2
- opentrons/hardware_control/modules/__init__.py +7 -1
- opentrons/hardware_control/modules/absorbance_reader.py +230 -83
- opentrons/hardware_control/modules/errors.py +7 -0
- opentrons/hardware_control/modules/heater_shaker.py +8 -3
- opentrons/hardware_control/modules/magdeck.py +12 -3
- opentrons/hardware_control/modules/mod_abc.py +27 -2
- opentrons/hardware_control/modules/tempdeck.py +15 -7
- opentrons/hardware_control/modules/thermocycler.py +69 -3
- opentrons/hardware_control/modules/types.py +11 -5
- opentrons/hardware_control/modules/update.py +11 -5
- opentrons/hardware_control/modules/utils.py +3 -1
- opentrons/hardware_control/ot3_calibration.py +6 -6
- opentrons/hardware_control/ot3api.py +126 -89
- opentrons/hardware_control/poller.py +15 -11
- opentrons/hardware_control/protocols/__init__.py +1 -7
- opentrons/hardware_control/protocols/instrument_configurer.py +14 -2
- opentrons/hardware_control/protocols/liquid_handler.py +5 -0
- opentrons/motion_planning/__init__.py +2 -0
- opentrons/motion_planning/waypoints.py +32 -0
- opentrons/protocol_api/__init__.py +2 -1
- opentrons/protocol_api/_liquid.py +87 -1
- opentrons/protocol_api/_parameter_context.py +10 -1
- opentrons/protocol_api/core/engine/deck_conflict.py +0 -297
- opentrons/protocol_api/core/engine/instrument.py +29 -25
- opentrons/protocol_api/core/engine/labware.py +10 -2
- opentrons/protocol_api/core/engine/module_core.py +129 -17
- opentrons/protocol_api/core/engine/pipette_movement_conflict.py +355 -0
- opentrons/protocol_api/core/engine/protocol.py +55 -2
- opentrons/protocol_api/core/instrument.py +2 -0
- opentrons/protocol_api/core/legacy/legacy_instrument_core.py +2 -0
- opentrons/protocol_api/core/legacy/legacy_protocol_core.py +5 -2
- opentrons/protocol_api/core/legacy_simulator/legacy_instrument_core.py +2 -0
- opentrons/protocol_api/core/module.py +22 -4
- opentrons/protocol_api/core/protocol.py +5 -2
- opentrons/protocol_api/instrument_context.py +52 -20
- opentrons/protocol_api/labware.py +13 -1
- opentrons/protocol_api/module_contexts.py +68 -13
- opentrons/protocol_api/protocol_context.py +38 -4
- opentrons/protocol_api/validation.py +5 -3
- opentrons/protocol_engine/__init__.py +10 -9
- opentrons/protocol_engine/actions/__init__.py +5 -0
- opentrons/protocol_engine/actions/actions.py +42 -25
- opentrons/protocol_engine/actions/get_state_update.py +38 -0
- opentrons/protocol_engine/clients/sync_client.py +7 -1
- opentrons/protocol_engine/clients/transports.py +1 -1
- opentrons/protocol_engine/commands/__init__.py +0 -4
- opentrons/protocol_engine/commands/absorbance_reader/__init__.py +41 -11
- opentrons/protocol_engine/commands/absorbance_reader/close_lid.py +161 -0
- opentrons/protocol_engine/commands/absorbance_reader/initialize.py +53 -9
- opentrons/protocol_engine/commands/absorbance_reader/open_lid.py +160 -0
- opentrons/protocol_engine/commands/absorbance_reader/read.py +196 -0
- opentrons/protocol_engine/commands/aspirate.py +29 -16
- opentrons/protocol_engine/commands/aspirate_in_place.py +32 -15
- opentrons/protocol_engine/commands/blow_out.py +63 -14
- opentrons/protocol_engine/commands/blow_out_in_place.py +55 -13
- opentrons/protocol_engine/commands/calibration/calibrate_gripper.py +2 -5
- opentrons/protocol_engine/commands/calibration/calibrate_module.py +3 -4
- opentrons/protocol_engine/commands/calibration/calibrate_pipette.py +2 -5
- opentrons/protocol_engine/commands/calibration/move_to_maintenance_position.py +6 -4
- opentrons/protocol_engine/commands/command.py +28 -17
- opentrons/protocol_engine/commands/command_unions.py +37 -24
- opentrons/protocol_engine/commands/comment.py +5 -3
- opentrons/protocol_engine/commands/configure_for_volume.py +11 -14
- opentrons/protocol_engine/commands/configure_nozzle_layout.py +9 -15
- opentrons/protocol_engine/commands/custom.py +5 -3
- opentrons/protocol_engine/commands/dispense.py +42 -20
- opentrons/protocol_engine/commands/dispense_in_place.py +32 -14
- opentrons/protocol_engine/commands/drop_tip.py +68 -15
- opentrons/protocol_engine/commands/drop_tip_in_place.py +52 -11
- opentrons/protocol_engine/commands/get_tip_presence.py +5 -3
- opentrons/protocol_engine/commands/heater_shaker/close_labware_latch.py +6 -6
- opentrons/protocol_engine/commands/heater_shaker/deactivate_heater.py +6 -6
- opentrons/protocol_engine/commands/heater_shaker/deactivate_shaker.py +6 -6
- opentrons/protocol_engine/commands/heater_shaker/open_labware_latch.py +8 -6
- opentrons/protocol_engine/commands/heater_shaker/set_and_wait_for_shake_speed.py +8 -4
- opentrons/protocol_engine/commands/heater_shaker/set_target_temperature.py +6 -4
- opentrons/protocol_engine/commands/heater_shaker/wait_for_temperature.py +6 -6
- opentrons/protocol_engine/commands/home.py +11 -5
- opentrons/protocol_engine/commands/liquid_probe.py +146 -88
- opentrons/protocol_engine/commands/load_labware.py +19 -5
- opentrons/protocol_engine/commands/load_liquid.py +18 -7
- opentrons/protocol_engine/commands/load_module.py +43 -6
- opentrons/protocol_engine/commands/load_pipette.py +18 -17
- opentrons/protocol_engine/commands/magnetic_module/disengage.py +6 -6
- opentrons/protocol_engine/commands/magnetic_module/engage.py +6 -4
- opentrons/protocol_engine/commands/move_labware.py +106 -19
- opentrons/protocol_engine/commands/move_relative.py +15 -3
- opentrons/protocol_engine/commands/move_to_addressable_area.py +29 -4
- opentrons/protocol_engine/commands/move_to_addressable_area_for_drop_tip.py +13 -4
- opentrons/protocol_engine/commands/move_to_coordinates.py +11 -5
- opentrons/protocol_engine/commands/move_to_well.py +37 -10
- opentrons/protocol_engine/commands/pick_up_tip.py +50 -29
- opentrons/protocol_engine/commands/pipetting_common.py +39 -15
- opentrons/protocol_engine/commands/prepare_to_aspirate.py +62 -15
- opentrons/protocol_engine/commands/reload_labware.py +13 -4
- opentrons/protocol_engine/commands/retract_axis.py +6 -3
- opentrons/protocol_engine/commands/save_position.py +2 -3
- opentrons/protocol_engine/commands/set_rail_lights.py +5 -3
- opentrons/protocol_engine/commands/set_status_bar.py +5 -3
- opentrons/protocol_engine/commands/temperature_module/deactivate.py +6 -4
- opentrons/protocol_engine/commands/temperature_module/set_target_temperature.py +3 -4
- opentrons/protocol_engine/commands/temperature_module/wait_for_temperature.py +6 -6
- opentrons/protocol_engine/commands/thermocycler/__init__.py +19 -0
- opentrons/protocol_engine/commands/thermocycler/close_lid.py +8 -8
- opentrons/protocol_engine/commands/thermocycler/deactivate_block.py +6 -4
- opentrons/protocol_engine/commands/thermocycler/deactivate_lid.py +6 -4
- opentrons/protocol_engine/commands/thermocycler/open_lid.py +8 -4
- opentrons/protocol_engine/commands/thermocycler/run_extended_profile.py +165 -0
- opentrons/protocol_engine/commands/thermocycler/run_profile.py +6 -6
- opentrons/protocol_engine/commands/thermocycler/set_target_block_temperature.py +3 -4
- opentrons/protocol_engine/commands/thermocycler/set_target_lid_temperature.py +3 -4
- opentrons/protocol_engine/commands/thermocycler/wait_for_block_temperature.py +6 -4
- opentrons/protocol_engine/commands/thermocycler/wait_for_lid_temperature.py +6 -4
- opentrons/protocol_engine/commands/touch_tip.py +19 -7
- opentrons/protocol_engine/commands/unsafe/__init__.py +30 -0
- opentrons/protocol_engine/commands/unsafe/unsafe_blow_out_in_place.py +6 -4
- opentrons/protocol_engine/commands/unsafe/unsafe_drop_tip_in_place.py +12 -4
- opentrons/protocol_engine/commands/unsafe/unsafe_engage_axes.py +5 -3
- opentrons/protocol_engine/commands/unsafe/unsafe_place_labware.py +194 -0
- opentrons/protocol_engine/commands/unsafe/unsafe_ungrip_labware.py +75 -0
- opentrons/protocol_engine/commands/unsafe/update_position_estimators.py +5 -3
- opentrons/protocol_engine/commands/verify_tip_presence.py +5 -5
- opentrons/protocol_engine/commands/wait_for_duration.py +5 -3
- opentrons/protocol_engine/commands/wait_for_resume.py +5 -3
- opentrons/protocol_engine/create_protocol_engine.py +41 -8
- opentrons/protocol_engine/engine_support.py +2 -1
- opentrons/protocol_engine/error_recovery_policy.py +14 -3
- opentrons/protocol_engine/errors/__init__.py +18 -0
- opentrons/protocol_engine/errors/exceptions.py +114 -2
- opentrons/protocol_engine/execution/__init__.py +2 -0
- opentrons/protocol_engine/execution/command_executor.py +22 -13
- opentrons/protocol_engine/execution/create_queue_worker.py +5 -1
- opentrons/protocol_engine/execution/door_watcher.py +1 -1
- opentrons/protocol_engine/execution/equipment.py +2 -1
- opentrons/protocol_engine/execution/error_recovery_hardware_state_synchronizer.py +101 -0
- opentrons/protocol_engine/execution/gantry_mover.py +4 -2
- opentrons/protocol_engine/execution/hardware_stopper.py +3 -3
- opentrons/protocol_engine/execution/heater_shaker_movement_flagger.py +1 -4
- opentrons/protocol_engine/execution/labware_movement.py +6 -3
- opentrons/protocol_engine/execution/movement.py +8 -3
- opentrons/protocol_engine/execution/pipetting.py +7 -4
- opentrons/protocol_engine/execution/queue_worker.py +6 -2
- opentrons/protocol_engine/execution/run_control.py +1 -1
- opentrons/protocol_engine/execution/thermocycler_movement_flagger.py +1 -1
- opentrons/protocol_engine/execution/thermocycler_plate_lifter.py +2 -1
- opentrons/protocol_engine/execution/tip_handler.py +77 -43
- opentrons/protocol_engine/notes/__init__.py +14 -2
- opentrons/protocol_engine/notes/notes.py +18 -1
- opentrons/protocol_engine/plugins.py +1 -1
- opentrons/protocol_engine/protocol_engine.py +54 -31
- opentrons/protocol_engine/resources/__init__.py +2 -0
- opentrons/protocol_engine/resources/deck_data_provider.py +58 -5
- opentrons/protocol_engine/resources/file_provider.py +157 -0
- opentrons/protocol_engine/resources/fixture_validation.py +5 -0
- opentrons/protocol_engine/resources/labware_validation.py +10 -0
- opentrons/protocol_engine/state/__init__.py +0 -70
- opentrons/protocol_engine/state/addressable_areas.py +1 -1
- opentrons/protocol_engine/state/command_history.py +21 -2
- opentrons/protocol_engine/state/commands.py +110 -31
- opentrons/protocol_engine/state/files.py +59 -0
- opentrons/protocol_engine/state/frustum_helpers.py +440 -0
- opentrons/protocol_engine/state/geometry.py +359 -15
- opentrons/protocol_engine/state/labware.py +166 -63
- opentrons/protocol_engine/state/liquids.py +1 -1
- opentrons/protocol_engine/state/module_substates/absorbance_reader_substate.py +19 -3
- opentrons/protocol_engine/state/modules.py +167 -85
- opentrons/protocol_engine/state/motion.py +16 -9
- opentrons/protocol_engine/state/pipettes.py +157 -317
- opentrons/protocol_engine/state/state.py +30 -1
- opentrons/protocol_engine/state/state_summary.py +3 -0
- opentrons/protocol_engine/state/tips.py +69 -114
- opentrons/protocol_engine/state/update_types.py +408 -0
- opentrons/protocol_engine/state/wells.py +236 -0
- opentrons/protocol_engine/types.py +90 -0
- opentrons/protocol_reader/file_format_validator.py +83 -15
- opentrons/protocol_runner/json_translator.py +21 -5
- opentrons/protocol_runner/legacy_command_mapper.py +27 -6
- opentrons/protocol_runner/legacy_context_plugin.py +27 -71
- opentrons/protocol_runner/protocol_runner.py +6 -3
- opentrons/protocol_runner/run_orchestrator.py +26 -6
- opentrons/protocols/advanced_control/mix.py +3 -5
- opentrons/protocols/advanced_control/transfers.py +125 -56
- opentrons/protocols/api_support/constants.py +1 -1
- opentrons/protocols/api_support/definitions.py +1 -1
- opentrons/protocols/api_support/labware_like.py +4 -4
- opentrons/protocols/api_support/tip_tracker.py +2 -2
- opentrons/protocols/api_support/types.py +15 -2
- opentrons/protocols/api_support/util.py +30 -42
- opentrons/protocols/duration/errors.py +1 -1
- opentrons/protocols/duration/estimator.py +50 -29
- opentrons/protocols/execution/dev_types.py +2 -2
- opentrons/protocols/execution/execute_json_v4.py +15 -10
- opentrons/protocols/execution/execute_python.py +8 -3
- opentrons/protocols/geometry/planning.py +12 -12
- opentrons/protocols/labware.py +17 -33
- opentrons/simulate.py +3 -3
- opentrons/types.py +30 -3
- opentrons/util/logging_config.py +34 -0
- {opentrons-8.1.0a0.dist-info → opentrons-8.2.0a0.dist-info}/METADATA +5 -4
- {opentrons-8.1.0a0.dist-info → opentrons-8.2.0a0.dist-info}/RECORD +227 -215
- opentrons/protocol_engine/commands/absorbance_reader/measure.py +0 -94
- opentrons/protocol_engine/commands/configuring_common.py +0 -26
- opentrons/protocol_runner/thread_async_queue.py +0 -174
- /opentrons/protocol_engine/state/{abstract_store.py → _abstract_store.py} +0 -0
- /opentrons/protocol_engine/state/{move_types.py → _move_types.py} +0 -0
- {opentrons-8.1.0a0.dist-info → opentrons-8.2.0a0.dist-info}/LICENSE +0 -0
- {opentrons-8.1.0a0.dist-info → opentrons-8.2.0a0.dist-info}/WHEEL +0 -0
- {opentrons-8.1.0a0.dist-info → opentrons-8.2.0a0.dist-info}/entry_points.txt +0 -0
- {opentrons-8.1.0a0.dist-info → opentrons-8.2.0a0.dist-info}/top_level.txt +0 -0
|
@@ -24,10 +24,14 @@ from opentrons.hardware_control.modules.types import LiveData
|
|
|
24
24
|
from opentrons.motion_planning.adjacent_slots_getters import (
|
|
25
25
|
get_east_slot,
|
|
26
26
|
get_west_slot,
|
|
27
|
+
get_adjacent_staging_slot,
|
|
27
28
|
)
|
|
28
29
|
from opentrons.protocol_engine.commands.calibration.calibrate_module import (
|
|
29
30
|
CalibrateModuleResult,
|
|
30
31
|
)
|
|
32
|
+
from opentrons.protocol_engine.state.module_substates.absorbance_reader_substate import (
|
|
33
|
+
AbsorbanceReaderMeasureMode,
|
|
34
|
+
)
|
|
31
35
|
from opentrons.types import DeckSlotName, MountType
|
|
32
36
|
from ..errors import ModuleNotConnectedError
|
|
33
37
|
|
|
@@ -45,7 +49,10 @@ from ..types import (
|
|
|
45
49
|
HeaterShakerMovementRestrictors,
|
|
46
50
|
DeckType,
|
|
47
51
|
LabwareMovementOffsetData,
|
|
52
|
+
AddressableAreaLocation,
|
|
48
53
|
)
|
|
54
|
+
|
|
55
|
+
from ..resources import DeckFixedLabware
|
|
49
56
|
from .addressable_areas import AddressableAreaView
|
|
50
57
|
from .. import errors
|
|
51
58
|
from ..commands import (
|
|
@@ -56,8 +63,13 @@ from ..commands import (
|
|
|
56
63
|
thermocycler,
|
|
57
64
|
absorbance_reader,
|
|
58
65
|
)
|
|
59
|
-
from ..actions import
|
|
60
|
-
|
|
66
|
+
from ..actions import (
|
|
67
|
+
Action,
|
|
68
|
+
SucceedCommandAction,
|
|
69
|
+
AddModuleAction,
|
|
70
|
+
AddAbsorbanceReaderLidAction,
|
|
71
|
+
)
|
|
72
|
+
from ._abstract_store import HasState, HandlesActions
|
|
61
73
|
from .module_substates import (
|
|
62
74
|
MagneticModuleSubState,
|
|
63
75
|
HeaterShakerModuleSubState,
|
|
@@ -174,6 +186,15 @@ class ModuleState:
|
|
|
174
186
|
deck_type: DeckType
|
|
175
187
|
"""Type of deck that the modules are on."""
|
|
176
188
|
|
|
189
|
+
deck_fixed_labware: Sequence[DeckFixedLabware]
|
|
190
|
+
"""Fixed labware from the deck which may be assigned to a module.
|
|
191
|
+
|
|
192
|
+
The Opentrons Plate Reader module makes use of an electronic Lid labware which moves
|
|
193
|
+
between the Reader and Dock positions, and is pre-loaded into the engine as to persist
|
|
194
|
+
even when not in use. For this reason, we inject it here when an appropriate match
|
|
195
|
+
is identified.
|
|
196
|
+
"""
|
|
197
|
+
|
|
177
198
|
|
|
178
199
|
class ModuleStore(HasState[ModuleState], HandlesActions):
|
|
179
200
|
"""Module state container."""
|
|
@@ -183,6 +204,7 @@ class ModuleStore(HasState[ModuleState], HandlesActions):
|
|
|
183
204
|
def __init__(
|
|
184
205
|
self,
|
|
185
206
|
config: Config,
|
|
207
|
+
deck_fixed_labware: Sequence[DeckFixedLabware],
|
|
186
208
|
module_calibration_offsets: Optional[Dict[str, ModuleOffsetData]] = None,
|
|
187
209
|
) -> None:
|
|
188
210
|
"""Initialize a ModuleStore and its state."""
|
|
@@ -194,6 +216,7 @@ class ModuleStore(HasState[ModuleState], HandlesActions):
|
|
|
194
216
|
substate_by_module_id={},
|
|
195
217
|
module_offset_by_serial=module_calibration_offsets or {},
|
|
196
218
|
deck_type=config.deck_type,
|
|
219
|
+
deck_fixed_labware=deck_fixed_labware,
|
|
197
220
|
)
|
|
198
221
|
self._robot_type = config.robot_type
|
|
199
222
|
|
|
@@ -211,6 +234,11 @@ class ModuleStore(HasState[ModuleState], HandlesActions):
|
|
|
211
234
|
requested_model=None,
|
|
212
235
|
module_live_data=action.module_live_data,
|
|
213
236
|
)
|
|
237
|
+
elif isinstance(action, AddAbsorbanceReaderLidAction):
|
|
238
|
+
self._update_absorbance_reader_lid_id(
|
|
239
|
+
module_id=action.module_id,
|
|
240
|
+
lid_id=action.lid_id,
|
|
241
|
+
)
|
|
214
242
|
|
|
215
243
|
def _handle_command(self, command: Command) -> None:
|
|
216
244
|
if isinstance(command.result, LoadModuleResult):
|
|
@@ -269,13 +297,38 @@ class ModuleStore(HasState[ModuleState], HandlesActions):
|
|
|
269
297
|
if isinstance(
|
|
270
298
|
command.result,
|
|
271
299
|
(
|
|
300
|
+
absorbance_reader.CloseLidResult,
|
|
301
|
+
absorbance_reader.OpenLidResult,
|
|
272
302
|
absorbance_reader.InitializeResult,
|
|
273
|
-
absorbance_reader.
|
|
303
|
+
absorbance_reader.ReadAbsorbanceResult,
|
|
274
304
|
),
|
|
275
305
|
):
|
|
276
306
|
self._handle_absorbance_reader_commands(command)
|
|
277
307
|
|
|
278
|
-
def
|
|
308
|
+
def _update_absorbance_reader_lid_id(
|
|
309
|
+
self,
|
|
310
|
+
module_id: str,
|
|
311
|
+
lid_id: str,
|
|
312
|
+
) -> None:
|
|
313
|
+
abs_substate = self._state.substate_by_module_id.get(module_id)
|
|
314
|
+
assert isinstance(
|
|
315
|
+
abs_substate, AbsorbanceReaderSubState
|
|
316
|
+
), f"{module_id} is not an absorbance plate reader."
|
|
317
|
+
|
|
318
|
+
prev_state: AbsorbanceReaderSubState = abs_substate
|
|
319
|
+
self._state.substate_by_module_id[module_id] = AbsorbanceReaderSubState(
|
|
320
|
+
module_id=AbsorbanceReaderId(module_id),
|
|
321
|
+
configured=prev_state.configured,
|
|
322
|
+
measured=prev_state.measured,
|
|
323
|
+
is_lid_on=prev_state.is_lid_on,
|
|
324
|
+
data=prev_state.data,
|
|
325
|
+
measure_mode=prev_state.measure_mode,
|
|
326
|
+
configured_wavelengths=prev_state.configured_wavelengths,
|
|
327
|
+
reference_wavelength=prev_state.reference_wavelength,
|
|
328
|
+
lid_id=lid_id,
|
|
329
|
+
)
|
|
330
|
+
|
|
331
|
+
def _add_module_substate( # noqa: C901
|
|
279
332
|
self,
|
|
280
333
|
module_id: str,
|
|
281
334
|
serial_number: Optional[str],
|
|
@@ -334,12 +387,26 @@ class ModuleStore(HasState[ModuleState], HandlesActions):
|
|
|
334
387
|
module_id=MagneticBlockId(module_id)
|
|
335
388
|
)
|
|
336
389
|
elif ModuleModel.is_absorbance_reader(actual_model):
|
|
390
|
+
lid_labware_id = None
|
|
391
|
+
slot = self._state.slot_by_module_id[module_id]
|
|
392
|
+
if slot is not None:
|
|
393
|
+
reader_addressable_area = f"absorbanceReaderV1{slot.value}"
|
|
394
|
+
for labware in self._state.deck_fixed_labware:
|
|
395
|
+
if labware.location == AddressableAreaLocation(
|
|
396
|
+
addressableAreaName=reader_addressable_area
|
|
397
|
+
):
|
|
398
|
+
lid_labware_id = labware.labware_id
|
|
399
|
+
break
|
|
337
400
|
self._state.substate_by_module_id[module_id] = AbsorbanceReaderSubState(
|
|
338
401
|
module_id=AbsorbanceReaderId(module_id),
|
|
339
402
|
configured=False,
|
|
340
403
|
measured=False,
|
|
404
|
+
is_lid_on=True,
|
|
341
405
|
data=None,
|
|
342
|
-
|
|
406
|
+
measure_mode=None,
|
|
407
|
+
configured_wavelengths=None,
|
|
408
|
+
reference_wavelength=None,
|
|
409
|
+
lid_id=lid_labware_id,
|
|
343
410
|
)
|
|
344
411
|
|
|
345
412
|
def _update_additional_slots_occupied_by_thermocycler(
|
|
@@ -513,7 +580,6 @@ class ModuleStore(HasState[ModuleState], HandlesActions):
|
|
|
513
580
|
target_block_temperature=block_temperature,
|
|
514
581
|
target_lid_temperature=None,
|
|
515
582
|
)
|
|
516
|
-
# TODO (spp, 2022-08-01): set is_lid_open to False upon lid commands' failure
|
|
517
583
|
elif isinstance(command.result, thermocycler.OpenLidResult):
|
|
518
584
|
self._state.substate_by_module_id[module_id] = ThermocyclerModuleSubState(
|
|
519
585
|
module_id=ThermocyclerModuleId(module_id),
|
|
@@ -533,7 +599,9 @@ class ModuleStore(HasState[ModuleState], HandlesActions):
|
|
|
533
599
|
self,
|
|
534
600
|
command: Union[
|
|
535
601
|
absorbance_reader.Initialize,
|
|
536
|
-
absorbance_reader.
|
|
602
|
+
absorbance_reader.ReadAbsorbance,
|
|
603
|
+
absorbance_reader.CloseLid,
|
|
604
|
+
absorbance_reader.OpenLid,
|
|
537
605
|
],
|
|
538
606
|
) -> None:
|
|
539
607
|
module_id = command.params.moduleId
|
|
@@ -544,25 +612,64 @@ class ModuleStore(HasState[ModuleState], HandlesActions):
|
|
|
544
612
|
|
|
545
613
|
# Get current values
|
|
546
614
|
configured = absorbance_reader_substate.configured
|
|
547
|
-
|
|
615
|
+
measure_mode = absorbance_reader_substate.measure_mode
|
|
616
|
+
configured_wavelengths = absorbance_reader_substate.configured_wavelengths
|
|
617
|
+
reference_wavelength = absorbance_reader_substate.reference_wavelength
|
|
618
|
+
is_lid_on = absorbance_reader_substate.is_lid_on
|
|
619
|
+
lid_id = absorbance_reader_substate.lid_id
|
|
620
|
+
data = absorbance_reader_substate.data
|
|
548
621
|
|
|
549
622
|
if isinstance(command.result, absorbance_reader.InitializeResult):
|
|
550
623
|
self._state.substate_by_module_id[module_id] = AbsorbanceReaderSubState(
|
|
551
624
|
module_id=AbsorbanceReaderId(module_id),
|
|
552
625
|
configured=True,
|
|
553
626
|
measured=False,
|
|
627
|
+
is_lid_on=is_lid_on,
|
|
628
|
+
lid_id=lid_id,
|
|
629
|
+
measure_mode=AbsorbanceReaderMeasureMode(command.params.measureMode),
|
|
630
|
+
configured_wavelengths=command.params.sampleWavelengths,
|
|
631
|
+
reference_wavelength=command.params.referenceWavelength,
|
|
554
632
|
data=None,
|
|
555
|
-
configured_wavelength=command.params.sampleWavelength,
|
|
556
633
|
)
|
|
557
|
-
elif isinstance(command.result, absorbance_reader.
|
|
634
|
+
elif isinstance(command.result, absorbance_reader.ReadAbsorbanceResult):
|
|
558
635
|
self._state.substate_by_module_id[module_id] = AbsorbanceReaderSubState(
|
|
559
636
|
module_id=AbsorbanceReaderId(module_id),
|
|
560
637
|
configured=configured,
|
|
561
|
-
configured_wavelength=configured_wavelength,
|
|
562
638
|
measured=True,
|
|
639
|
+
is_lid_on=is_lid_on,
|
|
640
|
+
lid_id=lid_id,
|
|
641
|
+
measure_mode=measure_mode,
|
|
642
|
+
configured_wavelengths=configured_wavelengths,
|
|
643
|
+
reference_wavelength=reference_wavelength,
|
|
563
644
|
data=command.result.data,
|
|
564
645
|
)
|
|
565
646
|
|
|
647
|
+
elif isinstance(command.result, absorbance_reader.OpenLidResult):
|
|
648
|
+
self._state.substate_by_module_id[module_id] = AbsorbanceReaderSubState(
|
|
649
|
+
module_id=AbsorbanceReaderId(module_id),
|
|
650
|
+
configured=configured,
|
|
651
|
+
measured=True,
|
|
652
|
+
is_lid_on=False,
|
|
653
|
+
lid_id=lid_id,
|
|
654
|
+
measure_mode=measure_mode,
|
|
655
|
+
configured_wavelengths=configured_wavelengths,
|
|
656
|
+
reference_wavelength=reference_wavelength,
|
|
657
|
+
data=data,
|
|
658
|
+
)
|
|
659
|
+
|
|
660
|
+
elif isinstance(command.result, absorbance_reader.CloseLidResult):
|
|
661
|
+
self._state.substate_by_module_id[module_id] = AbsorbanceReaderSubState(
|
|
662
|
+
module_id=AbsorbanceReaderId(module_id),
|
|
663
|
+
configured=configured,
|
|
664
|
+
measured=True,
|
|
665
|
+
is_lid_on=True,
|
|
666
|
+
lid_id=lid_id,
|
|
667
|
+
measure_mode=measure_mode,
|
|
668
|
+
configured_wavelengths=configured_wavelengths,
|
|
669
|
+
reference_wavelength=reference_wavelength,
|
|
670
|
+
data=data,
|
|
671
|
+
)
|
|
672
|
+
|
|
566
673
|
|
|
567
674
|
class ModuleView(HasState[ModuleState]):
|
|
568
675
|
"""Read-only view of computed module state."""
|
|
@@ -711,7 +818,7 @@ class ModuleView(HasState[ModuleState]):
|
|
|
711
818
|
return self._get_module_substate(
|
|
712
819
|
module_id=module_id,
|
|
713
820
|
expected_type=AbsorbanceReaderSubState,
|
|
714
|
-
expected_name="
|
|
821
|
+
expected_name="Absorbance Reader",
|
|
715
822
|
)
|
|
716
823
|
|
|
717
824
|
def get_location(self, module_id: str) -> DeckSlotLocation:
|
|
@@ -1179,6 +1286,25 @@ class ModuleView(HasState[ModuleState]):
|
|
|
1179
1286
|
else:
|
|
1180
1287
|
return False
|
|
1181
1288
|
|
|
1289
|
+
def convert_absorbance_reader_data_points(
|
|
1290
|
+
self, data: List[float]
|
|
1291
|
+
) -> Dict[str, float]:
|
|
1292
|
+
"""Return the data from the Absorbance Reader module in a map of wells for each read value."""
|
|
1293
|
+
if len(data) == 96:
|
|
1294
|
+
# We have to reverse the reader values because the Opentrons Absorbance Reader is rotated 180 degrees on the deck
|
|
1295
|
+
data.reverse()
|
|
1296
|
+
well_map: Dict[str, float] = {}
|
|
1297
|
+
for i, value in enumerate(data):
|
|
1298
|
+
row = chr(ord("A") + i // 12) # Convert index to row (A-H)
|
|
1299
|
+
col = (i % 12) + 1 # Convert index to column (1-12)
|
|
1300
|
+
well_key = f"{row}{col}"
|
|
1301
|
+
well_map[well_key] = value
|
|
1302
|
+
return well_map
|
|
1303
|
+
else:
|
|
1304
|
+
raise ValueError(
|
|
1305
|
+
"Only readings of 96 Well labware are supported for conversion to map of values by well."
|
|
1306
|
+
)
|
|
1307
|
+
|
|
1182
1308
|
def ensure_and_convert_module_fixture_location(
|
|
1183
1309
|
self,
|
|
1184
1310
|
deck_slot: DeckSlotName,
|
|
@@ -1194,84 +1320,40 @@ class ModuleView(HasState[ModuleState]):
|
|
|
1194
1320
|
f"Invalid Deck Type: {deck_type.name} - Does not support modules as fixtures."
|
|
1195
1321
|
)
|
|
1196
1322
|
|
|
1323
|
+
assert deck_slot in DeckSlotName.ot3_slots()
|
|
1197
1324
|
if model == ModuleModel.MAGNETIC_BLOCK_V1:
|
|
1198
|
-
|
|
1199
|
-
slot
|
|
1200
|
-
for slot in [
|
|
1201
|
-
"A1",
|
|
1202
|
-
"B1",
|
|
1203
|
-
"C1",
|
|
1204
|
-
"D1",
|
|
1205
|
-
"A2",
|
|
1206
|
-
"B2",
|
|
1207
|
-
"C2",
|
|
1208
|
-
"D2",
|
|
1209
|
-
"A3",
|
|
1210
|
-
"B3",
|
|
1211
|
-
"C3",
|
|
1212
|
-
"D3",
|
|
1213
|
-
]
|
|
1214
|
-
]
|
|
1215
|
-
addressable_areas = [
|
|
1216
|
-
"magneticBlockV1A1",
|
|
1217
|
-
"magneticBlockV1B1",
|
|
1218
|
-
"magneticBlockV1C1",
|
|
1219
|
-
"magneticBlockV1D1",
|
|
1220
|
-
"magneticBlockV1A2",
|
|
1221
|
-
"magneticBlockV1B2",
|
|
1222
|
-
"magneticBlockV1C2",
|
|
1223
|
-
"magneticBlockV1D2",
|
|
1224
|
-
"magneticBlockV1A3",
|
|
1225
|
-
"magneticBlockV1B3",
|
|
1226
|
-
"magneticBlockV1C3",
|
|
1227
|
-
"magneticBlockV1D3",
|
|
1228
|
-
]
|
|
1325
|
+
return f"magneticBlockV1{deck_slot.value}"
|
|
1229
1326
|
|
|
1230
1327
|
elif model == ModuleModel.HEATER_SHAKER_MODULE_V1:
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
"heaterShakerV1A1",
|
|
1236
|
-
"heaterShakerV1B1",
|
|
1237
|
-
"heaterShakerV1C1",
|
|
1238
|
-
"heaterShakerV1D1",
|
|
1239
|
-
"heaterShakerV1A3",
|
|
1240
|
-
"heaterShakerV1B3",
|
|
1241
|
-
"heaterShakerV1C3",
|
|
1242
|
-
"heaterShakerV1D3",
|
|
1243
|
-
]
|
|
1328
|
+
# only allowed in column 1 & 3
|
|
1329
|
+
assert deck_slot.value[-1] in ("1", "3")
|
|
1330
|
+
return f"heaterShakerV1{deck_slot.value}"
|
|
1331
|
+
|
|
1244
1332
|
elif model == ModuleModel.TEMPERATURE_MODULE_V2:
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
"temperatureModuleV2A1",
|
|
1250
|
-
"temperatureModuleV2B1",
|
|
1251
|
-
"temperatureModuleV2C1",
|
|
1252
|
-
"temperatureModuleV2D1",
|
|
1253
|
-
"temperatureModuleV2A3",
|
|
1254
|
-
"temperatureModuleV2B3",
|
|
1255
|
-
"temperatureModuleV2C3",
|
|
1256
|
-
"temperatureModuleV2D3",
|
|
1257
|
-
]
|
|
1333
|
+
# only allowed in column 1 & 3
|
|
1334
|
+
assert deck_slot.value[-1] in ("1", "3")
|
|
1335
|
+
return f"temperatureModuleV2{deck_slot.value}"
|
|
1336
|
+
|
|
1258
1337
|
elif model == ModuleModel.THERMOCYCLER_MODULE_V2:
|
|
1259
1338
|
return "thermocyclerModuleV2"
|
|
1339
|
+
|
|
1260
1340
|
elif model == ModuleModel.ABSORBANCE_READER_V1:
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
else:
|
|
1269
|
-
raise ValueError(
|
|
1270
|
-
f"Unknown module {model.name} has no addressable areas to provide."
|
|
1271
|
-
)
|
|
1341
|
+
# only allowed in column 3
|
|
1342
|
+
assert deck_slot.value[-1] == "3"
|
|
1343
|
+
return f"absorbanceReaderV1{deck_slot.value}"
|
|
1344
|
+
|
|
1345
|
+
raise ValueError(
|
|
1346
|
+
f"Unknown module {model.name} has no addressable areas to provide."
|
|
1347
|
+
)
|
|
1272
1348
|
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1349
|
+
def absorbance_reader_dock_location(
|
|
1350
|
+
self, module_id: str
|
|
1351
|
+
) -> AddressableAreaLocation:
|
|
1352
|
+
"""Get the addressable area for the absorbance reader dock."""
|
|
1353
|
+
reader_slot = self.get_location(module_id)
|
|
1354
|
+
lid_doc_slot = get_adjacent_staging_slot(reader_slot.slotName)
|
|
1355
|
+
assert lid_doc_slot is not None
|
|
1356
|
+
lid_dock_area = AddressableAreaLocation(
|
|
1357
|
+
addressableAreaName="absorbanceReaderV1LidDock" + lid_doc_slot.value
|
|
1358
|
+
)
|
|
1359
|
+
return lid_dock_area
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"""Motion state store and getters."""
|
|
2
2
|
from dataclasses import dataclass
|
|
3
|
-
from typing import List, Optional
|
|
3
|
+
from typing import List, Optional, Union
|
|
4
4
|
|
|
5
5
|
from opentrons.types import MountType, Point
|
|
6
6
|
from opentrons.hardware_control.types import CriticalPoint
|
|
@@ -10,11 +10,12 @@ from opentrons.motion_planning.adjacent_slots_getters import (
|
|
|
10
10
|
)
|
|
11
11
|
from opentrons import motion_planning
|
|
12
12
|
|
|
13
|
-
from . import
|
|
13
|
+
from . import _move_types
|
|
14
14
|
from .. import errors
|
|
15
15
|
from ..types import (
|
|
16
16
|
MotorAxis,
|
|
17
17
|
WellLocation,
|
|
18
|
+
LiquidHandlingWellLocation,
|
|
18
19
|
CurrentWell,
|
|
19
20
|
CurrentPipetteLocation,
|
|
20
21
|
AddressableOffsetVector,
|
|
@@ -89,13 +90,14 @@ class MotionView:
|
|
|
89
90
|
pipette_id: str,
|
|
90
91
|
labware_id: str,
|
|
91
92
|
well_name: str,
|
|
92
|
-
well_location: Optional[WellLocation],
|
|
93
|
+
well_location: Optional[Union[WellLocation, LiquidHandlingWellLocation]],
|
|
93
94
|
origin: Point,
|
|
94
95
|
origin_cp: Optional[CriticalPoint],
|
|
95
96
|
max_travel_z: float,
|
|
96
97
|
current_well: Optional[CurrentWell] = None,
|
|
97
98
|
force_direct: bool = False,
|
|
98
99
|
minimum_z_height: Optional[float] = None,
|
|
100
|
+
operation_volume: Optional[float] = None,
|
|
99
101
|
) -> List[motion_planning.Waypoint]:
|
|
100
102
|
"""Calculate waypoints to a destination that's specified as a well."""
|
|
101
103
|
location = current_well or self._pipettes.get_current_location()
|
|
@@ -107,12 +109,14 @@ class MotionView:
|
|
|
107
109
|
destination_cp = CriticalPoint.XY_CENTER
|
|
108
110
|
|
|
109
111
|
destination = self._geometry.get_well_position(
|
|
110
|
-
labware_id,
|
|
111
|
-
well_name,
|
|
112
|
-
well_location,
|
|
112
|
+
labware_id=labware_id,
|
|
113
|
+
well_name=well_name,
|
|
114
|
+
well_location=well_location,
|
|
115
|
+
operation_volume=operation_volume,
|
|
116
|
+
pipette_id=pipette_id,
|
|
113
117
|
)
|
|
114
118
|
|
|
115
|
-
move_type =
|
|
119
|
+
move_type = _move_types.get_move_type_to_well(
|
|
116
120
|
pipette_id, labware_id, well_name, location, force_direct
|
|
117
121
|
)
|
|
118
122
|
min_travel_z = self._geometry.get_min_travel_z(
|
|
@@ -151,6 +155,7 @@ class MotionView:
|
|
|
151
155
|
minimum_z_height: Optional[float] = None,
|
|
152
156
|
stay_at_max_travel_z: bool = False,
|
|
153
157
|
ignore_tip_configuration: Optional[bool] = True,
|
|
158
|
+
max_travel_z_extra_margin: Optional[float] = None,
|
|
154
159
|
) -> List[motion_planning.Waypoint]:
|
|
155
160
|
"""Calculate waypoints to a destination that's specified as an addressable area."""
|
|
156
161
|
location = self._pipettes.get_current_location()
|
|
@@ -169,7 +174,9 @@ class MotionView:
|
|
|
169
174
|
# beneath max_travel_z. Investigate why motion_planning.get_waypoints() does not
|
|
170
175
|
# let us travel at max_travel_z, and whether it's safe to make it do that.
|
|
171
176
|
# Possibly related: https://github.com/Opentrons/opentrons/pull/6882#discussion_r514248062
|
|
172
|
-
max_travel_z
|
|
177
|
+
max_travel_z
|
|
178
|
+
- motion_planning.waypoints.MINIMUM_Z_MARGIN
|
|
179
|
+
- (max_travel_z_extra_margin or 0.0),
|
|
173
180
|
)
|
|
174
181
|
destination = base_destination_at_max_z + Point(
|
|
175
182
|
offset.x, offset.y, offset.z
|
|
@@ -326,7 +333,7 @@ class MotionView:
|
|
|
326
333
|
labware_id, well_name, radius
|
|
327
334
|
)
|
|
328
335
|
|
|
329
|
-
positions =
|
|
336
|
+
positions = _move_types.get_edge_point_list(
|
|
330
337
|
center_point, x_offset, y_offset, edge_path_type
|
|
331
338
|
)
|
|
332
339
|
critical_point: Optional[CriticalPoint] = None
|