diff --git a/src/Helper.ts b/src/Helper.ts index e6ee596..30faa90 100644 --- a/src/Helper.ts +++ b/src/Helper.ts @@ -365,6 +365,17 @@ class Helper { return states; } + /** + * Get the state object of a HASS entity. + * + * @param {EntityRegistryEntry} entity The entity for which to get the state. + * @returns {HassEntity | undefined} The state object of the entity, or undefined if not found. + * @static + */ + static getEntityState(entity: EntityRegistryEntry): HassEntity | undefined { + return this.#hassStates[entity.entity_id]; + } + /** * Sanitize a classname. * diff --git a/src/cards/SceneCard.ts b/src/cards/SceneCard.ts new file mode 100644 index 0000000..09f40de --- /dev/null +++ b/src/cards/SceneCard.ts @@ -0,0 +1,63 @@ +import {AbstractCard} from "./AbstractCard"; +import {cards} from "../types/strategy/cards"; +import {EntityRegistryEntry} from "../types/homeassistant/data/entity_registry"; +import {generic} from "../types/strategy/generic"; +import {EntityCardConfig} from "../types/lovelace-mushroom/cards/entity-card-config"; +import {Helper} from "../Helper"; +import isCallServiceActionConfig = generic.isCallServiceActionConfig; +import isCallServiceActionTarget = generic.isCallServiceActionTarget; + +// noinspection JSUnusedGlobalSymbols Class is dynamically imported. +/** + * Scene Card Class + * + * Used to create a card for an entity of the scene domain. + * + * @class + * @extends AbstractCard + */ +class SceneCard extends AbstractCard { + /** + * Default configuration of the card. + * + * @type {EntityCardConfig} + * @private + */ + #defaultConfig: EntityCardConfig = { + type: "custom:mushroom-entity-card", + icon: "mdi:palette", + icon_color: "blue", + tap_action: { + action: "call-service", + service: "scene.turn_on", + target: { + entity_id: undefined, + }, + }, + }; + + /** + * Class constructor. + * + * @param {EntityRegistryEntry} entity The hass entity to create a card for. + * @param {cards.EntityCardOptions} [options={}] Options for the card. + * @throws {Error} If the Helper module isn't initialized. + */ + constructor(entity: EntityRegistryEntry, options: cards.EntityCardOptions = {}) { + super(entity); + + // Set the target for tap action. + if ( + isCallServiceActionConfig(this.#defaultConfig.tap_action) + && isCallServiceActionTarget(this.#defaultConfig.tap_action.target) + ) { + this.#defaultConfig.tap_action.target.entity_id = entity.entity_id; + } + + this.#defaultConfig.icon = Helper.getEntityState(entity)?.attributes.icon ?? this.#defaultConfig.icon; + + this.config = Object.assign(this.config, this.#defaultConfig, options); + } +} + +export {SceneCard}; diff --git a/src/configurationDefaults.ts b/src/configurationDefaults.ts index bc6400c..0fd7bea 100644 --- a/src/configurationDefaults.ts +++ b/src/configurationDefaults.ts @@ -37,6 +37,12 @@ export const getConfigurationDefaults = (localize: Function): StrategyDefaults = offService: "light.turn_off", hidden: false, }, + scene: { + title: localize("scene.scenes"), + showControls: false, + onService: "scene.turn_on", + hidden: false, + }, fan: { title: localize("fan.fans"), showControls: true, @@ -151,6 +157,10 @@ export const getConfigurationDefaults = (localize: Function): StrategyDefaults = order: 8, hidden: false, }, + scene: { + order: 9, + hidden: false, + }, } }; }; diff --git a/src/translations/en.json b/src/translations/en.json index 73a9c87..0b75e34 100644 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -44,6 +44,9 @@ "media_player": { "media_players": "Mediaplayers" }, + "scene": { + "scenes": "Scenes" + }, "select": { "selects": "Selects" }, diff --git a/src/translations/nl.json b/src/translations/nl.json index e6f6ecf..03009da 100644 --- a/src/translations/nl.json +++ b/src/translations/nl.json @@ -44,6 +44,9 @@ "media_player": { "media_players": "Mediaspelers" }, + "scene": { + "scenes": "Scenes" + }, "select": { "selects": "Statuslijsten" }, diff --git a/src/views/AbstractView.ts b/src/views/AbstractView.ts index 497cdaa..9e2b3a9 100644 --- a/src/views/AbstractView.ts +++ b/src/views/AbstractView.ts @@ -123,7 +123,7 @@ abstract class AbstractView { } // Add a Controller Card for all the entities in the view. - if (viewCards.length) { + if (this.viewControllerCard.cards.length && viewCards.length) { viewCards.unshift(this.viewControllerCard); } diff --git a/src/views/SceneView.ts b/src/views/SceneView.ts new file mode 100644 index 0000000..54a66ce --- /dev/null +++ b/src/views/SceneView.ts @@ -0,0 +1,52 @@ +import {Helper} from "../Helper"; +import {AbstractView} from "./AbstractView"; +import {views} from "../types/strategy/views"; + +// noinspection JSUnusedGlobalSymbols Class is dynamically imported. +/** + * Scene View Class. + * + * Used to create a view for entities of the scene domain. + * + * @class SceneView + * @extends AbstractView + */ +class SceneView extends AbstractView { + /** + * Domain of the view's entities. + * + * @type {string} + * @static + * @private + */ + static #domain: string = "scene"; + + /** + * Default configuration of the view. + * + * @type {views.ViewConfig} + * @private + */ + #defaultConfig: views.ViewConfig = { + title: Helper.customLocalize("scene.scenes"), + path: "scenes", + icon: "mdi:palette", + subview: false, + controllerCardOptions: { + showControls: false, + }, + }; + + /** + * Class constructor. + * + * @param {views.ViewConfig} [options={}] Options for the view. + */ + constructor(options: views.ViewConfig = {}) { + super(SceneView.#domain); + + this.config = Object.assign(this.config, this.#defaultConfig, options); + } +} + +export {SceneView};