Add event starring from the card.
This commit is contained in:
Vendored
+7
@@ -1,3 +1,10 @@
|
|||||||
# Review comments generated by i18n-ally. Please commit this file.
|
# Review comments generated by i18n-ally. Please commit this file.
|
||||||
|
|
||||||
reviews:
|
reviews:
|
||||||
|
error.failed_retain:
|
||||||
|
locales:
|
||||||
|
pt-BR:
|
||||||
|
translation_candidate:
|
||||||
|
source: en
|
||||||
|
text: Não foi possível reter o evento
|
||||||
|
time: '2022-06-28T05:18:48.431Z'
|
||||||
|
|||||||
@@ -1042,6 +1042,13 @@ A dashboard with the card can be cast onto a suitable device (such as the Nest H
|
|||||||
|
|
||||||
<img src="https://raw.githubusercontent.com/dermotduffy/frigate-hass-card/release-4.0.0/images/card-on-nest-hub.jpg" alt="Card on Nest Hub" width="400px">
|
<img src="https://raw.githubusercontent.com/dermotduffy/frigate-hass-card/release-4.0.0/images/card-on-nest-hub.jpg" alt="Card on Nest Hub" width="400px">
|
||||||
|
|
||||||
|
### Event starring
|
||||||
|
|
||||||
|
Retain interesting Frigate events forever:
|
||||||
|
|
||||||
|
<img src="https://raw.githubusercontent.com/dermotduffy/frigate-hass-card/release-4.0.0/images/star.gif" alt="Retain events" width="400px">
|
||||||
|
|
||||||
|
|
||||||
## Examples
|
## Examples
|
||||||
|
|
||||||
### Illustrative Expanded Configuration Reference
|
### Illustrative Expanded Configuration Reference
|
||||||
|
|||||||
Binary file not shown.
|
After Width: | Height: | Size: 321 KiB |
@@ -86,6 +86,7 @@ export class FrigateCardGallery extends LitElement {
|
|||||||
.hass=${this.hass}
|
.hass=${this.hass}
|
||||||
.view=${this.view}
|
.view=${this.view}
|
||||||
.galleryConfig=${this.galleryConfig}
|
.galleryConfig=${this.galleryConfig}
|
||||||
|
.cameras=${this.cameras}
|
||||||
>
|
>
|
||||||
</frigate-card-gallery-core>
|
</frigate-card-gallery-core>
|
||||||
`;
|
`;
|
||||||
@@ -116,6 +117,9 @@ export class FrigateCardGalleryCore extends LitElement {
|
|||||||
@property({ attribute: false })
|
@property({ attribute: false })
|
||||||
public galleryConfig?: GalleryConfig;
|
public galleryConfig?: GalleryConfig;
|
||||||
|
|
||||||
|
@property({ attribute: false })
|
||||||
|
public cameras?: Map<string, CameraConfig>;
|
||||||
|
|
||||||
protected _resizeObserver: ResizeObserver;
|
protected _resizeObserver: ResizeObserver;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
@@ -207,11 +211,13 @@ export class FrigateCardGalleryCore extends LitElement {
|
|||||||
!this.view ||
|
!this.view ||
|
||||||
!this.view.target ||
|
!this.view.target ||
|
||||||
!this.view.target.children ||
|
!this.view.target.children ||
|
||||||
!(this.view.is('clips') || this.view.is('snapshots'))
|
!(this.view.is('clips') || this.view.is('snapshots')) ||
|
||||||
|
!this.cameras
|
||||||
) {
|
) {
|
||||||
return html``;
|
return html``;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const cameraConfig = this.cameras.get(this.view.camera);
|
||||||
return html`
|
return html`
|
||||||
${this._showBackArrow()
|
${this._showBackArrow()
|
||||||
? html` <ha-card
|
? html` <ha-card
|
||||||
@@ -253,6 +259,8 @@ export class FrigateCardGalleryCore extends LitElement {
|
|||||||
.view=${this.view}
|
.view=${this.view}
|
||||||
.target=${this.view?.target ?? null}
|
.target=${this.view?.target ?? null}
|
||||||
.childIndex=${index}
|
.childIndex=${index}
|
||||||
|
.hass=${this.hass}
|
||||||
|
.clientID=${cameraConfig?.frigate.client_id}
|
||||||
?details=${!!this.galleryConfig?.controls.thumbnails.show_details}
|
?details=${!!this.galleryConfig?.controls.thumbnails.show_details}
|
||||||
?controls=${!!this.galleryConfig?.controls.thumbnails.show_controls}
|
?controls=${!!this.galleryConfig?.controls.thumbnails.show_controls}
|
||||||
@click=${(ev: Event) => {
|
@click=${(ev: Event) => {
|
||||||
|
|||||||
@@ -146,6 +146,7 @@ export class FrigateCardLive extends LitElement {
|
|||||||
.view=${this.view}
|
.view=${this.view}
|
||||||
.config=${config.controls.thumbnails}
|
.config=${config.controls.thumbnails}
|
||||||
.browseMediaParams=${browseMediaParams ?? undefined}
|
.browseMediaParams=${browseMediaParams ?? undefined}
|
||||||
|
.cameras=${this.cameras}
|
||||||
?fetch=${!this._preloaded}
|
?fetch=${!this._preloaded}
|
||||||
>
|
>
|
||||||
<frigate-card-live-carousel
|
<frigate-card-live-carousel
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import { customElement, property } from 'lit/decorators.js';
|
|||||||
import surroundThumbnailsStyle from '../scss/surround.scss';
|
import surroundThumbnailsStyle from '../scss/surround.scss';
|
||||||
import {
|
import {
|
||||||
BrowseMediaQueryParameters,
|
BrowseMediaQueryParameters,
|
||||||
|
CameraConfig,
|
||||||
FrigateBrowseMediaSource,
|
FrigateBrowseMediaSource,
|
||||||
FrigateCardError,
|
FrigateCardError,
|
||||||
FrigateCardView,
|
FrigateCardView,
|
||||||
@@ -46,6 +47,9 @@ export class FrigateCardSurround extends LitElement {
|
|||||||
@property({ attribute: false, hasChanged: contentsChanged })
|
@property({ attribute: false, hasChanged: contentsChanged })
|
||||||
public browseMediaParams?: BrowseMediaQueryParameters | BrowseMediaQueryParameters[];
|
public browseMediaParams?: BrowseMediaQueryParameters | BrowseMediaQueryParameters[];
|
||||||
|
|
||||||
|
@property({ attribute: false })
|
||||||
|
public cameras?: Map<string, CameraConfig>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fetch thumbnail media when a target is not specified in the view (e.g. for
|
* Fetch thumbnail media when a target is not specified in the view (e.g. for
|
||||||
* the live view).
|
* the live view).
|
||||||
@@ -137,10 +141,12 @@ export class FrigateCardSurround extends LitElement {
|
|||||||
${this.config && this.config.mode !== 'none'
|
${this.config && this.config.mode !== 'none'
|
||||||
? html` <frigate-card-thumbnail-carousel
|
? html` <frigate-card-thumbnail-carousel
|
||||||
slot=${this.config.mode}
|
slot=${this.config.mode}
|
||||||
|
.hass=${this.hass}
|
||||||
.config=${this.config}
|
.config=${this.config}
|
||||||
.view=${this.view}
|
.view=${this.view}
|
||||||
.target=${this.view.target}
|
.target=${this.view.target}
|
||||||
.selected=${this.view.childIndex}
|
.selected=${this.view.childIndex}
|
||||||
|
.cameras=${this.cameras}
|
||||||
@frigate-card:change-view=${(ev: CustomEvent) => changeDrawer(ev, 'close')}
|
@frigate-card:change-view=${(ev: CustomEvent) => changeDrawer(ev, 'close')}
|
||||||
@frigate-card:carousel:tap=${(ev: CustomEvent<ThumbnailCarouselTap>) => {
|
@frigate-card:carousel:tap=${(ev: CustomEvent<ThumbnailCarouselTap>) => {
|
||||||
// Send the view change from the source of the tap event, so the
|
// Send the view change from the source of the tap event, so the
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
|
import { HomeAssistant } from 'custom-card-helpers';
|
||||||
import { EmblaOptionsType, EmblaPluginType } from 'embla-carousel';
|
import { EmblaOptionsType, EmblaPluginType } from 'embla-carousel';
|
||||||
import { WheelGesturesPlugin } from 'embla-carousel-wheel-gestures';
|
import { WheelGesturesPlugin } from 'embla-carousel-wheel-gestures';
|
||||||
import { CSSResultGroup, html, PropertyValues, TemplateResult, unsafeCSS } from 'lit';
|
import { CSSResultGroup, html, PropertyValues, TemplateResult, unsafeCSS } from 'lit';
|
||||||
import { customElement, property, state } from 'lit/decorators.js';
|
import { customElement, property, state } from 'lit/decorators.js';
|
||||||
import { classMap } from 'lit/directives/class-map.js';
|
import { classMap } from 'lit/directives/class-map.js';
|
||||||
import thumbnailCarouselStyle from '../scss/thumbnail-carousel.scss';
|
import thumbnailCarouselStyle from '../scss/thumbnail-carousel.scss';
|
||||||
import type { FrigateBrowseMediaSource, ThumbnailsControlConfig } from '../types.js';
|
import type { CameraConfig, FrigateBrowseMediaSource, ThumbnailsControlConfig } from '../types.js';
|
||||||
import { stopEventFromActivatingCardWideActions } from '../utils/action.js';
|
import { stopEventFromActivatingCardWideActions } from '../utils/action.js';
|
||||||
import { contentsChanged, dispatchFrigateCardEvent } from '../utils/basic.js';
|
import { contentsChanged, dispatchFrigateCardEvent } from '../utils/basic.js';
|
||||||
import { isTrueMedia } from '../utils/ha/browse-media';
|
import { isTrueMedia } from '../utils/ha/browse-media';
|
||||||
@@ -20,6 +21,9 @@ export interface ThumbnailCarouselTap {
|
|||||||
|
|
||||||
@customElement('frigate-card-thumbnail-carousel')
|
@customElement('frigate-card-thumbnail-carousel')
|
||||||
export class FrigateCardThumbnailCarousel extends FrigateCardCarousel {
|
export class FrigateCardThumbnailCarousel extends FrigateCardCarousel {
|
||||||
|
@property({ attribute: false })
|
||||||
|
public hass?: HomeAssistant;
|
||||||
|
|
||||||
@property({ attribute: false })
|
@property({ attribute: false })
|
||||||
public view?: Readonly<View>;
|
public view?: Readonly<View>;
|
||||||
|
|
||||||
@@ -28,6 +32,9 @@ export class FrigateCardThumbnailCarousel extends FrigateCardCarousel {
|
|||||||
@property({ attribute: false, hasChanged: contentsChanged })
|
@property({ attribute: false, hasChanged: contentsChanged })
|
||||||
public target?: FrigateBrowseMediaSource | null;
|
public target?: FrigateBrowseMediaSource | null;
|
||||||
|
|
||||||
|
@property({ attribute: false })
|
||||||
|
public cameras?: Map<string, CameraConfig>;
|
||||||
|
|
||||||
// Thumbnail carousels can expand (e.g. drawer-based carousels after the main
|
// Thumbnail carousels can expand (e.g. drawer-based carousels after the main
|
||||||
// media loads). The carousel must be re-initialized in these cases, or the
|
// media loads). The carousel must be re-initialized in these cases, or the
|
||||||
// dynamic sizing fails (and users can scroll past the end of the carousel).
|
// dynamic sizing fails (and users can scroll past the end of the carousel).
|
||||||
@@ -195,10 +202,13 @@ export class FrigateCardThumbnailCarousel extends FrigateCardCarousel {
|
|||||||
'slide-selected': this._selected === childIndex,
|
'slide-selected': this._selected === childIndex,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const cameraConfig = this.view?.camera ? this.cameras?.get(this.view.camera) : null;
|
||||||
return html` <frigate-card-thumbnail
|
return html` <frigate-card-thumbnail
|
||||||
|
.hass=${this.hass}
|
||||||
.view=${this.view}
|
.view=${this.view}
|
||||||
.target=${parent}
|
.target=${parent}
|
||||||
.childIndex=${childIndex}
|
.childIndex=${childIndex}
|
||||||
|
.clientID=${cameraConfig?.frigate.client_id}
|
||||||
?details=${this._config?.show_details}
|
?details=${this._config?.show_details}
|
||||||
?controls=${this._config?.show_controls}
|
?controls=${this._config?.show_controls}
|
||||||
class="${classMap(classes)}"
|
class="${classMap(classes)}"
|
||||||
|
|||||||
+47
-10
@@ -1,6 +1,8 @@
|
|||||||
|
import { HomeAssistant } from 'custom-card-helpers';
|
||||||
import { format, fromUnixTime } from 'date-fns';
|
import { format, fromUnixTime } from 'date-fns';
|
||||||
import { CSSResult, html, LitElement, TemplateResult, unsafeCSS } from 'lit';
|
import { CSSResult, html, LitElement, TemplateResult, unsafeCSS } from 'lit';
|
||||||
import { customElement, property } from 'lit/decorators.js';
|
import { customElement, property } from 'lit/decorators.js';
|
||||||
|
import { classMap } from 'lit/directives/class-map.js';
|
||||||
import { localize } from '../localize/localize.js';
|
import { localize } from '../localize/localize.js';
|
||||||
import thumbnailDetailsStyle from '../scss/thumbnail-details.scss';
|
import thumbnailDetailsStyle from '../scss/thumbnail-details.scss';
|
||||||
import thumbnailFeatureEventStyle from '../scss/thumbnail-feature-event.scss';
|
import thumbnailFeatureEventStyle from '../scss/thumbnail-feature-event.scss';
|
||||||
@@ -9,10 +11,11 @@ import thumbnailStyle from '../scss/thumbnail.scss';
|
|||||||
import type {
|
import type {
|
||||||
FrigateBrowseMediaSource,
|
FrigateBrowseMediaSource,
|
||||||
FrigateEvent,
|
FrigateEvent,
|
||||||
FrigateRecording
|
FrigateRecording,
|
||||||
} from '../types.js';
|
} from '../types.js';
|
||||||
import { stopEventFromActivatingCardWideActions } from '../utils/action.js';
|
import { stopEventFromActivatingCardWideActions } from '../utils/action.js';
|
||||||
import { prettifyTitle } from '../utils/basic.js';
|
import { errorToConsole, prettifyTitle } from '../utils/basic.js';
|
||||||
|
import { retainEvent } from '../utils/frigate.js';
|
||||||
import { getEventDurationString } from '../utils/ha/browse-media.js';
|
import { getEventDurationString } from '../utils/ha/browse-media.js';
|
||||||
import { View } from '../view.js';
|
import { View } from '../view.js';
|
||||||
|
|
||||||
@@ -152,6 +155,15 @@ export class FrigateCardThumbnail extends LitElement {
|
|||||||
@property({ attribute: true })
|
@property({ attribute: true })
|
||||||
public event?: string;
|
public event?: string;
|
||||||
|
|
||||||
|
// ================================
|
||||||
|
// Optional parameters for controls
|
||||||
|
// ================================
|
||||||
|
@property({ attribute: false })
|
||||||
|
public hass?: HomeAssistant;
|
||||||
|
|
||||||
|
@property({ attribute: false })
|
||||||
|
public clientID?: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Render the element.
|
* Render the element.
|
||||||
* @returns A template to display to the user.
|
* @returns A template to display to the user.
|
||||||
@@ -182,6 +194,11 @@ export class FrigateCardThumbnail extends LitElement {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const starClasses = {
|
||||||
|
star: true,
|
||||||
|
starred: !!event?.retain_indefinitely,
|
||||||
|
};
|
||||||
|
|
||||||
return html` ${event
|
return html` ${event
|
||||||
? html`<frigate-card-thumbnail-feature-event
|
? html`<frigate-card-thumbnail-feature-event
|
||||||
aria-label="${label ?? ''}"
|
aria-label="${label ?? ''}"
|
||||||
@@ -194,11 +211,31 @@ export class FrigateCardThumbnail extends LitElement {
|
|||||||
title="${label ?? ''}"
|
title="${label ?? ''}"
|
||||||
.date=${recording ? fromUnixTime(recording.start_time) : undefined}
|
.date=${recording ? fromUnixTime(recording.start_time) : undefined}
|
||||||
></frigate-card-thumbnail-feature-recording>`}
|
></frigate-card-thumbnail-feature-recording>`}
|
||||||
${this.controls && event?.retain_indefinitely
|
${this.controls && this.hass && this.clientID
|
||||||
? html` <ha-icon
|
? html` <ha-icon
|
||||||
class="favorite"
|
class="${classMap(starClasses)}"
|
||||||
icon="mdi:star"
|
icon=${event?.retain_indefinitely ? 'mdi:star' : 'mdi:star-outline'}
|
||||||
title=${localize('thumbnail.retain_indefinitely')}
|
title=${localize('thumbnail.retain_indefinitely')}
|
||||||
|
@click=${(ev: Event) => {
|
||||||
|
stopEventFromActivatingCardWideActions(ev);
|
||||||
|
if (event && this.hass && this.clientID) {
|
||||||
|
retainEvent(
|
||||||
|
this.hass,
|
||||||
|
this.clientID,
|
||||||
|
event.id,
|
||||||
|
!event.retain_indefinitely,
|
||||||
|
)
|
||||||
|
.then(() => {
|
||||||
|
if (event) {
|
||||||
|
event.retain_indefinitely = !event.retain_indefinitely;
|
||||||
|
this.requestUpdate();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch((e) => {
|
||||||
|
errorToConsole(e);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}}
|
||||||
/></ha-icon>`
|
/></ha-icon>`
|
||||||
: ``}
|
: ``}
|
||||||
${this.details && event
|
${this.details && event
|
||||||
@@ -256,10 +293,10 @@ export class FrigateCardThumbnail extends LitElement {
|
|||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
interface HTMLElementTagNameMap {
|
interface HTMLElementTagNameMap {
|
||||||
"frigate-card-thumbnail": FrigateCardThumbnail
|
'frigate-card-thumbnail': FrigateCardThumbnail;
|
||||||
"frigate-card-thumbnail-details-recording": FrigateCardThumbnailDetailsRecording
|
'frigate-card-thumbnail-details-recording': FrigateCardThumbnailDetailsRecording;
|
||||||
"frigate-card-thumbnail-details-event": FrigateCardThumbnailDetailsEvent
|
'frigate-card-thumbnail-details-event': FrigateCardThumbnailDetailsEvent;
|
||||||
"frigate-card-thumbnail-feature-recording": FrigateCardThumbnailFeatureRecording
|
'frigate-card-thumbnail-feature-recording': FrigateCardThumbnailFeatureRecording;
|
||||||
"frigate-card-thumbnail-feature-event": FrigateCardThumbnailFeatureEvent
|
'frigate-card-thumbnail-feature-event': FrigateCardThumbnailFeatureEvent;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -450,6 +450,7 @@ export class FrigateCardTimeline extends LitElement {
|
|||||||
.hass=${this.hass}
|
.hass=${this.hass}
|
||||||
.view=${this.view}
|
.view=${this.view}
|
||||||
.config=${this.timelineConfig.controls.thumbnails}
|
.config=${this.timelineConfig.controls.thumbnails}
|
||||||
|
.cameras=${this.cameras}
|
||||||
>
|
>
|
||||||
<frigate-card-timeline-core
|
<frigate-card-timeline-core
|
||||||
.hass=${this.hass}
|
.hass=${this.hass}
|
||||||
|
|||||||
@@ -109,6 +109,7 @@ export class FrigateCardViewer extends LitElement {
|
|||||||
.hass=${this.hass}
|
.hass=${this.hass}
|
||||||
.view=${this.view}
|
.view=${this.view}
|
||||||
.config=${this.viewerConfig.controls.thumbnails}
|
.config=${this.viewerConfig.controls.thumbnails}
|
||||||
|
.cameras=${this.cameras}
|
||||||
>
|
>
|
||||||
<frigate-card-viewer-carousel
|
<frigate-card-viewer-carousel
|
||||||
.hass=${this.hass}
|
.hass=${this.hass}
|
||||||
|
|||||||
@@ -315,6 +315,7 @@
|
|||||||
"duplicate_camera_id": "Duplicate Frigate camera id for the following camera, use the 'id' parameter to uniquely identify cameras",
|
"duplicate_camera_id": "Duplicate Frigate camera id for the following camera, use the 'id' parameter to uniquely identify cameras",
|
||||||
"empty_response": "Received empty response from Home Assistant for request",
|
"empty_response": "Received empty response from Home Assistant for request",
|
||||||
"failed_response": "Failed to receive response from Home Assistant for request",
|
"failed_response": "Failed to receive response from Home Assistant for request",
|
||||||
|
"failed_retain": "Could not retain event",
|
||||||
"failed_sign": "Could not sign Home Assistant URL",
|
"failed_sign": "Could not sign Home Assistant URL",
|
||||||
"image_load_error": "The image could not be loaded",
|
"image_load_error": "The image could not be loaded",
|
||||||
"invalid_configuration": "Invalid configuration",
|
"invalid_configuration": "Invalid configuration",
|
||||||
|
|||||||
@@ -317,6 +317,7 @@
|
|||||||
"duplicate_camera_id": "Duplique o ID da câmera Frigate para a câmera a seguir, use o parâmetro 'id' para identificar exclusivamente as câmeras",
|
"duplicate_camera_id": "Duplique o ID da câmera Frigate para a câmera a seguir, use o parâmetro 'id' para identificar exclusivamente as câmeras",
|
||||||
"empty_response": "Sem resposta do Home Assistant para a solicitação",
|
"empty_response": "Sem resposta do Home Assistant para a solicitação",
|
||||||
"failed_response": "Falha ao receber resposta do Home Assistant para solicitação",
|
"failed_response": "Falha ao receber resposta do Home Assistant para solicitação",
|
||||||
|
"failed_retain": "",
|
||||||
"failed_sign": "Não foi possível assinar a URL do Home Assistant",
|
"failed_sign": "Não foi possível assinar a URL do Home Assistant",
|
||||||
"image_load_error": "A imagem não pôde ser carregada",
|
"image_load_error": "A imagem não pôde ser carregada",
|
||||||
"invalid_configuration": "Configuração inválida",
|
"invalid_configuration": "Configuração inválida",
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ export function localize(string: string, search = '', replace = ''): string {
|
|||||||
translated = string.split('.').reduce((o, i) => o[i], languages['en']);
|
translated = string.split('.').reduce((o, i) => o[i], languages['en']);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (translated === undefined) {
|
if (!translated) {
|
||||||
translated = string.split('.').reduce((o, i) => o[i], languages['en']);
|
translated = string.split('.').reduce((o, i) => o[i], languages['en']);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+15
-4
@@ -31,16 +31,27 @@
|
|||||||
ha-icon {
|
ha-icon {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
opacity: 0.8;
|
opacity: 0.5;
|
||||||
|
color: var(--primary-color);
|
||||||
|
top: 3px;
|
||||||
|
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
transition: opacity 0.2s ease-in-out, color 0.2s ease-in-out;
|
||||||
|
}
|
||||||
|
ha-icon:hover {
|
||||||
|
opacity: 1.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
ha-icon.favorite {
|
ha-icon.star {
|
||||||
|
left: 3px;
|
||||||
|
}
|
||||||
|
ha-icon.star.starred {
|
||||||
color: gold;
|
color: gold;
|
||||||
}
|
}
|
||||||
|
|
||||||
ha-icon.timeline {
|
ha-icon.timeline {
|
||||||
color: var(--primary-color);
|
right: 3px;
|
||||||
right: 0px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
frigate-card-thumbnail-details-event, frigate-card-thumbnail-details-recording {
|
frigate-card-thumbnail-details-event, frigate-card-thumbnail-details-recording {
|
||||||
|
|||||||
+42
-2
@@ -1,6 +1,8 @@
|
|||||||
|
import { HomeAssistant } from 'custom-card-helpers';
|
||||||
import { z } from 'zod';
|
import { z } from 'zod';
|
||||||
import { CameraConfig, ExtendedHomeAssistant } from '../types';
|
import { localize } from '../localize/localize';
|
||||||
import { homeAssistantHTTPRequest } from './ha';
|
import { CameraConfig, ExtendedHomeAssistant, FrigateCardError } from '../types';
|
||||||
|
import { homeAssistantHTTPRequest, homeAssistantWSRequest } from './ha';
|
||||||
|
|
||||||
export const FRIGATE_ICON_SVG_PATH =
|
export const FRIGATE_ICON_SVG_PATH =
|
||||||
'm 4.8759466,22.743573 c 0.0866,0.69274 0.811811,1.16359 0.37885,1.27183 ' +
|
'm 4.8759466,22.743573 c 0.0866,0.69274 0.811811,1.16359 0.37885,1.27183 ' +
|
||||||
@@ -50,6 +52,12 @@ const recordingSegmentSchema = z.object({
|
|||||||
const recordingSegmentsSchema = recordingSegmentSchema.array();
|
const recordingSegmentsSchema = recordingSegmentSchema.array();
|
||||||
export type RecordingSegments = z.infer<typeof recordingSegmentsSchema>;
|
export type RecordingSegments = z.infer<typeof recordingSegmentsSchema>;
|
||||||
|
|
||||||
|
const retainResultSchema = z.object({
|
||||||
|
success: z.boolean(),
|
||||||
|
message: z.string(),
|
||||||
|
});
|
||||||
|
export type RetainResult = z.infer<typeof retainResultSchema>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the recordings summary. May throw.
|
* Get the recordings summary. May throw.
|
||||||
* @param hass The Home Assistant object.
|
* @param hass The Home Assistant object.
|
||||||
@@ -96,6 +104,38 @@ export const getRecordingSegments = async (
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Request that Frigate retain an event. May throw.
|
||||||
|
* @param hass The HomeAssistant object.
|
||||||
|
* @param client_id The Frigate client_id.
|
||||||
|
* @param eventID The event ID to retain.
|
||||||
|
* @param retain `true` to retain or `false` to unretain.
|
||||||
|
*/
|
||||||
|
export async function retainEvent(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
client_id: string,
|
||||||
|
eventID: string,
|
||||||
|
retain: boolean,
|
||||||
|
): Promise<void> {
|
||||||
|
const retainRequest = {
|
||||||
|
type: 'frigate/event/retain',
|
||||||
|
instance_id: client_id,
|
||||||
|
event_id: eventID,
|
||||||
|
retain: retain,
|
||||||
|
};
|
||||||
|
const response = await homeAssistantWSRequest<RetainResult>(
|
||||||
|
hass,
|
||||||
|
retainResultSchema,
|
||||||
|
retainRequest,
|
||||||
|
);
|
||||||
|
if (!response.success) {
|
||||||
|
throw new FrigateCardError(localize('error.failed_retain'), {
|
||||||
|
request: retainRequest,
|
||||||
|
response: response,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get an id that unique identifies a particular camera (not zone, object, etc)
|
* Get an id that unique identifies a particular camera (not zone, object, etc)
|
||||||
* within a particular Frigate instance. ID will not (necessarily) be unique
|
* within a particular Frigate instance. ID will not (necessarily) be unique
|
||||||
|
|||||||
Reference in New Issue
Block a user