From 05ca368f2946270bab2f56057d33c34d51c16d29 Mon Sep 17 00:00:00 2001 From: Mitchell R Date: Fri, 22 May 2026 18:30:41 +0200 Subject: [PATCH] fix(onvif): import discovered cameras as type=onvif with credentials MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit importDiscoveredCamera was hardcoded to type="rtsp", losing ONVIF identity. Camera edit showed RTSP fields, ONVIF event subscription skipped (checks cam_type=="onvif"), re-discovery impossible. Now creates type="onvif" with onvif_host/port/username/password stored on the camera row. Streams still go into camera_streams (unchanged). Bundle ships onvif fields → kiosk subscribes to PullPoint events. Also passes host + port as hidden form fields from discover results page so the add handler has them available. Basic manual camera creation via UI stays rtsp-only (simpler); discovery flow produces onvif type. --- .../plugins/service-admin-http/routes-admin.ts | 17 +++++++++++++---- server/src/web-templates/admin-pages.tsx | 3 +++ 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/server/src/plugins/service-admin-http/routes-admin.ts b/server/src/plugins/service-admin-http/routes-admin.ts index e907457..460466b 100644 --- a/server/src/plugins/service-admin-http/routes-admin.ts +++ b/server/src/plugins/service-admin-http/routes-admin.ts @@ -174,6 +174,8 @@ function parseDiscoveredStreams(raw: string): DiscoverAddStream[] { function importDiscoveredCamera( deps: AdminDeps, rawName: string, + onvifHost: string, + onvifPort: number, username: string, password: string, streams: DiscoverAddStream[], @@ -185,9 +187,13 @@ function importDiscoveredCamera( const cam = deps.repo.createCamera({ name, - type: "rtsp", + type: "onvif", rtsp_url: mainRtspUrl, - }); + onvif_host: onvifHost, + onvif_port: onvifPort, + onvif_username: username, + onvif_password: password, + } as any); for (const stream of streams) { const width = stream.width == null ? null : Number(stream.width); const height = stream.height == null ? null : Number(stream.height); @@ -587,6 +593,7 @@ export function registerAdminRoutes(app: H3, deps: AdminDeps): void { return htmlPage(CameraDiscoverResultsPage({ user: user.username, host, + port, username, password, cameras, @@ -603,6 +610,8 @@ export function registerAdminRoutes(app: H3, deps: AdminDeps): void { app.post("/admin/cameras/discover/add", async (event) => { const body = await readBody>(event); + const onvifHost = formValue(body?.["host"]).trim(); + const onvifPort = parseInt(formValue(body?.["port"]) || "80", 10) || 80; const username = formValue(body?.["username"]).trim(); const password = formValue(body?.["password"]); let imported = 0; @@ -613,7 +622,7 @@ export function registerAdminRoutes(app: H3, deps: AdminDeps): void { const rawName = formValue(body?.[`camera_${idx}_name`]).trim() || "ONVIF camera"; const streams = parseDiscoveredStreams(formValue(body?.[`camera_${idx}_streams_json`])); if (streams.length === 0) continue; - const camId = importDiscoveredCamera(deps, rawName, username, password, streams); + const camId = importDiscoveredCamera(deps, rawName, onvifHost, onvifPort, username, password, streams); if (camId != null) { deps.nodered.forward("camera.changed", { camera_id: camId, event: "created", source: "server" }); } @@ -623,7 +632,7 @@ export function registerAdminRoutes(app: H3, deps: AdminDeps): void { const rawName = formValue(body?.["name"]).trim() || "ONVIF camera"; const streams = parseDiscoveredStreams(formValue(body?.["streams_json"])); if (streams.length > 0) { - const camId = importDiscoveredCamera(deps, rawName, username, password, streams); + const camId = importDiscoveredCamera(deps, rawName, onvifHost, onvifPort, username, password, streams); if (camId != null) { deps.nodered.forward("camera.changed", { camera_id: camId, event: "created", source: "server" }); } diff --git a/server/src/web-templates/admin-pages.tsx b/server/src/web-templates/admin-pages.tsx index be67c9e..16079dd 100644 --- a/server/src/web-templates/admin-pages.tsx +++ b/server/src/web-templates/admin-pages.tsx @@ -313,6 +313,7 @@ interface DiscoveredCameraRow { interface CameraDiscoverResultsProps { user: string; host: string; + port?: number; username: string; password: string; cameras: DiscoveredCameraRow[]; @@ -438,6 +439,8 @@ export function CameraDiscoverResultsPage(props: CameraDiscoverResultsProps) {
No profiles returned
) : (
+ +