Renamed Device to Browser throughout

This commit is contained in:
Thomas Lovén 2022-07-18 20:51:07 +00:00
parent 3bf2481e5b
commit acc4a15e02
18 changed files with 227 additions and 369 deletions

View File

@ -3,7 +3,7 @@ import logging
from .store import BrowserModStore from .store import BrowserModStore
from .mod_view import async_setup_view from .mod_view import async_setup_view
from .connection import async_setup_connection 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 from .service import async_setup_services
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
@ -15,7 +15,7 @@ async def async_setup(hass, config):
await store.load() await store.load()
hass.data[DOMAIN] = { hass.data[DOMAIN] = {
DATA_DEVICES: {}, DATA_BROWSERS: {},
DATA_ADDERS: {}, DATA_ADDERS: {},
DATA_STORE: store, DATA_STORE: store,
} }

View File

@ -3,7 +3,7 @@ import logging
from homeassistant.components.websocket_api import event_message from homeassistant.components.websocket_api import event_message
from homeassistant.helpers import device_registry, entity_registry 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 .coordinator import Coordinator
from .sensor import BrowserSensor from .sensor import BrowserSensor
from .light import BrowserModLight from .light import BrowserModLight
@ -14,13 +14,13 @@ from .camera import BrowserModCamera
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
class BrowserModDevice: class BrowserModBrowser:
"""A Browser_mod device.""" """A Browser_mod browser."""
def __init__(self, hass, deviceID): def __init__(self, hass, browserID):
""" """ """ """
self.deviceID = deviceID self.browserID = browserID
self.coordinator = Coordinator(hass, deviceID) self.coordinator = Coordinator(hass, browserID)
self.entities = {} self.entities = {}
self.data = {} self.data = {}
self.settings = {} self.settings = {}
@ -38,17 +38,17 @@ class BrowserModDevice:
self.update_entities(hass) self.update_entities(hass)
def update_entities(self, hass): def update_entities(self, hass):
"""Create all entities associated with the device.""" """Create all entities associated with the browser."""
coordinator = self.coordinator coordinator = self.coordinator
deviceID = self.deviceID browserID = self.browserID
def _assert_browser_sensor(type, name, *properties): def _assert_browser_sensor(type, name, *properties):
if name in self.entities: if name in self.entities:
return return
adder = hass.data[DOMAIN][DATA_ADDERS][type] adder = hass.data[DOMAIN][DATA_ADDERS][type]
cls = {"sensor": BrowserSensor, "binary_sensor": BrowserBinarySensor}[type] cls = {"sensor": BrowserSensor, "binary_sensor": BrowserBinarySensor}[type]
new = cls(coordinator, deviceID, name, *properties) new = cls(coordinator, browserID, name, *properties)
adder([new]) adder([new])
self.entities[name] = new self.entities[name] = new
@ -70,19 +70,19 @@ class BrowserModDevice:
if "screen" not in self.entities: if "screen" not in self.entities:
adder = hass.data[DOMAIN][DATA_ADDERS]["light"] adder = hass.data[DOMAIN][DATA_ADDERS]["light"]
new = BrowserModLight(coordinator, deviceID, self) new = BrowserModLight(coordinator, browserID, self)
adder([new]) adder([new])
self.entities["screen"] = new self.entities["screen"] = new
if "player" not in self.entities: if "player" not in self.entities:
adder = hass.data[DOMAIN][DATA_ADDERS]["media_player"] adder = hass.data[DOMAIN][DATA_ADDERS]["media_player"]
new = BrowserModPlayer(coordinator, deviceID, self) new = BrowserModPlayer(coordinator, browserID, self)
adder([new]) adder([new])
self.entities["player"] = new self.entities["player"] = new
if "camera" not in self.entities and self.settings.get("camera"): if "camera" not in self.entities and self.settings.get("camera"):
adder = hass.data[DOMAIN][DATA_ADDERS]["camera"] adder = hass.data[DOMAIN][DATA_ADDERS]["camera"]
new = BrowserModCamera(coordinator, deviceID) new = BrowserModCamera(coordinator, browserID)
adder([new]) adder([new])
self.entities["camera"] = new self.entities["camera"] = new
if "camera" in self.entities and not self.settings.get("camera"): if "camera" in self.entities and not self.settings.get("camera"):
@ -95,7 +95,7 @@ class BrowserModDevice:
) )
def send(self, command, **kwargs): def send(self, command, **kwargs):
"""Send a command to this device.""" """Send a command to this browser."""
if self.connection is None: if self.connection is None:
return return
@ -112,7 +112,7 @@ class BrowserModDevice:
) )
def delete(self, hass): def delete(self, hass):
"""Delete device and associated entities.""" """Delete browser and associated entities."""
dr = device_registry.async_get(hass) dr = device_registry.async_get(hass)
er = entity_registry.async_get(hass) er = entity_registry.async_get(hass)
@ -121,25 +121,25 @@ class BrowserModDevice:
self.entities = {} self.entities = {}
device = dr.async_get_device({(DOMAIN, self.deviceID)}) device = dr.async_get_device({(DOMAIN, self.browserID)})
dr.async_remove_device(device.id) dr.async_remove_device(device.id)
def getDevice(hass, deviceID, *, create=True): def getBrowser(hass, browserID, *, create=True):
"""Get or create device by deviceID.""" """Get or create browser by browserID."""
devices = hass.data[DOMAIN]["devices"] browsers = hass.data[DOMAIN][DATA_BROWSERS]
if deviceID in devices: if browserID in browsers:
return devices[deviceID] return browsers[browserID]
if not create: if not create:
return None return None
devices[deviceID] = BrowserModDevice(hass, deviceID) browsers[browserID] = BrowserModBrowser(hass, browserID)
return devices[deviceID] return browsers[browserID]
def deleteDevice(hass, deviceID): def deleteBrowser(hass, browserID):
devices = hass.data[DOMAIN]["devices"] browsers = hass.data[DOMAIN][DATA_BROWSERS]
if deviceID in devices: if browserID in browsers:
devices[deviceID].delete(hass) browsers[browserID].delete(hass)
del devices[deviceID] del browsers[browserID]

