Isolate hass state from base el (#3157)

This commit is contained in:
Paulus Schoutsen 2019-05-03 20:26:01 -07:00 committed by GitHub
parent 8729410dce
commit fcdb1b48a2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
24 changed files with 274 additions and 268 deletions

View File

@ -1,4 +1,4 @@
import { HomeAssistantAppEl } from "../../src/layouts/app/home-assistant";
import { HomeAssistantAppEl } from "../../src/layouts/home-assistant";
import {
provideHass,
MockHomeAssistant,
@ -18,7 +18,7 @@ import { HomeAssistant } from "../../src/types";
import { mockFrontend } from "./stubs/frontend";
class HaDemo extends HomeAssistantAppEl {
protected async _handleConnProm() {
protected async _initialize() {
const initial: Partial<MockHomeAssistant> = {
panelUrl: (this as any).panelUrl,
// Override updateHass so that the correct hass lifecycle methods are called

View File

@ -14,7 +14,7 @@ import {
} from "lit-element";
import { HomeAssistant } from "../../types";
import { HassEntity } from "home-assistant-js-websocket";
import { forwardHaptic } from "../../util/haptics";
import { forwardHaptic } from "../../data/haptics";
const isOn = (stateObj?: HassEntity) =>
stateObj !== undefined && !STATES_OFF.includes(stateObj.state);
@ -90,7 +90,7 @@ class HaEntityToggle extends LitElement {
if (!this.hass || !this.stateObj) {
return;
}
forwardHaptic(this, "light");
forwardHaptic("light");
const stateDomain = computeStateDomain(this.stateObj);
let serviceDomain;
let service;

View File

@ -0,0 +1,22 @@
/**
* Broadcast connection status updates
*/
import { fireEvent, HASSDomEvent } from "../common/dom/fire_event";
export type ConnectionStatus = "connected" | "auth-invalid" | "disconnected";
declare global {
// for fire event
interface HASSDomEvents {
"connection-status": ConnectionStatus;
}
interface GlobalEventHandlersEventMap {
"connection-status": HASSDomEvent<ConnectionStatus>;
}
}
export const broadcastConnectionStatus = (status: ConnectionStatus) => {
fireEvent(window, "connection-status", status);
};

View File

@ -1,5 +1,5 @@
/**
* Utility function that enables haptic feedback
* Broadcast haptic feedback requests
*/
import { fireEvent, HASSDomEvent } from "../common/dom/fire_event";
@ -27,6 +27,6 @@ declare global {
}
}
export const forwardHaptic = (el: HTMLElement, hapticType: HapticType) => {
fireEvent(el, "haptic", hapticType);
export const forwardHaptic = (hapticType: HapticType) => {
fireEvent(window, "haptic", hapticType);
};

View File

@ -11,7 +11,7 @@ import "../resources/roboto";
// properly into iron-meta, which is used to transfer iconsets to iron-icon.
import "../components/ha-iconset-svg";
import "../layouts/app/home-assistant";
import "../layouts/home-assistant";
setPassiveTouchGestures(true);
/* LastPass createElement workaround. See #428 */

View File

@ -1,7 +1,7 @@
import { ExternalMessaging } from "./external_messaging";
export const externalForwardConnectionEvents = (bus: ExternalMessaging) => {
document.addEventListener("connection-status", (ev) =>
window.addEventListener("connection-status", (ev) =>
bus.fireMessage({
type: "connection-status",
payload: { event: ev.detail },
@ -10,6 +10,6 @@ export const externalForwardConnectionEvents = (bus: ExternalMessaging) => {
};
export const externalForwardHaptics = (bus: ExternalMessaging) =>
document.addEventListener("haptic", (ev) =>
window.addEventListener("haptic", (ev) =>
bus.fireMessage({ type: "haptic", payload: { hapticType: ev.detail } })
);

View File

@ -1,161 +0,0 @@
import {
ERR_INVALID_AUTH,
subscribeEntities,
subscribeConfig,
subscribeServices,
callService,
} from "home-assistant-js-websocket";
import { translationMetadata } from "../../resources/translations-metadata";
import LocalizeMixin from "../../mixins/localize-mixin";
import EventsMixin from "../../mixins/events-mixin";
import { getState } from "../../util/ha-pref-storage";
import { getLocalLanguage } from "../../util/hass-translation";
import { fetchWithAuth } from "../../util/fetch-with-auth";
import hassCallApi from "../../util/hass-call-api";
import { subscribePanels } from "../../data/ws-panels";
import { forwardHaptic } from "../../util/haptics";
import { fireEvent } from "../../common/dom/fire_event";
export default (superClass) =>
class extends EventsMixin(LocalizeMixin(superClass)) {
firstUpdated(changedProps) {
super.firstUpdated(changedProps);
this._handleConnProm();
}
async _handleConnProm() {
let auth;
let conn;
try {
const result = await window.hassConnection;
auth = result.auth;
conn = result.conn;
} catch (err) {
this._error = true;
return;
}
this.hass = Object.assign(
{
auth,
connection: conn,
connected: true,
states: null,
config: null,
themes: null,
panels: null,
services: null,
user: null,
panelUrl: this._panelUrl,
language: getLocalLanguage(),
// If resources are already loaded, don't discard them
resources: (this.hass && this.hass.resources) || null,
localize: () => "",
translationMetadata: translationMetadata,
dockedSidebar: false,
moreInfoEntityId: null,
callService: async (domain, service, serviceData = {}) => {
if (__DEV__) {
// eslint-disable-next-line
console.log("Calling service", domain, service, serviceData);
}
try {
await callService(conn, domain, service, serviceData);
} catch (err) {
if (__DEV__) {
// eslint-disable-next-line
console.error(
"Error calling service",
domain,
service,
serviceData,
err
);
}
forwardHaptic(this, "error");
const message =
this.hass.localize(
"ui.notification_toast.service_call_failed",
"service",
`${domain}/${service}`
) + ` ${err.message}`;
this.fire("hass-notification", { message });
throw err;
}
},
callApi: async (method, path, parameters) =>
hassCallApi(auth, method, path, parameters),
fetchWithAuth: (path, init) =>
fetchWithAuth(auth, `${auth.data.hassUrl}${path}`, init),
// For messages that do not get a response
sendWS: (msg) => {
if (__DEV__) {
// eslint-disable-next-line
console.log("Sending", msg);
}
conn.sendMessage(msg);
},
// For messages that expect a response
callWS: (msg) => {
if (__DEV__) {
/* eslint-disable no-console */
console.log("Sending", msg);
}
const resp = conn.sendMessagePromise(msg);
if (__DEV__) {
resp.then(
(result) => console.log("Received", result),
(err) => console.error("Error", err)
);
}
return resp;
},
},
getState()
);
this.hassConnected();
}
hassConnected() {
super.hassConnected();
const conn = this.hass.connection;
fireEvent(document, "connection-status", "connected");
conn.addEventListener("ready", () => this.hassReconnected());
conn.addEventListener("disconnected", () => this.hassDisconnected());
// If we reconnect after losing connection and auth is no longer valid.
conn.addEventListener("reconnect-error", (_conn, err) => {
if (err === ERR_INVALID_AUTH) {
fireEvent(document, "connection-status", "auth-invalid");
location.reload();
}
});
subscribeEntities(conn, (states) => this._updateHass({ states }));
subscribeConfig(conn, (config) => this._updateHass({ config }));
subscribeServices(conn, (services) => this._updateHass({ services }));
subscribePanels(conn, (panels) => this._updateHass({ panels }));
}
hassReconnected() {
super.hassReconnected();
this._updateHass({ connected: true });
fireEvent(document, "connection-status", "connected");
}
hassDisconnected() {
super.hassDisconnected();
this._updateHass({ connected: false });
fireEvent(document, "connection-status", "disconnected");
}
};

View File

@ -1,45 +1,20 @@
import "@polymer/app-route/app-location";
import { html, LitElement, PropertyValues, css, property } from "lit-element";
import "../home-assistant-main";
import "../ha-init-page";
import "../../resources/ha-style";
import { registerServiceWorker } from "../../util/register-service-worker";
import { DEFAULT_PANEL } from "../../common/const";
import "./home-assistant-main";
import "./ha-init-page";
import "../resources/ha-style";
import { registerServiceWorker } from "../util/register-service-worker";
import { DEFAULT_PANEL } from "../common/const";
import HassBaseMixin from "./hass-base-mixin";
import AuthMixin from "./auth-mixin";
import TranslationsMixin from "./translations-mixin";
import ThemesMixin from "./themes-mixin";
import MoreInfoMixin from "./more-info-mixin";
import SidebarMixin from "./sidebar-mixin";
import { dialogManagerMixin } from "./dialog-manager-mixin";
import ConnectionMixin from "./connection-mixin";
import NotificationMixin from "./notification-mixin";
import DisconnectToastMixin from "./disconnect-toast-mixin";
import { urlSyncMixin } from "./url-sync-mixin";
import { Route, HomeAssistant } from "../../types";
import { navigate } from "../../common/navigate";
import { Route, HomeAssistant } from "../types";
import { navigate } from "../common/navigate";
import { HassElement } from "../state/hass-element";
(LitElement.prototype as any).html = html;
(LitElement.prototype as any).css = css;
const ext = <T>(baseClass: T, mixins): T =>
mixins.reduceRight((base, mixin) => mixin(base), baseClass);
export class HomeAssistantAppEl extends ext(HassBaseMixin(LitElement), [
AuthMixin,
ThemesMixin,
TranslationsMixin,
MoreInfoMixin,
SidebarMixin,
DisconnectToastMixin,
ConnectionMixin,
NotificationMixin,
dialogManagerMixin,
urlSyncMixin,
]) {
export class HomeAssistantAppEl extends HassElement {
@property() private _route?: Route;
@property() private _error?: boolean;
@property() private _panelUrl?: string;
@ -69,6 +44,7 @@ export class HomeAssistantAppEl extends ext(HassBaseMixin(LitElement), [
protected firstUpdated(changedProps) {
super.firstUpdated(changedProps);
this._initialize();
setTimeout(registerServiceWorker, 1000);
/* polyfill for paper-dropdown */
import(/* webpackChunkName: "polyfill-web-animations-next" */ "web-animations-js/web-animations-next-lite.min");
@ -86,6 +62,16 @@ export class HomeAssistantAppEl extends ext(HassBaseMixin(LitElement), [
}
}
protected async _initialize() {
try {
const { auth, conn } = await window.hassConnection;
this.initializeHass(auth, conn);
} catch (err) {
this._error = true;
return;
}
}
private _routeChanged(ev) {
const route = ev.detail.value as Route;
// If it's the first route that we process,

View File

@ -13,7 +13,7 @@ import { PaperToggleButtonElement } from "@polymer/paper-toggle-button/paper-tog
import { DOMAINS_TOGGLE } from "../../../common/const";
import { turnOnOffEntities } from "../common/entity/turn-on-off-entities";
import { HomeAssistant } from "../../../types";
import { forwardHaptic } from "../../../util/haptics";
import { forwardHaptic } from "../../../data/haptics";
@customElement("hui-entities-toggle")
class HuiEntitiesToggle extends LitElement {
@ -66,7 +66,7 @@ class HuiEntitiesToggle extends LitElement {
}
private _callService(ev: MouseEvent): void {
forwardHaptic(this, "light");
forwardHaptic("light");
const turnOn = (ev.target as PaperToggleButtonElement).checked;
turnOnOffEntities(this.hass!, this._toggleEntities!, turnOn!);
}

View File

@ -21,7 +21,7 @@ import { HomeAssistant, InputSelectEntity } from "../../../types";
import { EntityRow, EntityConfig } from "./types";
import { setInputSelectOption } from "../../../data/input-select";
import { hasConfigOrEntityChanged } from "../common/has-changed";
import { forwardHaptic } from "../../../util/haptics";
import { forwardHaptic } from "../../../data/haptics";
import { stopPropagation } from "../../../common/dom/stop_propagation";
@customElement("hui-input-select-entity-row")
@ -128,7 +128,7 @@ class HuiInputSelectEntityRow extends LitElement implements EntityRow {
return;
}
forwardHaptic(this, "light");
forwardHaptic("light");
setInputSelectOption(
this.hass!,

View File

@ -1,16 +1,5 @@
import * as translationMetadata_ from "../../build-translations/translationMetadata.json";
interface TranslationMetadata {
fragments: string[];
translations: {
[language: string]: {
nativeName: string;
fingerprints: {
[filename: string]: string;
};
};
};
}
import { TranslationMetadata } from "../types.js";
export const translationMetadata = (translationMetadata_ as any)
.default as TranslationMetadata;

View File

@ -1,6 +1,6 @@
import { clearState } from "../../util/ha-pref-storage";
import { askWrite } from "../../common/auth/token_storage";
import { subscribeUser, userCollection } from "../../data/ws-user";
import { clearState } from "../util/ha-pref-storage";
import { askWrite } from "../common/auth/token_storage";
import { subscribeUser, userCollection } from "../data/ws-user";
import { Constructor, LitElement } from "lit-element";
import { HassBaseEl } from "./hass-base-mixin";
@ -30,7 +30,7 @@ export default (superClass: Constructor<LitElement & HassBaseEl>) =>
if (askWrite()) {
this.updateComplete
.then(() =>
import(/* webpackChunkName: "ha-store-auth-card" */ "../../dialogs/ha-store-auth-card")
import(/* webpackChunkName: "ha-store-auth-card" */ "../dialogs/ha-store-auth-card")
)
.then(() => {
const el = document.createElement("ha-store-auth-card");

View File

@ -0,0 +1,149 @@
import {
ERR_INVALID_AUTH,
subscribeEntities,
subscribeConfig,
subscribeServices,
callService,
Auth,
Connection,
} from "home-assistant-js-websocket";
import { translationMetadata } from "../resources/translations-metadata";
import { getState } from "../util/ha-pref-storage";
import { getLocalLanguage } from "../util/hass-translation";
import { fetchWithAuth } from "../util/fetch-with-auth";
import hassCallApi from "../util/hass-call-api";
import { subscribePanels } from "../data/ws-panels";
import { forwardHaptic } from "../data/haptics";
import { fireEvent } from "../common/dom/fire_event";
import { Constructor, LitElement } from "lit-element";
import { HassBaseEl } from "./hass-base-mixin";
import { broadcastConnectionStatus } from "../data/connection-status";
export const connectionMixin = (
superClass: Constructor<LitElement & HassBaseEl>
) =>
class extends superClass {
protected initializeHass(auth: Auth, conn: Connection) {
this.hass = {
auth,
connection: conn,
connected: true,
states: null as any,
config: null as any,
themes: null as any,
panels: null as any,
services: null as any,
user: null as any,
panelUrl: (this as any)._panelUrl,
language: getLocalLanguage(),
selectedLanguage: null,
resources: null as any,
localize: () => "",
translationMetadata,
dockedSidebar: false,
moreInfoEntityId: null,
callService: async (domain, service, serviceData = {}) => {
if (__DEV__) {
// tslint:disable-next-line: no-console
console.log("Calling service", domain, service, serviceData);
}
try {
await callService(conn, domain, service, serviceData);
} catch (err) {
if (__DEV__) {
// tslint:disable-next-line: no-console
console.error(
"Error calling service",
domain,
service,
serviceData,
err
);
}
forwardHaptic("failure");
const message =
(this as any).hass.localize(
"ui.notification_toast.service_call_failed",
"service",
`${domain}/${service}`
) + ` ${err.message}`;
fireEvent(this as any, "hass-notification", { message });
throw err;
}
},
callApi: async (method, path, parameters) =>
hassCallApi(auth, method, path, parameters),
fetchWithAuth: (path, init) =>
fetchWithAuth(auth, `${auth.data.hassUrl}${path}`, init),
// For messages that do not get a response
sendWS: (msg) => {
if (__DEV__) {
// tslint:disable-next-line: no-console
console.log("Sending", msg);
}
conn.sendMessage(msg);
},
// For messages that expect a response
callWS: <T>(msg) => {
if (__DEV__) {
// tslint:disable-next-line: no-console
console.log("Sending", msg);
}
const resp = conn.sendMessagePromise<T>(msg);
if (__DEV__) {
resp.then(
// tslint:disable-next-line: no-console
(result) => console.log("Received", result),
// tslint:disable-next-line: no-console
(err) => console.error("Error", err)
);
}
return resp;
},
...getState(),
};
this.hassConnected();
}
protected hassConnected() {
super.hassConnected();
const conn = this.hass!.connection;
broadcastConnectionStatus("connected");
conn.addEventListener("ready", () => this.hassReconnected());
conn.addEventListener("disconnected", () => this.hassDisconnected());
// If we reconnect after losing connection and auth is no longer valid.
conn.addEventListener("reconnect-error", (_conn, err) => {
if (err === ERR_INVALID_AUTH) {
broadcastConnectionStatus("auth-invalid");
location.reload();
}
});
subscribeEntities(conn, (states) => this._updateHass({ states }));
subscribeConfig(conn, (config) => this._updateHass({ config }));
subscribeServices(conn, (services) => this._updateHass({ services }));
subscribePanels(conn, (panels) => this._updateHass({ panels }));
}
protected hassReconnected() {
super.hassReconnected();
this._updateHass({ connected: true });
broadcastConnectionStatus("connected");
}
protected hassDisconnected() {
super.hassDisconnected();
this._updateHass({ connected: false });
broadcastConnectionStatus("disconnected");
}
};

View File

@ -1,10 +1,7 @@
import { Constructor, LitElement } from "lit-element";
import { HASSDomEvent } from "../../common/dom/fire_event";
import { HASSDomEvent } from "../common/dom/fire_event";
import { HassBaseEl } from "./hass-base-mixin";
import {
makeDialogManager,
showDialog,
} from "../../dialogs/make-dialog-manager";
import { makeDialogManager, showDialog } from "../dialogs/make-dialog-manager";
interface RegisterDialogParams {
dialogShowEvent: keyof HASSDomEvents;

View File

@ -1,7 +1,7 @@
import { Constructor, LitElement } from "lit-element";
import { HassBaseEl } from "./hass-base-mixin";
import { HaToast } from "../../components/ha-toast";
import { computeRTL } from "../../common/util/compute_rtl";
import { HaToast } from "../components/ha-toast";
import { computeRTL } from "../common/util/compute_rtl";
export default (superClass: Constructor<LitElement & HassBaseEl>) =>
class extends superClass {
@ -10,7 +10,7 @@ export default (superClass: Constructor<LitElement & HassBaseEl>) =>
protected firstUpdated(changedProps) {
super.firstUpdated(changedProps);
// Need to load in advance because when disconnected, can't dynamically load code.
import(/* webpackChunkName: "ha-toast" */ "../../components/ha-toast");
import(/* webpackChunkName: "ha-toast" */ "../components/ha-toast");
}
protected hassReconnected() {

View File

@ -3,12 +3,14 @@ import {
// @ts-ignore
property,
} from "lit-element";
import { HomeAssistant } from "../../types";
import { Auth, Connection } from "home-assistant-js-websocket";
import { HomeAssistant } from "../types";
/* tslint:disable */
export class HassBaseEl {
protected hass?: HomeAssistant;
protected initializeHass(_auth: Auth, _conn: Connection) {}
protected hassConnected() {}
protected hassReconnected() {}
protected hassDisconnected() {}

28
src/state/hass-element.ts Normal file
View File

@ -0,0 +1,28 @@
import HassBaseMixin from "./hass-base-mixin";
import AuthMixin from "./auth-mixin";
import TranslationsMixin from "./translations-mixin";
import ThemesMixin from "./themes-mixin";
import MoreInfoMixin from "./more-info-mixin";
import SidebarMixin from "./sidebar-mixin";
import { dialogManagerMixin } from "./dialog-manager-mixin";
import { connectionMixin } from "./connection-mixin";
import NotificationMixin from "./notification-mixin";
import DisconnectToastMixin from "./disconnect-toast-mixin";
import { urlSyncMixin } from "./url-sync-mixin";
import { LitElement } from "lit-element";
const ext = <T>(baseClass: T, mixins): T =>
mixins.reduceRight((base, mixin) => mixin(base), baseClass);
export class HassElement extends ext(HassBaseMixin(LitElement), [
AuthMixin,
ThemesMixin,
TranslationsMixin,
MoreInfoMixin,
SidebarMixin,
DisconnectToastMixin,
connectionMixin,
NotificationMixin,
dialogManagerMixin,
urlSyncMixin,
]) {}

View File

@ -20,7 +20,7 @@ export default (superClass: Constructor<LitElement & HassBaseEl>) =>
this.addEventListener("hass-more-info", (e) => this._handleMoreInfo(e));
// Load it once we are having the initial rendering done.
import(/* webpackChunkName: "more-info-dialog" */ "../../dialogs/ha-more-info-dialog");
import(/* webpackChunkName: "more-info-dialog" */ "../dialogs/ha-more-info-dialog");
}
private async _handleMoreInfo(ev) {

View File

@ -6,7 +6,7 @@ export default (superClass) =>
dialogShowEvent: "hass-notification",
dialogTag: "notification-manager",
dialogImport: () =>
import(/* webpackChunkName: "notification-manager" */ "../../managers/notification-manager"),
import(/* webpackChunkName: "notification-manager" */ "../managers/notification-manager"),
});
}
};

View File

@ -1,7 +1,7 @@
import { storeState } from "../../util/ha-pref-storage";
import { storeState } from "../util/ha-pref-storage";
import { Constructor, LitElement } from "lit-element";
import { HassBaseEl } from "./hass-base-mixin";
import { HASSDomEvent } from "../../common/dom/fire_event";
import { HASSDomEvent } from "../common/dom/fire_event";
interface DockSidebarParams {
dock: boolean;

View File

@ -1,9 +1,9 @@
import applyThemesOnElement from "../../common/dom/apply_themes_on_element";
import { storeState } from "../../util/ha-pref-storage";
import { subscribeThemes } from "../../data/ws-themes";
import applyThemesOnElement from "../common/dom/apply_themes_on_element";
import { storeState } from "../util/ha-pref-storage";
import { subscribeThemes } from "../data/ws-themes";
import { Constructor, LitElement } from "lit-element";
import { HassBaseEl } from "./hass-base-mixin";
import { HASSDomEvent } from "../../common/dom/fire_event";
import { HASSDomEvent } from "../common/dom/fire_event";
declare global {
// for add event listener

View File

@ -1,17 +1,17 @@
import { translationMetadata } from "../../resources/translations-metadata";
import { translationMetadata } from "../resources/translations-metadata";
import {
getTranslation,
getLocalLanguage,
getUserLanguage,
} from "../../util/hass-translation";
} from "../util/hass-translation";
import { Constructor, LitElement } from "lit-element";
import { HassBaseEl } from "./hass-base-mixin";
import { computeLocalize } from "../../common/translations/localize";
import { computeRTL } from "../../common/util/compute_rtl";
import { HomeAssistant } from "../../types";
import { saveFrontendUserData } from "../../data/frontend";
import { storeState } from "../../util/ha-pref-storage";
import { getHassTranslations } from "../../data/translation";
import { computeLocalize } from "../common/translations/localize";
import { computeRTL } from "../common/util/compute_rtl";
import { HomeAssistant } from "../types";
import { saveFrontendUserData } from "../data/frontend";
import { storeState } from "../util/ha-pref-storage";
import { getHassTranslations } from "../data/translation";
/*
* superClass needs to contain `this.hass` and `this._updateHass`.

View File

@ -1,6 +1,6 @@
import { Constructor, LitElement } from "lit-element";
import { HassBaseEl } from "./hass-base-mixin";
import { fireEvent } from "../../common/dom/fire_event";
import { fireEvent } from "../common/dom/fire_event";
/* tslint:disable:no-console */
const DEBUG = false;

View File

@ -10,7 +10,6 @@ import {
} from "home-assistant-js-websocket";
import { LocalizeFunc } from "./common/translations/localize";
import { ExternalMessaging } from "./external_app/external_messaging";
import { HASSDomEvent } from "./common/dom/fire_event";
declare global {
var __DEV__: boolean;
@ -38,16 +37,9 @@ declare global {
value: unknown;
};
change: undefined;
"connection-status": ConnectionStatus;
}
interface GlobalEventHandlersEventMap {
"connection-status": HASSDomEvent<ConnectionStatus>;
}
}
type ConnectionStatus = "connected" | "auth-invalid" | "disconnected";
export interface WebhookError {
code: number;
message: string;
@ -103,6 +95,13 @@ export interface Translation {
fingerprints: { [fragment: string]: string };
}
export interface TranslationMetadata {
fragments: string[];
translations: {
[lang: string]: Translation;
};
}
export interface Notification {
notification_id: string;
message: string;
@ -135,18 +134,13 @@ export interface HomeAssistant {
// - english (en)
language: string;
// local stored language, keep that name for backward compability
selectedLanguage: string;
selectedLanguage: string | null;
resources: Resources;
localize: LocalizeFunc;
translationMetadata: {
fragments: string[];
translations: {
[lang: string]: Translation;
};
};
translationMetadata: TranslationMetadata;
dockedSidebar: boolean;
moreInfoEntityId: string;
moreInfoEntityId: string | null;
user?: CurrentUser;
callService: (
domain: string,
@ -162,7 +156,7 @@ export interface HomeAssistant {
path: string,
init?: { [key: string]: any }
) => Promise<Response>;
sendWS: (msg: MessageBase) => Promise<void>;
sendWS: (msg: MessageBase) => void;
callWS: <T>(msg: MessageBase) => Promise<T>;
}