Skip to content

Commit

Permalink
feat(app): Plate reader in LPC and CommandText, filter out plate read…
Browse files Browse the repository at this point in the history
…er lid as labware (#16489)

fix PLAT-483, PLAT-525, PLAT-526, PLAT-547, RQA-3310
  • Loading branch information
smb2268 authored Oct 15, 2024
1 parent f61ab98 commit d9b0e23
Show file tree
Hide file tree
Showing 18 changed files with 206 additions and 34 deletions.
11 changes: 9 additions & 2 deletions app/src/assets/localization/en/protocol_command_text.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
{
"absorbance_reader_open_lid": "Opening Absorbance Reader lid",
"absorbance_reader_close_lid": "Closing Absorbance Reader lid",
"absorbance_reader_initialize": "Initializing Absorbance Reader to perform {{mode}} measurement at {{wavelengths}}",
"absorbance_reader_read": "Reading plate in Absorbance Reader",
"adapter_in_mod_in_slot": "{{adapter}} on {{module}} in {{slot}}",
"adapter_in_slot": "{{adapter}} in {{slot}}",
"aspirate": "Aspirating {{volume}} µL from well {{well_name}} of {{labware}} in {{labware_location}} at {{flow_rate}} µL/sec",
Expand Down Expand Up @@ -49,6 +53,7 @@
"move_to_coordinates": "Moving to (X: {{x}}, Y: {{y}}, Z: {{z}})",
"move_to_slot": "Moving to Slot {{slot_name}}",
"move_to_well": "Moving to well {{well_name}} of {{labware}} in {{labware_location}}",
"multiple": "multiple",
"notes": "notes",
"off_deck": "off deck",
"offdeck": "offdeck",
Expand All @@ -66,9 +71,10 @@
"setting_temperature_module_temp": "Setting Temperature Module to {{temp}} (rounded to nearest integer)",
"setting_thermocycler_block_temp": "Setting Thermocycler block temperature to {{temp}} with hold time of {{hold_time_seconds}} seconds after target reached",
"setting_thermocycler_lid_temp": "Setting Thermocycler lid temperature to {{temp}}",
"single": "single",
"slot": "Slot {{slot_name}}",
"turning_rail_lights_off": "Turning rail lights off",
"turning_rail_lights_on": "Turning rail lights on",
"slot": "Slot {{slot_name}}",
"target_temperature": "target temperature",
"tc_awaiting_for_duration": "Waiting for Thermocycler profile to complete",
"tc_run_profile_steps": "Temperature: {{celsius}}°C, hold time: {{duration}}",
Expand All @@ -84,5 +90,6 @@
"waiting_for_tc_block_to_reach": "Waiting for Thermocycler block to reach target temperature and holding for specified time",
"waiting_for_tc_lid_to_reach": "Waiting for Thermocycler lid to reach target temperature",
"waiting_to_reach_temp_module": "Waiting for Temperature Module to reach {{temp}}",
"waste_chute": "Waste Chute"
"waste_chute": "Waste Chute",
"with_reference_of": "with reference of {{wavelength}} nm"
}
12 changes: 11 additions & 1 deletion app/src/molecules/Command/hooks/useCommandTextString/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,17 @@ export function useCommandTextString(
command,
}),
}

case 'absorbanceReader/openLid':
case 'absorbanceReader/closeLid':
case 'absorbanceReader/initialize':
case 'absorbanceReader/read':
return {
kind: 'generic',
commandText: utils.getAbsorbanceReaderCommandText({
...fullParams,
command,
}),
}
case 'thermocycler/runProfile':
return utils.getTCRunProfileCommandText({ ...fullParams, command })

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import type {
AbsorbanceReaderOpenLidRunTimeCommand,
AbsorbanceReaderCloseLidRunTimeCommand,
AbsorbanceReaderInitializeRunTimeCommand,
AbsorbanceReaderReadRunTimeCommand,
RunTimeCommand,
} from '@opentrons/shared-data'
import type { HandlesCommands } from './types'

