Add support to add arbitrary entities to menu.
Breaking: No longer treat the motion entity special. It must be configured under `entities` now.
This commit is contained in:
+1
-27
@@ -171,22 +171,6 @@ export class FrigateCardEditor extends LitElement implements LovelaceCardEditor
|
||||
</div>
|
||||
${options.optional.show
|
||||
? html` <div class="values">
|
||||
<paper-dropdown-menu
|
||||
label=${localize('editor.motion_entity')}
|
||||
@value-changed=${this._valueChanged}
|
||||
.configValue=${'motion_entity'}
|
||||
>
|
||||
<paper-listbox
|
||||
slot="dropdown-content"
|
||||
.selected=${binarySensorEntities.indexOf(
|
||||
this._config?.motion_entity || '',
|
||||
)}
|
||||
>
|
||||
${binarySensorEntities.map((entity) => {
|
||||
return html` <paper-item>${entity}</paper-item> `;
|
||||
})}
|
||||
</paper-listbox>
|
||||
</paper-dropdown-menu>
|
||||
<paper-input
|
||||
label=${localize('editor.frigate_camera_name')}
|
||||
.value=${this._config?.frigate_camera_name || ''}
|
||||
@@ -323,17 +307,7 @@ export class FrigateCardEditor extends LitElement implements LovelaceCardEditor
|
||||
@change=${this._valueChanged}
|
||||
></ha-switch>
|
||||
</ha-formfield>
|
||||
<br />
|
||||
<ha-formfield
|
||||
.label=${localize('editor.show_button') + ': ' + localize('menu.motion')}
|
||||
>
|
||||
<ha-switch
|
||||
.checked=${this._config?.menu_buttons?.frigate_ui ?? true}
|
||||
.configValue=${'menu_buttons.motion'}
|
||||
@change=${this._valueChanged}
|
||||
></ha-switch>
|
||||
</ha-formfield>
|
||||
<br /> `
|
||||
<br />`
|
||||
: ''}
|
||||
<div class="option" @click=${this._toggleOption} .option=${'advanced'}>
|
||||
<div class="row">
|
||||
|
||||
+47
-30
@@ -18,9 +18,10 @@ import { classMap } from 'lit-html/directives/class-map.js';
|
||||
|
||||
import {
|
||||
HomeAssistant,
|
||||
fireEvent,
|
||||
LovelaceCardEditor,
|
||||
fireEvent,
|
||||
getLovelace,
|
||||
stateIcon,
|
||||
} from 'custom-card-helpers';
|
||||
|
||||
import './editor';
|
||||
@@ -78,9 +79,9 @@ type FrigateCardMenuCallback = (name: string) => any;
|
||||
function shouldUpdateBasedOnHass(
|
||||
newHass: HomeAssistant | null,
|
||||
oldHass: HomeAssistant | undefined,
|
||||
entities: (string | null | undefined)[],
|
||||
entities: string[] | null,
|
||||
): boolean {
|
||||
if (!newHass) {
|
||||
if (!newHass || !entities) {
|
||||
return false;
|
||||
}
|
||||
if (!entities.length) {
|
||||
@@ -284,9 +285,13 @@ export class FrigateCard extends LitElement {
|
||||
// Whether or not there is an active clip being played.
|
||||
protected _clipPlaying = false;
|
||||
|
||||
@query(FrigateCardMenu.FRIGATE_CARD_MENU_ID)
|
||||
@query(`#${FrigateCardMenu.FRIGATE_CARD_MENU_ID}`)
|
||||
_menu!: FrigateCardMenu | null;
|
||||
|
||||
// A small cache to avoid needing to create a new list of entities every time
|
||||
// a hass update arrives.
|
||||
protected _entitiesToMonitor: string[] | null = null;
|
||||
|
||||
protected _updateMenu(): void {
|
||||
// Manually set hass in the menu. This is to allow the menu to update,
|
||||
// without necessarily re-rendering the entire card (re-rendering interrupts
|
||||
@@ -301,29 +306,44 @@ export class FrigateCard extends LitElement {
|
||||
protected _getMenuButtons(): Map<string, MenuButton> {
|
||||
const buttons: Map<string, MenuButton> = new Map();
|
||||
|
||||
if (this.config.menu_buttons?.frigate) {
|
||||
if (this.config.menu_buttons?.frigate ?? true) {
|
||||
buttons.set('frigate', { description: 'Frigate Menu' });
|
||||
}
|
||||
if (this.config.menu_buttons?.live) {
|
||||
buttons.set('live', { icon: 'mdi:cctv', description: 'View Live' });
|
||||
if (this.config.menu_buttons?.live ?? true) {
|
||||
buttons.set('live', {
|
||||
icon: 'mdi:cctv',
|
||||
description: 'View Live',
|
||||
emphasize: this._view.is('live'),
|
||||
});
|
||||
}
|
||||
if (this.config.menu_buttons?.clips) {
|
||||
buttons.set('clips', { icon: 'mdi:filmstrip', description: 'View Clips' });
|
||||
if (this.config.menu_buttons?.clips ?? true) {
|
||||
buttons.set('clips', {
|
||||
icon: 'mdi:filmstrip',
|
||||
description: 'View Clips',
|
||||
emphasize: this._view.is('clips'),
|
||||
});
|
||||
}
|
||||
if (this.config.menu_buttons?.snapshots) {
|
||||
buttons.set('snapshots', { icon: 'mdi:camera', description: 'View Snapshots' });
|
||||
if (this.config.menu_buttons?.snapshots ?? true) {
|
||||
buttons.set('snapshots', {
|
||||
icon: 'mdi:camera',
|
||||
description: 'View Snapshots',
|
||||
emphasize: this._view.is('snapshots'),
|
||||
});
|
||||
}
|
||||
if (this.config.menu_buttons?.frigate_ui && this.config.frigate_url) {
|
||||
if ((this.config.menu_buttons?.frigate_ui ?? true) && this.config.frigate_url) {
|
||||
buttons.set('frigate_ui', { icon: 'mdi:web', description: 'View Frigate UI' });
|
||||
}
|
||||
if (this.config.menu_buttons?.motion && this._hass && this.config.motion_entity) {
|
||||
const on = this._hass.states[this.config.motion_entity]?.state == 'on';
|
||||
const motionIcon = on ? 'mdi:motion-sensor' : 'mdi:walk';
|
||||
|
||||
buttons.set('motion', {
|
||||
icon: motionIcon,
|
||||
description: 'View Motion Sensor',
|
||||
emphasize: on,
|
||||
const entities = this.config.entities || [];
|
||||
for (let i = 0; this._hass && i < entities.length; i++) {
|
||||
if (!entities[i].show) {
|
||||
continue;
|
||||
}
|
||||
const entity = entities[i].entity;
|
||||
const state = this._hass.states[entity];
|
||||
buttons.set(entity, {
|
||||
description: state.attributes.friendly_name || entity,
|
||||
emphasize: ['on', 'active', 'home'].includes(state.state),
|
||||
icon: entities[i].icon || stateIcon(state),
|
||||
});
|
||||
}
|
||||
return buttons;
|
||||
@@ -374,6 +394,10 @@ export class FrigateCard extends LitElement {
|
||||
}
|
||||
|
||||
this.config = config;
|
||||
this._entitiesToMonitor = [
|
||||
...(this.config.entities || []).map((entity) => entity.entity),
|
||||
this.config.camera_entity,
|
||||
];
|
||||
this._changeView();
|
||||
}
|
||||
|
||||
@@ -407,10 +431,7 @@ export class FrigateCard extends LitElement {
|
||||
if (this._interactionTimerID || this._clipPlaying) {
|
||||
return false;
|
||||
}
|
||||
return shouldUpdateBasedOnHass(this._hass, oldHass, [
|
||||
this.config.camera_entity,
|
||||
this.config.motion_entity,
|
||||
]);
|
||||
return shouldUpdateBasedOnHass(this._hass, oldHass, this._entitiesToMonitor);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -623,13 +644,9 @@ export class FrigateCard extends LitElement {
|
||||
window.open(frigate_url);
|
||||
}
|
||||
break;
|
||||
case 'motion':
|
||||
if (this.config.motion_entity) {
|
||||
fireEvent(this, 'hass-more-info', { entityId: this.config.motion_entity });
|
||||
}
|
||||
break;
|
||||
default:
|
||||
console.warn('Unknown Frigate card menu option.');
|
||||
// If it's unknown, it's assumed to be an entity_id.
|
||||
fireEvent(this, 'hass-more-info', { entityId: name });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
"advanced": "Advanced",
|
||||
"advanced_secondary": "Advanced options",
|
||||
"camera_entity": "Camera Entity (Required)",
|
||||
"motion_entity": "Motion Entity (Optional)",
|
||||
"frigate_camera_name": "Frigate camera name (Optional)",
|
||||
"default_view": "Default view (Optional)",
|
||||
"frigate_client_id": "Frigate client id (Optional, for >1 Frigate server)",
|
||||
@@ -38,8 +37,7 @@
|
||||
"snapshots": "Snapshots Gallery",
|
||||
"clip": "Latest Clip",
|
||||
"snapshot": "Latest Snapshot",
|
||||
"frigate_ui": "Frigate User Interface",
|
||||
"motion": "Motion Entity"
|
||||
"frigate_ui": "Frigate User Interface"
|
||||
},
|
||||
"menu_mode": {
|
||||
"hidden-top": "Hidden Top",
|
||||
|
||||
+5
-9
@@ -41,7 +41,6 @@ export type FrigateMenuMode = typeof FRIGATE_MENU_MODES[number];
|
||||
|
||||
export const frigateCardConfigSchema = z.object({
|
||||
camera_entity: z.string(),
|
||||
motion_entity: z.string().optional(),
|
||||
// No URL validation to allow relative URLs within HA (e.g. addons).
|
||||
frigate_url: z.string().optional(),
|
||||
frigate_client_id: z.string().optional().default("frigate"),
|
||||
@@ -68,15 +67,12 @@ export const frigateCardConfigSchema = z.object({
|
||||
clips: z.boolean().default(true),
|
||||
snapshots: z.boolean().default(true),
|
||||
frigate_ui: z.boolean().default(true),
|
||||
motion: z.boolean().default(true),
|
||||
}).default({
|
||||
frigate: true,
|
||||
live: true,
|
||||
clips: true,
|
||||
snapshots: true,
|
||||
frigate_ui: true,
|
||||
motion: true,
|
||||
}),
|
||||
entities: z.object({
|
||||
entity: z.string(),
|
||||
show: z.boolean().default(true),
|
||||
icon: z.string().optional(),
|
||||
}).array().optional(),
|
||||
|
||||
// Stock lovelace card config.
|
||||
type: z.string(),
|
||||
|
||||
Reference in New Issue
Block a user