diff --git a/frigate/config.py b/frigate/config.py
index 788f51c18..42324b530 100644
--- a/frigate/config.py
+++ b/frigate/config.py
@@ -950,7 +950,8 @@ class FrigateConfig(FrigateBaseModel):
input.path = input.path.format(**FRIGATE_ENV_VARS)
# ONVIF substitution
- if camera_config.onvif.password:
+ if camera_config.onvif.user or camera_config.onvif.password:
+ camera_config.onvif.user = camera_config.onvif.user.format(**FRIGATE_ENV_VARS)
camera_config.onvif.password = camera_config.onvif.password.format(**FRIGATE_ENV_VARS)
# Add default filters
diff --git a/frigate/ptz.py b/frigate/ptz.py
index 3ae2aefe4..67e513b8e 100644
--- a/frigate/ptz.py
+++ b/frigate/ptz.py
@@ -41,17 +41,14 @@ class OnvifController:
cam.onvif.port,
cam.onvif.user,
cam.onvif.password,
- wsdl_dir=site.getsitepackages()[0].replace(
- "dist-packages", "site-packages"
- )
- + "/wsdl",
+ wsdl_dir="/home/vscode/.local/lib/python3.4/site-packages/wsdl/",
),
"init": False,
"active": False,
"presets": {},
}
- def _init_onvif(self, camera_name: str) -> None:
+ def _init_onvif(self, camera_name: str) -> bool:
onvif: ONVIFCamera = self.cams[camera_name]["onvif"]
# create init services
@@ -61,6 +58,7 @@ class OnvifController:
profile = media.GetProfiles()[0]
except ONVIFError as e:
logger.error(f"Unable to connect to camera: {camera_name}: {e}")
+ return False
ptz = onvif.create_ptz_service()
request = ptz.create_type("GetConfigurationOptions")
@@ -89,6 +87,7 @@ class OnvifController:
self.cams[camera_name]["features"] = supported_features
self.cams[camera_name]["init"] = True
+ return True
def _stop(self, camera_name: str) -> None:
onvif: ONVIFCamera = self.cams[camera_name]["onvif"]
@@ -177,7 +176,8 @@ class OnvifController:
return
if not self.cams[camera_name]["init"]:
- self._init_onvif(camera_name)
+ if not self._init_onvif(camera_name):
+ return
if command == OnvifCommandEnum.init:
# already init
diff --git a/web/src/routes/Birdseye.jsx b/web/src/routes/Birdseye.jsx
index 91c97fcb9..97de37494 100644
--- a/web/src/routes/Birdseye.jsx
+++ b/web/src/routes/Birdseye.jsx
@@ -6,6 +6,8 @@ import Heading from '../components/Heading';
import WebRtcPlayer from '../components/WebRtcPlayer';
import MsePlayer from '../components/MsePlayer';
import useSWR from 'swr';
+import { useMemo } from 'preact/hooks';
+import CameraControlPanel from '../components/CameraControlPanel';
export default function Birdseye() {
const { data: config } = useSWR('config');
@@ -16,6 +18,16 @@ export default function Birdseye() {
);
const sourceValues = ['mse', 'webrtc', 'jsmpeg'];
+ const ptzCameras = useMemo(() => {
+ if (!config) {
+ return [];
+ }
+
+ return Object.entries(config.cameras)
+ .filter(([_, conf]) => conf.onvif?.host)
+ .map(([_, camera]) => camera.name);
+ }, [config]);
+
if (!config || !sourceIsLoaded) {
return