Expand entity-filter options (#3692)

* Expand entity-filter options

Closes https://github.com/home-assistant/home-assistant-polymer/issues/3543

Adds the following to `state_filter`:
- `operator` option. Specify operator to use in comparison.
- `value` option. Specify value to compare against.
- `attribute` option.  Specify attribute to use instead of state in comparison.

e.g.
```yaml
type: entity-filter
state_filter:
  - "on"
  - operator: ">"
    value: 90
entities:
  - sensor.water_leak
  - sensor.outside_temp
  - entity: sensor.humidity_and_temp
    state_filter:
      operator: ">"
      value: 50
      attribute: humidity
```

* Update evaluate-filter.ts

* verify state_filter exists on card or each entity

* address review comments

* apply Bram's suggestion

* address review comments

* cleanup
This commit is contained in:
Ian Richardson 2019-09-24 03:34:57 -05:00 committed by Bram Kragten
parent 38b817bd67
commit 886c6dd88c
4 changed files with 72 additions and 8 deletions

View File

@ -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) {

View File

@ -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<EntityConfig | string>;
state_filter: string[];
entities: Array<EntityFilterEntityConfig | string>;
state_filter: Array<{ key: string } | string>;
card: Partial<LovelaceCardConfig>;
show_empty?: boolean;
}

View File

@ -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;
}
};

View File

@ -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;