opentrons 8.7.0a7__py3-none-any.whl → 8.7.0a9__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 (147) hide show
  1. opentrons/_version.py +2 -2
  2. opentrons/drivers/asyncio/communication/serial_connection.py +55 -129
  3. opentrons/drivers/flex_stacker/driver.py +6 -1
  4. opentrons/drivers/heater_shaker/abstract.py +0 -5
  5. opentrons/drivers/heater_shaker/driver.py +0 -10
  6. opentrons/drivers/heater_shaker/simulator.py +0 -4
  7. opentrons/drivers/thermocycler/abstract.py +0 -6
  8. opentrons/drivers/thermocycler/driver.py +10 -61
  9. opentrons/drivers/thermocycler/simulator.py +0 -6
  10. opentrons/hardware_control/api.py +5 -24
  11. opentrons/hardware_control/backends/controller.py +2 -8
  12. opentrons/hardware_control/backends/flex_protocol.py +1 -0
  13. opentrons/hardware_control/backends/ot3controller.py +3 -3
  14. opentrons/hardware_control/backends/ot3simulator.py +2 -2
  15. opentrons/hardware_control/backends/simulator.py +1 -2
  16. opentrons/hardware_control/backends/subsystem_manager.py +2 -5
  17. opentrons/hardware_control/emulation/abstract_emulator.py +4 -6
  18. opentrons/hardware_control/emulation/connection_handler.py +5 -8
  19. opentrons/hardware_control/emulation/heater_shaker.py +3 -12
  20. opentrons/hardware_control/emulation/settings.py +1 -1
  21. opentrons/hardware_control/emulation/thermocycler.py +15 -67
  22. opentrons/hardware_control/module_control.py +8 -82
  23. opentrons/hardware_control/modules/__init__.py +0 -3
  24. opentrons/hardware_control/modules/absorbance_reader.py +4 -11
  25. opentrons/hardware_control/modules/flex_stacker.py +9 -38
  26. opentrons/hardware_control/modules/heater_shaker.py +5 -42
  27. opentrons/hardware_control/modules/magdeck.py +4 -8
  28. opentrons/hardware_control/modules/mod_abc.py +5 -13
  29. opentrons/hardware_control/modules/tempdeck.py +5 -25
  30. opentrons/hardware_control/modules/thermocycler.py +11 -68
  31. opentrons/hardware_control/modules/types.py +1 -20
  32. opentrons/hardware_control/modules/utils.py +4 -11
  33. opentrons/hardware_control/nozzle_manager.py +0 -3
  34. opentrons/hardware_control/ot3api.py +7 -26
  35. opentrons/hardware_control/poller.py +8 -22
  36. opentrons/hardware_control/protocols/gripper_controller.py +1 -0
  37. opentrons/hardware_control/scripts/update_module_fw.py +0 -5
  38. opentrons/hardware_control/types.py +2 -31
  39. opentrons/legacy_commands/module_commands.py +0 -23
  40. opentrons/legacy_commands/protocol_commands.py +0 -20
  41. opentrons/legacy_commands/types.py +0 -80
  42. opentrons/motion_planning/deck_conflict.py +12 -17
  43. opentrons/motion_planning/waypoints.py +29 -15
  44. opentrons/protocol_api/__init__.py +1 -5
  45. opentrons/protocol_api/_types.py +1 -6
  46. opentrons/protocol_api/core/common.py +1 -3
  47. opentrons/protocol_api/core/engine/_default_labware_versions.py +11 -32
  48. opentrons/protocol_api/core/engine/labware.py +1 -8
  49. opentrons/protocol_api/core/engine/module_core.py +8 -75
  50. opentrons/protocol_api/core/engine/protocol.py +1 -18
  51. opentrons/protocol_api/core/engine/well.py +0 -8
  52. opentrons/protocol_api/core/legacy/legacy_module_core.py +4 -24
  53. opentrons/protocol_api/core/legacy/legacy_protocol_core.py +1 -11
  54. opentrons/protocol_api/core/legacy/legacy_well_core.py +0 -4
  55. opentrons/protocol_api/core/legacy_simulator/legacy_protocol_core.py +2 -14
  56. opentrons/protocol_api/core/module.py +4 -37
  57. opentrons/protocol_api/core/protocol.py +2 -11
  58. opentrons/protocol_api/core/well.py +0 -4
  59. opentrons/protocol_api/labware.py +0 -5
  60. opentrons/protocol_api/module_contexts.py +61 -122
  61. opentrons/protocol_api/protocol_context.py +4 -26
  62. opentrons/protocol_api/robot_context.py +21 -38
  63. opentrons/protocol_api/validation.py +1 -6
  64. opentrons/protocol_engine/actions/__init__.py +2 -4
  65. opentrons/protocol_engine/actions/actions.py +9 -22
  66. opentrons/protocol_engine/clients/sync_client.py +7 -42
  67. opentrons/protocol_engine/commands/__init__.py +0 -42
  68. opentrons/protocol_engine/commands/absorbance_reader/close_lid.py +15 -2
  69. opentrons/protocol_engine/commands/absorbance_reader/open_lid.py +15 -2
  70. opentrons/protocol_engine/commands/aspirate.py +0 -1
  71. opentrons/protocol_engine/commands/command.py +0 -1
  72. opentrons/protocol_engine/commands/command_unions.py +0 -49
  73. opentrons/protocol_engine/commands/dispense.py +0 -1
  74. opentrons/protocol_engine/commands/drop_tip.py +8 -32
  75. opentrons/protocol_engine/commands/heater_shaker/__init__.py +0 -14
  76. opentrons/protocol_engine/commands/heater_shaker/set_and_wait_for_shake_speed.py +4 -5
  77. opentrons/protocol_engine/commands/heater_shaker/set_target_temperature.py +5 -31
  78. opentrons/protocol_engine/commands/movement_common.py +0 -2
  79. opentrons/protocol_engine/commands/pick_up_tip.py +11 -21
  80. opentrons/protocol_engine/commands/temperature_module/set_target_temperature.py +7 -38
  81. opentrons/protocol_engine/commands/thermocycler/__init__.py +0 -16
  82. opentrons/protocol_engine/commands/thermocycler/run_extended_profile.py +0 -6
  83. opentrons/protocol_engine/commands/thermocycler/run_profile.py +0 -8
  84. opentrons/protocol_engine/commands/thermocycler/set_target_block_temperature.py +6 -40
  85. opentrons/protocol_engine/commands/thermocycler/set_target_lid_temperature.py +5 -29
  86. opentrons/protocol_engine/commands/touch_tip.py +1 -1
  87. opentrons/protocol_engine/commands/unsafe/unsafe_place_labware.py +22 -6
  88. opentrons/protocol_engine/errors/__init__.py +0 -4
  89. opentrons/protocol_engine/errors/exceptions.py +0 -55
  90. opentrons/protocol_engine/execution/__init__.py +0 -2
  91. opentrons/protocol_engine/execution/command_executor.py +0 -8
  92. opentrons/protocol_engine/execution/create_queue_worker.py +1 -5
  93. opentrons/protocol_engine/execution/labware_movement.py +21 -10
  94. opentrons/protocol_engine/execution/movement.py +0 -2
  95. opentrons/protocol_engine/execution/queue_worker.py +0 -4
  96. opentrons/protocol_engine/execution/run_control.py +0 -8
  97. opentrons/protocol_engine/protocol_engine.py +34 -75
  98. opentrons/protocol_engine/resources/__init__.py +0 -2
  99. opentrons/protocol_engine/resources/deck_configuration_provider.py +0 -7
  100. opentrons/protocol_engine/resources/labware_validation.py +6 -10
  101. opentrons/protocol_engine/state/_labware_origin_math.py +636 -0
  102. opentrons/protocol_engine/state/_well_math.py +18 -60
  103. opentrons/protocol_engine/state/addressable_areas.py +0 -2
  104. opentrons/protocol_engine/state/commands.py +11 -14
  105. opentrons/protocol_engine/state/geometry.py +374 -213
  106. opentrons/protocol_engine/state/labware.py +102 -52
  107. opentrons/protocol_engine/state/module_substates/thermocycler_module_substate.py +0 -37
  108. opentrons/protocol_engine/state/modules.py +8 -21
  109. opentrons/protocol_engine/state/motion.py +0 -44
  110. opentrons/protocol_engine/state/state.py +0 -14
  111. opentrons/protocol_engine/state/state_summary.py +0 -2
  112. opentrons/protocol_engine/state/tips.py +258 -177
  113. opentrons/protocol_engine/state/update_types.py +9 -16
  114. opentrons/protocol_engine/types/__init__.py +3 -9
  115. opentrons/protocol_engine/types/deck_configuration.py +1 -5
  116. opentrons/protocol_engine/types/instrument.py +1 -8
  117. opentrons/protocol_engine/types/labware.py +13 -1
  118. opentrons/protocol_engine/types/module.py +0 -10
  119. opentrons/protocol_engine/types/tip.py +0 -9
  120. opentrons/protocol_runner/create_simulating_orchestrator.py +2 -29
  121. opentrons/protocol_runner/run_orchestrator.py +2 -18
  122. opentrons/protocols/api_support/definitions.py +1 -1
  123. opentrons/protocols/api_support/types.py +1 -2
  124. opentrons/simulate.py +15 -48
  125. opentrons/system/camera.py +1 -1
  126. {opentrons-8.7.0a7.dist-info → opentrons-8.7.0a9.dist-info}/METADATA +4 -4
  127. {opentrons-8.7.0a7.dist-info → opentrons-8.7.0a9.dist-info}/RECORD +130 -146
  128. opentrons/protocol_api/core/engine/tasks.py +0 -48
  129. opentrons/protocol_api/core/legacy/tasks.py +0 -19
  130. opentrons/protocol_api/core/legacy_simulator/tasks.py +0 -19
  131. opentrons/protocol_api/core/tasks.py +0 -31
  132. opentrons/protocol_api/tasks.py +0 -48
  133. opentrons/protocol_engine/commands/create_timer.py +0 -83
  134. opentrons/protocol_engine/commands/heater_shaker/common.py +0 -20
  135. opentrons/protocol_engine/commands/heater_shaker/set_shake_speed.py +0 -136
  136. opentrons/protocol_engine/commands/set_tip_state.py +0 -97
  137. opentrons/protocol_engine/commands/thermocycler/start_run_extended_profile.py +0 -191
  138. opentrons/protocol_engine/commands/wait_for_tasks.py +0 -98
  139. opentrons/protocol_engine/execution/task_handler.py +0 -157
  140. opentrons/protocol_engine/resources/concurrency_provider.py +0 -27
  141. opentrons/protocol_engine/state/labware_origin_math/errors.py +0 -94
  142. opentrons/protocol_engine/state/labware_origin_math/stackup_origin_to_labware_origin.py +0 -1331
  143. opentrons/protocol_engine/state/tasks.py +0 -139
  144. opentrons/protocol_engine/types/tasks.py +0 -38
  145. {opentrons-8.7.0a7.dist-info → opentrons-8.7.0a9.dist-info}/WHEEL +0 -0
  146. {opentrons-8.7.0a7.dist-info → opentrons-8.7.0a9.dist-info}/entry_points.txt +0 -0
  147. {opentrons-8.7.0a7.dist-info → opentrons-8.7.0a9.dist-info}/licenses/LICENSE +0 -0
