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,683 @@
|
|
|
1
|
+
"""ProtocolEngine class definition."""
|
|
2
|
+
|
|
3
|
+
from contextlib import AsyncExitStack
|
|
4
|
+
from logging import getLogger
|
|
5
|
+
from typing import Dict, Optional, Union, AsyncGenerator, Callable
|
|
6
|
+
|
|
7
|
+
from opentrons_shared_data.errors import (
|
|
8
|
+
ErrorCodes,
|
|
9
|
+
EnumeratedError,
|
|
10
|
+
)
|
|
11
|
+
from opentrons_shared_data.labware.labware_definition import LabwareDefinition
|
|
12
|
+
|
|
13
|
+
from opentrons.hardware_control import HardwareControlAPI
|
|
14
|
+
from opentrons.hardware_control.modules import AbstractModule as HardwareModuleAPI
|
|
15
|
+
from opentrons.hardware_control.types import PauseType as HardwarePauseType
|
|
16
|
+
|
|
17
|
+
from .actions.actions import (
|
|
18
|
+
ResumeFromRecoveryAction,
|
|
19
|
+
SetErrorRecoveryPolicyAction,
|
|
20
|
+
)
|
|
21
|
+
from .errors import ProtocolCommandFailedError, ErrorOccurrence, CommandNotAllowedError
|
|
22
|
+
from .errors.exceptions import EStopActivatedError
|
|
23
|
+
from .error_recovery_policy import ErrorRecoveryPolicy
|
|
24
|
+
from . import commands, slot_standardization, labware_offset_standardization
|
|
25
|
+
from .resources import ModelUtils, ModuleDataProvider, FileProvider
|
|
26
|
+
from .types import (
|
|
27
|
+
LabwareOffset,
|
|
28
|
+
LabwareOffsetCreate,
|
|
29
|
+
LegacyLabwareOffsetCreate,
|
|
30
|
+
LabwareUri,
|
|
31
|
+
ModuleModel,
|
|
32
|
+
Liquid,
|
|
33
|
+
HexColor,
|
|
34
|
+
PostRunHardwareState,
|
|
35
|
+
DeckConfigurationType,
|
|
36
|
+
)
|
|
37
|
+
from .execution import (
|
|
38
|
+
QueueWorker,
|
|
39
|
+
create_queue_worker,
|
|
40
|
+
DoorWatcher,
|
|
41
|
+
HardwareStopper,
|
|
42
|
+
)
|
|
43
|
+
from .state.state import StateStore, StateView
|
|
44
|
+
from .state.update_types import StateUpdate
|
|
45
|
+
from .plugins import AbstractPlugin, PluginStarter
|
|
46
|
+
from .actions import (
|
|
47
|
+
ActionDispatcher,
|
|
48
|
+
PlayAction,
|
|
49
|
+
PauseAction,
|
|
50
|
+
PauseSource,
|
|
51
|
+
StopAction,
|
|
52
|
+
FinishAction,
|
|
53
|
+
FinishErrorDetails,
|
|
54
|
+
QueueCommandAction,
|
|
55
|
+
AddLabwareOffsetAction,
|
|
56
|
+
AddLabwareDefinitionAction,
|
|
57
|
+
AddLiquidAction,
|
|
58
|
+
SetDeckConfigurationAction,
|
|
59
|
+
AddAddressableAreaAction,
|
|
60
|
+
AddModuleAction,
|
|
61
|
+
HardwareStoppedAction,
|
|
62
|
+
ResetTipsAction,
|
|
63
|
+
SetPipetteMovementSpeedAction,
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
_log = getLogger(__name__)
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
class ProtocolEngine:
|
|
71
|
+
"""Main ProtocolEngine class.
|
|
72
|
+
|
|
73
|
+
A ProtocolEngine instance holds the state of a protocol as it executes,
|
|
74
|
+
and manages calls to a command executor that actually implements the logic
|
|
75
|
+
of the commands themselves.
|
|
76
|
+
|
|
77
|
+
Lifetime:
|
|
78
|
+
Instances are single-use. Each instance is associated with a single protocol,
|
|
79
|
+
or a a single chain of robot control such as Labware Position Check.
|
|
80
|
+
|
|
81
|
+
Concurrency:
|
|
82
|
+
Instances live in `asyncio` event loops. Each instance must be constructed inside an
|
|
83
|
+
event loop, and then must be interacted with exclusively through that
|
|
84
|
+
event loop's thread--even for regular non-`async` methods, like `.pause()`.
|
|
85
|
+
(This is because there are background async tasks that monitor state changes using
|
|
86
|
+
primitives that aren't thread-safe. See ChangeNotifier.)
|
|
87
|
+
"""
|
|
88
|
+
|
|
89
|
+
def __init__(
|
|
90
|
+
self,
|
|
91
|
+
hardware_api: HardwareControlAPI,
|
|
92
|
+
state_store: StateStore,
|
|
93
|
+
action_dispatcher: ActionDispatcher,
|
|
94
|
+
plugin_starter: PluginStarter,
|
|
95
|
+
model_utils: ModelUtils,
|
|
96
|
+
hardware_stopper: HardwareStopper,
|
|
97
|
+
door_watcher: DoorWatcher,
|
|
98
|
+
module_data_provider: ModuleDataProvider,
|
|
99
|
+
file_provider: FileProvider,
|
|
100
|
+
queue_worker: Optional[QueueWorker] = None,
|
|
101
|
+
) -> None:
|
|
102
|
+
"""Initialize a ProtocolEngine instance.
|
|
103
|
+
|
|
104
|
+
Must be called while an event loop is active.
|
|
105
|
+
|
|
106
|
+
This constructor is only for `ProtocolEngine` unit tests.
|
|
107
|
+
Prefer the `create_protocol_engine()` factory function.
|
|
108
|
+
"""
|
|
109
|
+
self._hardware_api = hardware_api
|
|
110
|
+
self._file_provider = file_provider
|
|
111
|
+
self._state_store = state_store
|
|
112
|
+
self._model_utils = model_utils
|
|
113
|
+
self._action_dispatcher = action_dispatcher
|
|
114
|
+
self._plugin_starter = plugin_starter
|
|
115
|
+
self._hardware_stopper = hardware_stopper
|
|
116
|
+
self._door_watcher = door_watcher
|
|
117
|
+
self._module_data_provider = module_data_provider
|
|
118
|
+
self._queue_worker = queue_worker
|
|
119
|
+
if self._queue_worker:
|
|
120
|
+
self._queue_worker.start()
|
|
121
|
+
self._door_watcher.start()
|
|
122
|
+
|
|
123
|
+
@property
|
|
124
|
+
def state_view(self) -> StateView:
|
|
125
|
+
"""Get an interface to retrieve calculated state values."""
|
|
126
|
+
return self._state_store
|
|
127
|
+
|
|
128
|
+
@property
|
|
129
|
+
def _get_queue_worker(self) -> QueueWorker:
|
|
130
|
+
"""Get the queue worker instance."""
|
|
131
|
+
assert self._queue_worker is not None
|
|
132
|
+
return self._queue_worker
|
|
133
|
+
|
|
134
|
+
def add_plugin(self, plugin: AbstractPlugin) -> None:
|
|
135
|
+
"""Add a plugin to the engine to customize behavior."""
|
|
136
|
+
self._plugin_starter.start(plugin)
|
|
137
|
+
|
|
138
|
+
def set_deck_configuration(
|
|
139
|
+
self, deck_configuration: Optional[DeckConfigurationType]
|
|
140
|
+
) -> None:
|
|
141
|
+
"""Inform the engine of the robot's current deck configuration.
|
|
142
|
+
|
|
143
|
+
If `Config.use_simulated_deck_config` is `True`, this is meaningless and unused.
|
|
144
|
+
You can call this with `None` if you want to be explicit--it will no-op.
|
|
145
|
+
|
|
146
|
+
If `Config.use_simulated_deck_config` is `False`, you should call this with the
|
|
147
|
+
robot's actual, full, non-`None` deck configuration, before you play the run for
|
|
148
|
+
the first time. Do not call this in the middle of a run.
|
|
149
|
+
"""
|
|
150
|
+
self._action_dispatcher.dispatch(SetDeckConfigurationAction(deck_configuration))
|
|
151
|
+
|
|
152
|
+
def play(self) -> None:
|
|
153
|
+
"""Start or resume executing commands in the queue."""
|
|
154
|
+
requested_at = self._model_utils.get_timestamp()
|
|
155
|
+
# TODO(mc, 2021-08-05): if starting, ensure plungers motors are
|
|
156
|
+
# homed if necessary
|
|
157
|
+
action = self._state_store.commands.validate_action_allowed(
|
|
158
|
+
PlayAction(requested_at=requested_at)
|
|
159
|
+
)
|
|
160
|
+
self._action_dispatcher.dispatch(action)
|
|
161
|
+
|
|
162
|
+
if self._state_store.commands.get_is_door_blocking():
|
|
163
|
+
self._hardware_api.pause(HardwarePauseType.PAUSE)
|
|
164
|
+
else:
|
|
165
|
+
self._hardware_api.resume(HardwarePauseType.PAUSE)
|
|
166
|
+
|
|
167
|
+
def request_pause(self) -> None:
|
|
168
|
+
"""Make command execution pause soon.
|
|
169
|
+
|
|
170
|
+
This will try to pause in the middle of the ongoing command, if there is one.
|
|
171
|
+
Otherwise, whenever the next command begins, the pause will happen then.
|
|
172
|
+
"""
|
|
173
|
+
action = self._state_store.commands.validate_action_allowed(
|
|
174
|
+
PauseAction(source=PauseSource.CLIENT)
|
|
175
|
+
)
|
|
176
|
+
self._action_dispatcher.dispatch(action)
|
|
177
|
+
self._hardware_api.pause(HardwarePauseType.PAUSE)
|
|
178
|
+
|
|
179
|
+
def resume_from_recovery(self, reconcile_false_positive: bool) -> None:
|
|
180
|
+
"""Resume normal protocol execution after the engine was `AWAITING_RECOVERY`.
|
|
181
|
+
|
|
182
|
+
If `reconcile_false_positive` is `False`, the engine will continue naively from
|
|
183
|
+
whatever state the error left it in. (Each defined error individually documents
|
|
184
|
+
exactly how it affects state.) This is appropriate for client-driven error
|
|
185
|
+
recovery, where the client wants predictable behavior from the engine.
|
|
186
|
+
|
|
187
|
+
If `reconcile_false_positive` is `True`, the engine may apply additional fixups
|
|
188
|
+
to its state to try to get the rest of the run to just work, assuming the error
|
|
189
|
+
was a false-positive.
|
|
190
|
+
|
|
191
|
+
For example, a `tipPhysicallyMissing` error from a `pickUpTip` would normally
|
|
192
|
+
leave the engine state without a tip on the pipette. If `reconcile_false_positive=True`,
|
|
193
|
+
the engine will set the pipette to have that missing tip before continuing, so
|
|
194
|
+
subsequent path planning, aspirates, dispenses, etc. will work as if nothing
|
|
195
|
+
went wrong.
|
|
196
|
+
"""
|
|
197
|
+
if reconcile_false_positive:
|
|
198
|
+
state_update = (
|
|
199
|
+
self._state_store.commands.get_state_update_for_false_positive()
|
|
200
|
+
)
|
|
201
|
+
else:
|
|
202
|
+
state_update = StateUpdate() # Empty/no-op.
|
|
203
|
+
|
|
204
|
+
action = self._state_store.commands.validate_action_allowed(
|
|
205
|
+
ResumeFromRecoveryAction(state_update)
|
|
206
|
+
)
|
|
207
|
+
|
|
208
|
+
self._action_dispatcher.dispatch(action)
|
|
209
|
+
|
|
210
|
+
def add_command(
|
|
211
|
+
self, request: commands.CommandCreate, failed_command_id: Optional[str] = None
|
|
212
|
+
) -> commands.Command:
|
|
213
|
+
"""Add a command to the `ProtocolEngine`'s queue.
|
|
214
|
+
|
|
215
|
+
Arguments:
|
|
216
|
+
request: The command type and payload data used to construct
|
|
217
|
+
the command in state.
|
|
218
|
+
|
|
219
|
+
Returns:
|
|
220
|
+
The full, newly queued command.
|
|
221
|
+
|
|
222
|
+
Raises:
|
|
223
|
+
SetupCommandNotAllowed: the request specified a setup command,
|
|
224
|
+
but the engine was not idle or paused.
|
|
225
|
+
RunStoppedError: the run has been stopped, so no new commands
|
|
226
|
+
may be added.
|
|
227
|
+
CommandNotAllowedError: the request specified a failed command id
|
|
228
|
+
with a non fixit command.
|
|
229
|
+
"""
|
|
230
|
+
request = slot_standardization.standardize_command(
|
|
231
|
+
request, self.state_view.config.robot_type
|
|
232
|
+
)
|
|
233
|
+
|
|
234
|
+
if failed_command_id and request.intent != commands.CommandIntent.FIXIT:
|
|
235
|
+
raise CommandNotAllowedError(
|
|
236
|
+
"failed command id should be supplied with a FIXIT command."
|
|
237
|
+
)
|
|
238
|
+
|
|
239
|
+
command_id = self._model_utils.generate_id()
|
|
240
|
+
if request.intent in (
|
|
241
|
+
commands.CommandIntent.SETUP,
|
|
242
|
+
commands.CommandIntent.FIXIT,
|
|
243
|
+
):
|
|
244
|
+
request_hash = None
|
|
245
|
+
else:
|
|
246
|
+
request_hash = commands.hash_protocol_command_params(
|
|
247
|
+
create=request,
|
|
248
|
+
last_hash=self._state_store.commands.get_latest_protocol_command_hash(),
|
|
249
|
+
)
|
|
250
|
+
|
|
251
|
+
action = self.state_view.commands.validate_action_allowed(
|
|
252
|
+
QueueCommandAction(
|
|
253
|
+
request=request,
|
|
254
|
+
request_hash=request_hash,
|
|
255
|
+
command_id=command_id,
|
|
256
|
+
created_at=self._model_utils.get_timestamp(),
|
|
257
|
+
failed_command_id=failed_command_id,
|
|
258
|
+
)
|
|
259
|
+
)
|
|
260
|
+
self._action_dispatcher.dispatch(action)
|
|
261
|
+
return self._state_store.commands.get(command_id)
|
|
262
|
+
|
|
263
|
+
async def wait_for_command(self, command_id: str) -> None:
|
|
264
|
+
"""Wait for a command to be completed.
|
|
265
|
+
|
|
266
|
+
Will also return if the engine was stopped before it reached the command.
|
|
267
|
+
"""
|
|
268
|
+
await self._state_store.wait_for(
|
|
269
|
+
self._state_store.commands.get_command_is_final,
|
|
270
|
+
command_id=command_id,
|
|
271
|
+
)
|
|
272
|
+
|
|
273
|
+
async def add_and_execute_command(
|
|
274
|
+
self, request: commands.CommandCreate
|
|
275
|
+
) -> commands.Command:
|
|
276
|
+
"""Add a command to the queue and wait for it to complete.
|
|
277
|
+
|
|
278
|
+
The engine must be started by calling `play` before the command will
|
|
279
|
+
execute. You only need to call `play` once.
|
|
280
|
+
|
|
281
|
+
Arguments:
|
|
282
|
+
request: The command type and payload data used to construct
|
|
283
|
+
the command in state.
|
|
284
|
+
|
|
285
|
+
Returns:
|
|
286
|
+
The command.
|
|
287
|
+
|
|
288
|
+
If the command completed, it will be succeeded or failed.
|
|
289
|
+
|
|
290
|
+
If the engine was stopped before it reached the command,
|
|
291
|
+
the command will be queued.
|
|
292
|
+
"""
|
|
293
|
+
command = self.add_command(request)
|
|
294
|
+
await self.wait_for_command(command.id)
|
|
295
|
+
return self._state_store.commands.get(command.id)
|
|
296
|
+
|
|
297
|
+
async def add_and_execute_command_wait_for_recovery(
|
|
298
|
+
self, request: commands.CommandCreate
|
|
299
|
+
) -> commands.Command:
|
|
300
|
+
"""Like `add_and_execute_command()`, except wait for error recovery.
|
|
301
|
+
|
|
302
|
+
Unlike `add_and_execute_command()`, if the command fails, this will not
|
|
303
|
+
immediately return the failed command. Instead, if the error is recoverable,
|
|
304
|
+
it will wait until error recovery has completed (e.g. when some other task
|
|
305
|
+
calls `self.resume_from_recovery()`).
|
|
306
|
+
|
|
307
|
+
Returns:
|
|
308
|
+
The command.
|
|
309
|
+
|
|
310
|
+
If the command completed, it will be succeeded or failed. If it failed
|
|
311
|
+
and then its failure was recovered from, it will still be failed.
|
|
312
|
+
|
|
313
|
+
If the engine was stopped before it reached the command,
|
|
314
|
+
the command will be queued.
|
|
315
|
+
"""
|
|
316
|
+
queued_command = self.add_command(request)
|
|
317
|
+
await self.wait_for_command(command_id=queued_command.id)
|
|
318
|
+
completed_command = self._state_store.commands.get(queued_command.id)
|
|
319
|
+
await self._state_store.wait_for_not(
|
|
320
|
+
self.state_view.commands.get_recovery_in_progress_for_command,
|
|
321
|
+
queued_command.id,
|
|
322
|
+
)
|
|
323
|
+
return completed_command
|
|
324
|
+
|
|
325
|
+
def estop(self) -> None:
|
|
326
|
+
"""Signal to the engine that an E-stop event occurred.
|
|
327
|
+
|
|
328
|
+
If an estop happens while the robot is moving, lower layers physically stop
|
|
329
|
+
motion and raise the event as an exception, which fails the Protocol Engine
|
|
330
|
+
command. No action from the `ProtocolEngine` caller is needed to handle that.
|
|
331
|
+
|
|
332
|
+
However, if an estop happens in between commands, or in the middle of
|
|
333
|
+
a command like `comment` or `waitForDuration` that doesn't access the hardware,
|
|
334
|
+
`ProtocolEngine` needs to be told about it so it can interrupt the command
|
|
335
|
+
and stop executing any more. This method is how to do that.
|
|
336
|
+
|
|
337
|
+
This acts roughly like `request_stop()`. After calling this, you should call
|
|
338
|
+
`finish()` with an EStopActivatedError.
|
|
339
|
+
"""
|
|
340
|
+
try:
|
|
341
|
+
action = self._state_store.commands.validate_action_allowed(
|
|
342
|
+
StopAction(from_estop=True)
|
|
343
|
+
)
|
|
344
|
+
except Exception: # todo(mm, 2024-04-16): Catch a more specific type.
|
|
345
|
+
# This is likely called from some hardware API callback that doesn't care
|
|
346
|
+
# about ProtocolEngine lifecycle or what methods are valid to call at what
|
|
347
|
+
# times. So it makes more sense for us to no-op here than to propagate this
|
|
348
|
+
# as an error.
|
|
349
|
+
_log.info(
|
|
350
|
+
"ProtocolEngine cannot handle E-stop event right now. Ignoring it.",
|
|
351
|
+
exc_info=True,
|
|
352
|
+
)
|
|
353
|
+
return
|
|
354
|
+
self._action_dispatcher.dispatch(action)
|
|
355
|
+
# self._queue_worker.cancel() will try to interrupt any ongoing command.
|
|
356
|
+
# Unfortunately, if it's a hardware command, this interruption will race
|
|
357
|
+
# against the E-stop exception propagating up from lower layers. But we need to
|
|
358
|
+
# do this because we want to make sure non-hardware commands, like
|
|
359
|
+
# `waitForDuration`, are also interrupted.
|
|
360
|
+
self._get_queue_worker.cancel()
|
|
361
|
+
# Unlike self.request_stop(), we don't need to do
|
|
362
|
+
# self._hardware_api.cancel_execution_and_running_tasks(). Since this was an
|
|
363
|
+
# E-stop event, the hardware API already knows.
|
|
364
|
+
|
|
365
|
+
async def request_stop(self) -> None:
|
|
366
|
+
"""Make command execution stop soon.
|
|
367
|
+
|
|
368
|
+
This will try to interrupt the ongoing command, if there is one. Future commands
|
|
369
|
+
are canceled. However, by the time this method returns, things may not have
|
|
370
|
+
settled by the time this method returns; the last command may still be
|
|
371
|
+
running.
|
|
372
|
+
|
|
373
|
+
After a stop has been requested, the engine cannot be restarted.
|
|
374
|
+
|
|
375
|
+
After a stop request, you must still call `finish` to give the engine a chance
|
|
376
|
+
to clean up resources and propagate errors.
|
|
377
|
+
"""
|
|
378
|
+
action = self._state_store.commands.validate_action_allowed(StopAction())
|
|
379
|
+
self._action_dispatcher.dispatch(action)
|
|
380
|
+
self._get_queue_worker.cancel()
|
|
381
|
+
if self._hardware_api.is_movement_execution_taskified():
|
|
382
|
+
# We 'taskify' hardware controller movement functions when running protocols
|
|
383
|
+
# that are not backed by the engine. Such runs cannot be stopped by cancelling
|
|
384
|
+
# the queue worker and hence need to be stopped via the execution manager.
|
|
385
|
+
# `cancel_execution_and_running_tasks()` sets the execution manager in a CANCELLED state
|
|
386
|
+
# and cancels the running tasks, which raises an error and gets us out of the
|
|
387
|
+
# run function execution, just like `_queue_worker.cancel()` does for
|
|
388
|
+
# engine-backed runs.
|
|
389
|
+
await self._hardware_api.cancel_execution_and_running_tasks()
|
|
390
|
+
|
|
391
|
+
async def wait_until_complete(self) -> None:
|
|
392
|
+
"""Wait until there are no more commands to execute.
|
|
393
|
+
|
|
394
|
+
If a command encountered a fatal error, it's raised as an exception.
|
|
395
|
+
"""
|
|
396
|
+
await self._state_store.wait_for(
|
|
397
|
+
condition=self._state_store.commands.get_all_commands_final
|
|
398
|
+
)
|
|
399
|
+
self._state_store.commands.raise_fatal_command_error()
|
|
400
|
+
|
|
401
|
+
async def finish(
|
|
402
|
+
self,
|
|
403
|
+
error: Optional[Exception] = None,
|
|
404
|
+
drop_tips_after_run: bool = True,
|
|
405
|
+
set_run_status: bool = True,
|
|
406
|
+
post_run_hardware_state: PostRunHardwareState = PostRunHardwareState.HOME_AND_STAY_ENGAGED,
|
|
407
|
+
) -> None:
|
|
408
|
+
"""Finish using the `ProtocolEngine`.
|
|
409
|
+
|
|
410
|
+
This does a few things:
|
|
411
|
+
|
|
412
|
+
1. It may do post-run actions like homing and dropping tips. This depends on the
|
|
413
|
+
arguments passed as well as heuristics based on the history of the engine.
|
|
414
|
+
2. It waits for the engine to be done controlling the robot's hardware.
|
|
415
|
+
3. It releases internal resources, like background tasks.
|
|
416
|
+
|
|
417
|
+
It's safe to call `finish()` multiple times. After you call `finish()`,
|
|
418
|
+
the engine can't be restarted.
|
|
419
|
+
|
|
420
|
+
This method should not raise. If any exceptions happened during execution that were not
|
|
421
|
+
properly caught by `ProtocolEngine` internals, or if any exceptions happen during this
|
|
422
|
+
`finish()` call, they should be saved as `.state_view.get_summary().errors`.
|
|
423
|
+
|
|
424
|
+
Arguments:
|
|
425
|
+
error: An error that caused the stop, if applicable.
|
|
426
|
+
drop_tips_after_run: Whether to drop tips as part of cleanup.
|
|
427
|
+
set_run_status: Whether to calculate a `success` or `failure` run status.
|
|
428
|
+
If `False`, will set status to `stopped`.
|
|
429
|
+
post_run_hardware_state: The state in which to leave the gantry and motors in
|
|
430
|
+
after the run is over.
|
|
431
|
+
"""
|
|
432
|
+
if self._state_store.commands.get_is_stopped_by_estop():
|
|
433
|
+
# This handles the case where the E-stop was pressed while we were *not* in the middle
|
|
434
|
+
# of some hardware interaction that would raise it as an exception. For example, imagine
|
|
435
|
+
# we were paused between two commands, or imagine we were executing a waitForDuration.
|
|
436
|
+
drop_tips_after_run = False
|
|
437
|
+
post_run_hardware_state = PostRunHardwareState.DISENGAGE_IN_PLACE
|
|
438
|
+
if error is None:
|
|
439
|
+
error = EStopActivatedError()
|
|
440
|
+
|
|
441
|
+
if error:
|
|
442
|
+
# If the run had an error, check if that error indicates an E-stop.
|
|
443
|
+
# This handles the case where the run was in the middle of some hardware control
|
|
444
|
+
# method and the hardware controller raised an E-stop error from it.
|
|
445
|
+
#
|
|
446
|
+
# To do this, we need to scan all the way through the error tree.
|
|
447
|
+
# By the time E-stop error has gotten to us, it may have been wrapped in other errors,
|
|
448
|
+
# so we need to unwrap them to uncover the E-stop error's inner beauty.
|
|
449
|
+
#
|
|
450
|
+
# We don't use self._hardware_api.get_estop_state() because the E-stop may have been
|
|
451
|
+
# released by the time we get here.
|
|
452
|
+
if isinstance(error, EnumeratedError):
|
|
453
|
+
if code_in_error_tree(
|
|
454
|
+
root_error=error, code=ErrorCodes.E_STOP_ACTIVATED
|
|
455
|
+
) or code_in_error_tree(
|
|
456
|
+
# Request from the hardware team for the v7.0 betas: to help in-house debugging
|
|
457
|
+
# of pipette overpressure events, leave the pipette where it was like we do
|
|
458
|
+
# for E-stops.
|
|
459
|
+
root_error=error,
|
|
460
|
+
code=ErrorCodes.PIPETTE_OVERPRESSURE,
|
|
461
|
+
):
|
|
462
|
+
drop_tips_after_run = False
|
|
463
|
+
post_run_hardware_state = PostRunHardwareState.DISENGAGE_IN_PLACE
|
|
464
|
+
|
|
465
|
+
error_details: Optional[FinishErrorDetails] = FinishErrorDetails(
|
|
466
|
+
error_id=self._model_utils.generate_id(),
|
|
467
|
+
created_at=self._model_utils.get_timestamp(),
|
|
468
|
+
error=error,
|
|
469
|
+
)
|
|
470
|
+
else:
|
|
471
|
+
error_details = None
|
|
472
|
+
|
|
473
|
+
self._action_dispatcher.dispatch(
|
|
474
|
+
FinishAction(error_details=error_details, set_run_status=set_run_status)
|
|
475
|
+
)
|
|
476
|
+
|
|
477
|
+
# We have a lot of independent things to tear down. If any teardown fails, we want
|
|
478
|
+
# to continue with the rest, to avoid leaking resources or leaving the engine with a broken
|
|
479
|
+
# state. We use an AsyncExitStack to avoid a gigantic try/finally tree. Note that execution
|
|
480
|
+
# order will be backwards because the stack is first-in-last-out.
|
|
481
|
+
exit_stack = AsyncExitStack()
|
|
482
|
+
exit_stack.push_async_callback(self._plugin_starter.stop) # Last step.
|
|
483
|
+
exit_stack.push_async_callback(
|
|
484
|
+
# Cleanup after hardware halt and reset the hardware controller
|
|
485
|
+
self._hardware_stopper.do_stop_and_recover,
|
|
486
|
+
post_run_hardware_state=post_run_hardware_state,
|
|
487
|
+
drop_tips_after_run=drop_tips_after_run,
|
|
488
|
+
)
|
|
489
|
+
exit_stack.callback(self._door_watcher.stop)
|
|
490
|
+
|
|
491
|
+
disengage_before_stopping = (
|
|
492
|
+
False
|
|
493
|
+
if post_run_hardware_state == PostRunHardwareState.STAY_ENGAGED_IN_PLACE
|
|
494
|
+
else True
|
|
495
|
+
)
|
|
496
|
+
# Halt any movements immediately
|
|
497
|
+
exit_stack.push_async_callback(
|
|
498
|
+
self._hardware_stopper.do_halt,
|
|
499
|
+
disengage_before_stopping=disengage_before_stopping,
|
|
500
|
+
)
|
|
501
|
+
exit_stack.push_async_callback(self._get_queue_worker.join) # First step.
|
|
502
|
+
try:
|
|
503
|
+
# If any teardown steps failed, this will raise something.
|
|
504
|
+
await exit_stack.aclose()
|
|
505
|
+
except Exception as hardware_stopped_exception:
|
|
506
|
+
_log.exception("Exception during post-run finish steps.")
|
|
507
|
+
finish_error_details: Optional[FinishErrorDetails] = FinishErrorDetails(
|
|
508
|
+
error_id=self._model_utils.generate_id(),
|
|
509
|
+
created_at=self._model_utils.get_timestamp(),
|
|
510
|
+
error=hardware_stopped_exception,
|
|
511
|
+
)
|
|
512
|
+
else:
|
|
513
|
+
finish_error_details = None
|
|
514
|
+
|
|
515
|
+
self._action_dispatcher.dispatch(
|
|
516
|
+
HardwareStoppedAction(
|
|
517
|
+
completed_at=self._model_utils.get_timestamp(),
|
|
518
|
+
finish_error_details=finish_error_details,
|
|
519
|
+
)
|
|
520
|
+
)
|
|
521
|
+
|
|
522
|
+
def add_labware_offset(
|
|
523
|
+
self, request: LabwareOffsetCreate | LegacyLabwareOffsetCreate
|
|
524
|
+
) -> LabwareOffset:
|
|
525
|
+
"""Add a new labware offset and return it.
|
|
526
|
+
|
|
527
|
+
The added offset will apply to subsequent `LoadLabwareCommand`s.
|
|
528
|
+
|
|
529
|
+
To retrieve offsets later, see `.state_view.labware`.
|
|
530
|
+
"""
|
|
531
|
+
internal_request = (
|
|
532
|
+
labware_offset_standardization.standardize_labware_offset_create(
|
|
533
|
+
request,
|
|
534
|
+
self.state_view.config.robot_type,
|
|
535
|
+
self.state_view.addressable_areas.deck_definition,
|
|
536
|
+
)
|
|
537
|
+
)
|
|
538
|
+
|
|
539
|
+
labware_offset_id = self._model_utils.generate_id()
|
|
540
|
+
created_at = self._model_utils.get_timestamp()
|
|
541
|
+
self._action_dispatcher.dispatch(
|
|
542
|
+
AddLabwareOffsetAction(
|
|
543
|
+
labware_offset_id=labware_offset_id,
|
|
544
|
+
created_at=created_at,
|
|
545
|
+
request=internal_request,
|
|
546
|
+
)
|
|
547
|
+
)
|
|
548
|
+
return self.state_view.labware.get_labware_offset(
|
|
549
|
+
labware_offset_id=labware_offset_id
|
|
550
|
+
)
|
|
551
|
+
|
|
552
|
+
def add_labware_definition(self, definition: LabwareDefinition) -> LabwareUri:
|
|
553
|
+
"""Add a labware definition to the state for subsequent labware loads."""
|
|
554
|
+
self._action_dispatcher.dispatch(
|
|
555
|
+
AddLabwareDefinitionAction(definition=definition)
|
|
556
|
+
)
|
|
557
|
+
return self._state_store.labware.get_uri_from_definition(definition)
|
|
558
|
+
|
|
559
|
+
def add_liquid(
|
|
560
|
+
self,
|
|
561
|
+
name: str,
|
|
562
|
+
color: Optional[HexColor],
|
|
563
|
+
description: Optional[str],
|
|
564
|
+
id: Optional[str] = None,
|
|
565
|
+
) -> Liquid:
|
|
566
|
+
"""Add a liquid to the state for subsequent liquid loads."""
|
|
567
|
+
if id is None:
|
|
568
|
+
id = self._model_utils.generate_id()
|
|
569
|
+
|
|
570
|
+
liquid = Liquid(
|
|
571
|
+
id=id,
|
|
572
|
+
displayName=name,
|
|
573
|
+
description=(description or ""),
|
|
574
|
+
displayColor=color,
|
|
575
|
+
)
|
|
576
|
+
validated_liquid = self._state_store.liquid.validate_liquid_allowed(
|
|
577
|
+
liquid=liquid
|
|
578
|
+
)
|
|
579
|
+
|
|
580
|
+
self._action_dispatcher.dispatch(AddLiquidAction(liquid=validated_liquid))
|
|
581
|
+
return validated_liquid
|
|
582
|
+
|
|
583
|
+
def add_addressable_area(self, addressable_area_name: str) -> None:
|
|
584
|
+
"""Add an addressable area to state."""
|
|
585
|
+
self._action_dispatcher.dispatch(
|
|
586
|
+
AddAddressableAreaAction(addressable_area_name)
|
|
587
|
+
)
|
|
588
|
+
|
|
589
|
+
def reset_tips(self, labware_id: str) -> None:
|
|
590
|
+
"""Reset the tip state of a given labware."""
|
|
591
|
+
# TODO(mm, 2023-03-10): Safely raise an error if the given labware isn't a
|
|
592
|
+
# tip rack?
|
|
593
|
+
self._action_dispatcher.dispatch(ResetTipsAction(labware_id=labware_id))
|
|
594
|
+
|
|
595
|
+
# TODO(mm, 2022-11-10): This is a method on ProtocolEngine instead of a command
|
|
596
|
+
# as a quick hack to support Python protocols. We should consider making this a
|
|
597
|
+
# command, or adding speed parameters to existing commands.
|
|
598
|
+
# https://opentrons.atlassian.net/browse/RCORE-373
|
|
599
|
+
def set_pipette_movement_speed(
|
|
600
|
+
self, pipette_id: str, speed: Optional[float]
|
|
601
|
+
) -> None:
|
|
602
|
+
"""Set the speed of a pipette's X/Y/Z movements. Does not affect plunger speed.
|
|
603
|
+
|
|
604
|
+
None will use the hardware API's default.
|
|
605
|
+
"""
|
|
606
|
+
self._action_dispatcher.dispatch(
|
|
607
|
+
SetPipetteMovementSpeedAction(pipette_id=pipette_id, speed=speed)
|
|
608
|
+
)
|
|
609
|
+
|
|
610
|
+
async def use_attached_modules(
|
|
611
|
+
self,
|
|
612
|
+
modules_by_id: Dict[str, HardwareModuleAPI],
|
|
613
|
+
) -> None:
|
|
614
|
+
"""Load attached modules directly into state, without locations."""
|
|
615
|
+
actions = [
|
|
616
|
+
AddModuleAction(
|
|
617
|
+
module_id=module_id,
|
|
618
|
+
serial_number=mod.device_info["serial"],
|
|
619
|
+
definition=self._module_data_provider.get_definition(
|
|
620
|
+
ModuleModel(mod.model())
|
|
621
|
+
),
|
|
622
|
+
module_live_data=mod.live_data,
|
|
623
|
+
)
|
|
624
|
+
for module_id, mod in modules_by_id.items()
|
|
625
|
+
]
|
|
626
|
+
|
|
627
|
+
for a in actions:
|
|
628
|
+
self._action_dispatcher.dispatch(a)
|
|
629
|
+
|
|
630
|
+
def set_and_start_queue_worker(
|
|
631
|
+
self, command_generator: Callable[[], AsyncGenerator[str, None]]
|
|
632
|
+
) -> None:
|
|
633
|
+
"""Set QueueWorker and start it."""
|
|
634
|
+
assert self._queue_worker is None
|
|
635
|
+
self._queue_worker = create_queue_worker(
|
|
636
|
+
hardware_api=self._hardware_api,
|
|
637
|
+
file_provider=self._file_provider,
|
|
638
|
+
state_store=self._state_store,
|
|
639
|
+
action_dispatcher=self._action_dispatcher,
|
|
640
|
+
command_generator=command_generator,
|
|
641
|
+
)
|
|
642
|
+
self._queue_worker.start()
|
|
643
|
+
|
|
644
|
+
def set_error_recovery_policy(self, policy: ErrorRecoveryPolicy) -> None:
|
|
645
|
+
"""Replace the run's error recovery policy with a new one."""
|
|
646
|
+
self._action_dispatcher.dispatch(SetErrorRecoveryPolicyAction(policy))
|
|
647
|
+
|
|
648
|
+
def clear_command_history(self) -> None:
|
|
649
|
+
"""Clear command history."""
|
|
650
|
+
self._state_store.clear_command_history()
|
|
651
|
+
|
|
652
|
+
|
|
653
|
+
# TODO(tz, 7-12-23): move this to shared data when we dont relay on ErrorOccurrence
|
|
654
|
+
def code_in_error_tree(
|
|
655
|
+
root_error: Union[EnumeratedError, ErrorOccurrence], code: ErrorCodes
|
|
656
|
+
) -> bool:
|
|
657
|
+
"""Check if the specified error code can be found in the given error tree."""
|
|
658
|
+
if isinstance(root_error, ErrorOccurrence):
|
|
659
|
+
# ErrorOccurrence is not the same as the enumerated error exceptions. Check the
|
|
660
|
+
# code by a string value.
|
|
661
|
+
if root_error.errorCode == code.value.code:
|
|
662
|
+
return True
|
|
663
|
+
return any(
|
|
664
|
+
code_in_error_tree(wrapped, code) for wrapped in root_error.wrappedErrors
|
|
665
|
+
)
|
|
666
|
+
|
|
667
|
+
# From here we have an exception, can just check the code + recurse to wrapped errors.
|
|
668
|
+
if root_error.code == code:
|
|
669
|
+
return True
|
|
670
|
+
|
|
671
|
+
if (
|
|
672
|
+
isinstance(root_error, ProtocolCommandFailedError)
|
|
673
|
+
and root_error.original_error is not None
|
|
674
|
+
):
|
|
675
|
+
# For this specific EnumeratedError child, we recurse on the original_error field
|
|
676
|
+
# in favor of the general error.wrapping field.
|
|
677
|
+
return code_in_error_tree(root_error.original_error, code)
|
|
678
|
+
|
|
679
|
+
if len(root_error.wrapping) == 0:
|
|
680
|
+
return False
|
|
681
|
+
return any(
|
|
682
|
+
code_in_error_tree(wrapped_error, code) for wrapped_error in root_error.wrapping
|
|
683
|
+
)
|