opentrons 8.3.1a1__py2.py3-none-any.whl → 8.4.0a1__py2.py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (192) hide show
  1. opentrons/calibration_storage/ot2/mark_bad_calibration.py +2 -0
  2. opentrons/calibration_storage/ot2/tip_length.py +6 -6
  3. opentrons/config/advanced_settings.py +9 -11
  4. opentrons/config/feature_flags.py +0 -4
  5. opentrons/config/reset.py +7 -2
  6. opentrons/drivers/asyncio/communication/__init__.py +2 -0
  7. opentrons/drivers/asyncio/communication/async_serial.py +4 -0
  8. opentrons/drivers/asyncio/communication/errors.py +41 -8
  9. opentrons/drivers/asyncio/communication/serial_connection.py +36 -10
  10. opentrons/drivers/flex_stacker/__init__.py +9 -3
  11. opentrons/drivers/flex_stacker/abstract.py +140 -15
  12. opentrons/drivers/flex_stacker/driver.py +593 -47
  13. opentrons/drivers/flex_stacker/errors.py +64 -0
  14. opentrons/drivers/flex_stacker/simulator.py +222 -24
  15. opentrons/drivers/flex_stacker/types.py +211 -15
  16. opentrons/drivers/flex_stacker/utils.py +19 -0
  17. opentrons/execute.py +4 -2
  18. opentrons/hardware_control/api.py +5 -0
  19. opentrons/hardware_control/backends/flex_protocol.py +4 -0
  20. opentrons/hardware_control/backends/ot3controller.py +12 -1
  21. opentrons/hardware_control/backends/ot3simulator.py +3 -0
  22. opentrons/hardware_control/backends/subsystem_manager.py +8 -4
  23. opentrons/hardware_control/instruments/ot2/instrument_calibration.py +10 -6
  24. opentrons/hardware_control/instruments/ot3/pipette_handler.py +59 -6
  25. opentrons/hardware_control/modules/__init__.py +12 -1
  26. opentrons/hardware_control/modules/absorbance_reader.py +11 -9
  27. opentrons/hardware_control/modules/flex_stacker.py +498 -0
  28. opentrons/hardware_control/modules/heater_shaker.py +12 -10
  29. opentrons/hardware_control/modules/magdeck.py +5 -1
  30. opentrons/hardware_control/modules/tempdeck.py +5 -1
  31. opentrons/hardware_control/modules/thermocycler.py +15 -14
  32. opentrons/hardware_control/modules/types.py +191 -1
  33. opentrons/hardware_control/modules/utils.py +3 -0
  34. opentrons/hardware_control/motion_utilities.py +20 -0
  35. opentrons/hardware_control/ot3api.py +145 -15
  36. opentrons/hardware_control/protocols/liquid_handler.py +47 -1
  37. opentrons/hardware_control/types.py +6 -0
  38. opentrons/legacy_commands/commands.py +19 -3
  39. opentrons/legacy_commands/helpers.py +15 -0
  40. opentrons/legacy_commands/types.py +3 -2
  41. opentrons/protocol_api/__init__.py +2 -0
  42. opentrons/protocol_api/_liquid.py +39 -8
  43. opentrons/protocol_api/_liquid_properties.py +20 -19
  44. opentrons/protocol_api/_transfer_liquid_validation.py +91 -0
  45. opentrons/protocol_api/core/common.py +3 -1
  46. opentrons/protocol_api/core/engine/deck_conflict.py +11 -1
  47. opentrons/protocol_api/core/engine/instrument.py +1233 -65
  48. opentrons/protocol_api/core/engine/labware.py +8 -4
  49. opentrons/protocol_api/core/engine/load_labware_params.py +68 -10
  50. opentrons/protocol_api/core/engine/module_core.py +118 -2
  51. opentrons/protocol_api/core/engine/protocol.py +253 -11
  52. opentrons/protocol_api/core/engine/stringify.py +19 -8
  53. opentrons/protocol_api/core/engine/transfer_components_executor.py +853 -0
  54. opentrons/protocol_api/core/engine/well.py +60 -5
  55. opentrons/protocol_api/core/instrument.py +65 -19
  56. opentrons/protocol_api/core/labware.py +6 -2
  57. opentrons/protocol_api/core/legacy/labware_offset_provider.py +7 -3
  58. opentrons/protocol_api/core/legacy/legacy_instrument_core.py +69 -21
  59. opentrons/protocol_api/core/legacy/legacy_labware_core.py +8 -4
  60. opentrons/protocol_api/core/legacy/legacy_protocol_core.py +36 -0
  61. opentrons/protocol_api/core/legacy/legacy_well_core.py +25 -1
  62. opentrons/protocol_api/core/legacy/load_info.py +4 -12
  63. opentrons/protocol_api/core/legacy/module_geometry.py +6 -1
  64. opentrons/protocol_api/core/legacy/well_geometry.py +3 -3
  65. opentrons/protocol_api/core/legacy_simulator/legacy_instrument_core.py +67 -21
  66. opentrons/protocol_api/core/module.py +43 -0
  67. opentrons/protocol_api/core/protocol.py +33 -0
  68. opentrons/protocol_api/core/well.py +21 -1
  69. opentrons/protocol_api/instrument_context.py +246 -123
  70. opentrons/protocol_api/labware.py +75 -11
  71. opentrons/protocol_api/module_contexts.py +140 -0
  72. opentrons/protocol_api/protocol_context.py +156 -16
  73. opentrons/protocol_api/validation.py +51 -41
  74. opentrons/protocol_engine/__init__.py +21 -2
  75. opentrons/protocol_engine/actions/actions.py +5 -5
  76. opentrons/protocol_engine/clients/sync_client.py +6 -0
  77. opentrons/protocol_engine/commands/__init__.py +30 -0
  78. opentrons/protocol_engine/commands/absorbance_reader/__init__.py +0 -1
  79. opentrons/protocol_engine/commands/air_gap_in_place.py +3 -2
  80. opentrons/protocol_engine/commands/aspirate.py +6 -2
  81. opentrons/protocol_engine/commands/aspirate_in_place.py +3 -1
  82. opentrons/protocol_engine/commands/aspirate_while_tracking.py +237 -0
  83. opentrons/protocol_engine/commands/blow_out.py +2 -0
  84. opentrons/protocol_engine/commands/blow_out_in_place.py +4 -1
  85. opentrons/protocol_engine/commands/command_unions.py +69 -0
  86. opentrons/protocol_engine/commands/configure_for_volume.py +3 -0
  87. opentrons/protocol_engine/commands/dispense.py +3 -1
  88. opentrons/protocol_engine/commands/dispense_in_place.py +3 -0
  89. opentrons/protocol_engine/commands/dispense_while_tracking.py +240 -0
  90. opentrons/protocol_engine/commands/drop_tip.py +23 -1
  91. opentrons/protocol_engine/commands/evotip_dispense.py +6 -7
  92. opentrons/protocol_engine/commands/evotip_seal_pipette.py +24 -29
  93. opentrons/protocol_engine/commands/evotip_unseal_pipette.py +1 -7
  94. opentrons/protocol_engine/commands/flex_stacker/__init__.py +106 -0
  95. opentrons/protocol_engine/commands/flex_stacker/close_latch.py +72 -0
  96. opentrons/protocol_engine/commands/flex_stacker/common.py +15 -0
  97. opentrons/protocol_engine/commands/flex_stacker/empty.py +161 -0
  98. opentrons/protocol_engine/commands/flex_stacker/fill.py +164 -0
  99. opentrons/protocol_engine/commands/flex_stacker/open_latch.py +70 -0
  100. opentrons/protocol_engine/commands/flex_stacker/prepare_shuttle.py +112 -0
  101. opentrons/protocol_engine/commands/flex_stacker/retrieve.py +394 -0
  102. opentrons/protocol_engine/commands/flex_stacker/set_stored_labware.py +190 -0
  103. opentrons/protocol_engine/commands/flex_stacker/store.py +288 -0
  104. opentrons/protocol_engine/commands/generate_command_schema.py +31 -2
  105. opentrons/protocol_engine/commands/labware_handling_common.py +24 -0
  106. opentrons/protocol_engine/commands/liquid_probe.py +21 -12
  107. opentrons/protocol_engine/commands/load_labware.py +42 -39
  108. opentrons/protocol_engine/commands/load_lid.py +21 -13
  109. opentrons/protocol_engine/commands/load_lid_stack.py +130 -47
  110. opentrons/protocol_engine/commands/load_module.py +18 -17
  111. opentrons/protocol_engine/commands/load_pipette.py +3 -0
  112. opentrons/protocol_engine/commands/move_labware.py +139 -20
  113. opentrons/protocol_engine/commands/pick_up_tip.py +5 -2
  114. opentrons/protocol_engine/commands/pipetting_common.py +154 -7
  115. opentrons/protocol_engine/commands/prepare_to_aspirate.py +17 -2
  116. opentrons/protocol_engine/commands/reload_labware.py +6 -19
  117. opentrons/protocol_engine/commands/unsafe/unsafe_blow_out_in_place.py +3 -1
  118. opentrons/protocol_engine/commands/unsafe/unsafe_drop_tip_in_place.py +6 -1
  119. opentrons/protocol_engine/errors/__init__.py +8 -0
  120. opentrons/protocol_engine/errors/exceptions.py +50 -0
  121. opentrons/protocol_engine/execution/equipment.py +123 -106
  122. opentrons/protocol_engine/execution/labware_movement.py +8 -6
  123. opentrons/protocol_engine/execution/pipetting.py +233 -26
  124. opentrons/protocol_engine/execution/tip_handler.py +14 -5
  125. opentrons/protocol_engine/labware_offset_standardization.py +173 -0
  126. opentrons/protocol_engine/protocol_engine.py +22 -13
  127. opentrons/protocol_engine/resources/deck_configuration_provider.py +94 -2
  128. opentrons/protocol_engine/resources/deck_data_provider.py +1 -1
  129. opentrons/protocol_engine/resources/labware_data_provider.py +32 -12
  130. opentrons/protocol_engine/resources/labware_validation.py +7 -5
  131. opentrons/protocol_engine/slot_standardization.py +11 -23
  132. opentrons/protocol_engine/state/addressable_areas.py +84 -46
  133. opentrons/protocol_engine/state/frustum_helpers.py +26 -10
  134. opentrons/protocol_engine/state/geometry.py +683 -100
  135. opentrons/protocol_engine/state/labware.py +252 -55
  136. opentrons/protocol_engine/state/module_substates/__init__.py +4 -0
  137. opentrons/protocol_engine/state/module_substates/flex_stacker_substate.py +68 -0
  138. opentrons/protocol_engine/state/module_substates/heater_shaker_module_substate.py +22 -0
  139. opentrons/protocol_engine/state/module_substates/temperature_module_substate.py +13 -0
  140. opentrons/protocol_engine/state/module_substates/thermocycler_module_substate.py +20 -0
  141. opentrons/protocol_engine/state/modules.py +178 -52
  142. opentrons/protocol_engine/state/pipettes.py +54 -0
  143. opentrons/protocol_engine/state/state.py +1 -1
  144. opentrons/protocol_engine/state/tips.py +14 -0
  145. opentrons/protocol_engine/state/update_types.py +180 -25
  146. opentrons/protocol_engine/state/wells.py +54 -8
  147. opentrons/protocol_engine/types/__init__.py +292 -0
  148. opentrons/protocol_engine/types/automatic_tip_selection.py +39 -0
  149. opentrons/protocol_engine/types/command_annotations.py +53 -0
  150. opentrons/protocol_engine/types/deck_configuration.py +72 -0
  151. opentrons/protocol_engine/types/execution.py +96 -0
  152. opentrons/protocol_engine/types/hardware_passthrough.py +25 -0
  153. opentrons/protocol_engine/types/instrument.py +47 -0
  154. opentrons/protocol_engine/types/instrument_sensors.py +47 -0
  155. opentrons/protocol_engine/types/labware.py +110 -0
  156. opentrons/protocol_engine/types/labware_movement.py +22 -0
  157. opentrons/protocol_engine/types/labware_offset_location.py +108 -0
  158. opentrons/protocol_engine/types/labware_offset_vector.py +33 -0
  159. opentrons/protocol_engine/types/liquid.py +40 -0
  160. opentrons/protocol_engine/types/liquid_class.py +59 -0
  161. opentrons/protocol_engine/types/liquid_handling.py +13 -0
  162. opentrons/protocol_engine/types/liquid_level_detection.py +137 -0
  163. opentrons/protocol_engine/types/location.py +193 -0
  164. opentrons/protocol_engine/types/module.py +269 -0
  165. opentrons/protocol_engine/types/partial_tip_configuration.py +76 -0
  166. opentrons/protocol_engine/types/run_time_parameters.py +133 -0
  167. opentrons/protocol_engine/types/tip.py +18 -0
  168. opentrons/protocol_engine/types/util.py +21 -0
  169. opentrons/protocol_engine/types/well_position.py +107 -0
  170. opentrons/protocol_reader/extract_labware_definitions.py +7 -3
  171. opentrons/protocol_reader/file_format_validator.py +5 -3
  172. opentrons/protocol_runner/json_translator.py +4 -2
  173. opentrons/protocol_runner/legacy_command_mapper.py +6 -2
  174. opentrons/protocol_runner/run_orchestrator.py +4 -1
  175. opentrons/protocols/advanced_control/transfers/common.py +48 -1
  176. opentrons/protocols/advanced_control/transfers/transfer_liquid_utils.py +204 -0
  177. opentrons/protocols/api_support/definitions.py +1 -1
  178. opentrons/protocols/api_support/instrument.py +16 -3
  179. opentrons/protocols/labware.py +5 -6
  180. opentrons/protocols/models/__init__.py +0 -21
  181. opentrons/simulate.py +4 -2
  182. opentrons/types.py +15 -6
  183. {opentrons-8.3.1a1.dist-info → opentrons-8.4.0a1.dist-info}/METADATA +4 -4
  184. {opentrons-8.3.1a1.dist-info → opentrons-8.4.0a1.dist-info}/RECORD +188 -148
  185. opentrons/calibration_storage/ot2/models/defaults.py +0 -0
  186. opentrons/calibration_storage/ot3/models/defaults.py +0 -0
  187. opentrons/protocol_api/core/legacy/legacy_robot_core.py +0 -0
  188. opentrons/protocol_engine/types.py +0 -1311
  189. {opentrons-8.3.1a1.dist-info → opentrons-8.4.0a1.dist-info}/LICENSE +0 -0
  190. {opentrons-8.3.1a1.dist-info → opentrons-8.4.0a1.dist-info}/WHEEL +0 -0
  191. {opentrons-8.3.1a1.dist-info → opentrons-8.4.0a1.dist-info}/entry_points.txt +0 -0
  192. {opentrons-8.3.1a1.dist-info → opentrons-8.4.0a1.dist-info}/top_level.txt +0 -0
