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
@@ -2,21 +2,19 @@ from __future__ import annotations
2
2
 
3
3
  import asyncio
4
4
  import logging
5
- from typing import Optional, Mapping, Callable
5
+ from typing import Optional, Mapping
6
6
  from typing_extensions import Final
7
7
 
8
8
  from opentrons.drivers.rpi_drivers.types import USBPort
9
9
  from opentrons.drivers.heater_shaker.driver import HeaterShakerDriver
10
10
  from opentrons.drivers.heater_shaker.abstract import AbstractHeaterShakerDriver
11
11
  from opentrons.drivers.heater_shaker.simulator import SimulatingDriver
12
- from opentrons.drivers.asyncio.communication.errors import UnhandledGcode
13
12
  from opentrons.drivers.types import Temperature, RPM, HeaterShakerLabwareLatchStatus
14
13
  from opentrons.hardware_control.execution_manager import ExecutionManager
15
14
  from opentrons.hardware_control.poller import Reader, Poller
16
15
  from opentrons.hardware_control.modules import mod_abc, update
17
16
  from opentrons.hardware_control.modules.types import (
18
17
  ModuleDisconnectedCallback,
19
- ModuleErrorCallback,
20
18
  ModuleType,
21
19
  TemperatureStatus,
22
20
  SpeedStatus,
@@ -49,13 +47,12 @@ class HeaterShaker(mod_abc.AbstractModule):
49
47
  port: str,
50
48
  usb_port: USBPort,
51
49
  hw_control_loop: asyncio.AbstractEventLoop,
52
- execution_manager: ExecutionManager,
53
- disconnected_callback: ModuleDisconnectedCallback,
54
- error_callback: ModuleErrorCallback,
50
+ execution_manager: Optional[ExecutionManager] = None,
55
51
  poll_interval_seconds: Optional[float] = None,
56
52
  simulating: bool = False,
57
53
  sim_model: Optional[str] = None,
58
54
  sim_serial_number: Optional[str] = None,
55
+ disconnected_callback: ModuleDisconnectedCallback = None,
59
56
  ) -> "HeaterShaker":
