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,426 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import asyncio
|
|
4
|
+
import logging
|
|
5
|
+
from typing import Optional, Mapping
|
|
6
|
+
from typing_extensions import Final
|
|
7
|
+
|
|
8
|
+
from opentrons.drivers.rpi_drivers.types import USBPort
|
|
9
|
+
from opentrons.drivers.heater_shaker.driver import HeaterShakerDriver
|
|
10
|
+
from opentrons.drivers.heater_shaker.abstract import AbstractHeaterShakerDriver
|
|
11
|
+
from opentrons.drivers.heater_shaker.simulator import SimulatingDriver
|
|
12
|
+
from opentrons.drivers.types import Temperature, RPM, HeaterShakerLabwareLatchStatus
|
|
13
|
+
from opentrons.hardware_control.execution_manager import ExecutionManager
|
|
14
|
+
from opentrons.hardware_control.poller import Reader, Poller
|
|
15
|
+
from opentrons.hardware_control.modules import mod_abc, update
|
|
16
|
+
from opentrons.hardware_control.modules.types import (
|
|
17
|
+
ModuleDisconnectedCallback,
|
|
18
|
+
ModuleType,
|
|
19
|
+
TemperatureStatus,
|
|
20
|
+
SpeedStatus,
|
|
21
|
+
HeaterShakerStatus,
|
|
22
|
+
UploadFunction,
|
|
23
|
+
LiveData,
|
|
24
|
+
HeaterShakerData,
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
log = logging.getLogger(__name__)
|
|
28
|
+
|
|
29
|
+
POLL_PERIOD = 1.0
|
|
30
|
+
|
|
31
|
+
# TODO(mc, 2022-06-14): this techinque copied from temperature module
|
|
32
|
+
# to speed up simulation of heater-shaker protocols, but it's pretty silly
|
|
33
|
+
# module simulation in PAPIv2 needs to be seriously rethought
|
|
34
|
+
SIMULATING_POLL_PERIOD = POLL_PERIOD / 20.0
|
|
35
|
+
|
|
36
|
+
DFU_PID = "df11"
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
class HeaterShaker(mod_abc.AbstractModule):
|
|
40
|
+
"""Hardware control interface for an attached Heater-Shaker module."""
|
|
41
|
+
|
|
42
|
+
MODULE_TYPE = ModuleType.HEATER_SHAKER
|
|
43
|
+
|
|
44
|
+
@classmethod
|
|
45
|
+
async def build(
|
|
46
|
+
cls,
|
|
47
|
+
port: str,
|
|
48
|
+
usb_port: USBPort,
|
|
49
|
+
hw_control_loop: asyncio.AbstractEventLoop,
|
|
50
|
+
execution_manager: Optional[ExecutionManager] = None,
|
|
51
|
+
poll_interval_seconds: Optional[float] = None,
|
|
52
|
+
simulating: bool = False,
|
|
53
|
+
sim_model: Optional[str] = None,
|
|
54
|
+
sim_serial_number: Optional[str] = None,
|
|
55
|
+
disconnected_callback: ModuleDisconnectedCallback = None,
|
|
56
|
+
) -> "HeaterShaker":
|
|
57
|
+
"""
|
|
58
|
+
Build a HeaterShaker
|
|
59
|
+
|
|
60
|
+
Args:
|
|
61
|
+
port: The port to connect to
|
|
62
|
+
usb_port: USB Port
|
|
63
|
+
hw_control_loop: The event loop running in the hardware control thread.
|
|
64
|
+
execution_manager: Execution manager.
|
|
65
|
+
poll_interval_seconds: Poll interval override.
|
|
66
|
+
simulating: whether to build a simulating driver
|
|
67
|
+
loop: Loop
|
|
68
|
+
sim_model: The model name used by simulator
|
|
69
|
+
disconnected_callback: Callback to inform the module controller that the device was disconnected
|
|
70
|
+
|
|
71
|
+
Returns:
|
|
72
|
+
HeaterShaker instance
|
|
73
|
+
"""
|
|
74
|
+
driver: AbstractHeaterShakerDriver
|
|
75
|
+
if not simulating:
|
|
76
|
+
driver = await HeaterShakerDriver.create(port=port, loop=hw_control_loop)
|
|
77
|
+
poll_interval_seconds = poll_interval_seconds or POLL_PERIOD
|
|
78
|
+
else:
|
|
79
|
+
driver = SimulatingDriver(serial_number=sim_serial_number)
|
|
80
|
+
poll_interval_seconds = poll_interval_seconds or SIMULATING_POLL_PERIOD
|
|
81
|
+
|
|
82
|
+
reader = HeaterShakerReader(driver=driver)
|
|
83
|
+
poller = Poller(reader=reader, interval=poll_interval_seconds)
|
|
84
|
+
module = cls(
|
|
85
|
+
port=port,
|
|
86
|
+
usb_port=usb_port,
|
|
87
|
+
driver=driver,
|
|
88
|
+
reader=reader,
|
|
89
|
+
poller=poller,
|
|
90
|
+
device_info=await driver.get_device_info(),
|
|
91
|
+
hw_control_loop=hw_control_loop,
|
|
92
|
+
execution_manager=execution_manager,
|
|
93
|
+
disconnected_callback=disconnected_callback,
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
try:
|
|
97
|
+
await poller.start()
|
|
98
|
+
except Exception:
|
|
99
|
+
log.exception(f"First read of Heater-Shaker on port {port} failed")
|
|
100
|
+
|
|
101
|
+
return module
|
|
102
|
+
|
|
103
|
+
def __init__(
|
|
104
|
+
self,
|
|
105
|
+
port: str,
|
|
106
|
+
usb_port: USBPort,
|
|
107
|
+
driver: AbstractHeaterShakerDriver,
|
|
108
|
+
reader: HeaterShakerReader,
|
|
109
|
+
poller: Poller,
|
|
110
|
+
device_info: Mapping[str, str],
|
|
111
|
+
hw_control_loop: asyncio.AbstractEventLoop,
|
|
112
|
+
execution_manager: Optional[ExecutionManager] = None,
|
|
113
|
+
disconnected_callback: ModuleDisconnectedCallback = None,
|
|
114
|
+
):
|
|
115
|
+
super().__init__(
|
|
116
|
+
port=port,
|
|
117
|
+
usb_port=usb_port,
|
|
118
|
+
hw_control_loop=hw_control_loop,
|
|
119
|
+
execution_manager=execution_manager,
|
|
120
|
+
disconnected_callback=disconnected_callback,
|
|
121
|
+
)
|
|
122
|
+
self._device_info = device_info
|
|
123
|
+
self._driver = driver
|
|
124
|
+
self._reader = reader
|
|
125
|
+
self._poller = poller
|
|
126
|
+
|
|
127
|
+
async def cleanup(self) -> None:
|
|
128
|
+
"""Stop the poller task"""
|
|
129
|
+
await self._poller.stop()
|
|
130
|
+
await self._driver.disconnect()
|
|
131
|
+
|
|
132
|
+
@classmethod
|
|
133
|
+
def name(cls) -> str:
|
|
134
|
+
"""Used for picking up serial port symlinks"""
|
|
135
|
+
return "heatershaker"
|
|
136
|
+
|
|
137
|
+
def firmware_prefix(self) -> str:
|
|
138
|
+
"""The prefix used for looking up firmware"""
|
|
139
|
+
return "heater-shaker"
|
|
140
|
+
|
|
141
|
+
@staticmethod
|
|
142
|
+
def _model_from_revision(revision: Optional[str]) -> str:
|
|
143
|
+
"""Defines the revision -> model mapping"""
|
|
144
|
+
return "heaterShakerModuleV1"
|
|
145
|
+
|
|
146
|
+
@staticmethod
|
|
147
|
+
def _get_temperature_status(temperature: Temperature) -> TemperatureStatus:
|
|
148
|
+
"""
|
|
149
|
+
Determine the status from the temperature.
|
|
150
|
+
|
|
151
|
+
Args:
|
|
152
|
+
temperature: A Temperature instance
|
|
153
|
+
|
|
154
|
+
Returns:
|
|
155
|
+
The status
|
|
156
|
+
"""
|
|
157
|
+
DELTA: Final = 0.7
|
|
158
|
+
status = TemperatureStatus.IDLE
|
|
159
|
+
if temperature.target is not None:
|
|
160
|
+
diff = temperature.target - temperature.current
|
|
161
|
+
if abs(diff) < DELTA: # To avoid status fluctuation near target
|
|
162
|
+
status = TemperatureStatus.HOLDING
|
|
163
|
+
elif diff < 0:
|
|
164
|
+
status = TemperatureStatus.COOLING
|
|
165
|
+
else:
|
|
166
|
+
status = TemperatureStatus.HEATING
|
|
167
|
+
return status
|
|
168
|
+
|
|
169
|
+
@staticmethod
|
|
170
|
+
def _get_speed_status(speed: RPM) -> SpeedStatus:
|
|
171
|
+
"""
|
|
172
|
+
Determine the status from the speed.
|
|
173
|
+
|
|
174
|
+
Args:
|
|
175
|
+
speed: An RPM instance
|
|
176
|
+
|
|
177
|
+
Returns:
|
|
178
|
+
The status
|
|
179
|
+
"""
|
|
180
|
+
DELTA: Final = 40
|
|
181
|
+
status = SpeedStatus.IDLE
|
|
182
|
+
if speed.target is not None:
|
|
183
|
+
diff = speed.target - speed.current
|
|
184
|
+
if abs(diff) < DELTA: # To avoid status fluctuation near target
|
|
185
|
+
status = SpeedStatus.HOLDING
|
|
186
|
+
elif diff < 0:
|
|
187
|
+
status = SpeedStatus.DECELERATING
|
|
188
|
+
else:
|
|
189
|
+
status = SpeedStatus.ACCELERATING
|
|
190
|
+
return status
|
|
191
|
+
|
|
192
|
+
def model(self) -> str:
|
|
193
|
+
return self._model_from_revision(self._device_info.get("model"))
|
|
194
|
+
|
|
195
|
+
def bootloader(self) -> UploadFunction:
|
|
196
|
+
return update.upload_via_dfu
|
|
197
|
+
|
|
198
|
+
@property
|
|
199
|
+
def device_info(self) -> Mapping[str, str]:
|
|
200
|
+
return self._device_info
|
|
201
|
+
|
|
202
|
+
@property
|
|
203
|
+
def live_data(self) -> LiveData:
|
|
204
|
+
data: HeaterShakerData = {
|
|
205
|
+
"temperatureStatus": self.temperature_status,
|
|
206
|
+
"speedStatus": self.speed_status,
|
|
207
|
+
"labwareLatchStatus": self.labware_latch_status,
|
|
208
|
+
"currentTemp": self.temperature,
|
|
209
|
+
"targetTemp": self.target_temperature,
|
|
210
|
+
"currentSpeed": self.speed,
|
|
211
|
+
"targetSpeed": self.target_speed,
|
|
212
|
+
"errorDetails": self._reader.error,
|
|
213
|
+
}
|
|
214
|
+
return {
|
|
215
|
+
"status": self.status.value,
|
|
216
|
+
"data": data,
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
@property
|
|
220
|
+
def temperature(self) -> float:
|
|
221
|
+
return self._reader.temperature.current
|
|
222
|
+
|
|
223
|
+
@property
|
|
224
|
+
def target_temperature(self) -> Optional[float]:
|
|
225
|
+
return self._reader.temperature.target
|
|
226
|
+
|
|
227
|
+
@property
|
|
228
|
+
def speed(self) -> int:
|
|
229
|
+
return self._reader.rpm.current
|
|
230
|
+
|
|
231
|
+
@property
|
|
232
|
+
def target_speed(self) -> Optional[int]:
|
|
233
|
+
return self._reader.rpm.target
|
|
234
|
+
|
|
235
|
+
@property
|
|
236
|
+
def temperature_status(self) -> TemperatureStatus:
|
|
237
|
+
return self._get_temperature_status(self._reader.temperature)
|
|
238
|
+
|
|
239
|
+
@property
|
|
240
|
+
def speed_status(self) -> SpeedStatus:
|
|
241
|
+
return self._get_speed_status(self._reader.rpm)
|
|
242
|
+
|
|
243
|
+
@property
|
|
244
|
+
def labware_latch_status(self) -> HeaterShakerLabwareLatchStatus:
|
|
245
|
+
return self._reader.labware_latch
|
|
246
|
+
|
|
247
|
+
@property
|
|
248
|
+
def status(self) -> HeaterShakerStatus:
|
|
249
|
+
"""Module status or error state details."""
|
|
250
|
+
# TODO (spp, 2022-2-22): Does this make sense as the overarching 'status'?
|
|
251
|
+
# Or maybe consolidate the above 3 statuses into this one?
|
|
252
|
+
if self._reader.error:
|
|
253
|
+
return HeaterShakerStatus.ERROR
|
|
254
|
+
elif (
|
|
255
|
+
self.temperature_status == TemperatureStatus.IDLE
|
|
256
|
+
and self.speed_status == SpeedStatus.IDLE
|
|
257
|
+
):
|
|
258
|
+
return HeaterShakerStatus.IDLE
|
|
259
|
+
else:
|
|
260
|
+
return HeaterShakerStatus.RUNNING
|
|
261
|
+
|
|
262
|
+
@property
|
|
263
|
+
def is_simulated(self) -> bool:
|
|
264
|
+
return isinstance(self._driver, SimulatingDriver)
|
|
265
|
+
|
|
266
|
+
async def start_set_temperature(self, celsius: float) -> None:
|
|
267
|
+
"""
|
|
268
|
+
Set temperature in degrees Celsius
|
|
269
|
+
|
|
270
|
+
Range: Room temperature to 90 degree Celsius
|
|
271
|
+
Any temperature above the value will be clipped to
|
|
272
|
+
the nearest limit. This is a resistive heater, not
|
|
273
|
+
a Peltier TEC, so a temperature that is too low
|
|
274
|
+
may be unattainable but we do not limit input on the
|
|
275
|
+
low side in case the user has this in a freezer.
|
|
276
|
+
|
|
277
|
+
This function will complete as soon as heating begins, and
|
|
278
|
+
will not wait until the temperature is achieved. To then wait
|
|
279
|
+
until heating is complete, use await_temperature. To start
|
|
280
|
+
heating and wait until heating is complete in one call, use
|
|
281
|
+
set_temperature.
|
|
282
|
+
|
|
283
|
+
"""
|
|
284
|
+
await self.wait_for_is_running()
|
|
285
|
+
await self._driver.set_temperature(celsius)
|
|
286
|
+
await self._reader.read_temperature()
|
|
287
|
+
|
|
288
|
+
# TODO(mc, 2022-10-10): remove `awaiting_temperature` argument,
|
|
289
|
+
# and instead, wait until status is holding
|
|
290
|
+
async def await_temperature(self, awaiting_temperature: float) -> None:
|
|
291
|
+
"""Await temperature in degrees Celsius.
|
|
292
|
+
|
|
293
|
+
Polls the Heater-Shaker's current temperature until
|
|
294
|
+
the specified temperature is reached. If `awaiting_temperature`
|
|
295
|
+
is different than the current target temperature,
|
|
296
|
+
the resulting behavior may be unpredictable.
|
|
297
|
+
"""
|
|
298
|
+
if self.is_simulated:
|
|
299
|
+
return
|
|
300
|
+
|
|
301
|
+
await self.wait_for_is_running()
|
|
302
|
+
await self._reader.read_temperature()
|
|
303
|
+
|
|
304
|
+
async def _await_temperature() -> None:
|
|
305
|
+
if self.temperature_status == TemperatureStatus.HEATING:
|
|
306
|
+
while self.temperature < awaiting_temperature:
|
|
307
|
+
await self._poller.wait_next_poll()
|
|
308
|
+
elif self.temperature_status == TemperatureStatus.COOLING:
|
|
309
|
+
while self.temperature > awaiting_temperature:
|
|
310
|
+
await self._poller.wait_next_poll()
|
|
311
|
+
|
|
312
|
+
t = self._loop.create_task(_await_temperature())
|
|
313
|
+
self.make_cancellable(t)
|
|
314
|
+
await t
|
|
315
|
+
|
|
316
|
+
async def set_speed(self, rpm: int) -> None:
|
|
317
|
+
"""
|
|
318
|
+
Set shake speed in RPM
|
|
319
|
+
|
|
320
|
+
Range: 0-3000 RPM
|
|
321
|
+
Any speed above or below these values will cause an error.
|
|
322
|
+
|
|
323
|
+
This function will not complete until the heater-shaker is at
|
|
324
|
+
the speed or an error occurs. To start spinning but not wait
|
|
325
|
+
until the final speed is reached, see start_set_speed.
|
|
326
|
+
"""
|
|
327
|
+
await self.wait_for_is_running()
|
|
328
|
+
await self._driver.set_rpm(rpm)
|
|
329
|
+
await self._reader.read_rpm()
|
|
330
|
+
|
|
331
|
+
async def _wait() -> None:
|
|
332
|
+
# Wait until we reach the target speed.
|
|
333
|
+
while self.speed_status != SpeedStatus.HOLDING:
|
|
334
|
+
await self._poller.wait_next_poll()
|
|
335
|
+
|
|
336
|
+
task = self._loop.create_task(_wait())
|
|
337
|
+
self.make_cancellable(task)
|
|
338
|
+
await task
|
|
339
|
+
|
|
340
|
+
async def _wait_for_labware_latch(
|
|
341
|
+
self, status: HeaterShakerLabwareLatchStatus
|
|
342
|
+
) -> None:
|
|
343
|
+
"""Wait until the hardware reports the labware latch status matches."""
|
|
344
|
+
while self.labware_latch_status != status:
|
|
345
|
+
await self._poller.wait_next_poll()
|
|
346
|
+
|
|
347
|
+
async def _wait_for_shake_deactivation(self) -> None:
|
|
348
|
+
"""Wait until hardware reports that module has stopped shaking and has homed."""
|
|
349
|
+
while self.speed_status != SpeedStatus.IDLE:
|
|
350
|
+
await self._poller.wait_next_poll()
|
|
351
|
+
|
|
352
|
+
async def deactivate(self, must_be_running: bool = True) -> None:
|
|
353
|
+
"""Stop heating/cooling; stop shaking and home the plate"""
|
|
354
|
+
await self.deactivate_heater(must_be_running=must_be_running)
|
|
355
|
+
await self.deactivate_shaker(must_be_running=must_be_running)
|
|
356
|
+
|
|
357
|
+
async def deactivate_heater(self, must_be_running: bool = True) -> None:
|
|
358
|
+
"""Stop heating/cooling"""
|
|
359
|
+
if must_be_running:
|
|
360
|
+
await self.wait_for_is_running()
|
|
361
|
+
await self._driver.deactivate_heater()
|
|
362
|
+
await self._reader.read_temperature()
|
|
363
|
+
|
|
364
|
+
async def deactivate_shaker(self, must_be_running: bool = True) -> None:
|
|
365
|
+
"""Stop shaking and home the plate"""
|
|
366
|
+
if must_be_running:
|
|
367
|
+
await self.wait_for_is_running()
|
|
368
|
+
await self._driver.home()
|
|
369
|
+
await self._wait_for_shake_deactivation()
|
|
370
|
+
|
|
371
|
+
async def open_labware_latch(self) -> None:
|
|
372
|
+
await self.wait_for_is_running()
|
|
373
|
+
await self._driver.open_labware_latch()
|
|
374
|
+
await self._wait_for_labware_latch(HeaterShakerLabwareLatchStatus.IDLE_OPEN)
|
|
375
|
+
|
|
376
|
+
async def close_labware_latch(self) -> None:
|
|
377
|
+
await self.wait_for_is_running()
|
|
378
|
+
await self._driver.close_labware_latch()
|
|
379
|
+
await self._wait_for_labware_latch(HeaterShakerLabwareLatchStatus.IDLE_CLOSED)
|
|
380
|
+
|
|
381
|
+
async def prep_for_update(self) -> str:
|
|
382
|
+
await self._poller.stop()
|
|
383
|
+
await self._driver.enter_programming_mode()
|
|
384
|
+
dfu_info = await update.find_dfu_device(pid=DFU_PID, expected_device_count=2)
|
|
385
|
+
return dfu_info
|
|
386
|
+
|
|
387
|
+
|
|
388
|
+
class HeaterShakerReader(Reader):
|
|
389
|
+
temperature: Temperature
|
|
390
|
+
rpm: RPM
|
|
391
|
+
labware_latch: HeaterShakerLabwareLatchStatus
|
|
392
|
+
error: Optional[str]
|
|
393
|
+
|
|
394
|
+
def __init__(self, driver: AbstractHeaterShakerDriver) -> None:
|
|
395
|
+
self.temperature = Temperature(current=25, target=None)
|
|
396
|
+
self.rpm = RPM(current=0, target=None)
|
|
397
|
+
self.labware_latch = HeaterShakerLabwareLatchStatus.IDLE_UNKNOWN
|
|
398
|
+
self.error: Optional[str] = None
|
|
399
|
+
self._driver = driver
|
|
400
|
+
|
|
401
|
+
async def read(self) -> None:
|
|
402
|
+
await self.read_temperature()
|
|
403
|
+
await self.read_rpm()
|
|
404
|
+
await self.read_labware_latch()
|
|
405
|
+
self._set_error(None)
|
|
406
|
+
|
|
407
|
+
def on_error(self, exception: Exception) -> None:
|
|
408
|
+
self._set_error(exception)
|
|
409
|
+
|
|
410
|
+
async def read_temperature(self) -> None:
|
|
411
|
+
self.temperature = await self._driver.get_temperature()
|
|
412
|
+
|
|
413
|
+
async def read_rpm(self) -> None:
|
|
414
|
+
self.rpm = await self._driver.get_rpm()
|
|
415
|
+
|
|
416
|
+
async def read_labware_latch(self) -> None:
|
|
417
|
+
self.labware_latch = await self._driver.get_labware_latch_status()
|
|
418
|
+
|
|
419
|
+
def _set_error(self, exception: Optional[Exception]) -> None:
|
|
420
|
+
if exception is None:
|
|
421
|
+
self.error = None
|
|
422
|
+
else:
|
|
423
|
+
try:
|
|
424
|
+
self.error = str(exception.args[0])
|
|
425
|
+
except Exception:
|
|
426
|
+
self.error = repr(exception)
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
from opentrons.drivers.types import Temperature
|
|
2
|
+
from opentrons.hardware_control.modules.types import TemperatureStatus
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class LidTemperatureStatus:
|
|
6
|
+
"""A wrapper for the lid temperature status."""
|
|
7
|
+
|
|
8
|
+
TEMP_THRESHOLD = 0.3
|
|
9
|
+
"""The threshold under which the difference between target and temperature
|
|
10
|
+
is considered `holding`."""
|
|
11
|
+
|
|
12
|
+
def __init__(self) -> None:
|
|
13
|
+
"""Construct."""
|
|
14
|
+
self._status = TemperatureStatus.ERROR
|
|
15
|
+
|
|
16
|
+
@property
|
|
17
|
+
def status(self) -> TemperatureStatus:
|
|
18
|
+
"""Return the current status."""
|
|
19
|
+
return self._status
|
|
20
|
+
|
|
21
|
+
def update(self, temperature: Temperature) -> TemperatureStatus:
|
|
22
|
+
"""Update the status based on the temperature."""
|
|
23
|
+
if temperature.target is None:
|
|
24
|
+
status = TemperatureStatus.IDLE
|
|
25
|
+
else:
|
|
26
|
+
diff = temperature.target - temperature.current
|
|
27
|
+
if abs(diff) < self.TEMP_THRESHOLD:
|
|
28
|
+
status = TemperatureStatus.HOLDING
|
|
29
|
+
elif diff < 0:
|
|
30
|
+
# TC lid can't actively cool
|
|
31
|
+
status = TemperatureStatus.IDLE
|
|
32
|
+
else:
|
|
33
|
+
status = TemperatureStatus.HEATING
|
|
34
|
+
self._status = status
|
|
35
|
+
return self._status
|
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
import logging
|
|
3
|
+
from typing import Dict, Optional
|
|
4
|
+
from opentrons.drivers.mag_deck import (
|
|
5
|
+
SimulatingDriver,
|
|
6
|
+
MagDeckDriver,
|
|
7
|
+
AbstractMagDeckDriver,
|
|
8
|
+
)
|
|
9
|
+
from opentrons.drivers.rpi_drivers.types import USBPort
|
|
10
|
+
from ..execution_manager import ExecutionManager
|
|
11
|
+
from . import update, mod_abc, types
|
|
12
|
+
|
|
13
|
+
log = logging.getLogger(__name__)
|
|
14
|
+
|
|
15
|
+
MAX_ENGAGE_HEIGHT = {
|
|
16
|
+
# Distance from home position.
|
|
17
|
+
# Measured in model-specific units (half-mm for GEN1, mm for GEN2).
|
|
18
|
+
"magneticModuleV1": 45,
|
|
19
|
+
"magneticModuleV2": 25,
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
# Measured in model-specific units (half-mm for GEN1, mm for GEN2).
|
|
23
|
+
# TODO(mc, 2022-06-13): the value for gen1 is off by ~1.5 mm
|
|
24
|
+
# The correct value is ~8.0 half-mm (4.0 mm)
|
|
25
|
+
# https://opentrons.atlassian.net/browse/RET-1242
|
|
26
|
+
OFFSET_TO_LABWARE_BOTTOM = {"magneticModuleV1": 5, "magneticModuleV2": 2.5}
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def engage_height_is_in_range(model: str, height: float) -> bool:
|
|
30
|
+
"""Return whether or not a height would be valid to pass to `MagDeck.engage()`.
|
|
31
|
+
|
|
32
|
+
Args:
|
|
33
|
+
model: The model of Magnetic Module for which you want to check
|
|
34
|
+
the engage height.
|
|
35
|
+
height: A height that you would provide to `MagDeck.engage()`.
|
|
36
|
+
"""
|
|
37
|
+
return 0 <= height <= MAX_ENGAGE_HEIGHT[model]
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
class MagDeck(mod_abc.AbstractModule):
|
|
41
|
+
"""Hardware control interface for an attached Temperature Module."""
|
|
42
|
+
|
|
43
|
+
MODULE_TYPE = types.ModuleType.MAGNETIC
|
|
44
|
+
FIRST_GEN2_REVISION = 20
|
|
45
|
+
|
|
46
|
+
@classmethod
|
|
47
|
+
async def build(
|
|
48
|
+
cls,
|
|
49
|
+
port: str,
|
|
50
|
+
usb_port: USBPort,
|
|
51
|
+
hw_control_loop: asyncio.AbstractEventLoop,
|
|
52
|
+
execution_manager: Optional[ExecutionManager] = None,
|
|
53
|
+
poll_interval_seconds: Optional[float] = None,
|
|
54
|
+
simulating: bool = False,
|
|
55
|
+
sim_model: Optional[str] = None,
|
|
56
|
+
sim_serial_number: Optional[str] = None,
|
|
57
|
+
disconnected_callback: types.ModuleDisconnectedCallback = None,
|
|
58
|
+
) -> "MagDeck":
|
|
59
|
+
"""Factory function."""
|
|
60
|
+
driver: AbstractMagDeckDriver
|
|
61
|
+
if not simulating:
|
|
62
|
+
driver = await MagDeckDriver.create(port=port, loop=hw_control_loop)
|
|
63
|
+
else:
|
|
64
|
+
driver = SimulatingDriver(
|
|
65
|
+
sim_model=sim_model, serial_number=sim_serial_number
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
mod = cls(
|
|
69
|
+
port=port,
|
|
70
|
+
usb_port=usb_port,
|
|
71
|
+
execution_manager=execution_manager,
|
|
72
|
+
hw_control_loop=hw_control_loop,
|
|
73
|
+
device_info=await driver.get_device_info(),
|
|
74
|
+
driver=driver,
|
|
75
|
+
disconnected_callback=disconnected_callback,
|
|
76
|
+
)
|
|
77
|
+
return mod
|
|
78
|
+
|
|
79
|
+
def __init__(
|
|
80
|
+
self,
|
|
81
|
+
port: str,
|
|
82
|
+
usb_port: USBPort,
|
|
83
|
+
hw_control_loop: asyncio.AbstractEventLoop,
|
|
84
|
+
driver: AbstractMagDeckDriver,
|
|
85
|
+
device_info: Dict[str, str],
|
|
86
|
+
execution_manager: Optional[ExecutionManager] = None,
|
|
87
|
+
disconnected_callback: types.ModuleDisconnectedCallback = None,
|
|
88
|
+
) -> None:
|
|
89
|
+
"""Constructor"""
|
|
90
|
+
super().__init__(
|
|
91
|
+
port=port,
|
|
92
|
+
usb_port=usb_port,
|
|
93
|
+
hw_control_loop=hw_control_loop,
|
|
94
|
+
execution_manager=execution_manager,
|
|
95
|
+
disconnected_callback=disconnected_callback,
|
|
96
|
+
)
|
|
97
|
+
self._device_info = device_info
|
|
98
|
+
self._driver = driver
|
|
99
|
+
self._current_height = 0.0
|
|
100
|
+
|
|
101
|
+
async def cleanup(self) -> None:
|
|
102
|
+
await self._driver.disconnect()
|
|
103
|
+
|
|
104
|
+
@classmethod
|
|
105
|
+
def name(cls) -> str:
|
|
106
|
+
"""Get the module name."""
|
|
107
|
+
return "magdeck"
|
|
108
|
+
|
|
109
|
+
def firmware_prefix(self) -> str:
|
|
110
|
+
"""The prefix used for looking up firmware"""
|
|
111
|
+
return "magnetic-module"
|
|
112
|
+
|
|
113
|
+
def model(self) -> str:
|
|
114
|
+
"""Get the model."""
|
|
115
|
+
return self._model_from_revision(self._device_info.get("model"))
|
|
116
|
+
|
|
117
|
+
def bootloader(self) -> types.UploadFunction:
|
|
118
|
+
"""Get the bootloating method."""
|
|
119
|
+
return update.upload_via_avrdude
|
|
120
|
+
|
|
121
|
+
async def calibrate(self) -> None:
|
|
122
|
+
"""Calibration involves probing for top plate to get the plate height."""
|
|
123
|
+
await self.wait_for_is_running()
|
|
124
|
+
await self._driver.probe_plate()
|
|
125
|
+
# return if successful or not?
|
|
126
|
+
|
|
127
|
+
# TODO(mc, 2022-09-23): refactor this method to take real mm,
|
|
128
|
+
# hardware API should abstract away the idea of "short millimeters"
|
|
129
|
+
# https://opentrons.atlassian.net/browse/RET-1242
|
|
130
|
+
async def engage(
|
|
131
|
+
self,
|
|
132
|
+
height: Optional[float] = None,
|
|
133
|
+
height_from_base: Optional[float] = None,
|
|
134
|
+
must_be_running: bool = True,
|
|
135
|
+
) -> None:
|
|
136
|
+
"""Move the magnet to a specific height, measured from home position.
|
|
137
|
+
|
|
138
|
+
The units of position depend on the module model.
|
|
139
|
+
For GEN1, it's half millimeters ("short millimeters").
|
|
140
|
+
For GEN2, it's millimeters.
|
|
141
|
+
"""
|
|
142
|
+
if height is None:
|
|
143
|
+
assert height_from_base is not None, "An engage height must be specified"
|
|
144
|
+
height = height_from_base + OFFSET_TO_LABWARE_BOTTOM[self.model()]
|
|
145
|
+
|
|
146
|
+
if must_be_running:
|
|
147
|
+
await self.wait_for_is_running()
|
|
148
|
+
if not engage_height_is_in_range(self.model(), height):
|
|
149
|
+
raise ValueError(
|
|
150
|
+
f"Invalid engage height for {self.model()}: {height}. "
|
|
151
|
+
f"Must be 0 - {MAX_ENGAGE_HEIGHT[self.model()]}."
|
|
152
|
+
)
|
|
153
|
+
await self._driver.move(height)
|
|
154
|
+
self._current_height = await self._driver.get_mag_position()
|
|
155
|
+
|
|
156
|
+
async def deactivate(self, must_be_running: bool = True) -> None:
|
|
157
|
+
"""Home the magnet."""
|
|
158
|
+
if must_be_running:
|
|
159
|
+
await self.wait_for_is_running()
|
|
160
|
+
await self._driver.home()
|
|
161
|
+
await self.engage(0.0, must_be_running=must_be_running)
|
|
162
|
+
|
|
163
|
+
@property
|
|
164
|
+
def current_height(self) -> float:
|
|
165
|
+
"""Get the current height."""
|
|
166
|
+
return self._current_height
|
|
167
|
+
|
|
168
|
+
@property
|
|
169
|
+
def device_info(self) -> Dict[str, str]:
|
|
170
|
+
"""
|
|
171
|
+
|
|
172
|
+
Returns: a dict
|
|
173
|
+
{ 'serial': 'abc123', 'model': '8675309', 'version': '9001' }
|
|
174
|
+
|
|
175
|
+
"""
|
|
176
|
+
return self._device_info
|
|
177
|
+
|
|
178
|
+
@property
|
|
179
|
+
def serial_number(self) -> Optional[str]:
|
|
180
|
+
"""The usb serial number of this device"""
|
|
181
|
+
return self._device_info.get("serial")
|
|
182
|
+
|
|
183
|
+
@property
|
|
184
|
+
def status(self) -> types.MagneticStatus:
|
|
185
|
+
if self.current_height > 0:
|
|
186
|
+
return types.MagneticStatus.ENGAGED
|
|
187
|
+
else:
|
|
188
|
+
return types.MagneticStatus.DISENGAGED
|
|
189
|
+
|
|
190
|
+
@property
|
|
191
|
+
def engaged(self) -> bool:
|
|
192
|
+
if self.current_height > 0:
|
|
193
|
+
return True
|
|
194
|
+
else:
|
|
195
|
+
return False
|
|
196
|
+
|
|
197
|
+
@property
|
|
198
|
+
def live_data(self) -> types.LiveData:
|
|
199
|
+
data: types.MagneticModuleData = {
|
|
200
|
+
"engaged": self.engaged,
|
|
201
|
+
"height": self.current_height,
|
|
202
|
+
}
|
|
203
|
+
return {
|
|
204
|
+
"status": self.status,
|
|
205
|
+
"data": data,
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
@property
|
|
209
|
+
def is_simulated(self) -> bool:
|
|
210
|
+
return isinstance(self._driver, SimulatingDriver)
|
|
211
|
+
|
|
212
|
+
# Internal Methods
|
|
213
|
+
|
|
214
|
+
async def prep_for_update(self) -> str:
|
|
215
|
+
await self._driver.enter_programming_mode()
|
|
216
|
+
new_port = await update.find_bootloader_port()
|
|
217
|
+
return new_port or self.port
|
|
218
|
+
|
|
219
|
+
@staticmethod
|
|
220
|
+
def _model_from_revision(revision: Optional[str]) -> str:
|
|
221
|
+
"""Defines the revision -> model mapping"""
|
|
222
|
+
if not revision or "v" not in revision:
|
|
223
|
+
log.error(f"bad revision: {revision}")
|
|
224
|
+
return "magneticModuleV1"
|
|
225
|
+
try:
|
|
226
|
+
revision_num = float(revision.split("v")[-1])
|
|
227
|
+
except (ValueError, TypeError):
|
|
228
|
+
log.exception("bad revision: {revision}")
|
|
229
|
+
return "magneticModuleV1"
|
|
230
|
+
if revision_num < MagDeck.FIRST_GEN2_REVISION:
|
|
231
|
+
return "magneticModuleV1"
|
|
232
|
+
else:
|
|
233
|
+
return "magneticModuleV2"
|