From ecc6fcf862bad7780cebdca93b04bfdbedb75228 Mon Sep 17 00:00:00 2001 From: Robbie Trencheny Date: Thu, 13 Feb 2020 17:47:08 -0800 Subject: [PATCH 1/9] Hide HTML5 push notification toggle if inside external app (#4860) * Hide HTML5 push notification toggle if external bus is engaged * Use isExternal instead * Hide the whole row * Black * Fix import Co-authored-by: Paulus Schoutsen --- src/data/external.ts | 4 ++++ src/entrypoints/core.ts | 6 +----- src/panels/profile/ha-panel-profile.ts | 13 +++++++++---- 3 files changed, 14 insertions(+), 9 deletions(-) create mode 100644 src/data/external.ts diff --git a/src/data/external.ts b/src/data/external.ts new file mode 100644 index 0000000000..3701f58e5e --- /dev/null +++ b/src/data/external.ts @@ -0,0 +1,4 @@ +export const isExternal = + window.externalApp || + window.webkit?.messageHandlers?.getExternalAuth || + location.search.includes("external_auth=1"); diff --git a/src/entrypoints/core.ts b/src/entrypoints/core.ts index c44f03d892..60688ee147 100644 --- a/src/entrypoints/core.ts +++ b/src/entrypoints/core.ts @@ -10,6 +10,7 @@ import { } from "home-assistant-js-websocket"; import { loadTokens, saveTokens } from "../common/auth/token_storage"; +import { isExternal } from "../data/external"; import { subscribePanels } from "../data/ws-panels"; import { subscribeThemes } from "../data/ws-themes"; import { subscribeUser } from "../data/ws-user"; @@ -23,11 +24,6 @@ declare global { } } -const isExternal = - window.externalApp || - window.webkit?.messageHandlers?.getExternalAuth || - location.search.includes("external_auth=1"); - const authProm = isExternal ? () => import( diff --git a/src/panels/profile/ha-panel-profile.ts b/src/panels/profile/ha-panel-profile.ts index b9ef34afcb..8f1443f898 100644 --- a/src/panels/profile/ha-panel-profile.ts +++ b/src/panels/profile/ha-panel-profile.ts @@ -31,6 +31,7 @@ import { getOptimisticFrontendUserDataCollection, CoreFrontendUserData, } from "../../data/frontend"; +import { isExternal } from "../../data/external"; import { haStyle } from "../../resources/styles"; import { HomeAssistant } from "../../types"; import { fireEvent } from "../../common/dom/fire_event"; @@ -113,10 +114,14 @@ class HaPanelProfile extends LitElement { > ` : ""} - + ${!isExternal + ? html` + + ` + : ""} ${this.hass.user!.is_admin ? html` Date: Tue, 25 Feb 2020 21:51:07 +0100 Subject: [PATCH 2/9] Fix for when the preview element was an error element (#4969) * Fix for when the preview element was an error element * Comments * Update hui-dialog-edit-card.ts --- src/panels/lovelace/cards/hui-error-card.ts | 8 ++++++-- .../editor/card-editor/hui-card-preview.ts | 18 +++++++++--------- .../editor/card-editor/hui-dialog-edit-card.ts | 18 ++++++++++++------ .../card-editor/hui-dialog-suggest-card.ts | 5 +++++ src/panels/lovelace/ha-panel-lovelace.ts | 2 +- 5 files changed, 33 insertions(+), 18 deletions(-) diff --git a/src/panels/lovelace/cards/hui-error-card.ts b/src/panels/lovelace/cards/hui-error-card.ts index e207cbe38b..088703a930 100644 --- a/src/panels/lovelace/cards/hui-error-card.ts +++ b/src/panels/lovelace/cards/hui-error-card.ts @@ -13,7 +13,7 @@ import { LovelaceCard } from "../types"; import { HomeAssistant } from "../../../types"; import { ErrorCardConfig } from "./types"; -export const createErrorCardElement = (config) => { +export const createErrorCardElement = (config: ErrorCardConfig) => { const el = document.createElement("hui-error-card"); el.setConfig(config); return el; @@ -46,7 +46,11 @@ export class HuiErrorCard extends LitElement implements LovelaceCard { return html` ${this._config.error} -
${safeDump(this._config.origConfig)}
+ ${this._config.origConfig + ? html` +
${safeDump(this._config.origConfig)}
+ ` + : ""} `; } diff --git a/src/panels/lovelace/editor/card-editor/hui-card-preview.ts b/src/panels/lovelace/editor/card-editor/hui-card-preview.ts index 9bce069854..8850d46c15 100644 --- a/src/panels/lovelace/editor/card-editor/hui-card-preview.ts +++ b/src/panels/lovelace/editor/card-editor/hui-card-preview.ts @@ -1,7 +1,5 @@ import "@polymer/paper-input/paper-textarea"; -import deepClone from "deep-clone-simple"; - import { createCardElement } from "../../create-element/create-card-element"; import { HomeAssistant } from "../../../../types"; import { LovelaceCardConfig } from "../../../../data/lovelace"; @@ -15,6 +13,10 @@ export class HuiCardPreview extends HTMLElement { private _element?: LovelaceCard; private _config?: LovelaceCardConfig; + private get _error() { + return this._element?.tagName === "HUI-ERROR-CARD"; + } + constructor() { super(); this.addEventListener("ll-rebuild", () => { @@ -37,12 +39,9 @@ export class HuiCardPreview extends HTMLElement { } set error(error: ConfigError) { - const configValue = createErrorCardConfig( - `${error.type}: ${error.message}`, - undefined + this._createCard( + createErrorCardConfig(`${error.type}: ${error.message}`, undefined) ); - - this._createCard(configValue); } set config(configValue: LovelaceCardConfig) { @@ -66,9 +65,10 @@ export class HuiCardPreview extends HTMLElement { return; } - if (curConfig && configValue.type === curConfig.type) { + // in case the element was an error element we always want to recreate it + if (!this._error && curConfig && configValue.type === curConfig.type) { try { - this._element.setConfig(deepClone(configValue)); + this._element.setConfig(configValue); } catch (err) { this._createCard(createErrorCardConfig(err.message, configValue)); } diff --git a/src/panels/lovelace/editor/card-editor/hui-dialog-edit-card.ts b/src/panels/lovelace/editor/card-editor/hui-dialog-edit-card.ts index cc53b1e305..66e3ed2429 100755 --- a/src/panels/lovelace/editor/card-editor/hui-dialog-edit-card.ts +++ b/src/panels/lovelace/editor/card-editor/hui-dialog-edit-card.ts @@ -8,6 +8,8 @@ import { property, } from "lit-element"; +import deepFreeze from "deep-freeze"; + import { HomeAssistant } from "../../../../types"; import { HASSDomEvent } from "../../../../common/dom/fire_event"; import { @@ -55,6 +57,9 @@ export class HuiDialogEditCard extends LitElement { this._viewConfig = params.lovelaceConfig.views[view]; this._cardConfig = card !== undefined ? this._viewConfig.cards![card] : undefined; + if (this._cardConfig && !Object.isFrozen(this._cardConfig)) { + this._cardConfig = deepFreeze(this._cardConfig); + } } private get _cardEditorEl(): HuiCardEditor | null { @@ -248,19 +253,20 @@ export class HuiDialogEditCard extends LitElement { } private _handleCardPicked(ev) { - this._cardConfig = ev.detail.config; + const config = ev.detail.config; if (this._params!.entities && this._params!.entities.length > 0) { - if (Object.keys(this._cardConfig!).includes("entities")) { - this._cardConfig!.entities = this._params!.entities; - } else if (Object.keys(this._cardConfig!).includes("entity")) { - this._cardConfig!.entity = this._params!.entities[0]; + if (Object.keys(config).includes("entities")) { + config.entities = this._params!.entities; + } else if (Object.keys(config).includes("entity")) { + config.entity = this._params!.entities[0]; } } + this._cardConfig = deepFreeze(config); this._error = ev.detail.error; } private _handleConfigChanged(ev) { - this._cardConfig = ev.detail.config; + this._cardConfig = deepFreeze(ev.detail.config); this._error = ev.detail.error; } diff --git a/src/panels/lovelace/editor/card-editor/hui-dialog-suggest-card.ts b/src/panels/lovelace/editor/card-editor/hui-dialog-suggest-card.ts index bc19be2282..b76bf47ed9 100755 --- a/src/panels/lovelace/editor/card-editor/hui-dialog-suggest-card.ts +++ b/src/panels/lovelace/editor/card-editor/hui-dialog-suggest-card.ts @@ -9,6 +9,8 @@ import { query, } from "lit-element"; +import deepFreeze from "deep-freeze"; + import { HomeAssistant } from "../../../../types"; import { LovelaceCardConfig } from "../../../../data/lovelace"; import "./hui-card-editor"; @@ -52,6 +54,9 @@ export class HuiDialogSuggestCard extends LitElement { {}, true ); + if (!Object.isFrozen(this._cardConfig)) { + this._cardConfig = deepFreeze(this._cardConfig); + } if (this._dialog) { this._dialog.open(); } diff --git a/src/panels/lovelace/ha-panel-lovelace.ts b/src/panels/lovelace/ha-panel-lovelace.ts index fcaa54af6c..3ff9faae8c 100644 --- a/src/panels/lovelace/ha-panel-lovelace.ts +++ b/src/panels/lovelace/ha-panel-lovelace.ts @@ -1,5 +1,5 @@ import "@material/mwc-button"; -import * as deepFreeze from "deep-freeze"; +import deepFreeze from "deep-freeze"; import { fetchConfig, From 9162e9c3187fa660dc947c9a1a5ee28f444362e8 Mon Sep 17 00:00:00 2001 From: Bram Kragten Date: Tue, 25 Feb 2020 21:55:36 +0100 Subject: [PATCH 3/9] Bumped version to 20200220.2 --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 76e88054d6..e17bd651d2 100644 --- a/setup.py +++ b/setup.py @@ -2,7 +2,7 @@ from setuptools import setup, find_packages setup( name="home-assistant-frontend", - version="20200220.1", + version="20200220.2", description="The Home Assistant frontend", url="https://github.com/home-assistant/home-assistant-polymer", author="The Home Assistant Authors", From 38d758b52f33b7a7ab373aecdea954cdd977c2fd Mon Sep 17 00:00:00 2001 From: Bram Kragten Date: Tue, 25 Feb 2020 21:56:52 +0100 Subject: [PATCH 4/9] Bumped version to 20200220.3 --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index e17bd651d2..bbe001eeed 100644 --- a/setup.py +++ b/setup.py @@ -2,7 +2,7 @@ from setuptools import setup, find_packages setup( name="home-assistant-frontend", - version="20200220.2", + version="20200220.3", description="The Home Assistant frontend", url="https://github.com/home-assistant/home-assistant-polymer", author="The Home Assistant Authors", From f02bb67485dcc51e14d1f08142c5c7881ca6fbc4 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Wed, 26 Feb 2020 00:40:54 -0800 Subject: [PATCH 5/9] Static import all the LL cards etc (#4987) --- .../create-element/create-badge-element.ts | 13 +++- .../create-element/create-card-element.ts | 64 +++++++++++++---- .../create-header-footer-element.ts | 15 +++- .../create-element/create-row-element.ts | 70 ++++++++++++++----- 4 files changed, 124 insertions(+), 38 deletions(-) diff --git a/src/panels/lovelace/create-element/create-badge-element.ts b/src/panels/lovelace/create-element/create-badge-element.ts index 120a51b98e..95aa0cd584 100644 --- a/src/panels/lovelace/create-element/create-badge-element.ts +++ b/src/panels/lovelace/create-element/create-badge-element.ts @@ -3,9 +3,18 @@ import "../badges/hui-state-label-badge"; import { LovelaceBadgeConfig } from "../../../data/lovelace"; import { createLovelaceElement } from "./create-element-base"; -const ALWAYS_LOADED_TYPES = new Set(["error", "state-label"]); +// lazy load imports +import "../badges/hui-entity-filter-badge"; + +const ALWAYS_LOADED_TYPES = new Set([ + "error", + "state-label", + + // lazy load types + "entity-filter", +]); const LAZY_LOAD_TYPES = { - "entity-filter": () => import("../badges/hui-entity-filter-badge"), + // "entity-filter": () => import("../badges/hui-entity-filter-badge"), }; export const createBadgeElement = (config: LovelaceBadgeConfig) => diff --git a/src/panels/lovelace/create-element/create-card-element.ts b/src/panels/lovelace/create-element/create-card-element.ts index 3669bba1f4..f793ae3d03 100644 --- a/src/panels/lovelace/create-element/create-card-element.ts +++ b/src/panels/lovelace/create-element/create-card-element.ts @@ -16,6 +16,23 @@ import { getLovelaceElementClass, } from "./create-element-base"; +// lazy load imports +import "../cards/hui-alarm-panel-card"; +import "../cards/hui-empty-state-card"; +import "../cards/hui-entity-filter-card"; +import "../cards/hui-picture-elements-card"; +import "../cards/hui-picture-entity-card"; +import "../cards/hui-picture-glance-card"; +import "../cards/hui-plant-status-card"; +import "../cards/hui-safe-mode-card"; +import "../cards/hui-shopping-list-card"; +import "../cards/hui-conditional-card"; +import "../cards/hui-gauge-card"; +import "../cards/hui-iframe-card"; +import "../cards/hui-map-card"; +import "../cards/hui-markdown-card"; +import "../cards/hui-picture-card"; + const ALWAYS_LOADED_TYPES = new Set([ "entities", "button", @@ -30,24 +47,41 @@ const ALWAYS_LOADED_TYPES = new Set([ "thermostat", "vertical-stack", "weather-forecast", + + // Lazy load types + "alarm-panel", + "empty-state", + "entity-filter", + "picture-elements", + "picture-entity", + "picture-glance", + "plant-status", + "safe-mode", + "shopping-list", + "conditional", + "gauge", + "iframe", + "map", + "markdown", + "picture", ]); const LAZY_LOAD_TYPES = { - "alarm-panel": () => import("../cards/hui-alarm-panel-card"), - "empty-state": () => import("../cards/hui-empty-state-card"), - "entity-filter": () => import("../cards/hui-entity-filter-card"), - "picture-elements": () => import("../cards/hui-picture-elements-card"), - "picture-entity": () => import("../cards/hui-picture-entity-card"), - "picture-glance": () => import("../cards/hui-picture-glance-card"), - "plant-status": () => import("../cards/hui-plant-status-card"), - "safe-mode": () => import("../cards/hui-safe-mode-card"), - "shopping-list": () => import("../cards/hui-shopping-list-card"), - conditional: () => import("../cards/hui-conditional-card"), - gauge: () => import("../cards/hui-gauge-card"), - iframe: () => import("../cards/hui-iframe-card"), - map: () => import("../cards/hui-map-card"), - markdown: () => import("../cards/hui-markdown-card"), - picture: () => import("../cards/hui-picture-card"), + // "alarm-panel": () => import("../cards/hui-alarm-panel-card"), + // "empty-state": () => import("../cards/hui-empty-state-card"), + // "entity-filter": () => import("../cards/hui-entity-filter-card"), + // "picture-elements": () => import("../cards/hui-picture-elements-card"), + // "picture-entity": () => import("../cards/hui-picture-entity-card"), + // "picture-glance": () => import("../cards/hui-picture-glance-card"), + // "plant-status": () => import("../cards/hui-plant-status-card"), + // "safe-mode": () => import("../cards/hui-safe-mode-card"), + // "shopping-list": () => import("../cards/hui-shopping-list-card"), + // conditional: () => import("../cards/hui-conditional-card"), + // gauge: () => import("../cards/hui-gauge-card"), + // iframe: () => import("../cards/hui-iframe-card"), + // map: () => import("../cards/hui-map-card"), + // markdown: () => import("../cards/hui-markdown-card"), + // picture: () => import("../cards/hui-picture-card"), }; export const createCardElement = (config: LovelaceCardConfig) => diff --git a/src/panels/lovelace/create-element/create-header-footer-element.ts b/src/panels/lovelace/create-element/create-header-footer-element.ts index f2e2859f3c..a9b97571be 100644 --- a/src/panels/lovelace/create-element/create-header-footer-element.ts +++ b/src/panels/lovelace/create-element/create-header-footer-element.ts @@ -1,16 +1,25 @@ import { LovelaceHeaderFooterConfig } from "../header-footer/types"; import { createLovelaceElement } from "./create-element-base"; +// lazy load imports +import "../header-footer/hui-picture-header-footer"; +import "../header-footer/hui-buttons-header-footer"; + +const ALWAYS_LOADED_TYPES = new Set([ + // lazy load types + "picture", + "buttons", +]); const LAZY_LOAD_TYPES = { - picture: () => import("../header-footer/hui-picture-header-footer"), - buttons: () => import("../header-footer/hui-buttons-header-footer"), + // picture: () => import("../header-footer/hui-picture-header-footer"), + // buttons: () => import("../header-footer/hui-buttons-header-footer"), }; export const createHeaderFooterElement = (config: LovelaceHeaderFooterConfig) => createLovelaceElement( "header-footer", config, - undefined, + ALWAYS_LOADED_TYPES, // replace with undefined when empty LAZY_LOAD_TYPES, undefined, undefined diff --git a/src/panels/lovelace/create-element/create-row-element.ts b/src/panels/lovelace/create-element/create-row-element.ts index d23464f7fb..e8154de5ef 100644 --- a/src/panels/lovelace/create-element/create-row-element.ts +++ b/src/panels/lovelace/create-element/create-row-element.ts @@ -8,6 +8,23 @@ import "../special-rows/hui-call-service-row"; import { EntityConfig } from "../entity-rows/types"; import { createLovelaceElement } from "./create-element-base"; +// lazy load imports +import "../entity-rows/hui-climate-entity-row"; +import "../entity-rows/hui-cover-entity-row"; +import "../entity-rows/hui-group-entity-row"; +import "../entity-rows/hui-input-datetime-entity-row"; +import "../entity-rows/hui-input-number-entity-row"; +import "../entity-rows/hui-input-select-entity-row"; +import "../entity-rows/hui-input-text-entity-row"; +import "../entity-rows/hui-lock-entity-row"; +import "../entity-rows/hui-timer-entity-row"; +import "../special-rows/hui-conditional-row"; +import "../special-rows/hui-divider-row"; +import "../special-rows/hui-section-row"; +import "../special-rows/hui-weblink-row"; +import "../special-rows/hui-cast-row"; +import "../special-rows/hui-buttons-row"; + const ALWAYS_LOADED_TYPES = new Set([ "media-player-entity", "scene-entity", @@ -16,26 +33,43 @@ const ALWAYS_LOADED_TYPES = new Set([ "text-entity", "toggle-entity", "call-service", + + // lazy load types + "climate-entity", + "cover-entity", + "group-entity", + "input-datetime-entity", + "input-number-entity", + "input-select-entity", + "input-text-entity", + "lock-entity", + "timer-entity", + "conditional", + "divider", + "section", + "weblink", + "cast", + "buttons", ]); const LAZY_LOAD_TYPES = { - "climate-entity": () => import("../entity-rows/hui-climate-entity-row"), - "cover-entity": () => import("../entity-rows/hui-cover-entity-row"), - "group-entity": () => import("../entity-rows/hui-group-entity-row"), - "input-datetime-entity": () => - import("../entity-rows/hui-input-datetime-entity-row"), - "input-number-entity": () => - import("../entity-rows/hui-input-number-entity-row"), - "input-select-entity": () => - import("../entity-rows/hui-input-select-entity-row"), - "input-text-entity": () => import("../entity-rows/hui-input-text-entity-row"), - "lock-entity": () => import("../entity-rows/hui-lock-entity-row"), - "timer-entity": () => import("../entity-rows/hui-timer-entity-row"), - conditional: () => import("../special-rows/hui-conditional-row"), - divider: () => import("../special-rows/hui-divider-row"), - section: () => import("../special-rows/hui-section-row"), - weblink: () => import("../special-rows/hui-weblink-row"), - cast: () => import("../special-rows/hui-cast-row"), - buttons: () => import("../special-rows/hui-buttons-row"), + // "climate-entity": () => import("../entity-rows/hui-climate-entity-row"), + // "cover-entity": () => import("../entity-rows/hui-cover-entity-row"), + // "group-entity": () => import("../entity-rows/hui-group-entity-row"), + // "input-datetime-entity": () => + // import("../entity-rows/hui-input-datetime-entity-row"), + // "input-number-entity": () => + // import("../entity-rows/hui-input-number-entity-row"), + // "input-select-entity": () => + // import("../entity-rows/hui-input-select-entity-row"), + // "input-text-entity": () => import("../entity-rows/hui-input-text-entity-row"), + // "lock-entity": () => import("../entity-rows/hui-lock-entity-row"), + // "timer-entity": () => import("../entity-rows/hui-timer-entity-row"), + // conditional: () => import("../special-rows/hui-conditional-row"), + // divider: () => import("../special-rows/hui-divider-row"), + // section: () => import("../special-rows/hui-section-row"), + // weblink: () => import("../special-rows/hui-weblink-row"), + // cast: () => import("../special-rows/hui-cast-row"), + // buttons: () => import("../special-rows/hui-buttons-row"), }; const DOMAIN_TO_ELEMENT_TYPE = { _domain_not_found: "text", From 6d145730a582b3b5378dc0d94e040ab2d1d62e18 Mon Sep 17 00:00:00 2001 From: Bram Kragten Date: Wed, 26 Feb 2020 09:42:10 +0100 Subject: [PATCH 6/9] Bumped version to 20200220.4 --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index bbe001eeed..dabc18fc7b 100644 --- a/setup.py +++ b/setup.py @@ -2,7 +2,7 @@ from setuptools import setup, find_packages setup( name="home-assistant-frontend", - version="20200220.3", + version="20200220.4", description="The Home Assistant frontend", url="https://github.com/home-assistant/home-assistant-polymer", author="The Home Assistant Authors", From 2298a55b161bcbb3949083a234a653f1c1b098ca Mon Sep 17 00:00:00 2001 From: Ian Richardson Date: Thu, 27 Feb 2020 02:20:20 -0600 Subject: [PATCH 7/9] Fix action handling for buttons row (#5007) --- src/panels/lovelace/components/hui-buttons-base.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/panels/lovelace/components/hui-buttons-base.ts b/src/panels/lovelace/components/hui-buttons-base.ts index b7c51f1c35..c0890e51b4 100644 --- a/src/panels/lovelace/components/hui-buttons-base.ts +++ b/src/panels/lovelace/components/hui-buttons-base.ts @@ -73,7 +73,7 @@ export class HuiButtonsBase extends LitElement { const config = (ev.currentTarget as any).config as EntitiesCardEntityConfig; handleAction( this, - this.hass!, + this._hass!, { tap_action: { action: "toggle" }, ...config }, ev.detail.action! ); From 8d65eb1fdf242d71ef620c702666d9d2d613cd97 Mon Sep 17 00:00:00 2001 From: Ian Richardson Date: Wed, 26 Feb 2020 16:03:47 -0600 Subject: [PATCH 8/9] Fix state_color for button (#4995) --- src/panels/lovelace/cards/hui-button-card.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/panels/lovelace/cards/hui-button-card.ts b/src/panels/lovelace/cards/hui-button-card.ts index feff566435..5fe36747da 100644 --- a/src/panels/lovelace/cards/hui-button-card.ts +++ b/src/panels/lovelace/cards/hui-button-card.ts @@ -72,6 +72,7 @@ export class HuiButtonCard extends LitElement implements LovelaceCard { double_tap_action: { action: "none" }, show_icon: true, show_name: true, + state_color: true, ...config, }; From 17c7a3bbac53369b44e6e3289f25effb7e38010e Mon Sep 17 00:00:00 2001 From: Bram Kragten Date: Fri, 28 Feb 2020 15:35:08 +0100 Subject: [PATCH 9/9] Bumped version to 20200220.5 --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index dabc18fc7b..458b6661a1 100644 --- a/setup.py +++ b/setup.py @@ -2,7 +2,7 @@ from setuptools import setup, find_packages setup( name="home-assistant-frontend", - version="20200220.4", + version="20200220.5", description="The Home Assistant frontend", url="https://github.com/home-assistant/home-assistant-polymer", author="The Home Assistant Authors",