Skip to content

Commit

Permalink
Merge branch 'edge' into abt-async-analyses
Browse files Browse the repository at this point in the history
  • Loading branch information
y3rsh committed Oct 8, 2024
2 parents f2a32db + 44aa757 commit 6985567
Show file tree
Hide file tree
Showing 46 changed files with 6,477 additions and 316 deletions.
1 change: 1 addition & 0 deletions api-client/src/errorRecovery/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './settings'
16 changes: 16 additions & 0 deletions api-client/src/errorRecovery/settings/getErrorRecoverySettings.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { GET, request } from '../../request'

import type { ResponsePromise } from '../../request'
import type { HostConfig } from '../../types'
import type { ErrorRecoverySettingsResponse } from './types'

export function getErrorRecoverySettings(
config: HostConfig
): ResponsePromise<ErrorRecoverySettingsResponse> {
return request<ErrorRecoverySettingsResponse>(
GET,
'/errorRecovery/settings',
null,
config
)
}
3 changes: 3 additions & 0 deletions api-client/src/errorRecovery/settings/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export { getErrorRecoverySettings } from './getErrorRecoverySettings'
export { updateErrorRecoverySettings } from './updateErrorRecoverySettings'
export * from './types'
9 changes: 9 additions & 0 deletions api-client/src/errorRecovery/settings/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
export interface ErrorRecoverySettingsResponse {
data: {
enabled: boolean
}
}

