-
Notifications
You must be signed in to change notification settings - Fork 179
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(robot-server): add e-stop state query & acknowledge-disengage en…
…dpoints (#13067) * Added stubbed-out endpoints to query estop status and reset it * Added a simple integration test for the new endpoints
- Loading branch information
Showing
6 changed files
with
184 additions
and
0 deletions.
There are no files selected for viewing
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
"""Request and response models for /robot/control endpoints.""" | ||
|
||
import enum | ||
from pydantic import BaseModel, Field | ||
|
||
|
||
class EstopState(enum.Enum): | ||
"""Current status of the estop on this robot.""" | ||
|
||
NOT_PRESENT = "notPresent" | ||
PHYSICALLY_ENGAGED = "physicallyEngaged" | ||
LOGICALLY_ENGAGED = "logicallyEngaged" | ||
DISENGAGED = "disengaged" | ||
|
||
|
||
class EstopPhysicalStatus(enum.Enum): | ||
"""Physical status of a specific estop.""" | ||
|
||
ENGAGED = "engaged" | ||
DISENGAGED = "disengaged" | ||
NOT_PRESENT = "notPresent" | ||
|
||
|
||
class EstopStatusModel(BaseModel): | ||
"""Model for the current estop status.""" | ||
|
||
status: EstopState = Field( | ||
..., description="The current status of the estop on this robot." | ||
) | ||
|
||
leftEstopPhysicalStatus: EstopPhysicalStatus = Field( | ||
..., description="Physical status of the left estop mount." | ||
) | ||
|
||
rightEstopPhysicalStatus: EstopPhysicalStatus = Field( | ||
..., description="Physical status of the right estop mount." | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
"""Router for /robot/control endpoints.""" | ||
from fastapi import APIRouter, status, Depends | ||
from typing import TYPE_CHECKING | ||
|
||
from robot_server.errors import ErrorBody | ||
from robot_server.errors.robot_errors import NotSupportedOnOT2 | ||
from robot_server.service.json_api import ( | ||
PydanticResponse, | ||
SimpleBody, | ||
) | ||
from robot_server.hardware import ( | ||
get_ot3_hardware, | ||
get_thread_manager, | ||
) | ||
from opentrons.hardware_control import ThreadManagedHardware | ||
|
||
from .models import ( | ||
EstopState, | ||
EstopStatusModel, | ||
EstopPhysicalStatus, | ||
) | ||
|
||
if TYPE_CHECKING: | ||
from opentrons.hardware_control.ot3api import OT3API # noqa: F401 | ||
|
||
control_router = APIRouter() | ||
|
||
|
||
async def _get_estop_status( | ||
thread_manager: ThreadManagedHardware, | ||
) -> PydanticResponse[SimpleBody[EstopStatusModel]]: | ||
"""Helper to generate the current Estop Status as a response model.""" | ||
get_ot3_hardware(thread_manager) | ||
|
||
# TODO - unstub the response here | ||
data = EstopStatusModel.construct( | ||
status=EstopState.DISENGAGED, | ||
leftEstopPhysicalStatus=EstopPhysicalStatus.DISENGAGED, | ||
rightEstopPhysicalStatus=EstopPhysicalStatus.DISENGAGED, | ||
) | ||
return await PydanticResponse.create(content=SimpleBody.construct(data=data)) | ||
|
||
|
||
@control_router.get( | ||
"/robot/control/estopStatus", | ||
summary="Get connected estop status.", | ||
description="Get the current estop status of the robot, as well as a list of connected estops.", | ||
responses={ | ||
status.HTTP_200_OK: {"model": SimpleBody[EstopStatusModel]}, | ||
status.HTTP_403_FORBIDDEN: {"model": ErrorBody[NotSupportedOnOT2]}, | ||
}, | ||
) | ||
async def get_estop_status( | ||
thread_manager: ThreadManagedHardware = Depends(get_thread_manager), | ||
) -> PydanticResponse[SimpleBody[EstopStatusModel]]: | ||
"""Return the current status of the estop.""" | ||
return await _get_estop_status(thread_manager) | ||
|
||
|
||
@control_router.put( | ||
"/robot/control/acknowledgeEstopDisengage", | ||
summary="Acknowledge and clear an Estop event.", | ||
description="If the estop is currently logically engaged (the estop was previously pressed but is " | ||
+ "now released), this endpoint will reset the state to reflect the current physical status.", | ||
responses={ | ||
status.HTTP_200_OK: {"model": SimpleBody[EstopStatusModel]}, | ||
status.HTTP_403_FORBIDDEN: {"model": ErrorBody[NotSupportedOnOT2]}, | ||
}, | ||
) | ||
async def put_acknowledge_estop_disengage( | ||
thread_manager: ThreadManagedHardware = Depends(get_thread_manager), | ||
) -> PydanticResponse[SimpleBody[EstopStatusModel]]: | ||
"""Transition from the `logically_engaged` status if applicable.""" | ||
return await _get_estop_status(thread_manager) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
"""Router for /robot endpoints.""" | ||
from fastapi import APIRouter | ||
|
||
from .control.router import control_router | ||
|
||
robot_router = APIRouter() | ||
|
||
robot_router.include_router(router=control_router) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
60 changes: 60 additions & 0 deletions
60
robot-server/tests/integration/test_estop_status.tavern.yaml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
--- | ||
test_name: GET estop status on OT-3 | ||
marks: | ||
- ot3_only | ||
- usefixtures: | ||
- ot3_server_base_url | ||
stages: | ||
- name: Get estop status | ||
request: | ||
method: GET | ||
url: "{ot3_server_base_url}/robot/control/estopStatus" | ||
response: | ||
status_code: 200 | ||
json: | ||
data: | ||
status: disengaged | ||
leftEstopPhysicalStatus: disengaged | ||
rightEstopPhysicalStatus: disengaged | ||
--- | ||
test_name: GET estop status on OT-2 | ||
marks: | ||
- usefixtures: | ||
- ot2_server_base_url | ||
stages: | ||
- name: Get estop status from OT-2 | ||
request: | ||
method: GET | ||
url: "{ot2_server_base_url}/robot/control/estopStatus" | ||
response: | ||
status_code: 403 | ||
--- | ||
test_name: PUT estop acknowledge & disengage on OT-3 | ||
marks: | ||
- ot3_only | ||
- usefixtures: | ||
- ot3_server_base_url | ||
stages: | ||
- name: PUT acknowledgeEstopDisengage | ||
request: | ||
method: PUT | ||
url: "{ot3_server_base_url}/robot/control/acknowledgeEstopDisengage" | ||
response: | ||
status_code: 200 | ||
json: | ||
data: | ||
status: disengaged | ||
leftEstopPhysicalStatus: disengaged | ||
rightEstopPhysicalStatus: disengaged | ||
--- | ||
test_name: PUT estop acknowledge & disengage on OT-2 | ||
marks: | ||
- usefixtures: | ||
- ot2_server_base_url | ||
stages: | ||
- name: PUT acknowledgeEstopDisengage on ot-2 | ||
request: | ||
method: PUT | ||
url: "{ot2_server_base_url}/robot/control/acknowledgeEstopDisengage" | ||
response: | ||
status_code: 403 |