diff --git a/src/external_app/external_events_forwarder.ts b/src/external_app/external_events_forwarder.ts new file mode 100644 index 0000000000..19f9a11ec7 --- /dev/null +++ b/src/external_app/external_events_forwarder.ts @@ -0,0 +1,10 @@ +import { ExternalMessaging } from "./external_messaging"; + +export const externalForwardConnectionEvents = (bus: ExternalMessaging) => { + document.addEventListener("connection-status", (ev) => + bus.fireMessage({ + type: "connection-status", + payload: { event: ev.detail }, + }) + ); +}; diff --git a/src/external_app/external_messaging.ts b/src/external_app/external_messaging.ts index 173fb62606..b2d74dc95a 100644 --- a/src/external_app/external_messaging.ts +++ b/src/external_app/external_messaging.ts @@ -1,3 +1,5 @@ +import { externalForwardConnectionEvents } from "./external_events_forwarder"; + const CALLBACK_EXTERNAL_BUS = "externalBus"; interface CommandInFlight { @@ -8,6 +10,7 @@ interface CommandInFlight { export interface InternalMessage { id?: number; type: string; + payload?: unknown; } interface ExternalError { @@ -37,6 +40,7 @@ export class ExternalMessaging { public msgId = 0; public attach() { + externalForwardConnectionEvents(this); window[CALLBACK_EXTERNAL_BUS] = (msg) => this.receiveMessage(msg); } diff --git a/src/layouts/app/connection-mixin.js b/src/layouts/app/connection-mixin.js index 94bf192926..a3f5fbe993 100644 --- a/src/layouts/app/connection-mixin.js +++ b/src/layouts/app/connection-mixin.js @@ -17,6 +17,7 @@ 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)) { @@ -128,11 +129,16 @@ export default (superClass) => 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) location.reload(); + if (err === ERR_INVALID_AUTH) { + fireEvent(document, "connection-status", "auth-invalid"); + location.reload(); + } }); subscribeEntities(conn, (states) => this._updateHass({ states })); @@ -144,10 +150,12 @@ export default (superClass) => hassReconnected() { super.hassReconnected(); this._updateHass({ connected: true }); + fireEvent(document, "connection-status", "connected"); } hassDisconnected() { super.hassDisconnected(); this._updateHass({ connected: false }); + fireEvent(document, "connection-status", "disconnected"); } }; diff --git a/src/types.ts b/src/types.ts index 4cad83fdf9..e312a1f6b9 100644 --- a/src/types.ts +++ b/src/types.ts @@ -10,6 +10,7 @@ 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; @@ -17,9 +18,7 @@ declare global { var __BUILD__: "latest" | "es5"; var __VERSION__: string; var __STATIC_PATH__: string; -} -declare global { interface Window { // Custom panel entry point url customPanelJS: string; @@ -39,9 +38,16 @@ declare global { value: unknown; }; change: undefined; + "connection-status": ConnectionStatus; + } + + interface GlobalEventHandlersEventMap { + "connection-status": HASSDomEvent; } } +type ConnectionStatus = "connected" | "auth-invalid" | "disconnected"; + export interface WebhookError { code: number; message: string;