Skip to content

Commit 7ed8d0c

Browse files
authored
fix(robot-server): Ensure camera device existence is validate for all endpoints (#20100)
Covers RQA-4839 Ensures that the camera device is always validated to exist first before any action is taken regarding any camera behavior anywhere.
1 parent 9f42aba commit 7ed8d0c

File tree

3 files changed

+18
-2
lines changed

3 files changed

+18
-2
lines changed

api/src/opentrons/system/camera.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -363,3 +363,9 @@ def get_boot_id() -> str:
363363
return Path("/proc/sys/kernel/random/boot_id").read_text().strip()
364364
else:
365365
return "SIMULATED_BOOT_ID"
366+
367+
368+
def camera_exists() -> bool:
369+
"""Validate whether or not the camera device exists."""
370+
return os.path.exists(DEFAULT_SYSTEM_CAMERA)
371+
# todo(chb, 2025-11-10): Eventually when we support multiple cameras this should accept a camera parameter to check for

robot-server/robot_server/runs/router/camera_router.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@
99
from opentrons.protocol_engine.resources.camera_provider import CameraSettings
1010
from opentrons.system import camera
1111

12-
from robot_server.errors.error_responses import ErrorBody
12+
from opentrons_shared_data.errors import ErrorCodes
13+
from robot_server.errors.error_responses import ErrorBody, LegacyErrorResponse
1314
from robot_server.service.json_api import (
1415
RequestModel,
1516
SimpleBody,
@@ -47,6 +48,7 @@
4748
status.HTTP_201_CREATED: {"model": SimpleBody[CameraSettings]},
4849
status.HTTP_404_NOT_FOUND: {"model": ErrorBody[RunNotFound]},
4950
status.HTTP_409_CONFLICT: {"model": ErrorBody[Union[RunStopped, RunNotIdle]]},
51+
status.HTTP_503_SERVICE_UNAVAILABLE: {},
5052
},
5153
)
5254
async def add_camera_settings(
@@ -67,6 +69,11 @@ async def add_camera_settings(
6769
robot_type: Used to validate robot type for live stream service.
6870
camera_provider: Access to the camera settings and related services.
6971
"""
72+
if not camera.camera_exists():
73+
raise LegacyErrorResponse(
74+
message="Video device is unavailable.",
75+
errorCode=ErrorCodes.GENERAL_ERROR.value.code,
76+
).as_error(status.HTTP_503_SERVICE_UNAVAILABLE)
7077
if run.current is False:
7178
raise RunStopped(detail=f"Run {run.id} is not the current run").as_error(
7279
status.HTTP_409_CONFLICT

robot-server/robot_server/service/legacy/routers/camera.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,7 @@ async def get_live_stream(
221221
RTMP:
222222
The full RTMP stream URL is formatted as: rtmp://{ROBOT_IP}/live/stream
223223
"""
224+
_validate_camera_present()
224225
enable_status = camera_settings_store.get_live_stream_enabled()
225226
return LiveStreamData(
226227
enabled=enable_status,
@@ -252,6 +253,7 @@ async def post_live_stream_settings(
252253
Arguments:
253254
request_body: Input payload from the request body.
254255
"""
256+
_validate_camera_present()
255257
if camera.robot_supports_livestream(robot_type) is False:
256258
raise LegacyErrorResponse(
257259
message="Opentrons Live Stream service is not available on OT-2.",
@@ -347,6 +349,7 @@ async def get_live_stream_settings(
347349

348350

349351
def _get_stream_settings() -> LiveStreamSettings:
352+
_validate_camera_present()
350353
contents = camera.load_stream_configuration_file_data()
351354
if contents is None:
352355
raise LegacyErrorResponse(
@@ -411,7 +414,7 @@ def _live_stream_settings_to_configuration_file(
411414

412415

413416
def _validate_camera_present() -> None:
414-
if IS_ROBOT and not os.path.exists(DEFAULT_CAMERA_PATH):
417+
if IS_ROBOT and not camera.camera_exists():
415418
# todo(chb, 2025-09-19): for the time being we will just be checking that the embedded flex camera exists to satisfy requirements
416419
# incase the camera isn't present, however eventually we can change this to support dynamically set third party cameras
417420
raise LegacyErrorResponse(

0 commit comments

Comments
 (0)