Area dashboard improvement (#24690)

* Add more domains in the areas dashboard and strip area name from the entity name

* Display cover without device classes

* Remove useless test
This commit is contained in:
Paul Bottein 2025-03-19 23:19:58 +01:00 committed by GitHub
parent 2c0c48106d
commit 7ce166e40f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 126 additions and 53 deletions

View File

@ -54,10 +54,7 @@ export const generateEntityFilter = (
} }
} }
if (deviceClasses) { if (deviceClasses) {
const dc = stateObj.attributes.device_class; const dc = stateObj.attributes.device_class || "none";
if (!dc) {
return false;
}
if (!deviceClasses.has(dc)) { if (!deviceClasses.has(dc)) {
return false; return false;
} }

View File

@ -5,15 +5,10 @@ import type { LovelaceCardConfig } from "../../../../data/lovelace/config/card";
import type { LovelaceSectionRawConfig } from "../../../../data/lovelace/config/section"; import type { LovelaceSectionRawConfig } from "../../../../data/lovelace/config/section";
import type { LovelaceViewConfig } from "../../../../data/lovelace/config/view"; import type { LovelaceViewConfig } from "../../../../data/lovelace/config/view";
import type { HomeAssistant } from "../../../../types"; import type { HomeAssistant } from "../../../../types";
import { supportsAlarmModesCardFeature } from "../../card-features/hui-alarm-modes-card-feature";
import { supportsCoverOpenCloseCardFeature } from "../../card-features/hui-cover-open-close-card-feature";
import { supportsLightBrightnessCardFeature } from "../../card-features/hui-light-brightness-card-feature";
import { supportsLockCommandsCardFeature } from "../../card-features/hui-lock-commands-card-feature";
import { supportsTargetTemperatureCardFeature } from "../../card-features/hui-target-temperature-card-feature";
import type { LovelaceCardFeatureConfig } from "../../card-features/types";
import { import {
AREA_STRATEGY_GROUP_ICONS, AREA_STRATEGY_GROUP_ICONS,
AREA_STRATEGY_GROUP_LABELS, AREA_STRATEGY_GROUP_LABELS,
computeAreaTileCardConfig,
getAreaGroupedEntities, getAreaGroupedEntities,
} from "./helpers/area-strategy-helper"; } from "./helpers/area-strategy-helper";
@ -28,41 +23,6 @@ export interface AreaViewStrategyConfig {
groups_options?: Record<string, EntitiesDisplay>; groups_options?: Record<string, EntitiesDisplay>;
} }
const computeTileCardConfig =
(hass: HomeAssistant) =>
(entity: string): LovelaceCardConfig => {
const stateObj = hass.states[entity];
let feature: LovelaceCardFeatureConfig | undefined;
if (supportsLightBrightnessCardFeature(stateObj)) {
feature = {
type: "light-brightness",
};
} else if (supportsCoverOpenCloseCardFeature(stateObj)) {
feature = {
type: "cover-open-close",
};
} else if (supportsTargetTemperatureCardFeature(stateObj)) {
feature = {
type: "target-temperature",
};
} else if (supportsAlarmModesCardFeature(stateObj)) {
feature = {
type: "alarm-modes",
};
} else if (supportsLockCommandsCardFeature(stateObj)) {
feature = {
type: "lock-commands",
};
}
return {
type: "tile",
entity: entity,
features: feature ? [feature] : undefined,
};
};
const computeHeadingCard = ( const computeHeadingCard = (
heading: string, heading: string,
icon: string icon: string
@ -114,9 +74,10 @@ export class AreaViewStrategy extends ReactiveElement {
config.groups_options config.groups_options
); );
const computeTileCard = computeTileCardConfig(hass); const computeTileCard = computeAreaTileCardConfig(hass, area.name, true);
const { lights, climate, media_players, security } = groupedEntities; const { lights, climate, media_players, security, others } =
groupedEntities;
if (lights.length > 0) { if (lights.length > 0) {
sections.push({ sections.push({
@ -170,6 +131,19 @@ export class AreaViewStrategy extends ReactiveElement {
}); });
} }
if (others.length > 0) {
sections.push({
type: "grid",
cards: [
computeHeadingCard(
AREA_STRATEGY_GROUP_LABELS.others,
AREA_STRATEGY_GROUP_ICONS.others
),
...others.map(computeTileCard),
],
});
}
return { return {
type: "sections", type: "sections",
header: { header: {

View File

@ -3,9 +3,12 @@ import { customElement } from "lit/decorators";
import type { LovelaceSectionConfig } from "../../../../data/lovelace/config/section"; import type { LovelaceSectionConfig } from "../../../../data/lovelace/config/section";
import type { LovelaceViewConfig } from "../../../../data/lovelace/config/view"; import type { LovelaceViewConfig } from "../../../../data/lovelace/config/view";
import type { HomeAssistant } from "../../../../types"; import type { HomeAssistant } from "../../../../types";
import { getAreaGroupedEntities } from "./helpers/area-strategy-helper";
import { computeAreaPath, getAreas } from "./helpers/areas-strategy-helpers";
import type { EntitiesDisplay } from "./area-view-strategy"; import type { EntitiesDisplay } from "./area-view-strategy";
import {
computeAreaTileCardConfig,
getAreaGroupedEntities,
} from "./helpers/area-strategy-helper";
import { computeAreaPath, getAreas } from "./helpers/areas-strategy-helpers";
interface AreaOptions { interface AreaOptions {
groups_options?: Record<string, EntitiesDisplay>; groups_options?: Record<string, EntitiesDisplay>;
@ -49,8 +52,11 @@ export class AreasViewStrategy extends ReactiveElement {
...groups.climate, ...groups.climate,
...groups.media_players, ...groups.media_players,
...groups.security, ...groups.security,
...groups.others,
]; ];
const computeTileCard = computeAreaTileCardConfig(hass, area.name);
return { return {
type: "grid", type: "grid",
cards: [ cards: [
@ -72,10 +78,7 @@ export class AreasViewStrategy extends ReactiveElement {
}, },
}, },
...(entities.length ...(entities.length
? entities.map((entity) => ({ ? entities.map(computeTileCard)
type: "tile",
entity: entity,
}))
: [ : [
{ {
type: "markdown", type: "markdown",

View File

@ -1,13 +1,25 @@
import { computeDomain } from "../../../../../common/entity/compute_domain";
import { computeStateName } from "../../../../../common/entity/compute_state_name";
import type { EntityFilterFunc } from "../../../../../common/entity/entity_filter"; import type { EntityFilterFunc } from "../../../../../common/entity/entity_filter";
import { generateEntityFilter } from "../../../../../common/entity/entity_filter"; import { generateEntityFilter } from "../../../../../common/entity/entity_filter";
import { stripPrefixFromEntityName } from "../../../../../common/entity/strip_prefix_from_entity_name";
import { orderCompare } from "../../../../../common/string/compare"; import { orderCompare } from "../../../../../common/string/compare";
import type { LovelaceCardConfig } from "../../../../../data/lovelace/config/card";
import type { HomeAssistant } from "../../../../../types"; import type { HomeAssistant } from "../../../../../types";
import { supportsAlarmModesCardFeature } from "../../../card-features/hui-alarm-modes-card-feature";
import { supportsCoverOpenCloseCardFeature } from "../../../card-features/hui-cover-open-close-card-feature";
import { supportsLightBrightnessCardFeature } from "../../../card-features/hui-light-brightness-card-feature";
import { supportsLockCommandsCardFeature } from "../../../card-features/hui-lock-commands-card-feature";
import { supportsTargetTemperatureCardFeature } from "../../../card-features/hui-target-temperature-card-feature";
import type { LovelaceCardFeatureConfig } from "../../../card-features/types";
import type { TileCardConfig } from "../../../cards/types";
export const AREA_STRATEGY_GROUPS = [ export const AREA_STRATEGY_GROUPS = [
"lights", "lights",
"climate", "climate",
"media_players", "media_players",
"security", "security",
"others",
] as const; ] as const;
export const AREA_STRATEGY_GROUP_ICONS = { export const AREA_STRATEGY_GROUP_ICONS = {
@ -15,6 +27,7 @@ export const AREA_STRATEGY_GROUP_ICONS = {
climate: "mdi:home-thermometer", climate: "mdi:home-thermometer",
media_players: "mdi:multimedia", media_players: "mdi:multimedia",
security: "mdi:security", security: "mdi:security",
others: "mdi:shape",
}; };
// Todo be replace by translation when validated // Todo be replace by translation when validated
@ -23,6 +36,7 @@ export const AREA_STRATEGY_GROUP_LABELS = {
climate: "Climate", climate: "Climate",
media_players: "Entertainment", media_players: "Entertainment",
security: "Security", security: "Security",
others: "Others",
}; };
export type AreaStrategyGroup = (typeof AREA_STRATEGY_GROUPS)[number]; export type AreaStrategyGroup = (typeof AREA_STRATEGY_GROUPS)[number];
@ -75,9 +89,15 @@ export const getAreaGroupedEntities = (
"shade", "shade",
"shutter", "shutter",
"window", "window",
"none",
], ],
entity_category: "none", entity_category: "none",
}), }),
generateEntityFilter(hass, {
domain: "fan",
area: area,
entity_category: "none",
}),
generateEntityFilter(hass, { generateEntityFilter(hass, {
domain: "binary_sensor", domain: "binary_sensor",
area: area, area: area,
@ -109,6 +129,11 @@ export const getAreaGroupedEntities = (
area: area, area: area,
entity_category: "none", entity_category: "none",
}), }),
generateEntityFilter(hass, {
domain: "camera",
area: area,
entity_category: "none",
}),
generateEntityFilter(hass, { generateEntityFilter(hass, {
domain: "binary_sensor", domain: "binary_sensor",
device_class: ["door", "garage_door"], device_class: ["door", "garage_door"],
@ -116,6 +141,28 @@ export const getAreaGroupedEntities = (
entity_category: "none", entity_category: "none",
}), }),
], ],
others: [
generateEntityFilter(hass, {
domain: "vacuum",
area: area,
entity_category: "none",
}),
generateEntityFilter(hass, {
domain: "lawn_mower",
area: area,
entity_category: "none",
}),
generateEntityFilter(hass, {
domain: "valve",
area: area,
entity_category: "none",
}),
generateEntityFilter(hass, {
domain: "switch",
area: area,
entity_category: "none",
}),
],
}; };
return Object.fromEntries( return Object.fromEntries(
@ -147,3 +194,55 @@ export const getAreaGroupedEntities = (
}) })
) as AreaEntitiesByGroup; ) as AreaEntitiesByGroup;
}; };
export const computeAreaTileCardConfig =
(hass: HomeAssistant, prefix: string, includeFeature?: boolean) =>
(entity: string): LovelaceCardConfig => {
const stateObj = hass.states[entity];
const additionalCardConfig: Partial<TileCardConfig> = {};
const domain = computeDomain(entity);
if (domain === "camera") {
additionalCardConfig.show_entity_picture = true;
}
let feature: LovelaceCardFeatureConfig | undefined;
if (includeFeature) {
if (supportsLightBrightnessCardFeature(stateObj)) {
feature = {
type: "light-brightness",
};
} else if (supportsCoverOpenCloseCardFeature(stateObj)) {
feature = {
type: "cover-open-close",
};
} else if (supportsTargetTemperatureCardFeature(stateObj)) {
feature = {
type: "target-temperature",
};
} else if (supportsAlarmModesCardFeature(stateObj)) {
feature = {
type: "alarm-modes",
};
} else if (supportsLockCommandsCardFeature(stateObj)) {
feature = {
type: "lock-commands",
};
}
}
if (feature) {
additionalCardConfig.features = [feature];
}
const name = computeStateName(stateObj);
const stripedName = stripPrefixFromEntityName(name, prefix.toLowerCase());
return {
type: "tile",
entity: entity,
name: stripedName,
...additionalCardConfig,
};
};