opentrons 8.3.2__py2.py3-none-any.whl → 8.4.0__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.

Potentially problematic release.


This version of opentrons might be problematic. Click here for more details.

Files changed (196) hide show
  1. opentrons/calibration_storage/ot2/mark_bad_calibration.py +2 -0
  2. opentrons/calibration_storage/ot2/tip_length.py +6 -6
  3. opentrons/config/advanced_settings.py +9 -11
  4. opentrons/config/feature_flags.py +0 -4
  5. opentrons/config/reset.py +7 -2
  6. opentrons/drivers/asyncio/communication/__init__.py +2 -0
  7. opentrons/drivers/asyncio/communication/async_serial.py +4 -0
  8. opentrons/drivers/asyncio/communication/errors.py +41 -8
  9. opentrons/drivers/asyncio/communication/serial_connection.py +36 -10
  10. opentrons/drivers/flex_stacker/__init__.py +9 -3
  11. opentrons/drivers/flex_stacker/abstract.py +140 -15
  12. opentrons/drivers/flex_stacker/driver.py +593 -47
  13. opentrons/drivers/flex_stacker/errors.py +64 -0
  14. opentrons/drivers/flex_stacker/simulator.py +222 -24
  15. opentrons/drivers/flex_stacker/types.py +211 -15
  16. opentrons/drivers/flex_stacker/utils.py +19 -0
  17. opentrons/execute.py +4 -2
  18. opentrons/hardware_control/api.py +5 -0
  19. opentrons/hardware_control/backends/flex_protocol.py +4 -0
  20. opentrons/hardware_control/backends/ot3controller.py +12 -1
  21. opentrons/hardware_control/backends/ot3simulator.py +3 -0
  22. opentrons/hardware_control/backends/subsystem_manager.py +8 -4
  23. opentrons/hardware_control/instruments/ot2/instrument_calibration.py +10 -6
  24. opentrons/hardware_control/instruments/ot3/pipette_handler.py +59 -6
  25. opentrons/hardware_control/modules/__init__.py +12 -1
  26. opentrons/hardware_control/modules/absorbance_reader.py +11 -9
  27. opentrons/hardware_control/modules/flex_stacker.py +498 -0
  28. opentrons/hardware_control/modules/heater_shaker.py +12 -10
  29. opentrons/hardware_control/modules/magdeck.py +5 -1
  30. opentrons/hardware_control/modules/tempdeck.py +5 -1
  31. opentrons/hardware_control/modules/thermocycler.py +15 -14
  32. opentrons/hardware_control/modules/types.py +191 -1
  33. opentrons/hardware_control/modules/utils.py +3 -0
  34. opentrons/hardware_control/motion_utilities.py +20 -0
  35. opentrons/hardware_control/ot3api.py +145 -15
  36. opentrons/hardware_control/protocols/liquid_handler.py +47 -1
  37. opentrons/hardware_control/types.py +6 -0
  38. opentrons/legacy_commands/commands.py +102 -5
  39. opentrons/legacy_commands/helpers.py +74 -1
  40. opentrons/legacy_commands/types.py +33 -2
  41. opentrons/protocol_api/__init__.py +2 -0
  42. opentrons/protocol_api/_liquid.py +39 -8
  43. opentrons/protocol_api/_liquid_properties.py +20 -19
  44. opentrons/protocol_api/_transfer_liquid_validation.py +91 -0
  45. opentrons/protocol_api/core/common.py +3 -1
  46. opentrons/protocol_api/core/engine/deck_conflict.py +11 -1
  47. opentrons/protocol_api/core/engine/instrument.py +1356 -107
  48. opentrons/protocol_api/core/engine/labware.py +8 -4
  49. opentrons/protocol_api/core/engine/load_labware_params.py +68 -10
  50. opentrons/protocol_api/core/engine/module_core.py +118 -2
  51. opentrons/protocol_api/core/engine/pipette_movement_conflict.py +6 -14
  52. opentrons/protocol_api/core/engine/protocol.py +253 -11
  53. opentrons/protocol_api/core/engine/stringify.py +19 -8
  54. opentrons/protocol_api/core/engine/transfer_components_executor.py +858 -0
  55. opentrons/protocol_api/core/engine/well.py +73 -5
  56. opentrons/protocol_api/core/instrument.py +71 -21
  57. opentrons/protocol_api/core/labware.py +6 -2
  58. opentrons/protocol_api/core/legacy/labware_offset_provider.py +7 -3
  59. opentrons/protocol_api/core/legacy/legacy_instrument_core.py +76 -49
  60. opentrons/protocol_api/core/legacy/legacy_labware_core.py +8 -4
  61. opentrons/protocol_api/core/legacy/legacy_protocol_core.py +36 -0
  62. opentrons/protocol_api/core/legacy/legacy_well_core.py +27 -2
  63. opentrons/protocol_api/core/legacy/load_info.py +4 -12
  64. opentrons/protocol_api/core/legacy/module_geometry.py +6 -1
  65. opentrons/protocol_api/core/legacy/well_geometry.py +3 -3
  66. opentrons/protocol_api/core/legacy_simulator/legacy_instrument_core.py +73 -23
  67. opentrons/protocol_api/core/module.py +43 -0
  68. opentrons/protocol_api/core/protocol.py +33 -0
  69. opentrons/protocol_api/core/well.py +23 -2
  70. opentrons/protocol_api/instrument_context.py +454 -150
  71. opentrons/protocol_api/labware.py +98 -50
  72. opentrons/protocol_api/module_contexts.py +140 -0
  73. opentrons/protocol_api/protocol_context.py +163 -19
  74. opentrons/protocol_api/validation.py +51 -41
  75. opentrons/protocol_engine/__init__.py +21 -2
  76. opentrons/protocol_engine/actions/actions.py +5 -5
  77. opentrons/protocol_engine/clients/sync_client.py +6 -0
  78. opentrons/protocol_engine/commands/__init__.py +66 -36
  79. opentrons/protocol_engine/commands/absorbance_reader/__init__.py +0 -1
  80. opentrons/protocol_engine/commands/air_gap_in_place.py +3 -2
  81. opentrons/protocol_engine/commands/aspirate.py +6 -2
  82. opentrons/protocol_engine/commands/aspirate_in_place.py +3 -1
  83. opentrons/protocol_engine/commands/aspirate_while_tracking.py +210 -0
  84. opentrons/protocol_engine/commands/blow_out.py +2 -0
  85. opentrons/protocol_engine/commands/blow_out_in_place.py +4 -1
  86. opentrons/protocol_engine/commands/command_unions.py +102 -33
  87. opentrons/protocol_engine/commands/configure_for_volume.py +3 -0
  88. opentrons/protocol_engine/commands/dispense.py +3 -1
  89. opentrons/protocol_engine/commands/dispense_in_place.py +3 -0
  90. opentrons/protocol_engine/commands/dispense_while_tracking.py +204 -0
  91. opentrons/protocol_engine/commands/drop_tip.py +23 -1
  92. opentrons/protocol_engine/commands/flex_stacker/__init__.py +106 -0
  93. opentrons/protocol_engine/commands/flex_stacker/close_latch.py +72 -0
  94. opentrons/protocol_engine/commands/flex_stacker/common.py +15 -0
  95. opentrons/protocol_engine/commands/flex_stacker/empty.py +161 -0
  96. opentrons/protocol_engine/commands/flex_stacker/fill.py +164 -0
  97. opentrons/protocol_engine/commands/flex_stacker/open_latch.py +70 -0
  98. opentrons/protocol_engine/commands/flex_stacker/prepare_shuttle.py +112 -0
  99. opentrons/protocol_engine/commands/flex_stacker/retrieve.py +394 -0
  100. opentrons/protocol_engine/commands/flex_stacker/set_stored_labware.py +190 -0
  101. opentrons/protocol_engine/commands/flex_stacker/store.py +291 -0
  102. opentrons/protocol_engine/commands/generate_command_schema.py +31 -2
  103. opentrons/protocol_engine/commands/labware_handling_common.py +29 -0
  104. opentrons/protocol_engine/commands/liquid_probe.py +27 -13
  105. opentrons/protocol_engine/commands/load_labware.py +42 -39
  106. opentrons/protocol_engine/commands/load_lid.py +21 -13
  107. opentrons/protocol_engine/commands/load_lid_stack.py +130 -47
  108. opentrons/protocol_engine/commands/load_module.py +18 -17
  109. opentrons/protocol_engine/commands/load_pipette.py +3 -0
  110. opentrons/protocol_engine/commands/move_labware.py +139 -20
  111. opentrons/protocol_engine/commands/move_to_well.py +5 -11
  112. opentrons/protocol_engine/commands/pick_up_tip.py +5 -2
  113. opentrons/protocol_engine/commands/pipetting_common.py +159 -8
  114. opentrons/protocol_engine/commands/prepare_to_aspirate.py +15 -5
  115. opentrons/protocol_engine/commands/{evotip_dispense.py → pressure_dispense.py} +33 -34
  116. opentrons/protocol_engine/commands/reload_labware.py +6 -19
  117. opentrons/protocol_engine/commands/{evotip_seal_pipette.py → seal_pipette_to_tip.py} +97 -76
  118. opentrons/protocol_engine/commands/unsafe/unsafe_blow_out_in_place.py +3 -1
  119. opentrons/protocol_engine/commands/unsafe/unsafe_drop_tip_in_place.py +6 -1
  120. opentrons/protocol_engine/commands/{evotip_unseal_pipette.py → unseal_pipette_from_tip.py} +31 -40
  121. opentrons/protocol_engine/errors/__init__.py +10 -0
  122. opentrons/protocol_engine/errors/exceptions.py +62 -0
  123. opentrons/protocol_engine/execution/equipment.py +123 -106
  124. opentrons/protocol_engine/execution/labware_movement.py +8 -6
  125. opentrons/protocol_engine/execution/pipetting.py +235 -25
  126. opentrons/protocol_engine/execution/tip_handler.py +82 -32
  127. opentrons/protocol_engine/labware_offset_standardization.py +194 -0
  128. opentrons/protocol_engine/protocol_engine.py +22 -13
  129. opentrons/protocol_engine/resources/deck_configuration_provider.py +98 -2
  130. opentrons/protocol_engine/resources/deck_data_provider.py +1 -1
  131. opentrons/protocol_engine/resources/labware_data_provider.py +32 -12
  132. opentrons/protocol_engine/resources/labware_validation.py +7 -5
  133. opentrons/protocol_engine/slot_standardization.py +11 -23
  134. opentrons/protocol_engine/state/addressable_areas.py +84 -46
  135. opentrons/protocol_engine/state/frustum_helpers.py +36 -14
  136. opentrons/protocol_engine/state/geometry.py +892 -227
  137. opentrons/protocol_engine/state/labware.py +252 -55
  138. opentrons/protocol_engine/state/module_substates/__init__.py +4 -0
  139. opentrons/protocol_engine/state/module_substates/flex_stacker_substate.py +68 -0
  140. opentrons/protocol_engine/state/module_substates/heater_shaker_module_substate.py +22 -0
  141. opentrons/protocol_engine/state/module_substates/temperature_module_substate.py +13 -0
  142. opentrons/protocol_engine/state/module_substates/thermocycler_module_substate.py +20 -0
  143. opentrons/protocol_engine/state/modules.py +210 -67
  144. opentrons/protocol_engine/state/pipettes.py +54 -0
  145. opentrons/protocol_engine/state/state.py +1 -1
  146. opentrons/protocol_engine/state/tips.py +14 -0
  147. opentrons/protocol_engine/state/update_types.py +180 -25
  148. opentrons/protocol_engine/state/wells.py +55 -9
  149. opentrons/protocol_engine/types/__init__.py +300 -0
  150. opentrons/protocol_engine/types/automatic_tip_selection.py +39 -0
  151. opentrons/protocol_engine/types/command_annotations.py +53 -0
  152. opentrons/protocol_engine/types/deck_configuration.py +72 -0
  153. opentrons/protocol_engine/types/execution.py +96 -0
  154. opentrons/protocol_engine/types/hardware_passthrough.py +25 -0
  155. opentrons/protocol_engine/types/instrument.py +47 -0
  156. opentrons/protocol_engine/types/instrument_sensors.py +47 -0
  157. opentrons/protocol_engine/types/labware.py +111 -0
  158. opentrons/protocol_engine/types/labware_movement.py +22 -0
  159. opentrons/protocol_engine/types/labware_offset_location.py +111 -0
  160. opentrons/protocol_engine/types/labware_offset_vector.py +33 -0
  161. opentrons/protocol_engine/types/liquid.py +40 -0
  162. opentrons/protocol_engine/types/liquid_class.py +59 -0
  163. opentrons/protocol_engine/types/liquid_handling.py +13 -0
  164. opentrons/protocol_engine/types/liquid_level_detection.py +131 -0
  165. opentrons/protocol_engine/types/location.py +194 -0
  166. opentrons/protocol_engine/types/module.py +301 -0
  167. opentrons/protocol_engine/types/partial_tip_configuration.py +76 -0
  168. opentrons/protocol_engine/types/run_time_parameters.py +133 -0
  169. opentrons/protocol_engine/types/tip.py +18 -0
  170. opentrons/protocol_engine/types/util.py +21 -0
  171. opentrons/protocol_engine/types/well_position.py +124 -0
  172. opentrons/protocol_reader/extract_labware_definitions.py +7 -3
  173. opentrons/protocol_reader/file_format_validator.py +5 -3
  174. opentrons/protocol_runner/json_translator.py +4 -2
  175. opentrons/protocol_runner/legacy_command_mapper.py +6 -2
  176. opentrons/protocol_runner/run_orchestrator.py +4 -1
  177. opentrons/protocols/advanced_control/transfers/common.py +48 -1
  178. opentrons/protocols/advanced_control/transfers/transfer_liquid_utils.py +204 -0
  179. opentrons/protocols/api_support/definitions.py +1 -1
  180. opentrons/protocols/api_support/instrument.py +16 -3
  181. opentrons/protocols/labware.py +27 -23
  182. opentrons/protocols/models/__init__.py +0 -21
  183. opentrons/simulate.py +4 -2
  184. opentrons/types.py +20 -7
  185. opentrons/util/logging_config.py +94 -25
  186. opentrons/util/logging_queue_handler.py +61 -0
  187. {opentrons-8.3.2.dist-info → opentrons-8.4.0.dist-info}/METADATA +4 -4
  188. {opentrons-8.3.2.dist-info → opentrons-8.4.0.dist-info}/RECORD +192 -151
  189. opentrons/calibration_storage/ot2/models/defaults.py +0 -0
  190. opentrons/calibration_storage/ot3/models/defaults.py +0 -0
  191. opentrons/protocol_api/core/legacy/legacy_robot_core.py +0 -0
  192. opentrons/protocol_engine/types.py +0 -1311
  193. {opentrons-8.3.2.dist-info → opentrons-8.4.0.dist-info}/LICENSE +0 -0
  194. {opentrons-8.3.2.dist-info → opentrons-8.4.0.dist-info}/WHEEL +0 -0
  195. {opentrons-8.3.2.dist-info → opentrons-8.4.0.dist-info}/entry_points.txt +0 -0
  196. {opentrons-8.3.2.dist-info → opentrons-8.4.0.dist-info}/top_level.txt +0 -0
