Renamed Device to Browser throughout
This commit is contained in:
		
							parent
							
								
									3bf2481e5b
								
							
						
					
					
						commit
						acc4a15e02
					
				| @ -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, | ||||
|     } | ||||
|  | ||||
| @ -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] | ||||
| @ -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 { | ||||
|           </ha-icon-button> | ||||
|         </div> | ||||
| 
 | ||||
|         <div class="device-id">${window.browser_mod.deviceID}</div> | ||||
|         <div class="browser-id">${window.browser_mod.browserID}</div> | ||||
|       </ha-card> | ||||
|     `;
 | ||||
|     } | ||||
| @ -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(); | ||||
| // })();
 | ||||
| 
 | ||||
| export { BrowserMod }; | ||||
|  | ||||
| @ -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(() => { | ||||
|                 </ha-settings-row> | ||||
| 
 | ||||
|                 <ha-settings-row> | ||||
|                   <span slot="heading">DeviceID</span> | ||||
|                   <span slot="heading">BrowserID</span> | ||||
|                   <span slot="description" | ||||
|                     >A unique identifier for this browser-device | ||||
|                     combination.</span | ||||
|                   > | ||||
|                   <ha-textfield | ||||
|                     .value=${(_c = window.browser_mod) === null || _c === void 0 ? void 0 : _c.deviceID} | ||||
|                     @change=${this.changeDeviceID} | ||||
|                     .value=${(_c = window.browser_mod) === null || _c === void 0 ? void 0 : _c.browserID} | ||||
|                     @change=${this.changeBrowserID} | ||||
|                   ></ha-textfield> | ||||
|                 </ha-settings-row> | ||||
| 
 | ||||
|                 <ha-settings-row> | ||||
|                   <span slot="heading">Enable camera</span> | ||||
|                   <span slot="description" | ||||
|                     >Get camera input from this device (hardware | ||||
|                     >Get camera input from this browser (hardware | ||||
|                     dependent)</span | ||||
|                   > | ||||
|                   <ha-switch | ||||
| @ -201,20 +201,20 @@ loadDevTools().then(() => { | ||||
|               </div> | ||||
|             </ha-card> | ||||
| 
 | ||||
|             <ha-card header="Registered devices" outlined> | ||||
|             <ha-card header="Registered browsers" outlined> | ||||
|               <div class="card-content"> | ||||
|                 ${Object.keys(window.browser_mod.devices).map((d) => $ ` <ha-settings-row>
 | ||||
|                 ${Object.keys(window.browser_mod.browsers).map((d) => $ ` <ha-settings-row>
 | ||||
|                     <span slot="heading"> ${d} </span> | ||||
|                     <span slot="description"> | ||||
|                       Last connected: | ||||
|                       <ha-relative-time | ||||
|                         .hass=${this.hass} | ||||
|                         .datetime=${window.browser_mod.devices[d].last_seen} | ||||
|                         .datetime=${window.browser_mod.browsers[d].last_seen} | ||||
|                       ></ha-relative-time> | ||||
|                     </span> | ||||
|                     <ha-icon-button | ||||
|                       .deviceID=${d} | ||||
|                       @click=${this.unregister_device} | ||||
|                       .browserID=${d} | ||||
|                       @click=${this.unregister_browser} | ||||
|                     > | ||||
|                       <ha-icon .icon=${"mdi:delete"}></ha-icon> | ||||
|                     </ha-icon-button> | ||||
|  | ||||
| @ -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): | ||||
|  | ||||
| @ -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) | ||||
|  | ||||
| @ -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" | ||||
|  | ||||
| @ -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 | ||||
|  | ||||
| @ -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(' ','_')}" | ||||
|  | ||||
| @ -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") | ||||
|  | ||||
| @ -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") | ||||
|  | ||||
| @ -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 | ||||
|  | ||||
| @ -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) | ||||
|  | ||||
| @ -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() | ||||
|  | ||||
| @ -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(() => { | ||||
|                 </ha-settings-row> | ||||
| 
 | ||||
|                 <ha-settings-row> | ||||
|                   <span slot="heading">DeviceID</span> | ||||
|                   <span slot="heading">BrowserID</span> | ||||
|                   <span slot="description" | ||||
|                     >A unique identifier for this browser-device | ||||
|                     combination.</span | ||||
|                   > | ||||
|                   <ha-textfield | ||||
|                     .value=${window.browser_mod?.deviceID} | ||||
|                     @change=${this.changeDeviceID} | ||||
|                     .value=${window.browser_mod?.browserID} | ||||
|                     @change=${this.changeBrowserID} | ||||
|                   ></ha-textfield> | ||||
|                 </ha-settings-row> | ||||
| 
 | ||||
|                 <ha-settings-row> | ||||
|                   <span slot="heading">Enable camera</span> | ||||
|                   <span slot="description" | ||||
|                     >Get camera input from this device (hardware | ||||
|                     >Get camera input from this browser (hardware | ||||
|                     dependent)</span | ||||
|                   > | ||||
|                   <ha-switch | ||||
| @ -134,21 +134,21 @@ loadDevTools().then(() => { | ||||
|               </div> | ||||
|             </ha-card> | ||||
| 
 | ||||
|             <ha-card header="Registered devices" outlined> | ||||
|             <ha-card header="Registered browsers" outlined> | ||||
|               <div class="card-content"> | ||||
|                 ${Object.keys(window.browser_mod.devices).map( | ||||
|                 ${Object.keys(window.browser_mod.browsers).map( | ||||
|                   (d) => html` <ha-settings-row>
 | ||||
|                     <span slot="heading"> ${d} </span> | ||||
|                     <span slot="description"> | ||||
|                       Last connected: | ||||
|                       <ha-relative-time | ||||
|                         .hass=${this.hass} | ||||
|                         .datetime=${window.browser_mod.devices[d].last_seen} | ||||
|                         .datetime=${window.browser_mod.browsers[d].last_seen} | ||||
|                       ></ha-relative-time> | ||||
|                     </span> | ||||
|                     <ha-icon-button | ||||
|                       .deviceID=${d} | ||||
|                       @click=${this.unregister_device} | ||||
|                       .browserID=${d} | ||||
|                       @click=${this.unregister_browser} | ||||
|                     > | ||||
|                       <ha-icon .icon=${"mdi:delete"}></ha-icon> | ||||
|                     </ha-icon-button> | ||||
|  | ||||
| @ -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 { | ||||
|           </ha-icon-button> | ||||
|         </div> | ||||
| 
 | ||||
|         <div class="device-id">${window.browser_mod.deviceID}</div> | ||||
|         <div class="browser-id">${window.browser_mod.browserID}</div> | ||||
|       </ha-card> | ||||
|     `;
 | ||||
|   } | ||||
| @ -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; | ||||
|  | ||||
| @ -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
 | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|  | ||||
| @ -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(); | ||||
| // })();
 | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user