Skip to content

Commit

Permalink
Add options to configure entity-cards (#31)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
DigiLive authored Jul 19, 2023
1 parent 5bded12 commit 140aec8
Show file tree
Hide file tree
Showing 7 changed files with 105 additions and 88 deletions.
36 changes: 20 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -109,16 +109,16 @@ weather entity for the weather chip.

The options available are:

| Name | Type | Default | Description |
|:---------------------|:--------------------------|:--------------------------------------------------------|:--------------------------------------------------------------------|
| `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). |
| `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). |
| `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_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). |
| Name | Type | Default | Description |
|:---------------------|:--------------------------|:--------------------------------------------------------|:---------------------------------------------------------------|
| `areas` | object (optional) | unset | One or more areas in a list, see [areas object](#area-object). |
| `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). |
| `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. |
| `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. |
| `domains` | object (optional) | All supported domains | See [Supported domains](#supported-domains). |

#### Example

Expand Down Expand Up @@ -200,19 +200,21 @@ 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.
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

```yaml
strategy:
type: custom:mushroom-strategy
options:
entity_config:
- entity: fan.master_bedroom_fan
card_options:
fan.master_bedroom_fan:
type: custom:mushroom-fan-card
remote.harmony_hub_wk:
hidden: true
views: [ ]
```

Expand Down Expand Up @@ -419,9 +421,11 @@ strategy:
front_door_id:
name: Front Door
icon: mdi:door-closed
entity_config:
- entity: fan.master_bedroom_fan
card_options:
fan.master_bedroom_fan:
type: custom:mushroom-fan-card
remote.harmony_hub_wk:
hidden: true
quick_access_cards:
- type: custom:mushroom-title-card
title: Security
Expand Down
2 changes: 1 addition & 1 deletion dist/mushroom-strategy.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion src/cards/AreaCard.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ class AreaCard extends AbstractCard {
},
hold_action: {
action: "none",
}
},
};

/**
Expand Down
6 changes: 5 additions & 1 deletion src/chips/ClimateChip.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,11 @@ class ClimateChip {
content: Helper.getCountTemplate("climate", "ne", "off"),
tap_action: {
action: "navigate",
navigation_path: "thermostats",
navigation_path: "climates",
},
hold_action: {
action: "navigate",
navigation_path: "climates",
},
};
}
Expand Down
76 changes: 38 additions & 38 deletions src/mushroom-strategy.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,6 @@ class MushroomStrategy {
type: "custom:mushroom-strategy",
options: {
area,
"entity_config": Helper.strategyOptions.entity_config,
},
},
});
Expand All @@ -84,12 +83,9 @@ class MushroomStrategy {
* @return {Promise<{cards: Object[]}>}
*/
static async generateView(info) {
const exposedDomainIds = Helper.getExposedDomainIds();
const area = info.view.strategy.options.area;
const viewCards = [...(area.extra_cards ?? [])];
const strategyOptions = {
entityConfig: info.view.strategy.options.entity_config,
};
const exposedDomainIds = Helper.getExposedDomainIds();
const area = info.view.strategy.options.area;
const viewCards = [...(area.extra_cards ?? [])];

// Create cards for each domain.
for (const domain of exposedDomainIds) {
Expand All @@ -110,7 +106,7 @@ class MushroomStrategy {
// Create a Title card for the current domain.
const titleCard = new TitleCard(
[area],
Helper.strategyOptions.domains[domain]
Helper.strategyOptions.domains[domain],
).createCard();

if (domain === "sensor") {
Expand All @@ -119,43 +115,44 @@ class MushroomStrategy {
const sensorCards = [];

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.
const sensorState = sensorStates.find(state => state.entity_id === sensor.entity_id);
let cardOptions = {};

if (sensorState?.attributes.unit_of_measurement) {
cardOptions = {
type: "custom:mini-graph-card",
entities: [sensor.entity_id],
};
let cardOptions = Helper.strategyOptions.card_options?.[sensor.entity_id] ?? {};

if (!cardOptions.hidden) {
if (sensorState?.attributes.unit_of_measurement) {
cardOptions = {
...{
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({
type: "vertical-stack",
cards: sensorCards,
});
if (sensorCards.length) {
domainCards.push({
type: "vertical-stack",
cards: sensorCards,
});

domainCards.unshift(titleCard);
}

domainCards.unshift(titleCard);
return domainCards;
}

// Create a card for each domain-entity of the current area.
for (const entity of entities) {
const card = (Helper.strategyOptions.entity_config ?? []).find(
config => config.entity === entity.entity_id,
) ?? new cardModule[className](entity).getCard();
let cardOptions = Helper.strategyOptions.card_options?.[entity.entity_id] ?? {};

domainCards.push(card);
if (!cardOptions.hidden) {
domainCards.push(new cardModule[className](entity, cardOptions).getCard());
}
}

if (domain === "binary_sensor") {
Expand All @@ -172,7 +169,9 @@ class MushroomStrategy {
domainCards = horizontalCards;
}

domainCards.unshift(titleCard);
if (domainCards.length) {
domainCards.unshift(titleCard);
}
}

return domainCards;
Expand Down Expand Up @@ -215,12 +214,13 @@ class MushroomStrategy {
const miscellaneousCards = [
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();
let cardOptions = Helper.strategyOptions.card_options?.[entity.entity_id] ?? {};

miscellaneousCards.push(card);
if (!cardOptions.hidden) {
miscellaneousCards.push(new cardModule.MiscellaneousCard(entity, cardOptions).getCard());
}
}

return miscellaneousCards;
Expand Down
6 changes: 3 additions & 3 deletions src/typedefs.js
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@
* @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[]} [entity_config] Card definition for entities.
* @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.
Expand All @@ -134,9 +134,9 @@
*/

/**
* @typedef {Object} entityConfig Custom card-configuration for an entity on a view card.
* @property {string} entity The id of the entity to create a card for.
* @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
*/

Expand Down
65 changes: 37 additions & 28 deletions src/views/AbstractView.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,43 +63,52 @@ class AbstractView {
*
* @return {Object[] | Promise} An array of card objects.
*/
createViewCards() {
async createViewCards() {
/** @type Object[] */
const viewCards = [this.viewTitleCard];

// 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");

import((`../cards/${className}`)).then(cardModule => {
if (entities.length) {
// Create a Title card for the current area.
areaCards.push(
new TitleCard([area], {
title: area.name,
...this.options["titleCard"],
}).createCard(),
);

// Create a card for each domain-entity of the current area.
for (const entity of entities) {
const card = (Helper.strategyOptions.entity_config ?? []).find(
config => config.entity === entity.entity_id,
) ?? new cardModule[className](entity).getCard();

areaCards.push(card);
}
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] ?? {};

if (cardOptions.hidden) {
continue;
}
});

viewCards.push({
type: "vertical-stack",
cards: areaCards,
});
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;
}

Expand Down

0 comments on commit 140aec8

Please sign in to comment.