opentrons 8.7.0a9__py3-none-any.whl → 8.8.0a8__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.
Files changed (190) hide show
  1. opentrons/_version.py +2 -2
  2. opentrons/cli/analyze.py +4 -1
  3. opentrons/config/__init__.py +7 -0
  4. opentrons/drivers/asyncio/communication/serial_connection.py +126 -49
  5. opentrons/drivers/heater_shaker/abstract.py +5 -0
  6. opentrons/drivers/heater_shaker/driver.py +10 -0
  7. opentrons/drivers/heater_shaker/simulator.py +4 -0
  8. opentrons/drivers/thermocycler/abstract.py +6 -0
  9. opentrons/drivers/thermocycler/driver.py +61 -10
  10. opentrons/drivers/thermocycler/simulator.py +6 -0
  11. opentrons/drivers/vacuum_module/__init__.py +5 -0
  12. opentrons/drivers/vacuum_module/abstract.py +93 -0
  13. opentrons/drivers/vacuum_module/driver.py +208 -0
  14. opentrons/drivers/vacuum_module/errors.py +39 -0
  15. opentrons/drivers/vacuum_module/simulator.py +85 -0
  16. opentrons/drivers/vacuum_module/types.py +79 -0
  17. opentrons/execute.py +3 -0
  18. opentrons/hardware_control/api.py +24 -5
  19. opentrons/hardware_control/backends/controller.py +8 -2
  20. opentrons/hardware_control/backends/flex_protocol.py +1 -0
  21. opentrons/hardware_control/backends/ot3controller.py +35 -2
  22. opentrons/hardware_control/backends/ot3simulator.py +3 -1
  23. opentrons/hardware_control/backends/ot3utils.py +37 -0
  24. opentrons/hardware_control/backends/simulator.py +2 -1
  25. opentrons/hardware_control/backends/subsystem_manager.py +5 -2
  26. opentrons/hardware_control/emulation/abstract_emulator.py +6 -4
  27. opentrons/hardware_control/emulation/connection_handler.py +8 -5
  28. opentrons/hardware_control/emulation/heater_shaker.py +12 -3
  29. opentrons/hardware_control/emulation/settings.py +1 -1
  30. opentrons/hardware_control/emulation/thermocycler.py +67 -15
  31. opentrons/hardware_control/module_control.py +105 -10
  32. opentrons/hardware_control/modules/__init__.py +3 -0
  33. opentrons/hardware_control/modules/absorbance_reader.py +11 -4
  34. opentrons/hardware_control/modules/flex_stacker.py +38 -9
  35. opentrons/hardware_control/modules/heater_shaker.py +42 -5
  36. opentrons/hardware_control/modules/magdeck.py +8 -4
  37. opentrons/hardware_control/modules/mod_abc.py +14 -6
  38. opentrons/hardware_control/modules/tempdeck.py +25 -5
  39. opentrons/hardware_control/modules/thermocycler.py +68 -11
  40. opentrons/hardware_control/modules/types.py +20 -1
  41. opentrons/hardware_control/modules/utils.py +11 -4
  42. opentrons/hardware_control/motion_utilities.py +6 -6
  43. opentrons/hardware_control/nozzle_manager.py +3 -0
  44. opentrons/hardware_control/ot3api.py +92 -17
  45. opentrons/hardware_control/poller.py +22 -8
  46. opentrons/hardware_control/protocols/liquid_handler.py +12 -4
  47. opentrons/hardware_control/scripts/update_module_fw.py +5 -0
  48. opentrons/hardware_control/types.py +43 -2
  49. opentrons/legacy_commands/commands.py +58 -5
  50. opentrons/legacy_commands/module_commands.py +52 -0
  51. opentrons/legacy_commands/protocol_commands.py +53 -1
  52. opentrons/legacy_commands/types.py +155 -1
  53. opentrons/motion_planning/deck_conflict.py +17 -12
  54. opentrons/motion_planning/waypoints.py +15 -29
  55. opentrons/protocol_api/__init__.py +5 -1
  56. opentrons/protocol_api/_transfer_liquid_validation.py +17 -2
  57. opentrons/protocol_api/_types.py +8 -1
  58. opentrons/protocol_api/core/common.py +3 -1
  59. opentrons/protocol_api/core/engine/_default_labware_versions.py +33 -11
  60. opentrons/protocol_api/core/engine/deck_conflict.py +3 -1
  61. opentrons/protocol_api/core/engine/instrument.py +109 -26
  62. opentrons/protocol_api/core/engine/labware.py +8 -1
  63. opentrons/protocol_api/core/engine/module_core.py +95 -4
  64. opentrons/protocol_api/core/engine/pipette_movement_conflict.py +4 -18
  65. opentrons/protocol_api/core/engine/protocol.py +51 -2
  66. opentrons/protocol_api/core/engine/stringify.py +2 -0
  67. opentrons/protocol_api/core/engine/tasks.py +48 -0
  68. opentrons/protocol_api/core/engine/well.py +8 -0
  69. opentrons/protocol_api/core/instrument.py +19 -2
  70. opentrons/protocol_api/core/legacy/legacy_instrument_core.py +19 -2
  71. opentrons/protocol_api/core/legacy/legacy_module_core.py +33 -2
  72. opentrons/protocol_api/core/legacy/legacy_protocol_core.py +23 -1
  73. opentrons/protocol_api/core/legacy/legacy_well_core.py +4 -0
  74. opentrons/protocol_api/core/legacy/tasks.py +19 -0
  75. opentrons/protocol_api/core/legacy_simulator/legacy_instrument_core.py +19 -2
  76. opentrons/protocol_api/core/legacy_simulator/legacy_protocol_core.py +14 -2
  77. opentrons/protocol_api/core/legacy_simulator/tasks.py +19 -0
  78. opentrons/protocol_api/core/module.py +58 -2
  79. opentrons/protocol_api/core/protocol.py +23 -2
  80. opentrons/protocol_api/core/tasks.py +31 -0
  81. opentrons/protocol_api/core/well.py +4 -0
  82. opentrons/protocol_api/instrument_context.py +388 -2
  83. opentrons/protocol_api/labware.py +10 -2
  84. opentrons/protocol_api/module_contexts.py +170 -6
  85. opentrons/protocol_api/protocol_context.py +87 -21
  86. opentrons/protocol_api/robot_context.py +41 -25
  87. opentrons/protocol_api/tasks.py +48 -0
  88. opentrons/protocol_api/validation.py +49 -3
  89. opentrons/protocol_engine/__init__.py +4 -0
  90. opentrons/protocol_engine/actions/__init__.py +6 -2
  91. opentrons/protocol_engine/actions/actions.py +31 -9
  92. opentrons/protocol_engine/clients/sync_client.py +42 -7
  93. opentrons/protocol_engine/commands/__init__.py +56 -0
  94. opentrons/protocol_engine/commands/absorbance_reader/close_lid.py +2 -15
  95. opentrons/protocol_engine/commands/absorbance_reader/open_lid.py +2 -15
  96. opentrons/protocol_engine/commands/absorbance_reader/read.py +22 -23
  97. opentrons/protocol_engine/commands/aspirate.py +1 -0
  98. opentrons/protocol_engine/commands/aspirate_while_tracking.py +52 -19
  99. opentrons/protocol_engine/commands/capture_image.py +302 -0
  100. opentrons/protocol_engine/commands/command.py +2 -0
  101. opentrons/protocol_engine/commands/command_unions.py +62 -0
  102. opentrons/protocol_engine/commands/create_timer.py +83 -0
  103. opentrons/protocol_engine/commands/dispense.py +1 -0
  104. opentrons/protocol_engine/commands/dispense_while_tracking.py +56 -19
  105. opentrons/protocol_engine/commands/drop_tip.py +32 -8
  106. opentrons/protocol_engine/commands/flex_stacker/common.py +35 -0
  107. opentrons/protocol_engine/commands/flex_stacker/set_stored_labware.py +7 -0
  108. opentrons/protocol_engine/commands/heater_shaker/__init__.py +14 -0
  109. opentrons/protocol_engine/commands/heater_shaker/common.py +20 -0
  110. opentrons/protocol_engine/commands/heater_shaker/set_and_wait_for_shake_speed.py +5 -4
  111. opentrons/protocol_engine/commands/heater_shaker/set_shake_speed.py +136 -0
  112. opentrons/protocol_engine/commands/heater_shaker/set_target_temperature.py +31 -5
  113. opentrons/protocol_engine/commands/move_labware.py +3 -4
  114. opentrons/protocol_engine/commands/move_to_addressable_area_for_drop_tip.py +1 -1
  115. opentrons/protocol_engine/commands/movement_common.py +31 -2
  116. opentrons/protocol_engine/commands/pick_up_tip.py +21 -11
  117. opentrons/protocol_engine/commands/pipetting_common.py +48 -3
  118. opentrons/protocol_engine/commands/set_tip_state.py +97 -0
  119. opentrons/protocol_engine/commands/temperature_module/set_target_temperature.py +38 -7
  120. opentrons/protocol_engine/commands/thermocycler/__init__.py +16 -0
  121. opentrons/protocol_engine/commands/thermocycler/run_extended_profile.py +6 -0
  122. opentrons/protocol_engine/commands/thermocycler/run_profile.py +8 -0
  123. opentrons/protocol_engine/commands/thermocycler/set_target_block_temperature.py +44 -7
  124. opentrons/protocol_engine/commands/thermocycler/set_target_lid_temperature.py +43 -14
  125. opentrons/protocol_engine/commands/thermocycler/start_run_extended_profile.py +191 -0
  126. opentrons/protocol_engine/commands/touch_tip.py +1 -1
  127. opentrons/protocol_engine/commands/unsafe/unsafe_place_labware.py +6 -22
  128. opentrons/protocol_engine/commands/wait_for_tasks.py +98 -0
  129. opentrons/protocol_engine/create_protocol_engine.py +12 -0
  130. opentrons/protocol_engine/engine_support.py +3 -0
  131. opentrons/protocol_engine/errors/__init__.py +12 -0
  132. opentrons/protocol_engine/errors/exceptions.py +119 -0
  133. opentrons/protocol_engine/execution/__init__.py +4 -0
  134. opentrons/protocol_engine/execution/command_executor.py +62 -1
  135. opentrons/protocol_engine/execution/create_queue_worker.py +9 -2
  136. opentrons/protocol_engine/execution/labware_movement.py +13 -15
  137. opentrons/protocol_engine/execution/movement.py +2 -0
  138. opentrons/protocol_engine/execution/pipetting.py +26 -25
  139. opentrons/protocol_engine/execution/queue_worker.py +4 -0
  140. opentrons/protocol_engine/execution/run_control.py +8 -0
  141. opentrons/protocol_engine/execution/task_handler.py +157 -0
  142. opentrons/protocol_engine/protocol_engine.py +137 -36
  143. opentrons/protocol_engine/resources/__init__.py +4 -0
  144. opentrons/protocol_engine/resources/camera_provider.py +110 -0
  145. opentrons/protocol_engine/resources/concurrency_provider.py +27 -0
  146. opentrons/protocol_engine/resources/deck_configuration_provider.py +7 -0
  147. opentrons/protocol_engine/resources/file_provider.py +133 -58
  148. opentrons/protocol_engine/resources/labware_validation.py +10 -6
  149. opentrons/protocol_engine/slot_standardization.py +2 -0
  150. opentrons/protocol_engine/state/_well_math.py +60 -18
  151. opentrons/protocol_engine/state/addressable_areas.py +2 -0
  152. opentrons/protocol_engine/state/camera.py +54 -0
  153. opentrons/protocol_engine/state/commands.py +37 -14
  154. opentrons/protocol_engine/state/geometry.py +276 -379
  155. opentrons/protocol_engine/state/labware.py +62 -108
  156. opentrons/protocol_engine/state/labware_origin_math/errors.py +94 -0
  157. opentrons/protocol_engine/state/labware_origin_math/stackup_origin_to_labware_origin.py +1336 -0
  158. opentrons/protocol_engine/state/module_substates/thermocycler_module_substate.py +37 -0
  159. opentrons/protocol_engine/state/modules.py +30 -8
  160. opentrons/protocol_engine/state/motion.py +60 -18
  161. opentrons/protocol_engine/state/preconditions.py +59 -0
  162. opentrons/protocol_engine/state/state.py +44 -0
  163. opentrons/protocol_engine/state/state_summary.py +4 -0
  164. opentrons/protocol_engine/state/tasks.py +139 -0
  165. opentrons/protocol_engine/state/tips.py +177 -258
  166. opentrons/protocol_engine/state/update_types.py +26 -9
  167. opentrons/protocol_engine/types/__init__.py +23 -4
  168. opentrons/protocol_engine/types/command_preconditions.py +18 -0
  169. opentrons/protocol_engine/types/deck_configuration.py +5 -1
  170. opentrons/protocol_engine/types/instrument.py +8 -1
  171. opentrons/protocol_engine/types/labware.py +1 -13
  172. opentrons/protocol_engine/types/location.py +26 -2
  173. opentrons/protocol_engine/types/module.py +11 -1
  174. opentrons/protocol_engine/types/tasks.py +38 -0
  175. opentrons/protocol_engine/types/tip.py +9 -0
  176. opentrons/protocol_runner/create_simulating_orchestrator.py +29 -2
  177. opentrons/protocol_runner/protocol_runner.py +14 -1
  178. opentrons/protocol_runner/run_orchestrator.py +49 -2
  179. opentrons/protocols/advanced_control/transfers/transfer_liquid_utils.py +2 -2
  180. opentrons/protocols/api_support/definitions.py +1 -1
  181. opentrons/protocols/api_support/types.py +2 -1
  182. opentrons/simulate.py +51 -15
  183. opentrons/system/camera.py +334 -4
  184. opentrons/system/ffmpeg.py +110 -0
  185. {opentrons-8.7.0a9.dist-info → opentrons-8.8.0a8.dist-info}/METADATA +4 -4
  186. {opentrons-8.7.0a9.dist-info → opentrons-8.8.0a8.dist-info}/RECORD +189 -161
  187. opentrons/protocol_engine/state/_labware_origin_math.py +0 -636
  188. {opentrons-8.7.0a9.dist-info → opentrons-8.8.0a8.dist-info}/WHEEL +0 -0
  189. {opentrons-8.7.0a9.dist-info → opentrons-8.8.0a8.dist-info}/entry_points.txt +0 -0
  190. {opentrons-8.7.0a9.dist-info → opentrons-8.8.0a8.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,48 @@
1
+ """Data for concurrent protocol tasks."""
2
+ from typing import TYPE_CHECKING
3
+ from datetime import datetime
4
+ from opentrons.protocols.api_support.util import requires_version
5
+ from opentrons.protocols.api_support.types import APIVersion
6
+
7
+ if TYPE_CHECKING:
8
+ from .core.common import TaskCore
9
+
10
+
11
+ class Task:
12
+ """A concurrent protocol task created by a protocol API function.
13
+
14
+ .. versionadded:: 2.27
15
+ """
16
+
17
+ def __init__(self, core: "TaskCore", api_version: APIVersion) -> None:
18
+ """Initialize a Task."""
19
+ self._core = core
20
+ self._api_version = api_version
21
+
22
+ @property
23
+ @requires_version(2, 27)
24
+ def created_at(self) -> datetime:
25
+ """The timestamp of when the task was created."""
26
+ return self._core.get_created_at_timestamp()
27
+
28
+ @property
29
+ @requires_version(2, 27)
30
+ def done(self) -> bool:
31
+ """Returns ``True`` if the task is done."""
32
+ return self._core.is_done()
33
+
34
+ @property
35
+ @requires_version(2, 27)
36
+ def started(self) -> bool:
37
+ """Returns ``True`` if the task has started."""
38
+ return self._core.is_started()
39
+ ...
40
+
41
+ @property
42
+ @requires_version(2, 27)
43
+ def finished_at(self) -> datetime | None:
44
+ """The timestamp of the when the task finished.
45
+
46
+ Returns ``None`` if the task hasn't finished yet.
47
+ """
48
+ return self._core.get_finished_at_timestamp()
@@ -99,11 +99,18 @@ class InvalidFixtureLocationError(ValueError):
99
99
  """An error raised when attempting to load a fixture in an invalid cutout."""
100
100
 
101
101
 
102
+ def is_pipette_96_channel(pipette: Optional[PipetteNameType]) -> bool:
103
+ """Return if this pipette type is a 96 channel."""
104
+ if pipette is not None:
105
+ return pipette in [PipetteNameType.P1000_96, PipetteNameType.P200_96]
106
+ return False
107
+
108
+
102
109
  def ensure_mount_for_pipette(
103
110
  mount: Union[str, Mount, None], pipette: PipetteNameType
104
111
  ) -> Mount:
105
112
  """Ensure that an input value represents a valid mount, and is valid for the given pipette."""
106
- if pipette in [PipetteNameType.P1000_96, PipetteNameType.P200_96]:
113
+ if is_pipette_96_channel(pipette):
107
114
  # Always validate the raw mount input, even if the pipette is a 96-channel and we're not going
108
115
  # to use the mount value.
109
116
  if mount is not None:
@@ -370,7 +377,7 @@ def ensure_definition_is_not_lid_after_api_version(
370
377
  and api_version >= LID_STACK_VERSION_GATE
371
378
  ):
372
379
  raise APIVersionError(
373
- f"Labware Lids cannot be loaded like standard labware in Protocols written with an API version greater than {LID_STACK_VERSION_GATE}."
380
+ f"Labware Lids cannot be loaded like standard labware in Protocols written with an API version of {LID_STACK_VERSION_GATE} or higher."
374
381
  )
375
382
 
376
383
 
@@ -489,6 +496,7 @@ def ensure_thermocycler_profile_steps(
489
496
  temperature = step.get("temperature")
490
497
  hold_mins = step.get("hold_time_minutes")
491
498
  hold_secs = step.get("hold_time_seconds")
499
+ ramp_rate = step.get("ramp_rate")
492
500
  if temperature is None:
493
501
  raise ValueError("temperature must be defined for each step in cycle")
494
502
  if hold_mins is None and hold_secs is None:
@@ -496,10 +504,14 @@ def ensure_thermocycler_profile_steps(
496
504
  "either hold_time_minutes or hold_time_seconds must be"
497
505
  "defined for each step in cycle"
498
506
  )
507
+ if ramp_rate is not None and ramp_rate <= 0:
508
+ raise ValueError("Ramp rate must be greater than 0.")
499
509
  validated_seconds = ensure_hold_time_seconds(hold_secs, hold_mins)
500
510
  validated_steps.append(
501
511
  ThermocyclerStep(
502
- temperature=temperature, hold_time_seconds=validated_seconds
512
+ temperature=temperature,
513
+ hold_time_seconds=validated_seconds,
514
+ ramp_rate=ramp_rate,
503
515
  )
504
516
  )
505
517
  return validated_steps
@@ -565,6 +577,40 @@ class LocationTypeError(TypeError):
565
577
  ValidTarget = Union[WellTarget, PointTarget, DisposalTarget]
566
578
 
567
579
 
580
+ def validate_dynamic_locations(
581
+ location: Optional[Union[Location, Well, TrashBin, WasteChute]],
582
+ end_location: Location,
583
+ ) -> None:
584
+ """Given that we have an end_location we check that they're a vaild dynamic pair."""
585
+ if location is None:
586
+ raise ValueError("Location must be supplied if using an End Location.")
587
+ if not isinstance(location, Location):
588
+ raise ValueError(
589
+ "Location must be a point within a well when dynamic pipetting."
590
+ )
591
+ # Shouldn't be true ever if using typing but a customer protocol may not check
592
+ if not isinstance(end_location, Location):
593
+ raise ValueError(
594
+ "End location must be a point within a well when dynamic pipetting."
595
+ )
596
+ if not location.labware.is_well:
597
+ raise ValueError("Start location must be within a well when dynamic pipetting")
598
+ if not end_location.labware.is_well:
599
+ raise ValueError("End location must be within a well when dynamic pipetting")
600
+ (
601
+ _,
602
+ start_well,
603
+ ) = location.labware.get_parent_labware_and_well()
604
+ (
605
+ _,
606
+ end_well,
607
+ ) = end_location.labware.get_parent_labware_and_well()
608
+ if start_well != end_well:
609
+ raise ValueError(
610
+ "Start and end locations must be within the same well when dynamic pipetting"
611
+ )
612
+
613
+
568
614
  def validate_location(
569
615
  location: Optional[Union[Location, Well, TrashBin, WasteChute]],
570
616
  last_location: Optional[Union[Location, TrashBin, WasteChute]],
@@ -41,6 +41,8 @@ from .types import (
41
41
  DeckType,
42
42
  DeckSlotLocation,
43
43
  InStackerHopperLocation,
44
+ WASTE_CHUTE_LOCATION,
45
+ AccessibleByGripperLocation,
44
46
  ModuleLocation,
45
47
  OnLabwareLocation,
46
48
  AddressableAreaLocation,
@@ -120,6 +122,8 @@ __all__ = [
120
122
  "ModuleLocation",
121
123
  "OnLabwareLocation",
122
124
  "AddressableAreaLocation",
125
+ "WASTE_CHUTE_LOCATION",
126
+ "AccessibleByGripperLocation",
123
127
  "InStackerHopperLocation",
124
128
  "OFF_DECK_LOCATION",
125
129
  "SYSTEM_LOCATION",
@@ -21,13 +21,15 @@ from .actions import (
21
21
  AddLabwareOffsetAction,
22
22
  AddLabwareDefinitionAction,
23
23
  AddLiquidAction,
24
+ AddCameraSettingsAction,
24
25
  SetDeckConfigurationAction,
25
26
  AddAddressableAreaAction,
26
27
  AddModuleAction,
27
28
  FinishErrorDetails,
28
29
  DoorChangeAction,
29
- ResetTipsAction,
30
30
  SetPipetteMovementSpeedAction,
31
+ StartTaskAction,
32
+ FinishTaskAction,
31
33
  )
32
34
  from .get_state_update import get_state_updates
33
35
 
@@ -50,13 +52,15 @@ __all__ = [
50
52
  "FailCommandAction",
51
53
  "AddLabwareOffsetAction",
52
54
  "AddLabwareDefinitionAction",
55
+ "AddCameraSettingsAction",
53
56
  "AddLiquidAction",
54
57
  "SetDeckConfigurationAction",
55
58
  "AddAddressableAreaAction",
56
59
  "AddModuleAction",
57
60
  "DoorChangeAction",
58
- "ResetTipsAction",
59
61
  "SetPipetteMovementSpeedAction",
62
+ "StartTaskAction",
63
+ "FinishTaskAction",
60
64
  # action payload values
61
65
  "PauseSource",
62
66
  "FinishErrorDetails",
@@ -3,6 +3,7 @@
3
3
  Actions can be passed to the ActionDispatcher, where they will trigger
4
4
  reactions in objects that subscribe to the pipeline, like the StateStore.
5
5
  """
6
+
6
7
  import dataclasses
7
8
  from datetime import datetime
8
9
  from enum import Enum
@@ -20,13 +21,16 @@ from ..commands import (
20
21
  CommandDefinedErrorData,
21
22
  )
22
23
  from ..error_recovery_policy import ErrorRecoveryPolicy, ErrorRecoveryType
24
+ from ..errors import ErrorOccurrence
23
25
  from ..notes.notes import CommandNote
24
26
  from ..state.update_types import StateUpdate
27
+ from ..resources.camera_provider import CameraSettings
25
28
  from ..types import (
26
29
  LabwareOffsetCreateInternal,
27
30
  ModuleDefinition,
28
31
  Liquid,
29
32
  DeckConfigurationType,
33
+ Task,
30
34
  )
31
35
 
32
36
 
@@ -60,7 +64,7 @@ class PauseAction:
60
64
  class StopAction:
61
65
  """Request engine execution to stop soon."""
62
66
 
63
- from_estop: bool = False
67
+ from_asynchronous_error: bool = False
64
68
 
65
69
 
66
70
  @dataclasses.dataclass(frozen=True)
@@ -201,6 +205,22 @@ class FailCommandAction:
201
205
  """The command to fail, in its prior `running` state."""
202
206
 
203
207
 
208
+ @dataclasses.dataclass(frozen=True)
209
+ class StartTaskAction:
210
+ """Store new task in state."""
211
+
212
+ task: Task
213
+
214
+
215
+ @dataclasses.dataclass(frozen=True)
216
+ class FinishTaskAction:
217
+ """Mark task as finished in state."""
218
+
219
+ task_id: str
220
+ finished_at: datetime
221
+ error: ErrorOccurrence | None
222
+
223
+
204
224
  @dataclasses.dataclass(frozen=True)
205
225
  class AddLabwareOffsetAction:
206
226
  """Add a labware offset, to apply to subsequent `LoadLabwareCommand`s."""
@@ -217,6 +237,13 @@ class AddLabwareDefinitionAction:
217
237
  definition: LabwareDefinition
218
238
 
219
239
 
240
+ @dataclasses.dataclass(frozen=True)
241
+ class AddCameraSettingsAction:
242
+ """Add Camera settings to be used in place of the Camera Provider accessible settings."""
243
+
244
+ enablement_settings: CameraSettings
245
+
246
+
220
247
  @dataclasses.dataclass(frozen=True)
221
248
  class AddLiquidAction:
222
249
  """Add a liquid, to apply to subsequent `LoadLiquid`s."""
@@ -253,13 +280,6 @@ class AddModuleAction:
253
280
  module_live_data: LiveData
254
281
 
255
282
 
256
- @dataclasses.dataclass(frozen=True)
257
- class ResetTipsAction:
258
- """Reset the tip tracking state of a given tip rack."""
259
-
260
- labware_id: str
261
-
262
-
263
283
  @dataclasses.dataclass(frozen=True)
264
284
  class SetPipetteMovementSpeedAction:
265
285
  """Set the speed of a pipette's X/Y/Z movements. Does not affect plunger speed.
@@ -293,10 +313,12 @@ Action = Union[
293
313
  AddLabwareOffsetAction,
294
314
  AddLabwareDefinitionAction,
295
315
  AddModuleAction,
316
+ AddCameraSettingsAction,
296
317
  SetDeckConfigurationAction,
297
318
  AddAddressableAreaAction,
298
319
  AddLiquidAction,
299
- ResetTipsAction,
300
320
  SetPipetteMovementSpeedAction,
301
321
  SetErrorRecoveryPolicyAction,
322
+ StartTaskAction,
323
+ FinishTaskAction,
302
324
  ]
@@ -65,6 +65,48 @@ class SyncClient:
65
65
  ) -> commands.LoadLabwareResult:
66
66
  pass
67
67
 
68
+ @overload
69
+ def execute_command_without_recovery(
70
+ self, params: commands.CreateTimerParams
71
+ ) -> commands.CreateTimerResult:
72
+ pass
73
+
74
+ @overload
75
+ def execute_command_without_recovery(
76
+ self, params: commands.temperature_module.SetTargetTemperatureParams
77
+ ) -> commands.temperature_module.SetTargetTemperatureResult:
78
+ pass
79
+
80
+ @overload
81
+ def execute_command_without_recovery(
82
+ self, params: commands.thermocycler.StartRunExtendedProfileParams
83
+ ) -> commands.thermocycler.StartRunExtendedProfileResult:
84
+ pass
85
+
86
+ @overload
87
+ def execute_command_without_recovery(
88
+ self, params: commands.heater_shaker.SetTargetTemperatureParams
89
+ ) -> commands.heater_shaker.SetTargetTemperatureResult:
90
+ pass
91
+
92
+ @overload
93
+ def execute_command_without_recovery(
94
+ self, params: commands.heater_shaker.SetShakeSpeedParams
95
+ ) -> commands.heater_shaker.SetShakeSpeedResult:
96
+ pass
97
+
98
+ @overload
99
+ def execute_command_without_recovery(
100
+ self, params: commands.thermocycler.SetTargetBlockTemperatureParams
101
+ ) -> commands.thermocycler.SetTargetBlockTemperatureResult:
102
+ pass
103
+
104
+ @overload
105
+ def execute_command_without_recovery(
106
+ self, params: commands.thermocycler.SetTargetLidTemperatureParams
107
+ ) -> commands.thermocycler.SetTargetLidTemperatureResult:
108
+ pass
109
+
68
110
  @overload
69
111
  def execute_command_without_recovery(
70
112
  self, params: commands.LoadModuleParams
@@ -149,13 +191,6 @@ class SyncClient:
149
191
  """Add a liquid to the engine."""
150
192
  return self._transport.call_method("add_liquid", name=name, color=color, description=description) # type: ignore[no-any-return]
151
193
 
152
- def reset_tips(self, labware_id: str) -> None:
153
- """Reset a labware's tip tracking state.."""
154
- self._transport.call_method(
155
- "reset_tips",
156
- labware_id=labware_id,
157
- )
158
-
159
194
  def add_labware_offset(self, request: LabwareOffsetCreate) -> None:
160
195
  """Add a labware offset."""
161
196
  self._transport.call_method("add_labware_offset", request=request)
@@ -271,6 +271,22 @@ from .wait_for_duration import (
271
271
  WaitForDurationCommandType,
272
272
  )
273
273
 
274
+ from .create_timer import (
275
+ CreateTimer,
276
+ CreateTimerCreate,
277
+ CreateTimerParams,
278
+ CreateTimerResult,
279
+ CreateTimerCommandType,
280
+ )
281
+
282
+ from .wait_for_tasks import (
283
+ WaitForTasks,
284
+ WaitForTasksCreate,
285
+ WaitForTasksParams,
286
+ WaitForTasksResult,
287
+ WaitForTasksCommandType,
288
+ )
289
+
274
290
  from .pick_up_tip import (
275
291
  PickUpTip,
276
292
  PickUpTipParams,
@@ -384,6 +400,14 @@ from .get_next_tip import (
384
400
  GetNextTipCommandType,
385
401
  )
386
402
 
403
+ from .set_tip_state import (
404
+ SetTipState,
405
+ SetTipStateCreate,
406
+ SetTipStateParams,
407
+ SetTipStateResult,
408
+ SetTipStateCommandType,
409
+ )
410
+
387
411
  from .liquid_probe import (
388
412
  LiquidProbe,
389
413
  LiquidProbeParams,
@@ -427,6 +451,14 @@ from .identify_module import (
427
451
  IdentifyModuleCommandType,
428
452
  )
429
453
 
454
+ from .capture_image import (
455
+ CaptureImage,
456
+ CaptureImageParams,
457
+ CaptureImageCreate,
458
+ CaptureImageResult,
459
+ CaptureImageCommandType,
460
+ )
461
+
430
462
  __all__ = [
431
463
  # command type unions
432
464
  "Command",
@@ -619,6 +651,12 @@ __all__ = [
619
651
  "WaitForDurationCreate",
620
652
  "WaitForDurationResult",
621
653
  "WaitForDurationCommandType",
654
+ # Timer command models
655
+ "CreateTimer",
656
+ "CreateTimerCreate",
657
+ "CreateTimerParams",
658
+ "CreateTimerResult",
659
+ "CreateTimerCommandType",
622
660
  # pick up tip command models
623
661
  "PickUpTip",
624
662
  "PickUpTipCreate",
@@ -725,6 +763,12 @@ __all__ = [
725
763
  "GetNextTipParams",
726
764
  "GetNextTipResult",
727
765
  "GetNextTipCommandType",
766
+ # set tip state command bundle
767
+ "SetTipState",
768
+ "SetTipStateCreate",
769
+ "SetTipStateParams",
770
+ "SetTipStateResult",
771
+ "SetTipStateCommandType",
728
772
  # liquid probe command bundle
729
773
  "LiquidProbe",
730
774
  "LiquidProbeParams",
@@ -754,4 +798,16 @@ __all__ = [
754
798
  "PressureDispenseCreate",
755
799
  "PressureDispenseResult",
756
800
  "PressureDispenseCommandType",
801
+ # wait for tasks command bundle
802
+ "WaitForTasks",
803
+ "WaitForTasksCreate",
804
+ "WaitForTasksParams",
805
+ "WaitForTasksResult",
806
+ "WaitForTasksCommandType",
807
+ # capture image command bundle
808
+ "CaptureImage",
809
+ "CaptureImageCreate",
810
+ "CaptureImageParams",
811
+ "CaptureImageResult",
812
+ "CaptureImageCommandType",
757
813
  ]
@@ -102,25 +102,12 @@ class CloseLidImpl(AbstractCommandImpl[CloseLidParams, SuccessData[CloseLidResul
102
102
  )
103
103
  )
104
104
 
105
- # The lid's labware definition stores gripper offsets for itself in the
106
- # space normally meant for offsets for labware stacked atop it.
107
- lid_gripper_offsets = self._state_view.labware.get_child_gripper_offsets(
108
- labware_definition=lid_definition,
109
- slot_name=None,
110
- )
111
- if lid_gripper_offsets is None:
112
- raise ValueError(
113
- "Gripper Offset values for Absorbance Reader Lid labware must not be None."
114
- )
115
-
116
105
  await self._labware_movement.move_labware_with_gripper(
117
106
  labware_definition=lid_definition,
118
107
  current_location=current_location,
119
108
  new_location=new_location,
120
- user_pick_up_offset=Point.from_xyz_attrs(
121
- lid_gripper_offsets.pickUpOffset
122
- ),
123
- user_drop_offset=Point.from_xyz_attrs(lid_gripper_offsets.dropOffset),
109
+ user_pick_up_offset=Point(),
110
+ user_drop_offset=Point(),
124
111
  post_drop_slide_offset=None,
125
112
  gripper_z_offset=LID_Z_CLEARANCE,
126
113
  )
@@ -103,25 +103,12 @@ class OpenLidImpl(AbstractCommandImpl[OpenLidParams, SuccessData[OpenLidResult]]
103
103
  mod_substate.module_id
104
104
  )
105
105
 
106
- # The lid's labware definition stores gripper offsets for itself in the
107
- # space normally meant for offsets for labware stacked atop it.
108
- lid_gripper_offsets = self._state_view.labware.get_child_gripper_offsets(
109
- labware_definition=lid_definition,
110
- slot_name=None,
111
- )
112
- if lid_gripper_offsets is None:
113
- raise ValueError(
114
- "Gripper Offset values for Absorbance Reader Lid labware must not be None."
115
- )
116
-
117
106
  await self._labware_movement.move_labware_with_gripper(
118
107
  labware_definition=lid_definition,
119
108
  current_location=current_location,
120
109
  new_location=new_location,
121
- user_pick_up_offset=Point.from_xyz_attrs(
122
- lid_gripper_offsets.pickUpOffset
123
- ),
124
- user_drop_offset=Point.from_xyz_attrs(lid_gripper_offsets.dropOffset),
110
+ user_pick_up_offset=Point(),
111
+ user_drop_offset=Point(),
125
112
  post_drop_slide_offset=None,
126
113
  gripper_z_offset=LID_Z_CLEARANCE,
127
114
  )
@@ -7,14 +7,15 @@ from typing_extensions import Literal, Type
7
7
  from pydantic import BaseModel, Field
8
8
  from pydantic.json_schema import SkipJsonSchema
9
9
 
10
+ from opentrons_shared_data.data_files import MimeType
10
11
  from ..command import AbstractCommandImpl, BaseCommand, BaseCommandCreate, SuccessData
11
- from ...errors import CannotPerformModuleAction, StorageLimitReachedError
12
+ from ...errors import CannotPerformModuleAction
12
13
  from ...errors.error_occurrence import ErrorOccurrence
13
14
 
14
15
  from ...resources.file_provider import (
15
16
  PlateReaderData,
16
17
  ReadData,
17
- MAXIMUM_CSV_FILE_LIMIT,
18
+ ReadCmdFileNameMetadata,
18
19
  )
19
20
  from ...resources import FileProvider
20
21
  from ...state import update_types
@@ -93,21 +94,6 @@ class ReadAbsorbanceImpl(
93
94
  "Absorbance Plate Reader can't read a plate with the lid open. Call `close_lid()` first."
94
95
  )
95
96
 
96
- # TODO: we need to return a file ID and increase the file count even when a moduel is not attached
97
- if (
98
- params.fileName is not None
99
- and abs_reader_substate.configured_wavelengths is not None
100
- ):
101
- # Validate that the amount of files we are about to generate does not put us higher than the limit
102
- if (
103
- self._state_view.files.get_filecount()
104
- + len(abs_reader_substate.configured_wavelengths)
105
- > MAXIMUM_CSV_FILE_LIMIT
106
- ):
107
- raise StorageLimitReachedError(
108
- message=f"Attempt to write file {params.fileName} exceeds file creation limit of {MAXIMUM_CSV_FILE_LIMIT} files."
109
- )
110
-
111
97
  asbsorbance_result: Dict[int, Dict[str, float]] = {}
112
98
  transform_results = []
113
99
  # Handle the measurement and begin building data for return
@@ -172,15 +158,28 @@ class ReadAbsorbanceImpl(
172
158
  )
173
159
 
174
160
  if isinstance(plate_read_result, PlateReaderData):
161
+ this_cmd_id = self._state_view.commands.get_running_command_id()
162
+ prev_cmd = (
163
+ self._state_view.commands.get_most_recently_finalized_command()
164
+ )
165
+ prev_cmd_id = prev_cmd.command.id if prev_cmd is not None else None
166
+
175
167
  # Write a CSV file for each of the measurements taken
176
168
  for measurement in plate_read_result.read_results:
177
- file_id = await self._file_provider.write_csv(
178
- write_data=plate_read_result.build_generic_csv(
179
- filename=params.fileName,
180
- measurement=measurement,
181
- )
169
+ csv_bytes = plate_read_result.build_csv_bytes(
170
+ measurement=measurement,
171
+ )
172
+ file_info = await self._file_provider.write_file(
173
+ data=csv_bytes,
174
+ mime_type=MimeType.TEXT_CSV,
175
+ command_metadata=ReadCmdFileNameMetadata(
176
+ base_filename=params.fileName,
177
+ wavelength=measurement.wavelength,
178
+ command_id=this_cmd_id or "",
179
+ prev_command_id=prev_cmd_id or "",
180
+ ),
182
181
  )
183
- file_ids.append(file_id)
182
+ file_ids.append(file_info.id)
184
183
 
185
184
  state_update.files_added = update_types.FilesAddedUpdate(
186
185
  file_ids=file_ids
@@ -161,6 +161,7 @@ class AspirateImplementation(AbstractCommandImpl[AspirateParams, _ExecuteReturn]
161
161
  well_location=well_location,
162
162
  current_well=current_well,
163
163
  operation_volume=-params.volume,
164
+ offset_pipette_for_reservoir_subwells=False,
164
165
  )
165
166
  state_update.append(move_result.state_update)
166
167
  if isinstance(move_result, DefinedErrorData):