diff --git a/README.md b/README.md
index 31aa0327..102d4a7d 100644
--- a/README.md
+++ b/README.md
@@ -103,18 +103,14 @@ See the [fully expanded cameras configuration example](#config-expanded-cameras)
| Option | Default | Overridable | Description |
| - | - | - | - |
| `camera_entity` | | :heavy_multiplication_x: | The Home Assistant camera entity to use with the `frigate` live provider view. Also used to automatically detect the name of the underlying Frigate camera, and the title/icon of the camera. |
-| `camera_name` | Autodetected from `camera_entity` if that is specified. | :heavy_multiplication_x: | The Frigate camera name to use when communicating with the Frigate server, e.g. for viewing clips/snapshots or the JSMPEG live view. To view the birdseye view set this to `birdseye` and use the `frigate-jsmpeg` live provider.|
| `live_provider` | `auto` | :heavy_multiplication_x: | The choice of live stream provider. See [Live Providers](#live-providers) below.|
-| `frigate_url` | | :heavy_multiplication_x: | The URL of the frigate server. If set, this value will be (exclusively) used for a `Frigate UI` menu button. |
-| `label` | | :heavy_multiplication_x: | A Frigate label / object filter used to filter events (clips & snapshots), e.g. 'person'.|
-| `zone` | | :heavy_multiplication_x: | A Frigate zone used to filter events (clips & snapshots), e.g. 'front_door'.|
-| `client_id` | `frigate` | :heavy_multiplication_x: | The Frigate client id to use. If this Home Assistant server has multiple Frigate server backends configured, this selects which server should be used. It should be set to the MQTT client id configured for this server, see [Frigate Integration Multiple Instance Support](https://docs.frigate.video/integrations/home-assistant/#multiple-instance-support).|
| `title` | Autodetected from `camera_entity` if that is specified. | :heavy_multiplication_x: | A friendly name for this camera to use in the card. |
| `icon` | Autodetected from `camera_entity` if that is specified. | :heavy_multiplication_x: | The icon to use for this camera in the camera menu and in the next & previous controls when using the `icon` style. |
-| `webrtc_card` | | :heavy_multiplication_x: | The WebRTC entity/URL to use for this camera with the `webrtc-card` live provider. See below. |
-| `id` | `camera_entity`, `webrtc_card.entity` or `camera_name` if set (in that preference order). | :heavy_multiplication_x: | An optional identifier to use throughout the card configuration to refer unambiguously to this camera. See [camera IDs](#camera-ids). |
-| `dependencies` | | :heavy_multiplication_x: | Other cameras that this camera should depend upon. See [camera dependencies](#camera-dependency-configuration) below. |
+| `id` | `camera_entity`, `webrtc_card.entity` or `frigate.camera_name` if set (in that preference order). | :heavy_multiplication_x: | An optional identifier to use throughout the card configuration to refer unambiguously to this camera. See [camera IDs](#camera-ids). |
+| `frigate` | | :heavy_multiplication_x: | Options for a Frigate camera. See [Frigate configuration](#camera-frigate-configuration) below. |
+| `dependencies` | | :heavy_multiplication_x: | Other cameras that this camera should depend upon. See [camera dependencies](#camera-dependencies-configuration) below. |
| `triggers` | | :heavy_multiplication_x: | Define what should cause this camera to update/trigger. See [camera triggers](#camera-trigger-configuration) below. |
+| `webrtc_card` | | :heavy_multiplication_x: | The WebRTC entity/URL to use for this camera with the `webrtc-card` live provider. See below. |
@@ -128,6 +124,26 @@ See the [fully expanded cameras configuration example](#config-expanded-cameras)
|`frigate-jsmpeg`|Better|Low|Builtin|Stream the JSMPEG stream from Frigate (proxied via the Frigate integration). See [note below on the required integration version](#jsmpeg-troubleshooting) for this live provider to function. This is the only live provider that can view the Frigate `birdseye` view.|
|`webrtc-card`|Best|High|Separate installation required|Embed's [AlexxIT's WebRTC Card](https://github.com/AlexxIT/WebRTC) to stream live feed, requires manual extra setup, see [below](#webrtc). Not to be confused with native Home Assistant WebRTC (use `ha` provider above).|
+
+
+
+#### Camera Frigate configuration
+
+The `frigate` block configures options for a Frigate camera. This configuration is included as part of a camera entry in the `cameras` array.
+
+```yaml
+cameras:
+ - frigate:
+```
+
+| Option | Default | Overridable | Description |
+| - | - | - | - |
+| `camera_name` | Autodetected from `camera_entity` if that is specified. | :heavy_multiplication_x: | The Frigate camera name to use when communicating with the Frigate server, e.g. for viewing clips/snapshots or the JSMPEG live view. To view the birdseye view set this to `birdseye` and use the `frigate-jsmpeg` live provider.|
+| `url` | | :heavy_multiplication_x: | The URL of the frigate server. If set, this value will be (exclusively) used for a `Frigate UI` menu button. All other communication with Frigate goes via Home Assistant. |
+| `label` | | :heavy_multiplication_x: | A Frigate label / object filter used to filter events (clips & snapshots), e.g. `person`.|
+| `zone` | | :heavy_multiplication_x: | A Frigate zone used to filter events (clips & snapshots), e.g. `front_door`.|
+| `client_id` | `frigate` | :heavy_multiplication_x: | The Frigate client id to use. If this Home Assistant server has multiple Frigate server backends configured, this selects which server should be used. It should be set to the MQTT client id configured for this server, see [Frigate Integration Multiple Instance Support](https://docs.frigate.video/integrations/home-assistant/#multiple-instance-support).|
+
#### Camera WebRTC Card configuration
The `webrtc_card` block configures only the entity/URL for this camera to be used with the WebRTC Card live provider. This configuration is included as part of a camera entry in the `cameras` array.
@@ -144,7 +160,7 @@ cameras:
See [Using the WebRTC Card](#webrtc) below for more details on how to use the WebRTC Card live provider.
-
+
#### Camera Dependency Configuration
@@ -160,7 +176,7 @@ cameras:
| `cameras` | | :heavy_multiplication_x: | An optional array of other camera identifiers (see [camera IDs](#camera-ids)). If specified the card will fetch events for this camera and *also* recursively events for the named cameras. All dependent cameras must themselves be a configured camera in the card. This can be useful to group events for cameras that are close together, to always have clips/snapshots show fully merged events across all cameras or to show events for the `birdseye` camera that otherwise would not have events itself.|
| `all_cameras` | `false` | :heavy_multiplication_x: | Shortcut to specify all other cameras as dependent cameras.|
-
+
#### Camera Trigger Configuration
@@ -181,7 +197,7 @@ cameras:
#### Camera IDs: Refering to cameras in card configuration
-Each camera configured in the card has a single identifier (`id`). For a given camera, this will be one of the camera {`id`, `camera_entity`, `webrtc_card.entity` or `camera_name`} parameters for that camera -- in that order of precedence. These ids may be used in conditions, dependencies or custom actions to refer to a given camera unambiguously. |
+Each camera configured in the card has a single identifier (`id`). For a given camera, this will be one of the camera {`id`, `camera_entity`, `webrtc_card.entity` or `frigate.camera_name`} parameters for that camera -- in that order of precedence. These ids may be used in conditions, dependencies or custom actions to refer to a given camera unambiguously. |
#### Example
@@ -205,7 +221,7 @@ See the [fully expanded view configuration example](#config-expanded-view) for h
| `timeout_seconds` | `300` | :white_check_mark: | A numbers of seconds of inactivity after user interaction, after which the card will reset to the default configured view (i.e. 'screensaver' functionality). Inactivity is defined as lack of mouse/touch interaction with the Frigate card. If the default view occurs sooner (e.g. via `update_seconds` or manually) the timer will be stopped. `0` means disable this functionality. |
| `update_seconds` | `0` | :white_check_mark: | A number of seconds after which to automatically update/refresh the default view. See [card updates](#card-updates) below for behavior and usecases. If the default view occurs sooner (e.g. manually) the timer will start over. `0` disables this functionality.|
| `update_force` | `false` | :white_check_mark: | Whether automated card updates/refreshes should ignore user interaction. See [card updates](#card-updates) below for behavior and usecases.|
-| `update_entities` | | :white_check_mark: | **YAML only**: A card-wide list of entities that should cause the view to reset to the default (if the entity only pertains to a particular camera use `triggers` for the selected camera instead, see [Trigger Configuration](#camera-triggers)). See [card updates](#card-updates) below for behavior and usecases.|
+| `update_entities` | | :white_check_mark: | **YAML only**: A card-wide list of entities that should cause the view to reset to the default (if the entity only pertains to a particular camera use `triggers` for the selected camera instead, see [Trigger Configuration](#camera-triggers-configuration)). See [card updates](#card-updates) below for behavior and usecases.|
| `update_cycle_camera` | `false` | :white_check_mark: | When set to `true` the selected camera is cycled on each default view change. |
| `render_entities` | | :white_check_mark: | **YAML only**: A list of entity ids that should cause the card to re-render 'in-place'. The view/camera is not changed. `update_*` flags do not pertain/relate to the behavior of this flag. This should **very** rarely be needed, but could be useful if the card is both setting and changing HA state of the same object as could be the case for some complex `card_mod` scenarios ([example](https://github.com/dermotduffy/frigate-hass-card/issues/343)). |
| `scan` | | :white_check_mark: | Configuration for [scan mode](#scan-mode). |
@@ -272,8 +288,8 @@ menu:
| `frigate` | :white_check_mark: | The `Frigate` menu button: brings the user to the default configured view (`view.default`), or collapses/expands the menu if the `menu.style` is `hidden` . |
| `cameras` | :white_check_mark: | The camera selection submenu. Will only appear if multiple cameras are configured. |
| `live` | :white_check_mark: | The `live` view menu button: brings the user to the `live` view. See [views](#views) below.|
-| `clips` | :white_check_mark: | The `clips` view menu button: brings the user to the `clips` view on tap and the most-recent `clip` view on hold. See [views](#views) below. This button will never be shown if the `camera_name` for the selected camera is not auto-detected/specified (e.g. non-Frigate cameras), or if the `camera_name` is `birdseye`.|
-| `snapshots` | :white_check_mark: | The `snapshots` view menu button: brings the user to the `clips` view on tap and the most-recent `snapshot` view on hold. See [views](#views) below. This button will never be shown if the `camera_name` for the selected camera is not auto-detected/specified (e.g. non-Frigate cameras), or if the `camera_name` is `birdseye`.|
+| `clips` | :white_check_mark: | The `clips` view menu button: brings the user to the `clips` view on tap and the most-recent `clip` view on hold. See [views](#views) below. This button will never be shown if the `frigate.camera_name` for the selected camera is not auto-detected/specified (e.g. non-Frigate cameras), or if the `frigate.camera_name` is `birdseye`.|
+| `snapshots` | :white_check_mark: | The `snapshots` view menu button: brings the user to the `clips` view on tap and the most-recent `snapshot` view on hold. See [views](#views) below. This button will never be shown if the `frigate.camera_name` for the selected camera is not auto-detected/specified (e.g. non-Frigate cameras), or if the `frigate.camera_name` is `birdseye`.|
| `image` | :white_check_mark: | The `image` view menu button: brings the user to the static `image` view. See [views](#views) below.|
| `download` | :white_check_mark: | The `download` menu button: allow direct download of the media being displayed.|
| `frigate_ui` | :white_check_mark: | The `frigate_ui` menu button: brings the user to a context-appropriate page on the Frigate UI (e.g. the camera homepage). Will only appear if the `frigate.url` option is set.|
@@ -1039,13 +1055,14 @@ Reference: [Camera Options](#camera-options).
```yaml
cameras:
- - frigate_url: http://my.frigate.local
- client_id: frigate
- camera_name: front_door
- label: person
- zone: steps
- camera_entity: camera.front_Door
+ - camera_entity: camera.front_Door
live_provider: ha
+ frigate:
+ url: http://my.frigate.local
+ client_id: frigate
+ camera_name: front_door
+ label: person
+ zone: steps
# Show events for camera-2 when this camera is viewed.
dependencies:
all_cameras: false
@@ -1056,13 +1073,14 @@ cameras:
occupancy: true
entities:
- binary_sensor.front_door_sensor
- - frigate_url: http://my-other.frigate.local
- client_id: frigate-other
- camera_name: entrance
- label: car
- zone: driveway
- camera_entity: camera.entrance
+ - camera_entity: camera.entrance
live_provider: webrtc-card
+ frigate:
+ url: http://my-other.frigate.local
+ client_id: frigate-other
+ camera_name: entrance
+ label: car
+ zone: driveway
icon: 'mdi:car'
title: 'Front entrance'
# Custom identifier for the camera to refer to it above.
@@ -2383,7 +2401,7 @@ the new overriden default immediately. Alternatives to trigger the card to
change view but without `update_entities` would just be having an
`update_seconds` parameter which reloads the default view that many seconds
after user interaction stops or through the use of the `triggers` option for a
-given camera (see [Trigger Configuration](#camera-triggers)).
+given camera (see [Trigger Configuration](#camera-triggers-configuration)).
```yaml
view:
@@ -2525,7 +2543,8 @@ This example shows events for all other cameras when `birdseye` is selected. Thi
cameras:
- camera_entity: camera.kitchen
- camera_entity: camera.sitting_room
- - camera_name: birdseye
+ - frigate:
+ camera_name: birdseye
dependencies:
all_cameras: true
```
@@ -2569,7 +2588,7 @@ The following table describes the behavior these flags have.
Note that no (other) automated updates are permitted when [scan mode](#scan-mode) is being triggered.
-In the below "Trigger Entities" refers to the combination of `view.update_entities` and the `triggers.entities` for the currently selected camera (which in turn will also include the occupancy and motion sensor entities for Frigate cameras if `triggers.occupancy` and `triggers.motion` options are enabled, see [Trigger Configuration](#camera-triggers)).
+In the below "Trigger Entities" refers to the combination of `view.update_entities` and the `triggers.entities` for the currently selected camera (which in turn will also include the occupancy and motion sensor entities for Frigate cameras if `triggers.occupancy` and `triggers.motion` options are enabled, see [Trigger Configuration](#camera-triggers-configuration)).
| `view . update_seconds` | `view . timeout_seconds` | `view . update_force` | Trigger Entities | Behavior |
| :-: | :-: | :-: | :-: | - |
diff --git a/src/card.ts b/src/card.ts
index e3d8c484..2aca0e41 100644
--- a/src/card.ts
+++ b/src/card.ts
@@ -396,8 +396,8 @@ export class FrigateCard extends LitElement {
// Don't show `clips` button if there's no `camera_name` (e.g. non-Frigate
// cameras), or is birdseye (unless there are dependent cameras).
if (
- cameraConfig?.camera_name &&
- (cameraConfig?.camera_name !== CAMERA_BIRDSEYE ||
+ cameraConfig?.frigate.camera_name &&
+ (cameraConfig?.frigate.camera_name !== CAMERA_BIRDSEYE ||
cameraConfig.dependencies.cameras.length ||
cameraConfig.dependencies.all_cameras)
) {
@@ -415,8 +415,8 @@ export class FrigateCard extends LitElement {
// Don't show `snapshots` button if there's no `camera_name` (e.g. non-Frigate
// cameras), or is birdseye (unless there are dependent cameras).
if (
- cameraConfig?.camera_name &&
- (cameraConfig?.camera_name !== CAMERA_BIRDSEYE ||
+ cameraConfig?.frigate.camera_name &&
+ (cameraConfig?.frigate.camera_name !== CAMERA_BIRDSEYE ||
cameraConfig?.dependencies.cameras.length ||
cameraConfig?.dependencies.all_cameras)
) {
@@ -449,7 +449,8 @@ export class FrigateCard extends LitElement {
if (
this._cameras &&
[...this._cameras.values()].some(
- (config) => config.camera_name && config.camera_name !== CAMERA_BIRDSEYE,
+ (config) =>
+ config.frigate.camera_name && config.frigate.camera_name !== CAMERA_BIRDSEYE,
)
) {
buttons.push({
@@ -475,7 +476,7 @@ export class FrigateCard extends LitElement {
});
}
- if (cameraConfig?.frigate_url) {
+ if (cameraConfig?.frigate.url) {
buttons.push({
icon: 'mdi:web',
...this._getConfig().menu.buttons.frigate_ui,
@@ -598,13 +599,15 @@ export class FrigateCard extends LitElement {
cache: ExtendedEntityCache,
cameraConfig: CameraConfig,
): string | null {
- if (cameraConfig.camera_name) {
+ if (cameraConfig.frigate.camera_name) {
return (
cache.getMatch(
(ent) =>
!!ent.unique_id?.match(
new RegExp(
- `:motion_sensor:${cameraConfig.zone || cameraConfig.camera_name}`,
+ `:motion_sensor:${
+ cameraConfig.frigate.zone || cameraConfig.frigate.camera_name
+ }`,
),
),
)?.entity_id ?? null
@@ -623,15 +626,15 @@ export class FrigateCard extends LitElement {
cache: ExtendedEntityCache,
cameraConfig: CameraConfig,
): string | null {
- if (cameraConfig.camera_name) {
+ if (cameraConfig.frigate.camera_name) {
return (
cache.getMatch(
(ent) =>
!!ent.unique_id?.match(
new RegExp(
- `:occupancy_sensor:${cameraConfig.zone || cameraConfig.camera_name}_${
- cameraConfig.label || 'all'
- }`,
+ `:occupancy_sensor:${
+ cameraConfig.frigate.zone || cameraConfig.frigate.camera_name
+ }_${cameraConfig.frigate.label || 'all'}`,
),
),
)?.entity_id ?? null
@@ -673,10 +676,10 @@ export class FrigateCard extends LitElement {
}
}
- if (!config.camera_name && entity) {
+ if (!config.frigate.camera_name && entity) {
const resolvedName = this._getFrigateCameraNameFromEntity(entity);
if (resolvedName) {
- config.camera_name = resolvedName;
+ config.frigate.camera_name = resolvedName;
}
}
@@ -1146,7 +1149,7 @@ export class FrigateCard extends LitElement {
}
const path =
- `/api/frigate/${cameraConfig.client_id}` +
+ `/api/frigate/${cameraConfig.frigate.client_id}` +
`/notifications/${event_id}/` +
`${this._view.isClipRelatedView() ? 'clip.mp4' : 'snapshot.jpg'}` +
`?download=true`;
@@ -1299,7 +1302,7 @@ export class FrigateCard extends LitElement {
: (this._getConfig().view.camera_select as FrigateCardView);
this._changeView({
view: new View({
- view: this._cameras?.get(camera)?.camera_name
+ view: this._cameras?.get(camera)?.frigate.camera_name
? targetView
: // Fallback to supported views for non-Frigate cameras.
View.selectBestViewForNonFrigateCameras(targetView),
@@ -1368,16 +1371,16 @@ export class FrigateCard extends LitElement {
*/
protected _getFrigateURLFromContext(): string | null {
const cameraConfig = this._getSelectedCameraConfig();
- if (!cameraConfig || !cameraConfig.frigate_url || !this._view) {
+ if (!cameraConfig || !cameraConfig.frigate.url || !this._view) {
return null;
}
- if (!cameraConfig.camera_name) {
- return cameraConfig.frigate_url;
+ if (!cameraConfig.frigate.camera_name) {
+ return cameraConfig.frigate.url;
}
if (this._view.isViewerView() || this._view.isGalleryView()) {
- return `${cameraConfig.frigate_url}/events?camera=${cameraConfig.camera_name}`;
+ return `${cameraConfig.frigate.url}/events?camera=${cameraConfig.frigate.camera_name}`;
}
- return `${cameraConfig.frigate_url}/cameras/${cameraConfig.camera_name}`;
+ return `${cameraConfig.frigate.url}/cameras/${cameraConfig.frigate.camera_name}`;
}
/**
diff --git a/src/components/live.ts b/src/components/live.ts
index 7bc50aa0..b0182eeb 100644
--- a/src/components/live.ts
+++ b/src/components/live.ts
@@ -639,7 +639,7 @@ export class FrigateCardLiveProvider extends LitElement {
return 'webrtc-card';
} else if (this.cameraConfig?.camera_entity) {
return 'ha';
- } else if (this.cameraConfig?.camera_name) {
+ } else if (this.cameraConfig?.frigate.camera_name) {
return 'frigate-jsmpeg';
}
return frigateCardConfigDefaults.cameras.live_provider;
@@ -1013,7 +1013,7 @@ export class FrigateCardLiveJSMPEG extends LitElement {
* @returns A URL or null.
*/
protected async _getURL(): Promise {
- if (!this.hass || !this.cameraConfig?.client_id || !this.cameraConfig?.camera_name) {
+ if (!this.hass || !this.cameraConfig?.frigate.client_id || !this.cameraConfig?.frigate.camera_name) {
return null;
}
@@ -1021,8 +1021,8 @@ export class FrigateCardLiveJSMPEG extends LitElement {
try {
response = await homeAssistantSignPath(
this.hass,
- `/api/frigate/${this.cameraConfig.client_id}` +
- `/jsmpeg/${this.cameraConfig.camera_name}`,
+ `/api/frigate/${this.cameraConfig.frigate.client_id}` +
+ `/jsmpeg/${this.cameraConfig.frigate.camera_name}`,
URL_SIGN_EXPIRY_SECONDS,
);
} catch (err) {
@@ -1131,7 +1131,7 @@ export class FrigateCardLiveJSMPEG extends LitElement {
this._jsmpegCanvasElement = document.createElement('canvas');
this._jsmpegCanvasElement.className = 'media';
- if (!this.cameraConfig?.camera_name) {
+ if (!this.cameraConfig?.frigate.camera_name) {
return dispatchErrorMessageEvent(
this,
localize('error.no_camera_name'),
diff --git a/src/components/menu.ts b/src/components/menu.ts
index a58b07e3..cb1204ef 100644
--- a/src/components/menu.ts
+++ b/src/components/menu.ts
@@ -27,30 +27,11 @@ import {
frigateCardHasAction,
getActionConfigGivenAction
} from '../utils/action.js';
+import { FRIGATE_ICON_SVG_PATH } from '../utils/frigate.js';
import { refreshDynamicStateParameters } from '../utils/ha';
import './submenu.js';
export const FRIGATE_BUTTON_MENU_ICON = 'frigate';
-export const FRIGATE_ICON_FILLED =
- 'm 4.8759466,22.743573 c 0.0866,0.69274 0.811811,1.16359 0.37885,1.27183 ' +
- '-0.43297,0.10824 -2.32718,-3.43665 -2.7601492,-4.95202 -0.4329602,-1.51538 ' +
- '-0.6764993,-3.22017 -0.5682593,-4.19434 0.1082301,-0.97417 5.7097085,-2.48955 ' +
- '5.7097085,-2.89545 0,-0.4059 -1.81304,-0.0271 -1.89422,-0.35178 -0.0812,-0.32472 ' +
- '1.36925,-0.12989 1.75892,-0.64945 0.60885,-0.81181 1.3800713,-0.6765 1.8671505,' +
- '-1.1094696 0.4870902,-0.4329599 1.0824089,-2.0836399 1.1906589,-2.7871996 0.108241,' +
- '-0.70357 -1.0824084,-1.51538 -1.4071389,-2.05658 -0.3247195,-0.54121 0.7035702,' +
- '-0.92005 3.1931099,-1.94834 2.48954,-1.02829 10.39114,-3.30134994 10.49938,' +
- '-3.03074994 0.10824,0.27061 -2.59779,1.40713994 -4.492,2.11069994 -1.89422,0.70357 ' +
- '-4.97909,2.05658 -4.97909,2.43542 0,0.37885 0.16236,0.67651 0.0541,1.54244 -0.10824,' +
- '0.86593 -0.12123,1.2702597 -0.32472,1.8400997 -0.1353,0.37884 -0.2706,1.27183 ' +
- '0,2.0836295 0.21648,0.64945 0.92005,1.13653 1.24477,1.24478 0.2706,0.018 1.01746,' +
- '0.0433 1.8401,0 1.02829,-0.0541 2.48954,0.0541 2.48954,0.32472 0,0.2706 -2.21894,' +
- '0.10824 -2.21894,0.48708 0,0.37885 2.27306,-0.0541 2.21894,0.32473 -0.0541,0.37884 ' +
- '-1.89422,0.21648 -2.86839,0.21648 -0.77933,0 -1.93031,-0.0361 -2.43542,-0.21648 ' +
- 'l -0.10824,0.37884 c -0.18038,0 -0.55744,0.10824 -0.94711,0.10824 -0.48708,0 ' +
- '-0.51414,0.16236 -1.40713,0.16236 -0.892989,0 -0.622391,-0.0541 -1.4341894,-0.10824 ' +
- '-0.81181,-0.0541 -3.842561,2.27306 -4.383761,3.03075 -0.54121,0.75768 ' +
- '-0.21649,2.59778 -0.21649,3.43665 0,0.75379 -0.10824,2.43542 0,3.30135 z';
/**
* A menu for the FrigateCard.
@@ -266,7 +247,7 @@ export class FrigateCardMenu extends LitElement {
let stateParameters: StateParameters = { ...button };
const svgPath =
- stateParameters.icon === FRIGATE_BUTTON_MENU_ICON ? FRIGATE_ICON_FILLED : '';
+ stateParameters.icon === FRIGATE_BUTTON_MENU_ICON ? FRIGATE_ICON_SVG_PATH : '';
if (this.hass && button.type === 'custom:frigate-card-menu-state-icon') {
stateParameters = refreshDynamicStateParameters(this.hass, stateParameters);
diff --git a/src/components/timeline.ts b/src/components/timeline.ts
index f0b4359e..28ff6a07 100644
--- a/src/components/timeline.ts
+++ b/src/components/timeline.ts
@@ -324,12 +324,16 @@ class TimelineDataManager {
camera: string,
config: CameraConfig,
): Promise => {
- if (!config.camera_name) {
+ if (!config.frigate.camera_name) {
return;
}
let summary: RecordingSummary;
try {
- summary = await getRecordingsSummary(hass, config.client_id, config.camera_name);
+ summary = await getRecordingsSummary(
+ hass,
+ config.frigate.client_id,
+ config.frigate.camera_name,
+ );
} catch (e) {
return dispatchFrigateCardErrorEvent(element, e as FrigateCardError);
}
@@ -382,7 +386,7 @@ class TimelineDataManager {
const params: BrowseMediaQueryParameters[] = [];
cameras.forEach((cameraConfig, cameraID) => {
(media === 'all' ? ['clips', 'snapshots'] : [media]).forEach((mediaType) => {
- if (cameraConfig.camera_name !== CAMERA_BIRDSEYE) {
+ if (cameraConfig.frigate.camera_name !== CAMERA_BIRDSEYE) {
const param = getBrowseMediaQueryParameters(hass, cameraID, cameraConfig, {
before: end.getTime() / 1000,
after: start.getTime() / 1000,
@@ -584,10 +588,10 @@ export class FrigateCardTimelineCore extends LitElement {
const processedCameras: Set = new Set();
// Get results in the order the cameras are specified in the configuration.
- for (const camera of (this.cameras?.keys() || [])) {
+ for (const camera of this.cameras?.keys() || []) {
const recording = results.get(camera);
const config = this.cameras?.get(camera);
- if (!recording || !config?.camera_name) {
+ if (!recording || !config?.frigate.camera_name) {
continue;
}
@@ -595,7 +599,7 @@ export class FrigateCardTimelineCore extends LitElement {
// Zones on that same camera do not get separate recordings. The card may
// have multiple instances of the same camera for different zoness, so
// need to enforce uniqueness here.
- const uniqueID = `${config.client_id}/${config.camera_name}`;
+ const uniqueID = `${config.frigate.client_id}/${config.frigate.camera_name}`;
if (processedCameras.has(uniqueID)) {
continue;
}
@@ -616,21 +620,21 @@ export class FrigateCardTimelineCore extends LitElement {
if (!onlyMatchingHour || isMatchingHour) {
children.push(
createVideoChild(
- `${prettifyTitle(config.camera_name)} ${format(
+ `${prettifyTitle(config.frigate.camera_name)} ${format(
hour,
'yyyy-MM-dd HH:mm',
)}`,
generateRecordingIdentifier({
- clientId: config.client_id,
+ clientId: config.frigate.client_id,
year: dayData.day.getFullYear(),
month: dayData.day.getMonth() + 1,
day: dayData.day.getDate(),
hour: hourData.hour,
- cameraName: config.camera_name,
+ cameraName: config.frigate.camera_name,
}),
{
recording: {
- camera: config.camera_name,
+ camera: config.frigate.camera_name,
start_time: getUnixTime(startHour),
end_time: getUnixTime(endHour),
events: hourData.events,
@@ -665,7 +669,7 @@ export class FrigateCardTimelineCore extends LitElement {
const results: Map = new Map();
const fetch = async (camera: string, config?: CameraConfig): Promise => {
- if (!config || !config.camera_name || !this.hass) {
+ if (!config || !config.frigate.camera_name || !this.hass) {
return;
}
@@ -673,12 +677,16 @@ export class FrigateCardTimelineCore extends LitElement {
const cameraResults = await Promise.all([
getRecordingSegments(
this.hass,
- config.client_id,
- config.camera_name,
+ config.frigate.client_id,
+ config.frigate.camera_name,
before,
after,
),
- getRecordingsSummary(this.hass, config.client_id, config.camera_name),
+ getRecordingsSummary(
+ this.hass,
+ config.frigate.client_id,
+ config.frigate.camera_name,
+ ),
]);
results.set(camera, { segments: cameraResults[0], summary: cameraResults[1] });
} catch (e) {}
@@ -879,7 +887,10 @@ export class FrigateCardTimelineCore extends LitElement {
protected _getGroups(): DataGroupCollectionType {
const groups: FrigateCardGroupData[] = [];
this.cameras?.forEach((cameraConfig, camera) => {
- if (cameraConfig.camera_name && cameraConfig.camera_name !== CAMERA_BIRDSEYE) {
+ if (
+ cameraConfig.frigate.camera_name &&
+ cameraConfig.frigate.camera_name !== CAMERA_BIRDSEYE
+ ) {
groups.push({
id: camera,
content: getCameraTitle(this.hass, cameraConfig),
diff --git a/src/config-mgmt.ts b/src/config-mgmt.ts
index 555b9ca6..a4d2b2f7 100644
--- a/src/config-mgmt.ts
+++ b/src/config-mgmt.ts
@@ -2,12 +2,7 @@ import { cloneDeep, get, isEqual, set } from 'lodash-es';
import {
CONF_CAMERAS,
CONF_CAMERAS_ARRAY_CAMERA_ENTITY,
- CONF_CAMERAS_ARRAY_CAMERA_NAME,
- CONF_CAMERAS_ARRAY_CLIENT_ID,
- CONF_CAMERAS_ARRAY_LABEL,
CONF_CAMERAS_ARRAY_LIVE_PROVIDER,
- CONF_CAMERAS_ARRAY_URL,
- CONF_CAMERAS_ARRAY_ZONE,
CONF_IMAGE_URL,
CONF_LIVE_AUTO_UNMUTE,
CONF_LIVE_CONTROLS_NEXT_PREVIOUS_SIZE,
@@ -378,11 +373,11 @@ const upgradeToMultipleCameras = (): ((obj: RawFrigateCardConfig) => boolean) =>
const imports = {
camera_entity: CONF_CAMERAS_ARRAY_CAMERA_ENTITY,
- 'frigate.camera_name': CONF_CAMERAS_ARRAY_CAMERA_NAME,
- 'frigate.client_id': CONF_CAMERAS_ARRAY_CLIENT_ID,
- 'frigate.label': CONF_CAMERAS_ARRAY_LABEL,
- 'frigate.url': CONF_CAMERAS_ARRAY_URL,
- 'frigate.zone': CONF_CAMERAS_ARRAY_ZONE,
+ 'frigate.camera_name': 'cameras.#.camera_name',
+ 'frigate.client_id': 'cameras.#.client_id',
+ 'frigate.label': 'cameras.#.label',
+ 'frigate.url': 'cameras.#.frigate_url',
+ 'frigate.zone': 'cameras.#.zone',
'live.webrtc.entity': `cameras.#.webrtc.entity`,
'live.webrtc.url': `cameras.#.webrtc.url`,
'live.provider': CONF_CAMERAS_ARRAY_LIVE_PROVIDER,
@@ -600,4 +595,9 @@ const UPGRADES = [
typeof val === 'boolean' ? (val ? 'all' : 'never') : undefined,
),
upgradeMoveToWithOverrides('event_viewer', CONF_MEDIA_VIEWER),
+ upgradeArrayValue(CONF_CAMERAS, upgradeMoveTo('camera_name', 'frigate.camera_name')),
+ upgradeArrayValue(CONF_CAMERAS, upgradeMoveTo('client_id', 'frigate.client_id')),
+ upgradeArrayValue(CONF_CAMERAS, upgradeMoveTo('label', 'frigate.label')),
+ upgradeArrayValue(CONF_CAMERAS, upgradeMoveTo('frigate_url', 'frigate.url')),
+ upgradeArrayValue(CONF_CAMERAS, upgradeMoveTo('zone', 'frigate.zone')),
];
diff --git a/src/const.ts b/src/const.ts
index 790e04ce..b34c2ed1 100644
--- a/src/const.ts
+++ b/src/const.ts
@@ -7,11 +7,11 @@ export const TROUBLESHOOTING_URL = `${REPO_URL}#troubleshooting` as const;
export const CONF_CAMERAS = 'cameras' as const;
export const CONF_CAMERAS_ARRAY_CAMERA_ENTITY =
`${CONF_CAMERAS}.#.camera_entity` as const;
-export const CONF_CAMERAS_ARRAY_CAMERA_NAME = `${CONF_CAMERAS}.#.camera_name` as const;
-export const CONF_CAMERAS_ARRAY_CLIENT_ID = `${CONF_CAMERAS}.#.client_id` as const;
-export const CONF_CAMERAS_ARRAY_LABEL = `${CONF_CAMERAS}.#.label` as const;
-export const CONF_CAMERAS_ARRAY_URL = `${CONF_CAMERAS}.#.frigate_url` as const;
-export const CONF_CAMERAS_ARRAY_ZONE = `${CONF_CAMERAS}.#.zone` as const;
+export const CONF_CAMERAS_ARRAY_FRIGATE_CAMERA_NAME = `${CONF_CAMERAS}.#.frigate.camera_name` as const;
+export const CONF_CAMERAS_ARRAY_FRIGATE_CLIENT_ID = `${CONF_CAMERAS}.#.frigate.client_id` as const;
+export const CONF_CAMERAS_ARRAY_FRIGATE_LABEL = `${CONF_CAMERAS}.#.frigate.label` as const;
+export const CONF_CAMERAS_ARRAY_FRIGATE_URL = `${CONF_CAMERAS}.#.frigate.url` as const;
+export const CONF_CAMERAS_ARRAY_FRIGATE_ZONE = `${CONF_CAMERAS}.#.frigate.zone` as const;
export const CONF_CAMERAS_ARRAY_ID = `${CONF_CAMERAS}.#.id` as const;
export const CONF_CAMERAS_ARRAY_TITLE = `${CONF_CAMERAS}.#.title` as const;
export const CONF_CAMERAS_ARRAY_ICON = `${CONF_CAMERAS}.#.icon` as const;
diff --git a/src/editor.ts b/src/editor.ts
index b7798e3e..029139df 100644
--- a/src/editor.ts
+++ b/src/editor.ts
@@ -14,22 +14,22 @@ import {
import {
CONF_CAMERAS,
CONF_CAMERAS_ARRAY_CAMERA_ENTITY,
- CONF_CAMERAS_ARRAY_CAMERA_NAME,
- CONF_CAMERAS_ARRAY_CLIENT_ID,
CONF_CAMERAS_ARRAY_DEPENDENCIES_ALL_CAMERAS,
CONF_CAMERAS_ARRAY_DEPENDENCIES_CAMERAS,
+ CONF_CAMERAS_ARRAY_FRIGATE_CAMERA_NAME,
+ CONF_CAMERAS_ARRAY_FRIGATE_CLIENT_ID,
+ CONF_CAMERAS_ARRAY_FRIGATE_LABEL,
+ CONF_CAMERAS_ARRAY_FRIGATE_URL,
+ CONF_CAMERAS_ARRAY_FRIGATE_ZONE,
CONF_CAMERAS_ARRAY_ICON,
CONF_CAMERAS_ARRAY_ID,
- CONF_CAMERAS_ARRAY_LABEL,
CONF_CAMERAS_ARRAY_LIVE_PROVIDER,
CONF_CAMERAS_ARRAY_TITLE,
CONF_CAMERAS_ARRAY_TRIGGERS_ENTITIES,
CONF_CAMERAS_ARRAY_TRIGGERS_MOTION,
CONF_CAMERAS_ARRAY_TRIGGERS_OCCUPANCY,
- CONF_CAMERAS_ARRAY_URL,
CONF_CAMERAS_ARRAY_WEBRTC_CARD_ENTITY,
CONF_CAMERAS_ARRAY_WEBRTC_CARD_URL,
- CONF_CAMERAS_ARRAY_ZONE,
CONF_DIMENSIONS_ASPECT_RATIO,
CONF_DIMENSIONS_ASPECT_RATIO_MODE,
CONF_EVENT_GALLERY_CONTROLS_THUMBNAILS_SHOW_CONTROLS,
@@ -110,11 +110,13 @@ import {
} from './types.js';
import { arrayMove } from './utils/basic.js';
import { getCameraID, getCameraTitle } from './utils/camera.js';
+import { FRIGATE_ICON_SVG_PATH } from './utils/frigate.js';
import { getEntitiesFromHASS, sideLoadHomeAssistantElements } from './utils/ha';
const MENU_BUTTONS = 'buttons';
const MENU_CAMERAS = 'cameras';
const MENU_CAMERAS_DEPENDENCIES = 'cameras.dependencies';
+const MENU_CAMERAS_FRIGATE = 'cameras.frigate';
const MENU_CAMERAS_TRIGGERS = 'cameras.triggers';
const MENU_CAMERAS_WEBRTC = 'cameras.webrtc';
const MENU_OPTIONS = 'options';
@@ -721,8 +723,11 @@ export class FrigateCardEditor extends LitElement implements LovelaceCardEditor
protected _putInSubmenu(
domain: string,
key: unknown,
- icon: string,
labelPath: string,
+ icon: {
+ name?: string;
+ path?: string;
+ },
template: TemplateResult,
): TemplateResult {
const submenuClasses = {
@@ -737,15 +742,16 @@ export class FrigateCardEditor extends LitElement implements LovelaceCardEditor
.domain=${domain}
.key=${key}
>
-
- ${localize(labelPath)}
-
- ${
- this._expandedMenus[domain] === key
- ? html`${template}
`
- : ''
- }
+ ${icon.name
+ ? html` `
+ : icon.path
+ ? html` `
+ : ``}
+ ${localize(labelPath)}
+ ${this._expandedMenus[domain] === key
+ ? html`${template}
`
+ : ''}
`;
}
@@ -891,52 +897,56 @@ export class FrigateCardEditor extends LitElement implements LovelaceCardEditor
getArrayConfigPath(CONF_CAMERAS_ARRAY_CAMERA_ENTITY, cameraIndex),
'camera',
)}
- ${this._renderStringInput(
- getArrayConfigPath(CONF_CAMERAS_ARRAY_CAMERA_NAME, cameraIndex),
- )}
${this._renderOptionSelector(
getArrayConfigPath(CONF_CAMERAS_ARRAY_LIVE_PROVIDER, cameraIndex),
liveProviders,
)}
- ${this._renderStringInput(
- getArrayConfigPath(CONF_CAMERAS_ARRAY_URL, cameraIndex),
- )}
- ${this._renderStringInput(
- getArrayConfigPath(CONF_CAMERAS_ARRAY_LABEL, cameraIndex),
- )}
- ${this._renderStringInput(
- getArrayConfigPath(CONF_CAMERAS_ARRAY_ZONE, cameraIndex),
- )}
- ${this._renderStringInput(
- getArrayConfigPath(CONF_CAMERAS_ARRAY_CLIENT_ID, cameraIndex),
- )}
${this._renderStringInput(
getArrayConfigPath(CONF_CAMERAS_ARRAY_TITLE, cameraIndex),
)}
- ${this._renderStringInput(
+ ${this._renderIconSelector(
getArrayConfigPath(CONF_CAMERAS_ARRAY_ICON, cameraIndex),
+ {
+ label: localize('config.cameras.icon'),
+ },
)}
${this._renderStringInput(
getArrayConfigPath(CONF_CAMERAS_ARRAY_ID, cameraIndex),
)}
${this._putInSubmenu(
- MENU_CAMERAS_WEBRTC,
+ MENU_CAMERAS_FRIGATE,
cameraIndex,
- 'mdi:webrtc',
- 'config.cameras.webrtc_card.options',
- html`${this._renderEntitySelector(
- getArrayConfigPath(CONF_CAMERAS_ARRAY_WEBRTC_CARD_ENTITY, cameraIndex),
- 'camera',
- )}
- ${this._renderStringInput(
- getArrayConfigPath(CONF_CAMERAS_ARRAY_WEBRTC_CARD_URL, cameraIndex),
- )}`,
+ 'config.cameras.frigate.options',
+ { path: FRIGATE_ICON_SVG_PATH },
+ html`
+ ${this._renderStringInput(
+ getArrayConfigPath(
+ CONF_CAMERAS_ARRAY_FRIGATE_CAMERA_NAME,
+ cameraIndex,
+ ),
+ )}
+ ${this._renderStringInput(
+ getArrayConfigPath(CONF_CAMERAS_ARRAY_FRIGATE_URL, cameraIndex),
+ )}
+ ${this._renderStringInput(
+ getArrayConfigPath(CONF_CAMERAS_ARRAY_FRIGATE_LABEL, cameraIndex),
+ )}
+ ${this._renderStringInput(
+ getArrayConfigPath(CONF_CAMERAS_ARRAY_FRIGATE_ZONE, cameraIndex),
+ )}
+ ${this._renderStringInput(
+ getArrayConfigPath(
+ CONF_CAMERAS_ARRAY_FRIGATE_CLIENT_ID,
+ cameraIndex,
+ ),
+ )}
+ `,
)}
${this._putInSubmenu(
MENU_CAMERAS_DEPENDENCIES,
cameraIndex,
- 'mdi:graph',
'config.cameras.dependencies.options',
+ { name: 'mdi:graph' },
html` ${this._renderSwitch(
getArrayConfigPath(
CONF_CAMERAS_ARRAY_DEPENDENCIES_ALL_CAMERAS,
@@ -958,8 +968,8 @@ export class FrigateCardEditor extends LitElement implements LovelaceCardEditor
${this._putInSubmenu(
MENU_CAMERAS_TRIGGERS,
cameraIndex,
- 'mdi:magnify-scan',
'config.cameras.triggers.options',
+ { name: 'mdi:magnify-scan' },
html` ${this._renderSwitch(
getArrayConfigPath(CONF_CAMERAS_ARRAY_TRIGGERS_OCCUPANCY, cameraIndex),
frigateCardConfigDefaults.cameras.triggers.occupancy,
@@ -976,6 +986,19 @@ export class FrigateCardEditor extends LitElement implements LovelaceCardEditor
},
)}`,
)}
+ ${this._putInSubmenu(
+ MENU_CAMERAS_WEBRTC,
+ cameraIndex,
+ 'config.cameras.webrtc_card.options',
+ { name: 'mdi:webrtc' },
+ html`${this._renderEntitySelector(
+ getArrayConfigPath(CONF_CAMERAS_ARRAY_WEBRTC_CARD_ENTITY, cameraIndex),
+ 'camera',
+ )}
+ ${this._renderStringInput(
+ getArrayConfigPath(CONF_CAMERAS_ARRAY_WEBRTC_CARD_URL, cameraIndex),
+ )}`,
+ )}
`
: ``}
diff --git a/src/localize/languages/en.json b/src/localize/languages/en.json
index 1534c875..d935ba2c 100644
--- a/src/localize/languages/en.json
+++ b/src/localize/languages/en.json
@@ -13,18 +13,22 @@
"config": {
"cameras": {
"camera_entity": "Camera Entity",
- "camera_name": "Frigate camera name (Autodetected from entity)",
- "client_id": "Frigate client id (For >1 Frigate server)",
+ "icon": "Icon for this camera (Autodetected from entity)",
+ "id": "Unique id for this camera in this card",
+ "title": "Title for this camera (Autodetected from entity)",
"dependencies": {
"options": "Dependency Options",
"cameras": "Show events for specific cameras with this camera",
"all_cameras": "Show events for all cameras with this camera"
},
- "id": "Unique id for this camera in this card",
- "label": "Frigate label/object filter",
- "frigate_url": "Frigate server URL",
- "title": "Title for this camera (Autodetected from entity)",
- "icon": "Icon for this camera (Autodetected from entity)",
+ "frigate": {
+ "options": "Frigate Options",
+ "camera_name": "Frigate camera name (Autodetected from entity)",
+ "client_id": "Frigate client id (For >1 Frigate server)",
+ "label": "Frigate label/object filter",
+ "url": "Frigate server URL",
+ "zone": "Frigate zone"
+ },
"live_provider": "Live view provider for this camera",
"live_providers": {
"auto": "Automatic",
@@ -42,8 +46,7 @@
"options": "WebRTC Card Options",
"entity": "WebRTC Card Camera Entity (Not a Frigate camera)",
"url": "WebRTC Card Camera URL"
- },
- "zone": "Frigate zone"
+ }
},
"common": {
"media_action_conditions": {
diff --git a/src/scss/editor.scss b/src/scss/editor.scss
index f7384a63..f861950d 100644
--- a/src/scss/editor.scss
+++ b/src/scss/editor.scss
@@ -62,7 +62,8 @@ div.upgrade span {
color: var(--secondary-text-color, 'black');
}
-.submenu-header ha-icon {
+.submenu-header ha-icon,
+.submenu-header ha-svg-icon {
padding-right: 15px;
}
@@ -78,7 +79,6 @@ div.upgrade span {
width: calc(100% - 10px * 2);
margin: auto;
margin-bottom: 10px;
-
}
.submenu :not(.submenu.selected) {
border: none;
diff --git a/src/types.ts b/src/types.ts
index e1d93d3d..cf0ea7a5 100644
--- a/src/types.ts
+++ b/src/types.ts
@@ -370,8 +370,10 @@ const customSchema = z
* Camera configuration section
*/
export const cameraConfigDefault = {
- client_id: 'frigate' as const,
live_provider: 'auto' as const,
+ frigate: {
+ client_id: 'frigate' as const,
+ },
dependencies: {
all_cameras: false,
cameras: [],
@@ -388,12 +390,6 @@ const webrtcCardCameraConfigSchema = z.object({
});
const cameraConfigSchema = z
.object({
- // No URL validation to allow relative URLs within HA (e.g. Frigate addon).
- frigate_url: z.string().optional(),
- client_id: z.string().default(cameraConfigDefault.client_id),
- camera_name: z.string().optional(),
- label: z.string().optional(),
- zone: z.string().optional(),
camera_entity: z.string().optional(),
live_provider: z.enum(LIVE_PROVIDERS).default(cameraConfigDefault.live_provider),
@@ -405,6 +401,15 @@ const cameraConfigSchema = z
// Optional identifier to separate different camera configurations used in
// this card.
id: z.string().optional(),
+
+ frigate: z.object({
+ // No URL validation to allow relative URLs within HA (e.g. Frigate addon).
+ url: z.string().optional(),
+ client_id: z.string().default(cameraConfigDefault.frigate.client_id),
+ camera_name: z.string().optional(),
+ label: z.string().optional(),
+ zone: z.string().optional(),
+ }).default(cameraConfigDefault.frigate),
// Camera identifiers for WebRTC.
webrtc_card: webrtcCardCameraConfigSchema.optional(),
diff --git a/src/utils/camera.ts b/src/utils/camera.ts
index 72756216..81c5d1ec 100644
--- a/src/utils/camera.ts
+++ b/src/utils/camera.ts
@@ -18,7 +18,10 @@ export function getCameraID(
config.webrtc_card &&
typeof config.webrtc_card['entity'] === 'string' &&
config.webrtc_card['entity']) ||
- (typeof config?.camera_name === 'string' && config.camera_name) ||
+ (typeof config?.frigate === 'object' &&
+ config.frigate &&
+ typeof config?.frigate['camera_name'] === 'string' &&
+ config.frigate['camera_name']) ||
''
);
}
@@ -46,7 +49,12 @@ export function getCameraTitle(
config.webrtc_card &&
typeof config.webrtc_card['entity'] === 'string' &&
config.webrtc_card['entity']) ||
- (typeof config?.camera_name === 'string' ? prettifyTitle(config.camera_name) : '') ||
+ (typeof config?.frigate === 'object' &&
+ config.frigate &&
+ typeof config?.frigate['camera_name'] === 'string' &&
+ config.frigate['camera_name']
+ ? prettifyTitle(config.frigate['camera_name'])
+ : '') ||
(typeof config?.id === 'string' && config.id) ||
''
);
diff --git a/src/utils/frigate.ts b/src/utils/frigate.ts
index 8054605f..0910ab36 100644
--- a/src/utils/frigate.ts
+++ b/src/utils/frigate.ts
@@ -2,6 +2,27 @@ import { z } from 'zod';
import { ExtendedHomeAssistant } from '../types';
import { homeAssistantHTTPRequest } from './ha';
+export const FRIGATE_ICON_SVG_PATH =
+ 'm 4.8759466,22.743573 c 0.0866,0.69274 0.811811,1.16359 0.37885,1.27183 ' +
+ '-0.43297,0.10824 -2.32718,-3.43665 -2.7601492,-4.95202 -0.4329602,-1.51538 ' +
+ '-0.6764993,-3.22017 -0.5682593,-4.19434 0.1082301,-0.97417 5.7097085,-2.48955 ' +
+ '5.7097085,-2.89545 0,-0.4059 -1.81304,-0.0271 -1.89422,-0.35178 -0.0812,-0.32472 ' +
+ '1.36925,-0.12989 1.75892,-0.64945 0.60885,-0.81181 1.3800713,-0.6765 1.8671505,' +
+ '-1.1094696 0.4870902,-0.4329599 1.0824089,-2.0836399 1.1906589,-2.7871996 0.108241,' +
+ '-0.70357 -1.0824084,-1.51538 -1.4071389,-2.05658 -0.3247195,-0.54121 0.7035702,' +
+ '-0.92005 3.1931099,-1.94834 2.48954,-1.02829 10.39114,-3.30134994 10.49938,' +
+ '-3.03074994 0.10824,0.27061 -2.59779,1.40713994 -4.492,2.11069994 -1.89422,0.70357 ' +
+ '-4.97909,2.05658 -4.97909,2.43542 0,0.37885 0.16236,0.67651 0.0541,1.54244 -0.10824,' +
+ '0.86593 -0.12123,1.2702597 -0.32472,1.8400997 -0.1353,0.37884 -0.2706,1.27183 ' +
+ '0,2.0836295 0.21648,0.64945 0.92005,1.13653 1.24477,1.24478 0.2706,0.018 1.01746,' +
+ '0.0433 1.8401,0 1.02829,-0.0541 2.48954,0.0541 2.48954,0.32472 0,0.2706 -2.21894,' +
+ '0.10824 -2.21894,0.48708 0,0.37885 2.27306,-0.0541 2.21894,0.32473 -0.0541,0.37884 ' +
+ '-1.89422,0.21648 -2.86839,0.21648 -0.77933,0 -1.93031,-0.0361 -2.43542,-0.21648 ' +
+ 'l -0.10824,0.37884 c -0.18038,0 -0.55744,0.10824 -0.94711,0.10824 -0.48708,0 ' +
+ '-0.51414,0.16236 -1.40713,0.16236 -0.892989,0 -0.622391,-0.0541 -1.4341894,-0.10824 ' +
+ '-0.81181,-0.0541 -3.842561,2.27306 -4.383761,3.03075 -0.54121,0.75768 ' +
+ '-0.21649,2.59778 -0.21649,3.43665 0,0.75379 -0.10824,2.43542 0,3.30135 z';
+
const recordingSummaryHourSchema = z.object({
hour: z.preprocess((arg) => Number(arg), z.number().min(0).max(23)),
duration: z.number().min(0),
diff --git a/src/utils/ha/browse-media.ts b/src/utils/ha/browse-media.ts
index 95fc561c..4cf9b88c 100644
--- a/src/utils/ha/browse-media.ts
+++ b/src/utils/ha/browse-media.ts
@@ -214,14 +214,14 @@ export const getBrowseMediaQueryParameters = (
cameraConfig?: CameraConfig,
overrides?: Partial,
): BrowseMediaQueryParameters | null => {
- if (!cameraConfig || !cameraConfig.camera_name) {
+ if (!cameraConfig || !cameraConfig.frigate.camera_name) {
return null;
}
return {
- clientId: cameraConfig.client_id,
- cameraName: cameraConfig.camera_name,
- label: cameraConfig.label,
- zone: cameraConfig.zone,
+ clientId: cameraConfig.frigate.client_id,
+ cameraName: cameraConfig.frigate.camera_name,
+ label: cameraConfig.frigate.label,
+ zone: cameraConfig.frigate.zone,
title: getCameraTitle(hass, cameraConfig),
cameraID: cameraID,
...overrides,