@@ -414,8 +414,7 @@ class Simulator:
414
414
 
415
415
  @ensure_yield
416
416
  async def clean_up(self) -> None:
417
- if hasattr(self, "_module_controls") and self._module_controls is not None:
418
- await self._module_controls.clean_up()
417
+ pass
419
418
 
420
419
  @ensure_yield
421
420
  async def configure_mount(
@@ -91,8 +91,6 @@ class SubsystemManager:
91
91
  self._present_tools = tools.types.ToolSummary(
92
92
  left=None, right=None, gripper=None
93
93
  )
94
- # This is intended to be an internal variable but is modified in unit tests to avoid long timeouts
95
- self._check_device_update_timeout = 10.0
96
94
 
97
95
  @property
98
96
  def ok(self) -> bool:
@@ -185,12 +183,11 @@ class SubsystemManager:
185
183
  return self._tool_task_state is True
186
184
 
187
185
  async def _check_devices_after_update(
188
- self, devices: Set[SubSystem], timeout_sec: Optional[float] = None
186
+ self, devices: Set[SubSystem], timeout_sec: float = 10.0
189
187
  ) -> None:
190
188
  try:
191
189
  await asyncio.wait_for(
192
- self._do_check_devices_after_update(devices),
193
- timeout=timeout_sec or self._check_device_update_timeout,
190
+ self._do_check_devices_after_update(devices), timeout=timeout_sec
194
191
  )
195
192
  except asyncio.TimeoutError:
196
193
  raise RuntimeError("Device failed to come back after firmware update")
@@ -10,14 +10,12 @@ class AbstractEmulator(ABC):
10
10
  """Handle a command and return a response."""
11
11
  ...
12
12
 
13
- def get_terminator(self) -> bytes:
13
+ @staticmethod
14
+ def get_terminator() -> bytes:
14
15
  """Get the command terminator for messages coming from PI."""
15
16
  return b"\r\n\r\n"
16
17
 
17
- def get_ack(self) -> bytes:
18
+ @staticmethod
19
+ def get_ack() -> bytes:
18
20
  """Get the command ack send to the PI."""
19
21
  return b"ok\r\nok\r\n"
20
-
21
- def get_autoack(self) -> bool:
22
- """Should this system automatically acknowledge messages?"""
23
- return True
@@ -27,15 +27,12 @@ class ConnectionHandler:
27
27
  try:
28
28
  response = self._emulator.handle(line.decode().strip())
29
29
  if response:
30
- response_bytes = response.encode() + self._emulator.get_terminator()
31
- logger.debug(f"{emulator_name} Sending: {response_bytes!r}")
32
- writer.write(response_bytes)
30
+ response = f"{response}\r\n"
31
+ logger.debug("%s Sending: %s", emulator_name, response)
32
+ writer.write(response.encode())
33
33
  except Exception as e:
34
34
  logger.exception("%s exception", emulator_name)
35
- writer.write(
36
- f"Error: {str(e)} ".encode() + self._emulator.get_terminator()
37
- )
35
+ writer.write(f"Error: {str(e)}\r\n".encode())
38
36
 
39
- if self._emulator.get_autoack():
40
- writer.write(self._emulator.get_ack())
37
+ writer.write(self._emulator.get_ack())
41
38
  await writer.drain()
@@ -2,7 +2,6 @@
2
2
 
3
3
  The purpose is to provide a fake backend that responds to GCODE commands.
4
4
  """
5
-
6
5
  import logging
7
6
  from time import sleep
8
7
  from typing import (
@@ -51,7 +50,6 @@ class HeaterShakerEmulator(AbstractEmulator):
51
50
  GCODE.CLOSE_LABWARE_LATCH.value: self._close_labware_latch,
52
51
  GCODE.GET_LABWARE_LATCH_STATE.value: self._get_labware_latch_state,
53
52
  GCODE.DEACTIVATE_HEATER.value: self._deactivate_heater,
54
- GCODE.GET_ERROR_STATE.value: self._get_error_state,
55
53
  }
56
54
  self.reset()
57
55
 
@@ -62,6 +60,7 @@ class HeaterShakerEmulator(AbstractEmulator):
62
60
  return None if not joined else joined
63
61
 
64
62
  def reset(self) -> None:
63
+
65
64
  self._temperature = Temperature(
66
65
  per_tick=self._settings.temperature.degrees_per_tick,
67
66
  current=self._settings.temperature.starting,
@@ -146,14 +145,6 @@ class HeaterShakerEmulator(AbstractEmulator):
146
145
  self._temperature.deactivate(TEMPERATURE_ROOM)
147
146
  return "M106"
148
147
 
149
- def _get_error_state(self, command: Command) -> str:
150
- return f"M411 {HS_ACK}M411"
151
-
152
- def get_terminator(self) -> bytes:
148
+ @staticmethod
149
+ def get_terminator() -> bytes:
153
150
  return b"\n"
154
-
155
- def get_ack(self) -> bytes:
156
- return HS_ACK.encode()
157
-
158
- def get_autoack(self) -> bool:
159
- return False
@@ -90,7 +90,7 @@ class Settings(BaseSettings):
90
90
  )
91
91
  thermocycler: ThermocyclerSettings = ThermocyclerSettings(
92
92
  serial_number="thermocycler_emulator",
93
- model="thermocyclerModuleV2",
93
+ model="v02",
94
94
  version="v1.1.0",
95
95
  lid_temperature=TemperatureModelSettings(),
96
96
  plate_temperature=TemperatureModelSettings(),
@@ -5,15 +5,8 @@ The purpose is to provide a fake backend that responds to GCODE commands.
5
5
 
6
6
  import logging
7
7
  from typing import Optional
8
- from opentrons.drivers.thermocycler.driver import (
9
- GCODE,
10
- TC_GEN2_ACK,
11
- TC_GEN2_SERIAL_ACK,
12
- TC_ACK as TC_GEN1_ACK,
13
- SERIAL_ACK as TC_GEN1_SERIAL_ACK,
14
- )
8
+ from opentrons.drivers.thermocycler.driver import GCODE
15
9
  from opentrons.drivers.types import ThermocyclerLidStatus
16
- from opentrons.hardware_control.modules.types import ThermocyclerModuleModel
17
10
  from opentrons.hardware_control.emulation.parser import Parser, Command
18
11
  from opentrons.hardware_control.emulation.settings import ThermocyclerSettings
19
12
 
@@ -36,31 +29,13 @@ class ThermocyclerEmulator(AbstractEmulator):
36
29
  def __init__(self, parser: Parser, settings: ThermocyclerSettings) -> None:
37
30
  self._parser = parser
38
31
  self._settings = settings
39
- # I hate this. These modules do not return anything like this for their actual versions
40
- # (gen2 returns "Opentrons-thermocycler-gen2" for instance) and this is not what any of
41
- # the settings anywhere use.
42
- self._model = (
43
- ThermocyclerModuleModel.THERMOCYCLER_V1
44
- if settings.model in ["thermocyclerModuleV1", "v1", "v01"]
45
- else ThermocyclerModuleModel.THERMOCYCLER_V2
46
- )
47
- self._terminator = (
48
- TC_GEN1_SERIAL_ACK
49
- if self._model is ThermocyclerModuleModel.THERMOCYCLER_V1
50
- else TC_GEN2_SERIAL_ACK
51
- )
52
- self._ack = (
53
- TC_GEN1_ACK
54
- if self._model is ThermocyclerModuleModel.THERMOCYCLER_V1
55
- else TC_GEN2_ACK
56
- )
57
32
  self.reset()
58
33
 
59
34
  def handle(self, line: str) -> Optional[str]:
60
35
  """Handle a line"""
61
36
  results = (self._handle(c) for c in self._parser.parse(line))
62
- joined = " ".join(f"{r} {self._ack}" for r in results if r)
63
- return self._ack if not joined else joined
37
+ joined = " ".join(r for r in results if r)
38
+ return None if not joined else joined
64
39
 
65
40
  def reset(self) -> None:
66
41
  self._lid_temperature = Temperature(
@@ -75,12 +50,6 @@ class ThermocyclerEmulator(AbstractEmulator):
75
50
  self.plate_volume = util.OptionalValue[float]()
76
51
  self.plate_ramp_rate = util.OptionalValue[float]()
77
52
 
78
- def _pref(self, command: Command) -> str:
79
- if self._model is ThermocyclerModuleModel.THERMOCYCLER_V1:
80
- return ""
81
- else:
82
- return f"{command.gcode} "
83
-
84
53
  def _handle(self, command: Command) -> Optional[str]: # noqa: C901
85
54
  """
86
55
  Handle a command.
@@ -93,7 +62,7 @@ class ThermocyclerEmulator(AbstractEmulator):
93
62
  elif command.gcode == GCODE.CLOSE_LID:
94
63
  self.lid_status = ThermocyclerLidStatus.CLOSED
95
64
  elif command.gcode == GCODE.GET_LID_STATUS:
96
- return self._pref(command) + f"Lid:{self.lid_status}"
65
+ return f"Lid:{self.lid_status}"
97
66
  elif command.gcode == GCODE.SET_LID_TEMP:
98
67
  temperature = command.params["S"]
99
68
  assert isinstance(
@@ -107,7 +76,7 @@ class ThermocyclerEmulator(AbstractEmulator):
107
76
  f"H:none Total_H:none"
108
77
  )
109
78
  self._lid_temperature.tick()
110
- return self._pref(command) + res
79
+ return res
111
80
  elif command.gcode == GCODE.EDIT_PID_PARAMS:
112
81
  pass
113
82
  elif command.gcode == GCODE.SET_PLATE_TEMP:
@@ -136,7 +105,7 @@ class ThermocyclerEmulator(AbstractEmulator):
136
105
  f"Total_H:{plate_total_hold_time} "
137
106
  )
