Add camera specific webrtc configuration.

This commit is contained in:
Dermot Duffy
2022-01-14 21:31:16 -08:00
parent 9f93a94f4a
commit 7030da4603
3 changed files with 47 additions and 28 deletions
+30 -17
View File
@@ -1,3 +1,4 @@
// TODO double media load event for webrtc
// TODO webrtc entities in camera section? // TODO webrtc entities in camera section?
// TODO conditional elements based on camera name (requires event changed to propagate upwards) // TODO conditional elements based on camera name (requires event changed to propagate upwards)
// TODO Remove media load event warning // TODO Remove media load event warning
@@ -5,7 +6,7 @@
// TODO search for TODOs // TODO search for TODOs
import { CSSResultGroup, LitElement, TemplateResult, html, unsafeCSS } from 'lit'; import { CSSResultGroup, LitElement, TemplateResult, html, unsafeCSS } from 'lit';
import type { import {
BrowseMediaSource, BrowseMediaSource,
ExtendedHomeAssistant, ExtendedHomeAssistant,
CameraConfig, CameraConfig,
@@ -14,6 +15,7 @@ import type {
MediaShowInfo, MediaShowInfo,
WebRTCConfig, WebRTCConfig,
StateParameters, StateParameters,
FrigateCardError,
} from '../types.js'; } from '../types.js';
import { EmblaOptionsType } from 'embla-carousel'; import { EmblaOptionsType } from 'embla-carousel';
import { HomeAssistant } from 'custom-card-helpers'; import { HomeAssistant } from 'custom-card-helpers';
@@ -420,6 +422,7 @@ export class FrigateCardLiveProvider extends LitElement {
: this.liveConfig.provider == 'webrtc' : this.liveConfig.provider == 'webrtc'
? html`<frigate-card-live-webrtc ? html`<frigate-card-live-webrtc
.hass=${this.hass} .hass=${this.hass}
.cameraConfig=${this.cameraConfig}
.webRTCConfig=${this.liveConfig.webrtc || {}} .webRTCConfig=${this.liveConfig.webrtc || {}}
> >
</frigate-card-live-webrtc>` </frigate-card-live-webrtc>`
@@ -482,23 +485,35 @@ export class FrigateCardLiveWebRTC extends LitElement {
@property({ attribute: false }) @property({ attribute: false })
protected webRTCConfig?: WebRTCConfig; protected webRTCConfig?: WebRTCConfig;
@property({ attribute: false })
protected cameraConfig?: CameraConfig;
protected hass?: HomeAssistant & ExtendedHomeAssistant; protected hass?: HomeAssistant & ExtendedHomeAssistant;
protected _webRTCElement: HTMLElement | null = null;
protected _callbacksAdded = false;
/** /**
* Create the WebRTC element. May throw. * Create the WebRTC element. May throw.
*/ */
protected _createWebRTC(): TemplateResult | void { protected _createWebRTC(): HTMLElement | undefined {
// eslint-disable-next-line @typescript-eslint/no-explicit-any // eslint-disable-next-line @typescript-eslint/no-explicit-any
const webrtcElement = customElements.get('webrtc-camera') as any; const webrtcElement = customElements.get('webrtc-camera') as any;
if (webrtcElement) { if (webrtcElement) {
const webrtc = new webrtcElement(); const webrtc = new webrtcElement();
webrtc.setConfig(this.webRTCConfig); const config = {...this.webRTCConfig};
// If the live WebRTC configuration does not specify a URL/entity to use,
// then take values from the camera configuration instead (if there are
// any).
if (!config.url) {
config.url = this.cameraConfig?.webrtc?.url;
}
if (!config.entity) {
config.entity = this.cameraConfig?.webrtc?.entity;
}
webrtc.setConfig(config);
webrtc.hass = this.hass; webrtc.hass = this.hass;
this._webRTCElement = webrtc; return webrtc;
} else { } else {
throw new Error(localize('error.missing_webrtc')); throw new FrigateCardError(localize('error.webrtc_missing'));
} }
} }
@@ -510,24 +525,23 @@ export class FrigateCardLiveWebRTC extends LitElement {
if (!this.hass) { if (!this.hass) {
return; return;
} }
if (!this._webRTCElement) { let webrtcElement: HTMLElement | undefined;
try { try {
this._createWebRTC(); webrtcElement = this._createWebRTC();
} catch (e) { } catch (e) {
return dispatchErrorMessageEvent(this, (e as Error).message); return dispatchErrorMessageEvent(
this,
e instanceof FrigateCardError
? (e as FrigateCardError).message
: localize('error.webrtc_reported_error') + ': ' + (e as Error).message);
} }
} return html`${webrtcElement}`;
return html`${this._webRTCElement}`;
} }
/** /**
* Updated lifecycle callback. * Updated lifecycle callback.
*/ */
public updated(): void { public updated(): void {
if (this._callbacksAdded) {
return;
}
// Extract the video component after it has been rendered and generate the // Extract the video component after it has been rendered and generate the
// media load event. // media load event.
this.updateComplete.then(() => { this.updateComplete.then(() => {
@@ -555,7 +569,6 @@ export class FrigateCardLiveWebRTC extends LitElement {
} }
dispatchPauseEvent(this); dispatchPauseEvent(this);
}; };
this._callbacksAdded = true;
} }
}); });
} }
+2 -1
View File
@@ -158,7 +158,8 @@
"invalid_configuration": "Invalid configuration", "invalid_configuration": "Invalid configuration",
"invalid_configuration_no_hint": "No location hint available (bad or missing type?)", "invalid_configuration_no_hint": "No location hint available (bad or missing type?)",
"upgrade_available": "An automated card configuration upgrade is available, please visit the visual card editor", "upgrade_available": "An automated card configuration upgrade is available, please visit the visual card editor",
"missing_webrtc": "WebRTC component not found", "webrtc_missing": "WebRTC component not found",
"webrtc_reported_error": "WebRTC component reported an error",
"no_cameras": "No valid cameras found, you must configure at least one camera with either a camera_entity or camera_name", "no_cameras": "No valid cameras found, you must configure at least one camera with either a camera_entity or camera_name",
"duplicate_camera_id": "Duplicate Frigate camera, use the 'id' parameter to uniquely identify cameras with the same 'camera_entity' or 'camera_name'", "duplicate_camera_id": "Duplicate Frigate camera, use the 'id' parameter to uniquely identify cameras with the same 'camera_entity' or 'camera_name'",
"could_not_render_elements": "Could not render picture elements", "could_not_render_elements": "Could not render picture elements",
+13 -8
View File
@@ -59,6 +59,8 @@ const FRIGATE_MENU_MODES = [
] as const; ] as const;
const LIVE_PROVIDERS = ['frigate', 'frigate-jsmpeg', 'webrtc'] as const; const LIVE_PROVIDERS = ['frigate', 'frigate-jsmpeg', 'webrtc'] as const;
export class FrigateCardError extends Error {}
/** /**
* Action Types (for "Picture Elements" / Menu) * Action Types (for "Picture Elements" / Menu)
*/ */
@@ -349,11 +351,16 @@ const pictureElementsSchema = pictureElementSchema.array().optional();
export type PictureElements = z.infer<typeof pictureElementsSchema>; export type PictureElements = z.infer<typeof pictureElementsSchema>;
/** /**
* Frigate configuration section. * Camera configuration section
*/ */
export const cameraConfigDefault = { export const cameraConfigDefault = {
client_id: 'frigate' as const, client_id: 'frigate' as const,
}; };
const webrtcCameraConfigSchema = z
.object({
entity: z.string().optional(),
url: z.string().optional(),
});
const cameraConfigDefaultSchema = z const cameraConfigDefaultSchema = z
.object({ .object({
// No URL validation to allow relative URLs within HA (e.g. Frigate addon). // No URL validation to allow relative URLs within HA (e.g. Frigate addon).
@@ -372,6 +379,9 @@ const cameraConfigDefaultSchema = z
// Optional identifier to separate different camera configurations used in // Optional identifier to separate different camera configurations used in
// this card. // this card.
id: z.string().optional(), id: z.string().optional(),
// Camera identifiers for WebRTC.
webrtc: webrtcCameraConfigSchema.optional(),
}) })
.default(cameraConfigDefault); .default(cameraConfigDefault);
export type CameraConfig = z.infer<typeof cameraConfigDefaultSchema>; export type CameraConfig = z.infer<typeof cameraConfigDefaultSchema>;
@@ -459,13 +469,8 @@ const liveConfigDefault = {
}, },
}, },
}; };
const webrtcConfigSchema = z
.object({ const webrtcConfigSchema = webrtcCameraConfigSchema.passthrough().optional();
entity: z.string().optional(),
url: z.string().optional(),
})
.passthrough()
.optional();
export type WebRTCConfig = z.infer<typeof webrtcConfigSchema>; export type WebRTCConfig = z.infer<typeof webrtcConfigSchema>;
const jsmpegConfigSchema = z const jsmpegConfigSchema = z