From 423bd9fd2bb2496fba45a9ed25aa697402f4c537 Mon Sep 17 00:00:00 2001 From: Dermot Duffy Date: Sun, 26 Sep 2021 20:36:54 -0700 Subject: [PATCH 1/3] Initial attempt to get camera name from entity unique_id. --- rollup.config.js | 2 +- src/card.ts | 164 ++++++++++++++++++++++----------- src/components/gallery.ts | 1 - src/localize/languages/en.json | 3 +- src/scss/card.scss | 8 +- src/scss/message.scss | 6 +- src/types.ts | 50 ++++++---- 7 files changed, 155 insertions(+), 79 deletions(-) diff --git a/rollup.config.js b/rollup.config.js index 30276be4..df6242f4 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -37,7 +37,7 @@ const plugins = [ exclude: 'node_modules/**', }), dev && serve(serveopts), - !dev && terser(), + //!dev && terser(), ]; export default [ diff --git a/src/card.ts b/src/card.ts index 8dfcea6f..9900d6e2 100644 --- a/src/card.ts +++ b/src/card.ts @@ -10,6 +10,7 @@ import { import { customElement, property, query, state } from 'lit/decorators'; import { classMap } from 'lit/directives/class-map.js'; import { styleMap } from 'lit/directives/style-map.js'; +import { until } from 'lit/directives/until'; import { HomeAssistant, LovelaceCardEditor, @@ -19,19 +20,22 @@ import { } from 'custom-card-helpers'; import screenfull from 'screenfull'; -import { MenuButton, frigateCardConfigSchema } from './types'; +import { entitySchema, frigateCardConfigSchema } from './types'; import type { BrowseMediaQueryParameters, + Entity, ExtendedHomeAssistant, FrigateCardConfig, MediaLoadInfo, + MenuButton, } from './types'; import { CARD_VERSION } from './const'; import { FrigateCardMenu } from './components/menu'; import { View } from './view'; -import { getParseErrorKeys } from './common'; +import { getParseErrorKeys, homeAssistantWSRequest } from './common'; import { localize } from './localize/localize'; +import { renderErrorMessage, renderProgressIndicator } from './components/message'; import './editor'; import './components/gallery'; @@ -134,6 +138,10 @@ export class FrigateCard extends LitElement { // Information about the most recently loaded media item. protected _mediaInfo: MediaLoadInfo | null = null; + // The frigate camera name to use (may be manually specified or automatically + // derived). + protected _frigateCameraName: string | null = null; + set hass(hass: HomeAssistant & ExtendedHomeAssistant) { this._hass = hass; this._updateMenu(); @@ -215,6 +223,49 @@ export class FrigateCard extends LitElement { return buttons; } + protected async _getFrigateCameraName(): Promise { + // No camera name specified, apply two heuristics in this order: + // - Get the entity information and pull out the camera name from the unique_id. + // - Apply basic entity name guesswork. + + if (!this._hass || !this.config) { + return null; + } + + // Option 1: Name specified in config -> done! + if (this.config.frigate_camera_name) { + return this.config.frigate_camera_name; + } + + // Option 2: Find entity unique_id in registry. + const request = { + type: 'config/entity_registry/get', + entity_id: this.config.camera_entity, + }; + try { + const entityResult = await homeAssistantWSRequest( + this._hass, + entitySchema, + request, + ); + if (entityResult && entityResult.platform == 'frigate') { + const match = entityResult.unique_id.match(/:camera:(?[^:]+)$/); + if (match && match.groups) { + return match.groups['camera']; + } + } + } catch (e: any) { + // Pass. + } + + // Option 3: Guess from the entity_id. + if (this.config.camera_entity.includes('.')) { + return this.config.camera_entity.split('.', 2)[1]; + } + + return null; + } + // Set the object configuration. public setConfig(inputConfig: FrigateCardConfig): void { if (!inputConfig) { @@ -232,15 +283,6 @@ export class FrigateCard extends LitElement { getLovelace().setEditMode(true); } - if (!config.frigate_camera_name) { - // No camera name specified, so just assume it's the same as the entity name. - if (config.camera_entity.includes('.')) { - config.frigate_camera_name = config.camera_entity.split('.', 2)[1]; - } else { - throw new Error(localize('error.invalid_configuration') + ': camera_entity'); - } - } - this.config = config; this._entitiesToMonitor = [ ...(this.config.entities || []).map((entity) => entity.entity), @@ -318,10 +360,12 @@ export class FrigateCard extends LitElement { if (!this.config.frigate_url) { return null; } - if (this._view.is('live')) { - return `${this.config.frigate_url}/cameras/${this.config.frigate_camera_name}`; + if (!this._frigateCameraName) { + return this.config.frigate_url; + } else if (this._view.is('live')) { + return `${this.config.frigate_url}/cameras/${this._frigateCameraName}`; } - return `${this.config.frigate_url}/events?camera=${this.config.frigate_camera_name}`; + return `${this.config.frigate_url}/events?camera=${this._frigateCameraName}`; } // Record interactions with the card. @@ -352,14 +396,15 @@ export class FrigateCard extends LitElement { `; } - protected _getBrowseMediaQueryParameters(): BrowseMediaQueryParameters { + protected _getBrowseMediaQueryParameters(): BrowseMediaQueryParameters | null { + if (!this._frigateCameraName) { + return null; + } + return { mediaType: this._view.view == 'clips' ? 'clips' : 'snapshots', clientId: this.config.frigate_client_id, - // frigate_camera_name cannot be null, it will be set to a default value - // in setConfig if not specified in the configuration. - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - cameraName: this.config.frigate_camera_name!, + cameraName: this._frigateCameraName, label: this.config.label, zone: this.config.zone, }; @@ -492,46 +537,59 @@ export class FrigateCard extends LitElement { ${this.config.menu_mode == 'above' ? this._renderMenu() : ''}
- ${this._view.is('clips') || this._view.is('snapshots') - ? html` - ` - : ``} - ${this._view.is('clip') || this._view.is('snapshot') - ? html` - ` - : ``} - ${this._view.is('live') - ? html` - ` - : ``} + ${until(this._render(), renderProgressIndicator())}
${this.config.menu_mode != 'above' ? this._renderMenu() : ''} `; } + protected async _render(): Promise { + if (!this._frigateCameraName) { + this._frigateCameraName = await this._getFrigateCameraName(); + } + const mediaQueryParameters = this._getBrowseMediaQueryParameters(); + if (!this._frigateCameraName || !mediaQueryParameters) { + return renderErrorMessage(localize('error.no_frigate_camera_name')); + } + + return html` + ${this._view.is('clips') || this._view.is('snapshots') + ? html` + ` + : ``} + ${this._view.is('clip') || this._view.is('snapshot') + ? html` + ` + : ``} + ${this._view.is('live') + ? html` + ` + : ``} + `; + } + // Show a warning card. private _showWarning(warning: string): TemplateResult { return html` ${warning} `; diff --git a/src/components/gallery.ts b/src/components/gallery.ts index eb4a4ab0..01254b44 100644 --- a/src/components/gallery.ts +++ b/src/components/gallery.ts @@ -91,7 +91,6 @@ export class FrigateCardGallery extends LitElement { width: `calc(${100 / this._columns}% - 1.2px)`, }; - console.info(this.clientWidth); return html`