138
107
  self._plate_temperature.tick()
139
- return self._pref(command) + res
108
+ return res
140
109
  elif command.gcode == GCODE.SET_RAMP_RATE:
141
110
  self.plate_ramp_rate.val = command.params["S"]
142
111
  elif command.gcode == GCODE.DEACTIVATE_ALL:
@@ -147,34 +116,13 @@ class ThermocyclerEmulator(AbstractEmulator):
147
116
  elif command.gcode == GCODE.DEACTIVATE_BLOCK:
148
117
  self._plate_temperature.deactivate(temperature=util.TEMPERATURE_ROOM)
149
118
  elif command.gcode == GCODE.DEVICE_INFO:
150
- # the gen2 returns a completely different device info format than the
151
- # gen1 which is pretty cool
152
- if self._model == ThermocyclerModuleModel.THERMOCYCLER_V1:
153
- return (
154
- f"serial:{self._settings.serial_number} "
155
- f"model:{self._settings.model} "
156
- f"version:{self._settings.version}"
157
- )
158
- else:
159
- return (
160
- command.gcode
161
- + " "
162
- + (
163
- f"FW:{self._settings.version} "
164
- f"HW:{self._settings.model} "
165
- f"SerialNo:{self._settings.serial_number}"
166
- )
167
- )
168
- elif command.gcode == GCODE.GET_ERROR_STATE:
169
- if self._model is ThermocyclerModuleModel.THERMOCYCLER_V2:
170
- return self._pref(command) + self._ack + self._pref(command)
171
- return self._pref(command)
172
-
173
- def get_terminator(self) -> bytes:
174
- return self._terminator.encode()
175
-
176
- def get_ack(self) -> bytes:
177
- return self._ack.encode()
119
+ return (
120
+ f"serial:{self._settings.serial_number} "
121
+ f"model:{self._settings.model} "
122
+ f"version:{self._settings.version}"
123
+ )
124
+ return None
178
125
 