View File

@ -129,7 +129,7 @@ class BrowserPlayer extends s {
composed: true, composed: true,
cancelable: false, cancelable: false,
detail: { 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> </ha-icon-button>
</div> </div>
<div class="device-id">${window.browser_mod.deviceID}</div> <div class="browser-id">${window.browser_mod.browserID}</div>
</ha-card> </ha-card>
`; `;
} }
@ -196,7 +196,7 @@ class BrowserPlayer extends s {
width: 24px; width: 24px;
padding: 8px; padding: 8px;
} }
.device-id { .browser-id {
opacity: 0.7; opacity: 0.7;
font-size: xx-small; font-size: xx-small;
margin-top: -10px; 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)); 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) => { const ConnectionMixin = (SuperClass) => {
class BrowserModConnection extends SuperClass { class BrowserModConnection extends SuperClass {
constructor() { constructor() {
@ -269,7 +269,7 @@ const ConnectionMixin = (SuperClass) => {
this.connectionPromise = new Promise((resolve) => { this.connectionPromise = new Promise((resolve) => {
this._connectionResolve = resolve; this._connectionResolve = resolve;
}); });
this.deviceEntities = {}; this.browserEntities = {};
} }
LOG(...args) { LOG(...args) {
const dt = new Date(); const dt = new Date();
@ -284,8 +284,8 @@ const ConnectionMixin = (SuperClass) => {
this.LOG("Command:", msg); this.LOG("Command:", msg);
this.fireEvent(`command-${msg.command}`, msg); this.fireEvent(`command-${msg.command}`, msg);
} }
else if (msg.deviceEntities) { else if (msg.browserEntities) {
this.deviceEntities = msg.deviceEntities; this.browserEntities = msg.browserEntities;
} }
else if (msg.result) { else if (msg.result) {
this.update_config(msg.result); this.update_config(msg.result);
@ -296,7 +296,7 @@ const ConnectionMixin = (SuperClass) => {
var _a; var _a;
this.LOG("Receive:", cfg); this.LOG("Receive:", cfg);
let update = false; 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; update = true;
} }
this._data = cfg; this._data = cfg;
@ -314,7 +314,7 @@ const ConnectionMixin = (SuperClass) => {
// Subscribe to configuration updates // Subscribe to configuration updates
conn.subscribeMessage((msg) => this.incoming_message(msg), { conn.subscribeMessage((msg) => this.incoming_message(msg), {
type: "browser_mod/connect", type: "browser_mod/connect",
deviceID: this.deviceID, browserID: this.browserID,
}); });
// Keep connection status up to date // Keep connection status up to date
conn.addEventListener("disconnected", () => { conn.addEventListener("disconnected", () => {
@ -332,13 +332,13 @@ const ConnectionMixin = (SuperClass) => {
var _a, _b; var _a, _b;
return (_b = (_a = this._data) === null || _a === void 0 ? void 0 : _a.config) !== null && _b !== void 0 ? _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; 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() { get registered() {
var _a; 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) { set registered(reg) {
(async () => { (async () => {
@ -347,7 +347,7 @@ const ConnectionMixin = (SuperClass) => {
return; return;
await this.connection.sendMessage({ await this.connection.sendMessage({
type: "browser_mod/register", type: "browser_mod/register",
deviceID: this.deviceID, browserID: this.browserID,
}); });
} }
else { else {
@ -355,7 +355,7 @@ const ConnectionMixin = (SuperClass) => {
return; return;
await this.connection.sendMessage({ await this.connection.sendMessage({
type: "browser_mod/unregister", type: "browser_mod/unregister",
deviceID: this.deviceID, browserID: this.browserID,
}); });
} }
})(); })();
@ -363,14 +363,14 @@ const ConnectionMixin = (SuperClass) => {
async _reregister(newData = {}) { async _reregister(newData = {}) {
await this.connection.sendMessage({ await this.connection.sendMessage({
type: "browser_mod/reregister", type: "browser_mod/reregister",
deviceID: this.deviceID, browserID: this.browserID,
data: Object.assign(Object.assign({}, this.devices[this.deviceID]), newData), data: Object.assign(Object.assign({}, this.browsers[this.browserID]), newData),
}); });
} }
get meta() { get meta() {
if (!this.registered) if (!this.registered)
return null; return null;
return this.devices[this.deviceID].meta; return this.browsers[this.browserID].meta;
} }
set meta(value) { set meta(value) {
this._reregister({ meta: value }); this._reregister({ meta: value });
@ -378,7 +378,7 @@ const ConnectionMixin = (SuperClass) => {
get cameraEnabled() { get cameraEnabled() {
if (!this.registered) if (!this.registered)
return null; return null;
return this.devices[this.deviceID].camera; return this.browsers[this.browserID].camera;
} }
set cameraEnabled(value) { set cameraEnabled(value) {
this._reregister({ camera: value }); this._reregister({ camera: value });
@ -389,19 +389,19 @@ const ConnectionMixin = (SuperClass) => {
this.LOG("Send:", data); this.LOG("Send:", data);
this.connection.sendMessage({ this.connection.sendMessage({
type: "browser_mod/update", type: "browser_mod/update",
deviceID: this.deviceID, browserID: this.browserID,
data, data,
}); });
} }
get deviceID() { get browserID() {
if (localStorage[ID_STORAGE_KEY]) if (localStorage[ID_STORAGE_KEY])
return localStorage[ID_STORAGE_KEY]; return localStorage[ID_STORAGE_KEY];
this.deviceID = ""; this.browserID = "";
return this.deviceID; return this.browserID;
} }
set deviceID(id) { set browserID(id) {
var _a, _b; var _a, _b;
function _createDeviceID() { function _createBrowserID() {
var _a, _b; var _a, _b;
const s4 = () => { const s4 = () => {
return Math.floor((1 + Math.random()) * 100000) 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()}`; return (_b = (_a = window.fully) === null || _a === void 0 ? void 0 : _a.getDeviceId()) !== null && _b !== void 0 ? _b : `${s4()}${s4()}-${s4()}${s4()}`;
} }
if (id === "") if (id === "")
id = _createDeviceID(); id = _createBrowserID();
const oldID = localStorage[ID_STORAGE_KEY]; const oldID = localStorage[ID_STORAGE_KEY];
localStorage[ID_STORAGE_KEY] = id; localStorage[ID_STORAGE_KEY] = id;
this.fireEvent("browser-mod-config-update"); this.fireEvent("browser-mod-config-update");
if (((_a = this.devices) === null || _a === void 0 ? void 0 : _a[oldID]) !== undefined && if (((_a = this.browsers) === null || _a === void 0 ? void 0 : _a[oldID]) !== undefined &&
((_b = this.devices) === null || _b === void 0 ? void 0 : _b[this.deviceID]) === undefined) { ((_b = this.browsers) === null || _b === void 0 ? void 0 : _b[this.browserID]) === undefined) {
(async () => { (async () => {
await this.connection.sendMessage({ await this.connection.sendMessage({
type: "browser_mod/reregister", type: "browser_mod/reregister",
deviceID: oldID, browserID: oldID,
data: Object.assign(Object.assign({}, this.devices[oldID]), { deviceID: this.deviceID }), data: Object.assign(Object.assign({}, this.browsers[oldID]), { browserID: this.browserID }),
}); });
})(); })();
} }
// TODO: Send update to backend to update device
} }
} }
return BrowserModConnection; return BrowserModConnection;
@ -1256,8 +1255,8 @@ var pjson = {
/* /*
TODO: TODO:
- Fix nomenclature - Fix nomenclature
- Command -> Service x Command -> Service
- Device -> Browser x Device -> Browser
- Popups - Popups
X Basic popups X Basic popups
- Card-mod integration - Card-mod integration
@ -1306,13 +1305,10 @@ class BrowserMod extends ServicesMixin(PopupMixin(BrowserStateMixin(CameraMixin(
// } // }
// }); // });
console.info(`%cBROWSER_MOD ${pjson.version} IS INSTALLED 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) if (!window.browser_mod)
window.browser_mod = new BrowserMod(); window.browser_mod = new BrowserMod();
// })();
export { BrowserMod }; export { BrowserMod };

View File

@ -90,28 +90,28 @@ loadDevTools().then(() => {
return; return;
window.browser_mod.registered = !window.browser_mod.registered; window.browser_mod.registered = !window.browser_mod.registered;
} }
changeDeviceID(ev) { changeBrowserID(ev) {
window.browser_mod.deviceID = ev.target.value; window.browser_mod.browserID = ev.target.value;
} }
toggleCameraEnabled() { toggleCameraEnabled() {
window.browser_mod.cameraEnabled = !window.browser_mod.cameraEnabled; window.browser_mod.cameraEnabled = !window.browser_mod.cameraEnabled;
} }
unregister_device(ev) { unregister_browser(ev) {
const deviceID = ev.currentTarget.deviceID; const browserID = ev.currentTarget.browserID;
const unregisterCallback = () => { const unregisterCallback = () => {
console.log(deviceID, window.browser_mod.deviceID); console.log(browserID, window.browser_mod.browserID);
if (deviceID === window.browser_mod.deviceID) { if (browserID === window.browser_mod.browserID) {
console.log("Unregister self"); console.log("Unregister self");
window.browser_mod.registered = false; window.browser_mod.registered = false;
} }
else { else {
window.browser_mod.connection.sendMessage({ window.browser_mod.connection.sendMessage({
type: "browser_mod/unregister", 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", primary_action: "Yes",
secondary_action: "No", secondary_action: "No",
callbacks: { callbacks: {
@ -176,21 +176,21 @@ loadDevTools().then(() => {
</ha-settings-row> </ha-settings-row>
<ha-settings-row> <ha-settings-row>
<span slot="heading">DeviceID</span> <span slot="heading">BrowserID</span>
<span slot="description" <span slot="description"
>A unique identifier for this browser-device >A unique identifier for this browser-device
combination.</span combination.</span
> >
<ha-textfield <ha-textfield
.value=${(_c = window.browser_mod) === null || _c === void 0 ? void 0 : _c.deviceID} .value=${(_c = window.browser_mod) === null || _c === void 0 ? void 0 : _c.browserID}
@change=${this.changeDeviceID} @change=${this.changeBrowserID}
></ha-textfield> ></ha-textfield>
</ha-settings-row> </ha-settings-row>
<ha-settings-row> <ha-settings-row>
<span slot="heading">Enable camera</span> <span slot="heading">Enable camera</span>
<span slot="description" <span slot="description"
>Get camera input from this device (hardware >Get camera input from this browser (hardware
dependent)</span dependent)</span
> >
<ha-switch <ha-switch
@ -201,20 +201,20 @@ loadDevTools().then(() => {
</div> </div>
</ha-card> </ha-card>
<ha-card header="Registered devices" outlined> <ha-card header="Registered browsers" outlined>
<div class="card-content"> <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="heading"> ${d} </span>
<span slot="description"> <span slot="description">
Last connected: Last connected:
<ha-relative-time <ha-relative-time
.hass=${this.hass} .hass=${this.hass}
.datetime=${window.browser_mod.devices[d].last_seen} .datetime=${window.browser_mod.browsers[d].last_seen}
></ha-relative-time> ></ha-relative-time>
</span> </span>
<ha-icon-button <ha-icon-button
.deviceID=${d} .browserID=${d}
@click=${this.unregister_device} @click=${this.unregister_browser}
> >
<ha-icon .icon=${"mdi:delete"}></ha-icon> <ha-icon .icon=${"mdi:delete"}></ha-icon>
</ha-icon-button> </ha-icon-button>

View File

@ -21,13 +21,13 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
class BrowserModCamera(BrowserModEntity, Camera): class BrowserModCamera(BrowserModEntity, Camera):
def __init__(self, coordinator, deviceID): def __init__(self, coordinator, browserID):
BrowserModEntity.__init__(self, coordinator, deviceID, None) BrowserModEntity.__init__(self, coordinator, browserID, None)
Camera.__init__(self) Camera.__init__(self)
@property @property
def unique_id(self): def unique_id(self):
return f"{self.deviceID}-camera" return f"{self.browserID}-camera"
@property @property
def entity_registry_visible_default(self): def entity_registry_visible_default(self):

View File

@ -18,7 +18,7 @@ from .const import (
DOMAIN, DOMAIN,
) )
from .device import getDevice, deleteDevice from .browser import getBrowser, deleteBrowser
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
@ -27,12 +27,12 @@ async def async_setup_connection(hass):
@websocket_api.websocket_command( @websocket_api.websocket_command(
{ {
vol.Required("type"): WS_CONNECT, vol.Required("type"): WS_CONNECT,
vol.Required("deviceID"): str, vol.Required("browserID"): str,
} }
) )
@websocket_api.async_response @websocket_api.async_response
async def handle_connect(hass, connection, msg): async def handle_connect(hass, connection, msg):
deviceID = msg["deviceID"] browserID = msg["browserID"]
store = hass.data[DOMAIN]["store"] store = hass.data[DOMAIN]["store"]
def listener(data): def listener(data):
@ -41,93 +41,93 @@ async def async_setup_connection(hass):
connection.subscriptions[msg["id"]] = store.add_listener(listener) connection.subscriptions[msg["id"]] = store.add_listener(listener)
connection.send_result(msg["id"]) connection.send_result(msg["id"])
if store.get_device(deviceID).enabled: if store.get_browser(browserID).enabled:
dev = getDevice(hass, deviceID) dev = getBrowser(hass, browserID)
dev.update_settings(hass, store.get_device(deviceID).asdict()) dev.update_settings(hass, store.get_browser(browserID).asdict())
dev.connection = (connection, msg["id"]) dev.connection = (connection, msg["id"])
await store.set_device( await store.set_browser(
deviceID, last_seen=datetime.now(tz=timezone.utc).isoformat() browserID, last_seen=datetime.now(tz=timezone.utc).isoformat()
) )
listener(store.asdict()) listener(store.asdict())
@websocket_api.websocket_command( @websocket_api.websocket_command(
{ {
vol.Required("type"): WS_REGISTER, vol.Required("type"): WS_REGISTER,
vol.Required("deviceID"): str, vol.Required("browserID"): str,
} }
) )
@websocket_api.async_response @websocket_api.async_response
async def handle_register(hass, connection, msg): async def handle_register(hass, connection, msg):
deviceID = msg["deviceID"] browserID = msg["browserID"]
store = hass.data[DOMAIN]["store"] store = hass.data[DOMAIN]["store"]
await store.set_device(deviceID, enabled=True) await store.set_browser(browserID, enabled=True)
connection.send_result(msg["id"]) connection.send_result(msg["id"])
@websocket_api.websocket_command( @websocket_api.websocket_command(
{ {
vol.Required("type"): WS_UNREGISTER, vol.Required("type"): WS_UNREGISTER,
vol.Required("deviceID"): str, vol.Required("browserID"): str,
} }
) )
@websocket_api.async_response @websocket_api.async_response
async def handle_unregister(hass, connection, msg): async def handle_unregister(hass, connection, msg):
deviceID = msg["deviceID"] browserID = msg["browserID"]
store = hass.data[DOMAIN]["store"] store = hass.data[DOMAIN]["store"]
deleteDevice(hass, deviceID) deleteBrowser(hass, browserID)
await store.delete_device(deviceID) await store.delete_browser(browserID)
connection.send_result(msg["id"]) connection.send_result(msg["id"])
@websocket_api.websocket_command( @websocket_api.websocket_command(
{ {
vol.Required("type"): WS_REREGISTER, vol.Required("type"): WS_REREGISTER,
vol.Required("deviceID"): str, vol.Required("browserID"): str,
vol.Required("data"): dict, vol.Required("data"): dict,
} }
) )
@websocket_api.async_response @websocket_api.async_response
async def handle_reregister(hass, connection, msg): async def handle_reregister(hass, connection, msg):
deviceID = msg["deviceID"] browserID = msg["browserID"]
store = hass.data[DOMAIN]["store"] store = hass.data[DOMAIN]["store"]
data = msg["data"] data = msg["data"]
del data["last_seen"] del data["last_seen"]
deviceSettings = {} browserSettings = {}
if "deviceID" in data: if "browserID" in data:
newDeviceID = data["deviceID"] newBrowserID = data["browserID"]
del data["deviceID"] del data["browserID"]
oldDeviceSettings = store.get_device(deviceID) oldBrowserSetting = store.get_browser(browserID)
if oldDeviceSettings: if oldBrowserSetting:
deviceSettings = oldDeviceSettings.asdict() browserSettings = oldBrowserSetting.asdict()
await store.delete_device(deviceID) 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) dev.update_settings(hass, data)
deviceSettings.update(data) browserSettings.update(data)
await store.set_device(deviceID, **deviceSettings) await store.set_browser(browserID, **browserSettings)
@websocket_api.websocket_command( @websocket_api.websocket_command(
{ {
vol.Required("type"): WS_UPDATE, vol.Required("type"): WS_UPDATE,
vol.Required("deviceID"): str, vol.Required("browserID"): str,
vol.Optional("data"): dict, vol.Optional("data"): dict,
} }
) )
@websocket_api.async_response @websocket_api.async_response
async def handle_update(hass, connection, msg): async def handle_update(hass, connection, msg):
deviceID = msg["deviceID"] browserID = msg["browserID"]
store = hass.data[DOMAIN]["store"] store = hass.data[DOMAIN]["store"]
if store.get_device(deviceID).enabled: if store.get_browser(browserID).enabled:
dev = getDevice(hass, deviceID) dev = getBrowser(hass, browserID)
dev.update(hass, msg.get("data", {})) dev.update(hass, msg.get("data", {}))
async_register_command(hass, handle_connect) async_register_command(hass, handle_connect)

View File

@ -3,7 +3,7 @@ DOMAIN = "browser_mod"
FRONTEND_SCRIPT_URL = "/browser_mod.js" FRONTEND_SCRIPT_URL = "/browser_mod.js"
SETTINGS_PANEL_URL = "/browser_mod_panel.js" SETTINGS_PANEL_URL = "/browser_mod_panel.js"
DATA_DEVICES = "devices" DATA_BROWSERS = "browsers"
DATA_ADDERS = "adders" DATA_ADDERS = "adders"
DATA_STORE = "store" DATA_STORE = "store"
DATA_ALIASES = "aliases" DATA_ALIASES = "aliases"

View File

@ -8,10 +8,10 @@ _LOGGER = logging.getLogger(__name__)
class Coordinator(DataUpdateCoordinator): class Coordinator(DataUpdateCoordinator):
def __init__(self, hass, deviceID): def __init__(self, hass, browserID):
super().__init__( super().__init__(
hass, hass,
_LOGGER, _LOGGER,
name="Browser Mod Coordinator", name="Browser Mod Coordinator",
) )
self.deviceID = deviceID self.browserID = browserID

View File

@ -11,9 +11,9 @@ _LOGGER = logging.getLogger(__name__)
class BrowserModEntity(CoordinatorEntity): class BrowserModEntity(CoordinatorEntity):
def __init__(self, coordinator, deviceID, name): def __init__(self, coordinator, browserID, name):
super().__init__(coordinator) super().__init__(coordinator)
self.deviceID = deviceID self.browserID = browserID
self._name = name self._name = name
@property @property
@ -26,8 +26,8 @@ class BrowserModEntity(CoordinatorEntity):
if ip := self._data.get("browser", {}).get("ip_address"): if ip := self._data.get("browser", {}).get("ip_address"):
config_url = {"configuration_url": f"http://{ip}:2323"} config_url = {"configuration_url": f"http://{ip}:2323"}
return { return {
"identifiers": {(DOMAIN, self.deviceID)}, "identifiers": {(DOMAIN, self.browserID)},
"name": self.deviceID, "name": self.browserID,
"manufacturer": "Browser Mod", "manufacturer": "Browser Mod",
**config_url, **config_url,
} }
@ -36,7 +36,7 @@ class BrowserModEntity(CoordinatorEntity):
def extra_state_attributes(self): def extra_state_attributes(self):
return { return {
"type": "browser_mod", "type": "browser_mod",
"deviceID": self.deviceID, "browserID": self.browserID,
} }
@property @property
@ -53,4 +53,4 @@ class BrowserModEntity(CoordinatorEntity):
@property @property
def unique_id(self): def unique_id(self):
return f"{self.deviceID}-{self._name.replace(' ','_')}" return f"{self.browserID}-{self._name.replace(' ','_')}"

View File

@ -15,10 +15,10 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
class BrowserModLight(BrowserModEntity, LightEntity): class BrowserModLight(BrowserModEntity, LightEntity):
def __init__(self, coordinator, deviceID, device): def __init__(self, coordinator, browserID, browser):
BrowserModEntity.__init__(self, coordinator, deviceID, "Screen") BrowserModEntity.__init__(self, coordinator, browserID, "Screen")
LightEntity.__init__(self) LightEntity.__init__(self)
self.device = device self.browser = browser
@property @property
def entity_registry_visible_default(self): def entity_registry_visible_default(self):
@ -41,7 +41,7 @@ class BrowserModLight(BrowserModEntity, LightEntity):
return self._data.get("screen_brightness", 1) return self._data.get("screen_brightness", 1)
def turn_on(self, **kwargs): def turn_on(self, **kwargs):
self.device.send("screen_on", **kwargs) self.browser.send("screen_on", **kwargs)
def turn_off(self, **kwargs): def turn_off(self, **kwargs):
self.device.send("screen_off") self.browser.send("screen_off")

View File

@ -39,14 +39,14 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
class BrowserModPlayer(BrowserModEntity, MediaPlayerEntity): class BrowserModPlayer(BrowserModEntity, MediaPlayerEntity):
def __init__(self, coordinator, deviceID, device): def __init__(self, coordinator, browserID, browser):
BrowserModEntity.__init__(self, coordinator, deviceID, None) BrowserModEntity.__init__(self, coordinator, browserID, None)
MediaPlayerEntity.__init__(self) MediaPlayerEntity.__init__(self)
self.device = device self.browser = browser
@property @property
def unique_id(self): def unique_id(self):
return f"{self.deviceID}-player" return f"{self.browserID}-player"
@property @property
def entity_registry_visible_default(self): def entity_registry_visible_default(self):
@ -83,10 +83,10 @@ class BrowserModPlayer(BrowserModEntity, MediaPlayerEntity):
return self._data.get("player", {}).get("muted", False) return self._data.get("player", {}).get("muted", False)
def set_volume_level(self, volume): 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): 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): async def async_play_media(self, media_type, media_id, **kwargs):
if media_source.is_media_source_id(media_id): if media_source.is_media_source_id(media_id):
@ -97,7 +97,7 @@ class BrowserModPlayer(BrowserModEntity, MediaPlayerEntity):
media_id = play_item.url media_id = play_item.url
if media_type in (MEDIA_TYPE_URL, MEDIA_TYPE_MUSIC): if media_type in (MEDIA_TYPE_URL, MEDIA_TYPE_MUSIC):
media_id = async_process_play_media_url(self.hass, media_id) 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): async def async_browse_media(self, media_content_type=None, media_content_id=None):
"""Implement the websocket media browsing helper.""" """Implement the websocket media browsing helper."""
@ -108,10 +108,10 @@ class BrowserModPlayer(BrowserModEntity, MediaPlayerEntity):
) )
def media_play(self): def media_play(self):
self.device.send("player-play") self.browser.send("player-play")
def media_pause(self): def media_pause(self):
self.device.send("player-pause") self.browser.send("player-pause")
def media_stop(self): def media_stop(self):
self.device.send("player-stop") self.browser.send("player-stop")

View File

@ -18,13 +18,13 @@ class BrowserSensor(BrowserModEntity, SensorEntity):
def __init__( def __init__(
self, self,
coordinator, coordinator,
deviceID, browserID,
parameter, parameter,
name, name,
unit_of_measurement=None, unit_of_measurement=None,
device_class=None, device_class=None,
): ):
super().__init__(coordinator, deviceID, name) super().__init__(coordinator, browserID, name)
self.parameter = parameter self.parameter = parameter
self._device_class = device_class self._device_class = device_class
self._unit_of_measurement = unit_of_measurement self._unit_of_measurement = unit_of_measurement

View File

@ -1,17 +1,10 @@
import logging import logging
from homeassistant.helpers.entity_registry import ( from homeassistant.helpers import device_registry
async_entries_for_config_entry,
async_entries_for_device,
)
from homeassistant.const import STATE_UNAVAILABLE
from homeassistant.helpers import device_registry, area_registry
from .const import ( from .const import (
DOMAIN, DOMAIN,
DATA_DEVICES, DATA_BROWSERS,
DATA_ALIASES,
USER_COMMANDS,
) )
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
@ -20,29 +13,31 @@ _LOGGER = logging.getLogger(__name__)
async def async_setup_services(hass): async def async_setup_services(hass):
def call_service(service, targets, data): def call_service(service, targets, data):
devices = hass.data[DOMAIN][DATA_DEVICES] browsers = hass.data[DOMAIN][DATA_BROWSERS]
if isinstance(targets, str): if isinstance(targets, str):
targets = [targets] targets = [targets]
# If no targets were specified, send to all browsers
if len(targets) == 0:
targets = browsers.keys()
for target in targets: for target in targets:
if target not in devices: if target not in browsers:
continue continue
device = devices[target] browser = browsers[target]
device.send(service, **data) browser.send(service, **data)
def handle_service(call): def handle_service(call):
service = call.service service = call.service
data = {**call.data} data = {**call.data}
device_ids = set(data.get("device_id", []))
data.pop("device_id", None) browsers = data.pop("browser_id", [])
area_ids = set(data.get("area_id", [])) if isinstance(browsers, str):
data.pop("area_id", None) browsers = [browsers]
targets = data.get("target", []) browsers = set(browsers)
if isinstance(targets, str): device_ids = set(data.pop("device_id", []))
targets = [targets] area_ids = set(data.pop("area_id", []))
targets = set(targets)
data.pop("target", None)
dr = device_registry.async_get(hass) dr = device_registry.async_get(hass)
@ -53,53 +48,16 @@ async def async_setup_services(hass):
browserID = list(dev.identifiers)[0][1] browserID = list(dev.identifiers)[0][1]
if browserID is None: if browserID is None:
continue continue
targets.add(browserID) browsers.add(browserID)
for area in area_ids: for area in area_ids:
for dev in device_registry.async_entries_for_area(dr, area): for dev in device_registry.async_entries_for_area(dr, area):
browserID = list(dev.identifiers)[0][1] browserID = list(dev.identifiers)[0][1]
if browserID is None: if browserID is None:
continue continue
targets.add(browserID) browsers.add(browserID)
_LOGGER.error(service) call_service(service, browsers, data)
_LOGGER.error(targets)
_LOGGER.error(data)
call_service(service, targets, data)
hass.services.async_register(DOMAIN, "test", handle_service) hass.services.async_register(DOMAIN, "test", handle_service)
hass.services.async_register(DOMAIN, "popup", 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)

View File

@ -10,7 +10,7 @@ _LOGGER = logging.getLogger(__name__)
@attr.s @attr.s
class DeviceStoreData: class BrowserStoreData:
last_seen = attr.ib(type=int, default=0) last_seen = attr.ib(type=int, default=0)
enabled = attr.ib(type=bool, default=False) enabled = attr.ib(type=bool, default=False)
camera = attr.ib(type=bool, default=False) camera = attr.ib(type=bool, default=False)
@ -26,17 +26,19 @@ class DeviceStoreData:
@attr.s @attr.s
class ConfigStoreData: 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") version = attr.ib(type=str, default="2.0")
@classmethod @classmethod
def from_dict(cls, data={}): 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( return cls(
**( **(
data data
| { | {
"devices": devices, "browsers": browsers,
} }
) )
) )
@ -83,15 +85,15 @@ class BrowserModStore:
return remove_listener return remove_listener
def get_device(self, deviceID): def get_browser(self, browserID):
return self.data.devices.get(deviceID, DeviceStoreData()) return self.data.browsers.get(browserID, BrowserStoreData())
async def set_device(self, deviceID, **data): async def set_browser(self, browserID, **data):
device = self.data.devices.get(deviceID, DeviceStoreData()) browser = self.data.browsers.get(browserID, BrowserStoreData())
device.__dict__.update(data) browser.__dict__.update(data)
self.data.devices[deviceID] = device self.data.browsers[browserID] = browser
await self.updated() await self.updated()
async def delete_device(self, deviceID): async def delete_browser(self, browserID):
del self.data.devices[deviceID] del self.data.browsers[browserID]
await self.updated() await self.updated()

View File

@ -14,32 +14,32 @@ loadDevTools().then(() => {
if (!window.browser_mod?.connected) return; if (!window.browser_mod?.connected) return;
window.browser_mod.registered = !window.browser_mod.registered; window.browser_mod.registered = !window.browser_mod.registered;
} }
changeDeviceID(ev) { changeBrowserID(ev) {
window.browser_mod.deviceID = ev.target.value; window.browser_mod.browserID = ev.target.value;
} }
toggleCameraEnabled() { toggleCameraEnabled() {
window.browser_mod.cameraEnabled = !window.browser_mod.cameraEnabled; window.browser_mod.cameraEnabled = !window.browser_mod.cameraEnabled;
} }
unregister_device(ev) { unregister_browser(ev) {
const deviceID = ev.currentTarget.deviceID; const browserID = ev.currentTarget.browserID;
const unregisterCallback = () => { const unregisterCallback = () => {
console.log(deviceID, window.browser_mod.deviceID); console.log(browserID, window.browser_mod.browserID);
if (deviceID === window.browser_mod.deviceID) { if (browserID === window.browser_mod.browserID) {
console.log("Unregister self"); console.log("Unregister self");
window.browser_mod.registered = false; window.browser_mod.registered = false;
} else { } else {
window.browser_mod.connection.sendMessage({ window.browser_mod.connection.sendMessage({
type: "browser_mod/unregister", type: "browser_mod/unregister",
deviceID, browserID,
}); });
} }
}; };
window.browser_mod.showPopup( window.browser_mod.showPopup(
"Unregister device", "Unregister browser",
`Are you sure you want to unregister device ${deviceID}?`, `Are you sure you want to unregister browser ${browserID}?`,
{ {
primary_action: "Yes", primary_action: "Yes",
secondary_action: "No", secondary_action: "No",
@ -109,21 +109,21 @@ loadDevTools().then(() => {
</ha-settings-row> </ha-settings-row>
<ha-settings-row> <ha-settings-row>
<span slot="heading">DeviceID</span> <span slot="heading">BrowserID</span>
<span slot="description" <span slot="description"
>A unique identifier for this browser-device >A unique identifier for this browser-device
combination.</span combination.</span
> >
<ha-textfield <ha-textfield
.value=${window.browser_mod?.deviceID} .value=${window.browser_mod?.browserID}
@change=${this.changeDeviceID} @change=${this.changeBrowserID}
></ha-textfield> ></ha-textfield>
</ha-settings-row> </ha-settings-row>
<ha-settings-row> <ha-settings-row>
<span slot="heading">Enable camera</span> <span slot="heading">Enable camera</span>
<span slot="description" <span slot="description"
>Get camera input from this device (hardware >Get camera input from this browser (hardware
dependent)</span dependent)</span
> >
<ha-switch <ha-switch
@ -134,21 +134,21 @@ loadDevTools().then(() => {
</div> </div>
</ha-card> </ha-card>
<ha-card header="Registered devices" outlined> <ha-card header="Registered browsers" outlined>
<div class="card-content"> <div class="card-content">
${Object.keys(window.browser_mod.devices).map( ${Object.keys(window.browser_mod.browsers).map(
(d) => html` <ha-settings-row> (d) => html` <ha-settings-row>
<span slot="heading"> ${d} </span> <span slot="heading"> ${d} </span>
<span slot="description"> <span slot="description">
Last connected: Last connected:
<ha-relative-time <ha-relative-time
.hass=${this.hass} .hass=${this.hass}
.datetime=${window.browser_mod.devices[d].last_seen} .datetime=${window.browser_mod.browsers[d].last_seen}
></ha-relative-time> ></ha-relative-time>
</span> </span>
<ha-icon-button <ha-icon-button
.deviceID=${d} .browserID=${d}
@click=${this.unregister_device} @click=${this.unregister_browser}
> >
<ha-icon .icon=${"mdi:delete"}></ha-icon> <ha-icon .icon=${"mdi:delete"}></ha-icon>
</ha-icon-button> </ha-icon-button>

View File

@ -47,7 +47,7 @@ class BrowserPlayer extends LitElement {
composed: true, composed: true,
cancelable: false, cancelable: false,
detail: { detail: {
entityId: window.browser_mod.deviceEntities?.player, entityId: window.browser_mod.browserEntities?.player,
}, },
}) })
); );
@ -98,7 +98,7 @@ class BrowserPlayer extends LitElement {
</ha-icon-button> </ha-icon-button>
</div> </div>
<div class="device-id">${window.browser_mod.deviceID}</div> <div class="browser-id">${window.browser_mod.browserID}</div>
</ha-card> </ha-card>
`; `;
} }
@ -116,7 +116,7 @@ class BrowserPlayer extends LitElement {
width: 24px; width: 24px;
padding: 8px; padding: 8px;
} }
.device-id { .browser-id {
opacity: 0.7; opacity: 0.7;
font-size: xx-small; font-size: xx-small;
margin-top: -10px; margin-top: -10px;

View File

@ -1,6 +1,6 @@
import { hass, provideHass } from "../helpers"; 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) => { export const ConnectionMixin = (SuperClass) => {
class BrowserModConnection extends SuperClass { class BrowserModConnection extends SuperClass {
@ -12,7 +12,7 @@ export const ConnectionMixin = (SuperClass) => {
public connectionPromise = new Promise((resolve) => { public connectionPromise = new Promise((resolve) => {
this._connectionResolve = resolve; this._connectionResolve = resolve;
}); });
public deviceEntities = {}; public browserEntities = {};
LOG(...args) { LOG(...args) {
const dt = new Date(); const dt = new Date();
@ -27,8 +27,8 @@ export const ConnectionMixin = (SuperClass) => {
if (msg.command) { if (msg.command) {
this.LOG("Command:", msg); this.LOG("Command:", msg);
this.fireEvent(`command-${msg.command}`, msg); this.fireEvent(`command-${msg.command}`, msg);
} else if (msg.deviceEntities) { } else if (msg.browserEntities) {
this.deviceEntities = msg.deviceEntities; this.browserEntities = msg.browserEntities;
} else if (msg.result) { } else if (msg.result) {
this.update_config(msg.result); this.update_config(msg.result);
} }
@ -39,7 +39,7 @@ export const ConnectionMixin = (SuperClass) => {
this.LOG("Receive:", cfg); this.LOG("Receive:", cfg);
let update = false; let update = false;
if (!this.registered && cfg.devices?.[this.deviceID]) { if (!this.registered && cfg.browsers?.[this.browserID]) {
update = true; update = true;
} }
this._data = cfg; this._data = cfg;
@ -61,7 +61,7 @@ export const ConnectionMixin = (SuperClass) => {
// Subscribe to configuration updates // Subscribe to configuration updates
conn.subscribeMessage((msg) => this.incoming_message(msg), { conn.subscribeMessage((msg) => this.incoming_message(msg), {
type: "browser_mod/connect", type: "browser_mod/connect",
deviceID: this.deviceID, browserID: this.browserID,
}); });
// Keep connection status up to date // Keep connection status up to date
@ -82,12 +82,12 @@ export const ConnectionMixin = (SuperClass) => {
return this._data?.config ?? {}; return this._data?.config ?? {};
} }
get devices() { get browsers() {
return this._data?.devices ?? []; return this._data?.browsers ?? [];
} }
get registered() { get registered() {
return this.devices?.[this.deviceID] !== undefined; return this.browsers?.[this.browserID] !== undefined;
} }
set registered(reg) { set registered(reg) {
@ -96,13 +96,13 @@ export const ConnectionMixin = (SuperClass) => {
if (this.registered) return; if (this.registered) return;
await this.connection.sendMessage({ await this.connection.sendMessage({
type: "browser_mod/register", type: "browser_mod/register",
deviceID: this.deviceID, browserID: this.browserID,
}); });
} else { } else {
if (!this.registered) return; if (!this.registered) return;
await this.connection.sendMessage({ await this.connection.sendMessage({
type: "browser_mod/unregister", type: "browser_mod/unregister",
deviceID: this.deviceID, browserID: this.browserID,
}); });
} }
})(); })();
@ -111,9 +111,9 @@ export const ConnectionMixin = (SuperClass) => {
private async _reregister(newData = {}) { private async _reregister(newData = {}) {
await this.connection.sendMessage({ await this.connection.sendMessage({
type: "browser_mod/reregister", type: "browser_mod/reregister",
deviceID: this.deviceID, browserID: this.browserID,
data: { data: {
...this.devices[this.deviceID], ...this.browsers[this.browserID],
...newData, ...newData,
}, },
}); });
@ -121,7 +121,7 @@ export const ConnectionMixin = (SuperClass) => {
get meta() { get meta() {
if (!this.registered) return null; if (!this.registered) return null;
return this.devices[this.deviceID].meta; return this.browsers[this.browserID].meta;
} }
set meta(value) { set meta(value) {
this._reregister({ meta: value }); this._reregister({ meta: value });
@ -129,7 +129,7 @@ export const ConnectionMixin = (SuperClass) => {
get cameraEnabled() { get cameraEnabled() {
if (!this.registered) return null; if (!this.registered) return null;
return this.devices[this.deviceID].camera; return this.browsers[this.browserID].camera;
} }
set cameraEnabled(value) { set cameraEnabled(value) {
this._reregister({ camera: value }); this._reregister({ camera: value });
@ -143,18 +143,18 @@ export const ConnectionMixin = (SuperClass) => {
this.connection.sendMessage({ this.connection.sendMessage({
type: "browser_mod/update", type: "browser_mod/update",
deviceID: this.deviceID, browserID: this.browserID,
data, data,
}); });
} }
get deviceID() { get browserID() {
if (localStorage[ID_STORAGE_KEY]) return localStorage[ID_STORAGE_KEY]; if (localStorage[ID_STORAGE_KEY]) return localStorage[ID_STORAGE_KEY];
this.deviceID = ""; this.browserID = "";
return this.deviceID; return this.browserID;
} }
set deviceID(id) { set browserID(id) {
function _createDeviceID() { function _createBrowserID() {
const s4 = () => { const s4 = () => {
return Math.floor((1 + Math.random()) * 100000) return Math.floor((1 + Math.random()) * 100000)
.toString(16) .toString(16)
@ -163,29 +163,27 @@ export const ConnectionMixin = (SuperClass) => {
return window.fully?.getDeviceId() ?? `${s4()}${s4()}-${s4()}${s4()}`; return window.fully?.getDeviceId() ?? `${s4()}${s4()}-${s4()}${s4()}`;
} }
if (id === "") id = _createDeviceID(); if (id === "") id = _createBrowserID();
const oldID = localStorage[ID_STORAGE_KEY]; const oldID = localStorage[ID_STORAGE_KEY];
localStorage[ID_STORAGE_KEY] = id; localStorage[ID_STORAGE_KEY] = id;
this.fireEvent("browser-mod-config-update"); this.fireEvent("browser-mod-config-update");
if ( if (
this.devices?.[oldID] !== undefined && this.browsers?.[oldID] !== undefined &&
this.devices?.[this.deviceID] === undefined this.browsers?.[this.browserID] === undefined
) { ) {
(async () => { (async () => {
await this.connection.sendMessage({ await this.connection.sendMessage({
type: "browser_mod/reregister", type: "browser_mod/reregister",
deviceID: oldID, browserID: oldID,
data: { data: {
...this.devices[oldID], ...this.browsers[oldID],
deviceID: this.deviceID, browserID: this.browserID,
}, },
}); });
})(); })();
} }
// TODO: Send update to backend to update device
} }
} }

View File

@ -16,8 +16,8 @@ import pjson from "../../package.json";
/* /*
TODO: TODO:
- Fix nomenclature - Fix nomenclature
- Command -> Service x Command -> Service
- Device -> Browser x Device -> Browser
- Popups - Popups
X Basic popups X Basic popups
- Card-mod integration - Card-mod integration
@ -81,107 +81,11 @@ export class BrowserMod extends ServicesMixin(
console.info( console.info(
`%cBROWSER_MOD ${pjson.version} IS INSTALLED `%cBROWSER_MOD ${pjson.version} IS INSTALLED
%cDeviceID: ${this.deviceID}`, %cBrowserID: ${this.browserID}`,
"color: green; font-weight: bold", "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(); if (!window.browser_mod) window.browser_mod = new BrowserMod();
// })();