export type AbsorbanceCreateCommand =
| AbsorbanceReaderOpenLidRunTimeCommand
| AbsorbanceReaderCloseLidRunTimeCommand
| AbsorbanceReaderInitializeRunTimeCommand
| AbsorbanceReaderReadRunTimeCommand

const KEYS_BY_COMMAND_TYPE: {
[commandType in AbsorbanceCreateCommand['commandType']]: string
} = {
'absorbanceReader/openLid': 'absorbance_reader_open_lid',
'absorbanceReader/closeLid': 'absorbance_reader_close_lid',
'absorbanceReader/initialize': 'absorbance_reader_initialize',
'absorbanceReader/read': 'absorbance_reader_read',
}

type HandledCommands = Extract<
RunTimeCommand,
{ commandType: keyof typeof KEYS_BY_COMMAND_TYPE }
>

type GetAbsorbanceReaderCommandText = HandlesCommands<HandledCommands>

export const getAbsorbanceReaderCommandText = ({
command,
t,
}: GetAbsorbanceReaderCommandText): string => {
if (command.commandType === 'absorbanceReader/initialize') {
const wavelengths = command.params.sampleWavelengths.join(' nm, ') + ` nm`
const mode =
command.params.measureMode === 'multi' ? t('multiple') : t('single')

return `${t('absorbance_reader_initialize', {
mode,
wavelengths,
})} ${
command.params.referenceWavelength != null
? t('with_reference_of', {
wavelength: command.params.referenceWavelength,
})
: ''
}`
}
return t(KEYS_BY_COMMAND_TYPE[command.commandType])
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,4 @@ export { getUnknownCommandText } from './getUnknownCommandText'
export { getPipettingCommandText } from './getPipettingCommandText'
export { getLiquidProbeCommandText } from './getLiquidProbeCommandText'
export { getRailLightsCommandText } from './getRailLightsCommandText'
export { getAbsorbanceReaderCommandText } from './getAbsorbanceReaderCommandText'
5 changes: 4 additions & 1 deletion app/src/organisms/Desktop/ProtocolDetails/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ import {
parseInitialLoadedLabwareBySlot,
parseInitialLoadedModulesBySlot,
parseInitialPipetteNamesByMount,
NON_USER_ADDRESSABLE_LABWARE,
} from '@opentrons/shared-data'

import { getTopPortalEl } from '/app/App/portal'
Expand Down Expand Up @@ -284,7 +285,9 @@ export function ProtocolDetails(
: []
),
}).filter(
labware => labware.result?.definition?.parameters?.format !== 'trash'
labware =>
labware.result?.definition?.parameters?.format !== 'trash' &&
!NON_USER_ADDRESSABLE_LABWARE.includes(labware?.params?.loadName)
)
: []

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import {
getModuleType,
HEATERSHAKER_MODULE_TYPE,
THERMOCYCLER_MODULE_TYPE,
ABSORBANCE_READER_TYPE,
NON_USER_ADDRESSABLE_LABWARE,
} from '@opentrons/shared-data'