export interface ErrorRecoverySettingsRequest {
data: Partial<ErrorRecoverySettingsResponse['data']>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { PATCH, request } from '../../request'

import type { ResponsePromise } from '../../request'
import type { HostConfig } from '../../types'
import type {
ErrorRecoverySettingsRequest,
ErrorRecoverySettingsResponse,
} from './types'

export function updateErrorRecoverySettings(
config: HostConfig,
settings: ErrorRecoverySettingsRequest
): ResponsePromise<ErrorRecoverySettingsResponse> {
return request<ErrorRecoverySettingsResponse, ErrorRecoverySettingsRequest>(
PATCH,
'/errorRecovery/settings',
settings,
config
)
}
1 change: 1 addition & 0 deletions api-client/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ export * from './calibration'
export * from './client_data'
export * from './dataFiles'
export * from './deck_configuration'
export * from './errorRecovery'
export * from './health'
export * from './instruments'
export * from './maintenance_runs'
Expand Down
61 changes: 59 additions & 2 deletions api/src/opentrons/hardware_control/modules/thermocycler.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import asyncio
import logging
from typing import Callable, Optional, List, Dict, Mapping
from typing import Callable, Optional, List, Dict, Mapping, Union, cast
from opentrons.drivers.rpi_drivers.types import USBPort
from opentrons.drivers.types import ThermocyclerLidStatus, Temperature, PlateTemperature
from opentrons.hardware_control.modules.lid_temp_status import LidTemperatureStatus
Expand Down Expand Up @@ -363,6 +363,39 @@ async def cycle_temperatures(
self.make_cancellable(task)
await task

async def execute_profile(
self,
profile: List[Union[types.ThermocyclerCycle, types.ThermocyclerStep]],
volume: Optional[float] = None,
) -> None:
"""Begin a set temperature profile, with both repeating and non-repeating steps.
Args:
profile: The temperature profile to follow.
volume: Optional volume
Returns: None
"""
await self.wait_for_is_running()
self._total_cycle_count = 0
self._total_step_count = 0
self._current_cycle_index = 0
self._current_step_index = 0
for step_or_cycle in profile:
if "steps" in step_or_cycle:
# basically https://github.com/python/mypy/issues/14766
this_cycle = cast(types.ThermocyclerCycle, step_or_cycle)
self._total_cycle_count += this_cycle["repetitions"]
self._total_step_count += (
len(this_cycle["steps"]) * this_cycle["repetitions"]
)
else:
self._total_step_count += 1
self._total_cycle_count += 1
task = self._loop.create_task(self._execute_profile(profile, volume))
self.make_cancellable(task)
await task

async def set_lid_temperature(self, temperature: float) -> None:
"""Set the lid temperature in degrees Celsius"""
await self.wait_for_is_running()
Expand Down Expand Up @@ -574,7 +607,7 @@ async def _execute_cycles(
self,
steps: List[types.ThermocyclerStep],
repetitions: int,
volume: Optional[float] = None,
volume: Optional[float],
) -> None:
"""
Execute cycles.
Expand All @@ -592,6 +625,30 @@ async def _execute_cycles(
self._current_step_index = step_idx + 1 # science starts at 1
await self._execute_cycle_step(step, volume)

async def _execute_profile(
self,
profile: List[Union[types.ThermocyclerCycle, types.ThermocyclerStep]],
volume: Optional[float],
) -> None:
"""
Execute profiles.
Profiles command a thermocycler pattern that can contain multiple cycles and out-of-cycle steps.
"""
self._current_cycle_index = 0
self._current_step_index = 0
for step_or_cycle in profile:
self._current_cycle_index += 1
if "repetitions" in step_or_cycle:
# basically https://github.com/python/mypy/issues/14766
this_cycle = cast(types.ThermocyclerCycle, step_or_cycle)
for rep in range(this_cycle["repetitions"]):
for step in this_cycle["steps"]:
self._current_step_index += 1
await self._execute_cycle_step(step, volume)
else:
await self._execute_cycle_step(step_or_cycle, volume)

# TODO(mc, 2022-10-13): why does this exist?
# Do the driver and poller really need to be disconnected?
# Could we accomplish the same thing by latching the error state
Expand Down
5 changes: 5 additions & 0 deletions api/src/opentrons/hardware_control/modules/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,11 @@ class ThermocyclerStep(ThermocyclerStepBase, total=False):
hold_time_minutes: float


class ThermocyclerCycle(TypedDict):
steps: List[ThermocyclerStep]
repetitions: int


UploadFunction = Callable[[str, str, Dict[str, Any]], Awaitable[Tuple[bool, str]]]


Expand Down
56 changes: 48 additions & 8 deletions api/src/opentrons/protocol_api/core/engine/module_core.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
"""Protocol API module implementation logic."""
from __future__ import annotations

from typing import Optional, List, Dict
from typing import Optional, List, Dict, Union

from opentrons.hardware_control import SynchronousAdapter, modules as hw_modules
from opentrons.hardware_control.modules.types import (
ModuleModel,
TemperatureStatus,
MagneticStatus,
ThermocyclerStep,
SpeedStatus,
module_model_from_string,
)
Expand All @@ -27,7 +26,7 @@
CannotPerformModuleAction,
)

from opentrons.protocols.api_support.types import APIVersion
from opentrons.protocols.api_support.types import APIVersion, ThermocyclerStep

from ... import validation
from ..module import (
Expand Down Expand Up @@ -327,15 +326,13 @@ def wait_for_lid_temperature(self) -> None:
cmd.thermocycler.WaitForLidTemperatureParams(moduleId=self.module_id)
)

def execute_profile(
def _execute_profile_pre_221(
self,
steps: List[ThermocyclerStep],
repetitions: int,
block_max_volume: Optional[float] = None,
block_max_volume: Optional[float],
) -> None:
"""Execute a Thermocycler Profile."""
self._repetitions = repetitions
self._step_count = len(steps)
"""Execute a thermocycler profile using thermocycler/runProfile and flattened steps."""
engine_steps = [
cmd.thermocycler.RunProfileStepParams(
celsius=step["temperature"],
Expand All @@ -352,6 +349,49 @@ def execute_profile(
)
)

def _execute_profile_post_221(
self,
steps: List[ThermocyclerStep],
repetitions: int,
block_max_volume: Optional[float],
) -> None:
"""Execute a thermocycler profile using thermocycler/runExtendedProfile."""
engine_steps: List[
Union[cmd.thermocycler.ProfileCycle, cmd.thermocycler.ProfileStep]
] = [
cmd.thermocycler.ProfileCycle(
repetitions=repetitions,
steps=[
cmd.thermocycler.ProfileStep(
celsius=step["temperature"],
holdSeconds=step["hold_time_seconds"],
)
for step in steps
],
)
]
self._engine_client.execute_command(
cmd.thermocycler.RunExtendedProfileParams(
moduleId=self.module_id,
profileElements=engine_steps,
blockMaxVolumeUl=block_max_volume,
)
)

def execute_profile(
self,
steps: List[ThermocyclerStep],
repetitions: int,
block_max_volume: Optional[float] = None,
) -> None:
"""Execute a Thermocycler Profile."""
self._repetitions = repetitions
self._step_count = len(steps)
if self.api_version >= APIVersion(2, 21):
return self._execute_profile_post_221(steps, repetitions, block_max_volume)
else:
return self._execute_profile_pre_221(steps, repetitions, block_max_volume)

def deactivate_lid(self) -> None:
"""Turn off the heated lid."""
self._engine_client.execute_command(
Expand Down
10 changes: 8 additions & 2 deletions api/src/opentrons/protocol_api/module_contexts.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,9 @@
from opentrons_shared_data.module.types import ModuleModel, ModuleType

from opentrons.legacy_broker import LegacyBroker
from opentrons.hardware_control.modules import ThermocyclerStep
from opentrons.legacy_commands import module_commands as cmds
from opentrons.legacy_commands.publisher import CommandPublisher, publish
from opentrons.protocols.api_support.types import APIVersion
from opentrons.protocols.api_support.types import APIVersion, ThermocyclerStep
from opentrons.protocols.api_support.util import (
APIVersionError,
requires_version,
Expand Down Expand Up @@ -629,6 +628,13 @@ def execute_profile(
``hold_time_minutes`` and ``hold_time_seconds`` must be defined
and for each step.
.. note:
Before API Version 2.21, Thermocycler profiles run with this command
would be listed in the app as having a number of repetitions equal to
their step count. At or above API Version 2.21, the structure of the
Thermocycler cycles is preserved.
"""
repetitions = validation.ensure_thermocycler_repetition_count(repetitions)
validated_steps = validation.ensure_thermocycler_profile_steps(steps)
Expand Down
3 changes: 1 addition & 2 deletions api/src/opentrons/protocol_api/validation.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
from opentrons_shared_data.pipette.types import PipetteNameType
from opentrons_shared_data.robot.types import RobotType

from opentrons.protocols.api_support.types import APIVersion
from opentrons.protocols.api_support.types import APIVersion, ThermocyclerStep
from opentrons.protocols.api_support.util import APIVersionError
from opentrons.protocols.models import LabwareDefinition
from opentrons.types import Mount, DeckSlotName, StagingSlotName, Location
Expand All @@ -30,7 +30,6 @@
HeaterShakerModuleModel,
MagneticBlockModel,
AbsorbanceReaderModel,
ThermocyclerStep,
)

from .disposal_locations import TrashBin, WasteChute
Expand Down
5 changes: 5 additions & 0 deletions api/src/opentrons/protocol_engine/commands/command_unions.py
Original file line number Diff line number Diff line change
Expand Up @@ -380,6 +380,7 @@
thermocycler.OpenLid,
thermocycler.CloseLid,
thermocycler.RunProfile,
thermocycler.RunExtendedProfile,
absorbance_reader.CloseLid,
absorbance_reader.OpenLid,
absorbance_reader.Initialize,
Expand Down Expand Up @@ -456,6 +457,7 @@
thermocycler.OpenLidParams,
thermocycler.CloseLidParams,
thermocycler.RunProfileParams,
thermocycler.RunExtendedProfileParams,
absorbance_reader.CloseLidParams,
absorbance_reader.OpenLidParams,
absorbance_reader.InitializeParams,
Expand Down Expand Up @@ -530,6 +532,7 @@
thermocycler.OpenLidCommandType,
thermocycler.CloseLidCommandType,
thermocycler.RunProfileCommandType,
thermocycler.RunExtendedProfileCommandType,
absorbance_reader.CloseLidCommandType,
absorbance_reader.OpenLidCommandType,
absorbance_reader.InitializeCommandType,
Expand Down Expand Up @@ -605,6 +608,7 @@
thermocycler.OpenLidCreate,
thermocycler.CloseLidCreate,
thermocycler.RunProfileCreate,
thermocycler.RunExtendedProfileCreate,
absorbance_reader.CloseLidCreate,
absorbance_reader.OpenLidCreate,
absorbance_reader.InitializeCreate,
Expand Down Expand Up @@ -681,6 +685,7 @@
thermocycler.OpenLidResult,
thermocycler.CloseLidResult,
thermocycler.RunProfileResult,
thermocycler.RunExtendedProfileResult,
absorbance_reader.CloseLidResult,
absorbance_reader.OpenLidResult,
absorbance_reader.InitializeResult,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,16 @@
RunProfileCreate,
)

from .run_extended_profile import (
RunExtendedProfileCommandType,
RunExtendedProfileParams,
RunExtendedProfileResult,
RunExtendedProfile,
RunExtendedProfileCreate,
ProfileCycle,
ProfileStep,
)


__all__ = [
# Set target block temperature command models
Expand Down Expand Up @@ -130,4 +140,13 @@
"RunProfileResult",
"RunProfile",
"RunProfileCreate",
# Run extended profile command models.
"RunExtendedProfileCommandType",
"RunExtendedProfileParams",
"RunExtendedProfileStepParams",
"RunExtendedProfileResult",
"RunExtendedProfile",
"RunExtendedProfileCreate",
"ProfileCycle",
"ProfileStep",
]
Loading

0 comments on commit 6985567

Please sign in to comment.