Skip to content

Commit 8a69884

Browse files
authored
feat(app, shared-data): update live vacuum module commands - pump controls (#21282)
This PR updates the start and deactivate pump commands for the vacuum module in the app, according to their recent additions as Protocol Engine commands. In scope is updating the shared-data types for the create command endpoints and params.
1 parent bc39e0b commit 8a69884

10 files changed

Lines changed: 100 additions & 42 deletions

File tree

api/src/opentrons/protocol_engine/commands/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
temperature_module,
2424
thermocycler,
2525
unsafe,
26+
vacuum_module,
2627
)
2728
from .air_gap_in_place import (
2829
AirGapInPlace,
@@ -686,6 +687,7 @@
686687
"magnetic_module",
687688
"temperature_module",
688689
"thermocycler",
690+
"vacuum_module",
689691
# calibration command bundle
690692
"calibration",
691693
# unsafe command bundle

app/src/assets/localization/en/device_details.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,7 @@
241241
"usb_port_stacker": "S-{{port}}",
242242
"vacuum_module": "Vacuum Module",
243243
"vacuum_pump": "Vacuum Pump",
244+
"vacuum_range_error": "Gauge pressure must be between {{min}} and {{max}} mbar",
244245
"valid_range": "Valid range between {{min}}-{{max}}",
245246
"vent": "Vent",
246247
"vent_closed": "Closed",

app/src/organisms/ModuleCard/VacuumModule/VacuumModuleSlideout.tsx

Lines changed: 26 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,16 @@ import { SubmitPrimaryButton } from '/app/atoms/buttons'
1919
import { Slideout } from '/app/atoms/Slideout'
2020

2121
import { useVacuumModuleControls } from './hooks/useVacuumModuleControls'
22+
import { parseGaugePressureValue } from './utils/parseGaugePressureValue'
23+
import { sanitizeGaugePressureInput } from './utils/sanitizeGaugePressureInput'
2224
import styles from './vacuummodule.module.css'
2325

2426
import type { VacuumMode } from '/app/redux/modules/api-types'
2527
import type { VacuumModule } from '/app/redux/modules/types'
2628

27-
// TODO: get from module definition or equivalent
28-
const MAX_PRESSURE = 1000
29-
const MIN_PRESSURE = 0
29+
// TODO: get from module definition or equivalent; If not, export to a shared location
30+
const MAX_PRESSURE = 0
31+
const MIN_PRESSURE = -200
3032

3133
interface VacuumModuleSlideoutProps {
3234
module: VacuumModule
@@ -41,10 +43,15 @@ export function VacuumModuleSlideout(
4143
const { moduleModel } = module
4244
const { t } = useTranslation('device_details')
4345
const [modeType, setModeType] = useState<VacuumMode | null>(null)
44-
const [pressure, setPressure] = useState<number | null>(null)
46+
const [pressureInput, setPressureInput] = useState<string>('')
4547
const [powerPercent, setPowerPercent] = useState<number>(1)
4648
const [targetProps, tooltipProps] = useHoverTooltip()
4749
const { setVacuumPressure, setVacuumPower } = useVacuumModuleControls(module)
50+
const [showPressureRangeError, setShowPressureRangeError] =
51+
useState<boolean>(false)
52+
const pressure = parseGaugePressureValue(pressureInput)
53+
const isPressureRangeError =
54+
pressure != null && (pressure < MIN_PRESSURE || pressure > MAX_PRESSURE)
4855

4956
const handleConfirm = (): void => {
5057
if (modeType == null) {
@@ -54,6 +61,10 @@ export function VacuumModuleSlideout(
5461
setVacuumPower(powerPercent)
5562
} else if (pressure != null) {
5663
// non-null pressure value with pressure mode selected
64+
if (isPressureRangeError) {
65+
setShowPressureRangeError(true)
66+
return
67+
}
5768
setVacuumPressure(pressure)
5869
} else {
5970
return
@@ -133,13 +144,19 @@ export function VacuumModuleSlideout(
133144
max: MAX_PRESSURE,
134145
})}
135146
units={t('mbar')}
136-
type="number"
147+
type="text"
137148
onChange={e => {
138-
setPressure(e.target.valueAsNumber)
149+
setPressureInput(sanitizeGaugePressureInput(e.target.value))
139150
}}
140-
value={pressure}
141-
max={MAX_PRESSURE}
142-
min={MIN_PRESSURE}
151+
value={pressureInput}
152+
error={
153+
showPressureRangeError && isPressureRangeError
154+
? t('vacuum_range_error', {
155+
min: MIN_PRESSURE,
156+
max: MAX_PRESSURE,
157+
})
158+
: null
159+
}
143160
/>
144161
)}
145162
{modeType === 'power' && (

app/src/organisms/ModuleCard/VacuumModule/__tests__/VacuumModuleSlideout.test.tsx

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ describe('VacuumModuleSlideout', () => {
9191
fireEvent.click(pressureButton)
9292

9393
expect(screen.getByText('Gauge pressure')).toBeInTheDocument()
94-
expect(screen.getByText('Valid range between 0-1000')).toBeInTheDocument()
94+
expect(screen.getByText('Valid range between -200-0')).toBeInTheDocument()
9595
expect(screen.getByText('mbar')).toBeInTheDocument()
9696
})
9797

@@ -141,10 +141,8 @@ describe('VacuumModuleSlideout', () => {
141141
const pressureButton = screen.getByLabelText('Pressure')
142142
fireEvent.click(pressureButton)
143143

144-
const input = screen.getByRole('spinbutton')
145-
fireEvent.change(input, { target: { value: '500' } })
146-
147-
expect(input).toHaveValue(500)
144+
screen.getByText('Gauge pressure')
145+
screen.getByText('Valid range between -200-0')
148146
})
149147

150148
it('calls setVacuumPressure with correct value when confirming in pressure mode', () => {
@@ -153,15 +151,15 @@ describe('VacuumModuleSlideout', () => {
153151
const pressureButton = screen.getByLabelText('Pressure')
154152
fireEvent.click(pressureButton)
155153

156-
const input = screen.getByRole('spinbutton')
157-
fireEvent.change(input, { target: { value: '500' } })
154+
const input = screen.getByLabelText('Gauge pressure')
155+
fireEvent.change(input, { target: { value: '-50' } })
158156

159157
const confirmButton = screen.getByTestId(
160158
`VacuumModuleSlideout_btn_${mockVacuumModule.serialNumber}`
161159
)
162160
fireEvent.click(confirmButton)
163161

164-
expect(mockSetVacuumPressure).toHaveBeenCalledWith(500)
162+
expect(mockSetVacuumPressure).toHaveBeenCalledWith(-50)
165163
expect(mockSetVacuumPower).not.toHaveBeenCalled()
166164
expect(mockOnCloseClick).toHaveBeenCalled()
167165
})

app/src/organisms/ModuleCard/VacuumModule/hooks/__tests__/useVacuumModuleControls.test.tsx

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -85,10 +85,10 @@ describe('useVacuumModuleControls', () => {
8585

8686
expect(mockCreateLiveCommand).toHaveBeenCalledWith({
8787
command: {
88-
commandType: 'vacuumModule/setTargetPressure',
88+
commandType: 'vacuumModule/startSetVacuumPressure',
8989
params: {
9090
moduleId: 'vacuum_id',
91-
pressure: 500,
91+
gaugePressure: 500,
9292
},
9393
},
9494
})
@@ -107,10 +107,10 @@ describe('useVacuumModuleControls', () => {
107107

108108
expect(mockCreateLiveCommand).toHaveBeenCalledWith({
109109
command: {
110-
commandType: 'vacuumModule/setTargetPower',
110+
commandType: 'vacuumModule/startSetVacuumPower',
111111
params: {
112112
moduleId: 'vacuum_id',
113-
power: 75,
113+
percentPower: 75,
114114
},
115115
},
116116
})
@@ -129,7 +129,7 @@ describe('useVacuumModuleControls', () => {
129129

130130
expect(mockCreateLiveCommand).toHaveBeenCalledWith({
131131
command: {
132-
commandType: 'vacuumModule/deactivate',
132+
commandType: 'vacuumModule/stopVacuum',
133133
params: {
134134
moduleId: 'vacuum_id',
135135
},
@@ -195,7 +195,7 @@ describe('useVacuumModuleControls', () => {
195195
expect(mockReportModuleCommand).toHaveBeenCalledWith({
196196
kind: 'liveCommand',
197197
moduleType: 'vacuumModuleType',
198-
analyticCommand: 'vacuumModule/deactivate',
198+
analyticCommand: 'vacuumModule/stopVacuum',
199199
result: { status: 'succeeded', data: undefined },
200200
serialNumber: 'vac123',
201201
errorDetails: '',

app/src/organisms/ModuleCard/VacuumModule/hooks/useVacuumModuleControls.tsx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -72,26 +72,26 @@ export function useVacuumModuleControls(
7272

7373
const setVacuumPressure = (pressure: number): void => {
7474
const command: VacuumModuleSetTargetPressureCreateCommand = {
75-
commandType: 'vacuumModule/setTargetPressure',
75+
commandType: 'vacuumModule/startSetVacuumPressure',
7676
params: {
7777
moduleId: module.id,
78-
pressure,
78+
gaugePressure: pressure,
7979
},
8080
}
8181
executeCommand(command)
8282
}
8383

8484
const setVacuumPower = (power: number): void => {
8585
const command: VacuumModuleSetTargetPowerCreateCommand = {
86-
commandType: 'vacuumModule/setTargetPower',
87-
params: { moduleId: module.id, power },
86+
commandType: 'vacuumModule/startSetVacuumPower',
87+
params: { moduleId: module.id, percentPower: power },
8888
}
8989
executeCommand(command)
9090
}
9191

9292
const deactivateVacuum = (): void => {
9393
const command: VacuumModuleDeactivateCreateCommand = {
94-
commandType: 'vacuumModule/deactivate',
94+
commandType: 'vacuumModule/stopVacuum',
9595
params: { moduleId: module.id },
9696
}
9797
executeCommand(command)
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
export const parseGaugePressureValue = (input: string): number => {
2+
if (input === '' || input === '-' || input === '.' || input === '-.') {
3+
return 0
4+
}
5+
return Number(input)
6+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
/** Allow optional leading `-` only, then digits with at most one `.`. */
2+
export const sanitizeGaugePressureInput = (raw: string): string => {
3+
let out = ''
4+
let i = 0
5+
if (raw[0] === '-') {
6+
out = '-'
7+
i = 1
8+
}
9+
let seenDecimal = false
10+
for (; i < raw.length; i++) {
11+
const c = raw[i]
12+
if (c >= '0' && c <= '9') {
13+
out += c
14+
} else if (c === '.' && !seenDecimal) {
15+
seenDecimal = true
16+
out += c
17+
}
18+
}
19+
return out
20+
}

robot-server/robot_server/commands/stateless_commands.py

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,9 @@
3434
commands.unsafe.UnsafeFlexStackerCloseLatchCreate,
3535
commands.unsafe.UnsafeFlexStackerOpenLatchCreate,
3636
commands.IdentifyModuleCreate,
37+
commands.vacuum_module.StartSetVacuumPressureCreate,
38+
commands.vacuum_module.StartSetVacuumPowerCreate,
39+
commands.vacuum_module.StopVacuumCreate,
3740
],
3841
Field(discriminator="commandType"),
3942
]
@@ -61,12 +64,13 @@
6164
commands.heater_shaker.CloseLabwareLatch,
6265
commands.vacuum_module.OpenVent,
6366
commands.vacuum_module.CloseVent,
64-
commands.unsafe.UnsafeFlexStackerPrepareShuttleCreate,
65-
commands.unsafe.UnsafeFlexStackerCloseLatchCreate,
66-
commands.unsafe.UnsafeFlexStackerOpenLatchCreate,
67+
commands.unsafe.UnsafeFlexStackerPrepareShuttle,
68+
commands.unsafe.UnsafeFlexStackerCloseLatch,
69+
commands.unsafe.UnsafeFlexStackerOpenLatch,
6770
commands.IdentifyModule,
68-
commands.vacuum_module.OpenVent,
69-
commands.vacuum_module.CloseVent,
71+
commands.vacuum_module.StartSetVacuumPressure,
72+
commands.vacuum_module.StartSetVacuumPower,
73+
commands.vacuum_module.StopVacuum,
7074
],
7175
Field(discriminator="commandType"),
7276
]

shared-data/command/types/module.ts

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -659,28 +659,38 @@ export interface IdentifyModuleRunTimeCommand
659659
result?: any
660660
}
661661

662-
interface VacuumModuleSetTargetPressureParams {
663-
moduleId: string
664-
pressure: number
662+
interface BaseVacuumModulePumpParams extends ModuleOnlyParams {
663+
// in seconds
664+
duration?: number
665+
// in mbar/s
666+
rate?: number
667+
// in seconds
668+
timeout?: number
669+
ventAfter?: boolean
665670
}
666671

667-
interface VacuumModuleSetTargetPowerParams {
668-
moduleId: string
669-
power: number
672+
interface VacuumModuleSetTargetPressureParams extends BaseVacuumModulePumpParams {
673+
// in mbar
674+
gaugePressure: number
675+
}
676+
677+
interface VacuumModuleSetTargetPowerParams extends BaseVacuumModulePumpParams {
678+
// in % between 0 and 100
679+
percentPower: number
670680
}
671681

672682
export interface VacuumModuleSetTargetPressureCreateCommand extends CommonCommandCreateInfo {
673-
commandType: 'vacuumModule/setTargetPressure'
683+
commandType: 'vacuumModule/startSetVacuumPressure'
674684
params: VacuumModuleSetTargetPressureParams
675685
}
676686

677687
export interface VacuumModuleSetTargetPowerCreateCommand extends CommonCommandCreateInfo {
678-
commandType: 'vacuumModule/setTargetPower'
688+
commandType: 'vacuumModule/startSetVacuumPower'
679689
params: VacuumModuleSetTargetPowerParams
680690
}
681691

682692
export interface VacuumModuleDeactivateCreateCommand extends CommonCommandCreateInfo {
683-
commandType: 'vacuumModule/deactivate'
693+
commandType: 'vacuumModule/stopVacuum'
684694
params: ModuleOnlyParams
685695
}
686696

0 commit comments

Comments
 (0)