Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

feat(shared-data): add deck schema v6 #17250

Draft
wants to merge 11 commits into
base: edge
Choose a base branch
from
508 changes: 508 additions & 0 deletions shared-data/deck/definitions/6/ot2_short_trash.json

Large diffs are not rendered by default.

508 changes: 508 additions & 0 deletions shared-data/deck/definitions/6/ot2_standard.json

Large diffs are not rendered by default.

1,614 changes: 1,614 additions & 0 deletions shared-data/deck/definitions/6/ot3_standard.json

Large diffs are not rendered by default.

431 changes: 431 additions & 0 deletions shared-data/deck/schemas/6.json

Large diffs are not rendered by default.

150 changes: 150 additions & 0 deletions shared-data/deck/types/schemaV6.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
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'
| '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'
| 'absorbanceReaderV1A3'
| 'absorbanceReaderV1B3'
| 'absorbanceReaderV1C3'
| 'absorbanceReaderV1D3'
| 'absorbanceReaderV1LidDockA4'
| 'absorbanceReaderV1LidDockB4'
| 'absorbanceReaderV1LidDockC4'
| 'absorbanceReaderV1LidDockD4'

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 =
| 'heaterShakerModuleV1'
| 'temperatureModuleV2'
| 'magneticBlockV1'
| 'stagingAreaSlotWithMagneticBlockV1'
| 'thermocyclerModuleV2Rear'
| 'thermocyclerModuleV2Front'
| 'absorbanceReaderV1'

export type OT2SingleStandardSlot = 'singleStandardSlot'

export type OT2FixedTrashSlot = 'fixedTrashSlot'

export type CutoutFixtureId =
| SingleSlotCutoutFixtureId
| StagingAreaRightSlotFixtureId
| TrashBinAdapterCutoutFixtureId
| WasteChuteCutoutFixtureId
| FlexModuleCutoutFixtureId
| OT2SingleStandardSlot
| OT2FixedTrashSlot
62 changes: 52 additions & 10 deletions shared-data/js/__tests__/deckSchemas.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,25 +6,27 @@ import glob from 'glob'
import { describe, expect, it } from 'vitest'
import deckSchema from '../../deck/schemas/3.json'
import deckSchemaV4 from '../../deck/schemas/4.json'
import deckSchemaV5 from '../../deck/schemas/5.json'
import deckSchemaV6 from '../../deck/schemas/6.json'

const fixtureGlob = path.join(__dirname, '../../deck/fixtures/3/*.json')
const defGlob = path.join(__dirname, '../../deck/definitions/3/*.json')
const defV4Glob = path.join(__dirname, '../../deck/definitions/4/*.json')
const defV5Glob = path.join(__dirname, '../../deck/definitions/5/*.json')
const defV6Glob = path.join(__dirname, '../../deck/definitions/6/*.json')

const ajv = new Ajv({ allErrors: true, jsonPointers: true })

const validateSchema = ajv.compile(deckSchema)
const validateSchemaV4 = ajv.compile(deckSchemaV4)

