Skip to content

Commit

Permalink
feat(api): add getter and setter for instrument lld setting (#15537)
Browse files Browse the repository at this point in the history
<!--
Thanks for taking the time to open a pull request! Please make sure
you've read the "Opening Pull Requests" section of our Contributing
Guide:


https://github.com/Opentrons/opentrons/blob/edge/CONTRIBUTING.md#opening-pull-requests

To ensure your code is reviewed quickly and thoroughly, please fill out
the sections below to the best of your ability!
-->

# Overview

<!--
Use this section to describe your pull-request at a high level. If the
PR addresses any open issues, please tag the issues here.
-->

fix #[EXEC-542](https://opentrons.atlassian.net/browse/EXEC-542) and fix
#[EXEC-543](https://opentrons.atlassian.net/browse/EXEC-543)

These change implement a getter and setter for a pipette's lld setting.
Since they do not have to be called at the time you load the instrument,
they allow for finer control of when LLD is active.
# Test Plan

<!--
Use this section to describe the steps that you took to test your Pull
Request.
If you did not perform any testing provide justification why.

OT-3 Developers: You should default to testing on actual physical
hardware.
Once again, if you did not perform testing against hardware, justify
why.

Note: It can be helpful to write a test plan before doing development

Example Test Plan (HTTP API Change)

- Verified that new optional argument `dance-party` causes the robot to
flash its lights, move the pipettes,
then home.
- Verified that when you omit the `dance-party` option the robot homes
normally
- Added protocol that uses `dance-party` argument to G-Code Testing
Suite
- Ran protocol that did not use `dance-party` argument and everything
was successful
- Added unit tests to validate that changes to pydantic model are
correct

-->

Added Unit Tests to test_instrument_context.py to ensure that the
functions properly interacted with the underlying InstrumentCore.

# Changelog

<!--
List out the changes to the code in this PR. Please try your best to
categorize your changes and describe what has changed and why.

Example changelog:
- Fixed app crash when trying to calibrate an illegal pipette
- Added state to API to track pipette usage
- Updated API docs to mention only two pipettes are supported

IMPORTANT: MAKE SURE ANY BREAKING CHANGES ARE PROPERLY COMMUNICATED
-->

# Review requests

<!--
Describe any requests for your reviewers here.
-->

# Risk assessment

<!--
Carefully go over your pull request and look at the other parts of the
codebase it may affect. Look for the possibility, even if you think it's
small, that your change may affect some other part of the system - for
instance, changing return tip behavior in protocol may also change the
behavior of labware calibration.

Identify the other parts of the system your codebase may affect, so that
in addition to your own review and testing, other people who may not
have the system internalized as much as you can focus their attention
and testing there.
-->

[EXEC-542]:
https://opentrons.atlassian.net/browse/EXEC-542?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ
[EXEC-543]:
https://opentrons.atlassian.net/browse/EXEC-543?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ
  • Loading branch information
aaron-kulkarni authored Jun 28, 2024
1 parent c5d543c commit 033d780
Show file tree
Hide file tree
Showing 8 changed files with 74 additions and 0 deletions.
9 changes: 9 additions & 0 deletions api/src/opentrons/protocol_api/core/engine/instrument.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,9 @@ def __init__(
self._flow_rates = FlowRates(self)

self.set_default_speed(speed=default_movement_speed)
self._liquid_presence_detection = bool(
self._engine_client.state.pipettes.get_liquid_presence_detection(pipette_id)
)

@property
def pipette_id(self) -> str:
Expand Down Expand Up @@ -747,6 +750,9 @@ def get_nozzle_configuration(self) -> NozzleConfigurationType:
self._pipette_id
)

def get_liquid_presence_detection(self) -> bool:
return self._liquid_presence_detection

def is_tip_tracking_available(self) -> bool:
primary_nozzle = self._engine_client.state.pipettes.get_primary_nozzle(
self._pipette_id
Expand Down Expand Up @@ -780,6 +786,9 @@ def set_flow_rate(
assert blow_out > 0
self._blow_out_flow_rate = blow_out

def set_liquid_presence_detection(self, enable: bool) -> None:
self._liquid_presence_detection = enable

def configure_for_volume(self, volume: float) -> None:
self._engine_client.execute_command(
cmd.ConfigureForVolumeParams(
Expand Down
8 changes: 8 additions & 0 deletions api/src/opentrons/protocol_api/core/instrument.py
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,14 @@ def get_dispense_flow_rate(self, rate: float = 1.0) -> float:
def get_blow_out_flow_rate(self, rate: float = 1.0) -> float:
...

@abstractmethod
def get_liquid_presence_detection(self) -> bool:
...

@abstractmethod
def set_liquid_presence_detection(self, enable: bool) -> None:
...

@abstractmethod
def set_flow_rate(
self,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ def __init__(
blow_out_defaults=pipette_state["default_blow_out_flow_rates"],
api_level=self._api_version,
)
self._liquid_presence_detection = False

def get_default_speed(self) -> float:
"""Gets the speed at which the robot's gantry moves."""
Expand Down Expand Up @@ -471,6 +472,9 @@ def get_return_height(self) -> float:
def get_flow_rate(self) -> FlowRates:
return self._flow_rates

def get_liquid_presence_detection(self) -> bool:
return self._liquid_presence_detection

def get_aspirate_flow_rate(self, rate: float = 1.0) -> float:
return self.get_hardware_state()["aspirate_flow_rate"] * rate

Expand All @@ -497,6 +501,9 @@ def set_flow_rate(
blow_out=blow_out,
)

def set_liquid_presence_detection(self, enable: bool) -> None:
self._protocol_interface.get_hardware().set_liquid_presence_detection(enable)

def set_pipette_speed(
self,
aspirate: Optional[float] = None,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ def __init__(
self._module_cores: List[legacy_module_core.LegacyModuleCore] = []
self._labware_cores: List[LegacyLabwareCore] = [self.fixed_trash]
self._disposal_locations: List[Union[Labware, TrashBin, WasteChute]] = []
self._liquid_presence_detection = False

@property
def api_version(self) -> APIVersion:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ def __init__(
self._instrument_max_height = (
protocol_interface.get_hardware().get_instrument_max_height(self._mount)
)
self._liquid_presence_detection = False

def get_default_speed(self) -> float:
return self._default_speed
Expand Down Expand Up @@ -363,6 +364,12 @@ def get_return_height(self) -> float:
def get_speed(self) -> PlungerSpeeds:
return self._plunger_speeds

def get_liquid_presence_detection(self) -> bool:
return self._liquid_presence_detection

def set_liquid_presence_detection(self, enable: bool) -> None:
self._liquid_presence_detection = enable

def get_flow_rate(self) -> FlowRates:
return self._flow_rate

Expand Down
18 changes: 18 additions & 0 deletions api/src/opentrons/protocol_api/instrument_context.py
Original file line number Diff line number Diff line change
Expand Up @@ -1670,6 +1670,24 @@ def tip_racks(self) -> List[labware.Labware]:
def tip_racks(self, racks: List[labware.Labware]) -> None:
self._tip_racks = racks

@property
@requires_version(2, 20)
def liquid_detection(self) -> bool:
"""
Gets the global setting for liquid level detection.
When True, `liquid_probe` will be called before
aspirates and dispenses to bring the tip to the liquid level.
The default value is False.
"""
return self._core.get_liquid_presence_detection()

@liquid_detection.setter
@requires_version(2, 20)
def liquid_detection(self, enable: bool) -> None:
self._core.set_liquid_presence_detection(enable)

@property
@requires_version(2, 0)
def trash_container(self) -> Union[labware.Labware, TrashBin, WasteChute]:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1149,6 +1149,20 @@ def test_has_tip(
assert subject.has_tip() is True


def test_liquid_presence_detection(
decoy: Decoy,
subject: InstrumentCore,
mock_engine_client: EngineClient,
) -> None:
"""It should have a default liquid presence detection boolean set to False."""
decoy.when(
mock_engine_client.state.pipettes.get_liquid_presence_detection(
subject.pipette_id
)
).then_return(False)
assert subject.get_liquid_presence_detection() is False


@pytest.mark.parametrize(
argnames=["style", "primary_nozzle", "front_right_nozzle", "expected_model"],
argvalues=[
Expand Down
10 changes: 10 additions & 0 deletions api/tests/opentrons/protocol_api/test_instrument_context.py
Original file line number Diff line number Diff line change
Expand Up @@ -1059,6 +1059,16 @@ def test_flow_rate(
assert result == flow_rates


def test_liquid_presence_detection(
decoy: Decoy, mock_instrument_core: InstrumentCore, subject: InstrumentContext
) -> None:
"""It should have a default liquid presence detection boolean set to False."""
decoy.when(mock_instrument_core.get_liquid_presence_detection()).then_return(False)
assert subject.liquid_detection is False
subject.liquid_detection = True
decoy.verify(mock_instrument_core.set_liquid_presence_detection(True), times=1)


@pytest.mark.parametrize("api_version", [APIVersion(2, 13)])
@pytest.mark.parametrize(
"mock_instrument_core",
Expand Down

0 comments on commit 033d780

Please sign in to comment.