mirror of
https://github.com/legop3/MultiRoombaRover.git
synced 2026-09-16 01:21:20 -04:00
IR controls
This commit is contained in:
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -78,7 +78,7 @@
|
|||||||
<script defer src="https://analytics.otter.land/script.js" data-website-id="82dd56a5-db44-4279-bd1e-a4d9fee39af7" data-domains="rover.otter.land"></script>
|
<script defer src="https://analytics.otter.land/script.js" data-website-id="82dd56a5-db44-4279-bd1e-a4d9fee39af7" data-domains="rover.otter.land"></script>
|
||||||
<script defer src="https://analytics.otter.land/recorder.js" data-website-id="82dd56a5-db44-4279-bd1e-a4d9fee39af7" data-domains="rover.otter.land" data-sample-rate="0.15" data-mask-level="moderate" data-max-duration="300000"></script>
|
<script defer src="https://analytics.otter.land/recorder.js" data-website-id="82dd56a5-db44-4279-bd1e-a4d9fee39af7" data-domains="rover.otter.land" data-sample-rate="0.15" data-mask-level="moderate" data-max-duration="300000"></script>
|
||||||
<title>Roomba Rover</title>
|
<title>Roomba Rover</title>
|
||||||
<script type="module" crossorigin src="/assets/index-CWTcRRlU.js"></script>
|
<script type="module" crossorigin src="/assets/index-DC_FLGBQ.js"></script>
|
||||||
<link rel="stylesheet" crossorigin href="/assets/index-DwpUkSbG.css">
|
<link rel="stylesheet" crossorigin href="/assets/index-DwpUkSbG.css">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|||||||
@@ -125,6 +125,18 @@ function normalizeSpotlightPayloadState(rawState) {
|
|||||||
return Boolean(Number(rawState));
|
return Boolean(Number(rawState));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function normalizeIrState(rawState) {
|
||||||
|
/*
|
||||||
|
Reolink accepts exactly Auto, On, and Off for this camera's IR LED control.
|
||||||
|
Normalize UI payloads at the server boundary so keyboard, mobile, and any
|
||||||
|
future direct socket callers all hit the same camera API contract.
|
||||||
|
*/
|
||||||
|
const normalized = String(rawState || '').trim().toLowerCase();
|
||||||
|
if (normalized === 'on' || normalized === '1' || normalized === 'true') return 'On';
|
||||||
|
if (normalized === 'off' || normalized === '0' || normalized === 'false') return 'Off';
|
||||||
|
return 'Auto';
|
||||||
|
}
|
||||||
|
|
||||||
function passesMode(socket) {
|
function passesMode(socket) {
|
||||||
const mode = getMode();
|
const mode = getMode();
|
||||||
if (mode === MODES.LOCKDOWN) return isLockdownAdmin(socket);
|
if (mode === MODES.LOCKDOWN) return isLockdownAdmin(socket);
|
||||||
@@ -650,11 +662,17 @@ async function setSpotlight(socket, payload = {}) {
|
|||||||
async function setIr(socket, payload = {}) {
|
async function setIr(socket, payload = {}) {
|
||||||
requireOperator(socket);
|
requireOperator(socket);
|
||||||
return serializeVendorState(async () => {
|
return serializeVendorState(async () => {
|
||||||
const nextState = String(payload.state || '').toLowerCase() === 'off' ? 'Off' : 'Auto';
|
const nextState = normalizeIrState(payload.state);
|
||||||
const client = await ensureReolinkClient();
|
const client = await ensureReolinkClient();
|
||||||
state.ir = { ...(state.ir || {}), state: nextState };
|
/*
|
||||||
|
The camera requires channel inside IrLights. Without it, SetIrLights
|
||||||
|
returns param error (-4), while the optimistic local state makes the UI
|
||||||
|
look like the command worked. Keep the optimistic state, but send the
|
||||||
|
minimal payload the camera actually accepts.
|
||||||
|
*/
|
||||||
|
state.ir = { ...(state.ir || {}), channel: 0, state: nextState };
|
||||||
emitChange('ir-pending');
|
emitChange('ir-pending');
|
||||||
await client.api('SetIrLights', { IrLights: { state: nextState } });
|
await client.api('SetIrLights', { IrLights: { channel: 0, state: nextState } });
|
||||||
await refreshVendorState();
|
await refreshVendorState();
|
||||||
emitChange('ir');
|
emitChange('ir');
|
||||||
return state.ir;
|
return state.ir;
|
||||||
|
|||||||
@@ -77,6 +77,25 @@ function isSpotlightOn(light = {}) {
|
|||||||
return Boolean(Number(raw));
|
return Boolean(Number(raw));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function normalizeIrMode(mode) {
|
||||||
|
const normalized = String(mode || '').trim().toLowerCase();
|
||||||
|
if (normalized === 'on') return 'On';
|
||||||
|
if (normalized === 'off') return 'Off';
|
||||||
|
return 'Auto';
|
||||||
|
}
|
||||||
|
|
||||||
|
function nextIrMode(currentMode) {
|
||||||
|
/*
|
||||||
|
The rover laser button becomes the PTZ camera's IR mode control while the
|
||||||
|
PTZ camera is active. Cycle all three modes exposed by this Reolink camera
|
||||||
|
instead of reducing the control to a two-state toggle.
|
||||||
|
*/
|
||||||
|
const current = normalizeIrMode(currentMode);
|
||||||
|
if (current === 'Auto') return 'On';
|
||||||
|
if (current === 'On') return 'Off';
|
||||||
|
return 'Auto';
|
||||||
|
}
|
||||||
|
|
||||||
export function usePtzControlAdapter() {
|
export function usePtzControlAdapter() {
|
||||||
const socket = useSocket();
|
const socket = useSocket();
|
||||||
const ptz = useSessionSelector((state) => state.session?.ptzCamera || null);
|
const ptz = useSessionSelector((state) => state.session?.ptzCamera || null);
|
||||||
@@ -176,8 +195,9 @@ export function usePtzControlAdapter() {
|
|||||||
const setIr = useCallback(
|
const setIr = useCallback(
|
||||||
(nextOn) => {
|
(nextOn) => {
|
||||||
if (!isActive) return false;
|
if (!isActive) return false;
|
||||||
const currentOff = String(ptz?.ir?.state || '').toLowerCase() === 'off';
|
const desiredState = typeof nextOn === 'boolean'
|
||||||
const desiredState = typeof nextOn === 'boolean' ? (nextOn ? 'Auto' : 'Off') : currentOff ? 'Auto' : 'Off';
|
? (nextOn ? 'On' : 'Off')
|
||||||
|
: nextIrMode(ptz?.ir?.state);
|
||||||
emitPtz('ptzCamera:ir', { state: desiredState });
|
emitPtz('ptzCamera:ir', { state: desiredState });
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user