179
- def get_autoack(self) -> bool:
180
- return False
126
+ @staticmethod
127
+ def get_terminator() -> bytes:
128
+ return b"\r\n"
@@ -2,11 +2,9 @@ from __future__ import annotations
2
2
  import asyncio
3
3
  import logging
4
4
  import re
5
- from typing import TYPE_CHECKING, List, Optional, Union, Callable
5
+ from typing import TYPE_CHECKING, List, Optional, Union
6
6
  from glob import glob
7
7
 
8
- from opentrons_shared_data.errors.exceptions import EnumeratedError
9
-
10
8
  from opentrons.config import IS_ROBOT, IS_LINUX
11
9
  from opentrons.drivers.rpi_drivers import types, interfaces, usb, usb_simulator
12
10
  from opentrons.hardware_control.emulation.module_server.helpers import (
@@ -21,16 +19,8 @@ from opentrons.hardware_control.modules.module_calibration import (
21
19
  from opentrons.hardware_control.modules.types import ModuleAtPort, ModuleType
22
20
  from opentrons.hardware_control.modules import SimulatingModuleAtPort
23
21
 
24
-
25
22
  from opentrons.types import Point
26
- from .types import (
27
- AionotifyEvent,
28
- BoardRevision,
29
- OT3Mount,
30
- StatusBarUpdateEvent,
31
- HardwareEvent,
32
- AsynchronousModuleErrorNotification,
33
- )
23
+ from .types import AionotifyEvent, BoardRevision, OT3Mount, StatusBarUpdateEvent
34
24
  from . import modules
35
25
 
36
26
  if TYPE_CHECKING:
@@ -61,21 +51,10 @@ class AttachedModulesControl:
61
51
  self,
62
52
  api: Union["API", "OT3API"],
63
53
  usb: interfaces.USBDriverInterface,
64
- event_callback: Callable[[HardwareEvent], None],
65
54
  ) -> None:
66
55
  self._available_modules: List[modules.AbstractModule] = []
67
56
  self._api = api
68
57
  self._usb = usb
69
- self._event_callback = event_callback
70
- if not IS_ROBOT and not api.is_simulator:
71
- # Start task that registers emulated modules.
72
- self._emulation_listen_task: asyncio.Task[
73
- None
74
- ] | None = api.loop.create_task(
75
- listen_module_connection(self.register_modules)
76
- )
77
- else:
78
- self._emulation_listen_task = None
79
58
 
80
59
  def subscribe_to_api_event(self, module: modules.AbstractModule) -> None:
81
60
  self._api.add_status_bar_listener(module.event_listener)
@@ -85,20 +64,22 @@ class AttachedModulesControl:
85
64
  cls,
86
65
  api_instance: Union["API", "OT3API"],
87
66
  board_revision: BoardRevision,
88
- event_callback: Callable[[HardwareEvent], None],
89
67
  ) -> AttachedModulesControl:
