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,245 @@
|
|
|
1
|
+
import abc
|
|
2
|
+
import asyncio
|
|
3
|
+
import logging
|
|
4
|
+
import re
|
|
5
|
+
from typing import Any, ClassVar, Mapping, Optional, TypeVar
|
|
6
|
+
from packaging.version import InvalidVersion, parse, Version
|
|
7
|
+
from opentrons.config import IS_ROBOT, ROBOT_FIRMWARE_DIR
|
|
8
|
+
from opentrons.drivers.rpi_drivers.types import USBPort
|
|
9
|
+
|
|
10
|
+
from ..execution_manager import ExecutionManager
|
|
11
|
+
from .types import (
|
|
12
|
+
BundledFirmware,
|
|
13
|
+
ModuleDisconnectedCallback,
|
|
14
|
+
UploadFunction,
|
|
15
|
+
LiveData,
|
|
16
|
+
ModuleType,
|
|
17
|
+
HopperDoorState,
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
mod_log = logging.getLogger(__name__)
|
|
21
|
+
|
|
22
|
+
TaskPayload = TypeVar("TaskPayload")
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def parse_fw_version(version: str) -> Version:
|
|
26
|
+
try:
|
|
27
|
+
device_version = parse(version)
|
|
28
|
+
# This is a patch for older versions of packaging - they would try and parse old
|
|
29
|
+
# kidns of versions and return a LegacyVersion object. We can't check for that
|
|
30
|
+
# explicitly because they removed it in modern versions of packaging.
|
|
31
|
+
if not isinstance(device_version, Version):
|
|
32
|
+
raise InvalidVersion()
|
|
33
|
+
except InvalidVersion:
|
|
34
|
+
device_version = parse("v0.0.0")
|
|
35
|
+
return device_version
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class AbstractModule(abc.ABC):
|
|
39
|
+
"""Defines the common methods of a module."""
|
|
40
|
+
|
|
41
|
+
MODULE_TYPE: ClassVar[ModuleType]
|
|
42
|
+
|
|
43
|
+
@classmethod
|
|
44
|
+
@abc.abstractmethod
|
|
45
|
+
async def build(
|
|
46
|
+
cls,
|
|
47
|
+
port: str,
|
|
48
|
+
usb_port: USBPort,
|
|
49
|
+
hw_control_loop: asyncio.AbstractEventLoop,
|
|
50
|
+
execution_manager: Optional[ExecutionManager] = None,
|
|
51
|
+
poll_interval_seconds: Optional[float] = None,
|
|
52
|
+
simulating: bool = False,
|
|
53
|
+
sim_model: Optional[str] = None,
|
|
54
|
+
sim_serial_number: Optional[str] = None,
|
|
55
|
+
disconnected_callback: ModuleDisconnectedCallback = None,
|
|
56
|
+
) -> "AbstractModule":
|
|
57
|
+
"""Modules should always be created using this factory.
|
|
58
|
+
|
|
59
|
+
This lets the (perhaps blocking) work of connecting to and initializing
|
|
60
|
+
a module be in a place that can be async.
|
|
61
|
+
"""
|
|
62
|
+
|
|
63
|
+
def __init__(
|
|
64
|
+
self,
|
|
65
|
+
port: str,
|
|
66
|
+
usb_port: USBPort,
|
|
67
|
+
hw_control_loop: asyncio.AbstractEventLoop,
|
|
68
|
+
execution_manager: Optional[ExecutionManager] = None,
|
|
69
|
+
disconnected_callback: ModuleDisconnectedCallback = None,
|
|
70
|
+
) -> None:
|
|
71
|
+
self._port = port
|
|
72
|
+
self._usb_port = usb_port
|
|
73
|
+
self._loop = hw_control_loop
|
|
74
|
+
self._execution_manager = execution_manager
|
|
75
|
+
self._bundled_fw: Optional[BundledFirmware] = self.get_bundled_fw()
|
|
76
|
+
self._disconnected_callback = disconnected_callback
|
|
77
|
+
self._updating = False
|
|
78
|
+
|
|
79
|
+
@staticmethod
|
|
80
|
+
def sort_key(inst: "AbstractModule") -> int:
|
|
81
|
+
usb_port = inst.usb_port
|
|
82
|
+
|
|
83
|
+
primary_port = usb_port.port_number
|
|
84
|
+
|
|
85
|
+
if usb_port.hub_port is not None:
|
|
86
|
+
secondary_port = usb_port.hub_port
|
|
87
|
+
else:
|
|
88
|
+
secondary_port = 0
|
|
89
|
+
|
|
90
|
+
return primary_port * 1000 + secondary_port
|
|
91
|
+
|
|
92
|
+
@property
|
|
93
|
+
def loop(self) -> asyncio.AbstractEventLoop:
|
|
94
|
+
return self._loop
|
|
95
|
+
|
|
96
|
+
@property
|
|
97
|
+
def updating(self) -> bool:
|
|
98
|
+
"""The device is updating is True."""
|
|
99
|
+
return self._updating
|
|
100
|
+
|
|
101
|
+
def disconnected_callback(self) -> None:
|
|
102
|
+
"""Called from within the module object to signify the object is no longer connected"""
|
|
103
|
+
if self._disconnected_callback is not None:
|
|
104
|
+
self._disconnected_callback(self.port, self.serial_number)
|
|
105
|
+
|
|
106
|
+
def get_bundled_fw(self) -> Optional[BundledFirmware]:
|
|
107
|
+
"""Get absolute path to bundled version of module fw if available."""
|
|
108
|
+
if not IS_ROBOT:
|
|
109
|
+
return None
|
|
110
|
+
file_prefix = self.firmware_prefix()
|
|
111
|
+
|
|
112
|
+
MODULE_FW_RE = re.compile(f"^{file_prefix}@v(.*)[.](hex|bin|byoup)$")
|
|
113
|
+
for fw_resource in ROBOT_FIRMWARE_DIR.iterdir(): # type: ignore
|
|
114
|
+
matches = MODULE_FW_RE.search(fw_resource.name)
|
|
115
|
+
if matches:
|
|
116
|
+
return BundledFirmware(version=matches.group(1), path=fw_resource)
|
|
117
|
+
|
|
118
|
+
mod_log.info(f"no available fw file found for: {file_prefix}")
|
|
119
|
+
return None
|
|
120
|
+
|
|
121
|
+
def has_available_update(self) -> bool:
|
|
122
|
+
"""Return whether a newer firmware file is available"""
|
|
123
|
+
if self.device_info and self._bundled_fw:
|
|
124
|
+
device_version = parse_fw_version(self.device_info["version"])
|
|
125
|
+
available_version = parse_fw_version(self._bundled_fw.version)
|
|
126
|
+
return available_version > device_version
|
|
127
|
+
return False
|
|
128
|
+
|
|
129
|
+
async def wait_for_is_running(self) -> None:
|
|
130
|
+
if not self.is_simulated and self._execution_manager is not None:
|
|
131
|
+
await self._execution_manager.wait_for_is_running()
|
|
132
|
+
|
|
133
|
+
def make_cancellable(self, task: "asyncio.Task[TaskPayload]") -> None:
|
|
134
|
+
if self._execution_manager is not None:
|
|
135
|
+
self._execution_manager.register_cancellable_task(task)
|
|
136
|
+
|
|
137
|
+
@abc.abstractmethod
|
|
138
|
+
async def deactivate(self, must_be_running: bool = True) -> None:
|
|
139
|
+
"""Deactivate the module.
|
|
140
|
+
|
|
141
|
+
Contains an override to the `wait_for_is_running` step in cases where the
|
|
142
|
+
module must be deactivated regardless of context."""
|
|
143
|
+
pass
|
|
144
|
+
|
|
145
|
+
@property
|
|
146
|
+
@abc.abstractmethod
|
|
147
|
+
def status(self) -> str:
|
|
148
|
+
"""Return some string describing status."""
|
|
149
|
+
pass
|
|
150
|
+
|
|
151
|
+
@property
|
|
152
|
+
@abc.abstractmethod
|
|
153
|
+
def device_info(self) -> Mapping[str, str]:
|
|
154
|
+
"""Return a dict of the module's static information (serial, etc)"""
|
|
155
|
+
pass
|
|
156
|
+
|
|
157
|
+
@property
|
|
158
|
+
@abc.abstractmethod
|
|
159
|
+
def live_data(self) -> LiveData:
|
|
160
|
+
"""Return a dict of the module's dynamic information"""
|
|
161
|
+
pass
|
|
162
|
+
|
|
163
|
+
@property
|
|
164
|
+
@abc.abstractmethod
|
|
165
|
+
def is_simulated(self) -> bool:
|
|
166
|
+
"""True if >this is a simulated module."""
|
|
167
|
+
pass
|
|
168
|
+
|
|
169
|
+
@property
|
|
170
|
+
def port(self) -> str:
|
|
171
|
+
"""The virtual port where the module is connected."""
|
|
172
|
+
return self._port
|
|
173
|
+
|
|
174
|
+
@property
|
|
175
|
+
def usb_port(self) -> USBPort:
|
|
176
|
+
"""The physical port where the module is connected."""
|
|
177
|
+
return self._usb_port
|
|
178
|
+
|
|
179
|
+
@property
|
|
180
|
+
def serial_number(self) -> Optional[str]:
|
|
181
|
+
"""The usb serial number of this device."""
|
|
182
|
+
return self.device_info.get("serial")
|
|
183
|
+
|
|
184
|
+
@property
|
|
185
|
+
def hopper_door_state(self) -> Optional[HopperDoorState]:
|
|
186
|
+
"""Return a Flex Stacker Hopper Module Door State"""
|
|
187
|
+
pass
|
|
188
|
+
|
|
189
|
+
@abc.abstractmethod
|
|
190
|
+
async def prep_for_update(self) -> str:
|
|
191
|
+
"""Prepare for an update.
|
|
192
|
+
|
|
193
|
+
By the time this coroutine completes, the hardware should be ready
|
|
194
|
+
to take an update. This implicitly tears down the module instance;
|
|
195
|
+
it does not need to be either working or recoverable after this
|
|
196
|
+
coroutine completes.
|
|
197
|
+
|
|
198
|
+
:returns str: The port we're running on.
|
|
199
|
+
"""
|
|
200
|
+
pass
|
|
201
|
+
|
|
202
|
+
@property
|
|
203
|
+
def bundled_fw(self) -> Optional[BundledFirmware]:
|
|
204
|
+
return self._bundled_fw
|
|
205
|
+
|
|
206
|
+
@abc.abstractmethod
|
|
207
|
+
def model(self) -> str:
|
|
208
|
+
"""A name for this specific module, matching module defs"""
|
|
209
|
+
pass
|
|
210
|
+
|
|
211
|
+
@classmethod
|
|
212
|
+
@abc.abstractmethod
|
|
213
|
+
def name(cls) -> str:
|
|
214
|
+
"""A shortname used for matching usb ports, among other things"""
|
|
215
|
+
pass
|
|
216
|
+
|
|
217
|
+
@abc.abstractmethod
|
|
218
|
+
def firmware_prefix(self) -> str:
|
|
219
|
+
"""The prefix used for looking up firmware"""
|
|
220
|
+
pass
|
|
221
|
+
|
|
222
|
+
@abc.abstractmethod
|
|
223
|
+
def bootloader(self) -> UploadFunction:
|
|
224
|
+
"""Method used to upload file to this module's bootloader."""
|
|
225
|
+
pass
|
|
226
|
+
|
|
227
|
+
async def cleanup(self) -> None:
|
|
228
|
+
"""Clean up the module instance.
|
|
229
|
+
|
|
230
|
+
Clean up, i.e. stop pollers, disconnect serial, etc in preparation for
|
|
231
|
+
object destruction.
|
|
232
|
+
"""
|
|
233
|
+
pass
|
|
234
|
+
|
|
235
|
+
def event_listener(self, event: Any) -> None:
|
|
236
|
+
"""Listen for events and update the module state."""
|
|
237
|
+
pass
|
|
238
|
+
|
|
239
|
+
async def identify(self, start: bool, color_name: Optional[str] = None) -> None:
|
|
240
|
+
"""Identify the module."""
|
|
241
|
+
pass
|
|
242
|
+
|
|
243
|
+
def cleanup_persistent(self) -> None:
|
|
244
|
+
"""Reset any persistent data on the module that should not exist outside of a run."""
|
|
245
|
+
pass
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
from datetime import datetime
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
from typing import List, Optional
|
|
5
|
+
from opentrons.calibration_storage.ot3.models.v1 import CalibrationStatus
|
|
6
|
+
from opentrons.calibration_storage.ot3.module_offset import (
|
|
7
|
+
get_module_offset,
|
|
8
|
+
load_all_module_offsets,
|
|
9
|
+
save_module_calibration,
|
|
10
|
+
)
|
|
11
|
+
from opentrons.calibration_storage.types import SourceType
|
|
12
|
+
from opentrons.hardware_control.modules.types import ModuleType
|
|
13
|
+
from opentrons.hardware_control.types import OT3Mount
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
from opentrons.types import Point
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@dataclass
|
|
20
|
+
class ModuleCalibrationOffset:
|
|
21
|
+
"""Class to store module offset calibration data."""
|
|
22
|
+
|
|
23
|
+
offset: Point
|
|
24
|
+
module_id: str
|
|
25
|
+
module: ModuleType
|
|
26
|
+
source: SourceType
|
|
27
|
+
status: CalibrationStatus
|
|
28
|
+
slot: str
|
|
29
|
+
mount: Optional[OT3Mount] = None
|
|
30
|
+
instrument_id: Optional[str] = None
|
|
31
|
+
last_modified: Optional[datetime] = None
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def load_module_calibration_offset(
|
|
35
|
+
module_type: ModuleType,
|
|
36
|
+
module_id: str,
|
|
37
|
+
) -> Optional[ModuleCalibrationOffset]:
|
|
38
|
+
"""Loads the calibration offset for a module."""
|
|
39
|
+
module_offset_data = get_module_offset(module_type, module_id)
|
|
40
|
+
if not module_offset_data:
|
|
41
|
+
return None
|
|
42
|
+
return ModuleCalibrationOffset(
|
|
43
|
+
module=module_type,
|
|
44
|
+
module_id=module_id,
|
|
45
|
+
slot=module_offset_data.slot,
|
|
46
|
+
mount=module_offset_data.mount,
|
|
47
|
+
offset=module_offset_data.offset,
|
|
48
|
+
last_modified=module_offset_data.lastModified,
|
|
49
|
+
instrument_id=module_offset_data.instrument_id,
|
|
50
|
+
source=module_offset_data.source,
|
|
51
|
+
status=CalibrationStatus(
|
|
52
|
+
markedAt=module_offset_data.status.markedAt,
|
|
53
|
+
markedBad=module_offset_data.status.markedBad,
|
|
54
|
+
source=module_offset_data.status.source,
|
|
55
|
+
),
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def save_module_calibration_offset(
|
|
60
|
+
offset: Point,
|
|
61
|
+
mount: OT3Mount,
|
|
62
|
+
slot: str,
|
|
63
|
+
module: ModuleType,
|
|
64
|
+
module_id: str,
|
|
65
|
+
instrument_id: Optional[str] = None,
|
|
66
|
+
) -> None:
|
|
67
|
+
"""Save the calibration offset for a given module."""
|
|
68
|
+
save_module_calibration(offset, mount, slot, module, module_id, instrument_id)
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def load_all_module_calibrations() -> List[ModuleCalibrationOffset]:
|
|
72
|
+
"""Loads all the module calibration stored on the robot."""
|
|
73
|
+
module_calibrations: List[ModuleCalibrationOffset] = []
|
|
74
|
+
module_offset_data = load_all_module_offsets()
|
|
75
|
+
for data in module_offset_data:
|
|
76
|
+
module_calibrations.append(
|
|
77
|
+
ModuleCalibrationOffset(
|
|
78
|
+
slot=data.slot,
|
|
79
|
+
module=data.module,
|
|
80
|
+
module_id=data.module_id,
|
|
81
|
+
mount=data.mount,
|
|
82
|
+
offset=data.offset,
|
|
83
|
+
last_modified=data.lastModified,
|
|
84
|
+
instrument_id=data.instrument_id,
|
|
85
|
+
source=data.source,
|
|
86
|
+
status=CalibrationStatus(
|
|
87
|
+
markedAt=data.status.markedAt,
|
|
88
|
+
markedBad=data.status.markedBad,
|
|
89
|
+
source=data.status.source,
|
|
90
|
+
),
|
|
91
|
+
)
|
|
92
|
+
)
|
|
93
|
+
return module_calibrations
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
from collections import deque
|
|
2
|
+
from typing import Deque
|
|
3
|
+
|
|
4
|
+
from opentrons.drivers.types import PlateTemperature
|
|
5
|
+
from opentrons.hardware_control.modules.types import TemperatureStatus
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class PlateTemperatureStatus:
|
|
9
|
+
|
|
10
|
+
TEMP_THRESHOLD = 0.3
|
|
11
|
+
"""The threshold under which the difference between target and temperature
|
|
12
|
+
is considered `holding`."""
|
|
13
|
+
|
|
14
|
+
MIN_SAMPLES_UNDER_THRESHOLD = 10
|
|
15
|
+
"""The number of temperature samples needed before determining that the
|
|
16
|
+
temperature is `holding`"""
|
|
17
|
+
|
|
18
|
+
def __init__(self) -> None:
|
|
19
|
+
"""Construct."""
|
|
20
|
+
self._temp_history: Deque[float] = deque(
|
|
21
|
+
maxlen=self.MIN_SAMPLES_UNDER_THRESHOLD
|
|
22
|
+
)
|
|
23
|
+
self._status = TemperatureStatus.ERROR
|
|
24
|
+
|
|
25
|
+
@property
|
|
26
|
+
def status(self) -> TemperatureStatus:
|
|
27
|
+
"""Return the current status."""
|
|
28
|
+
return self._status
|
|
29
|
+
|
|
30
|
+
def update(self, temperature: PlateTemperature) -> TemperatureStatus:
|
|
31
|
+
"""Update the status based on the temperature."""
|
|
32
|
+
# Add to history
|
|
33
|
+
self._temp_history.append(temperature.current)
|
|
34
|
+
|
|
35
|
+
if temperature.target is None:
|
|
36
|
+
_status = TemperatureStatus.IDLE
|
|
37
|
+
else:
|
|
38
|
+
diff = temperature.target - temperature.current
|
|
39
|
+
if self._is_holding_at_target(temperature.target, self._temp_history):
|
|
40
|
+
_status = TemperatureStatus.HOLDING
|
|
41
|
+
elif diff < 0:
|
|
42
|
+
_status = TemperatureStatus.COOLING
|
|
43
|
+
else:
|
|
44
|
+
_status = TemperatureStatus.HEATING
|
|
45
|
+
self._status = _status
|
|
46
|
+
return self._status
|
|
47
|
+
|
|
48
|
+
@staticmethod
|
|
49
|
+
def _is_holding_at_target(target: float, history: Deque[float]) -> bool:
|
|
50
|
+
"""
|
|
51
|
+
Checks block temp history to determine if block temp has stabilized at
|
|
52
|
+
the target temperature. Returns true only if all values in history are
|
|
53
|
+
within threshold range of target temperature.
|
|
54
|
+
"""
|
|
55
|
+
if len(history) < PlateTemperatureStatus.MIN_SAMPLES_UNDER_THRESHOLD:
|
|
56
|
+
# Not enough temp history
|
|
57
|
+
return False
|
|
58
|
+
else:
|
|
59
|
+
return all(
|
|
60
|
+
abs(target - t) < PlateTemperatureStatus.TEMP_THRESHOLD for t in history
|
|
61
|
+
)
|
|
@@ -0,0 +1,299 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import asyncio
|
|
4
|
+
import logging
|
|
5
|
+
from typing import Dict, Optional
|
|
6
|
+
|
|
7
|
+
from opentrons.hardware_control.modules.types import (
|
|
8
|
+
ModuleDisconnectedCallback,
|
|
9
|
+
TemperatureStatus,
|
|
10
|
+
)
|
|
11
|
+
from opentrons.hardware_control.poller import Reader, Poller
|
|
12
|
+
from typing_extensions import Final
|
|
13
|
+
from opentrons.drivers.types import Temperature
|
|
14
|
+
from opentrons.drivers.temp_deck import (
|
|
15
|
+
SimulatingDriver,
|
|
16
|
+
AbstractTempDeckDriver,
|
|
17
|
+
TempDeckDriver,
|
|
18
|
+
)
|
|
19
|
+
from opentrons.drivers.rpi_drivers.types import USBPort
|
|
20
|
+
from opentrons.hardware_control.execution_manager import ExecutionManager
|
|
21
|
+
from opentrons.hardware_control.modules import update, mod_abc, types, errors
|
|
22
|
+
|
|
23
|
+
log = logging.getLogger(__name__)
|
|
24
|
+
|
|
25
|
+
TEMP_POLL_INTERVAL_SECS = 1.0
|
|
26
|
+
SIM_TEMP_POLL_INTERVAL_SECS = TEMP_POLL_INTERVAL_SECS / 20.0
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class TempDeck(mod_abc.AbstractModule):
|
|
30
|
+
"""Hardware control interface for an attached Temperature Module."""
|
|
31
|
+
|
|
32
|
+
MODULE_TYPE = types.ModuleType["TEMPERATURE"]
|
|
33
|
+
FIRST_GEN2_REVISION = 20
|
|
34
|
+
|
|
35
|
+
@classmethod
|
|
36
|
+
async def build(
|
|
37
|
+
cls,
|
|
38
|
+
port: str,
|
|
39
|
+
usb_port: USBPort,
|
|
40
|
+
hw_control_loop: asyncio.AbstractEventLoop,
|
|
41
|
+
execution_manager: Optional[ExecutionManager] = None,
|
|
42
|
+
poll_interval_seconds: Optional[float] = None,
|
|
43
|
+
simulating: bool = False,
|
|
44
|
+
sim_model: Optional[str] = None,
|
|
45
|
+
sim_serial_number: Optional[str] = None,
|
|
46
|
+
disconnected_callback: ModuleDisconnectedCallback = None,
|
|
47
|
+
) -> "TempDeck":
|
|
48
|
+
"""
|
|
49
|
+
Build a TempDeck
|
|
50
|
+
|
|
51
|
+
Args:
|
|
52
|
+
port: The port to connect to
|
|
53
|
+
usb_port: USB Port
|
|
54
|
+
hw_control_loop: The event loop running in the hardware control thread.
|
|
55
|
+
execution_manager: Execution manager.
|
|
56
|
+
poll_interval_seconds: Poll interval override.
|
|
57
|
+
simulating: whether to build a simulating driver
|
|
58
|
+
sim_model: The model name used by simulator
|
|
59
|
+
disconnected_callback: Callback to inform the module controller that the device was disconnected
|
|
60
|
+
|
|
61
|
+
Returns:
|
|
62
|
+
Tempdeck instance
|
|
63
|
+
"""
|
|
64
|
+
driver: AbstractTempDeckDriver
|
|
65
|
+
if not simulating:
|
|
66
|
+
driver = await TempDeckDriver.create(port=port, loop=hw_control_loop)
|
|
67
|
+
poll_interval_seconds = poll_interval_seconds or TEMP_POLL_INTERVAL_SECS
|
|
68
|
+
else:
|
|
69
|
+
driver = SimulatingDriver(
|
|
70
|
+
sim_model=sim_model, serial_number=sim_serial_number
|
|
71
|
+
)
|
|
72
|
+
poll_interval_seconds = poll_interval_seconds or SIM_TEMP_POLL_INTERVAL_SECS
|
|
73
|
+
|
|
74
|
+
reader = TempDeckReader(driver=driver)
|
|
75
|
+
poller = Poller(reader=reader, interval=poll_interval_seconds)
|
|
76
|
+
module = cls(
|
|
77
|
+
port=port,
|
|
78
|
+
usb_port=usb_port,
|
|
79
|
+
execution_manager=execution_manager,
|
|
80
|
+
driver=driver,
|
|
81
|
+
reader=reader,
|
|
82
|
+
poller=poller,
|
|
83
|
+
device_info=await driver.get_device_info(),
|
|
84
|
+
hw_control_loop=hw_control_loop,
|
|
85
|
+
disconnected_callback=disconnected_callback,
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
try:
|
|
89
|
+
await poller.start()
|
|
90
|
+
except Exception:
|
|
91
|
+
log.exception(f"First read of Temperature Module on port {port} failed")
|
|
92
|
+
|
|
93
|
+
return module
|
|
94
|
+
|
|
95
|
+
def __init__(
|
|
96
|
+
self,
|
|
97
|
+
port: str,
|
|
98
|
+
usb_port: USBPort,
|
|
99
|
+
driver: AbstractTempDeckDriver,
|
|
100
|
+
reader: TempDeckReader,
|
|
101
|
+
poller: Poller,
|
|
102
|
+
device_info: Dict[str, str],
|
|
103
|
+
hw_control_loop: asyncio.AbstractEventLoop,
|
|
104
|
+
execution_manager: Optional[ExecutionManager] = None,
|
|
105
|
+
disconnected_callback: ModuleDisconnectedCallback = None,
|
|
106
|
+
) -> None:
|
|
107
|
+
"""Constructor"""
|
|
108
|
+
super().__init__(
|
|
109
|
+
port=port,
|
|
110
|
+
usb_port=usb_port,
|
|
111
|
+
hw_control_loop=hw_control_loop,
|
|
112
|
+
execution_manager=execution_manager,
|
|
113
|
+
disconnected_callback=disconnected_callback,
|
|
114
|
+
)
|
|
115
|
+
self._device_info = device_info
|
|
116
|
+
self._driver = driver
|
|
117
|
+
self._reader = reader
|
|
118
|
+
self._poller = poller
|
|
119
|
+
|
|
120
|
+
async def cleanup(self) -> None:
|
|
121
|
+
"""Stop the poller task."""
|
|
122
|
+
await self._poller.stop()
|
|
123
|
+
await self._driver.disconnect()
|
|
124
|
+
|
|
125
|
+
@classmethod
|
|
126
|
+
def name(cls) -> str:
|
|
127
|
+
return "tempdeck"
|
|
128
|
+
|
|
129
|
+
def firmware_prefix(self) -> str:
|
|
130
|
+
"""The prefix used for looking up firmware"""
|
|
131
|
+
return "temperature-module"
|
|
132
|
+
|
|
133
|
+
def model(self) -> str:
|
|
134
|
+
return self._model_from_revision(self._device_info.get("model"))
|
|
135
|
+
|
|
136
|
+
def bootloader(self) -> types.UploadFunction:
|
|
137
|
+
return update.upload_via_avrdude
|
|
138
|
+
|
|
139
|
+
async def start_set_temperature(self, celsius: float) -> None:
|
|
140
|
+
"""Set the target temperature in degrees Celsius.
|
|
141
|
+
|
|
142
|
+
Range: 4 to 95 degrees Celsius (QA tested).
|
|
143
|
+
|
|
144
|
+
The internal temp range is -9 to 99 °C, which is limited by the two-digit
|
|
145
|
+
temperature display. Any input outside of this range will be clipped
|
|
146
|
+
to the nearest limit.
|
|
147
|
+
"""
|
|
148
|
+
await self.wait_for_is_running()
|
|
149
|
+
await self._driver.set_temperature(celsius)
|
|
150
|
+
await self._reader.read()
|
|
151
|
+
|
|
152
|
+
async def await_temperature(self, awaiting_temperature: Optional[float]) -> None:
|
|
153
|
+
"""Await a target temperature in degrees Celsius.
|
|
154
|
+
|
|
155
|
+
Polls Temperature Module's temperature until
|
|
156
|
+
the specified temperature is reached.
|
|
157
|
+
|
|
158
|
+
Args:
|
|
159
|
+
temperature: The temperature to wait for.
|
|
160
|
+
If `None` (recommended), the module's target will be used.
|
|
161
|
+
Specifying any value other than the current target
|
|
162
|
+
may produce unpredictable behavior.
|
|
163
|
+
"""
|
|
164
|
+
if self.is_simulated:
|
|
165
|
+
return
|
|
166
|
+
|
|
167
|
+
await self.wait_for_is_running()
|
|
168
|
+
await self._reader.read()
|
|
169
|
+
|
|
170
|
+
async def _await_temperature() -> None:
|
|
171
|
+
if awaiting_temperature is None:
|
|
172
|
+
while self.status != TemperatureStatus.HOLDING:
|
|
173
|
+
await self._poller.wait_next_poll()
|
|
174
|
+
elif self.status == TemperatureStatus.HEATING:
|
|
175
|
+
while self.temperature < awaiting_temperature:
|
|
176
|
+
await self._poller.wait_next_poll()
|
|
177
|
+
elif self.status == TemperatureStatus.COOLING:
|
|
178
|
+
while self.temperature > awaiting_temperature:
|
|
179
|
+
await self._poller.wait_next_poll()
|
|
180
|
+
|
|
181
|
+
t = self._loop.create_task(_await_temperature())
|
|
182
|
+
self.make_cancellable(t)
|
|
183
|
+
await t
|
|
184
|
+
|
|
185
|
+
async def deactivate(self, must_be_running: bool = True) -> None:
|
|
186
|
+
"""Stop heating/cooling and turn off the fan"""
|
|
187
|
+
if must_be_running:
|
|
188
|
+
await self.wait_for_is_running()
|
|
189
|
+
await self._driver.deactivate()
|
|
190
|
+
await self._reader.read()
|
|
191
|
+
|
|
192
|
+
@property
|
|
193
|
+
def device_info(self) -> Dict[str, str]:
|
|
194
|
+
return self._device_info
|
|
195
|
+
|
|
196
|
+
@property
|
|
197
|
+
def live_data(self) -> types.LiveData:
|
|
198
|
+
data: types.TemperatureModuleData = {
|
|
199
|
+
"currentTemp": self.temperature,
|
|
200
|
+
"targetTemp": self.target,
|
|
201
|
+
}
|
|
202
|
+
return {
|
|
203
|
+
"status": self.status,
|
|
204
|
+
"data": data,
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
@property
|
|
208
|
+
def temperature(self) -> float:
|
|
209
|
+
return self._reader.temperature.current
|
|
210
|
+
|
|
211
|
+
@property
|
|
212
|
+
def target(self) -> Optional[float]:
|
|
213
|
+
return self._reader.temperature.target
|
|
214
|
+
|
|
215
|
+
@property
|
|
216
|
+
def status(self) -> TemperatureStatus:
|
|
217
|
+
return self._get_status(self._reader.temperature)
|
|
218
|
+
|
|
219
|
+
@property
|
|
220
|
+
def is_simulated(self) -> bool:
|
|
221
|
+
return isinstance(self._driver, SimulatingDriver)
|
|
222
|
+
|
|
223
|
+
async def prep_for_update(self) -> str:
|
|
224
|
+
model = self._device_info and self._device_info.get("model")
|
|
225
|
+
if model in ("temp_deck_v1", "temp_deck_v1.1", "temp_deck_v2"):
|
|
226
|
+
raise errors.UpdateError(
|
|
227
|
+
"This Temperature Module can't be updated."
|
|
228
|
+
"Please contact Opentrons Support."
|
|
229
|
+
)
|
|
230
|
+
await self._poller.stop()
|
|
231
|
+
await self._driver.enter_programming_mode()
|
|
232
|
+
new_port = await update.find_bootloader_port()
|
|
233
|
+
return new_port or self.port
|
|
234
|
+
|
|
235
|
+
def has_available_update(self) -> bool:
|
|
236
|
+
"""Override of abc implementation to suppress update notifications
|
|
237
|
+
for v1, v1.1, and v2 temperature modules which cannot be updated"""
|
|
238
|
+
if not self._device_info:
|
|
239
|
+
model = None
|
|
240
|
+
else:
|
|
241
|
+
model = self._device_info.get("model")
|
|
242
|
+
if model in {"temp_deck_v1", "temp_deck_v1.1", "temp_deck_v2", None}:
|
|
243
|
+
return False
|
|
244
|
+
return super().has_available_update()
|
|
245
|
+
|
|
246
|
+
@staticmethod
|
|
247
|
+
def _get_status(temperature: Temperature) -> TemperatureStatus:
|
|
248
|
+
"""
|
|
249
|
+
Determine the status from the temperature.
|
|
250
|
+
|
|
251
|
+
Args:
|
|
252
|
+
temperature: A Temperature instance
|
|
253
|
+
|
|
254
|
+
Returns:
|
|
255
|
+
The status
|
|
256
|
+
"""
|
|
257
|
+
DELTA: Final = 0.7
|
|
258
|
+
status = TemperatureStatus.IDLE
|
|
259
|
+
if temperature.target is not None:
|
|
260
|
+
diff = temperature.target - temperature.current
|
|
261
|
+
if abs(diff) < DELTA: # To avoid status fluctuation near target
|
|
262
|
+
status = TemperatureStatus.HOLDING
|
|
263
|
+
elif diff < 0:
|
|
264
|
+
status = TemperatureStatus.COOLING
|
|
265
|
+
else:
|
|
266
|
+
status = TemperatureStatus.HEATING
|
|
267
|
+
return status
|
|
268
|
+
|
|
269
|
+
@staticmethod
|
|
270
|
+
def _model_from_revision(revision: Optional[str]) -> str:
|
|
271
|
+
"""Defines the revision -> model mapping"""
|
|
272
|
+
if not revision or "v" not in revision:
|
|
273
|
+
log.error(f"bad revision: {revision}")
|
|
274
|
+
return "temperatureModuleV1"
|
|
275
|
+
try:
|
|
276
|
+
revision_num = float(revision.split("v")[-1])
|
|
277
|
+
except (ValueError, TypeError):
|
|
278
|
+
# none or corrupt
|
|
279
|
+
log.exception("no revision")
|
|
280
|
+
return "temperatureModuleV1"
|
|
281
|
+
|
|
282
|
+
if revision_num < TempDeck.FIRST_GEN2_REVISION:
|
|
283
|
+
return "temperatureModuleV1"
|
|
284
|
+
else:
|
|
285
|
+
return "temperatureModuleV2"
|
|
286
|
+
|
|
287
|
+
|
|
288
|
+
class TempDeckReader(Reader):
|
|
289
|
+
"""Reads data from an attached Temperature Module."""
|
|
290
|
+
|
|
291
|
+
temperature: Temperature
|
|
292
|
+
|
|
293
|
+
def __init__(self, driver: AbstractTempDeckDriver) -> None:
|
|
294
|
+
self.temperature = Temperature(current=25, target=None)
|
|
295
|
+
self._driver = driver
|
|
296
|
+
|
|
297
|
+
async def read(self) -> None:
|
|
298
|
+
"""Read the module's current and target temperatures."""
|
|
299
|
+
self.temperature = await self._driver.get_temperature()
|