Add options to configure entity-cards (#31)

* Add options to configure entity-cards

Closes #10.
- Option to set the type of entity card.
- Option to hide an entity card from the dashboard.

* Add hiding title cards

When all entity cards are hidden for an area or domain, the
corresponding title cards will be hidden also.

* Fix Climate Chip navigation

Closes #33

* Build production distribution
This commit is contained in:
Ferry Cools
2023-07-19 15:07:55 +02:00
committed by GitHub
parent 5bded12e70
commit 140aec854b
7 changed files with 103 additions and 86 deletions

View File

@@ -109,16 +109,16 @@ weather entity for the weather chip.
The options available are: The options available are:
| Name | Type | Default | Description | | Name | Type | Default | Description |
|:---------------------|:--------------------------|:--------------------------------------------------------|:--------------------------------------------------------------------| |:---------------------|:--------------------------|:--------------------------------------------------------|:---------------------------------------------------------------|
| `areas` | object (optional) | unset | One or more areas in a list, see [areas object](#area-object). | | `areas` | object (optional) | unset | One or more areas in a list, see [areas object](#area-object). |
| `entity_config` | array of cards (optional) | unset | Card definition for an entity, see [entity config](#entity-config). | | `card_options` | object (optional) | unset | Card options for an entity, see [Card Options](#card-options). |
| `views` | object (optional) | All default views | See available [Pre-built views](#pre-built-views). | | `views` | object (optional) | All default views | See available [Pre-built views](#pre-built-views). |
| `chips` | object | All count chips enabled with auto selected weather card | See [chips](#chips). | | `chips` | object | All count chips enabled with auto selected weather card | See [chips](#chips). |
| `quick_access_cards` | array of cards (optional) | unset | List of cards to show between welcome card and rooms cards. | | `quick_access_cards` | array of cards (optional) | unset | List of cards to show between welcome card and rooms cards. |
| `extra_cards` | array of cards (optional | unset | List of cards to show below room cards. | | `extra_cards` | array of cards (optional | unset | List of cards to show below room cards. |
| `extra_views` | array of views (optional) | unset | List of views to add to the dashboard. | | `extra_views` | array of views (optional) | unset | List of views to add to the dashboard. |
| `domains` | object (optional) | All supported domains | See [Supported domains](#supported-domains). | | `domains` | object (optional) | All supported domains | See [Supported domains](#supported-domains). |
#### Example #### Example
@@ -200,9 +200,9 @@ This area is enabled by default and includes the entities that aren't linked to
The area can be configured like any other area as described above. The area can be configured like any other area as described above.
To exclude this area from the dashboard and views, set its property `hidden` to `true`. To exclude this area from the dashboard and views, set its property `hidden` to `true`.
### Entity Config ### Card Options
The `entity_config` essentially enables you to give a specific entity any card you wish. The `card_options` entry enables you to specify a card type for an entity or to hide the card from the dashboard.
#### Example #### Example
@@ -210,9 +210,11 @@ The `entity_config` essentially enables you to give a specific entity any card y
strategy: strategy:
type: custom:mushroom-strategy type: custom:mushroom-strategy
options: options:
entity_config: card_options:
- entity: fan.master_bedroom_fan fan.master_bedroom_fan:
type: custom:mushroom-fan-card type: custom:mushroom-fan-card
remote.harmony_hub_wk:
hidden: true
views: [ ] views: [ ]
``` ```
@@ -419,9 +421,11 @@ strategy:
front_door_id: front_door_id:
name: Front Door name: Front Door
icon: mdi:door-closed icon: mdi:door-closed
entity_config: card_options:
- entity: fan.master_bedroom_fan fan.master_bedroom_fan:
type: custom:mushroom-fan-card type: custom:mushroom-fan-card
remote.harmony_hub_wk:
hidden: true
quick_access_cards: quick_access_cards:
- type: custom:mushroom-title-card - type: custom:mushroom-title-card
title: Security title: Security

File diff suppressed because one or more lines are too long

View File

@@ -26,7 +26,7 @@ class AreaCard extends AbstractCard {
}, },
hold_action: { hold_action: {
action: "none", action: "none",
} },
}; };
/** /**

View File

@@ -26,7 +26,11 @@ class ClimateChip {
content: Helper.getCountTemplate("climate", "ne", "off"), content: Helper.getCountTemplate("climate", "ne", "off"),
tap_action: { tap_action: {
action: "navigate", action: "navigate",
navigation_path: "thermostats", navigation_path: "climates",
},
hold_action: {
action: "navigate",
navigation_path: "climates",
}, },
}; };
} }

View File

@@ -57,7 +57,6 @@ class MushroomStrategy {
type: "custom:mushroom-strategy", type: "custom:mushroom-strategy",
options: { options: {
area, area,
"entity_config": Helper.strategyOptions.entity_config,
}, },
}, },
}); });
@@ -84,12 +83,9 @@ class MushroomStrategy {
* @return {Promise<{cards: Object[]}>} * @return {Promise<{cards: Object[]}>}
*/ */
static async generateView(info) { static async generateView(info) {
const exposedDomainIds = Helper.getExposedDomainIds(); const exposedDomainIds = Helper.getExposedDomainIds();
const area = info.view.strategy.options.area; const area = info.view.strategy.options.area;
const viewCards = [...(area.extra_cards ?? [])]; const viewCards = [...(area.extra_cards ?? [])];
const strategyOptions = {
entityConfig: info.view.strategy.options.entity_config,
};
// Create cards for each domain. // Create cards for each domain.
for (const domain of exposedDomainIds) { for (const domain of exposedDomainIds) {
@@ -110,7 +106,7 @@ class MushroomStrategy {
// Create a Title card for the current domain. // Create a Title card for the current domain.
const titleCard = new TitleCard( const titleCard = new TitleCard(
[area], [area],
Helper.strategyOptions.domains[domain] Helper.strategyOptions.domains[domain],
).createCard(); ).createCard();
if (domain === "sensor") { if (domain === "sensor") {
@@ -119,43 +115,44 @@ class MushroomStrategy {
const sensorCards = []; const sensorCards = [];
for (const sensor of entities) { for (const sensor of entities) {
let card = (strategyOptions.entityConfig?.find(config => config.entity_id === sensor.entity_id));
if (card) {
sensorCards.push(card);
continue;
}
// Find the state of the current sensor. // Find the state of the current sensor.
const sensorState = sensorStates.find(state => state.entity_id === sensor.entity_id); const sensorState = sensorStates.find(state => state.entity_id === sensor.entity_id);
let cardOptions = {}; let cardOptions = Helper.strategyOptions.card_options?.[sensor.entity_id] ?? {};
if (sensorState?.attributes.unit_of_measurement) { if (!cardOptions.hidden) {
cardOptions = { if (sensorState?.attributes.unit_of_measurement) {
type: "custom:mini-graph-card", cardOptions = {
entities: [sensor.entity_id], ...{
}; type: "custom:mini-graph-card",
entities: [sensor.entity_id],
},
...cardOptions,
};
}
sensorCards.push(new SensorCard(sensor, cardOptions).getCard());
} }
sensorCards.push(new SensorCard(sensor, cardOptions).getCard());
} }
domainCards.push({ if (sensorCards.length) {
type: "vertical-stack", domainCards.push({
cards: sensorCards, type: "vertical-stack",
}); cards: sensorCards,
});
domainCards.unshift(titleCard);
}
domainCards.unshift(titleCard);
return domainCards; return domainCards;
} }
// Create a card for each domain-entity of the current area. // Create a card for each domain-entity of the current area.
for (const entity of entities) { for (const entity of entities) {
const card = (Helper.strategyOptions.entity_config ?? []).find( let cardOptions = Helper.strategyOptions.card_options?.[entity.entity_id] ?? {};
config => config.entity === entity.entity_id,
) ?? new cardModule[className](entity).getCard();
domainCards.push(card); if (!cardOptions.hidden) {
domainCards.push(new cardModule[className](entity, cardOptions).getCard());
}
} }
if (domain === "binary_sensor") { if (domain === "binary_sensor") {
@@ -172,7 +169,9 @@ class MushroomStrategy {
domainCards = horizontalCards; domainCards = horizontalCards;
} }
domainCards.unshift(titleCard); if (domainCards.length) {
domainCards.unshift(titleCard);
}
} }
return domainCards; return domainCards;
@@ -215,12 +214,13 @@ class MushroomStrategy {
const miscellaneousCards = [ const miscellaneousCards = [
new TitleCard([area], Helper.strategyOptions.domains.default).createCard(), new TitleCard([area], Helper.strategyOptions.domains.default).createCard(),
]; ];
for (const entity of miscellaneousEntities) {
const card = (Helper.strategyOptions.entity_config ?? []).find(
config => config.entity === entity.entity_id,
) ?? new cardModule.MiscellaneousCard(entity).getCard();
miscellaneousCards.push(card); for (const entity of miscellaneousEntities) {
let cardOptions = Helper.strategyOptions.card_options?.[entity.entity_id] ?? {};
if (!cardOptions.hidden) {
miscellaneousCards.push(new cardModule.MiscellaneousCard(entity, cardOptions).getCard());
}
} }
return miscellaneousCards; return miscellaneousCards;

View File

@@ -111,7 +111,7 @@
* @typedef {Object} customStrategyOptions Custom strategy configuration. * @typedef {Object} customStrategyOptions Custom strategy configuration.
* @property {boolean} [debug] Set to true for more verbose debugging info. * @property {boolean} [debug] Set to true for more verbose debugging info.
* @property {Object.<areaEntity>} [areas] List of areas. * @property {Object.<areaEntity>} [areas] List of areas.
* @property {Object[]} [entity_config] Card definition for entities. * @property {Object.<cardOptions>} [card_options] Card options for entities.
* @property {Object.<viewEntity>} [views] List of views. * @property {Object.<viewEntity>} [views] List of views.
* @property {Object.<domainEntity>} [domains] List of domains. * @property {Object.<domainEntity>} [domains] List of domains.
* @property {chip[]} [chips] List of chips to show in the Home view. * @property {chip[]} [chips] List of chips to show in the Home view.
@@ -134,9 +134,9 @@
*/ */
/** /**
* @typedef {Object} entityConfig Custom card-configuration for an entity on a view card. * @typedef {Object} cardOptions Custom card-configuration for an entity.
* @property {string} entity The id of the entity to create a card for.
* @property {string} type Type of card for the 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 * @memberOf typedefs.generic
*/ */

View File

@@ -63,43 +63,52 @@ class AbstractView {
* *
* @return {Object[] | Promise} An array of card objects. * @return {Object[] | Promise} An array of card objects.
*/ */
createViewCards() { async createViewCards() {
/** @type Object[] */ /** @type Object[] */
const viewCards = [this.viewTitleCard]; const viewCards = [this.viewTitleCard];
// Create cards for each area. // Create cards for each area.
for (const area of Helper.areas) { for (const area of Helper.areas) {
const areaCards = []; const areaCards = [];
const entities = Helper.getDeviceEntities(area, this["domain"]); const entities = Helper.getDeviceEntities(area, this["domain"]);
const className = Helper.sanitizeClassName(this["domain"] + "Card"); const className = Helper.sanitizeClassName(this["domain"] + "Card");
const cardModule = await import(`../cards/${className}`);
import((`../cards/${className}`)).then(cardModule => { // Create a card for each domain-entity of the current area.
if (entities.length) { for (const entity of entities) {
// Create a Title card for the current area. let cardOptions = Helper.strategyOptions.card_options?.[entity.entity_id] ?? {};
areaCards.push(
new TitleCard([area], {
title: area.name,
...this.options["titleCard"],
}).createCard(),
);
// Create a card for each domain-entity of the current area. if (cardOptions.hidden) {
for (const entity of entities) { continue;
const card = (Helper.strategyOptions.entity_config ?? []).find(
config => config.entity === entity.entity_id,
) ?? new cardModule[className](entity).getCard();
areaCards.push(card);
}
} }
});
viewCards.push({ areaCards.push(new cardModule[className](entity, cardOptions).getCard());
type: "vertical-stack", }
cards: areaCards,
}); 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; return viewCards;
} }