diff --git a/web/src/api/__tests__/mqtt.test.jsx b/web/src/api/__tests__/mqtt.test.jsx index 6635f9d46..65964e6f8 100644 --- a/web/src/api/__tests__/mqtt.test.jsx +++ b/web/src/api/__tests__/mqtt.test.jsx @@ -105,7 +105,7 @@ describe('MqttProvider', () => { await screen.findByRole('button'); fireEvent.click(screen.getByRole('button')); await expect(wsClient.send).toHaveBeenCalledWith( - JSON.stringify({ topic: 'tacos', payload: JSON.stringify({ yes: true }) }) + JSON.stringify({ topic: 'tacos', payload: JSON.stringify({ yes: true }), retain: false }) ); }); @@ -124,22 +124,22 @@ describe('MqttProvider', () => { ); await screen.findByTestId('data'); expect(screen.getByTestId('front/detect/state')).toHaveTextContent( - '{"lastUpdate":123456,"payload":"ON","retain":true}' + '{"lastUpdate":123456,"payload":"ON","retain":false}' ); expect(screen.getByTestId('front/recordings/state')).toHaveTextContent( - '{"lastUpdate":123456,"payload":"OFF","retain":true}' + '{"lastUpdate":123456,"payload":"OFF","retain":false}' ); expect(screen.getByTestId('front/snapshots/state')).toHaveTextContent( - '{"lastUpdate":123456,"payload":"ON","retain":true}' + '{"lastUpdate":123456,"payload":"ON","retain":false}' ); expect(screen.getByTestId('side/detect/state')).toHaveTextContent( - '{"lastUpdate":123456,"payload":"OFF","retain":true}' + '{"lastUpdate":123456,"payload":"OFF","retain":false}' ); expect(screen.getByTestId('side/recordings/state')).toHaveTextContent( - '{"lastUpdate":123456,"payload":"OFF","retain":true}' + '{"lastUpdate":123456,"payload":"OFF","retain":false}' ); expect(screen.getByTestId('side/snapshots/state')).toHaveTextContent( - '{"lastUpdate":123456,"payload":"OFF","retain":true}' + '{"lastUpdate":123456,"payload":"OFF","retain":false}' ); }); }); diff --git a/web/src/api/mqtt.jsx b/web/src/api/mqtt.jsx index 7505702d6..0dcfa2939 100644 --- a/web/src/api/mqtt.jsx +++ b/web/src/api/mqtt.jsx @@ -42,9 +42,9 @@ export function MqttProvider({ useEffect(() => { Object.keys(config.cameras).forEach((camera) => { const { name, record, detect, snapshots } = config.cameras[camera]; - dispatch({ topic: `${name}/recordings/state`, payload: record.enabled ? 'ON' : 'OFF', retain: true }); - dispatch({ topic: `${name}/detect/state`, payload: detect.enabled ? 'ON' : 'OFF', retain: true }); - dispatch({ topic: `${name}/snapshots/state`, payload: snapshots.enabled ? 'ON' : 'OFF', retain: true }); + dispatch({ topic: `${name}/recordings/state`, payload: record.enabled ? 'ON' : 'OFF', retain: false }); + dispatch({ topic: `${name}/detect/state`, payload: detect.enabled ? 'ON' : 'OFF', retain: false }); + dispatch({ topic: `${name}/snapshots/state`, payload: snapshots.enabled ? 'ON' : 'OFF', retain: false }); }); }, [config]); @@ -78,11 +78,12 @@ export function useMqtt(watchTopic, publishTopic) { const value = state[watchTopic] || { payload: null }; const send = useCallback( - (payload) => { + (payload, retain = false) => { ws.send( JSON.stringify({ topic: publishTopic || watchTopic, payload: typeof payload !== 'string' ? JSON.stringify(payload) : payload, + retain, }) ); }, diff --git a/web/src/routes/Cameras.jsx b/web/src/routes/Cameras.jsx index a61aff91d..6628112b3 100644 --- a/web/src/routes/Cameras.jsx +++ b/web/src/routes/Cameras.jsx @@ -22,12 +22,13 @@ export default function Cameras() { } function SortedCameras({ unsortedCameras }) { - - const sortedCameras = useMemo(() => - Object.entries(unsortedCameras) - .filter(([_, conf]) => conf.ui.dashboard) - .sort(([_, aConf], [__, bConf]) => aConf.ui.order - bConf.ui.order), - [unsortedCameras]); + const sortedCameras = useMemo( + () => + Object.entries(unsortedCameras) + .filter(([_, conf]) => conf.ui.dashboard) + .sort(([_, aConf], [__, bConf]) => aConf.ui.order - bConf.ui.order), + [unsortedCameras] + ); return ( @@ -56,7 +57,7 @@ function Camera({ name }) { icon: MotionIcon, color: detectValue === 'ON' ? 'blue' : 'gray', onClick: () => { - sendDetect(detectValue === 'ON' ? 'OFF' : 'ON'); + sendDetect(detectValue === 'ON' ? 'OFF' : 'ON', true); }, }, { @@ -64,7 +65,7 @@ function Camera({ name }) { icon: ClipIcon, color: recordValue === 'ON' ? 'blue' : 'gray', onClick: () => { - sendRecordings(recordValue === 'ON' ? 'OFF' : 'ON'); + sendRecordings(recordValue === 'ON' ? 'OFF' : 'ON', true); }, }, { @@ -72,7 +73,7 @@ function Camera({ name }) { icon: SnapshotIcon, color: snapshotValue === 'ON' ? 'blue' : 'gray', onClick: () => { - sendSnapshots(snapshotValue === 'ON' ? 'OFF' : 'ON'); + sendSnapshots(snapshotValue === 'ON' ? 'OFF' : 'ON', true); }, }, ], diff --git a/web/src/routes/__tests__/Cameras.test.jsx b/web/src/routes/__tests__/Cameras.test.jsx index cbfe5a5f9..1f49f7343 100644 --- a/web/src/routes/__tests__/Cameras.test.jsx +++ b/web/src/routes/__tests__/Cameras.test.jsx @@ -54,14 +54,14 @@ describe('Cameras Route', () => { await waitForElementToBeRemoved(() => screen.queryByLabelText('Loading…')); fireEvent.click(screen.getAllByLabelText('Toggle detect off')[0]); - expect(sendDetect).toHaveBeenCalledWith('OFF'); + expect(sendDetect).toHaveBeenCalledWith('OFF', true); expect(sendDetect).toHaveBeenCalledTimes(1); fireEvent.click(screen.getAllByLabelText('Toggle snapshots off')[0]); - expect(sendSnapshots).toHaveBeenCalledWith('OFF'); + expect(sendSnapshots).toHaveBeenCalledWith('OFF', true); fireEvent.click(screen.getAllByLabelText('Toggle recordings on')[0]); - expect(sendRecordings).toHaveBeenCalledWith('ON'); + expect(sendRecordings).toHaveBeenCalledWith('ON', true); expect(sendDetect).toHaveBeenCalledTimes(1); expect(sendSnapshots).toHaveBeenCalledTimes(1);