From 88af0aa78873946d485daf9f00fdd871a899807e Mon Sep 17 00:00:00 2001 From: Zack Barett Date: Tue, 22 Mar 2022 14:58:03 -0500 Subject: [PATCH] Add entity include and exclude to selector (#12078) Co-authored-by: Paulus Schoutsen --- src/components/entity/ha-entities-picker.ts | 20 ++++++ src/components/entity/ha-entity-picker.ts | 64 +++++++++++++++++-- .../ha-selector/ha-selector-entity.ts | 6 +- src/data/selector.ts | 2 + 4 files changed, 85 insertions(+), 7 deletions(-) diff --git a/src/components/entity/ha-entities-picker.ts b/src/components/entity/ha-entities-picker.ts index 062b79eced..3f6127e303 100644 --- a/src/components/entity/ha-entities-picker.ts +++ b/src/components/entity/ha-entities-picker.ts @@ -46,6 +46,22 @@ class HaEntitiesPickerLight extends LitElement { @property({ type: Array, attribute: "include-unit-of-measurement" }) public includeUnitOfMeasurement?: string[]; + /** + * List of allowed entities to show. Will ignore all other filters. + * @type {Array} + * @attr include-entities + */ + @property({ type: Array, attribute: "include-entities" }) + public includeEntities?: string[]; + + /** + * List of entities to be excluded. + * @type {Array} + * @attr exclude-entities + */ + @property({ type: Array, attribute: "exclude-entities" }) + public excludeEntities?: string[]; + @property({ attribute: "picked-entity-label" }) public pickedEntityLabel?: string; @@ -69,6 +85,8 @@ class HaEntitiesPickerLight extends LitElement { .hass=${this.hass} .includeDomains=${this.includeDomains} .excludeDomains=${this.excludeDomains} + .includeEntities=${this.includeEntities} + .excludeEntities=${this.excludeEntities} .includeDeviceClasses=${this.includeDeviceClasses} .includeUnitOfMeasurement=${this.includeUnitOfMeasurement} .entityFilter=${this._entityFilter} @@ -84,6 +102,8 @@ class HaEntitiesPickerLight extends LitElement { .hass=${this.hass} .includeDomains=${this.includeDomains} .excludeDomains=${this.excludeDomains} + .includeEntities=${this.includeEntities} + .excludeEntities=${this.excludeEntities} .includeDeviceClasses=${this.includeDeviceClasses} .includeUnitOfMeasurement=${this.includeUnitOfMeasurement} .entityFilter=${this._entityFilter} diff --git a/src/components/entity/ha-entity-picker.ts b/src/components/entity/ha-entity-picker.ts index a8d17084c6..9b13c75515 100644 --- a/src/components/entity/ha-entity-picker.ts +++ b/src/components/entity/ha-entity-picker.ts @@ -7,6 +7,7 @@ import memoizeOne from "memoize-one"; import { fireEvent } from "../../common/dom/fire_event"; import { computeDomain } from "../../common/entity/compute_domain"; import { computeStateName } from "../../common/entity/compute_state_name"; +import { caseInsensitiveStringCompare } from "../../common/string/compare"; import { PolymerChangedEvent } from "../../polymer-types"; import { HomeAssistant } from "../../types"; import "../ha-combo-box"; @@ -77,6 +78,22 @@ export class HaEntityPicker extends LitElement { @property({ type: Array, attribute: "include-unit-of-measurement" }) public includeUnitOfMeasurement?: string[]; + /** + * List of allowed entities to show. Will ignore all other filters. + * @type {Array} + * @attr include-entities + */ + @property({ type: Array, attribute: "include-entities" }) + public includeEntities?: string[]; + + /** + * List of entities to be excluded. + * @type {Array} + * @attr exclude-entities + */ + @property({ type: Array, attribute: "exclude-entities" }) + public excludeEntities?: string[]; + @property() public entityFilter?: HaEntityPickerEntityFilterFunc; @property({ type: Boolean }) public hideClearIcon = false; @@ -109,7 +126,9 @@ export class HaEntityPicker extends LitElement { excludeDomains: this["excludeDomains"], entityFilter: this["entityFilter"], includeDeviceClasses: this["includeDeviceClasses"], - includeUnitOfMeasurement: this["includeUnitOfMeasurement"] + includeUnitOfMeasurement: this["includeUnitOfMeasurement"], + includeEntities: this["includeEntities"], + excludeEntities: this["excludeEntities"] ): HassEntityWithCachedName[] => { let states: HassEntityWithCachedName[] = []; @@ -139,6 +158,30 @@ export class HaEntityPicker extends LitElement { ]; } + if (includeEntities) { + entityIds = entityIds.filter((entityId) => + this.includeEntities!.includes(entityId) + ); + + return entityIds + .map((key) => ({ + ...hass!.states[key], + friendly_name: computeStateName(hass!.states[key]) || key, + })) + .sort((entityA, entityB) => + caseInsensitiveStringCompare( + entityA.friendly_name, + entityB.friendly_name + ) + ); + } + + if (excludeEntities) { + entityIds = entityIds.filter( + (entityId) => !excludeEntities!.includes(entityId) + ); + } + if (includeDomains) { entityIds = entityIds.filter((eid) => includeDomains.includes(computeDomain(eid)) @@ -151,10 +194,17 @@ export class HaEntityPicker extends LitElement { ); } - states = entityIds.sort().map((key) => ({ - ...hass!.states[key], - friendly_name: computeStateName(hass!.states[key]) || key, - })); + states = entityIds + .map((key) => ({ + ...hass!.states[key], + friendly_name: computeStateName(hass!.states[key]) || key, + })) + .sort((entityA, entityB) => + caseInsensitiveStringCompare( + entityA.friendly_name, + entityB.friendly_name + ) + ); if (includeDeviceClasses) { states = states.filter( @@ -231,7 +281,9 @@ export class HaEntityPicker extends LitElement { this.excludeDomains, this.entityFilter, this.includeDeviceClasses, - this.includeUnitOfMeasurement + this.includeUnitOfMeasurement, + this.includeEntities, + this.excludeEntities ); if (this._initedStates) { (this.comboBox as any).filteredItems = this._states; diff --git a/src/components/ha-selector/ha-selector-entity.ts b/src/components/ha-selector/ha-selector-entity.ts index cbc5366953..8bf085f79f 100644 --- a/src/components/ha-selector/ha-selector-entity.ts +++ b/src/components/ha-selector/ha-selector-entity.ts @@ -6,8 +6,8 @@ import { subscribeEntityRegistry } from "../../data/entity_registry"; import { EntitySelector } from "../../data/selector"; import { SubscribeMixin } from "../../mixins/subscribe-mixin"; import { HomeAssistant } from "../../types"; -import "../entity/ha-entity-picker"; import "../entity/ha-entities-picker"; +import "../entity/ha-entity-picker"; @customElement("ha-selector-entity") export class HaEntitySelector extends SubscribeMixin(LitElement) { @@ -29,6 +29,8 @@ export class HaEntitySelector extends SubscribeMixin(LitElement) { .hass=${this.hass} .value=${this.value} .label=${this.label} + .includeEntities=${this.selector.entity.includeEntities} + .excludeEntities=${this.selector.entity.excludeEntities} .entityFilter=${this._filterEntities} .disabled=${this.disabled} allow-custom-entity @@ -41,6 +43,8 @@ export class HaEntitySelector extends SubscribeMixin(LitElement) { .hass=${this.hass} .value=${this.value} .entityFilter=${this._filterEntities} + .includeEntities=${this.selector.entity.includeEntities} + .excludeEntities=${this.selector.entity.excludeEntities} > `; } diff --git a/src/data/selector.ts b/src/data/selector.ts index b48c11b179..aba717b4a7 100644 --- a/src/data/selector.ts +++ b/src/data/selector.ts @@ -28,6 +28,8 @@ export interface EntitySelector { domain?: string | string[]; device_class?: string; multiple?: boolean; + includeEntities?: string[]; + excludeEntities?: string[]; }; }