describe('validate v3 deck defs and fixtures', () => {
const validateSchemaV3 = ajv.compile(deckSchema)
const fixtures = glob.sync(fixtureGlob)

fixtures.forEach(fixturePath => {
const fixtureDef = require(fixturePath)

it('fixture validates against schema', () => {
const valid = validateSchema(fixtureDef)
const validationErrors = validateSchema.errors
it(`${fixturePath} validates against schema`, () => {
const valid = validateSchemaV3(fixtureDef)
const validationErrors = validateSchemaV3.errors

if (validationErrors) {
console.log(
Expand All @@ -44,9 +46,9 @@ describe('validate v3 deck defs and fixtures', () => {
defs.forEach(defPath => {
const deckDef = require(defPath)

it('deck validates against v3 schema', () => {
const valid = validateSchema(deckDef)
const validationErrors = validateSchema.errors
it(`${defPath} validates against v3 schema`, () => {
const valid = validateSchemaV3(deckDef)
const validationErrors = validateSchemaV3.errors

if (validationErrors) {
console.log(
Expand All @@ -64,11 +66,12 @@ describe('validate v3 deck defs and fixtures', () => {

describe('validate v4 deck defs', () => {
const defs = glob.sync(defV4Glob)
const validateSchemaV4 = ajv.compile(deckSchemaV4)

defs.forEach(defPath => {
const deckDef = require(defPath)

it('deck validates against v4 schema', () => {
it(`${defPath} validates against v4 schema`, () => {
const valid = validateSchemaV4(deckDef)
const validationErrors = validateSchemaV4.errors

Expand All @@ -85,3 +88,42 @@ describe('validate v4 deck defs', () => {
})
})
})

describe('validate v5 deck defs', () => {
const defs = glob.sync(defV5Glob)
const validateSchemaV5 = ajv.compile(deckSchemaV5)

defs.forEach(defPath => {
const deckDef = require(defPath)
const defBase = path.parse(defPath).base
it(`${defBase} validates against v5 schema`, () => {
const valid = validateSchemaV5(deckDef)
const validationErrors = validateSchemaV5.errors

if (validationErrors) {
console.log(defBase + ' ' + JSON.stringify(validationErrors, null, 4))
}
expect(validationErrors).toBe(null)
expect(valid).toBe(true)
})
})
})

describe('validate v6 deck defs', () => {
const defs = glob.sync(defV6Glob)
const validateSchemaV6 = ajv.compile(deckSchemaV6)
defs.forEach(defPath => {
const deckDef = require(defPath)
const defBase = path.parse(defPath).base
it(`${defPath} validates against v6 schema`, () => {
const valid = validateSchemaV6(deckDef)
const validationErrors = validateSchemaV6.errors

if (validationErrors) {
console.log(defBase + ' ' + JSON.stringify(validationErrors, null, 4))
}
expect(validationErrors).toBe(null)
expect(valid).toBe(true)
})
})
})
8 changes: 8 additions & 0 deletions shared-data/python/opentrons_shared_data/deck/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"""
opentrons_shared_data.deck: types and bindings for deck definitions
"""

from typing import Dict, List, NamedTuple, cast, overload, TYPE_CHECKING
from typing_extensions import Final
import json
Expand All @@ -17,6 +18,8 @@
DeckSchemaVersion4,
DeckDefinitionV5,
DeckSchemaVersion5,
DeckDefinitionV6,
DeckSchemaVersion6,
)

DEFAULT_DECK_DEFINITION_VERSION: Final = 5
Expand All @@ -40,6 +43,11 @@ class Offset(NamedTuple):
}


@overload
def load(name: str, version: "DeckSchemaVersion6") -> "DeckDefinitionV6":
...


@overload
def load(name: str, version: "DeckSchemaVersion5") -> "DeckDefinitionV5":
...
Expand Down
50 changes: 46 additions & 4 deletions shared-data/python/opentrons_shared_data/deck/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
from ..module.types import ModuleType


DeckSchemaVersion6 = Literal[6]
DeckSchemaVersion5 = Literal[5]
DeckSchemaVersion4 = Literal[4]
DeckSchemaVersion3 = Literal[3]
Expand All @@ -18,7 +19,12 @@

DeckSchema = NewType("DeckSchema", Dict[str, Any])

DeckSchemaId = Literal["opentronsDeckSchemaV3", "opentronsDeckSchemaV4"]
DeckSchemaId = Literal[
"opentronsDeckSchemaV3",
"opentronsDeckSchemaV4",
"opentronsDeckSchemaV5",
"opentronsDeckSchemaV6",
]
RobotModel = Union[Literal["OT-2 Standard"], Literal["OT-3 Standard"]]


Expand Down Expand Up @@ -89,6 +95,11 @@ class FixedVolumeByPosition(TypedDict):
position: List[float]


class LocatingFeature(TypedDict):
locatingFeatureId: str
offsetVector: List[float]


class _RequiredAddressableArea(TypedDict):
id: str
areaType: str
Expand All @@ -97,13 +108,20 @@ class _RequiredAddressableArea(TypedDict):
displayName: str


class AddressableArea(_RequiredAddressableArea, total=False):
class AddressableAreaV4(_RequiredAddressableArea, total=False):
compatibleModuleTypes: List[ModuleType]
matingSurfaceUnitVector: List[Union[Literal[1], Literal[-1]]]
ableToDropTips: bool
ableToDropLabware: bool


class AddressableAreaV6(_RequiredAddressableArea, total=False):
compatibleModuleTypes: List[ModuleType]
locatingFeatures: List[LocatingFeature]
ableToDropTips: bool
ableToDropLabware: bool


class Cutout(TypedDict):
id: str
position: List[float]
Expand Down Expand Up @@ -132,7 +150,14 @@ class LocationsV3(TypedDict):


class LocationsV4(TypedDict):
addressableAreas: List[AddressableArea]
addressableAreas: List[AddressableAreaV4]
calibrationPoints: List[CalibrationPoint]
cutouts: List[Cutout]
legacyFixtures: List[Fixture]


class LocationsV6(TypedDict):
addressableAreas: List[AddressableAreaV6]
calibrationPoints: List[CalibrationPoint]
cutouts: List[Cutout]
legacyFixtures: List[Fixture]
Expand Down Expand Up @@ -194,4 +219,21 @@ class DeckDefinitionV5(_RequiredDeckDefinitionV5, total=False):
gripperOffsets: Dict[str, GripperOffsets]


DeckDefinition = Union[DeckDefinitionV3, DeckDefinitionV4, DeckDefinitionV5]
class _RequiredDeckDefinitionV6(TypedDict):
otId: str
schemaVersion: Literal[6]
cornerOffsetFromOrigin: List[float]
dimensions: List[float]
metadata: Metadata
robot: Robot
locations: LocationsV6
cutoutFixtures: List[CutoutFixture]


class DeckDefinitionV6(_RequiredDeckDefinitionV6, total=False):
gripperOffsets: Dict[str, GripperOffsets]


DeckDefinition = Union[
DeckDefinitionV3, DeckDefinitionV4, DeckDefinitionV5, DeckDefinitionV6
]
Loading
Loading