hass-browser_mod/js/plugin/connection.ts

191 lines
4.7 KiB
TypeScript

import { hass, provideHass } from "../helpers";
const ID_STORAGE_KEY = "browser_mod-device-id";
export const ConnectionMixin = (SuperClass) => {
class BrowserModConnection extends SuperClass {
public hass;
public connection;
private _data;
public connected = false;
private _connectionResolve;
public connectionPromise = new Promise((resolve) => {
this._connectionResolve = resolve;
});
LOG(...args) {
const dt = new Date();
console.log(`${dt.toLocaleTimeString()}`, ...args);
}
private fireEvent(event, detail = undefined) {
this.dispatchEvent(new CustomEvent(event, { detail }));
}
private incoming_message(msg) {
if (msg.command) {
this.LOG("Command:", msg);
this.fireEvent(`command-${msg.command}`, msg);
} else if (msg.result) {
this.update_config(msg.result);
}
this._connectionResolve?.();
}
private update_config(cfg) {
this.LOG("Receive:", cfg);
let update = false;
if (!this.registered && cfg.devices?.[this.deviceID]) {
update = true;
}
this._data = cfg;
if (!this.connected) {
this.connected = true;
this.fireEvent("browser-mod-connected");
}
this.fireEvent("browser-mod-config-update");
if (update) this.sendUpdate({});
}
async connect() {
const conn = (await hass()).connection;
this.connection = conn;
// Subscribe to configuration updates
conn.subscribeMessage((msg) => this.incoming_message(msg), {
type: "browser_mod/connect",
deviceID: this.deviceID,
});
// Keep connection status up to date
conn.addEventListener("disconnected", () => {
this.connected = false;
this.fireEvent("browser-mod-disconnected");
});
conn.addEventListener("ready", () => {
this.connected = true;
this.fireEvent("browser-mod-connected");
this.sendUpdate({});
});
provideHass(this);
}
get config() {
return this._data?.config ?? {};
}
get devices() {
return this._data?.devices ?? [];
}
get registered() {
return this.devices?.[this.deviceID] !== undefined;
}
set registered(reg) {
(async () => {
if (reg) {
if (this.registered) return;
await this.connection.sendMessage({
type: "browser_mod/register",
deviceID: this.deviceID,
});
} else {
if (!this.registered) return;
await this.connection.sendMessage({
type: "browser_mod/unregister",
deviceID: this.deviceID,
});
}
})();
}
private async _reregister(newData = {}) {
await this.connection.sendMessage({
type: "browser_mod/reregister",
deviceID: this.deviceID,
data: {
...this.devices[this.deviceID],
...newData,
},
});
}
get meta() {
if (!this.registered) return null;
return this.devices[this.deviceID].meta;
}
set meta(value) {
this._reregister({ meta: value });
}
get cameraEnabled() {
if (!this.registered) return null;
return this.devices[this.deviceID].camera;
}
set cameraEnabled(value) {
this._reregister({ camera: value });
}
sendUpdate(data) {
if (!this.connected || !this.registered) return;
const dt = new Date();
this.LOG("Send:", data);
this.connection.sendMessage({
type: "browser_mod/update",
deviceID: this.deviceID,
data,
});
}
get deviceID() {
if (localStorage[ID_STORAGE_KEY]) return localStorage[ID_STORAGE_KEY];
this.deviceID = "";
return this.deviceID;
}
set deviceID(id) {
function _createDeviceID() {
const s4 = () => {
return Math.floor((1 + Math.random()) * 100000)
.toString(16)
.substring(1);
};
return window.fully?.getDeviceId() ?? `${s4()}${s4()}-${s4()}${s4()}`;
}
if (id === "") id = _createDeviceID();
const oldID = localStorage[ID_STORAGE_KEY];
localStorage[ID_STORAGE_KEY] = id;
this.fireEvent("browser-mod-config-update");
if (
this.devices?.[oldID] !== undefined &&
this.devices?.[this.deviceID] === undefined
) {
(async () => {
await this.connection.sendMessage({
type: "browser_mod/reregister",
deviceID: oldID,
data: {
...this.devices[oldID],
deviceID: this.deviceID,
},
});
})();
}
// TODO: Send update to backend to update device
}
}
return BrowserModConnection;
};