Skip to content

feat(api): implement mix() parameters aspirate_delay and dispense_delay#18000

Merged
ddcc4 merged 8 commits intoedgefrom
dc-mix-delay
Apr 23, 2025
Merged

feat(api): implement mix() parameters aspirate_delay and dispense_delay#18000
ddcc4 merged 8 commits intoedgefrom
dc-mix-delay

Conversation

@ddcc4
Copy link
Copy Markdown
Contributor

@ddcc4 ddcc4 commented Apr 7, 2025

Overview

In PD, you can specify a delay after each aspirate and dispense in a Mix step. There is no way to specify a delay in the PAPI mix() call, which means that we can't translate a PD Mix step into a PAPI mix() call.

This PR introduces the parameters aspirate_delay and dispense_delay to the InstrumentContext.mix() function. The new parameters are gated to API version 2.24 and above. AUTH-1366

Test Plan and Hands on Testing

I added tests to demonstrate that this implementation emits the correct calls to delay() when the caller requests a delay in the mix().

This is what the output looks like in simulate:

Mixing 2 times with a volume of 20.0 ul
	Aspirating 20.0 uL from C2 of (Retired) Armadillo 96 Well Plate 200 µL PCR Full Skirt on slot A2 at 716.0 uL/sec
	Delaying for 0 minutes and 2.5 seconds
	Dispensing 20.0 uL into C2 of (Retired) Armadillo 96 Well Plate 200 µL PCR Full Skirt on slot A2 at 716.0 uL/sec
	...

Review requests

InstrumentContext.mix() calls InstrumentContext.aspirate() and InstrumentContext.dispense() to implement the mix, which is nice because the public aspirate() and dispense() functions handle things like publishing messages for the simulator.

Ideally, we would also call the public delay() function for the delay. But the delay() function is in ProtocolContext, and InstrumentContext doesn't have access to that. We only have access to the ProtocolCore, so we have to publish messages to the simulator manually.

I ended up refactoring the code of mix() a bit because it was going to get too repetitive and nested with the delays and publish_context() messages added.

Risk assessment

Should be low. The new parameters are version-gated. The main risk is that we release this, and then decide that we don't want to change the public API this way.

@ddcc4 ddcc4 requested review from jerader and sanni-t April 7, 2025 20:42
@ddcc4 ddcc4 requested a review from a team as a code owner April 7, 2025 20:42
@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 8, 2025

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 24.44%. Comparing base (31448fc) to head (460f249).

Additional details and impacted files

Impacted file tree graph

@@           Coverage Diff           @@
##             edge   #18000   +/-   ##
=======================================
  Coverage   24.44%   24.44%           
=======================================
  Files        2956     2956           
  Lines      228425   228425           
  Branches    19032    19032           
=======================================
  Hits        55843    55843           
  Misses     172570   172570           
  Partials       12       12           
Flag Coverage Δ
protocol-designer 18.79% <ø> (ø)
step-generation 4.42% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copy link
Copy Markdown
Collaborator

@jerader jerader left a comment

Choose a reason for hiding this comment

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

this is great, getting closer to always emitting python mix() when a mix step is added.

Copy link
Copy Markdown
Collaborator

@ncdiehl11 ncdiehl11 left a comment

Choose a reason for hiding this comment

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

This is looking good! Thank you for the details about why we need to manually publish a message to the broker. Tested simulation and the output looks as expected (snipped below). Approving with the caveat that a robot server dev should put eyes on this :)
Screenshot 2025-04-10 at 11 25 10 AM

@ddcc4
Copy link
Copy Markdown
Contributor Author

ddcc4 commented Apr 10, 2025

Tested simulation and the output looks as expected (snipped below).

Oh wow, thanks for testing it in the app!

Copy link
Copy Markdown
Member

@sanni-t sanni-t left a comment

Choose a reason for hiding this comment

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

LGTM! Just some small comments

Comment on lines +575 to +579
# protocol_api_old/test_context.py does not allow push_out at all, even if
# it's set to None, so we have to hide the argument to make the test pass.
# I don't know if the test is even valid, but I'm afraid to change the test.
dispense_kwargs = {"push_out": push_out} if push_out is not None else {}
self.dispense(volume, None, rate, **dispense_kwargs)
Copy link
Copy Markdown
Member

@sanni-t sanni-t Apr 22, 2025

Choose a reason for hiding this comment

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

Hmm, ya looks like we're raising an error if push_out is used in dispense in API versions < 2.15. The old context tests are for < v2.15.
I guess another way to write this would have been to skip the push_out based on API version but this works too. Maybe you can update the comment to mention that legacy context based dispense doesn't take a push_out arg and hence you have to do this.