60
57
  """
61
58
  Build a HeaterShaker
@@ -70,7 +67,6 @@ class HeaterShaker(mod_abc.AbstractModule):
70
67
  loop: Loop
71
68
  sim_model: The model name used by simulator
72
69
  disconnected_callback: Callback to inform the module controller that the device was disconnected
73
- error_callback: Callback to inform the module controller of an asynchronous error
74
70
 
75
71
  Returns:
76
72
  HeaterShaker instance
@@ -95,7 +91,6 @@ class HeaterShaker(mod_abc.AbstractModule):
95
91
  hw_control_loop=hw_control_loop,
96
92
  execution_manager=execution_manager,
97
93
  disconnected_callback=disconnected_callback,
98
- error_callback=error_callback,
99
94
  )
100
95
 
101
96
  try:
@@ -114,9 +109,8 @@ class HeaterShaker(mod_abc.AbstractModule):
114
109
  poller: Poller,
115
110
  device_info: Mapping[str, str],
116
111
  hw_control_loop: asyncio.AbstractEventLoop,
117
- execution_manager: ExecutionManager,
118
- disconnected_callback: ModuleDisconnectedCallback,
119
- error_callback: ModuleErrorCallback,
112
+ execution_manager: Optional[ExecutionManager] = None,
113
+ disconnected_callback: ModuleDisconnectedCallback = None,
120
114
  ):
121
115
  super().__init__(
122
116
  port=port,
@@ -124,22 +118,14 @@ class HeaterShaker(mod_abc.AbstractModule):
124
118
  hw_control_loop=hw_control_loop,
125
119
  execution_manager=execution_manager,
126
120
  disconnected_callback=disconnected_callback,
127
- error_callback=error_callback,
128
121
  )
129
122
  self._device_info = device_info
130
123
  self._driver = driver
131
124
  self._reader = reader
132
125
  self._poller = poller
133
- self._unsubscribe_reader = self._reader.register_error_handler(
134
- self._handle_error
135
- )
136
-
137
- def _handle_error(self, error: Exception) -> None:
138
- self.error_callback(error)
139
126
 
140
127
  async def cleanup(self) -> None:
141
128
  """Stop the poller task"""
142
- self._unsubscribe_reader()
143
129
  await self._poller.stop()
144
130
  await self._driver.disconnect()
145
131
 
@@ -411,22 +397,11 @@ class HeaterShakerReader(Reader):
411
397
  self.labware_latch = HeaterShakerLabwareLatchStatus.IDLE_UNKNOWN
412
398
  self.error: Optional[str] = None
413
399
  self._driver = driver
414
- self._handle_error: Callable[[Exception], None] | None = None
415
-
416
- def register_error_handler(
417
- self, handle_error: Callable[[Exception], None]
418
- ) -> Callable[[], None]:
419
- self._handle_error = handle_error
420
- return self._unsubscribe_error_handler
421
-
422
- def _unsubscribe_error_handler(self) -> None:
423
- self._handle_error = None
424
400
 
425
401
  async def read(self) -> None:
426
402
  await self.read_temperature()
427
403
  await self.read_rpm()
428
404
  await self.read_labware_latch()
429
- await self._read_errors()
430
405
  self._set_error(None)
431
406
 
432
407
  def on_error(self, exception: Exception) -> None:
@@ -445,19 +420,7 @@ class HeaterShakerReader(Reader):
445
420
  if exception is None:
446
421
  self.error = None
447
422
  else:
448
- if self._handle_error:
449
- self._handle_error(exception)
450
423
  try:
451
424
  self.error = str(exception.args[0])
452
425
  except Exception:
453
426
  self.error = repr(exception)
454
-
455
- async def _read_errors(self) -> None:
456
- try:
457
- await self._driver.get_error_state()
458
- except UnhandledGcode:
459
- # This device's firmware cannot accept this command, because it
460
- # hasn't been updated or because it's a gen1. Ignore the result.
461
- pass
462
- # If the error is one we should let pass, raise it so the top level
463
- # error handler can take it.
@@ -49,13 +49,12 @@ class MagDeck(mod_abc.AbstractModule):
49
49
  port: str,
50
50
  usb_port: USBPort,
51
51
  hw_control_loop: asyncio.AbstractEventLoop,
52
- execution_manager: ExecutionManager,
53
- disconnected_callback: types.ModuleDisconnectedCallback,
54
- error_callback: types.ModuleErrorCallback,
52
+ execution_manager: Optional[ExecutionManager] = None,
55
53
  poll_interval_seconds: Optional[float] = None,
56
54
  simulating: bool = False,
57
55
  sim_model: Optional[str] = None,
58
56
  sim_serial_number: Optional[str] = None,
57
+ disconnected_callback: types.ModuleDisconnectedCallback = None,
59
58
  ) -> "MagDeck":
60
59
  """Factory function."""
61
60
  driver: AbstractMagDeckDriver
@@ -74,7 +73,6 @@ class MagDeck(mod_abc.AbstractModule):
74
73
  device_info=await driver.get_device_info(),
75
74
  driver=driver,
76
75
  disconnected_callback=disconnected_callback,
77
- error_callback=error_callback,
78
76
  )
79
77
  return mod
80
78
 
@@ -85,9 +83,8 @@ class MagDeck(mod_abc.AbstractModule):
85
83
  hw_control_loop: asyncio.AbstractEventLoop,
86
84
  driver: AbstractMagDeckDriver,
87
85
  device_info: Dict[str, str],
88
- execution_manager: ExecutionManager,
89
- disconnected_callback: types.ModuleDisconnectedCallback,
90
- error_callback: types.ModuleErrorCallback,
86
+ execution_manager: Optional[ExecutionManager] = None,
87
+ disconnected_callback: types.ModuleDisconnectedCallback = None,
91
88
  ) -> None:
92
89
  """Constructor"""
93
90
  super().__init__(
@@ -96,7 +93,6 @@ class MagDeck(mod_abc.AbstractModule):
96
93
  hw_control_loop=hw_control_loop,
97
94
  execution_manager=execution_manager,
98
95
  disconnected_callback=disconnected_callback,
99
- error_callback=error_callback,
100
96
  )
101
97
  self._device_info = device_info
102
98
  self._driver = driver
@@ -11,7 +11,6 @@ from ..execution_manager import ExecutionManager
11
11
  from .types import (
12
12
  BundledFirmware,
13
13
  ModuleDisconnectedCallback,
14
- ModuleErrorCallback,
15
14
  UploadFunction,
16
15
  LiveData,
17
16
  ModuleType,
@@ -48,13 +47,12 @@ class AbstractModule(abc.ABC):
48
47
  port: str,
49
48
  usb_port: USBPort,
50
49
  hw_control_loop: asyncio.AbstractEventLoop,
51
- execution_manager: ExecutionManager,
52
- disconnected_callback: ModuleDisconnectedCallback,
53
- error_callback: ModuleErrorCallback,
54
- poll_interval_seconds: float | None = None,
50
+ execution_manager: Optional[ExecutionManager] = None,
51
+ poll_interval_seconds: Optional[float] = None,
55
52
  simulating: bool = False,
56
53
  sim_model: Optional[str] = None,
57
54
  sim_serial_number: Optional[str] = None,
55
+ disconnected_callback: ModuleDisconnectedCallback = None,
58
56
  ) -> "AbstractModule":
59
57
  """Modules should always be created using this factory.
