mirror of
https://github.com/legop3/MultiRoombaRover.git
synced 2026-09-16 01:21:20 -04:00
better video ptz stuf
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/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>
|
||||
<script type="module" crossorigin src="/assets/index-Bi6EaYls.js"></script>
|
||||
<script type="module" crossorigin src="/assets/index-B8x6P1kX.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/assets/index-MAURNhur.css">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
@@ -7,6 +7,7 @@ const { issueCommand } = require('../commandService');
|
||||
const homeAssistantService = require('../homeAssistantService');
|
||||
const neatoService = require('../neatoService');
|
||||
const liftService = require('../liftService');
|
||||
const ptzCameraService = require('../ptzCameraService');
|
||||
const {
|
||||
HEADLIGHT_DISABLE_ACTION,
|
||||
LASER_DISABLE_ACTION,
|
||||
@@ -103,6 +104,17 @@ async function disableAllRoverLasers() {
|
||||
return { action: 'disableRoverLasers', attempted, failed };
|
||||
}
|
||||
|
||||
async function disablePtzEmitters() {
|
||||
/*
|
||||
The PTZ camera has its own light APIs and ownership rules, so the idle
|
||||
service delegates the actual Reolink calls to ptzCameraService instead of
|
||||
pretending they are rover commands. This keeps idleService responsible only
|
||||
for "idle fired; run cleanup actions" and keeps camera-specific payload
|
||||
details beside the rest of the PTZ integration.
|
||||
*/
|
||||
return ptzCameraService.disableEmittersForIdle();
|
||||
}
|
||||
|
||||
async function sendNeatoHome() {
|
||||
try {
|
||||
await neatoService.sendHome();
|
||||
@@ -126,6 +138,7 @@ const idleActions = [
|
||||
// dockAllRovers,
|
||||
disableAllRoverHeadlights,
|
||||
disableAllRoverLasers,
|
||||
disablePtzEmitters,
|
||||
sendNeatoHome,
|
||||
raiseLift,
|
||||
];
|
||||
|
||||
@@ -756,6 +756,81 @@ async function setIr(socket, payload = {}) {
|
||||
});
|
||||
}
|
||||
|
||||
async function disableEmittersForIdle() {
|
||||
/*
|
||||
Idle cleanup is a server-owned safety action, not a user control action, so
|
||||
it intentionally does not go through requireOperator(). If nobody is using
|
||||
the camera, the system still needs a way to leave every camera-side emitter
|
||||
in a known off state.
|
||||
*/
|
||||
if (!enabled) {
|
||||
return { action: 'disablePtzEmitters', skipped: true, reason: 'ptzDisabled' };
|
||||
}
|
||||
|
||||
await initialize();
|
||||
if (!state.initialized) {
|
||||
return {
|
||||
action: 'disablePtzEmitters',
|
||||
success: false,
|
||||
error: state.error || 'PTZ camera is not ready',
|
||||
};
|
||||
}
|
||||
|
||||
return serializeVendorState(async () => {
|
||||
const client = await ensureReolinkClient();
|
||||
const lightPayload = { channel: 0, state: spotlightCameraStateForLogicalOn(false) };
|
||||
const irPayload = { channel: 0, state: normalizeIrState('off') };
|
||||
const failures = [];
|
||||
|
||||
/*
|
||||
Set the public state before the API calls finish so the UI immediately
|
||||
reflects the idle policy. If a camera call fails, the result still records
|
||||
that failure and the next vendor refresh can correct the optimistic state.
|
||||
*/
|
||||
state.light = normalizeSpotlightState({
|
||||
...(state.light || {}),
|
||||
...lightPayload,
|
||||
on: false,
|
||||
});
|
||||
state.ir = {
|
||||
...(state.ir || {}),
|
||||
...irPayload,
|
||||
};
|
||||
emitChange('idle-emitters-off-pending');
|
||||
|
||||
try {
|
||||
await client.api('SetWhiteLed', { WhiteLed: lightPayload });
|
||||
} catch (err) {
|
||||
failures.push({ control: 'spotlight', error: err.message });
|
||||
}
|
||||
|
||||
try {
|
||||
await client.api('SetIrLights', { IrLights: irPayload });
|
||||
} catch (err) {
|
||||
failures.push({ control: 'ir', error: err.message });
|
||||
}
|
||||
|
||||
/*
|
||||
Read back once after the writes so stale optimistic state does not linger
|
||||
forever. The existing spotlight button path delays verification because it
|
||||
is user-facing and frequently toggled; idle fires rarely, so one ordered
|
||||
refresh keeps the final state simple.
|
||||
*/
|
||||
try {
|
||||
await refreshVendorState();
|
||||
} catch (err) {
|
||||
failures.push({ control: 'refresh', error: err.message });
|
||||
}
|
||||
|
||||
emitChange('idle-emitters-off');
|
||||
return {
|
||||
action: 'disablePtzEmitters',
|
||||
success: failures.length === 0,
|
||||
failures,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
function canRequestLiveVideo(socket) {
|
||||
if (!enabled || !passesMode(socket)) return false;
|
||||
if (state.operatorSocketId === socket?.id) return true;
|
||||
@@ -973,6 +1048,7 @@ module.exports = {
|
||||
ptzCameraEvents: events,
|
||||
getPublicState,
|
||||
canRequestLiveVideo,
|
||||
disableEmittersForIdle,
|
||||
getReplaySource: () => enabled && isReplayEnabled()
|
||||
? { type: 'ptz', id: PTZ_CAMERA_ID, label: cameraConfig.name || 'PTZ Camera' }
|
||||
: null,
|
||||
|
||||
Reference in New Issue
Block a user