refactor: Retire the use of unmaintained custom-card-helpers (#1956)

- Closes #1295
This commit is contained in:
Dermot Duffy
2025-03-09 16:02:33 -07:00
committed by GitHub
parent c65ee3f0f2
commit a79ffa6edc
116 changed files with 933 additions and 545 deletions
-1
View File
@@ -19,7 +19,6 @@
"license": "MIT",
"dependencies": {
"@cycjimmy/jsmpeg-player": "^6.0.5",
"@dermotduffy/custom-card-helpers": "^1.9.1",
"@dermotduffy/panzoom": "^4.5.1",
"@egjs/hammerjs": "^2.0.17",
"@graphiteds/core": "^1.9.21",
+8 -11
View File
@@ -1,8 +1,3 @@
import type {
ActionHandlerDetail,
ActionHandlerOptions,
} from '@dermotduffy/custom-card-helpers';
import { fireEvent } from '@dermotduffy/custom-card-helpers';
import { noChange } from 'lit';
import {
AttributePart,
@@ -10,6 +5,8 @@ import {
DirectiveParameters,
directive,
} from 'lit/directive.js';
import { fireHASSEvent } from './ha/fire-hass-event.js';
import { ActionHandlerDetail, ActionHandlerOptions } from './ha/types.js';
import { stopEventFromActivatingCardWideActions } from './utils/action.js';
import { Timer } from './utils/timer.js';
@@ -88,7 +85,7 @@ class ActionHandler extends HTMLElement implements ActionHandlerInterface {
// mousedown events (on Android).
if (!this.started) {
this.started = true;
fireEvent(element, 'action', { action: 'start_tap' });
fireHASSEvent(element, 'action', { action: 'start_tap' });
}
};
@@ -98,7 +95,7 @@ class ActionHandler extends HTMLElement implements ActionHandlerInterface {
if (this.started) {
this.started = false;
fireEvent(element, 'action', { action: 'end_tap' });
fireHASSEvent(element, 'action', { action: 'end_tap' });
}
};
@@ -122,21 +119,21 @@ class ActionHandler extends HTMLElement implements ActionHandlerInterface {
endTap(ev);
if (options?.hasHold && this.held) {
fireEvent(element, 'action', { action: 'hold' });
fireHASSEvent(element, 'action', { action: 'hold' });
} else if (options?.hasDoubleClick) {
if (
(ev.type === 'click' && (ev as MouseEvent).detail < 2) ||
!this.doubleClickTimer.isRunning()
) {
this.doubleClickTimer.start(0.25, () =>
fireEvent(element, 'action', { action: 'tap' }),
fireHASSEvent(element, 'action', { action: 'tap' }),
);
} else {
this.doubleClickTimer.stop();
fireEvent(element, 'action', { action: 'double_tap' });
fireHASSEvent(element, 'action', { action: 'double_tap' });
}
} else {
fireEvent(element, 'action', { action: 'tap' });
fireHASSEvent(element, 'action', { action: 'tap' });
}
};
+1 -1
View File
@@ -1,4 +1,4 @@
import { HomeAssistant } from '@dermotduffy/custom-card-helpers';
import { HomeAssistant } from '../../ha/types';
import { localize } from '../../localize/localize';
import { EntityRegistryManager } from '../../utils/ha/registry/entity';
import { Entity } from '../../utils/ha/registry/entity/types';
@@ -1,6 +1,6 @@
import { StateWatcherSubscriptionInterface } from '../../card-controller/hass/state-watcher';
import { CameraConfig } from '../../config/types';
import { ExtendedHomeAssistant } from '../../types';
import { HomeAssistant } from '../../ha/types';
import { canonicalizeHAURL } from '../../utils/ha';
import { BrowseMediaManager } from '../../utils/ha/browse-media/browse-media-manager';
import { BROWSE_MEDIA_CACHE_SECONDS } from '../../utils/ha/browse-media/types';
@@ -63,7 +63,7 @@ export class BrowseMediaCameraManagerEngine
}
public async getMediaDownloadPath(
hass: ExtendedHomeAssistant,
hass: HomeAssistant,
_cameraConfig: CameraConfig,
media: ViewMedia,
): Promise<CameraEndpoint | null> {
+1 -1
View File
@@ -1,6 +1,6 @@
import { HomeAssistant } from '@dermotduffy/custom-card-helpers';
import { StateWatcherSubscriptionInterface } from '../card-controller/hass/state-watcher';
import { CameraConfig } from '../config/types';
import { HomeAssistant } from '../ha/types';
import { localize } from '../localize/localize';
import { BrowseMediaManager } from '../utils/ha/browse-media/browse-media-manager';
import { EntityRegistryManager } from '../utils/ha/registry/entity';
+2 -3
View File
@@ -1,7 +1,6 @@
import { HomeAssistant } from '@dermotduffy/custom-card-helpers';
import { PTZAction } from '../config/ptz';
import { ActionPhase, CameraConfig } from '../config/types';
import { ExtendedHomeAssistant } from '../types';
import { HomeAssistant } from '../ha/types';
import { ViewMedia } from '../view/media';
import { Camera } from './camera';
import { CameraManagerReadOnlyConfigStore } from './store';
@@ -89,7 +88,7 @@ export interface CameraManagerEngine {
): ViewMedia[] | null;
getMediaDownloadPath(
hass: ExtendedHomeAssistant,
hass: HomeAssistant,
cameraConfig: CameraConfig,
media: ViewMedia,
): Promise<CameraEndpoint | null>;
+1 -1
View File
@@ -1,7 +1,7 @@
import { HomeAssistant } from '@dermotduffy/custom-card-helpers';
import uniq from 'lodash-es/uniq';
import { StateWatcherSubscriptionInterface } from '../../card-controller/hass/state-watcher';
import { CameraConfig } from '../../config/types';
import { HomeAssistant } from '../../ha/types';
import { localize } from '../../localize/localize';
import { PTZCapabilities, PTZMovementType } from '../../types';
import { errorToConsole } from '../../utils/basic';
+2 -3
View File
@@ -1,4 +1,3 @@
import { HomeAssistant } from '@dermotduffy/custom-card-helpers';
import { add, endOfHour, format, fromUnixTime, startOfHour } from 'date-fns';
import isEqual from 'lodash-es/isEqual';
import orderBy from 'lodash-es/orderBy';
@@ -7,7 +6,7 @@ import uniqWith from 'lodash-es/uniqWith';
import { StateWatcherSubscriptionInterface } from '../../card-controller/hass/state-watcher';
import { PTZAction } from '../../config/ptz';
import { ActionPhase, CameraConfig } from '../../config/types';
import { ExtendedHomeAssistant } from '../../types';
import { HomeAssistant } from '../../ha/types';
import {
allPromises,
formatDate,
@@ -157,7 +156,7 @@ export class FrigateCameraManagerEngine
}
public async getMediaDownloadPath(
_hass: ExtendedHomeAssistant,
_hass: HomeAssistant,
cameraConfig: CameraConfig,
media: ViewMedia,
): Promise<CameraEndpoint | null> {
+1 -1
View File
@@ -1,4 +1,4 @@
import { HomeAssistant } from '@dermotduffy/custom-card-helpers';
import { HomeAssistant } from '../../ha/types';
import { FrigateEventChange, frigateEventChangeSchema } from './types';
export interface FrigateEventWatcherRequest {
+1 -1
View File
@@ -1,4 +1,4 @@
import { HomeAssistant } from '@dermotduffy/custom-card-helpers';
import { HomeAssistant } from '../../ha/types';
import { localize } from '../../localize/localize';
import { AdvancedCameraCardError } from '../../types';
import { homeAssistantWSRequest } from '../../utils/ha/ws-request';
+2 -3
View File
@@ -1,10 +1,9 @@
/* eslint-disable @typescript-eslint/no-unused-vars */
import { HomeAssistant } from '@dermotduffy/custom-card-helpers';
import { StateWatcherSubscriptionInterface } from '../../card-controller/hass/state-watcher';
import { PTZAction } from '../../config/ptz';
import { ActionPhase, CameraConfig } from '../../config/types';
import { ExtendedHomeAssistant } from '../../types';
import { HomeAssistant } from '../../ha/types';
import { getEntityTitle } from '../../utils/ha';
import { ViewMedia } from '../../view/media';
import { Camera } from '../camera';
@@ -153,7 +152,7 @@ export class GenericCameraManagerEngine implements CameraManagerEngine {
}
public async getMediaDownloadPath(
_hass: ExtendedHomeAssistant,
_hass: HomeAssistant,
_cameraConfig: CameraConfig,
_media: ViewMedia,
): Promise<CameraEndpoint | null> {
@@ -1,7 +1,7 @@
import { HomeAssistant } from '@dermotduffy/custom-card-helpers';
import { add, endOfDay, parse, startOfDay } from 'date-fns';
import orderBy from 'lodash-es/orderBy';
import { CameraConfig } from '../../config/types';
import { HomeAssistant } from '../../ha/types';
import { allPromises, formatDate, isValidDate } from '../../utils/basic';
import {
BrowseMediaStep,
+1 -1
View File
@@ -1,4 +1,4 @@
import { HomeAssistant } from '@dermotduffy/custom-card-helpers';
import { HomeAssistant } from '../../ha/types';
import { localize } from '../../localize/localize';
import { EntityRegistryManager } from '../../utils/ha/registry/entity';
import { BrowseMediaCamera } from '../browse-media/camera';
+1 -1
View File
@@ -1,7 +1,7 @@
import { HomeAssistant } from '@dermotduffy/custom-card-helpers';
import { add, endOfDay, parse, startOfDay } from 'date-fns';
import { orderBy } from 'lodash-es';
import { CameraConfig } from '../../config/types';
import { HomeAssistant } from '../../ha/types';
import { allPromises, formatDate, isValidDate } from '../../utils/basic';
import { sortMediaByStartDate } from '../../utils/ha/browse-media/browse-media-manager';
import {
@@ -87,7 +87,8 @@ export class ActionsManager {
*/
public handleCustomActionEvent = (ev: Event): void => {
if (!('detail' in ev)) {
// The event may not be a CustomEvent object, see:
// The event may or may not be a CustomEvent object. For example, whilst
// this card doesn't use custom-card-helpers, embedded elements may:
// https://github.com/custom-cards/custom-card-helpers/blob/master/src/fire-event.ts#L70
return;
}
@@ -1,4 +1,5 @@
import { ActionConfig, handleActionConfig } from '@dermotduffy/custom-card-helpers';
import { handleActionConfig } from '../../../ha/handle-action';
import { ActionConfig } from '../../../ha/types';
import { CardActionsAPI } from '../../types';
import { BaseAction } from './base';
+1 -1
View File
@@ -1,6 +1,6 @@
import { ActionConfig } from '@dermotduffy/custom-card-helpers';
import { ActionContext } from 'action';
import { ActionType, INTERNAL_CALLBACK_ACTION } from '../../config/types';
import { ActionConfig } from '../../ha/types';
import { convertActionToCardCustomAction } from '../../utils/action';
import { CameraSelectAction } from './actions/camera-select';
import { CameraUIAction } from './actions/camera-ui';
@@ -1,11 +1,11 @@
import { dispatchAdvancedCameraCardEvent } from '../../../utils/basic';
import { fireAdvancedCameraCardEvent } from '../../../utils/fire-advanced-camera-card-event';
import { ActionExecutionRequest } from '../types';
export const dispatchActionExecutionRequest = (
element: HTMLElement,
request: ActionExecutionRequest,
) => {
dispatchAdvancedCameraCardEvent(element, 'action:execution-request', request);
fireAdvancedCameraCardEvent(element, 'action:execution-request', request);
};
export interface ActionExecutionRequestEventTarget extends EventTarget {
+1 -1
View File
@@ -1,8 +1,8 @@
import { LovelaceCardEditor } from '@dermotduffy/custom-card-helpers';
import { ReactiveController } from 'lit';
import { CameraManager } from '../camera-manager/manager';
import { ConditionStateManager } from '../conditions/state-manager';
import { AdvancedCameraCardConfig } from '../config/types';
import { LovelaceCardEditor } from '../ha/types';
import {
createDeviceRegistryCache,
DeviceRegistryManager,
+4 -4
View File
@@ -1,11 +1,11 @@
import { HomeAssistant } from '../../ha/types';
import { localize } from '../../localize/localize';
import { ExtendedHomeAssistant } from '../../types';
import { hasHAConnectionStateChanged } from '../../utils/ha';
import { CardHASSAPI } from '../types';
import { StateWatcher, StateWatcherSubscriptionInterface } from './state-watcher';
export class HASSManager {
protected _hass: ExtendedHomeAssistant | null = null;
protected _hass: HomeAssistant | null = null;
protected _api: CardHASSAPI;
protected _stateWatcher: StateWatcher = new StateWatcher();
@@ -13,7 +13,7 @@ export class HASSManager {
this._api = api;
}
public getHASS(): ExtendedHomeAssistant | null {
public getHASS(): HomeAssistant | null {
return this._hass;
}
@@ -25,7 +25,7 @@ export class HASSManager {
return this._stateWatcher;
}
public setHASS(hass?: ExtendedHomeAssistant | null): void {
public setHASS(hass?: HomeAssistant | null): void {
if (hasHAConnectionStateChanged(this._hass, hass)) {
if (!hass?.connected) {
this._api.getMessageManager().setMessageIfHigherPriority({
+1 -1
View File
@@ -1,4 +1,4 @@
import { HomeAssistant } from '@dermotduffy/custom-card-helpers';
import { HomeAssistant } from '../../ha/types';
import { getHassDifferences, HassStateDifference } from '../../utils/ha';
type StateWatcherCallback = (difference: HassStateDifference) => void;
+2 -2
View File
@@ -1,7 +1,7 @@
import { HomeAssistant } from '@dermotduffy/custom-card-helpers';
import { HASS, renderTemplate } from 'ha-nunjucks/dist';
import { ConditionsTriggerData, ConditionState } from '../../conditions/types';
import { ConditionState, ConditionsTriggerData } from '../../conditions/types';
import { ActionType } from '../../config/types';
import { HomeAssistant } from '../../ha/types';
interface TemplateContextInternal {
camera?: string;
+4 -4
View File
@@ -1,4 +1,3 @@
import { HomeAssistant, LovelaceCardEditor } from '@dermotduffy/custom-card-helpers';
import { CSSResultGroup, LitElement, TemplateResult, html, unsafeCSS } from 'lit';
import { customElement } from 'lit/decorators.js';
import { classMap } from 'lit/directives/class-map.js';
@@ -30,9 +29,10 @@ import {
StatusBarItem,
} from './config/types';
import { REPO_URL } from './const.js';
import { HomeAssistant, LovelaceCardEditor } from './ha/types.js';
import { localize } from './localize/localize.js';
import cardStyle from './scss/card.scss';
import { ExtendedHomeAssistant, MediaLoadedInfo, Message } from './types.js';
import { MediaLoadedInfo, Message } from './types.js';
import { hasAction } from './utils/action.js';
import { getReleaseVersion } from './utils/diagnostics';
@@ -110,11 +110,11 @@ class AdvancedCameraCard extends LitElement {
return this._controller.getConfigManager().getConfig();
}
get _hass(): ExtendedHomeAssistant | null {
get _hass(): HomeAssistant | null {
return this._controller.getHASSManager().getHASS();
}
set hass(hass: ExtendedHomeAssistant) {
set hass(hass: HomeAssistant) {
this._controller.getHASSManager().setHASS(hass);
// Manually set hass in the menu, elements and image. This is to allow these
+1 -1
View File
@@ -1,8 +1,8 @@
import { HomeAssistant } from '@dermotduffy/custom-card-helpers';
import { HassEntity } from 'home-assistant-js-websocket';
import frigateSVG from '../camera-manager/frigate/assets/frigate.svg';
import motioneyeSVG from '../camera-manager/motioneye/assets/motioneye.svg';
import reolinkSVG from '../camera-manager/reolink/assets/reolink.svg';
import { HomeAssistant } from '../ha/types';
import irisSVG from '../images/iris.svg';
import { Icon } from '../types';
@@ -1,5 +1,5 @@
import { dispatchAdvancedCameraCardEvent } from '../../../utils/basic';
import { fireAdvancedCameraCardEvent } from '../../../utils/fire-advanced-camera-card-event';
export function dispatchLiveErrorEvent(element: EventTarget): void {
dispatchAdvancedCameraCardEvent(element, 'live:error');
fireAdvancedCameraCardEvent(element, 'live:error');
}
+4 -7
View File
@@ -3,11 +3,8 @@ import throttle from 'lodash-es/throttle';
import Masonry from 'masonry-layout';
import { ViewDisplayConfig } from '../config/types';
import { MediaLoadedInfo } from '../types';
import {
dispatchAdvancedCameraCardEvent,
getChildrenFromElement,
setOrRemoveAttribute,
} from '../utils/basic';
import { getChildrenFromElement, setOrRemoveAttribute } from '../utils/basic';
import { fireAdvancedCameraCardEvent } from '../utils/fire-advanced-camera-card-event';
import {
AdvancedCameraCardMediaLoadedEventTarget,
dispatchExistingMediaLoadedInfoAsEvent,
@@ -137,7 +134,7 @@ export class MediaGridController {
}
this._selected = id;
dispatchAdvancedCameraCardEvent(this._host, 'media-grid:selected', { selected: id });
fireAdvancedCameraCardEvent(this._host, 'media-grid:selected', { selected: id });
const mediaLoadedInfo = this._mediaLoadedInfoMap.get(id);
if (mediaLoadedInfo) {
@@ -155,7 +152,7 @@ export class MediaGridController {
public unselectAll() {
if (this._selected !== null) {
dispatchMediaUnloadedEvent(this._host);
dispatchAdvancedCameraCardEvent(this._host, 'media-grid:unselected');
fireAdvancedCameraCardEvent(this._host, 'media-grid:unselected');
}
this._selected = null;
this._updateSelectedStylesOnElements();
+1 -1
View File
@@ -1,4 +1,3 @@
import { HomeAssistant } from '@dermotduffy/custom-card-helpers';
import { StyleInfo } from 'lit/directives/style-map';
import { CameraManager } from '../camera-manager/manager';
import { FullscreenManager } from '../card-controller/fullscreen/fullscreen-manager';
@@ -11,6 +10,7 @@ import {
MenuItem,
VIEWS_USER_SPECIFIED,
} from '../config/types';
import { HomeAssistant } from '../ha/types';
import { localize } from '../localize/localize.js';
import { MediaLoadedInfo } from '../types';
import {
+2 -2
View File
@@ -1,5 +1,5 @@
import { AdvancedCameraCardError, Message } from '../../types';
import { dispatchAdvancedCameraCardEvent } from '../../utils/basic';
import { fireAdvancedCameraCardEvent } from '../../utils/fire-advanced-camera-card-event';
// Facilitates correct typing of event handlers.
export interface AdvancedCameraCardMessageEventTarget extends EventTarget {
@@ -44,7 +44,7 @@ export const dispatchAdvancedCameraCardErrorEvent = (
error: unknown,
): void => {
if (error instanceof Error) {
dispatchAdvancedCameraCardEvent<Message>(element, 'message', {
fireAdvancedCameraCardEvent<Message>(element, 'message', {
message: error.message,
type: 'error',
...(error instanceof AdvancedCameraCardError && { context: error.context }),
+8 -8
View File
@@ -1,11 +1,11 @@
import { HomeAssistant } from '@dermotduffy/custom-card-helpers';
import { CameraManager } from '../../camera-manager/manager';
import { dispatchActionExecutionRequest } from '../../card-controller/actions/utils/execution-request';
import { PTZAction } from '../../config/ptz';
import { Actions, ActionsConfig, PTZControlsConfig } from '../../config/types';
import { Interaction } from '../../types';
import { createPTZMultiAction, getActionConfigGivenAction } from '../../utils/action';
import { SubmenuInteraction } from '../../components/submenu/types';
import { CameraManager } from '../../camera-manager/manager.js';
import { dispatchActionExecutionRequest } from '../../card-controller/actions/utils/execution-request.js';
import { SubmenuInteraction } from '../../components/submenu/types.js';
import { PTZAction } from '../../config/ptz.js';
import { Actions, ActionsConfig, PTZControlsConfig } from '../../config/types.js';
import { HomeAssistant } from '../../ha/types.js';
import { Interaction } from '../../types.js';
import { createPTZMultiAction, getActionConfigGivenAction } from '../../utils/action.js';
import { PTZControllerActions } from './types';
export class PTZController {
+1 -2
View File
@@ -1,4 +1,3 @@
import { HASSDomEvent } from '@dermotduffy/custom-card-helpers';
import { LitElement } from 'lit';
import isEqual from 'lodash-es/isEqual';
import orderBy from 'lodash-es/orderBy';
@@ -76,7 +75,7 @@ export class StatusBarController {
}
public actionHandler(
ev: HASSDomEvent<{ action: string; config?: ActionsConfig }>,
ev: CustomEvent<{ action: string; config?: ActionsConfig }>,
config?: ActionsConfig,
): void {
// These interactions should only be handled by the status bar, as nothing
+6 -9
View File
@@ -1,11 +1,8 @@
import Panzoom, { PanzoomEventDetail, PanzoomObject } from '@dermotduffy/panzoom';
import round from 'lodash-es/round';
import throttle from 'lodash-es/throttle';
import {
arefloatsApproximatelyEqual,
dispatchAdvancedCameraCardEvent,
isHoverableDevice,
} from '../../utils/basic';
import { arefloatsApproximatelyEqual, isHoverableDevice } from '../../utils/basic';
import { fireAdvancedCameraCardEvent } from '../../utils/fire-advanced-camera-card-event';
import {
PartialZoomSettings,
ZOOM_DEFAULT_PAN_X,
@@ -76,7 +73,7 @@ export class ZoomController {
// Even though the click is stopped,the card still needs to gain focus so
// that keyboard shortcuts will work immediately after the card is clicked
// upon.
dispatchAdvancedCameraCardEvent(this._element, 'focus');
fireAdvancedCameraCardEvent(this._element, 'focus');
}
this._allowClick = true;
};
@@ -211,11 +208,11 @@ export class ZoomController {
if (unzoomed && this._zoomed) {
this._zoomed = false;
this._setTouchAction(true);
dispatchAdvancedCameraCardEvent(this._element, 'zoom:unzoomed');
fireAdvancedCameraCardEvent(this._element, 'zoom:unzoomed');
} else if (!unzoomed && !this._zoomed) {
this._zoomed = true;
this._setTouchAction(false);
dispatchAdvancedCameraCardEvent(this._element, 'zoom:zoomed');
fireAdvancedCameraCardEvent(this._element, 'zoom:zoomed');
}
const converted = this._convertXYPanToPercent(pz.x, pz.y, pz.scale);
@@ -229,7 +226,7 @@ export class ZoomController {
unzoomed: unzoomed,
};
dispatchAdvancedCameraCardEvent(this._element, 'zoom:change', observed);
fireAdvancedCameraCardEvent(this._element, 'zoom:change', observed);
}
protected _isZoomEqual(a: PartialZoomSettings, b: PartialZoomSettings): boolean {
+2 -2
View File
@@ -4,7 +4,7 @@ import { createRef, ref, Ref } from 'lit/directives/ref.js';
import { localize } from '../localize/localize';
import datePickerStyle from '../scss/date-picker.scss';
import { stopEventFromActivatingCardWideActions } from '../utils/action';
import { dispatchAdvancedCameraCardEvent } from '../utils/basic';
import { fireAdvancedCameraCardEvent } from '../utils/fire-advanced-camera-card-event';
import './icon';
export interface DatePickerEvent {
@@ -32,7 +32,7 @@ export class AdvancedCameraCardDatePicker extends LitElement {
const changed = () => {
const value = this._refInput.value?.value;
dispatchAdvancedCameraCardEvent<DatePickerEvent>(this, 'date-picker:change', {
fireAdvancedCameraCardEvent<DatePickerEvent>(this, 'date-picker:change', {
date: value ? new Date(value) : null,
});
};
+1 -1
View File
@@ -1,8 +1,8 @@
import { HomeAssistant } from '@dermotduffy/custom-card-helpers';
import { CSSResultGroup, html, LitElement, TemplateResult, unsafeCSS } from 'lit';
import { customElement, property } from 'lit/decorators.js';
import { until } from 'lit/directives/until.js';
import { RawAdvancedCameraCardConfig } from '../config/types';
import { HomeAssistant } from '../ha/types';
import { localize } from '../localize/localize';
import basicBlockStyle from '../scss/basic-block.scss';
import { getDiagnostics } from '../utils/diagnostics';
+8 -7
View File
@@ -1,4 +1,3 @@
import { HomeAssistant } from '@dermotduffy/custom-card-helpers';
import {
CSSResultGroup,
html,
@@ -8,9 +7,9 @@ import {
unsafeCSS,
} from 'lit';
import { customElement, property, state } from 'lit/decorators.js';
import { dispatchAdvancedCameraCardErrorEvent } from '../components-lib/message/dispatch.js';
import { ConditionsManager } from '../conditions/conditions-manager.js';
import { getConditionStateManagerViaEvent } from '../conditions/state-manager-via-event.js';
import { dispatchAdvancedCameraCardErrorEvent } from '../components-lib/message/dispatch.js';
import {
AdvancedCameraCardConditional,
MenuIcon,
@@ -24,10 +23,12 @@ import {
StatusBarItem,
StatusBarString,
} from '../config/types.js';
import { HomeAssistant } from '../ha/types.js';
import { localize } from '../localize/localize.js';
import elementsStyle from '../scss/elements.scss';
import { AdvancedCameraCardError } from '../types.js';
import { dispatchAdvancedCameraCardEvent, errorToConsole } from '../utils/basic.js';
import { errorToConsole } from '../utils/basic.js';
import { fireAdvancedCameraCardEvent } from '../utils/fire-advanced-camera-card-event.js';
/* A note on picture element rendering:
*
@@ -169,7 +170,7 @@ export class AdvancedCameraCardElements extends LitElement {
protected _menuRemoveHandler = (ev: Event): void => {
// Re-dispatch event from this element (instead of the disconnected one, as
// there is no parent of the disconnected element).
dispatchAdvancedCameraCardEvent<MenuItem>(
fireAdvancedCameraCardEvent<MenuItem>(
this,
'menu:remove',
(ev as CustomEvent).detail,
@@ -179,7 +180,7 @@ export class AdvancedCameraCardElements extends LitElement {
protected _statusBarRemoveHandler = (ev: Event): void => {
// Re-dispatch event from this element (instead of the disconnected one, as
// there is no parent of the disconnected element).
dispatchAdvancedCameraCardEvent<StatusBarItem>(
fireAdvancedCameraCardEvent<StatusBarItem>(
this,
'status-bar:remove',
(ev as CustomEvent).detail,
@@ -346,7 +347,7 @@ export class AdvancedCameraCardElementsBaseItem<ConfigType> extends LitElement {
connectedCallback(): void {
super.connectedCallback();
if (this._config) {
dispatchAdvancedCameraCardEvent<ConfigType>(
fireAdvancedCameraCardEvent<ConfigType>(
this,
`${this._eventCategory}:add`,
this._config,
@@ -356,7 +357,7 @@ export class AdvancedCameraCardElementsBaseItem<ConfigType> extends LitElement {
disconnectedCallback(): void {
if (this._config) {
dispatchAdvancedCameraCardEvent<ConfigType>(
fireAdvancedCameraCardEvent<ConfigType>(
this,
`${this._eventCategory}:remove`,
this._config,
+3 -3
View File
@@ -14,10 +14,10 @@ import { CameraManager, ExtendedMediaQueryResult } from '../camera-manager/manag
import { EventQuery, MediaQuery, RecordingQuery } from '../camera-manager/types';
import { ViewManagerEpoch } from '../card-controller/view/types.js';
import { CardWideConfig, configDefaults, GalleryConfig } from '../config/types';
import { HomeAssistant } from '../ha/types.js';
import { localize } from '../localize/localize';
import galleryCoreStyle from '../scss/gallery-core.scss';
import galleryStyle from '../scss/gallery.scss';
import { ExtendedHomeAssistant } from '../types.js';
import { stopEventFromActivatingCardWideActions } from '../utils/action.js';
import { errorToConsole, sleep } from '../utils/basic';
import { scrollIntoView } from '../utils/scroll.js';
@@ -44,7 +44,7 @@ const MIN_GALLERY_EXTENSION_SECONDS = 0.5;
@customElement('advanced-camera-card-gallery')
export class AdvancedCameraCardGallery extends LitElement {
@property({ attribute: false })
public hass?: ExtendedHomeAssistant;
public hass?: HomeAssistant;
@property({ attribute: false })
public viewManagerEpoch?: ViewManagerEpoch;
@@ -112,7 +112,7 @@ export class AdvancedCameraCardGallery extends LitElement {
@customElement('advanced-camera-card-gallery-core')
export class AdvancedCameraCardGalleryCore extends LitElement {
@property({ attribute: false })
public hass?: ExtendedHomeAssistant;
public hass?: HomeAssistant;
@property({ attribute: false })
public viewManagerEpoch?: ViewManagerEpoch;
+1 -1
View File
@@ -1,4 +1,3 @@
import { HomeAssistant } from '@dermotduffy/custom-card-helpers';
import {
CSSResultGroup,
html,
@@ -9,6 +8,7 @@ import {
} from 'lit';
import { customElement, property } from 'lit/decorators.js';
import { IconController } from '../components-lib/icon-controller';
import { HomeAssistant } from '../ha/types';
import iconStyle from '../scss/icon.scss';
import { Icon } from '../types';
+1 -1
View File
@@ -1,4 +1,3 @@
import { HomeAssistant } from '@dermotduffy/custom-card-helpers';
import { HassEntity } from 'home-assistant-js-websocket';
import {
CSSResultGroup,
@@ -17,6 +16,7 @@ import { getCameraEntityFromConfig } from '../camera-manager/utils/camera-entity
import { CachedValueController } from '../components-lib/cached-value-controller.js';
import { UpdatingImageMediaPlayerController } from '../components-lib/media-player/updating-image.js';
import { CameraConfig, ImageMode, ImageViewConfig } from '../config/types.js';
import { HomeAssistant } from '../ha/types.js';
import defaultImage from '../images/iris-screensaver.jpg';
import { localize } from '../localize/localize.js';
import imageUpdatingPlayerStyle from '../scss/image-updating-player.scss';
+1 -1
View File
@@ -1,4 +1,3 @@
import { HomeAssistant } from '@dermotduffy/custom-card-helpers';
import {
CSSResultGroup,
html,
@@ -23,6 +22,7 @@ import { updateElementStyleFromMediaLayoutConfig } from '../utils/media-layout.j
import './image-updating-player';
import { resolveImageMode } from './image-updating-player';
import './zoomer.js';
import { HomeAssistant } from '../ha/types';
@customElement('advanced-camera-card-image')
export class AdvancedCameraCardImage extends LitElement implements MediaPlayer {
+2 -2
View File
@@ -23,8 +23,8 @@ import {
LiveConfig,
TransitionEffect,
} from '../../config/types.js';
import { HomeAssistant } from '../../ha/types.js';
import liveCarouselStyle from '../../scss/live-carousel.scss';
import { ExtendedHomeAssistant } from '../../types.js';
import { stopEventFromActivatingCardWideActions } from '../../utils/action.js';
import { CarouselSelected } from '../../utils/embla/carousel-controller.js';
import { AutoLazyLoad } from '../../utils/embla/plugins/auto-lazy-load/auto-lazy-load.js';
@@ -56,7 +56,7 @@ interface CameraNeighbors {
@customElement('advanced-camera-card-live-carousel')
export class AdvancedCameraCardLiveCarousel extends LitElement {
@property({ attribute: false })
public hass?: ExtendedHomeAssistant;
public hass?: HomeAssistant;
@property({ attribute: false })
public viewManagerEpoch?: ViewManagerEpoch;
+2 -2
View File
@@ -13,14 +13,14 @@ import { MicrophoneState } from '../../card-controller/types.js';
import { ViewManagerEpoch } from '../../card-controller/view/types.js';
import { MediaGridSelected } from '../../components-lib/media-grid-controller.js';
import { CardWideConfig, LiveConfig } from '../../config/types.js';
import { HomeAssistant } from '../../ha/types.js';
import liveGridStyle from '../../scss/live-grid.scss';
import { ExtendedHomeAssistant } from '../../types.js';
import './carousel.js';
@customElement('advanced-camera-card-live-grid')
export class AdvancedCameraCardLiveGrid extends LitElement {
@property({ attribute: false })
public hass?: ExtendedHomeAssistant;
public hass?: HomeAssistant;
@property({ attribute: false })
public viewManagerEpoch?: ViewManagerEpoch;
+2 -2
View File
@@ -5,14 +5,14 @@ import { MicrophoneState } from '../../card-controller/types.js';
import { ViewManagerEpoch } from '../../card-controller/view/types.js';
import { LiveController } from '../../components-lib/live/live-controller.js';
import { CardWideConfig, LiveConfig } from '../../config/types.js';
import { HomeAssistant } from '../../ha/types.js';
import basicBlockStyle from '../../scss/basic-block.scss';
import { ExtendedHomeAssistant } from '../../types.js';
import './grid.js';
@customElement('advanced-camera-card-live')
export class AdvancedCameraCardLive extends LitElement {
@property({ attribute: false })
public hass?: ExtendedHomeAssistant;
public hass?: HomeAssistant;
@property({ attribute: false })
public viewManagerEpoch?: ViewManagerEpoch;
+3 -7
View File
@@ -22,14 +22,10 @@ import {
LiveProvider,
} from '../../config/types.js';
import { STREAM_TROUBLESHOOTING_URL } from '../../const.js';
import { HomeAssistant } from '../../ha/types.js';
import { localize } from '../../localize/localize.js';
import liveProviderStyle from '../../scss/live-provider.scss';
import {
ExtendedHomeAssistant,
MediaPlayer,
MediaPlayerController,
MediaPlayerElement,
} from '../../types.js';
import { MediaPlayer, MediaPlayerController, MediaPlayerElement } from '../../types.js';
import { aspectRatioToString } from '../../utils/basic.js';
import { dispatchMediaUnloadedEvent } from '../../utils/media-info.js';
import { updateElementStyleFromMediaLayoutConfig } from '../../utils/media-layout.js';
@@ -42,7 +38,7 @@ import '../surround.js';
@customElement('advanced-camera-card-live-provider')
export class AdvancedCameraCardLiveProvider extends LitElement implements MediaPlayer {
@property({ attribute: false })
public hass?: ExtendedHomeAssistant;
public hass?: HomeAssistant;
@property({ attribute: false })
public cameraConfig?: CameraConfig;
@@ -12,14 +12,10 @@ import { MicrophoneState } from '../../../../card-controller/types.js';
import { dispatchLiveErrorEvent } from '../../../../components-lib/live/utils/dispatch-live-error.js';
import { VideoMediaPlayerController } from '../../../../components-lib/media-player/video.js';
import { CameraConfig, MicrophoneConfig } from '../../../../config/types.js';
import { HomeAssistant } from '../../../../ha/types.js';
import { localize } from '../../../../localize/localize.js';
import liveGo2RTCStyle from '../../../../scss/live-go2rtc.scss';
import {
ExtendedHomeAssistant,
MediaPlayer,
MediaPlayerController,
Message,
} from '../../../../types.js';
import { MediaPlayer, MediaPlayerController, Message } from '../../../../types.js';
import { convertEndpointAddressToSignedWebsocket } from '../../../../utils/endpoint.js';
import { renderMessage } from '../../../message.js';
import { VideoRTC } from './video-rtc.js';
@@ -36,7 +32,7 @@ const GO2RTC_URL_SIGN_EXPIRY_SECONDS = 24 * 60 * 60;
@customElement('advanced-camera-card-live-go2rtc')
export class AdvancedCameraCardGo2RTC extends LitElement implements MediaPlayer {
// Not an reactive property to avoid resetting the video.
public hass?: ExtendedHomeAssistant;
public hass?: HomeAssistant;
@property({ attribute: false })
public cameraConfig?: CameraConfig;
+1 -1
View File
@@ -1,8 +1,8 @@
import { HomeAssistant } from '@dermotduffy/custom-card-helpers';
import { CSSResultGroup, html, LitElement, TemplateResult, unsafeCSS } from 'lit';
import { customElement, property } from 'lit/decorators.js';
import { createRef, Ref, ref } from 'lit/directives/ref.js';
import { CameraConfig } from '../../../config/types';
import { HomeAssistant } from '../../../ha/types';
import '../../../patches/ha-camera-stream';
import '../../../patches/ha-hls-player.js';
import '../../../patches/ha-web-rtc-player.js';
+1 -1
View File
@@ -1,8 +1,8 @@
import { HomeAssistant } from '@dermotduffy/custom-card-helpers';
import { CSSResultGroup, html, LitElement, TemplateResult, unsafeCSS } from 'lit';
import { customElement, property } from 'lit/decorators.js';
import { createRef, ref, Ref } from 'lit/directives/ref.js';
import { CameraConfig } from '../../../config/types';
import { HomeAssistant } from '../../../ha/types';
import basicBlockStyle from '../../../scss/basic-block.scss';
import {
MediaPlayer,
+3 -7
View File
@@ -13,14 +13,10 @@ import { CameraEndpoints } from '../../../camera-manager/types.js';
import { dispatchLiveErrorEvent } from '../../../components-lib/live/utils/dispatch-live-error.js';
import { JSMPEGMediaPlayerController } from '../../../components-lib/media-player/jsmpeg.js';
import { CameraConfig, CardWideConfig } from '../../../config/types.js';
import { HomeAssistant } from '../../../ha/types.js';
import { localize } from '../../../localize/localize.js';
import liveJSMPEGStyle from '../../../scss/live-jsmpeg.scss';
import {
ExtendedHomeAssistant,
MediaPlayer,
MediaPlayerController,
Message,
} from '../../../types.js';
import { MediaPlayer, MediaPlayerController, Message } from '../../../types.js';
import { convertEndpointAddressToSignedWebsocket } from '../../../utils/endpoint.js';
import {
dispatchMediaLoadedEvent,
@@ -41,7 +37,7 @@ const JSMPEG_URL_SIGN_REFRESH_THRESHOLD_SECONDS = 1 * 60 * 60;
@customElement('advanced-camera-card-live-jsmpeg')
export class AdvancedCameraCardLiveJSMPEG extends LitElement implements MediaPlayer {
protected hass?: ExtendedHomeAssistant;
protected hass?: HomeAssistant;
@property({ attribute: false })
public cameraConfig?: CameraConfig;
+1 -1
View File
@@ -1,4 +1,3 @@
import { HomeAssistant } from '@dermotduffy/custom-card-helpers';
import { Task } from '@lit-labs/task';
import {
CSSResultGroup,
@@ -14,6 +13,7 @@ import { dispatchLiveErrorEvent } from '../../../components-lib/live/utils/dispa
import { getTechnologyForVideoRTC } from '../../../components-lib/live/utils/get-technology-for-video-rtc.js';
import { VideoMediaPlayerController } from '../../../components-lib/media-player/video.js';
import { CameraConfig, CardWideConfig } from '../../../config/types.js';
import { HomeAssistant } from '../../../ha/types.js';
import { localize } from '../../../localize/localize.js';
import liveWebRTCCardStyle from '../../../scss/live-webrtc-card.scss';
import {
+2 -2
View File
@@ -1,4 +1,3 @@
import { HomeAssistant } from '@dermotduffy/custom-card-helpers';
import { ScopedRegistryHost } from '@lit-labs/scoped-registry-mixin';
import {
CSSResultGroup,
@@ -12,6 +11,7 @@ import { customElement, property } from 'lit/decorators.js';
import { classMap } from 'lit/directives/class-map.js';
import { createRef, ref, Ref } from 'lit/directives/ref.js';
import { CameraManager } from '../camera-manager/manager';
import { ViewManagerEpoch } from '../card-controller/view/types';
import {
MediaFilterController,
MediaFilterCoreFavoriteSelection,
@@ -19,13 +19,13 @@ import {
MediaFilterMediaType,
} from '../components-lib/media-filter-controller';
import { CardWideConfig } from '../config/types';
import { HomeAssistant } from '../ha/types';
import { localize } from '../localize/localize';
import mediaFilterStyle from '../scss/media-filter.scss';
import { AdvancedCameraCardDatePicker } from './date-picker';
import './date-picker.js';
import { AdvancedCameraCardSelect } from './select';
import './select.js';
import { ViewManagerEpoch } from '../card-controller/view/types';
@customElement('advanced-camera-card-media-filter')
class AdvancedCameraCardMediaFilter extends ScopedRegistryHost(LitElement) {
+1 -1
View File
@@ -1,10 +1,10 @@
import { HomeAssistant } from '@dermotduffy/custom-card-helpers';
import { CSSResultGroup, LitElement, TemplateResult, html, unsafeCSS } from 'lit';
import { customElement, property } from 'lit/decorators.js';
import { styleMap } from 'lit/directives/style-map.js';
import { actionHandler } from '../action-handler-directive.js';
import { MenuController } from '../components-lib/menu-controller.js';
import type { MenuConfig, MenuItem } from '../config/types.js';
import { HomeAssistant } from '../ha/types.js';
import menuStyle from '../scss/menu.scss';
import { hasAction } from '../utils/action.js';
import { getEntityTitle } from '../utils/ha/index.js';
+1 -1
View File
@@ -1,8 +1,8 @@
import { HomeAssistant } from '@dermotduffy/custom-card-helpers';
import { CSSResultGroup, LitElement, TemplateResult, html, unsafeCSS } from 'lit';
import { customElement, property, state } from 'lit/decorators.js';
import { classMap } from 'lit/directives/class-map.js';
import { NextPreviousControlConfig } from '../config/types.js';
import { HomeAssistant } from '../ha/types.js';
import controlStyle from '../scss/next-previous-control.scss';
import { Icon } from '../types.js';
import { renderTask } from '../utils/task.js';
+1 -1
View File
@@ -1,4 +1,3 @@
import { HomeAssistant } from '@dermotduffy/custom-card-helpers';
import {
CSSResultGroup,
LitElement,
@@ -14,6 +13,7 @@ import { CameraManager } from '../camera-manager/manager.js';
import { PTZController } from '../components-lib/ptz/ptz-controller.js';
import { PTZControllerActions } from '../components-lib/ptz/types.js';
import { Actions, PTZControlsConfig } from '../config/types.js';
import { HomeAssistant } from '../ha/types.js';
import { localize } from '../localize/localize.js';
import ptzStyle from '../scss/ptz.scss';
import { Interaction } from '../types.js';
+3 -2
View File
@@ -9,7 +9,8 @@ import {
import { property } from 'lit/decorators.js';
import { createRef, ref, Ref } from 'lit/directives/ref.js';
import selectStyle from '../scss/select.scss';
import { contentsChanged, dispatchAdvancedCameraCardEvent } from '../utils/basic';
import { contentsChanged } from '../utils/basic';
import { fireAdvancedCameraCardEvent } from '../utils/fire-advanced-camera-card-event';
import { ScopedRegistryHost } from '@lit-labs/scoped-registry-mixin';
import { grSelectElements } from '../scoped-elements/gr-select';
import isEqual from 'lodash-es/isEqual';
@@ -73,7 +74,7 @@ export class AdvancedCameraCardSelect extends ScopedRegistryHost(LitElement) {
// (even when the user has not interacted with the control). Do not
// dispatch events for this.
if (!initialValueSet) {
dispatchAdvancedCameraCardEvent(this, 'select:change', value);
fireAdvancedCameraCardEvent(this, 'select:change', value);
}
}
}
+1 -1
View File
@@ -1,9 +1,9 @@
import { HomeAssistant } from '@dermotduffy/custom-card-helpers';
import { CSSResultGroup, html, LitElement, TemplateResult, unsafeCSS } from 'lit';
import { customElement, property } from 'lit/decorators.js';
import { ifDefined } from 'lit/directives/if-defined.js';
import { styleMap } from 'lit/directives/style-map.js';
import { actionHandler } from '../../action-handler-directive.js';
import { HomeAssistant } from '../../ha/types.js';
import submenuStyle from '../../scss/submenu.scss';
import {
hasAction,
+1 -1
View File
@@ -1,4 +1,3 @@
import { HomeAssistant } from '@dermotduffy/custom-card-helpers';
import {
CSSResultGroup,
html,
@@ -10,6 +9,7 @@ import {
import { customElement, property, state } from 'lit/decorators.js';
import { styleMap } from 'lit/directives/style-map.js';
import { MenuSubmenu, MenuSubmenuItem, MenuSubmenuSelect } from '../../config/types.js';
import { HomeAssistant } from '../../ha/types.js';
import menuButtonStyle from '../../scss/menu-button.scss';
import { getEntityTitle, isHassDifferent } from '../../utils/ha';
import { getEntityStateTranslation } from '../../utils/ha/entity-state-translation.js';
+2 -1
View File
@@ -1,9 +1,10 @@
import { hasAction, HomeAssistant } from '@dermotduffy/custom-card-helpers';
import { CSSResultGroup, html, LitElement, TemplateResult, unsafeCSS } from 'lit';
import { customElement, property } from 'lit/decorators.js';
import { styleMap } from 'lit/directives/style-map.js';
import { actionHandler } from '../../action-handler-directive.js';
import { MenuSubmenu } from '../../config/types.js';
import { hasAction } from '../../ha/has-action.js';
import { HomeAssistant } from '../../ha/types.js';
import menuButtonStyle from '../../scss/menu-button.scss';
import '../icon.js';
import './index.js';
+5 -4
View File
@@ -15,16 +15,17 @@ import {
MiniTimelineControlConfig,
ThumbnailsControlConfig,
} from '../config/types.js';
import { HomeAssistant } from '../ha/types.js';
import basicBlockStyle from '../scss/basic-block.scss';
import { ExtendedHomeAssistant } from '../types.js';
import { contentsChanged, dispatchAdvancedCameraCardEvent } from '../utils/basic.js';
import { contentsChanged } from '../utils/basic.js';
import { fireAdvancedCameraCardEvent } from '../utils/fire-advanced-camera-card-event.js';
import './surround-basic.js';
import { ThumbnailCarouselTap } from './thumbnail-carousel.js';
@customElement('advanced-camera-card-surround')
export class AdvancedCameraCardSurround extends LitElement {
@property({ attribute: false })
public hass?: ExtendedHomeAssistant;
public hass?: HomeAssistant;
@property({ attribute: false })
public viewManagerEpoch?: ViewManagerEpoch;
@@ -112,7 +113,7 @@ export class AdvancedCameraCardSurround extends LitElement {
// from the origin of the inbound event, so it can be handled by
// <advanced-camera-card-surround> .
if (this.thumbnailConfig && this._hasDrawer()) {
dispatchAdvancedCameraCardEvent(ev.composedPath()[0], 'drawer:' + action, {
fireAdvancedCameraCardEvent(ev.composedPath()[0], 'drawer:' + action, {
drawer: this.thumbnailConfig.mode,
});
}
+4 -4
View File
@@ -11,11 +11,11 @@ import { classMap } from 'lit/directives/class-map.js';
import { CameraManager } from '../camera-manager/manager.js';
import { ViewManagerEpoch } from '../card-controller/view/types.js';
import { ThumbnailsControlConfig } from '../config/types.js';
import { HomeAssistant } from '../ha/types.js';
import thumbnailCarouselStyle from '../scss/thumbnail-carousel.scss';
import { ExtendedHomeAssistant } from '../types.js';
import { stopEventFromActivatingCardWideActions } from '../utils/action.js';
import { dispatchAdvancedCameraCardEvent } from '../utils/basic.js';
import { CarouselDirection } from '../utils/embla/carousel-controller.js';
import { fireAdvancedCameraCardEvent } from '../utils/fire-advanced-camera-card-event.js';
import { MediaQueriesResults } from '../view/media-queries-results';
import './carousel.js';
import './thumbnail.js';
@@ -27,7 +27,7 @@ export interface ThumbnailCarouselTap {
@customElement('advanced-camera-card-thumbnail-carousel')
export class AdvancedCameraCardThumbnailCarousel extends LitElement {
@property({ attribute: false })
public hass?: ExtendedHomeAssistant;
public hass?: HomeAssistant;
@property({ attribute: false })
public viewManagerEpoch?: ViewManagerEpoch;
@@ -111,7 +111,7 @@ export class AdvancedCameraCardThumbnailCarousel extends LitElement {
@click=${(ev: Event) => {
const view = this.viewManagerEpoch?.manager.getView();
if (view && view.queryResults) {
dispatchAdvancedCameraCardEvent<ThumbnailCarouselTap>(
fireAdvancedCameraCardEvent<ThumbnailCarouselTap>(
this,
'thumbnail-carousel:tap',
{
+3 -3
View File
@@ -15,12 +15,12 @@ import { CameraManagerCameraMetadata } from '../camera-manager/types.js';
import { RemoveContextViewModifier } from '../card-controller/view/modifiers/remove-context.js';
import { ViewManagerEpoch } from '../card-controller/view/types.js';
import { dispatchAdvancedCameraCardErrorEvent } from '../components-lib/message/dispatch.js';
import { HomeAssistant } from '../ha/types.js';
import { localize } from '../localize/localize.js';
import thumbnailDetailsStyle from '../scss/thumbnail-details.scss';
import thumbnailFeatureTextStyle from '../scss/thumbnail-feature-text.scss';
import thumbnailFeatureThumbnailStyle from '../scss/thumbnail-feature-thumbnail.scss';
import thumbnailStyle from '../scss/thumbnail.scss';
import type { ExtendedHomeAssistant } from '../types.js';
import { stopEventFromActivatingCardWideActions } from '../utils/action.js';
import {
errorToConsole,
@@ -43,7 +43,7 @@ export class AdvancedCameraCardThumbnailFeatureThumbnail extends LitElement {
public thumbnail?: string;
@property({ attribute: false })
public hass?: ExtendedHomeAssistant;
public hass?: HomeAssistant;
@state()
protected _thumbnailError = false;
@@ -368,7 +368,7 @@ export class AdvancedCameraCardThumbnail extends LitElement {
// a re-render. The HomeAssistant object may be required for thumbnail signing
// (after initial signing the thumbnail is stored in a data URL, so the
// signing will not expire).
public hass?: ExtendedHomeAssistant;
public hass?: HomeAssistant;
// Performance: During timeline scrubbing, the view will be updated
// continuously. As it is not needed for the thumbnail rendering itself, it
+5 -5
View File
@@ -46,19 +46,19 @@ import {
TimelinePanMode,
configDefaults,
} from '../config/types';
import { HomeAssistant } from '../ha/types';
import { localize } from '../localize/localize';
import timelineCoreStyle from '../scss/timeline-core.scss';
import { ExtendedHomeAssistant } from '../types';
import { stopEventFromActivatingCardWideActions } from '../utils/action';
import {
contentsChanged,
dispatchAdvancedCameraCardEvent,
formatDateAndTime,
isHoverableDevice,
isTruthy,
setOrRemoveAttribute,
} from '../utils/basic';
import { findBestMediaIndex } from '../utils/find-best-media-index';
import { fireAdvancedCameraCardEvent } from '../utils/fire-advanced-camera-card-event';
import { ViewMedia } from '../view/media';
import { ViewMediaClassifier } from '../view/media-classifier';
import {
@@ -108,7 +108,7 @@ interface ExtendedTimeline extends Timeline {
// note below on why this is necessary.
interface ThumbnailDataRequest {
item: IdType;
hass?: ExtendedHomeAssistant;
hass?: HomeAssistant;
cameraManager?: CameraManager;
cameraConfig?: CameraConfig;
media?: ViewMedia;
@@ -187,7 +187,7 @@ export class AdvancedCameraCardTimelineThumbnail extends LitElement {
@customElement('advanced-camera-card-timeline-core')
export class AdvancedCameraCardTimelineCore extends LitElement {
@property({ attribute: false })
public hass?: ExtendedHomeAssistant;
public hass?: HomeAssistant;
@property({ attribute: false })
public viewManagerEpoch?: ViewManagerEpoch;
@@ -632,7 +632,7 @@ export class AdvancedCameraCardTimelineCore extends LitElement {
}
}
dispatchAdvancedCameraCardEvent(this, `thumbnails:${drawerAction}`);
fireAdvancedCameraCardEvent(this, `thumbnails:${drawerAction}`);
this._ignoreClick = false;
}
+2 -2
View File
@@ -3,15 +3,15 @@ import { customElement, property } from 'lit/decorators.js';
import { CameraManager } from '../camera-manager/manager';
import { ViewManagerEpoch } from '../card-controller/view/types';
import { CardWideConfig, TimelineConfig } from '../config/types';
import { HomeAssistant } from '../ha/types';
import basicBlockStyle from '../scss/basic-block.scss';
import { ExtendedHomeAssistant } from '../types';
import './surround.js';
import './timeline-core.js';
@customElement('advanced-camera-card-timeline')
export class AdvancedCameraCardTimeline extends LitElement {
@property({ attribute: false })
public hass?: ExtendedHomeAssistant;
public hass?: HomeAssistant;
@property({ attribute: false })
public viewManagerEpoch?: ViewManagerEpoch;
+3 -6
View File
@@ -19,14 +19,11 @@ import {
TransitionEffect,
ViewerConfig,
} from '../../config/types.js';
import { HomeAssistant } from '../../ha/types.js';
import { localize } from '../../localize/localize.js';
import '../../patches/ha-hls-player.js';
import viewerCarouselStyle from '../../scss/viewer-carousel.scss';
import {
ExtendedHomeAssistant,
MediaLoadedInfo,
MediaPlayerController,
} from '../../types.js';
import { MediaLoadedInfo, MediaPlayerController } from '../../types.js';
import { stopEventFromActivatingCardWideActions } from '../../utils/action.js';
import { contentsChanged, setOrRemoveAttribute } from '../../utils/basic.js';
import { CarouselSelected } from '../../utils/embla/carousel-controller.js';
@@ -59,7 +56,7 @@ const ADVANCED_CAMERA_CARD_VIEWER_PROVIDER = 'advanced-camera-card-viewer-provid
@customElement('advanced-camera-card-viewer-carousel')
export class AdvancedCameraCardViewerCarousel extends LitElement {
@property({ attribute: false })
public hass?: ExtendedHomeAssistant;
public hass?: HomeAssistant;
@property({ attribute: false })
public viewManagerEpoch?: ViewManagerEpoch;
+2 -2
View File
@@ -12,16 +12,16 @@ import { CameraManager } from '../../camera-manager/manager.js';
import { ViewManagerEpoch } from '../../card-controller/view/types.js';
import { MediaGridSelected } from '../../components-lib/media-grid-controller.js';
import { CardWideConfig, ViewerConfig } from '../../config/types.js';
import { HomeAssistant } from '../../ha/types.js';
import '../../patches/ha-hls-player.js';
import basicBlockStyle from '../../scss/basic-block.scss';
import { ExtendedHomeAssistant } from '../../types.js';
import { ResolvedMediaCache } from '../../utils/ha/resolved-media.js';
import './carousel';
@customElement('advanced-camera-card-viewer-grid')
export class AdvancedCameraCardViewerGrid extends LitElement {
@property({ attribute: false })
public hass?: ExtendedHomeAssistant;
public hass?: HomeAssistant;
@property({ attribute: false })
public viewManagerEpoch?: ViewManagerEpoch;
+2 -2
View File
@@ -3,10 +3,10 @@ import { customElement, property } from 'lit/decorators.js';
import { CameraManager } from '../../camera-manager/manager.js';
import { ViewManagerEpoch } from '../../card-controller/view/types.js';
import { CardWideConfig, ViewerConfig } from '../../config/types.js';
import { HomeAssistant } from '../../ha/types.js';
import { localize } from '../../localize/localize.js';
import '../../patches/ha-hls-player.js';
import viewerStyle from '../../scss/viewer.scss';
import { ExtendedHomeAssistant } from '../../types.js';
import { ResolvedMediaCache } from '../../utils/ha/resolved-media.js';
import { renderMessage } from '../message.js';
import './grid';
@@ -24,7 +24,7 @@ declare module 'view' {
@customElement('advanced-camera-card-viewer')
export class AdvancedCameraCardViewer extends LitElement {
@property({ attribute: false })
public hass?: ExtendedHomeAssistant;
public hass?: HomeAssistant;
@property({ attribute: false })
public viewManagerEpoch?: ViewManagerEpoch;
+2 -2
View File
@@ -14,10 +14,10 @@ import { ViewManagerEpoch } from '../../card-controller/view/types.js';
import { ZoomSettingsObserved } from '../../components-lib/zoom/types.js';
import { handleZoomSettingsObservedEvent } from '../../components-lib/zoom/zoom-view-context.js';
import { CardWideConfig, ViewerConfig } from '../../config/types.js';
import { HomeAssistant } from '../../ha/types.js';
import '../../patches/ha-hls-player.js';
import viewerProviderStyle from '../../scss/viewer-provider.scss';
import {
ExtendedHomeAssistant,
MediaPlayer,
MediaPlayerController,
MediaPlayerElement,
@@ -46,7 +46,7 @@ import '../video-player.js';
@customElement('advanced-camera-card-viewer-provider')
export class AdvancedCameraCardViewerProvider extends LitElement implements MediaPlayer {
@property({ attribute: false })
public hass?: ExtendedHomeAssistant;
public hass?: HomeAssistant;
@property({ attribute: false })
public viewManagerEpoch?: ViewManagerEpoch;
+2 -2
View File
@@ -16,8 +16,8 @@ import {
CardWideConfig,
RawAdvancedCameraCardConfig,
} from '../config/types.js';
import { HomeAssistant } from '../ha/types.js';
import viewsStyle from '../scss/views.scss';
import { ExtendedHomeAssistant } from '../types.js';
import { DeviceRegistryManager } from '../utils/ha/registry/device/index.js';
import { ResolvedMediaCache } from '../utils/ha/resolved-media.js';
import './surround.js';
@@ -29,7 +29,7 @@ import './diagnostics.js';
@customElement('advanced-camera-card-views')
export class AdvancedCameraCardViews extends LitElement {
@property({ attribute: false })
public hass?: ExtendedHomeAssistant;
public hass?: HomeAssistant;
@property({ attribute: false })
public viewManagerEpoch?: ViewManagerEpoch;
+3 -3
View File
@@ -1,8 +1,8 @@
import { CurrentUser } from '@dermotduffy/custom-card-helpers';
import { HassEntities } from 'home-assistant-js-websocket';
import { AdvancedCameraCardConfig, ViewDisplayMode } from '../config/types';
import { MediaLoadedInfo } from '../types';
import { KeysState, MicrophoneState } from '../card-controller/types';
import { AdvancedCameraCardConfig, ViewDisplayMode } from '../config/types';
import { CurrentUser } from '../ha/types';
import { MediaLoadedInfo } from '../types';
export interface ConditionState {
camera?: string;
+4 -4
View File
@@ -1,3 +1,6 @@
import { HassServiceTarget } from 'home-assistant-js-websocket';
import { z } from 'zod';
import { MEDIA_CHUNK_SIZE_DEFAULT, MEDIA_CHUNK_SIZE_MAX } from '../const.js';
import {
CallServiceActionConfig,
ConfirmationRestrictionConfig,
@@ -7,10 +10,7 @@ import {
PerformActionActionConfig,
ToggleActionConfig,
UrlActionConfig,
} from '@dermotduffy/custom-card-helpers';
import { HassServiceTarget } from 'home-assistant-js-websocket';
import { z } from 'zod';
import { MEDIA_CHUNK_SIZE_DEFAULT, MEDIA_CHUNK_SIZE_MAX } from '../const.js';
} from '../ha/types.js';
import { capabilityKeys } from '../types.js';
import { deepRemoveDefaults } from '../utils/zod.js';
import {
+3 -6
View File
@@ -1,8 +1,3 @@
import {
fireEvent,
HomeAssistant,
LovelaceCardEditor,
} from '@dermotduffy/custom-card-helpers';
import { CSSResultGroup, html, LitElement, TemplateResult, unsafeCSS } from 'lit';
import { customElement, property, state } from 'lit/decorators.js';
import { classMap } from 'lit/directives/class-map.js';
@@ -238,6 +233,8 @@ import {
CONF_VIEW_TRIGGERS_UNTRIGGER_SECONDS,
MEDIA_CHUNK_SIZE_MAX,
} from './const.js';
import { fireHASSEvent } from './ha/fire-hass-event.js';
import { HomeAssistant, LovelaceCardEditor } from './ha/types.js';
import { localize } from './localize/localize.js';
import editorStyle from './scss/editor.scss';
import { arrayMove, prettifyTitle } from './utils/basic.js';
@@ -2510,7 +2507,7 @@ export class AdvancedCameraCardEditor extends LitElement implements LovelaceCard
protected _updateConfig(config: RawAdvancedCameraCardConfig): void {
this._config = config;
fireEvent(this, 'config-changed', { config: this._config });
fireHASSEvent(this, 'config-changed', { config: this._config });
}
protected render(): TemplateResult | void {
+21
View File
@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2019 Custom cards for Home Assistant
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+7
View File
@@ -0,0 +1,7 @@
# Background
Some of these functions are inspired by or modified from the unmaintained
https://github.com/custom-cards/custom-card-helpers .
This directory is intended to contain usage agnostic Home Assistant
functionality.
+3
View File
@@ -0,0 +1,3 @@
export const computeDomain = (entityId: string): string => {
return entityId.substring(0, entityId.indexOf('.'));
};
+2
View File
@@ -0,0 +1,2 @@
export const STATES_OFF = ['closed', 'locked', 'off'];
export const STATES_ON = ['open', 'unlocked', 'on'];
+25
View File
@@ -0,0 +1,25 @@
import { ValidHassDomEvent } from './types';
/**
* Fire an event has per Home Assistant frontend specifications. All events
* fired by this method has expected content/behavior based on type.
*/
export const fireHASSEvent = <HassEvent extends ValidHassDomEvent>(
target: EventTarget,
type: HassEvent,
detail?: HASSDomEvents[HassEvent],
options?: {
bubbles?: boolean;
cancelable?: boolean;
composed?: boolean;
},
) => {
target.dispatchEvent(
new CustomEvent<HASSDomEvents[HassEvent]>(type, {
bubbles: options?.bubbles ?? true,
composed: options?.composed ?? true,
cancelable: options?.cancelable ?? false,
detail: detail,
}),
);
};
+90
View File
@@ -0,0 +1,90 @@
import { fireHASSEvent } from './fire-hass-event.js';
import { forwardHaptic } from './haptic.js';
import { navigate } from './navigate.js';
import { toggleEntity } from './toggle-entity.js';
import { ActionConfig, HomeAssistant } from './types.js';
export const handleActionConfig = (
node: HTMLElement,
hass: HomeAssistant,
config: {
entity?: string;
camera_image?: string;
hold_action?: ActionConfig;
tap_action?: ActionConfig;
double_tap_action?: ActionConfig;
},
actionConfig: ActionConfig | undefined,
): void => {
if (!actionConfig) {
actionConfig = {
action: 'more-info',
};
}
if (
actionConfig.confirmation &&
(!actionConfig.confirmation.exemptions ||
!actionConfig.confirmation.exemptions.some((e) => e.user === hass!.user!.id))
) {
forwardHaptic('warning');
if (
!confirm(
actionConfig.confirmation.text ||
`Are you sure you want to ${actionConfig.action}?`,
)
) {
return;
}
}
switch (actionConfig.action) {
case 'more-info':
if (config.entity || config.camera_image) {
fireHASSEvent(node, 'hass-more-info', {
entityId: config.entity ? config.entity : config.camera_image!,
});
}
break;
case 'navigate':
if (actionConfig.navigation_path) {
navigate(node, actionConfig.navigation_path);
}
break;
case 'url':
if (actionConfig.url_path) {
window.open(actionConfig.url_path);
}
break;
case 'toggle':
if (config.entity) {
toggleEntity(hass, config.entity!);
forwardHaptic('success');
}
break;
case 'perform-action': {
if (!actionConfig.perform_action) {
forwardHaptic('failure');
return;
}
const [domain, service] = actionConfig.perform_action.split('.', 2);
hass.callService(domain, service, actionConfig.data, actionConfig.target);
forwardHaptic('success');
break;
}
case 'call-service': {
if (!actionConfig.service) {
forwardHaptic('failure');
return;
}
const [domain, service] = actionConfig.service.split('.', 2);
hass.callService(domain, service, actionConfig.data, actionConfig.target);
forwardHaptic('success');
break;
}
case 'fire-dom-event': {
fireHASSEvent(node, 'll-custom', actionConfig);
}
}
};
+30
View File
@@ -0,0 +1,30 @@
/**
* Broadcast haptic feedback requests
*/
import { fireHASSEvent } from './fire-hass-event';
// Allowed types are from iOS HIG.
// https://developer.apple.com/design/human-interface-guidelines/ios/user-interaction/feedback/#haptics
// Implementors on platforms other than iOS should attempt to match the patterns (shown in HIG) as closely as possible.
export type HapticType =
| 'success'
| 'warning'
| 'failure'
| 'light'
| 'medium'
| 'heavy'
| 'selection';
declare global {
interface HASSDomEvents {
haptic: HapticType;
}
interface GlobalEventHandlersEventMap {
haptic: CustomEvent<HapticType>;
}
}
export const forwardHaptic = (hapticType: HapticType) => {
fireHASSEvent(window, 'haptic', hapticType);
};
+5
View File
@@ -0,0 +1,5 @@
import { ActionConfig } from './types.js';
export function hasAction(config?: ActionConfig): boolean {
return config !== undefined && config.action !== 'none';
}
+20
View File
@@ -0,0 +1,20 @@
import { fireHASSEvent } from './fire-hass-event.js';
declare global {
interface HASSDomEvents {
'location-changed': {
replace: boolean;
};
}
}
export const navigate = (_node: unknown, path: string, replace: boolean = false) => {
if (replace) {
history.replaceState(null, '', path);
} else {
history.pushState(null, '', path);
}
fireHASSEvent(window, 'location-changed', {
replace,
});
};
+8
View File
@@ -0,0 +1,8 @@
import { STATES_OFF } from './const.js';
import { turnOnOffEntity } from './turn-on-off-entity.js';
import { HomeAssistant } from './types.js';
export const toggleEntity = (hass: HomeAssistant, entityId: string): Promise<void> => {
const turnOn = STATES_OFF.includes(hass.states[entityId].state);
return turnOnOffEntity(hass, entityId, turnOn);
};
+25
View File
@@ -0,0 +1,25 @@
import { HomeAssistant } from './types.js';
import { computeDomain } from './compute-domain.js';
export const turnOnOffEntity = (
hass: HomeAssistant,
entityId: string,
turnOn = true,
): Promise<void> => {
const stateDomain = computeDomain(entityId);
const serviceDomain = stateDomain === 'group' ? 'homeassistant' : stateDomain;
let service;
switch (stateDomain) {
case 'lock':
service = turnOn ? 'unlock' : 'lock';
break;
case 'cover':
service = turnOn ? 'open_cover' : 'close_cover';
break;
default:
service = turnOn ? 'turn_on' : 'turn_off';
}
return hass.callService(serviceDomain, service, { entity_id: entityId });
};
+316
View File
@@ -0,0 +1,316 @@
import {
Auth,
Connection,
HassConfig,
HassEntities,
HassServices,
HassServiceTarget,
MessageBase,
} from 'home-assistant-js-websocket';
import { HapticType } from './haptic.js';
interface ToggleMenuActionConfig extends BaseActionConfig {
action: 'toggle-menu';
}
export interface ToggleActionConfig extends BaseActionConfig {
action: 'toggle';
}
export interface CallServiceActionConfig extends BaseActionConfig {
action: 'call-service';
service: string;
data?: {
entity_id?: string | [string];
[key: string]: unknown;
};
target?: HassServiceTarget;
repeat?: number;
haptic?: HapticType;
}
export interface PerformActionActionConfig extends BaseActionConfig {
action: 'perform-action';
perform_action: string;
data?: {
entity_id?: string | [string];
[key: string]: unknown;
};
target?: HassServiceTarget;
repeat?: number;
haptic?: HapticType;
}
export interface NavigateActionConfig extends BaseActionConfig {
action: 'navigate';
navigation_path: string;
}
export interface UrlActionConfig extends BaseActionConfig {
action: 'url';
url_path: string;
}
export interface MoreInfoActionConfig extends BaseActionConfig {
action: 'more-info';
entity?: string;
}
export interface NoActionConfig extends BaseActionConfig {
action: 'none';
}
interface CustomActionConfig extends BaseActionConfig {
action: 'fire-dom-event';
}
/**
* `repeat` and `haptic` are specifically for use in custom cards like the Button-Card
*/
interface BaseActionConfig {
confirmation?: ConfirmationRestrictionConfig;
repeat?: number;
haptic?: HapticType;
}
export interface ConfirmationRestrictionConfig {
text?: string;
exemptions?: RestrictionConfig[];
}
interface RestrictionConfig {
user: string;
}
export declare type ActionConfig =
| ToggleActionConfig
| CallServiceActionConfig
| PerformActionActionConfig
| NavigateActionConfig
| UrlActionConfig
| MoreInfoActionConfig
| NoActionConfig
| CustomActionConfig
| ToggleMenuActionConfig;
declare global {
interface HASSDomEvents {
'value-changed': {
value: unknown;
};
'config-changed': {
config: unknown;
};
'hass-more-info': {
entityId: string | undefined;
};
'll-rebuild': object;
'll-custom': object;
'location-changed': {
replace: boolean;
};
'show-dialog': object;
undefined: unknown;
action: {
action: string;
};
}
}
export type ValidHassDomEvent = keyof HASSDomEvents;
declare type LocalizeFunc = (key: string, ...args: unknown[]) => string;
interface Credential {
auth_provider_type: string;
auth_provider_id: string;
}
interface MFAModule {
id: string;
name: string;
enabled: boolean;
}
export interface CurrentUser {
id: string;
is_owner: boolean;
is_admin: boolean;
name: string;
credentials: Credential[];
mfa_modules: MFAModule[];
}
interface Theme {
'primary-color': string;
'text-primary-color': string;
'accent-color': string;
}
interface Themes {
darkMode?: boolean;
default_theme: string;
themes: {
[key: string]: Theme;
};
}
interface Panel {
component_name: string;
config: {
[key: string]: unknown;
} | null;
icon: string | null;
title: string | null;
url_path: string;
}
interface Panels {
[name: string]: Panel;
}
interface Resources {
[language: string]: {
[key: string]: string;
};
}
interface Translation {
nativeName: string;
isRTL: boolean;
fingerprints: {
[fragment: string]: string;
};
}
export interface ServiceCallRequest {
domain: string;
service: string;
serviceData?: Record<string, unknown>;
target?: HassServiceTarget;
}
export interface HomeAssistant {
auth: Auth;
connection: Connection;
connected: boolean;
states: HassEntities;
services: HassServices;
config: HassConfig;
themes: Themes;
selectedTheme?: string | null;
panels: Panels;
panelUrl: string;
language: string;
locale: FrontendLocaleData;
selectedLanguage: string | null;
resources: Resources;
localize: LocalizeFunc;
translationMetadata: {
fragments: string[];
translations: {
[lang: string]: Translation;
};
};
dockedSidebar: boolean;
moreInfoEntityId: string;
user: CurrentUser;
callService: (
domain: ServiceCallRequest['domain'],
service: ServiceCallRequest['service'],
serviceData?: ServiceCallRequest['serviceData'],
target?: ServiceCallRequest['target'],
) => Promise<void>;
callApi: <T>(
method: 'GET' | 'POST' | 'PUT' | 'DELETE',
path: string,
parameters?: {
[key: string]: unknown;
},
) => Promise<T>;
fetchWithAuth: (
path: string,
init?: {
[key: string]: unknown;
},
) => Promise<Response>;
hassUrl(path?): string;
sendWS: (msg: MessageBase) => Promise<void>;
callWS: <T>(msg: MessageBase) => Promise<T>;
}
declare enum NumberFormat {
language = 'language',
system = 'system',
comma_decimal = 'comma_decimal',
decimal_comma = 'decimal_comma',
space_comma = 'space_comma',
none = 'none',
}
declare enum TimeFormat {
language = 'language',
system = 'system',
am_pm = '12',
twenty_four = '24',
}
interface FrontendLocaleData {
language: string;
number_format: NumberFormat;
time_format: TimeFormat;
}
export interface LovelaceCardConfig {
index?: number;
view_index?: number;
type: string;
[key: string]: unknown;
}
export interface LovelaceCard extends HTMLElement {
hass?: HomeAssistant;
isPanel?: boolean;
editMode?: boolean;
getCardSize(): number | Promise<number>;
setConfig(config: LovelaceCardConfig): void;
}
export interface LovelaceCardEditor extends HTMLElement {
hass?: HomeAssistant;
lovelace?: LovelaceConfig;
setConfig(config: LovelaceCardConfig): void;
}
interface LovelaceConfig {
title?: string;
views: LovelaceViewConfig[];
background?: string;
}
interface LovelaceViewConfig {
index?: number;
title?: string;
badges?: Array<string | LovelaceBadgeConfig>;
cards?: LovelaceCardConfig[];
path?: string;
icon?: string;
theme?: string;
panel?: boolean;
background?: string;
visible?: boolean | ShowViewConfig[];
}
interface ShowViewConfig {
user?: string;
}
interface LovelaceBadgeConfig {
type?: string;
[key: string]: unknown;
}
export interface ActionHandlerDetail {
action: string;
}
export interface ActionHandlerOptions {
hasHold?: boolean;
hasDoubleClick?: boolean;
}
+1 -1
View File
@@ -1,4 +1,4 @@
import { HomeAssistant } from '@dermotduffy/custom-card-helpers';
import { HomeAssistant } from '../ha/types';
import * as en from './languages/en.json';
const DEFAULT_LANG = 'en' as const;
+1 -14
View File
@@ -1,11 +1,5 @@
import {
HomeAssistant,
LovelaceCard,
LovelaceCardConfig,
LovelaceCardEditor,
Themes,
} from '@dermotduffy/custom-card-helpers';
import { z } from 'zod';
import { LovelaceCard, LovelaceCardConfig, LovelaceCardEditor } from './ha/types';
export type ClipsOrSnapshots = 'clips' | 'snapshots';
export type ClipsOrSnapshotsOrAll = 'clips' | 'snapshots' | 'all';
@@ -19,13 +13,6 @@ export class AdvancedCameraCardError extends Error {
}
}
export interface ExtendedHomeAssistant extends HomeAssistant {
hassUrl(path?): string;
themes: Themes & {
darkMode?: boolean;
};
}
export interface MediaLoadedCapabilities {
supports2WayAudio?: boolean;
supportsPause?: boolean;
+2 -5
View File
@@ -1,8 +1,3 @@
import {
ActionConfig,
ServiceCallRequest,
hasAction as customCardHasAction,
} from '@dermotduffy/custom-card-helpers';
import { CardActionsAPI } from '../card-controller/types.js';
import { ZoomSettingsBase } from '../components-lib/zoom/types.js';
import { PTZAction } from '../config/ptz.js';
@@ -29,6 +24,8 @@ import {
ViewActionConfig,
internalAdvancedCameraCardCustomActionSchema,
} from '../config/types.js';
import { hasAction as customCardHasAction } from '../ha/has-action.js';
import { ActionConfig, ServiceCallRequest } from '../ha/types.js';
import { arrayify } from './basic.js';
/**
-20
View File
@@ -13,26 +13,6 @@ import { AdvancedCameraCardError } from '../types';
export type ModifyInterface<T, R> = Omit<T, keyof R> & R;
/**
* Dispatch an Advanced Camera Card event.
* @param target The target from which send the event.
* @param name The name of the Advanced Camera Card event to send.
* @param detail An optional detail object to attach.
*/
export function dispatchAdvancedCameraCardEvent<T>(
target: EventTarget,
name: string,
detail?: T,
): void {
target.dispatchEvent(
new CustomEvent<T>(`advanced-camera-card:${name}`, {
bubbles: true,
composed: true,
detail: detail,
}),
);
}
/**
* Prettify a title by converting '_' to spaces and capitalizing words.
* @param input The input string.
+1 -1
View File
@@ -1,6 +1,6 @@
import { HomeAssistant } from '@dermotduffy/custom-card-helpers';
import pkg from '../../package.json';
import { RawAdvancedCameraCardConfig } from '../config/types';
import { HomeAssistant } from '../ha/types';
import { getLanguage } from '../localize/localize';
import { getIntegrationManifest } from './ha/integration';
import { IntegrationManifest } from './ha/integration/types';
+8 -7
View File
@@ -1,10 +1,11 @@
import { format } from 'date-fns';
import { CameraManager } from '../camera-manager/manager';
import { localize } from '../localize/localize';
import { AdvancedCameraCardError, ExtendedHomeAssistant } from '../types';
import { ViewMedia } from '../view/media';
import { errorToConsole } from './basic';
import { homeAssistantSignPath } from './ha';
import { CameraManager } from '../camera-manager/manager.js';
import { HomeAssistant } from '../ha/types.js';
import { localize } from '../localize/localize.js';
import { AdvancedCameraCardError } from '../types.js';
import { ViewMedia } from '../view/media.js';
import { errorToConsole } from './basic.js';
import { homeAssistantSignPath } from './ha/index.js';
export const downloadURL = (url: string, filename = 'download'): void => {
// The download attribute only works on the same origin.
@@ -27,7 +28,7 @@ export const downloadURL = (url: string, filename = 'download'): void => {
};
export const downloadMedia = async (
hass: ExtendedHomeAssistant,
hass: HomeAssistant,
cameraManager: CameraManager,
media: ViewMedia,
): Promise<void> => {
+4 -3
View File
@@ -3,7 +3,8 @@ import { WheelGesturesPlugin } from 'embla-carousel-wheel-gestures';
import { CreatePluginType, LoosePluginType } from 'embla-carousel/components/Plugins';
import isEqual from 'lodash-es/isEqual';
import { TransitionEffect } from '../../config/types';
import { dispatchAdvancedCameraCardEvent, getChildrenFromElement } from '../basic.js';
import { getChildrenFromElement } from '../basic.js';
import { fireAdvancedCameraCardEvent } from '../fire-advanced-camera-card-event';
import { TextDirection } from '../text-direction';
export interface CarouselSelected {
@@ -99,7 +100,7 @@ export class CarouselController {
// this is used.
const newSlide = this.getSlide(index);
if (newSlide) {
dispatchAdvancedCameraCardEvent<CarouselSelected>(
fireAdvancedCameraCardEvent<CarouselSelected>(
this._parent,
'carousel:force-select',
{
@@ -172,7 +173,7 @@ export class CarouselController {
const selectSlide = (): void => {
const carouselSelected = getCarouselSelectedObject();
if (carouselSelected) {
dispatchAdvancedCameraCardEvent<CarouselSelected>(
fireAdvancedCameraCardEvent<CarouselSelected>(
this._parent,
'carousel:select',
carouselSelected,
+2 -2
View File
@@ -1,10 +1,10 @@
import { CameraEndpoint } from '../camera-manager/types';
import { ExtendedHomeAssistant } from '../types';
import { HomeAssistant } from '../ha/types';
import { errorToConsole } from './basic';
import { homeAssistantSignPath } from './ha';
export const convertEndpointAddressToSignedWebsocket = async (
hass: ExtendedHomeAssistant,
hass: HomeAssistant,
endpoint: CameraEndpoint,
expires?: number,
): Promise<string | null> => {
@@ -0,0 +1,25 @@
/**
* Dispatch an Advanced Camera Card event.
* @param target The target from which send the event.
* @param type The type of the Advanced Camera Card event to send.
* @param detail An optional detail object to attach.
*/
export function fireAdvancedCameraCardEvent<T>(
target: EventTarget,
type: string,
detail?: T,
options?: {
bubbles?: boolean;
cancelable?: boolean;
composed?: boolean;
},
): void {
target.dispatchEvent(
new CustomEvent<T>(`advanced-camera-card:${type}`, {
bubbles: options?.bubbles ?? true,
composed: options?.composed ?? true,
cancelable: options?.cancelable ?? false,
detail: detail,
}),
);
}
@@ -1,9 +1,9 @@
import { HomeAssistant } from '@dermotduffy/custom-card-helpers';
import { add } from 'date-fns';
import chunk from 'lodash-es/chunk';
import orderBy from 'lodash-es/orderBy';
import { BrowseMediaMetadata } from '../../../camera-manager/browse-media/types';
import { MemoryRequestCache } from '../../../camera-manager/cache';
import { HomeAssistant } from '../../../ha/types';
import { allPromises } from '../../basic';
import { homeAssistantWSRequest } from '../ws-request';
import {
+3 -2
View File
@@ -1,6 +1,7 @@
import { computeDomain, HomeAssistant } from '@dermotduffy/custom-card-helpers';
import { HassEntity } from 'home-assistant-js-websocket';
import { Entity } from './registry/entity/types';
import { computeDomain } from '../../ha/compute-domain.js';
import { HomeAssistant } from '../../ha/types.js';
import { Entity } from './registry/entity/types.js';
/**
* Get the translation of an entity state. Inspired by:
+7 -13
View File
@@ -1,8 +1,8 @@
import { HomeAssistant } from '@dermotduffy/custom-card-helpers';
import { HassEntity } from 'home-assistant-js-websocket';
import { STATES_ON } from '../../ha/const.js';
import { HomeAssistant } from '../../ha/types.js';
import {
CardHelpers,
ExtendedHomeAssistant,
LovelaceCardWithEditor,
SignedPath,
signedPathSchema,
@@ -18,7 +18,7 @@ import { homeAssistantWSRequest } from './ws-request.js';
* @returns The signed URL, or null if the response was malformed.
*/
export async function homeAssistantSignPath(
hass: ExtendedHomeAssistant,
hass: HomeAssistant,
path: string,
expires?: number,
): Promise<string | null> {
@@ -183,7 +183,7 @@ export const sideLoadHomeAssistantElements = async (): Promise<boolean> => {
* @returns `true` if triggered, `false` otherwise.
*/
export const isTriggeredState = (state?: string): boolean => {
return !!state && ['on', 'open'].includes(state);
return !!state && STATES_ON.includes(state);
};
/**
@@ -224,15 +224,9 @@ export function isHARelativeURL(url?: string): boolean {
* location will be the Chromecast receiver, not HA).
* @param url The media URL
*/
export function canonicalizeHAURL(hass: ExtendedHomeAssistant, url: string): string;
export function canonicalizeHAURL(
hass: ExtendedHomeAssistant,
url?: string,
): string | null;
export function canonicalizeHAURL(
hass: ExtendedHomeAssistant,
url?: string,
): string | null {
export function canonicalizeHAURL(hass: HomeAssistant, url: string): string;
export function canonicalizeHAURL(hass: HomeAssistant, url?: string): string | null;
export function canonicalizeHAURL(hass: HomeAssistant, url?: string): string | null {
if (isHARelativeURL(url)) {
return hass.hassUrl(url);
}
+3 -3
View File
@@ -1,6 +1,6 @@
import { HomeAssistant } from '@dermotduffy/custom-card-helpers';
import { homeAssistantWSRequest } from '../ws-request';
import { IntegrationManifest, integrationManifestSchema } from './types';
import { HomeAssistant } from '../../../ha/types.js';
import { homeAssistantWSRequest } from '../ws-request.js';
import { IntegrationManifest, integrationManifestSchema } from './types.js';
export const getIntegrationManifest = async (
hass: HomeAssistant,
+2 -2
View File
@@ -1,6 +1,6 @@
import { HomeAssistant } from '@dermotduffy/custom-card-helpers';
import { homeAssistantWSRequest } from '../../ws-request';
import { HomeAssistant } from '../../../../ha/types';
import { errorToConsole } from '../../../basic';
import { homeAssistantWSRequest } from '../../ws-request';
import { RegistryCache } from '../cache';
import { Device, DeviceList, deviceListSchema } from './types';
+4 -4
View File
@@ -1,7 +1,7 @@
import { HomeAssistant } from '@dermotduffy/custom-card-helpers';
import { homeAssistantWSRequest } from '../../ws-request';
import { errorToConsole } from '../../../basic';
import { RegistryCache } from '../cache';
import { HomeAssistant } from '../../../../ha/types.js';
import { errorToConsole } from '../../../basic.js';
import { homeAssistantWSRequest } from '../../ws-request.js';
import { RegistryCache } from '../cache.js';
import { Entity, EntityList, entityListSchema, entitySchema } from './types.js';
export const createEntityRegistryCache = (): RegistryCache<Entity> => {
+2 -2
View File
@@ -1,8 +1,8 @@
import { HomeAssistant } from '@dermotduffy/custom-card-helpers';
import QuickLRU from 'quick-lru';
import { homeAssistantWSRequest } from './ws-request';
import { HomeAssistant } from '../../ha/types';
import { ResolvedMedia, resolvedMediaSchema } from '../../types.js';
import { errorToConsole } from '../basic';
import { homeAssistantWSRequest } from './ws-request';
// It's important the cache size be at least as large as the largest likely
// media query or media items will from a given query will be evicted for other
+2 -3
View File
@@ -1,6 +1,5 @@
import { HomeAssistant } from '@dermotduffy/custom-card-helpers';
import { CameraProxyConfig } from '../../camera-manager/types';
import { ExtendedHomeAssistant } from '../../types';
import { HomeAssistant } from '../../ha/types';
export const HASS_WEB_PROXY_DOMAIN = 'hass_web_proxy';
@@ -29,7 +28,7 @@ export const shouldUseWebProxy = (
* @returns The signed URL, or null if the response was malformed.
*/
export async function addDynamicProxyURL(
hass: ExtendedHomeAssistant,
hass: HomeAssistant,
url_pattern: string,
options?: {
urlID?: string;
+1 -1
View File
@@ -1,6 +1,6 @@
import { HomeAssistant } from '@dermotduffy/custom-card-helpers';
import { MessageBase } from 'home-assistant-js-websocket';
import { ZodSchema } from 'zod';
import { HomeAssistant } from '../../ha/types';
import { localize } from '../../localize/localize';
import { AdvancedCameraCardError } from '../../types';
import { getParseErrorKeys } from '../zod';
+8 -12
View File
@@ -4,7 +4,7 @@ import {
MediaPlayerController,
MediaTechnology,
} from '../types.js';
import { dispatchAdvancedCameraCardEvent } from './basic.js';
import { fireAdvancedCameraCardEvent } from './fire-advanced-camera-card-event.js';
const MEDIA_INFO_HEIGHT_CUTOFF = 50;
const MEDIA_INFO_WIDTH_CUTOFF = MEDIA_INFO_HEIGHT_CUTOFF;
@@ -75,17 +75,13 @@ export function dispatchMediaLoadedEvent(
/**
* Dispatch a pre-existing MediaLoadedInfo object as an event.
* @param element The element to send the event.
* @param MediaLoadedInfo The MediaLoadedInfo object to send.
* @param mediaLoadedInfo The MediaLoadedInfo object to send.
*/
export function dispatchExistingMediaLoadedInfoAsEvent(
target: EventTarget,
MediaLoadedInfo: MediaLoadedInfo,
mediaLoadedInfo: MediaLoadedInfo,
): void {
dispatchAdvancedCameraCardEvent<MediaLoadedInfo>(
target,
'media:loaded',
MediaLoadedInfo,
);
fireAdvancedCameraCardEvent<MediaLoadedInfo>(target, 'media:loaded', mediaLoadedInfo);
}
/**
@@ -93,19 +89,19 @@ export function dispatchExistingMediaLoadedInfoAsEvent(
* @param element The element to send the event.
*/
export function dispatchMediaUnloadedEvent(element: HTMLElement): void {
dispatchAdvancedCameraCardEvent(element, 'media:unloaded');
fireAdvancedCameraCardEvent(element, 'media:unloaded');
}
export function dispatchMediaVolumeChangeEvent(target: HTMLElement): void {
dispatchAdvancedCameraCardEvent(target, 'media:volumechange');
fireAdvancedCameraCardEvent(target, 'media:volumechange');
}
export function dispatchMediaPlayEvent(target: HTMLElement): void {
dispatchAdvancedCameraCardEvent(target, 'media:play');
fireAdvancedCameraCardEvent(target, 'media:play');
}
export function dispatchMediaPauseEvent(target: HTMLElement): void {
dispatchAdvancedCameraCardEvent(target, 'media:pause');
fireAdvancedCameraCardEvent(target, 'media:pause');
}
/**
+1 -1
View File
@@ -1,6 +1,6 @@
import { Task } from '@lit-labs/task';
import { ReactiveControllerHost } from '@lit/reactive-element';
import { HomeAssistant } from '@dermotduffy/custom-card-helpers';
import { HomeAssistant } from '../ha/types';
// See: https://github.com/sindresorhus/is-absolute-url
// Scheme: https://tools.ietf.org/html/rfc3986#section-3.1

Some files were not shown because too many files have changed in this diff Show More