Skip to content

Commit d6d4b79

Browse files
authored
refactor(mono, robot-server, app): Add notification support for /camera (#20105)
1 parent 6b392d4 commit d6d4b79

File tree

8 files changed

+64
-9
lines changed

8 files changed

+64
-9
lines changed

.eslintrc.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ module.exports = {
7272
'useAllCommandsAsPreSerializedList',
7373
'useSearchLabwareOffsets',
7474
'useImageFileQuery',
75+
'useCamera',
7576
],
7677
message:
7778
'HTTP hook deprecated. Use the equivalent notification wrapper (useNotifyXYZ).',

app/src/local-resources/images/hooks/useCameraUsageSettings.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import { useEffect, useState } from 'react'
22

3-
import { useCamera, useUpdateCamera } from '@opentrons/react-api-client'
3+
import { useUpdateCamera } from '@opentrons/react-api-client'
4+
5+
import { useNotifyCamera } from '/app/resources/camera/useNotifyCamera'
46

57
const CAMERA_POLLING_INTERVAL_MS = 5000
68

@@ -17,7 +19,7 @@ export interface UseCameraUsageSettingsResult {
1719

1820
// general camera usage settings. inteded for out of run setup use only.
1921
export function useCameraUsageSettings(): UseCameraUsageSettingsResult {
20-
const { data: cameraData } = useCamera({
22+
const { data: cameraData } = useNotifyCamera({
2123
refetchInterval: CAMERA_POLLING_INTERVAL_MS,
2224
})
2325
const { mutateAsync: updateCamera } = useUpdateCamera()

app/src/local-resources/images/hooks/useInitializeCameraState.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,19 @@
11
import { useEffect } from 'react'
22
import { useDispatch } from 'react-redux'
33

4-
import { useCamera } from '@opentrons/react-api-client'
5-
64
import {
75
updateCameraEnablement,
86
updateCameraRecoveryEnablement,
97
updateCameraStreamEnablement,
108
} from '/app/redux/protocol-runs'
9+
import { useNotifyCamera } from '/app/resources/camera/useNotifyCamera'
1110
import { useNotifyRunQuery } from '/app/resources/runs'
1211

1312
// Populate the toggles with the run settings if they have been set,
1413
// otherwise, populate the toggles with the camera settings once the network
1514
// request completes.
1615
export function useInitializeCameraState(runId: string): void {
17-
const { data: cameraSettings } = useCamera()
16+
const { data: cameraSettings } = useNotifyCamera({ staleTime: Infinity })
1817
const { data } = useNotifyRunQuery(runId)
1918
const dispatch = useDispatch()
2019
const runCameraSettings = data?.data.cameraSettings

app/src/organisms/Desktop/Devices/RobotCard.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ import {
2020
WRAP,
2121
} from '@opentrons/components'
2222
import {
23-
useCamera,
2423
useInstrumentsQuery,
2524
useModulesQuery,
2625
usePipettesQuery,
@@ -37,6 +36,7 @@ import { InstrumentContainer } from '/app/atoms/InstrumentContainer'
3736
import { ModuleIcon } from '/app/molecules/ModuleIcon'
3837
import { useIsFlex } from '/app/redux-resources/robots'
3938
import { CONNECTABLE, getRobotModelByName } from '/app/redux/discovery'
39+
import { useNotifyCamera } from '/app/resources/camera/useNotifyCamera'
4040

4141
import { UpdateRobotBanner } from '../UpdateRobotBanner'
4242
import {
@@ -52,6 +52,8 @@ import type { GripperModel } from '@opentrons/shared-data'
5252
import type { DiscoveredRobot } from '/app/redux/discovery/types'
5353
import type { State } from '/app/redux/types'
5454

55+
const CAMERA_REFETCH_MS = 5000
56+
5557
interface RobotCardProps {
5658
robot: DiscoveredRobot
5759
}
@@ -173,7 +175,7 @@ function AttachedModules(props: { robotName: string }): JSX.Element | null {
173175
function AttachedDevices(props: { robotName: string }): JSX.Element | null {
174176
const { robotName } = props
175177
const { t } = useTranslation('devices_landing')
176-
const { data } = useCamera()
178+
const { data } = useNotifyCamera({ refetchInterval: CAMERA_REFETCH_MS })
177179

178180
return data?.cameraEnabled ? (
179181
<Flex

app/src/pages/ODD/ProtocolSetup/index.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@ import {
2424
} from '@opentrons/components'
2525
import {
2626
useAddCameraSettingsToRunMutation,
27-
useCamera,
2827
useInstrumentsQuery,
2928
useProtocolAnalysisAsDocumentQuery,
3029
useProtocolQuery,
@@ -92,6 +91,7 @@ import {
9291
updateCameraEnablement,
9392
} from '/app/redux/protocol-runs'
9493
import { useStoredProtocolAnalysis } from '/app/resources/analysis'
94+
import { useNotifyCamera } from '/app/resources/camera/useNotifyCamera'
9595
import { useDeckConfigurationCompatibility } from '/app/resources/deck_configuration/hooks'
9696
import { getRequiredDeckConfig } from '/app/resources/deck_configuration/utils'
9797
import { useRobotStorageInfo } from '/app/resources/health/useIsImageStorageLow'
@@ -847,7 +847,9 @@ export function ProtocolSetup(): JSX.Element {
847847
const { applyOffsets, isApplyingOffsets } = useApplyOffsets(runId)
848848

849849
const [cameraSettingsConfirmed, setCameraSettingsConfirmed] = useState(false)
850-
const { data: initialRobotCameraSettings } = useCamera()
850+
const { data: initialRobotCameraSettings } = useNotifyCamera({
851+
staleTime: Infinity,
852+
})
851853

852854
// The initial app-internal camera state should match the server state.
853855
useEffect(() => {

app/src/redux/shell/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,7 @@ export type NotifyTopic =
161161
| `robot-server/runs/${string}`
162162
| `robot-server/runs/pre_serialized_commands/${string}`
163163
| `robot-server/dataFiles/${string}/images`
164+
| 'robot-server/camera'
164165

165166
export interface NotifySubscribeAction {
166167
type: 'shell:NOTIFY_SUBSCRIBE'
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import { useCamera } from '@opentrons/react-api-client'
2+
3+
import { useNotifyDataReady } from '../useNotifyDataReady'
4+
5+
import type { UseQueryResult } from 'react-query'
6+
import type { CameraResponse } from '@opentrons/api-client'
7+
import type { QueryOptionsWithPolling } from '../useNotifyDataReady'
8+
9+
export function useNotifyCamera(
10+
options: QueryOptionsWithPolling<CameraResponse, unknown> = {}
11+
): UseQueryResult<CameraResponse> {
12+
const { shouldRefetch, queryOptionsNotify } = useNotifyDataReady({
13+
topic: `robot-server/camera`,
14+
options,
15+
})
16+
17+
const httpQueryResult = useCamera(queryOptionsNotify)
18+
19+
if (shouldRefetch) {
20+
void httpQueryResult.refetch()
21+
}
22+
23+
return httpQueryResult
24+
}

robot-server/tests/conftest.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
helpers,
2525
save_robot_deck_attitude,
2626
)
27+
from server_utils.fastapi_utils.app_state import AppState, get_app_state
2728

2829
# NOTE(FS 10-24-2023), the fixtures using these functions currently ONLY
2930
# get pulled in by OT-2 server tests. If this ever changes, we need to
@@ -47,6 +48,10 @@
4748
from robot_server.health.router import ComponentVersions, get_versions
4849
from robot_server.runs.run_data_manager import RunDataManager
4950
from robot_server.runs.dependencies import get_run_data_manager
51+
from robot_server.service.notifications.notification_client import (
52+
NotificationClient,
53+
_notification_client_accessor,
54+
)
5055

5156
test_router = routing.APIRouter()
5257

@@ -178,12 +183,30 @@ async def get_run_data_manager_override() -> RunDataManager:
178183
del app.dependency_overrides[get_run_data_manager]
179184

180185

186+
@pytest.fixture
187+
def _override_app_state_with_notification_client(decoy: Decoy) -> Iterator[None]:
188+
"""Override app_state to include a mocked notification client."""
189+
mock_app_state = AppState()
190+
mock_notification_client = decoy.mock(cls=NotificationClient)
191+
192+
_notification_client_accessor.set_on(mock_app_state, mock_notification_client)
193+
194+
async def get_app_state_override() -> AppState:
195+
"""Override for get_app_state."""
196+
return mock_app_state
197+
198+
app.dependency_overrides[get_app_state] = get_app_state_override
199+
yield
200+
del app.dependency_overrides[get_app_state]
201+
202+
181203
@pytest.fixture
182204
def api_client(
183205
_override_hardware_with_mock: None,
184206
_override_sql_engine_with_mock: None,
185207
_override_version_with_mock: None,
186208
_override_ot2_hardware_with_mock: None,
209+
_override_app_state_with_notification_client: None,
187210
) -> TestClient:
188211
client = TestClient(app)
189212
client.headers.update(
@@ -199,6 +222,7 @@ def api_client_camera_overrides(
199222
_override_version_with_mock: None,
200223
_override_ot2_hardware_with_mock: None,
201224
_override_run_data_manager_with_mock: None,
225+
_override_app_state_with_notification_client: None,
202226
) -> TestClient:
203227
client = TestClient(app)
204228
client.headers.update(

0 commit comments

Comments
 (0)