Skip to content

Commit

Permalink
feat(robot-server): add e-stop state query & acknowledge-disengage en…
Browse files Browse the repository at this point in the history
…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
fsinapi authored Jul 12, 2023
1 parent 0f1e0bb commit 869b992
Show file tree
Hide file tree
Showing 6 changed files with 184 additions and 0 deletions.
Empty file.
37 changes: 37 additions & 0 deletions robot-server/robot_server/robot/control/models.py
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."
)
74 changes: 74 additions & 0 deletions robot-server/robot_server/robot/control/router.py
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)
8 changes: 8 additions & 0 deletions robot-server/robot_server/robot/router.py
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)
5 changes: 5 additions & 0 deletions robot-server/robot_server/router.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
from .service.tip_length.router import router as tl_router
from .service.notifications.router import router as notifications_router
from .subsystems.router import subsystems_router
from .robot.router import robot_router

router = APIRouter()

Expand Down Expand Up @@ -121,3 +122,7 @@
tags=["Subsystem Management"],
dependencies=[Depends(check_version_header)],
)

router.include_router(
router=robot_router, tags=["Robot"], dependencies=[Depends(check_version_header)]
)
60 changes: 60 additions & 0 deletions robot-server/tests/integration/test_estop_status.tavern.yaml
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

0 comments on commit 869b992

Please sign in to comment.