import type {
Expand All @@ -13,6 +15,7 @@ import type {
RunTimeCommand,
SetupRunTimeCommand,
TCOpenLidCreateCommand,
AbsorbanceReaderOpenLidCreateCommand,
} from '@opentrons/shared-data'

type LPCPrepCommand =
Expand All @@ -21,6 +24,7 @@ type LPCPrepCommand =
| TCOpenLidCreateCommand
| HeaterShakerDeactivateShakerCreateCommand
| HeaterShakerCloseLatchCreateCommand
| AbsorbanceReaderOpenLidCreateCommand

export function getPrepCommands(
protocolData: CompletedProtocolAnalysis
Expand All @@ -45,7 +49,8 @@ export function getPrepCommands(
return [...acc, loadWithPipetteId]
} else if (
command.commandType === 'loadLabware' &&
command.result?.labwareId != null
command.result?.labwareId != null &&
!NON_USER_ADDRESSABLE_LABWARE.includes(command.params.loadName)
) {
// load all labware off-deck so that LPC can move them on individually later
return [
Expand Down Expand Up @@ -97,6 +102,26 @@ export function getPrepCommands(
[]
)

const AbsorbanceCommands = protocolData.modules.reduce<LPCPrepCommand[]>(
(acc, module) => {
if (getModuleType(module.model) === ABSORBANCE_READER_TYPE) {
return [
...acc,
{
commandType: 'home',
params: {},
},
{
commandType: 'absorbanceReader/openLid',
params: { moduleId: module.id },
},
]
}
return acc
},
[]
)

const HSCommands = protocolData.modules.reduce<
HeaterShakerCloseLatchCreateCommand[]
>((acc, module) => {
Expand All @@ -116,7 +141,13 @@ export function getPrepCommands(
params: {},
}
// prepCommands will be run when a user starts LPC
return [...loadCommands, ...TCCommands, ...HSCommands, homeCommand]
return [
...loadCommands,
...TCCommands,
...AbsorbanceCommands,
...HSCommands,
homeCommand,
]
}

function isLoadCommand(
Expand Down
14 changes: 4 additions & 10 deletions app/src/organisms/LabwarePositionCheck/useLaunchLPC.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,6 @@ import { getLabwareDefinitionsFromCommands } from '/app/molecules/Command/utils/

import type { RobotType } from '@opentrons/shared-data'

const filteredLabware = [
'opentrons_tough_pcr_auto_sealing_lid',
'opentrons_flex_lid_absorbance_plate_reader_module',
]

export function useLaunchLPC(
runId: string,
robotType: RobotType,
Expand Down Expand Up @@ -67,11 +62,10 @@ export function useLaunchLPC(
getLabwareDefinitionsFromCommands(
mostRecentAnalysis?.commands ?? []
).map(def => {
if (!filteredLabware.includes(def.parameters.loadName))
createLabwareDefinition({
maintenanceRunId: maintenanceRun?.data?.id,
labwareDef: def,
})
createLabwareDefinition({
maintenanceRunId: maintenanceRun?.data?.id,
labwareDef: def,
})
})
).then(() => {
setMaintenanceRunId(maintenanceRun.data.id)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,10 @@ function getAllCheckSectionSteps(
const labwareDef = labwareDefinitions.find(
def => getLabwareDefURI(def) === labwareLocationCombo.definitionUri
)
if ((labwareDef?.allowedRoles ?? []).includes('adapter')) {
if (
(labwareDef?.allowedRoles ?? []).includes('adapter') ||
(labwareDef?.allowedRoles ?? []).includes('lid')
) {
return acc
}
// remove duplicate definitionUri in same location
Expand All @@ -73,12 +76,7 @@ function getAllCheckSectionSteps(
[]
)

// HACK: Remove LPC for plate reader to unblock science.
const filteredLabwareLocations = labwareLocations.filter(labware => {
return labware.location?.moduleModel !== 'absorbanceReaderV1'
})

return filteredLabwareLocations.map(
return labwareLocations.map(
({ location, labwareId, moduleId, adapterId, definitionUri }) => ({
section: SECTIONS.CHECK_POSITIONS,
labwareId: labwareId,
Expand Down
2 changes: 1 addition & 1 deletion app/src/organisms/ModuleCard/AbsorbanceReaderData.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ export const AbsorbanceReaderData = (
data-testid="abs_module_data"
>
{t('abs_reader_lid_status', {
status: moduleData.lidStatus === 'on' ? 'open' : 'closed',
status: moduleData.lidStatus === 'on' ? 'closed' : 'open',
})}
</StyledText>
</>
Expand Down
4 changes: 3 additions & 1 deletion app/src/transformations/analysis/getProtocolModulesInfo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {
getModuleDef2,
getLoadedLabwareDefinitionsByUri,
getPositionFromSlotId,
NON_USER_ADDRESSABLE_LABWARE,
} from '@opentrons/shared-data'
import { getModuleInitialLoadInfo } from '../commands'
import type {
Expand Down Expand Up @@ -38,7 +39,8 @@ export const getProtocolModulesInfo = (
protocolData.commands
.filter(
(command): command is LoadLabwareRunTimeCommand =>
command.commandType === 'loadLabware'
command.commandType === 'loadLabware' &&
!NON_USER_ADDRESSABLE_LABWARE.includes(command.params.loadName)
)
.find(
(command: LoadLabwareRunTimeCommand) =>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import partition from 'lodash/partition'
import { getLabwareDisplayName } from '@opentrons/shared-data'
import {
getLabwareDisplayName,
NON_USER_ADDRESSABLE_LABWARE,
} from '@opentrons/shared-data'

import type {
LabwareDefinition2,
Expand Down Expand Up @@ -43,7 +46,8 @@ export function getLabwareSetupItemGroups(
commands.reduce<LabwareSetupItem[]>((acc, c) => {
if (
c.commandType === 'loadLabware' &&
c.result?.definition?.metadata?.displayCategory !== 'trash'
c.result?.definition?.metadata?.displayCategory !== 'trash' &&
!NON_USER_ADDRESSABLE_LABWARE.includes(c.params?.loadName)
) {
const { location, displayName } = c.params
const { definition } = c.result ?? {}
Expand Down
5 changes: 4 additions & 1 deletion components/src/hardware-sim/BaseDeck/BaseDeck.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,10 @@ export function BaseDeck(props: BaseDeckProps): JSX.Element {
color={COLORS.black90}
show4thColumn={
stagingAreaFixtures.length > 0 ||
wasteChuteStagingAreaFixtures.length > 0
wasteChuteStagingAreaFixtures.length > 0 ||
modulesOnDeck.findIndex(
module => module.moduleModel === 'absorbanceReaderV1'
) >= 0
}
/>
) : null}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ interface AbsorbanceReaderFixtureProps {
selected?: boolean
}

const ABSORBANCE_READER_FIXTURE_DISPLAY_NAME = 'Absorbance Reader'
const ABSORBANCE_READER_FIXTURE_DISPLAY_NAME = 'Absorbance'

export function AbsorbanceReaderFixture(
props: AbsorbanceReaderFixtureProps
Expand Down
3 changes: 2 additions & 1 deletion components/src/hardware-sim/DeckConfigurator/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -275,7 +275,8 @@ export function DeckConfigurator(props: DeckConfiguratorProps): JSX.Element {
show4thColumn={
stagingAreaFixtures.length > 0 ||
wasteChuteStagingAreaFixtures.length > 0 ||
magneticBlockStagingAreaFixtures.length > 0
magneticBlockStagingAreaFixtures.length > 0 ||
absorbanceReaderFixtures.length > 0
}
/>
{children}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import {
SPAN7_8_10_11_SLOT,
getModuleDef2,
getLoadedLabwareDefinitionsByUri,
NON_USER_ADDRESSABLE_LABWARE,
} from '@opentrons/shared-data'
import type {
CompletedProtocolAnalysis,
Expand Down Expand Up @@ -36,7 +37,8 @@ export const getModulesInSlots = (
commands
.filter(
(command): command is LoadLabwareRunTimeCommand =>
command.commandType === 'loadLabware'
command.commandType === 'loadLabware' &&
!NON_USER_ADDRESSABLE_LABWARE.includes(command.params.loadName)
)
.find(
(command: LoadLabwareRunTimeCommand) =>
Expand Down
Loading

0 comments on commit d9b0e23

Please sign in to comment.