From a79ffa6edcd1899324677f0899bb10639e8913f0 Mon Sep 17 00:00:00 2001 From: Dermot Duffy Date: Sun, 9 Mar 2025 16:02:33 -0700 Subject: [PATCH] refactor: Retire the use of unmaintained `custom-card-helpers` (#1956) - Closes #1295 --- package.json | 1 - src/action-handler-directive.ts | 19 +- src/camera-manager/browse-media/camera.ts | 2 +- .../browse-media/engine-browse-media.ts | 4 +- src/camera-manager/engine-factory.ts | 2 +- src/camera-manager/engine.ts | 5 +- src/camera-manager/frigate/camera.ts | 2 +- src/camera-manager/frigate/engine-frigate.ts | 5 +- src/camera-manager/frigate/event-watcher.ts | 2 +- src/camera-manager/frigate/requests.ts | 2 +- src/camera-manager/generic/engine-generic.ts | 5 +- .../motioneye/engine-motioneye.ts | 2 +- src/camera-manager/reolink/camera.ts | 2 +- src/camera-manager/reolink/engine-reolink.ts | 2 +- .../actions/actions-manager.ts | 3 +- .../actions/actions/generic.ts | 3 +- src/card-controller/actions/factory.ts | 2 +- .../actions/utils/execution-request.ts | 4 +- src/card-controller/controller.ts | 2 +- src/card-controller/hass/hass-manager.ts | 8 +- src/card-controller/hass/state-watcher.ts | 2 +- src/card-controller/templates/index.ts | 4 +- src/card.ts | 8 +- src/components-lib/icon-controller.ts | 2 +- .../live/utils/dispatch-live-error.ts | 4 +- src/components-lib/media-grid-controller.ts | 11 +- src/components-lib/menu-button-controller.ts | 2 +- src/components-lib/message/dispatch.ts | 4 +- src/components-lib/ptz/ptz-controller.ts | 16 +- src/components-lib/status-bar-controller.ts | 3 +- src/components-lib/zoom/zoom-controller.ts | 15 +- src/components/date-picker.ts | 4 +- src/components/diagnostics.ts | 2 +- src/components/elements.ts | 15 +- src/components/gallery.ts | 6 +- src/components/icon.ts | 2 +- src/components/image-updating-player.ts | 2 +- src/components/image.ts | 2 +- src/components/live/carousel.ts | 4 +- src/components/live/grid.ts | 4 +- src/components/live/index.ts | 4 +- src/components/live/provider.ts | 10 +- src/components/live/providers/go2rtc/index.ts | 10 +- src/components/live/providers/ha.ts | 2 +- src/components/live/providers/image.ts | 2 +- src/components/live/providers/jsmpeg.ts | 10 +- src/components/live/providers/webrtc-card.ts | 2 +- src/components/media-filter.ts | 4 +- src/components/menu.ts | 2 +- src/components/next-prev-control.ts | 2 +- src/components/ptz.ts | 2 +- src/components/select.ts | 5 +- src/components/submenu/index.ts | 2 +- src/components/submenu/select-button.ts | 2 +- src/components/submenu/submenu-button.ts | 3 +- src/components/surround.ts | 9 +- src/components/thumbnail-carousel.ts | 8 +- src/components/thumbnail.ts | 6 +- src/components/timeline-core.ts | 10 +- src/components/timeline.ts | 4 +- src/components/viewer/carousel.ts | 9 +- src/components/viewer/grid.ts | 4 +- src/components/viewer/index.ts | 4 +- src/components/viewer/provider.ts | 4 +- src/components/views.ts | 4 +- src/conditions/types.ts | 6 +- src/config/types.ts | 8 +- src/editor.ts | 9 +- src/ha/LICENSE | 21 ++ src/ha/README.md | 7 + src/ha/compute-domain.ts | 3 + src/ha/const.ts | 2 + src/ha/fire-hass-event.ts | 25 ++ src/ha/handle-action.ts | 90 +++++ src/ha/haptic.ts | 30 ++ src/ha/has-action.ts | 5 + src/ha/navigate.ts | 20 ++ src/ha/toggle-entity.ts | 8 + src/ha/turn-on-off-entity.ts | 25 ++ src/ha/types.ts | 316 ++++++++++++++++++ src/localize/localize.ts | 2 +- src/types.ts | 15 +- src/utils/action.ts | 7 +- src/utils/basic.ts | 20 -- src/utils/diagnostics.ts | 2 +- src/utils/download.ts | 15 +- src/utils/embla/carousel-controller.ts | 7 +- src/utils/endpoint.ts | 4 +- src/utils/fire-advanced-camera-card-event.ts | 25 ++ .../ha/browse-media/browse-media-manager.ts | 2 +- src/utils/ha/entity-state-translation.ts | 5 +- src/utils/ha/index.ts | 20 +- src/utils/ha/integration/index.ts | 6 +- src/utils/ha/registry/device/index.ts | 4 +- src/utils/ha/registry/entity/index.ts | 8 +- src/utils/ha/resolved-media.ts | 4 +- src/utils/ha/web-proxy.ts | 5 +- src/utils/ha/ws-request.ts | 2 +- src/utils/media-info.ts | 20 +- src/utils/thumbnail.ts | 2 +- .../frigate/event-watcher.test.ts | 8 +- tests/camera-manager/manager.test.ts | 22 +- .../actions/actions/generic.test.ts | 8 +- .../media-player-manager.test.ts | 12 +- .../menu-button-controller.test.ts | 32 +- tests/components-lib/menu-controller.test.ts | 10 +- tests/config/management.test.ts | 16 +- tests/ha/compute-domain.test.ts | 26 ++ tests/ha/haptic.test.ts | 24 ++ tests/test-utils.ts | 16 +- tests/utils/action.test.ts | 8 +- tests/utils/basic.test.ts | 33 +- .../fire-advanced-camera-card-event.test.ts | 26 ++ tests/utils/ha/index.test.ts | 2 +- vite.config.ts | 1 + yarn.lock | 171 +--------- 116 files changed, 933 insertions(+), 545 deletions(-) create mode 100644 src/ha/LICENSE create mode 100644 src/ha/README.md create mode 100644 src/ha/compute-domain.ts create mode 100644 src/ha/const.ts create mode 100644 src/ha/fire-hass-event.ts create mode 100644 src/ha/handle-action.ts create mode 100644 src/ha/haptic.ts create mode 100644 src/ha/has-action.ts create mode 100644 src/ha/navigate.ts create mode 100644 src/ha/toggle-entity.ts create mode 100644 src/ha/turn-on-off-entity.ts create mode 100644 src/ha/types.ts create mode 100644 src/utils/fire-advanced-camera-card-event.ts create mode 100644 tests/ha/compute-domain.test.ts create mode 100644 tests/ha/haptic.test.ts create mode 100644 tests/utils/fire-advanced-camera-card-event.test.ts diff --git a/package.json b/package.json index a113025b..57f96b7f 100644 --- a/package.json +++ b/package.json @@ -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", diff --git a/src/action-handler-directive.ts b/src/action-handler-directive.ts index dcd6744f..bef6bc52 100644 --- a/src/action-handler-directive.ts +++ b/src/action-handler-directive.ts @@ -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' }); } }; diff --git a/src/camera-manager/browse-media/camera.ts b/src/camera-manager/browse-media/camera.ts index 4a207ab2..d679642a 100644 --- a/src/camera-manager/browse-media/camera.ts +++ b/src/camera-manager/browse-media/camera.ts @@ -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'; diff --git a/src/camera-manager/browse-media/engine-browse-media.ts b/src/camera-manager/browse-media/engine-browse-media.ts index 4eb98044..599eed67 100644 --- a/src/camera-manager/browse-media/engine-browse-media.ts +++ b/src/camera-manager/browse-media/engine-browse-media.ts @@ -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 { diff --git a/src/camera-manager/engine-factory.ts b/src/camera-manager/engine-factory.ts index d34830b7..44934b21 100644 --- a/src/camera-manager/engine-factory.ts +++ b/src/camera-manager/engine-factory.ts @@ -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'; diff --git a/src/camera-manager/engine.ts b/src/camera-manager/engine.ts index e9fa6b0b..2f113a82 100644 --- a/src/camera-manager/engine.ts +++ b/src/camera-manager/engine.ts @@ -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; diff --git a/src/camera-manager/frigate/camera.ts b/src/camera-manager/frigate/camera.ts index 726832b8..4b515c85 100644 --- a/src/camera-manager/frigate/camera.ts +++ b/src/camera-manager/frigate/camera.ts @@ -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'; diff --git a/src/camera-manager/frigate/engine-frigate.ts b/src/camera-manager/frigate/engine-frigate.ts index 700ae635..73a1f65d 100644 --- a/src/camera-manager/frigate/engine-frigate.ts +++ b/src/camera-manager/frigate/engine-frigate.ts @@ -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 { diff --git a/src/camera-manager/frigate/event-watcher.ts b/src/camera-manager/frigate/event-watcher.ts index 6aee9002..ba79dc2e 100644 --- a/src/camera-manager/frigate/event-watcher.ts +++ b/src/camera-manager/frigate/event-watcher.ts @@ -1,4 +1,4 @@ -import { HomeAssistant } from '@dermotduffy/custom-card-helpers'; +import { HomeAssistant } from '../../ha/types'; import { FrigateEventChange, frigateEventChangeSchema } from './types'; export interface FrigateEventWatcherRequest { diff --git a/src/camera-manager/frigate/requests.ts b/src/camera-manager/frigate/requests.ts index 95939d2a..5ca6a0f0 100644 --- a/src/camera-manager/frigate/requests.ts +++ b/src/camera-manager/frigate/requests.ts @@ -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'; diff --git a/src/camera-manager/generic/engine-generic.ts b/src/camera-manager/generic/engine-generic.ts index a9af9264..b978d24b 100644 --- a/src/camera-manager/generic/engine-generic.ts +++ b/src/camera-manager/generic/engine-generic.ts @@ -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 { diff --git a/src/camera-manager/motioneye/engine-motioneye.ts b/src/camera-manager/motioneye/engine-motioneye.ts index 2cbcdbc4..2fc92480 100644 --- a/src/camera-manager/motioneye/engine-motioneye.ts +++ b/src/camera-manager/motioneye/engine-motioneye.ts @@ -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, diff --git a/src/camera-manager/reolink/camera.ts b/src/camera-manager/reolink/camera.ts index 09cc301e..0eaf127c 100644 --- a/src/camera-manager/reolink/camera.ts +++ b/src/camera-manager/reolink/camera.ts @@ -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'; diff --git a/src/camera-manager/reolink/engine-reolink.ts b/src/camera-manager/reolink/engine-reolink.ts index 0cbec88f..ec0b9d69 100644 --- a/src/camera-manager/reolink/engine-reolink.ts +++ b/src/camera-manager/reolink/engine-reolink.ts @@ -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 { diff --git a/src/card-controller/actions/actions-manager.ts b/src/card-controller/actions/actions-manager.ts index 9c7b9cd1..3efd2918 100644 --- a/src/card-controller/actions/actions-manager.ts +++ b/src/card-controller/actions/actions-manager.ts @@ -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; } diff --git a/src/card-controller/actions/actions/generic.ts b/src/card-controller/actions/actions/generic.ts index 514556cd..186027d3 100644 --- a/src/card-controller/actions/actions/generic.ts +++ b/src/card-controller/actions/actions/generic.ts @@ -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'; diff --git a/src/card-controller/actions/factory.ts b/src/card-controller/actions/factory.ts index 57f95cf7..fea18a34 100644 --- a/src/card-controller/actions/factory.ts +++ b/src/card-controller/actions/factory.ts @@ -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'; diff --git a/src/card-controller/actions/utils/execution-request.ts b/src/card-controller/actions/utils/execution-request.ts index b0ad889b..12a2527c 100644 --- a/src/card-controller/actions/utils/execution-request.ts +++ b/src/card-controller/actions/utils/execution-request.ts @@ -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 { diff --git a/src/card-controller/controller.ts b/src/card-controller/controller.ts index df19b1ec..3b911163 100644 --- a/src/card-controller/controller.ts +++ b/src/card-controller/controller.ts @@ -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, diff --git a/src/card-controller/hass/hass-manager.ts b/src/card-controller/hass/hass-manager.ts index 7d2286d4..c26cc71a 100644 --- a/src/card-controller/hass/hass-manager.ts +++ b/src/card-controller/hass/hass-manager.ts @@ -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({ diff --git a/src/card-controller/hass/state-watcher.ts b/src/card-controller/hass/state-watcher.ts index 08e42250..7c9e266a 100644 --- a/src/card-controller/hass/state-watcher.ts +++ b/src/card-controller/hass/state-watcher.ts @@ -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; diff --git a/src/card-controller/templates/index.ts b/src/card-controller/templates/index.ts index 8f17990a..47e74a07 100644 --- a/src/card-controller/templates/index.ts +++ b/src/card-controller/templates/index.ts @@ -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; diff --git a/src/card.ts b/src/card.ts index c7a7b71f..ce2531ff 100644 --- a/src/card.ts +++ b/src/card.ts @@ -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 diff --git a/src/components-lib/icon-controller.ts b/src/components-lib/icon-controller.ts index 97ab232e..9a5a4a4e 100644 --- a/src/components-lib/icon-controller.ts +++ b/src/components-lib/icon-controller.ts @@ -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'; diff --git a/src/components-lib/live/utils/dispatch-live-error.ts b/src/components-lib/live/utils/dispatch-live-error.ts index 16e37f48..69d49bb9 100644 --- a/src/components-lib/live/utils/dispatch-live-error.ts +++ b/src/components-lib/live/utils/dispatch-live-error.ts @@ -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'); } diff --git a/src/components-lib/media-grid-controller.ts b/src/components-lib/media-grid-controller.ts index 73aa9ffc..5aa58e95 100644 --- a/src/components-lib/media-grid-controller.ts +++ b/src/components-lib/media-grid-controller.ts @@ -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(); diff --git a/src/components-lib/menu-button-controller.ts b/src/components-lib/menu-button-controller.ts index 50e53038..1526ffdf 100644 --- a/src/components-lib/menu-button-controller.ts +++ b/src/components-lib/menu-button-controller.ts @@ -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 { diff --git a/src/components-lib/message/dispatch.ts b/src/components-lib/message/dispatch.ts index 4928cdfd..77045902 100644 --- a/src/components-lib/message/dispatch.ts +++ b/src/components-lib/message/dispatch.ts @@ -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(element, 'message', { + fireAdvancedCameraCardEvent(element, 'message', { message: error.message, type: 'error', ...(error instanceof AdvancedCameraCardError && { context: error.context }), diff --git a/src/components-lib/ptz/ptz-controller.ts b/src/components-lib/ptz/ptz-controller.ts index 770b06c1..9539cac8 100644 --- a/src/components-lib/ptz/ptz-controller.ts +++ b/src/components-lib/ptz/ptz-controller.ts @@ -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 { diff --git a/src/components-lib/status-bar-controller.ts b/src/components-lib/status-bar-controller.ts index 401726e1..b2775529 100644 --- a/src/components-lib/status-bar-controller.ts +++ b/src/components-lib/status-bar-controller.ts @@ -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 diff --git a/src/components-lib/zoom/zoom-controller.ts b/src/components-lib/zoom/zoom-controller.ts index 3dd05075..3df0517c 100644 --- a/src/components-lib/zoom/zoom-controller.ts +++ b/src/components-lib/zoom/zoom-controller.ts @@ -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 { diff --git a/src/components/date-picker.ts b/src/components/date-picker.ts index 47799c21..89fb9e04 100644 --- a/src/components/date-picker.ts +++ b/src/components/date-picker.ts @@ -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(this, 'date-picker:change', { + fireAdvancedCameraCardEvent(this, 'date-picker:change', { date: value ? new Date(value) : null, }); }; diff --git a/src/components/diagnostics.ts b/src/components/diagnostics.ts index f9c3f56b..8c60be52 100644 --- a/src/components/diagnostics.ts +++ b/src/components/diagnostics.ts @@ -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'; diff --git a/src/components/elements.ts b/src/components/elements.ts index 3f361c18..dedc8de1 100644 --- a/src/components/elements.ts +++ b/src/components/elements.ts @@ -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( + fireAdvancedCameraCardEvent( 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( + fireAdvancedCameraCardEvent( this, 'status-bar:remove', (ev as CustomEvent).detail, @@ -346,7 +347,7 @@ export class AdvancedCameraCardElementsBaseItem extends LitElement { connectedCallback(): void { super.connectedCallback(); if (this._config) { - dispatchAdvancedCameraCardEvent( + fireAdvancedCameraCardEvent( this, `${this._eventCategory}:add`, this._config, @@ -356,7 +357,7 @@ export class AdvancedCameraCardElementsBaseItem extends LitElement { disconnectedCallback(): void { if (this._config) { - dispatchAdvancedCameraCardEvent( + fireAdvancedCameraCardEvent( this, `${this._eventCategory}:remove`, this._config, diff --git a/src/components/gallery.ts b/src/components/gallery.ts index 1100dd73..0563f86a 100644 --- a/src/components/gallery.ts +++ b/src/components/gallery.ts @@ -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; diff --git a/src/components/icon.ts b/src/components/icon.ts index e2536fb0..1e8d97e9 100644 --- a/src/components/icon.ts +++ b/src/components/icon.ts @@ -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'; diff --git a/src/components/image-updating-player.ts b/src/components/image-updating-player.ts index 44b34454..b0ce645f 100644 --- a/src/components/image-updating-player.ts +++ b/src/components/image-updating-player.ts @@ -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'; diff --git a/src/components/image.ts b/src/components/image.ts index 12e35221..b2281fac 100644 --- a/src/components/image.ts +++ b/src/components/image.ts @@ -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 { diff --git a/src/components/live/carousel.ts b/src/components/live/carousel.ts index 4f78c75c..d37de101 100644 --- a/src/components/live/carousel.ts +++ b/src/components/live/carousel.ts @@ -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; diff --git a/src/components/live/grid.ts b/src/components/live/grid.ts index 1141d7f4..197acba0 100644 --- a/src/components/live/grid.ts +++ b/src/components/live/grid.ts @@ -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; diff --git a/src/components/live/index.ts b/src/components/live/index.ts index 1639450a..8fa0480e 100644 --- a/src/components/live/index.ts +++ b/src/components/live/index.ts @@ -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; diff --git a/src/components/live/provider.ts b/src/components/live/provider.ts index bd314206..3d8fbd20 100644 --- a/src/components/live/provider.ts +++ b/src/components/live/provider.ts @@ -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; diff --git a/src/components/live/providers/go2rtc/index.ts b/src/components/live/providers/go2rtc/index.ts index 2284627c..d66b002b 100644 --- a/src/components/live/providers/go2rtc/index.ts +++ b/src/components/live/providers/go2rtc/index.ts @@ -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; diff --git a/src/components/live/providers/ha.ts b/src/components/live/providers/ha.ts index 3e72e55a..e24417bc 100644 --- a/src/components/live/providers/ha.ts +++ b/src/components/live/providers/ha.ts @@ -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'; diff --git a/src/components/live/providers/image.ts b/src/components/live/providers/image.ts index 581631dd..0d01a7b6 100644 --- a/src/components/live/providers/image.ts +++ b/src/components/live/providers/image.ts @@ -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, diff --git a/src/components/live/providers/jsmpeg.ts b/src/components/live/providers/jsmpeg.ts index a4fa1213..e0cc3017 100644 --- a/src/components/live/providers/jsmpeg.ts +++ b/src/components/live/providers/jsmpeg.ts @@ -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; diff --git a/src/components/live/providers/webrtc-card.ts b/src/components/live/providers/webrtc-card.ts index 806bb013..3d5afe8e 100644 --- a/src/components/live/providers/webrtc-card.ts +++ b/src/components/live/providers/webrtc-card.ts @@ -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 { diff --git a/src/components/media-filter.ts b/src/components/media-filter.ts index 7cf14393..8d5194c1 100644 --- a/src/components/media-filter.ts +++ b/src/components/media-filter.ts @@ -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) { diff --git a/src/components/menu.ts b/src/components/menu.ts index 85d4a998..d7269f41 100644 --- a/src/components/menu.ts +++ b/src/components/menu.ts @@ -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'; diff --git a/src/components/next-prev-control.ts b/src/components/next-prev-control.ts index db4999af..c8d7e135 100644 --- a/src/components/next-prev-control.ts +++ b/src/components/next-prev-control.ts @@ -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'; diff --git a/src/components/ptz.ts b/src/components/ptz.ts index fa9ac6df..05d5ef94 100644 --- a/src/components/ptz.ts +++ b/src/components/ptz.ts @@ -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'; diff --git a/src/components/select.ts b/src/components/select.ts index 741018a3..30571067 100644 --- a/src/components/select.ts +++ b/src/components/select.ts @@ -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); } } } diff --git a/src/components/submenu/index.ts b/src/components/submenu/index.ts index e624668c..73bd0e20 100644 --- a/src/components/submenu/index.ts +++ b/src/components/submenu/index.ts @@ -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, diff --git a/src/components/submenu/select-button.ts b/src/components/submenu/select-button.ts index 6a6b1c01..1169c53f 100644 --- a/src/components/submenu/select-button.ts +++ b/src/components/submenu/select-button.ts @@ -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'; diff --git a/src/components/submenu/submenu-button.ts b/src/components/submenu/submenu-button.ts index 9970f80d..f0726ed8 100644 --- a/src/components/submenu/submenu-button.ts +++ b/src/components/submenu/submenu-button.ts @@ -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'; diff --git a/src/components/surround.ts b/src/components/surround.ts index b63df56e..90f07dcd 100644 --- a/src/components/surround.ts +++ b/src/components/surround.ts @@ -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 // . if (this.thumbnailConfig && this._hasDrawer()) { - dispatchAdvancedCameraCardEvent(ev.composedPath()[0], 'drawer:' + action, { + fireAdvancedCameraCardEvent(ev.composedPath()[0], 'drawer:' + action, { drawer: this.thumbnailConfig.mode, }); } diff --git a/src/components/thumbnail-carousel.ts b/src/components/thumbnail-carousel.ts index ea437449..508971b5 100644 --- a/src/components/thumbnail-carousel.ts +++ b/src/components/thumbnail-carousel.ts @@ -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( + fireAdvancedCameraCardEvent( this, 'thumbnail-carousel:tap', { diff --git a/src/components/thumbnail.ts b/src/components/thumbnail.ts index 7a54bddc..00e66ee7 100644 --- a/src/components/thumbnail.ts +++ b/src/components/thumbnail.ts @@ -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 diff --git a/src/components/timeline-core.ts b/src/components/timeline-core.ts index b99cfe34..386c98ca 100644 --- a/src/components/timeline-core.ts +++ b/src/components/timeline-core.ts @@ -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; } diff --git a/src/components/timeline.ts b/src/components/timeline.ts index d8554af8..fc60a98a 100644 --- a/src/components/timeline.ts +++ b/src/components/timeline.ts @@ -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; diff --git a/src/components/viewer/carousel.ts b/src/components/viewer/carousel.ts index 3ad66c1d..01371a53 100644 --- a/src/components/viewer/carousel.ts +++ b/src/components/viewer/carousel.ts @@ -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; diff --git a/src/components/viewer/grid.ts b/src/components/viewer/grid.ts index 20b697dc..4eaae02b 100644 --- a/src/components/viewer/grid.ts +++ b/src/components/viewer/grid.ts @@ -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; diff --git a/src/components/viewer/index.ts b/src/components/viewer/index.ts index 41b8b8a2..381c9bbf 100644 --- a/src/components/viewer/index.ts +++ b/src/components/viewer/index.ts @@ -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; diff --git a/src/components/viewer/provider.ts b/src/components/viewer/provider.ts index 02bdc6a9..e36bf372 100644 --- a/src/components/viewer/provider.ts +++ b/src/components/viewer/provider.ts @@ -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; diff --git a/src/components/views.ts b/src/components/views.ts index 0640d8f4..1872541f 100644 --- a/src/components/views.ts +++ b/src/components/views.ts @@ -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; diff --git a/src/conditions/types.ts b/src/conditions/types.ts index 84cc3995..45c43027 100644 --- a/src/conditions/types.ts +++ b/src/conditions/types.ts @@ -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; diff --git a/src/config/types.ts b/src/config/types.ts index 7ba6c7fd..a1b4144d 100644 --- a/src/config/types.ts +++ b/src/config/types.ts @@ -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 { diff --git a/src/editor.ts b/src/editor.ts index 114fd557..47fd8a7a 100644 --- a/src/editor.ts +++ b/src/editor.ts @@ -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 { diff --git a/src/ha/LICENSE b/src/ha/LICENSE new file mode 100644 index 00000000..6893c343 --- /dev/null +++ b/src/ha/LICENSE @@ -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. diff --git a/src/ha/README.md b/src/ha/README.md new file mode 100644 index 00000000..2617af8b --- /dev/null +++ b/src/ha/README.md @@ -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. diff --git a/src/ha/compute-domain.ts b/src/ha/compute-domain.ts new file mode 100644 index 00000000..a74ec336 --- /dev/null +++ b/src/ha/compute-domain.ts @@ -0,0 +1,3 @@ +export const computeDomain = (entityId: string): string => { + return entityId.substring(0, entityId.indexOf('.')); +}; diff --git a/src/ha/const.ts b/src/ha/const.ts new file mode 100644 index 00000000..1df670cf --- /dev/null +++ b/src/ha/const.ts @@ -0,0 +1,2 @@ +export const STATES_OFF = ['closed', 'locked', 'off']; +export const STATES_ON = ['open', 'unlocked', 'on']; diff --git a/src/ha/fire-hass-event.ts b/src/ha/fire-hass-event.ts new file mode 100644 index 00000000..cb082436 --- /dev/null +++ b/src/ha/fire-hass-event.ts @@ -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 = ( + target: EventTarget, + type: HassEvent, + detail?: HASSDomEvents[HassEvent], + options?: { + bubbles?: boolean; + cancelable?: boolean; + composed?: boolean; + }, +) => { + target.dispatchEvent( + new CustomEvent(type, { + bubbles: options?.bubbles ?? true, + composed: options?.composed ?? true, + cancelable: options?.cancelable ?? false, + detail: detail, + }), + ); +}; diff --git a/src/ha/handle-action.ts b/src/ha/handle-action.ts new file mode 100644 index 00000000..e504a3e0 --- /dev/null +++ b/src/ha/handle-action.ts @@ -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); + } + } +}; diff --git a/src/ha/haptic.ts b/src/ha/haptic.ts new file mode 100644 index 00000000..0d6b36d8 --- /dev/null +++ b/src/ha/haptic.ts @@ -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; + } +} + +export const forwardHaptic = (hapticType: HapticType) => { + fireHASSEvent(window, 'haptic', hapticType); +}; diff --git a/src/ha/has-action.ts b/src/ha/has-action.ts new file mode 100644 index 00000000..c2a0b15f --- /dev/null +++ b/src/ha/has-action.ts @@ -0,0 +1,5 @@ +import { ActionConfig } from './types.js'; + +export function hasAction(config?: ActionConfig): boolean { + return config !== undefined && config.action !== 'none'; +} diff --git a/src/ha/navigate.ts b/src/ha/navigate.ts new file mode 100644 index 00000000..79c00511 --- /dev/null +++ b/src/ha/navigate.ts @@ -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, + }); +}; diff --git a/src/ha/toggle-entity.ts b/src/ha/toggle-entity.ts new file mode 100644 index 00000000..438d6ae6 --- /dev/null +++ b/src/ha/toggle-entity.ts @@ -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 => { + const turnOn = STATES_OFF.includes(hass.states[entityId].state); + return turnOnOffEntity(hass, entityId, turnOn); +}; diff --git a/src/ha/turn-on-off-entity.ts b/src/ha/turn-on-off-entity.ts new file mode 100644 index 00000000..490156be --- /dev/null +++ b/src/ha/turn-on-off-entity.ts @@ -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 => { + 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 }); +}; diff --git a/src/ha/types.ts b/src/ha/types.ts new file mode 100644 index 00000000..2362fc85 --- /dev/null +++ b/src/ha/types.ts @@ -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; + 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; + callApi: ( + method: 'GET' | 'POST' | 'PUT' | 'DELETE', + path: string, + parameters?: { + [key: string]: unknown; + }, + ) => Promise; + fetchWithAuth: ( + path: string, + init?: { + [key: string]: unknown; + }, + ) => Promise; + hassUrl(path?): string; + sendWS: (msg: MessageBase) => Promise; + callWS: (msg: MessageBase) => Promise; +} + +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; + 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; + 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; +} diff --git a/src/localize/localize.ts b/src/localize/localize.ts index 556f3f5e..20253b4b 100644 --- a/src/localize/localize.ts +++ b/src/localize/localize.ts @@ -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; diff --git a/src/types.ts b/src/types.ts index 7274e418..be57899f 100644 --- a/src/types.ts +++ b/src/types.ts @@ -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; diff --git a/src/utils/action.ts b/src/utils/action.ts index 58cc1d82..7ef37d6c 100644 --- a/src/utils/action.ts +++ b/src/utils/action.ts @@ -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'; /** diff --git a/src/utils/basic.ts b/src/utils/basic.ts index 8c692ed9..179cb4bc 100644 --- a/src/utils/basic.ts +++ b/src/utils/basic.ts @@ -13,26 +13,6 @@ import { AdvancedCameraCardError } from '../types'; export type ModifyInterface = Omit & 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( - target: EventTarget, - name: string, - detail?: T, -): void { - target.dispatchEvent( - new CustomEvent(`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. diff --git a/src/utils/diagnostics.ts b/src/utils/diagnostics.ts index 3115fe6f..1fe4babb 100644 --- a/src/utils/diagnostics.ts +++ b/src/utils/diagnostics.ts @@ -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'; diff --git a/src/utils/download.ts b/src/utils/download.ts index 04dc1ec7..4d1e6961 100644 --- a/src/utils/download.ts +++ b/src/utils/download.ts @@ -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 => { diff --git a/src/utils/embla/carousel-controller.ts b/src/utils/embla/carousel-controller.ts index db98ce0c..a32de0e6 100644 --- a/src/utils/embla/carousel-controller.ts +++ b/src/utils/embla/carousel-controller.ts @@ -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( + fireAdvancedCameraCardEvent( this._parent, 'carousel:force-select', { @@ -172,7 +173,7 @@ export class CarouselController { const selectSlide = (): void => { const carouselSelected = getCarouselSelectedObject(); if (carouselSelected) { - dispatchAdvancedCameraCardEvent( + fireAdvancedCameraCardEvent( this._parent, 'carousel:select', carouselSelected, diff --git a/src/utils/endpoint.ts b/src/utils/endpoint.ts index e0b7de1a..b1d5698e 100644 --- a/src/utils/endpoint.ts +++ b/src/utils/endpoint.ts @@ -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 => { diff --git a/src/utils/fire-advanced-camera-card-event.ts b/src/utils/fire-advanced-camera-card-event.ts new file mode 100644 index 00000000..cf11ee2c --- /dev/null +++ b/src/utils/fire-advanced-camera-card-event.ts @@ -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( + target: EventTarget, + type: string, + detail?: T, + options?: { + bubbles?: boolean; + cancelable?: boolean; + composed?: boolean; + }, +): void { + target.dispatchEvent( + new CustomEvent(`advanced-camera-card:${type}`, { + bubbles: options?.bubbles ?? true, + composed: options?.composed ?? true, + cancelable: options?.cancelable ?? false, + detail: detail, + }), + ); +} diff --git a/src/utils/ha/browse-media/browse-media-manager.ts b/src/utils/ha/browse-media/browse-media-manager.ts index a52ad127..08ac552b 100644 --- a/src/utils/ha/browse-media/browse-media-manager.ts +++ b/src/utils/ha/browse-media/browse-media-manager.ts @@ -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 { diff --git a/src/utils/ha/entity-state-translation.ts b/src/utils/ha/entity-state-translation.ts index 1a44ae20..75ce402c 100644 --- a/src/utils/ha/entity-state-translation.ts +++ b/src/utils/ha/entity-state-translation.ts @@ -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: diff --git a/src/utils/ha/index.ts b/src/utils/ha/index.ts index 46b4a35e..607175da 100644 --- a/src/utils/ha/index.ts +++ b/src/utils/ha/index.ts @@ -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 { @@ -183,7 +183,7 @@ export const sideLoadHomeAssistantElements = async (): Promise => { * @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); } diff --git a/src/utils/ha/integration/index.ts b/src/utils/ha/integration/index.ts index 084d2a1c..be878127 100644 --- a/src/utils/ha/integration/index.ts +++ b/src/utils/ha/integration/index.ts @@ -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, diff --git a/src/utils/ha/registry/device/index.ts b/src/utils/ha/registry/device/index.ts index 5cbb0ca0..5f47caf6 100644 --- a/src/utils/ha/registry/device/index.ts +++ b/src/utils/ha/registry/device/index.ts @@ -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'; diff --git a/src/utils/ha/registry/entity/index.ts b/src/utils/ha/registry/entity/index.ts index b5dc69f3..7010f9df 100644 --- a/src/utils/ha/registry/entity/index.ts +++ b/src/utils/ha/registry/entity/index.ts @@ -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 => { diff --git a/src/utils/ha/resolved-media.ts b/src/utils/ha/resolved-media.ts index 0bd8b553..977f5f6d 100644 --- a/src/utils/ha/resolved-media.ts +++ b/src/utils/ha/resolved-media.ts @@ -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 diff --git a/src/utils/ha/web-proxy.ts b/src/utils/ha/web-proxy.ts index f22cadff..576edf03 100644 --- a/src/utils/ha/web-proxy.ts +++ b/src/utils/ha/web-proxy.ts @@ -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; diff --git a/src/utils/ha/ws-request.ts b/src/utils/ha/ws-request.ts index c65ce724..8a0a7bb6 100644 --- a/src/utils/ha/ws-request.ts +++ b/src/utils/ha/ws-request.ts @@ -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'; diff --git a/src/utils/media-info.ts b/src/utils/media-info.ts index 3929b2a6..99ecc1a8 100644 --- a/src/utils/media-info.ts +++ b/src/utils/media-info.ts @@ -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( - target, - 'media:loaded', - MediaLoadedInfo, - ); + fireAdvancedCameraCardEvent(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'); } /** diff --git a/src/utils/thumbnail.ts b/src/utils/thumbnail.ts index 81ec45e0..a5e0edfd 100644 --- a/src/utils/thumbnail.ts +++ b/src/utils/thumbnail.ts @@ -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 diff --git a/tests/camera-manager/frigate/event-watcher.test.ts b/tests/camera-manager/frigate/event-watcher.test.ts index 36219baf..a7e2eb1b 100644 --- a/tests/camera-manager/frigate/event-watcher.test.ts +++ b/tests/camera-manager/frigate/event-watcher.test.ts @@ -1,8 +1,8 @@ import { afterEach, describe, expect, it, vi } from 'vitest'; -import { FrigateEventWatcher } from '../../../src/camera-manager/frigate/event-watcher'; -import { createHASS } from '../../test-utils'; -import { HomeAssistant } from '@dermotduffy/custom-card-helpers'; -import { FrigateEventChange } from '../../../src/camera-manager/frigate/types'; +import { FrigateEventWatcher } from '../../../src/camera-manager/frigate/event-watcher.js'; +import { FrigateEventChange } from '../../../src/camera-manager/frigate/types.js'; +import { HomeAssistant } from '../../../src/ha/types.js'; +import { createHASS } from '../../test-utils.js'; const createEventChange = (): FrigateEventChange => { return { diff --git a/tests/camera-manager/manager.test.ts b/tests/camera-manager/manager.test.ts index fb80c74e..1db3c1ae 100644 --- a/tests/camera-manager/manager.test.ts +++ b/tests/camera-manager/manager.test.ts @@ -1,16 +1,15 @@ -import { HomeAssistant } from '@dermotduffy/custom-card-helpers'; import { add } from 'date-fns'; import { afterAll, beforeAll, beforeEach, describe, expect, it, vi } from 'vitest'; import { mock } from 'vitest-mock-extended'; -import { Camera } from '../../src/camera-manager/camera'; -import { Capabilities } from '../../src/camera-manager/capabilities'; -import { CameraManagerEngine } from '../../src/camera-manager/engine'; +import { Camera } from '../../src/camera-manager/camera.js'; +import { Capabilities } from '../../src/camera-manager/capabilities.js'; import { CameraManagerEngineFactory } from '../../src/camera-manager/engine-factory.js'; +import { CameraManagerEngine } from '../../src/camera-manager/engine.js'; import { CameraManager, QueryClassifier, QueryResultClassifier, -} from '../../src/camera-manager/manager'; +} from '../../src/camera-manager/manager.js'; import { CameraEndpoint, CameraEndpoints, @@ -25,11 +24,12 @@ import { QueryResults, QueryResultsType, QueryType, -} from '../../src/camera-manager/types'; -import { sortMedia } from '../../src/camera-manager/utils/sort-media'; -import { CardController } from '../../src/card-controller/controller'; -import { CameraConfig } from '../../src/config/types'; -import { ViewMedia } from '../../src/view/media'; +} from '../../src/camera-manager/types.js'; +import { sortMedia } from '../../src/camera-manager/utils/sort-media.js'; +import { CardController } from '../../src/card-controller/controller.js'; +import { CameraConfig } from '../../src/config/types.js'; +import { HomeAssistant } from '../../src/ha/types.js'; +import { ViewMedia } from '../../src/view/media.js'; import { TestViewMedia, createCamera, @@ -39,7 +39,7 @@ import { createConfig, createHASS, generateViewMediaArray, -} from '../test-utils'; +} from '../test-utils.js'; describe('QueryClassifier', async () => { it('should classify event query', async () => { diff --git a/tests/card-controller/actions/actions/generic.test.ts b/tests/card-controller/actions/actions/generic.test.ts index ae84a103..af50b09c 100644 --- a/tests/card-controller/actions/actions/generic.test.ts +++ b/tests/card-controller/actions/actions/generic.test.ts @@ -1,9 +1,9 @@ import { describe, expect, it, vi } from 'vitest'; -import { createCardAPI, createHASS, createLitElement } from '../../../test-utils'; -import { GenericAction } from '../../../../src/card-controller/actions/actions/generic'; -import { handleActionConfig } from '@dermotduffy/custom-card-helpers'; +import { createCardAPI, createHASS, createLitElement } from '../../../test-utils.js'; +import { GenericAction } from '../../../../src/card-controller/actions/actions/generic.js'; +import { handleActionConfig } from '../../../../src/ha/handle-action.js'; -vi.mock('@dermotduffy/custom-card-helpers'); +vi.mock('../../../../src/ha/handle-action.js'); describe('should handle generic action', () => { it('without hass', async () => { diff --git a/tests/card-controller/media-player-manager.test.ts b/tests/card-controller/media-player-manager.test.ts index 7140a283..b5c0d02a 100644 --- a/tests/card-controller/media-player-manager.test.ts +++ b/tests/card-controller/media-player-manager.test.ts @@ -1,13 +1,13 @@ import { beforeEach, describe, expect, it, vi } from 'vitest'; import { mock } from 'vitest-mock-extended'; -import { MediaPlayerManager } from '../../src/card-controller/media-player-manager'; +import { MediaPlayerManager } from '../../src/card-controller/media-player-manager.js'; import { MEDIA_PLAYER_SUPPORT_BROWSE_MEDIA, MEDIA_PLAYER_SUPPORT_STOP, MEDIA_PLAYER_SUPPORT_TURN_OFF, } from '../../src/const'; -import { ExtendedHomeAssistant } from '../../src/types'; -import { EntityRegistryManager } from '../../src/utils/ha/registry/entity'; +import { HomeAssistant } from '../../src/ha/types.js'; +import { EntityRegistryManager } from '../../src/utils/ha/registry/entity/index.js'; import { createCameraConfig, createCameraManager, @@ -18,9 +18,9 @@ import { createStateEntity, createStore, TestViewMedia, -} from '../test-utils'; +} from '../test-utils.js'; -const createHASSWithMediaPlayers = (): ExtendedHomeAssistant => { +const createHASSWithMediaPlayers = (): HomeAssistant => { const attributesSupported = { supported_features: MEDIA_PLAYER_SUPPORT_BROWSE_MEDIA, }; @@ -292,7 +292,7 @@ describe('MediaPlayerManager', () => { ); vi.mocked(api.getCameraManager().getCameraMetadata).mockReturnValue({ title: 'camera title', - icon: 'icon', + icon: { icon: 'icon' }, }); vi.mocked(api.getHASSManager().getHASS).mockReturnValue( createHASS({ diff --git a/tests/components-lib/menu-button-controller.test.ts b/tests/components-lib/menu-button-controller.test.ts index 9c81a477..0b8a3b8e 100644 --- a/tests/components-lib/menu-button-controller.test.ts +++ b/tests/components-lib/menu-button-controller.test.ts @@ -1,29 +1,29 @@ -import { HomeAssistant } from '@dermotduffy/custom-card-helpers'; import isEqual from 'lodash-es/isEqual'; import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; import { mock } from 'vitest-mock-extended'; -import { Capabilities } from '../../src/camera-manager/capabilities'; -import { CameraManager } from '../../src/camera-manager/manager'; -import { CameraManagerCameraMetadata } from '../../src/camera-manager/types'; -import { FullscreenManager } from '../../src/card-controller/fullscreen/fullscreen-manager'; -import { MediaPlayerManager } from '../../src/card-controller/media-player-manager'; -import { MicrophoneManager } from '../../src/card-controller/microphone-manager'; -import { ViewManager } from '../../src/card-controller/view/view-manager'; +import { Capabilities } from '../../src/camera-manager/capabilities.js'; +import { CameraManager } from '../../src/camera-manager/manager.js'; +import { CameraManagerCameraMetadata } from '../../src/camera-manager/types.js'; +import { FullscreenManager } from '../../src/card-controller/fullscreen/fullscreen-manager.js'; +import { MediaPlayerManager } from '../../src/card-controller/media-player-manager.js'; +import { MicrophoneManager } from '../../src/card-controller/microphone-manager.js'; +import { ViewManager } from '../../src/card-controller/view/view-manager.js'; import { MenuButtonController, MenuButtonControllerOptions, -} from '../../src/components-lib/menu-button-controller'; +} from '../../src/components-lib/menu-button-controller.js'; import { AdvancedCameraCardConfig, AdvancedCameraCardView, MenuItem, ViewDisplayMode, -} from '../../src/config/types'; -import { MediaPlayerController } from '../../src/types'; -import { createGeneralAction, createViewAction } from '../../src/utils/action'; -import { ViewMedia } from '../../src/view/media'; -import { MediaQueriesResults } from '../../src/view/media-queries-results'; -import { View } from '../../src/view/view'; +} from '../../src/config/types.js'; +import { HomeAssistant } from '../../src/ha/types.js'; +import { MediaPlayerController } from '../../src/types.js'; +import { createGeneralAction, createViewAction } from '../../src/utils/action.js'; +import { MediaQueriesResults } from '../../src/view/media-queries-results.js'; +import { ViewMedia } from '../../src/view/media.js'; +import { View } from '../../src/view/view.js'; import { createCameraConfig, createCameraManager, @@ -36,7 +36,7 @@ import { createStore, createView, TestViewMedia, -} from '../test-utils'; +} from '../test-utils.js'; vi.mock('../../src/utils/media-player-controller.js'); vi.mock('../../src/card-controller/microphone-manager.js'); diff --git a/tests/components-lib/menu-controller.test.ts b/tests/components-lib/menu-controller.test.ts index 44792ce2..0c94b6c3 100644 --- a/tests/components-lib/menu-controller.test.ts +++ b/tests/components-lib/menu-controller.test.ts @@ -1,15 +1,15 @@ -import { handleActionConfig } from '@dermotduffy/custom-card-helpers'; import { beforeEach, describe, expect, it, vi } from 'vitest'; -import { MenuController } from '../../src/components-lib/menu-controller'; -import { SubmenuItem } from '../../src/components/submenu/types'; -import { MenuConfig, menuConfigSchema } from '../../src/config/types'; +import { MenuController } from '../../src/components-lib/menu-controller.js'; +import { SubmenuItem } from '../../src/components/submenu/types.js'; +import { MenuConfig, menuConfigSchema } from '../../src/config/types.js'; +import { handleActionConfig } from '../../src/ha/handle-action.js'; import { createInteractionActionEvent, createLitElement, createSubmenuInteractionActionEvent, } from '../test-utils'; -vi.mock('@dermotduffy/custom-card-helpers'); +vi.mock('../../src/ha/handle-action.js'); vi.mock('../../src/utils/ha'); const createMenuConfig = (config: unknown): MenuConfig => { diff --git a/tests/config/management.test.ts b/tests/config/management.test.ts index 9d202374..51eab9cf 100644 --- a/tests/config/management.test.ts +++ b/tests/config/management.test.ts @@ -1,7 +1,3 @@ -import { - CallServiceActionConfig, - PerformActionActionConfig, -} from '@dermotduffy/custom-card-helpers'; import { describe, expect, it } from 'vitest'; import { copyConfig, @@ -20,14 +16,18 @@ import { upgradeMoveToWithOverrides, upgradeObjectRecursively, upgradeWithOverrides, -} from '../../src/config/management'; -import { PTZControlAction } from '../../src/config/ptz'; +} from '../../src/config/management.js'; +import { PTZControlAction } from '../../src/config/ptz.js'; import { Actions, RawAdvancedCameraCardConfig, advancedCameraCardConfigSchema, -} from '../../src/config/types'; -import { getParseErrorPaths } from '../../src/utils/zod'; +} from '../../src/config/types.js'; +import { + CallServiceActionConfig, + PerformActionActionConfig, +} from '../../src/ha/types.js'; +import { getParseErrorPaths } from '../../src/utils/zod.js'; describe('general functions', () => { it('should set value', () => { diff --git a/tests/ha/compute-domain.test.ts b/tests/ha/compute-domain.test.ts new file mode 100644 index 00000000..c0f652a1 --- /dev/null +++ b/tests/ha/compute-domain.test.ts @@ -0,0 +1,26 @@ +import { describe, it, expect } from 'vitest'; +import { computeDomain } from '../../src/ha/compute-domain.js'; + +describe('computeDomain', () => { + it('should return the domain of an entity ID', () => { + expect(computeDomain('light.kitchen')).toBe('light'); + expect(computeDomain('sensor.temperature')).toBe('sensor'); + expect(computeDomain('switch.garage')).toBe('switch'); + }); + + it('should return an empty string if there is no dot in the entity ID', () => { + expect(computeDomain('invalidEntityId')).toBe(''); + }); + + it('should handle entity IDs with multiple dots correctly', () => { + expect(computeDomain('light.kitchen.ceiling')).toBe('light'); + }); + + it('should return an empty string for an empty entity ID', () => { + expect(computeDomain('')).toBe(''); + }); + + it('should return an empty string for a dot-only entity ID', () => { + expect(computeDomain('.')).toBe(''); + }); +}); diff --git a/tests/ha/haptic.test.ts b/tests/ha/haptic.test.ts new file mode 100644 index 00000000..8451ab70 --- /dev/null +++ b/tests/ha/haptic.test.ts @@ -0,0 +1,24 @@ +import { describe, expect, it, vi } from 'vitest'; +import { fireHASSEvent } from '../../src/ha/fire-hass-event.js'; +import { forwardHaptic, HapticType } from '../../src/ha/haptic.js'; + +vi.mock('../../src/ha/fire-hass-event.js', () => ({ + fireHASSEvent: vi.fn(), +})); + +// @vitest-environment jsdom +describe('forwardHaptic', () => { + it.each([ + ['success' as const], + ['warning' as const], + ['failure' as const], + ['light' as const], + ['medium' as const], + ['heavy' as const], + ['selection' as const], + ])('should call fireHASSEvent with %s', (hapticType: HapticType) => { + forwardHaptic(hapticType); + + expect(fireHASSEvent).toBeCalledWith(window, 'haptic', hapticType); + }); +}); diff --git a/tests/test-utils.ts b/tests/test-utils.ts index 381c3b99..67c5c32c 100644 --- a/tests/test-utils.ts +++ b/tests/test-utils.ts @@ -1,4 +1,3 @@ -import { CurrentUser } from '@dermotduffy/custom-card-helpers'; import { HassEntities, HassEntity } from 'home-assistant-js-websocket'; import { LitElement } from 'lit'; import screenfull from 'screenfull'; @@ -52,12 +51,8 @@ import { internalAdvancedCameraCardCustomActionSchema, performanceConfigSchema, } from '../src/config/types'; -import { - CapabilitiesRaw, - ExtendedHomeAssistant, - Interaction, - MediaLoadedInfo, -} from '../src/types'; +import { CurrentUser, HomeAssistant } from '../src/ha/types'; +import { CapabilitiesRaw, Interaction, MediaLoadedInfo } from '../src/types'; import { HassStateDifference } from '../src/utils/ha'; import { Device } from '../src/utils/ha/registry/device/types'; import { EntityRegistryManager } from '../src/utils/ha/registry/entity'; @@ -104,11 +99,8 @@ export const createCamera = ( return new Camera(config, engine, { capabilities: capabilities }); }; -export const createHASS = ( - states?: HassEntities, - user?: CurrentUser, -): ExtendedHomeAssistant => { - const hass = mock(); +export const createHASS = (states?: HassEntities, user?: CurrentUser): HomeAssistant => { + const hass = mock(); if (states) { hass.states = states; } diff --git a/tests/utils/action.test.ts b/tests/utils/action.test.ts index 70193e52..badfba53 100644 --- a/tests/utils/action.test.ts +++ b/tests/utils/action.test.ts @@ -1,7 +1,7 @@ -import { hasAction as customCardHasAction } from '@dermotduffy/custom-card-helpers'; import { afterEach, describe, expect, it, vi } from 'vitest'; import { mock } from 'vitest-mock-extended'; -import { actionSchema, INTERNAL_CALLBACK_ACTION } from '../../src/config/types'; +import { actionSchema, INTERNAL_CALLBACK_ACTION } from '../../src/config/types.js'; +import { hasAction as customCardHasAction } from '../../src/ha/has-action.js'; import { convertActionToCardCustomAction, createCameraAction, @@ -19,9 +19,9 @@ import { getActionConfigGivenAction, hasAction, stopEventFromActivatingCardWideActions, -} from '../../src/utils/action'; +} from '../../src/utils/action.js'; -vi.mock('@dermotduffy/custom-card-helpers'); +vi.mock('../../src/ha/has-action.js'); describe('convertActionToAdvancedCameraCardCustomAction', () => { it('should skip null action', () => { diff --git a/tests/utils/basic.test.ts b/tests/utils/basic.test.ts index f0578db6..6365e33e 100644 --- a/tests/utils/basic.test.ts +++ b/tests/utils/basic.test.ts @@ -1,5 +1,5 @@ import { afterAll, describe, expect, it, vi } from 'vitest'; -import { AdvancedCameraCardError } from '../../src/types'; +import { AdvancedCameraCardError } from '../../src/types.js'; import { allPromises, arefloatsApproximatelyEqual, @@ -9,7 +9,6 @@ import { contentsChanged, dayToDate, desparsifyArrays, - dispatchAdvancedCameraCardEvent, errorToConsole, formatDate, formatDateAndTime, @@ -28,32 +27,8 @@ import { setify, setOrRemoveAttribute, sleep, -} from '../../src/utils/basic'; -import { createSlot, createSlotHost } from '../test-utils'; - -// @vitest-environment jsdom -describe('dispatchAdvancedCameraCardEvent', () => { - it('should dispatch event without data', () => { - const element = document.createElement('div'); - const handler = vi.fn(); - element.addEventListener('advanced-camera-card:foo', handler); - - dispatchAdvancedCameraCardEvent(element, 'foo'); - expect(handler).toBeCalled(); - }); - - it('should dispatch event with data', () => { - const element = document.createElement('div'); - const data = { bar: 2 }; - const handler = vi.fn((ev) => { - expect(ev.detail).toBe(data); - }); - - element.addEventListener('advanced-camera-card:foo', handler); - dispatchAdvancedCameraCardEvent(element, 'foo', data); - expect(handler).toBeCalled(); - }); -}); +} from '../../src/utils/basic.js'; +import { createSlot, createSlotHost } from '../test-utils.js'; describe('prettifyTitle', () => { it('should return undefined when passed undefined', () => { @@ -130,6 +105,7 @@ describe('errorToConsole', () => { }); }); +// @vitest-environment jsdom describe('isHoverableDevice', () => { afterAll(() => { vi.restoreAllMocks(); @@ -163,6 +139,7 @@ describe('formatDate', () => { }); }); +// @vitest-environment jsdom describe('runWhenIdleIfSupported', () => { const originalRequestIdleCallback = window.requestIdleCallback; afterAll(() => { diff --git a/tests/utils/fire-advanced-camera-card-event.test.ts b/tests/utils/fire-advanced-camera-card-event.test.ts new file mode 100644 index 00000000..a8ec663d --- /dev/null +++ b/tests/utils/fire-advanced-camera-card-event.test.ts @@ -0,0 +1,26 @@ +import { describe, expect, it, vi } from 'vitest'; +import { fireAdvancedCameraCardEvent } from '../../src/utils/fire-advanced-camera-card-event.js'; + +// @vitest-environment jsdom +describe('fireAdvancedCameraCardEvent', () => { + it('should fire event without data', () => { + const element = document.createElement('div'); + const handler = vi.fn(); + element.addEventListener('advanced-camera-card:foo', handler); + + fireAdvancedCameraCardEvent(element, 'foo'); + expect(handler).toBeCalled(); + }); + + it('should fire event with data', () => { + const element = document.createElement('div'); + const data = { bar: 2 }; + const handler = vi.fn((ev) => { + expect(ev.detail).toBe(data); + }); + + element.addEventListener('advanced-camera-card:foo', handler); + fireAdvancedCameraCardEvent(element, 'foo', data); + expect(handler).toBeCalled(); + }); +}); diff --git a/tests/utils/ha/index.test.ts b/tests/utils/ha/index.test.ts index 52ca319d..4103cf76 100644 --- a/tests/utils/ha/index.test.ts +++ b/tests/utils/ha/index.test.ts @@ -1,5 +1,5 @@ -import { HomeAssistant } from '@dermotduffy/custom-card-helpers'; import { describe, expect, it, vi } from 'vitest'; +import { HomeAssistant } from '../../../src/ha/types.js'; import { canonicalizeHAURL, hasHAConnectionStateChanged, diff --git a/vite.config.ts b/vite.config.ts index 07b6d2fc..66930b91 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -13,6 +13,7 @@ const FULL_COVERAGE_FILES_RELATIVE = [ 'camera-manager/utils/*.ts', 'card-controller/**/*.ts', 'components-lib/**/!(timeline-source.ts)', + 'conditions/**/*.ts', 'config/**/*.ts', 'const.ts', 'types.ts', diff --git a/yarn.lock b/yarn.lock index 4b528376..1cd34758 100644 --- a/yarn.lock +++ b/yarn.lock @@ -630,21 +630,6 @@ __metadata: languageName: node linkType: hard -"@dermotduffy/custom-card-helpers@npm:^1.9.1": - version: 1.9.1 - resolution: "@dermotduffy/custom-card-helpers@npm:1.9.1" - dependencies: - "@formatjs/intl-utils": "npm:^3.8.4" - home-assistant-js-websocket: "npm:^9.4.0" - intl-messageformat: "npm:^9.11.1" - lit: "npm:^2.1.1" - rollup: "npm:^2.63.0" - superstruct: "npm:^0.15.3" - typescript: "npm:^4.5.4" - checksum: 10c0/e42073e00682195c3d253f9b36dc091f7329a5e2a5cdd395bf0988ec2c8585db887ef772975894e4a1126653a2f3cb348a4ea4c1fbe8ce739002fd0f8461da40 - languageName: node - linkType: hard - "@dermotduffy/panzoom@npm:^4.5.1": version: 4.5.1 resolution: "@dermotduffy/panzoom@npm:4.5.1" @@ -887,64 +872,6 @@ __metadata: languageName: node linkType: hard -"@formatjs/ecma402-abstract@npm:1.11.4": - version: 1.11.4 - resolution: "@formatjs/ecma402-abstract@npm:1.11.4" - dependencies: - "@formatjs/intl-localematcher": "npm:0.2.25" - tslib: "npm:^2.1.0" - checksum: 10c0/c25d56a54f7c6a356c8475ba76ba5357bbf8cb035ab1da5a6b3b75b41a49dae6e1790271bb619e8d09aca52f1daa3e28d5fa2297297fdef5e986e213be4c84b7 - languageName: node - linkType: hard - -"@formatjs/fast-memoize@npm:1.2.1": - version: 1.2.1 - resolution: "@formatjs/fast-memoize@npm:1.2.1" - dependencies: - tslib: "npm:^2.1.0" - checksum: 10c0/ec3d5f256ab5c889d7061f58a6c178908b3cec43831d26efdbf79db7f31a6045ab7d4448cf1829de213fa05bec144b795a632249d6a6cd566f7eb7f98daec574 - languageName: node - linkType: hard - -"@formatjs/icu-messageformat-parser@npm:2.1.0": - version: 2.1.0 - resolution: "@formatjs/icu-messageformat-parser@npm:2.1.0" - dependencies: - "@formatjs/ecma402-abstract": "npm:1.11.4" - "@formatjs/icu-skeleton-parser": "npm:1.3.6" - tslib: "npm:^2.1.0" - checksum: 10c0/d4d432df5232143e343a613a691abf4253f3e97a1fc0edc04b8dcdf2a88628f52fe5a47ed3e4c90ab20d843b6b4ac4c84cb883d040487d576181bfcae7f760f1 - languageName: node - linkType: hard - -"@formatjs/icu-skeleton-parser@npm:1.3.6": - version: 1.3.6 - resolution: "@formatjs/icu-skeleton-parser@npm:1.3.6" - dependencies: - "@formatjs/ecma402-abstract": "npm:1.11.4" - tslib: "npm:^2.1.0" - checksum: 10c0/47aed8193fb632e005a361c229725e2cd9e21844ef1c73995f2e64c67a15dd6c35897760a63af2345f1cbc1807d9ff8b3d90bc9d8c5d985ebfe877e079fdba27 - languageName: node - linkType: hard - -"@formatjs/intl-localematcher@npm:0.2.25": - version: 0.2.25 - resolution: "@formatjs/intl-localematcher@npm:0.2.25" - dependencies: - tslib: "npm:^2.1.0" - checksum: 10c0/a49d5d1a09ff5d02b3c14176783f0e26978895878a35b986fafdf8ecbaa474d669eb1ee1b7a257167cb8df54d5001011d6abde691bc7f75fd123e070e87c194a - languageName: node - linkType: hard - -"@formatjs/intl-utils@npm:^3.8.4": - version: 3.8.4 - resolution: "@formatjs/intl-utils@npm:3.8.4" - dependencies: - emojis-list: "npm:^3.0.0" - checksum: 10c0/737d5e796c46da0efc956a31a73a754e4e368fa1d7d7190a6c5a10192f6bab93569437a3165669fb0d435f6f054e0651f30e511f3d14bab467fd79384d0e2062 - languageName: node - linkType: hard - "@graphiteds/core@npm:^1.9.21": version: 1.9.21 resolution: "@graphiteds/core@npm:1.9.21" @@ -1090,7 +1017,7 @@ __metadata: languageName: node linkType: hard -"@lit-labs/ssr-dom-shim@npm:^1.0.0, @lit-labs/ssr-dom-shim@npm:^1.1.0, @lit-labs/ssr-dom-shim@npm:^1.2.0": +"@lit-labs/ssr-dom-shim@npm:^1.0.0, @lit-labs/ssr-dom-shim@npm:^1.2.0": version: 1.2.0 resolution: "@lit-labs/ssr-dom-shim@npm:1.2.0" checksum: 10c0/016168cf6901ab343462c13fb168dda6d549f8b42680aa394e6b7cd0af7cce51271e00dbfa5bbbe388912bf89cbb8f941a21cc3ec9bf95d6a84b6241aa9e5a72 @@ -1115,7 +1042,7 @@ __metadata: languageName: node linkType: hard -"@lit/reactive-element@npm:^1.1.0, @lit/reactive-element@npm:^1.3.0, @lit/reactive-element@npm:^1.6.0": +"@lit/reactive-element@npm:^1.1.0": version: 1.6.3 resolution: "@lit/reactive-element@npm:1.6.3" dependencies: @@ -2476,7 +2403,6 @@ __metadata: "@babel/plugin-proposal-decorators": "npm:^7.24.7" "@babel/plugin-transform-class-properties": "npm:^7.24.7" "@cycjimmy/jsmpeg-player": "npm:^6.0.5" - "@dermotduffy/custom-card-helpers": "npm:^1.9.1" "@dermotduffy/panzoom": "npm:^4.5.1" "@egjs/hammerjs": "npm:^2.0.17" "@graphiteds/core": "npm:^1.9.21" @@ -4474,13 +4400,6 @@ __metadata: languageName: node linkType: hard -"emojis-list@npm:^3.0.0": - version: 3.0.0 - resolution: "emojis-list@npm:3.0.0" - checksum: 10c0/7dc4394b7b910444910ad64b812392159a21e1a7ecc637c775a440227dcb4f80eff7fe61f4453a7d7603fa23d23d30cc93fe9e4b5ed985b88d6441cd4a35117b - languageName: node - linkType: hard - "encodeurl@npm:~1.0.2": version: 1.0.2 resolution: "encodeurl@npm:1.0.2" @@ -6212,18 +6131,6 @@ __metadata: languageName: node linkType: hard -"intl-messageformat@npm:^9.11.1": - version: 9.13.0 - resolution: "intl-messageformat@npm:9.13.0" - dependencies: - "@formatjs/ecma402-abstract": "npm:1.11.4" - "@formatjs/fast-memoize": "npm:1.2.1" - "@formatjs/icu-messageformat-parser": "npm:2.1.0" - tslib: "npm:^2.1.0" - checksum: 10c0/d50b220ae943278a4403cb004e3776f288b5c2a2673b0dc11347d9b9d4e0361c3c33288cea54189a69b42c64a35171608c9c25ed55d6a9a6ec7f7af5e7782541 - languageName: node - linkType: hard - "into-stream@npm:^7.0.0": version: 7.0.0 resolution: "into-stream@npm:7.0.0" @@ -7136,17 +7043,6 @@ __metadata: languageName: node linkType: hard -"lit-element@npm:^3.3.0": - version: 3.3.3 - resolution: "lit-element@npm:3.3.3" - dependencies: - "@lit-labs/ssr-dom-shim": "npm:^1.1.0" - "@lit/reactive-element": "npm:^1.3.0" - lit-html: "npm:^2.8.0" - checksum: 10c0/f44c12fa3423a4e9ca5b84651410687e14646bb270ac258325e6905affac64a575f041f8440377e7ebaefa3910b6f0d6b8b1e902cb1aa5d0849b3fdfbf4fb3b6 - languageName: node - linkType: hard - "lit-element@npm:^4.0.4": version: 4.0.4 resolution: "lit-element@npm:4.0.4" @@ -7158,15 +7054,6 @@ __metadata: languageName: node linkType: hard -"lit-html@npm:^2.8.0": - version: 2.8.0 - resolution: "lit-html@npm:2.8.0" - dependencies: - "@types/trusted-types": "npm:^2.0.2" - checksum: 10c0/90057dee050803823ac884c1355b0213ab8c05fbe2ec63943c694b61aade5d36272068f3925f45a312835e504f9c9784738ef797009f0a756a750351eafb52d5 - languageName: node - linkType: hard - "lit-html@npm:^3.1.2": version: 3.1.2 resolution: "lit-html@npm:3.1.2" @@ -7187,17 +7074,6 @@ __metadata: languageName: node linkType: hard -"lit@npm:^2.1.1": - version: 2.8.0 - resolution: "lit@npm:2.8.0" - dependencies: - "@lit/reactive-element": "npm:^1.6.0" - lit-element: "npm:^3.3.0" - lit-html: "npm:^2.8.0" - checksum: 10c0/bf33c26b1937ee204aed1adbfa4b3d43a284e85aad8ea9763c7865365917426eded4e5888158b4136095ea42054812561fe272862b61775f1198fad3588b071f - languageName: node - linkType: hard - "lit@npm:^3.1.4": version: 3.1.4 resolution: "lit@npm:3.1.4" @@ -10025,20 +9901,6 @@ __metadata: languageName: node linkType: hard -"rollup@npm:^2.63.0": - version: 2.79.1 - resolution: "rollup@npm:2.79.1" - dependencies: - fsevents: "npm:~2.3.2" - dependenciesMeta: - fsevents: - optional: true - bin: - rollup: dist/bin/rollup - checksum: 10c0/421418687f5dcd7324f4387f203c6bfc7118b7ace789e30f5da022471c43e037a76f5fd93837052754eeeae798a4fb266ac05ccee1e594406d912a59af98dde9 - languageName: node - linkType: hard - "rollup@npm:^3.29.4": version: 3.29.4 resolution: "rollup@npm:3.29.4" @@ -10902,13 +10764,6 @@ __metadata: languageName: node linkType: hard -"superstruct@npm:^0.15.3": - version: 0.15.5 - resolution: "superstruct@npm:0.15.5" - checksum: 10c0/73ae2043443dcc7868da6e8b4e4895410c79a88e021b514c665161199675ee920d5eadd85bb9dee5a9f515817e62f4b65a67ccb82d29f73259d012afcbcd3ce4 - languageName: node - linkType: hard - "supports-color@npm:^2.0.0": version: 2.0.0 resolution: "supports-color@npm:2.0.0" @@ -11304,7 +11159,7 @@ __metadata: languageName: node linkType: hard -"tslib@npm:^2.0.1, tslib@npm:^2.1.0": +"tslib@npm:^2.0.1": version: 2.6.2 resolution: "tslib@npm:2.6.2" checksum: 10c0/e03a8a4271152c8b26604ed45535954c0a45296e32445b4b87f8a5abdb2421f40b59b4ca437c4346af0f28179780d604094eb64546bee2019d903d01c6c19bdb @@ -11462,16 +11317,6 @@ __metadata: languageName: node linkType: hard -"typescript@npm:^4.5.4": - version: 4.9.5 - resolution: "typescript@npm:4.9.5" - bin: - tsc: bin/tsc - tsserver: bin/tsserver - checksum: 10c0/5f6cad2e728a8a063521328e612d7876e12f0d8a8390d3b3aaa452a6a65e24e9ac8ea22beb72a924fd96ea0a49ea63bb4e251fb922b12eedfb7f7a26475e5c56 - languageName: node - linkType: hard - "typescript@npm:^5.4.5": version: 5.4.5 resolution: "typescript@npm:5.4.5" @@ -11482,16 +11327,6 @@ __metadata: languageName: node linkType: hard -"typescript@patch:typescript@npm%3A^4.5.4#optional!builtin": - version: 4.9.5 - resolution: "typescript@patch:typescript@npm%3A4.9.5#optional!builtin::version=4.9.5&hash=289587" - bin: - tsc: bin/tsc - tsserver: bin/tsserver - checksum: 10c0/e3333f887c6829dfe0ab6c1dbe0dd1e3e2aeb56c66460cb85c5440c566f900c833d370ca34eb47558c0c69e78ced4bfe09b8f4f98b6de7afed9b84b8d1dd06a1 - languageName: node - linkType: hard - "typescript@patch:typescript@npm%3A^5.4.5#optional!builtin": version: 5.4.5 resolution: "typescript@patch:typescript@npm%3A5.4.5#optional!builtin::version=5.4.5&hash=5adc0c"