diff --git a/src/panels/lovelace/cards/hui-entity-filter-card.ts b/src/panels/lovelace/cards/hui-entity-filter-card.ts index a225065dd4..93dae22a6f 100644 --- a/src/panels/lovelace/cards/hui-entity-filter-card.ts +++ b/src/panels/lovelace/cards/hui-entity-filter-card.ts @@ -2,25 +2,38 @@ import { createCardElement } from "../common/create-card-element"; import { processConfigEntities } from "../common/process-config-entities"; import { LovelaceCard } from "../types"; import { LovelaceCardConfig } from "../../../data/lovelace"; -import { EntityConfig } from "../entity-rows/types"; +import { EntityFilterEntityConfig } from "../entity-rows/types"; import { HomeAssistant } from "../../../types"; import { EntityFilterCardConfig } from "./types"; +import { evaluateFilter } from "../common/evaluate-filter"; class EntityFilterCard extends HTMLElement implements LovelaceCard { public isPanel?: boolean; private _element?: LovelaceCard; private _config?: EntityFilterCardConfig; - private _configEntities?: EntityConfig[]; + private _configEntities?: EntityFilterEntityConfig[]; private _baseCardConfig?: LovelaceCardConfig; private _hass?: HomeAssistant; - private _oldEntities?: EntityConfig[]; + private _oldEntities?: EntityFilterEntityConfig[]; public getCardSize(): number { return this._element ? this._element.getCardSize() : 1; } public setConfig(config: EntityFilterCardConfig): void { - if (!config.state_filter || !Array.isArray(config.state_filter)) { + if (!config.entities || !Array.isArray(config.entities)) { + throw new Error("entities must be specified."); + } + + if ( + !(config.state_filter && Array.isArray(config.state_filter)) && + !config.entities.every( + (entity) => + typeof entity === "object" && + entity.state_filter && + Array.isArray(entity.state_filter) + ) + ) { throw new Error("Incorrect filter config."); } @@ -56,7 +69,26 @@ class EntityFilterCard extends HTMLElement implements LovelaceCard { const entitiesList = this._configEntities.filter((entityConf) => { const stateObj = hass.states[entityConf.entity]; - return stateObj && this._config!.state_filter.includes(stateObj.state); + + if (!stateObj) { + return false; + } + + if (entityConf.state_filter) { + for (const filter of entityConf.state_filter) { + if (evaluateFilter(stateObj, filter)) { + return true; + } + } + } else { + for (const filter of this._config!.state_filter) { + if (evaluateFilter(stateObj, filter)) { + return true; + } + } + } + + return false; }); if (entitiesList.length === 0 && this._config.show_empty === false) { diff --git a/src/panels/lovelace/cards/types.ts b/src/panels/lovelace/cards/types.ts index 8eafdb27e6..9b050b431c 100644 --- a/src/panels/lovelace/cards/types.ts +++ b/src/panels/lovelace/cards/types.ts @@ -1,6 +1,6 @@ import { LovelaceCardConfig, ActionConfig } from "../../../data/lovelace"; import { Condition } from "../common/validate-condition"; -import { EntityConfig } from "../entity-rows/types"; +import { EntityConfig, EntityFilterEntityConfig } from "../entity-rows/types"; import { LovelaceElementConfig } from "../elements/types"; import { HuiImage } from "../components/hui-image"; @@ -50,8 +50,8 @@ export interface EntityButtonCardConfig extends LovelaceCardConfig { export interface EntityFilterCardConfig extends LovelaceCardConfig { type: "entity-filter"; - entities: Array; - state_filter: string[]; + entities: Array; + state_filter: Array<{ key: string } | string>; card: Partial; show_empty?: boolean; } diff --git a/src/panels/lovelace/common/evaluate-filter.ts b/src/panels/lovelace/common/evaluate-filter.ts new file mode 100644 index 0000000000..fd2e341563 --- /dev/null +++ b/src/panels/lovelace/common/evaluate-filter.ts @@ -0,0 +1,29 @@ +import { HassEntity } from "home-assistant-js-websocket"; + +export const evaluateFilter = (stateObj: HassEntity, filter: any): boolean => { + const operator = filter.operator || "=="; + const value = filter.value || filter; + const state = filter.attribute + ? stateObj.attributes[filter.attribute] + : stateObj.state; + + switch (operator) { + case "==": + return state === value; + case "<=": + return state <= value; + case "<": + return state < value; + case ">=": + return state >= value; + case ">": + return state > value; + case "!=": + return state !== value; + case "regex": { + return state.match(value); + } + default: + return false; + } +}; diff --git a/src/panels/lovelace/entity-rows/types.ts b/src/panels/lovelace/entity-rows/types.ts index c827e6b349..b481969266 100644 --- a/src/panels/lovelace/entity-rows/types.ts +++ b/src/panels/lovelace/entity-rows/types.ts @@ -7,6 +7,9 @@ export interface EntityConfig { icon?: string; image?: string; } +export interface EntityFilterEntityConfig extends EntityConfig { + state_filter?: Array<{ key: string } | string>; +} export interface DividerConfig { type: "divider"; style: string;