diff --git a/web/public/locales/en/views/settings.json b/web/public/locales/en/views/settings.json
index e91f2d29c..7714a00e7 100644
--- a/web/public/locales/en/views/settings.json
+++ b/web/public/locales/en/views/settings.json
@@ -154,6 +154,7 @@
"description": "Follow the steps below to add a new camera to your Frigate installation.",
"steps": {
"nameAndConnection": "Name & Connection",
+ "probeOrSnapshot": "Probe or Snapshot",
"streamConfiguration": "Stream Configuration",
"validationAndTesting": "Validation & Testing"
},
@@ -240,6 +241,43 @@
}
},
"step2": {
+ "description": "Probe the camera for available streams or configure manual settings based on your selected detection method.",
+ "testSuccess": "Connection test successful!",
+ "testFailed": "Connection test failed. Please check your input and try again.",
+ "streamDetails": "Stream Details",
+ "probing": "Probing camera...",
+ "retry": "Retry",
+ "testing": {
+ "probingMetadata": "Probing camera metadata...",
+ "fetchingSnapshot": "Fetching camera snapshot..."
+ },
+ "probeFailed": "Failed to probe camera: {{error}}",
+ "probingDevice": "Probing device...",
+ "probeSuccessful": "Probe successful",
+ "probeError": "Probe Error",
+ "probeNoSuccess": "Probe unsuccessful",
+ "deviceInfo": "Device Information",
+ "manufacturer": "Manufacturer",
+ "model": "Model",
+ "firmware": "Firmware",
+ "profiles": "Profiles",
+ "ptzSupport": "PTZ Support",
+ "autotrackingSupport": "Autotracking Support",
+ "presets": "Presets",
+ "rtspCandidates": "RTSP Candidates",
+ "candidateStreamTitle": "Candidate {{number}}",
+ "useCandidate": "Use",
+ "uriCopy": "Copy",
+ "uriCopied": "URI copied to clipboard",
+ "testConnection": "Test Connection",
+ "toggleUriView": "Click to toggle full URI view",
+ "connected": "Connected",
+ "notConnected": "Not Connected",
+ "errors": {
+ "hostRequired": "Host/IP address is required"
+ }
+ },
+ "step3": {
"description": "Configure stream roles and add additional streams for your camera.",
"streamsTitle": "Camera Streams",
"addStream": "Add Stream",
@@ -278,7 +316,7 @@
"description": "Use go2rtc restreaming to reduce connections to your camera."
}
},
- "step3": {
+ "step4": {
"description": "Final validation and analysis before saving your new camera. Connect each stream before saving.",
"validationTitle": "Stream Validation",
"connectAllStreams": "Connect All Streams",
@@ -314,6 +352,9 @@
"audioCodecRecordError": "The AAC audio codec is required to support audio in recordings.",
"audioCodecRequired": "An audio stream is required to support audio detection.",
"restreamingWarning": "Reducing connections to the camera for the record stream may increase CPU usage slightly.",
+ "brands": {
+ "reolink-rtsp": "Reolink RTSP is not recommended. Enable HTTP in the camera's firmware settings and restart the wizard."
+ },
"dahua": {
"substreamWarning": "Substream 1 is locked to a low resolution. Many Dahua / Amcrest / EmpireTech cameras support additional substreams that need to be enabled in the camera's settings. It is recommended to check and utilize those streams if available."
},
diff --git a/web/src/components/settings/CameraWizardDialog.tsx b/web/src/components/settings/CameraWizardDialog.tsx
index 6611a9dd6..7bffd772d 100644
--- a/web/src/components/settings/CameraWizardDialog.tsx
+++ b/web/src/components/settings/CameraWizardDialog.tsx
@@ -12,8 +12,9 @@ import { toast } from "sonner";
import useSWR from "swr";
import axios from "axios";
import Step1NameCamera from "@/components/settings/wizard/Step1NameCamera";
-import Step2StreamConfig from "@/components/settings/wizard/Step2StreamConfig";
-import Step3Validation from "@/components/settings/wizard/Step3Validation";
+import Step2ProbeOrSnapshot from "@/components/settings/wizard/Step2ProbeOrSnapshot";
+import Step3StreamConfig from "@/components/settings/wizard/Step3StreamConfig";
+import Step4Validation from "@/components/settings/wizard/Step4Validation";
import type {
WizardFormData,
CameraConfigData,
@@ -57,6 +58,7 @@ const wizardReducer = (
const STEPS = [
"cameraWizard.steps.nameAndConnection",
+ "cameraWizard.steps.probeOrSnapshot",
"cameraWizard.steps.streamConfiguration",
"cameraWizard.steps.validationAndTesting",
];
@@ -100,20 +102,20 @@ export default function CameraWizardDialog({
const canProceedToNext = useCallback((): boolean => {
switch (currentStep) {
case 0:
- // Can proceed if camera name is set and at least one stream exists
- return !!(
- state.wizardData.cameraName &&
- (state.wizardData.streams?.length ?? 0) > 0
- );
+ // Step 1: Can proceed if camera name is set
+ return !!state.wizardData.cameraName;
case 1:
- // Can proceed if at least one stream has 'detect' role
+ // Step 2: Can proceed if at least one stream exists (from probe or manual test)
+ return (state.wizardData.streams?.length ?? 0) > 0;
+ case 2:
+ // Step 3: Can proceed if at least one stream has 'detect' role
return !!(
state.wizardData.streams?.some((stream) =>
stream.roles.includes("detect"),
) ?? false
);
- case 2:
- // Always can proceed from final step (save will be handled there)
+ case 3:
+ // Step 4: Always can proceed from final step (save will be handled there)
return true;
default:
return false;
@@ -385,7 +387,16 @@ export default function CameraWizardDialog({
/>
)}
{currentStep === 1 && (
-
+ )}
+ {currentStep === 2 && (
+
)}
- {currentStep === 2 && (
- {
navigator.clipboard.writeText(uri);
setCopiedUri(uri);
- toast.success(t("cameraWizard.step1.uriCopied"));
+ toast.success(t("cameraWizard.step2.uriCopied"));
setTimeout(() => setCopiedUri(null), 2000);
};
@@ -58,7 +58,7 @@ export default function OnvifProbeResults({