@@ -30,8 +30,10 @@ import {
30
30
import { OddModal } from '/app/molecules/OddModal'
31
31
import { useNotifyDeckConfigurationQuery } from '/app/resources/deck_configuration/'
32
32
33
+ import { useSendIdentifyStacker } from '../ModuleWizardFlows/hooks'
33
34
import { getOptions } from './utils'
34
35
36
+ import type { AttachedModule } from '@opentrons/api-client'
35
37
import type { ModalProps } from '@opentrons/components'
36
38
import type {
37
39
AddressableAreaNamesWithFakes ,
@@ -42,6 +44,9 @@ import type {
42
44
} from '@opentrons/shared-data'
43
45
import type { OddModalHeaderBaseProps } from '/app/molecules/OddModal/types'
44
46
47
+ const FLEX_STACKER_FIXTURE = 'flexStackerModuleV1'
48
+ const MODULE_IDENTIFY_TIME_MS = 10000
49
+
45
50
interface AddFixtureModalProps {
46
51
cutoutId : CutoutId
47
52
addressableAreaId : AddressableAreaNamesWithFakes
@@ -161,7 +166,14 @@ export function AddFixtureModal({
161
166
)
162
167
}
163
168
164
- const handleAddFixture = ( addedCutoutConfigs : CutoutConfigMap [ ] ) : void => {
169
+ const sendIdentifyStacker = useSendIdentifyStacker ( )
170
+ const [ identifyInUse , setIdentifyInUse ] = useState < string | null > ( null )
171
+ const [ identifyTimeout , setTimeoutID ] = useState < NodeJS . Timeout | null > ( null )
172
+
173
+ const handleAddFixture = (
174
+ addedCutoutConfigs : CutoutConfigMap [ ] ,
175
+ fixtureSerialNumber ?: string
176
+ ) : void => {
165
177
const addedCutoutConfigsWithCombo = replaceCutoutFixtureWithComboFixture (
166
178
addedCutoutConfigs ,
167
179
deckConfigWithAA ,
@@ -175,10 +187,54 @@ export function AddFixtureModal({
175
187
)
176
188
} ) as CutoutConfig [ ] // we can do this bc we are mapping each aa to the proper fixture
177
189
190
+ if ( fixtureSerialNumber ) {
191
+ const module =
192
+ unconfiguredMods ?. find ( m => m . serialNumber === fixtureSerialNumber ) ??
193
+ null
194
+ if ( module !== null ) {
195
+ sendIdentifyStacker ( module , false )
196
+ if ( identifyTimeout !== null ) {
197
+ clearTimeout ( identifyTimeout )
198
+ }
199
+ }
200
+ }
178
201
updateDeckConfiguration ( newDeckConfig )
179
202
closeModal ( )
180
203
}
181
204
205
+ const stackerIdentifyHandler = ( module : AttachedModule ) : void => {
206
+ // Identify the stacker module
207
+ sendIdentifyStacker ( module , true , 'blue' )
208
+ // Ensure that the module reverts after a set time
209
+ setIdentifyInUse ( module . serialNumber )
210
+ const timeoutID = setTimeout ( ( ) => {
211
+ sendIdentifyStacker ( module , false )
212
+ setIdentifyInUse ( null )
213
+ } , MODULE_IDENTIFY_TIME_MS )
214
+ setTimeoutID ( timeoutID )
215
+ }
216
+
217
+ const handleIdentifyFixture = ( fixtureSerialNumber : string ) : void => {
218
+ const module =
219
+ unconfiguredMods . find ( m => m . serialNumber === fixtureSerialNumber ) ?? null
220
+ if ( identifyInUse === null && module !== null ) {
221
+ stackerIdentifyHandler ( module )
222
+ } else if (
223
+ identifyInUse !== fixtureSerialNumber &&
224
+ identifyInUse !== null
225
+ ) {
226
+ const previousModule =
227
+ unconfiguredMods . find ( m => m . serialNumber === identifyInUse ) ?? null
228
+ if ( previousModule !== null && module !== null ) {
229
+ sendIdentifyStacker ( previousModule , false )
230
+ if ( identifyTimeout !== null ) {
231
+ clearTimeout ( identifyTimeout )
232
+ }
233
+ stackerIdentifyHandler ( module )
234
+ }
235
+ }
236
+ }
237
+
182
238
const fixtureOptions = availableOptions . map ( cutoutConfigs => {
183
239
const usbPort = ( modulesData ?. data ?? [ ] ) . find (
184
240
m => m . serialNumber === cutoutConfigs [ 0 ] . opentronsModuleSerialNumber
@@ -188,20 +244,45 @@ export function AddFixtureModal({
188
244
? `${ usbPort . port } .${ usbPort . hubPort } `
189
245
: usbPort ?. port
190
246
191
- return (
192
- < FixtureOption
193
- key = { cutoutConfigs [ 0 ] . cutoutFixtureId }
194
- optionName = { getFixtureDisplayName (
195
- cutoutConfigs [ 0 ] . cutoutFixtureId ,
196
- portDisplay
197
- ) }
198
- buttonText = { t ( 'add' ) }
199
- onClickHandler = { ( ) => {
200
- handleAddFixture ( cutoutConfigs )
201
- } }
202
- isOnDevice = { isOnDevice }
203
- />
204
- )
247
+ const fixtureSerialNumber = cutoutConfigs [ 0 ] . opentronsModuleSerialNumber
248
+ if (
249
+ fixtureSerialNumber !== undefined &&
250
+ cutoutConfigs [ 0 ] . cutoutFixtureId . includes ( FLEX_STACKER_FIXTURE )
251
+ ) {
252
+ return (
253
+ < FixtureOption
254
+ key = { cutoutConfigs [ 0 ] . cutoutFixtureId }
255
+ optionName = { getFixtureDisplayName (
256
+ cutoutConfigs [ 0 ] . cutoutFixtureId ,
257
+ portDisplay
258
+ ) }
259
+ buttonText = { t ( 'add' ) }
260
+ onClickHandler = { ( ) => {
261
+ handleAddFixture ( cutoutConfigs , fixtureSerialNumber )
262
+ } }
263
+ secondaryButtonText = { t ( 'identify' ) }
264
+ secondaryOnClickHandler = { ( ) => {
265
+ handleIdentifyFixture ( fixtureSerialNumber )
266
+ } }
267
+ isOnDevice = { isOnDevice }
268
+ />
269
+ )
270
+ } else {
271
+ return (
272
+ < FixtureOption
273
+ key = { cutoutConfigs [ 0 ] . cutoutFixtureId }
274
+ optionName = { getFixtureDisplayName (
275
+ cutoutConfigs [ 0 ] . cutoutFixtureId ,
276
+ portDisplay
277
+ ) }
278
+ buttonText = { t ( 'add' ) }
279
+ onClickHandler = { ( ) => {
280
+ handleAddFixture ( cutoutConfigs )
281
+ } }
282
+ isOnDevice = { isOnDevice }
283
+ />
284
+ )
285
+ }
205
286
} )
206
287
207
288
return (
0 commit comments