90
68
  usb_instance = (
91
69
  usb.USBBus(board_revision)
92
70
  if not api_instance.is_simulator and IS_ROBOT
93
71
  else usb_simulator.USBBusSimulator()
94
72
  )
95
- mc_instance = cls(
96
- api=api_instance, usb=usb_instance, event_callback=event_callback
97
- )
73
+ mc_instance = cls(api=api_instance, usb=usb_instance)
98
74
 
99
75
  if not api_instance.is_simulator:
100
76
  # Do an initial scan of modules.
101
77
  await mc_instance.register_modules(mc_instance.scan())
78
+ if not IS_ROBOT:
79
+ # Start task that registers emulated modules.
80
+ api_instance.loop.create_task(
81
+ listen_module_connection(mc_instance.register_modules)
82
+ )
102
83
 
103
84
  return mc_instance
104
85
 
@@ -106,37 +87,6 @@ class AttachedModulesControl:
106
87
  def available_modules(self) -> List[modules.AbstractModule]:
107
88
  return self._available_modules
108
89
 
109
- async def clean_up(self) -> None:
110
- """Clean up all registered modules and emulator scanning tasks (if any)."""
111
- for module in self._available_modules:
112
- await module.cleanup()
113
- if self._emulation_listen_task is not None:
114
- self._emulation_listen_task.cancel("cleanup")
115
- try:
116
- await self._emulation_listen_task
117
- except asyncio.CancelledError:
118
- pass
119
- except Exception:
120
- log.exception("Exception cleaning up emulation listen task")
121
- finally:
122
- self._emulation_listen_task = None
123
-
124
- async def register_simulated_module(
125
- self,
126
- simulated_usb_port: types.USBPort,
127
- type: modules.ModuleType,
128
- sim_model: str,
129
- ) -> modules.AbstractModule:
130
- """Register a simulated module."""
131
- module = await self.build_module(
132
- "", simulated_usb_port, type, sim_model, sim_serial_number=None
133
- )
134
- self._available_modules.append(module)
135
- self._available_modules = sorted(
136
- self._available_modules, key=modules.AbstractModule.sort_key
137
- )
138
- return module
139
-
140
90
  async def build_module(
141
91
  self,
142
92
  port: str,
@@ -155,7 +105,6 @@ class AttachedModulesControl:
155
105
  sim_model=sim_model,
156
106
  sim_serial_number=sim_serial_number,
157
107
  disconnected_callback=self._disconnected_callback,
158
- error_callback=self._async_error_callback,
159
108
  )
