From acc4a15e027e144cbddb7b46d1283f6e1ad37032 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Lov=C3=A9n?= Date: Mon, 18 Jul 2022 20:51:07 +0000 Subject: [PATCH] Renamed Device to Browser throughout --- custom_components/browser_mod/__init__.py | 4 +- .../browser_mod/{device.py => browser.py} | 54 +++++----- custom_components/browser_mod/browser_mod.js | 70 ++++++------ .../browser_mod/browser_mod_panel.js | 34 +++--- custom_components/browser_mod/camera.py | 6 +- custom_components/browser_mod/connection.py | 68 ++++++------ custom_components/browser_mod/const.py | 2 +- custom_components/browser_mod/coordinator.py | 4 +- custom_components/browser_mod/helpers.py | 12 +-- custom_components/browser_mod/light.py | 10 +- custom_components/browser_mod/media_player.py | 20 ++-- custom_components/browser_mod/sensor.py | 4 +- custom_components/browser_mod/service.py | 82 ++++---------- custom_components/browser_mod/store.py | 26 ++--- js/config_panel/main.ts | 36 +++---- js/plugin/browser-player.ts | 6 +- js/plugin/connection.ts | 56 +++++----- js/plugin/main.ts | 102 +----------------- 18 files changed, 227 insertions(+), 369 deletions(-) rename custom_components/browser_mod/{device.py => browser.py} (75%) diff --git a/custom_components/browser_mod/__init__.py b/custom_components/browser_mod/__init__.py index 801fa3f..6751a86 100644 --- a/custom_components/browser_mod/__init__.py +++ b/custom_components/browser_mod/__init__.py @@ -3,7 +3,7 @@ import logging from .store import BrowserModStore from .mod_view import async_setup_view from .connection import async_setup_connection -from .const import DOMAIN, DATA_DEVICES, DATA_ADDERS, DATA_STORE +from .const import DOMAIN, DATA_BROWSERS, DATA_ADDERS, DATA_STORE from .service import async_setup_services _LOGGER = logging.getLogger(__name__) @@ -15,7 +15,7 @@ async def async_setup(hass, config): await store.load() hass.data[DOMAIN] = { - DATA_DEVICES: {}, + DATA_BROWSERS: {}, DATA_ADDERS: {}, DATA_STORE: store, } diff --git a/custom_components/browser_mod/device.py b/custom_components/browser_mod/browser.py similarity index 75% rename from custom_components/browser_mod/device.py rename to custom_components/browser_mod/browser.py index 8842d5e..abba9e1 100644 --- a/custom_components/browser_mod/device.py +++ b/custom_components/browser_mod/browser.py @@ -3,7 +3,7 @@ import logging from homeassistant.components.websocket_api import event_message from homeassistant.helpers import device_registry, entity_registry -from .const import DOMAIN, DATA_ADDERS +from .const import DATA_BROWSERS, DOMAIN, DATA_ADDERS from .coordinator import Coordinator from .sensor import BrowserSensor from .light import BrowserModLight @@ -14,13 +14,13 @@ from .camera import BrowserModCamera _LOGGER = logging.getLogger(__name__) -class BrowserModDevice: - """A Browser_mod device.""" +class BrowserModBrowser: + """A Browser_mod browser.""" - def __init__(self, hass, deviceID): + def __init__(self, hass, browserID): """ """ - self.deviceID = deviceID - self.coordinator = Coordinator(hass, deviceID) + self.browserID = browserID + self.coordinator = Coordinator(hass, browserID) self.entities = {} self.data = {} self.settings = {} @@ -38,17 +38,17 @@ class BrowserModDevice: self.update_entities(hass) def update_entities(self, hass): - """Create all entities associated with the device.""" + """Create all entities associated with the browser.""" coordinator = self.coordinator - deviceID = self.deviceID + browserID = self.browserID def _assert_browser_sensor(type, name, *properties): if name in self.entities: return adder = hass.data[DOMAIN][DATA_ADDERS][type] cls = {"sensor": BrowserSensor, "binary_sensor": BrowserBinarySensor}[type] - new = cls(coordinator, deviceID, name, *properties) + new = cls(coordinator, browserID, name, *properties) adder([new]) self.entities[name] = new @@ -70,19 +70,19 @@ class BrowserModDevice: if "screen" not in self.entities: adder = hass.data[DOMAIN][DATA_ADDERS]["light"] - new = BrowserModLight(coordinator, deviceID, self) + new = BrowserModLight(coordinator, browserID, self) adder([new]) self.entities["screen"] = new if "player" not in self.entities: adder = hass.data[DOMAIN][DATA_ADDERS]["media_player"] - new = BrowserModPlayer(coordinator, deviceID, self) + new = BrowserModPlayer(coordinator, browserID, self) adder([new]) self.entities["player"] = new if "camera" not in self.entities and self.settings.get("camera"): adder = hass.data[DOMAIN][DATA_ADDERS]["camera"] - new = BrowserModCamera(coordinator, deviceID) + new = BrowserModCamera(coordinator, browserID) adder([new]) self.entities["camera"] = new if "camera" in self.entities and not self.settings.get("camera"): @@ -95,7 +95,7 @@ class BrowserModDevice: ) def send(self, command, **kwargs): - """Send a command to this device.""" + """Send a command to this browser.""" if self.connection is None: return @@ -112,7 +112,7 @@ class BrowserModDevice: ) def delete(self, hass): - """Delete device and associated entities.""" + """Delete browser and associated entities.""" dr = device_registry.async_get(hass) er = entity_registry.async_get(hass) @@ -121,25 +121,25 @@ class BrowserModDevice: self.entities = {} - device = dr.async_get_device({(DOMAIN, self.deviceID)}) + device = dr.async_get_device({(DOMAIN, self.browserID)}) dr.async_remove_device(device.id) -def getDevice(hass, deviceID, *, create=True): - """Get or create device by deviceID.""" - devices = hass.data[DOMAIN]["devices"] - if deviceID in devices: - return devices[deviceID] +def getBrowser(hass, browserID, *, create=True): + """Get or create browser by browserID.""" + browsers = hass.data[DOMAIN][DATA_BROWSERS] + if browserID in browsers: + return browsers[browserID] if not create: return None - devices[deviceID] = BrowserModDevice(hass, deviceID) - return devices[deviceID] + browsers[browserID] = BrowserModBrowser(hass, browserID) + return browsers[browserID] -def deleteDevice(hass, deviceID): - devices = hass.data[DOMAIN]["devices"] - if deviceID in devices: - devices[deviceID].delete(hass) - del devices[deviceID] +def deleteBrowser(hass, browserID): + browsers = hass.data[DOMAIN][DATA_BROWSERS] + if browserID in browsers: + browsers[browserID].delete(hass) + del browsers[browserID] diff --git a/custom_components/browser_mod/browser_mod.js b/custom_components/browser_mod/browser_mod.js index f73094a..66fc7c0 100644 --- a/custom_components/browser_mod/browser_mod.js +++ b/custom_components/browser_mod/browser_mod.js @@ -129,7 +129,7 @@ class BrowserPlayer extends s { composed: true, cancelable: false, detail: { - entityId: (_a = window.browser_mod.deviceEntities) === null || _a === void 0 ? void 0 : _a.player, + entityId: (_a = window.browser_mod.browserEntities) === null || _a === void 0 ? void 0 : _a.player, }, })); } @@ -179,7 +179,7 @@ class BrowserPlayer extends s { -
${window.browser_mod.deviceID}
+
${window.browser_mod.browserID}
`; } @@ -196,7 +196,7 @@ class BrowserPlayer extends s { width: 24px; padding: 8px; } - .device-id { + .browser-id { opacity: 0.7; font-size: xx-small; margin-top: -10px; @@ -260,7 +260,7 @@ const loadLoadCardHelpers = async () => { await ((_c = (_b = (_a = routes === null || routes === void 0 ? void 0 : routes.routes) === null || _a === void 0 ? void 0 : _a.a) === null || _b === void 0 ? void 0 : _b.load) === null || _c === void 0 ? void 0 : _c.call(_b)); }; -const ID_STORAGE_KEY = "browser_mod-device-id"; +const ID_STORAGE_KEY = "browser_mod-browser-id"; const ConnectionMixin = (SuperClass) => { class BrowserModConnection extends SuperClass { constructor() { @@ -269,7 +269,7 @@ const ConnectionMixin = (SuperClass) => { this.connectionPromise = new Promise((resolve) => { this._connectionResolve = resolve; }); - this.deviceEntities = {}; + this.browserEntities = {}; } LOG(...args) { const dt = new Date(); @@ -284,8 +284,8 @@ const ConnectionMixin = (SuperClass) => { this.LOG("Command:", msg); this.fireEvent(`command-${msg.command}`, msg); } - else if (msg.deviceEntities) { - this.deviceEntities = msg.deviceEntities; + else if (msg.browserEntities) { + this.browserEntities = msg.browserEntities; } else if (msg.result) { this.update_config(msg.result); @@ -296,7 +296,7 @@ const ConnectionMixin = (SuperClass) => { var _a; this.LOG("Receive:", cfg); let update = false; - if (!this.registered && ((_a = cfg.devices) === null || _a === void 0 ? void 0 : _a[this.deviceID])) { + if (!this.registered && ((_a = cfg.browsers) === null || _a === void 0 ? void 0 : _a[this.browserID])) { update = true; } this._data = cfg; @@ -314,7 +314,7 @@ const ConnectionMixin = (SuperClass) => { // Subscribe to configuration updates conn.subscribeMessage((msg) => this.incoming_message(msg), { type: "browser_mod/connect", - deviceID: this.deviceID, + browserID: this.browserID, }); // Keep connection status up to date conn.addEventListener("disconnected", () => { @@ -332,13 +332,13 @@ const ConnectionMixin = (SuperClass) => { var _a, _b; return (_b = (_a = this._data) === null || _a === void 0 ? void 0 : _a.config) !== null && _b !== void 0 ? _b : {}; } - get devices() { + get browsers() { var _a, _b; - return (_b = (_a = this._data) === null || _a === void 0 ? void 0 : _a.devices) !== null && _b !== void 0 ? _b : []; + return (_b = (_a = this._data) === null || _a === void 0 ? void 0 : _a.browsers) !== null && _b !== void 0 ? _b : []; } get registered() { var _a; - return ((_a = this.devices) === null || _a === void 0 ? void 0 : _a[this.deviceID]) !== undefined; + return ((_a = this.browsers) === null || _a === void 0 ? void 0 : _a[this.browserID]) !== undefined; } set registered(reg) { (async () => { @@ -347,7 +347,7 @@ const ConnectionMixin = (SuperClass) => { return; await this.connection.sendMessage({ type: "browser_mod/register", - deviceID: this.deviceID, + browserID: this.browserID, }); } else { @@ -355,7 +355,7 @@ const ConnectionMixin = (SuperClass) => { return; await this.connection.sendMessage({ type: "browser_mod/unregister", - deviceID: this.deviceID, + browserID: this.browserID, }); } })(); @@ -363,14 +363,14 @@ const ConnectionMixin = (SuperClass) => { async _reregister(newData = {}) { await this.connection.sendMessage({ type: "browser_mod/reregister", - deviceID: this.deviceID, - data: Object.assign(Object.assign({}, this.devices[this.deviceID]), newData), + browserID: this.browserID, + data: Object.assign(Object.assign({}, this.browsers[this.browserID]), newData), }); } get meta() { if (!this.registered) return null; - return this.devices[this.deviceID].meta; + return this.browsers[this.browserID].meta; } set meta(value) { this._reregister({ meta: value }); @@ -378,7 +378,7 @@ const ConnectionMixin = (SuperClass) => { get cameraEnabled() { if (!this.registered) return null; - return this.devices[this.deviceID].camera; + return this.browsers[this.browserID].camera; } set cameraEnabled(value) { this._reregister({ camera: value }); @@ -389,19 +389,19 @@ const ConnectionMixin = (SuperClass) => { this.LOG("Send:", data); this.connection.sendMessage({ type: "browser_mod/update", - deviceID: this.deviceID, + browserID: this.browserID, data, }); } - get deviceID() { + get browserID() { if (localStorage[ID_STORAGE_KEY]) return localStorage[ID_STORAGE_KEY]; - this.deviceID = ""; - return this.deviceID; + this.browserID = ""; + return this.browserID; } - set deviceID(id) { + set browserID(id) { var _a, _b; - function _createDeviceID() { + function _createBrowserID() { var _a, _b; const s4 = () => { return Math.floor((1 + Math.random()) * 100000) @@ -411,21 +411,20 @@ const ConnectionMixin = (SuperClass) => { return (_b = (_a = window.fully) === null || _a === void 0 ? void 0 : _a.getDeviceId()) !== null && _b !== void 0 ? _b : `${s4()}${s4()}-${s4()}${s4()}`; } if (id === "") - id = _createDeviceID(); + id = _createBrowserID(); const oldID = localStorage[ID_STORAGE_KEY]; localStorage[ID_STORAGE_KEY] = id; this.fireEvent("browser-mod-config-update"); - if (((_a = this.devices) === null || _a === void 0 ? void 0 : _a[oldID]) !== undefined && - ((_b = this.devices) === null || _b === void 0 ? void 0 : _b[this.deviceID]) === undefined) { + if (((_a = this.browsers) === null || _a === void 0 ? void 0 : _a[oldID]) !== undefined && + ((_b = this.browsers) === null || _b === void 0 ? void 0 : _b[this.browserID]) === undefined) { (async () => { await this.connection.sendMessage({ type: "browser_mod/reregister", - deviceID: oldID, - data: Object.assign(Object.assign({}, this.devices[oldID]), { deviceID: this.deviceID }), + browserID: oldID, + data: Object.assign(Object.assign({}, this.browsers[oldID]), { browserID: this.browserID }), }); })(); } - // TODO: Send update to backend to update device } } return BrowserModConnection; @@ -1256,8 +1255,8 @@ var pjson = { /* TODO: - Fix nomenclature - - Command -> Service - - Device -> Browser + x Command -> Service + x Device -> Browser - Popups X Basic popups - Card-mod integration @@ -1306,13 +1305,10 @@ class BrowserMod extends ServicesMixin(PopupMixin(BrowserStateMixin(CameraMixin( // } // }); console.info(`%cBROWSER_MOD ${pjson.version} IS INSTALLED - %cDeviceID: ${this.deviceID}`, "color: green; font-weight: bold", ""); + %cBrowserID: ${this.browserID}`, "color: green; font-weight: bold", ""); } } -// (async () => { -// await hass_loaded(); if (!window.browser_mod) - window.browser_mod = new BrowserMod(); -// })(); + window.browser_mod = new BrowserMod(); export { BrowserMod }; diff --git a/custom_components/browser_mod/browser_mod_panel.js b/custom_components/browser_mod/browser_mod_panel.js index 417359e..2e4c9c4 100644 --- a/custom_components/browser_mod/browser_mod_panel.js +++ b/custom_components/browser_mod/browser_mod_panel.js @@ -90,28 +90,28 @@ loadDevTools().then(() => { return; window.browser_mod.registered = !window.browser_mod.registered; } - changeDeviceID(ev) { - window.browser_mod.deviceID = ev.target.value; + changeBrowserID(ev) { + window.browser_mod.browserID = ev.target.value; } toggleCameraEnabled() { window.browser_mod.cameraEnabled = !window.browser_mod.cameraEnabled; } - unregister_device(ev) { - const deviceID = ev.currentTarget.deviceID; + unregister_browser(ev) { + const browserID = ev.currentTarget.browserID; const unregisterCallback = () => { - console.log(deviceID, window.browser_mod.deviceID); - if (deviceID === window.browser_mod.deviceID) { + console.log(browserID, window.browser_mod.browserID); + if (browserID === window.browser_mod.browserID) { console.log("Unregister self"); window.browser_mod.registered = false; } else { window.browser_mod.connection.sendMessage({ type: "browser_mod/unregister", - deviceID, + browserID, }); } }; - window.browser_mod.showPopup("Unregister device", `Are you sure you want to unregister device ${deviceID}?`, { + window.browser_mod.showPopup("Unregister browser", `Are you sure you want to unregister browser ${browserID}?`, { primary_action: "Yes", secondary_action: "No", callbacks: { @@ -176,21 +176,21 @@ loadDevTools().then(() => { - DeviceID + BrowserID A unique identifier for this browser-device combination. Enable camera Get camera input from this device (hardware + >Get camera input from this browser (hardware dependent) { - +
- ${Object.keys(window.browser_mod.devices).map((d) => $ ` + ${Object.keys(window.browser_mod.browsers).map((d) => $ ` ${d} Last connected: diff --git a/custom_components/browser_mod/camera.py b/custom_components/browser_mod/camera.py index 3a24f6e..d9dfabd 100644 --- a/custom_components/browser_mod/camera.py +++ b/custom_components/browser_mod/camera.py @@ -21,13 +21,13 @@ async def async_setup_entry(hass, config_entry, async_add_entities): class BrowserModCamera(BrowserModEntity, Camera): - def __init__(self, coordinator, deviceID): - BrowserModEntity.__init__(self, coordinator, deviceID, None) + def __init__(self, coordinator, browserID): + BrowserModEntity.__init__(self, coordinator, browserID, None) Camera.__init__(self) @property def unique_id(self): - return f"{self.deviceID}-camera" + return f"{self.browserID}-camera" @property def entity_registry_visible_default(self): diff --git a/custom_components/browser_mod/connection.py b/custom_components/browser_mod/connection.py index fa3df1f..f447fd4 100644 --- a/custom_components/browser_mod/connection.py +++ b/custom_components/browser_mod/connection.py @@ -18,7 +18,7 @@ from .const import ( DOMAIN, ) -from .device import getDevice, deleteDevice +from .browser import getBrowser, deleteBrowser _LOGGER = logging.getLogger(__name__) @@ -27,12 +27,12 @@ async def async_setup_connection(hass): @websocket_api.websocket_command( { vol.Required("type"): WS_CONNECT, - vol.Required("deviceID"): str, + vol.Required("browserID"): str, } ) @websocket_api.async_response async def handle_connect(hass, connection, msg): - deviceID = msg["deviceID"] + browserID = msg["browserID"] store = hass.data[DOMAIN]["store"] def listener(data): @@ -41,93 +41,93 @@ async def async_setup_connection(hass): connection.subscriptions[msg["id"]] = store.add_listener(listener) connection.send_result(msg["id"]) - if store.get_device(deviceID).enabled: - dev = getDevice(hass, deviceID) - dev.update_settings(hass, store.get_device(deviceID).asdict()) + if store.get_browser(browserID).enabled: + dev = getBrowser(hass, browserID) + dev.update_settings(hass, store.get_browser(browserID).asdict()) dev.connection = (connection, msg["id"]) - await store.set_device( - deviceID, last_seen=datetime.now(tz=timezone.utc).isoformat() + await store.set_browser( + browserID, last_seen=datetime.now(tz=timezone.utc).isoformat() ) listener(store.asdict()) @websocket_api.websocket_command( { vol.Required("type"): WS_REGISTER, - vol.Required("deviceID"): str, + vol.Required("browserID"): str, } ) @websocket_api.async_response async def handle_register(hass, connection, msg): - deviceID = msg["deviceID"] + browserID = msg["browserID"] store = hass.data[DOMAIN]["store"] - await store.set_device(deviceID, enabled=True) + await store.set_browser(browserID, enabled=True) connection.send_result(msg["id"]) @websocket_api.websocket_command( { vol.Required("type"): WS_UNREGISTER, - vol.Required("deviceID"): str, + vol.Required("browserID"): str, } ) @websocket_api.async_response async def handle_unregister(hass, connection, msg): - deviceID = msg["deviceID"] + browserID = msg["browserID"] store = hass.data[DOMAIN]["store"] - deleteDevice(hass, deviceID) - await store.delete_device(deviceID) + deleteBrowser(hass, browserID) + await store.delete_browser(browserID) connection.send_result(msg["id"]) @websocket_api.websocket_command( { vol.Required("type"): WS_REREGISTER, - vol.Required("deviceID"): str, + vol.Required("browserID"): str, vol.Required("data"): dict, } ) @websocket_api.async_response async def handle_reregister(hass, connection, msg): - deviceID = msg["deviceID"] + browserID = msg["browserID"] store = hass.data[DOMAIN]["store"] data = msg["data"] del data["last_seen"] - deviceSettings = {} + browserSettings = {} - if "deviceID" in data: - newDeviceID = data["deviceID"] - del data["deviceID"] + if "browserID" in data: + newBrowserID = data["browserID"] + del data["browserID"] - oldDeviceSettings = store.get_device(deviceID) - if oldDeviceSettings: - deviceSettings = oldDeviceSettings.asdict() - await store.delete_device(deviceID) + oldBrowserSetting = store.get_browser(browserID) + if oldBrowserSetting: + browserSettings = oldBrowserSetting.asdict() + await store.delete_browser(browserID) - deleteDevice(hass, deviceID) + deleteBrowser(hass, browserID) - deviceID = newDeviceID + browserID = newBrowserID - if (dev := getDevice(hass, deviceID, create=False)) is not None: + if (dev := getBrowser(hass, browserID, create=False)) is not None: dev.update_settings(hass, data) - deviceSettings.update(data) - await store.set_device(deviceID, **deviceSettings) + browserSettings.update(data) + await store.set_browser(browserID, **browserSettings) @websocket_api.websocket_command( { vol.Required("type"): WS_UPDATE, - vol.Required("deviceID"): str, + vol.Required("browserID"): str, vol.Optional("data"): dict, } ) @websocket_api.async_response async def handle_update(hass, connection, msg): - deviceID = msg["deviceID"] + browserID = msg["browserID"] store = hass.data[DOMAIN]["store"] - if store.get_device(deviceID).enabled: - dev = getDevice(hass, deviceID) + if store.get_browser(browserID).enabled: + dev = getBrowser(hass, browserID) dev.update(hass, msg.get("data", {})) async_register_command(hass, handle_connect) diff --git a/custom_components/browser_mod/const.py b/custom_components/browser_mod/const.py index c083a44..6130de7 100644 --- a/custom_components/browser_mod/const.py +++ b/custom_components/browser_mod/const.py @@ -3,7 +3,7 @@ DOMAIN = "browser_mod" FRONTEND_SCRIPT_URL = "/browser_mod.js" SETTINGS_PANEL_URL = "/browser_mod_panel.js" -DATA_DEVICES = "devices" +DATA_BROWSERS = "browsers" DATA_ADDERS = "adders" DATA_STORE = "store" DATA_ALIASES = "aliases" diff --git a/custom_components/browser_mod/coordinator.py b/custom_components/browser_mod/coordinator.py index 3f3f135..6803563 100644 --- a/custom_components/browser_mod/coordinator.py +++ b/custom_components/browser_mod/coordinator.py @@ -8,10 +8,10 @@ _LOGGER = logging.getLogger(__name__) class Coordinator(DataUpdateCoordinator): - def __init__(self, hass, deviceID): + def __init__(self, hass, browserID): super().__init__( hass, _LOGGER, name="Browser Mod Coordinator", ) - self.deviceID = deviceID + self.browserID = browserID diff --git a/custom_components/browser_mod/helpers.py b/custom_components/browser_mod/helpers.py index 579125e..eece033 100644 --- a/custom_components/browser_mod/helpers.py +++ b/custom_components/browser_mod/helpers.py @@ -11,9 +11,9 @@ _LOGGER = logging.getLogger(__name__) class BrowserModEntity(CoordinatorEntity): - def __init__(self, coordinator, deviceID, name): + def __init__(self, coordinator, browserID, name): super().__init__(coordinator) - self.deviceID = deviceID + self.browserID = browserID self._name = name @property @@ -26,8 +26,8 @@ class BrowserModEntity(CoordinatorEntity): if ip := self._data.get("browser", {}).get("ip_address"): config_url = {"configuration_url": f"http://{ip}:2323"} return { - "identifiers": {(DOMAIN, self.deviceID)}, - "name": self.deviceID, + "identifiers": {(DOMAIN, self.browserID)}, + "name": self.browserID, "manufacturer": "Browser Mod", **config_url, } @@ -36,7 +36,7 @@ class BrowserModEntity(CoordinatorEntity): def extra_state_attributes(self): return { "type": "browser_mod", - "deviceID": self.deviceID, + "browserID": self.browserID, } @property @@ -53,4 +53,4 @@ class BrowserModEntity(CoordinatorEntity): @property def unique_id(self): - return f"{self.deviceID}-{self._name.replace(' ','_')}" + return f"{self.browserID}-{self._name.replace(' ','_')}" diff --git a/custom_components/browser_mod/light.py b/custom_components/browser_mod/light.py index 6c5f4e4..faa7149 100644 --- a/custom_components/browser_mod/light.py +++ b/custom_components/browser_mod/light.py @@ -15,10 +15,10 @@ async def async_setup_entry(hass, config_entry, async_add_entities): class BrowserModLight(BrowserModEntity, LightEntity): - def __init__(self, coordinator, deviceID, device): - BrowserModEntity.__init__(self, coordinator, deviceID, "Screen") + def __init__(self, coordinator, browserID, browser): + BrowserModEntity.__init__(self, coordinator, browserID, "Screen") LightEntity.__init__(self) - self.device = device + self.browser = browser @property def entity_registry_visible_default(self): @@ -41,7 +41,7 @@ class BrowserModLight(BrowserModEntity, LightEntity): return self._data.get("screen_brightness", 1) def turn_on(self, **kwargs): - self.device.send("screen_on", **kwargs) + self.browser.send("screen_on", **kwargs) def turn_off(self, **kwargs): - self.device.send("screen_off") + self.browser.send("screen_off") diff --git a/custom_components/browser_mod/media_player.py b/custom_components/browser_mod/media_player.py index 6fa26db..888bb74 100644 --- a/custom_components/browser_mod/media_player.py +++ b/custom_components/browser_mod/media_player.py @@ -39,14 +39,14 @@ async def async_setup_entry(hass, config_entry, async_add_entities): class BrowserModPlayer(BrowserModEntity, MediaPlayerEntity): - def __init__(self, coordinator, deviceID, device): - BrowserModEntity.__init__(self, coordinator, deviceID, None) + def __init__(self, coordinator, browserID, browser): + BrowserModEntity.__init__(self, coordinator, browserID, None) MediaPlayerEntity.__init__(self) - self.device = device + self.browser = browser @property def unique_id(self): - return f"{self.deviceID}-player" + return f"{self.browserID}-player" @property def entity_registry_visible_default(self): @@ -83,10 +83,10 @@ class BrowserModPlayer(BrowserModEntity, MediaPlayerEntity): return self._data.get("player", {}).get("muted", False) def set_volume_level(self, volume): - self.device.send("player-set-volume", volume_level=volume) + self.browser.send("player-set-volume", volume_level=volume) def mute_volume(self, mute): - self.device.send("player-mute", mute=mute) + self.browser.send("player-mute", mute=mute) async def async_play_media(self, media_type, media_id, **kwargs): if media_source.is_media_source_id(media_id): @@ -97,7 +97,7 @@ class BrowserModPlayer(BrowserModEntity, MediaPlayerEntity): media_id = play_item.url if media_type in (MEDIA_TYPE_URL, MEDIA_TYPE_MUSIC): media_id = async_process_play_media_url(self.hass, media_id) - self.device.send("player-play", media_content_id=media_id) + self.browser.send("player-play", media_content_id=media_id) async def async_browse_media(self, media_content_type=None, media_content_id=None): """Implement the websocket media browsing helper.""" @@ -108,10 +108,10 @@ class BrowserModPlayer(BrowserModEntity, MediaPlayerEntity): ) def media_play(self): - self.device.send("player-play") + self.browser.send("player-play") def media_pause(self): - self.device.send("player-pause") + self.browser.send("player-pause") def media_stop(self): - self.device.send("player-stop") + self.browser.send("player-stop") diff --git a/custom_components/browser_mod/sensor.py b/custom_components/browser_mod/sensor.py index 21f6012..f64ed2c 100644 --- a/custom_components/browser_mod/sensor.py +++ b/custom_components/browser_mod/sensor.py @@ -18,13 +18,13 @@ class BrowserSensor(BrowserModEntity, SensorEntity): def __init__( self, coordinator, - deviceID, + browserID, parameter, name, unit_of_measurement=None, device_class=None, ): - super().__init__(coordinator, deviceID, name) + super().__init__(coordinator, browserID, name) self.parameter = parameter self._device_class = device_class self._unit_of_measurement = unit_of_measurement diff --git a/custom_components/browser_mod/service.py b/custom_components/browser_mod/service.py index 7b79dea..b8841f0 100644 --- a/custom_components/browser_mod/service.py +++ b/custom_components/browser_mod/service.py @@ -1,17 +1,10 @@ import logging -from homeassistant.helpers.entity_registry import ( - async_entries_for_config_entry, - async_entries_for_device, -) -from homeassistant.const import STATE_UNAVAILABLE -from homeassistant.helpers import device_registry, area_registry +from homeassistant.helpers import device_registry from .const import ( DOMAIN, - DATA_DEVICES, - DATA_ALIASES, - USER_COMMANDS, + DATA_BROWSERS, ) _LOGGER = logging.getLogger(__name__) @@ -20,29 +13,31 @@ _LOGGER = logging.getLogger(__name__) async def async_setup_services(hass): def call_service(service, targets, data): - devices = hass.data[DOMAIN][DATA_DEVICES] + browsers = hass.data[DOMAIN][DATA_BROWSERS] if isinstance(targets, str): targets = [targets] + # If no targets were specified, send to all browsers + if len(targets) == 0: + targets = browsers.keys() + for target in targets: - if target not in devices: + if target not in browsers: continue - device = devices[target] - device.send(service, **data) + browser = browsers[target] + browser.send(service, **data) def handle_service(call): service = call.service data = {**call.data} - device_ids = set(data.get("device_id", [])) - data.pop("device_id", None) - area_ids = set(data.get("area_id", [])) - data.pop("area_id", None) - targets = data.get("target", []) - if isinstance(targets, str): - targets = [targets] - targets = set(targets) - data.pop("target", None) + + browsers = data.pop("browser_id", []) + if isinstance(browsers, str): + browsers = [browsers] + browsers = set(browsers) + device_ids = set(data.pop("device_id", [])) + area_ids = set(data.pop("area_id", [])) dr = device_registry.async_get(hass) @@ -53,53 +48,16 @@ async def async_setup_services(hass): browserID = list(dev.identifiers)[0][1] if browserID is None: continue - targets.add(browserID) + browsers.add(browserID) for area in area_ids: for dev in device_registry.async_entries_for_area(dr, area): browserID = list(dev.identifiers)[0][1] if browserID is None: continue - targets.add(browserID) + browsers.add(browserID) - _LOGGER.error(service) - _LOGGER.error(targets) - _LOGGER.error(data) - - call_service(service, targets, data) + call_service(service, browsers, data) hass.services.async_register(DOMAIN, "test", handle_service) hass.services.async_register(DOMAIN, "popup", handle_service) - - -async def setup_service(hass): - def handle_command(call): - command = call.data.get("command", None) - if not command: - return - - targets = call.data.get("deviceID", None) - if isinstance(targets, str): - targets = [targets] - devices = hass.data[DOMAIN][DATA_DEVICES] - aliases = hass.data[DOMAIN][DATA_ALIASES] - if not targets: - targets = devices.keys() - targets = [aliases.get(t, t) for t in targets] - - data = dict(call.data) - del data["command"] - - for t in targets: - if t in devices: - devices[t].send(command, **data) - - def command_wrapper(call): - command = call.service.replace("_", "-") - call.data = dict(call.data) - call.data["command"] = command - handle_command(call) - - hass.services.async_register(DOMAIN, "command", handle_command) - for cmd in USER_COMMANDS: - hass.services.async_register(DOMAIN, cmd.replace("-", "_"), command_wrapper) diff --git a/custom_components/browser_mod/store.py b/custom_components/browser_mod/store.py index 721419f..20a5c45 100644 --- a/custom_components/browser_mod/store.py +++ b/custom_components/browser_mod/store.py @@ -10,7 +10,7 @@ _LOGGER = logging.getLogger(__name__) @attr.s -class DeviceStoreData: +class BrowserStoreData: last_seen = attr.ib(type=int, default=0) enabled = attr.ib(type=bool, default=False) camera = attr.ib(type=bool, default=False) @@ -26,17 +26,19 @@ class DeviceStoreData: @attr.s class ConfigStoreData: - devices = attr.ib(type=dict[str:DeviceStoreData], factory=dict) + browsers = attr.ib(type=dict[str:BrowserStoreData], factory=dict) version = attr.ib(type=str, default="2.0") @classmethod def from_dict(cls, data={}): - devices = {k: DeviceStoreData.from_dict(v) for k, v in data["devices"].items()} + browsers = { + k: BrowserStoreData.from_dict(v) for k, v in data["browsers"].items() + } return cls( **( data | { - "devices": devices, + "browsers": browsers, } ) ) @@ -83,15 +85,15 @@ class BrowserModStore: return remove_listener - def get_device(self, deviceID): - return self.data.devices.get(deviceID, DeviceStoreData()) + def get_browser(self, browserID): + return self.data.browsers.get(browserID, BrowserStoreData()) - async def set_device(self, deviceID, **data): - device = self.data.devices.get(deviceID, DeviceStoreData()) - device.__dict__.update(data) - self.data.devices[deviceID] = device + async def set_browser(self, browserID, **data): + browser = self.data.browsers.get(browserID, BrowserStoreData()) + browser.__dict__.update(data) + self.data.browsers[browserID] = browser await self.updated() - async def delete_device(self, deviceID): - del self.data.devices[deviceID] + async def delete_browser(self, browserID): + del self.data.browsers[browserID] await self.updated() diff --git a/js/config_panel/main.ts b/js/config_panel/main.ts index 640dfd6..20be064 100644 --- a/js/config_panel/main.ts +++ b/js/config_panel/main.ts @@ -14,32 +14,32 @@ loadDevTools().then(() => { if (!window.browser_mod?.connected) return; window.browser_mod.registered = !window.browser_mod.registered; } - changeDeviceID(ev) { - window.browser_mod.deviceID = ev.target.value; + changeBrowserID(ev) { + window.browser_mod.browserID = ev.target.value; } toggleCameraEnabled() { window.browser_mod.cameraEnabled = !window.browser_mod.cameraEnabled; } - unregister_device(ev) { - const deviceID = ev.currentTarget.deviceID; + unregister_browser(ev) { + const browserID = ev.currentTarget.browserID; const unregisterCallback = () => { - console.log(deviceID, window.browser_mod.deviceID); - if (deviceID === window.browser_mod.deviceID) { + console.log(browserID, window.browser_mod.browserID); + if (browserID === window.browser_mod.browserID) { console.log("Unregister self"); window.browser_mod.registered = false; } else { window.browser_mod.connection.sendMessage({ type: "browser_mod/unregister", - deviceID, + browserID, }); } }; window.browser_mod.showPopup( - "Unregister device", - `Are you sure you want to unregister device ${deviceID}?`, + "Unregister browser", + `Are you sure you want to unregister browser ${browserID}?`, { primary_action: "Yes", secondary_action: "No", @@ -109,21 +109,21 @@ loadDevTools().then(() => { - DeviceID + BrowserID A unique identifier for this browser-device combination. Enable camera Get camera input from this device (hardware + >Get camera input from this browser (hardware dependent) {
- +
- ${Object.keys(window.browser_mod.devices).map( + ${Object.keys(window.browser_mod.browsers).map( (d) => html` ${d} Last connected: diff --git a/js/plugin/browser-player.ts b/js/plugin/browser-player.ts index e2e8f90..c8ec5f0 100644 --- a/js/plugin/browser-player.ts +++ b/js/plugin/browser-player.ts @@ -47,7 +47,7 @@ class BrowserPlayer extends LitElement { composed: true, cancelable: false, detail: { - entityId: window.browser_mod.deviceEntities?.player, + entityId: window.browser_mod.browserEntities?.player, }, }) ); @@ -98,7 +98,7 @@ class BrowserPlayer extends LitElement {
-
${window.browser_mod.deviceID}
+
${window.browser_mod.browserID}
`; } @@ -116,7 +116,7 @@ class BrowserPlayer extends LitElement { width: 24px; padding: 8px; } - .device-id { + .browser-id { opacity: 0.7; font-size: xx-small; margin-top: -10px; diff --git a/js/plugin/connection.ts b/js/plugin/connection.ts index a8d119d..b219ba2 100644 --- a/js/plugin/connection.ts +++ b/js/plugin/connection.ts @@ -1,6 +1,6 @@ import { hass, provideHass } from "../helpers"; -const ID_STORAGE_KEY = "browser_mod-device-id"; +const ID_STORAGE_KEY = "browser_mod-browser-id"; export const ConnectionMixin = (SuperClass) => { class BrowserModConnection extends SuperClass { @@ -12,7 +12,7 @@ export const ConnectionMixin = (SuperClass) => { public connectionPromise = new Promise((resolve) => { this._connectionResolve = resolve; }); - public deviceEntities = {}; + public browserEntities = {}; LOG(...args) { const dt = new Date(); @@ -27,8 +27,8 @@ export const ConnectionMixin = (SuperClass) => { if (msg.command) { this.LOG("Command:", msg); this.fireEvent(`command-${msg.command}`, msg); - } else if (msg.deviceEntities) { - this.deviceEntities = msg.deviceEntities; + } else if (msg.browserEntities) { + this.browserEntities = msg.browserEntities; } else if (msg.result) { this.update_config(msg.result); } @@ -39,7 +39,7 @@ export const ConnectionMixin = (SuperClass) => { this.LOG("Receive:", cfg); let update = false; - if (!this.registered && cfg.devices?.[this.deviceID]) { + if (!this.registered && cfg.browsers?.[this.browserID]) { update = true; } this._data = cfg; @@ -61,7 +61,7 @@ export const ConnectionMixin = (SuperClass) => { // Subscribe to configuration updates conn.subscribeMessage((msg) => this.incoming_message(msg), { type: "browser_mod/connect", - deviceID: this.deviceID, + browserID: this.browserID, }); // Keep connection status up to date @@ -82,12 +82,12 @@ export const ConnectionMixin = (SuperClass) => { return this._data?.config ?? {}; } - get devices() { - return this._data?.devices ?? []; + get browsers() { + return this._data?.browsers ?? []; } get registered() { - return this.devices?.[this.deviceID] !== undefined; + return this.browsers?.[this.browserID] !== undefined; } set registered(reg) { @@ -96,13 +96,13 @@ export const ConnectionMixin = (SuperClass) => { if (this.registered) return; await this.connection.sendMessage({ type: "browser_mod/register", - deviceID: this.deviceID, + browserID: this.browserID, }); } else { if (!this.registered) return; await this.connection.sendMessage({ type: "browser_mod/unregister", - deviceID: this.deviceID, + browserID: this.browserID, }); } })(); @@ -111,9 +111,9 @@ export const ConnectionMixin = (SuperClass) => { private async _reregister(newData = {}) { await this.connection.sendMessage({ type: "browser_mod/reregister", - deviceID: this.deviceID, + browserID: this.browserID, data: { - ...this.devices[this.deviceID], + ...this.browsers[this.browserID], ...newData, }, }); @@ -121,7 +121,7 @@ export const ConnectionMixin = (SuperClass) => { get meta() { if (!this.registered) return null; - return this.devices[this.deviceID].meta; + return this.browsers[this.browserID].meta; } set meta(value) { this._reregister({ meta: value }); @@ -129,7 +129,7 @@ export const ConnectionMixin = (SuperClass) => { get cameraEnabled() { if (!this.registered) return null; - return this.devices[this.deviceID].camera; + return this.browsers[this.browserID].camera; } set cameraEnabled(value) { this._reregister({ camera: value }); @@ -143,18 +143,18 @@ export const ConnectionMixin = (SuperClass) => { this.connection.sendMessage({ type: "browser_mod/update", - deviceID: this.deviceID, + browserID: this.browserID, data, }); } - get deviceID() { + get browserID() { if (localStorage[ID_STORAGE_KEY]) return localStorage[ID_STORAGE_KEY]; - this.deviceID = ""; - return this.deviceID; + this.browserID = ""; + return this.browserID; } - set deviceID(id) { - function _createDeviceID() { + set browserID(id) { + function _createBrowserID() { const s4 = () => { return Math.floor((1 + Math.random()) * 100000) .toString(16) @@ -163,29 +163,27 @@ export const ConnectionMixin = (SuperClass) => { return window.fully?.getDeviceId() ?? `${s4()}${s4()}-${s4()}${s4()}`; } - if (id === "") id = _createDeviceID(); + if (id === "") id = _createBrowserID(); 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 + this.browsers?.[oldID] !== undefined && + this.browsers?.[this.browserID] === undefined ) { (async () => { await this.connection.sendMessage({ type: "browser_mod/reregister", - deviceID: oldID, + browserID: oldID, data: { - ...this.devices[oldID], - deviceID: this.deviceID, + ...this.browsers[oldID], + browserID: this.browserID, }, }); })(); } - - // TODO: Send update to backend to update device } } diff --git a/js/plugin/main.ts b/js/plugin/main.ts index 22b8225..85fc78b 100644 --- a/js/plugin/main.ts +++ b/js/plugin/main.ts @@ -16,8 +16,8 @@ import pjson from "../../package.json"; /* TODO: - Fix nomenclature - - Command -> Service - - Device -> Browser + x Command -> Service + x Device -> Browser - Popups X Basic popups - Card-mod integration @@ -81,107 +81,11 @@ export class BrowserMod extends ServicesMixin( console.info( `%cBROWSER_MOD ${pjson.version} IS INSTALLED - %cDeviceID: ${this.deviceID}`, + %cBrowserID: ${this.browserID}`, "color: green; font-weight: bold", "" ); } - - // async msg_callback(msg) { - // const handlers = { - // update: (msg) => this.update(msg), - // debug: (msg) => this.debug(msg), - - // play: (msg) => this.player_play(msg.media_content_id), - // pause: (msg) => this.player_pause(), - // stop: (msg) => this.player_stop(), - // "set-volume": (msg) => this.player_set_volume(msg.volume_level), - // mute: (msg) => this.player_mute(msg.mute), - - // toast: (msg) => this.do_toast(msg.message, msg.duration), - // popup: (msg) => this.do_popup(msg), - // "close-popup": (msg) => this.do_close_popup(), - // "more-info": (msg) => this.do_more_info(msg.entity_id, msg.large), - - // navigate: (msg) => this.do_navigate(msg.navigation_path), - // "set-theme": (msg) => this.set_theme(msg), - // "lovelace-reload": (msg) => this.lovelace_reload(msg), - // "window-reload": () => window.location.reload(), - - // blackout: (msg) => - // this.do_blackout(msg.time ? parseInt(msg.time) : undefined), - // "no-blackout": (msg) => { - // if (msg.brightness && this.isFully) { - // (window as any).fully.setScreenBrightness(msg.brightness); - // } - // this.no_blackout(); - // }, - - // "call-service": (msg) => this.call_service(msg), - // commands: async (msg) => { - // for (const m of msg.commands) { - // await this.msg_callback(m); - // } - // }, - // delay: async (msg) => - // await new Promise((resolve) => { - // window.setTimeout(resolve, msg.seconds * 1000); - // }), - // }; - - // await handlers[msg.command.replace("_", "-")](msg); - // } - - // debug(msg) { - // popUp(`deviceID`, { type: "markdown", content: `# ${deviceID}` }); - // alert(deviceID); - // } - - // set_theme(msg) { - // if (!msg.theme) msg.theme = "default"; - // fireEvent("settheme", { theme: msg.theme }, ha_element()); - // } - - // lovelace_reload(msg) { - // const ll = lovelace_view(); - // if (ll) fireEvent("config-refresh", {}, ll); - // } - - // call_service(msg) { - // const _replaceThis = (data) => { - // if (data === "this") return deviceID; - // if (Array.isArray(data)) return data.map(_replaceThis); - // if (data.constructor == Object) { - // for (const key in data) data[key] = _replaceThis(data[key]); - // } - // return data; - // }; - // const [domain, service] = msg.service.split(".", 2); - // let service_data = _replaceThis( - // JSON.parse(JSON.stringify(msg.service_data)) - // ); - // this.hass.callService(domain, service, service_data); - // } - - // // update(msg = null) { - // // if (msg) { - // // if (msg.name) { - // // this.entity_id = msg.name.toLowerCase(); - // // } - // // if (msg.camera && !this.isFully) { - // // this.setup_camera(); - // // } - // // this.config = { ...this.config, ...msg }; - // // } - // // this.player_update(); - // // this.fully_update(); - // // this.screen_update(); - // // this.sensor_update(); - // // } } -// (async () => { -// await hass_loaded(); - if (!window.browser_mod) window.browser_mod = new BrowserMod(); -// })();