Show stock image for unavailable entities.
This commit is contained in:
+47
-32
@@ -1,4 +1,5 @@
|
|||||||
import { HomeAssistant } from 'custom-card-helpers';
|
import { HomeAssistant } from 'custom-card-helpers';
|
||||||
|
import { HassEntity } from 'home-assistant-js-websocket';
|
||||||
import {
|
import {
|
||||||
CSSResultGroup,
|
CSSResultGroup,
|
||||||
html,
|
html,
|
||||||
@@ -45,8 +46,11 @@ export class FrigateCardImage extends LitElement {
|
|||||||
* Get the camera entity for the current camera configuration.
|
* Get the camera entity for the current camera configuration.
|
||||||
* @returns The entity or undefined if no camera entity is available.
|
* @returns The entity or undefined if no camera entity is available.
|
||||||
*/
|
*/
|
||||||
protected _getCameraEntity(): string | undefined {
|
protected _getCameraEntity(): string | null {
|
||||||
return this.cameraConfig?.camera_entity || this.cameraConfig?.webrtc_card?.entity;
|
return (
|
||||||
|
(this.cameraConfig?.camera_entity || this.cameraConfig?.webrtc_card?.entity) ??
|
||||||
|
null
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -59,23 +63,7 @@ export class FrigateCardImage extends LitElement {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If camera mode is enabled, reject all updates if hass is older than
|
|
||||||
// HASS_REJECTION_CUTOFF_MS or if HASS is not currently connected. By using
|
|
||||||
// an older hass (even if it is not the property being updated), we run the
|
|
||||||
// risk that the JS has an old access token for the camera, and that results
|
|
||||||
// in a notification on the HA UI about a failed login. See
|
|
||||||
// https://github.com/dermotduffy/frigate-hass-card/issues/398 .
|
|
||||||
const cameraEntity = this._getCameraEntity();
|
const cameraEntity = this._getCameraEntity();
|
||||||
const state = cameraEntity ? this.hass.states[cameraEntity] : undefined;
|
|
||||||
if (
|
|
||||||
this.imageConfig?.mode === 'camera' &&
|
|
||||||
(!this.hass.connected ||
|
|
||||||
!state ||
|
|
||||||
Date.now() - Date.parse(state.last_updated) >= HASS_REJECTION_CUTOFF_MS)
|
|
||||||
) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
if (
|
||||||
changedProps.has('hass') &&
|
changedProps.has('hass') &&
|
||||||
changedProps.size == 1 &&
|
changedProps.size == 1 &&
|
||||||
@@ -113,8 +101,16 @@ export class FrigateCardImage extends LitElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the camera changed, immediately discard the old value.
|
// If the camera or view changed, immediately discard the old value (view to
|
||||||
if (changedProps.has('cameraConfig')) {
|
// allow pressing of the image button to fetch a fresh image). Likewise, if
|
||||||
|
// the state is not acceptable, discard the old value (to allow a stock or
|
||||||
|
// backup image to be displayed).
|
||||||
|
if (
|
||||||
|
changedProps.has('cameraConfig') ||
|
||||||
|
changedProps.has('view') ||
|
||||||
|
(this.imageConfig?.mode === 'camera' &&
|
||||||
|
!this._getAcceptableState(this._getCameraEntity()))
|
||||||
|
) {
|
||||||
this._cachedValueController?.clearValue();
|
this._cachedValueController?.clearValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -123,6 +119,26 @@ export class FrigateCardImage extends LitElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine if a given entity is acceptable as the basis for an image render
|
||||||
|
* (detects old or disconnected states). Using an old state is problematic as
|
||||||
|
* it runs the risk that the JS has an old access token for the camera, and
|
||||||
|
* that results in a notification on the HA UI about a failed login. See:
|
||||||
|
* https://github.com/dermotduffy/frigate-hass-card/issues/398 .
|
||||||
|
* @param entity The entity.
|
||||||
|
* @returns The state or null if not acceptable.
|
||||||
|
*/
|
||||||
|
protected _getAcceptableState(entity: string | null): HassEntity | null {
|
||||||
|
const state = (entity ? this.hass?.states[entity] : null) ?? null;
|
||||||
|
|
||||||
|
return !!this.hass &&
|
||||||
|
this.hass.connected &&
|
||||||
|
!!state &&
|
||||||
|
Date.now() - Date.parse(state.last_updated) < HASS_REJECTION_CUTOFF_MS
|
||||||
|
? state
|
||||||
|
: null;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Component connected callback.
|
* Component connected callback.
|
||||||
*/
|
*/
|
||||||
@@ -177,17 +193,15 @@ export class FrigateCardImage extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected _getImageSource(): string {
|
protected _getImageSource(): string {
|
||||||
if (this.imageConfig?.mode === 'url' && this.imageConfig?.url) {
|
if (this.hass && this.imageConfig?.mode === 'camera') {
|
||||||
return this._buildImageURL(this.imageConfig.url);
|
const state = this._getAcceptableState(this._getCameraEntity());
|
||||||
} else if (this.hass && this.imageConfig?.mode === 'camera') {
|
if (state?.attributes.entity_picture) {
|
||||||
const entity = this._getCameraEntity();
|
return this._buildImageURL(state.attributes.entity_picture);
|
||||||
if (entity) {
|
|
||||||
const state = this.hass.states[entity];
|
|
||||||
if (state && state.attributes.entity_picture) {
|
|
||||||
return this._buildImageURL(state.attributes.entity_picture);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (this.imageConfig?.mode !== 'screensaver' && this.imageConfig?.url) {
|
||||||
|
return this._buildImageURL(this.imageConfig.url);
|
||||||
|
}
|
||||||
return defaultImage;
|
return defaultImage;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -196,7 +210,8 @@ export class FrigateCardImage extends LitElement {
|
|||||||
*/
|
*/
|
||||||
protected _forceSafeImage(stockOnly?: boolean): void {
|
protected _forceSafeImage(stockOnly?: boolean): void {
|
||||||
if (this._refImage.value) {
|
if (this._refImage.value) {
|
||||||
this._refImage.value.src = (!stockOnly && this.imageConfig?.url) ? this.imageConfig.url : defaultImage;
|
this._refImage.value.src =
|
||||||
|
!stockOnly && this.imageConfig?.url ? this.imageConfig.url : defaultImage;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -214,8 +229,8 @@ export class FrigateCardImage extends LitElement {
|
|||||||
// In camera mode, the user has likely not made an error, but HA
|
// In camera mode, the user has likely not made an error, but HA
|
||||||
// may be unavailble, so show the stock image. Don't let the URL
|
// may be unavailble, so show the stock image. Don't let the URL
|
||||||
// override the stock image in this case, as this could create an
|
// override the stock image in this case, as this could create an
|
||||||
// error loop.
|
// error loop if that URL subsequently failed to load.
|
||||||
this._forceSafeImage(true)
|
this._forceSafeImage(true);
|
||||||
} else if (this.imageConfig?.mode === 'url') {
|
} else if (this.imageConfig?.mode === 'url') {
|
||||||
// In url mode, the user likely specified a URL that cannot be
|
// In url mode, the user likely specified a URL that cannot be
|
||||||
// resolved. Show an error message.
|
// resolved. Show an error message.
|
||||||
|
|||||||
Reference in New Issue
Block a user