forked from DigiLive/mushroom-strategy
Refactor JavaScript to TypeScript (#81)
Other changes include: * Add Vacuum Card and View. * Add hiding a view if no device is configured for it. Closes #24. * Add icon to HomeView configuration. * Add version output to console. * Add version bumper. * Add .editorconfig settings. * Refactor README, because the information moved to the repository's Wiki. Closes #87.
This commit is contained in:
+196
-168
@@ -1,4 +1,11 @@
|
||||
import {optionDefaults} from "./optionDefaults";
|
||||
import {configurationDefaults} from "./configurationDefaults";
|
||||
import {HassEntities, HassEntity} from "home-assistant-js-websocket";
|
||||
import deepmerge from "deepmerge";
|
||||
import {EntityRegistryEntry} from "./types/homeassistant/data/entity_registry";
|
||||
import {DeviceRegistryEntry} from "./types/homeassistant/data/device_registry";
|
||||
import {AreaRegistryEntry} from "./types/homeassistant/data/area_registry";
|
||||
import {generic} from "./types/strategy/generic";
|
||||
import StrategyArea = generic.StrategyArea;
|
||||
|
||||
/**
|
||||
* Helper Class
|
||||
@@ -9,31 +16,34 @@ class Helper {
|
||||
/**
|
||||
* An array of entities from Home Assistant's entity registry.
|
||||
*
|
||||
* @type {hassEntity[]}
|
||||
* @type {EntityRegistryEntry[]}
|
||||
* @private
|
||||
*/
|
||||
static #entities;
|
||||
static #entities: EntityRegistryEntry[];
|
||||
|
||||
/**
|
||||
* An array of entities from Home Assistant's device registry.
|
||||
*
|
||||
* @type {deviceEntity[]}
|
||||
* @type {DeviceRegistryEntry[]}
|
||||
* @private
|
||||
*/
|
||||
static #devices;
|
||||
static #devices: DeviceRegistryEntry[];
|
||||
|
||||
/**
|
||||
* An array of entities from Home Assistant's area registry.
|
||||
*
|
||||
* @type {areaEntity[]}
|
||||
* @type {StrategyArea[]}
|
||||
* @private
|
||||
*/
|
||||
static #areas = [];
|
||||
static #areas: StrategyArea[] = [];
|
||||
|
||||
/**
|
||||
* An array of state entities from Home Assistant's Hass object.
|
||||
*
|
||||
* @type {hassObject["states"]}
|
||||
* @type {HassEntities}
|
||||
* @private
|
||||
*/
|
||||
static #hassStates;
|
||||
static #hassStates: HassEntities;
|
||||
|
||||
/**
|
||||
* Indicates whether this module is initialized.
|
||||
@@ -41,27 +51,30 @@ class Helper {
|
||||
* @type {boolean} True if initialized.
|
||||
* @private
|
||||
*/
|
||||
static #initialized = false;
|
||||
static #initialized: boolean = false;
|
||||
|
||||
/**
|
||||
* The Custom strategy configuration.
|
||||
*
|
||||
* @type {customStrategyOptions | {}}
|
||||
* @type {generic.StrategyConfig}
|
||||
* @private
|
||||
*/
|
||||
static #strategyOptions = {};
|
||||
static #strategyOptions: generic.StrategyConfig;
|
||||
|
||||
/**
|
||||
* Set to true for more verbose information in the console.
|
||||
*
|
||||
* @type {boolean}
|
||||
* @private
|
||||
*/
|
||||
static debug = optionDefaults.debug;
|
||||
static #debug: boolean;
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* This class shouldn't be instantiated directly. Instead, it should be initialized with method initialize().
|
||||
* This class shouldn't be instantiated directly.
|
||||
* Instead, it should be initialized with method initialize().
|
||||
*
|
||||
* @throws {Error} If trying to instantiate this class.
|
||||
*/
|
||||
constructor() {
|
||||
@@ -71,127 +84,115 @@ class Helper {
|
||||
/**
|
||||
* Custom strategy configuration.
|
||||
*
|
||||
* @returns {customStrategyOptions|{}}
|
||||
* @returns {generic.StrategyConfig}
|
||||
* @static
|
||||
*/
|
||||
static get strategyOptions() {
|
||||
static get strategyOptions(): generic.StrategyConfig {
|
||||
return this.#strategyOptions;
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {areaEntity[]}
|
||||
* Get the entities from Home Assistant's area registry.
|
||||
*
|
||||
* @returns {StrategyArea[]}
|
||||
* @static
|
||||
*/
|
||||
static get areas() {
|
||||
static get areas(): StrategyArea[] {
|
||||
return this.#areas;
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {deviceEntity[]}
|
||||
* Get the devices from Home Assistant's device registry.
|
||||
*
|
||||
* @returns {DeviceRegistryEntry[]}
|
||||
* @static
|
||||
*/
|
||||
static get devices() {
|
||||
static get devices(): DeviceRegistryEntry[] {
|
||||
return this.#devices;
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {hassEntity[]}
|
||||
* Get the entities from Home Assistant's entity registry.
|
||||
*
|
||||
* @returns {EntityRegistryEntry[]}
|
||||
* @static
|
||||
*/
|
||||
static get entities() {
|
||||
static get entities(): EntityRegistryEntry[] {
|
||||
return this.#entities;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current debug mode of the mushroom strategy.
|
||||
*
|
||||
* @returns {boolean}
|
||||
* @static
|
||||
*/
|
||||
static get debug() {
|
||||
return this.debug;
|
||||
static get debug(): boolean {
|
||||
return this.#debug;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize this module.
|
||||
*
|
||||
* @param {dashBoardInfo | viewInfo} info Strategy information object.
|
||||
* @param {generic.DashBoardInfo} info Strategy information object.
|
||||
* @returns {Promise<void>}
|
||||
* @static
|
||||
*/
|
||||
static async initialize(info) {
|
||||
static async initialize(info: generic.DashBoardInfo): Promise<void> {
|
||||
// Initialize properties.
|
||||
this.#hassStates = info.hass.states;
|
||||
this.#strategyOptions = deepmerge(configurationDefaults, info.config?.strategy?.options ?? {});
|
||||
this.#debug = this.#strategyOptions.debug;
|
||||
|
||||
try {
|
||||
// Query the registries of Home Assistant.
|
||||
[this.#entities, this.#devices, this.#areas] = await Promise.all([
|
||||
info.hass.callWS({type: "config/entity_registry/list"}),
|
||||
info.hass.callWS({type: "config/device_registry/list"}),
|
||||
info.hass.callWS({type: "config/area_registry/list"}),
|
||||
|
||||
// noinspection ES6MissingAwait False positive? https://youtrack.jetbrains.com/issue/WEB-63746
|
||||
[Helper.#entities, Helper.#devices, Helper.#areas] = await Promise.all([
|
||||
info.hass.callWS({type: "config/entity_registry/list"}) as Promise<EntityRegistryEntry[]>,
|
||||
info.hass.callWS({type: "config/device_registry/list"}) as Promise<DeviceRegistryEntry[]>,
|
||||
info.hass.callWS({type: "config/area_registry/list"}) as Promise<AreaRegistryEntry[]>,
|
||||
]);
|
||||
} catch (e) {
|
||||
console.error(Helper.debug ? e : "An error occurred while querying Home assistant's registries!");
|
||||
Helper.logError("An error occurred while querying Home assistant's registries!", e);
|
||||
throw 'Check the console for details';
|
||||
}
|
||||
|
||||
// Cloning is required for the purpose of the required undisclosed area.
|
||||
this.#strategyOptions = structuredClone(info.config.strategy.options || {});
|
||||
this.debug = this.#strategyOptions.debug;
|
||||
|
||||
// Setup required configuration entries.
|
||||
// TODO: Refactor to something smarter than repeating code for areas, views and domains.
|
||||
this.#strategyOptions.areas = this.#strategyOptions.areas ?? {};
|
||||
this.#strategyOptions.views = this.#strategyOptions.views ?? {};
|
||||
this.#strategyOptions.domains = this.#strategyOptions.domains ?? {};
|
||||
|
||||
// Setup and add the undisclosed area if not hidden in the strategy options.
|
||||
// Create and add the undisclosed area if not hidden in the strategy options.
|
||||
if (!this.#strategyOptions.areas.undisclosed?.hidden) {
|
||||
this.#strategyOptions.areas.undisclosed = {
|
||||
...optionDefaults.areas.undisclosed,
|
||||
...configurationDefaults.areas.undisclosed,
|
||||
...this.#strategyOptions.areas.undisclosed,
|
||||
};
|
||||
|
||||
// Make sure the area_id of the custom undisclosed area remains null.
|
||||
this.#strategyOptions.areas.undisclosed.area_id = null;
|
||||
// Make sure the custom configuration of the undisclosed area doesn't overwrite the area_id.
|
||||
this.#strategyOptions.areas.undisclosed.area_id = "undisclosed";
|
||||
|
||||
this.#areas.push(this.#strategyOptions.areas.undisclosed);
|
||||
}
|
||||
|
||||
// Merge custom areas of the strategy options into hass areas.
|
||||
// Merge custom areas of the strategy options into strategy areas.
|
||||
this.#areas = Helper.areas.map(area => {
|
||||
return {...area, ...this.#strategyOptions.areas[area.area_id ?? "undisclosed"]};
|
||||
return {...area, ...this.#strategyOptions.areas?.[area.area_id]};
|
||||
});
|
||||
|
||||
// Sort hass areas by order first and then by name.
|
||||
// Sort strategy areas by order first and then by name.
|
||||
this.#areas.sort((a, b) => {
|
||||
return (a.order ?? Infinity) - (b.order ?? Infinity) || a.name.localeCompare(b.name);
|
||||
});
|
||||
|
||||
// Merge the views of the strategy options and the default views.
|
||||
for (const view of Object.keys(optionDefaults.views)) {
|
||||
this.#strategyOptions.views[view] = {
|
||||
...optionDefaults.views[view],
|
||||
...(this.#strategyOptions.views[view]),
|
||||
};
|
||||
}
|
||||
|
||||
// Sort views of the strategy options by order first and then by title.
|
||||
// Sort custom and default views of the strategy options by order first and then by title.
|
||||
this.#strategyOptions.views = Object.fromEntries(
|
||||
Object.entries(this.#strategyOptions.views).sort(([, a], [, b]) => {
|
||||
return (a.order ?? Infinity) - (b.order ?? Infinity) || a.title?.localeCompare(b.title);
|
||||
}),
|
||||
Object.entries(this.#strategyOptions.views).sort(([, a], [, b]) => {
|
||||
return (a.order ?? Infinity) - (b.order ?? Infinity) || (a.title ?? "undefined").localeCompare(b.title ?? "undefined");
|
||||
}),
|
||||
);
|
||||
|
||||
// Merge the domains of the strategy options and the default domains.
|
||||
for (const domain of Object.keys(optionDefaults.domains)) {
|
||||
this.#strategyOptions.domains[domain] = {
|
||||
...optionDefaults.domains[domain],
|
||||
...(this.#strategyOptions.domains[domain]),
|
||||
};
|
||||
}
|
||||
|
||||
// Sort domains of the strategy options by order first and then by title.
|
||||
// Sort custom and default domains of the strategy options by order first and then by title.
|
||||
this.#strategyOptions.domains = Object.fromEntries(
|
||||
Object.entries(this.#strategyOptions.domains).sort(([, a], [, b]) => {
|
||||
return (a.order ?? Infinity) - (b.order ?? Infinity) || a.title?.localeCompare(b.title);
|
||||
}),
|
||||
Object.entries(this.#strategyOptions.domains).sort(([, a], [, b]) => {
|
||||
return (a.order ?? Infinity) - (b.order ?? Infinity) || (a.title ?? "undefined").localeCompare(b.title ?? "undefined");
|
||||
}),
|
||||
);
|
||||
|
||||
this.#initialized = true;
|
||||
@@ -203,7 +204,7 @@ class Helper {
|
||||
* @returns {boolean} True if this module is initialized.
|
||||
* @static
|
||||
*/
|
||||
static isInitialized() {
|
||||
static isInitialized(): boolean {
|
||||
return this.#initialized;
|
||||
}
|
||||
|
||||
@@ -219,7 +220,7 @@ class Helper {
|
||||
* @return {string} The template string.
|
||||
* @static
|
||||
*/
|
||||
static getCountTemplate(domain, operator, value) {
|
||||
static getCountTemplate(domain: string, operator: string, value: string): string {
|
||||
// noinspection JSMismatchedCollectionQueryUpdate (False positive per 17-04-2023)
|
||||
/**
|
||||
* Array of entity state-entries, filtered by domain.
|
||||
@@ -232,7 +233,7 @@ class Helper {
|
||||
*
|
||||
* @type {string[]}
|
||||
*/
|
||||
const states = [];
|
||||
const states: string[] = [];
|
||||
|
||||
if (!this.isInitialized()) {
|
||||
console.warn("Helper class should be initialized before calling this method!");
|
||||
@@ -240,20 +241,20 @@ class Helper {
|
||||
|
||||
// Get the ID of the devices which are linked to the given area.
|
||||
for (const area of this.#areas) {
|
||||
const areaDeviceIds = this.#devices.filter(device => {
|
||||
const areaDeviceIds = this.#devices.filter((device) => {
|
||||
return device.area_id === area.area_id;
|
||||
}).map(device => {
|
||||
}).map((device) => {
|
||||
return device.id;
|
||||
});
|
||||
|
||||
// Get the entities of which all conditions of the callback function are met. @see areaFilterCallback.
|
||||
const newStates = this.#entities.filter(
|
||||
this.#areaFilterCallback, {
|
||||
area: area,
|
||||
domain: domain,
|
||||
areaDeviceIds: areaDeviceIds,
|
||||
})
|
||||
.map(entity => `states['${entity.entity_id}']`);
|
||||
this.#areaFilterCallback, {
|
||||
area: area,
|
||||
domain: domain,
|
||||
areaDeviceIds: areaDeviceIds,
|
||||
})
|
||||
.map((entity) => `states['${entity.entity_id}']`);
|
||||
|
||||
states.push(...newStates);
|
||||
}
|
||||
@@ -261,35 +262,6 @@ class Helper {
|
||||
return `{% set entities = [${states}] %} {{ entities | selectattr('state','${operator}','${value}') | list | count }}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback function for filtering entities.
|
||||
*
|
||||
* Entities of which all the conditions below are met are kept:
|
||||
* 1. Or/Neither the entity's linked device (if any) or/nor the entity itself is lined to the given area.
|
||||
* (See variable areaMatch)
|
||||
* 2. The entity's domain matches the given domain.
|
||||
* 3. The entity is not hidden and is not disabled.
|
||||
*
|
||||
* @param {hassEntity} entity The current hass entity to evaluate.
|
||||
* @this {areaFilterContext}
|
||||
*
|
||||
* @return {boolean} True to keep the entity.
|
||||
* @static
|
||||
*/
|
||||
static #areaFilterCallback(entity) {
|
||||
const areaMatch = this.area.area_id
|
||||
// Area is a hass entity; The entity's linked device or the entity itself is linked to the given area.
|
||||
? this.areaDeviceIds.includes(entity.device_id) || entity.area_id === this.area.area_id
|
||||
// Undisclosed area; Neither the entity's linked device (if any), nor the entity itself is linked to any area.
|
||||
: (this.areaDeviceIds.includes(entity.device_id) || !entity.device_id) && !entity.area_id;
|
||||
|
||||
return (
|
||||
areaMatch
|
||||
&& entity.entity_id.startsWith(`${this.domain}.`)
|
||||
&& entity.hidden_by == null && entity.disabled_by == null
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get device entities from the entity registry, filtered by area and domain.
|
||||
*
|
||||
@@ -298,36 +270,35 @@ class Helper {
|
||||
*
|
||||
* The result excludes hidden and disabled entities.
|
||||
*
|
||||
* @param {areaEntity} area Area entity.
|
||||
* @param {AreaRegistryEntry} area Area entity.
|
||||
* @param {string} domain The domain of the entity-id.
|
||||
*
|
||||
* @return {hassEntity[]} Array of device entities.
|
||||
* @return {EntityRegistryEntry[]} Array of device entities.
|
||||
* @static
|
||||
*/
|
||||
static getDeviceEntities(area, domain) {
|
||||
static getDeviceEntities(area: AreaRegistryEntry, domain: string): EntityRegistryEntry[] {
|
||||
if (!this.isInitialized()) {
|
||||
console.warn("Helper class should be initialized before calling this method!");
|
||||
}
|
||||
|
||||
// Get the ID of the devices which are linked to the given area.
|
||||
const areaDeviceIds = this.#devices.filter(device => {
|
||||
return device.area_id === area.area_id;
|
||||
}).map(device => {
|
||||
const areaDeviceIds = this.#devices.filter((device) => {
|
||||
return (device.area_id ?? "undisclosed") === area.area_id;
|
||||
}).map((device: DeviceRegistryEntry) => {
|
||||
|
||||
return device.id;
|
||||
});
|
||||
|
||||
// Return the entities of which all conditions of the callback function are met. @see areaFilterCallback.
|
||||
return this.#entities.filter(
|
||||
this.#areaFilterCallback, {
|
||||
area: area,
|
||||
domain: domain,
|
||||
areaDeviceIds: areaDeviceIds,
|
||||
})
|
||||
.sort((a, b) => {
|
||||
/** @type hassEntity */
|
||||
return a.original_name?.localeCompare(b.original_name);
|
||||
});
|
||||
this.#areaFilterCallback, {
|
||||
area: area,
|
||||
domain: domain,
|
||||
areaDeviceIds: areaDeviceIds,
|
||||
})
|
||||
.sort((a, b) => {
|
||||
return (a.original_name ?? "undefined").localeCompare(b.original_name ?? "undefined");
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -335,39 +306,41 @@ class Helper {
|
||||
*
|
||||
* The result excludes hidden and disabled entities.
|
||||
*
|
||||
* @param {areaEntity} area Area entity.
|
||||
* @param {AreaRegistryEntry} area Area entity.
|
||||
* @param {string} domain Domain of the entity-id.
|
||||
*
|
||||
* @return {stateObject[]} Array of state entities.
|
||||
* @return {HassEntity[]} Array of state entities.
|
||||
*/
|
||||
static getStateEntities(area, domain) {
|
||||
static getStateEntities(area: AreaRegistryEntry, domain: string): HassEntity[] {
|
||||
if (!this.isInitialized()) {
|
||||
console.warn("Helper class should be initialized before calling this method!");
|
||||
}
|
||||
|
||||
const states = [];
|
||||
const states: HassEntity[] = [];
|
||||
|
||||
// Create a map for the hassEntities and devices {id: object} to improve lookup speed.
|
||||
/** @type {Object<string, hassEntity>} */
|
||||
const entityMap = Object.fromEntries(this.#entities.map(entity => [entity.entity_id, entity]));
|
||||
/** @type {Object<string, deviceEntity>} */
|
||||
const deviceMap = Object.fromEntries(this.#devices.map(device => [device.id, device]));
|
||||
const entityMap: {
|
||||
[s: string]: EntityRegistryEntry;
|
||||
} = Object.fromEntries(this.#entities.map((entity) => [entity.entity_id, entity]));
|
||||
const deviceMap: {
|
||||
[s: string]: DeviceRegistryEntry;
|
||||
} = Object.fromEntries(this.#devices.map((device) => [device.id, device]));
|
||||
|
||||
// Get states whose entity-id starts with the given string.
|
||||
const stateEntities = Object.values(this.#hassStates).filter(
|
||||
state => state.entity_id.startsWith(`${domain}.`),
|
||||
(state) => state.entity_id.startsWith(`${domain}.`),
|
||||
);
|
||||
|
||||
for (const state of stateEntities) {
|
||||
const hassEntity = entityMap[state.entity_id];
|
||||
const device = deviceMap[hassEntity?.device_id];
|
||||
const device = deviceMap[hassEntity?.device_id ?? ""];
|
||||
|
||||
// Collect states of which any (whichever comes first) of the conditions below are met:
|
||||
// 1. The linked entity is linked to the given area.
|
||||
// 2. The entity is linked to a device, and the linked device is linked to the given area.
|
||||
if (
|
||||
(hassEntity?.area_id === area.area_id)
|
||||
|| (device && device.area_id === area.area_id)
|
||||
(hassEntity?.area_id === area.area_id)
|
||||
|| (device && device.area_id === area.area_id)
|
||||
) {
|
||||
states.push(state);
|
||||
}
|
||||
@@ -385,44 +358,22 @@ class Helper {
|
||||
* @param {string} className Name of the class to sanitize.
|
||||
* @returns {string} The sanitized classname.
|
||||
*/
|
||||
static sanitizeClassName(className) {
|
||||
static sanitizeClassName(className: string): string {
|
||||
className = className.charAt(0).toUpperCase() + className.slice(1);
|
||||
|
||||
return className.replace(/([-_][a-z])/g, group =>
|
||||
group
|
||||
.toUpperCase()
|
||||
.replace("-", "")
|
||||
.replace("_", ""),
|
||||
return className.replace(/([-_][a-z])/g, (group) => group
|
||||
.toUpperCase()
|
||||
.replace("-", "")
|
||||
.replace("_", ""),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the keys of nested objects by its property value.
|
||||
*
|
||||
* @param {Object<Object>} object An object of objects.
|
||||
* @param {string|number} property The name of the property to evaluate.
|
||||
* @param {*} value The value which the property should match.
|
||||
*
|
||||
* @return {string[]|number[]} An array with keys.
|
||||
*/
|
||||
static #getObjectKeysByPropertyValue(object, property, value) {
|
||||
const keys = [];
|
||||
|
||||
for (const key of Object.keys(object)) {
|
||||
if (object[key][property] === value) {
|
||||
keys.push(key);
|
||||
}
|
||||
}
|
||||
|
||||
return keys;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the ids of the views which aren't set to hidden in the strategy options.
|
||||
*
|
||||
* @return {string[]} An array of view ids.
|
||||
*/
|
||||
static getExposedViewIds() {
|
||||
static getExposedViewIds(): string[] {
|
||||
if (!this.isInitialized()) {
|
||||
console.warn("Helper class should be initialized before calling this method!");
|
||||
}
|
||||
@@ -435,13 +386,90 @@ class Helper {
|
||||
*
|
||||
* @return {string[]} An array of domain ids.
|
||||
*/
|
||||
static getExposedDomainIds() {
|
||||
static getExposedDomainIds(): string[] {
|
||||
if (!this.isInitialized()) {
|
||||
console.warn("Helper class should be initialized before calling this method!");
|
||||
}
|
||||
|
||||
return this.#getObjectKeysByPropertyValue(this.#strategyOptions.domains, "hidden", false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback function for filtering entities.
|
||||
*
|
||||
* Entities of which all the conditions below are met are kept:
|
||||
* 1. The entity is not hidden and is not disabled.
|
||||
* 2. The entity's domain matches the given domain.
|
||||
* 3. Or/Neither the entity's linked device (if any) or/nor the entity itself is linked to the given area.
|
||||
* (See variable areaMatch)
|
||||
*
|
||||
* @param {EntityRegistryEntry} entity The current hass entity to evaluate.
|
||||
* @this {AreaFilterContext}
|
||||
*
|
||||
* @return {boolean} True to keep the entity.
|
||||
* @static
|
||||
*/
|
||||
static #areaFilterCallback(
|
||||
this: {
|
||||
area: AreaRegistryEntry,
|
||||
areaDeviceIds: string[],
|
||||
domain: string,
|
||||
},
|
||||
entity: EntityRegistryEntry): boolean {
|
||||
const entityUnhidden = entity.hidden_by === null && entity.disabled_by === null;
|
||||
const domainMatches = entity.entity_id.startsWith(`${this.domain}.`);
|
||||
const entityLinked = this.area.area_id === "undisclosed"
|
||||
// Undisclosed area;
|
||||
// nor the entity itself, neither the entity's linked device (if any) is linked to any area.
|
||||
? !entity.area_id && (this.areaDeviceIds.includes(entity.device_id ?? "") || !entity.device_id)
|
||||
// Area is a hass entity;
|
||||
// The entity's linked device or the entity itself is linked to the given area.
|
||||
: this.areaDeviceIds.includes(entity.device_id ?? "") || entity.area_id === this.area.area_id;
|
||||
|
||||
return (entityUnhidden && domainMatches && entityLinked);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the keys of nested objects by its property value.
|
||||
*
|
||||
* @param {Object<string, any>} object An object of objects.
|
||||
* @param {string|number} property The name of the property to evaluate.
|
||||
* @param {*} value The value which the property should match.
|
||||
*
|
||||
* @return {string[]} An array with keys.
|
||||
*/
|
||||
static #getObjectKeysByPropertyValue(
|
||||
object: { [k: string]: any },
|
||||
property: string, value: any
|
||||
): string[] {
|
||||
const keys: string[] = [];
|
||||
|
||||
for (const key of Object.keys(object)) {
|
||||
if (object[key][property] === value) {
|
||||
keys.push(key);
|
||||
}
|
||||
}
|
||||
|
||||
return keys;
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs an error message to the console.
|
||||
*
|
||||
* @param {string} userMessage - The error message to display.
|
||||
* @param {unknown} [e] - (Optional) The error object or additional information.
|
||||
*
|
||||
* @return {void}
|
||||
*/
|
||||
static logError(userMessage: string, e?: unknown): void {
|
||||
if (Helper.debug) {
|
||||
console.error(userMessage, e);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
console.error(userMessage);
|
||||
}
|
||||
}
|
||||
|
||||
export {Helper};
|
||||
@@ -1,81 +0,0 @@
|
||||
import {Helper} from "../Helper";
|
||||
|
||||
/**
|
||||
* Abstract Card Class
|
||||
*
|
||||
* To create a new card, extend the new class with this one.
|
||||
*
|
||||
* @class
|
||||
* @abstract
|
||||
*/
|
||||
class AbstractCard {
|
||||
/**
|
||||
* Entity to create the card for.
|
||||
*
|
||||
* @type {hassEntity | areaEntity}
|
||||
*/
|
||||
entity;
|
||||
|
||||
/**
|
||||
* Options for creating a card.
|
||||
*
|
||||
* @type {abstractOptions}
|
||||
*/
|
||||
options = {
|
||||
type: "custom:mushroom-entity-card",
|
||||
icon: "mdi:help-circle",
|
||||
double_tap_action: {
|
||||
action: null,
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param {hassEntity | areaEntity} entity The hass entity to create a card for.
|
||||
* @throws {Error} If the Helper module isn't initialized.
|
||||
*/
|
||||
constructor(entity) {
|
||||
if (this.constructor === AbstractCard) {
|
||||
throw new Error("Abstract classes can't be instantiated.");
|
||||
}
|
||||
|
||||
if (!Helper.isInitialized()) {
|
||||
throw new Error("The Helper module must be initialized before using this one.");
|
||||
}
|
||||
|
||||
this.entity = entity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Merge the default options of this class and the custom options into the options of the parent class.
|
||||
*
|
||||
* @param {Object} [defaultOptions={}] Default options for the card.
|
||||
* @param {Object} [customOptions={}] Custom Options for the card.
|
||||
*/
|
||||
mergeOptions(defaultOptions, customOptions) {
|
||||
this.options = {
|
||||
...this.options,
|
||||
...defaultOptions,
|
||||
...customOptions,
|
||||
};
|
||||
|
||||
try {
|
||||
this.options.double_tap_action.target.entity_id = this.entity.entity_id;
|
||||
} catch { }
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a card for an entity.
|
||||
*
|
||||
* @return {abstractOptions & Object} A card object.
|
||||
*/
|
||||
getCard() {
|
||||
return {
|
||||
entity: this.entity.entity_id,
|
||||
...this.options,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export {AbstractCard};
|
||||
@@ -0,0 +1,59 @@
|
||||
import {Helper} from "../Helper";
|
||||
import {cards} from "../types/strategy/cards";
|
||||
import {generic} from "../types/strategy/generic";
|
||||
import {EntityCardConfig} from "../types/lovelace-mushroom/cards/entity-card-config";
|
||||
|
||||
/**
|
||||
* Abstract Card Class
|
||||
*
|
||||
* To create a new card, extend the new class with this one.
|
||||
*
|
||||
* @class
|
||||
* @abstract
|
||||
*/
|
||||
abstract class AbstractCard {
|
||||
/**
|
||||
* Entity to create the card for.
|
||||
*
|
||||
* @type {generic.RegistryEntry}
|
||||
*/
|
||||
entity: generic.RegistryEntry;
|
||||
|
||||
/**
|
||||
* Configuration of the card.
|
||||
*
|
||||
* @type {EntityCardConfig}
|
||||
*/
|
||||
config: EntityCardConfig = {
|
||||
type: "custom:mushroom-entity-card",
|
||||
icon: "mdi:help-circle",
|
||||
};
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param {generic.RegistryEntry} entity The hass entity to create a card for.
|
||||
* @throws {Error} If the Helper module isn't initialized.
|
||||
*/
|
||||
protected constructor(entity: generic.RegistryEntry) {
|
||||
if (!Helper.isInitialized()) {
|
||||
throw new Error("The Helper module must be initialized before using this one.");
|
||||
}
|
||||
|
||||
this.entity = entity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a card.
|
||||
*
|
||||
* @return {cards.AbstractCardConfig} A card object.
|
||||
*/
|
||||
getCard(): cards.AbstractCardConfig {
|
||||
return {
|
||||
...this.config,
|
||||
entity: "entity_id" in this.entity ? this.entity.entity_id : undefined,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export {AbstractCard};
|
||||
@@ -1,62 +0,0 @@
|
||||
import {AbstractCard} from "./AbstractCard";
|
||||
|
||||
/**
|
||||
* Area Card Class
|
||||
*
|
||||
* Used to create a card for an entity of the area domain.
|
||||
*
|
||||
* @class
|
||||
* @extends AbstractCard
|
||||
*/
|
||||
class AreaCard extends AbstractCard {
|
||||
/**
|
||||
* Default options of the card.
|
||||
*
|
||||
* @type {areaCardOptions}
|
||||
* @private
|
||||
*/
|
||||
#defaultOptions = {
|
||||
type: "custom:mushroom-template-card",
|
||||
primary: undefined,
|
||||
icon: "mdi:texture-box",
|
||||
icon_color: "blue",
|
||||
tap_action: {
|
||||
action: "navigate",
|
||||
navigation_path: undefined,
|
||||
},
|
||||
hold_action: {
|
||||
action: "none",
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param {areaEntity} area The area entity to create a card for.
|
||||
* @param {areaCardOptions} [options={}] Options for the card.
|
||||
* @throws {Error} If the Helper module isn't initialized.
|
||||
*/
|
||||
constructor(area, options = {}) {
|
||||
super(area);
|
||||
|
||||
this.#defaultOptions.primary = area.name;
|
||||
this.#defaultOptions.tap_action.navigation_path = area.area_id ?? area.name;
|
||||
|
||||
// Set card type to default if a type "default" is given in strategy options.
|
||||
if (options.type === "default") {
|
||||
options.type = this.#defaultOptions.type;
|
||||
}
|
||||
|
||||
this.mergeOptions(
|
||||
this.#defaultOptions,
|
||||
options,
|
||||
);
|
||||
|
||||
// Override the area's name with a custom name, unless a custom primary text is set.
|
||||
if (!options.primary && options.name) {
|
||||
this.options.primary = options.name;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export {AreaCard};
|
||||
@@ -0,0 +1,62 @@
|
||||
import {AbstractCard} from "./AbstractCard";
|
||||
import {cards} from "../types/strategy/cards";
|
||||
import {AreaRegistryEntry} from "../types/homeassistant/data/area_registry";
|
||||
import {TemplateCardConfig} from "../types/lovelace-mushroom/cards/template-card-config";
|
||||
|
||||
// noinspection JSUnusedGlobalSymbols Class is dynamically imported.
|
||||
/**
|
||||
* Area Card Class
|
||||
*
|
||||
* Used to create a card for an entity of the area domain.
|
||||
*
|
||||
* @class
|
||||
* @extends AbstractCard
|
||||
*/
|
||||
class AreaCard extends AbstractCard {
|
||||
/**
|
||||
* Default configuration of the card.
|
||||
*
|
||||
* @type {TemplateCardConfig}
|
||||
* @private
|
||||
*/
|
||||
#defaultConfig: TemplateCardConfig = {
|
||||
type: "custom:mushroom-template-card",
|
||||
primary: undefined,
|
||||
icon: "mdi:texture-box",
|
||||
icon_color: "blue",
|
||||
tap_action: {
|
||||
action: "navigate",
|
||||
navigation_path: "",
|
||||
},
|
||||
hold_action: {
|
||||
action: "none",
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param {AreaRegistryEntry} area The area entity to create a card for.
|
||||
* @param {cards.TemplateCardOptions} [options={}] Options for the card.
|
||||
*
|
||||
* @throws {Error} If the Helper module isn't initialized.
|
||||
*/
|
||||
constructor(area: AreaRegistryEntry, options: cards.TemplateCardOptions = {}) {
|
||||
super(area);
|
||||
|
||||
// Don't override the default card type if default is set in the strategy options.
|
||||
if (options.type === "default") {
|
||||
delete options.type;
|
||||
}
|
||||
|
||||
// Initialize the default configuration.
|
||||
this.#defaultConfig.primary = area.name;
|
||||
if (this.#defaultConfig.tap_action && ("navigation_path" in this.#defaultConfig.tap_action)) {
|
||||
this.#defaultConfig.tap_action.navigation_path = area.area_id;
|
||||
}
|
||||
|
||||
this.config = Object.assign(this.config, this.#defaultConfig, options);
|
||||
}
|
||||
}
|
||||
|
||||
export {AreaCard};
|
||||
@@ -1,41 +0,0 @@
|
||||
import {SensorCard} from "./SensorCard";
|
||||
|
||||
/**
|
||||
* Sensor Card Class
|
||||
*
|
||||
* Used to create a card for controlling an entity of the binary_sensor domain.
|
||||
*
|
||||
* @class
|
||||
* @extends SensorCard
|
||||
*/
|
||||
class BinarySensorCard extends SensorCard {
|
||||
/**
|
||||
* Default options of the card.
|
||||
*
|
||||
* @type {sensorCardOptions}
|
||||
* @private
|
||||
*/
|
||||
#defaultOptions = {
|
||||
type: "custom:mushroom-entity-card",
|
||||
icon: "mdi:power-cycle",
|
||||
icon_color: "green",
|
||||
};
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param {hassEntity} entity The hass entity to create a card for.
|
||||
* @param {sensorCardOptions} [options={}] Options for the card.
|
||||
* @throws {Error} If the Helper module isn't initialized.
|
||||
*/
|
||||
constructor(entity, options = {}) {
|
||||
super(entity);
|
||||
|
||||
this.mergeOptions(
|
||||
this.#defaultOptions,
|
||||
options,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export {BinarySensorCard};
|
||||
@@ -0,0 +1,42 @@
|
||||
import {SensorCard} from "./SensorCard";
|
||||
import {cards} from "../types/strategy/cards";
|
||||
import {EntityRegistryEntry} from "../types/homeassistant/data/entity_registry";
|
||||
import {EntityCardConfig} from "../types/lovelace-mushroom/cards/entity-card-config";
|
||||
|
||||
// noinspection JSUnusedGlobalSymbols Class is dynamically imported.
|
||||
/**
|
||||
* Sensor Card Class
|
||||
*
|
||||
* Used to create a card for controlling an entity of the binary_sensor domain.
|
||||
*
|
||||
* @class
|
||||
* @extends SensorCard
|
||||
*/
|
||||
class BinarySensorCard extends SensorCard {
|
||||
/**
|
||||
* Default configuration of the card.
|
||||
*
|
||||
* @type {EntityCardConfig}
|
||||
* @private
|
||||
*/
|
||||
#defaultConfig: EntityCardConfig = {
|
||||
type: "custom:mushroom-entity-card",
|
||||
icon: "mdi:power-cycle",
|
||||
icon_color: "green",
|
||||
};
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
this.config = Object.assign(this.config, this.#defaultConfig, options);
|
||||
}
|
||||
}
|
||||
|
||||
export {BinarySensorCard};
|
||||
@@ -1,41 +0,0 @@
|
||||
import {AbstractCard} from "./AbstractCard";
|
||||
|
||||
/**
|
||||
* Camera Card Class
|
||||
*
|
||||
* Used to create a card for controlling an entity of the camera domain.
|
||||
*
|
||||
* @class
|
||||
* @extends AbstractCard
|
||||
*/
|
||||
class CameraCard extends AbstractCard {
|
||||
/**
|
||||
* Default options of the card.
|
||||
*
|
||||
* @type {cameraCardOptions}
|
||||
* @private
|
||||
*/
|
||||
#defaultOptions = {
|
||||
type: "picture-entity",
|
||||
show_name: false,
|
||||
show_state: false,
|
||||
camera_view: "live",
|
||||
};
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param {hassEntity} entity The hass entity to create a card for.
|
||||
* @param {cameraCardOptions} [options={}] Options for the card.
|
||||
* @throws {Error} If the Helper module isn't initialized.
|
||||
*/
|
||||
constructor(entity, options = {}) {
|
||||
super(entity);
|
||||
this.mergeOptions(
|
||||
this.#defaultOptions,
|
||||
options,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export {CameraCard};
|
||||
@@ -0,0 +1,44 @@
|
||||
import {AbstractCard} from "./AbstractCard";
|
||||
import {cards} from "../types/strategy/cards";
|
||||
import {EntityRegistryEntry} from "../types/homeassistant/data/entity_registry";
|
||||
import {PictureEntityCardConfig} from "../types/homeassistant/panels/lovelave/cards/types";
|
||||
|
||||
// noinspection JSUnusedGlobalSymbols Class is dynamically imported.
|
||||
/**
|
||||
* Camera Card Class
|
||||
*
|
||||
* Used to create a card for controlling an entity of the camera domain.
|
||||
*
|
||||
* @class
|
||||
* @extends AbstractCard
|
||||
*/
|
||||
class CameraCard extends AbstractCard {
|
||||
/**
|
||||
* Default configuration of the card.
|
||||
*
|
||||
* @type {PictureEntityCardConfig}
|
||||
* @private
|
||||
*/
|
||||
#defaultConfig: PictureEntityCardConfig = {
|
||||
entity: "",
|
||||
type: "picture-entity",
|
||||
show_name: false,
|
||||
show_state: false,
|
||||
camera_view: "live",
|
||||
};
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param {EntityRegistryEntry} entity The hass entity to create a card for.
|
||||
* @param {cards.PictureEntityCardOptions} [options={}] Options for the card.
|
||||
* @throws {Error} If the Helper module isn't initialized.
|
||||
*/
|
||||
constructor(entity: EntityRegistryEntry, options: cards.PictureEntityCardOptions = {}) {
|
||||
super(entity);
|
||||
|
||||
this.config = Object.assign(this.config, this.#defaultConfig, options);
|
||||
}
|
||||
}
|
||||
|
||||
export {CameraCard};
|
||||
@@ -1,46 +0,0 @@
|
||||
import {AbstractCard} from "./AbstractCard";
|
||||
|
||||
/**
|
||||
* Climate Card Class
|
||||
*
|
||||
* Used to create a card for controlling an entity of the climate domain.
|
||||
*
|
||||
* @class
|
||||
* @extends AbstractCard
|
||||
*/
|
||||
class ClimateCard extends AbstractCard {
|
||||
/**
|
||||
* Default options of the card.
|
||||
*
|
||||
* @type {climateCardOptions}
|
||||
* @private
|
||||
*/
|
||||
#defaultOptions = {
|
||||
type: "custom:mushroom-climate-card",
|
||||
icon: undefined,
|
||||
hvac_modes: [
|
||||
"off",
|
||||
"cool",
|
||||
"heat",
|
||||
"fan_only",
|
||||
],
|
||||
show_temperature_control: true,
|
||||
};
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param {hassEntity} entity The hass entity to create a card for.
|
||||
* @param {climateCardOptions} [options={}] Options for the card.
|
||||
* @throws {Error} If the Helper module isn't initialized.
|
||||
*/
|
||||
constructor(entity, options = {}) {
|
||||
super(entity);
|
||||
this.mergeOptions(
|
||||
this.#defaultOptions,
|
||||
options,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export {ClimateCard};
|
||||
@@ -0,0 +1,48 @@
|
||||
import {AbstractCard} from "./AbstractCard";
|
||||
import {cards} from "../types/strategy/cards";
|
||||
import {EntityRegistryEntry} from "../types/homeassistant/data/entity_registry";
|
||||
import {ClimateCardConfig} from "../types/lovelace-mushroom/cards/climate-card-config";
|
||||
|
||||
// noinspection JSUnusedGlobalSymbols Class is dynamically imported.
|
||||
/**
|
||||
* Climate Card Class
|
||||
*
|
||||
* Used to create a card for controlling an entity of the climate domain.
|
||||
*
|
||||
* @class
|
||||
* @extends AbstractCard
|
||||
*/
|
||||
class ClimateCard extends AbstractCard {
|
||||
/**
|
||||
* Default configuration of the card.
|
||||
*
|
||||
* @type {ClimateCardConfig}
|
||||
* @private
|
||||
*/
|
||||
#defaultConfig: ClimateCardConfig = {
|
||||
type: "custom:mushroom-climate-card",
|
||||
icon: undefined,
|
||||
hvac_modes: [
|
||||
"off",
|
||||
"cool",
|
||||
"heat",
|
||||
"fan_only",
|
||||
],
|
||||
show_temperature_control: true,
|
||||
};
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param {EntityRegistryEntry} entity The hass entity to create a card for.
|
||||
* @param {cards.ClimateCardOptions} [options={}] Options for the card.
|
||||
* @throws {Error} If the Helper module isn't initialized.
|
||||
*/
|
||||
constructor(entity: EntityRegistryEntry, options: cards.ClimateCardOptions = {}) {
|
||||
super(entity);
|
||||
|
||||
this.config = Object.assign(this.config, this.#defaultConfig, options);
|
||||
}
|
||||
}
|
||||
|
||||
export {ClimateCard};
|
||||
@@ -0,0 +1,102 @@
|
||||
import {cards} from "../types/strategy/cards";
|
||||
import {StackCardConfig} from "../types/homeassistant/lovelace/cards/types";
|
||||
import {LovelaceCardConfig} from "../types/homeassistant/data/lovelace";
|
||||
import {HassServiceTarget} from "home-assistant-js-websocket";
|
||||
|
||||
/**
|
||||
* Controller Card class.
|
||||
*
|
||||
* Used for creating a Title Card with controls.
|
||||
*
|
||||
* @class
|
||||
*/
|
||||
class ControllerCard {
|
||||
/**
|
||||
* @type {HassServiceTarget} The target to control the entities of.
|
||||
* @private
|
||||
*/
|
||||
readonly #target: HassServiceTarget;
|
||||
|
||||
/**
|
||||
* Default configuration of the card.
|
||||
*
|
||||
* @type {cards.ControllerCardConfig}
|
||||
* @private
|
||||
*/
|
||||
readonly #defaultConfig: cards.ControllerCardConfig = {
|
||||
type: "mushroom-title-card",
|
||||
showControls: true,
|
||||
iconOn: "mdi:power-on",
|
||||
iconOff: "mdi:power-off",
|
||||
onService: "none",
|
||||
offService: "none",
|
||||
};
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param {HassServiceTarget} target The target to control the entities of.
|
||||
* @param {cards.ControllerCardOptions} options Controller Card options.
|
||||
*/
|
||||
constructor(target: HassServiceTarget, options: cards.ControllerCardOptions = {}) {
|
||||
this.#target = target;
|
||||
this.#defaultConfig = {
|
||||
...this.#defaultConfig,
|
||||
...options,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a Controller card.
|
||||
*
|
||||
* @return {StackCardConfig} A Controller card.
|
||||
*/
|
||||
createCard(): StackCardConfig {
|
||||
const cards: LovelaceCardConfig[] = [
|
||||
{
|
||||
type: "custom:mushroom-title-card",
|
||||
title: this.#defaultConfig.title,
|
||||
subtitle: this.#defaultConfig.subtitle,
|
||||
},
|
||||
];
|
||||
|
||||
if (this.#defaultConfig.showControls) {
|
||||
cards.push({
|
||||
type: "horizontal-stack",
|
||||
cards: [
|
||||
{
|
||||
type: "custom:mushroom-template-card",
|
||||
icon: this.#defaultConfig.iconOff,
|
||||
layout: "vertical",
|
||||
icon_color: "red",
|
||||
tap_action: {
|
||||
action: "call-service",
|
||||
service: this.#defaultConfig.offService,
|
||||
target: this.#target,
|
||||
data: {},
|
||||
},
|
||||
},
|
||||
{
|
||||
type: "custom:mushroom-template-card",
|
||||
icon: this.#defaultConfig.iconOn,
|
||||
layout: "vertical",
|
||||
icon_color: "amber",
|
||||
tap_action: {
|
||||
action: "call-service",
|
||||
service: this.#defaultConfig.onService,
|
||||
target: this.#target,
|
||||
data: {},
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
type: "horizontal-stack",
|
||||
cards: cards,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export {ControllerCard};
|
||||
@@ -1,42 +0,0 @@
|
||||
import {AbstractCard} from "./AbstractCard";
|
||||
|
||||
/**
|
||||
* Cover Card Class
|
||||
*
|
||||
* Used to create a card for controlling an entity of the cover domain.
|
||||
*
|
||||
* @class
|
||||
* @extends AbstractCard
|
||||
*/
|
||||
class CoverCard extends AbstractCard {
|
||||
/**
|
||||
* Default options of the card.
|
||||
*
|
||||
* @type {coverCardOptions}
|
||||
* @private
|
||||
*/
|
||||
#defaultOptions = {
|
||||
type: "custom:mushroom-cover-card",
|
||||
icon: undefined,
|
||||
show_buttons_control: true,
|
||||
show_position_control: true,
|
||||
show_tilt_position_control: true,
|
||||
};
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param {hassEntity} entity The hass entity to create a card for.
|
||||
* @param {coverCardOptions} [options={}] Options for the card.
|
||||
* @throws {Error} If the Helper module isn't initialized.
|
||||
*/
|
||||
constructor(entity, options = {}) {
|
||||
super(entity);
|
||||
this.mergeOptions(
|
||||
this.#defaultOptions,
|
||||
options,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export {CoverCard};
|
||||
@@ -0,0 +1,44 @@
|
||||
import {AbstractCard} from "./AbstractCard";
|
||||
import {cards} from "../types/strategy/cards";
|
||||
import {EntityRegistryEntry} from "../types/homeassistant/data/entity_registry";
|
||||
import {CoverCardConfig} from "../types/lovelace-mushroom/cards/cover-card-config";
|
||||
|
||||
// noinspection JSUnusedGlobalSymbols Class is dynamically imported.
|
||||
/**
|
||||
* Cover Card Class
|
||||
*
|
||||
* Used to create a card for controlling an entity of the cover domain.
|
||||
*
|
||||
* @class
|
||||
* @extends AbstractCard
|
||||
*/
|
||||
class CoverCard extends AbstractCard {
|
||||
/**
|
||||
* Default configuration of the card.
|
||||
*
|
||||
* @type {CoverCardConfig}
|
||||
* @private
|
||||
*/
|
||||
#defaultConfig: CoverCardConfig = {
|
||||
type: "custom:mushroom-cover-card",
|
||||
icon: undefined,
|
||||
show_buttons_control: true,
|
||||
show_position_control: true,
|
||||
show_tilt_position_control: true,
|
||||
};
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param {EntityRegistryEntry} entity The hass entity to create a card for.
|
||||
* @param {cards.CoverCardOptions} [options={}] Options for the card.
|
||||
* @throws {Error} If the Helper module isn't initialized.
|
||||
*/
|
||||
constructor(entity: EntityRegistryEntry, options: cards.CoverCardOptions = {}) {
|
||||
super(entity);
|
||||
|
||||
this.config = Object.assign(this.config, this.#defaultConfig, options);
|
||||
}
|
||||
}
|
||||
|
||||
export {CoverCard};
|
||||
@@ -1,42 +0,0 @@
|
||||
import {AbstractCard} from "./AbstractCard";
|
||||
|
||||
/**
|
||||
* Fan Card Class
|
||||
*
|
||||
* Used to create a card for controlling an entity of the fan domain.
|
||||
*
|
||||
* @class
|
||||
* @extends AbstractCard
|
||||
*/
|
||||
class FanCard extends AbstractCard {
|
||||
/**
|
||||
* Default options of the card.
|
||||
*
|
||||
* @type {fanCardOptions}
|
||||
* @private
|
||||
*/
|
||||
#defaultOptions = {
|
||||
type: "custom:mushroom-fan-card",
|
||||
icon: undefined,
|
||||
show_percentage_control: true,
|
||||
show_oscillate_control: true,
|
||||
icon_animation: true,
|
||||
};
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param {hassEntity} entity The hass entity to create a card for.
|
||||
* @param {fanCardOptions} [options={}] Options for the card.
|
||||
* @throws {Error} If the Helper module isn't initialized.
|
||||
*/
|
||||
constructor(entity, options = {}) {
|
||||
super(entity);
|
||||
this.mergeOptions(
|
||||
this.#defaultOptions,
|
||||
options,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export {FanCard};
|
||||
@@ -0,0 +1,44 @@
|
||||
import {AbstractCard} from "./AbstractCard";
|
||||
import {cards} from "../types/strategy/cards";
|
||||
import {EntityRegistryEntry} from "../types/homeassistant/data/entity_registry";
|
||||
import {FanCardConfig} from "../types/lovelace-mushroom/cards/fan-card-config";
|
||||
|
||||
// noinspection JSUnusedGlobalSymbols Class is dynamically imported.
|
||||
/**
|
||||
* Fan Card Class
|
||||
*
|
||||
* Used to create a card for controlling an entity of the fan domain.
|
||||
*
|
||||
* @class
|
||||
* @extends AbstractCard
|
||||
*/
|
||||
class FanCard extends AbstractCard {
|
||||
/**
|
||||
* Default configuration of the card.
|
||||
*
|
||||
* @type {FanCardConfig}
|
||||
* @private
|
||||
*/
|
||||
#defaultConfig: FanCardConfig = {
|
||||
type: "custom:mushroom-fan-card",
|
||||
icon: undefined,
|
||||
show_percentage_control: true,
|
||||
show_oscillate_control: true,
|
||||
icon_animation: true,
|
||||
};
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param {EntityRegistryEntry} entity The hass entity to create a card for.
|
||||
* @param {cards.FanCardOptions} [options={}] Options for the card.
|
||||
* @throws {Error} If the Helper module isn't initialized.
|
||||
*/
|
||||
constructor(entity: EntityRegistryEntry, options: cards.FanCardOptions = {}) {
|
||||
super(entity);
|
||||
|
||||
this.config = Object.assign(this.config, this.#defaultConfig, options);
|
||||
}
|
||||
}
|
||||
|
||||
export {FanCard};
|
||||
@@ -1,47 +0,0 @@
|
||||
import {AbstractCard} from "./AbstractCard";
|
||||
|
||||
/**
|
||||
* HA Area Card Class
|
||||
*
|
||||
* Used to create a card for an entity of the area domain using the built in type 'area'.
|
||||
*
|
||||
* @class
|
||||
* @extends AbstractCard
|
||||
*/
|
||||
class AreaCard extends AbstractCard {
|
||||
/**
|
||||
* Default options of the card.
|
||||
*
|
||||
* @type {HaAreaCardOptions}
|
||||
* @private
|
||||
*/
|
||||
#defaultOptions = {
|
||||
type: "area",
|
||||
area: undefined,
|
||||
navigation_path: undefined,
|
||||
};
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param {areaEntity} area The area entity to create a card for.
|
||||
* @param {HaAreaCardOptions} [options={}] Options for the card.
|
||||
* @throws {Error} If the Helper module isn't initialized.
|
||||
*/
|
||||
|
||||
constructor(area, options = {}) {
|
||||
super(area);
|
||||
this.#defaultOptions.area = area.area_id ?? area.name;
|
||||
this.#defaultOptions.navigation_path = area.area_id ?? area.name;
|
||||
|
||||
// Enforce the card type.
|
||||
options.type = this.#defaultOptions.type;
|
||||
|
||||
this.mergeOptions(
|
||||
this.#defaultOptions,
|
||||
options,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export {AreaCard};
|
||||
@@ -0,0 +1,49 @@
|
||||
import {AbstractCard} from "./AbstractCard";
|
||||
import {cards} from "../types/strategy/cards";
|
||||
import {AreaRegistryEntry} from "../types/homeassistant/data/area_registry";
|
||||
import {AreaCardConfig} from "../types/homeassistant/lovelace/cards/types";
|
||||
|
||||
// noinspection JSUnusedGlobalSymbols Class is dynamically imported.
|
||||
/**
|
||||
* HA Area Card Class
|
||||
*
|
||||
* Used to create a card for an entity of the area domain using the built-in type 'area'.
|
||||
*
|
||||
* @class
|
||||
* @extends AbstractCard
|
||||
*/
|
||||
class AreaCard extends AbstractCard {
|
||||
/**
|
||||
* Default configuration of the card.
|
||||
*
|
||||
* @type {AreaCardConfig}
|
||||
* @private
|
||||
*/
|
||||
#defaultConfig: AreaCardConfig = {
|
||||
type: "area",
|
||||
area: "",
|
||||
};
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param {AreaRegistryEntry} area The area entity to create a card for.
|
||||
* @param {cards.AreaCardOptions} [options={}] Options for the card.
|
||||
* @throws {Error} If the Helper module isn't initialized.
|
||||
*/
|
||||
|
||||
constructor(area: AreaRegistryEntry, options: cards.AreaCardOptions = {}) {
|
||||
super(area);
|
||||
|
||||
// Initialize the default configuration.
|
||||
this.#defaultConfig.area = area.area_id;
|
||||
this.#defaultConfig.navigation_path = this.#defaultConfig.area;
|
||||
|
||||
// Enforce the card type.
|
||||
delete options.type;
|
||||
|
||||
this.config = Object.assign(this.config, this.#defaultConfig, options);
|
||||
}
|
||||
}
|
||||
|
||||
export {AreaCard};
|
||||
@@ -1,53 +0,0 @@
|
||||
import {AbstractCard} from "./AbstractCard";
|
||||
|
||||
/**
|
||||
* Light Card Class
|
||||
*
|
||||
* Used to create a card for controlling an entity of the light domain.
|
||||
*
|
||||
* @class
|
||||
* @extends AbstractCard
|
||||
*/
|
||||
class LightCard extends AbstractCard {
|
||||
/**
|
||||
* Default options of the card.
|
||||
*
|
||||
* @type {lightCardOptions}
|
||||
* @private
|
||||
*/
|
||||
#defaultOptions = {
|
||||
type: "custom:mushroom-light-card",
|
||||
icon: undefined,
|
||||
show_brightness_control: true,
|
||||
show_color_control: true,
|
||||
use_light_color: true,
|
||||
show_color_temp_control: true,
|
||||
double_tap_action: {
|
||||
target: {
|
||||
entity_id: undefined,
|
||||
},
|
||||
action: "call-service",
|
||||
service: "light.turn_on",
|
||||
data: {
|
||||
rgb_color: [255, 255, 255],
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param {hassEntity} entity The hass entity to create a card for.
|
||||
* @param {lightCardOptions} [options={}] Options for the card.
|
||||
* @throws {Error} If the Helper module isn't initialized.
|
||||
*/
|
||||
constructor(entity, options = {}) {
|
||||
super(entity);
|
||||
this.mergeOptions(
|
||||
this.#defaultOptions,
|
||||
options,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export {LightCard};
|
||||
@@ -0,0 +1,67 @@
|
||||
import {AbstractCard} from "./AbstractCard";
|
||||
import {cards} from "../types/strategy/cards";
|
||||
import {EntityRegistryEntry} from "../types/homeassistant/data/entity_registry";
|
||||
import {LightCardConfig} from "../types/lovelace-mushroom/cards/light-card-config";
|
||||
import {generic} from "../types/strategy/generic";
|
||||
import isCallServiceActionConfig = generic.isCallServiceActionConfig;
|
||||
import isCallServiceActionTarget = generic.isCallServiceActionTarget;
|
||||
|
||||
|
||||
// noinspection JSUnusedGlobalSymbols Class is dynamically imported.
|
||||
/**
|
||||
* Light Card Class
|
||||
*
|
||||
* Used to create a card for controlling an entity of the light domain.
|
||||
*
|
||||
* @class
|
||||
* @extends AbstractCard
|
||||
*/
|
||||
class LightCard extends AbstractCard {
|
||||
/**
|
||||
* Default configuration of the card.
|
||||
*
|
||||
* @type {LightCardConfig}
|
||||
* @private
|
||||
*/
|
||||
#defaultConfig: LightCardConfig = {
|
||||
type: "custom:mushroom-light-card",
|
||||
icon: undefined,
|
||||
show_brightness_control: true,
|
||||
show_color_control: true,
|
||||
show_color_temp_control: true,
|
||||
use_light_color: true,
|
||||
double_tap_action: {
|
||||
action: "call-service",
|
||||
service: "light.turn_on",
|
||||
target: {
|
||||
entity_id: undefined,
|
||||
},
|
||||
data: {
|
||||
rgb_color: [255, 255, 255],
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param {EntityRegistryEntry} entity The hass entity to create a card for.
|
||||
* @param {cards.LightCardOptions} [options={}] Options for the card.
|
||||
* @throws {Error} If the Helper module isn't initialized.
|
||||
*/
|
||||
constructor(entity: EntityRegistryEntry, options: cards.LightCardOptions = {}) {
|
||||
super(entity);
|
||||
|
||||
// Set the target for double-tap action.
|
||||
if (
|
||||
isCallServiceActionConfig(this.#defaultConfig.double_tap_action)
|
||||
&& isCallServiceActionTarget(this.#defaultConfig.double_tap_action.target)
|
||||
) {
|
||||
this.#defaultConfig.double_tap_action.target.entity_id = entity.entity_id;
|
||||
}
|
||||
|
||||
this.config = Object.assign(this.config, this.#defaultConfig, options);
|
||||
}
|
||||
}
|
||||
|
||||
export {LightCard};
|
||||
@@ -1,39 +0,0 @@
|
||||
import {AbstractCard} from "./AbstractCard";
|
||||
|
||||
/**
|
||||
* Lock Card Class
|
||||
*
|
||||
* Used to create a card for controlling an entity of the lock domain.
|
||||
*
|
||||
* @class
|
||||
* @extends AbstractCard
|
||||
*/
|
||||
class LockCard extends AbstractCard {
|
||||
/**
|
||||
* Default options of the card.
|
||||
*
|
||||
* @type {lockCardOptions}
|
||||
* @private
|
||||
*/
|
||||
#defaultOptions = {
|
||||
type: "custom:mushroom-lock-card",
|
||||
icon: undefined,
|
||||
};
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param {hassEntity} entity The hass entity to create a card for.
|
||||
* @param {lockCardOptions} [options={}] Options for the card.
|
||||
* @throws {Error} If the Helper module isn't initialized.
|
||||
*/
|
||||
constructor(entity, options = {}) {
|
||||
super(entity);
|
||||
this.mergeOptions(
|
||||
this.#defaultOptions,
|
||||
options,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export {LockCard};
|
||||
@@ -0,0 +1,41 @@
|
||||
import {AbstractCard} from "./AbstractCard";
|
||||
import {cards} from "../types/strategy/cards";
|
||||
import {EntityRegistryEntry} from "../types/homeassistant/data/entity_registry";
|
||||
import {LockCardConfig} from "../types/lovelace-mushroom/cards/lock-card-config";
|
||||
|
||||
// noinspection JSUnusedGlobalSymbols Class is dynamically imported.
|
||||
/**
|
||||
* Lock Card Class
|
||||
*
|
||||
* Used to create a card for controlling an entity of the lock domain.
|
||||
*
|
||||
* @class
|
||||
* @extends AbstractCard
|
||||
*/
|
||||
class LockCard extends AbstractCard {
|
||||
/**
|
||||
* Default configuration of the card.
|
||||
*
|
||||
* @type {LockCardConfig}
|
||||
* @private
|
||||
*/
|
||||
#defaultConfig: LockCardConfig = {
|
||||
type: "custom:mushroom-lock-card",
|
||||
icon: undefined,
|
||||
};
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param {EntityRegistryEntry} entity The hass entity to create a card for.
|
||||
* @param {cards.LockCardOptions} [options={}] Options for the card.
|
||||
* @throws {Error} If the Helper module isn't initialized.
|
||||
*/
|
||||
constructor(entity: EntityRegistryEntry, options: cards.LockCardOptions = {}) {
|
||||
super(entity);
|
||||
|
||||
this.config = Object.assign(this.config, this.#defaultConfig, options);
|
||||
}
|
||||
}
|
||||
|
||||
export {LockCard};
|
||||
@@ -1,50 +0,0 @@
|
||||
import {AbstractCard} from "./AbstractCard";
|
||||
|
||||
/**
|
||||
* Mediaplayer Card Class
|
||||
*
|
||||
* Used to create a card for controlling an entity of the media_player domain.
|
||||
*
|
||||
* @class
|
||||
* @extends AbstractCard
|
||||
*/
|
||||
class MediaPlayerCard extends AbstractCard {
|
||||
/**
|
||||
* Default options of the card.
|
||||
*
|
||||
* @type {mediaPlayerCardOptions}
|
||||
* @private
|
||||
*/
|
||||
#defaultOptions = {
|
||||
type: "custom:mushroom-media-player-card",
|
||||
icon: undefined,
|
||||
use_media_info: true,
|
||||
media_controls: [
|
||||
"on_off",
|
||||
"play_pause_stop",
|
||||
],
|
||||
show_volume_level: true,
|
||||
volume_controls: [
|
||||
"volume_mute",
|
||||
"volume_set",
|
||||
"volume_buttons",
|
||||
],
|
||||
};
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param {hassEntity} entity The hass entity to create a card for.
|
||||
* @param {mediaPlayerCardOptions} [options={}] Options for the card.
|
||||
* @throws {Error} If the Helper module isn't initialized.
|
||||
*/
|
||||
constructor(entity, options = {}) {
|
||||
super(entity);
|
||||
this.mergeOptions(
|
||||
this.#defaultOptions,
|
||||
options,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export {MediaPlayerCard};
|
||||
@@ -0,0 +1,51 @@
|
||||
import {AbstractCard} from "./AbstractCard";
|
||||
import {cards} from "../types/strategy/cards";
|
||||
import {EntityRegistryEntry} from "../types/homeassistant/data/entity_registry";
|
||||
import {MediaPlayerCardConfig} from "../types/lovelace-mushroom/cards/media-player-card-config";
|
||||
|
||||
// noinspection JSUnusedGlobalSymbols Class is dynamically imported.
|
||||
/**
|
||||
* Mediaplayer Card Class
|
||||
*
|
||||
* Used to create a card for controlling an entity of the media_player domain.
|
||||
*
|
||||
* @class
|
||||
* @extends AbstractCard
|
||||
*/
|
||||
class MediaPlayerCard extends AbstractCard {
|
||||
/**
|
||||
* Default configuration of the card.
|
||||
*
|
||||
* @type {MediaPlayerCardConfig}
|
||||
* @private
|
||||
*/
|
||||
#defaultConfig: MediaPlayerCardConfig = {
|
||||
type: "custom:mushroom-media-player-card",
|
||||
use_media_info: true,
|
||||
media_controls: [
|
||||
"on_off",
|
||||
"play_pause_stop",
|
||||
],
|
||||
show_volume_level: true,
|
||||
volume_controls: [
|
||||
"volume_mute",
|
||||
"volume_set",
|
||||
"volume_buttons",
|
||||
],
|
||||
};
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param {EntityRegistryEntry} entity The hass entity to create a card for.
|
||||
* @param {cards.MediaPlayerCardOptions} [options={}] Options for the card.
|
||||
* @throws {Error} If the Helper module isn't initialized.
|
||||
*/
|
||||
constructor(entity: EntityRegistryEntry, options: cards.MediaPlayerCardOptions = {}) {
|
||||
super(entity);
|
||||
|
||||
this.config = Object.assign(this.config, this.#defaultConfig, options);
|
||||
}
|
||||
}
|
||||
|
||||
export {MediaPlayerCard};
|
||||
@@ -1,39 +0,0 @@
|
||||
import {AbstractCard} from "./AbstractCard";
|
||||
|
||||
/**
|
||||
* Miscellaneous Card Class
|
||||
*
|
||||
* Used to create a card an entity of any domain.
|
||||
*
|
||||
* @class
|
||||
* @extends AbstractCard
|
||||
*/
|
||||
class MiscellaneousCard extends AbstractCard {
|
||||
/**
|
||||
* Default options of the card.
|
||||
*
|
||||
* @type {miscellaneousCardOptions}
|
||||
* @private
|
||||
*/
|
||||
#defaultOptions = {
|
||||
type: "custom:mushroom-entity-card",
|
||||
icon_color: "blue-grey",
|
||||
};
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param {hassEntity} entity The hass entity to create a card for.
|
||||
* @param {miscellaneousCardOptions} [options={}] Options for the card.
|
||||
* @throws {Error} If the Helper module isn't initialized.
|
||||
*/
|
||||
constructor(entity, options = {}) {
|
||||
super(entity);
|
||||
this.mergeOptions(
|
||||
this.#defaultOptions,
|
||||
options,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export {MiscellaneousCard};
|
||||
@@ -0,0 +1,40 @@
|
||||
import {AbstractCard} from "./AbstractCard";
|
||||
import {cards} from "../types/strategy/cards";
|
||||
import {EntityRegistryEntry} from "../types/homeassistant/data/entity_registry";
|
||||
import {EntityCardConfig} from "../types/lovelace-mushroom/cards/entity-card-config";
|
||||
|
||||
/**
|
||||
* Miscellaneous Card Class
|
||||
*
|
||||
* Used to create a card an entity of any domain.
|
||||
*
|
||||
* @class
|
||||
* @extends AbstractCard
|
||||
*/
|
||||
class MiscellaneousCard extends AbstractCard {
|
||||
/**
|
||||
* Default configuration of the card.
|
||||
*
|
||||
* @type {EntityCardConfig}
|
||||
* @private
|
||||
*/
|
||||
#defaultConfig: EntityCardConfig = {
|
||||
type: "custom:mushroom-entity-card",
|
||||
icon_color: "blue-grey",
|
||||
};
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
this.config = Object.assign(this.config, this.#defaultConfig, options);
|
||||
}
|
||||
}
|
||||
|
||||
export {MiscellaneousCard};
|
||||
@@ -1,37 +0,0 @@
|
||||
import {AbstractCard} from "./AbstractCard";
|
||||
|
||||
/**
|
||||
* Number Card Class
|
||||
*
|
||||
* Used to create a card for controlling an entity of the number domain.
|
||||
*
|
||||
* @class
|
||||
* @extends AbstractCard
|
||||
*/
|
||||
class NumberCard extends AbstractCard {
|
||||
/**
|
||||
* Default options of the card.
|
||||
*
|
||||
* @type {numberCardOptions}
|
||||
* @private
|
||||
*/
|
||||
#defaultOptions = {
|
||||
type: "custom:mushroom-number-card",
|
||||
icon: undefined,
|
||||
};
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param {hassEntity} entity The hass entity to create a card for.
|
||||
* @param {numberCardOptions} [options={}] Options for the card.
|
||||
* @throws {Error} If the Helper module isn't initialized.
|
||||
*/
|
||||
constructor(entity, options = {}) {
|
||||
super(entity);
|
||||
|
||||
this.mergeOptions(this.#defaultOptions, options);
|
||||
}
|
||||
}
|
||||
|
||||
export {NumberCard};
|
||||
@@ -0,0 +1,41 @@
|
||||
import {AbstractCard} from "./AbstractCard";
|
||||
import {cards} from "../types/strategy/cards";
|
||||
import {EntityRegistryEntry} from "../types/homeassistant/data/entity_registry";
|
||||
import {NumberCardConfig} from "../types/lovelace-mushroom/cards/number-card-config";
|
||||
|
||||
// noinspection JSUnusedGlobalSymbols Class is dynamically imported
|
||||
/**
|
||||
* Number Card Class
|
||||
*
|
||||
* Used to create a card for controlling an entity of the number domain.
|
||||
*
|
||||
* @class
|
||||
* @extends AbstractCard
|
||||
*/
|
||||
class NumberCard extends AbstractCard {
|
||||
/**
|
||||
* Default configuration of the card.
|
||||
*
|
||||
* @type {NumberCardConfig}
|
||||
* @private
|
||||
*/
|
||||
#defaultConfig: NumberCardConfig = {
|
||||
type: "custom:mushroom-number-card",
|
||||
icon: undefined,
|
||||
};
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param {EntityRegistryEntry} entity The hass entity to create a card for.
|
||||
* @param {cards.NumberCardOptions} [options={}] Options for the card.
|
||||
* @throws {Error} If the Helper module isn't initialized.
|
||||
*/
|
||||
constructor(entity: EntityRegistryEntry, options: cards.NumberCardOptions = {}) {
|
||||
super(entity);
|
||||
|
||||
this.config = Object.assign(this.config, this.#defaultConfig, options);
|
||||
}
|
||||
}
|
||||
|
||||
export {NumberCard};
|
||||
@@ -1,42 +0,0 @@
|
||||
import {AbstractCard} from "./AbstractCard";
|
||||
|
||||
/**
|
||||
* Person Card Class
|
||||
*
|
||||
* Used to create a card for an entity of the person domain.
|
||||
*
|
||||
* @class
|
||||
* @extends AbstractCard
|
||||
*/
|
||||
class PersonCard extends AbstractCard {
|
||||
/**
|
||||
* Default options of the card.
|
||||
*
|
||||
* @type {personCardOptions}
|
||||
* @private
|
||||
*/
|
||||
#defaultOptions = {
|
||||
type: "custom:mushroom-person-card",
|
||||
layout: "vertical",
|
||||
primary_info: "none",
|
||||
secondary_info: "none",
|
||||
icon_type: "entity-picture",
|
||||
};
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param {hassEntity} entity The hass entity to create a card for.
|
||||
* @param {personCardOptions} [options={}] Options for the card.
|
||||
* @throws {Error} If the Helper module isn't initialized.
|
||||
*/
|
||||
constructor(entity, options = {}) {
|
||||
super(entity);
|
||||
this.mergeOptions(
|
||||
this.#defaultOptions,
|
||||
options,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export {PersonCard};
|
||||
@@ -0,0 +1,43 @@
|
||||
import {AbstractCard} from "./AbstractCard";
|
||||
import {cards} from "../types/strategy/cards";
|
||||
import {EntityRegistryEntry} from "../types/homeassistant/data/entity_registry";
|
||||
import {PersonCardConfig} from "../types/lovelace-mushroom/cards/person-card-config";
|
||||
|
||||
/**
|
||||
* Person Card Class
|
||||
*
|
||||
* Used to create a card for an entity of the Person domain.
|
||||
*
|
||||
* @class
|
||||
* @extends AbstractCard
|
||||
*/
|
||||
class PersonCard extends AbstractCard {
|
||||
/**
|
||||
* Default configuration of the card.
|
||||
*
|
||||
* @type {PersonCardConfig}
|
||||
* @private
|
||||
*/
|
||||
#defaultConfig: PersonCardConfig = {
|
||||
type: "custom:mushroom-person-card",
|
||||
layout: "vertical",
|
||||
primary_info: "none",
|
||||
secondary_info: "none",
|
||||
icon_type: "entity-picture",
|
||||
};
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param {EntityRegistryEntry} entity The hass entity to create a card for.
|
||||
* @param {cards.PersonCardOptions} [options={}] Options for the card.
|
||||
* @throws {Error} If the Helper module isn't initialized.
|
||||
*/
|
||||
constructor(entity: EntityRegistryEntry, options: cards.PersonCardOptions = {}) {
|
||||
super(entity);
|
||||
|
||||
this.config = Object.assign(this.config, this.#defaultConfig, options);
|
||||
}
|
||||
}
|
||||
|
||||
export {PersonCard};
|
||||
@@ -1,42 +0,0 @@
|
||||
import {AbstractCard} from "./AbstractCard";
|
||||
|
||||
/**
|
||||
* Sensor Card Class
|
||||
*
|
||||
* Used to create a card for controlling an entity of the sensor domain.
|
||||
*
|
||||
* @class
|
||||
* @extends AbstractCard
|
||||
*/
|
||||
class SensorCard extends AbstractCard {
|
||||
/**
|
||||
* Default options of the card.
|
||||
*
|
||||
* @type {sensorCardOptions}
|
||||
* @private
|
||||
*/
|
||||
#defaultOptions = {
|
||||
type: "custom:mushroom-entity-card",
|
||||
icon: "mdi:information",
|
||||
animate: true,
|
||||
line_color: "green",
|
||||
};
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param {hassEntity} entity The hass entity to create a card for.
|
||||
* @param {sensorCardOptions} [options={}] Options for the card.
|
||||
* @throws {Error} If the Helper module isn't initialized.
|
||||
*/
|
||||
constructor(entity, options = {}) {
|
||||
super(entity);
|
||||
|
||||
this.mergeOptions(
|
||||
this.#defaultOptions,
|
||||
options,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export {SensorCard};
|
||||
@@ -0,0 +1,42 @@
|
||||
import {AbstractCard} from "./AbstractCard";
|
||||
import {cards} from "../types/strategy/cards";
|
||||
import {EntityRegistryEntry} from "../types/homeassistant/data/entity_registry";
|
||||
import {EntityCardConfig} from "../types/lovelace-mushroom/cards/entity-card-config";
|
||||
|
||||
/**
|
||||
* Sensor Card Class
|
||||
*
|
||||
* Used to create a card for controlling an entity of the sensor domain.
|
||||
*
|
||||
* @class
|
||||
* @extends AbstractCard
|
||||
*/
|
||||
class SensorCard extends AbstractCard {
|
||||
/**
|
||||
* Default configuration of the card.
|
||||
*
|
||||
* @type {EntityCardConfig}
|
||||
* @private
|
||||
*/
|
||||
#defaultConfig: EntityCardConfig = {
|
||||
type: "custom:mushroom-entity-card",
|
||||
icon: "mdi:information",
|
||||
animate: true,
|
||||
line_color: "green",
|
||||
};
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
this.config = Object.assign(this.config, this.#defaultConfig, options);
|
||||
}
|
||||
}
|
||||
|
||||
export {SensorCard};
|
||||
@@ -1,42 +0,0 @@
|
||||
import {AbstractCard} from "./AbstractCard";
|
||||
|
||||
/**
|
||||
* Switch Card Class
|
||||
*
|
||||
* Used to create a card for controlling an entity of the switch domain.
|
||||
*
|
||||
* @class
|
||||
* @extends AbstractCard
|
||||
*/
|
||||
class SwitchCard extends AbstractCard {
|
||||
/**
|
||||
* Default options of the card.
|
||||
*
|
||||
* @type {switchCardOptions}
|
||||
* @private
|
||||
*/
|
||||
#defaultOptions = {
|
||||
type: "custom:mushroom-entity-card",
|
||||
icon: undefined,
|
||||
tap_action: {
|
||||
action: "toggle",
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param {hassEntity} entity The hass entity to create a card for.
|
||||
* @param {switchCardOptions} [options={}] Options for the card.
|
||||
* @throws {Error} If the Helper module isn't initialized.
|
||||
*/
|
||||
constructor(entity, options = {}) {
|
||||
super(entity);
|
||||
this.mergeOptions(
|
||||
this.#defaultOptions,
|
||||
options,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export {SwitchCard};
|
||||
@@ -0,0 +1,44 @@
|
||||
import {AbstractCard} from "./AbstractCard";
|
||||
import {cards} from "../types/strategy/cards";
|
||||
import {EntityRegistryEntry} from "../types/homeassistant/data/entity_registry";
|
||||
import {EntityCardConfig} from "../types/lovelace-mushroom/cards/entity-card-config";
|
||||
|
||||
// noinspection JSUnusedGlobalSymbols Class is dynamically imported.
|
||||
/**
|
||||
* Switch Card Class
|
||||
*
|
||||
* Used to create a card for controlling an entity of the switch domain.
|
||||
*
|
||||
* @class
|
||||
* @extends AbstractCard
|
||||
*/
|
||||
class SwitchCard extends AbstractCard {
|
||||
/**
|
||||
* Default configuration of the card.
|
||||
*
|
||||
* @type {EntityCardConfig}
|
||||
* @private
|
||||
*/
|
||||
#defaultConfig: EntityCardConfig = {
|
||||
type: "custom:mushroom-entity-card",
|
||||
icon: undefined,
|
||||
tap_action: {
|
||||
action: "toggle",
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
this.config = Object.assign(this.config, this.#defaultConfig, options);
|
||||
}
|
||||
}
|
||||
|
||||
export {SwitchCard};
|
||||
@@ -1,101 +0,0 @@
|
||||
/**
|
||||
* Title Card class.
|
||||
*
|
||||
* Used for creating a Title Card.
|
||||
*
|
||||
* @class
|
||||
*/
|
||||
class TitleCard {
|
||||
/**
|
||||
* @type {string[]} An array of area ids.
|
||||
* @private
|
||||
*/
|
||||
#areaIds;
|
||||
|
||||
/**
|
||||
* @type {titleCardOptions}
|
||||
* @private
|
||||
*/
|
||||
#options = {
|
||||
title: undefined,
|
||||
subtitle: undefined,
|
||||
showControls: true,
|
||||
iconOn: "mdi:power-on",
|
||||
iconOff: "mdi:power-off",
|
||||
onService: "none",
|
||||
offService: "none",
|
||||
};
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param {areaEntity[]} areas An array of area entities.
|
||||
* @param {titleCardOptions} options Title Card options.
|
||||
*/
|
||||
constructor(areas, options = {}) {
|
||||
this.#areaIds = areas.map(area => area.area_id).filter(area_id => area_id);
|
||||
this.#options = {
|
||||
...this.#options,
|
||||
...options,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a Title card.
|
||||
*
|
||||
* @return {Object} A Title card.
|
||||
*/
|
||||
createCard() {
|
||||
/** @type {Object[]} */
|
||||
const cards = [
|
||||
{
|
||||
type: "custom:mushroom-title-card",
|
||||
title: this.#options.title,
|
||||
subtitle: this.#options.subtitle,
|
||||
},
|
||||
];
|
||||
|
||||
if (this.#options.showControls) {
|
||||
cards.push({
|
||||
type: "horizontal-stack",
|
||||
cards: [
|
||||
{
|
||||
type: "custom:mushroom-template-card",
|
||||
icon: this.#options.iconOff,
|
||||
layout: "vertical",
|
||||
icon_color: "red",
|
||||
tap_action: {
|
||||
action: "call-service",
|
||||
service: this.#options.offService,
|
||||
target: {
|
||||
area_id: this.#areaIds,
|
||||
},
|
||||
data: {},
|
||||
},
|
||||
},
|
||||
{
|
||||
type: "custom:mushroom-template-card",
|
||||
icon: this.#options.iconOn,
|
||||
layout: "vertical",
|
||||
icon_color: "amber",
|
||||
tap_action: {
|
||||
action: "call-service",
|
||||
service: this.#options.onService,
|
||||
target: {
|
||||
area_id: this.#areaIds,
|
||||
},
|
||||
data: {},
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
type: "horizontal-stack",
|
||||
cards: cards,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export {TitleCard};
|
||||
@@ -0,0 +1,46 @@
|
||||
import {AbstractCard} from "./AbstractCard";
|
||||
import {cards} from "../types/strategy/cards";
|
||||
import {EntityRegistryEntry} from "../types/homeassistant/data/entity_registry";
|
||||
import {VACUUM_COMMANDS, VacuumCardConfig} from "../types/lovelace-mushroom/cards/vacuum-card-config";
|
||||
|
||||
// noinspection JSUnusedGlobalSymbols Class is dynamically imported.
|
||||
/**
|
||||
* Vacuum Card Class
|
||||
*
|
||||
* Used to create a card for controlling an entity of the vacuum domain.
|
||||
*
|
||||
* @class
|
||||
* @extends AbstractCard
|
||||
*/
|
||||
class VacuumCard extends AbstractCard {
|
||||
/**
|
||||
* Default configuration of the card.
|
||||
*
|
||||
* @type {VacuumCardConfig}
|
||||
* @private
|
||||
*/
|
||||
#defaultConfig: VacuumCardConfig = {
|
||||
type: "custom:mushroom-vacuum-card",
|
||||
icon: undefined,
|
||||
icon_animation: true,
|
||||
commands: [...VACUUM_COMMANDS],
|
||||
tap_action: {
|
||||
action: "more-info",
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param {EntityRegistryEntry} entity The hass entity to create a card for.
|
||||
* @param {cards.VacuumCardOptions} [options={}] Options for the card.
|
||||
* @throws {Error} If the Helper module isn't initialized.
|
||||
*/
|
||||
constructor(entity: EntityRegistryEntry, options: cards.VacuumCardOptions = {}) {
|
||||
super(entity);
|
||||
|
||||
this.config = Object.assign(this.config, this.#defaultConfig, options);
|
||||
}
|
||||
}
|
||||
|
||||
export {VacuumCard};
|
||||
@@ -1,154 +0,0 @@
|
||||
/**
|
||||
* @namespace typedefs.cards
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} abstractOptions
|
||||
* @property {string} [type] The type of the card.
|
||||
* @property {string} [icon] Icon of the card.
|
||||
* @property {Object} [double_tap_action] Home assistant action to perform on double_tap.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} titleCardOptions Title Card options.
|
||||
* @property {string} [title] Title to render. May contain templates.
|
||||
* @property {string} [subtitle] Subtitle to render. May contain templates.
|
||||
* @property {boolean} [showControls=true] False to hide controls.
|
||||
* @property {string} [iconOn] Icon to show for switching entities from off state.
|
||||
* @property {string} [iconOff] Icon to show for switching entities to off state.
|
||||
* @property {string} [onService=none] Service to call for switching entities from off state.
|
||||
* @property {string} [offService=none] Service to call for switching entities to off state.
|
||||
* @memberOf typedefs.cards
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {abstractOptions & Object} lightCardOptions Light Card options.
|
||||
* @property {boolean} [show_brightness_control=true] Show a slider to control brightness
|
||||
* @property {boolean} [show_color_control=true] Show a slider to control RGB color
|
||||
* @property {boolean} [use_light_color=true] Colorize the icon and slider according light temperature or color
|
||||
* @property {{double_tap_action: lightDoubleTapAction}} [action] Home assistant action to perform on double_tap
|
||||
* @memberOf typedefs.cards
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} lightDoubleTapAction Home assistant action to perform on double_tap.
|
||||
* @property {{entity_id: string}} target The target entity id.
|
||||
* @property {"call-service"} action Calls a hass service.
|
||||
* @property {"light.turn_on"} service The hass service to call
|
||||
* @property {{rgb_color: [255, 255, 255]}} data The data payload for the service.
|
||||
* @memberOf typedefs.cards
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {abstractOptions & Object} coverCardOptions Cover Card options.
|
||||
* @property {boolean} [show_buttons_control=true] Show buttons to open, close and stop cover.
|
||||
* @property {boolean} [show_position_control=true] Show a slider to control position of the cover.
|
||||
* @property {boolean} [show_tilt_position_control=true] Show a slider to control tilt position of the cover.
|
||||
* @memberOf typedefs.cards
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {abstractOptions & Object} fanCardOptions Fan Card options.
|
||||
* @property {boolean} [show_percentage_control=true] Show a slider to control speed.
|
||||
* @property {boolean} [show_oscillate_control=true] Show a button to control oscillation.
|
||||
* @property {boolean} [icon_animation=true] Animate the icon when fan is on.
|
||||
* @memberOf typedefs.cards
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {abstractOptions & Object} lockCardOptions Lock Card options.
|
||||
* @memberOf typedefs.cards
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {abstractOptions & Object} numberCardOptions Number Card options.
|
||||
* @memberOf typedefs.cards
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {abstractOptions & Object} switchCardOptions Switch Card options.
|
||||
* @property {{tap_action: switchTapAction}} [action] Home assistant action to perform on tap.
|
||||
* @memberOf typedefs.cards
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} switchTapAction Home assistant action to perform on tap.
|
||||
* @property {"toggle"} action Toggles a hass entity.
|
||||
* @memberOf typedefs.cards
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {abstractOptions & Object} climateCardOptions Climate Card options.
|
||||
* @property {["off", "cool", "heat", "fan_only"]} [hvac_modes] Show buttons to control target temperature.
|
||||
* @property {boolean} [show_temperature_control=true] Show buttons to control target temperature.
|
||||
* @memberOf typedefs.cards
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {abstractOptions} cameraCardOptions Camera Card options.
|
||||
* @memberOf typedefs.cards
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {abstractOptions & Object} personCardOptions Person Card options.
|
||||
* @property {string} [layout] Layout of the card. Vertical, horizontal, and default layouts are supported.
|
||||
* @property {("name" | "state" | "last-changed" | "last-updated" | "none")} [primary_info=name] Info to show as
|
||||
* primary info.
|
||||
* @property {("name" | "state" | "last-changed" | "last-updated" | "none")} [secondary_info=sate] Info to show as
|
||||
* secondary info.
|
||||
* @property {("icon" | "entity-picture" | "none")} [icon_type]=icon Type of icon to display.
|
||||
* @memberOf typedefs.cards
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {abstractOptions & Object} areaCardOptions Area Card options.
|
||||
* @property {string} [name] The name of the area
|
||||
* @property {string} [icon] Icon to render. May contain templates.
|
||||
* @property {string} [icon_color] Icon color to render. May contain templates.
|
||||
* @property {string} [primary] Primary info to render. May contain templates.
|
||||
* @property {areaTapAction} [tap_action] Home assistant action to perform on tap.
|
||||
* @memberOf typedefs.cards
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} areaTapAction Home assistant action to perform on tap.
|
||||
* @property {"navigate"} action Toggles a hass entity.
|
||||
* @property {string} navigation_path The id of the area to navigate to.
|
||||
* @memberOf typedefs.cards
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {abstractOptions & Object} HaAreaCardOptions HA Area Card options.
|
||||
* @property {string} area The id of the area.
|
||||
* @property {string} navigation_path The id of the area to navigate to.
|
||||
* @memberOf typedefs.cards
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {abstractOptions & Object} mediaPlayerCardOptions Media Player Card options.
|
||||
* @property {boolean} [use_media_info=true] Use media info instead of name, state, and icon when a media is playing
|
||||
* @property {string[]} [media_controls="on_off", "play_pause_stop"] List of controls to display
|
||||
* (on_off, shuffle, previous, play_pause_stop, next,
|
||||
* repeat)
|
||||
* @property {boolean} [show_volume_level=true] Show volume level next to media state when media is playing
|
||||
* @property {string[]} [volume_controls="volume_mute", "volume_set", "volume_buttons"] List of controls to display
|
||||
* (volume_mute, volume_set,
|
||||
* volume_buttons)
|
||||
* @memberOf typedefs.cards
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {abstractOptions & Object} sensorCardOptions Sensor Card options.
|
||||
* @property {string} [icon_color=green] Custom color for icon when entity is state is active.
|
||||
* @property {boolean} [animate=true] Add a reveal animation to the graph.
|
||||
* @property {string} [line_color=green] Set a custom color for the graph line.
|
||||
* Provide a list of colors for multiple graph entries.
|
||||
* @memberOf typedefs.cards
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {abstractOptions & Object} miscellaneousCardOptions Miscellaneous Card options.
|
||||
* @property {string} [icon_color=blue-grey] Custom color for icon when entity is state is active.
|
||||
* @memberOf typedefs.cards
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
import {HassServiceTarget} from "home-assistant-js-websocket";
|
||||
import {LovelaceChipConfig} from "../types/lovelace-mushroom/utils/lovelace/chip/types";
|
||||
import {Helper} from "../Helper";
|
||||
import {generic} from "../types/strategy/generic";
|
||||
import isCallServiceActionConfig = generic.isCallServiceActionConfig;
|
||||
|
||||
/**
|
||||
* Abstract Chip class.
|
||||
*
|
||||
* To create a new chip, extend this one.
|
||||
*
|
||||
* @class
|
||||
* @abstract
|
||||
*/
|
||||
abstract class AbstractChip {
|
||||
/**
|
||||
* Configuration of the chip.
|
||||
*
|
||||
* @type {LovelaceChipConfig}
|
||||
*/
|
||||
config: LovelaceChipConfig = {
|
||||
type: "template"
|
||||
};
|
||||
|
||||
/**
|
||||
* Class Constructor.
|
||||
*/
|
||||
protected constructor() {
|
||||
if (!Helper.isInitialized()) {
|
||||
throw new Error("The Helper module must be initialized before using this one.");
|
||||
}
|
||||
}
|
||||
|
||||
// noinspection JSUnusedGlobalSymbols Method is called on dymanically imported classes.
|
||||
/**
|
||||
* Get the chip.
|
||||
*
|
||||
* @returns {LovelaceChipConfig} A chip.
|
||||
*/
|
||||
getChip(): LovelaceChipConfig {
|
||||
return this.config;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the target to switch.
|
||||
*
|
||||
* @param {HassServiceTarget} target Target to switch.
|
||||
*/
|
||||
setTapActionTarget(target: HassServiceTarget) {
|
||||
if ("tap_action" in this.config && isCallServiceActionConfig(this.config.tap_action)) {
|
||||
this.config.tap_action.target = target;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (Helper.debug) {
|
||||
console.warn(
|
||||
this.constructor.name
|
||||
+ " - Target not set: Invalid target or tap action.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export {AbstractChip};
|
||||
@@ -1,39 +0,0 @@
|
||||
import {Helper} from "../Helper";
|
||||
|
||||
class ClimateChip {
|
||||
#areaIds;
|
||||
#options = {
|
||||
// No default options.
|
||||
};
|
||||
|
||||
constructor(areaIds, options = {}) {
|
||||
if (!Helper.isInitialized()) {
|
||||
throw new Error("The Helper module must be initialized before using this one.");
|
||||
}
|
||||
|
||||
this.#areaIds = areaIds.filter(areaId => areaId);
|
||||
this.#options = {
|
||||
...this.#options,
|
||||
...options,
|
||||
};
|
||||
}
|
||||
|
||||
getChip() {
|
||||
return {
|
||||
type: "template",
|
||||
icon: "mdi:thermostat",
|
||||
icon_color: "orange",
|
||||
content: Helper.getCountTemplate("climate", "ne", "off"),
|
||||
tap_action: {
|
||||
action: "navigate",
|
||||
navigation_path: "climates",
|
||||
},
|
||||
hold_action: {
|
||||
action: "navigate",
|
||||
navigation_path: "climates",
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export {ClimateChip};
|
||||
@@ -0,0 +1,47 @@
|
||||
import {Helper} from "../Helper";
|
||||
import {AbstractChip} from "./AbstractChip";
|
||||
import {chips} from "../types/strategy/chips";
|
||||
import {TemplateChipConfig} from "../types/lovelace-mushroom/utils/lovelace/chip/types";
|
||||
|
||||
// noinspection JSUnusedGlobalSymbols Class is dynamically imported.
|
||||
/**
|
||||
* Climate Chip class.
|
||||
*
|
||||
* Used to create a chip to indicate how many climates are operating.
|
||||
*/
|
||||
class ClimateChip extends AbstractChip {
|
||||
/**
|
||||
* Default configuration of the chip.
|
||||
*
|
||||
* @type {TemplateChipConfig}
|
||||
*
|
||||
* @readonly
|
||||
* @private
|
||||
*/
|
||||
readonly #defaultConfig: TemplateChipConfig = {
|
||||
type: "template",
|
||||
icon: "mdi:thermostat",
|
||||
icon_color: "orange",
|
||||
content: Helper.getCountTemplate("climate", "ne", "off"),
|
||||
tap_action: {
|
||||
action: "none",
|
||||
},
|
||||
hold_action: {
|
||||
action: "navigate",
|
||||
navigation_path: "climates",
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Class Constructor.
|
||||
*
|
||||
* @param {chips.TemplateChipOptions} options The chip options.
|
||||
*/
|
||||
constructor(options: chips.TemplateChipOptions = {}) {
|
||||
super();
|
||||
|
||||
this.config = Object.assign(this.config, this.#defaultConfig, options);
|
||||
}
|
||||
}
|
||||
|
||||
export {ClimateChip};
|
||||
@@ -1,35 +0,0 @@
|
||||
import {Helper} from "../Helper";
|
||||
|
||||
class CoverChip {
|
||||
#areaIds;
|
||||
#options = {
|
||||
// No default options.
|
||||
};
|
||||
|
||||
constructor(areaIds, options = {}) {
|
||||
if (!Helper.isInitialized()) {
|
||||
throw new Error("The Helper module must be initialized before using this one.");
|
||||
}
|
||||
|
||||
this.#areaIds = areaIds.filter(areaId => areaId);
|
||||
this.#options = {
|
||||
...this.#options,
|
||||
...options,
|
||||
};
|
||||
}
|
||||
|
||||
getChip() {
|
||||
return {
|
||||
type: "template",
|
||||
icon: "mdi:window-open",
|
||||
icon_color: "cyan",
|
||||
content: Helper.getCountTemplate("cover", "eq", "open"),
|
||||
tap_action: {
|
||||
action: "navigate",
|
||||
navigation_path: "covers",
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export {CoverChip};
|
||||
@@ -0,0 +1,47 @@
|
||||
import {Helper} from "../Helper";
|
||||
import {chips} from "../types/strategy/chips";
|
||||
import {AbstractChip} from "./AbstractChip";
|
||||
import {TemplateChipConfig} from "../types/lovelace-mushroom/utils/lovelace/chip/types";
|
||||
|
||||
// noinspection JSUnusedGlobalSymbols Class is dynamically imported.
|
||||
/**
|
||||
* Cover Chip class.
|
||||
*
|
||||
* Used to create a chip to indicate how many covers aren't closed.
|
||||
*/
|
||||
class CoverChip extends AbstractChip {
|
||||
/**
|
||||
* Default configuration of the chip.
|
||||
*
|
||||
* @type {TemplateChipConfig}
|
||||
*
|
||||
* @readonly
|
||||
* @private
|
||||
*/
|
||||
readonly #defaultConfig: TemplateChipConfig = {
|
||||
type: "template",
|
||||
icon: "mdi:window-open",
|
||||
icon_color: "cyan",
|
||||
content: Helper.getCountTemplate("cover", "eq", "open"),
|
||||
tap_action: {
|
||||
action: "none",
|
||||
},
|
||||
hold_action: {
|
||||
action: "navigate",
|
||||
navigation_path: "covers",
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Class Constructor.
|
||||
*
|
||||
* @param {chips.TemplateChipOptions} options The chip options.
|
||||
*/
|
||||
constructor(options: chips.TemplateChipOptions = {}) {
|
||||
super();
|
||||
|
||||
this.config = Object.assign(this.config, this.#defaultConfig, options);
|
||||
}
|
||||
}
|
||||
|
||||
export {CoverChip};
|
||||
@@ -1,43 +0,0 @@
|
||||
import {Helper} from "../Helper";
|
||||
|
||||
class FanChip {
|
||||
#areaIds;
|
||||
#options = {
|
||||
// No default options.
|
||||
};
|
||||
|
||||
constructor(areaIds, options = {}) {
|
||||
if (!Helper.isInitialized()) {
|
||||
throw new Error("The Helper module must be initialized before using this one.");
|
||||
}
|
||||
|
||||
this.#areaIds = areaIds.filter(areaId => areaId);
|
||||
this.#options = {
|
||||
...this.#options,
|
||||
...options,
|
||||
};
|
||||
}
|
||||
|
||||
getChip() {
|
||||
return {
|
||||
type: "template",
|
||||
icon: "mdi:fan",
|
||||
icon_color: "green",
|
||||
content: Helper.getCountTemplate("fan", "eq", "on"),
|
||||
tap_action: {
|
||||
action: "call-service",
|
||||
service: "fan.turn_off",
|
||||
target: {
|
||||
area_id: this.#areaIds,
|
||||
},
|
||||
data: {},
|
||||
},
|
||||
hold_action: {
|
||||
action: "navigate",
|
||||
navigation_path: "fans",
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export {FanChip};
|
||||
@@ -0,0 +1,48 @@
|
||||
import {Helper} from "../Helper";
|
||||
import {chips} from "../types/strategy/chips";
|
||||
import {AbstractChip} from "./AbstractChip";
|
||||
import {TemplateChipConfig} from "../types/lovelace-mushroom/utils/lovelace/chip/types";
|
||||
|
||||
// noinspection JSUnusedGlobalSymbols Class is dynamically imported.
|
||||
/**
|
||||
* Fan Chip class.
|
||||
*
|
||||
* Used to create a chip to indicate how many fans are on and to turn all off.
|
||||
*/
|
||||
class FanChip extends AbstractChip {
|
||||
/**
|
||||
* Default configuration of the chip.
|
||||
*
|
||||
* @type {TemplateChipConfig}
|
||||
*
|
||||
* @readonly
|
||||
* @private
|
||||
*/
|
||||
readonly #defaultConfig: TemplateChipConfig = {
|
||||
type: "template",
|
||||
icon: "mdi:fan",
|
||||
icon_color: "green",
|
||||
content: Helper.getCountTemplate("fan", "eq", "on"),
|
||||
tap_action: {
|
||||
action: "call-service",
|
||||
service: "fan.turn_off",
|
||||
},
|
||||
hold_action: {
|
||||
action: "navigate",
|
||||
navigation_path: "fans",
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Class Constructor.
|
||||
*
|
||||
* @param {chips.TemplateChipOptions} options The chip options.
|
||||
*/
|
||||
constructor(options: chips.TemplateChipOptions = {}) {
|
||||
super();
|
||||
|
||||
this.config = Object.assign(this.config, this.#defaultConfig, options);
|
||||
}
|
||||
}
|
||||
|
||||
export {FanChip};
|
||||
@@ -1,43 +0,0 @@
|
||||
import {Helper} from "../Helper";
|
||||
|
||||
class LightChip {
|
||||
#areaIds;
|
||||
#options = {
|
||||
// No default options.
|
||||
};
|
||||
|
||||
constructor(areaIds, options = {}) {
|
||||
if (!Helper.isInitialized()) {
|
||||
throw new Error("The Helper module must be initialized before using this one.");
|
||||
}
|
||||
|
||||
this.#areaIds = areaIds.filter(areaId => areaId);
|
||||
this.#options = {
|
||||
...this.#options,
|
||||
...options,
|
||||
};
|
||||
}
|
||||
|
||||
getChip() {
|
||||
return {
|
||||
type: "template",
|
||||
icon: "mdi:lightbulb-group",
|
||||
icon_color: "amber",
|
||||
content: Helper.getCountTemplate("light", "eq", "on"),
|
||||
tap_action: {
|
||||
action: "call-service",
|
||||
service: "light.turn_off",
|
||||
target: {
|
||||
area_id: this.#areaIds,
|
||||
},
|
||||
data: {},
|
||||
},
|
||||
hold_action: {
|
||||
action: "navigate",
|
||||
navigation_path: "lights",
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export {LightChip};
|
||||
@@ -0,0 +1,48 @@
|
||||
import {Helper} from "../Helper";
|
||||
import {chips} from "../types/strategy/chips";
|
||||
import {AbstractChip} from "./AbstractChip";
|
||||
import {TemplateChipConfig} from "../types/lovelace-mushroom/utils/lovelace/chip/types";
|
||||
|
||||
// noinspection JSUnusedGlobalSymbols Class is dynamically imported.
|
||||
/**
|
||||
* Light Chip class.
|
||||
*
|
||||
* Used to create a chip to indicate how many lights are on and to turn all off.
|
||||
*/
|
||||
class LightChip extends AbstractChip {
|
||||
/**
|
||||
* Default configuration of the chip.
|
||||
*
|
||||
* @type {TemplateChipConfig}
|
||||
*
|
||||
* @readonly
|
||||
* @private
|
||||
*/
|
||||
readonly #defaultConfig: TemplateChipConfig = {
|
||||
type: "template",
|
||||
icon: "mdi:lightbulb-group",
|
||||
icon_color: "amber",
|
||||
content: Helper.getCountTemplate("light", "eq", "on"),
|
||||
tap_action: {
|
||||
action: "call-service",
|
||||
service: "light.turn_off",
|
||||
},
|
||||
hold_action: {
|
||||
action: "navigate",
|
||||
navigation_path: "lights",
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Class Constructor.
|
||||
*
|
||||
* @param {chips.TemplateChipOptions} options The chip options.
|
||||
*/
|
||||
constructor(options: chips.TemplateChipOptions = {}) {
|
||||
super();
|
||||
|
||||
this.config = Object.assign(this.config, this.#defaultConfig, options);
|
||||
}
|
||||
}
|
||||
|
||||
export {LightChip};
|
||||
@@ -1,43 +0,0 @@
|
||||
import {Helper} from "../Helper";
|
||||
|
||||
class SwitchChip {
|
||||
#areaIds;
|
||||
#options = {
|
||||
// No default options.
|
||||
};
|
||||
|
||||
constructor(areaIds, options = {}) {
|
||||
if (!Helper.isInitialized()) {
|
||||
throw new Error("The Helper module must be initialized before using this one.");
|
||||
}
|
||||
|
||||
this.#areaIds = areaIds.filter(areaId => areaId);
|
||||
this.#options = {
|
||||
...this.#options,
|
||||
...options,
|
||||
};
|
||||
}
|
||||
|
||||
getChip() {
|
||||
return {
|
||||
type: "template",
|
||||
icon: "mdi:dip-switch",
|
||||
icon_color: "blue",
|
||||
content: Helper.getCountTemplate("switch", "eq", "on"),
|
||||
tap_action: {
|
||||
action: "call-service",
|
||||
service: "switch.turn_off",
|
||||
target: {
|
||||
area_id: this.#areaIds,
|
||||
},
|
||||
data: {},
|
||||
},
|
||||
hold_action: {
|
||||
action: "navigate",
|
||||
navigation_path: "switches",
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export {SwitchChip};
|
||||
@@ -0,0 +1,48 @@
|
||||
import {Helper} from "../Helper";
|
||||
import {chips} from "../types/strategy/chips";
|
||||
import {AbstractChip} from "./AbstractChip";
|
||||
import {TemplateChipConfig} from "../types/lovelace-mushroom/utils/lovelace/chip/types";
|
||||
|
||||
// noinspection JSUnusedGlobalSymbols Class is dynamically imported.
|
||||
/**
|
||||
* Switch Chip class.
|
||||
*
|
||||
* Used to create a chip to indicate how many switches are on and to turn all off.
|
||||
*/
|
||||
class SwitchChip extends AbstractChip {
|
||||
/**
|
||||
* Default configuration of the chip.
|
||||
*
|
||||
* @type {TemplateChipConfig}
|
||||
*
|
||||
* @readonly
|
||||
* @private
|
||||
*/
|
||||
readonly #defaultConfig: TemplateChipConfig = {
|
||||
type: "template",
|
||||
icon: "mdi:dip-switch",
|
||||
icon_color: "blue",
|
||||
content: Helper.getCountTemplate("switch", "eq", "on"),
|
||||
tap_action: {
|
||||
action: "call-service",
|
||||
service: "switch.turn_off",
|
||||
},
|
||||
hold_action: {
|
||||
action: "navigate",
|
||||
navigation_path: "switches",
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Class Constructor.
|
||||
*
|
||||
* @param {chips.TemplateChipOptions} options The chip options.
|
||||
*/
|
||||
constructor(options: chips.TemplateChipOptions = {}) {
|
||||
super();
|
||||
|
||||
this.config = Object.assign(this.config, this.#defaultConfig, options);
|
||||
}
|
||||
}
|
||||
|
||||
export {SwitchChip};
|
||||
@@ -1,25 +0,0 @@
|
||||
class WeatherChip {
|
||||
#entityId;
|
||||
#options = {
|
||||
show_temperature: true,
|
||||
show_conditions: true,
|
||||
};
|
||||
|
||||
constructor(entityId, options = {}) {
|
||||
this.#entityId = entityId;
|
||||
this.#options = {
|
||||
...this.#options,
|
||||
...options,
|
||||
};
|
||||
}
|
||||
|
||||
getChip() {
|
||||
return {
|
||||
type: "weather",
|
||||
entity: this.#entityId,
|
||||
...this.#options,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export {WeatherChip};
|
||||
@@ -0,0 +1,42 @@
|
||||
import {chips} from "../types/strategy/chips";
|
||||
import {WeatherChipConfig} from "../types/lovelace-mushroom/utils/lovelace/chip/types";
|
||||
import {AbstractChip} from "./AbstractChip";
|
||||
|
||||
// noinspection JSUnusedGlobalSymbols False positive.
|
||||
/**
|
||||
* Weather Chip class.
|
||||
*
|
||||
* Used to create a chip for showing the weather.
|
||||
*/
|
||||
class WeatherChip extends AbstractChip {
|
||||
/**
|
||||
* Default configuration of the chip.
|
||||
*
|
||||
* @private
|
||||
* @readonly
|
||||
*/
|
||||
readonly #defaultConfig: WeatherChipConfig = {
|
||||
type: "weather",
|
||||
show_temperature: true,
|
||||
show_conditions: true,
|
||||
};
|
||||
|
||||
/**
|
||||
* Class Constructor.
|
||||
*
|
||||
* @param {string} entityId Id of a weather entity.
|
||||
* @param {chips.WeatherChipOptions} options Weather Chip options.
|
||||
*/
|
||||
constructor(entityId: string, options: chips.WeatherChipOptions = {}) {
|
||||
super();
|
||||
this.#defaultConfig = {
|
||||
...this.#defaultConfig,
|
||||
...{entity: entityId},
|
||||
...options,
|
||||
};
|
||||
|
||||
this.config = Object.assign(this.config, this.#defaultConfig, options);
|
||||
}
|
||||
}
|
||||
|
||||
export {WeatherChip};
|
||||
@@ -1,44 +1,20 @@
|
||||
export const optionDefaults = {
|
||||
debug: false,
|
||||
views: {
|
||||
home: {
|
||||
order: 1,
|
||||
hidden: false,
|
||||
},
|
||||
light: {
|
||||
order: 2,
|
||||
hidden: false,
|
||||
},
|
||||
fan: {
|
||||
order: 3,
|
||||
hidden: false,
|
||||
},
|
||||
cover: {
|
||||
order: 4,
|
||||
hidden: false,
|
||||
},
|
||||
switch: {
|
||||
order: 5,
|
||||
hidden: false,
|
||||
},
|
||||
climate: {
|
||||
order: 6,
|
||||
hidden: false,
|
||||
},
|
||||
camera: {
|
||||
order: 7,
|
||||
hidden: false,
|
||||
}
|
||||
},
|
||||
import {generic} from "./types/strategy/generic";
|
||||
import StrategyDefaults = generic.StrategyDefaults;
|
||||
|
||||
/**
|
||||
* Default configuration for the mushroom strategy.
|
||||
*/
|
||||
export const configurationDefaults: StrategyDefaults = {
|
||||
areas: {
|
||||
undisclosed: {
|
||||
aliases: [],
|
||||
area_id: null,
|
||||
area_id: "undisclosed",
|
||||
name: "Undisclosed",
|
||||
picture: null,
|
||||
hidden: false,
|
||||
}
|
||||
},
|
||||
debug: false,
|
||||
domains: {
|
||||
default: {
|
||||
title: "Miscellaneous",
|
||||
@@ -116,5 +92,47 @@ export const optionDefaults = {
|
||||
showControls: false,
|
||||
hidden: false,
|
||||
},
|
||||
vacuum: {
|
||||
title: "Vacuums",
|
||||
showControls: true,
|
||||
hidden: false,
|
||||
},
|
||||
},
|
||||
home_view: {
|
||||
hidden: [],
|
||||
},
|
||||
views: {
|
||||
home: {
|
||||
order: 1,
|
||||
hidden: false,
|
||||
},
|
||||
light: {
|
||||
order: 2,
|
||||
hidden: false,
|
||||
},
|
||||
fan: {
|
||||
order: 3,
|
||||
hidden: false,
|
||||
},
|
||||
cover: {
|
||||
order: 4,
|
||||
hidden: false,
|
||||
},
|
||||
switch: {
|
||||
order: 5,
|
||||
hidden: false,
|
||||
},
|
||||
climate: {
|
||||
order: 6,
|
||||
hidden: false,
|
||||
},
|
||||
camera: {
|
||||
order: 7,
|
||||
hidden: false,
|
||||
},
|
||||
vacuum: {
|
||||
order: 8,
|
||||
hidden: false,
|
||||
},
|
||||
}
|
||||
};
|
||||
@@ -1,34 +1,40 @@
|
||||
import {Helper} from "./Helper";
|
||||
import {SensorCard} from "./cards/SensorCard";
|
||||
import {TitleCard} from "./cards/TitleCard";
|
||||
import {ControllerCard} from "./cards/ControllerCard";
|
||||
import {generic} from "./types/strategy/generic";
|
||||
import {LovelaceCardConfig, LovelaceConfig, LovelaceViewConfig} from "./types/homeassistant/data/lovelace";
|
||||
import {StackCardConfig} from "./types/homeassistant/lovelace/cards/types";
|
||||
import {EntityCardConfig} from "./types/lovelace-mushroom/cards/entity-card-config";
|
||||
import {HassServiceTarget} from "home-assistant-js-websocket";
|
||||
import StrategyArea = generic.StrategyArea;
|
||||
|
||||
/**
|
||||
* Mushroom Dashboard Strategy.<br>
|
||||
* <br>
|
||||
* Mushroom dashboard strategy provides a strategy for Home-Assistant to create a dashboard automatically.<br>
|
||||
* The strategy makes use Mushroom, Mini Graph and WebRTC cards to represent your entities.<br>
|
||||
* The strategy makes use Mushroom and Mini Graph cards to represent your entities.<br>
|
||||
* <br>
|
||||
* Features:<br>
|
||||
* 🛠 Automatically create dashboard with 3 lines of yaml.<br>
|
||||
* 🛠 Automatically create dashboard with three lines of yaml.<br>
|
||||
* 😍 Built-in Views for several standard domains.<br>
|
||||
* 🎨 Many options to customize to your needs.<br>
|
||||
* <br>
|
||||
* Check the [Repository]{@link https://github.com/AalianKhan/mushroom-strategy} for more information.
|
||||
*/
|
||||
class MushroomStrategy {
|
||||
class MushroomStrategy extends HTMLTemplateElement {
|
||||
/**
|
||||
* Generate a dashboard.
|
||||
*
|
||||
* Called when opening a dashboard.
|
||||
*
|
||||
* @param {dashBoardInfo} info Dashboard strategy information object.
|
||||
* @return {Promise<{views: Object[]}>}
|
||||
* @param {generic.DashBoardInfo} info Dashboard strategy information object.
|
||||
* @return {Promise<LovelaceConfig>}
|
||||
*/
|
||||
static async generateDashboard(info) {
|
||||
static async generateDashboard(info: generic.DashBoardInfo): Promise<LovelaceConfig> {
|
||||
await Helper.initialize(info);
|
||||
|
||||
// Create views.
|
||||
const views = [];
|
||||
const views: LovelaceViewConfig[] = info.config?.views ?? [];
|
||||
|
||||
let viewModule;
|
||||
|
||||
@@ -36,13 +42,14 @@ class MushroomStrategy {
|
||||
for (let viewId of Helper.getExposedViewIds()) {
|
||||
try {
|
||||
const viewType = Helper.sanitizeClassName(viewId + "View");
|
||||
viewModule = await import(`./views/${viewType}`);
|
||||
const view = await new viewModule[viewType](Helper.strategyOptions.views[viewId]).getView();
|
||||
|
||||
views.push(view);
|
||||
viewModule = await import(`./views/${viewType}`);
|
||||
const view: LovelaceViewConfig = await new viewModule[viewType](Helper.strategyOptions.views[viewId]).getView();
|
||||
|
||||
if (view.cards?.length) {
|
||||
views.push(view);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(Helper.debug ? e : `View '${viewId}' couldn't be loaded!`);
|
||||
Helper.logError(`View '${viewId}' couldn't be loaded!`, e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -79,13 +86,18 @@ class MushroomStrategy {
|
||||
*
|
||||
* Called when opening a subview.
|
||||
*
|
||||
* @param {viewInfo} info The view's strategy information object.
|
||||
* @return {Promise<{cards: Object[]}>}
|
||||
* @param {generic.ViewInfo} info The view's strategy information object.
|
||||
* @return {Promise<LovelaceViewConfig>}
|
||||
*/
|
||||
static async generateView(info) {
|
||||
static async generateView(info: generic.ViewInfo): Promise<LovelaceViewConfig> {
|
||||
const exposedDomainIds = Helper.getExposedDomainIds();
|
||||
const area = info.view.strategy.options.area;
|
||||
const viewCards = [...(area.extra_cards ?? [])];
|
||||
const area = info.view.strategy?.options?.area ?? {} as StrategyArea;
|
||||
const viewCards: LovelaceCardConfig[] = [...(area.extra_cards ?? [])];
|
||||
|
||||
// Set the target for controller cards to the current area.
|
||||
let target: HassServiceTarget = {
|
||||
area_id: [area.area_id],
|
||||
};
|
||||
|
||||
// Create cards for each domain.
|
||||
for (const domain of exposedDomainIds) {
|
||||
@@ -100,27 +112,34 @@ class MushroomStrategy {
|
||||
try {
|
||||
domainCards = await import(`./cards/${className}`).then(cardModule => {
|
||||
let domainCards = [];
|
||||
const entities = Helper.getDeviceEntities(area, domain);
|
||||
const entities = Helper.getDeviceEntities(area, domain);
|
||||
|
||||
// Set the target for controller cards to entities without an area.
|
||||
if (area.area_id === "undisclosed") {
|
||||
target = {
|
||||
entity_id: entities.map(entity => entity.entity_id),
|
||||
}
|
||||
}
|
||||
|
||||
if (entities.length) {
|
||||
// Create a Title card for the current domain.
|
||||
const titleCard = new TitleCard(
|
||||
[area],
|
||||
Helper.strategyOptions.domains[domain],
|
||||
// Create a Controller card for the current domain.
|
||||
const titleCard = new ControllerCard(
|
||||
target,
|
||||
Helper.strategyOptions.domains[domain],
|
||||
).createCard();
|
||||
|
||||
if (domain === "sensor") {
|
||||
// Create a card for each entity-sensor of the current area.
|
||||
const sensorStates = Helper.getStateEntities(area, "sensor");
|
||||
const sensorCards = [];
|
||||
const sensorCards: EntityCardConfig[] = [];
|
||||
|
||||
for (const sensor of entities) {
|
||||
// Find the state of the current sensor.
|
||||
const sensorState = sensorStates.find(state => state.entity_id === sensor.entity_id);
|
||||
let cardOptions = Helper.strategyOptions.card_options?.[sensor.entity_id] ?? {};
|
||||
let deviceOptions = Helper.strategyOptions.card_options?.[sensor.device_id] ?? {};
|
||||
let cardOptions = Helper.strategyOptions.card_options?.[sensor.entity_id];
|
||||
let deviceOptions = Helper.strategyOptions.card_options?.[sensor.device_id ?? "null"];
|
||||
|
||||
if (!cardOptions.hidden && !deviceOptions.hidden) {
|
||||
if (!cardOptions?.hidden && !deviceOptions?.hidden) {
|
||||
if (sensorState?.attributes.unit_of_measurement) {
|
||||
cardOptions = {
|
||||
...{
|
||||
@@ -147,12 +166,16 @@ class MushroomStrategy {
|
||||
return domainCards;
|
||||
}
|
||||
|
||||
// Create a card for each domain-entity of the current area.
|
||||
// Create a card for each other domain-entity of the current area.
|
||||
for (const entity of entities) {
|
||||
let cardOptions = Helper.strategyOptions.card_options?.[entity.entity_id] ?? {};
|
||||
let deviceOptions = Helper.strategyOptions.card_options?.[entity.device_id] ?? {};
|
||||
let deviceOptions;
|
||||
let cardOptions = Helper.strategyOptions.card_options?.[entity.entity_id];
|
||||
|
||||
if (!cardOptions.hidden && !deviceOptions.hidden) {
|
||||
if (entity.device_id) {
|
||||
deviceOptions = Helper.strategyOptions.card_options?.[entity.device_id];
|
||||
}
|
||||
|
||||
if (!cardOptions?.hidden && !deviceOptions?.hidden) {
|
||||
domainCards.push(new cardModule[className](entity, cardOptions).getCard());
|
||||
}
|
||||
}
|
||||
@@ -179,7 +202,7 @@ class MushroomStrategy {
|
||||
return domainCards;
|
||||
});
|
||||
} catch (e) {
|
||||
console.error(Helper.debug ? e : "An error occurred while creating the domain cards!");
|
||||
Helper.logError("An error occurred while creating the domain cards!", e);
|
||||
}
|
||||
|
||||
if (domainCards.length) {
|
||||
@@ -193,36 +216,37 @@ class MushroomStrategy {
|
||||
if (!Helper.strategyOptions.domains.default.hidden) {
|
||||
// Create cards for any other domain.
|
||||
// Collect device entities of the current area.
|
||||
const areaDevices = Helper.devices.filter(device => device.area_id === area.area_id)
|
||||
.map(device => device.id);
|
||||
const areaDevices = Helper.devices.filter((device) => device.area_id === area.area_id)
|
||||
.map((device) => device.id);
|
||||
|
||||
// Collect the remaining entities of which all conditions below are met:
|
||||
// 1. The entity is linked to a device which is linked to the current area,
|
||||
// 1. The entity is not hidden.
|
||||
// 2. The entity's domain isn't exposed (entities of exposed domains are already included).
|
||||
// 3. The entity is linked to a device which is linked to the current area,
|
||||
// or the entity itself is linked to the current area.
|
||||
// 2. The entity is not hidden and is not disabled.
|
||||
const miscellaneousEntities = Helper.entities.filter(entity => {
|
||||
return (areaDevices.includes(entity.device_id) || entity.area_id === area.area_id)
|
||||
&& entity.hidden_by == null
|
||||
&& entity.disabled_by == null
|
||||
&& !exposedDomainIds.includes(entity.entity_id.split(".", 1)[0]);
|
||||
const miscellaneousEntities = Helper.entities.filter((entity) => {
|
||||
const entityLinked = areaDevices.includes(entity.device_id ?? "null") || entity.area_id === area.area_id;
|
||||
const entityUnhidden = entity.hidden_by === null && entity.disabled_by === null;
|
||||
const domainExposed = exposedDomainIds.includes(entity.entity_id.split(".", 1)[0]);
|
||||
|
||||
return entityUnhidden && !domainExposed && entityLinked;
|
||||
});
|
||||
|
||||
// Create a column of miscellaneous entity cards.
|
||||
if (miscellaneousEntities.length) {
|
||||
let miscellaneousCards = [];
|
||||
let miscellaneousCards: (StackCardConfig | EntityCardConfig)[] = [];
|
||||
|
||||
try {
|
||||
miscellaneousCards = await import("./cards/MiscellaneousCard").then(cardModule => {
|
||||
/** @type Object[] */
|
||||
const miscellaneousCards = [
|
||||
new TitleCard([area], Helper.strategyOptions.domains.default).createCard(),
|
||||
const miscellaneousCards: (StackCardConfig | EntityCardConfig)[] = [
|
||||
new ControllerCard(target, Helper.strategyOptions.domains.default).createCard(),
|
||||
];
|
||||
|
||||
for (const entity of miscellaneousEntities) {
|
||||
let cardOptions = Helper.strategyOptions.card_options?.[entity.entity_id] ?? {};
|
||||
let deviceOptions = Helper.strategyOptions.card_options?.[entity.device_id] ?? {};
|
||||
let cardOptions = Helper.strategyOptions.card_options?.[entity.entity_id];
|
||||
let deviceOptions = Helper.strategyOptions.card_options?.[entity.device_id ?? "null"];
|
||||
|
||||
if (!cardOptions.hidden && !deviceOptions.hidden) {
|
||||
if (!cardOptions?.hidden && !deviceOptions?.hidden) {
|
||||
miscellaneousCards.push(new cardModule.MiscellaneousCard(entity, cardOptions).getCard());
|
||||
}
|
||||
}
|
||||
@@ -230,7 +254,7 @@ class MushroomStrategy {
|
||||
return miscellaneousCards;
|
||||
});
|
||||
} catch (e) {
|
||||
console.error(Helper.debug ? e : "An error occurred while creating the domain cards!");
|
||||
Helper.logError("An error occurred while creating the domain cards!", e);
|
||||
}
|
||||
|
||||
viewCards.push({
|
||||
@@ -247,5 +271,10 @@ class MushroomStrategy {
|
||||
}
|
||||
}
|
||||
|
||||
// noinspection JSUnresolvedReference
|
||||
customElements.define("ll-strategy-mushroom-strategy", MushroomStrategy);
|
||||
|
||||
const version = "v2.0.0";
|
||||
console.info(
|
||||
"%c Mushroom Strategy %c ".concat(version, " "),
|
||||
"color: white; background: coral; font-weight: 700;", "color: coral; background: white; font-weight: 700;"
|
||||
);
|
||||
-255
@@ -1,255 +0,0 @@
|
||||
/**
|
||||
* @namespace typedefs.generic
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} hassEntity Home assistant entity.
|
||||
* @property {string} name The name of this entity.
|
||||
* @property {string} original_name The original name of this entity.
|
||||
* @property {string} entity_id The id of this entity.
|
||||
* @property {string} device_id The id of the device to which this entity is linked.
|
||||
* @property {string} area_id The id of the area to which this entity is linked.
|
||||
* @property {string[]|null} disabled_by Indicates by what this entity is disabled.
|
||||
* @property {string[]|null} hidden_by Indicates by what this entity is hidden.
|
||||
* @memberOf typedefs.generic
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} deviceEntity Device Entity.
|
||||
* @property {string} area_id The Area which the device is placed in.
|
||||
* @property {string} id Unique ID of a device (generated by Home Assistant).
|
||||
* @property {string[]|null} disabled_by Indicates by what this entity is disabled.
|
||||
* @property {string[]|null} hidden_by Indicates by what this entity is hidden.
|
||||
* @memberOf typedefs.generic
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} areaEntity Area Entity.
|
||||
* @property {string[]} [aliases] Array of aliases of this entity.
|
||||
* @property {string|null} area_id The id of this entity.
|
||||
* @property {string} name Name of this entity.
|
||||
* @property {string|null} picture URL to a picture that should be used instead of showing the domain icon.
|
||||
* @property {number} [order] Ordering position of the area in the list of available areas.
|
||||
* @property {boolean} [hidden] True if the entity should be hidden from the dashboard.
|
||||
* This property is added by the custom strategy.
|
||||
* @property {Object[]} [extra_cards] An array of card configurations.
|
||||
* The configured cards are added to the dashboard.
|
||||
* This property is added by the custom strategy.
|
||||
* @property {boolean} [use_ha_area_card] Set to true to use ha area card instead of mushroom.
|
||||
* @memberOf typedefs.generic
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} viewEntity View Entity.
|
||||
* This entity is added by the custom strategy.
|
||||
* @property {string} title Title of this entity.
|
||||
* @property {string} icon Icon to use for the entity in the frontend.
|
||||
* Example: `mdi:home`.
|
||||
* @property {number} [order] Ordering position of the entity in the list of available views.
|
||||
* @property {boolean} [hidden] True if the entity should be hidden from the dashboard.
|
||||
* @memberOf typedefs.generic
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object & titleCardOptions} domainEntity Domain Entity.
|
||||
* This entity is added by the custom strategy.
|
||||
* @property {number} [order] Ordering position of the entity in the list of available views.
|
||||
* @property {boolean} [hidden] True if the entity should be hidden from the dashboard.
|
||||
* @memberOf typedefs.generic
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} titleCardOptions Title Card options.
|
||||
* @property {string} [title] Title to render. May contain templates.
|
||||
* @property {string} [subtitle] Subtitle to render. May contain templates.
|
||||
* @property {boolean} [showControls=true] False to hide controls.
|
||||
* @property {string} [iconOn] Icon to show for switching entities from off state.
|
||||
* @property {string} [iconOff] Icon to show for switching entities to off state.
|
||||
* @property {string} [onService=none] Service to call for switching entities from off state.
|
||||
* @property {string} [offService=none] Service to call for switching entities to off state.
|
||||
* @memberOf typedefs.generic
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} dashBoardInfo Strategy information object.
|
||||
* @property {dashboardConfig} config User supplied dashboard configuration, if any.
|
||||
* @property {hassObject} hass The Home Assistant object.
|
||||
* @property {boolean} narrow If the current user interface is rendered in narrow mode or not.
|
||||
* @memberOf typedefs.generic
|
||||
* @see https://developers.home-assistant.io/docs/frontend/custom-ui/custom-strategy/#dashboard-strategies
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} viewInfo Strategy information object.
|
||||
* @property {Object} view Configuration of the current view.
|
||||
* @property {viewConfig} config Dashboard configuration.
|
||||
* @property {hassObject} hass The Home Assistant object.
|
||||
* @property {boolean} narrow If the current user interface is rendered in narrow mode or not.
|
||||
* @memberOf typedefs.generic
|
||||
* @see https://developers.home-assistant.io/docs/frontend/custom-ui/custom-strategy/#view-strategies
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} dashboardConfig User supplied dashboard configuration.
|
||||
* @property {strategyObject} strategy User supplied dashboard configuration.
|
||||
* @memberOf typedefs.generic
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} viewConfig Dashboard configuration.
|
||||
* @property {Object[]} strategy Array of views generated by the strategy.
|
||||
* @memberOf typedefs.generic
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} strategyObject User supplied dashboard configuration.
|
||||
* @property {strategyOptions} options Custom strategy configuration.
|
||||
* @property {string} type Strategy type.
|
||||
* @memberOf typedefs.generic
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} customStrategyOptions Custom strategy configuration.
|
||||
* @property {boolean} [debug] Set to true for more verbose debugging info.
|
||||
* @property {Object.<areaEntity>} [areas] List of areas.
|
||||
* @property {Object.<cardOptions>} [card_options] Card options for entities.
|
||||
* @property {Object.<viewEntity>} [views] List of views.
|
||||
* @property {Object.<domainEntity>} [domains] List of domains.
|
||||
* @property {chip[]} [chips] List of chips to show in the Home view.
|
||||
* @property {Object[]} [quick_access_cards] List of cards to show between welcome card and rooms cards.
|
||||
* @property {Object[]} [extra_cards] List of cards to show below room cards.
|
||||
* @property {Object[]} [extra_views] List of views to add to the dashboard.
|
||||
* @property {Object.<homeViewOptions>} [homeView] Options for the home view.
|
||||
* @memberOf typedefs.generic
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} chip List of chips to show in the Home view.
|
||||
* @property {boolean} light_count Chip to display the number of lights on.
|
||||
* @property {boolean} fan_count Chip to display the number of fans on.
|
||||
* @property {boolean} cover_count Chip to display the number of unclosed covers.
|
||||
* @property {boolean} switch_count Chip to display the number of switches on.
|
||||
* @property {boolean} climate_count Chip to display the number of climates which are not off.
|
||||
* @property {string} weather_entity Entity ID for the weather chip to use, accepts `weather.` only.
|
||||
* @property {Object[]} extra_chips List of extra chips.
|
||||
* @memberOf typedefs.generic
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} homeViewOptions Options for the home view.
|
||||
* @property {string[]} [hidden] Elements to hide from the home view.
|
||||
* @memberOf typedefs.generic
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} cardOptions Custom card-configuration for an entity.
|
||||
* @property {string} type Type of card for the entity
|
||||
* @property {boolean} hidden True if the entity should be hidden from the dashboard.
|
||||
* @memberOf typedefs.generic
|
||||
*/
|
||||
|
||||
/**
|
||||
* The frontend passes a single hass object around.
|
||||
* This object contains the latest state and allows you to send commands back to the server.
|
||||
*
|
||||
* @typedef {Object} hassObject Home Assistant object.
|
||||
* @property {Object<string, stateObject>} states An object containing the states of all entities in Home Assistant.
|
||||
* The key is the entity_id, the value is the state object.
|
||||
* @property {hassUser} user The logged-in user.
|
||||
* @property {function} callWS Call a WebSocket command on the backend.
|
||||
* @memberOf typedefs.generic
|
||||
* @see https://developers.home-assistant.io/docs/frontend/data/
|
||||
*/
|
||||
|
||||
/**
|
||||
* The logged-in user.
|
||||
*
|
||||
* @typedef {Object} hassUser The logged-in user.
|
||||
* @property {string} name Name of the user.
|
||||
* @property {boolean} is_owner True if the user is the owner.
|
||||
* @property {boolean} is_owner True if the user is an administrator.
|
||||
* @property {Object[]} credentials Authentication credentials.
|
||||
* @memberOf typedefs.generic
|
||||
* @see https://developers.home-assistant.io/docs/frontend/data/#hassuser
|
||||
*/
|
||||
|
||||
/**
|
||||
* States are a current representation of the entity.
|
||||
*
|
||||
* All states will always have an entity id, a state and a timestamp when last updated and last changed.
|
||||
*
|
||||
* @typedef {Object} stateObject State object.
|
||||
* @property {string} state String representation of the entity's current state.
|
||||
* Example `off`.
|
||||
* @property {string} entity_id Entity ID.
|
||||
* Format: <domain>.<object_id>.
|
||||
* Example: `light.kitchen`.
|
||||
* @property {string} domain Domain of the entity.
|
||||
* Example: `light`.
|
||||
* @property {string} object_id Object ID of entity.
|
||||
* Example: `kitchen`.
|
||||
* @property {string} name Name of the entity.
|
||||
* Based on `friendly_name` attribute with fall-back to object ID.
|
||||
* Example: `Kitchen Ceiling`.
|
||||
* @property {string} last_updated Time the state was written to the state machine in UTC time.
|
||||
* Note that writing the exact same state including attributes will not result in this
|
||||
* field being updated.
|
||||
* Example: `2017-10-28 08:13:36.715874+00:00`.
|
||||
* @property {string} last_changed Time the state changed in the state machine in UTC time.
|
||||
* This is not updated when there are only updated attributes.
|
||||
* Example: `2017-10-28 08:13:36.715874+00:00`.
|
||||
* @property {stateAttributes} attributes A dictionary with extra attributes related to the current state.
|
||||
* @property {stateContext} context A dictionary with extra attributes related to the context of the state.
|
||||
* @memberOf typedefs.generic
|
||||
* @see https://www.home-assistant.io/docs/configuration/state_object/
|
||||
*/
|
||||
|
||||
/**
|
||||
* The attributes of an entity are optional.
|
||||
*
|
||||
* There are a few attributes that are used by Home Assistant for representing the entity in a specific way.
|
||||
* Each integration will also have its own attributes to represent extra state data about the entity.
|
||||
* For example, the light integration has attributes for the current brightness and color of the light.
|
||||
*
|
||||
* When an attribute is not available, Home Assistant will not write it to the state.
|
||||
*
|
||||
* @typedef {Object} stateAttributes State attributes.
|
||||
* @property {string} friendly_name Name of the entity.
|
||||
* Example: `Kitchen Ceiling`.
|
||||
* @property {string} icon Icon to use for the entity in the frontend.
|
||||
* Example: `mdi:home`.
|
||||
* @property {string} entity_picture URL to a picture that should be used instead of showing the domain icon.
|
||||
* @property {string} assumed_state Boolean if the current state is an assumption.
|
||||
* @property {string} unit_of_measurement The unit of measurement the state is expressed in.
|
||||
* Used for grouping graphs or understanding the entity.
|
||||
* Example: `°C`.
|
||||
* @memberOf typedefs.generic
|
||||
* @see https://www.home-assistant.io/docs/configuration/state_object/#attributes
|
||||
*/
|
||||
|
||||
/**
|
||||
* Context is used to tie events and states together in Home Assistant. Whenever an automation or user interaction
|
||||
* causes states to change, a new context is assigned. This context will be attached to all events and states that
|
||||
* happen as a result of the change.
|
||||
*
|
||||
* @typedef {Object} stateContext State context.
|
||||
* @property {string} context_id Unique identifier for the context.
|
||||
* @property {string} user_id Unique identifier of the user that started the change.
|
||||
* Will be None if action was not started by a user (i.e., started by an automation)
|
||||
* @property {string} parent_id Unique identifier of the parent context that started the change, if available.
|
||||
* For example, if an automation is triggered, the context of the trigger will be set as
|
||||
* parent.
|
||||
* @see https://www.home-assistant.io/docs/configuration/state_object/#context
|
||||
* @memberOf typedefs.generic
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} areaFilterContext fer Card options.
|
||||
* @property {areaEntity} area Area Entity.
|
||||
* @property {string} domain Domain of the entity.
|
||||
* Example: `light`.
|
||||
* @property {string[]} areaDeviceIds The id of devices which are linked to the area entity.
|
||||
* @memberOf typedefs.cards
|
||||
*/
|
||||
|
||||
export {};
|
||||
@@ -0,0 +1,22 @@
|
||||
This directory contains partial code from
|
||||
the [Home Assistant Frontend repository](https://github.com/home-assistant/frontend).
|
||||
|
||||
The code mainly defines Home Assistant interfaces/types which are refactored to fit this repository.
|
||||
This means properties are added/removed from the originals and subtypes may have been changed.
|
||||
|
||||
The [Apache 2.0 License](https://github.com/home-assistant/frontend/blob/dev/LICENSE.md) applies to all files in this
|
||||
directory.
|
||||
|
||||
Copyright 2023 Ferry Cools
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
@@ -0,0 +1,14 @@
|
||||
/**
|
||||
* Area Entity.
|
||||
*
|
||||
* @property {string} area_id The id of the area.
|
||||
* @property {string} name Name of the area.
|
||||
* @property {string|null} picture URL to a picture that should be used instead of showing the domain icon.
|
||||
* @property {string[]} aliases Array of aliases of the area.
|
||||
*/
|
||||
export interface AreaRegistryEntry {
|
||||
area_id: string;
|
||||
name: string;
|
||||
picture: string | null;
|
||||
aliases: string[];
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
export const HVAC_MODES = [
|
||||
"auto",
|
||||
"heat_cool",
|
||||
"heat",
|
||||
"cool",
|
||||
"dry",
|
||||
"fan_only",
|
||||
"off",
|
||||
] as const;
|
||||
|
||||
export type HvacMode = (typeof HVAC_MODES)[number];
|
||||
|
||||
HVAC_MODES.reduce(
|
||||
(order, mode, index) => {
|
||||
order[mode] = index;
|
||||
return order;
|
||||
},
|
||||
{} as Record<HvacMode, number>
|
||||
);
|
||||
@@ -0,0 +1,38 @@
|
||||
/**
|
||||
* Device Entity.
|
||||
*
|
||||
* @property {string} id Unique ID of a device (generated by Home Assistant).
|
||||
* @property {string[]} config_entries
|
||||
* @property {Array} connections
|
||||
* @property {Array} identifiers
|
||||
* @property {string | null} manufacturer
|
||||
* @property {string | null} model
|
||||
* @property {string | null} name
|
||||
* @property {string | null} sw_version
|
||||
* @property {string | null} hw_version
|
||||
* @property {string | null} serial_number
|
||||
* @property {string | null} via_device_id
|
||||
* @property {string} area_id The Area which the device is placed in.
|
||||
* @property {string | null} name_by_user
|
||||
* @property {string[] | null} entry_type
|
||||
* @property {string | null} disabled_by Indicates by what this entity is disabled.
|
||||
* @property {string | null} configuration_url
|
||||
*/
|
||||
export interface DeviceRegistryEntry {
|
||||
id: string;
|
||||
config_entries: string[];
|
||||
connections: Array<[string, string]>;
|
||||
identifiers: Array<[string, string]>;
|
||||
manufacturer: string | null;
|
||||
model: string | null;
|
||||
name: string | null;
|
||||
sw_version: string | null;
|
||||
hw_version: string | null;
|
||||
serial_number: string | null;
|
||||
via_device_id: string | null;
|
||||
area_id: string | null;
|
||||
name_by_user: string | null;
|
||||
entry_type: "service" | null;
|
||||
disabled_by: "user" | "integration" | "config_entry" | null;
|
||||
configuration_url: string | null;
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
import {LightColor} from "./light";
|
||||
|
||||
type EntityCategory = "config" | "diagnostic";
|
||||
|
||||
export interface EntityRegistryDisplayEntry {
|
||||
entity_id: string;
|
||||
name?: string;
|
||||
device_id?: string;
|
||||
area_id?: string;
|
||||
hidden?: boolean;
|
||||
entity_category?: EntityCategory;
|
||||
translation_key?: string;
|
||||
platform?: string;
|
||||
display_precision?: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Home assistant entity.
|
||||
*
|
||||
* @property {string} id
|
||||
* @property {string} entity_id The id of this entity.
|
||||
* @property {string} name The name of this entity.
|
||||
* @property {string | null} icon
|
||||
* @property {string | null} platform
|
||||
* @property {string | null} config_entry_id
|
||||
* @property {string | null} device_id The id of the device to which this entity is linked.
|
||||
* @property {string | null} area_id The id of the area to which this entity is linked.
|
||||
* @property {string | null} disabled_by Indicates by what this entity is disabled.
|
||||
* @property {Object} hidden_by Indicates by what this entity is hidden.
|
||||
* @property {EntityCategory | null} entity_category
|
||||
* @property {boolean} has_entity_name
|
||||
* @property {string} [original_name]
|
||||
* @property {string} unique_id
|
||||
* @property {string} [translation_key]
|
||||
* @property {EntityRegistryOptions | null} options
|
||||
*/
|
||||
export interface EntityRegistryEntry {
|
||||
id: string;
|
||||
entity_id: string;
|
||||
name: string | null;
|
||||
icon: string | null;
|
||||
platform: string;
|
||||
config_entry_id: string | null;
|
||||
device_id: string | null;
|
||||
area_id: string | null;
|
||||
disabled_by: "user" | "device" | "integration" | "config_entry" | null;
|
||||
hidden_by: Exclude<EntityRegistryEntry["disabled_by"], "config_entry">;
|
||||
entity_category: EntityCategory | null;
|
||||
has_entity_name: boolean;
|
||||
original_name?: string;
|
||||
unique_id: string;
|
||||
translation_key?: string;
|
||||
options: EntityRegistryOptions | null;
|
||||
}
|
||||
|
||||
export interface SensorEntityOptions {
|
||||
display_precision?: number | null;
|
||||
suggested_display_precision?: number | null;
|
||||
unit_of_measurement?: string | null;
|
||||
}
|
||||
|
||||
export interface LightEntityOptions {
|
||||
favorite_colors?: LightColor[];
|
||||
}
|
||||
|
||||
export interface NumberEntityOptions {
|
||||
unit_of_measurement?: string | null;
|
||||
}
|
||||
|
||||
export interface LockEntityOptions {
|
||||
default_code?: string | null;
|
||||
}
|
||||
|
||||
export interface WeatherEntityOptions {
|
||||
precipitation_unit?: string | null;
|
||||
pressure_unit?: string | null;
|
||||
temperature_unit?: string | null;
|
||||
visibility_unit?: string | null;
|
||||
wind_speed_unit?: string | null;
|
||||
}
|
||||
|
||||
export interface SwitchAsXEntityOptions {
|
||||
entity_id: string;
|
||||
}
|
||||
|
||||
export interface EntityRegistryOptions {
|
||||
number?: NumberEntityOptions;
|
||||
sensor?: SensorEntityOptions;
|
||||
lock?: LockEntityOptions;
|
||||
weather?: WeatherEntityOptions;
|
||||
light?: LightEntityOptions;
|
||||
switch_as_x?: SwitchAsXEntityOptions;
|
||||
conversation?: Record<string, unknown>;
|
||||
"cloud.alexa"?: Record<string, unknown>;
|
||||
"cloud.google_assistant"?: Record<string, unknown>;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
export type LightColor =
|
||||
| { color_temp_kelvin: number; }
|
||||
| { hs_color: [number, number]; }
|
||||
| { rgb_color: [number, number, number]; }
|
||||
| { rgbw_color: [number, number, number, number]; }
|
||||
| { rgbww_color: [number, number, number, number, number]; };
|
||||
@@ -0,0 +1,118 @@
|
||||
import {HassServiceTarget} from "home-assistant-js-websocket";
|
||||
|
||||
export type LovelaceStrategyConfig = {
|
||||
type: string;
|
||||
[key: string]: any;
|
||||
};
|
||||
|
||||
export interface LovelaceConfig {
|
||||
title?: string;
|
||||
strategy?: LovelaceStrategyConfig;
|
||||
views: LovelaceViewConfig[];
|
||||
background?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* View Config.
|
||||
*
|
||||
* @see https://www.home-assistant.io/dashboards/views/
|
||||
*/
|
||||
export interface LovelaceViewConfig {
|
||||
index?: number;
|
||||
title?: string;
|
||||
type?: string;
|
||||
strategy?: LovelaceStrategyConfig;
|
||||
badges?: Array<string | LovelaceBadgeConfig>;
|
||||
cards?: LovelaceCardConfig[];
|
||||
path?: string;
|
||||
icon?: string;
|
||||
theme?: string;
|
||||
panel?: boolean;
|
||||
background?: string;
|
||||
visible?: boolean | ShowViewConfig[];
|
||||
subview?: boolean;
|
||||
back_path?: string;
|
||||
}
|
||||
|
||||
export interface ShowViewConfig {
|
||||
user?: string;
|
||||
}
|
||||
|
||||
export interface LovelaceBadgeConfig {
|
||||
type?: string;
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
export interface LovelaceCardConfig {
|
||||
index?: number;
|
||||
view_index?: number;
|
||||
view_layout?: any;
|
||||
type: string;
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
export interface ToggleActionConfig extends BaseActionConfig {
|
||||
action: "toggle";
|
||||
}
|
||||
|
||||
export interface CallServiceActionConfig extends BaseActionConfig {
|
||||
action: "call-service";
|
||||
service: string;
|
||||
target?: HassServiceTarget;
|
||||
// Property "service_data" is kept for backwards compatibility. Replaced by "data".
|
||||
service_data?: Record<string, unknown>;
|
||||
data?: Record<string, unknown>;
|
||||
}
|
||||
|
||||
export interface NavigateActionConfig extends BaseActionConfig {
|
||||
action: "navigate";
|
||||
navigation_path: string;
|
||||
navigation_replace?: boolean;
|
||||
}
|
||||
|
||||
export interface UrlActionConfig extends BaseActionConfig {
|
||||
action: "url";
|
||||
url_path: string;
|
||||
}
|
||||
|
||||
export interface MoreInfoActionConfig extends BaseActionConfig {
|
||||
action: "more-info";
|
||||
}
|
||||
|
||||
export interface AssistActionConfig extends BaseActionConfig {
|
||||
action: "assist";
|
||||
pipeline_id?: string;
|
||||
start_listening?: boolean;
|
||||
}
|
||||
|
||||
export interface NoActionConfig extends BaseActionConfig {
|
||||
action: "none";
|
||||
}
|
||||
|
||||
export interface CustomActionConfig extends BaseActionConfig {
|
||||
action: "fire-dom-event";
|
||||
}
|
||||
|
||||
export interface BaseActionConfig {
|
||||
action: string;
|
||||
confirmation?: ConfirmationRestrictionConfig;
|
||||
}
|
||||
|
||||
export interface ConfirmationRestrictionConfig {
|
||||
text?: string;
|
||||
exemptions?: RestrictionConfig[];
|
||||
}
|
||||
|
||||
export interface RestrictionConfig {
|
||||
user: string;
|
||||
}
|
||||
|
||||
export type ActionConfig =
|
||||
| ToggleActionConfig
|
||||
| CallServiceActionConfig
|
||||
| NavigateActionConfig
|
||||
| UrlActionConfig
|
||||
| MoreInfoActionConfig
|
||||
| AssistActionConfig
|
||||
| NoActionConfig
|
||||
| CustomActionConfig;
|
||||
@@ -0,0 +1,26 @@
|
||||
import {LovelaceCardConfig} from "../../data/lovelace";
|
||||
|
||||
/**
|
||||
* Home Assistant Stack Card Config.
|
||||
*
|
||||
* @property {string} type The stack type.
|
||||
* @property {Object[]} cards The content of the stack.
|
||||
*
|
||||
* @see https://www.home-assistant.io/dashboards/horizontal-stack/
|
||||
* @see https://www.home-assistant.io/dashboards/vertical-stack/
|
||||
*/
|
||||
export interface StackCardConfig extends LovelaceCardConfig {
|
||||
cards: LovelaceCardConfig[];
|
||||
title?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Home Assistant Area Card Config.
|
||||
*
|
||||
* @see https://www.home-assistant.io/dashboards/area/
|
||||
*/
|
||||
export interface AreaCardConfig extends LovelaceCardConfig {
|
||||
area: string;
|
||||
navigation_path?: string;
|
||||
show_camera?: boolean;
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
import {ActionConfig, LovelaceCardConfig} from "../../../data/lovelace";
|
||||
|
||||
/**
|
||||
* Home Assistant Picture Entity Config.
|
||||
*
|
||||
* @property {string} entity An entity_id used for the picture.
|
||||
* @property {string} [name] Overwrite entity name.
|
||||
* @property {string} [image] URL of an image.
|
||||
* @property {string} [camera_image] Camera entity_id to use. (not required if entity is already a camera-entity).
|
||||
* @property {string} [camera_view=auto] “live” will show the live view if stream is enabled.
|
||||
* @property {Record<string, unknown>} [state_image] Map entity states to images (state: image URL).
|
||||
* @property {string[]} [state_filter] State-based CSS filters.
|
||||
* @property {string} [aspect_ratio] Forces the height of the image to be a ratio of the width.
|
||||
* Valid formats: Height percentage value (23%) or ratio expressed with colon or “x”
|
||||
* separator (16:9 or 16x9).
|
||||
* For a ratio, the second element can be omitted and will default to “1”
|
||||
* (1.78 equals 1.78:1).
|
||||
* @property {ActionConfig} [tap_action] Action taken on card tap.
|
||||
* @property {ActionConfig} [hold_action] Action taken on card tap and hold.
|
||||
* @property {ActionConfig} [double_tap_action] Action taken on card double tap.
|
||||
* @property {boolean} [show_name=true] Shows name in footer.
|
||||
* @property {string} [theme=true] Override the used theme for this card with any loaded theme.
|
||||
*
|
||||
* @see https://www.home-assistant.io/dashboards/picture-entity/
|
||||
*/
|
||||
export interface PictureEntityCardConfig extends LovelaceCardConfig {
|
||||
entity: string;
|
||||
name?: string;
|
||||
image?: string;
|
||||
camera_image?: string;
|
||||
camera_view?: "live" | "auto";
|
||||
state_image?: Record<string, unknown>;
|
||||
state_filter?: string[];
|
||||
aspect_ratio?: string;
|
||||
tap_action?: ActionConfig;
|
||||
hold_action?: ActionConfig;
|
||||
double_tap_action?: ActionConfig;
|
||||
show_name?: boolean;
|
||||
show_state?: boolean;
|
||||
theme?: string;
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
import {Auth, Connection, HassConfig, HassEntities, HassServices, MessageBase,} from "home-assistant-js-websocket";
|
||||
import {AreaRegistryEntry} from "./data/area_registry";
|
||||
import {DeviceRegistryEntry} from "./data/device_registry";
|
||||
import {EntityRegistryDisplayEntry} from "./data/entity_registry";
|
||||
|
||||
export interface Credential {
|
||||
auth_provider_type: string;
|
||||
auth_provider_id: string;
|
||||
}
|
||||
|
||||
export 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[];
|
||||
}
|
||||
|
||||
export interface PanelInfo<T = Record<string, any> | null> {
|
||||
component_name: string;
|
||||
config: T;
|
||||
icon: string | null;
|
||||
title: string | null;
|
||||
url_path: string;
|
||||
config_panel_domain?: string;
|
||||
}
|
||||
|
||||
export interface Panels {
|
||||
[name: string]: PanelInfo;
|
||||
}
|
||||
|
||||
|
||||
export interface Translation {
|
||||
nativeName: string;
|
||||
isRTL: boolean;
|
||||
hash: string;
|
||||
}
|
||||
|
||||
export interface TranslationMetadata {
|
||||
fragments: string[];
|
||||
translations: {
|
||||
[lang: string]: Translation;
|
||||
};
|
||||
}
|
||||
|
||||
export interface Resources {
|
||||
[language: string]: Record<string, string>;
|
||||
}
|
||||
|
||||
export interface HomeAssistant {
|
||||
auth: Auth & { external?: any };
|
||||
connection: Connection;
|
||||
connected: boolean;
|
||||
states: HassEntities;
|
||||
entities: { [id: string]: EntityRegistryDisplayEntry };
|
||||
devices: { [id: string]: DeviceRegistryEntry };
|
||||
areas: { [id: string]: AreaRegistryEntry };
|
||||
services: HassServices;
|
||||
config: HassConfig;
|
||||
themes: { [k: string]: any };
|
||||
selectedTheme: { [k: string]: any } | null;
|
||||
panels: Panels;
|
||||
panelUrl: string;
|
||||
// i18n
|
||||
// current effective language in that order:
|
||||
// - backend saved user selected language
|
||||
// - language in local app storage
|
||||
// - browser language
|
||||
// - english (en)
|
||||
language: string;
|
||||
// local stored language, keep that name for backward compatibility
|
||||
selectedLanguage: string | null;
|
||||
locale: { [k: string]: any };
|
||||
resources: Resources;
|
||||
localize: Function;
|
||||
translationMetadata: TranslationMetadata;
|
||||
suspendWhenHidden: boolean;
|
||||
enableShortcuts: boolean;
|
||||
vibrate: boolean;
|
||||
debugConnection: boolean;
|
||||
dockedSidebar: "docked" | "always_hidden" | "auto";
|
||||
defaultPanel: string;
|
||||
moreInfoEntityId: string | null;
|
||||
user?: CurrentUser;
|
||||
userData?: { [k: string]: any } | null;
|
||||
|
||||
callWS<T>(msg: MessageBase): Promise<T>;
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
This directory contains partial code from
|
||||
the [Lovelace Mushroom repository](https://github.com/piitaya/lovelace-mushroom).
|
||||
|
||||
The code mainly defines Home Assistant interfaces/types which are refactored to fit this repository.
|
||||
This means properties are added/removed from the originals and subtypes may have been changed.
|
||||
|
||||
The [Apache 2.0 License](https://github.com/home-assistant/frontend/blob/dev/LICENSE.md) applies to all files in this
|
||||
directory.
|
||||
|
||||
Copyright 2023 Ferry Cools
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
@@ -0,0 +1,15 @@
|
||||
import {LovelaceCardConfig} from "../../homeassistant/data/lovelace";
|
||||
import {LovelaceChipConfig} from "../utils/lovelace/chip/types";
|
||||
|
||||
/**
|
||||
* Chips Card Configuration
|
||||
*
|
||||
* @param {LovelaceChipConfig[]} chips Chips Array
|
||||
* @param {string} [alignment=start] Chips alignment (end, center, justify), when empty default behavior is start.
|
||||
*
|
||||
* @see https://github.com/piitaya/lovelace-mushroom/blob/main/docs/cards/chips.md
|
||||
*/
|
||||
export interface ChipsCardConfig extends LovelaceCardConfig {
|
||||
chips: LovelaceChipConfig[];
|
||||
alignment?: string;
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
import {HvacMode} from "../../homeassistant/data/climate";
|
||||
import {LovelaceCardConfig} from "../../homeassistant/data/lovelace";
|
||||
import {EntitySharedConfig} from "../shared/config/entity-config";
|
||||
import {AppearanceSharedConfig} from "../shared/config/appearance-config";
|
||||
import {ActionsSharedConfig} from "../shared/config/actions-config";
|
||||
|
||||
/**
|
||||
* Climate Card Config.
|
||||
*
|
||||
* @property {boolean} [show_temperature_control=false] Show buttons to control target temperature.
|
||||
* @property {HvacMode[]} [hvac_modes] List of hvac modes to display (auto, heat_cool, heat, cool, dry, fan_only, off).
|
||||
* @property {boolean} [collapsible_controls] Collapse controls when off.
|
||||
*
|
||||
* @see https://github.com/piitaya/lovelace-mushroom/blob/main/docs/cards/climate.md
|
||||
*/
|
||||
export type ClimateCardConfig = LovelaceCardConfig &
|
||||
EntitySharedConfig &
|
||||
AppearanceSharedConfig &
|
||||
ActionsSharedConfig & {
|
||||
show_temperature_control?: boolean;
|
||||
hvac_modes?: HvacMode[];
|
||||
collapsible_controls?: boolean;
|
||||
};
|
||||
@@ -0,0 +1,22 @@
|
||||
import {ActionsSharedConfig} from "../shared/config/actions-config";
|
||||
import {LovelaceCardConfig} from "../../homeassistant/data/lovelace";
|
||||
import {EntitySharedConfig} from "../shared/config/entity-config";
|
||||
import {AppearanceSharedConfig} from "../shared/config/appearance-config";
|
||||
|
||||
/**
|
||||
* Cover Card Config.
|
||||
*
|
||||
* @property {boolean} [show_buttons_control=false] Show buttons to open, close and stop cover.
|
||||
* @property {boolean} [show_position_control=false] Show a slider to control position of the cover.
|
||||
* @property {boolean} [show_tilt_position_control=false] Show a slider to control tilt position of the cover.
|
||||
*
|
||||
* @see https://github.com/piitaya/lovelace-mushroom/blob/main/docs/cards/cover.md
|
||||
*/
|
||||
export type CoverCardConfig = LovelaceCardConfig &
|
||||
EntitySharedConfig &
|
||||
AppearanceSharedConfig &
|
||||
ActionsSharedConfig & {
|
||||
show_buttons_control?: boolean;
|
||||
show_position_control?: boolean;
|
||||
show_tilt_position_control?: boolean;
|
||||
};
|
||||
@@ -0,0 +1,18 @@
|
||||
import {LovelaceCardConfig} from "../../homeassistant/data/lovelace";
|
||||
import {AppearanceSharedConfig} from "../shared/config/appearance-config";
|
||||
import {EntitySharedConfig} from "../shared/config/entity-config";
|
||||
import {ActionsSharedConfig} from "../shared/config/actions-config";
|
||||
|
||||
/**
|
||||
* Entity Card Config.
|
||||
*
|
||||
* @property {string} [icon_color=blue] Custom color for icon when entity is state is active.
|
||||
*
|
||||
* @see https://github.com/piitaya/lovelace-mushroom/blob/main/docs/cards/entity.md
|
||||
*/
|
||||
export type EntityCardConfig = LovelaceCardConfig &
|
||||
EntitySharedConfig &
|
||||
AppearanceSharedConfig &
|
||||
ActionsSharedConfig & {
|
||||
icon_color?: string;
|
||||
};
|
||||
@@ -0,0 +1,24 @@
|
||||
import {ActionsSharedConfig} from "../shared/config/actions-config";
|
||||
import {LovelaceCardConfig} from "../../homeassistant/data/lovelace";
|
||||
import {EntitySharedConfig} from "../shared/config/entity-config";
|
||||
import {AppearanceSharedConfig} from "../shared/config/appearance-config";
|
||||
|
||||
/**
|
||||
* Fan Card Config.
|
||||
*
|
||||
* @property {boolean} [icon_animation=false] Animate the icon when fan is on.
|
||||
* @property {boolean} [show_percentage_control=false] Show a slider to control speed.
|
||||
* @property {boolean} [show_oscillate_control=false] Show a button to control oscillation.
|
||||
* @property {boolean} [icon_animation=false] Animate the icon when fan is on.
|
||||
*
|
||||
* @see https://github.com/piitaya/lovelace-mushroom/blob/main/docs/cards/fan.md
|
||||
*/
|
||||
export type FanCardConfig = LovelaceCardConfig &
|
||||
EntitySharedConfig &
|
||||
AppearanceSharedConfig &
|
||||
ActionsSharedConfig & {
|
||||
icon_animation?: boolean;
|
||||
show_percentage_control?: boolean;
|
||||
show_oscillate_control?: boolean;
|
||||
collapsible_controls?: boolean;
|
||||
};
|
||||
@@ -0,0 +1,29 @@
|
||||
import {ActionsSharedConfig} from "../shared/config/actions-config";
|
||||
import {LovelaceCardConfig} from "../../homeassistant/data/lovelace";
|
||||
import {EntitySharedConfig} from "../shared/config/entity-config";
|
||||
import {AppearanceSharedConfig} from "../shared/config/appearance-config";
|
||||
|
||||
/**
|
||||
* Light Card Config.
|
||||
*
|
||||
* @property {string} [icon_color=blue] Custom color for icon and brightness bar when the lights are on and
|
||||
* use_light_color is false.
|
||||
* @property {boolean} [show_brightness_control=false] Show a slider to control brightness.
|
||||
* @property {boolean} [show_color_temp_control=false] Show a slider to control temperature color.
|
||||
* @property {boolean} [show_color_control=false] Show a slider to control RGB color.
|
||||
* @property {boolean} [collapsible_controls=false] Collapse controls when off.
|
||||
* @property {boolean} [use_light_color=false] Colorize the icon and slider according light temperature or color.
|
||||
*
|
||||
* @see https://github.com/piitaya/lovelace-mushroom/blob/main/docs/cards/light.md
|
||||
*/
|
||||
export type LightCardConfig = LovelaceCardConfig &
|
||||
EntitySharedConfig &
|
||||
AppearanceSharedConfig &
|
||||
ActionsSharedConfig & {
|
||||
icon_color?: string;
|
||||
show_brightness_control?: boolean;
|
||||
show_color_temp_control?: boolean;
|
||||
show_color_control?: boolean;
|
||||
collapsible_controls?: boolean;
|
||||
use_light_color?: boolean;
|
||||
};
|
||||
@@ -0,0 +1,14 @@
|
||||
import {ActionsSharedConfig} from "../shared/config/actions-config";
|
||||
import {LovelaceCardConfig} from "../../homeassistant/data/lovelace";
|
||||
import {EntitySharedConfig} from "../shared/config/entity-config";
|
||||
import {AppearanceSharedConfig} from "../shared/config/appearance-config";
|
||||
|
||||
/**
|
||||
* Lock Card Config.
|
||||
*
|
||||
* @see https://github.com/piitaya/lovelace-mushroom/blob/main/docs/cards/lock.md
|
||||
*/
|
||||
export type LockCardConfig = LovelaceCardConfig &
|
||||
EntitySharedConfig &
|
||||
AppearanceSharedConfig &
|
||||
ActionsSharedConfig;
|
||||
@@ -0,0 +1,45 @@
|
||||
import {ActionsSharedConfig} from "../shared/config/actions-config";
|
||||
import {LovelaceCardConfig} from "../../homeassistant/data/lovelace";
|
||||
import {EntitySharedConfig} from "../shared/config/entity-config";
|
||||
import {AppearanceSharedConfig} from "../shared/config/appearance-config";
|
||||
|
||||
export const MEDIA_LAYER_MEDIA_CONTROLS = [
|
||||
"on_off",
|
||||
"shuffle",
|
||||
"previous",
|
||||
"play_pause_stop",
|
||||
"next",
|
||||
"repeat",
|
||||
] as const;
|
||||
|
||||
export type MediaPlayerMediaControl = (typeof MEDIA_LAYER_MEDIA_CONTROLS)[number];
|
||||
|
||||
export const MEDIA_PLAYER_VOLUME_CONTROLS = [
|
||||
"volume_mute",
|
||||
"volume_set",
|
||||
"volume_buttons",
|
||||
] as const;
|
||||
|
||||
export type MediaPlayerVolumeControl = (typeof MEDIA_PLAYER_VOLUME_CONTROLS)[number];
|
||||
|
||||
/**
|
||||
* Media Player Card Config.
|
||||
*
|
||||
* @property {boolean} [use_media_info=false] Use media info instead of name, state, and icon when media is playing.
|
||||
* @property {boolean} [show_volume_level=false] Show volume level next to media state when media is playing.
|
||||
* @property {MediaPlayerVolumeControl[]} [volume_controls] List of controls to display (volume_mute, volume_set, volume_buttons)
|
||||
* @property {MediaPlayerMediaControl[]} [media_controls] List of controls to display (on_off, shuffle, previous, play_pause_stop, next, repeat)
|
||||
* @property {boolean} [collapsible_controls=false] Collapse controls when off
|
||||
*
|
||||
* @see https://github.com/piitaya/lovelace-mushroom/blob/main/docs/cards/media-player.md
|
||||
*/
|
||||
export type MediaPlayerCardConfig = LovelaceCardConfig &
|
||||
EntitySharedConfig &
|
||||
AppearanceSharedConfig &
|
||||
ActionsSharedConfig & {
|
||||
use_media_info?: boolean;
|
||||
show_volume_level?: boolean;
|
||||
volume_controls?: MediaPlayerVolumeControl[];
|
||||
media_controls?: MediaPlayerMediaControl[];
|
||||
collapsible_controls?: boolean;
|
||||
};
|
||||
@@ -0,0 +1,24 @@
|
||||
import {ActionsSharedConfig} from "../shared/config/actions-config";
|
||||
import {LovelaceCardConfig} from "../../homeassistant/data/lovelace";
|
||||
import {EntitySharedConfig} from "../shared/config/entity-config";
|
||||
import {AppearanceSharedConfig} from "../shared/config/appearance-config";
|
||||
|
||||
export const DISPLAY_MODES = ["slider", "buttons"] as const;
|
||||
|
||||
type DisplayMode = (typeof DISPLAY_MODES)[number];
|
||||
|
||||
/**
|
||||
* Number Card Config.
|
||||
*
|
||||
* @property {string} [icon_color=blue] Custom color for icon when entity state is active.
|
||||
* @property {DisplayMode} [display_mode=slider] Slider or Button controls.
|
||||
*
|
||||
* @see https://github.com/piitaya/lovelace-mushroom/blob/main/docs/cards/number.md
|
||||
*/
|
||||
export type NumberCardConfig = LovelaceCardConfig &
|
||||
EntitySharedConfig &
|
||||
AppearanceSharedConfig &
|
||||
ActionsSharedConfig & {
|
||||
icon_color?: string;
|
||||
display_mode?: DisplayMode;
|
||||
};
|
||||
@@ -0,0 +1,14 @@
|
||||
import {ActionsSharedConfig} from "../shared/config/actions-config";
|
||||
import {LovelaceCardConfig} from "../../homeassistant/data/lovelace";
|
||||
import {EntitySharedConfig} from "../shared/config/entity-config";
|
||||
import {AppearanceSharedConfig} from "../shared/config/appearance-config";
|
||||
|
||||
/**
|
||||
* Person Card Config.
|
||||
*
|
||||
* @see https://github.com/piitaya/lovelace-mushroom/blob/main/docs/cards/person.md
|
||||
*/
|
||||
export type PersonCardConfig = LovelaceCardConfig &
|
||||
EntitySharedConfig &
|
||||
AppearanceSharedConfig &
|
||||
ActionsSharedConfig;
|
||||
@@ -0,0 +1,36 @@
|
||||
import {ActionsSharedConfig} from "../shared/config/actions-config";
|
||||
import {LovelaceCardConfig} from "../../homeassistant/data/lovelace";
|
||||
import {AppearanceSharedConfig} from "../shared/config/appearance-config";
|
||||
|
||||
/**
|
||||
* Template Card Config.
|
||||
*
|
||||
* @property {string} [entity]
|
||||
* @property {string} [icon] Icon to render. May contain templates.
|
||||
* @property {string} [icon_color] Icon color to render. May contain templates.
|
||||
* @property {string} [primary] Primary info to render. May contain templates.
|
||||
* @property {string} [secondary] Secondary info to render. May contain templates.
|
||||
* @property {string} [badge_icon] Badge icon to render. May contain templates.
|
||||
* @property {string} [badge_color] Badge icon color to render. May contain templates.
|
||||
* @property {string} [picture] Picture to render. May contain templates.
|
||||
* @property {boolean} [multiline_secondary] Enables support for multiline text for the secondary info.
|
||||
* @property {string | string[]} [entity_id] Only reacts to the state changes of these entities.
|
||||
* This can be used if the automatic analysis fails to find all relevant
|
||||
* entities.
|
||||
*
|
||||
* @see https://github.com/piitaya/lovelace-mushroom/blob/main/docs/cards/template.md
|
||||
*/
|
||||
export type TemplateCardConfig = LovelaceCardConfig &
|
||||
AppearanceSharedConfig &
|
||||
ActionsSharedConfig & {
|
||||
entity?: string;
|
||||
icon?: string;
|
||||
icon_color?: string;
|
||||
primary?: string;
|
||||
secondary?: string;
|
||||
badge_icon?: string;
|
||||
badge_color?: string;
|
||||
picture?: string;
|
||||
multiline_secondary?: boolean;
|
||||
entity_id?: string | string[];
|
||||
};
|
||||
@@ -0,0 +1,21 @@
|
||||
import {ActionConfig, LovelaceCardConfig} from "../../homeassistant/data/lovelace";
|
||||
|
||||
/**
|
||||
* Title Card Config.
|
||||
*
|
||||
* @property {string} [title] Title to render. May contain templates.
|
||||
* @property {string} [subtitle] Subtitle to render. May contain templates.
|
||||
* @property {ActionConfig} [title_tap_action=none] Home assistant action to perform on title tap.
|
||||
* @property {ActionConfig} [subtitle_tap_action=none] Home assistant action to perform on subtitle tap.
|
||||
*
|
||||
* @see https://github.com/piitaya/lovelace-mushroom/blob/main/docs/cards/title.md
|
||||
*/
|
||||
export interface TitleCardConfig extends LovelaceCardConfig {
|
||||
title?: string;
|
||||
subtitle?: string;
|
||||
alignment?: string;
|
||||
title_tap_action?: ActionConfig;
|
||||
subtitle_tap_action?: ActionConfig;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
import {ActionsSharedConfig} from "../shared/config/actions-config";
|
||||
import {LovelaceCardConfig} from "../../homeassistant/data/lovelace";
|
||||
import {EntitySharedConfig} from "../shared/config/entity-config";
|
||||
import {AppearanceSharedConfig} from "../shared/config/appearance-config";
|
||||
|
||||
export const VACUUM_COMMANDS = [
|
||||
"on_off",
|
||||
"start_pause",
|
||||
"stop",
|
||||
"locate",
|
||||
"clean_spot",
|
||||
"return_home",
|
||||
] as const;
|
||||
|
||||
export type VacuumCommand = (typeof VACUUM_COMMANDS)[number];
|
||||
|
||||
/**
|
||||
* Vacuum Card Config.
|
||||
*
|
||||
* @param {boolean} icon_animation Animate the icon when vacuum is cleaning.
|
||||
* @param {VacuumCommand[]} commands List of commands to display (start_pause, stop, locate, clean_spot, return_home).
|
||||
*
|
||||
* @see https://github.com/piitaya/lovelace-mushroom/blob/main/docs/cards/vacuum.md
|
||||
*/
|
||||
export type VacuumCardConfig = LovelaceCardConfig &
|
||||
EntitySharedConfig &
|
||||
AppearanceSharedConfig &
|
||||
ActionsSharedConfig & {
|
||||
icon_animation?: boolean;
|
||||
commands?: VacuumCommand[];
|
||||
};
|
||||
@@ -0,0 +1,7 @@
|
||||
import {ActionConfig} from "../../../homeassistant/data/lovelace";
|
||||
|
||||
export type ActionsSharedConfig = {
|
||||
tap_action?: ActionConfig;
|
||||
hold_action?: ActionConfig;
|
||||
double_tap_action?: ActionConfig;
|
||||
};
|
||||
@@ -0,0 +1,13 @@
|
||||
import {boolean, enums, Infer, object, optional} from "superstruct";
|
||||
import {layoutStruct} from "./utils/layout";
|
||||
import {ICON_TYPES, INFOS} from "./utils/info";
|
||||
|
||||
export const appearanceSharedConfigStruct = object({
|
||||
layout: optional(layoutStruct),
|
||||
fill_container: optional(boolean()),
|
||||
primary_info: optional(enums(INFOS)),
|
||||
secondary_info: optional(enums(INFOS)),
|
||||
icon_type: optional(enums(ICON_TYPES)),
|
||||
});
|
||||
|
||||
export type AppearanceSharedConfig = Infer<typeof appearanceSharedConfigStruct>;
|
||||
@@ -0,0 +1,9 @@
|
||||
import {Infer, object, optional, string} from "superstruct";
|
||||
|
||||
export const entitySharedConfigStruct = object({
|
||||
entity: optional(string()),
|
||||
name: optional(string()),
|
||||
icon: optional(string()),
|
||||
});
|
||||
|
||||
export type EntitySharedConfig = Infer<typeof entitySharedConfigStruct>;
|
||||
@@ -0,0 +1,2 @@
|
||||
export const INFOS = ["name", "state", "last-changed", "last-updated", "none"] as const;
|
||||
export const ICON_TYPES = ["icon", "entity-picture", "none"] as const;
|
||||
@@ -0,0 +1,3 @@
|
||||
import {literal, union} from "superstruct";
|
||||
|
||||
export const layoutStruct = union([literal("horizontal"), literal("vertical"), literal("default")]);
|
||||
@@ -0,0 +1,2 @@
|
||||
export const INFOS = ["name", "state", "last-changed", "last-updated", "none"] as const;
|
||||
export type Info = (typeof INFOS)[number];
|
||||
@@ -0,0 +1,202 @@
|
||||
import {ActionConfig} from "../../../../homeassistant/data/lovelace";
|
||||
import {Info} from "../../info";
|
||||
|
||||
/**
|
||||
* Action Chip Config
|
||||
*
|
||||
* @property {"action"} type Type of the chip.
|
||||
* @property {string} [icon] Custom icon.
|
||||
* @property {string} [icon_color] Custom color for icon.
|
||||
* @property {ActionConfig} [tap_action] Home assistant action to perform on tap.
|
||||
* @property {ActionConfig} [hold_action] Home assistant action to perform on hold.
|
||||
* @property {ActionConfig} [double_tap_action] Home assistant action to perform on double_tap.
|
||||
*/
|
||||
export type ActionChipConfig = {
|
||||
type: "action";
|
||||
icon?: string;
|
||||
icon_color?: string;
|
||||
tap_action?: ActionConfig;
|
||||
hold_action?: ActionConfig;
|
||||
double_tap_action?: ActionConfig;
|
||||
};
|
||||
|
||||
/**
|
||||
* Alarm Control Panel Chip Config
|
||||
*
|
||||
* @property {"alarm-control-panel"} type Type of the chip.
|
||||
* @property {string} [entity] Entity.
|
||||
* @property {string} [name] Custom name.
|
||||
* @property {string} [content_info] Custom content.
|
||||
* @property {string} [icon] Custom icon.
|
||||
* @property {string} [icon_color] Custom color for icon.
|
||||
* @property {ActionConfig} [tap_action] Home assistant action to perform on tap.
|
||||
* @property {ActionConfig} [hold_action] Home assistant action to perform on hold.
|
||||
* @property {ActionConfig} [double_tap_action] Home assistant action to perform on double_tap.
|
||||
*/
|
||||
export type AlarmControlPanelChipConfig = {
|
||||
type: "alarm-control-panel";
|
||||
entity?: string;
|
||||
name?: string;
|
||||
content_info?: Info;
|
||||
icon?: string;
|
||||
icon_color?: string;
|
||||
tap_action?: ActionConfig;
|
||||
hold_action?: ActionConfig;
|
||||
double_tap_action?: ActionConfig;
|
||||
};
|
||||
|
||||
/**
|
||||
* Back Chip Config
|
||||
*
|
||||
* @property {"back"} type Type of the chip.
|
||||
* @property {string} [icon] Custom icon.
|
||||
*/
|
||||
export type BackChipConfig = {
|
||||
type: "back";
|
||||
icon?: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* Entity Chip Config
|
||||
*
|
||||
* @property {"entity"} type Type of the chip.
|
||||
* @property {string} [entity] Entity.
|
||||
* @property {string} [name] Custom name.
|
||||
* @property {string} [content_info] Custom content.
|
||||
* @property {string} [icon] Custom icon.
|
||||
* @property {string} [icon_color] Custom color for icon.
|
||||
* @property {boolean} [use_entity_picture]
|
||||
* @property {ActionConfig} [tap_action] Home assistant action to perform on tap.
|
||||
* @property {ActionConfig} [hold_action] Home assistant action to perform on hold.
|
||||
* @property {ActionConfig} [double_tap_action] Home assistant action to perform on double_tap.
|
||||
*/
|
||||
export type EntityChipConfig = {
|
||||
type: "entity";
|
||||
entity?: string;
|
||||
name?: string;
|
||||
content_info?: Info;
|
||||
icon?: string;
|
||||
icon_color?: string;
|
||||
use_entity_picture?: boolean;
|
||||
tap_action?: ActionConfig;
|
||||
hold_action?: ActionConfig;
|
||||
double_tap_action?: ActionConfig;
|
||||
};
|
||||
|
||||
/**
|
||||
* Menu Chip Config
|
||||
*
|
||||
* @property {"menu"} type Type of the chip.
|
||||
* @property {string} [icon] Custom icon.
|
||||
*/
|
||||
export type MenuChipConfig = {
|
||||
type: "menu";
|
||||
icon?: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* Weather Chip Config
|
||||
*
|
||||
* @property {"weather"} type Type of the chip.
|
||||
* @property {string} [entity] Entity.
|
||||
* @property {ActionConfig} [tap_action] Home assistant action to perform on tap.
|
||||
* @property {ActionConfig} [hold_action] Home assistant action to perform on hold.
|
||||
* @property {ActionConfig} [double_tap_action] Home assistant action to perform on double_tap.
|
||||
* @property {boolean} [show_temperature] Show the temperature.
|
||||
* @property {boolean} [show_conditions] Show the conditions.
|
||||
*/
|
||||
export type WeatherChipConfig = {
|
||||
type: "weather";
|
||||
entity?: string;
|
||||
tap_action?: ActionConfig;
|
||||
hold_action?: ActionConfig;
|
||||
double_tap_action?: ActionConfig;
|
||||
show_temperature?: boolean;
|
||||
show_conditions?: boolean;
|
||||
};
|
||||
|
||||
/**
|
||||
* Template Chip Config
|
||||
*
|
||||
* @property {"template"} type Type of the chip.
|
||||
* @property {string} [entity] Entity.
|
||||
* @property {ActionConfig} [tap_action] Home assistant action to perform on tap.
|
||||
* @property {ActionConfig} [hold_action] Home assistant action to perform on hold.
|
||||
* @property {ActionConfig} [double_tap_action] Home assistant action to perform on double_tap.
|
||||
* @property {string} [content]
|
||||
* @property {string} [icon] Custom icon.
|
||||
* @property {string} [icon_color] Custom color for icon.
|
||||
* @property {string} [picture]
|
||||
* @property {string | string[]} [entity_id]
|
||||
*/
|
||||
export type TemplateChipConfig = {
|
||||
type: "template";
|
||||
entity?: string;
|
||||
hold_action?: ActionConfig;
|
||||
tap_action?: ActionConfig;
|
||||
double_tap_action?: ActionConfig;
|
||||
content?: string;
|
||||
icon?: string;
|
||||
icon_color?: string;
|
||||
picture?: string;
|
||||
entity_id?: string | string[];
|
||||
};
|
||||
|
||||
/**
|
||||
* Conditional Chip Config
|
||||
*
|
||||
* @property {"conditional"} type Type of the chip.
|
||||
* @property {LovelaceChipConfig} [chip] A chip configuration.
|
||||
* @property {[]} conditions
|
||||
*/
|
||||
export interface ConditionalChipConfig {
|
||||
type: "conditional";
|
||||
chip?: LovelaceChipConfig;
|
||||
conditions: any[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Light Chip Config
|
||||
*
|
||||
* @property {"light"} type Type of the chip.
|
||||
* @property {string} [entity] Entity.
|
||||
* @property {string} [name]
|
||||
* @property {Info} [content_info]
|
||||
* @property {string} [icon] Custom icon.
|
||||
* @property {boolean} [use_light_color] Colorize the icon and slider according light temperature or color.
|
||||
* @property {ActionConfig} [tap_action] Home assistant action to perform on tap.
|
||||
* @property {ActionConfig} [hold_action] Home assistant action to perform on hold.
|
||||
* @property {ActionConfig} [double_tap_action] Home assistant action to perform on double_tap.
|
||||
*/
|
||||
export type LightChipConfig = {
|
||||
type: "light";
|
||||
entity?: string;
|
||||
name?: string;
|
||||
content_info?: Info;
|
||||
icon?: string;
|
||||
use_light_color?: boolean;
|
||||
hold_action?: ActionConfig;
|
||||
tap_action?: ActionConfig;
|
||||
double_tap_action?: ActionConfig;
|
||||
};
|
||||
|
||||
/**
|
||||
* Spacer Chip Config
|
||||
*
|
||||
* @property {"spacer"} type Type of the chip.
|
||||
*/
|
||||
export type SpacerChipConfig = {
|
||||
type: "spacer";
|
||||
};
|
||||
|
||||
export type LovelaceChipConfig =
|
||||
| ActionChipConfig
|
||||
| AlarmControlPanelChipConfig
|
||||
| BackChipConfig
|
||||
| EntityChipConfig
|
||||
| MenuChipConfig
|
||||
| WeatherChipConfig
|
||||
| TemplateChipConfig
|
||||
| ConditionalChipConfig
|
||||
| LightChipConfig
|
||||
| SpacerChipConfig;
|
||||
@@ -0,0 +1,70 @@
|
||||
import {LovelaceCardConfig} from "../homeassistant/data/lovelace";
|
||||
import {TitleCardConfig} from "../lovelace-mushroom/cards/title-card-config";
|
||||
import {EntitySharedConfig} from "../lovelace-mushroom/shared/config/entity-config";
|
||||
import {AppearanceSharedConfig} from "../lovelace-mushroom/shared/config/appearance-config";
|
||||
import {ActionsSharedConfig} from "../lovelace-mushroom/shared/config/actions-config";
|
||||
import {TemplateCardConfig} from "../lovelace-mushroom/cards/template-card-config";
|
||||
import {EntityCardConfig} from "../lovelace-mushroom/cards/entity-card-config";
|
||||
import {PictureEntityCardConfig} from "../homeassistant/panels/lovelave/cards/types";
|
||||
import {ClimateCardConfig} from "../lovelace-mushroom/cards/climate-card-config";
|
||||
import {CoverCardConfig} from "../lovelace-mushroom/cards/cover-card-config";
|
||||
import {FanCardConfig} from "../lovelace-mushroom/cards/fan-card-config";
|
||||
import {AreaCardConfig} from "../homeassistant/lovelace/cards/types";
|
||||
import {LightCardConfig} from "../lovelace-mushroom/cards/light-card-config";
|
||||
import {LockCardConfig} from "../lovelace-mushroom/cards/lock-card-config";
|
||||
import {MediaPlayerCardConfig} from "../lovelace-mushroom/cards/media-player-card-config";
|
||||
import {NumberCardConfig} from "../lovelace-mushroom/cards/number-card-config";
|
||||
import {PersonCardConfig} from "../lovelace-mushroom/cards/person-card-config";
|
||||
import {VacuumCardConfig} from "../lovelace-mushroom/cards/vacuum-card-config";
|
||||
|
||||
export namespace cards {
|
||||
/**
|
||||
* Abstract Card Config.
|
||||
*/
|
||||
export type AbstractCardConfig = LovelaceCardConfig &
|
||||
EntitySharedConfig &
|
||||
AppearanceSharedConfig &
|
||||
ActionsSharedConfig;
|
||||
|
||||
/**
|
||||
* Controller Card Config.
|
||||
*
|
||||
* @property {boolean} [showControls=true] False to hide controls.
|
||||
* @property {string} [iconOn] Icon to show for switching entities from off state.
|
||||
* @property {string} [iconOff] Icon to show for switching entities to off state.
|
||||
* @property {string} [onService=none] Service to call for switching entities from off state.
|
||||
* @property {string} [offService=none] Service to call for switching entities to off state.
|
||||
*/
|
||||
export interface ControllerCardConfig extends TitleCardConfig {
|
||||
type: "mushroom-title-card",
|
||||
showControls?: boolean;
|
||||
iconOn?: string;
|
||||
iconOff?: string;
|
||||
onService?: string;
|
||||
offService?: string;
|
||||
}
|
||||
|
||||
export type AreaCardOptions = Omit<AreaCardConfig, "type">;
|
||||
export type ClimateCardOptions = Omit<ClimateCardConfig, "type">;
|
||||
export type ControllerCardOptions = Omit<ControllerCardConfig, "type">;
|
||||
export type CoverCardOptions = Omit<CoverCardConfig, "type">;
|
||||
export type EntityCardOptions = Omit<EntityCardConfig, "type">;
|
||||
export type FanCardOptions = Omit<FanCardConfig, "type">;
|
||||
export type LightCardOptions = Omit<LightCardConfig, "type">;
|
||||
export type LockCardOptions = Omit<LockCardConfig, "type">;
|
||||
export type MediaPlayerCardOptions = Omit<MediaPlayerCardConfig, "type">;
|
||||
export type NumberCardOptions = Omit<NumberCardConfig, "type">;
|
||||
export type PersonCardOptions = Omit<PersonCardConfig, "type">;
|
||||
export type PictureEntityCardOptions = Omit<PictureEntityCardConfig, "type">;
|
||||
export type TemplateCardOptions = Omit<TemplateCardConfig, "type">;
|
||||
export type VacuumCardOptions = Omit<VacuumCardConfig, "type">;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
import {TemplateChipConfig, WeatherChipConfig} from "../lovelace-mushroom/utils/lovelace/chip/types";
|
||||
|
||||
export namespace chips {
|
||||
export type TemplateChipOptions = Omit<TemplateChipConfig, "type">;
|
||||
export type WeatherChipOptions = Omit<WeatherChipConfig, "type">;
|
||||
}
|
||||
@@ -0,0 +1,214 @@
|
||||
import {
|
||||
CallServiceActionConfig,
|
||||
LovelaceCardConfig,
|
||||
LovelaceConfig,
|
||||
LovelaceViewConfig
|
||||
} from "../homeassistant/data/lovelace";
|
||||
import {HomeAssistant} from "../homeassistant/types";
|
||||
import {AreaRegistryEntry} from "../homeassistant/data/area_registry";
|
||||
import {cards} from "./cards";
|
||||
import {EntityRegistryEntry} from "../homeassistant/data/entity_registry";
|
||||
import {LovelaceChipConfig} from "../lovelace-mushroom/utils/lovelace/chip/types";
|
||||
import {HassServiceTarget} from "home-assistant-js-websocket";
|
||||
|
||||
export namespace generic {
|
||||
/**
|
||||
* An entry out of a Home Assistant Register.
|
||||
*/
|
||||
export type RegistryEntry =
|
||||
| AreaRegistryEntry
|
||||
| DataTransfer
|
||||
| EntityRegistryEntry
|
||||
|
||||
/**
|
||||
* View Entity.
|
||||
*
|
||||
* @property {number} [order] Ordering position of the entity in the list of available views.
|
||||
* @property {boolean} [hidden] True if the entity should be hidden from the dashboard.
|
||||
*/
|
||||
export interface ViewConfig extends LovelaceViewConfig {
|
||||
hidden?: boolean;
|
||||
order?: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Domain Configuration.
|
||||
*
|
||||
* @property {number} [order] Ordering position of the entity in the list of available views.
|
||||
* @property {boolean} [hidden] True if the entity should be hidden from the dashboard.
|
||||
*/
|
||||
export interface DomainConfig extends Partial<cards.ControllerCardConfig> {
|
||||
hidden?: boolean;
|
||||
order?: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Dashboard Information Object.
|
||||
*
|
||||
* Home Assistant passes this object to the Dashboard Generator method.
|
||||
*
|
||||
* @property {LovelaceConfig} config Dashboard configuration.
|
||||
* @property {HomeAssistant} hass The Home Assistant object.
|
||||
*
|
||||
* @see https://developers.home-assistant.io/docs/frontend/custom-ui/custom-strategy/#dashboard-strategies
|
||||
*/
|
||||
export interface DashBoardInfo {
|
||||
config?: LovelaceConfig & {
|
||||
strategy: {
|
||||
options?: StrategyConfig
|
||||
}
|
||||
};
|
||||
hass: HomeAssistant;
|
||||
}
|
||||
|
||||
/**
|
||||
* View Information Object.
|
||||
*
|
||||
* Home Assistant passes this object to the View Generator method.
|
||||
*
|
||||
* @property {LovelaceViewConfig} view View configuration.
|
||||
* @property {LovelaceConfig} config Dashboard configuration.
|
||||
* @property {HomeAssistant} hass The Home Assistant object.
|
||||
*
|
||||
* @see https://developers.home-assistant.io/docs/frontend/custom-ui/custom-strategy/#view-strategies
|
||||
*/
|
||||
export interface ViewInfo {
|
||||
view: LovelaceViewConfig & {
|
||||
strategy?: {
|
||||
options?: StrategyConfig & { area: StrategyArea }
|
||||
}
|
||||
};
|
||||
config: LovelaceConfig
|
||||
hass: HomeAssistant;
|
||||
}
|
||||
|
||||
/**
|
||||
* Strategy Configuration.
|
||||
*
|
||||
* @property {Object.<AreaRegistryEntry>} areas List of areas.
|
||||
* @property {Object.<CustomCardConfig>} [card_options] Card options for entities.
|
||||
* @property {chips} [chips] List of chips to show in the Home view.
|
||||
* @property {boolean} [debug] Set to true for more verbose debugging info.
|
||||
* @property {Object.<DomainConfig>} domains List of domains.
|
||||
* @property {object[]} [extra_cards] List of cards to show below room cards.
|
||||
* @property {object[]} [extra_views] List of views to add to the dashboard.
|
||||
* @property {object[]} [quick_access_cards] List of cards to show between welcome card and rooms cards.
|
||||
* @property {Object.<ViewConfig>} views List of views.
|
||||
*/
|
||||
export interface StrategyConfig {
|
||||
areas: { [k: string]: StrategyArea };
|
||||
card_options?: { [k: string]: CustomCardConfig };
|
||||
chips?: Chips;
|
||||
debug: boolean;
|
||||
domains: { [k: string]: DomainConfig };
|
||||
extra_cards?: LovelaceCardConfig[];
|
||||
extra_views?: ViewConfig[];
|
||||
home_view: {
|
||||
hidden: HiddenSectionType[]
|
||||
}
|
||||
quick_access_cards?: LovelaceCardConfig[];
|
||||
views: { [k: string]: ViewConfig };
|
||||
}
|
||||
|
||||
const hiddenSectionList = ["chips", "persons", "greeting", "areas", "areasTitle"] as const;
|
||||
export type HiddenSectionType = typeof hiddenSectionList[number];
|
||||
|
||||
/**
|
||||
* Represents the default configuration for a strategy.
|
||||
*/
|
||||
export interface StrategyDefaults extends StrategyConfig {
|
||||
areas: {
|
||||
undisclosed: StrategyArea & {
|
||||
area_id: "undisclosed",
|
||||
},
|
||||
[k: string]: StrategyArea,
|
||||
},
|
||||
domains: {
|
||||
default: DomainConfig,
|
||||
[k: string]: DomainConfig,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Strategy Area.
|
||||
*
|
||||
* @property {number} [order] Ordering position of the area in the list of available areas.
|
||||
* @property {boolean} [hidden] True if the entity should be hidden from the dashboard.
|
||||
* @property {object[]} [extra_cards] An array of card configurations.
|
||||
* The configured cards are added to the dashboard.
|
||||
* @property {string} [type=default] The type of area card.
|
||||
*/
|
||||
export interface StrategyArea extends AreaRegistryEntry {
|
||||
order?: number;
|
||||
hidden?: boolean;
|
||||
extra_cards?: LovelaceCardConfig[];
|
||||
type?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* A list of chips to show in the Home view.
|
||||
*
|
||||
* @property {boolean} light_count Chip to display the number of lights on.
|
||||
* @property {boolean} fan_count Chip to display the number of fans on.
|
||||
* @property {boolean} cover_count Chip to display the number of unclosed covers.
|
||||
* @property {boolean} switch_count Chip to display the number of switches on.
|
||||
* @property {boolean} climate_count Chip to display the number of climates which are not off.
|
||||
* @property {string} weather_entity Entity ID for the weather chip to use, accepts `weather.` only.
|
||||
* @property {object[]} extra_chips List of extra chips.
|
||||
*/
|
||||
export interface Chips {
|
||||
extra_chips: LovelaceChipConfig[];
|
||||
|
||||
light_count: boolean;
|
||||
fan_count: boolean;
|
||||
cover_count: boolean;
|
||||
switch_count: boolean;
|
||||
climate_count: boolean;
|
||||
weather_entity: string;
|
||||
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom Card Configuration for an entity.
|
||||
*
|
||||
* @property {boolean} hidden True if the entity should be hidden from the dashboard.
|
||||
*/
|
||||
export interface CustomCardConfig extends LovelaceCardConfig {
|
||||
hidden?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Area Filter Context.
|
||||
*
|
||||
* @property {AreaRegistryEntry} area Area Entity.
|
||||
* @property {string[]} areaDeviceIds The id of devices which are linked to the area entity.
|
||||
* @property {string} domain Domain of the entity.
|
||||
* Example: `light`.
|
||||
*/
|
||||
export interface AreaFilterContext {
|
||||
area: AreaRegistryEntry;
|
||||
areaDeviceIds: string[];
|
||||
domain: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the given object is an instance of CallServiceActionConfig.
|
||||
*
|
||||
* @param {any} obj - The object to be checked.
|
||||
* @return {boolean} - Returns true if the object is an instance of CallServiceActionConfig, otherwise false.
|
||||
*/
|
||||
export function isCallServiceActionConfig(obj: any): obj is CallServiceActionConfig {
|
||||
return obj && obj.action === "call-service" && ["action", "service"].every(key => key in obj);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the given object is an instance of HassServiceTarget.
|
||||
*
|
||||
* @param {any} obj - The object to check.
|
||||
* @return {boolean} - True if the object is an instance of HassServiceTarget, false otherwise.
|
||||
*/
|
||||
export function isCallServiceActionTarget(obj: any): obj is HassServiceTarget {
|
||||
return obj && ["entity_id", "device_id", "area_id"].some(key => key in obj);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
import {cards} from "./cards";
|
||||
import {LovelaceViewConfig} from "../homeassistant/data/lovelace";
|
||||
|
||||
export namespace views {
|
||||
/**
|
||||
* Options for the extended View class.
|
||||
*
|
||||
* @property {cards.ControllerCardConfig} [controllerCardOptions] Options for the Controller card.
|
||||
*/
|
||||
export interface ViewConfig extends LovelaceViewConfig {
|
||||
controllerCardOptions?: cards.ControllerCardOptions;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,131 +0,0 @@
|
||||
import {Helper} from "../Helper";
|
||||
import {TitleCard} from "../cards/TitleCard";
|
||||
|
||||
/**
|
||||
* Abstract View Class.
|
||||
*
|
||||
* To create a new view, extend the new class with this one.
|
||||
*
|
||||
* @class
|
||||
* @abstract
|
||||
*/
|
||||
class AbstractView {
|
||||
/**
|
||||
* Options for creating a view.
|
||||
*
|
||||
* @type {abstractOptions}
|
||||
*/
|
||||
options = {
|
||||
title: null,
|
||||
path: null,
|
||||
icon: "mdi:view-dashboard",
|
||||
subview: false,
|
||||
};
|
||||
|
||||
/**
|
||||
* A card to switch all entities in the view.
|
||||
*
|
||||
* @type {Object}
|
||||
*/
|
||||
viewTitleCard;
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @throws {Error} If trying to instantiate this class.
|
||||
* @throws {Error} If the Helper module isn't initialized.
|
||||
*/
|
||||
constructor() {
|
||||
if (this.constructor === AbstractView) {
|
||||
throw new Error("Abstract classes can't be instantiated.");
|
||||
}
|
||||
|
||||
if (!Helper.isInitialized()) {
|
||||
throw new Error("The Helper module must be initialized before using this one.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Merge the default options of this class and the custom options into the options of the parent class.
|
||||
*
|
||||
* @param {Object} [defaultOptions={}] Default options for the card.
|
||||
* @param {Object} [customOptions={}] Custom Options for the card.
|
||||
*/
|
||||
mergeOptions(defaultOptions, customOptions) {
|
||||
this.options = {
|
||||
...defaultOptions,
|
||||
...customOptions,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the cards to include in the view.
|
||||
*
|
||||
* @return {Object[] | Promise} An array of card objects.
|
||||
*/
|
||||
async createViewCards() {
|
||||
/** @type Object[] */
|
||||
const viewCards = [];
|
||||
|
||||
// Create cards for each area.
|
||||
for (const area of Helper.areas) {
|
||||
const areaCards = [];
|
||||
const entities = Helper.getDeviceEntities(area, this["domain"]);
|
||||
const className = Helper.sanitizeClassName(this["domain"] + "Card");
|
||||
const cardModule = await import(`../cards/${className}`);
|
||||
|
||||
// Create a card for each domain-entity of the current area.
|
||||
for (const entity of entities) {
|
||||
let cardOptions = Helper.strategyOptions.card_options?.[entity.entity_id] ?? {};
|
||||
let deviceOptions = Helper.strategyOptions.card_options?.[entity.device_id] ?? {};
|
||||
|
||||
if (cardOptions.hidden || deviceOptions.hidden) {
|
||||
continue;
|
||||
}
|
||||
|
||||
areaCards.push(new cardModule[className](entity, cardOptions).getCard());
|
||||
}
|
||||
|
||||
if (areaCards.length) {
|
||||
// Create a Title card for the current area if it has entities.
|
||||
areaCards.unshift(new TitleCard(
|
||||
[area],
|
||||
{
|
||||
title: area.name,
|
||||
...this.options["titleCard"],
|
||||
},
|
||||
this["domain"],
|
||||
).createCard());
|
||||
|
||||
viewCards.push({
|
||||
type: "vertical-stack",
|
||||
cards: areaCards,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
viewCards.unshift(viewCards.length ? this.viewTitleCard : {
|
||||
type: "custom:mushroom-title-card",
|
||||
title: "No Entities Available",
|
||||
subtitle: "They're either hidden by the configuration or by Home Assistant.",
|
||||
});
|
||||
|
||||
return viewCards;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a view object.
|
||||
*
|
||||
* The view includes the cards which are created by method createViewCards().
|
||||
*
|
||||
* @returns {viewOptions & {cards: Object[]}} The view object.
|
||||
*/
|
||||
async getView() {
|
||||
return {
|
||||
...this.options,
|
||||
cards: await this.createViewCards(),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export {AbstractView};
|
||||
@@ -0,0 +1,158 @@
|
||||
import {Helper} from "../Helper";
|
||||
import {ControllerCard} from "../cards/ControllerCard";
|
||||
import {StackCardConfig} from "../types/homeassistant/lovelace/cards/types";
|
||||
import {LovelaceCardConfig, LovelaceViewConfig} from "../types/homeassistant/data/lovelace";
|
||||
import {cards} from "../types/strategy/cards";
|
||||
import {TitleCardConfig} from "../types/lovelace-mushroom/cards/title-card-config";
|
||||
import {HassServiceTarget} from "home-assistant-js-websocket";
|
||||
import abstractCardConfig = cards.AbstractCardConfig;
|
||||
|
||||
/**
|
||||
* Abstract View Class.
|
||||
*
|
||||
* To create a new view, extend the new class with this one.
|
||||
*
|
||||
* @class
|
||||
* @abstract
|
||||
*/
|
||||
abstract class AbstractView {
|
||||
/**
|
||||
* Configuration of the view.
|
||||
*
|
||||
* @type {LovelaceViewConfig}
|
||||
*/
|
||||
config: LovelaceViewConfig = {
|
||||
icon: "mdi:view-dashboard",
|
||||
subview: false,
|
||||
};
|
||||
|
||||
/**
|
||||
* A card to switch all entities in the view.
|
||||
*
|
||||
* @type {StackCardConfig}
|
||||
*/
|
||||
viewControllerCard: StackCardConfig = {
|
||||
cards: [],
|
||||
type: "",
|
||||
};
|
||||
|
||||
/**
|
||||
* The domain of which we operate the devices.
|
||||
*
|
||||
* @private
|
||||
* @readonly
|
||||
*/
|
||||
readonly #domain?: string;
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param {string} [domain] The domain which the view is representing.
|
||||
*
|
||||
* @throws {Error} If trying to instantiate this class.
|
||||
* @throws {Error} If the Helper module isn't initialized.
|
||||
*/
|
||||
protected constructor(domain: string = "") {
|
||||
if (!Helper.isInitialized()) {
|
||||
throw new Error("The Helper module must be initialized before using this one.");
|
||||
}
|
||||
|
||||
if (domain) {
|
||||
this.#domain = domain;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the cards to include in the view.
|
||||
*
|
||||
* @return {Promise<(StackCardConfig | TitleCardConfig)[]>} An array of card objects.
|
||||
*/
|
||||
async createViewCards(): Promise<(StackCardConfig | TitleCardConfig)[]> {
|
||||
const viewCards: LovelaceCardConfig[] = [];
|
||||
|
||||
// Create cards for each area.
|
||||
for (const area of Helper.areas) {
|
||||
const areaCards: abstractCardConfig[] = [];
|
||||
const entities = Helper.getDeviceEntities(area, this.#domain ?? "");
|
||||
const className = Helper.sanitizeClassName(this.#domain + "Card");
|
||||
const cardModule = await import(`../cards/${className}`);
|
||||
|
||||
// Set the target for controller cards to the current area.
|
||||
let target: HassServiceTarget = {
|
||||
area_id: [area.area_id],
|
||||
};
|
||||
|
||||
// Set the target for controller cards to entities without an area.
|
||||
if (area.area_id === "undisclosed") {
|
||||
target = {
|
||||
entity_id: entities.map(entity => entity.entity_id),
|
||||
}
|
||||
}
|
||||
|
||||
// Create a card for each domain-entity of the current area.
|
||||
for (const entity of entities) {
|
||||
let cardOptions = Helper.strategyOptions.card_options?.[entity.entity_id];
|
||||
let deviceOptions = Helper.strategyOptions.card_options?.[entity.device_id ?? "null"];
|
||||
|
||||
if (cardOptions?.hidden || deviceOptions?.hidden) {
|
||||
continue;
|
||||
}
|
||||
|
||||
areaCards.push(new cardModule[className](entity, cardOptions).getCard());
|
||||
}
|
||||
|
||||
// Vertical stack the area cards if it has entities.
|
||||
if (areaCards.length) {
|
||||
const titleCardOptions = ("controllerCardOptions" in this.config) ? this.config.controllerCardOptions : {};
|
||||
|
||||
// Create and insert a Controller card.
|
||||
areaCards.unshift(new ControllerCard(target, Object.assign({title: area.name}, titleCardOptions)).createCard());
|
||||
|
||||
viewCards.push({
|
||||
type: "vertical-stack",
|
||||
cards: areaCards,
|
||||
} as StackCardConfig);
|
||||
}
|
||||
}
|
||||
|
||||
// Add a Controller Card for all the entities in the view.
|
||||
if (viewCards.length) {
|
||||
viewCards.unshift(this.viewControllerCard);
|
||||
}
|
||||
|
||||
return viewCards;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a view object.
|
||||
*
|
||||
* The view includes the cards which are created by method createViewCards().
|
||||
*
|
||||
* @returns {Promise<LovelaceViewConfig>} The view object.
|
||||
*/
|
||||
async getView(): Promise<LovelaceViewConfig> {
|
||||
return {
|
||||
...this.config,
|
||||
cards: await this.createViewCards(),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a target of entity IDs for the given domain.
|
||||
*
|
||||
* @param {string} domain - The target domain to retrieve entity IDs from.
|
||||
* @return {HassServiceTarget} - A target for a service call.
|
||||
*/
|
||||
targetDomain(domain: string): HassServiceTarget {
|
||||
return {
|
||||
entity_id: Helper.entities.filter(
|
||||
entity =>
|
||||
entity.entity_id.startsWith(domain + ".")
|
||||
&& !entity.hidden_by
|
||||
&& !Helper.strategyOptions.card_options?.entity_id.hidden
|
||||
).map(entity => entity.entity_id),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export {AbstractView};
|
||||
@@ -1,70 +0,0 @@
|
||||
import {Helper} from "../Helper";
|
||||
import {TitleCard} from "../cards/TitleCard";
|
||||
import {AbstractView} from "./AbstractView";
|
||||
|
||||
/**
|
||||
* Camera View Class.
|
||||
*
|
||||
* Used to create a view for entities of the camera domain.
|
||||
*
|
||||
* @class CameraView
|
||||
* @extends AbstractView
|
||||
*/
|
||||
class CameraView extends AbstractView {
|
||||
/**
|
||||
* Domain of the view's entities.
|
||||
* @type {string}
|
||||
*/
|
||||
#domain = "camera";
|
||||
|
||||
/**
|
||||
* Default options for the view.
|
||||
*
|
||||
* @type {viewOptions}
|
||||
* @private
|
||||
*/
|
||||
#defaultOptions = {
|
||||
title: "Cameras",
|
||||
path: "cameras",
|
||||
icon: "mdi:cctv",
|
||||
subview: false,
|
||||
titleCard: {
|
||||
showControls: false,
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Options for the view's title card.
|
||||
*
|
||||
* @type {viewTitleCardOptions}
|
||||
*/
|
||||
#viewTitleCardOption = {
|
||||
title: "All Cameras",
|
||||
...this.options["titleCard"],
|
||||
};
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param {viewOptions} [options={}] Options for the view.
|
||||
*/
|
||||
constructor(options = {}) {
|
||||
super();
|
||||
this.mergeOptions(
|
||||
this.#defaultOptions,
|
||||
options,
|
||||
);
|
||||
|
||||
// Create a title card to switch all entities of the domain.
|
||||
this.viewTitleCard = new TitleCard(Helper.areas, {
|
||||
...this.#viewTitleCardOption,
|
||||
...this.options["titleCard"],
|
||||
}).createCard();
|
||||
}
|
||||
|
||||
get domain() {
|
||||
return this.#domain;
|
||||
}
|
||||
}
|
||||
|
||||
export {CameraView};
|
||||
@@ -0,0 +1,73 @@
|
||||
import {ControllerCard} from "../cards/ControllerCard";
|
||||
import {AbstractView} from "./AbstractView";
|
||||
import {views} from "../types/strategy/views";
|
||||
import {cards} from "../types/strategy/cards";
|
||||
import {Helper} from "../Helper";
|
||||
|
||||
// noinspection JSUnusedGlobalSymbols Class is dynamically imported.
|
||||
/**
|
||||
* Camera View Class.
|
||||
*
|
||||
* Used to create a view for entities of the camera domain.
|
||||
*
|
||||
* @class CameraView
|
||||
* @extends AbstractView
|
||||
*/
|
||||
class CameraView extends AbstractView {
|
||||
/**
|
||||
* Domain of the view's entities.
|
||||
*
|
||||
* @type {string}
|
||||
* @static
|
||||
* @private
|
||||
*/
|
||||
static #domain: string = "camera";
|
||||
|
||||
/**
|
||||
* Default configuration of the view.
|
||||
*
|
||||
* @type {views.ViewConfig}
|
||||
* @private
|
||||
*/
|
||||
#defaultConfig: views.ViewConfig = {
|
||||
title: "Cameras",
|
||||
path: "cameras",
|
||||
icon: "mdi:cctv",
|
||||
subview: false,
|
||||
controllerCardOptions: {
|
||||
showControls: false,
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Default configuration of the view's Controller card.
|
||||
*
|
||||
* @type {cards.ControllerCardOptions}
|
||||
* @private
|
||||
*/
|
||||
#viewControllerCardConfig: cards.ControllerCardOptions = {
|
||||
title: "All Cameras",
|
||||
subtitle: Helper.getCountTemplate(CameraView.#domain, "ne", "off") + " cameras on",
|
||||
};
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param {views.ViewConfig} [options={}] Options for the view.
|
||||
*/
|
||||
constructor(options: views.ViewConfig = {}) {
|
||||
super(CameraView.#domain);
|
||||
|
||||
this.config = Object.assign(this.config, this.#defaultConfig, options);
|
||||
|
||||
// Create a Controller card to switch all entities of the domain.
|
||||
this.viewControllerCard = new ControllerCard(
|
||||
{},
|
||||
{
|
||||
...this.#viewControllerCardConfig,
|
||||
...("controllerCardOptions" in this.config ? this.config.controllerCardOptions : {}) as cards.ControllerCardConfig,
|
||||
}).createCard();
|
||||
}
|
||||
}
|
||||
|
||||
export {CameraView};
|
||||
@@ -1,71 +0,0 @@
|
||||
import {Helper} from "../Helper";
|
||||
import {TitleCard} from "../cards/TitleCard";
|
||||
import {AbstractView} from "./AbstractView";
|
||||
|
||||
/**
|
||||
* Climate View Class.
|
||||
*
|
||||
* Used to create a view for entities of the climate domain.
|
||||
*
|
||||
* @class ClimateView
|
||||
* @extends AbstractView
|
||||
*/
|
||||
class ClimateView extends AbstractView {
|
||||
/**
|
||||
* Domain of the view's entities.
|
||||
* @type {string}
|
||||
*/
|
||||
#domain = "climate";
|
||||
|
||||
/**
|
||||
* Default options for the view.
|
||||
*
|
||||
* @type {viewOptions}
|
||||
* @private
|
||||
*/
|
||||
#defaultOptions = {
|
||||
title: "Climates",
|
||||
path: "climates",
|
||||
icon: "mdi:thermostat",
|
||||
subview: false,
|
||||
titleCard: {
|
||||
showControls: false,
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Options for the view's title card.
|
||||
*
|
||||
* @type {viewTitleCardOptions}
|
||||
*/
|
||||
#viewTitleCardOption = {
|
||||
title: "All Climates",
|
||||
subtitle: Helper.getCountTemplate(this.domain, "ne", "off") + " climates on",
|
||||
...this.options["titleCard"],
|
||||
};
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param {viewOptions} [options={}] Options for the view.
|
||||
*/
|
||||
constructor(options = {}) {
|
||||
super();
|
||||
this.mergeOptions(
|
||||
this.#defaultOptions,
|
||||
options,
|
||||
);
|
||||
|
||||
// Create a title card to switch all entities of the domain.
|
||||
this.viewTitleCard = new TitleCard(Helper.areas, {
|
||||
...this.#viewTitleCardOption,
|
||||
...this.options["titleCard"],
|
||||
}).createCard();
|
||||
}
|
||||
|
||||
get domain() {
|
||||
return this.#domain;
|
||||
}
|
||||
}
|
||||
|
||||
export {ClimateView};
|
||||
@@ -0,0 +1,73 @@
|
||||
import {Helper} from "../Helper";
|
||||
import {ControllerCard} from "../cards/ControllerCard";
|
||||
import {AbstractView} from "./AbstractView";
|
||||
import {views} from "../types/strategy/views";
|
||||
import {cards} from "../types/strategy/cards";
|
||||
|
||||
// noinspection JSUnusedGlobalSymbols Class is dynamically imported.
|
||||
/**
|
||||
* Climate View Class.
|
||||
*
|
||||
* Used to create a view for entities of the climate domain.
|
||||
*
|
||||
* @class ClimateView
|
||||
* @extends AbstractView
|
||||
*/
|
||||
class ClimateView extends AbstractView {
|
||||
/**
|
||||
* Domain of the view's entities.
|
||||
*
|
||||
* @type {string}
|
||||
* @static
|
||||
* @private
|
||||
*/
|
||||
static #domain: string = "climate";
|
||||
|
||||
/**
|
||||
* Default configuration of the view.
|
||||
*
|
||||
* @type {views.ViewConfig}
|
||||
* @private
|
||||
*/
|
||||
#defaultConfig: views.ViewConfig = {
|
||||
title: "Climates",
|
||||
path: "climates",
|
||||
icon: "mdi:thermostat",
|
||||
subview: false,
|
||||
controllerCardOptions: {
|
||||
showControls: false,
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Default configuration of the view's Controller card.
|
||||
*
|
||||
* @type {cards.ControllerCardOptions}
|
||||
* @private
|
||||
*/
|
||||
#viewControllerCardConfig: cards.ControllerCardOptions = {
|
||||
title: "All Climates",
|
||||
subtitle: Helper.getCountTemplate(ClimateView.#domain, "ne", "off") + " climates on",
|
||||
};
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param {views.ViewConfig} [options={}] Options for the view.
|
||||
*/
|
||||
constructor(options: views.ViewConfig = {}) {
|
||||
super(ClimateView.#domain);
|
||||
|
||||
this.config = Object.assign(this.config, this.#defaultConfig, options);
|
||||
|
||||
// Create a Controller card to switch all entities of the domain.
|
||||
this.viewControllerCard = new ControllerCard(
|
||||
this.targetDomain(ClimateView.#domain),
|
||||
{
|
||||
...this.#viewControllerCardConfig,
|
||||
...("controllerCardOptions" in this.config ? this.config.controllerCardOptions : {}) as cards.ControllerCardConfig,
|
||||
}).createCard();
|
||||
}
|
||||
}
|
||||
|
||||
export {ClimateView};
|
||||
@@ -1,73 +0,0 @@
|
||||
import {Helper} from "../Helper";
|
||||
import {TitleCard} from "../cards/TitleCard";
|
||||
import {AbstractView} from "./AbstractView";
|
||||
|
||||
/**
|
||||
* Cover View Class.
|
||||
*
|
||||
* Used to create a view for entities of the cover domain.
|
||||
*
|
||||
* @class CoverView
|
||||
* @extends AbstractView
|
||||
*/
|
||||
class CoverView extends AbstractView {
|
||||
/**
|
||||
* Domain of the view's entities.
|
||||
* @type {string}
|
||||
*/
|
||||
#domain = "cover";
|
||||
|
||||
/**
|
||||
* Default options for the view.
|
||||
*
|
||||
* @type {viewOptions}
|
||||
* @private
|
||||
*/
|
||||
#defaultOptions = {
|
||||
title: "Covers",
|
||||
path: "covers",
|
||||
icon: "mdi:window-open",
|
||||
subview: false,
|
||||
titleCard: {
|
||||
iconOn: "mdi:arrow-up",
|
||||
iconOff: "mdi:arrow-down",
|
||||
onService: "cover.open_cover",
|
||||
offService: "cover.close_cover",
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Options for the view's title card.
|
||||
*
|
||||
* @type {viewTitleCardOptions}
|
||||
*/
|
||||
#viewTitleCardOption = {
|
||||
title: "All Covers",
|
||||
subtitle: Helper.getCountTemplate(this.domain, "eq", "open") + " covers open",
|
||||
};
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param {viewOptions} [options={}] Options for the view.
|
||||
*/
|
||||
constructor(options = {}) {
|
||||
super();
|
||||
this.mergeOptions(
|
||||
this.#defaultOptions,
|
||||
options,
|
||||
);
|
||||
|
||||
// Create a title card to switch all entities of the domain.
|
||||
this.viewTitleCard = new TitleCard(Helper.areas, {
|
||||
...this.#viewTitleCardOption,
|
||||
...this.options["titleCard"],
|
||||
}).createCard();
|
||||
}
|
||||
|
||||
get domain() {
|
||||
return this.#domain;
|
||||
}
|
||||
}
|
||||
|
||||
export {CoverView};
|
||||
@@ -0,0 +1,76 @@
|
||||
import {Helper} from "../Helper";
|
||||
import {ControllerCard} from "../cards/ControllerCard";
|
||||
import {AbstractView} from "./AbstractView";
|
||||
import {views} from "../types/strategy/views";
|
||||
import {cards} from "../types/strategy/cards";
|
||||
|
||||
// noinspection JSUnusedGlobalSymbols Class is dynamically imported.
|
||||
/**
|
||||
* Cover View Class.
|
||||
*
|
||||
* Used to create a view for entities of the cover domain.
|
||||
*
|
||||
* @class CoverView
|
||||
* @extends AbstractView
|
||||
*/
|
||||
class CoverView extends AbstractView {
|
||||
/**
|
||||
* Domain of the view's entities.
|
||||
*
|
||||
* @type {string}
|
||||
* @static
|
||||
* @private
|
||||
*/
|
||||
static #domain: string = "cover";
|
||||
|
||||
/**
|
||||
* Default configuration of the view.
|
||||
*
|
||||
* @type {views.ViewConfig}
|
||||
* @private
|
||||
*/
|
||||
#defaultConfig: views.ViewConfig = {
|
||||
title: "Covers",
|
||||
path: "covers",
|
||||
icon: "mdi:window-open",
|
||||
subview: false,
|
||||
controllerCardOptions: {
|
||||
iconOn: "mdi:arrow-up",
|
||||
iconOff: "mdi:arrow-down",
|
||||
onService: "cover.open_cover",
|
||||
offService: "cover.close_cover",
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Default configuration of the view's Controller card.
|
||||
*
|
||||
* @type {cards.ControllerCardOptions}
|
||||
* @private
|
||||
*/
|
||||
#viewControllerCardConfig: cards.ControllerCardOptions = {
|
||||
title: "All Covers",
|
||||
subtitle: Helper.getCountTemplate(CoverView.#domain, "eq", "open") + " covers open",
|
||||
};
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param {views.ViewConfig} [options={}] Options for the view.
|
||||
*/
|
||||
constructor(options: views.ViewConfig = {}) {
|
||||
super(CoverView.#domain);
|
||||
|
||||
this.config = Object.assign(this.config, this.#defaultConfig, options);
|
||||
|
||||
// Create a Controller card to switch all entities of the domain.
|
||||
this.viewControllerCard = new ControllerCard(
|
||||
this.targetDomain(CoverView.#domain),
|
||||
{
|
||||
...this.#viewControllerCardConfig,
|
||||
...("controllerCardOptions" in this.config ? this.config.controllerCardOptions : {}) as cards.ControllerCardConfig,
|
||||
}).createCard();
|
||||
}
|
||||
}
|
||||
|
||||
export {CoverView};
|
||||
@@ -1,73 +0,0 @@
|
||||
import {Helper} from "../Helper";
|
||||
import {TitleCard} from "../cards/TitleCard";
|
||||
import {AbstractView} from "./AbstractView";
|
||||
|
||||
/**
|
||||
* Fan View Class.
|
||||
*
|
||||
* Used to create a view for entities of the fan domain.
|
||||
*
|
||||
* @class FanView
|
||||
* @extends AbstractView
|
||||
*/
|
||||
class FanView extends AbstractView {
|
||||
/**
|
||||
* Domain of the view's entities.
|
||||
* @type {string}
|
||||
*/
|
||||
#domain = "fan";
|
||||
|
||||
/**
|
||||
* Default options for the view.
|
||||
*
|
||||
* @type {viewOptions}
|
||||
* @private
|
||||
*/
|
||||
#defaultOptions = {
|
||||
title: "Fans",
|
||||
path: "fans",
|
||||
icon: "mdi:fan",
|
||||
subview: false,
|
||||
titleCard: {
|
||||
iconOn: "mdi:fan",
|
||||
iconOff: "mdi:fan-off",
|
||||
onService: "fan.turn_on",
|
||||
offService: "fan.turn_off",
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Options for the view's title card.
|
||||
*
|
||||
* @type {viewTitleCardOptions}
|
||||
*/
|
||||
#viewTitleCardOption = {
|
||||
title: "All Fans",
|
||||
subtitle: Helper.getCountTemplate(this.domain, "eq", "on") + " fans on",
|
||||
};
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param {viewOptions} [options={}] Options for the view.
|
||||
*/
|
||||
constructor(options = {}) {
|
||||
super();
|
||||
this.mergeOptions(
|
||||
this.#defaultOptions,
|
||||
options,
|
||||
);
|
||||
|
||||
// Create a title card to switch all entities of the domain.
|
||||
this.viewTitleCard = new TitleCard(Helper.areas, {
|
||||
...this.#viewTitleCardOption,
|
||||
...this.options["titleCard"],
|
||||
}).createCard();
|
||||
}
|
||||
|
||||
get domain() {
|
||||
return this.#domain;
|
||||
}
|
||||
}
|
||||
|
||||
export {FanView};
|
||||
@@ -0,0 +1,76 @@
|
||||
import {Helper} from "../Helper";
|
||||
import {ControllerCard} from "../cards/ControllerCard";
|
||||
import {AbstractView} from "./AbstractView";
|
||||
import {views} from "../types/strategy/views";
|
||||
import {cards} from "../types/strategy/cards";
|
||||
|
||||
// noinspection JSUnusedGlobalSymbols Class is dynamically imported.
|
||||
/**
|
||||
* Fan View Class.
|
||||
*
|
||||
* Used to create a view for entities of the fan domain.
|
||||
*
|
||||
* @class FanView
|
||||
* @extends AbstractView
|
||||
*/
|
||||
class FanView extends AbstractView {
|
||||
/**
|
||||
* Domain of the view's entities.
|
||||
*
|
||||
* @type {string}
|
||||
* @static
|
||||
* @private
|
||||
*/
|
||||
static #domain: string = "fan";
|
||||
|
||||
/**
|
||||
* Default configuration of the view.
|
||||
*
|
||||
* @type {views.ViewConfig}
|
||||
* @private
|
||||
*/
|
||||
#defaultConfig: views.ViewConfig = {
|
||||
title: "Fans",
|
||||
path: "fans",
|
||||
icon: "mdi:fan",
|
||||
subview: false,
|
||||
controllerCardOptions: {
|
||||
iconOn: "mdi:fan",
|
||||
iconOff: "mdi:fan-off",
|
||||
onService: "fan.turn_on",
|
||||
offService: "fan.turn_off",
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Default configuration of the view's Controller card.
|
||||
*
|
||||
* @type {cards.ControllerCardOptions}
|
||||
* @private
|
||||
*/
|
||||
#viewControllerCardConfig: cards.ControllerCardOptions = {
|
||||
title: "All Fans",
|
||||
subtitle: Helper.getCountTemplate(FanView.#domain, "eq", "on") + " fans on",
|
||||
};
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param {views.ViewConfig} [options={}] Options for the view.
|
||||
*/
|
||||
constructor(options: views.ViewConfig = {}) {
|
||||
super(FanView.#domain);
|
||||
|
||||
this.config = Object.assign(this.config, this.#defaultConfig, options);
|
||||
|
||||
// Create a Controller card to switch all entities of the domain.
|
||||
this.viewControllerCard = new ControllerCard(
|
||||
this.targetDomain(FanView.#domain),
|
||||
{
|
||||
...this.#viewControllerCardConfig,
|
||||
...("controllerCardOptions" in this.config ? this.config.controllerCardOptions : {}) as cards.ControllerCardConfig,
|
||||
}).createCard();
|
||||
}
|
||||
}
|
||||
|
||||
export {FanView};
|
||||
@@ -1,6 +1,16 @@
|
||||
import {Helper} from "../Helper";
|
||||
import {AbstractView} from "./AbstractView";
|
||||
import {views} from "../types/strategy/views";
|
||||
import {LovelaceChipConfig} from "../types/lovelace-mushroom/utils/lovelace/chip/types";
|
||||
import {ChipsCardConfig} from "../types/lovelace-mushroom/cards/chips-card";
|
||||
import {AreaCardConfig, StackCardConfig} from "../types/homeassistant/lovelace/cards/types";
|
||||
import {TemplateCardConfig} from "../types/lovelace-mushroom/cards/template-card-config";
|
||||
import {ActionConfig} from "../types/homeassistant/data/lovelace";
|
||||
import {TitleCardConfig} from "../types/lovelace-mushroom/cards/title-card-config";
|
||||
import {PersonCardConfig} from "../types/lovelace-mushroom/cards/person-card-config";
|
||||
|
||||
|
||||
// noinspection JSUnusedGlobalSymbols Class is dynamically imported.
|
||||
/**
|
||||
* Home View Class.
|
||||
*
|
||||
@@ -11,13 +21,14 @@ import {AbstractView} from "./AbstractView";
|
||||
*/
|
||||
class HomeView extends AbstractView {
|
||||
/**
|
||||
* Default options for the view.
|
||||
* Default configuration of the view.
|
||||
*
|
||||
* @type {viewOptions}
|
||||
* @type {views.ViewConfig}
|
||||
* @private
|
||||
*/
|
||||
#defaultOptions = {
|
||||
#defaultConfig: views.ViewConfig = {
|
||||
title: "Home",
|
||||
icon: "mdi:home-assistant",
|
||||
path: "home",
|
||||
subview: false,
|
||||
};
|
||||
@@ -25,73 +36,65 @@ class HomeView extends AbstractView {
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param {viewOptions} [options={}] Options for the view.
|
||||
* @param {views.ViewConfig} [options={}] Options for the view.
|
||||
*/
|
||||
constructor(options = {}) {
|
||||
constructor(options: views.ViewConfig = {}) {
|
||||
super();
|
||||
this.mergeOptions(
|
||||
this.#defaultOptions,
|
||||
options,
|
||||
);
|
||||
|
||||
this.config = Object.assign(this.config, this.#defaultConfig, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the cards to include in the view.
|
||||
*
|
||||
* @return {Promise} A promise of a card object array.
|
||||
* @return {Promise<(StackCardConfig | TemplateCardConfig | ChipsCardConfig)[]>} Promise a View Card array.
|
||||
* @override
|
||||
*/
|
||||
async createViewCards() {
|
||||
async createViewCards(): Promise<(StackCardConfig | TemplateCardConfig | ChipsCardConfig)[]> {
|
||||
return await Promise.all([
|
||||
this.#createChips(),
|
||||
this.#createPersonCards(),
|
||||
this.#createAreaCards(),
|
||||
this.#createAreaSection(),
|
||||
]).then(([chips, personCards, areaCards]) => {
|
||||
const options = Helper.strategyOptions;
|
||||
const homeViewCards = [];
|
||||
|
||||
// Add chips to the view.
|
||||
if (chips.length) {
|
||||
// TODO: Create the Chip card at this.#createChips()
|
||||
homeViewCards.push({
|
||||
type: "custom:mushroom-chips-card",
|
||||
alignment: "center",
|
||||
chips: chips,
|
||||
});
|
||||
} as ChipsCardConfig)
|
||||
}
|
||||
|
||||
// Add persons to the view
|
||||
if (personCards.length) {
|
||||
// TODO: Create the stack at this.#createPersonCards()
|
||||
homeViewCards.push({
|
||||
type: "horizontal-stack",
|
||||
cards: personCards,
|
||||
});
|
||||
} as StackCardConfig);
|
||||
}
|
||||
|
||||
// Add greeting to the view if not hidden.
|
||||
if (!Helper.strategyOptions.homeView?.hidden?.includes("greeting")) {
|
||||
if (!Helper.strategyOptions.home_view.hidden.includes("greeting")) {
|
||||
homeViewCards.push({
|
||||
type: "custom:mushroom-template-card",
|
||||
primary:
|
||||
"{% set time = now().hour %}" +
|
||||
"{% if (time >= 18) %} Good Evening, {{user}}!" +
|
||||
"{% elif (time >= 12) %} Good Afternoon, {{user}}!" +
|
||||
"{% elif (time >= 5) %} Good Morning, {{user}}!" +
|
||||
"{% else %} Hello, {{user}}!" +
|
||||
"{% endif %}",
|
||||
primary: "{% set time = now().hour %} {% if (time >= 18) %} Good Evening, {{user}}! {% elif (time >= 12) %} Good Afternoon, {{user}}! {% elif (time >= 5) %} Good Morning, {{user}}! {% else %} Hello, {{user}}! {% endif %}",
|
||||
icon: "mdi:hand-wave",
|
||||
icon_color: "orange",
|
||||
tap_action: {
|
||||
action: "none",
|
||||
},
|
||||
} as ActionConfig,
|
||||
double_tap_action: {
|
||||
action: "none",
|
||||
},
|
||||
} as ActionConfig,
|
||||
hold_action: {
|
||||
action: "none",
|
||||
},
|
||||
});
|
||||
} as ActionConfig,
|
||||
} as TemplateCardConfig);
|
||||
}
|
||||
|
||||
|
||||
// Add quick access cards.
|
||||
if (options.quick_access_cards) {
|
||||
homeViewCards.push(...options.quick_access_cards);
|
||||
@@ -101,7 +104,7 @@ class HomeView extends AbstractView {
|
||||
homeViewCards.push({
|
||||
type: "vertical-stack",
|
||||
cards: areaCards,
|
||||
});
|
||||
} as StackCardConfig);
|
||||
|
||||
// Add custom cards.
|
||||
if (options.extra_cards) {
|
||||
@@ -115,49 +118,53 @@ class HomeView extends AbstractView {
|
||||
/**
|
||||
* Create the chips to include in the view.
|
||||
*
|
||||
* @return {Object[]} A chip object array.
|
||||
* @return {Promise<LovelaceChipConfig[]>} Promise a chip array.
|
||||
*/
|
||||
async #createChips() {
|
||||
if (Helper.strategyOptions.homeView?.hidden?.includes("chips")) {
|
||||
// Chips section is hidden; Return 0 chips.
|
||||
async #createChips(): Promise<LovelaceChipConfig[]> {
|
||||
if (Helper.strategyOptions.home_view.hidden.includes("chips")) {
|
||||
// Chips section is hidden.
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
const chips = [];
|
||||
const chips: LovelaceChipConfig[] = [];
|
||||
const chipOptions = Helper.strategyOptions.chips;
|
||||
|
||||
// TODO: Get domains from config.
|
||||
const exposed_chips = ["light", "fan", "cover", "switch", "climate"];
|
||||
const exposedChips = ["light", "fan", "cover", "switch", "climate"];
|
||||
// Create a list of area-ids, used for switching all devices via chips
|
||||
const areaIds = Helper.areas.map(area => area.area_id);
|
||||
const areaIds = Helper.areas.map(area => area.area_id ?? "");
|
||||
|
||||
let chipModule;
|
||||
|
||||
// Weather chip.
|
||||
const weatherEntityId = chipOptions?.weather_entity ?? Helper.entities.find(
|
||||
entity => entity.entity_id.startsWith("weather.") && entity.disabled_by == null && entity.hidden_by == null,
|
||||
(entity) => entity.entity_id.startsWith("weather.") && entity.disabled_by === null && entity.hidden_by === null,
|
||||
)?.entity_id;
|
||||
|
||||
if (weatherEntityId) {
|
||||
try {
|
||||
chipModule = await import("../chips/WeatherChip");
|
||||
const weatherChip = new chipModule.WeatherChip(weatherEntityId);
|
||||
|
||||
chips.push(weatherChip.getChip());
|
||||
} catch (e) {
|
||||
console.error(Helper.debug ? e : "An error occurred while creating the weather chip!");
|
||||
Helper.logError("An error occurred while creating the weather chip!", e);
|
||||
}
|
||||
}
|
||||
|
||||
// Numeric chips.
|
||||
for (let chipType of exposed_chips) {
|
||||
if (chipOptions?.[`${chipType}_count`] ?? true) {
|
||||
for (let chipType of exposedChips) {
|
||||
if (chipOptions?.[`${chipType}_count` as string] ?? true) {
|
||||
const className = Helper.sanitizeClassName(chipType + "Chip");
|
||||
try {
|
||||
chipModule = await import((`../chips/${className}`));
|
||||
const chip = new chipModule[className](areaIds);
|
||||
const chip = new chipModule[className]();
|
||||
|
||||
chip.setTapActionTarget({area_id: areaIds});
|
||||
chips.push(chip.getChip());
|
||||
} catch (e) {
|
||||
console.error(Helper.debug ? e : `An error occurred while creating the ${chipType} chip!`);
|
||||
Helper.logError(`An error occurred while creating the ${chipType} chip!`, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -173,18 +180,19 @@ class HomeView extends AbstractView {
|
||||
/**
|
||||
* Create the person cards to include in the view.
|
||||
*
|
||||
* @return {Object[]} A card object array.
|
||||
* @return {PersonCardConfig[]} A Person Card array.
|
||||
*/
|
||||
#createPersonCards() {
|
||||
if (Helper.strategyOptions.homeView?.hidden?.includes("persons")) {
|
||||
// Person section is hidden; Return 0 cards.
|
||||
#createPersonCards(): PersonCardConfig[] {
|
||||
if (Helper.strategyOptions.home_view.hidden.includes("persons")) {
|
||||
// Person section is hidden.
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
const cards = [];
|
||||
const cards: PersonCardConfig[] = [];
|
||||
|
||||
import("../cards/PersonCard").then(personModule => {
|
||||
for (const person of Helper.entities.filter(entity => {
|
||||
for (const person of Helper.entities.filter((entity) => {
|
||||
return entity.entity_id.startsWith("person.")
|
||||
&& entity.hidden_by == null
|
||||
&& entity.disabled_by == null;
|
||||
@@ -201,40 +209,35 @@ class HomeView extends AbstractView {
|
||||
*
|
||||
* Area cards are grouped into two areas per row.
|
||||
*
|
||||
* @return {Object[]} A card object array.
|
||||
* @return {Promise<(TitleCardConfig | StackCardConfig)[]>} Promise an Area Card Section.
|
||||
*/
|
||||
async #createAreaCards() {
|
||||
if (Helper.strategyOptions.homeView?.hidden?.includes("areas")) {
|
||||
// Area section is hidden; Return 0 cards.
|
||||
async #createAreaSection(): Promise<(TitleCardConfig | StackCardConfig)[]> {
|
||||
if (Helper.strategyOptions.home_view.hidden.includes("areas")) {
|
||||
// Areas section is hidden.
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Cards to be stacked vertically.
|
||||
*
|
||||
* Contains a Title card and horizontal stacks of Area cards.
|
||||
*
|
||||
* @type {[{}]}
|
||||
*/
|
||||
const groupedCards = [];
|
||||
const groupedCards: (TitleCardConfig | StackCardConfig)[] = [];
|
||||
|
||||
let areaCards = [];
|
||||
let areaCards: (TemplateCardConfig | AreaCardConfig)[] = [];
|
||||
|
||||
// Add title to the area section.
|
||||
if (!Helper.strategyOptions.homeView?.hidden?.includes("areasTitle")) {
|
||||
if (!Helper.strategyOptions.home_view.hidden.includes("areasTitle")) {
|
||||
groupedCards.push({
|
||||
type: "custom:mushroom-title-card",
|
||||
title: "Areas",
|
||||
});
|
||||
type: "custom:mushroom-title-card",
|
||||
title: "Areas",
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
// Add cards to the area section.
|
||||
for (const [i, area] of Helper.areas.entries()) {
|
||||
let module;
|
||||
type ModuleType = typeof import("../cards/AreaCard");
|
||||
|
||||
let module: ModuleType;
|
||||
let moduleName =
|
||||
Helper.strategyOptions.areas[area.area_id ?? "undisclosed"]?.type ??
|
||||
Helper.strategyOptions.areas["_"]?.type ??
|
||||
"default";
|
||||
Helper.strategyOptions.areas[area.area_id]?.type ??
|
||||
Helper.strategyOptions.areas["_"]?.type ??
|
||||
"default";
|
||||
|
||||
// Load module by type in strategy options.
|
||||
try {
|
||||
@@ -249,10 +252,10 @@ class HomeView extends AbstractView {
|
||||
}
|
||||
|
||||
// Get a card for the area.
|
||||
if (!Helper.strategyOptions.areas[area.area_id]?.hidden) {
|
||||
if (!Helper.strategyOptions.areas[area.area_id as string]?.hidden) {
|
||||
let options = {
|
||||
...Helper.strategyOptions.areas["_"],
|
||||
...Helper.strategyOptions.areas[area.area_id ?? "undisclosed"],
|
||||
...Helper.strategyOptions.areas[area.area_id],
|
||||
};
|
||||
|
||||
areaCards.push(new module.AreaCard(area, options).getCard());
|
||||
@@ -264,7 +267,7 @@ class HomeView extends AbstractView {
|
||||
groupedCards.push({
|
||||
type: "horizontal-stack",
|
||||
cards: areaCards.slice(i, i + 2),
|
||||
});
|
||||
} as StackCardConfig);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,73 +0,0 @@
|
||||
import {Helper} from "../Helper";
|
||||
import {TitleCard} from "../cards/TitleCard";
|
||||
import {AbstractView} from "./AbstractView";
|
||||
|
||||
/**
|
||||
* Light View Class.
|
||||
*
|
||||
* Used to create a view for entities of the light domain.
|
||||
*
|
||||
* @class LightView
|
||||
* @extends AbstractView
|
||||
*/
|
||||
class LightView extends AbstractView {
|
||||
/**
|
||||
* Domain of the view's entities.
|
||||
* @type {string}
|
||||
*/
|
||||
#domain = "light";
|
||||
|
||||
/**
|
||||
* Default options for the view.
|
||||
*
|
||||
* @type {viewOptions}
|
||||
* @private
|
||||
*/
|
||||
#defaultOptions = {
|
||||
title: "Lights",
|
||||
path: "lights",
|
||||
icon: "mdi:lightbulb-group",
|
||||
subview: false,
|
||||
titleCard: {
|
||||
iconOn: "mdi:lightbulb",
|
||||
iconOff: "mdi:lightbulb-off",
|
||||
onService: "light.turn_on",
|
||||
offService: "light.turn_off",
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Options for the view's title card.
|
||||
*
|
||||
* @type {viewTitleCardOptions}
|
||||
*/
|
||||
#viewTitleCardOption = {
|
||||
title: "All Lights",
|
||||
subtitle: Helper.getCountTemplate(this.domain, "eq", "on") + " lights on",
|
||||
};
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param {viewOptions} [options={}] Options for the view.
|
||||
*/
|
||||
constructor(options = {}) {
|
||||
super();
|
||||
this.mergeOptions(
|
||||
this.#defaultOptions,
|
||||
options,
|
||||
);
|
||||
|
||||
// Create a title card to switch all entities of the domain.
|
||||
this.viewTitleCard = new TitleCard(Helper.areas, {
|
||||
...this.#viewTitleCardOption,
|
||||
...this.options["titleCard"],
|
||||
}).createCard();
|
||||
}
|
||||
|
||||
get domain() {
|
||||
return this.#domain;
|
||||
}
|
||||
}
|
||||
|
||||
export {LightView};
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user