160
109
  last_event = StatusBarUpdateEvent(
161
110
  self._api.get_status_bar_state(), self._api.get_status_bar_enabled()
@@ -172,29 +121,6 @@ class AttachedModulesControl:
172
121
  self._api.loop,
173
122
  )
174
123
 
175
- def _async_error_callback(
176
- self,
177
- exc: Exception,
178
- model: str,
179
- port: str,
180
- serial: str | None,
181
- ) -> None:
182
- """Used by the module to indicate it saw an error from its data poller."""
183
- try:
184
- self._api.loop.call_soon(
185
- self._event_callback,
186
- AsynchronousModuleErrorNotification(
187
- exception=EnumeratedError.ensure(exc),
188
- module_serial=serial,
189
- module_model=modules.module_model_from_string(model),
190
- port=port,
191
- ),
192
- )
193
- except Exception:
194
- log.exception(
195
- f"Async error callback for module {model} {serial} at {port} for exc {exc} failed"
196
- )
197
-
198
124
  async def unregister_modules(
199
125
  self,
200
126
  mods_at_ports: Union[
@@ -27,9 +27,7 @@ from .types import (
27
27
  LiveData,
28
28
  ModuleData,
29
29
  ModuleDataValidator,
30
- module_model_from_string,
31
30
  )
32
-
33
31
  from .errors import (
34
32
  UpdateError,
35
33
  AbsorbanceReaderDisconnectedError,
@@ -68,5 +66,4 @@ __all__ = [
68
66
  "FlexStackerStatus",
69
67
  "PlatformState",
70
68
  "StackerAxisState",
71
- "module_model_from_string",
72
69
  ]
@@ -21,7 +21,6 @@ from opentrons.hardware_control.poller import Poller, Reader
21
21
  from opentrons.hardware_control.modules import mod_abc
22
22
  from opentrons.hardware_control.modules.types import (
23
23
  ModuleDisconnectedCallback,
24
- ModuleErrorCallback,
25
24
  ModuleType,
26
25
  AbsorbanceReaderStatus,
27
26
  LiveData,
@@ -105,13 +104,12 @@ class AbsorbanceReader(mod_abc.AbstractModule):
105
104
  port: str,
106
105
  usb_port: USBPort,
107
106
  hw_control_loop: asyncio.AbstractEventLoop,
108
- execution_manager: ExecutionManager,
109
- disconnected_callback: ModuleDisconnectedCallback,
110
- error_callback: ModuleErrorCallback,
107
+ execution_manager: Optional[ExecutionManager] = None,
111
108
  poll_interval_seconds: Optional[float] = None,
112
109
  simulating: bool = False,
113
110
  sim_model: Optional[str] = None,
114
111
  sim_serial_number: Optional[str] = None,
112
+ disconnected_callback: ModuleDisconnectedCallback = None,
115
113
  ) -> "AbsorbanceReader":
116
114
  """
117
115
  Build and connect to an AbsorbanceReader
@@ -154,7 +152,6 @@ class AbsorbanceReader(mod_abc.AbstractModule):
154
152
  hw_control_loop=hw_control_loop,
155
153
  execution_manager=execution_manager,
156
154
  disconnected_callback=disconnected_callback,
157
- error_callback=error_callback,
158
155
  )
159
156
 
160
157
  try:
@@ -173,9 +170,8 @@ class AbsorbanceReader(mod_abc.AbstractModule):
173
170
  poller: Poller,
174
171
  device_info: Mapping[str, str],
175
172
  hw_control_loop: asyncio.AbstractEventLoop,
176
- execution_manager: ExecutionManager,
177
- disconnected_callback: ModuleDisconnectedCallback,
178
- error_callback: ModuleErrorCallback,
173
+ execution_manager: Optional[ExecutionManager] = None,
174
+ disconnected_callback: ModuleDisconnectedCallback = None,
179
175
  ) -> None:
180
176
  """
181
177
  Constructor
@@ -197,7 +193,6 @@ class AbsorbanceReader(mod_abc.AbstractModule):
197
193
  hw_control_loop=hw_control_loop,
198
194
  execution_manager=execution_manager,
199
195
  disconnected_callback=disconnected_callback,
200
- error_callback=error_callback,
201
196
  )
202
197
  self._device_info = device_info
203
198
  self._reader = reader
@@ -376,5 +371,3 @@ class AbsorbanceReader(mod_abc.AbstractModule):
376
371
  self._error = str(error)
377
372
  if isinstance(error, AbsorbanceReaderDisconnectedError):
378
373
  self.disconnected_callback()
379
- else:
380
- self.error_callback(error)
@@ -44,7 +44,6 @@ from opentrons.hardware_control.modules.types import (
44
44
  FlexStackerStatus,
45
45
  HopperDoorState,
46
46
  LatchState,
47
- ModuleErrorCallback,
48
47
  ModuleDisconnectedCallback,
49
48
  ModuleType,
50
49
  PlatformState,
@@ -216,13 +215,12 @@ class FlexStacker(mod_abc.AbstractModule):
216
215
  port: str,
217
216
  usb_port: USBPort,
218
217
  hw_control_loop: asyncio.AbstractEventLoop,
219
- execution_manager: ExecutionManager,
220
- disconnected_callback: ModuleDisconnectedCallback,
221
- error_callback: ModuleErrorCallback,
222
- poll_interval_seconds: float | None = None,
218
+ execution_manager: Optional[ExecutionManager] = None,
219
+ poll_interval_seconds: Optional[float] = None,
223
220
  simulating: bool = False,
224
221
  sim_model: Optional[str] = None,
225
222
  sim_serial_number: Optional[str] = None,
223
+ disconnected_callback: ModuleDisconnectedCallback = None,
226
224
  ) -> "FlexStacker":
227
225
  """
228
226
  Build a FlexStacker
@@ -261,9 +259,11 @@ class FlexStacker(mod_abc.AbstractModule):
261
259
  hw_control_loop=hw_control_loop,
262
260
  execution_manager=execution_manager,
263
261
  disconnected_callback=disconnected_callback,
264
- error_callback=error_callback,
265
262
  )
266
263
 
264
+ # Set initialized callback
265
+ reader.set_initialized_callback(module._initialized_callback)
266
+
267
267
  # Enable stallguard
268
268
  for axis, config in STALLGUARD_CONFIG.items():
269
269
  await driver.set_stallguard_threshold(
@@ -286,9 +286,8 @@ class FlexStacker(mod_abc.AbstractModule):
286
286
  poller: Poller,
287
287
  device_info: Mapping[str, str],
288
288
  hw_control_loop: asyncio.AbstractEventLoop,
289
- execution_manager: ExecutionManager,
290
- disconnected_callback: ModuleDisconnectedCallback,
291
- error_callback: ModuleErrorCallback,
289
+ execution_manager: Optional[ExecutionManager] = None,
290
+ disconnected_callback: ModuleDisconnectedCallback = None,
292
291
  ):
293
292
  super().__init__(
294
293
  port=port,
@@ -296,7 +295,6 @@ class FlexStacker(mod_abc.AbstractModule):
296
295
  hw_control_loop=hw_control_loop,
297
296
  execution_manager=execution_manager,
298
297
  disconnected_callback=disconnected_callback,
299
- error_callback=error_callback,
300
298
  )
301
299
  self._device_info = device_info
302
300
  self._driver = driver
@@ -306,20 +304,12 @@ class FlexStacker(mod_abc.AbstractModule):
306
304
  self._stacker_status = FlexStackerStatus.IDLE
307
305
  self._last_status_bar_event: Optional[StatusBarUpdateEvent] = None
308
306
  self._should_identify = False
309
- # Set initialized callback
310
- self._unsubscribe_init = reader.set_initialized_callback(
311
- self._initialized_callback
312
- )
313
- self._unsubscribe_error = reader.set_error_callback(self._async_error_callback)
314
307
 
315
308
  async def _initialized_callback(self) -> None:
316
309
  """Called by the reader once the module is initialized."""
317
310
  if self._last_status_bar_event:
318
311
  await self._handle_status_bar_event(self._last_status_bar_event)
319
312
 
320
- def _async_error_callback(self, exception: Exception) -> None:
321
- self.error_callback(exception)
322
-
323
313
  async def cleanup(self) -> None:
324
314
  """Stop the poller task"""
325
315
  await self._poller.stop()
@@ -874,27 +864,10 @@ class FlexStackerReader(Reader):
874
864
  self.installation_detected = False
875
865
  self._refresh_state = False
876
866
  self._initialized_callback: Optional[Callable[[], Awaitable[None]]] = None
877
- self._error_callback: Optional[Callable[[Exception], None]] = None
878
867
 
879
- def set_initialized_callback(
880
- self, callback: Callable[[], Awaitable[None]]
881
- ) -> Callable[[], None]:
868
+ def set_initialized_callback(self, callback: Callable[[], Awaitable[None]]) -> None:
882
869
  """Sets the callback used when done initializing the module."""
883
870
  self._initialized_callback = callback
884
- return self._remove_init_callback
885
-
886
- def _remove_init_callback(self) -> None:
887
- self._initialized_callback = None
888
-
889
- def set_error_callback(
890
- self, error_callback: Callable[[Exception], None]
891
- ) -> Callable[[], None]:
892
- """Register a handler for asynchronous hardware errors."""
893
- self._error_callback = error_callback
894
- return self._remove_error_callback
895
-
896
- def _remove_error_callback(self) -> None:
897
- self._error_callback = None
898
871
 
899
872
  async def read(self) -> None:
900
873
  await self.get_door_closed()
@@ -969,8 +942,6 @@ class FlexStackerReader(Reader):
969
942
  if exception is None:
970
943
  self.error = None
971
944
  else:
972
- if self._error_callback:
973
- self._error_callback(exception)
974
945
  try:
975
946
  self.error = str(exception.args[0])
976
947
  except Exception: