-
Notifications
You must be signed in to change notification settings - Fork 179
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
fix(engine): pause hardware API when engine is paused #10882
Changes from 3 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,40 +1,31 @@ | ||
"""Main ProtocolEngine factory.""" | ||
from opentrons.hardware_control import HardwareControlAPI | ||
from opentrons.hardware_control.types import DoorState | ||
from opentrons.config import feature_flags | ||
|
||
from .protocol_engine import ProtocolEngine | ||
from .resources import DeckDataProvider | ||
from .state import StateStore, EngineConfigs | ||
from .state import Config, StateStore | ||
|
||
|
||
async def create_protocol_engine( | ||
hardware_api: HardwareControlAPI, | ||
configs: EngineConfigs = EngineConfigs(), | ||
config: Config, | ||
) -> ProtocolEngine: | ||
"""Create a ProtocolEngine instance. | ||
|
||
Arguments: | ||
hardware_api: Hardware control API to pass down to dependencies. | ||
configs: Protocol Engine configurations. | ||
config: ProtocolEngine configuration. | ||
""" | ||
# TODO(mc, 2020-11-18): check short trash FF | ||
deck_data = DeckDataProvider() | ||
deck_definition = await deck_data.get_deck_definition() | ||
deck_fixed_labware = await deck_data.get_deck_fixed_labware(deck_definition) | ||
# TODO(mc, 2021-09-22): figure out a better way to load deck data that | ||
# can more consistently handle Python vs JSON vs legacy differences | ||
|
||
is_door_blocking = ( | ||
feature_flags.enable_door_safety_switch() | ||
and hardware_api.door_state is DoorState.OPEN | ||
) | ||
|
||
state_store = StateStore( | ||
config=config, | ||
deck_definition=deck_definition, | ||
deck_fixed_labware=deck_fixed_labware, | ||
configs=configs, | ||
is_door_blocking=is_door_blocking, | ||
is_door_open=hardware_api.door_state is DoorState.OPEN, | ||
) | ||
|
||
return ProtocolEngine(state_store=state_store, hardware_api=hardware_api) |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,6 +4,7 @@ | |
from opentrons.protocols.models import LabwareDefinition | ||
from opentrons.hardware_control import HardwareControlAPI | ||
from opentrons.hardware_control.modules import AbstractModule as HardwareModuleAPI | ||
from opentrons.hardware_control.types import PauseType as HardwarePauseType | ||
|
||
from .resources import ModelUtils, ModuleDataProvider | ||
from .commands import Command, CommandCreate | ||
|
@@ -59,6 +60,7 @@ def __init__( | |
This constructor does not inject provider implementations. | ||
Prefer the `create_protocol_engine()` factory function. | ||
""" | ||
self._hardware_api = hardware_api | ||
self._state_store = state_store | ||
self._model_utils = model_utils or ModelUtils() | ||
|
||
|
@@ -107,14 +109,19 @@ def play(self) -> None: | |
PlayAction(requested_at=requested_at) | ||
) | ||
self._action_dispatcher.dispatch(action) | ||
self._queue_worker.start() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this an intentional removal of There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @SyntaxColoring @mcous I saw it the tests that instead we are now calling hardware_api.resume(HardwarePauseType.PAUSE) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is intentional; |
||
|
||
if self._state_store.commands.get_is_door_blocking(): | ||
self._hardware_api.pause(HardwarePauseType.PAUSE) | ||
TamarZanzouri marked this conversation as resolved.
Show resolved
Hide resolved
|
||
else: | ||
self._hardware_api.resume(HardwarePauseType.PAUSE) | ||
|
||
def pause(self) -> None: | ||
"""Pause executing commands in the queue.""" | ||
action = self._state_store.commands.validate_action_allowed( | ||
PauseAction(source=PauseSource.CLIENT) | ||
) | ||
self._action_dispatcher.dispatch(action) | ||
self._hardware_api.pause(HardwarePauseType.PAUSE) | ||
|
||
def add_command(self, request: CommandCreate) -> Command: | ||
"""Add a command to the `ProtocolEngine`'s queue. | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
"""Top-level ProtocolEngine configuration options.""" | ||
from dataclasses import dataclass | ||
|
||
|
||
@dataclass(frozen=True) | ||
class Config: | ||
"""ProtocolEngine configuration options.""" | ||
|
||
ignore_pause: bool = False | ||
use_virtual_modules: bool = False | ||
mcous marked this conversation as resolved.
Show resolved
Hide resolved
|
||
block_on_door_open: bool = False |
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -291,7 +291,7 @@ class ModuleView(HasState[ModuleState]): | |
|
||
_state: ModuleState | ||
|
||
def __init__(self, state: ModuleState, virtualize_modules: bool) -> None: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Argument was completely unused |
||
def __init__(self, state: ModuleState) -> None: | ||
"""Initialize the view with its backing state value.""" | ||
self._state = state | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I checked in with @sfoster1 on this one: the HW API would rather simply report door open and close events. This lines up nicely with a desire on our end to stop deeply nesting access to the config singleton.
Given that this PR gives the
ProtocolEngine
enough information to reject an invalid resume while the door is open, I removed the unnecessary door logic fromPauseManager
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My opinion isn't a super informed one, but I'm a big fan of this. It seems way easier to reason about the HW API if we're always controlling it and it's never controlling itself independently.