opentrons 8.1.0a0__py2.py3-none-any.whl → 8.2.0__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/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 +208 -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/backends/ot3utils.py +1 -0
- 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 +232 -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 +131 -94
- 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/hardware_control/protocols/position_estimator.py +3 -1
- opentrons/hardware_control/types.py +2 -0
- opentrons/legacy_commands/helpers.py +8 -2
- 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 +20 -4
- opentrons/protocol_api/core/engine/module_core.py +166 -17
- opentrons/protocol_api/core/engine/pipette_movement_conflict.py +362 -0
- opentrons/protocol_api/core/engine/protocol.py +30 -2
- opentrons/protocol_api/core/instrument.py +2 -0
- opentrons/protocol_api/core/labware.py +4 -0
- opentrons/protocol_api/core/legacy/legacy_instrument_core.py +2 -0
- opentrons/protocol_api/core/legacy/legacy_labware_core.py +5 -0
- opentrons/protocol_api/core/legacy/legacy_protocol_core.py +6 -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 +6 -2
- opentrons/protocol_api/instrument_context.py +52 -20
- opentrons/protocol_api/labware.py +13 -1
- opentrons/protocol_api/module_contexts.py +115 -17
- opentrons/protocol_api/protocol_context.py +49 -5
- opentrons/protocol_api/validation.py +5 -3
- opentrons/protocol_engine/__init__.py +10 -9
- opentrons/protocol_engine/actions/__init__.py +3 -0
- opentrons/protocol_engine/actions/actions.py +30 -25
- opentrons/protocol_engine/actions/get_state_update.py +38 -0
- opentrons/protocol_engine/clients/sync_client.py +1 -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 +148 -0
- opentrons/protocol_engine/commands/absorbance_reader/initialize.py +65 -9
- opentrons/protocol_engine/commands/absorbance_reader/open_lid.py +148 -0
- opentrons/protocol_engine/commands/absorbance_reader/read.py +200 -0
- opentrons/protocol_engine/commands/aspirate.py +29 -16
- opentrons/protocol_engine/commands/aspirate_in_place.py +33 -16
- 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 +31 -18
- 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 +70 -16
- opentrons/protocol_engine/commands/drop_tip_in_place.py +59 -13
- 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 +28 -5
- opentrons/protocol_engine/commands/load_liquid.py +18 -7
- opentrons/protocol_engine/commands/load_module.py +4 -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 +155 -23
- 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 +51 -30
- opentrons/protocol_engine/commands/pipetting_common.py +47 -16
- 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 +208 -0
- opentrons/protocol_engine/commands/unsafe/unsafe_ungrip_labware.py +77 -0
- opentrons/protocol_engine/commands/unsafe/update_position_estimators.py +10 -4
- 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 +60 -10
- opentrons/protocol_engine/engine_support.py +2 -1
- opentrons/protocol_engine/error_recovery_policy.py +14 -3
- opentrons/protocol_engine/errors/__init__.py +20 -0
- opentrons/protocol_engine/errors/error_occurrence.py +8 -3
- opentrons/protocol_engine/errors/exceptions.py +127 -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 +73 -22
- opentrons/protocol_engine/execution/movement.py +17 -7
- 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 +47 -31
- opentrons/protocol_engine/resources/__init__.py +2 -0
- opentrons/protocol_engine/resources/deck_data_provider.py +19 -5
- opentrons/protocol_engine/resources/file_provider.py +161 -0
- opentrons/protocol_engine/resources/fixture_validation.py +11 -1
- 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 +445 -59
- opentrons/protocol_engine/state/labware.py +264 -84
- opentrons/protocol_engine/state/liquids.py +1 -1
- opentrons/protocol_engine/state/module_substates/absorbance_reader_substate.py +21 -3
- opentrons/protocol_engine/state/modules.py +145 -90
- opentrons/protocol_engine/state/motion.py +33 -14
- 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 +424 -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 +41 -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/protocols/parameters/csv_parameter_interface.py +3 -1
- 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.0.dist-info}/METADATA +5 -4
- {opentrons-8.1.0a0.dist-info → opentrons-8.2.0.dist-info}/RECORD +235 -223
- 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.0.dist-info}/LICENSE +0 -0
- {opentrons-8.1.0a0.dist-info → opentrons-8.2.0.dist-info}/WHEEL +0 -0
- {opentrons-8.1.0a0.dist-info → opentrons-8.2.0.dist-info}/entry_points.txt +0 -0
- {opentrons-8.1.0a0.dist-info → opentrons-8.2.0.dist-info}/top_level.txt +0 -0
|
@@ -2,11 +2,17 @@
|
|
|
2
2
|
from __future__ import annotations
|
|
3
3
|
from typing import Dict, Optional, Type, Union, List, Tuple, TYPE_CHECKING
|
|
4
4
|
|
|
5
|
+
from opentrons_shared_data.liquid_classes import LiquidClassDefinitionDoesNotExist
|
|
6
|
+
|
|
5
7
|
from opentrons.protocol_engine import commands as cmd
|
|
6
8
|
from opentrons.protocol_engine.commands import LoadModuleResult
|
|
7
9
|
from opentrons_shared_data.deck.types import DeckDefinitionV5, SlotDefV3
|
|
8
10
|
from opentrons_shared_data.labware.labware_definition import LabwareDefinition
|
|
9
11
|
from opentrons_shared_data.labware.types import LabwareDefinition as LabwareDefDict
|
|
12
|
+
from opentrons_shared_data import liquid_classes
|
|
13
|
+
from opentrons_shared_data.liquid_classes.liquid_class_definition import (
|
|
14
|
+
LiquidClassSchemaV1,
|
|
15
|
+
)
|
|
10
16
|
from opentrons_shared_data.pipette.types import PipetteNameType
|
|
11
17
|
from opentrons_shared_data.robot.types import RobotType
|
|
12
18
|
|
|
@@ -51,7 +57,7 @@ from opentrons.protocol_engine.errors import (
|
|
|
51
57
|
|
|
52
58
|
from ... import validation
|
|
53
59
|
from ..._types import OffDeckType
|
|
54
|
-
from ..._liquid import Liquid
|
|
60
|
+
from ..._liquid import Liquid, LiquidClass
|
|
55
61
|
from ...disposal_locations import TrashBin, WasteChute
|
|
56
62
|
from ..protocol import AbstractProtocol
|
|
57
63
|
from ..labware import LabwareLoadParams
|
|
@@ -103,6 +109,7 @@ class ProtocolCore(
|
|
|
103
109
|
str, Union[ModuleCore, NonConnectedModuleCore]
|
|
104
110
|
] = {}
|
|
105
111
|
self._disposal_locations: List[Union[Labware, TrashBin, WasteChute]] = []
|
|
112
|
+
self._defined_liquid_class_defs_by_name: Dict[str, LiquidClassSchemaV1] = {}
|
|
106
113
|
self._load_fixed_trash()
|
|
107
114
|
|
|
108
115
|
@property
|
|
@@ -311,7 +318,6 @@ class ProtocolCore(
|
|
|
311
318
|
|
|
312
319
|
return labware_core
|
|
313
320
|
|
|
314
|
-
# TODO (spp, 2022-12-14): https://opentrons.atlassian.net/browse/RLAB-237
|
|
315
321
|
def move_labware(
|
|
316
322
|
self,
|
|
317
323
|
labware_core: LabwareCore,
|
|
@@ -323,6 +329,7 @@ class ProtocolCore(
|
|
|
323
329
|
NonConnectedModuleCore,
|
|
324
330
|
OffDeckType,
|
|
325
331
|
WasteChute,
|
|
332
|
+
TrashBin,
|
|
326
333
|
],
|
|
327
334
|
use_gripper: bool,
|
|
328
335
|
pause_for_manual_move: bool,
|
|
@@ -723,6 +730,23 @@ class ProtocolCore(
|
|
|
723
730
|
),
|
|
724
731
|
)
|
|
725
732
|
|
|
733
|
+
def define_liquid_class(self, name: str) -> LiquidClass:
|
|
734
|
+
"""Define a liquid class for use in transfer functions."""
|
|
735
|
+
try:
|
|
736
|
+
# Check if we have already loaded this liquid class' definition
|
|
737
|
+
liquid_class_def = self._defined_liquid_class_defs_by_name[name]
|
|
738
|
+
except KeyError:
|
|
739
|
+
try:
|
|
740
|
+
# Fetching the liquid class data from file and parsing it
|
|
741
|
+
# is an expensive operation and should be avoided.
|
|
742
|
+
# Calling this often will degrade protocol execution performance.
|
|
743
|
+
liquid_class_def = liquid_classes.load_definition(name)
|
|
744
|
+
self._defined_liquid_class_defs_by_name[name] = liquid_class_def
|
|
745
|
+
except LiquidClassDefinitionDoesNotExist:
|
|
746
|
+
raise ValueError(f"Liquid class definition not found for '{name}'.")
|
|
747
|
+
|
|
748
|
+
return LiquidClass.create(liquid_class_def)
|
|
749
|
+
|
|
726
750
|
def get_labware_location(
|
|
727
751
|
self, labware_core: LabwareCore
|
|
728
752
|
) -> Union[str, LabwareCore, ModuleCore, NonConnectedModuleCore, OffDeckType]:
|
|
@@ -754,6 +778,7 @@ class ProtocolCore(
|
|
|
754
778
|
NonConnectedModuleCore,
|
|
755
779
|
OffDeckType,
|
|
756
780
|
WasteChute,
|
|
781
|
+
TrashBin,
|
|
757
782
|
],
|
|
758
783
|
) -> LabwareLocation:
|
|
759
784
|
if isinstance(location, LabwareCore):
|
|
@@ -770,6 +795,7 @@ class ProtocolCore(
|
|
|
770
795
|
NonConnectedModuleCore,
|
|
771
796
|
OffDeckType,
|
|
772
797
|
WasteChute,
|
|
798
|
+
TrashBin,
|
|
773
799
|
]
|
|
774
800
|
) -> NonStackedLocation:
|
|
775
801
|
if isinstance(location, (ModuleCore, NonConnectedModuleCore)):
|
|
@@ -783,3 +809,5 @@ class ProtocolCore(
|
|
|
783
809
|
elif isinstance(location, WasteChute):
|
|
784
810
|
# TODO(mm, 2023-12-06) This will need to determine the appropriate Waste Chute to return, but only move_labware uses this for now
|
|
785
811
|
return AddressableAreaLocation(addressableAreaName="gripperWasteChute")
|
|
812
|
+
elif isinstance(location, TrashBin):
|
|
813
|
+
return AddressableAreaLocation(addressableAreaName=location.area_name)
|
|
@@ -33,6 +33,7 @@ class AbstractInstrument(ABC, Generic[WellCoreType]):
|
|
|
33
33
|
rate: float,
|
|
34
34
|
flow_rate: float,
|
|
35
35
|
in_place: bool,
|
|
36
|
+
is_meniscus: Optional[bool] = None,
|
|
36
37
|
) -> None:
|
|
37
38
|
"""Aspirate a given volume of liquid from the specified location.
|
|
38
39
|
Args:
|
|
@@ -55,6 +56,7 @@ class AbstractInstrument(ABC, Generic[WellCoreType]):
|
|
|
55
56
|
flow_rate: float,
|
|
56
57
|
in_place: bool,
|
|
57
58
|
push_out: Optional[float],
|
|
59
|
+
is_meniscus: Optional[bool] = None,
|
|
58
60
|
) -> None:
|
|
59
61
|
"""Dispense a given volume of liquid into the specified location.
|
|
60
62
|
Args:
|
|
@@ -97,6 +97,10 @@ class AbstractLabware(ABC, Generic[WellCoreType]):
|
|
|
97
97
|
def is_adapter(self) -> bool:
|
|
98
98
|
"""Whether the labware is an adapter."""
|
|
99
99
|
|
|
100
|
+
@abstractmethod
|
|
101
|
+
def is_lid(self) -> bool:
|
|
102
|
+
"""Whether the labware is a lid."""
|
|
103
|
+
|
|
100
104
|
@abstractmethod
|
|
101
105
|
def is_fixed_trash(self) -> bool:
|
|
102
106
|
"""Whether the labware is a fixed trash."""
|
|
@@ -80,6 +80,7 @@ class LegacyInstrumentCore(AbstractInstrument[LegacyWellCore]):
|
|
|
80
80
|
rate: float,
|
|
81
81
|
flow_rate: float,
|
|
82
82
|
in_place: bool,
|
|
83
|
+
is_meniscus: Optional[bool] = None,
|
|
83
84
|
) -> None:
|
|
84
85
|
"""Aspirate a given volume of liquid from the specified location.
|
|
85
86
|
Args:
|
|
@@ -122,6 +123,7 @@ class LegacyInstrumentCore(AbstractInstrument[LegacyWellCore]):
|
|
|
122
123
|
flow_rate: float,
|
|
123
124
|
in_place: bool,
|
|
124
125
|
push_out: Optional[float],
|
|
126
|
+
is_meniscus: Optional[bool] = None,
|
|
125
127
|
) -> None:
|
|
126
128
|
"""Dispense a given volume of liquid into the specified location.
|
|
127
129
|
Args:
|
|
@@ -138,6 +138,11 @@ class LegacyLabwareCore(AbstractLabware[LegacyWellCore]):
|
|
|
138
138
|
def is_adapter(self) -> bool:
|
|
139
139
|
return False # Adapters were introduced in v2.15 and not supported in legacy protocols
|
|
140
140
|
|
|
141
|
+
def is_lid(self) -> bool:
|
|
142
|
+
return (
|
|
143
|
+
False # Lids were introduced in v2.21 and not supported in legacy protocols
|
|
144
|
+
)
|
|
145
|
+
|
|
141
146
|
def is_fixed_trash(self) -> bool:
|
|
142
147
|
"""Whether the labware is fixed trash."""
|
|
143
148
|
return "fixedTrash" in self.get_quirks()
|
|
@@ -17,7 +17,7 @@ from opentrons.protocols import labware as labware_definition
|
|
|
17
17
|
|
|
18
18
|
from ...labware import Labware
|
|
19
19
|
from ...disposal_locations import TrashBin, WasteChute
|
|
20
|
-
from ..._liquid import Liquid
|
|
20
|
+
from ..._liquid import Liquid, LiquidClass
|
|
21
21
|
from ..._types import OffDeckType
|
|
22
22
|
from ..protocol import AbstractProtocol
|
|
23
23
|
from ..labware import LabwareLoadParams
|
|
@@ -267,7 +267,6 @@ class LegacyProtocolCore(
|
|
|
267
267
|
"""Load an adapter using its identifying parameters"""
|
|
268
268
|
raise APIVersionError(api_element="Loading adapter")
|
|
269
269
|
|
|
270
|
-
# TODO (spp, 2022-12-14): https://opentrons.atlassian.net/browse/RLAB-237
|
|
271
270
|
def move_labware(
|
|
272
271
|
self,
|
|
273
272
|
labware_core: LegacyLabwareCore,
|
|
@@ -278,6 +277,7 @@ class LegacyProtocolCore(
|
|
|
278
277
|
legacy_module_core.LegacyModuleCore,
|
|
279
278
|
OffDeckType,
|
|
280
279
|
WasteChute,
|
|
280
|
+
TrashBin,
|
|
281
281
|
],
|
|
282
282
|
use_gripper: bool,
|
|
283
283
|
pause_for_manual_move: bool,
|
|
@@ -532,6 +532,10 @@ class LegacyProtocolCore(
|
|
|
532
532
|
"""Define a liquid to load into a well."""
|
|
533
533
|
assert False, "define_liquid only supported on engine core"
|
|
534
534
|
|
|
535
|
+
def define_liquid_class(self, name: str) -> LiquidClass:
|
|
536
|
+
"""Define a liquid class."""
|
|
537
|
+
assert False, "define_liquid_class is only supported on engine core"
|
|
538
|
+
|
|
535
539
|
def get_labware_location(
|
|
536
540
|
self, labware_core: LegacyLabwareCore
|
|
537
541
|
) -> Union[
|
|
@@ -91,6 +91,7 @@ class LegacyInstrumentCoreSimulator(AbstractInstrument[LegacyWellCore]):
|
|
|
91
91
|
rate: float,
|
|
92
92
|
flow_rate: float,
|
|
93
93
|
in_place: bool,
|
|
94
|
+
is_meniscus: Optional[bool] = None,
|
|
94
95
|
) -> None:
|
|
95
96
|
if self.get_current_volume() == 0:
|
|
96
97
|
# Make sure we're at the top of the labware and clear of any
|
|
@@ -132,6 +133,7 @@ class LegacyInstrumentCoreSimulator(AbstractInstrument[LegacyWellCore]):
|
|
|
132
133
|
flow_rate: float,
|
|
133
134
|
in_place: bool,
|
|
134
135
|
push_out: Optional[float],
|
|
136
|
+
is_meniscus: Optional[bool] = None,
|
|
135
137
|
) -> None:
|
|
136
138
|
if isinstance(location, (TrashBin, WasteChute)):
|
|
137
139
|
raise APIVersionError(
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
from __future__ import annotations
|
|
3
3
|
|
|
4
4
|
from abc import ABC, abstractmethod
|
|
5
|
-
from typing import List, Optional, TypeVar, ClassVar
|
|
5
|
+
from typing import List, Dict, Optional, TypeVar, ClassVar
|
|
6
6
|
|
|
7
7
|
from opentrons.drivers.types import (
|
|
8
8
|
HeaterShakerLabwareLatchStatus,
|
|
@@ -16,6 +16,7 @@ from opentrons.hardware_control.modules.types import (
|
|
|
16
16
|
MagneticStatus,
|
|
17
17
|
SpeedStatus,
|
|
18
18
|
)
|
|
19
|
+
from opentrons.protocol_engine.types import ABSMeasureMode
|
|
19
20
|
from opentrons.types import DeckSlotName
|
|
20
21
|
|
|
21
22
|
|
|
@@ -355,9 +356,26 @@ class AbstractAbsorbanceReaderCore(AbstractModuleCore):
|
|
|
355
356
|
"""Get the module's unique hardware serial number."""
|
|
356
357
|
|
|
357
358
|
@abstractmethod
|
|
358
|
-
def initialize(
|
|
359
|
+
def initialize(
|
|
360
|
+
self,
|
|
361
|
+
mode: ABSMeasureMode,
|
|
362
|
+
wavelengths: List[int],
|
|
363
|
+
reference_wavelength: Optional[int] = None,
|
|
364
|
+
) -> None:
|
|
359
365
|
"""Initialize the Absorbance Reader by taking zero reading."""
|
|
360
366
|
|
|
361
367
|
@abstractmethod
|
|
362
|
-
def
|
|
363
|
-
"""
|
|
368
|
+
def read(self, filename: Optional[str] = None) -> Dict[int, Dict[str, float]]:
|
|
369
|
+
"""Get an absorbance reading from the Absorbance Reader."""
|
|
370
|
+
|
|
371
|
+
@abstractmethod
|
|
372
|
+
def close_lid(self) -> None:
|
|
373
|
+
"""Close the Absorbance Reader's lid."""
|
|
374
|
+
|
|
375
|
+
@abstractmethod
|
|
376
|
+
def open_lid(self) -> None:
|
|
377
|
+
"""Open the Absorbance Reader's lid."""
|
|
378
|
+
|
|
379
|
+
@abstractmethod
|
|
380
|
+
def is_lid_on(self) -> bool:
|
|
381
|
+
"""Return True if the Absorbance Reader's lid is currently closed."""
|
|
@@ -18,7 +18,7 @@ from opentrons.protocols.api_support.util import AxisMaxSpeeds
|
|
|
18
18
|
from .instrument import InstrumentCoreType
|
|
19
19
|
from .labware import LabwareCoreType, LabwareLoadParams
|
|
20
20
|
from .module import ModuleCoreType
|
|
21
|
-
from .._liquid import Liquid
|
|
21
|
+
from .._liquid import Liquid, LiquidClass
|
|
22
22
|
from .._types import OffDeckType
|
|
23
23
|
from ..disposal_locations import TrashBin, WasteChute
|
|
24
24
|
|
|
@@ -93,7 +93,6 @@ class AbstractProtocol(
|
|
|
93
93
|
"""Load an adapter using its identifying parameters"""
|
|
94
94
|
...
|
|
95
95
|
|
|
96
|
-
# TODO (spp, 2022-12-14): https://opentrons.atlassian.net/browse/RLAB-237
|
|
97
96
|
@abstractmethod
|
|
98
97
|
def move_labware(
|
|
99
98
|
self,
|
|
@@ -105,6 +104,7 @@ class AbstractProtocol(
|
|
|
105
104
|
ModuleCoreType,
|
|
106
105
|
OffDeckType,
|
|
107
106
|
WasteChute,
|
|
107
|
+
TrashBin,
|
|
108
108
|
],
|
|
109
109
|
use_gripper: bool,
|
|
110
110
|
pause_for_manual_move: bool,
|
|
@@ -248,6 +248,10 @@ class AbstractProtocol(
|
|
|
248
248
|
) -> Liquid:
|
|
249
249
|
"""Define a liquid to load into a well."""
|
|
250
250
|
|
|
251
|
+
@abstractmethod
|
|
252
|
+
def define_liquid_class(self, name: str) -> LiquidClass:
|
|
253
|
+
"""Define a liquid class for use in transfer functions."""
|
|
254
|
+
|
|
251
255
|
@abstractmethod
|
|
252
256
|
def get_labware_location(
|
|
253
257
|
self, labware_core: LabwareCoreType
|
|
@@ -39,12 +39,7 @@ from ._nozzle_layout import NozzleLayout
|
|
|
39
39
|
from . import labware, validation
|
|
40
40
|
|
|
41
41
|
|
|
42
|
-
AdvancedLiquidHandling =
|
|
43
|
-
labware.Well,
|
|
44
|
-
types.Location,
|
|
45
|
-
Sequence[Union[labware.Well, types.Location]],
|
|
46
|
-
Sequence[Sequence[labware.Well]],
|
|
47
|
-
]
|
|
42
|
+
AdvancedLiquidHandling = transfers.AdvancedLiquidHandling
|
|
48
43
|
|
|
49
44
|
_DEFAULT_ASPIRATE_CLEARANCE = 1.0
|
|
50
45
|
_DEFAULT_DISPENSE_CLEARANCE = 1.0
|
|
@@ -222,8 +217,9 @@ class InstrumentContext(publisher.CommandPublisher):
|
|
|
222
217
|
)
|
|
223
218
|
)
|
|
224
219
|
|
|
225
|
-
well: Optional[labware.Well] = None
|
|
226
220
|
move_to_location: types.Location
|
|
221
|
+
well: Optional[labware.Well] = None
|
|
222
|
+
is_meniscus: Optional[bool] = None
|
|
227
223
|
last_location = self._get_last_location_by_api_version()
|
|
228
224
|
try:
|
|
229
225
|
target = validation.validate_location(
|
|
@@ -237,17 +233,13 @@ class InstrumentContext(publisher.CommandPublisher):
|
|
|
237
233
|
"knows where it is."
|
|
238
234
|
) from e
|
|
239
235
|
|
|
240
|
-
if isinstance(target, validation.WellTarget):
|
|
241
|
-
move_to_location = target.location or target.well.bottom(
|
|
242
|
-
z=self._well_bottom_clearances.aspirate
|
|
243
|
-
)
|
|
244
|
-
well = target.well
|
|
245
|
-
if isinstance(target, validation.PointTarget):
|
|
246
|
-
move_to_location = target.location
|
|
247
236
|
if isinstance(target, (TrashBin, WasteChute)):
|
|
248
237
|
raise ValueError(
|
|
249
238
|
"Trash Bin and Waste Chute are not acceptable location parameters for Aspirate commands."
|
|
250
239
|
)
|
|
240
|
+
move_to_location, well, is_meniscus = self._handle_aspirate_target(
|
|
241
|
+
target=target
|
|
242
|
+
)
|
|
251
243
|
if self.api_version >= APIVersion(2, 11):
|
|
252
244
|
instrument.validate_takes_liquid(
|
|
253
245
|
location=move_to_location,
|
|
@@ -287,6 +279,7 @@ class InstrumentContext(publisher.CommandPublisher):
|
|
|
287
279
|
rate=rate,
|
|
288
280
|
flow_rate=flow_rate,
|
|
289
281
|
in_place=target.in_place,
|
|
282
|
+
is_meniscus=is_meniscus,
|
|
290
283
|
)
|
|
291
284
|
|
|
292
285
|
return self
|
|
@@ -389,6 +382,7 @@ class InstrumentContext(publisher.CommandPublisher):
|
|
|
389
382
|
)
|
|
390
383
|
)
|
|
391
384
|
well: Optional[labware.Well] = None
|
|
385
|
+
is_meniscus: Optional[bool] = None
|
|
392
386
|
last_location = self._get_last_location_by_api_version()
|
|
393
387
|
|
|
394
388
|
try:
|
|
@@ -407,6 +401,7 @@ class InstrumentContext(publisher.CommandPublisher):
|
|
|
407
401
|
well = target.well
|
|
408
402
|
if target.location:
|
|
409
403
|
move_to_location = target.location
|
|
404
|
+
is_meniscus = target.location.is_meniscus
|
|
410
405
|
elif well.parent._core.is_fixed_trash():
|
|
411
406
|
move_to_location = target.well.top()
|
|
412
407
|
else:
|
|
@@ -472,6 +467,7 @@ class InstrumentContext(publisher.CommandPublisher):
|
|
|
472
467
|
flow_rate=flow_rate,
|
|
473
468
|
in_place=target.in_place,
|
|
474
469
|
push_out=push_out,
|
|
470
|
+
is_meniscus=is_meniscus,
|
|
475
471
|
)
|
|
476
472
|
|
|
477
473
|
return self
|
|
@@ -545,12 +541,12 @@ class InstrumentContext(publisher.CommandPublisher):
|
|
|
545
541
|
),
|
|
546
542
|
):
|
|
547
543
|
self.aspirate(volume, location, rate)
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
544
|
+
with AutoProbeDisable(self):
|
|
545
|
+
while repetitions - 1 > 0:
|
|
546
|
+
self.dispense(volume, rate=rate, **dispense_kwargs)
|
|
547
|
+
self.aspirate(volume, rate=rate)
|
|
548
|
+
repetitions -= 1
|
|
549
|
+
self.dispense(volume, rate=rate)
|
|
554
550
|
return self
|
|
555
551
|
|
|
556
552
|
@requires_version(2, 0)
|
|
@@ -2196,6 +2192,42 @@ class InstrumentContext(publisher.CommandPublisher):
|
|
|
2196
2192
|
)
|
|
2197
2193
|
# SINGLE, QUADRANT and ALL are supported by all pipettes
|
|
2198
2194
|
|
|
2195
|
+
def _handle_aspirate_target(
|
|
2196
|
+
self, target: validation.ValidTarget
|
|
2197
|
+
) -> tuple[types.Location, Optional[labware.Well], Optional[bool]]:
|
|
2198
|
+
move_to_location: types.Location
|
|
2199
|
+
well: Optional[labware.Well] = None
|
|
2200
|
+
is_meniscus: Optional[bool] = None
|
|
2201
|
+
if isinstance(target, validation.WellTarget):
|
|
2202
|
+
well = target.well
|
|
2203
|
+
if target.location:
|
|
2204
|
+
move_to_location = target.location
|
|
2205
|
+
is_meniscus = target.location.is_meniscus
|
|
2206
|
+
|
|
2207
|
+
else:
|
|
2208
|
+
move_to_location = target.well.bottom(
|
|
2209
|
+
z=self._well_bottom_clearances.aspirate
|
|
2210
|
+
)
|
|
2211
|
+
if isinstance(target, validation.PointTarget):
|
|
2212
|
+
move_to_location = target.location
|
|
2213
|
+
return (move_to_location, well, is_meniscus)
|
|
2214
|
+
|
|
2215
|
+
|
|
2216
|
+
class AutoProbeDisable:
|
|
2217
|
+
"""Use this class to temporarily disable automatic liquid presence detection."""
|
|
2218
|
+
|
|
2219
|
+
def __init__(self, instrument: InstrumentContext):
|
|
2220
|
+
self.instrument = instrument
|
|
2221
|
+
|
|
2222
|
+
def __enter__(self) -> None:
|
|
2223
|
+
if self.instrument.api_version >= APIVersion(2, 21):
|
|
2224
|
+
self.auto_presence = self.instrument.liquid_presence_detection
|
|
2225
|
+
self.instrument.liquid_presence_detection = False
|
|
2226
|
+
|
|
2227
|
+
def __exit__(self, *args: Any, **kwargs: Any) -> None:
|
|
2228
|
+
if self.instrument.api_version >= APIVersion(2, 21):
|
|
2229
|
+
self.instrument.liquid_presence_detection = self.auto_presence
|
|
2230
|
+
|
|
2199
2231
|
|
|
2200
2232
|
def _raise_if_has_end_or_front_right_or_back_left(
|
|
2201
2233
|
style: NozzleLayout,
|
|
@@ -30,7 +30,6 @@ from opentrons.hardware_control.nozzle_manager import NozzleMap
|
|
|
30
30
|
# remove when their usage is no longer needed
|
|
31
31
|
from opentrons.protocols.labware import ( # noqa: F401
|
|
32
32
|
get_labware_definition as get_labware_definition,
|
|
33
|
-
get_all_labware_definitions as get_all_labware_definitions,
|
|
34
33
|
verify_definition as verify_definition,
|
|
35
34
|
save_definition as save_definition,
|
|
36
35
|
)
|
|
@@ -222,6 +221,19 @@ class Well:
|
|
|
222
221
|
"""
|
|
223
222
|
return Location(self._core.get_center(), self)
|
|
224
223
|
|
|
224
|
+
@requires_version(2, 21)
|
|
225
|
+
def meniscus(self, z: float = 0.0) -> Location:
|
|
226
|
+
"""
|
|
227
|
+
:param z: An offset on the z-axis, in mm. Positive offsets are higher and
|
|
228
|
+
negative offsets are lower.
|
|
229
|
+
:return: A :py:class:`~opentrons.types.Location` that indicates location is meniscus and that holds the ``z`` offset in its point.z field.
|
|
230
|
+
|
|
231
|
+
:meta private:
|
|
232
|
+
"""
|
|
233
|
+
return Location(
|
|
234
|
+
point=Point(x=0, y=0, z=z), labware=self, _ot_internal_is_meniscus=True
|
|
235
|
+
)
|
|
236
|
+
|
|
225
237
|
@requires_version(2, 8)
|
|
226
238
|
def from_center_cartesian(self, x: float, y: float, z: float) -> Point:
|
|
227
239
|
"""
|
|
@@ -1,16 +1,18 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
import logging
|
|
4
|
-
from typing import List, Optional, Union, cast
|
|
4
|
+
from typing import List, Dict, Optional, Union, cast
|
|
5
5
|
|
|
6
|
+
from opentrons_shared_data.errors.exceptions import CommandPreconditionViolated
|
|
7
|
+
|
|
8
|
+
from opentrons.protocol_engine.types import ABSMeasureMode
|
|
6
9
|
from opentrons_shared_data.labware.types import LabwareDefinition
|
|
7
10
|
from opentrons_shared_data.module.types import ModuleModel, ModuleType
|
|
8
11
|
|
|
9
12
|
from opentrons.legacy_broker import LegacyBroker
|
|
10
|
-
from opentrons.hardware_control.modules import ThermocyclerStep
|
|
11
13
|
from opentrons.legacy_commands import module_commands as cmds
|
|
12
14
|
from opentrons.legacy_commands.publisher import CommandPublisher, publish
|
|
13
|
-
from opentrons.protocols.api_support.types import APIVersion
|
|
15
|
+
from opentrons.protocols.api_support.types import APIVersion, ThermocyclerStep
|
|
14
16
|
from opentrons.protocols.api_support.util import (
|
|
15
17
|
APIVersionError,
|
|
16
18
|
requires_version,
|
|
@@ -159,7 +161,18 @@ class ModuleContext(CommandPublisher):
|
|
|
159
161
|
load_location = loaded_adapter._core
|
|
160
162
|
else:
|
|
161
163
|
load_location = self._core
|
|
164
|
+
|
|
162
165
|
name = validation.ensure_lowercase_name(name)
|
|
166
|
+
|
|
167
|
+
# todo(mm, 2024-11-08): This check belongs in opentrons.protocol_api.core.engine.deck_conflict.
|
|
168
|
+
# We're currently doing it here, at the ModuleContext level, for consistency with what
|
|
169
|
+
# ProtocolContext.load_labware() does. (It should also be moved to the deck_conflict module.)
|
|
170
|
+
if isinstance(self._core, AbsorbanceReaderCore):
|
|
171
|
+
if self._core.is_lid_on():
|
|
172
|
+
raise CommandPreconditionViolated(
|
|
173
|
+
f"Cannot load {name} onto the Absorbance Reader Module when its lid is closed."
|
|
174
|
+
)
|
|
175
|
+
|
|
163
176
|
labware_core = self._protocol_core.load_labware(
|
|
164
177
|
load_name=name,
|
|
165
178
|
label=label,
|
|
@@ -568,7 +581,7 @@ class ThermocyclerContext(ModuleContext):
|
|
|
568
581
|
individual well of the loaded labware, in µL.
|
|
569
582
|
If not specified, the default is 25 µL.
|
|
570
583
|
|
|
571
|
-
.. note
|
|
584
|
+
.. note::
|
|
572
585
|
|
|
573
586
|
If ``hold_time_minutes`` and ``hold_time_seconds`` are not
|
|
574
587
|
specified, the Thermocycler will proceed to the next command
|
|
@@ -592,7 +605,7 @@ class ThermocyclerContext(ModuleContext):
|
|
|
592
605
|
:param temperature: A value between 37 and 110, representing the target
|
|
593
606
|
temperature in °C.
|
|
594
607
|
|
|
595
|
-
.. note
|
|
608
|
+
.. note::
|
|
596
609
|
|
|
597
610
|
The Thermocycler will proceed to the next command immediately after
|
|
598
611
|
``temperature`` has been reached.
|
|
@@ -622,12 +635,19 @@ class ThermocyclerContext(ModuleContext):
|
|
|
622
635
|
individual well of the loaded labware, in µL.
|
|
623
636
|
If not specified, the default is 25 µL.
|
|
624
637
|
|
|
625
|
-
.. note
|
|
638
|
+
.. note::
|
|
626
639
|
|
|
627
640
|
Unlike with :py:meth:`set_block_temperature`, either or both of
|
|
628
641
|
``hold_time_minutes`` and ``hold_time_seconds`` must be defined
|
|
629
642
|
and for each step.
|
|
630
643
|
|
|
644
|
+
.. note::
|
|
645
|
+
|
|
646
|
+
Before API Version 2.21, Thermocycler profiles run with this command
|
|
647
|
+
would be listed in the app as having a number of repetitions equal to
|
|
648
|
+
their step count. At or above API Version 2.21, the structure of the
|
|
649
|
+
Thermocycler cycles is preserved.
|
|
650
|
+
|
|
631
651
|
"""
|
|
632
652
|
repetitions = validation.ensure_thermocycler_repetition_count(repetitions)
|
|
633
653
|
validated_steps = validation.ensure_thermocycler_profile_steps(steps)
|
|
@@ -971,28 +991,106 @@ class MagneticBlockContext(ModuleContext):
|
|
|
971
991
|
|
|
972
992
|
|
|
973
993
|
class AbsorbanceReaderContext(ModuleContext):
|
|
974
|
-
"""An object representing a connected Absorbance Reader Module.
|
|
994
|
+
"""An object representing a connected Absorbance Plate Reader Module.
|
|
975
995
|
|
|
976
996
|
It should not be instantiated directly; instead, it should be
|
|
977
997
|
created through :py:meth:`.ProtocolContext.load_module`.
|
|
978
998
|
|
|
979
|
-
.. versionadded:: 2.
|
|
999
|
+
.. versionadded:: 2.21
|
|
980
1000
|
"""
|
|
981
1001
|
|
|
982
1002
|
_core: AbsorbanceReaderCore
|
|
983
1003
|
|
|
984
1004
|
@property
|
|
985
|
-
@requires_version(2,
|
|
1005
|
+
@requires_version(2, 21)
|
|
986
1006
|
def serial_number(self) -> str:
|
|
987
1007
|
"""Get the module's unique hardware serial number."""
|
|
988
1008
|
return self._core.get_serial_number()
|
|
989
1009
|
|
|
990
|
-
@requires_version(2,
|
|
991
|
-
def
|
|
992
|
-
"""
|
|
993
|
-
|
|
1010
|
+
@requires_version(2, 21)
|
|
1011
|
+
def close_lid(self) -> None:
|
|
1012
|
+
"""Use the Flex Gripper to close the lid of the Absorbance Plate Reader.
|
|
1013
|
+
|
|
1014
|
+
You must call this method before initializing the reader, even if the reader was
|
|
1015
|
+
in the closed position at the start of the protocol.
|
|
1016
|
+
"""
|
|
1017
|
+
self._core.close_lid()
|
|
1018
|
+
|
|
1019
|
+
@requires_version(2, 21)
|
|
1020
|
+
def open_lid(self) -> None:
|
|
1021
|
+
"""Use the Flex Gripper to open the lid of the Absorbance Plate Reader."""
|
|
1022
|
+
self._core.open_lid()
|
|
1023
|
+
|
|
1024
|
+
@requires_version(2, 21)
|
|
1025
|
+
def is_lid_on(self) -> bool:
|
|
1026
|
+
"""Return ``True`` if the Absorbance Plate Reader's lid is currently closed."""
|
|
1027
|
+
return self._core.is_lid_on()
|
|
994
1028
|
|
|
995
|
-
@requires_version(2,
|
|
996
|
-
def
|
|
997
|
-
|
|
998
|
-
|
|
1029
|
+
@requires_version(2, 21)
|
|
1030
|
+
def initialize(
|
|
1031
|
+
self,
|
|
1032
|
+
mode: ABSMeasureMode,
|
|
1033
|
+
wavelengths: List[int],
|
|
1034
|
+
reference_wavelength: Optional[int] = None,
|
|
1035
|
+
) -> None:
|
|
1036
|
+
"""Prepare the Absorbance Plate Reader to read a plate.
|
|
1037
|
+
|
|
1038
|
+
See :ref:`absorbance-initialization` for examples.
|
|
1039
|
+
|
|
1040
|
+
:param mode: Either ``"single"`` or ``"multi"``.
|
|
1041
|
+
|
|
1042
|
+
- In single measurement mode, :py:meth:`.AbsorbanceReaderContext.read` uses
|
|
1043
|
+
one sample wavelength and an optional reference wavelength.
|
|
1044
|
+
- In multiple measurement mode, :py:meth:`.AbsorbanceReaderContext.read` uses
|
|
1045
|
+
a list of up to six sample wavelengths.
|
|
1046
|
+
:param wavelengths: A list of wavelengths, in nm, to measure.
|
|
1047
|
+
|
|
1048
|
+
- In the default hardware configuration, each wavelength must be one of
|
|
1049
|
+
``450`` (blue), ``562`` (green), ``600`` (orange), or ``650`` (red). In
|
|
1050
|
+
custom hardware configurations, the module may accept other integers
|
|
1051
|
+
between 350 and 1000.
|
|
1052
|
+
- The list must contain only one item when initializing a single measurement.
|
|
1053
|
+
- The list can contain one to six items when initializing a multiple measurement.
|
|
1054
|
+
:param reference_wavelength: An optional reference wavelength, in nm. If provided,
|
|
1055
|
+
:py:meth:`.AbsorbanceReaderContext.read` will read at the reference
|
|
1056
|
+
wavelength and then subtract the reference wavelength values from the
|
|
1057
|
+
measurement wavelength values. Can only be used with single measurements.
|
|
1058
|
+
"""
|
|
1059
|
+
self._core.initialize(
|
|
1060
|
+
mode, wavelengths, reference_wavelength=reference_wavelength
|
|
1061
|
+
)
|
|
1062
|
+
|
|
1063
|
+
@requires_version(2, 21)
|
|
1064
|
+
def read(
|
|
1065
|
+
self, export_filename: Optional[str] = None
|
|
1066
|
+
) -> Dict[int, Dict[str, float]]:
|
|
1067
|
+
"""Read a plate on the Absorbance Plate Reader.
|
|
1068
|
+
|
|
1069
|
+
This method always returns a dictionary of measurement data. It optionally will
|
|
1070
|
+
save a CSV file of the results to the Flex filesystem, which you can access from
|
|
1071
|
+
the Recent Protocol Runs screen in the Opentrons App. These files are `only` saved
|
|
1072
|
+
if you specify ``export_filename``.
|
|
1073
|
+
|
|
1074
|
+
In simulation, the values for each well key in the dictionary are set to zero, and
|
|
1075
|
+
no files are written.
|
|
1076
|
+
|
|
1077
|
+
.. note::
|
|
1078
|
+
|
|
1079
|
+
Avoid divide-by-zero errors when simulating and using the results of this
|
|
1080
|
+
method later in the protocol. If you divide by any of the measurement
|
|
1081
|
+
values, use :py:meth:`.ProtocolContext.is_simulating` to use alternate dummy
|
|
1082
|
+
data or skip the division step.
|
|
1083
|
+
|
|
1084
|
+
:param export_filename: An optional file basename. If provided, this method
|
|
1085
|
+
will write a CSV file for each measurement in the read operation. File
|
|
1086
|
+
names will use the value of this parameter, the measurement wavelength
|
|
1087
|
+
supplied in :py:meth:`~.AbsorbanceReaderContext.initialize`, and a
|
|
1088
|
+
``.csv`` extension. For example, when reading at wavelengths 450 and 562
|
|
1089
|
+
with ``export_filename="my_data"``, there will be two output files:
|
|
1090
|
+
``my_data_450.csv`` and ``my_data_562.csv``.
|
|
1091
|
+
|
|
1092
|
+
See :ref:`absorbance-csv` for information on working with these CSV files.
|
|
1093
|
+
|
|
1094
|
+
:returns: A dictionary of wavelengths to dictionary of values ordered by well name.
|
|
1095
|
+
"""
|
|
1096
|
+
return self._core.read(filename=export_filename)
|