60
58
 
@@ -67,9 +65,8 @@ class AbstractModule(abc.ABC):
67
65
  port: str,
68
66
  usb_port: USBPort,
69
67
  hw_control_loop: asyncio.AbstractEventLoop,
70
- execution_manager: ExecutionManager,
71
- disconnected_callback: ModuleDisconnectedCallback,
72
- error_callback: ModuleErrorCallback,
68
+ execution_manager: Optional[ExecutionManager] = None,
69
+ disconnected_callback: ModuleDisconnectedCallback = None,
73
70
  ) -> None:
74
71
  self._port = port
75
72
  self._usb_port = usb_port
@@ -78,7 +75,6 @@ class AbstractModule(abc.ABC):
78
75
  self._bundled_fw: Optional[BundledFirmware] = self.get_bundled_fw()
79
76
  self._disconnected_callback = disconnected_callback
80
77
  self._updating = False
81
- self._error_callback = error_callback
82
78
 
83
79
  @staticmethod
84
80
  def sort_key(inst: "AbstractModule") -> int:
@@ -107,10 +103,6 @@ class AbstractModule(abc.ABC):
107
103
  if self._disconnected_callback is not None:
108
104
  self._disconnected_callback(self.port, self.serial_number)
109
105
 
110
- def error_callback(self, exc: Exception) -> None:
111
- """Called from within the module object when an asynchronous hardware error occurrs."""
112
- self._error_callback(exc, self.model(), self.port, self.serial_number)
113
-
114
106
  def get_bundled_fw(self) -> Optional[BundledFirmware]:
115
107
  """Get absolute path to bundled version of module fw if available."""
116
108
  if not IS_ROBOT:
@@ -2,11 +2,10 @@ from __future__ import annotations
2
2
 
3
3
  import asyncio
4
4
  import logging
5
- from typing import Dict, Optional, Callable
5
+ from typing import Dict, Optional
6
6
 
7
7
  from opentrons.hardware_control.modules.types import (
8
8
  ModuleDisconnectedCallback,
9
- ModuleErrorCallback,
10
9
  TemperatureStatus,
11
10
  )
12
11
  from opentrons.hardware_control.poller import Reader, Poller
@@ -39,13 +38,12 @@ class TempDeck(mod_abc.AbstractModule):
39
38
  port: str,
40
39
  usb_port: USBPort,
41
40
  hw_control_loop: asyncio.AbstractEventLoop,
42
- execution_manager: ExecutionManager,
43
- disconnected_callback: ModuleDisconnectedCallback,
44
- error_callback: ModuleErrorCallback,
41
+ execution_manager: Optional[ExecutionManager] = None,
45
42
  poll_interval_seconds: Optional[float] = None,
46
43
  simulating: bool = False,
47
44
  sim_model: Optional[str] = None,
48
45
  sim_serial_number: Optional[str] = None,
46
+ disconnected_callback: ModuleDisconnectedCallback = None,
49
47
  ) -> "TempDeck":
