opentrons 8.3.1a1__py2.py3-none-any.whl → 8.4.0a1__py2.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.
- opentrons/calibration_storage/ot2/mark_bad_calibration.py +2 -0
- opentrons/calibration_storage/ot2/tip_length.py +6 -6
- opentrons/config/advanced_settings.py +9 -11
- opentrons/config/feature_flags.py +0 -4
- opentrons/config/reset.py +7 -2
- opentrons/drivers/asyncio/communication/__init__.py +2 -0
- opentrons/drivers/asyncio/communication/async_serial.py +4 -0
- opentrons/drivers/asyncio/communication/errors.py +41 -8
- opentrons/drivers/asyncio/communication/serial_connection.py +36 -10
- opentrons/drivers/flex_stacker/__init__.py +9 -3
- opentrons/drivers/flex_stacker/abstract.py +140 -15
- opentrons/drivers/flex_stacker/driver.py +593 -47
- opentrons/drivers/flex_stacker/errors.py +64 -0
- opentrons/drivers/flex_stacker/simulator.py +222 -24
- opentrons/drivers/flex_stacker/types.py +211 -15
- opentrons/drivers/flex_stacker/utils.py +19 -0
- opentrons/execute.py +4 -2
- opentrons/hardware_control/api.py +5 -0
- opentrons/hardware_control/backends/flex_protocol.py +4 -0
- opentrons/hardware_control/backends/ot3controller.py +12 -1
- opentrons/hardware_control/backends/ot3simulator.py +3 -0
- opentrons/hardware_control/backends/subsystem_manager.py +8 -4
- opentrons/hardware_control/instruments/ot2/instrument_calibration.py +10 -6
- opentrons/hardware_control/instruments/ot3/pipette_handler.py +59 -6
- opentrons/hardware_control/modules/__init__.py +12 -1
- opentrons/hardware_control/modules/absorbance_reader.py +11 -9
- opentrons/hardware_control/modules/flex_stacker.py +498 -0
- opentrons/hardware_control/modules/heater_shaker.py +12 -10
- opentrons/hardware_control/modules/magdeck.py +5 -1
- opentrons/hardware_control/modules/tempdeck.py +5 -1
- opentrons/hardware_control/modules/thermocycler.py +15 -14
- opentrons/hardware_control/modules/types.py +191 -1
- opentrons/hardware_control/modules/utils.py +3 -0
- opentrons/hardware_control/motion_utilities.py +20 -0
- opentrons/hardware_control/ot3api.py +145 -15
- opentrons/hardware_control/protocols/liquid_handler.py +47 -1
- opentrons/hardware_control/types.py +6 -0
- opentrons/legacy_commands/commands.py +19 -3
- opentrons/legacy_commands/helpers.py +15 -0
- opentrons/legacy_commands/types.py +3 -2
- opentrons/protocol_api/__init__.py +2 -0
- opentrons/protocol_api/_liquid.py +39 -8
- opentrons/protocol_api/_liquid_properties.py +20 -19
- opentrons/protocol_api/_transfer_liquid_validation.py +91 -0
- opentrons/protocol_api/core/common.py +3 -1
- opentrons/protocol_api/core/engine/deck_conflict.py +11 -1
- opentrons/protocol_api/core/engine/instrument.py +1233 -65
- opentrons/protocol_api/core/engine/labware.py +8 -4
- opentrons/protocol_api/core/engine/load_labware_params.py +68 -10
- opentrons/protocol_api/core/engine/module_core.py +118 -2
- opentrons/protocol_api/core/engine/protocol.py +253 -11
- opentrons/protocol_api/core/engine/stringify.py +19 -8
- opentrons/protocol_api/core/engine/transfer_components_executor.py +853 -0
- opentrons/protocol_api/core/engine/well.py +60 -5
- opentrons/protocol_api/core/instrument.py +65 -19
- opentrons/protocol_api/core/labware.py +6 -2
- opentrons/protocol_api/core/legacy/labware_offset_provider.py +7 -3
- opentrons/protocol_api/core/legacy/legacy_instrument_core.py +69 -21
- opentrons/protocol_api/core/legacy/legacy_labware_core.py +8 -4
- opentrons/protocol_api/core/legacy/legacy_protocol_core.py +36 -0
- opentrons/protocol_api/core/legacy/legacy_well_core.py +25 -1
- opentrons/protocol_api/core/legacy/load_info.py +4 -12
- opentrons/protocol_api/core/legacy/module_geometry.py +6 -1
- opentrons/protocol_api/core/legacy/well_geometry.py +3 -3
- opentrons/protocol_api/core/legacy_simulator/legacy_instrument_core.py +67 -21
- opentrons/protocol_api/core/module.py +43 -0
- opentrons/protocol_api/core/protocol.py +33 -0
- opentrons/protocol_api/core/well.py +21 -1
- opentrons/protocol_api/instrument_context.py +246 -123
- opentrons/protocol_api/labware.py +75 -11
- opentrons/protocol_api/module_contexts.py +140 -0
- opentrons/protocol_api/protocol_context.py +156 -16
- opentrons/protocol_api/validation.py +51 -41
- opentrons/protocol_engine/__init__.py +21 -2
- opentrons/protocol_engine/actions/actions.py +5 -5
- opentrons/protocol_engine/clients/sync_client.py +6 -0
- opentrons/protocol_engine/commands/__init__.py +30 -0
- opentrons/protocol_engine/commands/absorbance_reader/__init__.py +0 -1
- opentrons/protocol_engine/commands/air_gap_in_place.py +3 -2
- opentrons/protocol_engine/commands/aspirate.py +6 -2
- opentrons/protocol_engine/commands/aspirate_in_place.py +3 -1
- opentrons/protocol_engine/commands/aspirate_while_tracking.py +237 -0
- opentrons/protocol_engine/commands/blow_out.py +2 -0
- opentrons/protocol_engine/commands/blow_out_in_place.py +4 -1
- opentrons/protocol_engine/commands/command_unions.py +69 -0
- opentrons/protocol_engine/commands/configure_for_volume.py +3 -0
- opentrons/protocol_engine/commands/dispense.py +3 -1
- opentrons/protocol_engine/commands/dispense_in_place.py +3 -0
- opentrons/protocol_engine/commands/dispense_while_tracking.py +240 -0
- opentrons/protocol_engine/commands/drop_tip.py +23 -1
- opentrons/protocol_engine/commands/evotip_dispense.py +6 -7
- opentrons/protocol_engine/commands/evotip_seal_pipette.py +24 -29
- opentrons/protocol_engine/commands/evotip_unseal_pipette.py +1 -7
- opentrons/protocol_engine/commands/flex_stacker/__init__.py +106 -0
- opentrons/protocol_engine/commands/flex_stacker/close_latch.py +72 -0
- opentrons/protocol_engine/commands/flex_stacker/common.py +15 -0
- opentrons/protocol_engine/commands/flex_stacker/empty.py +161 -0
- opentrons/protocol_engine/commands/flex_stacker/fill.py +164 -0
- opentrons/protocol_engine/commands/flex_stacker/open_latch.py +70 -0
- opentrons/protocol_engine/commands/flex_stacker/prepare_shuttle.py +112 -0
- opentrons/protocol_engine/commands/flex_stacker/retrieve.py +394 -0
- opentrons/protocol_engine/commands/flex_stacker/set_stored_labware.py +190 -0
- opentrons/protocol_engine/commands/flex_stacker/store.py +288 -0
- opentrons/protocol_engine/commands/generate_command_schema.py +31 -2
- opentrons/protocol_engine/commands/labware_handling_common.py +24 -0
- opentrons/protocol_engine/commands/liquid_probe.py +21 -12
- opentrons/protocol_engine/commands/load_labware.py +42 -39
- opentrons/protocol_engine/commands/load_lid.py +21 -13
- opentrons/protocol_engine/commands/load_lid_stack.py +130 -47
- opentrons/protocol_engine/commands/load_module.py +18 -17
- opentrons/protocol_engine/commands/load_pipette.py +3 -0
- opentrons/protocol_engine/commands/move_labware.py +139 -20
- opentrons/protocol_engine/commands/pick_up_tip.py +5 -2
- opentrons/protocol_engine/commands/pipetting_common.py +154 -7
- opentrons/protocol_engine/commands/prepare_to_aspirate.py +17 -2
- opentrons/protocol_engine/commands/reload_labware.py +6 -19
- opentrons/protocol_engine/commands/unsafe/unsafe_blow_out_in_place.py +3 -1
- opentrons/protocol_engine/commands/unsafe/unsafe_drop_tip_in_place.py +6 -1
- opentrons/protocol_engine/errors/__init__.py +8 -0
- opentrons/protocol_engine/errors/exceptions.py +50 -0
- opentrons/protocol_engine/execution/equipment.py +123 -106
- opentrons/protocol_engine/execution/labware_movement.py +8 -6
- opentrons/protocol_engine/execution/pipetting.py +233 -26
- opentrons/protocol_engine/execution/tip_handler.py +14 -5
- opentrons/protocol_engine/labware_offset_standardization.py +173 -0
- opentrons/protocol_engine/protocol_engine.py +22 -13
- opentrons/protocol_engine/resources/deck_configuration_provider.py +94 -2
- opentrons/protocol_engine/resources/deck_data_provider.py +1 -1
- opentrons/protocol_engine/resources/labware_data_provider.py +32 -12
- opentrons/protocol_engine/resources/labware_validation.py +7 -5
- opentrons/protocol_engine/slot_standardization.py +11 -23
- opentrons/protocol_engine/state/addressable_areas.py +84 -46
- opentrons/protocol_engine/state/frustum_helpers.py +26 -10
- opentrons/protocol_engine/state/geometry.py +683 -100
- opentrons/protocol_engine/state/labware.py +252 -55
- opentrons/protocol_engine/state/module_substates/__init__.py +4 -0
- opentrons/protocol_engine/state/module_substates/flex_stacker_substate.py +68 -0
- opentrons/protocol_engine/state/module_substates/heater_shaker_module_substate.py +22 -0
- opentrons/protocol_engine/state/module_substates/temperature_module_substate.py +13 -0
- opentrons/protocol_engine/state/module_substates/thermocycler_module_substate.py +20 -0
- opentrons/protocol_engine/state/modules.py +178 -52
- opentrons/protocol_engine/state/pipettes.py +54 -0
- opentrons/protocol_engine/state/state.py +1 -1
- opentrons/protocol_engine/state/tips.py +14 -0
- opentrons/protocol_engine/state/update_types.py +180 -25
- opentrons/protocol_engine/state/wells.py +54 -8
- opentrons/protocol_engine/types/__init__.py +292 -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 +72 -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 +110 -0
- opentrons/protocol_engine/types/labware_movement.py +22 -0
- opentrons/protocol_engine/types/labware_offset_location.py +108 -0
- opentrons/protocol_engine/types/labware_offset_vector.py +33 -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 +137 -0
- opentrons/protocol_engine/types/location.py +193 -0
- opentrons/protocol_engine/types/module.py +269 -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 +107 -0
- opentrons/protocol_reader/extract_labware_definitions.py +7 -3
- opentrons/protocol_reader/file_format_validator.py +5 -3
- opentrons/protocol_runner/json_translator.py +4 -2
- opentrons/protocol_runner/legacy_command_mapper.py +6 -2
- opentrons/protocol_runner/run_orchestrator.py +4 -1
- opentrons/protocols/advanced_control/transfers/common.py +48 -1
- opentrons/protocols/advanced_control/transfers/transfer_liquid_utils.py +204 -0
- opentrons/protocols/api_support/definitions.py +1 -1
- opentrons/protocols/api_support/instrument.py +16 -3
- opentrons/protocols/labware.py +5 -6
- opentrons/protocols/models/__init__.py +0 -21
- opentrons/simulate.py +4 -2
- opentrons/types.py +15 -6
- {opentrons-8.3.1a1.dist-info → opentrons-8.4.0a1.dist-info}/METADATA +4 -4
- {opentrons-8.3.1a1.dist-info → opentrons-8.4.0a1.dist-info}/RECORD +188 -148
- opentrons/calibration_storage/ot2/models/defaults.py +0 -0
- opentrons/calibration_storage/ot3/models/defaults.py +0 -0
- opentrons/protocol_api/core/legacy/legacy_robot_core.py +0 -0
- opentrons/protocol_engine/types.py +0 -1311
- {opentrons-8.3.1a1.dist-info → opentrons-8.4.0a1.dist-info}/LICENSE +0 -0
- {opentrons-8.3.1a1.dist-info → opentrons-8.4.0a1.dist-info}/WHEEL +0 -0
- {opentrons-8.3.1a1.dist-info → opentrons-8.4.0a1.dist-info}/entry_points.txt +0 -0
- {opentrons-8.3.1a1.dist-info → opentrons-8.4.0a1.dist-info}/top_level.txt +0 -0
|
@@ -16,7 +16,7 @@ from opentrons.util.helpers import utc_now
|
|
|
16
16
|
from .models import v1
|
|
17
17
|
|
|
18
18
|
if typing.TYPE_CHECKING:
|
|
19
|
-
from opentrons_shared_data.labware.types import
|
|
19
|
+
from opentrons_shared_data.labware.types import LabwareDefinition2
|
|
20
20
|
|
|
21
21
|
|
|
22
22
|
log = logging.getLogger(__name__)
|
|
@@ -78,7 +78,7 @@ def tip_lengths_for_pipette(
|
|
|
78
78
|
|
|
79
79
|
|
|
80
80
|
def load_tip_length_calibration(
|
|
81
|
-
pip_id: str, definition: "
|
|
81
|
+
pip_id: str, definition: "LabwareDefinition2"
|
|
82
82
|
) -> v1.TipLengthModel:
|
|
83
83
|
"""
|
|
84
84
|
Function used to grab the current tip length associated
|
|
@@ -127,7 +127,7 @@ def get_all_tip_length_calibrations() -> typing.List[v1.TipLengthCalibration]:
|
|
|
127
127
|
return all_tip_lengths_available
|
|
128
128
|
|
|
129
129
|
|
|
130
|
-
def get_custom_tiprack_definition_for_tlc(labware_uri: str) -> "
|
|
130
|
+
def get_custom_tiprack_definition_for_tlc(labware_uri: str) -> "LabwareDefinition2":
|
|
131
131
|
"""
|
|
132
132
|
Return the custom tiprack definition saved in the custom tiprack directory
|
|
133
133
|
during tip length calibration
|
|
@@ -137,7 +137,7 @@ def get_custom_tiprack_definition_for_tlc(labware_uri: str) -> "LabwareDefinitio
|
|
|
137
137
|
try:
|
|
138
138
|
with open(custom_tiprack_path, "rb") as f:
|
|
139
139
|
return typing.cast(
|
|
140
|
-
"
|
|
140
|
+
"LabwareDefinition2",
|
|
141
141
|
json.loads(f.read().decode("utf-8")),
|
|
142
142
|
)
|
|
143
143
|
except FileNotFoundError:
|
|
@@ -213,7 +213,7 @@ def clear_tip_length_calibration() -> None:
|
|
|
213
213
|
|
|
214
214
|
|
|
215
215
|
def create_tip_length_data(
|
|
216
|
-
definition: "
|
|
216
|
+
definition: "LabwareDefinition2",
|
|
217
217
|
length: float,
|
|
218
218
|
cal_status: typing.Optional[
|
|
219
219
|
typing.Union[local_types.CalibrationStatus, v1.CalibrationStatus]
|
|
@@ -251,7 +251,7 @@ def create_tip_length_data(
|
|
|
251
251
|
|
|
252
252
|
def _save_custom_tiprack_definition(
|
|
253
253
|
labware_uri: str,
|
|
254
|
-
definition: "
|
|
254
|
+
definition: "LabwareDefinition2",
|
|
255
255
|
) -> None:
|
|
256
256
|
namespace, load_name, version = labware_uri.split("/")
|
|
257
257
|
custom_tr_dir_path = config.get_custom_tiprack_def_path()
|
|
@@ -222,17 +222,6 @@ settings = [
|
|
|
222
222
|
robot_type=[RobotTypeEnum.OT2, RobotTypeEnum.FLEX],
|
|
223
223
|
internal_only=True,
|
|
224
224
|
),
|
|
225
|
-
SettingDefinition(
|
|
226
|
-
_id="allowLiquidClasses",
|
|
227
|
-
title="Allow the use of liquid classes",
|
|
228
|
-
description=(
|
|
229
|
-
"Do not enable."
|
|
230
|
-
" This is an Opentrons internal setting to allow using in-development"
|
|
231
|
-
" liquid classes."
|
|
232
|
-
),
|
|
233
|
-
robot_type=[RobotTypeEnum.OT2, RobotTypeEnum.FLEX],
|
|
234
|
-
internal_only=True,
|
|
235
|
-
),
|
|
236
225
|
]
|
|
237
226
|
|
|
238
227
|
|
|
@@ -736,6 +725,14 @@ def _migrate35to36(previous: SettingsMap) -> SettingsMap:
|
|
|
736
725
|
return newmap
|
|
737
726
|
|
|
738
727
|
|
|
728
|
+
def _migrate36to37(previous: SettingsMap) -> SettingsMap:
|
|
729
|
+
"""Migrate to version 37 of the feature flags file.
|
|
730
|
+
|
|
731
|
+
- Removes the allowLiquidClasses flag.
|
|
732
|
+
"""
|
|
733
|
+
return {k: v for k, v in previous.items() if "allowLiquidClasses" != k}
|
|
734
|
+
|
|
735
|
+
|
|
739
736
|
_MIGRATIONS = [
|
|
740
737
|
_migrate0to1,
|
|
741
738
|
_migrate1to2,
|
|
@@ -773,6 +770,7 @@ _MIGRATIONS = [
|
|
|
773
770
|
_migrate33to34,
|
|
774
771
|
_migrate34to35,
|
|
775
772
|
_migrate35to36,
|
|
773
|
+
_migrate36to37,
|
|
776
774
|
]
|
|
777
775
|
"""
|
|
778
776
|
List of all migrations to apply, indexed by (version - 1). See _migrate below
|
|
@@ -78,7 +78,3 @@ def enable_performance_metrics(robot_type: RobotTypeEnum) -> bool:
|
|
|
78
78
|
|
|
79
79
|
def oem_mode_enabled() -> bool:
|
|
80
80
|
return advs.get_setting_with_env_overload("enableOEMMode", RobotTypeEnum.FLEX)
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
def allow_liquid_classes(robot_type: RobotTypeEnum) -> bool:
|
|
84
|
-
return advs.get_setting_with_env_overload("allowLiquidClasses", robot_type)
|
opentrons/config/reset.py
CHANGED
|
@@ -90,8 +90,13 @@ _settings_reset_options = {
|
|
|
90
90
|
# This option is defined here only as a convenience for robot-server.
|
|
91
91
|
# Find a way to split things up and define this in robot-server instead.
|
|
92
92
|
ResetOptionId.runs_history: CommonResetOption(
|
|
93
|
-
name="Clear
|
|
94
|
-
description=
|
|
93
|
+
name="Clear Robot Server Data",
|
|
94
|
+
description=(
|
|
95
|
+
"Erase everything stored by the robot server. This is *not* everything stored"
|
|
96
|
+
" on the robot. It currently includes runs, protocols, labware offsets, and more,"
|
|
97
|
+
" and the exact list may change over time. This is exposed for troubleshooting"
|
|
98
|
+
" and system recovery. The name `runsHistory` is a misnomer, for historical reasons."
|
|
99
|
+
),
|
|
95
100
|
),
|
|
96
101
|
ResetOptionId.on_device_display: CommonResetOption(
|
|
97
102
|
name="On-Device Display Configuration",
|
|
@@ -5,6 +5,7 @@ from opentrons.drivers.asyncio.communication.errors import (
|
|
|
5
5
|
AlarmResponse,
|
|
6
6
|
ErrorResponse,
|
|
7
7
|
UnhandledGcode,
|
|
8
|
+
DefaultErrorCodes,
|
|
8
9
|
)
|
|
9
10
|
from .async_serial import AsyncSerial
|
|
10
11
|
|
|
@@ -17,4 +18,5 @@ __all__ = [
|
|
|
17
18
|
"AlarmResponse",
|
|
18
19
|
"ErrorResponse",
|
|
19
20
|
"UnhandledGcode",
|
|
21
|
+
"DefaultErrorCodes",
|
|
20
22
|
]
|
|
@@ -155,6 +155,10 @@ class AsyncSerial:
|
|
|
155
155
|
"""Reset the input buffer"""
|
|
156
156
|
self._serial.reset_input_buffer()
|
|
157
157
|
|
|
158
|
+
def reset_output_buffer(self) -> None:
|
|
159
|
+
"""Reset the output buffer"""
|
|
160
|
+
self._serial.reset_output_buffer()
|
|
161
|
+
|
|
158
162
|
@contextlib.asynccontextmanager
|
|
159
163
|
async def timeout_override(
|
|
160
164
|
self, timeout_property: TimeoutProperties, timeout: Optional[float]
|
|
@@ -1,11 +1,7 @@
|
|
|
1
1
|
"""Errors raised by serial connection."""
|
|
2
2
|
|
|
3
|
-
|
|
4
3
|
from enum import Enum
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
class ErrorCodes(Enum):
|
|
8
|
-
UNHANDLED_GCODE = "ERR003"
|
|
4
|
+
from typing import Dict, Type, Optional
|
|
9
5
|
|
|
10
6
|
|
|
11
7
|
class SerialException(Exception):
|
|
@@ -36,10 +32,47 @@ class AlarmResponse(FailedCommand):
|
|
|
36
32
|
|
|
37
33
|
|
|
38
34
|
class ErrorResponse(FailedCommand):
|
|
39
|
-
|
|
35
|
+
def __init__(self, port: str, response: str, command: Optional[str] = None) -> None:
|
|
36
|
+
super().__init__(port, response)
|
|
37
|
+
self.command = command
|
|
40
38
|
|
|
41
39
|
|
|
42
40
|
class UnhandledGcode(ErrorResponse):
|
|
43
41
|
def __init__(self, port: str, response: str, command: str) -> None:
|
|
44
|
-
|
|
45
|
-
|
|
42
|
+
super().__init__(port, response, command)
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
class BaseErrorCode(Enum):
|
|
46
|
+
"""Base class for error code enums.
|
|
47
|
+
|
|
48
|
+
This class should be inherited to define specific sets of error codes.
|
|
49
|
+
"""
|
|
50
|
+
|
|
51
|
+
@property
|
|
52
|
+
def code_string(self) -> str:
|
|
53
|
+
"""Return the error code string."""
|
|
54
|
+
code: str = self.value[0]
|
|
55
|
+
return code.lower()
|
|
56
|
+
|
|
57
|
+
@property
|
|
58
|
+
def exception(self) -> Type[ErrorResponse]:
|
|
59
|
+
"""Return the exception class associated with this error code."""
|
|
60
|
+
exc: Type[ErrorResponse] = self.value[1]
|
|
61
|
+
return exc
|
|
62
|
+
|
|
63
|
+
def raise_exception(self, port: str, response: str, command: str) -> None:
|
|
64
|
+
"""Raise the appropriate exception for this error code."""
|
|
65
|
+
raise self.exception(port=port, response=response, command=command)
|
|
66
|
+
|
|
67
|
+
@classmethod
|
|
68
|
+
def get_error_codes(cls) -> Dict[str, "BaseErrorCode"]:
|
|
69
|
+
"""Get all error codes as a dictionary mapping code string to ErrorCode instance."""
|
|
70
|
+
return {code.code_string: code for code in cls}
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
class DefaultErrorCodes(BaseErrorCode):
|
|
74
|
+
"""
|
|
75
|
+
Default error codes that are previously handled by the SerialConnection class.
|
|
76
|
+
"""
|
|
77
|
+
|
|
78
|
+
UNHANDLED_GCODE = ("ERR003", UnhandledGcode)
|
|
@@ -2,11 +2,17 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
import asyncio
|
|
4
4
|
import logging
|
|
5
|
-
from typing import Optional, List
|
|
5
|
+
from typing import Optional, List, Type
|
|
6
6
|
|
|
7
7
|
from opentrons.drivers.command_builder import CommandBuilder
|
|
8
8
|
|
|
9
|
-
from .errors import
|
|
9
|
+
from .errors import (
|
|
10
|
+
NoResponse,
|
|
11
|
+
AlarmResponse,
|
|
12
|
+
ErrorResponse,
|
|
13
|
+
BaseErrorCode,
|
|
14
|
+
DefaultErrorCodes,
|
|
15
|
+
)
|
|
10
16
|
from .async_serial import AsyncSerial
|
|
11
17
|
|
|
12
18
|
log = logging.getLogger(__name__)
|
|
@@ -43,7 +49,8 @@ class SerialConnection:
|
|
|
43
49
|
error_keyword: Optional[str] = None,
|
|
44
50
|
alarm_keyword: Optional[str] = None,
|
|
45
51
|
reset_buffer_before_write: bool = False,
|
|
46
|
-
|
|
52
|
+
error_codes: Type[BaseErrorCode] = DefaultErrorCodes,
|
|
53
|
+
) -> "SerialConnection":
|
|
47
54
|
"""
|
|
48
55
|
Create a connection.
|
|
49
56
|
|
|
@@ -63,6 +70,8 @@ class SerialConnection:
|
|
|
63
70
|
(default: alarm)
|
|
64
71
|
reset_buffer_before_write: whether to reset the read buffer before
|
|
65
72
|
every write
|
|
73
|
+
error_codes: Enum class for error codes
|
|
74
|
+
(default: DefaultErrorCodes)
|
|
66
75
|
|
|
67
76
|
Returns: SerialConnection
|
|
68
77
|
"""
|
|
@@ -82,6 +91,7 @@ class SerialConnection:
|
|
|
82
91
|
retry_wait_time_seconds=retry_wait_time_seconds,
|
|
83
92
|
error_keyword=error_keyword or "error",
|
|
84
93
|
alarm_keyword=alarm_keyword or "alarm",
|
|
94
|
+
error_codes=error_codes,
|
|
85
95
|
)
|
|
86
96
|
|
|
87
97
|
def __init__(
|
|
@@ -93,6 +103,7 @@ class SerialConnection:
|
|
|
93
103
|
retry_wait_time_seconds: float,
|
|
94
104
|
error_keyword: str,
|
|
95
105
|
alarm_keyword: str,
|
|
106
|
+
error_codes: Type[BaseErrorCode] = DefaultErrorCodes,
|
|
96
107
|
) -> None:
|
|
97
108
|
"""
|
|
98
109
|
Constructor
|
|
@@ -107,6 +118,7 @@ class SerialConnection:
|
|
|
107
118
|
exception when detected
|
|
108
119
|
alarm_keyword: string that will cause an AlarmResponse
|
|
109
120
|
exception when detected
|
|
121
|
+
error_codes: Enum class for error codes
|
|
110
122
|
"""
|
|
111
123
|
self._serial = serial
|
|
112
124
|
self._port = port
|
|
@@ -116,6 +128,7 @@ class SerialConnection:
|
|
|
116
128
|
self._send_data_lock = asyncio.Lock()
|
|
117
129
|
self._error_keyword = error_keyword.lower()
|
|
118
130
|
self._alarm_keyword = alarm_keyword.lower()
|
|
131
|
+
self._error_codes = error_codes
|
|
119
132
|
|
|
120
133
|
async def send_command(
|
|
121
134
|
self, command: CommandBuilder, retries: int = 0, timeout: Optional[float] = None
|
|
@@ -237,8 +250,8 @@ class SerialConnection:
|
|
|
237
250
|
Raise an error if the response contains an error
|
|
238
251
|
|
|
239
252
|
Args:
|
|
240
|
-
gcode: the requesting gocde
|
|
241
253
|
response: response
|
|
254
|
+
request: the requesting command
|
|
242
255
|
|
|
243
256
|
Returns: None
|
|
244
257
|
|
|
@@ -250,12 +263,16 @@ class SerialConnection:
|
|
|
250
263
|
raise AlarmResponse(port=self._port, response=response)
|
|
251
264
|
|
|
252
265
|
if self._error_keyword.lower() in lower:
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
266
|
+
# Check for specific error codes
|
|
267
|
+
error_codes_dict = self._error_codes.get_error_codes()
|
|
268
|
+
for code, error_code in error_codes_dict.items():
|
|
269
|
+
if code in lower:
|
|
270
|
+
error_code.raise_exception(
|
|
271
|
+
port=self._port, response=response, command=request
|
|
272
|
+
)
|
|
273
|
+
|
|
274
|
+
# If no specific error code was found, raise a generic ErrorResponse
|
|
275
|
+
raise ErrorResponse(port=self._port, response=response)
|
|
259
276
|
|
|
260
277
|
async def on_retry(self) -> None:
|
|
261
278
|
"""
|
|
@@ -297,6 +314,7 @@ class AsyncResponseSerialConnection(SerialConnection):
|
|
|
297
314
|
error_keyword: Optional[str] = None,
|
|
298
315
|
alarm_keyword: Optional[str] = None,
|
|
299
316
|
reset_buffer_before_write: bool = False,
|
|
317
|
+
error_codes: Type[BaseErrorCode] = DefaultErrorCodes,
|
|
300
318
|
async_error_ack: Optional[str] = None,
|
|
301
319
|
number_of_retries: int = 0,
|
|
302
320
|
) -> AsyncResponseSerialConnection:
|
|
@@ -321,6 +339,9 @@ class AsyncResponseSerialConnection(SerialConnection):
|
|
|
321
339
|
every write
|
|
322
340
|
async_error_ack: optional string that will indicate an asynchronous
|
|
323
341
|
error when detected (default: async)
|
|
342
|
+
number_of_retries: default number of retries
|
|
343
|
+
error_codes: Enum class for error codes
|
|
344
|
+
(default: DefaultErrorCodes)
|
|
324
345
|
|
|
325
346
|
Returns: AsyncResponseSerialConnection
|
|
326
347
|
"""
|
|
@@ -342,6 +363,7 @@ class AsyncResponseSerialConnection(SerialConnection):
|
|
|
342
363
|
alarm_keyword=alarm_keyword or "alarm",
|
|
343
364
|
async_error_ack=async_error_ack or "async",
|
|
344
365
|
number_of_retries=number_of_retries,
|
|
366
|
+
error_codes=error_codes,
|
|
345
367
|
)
|
|
346
368
|
|
|
347
369
|
def __init__(
|
|
@@ -355,6 +377,7 @@ class AsyncResponseSerialConnection(SerialConnection):
|
|
|
355
377
|
alarm_keyword: str,
|
|
356
378
|
async_error_ack: str,
|
|
357
379
|
number_of_retries: int = 0,
|
|
380
|
+
error_codes: Type[BaseErrorCode] = DefaultErrorCodes,
|
|
358
381
|
) -> None:
|
|
359
382
|
"""
|
|
360
383
|
Constructor
|
|
@@ -371,6 +394,8 @@ class AsyncResponseSerialConnection(SerialConnection):
|
|
|
371
394
|
exception when detected
|
|
372
395
|
async_error_ack: string that will indicate an asynchronous
|
|
373
396
|
error when detected
|
|
397
|
+
number_of_retries: default number of retries
|
|
398
|
+
error_codes: Enum class for error codes
|
|
374
399
|
"""
|
|
375
400
|
super().__init__(
|
|
376
401
|
serial=serial,
|
|
@@ -380,6 +405,7 @@ class AsyncResponseSerialConnection(SerialConnection):
|
|
|
380
405
|
retry_wait_time_seconds=retry_wait_time_seconds,
|
|
381
406
|
error_keyword=error_keyword,
|
|
382
407
|
alarm_keyword=alarm_keyword,
|
|
408
|
+
error_codes=error_codes,
|
|
383
409
|
)
|
|
384
410
|
self._serial = serial
|
|
385
411
|
self._port = port
|
|
@@ -1,9 +1,15 @@
|
|
|
1
|
-
from .abstract import
|
|
2
|
-
from .driver import FlexStackerDriver
|
|
1
|
+
from .abstract import AbstractFlexStackerDriver
|
|
2
|
+
from .driver import FlexStackerDriver, STACKER_MOTION_CONFIG, STALLGUARD_CONFIG
|
|
3
3
|
from .simulator import SimulatingDriver
|
|
4
|
+
from . import types as FlexStackerTypes
|
|
5
|
+
from . import utils as FlexStackerUtils
|
|
4
6
|
|
|
5
7
|
__all__ = [
|
|
6
|
-
"
|
|
8
|
+
"AbstractFlexStackerDriver",
|
|
7
9
|
"FlexStackerDriver",
|
|
8
10
|
"SimulatingDriver",
|
|
11
|
+
"FlexStackerTypes",
|
|
12
|
+
"FlexStackerUtils",
|
|
13
|
+
"STACKER_MOTION_CONFIG",
|
|
14
|
+
"STALLGUARD_CONFIG",
|
|
9
15
|
]
|
|
@@ -1,16 +1,28 @@
|
|
|
1
|
-
from typing import Protocol
|
|
1
|
+
from typing import List, Optional, Protocol
|
|
2
2
|
|
|
3
3
|
from .types import (
|
|
4
|
+
ActiveRange,
|
|
5
|
+
LEDPattern,
|
|
6
|
+
LimitSwitchStatus,
|
|
7
|
+
MeasurementKind,
|
|
8
|
+
MoveResult,
|
|
9
|
+
SpadMapID,
|
|
4
10
|
StackerAxis,
|
|
5
11
|
PlatformStatus,
|
|
6
12
|
Direction,
|
|
7
13
|
MoveParams,
|
|
8
14
|
StackerInfo,
|
|
9
15
|
LEDColor,
|
|
16
|
+
StallGuardParams,
|
|
17
|
+
TOFConfiguration,
|
|
18
|
+
TOFMeasurement,
|
|
19
|
+
TOFMeasurementResult,
|
|
20
|
+
TOFSensor,
|
|
21
|
+
TOFSensorStatus,
|
|
10
22
|
)
|
|
11
23
|
|
|
12
24
|
|
|
13
|
-
class
|
|
25
|
+
class AbstractFlexStackerDriver(Protocol):
|
|
14
26
|
"""Protocol for the Stacker driver."""
|
|
15
27
|
|
|
16
28
|
async def connect(self) -> None:
|
|
@@ -25,22 +37,110 @@ class AbstractStackerDriver(Protocol):
|
|
|
25
37
|
"""Check connection to stacker."""
|
|
26
38
|
...
|
|
27
39
|
|
|
28
|
-
async def update_firmware(self, firmware_file_path: str) -> None:
|
|
29
|
-
"""Updates the firmware on the device."""
|
|
30
|
-
...
|
|
31
|
-
|
|
32
40
|
async def get_device_info(self) -> StackerInfo:
|
|
33
41
|
"""Get Device Info."""
|
|
34
42
|
...
|
|
35
43
|
|
|
36
|
-
async def set_serial_number(self, sn: str) ->
|
|
44
|
+
async def set_serial_number(self, sn: str) -> None:
|
|
37
45
|
"""Set Serial Number."""
|
|
38
46
|
...
|
|
39
47
|
|
|
40
|
-
async def
|
|
48
|
+
async def enable_motors(self, axis: List[StackerAxis]) -> None:
|
|
49
|
+
"""Enables the axis motor if present, disables it otherwise."""
|
|
50
|
+
...
|
|
51
|
+
|
|
52
|
+
async def stop_motors(self) -> None:
|
|
41
53
|
"""Stop all motor movement."""
|
|
42
54
|
...
|
|
43
55
|
|
|
56
|
+
async def set_run_current(self, axis: StackerAxis, current: float) -> None:
|
|
57
|
+
"""Set axis peak run current in amps."""
|
|
58
|
+
...
|
|
59
|
+
|
|
60
|
+
async def set_ihold_current(self, axis: StackerAxis, current: float) -> None:
|
|
61
|
+
"""Set axis hold current in amps."""
|
|
62
|
+
...
|
|
63
|
+
|
|
64
|
+
async def set_stallguard_threshold(
|
|
65
|
+
self, axis: StackerAxis, enable: bool, threshold: int
|
|
66
|
+
) -> None:
|
|
67
|
+
"""Enables and sets the stallguard threshold for the given axis motor."""
|
|
68
|
+
...
|
|
69
|
+
|
|
70
|
+
async def enable_tof_sensor(self, sensor: TOFSensor, enable: bool) -> None:
|
|
71
|
+
"""Enable or disable the TOF sensor."""
|
|
72
|
+
...
|
|
73
|
+
|
|
74
|
+
async def manage_tof_measurement(
|
|
75
|
+
self,
|
|
76
|
+
sensor: TOFSensor,
|
|
77
|
+
kind: MeasurementKind = MeasurementKind.HISTOGRAM,
|
|
78
|
+
start: bool = True,
|
|
79
|
+
) -> TOFMeasurement:
|
|
80
|
+
"""Start or stop Measurements from the TOF sensor."""
|
|
81
|
+
...
|
|
82
|
+
|
|
83
|
+
async def get_tof_histogram(self, sensor: TOFSensor) -> TOFMeasurementResult:
|
|
84
|
+
"""Get the full histogram measurement from the TOF sensor."""
|
|
85
|
+
...
|
|
86
|
+
|
|
87
|
+
async def set_tof_configuration(
|
|
88
|
+
self,
|
|
89
|
+
sensor: TOFSensor,
|
|
90
|
+
spad_map_id: SpadMapID,
|
|
91
|
+
active_range: Optional[ActiveRange] = None,
|
|
92
|
+
kilo_iterations: Optional[int] = None,
|
|
93
|
+
report_period_ms: Optional[int] = None,
|
|
94
|
+
histogram_dump: Optional[bool] = None,
|
|
95
|
+
) -> None:
|
|
96
|
+
"""Set the configuration of the TOF sensor.
|
|
97
|
+
|
|
98
|
+
:param sensor: The TOF sensor to configure.
|
|
99
|
+
:param spad_map_id: The pre-defined SPAD map which sets the fov and focus area (14 default).
|
|
100
|
+
:active_range: The operating mode Short-range high-accuracy (default) or long range.
|
|
101
|
+
:kilo_iterations: The Measurement iterations times 1024 (4000 default).
|
|
102
|
+
:report_period_ms: The reporting period before each measurement (500 default).
|
|
103
|
+
:histogram_dump: Enables/Disables histogram measurements (True default).
|
|
104
|
+
:return: None
|
|
105
|
+
"""
|
|
106
|
+
...
|
|
107
|
+
|
|
108
|
+
async def get_tof_configuration(self, sensor: TOFSensor) -> TOFConfiguration:
|
|
109
|
+
"""Get the configuration of the TOF sensor."""
|
|
110
|
+
...
|
|
111
|
+
|
|
112
|
+
async def set_motor_driver_register(
|
|
113
|
+
self, axis: StackerAxis, reg: int, value: int
|
|
114
|
+
) -> None:
|
|
115
|
+
"""Set the register of the given motor axis driver to the given value."""
|
|
116
|
+
...
|
|
117
|
+
|
|
118
|
+
async def get_motor_driver_register(self, axis: StackerAxis, reg: int) -> int:
|
|
119
|
+
"""Gets the register value of the given motor axis driver."""
|
|
120
|
+
...
|
|
121
|
+
|
|
122
|
+
async def set_tof_driver_register(
|
|
123
|
+
self, sensor: TOFSensor, reg: int, value: int
|
|
124
|
+
) -> None:
|
|
125
|
+
"""Set the register of the given tof sensor driver to the given value."""
|
|
126
|
+
...
|
|
127
|
+
|
|
128
|
+
async def get_tof_driver_register(self, sensor: TOFSensor, reg: int) -> int:
|
|
129
|
+
"""Gets the register value of the given tof sensor driver."""
|
|
130
|
+
...
|
|
131
|
+
|
|
132
|
+
async def get_tof_sensor_status(self, sensor: TOFSensor) -> TOFSensorStatus:
|
|
133
|
+
"""Get the status of the tof sensor."""
|
|
134
|
+
...
|
|
135
|
+
|
|
136
|
+
async def get_motion_params(self, axis: StackerAxis) -> MoveParams:
|
|
137
|
+
"""Get the motion parameters used by the given axis motor."""
|
|
138
|
+
...
|
|
139
|
+
|
|
140
|
+
async def get_stallguard_threshold(self, axis: StackerAxis) -> StallGuardParams:
|
|
141
|
+
"""Get the stallguard parameters by the given axis motor."""
|
|
142
|
+
...
|
|
143
|
+
|
|
44
144
|
async def get_limit_switch(self, axis: StackerAxis, direction: Direction) -> bool:
|
|
45
145
|
"""Get limit switch status.
|
|
46
146
|
|
|
@@ -48,6 +148,10 @@ class AbstractStackerDriver(Protocol):
|
|
|
48
148
|
"""
|
|
49
149
|
...
|
|
50
150
|
|
|
151
|
+
async def get_limit_switches_status(self) -> LimitSwitchStatus:
|
|
152
|
+
"""Get limit switch statuses for all axes."""
|
|
153
|
+
...
|
|
154
|
+
|
|
51
155
|
async def get_platform_sensor(self, direction: Direction) -> bool:
|
|
52
156
|
"""Get platform sensor status.
|
|
53
157
|
|
|
@@ -66,24 +170,45 @@ class AbstractStackerDriver(Protocol):
|
|
|
66
170
|
"""
|
|
67
171
|
...
|
|
68
172
|
|
|
173
|
+
async def get_installation_detected(self) -> bool:
|
|
174
|
+
"""Get whether or not installation is detected.
|
|
175
|
+
|
|
176
|
+
:return: True if installation is detected, False otherwise
|
|
177
|
+
"""
|
|
178
|
+
...
|
|
179
|
+
|
|
69
180
|
async def move_in_mm(
|
|
70
181
|
self, axis: StackerAxis, distance: float, params: MoveParams | None = None
|
|
71
|
-
) ->
|
|
72
|
-
"""Move axis."""
|
|
182
|
+
) -> MoveResult:
|
|
183
|
+
"""Move axis by the given distance in mm."""
|
|
73
184
|
...
|
|
74
185
|
|
|
75
186
|
async def move_to_limit_switch(
|
|
76
187
|
self, axis: StackerAxis, direction: Direction, params: MoveParams | None = None
|
|
77
|
-
) ->
|
|
188
|
+
) -> MoveResult:
|
|
78
189
|
"""Move until limit switch is triggered."""
|
|
79
190
|
...
|
|
80
191
|
|
|
81
|
-
async def home_axis(self, axis: StackerAxis, direction: Direction) ->
|
|
192
|
+
async def home_axis(self, axis: StackerAxis, direction: Direction) -> MoveResult:
|
|
82
193
|
"""Home axis."""
|
|
83
194
|
...
|
|
84
195
|
|
|
85
196
|
async def set_led(
|
|
86
|
-
self,
|
|
87
|
-
|
|
88
|
-
|
|
197
|
+
self,
|
|
198
|
+
power: float,
|
|
199
|
+
color: Optional[LEDColor] = None,
|
|
200
|
+
external: Optional[bool] = None,
|
|
201
|
+
pattern: Optional[LEDPattern] = None,
|
|
202
|
+
duration: Optional[int] = None,
|
|
203
|
+
reps: Optional[int] = None,
|
|
204
|
+
) -> None:
|
|
205
|
+
"""Set LED Status bar color and pattern."""
|
|
206
|
+
...
|
|
207
|
+
|
|
208
|
+
async def enter_programming_mode(self) -> None:
|
|
209
|
+
"""Reboot into programming mode"""
|
|
210
|
+
...
|
|
211
|
+
|
|
212
|
+
def reset_serial_buffers(self) -> None:
|
|
213
|
+
"""Reset the input and output serial buffers."""
|
|
89
214
|
...
|