Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(protocol-designer): add load liquid commands #9923

Merged
merged 6 commits into from
Apr 13, 2022
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2,695 changes: 2,695 additions & 0 deletions protocol-designer/fixtures/protocol/5/multipleLiquids.json

Large diffs are not rendered by default.

77 changes: 41 additions & 36 deletions protocol-designer/src/file-data/selectors/fileCreator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { uuid } from '../../utils'
import { selectors as ingredSelectors } from '../../labware-ingred/selectors'
import { selectors as stepFormSelectors } from '../../step-forms'
import { selectors as uiLabwareSelectors } from '../../ui/labware'
import { getLoadLiquidCommands } from '../../load-file/migration/utils/getLoadLiquidCommands'
import {
DEFAULT_MM_FROM_BOTTOM_ASPIRATE,
DEFAULT_MM_FROM_BOTTOM_DISPENSE,
Expand All @@ -32,8 +33,8 @@ import type {
CreateCommand,
ProtocolFile,
} from '@opentrons/shared-data/protocol/types/schemaV6'
import { Selector } from '../../types'
import {
import type { Selector } from '../../types'
import type {
LoadLabwareCreateCommand,
LoadModuleCreateCommand,
LoadPipetteCreateCommand,
Expand Down Expand Up @@ -108,6 +109,39 @@ export const createFile: Selector<ProtocolFile> = createSelector(
const { author, description, created } = fileMetadata
const name = fileMetadata.protocolName || 'untitled'
const lastModified = fileMetadata.lastModified
// TODO: Ian 2018-07-10 allow user to save steps in JSON file, even if those
// step never have saved forms.
// (We could just export the `steps` reducer, but we've sunset it)
const savedOrderedStepIds = orderedStepIds.filter(
stepId => savedStepForms[stepId]
)
const designerApplication = {
name: 'opentrons/protocol-designer',
version: applicationVersion,
data: {
_internalAppBuildDate,
defaultValues: {
// TODO: Ian 2019-06-13 load these into redux and always get them from redux, not constants.js
// This `defaultValues` key is not yet read by anything, but is populated here for auditability
// and so that later we can do #3587 without a PD migration
aspirate_mmFromBottom: DEFAULT_MM_FROM_BOTTOM_ASPIRATE,
dispense_mmFromBottom: DEFAULT_MM_FROM_BOTTOM_DISPENSE,
touchTip_mmFromTop: DEFAULT_MM_TOUCH_TIP_OFFSET_FROM_TOP,
blowout_mmFromTop: DEFAULT_MM_BLOWOUT_OFFSET_FROM_TOP,
},
pipetteTiprackAssignments: mapValues(
pipetteEntities,
(
p: typeof pipetteEntities[keyof typeof pipetteEntities]
): string | null | undefined => p.tiprackDefURI
),
dismissedWarnings,
ingredients,
ingredLocations,
savedStepForms,
orderedStepIds: savedOrderedStepIds,
},
}

const pipettes: ProtocolFile['pipettes'] = mapValues(
initialRobotState.pipettes,
Expand Down Expand Up @@ -179,6 +213,8 @@ export const createFile: Selector<ProtocolFile> = createSelector(
return loadLabwareCommand
}
)

const loadLiquidCommands = getLoadLiquidCommands(designerApplication)
const modules: ProtocolFile['modules'] = mapValues(
moduleEntities,
(moduleEntity: ModuleEntity, moduleId: string) => ({
Expand All @@ -203,12 +239,7 @@ export const createFile: Selector<ProtocolFile> = createSelector(
return loadModuleCommand
}
)
// TODO: Ian 2018-07-10 allow user to save steps in JSON file, even if those
// step never have saved forms.
// (We could just export the `steps` reducer, but we've sunset it)
const savedOrderedStepIds = orderedStepIds.filter(
stepId => savedStepForms[stepId]
)

const labwareDefinitions = getLabwareDefinitionsInUse(
labwareEntities,
pipetteEntities,
Expand All @@ -218,7 +249,7 @@ export const createFile: Selector<ProtocolFile> = createSelector(
...loadPipetteCommands,
...loadLabwareCommands,
...loadModuleCommands,
// TODO: generate load liquid commands https://github.com/Opentrons/opentrons/issues/9702
...loadLiquidCommands,
]

const nonLoadCommands: CreateCommand[] = flatMap(
Expand All @@ -240,33 +271,7 @@ export const createFile: Selector<ProtocolFile> = createSelector(
subcategory: null,
tags: [],
},
designerApplication: {
name: 'opentrons/protocol-designer',
version: applicationVersion,
data: {
_internalAppBuildDate,
defaultValues: {
// TODO: Ian 2019-06-13 load these into redux and always get them from redux, not constants.js
// This `defaultValues` key is not yet read by anything, but is populated here for auditability
// and so that later we can do #3587 without a PD migration
aspirate_mmFromBottom: DEFAULT_MM_FROM_BOTTOM_ASPIRATE,
dispense_mmFromBottom: DEFAULT_MM_FROM_BOTTOM_DISPENSE,
touchTip_mmFromTop: DEFAULT_MM_TOUCH_TIP_OFFSET_FROM_TOP,
blowout_mmFromTop: DEFAULT_MM_BLOWOUT_OFFSET_FROM_TOP,
},
pipetteTiprackAssignments: mapValues(
pipetteEntities,
(
p: typeof pipetteEntities[keyof typeof pipetteEntities]
): string | null | undefined => p.tiprackDefURI
),
dismissedWarnings,
ingredients,
ingredLocations,
savedStepForms,
orderedStepIds: savedOrderedStepIds,
},
},
designerApplication,
robot: {
model: OT2_STANDARD_MODEL,
deckId: OT2_STANDARD_DECKID,
Expand Down
19 changes: 5 additions & 14 deletions protocol-designer/src/load-file/migration/6_0_0.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { uuid } from '../../utils'
// and labware access parameters, renames AirGap to aspirate, and removes all temporal properties from labware, pipettes,
// and module keys such as slot, mount
// and renames well to wellName
import { getLoadLiquidCommands } from './utils/getLoadLiquidCommands'
import type {
LoadPipetteCreateCommand,
LoadModuleCreateCommand,
Expand All @@ -21,18 +22,7 @@ import type {
CreateCommand,
ProtocolFile,
} from '@opentrons/shared-data/protocol/types/schemaV6'

interface DesignerApplicationData {
ingredients: Record<
string,
{
name: string
description: string | null
serialize: boolean
liquidGroupId: string
}
>
}
import type { DesignerApplicationData } from './utils/getLoadLiquidCommands'

const PD_VERSION = '6.0.0'
const SCHEMA_VERSION = 6
Expand Down Expand Up @@ -85,7 +75,7 @@ const migrateCommands = (
export const migrateFile = (
appData: ProtocolFileV5<DesignerApplicationData>
): ProtocolFile => {
const { pipettes, labware, modules, commands } = appData
const { pipettes, labware, modules, commands, designerApplication } = appData
const loadPipetteCommands: LoadPipetteCreateCommand[] = map(
pipettes,
(pipette, pipetteId) => {
Expand Down Expand Up @@ -131,6 +121,7 @@ export const migrateFile = (
}
)

const loadLiquidCommands = getLoadLiquidCommands(designerApplication)
const migratedV5Commands = migrateCommands(commands)

const liquids: ProtocolFile['liquids'] =
Expand Down Expand Up @@ -168,7 +159,7 @@ export const migrateFile = (
modules: migrateModules(appData.modules),
liquids,
commands: [
// TODO: generate load liquid commands https://github.com/Opentrons/opentrons/issues/9702
...loadLiquidCommands,
...loadPipetteCommands,
...loadModuleCommands,
...loadLabwareCommands,
Expand Down
199 changes: 199 additions & 0 deletions protocol-designer/src/load-file/migration/__tests__/6_0_0.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { migrateFile } from '../6_0_0'
import _oldProtocol from 'protocol-designer/fixtures/protocol/5/doItAllV5.json'
import _oldProtocolMultipleLiquids from 'protocol-designer/fixtures/protocol/5/multipleLiquids.json'
import type { ProtocolFile, ProtocolFileV5 } from '@opentrons/shared-data'

const oldProtocol = (_oldProtocol as unknown) as ProtocolFileV5<any>
Expand Down Expand Up @@ -140,6 +141,204 @@ describe('v6 migration', () => {
]
expect(loadLabwareCommands).toEqual(expectedLoadLabwareCommaands)
})
it('creates loadLiquid commands', () => {
const expectedLoadLiquidCommands = [
{
key: expect.any(String),
commandType: 'loadLiquid',
params: {
liquidId: '0',
labwareId:
'6114d3d0-b759-11ec-81e8-7fa12dc3e861:opentrons/opentrons_24_tuberack_eppendorf_1.5ml_safelock_snapcap/1', // this is just taken from the fixture
volumeByWell: {
A1: 222,
B1: 222,
C1: 222,
D1: 222,
A2: 222,
B2: 222,
C2: 222,
D2: 222,
},
},
},
{
key: expect.any(String),
commandType: 'loadLiquid',
params: {
liquidId: '1',
labwareId:
'6114d3d0-b759-11ec-81e8-7fa12dc3e861:opentrons/opentrons_24_tuberack_eppendorf_1.5ml_safelock_snapcap/1', // this is just taken from the fixture
volumeByWell: {
A3: 333,
B3: 333,
C3: 333,
D3: 333,
A4: 333,
B4: 333,
C4: 333,
D4: 333,
},
},
},
{
key: expect.any(String),
commandType: 'loadLiquid',
params: {
liquidId: '2',
labwareId:
'6114d3d0-b759-11ec-81e8-7fa12dc3e861:opentrons/opentrons_24_tuberack_eppendorf_1.5ml_safelock_snapcap/1', // this is just taken from the fixture
volumeByWell: {
A5: 444,
B5: 444,
C5: 444,
D5: 444,
A6: 444,
B6: 444,
C6: 444,
D6: 444,
},
},
},
{
key: expect.any(String),
commandType: 'loadLiquid',
params: {
liquidId: '0',
labwareId:
'64c66a20-b759-11ec-81e8-7fa12dc3e861:opentrons/usascientific_96_wellplate_2.4ml_deep/1', // this is just taken from the fixture
volumeByWell: {
A1: 555,
B1: 555,
C1: 555,
D1: 555,
E1: 555,
F1: 555,
G1: 555,
H1: 555,
A2: 555,
B2: 555,
C2: 555,
D2: 555,
E2: 555,
F2: 555,
G2: 555,
H2: 555,
A3: 555,
B3: 555,
C3: 555,
D3: 555,
E3: 555,
F3: 555,
G3: 555,
H3: 555,
},
},
},
{
key: expect.any(String),
commandType: 'loadLiquid',
params: {
liquidId: '1',
labwareId:
'64c66a20-b759-11ec-81e8-7fa12dc3e861:opentrons/usascientific_96_wellplate_2.4ml_deep/1', // this is just taken from the fixture
volumeByWell: {
A4: 666,
B4: 666,
C4: 666,
D4: 666,
E4: 666,
F4: 666,
G4: 666,
H4: 666,
A5: 666,
B5: 666,
C5: 666,
D5: 666,
E5: 666,
F5: 666,
G5: 666,
H5: 666,
A6: 666,
B6: 666,
C6: 666,
D6: 666,
E6: 666,
F6: 666,
G6: 666,
H6: 666,
},
},
},
{
key: expect.any(String),
commandType: 'loadLiquid',
params: {
liquidId: '2',
labwareId:
'64c66a20-b759-11ec-81e8-7fa12dc3e861:opentrons/usascientific_96_wellplate_2.4ml_deep/1', // this is just taken from the fixture
volumeByWell: {
A7: 777,
B7: 777,
C7: 777,
D7: 777,
E7: 777,
F7: 777,
G7: 777,
H7: 777,
A8: 777,
B8: 777,
C8: 777,
D8: 777,
E8: 777,
F8: 777,
G8: 777,
H8: 777,
A9: 777,
B9: 777,
C9: 777,
D9: 777,
E9: 777,
F9: 777,
G9: 777,
H9: 777,
A10: 777,
B10: 777,
C10: 777,
D10: 777,
E10: 777,
F10: 777,
G10: 777,
H10: 777,
A11: 777,
B11: 777,
C11: 777,
D11: 777,
E11: 777,
F11: 777,
G11: 777,
H11: 777,
A12: 777,
B12: 777,
C12: 777,
D12: 777,
E12: 777,
F12: 777,
G12: 777,
H12: 777,
},
},
},
]

const migratedLiquidsFile = migrateFile(_oldProtocolMultipleLiquids as any)
const loadLiquidCommands = migratedLiquidsFile.commands.filter(
command => command.commandType === 'loadLiquid'
)
expect(loadLiquidCommands).toEqual(
expect.arrayContaining(expectedLoadLiquidCommands)
)
})
it('replaces air gap commands with aspirate commands', () => {
const expectedConvertedAirgapCommands = [
{
Expand Down
Loading