@@ -1,1311 +0,0 @@
1
- """Public protocol engine value types and models."""
2
- from __future__ import annotations
3
- from datetime import datetime
4
- from enum import Enum
5
- from dataclasses import dataclass
6
- from pathlib import Path
7
- from typing import (
8
- Any,
9
- Dict,
10
- FrozenSet,
11
- List,
12
- Mapping,
13
- NamedTuple,
14
- Optional,
15
- Tuple,
16
- Union,
17
- )
18
-
19
- from pydantic import (
20
- ConfigDict,
21
- BaseModel,
22
- Field,
23
- RootModel,
24
- StrictBool,
25
- StrictFloat,
26
- StrictInt,
27
- StrictStr,
28
- )
29
- from typing_extensions import Literal, TypeGuard
30
-
31
- from opentrons_shared_data.pipette.types import PipetteNameType
32
- from opentrons.types import MountType, DeckSlotName, StagingSlotName
33
- from opentrons.hardware_control.types import (
34
- TipStateType as HwTipStateType,
35
- InstrumentProbeType,
36
- )
37
- from opentrons.hardware_control.modules import (
38
- ModuleType as ModuleType,
39
- )
40
- from opentrons_shared_data.liquid_classes.liquid_class_definition import (
41
- ByTipTypeSetting,
42
- )
43
- from opentrons_shared_data.pipette.types import ( # noqa: F401
44
- # convenience re-export of LabwareUri type
45
- LabwareUri as LabwareUri,
46
- )
47
- from opentrons_shared_data.module.types import ModuleType as SharedDataModuleType
48
-
49
-
50
- # todo(mm, 2024-06-24): This monolithic status field is getting to be a bit much.
51
- # We should consider splitting this up into multiple fields.
52
- class EngineStatus(str, Enum):
53
- """Current execution status of a ProtocolEngine.
54
-
55
- This is a high-level summary of what the robot is doing and what interactions are
56
- appropriate.
57
- """
58
-
59
- # Statuses for an ongoing run:
60
-
61
- IDLE = "idle"
62
- """The protocol has not been started yet.
63
-
64
- The robot may truly be idle, or it may be executing commands with `intent: "setup"`.
65
- """
66
-
67
- RUNNING = "running"
68
- """The engine is actively running the protocol."""
69
-
70
- PAUSED = "paused"
71
- """A pause has been requested. Activity is paused, or will pause soon.
72
-
73
- (There is currently no way to tell which.)
74
- """
75
-
76
- BLOCKED_BY_OPEN_DOOR = "blocked-by-open-door"
77
- """The robot's door is open. Activity is paused, or will pause soon."""
78
-
79
- STOP_REQUESTED = "stop-requested"
80
- """A stop has been requested. Activity will stop soon."""
81
-
82
- FINISHING = "finishing"
83
- """The robot is doing post-run cleanup, like homing and dropping tips."""
84
-
85
- # Statuses for error recovery mode:
86
-
87
- AWAITING_RECOVERY = "awaiting-recovery"
88
- """The engine is waiting for external input to recover from a nonfatal error.
89
-
90
- New commands with `intent: "fixit"` may be enqueued, which will run immediately.
91
- The run can't be paused in this state, but it can be canceled, or resumed from the
92
- next protocol command if recovery is complete.
93
- """
94
-
95
- AWAITING_RECOVERY_PAUSED = "awaiting-recovery-paused"
96
- """The engine is paused while in error recovery mode. Activity is paused, or will pause soon.
97
-
98
- This state is not possible to enter manually. It happens when an open door
99
- gets closed during error recovery.
100
- """
101
-
102
- AWAITING_RECOVERY_BLOCKED_BY_OPEN_DOOR = "awaiting-recovery-blocked-by-open-door"
103
- """The robot's door is open while in recovery mode. Activity is paused, or will pause soon."""
104
-
105
- # Terminal statuses:
106
-
107
- STOPPED = "stopped"
108
- """All activity is over; it was stopped by an explicit external request."""
109
-
110
- FAILED = "failed"
111
- """All activity is over; there was a fatal error."""
112
-
113
- SUCCEEDED = "succeeded"
114
- """All activity is over; things completed without any fatal error."""
115
-
116
-
117
- class DeckSlotLocation(BaseModel):
118
- """The location of something placed in a single deck slot."""
119
-
120
- slotName: DeckSlotName = Field(
121
- ...,
122
- description=(
123
- # This description should be kept in sync with LabwareOffsetLocation.slotName.
124
- "A slot on the robot's deck."
125
- "\n\n"
126
- 'The plain numbers like `"5"` are for the OT-2,'
127
- ' and the coordinates like `"C2"` are for the Flex.'
128
- "\n\n"
129
- "When you provide one of these values, you can use either style."
130
- " It will automatically be converted to match the robot."
131
- "\n\n"
132
- "When one of these values is returned, it will always match the robot."
133
- ),
134
- )
135
-
136
-
137
- class StagingSlotLocation(BaseModel):
138
- """The location of something placed in a single staging slot."""
139
-
140
- slotName: StagingSlotName = Field(
141
- ...,
142
- description=(
143
- # This description should be kept in sync with LabwareOffsetLocation.slotName.
144
- "A slot on the robot's staging area."
145
- "\n\n"
146
- "These apply only to the Flex. The OT-2 has no staging slots."
147
- ),
148
- )
149
-
150
-
151
- class AddressableAreaLocation(BaseModel):
152
- """The location of something place in an addressable area. This is a superset of deck slots."""
153
-
154
- addressableAreaName: str = Field(
155
- ...,
156
- description=(
157
- "The name of the addressable area that you want to use."
158
- " Valid values are the `id`s of `addressableArea`s in the"
159
- " [deck definition](https://github.com/Opentrons/opentrons/tree/edge/shared-data/deck)."
160
- ),
161
- )
162
-
163
-
164
- class ModuleLocation(BaseModel):
165
- """The location of something placed atop a hardware module."""
166
-
167
- moduleId: str = Field(
168
- ...,
169
- description="The ID of a loaded module from a prior `loadModule` command.",
170
- )
171
-
172
-
173
- class OnLabwareLocation(BaseModel):
174
- """The location of something placed atop another labware."""
175
-
176
- labwareId: str = Field(
177
- ...,
178
- description="The ID of a loaded Labware from a prior `loadLabware` command.",
179
- )
180
-
181
-
182
- _OffDeckLocationType = Literal["offDeck"]
183
- OFF_DECK_LOCATION: _OffDeckLocationType = "offDeck"
184
-
185
- LabwareLocation = Union[
186
- DeckSlotLocation,
187
- ModuleLocation,
188
- OnLabwareLocation,
189
- _OffDeckLocationType,
190
- AddressableAreaLocation,
191
- ]
192
- """Union of all locations where it's legal to keep a labware."""
193
-
194
- OnDeckLabwareLocation = Union[
195
- DeckSlotLocation, ModuleLocation, OnLabwareLocation, AddressableAreaLocation
196
- ]
197
-
198
- NonStackedLocation = Union[
199
- DeckSlotLocation, AddressableAreaLocation, ModuleLocation, _OffDeckLocationType
200
- ]
201
- """Union of all locations where it's legal to keep a labware that can't be stacked on another labware"""
202
-
203
-
204
- class WellOrigin(str, Enum):
205
- """Origin of WellLocation offset.
206
-
207
- Props:
208
- TOP: the top-center of the well
209
- BOTTOM: the bottom-center of the well
210
- CENTER: the middle-center of the well
211
- MENISCUS: the meniscus-center of the well
212
- """
213
-
214
- TOP = "top"
215
- BOTTOM = "bottom"
216
- CENTER = "center"
217
- MENISCUS = "meniscus"
218
-
219
-
220
- class PickUpTipWellOrigin(str, Enum):
221
- """The origin of a PickUpTipWellLocation offset.
222
-
223
- Props:
224
- TOP: the top-center of the well
225
- BOTTOM: the bottom-center of the well
226
- CENTER: the middle-center of the well
227
- """
228
-
229
- TOP = "top"
230
- BOTTOM = "bottom"
231
- CENTER = "center"
232
-
233
-
234
- class DropTipWellOrigin(str, Enum):
235
- """The origin of a DropTipWellLocation offset.
236
-
237
- Props:
238
- TOP: the top-center of the well
239
- BOTTOM: the bottom-center of the well
240
- CENTER: the middle-center of the well
241
- DEFAULT: the default drop-tip location of the well,
242
- based on pipette configuration and length of the tip.
243
- """
244
-
245
- TOP = "top"
246
- BOTTOM = "bottom"
247
- CENTER = "center"
248
- DEFAULT = "default"
249
-
250
-
251
- # This is deliberately a separate type from Vec3f to let components default to 0.
252
- class WellOffset(BaseModel):
253
- """An offset vector in (x, y, z)."""
254
-
255
- x: float = 0
256
- y: float = 0
257
- z: float = 0
258
-
259
-
260
- class WellLocation(BaseModel):
261
- """A relative location in reference to a well's location."""
262
-
263
- origin: WellOrigin = WellOrigin.TOP
264
- offset: WellOffset = Field(default_factory=WellOffset)
265
- volumeOffset: float = Field(
266
- default=0.0,
267
- description="""A volume of liquid, in µL, to offset the z-axis offset.""",
268
- )
269
-
270
-
271
- class LiquidHandlingWellLocation(BaseModel):
272
- """A relative location in reference to a well's location.
273
-
274
- To be used with commands that handle liquids.
275
- """
276
-
277
- origin: WellOrigin = WellOrigin.TOP
278
- offset: WellOffset = Field(default_factory=WellOffset)
279
- volumeOffset: Union[float, Literal["operationVolume"]] = Field(
280
- default=0.0,
281
- description="""A volume of liquid, in µL, to offset the z-axis offset. When "operationVolume" is specified, this volume is pulled from the command volume parameter.""",
282
- )
283
-
284
-
285
- class PickUpTipWellLocation(BaseModel):
286
- """A relative location in reference to a well's location.
287
-
288
- To be used for picking up tips.
289
- """
290
-
291
- origin: PickUpTipWellOrigin = PickUpTipWellOrigin.TOP
292
- offset: WellOffset = Field(default_factory=WellOffset)
293
-
294
-
295
- class DropTipWellLocation(BaseModel):
296
- """Like WellLocation, but for dropping tips.
297
-
298
- Unlike a typical WellLocation, the location for a drop tip
299
- defaults to location based on the tip length rather than the well's top.
300
- """
301
-
302
- origin: DropTipWellOrigin = DropTipWellOrigin.DEFAULT
303
- offset: WellOffset = Field(default_factory=WellOffset)
304
-
305
-
306
- @dataclass(frozen=True)
307
- class Dimensions:
308
- """Dimensions of an object in deck-space."""
309
-
310
- x: float
311
- y: float
312
- z: float
313
-
314
-
315
- # TODO(mm, 2022-11-07): Deduplicate with Vec3f.
316
- class DeckPoint(BaseModel):
317
- """Coordinates of a point in deck space."""
318
-
319
- x: float
320
- y: float
321
- z: float
322
-
323
-
324
- # TODO(mm, 2023-05-10): Deduplicate with constants in
325
- # opentrons.protocols.api_support.deck_type
326
- # and consider moving to shared-data.
327
- class DeckType(str, Enum):
328
- """Types of deck available."""
329
-
330
- OT2_STANDARD = "ot2_standard"
331
- OT2_SHORT_TRASH = "ot2_short_trash"
332
- OT3_STANDARD = "ot3_standard"
333
-
334
-
335
- class LoadedPipette(BaseModel):
336
- """A pipette that has been loaded."""
337
-
338
- id: str
339
- pipetteName: PipetteNameType
340
- mount: MountType
341
-
342
-
343
- @dataclass
344
- class FlowRates:
345
- """Default and current flow rates for a pipette."""
346
-
347
- default_blow_out: Dict[str, float]
348
- default_aspirate: Dict[str, float]
349
- default_dispense: Dict[str, float]
350
-
351
-
352
- @dataclass(frozen=True)
353
- class CurrentWell:
354
- """The latest well that the robot has accessed."""
355
-
356
- pipette_id: str
357
- labware_id: str
358
- well_name: str
359
-
360
-
361
- class LoadedVolumeInfo(BaseModel):
362
- """A well's liquid volume, initialized by a LoadLiquid, updated by Aspirate and Dispense."""
363
-
364
- volume: Optional[float] = None
365
- last_loaded: datetime
366
- operations_since_load: int
367
-
368
-
369
- class ProbedHeightInfo(BaseModel):
370
- """A well's liquid height, initialized by a LiquidProbe, cleared by Aspirate and Dispense."""
371
-
372
- height: Optional[float] = None
373
- last_probed: datetime
374
-
375
-
376
- class ProbedVolumeInfo(BaseModel):
377
- """A well's liquid volume, initialized by a LiquidProbe, updated by Aspirate and Dispense."""
378
-
379
- volume: Optional[float] = None
380
- last_probed: datetime
381
- operations_since_probe: int
382
-
383
-
384
- class WellInfoSummary(BaseModel):
385
- """Payload for a well's liquid info in StateSummary."""
386
-
387
- labware_id: str
388
- well_name: str
389
- loaded_volume: Optional[float] = None
390
- probed_height: Optional[float] = None
391
- probed_volume: Optional[float] = None
392
-
393
-
394
- @dataclass
395
- class WellLiquidInfo:
396
- """Tracked and sensed information about liquid in a well."""
397
-
398
- probed_height: Optional[ProbedHeightInfo]
399
- loaded_volume: Optional[LoadedVolumeInfo]
400
- probed_volume: Optional[ProbedVolumeInfo]
401
-
402
-
403
- @dataclass(frozen=True)
404
- class CurrentAddressableArea:
405
- """The latest addressable area the robot has accessed."""
406
-
407
- pipette_id: str
408
- addressable_area_name: str
409
-
410
-
411
- CurrentPipetteLocation = Union[CurrentWell, CurrentAddressableArea]
412
-
413
-
414
- @dataclass(frozen=True)
415
- class TipGeometry:
416
- """Tip geometry data.
417
-
418
- Props:
419
- length: The effective length (total length minus overlap) of a tip in mm.
420
- diameter: Tip diameter in mm.
421
- volume: Maximum volume in µL.
422
- """
423
-
424
- length: float
425
- diameter: float
426
- volume: float
427
-
428
-
429
- class FluidKind(str, Enum):
430
- """A kind of fluid that can be inside a pipette."""
431
-
432
- LIQUID = "LIQUID"
433
- AIR = "AIR"
434
-
435
-
436
- @dataclass(frozen=True)
437
- class AspiratedFluid:
438
- """Fluid inside a pipette."""
439
-
440
- kind: FluidKind
441
- volume: float
442
-
443
-
444
- class MovementAxis(str, Enum):
445
- """Axis on which to issue a relative movement."""
446
-
447
- X = "x"
448
- Y = "y"
449
- Z = "z"
450
-
451
-
452
- class MotorAxis(str, Enum):
453
- """Motor axis on which to issue a home command."""
454
-
455
- X = "x"
456
- Y = "y"
457
- LEFT_Z = "leftZ"
458
- RIGHT_Z = "rightZ"
459
- LEFT_PLUNGER = "leftPlunger"
460
- RIGHT_PLUNGER = "rightPlunger"
461
- EXTENSION_Z = "extensionZ"
462
- EXTENSION_JAW = "extensionJaw"
463
- AXIS_96_CHANNEL_CAM = "axis96ChannelCam"
464
-
465
-
466
- # TODO(mc, 2022-01-18): use opentrons_shared_data.module.types.ModuleModel
467
- class ModuleModel(str, Enum):
468
- """All available modules' models."""
469
-
470
- TEMPERATURE_MODULE_V1 = "temperatureModuleV1"
471
- TEMPERATURE_MODULE_V2 = "temperatureModuleV2"
472
- MAGNETIC_MODULE_V1 = "magneticModuleV1"
473
- MAGNETIC_MODULE_V2 = "magneticModuleV2"
474
- THERMOCYCLER_MODULE_V1 = "thermocyclerModuleV1"
475
- THERMOCYCLER_MODULE_V2 = "thermocyclerModuleV2"
476
- HEATER_SHAKER_MODULE_V1 = "heaterShakerModuleV1"
477
- MAGNETIC_BLOCK_V1 = "magneticBlockV1"
478
- ABSORBANCE_READER_V1 = "absorbanceReaderV1"
479
-
480
- def as_type(self) -> ModuleType:
481
- """Get the ModuleType of this model."""
482
- if ModuleModel.is_temperature_module_model(self):
483
- return ModuleType.TEMPERATURE
484
- elif ModuleModel.is_magnetic_module_model(self):
485
- return ModuleType.MAGNETIC
486
- elif ModuleModel.is_thermocycler_module_model(self):
487
- return ModuleType.THERMOCYCLER
488
- elif ModuleModel.is_heater_shaker_module_model(self):
489
- return ModuleType.HEATER_SHAKER
490
- elif ModuleModel.is_magnetic_block(self):
491
- return ModuleType.MAGNETIC_BLOCK
492
- elif ModuleModel.is_absorbance_reader(self):
493
- return ModuleType.ABSORBANCE_READER
494
-
495
- assert False, f"Invalid ModuleModel {self}"
496
-
497
- @classmethod
498
- def is_temperature_module_model(
499
- cls, model: ModuleModel
500
- ) -> TypeGuard[TemperatureModuleModel]:
501
- """Whether a given model is a Temperature Module."""
502
- return model in [cls.TEMPERATURE_MODULE_V1, cls.TEMPERATURE_MODULE_V2]
503
-
504
- @classmethod
505
- def is_magnetic_module_model(
506
- cls, model: ModuleModel
507
- ) -> TypeGuard[MagneticModuleModel]:
508
- """Whether a given model is a Magnetic Module."""
509
- return model in [cls.MAGNETIC_MODULE_V1, cls.MAGNETIC_MODULE_V2]
510
-
511
- @classmethod
512
- def is_thermocycler_module_model(
513
- cls, model: ModuleModel
514
- ) -> TypeGuard[ThermocyclerModuleModel]:
515
- """Whether a given model is a Thermocycler Module."""
516
- return model in [cls.THERMOCYCLER_MODULE_V1, cls.THERMOCYCLER_MODULE_V2]
517
-
518
- @classmethod
519
- def is_heater_shaker_module_model(
520
- cls, model: ModuleModel
521
- ) -> TypeGuard[HeaterShakerModuleModel]:
522
- """Whether a given model is a Heater-Shaker Module."""
523
- return model == cls.HEATER_SHAKER_MODULE_V1
524
-
525
- @classmethod
526
- def is_magnetic_block(cls, model: ModuleModel) -> TypeGuard[MagneticBlockModel]:
527
- """Whether a given model is a Magnetic block."""
528
- return model == cls.MAGNETIC_BLOCK_V1
529
-
530
- @classmethod
531
- def is_absorbance_reader(
532
- cls, model: ModuleModel
533
- ) -> TypeGuard[AbsorbanceReaderModel]:
534
- """Whether a given model is an Absorbance Plate Reader."""
535
- return model == cls.ABSORBANCE_READER_V1
536
-
537
-
538
- TemperatureModuleModel = Literal[
539
- ModuleModel.TEMPERATURE_MODULE_V1, ModuleModel.TEMPERATURE_MODULE_V2
540
- ]
541
- MagneticModuleModel = Literal[
542
- ModuleModel.MAGNETIC_MODULE_V1, ModuleModel.MAGNETIC_MODULE_V2
543
- ]
544
- ThermocyclerModuleModel = Literal[
545
- ModuleModel.THERMOCYCLER_MODULE_V1, ModuleModel.THERMOCYCLER_MODULE_V2
546
- ]
547
- HeaterShakerModuleModel = Literal[ModuleModel.HEATER_SHAKER_MODULE_V1]
548
- MagneticBlockModel = Literal[ModuleModel.MAGNETIC_BLOCK_V1]
549
- AbsorbanceReaderModel = Literal[ModuleModel.ABSORBANCE_READER_V1]
550
-
551
-
552
- class ModuleDimensions(BaseModel):
553
- """Dimension type for modules."""
554
-
555
- bareOverallHeight: float
556
- overLabwareHeight: float
557
- lidHeight: Optional[float] = None
558
-
559
-
560
- class Vec3f(BaseModel):
561
- """A 3D vector of floats."""
562
-
563
- x: float
564
- y: float
565
- z: float
566
-
567
-
568
- # TODO(mm, 2022-11-07): Deduplicate with Vec3f.
569
- class ModuleCalibrationPoint(BaseModel):
570
- """Calibration Point type for module definition."""
571
-
572
- x: float
573
- y: float
574
- z: float
575
-
576
-
577
- # TODO(mm, 2022-11-07): Deduplicate with Vec3f.
578
- class LabwareOffsetVector(BaseModel):
579
- """Offset, in deck coordinates from nominal to actual position."""
580
-
581
- x: float
582
- y: float
583
- z: float
584
-
585
- def __add__(self, other: Any) -> LabwareOffsetVector:
586
- """Adds two vectors together."""
587
- if not isinstance(other, LabwareOffsetVector):
588
- return NotImplemented
589
- return LabwareOffsetVector(
590
- x=self.x + other.x, y=self.y + other.y, z=self.z + other.z
591
- )
592
-
593
- def __sub__(self, other: Any) -> LabwareOffsetVector:
594
- """Subtracts two vectors."""
595
- if not isinstance(other, LabwareOffsetVector):
596
- return NotImplemented
597
- return LabwareOffsetVector(
598
- x=self.x - other.x, y=self.y - other.y, z=self.z - other.z
599
- )
600
-
601
-
602
- # TODO(mm, 2022-11-07): Deduplicate with Vec3f.
603
- class InstrumentOffsetVector(BaseModel):
604
- """Instrument Offset from home position to robot deck."""
605
-
606
- x: float
607
- y: float
608
- z: float
609
-
610
-
611
- # TODO(mm, 2022-11-07): Deduplicate with Vec3f.
612
- class ModuleOffsetVector(BaseModel):
613
- """Offset, in deck coordinates, from nominal to actual position of labware on a module."""
614
-
615
- x: float
616
- y: float
617
- z: float
618
-
619
-
620
- @dataclass
621
- class ModuleOffsetData:
622
- """Module calibration offset data."""
623
-
624
- moduleOffsetVector: ModuleOffsetVector
625
- location: DeckSlotLocation
626
-
627
-
628
- class OverlapOffset(Vec3f):
629
- """Offset representing overlap space of one labware on top of another labware or module."""
630
-
631
-
632
- class AddressableOffsetVector(Vec3f):
633
- """Offset, in deck coordinates, from nominal to actual position of an addressable area."""
634
-
635
-
636
- class LabwareMovementOffsetData(BaseModel):
637
- """Offsets to be used during labware movement."""
638
-
639
- pickUpOffset: LabwareOffsetVector
640
- dropOffset: LabwareOffsetVector
641
-
642
-
643
- # TODO(mm, 2023-04-13): Move to shared-data, so this binding can be maintained alongside the JSON
644
- # schema that it's sourced from. We already do that for labware definitions and JSON protocols.
645
- class ModuleDefinition(BaseModel):
646
- """A module definition conforming to module definition schema v3."""
647
-
648
- # Note: This field is misleading.
649
- #
650
- # This class only models v3 definitions ("module/schemas/3"), not v2 ("module/schemas/2").
651
- # labwareOffset is required to have a z-component, for example.
652
- #
653
- # When parsing from a schema v3 JSON definition into this model,
654
- # the definition's `"$otSharedSchema": "module/schemas/3"` field will be thrown away
655
- # because it has a dollar sign, which doesn't match this field.
656
- # Then, this field will default to "module/schemas/2", because no value was provided.
657
- #
658
- # We should fix this field once Jira RSS-221 is resolved. RSS-221 makes it difficult to fix
659
- # because robot-server has been storing and loading these bad fields in its database.
660
- otSharedSchema: str = Field("module/schemas/2", description="The current schema.")
661
-
662
- moduleType: ModuleType = Field(
663
- ...,
664
- description="Module type (Temperature/Magnetic/Thermocycler)",
665
- )
666
-
667
- model: ModuleModel = Field(..., description="Model name of the module")
668
-
669
- labwareOffset: LabwareOffsetVector = Field(
670
- ...,
671
- description="Labware offset in x, y, z.",
672
- )
673
-
674
- dimensions: ModuleDimensions = Field(..., description="Module dimension")
675
-
676
- calibrationPoint: ModuleCalibrationPoint = Field(
677
- ...,
678
- description="Calibration point of module.",
679
- )
680
-
681
- displayName: str = Field(..., description="Display name.")
682
-
683
- quirks: List[str] = Field(..., description="Module quirks")
684
-
685
- # In releases prior to https://github.com/Opentrons/opentrons/pull/11873 (v6.3.0),
686
- # the matrices in slotTransforms were 3x3.
687
- # After, they are 4x4, even though there was no schema version bump.
688
- #
689
- # Because old objects of this class, with the 3x3 matrices, were stored in robot-server's
690
- # database, this field needs to stay typed loosely enough to support both sizes.
691
- # We can fix this once Jira RSS-221 is resolved.
692
- slotTransforms: Dict[str, Any] = Field(
693
- ...,
694
- description="Dictionary of transforms for each slot.",
695
- )
696
-
697
- compatibleWith: List[ModuleModel] = Field(
698
- ...,
699
- description="List of module models this model is compatible with.",
700
- )
701
- gripperOffsets: Optional[Dict[str, LabwareMovementOffsetData]] = Field(
702
- default_factory=dict,
703
- description="Offsets to use for labware movement using gripper",
704
- )
705
-
706
-
707
- class LoadedModule(BaseModel):
708
- """A module that has been loaded."""
709
-
710
- id: str
711
- model: ModuleModel
712
- location: Optional[DeckSlotLocation] = None
713
- serialNumber: Optional[str] = None
714
-
715
-
716
- class LabwareOffsetLocation(BaseModel):
717
- """Parameters describing when a given offset may apply to a given labware load."""
718
-
719
- slotName: DeckSlotName = Field(
720
- ...,
721
- description=(
722
- "The deck slot where the protocol will load the labware."
723
- " Or, if the protocol will load the labware on a module,"
724
- " the deck slot where the protocol will load that module."
725
- "\n\n"
726
- # This description should be kept in sync with DeckSlotLocation.slotName.
727
- 'The plain numbers like `"5"` are for the OT-2,'
728
- ' and the coordinates like `"C2"` are for the Flex.'
729
- "\n\n"
730
- "When you provide one of these values, you can use either style."
731
- " It will automatically be converted to match the robot."
732
- "\n\n"
733
- "When one of these values is returned, it will always match the robot."
734
- ),
735
- )
736
- moduleModel: Optional[ModuleModel] = Field(
737
- None,
738
- description=(
739
- "The model of the module that the labware will be loaded onto,"
740
- " if applicable."
741
- "\n\n"
742
- "Because of module compatibility, the model that the protocol requests"
743
- " may not be exactly the same"
744
- " as what it will find physically connected during execution."
745
- " For this labware offset to apply,"
746
- " this field must be the *requested* model, not the connected one."
747
- " You can retrieve this from a `loadModule` command's `params.model`"
748
- " in the protocol's analysis."
749
- ),
750
- )
751
- definitionUri: Optional[str] = Field(
752
- None,
753
- description=(
754
- "The definition URI of a labware that a labware can be loaded onto,"
755
- " if applicable."
756
- "\n\n"
757
- "This can be combined with moduleModel if the labware is loaded on top of"
758
- " an adapter that is loaded on a module."
759
- ),
760
- )
761
-
762
-
763
- class LabwareOffset(BaseModel):
764
- """An offset that the robot adds to a pipette's position when it moves to a labware.
765
-
766
- During the run, if a labware is loaded whose definition URI and location
767
- both match what's found here, the given offset will be added to all
768
- pipette movements that use that labware as a reference point.
769
- """
770
-
771
- id: str = Field(..., description="Unique labware offset record identifier.")
772
- createdAt: datetime = Field(..., description="When this labware offset was added.")
773
- definitionUri: str = Field(..., description="The URI for the labware's definition.")
774
- location: LabwareOffsetLocation = Field(
775
- ...,
776
- description="Where the labware is located on the robot.",
777
- )
778
- vector: LabwareOffsetVector = Field(
779
- ...,
780
- description="The offset applied to matching labware.",
781
- )
782
-
783
-
784
- class LabwareOffsetCreate(BaseModel):
785
- """Create request data for a labware offset."""
786
-
787
- definitionUri: str = Field(..., description="The URI for the labware's definition.")
788
- location: LabwareOffsetLocation = Field(
789
- ...,
790
- description="Where the labware is located on the robot.",
791
- )
792
- vector: LabwareOffsetVector = Field(
793
- ...,
794
- description="The offset applied to matching labware.",
795
- )
796
-
797
-
798
- class LoadedLabware(BaseModel):
799
- """A labware that has been loaded."""
800
-
801
- id: str
802
- loadName: str
803
- definitionUri: str
804
- location: LabwareLocation = Field(
805
- ..., description="The labware's current location."
806
- )
807
- lid_id: Optional[str] = Field(
808
- None,
809
- description=("Labware ID of a Lid currently loaded on top of the labware."),
810
- )
811
- offsetId: Optional[str] = Field(
812
- None,
813
- description=(
814
- "An ID referencing the labware offset"
815
- " that applies to this labware placement."
816
- " Null or undefined means no offset was provided for this load,"
817
- " so the default of (0, 0, 0) will be used."
818
- ),
819
- )
820
- displayName: Optional[str] = Field(
821
- None,
822
- description="A user-specified display name for this labware, if provided.",
823
- )
824
-
825
-
826
- class HexColor(RootModel[str]):
827
- """Hex color representation."""
828
-
829
- root: str = Field(pattern=r"^#(?:[0-9a-fA-F]{3,4}){1,2}$")
830
-
831
-
832
- EmptyLiquidId = Literal["EMPTY"]
833
- LiquidId = str | EmptyLiquidId
834
-
835
-
836
- class Liquid(BaseModel):
837
- """Payload required to create a liquid."""
838
-
839
- id: str
840
- displayName: str
841
- description: str
842
- displayColor: Optional[HexColor] = None
843
-
844
-
845
- class LiquidClassRecord(ByTipTypeSetting, frozen=True):
846
- """LiquidClassRecord is our internal representation of an (immutable) liquid class.
847
-
848
- Conceptually, a liquid class record is the tuple (name, pipette, tip, transfer properties).
849
- We consider two liquid classes to be the same if every entry in that tuple is the same; and liquid
850
- classes are different if any entry in the tuple is different.
851
-
852
- This class defines the tuple via inheritance so that we can reuse the definitions from shared_data.
853
- """
854
-
855
- liquidClassName: str = Field(
856
- ...,
857
- description="Identifier for the liquid of this liquid class, e.g. glycerol50.",
858
- )
859
- pipetteModel: str = Field(
860
- ...,
861
- description="Identifier for the pipette of this liquid class.",
862
- )
863
- # The other fields like tiprack ID, aspirate properties, etc. are pulled in from ByTipTypeSetting.
864
-
865
- def __hash__(self) -> int:
866
- """Hash function for LiquidClassRecord."""
867
- # Within the Protocol Engine, LiquidClassRecords are immutable, and we'd like to be able to
868
- # look up LiquidClassRecords by value, which involves hashing. However, Pydantic does not
869
- # generate a usable hash function if any of the subfields (like Coordinate) are not frozen.
870
- # So we have to implement the hash function ourselves.
871
- # Our strategy is to recursively convert this object into a list of (key, value) tuples.
872
- def dict_to_tuple(d: dict[str, Any]) -> tuple[tuple[str, Any], ...]:
873
- return tuple(
874
- (
875
- field_name,
876
- dict_to_tuple(value)
877
- if isinstance(value, dict)
878
- else tuple(value)
879
- if isinstance(value, list)
880
- else value,
881
- )
882
- for field_name, value in d.items()
883
- )
884
-
885
- return hash(dict_to_tuple(self.model_dump()))
886
-
887
-
888
- class LiquidClassRecordWithId(LiquidClassRecord, frozen=True):
889
- """A LiquidClassRecord with its ID, for use in summary lists."""
890
-
891
- liquidClassId: str = Field(
892
- ...,
893
- description="Unique identifier for this liquid class.",
894
- )
895
-
896
-
897
- class SpeedRange(NamedTuple):
898
- """Minimum and maximum allowed speeds for a shaking module."""
899
-
900
- min: int
901
- max: int
902
-
903
-
904
- class TemperatureRange(NamedTuple):
905
- """Minimum and maximum allowed temperatures for a heating module."""
906
-
907
- min: float
908
- max: float
909
-
910
-
911
- class HeaterShakerLatchStatus(Enum):
912
- """Heater-Shaker latch status for determining pipette and labware movement errors."""
913
-
914
- CLOSED = "closed"
915
- OPEN = "open"
916
- UNKNOWN = "unknown"
917
-
918
-
919
- @dataclass(frozen=True)
920
- class HeaterShakerMovementRestrictors:
921
- """Shaking status, latch status and slot location for determining movement restrictions."""
922
-
923
- plate_shaking: bool
924
- latch_status: HeaterShakerLatchStatus
925
- deck_slot: int
926
-
927
-
928
- class LabwareMovementStrategy(str, Enum):
929
- """Strategy to use for labware movement."""
930
-
931
- USING_GRIPPER = "usingGripper"
932
- MANUAL_MOVE_WITH_PAUSE = "manualMoveWithPause"
933
- MANUAL_MOVE_WITHOUT_PAUSE = "manualMoveWithoutPause"
934
-
935
-
936
- @dataclass(frozen=True)
937
- class PotentialCutoutFixture:
938
- """Cutout and cutout fixture id associated with a potential cutout fixture that can be on the deck."""
939
-
940
- cutout_id: str
941
- cutout_fixture_id: str
942
- provided_addressable_areas: FrozenSet[str]
943
-
944
-
945
- class AreaType(Enum):
946
- """The type of addressable area."""
947
-
948
- SLOT = "slot"
949
- STAGING_SLOT = "stagingSlot"
950
- MOVABLE_TRASH = "movableTrash"
951
- FIXED_TRASH = "fixedTrash"
952
- WASTE_CHUTE = "wasteChute"
953
- THERMOCYCLER = "thermocycler"
954
- HEATER_SHAKER = "heaterShaker"
955
- TEMPERATURE = "temperatureModule"
956
- MAGNETICBLOCK = "magneticBlock"
957
- ABSORBANCE_READER = "absorbanceReader"
958
- LID_DOCK = "lidDock"
959
-
960
-
961
- @dataclass(frozen=True)
962
- class AddressableArea:
963
- """Addressable area that has been loaded."""
964
-
965
- area_name: str
966
- area_type: AreaType
967
- base_slot: DeckSlotName
968
- display_name: str
969
- bounding_box: Dimensions
970
- position: AddressableOffsetVector
971
- compatible_module_types: List[SharedDataModuleType]
972
-
973
-
974
- class PostRunHardwareState(Enum):
975
- """State of robot gantry & motors after a stop is performed and the hardware API is reset.
976
-
977
- HOME_AND_STAY_ENGAGED: home the gantry and keep all motors engaged. This allows the
978
- robot to continue performing movement actions without re-homing
979
- HOME_THEN_DISENGAGE: home the gantry and then disengage motors.
980
- Reduces current consumption of the motors and prevents coil heating.
981
- Re-homing is required to re-engage the motors and resume robot movement.
982
- STAY_ENGAGED_IN_PLACE: do not home after the stop and keep the motors engaged.
983
- Keeps gantry in the same position as prior to `stop()` execution
984
- and allows the robot to execute movement commands without requiring to re-home first.
985
- DISENGAGE_IN_PLACE: disengage motors and do not home the robot
986
- Probable states for pipette:
987
- - for 1- or 8-channel:
988
- - HOME_AND_STAY_ENGAGED after protocol runs
989
- - STAY_ENGAGED_IN_PLACE after maintenance runs
990
- - for 96-channel:
991
- - HOME_THEN_DISENGAGE after protocol runs
992
- - DISENGAGE_IN_PLACE after maintenance runs
993
- """
994
-
995
- HOME_AND_STAY_ENGAGED = "homeAndStayEngaged"
996
- HOME_THEN_DISENGAGE = "homeThenDisengage"
997
- STAY_ENGAGED_IN_PLACE = "stayEngagedInPlace"
998
- DISENGAGE_IN_PLACE = "disengageInPlace"
999
-
1000
-
1001
- NOZZLE_NAME_REGEX = r"[A-Z]\d{1,2}"
1002
- PRIMARY_NOZZLE_LITERAL = Literal["A1", "H1", "A12", "H12"]
1003
-
1004
-
1005
- class AllNozzleLayoutConfiguration(BaseModel):
1006
- """All basemodel to represent a reset to the nozzle configuration. Sending no parameters resets to default."""
1007
-
1008
- style: Literal["ALL"] = "ALL"
1009
-
1010
-
1011
- class SingleNozzleLayoutConfiguration(BaseModel):
1012
- """Minimum information required for a new nozzle configuration."""
1013
-
1014
- style: Literal["SINGLE"] = "SINGLE"
1015
- primaryNozzle: PRIMARY_NOZZLE_LITERAL = Field(
1016
- ...,
1017
- description="The primary nozzle to use in the layout configuration. This nozzle will update the critical point of the current pipette. For now, this is also the back left corner of your rectangle.",
1018
- )
1019
-
1020
-
1021
- class RowNozzleLayoutConfiguration(BaseModel):
1022
- """Minimum information required for a new nozzle configuration."""
1023
-
1024
- style: Literal["ROW"] = "ROW"
1025
- primaryNozzle: PRIMARY_NOZZLE_LITERAL = Field(
1026
- ...,
1027
- description="The primary nozzle to use in the layout configuration. This nozzle will update the critical point of the current pipette. For now, this is also the back left corner of your rectangle.",
1028
- )
1029
-
1030
-
1031
- class ColumnNozzleLayoutConfiguration(BaseModel):
1032
- """Information required for nozzle configurations of type ROW and COLUMN."""
1033
-
1034
- style: Literal["COLUMN"] = "COLUMN"
1035
- primaryNozzle: PRIMARY_NOZZLE_LITERAL = Field(
1036
- ...,
1037
- description="The primary nozzle to use in the layout configuration. This nozzle will update the critical point of the current pipette. For now, this is also the back left corner of your rectangle.",
1038
- )
1039
-
1040
-
1041
- class QuadrantNozzleLayoutConfiguration(BaseModel):
1042
- """Information required for nozzle configurations of type QUADRANT."""
1043
-
1044
- style: Literal["QUADRANT"] = "QUADRANT"
1045
- primaryNozzle: PRIMARY_NOZZLE_LITERAL = Field(
1046
- ...,
1047
- description="The primary nozzle to use in the layout configuration. This nozzle will update the critical point of the current pipette. For now, this is also the back left corner of your rectangle.",
1048
- )
1049
- frontRightNozzle: str = Field(
1050
- ...,
1051
- pattern=NOZZLE_NAME_REGEX,
1052
- description="The front right nozzle in your configuration.",
1053
- )
1054
- backLeftNozzle: str = Field(
1055
- ...,
1056
- pattern=NOZZLE_NAME_REGEX,
1057
- description="The back left nozzle in your configuration.",
1058
- )
1059
-
1060
-
1061
- NozzleLayoutConfigurationType = Union[
1062
- AllNozzleLayoutConfiguration,
1063
- SingleNozzleLayoutConfiguration,
1064
- ColumnNozzleLayoutConfiguration,
1065
- RowNozzleLayoutConfiguration,
1066
- QuadrantNozzleLayoutConfiguration,
1067
- ]
1068
-
1069
- # TODO make the below some sort of better type
1070
- # TODO This should instead contain a proper cutout fixture type
1071
- DeckConfigurationType = List[
1072
- Tuple[str, str, Optional[str]]
1073
- ] # cutout_id, cutout_fixture_id, opentrons_module_serial_number
1074
-
1075
-
1076
- class InstrumentSensorId(str, Enum):
1077
- """Primary and secondary sensor ids."""
1078
-
1079
- PRIMARY = "primary"
1080
- SECONDARY = "secondary"
1081
- BOTH = "both"
1082
-
1083
- def to_instrument_probe_type(self) -> InstrumentProbeType:
1084
- """Convert to InstrumentProbeType."""
1085
- return {
1086
- InstrumentSensorId.PRIMARY: InstrumentProbeType.PRIMARY,
1087
- InstrumentSensorId.SECONDARY: InstrumentProbeType.SECONDARY,
1088
- InstrumentSensorId.BOTH: InstrumentProbeType.BOTH,
1089
- }[self]
1090
-
1091
-
1092
- class TipPresenceStatus(str, Enum):
1093
- """Tip presence status reported by a pipette."""
1094
-
1095
- PRESENT = "present"
1096
- ABSENT = "absent"
1097
- UNKNOWN = "unknown"
1098
-
1099
- def to_hw_state(self) -> HwTipStateType:
1100
- """Convert to hardware tip state."""
1101
- assert self != TipPresenceStatus.UNKNOWN
1102
- return {
1103
- TipPresenceStatus.PRESENT: HwTipStateType.PRESENT,
1104
- TipPresenceStatus.ABSENT: HwTipStateType.ABSENT,
1105
- }[self]
1106
-
1107
- @classmethod
1108
- def from_hw_state(cls, state: HwTipStateType) -> "TipPresenceStatus":
1109
- """Convert from hardware tip state."""
1110
- return {
1111
- HwTipStateType.PRESENT: TipPresenceStatus.PRESENT,
1112
- HwTipStateType.ABSENT: TipPresenceStatus.ABSENT,
1113
- }[state]
1114
-
1115
-
1116
- class NextTipInfo(BaseModel):
1117
- """Next available tip labware and well name data."""
1118
-
1119
- labwareId: str = Field(
1120
- ...,
1121
- description="The labware ID of the tip rack where the next available tip(s) are located.",
1122
- )
1123
- tipStartingWell: str = Field(
1124
- ..., description="The (starting) well name of the next available tip(s)."
1125
- )
1126
-
1127
-
1128
- class NoTipReason(Enum):
1129
- """The cause of no tip being available for a pipette and tip rack(s)."""
1130
-
1131
- NO_AVAILABLE_TIPS = "noAvailableTips"
1132
- STARTING_TIP_WITH_PARTIAL = "startingTipWithPartial"
1133
- INCOMPATIBLE_CONFIGURATION = "incompatibleConfiguration"
1134
-
1135
-
1136
- class NoTipAvailable(BaseModel):
1137
- """No available next tip data."""
1138
-
1139
- noTipReason: NoTipReason = Field(
1140
- ..., description="The reason why no next available tip could be provided."
1141
- )
1142
- message: Optional[str] = Field(
1143
- None, description="Optional message explaining why a tip wasn't available."
1144
- )
1145
-
1146
-
1147
- class BaseCommandAnnotation(BaseModel):
1148
- """Optional annotations for protocol engine commands."""
1149
-
1150
- commandKeys: List[str] = Field(
1151
- ..., description="Command keys to which this annotation applies"
1152
- )
1153
- annotationType: str = Field(
1154
- ..., description="The type of annotation (for machine parsing)"
1155
- )
1156
-
1157
-
1158
- class SecondOrderCommandAnnotation(BaseCommandAnnotation):
1159
- """Annotates a group of atomic commands which were the direct result of a second order command.
1160
-
1161
- Examples of second order commands would be transfer, consolidate, mix, etc.
1162
- """
1163
-
1164
- annotationType: Literal["secondOrderCommand"] = "secondOrderCommand"
1165
- params: Dict[str, Any] = Field(
1166
- ...,
1167
- description="Key value pairs of the parameters passed to the second order command that this annotates.",
1168
- )
1169
- machineReadableName: str = Field(
1170
- ...,
1171
- description="The name of the second order command in the form that the generating software refers to it",
1172
- )
1173
- userSpecifiedName: Optional[str] = Field(
1174
- None, description="The optional user-specified name of the second order command"
1175
- )
1176
- userSpecifiedDescription: Optional[str] = Field(
1177
- None,
1178
- description="The optional user-specified description of the second order command",
1179
- )
1180
-
1181
-
1182
- class CustomCommandAnnotation(BaseCommandAnnotation):
1183
- """Annotates a group of atomic commands in some manner that Opentrons software does not anticipate or originate."""
1184
-
1185
- annotationType: Literal["custom"] = "custom"
1186
- model_config = ConfigDict(extra="allow")
1187
-
1188
-
1189
- CommandAnnotation = Union[SecondOrderCommandAnnotation, CustomCommandAnnotation]
1190
-
1191
-
1192
- # TODO (spp, 2024-04-02): move all RTP types to runner
1193
- class RTPBase(BaseModel):
1194
- """Parameters defined in a protocol."""
1195
-
1196
- displayName: StrictStr = Field(..., description="Display string for the parameter.")
1197
- variableName: StrictStr = Field(
1198
- ..., description="Python variable name of the parameter."
1199
- )
1200
- description: Optional[StrictStr] = Field(
1201
- None, description="Detailed description of the parameter."
1202
- )
1203
- suffix: Optional[StrictStr] = Field(
1204
- None,
1205
- description="Units (like mL, mm/sec, etc) or a custom suffix for the parameter.",
1206
- )
1207
-
1208
-
1209
- class NumberParameter(RTPBase):
1210
- """An integer parameter defined in a protocol."""
1211
-
1212
- type: Literal["int", "float"] = Field(
1213
- ..., description="String specifying whether the number is an int or float type."
1214
- )
1215
- min: Union[StrictInt, StrictFloat] = Field(
1216
- ..., description="Minimum value that the number param is allowed to have."
1217
- )
1218
- max: Union[StrictInt, StrictFloat] = Field(
1219
- ..., description="Maximum value that the number param is allowed to have."
1220
- )
1221
- value: Union[StrictInt, StrictFloat] = Field(
1222
- ...,
1223
- description="The value assigned to the parameter; if not supplied by the client, will be assigned the default value.",
1224
- )
1225
- default: Union[StrictInt, StrictFloat] = Field(
1226
- ...,
1227
- description="Default value of the parameter, to be used when there is no client-specified value.",
1228
- )
1229
-
1230
-
1231
- class BooleanParameter(RTPBase):
1232
- """A boolean parameter defined in a protocol."""
1233
-
1234
- type: Literal["bool"] = Field(
1235
- default="bool", description="String specifying the type of this parameter"
1236
- )
1237
- value: StrictBool = Field(
1238
- ...,
1239
- description="The value assigned to the parameter; if not supplied by the client, will be assigned the default value.",
1240
- )
1241
- default: StrictBool = Field(
1242
- ...,
1243
- description="Default value of the parameter, to be used when there is no client-specified value.",
1244
- )
1245
-
1246
-
1247
- class EnumChoice(BaseModel):
1248
- """Components of choices used in RTP Enum Parameters."""
1249
-
1250
- displayName: StrictStr = Field(
1251
- ..., description="Display string for the param's choice."
1252
- )
1253
- value: Union[StrictInt, StrictFloat, StrictStr] = Field(
1254
- ..., description="Enum value of the param's choice."
1255
- )
1256
-
1257
-
1258
- class EnumParameter(RTPBase):
1259
- """A string enum defined in a protocol."""
1260
-
1261
- type: Literal["int", "float", "str"] = Field(
1262
- ...,
1263
- description="String specifying whether the parameter is an int or float or string type.",
1264
- )
1265
- choices: List[EnumChoice] = Field(
1266
- ..., description="List of valid choices for this parameter."
1267
- )
1268
- value: Union[StrictInt, StrictFloat, StrictStr] = Field(
1269
- ...,
1270
- description="The value assigned to the parameter; if not supplied by the client, will be assigned the default value.",
1271
- )
1272
- default: Union[StrictInt, StrictFloat, StrictStr] = Field(
1273
- ...,
1274
- description="Default value of the parameter, to be used when there is no client-specified value.",
1275
- )
1276
-
1277
-
1278
- class FileInfo(BaseModel):
1279
- """A file UUID descriptor."""
1280
-
1281
- id: str = Field(
1282
- ...,
1283
- description="The UUID identifier of the file stored on the robot.",
1284
- )
1285
- name: str = Field(..., description="Name of the file, including the extension.")
1286
-
1287
-
1288
- class CSVParameter(RTPBase):
1289
- """A CSV file parameter defined in a protocol."""
1290
-
1291
- type: Literal["csv_file"] = Field(
1292
- default="csv_file", description="String specifying the type of this parameter"
1293
- )
1294
- file: Optional[FileInfo] = Field(
1295
- default=None,
1296
- description="ID of the CSV file stored on the robot; to be used for fetching the CSV file."
1297
- " For local analysis this will most likely be empty.",
1298
- )
1299
-
1300
-
1301
- RunTimeParameter = Union[NumberParameter, EnumParameter, BooleanParameter, CSVParameter]
1302
-
1303
- PrimitiveRunTimeParamValuesType = Mapping[
1304
- StrictStr, Union[StrictInt, StrictFloat, StrictBool, StrictStr]
1305
- ] # update value types as more RTP types are added
1306
-
1307
- CSVRunTimeParamFilesType = Mapping[StrictStr, StrictStr]
1308
- CSVRuntimeParamPaths = Dict[str, Path]
1309
-
1310
-
1311
- ABSMeasureMode = Literal["single", "multi"]