214 lines
7.2 KiB
Python
214 lines
7.2 KiB
Python
import logging
|
|
|
|
from homeassistant.components.websocket_api import event_message
|
|
from homeassistant.helpers import device_registry, entity_registry
|
|
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator
|
|
from homeassistant.core import callback
|
|
|
|
from .const import DATA_BROWSERS, DOMAIN, DATA_ADDERS
|
|
from .sensor import BrowserSensor
|
|
from .light import BrowserModLight
|
|
from .binary_sensor import BrowserBinarySensor, ActivityBinarySensor
|
|
from .media_player import BrowserModPlayer
|
|
from .camera import BrowserModCamera
|
|
|
|
_LOGGER = logging.getLogger(__name__)
|
|
|
|
|
|
class Coordinator(DataUpdateCoordinator):
|
|
def __init__(self, hass, browserID):
|
|
super().__init__(
|
|
hass,
|
|
_LOGGER,
|
|
name="Browser Mod Coordinator",
|
|
)
|
|
self.browserID = browserID
|
|
|
|
|
|
class BrowserModBrowser:
|
|
"""A Browser_mod browser.
|
|
Handles the Home Assistant device corresponding to a registered Browser.
|
|
Creates and updates entities based on available data.
|
|
"""
|
|
|
|
def __init__(self, hass, browserID):
|
|
self.browserID = browserID
|
|
self.coordinator = Coordinator(hass, browserID)
|
|
self.entities = {}
|
|
self.data = {}
|
|
self.settings = {}
|
|
self._connections = []
|
|
|
|
self.update_entities(hass)
|
|
|
|
def update(self, hass, newData):
|
|
"""Update state of all related entities."""
|
|
self.data.update(newData)
|
|
self.update_entities(hass)
|
|
self.coordinator.async_set_updated_data(self.data)
|
|
|
|
def update_settings(self, hass, settings):
|
|
"""Update Browser settings and entities if needed."""
|
|
self.settings = settings
|
|
self.update_entities(hass)
|
|
|
|
def update_entities(self, hass):
|
|
"""Create all entities associated with the browser."""
|
|
|
|
coordinator = self.coordinator
|
|
browserID = self.browserID
|
|
|
|
def _assert_browser_sensor(type, name, *properties, **kwarg):
|
|
"""Create a browser state sensor if it does not already exist"""
|
|
if name in self.entities:
|
|
return
|
|
adder = hass.data[DOMAIN][DATA_ADDERS][type]
|
|
cls = {"sensor": BrowserSensor, "binary_sensor": BrowserBinarySensor}[type]
|
|
new = cls(coordinator, browserID, name, *properties, **kwarg)
|
|
adder([new])
|
|
self.entities[name] = new
|
|
|
|
_assert_browser_sensor("sensor", "path", "Browser path", icon="mdi:web")
|
|
_assert_browser_sensor("sensor", "visibility", "Browser visibility")
|
|
_assert_browser_sensor(
|
|
"sensor", "userAgent", "Browser userAgent", icon="mdi:account-details"
|
|
)
|
|
_assert_browser_sensor(
|
|
"sensor", "currentUser", "Browser user", icon="mdi:account"
|
|
)
|
|
_assert_browser_sensor(
|
|
"sensor", "width", "Browser width", "px", icon="mdi:arrow-left-right"
|
|
)
|
|
_assert_browser_sensor(
|
|
"sensor", "height", "Browser height", "px", icon="mdi:arrow-up-down"
|
|
)
|
|
# Don't create battery sensor unless battery level is reported
|
|
if self.data.get("browser", {}).get("battery_level", None) is not None:
|
|
_assert_browser_sensor(
|
|
"sensor", "battery_level", "Browser battery", "%", "battery"
|
|
)
|
|
|
|
_assert_browser_sensor(
|
|
"binary_sensor",
|
|
"darkMode",
|
|
"Browser dark mode",
|
|
icon="mdi:theme-light-dark",
|
|
)
|
|
_assert_browser_sensor(
|
|
"binary_sensor", "fullyKiosk", "Browser FullyKiosk", icon="mdi:alpha-f"
|
|
)
|
|
# Don't create a charging sensor unless charging state is reported
|
|
if self.data.get("browser", {}).get("charging", None) is not None:
|
|
_assert_browser_sensor(
|
|
"binary_sensor", "charging", "Browser charging", icon="mdi:power-plug"
|
|
)
|
|
|
|
if "activity" not in self.entities:
|
|
adder = hass.data[DOMAIN][DATA_ADDERS]["binary_sensor"]
|
|
new = ActivityBinarySensor(coordinator, browserID)
|
|
adder([new])
|
|
self.entities["activity"] = new
|
|
|
|
if "screen" not in self.entities:
|
|
adder = hass.data[DOMAIN][DATA_ADDERS]["light"]
|
|
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, 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, browserID)
|
|
adder([new])
|
|
self.entities["camera"] = new
|
|
if "camera" in self.entities and not self.settings.get("camera"):
|
|
er = entity_registry.async_get(hass)
|
|
er.async_remove(self.entities["camera"].entity_id)
|
|
del self.entities["camera"]
|
|
|
|
hass.create_task(
|
|
self.send(
|
|
None, browserEntities={k: v.entity_id for k, v in self.entities.items()}
|
|
)
|
|
)
|
|
|
|
@callback
|
|
async def send(self, command, **kwargs):
|
|
"""Send a command to this browser."""
|
|
if self.connection is None:
|
|
return
|
|
|
|
for (connection, cid) in self.connection:
|
|
connection.send_message(
|
|
event_message(
|
|
cid,
|
|
{
|
|
"command": command,
|
|
**kwargs,
|
|
},
|
|
)
|
|
)
|
|
|
|
def delete(self, hass):
|
|
"""Delete the device and associated entities."""
|
|
dr = device_registry.async_get(hass)
|
|
er = entity_registry.async_get(hass)
|
|
|
|
for e in self.entities.values():
|
|
er.async_remove(e.entity_id)
|
|
|
|
self.entities = {}
|
|
|
|
device = dr.async_get_device({(DOMAIN, self.browserID)})
|
|
dr.async_remove_device(device.id)
|
|
|
|
@property
|
|
def connection(self):
|
|
"""The current websocket connections for this Browser."""
|
|
return self._connections
|
|
|
|
def open_connection(self, connection, cid):
|
|
"""Add a websocket connection."""
|
|
self._connections.append((connection, cid))
|
|
|
|
def close_connection(self, connection):
|
|
"""Close a websocket connection."""
|
|
self._connections = list(
|
|
filter(lambda v: v[0] != connection, self._connections)
|
|
)
|
|
|
|
|
|
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
|
|
|
|
browsers[browserID] = BrowserModBrowser(hass, browserID)
|
|
return browsers[browserID]
|
|
|
|
|
|
def deleteBrowser(hass, browserID):
|
|
"""Delete a browser by BrowserID."""
|
|
browsers = hass.data[DOMAIN][DATA_BROWSERS]
|
|
if browserID in browsers:
|
|
browsers[browserID].delete(hass)
|
|
del browsers[browserID]
|
|
|
|
|
|
def getBrowserByConnection(hass, connection):
|
|
"""Get the browser that has a given connection open."""
|
|
browsers = hass.data[DOMAIN][DATA_BROWSERS]
|
|
|
|
for k, v in browsers.items():
|
|
if any([c[0] == connection for c in v.connection]):
|
|
return v
|