cameras/scripts/camera-check.ts
Michael Mainguy f39d16a8c0 Add ONVIF camera app with a server-rendered camera dashboard
Discovers ONVIF cameras (Hikvision/Annke) over WS-Discovery, keeps a
server-side registry and an encrypted credential store, and serves
info, snapshot and credentials routes for each camera.

The home page is now a Server Component that lists known cameras from
the registry on load, without a scan (vrek iss-a0hz0py). The snapshot
refresh rate lives in the URL (?refresh=), and a scan refreshes the
server-rendered list.

Route input is validated with zod (iss-rjqy3hy), and /api/discover no
longer returns raw error messages (iss-dbwgww8). Adds
@tanstack/react-query and zod as dependencies, with a QueryClient
provider in the root layout.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-19 08:40:32 -05:00

36 lines
1.4 KiB
TypeScript

// Checks ONVIF login, profiles and snapshot for one camera, outside of Next.js.
// The camera must be in .data/cameras.json (run a scan in the app first).
// Usage: npx tsx --env-file=.env.local --conditions=react-server scripts/camera-check.ts <id-or-ip>
import { readFileSync, writeFileSync } from "node:fs";
import { getCameraInfo, getSnapshot } from "../src/lib/camera";
import type { CameraRecord } from "../src/lib/camera-registry";
const [idOrHost] = process.argv.slice(2);
if (!idOrHost) {
console.error("Usage: scripts/camera-check.ts <id-or-ip>");
process.exit(1);
}
const registry: Record<string, CameraRecord> = JSON.parse(
readFileSync(".data/cameras.json", "utf8"),
);
const record = Object.values(registry).find((r) => r.id === idOrHost || r.host === idOrHost);
if (!record) {
console.error(`${idOrHost} is not in .data/cameras.json; scan the network first.`);
process.exit(1);
}
const target = { id: record.id, host: record.host, port: record.port };
console.log(`Camera ${record.id} at ${record.host}:${record.port}`);
(async () => {
try {
console.log(JSON.stringify(await getCameraInfo(target), null, 2));
const snap = await getSnapshot(target);
writeFileSync("snapshot.jpg", snap.body);
console.log(`Snapshot: ${snap.contentType}, ${snap.body.length} bytes -> snapshot.jpg`);
} catch (err) {
console.error(`Error (${(err as Error).name}):`, err instanceof Error ? err.message : err);
}
process.exit(0);
})();