opentrons 8.7.0a9__py3-none-any.whl → 8.8.0a8__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- opentrons/_version.py +2 -2
- opentrons/cli/analyze.py +4 -1
- opentrons/config/__init__.py +7 -0
- opentrons/drivers/asyncio/communication/serial_connection.py +126 -49
- opentrons/drivers/heater_shaker/abstract.py +5 -0
- opentrons/drivers/heater_shaker/driver.py +10 -0
- opentrons/drivers/heater_shaker/simulator.py +4 -0
- opentrons/drivers/thermocycler/abstract.py +6 -0
- opentrons/drivers/thermocycler/driver.py +61 -10
- opentrons/drivers/thermocycler/simulator.py +6 -0
- opentrons/drivers/vacuum_module/__init__.py +5 -0
- opentrons/drivers/vacuum_module/abstract.py +93 -0
- opentrons/drivers/vacuum_module/driver.py +208 -0
- opentrons/drivers/vacuum_module/errors.py +39 -0
- opentrons/drivers/vacuum_module/simulator.py +85 -0
- opentrons/drivers/vacuum_module/types.py +79 -0
- opentrons/execute.py +3 -0
- opentrons/hardware_control/api.py +24 -5
- opentrons/hardware_control/backends/controller.py +8 -2
- opentrons/hardware_control/backends/flex_protocol.py +1 -0
- opentrons/hardware_control/backends/ot3controller.py +35 -2
- opentrons/hardware_control/backends/ot3simulator.py +3 -1
- opentrons/hardware_control/backends/ot3utils.py +37 -0
- opentrons/hardware_control/backends/simulator.py +2 -1
- opentrons/hardware_control/backends/subsystem_manager.py +5 -2
- opentrons/hardware_control/emulation/abstract_emulator.py +6 -4
- opentrons/hardware_control/emulation/connection_handler.py +8 -5
- opentrons/hardware_control/emulation/heater_shaker.py +12 -3
- opentrons/hardware_control/emulation/settings.py +1 -1
- opentrons/hardware_control/emulation/thermocycler.py +67 -15
- opentrons/hardware_control/module_control.py +105 -10
- opentrons/hardware_control/modules/__init__.py +3 -0
- opentrons/hardware_control/modules/absorbance_reader.py +11 -4
- opentrons/hardware_control/modules/flex_stacker.py +38 -9
- opentrons/hardware_control/modules/heater_shaker.py +42 -5
- opentrons/hardware_control/modules/magdeck.py +8 -4
- opentrons/hardware_control/modules/mod_abc.py +14 -6
- opentrons/hardware_control/modules/tempdeck.py +25 -5
- opentrons/hardware_control/modules/thermocycler.py +68 -11
- opentrons/hardware_control/modules/types.py +20 -1
- opentrons/hardware_control/modules/utils.py +11 -4
- opentrons/hardware_control/motion_utilities.py +6 -6
- opentrons/hardware_control/nozzle_manager.py +3 -0
- opentrons/hardware_control/ot3api.py +92 -17
- opentrons/hardware_control/poller.py +22 -8
- opentrons/hardware_control/protocols/liquid_handler.py +12 -4
- opentrons/hardware_control/scripts/update_module_fw.py +5 -0
- opentrons/hardware_control/types.py +43 -2
- opentrons/legacy_commands/commands.py +58 -5
- opentrons/legacy_commands/module_commands.py +52 -0
- opentrons/legacy_commands/protocol_commands.py +53 -1
- opentrons/legacy_commands/types.py +155 -1
- opentrons/motion_planning/deck_conflict.py +17 -12
- opentrons/motion_planning/waypoints.py +15 -29
- opentrons/protocol_api/__init__.py +5 -1
- opentrons/protocol_api/_transfer_liquid_validation.py +17 -2
- opentrons/protocol_api/_types.py +8 -1
- opentrons/protocol_api/core/common.py +3 -1
- opentrons/protocol_api/core/engine/_default_labware_versions.py +33 -11
- opentrons/protocol_api/core/engine/deck_conflict.py +3 -1
- opentrons/protocol_api/core/engine/instrument.py +109 -26
- opentrons/protocol_api/core/engine/labware.py +8 -1
- opentrons/protocol_api/core/engine/module_core.py +95 -4
- opentrons/protocol_api/core/engine/pipette_movement_conflict.py +4 -18
- opentrons/protocol_api/core/engine/protocol.py +51 -2
- opentrons/protocol_api/core/engine/stringify.py +2 -0
- opentrons/protocol_api/core/engine/tasks.py +48 -0
- opentrons/protocol_api/core/engine/well.py +8 -0
- opentrons/protocol_api/core/instrument.py +19 -2
- opentrons/protocol_api/core/legacy/legacy_instrument_core.py +19 -2
- opentrons/protocol_api/core/legacy/legacy_module_core.py +33 -2
- opentrons/protocol_api/core/legacy/legacy_protocol_core.py +23 -1
- opentrons/protocol_api/core/legacy/legacy_well_core.py +4 -0
- opentrons/protocol_api/core/legacy/tasks.py +19 -0
- opentrons/protocol_api/core/legacy_simulator/legacy_instrument_core.py +19 -2
- opentrons/protocol_api/core/legacy_simulator/legacy_protocol_core.py +14 -2
- opentrons/protocol_api/core/legacy_simulator/tasks.py +19 -0
- opentrons/protocol_api/core/module.py +58 -2
- opentrons/protocol_api/core/protocol.py +23 -2
- opentrons/protocol_api/core/tasks.py +31 -0
- opentrons/protocol_api/core/well.py +4 -0
- opentrons/protocol_api/instrument_context.py +388 -2
- opentrons/protocol_api/labware.py +10 -2
- opentrons/protocol_api/module_contexts.py +170 -6
- opentrons/protocol_api/protocol_context.py +87 -21
- opentrons/protocol_api/robot_context.py +41 -25
- opentrons/protocol_api/tasks.py +48 -0
- opentrons/protocol_api/validation.py +49 -3
- opentrons/protocol_engine/__init__.py +4 -0
- opentrons/protocol_engine/actions/__init__.py +6 -2
- opentrons/protocol_engine/actions/actions.py +31 -9
- opentrons/protocol_engine/clients/sync_client.py +42 -7
- opentrons/protocol_engine/commands/__init__.py +56 -0
- opentrons/protocol_engine/commands/absorbance_reader/close_lid.py +2 -15
- opentrons/protocol_engine/commands/absorbance_reader/open_lid.py +2 -15
- opentrons/protocol_engine/commands/absorbance_reader/read.py +22 -23
- opentrons/protocol_engine/commands/aspirate.py +1 -0
- opentrons/protocol_engine/commands/aspirate_while_tracking.py +52 -19
- opentrons/protocol_engine/commands/capture_image.py +302 -0
- opentrons/protocol_engine/commands/command.py +2 -0
- opentrons/protocol_engine/commands/command_unions.py +62 -0
- opentrons/protocol_engine/commands/create_timer.py +83 -0
- opentrons/protocol_engine/commands/dispense.py +1 -0
- opentrons/protocol_engine/commands/dispense_while_tracking.py +56 -19
- opentrons/protocol_engine/commands/drop_tip.py +32 -8
- opentrons/protocol_engine/commands/flex_stacker/common.py +35 -0
- opentrons/protocol_engine/commands/flex_stacker/set_stored_labware.py +7 -0
- opentrons/protocol_engine/commands/heater_shaker/__init__.py +14 -0
- opentrons/protocol_engine/commands/heater_shaker/common.py +20 -0
- opentrons/protocol_engine/commands/heater_shaker/set_and_wait_for_shake_speed.py +5 -4
- opentrons/protocol_engine/commands/heater_shaker/set_shake_speed.py +136 -0
- opentrons/protocol_engine/commands/heater_shaker/set_target_temperature.py +31 -5
- opentrons/protocol_engine/commands/move_labware.py +3 -4
- opentrons/protocol_engine/commands/move_to_addressable_area_for_drop_tip.py +1 -1
- opentrons/protocol_engine/commands/movement_common.py +31 -2
- opentrons/protocol_engine/commands/pick_up_tip.py +21 -11
- opentrons/protocol_engine/commands/pipetting_common.py +48 -3
- opentrons/protocol_engine/commands/set_tip_state.py +97 -0
- opentrons/protocol_engine/commands/temperature_module/set_target_temperature.py +38 -7
- opentrons/protocol_engine/commands/thermocycler/__init__.py +16 -0
- opentrons/protocol_engine/commands/thermocycler/run_extended_profile.py +6 -0
- opentrons/protocol_engine/commands/thermocycler/run_profile.py +8 -0
- opentrons/protocol_engine/commands/thermocycler/set_target_block_temperature.py +44 -7
- opentrons/protocol_engine/commands/thermocycler/set_target_lid_temperature.py +43 -14
- opentrons/protocol_engine/commands/thermocycler/start_run_extended_profile.py +191 -0
- opentrons/protocol_engine/commands/touch_tip.py +1 -1
- opentrons/protocol_engine/commands/unsafe/unsafe_place_labware.py +6 -22
- opentrons/protocol_engine/commands/wait_for_tasks.py +98 -0
- opentrons/protocol_engine/create_protocol_engine.py +12 -0
- opentrons/protocol_engine/engine_support.py +3 -0
- opentrons/protocol_engine/errors/__init__.py +12 -0
- opentrons/protocol_engine/errors/exceptions.py +119 -0
- opentrons/protocol_engine/execution/__init__.py +4 -0
- opentrons/protocol_engine/execution/command_executor.py +62 -1
- opentrons/protocol_engine/execution/create_queue_worker.py +9 -2
- opentrons/protocol_engine/execution/labware_movement.py +13 -15
- opentrons/protocol_engine/execution/movement.py +2 -0
- opentrons/protocol_engine/execution/pipetting.py +26 -25
- opentrons/protocol_engine/execution/queue_worker.py +4 -0
- opentrons/protocol_engine/execution/run_control.py +8 -0
- opentrons/protocol_engine/execution/task_handler.py +157 -0
- opentrons/protocol_engine/protocol_engine.py +137 -36
- opentrons/protocol_engine/resources/__init__.py +4 -0
- opentrons/protocol_engine/resources/camera_provider.py +110 -0
- opentrons/protocol_engine/resources/concurrency_provider.py +27 -0
- opentrons/protocol_engine/resources/deck_configuration_provider.py +7 -0
- opentrons/protocol_engine/resources/file_provider.py +133 -58
- opentrons/protocol_engine/resources/labware_validation.py +10 -6
- opentrons/protocol_engine/slot_standardization.py +2 -0
- opentrons/protocol_engine/state/_well_math.py +60 -18
- opentrons/protocol_engine/state/addressable_areas.py +2 -0
- opentrons/protocol_engine/state/camera.py +54 -0
- opentrons/protocol_engine/state/commands.py +37 -14
- opentrons/protocol_engine/state/geometry.py +276 -379
- opentrons/protocol_engine/state/labware.py +62 -108
- opentrons/protocol_engine/state/labware_origin_math/errors.py +94 -0
- opentrons/protocol_engine/state/labware_origin_math/stackup_origin_to_labware_origin.py +1336 -0
- opentrons/protocol_engine/state/module_substates/thermocycler_module_substate.py +37 -0
- opentrons/protocol_engine/state/modules.py +30 -8
- opentrons/protocol_engine/state/motion.py +60 -18
- opentrons/protocol_engine/state/preconditions.py +59 -0
- opentrons/protocol_engine/state/state.py +44 -0
- opentrons/protocol_engine/state/state_summary.py +4 -0
- opentrons/protocol_engine/state/tasks.py +139 -0
- opentrons/protocol_engine/state/tips.py +177 -258
- opentrons/protocol_engine/state/update_types.py +26 -9
- opentrons/protocol_engine/types/__init__.py +23 -4
- opentrons/protocol_engine/types/command_preconditions.py +18 -0
- opentrons/protocol_engine/types/deck_configuration.py +5 -1
- opentrons/protocol_engine/types/instrument.py +8 -1
- opentrons/protocol_engine/types/labware.py +1 -13
- opentrons/protocol_engine/types/location.py +26 -2
- opentrons/protocol_engine/types/module.py +11 -1
- opentrons/protocol_engine/types/tasks.py +38 -0
- opentrons/protocol_engine/types/tip.py +9 -0
- opentrons/protocol_runner/create_simulating_orchestrator.py +29 -2
- opentrons/protocol_runner/protocol_runner.py +14 -1
- opentrons/protocol_runner/run_orchestrator.py +49 -2
- opentrons/protocols/advanced_control/transfers/transfer_liquid_utils.py +2 -2
- opentrons/protocols/api_support/definitions.py +1 -1
- opentrons/protocols/api_support/types.py +2 -1
- opentrons/simulate.py +51 -15
- opentrons/system/camera.py +334 -4
- opentrons/system/ffmpeg.py +110 -0
- {opentrons-8.7.0a9.dist-info → opentrons-8.8.0a8.dist-info}/METADATA +4 -4
- {opentrons-8.7.0a9.dist-info → opentrons-8.8.0a8.dist-info}/RECORD +189 -161
- opentrons/protocol_engine/state/_labware_origin_math.py +0 -636
- {opentrons-8.7.0a9.dist-info → opentrons-8.8.0a8.dist-info}/WHEEL +0 -0
- {opentrons-8.7.0a9.dist-info → opentrons-8.8.0a8.dist-info}/entry_points.txt +0 -0
- {opentrons-8.7.0a9.dist-info → opentrons-8.8.0a8.dist-info}/licenses/LICENSE +0 -0
|
@@ -13,7 +13,7 @@ from .pipetting_common import (
|
|
|
13
13
|
aspirate_while_tracking,
|
|
14
14
|
)
|
|
15
15
|
from .movement_common import (
|
|
16
|
-
|
|
16
|
+
DynamicLiquidHandlingWellLocationMixin,
|
|
17
17
|
DestinationPositionResult,
|
|
18
18
|
StallOrCollisionError,
|
|
19
19
|
move_to_well,
|
|
@@ -45,7 +45,7 @@ class AspirateWhileTrackingParams(
|
|
|
45
45
|
PipetteIdMixin,
|
|
46
46
|
AspirateVolumeMixin,
|
|
47
47
|
FlowRateMixin,
|
|
48
|
-
|
|
48
|
+
DynamicLiquidHandlingWellLocationMixin,
|
|
49
49
|
):
|
|
50
50
|
"""Parameters required to aspirate from a specific well."""
|
|
51
51
|
|
|
@@ -107,14 +107,20 @@ class AspirateWhileTrackingImplementation(
|
|
|
107
107
|
)
|
|
108
108
|
state_update = StateUpdate()
|
|
109
109
|
|
|
110
|
+
end_point = self._state_view.geometry.get_well_position(
|
|
111
|
+
labware_id=params.labwareId,
|
|
112
|
+
well_name=params.wellName,
|
|
113
|
+
well_location=params.trackToLocation,
|
|
114
|
+
operation_volume=-params.volume,
|
|
115
|
+
pipette_id=params.pipetteId,
|
|
116
|
+
)
|
|
110
117
|
move_result = await move_to_well(
|
|
111
118
|
movement=self._movement,
|
|
112
119
|
model_utils=self._model_utils,
|
|
113
120
|
pipette_id=params.pipetteId,
|
|
114
121
|
labware_id=params.labwareId,
|
|
115
122
|
well_name=params.wellName,
|
|
116
|
-
well_location=params.
|
|
117
|
-
operation_volume=-params.volume,
|
|
123
|
+
well_location=params.trackFromLocation,
|
|
118
124
|
)
|
|
119
125
|
state_update.append(move_result.state_update)
|
|
120
126
|
if isinstance(move_result, DefinedErrorData):
|
|
@@ -128,6 +134,7 @@ class AspirateWhileTrackingImplementation(
|
|
|
128
134
|
well_name=params.wellName,
|
|
129
135
|
volume=params.volume,
|
|
130
136
|
flow_rate=params.flowRate,
|
|
137
|
+
end_point=end_point,
|
|
131
138
|
location_if_error={
|
|
132
139
|
"retryLocation": (
|
|
133
140
|
move_result.public.position.x,
|
|
@@ -138,7 +145,48 @@ class AspirateWhileTrackingImplementation(
|
|
|
138
145
|
command_note_adder=self._command_note_adder,
|
|
139
146
|
pipetting=self._pipetting,
|
|
140
147
|
model_utils=self._model_utils,
|
|
148
|
+
movement_delay=params.movement_delay,
|
|
141
149
|
)
|
|
150
|
+
if isinstance(aspirate_result, DefinedErrorData):
|
|
151
|
+
if isinstance(aspirate_result.public, OverpressureError):
|
|
152
|
+
return DefinedErrorData(
|
|
153
|
+
public=OverpressureError(
|
|
154
|
+
id=aspirate_result.public.id,
|
|
155
|
+
createdAt=aspirate_result.public.createdAt,
|
|
156
|
+
wrappedErrors=aspirate_result.public.wrappedErrors,
|
|
157
|
+
errorInfo=aspirate_result.public.errorInfo,
|
|
158
|
+
),
|
|
159
|
+
state_update=aspirate_result.state_update.set_liquid_operated(
|
|
160
|
+
labware_id=params.labwareId,
|
|
161
|
+
well_names=self._state_view.geometry.get_wells_covered_by_pipette_with_active_well(
|
|
162
|
+
params.labwareId,
|
|
163
|
+
params.wellName,
|
|
164
|
+
params.pipetteId,
|
|
165
|
+
),
|
|
166
|
+
volume_added=CLEAR,
|
|
167
|
+
),
|
|
168
|
+
state_update_if_false_positive=aspirate_result.state_update_if_false_positive,
|
|
169
|
+
)
|
|
170
|
+
elif isinstance(aspirate_result.public, StallOrCollisionError):
|
|
171
|
+
return DefinedErrorData(
|
|
172
|
+
public=StallOrCollisionError(
|
|
173
|
+
id=aspirate_result.public.id,
|
|
174
|
+
createdAt=aspirate_result.public.createdAt,
|
|
175
|
+
wrappedErrors=aspirate_result.public.wrappedErrors,
|
|
176
|
+
errorInfo=aspirate_result.public.errorInfo,
|
|
177
|
+
),
|
|
178
|
+
state_update=aspirate_result.state_update.set_liquid_operated(
|
|
179
|
+
labware_id=params.labwareId,
|
|
180
|
+
well_names=self._state_view.geometry.get_wells_covered_by_pipette_with_active_well(
|
|
181
|
+
params.labwareId,
|
|
182
|
+
params.wellName,
|
|
183
|
+
params.pipetteId,
|
|
184
|
+
),
|
|
185
|
+
volume_added=CLEAR,
|
|
186
|
+
),
|
|
187
|
+
state_update_if_false_positive=aspirate_result.state_update_if_false_positive,
|
|
188
|
+
)
|
|
189
|
+
|
|
142
190
|
position_after_aspirate = await self._gantry_mover.get_position(
|
|
143
191
|
params.pipetteId
|
|
144
192
|
)
|
|
@@ -147,21 +195,6 @@ class AspirateWhileTrackingImplementation(
|
|
|
147
195
|
y=position_after_aspirate.y,
|
|
148
196
|
z=position_after_aspirate.z,
|
|
149
197
|
)
|
|
150
|
-
if isinstance(aspirate_result, DefinedErrorData):
|
|
151
|
-
return DefinedErrorData(
|
|
152
|
-
public=aspirate_result.public,
|
|
153
|
-
state_update=aspirate_result.state_update.set_liquid_operated(
|
|
154
|
-
labware_id=params.labwareId,
|
|
155
|
-
well_names=self._state_view.geometry.get_wells_covered_by_pipette_with_active_well(
|
|
156
|
-
params.labwareId,
|
|
157
|
-
params.wellName,
|
|
158
|
-
params.pipetteId,
|
|
159
|
-
),
|
|
160
|
-
volume_added=CLEAR,
|
|
161
|
-
),
|
|
162
|
-
state_update_if_false_positive=aspirate_result.state_update_if_false_positive,
|
|
163
|
-
)
|
|
164
|
-
|
|
165
198
|
return SuccessData(
|
|
166
199
|
public=AspirateWhileTrackingResult(
|
|
167
200
|
volume=aspirate_result.public.volume,
|
|
@@ -0,0 +1,302 @@
|
|
|
1
|
+
"""Command models to capture an image with a camera."""
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
from typing import Optional, TYPE_CHECKING, Tuple, Any
|
|
4
|
+
from datetime import datetime
|
|
5
|
+
|
|
6
|
+
from typing_extensions import Literal, Type
|
|
7
|
+
from pydantic import BaseModel, Field
|
|
8
|
+
from pydantic.json_schema import SkipJsonSchema
|
|
9
|
+
|
|
10
|
+
from opentrons_shared_data.data_files import MimeType
|
|
11
|
+
from opentrons.system.camera import (
|
|
12
|
+
CONTRAST_DEFAULT,
|
|
13
|
+
BRIGHTNESS_DEFAULT,
|
|
14
|
+
SATURATION_DEFAULT,
|
|
15
|
+
ZOOM_MIN,
|
|
16
|
+
ZOOM_MAX,
|
|
17
|
+
ZOOM_DEFAULT,
|
|
18
|
+
RESOLUTION_MIN,
|
|
19
|
+
RESOLUTION_MAX,
|
|
20
|
+
RESOLUTION_DEFAULT,
|
|
21
|
+
)
|
|
22
|
+
from ..types import PreconditionTypes
|
|
23
|
+
from .command import AbstractCommandImpl, BaseCommand, BaseCommandCreate, SuccessData
|
|
24
|
+
from ..errors import (
|
|
25
|
+
CameraDisabledError,
|
|
26
|
+
CameraSettingsInvalidError,
|
|
27
|
+
FileNameInvalidError,
|
|
28
|
+
)
|
|
29
|
+
from ..errors.error_occurrence import ErrorOccurrence
|
|
30
|
+
|
|
31
|
+
from ..resources.file_provider import (
|
|
32
|
+
ImageCaptureCmdFileNameMetadata,
|
|
33
|
+
)
|
|
34
|
+
from ..resources import FileProvider
|
|
35
|
+
from ..resources.file_provider import SPECIAL_CHARACTERS
|
|
36
|
+
from ..resources import CameraProvider
|
|
37
|
+
from ..resources.camera_provider import ImageParameters
|
|
38
|
+
from ..state import update_types
|
|
39
|
+
|
|
40
|
+
if TYPE_CHECKING:
|
|
41
|
+
from opentrons.protocol_engine.state.state import StateView
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def _remove_default(s: dict[str, Any]) -> None:
|
|
45
|
+
s.pop("default", None)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
CaptureImageCommandType = Literal["captureImage"]
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
class CaptureImageParams(BaseModel):
|
|
52
|
+
"""Input parameters for an image capture."""
|
|
53
|
+
|
|
54
|
+
fileName: str | SkipJsonSchema[None] = Field(
|
|
55
|
+
None,
|
|
56
|
+
description="Optional file name to use when storing the results of an Image Capture.",
|
|
57
|
+
json_schema_extra=_remove_default,
|
|
58
|
+
)
|
|
59
|
+
resolution: Optional[Tuple[int, int]] = Field(
|
|
60
|
+
None,
|
|
61
|
+
description="Width by height resolution in pixels for the image to be captured with.",
|
|
62
|
+
)
|
|
63
|
+
zoom: Optional[float] = Field(
|
|
64
|
+
None,
|
|
65
|
+
description="Multiplier to use when cropping and scaling a captured image. Scale is 1.0 to 2.0.",
|
|
66
|
+
)
|
|
67
|
+
pan: Optional[Tuple[int, int]] = Field(
|
|
68
|
+
None,
|
|
69
|
+
description="X/Y (pixels) position to pan to for a given zoom. Default is the center of the image.",
|
|
70
|
+
)
|
|
71
|
+
contrast: Optional[float] = Field(
|
|
72
|
+
None,
|
|
73
|
+
description="The contrast to use when processing an image. Scale is 0% to 100%.",
|
|
74
|
+
)
|
|
75
|
+
brightness: Optional[float] = Field(
|
|
76
|
+
None,
|
|
77
|
+
description="The brightness to use when processing an image. Scale is 0% to 100%.",
|
|
78
|
+
)
|
|
79
|
+
saturation: Optional[float] = Field(
|
|
80
|
+
None,
|
|
81
|
+
description="The saturation to use when processing an image. Scale is 0% to 100%.",
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
class CaptureImageResult(BaseModel):
|
|
86
|
+
"""Result data from running an image capture."""
|
|
87
|
+
|
|
88
|
+
fileId: Optional[str] = Field(
|
|
89
|
+
None,
|
|
90
|
+
description="File ID for image files output as a result of an image capture action.",
|
|
91
|
+
)
|
|
92
|
+
resolution: Tuple[int, int] = Field(
|
|
93
|
+
...,
|
|
94
|
+
description="Width by height resolution in pixels the image was captured with.",
|
|
95
|
+
)
|
|
96
|
+
zoom: float = Field(
|
|
97
|
+
...,
|
|
98
|
+
description="Multiplier used when cropping and scaling the captured image. Scale is 1.0 to 2.0.",
|
|
99
|
+
)
|
|
100
|
+
pan: Optional[Tuple[int, int]] = Field(
|
|
101
|
+
None,
|
|
102
|
+
description="X/Y (pixels) position panned to.",
|
|
103
|
+
)
|
|
104
|
+
contrast: float = Field(
|
|
105
|
+
...,
|
|
106
|
+
description="The contrast used when processing the image. Scale is 0% to 100%.",
|
|
107
|
+
)
|
|
108
|
+
brightness: float = Field(
|
|
109
|
+
...,
|
|
110
|
+
description="The brightness used when processing the image. Scale is 0% to 100%.",
|
|
111
|
+
)
|
|
112
|
+
saturation: float = Field(
|
|
113
|
+
...,
|
|
114
|
+
description="The saturation used when processing the image. Scale is 0% to 100%.",
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
def _converted_image_params(params: CaptureImageParams) -> ImageParameters:
|
|
119
|
+
return ImageParameters(
|
|
120
|
+
resolution=params.resolution,
|
|
121
|
+
zoom=params.zoom,
|
|
122
|
+
pan=params.pan,
|
|
123
|
+
contrast=(
|
|
124
|
+
(params.contrast / 100) * 2.0 if params.contrast is not None else None
|
|
125
|
+
),
|
|
126
|
+
brightness=(
|
|
127
|
+
int(((params.brightness * 256) // 100) - 128) * -1
|
|
128
|
+
if params.brightness is not None
|
|
129
|
+
else None
|
|
130
|
+
),
|
|
131
|
+
saturation=(
|
|
132
|
+
(params.saturation / 100) * 2.0 if params.saturation is not None else None
|
|
133
|
+
),
|
|
134
|
+
)
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
def _revert_image_parameters(
|
|
138
|
+
file_id: Optional[str], image_params: ImageParameters
|
|
139
|
+
) -> CaptureImageResult:
|
|
140
|
+
contrast = (
|
|
141
|
+
image_params.contrast if image_params.contrast is not None else CONTRAST_DEFAULT
|
|
142
|
+
)
|
|
143
|
+
brightness = (
|
|
144
|
+
image_params.brightness
|
|
145
|
+
if image_params.brightness is not None
|
|
146
|
+
else BRIGHTNESS_DEFAULT
|
|
147
|
+
)
|
|
148
|
+
saturation = (
|
|
149
|
+
image_params.saturation
|
|
150
|
+
if image_params.saturation is not None
|
|
151
|
+
else SATURATION_DEFAULT
|
|
152
|
+
)
|
|
153
|
+
# todo (chb, 2025-10-29): Eventually we will have override defaults that can be passed into the Camera state, load those if they exist
|
|
154
|
+
|
|
155
|
+
return CaptureImageResult(
|
|
156
|
+
fileId=file_id,
|
|
157
|
+
resolution=image_params.resolution
|
|
158
|
+
if image_params.resolution is not None
|
|
159
|
+
else RESOLUTION_DEFAULT,
|
|
160
|
+
zoom=image_params.zoom if image_params.zoom is not None else ZOOM_DEFAULT,
|
|
161
|
+
pan=image_params.pan,
|
|
162
|
+
contrast=(contrast / 2) * 100.0,
|
|
163
|
+
brightness=round((((brightness * -1) + 128) * 100) / 256),
|
|
164
|
+
saturation=(saturation / 2) * 100.0,
|
|
165
|
+
)
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
def _validate_image_params(params: CaptureImageParams) -> None:
|
|
169
|
+
# Validate the filename param provided to fail analysis
|
|
170
|
+
if params.fileName is not None and set(SPECIAL_CHARACTERS).intersection(
|
|
171
|
+
set(params.fileName)
|
|
172
|
+
):
|
|
173
|
+
raise FileNameInvalidError(
|
|
174
|
+
message=f"Capture image filename cannot contain character(s): {SPECIAL_CHARACTERS.intersection(set(params.fileName))}"
|
|
175
|
+
)
|
|
176
|
+
|
|
177
|
+
# Validate the image filter parameters
|
|
178
|
+
if params.zoom is not None and (params.zoom < ZOOM_MIN or params.zoom > ZOOM_MAX):
|
|
179
|
+
raise CameraSettingsInvalidError(
|
|
180
|
+
message="Capture image zoom must be a valid value from 1.0X to 2.0X zoom."
|
|
181
|
+
)
|
|
182
|
+
if params.resolution is not None and (
|
|
183
|
+
params.resolution[0] < RESOLUTION_MIN[0]
|
|
184
|
+
or params.resolution[1] < RESOLUTION_MIN[1]
|
|
185
|
+
or params.resolution[0] > RESOLUTION_MAX[0]
|
|
186
|
+
or params.resolution[1] > RESOLUTION_MAX[1]
|
|
187
|
+
):
|
|
188
|
+
raise CameraSettingsInvalidError(
|
|
189
|
+
message="Capture image resolution must be a valid resolution from 240p through 8K resolutuon."
|
|
190
|
+
)
|
|
191
|
+
if params.brightness is not None and (
|
|
192
|
+
params.brightness < 0 or params.brightness > 100
|
|
193
|
+
):
|
|
194
|
+
raise CameraSettingsInvalidError(
|
|
195
|
+
message="Capture image brightness must be a percentage from 0% to 100%."
|
|
196
|
+
)
|
|
197
|
+
if params.contrast is not None and (params.contrast < 0 or params.contrast > 100):
|
|
198
|
+
raise CameraSettingsInvalidError(
|
|
199
|
+
message="Capture image contrast must be a percentage from 0% to 100%."
|
|
200
|
+
)
|
|
201
|
+
if params.saturation is not None and (
|
|
202
|
+
params.saturation < 0 or params.saturation > 100
|
|
203
|
+
):
|
|
204
|
+
raise CameraSettingsInvalidError(
|
|
205
|
+
message="Capture image saturation must be a percentage from 0% to 100%."
|
|
206
|
+
)
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
class CaptureImageImpl(
|
|
210
|
+
AbstractCommandImpl[CaptureImageParams, SuccessData[CaptureImageResult]]
|
|
211
|
+
):
|
|
212
|
+
"""Execution implementation of an image capture."""
|
|
213
|
+
|
|
214
|
+
def __init__(
|
|
215
|
+
self,
|
|
216
|
+
state_view: StateView,
|
|
217
|
+
file_provider: FileProvider,
|
|
218
|
+
camera_provider: CameraProvider,
|
|
219
|
+
**unused_dependencies: object,
|
|
220
|
+
) -> None:
|
|
221
|
+
self._state_view = state_view
|
|
222
|
+
self._file_provider = file_provider
|
|
223
|
+
self._camera_provider = camera_provider
|
|
224
|
+
|
|
225
|
+
async def execute(
|
|
226
|
+
self, params: CaptureImageParams
|
|
227
|
+
) -> SuccessData[CaptureImageResult]:
|
|
228
|
+
"""Initiate an image capture with a camera."""
|
|
229
|
+
state_update = update_types.StateUpdate()
|
|
230
|
+
state_update.precondition_update = update_types.PreconditionUpdate(
|
|
231
|
+
{PreconditionTypes.IS_CAMERA_USED: True}
|
|
232
|
+
)
|
|
233
|
+
|
|
234
|
+
# Validate that the provided parameters are all acceptable. We do this here and in system/camera.py to ensure analysis fails properly.
|
|
235
|
+
_validate_image_params(params)
|
|
236
|
+
|
|
237
|
+
# Handle capturing an image with the CameraProvider - Engine camera settings take priority
|
|
238
|
+
camera_settings = await self._camera_provider.get_camera_settings()
|
|
239
|
+
engine_camera_settings = self._state_view.camera.get_enablement_settings()
|
|
240
|
+
if (
|
|
241
|
+
engine_camera_settings is None and camera_settings.cameraEnabled is False
|
|
242
|
+
) or (
|
|
243
|
+
engine_camera_settings is not None
|
|
244
|
+
and engine_camera_settings.cameraEnabled is False
|
|
245
|
+
):
|
|
246
|
+
raise CameraDisabledError(
|
|
247
|
+
"Cannot capture image because Camera is disabled."
|
|
248
|
+
)
|
|
249
|
+
|
|
250
|
+
parameters = _converted_image_params(params=params)
|
|
251
|
+
camera_data = await self._camera_provider.capture_image(
|
|
252
|
+
self._state_view.config.robot_type, parameters
|
|
253
|
+
)
|
|
254
|
+
|
|
255
|
+
# Conditionally save file if camera data was returned - in simulation we don't return anything.
|
|
256
|
+
file_id: str | None = None
|
|
257
|
+
if camera_data:
|
|
258
|
+
this_cmd_id = self._state_view.commands.get_running_command_id()
|
|
259
|
+
prev_cmd = self._state_view.commands.get_most_recently_finalized_command()
|
|
260
|
+
prev_cmd_id = prev_cmd.command.id if prev_cmd is not None else None
|
|
261
|
+
|
|
262
|
+
file_info = await self._file_provider.write_file(
|
|
263
|
+
data=camera_data,
|
|
264
|
+
mime_type=MimeType.IMAGE_JPEG,
|
|
265
|
+
command_metadata=ImageCaptureCmdFileNameMetadata(
|
|
266
|
+
step_number=len(self._state_view.commands.get_all()),
|
|
267
|
+
command_timestamp=datetime.now(),
|
|
268
|
+
base_filename=params.fileName,
|
|
269
|
+
command_id=this_cmd_id or "",
|
|
270
|
+
prev_command_id=prev_cmd_id or "",
|
|
271
|
+
),
|
|
272
|
+
)
|
|
273
|
+
file_id = file_info.id
|
|
274
|
+
state_update.files_added = update_types.FilesAddedUpdate(file_ids=[file_id])
|
|
275
|
+
|
|
276
|
+
result = _revert_image_parameters(file_id=file_id, image_params=parameters)
|
|
277
|
+
|
|
278
|
+
return SuccessData(
|
|
279
|
+
public=result,
|
|
280
|
+
state_update=state_update,
|
|
281
|
+
)
|
|
282
|
+
|
|
283
|
+
|
|
284
|
+
class CaptureImage(
|
|
285
|
+
BaseCommand[CaptureImageParams, CaptureImageResult, ErrorOccurrence]
|
|
286
|
+
):
|
|
287
|
+
"""A command to execute an Absorbance Reader measurement."""
|
|
288
|
+
|
|
289
|
+
commandType: CaptureImageCommandType = "captureImage"
|
|
290
|
+
params: CaptureImageParams
|
|
291
|
+
result: Optional[CaptureImageResult] = None
|
|
292
|
+
|
|
293
|
+
_ImplementationCls: Type[CaptureImageImpl] = CaptureImageImpl
|
|
294
|
+
|
|
295
|
+
|
|
296
|
+
class CaptureImageCreate(BaseCommandCreate[CaptureImageParams]):
|
|
297
|
+
"""A request to execute an Absorbance Reader measurement."""
|
|
298
|
+
|
|
299
|
+
commandType: CaptureImageCommandType = "captureImage"
|
|
300
|
+
params: CaptureImageParams
|
|
301
|
+
|
|
302
|
+
_CommandCls: Type[CaptureImage] = CaptureImage
|
|
@@ -178,6 +178,7 @@ class AbstractCommandImpl(
|
|
|
178
178
|
hardware_api: HardwareControlAPI,
|
|
179
179
|
equipment: execution.EquipmentHandler,
|
|
180
180
|
file_provider: execution.FileProvider,
|
|
181
|
+
camera_provider: execution.CameraProvider,
|
|
181
182
|
movement: execution.MovementHandler,
|
|
182
183
|
gantry_mover: execution.GantryMover,
|
|
183
184
|
labware_movement: execution.LabwareMovementHandler,
|
|
@@ -185,6 +186,7 @@ class AbstractCommandImpl(
|
|
|
185
186
|
tip_handler: execution.TipHandler,
|
|
186
187
|
run_control: execution.RunControlHandler,
|
|
187
188
|
rail_lights: execution.RailLightsHandler,
|
|
189
|
+
task_handler: execution.TaskHandler,
|
|
188
190
|
model_utils: ModelUtils,
|
|
189
191
|
status_bar: execution.StatusBarHandler,
|
|
190
192
|
command_note_adder: CommandNoteAdder,
|
|
@@ -267,6 +267,22 @@ from .wait_for_duration import (
|
|
|
267
267
|
WaitForDurationCommandType,
|
|
268
268
|
)
|
|
269
269
|
|
|
270
|
+
from .create_timer import (
|
|
271
|
+
CreateTimer,
|
|
272
|
+
CreateTimerCreate,
|
|
273
|
+
CreateTimerParams,
|
|
274
|
+
CreateTimerResult,
|
|
275
|
+
CreateTimerCommandType,
|
|
276
|
+
)
|
|
277
|
+
|
|
278
|
+
from .wait_for_tasks import (
|
|
279
|
+
WaitForTasks,
|
|
280
|
+
WaitForTasksCreate,
|
|
281
|
+
WaitForTasksParams,
|
|
282
|
+
WaitForTasksResult,
|
|
283
|
+
WaitForTasksCommandType,
|
|
284
|
+
)
|
|
285
|
+
|
|
270
286
|
from .pick_up_tip import (
|
|
271
287
|
PickUpTip,
|
|
272
288
|
PickUpTipParams,
|
|
@@ -372,6 +388,14 @@ from .get_next_tip import (
|
|
|
372
388
|
GetNextTipCommandType,
|
|
373
389
|
)
|
|
374
390
|
|
|
391
|
+
from .set_tip_state import (
|
|
392
|
+
SetTipState,
|
|
393
|
+
SetTipStateCreate,
|
|
394
|
+
SetTipStateParams,
|
|
395
|
+
SetTipStateResult,
|
|
396
|
+
SetTipStateCommandType,
|
|
397
|
+
)
|
|
398
|
+
|
|
375
399
|
from .liquid_probe import (
|
|
376
400
|
LiquidProbe,
|
|
377
401
|
LiquidProbeParams,
|
|
@@ -417,6 +441,14 @@ from .identify_module import (
|
|
|
417
441
|
IdentifyModuleCommandType,
|
|
418
442
|
)
|
|
419
443
|
|
|
444
|
+
from .capture_image import (
|
|
445
|
+
CaptureImage,
|
|
446
|
+
CaptureImageParams,
|
|
447
|
+
CaptureImageCreate,
|
|
448
|
+
CaptureImageResult,
|
|
449
|
+
CaptureImageCommandType,
|
|
450
|
+
)
|
|
451
|
+
|
|
420
452
|
Command = Annotated[
|
|
421
453
|
Union[
|
|
422
454
|
AirGapInPlace,
|
|
@@ -454,6 +486,8 @@ Command = Annotated[
|
|
|
454
486
|
PrepareToAspirate,
|
|
455
487
|
WaitForResume,
|
|
456
488
|
WaitForDuration,
|
|
489
|
+
WaitForTasks,
|
|
490
|
+
CreateTimer,
|
|
457
491
|
PickUpTip,
|
|
458
492
|
SavePosition,
|
|
459
493
|
SetRailLights,
|
|
@@ -462,15 +496,18 @@ Command = Annotated[
|
|
|
462
496
|
VerifyTipPresence,
|
|
463
497
|
GetTipPresence,
|
|
464
498
|
GetNextTip,
|
|
499
|
+
SetTipState,
|
|
465
500
|
LiquidProbe,
|
|
466
501
|
TryLiquidProbe,
|
|
467
502
|
SealPipetteToTip,
|
|
468
503
|
PressureDispense,
|
|
469
504
|
UnsealPipetteFromTip,
|
|
505
|
+
CaptureImage,
|
|
470
506
|
heater_shaker.WaitForTemperature,
|
|
471
507
|
heater_shaker.SetTargetTemperature,
|
|
472
508
|
heater_shaker.DeactivateHeater,
|
|
473
509
|
heater_shaker.SetAndWaitForShakeSpeed,
|
|
510
|
+
heater_shaker.SetShakeSpeed,
|
|
474
511
|
heater_shaker.DeactivateShaker,
|
|
475
512
|
heater_shaker.OpenLabwareLatch,
|
|
476
513
|
heater_shaker.CloseLabwareLatch,
|
|
@@ -488,6 +525,7 @@ Command = Annotated[
|
|
|
488
525
|
thermocycler.OpenLid,
|
|
489
526
|
thermocycler.CloseLid,
|
|
490
527
|
thermocycler.RunProfile,
|
|
528
|
+
thermocycler.StartRunExtendedProfile,
|
|
491
529
|
thermocycler.RunExtendedProfile,
|
|
492
530
|
absorbance_reader.CloseLid,
|
|
493
531
|
absorbance_reader.OpenLid,
|
|
@@ -557,6 +595,8 @@ CommandParams = Union[
|
|
|
557
595
|
PrepareToAspirateParams,
|
|
558
596
|
WaitForResumeParams,
|
|
559
597
|
WaitForDurationParams,
|
|
598
|
+
WaitForTasksParams,
|
|
599
|
+
CreateTimerParams,
|
|
560
600
|
PickUpTipParams,
|
|
561
601
|
SavePositionParams,
|
|
562
602
|
SetRailLightsParams,
|
|
@@ -565,15 +605,18 @@ CommandParams = Union[
|
|
|
565
605
|
VerifyTipPresenceParams,
|
|
566
606
|
GetTipPresenceParams,
|
|
567
607
|
GetNextTipParams,
|
|
608
|
+
SetTipStateParams,
|
|
568
609
|
LiquidProbeParams,
|
|
569
610
|
TryLiquidProbeParams,
|
|
570
611
|
SealPipetteToTipParams,
|
|
571
612
|
PressureDispenseParams,
|
|
572
613
|
UnsealPipetteFromTipParams,
|
|
614
|
+
CaptureImageParams,
|
|
573
615
|
heater_shaker.WaitForTemperatureParams,
|
|
574
616
|
heater_shaker.SetTargetTemperatureParams,
|
|
575
617
|
heater_shaker.DeactivateHeaterParams,
|
|
576
618
|
heater_shaker.SetAndWaitForShakeSpeedParams,
|
|
619
|
+
heater_shaker.SetShakeSpeedParams,
|
|
577
620
|
heater_shaker.DeactivateShakerParams,
|
|
578
621
|
heater_shaker.OpenLabwareLatchParams,
|
|
579
622
|
heater_shaker.CloseLabwareLatchParams,
|
|
@@ -591,6 +634,7 @@ CommandParams = Union[
|
|
|
591
634
|
thermocycler.OpenLidParams,
|
|
592
635
|
thermocycler.CloseLidParams,
|
|
593
636
|
thermocycler.RunProfileParams,
|
|
637
|
+
thermocycler.StartRunExtendedProfileParams,
|
|
594
638
|
thermocycler.RunExtendedProfileParams,
|
|
595
639
|
absorbance_reader.CloseLidParams,
|
|
596
640
|
absorbance_reader.OpenLidParams,
|
|
@@ -658,6 +702,8 @@ CommandType = Union[
|
|
|
658
702
|
PrepareToAspirateCommandType,
|
|
659
703
|
WaitForResumeCommandType,
|
|
660
704
|
WaitForDurationCommandType,
|
|
705
|
+
WaitForTasksCommandType,
|
|
706
|
+
CreateTimerCommandType,
|
|
661
707
|
PickUpTipCommandType,
|
|
662
708
|
SavePositionCommandType,
|
|
663
709
|
SetRailLightsCommandType,
|
|
@@ -666,15 +712,18 @@ CommandType = Union[
|
|
|
666
712
|
VerifyTipPresenceCommandType,
|
|
667
713
|
GetTipPresenceCommandType,
|
|
668
714
|
GetNextTipCommandType,
|
|
715
|
+
SetTipStateCommandType,
|
|
669
716
|
LiquidProbeCommandType,
|
|
670
717
|
TryLiquidProbeCommandType,
|
|
671
718
|
SealPipetteToTipCommandType,
|
|
672
719
|
PressureDispenseCommandType,
|
|
673
720
|
UnsealPipetteFromTipCommandType,
|
|
721
|
+
CaptureImageCommandType,
|
|
674
722
|
heater_shaker.WaitForTemperatureCommandType,
|
|
675
723
|
heater_shaker.SetTargetTemperatureCommandType,
|
|
676
724
|
heater_shaker.DeactivateHeaterCommandType,
|
|
677
725
|
heater_shaker.SetAndWaitForShakeSpeedCommandType,
|
|
726
|
+
heater_shaker.SetShakeSpeedCommandType,
|
|
678
727
|
heater_shaker.DeactivateShakerCommandType,
|
|
679
728
|
heater_shaker.OpenLabwareLatchCommandType,
|
|
680
729
|
heater_shaker.CloseLabwareLatchCommandType,
|
|
@@ -692,6 +741,7 @@ CommandType = Union[
|
|
|
692
741
|
thermocycler.OpenLidCommandType,
|
|
693
742
|
thermocycler.CloseLidCommandType,
|
|
694
743
|
thermocycler.RunProfileCommandType,
|
|
744
|
+
thermocycler.StartRunExtendedProfileCommandType,
|
|
695
745
|
thermocycler.RunExtendedProfileCommandType,
|
|
696
746
|
absorbance_reader.CloseLidCommandType,
|
|
697
747
|
absorbance_reader.OpenLidCommandType,
|
|
@@ -760,6 +810,8 @@ CommandCreate = Annotated[
|
|
|
760
810
|
PrepareToAspirateCreate,
|
|
761
811
|
WaitForResumeCreate,
|
|
762
812
|
WaitForDurationCreate,
|
|
813
|
+
WaitForTasksCreate,
|
|
814
|
+
CreateTimerCreate,
|
|
763
815
|
PickUpTipCreate,
|
|
764
816
|
SavePositionCreate,
|
|
765
817
|
SetRailLightsCreate,
|
|
@@ -768,15 +820,18 @@ CommandCreate = Annotated[
|
|
|
768
820
|
VerifyTipPresenceCreate,
|
|
769
821
|
GetTipPresenceCreate,
|
|
770
822
|
GetNextTipCreate,
|
|
823
|
+
SetTipStateCreate,
|
|
771
824
|
LiquidProbeCreate,
|
|
772
825
|
TryLiquidProbeCreate,
|
|
773
826
|
SealPipetteToTipCreate,
|
|
774
827
|
PressureDispenseCreate,
|
|
775
828
|
UnsealPipetteFromTipCreate,
|
|
829
|
+
CaptureImageCreate,
|
|
776
830
|
heater_shaker.WaitForTemperatureCreate,
|
|
777
831
|
heater_shaker.SetTargetTemperatureCreate,
|
|
778
832
|
heater_shaker.DeactivateHeaterCreate,
|
|
779
833
|
heater_shaker.SetAndWaitForShakeSpeedCreate,
|
|
834
|
+
heater_shaker.SetShakeSpeedCreate,
|
|
780
835
|
heater_shaker.DeactivateShakerCreate,
|
|
781
836
|
heater_shaker.OpenLabwareLatchCreate,
|
|
782
837
|
heater_shaker.CloseLabwareLatchCreate,
|
|
@@ -794,6 +849,7 @@ CommandCreate = Annotated[
|
|
|
794
849
|
thermocycler.OpenLidCreate,
|
|
795
850
|
thermocycler.CloseLidCreate,
|
|
796
851
|
thermocycler.RunProfileCreate,
|
|
852
|
+
thermocycler.StartRunExtendedProfileCreate,
|
|
797
853
|
thermocycler.RunExtendedProfileCreate,
|
|
798
854
|
absorbance_reader.CloseLidCreate,
|
|
799
855
|
absorbance_reader.OpenLidCreate,
|
|
@@ -870,6 +926,8 @@ CommandResult = Union[
|
|
|
870
926
|
PrepareToAspirateResult,
|
|
871
927
|
WaitForResumeResult,
|
|
872
928
|
WaitForDurationResult,
|
|
929
|
+
WaitForTasksResult,
|
|
930
|
+
CreateTimerResult,
|
|
873
931
|
PickUpTipResult,
|
|
874
932
|
SavePositionResult,
|
|
875
933
|
SetRailLightsResult,
|
|
@@ -878,15 +936,18 @@ CommandResult = Union[
|
|
|
878
936
|
VerifyTipPresenceResult,
|
|
879
937
|
GetTipPresenceResult,
|
|
880
938
|
GetNextTipResult,
|
|
939
|
+
SetTipStateResult,
|
|
881
940
|
LiquidProbeResult,
|
|
882
941
|
TryLiquidProbeResult,
|
|
883
942
|
SealPipetteToTipResult,
|
|
884
943
|
PressureDispenseResult,
|
|
885
944
|
UnsealPipetteFromTipResult,
|
|
945
|
+
CaptureImageResult,
|
|
886
946
|
heater_shaker.WaitForTemperatureResult,
|
|
887
947
|
heater_shaker.SetTargetTemperatureResult,
|
|
888
948
|
heater_shaker.DeactivateHeaterResult,
|
|
889
949
|
heater_shaker.SetAndWaitForShakeSpeedResult,
|
|
950
|
+
heater_shaker.SetShakeSpeedResult,
|
|
890
951
|
heater_shaker.DeactivateShakerResult,
|
|
891
952
|
heater_shaker.OpenLabwareLatchResult,
|
|
892
953
|
heater_shaker.CloseLabwareLatchResult,
|
|
@@ -904,6 +965,7 @@ CommandResult = Union[
|
|
|
904
965
|
thermocycler.OpenLidResult,
|
|
905
966
|
thermocycler.CloseLidResult,
|
|
906
967
|
thermocycler.RunProfileResult,
|
|
968
|
+
thermocycler.StartRunExtendedProfileResult,
|
|
907
969
|
thermocycler.RunExtendedProfileResult,
|
|
908
970
|
absorbance_reader.CloseLidResult,
|
|
909
971
|
absorbance_reader.OpenLidResult,
|