From 64b52080d97d2bcbb67895e2556f034e1797ad3a Mon Sep 17 00:00:00 2001 From: Brian Cooper Date: Mon, 18 Mar 2024 13:17:05 -0400 Subject: [PATCH 1/3] add cutout fixtures and helpers for module fixtures --- shared-data/deck/index.ts | 16 +- shared-data/deck/types/schemaV5.ts | 128 +++++++++++++++ shared-data/js/constants.ts | 35 +++- shared-data/js/deck/index.ts | 8 +- shared-data/js/fixtures.ts | 149 ++++++++++++------ .../helpers/getAddressableAreasInProtocol.ts | 59 +++---- shared-data/js/types.ts | 1 + 7 files changed, 312 insertions(+), 84 deletions(-) create mode 100644 shared-data/deck/types/schemaV5.ts diff --git a/shared-data/deck/index.ts b/shared-data/deck/index.ts index e308d7a17ad..7d68bdeebd9 100644 --- a/shared-data/deck/index.ts +++ b/shared-data/deck/index.ts @@ -8,11 +8,16 @@ import ot2StandardDeckV4 from './definitions/4/ot2_standard.json' import ot2ShortFixedTrashDeckV4 from './definitions/4/ot2_short_trash.json' import ot3StandardDeckV4 from './definitions/4/ot3_standard.json' +// v5 deck defs +import ot2StandardDeckV5 from './definitions/5/ot2_standard.json' +import ot2ShortFixedTrashDeckV5 from './definitions/5/ot2_short_trash.json' +import ot3StandardDeckV5 from './definitions/5/ot3_standard.json' + import deckExample from './fixtures/3/deckExample.json' import type { DeckDefinition } from '../js/types' -export * from './types/schemaV4' +export * from './types/schemaV5' export { ot2StandardDeckV3, @@ -21,13 +26,16 @@ export { ot2StandardDeckV4, ot2ShortFixedTrashDeckV4, ot3StandardDeckV4, + ot2StandardDeckV5, + ot2ShortFixedTrashDeckV5, + ot3StandardDeckV5, deckExample, } const latestDeckDefinitions = { - ot2StandardDeckV4, - ot2ShortFixedTrashDeckV4, - ot3StandardDeckV4, + ot2StandardDeckV5, + ot2ShortFixedTrashDeckV5, + ot3StandardDeckV5, } export function getDeckDefinitions(): Record { diff --git a/shared-data/deck/types/schemaV5.ts b/shared-data/deck/types/schemaV5.ts new file mode 100644 index 00000000000..df939dbb24b --- /dev/null +++ b/shared-data/deck/types/schemaV5.ts @@ -0,0 +1,128 @@ +export type FlexAddressableAreaName = + | 'A1' + | 'B1' + | 'C1' + | 'D1' + | 'A2' + | 'B2' + | 'C2' + | 'D2' + | 'A3' + | 'B3' + | 'C3' + | 'D3' + | 'A4' + | 'B4' + | 'C4' + | 'D4' + | 'movableTrashA1' + | 'movableTrashB1' + | 'movableTrashC1' + | 'movableTrashD1' + | 'movableTrashA3' + | 'movableTrashB3' + | 'movableTrashC3' + | 'movableTrashD3' + | '1ChannelWasteChute' + | '8ChannelWasteChute' + | '96ChannelWasteChute' + | 'gripperWasteChute' + | 'thermocyclerModule' + | 'heaterShakerA1' + | 'heaterShakerB1' + | 'heaterShakerC1' + | 'heaterShakerD1' + | 'heaterShakerA3' + | 'heaterShakerB3' + | 'heaterShakerC3' + | 'heaterShakerD3' + | 'temperatureModuleA1' + | 'temperatureModuleB1' + | 'temperatureModuleC1' + | 'temperatureModuleD1' + | 'temperatureModuleA3' + | 'temperatureModuleB3' + | 'temperatureModuleC3' + | 'temperatureModuleD3' + +export type OT2AddressableAreaName = + | '1' + | '2' + | '3' + | '4' + | '5' + | '6' + | '7' + | '8' + | '9' + | '10' + | '11' + | '12' + | 'fixedTrash' + +export type AddressableAreaName = + | FlexAddressableAreaName + | OT2AddressableAreaName + +export type CutoutId = + | 'cutoutD1' + | 'cutoutD2' + | 'cutoutD3' + | 'cutoutC1' + | 'cutoutC2' + | 'cutoutC3' + | 'cutoutB1' + | 'cutoutB2' + | 'cutoutB3' + | 'cutoutA1' + | 'cutoutA2' + | 'cutoutA3' + +export type OT2CutoutId = + | 'cutout1' + | 'cutout2' + | 'cutout3' + | 'cutout4' + | 'cutout5' + | 'cutout6' + | 'cutout7' + | 'cutout8' + | 'cutout9' + | 'cutout10' + | 'cutout11' + | 'cutout12' + +export type SingleSlotCutoutFixtureId = + | 'singleLeftSlot' + | 'singleCenterSlot' + | 'singleRightSlot' + +export type StagingAreaRightSlotFixtureId = 'stagingAreaRightSlot' + +export type TrashBinAdapterCutoutFixtureId = 'trashBinAdapter' + +export type WasteChuteCutoutFixtureId = + | 'wasteChuteRightAdapterCovered' + | 'wasteChuteRightAdapterNoCover' + | 'stagingAreaSlotWithWasteChuteRightAdapterCovered' + | 'stagingAreaSlotWithWasteChuteRightAdapterNoCover' + +export type FlexModuleCutoutFixtureId = + | 'heaterShakerModule' + | 'temperatureModule' + | 'magneticBlockModule' + | 'thermocyclerModuleRear' + | 'thermocyclerModuleFront' + +export type OT2SingleStandardSlot = 'singleStandardSlot' + +export type OT2FixedTrashSlot = 'fixedTrashSlot' + +export type CutoutFixtureId = + | SingleSlotCutoutFixtureId + | StagingAreaRightSlotFixtureId + | TrashBinAdapterCutoutFixtureId + | WasteChuteCutoutFixtureId + | FlexModuleCutoutFixtureId + | OT2SingleStandardSlot + | OT2FixedTrashSlot diff --git a/shared-data/js/constants.ts b/shared-data/js/constants.ts index 1b944418e0e..ab28e628e18 100644 --- a/shared-data/js/constants.ts +++ b/shared-data/js/constants.ts @@ -1,5 +1,5 @@ -import type { CutoutFixtureId, CutoutId, AddressableAreaName } from '../deck' -import type { ModuleType } from './types' +import type { CutoutFixtureId, CutoutId, AddressableAreaName, FlexModuleCutoutFixtureId } from '../deck' +import type { ModuleModel, ModuleType } from './types' // constants for dealing with robot coordinate system (eg in labwareTools) export const SLOT_LENGTH_MM = 127.76 // along X axis in robot coordinate system @@ -275,6 +275,24 @@ export const NINETY_SIX_CHANNEL_WASTE_CHUTE_ADDRESSABLE_AREA: '96ChannelWasteChu export const GRIPPER_WASTE_CHUTE_ADDRESSABLE_AREA: 'gripperWasteChute' = 'gripperWasteChute' +export const THERMOCYCLER_ADDRESSABLE_AREA: 'thermocyclerModule' = 'thermocyclerModule' +export const HEATERSHAKER_A1_ADDRESSABLE_AREA: 'heaterShakerA1' = 'heaterShakerA1' +export const HEATERSHAKER_B1_ADDRESSABLE_AREA: 'heaterShakerB1' = 'heaterShakerB1' +export const HEATERSHAKER_C1_ADDRESSABLE_AREA: 'heaterShakerC1' = 'heaterShakerC1' +export const HEATERSHAKER_D1_ADDRESSABLE_AREA: 'heaterShakerD1' = 'heaterShakerD1' +export const HEATERSHAKER_A3_ADDRESSABLE_AREA: 'heaterShakerA3' = 'heaterShakerA3' +export const HEATERSHAKER_B3_ADDRESSABLE_AREA: 'heaterShakerB3' = 'heaterShakerB3' +export const HEATERSHAKER_C3_ADDRESSABLE_AREA: 'heaterShakerC3' = 'heaterShakerC3' +export const HEATERSHAKER_D3_ADDRESSABLE_AREA: 'heaterShakerD3' = 'heaterShakerD3' +export const TEMPERATURE_MODULE_A1_ADDRESSABLE_AREA: 'temperatureModuleA1' = 'temperatureModuleA1' +export const TEMPERATURE_MODULE_B1_ADDRESSABLE_AREA: 'temperatureModuleB1' = 'temperatureModuleB1' +export const TEMPERATURE_MODULE_C1_ADDRESSABLE_AREA: 'temperatureModuleC1' = 'temperatureModuleC1' +export const TEMPERATURE_MODULE_D1_ADDRESSABLE_AREA: 'temperatureModuleD1' = 'temperatureModuleD1' +export const TEMPERATURE_MODULE_A3_ADDRESSABLE_AREA: 'temperatureModuleA3' = 'temperatureModuleA3' +export const TEMPERATURE_MODULE_B3_ADDRESSABLE_AREA: 'temperatureModuleB3' = 'temperatureModuleB3' +export const TEMPERATURE_MODULE_C3_ADDRESSABLE_AREA: 'temperatureModuleC3' = 'temperatureModuleC3' +export const TEMPERATURE_MODULE_D3_ADDRESSABLE_AREA: 'temperatureModuleD3' = 'temperatureModuleD3' + export const ADDRESSABLE_AREA_1: '1' = '1' export const ADDRESSABLE_AREA_2: '2' = '2' export const ADDRESSABLE_AREA_3: '3' = '3' @@ -359,6 +377,19 @@ export const STAGING_AREA_SLOT_WITH_WASTE_CHUTE_RIGHT_ADAPTER_COVERED_FIXTURE: ' export const STAGING_AREA_SLOT_WITH_WASTE_CHUTE_RIGHT_ADAPTER_NO_COVER_FIXTURE: 'stagingAreaSlotWithWasteChuteRightAdapterNoCover' = 'stagingAreaSlotWithWasteChuteRightAdapterNoCover' +export const HEATERSHAKER_MODULE_V1_FIXTURE: 'heaterShakerModule' = 'heaterShakerModule' +export const TEMPERATURE_MODULE_V2_FIXTURE: 'temperatureModule' = 'temperatureModule' +export const MAGNETIC_BLOCK_V1_FIXTURE: 'magneticBlockModule' = 'magneticBlockModule' +export const THERMOCYCLER_V2_REAR_FIXTURE: 'thermocyclerModuleRear' = 'thermocyclerModuleRear' +export const THERMOCYCLER_V2_FRONT_FIXTURE: 'thermocyclerModuleFront' = 'thermocyclerModuleFront' + +export const MODULE_FIXTURES_BY_MODEL: {[moduleModel in ModuleModel]?: FlexModuleCutoutFixtureId[]} = { + [HEATERSHAKER_MODULE_V1]: [HEATERSHAKER_MODULE_V1_FIXTURE], + [TEMPERATURE_MODULE_V2]: [TEMPERATURE_MODULE_V2_FIXTURE], + [MAGNETIC_BLOCK_V1]: [MAGNETIC_BLOCK_V1_FIXTURE], + [THERMOCYCLER_MODULE_V2]: [THERMOCYCLER_V2_REAR_FIXTURE, THERMOCYCLER_V2_FRONT_FIXTURE], +} + export const SINGLE_SLOT_FIXTURES: CutoutFixtureId[] = [ SINGLE_LEFT_SLOT_FIXTURE, SINGLE_CENTER_SLOT_FIXTURE, diff --git a/shared-data/js/deck/index.ts b/shared-data/js/deck/index.ts index 786325be5a7..fce6ffb05fe 100644 --- a/shared-data/js/deck/index.ts +++ b/shared-data/js/deck/index.ts @@ -1,5 +1,5 @@ -import flexDeckDefV4 from '../../deck/definitions/4/ot3_standard.json' -import ot2DeckDefV4 from '../../deck/definitions/4/ot2_standard.json' -import ot2DeckDefShortFixedTrashV4 from '../../deck/definitions/4/ot2_short_trash.json' +import flexDeckDefV5 from '../../deck/definitions/5/ot3_standard.json' +import ot2DeckDefV5 from '../../deck/definitions/5/ot2_standard.json' +import ot2DeckDefShortFixedTrashV5 from '../../deck/definitions/5/ot2_short_trash.json' -export { ot2DeckDefV4, ot2DeckDefShortFixedTrashV4, flexDeckDefV4 } +export { ot2DeckDefV5, ot2DeckDefShortFixedTrashV5, flexDeckDefV5 } diff --git a/shared-data/js/fixtures.ts b/shared-data/js/fixtures.ts index 7e2f117bca8..9730ed33356 100644 --- a/shared-data/js/fixtures.ts +++ b/shared-data/js/fixtures.ts @@ -6,9 +6,44 @@ import { WASTE_CHUTE_RIGHT_ADAPTER_NO_COVER_FIXTURE, STAGING_AREA_SLOT_WITH_WASTE_CHUTE_RIGHT_ADAPTER_COVERED_FIXTURE, STAGING_AREA_SLOT_WITH_WASTE_CHUTE_RIGHT_ADAPTER_NO_COVER_FIXTURE, + A1_ADDRESSABLE_AREA, + A2_ADDRESSABLE_AREA, + A3_ADDRESSABLE_AREA, + B1_ADDRESSABLE_AREA, + B2_ADDRESSABLE_AREA, + B3_ADDRESSABLE_AREA, + C1_ADDRESSABLE_AREA, + C2_ADDRESSABLE_AREA, + C3_ADDRESSABLE_AREA, + D1_ADDRESSABLE_AREA, + D2_ADDRESSABLE_AREA, + D3_ADDRESSABLE_AREA, + ADDRESSABLE_AREA_1, + ADDRESSABLE_AREA_2, + ADDRESSABLE_AREA_3, + ADDRESSABLE_AREA_4, + ADDRESSABLE_AREA_5, + ADDRESSABLE_AREA_6, + ADDRESSABLE_AREA_7, + ADDRESSABLE_AREA_8, + ADDRESSABLE_AREA_9, + ADDRESSABLE_AREA_10, + ADDRESSABLE_AREA_11, + HEATERSHAKER_MODULE_V1_FIXTURE, + HEATERSHAKER_MODULE_V1, + TEMPERATURE_MODULE_V2_FIXTURE, + TEMPERATURE_MODULE_V2, + MAGNETIC_BLOCK_V1_FIXTURE, + MAGNETIC_BLOCK_V1, + THERMOCYCLER_V2_REAR_FIXTURE, + THERMOCYCLER_MODULE_V2, + THERMOCYCLER_V2_FRONT_FIXTURE, + MODULE_FIXTURES_BY_MODEL, } from './constants' -import type { CutoutFixtureId, CutoutId, OT2CutoutId } from '../deck' -import type { AddressableArea, CoordinateTuple, DeckDefinition } from './types' +import type { CutoutFixtureId, CutoutId, FlexModuleCutoutFixtureId, OT2CutoutId } from '../deck' +import type { AddressableArea, CoordinateTuple, DeckDefinition, ModuleModel } from './types' +import type { LoadModuleCreateCommand } from '../command' +import { getModuleDisplayName } from './modules' export function getCutoutDisplayName(cutout: CutoutId): string { return cutout.replace('cutout', '') @@ -107,59 +142,83 @@ export function getAddressableAreaFromSlotId( ) } +export function getCutoutFixturesForModuleModel( + moduleModel: ModuleModel +): FlexModuleCutoutFixtureId[] { + const moduleFixtures = MODULE_FIXTURES_BY_MODEL[moduleModel] + return moduleFixtures ?? [] +} + +export function getAddressableAreaFromLoadedModule( + params: LoadModuleCreateCommand['params'], + deckDef: DeckDefinition +): AddressableArea | null { + const moduleFixtures = getCutoutFixturesForModuleModel(params.model) + return ( + deckDef.locations.addressableAreas.find( + addressableArea => addressableArea.id === slotId + ) ?? null + ) +} + export function getFixtureDisplayName( cutoutFixtureId: CutoutFixtureId | null ): string { - if (cutoutFixtureId === STAGING_AREA_RIGHT_SLOT_FIXTURE) { - return 'Staging area slot' - } else if (cutoutFixtureId === TRASH_BIN_ADAPTER_FIXTURE) { - return 'Trash bin' - } else if (cutoutFixtureId === WASTE_CHUTE_RIGHT_ADAPTER_NO_COVER_FIXTURE) { - return 'Waste chute only' - } else if (cutoutFixtureId === WASTE_CHUTE_RIGHT_ADAPTER_COVERED_FIXTURE) { - return 'Waste chute only with cover' - } else if ( - cutoutFixtureId === - STAGING_AREA_SLOT_WITH_WASTE_CHUTE_RIGHT_ADAPTER_NO_COVER_FIXTURE - ) { - return 'Waste chute with staging area slot' - } else if ( - cutoutFixtureId === - STAGING_AREA_SLOT_WITH_WASTE_CHUTE_RIGHT_ADAPTER_COVERED_FIXTURE - ) { - return 'Waste chute with staging area slot and cover' - } else { - return 'Slot' + switch(cutoutFixtureId) { + case STAGING_AREA_RIGHT_SLOT_FIXTURE: + return 'Staging area slot' + case TRASH_BIN_ADAPTER_FIXTURE: + return 'Trash bin' + case WASTE_CHUTE_RIGHT_ADAPTER_NO_COVER_FIXTURE: + return 'Waste chute only' + case WASTE_CHUTE_RIGHT_ADAPTER_COVERED_FIXTURE: + return 'Waste chute only with cover' + case STAGING_AREA_SLOT_WITH_WASTE_CHUTE_RIGHT_ADAPTER_NO_COVER_FIXTURE: + return 'Waste chute with staging area slot' + case STAGING_AREA_SLOT_WITH_WASTE_CHUTE_RIGHT_ADAPTER_COVERED_FIXTURE: + return 'Waste chute with staging area slot and cover' + case HEATERSHAKER_MODULE_V1_FIXTURE: + return getModuleDisplayName(HEATERSHAKER_MODULE_V1) + case TEMPERATURE_MODULE_V2_FIXTURE: + return getModuleDisplayName(TEMPERATURE_MODULE_V2) + case MAGNETIC_BLOCK_V1_FIXTURE: + return getModuleDisplayName(MAGNETIC_BLOCK_V1) + case THERMOCYCLER_V2_REAR_FIXTURE: + return getModuleDisplayName(THERMOCYCLER_MODULE_V2) + case THERMOCYCLER_V2_FRONT_FIXTURE: + return getModuleDisplayName(THERMOCYCLER_MODULE_V2) + default: + return 'Slot' } } const STANDARD_OT2_SLOTS = [ - '1', - '2', - '3', - '4', - '5', - '6', - '7', - '8', - '9', - '10', - '11', + ADDRESSABLE_AREA_1, + ADDRESSABLE_AREA_2, + ADDRESSABLE_AREA_3, + ADDRESSABLE_AREA_4, + ADDRESSABLE_AREA_5, + ADDRESSABLE_AREA_6, + ADDRESSABLE_AREA_7, + ADDRESSABLE_AREA_8, + ADDRESSABLE_AREA_9, + ADDRESSABLE_AREA_10, + ADDRESSABLE_AREA_11, ] const STANDARD_FLEX_SLOTS = [ - 'A1', - 'A2', - 'A3', - 'B1', - 'B2', - 'B3', - 'C1', - 'C2', - 'C3', - 'D1', - 'D2', - 'D3', + A1_ADDRESSABLE_AREA, + A2_ADDRESSABLE_AREA, + A3_ADDRESSABLE_AREA, + B1_ADDRESSABLE_AREA, + B2_ADDRESSABLE_AREA, + B3_ADDRESSABLE_AREA, + C1_ADDRESSABLE_AREA, + C2_ADDRESSABLE_AREA, + C3_ADDRESSABLE_AREA, + D1_ADDRESSABLE_AREA, + D2_ADDRESSABLE_AREA, + D3_ADDRESSABLE_AREA, ] export const isAddressableAreaStandardSlot = ( diff --git a/shared-data/js/helpers/getAddressableAreasInProtocol.ts b/shared-data/js/helpers/getAddressableAreasInProtocol.ts index 1ca3013930a..902a9544c0e 100644 --- a/shared-data/js/helpers/getAddressableAreasInProtocol.ts +++ b/shared-data/js/helpers/getAddressableAreasInProtocol.ts @@ -12,16 +12,17 @@ export function getAddressableAreasInProtocol( const addressableAreasFromCommands = commands.reduce( (acc, command) => { + const { commandType, params } = command if ( - command.commandType === 'moveLabware' && - command.params.newLocation !== 'offDeck' && - 'slotName' in command.params.newLocation && + commandType === 'moveLabware' && + params.newLocation !== 'offDeck' && + 'slotName' in params.newLocation && !acc.includes( - command.params.newLocation.slotName as AddressableAreaName + params.newLocation.slotName as AddressableAreaName ) ) { const addressableAreaName = getAddressableAreaFromSlotId( - command.params.newLocation.slotName, + params.newLocation.slotName, deckDef )?.id @@ -31,51 +32,51 @@ export function getAddressableAreasInProtocol( return [...acc, addressableAreaName] } } else if ( - command.commandType === 'moveLabware' && - command.params.newLocation !== 'offDeck' && - 'addressableAreaName' in command.params.newLocation && - !acc.includes(command.params.newLocation.addressableAreaName) + commandType === 'moveLabware' && + params.newLocation !== 'offDeck' && + 'addressableAreaName' in params.newLocation && + !acc.includes(params.newLocation.addressableAreaName) ) { - return [...acc, command.params.newLocation.addressableAreaName] + return [...acc, params.newLocation.addressableAreaName] } else if ( - (command.commandType === 'loadLabware' || - command.commandType === 'loadModule') && - command.params.location !== 'offDeck' && - 'slotName' in command.params.location && - !acc.includes(command.params.location.slotName as AddressableAreaName) + (commandType === 'loadLabware' || + commandType === 'loadModule') && + params.location !== 'offDeck' && + 'slotName' in params.location && + !acc.includes(params.location.slotName as AddressableAreaName) ) { const addressableAreaName = getAddressableAreaFromSlotId( - command.params.location.slotName, + params.location.slotName, deckDef )?.id // do not add addressable area name for legacy trash labware if ( addressableAreaName == null || - ('loadName' in command.params && - command.params.loadName === 'opentrons_1_trash_3200ml_fixed') + ('loadName' in params && + params.loadName === 'opentrons_1_trash_3200ml_fixed') ) { return acc } else { return [...acc, addressableAreaName] } } else if ( - command.commandType === 'loadLabware' && - command.params.location !== 'offDeck' && - 'addressableAreaName' in command.params.location && - !acc.includes(command.params.location.addressableAreaName) + commandType === 'loadLabware' && + params.location !== 'offDeck' && + 'addressableAreaName' in params.location && + !acc.includes(params.location.addressableAreaName) ) { - return [...acc, command.params.location.addressableAreaName] + return [...acc, params.location.addressableAreaName] } else if ( - command.commandType === 'moveToAddressableArea' && - !acc.includes(command.params.addressableAreaName) + commandType === 'moveToAddressableArea' && + !acc.includes(params.addressableAreaName) ) { - return [...acc, command.params.addressableAreaName] + return [...acc, params.addressableAreaName] } else if ( - command.commandType === 'moveToAddressableAreaForDropTip' && - !acc.includes(command.params.addressableAreaName) + commandType === 'moveToAddressableAreaForDropTip' && + !acc.includes(params.addressableAreaName) ) { - return [...acc, command.params.addressableAreaName] + return [...acc, params.addressableAreaName] } else { return acc } diff --git a/shared-data/js/types.ts b/shared-data/js/types.ts index 82fd65fb87d..14b77a8068e 100644 --- a/shared-data/js/types.ts +++ b/shared-data/js/types.ts @@ -563,6 +563,7 @@ export type StatusBarAnimations = StatusBarAnimation[] export interface CutoutConfig { cutoutId: CutoutId cutoutFixtureId: CutoutFixtureId | null + opentronsModuleSerialNumber?: string } export type DeckConfiguration = CutoutConfig[] From 46655e27a0839accc24ab65a316d2b5a0fe4c80f Mon Sep 17 00:00:00 2001 From: ahiuchingau <20424172+ahiuchingau@users.noreply.github.com> Date: Wed, 20 Mar 2024 17:14:14 -0400 Subject: [PATCH 2/3] v5 ot3 deck definition fixup --- shared-data/deck/definitions/5/ot3_standard.json | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/shared-data/deck/definitions/5/ot3_standard.json b/shared-data/deck/definitions/5/ot3_standard.json index b7f95f66ed7..2772b6028ae 100644 --- a/shared-data/deck/definitions/5/ot3_standard.json +++ b/shared-data/deck/definitions/5/ot3_standard.json @@ -890,7 +890,9 @@ "expectOpentronsModuleSerialNumber": true, "mayMountTo": ["cutoutA1"], "displayName": "Rear Slot portion of the Thermocycler Moduler", - "providesAddressableAreas": {}, + "providesAddressableAreas": { + "cutoutA1": ["thermocyclerModuleV2"] + }, "fixtureGroup": ["thermocyclerModuleV2Rear", "thermocyclerModuleV2Front"], "height": 124.5 }, @@ -924,7 +926,7 @@ "cutoutC1": ["heaterShakerV1C1"], "cutoutB1": ["heaterShakerV1B1"], "cutoutA1": ["heaterShakerV1A1"], - "cutoutD3": ["heaterShakerV13"], + "cutoutD3": ["heaterShakerV1D3"], "cutoutC3": ["heaterShakerV1C3"], "cutoutB3": ["heaterShakerV1B3"], "cutoutA3": ["heaterShakerV1A3"] From 9e4b15c59d7f2fd917193de0e29461f1e1eb1413 Mon Sep 17 00:00:00 2001 From: Brian Cooper Date: Wed, 20 Mar 2024 17:18:39 -0400 Subject: [PATCH 3/3] module fixtures and AA's are versioned --- .../hardware-sim/DeckSlotLocation/index.tsx | 6 +- shared-data/deck/types/schemaV5.ts | 56 +++++++++++-------- shared-data/js/constants.ts | 10 ++-- shared-data/js/fixtures.ts | 50 ++++++++++------- .../helpers/getAddressableAreasInProtocol.ts | 19 +++++-- 5 files changed, 86 insertions(+), 55 deletions(-) diff --git a/components/src/hardware-sim/DeckSlotLocation/index.tsx b/components/src/hardware-sim/DeckSlotLocation/index.tsx index f40558219ec..fbe8431ea54 100644 --- a/components/src/hardware-sim/DeckSlotLocation/index.tsx +++ b/components/src/hardware-sim/DeckSlotLocation/index.tsx @@ -2,7 +2,7 @@ import * as React from 'react' import { getPositionFromSlotId, OT2_ROBOT_TYPE, - ot2DeckDefV4, + ot2DeckDefV5, } from '@opentrons/shared-data' import { SlotBase } from '../BaseDeck/SlotBase' @@ -40,7 +40,7 @@ export function LegacyDeckSlotLocation( if (robotType !== OT2_ROBOT_TYPE) return null - const slotDef = ot2DeckDefV4.locations.addressableAreas.find( + const slotDef = ot2DeckDefV5.locations.addressableAreas.find( s => s.id === slotName ) if (slotDef == null) { @@ -52,7 +52,7 @@ export function LegacyDeckSlotLocation( const slotPosition = getPositionFromSlotId( slotName, - (ot2DeckDefV4 as unknown) as DeckDefinition + (ot2DeckDefV5 as unknown) as DeckDefinition ) const isFixedTrash = slotName === 'fixedTrash' diff --git a/shared-data/deck/types/schemaV5.ts b/shared-data/deck/types/schemaV5.ts index df939dbb24b..7e2bb027088 100644 --- a/shared-data/deck/types/schemaV5.ts +++ b/shared-data/deck/types/schemaV5.ts @@ -27,23 +27,35 @@ export type FlexAddressableAreaName = | '8ChannelWasteChute' | '96ChannelWasteChute' | 'gripperWasteChute' - | 'thermocyclerModule' - | 'heaterShakerA1' - | 'heaterShakerB1' - | 'heaterShakerC1' - | 'heaterShakerD1' - | 'heaterShakerA3' - | 'heaterShakerB3' - | 'heaterShakerC3' - | 'heaterShakerD3' - | 'temperatureModuleA1' - | 'temperatureModuleB1' - | 'temperatureModuleC1' - | 'temperatureModuleD1' - | 'temperatureModuleA3' - | 'temperatureModuleB3' - | 'temperatureModuleC3' - | 'temperatureModuleD3' + | 'thermocyclerModuleV2' + | 'heaterShakerV1A1' + | 'heaterShakerV1B1' + | 'heaterShakerV1C1' + | 'heaterShakerV1D1' + | 'heaterShakerV1A3' + | 'heaterShakerV1B3' + | 'heaterShakerV1C3' + | 'heaterShakerV1D3' + | 'temperatureModuleV2A1' + | 'temperatureModuleV2B1' + | 'temperatureModuleV2C1' + | 'temperatureModuleV2D1' + | 'temperatureModuleV2A3' + | 'temperatureModuleV2B3' + | 'temperatureModuleV2C3' + | 'temperatureModuleV2D3' + | 'magneticBlockV1A1' + | 'magneticBlockV1B1' + | 'magneticBlockV1C1' + | 'magneticBlockV1D1' + | 'magneticBlockV1A2' + | 'magneticBlockV1B2' + | 'magneticBlockV1C2' + | 'magneticBlockV1D2' + | 'magneticBlockV1A3' + | 'magneticBlockV1B3' + | 'magneticBlockV1C3' + | 'magneticBlockV1D3' export type OT2AddressableAreaName = | '1' @@ -108,11 +120,11 @@ export type WasteChuteCutoutFixtureId = | 'stagingAreaSlotWithWasteChuteRightAdapterNoCover' export type FlexModuleCutoutFixtureId = - | 'heaterShakerModule' - | 'temperatureModule' - | 'magneticBlockModule' - | 'thermocyclerModuleRear' - | 'thermocyclerModuleFront' + | 'heaterShakerModuleV1' + | 'temperatureModuleV2' + | 'magneticBlockModuleV1' + | 'thermocyclerModuleV2Rear' + | 'thermocyclerModuleV2Front' export type OT2SingleStandardSlot = 'singleStandardSlot' diff --git a/shared-data/js/constants.ts b/shared-data/js/constants.ts index ab28e628e18..d5216e27184 100644 --- a/shared-data/js/constants.ts +++ b/shared-data/js/constants.ts @@ -377,11 +377,11 @@ export const STAGING_AREA_SLOT_WITH_WASTE_CHUTE_RIGHT_ADAPTER_COVERED_FIXTURE: ' export const STAGING_AREA_SLOT_WITH_WASTE_CHUTE_RIGHT_ADAPTER_NO_COVER_FIXTURE: 'stagingAreaSlotWithWasteChuteRightAdapterNoCover' = 'stagingAreaSlotWithWasteChuteRightAdapterNoCover' -export const HEATERSHAKER_MODULE_V1_FIXTURE: 'heaterShakerModule' = 'heaterShakerModule' -export const TEMPERATURE_MODULE_V2_FIXTURE: 'temperatureModule' = 'temperatureModule' -export const MAGNETIC_BLOCK_V1_FIXTURE: 'magneticBlockModule' = 'magneticBlockModule' -export const THERMOCYCLER_V2_REAR_FIXTURE: 'thermocyclerModuleRear' = 'thermocyclerModuleRear' -export const THERMOCYCLER_V2_FRONT_FIXTURE: 'thermocyclerModuleFront' = 'thermocyclerModuleFront' +export const HEATERSHAKER_MODULE_V1_FIXTURE: 'heaterShakerModuleV1' = 'heaterShakerModuleV1' +export const TEMPERATURE_MODULE_V2_FIXTURE: 'temperatureModuleV2' = 'temperatureModuleV2' +export const MAGNETIC_BLOCK_V1_FIXTURE: 'magneticBlockModuleV1' = 'magneticBlockModuleV1' +export const THERMOCYCLER_V2_REAR_FIXTURE: 'thermocyclerModuleV2Rear' = 'thermocyclerModuleV2Rear' +export const THERMOCYCLER_V2_FRONT_FIXTURE: 'thermocyclerModuleV2Front' = 'thermocyclerModuleV2Front' export const MODULE_FIXTURES_BY_MODEL: {[moduleModel in ModuleModel]?: FlexModuleCutoutFixtureId[]} = { [HEATERSHAKER_MODULE_V1]: [HEATERSHAKER_MODULE_V1_FIXTURE], diff --git a/shared-data/js/fixtures.ts b/shared-data/js/fixtures.ts index 9730ed33356..44da5ccb56d 100644 --- a/shared-data/js/fixtures.ts +++ b/shared-data/js/fixtures.ts @@ -40,9 +40,9 @@ import { THERMOCYCLER_V2_FRONT_FIXTURE, MODULE_FIXTURES_BY_MODEL, } from './constants' -import type { CutoutFixtureId, CutoutId, FlexModuleCutoutFixtureId, OT2CutoutId } from '../deck' +import type { AddressableAreaName, CutoutFixtureId, CutoutId, FlexAddressableAreaName, FlexModuleCutoutFixtureId, OT2CutoutId } from '../deck' import type { AddressableArea, CoordinateTuple, DeckDefinition, ModuleModel } from './types' -import type { LoadModuleCreateCommand } from '../command' +import type { LoadModuleCreateCommand, ModuleLocation } from '../command' import { getModuleDisplayName } from './modules' export function getCutoutDisplayName(cutout: CutoutId): string { @@ -122,10 +122,10 @@ export function getPositionFromSlotId( const slotPosition: CoordinateTuple | null = cutoutPosition != null ? [ - cutoutPosition[0] + offsetFromCutoutFixture[0], - cutoutPosition[1] + offsetFromCutoutFixture[1], - cutoutPosition[2] + offsetFromCutoutFixture[2], - ] + cutoutPosition[0] + offsetFromCutoutFixture[0], + cutoutPosition[1] + offsetFromCutoutFixture[1], + cutoutPosition[2] + offsetFromCutoutFixture[2], + ] : null return slotPosition @@ -142,29 +142,41 @@ export function getAddressableAreaFromSlotId( ) } -export function getCutoutFixturesForModuleModel( +export function getCutoutFixtureIdsForModuleModel( moduleModel: ModuleModel ): FlexModuleCutoutFixtureId[] { const moduleFixtures = MODULE_FIXTURES_BY_MODEL[moduleModel] return moduleFixtures ?? [] } -export function getAddressableAreaFromLoadedModule( +export function getCutoutIdFromModuleLocation( + location: ModuleLocation, + deckDef: DeckDefinition +): CutoutId | null { + return deckDef.locations.cutouts.find( + cutout => cutout.id.includes(location.slotName) + )?.id ?? null +} + +export function getAddressableAreaNamesFromLoadedModule( params: LoadModuleCreateCommand['params'], deckDef: DeckDefinition -): AddressableArea | null { - const moduleFixtures = getCutoutFixturesForModuleModel(params.model) - return ( - deckDef.locations.addressableAreas.find( - addressableArea => addressableArea.id === slotId +): AddressableAreaName[] { + const moduleFixtureIds = getCutoutFixtureIdsForModuleModel(params.model) + const cutoutId = getCutoutIdFromModuleLocation(params.location, deckDef) + return moduleFixtureIds.reduce((acc, cutoutFixtureId) => { + const cutoutFixture = deckDef.cutoutFixtures.find( + cf => cf.id === cutoutFixtureId ) ?? null - ) + const providedAddressableAreas = cutoutId != null ?cutoutFixture?.providesAddressableAreas[cutoutId] ?? [] : [] + return [...acc, ...providedAddressableAreas] + }, []) } export function getFixtureDisplayName( cutoutFixtureId: CutoutFixtureId | null ): string { - switch(cutoutFixtureId) { + switch (cutoutFixtureId) { case STAGING_AREA_RIGHT_SLOT_FIXTURE: return 'Staging area slot' case TRASH_BIN_ADAPTER_FIXTURE: @@ -192,7 +204,7 @@ export function getFixtureDisplayName( } } -const STANDARD_OT2_SLOTS = [ +const STANDARD_OT2_SLOTS: AddressableAreaName[]= [ ADDRESSABLE_AREA_1, ADDRESSABLE_AREA_2, ADDRESSABLE_AREA_3, @@ -206,7 +218,7 @@ const STANDARD_OT2_SLOTS = [ ADDRESSABLE_AREA_11, ] -const STANDARD_FLEX_SLOTS = [ +const STANDARD_FLEX_SLOTS: AddressableAreaName[] = [ A1_ADDRESSABLE_AREA, A2_ADDRESSABLE_AREA, A3_ADDRESSABLE_AREA, @@ -222,10 +234,10 @@ const STANDARD_FLEX_SLOTS = [ ] export const isAddressableAreaStandardSlot = ( - addressableAreaId: string, + addressableAreaName: AddressableAreaName, deckDef: DeckDefinition ): boolean => (deckDef.robot.model === FLEX_ROBOT_TYPE ? STANDARD_FLEX_SLOTS : STANDARD_OT2_SLOTS - ).includes(addressableAreaId) + ).includes(addressableAreaName) diff --git a/shared-data/js/helpers/getAddressableAreasInProtocol.ts b/shared-data/js/helpers/getAddressableAreasInProtocol.ts index 902a9544c0e..82367c77a5a 100644 --- a/shared-data/js/helpers/getAddressableAreasInProtocol.ts +++ b/shared-data/js/helpers/getAddressableAreasInProtocol.ts @@ -1,5 +1,5 @@ import { MOVABLE_TRASH_A3_ADDRESSABLE_AREA } from '../constants' -import { getAddressableAreaFromSlotId } from '../fixtures' +import { getAddressableAreaNamesFromLoadedModule, getAddressableAreaFromSlotId } from '../fixtures' import type { AddressableAreaName } from '../../deck' import type { ProtocolAnalysisOutput } from '../../protocol' import type { CompletedProtocolAnalysis, DeckDefinition } from '../types' @@ -17,9 +17,7 @@ export function getAddressableAreasInProtocol( commandType === 'moveLabware' && params.newLocation !== 'offDeck' && 'slotName' in params.newLocation && - !acc.includes( - params.newLocation.slotName as AddressableAreaName - ) + !acc.includes(params.newLocation.slotName as AddressableAreaName) ) { const addressableAreaName = getAddressableAreaFromSlotId( params.newLocation.slotName, @@ -39,8 +37,7 @@ export function getAddressableAreasInProtocol( ) { return [...acc, params.newLocation.addressableAreaName] } else if ( - (commandType === 'loadLabware' || - commandType === 'loadModule') && + commandType === 'loadLabware' && params.location !== 'offDeck' && 'slotName' in params.location && !acc.includes(params.location.slotName as AddressableAreaName) @@ -60,6 +57,16 @@ export function getAddressableAreasInProtocol( } else { return [...acc, addressableAreaName] } + } else if ( + commandType === 'loadModule' && + !acc.includes(params.location.slotName as AddressableAreaName) + ) { + const addressableAreaNames = getAddressableAreaNamesFromLoadedModule( + params, + deckDef + ) + + return [...acc, ...addressableAreaNames] } else if ( commandType === 'loadLabware' && params.location !== 'offDeck' &&