Comment on lines +1611 to +1618
mock_instrument_core.aspirate(
input_location,
mock_well._core,
10.0,
1,
4.56,
True,
None,
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

A soft opinion- it's better to use kw args when calling any functions with more than 2 args, It gets difficult to read through the calls quickly otherwise.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Sure!

@ddcc4 ddcc4 merged commit 5012148 into edge Apr 23, 2025
24 checks passed
@ddcc4 ddcc4 deleted the dc-mix-delay branch April 23, 2025 18:06
ddcc4 added a commit that referenced this pull request May 16, 2025
…delay` (#18000)

# Overview

In PD, you can specify a delay after each aspirate and dispense in a Mix
step. There is no way to specify a delay in the PAPI `mix()` call, which
means that we can't translate a PD Mix step into a PAPI `mix()` call.

This PR introduces the parameters `aspirate_delay` and `dispense_delay`
to the `InstrumentContext.mix()` function. The new parameters are gated
to API version 2.24 and above. AUTH-1366

## Test Plan and Hands on Testing

I added tests to demonstrate that this implementation emits the correct
calls to `delay()` when the caller requests a delay in the `mix()`.

This is what the output looks like in `simulate`:
```
Mixing 2 times with a volume of 20.0 ul
	Aspirating 20.0 uL from C2 of (Retired) Armadillo 96 Well Plate 200 µL PCR Full Skirt on slot A2 at 716.0 uL/sec
	Delaying for 0 minutes and 2.5 seconds
	Dispensing 20.0 uL into C2 of (Retired) Armadillo 96 Well Plate 200 µL PCR Full Skirt on slot A2 at 716.0 uL/sec
	...
```

## Review requests

`InstrumentContext.mix()` calls `InstrumentContext.aspirate()` and
`InstrumentContext.dispense()` to implement the mix, which is nice
because the public `aspirate()` and `dispense()` functions handle things
like publishing messages for the simulator.

Ideally, we would also call the public `delay()` function for the delay.
But the `delay()` function is in `ProtocolContext`, and
`InstrumentContext` doesn't have access to that. We only have access to
the `ProtocolCore`, so we have to publish messages to the simulator
manually.

I ended up refactoring the code of `mix()` a bit because it was going to
get too repetitive and nested with the delays and `publish_context()`
messages added.

## Risk assessment

Should be low. The new parameters are version-gated. The main risk is
that we release this, and then decide that we don't want to change the
public API this way.
ddcc4 added a commit that referenced this pull request May 16, 2025
…delay` (#18000)

# Overview

In PD, you can specify a delay after each aspirate and dispense in a Mix
step. There is no way to specify a delay in the PAPI `mix()` call, which
means that we can't translate a PD Mix step into a PAPI `mix()` call.

This PR introduces the parameters `aspirate_delay` and `dispense_delay`
to the `InstrumentContext.mix()` function. The new parameters are gated
to API version 2.24 and above. AUTH-1366

## Test Plan and Hands on Testing

I added tests to demonstrate that this implementation emits the correct
calls to `delay()` when the caller requests a delay in the `mix()`.

This is what the output looks like in `simulate`:
```
Mixing 2 times with a volume of 20.0 ul
	Aspirating 20.0 uL from C2 of (Retired) Armadillo 96 Well Plate 200 µL PCR Full Skirt on slot A2 at 716.0 uL/sec
	Delaying for 0 minutes and 2.5 seconds
	Dispensing 20.0 uL into C2 of (Retired) Armadillo 96 Well Plate 200 µL PCR Full Skirt on slot A2 at 716.0 uL/sec
	...
```

## Review requests

`InstrumentContext.mix()` calls `InstrumentContext.aspirate()` and
`InstrumentContext.dispense()` to implement the mix, which is nice
because the public `aspirate()` and `dispense()` functions handle things
like publishing messages for the simulator.

Ideally, we would also call the public `delay()` function for the delay.
But the `delay()` function is in `ProtocolContext`, and
`InstrumentContext` doesn't have access to that. We only have access to
the `ProtocolCore`, so we have to publish messages to the simulator
manually.

I ended up refactoring the code of `mix()` a bit because it was going to
get too repetitive and nested with the delays and `publish_context()`
messages added.

## Risk assessment

Should be low. The new parameters are version-gated. The main risk is
that we release this, and then decide that we don't want to change the
public API this way.
ddcc4 added a commit that referenced this pull request May 16, 2025
…delay` (#18000)

# Overview

In PD, you can specify a delay after each aspirate and dispense in a Mix
step. There is no way to specify a delay in the PAPI `mix()` call, which
means that we can't translate a PD Mix step into a PAPI `mix()` call.

This PR introduces the parameters `aspirate_delay` and `dispense_delay`
to the `InstrumentContext.mix()` function. The new parameters are gated
to API version 2.24 and above. AUTH-1366

## Test Plan and Hands on Testing

I added tests to demonstrate that this implementation emits the correct
calls to `delay()` when the caller requests a delay in the `mix()`.

This is what the output looks like in `simulate`:
```
Mixing 2 times with a volume of 20.0 ul
	Aspirating 20.0 uL from C2 of (Retired) Armadillo 96 Well Plate 200 µL PCR Full Skirt on slot A2 at 716.0 uL/sec
	Delaying for 0 minutes and 2.5 seconds
	Dispensing 20.0 uL into C2 of (Retired) Armadillo 96 Well Plate 200 µL PCR Full Skirt on slot A2 at 716.0 uL/sec
	...
```

## Review requests

`InstrumentContext.mix()` calls `InstrumentContext.aspirate()` and
`InstrumentContext.dispense()` to implement the mix, which is nice
because the public `aspirate()` and `dispense()` functions handle things
like publishing messages for the simulator.

Ideally, we would also call the public `delay()` function for the delay.
But the `delay()` function is in `ProtocolContext`, and
`InstrumentContext` doesn't have access to that. We only have access to
the `ProtocolCore`, so we have to publish messages to the simulator
manually.

I ended up refactoring the code of `mix()` a bit because it was going to
get too repetitive and nested with the delays and `publish_context()`
messages added.

## Risk assessment

Should be low. The new parameters are version-gated. The main risk is
that we release this, and then decide that we don't want to change the
public API this way.
ddcc4 added a commit that referenced this pull request May 16, 2025
…delay` (#18000)

# Overview

In PD, you can specify a delay after each aspirate and dispense in a Mix
step. There is no way to specify a delay in the PAPI `mix()` call, which
means that we can't translate a PD Mix step into a PAPI `mix()` call.

This PR introduces the parameters `aspirate_delay` and `dispense_delay`
to the `InstrumentContext.mix()` function. The new parameters are gated
to API version 2.24 and above. AUTH-1366

## Test Plan and Hands on Testing

I added tests to demonstrate that this implementation emits the correct
calls to `delay()` when the caller requests a delay in the `mix()`.

This is what the output looks like in `simulate`:
```
Mixing 2 times with a volume of 20.0 ul
	Aspirating 20.0 uL from C2 of (Retired) Armadillo 96 Well Plate 200 µL PCR Full Skirt on slot A2 at 716.0 uL/sec
	Delaying for 0 minutes and 2.5 seconds
	Dispensing 20.0 uL into C2 of (Retired) Armadillo 96 Well Plate 200 µL PCR Full Skirt on slot A2 at 716.0 uL/sec
	...
```

## Review requests

`InstrumentContext.mix()` calls `InstrumentContext.aspirate()` and
`InstrumentContext.dispense()` to implement the mix, which is nice
because the public `aspirate()` and `dispense()` functions handle things
like publishing messages for the simulator.

Ideally, we would also call the public `delay()` function for the delay.
But the `delay()` function is in `ProtocolContext`, and
`InstrumentContext` doesn't have access to that. We only have access to
the `ProtocolCore`, so we have to publish messages to the simulator
manually.

I ended up refactoring the code of `mix()` a bit because it was going to
get too repetitive and nested with the delays and `publish_context()`
messages added.

## Risk assessment

Should be low. The new parameters are version-gated. The main risk is
that we release this, and then decide that we don't want to change the
public API this way.
ddcc4 added a commit that referenced this pull request May 16, 2025
…delay` (#18000)

# Overview

In PD, you can specify a delay after each aspirate and dispense in a Mix
step. There is no way to specify a delay in the PAPI `mix()` call, which
means that we can't translate a PD Mix step into a PAPI `mix()` call.

This PR introduces the parameters `aspirate_delay` and `dispense_delay`
to the `InstrumentContext.mix()` function. The new parameters are gated
to API version 2.24 and above. AUTH-1366

## Test Plan and Hands on Testing

I added tests to demonstrate that this implementation emits the correct
calls to `delay()` when the caller requests a delay in the `mix()`.

This is what the output looks like in `simulate`:
```
Mixing 2 times with a volume of 20.0 ul
	Aspirating 20.0 uL from C2 of (Retired) Armadillo 96 Well Plate 200 µL PCR Full Skirt on slot A2 at 716.0 uL/sec
	Delaying for 0 minutes and 2.5 seconds
	Dispensing 20.0 uL into C2 of (Retired) Armadillo 96 Well Plate 200 µL PCR Full Skirt on slot A2 at 716.0 uL/sec
	...
```

## Review requests

`InstrumentContext.mix()` calls `InstrumentContext.aspirate()` and
`InstrumentContext.dispense()` to implement the mix, which is nice
because the public `aspirate()` and `dispense()` functions handle things
like publishing messages for the simulator.

Ideally, we would also call the public `delay()` function for the delay.
But the `delay()` function is in `ProtocolContext`, and
`InstrumentContext` doesn't have access to that. We only have access to
the `ProtocolCore`, so we have to publish messages to the simulator
manually.

I ended up refactoring the code of `mix()` a bit because it was going to
get too repetitive and nested with the delays and `publish_context()`
messages added.

## Risk assessment

Should be low. The new parameters are version-gated. The main risk is
that we release this, and then decide that we don't want to change the
public API this way.
ddcc4 added a commit that referenced this pull request May 16, 2025
…delay` (#18000)

# Overview

In PD, you can specify a delay after each aspirate and dispense in a Mix
step. There is no way to specify a delay in the PAPI `mix()` call, which
means that we can't translate a PD Mix step into a PAPI `mix()` call.

This PR introduces the parameters `aspirate_delay` and `dispense_delay`
to the `InstrumentContext.mix()` function. The new parameters are gated
to API version 2.24 and above. AUTH-1366

## Test Plan and Hands on Testing

I added tests to demonstrate that this implementation emits the correct
calls to `delay()` when the caller requests a delay in the `mix()`.

This is what the output looks like in `simulate`:
```
Mixing 2 times with a volume of 20.0 ul
	Aspirating 20.0 uL from C2 of (Retired) Armadillo 96 Well Plate 200 µL PCR Full Skirt on slot A2 at 716.0 uL/sec
	Delaying for 0 minutes and 2.5 seconds
	Dispensing 20.0 uL into C2 of (Retired) Armadillo 96 Well Plate 200 µL PCR Full Skirt on slot A2 at 716.0 uL/sec
	...
```

## Review requests

`InstrumentContext.mix()` calls `InstrumentContext.aspirate()` and
`InstrumentContext.dispense()` to implement the mix, which is nice
because the public `aspirate()` and `dispense()` functions handle things
like publishing messages for the simulator.

Ideally, we would also call the public `delay()` function for the delay.
But the `delay()` function is in `ProtocolContext`, and
`InstrumentContext` doesn't have access to that. We only have access to
the `ProtocolCore`, so we have to publish messages to the simulator
manually.

I ended up refactoring the code of `mix()` a bit because it was going to
get too repetitive and nested with the delays and `publish_context()`
messages added.

## Risk assessment

Should be low. The new parameters are version-gated. The main risk is
that we release this, and then decide that we don't want to change the
public API this way.
ddcc4 added a commit that referenced this pull request May 17, 2025
…delay` (#18000)

# Overview

In PD, you can specify a delay after each aspirate and dispense in a Mix
step. There is no way to specify a delay in the PAPI `mix()` call, which
means that we can't translate a PD Mix step into a PAPI `mix()` call.

This PR introduces the parameters `aspirate_delay` and `dispense_delay`
to the `InstrumentContext.mix()` function. The new parameters are gated
to API version 2.24 and above. AUTH-1366

## Test Plan and Hands on Testing

I added tests to demonstrate that this implementation emits the correct
calls to `delay()` when the caller requests a delay in the `mix()`.

This is what the output looks like in `simulate`:
```
Mixing 2 times with a volume of 20.0 ul
	Aspirating 20.0 uL from C2 of (Retired) Armadillo 96 Well Plate 200 µL PCR Full Skirt on slot A2 at 716.0 uL/sec
	Delaying for 0 minutes and 2.5 seconds
	Dispensing 20.0 uL into C2 of (Retired) Armadillo 96 Well Plate 200 µL PCR Full Skirt on slot A2 at 716.0 uL/sec
	...
```

## Review requests

`InstrumentContext.mix()` calls `InstrumentContext.aspirate()` and
`InstrumentContext.dispense()` to implement the mix, which is nice
because the public `aspirate()` and `dispense()` functions handle things
like publishing messages for the simulator.

Ideally, we would also call the public `delay()` function for the delay.
But the `delay()` function is in `ProtocolContext`, and
`InstrumentContext` doesn't have access to that. We only have access to
the `ProtocolCore`, so we have to publish messages to the simulator
manually.

I ended up refactoring the code of `mix()` a bit because it was going to
get too repetitive and nested with the delays and `publish_context()`
messages added.

## Risk assessment

Should be low. The new parameters are version-gated. The main risk is
that we release this, and then decide that we don't want to change the
public API this way.
ddcc4 added a commit that referenced this pull request May 17, 2025
…delay` (#18000)

# Overview

In PD, you can specify a delay after each aspirate and dispense in a Mix
step. There is no way to specify a delay in the PAPI `mix()` call, which
means that we can't translate a PD Mix step into a PAPI `mix()` call.

This PR introduces the parameters `aspirate_delay` and `dispense_delay`
to the `InstrumentContext.mix()` function. The new parameters are gated
to API version 2.24 and above. AUTH-1366

## Test Plan and Hands on Testing

I added tests to demonstrate that this implementation emits the correct
calls to `delay()` when the caller requests a delay in the `mix()`.

This is what the output looks like in `simulate`:
```
Mixing 2 times with a volume of 20.0 ul
	Aspirating 20.0 uL from C2 of (Retired) Armadillo 96 Well Plate 200 µL PCR Full Skirt on slot A2 at 716.0 uL/sec
	Delaying for 0 minutes and 2.5 seconds
	Dispensing 20.0 uL into C2 of (Retired) Armadillo 96 Well Plate 200 µL PCR Full Skirt on slot A2 at 716.0 uL/sec
	...
```

## Review requests

`InstrumentContext.mix()` calls `InstrumentContext.aspirate()` and
`InstrumentContext.dispense()` to implement the mix, which is nice
because the public `aspirate()` and `dispense()` functions handle things
like publishing messages for the simulator.

Ideally, we would also call the public `delay()` function for the delay.
But the `delay()` function is in `ProtocolContext`, and
`InstrumentContext` doesn't have access to that. We only have access to
the `ProtocolCore`, so we have to publish messages to the simulator
manually.

I ended up refactoring the code of `mix()` a bit because it was going to
get too repetitive and nested with the delays and `publish_context()`
messages added.

## Risk assessment

Should be low. The new parameters are version-gated. The main risk is
that we release this, and then decide that we don't want to change the
public API this way.
ddcc4 added a commit that referenced this pull request May 17, 2025
…delay` (#18000)

# Overview

In PD, you can specify a delay after each aspirate and dispense in a Mix
step. There is no way to specify a delay in the PAPI `mix()` call, which
means that we can't translate a PD Mix step into a PAPI `mix()` call.

This PR introduces the parameters `aspirate_delay` and `dispense_delay`
to the `InstrumentContext.mix()` function. The new parameters are gated
to API version 2.24 and above. AUTH-1366

## Test Plan and Hands on Testing

I added tests to demonstrate that this implementation emits the correct
calls to `delay()` when the caller requests a delay in the `mix()`.

This is what the output looks like in `simulate`:
```
Mixing 2 times with a volume of 20.0 ul
	Aspirating 20.0 uL from C2 of (Retired) Armadillo 96 Well Plate 200 µL PCR Full Skirt on slot A2 at 716.0 uL/sec
	Delaying for 0 minutes and 2.5 seconds
	Dispensing 20.0 uL into C2 of (Retired) Armadillo 96 Well Plate 200 µL PCR Full Skirt on slot A2 at 716.0 uL/sec
	...
```

## Review requests

`InstrumentContext.mix()` calls `InstrumentContext.aspirate()` and
`InstrumentContext.dispense()` to implement the mix, which is nice
because the public `aspirate()` and `dispense()` functions handle things
like publishing messages for the simulator.

Ideally, we would also call the public `delay()` function for the delay.
But the `delay()` function is in `ProtocolContext`, and
`InstrumentContext` doesn't have access to that. We only have access to
the `ProtocolCore`, so we have to publish messages to the simulator
manually.

I ended up refactoring the code of `mix()` a bit because it was going to
get too repetitive and nested with the delays and `publish_context()`
messages added.

## Risk assessment

Should be low. The new parameters are version-gated. The main risk is
that we release this, and then decide that we don't want to change the
public API this way.
ddcc4 added a commit that referenced this pull request May 17, 2025
…delay` (#18000)

# Overview

In PD, you can specify a delay after each aspirate and dispense in a Mix
step. There is no way to specify a delay in the PAPI `mix()` call, which
means that we can't translate a PD Mix step into a PAPI `mix()` call.

This PR introduces the parameters `aspirate_delay` and `dispense_delay`
to the `InstrumentContext.mix()` function. The new parameters are gated
to API version 2.24 and above. AUTH-1366

## Test Plan and Hands on Testing

I added tests to demonstrate that this implementation emits the correct
calls to `delay()` when the caller requests a delay in the `mix()`.

This is what the output looks like in `simulate`:
```
Mixing 2 times with a volume of 20.0 ul
	Aspirating 20.0 uL from C2 of (Retired) Armadillo 96 Well Plate 200 µL PCR Full Skirt on slot A2 at 716.0 uL/sec
	Delaying for 0 minutes and 2.5 seconds
	Dispensing 20.0 uL into C2 of (Retired) Armadillo 96 Well Plate 200 µL PCR Full Skirt on slot A2 at 716.0 uL/sec
	...
```

## Review requests

`InstrumentContext.mix()` calls `InstrumentContext.aspirate()` and
`InstrumentContext.dispense()` to implement the mix, which is nice
because the public `aspirate()` and `dispense()` functions handle things
like publishing messages for the simulator.

Ideally, we would also call the public `delay()` function for the delay.
But the `delay()` function is in `ProtocolContext`, and
`InstrumentContext` doesn't have access to that. We only have access to
the `ProtocolCore`, so we have to publish messages to the simulator
manually.

I ended up refactoring the code of `mix()` a bit because it was going to
get too repetitive and nested with the delays and `publish_context()`
messages added.

## Risk assessment

Should be low. The new parameters are version-gated. The main risk is
that we release this, and then decide that we don't want to change the
public API this way.

(cherry picked from commit 5012148)
ddcc4 added a commit that referenced this pull request May 17, 2025
…delay` (#18000)

# Overview

In PD, you can specify a delay after each aspirate and dispense in a Mix
step. There is no way to specify a delay in the PAPI `mix()` call, which
means that we can't translate a PD Mix step into a PAPI `mix()` call.

This PR introduces the parameters `aspirate_delay` and `dispense_delay`
to the `InstrumentContext.mix()` function. The new parameters are gated
to API version 2.24 and above. AUTH-1366

## Test Plan and Hands on Testing

I added tests to demonstrate that this implementation emits the correct
calls to `delay()` when the caller requests a delay in the `mix()`.

This is what the output looks like in `simulate`:
```
Mixing 2 times with a volume of 20.0 ul
	Aspirating 20.0 uL from C2 of (Retired) Armadillo 96 Well Plate 200 µL PCR Full Skirt on slot A2 at 716.0 uL/sec
	Delaying for 0 minutes and 2.5 seconds
	Dispensing 20.0 uL into C2 of (Retired) Armadillo 96 Well Plate 200 µL PCR Full Skirt on slot A2 at 716.0 uL/sec
	...
```

## Review requests

`InstrumentContext.mix()` calls `InstrumentContext.aspirate()` and
`InstrumentContext.dispense()` to implement the mix, which is nice
because the public `aspirate()` and `dispense()` functions handle things
like publishing messages for the simulator.

Ideally, we would also call the public `delay()` function for the delay.
But the `delay()` function is in `ProtocolContext`, and
`InstrumentContext` doesn't have access to that. We only have access to
the `ProtocolCore`, so we have to publish messages to the simulator
manually.

I ended up refactoring the code of `mix()` a bit because it was going to
get too repetitive and nested with the delays and `publish_context()`
messages added.

## Risk assessment

Should be low. The new parameters are version-gated. The main risk is
that we release this, and then decide that we don't want to change the
public API this way.

(cherry picked from commit 5012148)
ddcc4 added a commit that referenced this pull request May 17, 2025
…delay` (#18000)

# Overview

In PD, you can specify a delay after each aspirate and dispense in a Mix
step. There is no way to specify a delay in the PAPI `mix()` call, which
means that we can't translate a PD Mix step into a PAPI `mix()` call.

This PR introduces the parameters `aspirate_delay` and `dispense_delay`
to the `InstrumentContext.mix()` function. The new parameters are gated
to API version 2.24 and above. AUTH-1366

## Test Plan and Hands on Testing

I added tests to demonstrate that this implementation emits the correct
calls to `delay()` when the caller requests a delay in the `mix()`.

This is what the output looks like in `simulate`:
```
Mixing 2 times with a volume of 20.0 ul
	Aspirating 20.0 uL from C2 of (Retired) Armadillo 96 Well Plate 200 µL PCR Full Skirt on slot A2 at 716.0 uL/sec
	Delaying for 0 minutes and 2.5 seconds
	Dispensing 20.0 uL into C2 of (Retired) Armadillo 96 Well Plate 200 µL PCR Full Skirt on slot A2 at 716.0 uL/sec
	...
```

## Review requests

`InstrumentContext.mix()` calls `InstrumentContext.aspirate()` and
`InstrumentContext.dispense()` to implement the mix, which is nice
because the public `aspirate()` and `dispense()` functions handle things
like publishing messages for the simulator.

Ideally, we would also call the public `delay()` function for the delay.
But the `delay()` function is in `ProtocolContext`, and
`InstrumentContext` doesn't have access to that. We only have access to
the `ProtocolCore`, so we have to publish messages to the simulator
manually.

I ended up refactoring the code of `mix()` a bit because it was going to
get too repetitive and nested with the delays and `publish_context()`
messages added.

## Risk assessment

Should be low. The new parameters are version-gated. The main risk is
that we release this, and then decide that we don't want to change the
public API this way.

(cherry picked from commit 5012148)
ddcc4 added a commit that referenced this pull request May 17, 2025
…delay` (#18000)

# Overview

In PD, you can specify a delay after each aspirate and dispense in a Mix
step. There is no way to specify a delay in the PAPI `mix()` call, which
means that we can't translate a PD Mix step into a PAPI `mix()` call.

This PR introduces the parameters `aspirate_delay` and `dispense_delay`
to the `InstrumentContext.mix()` function. The new parameters are gated
to API version 2.24 and above. AUTH-1366

## Test Plan and Hands on Testing

I added tests to demonstrate that this implementation emits the correct
calls to `delay()` when the caller requests a delay in the `mix()`.

This is what the output looks like in `simulate`:
```
Mixing 2 times with a volume of 20.0 ul
	Aspirating 20.0 uL from C2 of (Retired) Armadillo 96 Well Plate 200 µL PCR Full Skirt on slot A2 at 716.0 uL/sec
	Delaying for 0 minutes and 2.5 seconds
	Dispensing 20.0 uL into C2 of (Retired) Armadillo 96 Well Plate 200 µL PCR Full Skirt on slot A2 at 716.0 uL/sec
	...
```

## Review requests

`InstrumentContext.mix()` calls `InstrumentContext.aspirate()` and
`InstrumentContext.dispense()` to implement the mix, which is nice
because the public `aspirate()` and `dispense()` functions handle things
like publishing messages for the simulator.

Ideally, we would also call the public `delay()` function for the delay.
But the `delay()` function is in `ProtocolContext`, and
`InstrumentContext` doesn't have access to that. We only have access to
the `ProtocolCore`, so we have to publish messages to the simulator
manually.

I ended up refactoring the code of `mix()` a bit because it was going to
get too repetitive and nested with the delays and `publish_context()`
messages added.

## Risk assessment

Should be low. The new parameters are version-gated. The main risk is
that we release this, and then decide that we don't want to change the
public API this way.

(cherry picked from commit 5012148)
ddcc4 added a commit that referenced this pull request May 17, 2025
…delay` (#18000)

# Overview

In PD, you can specify a delay after each aspirate and dispense in a Mix
step. There is no way to specify a delay in the PAPI `mix()` call, which
means that we can't translate a PD Mix step into a PAPI `mix()` call.

This PR introduces the parameters `aspirate_delay` and `dispense_delay`
to the `InstrumentContext.mix()` function. The new parameters are gated
to API version 2.24 and above. AUTH-1366

## Test Plan and Hands on Testing

I added tests to demonstrate that this implementation emits the correct
calls to `delay()` when the caller requests a delay in the `mix()`.

This is what the output looks like in `simulate`:
```
Mixing 2 times with a volume of 20.0 ul
	Aspirating 20.0 uL from C2 of (Retired) Armadillo 96 Well Plate 200 µL PCR Full Skirt on slot A2 at 716.0 uL/sec
	Delaying for 0 minutes and 2.5 seconds
	Dispensing 20.0 uL into C2 of (Retired) Armadillo 96 Well Plate 200 µL PCR Full Skirt on slot A2 at 716.0 uL/sec
	...
```

## Review requests

`InstrumentContext.mix()` calls `InstrumentContext.aspirate()` and
`InstrumentContext.dispense()` to implement the mix, which is nice
because the public `aspirate()` and `dispense()` functions handle things
like publishing messages for the simulator.

Ideally, we would also call the public `delay()` function for the delay.
But the `delay()` function is in `ProtocolContext`, and
`InstrumentContext` doesn't have access to that. We only have access to
the `ProtocolCore`, so we have to publish messages to the simulator
manually.

I ended up refactoring the code of `mix()` a bit because it was going to
get too repetitive and nested with the delays and `publish_context()`
messages added.

## Risk assessment

Should be low. The new parameters are version-gated. The main risk is
that we release this, and then decide that we don't want to change the
public API this way.

(cherry picked from commit 5012148)
ddcc4 added a commit that referenced this pull request May 17, 2025
…delay` (#18000)

# Overview

In PD, you can specify a delay after each aspirate and dispense in a Mix
step. There is no way to specify a delay in the PAPI `mix()` call, which
means that we can't translate a PD Mix step into a PAPI `mix()` call.

This PR introduces the parameters `aspirate_delay` and `dispense_delay`
to the `InstrumentContext.mix()` function. The new parameters are gated
to API version 2.24 and above. AUTH-1366

## Test Plan and Hands on Testing

I added tests to demonstrate that this implementation emits the correct
calls to `delay()` when the caller requests a delay in the `mix()`.

This is what the output looks like in `simulate`:
```
Mixing 2 times with a volume of 20.0 ul
	Aspirating 20.0 uL from C2 of (Retired) Armadillo 96 Well Plate 200 µL PCR Full Skirt on slot A2 at 716.0 uL/sec
	Delaying for 0 minutes and 2.5 seconds
	Dispensing 20.0 uL into C2 of (Retired) Armadillo 96 Well Plate 200 µL PCR Full Skirt on slot A2 at 716.0 uL/sec
	...
```

## Review requests

`InstrumentContext.mix()` calls `InstrumentContext.aspirate()` and
`InstrumentContext.dispense()` to implement the mix, which is nice
because the public `aspirate()` and `dispense()` functions handle things
like publishing messages for the simulator.

Ideally, we would also call the public `delay()` function for the delay.
But the `delay()` function is in `ProtocolContext`, and
`InstrumentContext` doesn't have access to that. We only have access to
the `ProtocolCore`, so we have to publish messages to the simulator
manually.

I ended up refactoring the code of `mix()` a bit because it was going to
get too repetitive and nested with the delays and `publish_context()`
messages added.

## Risk assessment

Should be low. The new parameters are version-gated. The main risk is
that we release this, and then decide that we don't want to change the
public API this way.

(cherry picked from commit 5012148)
ddcc4 added a commit that referenced this pull request May 19, 2025
…delay` (#18000)

# Overview

In PD, you can specify a delay after each aspirate and dispense in a Mix
step. There is no way to specify a delay in the PAPI `mix()` call, which
means that we can't translate a PD Mix step into a PAPI `mix()` call.

This PR introduces the parameters `aspirate_delay` and `dispense_delay`
to the `InstrumentContext.mix()` function. The new parameters are gated
to API version 2.24 and above. AUTH-1366

## Test Plan and Hands on Testing

I added tests to demonstrate that this implementation emits the correct
calls to `delay()` when the caller requests a delay in the `mix()`.

This is what the output looks like in `simulate`:
```
Mixing 2 times with a volume of 20.0 ul
	Aspirating 20.0 uL from C2 of (Retired) Armadillo 96 Well Plate 200 µL PCR Full Skirt on slot A2 at 716.0 uL/sec
	Delaying for 0 minutes and 2.5 seconds
	Dispensing 20.0 uL into C2 of (Retired) Armadillo 96 Well Plate 200 µL PCR Full Skirt on slot A2 at 716.0 uL/sec
	...
```

## Review requests

`InstrumentContext.mix()` calls `InstrumentContext.aspirate()` and
`InstrumentContext.dispense()` to implement the mix, which is nice
because the public `aspirate()` and `dispense()` functions handle things
like publishing messages for the simulator.

Ideally, we would also call the public `delay()` function for the delay.
But the `delay()` function is in `ProtocolContext`, and
`InstrumentContext` doesn't have access to that. We only have access to
the `ProtocolCore`, so we have to publish messages to the simulator
manually.

I ended up refactoring the code of `mix()` a bit because it was going to
get too repetitive and nested with the delays and `publish_context()`
messages added.

## Risk assessment

Should be low. The new parameters are version-gated. The main risk is
that we release this, and then decide that we don't want to change the
public API this way.

(cherry picked from commit 5012148)
ddcc4 added a commit that referenced this pull request May 19, 2025
…delay` (#18000)

# Overview

In PD, you can specify a delay after each aspirate and dispense in a Mix
step. There is no way to specify a delay in the PAPI `mix()` call, which
means that we can't translate a PD Mix step into a PAPI `mix()` call.

This PR introduces the parameters `aspirate_delay` and `dispense_delay`
to the `InstrumentContext.mix()` function. The new parameters are gated
to API version 2.24 and above. AUTH-1366

## Test Plan and Hands on Testing

I added tests to demonstrate that this implementation emits the correct
calls to `delay()` when the caller requests a delay in the `mix()`.

This is what the output looks like in `simulate`:
```
Mixing 2 times with a volume of 20.0 ul
	Aspirating 20.0 uL from C2 of (Retired) Armadillo 96 Well Plate 200 µL PCR Full Skirt on slot A2 at 716.0 uL/sec
	Delaying for 0 minutes and 2.5 seconds
	Dispensing 20.0 uL into C2 of (Retired) Armadillo 96 Well Plate 200 µL PCR Full Skirt on slot A2 at 716.0 uL/sec
	...
```

## Review requests

`InstrumentContext.mix()` calls `InstrumentContext.aspirate()` and
`InstrumentContext.dispense()` to implement the mix, which is nice
because the public `aspirate()` and `dispense()` functions handle things
like publishing messages for the simulator.

Ideally, we would also call the public `delay()` function for the delay.
But the `delay()` function is in `ProtocolContext`, and
`InstrumentContext` doesn't have access to that. We only have access to
the `ProtocolCore`, so we have to publish messages to the simulator
manually.

I ended up refactoring the code of `mix()` a bit because it was going to
get too repetitive and nested with the delays and `publish_context()`
messages added.

## Risk assessment

Should be low. The new parameters are version-gated. The main risk is
that we release this, and then decide that we don't want to change the
public API this way.

(cherry picked from commit 5012148)
ddcc4 added a commit that referenced this pull request May 19, 2025
…delay` (#18000)

# Overview

In PD, you can specify a delay after each aspirate and dispense in a Mix
step. There is no way to specify a delay in the PAPI `mix()` call, which
means that we can't translate a PD Mix step into a PAPI `mix()` call.

This PR introduces the parameters `aspirate_delay` and `dispense_delay`
to the `InstrumentContext.mix()` function. The new parameters are gated
to API version 2.24 and above. AUTH-1366

## Test Plan and Hands on Testing

I added tests to demonstrate that this implementation emits the correct
calls to `delay()` when the caller requests a delay in the `mix()`.

This is what the output looks like in `simulate`:
```
Mixing 2 times with a volume of 20.0 ul
	Aspirating 20.0 uL from C2 of (Retired) Armadillo 96 Well Plate 200 µL PCR Full Skirt on slot A2 at 716.0 uL/sec
	Delaying for 0 minutes and 2.5 seconds
	Dispensing 20.0 uL into C2 of (Retired) Armadillo 96 Well Plate 200 µL PCR Full Skirt on slot A2 at 716.0 uL/sec
	...
```

## Review requests

`InstrumentContext.mix()` calls `InstrumentContext.aspirate()` and
`InstrumentContext.dispense()` to implement the mix, which is nice
because the public `aspirate()` and `dispense()` functions handle things
like publishing messages for the simulator.

Ideally, we would also call the public `delay()` function for the delay.
But the `delay()` function is in `ProtocolContext`, and
`InstrumentContext` doesn't have access to that. We only have access to
the `ProtocolCore`, so we have to publish messages to the simulator
manually.

I ended up refactoring the code of `mix()` a bit because it was going to
get too repetitive and nested with the delays and `publish_context()`
messages added.

## Risk assessment

Should be low. The new parameters are version-gated. The main risk is
that we release this, and then decide that we don't want to change the
public API this way.

(cherry picked from commit 5012148)
ddcc4 added a commit that referenced this pull request May 20, 2025
…delay` (#18000)

# Overview

In PD, you can specify a delay after each aspirate and dispense in a Mix
step. There is no way to specify a delay in the PAPI `mix()` call, which
means that we can't translate a PD Mix step into a PAPI `mix()` call.

This PR introduces the parameters `aspirate_delay` and `dispense_delay`
to the `InstrumentContext.mix()` function. The new parameters are gated
to API version 2.24 and above. AUTH-1366

## Test Plan and Hands on Testing

I added tests to demonstrate that this implementation emits the correct
calls to `delay()` when the caller requests a delay in the `mix()`.

This is what the output looks like in `simulate`:
```
Mixing 2 times with a volume of 20.0 ul
	Aspirating 20.0 uL from C2 of (Retired) Armadillo 96 Well Plate 200 µL PCR Full Skirt on slot A2 at 716.0 uL/sec
	Delaying for 0 minutes and 2.5 seconds
	Dispensing 20.0 uL into C2 of (Retired) Armadillo 96 Well Plate 200 µL PCR Full Skirt on slot A2 at 716.0 uL/sec
	...
```

## Review requests

`InstrumentContext.mix()` calls `InstrumentContext.aspirate()` and
`InstrumentContext.dispense()` to implement the mix, which is nice
because the public `aspirate()` and `dispense()` functions handle things
like publishing messages for the simulator.

Ideally, we would also call the public `delay()` function for the delay.
But the `delay()` function is in `ProtocolContext`, and
`InstrumentContext` doesn't have access to that. We only have access to
the `ProtocolCore`, so we have to publish messages to the simulator
manually.

I ended up refactoring the code of `mix()` a bit because it was going to
get too repetitive and nested with the delays and `publish_context()`
messages added.

## Risk assessment

Should be low. The new parameters are version-gated. The main risk is
that we release this, and then decide that we don't want to change the
public API this way.

(cherry picked from commit 5012148)
ddcc4 added a commit that referenced this pull request May 20, 2025
…delay` (#18000)

# Overview

In PD, you can specify a delay after each aspirate and dispense in a Mix
step. There is no way to specify a delay in the PAPI `mix()` call, which
means that we can't translate a PD Mix step into a PAPI `mix()` call.

This PR introduces the parameters `aspirate_delay` and `dispense_delay`
to the `InstrumentContext.mix()` function. The new parameters are gated
to API version 2.24 and above. AUTH-1366

## Test Plan and Hands on Testing

I added tests to demonstrate that this implementation emits the correct
calls to `delay()` when the caller requests a delay in the `mix()`.

This is what the output looks like in `simulate`:
```
Mixing 2 times with a volume of 20.0 ul
	Aspirating 20.0 uL from C2 of (Retired) Armadillo 96 Well Plate 200 µL PCR Full Skirt on slot A2 at 716.0 uL/sec
	Delaying for 0 minutes and 2.5 seconds
	Dispensing 20.0 uL into C2 of (Retired) Armadillo 96 Well Plate 200 µL PCR Full Skirt on slot A2 at 716.0 uL/sec
	...
```

## Review requests

`InstrumentContext.mix()` calls `InstrumentContext.aspirate()` and
`InstrumentContext.dispense()` to implement the mix, which is nice
because the public `aspirate()` and `dispense()` functions handle things
like publishing messages for the simulator.

Ideally, we would also call the public `delay()` function for the delay.
But the `delay()` function is in `ProtocolContext`, and
`InstrumentContext` doesn't have access to that. We only have access to
the `ProtocolCore`, so we have to publish messages to the simulator
manually.

I ended up refactoring the code of `mix()` a bit because it was going to
get too repetitive and nested with the delays and `publish_context()`
messages added.

## Risk assessment

Should be low. The new parameters are version-gated. The main risk is
that we release this, and then decide that we don't want to change the
public API this way.

(cherry picked from commit 5012148)
ddcc4 added a commit that referenced this pull request May 22, 2025
…delay` (#18000)

# Overview

In PD, you can specify a delay after each aspirate and dispense in a Mix
step. There is no way to specify a delay in the PAPI `mix()` call, which
means that we can't translate a PD Mix step into a PAPI `mix()` call.

This PR introduces the parameters `aspirate_delay` and `dispense_delay`
to the `InstrumentContext.mix()` function. The new parameters are gated
to API version 2.24 and above. AUTH-1366

## Test Plan and Hands on Testing

I added tests to demonstrate that this implementation emits the correct
calls to `delay()` when the caller requests a delay in the `mix()`.

This is what the output looks like in `simulate`:
```
Mixing 2 times with a volume of 20.0 ul
	Aspirating 20.0 uL from C2 of (Retired) Armadillo 96 Well Plate 200 µL PCR Full Skirt on slot A2 at 716.0 uL/sec
	Delaying for 0 minutes and 2.5 seconds
	Dispensing 20.0 uL into C2 of (Retired) Armadillo 96 Well Plate 200 µL PCR Full Skirt on slot A2 at 716.0 uL/sec
	...
```

## Review requests

`InstrumentContext.mix()` calls `InstrumentContext.aspirate()` and
`InstrumentContext.dispense()` to implement the mix, which is nice
because the public `aspirate()` and `dispense()` functions handle things
like publishing messages for the simulator.

Ideally, we would also call the public `delay()` function for the delay.
But the `delay()` function is in `ProtocolContext`, and
`InstrumentContext` doesn't have access to that. We only have access to
the `ProtocolCore`, so we have to publish messages to the simulator
manually.

I ended up refactoring the code of `mix()` a bit because it was going to
get too repetitive and nested with the delays and `publish_context()`
messages added.

## Risk assessment

Should be low. The new parameters are version-gated. The main risk is
that we release this, and then decide that we don't want to change the
public API this way.

(cherry picked from commit 5012148)
ddcc4 added a commit that referenced this pull request May 23, 2025
…delay` (#18000)

# Overview

In PD, you can specify a delay after each aspirate and dispense in a Mix
step. There is no way to specify a delay in the PAPI `mix()` call, which
means that we can't translate a PD Mix step into a PAPI `mix()` call.

This PR introduces the parameters `aspirate_delay` and `dispense_delay`
to the `InstrumentContext.mix()` function. The new parameters are gated
to API version 2.24 and above. AUTH-1366

## Test Plan and Hands on Testing

I added tests to demonstrate that this implementation emits the correct
calls to `delay()` when the caller requests a delay in the `mix()`.

This is what the output looks like in `simulate`:
```
Mixing 2 times with a volume of 20.0 ul
	Aspirating 20.0 uL from C2 of (Retired) Armadillo 96 Well Plate 200 µL PCR Full Skirt on slot A2 at 716.0 uL/sec
	Delaying for 0 minutes and 2.5 seconds
	Dispensing 20.0 uL into C2 of (Retired) Armadillo 96 Well Plate 200 µL PCR Full Skirt on slot A2 at 716.0 uL/sec
	...
```

## Review requests

`InstrumentContext.mix()` calls `InstrumentContext.aspirate()` and
`InstrumentContext.dispense()` to implement the mix, which is nice
because the public `aspirate()` and `dispense()` functions handle things
like publishing messages for the simulator.

Ideally, we would also call the public `delay()` function for the delay.
But the `delay()` function is in `ProtocolContext`, and
`InstrumentContext` doesn't have access to that. We only have access to
the `ProtocolCore`, so we have to publish messages to the simulator
manually.

I ended up refactoring the code of `mix()` a bit because it was going to
get too repetitive and nested with the delays and `publish_context()`
messages added.

## Risk assessment

Should be low. The new parameters are version-gated. The main risk is
that we release this, and then decide that we don't want to change the
public API this way.

(cherry picked from commit 5012148)
ddcc4 added a commit that referenced this pull request May 24, 2025
…delay` (#18000)

# Overview

In PD, you can specify a delay after each aspirate and dispense in a Mix
step. There is no way to specify a delay in the PAPI `mix()` call, which
means that we can't translate a PD Mix step into a PAPI `mix()` call.

This PR introduces the parameters `aspirate_delay` and `dispense_delay`
to the `InstrumentContext.mix()` function. The new parameters are gated
to API version 2.24 and above. AUTH-1366

## Test Plan and Hands on Testing

I added tests to demonstrate that this implementation emits the correct
calls to `delay()` when the caller requests a delay in the `mix()`.

This is what the output looks like in `simulate`:
```
Mixing 2 times with a volume of 20.0 ul
	Aspirating 20.0 uL from C2 of (Retired) Armadillo 96 Well Plate 200 µL PCR Full Skirt on slot A2 at 716.0 uL/sec
	Delaying for 0 minutes and 2.5 seconds
	Dispensing 20.0 uL into C2 of (Retired) Armadillo 96 Well Plate 200 µL PCR Full Skirt on slot A2 at 716.0 uL/sec
	...
```

## Review requests

`InstrumentContext.mix()` calls `InstrumentContext.aspirate()` and
`InstrumentContext.dispense()` to implement the mix, which is nice
because the public `aspirate()` and `dispense()` functions handle things
like publishing messages for the simulator.

Ideally, we would also call the public `delay()` function for the delay.
But the `delay()` function is in `ProtocolContext`, and
`InstrumentContext` doesn't have access to that. We only have access to
the `ProtocolCore`, so we have to publish messages to the simulator
manually.

I ended up refactoring the code of `mix()` a bit because it was going to
get too repetitive and nested with the delays and `publish_context()`
messages added.

## Risk assessment

Should be low. The new parameters are version-gated. The main risk is
that we release this, and then decide that we don't want to change the
public API this way.

(cherry picked from commit 5012148)
ddcc4 added a commit that referenced this pull request May 24, 2025
…delay` (#18000)

# Overview

In PD, you can specify a delay after each aspirate and dispense in a Mix
step. There is no way to specify a delay in the PAPI `mix()` call, which
means that we can't translate a PD Mix step into a PAPI `mix()` call.

This PR introduces the parameters `aspirate_delay` and `dispense_delay`
to the `InstrumentContext.mix()` function. The new parameters are gated
to API version 2.24 and above. AUTH-1366

## Test Plan and Hands on Testing

I added tests to demonstrate that this implementation emits the correct
calls to `delay()` when the caller requests a delay in the `mix()`.

This is what the output looks like in `simulate`:
```
Mixing 2 times with a volume of 20.0 ul
	Aspirating 20.0 uL from C2 of (Retired) Armadillo 96 Well Plate 200 µL PCR Full Skirt on slot A2 at 716.0 uL/sec
	Delaying for 0 minutes and 2.5 seconds
	Dispensing 20.0 uL into C2 of (Retired) Armadillo 96 Well Plate 200 µL PCR Full Skirt on slot A2 at 716.0 uL/sec
	...
```

## Review requests

`InstrumentContext.mix()` calls `InstrumentContext.aspirate()` and
`InstrumentContext.dispense()` to implement the mix, which is nice
because the public `aspirate()` and `dispense()` functions handle things
like publishing messages for the simulator.

Ideally, we would also call the public `delay()` function for the delay.
But the `delay()` function is in `ProtocolContext`, and
`InstrumentContext` doesn't have access to that. We only have access to
the `ProtocolCore`, so we have to publish messages to the simulator
manually.

I ended up refactoring the code of `mix()` a bit because it was going to
get too repetitive and nested with the delays and `publish_context()`
messages added.

## Risk assessment

Should be low. The new parameters are version-gated. The main risk is
that we release this, and then decide that we don't want to change the
public API this way.

(cherry picked from commit 5012148)
ddcc4 added a commit that referenced this pull request May 29, 2025
…delay` (#18000)

# Overview

In PD, you can specify a delay after each aspirate and dispense in a Mix
step. There is no way to specify a delay in the PAPI `mix()` call, which
means that we can't translate a PD Mix step into a PAPI `mix()` call.

This PR introduces the parameters `aspirate_delay` and `dispense_delay`
to the `InstrumentContext.mix()` function. The new parameters are gated
to API version 2.24 and above. AUTH-1366

## Test Plan and Hands on Testing

I added tests to demonstrate that this implementation emits the correct
calls to `delay()` when the caller requests a delay in the `mix()`.

This is what the output looks like in `simulate`:
```
Mixing 2 times with a volume of 20.0 ul
	Aspirating 20.0 uL from C2 of (Retired) Armadillo 96 Well Plate 200 µL PCR Full Skirt on slot A2 at 716.0 uL/sec
	Delaying for 0 minutes and 2.5 seconds
	Dispensing 20.0 uL into C2 of (Retired) Armadillo 96 Well Plate 200 µL PCR Full Skirt on slot A2 at 716.0 uL/sec
	...
```

## Review requests

`InstrumentContext.mix()` calls `InstrumentContext.aspirate()` and
`InstrumentContext.dispense()` to implement the mix, which is nice
because the public `aspirate()` and `dispense()` functions handle things
like publishing messages for the simulator.

Ideally, we would also call the public `delay()` function for the delay.
But the `delay()` function is in `ProtocolContext`, and
`InstrumentContext` doesn't have access to that. We only have access to
the `ProtocolCore`, so we have to publish messages to the simulator
manually.

I ended up refactoring the code of `mix()` a bit because it was going to
get too repetitive and nested with the delays and `publish_context()`
messages added.

## Risk assessment

Should be low. The new parameters are version-gated. The main risk is
that we release this, and then decide that we don't want to change the
public API this way.

(cherry picked from commit 5012148)
ddcc4 added a commit that referenced this pull request May 29, 2025
…delay` (#18000)

# Overview

In PD, you can specify a delay after each aspirate and dispense in a Mix
step. There is no way to specify a delay in the PAPI `mix()` call, which
means that we can't translate a PD Mix step into a PAPI `mix()` call.

This PR introduces the parameters `aspirate_delay` and `dispense_delay`
to the `InstrumentContext.mix()` function. The new parameters are gated
to API version 2.24 and above. AUTH-1366

## Test Plan and Hands on Testing

I added tests to demonstrate that this implementation emits the correct
calls to `delay()` when the caller requests a delay in the `mix()`.

This is what the output looks like in `simulate`:
```
Mixing 2 times with a volume of 20.0 ul
	Aspirating 20.0 uL from C2 of (Retired) Armadillo 96 Well Plate 200 µL PCR Full Skirt on slot A2 at 716.0 uL/sec
	Delaying for 0 minutes and 2.5 seconds
	Dispensing 20.0 uL into C2 of (Retired) Armadillo 96 Well Plate 200 µL PCR Full Skirt on slot A2 at 716.0 uL/sec
	...
```

## Review requests

`InstrumentContext.mix()` calls `InstrumentContext.aspirate()` and
`InstrumentContext.dispense()` to implement the mix, which is nice
because the public `aspirate()` and `dispense()` functions handle things
like publishing messages for the simulator.

Ideally, we would also call the public `delay()` function for the delay.
But the `delay()` function is in `ProtocolContext`, and
`InstrumentContext` doesn't have access to that. We only have access to
the `ProtocolCore`, so we have to publish messages to the simulator
manually.

I ended up refactoring the code of `mix()` a bit because it was going to
get too repetitive and nested with the delays and `publish_context()`
messages added.

## Risk assessment

Should be low. The new parameters are version-gated. The main risk is
that we release this, and then decide that we don't want to change the
public API this way.

(cherry picked from commit 5012148)
ddcc4 added a commit that referenced this pull request May 29, 2025
…delay` (#18000)

# Overview

In PD, you can specify a delay after each aspirate and dispense in a Mix
step. There is no way to specify a delay in the PAPI `mix()` call, which
means that we can't translate a PD Mix step into a PAPI `mix()` call.

This PR introduces the parameters `aspirate_delay` and `dispense_delay`
to the `InstrumentContext.mix()` function. The new parameters are gated
to API version 2.24 and above. AUTH-1366

## Test Plan and Hands on Testing

I added tests to demonstrate that this implementation emits the correct
calls to `delay()` when the caller requests a delay in the `mix()`.

This is what the output looks like in `simulate`:
```
Mixing 2 times with a volume of 20.0 ul
	Aspirating 20.0 uL from C2 of (Retired) Armadillo 96 Well Plate 200 µL PCR Full Skirt on slot A2 at 716.0 uL/sec
	Delaying for 0 minutes and 2.5 seconds
	Dispensing 20.0 uL into C2 of (Retired) Armadillo 96 Well Plate 200 µL PCR Full Skirt on slot A2 at 716.0 uL/sec
	...
```

## Review requests

`InstrumentContext.mix()` calls `InstrumentContext.aspirate()` and
`InstrumentContext.dispense()` to implement the mix, which is nice
because the public `aspirate()` and `dispense()` functions handle things
like publishing messages for the simulator.

Ideally, we would also call the public `delay()` function for the delay.
But the `delay()` function is in `ProtocolContext`, and
`InstrumentContext` doesn't have access to that. We only have access to
the `ProtocolCore`, so we have to publish messages to the simulator
manually.

I ended up refactoring the code of `mix()` a bit because it was going to
get too repetitive and nested with the delays and `publish_context()`
messages added.

## Risk assessment

Should be low. The new parameters are version-gated. The main risk is
that we release this, and then decide that we don't want to change the
public API this way.

(cherry picked from commit 5012148)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants