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): create v3 JSON protocol schema def #3307

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions shared-data/labware-json-schema/labware-schema.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{
"$id": "opentronsLabwareSchemaV2",
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {
"positiveNumber": {
Expand Down
382 changes: 382 additions & 0 deletions shared-data/protocol-json-schema/protocolSchemaV3.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,382 @@
{
"$id": "opentronsProtocolSchemaV3",
"$schema": "http://json-schema.org/draft-07/schema#",

"definitions": {
"pipetteName": {
"description": "Name of a pipette. Does not contain info about specific model/version. Should match keys in pipetteNameSpecs.json",
"type": "string",
"enum": [
"p10_single",
"p10_multi",
"p50_single",
"p50_multi",
"p300_single",
"p300_multi",
"p1000_single",
"p1000_multi"
]
},

"mmOffset": {
"description": "Millimeters for pipette location offsets",
"type": "number"
},

"flowRateForPipettes": {
"description": "Flow rate in mm/sec for each pipette used in the protocol, by pipette name",
"type": "object",
"propertyNames": {"$ref": "#/definitions/pipetteName"},
"patternProperties": {".*": {"type": "number"}},
"additionalProperties": false
},

"flowRateParams": {
"properties": {
"flowRate": {
"description": "Flow rate for aspirate/dispense. If omitted, defaults to the corresponding values in \"defaultValues\"",
"type": "number"
}
}
},

"offsetFromBottomMm": {
"description": "Offset from bottom of well in millimeters",
"properties": {
"offsetFromBottomMm": {"$ref": "#/definitions/mmOffset"}
}
},

"pipetteAccessParams": {
"required": ["pipette", "labware", "well"],
"properties": {
"pipette": {
"type": "string"
},
"labware": {
"type": "string"
},
"well": {
"type": "string"
}
}
},

"volumeParams": {
"required": ["volume"],
"volume": {
"type": "number"
}
},

"slot": {
"description": "Slot on the deck of an OT-2 robot",
"type": "string",
"enum": ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12"]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Out of curiosity, how hard would it be to have this reference the deck schema? This might be a nice change to start moving towards minimizing the sources of truth for slots.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmmm... the deckSchema.json schema doesn't have a slot enum, that info isn't in the deck schema itself. I don't know if JSON Schema has a way to extract these strings from an ordinary data JSON (eg shared-data/robot-data/decks/ot2Standard.json), I think it can only reference other JSON schemas.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Aha that makes sense, good point.

}
},

"type": "object",
"additionalProperties": false,
"required": [
"schemaVersion",
"defaultValues",
"metadata",
"robot",
"pipettes",
"labware",
"labwareDefinitions",
"commands"
],
"properties": {
"schemaVersion": {
"description": "Schema version of a protocol is a single integer",
"enum": [3]
},

"metadata": {
"description": "Optional metadata about the protocol",
"type": "object",

"properties": {
"protocolName": {
"description": "A short, human-readable name for the protocol",
"type": "string"
},
"author": {
"description": "The author or organization who created the protocol",
"type": "string"
},
"description": {
"description": "A text description of the protocol.",
"type": ["string", "null"]
},

"created": {
"description": "UNIX timestamp when this file was created",
"type": "number"
},
"lastModified": {
"description": "UNIX timestamp when this file was last modified",
"type": ["number", "null"]
},

"category": {
"description": "Category of protocol (eg, \"Basic Pipetting\")",
"type": ["string", "null"]
},
"subcategory": {
"description": "Subcategory of protocol (eg, \"Cell Plating\")",
"type": ["string", "null"]
},
"tags": {
"description": "Tags to be used in searching for this protocol",
"type": "array",
"items": {
"type": "string"
}
}
}
},

"defaultValues": {
"description": "Default values required for protocol execution",
"type": "object",
"required": [
"aspirateFlowRate",
"dispenseFlowRate",
"aspirateMmFromBottom",
"dispenseMmFromBottom",
"touchTipMmFromTop"
],
"properties": {
"aspirateFlowRate": {"$ref": "#/definitions/flowRateForPipettes"},
"dispenseFlowRate": {"$ref": "#/definitions/flowRateForPipettes"},
"aspirateMmFromBottom": {"$ref": "#/definitions/mmOffset"},
"dispenseMmFromBottom": {"$ref": "#/definitions/mmOffset"},
"touchTipMmFromTop": {"$ref": "#/definitions/mmOffset"}
}
},

"designerApplication": {
"description": "Optional data & metadata not required to execute the protocol, used by the application that created this protocol",
"type": "object",
"properties": {
"name": {
"description": "Name of the application that created the protocol. Should be namespaced under the organization or individual who owns the organization, eg \"opentrons/protocol-designer\"",
"type": "string"
},
"version": {
"description": "Version of the application that created the protocol",
"type": "string"
},
"data": {
"description": "Any data used by the application that created this protocol)",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is that an extra closing paren?

"type": "object"
}
}
},

"robot": {
"required": ["model"],
"properties": {
"model": {
"description": "Model of the robot this protocol is written for (currently only OT-2 Standard is supported)",
"type": "string",
"enum": ["OT-2 Standard"]
}
}
},

"pipettes": {
"description": "The pipettes used in this protocol, keyed by an arbitrary unique ID",
"additionalProperties": false,
"patternProperties": {
".+": {
"description": "Fields describing an individual pipette",
"type": "object",
"required": ["mount", "name"],
"additionalProperties": false,
"properties": {
"mount": {
"description": "Where the pipette is mounted",
"type": "string",
"enum": ["left", "right"]
},
"name": {
"$ref": "#/definitions/pipetteName"
}
}
}
}
},

"labwareDefinitions": {
"description": "All labware definitions used by labware in this protocol, keyed by UUID",
"patternProperties": {
".+": {
"$ref": "opentronsLabwareSchemaV2"
}
}
},

"labware": {
"description": "All types of labware used in this protocol, and references to their definitions",
"patternProperties": {
".+": {
"description": "Fields describing a single labware on the deck",
"type": "object",
"required": ["slot", "definitionId"],
"additionalProperties": false,
"properties": {
"slot": {"$ref": "#/definitions/slot"},
"definitionId": {
"description": "reference to this labware's ID in \"labwareDefinitions\"",
"type": "string"
},
"displayName": {
"description": "An optional human-readable nickname for this labware. Eg \"Buffer Trough\"",
"type": "string"
}
}
}
}
},

"commands": {
"description": "An array of command objects representing steps to be executed on the robot",
"type": "array",
"items": {
"anyOf": [
{
"description": "Aspirate / dispense / air gap commands",
"type": "object",
"required": ["command", "params"],
"additionalProperties": false,
"properties": {
"command": {
"enum": ["aspirate", "dispense", "airGap"]
},
"params": {
"allOf": [
{"$ref": "#/definitions/flowRateParams"},
{"$ref": "#/definitions/pipetteAccessParams"},
{"$ref": "#/definitions/volumeParams"},
{"$ref": "#/definitions/offsetFromBottomMm"}
]
}
}
},

{
"description": "Touch tip commands",
"type": "object",
"required": ["command", "params"],
"additionalProperties": false,
"properties": {
"command": {
"enum": ["touchTip"]
},
"params": {
"allOf": [
{"$ref": "#/definitions/pipetteAccessParams"},
{"$ref": "#/definitions/offsetFromBottomMm"}
]
}
}
},


{
"description": "Pick up tip / drop tip / blowout commands",
"type": "object",
"required": ["command", "params"],
"additionalProperties": false,
"properties": {
"command": {
"enum": ["pickUpTip", "dropTip", "blowout"]
},
"params": {
"allOf": [
{"$ref": "#/definitions/pipetteAccessParams"}
]
}
}
},

{
"description": "Move to slot command. NOTE: this is an EXPERIMENTAL command, its behavior is subject to change in future releases.",
"type": "object",
"required": ["command", "params"],
"additionalProperties": false,
"properties": {
"command": {"enum": ["moveToSlot"]},
"params": {
"type": "object",
"required": ["pipette", "slot"],
"additionalProperties": false,
"properties": {
"pipette": {"type": "string"},
"slot": {"$ref": "#/definitions/slot"},
"offset": {
"description": "Optional offset from slot bottom left corner, in mm",
"type": "object",
"required": ["x", "y", "z"],
"properties": {
"x": {"type": "number"},
"y": {"type": "number"},
"z": {"type": "number"}
}
},
"minimumZHeight": {
"description": "Optional minimal Z margin in mm. If this is larger than the API's default safe Z margin, it will make the arc higher. If it's smaller, it will have no effect. Specifying this for movements that would not arc (moving within the same well in the same labware) will cause an arc movement instead. This param only supported in API v2, API v1 will ignore it.",
"type": "number",
"minimum": 0
},
"forceDirect": {
"description": "Default is false. If true, moving from one labware/well to another will not arc to the default safe z, but instead will move directly to the specified location. This will also force the 'minimumZHeight' param to be ignored. In APIv1, this will use strategy='direct', which moves first in X/Y plane and then in Z. In API v2, a 'direct' movement is in X/Y/Z simultaneously",
"type": "boolean"
}
}
}
}
},

{
"description": "Delay command",
"type": "object",
"required": ["command", "params"],
"additionalProperties": false,
"properties": {
"command": {
"enum": ["delay"]
},
"params": {
"type": "object",
"additionalProperties": false,
"required": ["wait"],
"properties": {
"wait": {
"description": "either a number of seconds to wait (fractional values OK), or `true` to wait indefinitely until the user manually resumes the protocol",
"anyOf": [
{"type": "number"},
{"enum": [true]}
]
},
"message": {
"description": "optional message describing the delay"
}
}
}
}
}
]
}
},

"commandAnnotations": {
"description": "An optional object of annotations associated with commands. Its usage has not yet been defined, so its shape is not enforced by this schema.",
"type": "object"
}
}
}