50
48
  """
51
49
  Build a TempDeck
@@ -85,7 +83,6 @@ class TempDeck(mod_abc.AbstractModule):
85
83
  device_info=await driver.get_device_info(),
86
84
  hw_control_loop=hw_control_loop,
87
85
  disconnected_callback=disconnected_callback,
88
- error_callback=error_callback,
89
86
  )
90
87
 
91
88
  try:
@@ -104,9 +101,8 @@ class TempDeck(mod_abc.AbstractModule):
104
101
  poller: Poller,
105
102
  device_info: Dict[str, str],
106
103
  hw_control_loop: asyncio.AbstractEventLoop,
107
- execution_manager: ExecutionManager,
108
- disconnected_callback: ModuleDisconnectedCallback,
109
- error_callback: ModuleErrorCallback,
104
+ execution_manager: Optional[ExecutionManager] = None,
105
+ disconnected_callback: ModuleDisconnectedCallback = None,
110
106
  ) -> None:
111
107
  """Constructor"""
112
108
  super().__init__(
@@ -115,13 +111,11 @@ class TempDeck(mod_abc.AbstractModule):
115
111
  hw_control_loop=hw_control_loop,
116
112
  execution_manager=execution_manager,
117
113
  disconnected_callback=disconnected_callback,
118
- error_callback=error_callback,
119
114
  )
120
115
  self._device_info = device_info
121
116
  self._driver = driver
122
117
  self._reader = reader
123
118
  self._poller = poller
124
- self._reader.set_error_callback(self.error_callback)
125
119
 
126
120
  async def cleanup(self) -> None:
127
121
  """Stop the poller task."""
@@ -299,21 +293,7 @@ class TempDeckReader(Reader):
299
293
  def __init__(self, driver: AbstractTempDeckDriver) -> None:
300
294
  self.temperature = Temperature(current=25, target=None)
301
295
  self._driver = driver
302
- self._error_callback: Optional[Callable[[Exception], None]] = None
303
296
 
304
297
  async def read(self) -> None:
305
298
  """Read the module's current and target temperatures."""
306
299
  self.temperature = await self._driver.get_temperature()
307
-
308
- def set_error_callback(
309
- self, error_callback: Callable[[Exception], None]
310
- ) -> Callable[[], None]:
311
- self._error_callback = error_callback
312
- return self._remove_error_callback
313
-
314
- def _remove_error_callback(self) -> None:
315
- self._error_callback = None
316
-
317
- def on_error(self, exception: Exception) -> None:
318
- if self._error_callback:
319
- self._error_callback(exception)
@@ -9,7 +9,6 @@ from opentrons.hardware_control.modules.lid_temp_status import LidTemperatureSta
9
9
  from opentrons.hardware_control.modules.plate_temp_status import PlateTemperatureStatus
10
10
  from opentrons.hardware_control.modules.types import (
11
11
  ModuleDisconnectedCallback,
12
- ModuleErrorCallback,
13
12
  TemperatureStatus,
14
13
  )
15
14
  from opentrons.hardware_control.poller import Reader, Poller
@@ -22,7 +21,6 @@ from opentrons.drivers.thermocycler import (
22
21
  ThermocyclerDriverV2,
23
22
  ThermocyclerDriverFactory,
24
23
  )
25
- from opentrons.drivers.asyncio.communication.errors import UnhandledGcode
26
24
 
27
25
 
28
26
  log = logging.getLogger(__name__)
@@ -38,8 +36,6 @@ DFU_PID = "df11"
38
36
  _TC_PLATE_LIFT_OPEN_DEGREES = 20
39
37
  _TC_PLATE_LIFT_RETURN_DEGREES = 23
40
38
 
41
- _TC_RAMP_RATE_ADDED_VERSION = (1, 0, 8) # v1.0.8
42
-
43
39
 
44
40
  class ThermocyclerError(Exception):
45
41
  pass
@@ -66,13 +62,12 @@ class Thermocycler(mod_abc.AbstractModule):
66
62
  port: str,
67
63
  usb_port: USBPort,
68
64
  hw_control_loop: asyncio.AbstractEventLoop,
69
- execution_manager: ExecutionManager,
70
- disconnected_callback: ModuleDisconnectedCallback,
71
- error_callback: ModuleErrorCallback,
65
+ execution_manager: Optional[ExecutionManager] = None,
72
66
  poll_interval_seconds: Optional[float] = None,
