opentrons 8.6.0a1__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 +501 -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 +183 -0
- opentrons/drivers/asyncio/communication/errors.py +88 -0
- opentrons/drivers/asyncio/communication/serial_connection.py +552 -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/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 +215 -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 +1115 -0
- opentrons/motion_planning/__init__.py +32 -0
- opentrons/motion_planning/adjacent_slots_getters.py +168 -0
- opentrons/motion_planning/deck_conflict.py +396 -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 +348 -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 +1025 -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 +990 -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 +3212 -0
- opentrons/protocol_api/labware.py +1579 -0
- opentrons/protocol_api/module_contexts.py +1425 -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 +326 -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 +349 -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 +58 -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 +1158 -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 +2359 -0
- opentrons/protocol_engine/state/inner_well_math_utils.py +548 -0
- opentrons/protocol_engine/state/labware.py +1459 -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 +1500 -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 +308 -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 +303 -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 +848 -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.0a1.dist-info/METADATA +37 -0
- opentrons-8.6.0a1.dist-info/RECORD +600 -0
- opentrons-8.6.0a1.dist-info/WHEEL +4 -0
- opentrons-8.6.0a1.dist-info/entry_points.txt +3 -0
- opentrons-8.6.0a1.dist-info/licenses/LICENSE +202 -0
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
# this file defines types that require dev dependencies
|
|
4
|
+
# and are only relevant for static typechecking. this file should only
|
|
5
|
+
# be imported if typing.TYPE_CHECKING is True
|
|
6
|
+
from typing import Optional, Dict, List, Union
|
|
7
|
+
|
|
8
|
+
from typing_extensions import TypedDict, Literal
|
|
9
|
+
|
|
10
|
+
from opentrons.hardware_control.instruments.ot3.instrument_calibration import (
|
|
11
|
+
GripperCalibrationOffset,
|
|
12
|
+
)
|
|
13
|
+
from opentrons_shared_data.pipette.types import (
|
|
14
|
+
PipetteModel,
|
|
15
|
+
PipetteName,
|
|
16
|
+
ChannelCount,
|
|
17
|
+
)
|
|
18
|
+
from opentrons_shared_data.pipette.types import PipetteTipType
|
|
19
|
+
from opentrons_shared_data.pipette.pipette_definition import (
|
|
20
|
+
PipetteConfigurations,
|
|
21
|
+
SupportedTipsDefinition,
|
|
22
|
+
PipetteBoundingBoxOffsetDefinition,
|
|
23
|
+
AvailableSensorDefinition,
|
|
24
|
+
)
|
|
25
|
+
from opentrons_shared_data.gripper import (
|
|
26
|
+
GripperModel,
|
|
27
|
+
GripperDefinition,
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
from opentrons.drivers.types import MoveSplit
|
|
31
|
+
from opentrons.types import Mount
|
|
32
|
+
from opentrons.hardware_control.types import GripperJawState
|
|
33
|
+
from opentrons.hardware_control.nozzle_manager import NozzleMap
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class InstrumentSpec(TypedDict):
|
|
37
|
+
id: Optional[str]
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
class PipetteSpec(InstrumentSpec):
|
|
41
|
+
model: Union[PipetteModel, None]
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
class GripperSpec(InstrumentSpec):
|
|
45
|
+
model: Union[GripperModel, None]
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
class AttachedPipette(TypedDict):
|
|
49
|
+
config: Optional[PipetteConfigurations]
|
|
50
|
+
id: Optional[str]
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
class AttachedGripper(TypedDict):
|
|
54
|
+
config: Optional[GripperDefinition]
|
|
55
|
+
id: Optional[str]
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
AttachedInstruments = Dict[Mount, AttachedPipette]
|
|
59
|
+
|
|
60
|
+
OT3AttachedInstruments = Union[AttachedPipette, AttachedGripper]
|
|
61
|
+
|
|
62
|
+
EIGHT_CHANNELS = Literal[8]
|
|
63
|
+
ONE_CHANNEL = Literal[1]
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
class InstrumentDict(TypedDict):
|
|
67
|
+
display_name: str
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
class PipetteDict(InstrumentDict):
|
|
71
|
+
name: PipetteName
|
|
72
|
+
model: PipetteModel
|
|
73
|
+
back_compat_names: List[PipetteName]
|
|
74
|
+
pipette_id: str
|
|
75
|
+
min_volume: float
|
|
76
|
+
max_volume: float
|
|
77
|
+
channels: ChannelCount
|
|
78
|
+
aspirate_flow_rate: float
|
|
79
|
+
dispense_flow_rate: float
|
|
80
|
+
blow_out_flow_rate: float
|
|
81
|
+
aspirate_speed: float
|
|
82
|
+
dispense_speed: float
|
|
83
|
+
blow_out_speed: float
|
|
84
|
+
current_volume: float
|
|
85
|
+
tip_length: float
|
|
86
|
+
working_volume: float
|
|
87
|
+
tip_overlap: Dict[str, float]
|
|
88
|
+
versioned_tip_overlap: Dict[str, Dict[str, float]]
|
|
89
|
+
available_volume: float
|
|
90
|
+
return_tip_height: float
|
|
91
|
+
default_aspirate_flow_rates: Dict[str, float]
|
|
92
|
+
default_dispense_flow_rates: Dict[str, float]
|
|
93
|
+
default_blow_out_flow_rates: Dict[str, float]
|
|
94
|
+
default_aspirate_speeds: Dict[str, float]
|
|
95
|
+
default_dispense_speeds: Dict[str, float]
|
|
96
|
+
default_blow_out_speeds: Dict[str, float]
|
|
97
|
+
ready_to_aspirate: bool
|
|
98
|
+
has_tip: bool
|
|
99
|
+
default_push_out_volume: Optional[float]
|
|
100
|
+
supported_tips: Dict[PipetteTipType, SupportedTipsDefinition]
|
|
101
|
+
pipette_bounding_box_offsets: PipetteBoundingBoxOffsetDefinition
|
|
102
|
+
current_nozzle_map: NozzleMap
|
|
103
|
+
lld_settings: Optional[Dict[str, Dict[str, float]]]
|
|
104
|
+
plunger_positions: Dict[str, float]
|
|
105
|
+
shaft_ul_per_mm: float
|
|
106
|
+
available_sensors: AvailableSensorDefinition
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
class PipetteStateDict(TypedDict):
|
|
110
|
+
tip_detected: bool
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
class GripperDict(InstrumentDict):
|
|
114
|
+
model: GripperModel
|
|
115
|
+
gripper_id: str
|
|
116
|
+
state: GripperJawState # Can we call this jaw_state?
|
|
117
|
+
calibration_offset: GripperCalibrationOffset
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
class InstrumentHardwareConfigs(TypedDict):
|
|
121
|
+
steps_per_mm: float
|
|
122
|
+
home_pos: float
|
|
123
|
+
max_travel: float
|
|
124
|
+
idle_current: float
|
|
125
|
+
splits: Optional[MoveSplit]
|
|
File without changes
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
from abc import ABC, abstractmethod
|
|
2
|
+
from typing import Optional
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class AbstractEmulator(ABC):
|
|
6
|
+
"""Interface of gcode line processing hardware emulator."""
|
|
7
|
+
|
|
8
|
+
@abstractmethod
|
|
9
|
+
def handle(self, line: str) -> Optional[str]:
|
|
10
|
+
"""Handle a command and return a response."""
|
|
11
|
+
...
|
|
12
|
+
|
|
13
|
+
@staticmethod
|
|
14
|
+
def get_terminator() -> bytes:
|
|
15
|
+
"""Get the command terminator for messages coming from PI."""
|
|
16
|
+
return b"\r\n\r\n"
|
|
17
|
+
|
|
18
|
+
@staticmethod
|
|
19
|
+
def get_ack() -> bytes:
|
|
20
|
+
"""Get the command ack send to the PI."""
|
|
21
|
+
return b"ok\r\nok\r\n"
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
import logging
|
|
3
|
+
|
|
4
|
+
from opentrons.hardware_control.emulation.module_server import ModuleStatusServer
|
|
5
|
+
from opentrons.hardware_control.emulation.proxy import Proxy
|
|
6
|
+
from opentrons.hardware_control.emulation.settings import Settings
|
|
7
|
+
from opentrons.hardware_control.emulation.types import ModuleType
|
|
8
|
+
|
|
9
|
+
logger = logging.getLogger(__name__)
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class Application:
|
|
13
|
+
"""The emulator application."""
|
|
14
|
+
|
|
15
|
+
def __init__(self, settings: Settings) -> None:
|
|
16
|
+
"""Constructor.
|
|
17
|
+
|
|
18
|
+
Args:
|
|
19
|
+
settings: Application settings.
|
|
20
|
+
"""
|
|
21
|
+
self._settings = settings
|
|
22
|
+
self._status_server = ModuleStatusServer(settings.module_server)
|
|
23
|
+
self._magdeck = Proxy(
|
|
24
|
+
ModuleType.Magnetic, self._status_server, self._settings.magdeck_proxy
|
|
25
|
+
)
|
|
26
|
+
self._temperature = Proxy(
|
|
27
|
+
ModuleType.Temperature,
|
|
28
|
+
self._status_server,
|
|
29
|
+
self._settings.temperature_proxy,
|
|
30
|
+
)
|
|
31
|
+
self._thermocycler = Proxy(
|
|
32
|
+
ModuleType.Thermocycler,
|
|
33
|
+
self._status_server,
|
|
34
|
+
self._settings.thermocycler_proxy,
|
|
35
|
+
)
|
|
36
|
+
self._heatershaker = Proxy(
|
|
37
|
+
ModuleType.Heatershaker,
|
|
38
|
+
self._status_server,
|
|
39
|
+
self._settings.heatershaker_proxy,
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
async def run(self) -> None:
|
|
43
|
+
"""Run the application."""
|
|
44
|
+
await asyncio.gather(
|
|
45
|
+
self._status_server.run(),
|
|
46
|
+
self._magdeck.run(),
|
|
47
|
+
self._temperature.run(),
|
|
48
|
+
self._thermocycler.run(),
|
|
49
|
+
self._heatershaker.run(),
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
if __name__ == "__main__":
|
|
54
|
+
logging.basicConfig(format="%(asctime)s:%(message)s", level=logging.DEBUG)
|
|
55
|
+
s = Settings()
|
|
56
|
+
asyncio.run(Application(settings=s).run())
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"""The handler of a driver client connection."""
|
|
2
|
+
|
|
3
|
+
import asyncio
|
|
4
|
+
import logging
|
|
5
|
+
|
|
6
|
+
from opentrons.hardware_control.emulation.abstract_emulator import AbstractEmulator
|
|
7
|
+
|
|
8
|
+
logger = logging.getLogger(__name__)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class ConnectionHandler:
|
|
12
|
+
"""Responsible for reading data and routing it to an emulator."""
|
|
13
|
+
|
|
14
|
+
def __init__(self, emulator: AbstractEmulator):
|
|
15
|
+
"""Construct with an emulator."""
|
|
16
|
+
self._emulator = emulator
|
|
17
|
+
|
|
18
|
+
async def __call__(
|
|
19
|
+
self, reader: asyncio.StreamReader, writer: asyncio.StreamWriter
|
|
20
|
+
) -> None:
|
|
21
|
+
"""New connection callback."""
|
|
22
|
+
emulator_name = self._emulator.__class__.__name__
|
|
23
|
+
logger.debug("%s Connected.", emulator_name)
|
|
24
|
+
while True:
|
|
25
|
+
line = await reader.readuntil(self._emulator.get_terminator())
|
|
26
|
+
logger.debug("%s Received: %s", emulator_name, line)
|
|
27
|
+
try:
|
|
28
|
+
response = self._emulator.handle(line.decode().strip())
|
|
29
|
+
if response:
|
|
30
|
+
response = f"{response}\r\n"
|
|
31
|
+
logger.debug("%s Sending: %s", emulator_name, response)
|
|
32
|
+
writer.write(response.encode())
|
|
33
|
+
except Exception as e:
|
|
34
|
+
logger.exception("%s exception", emulator_name)
|
|
35
|
+
writer.write(f"Error: {str(e)}\r\n".encode())
|
|
36
|
+
|
|
37
|
+
writer.write(self._emulator.get_ack())
|
|
38
|
+
await writer.drain()
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
"""An emulation of the opentrons heater shaker module.
|
|
2
|
+
|
|
3
|
+
The purpose is to provide a fake backend that responds to GCODE commands.
|
|
4
|
+
"""
|
|
5
|
+
import logging
|
|
6
|
+
from time import sleep
|
|
7
|
+
from typing import (
|
|
8
|
+
Optional,
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
from opentrons.drivers.heater_shaker.driver import (
|
|
12
|
+
GCODE,
|
|
13
|
+
HS_ACK,
|
|
14
|
+
)
|
|
15
|
+
from opentrons.hardware_control.emulation.parser import Parser, Command
|
|
16
|
+
from opentrons.hardware_control.emulation.settings import HeaterShakerSettings
|
|
17
|
+
from . import util
|
|
18
|
+
|
|
19
|
+
from .abstract_emulator import AbstractEmulator
|
|
20
|
+
from .simulations import (
|
|
21
|
+
Temperature,
|
|
22
|
+
RPM,
|
|
23
|
+
)
|
|
24
|
+
from .util import TEMPERATURE_ROOM
|
|
25
|
+
from ...drivers.types import HeaterShakerLabwareLatchStatus
|
|
26
|
+
|
|
27
|
+
logger = logging.getLogger(__name__)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class HeaterShakerEmulator(AbstractEmulator):
|
|
31
|
+
"""Heater Shaker emulator"""
|
|
32
|
+
|
|
33
|
+
_temperature: Temperature
|
|
34
|
+
_rpm: RPM
|
|
35
|
+
_latch_status: HeaterShakerLabwareLatchStatus
|
|
36
|
+
|
|
37
|
+
def __init__(self, parser: Parser, settings: HeaterShakerSettings) -> None:
|
|
38
|
+
self._parser = parser
|
|
39
|
+
self._settings = settings
|
|
40
|
+
self._gcode_to_function_mapping = {
|
|
41
|
+
GCODE.SET_RPM.value: self._set_rpm,
|
|
42
|
+
GCODE.GET_RPM.value: self._get_rpm,
|
|
43
|
+
GCODE.SET_TEMPERATURE.value: self._set_temp,
|
|
44
|
+
GCODE.GET_TEMPERATURE.value: self._get_temp,
|
|
45
|
+
GCODE.HOME.value: self._home,
|
|
46
|
+
GCODE.ENTER_BOOTLOADER.value: self._enter_bootloader,
|
|
47
|
+
GCODE.GET_VERSION.value: self._get_version,
|
|
48
|
+
GCODE.GET_RESET_REASON.value: self._get_reset_reason,
|
|
49
|
+
GCODE.OPEN_LABWARE_LATCH.value: self._open_labware_latch,
|
|
50
|
+
GCODE.CLOSE_LABWARE_LATCH.value: self._close_labware_latch,
|
|
51
|
+
GCODE.GET_LABWARE_LATCH_STATE.value: self._get_labware_latch_state,
|
|
52
|
+
GCODE.DEACTIVATE_HEATER.value: self._deactivate_heater,
|
|
53
|
+
}
|
|
54
|
+
self.reset()
|
|
55
|
+
|
|
56
|
+
def handle(self, line: str) -> Optional[str]:
|
|
57
|
+
"""Handle a line"""
|
|
58
|
+
results = (self._handle(c) for c in self._parser.parse(line))
|
|
59
|
+
joined = " ".join(r for r in results if r)
|
|
60
|
+
return None if not joined else joined
|
|
61
|
+
|
|
62
|
+
def reset(self) -> None:
|
|
63
|
+
|
|
64
|
+
self._temperature = Temperature(
|
|
65
|
+
per_tick=self._settings.temperature.degrees_per_tick,
|
|
66
|
+
current=self._settings.temperature.starting,
|
|
67
|
+
)
|
|
68
|
+
self._rpm = RPM(
|
|
69
|
+
per_tick=self._settings.rpm.rpm_per_tick,
|
|
70
|
+
current=self._settings.rpm.starting,
|
|
71
|
+
)
|
|
72
|
+
self._rpm.set_target(0.0)
|
|
73
|
+
self._latch_status = HeaterShakerLabwareLatchStatus.IDLE_OPEN
|
|
74
|
+
|
|
75
|
+
def _handle(self, command: Command) -> Optional[str]:
|
|
76
|
+
"""
|
|
77
|
+
Handle a command.
|
|
78
|
+
|
|
79
|
+
TODO: AL 20210218 create dispatch map and remove 'noqa(C901)'
|
|
80
|
+
"""
|
|
81
|
+
logger.info(f"Got command {command}")
|
|
82
|
+
func_to_run = self._gcode_to_function_mapping.get(command.gcode)
|
|
83
|
+
res = None if func_to_run is None else func_to_run(command)
|
|
84
|
+
return None if not isinstance(res, str) else f"{res} {HS_ACK}"
|
|
85
|
+
|
|
86
|
+
def _set_rpm(self, command: Command) -> str:
|
|
87
|
+
value = command.params["S"]
|
|
88
|
+
assert isinstance(value, float), f"invalid value '{value}'"
|
|
89
|
+
self._rpm.set_target(value)
|
|
90
|
+
return "M3"
|
|
91
|
+
|
|
92
|
+
def _get_rpm(self, command: Command) -> str:
|
|
93
|
+
res = (
|
|
94
|
+
f"M123 C:{self._rpm.current} "
|
|
95
|
+
f"T:{self._rpm.target if self._rpm.target is not None else 0}"
|
|
96
|
+
)
|
|
97
|
+
self._rpm.tick()
|
|
98
|
+
return res
|
|
99
|
+
|
|
100
|
+
def _set_temp(self, command: Command) -> str:
|
|
101
|
+
value = command.params["S"]
|
|
102
|
+
assert isinstance(value, float), f"invalid value '{value}'"
|
|
103
|
+
self._temperature.set_target(value)
|
|
104
|
+
return "M104"
|
|
105
|
+
|
|
106
|
+
def _get_temp(self, command: Command) -> str:
|
|
107
|
+
res = (
|
|
108
|
+
f"M105 C:{self._temperature.current} "
|
|
109
|
+
f"T:{util.OptionalValue(self._temperature.target)}"
|
|
110
|
+
)
|
|
111
|
+
self._temperature.tick()
|
|
112
|
+
return res
|
|
113
|
+
|
|
114
|
+
def _home(self, command: Command) -> str:
|
|
115
|
+
sleep(self._settings.home_delay_time)
|
|
116
|
+
self._rpm.deactivate(0.0)
|
|
117
|
+
self._rpm.set_target(0.0)
|
|
118
|
+
return "G28"
|
|
119
|
+
|
|
120
|
+
def _enter_bootloader(self, command: Command) -> None:
|
|
121
|
+
pass
|
|
122
|
+
|
|
123
|
+
def _get_version(self, command: Command) -> str:
|
|
124
|
+
return (
|
|
125
|
+
f"FW:{self._settings.version} "
|
|
126
|
+
f"HW:{self._settings.model} "
|
|
127
|
+
f"SerialNo:{self._settings.serial_number}"
|
|
128
|
+
)
|
|
129
|
+
|
|
130
|
+
def _get_reset_reason(self, command: Command) -> str:
|
|
131
|
+
return "M114 Last Reset Reason: 01"
|
|
132
|
+
|
|
133
|
+
def _open_labware_latch(self, command: Command) -> str:
|
|
134
|
+
self._latch_status = HeaterShakerLabwareLatchStatus.IDLE_OPEN
|
|
135
|
+
return "M242"
|
|
136
|
+
|
|
137
|
+
def _close_labware_latch(self, command: Command) -> str:
|
|
138
|
+
self._latch_status = HeaterShakerLabwareLatchStatus.IDLE_CLOSED
|
|
139
|
+
return "M243"
|
|
140
|
+
|
|
141
|
+
def _get_labware_latch_state(self, command: Command) -> str:
|
|
142
|
+
return f"M241 STATUS:{self._latch_status.value.upper()}"
|
|
143
|
+
|
|
144
|
+
def _deactivate_heater(self, command: Command) -> str:
|
|
145
|
+
self._temperature.deactivate(TEMPERATURE_ROOM)
|
|
146
|
+
return "M106"
|
|
147
|
+
|
|
148
|
+
@staticmethod
|
|
149
|
+
def get_terminator() -> bytes:
|
|
150
|
+
return b"\n"
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
"""An emulation of the opentrons magnetic module.
|
|
2
|
+
|
|
3
|
+
The purpose is to provide a fake backend that responds to GCODE commands.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import logging
|
|
7
|
+
from typing import Optional
|
|
8
|
+
from opentrons.drivers.mag_deck.driver import GCODE
|
|
9
|
+
from opentrons.hardware_control.emulation.parser import Parser, Command
|
|
10
|
+
from .abstract_emulator import AbstractEmulator
|
|
11
|
+
from .settings import MagDeckSettings
|
|
12
|
+
|
|
13
|
+
logger = logging.getLogger(__name__)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class MagDeckEmulator(AbstractEmulator):
|
|
17
|
+
"""Magdeck emulator"""
|
|
18
|
+
|
|
19
|
+
height: float = 0
|
|
20
|
+
position: float = 0
|
|
21
|
+
|
|
22
|
+
def __init__(self, parser: Parser, settings: MagDeckSettings) -> None:
|
|
23
|
+
self._settings = settings
|
|
24
|
+
self._parser = parser
|
|
25
|
+
self.reset()
|
|
26
|
+
|
|
27
|
+
def handle(self, line: str) -> Optional[str]:
|
|
28
|
+
"""Handle a line"""
|
|
29
|
+
results = (self._handle(c) for c in self._parser.parse(line))
|
|
30
|
+
joined = " ".join(r for r in results if r)
|
|
31
|
+
return None if not joined else joined
|
|
32
|
+
|
|
33
|
+
def reset(self) -> None:
|
|
34
|
+
self.height: float = 0
|
|
35
|
+
self.position: float = 0
|
|
36
|
+
|
|
37
|
+
def _handle(self, command: Command) -> Optional[str]:
|
|
38
|
+
"""Handle a command."""
|
|
39
|
+
logger.info(f"Got command {command}")
|
|
40
|
+
if command.gcode == GCODE.HOME:
|
|
41
|
+
self.height = 0
|
|
42
|
+
elif command.gcode == GCODE.MOVE:
|
|
43
|
+
position = command.params["Z"]
|
|
44
|
+
assert isinstance(position, float), f"invalid position '{position}'"
|
|
45
|
+
self.position = position
|
|
46
|
+
elif command.gcode == GCODE.PROBE_PLATE:
|
|
47
|
+
self.height = 45
|
|
48
|
+
elif command.gcode == GCODE.GET_PLATE_HEIGHT:
|
|
49
|
+
return f"height:{self.height}"
|
|
50
|
+
elif command.gcode == GCODE.GET_CURRENT_POSITION:
|
|
51
|
+
return f"Z:{self.position}"
|
|
52
|
+
elif command.gcode == GCODE.DEVICE_INFO:
|
|
53
|
+
return (
|
|
54
|
+
f"serial:{self._settings.serial_number} "
|
|
55
|
+
f"model:{self._settings.model} "
|
|
56
|
+
f"version:{self._settings.version}"
|
|
57
|
+
)
|
|
58
|
+
elif command.gcode == GCODE.PROGRAMMING_MODE:
|
|
59
|
+
pass
|
|
60
|
+
return None
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
import asyncio
|
|
3
|
+
from asyncio import IncompleteReadError, LimitOverrunError
|
|
4
|
+
from typing import Optional
|
|
5
|
+
|
|
6
|
+
from opentrons.hardware_control.emulation.module_server.models import Message
|
|
7
|
+
from opentrons.hardware_control.emulation.module_server.server import MessageDelimiter
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class ModuleServerClientError(Exception):
|
|
11
|
+
pass
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class ModuleServerDisconnected(ModuleServerClientError):
|
|
15
|
+
pass
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class ModuleStatusClient:
|
|
19
|
+
"""A module server client."""
|
|
20
|
+
|
|
21
|
+
def __init__(
|
|
22
|
+
self, reader: asyncio.StreamReader, writer: asyncio.StreamWriter
|
|
23
|
+
) -> None:
|
|
24
|
+
"""Constructor."""
|
|
25
|
+
self._reader = reader
|
|
26
|
+
self._writer = writer
|
|
27
|
+
|
|
28
|
+
@classmethod
|
|
29
|
+
async def connect(
|
|
30
|
+
cls,
|
|
31
|
+
host: str,
|
|
32
|
+
port: int,
|
|
33
|
+
retries: int = 3,
|
|
34
|
+
interval_seconds: float = 0.1,
|
|
35
|
+
) -> ModuleStatusClient:
|
|
36
|
+
"""Connect to the module server.
|
|
37
|
+
|
|
38
|
+
Args:
|
|
39
|
+
host: module server host.
|
|
40
|
+
port: module server port.
|
|
41
|
+
retries: number of retries
|
|
42
|
+
interval_seconds: time between retries.
|
|
43
|
+
|
|
44
|
+
Returns:
|
|
45
|
+
None
|
|
46
|
+
Raises:
|
|
47
|
+
IOError on retry expiry.
|
|
48
|
+
"""
|
|
49
|
+
r: Optional[asyncio.StreamReader] = None
|
|
50
|
+
w: Optional[asyncio.StreamWriter] = None
|
|
51
|
+
for i in range(retries):
|
|
52
|
+
try:
|
|
53
|
+
r, w = await asyncio.open_connection(host=host, port=port)
|
|
54
|
+
break
|
|
55
|
+
except OSError:
|
|
56
|
+
await asyncio.sleep(interval_seconds)
|
|
57
|
+
|
|
58
|
+
if r is not None and w is not None:
|
|
59
|
+
return ModuleStatusClient(reader=r, writer=w)
|
|
60
|
+
else:
|
|
61
|
+
raise IOError(
|
|
62
|
+
f"Failed to connect to module_server at after {retries} retries."
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
async def read(self) -> Message:
|
|
66
|
+
"""Read a message from the module server."""
|
|
67
|
+
try:
|
|
68
|
+
b = await self._reader.readuntil(MessageDelimiter)
|
|
69
|
+
m: Message = Message.model_validate_json(b)
|
|
70
|
+
return m
|
|
71
|
+
except LimitOverrunError as e:
|
|
72
|
+
raise ModuleServerClientError(str(e))
|
|
73
|
+
except IncompleteReadError:
|
|
74
|
+
raise ModuleServerDisconnected()
|
|
75
|
+
|
|
76
|
+
def close(self) -> None:
|
|
77
|
+
"""Close the client."""
|
|
78
|
+
self._writer.close()
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
"""Utililty methods and classes for interacting with the Module Status Server."""
|
|
2
|
+
|
|
3
|
+
import asyncio
|
|
4
|
+
from typing import Sequence, Set, Callable, List, Awaitable
|
|
5
|
+
|
|
6
|
+
from opentrons.drivers.rpi_drivers.types import USBPort
|
|
7
|
+
from opentrons.hardware_control.emulation.module_server.client import (
|
|
8
|
+
ModuleStatusClient,
|
|
9
|
+
ModuleServerClientError,
|
|
10
|
+
ModuleServerDisconnected,
|
|
11
|
+
)
|
|
12
|
+
from opentrons.hardware_control.emulation.module_server.models import Message
|
|
13
|
+
from opentrons.hardware_control.emulation.module_server.server import log
|
|
14
|
+
from opentrons.hardware_control.emulation.settings import Settings
|
|
15
|
+
from opentrons.hardware_control.emulation.types import ModuleType
|
|
16
|
+
from opentrons.hardware_control.modules import ModuleAtPort
|
|
17
|
+
|
|
18
|
+
NotifyMethod = Callable[[List[ModuleAtPort], List[ModuleAtPort]], Awaitable[None]]
|
|
19
|
+
"""Signature of method to be notified of new and removed modules."""
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
async def listen_module_connection(callback: NotifyMethod) -> None:
|
|
23
|
+
"""Listen for module emulator connections."""
|
|
24
|
+
settings = Settings()
|
|
25
|
+
try:
|
|
26
|
+
client = await ModuleStatusClient.connect(
|
|
27
|
+
host=settings.module_server.host,
|
|
28
|
+
port=settings.module_server.port,
|
|
29
|
+
interval_seconds=1.0,
|
|
30
|
+
)
|
|
31
|
+
listener = ModuleListener(client=client, notify_method=callback)
|
|
32
|
+
await listener.run()
|
|
33
|
+
except IOError:
|
|
34
|
+
log.exception("Failed to connect to module server.")
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class ModuleListener:
|
|
38
|
+
"""Provide a callback for listening for new and removed module connections."""
|
|
39
|
+
|
|
40
|
+
def __init__(self, client: ModuleStatusClient, notify_method: NotifyMethod) -> None:
|
|
41
|
+
"""Constructor.
|
|
42
|
+
|
|
43
|
+
Args:
|
|
44
|
+
client: A module server client
|
|
45
|
+
notify_method: callback method.
|
|
46
|
+
|
|
47
|
+
Returns:
|
|
48
|
+
None
|
|
49
|
+
"""
|
|
50
|
+
self._client = client
|
|
51
|
+
self._notify_method = notify_method
|
|
52
|
+
self._hub_index = 1
|
|
53
|
+
|
|
54
|
+
async def run(self) -> None:
|
|
55
|
+
"""Run the listener."""
|
|
56
|
+
while True:
|
|
57
|
+
try:
|
|
58
|
+
m = await self._client.read()
|
|
59
|
+
await self.handle_message(message=m)
|
|
60
|
+
except ModuleServerDisconnected:
|
|
61
|
+
log.info("Disconnected from module server.")
|
|
62
|
+
break
|
|
63
|
+
except ModuleServerClientError:
|
|
64
|
+
log.exception("Read error.")
|
|
65
|
+
break
|
|
66
|
+
|
|
67
|
+
async def handle_message(self, message: Message) -> None:
|
|
68
|
+
"""Call callback with results of message.
|
|
69
|
+
|
|
70
|
+
Args:
|
|
71
|
+
message: Message object from module server
|
|
72
|
+
|
|
73
|
+
Returns:
|
|
74
|
+
None
|
|
75
|
+
"""
|
|
76
|
+
|
|
77
|
+
def _next_index() -> int:
|
|
78
|
+
index = self._hub_index
|
|
79
|
+
self._hub_index += 1
|
|
80
|
+
return index
|
|
81
|
+
|
|
82
|
+
connections = [
|
|
83
|
+
ModuleAtPort(
|
|
84
|
+
port=c.url,
|
|
85
|
+
name=c.module_type,
|
|
86
|
+
usb_port=USBPort(name=c.identifier, port_number=_next_index()),
|
|
87
|
+
)
|
|
88
|
+
for c in message.connections
|
|
89
|
+
]
|
|
90
|
+
if message.status == "connected" or message.status == "dump":
|
|
91
|
+
await self._notify_method(connections, [])
|
|
92
|
+
elif message.status == "disconnected":
|
|
93
|
+
await self._notify_method([], connections)
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
async def wait_emulators(
|
|
97
|
+
client: ModuleStatusClient,
|
|
98
|
+
modules: Sequence[ModuleType],
|
|
99
|
+
timeout: float,
|
|
100
|
+
) -> None:
|
|
101
|
+
"""Wait for module emulators to connect.
|
|
102
|
+
|
|
103
|
+
Args:
|
|
104
|
+
client: module server client.
|
|
105
|
+
modules: collection of of module types to wait for.
|
|
106
|
+
timeout: how long to wait for emulators to connect (in seconds)
|
|
107
|
+
|
|
108
|
+
Returns:
|
|
109
|
+
None
|
|
110
|
+
Raises:
|
|
111
|
+
asyncio.TimeoutError on timeout.
|
|
112
|
+
"""
|
|
113
|
+
|
|
114
|
+
async def _wait_modules() -> None:
|
|
115
|
+
"""Read messages from module server waiting for modules in module_set to
|
|
116
|
+
be connected."""
|
|
117
|
+
module_set: Set[str] = set(modules)
|
|
118
|
+
|
|
119
|
+
while module_set:
|
|
120
|
+
m: Message = await client.read()
|
|
121
|
+
if m.status == "dump" or m.status == "connected":
|
|
122
|
+
for c in m.connections:
|
|
123
|
+
module_set.discard(c.module_type)
|
|
124
|
+
elif m.status == "disconnected":
|
|
125
|
+
for c in m.connections:
|
|
126
|
+
module_set.add(c.module_type)
|
|
127
|
+
|
|
128
|
+
log.debug(f"after message: {m}, awaiting module set is: {module_set}")
|
|
129
|
+
|
|
130
|
+
await asyncio.wait_for(_wait_modules(), timeout=timeout)
|