diff --git a/src/components/ha-floor-icon.ts b/src/components/ha-floor-icon.ts index 595f8add1a..a36b7ec391 100644 --- a/src/components/ha-floor-icon.ts +++ b/src/components/ha-floor-icon.ts @@ -30,6 +30,22 @@ export const floorDefaultIconPath = ( return mdiHome; }; +export const floorDefaultIcon = (floor: Pick) => { + switch (floor.level) { + case 0: + return "mdi:home-floor-0"; + case 1: + return "mdi:home-floor-1"; + case 2: + return "mdi:home-floor-2"; + case 3: + return "mdi:home-floor-3"; + case -1: + return "mdi:home-floor-negative-1"; + } + return "mdi:home"; +}; + @customElement("ha-floor-icon") export class HaFloorIcon extends LitElement { @property({ attribute: false }) public floor!: Pick< diff --git a/src/panels/lovelace/strategies/areas/area-view-strategy.ts b/src/panels/lovelace/strategies/areas/area-view-strategy.ts index 2fc8a0256d..3ce785fbfd 100644 --- a/src/panels/lovelace/strategies/areas/area-view-strategy.ts +++ b/src/panels/lovelace/strategies/areas/area-view-strategy.ts @@ -191,12 +191,6 @@ export class AreaViewStrategy extends ReactiveElement { type: "sections", header: { badges_position: "bottom", - layout: "responsive", - card: { - type: "markdown", - text_only: true, - content: `## ${area.name}`, - }, }, max_columns: maxColumns, sections: sections, diff --git a/src/panels/lovelace/strategies/areas/areas-dashboard-strategy.ts b/src/panels/lovelace/strategies/areas/areas-dashboard-strategy.ts index ef397b4a8e..3b882837bf 100644 --- a/src/panels/lovelace/strategies/areas/areas-dashboard-strategy.ts +++ b/src/panels/lovelace/strategies/areas/areas-dashboard-strategy.ts @@ -66,6 +66,7 @@ export class AreasDashboardStrategy extends ReactiveElement { return { title: area.name, path: path, + subview: true, strategy: { type: "area", area: area.area_id, diff --git a/src/panels/lovelace/strategies/areas/areas-overview-view-strategy.ts b/src/panels/lovelace/strategies/areas/areas-overview-view-strategy.ts index c8cda13888..74bbd0a38c 100644 --- a/src/panels/lovelace/strategies/areas/areas-overview-view-strategy.ts +++ b/src/panels/lovelace/strategies/areas/areas-overview-view-strategy.ts @@ -1,15 +1,15 @@ import { ReactiveElement } from "lit"; import { customElement } from "lit/decorators"; +import { stringCompare } from "../../../../common/string/compare"; +import { floorDefaultIcon } from "../../../../components/ha-floor-icon"; import type { LovelaceSectionConfig } from "../../../../data/lovelace/config/section"; import type { LovelaceViewConfig } from "../../../../data/lovelace/config/view"; import type { HomeAssistant } from "../../../../types"; +import { getAreaControlEntities } from "../../card-features/hui-area-controls-card-feature"; +import type { AreaControl } from "../../card-features/types"; +import type { AreaCardConfig, HeadingCardConfig } from "../../cards/types"; import type { EntitiesDisplay } from "./area-view-strategy"; -import { - computeAreaPath, - computeAreaTileCardConfig, - getAreaGroupedEntities, - getAreas, -} from "./helpers/areas-strategy-helper"; +import { computeAreaPath, getAreas } from "./helpers/areas-strategy-helper"; interface AreaOptions { groups_options?: Record; @@ -36,71 +36,88 @@ export class AreasOverviewViewStrategy extends ReactiveElement { config.areas_display?.order ); - const areaSections = areas - .map((area) => { - const path = computeAreaPath(area.area_id); + const floors = Object.values(hass.floors); + floors.sort((floorA, floorB) => { + if (floorA.level !== floorB.level) { + return (floorA.level ?? 0) - (floorB.level ?? 0); + } + return stringCompare(floorA.name, floorB.name); + }); - const areaConfig = config.areas_options?.[area.area_id]; - - const groups = getAreaGroupedEntities( - area.area_id, - hass, - areaConfig?.groups_options + const floorSections = [ + ...floors, + { floor_id: "default", name: "Default", level: null, icon: null }, + ] + .map((floor) => { + const areasInFloors = areas.filter( + (area) => + area.floor_id === floor.floor_id || + (!area.floor_id && floor.floor_id === "default") ); - const entities = [ - ...groups.lights, - ...groups.covers, - ...groups.climate, - ...groups.media_players, - ...groups.security, - ...groups.actions, - ...groups.others, - ]; + if (areasInFloors.length === 0) { + return undefined; + } - const computeTileCard = computeAreaTileCardConfig(hass, area.name); + const areasCards = areasInFloors.map((area) => { + const path = computeAreaPath(area.area_id); + + const controls: AreaControl[] = ["light", "fan"]; + const controlEntities = getAreaControlEntities( + controls, + area.area_id, + hass + ); + + const filteredControls = controls.filter( + (control) => controlEntities[control].length > 0 + ); + + return { + type: "area", + area: area.area_id, + display_type: "compact", + sensor_classes: ["temperature", "humidity"], + alert_classes: [ + "water_leak", + "smoke", + "gas", + "co", + "motion", + "occupancy", + "presence", + ], + features: filteredControls.length + ? [ + { + type: "area-controls", + controls: filteredControls, + }, + ] + : [], + navigation_path: path, + }; + }); + + const headingCard: HeadingCardConfig = { + type: "heading", + heading_style: "title", + heading: floor.name, + icon: floor.icon || floorDefaultIcon(floor), + }; return { + max_columns: 3, type: "grid", - cards: [ - { - type: "heading", - heading: area.name, - icon: area.icon || undefined, - badges: [ - ...(area.temperature_entity_id - ? [{ entity: area.temperature_entity_id }] - : []), - ...(area.humidity_entity_id - ? [{ entity: area.humidity_entity_id }] - : []), - ], - tap_action: { - action: "navigate", - navigation_path: path, - }, - }, - ...(entities.length - ? entities.map(computeTileCard) - : [ - { - type: "markdown", - content: hass.localize( - "ui.panel.lovelace.strategy.areas.no_entities" - ), - }, - ]), - ], + cards: [headingCard, ...areasCards], }; }) - .filter( - (section): section is LovelaceSectionConfig => section !== undefined - ); + ?.filter((section) => section !== undefined); return { type: "sections", max_columns: 3, - sections: areaSections, + sections: floorSections || [], }; } }