opentrons 8.6.0a1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of opentrons might be problematic. Click here for more details.
- opentrons/__init__.py +150 -0
- opentrons/_version.py +34 -0
- opentrons/calibration_storage/__init__.py +54 -0
- opentrons/calibration_storage/deck_configuration.py +62 -0
- opentrons/calibration_storage/encoder_decoder.py +31 -0
- opentrons/calibration_storage/file_operators.py +142 -0
- opentrons/calibration_storage/helpers.py +103 -0
- opentrons/calibration_storage/ot2/__init__.py +34 -0
- opentrons/calibration_storage/ot2/deck_attitude.py +85 -0
- opentrons/calibration_storage/ot2/mark_bad_calibration.py +27 -0
- opentrons/calibration_storage/ot2/models/__init__.py +0 -0
- opentrons/calibration_storage/ot2/models/v1.py +149 -0
- opentrons/calibration_storage/ot2/pipette_offset.py +129 -0
- opentrons/calibration_storage/ot2/tip_length.py +281 -0
- opentrons/calibration_storage/ot3/__init__.py +31 -0
- opentrons/calibration_storage/ot3/deck_attitude.py +83 -0
- opentrons/calibration_storage/ot3/gripper_offset.py +156 -0
- opentrons/calibration_storage/ot3/models/__init__.py +0 -0
- opentrons/calibration_storage/ot3/models/v1.py +122 -0
- opentrons/calibration_storage/ot3/module_offset.py +138 -0
- opentrons/calibration_storage/ot3/pipette_offset.py +95 -0
- opentrons/calibration_storage/types.py +45 -0
- opentrons/cli/__init__.py +21 -0
- opentrons/cli/__main__.py +5 -0
- opentrons/cli/analyze.py +501 -0
- opentrons/config/__init__.py +631 -0
- opentrons/config/advanced_settings.py +871 -0
- opentrons/config/defaults_ot2.py +214 -0
- opentrons/config/defaults_ot3.py +499 -0
- opentrons/config/feature_flags.py +86 -0
- opentrons/config/gripper_config.py +55 -0
- opentrons/config/reset.py +203 -0
- opentrons/config/robot_configs.py +187 -0
- opentrons/config/types.py +183 -0
- opentrons/drivers/__init__.py +0 -0
- opentrons/drivers/absorbance_reader/__init__.py +11 -0
- opentrons/drivers/absorbance_reader/abstract.py +72 -0
- opentrons/drivers/absorbance_reader/async_byonoy.py +352 -0
- opentrons/drivers/absorbance_reader/driver.py +81 -0
- opentrons/drivers/absorbance_reader/hid_protocol.py +161 -0
- opentrons/drivers/absorbance_reader/simulator.py +84 -0
- opentrons/drivers/asyncio/__init__.py +0 -0
- opentrons/drivers/asyncio/communication/__init__.py +22 -0
- opentrons/drivers/asyncio/communication/async_serial.py +183 -0
- opentrons/drivers/asyncio/communication/errors.py +88 -0
- opentrons/drivers/asyncio/communication/serial_connection.py +552 -0
- opentrons/drivers/command_builder.py +102 -0
- opentrons/drivers/flex_stacker/__init__.py +13 -0
- opentrons/drivers/flex_stacker/abstract.py +214 -0
- opentrons/drivers/flex_stacker/driver.py +768 -0
- opentrons/drivers/flex_stacker/errors.py +68 -0
- opentrons/drivers/flex_stacker/simulator.py +309 -0
- opentrons/drivers/flex_stacker/types.py +367 -0
- opentrons/drivers/flex_stacker/utils.py +19 -0
- opentrons/drivers/heater_shaker/__init__.py +5 -0
- opentrons/drivers/heater_shaker/abstract.py +76 -0
- opentrons/drivers/heater_shaker/driver.py +204 -0
- opentrons/drivers/heater_shaker/simulator.py +94 -0
- opentrons/drivers/mag_deck/__init__.py +6 -0
- opentrons/drivers/mag_deck/abstract.py +44 -0
- opentrons/drivers/mag_deck/driver.py +208 -0
- opentrons/drivers/mag_deck/simulator.py +63 -0
- opentrons/drivers/rpi_drivers/__init__.py +33 -0
- opentrons/drivers/rpi_drivers/dev_types.py +94 -0
- opentrons/drivers/rpi_drivers/gpio.py +282 -0
- opentrons/drivers/rpi_drivers/gpio_simulator.py +127 -0
- opentrons/drivers/rpi_drivers/interfaces.py +15 -0
- opentrons/drivers/rpi_drivers/types.py +364 -0
- opentrons/drivers/rpi_drivers/usb.py +102 -0
- opentrons/drivers/rpi_drivers/usb_simulator.py +22 -0
- opentrons/drivers/serial_communication.py +151 -0
- opentrons/drivers/smoothie_drivers/__init__.py +4 -0
- opentrons/drivers/smoothie_drivers/connection.py +51 -0
- opentrons/drivers/smoothie_drivers/constants.py +121 -0
- opentrons/drivers/smoothie_drivers/driver_3_0.py +1933 -0
- opentrons/drivers/smoothie_drivers/errors.py +49 -0
- opentrons/drivers/smoothie_drivers/parse_utils.py +143 -0
- opentrons/drivers/smoothie_drivers/simulator.py +99 -0
- opentrons/drivers/smoothie_drivers/types.py +16 -0
- opentrons/drivers/temp_deck/__init__.py +10 -0
- opentrons/drivers/temp_deck/abstract.py +54 -0
- opentrons/drivers/temp_deck/driver.py +197 -0
- opentrons/drivers/temp_deck/simulator.py +57 -0
- opentrons/drivers/thermocycler/__init__.py +12 -0
- opentrons/drivers/thermocycler/abstract.py +99 -0
- opentrons/drivers/thermocycler/driver.py +395 -0
- opentrons/drivers/thermocycler/simulator.py +126 -0
- opentrons/drivers/types.py +107 -0
- opentrons/drivers/utils.py +222 -0
- opentrons/execute.py +742 -0
- opentrons/hardware_control/__init__.py +65 -0
- opentrons/hardware_control/__main__.py +77 -0
- opentrons/hardware_control/adapters.py +98 -0
- opentrons/hardware_control/api.py +1347 -0
- opentrons/hardware_control/backends/__init__.py +7 -0
- opentrons/hardware_control/backends/controller.py +400 -0
- opentrons/hardware_control/backends/errors.py +9 -0
- opentrons/hardware_control/backends/estop_state.py +164 -0
- opentrons/hardware_control/backends/flex_protocol.py +497 -0
- opentrons/hardware_control/backends/ot3controller.py +1930 -0
- opentrons/hardware_control/backends/ot3simulator.py +900 -0
- opentrons/hardware_control/backends/ot3utils.py +664 -0
- opentrons/hardware_control/backends/simulator.py +442 -0
- opentrons/hardware_control/backends/status_bar_state.py +240 -0
- opentrons/hardware_control/backends/subsystem_manager.py +431 -0
- opentrons/hardware_control/backends/tip_presence_manager.py +173 -0
- opentrons/hardware_control/backends/types.py +14 -0
- opentrons/hardware_control/constants.py +6 -0
- opentrons/hardware_control/dev_types.py +125 -0
- opentrons/hardware_control/emulation/__init__.py +0 -0
- opentrons/hardware_control/emulation/abstract_emulator.py +21 -0
- opentrons/hardware_control/emulation/app.py +56 -0
- opentrons/hardware_control/emulation/connection_handler.py +38 -0
- opentrons/hardware_control/emulation/heater_shaker.py +150 -0
- opentrons/hardware_control/emulation/magdeck.py +60 -0
- opentrons/hardware_control/emulation/module_server/__init__.py +8 -0
- opentrons/hardware_control/emulation/module_server/client.py +78 -0
- opentrons/hardware_control/emulation/module_server/helpers.py +130 -0
- opentrons/hardware_control/emulation/module_server/models.py +31 -0
- opentrons/hardware_control/emulation/module_server/server.py +110 -0
- opentrons/hardware_control/emulation/parser.py +74 -0
- opentrons/hardware_control/emulation/proxy.py +241 -0
- opentrons/hardware_control/emulation/run_emulator.py +68 -0
- opentrons/hardware_control/emulation/scripts/__init__.py +0 -0
- opentrons/hardware_control/emulation/scripts/run_app.py +54 -0
- opentrons/hardware_control/emulation/scripts/run_module_emulator.py +72 -0
- opentrons/hardware_control/emulation/scripts/run_smoothie.py +37 -0
- opentrons/hardware_control/emulation/settings.py +119 -0
- opentrons/hardware_control/emulation/simulations.py +133 -0
- opentrons/hardware_control/emulation/smoothie.py +192 -0
- opentrons/hardware_control/emulation/tempdeck.py +69 -0
- opentrons/hardware_control/emulation/thermocycler.py +128 -0
- opentrons/hardware_control/emulation/types.py +10 -0
- opentrons/hardware_control/emulation/util.py +38 -0
- opentrons/hardware_control/errors.py +43 -0
- opentrons/hardware_control/execution_manager.py +164 -0
- opentrons/hardware_control/instruments/__init__.py +5 -0
- opentrons/hardware_control/instruments/instrument_abc.py +39 -0
- opentrons/hardware_control/instruments/ot2/__init__.py +0 -0
- opentrons/hardware_control/instruments/ot2/instrument_calibration.py +152 -0
- opentrons/hardware_control/instruments/ot2/pipette.py +777 -0
- opentrons/hardware_control/instruments/ot2/pipette_handler.py +995 -0
- opentrons/hardware_control/instruments/ot3/__init__.py +0 -0
- opentrons/hardware_control/instruments/ot3/gripper.py +420 -0
- opentrons/hardware_control/instruments/ot3/gripper_handler.py +173 -0
- opentrons/hardware_control/instruments/ot3/instrument_calibration.py +214 -0
- opentrons/hardware_control/instruments/ot3/pipette.py +858 -0
- opentrons/hardware_control/instruments/ot3/pipette_handler.py +1030 -0
- opentrons/hardware_control/module_control.py +332 -0
- opentrons/hardware_control/modules/__init__.py +69 -0
- opentrons/hardware_control/modules/absorbance_reader.py +373 -0
- opentrons/hardware_control/modules/errors.py +7 -0
- opentrons/hardware_control/modules/flex_stacker.py +948 -0
- opentrons/hardware_control/modules/heater_shaker.py +426 -0
- opentrons/hardware_control/modules/lid_temp_status.py +35 -0
- opentrons/hardware_control/modules/magdeck.py +233 -0
- opentrons/hardware_control/modules/mod_abc.py +245 -0
- opentrons/hardware_control/modules/module_calibration.py +93 -0
- opentrons/hardware_control/modules/plate_temp_status.py +61 -0
- opentrons/hardware_control/modules/tempdeck.py +299 -0
- opentrons/hardware_control/modules/thermocycler.py +731 -0
- opentrons/hardware_control/modules/types.py +417 -0
- opentrons/hardware_control/modules/update.py +255 -0
- opentrons/hardware_control/modules/utils.py +73 -0
- opentrons/hardware_control/motion_utilities.py +318 -0
- opentrons/hardware_control/nozzle_manager.py +422 -0
- opentrons/hardware_control/ot3_calibration.py +1171 -0
- opentrons/hardware_control/ot3api.py +3227 -0
- opentrons/hardware_control/pause_manager.py +31 -0
- opentrons/hardware_control/poller.py +112 -0
- opentrons/hardware_control/protocols/__init__.py +106 -0
- opentrons/hardware_control/protocols/asyncio_configurable.py +11 -0
- opentrons/hardware_control/protocols/calibratable.py +45 -0
- opentrons/hardware_control/protocols/chassis_accessory_manager.py +90 -0
- opentrons/hardware_control/protocols/configurable.py +48 -0
- opentrons/hardware_control/protocols/event_sourcer.py +18 -0
- opentrons/hardware_control/protocols/execution_controllable.py +33 -0
- opentrons/hardware_control/protocols/flex_calibratable.py +96 -0
- opentrons/hardware_control/protocols/flex_instrument_configurer.py +52 -0
- opentrons/hardware_control/protocols/gripper_controller.py +55 -0
- opentrons/hardware_control/protocols/hardware_manager.py +51 -0
- opentrons/hardware_control/protocols/identifiable.py +16 -0
- opentrons/hardware_control/protocols/instrument_configurer.py +206 -0
- opentrons/hardware_control/protocols/liquid_handler.py +266 -0
- opentrons/hardware_control/protocols/module_provider.py +16 -0
- opentrons/hardware_control/protocols/motion_controller.py +243 -0
- opentrons/hardware_control/protocols/position_estimator.py +45 -0
- opentrons/hardware_control/protocols/simulatable.py +10 -0
- opentrons/hardware_control/protocols/stoppable.py +9 -0
- opentrons/hardware_control/protocols/types.py +27 -0
- opentrons/hardware_control/robot_calibration.py +224 -0
- opentrons/hardware_control/scripts/README.md +28 -0
- opentrons/hardware_control/scripts/__init__.py +1 -0
- opentrons/hardware_control/scripts/gripper_control.py +208 -0
- opentrons/hardware_control/scripts/ot3gripper +7 -0
- opentrons/hardware_control/scripts/ot3repl +7 -0
- opentrons/hardware_control/scripts/repl.py +187 -0
- opentrons/hardware_control/scripts/tc_control.py +97 -0
- opentrons/hardware_control/simulator_setup.py +260 -0
- opentrons/hardware_control/thread_manager.py +431 -0
- opentrons/hardware_control/threaded_async_lock.py +97 -0
- opentrons/hardware_control/types.py +792 -0
- opentrons/hardware_control/util.py +234 -0
- opentrons/legacy_broker.py +53 -0
- opentrons/legacy_commands/__init__.py +1 -0
- opentrons/legacy_commands/commands.py +483 -0
- opentrons/legacy_commands/helpers.py +153 -0
- opentrons/legacy_commands/module_commands.py +215 -0
- opentrons/legacy_commands/protocol_commands.py +54 -0
- opentrons/legacy_commands/publisher.py +155 -0
- opentrons/legacy_commands/robot_commands.py +51 -0
- opentrons/legacy_commands/types.py +1115 -0
- opentrons/motion_planning/__init__.py +32 -0
- opentrons/motion_planning/adjacent_slots_getters.py +168 -0
- opentrons/motion_planning/deck_conflict.py +396 -0
- opentrons/motion_planning/errors.py +35 -0
- opentrons/motion_planning/types.py +42 -0
- opentrons/motion_planning/waypoints.py +218 -0
- opentrons/ordered_set.py +138 -0
- opentrons/protocol_api/__init__.py +105 -0
- opentrons/protocol_api/_liquid.py +157 -0
- opentrons/protocol_api/_liquid_properties.py +814 -0
- opentrons/protocol_api/_nozzle_layout.py +31 -0
- opentrons/protocol_api/_parameter_context.py +300 -0
- opentrons/protocol_api/_parameters.py +31 -0
- opentrons/protocol_api/_transfer_liquid_validation.py +108 -0
- opentrons/protocol_api/_types.py +43 -0
- opentrons/protocol_api/config.py +23 -0
- opentrons/protocol_api/core/__init__.py +23 -0
- opentrons/protocol_api/core/common.py +33 -0
- opentrons/protocol_api/core/core_map.py +74 -0
- opentrons/protocol_api/core/engine/__init__.py +22 -0
- opentrons/protocol_api/core/engine/_default_labware_versions.py +179 -0
- opentrons/protocol_api/core/engine/deck_conflict.py +348 -0
- opentrons/protocol_api/core/engine/exceptions.py +19 -0
- opentrons/protocol_api/core/engine/instrument.py +2391 -0
- opentrons/protocol_api/core/engine/labware.py +238 -0
- opentrons/protocol_api/core/engine/load_labware_params.py +73 -0
- opentrons/protocol_api/core/engine/module_core.py +1025 -0
- opentrons/protocol_api/core/engine/overlap_versions.py +20 -0
- opentrons/protocol_api/core/engine/pipette_movement_conflict.py +358 -0
- opentrons/protocol_api/core/engine/point_calculations.py +64 -0
- opentrons/protocol_api/core/engine/protocol.py +1153 -0
- opentrons/protocol_api/core/engine/robot.py +139 -0
- opentrons/protocol_api/core/engine/stringify.py +74 -0
- opentrons/protocol_api/core/engine/transfer_components_executor.py +990 -0
- opentrons/protocol_api/core/engine/well.py +241 -0
- opentrons/protocol_api/core/instrument.py +459 -0
- opentrons/protocol_api/core/labware.py +151 -0
- opentrons/protocol_api/core/legacy/__init__.py +11 -0
- opentrons/protocol_api/core/legacy/_labware_geometry.py +37 -0
- opentrons/protocol_api/core/legacy/deck.py +369 -0
- opentrons/protocol_api/core/legacy/labware_offset_provider.py +108 -0
- opentrons/protocol_api/core/legacy/legacy_instrument_core.py +709 -0
- opentrons/protocol_api/core/legacy/legacy_labware_core.py +235 -0
- opentrons/protocol_api/core/legacy/legacy_module_core.py +592 -0
- opentrons/protocol_api/core/legacy/legacy_protocol_core.py +612 -0
- opentrons/protocol_api/core/legacy/legacy_well_core.py +162 -0
- opentrons/protocol_api/core/legacy/load_info.py +67 -0
- opentrons/protocol_api/core/legacy/module_geometry.py +547 -0
- opentrons/protocol_api/core/legacy/well_geometry.py +148 -0
- opentrons/protocol_api/core/legacy_simulator/__init__.py +16 -0
- opentrons/protocol_api/core/legacy_simulator/legacy_instrument_core.py +624 -0
- opentrons/protocol_api/core/legacy_simulator/legacy_protocol_core.py +85 -0
- opentrons/protocol_api/core/module.py +484 -0
- opentrons/protocol_api/core/protocol.py +311 -0
- opentrons/protocol_api/core/robot.py +51 -0
- opentrons/protocol_api/core/well.py +116 -0
- opentrons/protocol_api/core/well_grid.py +45 -0
- opentrons/protocol_api/create_protocol_context.py +177 -0
- opentrons/protocol_api/deck.py +223 -0
- opentrons/protocol_api/disposal_locations.py +244 -0
- opentrons/protocol_api/instrument_context.py +3212 -0
- opentrons/protocol_api/labware.py +1579 -0
- opentrons/protocol_api/module_contexts.py +1425 -0
- opentrons/protocol_api/module_validation_and_errors.py +61 -0
- opentrons/protocol_api/protocol_context.py +1688 -0
- opentrons/protocol_api/robot_context.py +303 -0
- opentrons/protocol_api/validation.py +761 -0
- opentrons/protocol_engine/__init__.py +155 -0
- opentrons/protocol_engine/actions/__init__.py +65 -0
- opentrons/protocol_engine/actions/action_dispatcher.py +30 -0
- opentrons/protocol_engine/actions/action_handler.py +13 -0
- opentrons/protocol_engine/actions/actions.py +302 -0
- opentrons/protocol_engine/actions/get_state_update.py +38 -0
- opentrons/protocol_engine/clients/__init__.py +5 -0
- opentrons/protocol_engine/clients/sync_client.py +174 -0
- opentrons/protocol_engine/clients/transports.py +197 -0
- opentrons/protocol_engine/commands/__init__.py +757 -0
- opentrons/protocol_engine/commands/absorbance_reader/__init__.py +61 -0
- opentrons/protocol_engine/commands/absorbance_reader/close_lid.py +154 -0
- opentrons/protocol_engine/commands/absorbance_reader/common.py +6 -0
- opentrons/protocol_engine/commands/absorbance_reader/initialize.py +151 -0
- opentrons/protocol_engine/commands/absorbance_reader/open_lid.py +154 -0
- opentrons/protocol_engine/commands/absorbance_reader/read.py +226 -0
- opentrons/protocol_engine/commands/air_gap_in_place.py +162 -0
- opentrons/protocol_engine/commands/aspirate.py +244 -0
- opentrons/protocol_engine/commands/aspirate_in_place.py +184 -0
- opentrons/protocol_engine/commands/aspirate_while_tracking.py +211 -0
- opentrons/protocol_engine/commands/blow_out.py +146 -0
- opentrons/protocol_engine/commands/blow_out_in_place.py +119 -0
- opentrons/protocol_engine/commands/calibration/__init__.py +60 -0
- opentrons/protocol_engine/commands/calibration/calibrate_gripper.py +166 -0
- opentrons/protocol_engine/commands/calibration/calibrate_module.py +117 -0
- opentrons/protocol_engine/commands/calibration/calibrate_pipette.py +96 -0
- opentrons/protocol_engine/commands/calibration/move_to_maintenance_position.py +156 -0
- opentrons/protocol_engine/commands/command.py +308 -0
- opentrons/protocol_engine/commands/command_unions.py +974 -0
- opentrons/protocol_engine/commands/comment.py +57 -0
- opentrons/protocol_engine/commands/configure_for_volume.py +108 -0
- opentrons/protocol_engine/commands/configure_nozzle_layout.py +115 -0
- opentrons/protocol_engine/commands/custom.py +67 -0
- opentrons/protocol_engine/commands/dispense.py +194 -0
- opentrons/protocol_engine/commands/dispense_in_place.py +179 -0
- opentrons/protocol_engine/commands/dispense_while_tracking.py +204 -0
- opentrons/protocol_engine/commands/drop_tip.py +232 -0
- opentrons/protocol_engine/commands/drop_tip_in_place.py +205 -0
- opentrons/protocol_engine/commands/flex_stacker/__init__.py +64 -0
- opentrons/protocol_engine/commands/flex_stacker/common.py +900 -0
- opentrons/protocol_engine/commands/flex_stacker/empty.py +293 -0
- opentrons/protocol_engine/commands/flex_stacker/fill.py +281 -0
- opentrons/protocol_engine/commands/flex_stacker/retrieve.py +339 -0
- opentrons/protocol_engine/commands/flex_stacker/set_stored_labware.py +328 -0
- opentrons/protocol_engine/commands/flex_stacker/store.py +326 -0
- opentrons/protocol_engine/commands/generate_command_schema.py +61 -0
- opentrons/protocol_engine/commands/get_next_tip.py +134 -0
- opentrons/protocol_engine/commands/get_tip_presence.py +87 -0
- opentrons/protocol_engine/commands/hash_command_params.py +38 -0
- opentrons/protocol_engine/commands/heater_shaker/__init__.py +102 -0
- opentrons/protocol_engine/commands/heater_shaker/close_labware_latch.py +83 -0
- opentrons/protocol_engine/commands/heater_shaker/deactivate_heater.py +82 -0
- opentrons/protocol_engine/commands/heater_shaker/deactivate_shaker.py +84 -0
- opentrons/protocol_engine/commands/heater_shaker/open_labware_latch.py +110 -0
- opentrons/protocol_engine/commands/heater_shaker/set_and_wait_for_shake_speed.py +125 -0
- opentrons/protocol_engine/commands/heater_shaker/set_target_temperature.py +90 -0
- opentrons/protocol_engine/commands/heater_shaker/wait_for_temperature.py +102 -0
- opentrons/protocol_engine/commands/home.py +100 -0
- opentrons/protocol_engine/commands/identify_module.py +86 -0
- opentrons/protocol_engine/commands/labware_handling_common.py +29 -0
- opentrons/protocol_engine/commands/liquid_probe.py +464 -0
- opentrons/protocol_engine/commands/load_labware.py +210 -0
- opentrons/protocol_engine/commands/load_lid.py +154 -0
- opentrons/protocol_engine/commands/load_lid_stack.py +272 -0
- opentrons/protocol_engine/commands/load_liquid.py +95 -0
- opentrons/protocol_engine/commands/load_liquid_class.py +144 -0
- opentrons/protocol_engine/commands/load_module.py +223 -0
- opentrons/protocol_engine/commands/load_pipette.py +167 -0
- opentrons/protocol_engine/commands/magnetic_module/__init__.py +32 -0
- opentrons/protocol_engine/commands/magnetic_module/disengage.py +97 -0
- opentrons/protocol_engine/commands/magnetic_module/engage.py +119 -0
- opentrons/protocol_engine/commands/move_labware.py +546 -0
- opentrons/protocol_engine/commands/move_relative.py +102 -0
- opentrons/protocol_engine/commands/move_to_addressable_area.py +176 -0
- opentrons/protocol_engine/commands/move_to_addressable_area_for_drop_tip.py +198 -0
- opentrons/protocol_engine/commands/move_to_coordinates.py +107 -0
- opentrons/protocol_engine/commands/move_to_well.py +119 -0
- opentrons/protocol_engine/commands/movement_common.py +338 -0
- opentrons/protocol_engine/commands/pick_up_tip.py +241 -0
- opentrons/protocol_engine/commands/pipetting_common.py +443 -0
- opentrons/protocol_engine/commands/prepare_to_aspirate.py +121 -0
- opentrons/protocol_engine/commands/pressure_dispense.py +155 -0
- opentrons/protocol_engine/commands/reload_labware.py +90 -0
- opentrons/protocol_engine/commands/retract_axis.py +75 -0
- opentrons/protocol_engine/commands/robot/__init__.py +70 -0
- opentrons/protocol_engine/commands/robot/close_gripper_jaw.py +96 -0
- opentrons/protocol_engine/commands/robot/common.py +18 -0
- opentrons/protocol_engine/commands/robot/move_axes_relative.py +101 -0
- opentrons/protocol_engine/commands/robot/move_axes_to.py +100 -0
- opentrons/protocol_engine/commands/robot/move_to.py +94 -0
- opentrons/protocol_engine/commands/robot/open_gripper_jaw.py +86 -0
- opentrons/protocol_engine/commands/save_position.py +109 -0
- opentrons/protocol_engine/commands/seal_pipette_to_tip.py +353 -0
- opentrons/protocol_engine/commands/set_rail_lights.py +67 -0
- opentrons/protocol_engine/commands/set_status_bar.py +89 -0
- opentrons/protocol_engine/commands/temperature_module/__init__.py +46 -0
- opentrons/protocol_engine/commands/temperature_module/deactivate.py +86 -0
- opentrons/protocol_engine/commands/temperature_module/set_target_temperature.py +97 -0
- opentrons/protocol_engine/commands/temperature_module/wait_for_temperature.py +104 -0
- opentrons/protocol_engine/commands/thermocycler/__init__.py +152 -0
- opentrons/protocol_engine/commands/thermocycler/close_lid.py +87 -0
- opentrons/protocol_engine/commands/thermocycler/deactivate_block.py +80 -0
- opentrons/protocol_engine/commands/thermocycler/deactivate_lid.py +80 -0
- opentrons/protocol_engine/commands/thermocycler/open_lid.py +87 -0
- opentrons/protocol_engine/commands/thermocycler/run_extended_profile.py +171 -0
- opentrons/protocol_engine/commands/thermocycler/run_profile.py +124 -0
- opentrons/protocol_engine/commands/thermocycler/set_target_block_temperature.py +140 -0
- opentrons/protocol_engine/commands/thermocycler/set_target_lid_temperature.py +100 -0
- opentrons/protocol_engine/commands/thermocycler/wait_for_block_temperature.py +93 -0
- opentrons/protocol_engine/commands/thermocycler/wait_for_lid_temperature.py +89 -0
- opentrons/protocol_engine/commands/touch_tip.py +189 -0
- opentrons/protocol_engine/commands/unsafe/__init__.py +161 -0
- opentrons/protocol_engine/commands/unsafe/unsafe_blow_out_in_place.py +100 -0
- opentrons/protocol_engine/commands/unsafe/unsafe_drop_tip_in_place.py +121 -0
- opentrons/protocol_engine/commands/unsafe/unsafe_engage_axes.py +82 -0
- opentrons/protocol_engine/commands/unsafe/unsafe_place_labware.py +208 -0
- opentrons/protocol_engine/commands/unsafe/unsafe_stacker_close_latch.py +94 -0
- opentrons/protocol_engine/commands/unsafe/unsafe_stacker_manual_retrieve.py +295 -0
- opentrons/protocol_engine/commands/unsafe/unsafe_stacker_open_latch.py +91 -0
- opentrons/protocol_engine/commands/unsafe/unsafe_stacker_prepare_shuttle.py +136 -0
- opentrons/protocol_engine/commands/unsafe/unsafe_ungrip_labware.py +77 -0
- opentrons/protocol_engine/commands/unsafe/update_position_estimators.py +90 -0
- opentrons/protocol_engine/commands/unseal_pipette_from_tip.py +153 -0
- opentrons/protocol_engine/commands/verify_tip_presence.py +100 -0
- opentrons/protocol_engine/commands/wait_for_duration.py +76 -0
- opentrons/protocol_engine/commands/wait_for_resume.py +75 -0
- opentrons/protocol_engine/create_protocol_engine.py +193 -0
- opentrons/protocol_engine/engine_support.py +28 -0
- opentrons/protocol_engine/error_recovery_policy.py +81 -0
- opentrons/protocol_engine/errors/__init__.py +191 -0
- opentrons/protocol_engine/errors/error_occurrence.py +182 -0
- opentrons/protocol_engine/errors/exceptions.py +1308 -0
- opentrons/protocol_engine/execution/__init__.py +50 -0
- opentrons/protocol_engine/execution/command_executor.py +216 -0
- opentrons/protocol_engine/execution/create_queue_worker.py +102 -0
- opentrons/protocol_engine/execution/door_watcher.py +119 -0
- opentrons/protocol_engine/execution/equipment.py +819 -0
- opentrons/protocol_engine/execution/error_recovery_hardware_state_synchronizer.py +101 -0
- opentrons/protocol_engine/execution/gantry_mover.py +686 -0
- opentrons/protocol_engine/execution/hardware_stopper.py +147 -0
- opentrons/protocol_engine/execution/heater_shaker_movement_flagger.py +207 -0
- opentrons/protocol_engine/execution/labware_movement.py +297 -0
- opentrons/protocol_engine/execution/movement.py +349 -0
- opentrons/protocol_engine/execution/pipetting.py +607 -0
- opentrons/protocol_engine/execution/queue_worker.py +86 -0
- opentrons/protocol_engine/execution/rail_lights.py +25 -0
- opentrons/protocol_engine/execution/run_control.py +33 -0
- opentrons/protocol_engine/execution/status_bar.py +34 -0
- opentrons/protocol_engine/execution/thermocycler_movement_flagger.py +188 -0
- opentrons/protocol_engine/execution/thermocycler_plate_lifter.py +81 -0
- opentrons/protocol_engine/execution/tip_handler.py +550 -0
- opentrons/protocol_engine/labware_offset_standardization.py +194 -0
- opentrons/protocol_engine/notes/__init__.py +17 -0
- opentrons/protocol_engine/notes/notes.py +59 -0
- opentrons/protocol_engine/plugins.py +104 -0
- opentrons/protocol_engine/protocol_engine.py +683 -0
- opentrons/protocol_engine/resources/__init__.py +26 -0
- opentrons/protocol_engine/resources/deck_configuration_provider.py +232 -0
- opentrons/protocol_engine/resources/deck_data_provider.py +94 -0
- opentrons/protocol_engine/resources/file_provider.py +161 -0
- opentrons/protocol_engine/resources/fixture_validation.py +58 -0
- opentrons/protocol_engine/resources/labware_data_provider.py +106 -0
- opentrons/protocol_engine/resources/labware_validation.py +73 -0
- opentrons/protocol_engine/resources/model_utils.py +32 -0
- opentrons/protocol_engine/resources/module_data_provider.py +44 -0
- opentrons/protocol_engine/resources/ot3_validation.py +21 -0
- opentrons/protocol_engine/resources/pipette_data_provider.py +379 -0
- opentrons/protocol_engine/slot_standardization.py +128 -0
- opentrons/protocol_engine/state/__init__.py +1 -0
- opentrons/protocol_engine/state/_abstract_store.py +27 -0
- opentrons/protocol_engine/state/_axis_aligned_bounding_box.py +50 -0
- opentrons/protocol_engine/state/_labware_origin_math.py +636 -0
- opentrons/protocol_engine/state/_move_types.py +83 -0
- opentrons/protocol_engine/state/_well_math.py +193 -0
- opentrons/protocol_engine/state/addressable_areas.py +699 -0
- opentrons/protocol_engine/state/command_history.py +309 -0
- opentrons/protocol_engine/state/commands.py +1158 -0
- opentrons/protocol_engine/state/config.py +39 -0
- opentrons/protocol_engine/state/files.py +57 -0
- opentrons/protocol_engine/state/fluid_stack.py +138 -0
- opentrons/protocol_engine/state/geometry.py +2359 -0
- opentrons/protocol_engine/state/inner_well_math_utils.py +548 -0
- opentrons/protocol_engine/state/labware.py +1459 -0
- opentrons/protocol_engine/state/liquid_classes.py +82 -0
- opentrons/protocol_engine/state/liquids.py +73 -0
- opentrons/protocol_engine/state/module_substates/__init__.py +45 -0
- opentrons/protocol_engine/state/module_substates/absorbance_reader_substate.py +35 -0
- opentrons/protocol_engine/state/module_substates/flex_stacker_substate.py +112 -0
- opentrons/protocol_engine/state/module_substates/heater_shaker_module_substate.py +115 -0
- opentrons/protocol_engine/state/module_substates/magnetic_block_substate.py +17 -0
- opentrons/protocol_engine/state/module_substates/magnetic_module_substate.py +65 -0
- opentrons/protocol_engine/state/module_substates/temperature_module_substate.py +67 -0
- opentrons/protocol_engine/state/module_substates/thermocycler_module_substate.py +163 -0
- opentrons/protocol_engine/state/modules.py +1500 -0
- opentrons/protocol_engine/state/motion.py +373 -0
- opentrons/protocol_engine/state/pipettes.py +905 -0
- opentrons/protocol_engine/state/state.py +421 -0
- opentrons/protocol_engine/state/state_summary.py +36 -0
- opentrons/protocol_engine/state/tips.py +420 -0
- opentrons/protocol_engine/state/update_types.py +904 -0
- opentrons/protocol_engine/state/wells.py +290 -0
- opentrons/protocol_engine/types/__init__.py +308 -0
- opentrons/protocol_engine/types/automatic_tip_selection.py +39 -0
- opentrons/protocol_engine/types/command_annotations.py +53 -0
- opentrons/protocol_engine/types/deck_configuration.py +81 -0
- opentrons/protocol_engine/types/execution.py +96 -0
- opentrons/protocol_engine/types/hardware_passthrough.py +25 -0
- opentrons/protocol_engine/types/instrument.py +47 -0
- opentrons/protocol_engine/types/instrument_sensors.py +47 -0
- opentrons/protocol_engine/types/labware.py +131 -0
- opentrons/protocol_engine/types/labware_movement.py +22 -0
- opentrons/protocol_engine/types/labware_offset_location.py +111 -0
- opentrons/protocol_engine/types/labware_offset_vector.py +16 -0
- opentrons/protocol_engine/types/liquid.py +40 -0
- opentrons/protocol_engine/types/liquid_class.py +59 -0
- opentrons/protocol_engine/types/liquid_handling.py +13 -0
- opentrons/protocol_engine/types/liquid_level_detection.py +191 -0
- opentrons/protocol_engine/types/location.py +194 -0
- opentrons/protocol_engine/types/module.py +303 -0
- opentrons/protocol_engine/types/partial_tip_configuration.py +76 -0
- opentrons/protocol_engine/types/run_time_parameters.py +133 -0
- opentrons/protocol_engine/types/tip.py +18 -0
- opentrons/protocol_engine/types/util.py +21 -0
- opentrons/protocol_engine/types/well_position.py +124 -0
- opentrons/protocol_reader/__init__.py +37 -0
- opentrons/protocol_reader/extract_labware_definitions.py +66 -0
- opentrons/protocol_reader/file_format_validator.py +152 -0
- opentrons/protocol_reader/file_hasher.py +27 -0
- opentrons/protocol_reader/file_identifier.py +284 -0
- opentrons/protocol_reader/file_reader_writer.py +90 -0
- opentrons/protocol_reader/input_file.py +16 -0
- opentrons/protocol_reader/protocol_files_invalid_error.py +6 -0
- opentrons/protocol_reader/protocol_reader.py +188 -0
- opentrons/protocol_reader/protocol_source.py +124 -0
- opentrons/protocol_reader/role_analyzer.py +86 -0
- opentrons/protocol_runner/__init__.py +26 -0
- opentrons/protocol_runner/create_simulating_orchestrator.py +118 -0
- opentrons/protocol_runner/json_file_reader.py +55 -0
- opentrons/protocol_runner/json_translator.py +314 -0
- opentrons/protocol_runner/legacy_command_mapper.py +848 -0
- opentrons/protocol_runner/legacy_context_plugin.py +116 -0
- opentrons/protocol_runner/protocol_runner.py +530 -0
- opentrons/protocol_runner/python_protocol_wrappers.py +179 -0
- opentrons/protocol_runner/run_orchestrator.py +496 -0
- opentrons/protocol_runner/task_queue.py +95 -0
- opentrons/protocols/__init__.py +6 -0
- opentrons/protocols/advanced_control/__init__.py +0 -0
- opentrons/protocols/advanced_control/common.py +38 -0
- opentrons/protocols/advanced_control/mix.py +60 -0
- opentrons/protocols/advanced_control/transfers/__init__.py +0 -0
- opentrons/protocols/advanced_control/transfers/common.py +180 -0
- opentrons/protocols/advanced_control/transfers/transfer.py +972 -0
- opentrons/protocols/advanced_control/transfers/transfer_liquid_utils.py +231 -0
- opentrons/protocols/api_support/__init__.py +0 -0
- opentrons/protocols/api_support/constants.py +8 -0
- opentrons/protocols/api_support/deck_type.py +110 -0
- opentrons/protocols/api_support/definitions.py +18 -0
- opentrons/protocols/api_support/instrument.py +151 -0
- opentrons/protocols/api_support/labware_like.py +233 -0
- opentrons/protocols/api_support/tip_tracker.py +175 -0
- opentrons/protocols/api_support/types.py +32 -0
- opentrons/protocols/api_support/util.py +403 -0
- opentrons/protocols/bundle.py +89 -0
- opentrons/protocols/duration/__init__.py +4 -0
- opentrons/protocols/duration/errors.py +5 -0
- opentrons/protocols/duration/estimator.py +628 -0
- opentrons/protocols/execution/__init__.py +0 -0
- opentrons/protocols/execution/dev_types.py +181 -0
- opentrons/protocols/execution/errors.py +40 -0
- opentrons/protocols/execution/execute.py +84 -0
- opentrons/protocols/execution/execute_json_v3.py +275 -0
- opentrons/protocols/execution/execute_json_v4.py +359 -0
- opentrons/protocols/execution/execute_json_v5.py +28 -0
- opentrons/protocols/execution/execute_python.py +169 -0
- opentrons/protocols/execution/json_dispatchers.py +87 -0
- opentrons/protocols/execution/types.py +7 -0
- opentrons/protocols/geometry/__init__.py +0 -0
- opentrons/protocols/geometry/planning.py +297 -0
- opentrons/protocols/labware.py +312 -0
- opentrons/protocols/models/__init__.py +0 -0
- opentrons/protocols/models/json_protocol.py +679 -0
- opentrons/protocols/parameters/__init__.py +0 -0
- opentrons/protocols/parameters/csv_parameter_definition.py +77 -0
- opentrons/protocols/parameters/csv_parameter_interface.py +96 -0
- opentrons/protocols/parameters/exceptions.py +34 -0
- opentrons/protocols/parameters/parameter_definition.py +272 -0
- opentrons/protocols/parameters/types.py +17 -0
- opentrons/protocols/parameters/validation.py +267 -0
- opentrons/protocols/parse.py +671 -0
- opentrons/protocols/types.py +159 -0
- opentrons/py.typed +0 -0
- opentrons/resources/scripts/lpc21isp +0 -0
- opentrons/resources/smoothie-edge-8414642.hex +23010 -0
- opentrons/simulate.py +1065 -0
- opentrons/system/__init__.py +6 -0
- opentrons/system/camera.py +51 -0
- opentrons/system/log_control.py +59 -0
- opentrons/system/nmcli.py +856 -0
- opentrons/system/resin.py +24 -0
- opentrons/system/smoothie_update.py +15 -0
- opentrons/system/wifi.py +204 -0
- opentrons/tools/__init__.py +0 -0
- opentrons/tools/args_handler.py +22 -0
- opentrons/tools/write_pipette_memory.py +157 -0
- opentrons/types.py +618 -0
- opentrons/util/__init__.py +1 -0
- opentrons/util/async_helpers.py +166 -0
- opentrons/util/broker.py +84 -0
- opentrons/util/change_notifier.py +47 -0
- opentrons/util/entrypoint_util.py +278 -0
- opentrons/util/get_union_elements.py +26 -0
- opentrons/util/helpers.py +6 -0
- opentrons/util/linal.py +178 -0
- opentrons/util/logging_config.py +265 -0
- opentrons/util/logging_queue_handler.py +61 -0
- opentrons/util/performance_helpers.py +157 -0
- opentrons-8.6.0a1.dist-info/METADATA +37 -0
- opentrons-8.6.0a1.dist-info/RECORD +600 -0
- opentrons-8.6.0a1.dist-info/WHEEL +4 -0
- opentrons-8.6.0a1.dist-info/entry_points.txt +3 -0
- opentrons-8.6.0a1.dist-info/licenses/LICENSE +202 -0
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
from typing import List
|
|
2
|
+
|
|
3
|
+
from typing_extensions import Literal
|
|
4
|
+
|
|
5
|
+
from pydantic import BaseModel, Field
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class ModuleConnection(BaseModel):
|
|
9
|
+
"""Model a single module connection."""
|
|
10
|
+
|
|
11
|
+
url: str = Field(
|
|
12
|
+
...,
|
|
13
|
+
description="The url (port) value the module driver should connect to. "
|
|
14
|
+
"For example: socket://host:port",
|
|
15
|
+
)
|
|
16
|
+
module_type: str = Field(
|
|
17
|
+
..., description="What kind of module this connection emulates."
|
|
18
|
+
)
|
|
19
|
+
identifier: str = Field(..., description="Unique id for this emulator.")
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class Message(BaseModel):
|
|
23
|
+
"""A message sent to module server clients."""
|
|
24
|
+
|
|
25
|
+
status: Literal["connected", "disconnected", "dump"] = Field(
|
|
26
|
+
...,
|
|
27
|
+
description="`dump` includes a complete list of connected emulators. "
|
|
28
|
+
"`connected` for new connections. `disconnected` for emulators "
|
|
29
|
+
"that have disconnected. ",
|
|
30
|
+
)
|
|
31
|
+
connections: List[ModuleConnection]
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
"""Server notifying of module connections."""
|
|
2
|
+
import asyncio
|
|
3
|
+
import logging
|
|
4
|
+
from typing import Dict, Set
|
|
5
|
+
|
|
6
|
+
from opentrons.hardware_control.emulation.module_server.models import (
|
|
7
|
+
ModuleConnection,
|
|
8
|
+
Message,
|
|
9
|
+
)
|
|
10
|
+
from opentrons.hardware_control.emulation.proxy import ProxyListener
|
|
11
|
+
from opentrons.hardware_control.emulation.settings import ModuleServerSettings
|
|
12
|
+
from typing_extensions import Final
|
|
13
|
+
|
|
14
|
+
log = logging.getLogger(__name__)
|
|
15
|
+
|
|
16
|
+
MessageDelimiter: Final = b"\n"
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class ModuleStatusServer(ProxyListener):
|
|
20
|
+
"""The module status server is the emulator equivalent of inotify. A client
|
|
21
|
+
can know when an emulated module connects or disconnects.
|
|
22
|
+
|
|
23
|
+
Clients connect and read JSON messages (See models module).
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
def __init__(self, settings: ModuleServerSettings) -> None:
|
|
27
|
+
"""Constructor
|
|
28
|
+
|
|
29
|
+
Args:
|
|
30
|
+
settings: app settings
|
|
31
|
+
"""
|
|
32
|
+
self._settings = settings
|
|
33
|
+
self._connections: Dict[str, ModuleConnection] = {}
|
|
34
|
+
self._clients: Set[asyncio.StreamWriter] = set()
|
|
35
|
+
|
|
36
|
+
def on_server_connected(
|
|
37
|
+
self, server_type: str, client_uri: str, identifier: str
|
|
38
|
+
) -> None:
|
|
39
|
+
"""Called when a new module has connected.
|
|
40
|
+
|
|
41
|
+
Args:
|
|
42
|
+
server_type: the type of module
|
|
43
|
+
client_uri: the url string for a driver to connect to
|
|
44
|
+
identifier: unique id for connection
|
|
45
|
+
|
|
46
|
+
Returns: None
|
|
47
|
+
|
|
48
|
+
"""
|
|
49
|
+
log.info(f"On connected {server_type} {client_uri} {identifier}")
|
|
50
|
+
connection = ModuleConnection(
|
|
51
|
+
module_type=server_type, url=client_uri, identifier=identifier
|
|
52
|
+
)
|
|
53
|
+
self._connections[identifier] = connection
|
|
54
|
+
for c in self._clients:
|
|
55
|
+
c.write(
|
|
56
|
+
Message(status="connected", connections=[connection])
|
|
57
|
+
.model_dump_json()
|
|
58
|
+
.encode()
|
|
59
|
+
)
|
|
60
|
+
c.write(b"\n")
|
|
61
|
+
|
|
62
|
+
def on_server_disconnected(self, identifier: str) -> None:
|
|
63
|
+
"""Called when a module has disconnected.
|
|
64
|
+
|
|
65
|
+
Args:
|
|
66
|
+
identifier: unique id for the connection
|
|
67
|
+
|
|
68
|
+
Returns: None
|
|
69
|
+
"""
|
|
70
|
+
log.info(f"On disconnected {identifier}")
|
|
71
|
+
try:
|
|
72
|
+
connection = self._connections[identifier]
|
|
73
|
+
del self._connections[identifier]
|
|
74
|
+
for c in self._clients:
|
|
75
|
+
c.write(
|
|
76
|
+
Message(status="disconnected", connections=[connection])
|
|
77
|
+
.model_dump_json()
|
|
78
|
+
.encode()
|
|
79
|
+
)
|
|
80
|
+
c.write(MessageDelimiter)
|
|
81
|
+
except KeyError:
|
|
82
|
+
log.exception("Failed to find identifier")
|
|
83
|
+
|
|
84
|
+
async def run(self) -> None:
|
|
85
|
+
"""Run the server."""
|
|
86
|
+
server = await asyncio.start_server(
|
|
87
|
+
self._handle_connection, host=self._settings.host, port=self._settings.port
|
|
88
|
+
)
|
|
89
|
+
await server.serve_forever()
|
|
90
|
+
|
|
91
|
+
async def _handle_connection(
|
|
92
|
+
self, reader: asyncio.StreamReader, writer: asyncio.StreamWriter
|
|
93
|
+
) -> None:
|
|
94
|
+
"""Handle a client connection to the server."""
|
|
95
|
+
log.info("Client connected to module server.")
|
|
96
|
+
|
|
97
|
+
# A client connected. Send a dump of all connected modules.
|
|
98
|
+
m = Message(status="dump", connections=list(self._connections.values()))
|
|
99
|
+
|
|
100
|
+
writer.write(m.model_dump_json().encode())
|
|
101
|
+
writer.write(MessageDelimiter)
|
|
102
|
+
|
|
103
|
+
self._clients.add(writer)
|
|
104
|
+
|
|
105
|
+
while True:
|
|
106
|
+
if b"" == await reader.read():
|
|
107
|
+
self._clients.remove(writer)
|
|
108
|
+
break
|
|
109
|
+
|
|
110
|
+
log.info("Client disconnected from module server.")
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import re
|
|
2
|
+
from dataclasses import dataclass
|
|
3
|
+
from typing import Dict, Generator, Optional
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
@dataclass
|
|
7
|
+
class Command:
|
|
8
|
+
gcode: str
|
|
9
|
+
body: str
|
|
10
|
+
params: Dict[str, Optional[float]]
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class Parser:
|
|
14
|
+
"""Gcode line parser."""
|
|
15
|
+
|
|
16
|
+
# TODO (al, 2021-05-11): Should G01 and G1 be treated differently? Currently
|
|
17
|
+
# they are two different Gcodes.
|
|
18
|
+
GCODE_RE = re.compile(r"(?:(?:[MG]\d+\.?\d*)|dfu|version)")
|
|
19
|
+
"""A gcode is either M or G followed by decimal. Or 'dfu' or 'version'."""
|
|
20
|
+
ALPHA_PREFIXED_NUMBER_RE = re.compile(r"(?P<prefix>[A-Z])(?P<number>-?\d*\.?\d*)")
|
|
21
|
+
"""All parameters are a capital letter followed by a decimal value."""
|
|
22
|
+
|
|
23
|
+
def parse(self, line: str) -> Generator[Command, None, None]:
|
|
24
|
+
"""
|
|
25
|
+
Parse a line to extract commands.
|
|
26
|
+
|
|
27
|
+
Args:
|
|
28
|
+
line: a line containing gcodes and their values. spaces are optional.
|
|
29
|
+
|
|
30
|
+
Returns:
|
|
31
|
+
Command object
|
|
32
|
+
"""
|
|
33
|
+
line = line.strip()
|
|
34
|
+
previous = None
|
|
35
|
+
for i in self.GCODE_RE.finditer(line):
|
|
36
|
+
if previous:
|
|
37
|
+
yield self._create_command(
|
|
38
|
+
line[previous.start() : previous.end()],
|
|
39
|
+
line[previous.end() : i.start()],
|
|
40
|
+
)
|
|
41
|
+
else:
|
|
42
|
+
# This is the first match. It better be at the beginning or
|
|
43
|
+
# there's junk in the beginning.
|
|
44
|
+
if i.start() != 0:
|
|
45
|
+
raise ValueError(f"Invalid content: {line}")
|
|
46
|
+
previous = i
|
|
47
|
+
if previous:
|
|
48
|
+
# Create command from final GCODE and remainder of the line.
|
|
49
|
+
yield self._create_command(
|
|
50
|
+
line[previous.start() : previous.end()], line[previous.end() :]
|
|
51
|
+
)
|
|
52
|
+
elif line:
|
|
53
|
+
# There are no GCODEs and it's a non-empty line.
|
|
54
|
+
raise ValueError(f"Invalid content: {line}")
|
|
55
|
+
|
|
56
|
+
@staticmethod
|
|
57
|
+
def _create_command(gcode: str, body: str) -> Command:
|
|
58
|
+
"""
|
|
59
|
+
Create a Command.
|
|
60
|
+
|
|
61
|
+
Args:
|
|
62
|
+
gcode: the gcode
|
|
63
|
+
body: the parameter string
|
|
64
|
+
|
|
65
|
+
Returns: a Command object
|
|
66
|
+
"""
|
|
67
|
+
pars = (i.groupdict() for i in Parser.ALPHA_PREFIXED_NUMBER_RE.finditer(body))
|
|
68
|
+
return Command(
|
|
69
|
+
gcode=gcode,
|
|
70
|
+
body=body.strip(),
|
|
71
|
+
params={
|
|
72
|
+
p["prefix"]: float(p["number"]) if p["number"] else None for p in pars
|
|
73
|
+
},
|
|
74
|
+
)
|
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
"""The Proxy class module."""
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
import asyncio
|
|
4
|
+
import logging
|
|
5
|
+
import uuid
|
|
6
|
+
import socket
|
|
7
|
+
from abc import ABC, abstractmethod
|
|
8
|
+
from dataclasses import dataclass
|
|
9
|
+
from typing import List
|
|
10
|
+
|
|
11
|
+
from opentrons.hardware_control.emulation.settings import ProxySettings
|
|
12
|
+
|
|
13
|
+
log = logging.getLogger(__name__)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@dataclass(frozen=True)
|
|
17
|
+
class Connection:
|
|
18
|
+
"""Attributes of a client connected on the server port (module emulator)."""
|
|
19
|
+
|
|
20
|
+
identifier: str
|
|
21
|
+
reader: asyncio.StreamReader
|
|
22
|
+
writer: asyncio.StreamWriter
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class ProxyListener(ABC):
|
|
26
|
+
"""Interface defining an object needing to know when a server (module emulator)
|
|
27
|
+
connected/disconnected."""
|
|
28
|
+
|
|
29
|
+
@abstractmethod
|
|
30
|
+
def on_server_connected(
|
|
31
|
+
self, server_type: str, client_uri: str, identifier: str
|
|
32
|
+
) -> None:
|
|
33
|
+
"""Called when a new server connects."""
|
|
34
|
+
...
|
|
35
|
+
|
|
36
|
+
@abstractmethod
|
|
37
|
+
def on_server_disconnected(self, identifier: str) -> None:
|
|
38
|
+
"""Called when a server disconnects."""
|
|
39
|
+
...
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
class Proxy:
|
|
43
|
+
"""A class that has servers (emulators) connect on one port and clients
|
|
44
|
+
(drivers) on another. A server connection will be added to a collection. A
|
|
45
|
+
client connection will check for a server connection and if available will
|
|
46
|
+
have its write stream attached to the servers read stream and vice versa."""
|
|
47
|
+
|
|
48
|
+
def __init__(
|
|
49
|
+
self, name: str, listener: ProxyListener, settings: ProxySettings
|
|
50
|
+
) -> None:
|
|
51
|
+
"""Constructor.
|
|
52
|
+
|
|
53
|
+
Args:
|
|
54
|
+
name: Proxy name.
|
|
55
|
+
listener: Connection even listener.
|
|
56
|
+
settings: The proxy settings.
|
|
57
|
+
"""
|
|
58
|
+
self._name = name
|
|
59
|
+
self._settings = settings
|
|
60
|
+
self._event_listener = listener
|
|
61
|
+
self._cons: List[Connection] = []
|
|
62
|
+
|
|
63
|
+
@property
|
|
64
|
+
def name(self) -> str:
|
|
65
|
+
"""Return the name of the proxy."""
|
|
66
|
+
return self._name
|
|
67
|
+
|
|
68
|
+
async def run(self) -> None:
|
|
69
|
+
"""Run the server."""
|
|
70
|
+
await asyncio.gather(
|
|
71
|
+
self._listen_server_connections(),
|
|
72
|
+
self._listen_client_connections(),
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
async def _listen_server_connections(self) -> None:
|
|
76
|
+
"""Run the server listener."""
|
|
77
|
+
log.info(
|
|
78
|
+
f"starting {self._name} server connection server at "
|
|
79
|
+
f"{self._settings.host}:{self._settings.emulator_port}"
|
|
80
|
+
)
|
|
81
|
+
server = await asyncio.start_server(
|
|
82
|
+
self._handle_server_connection,
|
|
83
|
+
self._settings.host,
|
|
84
|
+
self._settings.emulator_port,
|
|
85
|
+
)
|
|
86
|
+
await server.serve_forever()
|
|
87
|
+
|
|
88
|
+
async def _listen_client_connections(self) -> None:
|
|
89
|
+
"""Run the client listener."""
|
|
90
|
+
log.info(
|
|
91
|
+
f"starting {self._name} client connection server at "
|
|
92
|
+
f"{self._settings.host}:{self._settings.driver_port}"
|
|
93
|
+
)
|
|
94
|
+
server = await asyncio.start_server(
|
|
95
|
+
self._handle_client_connection,
|
|
96
|
+
self._settings.host,
|
|
97
|
+
self._settings.driver_port,
|
|
98
|
+
)
|
|
99
|
+
await server.serve_forever()
|
|
100
|
+
|
|
101
|
+
async def _handle_server_connection(
|
|
102
|
+
self, reader: asyncio.StreamReader, writer: asyncio.StreamWriter
|
|
103
|
+
) -> None:
|
|
104
|
+
"""Handle a server connection.
|
|
105
|
+
|
|
106
|
+
A new connection will be added to the our connection collection.
|
|
107
|
+
|
|
108
|
+
Args:
|
|
109
|
+
reader: Reader
|
|
110
|
+
writer: Writer
|
|
111
|
+
|
|
112
|
+
Returns:
|
|
113
|
+
None
|
|
114
|
+
"""
|
|
115
|
+
log.info(f"{self._name} emulator connected.")
|
|
116
|
+
connection = Connection(
|
|
117
|
+
identifier=str(uuid.uuid1()), reader=reader, writer=writer
|
|
118
|
+
)
|
|
119
|
+
|
|
120
|
+
log.info(f"Using Local Host: {self._settings.use_local_host}")
|
|
121
|
+
|
|
122
|
+
client_host = (
|
|
123
|
+
"127.0.0.1" if self._settings.use_local_host else socket.gethostname()
|
|
124
|
+
)
|
|
125
|
+
|
|
126
|
+
self._cons.append(connection)
|
|
127
|
+
self._event_listener.on_server_connected(
|
|
128
|
+
server_type=self._name,
|
|
129
|
+
client_uri=f"socket://{client_host}:{self._settings.driver_port}",
|
|
130
|
+
identifier=connection.identifier,
|
|
131
|
+
)
|
|
132
|
+
|
|
133
|
+
async def _handle_client_connection(
|
|
134
|
+
self, reader: asyncio.StreamReader, writer: asyncio.StreamWriter
|
|
135
|
+
) -> None:
|
|
136
|
+
"""Handle a client connection.
|
|
137
|
+
|
|
138
|
+
Attempt to match the client steam with an available server stream.
|
|
139
|
+
|
|
140
|
+
Args:
|
|
141
|
+
reader: Reader
|
|
142
|
+
writer: Writer
|
|
143
|
+
|
|
144
|
+
Returns:
|
|
145
|
+
None
|
|
146
|
+
"""
|
|
147
|
+
try:
|
|
148
|
+
while True:
|
|
149
|
+
# Pop an emulator connection.
|
|
150
|
+
connection = self._cons.pop(0)
|
|
151
|
+
if not connection.reader.at_eof():
|
|
152
|
+
break
|
|
153
|
+
else:
|
|
154
|
+
log.info(f"{self._name} server connection terminated")
|
|
155
|
+
self._event_listener.on_server_disconnected(connection.identifier)
|
|
156
|
+
except IndexError:
|
|
157
|
+
log.info(f"{self._name} no emulator connected.")
|
|
158
|
+
writer.close()
|
|
159
|
+
return
|
|
160
|
+
|
|
161
|
+
log.info(
|
|
162
|
+
f"{self._name} "
|
|
163
|
+
f"client at {writer.transport.get_extra_info('socket')}"
|
|
164
|
+
f" connected to {connection.writer.transport.get_extra_info('socket')}."
|
|
165
|
+
)
|
|
166
|
+
|
|
167
|
+
await self._handle_proxy(
|
|
168
|
+
driver=Connection(
|
|
169
|
+
reader=reader, writer=writer, identifier=connection.identifier
|
|
170
|
+
),
|
|
171
|
+
server=connection,
|
|
172
|
+
)
|
|
173
|
+
|
|
174
|
+
# Return the emulator connection to the pool.
|
|
175
|
+
if not connection.reader.at_eof():
|
|
176
|
+
log.info(f"{self._name} returning connection to pool")
|
|
177
|
+
self._cons.append(connection)
|
|
178
|
+
else:
|
|
179
|
+
log.info(f"{self._name} server connection terminated")
|
|
180
|
+
self._event_listener.on_server_disconnected(connection.identifier)
|
|
181
|
+
|
|
182
|
+
async def _handle_proxy(self, driver: Connection, server: Connection) -> None:
|
|
183
|
+
"""Connect the driver to the emulator.
|
|
184
|
+
|
|
185
|
+
Args:
|
|
186
|
+
driver: Driver connection
|
|
187
|
+
server: Emulator connection
|
|
188
|
+
|
|
189
|
+
Returns:
|
|
190
|
+
None
|
|
191
|
+
"""
|
|
192
|
+
loop = asyncio.get_event_loop()
|
|
193
|
+
read_from_client_task = loop.create_task(
|
|
194
|
+
self._data_router(driver, server, False)
|
|
195
|
+
)
|
|
196
|
+
read_from_server_task = loop.create_task(
|
|
197
|
+
self._data_router(server, driver, True)
|
|
198
|
+
)
|
|
199
|
+
await read_from_client_task
|
|
200
|
+
read_from_server_task.cancel()
|
|
201
|
+
try:
|
|
202
|
+
await read_from_server_task
|
|
203
|
+
except asyncio.CancelledError:
|
|
204
|
+
log.exception("Server task cancelled")
|
|
205
|
+
pass
|
|
206
|
+
|
|
207
|
+
@staticmethod
|
|
208
|
+
async def _data_router(
|
|
209
|
+
in_connection: Connection,
|
|
210
|
+
out_connection: Connection,
|
|
211
|
+
close_other_on_disconnect: bool,
|
|
212
|
+
) -> None:
|
|
213
|
+
"""Route date from in to out.
|
|
214
|
+
|
|
215
|
+
Args:
|
|
216
|
+
in_connection: connection to read from.
|
|
217
|
+
out_connection: connection to write to
|
|
218
|
+
close_other_on_disconnect: whether the other connection should
|
|
219
|
+
be closed if the in_connection is closed.
|
|
220
|
+
A driver disconnect should close connection with emulator, while
|
|
221
|
+
an emulator disconnect should close the attached driver.
|
|
222
|
+
|
|
223
|
+
Returns:
|
|
224
|
+
None
|
|
225
|
+
"""
|
|
226
|
+
while True:
|
|
227
|
+
try:
|
|
228
|
+
d = await in_connection.reader.read(1)
|
|
229
|
+
out_connection.writer.write(d)
|
|
230
|
+
|
|
231
|
+
if not d:
|
|
232
|
+
log.info(
|
|
233
|
+
f"{in_connection.writer.transport.get_extra_info('socket')} "
|
|
234
|
+
f"disconnected."
|
|
235
|
+
)
|
|
236
|
+
break
|
|
237
|
+
except ConnectionError:
|
|
238
|
+
log.exception("connection error in data router")
|
|
239
|
+
break
|
|
240
|
+
if close_other_on_disconnect:
|
|
241
|
+
out_connection.writer.close()
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
import logging
|
|
3
|
+
from typing import Optional
|
|
4
|
+
|
|
5
|
+
from opentrons.hardware_control.emulation.abstract_emulator import AbstractEmulator
|
|
6
|
+
from opentrons.hardware_control.emulation.connection_handler import ConnectionHandler
|
|
7
|
+
|
|
8
|
+
log = logging.getLogger(__name__)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
async def run_emulator_client(
|
|
12
|
+
host: str,
|
|
13
|
+
port: int,
|
|
14
|
+
emulator: AbstractEmulator,
|
|
15
|
+
retries: int = 3,
|
|
16
|
+
interval_seconds: float = 0.1,
|
|
17
|
+
) -> None:
|
|
18
|
+
"""Run an emulator as a client.
|
|
19
|
+
|
|
20
|
+
Args:
|
|
21
|
+
host: Host to connect to.
|
|
22
|
+
port: Port to connect on.
|
|
23
|
+
emulator: The emulator instance.
|
|
24
|
+
retries: Number of retries on a failed connection attempt.
|
|
25
|
+
interval_seconds: How long to wait between retries.
|
|
26
|
+
|
|
27
|
+
Returns:
|
|
28
|
+
None
|
|
29
|
+
"""
|
|
30
|
+
log.info(f"Connecting to {emulator.__class__.__name__} at {host}:{port}")
|
|
31
|
+
|
|
32
|
+
r: Optional[asyncio.StreamReader] = None
|
|
33
|
+
w: Optional[asyncio.StreamWriter] = None
|
|
34
|
+
for i in range(retries):
|
|
35
|
+
try:
|
|
36
|
+
r, w = await asyncio.open_connection(host, port)
|
|
37
|
+
break
|
|
38
|
+
except IOError:
|
|
39
|
+
log.error(
|
|
40
|
+
f"{emulator.__class__.__name__} failed to connect on "
|
|
41
|
+
f"try {i + 1}. Retrying in {interval_seconds} seconds."
|
|
42
|
+
)
|
|
43
|
+
await asyncio.sleep(interval_seconds)
|
|
44
|
+
|
|
45
|
+
if r is None or w is None:
|
|
46
|
+
raise IOError(
|
|
47
|
+
f"Failed to connect to {emulator.__class__.__name__} at "
|
|
48
|
+
f"{host}:{port} after {retries} retries."
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
connection = ConnectionHandler(emulator)
|
|
52
|
+
await connection(r, w)
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
async def run_emulator_server(host: str, port: int, emulator: AbstractEmulator) -> None:
|
|
56
|
+
"""Run an emulator as a server.
|
|
57
|
+
|
|
58
|
+
Args:
|
|
59
|
+
host: Host to listen on.
|
|
60
|
+
port: Port to listen on.
|
|
61
|
+
emulator: Emulator instance.
|
|
62
|
+
|
|
63
|
+
Returns:
|
|
64
|
+
None
|
|
65
|
+
"""
|
|
66
|
+
log.info(f"Starting {emulator.__class__.__name__} at {host}:{port}")
|
|
67
|
+
server = await asyncio.start_server(ConnectionHandler(emulator), host, port)
|
|
68
|
+
await server.serve_forever()
|
|
File without changes
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
"""Script for starting up emulation up with module emulators."""
|
|
2
|
+
import logging
|
|
3
|
+
import asyncio
|
|
4
|
+
from argparse import ArgumentParser
|
|
5
|
+
from typing import List
|
|
6
|
+
|
|
7
|
+
from opentrons.hardware_control.emulation.app import Application
|
|
8
|
+
from opentrons.hardware_control.emulation.scripts.run_module_emulator import (
|
|
9
|
+
emulator_builder,
|
|
10
|
+
)
|
|
11
|
+
from opentrons.hardware_control.emulation.settings import Settings
|
|
12
|
+
from .run_module_emulator import run as run_module_by_name
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
async def run(settings: Settings, modules: List[str]) -> None:
|
|
16
|
+
"""Run the emulator app with connected module emulators.
|
|
17
|
+
|
|
18
|
+
Args:
|
|
19
|
+
settings: App settings.
|
|
20
|
+
modules: The module emulators to start.
|
|
21
|
+
|
|
22
|
+
Returns:
|
|
23
|
+
None
|
|
24
|
+
|
|
25
|
+
"""
|
|
26
|
+
loop = asyncio.get_event_loop()
|
|
27
|
+
|
|
28
|
+
app_task = loop.create_task(Application(settings=settings).run())
|
|
29
|
+
module_tasks = [
|
|
30
|
+
loop.create_task(
|
|
31
|
+
run_module_by_name(settings=settings, emulator_name=n, host="localhost")
|
|
32
|
+
)
|
|
33
|
+
for n in modules
|
|
34
|
+
]
|
|
35
|
+
await asyncio.gather(app_task, *module_tasks)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def main() -> None:
|
|
39
|
+
"""Entry point."""
|
|
40
|
+
a = ArgumentParser()
|
|
41
|
+
a.add_argument(
|
|
42
|
+
"--m",
|
|
43
|
+
action="append",
|
|
44
|
+
choices=emulator_builder.keys(),
|
|
45
|
+
help="which module(s) to emulate.",
|
|
46
|
+
)
|
|
47
|
+
args = a.parse_args()
|
|
48
|
+
|
|
49
|
+
logging.basicConfig(format="%(asctime)s:%(message)s", level=logging.DEBUG)
|
|
50
|
+
asyncio.run(run(Settings(), args.m))
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
if __name__ == "__main__":
|
|
54
|
+
main()
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
"""Script for starting up a python module emulator."""
|
|
2
|
+
import logging
|
|
3
|
+
import asyncio
|
|
4
|
+
from argparse import ArgumentParser
|
|
5
|
+
from typing import Dict, Callable
|
|
6
|
+
from typing_extensions import Final
|
|
7
|
+
|
|
8
|
+
from opentrons.hardware_control.emulation.abstract_emulator import AbstractEmulator
|
|
9
|
+
from opentrons.hardware_control.emulation.heater_shaker import HeaterShakerEmulator
|
|
10
|
+
from opentrons.hardware_control.emulation.types import ModuleType
|
|
11
|
+
from opentrons.hardware_control.emulation.magdeck import MagDeckEmulator
|
|
12
|
+
from opentrons.hardware_control.emulation.parser import Parser
|
|
13
|
+
from opentrons.hardware_control.emulation.tempdeck import TempDeckEmulator
|
|
14
|
+
from opentrons.hardware_control.emulation.thermocycler import ThermocyclerEmulator
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
from opentrons.hardware_control.emulation.run_emulator import run_emulator_client
|
|
18
|
+
from opentrons.hardware_control.emulation.settings import Settings, ProxySettings
|
|
19
|
+
|
|
20
|
+
emulator_builder: Final[Dict[str, Callable[[Settings], AbstractEmulator]]] = {
|
|
21
|
+
ModuleType.Magnetic.value: lambda s: MagDeckEmulator(Parser(), s.magdeck),
|
|
22
|
+
ModuleType.Temperature.value: lambda s: TempDeckEmulator(Parser(), s.tempdeck),
|
|
23
|
+
ModuleType.Thermocycler.value: lambda s: ThermocyclerEmulator(
|
|
24
|
+
Parser(), s.thermocycler
|
|
25
|
+
),
|
|
26
|
+
ModuleType.Heatershaker.value: lambda s: HeaterShakerEmulator(
|
|
27
|
+
Parser(), s.heatershaker
|
|
28
|
+
),
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
emulator_port: Final[Dict[str, Callable[[Settings], ProxySettings]]] = {
|
|
32
|
+
ModuleType.Magnetic.value: lambda s: s.magdeck_proxy,
|
|
33
|
+
ModuleType.Temperature.value: lambda s: s.temperature_proxy,
|
|
34
|
+
ModuleType.Thermocycler.value: lambda s: s.thermocycler_proxy,
|
|
35
|
+
ModuleType.Heatershaker.value: lambda s: s.heatershaker_proxy,
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
async def run(settings: Settings, emulator_name: str, host: str) -> None:
|
|
40
|
+
"""Run an emulator.
|
|
41
|
+
|
|
42
|
+
Args:
|
|
43
|
+
settings: emulator settings
|
|
44
|
+
emulator_name: Name of emulator. This must be a key in emulator_builder
|
|
45
|
+
host: host to connect to.
|
|
46
|
+
|
|
47
|
+
Returns:
|
|
48
|
+
None
|
|
49
|
+
"""
|
|
50
|
+
e = emulator_builder[emulator_name](settings)
|
|
51
|
+
proxy_settings = emulator_port[emulator_name](settings)
|
|
52
|
+
await run_emulator_client(host, proxy_settings.emulator_port, e)
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def main() -> None:
|
|
56
|
+
"""Entry point."""
|
|
57
|
+
a = ArgumentParser()
|
|
58
|
+
a.add_argument(
|
|
59
|
+
"emulator",
|
|
60
|
+
type=str,
|
|
61
|
+
choices=emulator_builder.keys(),
|
|
62
|
+
help="which module to emulate.",
|
|
63
|
+
)
|
|
64
|
+
a.add_argument("host", type=str, help="the emulator host")
|
|
65
|
+
args = a.parse_args()
|
|
66
|
+
|
|
67
|
+
logging.basicConfig(format="%(asctime)s:%(message)s", level=logging.DEBUG)
|
|
68
|
+
asyncio.run(run(Settings(), args.emulator, args.host))
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
if __name__ == "__main__":
|
|
72
|
+
main()
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"""Script for starting up a python smoothie emulator."""
|
|
2
|
+
import logging
|
|
3
|
+
import asyncio
|
|
4
|
+
|
|
5
|
+
from opentrons.hardware_control.emulation.smoothie import SmoothieEmulator
|
|
6
|
+
from opentrons.hardware_control.emulation.parser import Parser
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
from opentrons.hardware_control.emulation.run_emulator import run_emulator_server
|
|
10
|
+
from opentrons.hardware_control.emulation.settings import Settings
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
async def run(settings: Settings) -> None:
|
|
14
|
+
"""Run the smoothie emulator.
|
|
15
|
+
|
|
16
|
+
Args:
|
|
17
|
+
settings: emulator settings
|
|
18
|
+
|
|
19
|
+
Returns:
|
|
20
|
+
None
|
|
21
|
+
"""
|
|
22
|
+
smoothie = SmoothieEmulator(parser=Parser(), settings=settings.smoothie)
|
|
23
|
+
await run_emulator_server(
|
|
24
|
+
host=settings.smoothie.host,
|
|
25
|
+
port=settings.smoothie.port,
|
|
26
|
+
emulator=smoothie,
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def main() -> None:
|
|
31
|
+
"""Entry point."""
|
|
32
|
+
logging.basicConfig(format="%(asctime)s:%(message)s", level=logging.DEBUG)
|
|
33
|
+
asyncio.run(run(Settings()))
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
if __name__ == "__main__":
|
|
37
|
+
main()
|