diff --git a/src/components/device/ha-device-picker.ts b/src/components/device/ha-device-picker.ts index d93e717b27..c51032eee9 100644 --- a/src/components/device/ha-device-picker.ts +++ b/src/components/device/ha-device-picker.ts @@ -84,6 +84,14 @@ export class HaDevicePicker extends SubscribeMixin(LitElement) { @property({ type: Array, attribute: "include-device-classes" }) public includeDeviceClasses?: string[]; + /** + * List of devices to be excluded. + * @type {Array} + * @attr exclude-devices + */ + @property({ type: Array, attribute: "exclude-devices" }) + public excludeDevices?: string[]; + @property() public deviceFilter?: HaDevicePickerDeviceFilterFunc; @property({ type: Boolean }) public disabled?: boolean; @@ -104,7 +112,8 @@ export class HaDevicePicker extends SubscribeMixin(LitElement) { includeDomains: this["includeDomains"], excludeDomains: this["excludeDomains"], includeDeviceClasses: this["includeDeviceClasses"], - deviceFilter: this["deviceFilter"] + deviceFilter: this["deviceFilter"], + excludeDevices: this["excludeDevices"] ): Device[] => { if (!devices.length) { return [ @@ -164,6 +173,12 @@ export class HaDevicePicker extends SubscribeMixin(LitElement) { }); } + if (excludeDevices) { + inputDevices = inputDevices.filter( + (device) => !excludeDevices!.includes(device.id) + ); + } + if (includeDeviceClasses) { inputDevices = inputDevices.filter((device) => { const devEntities = deviceEntityLookup[device.id]; @@ -258,7 +273,8 @@ export class HaDevicePicker extends SubscribeMixin(LitElement) { this.includeDomains, this.excludeDomains, this.includeDeviceClasses, - this.deviceFilter + this.deviceFilter, + this.excludeDevices ); } } diff --git a/src/components/ha-area-picker.ts b/src/components/ha-area-picker.ts index ec242ba8cc..d45f4fdb89 100644 --- a/src/components/ha-area-picker.ts +++ b/src/components/ha-area-picker.ts @@ -73,6 +73,14 @@ export class HaAreaPicker extends LitElement { @property({ type: Array, attribute: "include-device-classes" }) public includeDeviceClasses?: string[]; + /** + * List of areas to be excluded. + * @type {Array} + * @attr exclude-areas + */ + @property({ type: Array, attribute: "exclude-areas" }) + public excludeAreas?: string[]; + @property() public deviceFilter?: HaDevicePickerDeviceFilterFunc; @property() public entityFilter?: (entity: EntityRegistryEntry) => boolean; @@ -109,7 +117,8 @@ export class HaAreaPicker extends LitElement { includeDeviceClasses: this["includeDeviceClasses"], deviceFilter: this["deviceFilter"], entityFilter: this["entityFilter"], - noAdd: this["noAdd"] + noAdd: this["noAdd"], + excludeAreas: this["excludeAreas"] ): AreaRegistryEntry[] => { if (!areas.length) { return [ @@ -235,6 +244,12 @@ export class HaAreaPicker extends LitElement { outputAreas = areas.filter((area) => areaIds!.includes(area.area_id)); } + if (excludeAreas) { + outputAreas = outputAreas.filter( + (area) => !excludeAreas!.includes(area.area_id) + ); + } + if (!outputAreas.length) { outputAreas = [ { @@ -264,7 +279,7 @@ export class HaAreaPicker extends LitElement { (this._init && changedProps.has("_opened") && this._opened) ) { this._init = true; - (this.comboBox as any).items = this._getAreas( + const areas = this._getAreas( Object.values(this.hass.areas), Object.values(this.hass.devices), Object.values(this.hass.entities), @@ -273,8 +288,11 @@ export class HaAreaPicker extends LitElement { this.includeDeviceClasses, this.deviceFilter, this.entityFilter, - this.noAdd + this.noAdd, + this.excludeAreas ); + (this.comboBox as any).items = areas; + (this.comboBox as any).filteredItems = areas; } } @@ -384,7 +402,8 @@ export class HaAreaPicker extends LitElement { this.includeDeviceClasses, this.deviceFilter, this.entityFilter, - this.noAdd + this.noAdd, + this.excludeAreas ); await this.updateComplete; await this.comboBox.updateComplete; diff --git a/src/components/ha-target-picker.ts b/src/components/ha-target-picker.ts index 09336afc65..3aa581b441 100644 --- a/src/components/ha-target-picker.ts +++ b/src/components/ha-target-picker.ts @@ -345,6 +345,7 @@ export class HaTargetPicker extends SubscribeMixin(LitElement) { .entityFilter=${this.entityRegFilter} .includeDeviceClasses=${this.includeDeviceClasses} .includeDomains=${this.includeDomains} + .excludeAreas=${ensureArray(this.value?.area_id)} @value-changed=${this._targetPicked} > `; @@ -360,6 +361,7 @@ export class HaTargetPicker extends SubscribeMixin(LitElement) { .deviceFilter=${this.deviceFilter} .includeDeviceClasses=${this.includeDeviceClasses} .includeDomains=${this.includeDomains} + .excludeDevices=${ensureArray(this.value?.device_id)} @value-changed=${this._targetPicked} > `; @@ -375,6 +377,7 @@ export class HaTargetPicker extends SubscribeMixin(LitElement) { .entityFilter=${this.entityFilter} .includeDeviceClasses=${this.includeDeviceClasses} .includeDomains=${this.includeDomains} + .excludeEntities=${ensureArray(this.value?.entity_id)} @value-changed=${this._targetPicked} allow-custom-entity > @@ -392,6 +395,13 @@ export class HaTargetPicker extends SubscribeMixin(LitElement) { const target = ev.currentTarget; target.value = ""; this._addMode = undefined; + if ( + this.value && + this.value[target.type] && + ensureArray(this.value[target.type]).includes(value) + ) { + return; + } fireEvent(this, "value-changed", { value: this.value ? {