From e8086b6a6f0f74ab945e0851622c316d493877f2 Mon Sep 17 00:00:00 2001 From: Zack Barett Date: Thu, 7 Jul 2022 07:27:28 -0500 Subject: [PATCH 1/5] Refactor History Panel Code a bit (#13129) Co-authored-by: D3v01dZA --- src/data/area_registry.ts | 42 ++++++ src/data/device_registry.ts | 16 +++ src/panels/history/ha-panel-history.ts | 172 +++++++------------------ 3 files changed, 108 insertions(+), 122 deletions(-) diff --git a/src/data/area_registry.ts b/src/data/area_registry.ts index ffb3d4c153..c316785cfc 100644 --- a/src/data/area_registry.ts +++ b/src/data/area_registry.ts @@ -3,6 +3,8 @@ import { Store } from "home-assistant-js-websocket/dist/store"; import { stringCompare } from "../common/string/compare"; import { debounce } from "../common/util/debounce"; import { HomeAssistant } from "../types"; +import { DeviceRegistryEntry } from "./device_registry"; +import { EntityRegistryEntry } from "./entity_registry"; export interface AreaRegistryEntry { area_id: string; @@ -10,6 +12,14 @@ export interface AreaRegistryEntry { picture: string | null; } +export interface AreaEntityLookup { + [areaId: string]: EntityRegistryEntry[]; +} + +export interface AreaDeviceLookup { + [areaId: string]: DeviceRegistryEntry[]; +} + export interface AreaRegistryEntryMutableParams { name: string; picture?: string | null; @@ -79,3 +89,35 @@ export const subscribeAreaRegistry = ( conn, onChange ); + +export const getAreaEntityLookup = ( + entities: EntityRegistryEntry[] +): AreaEntityLookup => { + const areaEntityLookup: AreaEntityLookup = {}; + for (const entity of entities) { + if (!entity.area_id) { + continue; + } + if (!(entity.area_id in areaEntityLookup)) { + areaEntityLookup[entity.area_id] = []; + } + areaEntityLookup[entity.area_id].push(entity); + } + return areaEntityLookup; +}; + +export const getAreaDeviceLookup = ( + devices: DeviceRegistryEntry[] +): AreaDeviceLookup => { + const areaDeviceLookup: AreaDeviceLookup = {}; + for (const device of devices) { + if (!device.area_id) { + continue; + } + if (!(device.area_id in areaDeviceLookup)) { + areaDeviceLookup[device.area_id] = []; + } + areaDeviceLookup[device.area_id].push(device); + } + return areaDeviceLookup; +}; diff --git a/src/data/device_registry.ts b/src/data/device_registry.ts index 6fb72404aa..63b050c856 100644 --- a/src/data/device_registry.ts +++ b/src/data/device_registry.ts @@ -126,3 +126,19 @@ export const sortDeviceRegistryByName = (entries: DeviceRegistryEntry[]) => entries.sort((entry1, entry2) => caseInsensitiveStringCompare(entry1.name || "", entry2.name || "") ); + +export const getDeviceEntityLookup = ( + entities: EntityRegistryEntry[] +): DeviceEntityLookup => { + const deviceEntityLookup: DeviceEntityLookup = {}; + for (const entity of entities) { + if (!entity.device_id) { + continue; + } + if (!(entity.device_id in deviceEntityLookup)) { + deviceEntityLookup[entity.device_id] = []; + } + deviceEntityLookup[entity.device_id].push(entity); + } + return deviceEntityLookup; +}; diff --git a/src/panels/history/ha-panel-history.ts b/src/panels/history/ha-panel-history.ts index ec643ea537..135620f5ed 100644 --- a/src/panels/history/ha-panel-history.ts +++ b/src/panels/history/ha-panel-history.ts @@ -18,8 +18,6 @@ import { css, html, LitElement, PropertyValues } from "lit"; import { property, state } from "lit/decorators"; import { LocalStorage } from "../../common/decorators/local-storage"; import { ensureArray } from "../../common/ensure-array"; -import { computeDomain } from "../../common/entity/compute_domain"; -import { computeStateName } from "../../common/entity/compute_state_name"; import { navigate } from "../../common/navigate"; import { createSearchParam, @@ -34,13 +32,17 @@ import "../../components/ha-icon-button"; import "../../components/ha-menu-button"; import "../../components/ha-target-picker"; import { - DeviceRegistryEntry, + AreaDeviceLookup, + AreaEntityLookup, + getAreaDeviceLookup, + getAreaEntityLookup, +} from "../../data/area_registry"; +import { + DeviceEntityLookup, + getDeviceEntityLookup, subscribeDeviceRegistry, } from "../../data/device_registry"; -import { - EntityRegistryEntry, - subscribeEntityRegistry, -} from "../../data/entity_registry"; +import { subscribeEntityRegistry } from "../../data/entity_registry"; import { computeHistory, fetchDateWS } from "../../data/history"; import "../../layouts/ha-app-layout"; import { SubscribeMixin } from "../../mixins/subscribe-mixin"; @@ -67,23 +69,11 @@ class HaPanelHistory extends SubscribeMixin(LitElement) { @state() private _ranges?: DateRangePickerRanges; - @state() private _devices?: { [deviceId: string]: DeviceRegistryEntry }; + @state() private _deviceEntityLookup?: DeviceEntityLookup; - @state() private _entities?: { [entityId: string]: EntityRegistryEntry }; + @state() private _areaEntityLookup?: AreaEntityLookup; - @state() private _stateEntities?: { [entityId: string]: EntityRegistryEntry }; - - @state() private _deviceIdToEntities?: { - [deviceId: string]: EntityRegistryEntry[]; - }; - - @state() private _areaIdToEntities?: { - [areaId: string]: EntityRegistryEntry[]; - }; - - @state() private _areaIdToDevices?: { - [areaId: string]: DeviceRegistryEntry[]; - }; + @state() private _areaDeviceLookup?: AreaDeviceLookup; public constructor() { super(); @@ -100,52 +90,11 @@ class HaPanelHistory extends SubscribeMixin(LitElement) { public hassSubscribe(): UnsubscribeFunc[] { return [ subscribeEntityRegistry(this.hass.connection!, (entities) => { - this._entities = entities.reduce((accumulator, current) => { - accumulator[current.entity_id] = current; - return accumulator; - }, {}); - this._deviceIdToEntities = entities.reduce((accumulator, current) => { - if (!current.device_id) { - return accumulator; - } - let found = accumulator[current.device_id]; - if (found === undefined) { - found = []; - accumulator[current.device_id] = found; - } - found.push(current); - return accumulator; - }, {}); - this._areaIdToEntities = entities.reduce((accumulator, current) => { - if (!current.area_id) { - return accumulator; - } - let found = accumulator[current.area_id]; - if (found === undefined) { - found = []; - accumulator[current.area_id] = found; - } - found.push(current); - return accumulator; - }, {}); + this._deviceEntityLookup = getDeviceEntityLookup(entities); + this._areaEntityLookup = getAreaEntityLookup(entities); }), subscribeDeviceRegistry(this.hass.connection!, (devices) => { - this._devices = devices.reduce((accumulator, current) => { - accumulator[current.id] = current; - return accumulator; - }, {}); - this._areaIdToDevices = devices.reduce((accumulator, current) => { - if (!current.area_id) { - return accumulator; - } - let found = accumulator[current.area_id]; - if (found === undefined) { - found = []; - accumulator[current.area_id] = found; - } - found.push(current); - return accumulator; - }, {}); + this._areaDeviceLookup = getAreaDeviceLookup(devices); }), ]; } @@ -282,12 +231,9 @@ class HaPanelHistory extends SubscribeMixin(LitElement) { changedProps.has("_endDate") || changedProps.has("_targetPickerValue") || (!this._stateHistory && - (changedProps.has("_entities") || - changedProps.has("_devices") || - changedProps.has("_stateEntities") || - changedProps.has("_deviceIdToEntities") || - changedProps.has("_areaIdToEntities") || - changedProps.has("_areaIdToDevices")))) + (changedProps.has("_deviceEntityLookup") || + changedProps.has("_areaEntityLookup") || + changedProps.has("_areaDeviceLookup")))) ) { this._getHistory(); } @@ -300,29 +246,6 @@ class HaPanelHistory extends SubscribeMixin(LitElement) { if (!oldHass || oldHass.language !== this.hass.language) { this.rtl = computeRTL(this.hass); } - - if (this._entities) { - const stateEntities: { [entityId: string]: EntityRegistryEntry } = {}; - const regEntityIds = new Set(Object.keys(this._entities)); - for (const entityId of Object.keys(this.hass.states)) { - if (regEntityIds.has(entityId)) { - continue; - } - stateEntities[entityId] = { - name: computeStateName(this.hass.states[entityId]), - entity_id: entityId, - platform: computeDomain(entityId), - disabled_by: null, - hidden_by: null, - area_id: null, - config_entry_id: null, - device_id: null, - icon: null, - entity_category: null, - }; - } - this._stateEntities = stateEntities; - } } private _removeAll() { @@ -363,15 +286,13 @@ class HaPanelHistory extends SubscribeMixin(LitElement) { private _getEntityIds(): string[] | undefined { if ( !this._targetPickerValue || - this._entities === undefined || - this._stateEntities === undefined || - this._devices === undefined || - this._deviceIdToEntities === undefined || - this._areaIdToEntities === undefined || - this._areaIdToDevices === undefined + this._deviceEntityLookup === undefined || + this._areaEntityLookup === undefined || + this._areaDeviceLookup === undefined ) { return undefined; } + const entityIds = new Set(); let { area_id: searchingAreaId, @@ -382,7 +303,7 @@ class HaPanelHistory extends SubscribeMixin(LitElement) { if (searchingAreaId) { searchingAreaId = ensureArray(searchingAreaId); for (const singleSearchingAreaId of searchingAreaId) { - const foundEntities = this._areaIdToEntities[singleSearchingAreaId]; + const foundEntities = this._areaEntityLookup[singleSearchingAreaId]; if (foundEntities?.length) { for (const foundEntity of foundEntities) { if (foundEntity.entity_category === null) { @@ -391,19 +312,24 @@ class HaPanelHistory extends SubscribeMixin(LitElement) { } } - const foundDevices = this._areaIdToDevices[singleSearchingAreaId]; - if (foundDevices) { - for (const foundDevice of foundDevices) { - const foundDeviceEntities = - this._deviceIdToEntities[foundDevice.id]; - for (const foundDeviceEntity of foundDeviceEntities) { - if ( - (!foundDeviceEntity.area_id || - foundDeviceEntity.area_id === singleSearchingAreaId) && - foundDeviceEntity.entity_category === null - ) { - entityIds.add(foundDeviceEntity.entity_id); - } + const foundDevices = this._areaDeviceLookup[singleSearchingAreaId]; + if (!foundDevices?.length) { + continue; + } + + for (const foundDevice of foundDevices) { + const foundDeviceEntities = this._deviceEntityLookup[foundDevice.id]; + if (!foundDeviceEntities?.length) { + continue; + } + + for (const foundDeviceEntity of foundDeviceEntities) { + if ( + (!foundDeviceEntity.area_id || + foundDeviceEntity.area_id === singleSearchingAreaId) && + foundDeviceEntity.entity_category === null + ) { + entityIds.add(foundDeviceEntity.entity_id); } } } @@ -413,18 +339,20 @@ class HaPanelHistory extends SubscribeMixin(LitElement) { if (searchingDeviceId) { searchingDeviceId = ensureArray(searchingDeviceId); for (const singleSearchingDeviceId of searchingDeviceId) { - const foundEntities = this._deviceIdToEntities[singleSearchingDeviceId]; - if (foundEntities?.length) { - for (const foundEntity of foundEntities) { - if (foundEntity.entity_category === null) { - entityIds.add(foundEntity.entity_id); - } + const foundEntities = this._deviceEntityLookup[singleSearchingDeviceId]; + if (!foundEntities?.length) { + continue; + } + + for (const foundEntity of foundEntities) { + if (foundEntity.entity_category === null) { + entityIds.add(foundEntity.entity_id); } } } } - if (searchingEntityId !== undefined) { + if (searchingEntityId) { searchingEntityId = ensureArray(searchingEntityId); for (const singleSearchingEntityId of searchingEntityId) { entityIds.add(singleSearchingEntityId); From 24688ba18e4167f092189e82adc1ff200b1699cb Mon Sep 17 00:00:00 2001 From: Bram Kragten Date: Thu, 7 Jul 2022 14:58:51 +0200 Subject: [PATCH 2/5] fix reload history when no selection made (#13137) --- src/panels/history/ha-panel-history.ts | 34 +++++++++++++++----------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/src/panels/history/ha-panel-history.ts b/src/panels/history/ha-panel-history.ts index 135620f5ed..d750ba5143 100644 --- a/src/panels/history/ha-panel-history.ts +++ b/src/panels/history/ha-panel-history.ts @@ -121,7 +121,7 @@ class HaPanelHistory extends SubscribeMixin(LitElement) { : ""} @@ -254,10 +254,14 @@ class HaPanelHistory extends SubscribeMixin(LitElement) { } private async _getHistory() { + if (!this._targetPickerValue) { + return; + } this._isLoading = true; const entityIds = this._getEntityIds(); if (entityIds === undefined) { + this._isLoading = false; this._stateHistory = undefined; return; } @@ -267,20 +271,22 @@ class HaPanelHistory extends SubscribeMixin(LitElement) { this._stateHistory = []; return; } + try { + const dateHistory = await fetchDateWS( + this.hass, + this._startDate, + this._endDate, + entityIds + ); - const dateHistory = await fetchDateWS( - this.hass, - this._startDate, - this._endDate, - entityIds - ); - - this._stateHistory = computeHistory( - this.hass, - dateHistory, - this.hass.localize - ); - this._isLoading = false; + this._stateHistory = computeHistory( + this.hass, + dateHistory, + this.hass.localize + ); + } finally { + this._isLoading = false; + } } private _getEntityIds(): string[] | undefined { From 87aab72b6394227b97dde499bb0758a742cdcc3b Mon Sep 17 00:00:00 2001 From: Bram Kragten Date: Thu, 7 Jul 2022 15:01:29 +0200 Subject: [PATCH 3/5] opti search params history --- src/panels/history/ha-panel-history.ts | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/panels/history/ha-panel-history.ts b/src/panels/history/ha-panel-history.ts index d750ba5143..8be17099f5 100644 --- a/src/panels/history/ha-panel-history.ts +++ b/src/panels/history/ha-panel-history.ts @@ -21,7 +21,7 @@ import { ensureArray } from "../../common/ensure-array"; import { navigate } from "../../common/navigate"; import { createSearchParam, - extractSearchParam, + extractSearchParamsObject, } from "../../common/url/search-params"; import { computeRTL } from "../../common/util/compute_rtl"; import "../../components/chart/state-history-charts"; @@ -195,9 +195,10 @@ class HaPanelHistory extends SubscribeMixin(LitElement) { [addDays(weekStart, -7), addDays(weekEnd, -7)], }; - const entityIds = extractSearchParam("entity_id"); - const deviceIds = extractSearchParam("device_id"); - const areaIds = extractSearchParam("area_id"); + const searchParams = extractSearchParamsObject(); + const entityIds = searchParams.entity_id; + const deviceIds = searchParams.device_id; + const areaIds = searchParams.area_id; if (entityIds || deviceIds || areaIds) { this._targetPickerValue = {}; } @@ -214,11 +215,11 @@ class HaPanelHistory extends SubscribeMixin(LitElement) { this._targetPickerValue!.area_id = splitIds; } - const startDate = extractSearchParam("start_date"); + const startDate = searchParams.start_date; if (startDate) { this._startDate = new Date(startDate); } - const endDate = extractSearchParam("end_date"); + const endDate = searchParams.end_date; if (endDate) { this._endDate = new Date(endDate); } From f8bccf9e79e6794703a69c98a28f16d812b4635a Mon Sep 17 00:00:00 2001 From: Bram Kragten Date: Thu, 7 Jul 2022 15:02:08 +0200 Subject: [PATCH 4/5] Bumped version to 20220707.0 --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 1432ca6257..7eb2cd6854 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "home-assistant-frontend" -version = "20220706.0" +version = "20220707.0" license = {text = "Apache-2.0"} description = "The Home Assistant frontend" readme = "README.md" From 399efca41179aa3cae48a8f9a5dc7c94ca2994af Mon Sep 17 00:00:00 2001 From: Raman Gupta <7243222+raman325@users.noreply.github.com> Date: Thu, 7 Jul 2022 09:03:11 -0400 Subject: [PATCH 5/5] Only show firmware update warning if no firmware update is in progress (#13068) --- .../integration-elements/zwave_js/device-actions.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/panels/config/devices/device-detail/integration-elements/zwave_js/device-actions.ts b/src/panels/config/devices/device-detail/integration-elements/zwave_js/device-actions.ts index 180d33adb0..3ff12f5386 100644 --- a/src/panels/config/devices/device-detail/integration-elements/zwave_js/device-actions.ts +++ b/src/panels/config/devices/device-detail/integration-elements/zwave_js/device-actions.ts @@ -99,6 +99,13 @@ export const getZwaveDeviceActions = async ( ), action: async () => { if ( + isNodeFirmwareUpdateInProgress || + (await fetchZwaveNodeIsFirmwareUpdateInProgress(hass, device.id)) + ) { + showZWaveJUpdateFirmwareNodeDialog(el, { + device, + }); + } else if ( await showConfirmationDialog(el, { text: hass.localize( "ui.panel.config.zwave_js.update_firmware.warning"