73
67
  simulating: bool = False,
74
68
  sim_model: Optional[str] = None,
75
69
  sim_serial_number: Optional[str] = None,
70
+ disconnected_callback: ModuleDisconnectedCallback = None,
76
71
  ) -> "Thermocycler":
77
72
  """
78
73
  Build and connect to a Thermocycler
@@ -113,7 +108,6 @@ class Thermocycler(mod_abc.AbstractModule):
113
108
  hw_control_loop=hw_control_loop,
114
109
  execution_manager=execution_manager,
115
110
  disconnected_callback=disconnected_callback,
116
- error_callback=error_callback,
117
111
  )
118
112
 
119
113
  try:
@@ -132,9 +126,8 @@ class Thermocycler(mod_abc.AbstractModule):
132
126
  poller: Poller,
133
127
  device_info: Dict[str, str],
134
128
  hw_control_loop: asyncio.AbstractEventLoop,
135
- execution_manager: ExecutionManager,
136
- disconnected_callback: ModuleDisconnectedCallback,
137
- error_callback: ModuleErrorCallback,
129
+ execution_manager: Optional[ExecutionManager] = None,
130
+ disconnected_callback: ModuleDisconnectedCallback = None,
138
131
  ) -> None:
139
132
  """
140
133
  Constructor
@@ -157,7 +150,6 @@ class Thermocycler(mod_abc.AbstractModule):
157
150
  hw_control_loop=hw_control_loop,
158
151
  execution_manager=execution_manager,
159
152
  disconnected_callback=disconnected_callback,
160
- error_callback=error_callback,
161
153
  )
162
154
  self._device_info = device_info
163
155
  self._reader = reader
@@ -167,13 +159,10 @@ class Thermocycler(mod_abc.AbstractModule):
167
159
  self._total_step_count: Optional[int] = None
168
160
  self._current_step_index: Optional[int] = None
169
161
  self._error: Optional[str] = None
170
- self._unsubscribe_reader = self._reader.register_error_handler(
171
- self._enter_error_state
172
- )
162
+ self._reader.register_error_handler(self._enter_error_state)
173
163
 
174
164
  async def cleanup(self) -> None:
175
165
  """Stop the poller task."""
176
- self._unsubscribe_reader()
177
166
  await self._poller.stop()
178
167
  await self._driver.disconnect()
179
168
 
@@ -276,19 +265,6 @@ class Thermocycler(mod_abc.AbstractModule):
276
265
  await self.open()
277
266
  await self._wait_for_lid_status(ThermocyclerLidStatus.OPEN)
278
267
 
