opentrons 8.6.0__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/__init__.py +150 -0
- opentrons/_version.py +34 -0
- opentrons/calibration_storage/__init__.py +54 -0
- opentrons/calibration_storage/deck_configuration.py +62 -0
- opentrons/calibration_storage/encoder_decoder.py +31 -0
- opentrons/calibration_storage/file_operators.py +142 -0
- opentrons/calibration_storage/helpers.py +103 -0
- opentrons/calibration_storage/ot2/__init__.py +34 -0
- opentrons/calibration_storage/ot2/deck_attitude.py +85 -0
- opentrons/calibration_storage/ot2/mark_bad_calibration.py +27 -0
- opentrons/calibration_storage/ot2/models/__init__.py +0 -0
- opentrons/calibration_storage/ot2/models/v1.py +149 -0
- opentrons/calibration_storage/ot2/pipette_offset.py +129 -0
- opentrons/calibration_storage/ot2/tip_length.py +281 -0
- opentrons/calibration_storage/ot3/__init__.py +31 -0
- opentrons/calibration_storage/ot3/deck_attitude.py +83 -0
- opentrons/calibration_storage/ot3/gripper_offset.py +156 -0
- opentrons/calibration_storage/ot3/models/__init__.py +0 -0
- opentrons/calibration_storage/ot3/models/v1.py +122 -0
- opentrons/calibration_storage/ot3/module_offset.py +138 -0
- opentrons/calibration_storage/ot3/pipette_offset.py +95 -0
- opentrons/calibration_storage/types.py +45 -0
- opentrons/cli/__init__.py +21 -0
- opentrons/cli/__main__.py +5 -0
- opentrons/cli/analyze.py +557 -0
- opentrons/config/__init__.py +631 -0
- opentrons/config/advanced_settings.py +871 -0
- opentrons/config/defaults_ot2.py +214 -0
- opentrons/config/defaults_ot3.py +499 -0
- opentrons/config/feature_flags.py +86 -0
- opentrons/config/gripper_config.py +55 -0
- opentrons/config/reset.py +203 -0
- opentrons/config/robot_configs.py +187 -0
- opentrons/config/types.py +183 -0
- opentrons/drivers/__init__.py +0 -0
- opentrons/drivers/absorbance_reader/__init__.py +11 -0
- opentrons/drivers/absorbance_reader/abstract.py +72 -0
- opentrons/drivers/absorbance_reader/async_byonoy.py +352 -0
- opentrons/drivers/absorbance_reader/driver.py +81 -0
- opentrons/drivers/absorbance_reader/hid_protocol.py +161 -0
- opentrons/drivers/absorbance_reader/simulator.py +84 -0
- opentrons/drivers/asyncio/__init__.py +0 -0
- opentrons/drivers/asyncio/communication/__init__.py +22 -0
- opentrons/drivers/asyncio/communication/async_serial.py +187 -0
- opentrons/drivers/asyncio/communication/errors.py +88 -0
- opentrons/drivers/asyncio/communication/serial_connection.py +557 -0
- opentrons/drivers/command_builder.py +102 -0
- opentrons/drivers/flex_stacker/__init__.py +13 -0
- opentrons/drivers/flex_stacker/abstract.py +214 -0
- opentrons/drivers/flex_stacker/driver.py +768 -0
- opentrons/drivers/flex_stacker/errors.py +68 -0
- opentrons/drivers/flex_stacker/simulator.py +309 -0
- opentrons/drivers/flex_stacker/types.py +367 -0
- opentrons/drivers/flex_stacker/utils.py +19 -0
- opentrons/drivers/heater_shaker/__init__.py +5 -0
- opentrons/drivers/heater_shaker/abstract.py +76 -0
- opentrons/drivers/heater_shaker/driver.py +204 -0
- opentrons/drivers/heater_shaker/simulator.py +94 -0
- opentrons/drivers/mag_deck/__init__.py +6 -0
- opentrons/drivers/mag_deck/abstract.py +44 -0
- opentrons/drivers/mag_deck/driver.py +208 -0
- opentrons/drivers/mag_deck/simulator.py +63 -0
- opentrons/drivers/rpi_drivers/__init__.py +33 -0
- opentrons/drivers/rpi_drivers/dev_types.py +94 -0
- opentrons/drivers/rpi_drivers/gpio.py +282 -0
- opentrons/drivers/rpi_drivers/gpio_simulator.py +127 -0
- opentrons/drivers/rpi_drivers/interfaces.py +15 -0
- opentrons/drivers/rpi_drivers/types.py +364 -0
- opentrons/drivers/rpi_drivers/usb.py +102 -0
- opentrons/drivers/rpi_drivers/usb_simulator.py +22 -0
- opentrons/drivers/serial_communication.py +151 -0
- opentrons/drivers/smoothie_drivers/__init__.py +4 -0
- opentrons/drivers/smoothie_drivers/connection.py +51 -0
- opentrons/drivers/smoothie_drivers/constants.py +121 -0
- opentrons/drivers/smoothie_drivers/driver_3_0.py +1933 -0
- opentrons/drivers/smoothie_drivers/errors.py +49 -0
- opentrons/drivers/smoothie_drivers/parse_utils.py +143 -0
- opentrons/drivers/smoothie_drivers/simulator.py +99 -0
- opentrons/drivers/smoothie_drivers/types.py +16 -0
- opentrons/drivers/temp_deck/__init__.py +10 -0
- opentrons/drivers/temp_deck/abstract.py +54 -0
- opentrons/drivers/temp_deck/driver.py +197 -0
- opentrons/drivers/temp_deck/simulator.py +57 -0
- opentrons/drivers/thermocycler/__init__.py +12 -0
- opentrons/drivers/thermocycler/abstract.py +99 -0
- opentrons/drivers/thermocycler/driver.py +395 -0
- opentrons/drivers/thermocycler/simulator.py +126 -0
- opentrons/drivers/types.py +107 -0
- opentrons/drivers/utils.py +222 -0
- opentrons/execute.py +742 -0
- opentrons/hardware_control/__init__.py +65 -0
- opentrons/hardware_control/__main__.py +77 -0
- opentrons/hardware_control/adapters.py +98 -0
- opentrons/hardware_control/api.py +1347 -0
- opentrons/hardware_control/backends/__init__.py +7 -0
- opentrons/hardware_control/backends/controller.py +400 -0
- opentrons/hardware_control/backends/errors.py +9 -0
- opentrons/hardware_control/backends/estop_state.py +164 -0
- opentrons/hardware_control/backends/flex_protocol.py +497 -0
- opentrons/hardware_control/backends/ot3controller.py +1930 -0
- opentrons/hardware_control/backends/ot3simulator.py +900 -0
- opentrons/hardware_control/backends/ot3utils.py +664 -0
- opentrons/hardware_control/backends/simulator.py +442 -0
- opentrons/hardware_control/backends/status_bar_state.py +240 -0
- opentrons/hardware_control/backends/subsystem_manager.py +431 -0
- opentrons/hardware_control/backends/tip_presence_manager.py +173 -0
- opentrons/hardware_control/backends/types.py +14 -0
- opentrons/hardware_control/constants.py +6 -0
- opentrons/hardware_control/dev_types.py +125 -0
- opentrons/hardware_control/emulation/__init__.py +0 -0
- opentrons/hardware_control/emulation/abstract_emulator.py +21 -0
- opentrons/hardware_control/emulation/app.py +56 -0
- opentrons/hardware_control/emulation/connection_handler.py +38 -0
- opentrons/hardware_control/emulation/heater_shaker.py +150 -0
- opentrons/hardware_control/emulation/magdeck.py +60 -0
- opentrons/hardware_control/emulation/module_server/__init__.py +8 -0
- opentrons/hardware_control/emulation/module_server/client.py +78 -0
- opentrons/hardware_control/emulation/module_server/helpers.py +130 -0
- opentrons/hardware_control/emulation/module_server/models.py +31 -0
- opentrons/hardware_control/emulation/module_server/server.py +110 -0
- opentrons/hardware_control/emulation/parser.py +74 -0
- opentrons/hardware_control/emulation/proxy.py +241 -0
- opentrons/hardware_control/emulation/run_emulator.py +68 -0
- opentrons/hardware_control/emulation/scripts/__init__.py +0 -0
- opentrons/hardware_control/emulation/scripts/run_app.py +54 -0
- opentrons/hardware_control/emulation/scripts/run_module_emulator.py +72 -0
- opentrons/hardware_control/emulation/scripts/run_smoothie.py +37 -0
- opentrons/hardware_control/emulation/settings.py +119 -0
- opentrons/hardware_control/emulation/simulations.py +133 -0
- opentrons/hardware_control/emulation/smoothie.py +192 -0
- opentrons/hardware_control/emulation/tempdeck.py +69 -0
- opentrons/hardware_control/emulation/thermocycler.py +128 -0
- opentrons/hardware_control/emulation/types.py +10 -0
- opentrons/hardware_control/emulation/util.py +38 -0
- opentrons/hardware_control/errors.py +43 -0
- opentrons/hardware_control/execution_manager.py +164 -0
- opentrons/hardware_control/instruments/__init__.py +5 -0
- opentrons/hardware_control/instruments/instrument_abc.py +39 -0
- opentrons/hardware_control/instruments/ot2/__init__.py +0 -0
- opentrons/hardware_control/instruments/ot2/instrument_calibration.py +152 -0
- opentrons/hardware_control/instruments/ot2/pipette.py +777 -0
- opentrons/hardware_control/instruments/ot2/pipette_handler.py +995 -0
- opentrons/hardware_control/instruments/ot3/__init__.py +0 -0
- opentrons/hardware_control/instruments/ot3/gripper.py +420 -0
- opentrons/hardware_control/instruments/ot3/gripper_handler.py +173 -0
- opentrons/hardware_control/instruments/ot3/instrument_calibration.py +214 -0
- opentrons/hardware_control/instruments/ot3/pipette.py +858 -0
- opentrons/hardware_control/instruments/ot3/pipette_handler.py +1030 -0
- opentrons/hardware_control/module_control.py +332 -0
- opentrons/hardware_control/modules/__init__.py +69 -0
- opentrons/hardware_control/modules/absorbance_reader.py +373 -0
- opentrons/hardware_control/modules/errors.py +7 -0
- opentrons/hardware_control/modules/flex_stacker.py +948 -0
- opentrons/hardware_control/modules/heater_shaker.py +426 -0
- opentrons/hardware_control/modules/lid_temp_status.py +35 -0
- opentrons/hardware_control/modules/magdeck.py +233 -0
- opentrons/hardware_control/modules/mod_abc.py +245 -0
- opentrons/hardware_control/modules/module_calibration.py +93 -0
- opentrons/hardware_control/modules/plate_temp_status.py +61 -0
- opentrons/hardware_control/modules/tempdeck.py +299 -0
- opentrons/hardware_control/modules/thermocycler.py +731 -0
- opentrons/hardware_control/modules/types.py +417 -0
- opentrons/hardware_control/modules/update.py +255 -0
- opentrons/hardware_control/modules/utils.py +73 -0
- opentrons/hardware_control/motion_utilities.py +318 -0
- opentrons/hardware_control/nozzle_manager.py +422 -0
- opentrons/hardware_control/ot3_calibration.py +1171 -0
- opentrons/hardware_control/ot3api.py +3227 -0
- opentrons/hardware_control/pause_manager.py +31 -0
- opentrons/hardware_control/poller.py +112 -0
- opentrons/hardware_control/protocols/__init__.py +106 -0
- opentrons/hardware_control/protocols/asyncio_configurable.py +11 -0
- opentrons/hardware_control/protocols/calibratable.py +45 -0
- opentrons/hardware_control/protocols/chassis_accessory_manager.py +90 -0
- opentrons/hardware_control/protocols/configurable.py +48 -0
- opentrons/hardware_control/protocols/event_sourcer.py +18 -0
- opentrons/hardware_control/protocols/execution_controllable.py +33 -0
- opentrons/hardware_control/protocols/flex_calibratable.py +96 -0
- opentrons/hardware_control/protocols/flex_instrument_configurer.py +52 -0
- opentrons/hardware_control/protocols/gripper_controller.py +55 -0
- opentrons/hardware_control/protocols/hardware_manager.py +51 -0
- opentrons/hardware_control/protocols/identifiable.py +16 -0
- opentrons/hardware_control/protocols/instrument_configurer.py +206 -0
- opentrons/hardware_control/protocols/liquid_handler.py +266 -0
- opentrons/hardware_control/protocols/module_provider.py +16 -0
- opentrons/hardware_control/protocols/motion_controller.py +243 -0
- opentrons/hardware_control/protocols/position_estimator.py +45 -0
- opentrons/hardware_control/protocols/simulatable.py +10 -0
- opentrons/hardware_control/protocols/stoppable.py +9 -0
- opentrons/hardware_control/protocols/types.py +27 -0
- opentrons/hardware_control/robot_calibration.py +224 -0
- opentrons/hardware_control/scripts/README.md +28 -0
- opentrons/hardware_control/scripts/__init__.py +1 -0
- opentrons/hardware_control/scripts/gripper_control.py +208 -0
- opentrons/hardware_control/scripts/ot3gripper +7 -0
- opentrons/hardware_control/scripts/ot3repl +7 -0
- opentrons/hardware_control/scripts/repl.py +187 -0
- opentrons/hardware_control/scripts/tc_control.py +97 -0
- opentrons/hardware_control/scripts/update_module_fw.py +274 -0
- opentrons/hardware_control/simulator_setup.py +260 -0
- opentrons/hardware_control/thread_manager.py +431 -0
- opentrons/hardware_control/threaded_async_lock.py +97 -0
- opentrons/hardware_control/types.py +792 -0
- opentrons/hardware_control/util.py +234 -0
- opentrons/legacy_broker.py +53 -0
- opentrons/legacy_commands/__init__.py +1 -0
- opentrons/legacy_commands/commands.py +483 -0
- opentrons/legacy_commands/helpers.py +153 -0
- opentrons/legacy_commands/module_commands.py +276 -0
- opentrons/legacy_commands/protocol_commands.py +54 -0
- opentrons/legacy_commands/publisher.py +155 -0
- opentrons/legacy_commands/robot_commands.py +51 -0
- opentrons/legacy_commands/types.py +1186 -0
- opentrons/motion_planning/__init__.py +32 -0
- opentrons/motion_planning/adjacent_slots_getters.py +168 -0
- opentrons/motion_planning/deck_conflict.py +501 -0
- opentrons/motion_planning/errors.py +35 -0
- opentrons/motion_planning/types.py +42 -0
- opentrons/motion_planning/waypoints.py +218 -0
- opentrons/ordered_set.py +138 -0
- opentrons/protocol_api/__init__.py +105 -0
- opentrons/protocol_api/_liquid.py +157 -0
- opentrons/protocol_api/_liquid_properties.py +814 -0
- opentrons/protocol_api/_nozzle_layout.py +31 -0
- opentrons/protocol_api/_parameter_context.py +300 -0
- opentrons/protocol_api/_parameters.py +31 -0
- opentrons/protocol_api/_transfer_liquid_validation.py +108 -0
- opentrons/protocol_api/_types.py +43 -0
- opentrons/protocol_api/config.py +23 -0
- opentrons/protocol_api/core/__init__.py +23 -0
- opentrons/protocol_api/core/common.py +33 -0
- opentrons/protocol_api/core/core_map.py +74 -0
- opentrons/protocol_api/core/engine/__init__.py +22 -0
- opentrons/protocol_api/core/engine/_default_labware_versions.py +179 -0
- opentrons/protocol_api/core/engine/deck_conflict.py +400 -0
- opentrons/protocol_api/core/engine/exceptions.py +19 -0
- opentrons/protocol_api/core/engine/instrument.py +2391 -0
- opentrons/protocol_api/core/engine/labware.py +238 -0
- opentrons/protocol_api/core/engine/load_labware_params.py +73 -0
- opentrons/protocol_api/core/engine/module_core.py +1027 -0
- opentrons/protocol_api/core/engine/overlap_versions.py +20 -0
- opentrons/protocol_api/core/engine/pipette_movement_conflict.py +358 -0
- opentrons/protocol_api/core/engine/point_calculations.py +64 -0
- opentrons/protocol_api/core/engine/protocol.py +1153 -0
- opentrons/protocol_api/core/engine/robot.py +139 -0
- opentrons/protocol_api/core/engine/stringify.py +74 -0
- opentrons/protocol_api/core/engine/transfer_components_executor.py +1006 -0
- opentrons/protocol_api/core/engine/well.py +241 -0
- opentrons/protocol_api/core/instrument.py +459 -0
- opentrons/protocol_api/core/labware.py +151 -0
- opentrons/protocol_api/core/legacy/__init__.py +11 -0
- opentrons/protocol_api/core/legacy/_labware_geometry.py +37 -0
- opentrons/protocol_api/core/legacy/deck.py +369 -0
- opentrons/protocol_api/core/legacy/labware_offset_provider.py +108 -0
- opentrons/protocol_api/core/legacy/legacy_instrument_core.py +709 -0
- opentrons/protocol_api/core/legacy/legacy_labware_core.py +235 -0
- opentrons/protocol_api/core/legacy/legacy_module_core.py +592 -0
- opentrons/protocol_api/core/legacy/legacy_protocol_core.py +612 -0
- opentrons/protocol_api/core/legacy/legacy_well_core.py +162 -0
- opentrons/protocol_api/core/legacy/load_info.py +67 -0
- opentrons/protocol_api/core/legacy/module_geometry.py +547 -0
- opentrons/protocol_api/core/legacy/well_geometry.py +148 -0
- opentrons/protocol_api/core/legacy_simulator/__init__.py +16 -0
- opentrons/protocol_api/core/legacy_simulator/legacy_instrument_core.py +624 -0
- opentrons/protocol_api/core/legacy_simulator/legacy_protocol_core.py +85 -0
- opentrons/protocol_api/core/module.py +484 -0
- opentrons/protocol_api/core/protocol.py +311 -0
- opentrons/protocol_api/core/robot.py +51 -0
- opentrons/protocol_api/core/well.py +116 -0
- opentrons/protocol_api/core/well_grid.py +45 -0
- opentrons/protocol_api/create_protocol_context.py +177 -0
- opentrons/protocol_api/deck.py +223 -0
- opentrons/protocol_api/disposal_locations.py +244 -0
- opentrons/protocol_api/instrument_context.py +3272 -0
- opentrons/protocol_api/labware.py +1579 -0
- opentrons/protocol_api/module_contexts.py +1447 -0
- opentrons/protocol_api/module_validation_and_errors.py +61 -0
- opentrons/protocol_api/protocol_context.py +1688 -0
- opentrons/protocol_api/robot_context.py +303 -0
- opentrons/protocol_api/validation.py +761 -0
- opentrons/protocol_engine/__init__.py +155 -0
- opentrons/protocol_engine/actions/__init__.py +65 -0
- opentrons/protocol_engine/actions/action_dispatcher.py +30 -0
- opentrons/protocol_engine/actions/action_handler.py +13 -0
- opentrons/protocol_engine/actions/actions.py +302 -0
- opentrons/protocol_engine/actions/get_state_update.py +38 -0
- opentrons/protocol_engine/clients/__init__.py +5 -0
- opentrons/protocol_engine/clients/sync_client.py +174 -0
- opentrons/protocol_engine/clients/transports.py +197 -0
- opentrons/protocol_engine/commands/__init__.py +757 -0
- opentrons/protocol_engine/commands/absorbance_reader/__init__.py +61 -0
- opentrons/protocol_engine/commands/absorbance_reader/close_lid.py +154 -0
- opentrons/protocol_engine/commands/absorbance_reader/common.py +6 -0
- opentrons/protocol_engine/commands/absorbance_reader/initialize.py +151 -0
- opentrons/protocol_engine/commands/absorbance_reader/open_lid.py +154 -0
- opentrons/protocol_engine/commands/absorbance_reader/read.py +226 -0
- opentrons/protocol_engine/commands/air_gap_in_place.py +162 -0
- opentrons/protocol_engine/commands/aspirate.py +244 -0
- opentrons/protocol_engine/commands/aspirate_in_place.py +184 -0
- opentrons/protocol_engine/commands/aspirate_while_tracking.py +211 -0
- opentrons/protocol_engine/commands/blow_out.py +146 -0
- opentrons/protocol_engine/commands/blow_out_in_place.py +119 -0
- opentrons/protocol_engine/commands/calibration/__init__.py +60 -0
- opentrons/protocol_engine/commands/calibration/calibrate_gripper.py +166 -0
- opentrons/protocol_engine/commands/calibration/calibrate_module.py +117 -0
- opentrons/protocol_engine/commands/calibration/calibrate_pipette.py +96 -0
- opentrons/protocol_engine/commands/calibration/move_to_maintenance_position.py +156 -0
- opentrons/protocol_engine/commands/command.py +308 -0
- opentrons/protocol_engine/commands/command_unions.py +974 -0
- opentrons/protocol_engine/commands/comment.py +57 -0
- opentrons/protocol_engine/commands/configure_for_volume.py +108 -0
- opentrons/protocol_engine/commands/configure_nozzle_layout.py +115 -0
- opentrons/protocol_engine/commands/custom.py +67 -0
- opentrons/protocol_engine/commands/dispense.py +194 -0
- opentrons/protocol_engine/commands/dispense_in_place.py +179 -0
- opentrons/protocol_engine/commands/dispense_while_tracking.py +204 -0
- opentrons/protocol_engine/commands/drop_tip.py +232 -0
- opentrons/protocol_engine/commands/drop_tip_in_place.py +205 -0
- opentrons/protocol_engine/commands/flex_stacker/__init__.py +64 -0
- opentrons/protocol_engine/commands/flex_stacker/common.py +900 -0
- opentrons/protocol_engine/commands/flex_stacker/empty.py +293 -0
- opentrons/protocol_engine/commands/flex_stacker/fill.py +281 -0
- opentrons/protocol_engine/commands/flex_stacker/retrieve.py +339 -0
- opentrons/protocol_engine/commands/flex_stacker/set_stored_labware.py +328 -0
- opentrons/protocol_engine/commands/flex_stacker/store.py +339 -0
- opentrons/protocol_engine/commands/generate_command_schema.py +61 -0
- opentrons/protocol_engine/commands/get_next_tip.py +134 -0
- opentrons/protocol_engine/commands/get_tip_presence.py +87 -0
- opentrons/protocol_engine/commands/hash_command_params.py +38 -0
- opentrons/protocol_engine/commands/heater_shaker/__init__.py +102 -0
- opentrons/protocol_engine/commands/heater_shaker/close_labware_latch.py +83 -0
- opentrons/protocol_engine/commands/heater_shaker/deactivate_heater.py +82 -0
- opentrons/protocol_engine/commands/heater_shaker/deactivate_shaker.py +84 -0
- opentrons/protocol_engine/commands/heater_shaker/open_labware_latch.py +110 -0
- opentrons/protocol_engine/commands/heater_shaker/set_and_wait_for_shake_speed.py +125 -0
- opentrons/protocol_engine/commands/heater_shaker/set_target_temperature.py +90 -0
- opentrons/protocol_engine/commands/heater_shaker/wait_for_temperature.py +102 -0
- opentrons/protocol_engine/commands/home.py +100 -0
- opentrons/protocol_engine/commands/identify_module.py +86 -0
- opentrons/protocol_engine/commands/labware_handling_common.py +29 -0
- opentrons/protocol_engine/commands/liquid_probe.py +464 -0
- opentrons/protocol_engine/commands/load_labware.py +210 -0
- opentrons/protocol_engine/commands/load_lid.py +154 -0
- opentrons/protocol_engine/commands/load_lid_stack.py +272 -0
- opentrons/protocol_engine/commands/load_liquid.py +95 -0
- opentrons/protocol_engine/commands/load_liquid_class.py +144 -0
- opentrons/protocol_engine/commands/load_module.py +223 -0
- opentrons/protocol_engine/commands/load_pipette.py +167 -0
- opentrons/protocol_engine/commands/magnetic_module/__init__.py +32 -0
- opentrons/protocol_engine/commands/magnetic_module/disengage.py +97 -0
- opentrons/protocol_engine/commands/magnetic_module/engage.py +119 -0
- opentrons/protocol_engine/commands/move_labware.py +546 -0
- opentrons/protocol_engine/commands/move_relative.py +102 -0
- opentrons/protocol_engine/commands/move_to_addressable_area.py +176 -0
- opentrons/protocol_engine/commands/move_to_addressable_area_for_drop_tip.py +198 -0
- opentrons/protocol_engine/commands/move_to_coordinates.py +107 -0
- opentrons/protocol_engine/commands/move_to_well.py +119 -0
- opentrons/protocol_engine/commands/movement_common.py +338 -0
- opentrons/protocol_engine/commands/pick_up_tip.py +241 -0
- opentrons/protocol_engine/commands/pipetting_common.py +443 -0
- opentrons/protocol_engine/commands/prepare_to_aspirate.py +121 -0
- opentrons/protocol_engine/commands/pressure_dispense.py +155 -0
- opentrons/protocol_engine/commands/reload_labware.py +90 -0
- opentrons/protocol_engine/commands/retract_axis.py +75 -0
- opentrons/protocol_engine/commands/robot/__init__.py +70 -0
- opentrons/protocol_engine/commands/robot/close_gripper_jaw.py +96 -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 +86 -0
- opentrons/protocol_engine/commands/save_position.py +109 -0
- opentrons/protocol_engine/commands/seal_pipette_to_tip.py +353 -0
- opentrons/protocol_engine/commands/set_rail_lights.py +67 -0
- opentrons/protocol_engine/commands/set_status_bar.py +89 -0
- opentrons/protocol_engine/commands/temperature_module/__init__.py +46 -0
- opentrons/protocol_engine/commands/temperature_module/deactivate.py +86 -0
- opentrons/protocol_engine/commands/temperature_module/set_target_temperature.py +97 -0
- opentrons/protocol_engine/commands/temperature_module/wait_for_temperature.py +104 -0
- opentrons/protocol_engine/commands/thermocycler/__init__.py +152 -0
- opentrons/protocol_engine/commands/thermocycler/close_lid.py +87 -0
- opentrons/protocol_engine/commands/thermocycler/deactivate_block.py +80 -0
- opentrons/protocol_engine/commands/thermocycler/deactivate_lid.py +80 -0
- opentrons/protocol_engine/commands/thermocycler/open_lid.py +87 -0
- opentrons/protocol_engine/commands/thermocycler/run_extended_profile.py +171 -0
- opentrons/protocol_engine/commands/thermocycler/run_profile.py +124 -0
- opentrons/protocol_engine/commands/thermocycler/set_target_block_temperature.py +140 -0
- opentrons/protocol_engine/commands/thermocycler/set_target_lid_temperature.py +100 -0
- opentrons/protocol_engine/commands/thermocycler/wait_for_block_temperature.py +93 -0
- opentrons/protocol_engine/commands/thermocycler/wait_for_lid_temperature.py +89 -0
- opentrons/protocol_engine/commands/touch_tip.py +189 -0
- opentrons/protocol_engine/commands/unsafe/__init__.py +161 -0
- opentrons/protocol_engine/commands/unsafe/unsafe_blow_out_in_place.py +100 -0
- opentrons/protocol_engine/commands/unsafe/unsafe_drop_tip_in_place.py +121 -0
- opentrons/protocol_engine/commands/unsafe/unsafe_engage_axes.py +82 -0
- opentrons/protocol_engine/commands/unsafe/unsafe_place_labware.py +208 -0
- opentrons/protocol_engine/commands/unsafe/unsafe_stacker_close_latch.py +94 -0
- opentrons/protocol_engine/commands/unsafe/unsafe_stacker_manual_retrieve.py +295 -0
- opentrons/protocol_engine/commands/unsafe/unsafe_stacker_open_latch.py +91 -0
- opentrons/protocol_engine/commands/unsafe/unsafe_stacker_prepare_shuttle.py +136 -0
- opentrons/protocol_engine/commands/unsafe/unsafe_ungrip_labware.py +77 -0
- opentrons/protocol_engine/commands/unsafe/update_position_estimators.py +90 -0
- opentrons/protocol_engine/commands/unseal_pipette_from_tip.py +153 -0
- opentrons/protocol_engine/commands/verify_tip_presence.py +100 -0
- opentrons/protocol_engine/commands/wait_for_duration.py +76 -0
- opentrons/protocol_engine/commands/wait_for_resume.py +75 -0
- opentrons/protocol_engine/create_protocol_engine.py +193 -0
- opentrons/protocol_engine/engine_support.py +28 -0
- opentrons/protocol_engine/error_recovery_policy.py +81 -0
- opentrons/protocol_engine/errors/__init__.py +191 -0
- opentrons/protocol_engine/errors/error_occurrence.py +182 -0
- opentrons/protocol_engine/errors/exceptions.py +1308 -0
- opentrons/protocol_engine/execution/__init__.py +50 -0
- opentrons/protocol_engine/execution/command_executor.py +216 -0
- opentrons/protocol_engine/execution/create_queue_worker.py +102 -0
- opentrons/protocol_engine/execution/door_watcher.py +119 -0
- opentrons/protocol_engine/execution/equipment.py +819 -0
- opentrons/protocol_engine/execution/error_recovery_hardware_state_synchronizer.py +101 -0
- opentrons/protocol_engine/execution/gantry_mover.py +686 -0
- opentrons/protocol_engine/execution/hardware_stopper.py +147 -0
- opentrons/protocol_engine/execution/heater_shaker_movement_flagger.py +207 -0
- opentrons/protocol_engine/execution/labware_movement.py +297 -0
- opentrons/protocol_engine/execution/movement.py +350 -0
- opentrons/protocol_engine/execution/pipetting.py +607 -0
- opentrons/protocol_engine/execution/queue_worker.py +86 -0
- opentrons/protocol_engine/execution/rail_lights.py +25 -0
- opentrons/protocol_engine/execution/run_control.py +33 -0
- opentrons/protocol_engine/execution/status_bar.py +34 -0
- opentrons/protocol_engine/execution/thermocycler_movement_flagger.py +188 -0
- opentrons/protocol_engine/execution/thermocycler_plate_lifter.py +81 -0
- opentrons/protocol_engine/execution/tip_handler.py +550 -0
- opentrons/protocol_engine/labware_offset_standardization.py +194 -0
- opentrons/protocol_engine/notes/__init__.py +17 -0
- opentrons/protocol_engine/notes/notes.py +59 -0
- opentrons/protocol_engine/plugins.py +104 -0
- opentrons/protocol_engine/protocol_engine.py +683 -0
- opentrons/protocol_engine/resources/__init__.py +26 -0
- opentrons/protocol_engine/resources/deck_configuration_provider.py +232 -0
- opentrons/protocol_engine/resources/deck_data_provider.py +94 -0
- opentrons/protocol_engine/resources/file_provider.py +161 -0
- opentrons/protocol_engine/resources/fixture_validation.py +68 -0
- opentrons/protocol_engine/resources/labware_data_provider.py +106 -0
- opentrons/protocol_engine/resources/labware_validation.py +73 -0
- opentrons/protocol_engine/resources/model_utils.py +32 -0
- opentrons/protocol_engine/resources/module_data_provider.py +44 -0
- opentrons/protocol_engine/resources/ot3_validation.py +21 -0
- opentrons/protocol_engine/resources/pipette_data_provider.py +379 -0
- opentrons/protocol_engine/slot_standardization.py +128 -0
- opentrons/protocol_engine/state/__init__.py +1 -0
- opentrons/protocol_engine/state/_abstract_store.py +27 -0
- opentrons/protocol_engine/state/_axis_aligned_bounding_box.py +50 -0
- opentrons/protocol_engine/state/_labware_origin_math.py +636 -0
- opentrons/protocol_engine/state/_move_types.py +83 -0
- opentrons/protocol_engine/state/_well_math.py +193 -0
- opentrons/protocol_engine/state/addressable_areas.py +699 -0
- opentrons/protocol_engine/state/command_history.py +309 -0
- opentrons/protocol_engine/state/commands.py +1164 -0
- opentrons/protocol_engine/state/config.py +39 -0
- opentrons/protocol_engine/state/files.py +57 -0
- opentrons/protocol_engine/state/fluid_stack.py +138 -0
- opentrons/protocol_engine/state/geometry.py +2408 -0
- opentrons/protocol_engine/state/inner_well_math_utils.py +548 -0
- opentrons/protocol_engine/state/labware.py +1432 -0
- opentrons/protocol_engine/state/liquid_classes.py +82 -0
- opentrons/protocol_engine/state/liquids.py +73 -0
- opentrons/protocol_engine/state/module_substates/__init__.py +45 -0
- opentrons/protocol_engine/state/module_substates/absorbance_reader_substate.py +35 -0
- opentrons/protocol_engine/state/module_substates/flex_stacker_substate.py +112 -0
- opentrons/protocol_engine/state/module_substates/heater_shaker_module_substate.py +115 -0
- opentrons/protocol_engine/state/module_substates/magnetic_block_substate.py +17 -0
- opentrons/protocol_engine/state/module_substates/magnetic_module_substate.py +65 -0
- opentrons/protocol_engine/state/module_substates/temperature_module_substate.py +67 -0
- opentrons/protocol_engine/state/module_substates/thermocycler_module_substate.py +163 -0
- opentrons/protocol_engine/state/modules.py +1515 -0
- opentrons/protocol_engine/state/motion.py +373 -0
- opentrons/protocol_engine/state/pipettes.py +905 -0
- opentrons/protocol_engine/state/state.py +421 -0
- opentrons/protocol_engine/state/state_summary.py +36 -0
- opentrons/protocol_engine/state/tips.py +420 -0
- opentrons/protocol_engine/state/update_types.py +904 -0
- opentrons/protocol_engine/state/wells.py +290 -0
- opentrons/protocol_engine/types/__init__.py +310 -0
- opentrons/protocol_engine/types/automatic_tip_selection.py +39 -0
- opentrons/protocol_engine/types/command_annotations.py +53 -0
- opentrons/protocol_engine/types/deck_configuration.py +81 -0
- opentrons/protocol_engine/types/execution.py +96 -0
- opentrons/protocol_engine/types/hardware_passthrough.py +25 -0
- opentrons/protocol_engine/types/instrument.py +47 -0
- opentrons/protocol_engine/types/instrument_sensors.py +47 -0
- opentrons/protocol_engine/types/labware.py +131 -0
- opentrons/protocol_engine/types/labware_movement.py +22 -0
- opentrons/protocol_engine/types/labware_offset_location.py +111 -0
- opentrons/protocol_engine/types/labware_offset_vector.py +16 -0
- opentrons/protocol_engine/types/liquid.py +40 -0
- opentrons/protocol_engine/types/liquid_class.py +59 -0
- opentrons/protocol_engine/types/liquid_handling.py +13 -0
- opentrons/protocol_engine/types/liquid_level_detection.py +191 -0
- opentrons/protocol_engine/types/location.py +194 -0
- opentrons/protocol_engine/types/module.py +310 -0
- opentrons/protocol_engine/types/partial_tip_configuration.py +76 -0
- opentrons/protocol_engine/types/run_time_parameters.py +133 -0
- opentrons/protocol_engine/types/tip.py +18 -0
- opentrons/protocol_engine/types/util.py +21 -0
- opentrons/protocol_engine/types/well_position.py +124 -0
- opentrons/protocol_reader/__init__.py +37 -0
- opentrons/protocol_reader/extract_labware_definitions.py +66 -0
- opentrons/protocol_reader/file_format_validator.py +152 -0
- opentrons/protocol_reader/file_hasher.py +27 -0
- opentrons/protocol_reader/file_identifier.py +284 -0
- opentrons/protocol_reader/file_reader_writer.py +90 -0
- opentrons/protocol_reader/input_file.py +16 -0
- opentrons/protocol_reader/protocol_files_invalid_error.py +6 -0
- opentrons/protocol_reader/protocol_reader.py +188 -0
- opentrons/protocol_reader/protocol_source.py +124 -0
- opentrons/protocol_reader/role_analyzer.py +86 -0
- opentrons/protocol_runner/__init__.py +26 -0
- opentrons/protocol_runner/create_simulating_orchestrator.py +118 -0
- opentrons/protocol_runner/json_file_reader.py +55 -0
- opentrons/protocol_runner/json_translator.py +314 -0
- opentrons/protocol_runner/legacy_command_mapper.py +852 -0
- opentrons/protocol_runner/legacy_context_plugin.py +116 -0
- opentrons/protocol_runner/protocol_runner.py +530 -0
- opentrons/protocol_runner/python_protocol_wrappers.py +179 -0
- opentrons/protocol_runner/run_orchestrator.py +496 -0
- opentrons/protocol_runner/task_queue.py +95 -0
- opentrons/protocols/__init__.py +6 -0
- opentrons/protocols/advanced_control/__init__.py +0 -0
- opentrons/protocols/advanced_control/common.py +38 -0
- opentrons/protocols/advanced_control/mix.py +60 -0
- opentrons/protocols/advanced_control/transfers/__init__.py +0 -0
- opentrons/protocols/advanced_control/transfers/common.py +180 -0
- opentrons/protocols/advanced_control/transfers/transfer.py +972 -0
- opentrons/protocols/advanced_control/transfers/transfer_liquid_utils.py +231 -0
- opentrons/protocols/api_support/__init__.py +0 -0
- opentrons/protocols/api_support/constants.py +8 -0
- opentrons/protocols/api_support/deck_type.py +110 -0
- opentrons/protocols/api_support/definitions.py +18 -0
- opentrons/protocols/api_support/instrument.py +151 -0
- opentrons/protocols/api_support/labware_like.py +233 -0
- opentrons/protocols/api_support/tip_tracker.py +175 -0
- opentrons/protocols/api_support/types.py +32 -0
- opentrons/protocols/api_support/util.py +403 -0
- opentrons/protocols/bundle.py +89 -0
- opentrons/protocols/duration/__init__.py +4 -0
- opentrons/protocols/duration/errors.py +5 -0
- opentrons/protocols/duration/estimator.py +628 -0
- opentrons/protocols/execution/__init__.py +0 -0
- opentrons/protocols/execution/dev_types.py +181 -0
- opentrons/protocols/execution/errors.py +40 -0
- opentrons/protocols/execution/execute.py +84 -0
- opentrons/protocols/execution/execute_json_v3.py +275 -0
- opentrons/protocols/execution/execute_json_v4.py +359 -0
- opentrons/protocols/execution/execute_json_v5.py +28 -0
- opentrons/protocols/execution/execute_python.py +169 -0
- opentrons/protocols/execution/json_dispatchers.py +87 -0
- opentrons/protocols/execution/types.py +7 -0
- opentrons/protocols/geometry/__init__.py +0 -0
- opentrons/protocols/geometry/planning.py +297 -0
- opentrons/protocols/labware.py +312 -0
- opentrons/protocols/models/__init__.py +0 -0
- opentrons/protocols/models/json_protocol.py +679 -0
- opentrons/protocols/parameters/__init__.py +0 -0
- opentrons/protocols/parameters/csv_parameter_definition.py +77 -0
- opentrons/protocols/parameters/csv_parameter_interface.py +96 -0
- opentrons/protocols/parameters/exceptions.py +34 -0
- opentrons/protocols/parameters/parameter_definition.py +272 -0
- opentrons/protocols/parameters/types.py +17 -0
- opentrons/protocols/parameters/validation.py +267 -0
- opentrons/protocols/parse.py +671 -0
- opentrons/protocols/types.py +159 -0
- opentrons/py.typed +0 -0
- opentrons/resources/scripts/lpc21isp +0 -0
- opentrons/resources/smoothie-edge-8414642.hex +23010 -0
- opentrons/simulate.py +1065 -0
- opentrons/system/__init__.py +6 -0
- opentrons/system/camera.py +51 -0
- opentrons/system/log_control.py +59 -0
- opentrons/system/nmcli.py +856 -0
- opentrons/system/resin.py +24 -0
- opentrons/system/smoothie_update.py +15 -0
- opentrons/system/wifi.py +204 -0
- opentrons/tools/__init__.py +0 -0
- opentrons/tools/args_handler.py +22 -0
- opentrons/tools/write_pipette_memory.py +157 -0
- opentrons/types.py +618 -0
- opentrons/util/__init__.py +1 -0
- opentrons/util/async_helpers.py +166 -0
- opentrons/util/broker.py +84 -0
- opentrons/util/change_notifier.py +47 -0
- opentrons/util/entrypoint_util.py +278 -0
- opentrons/util/get_union_elements.py +26 -0
- opentrons/util/helpers.py +6 -0
- opentrons/util/linal.py +178 -0
- opentrons/util/logging_config.py +265 -0
- opentrons/util/logging_queue_handler.py +61 -0
- opentrons/util/performance_helpers.py +157 -0
- opentrons-8.6.0.dist-info/METADATA +37 -0
- opentrons-8.6.0.dist-info/RECORD +601 -0
- opentrons-8.6.0.dist-info/WHEEL +4 -0
- opentrons-8.6.0.dist-info/entry_points.txt +3 -0
- opentrons-8.6.0.dist-info/licenses/LICENSE +202 -0
|
@@ -0,0 +1,1027 @@
|
|
|
1
|
+
"""Protocol API module implementation logic."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
from dataclasses import dataclass
|
|
5
|
+
from typing import Optional, List, Dict, Union, Sequence, TYPE_CHECKING, overload
|
|
6
|
+
|
|
7
|
+
from opentrons_shared_data.errors.exceptions import CommandPreconditionViolated
|
|
8
|
+
|
|
9
|
+
from opentrons.hardware_control import SynchronousAdapter, modules as hw_modules
|
|
10
|
+
from opentrons.hardware_control.modules.types import (
|
|
11
|
+
ModuleModel,
|
|
12
|
+
TemperatureStatus,
|
|
13
|
+
MagneticStatus,
|
|
14
|
+
SpeedStatus,
|
|
15
|
+
module_model_from_string,
|
|
16
|
+
)
|
|
17
|
+
from opentrons.drivers.types import (
|
|
18
|
+
HeaterShakerLabwareLatchStatus,
|
|
19
|
+
ThermocyclerLidStatus,
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
from opentrons.protocol_engine import commands as cmd
|
|
23
|
+
from opentrons.protocol_engine.types import (
|
|
24
|
+
ABSMeasureMode,
|
|
25
|
+
StackerFillEmptyStrategy,
|
|
26
|
+
StackerStoredLabwareGroup,
|
|
27
|
+
StackerLabwareMovementStrategy,
|
|
28
|
+
)
|
|
29
|
+
from opentrons.types import DeckSlotName
|
|
30
|
+
from opentrons.protocol_engine.clients import SyncClient as ProtocolEngineClient
|
|
31
|
+
from opentrons.protocol_engine.errors.exceptions import (
|
|
32
|
+
LabwareNotLoadedOnModuleError,
|
|
33
|
+
NoMagnetEngageHeightError,
|
|
34
|
+
CannotPerformModuleAction,
|
|
35
|
+
FlexStackerLabwarePoolNotYetDefinedError,
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
from opentrons.protocols.api_support.types import APIVersion, ThermocyclerStep
|
|
39
|
+
|
|
40
|
+
from ... import validation
|
|
41
|
+
from ..module import (
|
|
42
|
+
AbstractModuleCore,
|
|
43
|
+
AbstractTemperatureModuleCore,
|
|
44
|
+
AbstractMagneticModuleCore,
|
|
45
|
+
AbstractThermocyclerCore,
|
|
46
|
+
AbstractHeaterShakerCore,
|
|
47
|
+
AbstractMagneticBlockCore,
|
|
48
|
+
AbstractAbsorbanceReaderCore,
|
|
49
|
+
AbstractFlexStackerCore,
|
|
50
|
+
)
|
|
51
|
+
from .exceptions import InvalidMagnetEngageHeightError
|
|
52
|
+
|
|
53
|
+
from .labware import LabwareCore
|
|
54
|
+
from . import load_labware_params
|
|
55
|
+
|
|
56
|
+
if TYPE_CHECKING:
|
|
57
|
+
from .protocol import ProtocolCore
|
|
58
|
+
|
|
59
|
+
# Valid wavelength range for absorbance reader
|
|
60
|
+
ABS_WAVELENGTH_MIN = 350
|
|
61
|
+
ABS_WAVELENGTH_MAX = 1000
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
class ModuleCore(AbstractModuleCore[LabwareCore]):
|
|
65
|
+
"""Module core logic implementation for Python protocols.
|
|
66
|
+
Args:
|
|
67
|
+
module_id: ProtocolEngine ID of the loaded modules.
|
|
68
|
+
"""
|
|
69
|
+
|
|
70
|
+
def __init__(
|
|
71
|
+
self,
|
|
72
|
+
module_id: str,
|
|
73
|
+
engine_client: ProtocolEngineClient,
|
|
74
|
+
api_version: APIVersion,
|
|
75
|
+
sync_module_hardware: SynchronousAdapter[hw_modules.AbstractModule],
|
|
76
|
+
protocol_core: ProtocolCore,
|
|
77
|
+
) -> None:
|
|
78
|
+
self._module_id = module_id
|
|
79
|
+
self._engine_client = engine_client
|
|
80
|
+
self._api_version = api_version
|
|
81
|
+
self._sync_module_hardware = sync_module_hardware
|
|
82
|
+
self._protocol_core = protocol_core
|
|
83
|
+
|
|
84
|
+
@property
|
|
85
|
+
def api_version(self) -> APIVersion:
|
|
86
|
+
"""Get the api version protocol module target."""
|
|
87
|
+
return self._api_version
|
|
88
|
+
|
|
89
|
+
@property
|
|
90
|
+
def module_id(self) -> str:
|
|
91
|
+
"""The module's unique ProtocolEngine ID."""
|
|
92
|
+
return self._module_id
|
|
93
|
+
|
|
94
|
+
def get_model(self) -> ModuleModel:
|
|
95
|
+
"""Get the module's model identifier."""
|
|
96
|
+
return module_model_from_string(
|
|
97
|
+
self._engine_client.state.modules.get_connected_model(self.module_id)
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
def get_serial_number(self) -> str:
|
|
101
|
+
"""Get the module's unique hardware serial number."""
|
|
102
|
+
return self._engine_client.state.modules.get_serial_number(self.module_id)
|
|
103
|
+
|
|
104
|
+
def get_deck_slot(self) -> DeckSlotName:
|
|
105
|
+
"""Get the module's deck slot."""
|
|
106
|
+
return self._engine_client.state.modules.get_location(self.module_id).slotName
|
|
107
|
+
|
|
108
|
+
def get_deck_slot_id(self) -> str:
|
|
109
|
+
slot_name = self.get_deck_slot()
|
|
110
|
+
return validation.internal_slot_to_public_string(
|
|
111
|
+
slot_name, robot_type=self._engine_client.state.config.robot_type
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
def get_display_name(self) -> str:
|
|
115
|
+
"""Get the module's display name."""
|
|
116
|
+
return self._engine_client.state.modules.get_definition(
|
|
117
|
+
self.module_id
|
|
118
|
+
).displayName
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
class NonConnectedModuleCore(AbstractModuleCore[LabwareCore]):
|
|
122
|
+
"""Not connected module core logic implementation for Python protocols.
|
|
123
|
+
|
|
124
|
+
Args:
|
|
125
|
+
module_id: ProtocolEngine ID of the loaded modules.
|
|
126
|
+
"""
|
|
127
|
+
|
|
128
|
+
def __init__(
|
|
129
|
+
self,
|
|
130
|
+
module_id: str,
|
|
131
|
+
engine_client: ProtocolEngineClient,
|
|
132
|
+
api_version: APIVersion,
|
|
133
|
+
protocol_core: ProtocolCore,
|
|
134
|
+
) -> None:
|
|
135
|
+
self._module_id = module_id
|
|
136
|
+
self._engine_client = engine_client
|
|
137
|
+
self._api_version = api_version
|
|
138
|
+
self._protocol_core = protocol_core
|
|
139
|
+
|
|
140
|
+
@property
|
|
141
|
+
def api_version(self) -> APIVersion:
|
|
142
|
+
"""Get the api version protocol module target."""
|
|
143
|
+
return self._api_version
|
|
144
|
+
|
|
145
|
+
@property
|
|
146
|
+
def module_id(self) -> str:
|
|
147
|
+
"""The module's unique ProtocolEngine ID."""
|
|
148
|
+
return self._module_id
|
|
149
|
+
|
|
150
|
+
def get_model(self) -> ModuleModel:
|
|
151
|
+
"""Get the module's model identifier."""
|
|
152
|
+
return module_model_from_string(
|
|
153
|
+
self._engine_client.state.modules.get_connected_model(self.module_id)
|
|
154
|
+
)
|
|
155
|
+
|
|
156
|
+
def get_deck_slot(self) -> DeckSlotName:
|
|
157
|
+
"""Get the module's deck slot."""
|
|
158
|
+
return self._engine_client.state.modules.get_location(self.module_id).slotName
|
|
159
|
+
|
|
160
|
+
def get_display_name(self) -> str:
|
|
161
|
+
"""Get the module's display name."""
|
|
162
|
+
return self._engine_client.state.modules.get_definition(
|
|
163
|
+
self.module_id
|
|
164
|
+
).displayName
|
|
165
|
+
|
|
166
|
+
def get_deck_slot_id(self) -> str:
|
|
167
|
+
slot_name = self.get_deck_slot()
|
|
168
|
+
return validation.internal_slot_to_public_string(
|
|
169
|
+
slot_name, robot_type=self._engine_client.state.config.robot_type
|
|
170
|
+
)
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
class TemperatureModuleCore(ModuleCore, AbstractTemperatureModuleCore[LabwareCore]):
|
|
174
|
+
"""Temperature Module core logic implementation for Python protocols."""
|
|
175
|
+
|
|
176
|
+
_sync_module_hardware: SynchronousAdapter[hw_modules.TempDeck]
|
|
177
|
+
|
|
178
|
+
def set_target_temperature(self, celsius: float) -> None:
|
|
179
|
+
"""Set the Temperature Module's target temperature in °C."""
|
|
180
|
+
self._engine_client.execute_command(
|
|
181
|
+
cmd.temperature_module.SetTargetTemperatureParams(
|
|
182
|
+
moduleId=self.module_id, celsius=celsius
|
|
183
|
+
)
|
|
184
|
+
)
|
|
185
|
+
|
|
186
|
+
def wait_for_target_temperature(self, celsius: Optional[float] = None) -> None:
|
|
187
|
+
"""Wait until the module's target temperature is reached.
|
|
188
|
+
Specifying a value for ``celsius`` that is different than
|
|
189
|
+
the module's current target temperature may behave unpredictably.
|
|
190
|
+
"""
|
|
191
|
+
self._engine_client.execute_command(
|
|
192
|
+
cmd.temperature_module.WaitForTemperatureParams(
|
|
193
|
+
moduleId=self.module_id, celsius=celsius
|
|
194
|
+
)
|
|
195
|
+
)
|
|
196
|
+
|
|
197
|
+
def deactivate(self) -> None:
|
|
198
|
+
"""Deactivate the Temperature Module."""
|
|
199
|
+
self._engine_client.execute_command(
|
|
200
|
+
cmd.temperature_module.DeactivateTemperatureParams(moduleId=self.module_id)
|
|
201
|
+
)
|
|
202
|
+
|
|
203
|
+
def get_current_temperature(self) -> float:
|
|
204
|
+
"""Get the module's current temperature in °C."""
|
|
205
|
+
return self._sync_module_hardware.temperature # type: ignore[no-any-return]
|
|
206
|
+
|
|
207
|
+
def get_target_temperature(self) -> Optional[float]:
|
|
208
|
+
"""Get the module's target temperature in °C, if set."""
|
|
209
|
+
return self._sync_module_hardware.target # type: ignore[no-any-return]
|
|
210
|
+
|
|
211
|
+
def get_status(self) -> TemperatureStatus:
|
|
212
|
+
"""Get the module's current temperature status."""
|
|
213
|
+
return self._sync_module_hardware.status # type: ignore[no-any-return]
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
class MagneticModuleCore(ModuleCore, AbstractMagneticModuleCore[LabwareCore]):
|
|
217
|
+
"""Magnetic Module control interface via a ProtocolEngine."""
|
|
218
|
+
|
|
219
|
+
_sync_module_hardware: SynchronousAdapter[hw_modules.MagDeck]
|
|
220
|
+
|
|
221
|
+
def engage(
|
|
222
|
+
self,
|
|
223
|
+
height_from_base: Optional[float] = None,
|
|
224
|
+
height_from_home: Optional[float] = None,
|
|
225
|
+
) -> None:
|
|
226
|
+
"""Raise the module's magnets.
|
|
227
|
+
Only one of `height_from_base` or `height_from_home` may be specified.
|
|
228
|
+
Args:
|
|
229
|
+
height_from_base: Distance from labware base to raise the magnets.
|
|
230
|
+
height_from_home: Distance from motor home position to raise the magnets.
|
|
231
|
+
"""
|
|
232
|
+
|
|
233
|
+
# This core will only be used in apiLevels >=2.14, where
|
|
234
|
+
# MagneticModuleContext.engage(height=...) is no longer available.
|
|
235
|
+
# So these asserts should always pass.
|
|
236
|
+
assert (
|
|
237
|
+
height_from_home is None
|
|
238
|
+
), "Expected engage height to be specified from base."
|
|
239
|
+
assert (
|
|
240
|
+
height_from_base is not None
|
|
241
|
+
), "Expected engage height to be specified from base."
|
|
242
|
+
|
|
243
|
+
self._engine_client.execute_command(
|
|
244
|
+
cmd.magnetic_module.EngageParams(
|
|
245
|
+
moduleId=self._module_id, height=height_from_base
|
|
246
|
+
)
|
|
247
|
+
)
|
|
248
|
+
|
|
249
|
+
def engage_to_labware(
|
|
250
|
+
self, offset: float = 0, preserve_half_mm: bool = False
|
|
251
|
+
) -> None:
|
|
252
|
+
"""Raise the module's magnets up to its loaded labware.
|
|
253
|
+
Args:
|
|
254
|
+
offset: Offset from the labware's default engage height.
|
|
255
|
+
preserve_half_mm: For labware whose definitions
|
|
256
|
+
erroneously use half-mm for their defined default engage height,
|
|
257
|
+
use the value directly instead of converting it to real millimeters.
|
|
258
|
+
"""
|
|
259
|
+
try:
|
|
260
|
+
default_height = (
|
|
261
|
+
self._engine_client.state.labware.get_default_magnet_height(
|
|
262
|
+
module_id=self.module_id, offset=offset
|
|
263
|
+
)
|
|
264
|
+
)
|
|
265
|
+
except LabwareNotLoadedOnModuleError:
|
|
266
|
+
raise InvalidMagnetEngageHeightError(
|
|
267
|
+
"There is no labware loaded on this Magnetic Module,"
|
|
268
|
+
" so you must specify an engage height"
|
|
269
|
+
" with the `height_from_base` parameter."
|
|
270
|
+
)
|
|
271
|
+
except NoMagnetEngageHeightError:
|
|
272
|
+
raise InvalidMagnetEngageHeightError(
|
|
273
|
+
"The labware loaded on this Magnetic Module"
|
|
274
|
+
" does not have a default engage height,"
|
|
275
|
+
" so you must specify an engage height"
|
|
276
|
+
" with the `height_from_base` parameter."
|
|
277
|
+
)
|
|
278
|
+
|
|
279
|
+
self._engine_client.execute_command(
|
|
280
|
+
cmd.magnetic_module.EngageParams(
|
|
281
|
+
moduleId=self.module_id, height=default_height
|
|
282
|
+
)
|
|
283
|
+
)
|
|
284
|
+
|
|
285
|
+
def disengage(self) -> None:
|
|
286
|
+
"""Lower the magnets back into the module."""
|
|
287
|
+
self._engine_client.execute_command(
|
|
288
|
+
cmd.magnetic_module.DisengageParams(moduleId=self.module_id)
|
|
289
|
+
)
|
|
290
|
+
|
|
291
|
+
def get_status(self) -> MagneticStatus:
|
|
292
|
+
"""Get the module's current magnet status."""
|
|
293
|
+
return self._sync_module_hardware.status # type: ignore[no-any-return]
|
|
294
|
+
|
|
295
|
+
|
|
296
|
+
class ThermocyclerModuleCore(ModuleCore, AbstractThermocyclerCore[LabwareCore]):
|
|
297
|
+
"""Core control interface for an attached Thermocycler Module."""
|
|
298
|
+
|
|
299
|
+
_sync_module_hardware: SynchronousAdapter[hw_modules.Thermocycler]
|
|
300
|
+
_repetitions: Optional[int] = None
|
|
301
|
+
_step_count: Optional[int] = None
|
|
302
|
+
|
|
303
|
+
def open_lid(self) -> ThermocyclerLidStatus:
|
|
304
|
+
"""Open the Thermocycler's lid."""
|
|
305
|
+
self._engine_client.execute_command(
|
|
306
|
+
cmd.thermocycler.OpenLidParams(moduleId=self.module_id)
|
|
307
|
+
)
|
|
308
|
+
return ThermocyclerLidStatus.OPEN
|
|
309
|
+
|
|
310
|
+
def close_lid(self) -> ThermocyclerLidStatus:
|
|
311
|
+
"""Close the Thermocycler's lid."""
|
|
312
|
+
self._engine_client.execute_command(
|
|
313
|
+
cmd.thermocycler.CloseLidParams(moduleId=self.module_id)
|
|
314
|
+
)
|
|
315
|
+
return ThermocyclerLidStatus.CLOSED
|
|
316
|
+
|
|
317
|
+
def set_target_block_temperature(
|
|
318
|
+
self,
|
|
319
|
+
celsius: float,
|
|
320
|
+
hold_time_seconds: Optional[float] = None,
|
|
321
|
+
block_max_volume: Optional[float] = None,
|
|
322
|
+
) -> None:
|
|
323
|
+
"""Set the target temperature for the well block, in °C."""
|
|
324
|
+
self._engine_client.execute_command(
|
|
325
|
+
cmd.thermocycler.SetTargetBlockTemperatureParams(
|
|
326
|
+
moduleId=self.module_id,
|
|
327
|
+
celsius=celsius,
|
|
328
|
+
blockMaxVolumeUl=block_max_volume,
|
|
329
|
+
holdTimeSeconds=hold_time_seconds,
|
|
330
|
+
)
|
|
331
|
+
)
|
|
332
|
+
|
|
333
|
+
def wait_for_block_temperature(self) -> None:
|
|
334
|
+
"""Wait for target block temperature to be reached."""
|
|
335
|
+
self._engine_client.execute_command(
|
|
336
|
+
cmd.thermocycler.WaitForBlockTemperatureParams(moduleId=self.module_id)
|
|
337
|
+
)
|
|
338
|
+
|
|
339
|
+
def set_target_lid_temperature(self, celsius: float) -> None:
|
|
340
|
+
"""Set the target temperature for the heated lid, in °C."""
|
|
341
|
+
self._engine_client.execute_command(
|
|
342
|
+
cmd.thermocycler.SetTargetLidTemperatureParams(
|
|
343
|
+
moduleId=self.module_id, celsius=celsius
|
|
344
|
+
)
|
|
345
|
+
)
|
|
346
|
+
|
|
347
|
+
def wait_for_lid_temperature(self) -> None:
|
|
348
|
+
"""Wait for target lid temperature to be reached."""
|
|
349
|
+
self._engine_client.execute_command(
|
|
350
|
+
cmd.thermocycler.WaitForLidTemperatureParams(moduleId=self.module_id)
|
|
351
|
+
)
|
|
352
|
+
|
|
353
|
+
def _execute_profile_pre_221(
|
|
354
|
+
self,
|
|
355
|
+
steps: List[ThermocyclerStep],
|
|
356
|
+
repetitions: int,
|
|
357
|
+
block_max_volume: Optional[float],
|
|
358
|
+
) -> None:
|
|
359
|
+
"""Execute a thermocycler profile using thermocycler/runProfile and flattened steps."""
|
|
360
|
+
engine_steps = [
|
|
361
|
+
cmd.thermocycler.RunProfileStepParams(
|
|
362
|
+
celsius=step["temperature"],
|
|
363
|
+
holdSeconds=step["hold_time_seconds"],
|
|
364
|
+
)
|
|
365
|
+
for step in steps
|
|
366
|
+
]
|
|
367
|
+
repeated_engine_steps = engine_steps * repetitions
|
|
368
|
+
self._engine_client.execute_command(
|
|
369
|
+
cmd.thermocycler.RunProfileParams(
|
|
370
|
+
moduleId=self.module_id,
|
|
371
|
+
profile=repeated_engine_steps,
|
|
372
|
+
blockMaxVolumeUl=block_max_volume,
|
|
373
|
+
)
|
|
374
|
+
)
|
|
375
|
+
|
|
376
|
+
def _execute_profile_post_221(
|
|
377
|
+
self,
|
|
378
|
+
steps: List[ThermocyclerStep],
|
|
379
|
+
repetitions: int,
|
|
380
|
+
block_max_volume: Optional[float],
|
|
381
|
+
) -> None:
|
|
382
|
+
"""Execute a thermocycler profile using thermocycler/runExtendedProfile."""
|
|
383
|
+
engine_steps: List[
|
|
384
|
+
Union[cmd.thermocycler.ProfileCycle, cmd.thermocycler.ProfileStep]
|
|
385
|
+
] = [
|
|
386
|
+
cmd.thermocycler.ProfileCycle(
|
|
387
|
+
repetitions=repetitions,
|
|
388
|
+
steps=[
|
|
389
|
+
cmd.thermocycler.ProfileStep(
|
|
390
|
+
celsius=step["temperature"],
|
|
391
|
+
holdSeconds=step["hold_time_seconds"],
|
|
392
|
+
)
|
|
393
|
+
for step in steps
|
|
394
|
+
],
|
|
395
|
+
)
|
|
396
|
+
]
|
|
397
|
+
self._engine_client.execute_command(
|
|
398
|
+
cmd.thermocycler.RunExtendedProfileParams(
|
|
399
|
+
moduleId=self.module_id,
|
|
400
|
+
profileElements=engine_steps,
|
|
401
|
+
blockMaxVolumeUl=block_max_volume,
|
|
402
|
+
)
|
|
403
|
+
)
|
|
404
|
+
|
|
405
|
+
def execute_profile(
|
|
406
|
+
self,
|
|
407
|
+
steps: List[ThermocyclerStep],
|
|
408
|
+
repetitions: int,
|
|
409
|
+
block_max_volume: Optional[float] = None,
|
|
410
|
+
) -> None:
|
|
411
|
+
"""Execute a Thermocycler Profile."""
|
|
412
|
+
self._repetitions = repetitions
|
|
413
|
+
self._step_count = len(steps)
|
|
414
|
+
if self.api_version >= APIVersion(2, 21):
|
|
415
|
+
return self._execute_profile_post_221(steps, repetitions, block_max_volume)
|
|
416
|
+
else:
|
|
417
|
+
return self._execute_profile_pre_221(steps, repetitions, block_max_volume)
|
|
418
|
+
|
|
419
|
+
def deactivate_lid(self) -> None:
|
|
420
|
+
"""Turn off the heated lid."""
|
|
421
|
+
self._engine_client.execute_command(
|
|
422
|
+
cmd.thermocycler.DeactivateLidParams(moduleId=self.module_id)
|
|
423
|
+
)
|
|
424
|
+
|
|
425
|
+
def deactivate_block(self) -> None:
|
|
426
|
+
"""Turn off the well block temperature controller"""
|
|
427
|
+
self._clear_cycle_counters()
|
|
428
|
+
self._engine_client.execute_command(
|
|
429
|
+
cmd.thermocycler.DeactivateBlockParams(moduleId=self.module_id)
|
|
430
|
+
)
|
|
431
|
+
|
|
432
|
+
def deactivate(self) -> None:
|
|
433
|
+
"""Turn off the well block temperature controller, and heated lid"""
|
|
434
|
+
self.deactivate_block()
|
|
435
|
+
self.deactivate_lid()
|
|
436
|
+
|
|
437
|
+
def get_lid_position(self) -> Optional[ThermocyclerLidStatus]:
|
|
438
|
+
"""Get the thermocycler's lid position."""
|
|
439
|
+
return self._sync_module_hardware.lid_status # type: ignore[no-any-return]
|
|
440
|
+
|
|
441
|
+
def get_block_temperature_status(self) -> TemperatureStatus:
|
|
442
|
+
"""Get the thermocycler's block temperature status."""
|
|
443
|
+
return self._sync_module_hardware.status # type: ignore[no-any-return]
|
|
444
|
+
|
|
445
|
+
def get_lid_temperature_status(self) -> Optional[TemperatureStatus]:
|
|
446
|
+
"""Get the thermocycler's lid temperature status."""
|
|
447
|
+
return self._sync_module_hardware.lid_temp_status # type: ignore[no-any-return]
|
|
448
|
+
|
|
449
|
+
def get_block_temperature(self) -> Optional[float]:
|
|
450
|
+
"""Get the thermocycler's current block temperature in °C."""
|
|
451
|
+
return self._sync_module_hardware.temperature # type: ignore[no-any-return]
|
|
452
|
+
|
|
453
|
+
def get_block_target_temperature(self) -> Optional[float]:
|
|
454
|
+
"""Get the thermocycler's target block temperature in °C."""
|
|
455
|
+
return self._sync_module_hardware.target # type: ignore[no-any-return]
|
|
456
|
+
|
|
457
|
+
def get_lid_temperature(self) -> Optional[float]:
|
|
458
|
+
"""Get the thermocycler's current lid temperature in °C."""
|
|
459
|
+
return self._sync_module_hardware.lid_temp # type: ignore[no-any-return]
|
|
460
|
+
|
|
461
|
+
def get_lid_target_temperature(self) -> Optional[float]:
|
|
462
|
+
"""Get the thermocycler's target lid temperature in °C."""
|
|
463
|
+
return self._sync_module_hardware.lid_target # type: ignore[no-any-return]
|
|
464
|
+
|
|
465
|
+
def get_ramp_rate(self) -> Optional[float]:
|
|
466
|
+
"""Get the thermocycler's current ramp rate in °C/sec."""
|
|
467
|
+
return self._sync_module_hardware.ramp_rate # type: ignore[no-any-return]
|
|
468
|
+
|
|
469
|
+
def get_hold_time(self) -> Optional[float]:
|
|
470
|
+
"""Get the remaining hold time in seconds."""
|
|
471
|
+
return self._sync_module_hardware.hold_time # type: ignore[no-any-return]
|
|
472
|
+
|
|
473
|
+
def get_total_cycle_count(self) -> Optional[int]:
|
|
474
|
+
"""Get number of repetitions for current set cycle."""
|
|
475
|
+
return self._repetitions
|
|
476
|
+
|
|
477
|
+
def get_current_cycle_index(self) -> Optional[int]:
|
|
478
|
+
"""Get index of the current set cycle repetition."""
|
|
479
|
+
if self._repetitions is None:
|
|
480
|
+
return None
|
|
481
|
+
step_index = self._sync_module_hardware.current_step_index
|
|
482
|
+
# TODO(jbl 2022-10-31) this is intended to work even if execute profile is non-blocking, but it is blocking so
|
|
483
|
+
# this is not guaranteed to be accurate
|
|
484
|
+
return (step_index - 1) // self._step_count + 1 # type: ignore[no-any-return]
|
|
485
|
+
|
|
486
|
+
def get_total_step_count(self) -> Optional[int]:
|
|
487
|
+
"""Get number of steps within the current cycle."""
|
|
488
|
+
return self._step_count
|
|
489
|
+
|
|
490
|
+
def get_current_step_index(self) -> Optional[int]:
|
|
491
|
+
"""Get the index of the current step within the current cycle."""
|
|
492
|
+
if self._step_count is None:
|
|
493
|
+
return None
|
|
494
|
+
step_index = self._sync_module_hardware.current_step_index
|
|
495
|
+
# TODO(jbl 2022-10-31) this is intended to work even if execute profile is non-blocking, but it is blocking so
|
|
496
|
+
# this is not guaranteed to be accurate
|
|
497
|
+
return (step_index - 1) % self._step_count + 1 # type: ignore[no-any-return]
|
|
498
|
+
|
|
499
|
+
def _clear_cycle_counters(self) -> None:
|
|
500
|
+
"""Clear core-tracked cycle counters."""
|
|
501
|
+
self._repetitions = None
|
|
502
|
+
self._step_count = None
|
|
503
|
+
|
|
504
|
+
|
|
505
|
+
class HeaterShakerModuleCore(ModuleCore, AbstractHeaterShakerCore[LabwareCore]):
|
|
506
|
+
"""Core control interface for an attached Heater-Shaker Module."""
|
|
507
|
+
|
|
508
|
+
_sync_module_hardware: SynchronousAdapter[hw_modules.HeaterShaker]
|
|
509
|
+
|
|
510
|
+
def set_target_temperature(self, celsius: float) -> None:
|
|
511
|
+
"""Set the labware plate's target temperature in °C."""
|
|
512
|
+
self._engine_client.execute_command(
|
|
513
|
+
cmd.heater_shaker.SetTargetTemperatureParams(
|
|
514
|
+
moduleId=self.module_id, celsius=celsius
|
|
515
|
+
)
|
|
516
|
+
)
|
|
517
|
+
|
|
518
|
+
def wait_for_target_temperature(self) -> None:
|
|
519
|
+
"""Wait for the labware plate's target temperature to be reached."""
|
|
520
|
+
self._engine_client.execute_command(
|
|
521
|
+
cmd.heater_shaker.WaitForTemperatureParams(moduleId=self.module_id)
|
|
522
|
+
)
|
|
523
|
+
|
|
524
|
+
def set_and_wait_for_shake_speed(self, rpm: int) -> None:
|
|
525
|
+
"""Set the shaker's target shake speed and wait for it to spin up."""
|
|
526
|
+
self._engine_client.execute_command(
|
|
527
|
+
cmd.heater_shaker.SetAndWaitForShakeSpeedParams(
|
|
528
|
+
moduleId=self.module_id, rpm=rpm
|
|
529
|
+
)
|
|
530
|
+
)
|
|
531
|
+
|
|
532
|
+
def open_labware_latch(self) -> None:
|
|
533
|
+
"""Open the labware latch."""
|
|
534
|
+
self._engine_client.execute_command(
|
|
535
|
+
cmd.heater_shaker.OpenLabwareLatchParams(moduleId=self.module_id)
|
|
536
|
+
)
|
|
537
|
+
|
|
538
|
+
def close_labware_latch(self) -> None:
|
|
539
|
+
"""Close the labware latch."""
|
|
540
|
+
self._engine_client.execute_command(
|
|
541
|
+
cmd.heater_shaker.CloseLabwareLatchParams(moduleId=self.module_id)
|
|
542
|
+
)
|
|
543
|
+
|
|
544
|
+
def deactivate_shaker(self) -> None:
|
|
545
|
+
"""Stop shaking."""
|
|
546
|
+
self._engine_client.execute_command(
|
|
547
|
+
cmd.heater_shaker.DeactivateShakerParams(moduleId=self.module_id)
|
|
548
|
+
)
|
|
549
|
+
|
|
550
|
+
def deactivate_heater(self) -> None:
|
|
551
|
+
"""Stop heating."""
|
|
552
|
+
self._engine_client.execute_command(
|
|
553
|
+
cmd.heater_shaker.DeactivateHeaterParams(moduleId=self.module_id)
|
|
554
|
+
)
|
|
555
|
+
|
|
556
|
+
def get_current_temperature(self) -> float:
|
|
557
|
+
"""Get the labware plate's current temperature in °C."""
|
|
558
|
+
return self._sync_module_hardware.temperature # type: ignore[no-any-return]
|
|
559
|
+
|
|
560
|
+
def get_target_temperature(self) -> Optional[float]:
|
|
561
|
+
"""Get the labware plate's target temperature in °C, if set."""
|
|
562
|
+
return self._sync_module_hardware.target_temperature # type: ignore[no-any-return]
|
|
563
|
+
|
|
564
|
+
def get_current_speed(self) -> int:
|
|
565
|
+
"""Get the shaker's current speed in RPM."""
|
|
566
|
+
return self._sync_module_hardware.speed # type: ignore[no-any-return]
|
|
567
|
+
|
|
568
|
+
def get_target_speed(self) -> Optional[int]:
|
|
569
|
+
"""Get the shaker's target speed in RPM, if set."""
|
|
570
|
+
return self._sync_module_hardware.target_speed # type: ignore[no-any-return]
|
|
571
|
+
|
|
572
|
+
def get_temperature_status(self) -> TemperatureStatus:
|
|
573
|
+
"""Get the module's heater status."""
|
|
574
|
+
return self._sync_module_hardware.temperature_status # type: ignore[no-any-return]
|
|
575
|
+
|
|
576
|
+
def get_speed_status(self) -> SpeedStatus:
|
|
577
|
+
"""Get the module's heater status."""
|
|
578
|
+
return self._sync_module_hardware.speed_status # type: ignore[no-any-return]
|
|
579
|
+
|
|
580
|
+
def get_labware_latch_status(self) -> HeaterShakerLabwareLatchStatus:
|
|
581
|
+
"""Get the module's labware latch status."""
|
|
582
|
+
return self._sync_module_hardware.labware_latch_status # type: ignore[no-any-return]
|
|
583
|
+
|
|
584
|
+
|
|
585
|
+
class MagneticBlockCore(NonConnectedModuleCore, AbstractMagneticBlockCore[LabwareCore]):
|
|
586
|
+
"""Magnetic Block control interface via a ProtocolEngine."""
|
|
587
|
+
|
|
588
|
+
|
|
589
|
+
class AbsorbanceReaderCore(ModuleCore, AbstractAbsorbanceReaderCore[LabwareCore]):
|
|
590
|
+
"""Absorbance Reader core logic implementation for Python protocols."""
|
|
591
|
+
|
|
592
|
+
_sync_module_hardware: SynchronousAdapter[hw_modules.AbsorbanceReader]
|
|
593
|
+
_initialized_value: Optional[List[int]] = None
|
|
594
|
+
_ready_to_initialize: bool = False
|
|
595
|
+
|
|
596
|
+
def initialize(
|
|
597
|
+
self,
|
|
598
|
+
mode: ABSMeasureMode,
|
|
599
|
+
wavelengths: List[int],
|
|
600
|
+
reference_wavelength: Optional[int] = None,
|
|
601
|
+
) -> None:
|
|
602
|
+
"""Initialize the Absorbance Reader by taking zero reading."""
|
|
603
|
+
if not self._ready_to_initialize:
|
|
604
|
+
raise CannotPerformModuleAction(
|
|
605
|
+
"Cannot perform Initialize action on Absorbance Reader without calling `.close_lid()` first."
|
|
606
|
+
)
|
|
607
|
+
|
|
608
|
+
wavelength_len = len(wavelengths)
|
|
609
|
+
if mode == "single" and wavelength_len != 1:
|
|
610
|
+
raise ValueError(
|
|
611
|
+
f"Single mode can only be initialized with 1 wavelength"
|
|
612
|
+
f" {wavelength_len} wavelengths provided instead."
|
|
613
|
+
)
|
|
614
|
+
|
|
615
|
+
if mode == "multi" and (wavelength_len < 1 or wavelength_len > 6):
|
|
616
|
+
raise ValueError(
|
|
617
|
+
f"Multi mode can only be initialized with 1 - 6 wavelengths."
|
|
618
|
+
f" {wavelength_len} wavelengths provided instead."
|
|
619
|
+
)
|
|
620
|
+
|
|
621
|
+
if reference_wavelength is not None and (
|
|
622
|
+
reference_wavelength < ABS_WAVELENGTH_MIN
|
|
623
|
+
or reference_wavelength > ABS_WAVELENGTH_MAX
|
|
624
|
+
):
|
|
625
|
+
raise ValueError(
|
|
626
|
+
f"Unsupported reference wavelength: ({reference_wavelength}) needs"
|
|
627
|
+
f" to between {ABS_WAVELENGTH_MIN} and {ABS_WAVELENGTH_MAX} nm."
|
|
628
|
+
)
|
|
629
|
+
|
|
630
|
+
for wavelength in wavelengths:
|
|
631
|
+
if (
|
|
632
|
+
not isinstance(wavelength, int)
|
|
633
|
+
or wavelength < ABS_WAVELENGTH_MIN
|
|
634
|
+
or wavelength > ABS_WAVELENGTH_MAX
|
|
635
|
+
):
|
|
636
|
+
raise ValueError(
|
|
637
|
+
f"Unsupported sample wavelength: ({wavelength}) needs"
|
|
638
|
+
f" to between {ABS_WAVELENGTH_MIN} and {ABS_WAVELENGTH_MAX} nm."
|
|
639
|
+
)
|
|
640
|
+
|
|
641
|
+
self._engine_client.execute_command(
|
|
642
|
+
cmd.absorbance_reader.InitializeParams(
|
|
643
|
+
moduleId=self.module_id,
|
|
644
|
+
measureMode=mode,
|
|
645
|
+
sampleWavelengths=wavelengths,
|
|
646
|
+
referenceWavelength=reference_wavelength,
|
|
647
|
+
),
|
|
648
|
+
)
|
|
649
|
+
self._initialized_value = wavelengths
|
|
650
|
+
|
|
651
|
+
def read(self, filename: Optional[str] = None) -> Dict[int, Dict[str, float]]:
|
|
652
|
+
"""Initiate a read on the Absorbance Reader, and return the results. During Analysis, this will return a measurement of zero for all wells."""
|
|
653
|
+
wavelengths = self._engine_client.state.modules.get_absorbance_reader_substate(
|
|
654
|
+
self.module_id
|
|
655
|
+
).configured_wavelengths
|
|
656
|
+
if wavelengths is None:
|
|
657
|
+
raise CannotPerformModuleAction(
|
|
658
|
+
"Cannot perform Read action on Absorbance Reader without calling `.initialize(...)` first."
|
|
659
|
+
)
|
|
660
|
+
if self._initialized_value:
|
|
661
|
+
self._engine_client.execute_command(
|
|
662
|
+
cmd.absorbance_reader.ReadAbsorbanceParams(
|
|
663
|
+
moduleId=self.module_id, fileName=filename
|
|
664
|
+
)
|
|
665
|
+
)
|
|
666
|
+
if not self._engine_client.state.config.use_virtual_modules:
|
|
667
|
+
read_result = (
|
|
668
|
+
self._engine_client.state.modules.get_absorbance_reader_substate(
|
|
669
|
+
self.module_id
|
|
670
|
+
).data
|
|
671
|
+
)
|
|
672
|
+
if read_result is not None:
|
|
673
|
+
return read_result
|
|
674
|
+
raise CannotPerformModuleAction(
|
|
675
|
+
"Absorbance Reader failed to return expected read result."
|
|
676
|
+
)
|
|
677
|
+
|
|
678
|
+
# When using virtual modules, return all zeroes
|
|
679
|
+
virtual_asbsorbance_result: Dict[int, Dict[str, float]] = {}
|
|
680
|
+
for wavelength in wavelengths:
|
|
681
|
+
converted_values = (
|
|
682
|
+
self._engine_client.state.modules.convert_absorbance_reader_data_points(
|
|
683
|
+
data=[0] * 96
|
|
684
|
+
)
|
|
685
|
+
)
|
|
686
|
+
virtual_asbsorbance_result[wavelength] = converted_values
|
|
687
|
+
return virtual_asbsorbance_result
|
|
688
|
+
|
|
689
|
+
def close_lid(
|
|
690
|
+
self,
|
|
691
|
+
) -> None:
|
|
692
|
+
"""Close the Absorbance Reader's lid."""
|
|
693
|
+
self._engine_client.execute_command(
|
|
694
|
+
cmd.absorbance_reader.CloseLidParams(
|
|
695
|
+
moduleId=self.module_id,
|
|
696
|
+
)
|
|
697
|
+
)
|
|
698
|
+
self._ready_to_initialize = True
|
|
699
|
+
|
|
700
|
+
def open_lid(self) -> None:
|
|
701
|
+
"""Close the Absorbance Reader's lid."""
|
|
702
|
+
self._engine_client.execute_command(
|
|
703
|
+
cmd.absorbance_reader.OpenLidParams(
|
|
704
|
+
moduleId=self.module_id,
|
|
705
|
+
)
|
|
706
|
+
)
|
|
707
|
+
|
|
708
|
+
def is_lid_on(self) -> bool:
|
|
709
|
+
"""Returns True if the Absorbance Reader's lid is currently on the Reader slot."""
|
|
710
|
+
abs_state = self._engine_client.state.modules.get_absorbance_reader_substate(
|
|
711
|
+
self.module_id
|
|
712
|
+
)
|
|
713
|
+
return abs_state.is_lid_on
|
|
714
|
+
|
|
715
|
+
|
|
716
|
+
@dataclass
|
|
717
|
+
class _CoreTrio:
|
|
718
|
+
primary: LabwareCore
|
|
719
|
+
adapter: LabwareCore | None
|
|
720
|
+
lid: LabwareCore | None
|
|
721
|
+
|
|
722
|
+
|
|
723
|
+
class FlexStackerCore(ModuleCore, AbstractFlexStackerCore[LabwareCore]):
|
|
724
|
+
"""Flex Stacker core logic implementation for Python protocols."""
|
|
725
|
+
|
|
726
|
+
_sync_module_hardware: SynchronousAdapter[hw_modules.FlexStacker]
|
|
727
|
+
|
|
728
|
+
def retrieve(self) -> LabwareCore:
|
|
729
|
+
"""Retrieve a labware from the Flex Stacker's hopper.
|
|
730
|
+
|
|
731
|
+
Returns the primary labware.
|
|
732
|
+
"""
|
|
733
|
+
self._engine_client.execute_command(
|
|
734
|
+
cmd.flex_stacker.RetrieveParams(
|
|
735
|
+
moduleId=self.module_id,
|
|
736
|
+
)
|
|
737
|
+
)
|
|
738
|
+
base = self._protocol_core.get_labware_on_module(self)
|
|
739
|
+
assert base, "Retrieve failed to provide a labware"
|
|
740
|
+
if base.is_adapter():
|
|
741
|
+
primary = self._protocol_core.get_labware_on_labware(base)
|
|
742
|
+
if primary:
|
|
743
|
+
return primary
|
|
744
|
+
return base
|
|
745
|
+
|
|
746
|
+
def store(self) -> None:
|
|
747
|
+
"""Store a labware into Flex Stacker's hopper."""
|
|
748
|
+
self._engine_client.execute_command(
|
|
749
|
+
cmd.flex_stacker.StoreParams(
|
|
750
|
+
moduleId=self.module_id,
|
|
751
|
+
strategy=StackerLabwareMovementStrategy.AUTOMATIC,
|
|
752
|
+
)
|
|
753
|
+
)
|
|
754
|
+
|
|
755
|
+
def fill(self, count: int | None, message: str | None) -> None:
|
|
756
|
+
"""Pause the protocol to add more labware to the Flex Stacker's hopper."""
|
|
757
|
+
self._engine_client.execute_command(
|
|
758
|
+
cmd.flex_stacker.FillParams(
|
|
759
|
+
moduleId=self.module_id,
|
|
760
|
+
strategy=StackerFillEmptyStrategy.MANUAL_WITH_PAUSE,
|
|
761
|
+
message=message,
|
|
762
|
+
count=count,
|
|
763
|
+
)
|
|
764
|
+
)
|
|
765
|
+
|
|
766
|
+
def _core_groups_from_primary_core(self, labware: LabwareCore) -> _CoreTrio:
|
|
767
|
+
possible_adapter = self._protocol_core.get_labware_location(labware)
|
|
768
|
+
return _CoreTrio(
|
|
769
|
+
primary=labware,
|
|
770
|
+
adapter=(
|
|
771
|
+
possible_adapter if isinstance(possible_adapter, LabwareCore) else None
|
|
772
|
+
),
|
|
773
|
+
lid=self._protocol_core.get_labware_on_labware(labware),
|
|
774
|
+
)
|
|
775
|
+
|
|
776
|
+
def _group_from_core_group(
|
|
777
|
+
self, core_group: _CoreTrio
|
|
778
|
+
) -> StackerStoredLabwareGroup:
|
|
779
|
+
return StackerStoredLabwareGroup(
|
|
780
|
+
primaryLabwareId=core_group.primary.labware_id,
|
|
781
|
+
adapterLabwareId=(
|
|
782
|
+
core_group.adapter.labware_id if core_group.adapter else None
|
|
783
|
+
),
|
|
784
|
+
lidLabwareId=core_group.lid.labware_id if core_group.lid else None,
|
|
785
|
+
)
|
|
786
|
+
|
|
787
|
+
def _group_from_core(self, labware: LabwareCore) -> StackerStoredLabwareGroup:
|
|
788
|
+
return self._group_from_core_group(self._core_groups_from_primary_core(labware))
|
|
789
|
+
|
|
790
|
+
def fill_items(self, labware: Sequence[LabwareCore], message: str | None) -> None:
|
|
791
|
+
"""Pause the protocol to fill with a specific set of labware."""
|
|
792
|
+
groups = [self._group_from_core(core) for core in labware]
|
|
793
|
+
self._engine_client.execute_command(
|
|
794
|
+
cmd.flex_stacker.FillParams(
|
|
795
|
+
moduleId=self._module_id,
|
|
796
|
+
strategy=StackerFillEmptyStrategy.MANUAL_WITH_PAUSE,
|
|
797
|
+
message=message,
|
|
798
|
+
labwareToStore=groups,
|
|
799
|
+
count=None,
|
|
800
|
+
)
|
|
801
|
+
)
|
|
802
|
+
|
|
803
|
+
def empty(self, message: str | None) -> None:
|
|
804
|
+
"""Pause the protocol to remove labware from the Flex Stacker's hopper."""
|
|
805
|
+
self._engine_client.execute_command(
|
|
806
|
+
cmd.flex_stacker.EmptyParams(
|
|
807
|
+
moduleId=self.module_id,
|
|
808
|
+
strategy=StackerFillEmptyStrategy.MANUAL_WITH_PAUSE,
|
|
809
|
+
message=message,
|
|
810
|
+
count=0,
|
|
811
|
+
)
|
|
812
|
+
)
|
|
813
|
+
|
|
814
|
+
def get_max_storable_labware(self) -> int:
|
|
815
|
+
"""Get the total number of configured labware the stacker can store."""
|
|
816
|
+
max_lw = self._engine_client.state.modules.stacker_max_pool_count(
|
|
817
|
+
self._module_id
|
|
818
|
+
)
|
|
819
|
+
if max_lw is None:
|
|
820
|
+
location = self._engine_client.state.modules.get_location(self._module_id)
|
|
821
|
+
raise FlexStackerLabwarePoolNotYetDefinedError(
|
|
822
|
+
message=f"The Flex Stacker in {location} has not been configured yet and cannot be filled."
|
|
823
|
+
)
|
|
824
|
+
return max_lw
|
|
825
|
+
|
|
826
|
+
def get_current_storable_labware(self) -> int:
|
|
827
|
+
"""Get the amount of space currently available for labware."""
|
|
828
|
+
max_lw = self.get_max_storable_labware()
|
|
829
|
+
if max_lw is None:
|
|
830
|
+
location = self._engine_client.state.modules.get_location(self._module_id)
|
|
831
|
+
raise FlexStackerLabwarePoolNotYetDefinedError(
|
|
832
|
+
message=f"The Flex Stacker in {location} has not been configured yet and cannot be filled."
|
|
833
|
+
)
|
|
834
|
+
current = len(
|
|
835
|
+
self._engine_client.state.modules.stacker_contained_labware(self._module_id)
|
|
836
|
+
)
|
|
837
|
+
return max_lw - current
|
|
838
|
+
|
|
839
|
+
def _predict_storable_count(
|
|
840
|
+
self,
|
|
841
|
+
labwares: _CoreTrio,
|
|
842
|
+
overlap_offset: float | None = None,
|
|
843
|
+
) -> int:
|
|
844
|
+
definitions = (
|
|
845
|
+
self._engine_client.state.labware.stacker_labware_pool_to_ordered_list(
|
|
846
|
+
labwares.primary.get_engine_definition(),
|
|
847
|
+
labwares.lid.get_engine_definition() if labwares.lid else None,
|
|
848
|
+
labwares.adapter.get_engine_definition() if labwares.adapter else None,
|
|
849
|
+
)
|
|
850
|
+
)
|
|
851
|
+
pool_height = self._engine_client.state.geometry.get_height_of_labware_stack(
|
|
852
|
+
definitions
|
|
853
|
+
)
|
|
854
|
+
pool_overlap = (
|
|
855
|
+
overlap_offset
|
|
856
|
+
if overlap_offset is not None
|
|
857
|
+
else self._engine_client.state.labware.get_stacker_labware_overlap_offset(
|
|
858
|
+
definitions
|
|
859
|
+
).z
|
|
860
|
+
)
|
|
861
|
+
return self._engine_client.state.modules.stacker_max_pool_count_by_height(
|
|
862
|
+
self._module_id, pool_height, pool_overlap
|
|
863
|
+
)
|
|
864
|
+
|
|
865
|
+
def get_max_storable_labware_from_list(
|
|
866
|
+
self,
|
|
867
|
+
labware: Sequence[LabwareCore],
|
|
868
|
+
overlap_offset: float | None = None,
|
|
869
|
+
) -> Sequence[LabwareCore]:
|
|
870
|
+
"""Limit the passed list to how many labware can fit in a stacker."""
|
|
871
|
+
if not labware:
|
|
872
|
+
return labware
|
|
873
|
+
max_count: int
|
|
874
|
+
try:
|
|
875
|
+
# if the stacker has been configured, make sure the provided overlap
|
|
876
|
+
# offset, if any, matches the configured one
|
|
877
|
+
max_count = self.get_max_storable_labware()
|
|
878
|
+
if overlap_offset is not None:
|
|
879
|
+
self._engine_client.state.modules.validate_stacker_overlap_offset(
|
|
880
|
+
self._module_id, overlap_offset
|
|
881
|
+
)
|
|
882
|
+
except FlexStackerLabwarePoolNotYetDefinedError:
|
|
883
|
+
max_count = self._predict_storable_count(
|
|
884
|
+
self._core_groups_from_primary_core(labware[0]), overlap_offset
|
|
885
|
+
)
|
|
886
|
+
return labware[:max_count]
|
|
887
|
+
|
|
888
|
+
def get_current_storable_labware_from_list(
|
|
889
|
+
self,
|
|
890
|
+
labware: Sequence[LabwareCore],
|
|
891
|
+
) -> Sequence[LabwareCore]:
|
|
892
|
+
"""Limit the passed list to how many labware can fit in the stacker right now."""
|
|
893
|
+
if not labware:
|
|
894
|
+
return labware
|
|
895
|
+
storable = self.get_current_storable_labware()
|
|
896
|
+
return labware[:storable]
|
|
897
|
+
|
|
898
|
+
def get_stored_labware(self) -> Sequence[LabwareCore]:
|
|
899
|
+
"""Get the currently-stored primary labware from the stacker."""
|
|
900
|
+
stored_groups = self._engine_client.state.modules.stacker_contained_labware(
|
|
901
|
+
self._module_id
|
|
902
|
+
)
|
|
903
|
+
return [
|
|
904
|
+
self._protocol_core.add_or_get_labware_core(group.primaryLabwareId)
|
|
905
|
+
for group in stored_groups
|
|
906
|
+
]
|
|
907
|
+
|
|
908
|
+
@overload
|
|
909
|
+
def _ssld_from_core(
|
|
910
|
+
self, core: LabwareCore
|
|
911
|
+
) -> cmd.flex_stacker.StackerStoredLabwareDetails:
|
|
912
|
+
...
|
|
913
|
+
|
|
914
|
+
@overload
|
|
915
|
+
def _ssld_from_core(self, core: None) -> None:
|
|
916
|
+
...
|
|
917
|
+
|
|
918
|
+
def _ssld_from_core(
|
|
919
|
+
self, core: LabwareCore | None
|
|
920
|
+
) -> cmd.flex_stacker.StackerStoredLabwareDetails | None:
|
|
921
|
+
if not core:
|
|
922
|
+
return None
|
|
923
|
+
definition = core.get_engine_definition()
|
|
924
|
+
return cmd.flex_stacker.StackerStoredLabwareDetails(
|
|
925
|
+
loadName=definition.parameters.loadName,
|
|
926
|
+
namespace=definition.namespace,
|
|
927
|
+
version=definition.version,
|
|
928
|
+
)
|
|
929
|
+
|
|
930
|
+
def set_stored_labware_items(
|
|
931
|
+
self,
|
|
932
|
+
labware: Sequence[LabwareCore],
|
|
933
|
+
stacking_offset_z: float | None,
|
|
934
|
+
) -> None:
|
|
935
|
+
"""Configure the stacker to contain a set of labware."""
|
|
936
|
+
core_groups = [self._core_groups_from_primary_core(core) for core in labware]
|
|
937
|
+
if len(core_groups) < 1:
|
|
938
|
+
raise CommandPreconditionViolated(
|
|
939
|
+
"At least one labware must be passed to set_stored_labware_items"
|
|
940
|
+
)
|
|
941
|
+
stacker_groups = [
|
|
942
|
+
self._group_from_core_group(core_group) for core_group in core_groups
|
|
943
|
+
]
|
|
944
|
+
|
|
945
|
+
self._engine_client.execute_command(
|
|
946
|
+
cmd.flex_stacker.SetStoredLabwareParams(
|
|
947
|
+
moduleId=self.module_id,
|
|
948
|
+
initialCount=None,
|
|
949
|
+
initialStoredLabware=stacker_groups,
|
|
950
|
+
primaryLabware=self._ssld_from_core(core_groups[0].primary),
|
|
951
|
+
lidLabware=self._ssld_from_core(core_groups[0].lid),
|
|
952
|
+
adapterLabware=self._ssld_from_core(core_groups[0].adapter),
|
|
953
|
+
poolOverlapOverride=stacking_offset_z,
|
|
954
|
+
)
|
|
955
|
+
)
|
|
956
|
+
|
|
957
|
+
def set_stored_labware(
|
|
958
|
+
self,
|
|
959
|
+
main_load_name: str,
|
|
960
|
+
main_namespace: str | None,
|
|
961
|
+
main_version: int | None,
|
|
962
|
+
lid_load_name: str | None,
|
|
963
|
+
lid_namespace: str | None,
|
|
964
|
+
lid_version: int | None,
|
|
965
|
+
adapter_load_name: str | None,
|
|
966
|
+
adapter_namespace: str | None,
|
|
967
|
+
adapter_version: int | None,
|
|
968
|
+
count: int | None,
|
|
969
|
+
stacking_offset_z: float | None = None,
|
|
970
|
+
) -> None:
|
|
971
|
+
"""Configure the kind of labware that the stacker stores."""
|
|
972
|
+
|
|
973
|
+
custom_labware_params = (
|
|
974
|
+
self._engine_client.state.labware.find_custom_labware_load_params()
|
|
975
|
+
)
|
|
976
|
+
|
|
977
|
+
main_namespace, main_version = load_labware_params.resolve(
|
|
978
|
+
main_load_name,
|
|
979
|
+
main_namespace,
|
|
980
|
+
main_version,
|
|
981
|
+
custom_labware_params,
|
|
982
|
+
self._api_version,
|
|
983
|
+
)
|
|
984
|
+
main_labware = cmd.flex_stacker.StackerStoredLabwareDetails(
|
|
985
|
+
loadName=main_load_name, namespace=main_namespace, version=main_version
|
|
986
|
+
)
|
|
987
|
+
|
|
988
|
+
lid_labware: cmd.flex_stacker.StackerStoredLabwareDetails | None = None
|
|
989
|
+
|
|
990
|
+
if lid_load_name:
|
|
991
|
+
lid_namespace, lid_version = load_labware_params.resolve(
|
|
992
|
+
lid_load_name,
|
|
993
|
+
lid_namespace,
|
|
994
|
+
lid_version,
|
|
995
|
+
custom_labware_params,
|
|
996
|
+
self._api_version,
|
|
997
|
+
)
|
|
998
|
+
lid_labware = cmd.flex_stacker.StackerStoredLabwareDetails(
|
|
999
|
+
loadName=lid_load_name, namespace=lid_namespace, version=lid_version
|
|
1000
|
+
)
|
|
1001
|
+
|
|
1002
|
+
adapter_labware: cmd.flex_stacker.StackerStoredLabwareDetails | None = None
|
|
1003
|
+
|
|
1004
|
+
if adapter_load_name:
|
|
1005
|
+
adapter_namespace, adapter_version = load_labware_params.resolve(
|
|
1006
|
+
adapter_load_name,
|
|
1007
|
+
adapter_namespace,
|
|
1008
|
+
adapter_version,
|
|
1009
|
+
custom_labware_params,
|
|
1010
|
+
self._api_version,
|
|
1011
|
+
)
|
|
1012
|
+
adapter_labware = cmd.flex_stacker.StackerStoredLabwareDetails(
|
|
1013
|
+
loadName=adapter_load_name,
|
|
1014
|
+
namespace=adapter_namespace,
|
|
1015
|
+
version=adapter_version,
|
|
1016
|
+
)
|
|
1017
|
+
|
|
1018
|
+
self._engine_client.execute_command(
|
|
1019
|
+
cmd.flex_stacker.SetStoredLabwareParams(
|
|
1020
|
+
moduleId=self.module_id,
|
|
1021
|
+
initialCount=count,
|
|
1022
|
+
primaryLabware=main_labware,
|
|
1023
|
+
lidLabware=lid_labware,
|
|
1024
|
+
adapterLabware=adapter_labware,
|
|
1025
|
+
poolOverlapOverride=stacking_offset_z,
|
|
1026
|
+
)
|
|
1027
|
+
)
|