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,442 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
import asyncio
|
|
3
|
+
import copy
|
|
4
|
+
import logging
|
|
5
|
+
from threading import Event
|
|
6
|
+
from typing import Dict, Optional, List, Tuple, TYPE_CHECKING, Sequence, Iterator, cast
|
|
7
|
+
from contextlib import contextmanager
|
|
8
|
+
|
|
9
|
+
from opentrons_shared_data.pipette import (
|
|
10
|
+
pipette_load_name_conversions as pipette_load_name,
|
|
11
|
+
mutable_configurations,
|
|
12
|
+
pipette_definition,
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
from opentrons import types
|
|
16
|
+
from opentrons.config.types import RobotConfig
|
|
17
|
+
from opentrons.config import get_opentrons_path
|
|
18
|
+
from opentrons.drivers.smoothie_drivers import SimulatingDriver
|
|
19
|
+
|
|
20
|
+
from opentrons.drivers.rpi_drivers.gpio_simulator import SimulatingGPIOCharDev
|
|
21
|
+
from opentrons.util.async_helpers import ensure_yield
|
|
22
|
+
|
|
23
|
+
from .. import modules
|
|
24
|
+
from ..types import BoardRevision, Axis
|
|
25
|
+
from ..module_control import AttachedModulesControl
|
|
26
|
+
from ..util import ot2_axis_to_string
|
|
27
|
+
|
|
28
|
+
if TYPE_CHECKING:
|
|
29
|
+
from opentrons_shared_data.pipette.types import PipetteName, PipetteModel
|
|
30
|
+
from ..dev_types import (
|
|
31
|
+
AttachedPipette,
|
|
32
|
+
AttachedInstruments,
|
|
33
|
+
PipetteSpec,
|
|
34
|
+
InstrumentHardwareConfigs,
|
|
35
|
+
)
|
|
36
|
+
from opentrons.drivers.rpi_drivers.dev_types import GPIODriverLike
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
MODULE_LOG = logging.getLogger(__name__)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
class Simulator:
|
|
43
|
+
"""This is a subclass of hardware_control that only simulates the
|
|
44
|
+
hardware actions. It is suitable for use on a dev machine or on
|
|
45
|
+
a robot with no smoothie connected.
|
|
46
|
+
"""
|
|
47
|
+
|
|
48
|
+
@classmethod
|
|
49
|
+
async def build(
|
|
50
|
+
cls,
|
|
51
|
+
attached_instruments: Dict[types.Mount, Dict[str, Optional[str]]],
|
|
52
|
+
attached_modules: Dict[str, List[modules.SimulatingModule]],
|
|
53
|
+
config: RobotConfig,
|
|
54
|
+
loop: asyncio.AbstractEventLoop,
|
|
55
|
+
strict_attached_instruments: bool = True,
|
|
56
|
+
) -> Simulator:
|
|
57
|
+
"""Build the simulator.
|
|
58
|
+
|
|
59
|
+
Use this factory method rather than the initializer to handle proper GPIO
|
|
60
|
+
initialization.
|
|
61
|
+
|
|
62
|
+
:param attached_instruments: A dictionary describing the instruments
|
|
63
|
+
the simulator should consider attached.
|
|
64
|
+
If this argument is specified and
|
|
65
|
+
:py:meth:`get_attached_instruments` is
|
|
66
|
+
called with expectations that do not
|
|
67
|
+
match, the call fails. This is useful for
|
|
68
|
+
making the simulator match the real
|
|
69
|
+
hardware, for instance to check if a
|
|
70
|
+
protocol asks for the right instruments.
|
|
71
|
+
This dict should map mounts to either
|
|
72
|
+
empty dicts or to dicts containing
|
|
73
|
+
'model' and 'id' keys.
|
|
74
|
+
:param attached_modules: A map of module type names (e.g.
|
|
75
|
+
`'tempdeck'` or `'magdeck'`) to lists of SimulatingModel
|
|
76
|
+
dataclasses representing
|
|
77
|
+
modules the simulator should assume are
|
|
78
|
+
attached. Like `attached_instruments`, used
|
|
79
|
+
to make the simulator match the setup of the
|
|
80
|
+
real hardware.
|
|
81
|
+
:param config: The robot config to use
|
|
82
|
+
:param loop: The asyncio event loop to use.
|
|
83
|
+
:param strict_attached_instruments: This param changes the behavior of
|
|
84
|
+
the instrument cache. If ``True``,
|
|
85
|
+
(default), ``cache_instrument``
|
|
86
|
+
calls requesting instruments not
|
|
87
|
+
in ``attached_instruments`` will
|
|
88
|
+
fail as if the instrument was not
|
|
89
|
+
present. If ``False``, those calls
|
|
90
|
+
will still pass but give a response
|
|
91
|
+
version of 1, while calls
|
|
92
|
+
requesting instruments that _are_
|
|
93
|
+
present get the full number.
|
|
94
|
+
"""
|
|
95
|
+
gpio = SimulatingGPIOCharDev("gpiochip0")
|
|
96
|
+
await gpio.setup()
|
|
97
|
+
return cls(
|
|
98
|
+
attached_instruments,
|
|
99
|
+
attached_modules,
|
|
100
|
+
config,
|
|
101
|
+
loop,
|
|
102
|
+
gpio,
|
|
103
|
+
strict_attached_instruments,
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
def __init__(
|
|
107
|
+
self,
|
|
108
|
+
attached_instruments: Dict[types.Mount, Dict[str, Optional[str]]],
|
|
109
|
+
attached_modules: Dict[str, List[modules.SimulatingModule]],
|
|
110
|
+
config: RobotConfig,
|
|
111
|
+
loop: asyncio.AbstractEventLoop,
|
|
112
|
+
gpio_chardev: GPIODriverLike,
|
|
113
|
+
strict_attached_instruments: bool = True,
|
|
114
|
+
) -> None:
|
|
115
|
+
"""Initialize the simulator.
|
|
116
|
+
|
|
117
|
+
Always prefer using :py:meth:`.build` to create an instance of this class. For
|
|
118
|
+
more information on arguments, see that method. If you want to use this
|
|
119
|
+
directly, you must pass in an initialized _and set up_ GPIO driver instance.
|
|
120
|
+
"""
|
|
121
|
+
self.config = config
|
|
122
|
+
self._loop = loop
|
|
123
|
+
self._smoothie_driver = SimulatingDriver()
|
|
124
|
+
self._gpio_chardev = gpio_chardev
|
|
125
|
+
|
|
126
|
+
def _sanitize_attached_instrument(
|
|
127
|
+
passed_ai: Optional[PipetteSpec] = None,
|
|
128
|
+
) -> PipetteSpec:
|
|
129
|
+
if not passed_ai or not passed_ai.get("model"):
|
|
130
|
+
return {"model": None, "id": None}
|
|
131
|
+
if pipette_load_name.supported_pipette(
|
|
132
|
+
cast("PipetteName", passed_ai["model"])
|
|
133
|
+
):
|
|
134
|
+
if pipette_load_name.is_model(passed_ai["model"]):
|
|
135
|
+
return passed_ai
|
|
136
|
+
else:
|
|
137
|
+
get_pip_model = pipette_load_name.convert_pipette_name(
|
|
138
|
+
cast("PipetteName", passed_ai["model"])
|
|
139
|
+
)
|
|
140
|
+
return {
|
|
141
|
+
"model": PipetteModel(str(get_pip_model)),
|
|
142
|
+
"id": passed_ai.get("id"),
|
|
143
|
+
}
|
|
144
|
+
raise KeyError(
|
|
145
|
+
"If you specify attached_instruments, the model "
|
|
146
|
+
"should be pipette names or pipette models, but "
|
|
147
|
+
f'{passed_ai["model"]} is not'
|
|
148
|
+
)
|
|
149
|
+
|
|
150
|
+
self._attached_instruments = {
|
|
151
|
+
m: _sanitize_attached_instrument(attached_instruments.get(m)) # type: ignore
|
|
152
|
+
for m in types.Mount.ot2_mounts()
|
|
153
|
+
}
|
|
154
|
+
self._stubbed_attached_modules = attached_modules
|
|
155
|
+
self._position = copy.copy(self._smoothie_driver.homed_position)
|
|
156
|
+
# Engaged axes start all true in smoothie for some reason so we
|
|
157
|
+
# imitate that here
|
|
158
|
+
# TODO(LC2642019) Create a simulating driver for smoothie instead of
|
|
159
|
+
# using a flag
|
|
160
|
+
|
|
161
|
+
self._engaged_axes = {ax: True for ax in self._smoothie_driver.homed_position}
|
|
162
|
+
self._lights = {"button": False, "rails": False}
|
|
163
|
+
self._run_flag = Event()
|
|
164
|
+
self._run_flag.set()
|
|
165
|
+
self._log = MODULE_LOG.getChild(repr(self))
|
|
166
|
+
self._strict_attached = bool(strict_attached_instruments)
|
|
167
|
+
self._board_revision = BoardRevision.OG
|
|
168
|
+
# TODO (lc 05-12-2021) In a follow-up refactor that pulls the execution
|
|
169
|
+
# manager responsbility into the controller/backend itself as opposed
|
|
170
|
+
# to the hardware api controller.
|
|
171
|
+
self._module_controls: Optional[AttachedModulesControl] = None
|
|
172
|
+
|
|
173
|
+
async def get_serial_number(self) -> Optional[str]:
|
|
174
|
+
return "simulator"
|
|
175
|
+
|
|
176
|
+
@property
|
|
177
|
+
def gpio_chardev(self) -> GPIODriverLike:
|
|
178
|
+
return self._gpio_chardev
|
|
179
|
+
|
|
180
|
+
@property
|
|
181
|
+
def module_controls(self) -> AttachedModulesControl:
|
|
182
|
+
if not self._module_controls:
|
|
183
|
+
raise AttributeError("Module controls not found.")
|
|
184
|
+
return self._module_controls
|
|
185
|
+
|
|
186
|
+
@module_controls.setter
|
|
187
|
+
def module_controls(self, module_controls: AttachedModulesControl) -> None:
|
|
188
|
+
self._module_controls = module_controls
|
|
189
|
+
|
|
190
|
+
@ensure_yield
|
|
191
|
+
async def update_position(self) -> Dict[str, float]:
|
|
192
|
+
return self._position
|
|
193
|
+
|
|
194
|
+
def _unhomed_axes(self, axes: Sequence[str]) -> List[str]:
|
|
195
|
+
return list(
|
|
196
|
+
axis
|
|
197
|
+
for axis in axes
|
|
198
|
+
if not self._smoothie_driver.homed_flags.get(axis, False)
|
|
199
|
+
)
|
|
200
|
+
|
|
201
|
+
def is_homed(self, axes: Sequence[str]) -> bool:
|
|
202
|
+
return not any(self._unhomed_axes(axes))
|
|
203
|
+
|
|
204
|
+
@ensure_yield
|
|
205
|
+
async def move(
|
|
206
|
+
self,
|
|
207
|
+
target_position: Dict[str, float],
|
|
208
|
+
home_flagged_axes: bool = True,
|
|
209
|
+
speed: Optional[float] = None,
|
|
210
|
+
axis_max_speeds: Optional[Dict[str, float]] = None,
|
|
211
|
+
) -> None:
|
|
212
|
+
self._position.update(target_position)
|
|
213
|
+
self._engaged_axes.update({ax: True for ax in target_position})
|
|
214
|
+
|
|
215
|
+
@ensure_yield
|
|
216
|
+
async def home(self, axes: Optional[List[str]] = None) -> Dict[str, float]:
|
|
217
|
+
# driver_3_0-> HOMED_POSITION
|
|
218
|
+
checked_axes = "".join(axes) if axes else "XYZABC"
|
|
219
|
+
self._position.update(
|
|
220
|
+
{ax: self._smoothie_driver.homed_position[ax] for ax in checked_axes}
|
|
221
|
+
)
|
|
222
|
+
self._engaged_axes.update({ax: True for ax in checked_axes})
|
|
223
|
+
await self._smoothie_driver.home(axis=checked_axes)
|
|
224
|
+
return self._position
|
|
225
|
+
|
|
226
|
+
@ensure_yield
|
|
227
|
+
async def fast_home(self, axis: Sequence[str], margin: float) -> Dict[str, float]:
|
|
228
|
+
for ax in axis:
|
|
229
|
+
self._position[ax] = self._smoothie_driver.homed_position[ax]
|
|
230
|
+
self._engaged_axes[ax] = True
|
|
231
|
+
return self._position
|
|
232
|
+
|
|
233
|
+
def _attached_to_mount(
|
|
234
|
+
self, mount: types.Mount, expected_instr: Optional["PipetteName"]
|
|
235
|
+
) -> AttachedPipette:
|
|
236
|
+
init_instr = self._attached_instruments.get(mount, {"model": None, "id": None})
|
|
237
|
+
found_model = init_instr["model"]
|
|
238
|
+
back_compat: List["PipetteName"] = []
|
|
239
|
+
|
|
240
|
+
path_to_overrides = get_opentrons_path("pipette_config_overrides_dir")
|
|
241
|
+
found_model_configs: Optional[pipette_definition.PipetteConfigurations] = None
|
|
242
|
+
|
|
243
|
+
converted_found_name: Optional[pipette_definition.PipetteNameType] = None
|
|
244
|
+
if found_model:
|
|
245
|
+
converted_found_model = pipette_load_name.convert_pipette_model(found_model)
|
|
246
|
+
converted_found_name = pipette_load_name.convert_to_pipette_name_type(
|
|
247
|
+
found_model
|
|
248
|
+
)
|
|
249
|
+
found_model_configs = (
|
|
250
|
+
mutable_configurations.load_with_mutable_configurations(
|
|
251
|
+
converted_found_model, path_to_overrides, init_instr["id"]
|
|
252
|
+
)
|
|
253
|
+
)
|
|
254
|
+
back_compat = found_model_configs.pipette_backcompat_names
|
|
255
|
+
if (
|
|
256
|
+
expected_instr
|
|
257
|
+
and found_model
|
|
258
|
+
and found_model_configs
|
|
259
|
+
and (
|
|
260
|
+
str(converted_found_name) != expected_instr
|
|
261
|
+
and expected_instr not in back_compat
|
|
262
|
+
)
|
|
263
|
+
):
|
|
264
|
+
if self._strict_attached:
|
|
265
|
+
raise RuntimeError(
|
|
266
|
+
"mount {}: expected instrument {} but got {}".format(
|
|
267
|
+
mount.name, expected_instr, found_model
|
|
268
|
+
)
|
|
269
|
+
)
|
|
270
|
+
else:
|
|
271
|
+
converted_expected_model = pipette_load_name.convert_pipette_name(
|
|
272
|
+
expected_instr
|
|
273
|
+
)
|
|
274
|
+
return {
|
|
275
|
+
"config": mutable_configurations.load_with_mutable_configurations(
|
|
276
|
+
converted_expected_model, path_to_overrides
|
|
277
|
+
),
|
|
278
|
+
"id": None,
|
|
279
|
+
}
|
|
280
|
+
elif found_model and found_model_configs:
|
|
281
|
+
# Instrument detected matches instrument expected (note:
|
|
282
|
+
# "instrument detected" means passed as an argument to the
|
|
283
|
+
# constructor of this class) OR,
|
|
284
|
+
# Instrument detected and no expected instrument specified
|
|
285
|
+
return {
|
|
286
|
+
"config": found_model_configs,
|
|
287
|
+
"id": init_instr["id"],
|
|
288
|
+
}
|
|
289
|
+
elif expected_instr:
|
|
290
|
+
# Expected instrument specified and no instrument detected
|
|
291
|
+
converted_expected_model = pipette_load_name.convert_pipette_name(
|
|
292
|
+
expected_instr
|
|
293
|
+
)
|
|
294
|
+
return {
|
|
295
|
+
"config": mutable_configurations.load_with_mutable_configurations(
|
|
296
|
+
converted_expected_model, path_to_overrides
|
|
297
|
+
),
|
|
298
|
+
"id": None,
|
|
299
|
+
}
|
|
300
|
+
else:
|
|
301
|
+
# No instrument detected or expected
|
|
302
|
+
return {"config": None, "id": None}
|
|
303
|
+
|
|
304
|
+
@ensure_yield
|
|
305
|
+
async def get_attached_instruments(
|
|
306
|
+
self, expected: Dict[types.Mount, "PipetteName"]
|
|
307
|
+
) -> AttachedInstruments:
|
|
308
|
+
"""Update the internal cache of attached instruments.
|
|
309
|
+
|
|
310
|
+
This method allows after-init-time specification of attached simulated
|
|
311
|
+
instruments. The method will return
|
|
312
|
+
- the instruments specified at init-time, or if those do not exists,
|
|
313
|
+
- the instruments specified in expected, or if that is not passed,
|
|
314
|
+
- nothing
|
|
315
|
+
|
|
316
|
+
:param expected: A mapping of mount to instrument model prefixes. When
|
|
317
|
+
loading instruments from a prefix, we return the
|
|
318
|
+
lexically-first model that matches the prefix. If the
|
|
319
|
+
models specified in expected do not match the models
|
|
320
|
+
specified in the `attached_instruments` argument of
|
|
321
|
+
:py:meth:`__init__`, :py:attr:`RuntimeError` is
|
|
322
|
+
raised.
|
|
323
|
+
:raises RuntimeError: If an instrument is expected but not found.
|
|
324
|
+
:returns: A dict of mount to either instrument model names or `None`.
|
|
325
|
+
"""
|
|
326
|
+
return {
|
|
327
|
+
mount: self._attached_to_mount(mount, expected.get(mount))
|
|
328
|
+
for mount in types.Mount.ot2_mounts()
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
def set_active_current(self, axis_currents: Dict[Axis, float]) -> None:
|
|
332
|
+
pass
|
|
333
|
+
|
|
334
|
+
@ensure_yield
|
|
335
|
+
async def watch(self) -> None:
|
|
336
|
+
new_mods_at_ports = []
|
|
337
|
+
for mod_name, list_of_modules in self._stubbed_attached_modules.items():
|
|
338
|
+
for module_details in list_of_modules:
|
|
339
|
+
new_mods_at_ports.append(
|
|
340
|
+
modules.SimulatingModuleAtPort(
|
|
341
|
+
port=f"/dev/ot_module_sim_{mod_name}{str(module_details.serial_number)}",
|
|
342
|
+
name=mod_name,
|
|
343
|
+
serial_number=module_details.serial_number,
|
|
344
|
+
model=module_details.model,
|
|
345
|
+
)
|
|
346
|
+
)
|
|
347
|
+
await self.module_controls.register_modules(new_mods_at_ports=new_mods_at_ports)
|
|
348
|
+
|
|
349
|
+
@contextmanager
|
|
350
|
+
def save_current(self) -> Iterator[None]:
|
|
351
|
+
yield
|
|
352
|
+
|
|
353
|
+
@property
|
|
354
|
+
def axis_bounds(self) -> Dict[Axis, Tuple[float, float]]:
|
|
355
|
+
"""The (minimum, maximum) bounds for each axis."""
|
|
356
|
+
return {
|
|
357
|
+
Axis[ax]: (0, pos)
|
|
358
|
+
for ax, pos in self._smoothie_driver.axis_bounds.items()
|
|
359
|
+
if ax not in "BC"
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
@property
|
|
363
|
+
def fw_version(self) -> Optional[str]:
|
|
364
|
+
return "Virtual Smoothie"
|
|
365
|
+
|
|
366
|
+
@ensure_yield
|
|
367
|
+
async def update_fw_version(self) -> None:
|
|
368
|
+
pass
|
|
369
|
+
|
|
370
|
+
@property
|
|
371
|
+
def board_revision(self) -> BoardRevision:
|
|
372
|
+
return self._board_revision
|
|
373
|
+
|
|
374
|
+
@ensure_yield
|
|
375
|
+
async def update_firmware(
|
|
376
|
+
self, filename: str, loop: asyncio.AbstractEventLoop, modeset: bool
|
|
377
|
+
) -> str:
|
|
378
|
+
return "Did nothing (simulating)"
|
|
379
|
+
|
|
380
|
+
def engaged_axes(self) -> Dict[str, bool]:
|
|
381
|
+
return self._engaged_axes
|
|
382
|
+
|
|
383
|
+
@ensure_yield
|
|
384
|
+
async def disengage_axes(self, axes: List[str]) -> None:
|
|
385
|
+
self._engaged_axes.update({ax: False for ax in axes})
|
|
386
|
+
|
|
387
|
+
def set_lights(self, button: Optional[bool], rails: Optional[bool]) -> None:
|
|
388
|
+
if button is not None:
|
|
389
|
+
self._lights["button"] = button
|
|
390
|
+
if rails is not None:
|
|
391
|
+
self._lights["rails"] = rails
|
|
392
|
+
|
|
393
|
+
def get_lights(self) -> Dict[str, bool]:
|
|
394
|
+
return self._lights
|
|
395
|
+
|
|
396
|
+
def pause(self) -> None:
|
|
397
|
+
self._run_flag.clear()
|
|
398
|
+
|
|
399
|
+
def resume(self) -> None:
|
|
400
|
+
self._run_flag.set()
|
|
401
|
+
|
|
402
|
+
@ensure_yield
|
|
403
|
+
async def halt(self) -> None:
|
|
404
|
+
self._run_flag.set()
|
|
405
|
+
|
|
406
|
+
@ensure_yield
|
|
407
|
+
async def hard_halt(self) -> None:
|
|
408
|
+
self._run_flag.set()
|
|
409
|
+
|
|
410
|
+
@ensure_yield
|
|
411
|
+
async def probe(self, axis: str, distance: float) -> Dict[str, float]:
|
|
412
|
+
self._position[axis.upper()] = self._position[axis.upper()] + distance
|
|
413
|
+
return self._position
|
|
414
|
+
|
|
415
|
+
@ensure_yield
|
|
416
|
+
async def clean_up(self) -> None:
|
|
417
|
+
pass
|
|
418
|
+
|
|
419
|
+
@ensure_yield
|
|
420
|
+
async def configure_mount(
|
|
421
|
+
self, mount: types.Mount, config: InstrumentHardwareConfigs
|
|
422
|
+
) -> None:
|
|
423
|
+
mount_axis = Axis.by_mount(mount)
|
|
424
|
+
plunger_axis = Axis.of_plunger(mount)
|
|
425
|
+
|
|
426
|
+
await self._smoothie_driver.update_steps_per_mm(
|
|
427
|
+
{ot2_axis_to_string(plunger_axis): config["steps_per_mm"]}
|
|
428
|
+
)
|
|
429
|
+
await self._smoothie_driver.update_pipette_config(
|
|
430
|
+
ot2_axis_to_string(mount_axis), {"home": config["home_pos"]}
|
|
431
|
+
)
|
|
432
|
+
await self._smoothie_driver.update_pipette_config(
|
|
433
|
+
ot2_axis_to_string(plunger_axis), {"max_travel": config["max_travel"]}
|
|
434
|
+
)
|
|
435
|
+
self._smoothie_driver.set_dwelling_current(
|
|
436
|
+
{ot2_axis_to_string(plunger_axis): config["idle_current"]}
|
|
437
|
+
)
|
|
438
|
+
ms = config["splits"]
|
|
439
|
+
if ms:
|
|
440
|
+
self._smoothie_driver.configure_splits_for(
|
|
441
|
+
{ot2_axis_to_string(plunger_axis): ms}
|
|
442
|
+
)
|
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
from opentrons.hardware_control.types import (
|
|
2
|
+
StatusBarState,
|
|
3
|
+
StatusBarUpdateEvent,
|
|
4
|
+
StatusBarUpdateListener,
|
|
5
|
+
StatusBarUpdateUnsubscriber,
|
|
6
|
+
)
|
|
7
|
+
from opentrons_hardware.hardware_control import status_bar
|
|
8
|
+
from opentrons_hardware.firmware_bindings.binary_constants import (
|
|
9
|
+
LightAnimationType,
|
|
10
|
+
LightTransitionType,
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
from typing import List
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class StatusBarStateController:
|
|
17
|
+
"""Stateful control of the status bar.
|
|
18
|
+
|
|
19
|
+
Note that the controller can be enabled/disabled at any time. If the controller
|
|
20
|
+
is ever disabled, the lights are set to OFF and future state changes will not
|
|
21
|
+
write to the rear panel board. However, the proper `StatusBarState` will still
|
|
22
|
+
be cached, so if the controller becomes enabled/disabled in the future it will
|
|
23
|
+
be able to resume the correct animation based on the current system state."""
|
|
24
|
+
|
|
25
|
+
def __init__(self, controller: status_bar.StatusBar) -> None:
|
|
26
|
+
"""Create a StatusBarStateController."""
|
|
27
|
+
self._status_bar_state = StatusBarState.IDLE
|
|
28
|
+
self._controller = controller
|
|
29
|
+
self._enabled = True
|
|
30
|
+
self._listeners: List[StatusBarUpdateListener] = []
|
|
31
|
+
|
|
32
|
+
def add_listener(
|
|
33
|
+
self, listener: StatusBarUpdateListener
|
|
34
|
+
) -> StatusBarUpdateUnsubscriber:
|
|
35
|
+
"""Add a listener to the status bar state."""
|
|
36
|
+
if listener not in self._listeners:
|
|
37
|
+
self._listeners.append(listener)
|
|
38
|
+
|
|
39
|
+
def _remove_listener() -> None:
|
|
40
|
+
self._listeners.remove(listener)
|
|
41
|
+
|
|
42
|
+
return _remove_listener
|
|
43
|
+
|
|
44
|
+
def emit_event(self) -> None:
|
|
45
|
+
"""Emit an event to all listeners."""
|
|
46
|
+
for listener in self._listeners:
|
|
47
|
+
listener(StatusBarUpdateEvent(self._status_bar_state, self._enabled))
|
|
48
|
+
|
|
49
|
+
async def _status_bar_idle(self) -> None:
|
|
50
|
+
self._status_bar_state = StatusBarState.IDLE
|
|
51
|
+
if self._enabled:
|
|
52
|
+
await self._controller.static_color(status_bar.WHITE)
|
|
53
|
+
|
|
54
|
+
async def _status_bar_running(self) -> None:
|
|
55
|
+
self._status_bar_state = StatusBarState.RUNNING
|
|
56
|
+
if self._enabled:
|
|
57
|
+
await self._controller.static_color(status_bar.GREEN)
|
|
58
|
+
|
|
59
|
+
async def _status_bar_paused(self) -> None:
|
|
60
|
+
self._status_bar_state = StatusBarState.PAUSED
|
|
61
|
+
if self._enabled:
|
|
62
|
+
await self._controller.pulse_color(status_bar.BLUE)
|
|
63
|
+
|
|
64
|
+
async def _status_bar_hardware_error(self) -> None:
|
|
65
|
+
self._status_bar_state = StatusBarState.HARDWARE_ERROR
|
|
66
|
+
if self._enabled:
|
|
67
|
+
await self._controller.flash_color(status_bar.RED)
|
|
68
|
+
|
|
69
|
+
async def _status_bar_software_error(self) -> None:
|
|
70
|
+
self._status_bar_state = StatusBarState.SOFTWARE_ERROR
|
|
71
|
+
if self._enabled:
|
|
72
|
+
await self._controller.static_color(status_bar.YELLOW)
|
|
73
|
+
|
|
74
|
+
async def _status_bar_error_recovery(self) -> None:
|
|
75
|
+
self._status_bar_state = StatusBarState.ERROR_RECOVERY
|
|
76
|
+
if self._enabled:
|
|
77
|
+
await self._controller.pulse_color(status_bar.YELLOW)
|
|
78
|
+
|
|
79
|
+
async def _status_bar_confirm(self) -> None:
|
|
80
|
+
# Confirm should revert to IDLE
|
|
81
|
+
self._status_bar_state = StatusBarState.IDLE
|
|
82
|
+
if self._enabled:
|
|
83
|
+
await self._controller.blink_once(status_bar.GREEN, status_bar.WHITE)
|
|
84
|
+
|
|
85
|
+
async def _status_bar_run_complete(self) -> None:
|
|
86
|
+
self._status_bar_state = StatusBarState.RUN_COMPLETED
|
|
87
|
+
if self._enabled:
|
|
88
|
+
await self._controller.pulse_color(status_bar.GREEN)
|
|
89
|
+
|
|
90
|
+
async def _status_bar_updating(self) -> None:
|
|
91
|
+
self._status_bar_state = StatusBarState.UPDATING
|
|
92
|
+
if self._enabled:
|
|
93
|
+
await self._controller.pulse_color(status_bar.WHITE)
|
|
94
|
+
|
|
95
|
+
async def _status_bar_activation(self) -> None:
|
|
96
|
+
# Activation should revert to IDLE
|
|
97
|
+
self._status_bar_state = StatusBarState.IDLE
|
|
98
|
+
|
|
99
|
+
# This animation uses an intermediate color between the blue and the white.
|
|
100
|
+
# This results in a sort of light-blue effect.
|
|
101
|
+
steps: List[status_bar.ColorStep] = [
|
|
102
|
+
status_bar.ColorStep(LightTransitionType.linear, 250, status_bar.OFF),
|
|
103
|
+
status_bar.ColorStep(LightTransitionType.linear, 750, status_bar.OFF),
|
|
104
|
+
status_bar.ColorStep(LightTransitionType.linear, 1000, status_bar.BLUE),
|
|
105
|
+
status_bar.ColorStep(
|
|
106
|
+
LightTransitionType.linear,
|
|
107
|
+
250,
|
|
108
|
+
status_bar.Color(
|
|
109
|
+
r=0,
|
|
110
|
+
g=int(status_bar.BLUE.g * 0.75),
|
|
111
|
+
b=int(status_bar.BLUE.b * 0.75),
|
|
112
|
+
w=50,
|
|
113
|
+
),
|
|
114
|
+
),
|
|
115
|
+
status_bar.ColorStep(LightTransitionType.linear, 250, status_bar.WHITE),
|
|
116
|
+
]
|
|
117
|
+
|
|
118
|
+
if self._enabled:
|
|
119
|
+
await self._controller.start_animation(
|
|
120
|
+
steps=steps, type=LightAnimationType.single_shot
|
|
121
|
+
)
|
|
122
|
+
|
|
123
|
+
async def _status_bar_disco(self) -> None:
|
|
124
|
+
# TODO - update implementation
|
|
125
|
+
colors = [
|
|
126
|
+
status_bar.GREEN,
|
|
127
|
+
status_bar.YELLOW,
|
|
128
|
+
status_bar.PURPLE,
|
|
129
|
+
status_bar.ORANGE,
|
|
130
|
+
status_bar.GREEN,
|
|
131
|
+
status_bar.YELLOW,
|
|
132
|
+
status_bar.PURPLE,
|
|
133
|
+
status_bar.ORANGE,
|
|
134
|
+
status_bar.WHITE,
|
|
135
|
+
]
|
|
136
|
+
steps: List[status_bar.ColorStep] = [
|
|
137
|
+
status_bar.ColorStep(LightTransitionType.linear, 300, color)
|
|
138
|
+
for color in colors
|
|
139
|
+
]
|
|
140
|
+
steps.append(
|
|
141
|
+
status_bar.ColorStep(LightTransitionType.linear, 500, status_bar.OFF)
|
|
142
|
+
)
|
|
143
|
+
steps.append(
|
|
144
|
+
status_bar.ColorStep(LightTransitionType.linear, 75, status_bar.BLUE)
|
|
145
|
+
)
|
|
146
|
+
steps.append(
|
|
147
|
+
status_bar.ColorStep(
|
|
148
|
+
LightTransitionType.instant,
|
|
149
|
+
transition_time_ms=150,
|
|
150
|
+
color=status_bar.GREEN,
|
|
151
|
+
)
|
|
152
|
+
)
|
|
153
|
+
steps.append(
|
|
154
|
+
status_bar.ColorStep(
|
|
155
|
+
LightTransitionType.instant,
|
|
156
|
+
transition_time_ms=150,
|
|
157
|
+
color=status_bar.OFF,
|
|
158
|
+
)
|
|
159
|
+
)
|
|
160
|
+
steps.append(
|
|
161
|
+
status_bar.ColorStep(
|
|
162
|
+
LightTransitionType.instant,
|
|
163
|
+
transition_time_ms=150,
|
|
164
|
+
color=status_bar.GREEN,
|
|
165
|
+
)
|
|
166
|
+
)
|
|
167
|
+
steps.append(
|
|
168
|
+
status_bar.ColorStep(
|
|
169
|
+
LightTransitionType.linear,
|
|
170
|
+
transition_time_ms=1000,
|
|
171
|
+
color=status_bar.WHITE,
|
|
172
|
+
)
|
|
173
|
+
)
|
|
174
|
+
|
|
175
|
+
self._status_bar_state = StatusBarState.IDLE
|
|
176
|
+
if self._enabled:
|
|
177
|
+
await self._controller.start_animation(
|
|
178
|
+
steps=steps, type=LightAnimationType.single_shot
|
|
179
|
+
)
|
|
180
|
+
|
|
181
|
+
async def _status_bar_off(self) -> None:
|
|
182
|
+
self._status_bar_state = StatusBarState.OFF
|
|
183
|
+
if self._enabled:
|
|
184
|
+
await self._controller.static_color(status_bar.OFF)
|
|
185
|
+
|
|
186
|
+
async def set_status_bar_state(self, state: StatusBarState) -> None:
|
|
187
|
+
"""Main interface to set a new state."""
|
|
188
|
+
callbacks = {
|
|
189
|
+
StatusBarState.IDLE: self._status_bar_idle,
|
|
190
|
+
StatusBarState.RUNNING: self._status_bar_running,
|
|
191
|
+
StatusBarState.PAUSED: self._status_bar_paused,
|
|
192
|
+
StatusBarState.HARDWARE_ERROR: self._status_bar_hardware_error,
|
|
193
|
+
StatusBarState.SOFTWARE_ERROR: self._status_bar_software_error,
|
|
194
|
+
StatusBarState.ERROR_RECOVERY: self._status_bar_error_recovery,
|
|
195
|
+
StatusBarState.CONFIRMATION: self._status_bar_confirm,
|
|
196
|
+
StatusBarState.RUN_COMPLETED: self._status_bar_run_complete,
|
|
197
|
+
StatusBarState.UPDATING: self._status_bar_updating,
|
|
198
|
+
StatusBarState.ACTIVATION: self._status_bar_activation,
|
|
199
|
+
StatusBarState.DISCO: self._status_bar_disco,
|
|
200
|
+
StatusBarState.OFF: self._status_bar_off,
|
|
201
|
+
}
|
|
202
|
+
await callbacks[state]()
|
|
203
|
+
self.emit_event()
|
|
204
|
+
|
|
205
|
+
def get_current_state(self) -> StatusBarState:
|
|
206
|
+
"""Get the current state."""
|
|
207
|
+
return self._status_bar_state
|
|
208
|
+
|
|
209
|
+
async def set_enabled(self, enabled: bool) -> None:
|
|
210
|
+
"""Enable or disable the status bar.
|
|
211
|
+
|
|
212
|
+
If the status bar is newly disabled, the lights are set OFF
|
|
213
|
+
and the old status is cached so it can later be restored.
|
|
214
|
+
|
|
215
|
+
If the status bar is newly enabled, the last-set animation
|
|
216
|
+
will be sent to the rear panel.
|
|
217
|
+
|
|
218
|
+
NOTE When the status bar is disabled, `set_status_bar_state` will
|
|
219
|
+
still update the internal status bar setting as if the bar is on!
|
|
220
|
+
This means that, when the status bar is reenabled, it will look
|
|
221
|
+
correct for the current robot status."""
|
|
222
|
+
if enabled == self._enabled:
|
|
223
|
+
return
|
|
224
|
+
|
|
225
|
+
if enabled:
|
|
226
|
+
# Need to turn Enabled true *first* so that we can actually write
|
|
227
|
+
# the setting to the rear panel
|
|
228
|
+
self._enabled = True
|
|
229
|
+
await self.set_status_bar_state(self._status_bar_state)
|
|
230
|
+
else:
|
|
231
|
+
cached_state = self.get_current_state()
|
|
232
|
+
await self.set_status_bar_state(StatusBarState.OFF)
|
|
233
|
+
self._enabled = False
|
|
234
|
+
# This ensures that the status bar will be set to the correct state
|
|
235
|
+
# if it's reactivated before the state gets set again.
|
|
236
|
+
self._status_bar_state = cached_state
|
|
237
|
+
|
|
238
|
+
def get_enabled(self) -> bool:
|
|
239
|
+
"""Check whether the status bar is enabled."""
|
|
240
|
+
return self._enabled
|