From 1f47e0cfd8650f83583eb243253f9e534ba16708 Mon Sep 17 00:00:00 2001 From: Andy Sigler Date: Tue, 12 Sep 2023 12:37:57 -0400 Subject: [PATCH 01/13] hardware-testing changes to get low-volume pipetting working (#13523) --- .../gravimetric/liquid_class/pipetting.py | 26 ++++++++++++------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/hardware-testing/hardware_testing/gravimetric/liquid_class/pipetting.py b/hardware-testing/hardware_testing/gravimetric/liquid_class/pipetting.py index 7f7c76fd4b5..a18bd7701de 100644 --- a/hardware-testing/hardware_testing/gravimetric/liquid_class/pipetting.py +++ b/hardware-testing/hardware_testing/gravimetric/liquid_class/pipetting.py @@ -176,14 +176,16 @@ def _pipette_with_liquid_settings( # FIXME: stop using hwapi, and get those functions into core software hw_api = ctx._core.get_hardware() hw_mount = OT3Mount.LEFT if pipette.mount == "left" else OT3Mount.RIGHT + hw_pipette = hw_api.hardware_pipettes[hw_mount.to_mount()] _check_aspirate_dispense_args(aspirate, dispense) def _dispense_with_added_blow_out() -> None: - # dispense all liquid, plus some air by calling `pipette.blow_out(location, volume)` - # FIXME: this is a hack, until there's an equivalent `pipette.blow_out(location, volume)` + # dispense all liquid, plus some air + # FIXME: push-out is not supported in Legacy core, so here + # we again use the hardware controller hw_api = ctx._core.get_hardware() hw_mount = OT3Mount.LEFT if pipette.mount == "left" else OT3Mount.RIGHT - hw_api.blow_out(hw_mount, liquid_class.dispense.blow_out_submerged) + hw_api.dispense(hw_mount, push_out=liquid_class.dispense.blow_out_submerged) # ASPIRATE/DISPENSE SEQUENCE HAS THREE PHASES: # 1. APPROACH @@ -211,14 +213,18 @@ def _dispense_with_added_blow_out() -> None: # CREATE CALLBACKS FOR EACH PHASE def _aspirate_on_approach() -> None: + if hw_pipette.current_volume > 0: + print( + "WARNING: removing trailing air-gap from pipette, " + "this should only happen during blank trials" + ) + hw_api.dispense(hw_mount) + hw_api.configure_for_volume(hw_mount, aspirate if aspirate else dispense) + hw_api.prepare_for_aspirate(hw_mount) if liquid_class.aspirate.leading_air_gap > 0: pipette.aspirate(liquid_class.aspirate.leading_air_gap) def _aspirate_on_submerge() -> None: - # TODO: re-implement mixing once we have a real use for it - # and once the rest of the script settles down - if mix: - raise NotImplementedError("mixing is not currently implemented") # aspirate specified volume callbacks.on_aspirating() pipette.aspirate(aspirate) @@ -308,8 +314,9 @@ def aspirate_with_liquid_class( touch_tip: bool = False, ) -> None: """Aspirate with liquid class.""" + pip_size = 50 if "50" in pipette.name else 1000 liquid_class = get_liquid_class( - int(pipette.max_volume), pipette.channels, tip_volume, int(aspirate_volume) + pip_size, pipette.channels, tip_volume, int(aspirate_volume) ) _pipette_with_liquid_settings( ctx, @@ -345,8 +352,9 @@ def dispense_with_liquid_class( touch_tip: bool = False, ) -> None: """Dispense with liquid class.""" + pip_size = 50 if "50" in pipette.name else 1000 liquid_class = get_liquid_class( - int(pipette.max_volume), pipette.channels, tip_volume, int(dispense_volume) + pip_size, pipette.channels, tip_volume, int(dispense_volume) ) _pipette_with_liquid_settings( ctx, From f4b5eed17dd94c019b7a3dbfac464ef152a722ef Mon Sep 17 00:00:00 2001 From: Jethary Date: Tue, 12 Sep 2023 08:56:22 -0400 Subject: [PATCH 02/13] add PD support for low volume --- .../en/protocol_command_text.json | 1 + app/src/organisms/CommandText/index.tsx | 8 ++++ .../makeSingleEditFieldProps.test.ts | 1 + .../fields/makeSingleEditFieldProps.ts | 6 ++- .../forms/MoveLiquidForm/SourceDestFields.tsx | 45 ++++++++++++------- .../forms/__tests__/SourceDestFields.test.tsx | 31 ++++++++++++- .../src/components/StepEditForm/index.tsx | 5 ++- protocol-designer/src/form-types.ts | 1 + .../src/load-file/migration/7_0_0.ts | 23 +++++++++- .../src/localization/en/form.json | 1 + .../src/localization/en/tooltip.json | 3 +- .../test/createPresavedStepForm.test.ts | 1 + .../formLevel/getDefaultsForStepType.ts | 1 + .../getDisabledFieldsMoveLiquidForm.ts | 16 ++++++- .../formLevel/getDisabledFields/index.ts | 11 +++-- .../stepFormToArgs/moveLiquidFormToArgs.ts | 1 + .../test/getDefaultsForStepType.test.ts | 1 + .../src/ui/steps/test/selectors.test.ts | 8 ++++ .../types/schemaV7/command/pipetting.ts | 22 ++++++++- .../src/__tests__/configureForVolume.test.ts | 38 ++++++++++++++++ .../atomic/configureForVolume.ts | 35 +++++++++++++++ .../src/commandCreators/atomic/dispense.ts | 7 ++- .../src/commandCreators/compound/transfer.ts | 18 ++++++++ .../src/getNextRobotStateAndWarnings/index.ts | 1 + step-generation/src/types.ts | 2 + 25 files changed, 259 insertions(+), 28 deletions(-) create mode 100644 step-generation/src/__tests__/configureForVolume.test.ts create mode 100644 step-generation/src/commandCreators/atomic/configureForVolume.ts diff --git a/app/src/assets/localization/en/protocol_command_text.json b/app/src/assets/localization/en/protocol_command_text.json index f026cd6e865..7c454788c09 100644 --- a/app/src/assets/localization/en/protocol_command_text.json +++ b/app/src/assets/localization/en/protocol_command_text.json @@ -1,6 +1,7 @@ { "aspirate": "Aspirating {{volume}} µL from well {{well_name}} of {{labware}} in {{labware_location}} at {{flow_rate}} µL/sec", "blowout": "Blowing out at well {{well_name}} of {{labware}} in {{labware_location}} at {{flow_rate}} µL/sec", + "configure_for_volume": "Configure {{volume}} µL for aspirate", "closing_tc_lid": "Closing Thermocycler lid", "comment": "Comment", "confirm_and_resume": "Confirm and resume", diff --git a/app/src/organisms/CommandText/index.tsx b/app/src/organisms/CommandText/index.tsx index 522e794c12e..42d8aad59ea 100644 --- a/app/src/organisms/CommandText/index.tsx +++ b/app/src/organisms/CommandText/index.tsx @@ -139,6 +139,14 @@ export function CommandText(props: Props): JSX.Element | null { ) } + case 'configureForVolume': { + const { volume } = command.params + return ( + + {t('configure_for_volume', { volume })} + + ) + } case 'touchTip': case 'home': case 'savePosition': diff --git a/protocol-designer/src/components/StepEditForm/fields/__tests__/makeSingleEditFieldProps.test.ts b/protocol-designer/src/components/StepEditForm/fields/__tests__/makeSingleEditFieldProps.test.ts index bb998523130..00389498caf 100644 --- a/protocol-designer/src/components/StepEditForm/fields/__tests__/makeSingleEditFieldProps.test.ts +++ b/protocol-designer/src/components/StepEditForm/fields/__tests__/makeSingleEditFieldProps.test.ts @@ -101,6 +101,7 @@ describe('makeSingleEditFieldProps', () => { const result = makeSingleEditFieldProps( focusHandlers, formData, + {}, handleChangeFormInput ) expect(result).toEqual({ diff --git a/protocol-designer/src/components/StepEditForm/fields/makeSingleEditFieldProps.ts b/protocol-designer/src/components/StepEditForm/fields/makeSingleEditFieldProps.ts index 7daf2a4abca..2d87235ee49 100644 --- a/protocol-designer/src/components/StepEditForm/fields/makeSingleEditFieldProps.ts +++ b/protocol-designer/src/components/StepEditForm/fields/makeSingleEditFieldProps.ts @@ -9,6 +9,7 @@ import { } from '../utils' import { StepFieldName, FormData } from '../../../form-types' import { FieldProps, FieldPropsByName, FocusHandlers } from '../types' +import { PipetteEntities } from '@opentrons/step-generation' interface ShowFieldErrorParams { name: StepFieldName focusedField: StepFieldName | null @@ -23,6 +24,7 @@ export const showFieldErrors = ({ export const makeSingleEditFieldProps = ( focusHandlers: FocusHandlers, formData: FormData, + pipetteEntities: PipetteEntities, handleChangeFormInput: (name: string, value: unknown) => void ): FieldPropsByName => { const { dirtyFields, blur, focusedField, focus } = focusHandlers @@ -30,7 +32,9 @@ export const makeSingleEditFieldProps = ( getDefaultsForStepType(formData.stepType) ) return fieldNames.reduce((acc, name) => { - const disabled = formData ? getDisabledFields(formData).has(name) : false + const disabled = formData + ? getDisabledFields(formData, pipetteEntities).has(name) + : false const value = formData ? formData[name] : null const showErrors = showFieldErrors({ name, diff --git a/protocol-designer/src/components/StepEditForm/forms/MoveLiquidForm/SourceDestFields.tsx b/protocol-designer/src/components/StepEditForm/forms/MoveLiquidForm/SourceDestFields.tsx index 127afbda34c..33ee245d82f 100644 --- a/protocol-designer/src/components/StepEditForm/forms/MoveLiquidForm/SourceDestFields.tsx +++ b/protocol-designer/src/components/StepEditForm/forms/MoveLiquidForm/SourceDestFields.tsx @@ -1,6 +1,9 @@ import * as React from 'react' +import { useSelector } from 'react-redux' import { i18n } from '../../../../localization' +import { FLEX_ROBOT_TYPE } from '@opentrons/shared-data' +import { getRobotType } from '../../../../file-data/selectors' import { BlowoutLocationField, CheckboxRowField, @@ -37,6 +40,7 @@ const makeAddFieldNamePrefix = (prefix: string) => ( export const SourceDestFields = (props: SourceDestFieldsProps): JSX.Element => { const { className, formData, prefix, propsForFields, allLabware } = props + const robotType = useSelector(getRobotType) const addFieldNamePrefix = makeAddFieldNamePrefix(prefix) const getDelayFields = (): JSX.Element => ( @@ -156,22 +160,31 @@ export const SourceDestFields = (props: SourceDestFieldsProps): JSX.Element => { /> - {prefix === 'dispense' && ( - - - - )} + {prefix === 'dispense' ? ( + <> + + + + {robotType === FLEX_ROBOT_TYPE ? ( + + ) : null} + + ) : null} +const mockGetRobotType = getRobotType as jest.MockedFunction< + typeof getRobotType +> jest.mock('../../fields/', () => { const actualFields = jest.requireActual('../../fields') @@ -201,6 +210,7 @@ describe('SourceDestFields', () => { getUnsavedFormMock.mockReturnValue({ stepType: 'moveLiquid', } as FormData) + mockGetRobotType.mockReturnValue(OT2_ROBOT_TYPE) }) const render = (props: React.ComponentProps) => @@ -247,7 +257,7 @@ describe('SourceDestFields', () => { beforeEach(() => { props = { ...props, prefix: 'dispense' } }) - it('should render the correct checkboxes', () => { + it('should render the correct checkboxes for an OT-2', () => { const wrapper = render(props) const checkboxes = wrapper.find(CheckboxRowField) @@ -262,6 +272,23 @@ describe('SourceDestFields', () => { expect(checkboxes.at(2).prop('name')).toBe('blowout_checkbox') expect(checkboxes.at(3).prop('name')).toBe('dispense_airGap_checkbox') }) + it('should render the correct checkboxes for a flex', () => { + mockGetRobotType.mockReturnValue(FLEX_ROBOT_TYPE) + const wrapper = render(props) + const checkboxes = wrapper.find(CheckboxRowField) + + const delayFields = wrapper.find(DelayFields) + expect(delayFields.props()).toMatchObject({ + checkboxFieldName: 'dispense_delay_checkbox', + secondsFieldName: 'dispense_delay_seconds', + tipPositionFieldName: 'dispense_delay_mmFromBottom', + }) + expect(checkboxes.at(0).prop('name')).toBe('dispense_mix_checkbox') + expect(checkboxes.at(1).prop('name')).toBe('dispense_touchTip_checkbox') + expect(checkboxes.at(2).prop('name')).toBe('blowout_checkbox') + expect(checkboxes.at(3).prop('name')).toBe('dispense_pushOut') + expect(checkboxes.at(4).prop('name')).toBe('dispense_airGap_checkbox') + }) it('should render a well order field', () => { const wrapper = render(props) const wellOrderField = wrapper.find(WellOrderField) diff --git a/protocol-designer/src/components/StepEditForm/index.tsx b/protocol-designer/src/components/StepEditForm/index.tsx index d4c60961d6a..966e86c2996 100644 --- a/protocol-designer/src/components/StepEditForm/index.tsx +++ b/protocol-designer/src/components/StepEditForm/index.tsx @@ -1,6 +1,6 @@ import { useConditionalConfirm } from '@opentrons/components' import * as React from 'react' -import { connect } from 'react-redux' +import { connect, useSelector } from 'react-redux' import { actions } from '../../steplist' import { actions as stepsActions } from '../../ui/steps' import { resetScrollElements } from '../../ui/steps/utils' @@ -19,6 +19,7 @@ import { StepEditFormComponent } from './StepEditFormComponent' import { getDirtyFields } from './utils' import { BaseState, ThunkDispatch } from '../../types' import { FormData, StepFieldName, StepIdType } from '../../form-types' +import { getPipetteEntities } from '../../step-forms/selectors' interface SP { canSave: boolean @@ -64,6 +65,7 @@ const StepEditFormManager = ( const [dirtyFields, setDirtyFields] = React.useState( getDirtyFields(isNewStep, formData) ) + const pipetteEntities = useSelector(getPipetteEntities) const toggleMoreOptionsModal = (): void => { resetScrollElements() @@ -135,6 +137,7 @@ const StepEditFormManager = ( const propsForFields = makeSingleEditFieldProps( focusHandlers, formData, + pipetteEntities, handleChangeFormInput ) let handleSave = saveStepForm diff --git a/protocol-designer/src/form-types.ts b/protocol-designer/src/form-types.ts index c6ffab1b7cf..0d98134bb7a 100644 --- a/protocol-designer/src/form-types.ts +++ b/protocol-designer/src/form-types.ts @@ -211,6 +211,7 @@ export interface HydratedMoveLiquidFormData { dispense_mix_checkbox: boolean dispense_mix_volume: number | null | undefined dispense_mix_times: number | null | undefined + dispense_pushOut: boolean disposalVolume_checkbox: boolean disposalVolume_volume: number | null | undefined blowout_checkbox: boolean diff --git a/protocol-designer/src/load-file/migration/7_0_0.ts b/protocol-designer/src/load-file/migration/7_0_0.ts index 026abbcf5fc..4057c2a5194 100644 --- a/protocol-designer/src/load-file/migration/7_0_0.ts +++ b/protocol-designer/src/load-file/migration/7_0_0.ts @@ -1,3 +1,4 @@ +import mapValues from 'lodash/mapValues' import { uuid } from '../../utils' import { getOnlyLatestDefs } from '../../labware-defs' import { INITIAL_DECK_SETUP_STEP_ID } from '../../constants' @@ -252,6 +253,26 @@ export const migrateFile = ( } const newLabwareIngreds = getNewLabwareIngreds(ingredLocations) + const migrateSavedStepForms = ( + savedStepForms: Record + ): Record => { + return mapValues(savedStepForms, stepForm => { + if (stepForm.stepType === 'moveLiquid') { + return { + ...stepForm, + dispense_pushOut: false, + } + } + return stepForm + }) + } + const filteredavedStepForms = Object.fromEntries( + Object.entries( + appData.designerApplication?.data?.savedStepForms ?? {} + ).filter(([key, value]) => key !== INITIAL_DECK_SETUP_STEP_ID) + ) + const newFilteredavedStepForms = migrateSavedStepForms(filteredavedStepForms) + return { ...rest, designerApplication: { @@ -263,7 +284,6 @@ export const migrateFile = ( ...newLabwareIngreds, }, savedStepForms: { - ...appData.designerApplication?.data?.savedStepForms, [INITIAL_DECK_SETUP_STEP_ID]: { ...appData.designerApplication?.data?.savedStepForms[ INITIAL_DECK_SETUP_STEP_ID @@ -272,6 +292,7 @@ export const migrateFile = ( ...newLabwareLocationUpdate, }, }, + ...newFilteredavedStepForms, }, }, }, diff --git a/protocol-designer/src/localization/en/form.json b/protocol-designer/src/localization/en/form.json index d7fc7289fa4..ce56e8ff720 100644 --- a/protocol-designer/src/localization/en/form.json +++ b/protocol-designer/src/localization/en/form.json @@ -49,6 +49,7 @@ }, "field": { "airGap": { "label": "air gap" }, + "pushOut": { "label": "push out" }, "blowout": { "label": "blowout" }, "change_tip": { "label": "change tip", diff --git a/protocol-designer/src/localization/en/tooltip.json b/protocol-designer/src/localization/en/tooltip.json index 0ac80ec523e..727702fa292 100644 --- a/protocol-designer/src/localization/en/tooltip.json +++ b/protocol-designer/src/localization/en/tooltip.json @@ -65,7 +65,8 @@ "moveLiquid": { "disabled": { "$generic": "Incompatible with current path", - "blowout_checkbox": "Redundant with disposal volume" + "blowout_checkbox": "Redundant with disposal volume", + "dispense_pushOut": "Not available unless dispensing 1µL or less" } }, "moveLabware": { diff --git a/protocol-designer/src/step-forms/test/createPresavedStepForm.test.ts b/protocol-designer/src/step-forms/test/createPresavedStepForm.test.ts index 9c7b01612d8..7436d3aa61b 100644 --- a/protocol-designer/src/step-forms/test/createPresavedStepForm.test.ts +++ b/protocol-designer/src/step-forms/test/createPresavedStepForm.test.ts @@ -167,6 +167,7 @@ describe('createPresavedStepForm', () => { dispense_wells: [], disposalVolume_checkbox: true, disposalVolume_volume: '1', + dispense_pushOut: false, path: 'single', preWetTip: false, stepDetails: '', diff --git a/protocol-designer/src/steplist/formLevel/getDefaultsForStepType.ts b/protocol-designer/src/steplist/formLevel/getDefaultsForStepType.ts index ba75ab88974..88c22109173 100644 --- a/protocol-designer/src/steplist/formLevel/getDefaultsForStepType.ts +++ b/protocol-designer/src/steplist/formLevel/getDefaultsForStepType.ts @@ -66,6 +66,7 @@ export function getDefaultsForStepType( dispense_mmFromBottom: null, dispense_touchTip_checkbox: false, dispense_touchTip_mmFromBottom: null, + dispense_pushOut: false, disposalVolume_checkbox: false, disposalVolume_volume: null, blowout_checkbox: false, diff --git a/protocol-designer/src/steplist/formLevel/getDisabledFields/getDisabledFieldsMoveLiquidForm.ts b/protocol-designer/src/steplist/formLevel/getDisabledFields/getDisabledFieldsMoveLiquidForm.ts index e45ad3d4672..59a603e40fa 100644 --- a/protocol-designer/src/steplist/formLevel/getDisabledFields/getDisabledFieldsMoveLiquidForm.ts +++ b/protocol-designer/src/steplist/formLevel/getDisabledFields/getDisabledFieldsMoveLiquidForm.ts @@ -1,11 +1,21 @@ +import { PipetteEntities } from '@opentrons/step-generation' import { FormData } from '../../../form-types' // NOTE: expects that '_checkbox' fields are implemented so that // when checkbox is disabled, its dependent fields are hidden export function getDisabledFieldsMoveLiquidForm( - rawForm: FormData // TODO IMMEDIATELY use raw form type instead of FormData + rawForm: FormData, // TODO IMMEDIATELY use raw form type instead of FormData + pipetteEntities: PipetteEntities ): Set { const disabled: Set = new Set() const prefixes = ['aspirate', 'dispense'] + const pipetteSelected = + rawForm.pipette != null + ? pipetteEntities[String(rawForm.pipette)].name + : null + const pushOutAllowed = + Number(rawForm.volume) <= 1 && + (pipetteSelected === 'p50_single_flex' || + pipetteSelected === 'p50_multi_flex') if (rawForm.path === 'multiAspirate') { disabled.add('aspirate_mix_checkbox') @@ -25,5 +35,9 @@ export function getDisabledFieldsMoveLiquidForm( disabled.add(prefix + '_wells') } }) + + if (!pushOutAllowed) { + disabled.add('dispense_pushOut') + } return disabled } diff --git a/protocol-designer/src/steplist/formLevel/getDisabledFields/index.ts b/protocol-designer/src/steplist/formLevel/getDisabledFields/index.ts index 0454209b3a7..0e3a1a90f04 100644 --- a/protocol-designer/src/steplist/formLevel/getDisabledFields/index.ts +++ b/protocol-designer/src/steplist/formLevel/getDisabledFields/index.ts @@ -3,11 +3,15 @@ import { getDisabledFieldsMoveLiquidForm } from './getDisabledFieldsMoveLiquidFo import { getDisabledFieldsMixForm } from './getDisabledFieldsMixForm' import { getDisabledFieldsHeaterShaker } from './getDisabledFieldsHeaterShaker' import { FormData } from '../../../form-types' +import { PipetteEntities } from '@opentrons/step-generation' -function _getDisabledFields(rawForm: FormData): Set { +function _getDisabledFields( + rawForm: FormData, + pipetteEntities: PipetteEntities +): Set { switch (rawForm.stepType) { case 'moveLiquid': - return getDisabledFieldsMoveLiquidForm(rawForm) + return getDisabledFieldsMoveLiquidForm(rawForm, pipetteEntities) case 'mix': return getDisabledFieldsMixForm(rawForm) @@ -34,5 +38,6 @@ function _getDisabledFields(rawForm: FormData): Set { // shallow-memoized because every disable-able field in the form calls this function once // WARNING: do not mutate the same rawForm obj or this memoization will break export const getDisabledFields: ( - rawForm: FormData + rawForm: FormData, + pipetteEntities: PipetteEntities ) => Set = defaultMemoize(_getDisabledFields) diff --git a/protocol-designer/src/steplist/formLevel/stepFormToArgs/moveLiquidFormToArgs.ts b/protocol-designer/src/steplist/formLevel/stepFormToArgs/moveLiquidFormToArgs.ts index a3520288846..a2ba68f2c20 100644 --- a/protocol-designer/src/steplist/formLevel/stepFormToArgs/moveLiquidFormToArgs.ts +++ b/protocol-designer/src/steplist/formLevel/stepFormToArgs/moveLiquidFormToArgs.ts @@ -176,6 +176,7 @@ export const moveLiquidFormToArgs = ( touchTipAfterDispenseOffsetMmFromBottom, description: hydratedFormData.description, name: hydratedFormData.stepName, + dispense_pushOut: hydratedFormData.fields.dispense_pushOut, } assert( sourceWellsUnordered.length > 0, diff --git a/protocol-designer/src/steplist/formLevel/test/getDefaultsForStepType.test.ts b/protocol-designer/src/steplist/formLevel/test/getDefaultsForStepType.test.ts index 734c74ce0e9..2ece2b41b06 100644 --- a/protocol-designer/src/steplist/formLevel/test/getDefaultsForStepType.test.ts +++ b/protocol-designer/src/steplist/formLevel/test/getDefaultsForStepType.test.ts @@ -63,6 +63,7 @@ describe('getDefaultsForStepType', () => { dispense_delay_checkbox: false, dispense_delay_seconds: `${DEFAULT_DELAY_SECONDS}`, dispense_delay_mmFromBottom: null, + dispense_pushOut: false, }) }) }) diff --git a/protocol-designer/src/ui/steps/test/selectors.test.ts b/protocol-designer/src/ui/steps/test/selectors.test.ts index f3292dcf15a..1914c34c7db 100644 --- a/protocol-designer/src/ui/steps/test/selectors.test.ts +++ b/protocol-designer/src/ui/steps/test/selectors.test.ts @@ -531,6 +531,10 @@ describe('_getSavedMultiSelectFieldValues', () => { value: 1, isIndeterminate: false, }, + dispense_pushOut: { + value: undefined, + isIndeterminate: false, + }, blowout_checkbox: { value: true, isIndeterminate: false, @@ -728,6 +732,10 @@ describe('_getSavedMultiSelectFieldValues', () => { isIndeterminate: false, value: 1, }, + dispense_pushOut: { + value: undefined, + isIndeterminate: false, + }, blowout_checkbox: { isIndeterminate: true, }, diff --git a/shared-data/protocol/types/schemaV7/command/pipetting.ts b/shared-data/protocol/types/schemaV7/command/pipetting.ts index 06742de9050..99203a6c57a 100644 --- a/shared-data/protocol/types/schemaV7/command/pipetting.ts +++ b/shared-data/protocol/types/schemaV7/command/pipetting.ts @@ -6,6 +6,8 @@ export type PipettingRunTimeCommand = | TouchTipRunTimeCommand | PickUpTipRunTimeCommand | DropTipRunTimeCommand + | ConfigureForVolumeRunTimeCommand + export type PipettingCreateCommand = | AspirateCreateCommand | DispenseCreateCommand @@ -13,7 +15,18 @@ export type PipettingCreateCommand = | TouchTipCreateCommand | PickUpTipCreateCommand | DropTipCreateCommand + | ConfigureForVolumeCreateCommand +export interface ConfigureForVolumeCreateCommand + extends CommonCommandCreateInfo { + commandType: 'configureForVolume' + params: ConfigureForVolumeParams +} +export interface ConfigureForVolumeRunTimeCommand + extends CommonCommandRunTimeInfo, + ConfigureForVolumeCreateCommand { + result?: BasicLiquidHandlingResult +} export interface AspirateCreateCommand extends CommonCommandCreateInfo { commandType: 'aspirate' params: AspDispAirgapParams @@ -23,9 +36,11 @@ export interface AspirateRunTimeCommand AspirateCreateCommand { result?: BasicLiquidHandlingResult } + +export type DispenseParams = AspDispAirgapParams & { pushOut?: number } export interface DispenseCreateCommand extends CommonCommandCreateInfo { commandType: 'dispense' - params: AspDispAirgapParams + params: DispenseParams } export interface DispenseRunTimeCommand extends CommonCommandRunTimeInfo, @@ -69,6 +84,11 @@ export interface DropTipRunTimeCommand result?: any } +export type ConfigureForVolumeParams = { + pipetteId: string + volume: number +} + export type AspDispAirgapParams = FlowRateParams & PipetteAccessParams & VolumeParams & diff --git a/step-generation/src/__tests__/configureForVolume.test.ts b/step-generation/src/__tests__/configureForVolume.test.ts new file mode 100644 index 00000000000..03e40f7b80b --- /dev/null +++ b/step-generation/src/__tests__/configureForVolume.test.ts @@ -0,0 +1,38 @@ +import { getSuccessResult } from '../fixtures' +import { configureForVolume } from '../commandCreators/atomic/configureForVolume' + +const getRobotInitialState = (): any => { + return {} +} +const mockId = 'mockId' +const invariantContext: any = { + pipetteEntities: { + [mockId]: { + name: 'p50_single_flex', + id: mockId, + }, + }, +} + +describe('configureForVolume', () => { + it('should call configureForVolume with correct params', () => { + const robotInitialState = getRobotInitialState() + const mockId = 'mockId' + const result = configureForVolume( + { pipetteId: mockId, volume: 1 }, + invariantContext, + robotInitialState + ) + const res = getSuccessResult(result) + expect(res.commands).toEqual([ + { + commandType: 'configureForVolume', + key: expect.any(String), + params: { + pipetteId: mockId, + volume: 1, + }, + }, + ]) + }) +}) diff --git a/step-generation/src/commandCreators/atomic/configureForVolume.ts b/step-generation/src/commandCreators/atomic/configureForVolume.ts new file mode 100644 index 00000000000..ee977c8a47b --- /dev/null +++ b/step-generation/src/commandCreators/atomic/configureForVolume.ts @@ -0,0 +1,35 @@ +import { uuid } from '../../utils' +import type { CommandCreator } from '../../types' +interface configureForVolumeArgs { + pipetteId: string + volume: number +} + +export const configureForVolume: CommandCreator = ( + args, + invariantContext, + prevRobotState +) => { + const { pipetteId, volume } = args + + // No-op if there is no pipette + if (!invariantContext.pipetteEntities[pipetteId]) { + return { + commands: [], + } + } + + const commands = [ + { + commandType: 'configureForVolume' as const, + key: uuid(), + params: { + pipetteId, + volume, + }, + }, + ] + return { + commands, + } +} diff --git a/step-generation/src/commandCreators/atomic/dispense.ts b/step-generation/src/commandCreators/atomic/dispense.ts index 6d83e4d1703..99ece204163 100644 --- a/step-generation/src/commandCreators/atomic/dispense.ts +++ b/step-generation/src/commandCreators/atomic/dispense.ts @@ -12,9 +12,12 @@ import { uuid, } from '../../utils' import type { CreateCommand } from '@opentrons/shared-data' -import type { DispenseParams } from '@opentrons/shared-data/protocol/types/schemaV3' +import type { DispenseParams as DispenseParamsV3 } from '@opentrons/shared-data/protocol/types/schemaV3' import type { CommandCreator, CommandCreatorError } from '../../types' +interface DispenseParams extends DispenseParamsV3 { + pushOut?: number +} /** Dispense with given args. Requires tip. */ export const dispense: CommandCreator = ( args, @@ -29,6 +32,7 @@ export const dispense: CommandCreator = ( offsetFromBottomMm, flowRate, isAirGap, + pushOut, } = args const actionName = 'dispense' const errors: CommandCreatorError[] = [] @@ -170,6 +174,7 @@ export const dispense: CommandCreator = ( }, }, flowRate, + pushOut, }, ...(isAirGap && { meta: { isAirGap } }), }, diff --git a/step-generation/src/commandCreators/compound/transfer.ts b/step-generation/src/commandCreators/compound/transfer.ts index 654c6de4cfc..1d6f68fff7c 100644 --- a/step-generation/src/commandCreators/compound/transfer.ts +++ b/step-generation/src/commandCreators/compound/transfer.ts @@ -26,6 +26,7 @@ import type { CommandCreator, CommandCreatorError, } from '../../types' +import { configureForVolume } from '../atomic/configureForVolume' export const transfer: CommandCreator = ( args, invariantContext, @@ -97,6 +98,7 @@ export const transfer: CommandCreator = ( blowoutOffsetFromTopMm, dispenseFlowRateUlSec, dispenseOffsetFromBottomMm, + dispense_pushOut, } = args const aspirateAirGapVolume = args.aspirateAirGapVolume || 0 const dispenseAirGapVolume = args.dispenseAirGapVolume || 0 @@ -163,6 +165,20 @@ export const transfer: CommandCreator = ( changeTipNow = isInitialSubtransfer || destWell !== prevDestWell } + const configureForVolumeCommand: CurriedCommandCreator[] = + args.volume <= 1 && + (invariantContext.pipetteEntities[args.pipette].name === + 'p50_single_flex' || + invariantContext.pipetteEntities[args.pipette].name === + 'p50_multi_flex') + ? [ + curryCommandCreator(configureForVolume, { + pipetteId: args.pipette, + volume: args.volume, + }), + ] + : [] + const tipCommands: CurriedCommandCreator[] = changeTipNow ? [ curryCommandCreator(replaceTip, { @@ -406,6 +422,7 @@ export const transfer: CommandCreator = ( ...tipCommands, ...preWetTipCommands, ...mixBeforeAspirateCommands, + ...configureForVolumeCommand, curryCommandCreator(aspirate, { pipette: args.pipette, volume: subTransferVol, @@ -424,6 +441,7 @@ export const transfer: CommandCreator = ( well: destWell, flowRate: dispenseFlowRateUlSec, offsetFromBottomMm: dispenseOffsetFromBottomMm, + pushOut: dispense_pushOut ? subTransferVol : undefined, }), ...delayAfterDispenseCommands, ...mixInDestinationCommands, diff --git a/step-generation/src/getNextRobotStateAndWarnings/index.ts b/step-generation/src/getNextRobotStateAndWarnings/index.ts index a4ea09a5285..31f75eb8665 100644 --- a/step-generation/src/getNextRobotStateAndWarnings/index.ts +++ b/step-generation/src/getNextRobotStateAndWarnings/index.ts @@ -97,6 +97,7 @@ function _getNextRobotStateAndWarningsSingleCommand( case 'waitForResume': case 'moveToWell': case 'delay': + case 'configureForVolume': // these commands don't have any effects on the state break diff --git a/step-generation/src/types.ts b/step-generation/src/types.ts index 8962c9121aa..384cab3e9df 100644 --- a/step-generation/src/types.ts +++ b/step-generation/src/types.ts @@ -196,6 +196,8 @@ export type SharedTransferLikeArgs = CommonArgs & { dispenseFlowRateUlSec: number /** offset from bottom of well in mm */ dispenseOffsetFromBottomMm: number + /** Push out param only in dispense */ + dispense_pushOut: boolean } export type ConsolidateArgs = SharedTransferLikeArgs & { From d68caf35fc76a27b41a0e73792208e871655cf9a Mon Sep 17 00:00:00 2001 From: Jethary Date: Tue, 12 Sep 2023 09:53:04 -0400 Subject: [PATCH 03/13] add support in app for commandText --- .../en/protocol_command_text.json | 3 +- .../CommandText/PipettingCommandText.tsx | 25 ++++++--- .../__tests__/CommandText.test.tsx | 51 ++++++++++++++++++- app/src/organisms/CommandText/index.tsx | 16 ++++-- .../stepFormToArgs/moveLiquidFormToArgs.ts | 2 +- .../generateRobotStateTimeline.test.ts | 2 + .../types/schemaV7/command/pipetting.ts | 10 ++-- .../src/commandCreators/compound/transfer.ts | 4 +- step-generation/src/types.ts | 2 +- 9 files changed, 92 insertions(+), 23 deletions(-) diff --git a/app/src/assets/localization/en/protocol_command_text.json b/app/src/assets/localization/en/protocol_command_text.json index 7c454788c09..977c399ca31 100644 --- a/app/src/assets/localization/en/protocol_command_text.json +++ b/app/src/assets/localization/en/protocol_command_text.json @@ -1,7 +1,7 @@ { "aspirate": "Aspirating {{volume}} µL from well {{well_name}} of {{labware}} in {{labware_location}} at {{flow_rate}} µL/sec", "blowout": "Blowing out at well {{well_name}} of {{labware}} in {{labware_location}} at {{flow_rate}} µL/sec", - "configure_for_volume": "Configure {{volume}} µL for aspirate", + "configure_for_volume": "Configure {{volume}} µL for aspirating with {{pipette}}", "closing_tc_lid": "Closing Thermocycler lid", "comment": "Comment", "confirm_and_resume": "Confirm and resume", @@ -13,6 +13,7 @@ "degrees_c": "{{temp}}°C", "disengaging_magnetic_module": "Disengaging Magnetic Module", "dispense": "Dispensing {{volume}} µL into well {{well_name}} of {{labware}} in {{labware_location}} at {{flow_rate}} µL/sec", + "dispense_push_out": "Dispensing {{volume}} µL into well {{well_name}} of {{labware}} in {{labware_location}} at {{flow_rate}} µL/sec with push out volume {{push_out_volume}} µL", "drop_tip": "Dropping tip in {{well_name}} of {{labware}}", "engaging_magnetic_module": "Engaging Magnetic Module", "fixed_trash": "Fixed Trash", diff --git a/app/src/organisms/CommandText/PipettingCommandText.tsx b/app/src/organisms/CommandText/PipettingCommandText.tsx index 5249386dfe5..cc601bd747c 100644 --- a/app/src/organisms/CommandText/PipettingCommandText.tsx +++ b/app/src/organisms/CommandText/PipettingCommandText.tsx @@ -48,14 +48,23 @@ export const PipettingCommandText = ({ }) } case 'dispense': { - const { volume, flowRate } = command.params - return t('dispense', { - well_name: wellName, - labware: getLabwareName(robotSideAnalysis, labwareId), - labware_location: displayLocation, - volume: volume, - flow_rate: flowRate, - }) + const { volume, flowRate, pushOut } = command.params + return pushOut + ? t('dispense_push_out', { + well_name: wellName, + labware: getLabwareName(robotSideAnalysis, labwareId), + labware_location: displayLocation, + volume: volume, + flow_rate: flowRate, + push_out_volume: pushOut, + }) + : t('dispense', { + well_name: wellName, + labware: getLabwareName(robotSideAnalysis, labwareId), + labware_location: displayLocation, + volume: volume, + flow_rate: flowRate, + }) } case 'blowout': { const { flowRate } = command.params diff --git a/app/src/organisms/CommandText/__tests__/CommandText.test.tsx b/app/src/organisms/CommandText/__tests__/CommandText.test.tsx index 072da01a1ea..b0380a5dc03 100644 --- a/app/src/organisms/CommandText/__tests__/CommandText.test.tsx +++ b/app/src/organisms/CommandText/__tests__/CommandText.test.tsx @@ -5,7 +5,11 @@ import { CommandText } from '../' import { mockRobotSideAnalysis } from '../__fixtures__' import type { MoveToWellRunTimeCommand } from '@opentrons/shared-data/protocol/types/schemaV7/command/gantry' -import type { BlowoutRunTimeCommand } from '@opentrons/shared-data/protocol/types/schemaV7/command/pipetting' +import type { + BlowoutRunTimeCommand, + DispenseRunTimeCommand, + ConfigureForVolumeRunTimeCommand, +} from '@opentrons/shared-data/protocol/types/schemaV7/command/pipetting' import type { LoadLabwareRunTimeCommand, LoadLiquidRunTimeCommand, @@ -31,7 +35,7 @@ describe('CommandText', () => { ) } }) - it('renders correct text for dispense', () => { + it('renders correct text for dispense without pushOut', () => { const command = mockRobotSideAnalysis.commands.find( c => c.commandType === 'dispense' ) @@ -49,6 +53,31 @@ describe('CommandText', () => { ) } }) + it('renders correct text for dispense with pushOut', () => { + const command = mockRobotSideAnalysis.commands.find( + c => c.commandType === 'dispense' + ) + const pushOutDispenseCommand = { + ...command, + params: { + ...command?.params, + pushOut: 10, + }, + } as DispenseRunTimeCommand + expect(pushOutDispenseCommand).not.toBeUndefined() + if (pushOutDispenseCommand != null) { + const { getByText } = renderWithProviders( + , + { i18nInstance: i18n } + )[0] + getByText( + 'Dispensing 100 µL into well A1 of NEST 96 Well Plate 100 µL PCR Full Skirt (1) in Magnetic Module GEN2 in Slot 1 at 300 µL/sec with push out volume 10 µL' + ) + } + }) it('renders correct text for blowout', () => { const dispenseCommand = mockRobotSideAnalysis.commands.find( c => c.commandType === 'dispense' @@ -91,6 +120,24 @@ describe('CommandText', () => { getByText('Moving to well A1 of NEST 1 Well Reservoir 195 mL in Slot 5') } }) + it('renders correct text for configureForVolume', () => { + const command = { + commandType: 'configureForVolume', + params: { + volume: 1, + pipetteId: 'f6d1c83c-9d1b-4d0d-9de3-e6d649739cfb', + }, + } as ConfigureForVolumeRunTimeCommand + + const { getByText } = renderWithProviders( + , + { i18nInstance: i18n } + )[0] + getByText('Configure 1 µL for aspirating with P300 Single-Channel GEN1') + }) it('renders correct text for dropTip', () => { const command = mockRobotSideAnalysis.commands.find( c => c.commandType === 'dropTip' diff --git a/app/src/organisms/CommandText/index.tsx b/app/src/organisms/CommandText/index.tsx index 42d8aad59ea..f791f33f7d8 100644 --- a/app/src/organisms/CommandText/index.tsx +++ b/app/src/organisms/CommandText/index.tsx @@ -2,13 +2,13 @@ import * as React from 'react' import { useTranslation } from 'react-i18next' import { Flex, DIRECTION_COLUMN, SPACING } from '@opentrons/components' +import { getPipetteNameSpecs, RunTimeCommand } from '@opentrons/shared-data' import { StyledText } from '../../atoms/text' import { LoadCommandText } from './LoadCommandText' import { PipettingCommandText } from './PipettingCommandText' import { TemperatureCommandText } from './TemperatureCommandText' import { MoveLabwareCommandText } from './MoveLabwareCommandText' -import type { RunTimeCommand } from '@opentrons/shared-data' import type { CompletedProtocolAnalysis } from '@opentrons/shared-data/js' import type { StyleProps } from '@opentrons/components' @@ -140,10 +140,20 @@ export function CommandText(props: Props): JSX.Element | null { ) } case 'configureForVolume': { - const { volume } = command.params + const { volume, pipetteId } = command.params + const pipetteName = robotSideAnalysis.pipettes.find( + pip => pip.id === pipetteId + )?.pipetteName + return ( - {t('configure_for_volume', { volume })} + {t('configure_for_volume', { + volume, + pipette: + pipetteName != null + ? getPipetteNameSpecs(pipetteName)?.displayName + : '', + })} ) } diff --git a/protocol-designer/src/steplist/formLevel/stepFormToArgs/moveLiquidFormToArgs.ts b/protocol-designer/src/steplist/formLevel/stepFormToArgs/moveLiquidFormToArgs.ts index a2ba68f2c20..66abd90c466 100644 --- a/protocol-designer/src/steplist/formLevel/stepFormToArgs/moveLiquidFormToArgs.ts +++ b/protocol-designer/src/steplist/formLevel/stepFormToArgs/moveLiquidFormToArgs.ts @@ -176,7 +176,7 @@ export const moveLiquidFormToArgs = ( touchTipAfterDispenseOffsetMmFromBottom, description: hydratedFormData.description, name: hydratedFormData.stepName, - dispense_pushOut: hydratedFormData.fields.dispense_pushOut, + dispensePushOut: hydratedFormData.fields.dispense_pushOut, } assert( sourceWellsUnordered.length > 0, diff --git a/protocol-designer/src/timelineMiddleware/__tests__/generateRobotStateTimeline.test.ts b/protocol-designer/src/timelineMiddleware/__tests__/generateRobotStateTimeline.test.ts index 8d4469e63c8..ac8251f72be 100644 --- a/protocol-designer/src/timelineMiddleware/__tests__/generateRobotStateTimeline.test.ts +++ b/protocol-designer/src/timelineMiddleware/__tests__/generateRobotStateTimeline.test.ts @@ -43,6 +43,7 @@ describe('generateRobotStateTimeline', () => { destWells: ['A12', 'A12'], mixBeforeAspirate: null, description: null, + dispensePushOut: false, }, }, b: { @@ -76,6 +77,7 @@ describe('generateRobotStateTimeline', () => { destWells: ['A12'], mixBeforeAspirate: null, description: null, + dispensePushOut: false, }, }, c: { diff --git a/shared-data/protocol/types/schemaV7/command/pipetting.ts b/shared-data/protocol/types/schemaV7/command/pipetting.ts index 99203a6c57a..d6f822c53bc 100644 --- a/shared-data/protocol/types/schemaV7/command/pipetting.ts +++ b/shared-data/protocol/types/schemaV7/command/pipetting.ts @@ -22,6 +22,11 @@ export interface ConfigureForVolumeCreateCommand commandType: 'configureForVolume' params: ConfigureForVolumeParams } + +export interface ConfigureForVolumeParams { + pipetteId: string + volume: number +} export interface ConfigureForVolumeRunTimeCommand extends CommonCommandRunTimeInfo, ConfigureForVolumeCreateCommand { @@ -84,11 +89,6 @@ export interface DropTipRunTimeCommand result?: any } -export type ConfigureForVolumeParams = { - pipetteId: string - volume: number -} - export type AspDispAirgapParams = FlowRateParams & PipetteAccessParams & VolumeParams & diff --git a/step-generation/src/commandCreators/compound/transfer.ts b/step-generation/src/commandCreators/compound/transfer.ts index 1d6f68fff7c..9a3c1c3abb6 100644 --- a/step-generation/src/commandCreators/compound/transfer.ts +++ b/step-generation/src/commandCreators/compound/transfer.ts @@ -98,7 +98,7 @@ export const transfer: CommandCreator = ( blowoutOffsetFromTopMm, dispenseFlowRateUlSec, dispenseOffsetFromBottomMm, - dispense_pushOut, + dispensePushOut, } = args const aspirateAirGapVolume = args.aspirateAirGapVolume || 0 const dispenseAirGapVolume = args.dispenseAirGapVolume || 0 @@ -441,7 +441,7 @@ export const transfer: CommandCreator = ( well: destWell, flowRate: dispenseFlowRateUlSec, offsetFromBottomMm: dispenseOffsetFromBottomMm, - pushOut: dispense_pushOut ? subTransferVol : undefined, + pushOut: dispensePushOut ? subTransferVol : undefined, }), ...delayAfterDispenseCommands, ...mixInDestinationCommands, diff --git a/step-generation/src/types.ts b/step-generation/src/types.ts index 384cab3e9df..cc6cfcb9ca9 100644 --- a/step-generation/src/types.ts +++ b/step-generation/src/types.ts @@ -197,7 +197,7 @@ export type SharedTransferLikeArgs = CommonArgs & { /** offset from bottom of well in mm */ dispenseOffsetFromBottomMm: number /** Push out param only in dispense */ - dispense_pushOut: boolean + dispensePushOut: boolean } export type ConsolidateArgs = SharedTransferLikeArgs & { From cf2043b43fb8ce52d08ff12440000eeedfcabbd8 Mon Sep 17 00:00:00 2001 From: Jethary Date: Tue, 12 Sep 2023 11:03:28 -0400 Subject: [PATCH 04/13] fix cypress tests --- protocol-designer/fixtures/protocol/7/doItAllV3MigratedToV7.json | 1 + protocol-designer/fixtures/protocol/7/doItAllV4MigratedToV7.json | 1 + protocol-designer/fixtures/protocol/7/doItAllV7.json | 1 + .../fixtures/protocol/7/example_1_1_0MigratedFromV1_0_0.json | 1 + 4 files changed, 4 insertions(+) diff --git a/protocol-designer/fixtures/protocol/7/doItAllV3MigratedToV7.json b/protocol-designer/fixtures/protocol/7/doItAllV3MigratedToV7.json index 32c96b7e3d8..f65443d32ce 100644 --- a/protocol-designer/fixtures/protocol/7/doItAllV3MigratedToV7.json +++ b/protocol-designer/fixtures/protocol/7/doItAllV3MigratedToV7.json @@ -110,6 +110,7 @@ "dispense_delay_checkbox": false, "dispense_delay_seconds": "1", "dispense_delay_mmFromBottom": "0.5", + "dispense_pushOut": false, "id": "3961e4c0-75c7-11ea-b42f-4b64e50f43e5", "stepType": "moveLiquid", "stepName": "transfer", diff --git a/protocol-designer/fixtures/protocol/7/doItAllV4MigratedToV7.json b/protocol-designer/fixtures/protocol/7/doItAllV4MigratedToV7.json index 3d9a7f1ec27..a429ac0dfe2 100644 --- a/protocol-designer/fixtures/protocol/7/doItAllV4MigratedToV7.json +++ b/protocol-designer/fixtures/protocol/7/doItAllV4MigratedToV7.json @@ -144,6 +144,7 @@ "dispense_delay_checkbox": false, "dispense_delay_seconds": "1", "dispense_delay_mmFromBottom": "0.5", + "dispense_pushOut": false, "id": "3961e4c0-75c7-11ea-b42f-4b64e50f43e5", "stepType": "moveLiquid", "stepName": "transfer", diff --git a/protocol-designer/fixtures/protocol/7/doItAllV7.json b/protocol-designer/fixtures/protocol/7/doItAllV7.json index dbde26caf46..ca9100996ed 100644 --- a/protocol-designer/fixtures/protocol/7/doItAllV7.json +++ b/protocol-designer/fixtures/protocol/7/doItAllV7.json @@ -186,6 +186,7 @@ "dispense_delay_checkbox": false, "dispense_delay_seconds": "1", "dispense_delay_mmFromBottom": null, + "dispense_pushOut": false, "id": "f9a294f1-f42b-4cae-893a-592405349d56", "stepType": "moveLiquid", "stepName": "transfer", diff --git a/protocol-designer/fixtures/protocol/7/example_1_1_0MigratedFromV1_0_0.json b/protocol-designer/fixtures/protocol/7/example_1_1_0MigratedFromV1_0_0.json index cc8389e27bc..00c517d9dd6 100644 --- a/protocol-designer/fixtures/protocol/7/example_1_1_0MigratedFromV1_0_0.json +++ b/protocol-designer/fixtures/protocol/7/example_1_1_0MigratedFromV1_0_0.json @@ -120,6 +120,7 @@ "dispense_delay_checkbox": false, "dispense_delay_seconds": "1", "dispense_delay_mmFromBottom": "0.5", + "dispense_pushOut": false, "id": "e7d36200-92a5-11e9-ac62-1b173f839d9e", "stepType": "moveLiquid", "stepName": "transfer things", From bf776c0dbad29705c0b0a1f14a8f3a00b25d65df Mon Sep 17 00:00:00 2001 From: Jethary Date: Tue, 12 Sep 2023 12:20:31 -0400 Subject: [PATCH 05/13] feat(app, shared-data, protocol-designer, step-generation): frontend low volume support closes RAUT-714 --- step-generation/src/commandCreators/compound/transfer.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/step-generation/src/commandCreators/compound/transfer.ts b/step-generation/src/commandCreators/compound/transfer.ts index 9a3c1c3abb6..bcff0306293 100644 --- a/step-generation/src/commandCreators/compound/transfer.ts +++ b/step-generation/src/commandCreators/compound/transfer.ts @@ -164,7 +164,9 @@ export const transfer: CommandCreator = ( } else if (args.changeTip === 'perDest') { changeTipNow = isInitialSubtransfer || destWell !== prevDestWell } - + + // todo(jr, 9/12/23): figure out a way to only emit this command if the the previous pipetting volume + // with the same pipette is the same 1uL volume const configureForVolumeCommand: CurriedCommandCreator[] = args.volume <= 1 && (invariantContext.pipetteEntities[args.pipette].name === From cad990ad487b5658f3cf792fd2963ac9a0b5da75 Mon Sep 17 00:00:00 2001 From: Jethary Date: Tue, 12 Sep 2023 12:44:27 -0400 Subject: [PATCH 06/13] fix lint --- .../forms/__tests__/SourceDestFields.test.tsx | 16 ++++++++++++++++ .../src/commandCreators/compound/transfer.ts | 2 +- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/protocol-designer/src/components/StepEditForm/forms/__tests__/SourceDestFields.test.tsx b/protocol-designer/src/components/StepEditForm/forms/__tests__/SourceDestFields.test.tsx index 8067168956b..2f462890fc0 100644 --- a/protocol-designer/src/components/StepEditForm/forms/__tests__/SourceDestFields.test.tsx +++ b/protocol-designer/src/components/StepEditForm/forms/__tests__/SourceDestFields.test.tsx @@ -273,6 +273,21 @@ describe('SourceDestFields', () => { expect(checkboxes.at(3).prop('name')).toBe('dispense_airGap_checkbox') }) it('should render the correct checkboxes for a flex', () => { + props = { + ...props, + propsForFields: { + ...props.propsForFields, + dispense_pushOut: { + onFieldFocus: jest.fn() as any, + onFieldBlur: jest.fn() as any, + errorToShow: null, + disabled: false, + name: 'dispense_pushOut', + updateValue: jest.fn() as any, + value: true, + } as any, + }, + } mockGetRobotType.mockReturnValue(FLEX_ROBOT_TYPE) const wrapper = render(props) const checkboxes = wrapper.find(CheckboxRowField) @@ -283,6 +298,7 @@ describe('SourceDestFields', () => { secondsFieldName: 'dispense_delay_seconds', tipPositionFieldName: 'dispense_delay_mmFromBottom', }) + expect(checkboxes.at(0).prop('name')).toBe('dispense_mix_checkbox') expect(checkboxes.at(1).prop('name')).toBe('dispense_touchTip_checkbox') expect(checkboxes.at(2).prop('name')).toBe('blowout_checkbox') diff --git a/step-generation/src/commandCreators/compound/transfer.ts b/step-generation/src/commandCreators/compound/transfer.ts index bcff0306293..e348afae43e 100644 --- a/step-generation/src/commandCreators/compound/transfer.ts +++ b/step-generation/src/commandCreators/compound/transfer.ts @@ -164,7 +164,7 @@ export const transfer: CommandCreator = ( } else if (args.changeTip === 'perDest') { changeTipNow = isInitialSubtransfer || destWell !== prevDestWell } - + // todo(jr, 9/12/23): figure out a way to only emit this command if the the previous pipetting volume // with the same pipette is the same 1uL volume const configureForVolumeCommand: CurriedCommandCreator[] = From 729e32ec60e6db795bafc6c27cc3ae0560679b78 Mon Sep 17 00:00:00 2001 From: Jethary Date: Tue, 12 Sep 2023 12:59:31 -0400 Subject: [PATCH 07/13] remove comment --- step-generation/src/commandCreators/compound/transfer.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/step-generation/src/commandCreators/compound/transfer.ts b/step-generation/src/commandCreators/compound/transfer.ts index e348afae43e..9a3c1c3abb6 100644 --- a/step-generation/src/commandCreators/compound/transfer.ts +++ b/step-generation/src/commandCreators/compound/transfer.ts @@ -165,8 +165,6 @@ export const transfer: CommandCreator = ( changeTipNow = isInitialSubtransfer || destWell !== prevDestWell } - // todo(jr, 9/12/23): figure out a way to only emit this command if the the previous pipetting volume - // with the same pipette is the same 1uL volume const configureForVolumeCommand: CurriedCommandCreator[] = args.volume <= 1 && (invariantContext.pipetteEntities[args.pipette].name === From 354042c8bbb9e15a733aa6e5ce75f0d18dd77573 Mon Sep 17 00:00:00 2001 From: Jethary Date: Tue, 12 Sep 2023 14:45:17 -0400 Subject: [PATCH 08/13] remove pushOut option from Pd --- .../protocol/7/doItAllV3MigratedToV7.json | 1 - .../protocol/7/doItAllV4MigratedToV7.json | 1 - .../fixtures/protocol/7/doItAllV7.json | 1 - .../7/example_1_1_0MigratedFromV1_0_0.json | 1 - .../makeSingleEditFieldProps.test.ts | 1 - .../fields/makeSingleEditFieldProps.ts | 6 +-- .../forms/MoveLiquidForm/SourceDestFields.tsx | 45 +++++++----------- .../forms/__tests__/SourceDestFields.test.tsx | 47 +------------------ .../src/components/StepEditForm/index.tsx | 5 +- protocol-designer/src/form-types.ts | 1 - .../src/load-file/migration/7_0_0.ts | 23 +-------- .../src/localization/en/form.json | 1 - .../src/localization/en/tooltip.json | 3 +- .../test/createPresavedStepForm.test.ts | 1 - .../formLevel/getDefaultsForStepType.ts | 1 - .../getDisabledFieldsMoveLiquidForm.ts | 16 +------ .../formLevel/getDisabledFields/index.ts | 11 ++--- .../stepFormToArgs/moveLiquidFormToArgs.ts | 1 - .../test/getDefaultsForStepType.test.ts | 1 - .../generateRobotStateTimeline.test.ts | 2 - .../src/ui/steps/test/selectors.test.ts | 8 ---- .../src/commandCreators/atomic/dispense.ts | 9 ++-- .../src/commandCreators/compound/transfer.ts | 2 - step-generation/src/types.ts | 2 - 24 files changed, 29 insertions(+), 161 deletions(-) diff --git a/protocol-designer/fixtures/protocol/7/doItAllV3MigratedToV7.json b/protocol-designer/fixtures/protocol/7/doItAllV3MigratedToV7.json index f65443d32ce..32c96b7e3d8 100644 --- a/protocol-designer/fixtures/protocol/7/doItAllV3MigratedToV7.json +++ b/protocol-designer/fixtures/protocol/7/doItAllV3MigratedToV7.json @@ -110,7 +110,6 @@ "dispense_delay_checkbox": false, "dispense_delay_seconds": "1", "dispense_delay_mmFromBottom": "0.5", - "dispense_pushOut": false, "id": "3961e4c0-75c7-11ea-b42f-4b64e50f43e5", "stepType": "moveLiquid", "stepName": "transfer", diff --git a/protocol-designer/fixtures/protocol/7/doItAllV4MigratedToV7.json b/protocol-designer/fixtures/protocol/7/doItAllV4MigratedToV7.json index a429ac0dfe2..3d9a7f1ec27 100644 --- a/protocol-designer/fixtures/protocol/7/doItAllV4MigratedToV7.json +++ b/protocol-designer/fixtures/protocol/7/doItAllV4MigratedToV7.json @@ -144,7 +144,6 @@ "dispense_delay_checkbox": false, "dispense_delay_seconds": "1", "dispense_delay_mmFromBottom": "0.5", - "dispense_pushOut": false, "id": "3961e4c0-75c7-11ea-b42f-4b64e50f43e5", "stepType": "moveLiquid", "stepName": "transfer", diff --git a/protocol-designer/fixtures/protocol/7/doItAllV7.json b/protocol-designer/fixtures/protocol/7/doItAllV7.json index ca9100996ed..dbde26caf46 100644 --- a/protocol-designer/fixtures/protocol/7/doItAllV7.json +++ b/protocol-designer/fixtures/protocol/7/doItAllV7.json @@ -186,7 +186,6 @@ "dispense_delay_checkbox": false, "dispense_delay_seconds": "1", "dispense_delay_mmFromBottom": null, - "dispense_pushOut": false, "id": "f9a294f1-f42b-4cae-893a-592405349d56", "stepType": "moveLiquid", "stepName": "transfer", diff --git a/protocol-designer/fixtures/protocol/7/example_1_1_0MigratedFromV1_0_0.json b/protocol-designer/fixtures/protocol/7/example_1_1_0MigratedFromV1_0_0.json index 00c517d9dd6..cc8389e27bc 100644 --- a/protocol-designer/fixtures/protocol/7/example_1_1_0MigratedFromV1_0_0.json +++ b/protocol-designer/fixtures/protocol/7/example_1_1_0MigratedFromV1_0_0.json @@ -120,7 +120,6 @@ "dispense_delay_checkbox": false, "dispense_delay_seconds": "1", "dispense_delay_mmFromBottom": "0.5", - "dispense_pushOut": false, "id": "e7d36200-92a5-11e9-ac62-1b173f839d9e", "stepType": "moveLiquid", "stepName": "transfer things", diff --git a/protocol-designer/src/components/StepEditForm/fields/__tests__/makeSingleEditFieldProps.test.ts b/protocol-designer/src/components/StepEditForm/fields/__tests__/makeSingleEditFieldProps.test.ts index 00389498caf..bb998523130 100644 --- a/protocol-designer/src/components/StepEditForm/fields/__tests__/makeSingleEditFieldProps.test.ts +++ b/protocol-designer/src/components/StepEditForm/fields/__tests__/makeSingleEditFieldProps.test.ts @@ -101,7 +101,6 @@ describe('makeSingleEditFieldProps', () => { const result = makeSingleEditFieldProps( focusHandlers, formData, - {}, handleChangeFormInput ) expect(result).toEqual({ diff --git a/protocol-designer/src/components/StepEditForm/fields/makeSingleEditFieldProps.ts b/protocol-designer/src/components/StepEditForm/fields/makeSingleEditFieldProps.ts index 2d87235ee49..7daf2a4abca 100644 --- a/protocol-designer/src/components/StepEditForm/fields/makeSingleEditFieldProps.ts +++ b/protocol-designer/src/components/StepEditForm/fields/makeSingleEditFieldProps.ts @@ -9,7 +9,6 @@ import { } from '../utils' import { StepFieldName, FormData } from '../../../form-types' import { FieldProps, FieldPropsByName, FocusHandlers } from '../types' -import { PipetteEntities } from '@opentrons/step-generation' interface ShowFieldErrorParams { name: StepFieldName focusedField: StepFieldName | null @@ -24,7 +23,6 @@ export const showFieldErrors = ({ export const makeSingleEditFieldProps = ( focusHandlers: FocusHandlers, formData: FormData, - pipetteEntities: PipetteEntities, handleChangeFormInput: (name: string, value: unknown) => void ): FieldPropsByName => { const { dirtyFields, blur, focusedField, focus } = focusHandlers @@ -32,9 +30,7 @@ export const makeSingleEditFieldProps = ( getDefaultsForStepType(formData.stepType) ) return fieldNames.reduce((acc, name) => { - const disabled = formData - ? getDisabledFields(formData, pipetteEntities).has(name) - : false + const disabled = formData ? getDisabledFields(formData).has(name) : false const value = formData ? formData[name] : null const showErrors = showFieldErrors({ name, diff --git a/protocol-designer/src/components/StepEditForm/forms/MoveLiquidForm/SourceDestFields.tsx b/protocol-designer/src/components/StepEditForm/forms/MoveLiquidForm/SourceDestFields.tsx index 33ee245d82f..127afbda34c 100644 --- a/protocol-designer/src/components/StepEditForm/forms/MoveLiquidForm/SourceDestFields.tsx +++ b/protocol-designer/src/components/StepEditForm/forms/MoveLiquidForm/SourceDestFields.tsx @@ -1,9 +1,6 @@ import * as React from 'react' -import { useSelector } from 'react-redux' import { i18n } from '../../../../localization' -import { FLEX_ROBOT_TYPE } from '@opentrons/shared-data' -import { getRobotType } from '../../../../file-data/selectors' import { BlowoutLocationField, CheckboxRowField, @@ -40,7 +37,6 @@ const makeAddFieldNamePrefix = (prefix: string) => ( export const SourceDestFields = (props: SourceDestFieldsProps): JSX.Element => { const { className, formData, prefix, propsForFields, allLabware } = props - const robotType = useSelector(getRobotType) const addFieldNamePrefix = makeAddFieldNamePrefix(prefix) const getDelayFields = (): JSX.Element => ( @@ -160,31 +156,22 @@ export const SourceDestFields = (props: SourceDestFieldsProps): JSX.Element => { /> - {prefix === 'dispense' ? ( - <> - - - - {robotType === FLEX_ROBOT_TYPE ? ( - - ) : null} - - ) : null} + {prefix === 'dispense' && ( + + + + )} -const mockGetRobotType = getRobotType as jest.MockedFunction< - typeof getRobotType -> jest.mock('../../fields/', () => { const actualFields = jest.requireActual('../../fields') @@ -210,7 +201,6 @@ describe('SourceDestFields', () => { getUnsavedFormMock.mockReturnValue({ stepType: 'moveLiquid', } as FormData) - mockGetRobotType.mockReturnValue(OT2_ROBOT_TYPE) }) const render = (props: React.ComponentProps) => @@ -257,7 +247,7 @@ describe('SourceDestFields', () => { beforeEach(() => { props = { ...props, prefix: 'dispense' } }) - it('should render the correct checkboxes for an OT-2', () => { + it('should render the correct checkboxes', () => { const wrapper = render(props) const checkboxes = wrapper.find(CheckboxRowField) @@ -272,39 +262,6 @@ describe('SourceDestFields', () => { expect(checkboxes.at(2).prop('name')).toBe('blowout_checkbox') expect(checkboxes.at(3).prop('name')).toBe('dispense_airGap_checkbox') }) - it('should render the correct checkboxes for a flex', () => { - props = { - ...props, - propsForFields: { - ...props.propsForFields, - dispense_pushOut: { - onFieldFocus: jest.fn() as any, - onFieldBlur: jest.fn() as any, - errorToShow: null, - disabled: false, - name: 'dispense_pushOut', - updateValue: jest.fn() as any, - value: true, - } as any, - }, - } - mockGetRobotType.mockReturnValue(FLEX_ROBOT_TYPE) - const wrapper = render(props) - const checkboxes = wrapper.find(CheckboxRowField) - - const delayFields = wrapper.find(DelayFields) - expect(delayFields.props()).toMatchObject({ - checkboxFieldName: 'dispense_delay_checkbox', - secondsFieldName: 'dispense_delay_seconds', - tipPositionFieldName: 'dispense_delay_mmFromBottom', - }) - - expect(checkboxes.at(0).prop('name')).toBe('dispense_mix_checkbox') - expect(checkboxes.at(1).prop('name')).toBe('dispense_touchTip_checkbox') - expect(checkboxes.at(2).prop('name')).toBe('blowout_checkbox') - expect(checkboxes.at(3).prop('name')).toBe('dispense_pushOut') - expect(checkboxes.at(4).prop('name')).toBe('dispense_airGap_checkbox') - }) it('should render a well order field', () => { const wrapper = render(props) const wellOrderField = wrapper.find(WellOrderField) diff --git a/protocol-designer/src/components/StepEditForm/index.tsx b/protocol-designer/src/components/StepEditForm/index.tsx index 966e86c2996..d4c60961d6a 100644 --- a/protocol-designer/src/components/StepEditForm/index.tsx +++ b/protocol-designer/src/components/StepEditForm/index.tsx @@ -1,6 +1,6 @@ import { useConditionalConfirm } from '@opentrons/components' import * as React from 'react' -import { connect, useSelector } from 'react-redux' +import { connect } from 'react-redux' import { actions } from '../../steplist' import { actions as stepsActions } from '../../ui/steps' import { resetScrollElements } from '../../ui/steps/utils' @@ -19,7 +19,6 @@ import { StepEditFormComponent } from './StepEditFormComponent' import { getDirtyFields } from './utils' import { BaseState, ThunkDispatch } from '../../types' import { FormData, StepFieldName, StepIdType } from '../../form-types' -import { getPipetteEntities } from '../../step-forms/selectors' interface SP { canSave: boolean @@ -65,7 +64,6 @@ const StepEditFormManager = ( const [dirtyFields, setDirtyFields] = React.useState( getDirtyFields(isNewStep, formData) ) - const pipetteEntities = useSelector(getPipetteEntities) const toggleMoreOptionsModal = (): void => { resetScrollElements() @@ -137,7 +135,6 @@ const StepEditFormManager = ( const propsForFields = makeSingleEditFieldProps( focusHandlers, formData, - pipetteEntities, handleChangeFormInput ) let handleSave = saveStepForm diff --git a/protocol-designer/src/form-types.ts b/protocol-designer/src/form-types.ts index 0d98134bb7a..c6ffab1b7cf 100644 --- a/protocol-designer/src/form-types.ts +++ b/protocol-designer/src/form-types.ts @@ -211,7 +211,6 @@ export interface HydratedMoveLiquidFormData { dispense_mix_checkbox: boolean dispense_mix_volume: number | null | undefined dispense_mix_times: number | null | undefined - dispense_pushOut: boolean disposalVolume_checkbox: boolean disposalVolume_volume: number | null | undefined blowout_checkbox: boolean diff --git a/protocol-designer/src/load-file/migration/7_0_0.ts b/protocol-designer/src/load-file/migration/7_0_0.ts index 4057c2a5194..026abbcf5fc 100644 --- a/protocol-designer/src/load-file/migration/7_0_0.ts +++ b/protocol-designer/src/load-file/migration/7_0_0.ts @@ -1,4 +1,3 @@ -import mapValues from 'lodash/mapValues' import { uuid } from '../../utils' import { getOnlyLatestDefs } from '../../labware-defs' import { INITIAL_DECK_SETUP_STEP_ID } from '../../constants' @@ -253,26 +252,6 @@ export const migrateFile = ( } const newLabwareIngreds = getNewLabwareIngreds(ingredLocations) - const migrateSavedStepForms = ( - savedStepForms: Record - ): Record => { - return mapValues(savedStepForms, stepForm => { - if (stepForm.stepType === 'moveLiquid') { - return { - ...stepForm, - dispense_pushOut: false, - } - } - return stepForm - }) - } - const filteredavedStepForms = Object.fromEntries( - Object.entries( - appData.designerApplication?.data?.savedStepForms ?? {} - ).filter(([key, value]) => key !== INITIAL_DECK_SETUP_STEP_ID) - ) - const newFilteredavedStepForms = migrateSavedStepForms(filteredavedStepForms) - return { ...rest, designerApplication: { @@ -284,6 +263,7 @@ export const migrateFile = ( ...newLabwareIngreds, }, savedStepForms: { + ...appData.designerApplication?.data?.savedStepForms, [INITIAL_DECK_SETUP_STEP_ID]: { ...appData.designerApplication?.data?.savedStepForms[ INITIAL_DECK_SETUP_STEP_ID @@ -292,7 +272,6 @@ export const migrateFile = ( ...newLabwareLocationUpdate, }, }, - ...newFilteredavedStepForms, }, }, }, diff --git a/protocol-designer/src/localization/en/form.json b/protocol-designer/src/localization/en/form.json index ce56e8ff720..d7fc7289fa4 100644 --- a/protocol-designer/src/localization/en/form.json +++ b/protocol-designer/src/localization/en/form.json @@ -49,7 +49,6 @@ }, "field": { "airGap": { "label": "air gap" }, - "pushOut": { "label": "push out" }, "blowout": { "label": "blowout" }, "change_tip": { "label": "change tip", diff --git a/protocol-designer/src/localization/en/tooltip.json b/protocol-designer/src/localization/en/tooltip.json index 727702fa292..0ac80ec523e 100644 --- a/protocol-designer/src/localization/en/tooltip.json +++ b/protocol-designer/src/localization/en/tooltip.json @@ -65,8 +65,7 @@ "moveLiquid": { "disabled": { "$generic": "Incompatible with current path", - "blowout_checkbox": "Redundant with disposal volume", - "dispense_pushOut": "Not available unless dispensing 1µL or less" + "blowout_checkbox": "Redundant with disposal volume" } }, "moveLabware": { diff --git a/protocol-designer/src/step-forms/test/createPresavedStepForm.test.ts b/protocol-designer/src/step-forms/test/createPresavedStepForm.test.ts index 7436d3aa61b..9c7b01612d8 100644 --- a/protocol-designer/src/step-forms/test/createPresavedStepForm.test.ts +++ b/protocol-designer/src/step-forms/test/createPresavedStepForm.test.ts @@ -167,7 +167,6 @@ describe('createPresavedStepForm', () => { dispense_wells: [], disposalVolume_checkbox: true, disposalVolume_volume: '1', - dispense_pushOut: false, path: 'single', preWetTip: false, stepDetails: '', diff --git a/protocol-designer/src/steplist/formLevel/getDefaultsForStepType.ts b/protocol-designer/src/steplist/formLevel/getDefaultsForStepType.ts index 88c22109173..ba75ab88974 100644 --- a/protocol-designer/src/steplist/formLevel/getDefaultsForStepType.ts +++ b/protocol-designer/src/steplist/formLevel/getDefaultsForStepType.ts @@ -66,7 +66,6 @@ export function getDefaultsForStepType( dispense_mmFromBottom: null, dispense_touchTip_checkbox: false, dispense_touchTip_mmFromBottom: null, - dispense_pushOut: false, disposalVolume_checkbox: false, disposalVolume_volume: null, blowout_checkbox: false, diff --git a/protocol-designer/src/steplist/formLevel/getDisabledFields/getDisabledFieldsMoveLiquidForm.ts b/protocol-designer/src/steplist/formLevel/getDisabledFields/getDisabledFieldsMoveLiquidForm.ts index 59a603e40fa..e45ad3d4672 100644 --- a/protocol-designer/src/steplist/formLevel/getDisabledFields/getDisabledFieldsMoveLiquidForm.ts +++ b/protocol-designer/src/steplist/formLevel/getDisabledFields/getDisabledFieldsMoveLiquidForm.ts @@ -1,21 +1,11 @@ -import { PipetteEntities } from '@opentrons/step-generation' import { FormData } from '../../../form-types' // NOTE: expects that '_checkbox' fields are implemented so that // when checkbox is disabled, its dependent fields are hidden export function getDisabledFieldsMoveLiquidForm( - rawForm: FormData, // TODO IMMEDIATELY use raw form type instead of FormData - pipetteEntities: PipetteEntities + rawForm: FormData // TODO IMMEDIATELY use raw form type instead of FormData ): Set { const disabled: Set = new Set() const prefixes = ['aspirate', 'dispense'] - const pipetteSelected = - rawForm.pipette != null - ? pipetteEntities[String(rawForm.pipette)].name - : null - const pushOutAllowed = - Number(rawForm.volume) <= 1 && - (pipetteSelected === 'p50_single_flex' || - pipetteSelected === 'p50_multi_flex') if (rawForm.path === 'multiAspirate') { disabled.add('aspirate_mix_checkbox') @@ -35,9 +25,5 @@ export function getDisabledFieldsMoveLiquidForm( disabled.add(prefix + '_wells') } }) - - if (!pushOutAllowed) { - disabled.add('dispense_pushOut') - } return disabled } diff --git a/protocol-designer/src/steplist/formLevel/getDisabledFields/index.ts b/protocol-designer/src/steplist/formLevel/getDisabledFields/index.ts index 0e3a1a90f04..0454209b3a7 100644 --- a/protocol-designer/src/steplist/formLevel/getDisabledFields/index.ts +++ b/protocol-designer/src/steplist/formLevel/getDisabledFields/index.ts @@ -3,15 +3,11 @@ import { getDisabledFieldsMoveLiquidForm } from './getDisabledFieldsMoveLiquidFo import { getDisabledFieldsMixForm } from './getDisabledFieldsMixForm' import { getDisabledFieldsHeaterShaker } from './getDisabledFieldsHeaterShaker' import { FormData } from '../../../form-types' -import { PipetteEntities } from '@opentrons/step-generation' -function _getDisabledFields( - rawForm: FormData, - pipetteEntities: PipetteEntities -): Set { +function _getDisabledFields(rawForm: FormData): Set { switch (rawForm.stepType) { case 'moveLiquid': - return getDisabledFieldsMoveLiquidForm(rawForm, pipetteEntities) + return getDisabledFieldsMoveLiquidForm(rawForm) case 'mix': return getDisabledFieldsMixForm(rawForm) @@ -38,6 +34,5 @@ function _getDisabledFields( // shallow-memoized because every disable-able field in the form calls this function once // WARNING: do not mutate the same rawForm obj or this memoization will break export const getDisabledFields: ( - rawForm: FormData, - pipetteEntities: PipetteEntities + rawForm: FormData ) => Set = defaultMemoize(_getDisabledFields) diff --git a/protocol-designer/src/steplist/formLevel/stepFormToArgs/moveLiquidFormToArgs.ts b/protocol-designer/src/steplist/formLevel/stepFormToArgs/moveLiquidFormToArgs.ts index 66abd90c466..a3520288846 100644 --- a/protocol-designer/src/steplist/formLevel/stepFormToArgs/moveLiquidFormToArgs.ts +++ b/protocol-designer/src/steplist/formLevel/stepFormToArgs/moveLiquidFormToArgs.ts @@ -176,7 +176,6 @@ export const moveLiquidFormToArgs = ( touchTipAfterDispenseOffsetMmFromBottom, description: hydratedFormData.description, name: hydratedFormData.stepName, - dispensePushOut: hydratedFormData.fields.dispense_pushOut, } assert( sourceWellsUnordered.length > 0, diff --git a/protocol-designer/src/steplist/formLevel/test/getDefaultsForStepType.test.ts b/protocol-designer/src/steplist/formLevel/test/getDefaultsForStepType.test.ts index 2ece2b41b06..734c74ce0e9 100644 --- a/protocol-designer/src/steplist/formLevel/test/getDefaultsForStepType.test.ts +++ b/protocol-designer/src/steplist/formLevel/test/getDefaultsForStepType.test.ts @@ -63,7 +63,6 @@ describe('getDefaultsForStepType', () => { dispense_delay_checkbox: false, dispense_delay_seconds: `${DEFAULT_DELAY_SECONDS}`, dispense_delay_mmFromBottom: null, - dispense_pushOut: false, }) }) }) diff --git a/protocol-designer/src/timelineMiddleware/__tests__/generateRobotStateTimeline.test.ts b/protocol-designer/src/timelineMiddleware/__tests__/generateRobotStateTimeline.test.ts index ac8251f72be..8d4469e63c8 100644 --- a/protocol-designer/src/timelineMiddleware/__tests__/generateRobotStateTimeline.test.ts +++ b/protocol-designer/src/timelineMiddleware/__tests__/generateRobotStateTimeline.test.ts @@ -43,7 +43,6 @@ describe('generateRobotStateTimeline', () => { destWells: ['A12', 'A12'], mixBeforeAspirate: null, description: null, - dispensePushOut: false, }, }, b: { @@ -77,7 +76,6 @@ describe('generateRobotStateTimeline', () => { destWells: ['A12'], mixBeforeAspirate: null, description: null, - dispensePushOut: false, }, }, c: { diff --git a/protocol-designer/src/ui/steps/test/selectors.test.ts b/protocol-designer/src/ui/steps/test/selectors.test.ts index 1914c34c7db..f3292dcf15a 100644 --- a/protocol-designer/src/ui/steps/test/selectors.test.ts +++ b/protocol-designer/src/ui/steps/test/selectors.test.ts @@ -531,10 +531,6 @@ describe('_getSavedMultiSelectFieldValues', () => { value: 1, isIndeterminate: false, }, - dispense_pushOut: { - value: undefined, - isIndeterminate: false, - }, blowout_checkbox: { value: true, isIndeterminate: false, @@ -732,10 +728,6 @@ describe('_getSavedMultiSelectFieldValues', () => { isIndeterminate: false, value: 1, }, - dispense_pushOut: { - value: undefined, - isIndeterminate: false, - }, blowout_checkbox: { isIndeterminate: true, }, diff --git a/step-generation/src/commandCreators/atomic/dispense.ts b/step-generation/src/commandCreators/atomic/dispense.ts index 99ece204163..c8ddfe1dc96 100644 --- a/step-generation/src/commandCreators/atomic/dispense.ts +++ b/step-generation/src/commandCreators/atomic/dispense.ts @@ -12,12 +12,9 @@ import { uuid, } from '../../utils' import type { CreateCommand } from '@opentrons/shared-data' -import type { DispenseParams as DispenseParamsV3 } from '@opentrons/shared-data/protocol/types/schemaV3' +import type { DispenseParams } from '@opentrons/shared-data/protocol/types/schemaV3' import type { CommandCreator, CommandCreatorError } from '../../types' -interface DispenseParams extends DispenseParamsV3 { - pushOut?: number -} /** Dispense with given args. Requires tip. */ export const dispense: CommandCreator = ( args, @@ -32,7 +29,6 @@ export const dispense: CommandCreator = ( offsetFromBottomMm, flowRate, isAirGap, - pushOut, } = args const actionName = 'dispense' const errors: CommandCreatorError[] = [] @@ -174,7 +170,8 @@ export const dispense: CommandCreator = ( }, }, flowRate, - pushOut, + // pushOut will always be undefined in step-generation for now + // since there is no easy way to allow users to select a volume for it in PD }, ...(isAirGap && { meta: { isAirGap } }), }, diff --git a/step-generation/src/commandCreators/compound/transfer.ts b/step-generation/src/commandCreators/compound/transfer.ts index 9a3c1c3abb6..17ec220d1cf 100644 --- a/step-generation/src/commandCreators/compound/transfer.ts +++ b/step-generation/src/commandCreators/compound/transfer.ts @@ -98,7 +98,6 @@ export const transfer: CommandCreator = ( blowoutOffsetFromTopMm, dispenseFlowRateUlSec, dispenseOffsetFromBottomMm, - dispensePushOut, } = args const aspirateAirGapVolume = args.aspirateAirGapVolume || 0 const dispenseAirGapVolume = args.dispenseAirGapVolume || 0 @@ -441,7 +440,6 @@ export const transfer: CommandCreator = ( well: destWell, flowRate: dispenseFlowRateUlSec, offsetFromBottomMm: dispenseOffsetFromBottomMm, - pushOut: dispensePushOut ? subTransferVol : undefined, }), ...delayAfterDispenseCommands, ...mixInDestinationCommands, diff --git a/step-generation/src/types.ts b/step-generation/src/types.ts index cc6cfcb9ca9..8962c9121aa 100644 --- a/step-generation/src/types.ts +++ b/step-generation/src/types.ts @@ -196,8 +196,6 @@ export type SharedTransferLikeArgs = CommonArgs & { dispenseFlowRateUlSec: number /** offset from bottom of well in mm */ dispenseOffsetFromBottomMm: number - /** Push out param only in dispense */ - dispensePushOut: boolean } export type ConsolidateArgs = SharedTransferLikeArgs & { From 8dffe82c8d566c6362d53ba28cf4c95f086577ce Mon Sep 17 00:00:00 2001 From: Jethary Date: Tue, 12 Sep 2023 15:48:15 -0400 Subject: [PATCH 09/13] extend the configureForVolumeCommand to happen in mix form as well --- .../src/commandCreators/compound/mix.ts | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/step-generation/src/commandCreators/compound/mix.ts b/step-generation/src/commandCreators/compound/mix.ts index f0b23a92da5..557d32ac53d 100644 --- a/step-generation/src/commandCreators/compound/mix.ts +++ b/step-generation/src/commandCreators/compound/mix.ts @@ -12,6 +12,7 @@ import type { CurriedCommandCreator, } from '../../types' import { aspirate, dispense, delay, replaceTip, touchTip } from '../atomic' +import { configureForVolume } from '../atomic/configureForVolume' /** Helper fn to make mix command creators w/ minimal arguments */ export function mixUtil(args: { @@ -137,6 +138,18 @@ export const mix: CommandCreator = ( } } + const configureForVolumeCommand: CurriedCommandCreator[] = + volume <= 1 && + (invariantContext.pipetteEntities[pipette].name === 'p50_single_flex' || + invariantContext.pipetteEntities[pipette].name === 'p50_multi_flex') + ? [ + curryCommandCreator(configureForVolume, { + pipetteId: pipette, + volume: volume, + }), + ] + : [] + // Command generation const commandCreators = flatMap( wells, @@ -187,6 +200,7 @@ export const mix: CommandCreator = ( }) return [ ...tipCommands, + ...configureForVolumeCommand, ...mixCommands, ...blowoutCommand, ...touchTipCommands, From 78dee82ea0df88de6ae9d6d2783f70573c33ed65 Mon Sep 17 00:00:00 2001 From: Jethary Date: Tue, 12 Sep 2023 17:18:45 -0400 Subject: [PATCH 10/13] fix run log command text --- app/src/assets/localization/en/protocol_command_text.json | 4 ++-- app/src/organisms/CommandText/__tests__/CommandText.test.tsx | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/app/src/assets/localization/en/protocol_command_text.json b/app/src/assets/localization/en/protocol_command_text.json index 977c399ca31..a1476e8b77e 100644 --- a/app/src/assets/localization/en/protocol_command_text.json +++ b/app/src/assets/localization/en/protocol_command_text.json @@ -1,7 +1,7 @@ { "aspirate": "Aspirating {{volume}} µL from well {{well_name}} of {{labware}} in {{labware_location}} at {{flow_rate}} µL/sec", "blowout": "Blowing out at well {{well_name}} of {{labware}} in {{labware_location}} at {{flow_rate}} µL/sec", - "configure_for_volume": "Configure {{volume}} µL for aspirating with {{pipette}}", + "configure_for_volume": "Configure {{pipette}} to aspirate {{volume}} µL", "closing_tc_lid": "Closing Thermocycler lid", "comment": "Comment", "confirm_and_resume": "Confirm and resume", @@ -13,7 +13,7 @@ "degrees_c": "{{temp}}°C", "disengaging_magnetic_module": "Disengaging Magnetic Module", "dispense": "Dispensing {{volume}} µL into well {{well_name}} of {{labware}} in {{labware_location}} at {{flow_rate}} µL/sec", - "dispense_push_out": "Dispensing {{volume}} µL into well {{well_name}} of {{labware}} in {{labware_location}} at {{flow_rate}} µL/sec with push out volume {{push_out_volume}} µL", + "dispense_push_out": "Dispensing {{volume}} µL into well {{well_name}} of {{labware}} in {{labware_location}} at {{flow_rate}} µL/sec and pushing out {{push_out_volume}} µL", "drop_tip": "Dropping tip in {{well_name}} of {{labware}}", "engaging_magnetic_module": "Engaging Magnetic Module", "fixed_trash": "Fixed Trash", diff --git a/app/src/organisms/CommandText/__tests__/CommandText.test.tsx b/app/src/organisms/CommandText/__tests__/CommandText.test.tsx index b0380a5dc03..34b8438beab 100644 --- a/app/src/organisms/CommandText/__tests__/CommandText.test.tsx +++ b/app/src/organisms/CommandText/__tests__/CommandText.test.tsx @@ -74,7 +74,7 @@ describe('CommandText', () => { { i18nInstance: i18n } )[0] getByText( - 'Dispensing 100 µL into well A1 of NEST 96 Well Plate 100 µL PCR Full Skirt (1) in Magnetic Module GEN2 in Slot 1 at 300 µL/sec with push out volume 10 µL' + 'Dispensing 100 µL into well A1 of NEST 96 Well Plate 100 µL PCR Full Skirt (1) in Magnetic Module GEN2 in Slot 1 at 300 µL/sec and pushing out 10 µL' ) } }) @@ -136,7 +136,7 @@ describe('CommandText', () => { />, { i18nInstance: i18n } )[0] - getByText('Configure 1 µL for aspirating with P300 Single-Channel GEN1') + getByText('Configure P300 Single-Channel GEN1 to aspirate 1 µL') }) it('renders correct text for dropTip', () => { const command = mockRobotSideAnalysis.commands.find( From c133277a23a468e9d618299c5492cdda23868f02 Mon Sep 17 00:00:00 2001 From: Jethary Date: Tue, 12 Sep 2023 18:10:33 -0400 Subject: [PATCH 11/13] remove 1uL volume restriction and extend to consolidate --- .../commandCreators/compound/consolidate.ts | 19 +++++++++++++++++++ .../src/commandCreators/compound/mix.ts | 5 ++--- .../src/commandCreators/compound/transfer.ts | 7 +++---- 3 files changed, 24 insertions(+), 7 deletions(-) diff --git a/step-generation/src/commandCreators/compound/consolidate.ts b/step-generation/src/commandCreators/compound/consolidate.ts index cf4f746e612..78121caacbb 100644 --- a/step-generation/src/commandCreators/compound/consolidate.ts +++ b/step-generation/src/commandCreators/compound/consolidate.ts @@ -24,6 +24,7 @@ import { touchTip, } from '../atomic' import { mixUtil } from './mix' +import { configureForVolume } from '../atomic/configureForVolume' export const consolidate: CommandCreator = ( args, invariantContext, @@ -84,7 +85,11 @@ export const consolidate: CommandCreator = ( const destLabwareDef = invariantContext.labwareEntities[args.destLabware].def const airGapOffsetDestWell = getWellDepth(destLabwareDef, args.destWell) + AIR_GAP_OFFSET_FROM_TOP + const sourceWellChunks = chunk(args.sourceWells, maxWellsPerChunk) + const numOfWells = sourceWellChunks.flatMap(chunk => chunk).length + const totalVolumeAspirated = args.volume * numOfWells + const commandCreators = flatMap( sourceWellChunks, ( @@ -308,10 +313,24 @@ export const consolidate: CommandCreator = ( offsetFromTopMm: blowoutOffsetFromTopMm, invariantContext, }) + + const configureForVolumeCommand: CurriedCommandCreator[] = + invariantContext.pipetteEntities[args.pipette].name === + 'p50_single_flex' || + invariantContext.pipetteEntities[args.pipette].name === 'p50_multi_flex' + ? [ + curryCommandCreator(configureForVolume, { + pipetteId: args.pipette, + volume: totalVolumeAspirated, + }), + ] + : [] + return [ ...tipCommands, ...mixBeforeCommands, ...preWetTipCommands, // NOTE when you both mix-before and pre-wet tip, it's kinda redundant. Prewet is like mixing once. + ...configureForVolumeCommand, ...aspirateCommands, curryCommandCreator(dispense, { pipette: args.pipette, diff --git a/step-generation/src/commandCreators/compound/mix.ts b/step-generation/src/commandCreators/compound/mix.ts index 557d32ac53d..a37c75886e0 100644 --- a/step-generation/src/commandCreators/compound/mix.ts +++ b/step-generation/src/commandCreators/compound/mix.ts @@ -139,9 +139,8 @@ export const mix: CommandCreator = ( } const configureForVolumeCommand: CurriedCommandCreator[] = - volume <= 1 && - (invariantContext.pipetteEntities[pipette].name === 'p50_single_flex' || - invariantContext.pipetteEntities[pipette].name === 'p50_multi_flex') + invariantContext.pipetteEntities[pipette].name === 'p50_single_flex' || + invariantContext.pipetteEntities[pipette].name === 'p50_multi_flex' ? [ curryCommandCreator(configureForVolume, { pipetteId: pipette, diff --git a/step-generation/src/commandCreators/compound/transfer.ts b/step-generation/src/commandCreators/compound/transfer.ts index 17ec220d1cf..e0c014fb766 100644 --- a/step-generation/src/commandCreators/compound/transfer.ts +++ b/step-generation/src/commandCreators/compound/transfer.ts @@ -165,11 +165,10 @@ export const transfer: CommandCreator = ( } const configureForVolumeCommand: CurriedCommandCreator[] = - args.volume <= 1 && - (invariantContext.pipetteEntities[args.pipette].name === + invariantContext.pipetteEntities[args.pipette].name === 'p50_single_flex' || - invariantContext.pipetteEntities[args.pipette].name === - 'p50_multi_flex') + invariantContext.pipetteEntities[args.pipette].name === + 'p50_multi_flex' ? [ curryCommandCreator(configureForVolume, { pipetteId: args.pipette, From 96bcdcbe74a4e05e9211281898bfd0428d1db762 Mon Sep 17 00:00:00 2001 From: Jethary Date: Tue, 12 Sep 2023 18:23:46 -0400 Subject: [PATCH 12/13] slight tweak in consolidate configureForVolume volume logic --- step-generation/src/commandCreators/compound/consolidate.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/step-generation/src/commandCreators/compound/consolidate.ts b/step-generation/src/commandCreators/compound/consolidate.ts index 78121caacbb..9d5a7504da7 100644 --- a/step-generation/src/commandCreators/compound/consolidate.ts +++ b/step-generation/src/commandCreators/compound/consolidate.ts @@ -87,8 +87,6 @@ export const consolidate: CommandCreator = ( getWellDepth(destLabwareDef, args.destWell) + AIR_GAP_OFFSET_FROM_TOP const sourceWellChunks = chunk(args.sourceWells, maxWellsPerChunk) - const numOfWells = sourceWellChunks.flatMap(chunk => chunk).length - const totalVolumeAspirated = args.volume * numOfWells const commandCreators = flatMap( sourceWellChunks, @@ -321,7 +319,9 @@ export const consolidate: CommandCreator = ( ? [ curryCommandCreator(configureForVolume, { pipetteId: args.pipette, - volume: totalVolumeAspirated, + volume: + args.volume * sourceWellChunk.length + + aspirateAirGapVolume * sourceWellChunk.length, }), ] : [] From 103b957946759c79f4419e64282fdde76ce30bbe Mon Sep 17 00:00:00 2001 From: Jethary Date: Wed, 13 Sep 2023 08:32:39 -0400 Subject: [PATCH 13/13] add configureForVolume to cypress test fixture --- .../fixtures/protocol/7/doItAllV7.json | 220 +++++++++--------- .../commandCreators/compound/consolidate.ts | 12 +- .../commandCreators/compound/distribute.ts | 27 ++- .../src/commandCreators/compound/mix.ts | 5 +- .../src/commandCreators/compound/transfer.ts | 2 +- 5 files changed, 144 insertions(+), 122 deletions(-) diff --git a/protocol-designer/fixtures/protocol/7/doItAllV7.json b/protocol-designer/fixtures/protocol/7/doItAllV7.json index dbde26caf46..a4e49d049f6 100644 --- a/protocol-designer/fixtures/protocol/7/doItAllV7.json +++ b/protocol-designer/fixtures/protocol/7/doItAllV7.json @@ -4,7 +4,7 @@ "author": "", "description": "", "created": 1689346890165, - "lastModified": 1691185607319, + "lastModified": 1694608126903, "category": null, "subcategory": null, "tags": [] @@ -13,7 +13,7 @@ "name": "opentrons/protocol-designer", "version": "7.0.0", "data": { - "_internalAppBuildDate": "Fri, 04 Aug 2023 21:40:03 GMT", + "_internalAppBuildDate": "Wed, 13 Sep 2023 12:28:06 GMT", "defaultValues": { "aspirate_mmFromBottom": 1, "dispense_mmFromBottom": 0.5, @@ -3780,7 +3780,7 @@ "schemaVersion": 7, "commands": [ { - "key": "49d62252-5d6f-49b3-be15-406603d15910", + "key": "70156bb6-4e75-4087-94f5-367f832394f3", "commandType": "loadPipette", "params": { "pipetteName": "p1000_single_flex", @@ -3789,7 +3789,7 @@ } }, { - "key": "7e0defcb-656b-42a3-94e8-c7dee49f1d1b", + "key": "c0ebb2c1-211c-49cd-ad9a-f75f2fce17ce", "commandType": "loadPipette", "params": { "pipetteName": "p50_multi_flex", @@ -3798,7 +3798,7 @@ } }, { - "key": "6f29fa00-f993-44b1-a2f6-62f5112f0ad3", + "key": "878ea265-ee22-463b-a413-9219fa68f6b7", "commandType": "loadModule", "params": { "model": "magneticBlockV1", @@ -3807,7 +3807,7 @@ } }, { - "key": "ee9ee0f1-870c-45f4-8f41-38edb51f5498", + "key": "a0059887-8f94-49e1-a944-eec3e0656324", "commandType": "loadModule", "params": { "model": "heaterShakerModuleV1", @@ -3816,7 +3816,7 @@ } }, { - "key": "a38adb7d-f569-4bd8-afc9-5912ad6991e2", + "key": "0376b406-ea82-4abc-ac7f-7ffbbb2e92f2", "commandType": "loadModule", "params": { "model": "temperatureModuleV2", @@ -3825,7 +3825,7 @@ } }, { - "key": "8dbfacff-956b-412d-a568-0dff62c41dcd", + "key": "90a8b61d-2b53-4411-8766-dd4fd5b66129", "commandType": "loadModule", "params": { "model": "thermocyclerModuleV2", @@ -3834,7 +3834,7 @@ } }, { - "key": "23a9c172-8f8d-4bef-b679-2e22ccaf7e56", + "key": "dd191121-d799-4ea0-bb8a-a1e9a71ca9b0", "commandType": "loadLabware", "params": { "displayName": "Opentrons 96 Flat Bottom Adapter", @@ -3848,7 +3848,7 @@ } }, { - "key": "512168fc-0d1e-4232-b972-51bb7a418f28", + "key": "15e24d19-7413-4245-80f1-ff4a2790dd99", "commandType": "loadLabware", "params": { "displayName": "Opentrons Flex 96 Filter Tip Rack 50 µL", @@ -3860,7 +3860,7 @@ } }, { - "key": "40c35012-0e57-4569-9cb1-8d0adfd17c6d", + "key": "a126d484-3ca9-46f9-88f2-bc031b572dc5", "commandType": "loadLabware", "params": { "displayName": "NEST 96 Well Plate 100 µL PCR Full Skirt", @@ -3874,7 +3874,7 @@ } }, { - "key": "f8eff1d6-1925-43cb-8dde-7f9e32979fb5", + "key": "365d94e7-d09a-4f44-a2e3-3ac6962595a5", "commandType": "loadLabware", "params": { "displayName": "Opentrons 24 Well Aluminum Block with NEST 1.5 mL Snapcap", @@ -3888,7 +3888,7 @@ } }, { - "key": "54f9d3eb-4006-45cf-8ff2-ae07d2176bc4", + "key": "e140a07b-03eb-45f8-a889-28c6f383456d", "commandType": "loadLabware", "params": { "displayName": "NEST 96 Well Plate 200 µL Flat", @@ -3903,7 +3903,7 @@ }, { "commandType": "loadLiquid", - "key": "17687c7f-dbc0-4096-84d5-fc9010cf37e6", + "key": "7e318557-1dde-4e2a-a09b-5fc0969a422a", "params": { "liquidId": "1", "labwareId": "a793a135-06aa-4ed6-a1d3-c176c7810afa:opentrons/opentrons_24_aluminumblock_nest_1.5ml_snapcap/1", @@ -3912,7 +3912,7 @@ }, { "commandType": "loadLiquid", - "key": "129a7b9e-04fe-48b4-a2dc-7ed4ed59b797", + "key": "b9644425-85d3-40ef-b9d7-e954ad0ba0eb", "params": { "liquidId": "0", "labwareId": "fcba73e7-b88e-438e-963e-f8b9a5de0983:opentrons/nest_96_wellplate_100ul_pcr_full_skirt/2", @@ -3930,7 +3930,7 @@ }, { "commandType": "temperatureModule/setTargetTemperature", - "key": "b38c8ef6-1b5c-45b0-807b-15c9ef1f39bb", + "key": "b3971959-c9f3-45d4-b6b0-b1810ff6e439", "params": { "moduleId": "ef44ad7f-0fd9-46d6-8bc0-c70785644cc8:temperatureModuleType", "celsius": 4 @@ -3938,7 +3938,7 @@ }, { "commandType": "heaterShaker/waitForTemperature", - "key": "66f96b29-7dd4-4b71-a6f3-5a5734d409f8", + "key": "22456876-beab-4d63-b956-093ed1b1d721", "params": { "moduleId": "c19dffa3-cb34-4702-bcf6-dcea786257d1:heaterShakerModuleType", "celsius": 4 @@ -3946,14 +3946,14 @@ }, { "commandType": "thermocycler/closeLid", - "key": "8986aa12-f68d-4cd4-badf-607fc87cf57c", + "key": "415c4477-9920-4bfc-aa17-a18717479bfc", "params": { "moduleId": "627b7a27-5bb7-46de-a530-67af45652e3b:thermocyclerModuleType" } }, { "commandType": "thermocycler/setTargetLidTemperature", - "key": "d538c76a-5fd2-485f-a2d2-807743639f5b", + "key": "c42ab3d1-5391-4a65-afb1-4af732a30ffe", "params": { "moduleId": "627b7a27-5bb7-46de-a530-67af45652e3b:thermocyclerModuleType", "celsius": 40 @@ -3961,14 +3961,14 @@ }, { "commandType": "thermocycler/waitForLidTemperature", - "key": "f646fca7-a648-4491-91d0-2eb777132864", + "key": "201d0900-ac0d-41c5-b704-8e97833e8ab3", "params": { "moduleId": "627b7a27-5bb7-46de-a530-67af45652e3b:thermocyclerModuleType" } }, { "commandType": "thermocycler/runProfile", - "key": "e56e6f9a-94ba-4622-8c67-69afb04cbd84", + "key": "427f6fd3-1b12-4f4b-b7d7-30128b27be24", "params": { "moduleId": "627b7a27-5bb7-46de-a530-67af45652e3b:thermocyclerModuleType", "profile": [ @@ -3980,28 +3980,28 @@ }, { "commandType": "thermocycler/deactivateBlock", - "key": "524c27e2-ace3-42b8-b716-c85cf6d5174b", + "key": "27f65750-ddb8-41a2-bcec-7809b492257e", "params": { "moduleId": "627b7a27-5bb7-46de-a530-67af45652e3b:thermocyclerModuleType" } }, { "commandType": "thermocycler/deactivateLid", - "key": "f156f0d6-0e20-4d1c-b4ab-46a6ad3225c4", + "key": "beea24a1-2ae9-4919-91cf-e4bdcc65021e", "params": { "moduleId": "627b7a27-5bb7-46de-a530-67af45652e3b:thermocyclerModuleType" } }, { "commandType": "thermocycler/openLid", - "key": "ad01a08a-ec9e-4fea-92a1-accd7f9ee32c", + "key": "355a9342-7ee4-4093-b052-bc37cd1ff74b", "params": { "moduleId": "627b7a27-5bb7-46de-a530-67af45652e3b:thermocyclerModuleType" } }, { "commandType": "pickUpTip", - "key": "14c3dead-ed0d-4fe9-8414-b3a9a6e9d3ec", + "key": "dfc140ed-e295-4190-9219-6b591fe89c42", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "labwareId": "23ed35de-5bfd-4bb0-8f54-da99a2804ed9:opentrons/opentrons_flex_96_filtertiprack_50ul/1", @@ -4010,7 +4010,7 @@ }, { "commandType": "aspirate", - "key": "dbee48bf-d38d-4276-8700-281ada24588e", + "key": "7cffdd19-ba70-451e-af60-c79ca8a0da36", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "volume": 50, @@ -4022,7 +4022,7 @@ }, { "commandType": "dispense", - "key": "8d90daaf-798b-48c2-b713-1e35cdb63c95", + "key": "3bc64382-6327-4e47-b69a-1b96c511bb9a", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "volume": 50, @@ -4034,7 +4034,7 @@ }, { "commandType": "dropTip", - "key": "f140ad06-8c5c-4ddc-9d9f-86e42440ad61", + "key": "d7dac683-618f-4607-bd10-76018e59f88f", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "labwareId": "fixedTrash", @@ -4043,7 +4043,7 @@ }, { "commandType": "pickUpTip", - "key": "f67a1a2c-09bc-40c6-97f0-91a3d5837929", + "key": "3353be58-d98e-4d1f-a211-35396e066d60", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "labwareId": "23ed35de-5bfd-4bb0-8f54-da99a2804ed9:opentrons/opentrons_flex_96_filtertiprack_50ul/1", @@ -4052,7 +4052,7 @@ }, { "commandType": "aspirate", - "key": "a7856022-c305-469b-945d-6532884fe5f9", + "key": "f58188aa-f83c-4f30-bcd7-eb3c5ac41b66", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "volume": 50, @@ -4064,7 +4064,7 @@ }, { "commandType": "dispense", - "key": "eefc71fb-b7d2-4116-90f3-e0e10b40c8ce", + "key": "9eeba918-faac-41ad-b682-6a68df7b4e96", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "volume": 50, @@ -4076,7 +4076,7 @@ }, { "commandType": "dropTip", - "key": "99dcd1fe-7694-4903-8b5a-01feb359619e", + "key": "75e0e278-bb36-41ad-9fd1-a5e3115bd16c", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "labwareId": "fixedTrash", @@ -4085,7 +4085,7 @@ }, { "commandType": "pickUpTip", - "key": "e08580b4-8b3b-4651-b945-b1f87af70b0c", + "key": "8cf793df-1287-45f1-bf72-d3571d359be8", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "labwareId": "23ed35de-5bfd-4bb0-8f54-da99a2804ed9:opentrons/opentrons_flex_96_filtertiprack_50ul/1", @@ -4094,7 +4094,7 @@ }, { "commandType": "aspirate", - "key": "a9ea2067-0d19-4d5f-9ba0-93c16a787ee3", + "key": "37bee79d-086a-414f-8987-9d110d5c1796", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "volume": 50, @@ -4106,7 +4106,7 @@ }, { "commandType": "dispense", - "key": "208e0da5-9ec1-4769-861b-c0e60da60858", + "key": "b04afc19-fee4-4a1e-a99f-bd8c0b31ea6e", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "volume": 50, @@ -4118,7 +4118,7 @@ }, { "commandType": "dropTip", - "key": "af937bbc-466b-4b93-a2ad-4d1c1bfefd0a", + "key": "33b993e6-1bfa-4d31-9269-4efd343e2a74", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "labwareId": "fixedTrash", @@ -4127,7 +4127,7 @@ }, { "commandType": "pickUpTip", - "key": "f9de61a9-e76a-4528-a3c5-47906b7dc224", + "key": "2aa917c4-9ac0-464f-a41d-2974fd477ac0", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "labwareId": "23ed35de-5bfd-4bb0-8f54-da99a2804ed9:opentrons/opentrons_flex_96_filtertiprack_50ul/1", @@ -4136,7 +4136,7 @@ }, { "commandType": "aspirate", - "key": "ec25cc03-ce12-4c65-aad3-84e43b189580", + "key": "db3e5bd4-8511-4a0d-aff0-6bf351e1ea8b", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "volume": 50, @@ -4148,7 +4148,7 @@ }, { "commandType": "dispense", - "key": "7ccee701-6ed8-4899-b367-b7a271e7abf6", + "key": "85ae6787-4148-4c36-863d-75a5b473a0e0", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "volume": 50, @@ -4160,7 +4160,7 @@ }, { "commandType": "dropTip", - "key": "8b85901e-b982-47f2-a703-25ce815adedc", + "key": "01232d14-ee91-41fa-86a8-488ecb5a761f", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "labwareId": "fixedTrash", @@ -4169,7 +4169,7 @@ }, { "commandType": "pickUpTip", - "key": "fefdaf60-e8e6-467a-a20d-5437f7c251bb", + "key": "b8a7fb8a-585f-496c-acdf-48c1c0d62e0b", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "labwareId": "23ed35de-5bfd-4bb0-8f54-da99a2804ed9:opentrons/opentrons_flex_96_filtertiprack_50ul/1", @@ -4178,7 +4178,7 @@ }, { "commandType": "aspirate", - "key": "6303f384-1953-455e-b5db-14ae8ef1dc70", + "key": "1abd13f3-e1b5-4076-8735-566fd1d53d8f", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "volume": 50, @@ -4190,7 +4190,7 @@ }, { "commandType": "dispense", - "key": "64e10d16-6cc0-4fa8-ad62-6c5bdbf98394", + "key": "84024bde-4ba6-4c60-bfa4-a78e11979c11", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "volume": 50, @@ -4202,7 +4202,7 @@ }, { "commandType": "dropTip", - "key": "3a5ab4b1-a096-405f-9693-8aa24353f1c9", + "key": "5b5e6825-d964-4727-8e09-920bfe1f4c57", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "labwareId": "fixedTrash", @@ -4211,7 +4211,7 @@ }, { "commandType": "pickUpTip", - "key": "383de8a4-7b62-4a82-a1dc-f5a0eecb0363", + "key": "d482ac5f-dbd3-4d13-af2f-870d0a01524f", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "labwareId": "23ed35de-5bfd-4bb0-8f54-da99a2804ed9:opentrons/opentrons_flex_96_filtertiprack_50ul/1", @@ -4220,7 +4220,7 @@ }, { "commandType": "aspirate", - "key": "471d4d57-1916-495c-8d02-d727704edfd0", + "key": "854a437f-57b4-4fca-b13e-8041a2c4faed", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "volume": 50, @@ -4232,7 +4232,7 @@ }, { "commandType": "dispense", - "key": "30185e5a-5faf-4f85-a167-cd068cb422d2", + "key": "b8c9bb1c-2ccb-4e86-a947-ffca14897d6e", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "volume": 50, @@ -4244,7 +4244,7 @@ }, { "commandType": "dropTip", - "key": "d6178be1-dcad-47e6-8f9b-769ba40265ce", + "key": "556aa41f-bc79-4ef4-a136-b2c291883b49", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "labwareId": "fixedTrash", @@ -4253,7 +4253,7 @@ }, { "commandType": "pickUpTip", - "key": "e79bd7dd-33a0-4a7a-8b47-31e629a51dbb", + "key": "814f18f7-8c0b-4ba0-86fa-10f7b47b7f31", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "labwareId": "23ed35de-5bfd-4bb0-8f54-da99a2804ed9:opentrons/opentrons_flex_96_filtertiprack_50ul/1", @@ -4262,7 +4262,7 @@ }, { "commandType": "aspirate", - "key": "9e2df1bd-f686-4db4-92c4-ba192db4998e", + "key": "a1035705-a625-4cf7-ba2c-98910ecd4834", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "volume": 50, @@ -4274,7 +4274,7 @@ }, { "commandType": "dispense", - "key": "a4c4052c-ed7b-414a-a50e-d4c7d59c75ae", + "key": "6fde8e45-2e4a-4508-923a-1c908fcc2e9b", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "volume": 50, @@ -4286,7 +4286,7 @@ }, { "commandType": "dropTip", - "key": "582df64c-d73a-41ba-a698-c90270abc4eb", + "key": "7542bebc-c307-4e0e-b681-953b03089250", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "labwareId": "fixedTrash", @@ -4295,7 +4295,7 @@ }, { "commandType": "pickUpTip", - "key": "1296b841-7723-4ede-9738-b4f58a889e62", + "key": "2817eeb0-d727-497f-b7a9-1ab0e2472a6f", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "labwareId": "23ed35de-5bfd-4bb0-8f54-da99a2804ed9:opentrons/opentrons_flex_96_filtertiprack_50ul/1", @@ -4304,7 +4304,7 @@ }, { "commandType": "aspirate", - "key": "c26e6cb9-b7ff-4c1c-9c08-d09524ce6853", + "key": "2fee1a7c-754e-453a-a38e-08e2d6770b72", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "volume": 50, @@ -4316,7 +4316,7 @@ }, { "commandType": "dispense", - "key": "8193fc98-fa2b-4d1a-bc20-bae2e6593dfc", + "key": "589d0c90-0dcb-4d3d-add7-47f27c2a1c8e", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "volume": 50, @@ -4328,7 +4328,7 @@ }, { "commandType": "dropTip", - "key": "86cca784-b360-4f46-acdd-d8de769bed3d", + "key": "7bf8e6b3-6121-4c79-a40f-4f95e71a4081", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "labwareId": "fixedTrash", @@ -4337,7 +4337,7 @@ }, { "commandType": "pickUpTip", - "key": "8af9cced-a9a7-4f2a-a0eb-d3d173ecb8ba", + "key": "81a081d2-014d-46a8-84a0-32c5db561c43", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "labwareId": "23ed35de-5bfd-4bb0-8f54-da99a2804ed9:opentrons/opentrons_flex_96_filtertiprack_50ul/1", @@ -4346,7 +4346,7 @@ }, { "commandType": "aspirate", - "key": "8955bc00-b5b0-4488-ba42-915879f8208a", + "key": "d760060f-8936-409d-8329-d6986d48c1f8", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "volume": 50, @@ -4358,7 +4358,7 @@ }, { "commandType": "dispense", - "key": "2c8fddb0-cda6-411e-a38a-6258a28dd2b0", + "key": "577080fc-ef68-4415-b06c-a48342d8ec53", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "volume": 50, @@ -4370,7 +4370,7 @@ }, { "commandType": "dropTip", - "key": "8a3d105c-79d1-4370-84c7-9833f315623f", + "key": "4fc4d1e2-4979-4706-87dc-020947b85b7e", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "labwareId": "fixedTrash", @@ -4379,7 +4379,7 @@ }, { "commandType": "pickUpTip", - "key": "380d9b1d-778e-4779-9f2c-8b525c5c07d2", + "key": "916572b4-00f7-4af5-bccd-9a015bf22f6b", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "labwareId": "23ed35de-5bfd-4bb0-8f54-da99a2804ed9:opentrons/opentrons_flex_96_filtertiprack_50ul/1", @@ -4388,7 +4388,7 @@ }, { "commandType": "aspirate", - "key": "ed622694-97bc-4c35-88cd-e7684470bb28", + "key": "3f114a9b-98a0-4f8b-b2de-973d0ae9c477", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "volume": 50, @@ -4400,7 +4400,7 @@ }, { "commandType": "dispense", - "key": "b9ee4d10-4338-4c0f-b1ed-43b0e1ede649", + "key": "2c73cf41-93ee-48cc-b382-17fd28adc799", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "volume": 50, @@ -4412,7 +4412,7 @@ }, { "commandType": "dropTip", - "key": "7aac9cb7-8390-4ec1-a17e-49c69ff09535", + "key": "48ac1ee7-0ea4-4805-9c0f-30ff75aa5cb2", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "labwareId": "fixedTrash", @@ -4421,7 +4421,7 @@ }, { "commandType": "pickUpTip", - "key": "f8b27e94-2a7f-4c76-bd41-b92662b3d056", + "key": "25acd345-f9bd-4b23-9994-24da11a487ac", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "labwareId": "23ed35de-5bfd-4bb0-8f54-da99a2804ed9:opentrons/opentrons_flex_96_filtertiprack_50ul/1", @@ -4430,7 +4430,7 @@ }, { "commandType": "aspirate", - "key": "52b18cb2-3fd3-4047-9e67-932f67d942e5", + "key": "16b20b99-6d3b-43e5-8e8f-4292150e120f", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "volume": 50, @@ -4442,7 +4442,7 @@ }, { "commandType": "dispense", - "key": "2178697e-efc6-4904-83dc-058ff4353c73", + "key": "c1b60549-7bfa-449e-8fb0-0dbc53d2a94b", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "volume": 50, @@ -4454,7 +4454,7 @@ }, { "commandType": "dropTip", - "key": "3b5a8693-1dc8-4fe1-ade2-4e8c09b4b96c", + "key": "8f027197-902b-4e1f-b3f6-1caa57cb1700", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "labwareId": "fixedTrash", @@ -4463,7 +4463,7 @@ }, { "commandType": "pickUpTip", - "key": "e6fbf4bb-243e-434f-95d5-950ceffda3c2", + "key": "c6854d17-1ed0-4941-acd3-988c6c78e1e0", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "labwareId": "23ed35de-5bfd-4bb0-8f54-da99a2804ed9:opentrons/opentrons_flex_96_filtertiprack_50ul/1", @@ -4472,7 +4472,7 @@ }, { "commandType": "aspirate", - "key": "b3ed0d22-8a31-41b7-b64e-588cb0bbdea1", + "key": "2a8e835f-a83b-4f5f-a4f1-c6b1261e06b3", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "volume": 50, @@ -4484,7 +4484,7 @@ }, { "commandType": "dispense", - "key": "9f764ae2-304f-4e9a-b0bf-9083ddd8ad80", + "key": "76bb8b02-161c-4850-aa6c-fbacef751ad1", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "volume": 50, @@ -4496,7 +4496,7 @@ }, { "commandType": "dropTip", - "key": "09a04113-fc39-408e-841b-884d789d4cf3", + "key": "2a1ab90d-14f2-4452-be8b-381735223c74", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "labwareId": "fixedTrash", @@ -4505,7 +4505,7 @@ }, { "commandType": "pickUpTip", - "key": "39992027-9f74-4712-bb9c-005fb6e176d0", + "key": "3df1d6f7-65cf-42f6-8a9f-7af01cb96eec", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "labwareId": "23ed35de-5bfd-4bb0-8f54-da99a2804ed9:opentrons/opentrons_flex_96_filtertiprack_50ul/1", @@ -4514,7 +4514,7 @@ }, { "commandType": "aspirate", - "key": "5b0d2d8a-e21c-4ae7-9c5f-79ef411a679e", + "key": "8b5c0df0-0b33-4405-815d-03672b2b7fba", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "volume": 50, @@ -4526,7 +4526,7 @@ }, { "commandType": "dispense", - "key": "249bb729-a402-4836-955b-a6d90a1fd0d3", + "key": "4481a649-9c2f-4f97-8c00-1e57c1de4c61", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "volume": 50, @@ -4538,7 +4538,7 @@ }, { "commandType": "dropTip", - "key": "c750c0a5-409a-4ad8-befe-3a13a3e15d31", + "key": "c5766753-b837-4f65-89ba-167cd941378f", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "labwareId": "fixedTrash", @@ -4547,7 +4547,7 @@ }, { "commandType": "pickUpTip", - "key": "6e010bf2-a20f-48fc-9232-90df3e246926", + "key": "1606194c-fa97-40c4-98bb-beb05bdbe300", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "labwareId": "23ed35de-5bfd-4bb0-8f54-da99a2804ed9:opentrons/opentrons_flex_96_filtertiprack_50ul/1", @@ -4556,7 +4556,7 @@ }, { "commandType": "aspirate", - "key": "b430b928-87da-4519-a8aa-adeabdde996a", + "key": "5b486cbe-4bd5-4b62-82f4-c4e14e7b6df8", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "volume": 50, @@ -4568,7 +4568,7 @@ }, { "commandType": "dispense", - "key": "6f495c52-47e9-46bd-afee-2a4d0639042c", + "key": "a2c1cafa-3dde-4805-8844-0cf4fe9e7a1f", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "volume": 50, @@ -4580,7 +4580,7 @@ }, { "commandType": "dropTip", - "key": "e7cb5774-9f5a-4eff-a9e6-374e991a3e16", + "key": "f2f315ec-6b0b-4100-ba3f-c9971858e5f5", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "labwareId": "fixedTrash", @@ -4589,7 +4589,7 @@ }, { "commandType": "pickUpTip", - "key": "7608979f-e0ad-4c85-9269-6236d769d0f3", + "key": "e45c5974-d348-4171-9247-be27a2e7bb53", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "labwareId": "23ed35de-5bfd-4bb0-8f54-da99a2804ed9:opentrons/opentrons_flex_96_filtertiprack_50ul/1", @@ -4598,7 +4598,7 @@ }, { "commandType": "aspirate", - "key": "7ed5c301-d2ce-4681-9a73-fcac21ce1ab0", + "key": "31402b63-3c1a-4d2f-a8e4-14c2322945cc", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "volume": 50, @@ -4610,7 +4610,7 @@ }, { "commandType": "dispense", - "key": "c5669a06-8892-4d41-b9bf-6ea42cec0a67", + "key": "f17998bd-207f-46c9-91e0-79fec2d7ee10", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "volume": 50, @@ -4622,7 +4622,7 @@ }, { "commandType": "dropTip", - "key": "be3570a9-f229-42d6-a6d5-342062fcb64a", + "key": "7cb12333-4765-4eff-992a-c51683073b2c", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "labwareId": "fixedTrash", @@ -4631,7 +4631,7 @@ }, { "commandType": "pickUpTip", - "key": "bf270b75-2e26-4c85-97e5-ba4ceea657bb", + "key": "d014eb58-5f6f-4e89-8bb2-e1cbc5be9a2e", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "labwareId": "23ed35de-5bfd-4bb0-8f54-da99a2804ed9:opentrons/opentrons_flex_96_filtertiprack_50ul/1", @@ -4640,7 +4640,7 @@ }, { "commandType": "aspirate", - "key": "eb6625a6-9167-4bf9-8301-ed2a3fa47c5a", + "key": "19aa7563-cc15-4834-a54c-984493397047", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "volume": 50, @@ -4652,7 +4652,7 @@ }, { "commandType": "dispense", - "key": "5e7eb8c8-4fc2-4067-bfb4-5db659dd632d", + "key": "e5d379f2-a2c2-48ac-b136-a374411d7176", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "volume": 50, @@ -4664,7 +4664,7 @@ }, { "commandType": "dropTip", - "key": "fb11c874-c347-4b70-a6ce-2310e6fc6413", + "key": "b0029b7b-005b-4243-85cb-4ab4acbd921a", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "labwareId": "fixedTrash", @@ -4673,16 +4673,24 @@ }, { "commandType": "pickUpTip", - "key": "1c4414b1-1f76-4810-a138-d42c935e1e8b", + "key": "d87b020c-20a9-4283-8e91-5e0dc931e642", "params": { "pipetteId": "6d1e53c3-2db3-451b-ad60-3fe13781a193", "labwareId": "23ed35de-5bfd-4bb0-8f54-da99a2804ed9:opentrons/opentrons_flex_96_filtertiprack_50ul/1", "wellName": "A3" } }, + { + "commandType": "configureForVolume", + "key": "ea06c743-d0ce-477a-9e35-b65513004622", + "params": { + "pipetteId": "6d1e53c3-2db3-451b-ad60-3fe13781a193", + "volume": 10 + } + }, { "commandType": "aspirate", - "key": "834329f1-77c2-44e6-a2aa-0c31a961432d", + "key": "f6b08f38-4a3e-4f36-a6df-63bbdefb8210", "params": { "pipetteId": "6d1e53c3-2db3-451b-ad60-3fe13781a193", "volume": 10, @@ -4694,7 +4702,7 @@ }, { "commandType": "dispense", - "key": "48284ea5-688c-4130-b5b4-2b4a4e7dd20c", + "key": "4538bae6-4299-4eef-bd26-997383eab06e", "params": { "pipetteId": "6d1e53c3-2db3-451b-ad60-3fe13781a193", "volume": 10, @@ -4706,7 +4714,7 @@ }, { "commandType": "aspirate", - "key": "5f366117-ca67-4849-98fc-39bab0299a1b", + "key": "b07f9f5c-11cf-4892-a862-fd432b5e0eb6", "params": { "pipetteId": "6d1e53c3-2db3-451b-ad60-3fe13781a193", "volume": 10, @@ -4718,7 +4726,7 @@ }, { "commandType": "dispense", - "key": "822cd50c-56e3-433b-8b45-137d939de809", + "key": "22f9e9df-5d7e-4bf0-8a4d-eb1b33a877ff", "params": { "pipetteId": "6d1e53c3-2db3-451b-ad60-3fe13781a193", "volume": 10, @@ -4730,7 +4738,7 @@ }, { "commandType": "dropTip", - "key": "d44d7193-abc6-4cc9-8eb7-348c16156534", + "key": "d21ae698-a0cc-4bb6-a284-de36b4ad0fbe", "params": { "pipetteId": "6d1e53c3-2db3-451b-ad60-3fe13781a193", "labwareId": "fixedTrash", @@ -4739,7 +4747,7 @@ }, { "commandType": "moveLabware", - "key": "039c3c41-7605-43bf-847f-6d37643a2fca", + "key": "d8c662b8-e0c9-40dd-8874-d89e1da1f57b", "params": { "labwareId": "fcba73e7-b88e-438e-963e-f8b9a5de0983:opentrons/nest_96_wellplate_100ul_pcr_full_skirt/2", "strategy": "usingGripper", @@ -4748,12 +4756,12 @@ }, { "commandType": "waitForDuration", - "key": "51134e29-57f7-4fbb-93be-7d7ce662cd7e", + "key": "db02ab6c-fc45-4840-acda-6f79acaa463b", "params": { "seconds": 60, "message": "" } }, { "commandType": "moveLabware", - "key": "5c37a758-6489-4318-ab8a-18d3b5b15ade", + "key": "651accac-df1d-4200-9854-7e6373ce4755", "params": { "labwareId": "fcba73e7-b88e-438e-963e-f8b9a5de0983:opentrons/nest_96_wellplate_100ul_pcr_full_skirt/2", "strategy": "usingGripper", @@ -4762,21 +4770,21 @@ }, { "commandType": "heaterShaker/closeLabwareLatch", - "key": "226f31dd-0222-46cb-9a65-99a252be4bd5", + "key": "505c8515-c61d-41c9-b318-fe0aae624251", "params": { "moduleId": "c19dffa3-cb34-4702-bcf6-dcea786257d1:heaterShakerModuleType" } }, { "commandType": "heaterShaker/deactivateHeater", - "key": "4c100b01-6548-4e4a-8900-4e21b1bd2ee2", + "key": "1bbdb172-f0fe-4b1c-b8dd-d2833efdd5c8", "params": { "moduleId": "c19dffa3-cb34-4702-bcf6-dcea786257d1:heaterShakerModuleType" } }, { "commandType": "heaterShaker/setAndWaitForShakeSpeed", - "key": "3e2cd99e-30da-4f01-9e84-52134987c34c", + "key": "435d2707-dbb0-4339-af9f-13255464dfca", "params": { "moduleId": "c19dffa3-cb34-4702-bcf6-dcea786257d1:heaterShakerModuleType", "rpm": 500 @@ -4784,28 +4792,28 @@ }, { "commandType": "heaterShaker/deactivateHeater", - "key": "daa98a92-2e2f-46ea-be14-7c0b16217d8d", + "key": "632c1e11-8a4b-418c-9db3-331eb7dfcee8", "params": { "moduleId": "c19dffa3-cb34-4702-bcf6-dcea786257d1:heaterShakerModuleType" } }, { "commandType": "heaterShaker/deactivateShaker", - "key": "98a0d76e-b158-49cb-9662-1c5299ee6aa2", + "key": "9415ddab-dc51-4c00-ac29-1ed4619f0136", "params": { "moduleId": "c19dffa3-cb34-4702-bcf6-dcea786257d1:heaterShakerModuleType" } }, { "commandType": "heaterShaker/openLabwareLatch", - "key": "f5838949-9116-4349-8535-99def9dd5060", + "key": "f07e3aeb-4af7-4641-8f68-44011dc5f7ea", "params": { "moduleId": "c19dffa3-cb34-4702-bcf6-dcea786257d1:heaterShakerModuleType" } }, { "commandType": "moveLabware", - "key": "25aa76c0-f6d1-46e0-9663-29e567404f54", + "key": "99f93f6f-eadf-4b4d-bb4d-c630af96abc3", "params": { "labwareId": "a793a135-06aa-4ed6-a1d3-c176c7810afa:opentrons/opentrons_24_aluminumblock_nest_1.5ml_snapcap/1", "strategy": "manualMoveWithPause", @@ -4814,14 +4822,14 @@ }, { "commandType": "temperatureModule/deactivate", - "key": "07407fdd-5f46-48a1-af8e-68cd0cfb75d3", + "key": "192e4aca-9efd-4b61-af6b-a6517dcce079", "params": { "moduleId": "ef44ad7f-0fd9-46d6-8bc0-c70785644cc8:temperatureModuleType" } }, { "commandType": "moveLabware", - "key": "72c4d774-6c86-48e6-b695-fb0e362bcc48", + "key": "ab2b9475-4570-4764-acb4-a21245346b97", "params": { "labwareId": "239ceac8-23ec-4900-810a-70aeef880273:opentrons/nest_96_wellplate_200ul_flat/2", "strategy": "manualMoveWithPause", diff --git a/step-generation/src/commandCreators/compound/consolidate.ts b/step-generation/src/commandCreators/compound/consolidate.ts index 9d5a7504da7..b0cef9f7eb0 100644 --- a/step-generation/src/commandCreators/compound/consolidate.ts +++ b/step-generation/src/commandCreators/compound/consolidate.ts @@ -4,16 +4,12 @@ import { getWellDepth } from '@opentrons/shared-data' import { AIR_GAP_OFFSET_FROM_TOP } from '../../constants' import * as errorCreators from '../../errorCreators' import { getPipetteWithTipMaxVol } from '../../robotStateSelectors' -import type { - ConsolidateArgs, - CommandCreator, - CurriedCommandCreator, -} from '../../types' import { blowoutUtil, curryCommandCreator, reduceCommandCreators, } from '../../utils' +import { configureForVolume } from '../atomic/configureForVolume' import { aspirate, delay, @@ -24,7 +20,11 @@ import { touchTip, } from '../atomic' import { mixUtil } from './mix' -import { configureForVolume } from '../atomic/configureForVolume' +import type { + ConsolidateArgs, + CommandCreator, + CurriedCommandCreator, +} from '../../types' export const consolidate: CommandCreator = ( args, invariantContext, diff --git a/step-generation/src/commandCreators/compound/distribute.ts b/step-generation/src/commandCreators/compound/distribute.ts index c3973cc9904..905a36d91dc 100644 --- a/step-generation/src/commandCreators/compound/distribute.ts +++ b/step-generation/src/commandCreators/compound/distribute.ts @@ -5,6 +5,12 @@ import { getWellDepth } from '@opentrons/shared-data' import { AIR_GAP_OFFSET_FROM_TOP } from '../../constants' import * as errorCreators from '../../errorCreators' import { getPipetteWithTipMaxVol } from '../../robotStateSelectors' +import { + curryCommandCreator, + reduceCommandCreators, + blowoutUtil, + getDispenseAirGapLocation, +} from '../../utils' import { aspirate, delay, @@ -14,13 +20,8 @@ import { replaceTip, touchTip, } from '../atomic' +import { configureForVolume } from '../atomic/configureForVolume' import { mixUtil } from './mix' -import { - curryCommandCreator, - reduceCommandCreators, - blowoutUtil, - getDispenseAirGapLocation, -} from '../../utils' import type { DistributeArgs, CommandCreator, @@ -345,9 +346,23 @@ export const distribute: CommandCreator = ( dispenseDelaySeconds: dispenseDelay?.seconds, }) : [] + + const configureForVolumeCommand: CurriedCommandCreator[] = + invariantContext.pipetteEntities[args.pipette].name === + 'p50_single_flex' || + invariantContext.pipetteEntities[args.pipette].name === 'p50_multi_flex' + ? [ + curryCommandCreator(configureForVolume, { + pipetteId: args.pipette, + volume: args.volume * destWellChunk.length + disposalVolume, + }), + ] + : [] + return [ ...tipCommands, ...mixBeforeAspirateCommands, + ...configureForVolumeCommand, curryCommandCreator(aspirate, { pipette, volume: args.volume * destWellChunk.length + disposalVolume, diff --git a/step-generation/src/commandCreators/compound/mix.ts b/step-generation/src/commandCreators/compound/mix.ts index a37c75886e0..2f0f3c4dfa1 100644 --- a/step-generation/src/commandCreators/compound/mix.ts +++ b/step-generation/src/commandCreators/compound/mix.ts @@ -6,14 +6,13 @@ import { reduceCommandCreators, } from '../../utils' import * as errorCreators from '../../errorCreators' +import { configureForVolume } from '../atomic/configureForVolume' +import { aspirate, dispense, delay, replaceTip, touchTip } from '../atomic' import type { MixArgs, CommandCreator, CurriedCommandCreator, } from '../../types' -import { aspirate, dispense, delay, replaceTip, touchTip } from '../atomic' -import { configureForVolume } from '../atomic/configureForVolume' - /** Helper fn to make mix command creators w/ minimal arguments */ export function mixUtil(args: { pipette: string diff --git a/step-generation/src/commandCreators/compound/transfer.ts b/step-generation/src/commandCreators/compound/transfer.ts index e0c014fb766..19cacdfc13d 100644 --- a/step-generation/src/commandCreators/compound/transfer.ts +++ b/step-generation/src/commandCreators/compound/transfer.ts @@ -19,6 +19,7 @@ import { touchTip, moveToWell, } from '../atomic' +import { configureForVolume } from '../atomic/configureForVolume' import { mixUtil } from './mix' import type { TransferArgs, @@ -26,7 +27,6 @@ import type { CommandCreator, CommandCreatorError, } from '../../types' -import { configureForVolume } from '../atomic/configureForVolume' export const transfer: CommandCreator = ( args, invariantContext,