@@ -10,7 +10,9 @@ from .models import v1
10
10
  CalibrationType = typing.TypeVar(
11
11
  "CalibrationType",
12
12
  v1.PipetteOffsetCalibration,
13
+ v1.InstrumentOffsetModel,
13
14
  v1.TipLengthCalibration,
15
+ v1.TipLengthModel,
14
16
  v1.DeckCalibrationModel,
15
17
  )
16
18
 
@@ -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 LabwareDefinition
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: "LabwareDefinition"
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) -> "LabwareDefinition":
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
- "LabwareDefinition",
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: "LabwareDefinition",
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: "LabwareDefinition",
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 Runs History",
94
- description="Erase this device's stored history of protocols and runs.",
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
- pass
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
- self.command = command
45
- super().__init__(port, response)
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 NoResponse, AlarmResponse, ErrorResponse, UnhandledGcode, ErrorCodes
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
- ) -> SerialConnection:
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
- if ErrorCodes.UNHANDLED_GCODE.value.lower() in lower:
254
- raise UnhandledGcode(
255
- port=self._port, response=response, command=request
256
- )
257
- else:
258
- raise ErrorResponse(port=self._port, response=response)
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 AbstractStackerDriver
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
- "AbstractStackerDriver",
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 AbstractStackerDriver(Protocol):
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) -> bool:
44
+ async def set_serial_number(self, sn: str) -> None:
37
45
  """Set Serial Number."""
38
46
  ...
39
47
 
40
- async def stop_motors(self) -> bool:
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
- ) -> bool:
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
- ) -> bool:
188
+ ) -> MoveResult:
78
189
  """Move until limit switch is triggered."""
79
190
  ...
80
191
 
81
- async def home_axis(self, axis: StackerAxis, direction: Direction) -> bool:
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, power: float, color: LEDColor | None = None, external: bool | None = None
87
- ) -> bool:
88
- """Set LED color of status bar."""
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
  ...