279
- def can_use_ramp_rate(self) -> bool:
280
- version_string = self._device_info.get("version", "v")
281
- if version_string.startswith("v"):
282
- version_string = version_string[1:]
283
- try:
284
- version_tuple = tuple(int(c) for c in version_string.split("."))
285
- return version_tuple >= _TC_RAMP_RATE_ADDED_VERSION
286
- except (ValueError, IndexError):
287
- log.error(
288
- f"Invalid version from device: {self._device_info.get('version', '')}"
289
- )
290
- return False
291
-
292
268
  async def set_temperature(
293
269
  self,
294
270
  temperature: float,
@@ -314,11 +290,6 @@ class Thermocycler(mod_abc.AbstractModule):
314
290
 
315
291
  Returns: None
316
292
  """
317
- if ramp_rate and not self.can_use_ramp_rate():
318
- raise ThermocyclerError(
319
- "Ramp rate is not supported by this thermocycler's firmware version, please update."
320
- )
321
-
322
293
  await self.wait_for_is_running()
323
294
  await self._set_temperature_no_pause(
324
295
  temperature=temperature,
@@ -341,13 +312,11 @@ class Thermocycler(mod_abc.AbstractModule):
341
312
  total_seconds = seconds + (minutes * 60)
342
313
  hold_time = total_seconds if total_seconds > 0 else 0
343
314
 
344
- if ramp_rate and not self.can_use_ramp_rate():
345
- raise ThermocyclerError(
346
- "Ramp rate is not supported by this thermocycler's firmware version, please update."
347
- )
315
+ if ramp_rate is not None:
316
+ await self._driver.set_ramp_rate(ramp_rate=ramp_rate)
348
317
 
349
318
  await self._driver.set_plate_temperature(
350
- temp=temperature, hold_time=hold_time, volume=volume, ramp_rate=ramp_rate
319
+ temp=temperature, hold_time=hold_time, volume=volume
351
320
  )
352
321
 
353
322
  task = self._loop.create_task(self._wait_for_block_target())
@@ -450,7 +419,6 @@ class Thermocycler(mod_abc.AbstractModule):
450
419
  celsius: float,
451
420
  hold_time_seconds: Optional[float] = None,
452
421
  volume: Optional[float] = None,
453
- ramp_rate: Optional[float] = None,
454
422
  ) -> None:
455
423
  """Set the Thermocycler's target block temperature.
456
424
 
@@ -460,17 +428,10 @@ class Thermocycler(mod_abc.AbstractModule):
460
428
  celsius: The target block temperature, in degrees celsius.
461
429
  """
462
430
  await self.wait_for_is_running()
463
-
464
- if ramp_rate and not self.can_use_ramp_rate():
465
- raise ThermocyclerError(
466
- "Ramp rate is not supported by this thermocycler's firmware version, please update."
467
- )
468
-
469
431
  await self._driver.set_plate_temperature(
470
432
  temp=celsius,
471
433
  hold_time=hold_time_seconds,
472
434
  volume=volume,
473
- ramp_rate=ramp_rate,
474
435
  )
475
436
  await self._reader.read_block_temperature()
476
437
 
@@ -635,12 +596,11 @@ class Thermocycler(mod_abc.AbstractModule):
635
596
  temperature = step.get("temperature")
636
597
  hold_time_minutes = step.get("hold_time_minutes", None)
637
598
  hold_time_seconds = step.get("hold_time_seconds", None)
638
- ramp_rate = step.get("ramp_rate", None)
639
599
  await self._set_temperature_no_pause(
640
600
  temperature=temperature, # type: ignore
641
601
  hold_time_minutes=hold_time_minutes,
642
602
  hold_time_seconds=hold_time_seconds,
643
- ramp_rate=ramp_rate,
603
+ ramp_rate=None,
644
604
  volume=volume,
645
605
  )
646
606
 
@@ -712,7 +672,7 @@ class Thermocycler(mod_abc.AbstractModule):
712
672
  f"https://support.opentrons.com/en/articles/3469797-thermocycler-module"
713
673
  f" for troubleshooting."
714
674
  )
715
- self.error_callback(error)
675
+ asyncio.run_coroutine_threadsafe(self.cleanup(), self._loop)
716
676
 
717
677
 
718
678
  class ThermocyclerReader(Reader):
@@ -750,31 +710,14 @@ class ThermocyclerReader(Reader):
750
710
  if self._handle_error is not None:
751
711
  self._handle_error(exception)
752
712
 
753
- def register_error_handler(
754
- self, handle_error: Callable[[Exception], None]
755
- ) -> Callable[[], None]:
713
+ def register_error_handler(self, handle_error: Callable[[Exception], None]) -> None:
756
714
  self._handle_error = handle_error
757
- return self._unsubscribe_error_handler
758
-
759
- def _unsubscribe_error_handler(self) -> None:
760
- self._handle_error = None
761
715
 
762
716
  async def read(self) -> None:
763
717
  """Poll the thermocycler."""
764
718
  await self.read_lid_status()
765
719
  await self.read_lid_temperature()
766
720
  await self.read_block_temperature()
767
- await self._read_errors()
768
-
769
- async def _read_errors(self) -> None:
770
- try:
771
- await self._driver.get_error_state()
772
- except UnhandledGcode:
773
- # This device's firmware cannot accept this command, because it
774
- # hasn't been updated or because it's a gen1. Ignore the result.
775
- pass
776
- # If the error is one we should let pass, raise it so the top level
777
- # error handler can take it.
778
721
 
779
722
  async def read_lid_status(self) -> None:
780
723
  self.lid_status = await self._driver.get_lid_status()
@@ -11,7 +11,6 @@ from typing import (
11
11
  Awaitable,
12
12
  Union,
13
13
  Optional,
14
- Protocol,
15
14
  cast,
16
15
  TYPE_CHECKING,
17
16
  TypeGuard,
@@ -45,7 +44,6 @@ class ThermocyclerStepBase(TypedDict):
45
44
  class ThermocyclerStep(ThermocyclerStepBase, total=False):
46
45
  hold_time_seconds: float
47
46
  hold_time_minutes: float
48
- ramp_rate: Optional[float]
49
47
 
50
48
 
51
49
  class ThermocyclerCycle(TypedDict):
@@ -56,24 +54,7 @@ class ThermocyclerCycle(TypedDict):
56
54
  UploadFunction = Callable[[str, str, Dict[str, Any]], Awaitable[Tuple[bool, str]]]
57
55
 
58
56
 
59
- class ModuleDisconnectedCallback(Protocol):
60
- """Protocol for the callback when the module should be disconnected."""
61
-
62
- def __call__(self, port: str, serial: str | None) -> None:
63
- ...
64
-
65
-
66
- class ModuleErrorCallback(Protocol):
67
- """Protocol for the callback when the module sees a hardware error."""
68
-
69
- def __call__(
70
- self,
71
- exc: Exception,
72
- model: str,
73
- port: str,
74
- serial: str | None,
75
- ) -> None:
76
- ...
57
+ ModuleDisconnectedCallback = Optional[Callable[[str, str | None], None]]
77
58
 
78
59
 
79
60
  class MagneticModuleData(TypedDict):
@@ -6,12 +6,7 @@ from opentrons.drivers.rpi_drivers.types import USBPort
6
6
 
7
7
  from ..execution_manager import ExecutionManager
8
8
 
9
- from .types import (
10
- ModuleDisconnectedCallback,
11
- ModuleType,
12
- SpeedStatus,
13
- ModuleErrorCallback,
14
- )
9
+ from .types import ModuleDisconnectedCallback, ModuleType, SpeedStatus
15
10
  from .mod_abc import AbstractModule
16
11
  from .tempdeck import TempDeck
17
12
  from .magdeck import MagDeck
@@ -51,11 +46,10 @@ async def build(
51
46
  simulating: bool,
52
47
  usb_port: USBPort,
53
48
  hw_control_loop: asyncio.AbstractEventLoop,
54
- execution_manager: ExecutionManager,
55
- disconnected_callback: ModuleDisconnectedCallback,
56
- error_callback: ModuleErrorCallback,
49
+ execution_manager: Optional[ExecutionManager] = None,
57
50
  sim_model: Optional[str] = None,
58
51
  sim_serial_number: Optional[str] = None,
52
+ disconnected_callback: ModuleDisconnectedCallback = None,
59
53
  ) -> AbstractModule:
60
54
  return await _MODULE_CLS_BY_TYPE[type].build(
61
55
  port=port,
@@ -63,10 +57,9 @@ async def build(
63
57
  simulating=simulating,
64
58
  hw_control_loop=hw_control_loop,
65
59
  execution_manager=execution_manager,
66
- disconnected_callback=disconnected_callback,
67
- error_callback=error_callback,
68
60
  sim_model=sim_model,
69
61
  sim_serial_number=sim_serial_number,
62
+ disconnected_callback=disconnected_callback,
70
63
  )
71
64
 
72
65
 
@@ -77,8 +77,6 @@ class NozzleMap:
77
77
  #: A map of all of the nozzles of an instrument
78
78
  full_instrument_rows: Dict[str, List[str]]
79
79
  #: A map of all the rows of an instrument
80
- full_instrument_columns: Dict[str, List[str]]
81
- #: A map of all the columns of an instrument
82
80
 
83
81
  @classmethod
84
82
  def determine_nozzle_configuration(
@@ -301,7 +299,6 @@ class NozzleMap:
301
299
  rows=rows,
302
300
  full_instrument_map_store=physical_nozzles,
303
301
  full_instrument_rows=physical_rows,
304
- full_instrument_columns=physical_columns,
305
302
  columns=columns,
306
303
  configuration=cls.determine_nozzle_configuration(
307
304
  physical_rows, rows, physical_columns, columns