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
@@ -89,7 +89,10 @@ class BlowOutInPlaceImplementation(
89
89
  if isinstance(result, DefinedErrorData):
90
90
  return result
91
91
  return SuccessData(
92
- public=BlowOutInPlaceResult(), state_update=result.state_update
92
+ public=BlowOutInPlaceResult(),
93
+ state_update=result.state_update.set_pipette_ready_to_aspirate(
94
+ pipette_id=params.pipetteId, ready_to_aspirate=False
95
+ ),
93
96
  )
94
97
 
95
98
 
@@ -14,8 +14,10 @@ from .pipetting_common import (
14
14
  TipPhysicallyAttachedError,
15
15
  )
16
16
  from .movement_common import StallOrCollisionError
17
+ from .flex_stacker.common import FlexStackerStallOrCollisionError
17
18
 
18
19
  from . import absorbance_reader
20
+ from . import flex_stacker
19
21
  from . import heater_shaker
20
22
  from . import magnetic_module
21
23
  from . import temperature_module
@@ -57,6 +59,14 @@ from .aspirate_in_place import (
57
59
  AspirateInPlaceCommandType,
58
60
  )
59
61
 
62
+ from .aspirate_while_tracking import (
63
+ AspirateWhileTracking,
64
+ AspirateWhileTrackingParams,
65
+ AspirateWhileTrackingCreate,
66
+ AspirateWhileTrackingResult,
67
+ AspirateWhileTrackingCommandType,
68
+ )
69
+
60
70
  from .comment import (
61
71
  Comment,
62
72
  CommentParams,
@@ -81,6 +91,14 @@ from .dispense import (
81
91
  DispenseCommandType,
82
92
  )
83
93
 
94
+ from .dispense_while_tracking import (
95
+ DispenseWhileTracking,
96
+ DispenseWhileTrackingParams,
97
+ DispenseWhileTrackingCreate,
98
+ DispenseWhileTrackingResult,
99
+ DispenseWhileTrackingCommandType,
100
+ )
101
+
84
102
  from .dispense_in_place import (
85
103
  DispenseInPlace,
86
104
  DispenseInPlaceParams,
@@ -389,10 +407,12 @@ Command = Annotated[
389
407
  AirGapInPlace,
390
408
  Aspirate,
391
409
  AspirateInPlace,
410
+ AspirateWhileTracking,
392
411
  Comment,
393
412
  Custom,
394
413
  Dispense,
395
414
  DispenseInPlace,
415
+ DispenseWhileTracking,
396
416
  BlowOut,
397
417
  BlowOutInPlace,
398
418
  ConfigureForVolume,
@@ -457,6 +477,14 @@ Command = Annotated[
457
477
  absorbance_reader.OpenLid,
458
478
  absorbance_reader.Initialize,
459
479
  absorbance_reader.ReadAbsorbance,
480
+ flex_stacker.Retrieve,
481
+ flex_stacker.Store,
482
+ flex_stacker.SetStoredLabware,
483
+ flex_stacker.Fill,
484
+ flex_stacker.Empty,
485
+ flex_stacker.CloseLatch,
486
+ flex_stacker.OpenLatch,
487
+ flex_stacker.PrepareShuttle,
460
488
  calibration.CalibrateGripper,
461
489
  calibration.CalibratePipette,
462
490
  calibration.CalibrateModule,
@@ -479,6 +507,7 @@ Command = Annotated[
479
507
  CommandParams = Union[
480
508
  AirGapInPlaceParams,
481
509
  AspirateParams,
510
+ AspirateWhileTrackingParams,
482
511
  AspirateInPlaceParams,
483
512
  CommentParams,
484
513
  ConfigureForVolumeParams,
@@ -486,6 +515,7 @@ CommandParams = Union[
486
515
  CustomParams,
487
516
  DispenseParams,
488
517
  DispenseInPlaceParams,
518
+ DispenseWhileTrackingParams,
489
519
  BlowOutParams,
490
520
  BlowOutInPlaceParams,
491
521
  DropTipParams,
@@ -548,6 +578,14 @@ CommandParams = Union[
548
578
  absorbance_reader.OpenLidParams,
549
579
  absorbance_reader.InitializeParams,
550
580
  absorbance_reader.ReadAbsorbanceParams,
581
+ flex_stacker.RetrieveParams,
582
+ flex_stacker.StoreParams,
583
+ flex_stacker.SetStoredLabwareParams,
584
+ flex_stacker.FillParams,
585
+ flex_stacker.EmptyParams,
586
+ flex_stacker.CloseLatchParams,
587
+ flex_stacker.OpenLatchParams,
588
+ flex_stacker.PrepareShuttleParams,
551
589
  calibration.CalibrateGripperParams,
552
590
  calibration.CalibratePipetteParams,
553
591
  calibration.CalibrateModuleParams,
@@ -568,6 +606,7 @@ CommandParams = Union[
568
606
  CommandType = Union[
569
607
  AirGapInPlaceCommandType,
570
608
  AspirateCommandType,
609
+ AspirateWhileTrackingCommandType,
571
610
  AspirateInPlaceCommandType,
572
611
  CommentCommandType,
573
612
  ConfigureForVolumeCommandType,
@@ -575,6 +614,7 @@ CommandType = Union[
575
614
  CustomCommandType,
576
615
  DispenseCommandType,
577
616
  DispenseInPlaceCommandType,
617
+ DispenseWhileTrackingCommandType,
578
618
  BlowOutCommandType,
579
619
  BlowOutInPlaceCommandType,
580
620
  DropTipCommandType,
@@ -637,6 +677,14 @@ CommandType = Union[
637
677
  absorbance_reader.OpenLidCommandType,
638
678
  absorbance_reader.InitializeCommandType,
639
679
  absorbance_reader.ReadAbsorbanceCommandType,
680
+ flex_stacker.RetrieveCommandType,
681
+ flex_stacker.StoreCommandType,
682
+ flex_stacker.SetStoredLabwareCommandType,
683
+ flex_stacker.FillCommandType,
684
+ flex_stacker.EmptyCommandType,
685
+ flex_stacker.CloseLatchCommandType,
686
+ flex_stacker.OpenLatchCommandType,
687
+ flex_stacker.PrepareShuttleCommandType,
640
688
  calibration.CalibrateGripperCommandType,
641
689
  calibration.CalibratePipetteCommandType,
642
690
  calibration.CalibrateModuleCommandType,
@@ -658,6 +706,7 @@ CommandCreate = Annotated[
658
706
  Union[
659
707
  AirGapInPlaceCreate,
660
708
  AspirateCreate,
709
+ AspirateWhileTrackingCreate,
661
710
  AspirateInPlaceCreate,
662
711
  CommentCreate,
663
712
  ConfigureForVolumeCreate,
@@ -665,6 +714,7 @@ CommandCreate = Annotated[
665
714
  CustomCreate,
666
715
  DispenseCreate,
667
716
  DispenseInPlaceCreate,
717
+ DispenseWhileTrackingCreate,
668
718
  BlowOutCreate,
669
719
  BlowOutInPlaceCreate,
670
720
  DropTipCreate,
@@ -727,6 +777,14 @@ CommandCreate = Annotated[
727
777
  absorbance_reader.OpenLidCreate,
728
778
  absorbance_reader.InitializeCreate,
729
779
  absorbance_reader.ReadAbsorbanceCreate,
780
+ flex_stacker.RetrieveCreate,
781
+ flex_stacker.StoreCreate,
782
+ flex_stacker.SetStoredLabwareCreate,
783
+ flex_stacker.FillCreate,
784
+ flex_stacker.EmptyCreate,
785
+ flex_stacker.CloseLatchCreate,
786
+ flex_stacker.OpenLatchCreate,
787
+ flex_stacker.PrepareShuttleCreate,
730
788
  calibration.CalibrateGripperCreate,
731
789
  calibration.CalibratePipetteCreate,
732
790
  calibration.CalibrateModuleCreate,
@@ -756,6 +814,7 @@ CommandAdapter: TypeAdapter[Command] = TypeAdapter(Command)
756
814
  CommandResult = Union[
757
815
  AirGapInPlaceResult,
758
816
  AspirateResult,
817
+ AspirateWhileTrackingResult,
759
818
  AspirateInPlaceResult,
760
819
  CommentResult,
761
820
  ConfigureForVolumeResult,
@@ -763,6 +822,7 @@ CommandResult = Union[
763
822
  CustomResult,
764
823
  DispenseResult,
765
824
  DispenseInPlaceResult,
825
+ DispenseWhileTrackingResult,
766
826
  BlowOutResult,
767
827
  BlowOutInPlaceResult,
768
828
  DropTipResult,
@@ -825,6 +885,14 @@ CommandResult = Union[
825
885
  absorbance_reader.OpenLidResult,
826
886
  absorbance_reader.InitializeResult,
827
887
  absorbance_reader.ReadAbsorbanceResult,
888
+ flex_stacker.RetrieveResult,
889
+ flex_stacker.StoreResult,
890
+ flex_stacker.SetStoredLabwareResult,
891
+ flex_stacker.FillResult,
892
+ flex_stacker.EmptyResult,
893
+ flex_stacker.CloseLatchResult,
894
+ flex_stacker.OpenLatchResult,
895
+ flex_stacker.PrepareShuttleResult,
828
896
  calibration.CalibrateGripperResult,
829
897
  calibration.CalibratePipetteResult,
830
898
  calibration.CalibrateModuleResult,
@@ -851,6 +919,7 @@ CommandDefinedErrorData = Union[
851
919
  DefinedErrorData[LiquidNotFoundError],
852
920
  DefinedErrorData[GripperMovementError],
853
921
  DefinedErrorData[StallOrCollisionError],
922
+ DefinedErrorData[FlexStackerStallOrCollisionError],
854
923
  ]
855
924
 
856
925
 
@@ -74,6 +74,9 @@ class ConfigureForVolumeImplementation(
74
74
  config=pipette_result.static_config,
75
75
  serial_number=pipette_result.serial_number,
76
76
  )
77
+ state_update.set_pipette_ready_to_aspirate(
78
+ pipette_result.pipette_id, ready_to_aspirate=False
79
+ )
77
80
 
78
81
  return SuccessData(
79
82
  public=ConfigureForVolumeResult(),
@@ -4,7 +4,6 @@ from __future__ import annotations
4
4
  from typing import TYPE_CHECKING, Optional, Type, Union, Any
5
5
  from typing_extensions import Literal
6
6
 
7
-
8
7
  from pydantic import Field
9
8
  from pydantic.json_schema import SkipJsonSchema
10
9
 
@@ -16,6 +15,7 @@ from .pipetting_common import (
16
15
  BaseLiquidHandlingResult,
17
16
  OverpressureError,
18
17
  dispense_in_place,
18
+ DEFAULT_CORRECTION_VOLUME,
19
19
  )
20
20
  from .movement_common import (
21
21
  LiquidHandlingWellLocationMixin,
@@ -100,6 +100,7 @@ class DispenseImplementation(AbstractCommandImpl[DispenseParams, _ExecuteReturn]
100
100
  labware_id=labware_id,
101
101
  well_name=well_name,
102
102
  well_location=well_location,
103
+ operation_volume=volume,
103
104
  )
104
105
  if isinstance(move_result, DefinedErrorData):
105
106
  return move_result
@@ -117,6 +118,7 @@ class DispenseImplementation(AbstractCommandImpl[DispenseParams, _ExecuteReturn]
117
118
  },
118
119
  pipetting=self._pipetting,
119
120
  model_utils=self._model_utils,
121
+ correction_volume=params.correctionVolume or DEFAULT_CORRECTION_VOLUME,
120
122
  )
121
123
 
122
124
  if isinstance(dispense_result, DefinedErrorData):
@@ -3,6 +3,7 @@
3
3
  from __future__ import annotations
4
4
  from typing import TYPE_CHECKING, Optional, Type, Union, Any
5
5
  from typing_extensions import Literal
6
+
6
7
  from pydantic import Field
7
8
  from pydantic.json_schema import SkipJsonSchema
8
9
 
@@ -13,6 +14,7 @@ from .pipetting_common import (
13
14
  BaseLiquidHandlingResult,
14
15
  OverpressureError,
15
16
  dispense_in_place,
17
+ DEFAULT_CORRECTION_VOLUME,
16
18
  )
17
19
  from .command import (
18
20
  AbstractCommandImpl,
@@ -95,6 +97,7 @@ class DispenseInPlaceImplementation(
95
97
  },
96
98
  pipetting=self._pipetting,
97
99
  model_utils=self._model_utils,
100
+ correction_volume=params.correctionVolume or DEFAULT_CORRECTION_VOLUME,
98
101
  )
99
102
  if isinstance(result, DefinedErrorData):
100
103
  if (
@@ -0,0 +1,240 @@
1
+ """Dispense command request, result, and implementation models."""
2
+
3
+ from __future__ import annotations
4
+ from typing import TYPE_CHECKING, Optional, Type, Union, Any
5
+ from typing_extensions import Literal
6
+
7
+
8
+ from pydantic import Field
9
+ from pydantic.json_schema import SkipJsonSchema
10
+
11
+ from ..state.update_types import CLEAR, StateUpdate
12
+ from ..types import CurrentWell, DeckPoint
13
+ from .pipetting_common import (
14
+ PipetteIdMixin,
15
+ DispenseVolumeMixin,
16
+ FlowRateMixin,
17
+ BaseLiquidHandlingResult,
18
+ OverpressureError,
19
+ dispense_while_tracking,
20
+ )
21
+ from .movement_common import (
22
+ LiquidHandlingWellLocationMixin,
23
+ DestinationPositionResult,
24
+ StallOrCollisionError,
25
+ move_to_well,
26
+ )
27
+ from .command import (
28
+ AbstractCommandImpl,
29
+ BaseCommand,
30
+ BaseCommandCreate,
31
+ DefinedErrorData,
32
+ SuccessData,
33
+ )
34
+
35
+ if TYPE_CHECKING:
36
+ from ..execution import PipettingHandler, GantryMover, MovementHandler
37
+ from ..resources import ModelUtils
38
+ from ..state.state import StateView
39
+
40
+
41
+ DispenseWhileTrackingCommandType = Literal["dispenseWhileTracking"]
42
+
43
+
44
+ def _remove_default(s: dict[str, Any]) -> None:
45
+ s.pop("default", None)
46
+
47
+
48
+ class DispenseWhileTrackingParams(
49
+ PipetteIdMixin,
50
+ DispenseVolumeMixin,
51
+ FlowRateMixin,
52
+ LiquidHandlingWellLocationMixin,
53
+ ):
54
+ """Payload required to dispense to a specific well."""
55
+
56
+ pushOut: float | SkipJsonSchema[None] = Field(
57
+ None,
58
+ description="push the plunger a small amount farther than necessary for accurate low-volume dispensing",
59
+ json_schema_extra=_remove_default,
60
+ )
61
+
62
+
63
+ class DispenseWhileTrackingResult(BaseLiquidHandlingResult, DestinationPositionResult):
64
+ """Result data from the execution of a Dispense command."""
65
+
66
+ pass
67
+
68
+
69
+ _ExecuteReturn = Union[
70
+ SuccessData[DispenseWhileTrackingResult],
71
+ DefinedErrorData[OverpressureError] | DefinedErrorData[StallOrCollisionError],
72
+ ]
73
+
74
+
75
+ class DispenseWhileTrackingImplementation(
76
+ AbstractCommandImpl[DispenseWhileTrackingParams, _ExecuteReturn]
77
+ ):
78
+ """Dispense command implementation."""
79
+
80
+ def __init__(
81
+ self,
82
+ state_view: StateView,
83
+ pipetting: PipettingHandler,
84
+ model_utils: ModelUtils,
85
+ gantry_mover: GantryMover,
86
+ movement: MovementHandler,
87
+ **kwargs: object,
88
+ ) -> None:
89
+ self._state_view = state_view
90
+ self._pipetting = pipetting
91
+ self._model_utils = model_utils
92
+ self._gantry_mover = gantry_mover
93
+ self._movement = movement
94
+
95
+ async def execute(self, params: DispenseWhileTrackingParams) -> _ExecuteReturn:
96
+ """Move to and dispense to the requested well."""
97
+ labware_id = params.labwareId
98
+ well_name = params.wellName
99
+
100
+ # TODO(pbm, 10-15-24): call self._state_view.geometry.validate_dispense_volume_into_well()
101
+
102
+ current_location = self._state_view.pipettes.get_current_location()
103
+ current_position = await self._gantry_mover.get_position(params.pipetteId)
104
+ current_well = CurrentWell(
105
+ pipette_id=params.pipetteId,
106
+ labware_id=params.labwareId,
107
+ well_name=params.wellName,
108
+ )
109
+ state_update = StateUpdate()
110
+ move_result = await move_to_well(
111
+ movement=self._movement,
112
+ model_utils=self._model_utils,
113
+ pipette_id=params.pipetteId,
114
+ labware_id=params.labwareId,
115
+ well_name=params.wellName,
116
+ well_location=params.wellLocation,
117
+ current_well=current_well,
118
+ operation_volume=-params.volume,
119
+ )
120
+ state_update.append(move_result.state_update)
121
+ if isinstance(move_result, DefinedErrorData):
122
+ return DefinedErrorData(
123
+ public=move_result.public, state_update=state_update
124
+ )
125
+
126
+ dispense_result = await dispense_while_tracking(
127
+ pipette_id=params.pipetteId,
128
+ labware_id=labware_id,
129
+ well_name=well_name,
130
+ volume=params.volume,
131
+ flow_rate=params.flowRate,
132
+ push_out=params.pushOut,
133
+ location_if_error={
134
+ "retryLocation": (
135
+ current_position.x,
136
+ current_position.y,
137
+ current_position.z,
138
+ )
139
+ },
140
+ pipetting=self._pipetting,
141
+ model_utils=self._model_utils,
142
+ )
143
+ position_after_dispense = await self._gantry_mover.get_position(
144
+ params.pipetteId
145
+ )
146
+ result_deck_point = DeckPoint.model_construct(
147
+ x=position_after_dispense.x,
148
+ y=position_after_dispense.y,
149
+ z=position_after_dispense.z,
150
+ )
151
+
152
+ if isinstance(dispense_result, DefinedErrorData):
153
+ if (
154
+ isinstance(current_location, CurrentWell)
155
+ and current_location.pipette_id == params.pipetteId
156
+ ):
157
+ return DefinedErrorData(
158
+ public=dispense_result.public,
159
+ state_update=dispense_result.state_update.set_liquid_operated(
160
+ labware_id=current_location.labware_id,
161
+ well_names=self._state_view.geometry.get_wells_covered_by_pipette_with_active_well(
162
+ current_location.labware_id,
163
+ current_location.well_name,
164
+ params.pipetteId,
165
+ ),
166
+ volume_added=CLEAR,
167
+ ),
168
+ state_update_if_false_positive=dispense_result.state_update_if_false_positive,
169
+ )
170
+ else:
171
+ return dispense_result
172
+ else:
173
+ if (
174
+ isinstance(current_location, CurrentWell)
175
+ and current_location.pipette_id == params.pipetteId
176
+ ):
177
+ volume_added = (
178
+ self._state_view.pipettes.get_liquid_dispensed_by_ejecting_volume(
179
+ pipette_id=params.pipetteId,
180
+ volume=dispense_result.public.volume,
181
+ )
182
+ )
183
+ if volume_added is not None:
184
+ volume_added *= self._state_view.geometry.get_nozzles_per_well(
185
+ current_location.labware_id,
186
+ current_location.well_name,
187
+ params.pipetteId,
188
+ )
189
+ return SuccessData(
190
+ public=DispenseWhileTrackingResult(
191
+ volume=dispense_result.public.volume,
192
+ position=result_deck_point,
193
+ ),
194
+ state_update=dispense_result.state_update.set_liquid_operated(
195
+ labware_id=current_location.labware_id,
196
+ well_names=self._state_view.geometry.get_wells_covered_by_pipette_with_active_well(
197
+ current_location.labware_id,
198
+ current_location.well_name,
199
+ params.pipetteId,
200
+ ),
201
+ volume_added=volume_added
202
+ if volume_added is not None
203
+ else CLEAR,
204
+ ),
205
+ )
206
+ else:
207
+ return SuccessData(
208
+ public=DispenseWhileTrackingResult(
209
+ volume=dispense_result.public.volume,
210
+ position=result_deck_point,
211
+ ),
212
+ state_update=dispense_result.state_update,
213
+ )
214
+
215
+
216
+ class DispenseWhileTracking(
217
+ BaseCommand[
218
+ DispenseWhileTrackingParams,
219
+ DispenseWhileTrackingResult,
220
+ OverpressureError | StallOrCollisionError,
221
+ ]
222
+ ):
223
+ """Dispense command model."""
224
+
225
+ commandType: DispenseWhileTrackingCommandType = "dispenseWhileTracking"
226
+ params: DispenseWhileTrackingParams
227
+ result: Optional[DispenseWhileTrackingResult] = None
228
+
229
+ _ImplementationCls: Type[
230
+ DispenseWhileTrackingImplementation
231
+ ] = DispenseWhileTrackingImplementation
232
+
233
+
234
+ class DispenseWhileTrackingCreate(BaseCommandCreate[DispenseWhileTrackingParams]):
235
+ """Create dispenseWhileTracking command request model."""
236
+
237
+ commandType: DispenseWhileTrackingCommandType = "dispenseWhileTracking"
238
+ params: DispenseWhileTrackingParams
239
+
240
+ _CommandCls: Type[DispenseWhileTracking] = DispenseWhileTracking
@@ -35,6 +35,7 @@ if TYPE_CHECKING:
35
35
  from ..state.state import StateView
36
36
  from ..execution import MovementHandler, TipHandler
37
37
 
38
+ from opentrons.hardware_control.types import TipScrapeType
38
39
 
39
40
  DropTipCommandType = Literal["dropTip"]
40
41
 
@@ -72,6 +73,16 @@ class DropTipParams(PipetteIdMixin):
72
73
  ),
73
74
  json_schema_extra=_remove_default,
74
75
  )
76
+ scrape_tips: bool | SkipJsonSchema[None] = Field(
77
+ False,
78
+ description=(
79
+ "Whether or not to scrape off the tips with the ejector all the way down."
80
+ " If True, and the target location is a tip rack well, it will move the pipette."
81
+ " Towards the center of the tip rack with the ejector in the 'drop_tip' position."
82
+ " If False, no horizontal movement will occur."
83
+ ),
84
+ json_schema_extra=_remove_default,
85
+ )
75
86
 
76
87
 
77
88
  class DropTipResult(DestinationPositionResult):
@@ -140,9 +151,20 @@ class DropTipImplementation(AbstractCommandImpl[DropTipParams, _ExecuteReturn]):
140
151
  if isinstance(move_result, DefinedErrorData):
141
152
  return move_result
142
153
 
154
+ scrape_type = TipScrapeType.NONE
155
+ if (
156
+ params.scrape_tips
157
+ and self._state_view.geometry._labware.get_definition(
158
+ labware_id
159
+ ).parameters.isTiprack
160
+ ):
161
+ if int("".join(filter(str.isdigit, well_name))) <= 6:
162
+ scrape_type = TipScrapeType.RIGHT_ONE_COL
163
+ else:
164
+ scrape_type = TipScrapeType.LEFT_ONE_COL
143
165
  try:
144
166
  await self._tip_handler.drop_tip(
145
- pipette_id=pipette_id, home_after=home_after
167
+ pipette_id=pipette_id, home_after=home_after, scrape_type=scrape_type
146
168
  )
147
169
  except TipAttachedError as exception:
148
170
  error = TipPhysicallyAttachedError(
@@ -4,13 +4,14 @@ from __future__ import annotations
4
4
  from typing import TYPE_CHECKING, Optional, Type, Union
5
5
  from typing_extensions import Literal
6
6
 
7
- from opentrons.protocol_engine.errors import UnsupportedLabwareForActionError
8
7
  from .pipetting_common import (
9
8
  PipetteIdMixin,
10
9
  FlowRateMixin,
11
10
  DispenseVolumeMixin,
12
11
  BaseLiquidHandlingResult,
13
12
  dispense_in_place,
13
+ increase_evo_disp_count,
14
+ DEFAULT_CORRECTION_VOLUME,
14
15
  )
15
16
  from .movement_common import (
16
17
  LiquidHandlingWellLocationMixin,
@@ -26,7 +27,6 @@ from .command import (
26
27
  DefinedErrorData,
27
28
  )
28
29
  from ..state.update_types import StateUpdate
29
- from ..resources import labware_validation
30
30
  from ..errors import ProtocolEngineError
31
31
 
32
32
  if TYPE_CHECKING:
@@ -84,11 +84,6 @@ class EvotipDispenseImplementation(
84
84
  labware_id = params.labwareId
85
85
  well_name = params.wellName
86
86
 
87
- labware_definition = self._state_view.labware.get_definition(params.labwareId)
88
- if not labware_validation.is_evotips(labware_definition.parameters.loadName):
89
- raise UnsupportedLabwareForActionError(
90
- f"Cannot use command: `EvotipDispense` with labware: {labware_definition.parameters.loadName}"
91
- )
92
87
  move_result = await move_to_well(
93
88
  movement=self._movement,
94
89
  model_utils=self._model_utils,
@@ -101,6 +96,9 @@ class EvotipDispenseImplementation(
101
96
  return move_result
102
97
 
103
98
  current_position = await self._gantry_mover.get_position(params.pipetteId)
99
+ await increase_evo_disp_count(
100
+ pipette_id=params.pipetteId, pipetting=self._pipetting
101
+ )
104
102
  result = await dispense_in_place(
105
103
  pipette_id=params.pipetteId,
106
104
  volume=params.volume,
@@ -115,6 +113,7 @@ class EvotipDispenseImplementation(
115
113
  },
116
114
  pipetting=self._pipetting,
117
115
  model_utils=self._model_utils,
116
+ correction_volume=params.correctionVolume or DEFAULT_CORRECTION_VOLUME,
118
117
  )
119
118
  if isinstance(result, DefinedErrorData):
120
119
  # TODO (chb, 2025-01-29): Remove this and the OverpressureError returns once disabled for this function