Skip to content

Commit

Permalink
Type outgoing messages on EM and add matter (home-assistant#13775)
Browse files Browse the repository at this point in the history
  • Loading branch information
balloob authored Sep 16, 2022
1 parent e1e3f9d commit 614c157
Show file tree
Hide file tree
Showing 3 changed files with 111 additions and 24 deletions.
2 changes: 1 addition & 1 deletion src/components/ha-hls-player.ts
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ class HaHLSPlayer extends LitElement {
window.addEventListener("resize", this._resizeExoPlayer);
this.updateComplete.then(() => nextRender()).then(this._resizeExoPlayer);
this._videoEl.style.visibility = "hidden";
await this.hass!.auth.external!.sendMessage({
await this.hass!.auth.external!.fireMessage({
type: "exoplayer/play_hls",
payload: {
url: new URL(url, window.location.href).toString(),
Expand Down
4 changes: 2 additions & 2 deletions src/external_app/external_app_entrypoint.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ This is the entry point for providing external app stuff from app entrypoint.

import { fireEvent } from "../common/dom/fire_event";
import { HomeAssistantMain } from "../layouts/home-assistant-main";
import type { EMExternalMessageCommands } from "./external_messaging";
import type { EMIncomingMessageCommands } from "./external_messaging";

export const attachExternalToApp = (hassMainEl: HomeAssistantMain) => {
window.addEventListener("haptic", (ev) =>
Expand All @@ -24,7 +24,7 @@ export const attachExternalToApp = (hassMainEl: HomeAssistantMain) => {

const handleExternalMessage = (
hassMainEl: HomeAssistantMain,
msg: EMExternalMessageCommands
msg: EMIncomingMessageCommands
): boolean => {
const bus = hassMainEl.hass.auth.external!;

Expand Down
129 changes: 108 additions & 21 deletions src/external_app/external_messaging.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ interface CommandInFlight {
export interface EMMessage {
id?: number;
type: string;
payload?: unknown;
}

interface EMError {
Expand All @@ -30,34 +29,120 @@ interface EMMessageResultError {
error: EMError;
}

interface EMExternalMessageRestart {
interface EMOutgoingMessageConfigGet extends EMMessage {
type: "config/get";
}

interface EMOutgoingMessageMatterCommission extends EMMessage {
type: "matter/commission";
}

type EMOutgoingMessageWithAnswer = {
"config/get": {
request: EMOutgoingMessageConfigGet;
response: ExternalConfig;
};
"matter/commission": {
request: EMOutgoingMessageMatterCommission;
response: {
code: string;
};
};
};

interface EMOutgoingMessageExoplayerPlayHLS extends EMMessage {
type: "exoplayer/play_hls";
payload: {
url: string;
muted: boolean;
};
}
interface EMOutgoingMessageExoplayerResize extends EMMessage {
type: "exoplayer/resize";
payload: {
left: number;
top: number;
right: number;
bottom: number;
};
}

interface EMOutgoingMessageExoplayerStop extends EMMessage {
type: "exoplayer/stop";
}

interface EMOutgoingMessageThemeUpdate extends EMMessage {
type: "theme-update";
}

interface EMOutgoingMessageHaptic extends EMMessage {
type: "haptic";
payload: { hapticType: string };
}

interface EMOutgoingMessageConnectionStatus extends EMMessage {
type: "connection-status";
payload: { event: string };
}

interface EMOutgoingMessageAppConfiguration extends EMMessage {
type: "config_screen/show";
}

interface EMOutgoingMessageTagWrite extends EMMessage {
type: "tag/write";
payload: {
name: string | null;
tag: string;
};
}

interface EMOutgoingMessageSidebarShow extends EMMessage {
type: "sidebar/show";
}

type EMOutgoingMessageWithoutAnswer =
| EMOutgoingMessageHaptic
| EMOutgoingMessageConnectionStatus
| EMOutgoingMessageAppConfiguration
| EMOutgoingMessageTagWrite
| EMOutgoingMessageSidebarShow
| EMOutgoingMessageExoplayerPlayHLS
| EMOutgoingMessageExoplayerResize
| EMOutgoingMessageExoplayerStop
| EMOutgoingMessageThemeUpdate
| EMMessageResultSuccess
| EMMessageResultError;

interface EMIncomingMessageRestart {
id: number;
type: "command";
command: "restart";
}

interface EMExternMessageShowNotifications {
interface EMIncomingMessageShowNotifications {
id: number;
type: "command";
command: "notifications/show";
}

export type EMExternalMessageCommands =
| EMExternalMessageRestart
| EMExternMessageShowNotifications;
export type EMIncomingMessageCommands =
| EMIncomingMessageRestart
| EMIncomingMessageShowNotifications;

type ExternalMessage =
type EMIncomingMessage =
| EMMessageResultSuccess
| EMMessageResultError
| EMExternalMessageCommands;
| EMIncomingMessageCommands;

type ExternalMessageHandler = (msg: EMExternalMessageCommands) => boolean;
type EMIncomingMessageHandler = (msg: EMIncomingMessageCommands) => boolean;

export interface ExternalConfig {
hasSettingsScreen: boolean;
hasSidebar: boolean;
canWriteTag: boolean;
hasExoPlayer: boolean;
canCommissionMatter: boolean;
}

export class ExternalMessaging {
Expand All @@ -67,7 +152,7 @@ export class ExternalMessaging {

public msgId = 0;

private _commandHandler?: ExternalMessageHandler;
private _commandHandler?: EMIncomingMessageHandler;

public async attach() {
window[CALLBACK_EXTERNAL_BUS] = (msg) => this.receiveMessage(msg);
Expand All @@ -77,44 +162,46 @@ export class ExternalMessaging {
payload: { event: ev.detail },
})
);
this.config = await this.sendMessage<ExternalConfig>({
this.config = await this.sendMessage<"config/get">({
type: "config/get",
});
}

public addCommandHandler(handler: ExternalMessageHandler) {
public addCommandHandler(handler: EMIncomingMessageHandler) {
this._commandHandler = handler;
}

/**
* Send message to external app that expects a response.
* @param msg message to send
*/
public sendMessage<T>(msg: EMMessage): Promise<T> {
public sendMessage<T extends keyof EMOutgoingMessageWithAnswer>(
msg: EMOutgoingMessageWithAnswer[T]["request"]
): Promise<EMOutgoingMessageWithAnswer[T]["response"]> {
const msgId = ++this.msgId;
msg.id = msgId;

this.fireMessage(msg);
this._sendExternal(msg);

return new Promise<T>((resolve, reject) => {
this.commands[msgId] = { resolve, reject };
});
return new Promise<EMOutgoingMessageWithAnswer[T]["response"]>(
(resolve, reject) => {
this.commands[msgId] = { resolve, reject };
}
);
}

/**
* Send message to external app without expecting a response.
* @param msg message to send
*/
public fireMessage(
msg: EMMessage | EMMessageResultSuccess | EMMessageResultError
) {
public fireMessage(msg: EMOutgoingMessageWithoutAnswer) {
if (!msg.id) {
msg.id = ++this.msgId;
}
this._sendExternal(msg);
}

public receiveMessage(msg: ExternalMessage) {
public receiveMessage(msg: EMIncomingMessage) {
if (__DEV__) {
// eslint-disable-next-line no-console
console.log("Receiving message from external app", msg);
Expand Down

0 comments on commit 614c157

Please sign in to comment.