opentrons 8.3.2__py2.py3-none-any.whl → 8.4.0__py2.py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


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

Files changed (196) hide show
  1. opentrons/calibration_storage/ot2/mark_bad_calibration.py +2 -0
  2. opentrons/calibration_storage/ot2/tip_length.py +6 -6
  3. opentrons/config/advanced_settings.py +9 -11
  4. opentrons/config/feature_flags.py +0 -4
  5. opentrons/config/reset.py +7 -2
  6. opentrons/drivers/asyncio/communication/__init__.py +2 -0
  7. opentrons/drivers/asyncio/communication/async_serial.py +4 -0
  8. opentrons/drivers/asyncio/communication/errors.py +41 -8
  9. opentrons/drivers/asyncio/communication/serial_connection.py +36 -10
  10. opentrons/drivers/flex_stacker/__init__.py +9 -3
  11. opentrons/drivers/flex_stacker/abstract.py +140 -15
  12. opentrons/drivers/flex_stacker/driver.py +593 -47
  13. opentrons/drivers/flex_stacker/errors.py +64 -0
  14. opentrons/drivers/flex_stacker/simulator.py +222 -24
  15. opentrons/drivers/flex_stacker/types.py +211 -15
  16. opentrons/drivers/flex_stacker/utils.py +19 -0
  17. opentrons/execute.py +4 -2
  18. opentrons/hardware_control/api.py +5 -0
  19. opentrons/hardware_control/backends/flex_protocol.py +4 -0
  20. opentrons/hardware_control/backends/ot3controller.py +12 -1
  21. opentrons/hardware_control/backends/ot3simulator.py +3 -0
  22. opentrons/hardware_control/backends/subsystem_manager.py +8 -4
  23. opentrons/hardware_control/instruments/ot2/instrument_calibration.py +10 -6
  24. opentrons/hardware_control/instruments/ot3/pipette_handler.py +59 -6
  25. opentrons/hardware_control/modules/__init__.py +12 -1
  26. opentrons/hardware_control/modules/absorbance_reader.py +11 -9
  27. opentrons/hardware_control/modules/flex_stacker.py +498 -0
  28. opentrons/hardware_control/modules/heater_shaker.py +12 -10
  29. opentrons/hardware_control/modules/magdeck.py +5 -1
  30. opentrons/hardware_control/modules/tempdeck.py +5 -1
  31. opentrons/hardware_control/modules/thermocycler.py +15 -14
  32. opentrons/hardware_control/modules/types.py +191 -1
  33. opentrons/hardware_control/modules/utils.py +3 -0
  34. opentrons/hardware_control/motion_utilities.py +20 -0
  35. opentrons/hardware_control/ot3api.py +145 -15
  36. opentrons/hardware_control/protocols/liquid_handler.py +47 -1
  37. opentrons/hardware_control/types.py +6 -0
  38. opentrons/legacy_commands/commands.py +102 -5
  39. opentrons/legacy_commands/helpers.py +74 -1
  40. opentrons/legacy_commands/types.py +33 -2
  41. opentrons/protocol_api/__init__.py +2 -0
  42. opentrons/protocol_api/_liquid.py +39 -8
  43. opentrons/protocol_api/_liquid_properties.py +20 -19
  44. opentrons/protocol_api/_transfer_liquid_validation.py +91 -0
  45. opentrons/protocol_api/core/common.py +3 -1
  46. opentrons/protocol_api/core/engine/deck_conflict.py +11 -1
  47. opentrons/protocol_api/core/engine/instrument.py +1356 -107
  48. opentrons/protocol_api/core/engine/labware.py +8 -4
  49. opentrons/protocol_api/core/engine/load_labware_params.py +68 -10
  50. opentrons/protocol_api/core/engine/module_core.py +118 -2
  51. opentrons/protocol_api/core/engine/pipette_movement_conflict.py +6 -14
  52. opentrons/protocol_api/core/engine/protocol.py +253 -11
  53. opentrons/protocol_api/core/engine/stringify.py +19 -8
  54. opentrons/protocol_api/core/engine/transfer_components_executor.py +858 -0
  55. opentrons/protocol_api/core/engine/well.py +73 -5
  56. opentrons/protocol_api/core/instrument.py +71 -21
  57. opentrons/protocol_api/core/labware.py +6 -2
  58. opentrons/protocol_api/core/legacy/labware_offset_provider.py +7 -3
  59. opentrons/protocol_api/core/legacy/legacy_instrument_core.py +76 -49
  60. opentrons/protocol_api/core/legacy/legacy_labware_core.py +8 -4
  61. opentrons/protocol_api/core/legacy/legacy_protocol_core.py +36 -0
  62. opentrons/protocol_api/core/legacy/legacy_well_core.py +27 -2
  63. opentrons/protocol_api/core/legacy/load_info.py +4 -12
  64. opentrons/protocol_api/core/legacy/module_geometry.py +6 -1
  65. opentrons/protocol_api/core/legacy/well_geometry.py +3 -3
  66. opentrons/protocol_api/core/legacy_simulator/legacy_instrument_core.py +73 -23
  67. opentrons/protocol_api/core/module.py +43 -0
  68. opentrons/protocol_api/core/protocol.py +33 -0
  69. opentrons/protocol_api/core/well.py +23 -2
  70. opentrons/protocol_api/instrument_context.py +454 -150
  71. opentrons/protocol_api/labware.py +98 -50
  72. opentrons/protocol_api/module_contexts.py +140 -0
  73. opentrons/protocol_api/protocol_context.py +163 -19
  74. opentrons/protocol_api/validation.py +51 -41
  75. opentrons/protocol_engine/__init__.py +21 -2
  76. opentrons/protocol_engine/actions/actions.py +5 -5
  77. opentrons/protocol_engine/clients/sync_client.py +6 -0
  78. opentrons/protocol_engine/commands/__init__.py +66 -36
  79. opentrons/protocol_engine/commands/absorbance_reader/__init__.py +0 -1
  80. opentrons/protocol_engine/commands/air_gap_in_place.py +3 -2
  81. opentrons/protocol_engine/commands/aspirate.py +6 -2
  82. opentrons/protocol_engine/commands/aspirate_in_place.py +3 -1
  83. opentrons/protocol_engine/commands/aspirate_while_tracking.py +210 -0
  84. opentrons/protocol_engine/commands/blow_out.py +2 -0
  85. opentrons/protocol_engine/commands/blow_out_in_place.py +4 -1
  86. opentrons/protocol_engine/commands/command_unions.py +102 -33
  87. opentrons/protocol_engine/commands/configure_for_volume.py +3 -0
  88. opentrons/protocol_engine/commands/dispense.py +3 -1
  89. opentrons/protocol_engine/commands/dispense_in_place.py +3 -0
  90. opentrons/protocol_engine/commands/dispense_while_tracking.py +204 -0
  91. opentrons/protocol_engine/commands/drop_tip.py +23 -1
  92. opentrons/protocol_engine/commands/flex_stacker/__init__.py +106 -0
  93. opentrons/protocol_engine/commands/flex_stacker/close_latch.py +72 -0
  94. opentrons/protocol_engine/commands/flex_stacker/common.py +15 -0
  95. opentrons/protocol_engine/commands/flex_stacker/empty.py +161 -0
  96. opentrons/protocol_engine/commands/flex_stacker/fill.py +164 -0
  97. opentrons/protocol_engine/commands/flex_stacker/open_latch.py +70 -0
  98. opentrons/protocol_engine/commands/flex_stacker/prepare_shuttle.py +112 -0
  99. opentrons/protocol_engine/commands/flex_stacker/retrieve.py +394 -0
  100. opentrons/protocol_engine/commands/flex_stacker/set_stored_labware.py +190 -0
  101. opentrons/protocol_engine/commands/flex_stacker/store.py +291 -0
  102. opentrons/protocol_engine/commands/generate_command_schema.py +31 -2
  103. opentrons/protocol_engine/commands/labware_handling_common.py +29 -0
  104. opentrons/protocol_engine/commands/liquid_probe.py +27 -13
  105. opentrons/protocol_engine/commands/load_labware.py +42 -39
  106. opentrons/protocol_engine/commands/load_lid.py +21 -13
  107. opentrons/protocol_engine/commands/load_lid_stack.py +130 -47
  108. opentrons/protocol_engine/commands/load_module.py +18 -17
  109. opentrons/protocol_engine/commands/load_pipette.py +3 -0
  110. opentrons/protocol_engine/commands/move_labware.py +139 -20
  111. opentrons/protocol_engine/commands/move_to_well.py +5 -11
  112. opentrons/protocol_engine/commands/pick_up_tip.py +5 -2
  113. opentrons/protocol_engine/commands/pipetting_common.py +159 -8
  114. opentrons/protocol_engine/commands/prepare_to_aspirate.py +15 -5
  115. opentrons/protocol_engine/commands/{evotip_dispense.py → pressure_dispense.py} +33 -34
  116. opentrons/protocol_engine/commands/reload_labware.py +6 -19
  117. opentrons/protocol_engine/commands/{evotip_seal_pipette.py → seal_pipette_to_tip.py} +97 -76
  118. opentrons/protocol_engine/commands/unsafe/unsafe_blow_out_in_place.py +3 -1
  119. opentrons/protocol_engine/commands/unsafe/unsafe_drop_tip_in_place.py +6 -1
  120. opentrons/protocol_engine/commands/{evotip_unseal_pipette.py → unseal_pipette_from_tip.py} +31 -40
  121. opentrons/protocol_engine/errors/__init__.py +10 -0
  122. opentrons/protocol_engine/errors/exceptions.py +62 -0
  123. opentrons/protocol_engine/execution/equipment.py +123 -106
  124. opentrons/protocol_engine/execution/labware_movement.py +8 -6
  125. opentrons/protocol_engine/execution/pipetting.py +235 -25
  126. opentrons/protocol_engine/execution/tip_handler.py +82 -32
  127. opentrons/protocol_engine/labware_offset_standardization.py +194 -0
  128. opentrons/protocol_engine/protocol_engine.py +22 -13
  129. opentrons/protocol_engine/resources/deck_configuration_provider.py +98 -2
  130. opentrons/protocol_engine/resources/deck_data_provider.py +1 -1
  131. opentrons/protocol_engine/resources/labware_data_provider.py +32 -12
  132. opentrons/protocol_engine/resources/labware_validation.py +7 -5
  133. opentrons/protocol_engine/slot_standardization.py +11 -23
  134. opentrons/protocol_engine/state/addressable_areas.py +84 -46
  135. opentrons/protocol_engine/state/frustum_helpers.py +36 -14
  136. opentrons/protocol_engine/state/geometry.py +892 -227
  137. opentrons/protocol_engine/state/labware.py +252 -55
  138. opentrons/protocol_engine/state/module_substates/__init__.py +4 -0
  139. opentrons/protocol_engine/state/module_substates/flex_stacker_substate.py +68 -0
  140. opentrons/protocol_engine/state/module_substates/heater_shaker_module_substate.py +22 -0
  141. opentrons/protocol_engine/state/module_substates/temperature_module_substate.py +13 -0
  142. opentrons/protocol_engine/state/module_substates/thermocycler_module_substate.py +20 -0
  143. opentrons/protocol_engine/state/modules.py +210 -67
  144. opentrons/protocol_engine/state/pipettes.py +54 -0
  145. opentrons/protocol_engine/state/state.py +1 -1
  146. opentrons/protocol_engine/state/tips.py +14 -0
  147. opentrons/protocol_engine/state/update_types.py +180 -25
  148. opentrons/protocol_engine/state/wells.py +55 -9
  149. opentrons/protocol_engine/types/__init__.py +300 -0
  150. opentrons/protocol_engine/types/automatic_tip_selection.py +39 -0
  151. opentrons/protocol_engine/types/command_annotations.py +53 -0
  152. opentrons/protocol_engine/types/deck_configuration.py +72 -0
  153. opentrons/protocol_engine/types/execution.py +96 -0
  154. opentrons/protocol_engine/types/hardware_passthrough.py +25 -0
  155. opentrons/protocol_engine/types/instrument.py +47 -0
  156. opentrons/protocol_engine/types/instrument_sensors.py +47 -0
  157. opentrons/protocol_engine/types/labware.py +111 -0
  158. opentrons/protocol_engine/types/labware_movement.py +22 -0
  159. opentrons/protocol_engine/types/labware_offset_location.py +111 -0
  160. opentrons/protocol_engine/types/labware_offset_vector.py +33 -0
  161. opentrons/protocol_engine/types/liquid.py +40 -0
  162. opentrons/protocol_engine/types/liquid_class.py +59 -0
  163. opentrons/protocol_engine/types/liquid_handling.py +13 -0
  164. opentrons/protocol_engine/types/liquid_level_detection.py +131 -0
  165. opentrons/protocol_engine/types/location.py +194 -0
  166. opentrons/protocol_engine/types/module.py +301 -0
  167. opentrons/protocol_engine/types/partial_tip_configuration.py +76 -0
  168. opentrons/protocol_engine/types/run_time_parameters.py +133 -0
  169. opentrons/protocol_engine/types/tip.py +18 -0
  170. opentrons/protocol_engine/types/util.py +21 -0
  171. opentrons/protocol_engine/types/well_position.py +124 -0
  172. opentrons/protocol_reader/extract_labware_definitions.py +7 -3
  173. opentrons/protocol_reader/file_format_validator.py +5 -3
  174. opentrons/protocol_runner/json_translator.py +4 -2
  175. opentrons/protocol_runner/legacy_command_mapper.py +6 -2
  176. opentrons/protocol_runner/run_orchestrator.py +4 -1
  177. opentrons/protocols/advanced_control/transfers/common.py +48 -1
  178. opentrons/protocols/advanced_control/transfers/transfer_liquid_utils.py +204 -0
  179. opentrons/protocols/api_support/definitions.py +1 -1
  180. opentrons/protocols/api_support/instrument.py +16 -3
  181. opentrons/protocols/labware.py +27 -23
  182. opentrons/protocols/models/__init__.py +0 -21
  183. opentrons/simulate.py +4 -2
  184. opentrons/types.py +20 -7
  185. opentrons/util/logging_config.py +94 -25
  186. opentrons/util/logging_queue_handler.py +61 -0
  187. {opentrons-8.3.2.dist-info → opentrons-8.4.0.dist-info}/METADATA +4 -4
  188. {opentrons-8.3.2.dist-info → opentrons-8.4.0.dist-info}/RECORD +192 -151
  189. opentrons/calibration_storage/ot2/models/defaults.py +0 -0
  190. opentrons/calibration_storage/ot3/models/defaults.py +0 -0
  191. opentrons/protocol_api/core/legacy/legacy_robot_core.py +0 -0
  192. opentrons/protocol_engine/types.py +0 -1311
  193. {opentrons-8.3.2.dist-info → opentrons-8.4.0.dist-info}/LICENSE +0 -0
  194. {opentrons-8.3.2.dist-info → opentrons-8.4.0.dist-info}/WHEEL +0 -0
  195. {opentrons-8.3.2.dist-info → opentrons-8.4.0.dist-info}/entry_points.txt +0 -0
  196. {opentrons-8.3.2.dist-info → opentrons-8.4.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,106 @@
1
+ """Command models for Flex Stacker commands."""
2
+
3
+ from .store import (
4
+ StoreCommandType,
5
+ StoreParams,
6
+ StoreResult,
7
+ Store,
8
+ StoreCreate,
9
+ )
10
+
11
+ from .retrieve import (
12
+ RetrieveCommandType,
13
+ RetrieveParams,
14
+ RetrieveResult,
15
+ Retrieve,
16
+ RetrieveCreate,
17
+ )
18
+
19
+ from .set_stored_labware import (
20
+ SetStoredLabwareCommandType,
21
+ SetStoredLabwareParams,
22
+ SetStoredLabwareResult,
23
+ SetStoredLabware,
24
+ SetStoredLabwareCreate,
25
+ StackerStoredLabwareDetails,
26
+ )
27
+
28
+ from .fill import FillCommandType, FillParams, FillResult, Fill, FillCreate
29
+
30
+ from .empty import EmptyCommandType, EmptyParams, EmptyResult, Empty, EmptyCreate
31
+
32
+ from .close_latch import (
33
+ CloseLatchCommandType,
34
+ CloseLatchParams,
35
+ CloseLatchResult,
36
+ CloseLatch,
37
+ CloseLatchCreate,
38
+ )
39
+ from .open_latch import (
40
+ OpenLatchCommandType,
41
+ OpenLatchParams,
42
+ OpenLatchResult,
43
+ OpenLatch,
44
+ OpenLatchCreate,
45
+ )
46
+
47
+ from .prepare_shuttle import (
48
+ PrepareShuttleCommandType,
49
+ PrepareShuttleParams,
50
+ PrepareShuttleResult,
51
+ PrepareShuttle,
52
+ PrepareShuttleCreate,
53
+ )
54
+
55
+
56
+ __all__ = [
57
+ # flexStacker/store
58
+ "StoreCommandType",
59
+ "StoreParams",
60
+ "StoreResult",
61
+ "Store",
62
+ "StoreCreate",
63
+ # flexStacker/retrieve
64
+ "RetrieveCommandType",
65
+ "RetrieveParams",
66
+ "RetrieveResult",
67
+ "Retrieve",
68
+ "RetrieveCreate",
69
+ # flexStacker/setStoredLabware
70
+ "SetStoredLabwareCommandType",
71
+ "SetStoredLabwareParams",
72
+ "SetStoredLabwareResult",
73
+ "SetStoredLabware",
74
+ "SetStoredLabwareCreate",
75
+ "StackerStoredLabwareDetails",
76
+ # flexStacker/fill
77
+ "FillCommandType",
78
+ "FillParams",
79
+ "FillResult",
80
+ "Fill",
81
+ "FillCreate",
82
+ # flexStacker/empty
83
+ "EmptyCommandType",
84
+ "EmptyParams",
85
+ "EmptyResult",
86
+ "Empty",
87
+ "EmptyCreate",
88
+ # flexStacker/closeLatch
89
+ "CloseLatchCommandType",
90
+ "CloseLatchParams",
91
+ "CloseLatchResult",
92
+ "CloseLatch",
93
+ "CloseLatchCreate",
94
+ # flexStacker/openLatch
95
+ "OpenLatchCommandType",
96
+ "OpenLatchParams",
97
+ "OpenLatchResult",
98
+ "OpenLatch",
99
+ "OpenLatchCreate",
100
+ # flexStacker/prepareShuttle
101
+ "PrepareShuttleCommandType",
102
+ "PrepareShuttleParams",
103
+ "PrepareShuttleResult",
104
+ "PrepareShuttle",
105
+ "PrepareShuttleCreate",
106
+ ]
@@ -0,0 +1,72 @@
1
+ """Command models to close the latch of a Flex Stacker."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from __future__ import annotations
6
+ from typing import Optional, Literal, TYPE_CHECKING
7
+ from typing_extensions import Type
8
+
9
+ from pydantic import BaseModel, Field
10
+
11
+ from ..command import AbstractCommandImpl, BaseCommand, BaseCommandCreate, SuccessData
12
+ from ...errors import (
13
+ ErrorOccurrence,
14
+ )
15
+
16
+ if TYPE_CHECKING:
17
+ from ...state.state import StateView
18
+ from opentrons.protocol_engine.execution import EquipmentHandler
19
+
20
+ CloseLatchCommandType = Literal["flexStacker/closeLatch"]
21
+
22
+
23
+ class CloseLatchParams(BaseModel):
24
+ """The parameters defining how a stacker should close its latch."""
25
+
26
+ moduleId: str = Field(..., description="Unique ID of the Flex Stacker")
27
+
28
+
29
+ class CloseLatchResult(BaseModel):
30
+ """Result data from a stacker CloseLatch command."""
31
+
32
+
33
+ class CloseLatchImpl(
34
+ AbstractCommandImpl[CloseLatchParams, SuccessData[CloseLatchResult]]
35
+ ):
36
+ """Implementation of a stacker CloseLatch command."""
37
+
38
+ def __init__(
39
+ self, state_view: StateView, equipment: EquipmentHandler, **kwargs: object
40
+ ) -> None:
41
+ self._state_view = state_view
42
+ self._equipment = equipment
43
+
44
+ async def execute(self, params: CloseLatchParams) -> SuccessData[CloseLatchResult]:
45
+ """Execute the stacker CloseLatch command."""
46
+ stacker_state = self._state_view.modules.get_flex_stacker_substate(
47
+ params.moduleId
48
+ )
49
+ stacker_hw = self._equipment.get_module_hardware_api(stacker_state.module_id)
50
+
51
+ if stacker_hw is not None:
52
+ await stacker_hw.close_latch()
53
+ return SuccessData(public=CloseLatchResult())
54
+
55
+
56
+ class CloseLatch(BaseCommand[CloseLatchParams, CloseLatchResult, ErrorOccurrence]):
57
+ """A command to CloseLatch the Flex Stacker of labware."""
58
+
59
+ commandType: CloseLatchCommandType = "flexStacker/closeLatch"
60
+ params: CloseLatchParams
61
+ result: Optional[CloseLatchResult] = None
62
+
63
+ _ImplementationCls: Type[CloseLatchImpl] = CloseLatchImpl
64
+
65
+
66
+ class CloseLatchCreate(BaseCommandCreate[CloseLatchParams]):
67
+ """A request to execute a Flex Stacker CloseLatch command."""
68
+
69
+ commandType: CloseLatchCommandType = "flexStacker/closeLatch"
70
+ params: CloseLatchParams
71
+
72
+ _CommandCls: Type[CloseLatch] = CloseLatch
@@ -0,0 +1,15 @@
1
+ """Common flex stacker base models."""
2
+ from typing import Literal
3
+
4
+ from ...errors import ErrorOccurrence
5
+ from opentrons_shared_data.errors import ErrorCodes
6
+
7
+
8
+ class FlexStackerStallOrCollisionError(ErrorOccurrence):
9
+ """Returned when the motor driver detects a stall."""
10
+
11
+ isDefined: bool = True
12
+ errorType: Literal["flexStackerStallOrCollision"] = "flexStackerStallOrCollision"
13
+
14
+ errorCode: str = ErrorCodes.FLEX_STACKER_STALL_OR_COLLISION_DETECTED.value.code
15
+ detail: str = ErrorCodes.FLEX_STACKER_STALL_OR_COLLISION_DETECTED.value.detail
@@ -0,0 +1,161 @@
1
+ """Command models to engage a user to empty a Flex Stacker."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from __future__ import annotations
6
+ from typing import Optional, Literal, TYPE_CHECKING, Annotated
7
+ from typing_extensions import Type
8
+
9
+ from pydantic import BaseModel, Field
10
+ from pydantic.json_schema import SkipJsonSchema
11
+
12
+ from ..command import AbstractCommandImpl, BaseCommand, BaseCommandCreate, SuccessData
13
+ from ...errors import (
14
+ ErrorOccurrence,
15
+ )
16
+ from ...errors.exceptions import FlexStackerLabwarePoolNotYetDefinedError
17
+ from ...state import update_types
18
+ from ...types import StackerFillEmptyStrategy
19
+ from opentrons.calibration_storage.helpers import uri_from_details
20
+
21
+ if TYPE_CHECKING:
22
+ from ...state.state import StateView
23
+ from ...execution import RunControlHandler
24
+
25
+ EmptyCommandType = Literal["flexStacker/empty"]
26
+
27
+
28
+ class EmptyParams(BaseModel):
29
+ """The parameters defining how a stacker should be emptied."""
30
+
31
+ moduleId: str = Field(..., description="Unique ID of the Flex Stacker")
32
+
33
+ strategy: StackerFillEmptyStrategy = Field(
34
+ ...,
35
+ description=(
36
+ "How to empty the stacker. "
37
+ "If manualWithPause, pause the protocol until the client sends an interaction, and mark "
38
+ "the labware pool as empty thereafter. If logical, do not pause but immediately apply the "
39
+ "specified count."
40
+ ),
41
+ )
42
+
43
+ message: str | SkipJsonSchema[None] = Field(
44
+ None,
45
+ description="The message to display on connected clients during a manualWithPause strategy empty.",
46
+ )
47
+
48
+ count: Optional[Annotated[int, Field(ge=0)]] = Field(
49
+ None,
50
+ description=(
51
+ "The new count of labware in the pool. If None, default to an empty pool. If this number is "
52
+ "larger than the amount of labware currently in the pool, default to the smaller amount. "
53
+ "Do not use the value in the parameters as an outside observer; instead, use the count value "
54
+ "from the results."
55
+ ),
56
+ )
57
+
58
+
59
+ class EmptyResult(BaseModel):
60
+ """Result data from a stacker empty command."""
61
+
62
+ count: int = Field(
63
+ ..., description="The new amount of labware stored in the stacker labware pool."
64
+ )
65
+ primaryLabwareURI: str = Field(
66
+ ...,
67
+ description="The labware definition URI of the primary labware.",
68
+ )
69
+ adapterLabwareURI: str | SkipJsonSchema[None] = Field(
70
+ None,
71
+ description="The labware definition URI of the adapter labware.",
72
+ )
73
+ lidLabwareURI: str | SkipJsonSchema[None] = Field(
74
+ None,
75
+ description="The labware definition URI of the lid labware.",
76
+ )
77
+
78
+
79
+ class EmptyImpl(AbstractCommandImpl[EmptyParams, SuccessData[EmptyResult]]):
80
+ """Implementation of a stacker empty command."""
81
+
82
+ def __init__(
83
+ self, state_view: StateView, run_control: RunControlHandler, **kwargs: object
84
+ ) -> None:
85
+ self._state_view = state_view
86
+ self._run_control = run_control
87
+
88
+ async def execute(self, params: EmptyParams) -> SuccessData[EmptyResult]:
89
+ """Execute the stacker empty command."""
90
+ stacker_state = self._state_view.modules.get_flex_stacker_substate(
91
+ params.moduleId
92
+ )
93
+
94
+ if stacker_state.pool_primary_definition is None:
95
+ location = self._state_view.modules.get_location(params.moduleId)
96
+ raise FlexStackerLabwarePoolNotYetDefinedError(
97
+ message=f"The Flex Stacker in {location} has not been configured yet and cannot be emptied."
98
+ )
99
+
100
+ count = params.count if params.count is not None else 0
101
+
102
+ new_count = min(stacker_state.pool_count, count)
103
+
104
+ state_update = (
105
+ update_types.StateUpdate().update_flex_stacker_labware_pool_count(
106
+ params.moduleId, new_count
107
+ )
108
+ )
109
+
110
+ if params.strategy == StackerFillEmptyStrategy.MANUAL_WITH_PAUSE:
111
+ await self._run_control.wait_for_resume()
112
+
113
+ if stacker_state.pool_primary_definition is None:
114
+ raise FlexStackerLabwarePoolNotYetDefinedError(
115
+ "The Primary Labware must be defined in the stacker pool."
116
+ )
117
+
118
+ return SuccessData(
119
+ public=EmptyResult(
120
+ count=new_count,
121
+ primaryLabwareURI=uri_from_details(
122
+ stacker_state.pool_primary_definition.namespace,
123
+ stacker_state.pool_primary_definition.parameters.loadName,
124
+ stacker_state.pool_primary_definition.version,
125
+ ),
126
+ adapterLabwareURI=uri_from_details(
127
+ stacker_state.pool_adapter_definition.namespace,
128
+ stacker_state.pool_adapter_definition.parameters.loadName,
129
+ stacker_state.pool_adapter_definition.version,
130
+ )
131
+ if stacker_state.pool_adapter_definition is not None
132
+ else None,
133
+ lidLabwareURI=uri_from_details(
134
+ stacker_state.pool_lid_definition.namespace,
135
+ stacker_state.pool_lid_definition.parameters.loadName,
136
+ stacker_state.pool_lid_definition.version,
137
+ )
138
+ if stacker_state.pool_lid_definition is not None
139
+ else None,
140
+ ),
141
+ state_update=state_update,
142
+ )
143
+
144
+
145
+ class Empty(BaseCommand[EmptyParams, EmptyResult, ErrorOccurrence]):
146
+ """A command to empty the Flex Stacker of labware."""
147
+
148
+ commandType: EmptyCommandType = "flexStacker/empty"
149
+ params: EmptyParams
150
+ result: Optional[EmptyResult] = None
151
+
152
+ _ImplementationCls: Type[EmptyImpl] = EmptyImpl
153
+
154
+
155
+ class EmptyCreate(BaseCommandCreate[EmptyParams]):
156
+ """A request to execute a Flex Stacker empty command."""
157
+
158
+ commandType: EmptyCommandType = "flexStacker/empty"
159
+ params: EmptyParams
160
+
161
+ _CommandCls: Type[Empty] = Empty
@@ -0,0 +1,164 @@
1
+ """Command models to engage a user to empty a Flex Stacker."""
2
+
3
+ from __future__ import annotations
4
+ from typing import Optional, Literal, TYPE_CHECKING, Annotated
5
+ from typing_extensions import Type
6
+
7
+ from pydantic import BaseModel, Field
8
+ from pydantic.json_schema import SkipJsonSchema
9
+
10
+ from ..command import AbstractCommandImpl, BaseCommand, BaseCommandCreate, SuccessData
11
+ from ...errors import (
12
+ ErrorOccurrence,
13
+ )
14
+ from ...errors.exceptions import FlexStackerLabwarePoolNotYetDefinedError
15
+ from ...state import update_types
16
+ from ...types import StackerFillEmptyStrategy
17
+ from opentrons.calibration_storage.helpers import uri_from_details
18
+
19
+ if TYPE_CHECKING:
20
+ from ...state.state import StateView
21
+ from ...execution import RunControlHandler
22
+
23
+ FillCommandType = Literal["flexStacker/fill"]
24
+
25
+
26
+ class FillParams(BaseModel):
27
+ """The parameters defining how a stacker should be filled."""
28
+
29
+ moduleId: str = Field(..., description="Unique ID of the Flex Stacker")
30
+
31
+ strategy: StackerFillEmptyStrategy = Field(
32
+ ...,
33
+ description=(
34
+ "How to fill the stacker. "
35
+ "If manualWithPause, pause the protocol until the client sends an interaction, and apply "
36
+ "the new specified count thereafter. If logical, do not pause but immediately apply the "
37
+ "specified count."
38
+ ),
39
+ )
40
+
41
+ message: str | SkipJsonSchema[None] = Field(
42
+ None,
43
+ description="The message to display on connected clients during a manualWithPause strategy fill.",
44
+ )
45
+
46
+ count: Optional[Annotated[int, Field(ge=1)]] = Field(
47
+ None,
48
+ description=(
49
+ "How full the labware pool should now be. If None, default to the maximum amount "
50
+ "of the currently-configured labware the pool can hold. "
51
+ "If this number is larger than the maximum the pool can hold, it will be clamped to "
52
+ "the maximum. If this number is smaller than the current amount of labware the pool "
53
+ "holds, it will be clamped to that minimum. Do not use the value in the parameters as "
54
+ "an outside observer; instead, use the count value from the results."
55
+ ),
56
+ )
57
+
58
+
59
+ class FillResult(BaseModel):
60
+ """Result data from a stacker fill command."""
61
+
62
+ count: int = Field(
63
+ ..., description="The new amount of labware stored in the stacker labware pool."
64
+ )
65
+ primaryLabwareURI: str = Field(
66
+ ...,
67
+ description="The labware definition URI of the primary labware.",
68
+ )
69
+ adapterLabwareURI: str | SkipJsonSchema[None] = Field(
70
+ None,
71
+ description="The labware definition URI of the adapter labware.",
72
+ )
73
+ lidLabwareURI: str | SkipJsonSchema[None] = Field(
74
+ None,
75
+ description="The labware definition URI of the lid labware.",
76
+ )
77
+
78
+
79
+ class FillImpl(AbstractCommandImpl[FillParams, SuccessData[FillResult]]):
80
+ """Implementation of a stacker fill command."""
81
+
82
+ def __init__(
83
+ self, state_view: StateView, run_control: RunControlHandler, **kwargs: object
84
+ ) -> None:
85
+ self._state_view = state_view
86
+ self._run_control = run_control
87
+
88
+ async def execute(self, params: FillParams) -> SuccessData[FillResult]:
89
+ """Execute the stacker fill command."""
90
+ stacker_state = self._state_view.modules.get_flex_stacker_substate(
91
+ params.moduleId
92
+ )
93
+
94
+ if stacker_state.pool_primary_definition is None:
95
+ location = self._state_view.modules.get_location(params.moduleId)
96
+ raise FlexStackerLabwarePoolNotYetDefinedError(
97
+ message=f"The Flex Stacker in {location} has not been configured yet and cannot be filled."
98
+ )
99
+
100
+ count = (
101
+ params.count if params.count is not None else stacker_state.max_pool_count
102
+ )
103
+ new_count = min(
104
+ stacker_state.max_pool_count, max(stacker_state.pool_count, count)
105
+ )
106
+
107
+ state_update = (
108
+ update_types.StateUpdate().update_flex_stacker_labware_pool_count(
109
+ params.moduleId, new_count
110
+ )
111
+ )
112
+
113
+ if params.strategy == StackerFillEmptyStrategy.MANUAL_WITH_PAUSE:
114
+ await self._run_control.wait_for_resume()
115
+
116
+ if stacker_state.pool_primary_definition is None:
117
+ raise FlexStackerLabwarePoolNotYetDefinedError(
118
+ "The Primary Labware must be defined in the stacker pool."
119
+ )
120
+
121
+ return SuccessData(
122
+ public=FillResult(
123
+ count=new_count,
124
+ primaryLabwareURI=uri_from_details(
125
+ stacker_state.pool_primary_definition.namespace,
126
+ stacker_state.pool_primary_definition.parameters.loadName,
127
+ stacker_state.pool_primary_definition.version,
128
+ ),
129
+ adapterLabwareURI=uri_from_details(
130
+ stacker_state.pool_adapter_definition.namespace,
131
+ stacker_state.pool_adapter_definition.parameters.loadName,
132
+ stacker_state.pool_adapter_definition.version,
133
+ )
134
+ if stacker_state.pool_adapter_definition is not None
135
+ else None,
136
+ lidLabwareURI=uri_from_details(
137
+ stacker_state.pool_lid_definition.namespace,
138
+ stacker_state.pool_lid_definition.parameters.loadName,
139
+ stacker_state.pool_lid_definition.version,
140
+ )
141
+ if stacker_state.pool_lid_definition is not None
142
+ else None,
143
+ ),
144
+ state_update=state_update,
145
+ )
146
+
147
+
148
+ class Fill(BaseCommand[FillParams, FillResult, ErrorOccurrence]):
149
+ """A command to fill the Flex Stacker with labware."""
150
+
151
+ commandType: FillCommandType = "flexStacker/fill"
152
+ params: FillParams
153
+ result: Optional[FillResult] = None
154
+
155
+ _ImplementationCls: Type[FillImpl] = FillImpl
156
+
157
+
158
+ class FillCreate(BaseCommandCreate[FillParams]):
159
+ """A request to execute a Flex Stacker fill command."""
160
+
161
+ commandType: FillCommandType = "flexStacker/fill"
162
+ params: FillParams
163
+
164
+ _CommandCls: Type[Fill] = Fill
@@ -0,0 +1,70 @@
1
+ """Command models to open the latch of a Flex Stacker."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from __future__ import annotations
6
+ from typing import Optional, Literal, TYPE_CHECKING
7
+ from typing_extensions import Type
8
+
9
+ from pydantic import BaseModel, Field
10
+
11
+ from ..command import AbstractCommandImpl, BaseCommand, BaseCommandCreate, SuccessData
12
+ from ...errors import (
13
+ ErrorOccurrence,
14
+ )
15
+
16
+ if TYPE_CHECKING:
17
+ from ...state.state import StateView
18
+ from opentrons.protocol_engine.execution import EquipmentHandler
19
+
20
+ OpenLatchCommandType = Literal["flexStacker/openLatch"]
21
+
22
+
23
+ class OpenLatchParams(BaseModel):
24
+ """The parameters defining how a stacker should open its latch."""
25
+
26
+ moduleId: str = Field(..., description="Unique ID of the Flex Stacker")
27
+
28
+
29
+ class OpenLatchResult(BaseModel):
30
+ """Result data from a stacker OpenLatch command."""
31
+
32
+
33
+ class OpenLatchImpl(AbstractCommandImpl[OpenLatchParams, SuccessData[OpenLatchResult]]):
34
+ """Implementation of a stacker OpenLatch command."""
35
+
36
+ def __init__(
37
+ self, state_view: StateView, equipment: EquipmentHandler, **kwargs: object
38
+ ) -> None:
39
+ self._state_view = state_view
40
+ self._equipment = equipment
41
+
42
+ async def execute(self, params: OpenLatchParams) -> SuccessData[OpenLatchResult]:
43
+ """Execute the stacker OpenLatch command."""
44
+ stacker_state = self._state_view.modules.get_flex_stacker_substate(
45
+ params.moduleId
46
+ )
47
+ stacker_hw = self._equipment.get_module_hardware_api(stacker_state.module_id)
48
+
49
+ if stacker_hw is not None:
50
+ await stacker_hw.open_latch()
51
+ return SuccessData(public=OpenLatchResult())
52
+
53
+
54
+ class OpenLatch(BaseCommand[OpenLatchParams, OpenLatchResult, ErrorOccurrence]):
55
+ """A command to OpenLatch the Flex Stacker of labware."""
56
+
57
+ commandType: OpenLatchCommandType = "flexStacker/openLatch"
58
+ params: OpenLatchParams
59
+ result: Optional[OpenLatchResult] = None
60
+
61
+ _ImplementationCls: Type[OpenLatchImpl] = OpenLatchImpl
62
+
63
+
64
+ class OpenLatchCreate(BaseCommandCreate[OpenLatchParams]):
65
+ """A request to execute a Flex Stacker OpenLatch command."""
66
+
67
+ commandType: OpenLatchCommandType = "flexStacker/openLatch"
68
+ params: OpenLatchParams
69
+
70
+ _CommandCls: Type[OpenLatch] = OpenLatch