Huge restructure in progress
This commit is contained in:
parent
13f17af309
commit
fdc509f402
@ -21,13 +21,18 @@ async def async_setup(hass, config):
|
|||||||
hass.data[DOMAIN] = {
|
hass.data[DOMAIN] = {
|
||||||
DATA_DEVICES: {},
|
DATA_DEVICES: {},
|
||||||
DATA_ALIASES: aliases,
|
DATA_ALIASES: aliases,
|
||||||
DATA_ADDERS: [],
|
DATA_ADDERS: {},
|
||||||
}
|
}
|
||||||
|
|
||||||
await hass.helpers.discovery.async_load_platform("media_player", DOMAIN, {}, config)
|
await hass.helpers.discovery.async_load_platform("media_player", DOMAIN, {}, config)
|
||||||
|
await hass.helpers.discovery.async_load_platform("sensor", DOMAIN, {}, config)
|
||||||
|
await hass.helpers.discovery.async_load_platform("light", DOMAIN, {}, config)
|
||||||
|
|
||||||
setup_connection(hass)
|
await setup_connection(hass, config)
|
||||||
|
|
||||||
setup_service(hass)
|
setup_service(hass)
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
File diff suppressed because one or more lines are too long
@ -4,78 +4,100 @@ import voluptuous as vol
|
|||||||
from homeassistant.components.websocket_api import websocket_command, result_message, event_message, async_register_command
|
from homeassistant.components.websocket_api import websocket_command, result_message, event_message, async_register_command
|
||||||
from homeassistant.helpers.entity import Entity, async_generate_entity_id
|
from homeassistant.helpers.entity import Entity, async_generate_entity_id
|
||||||
|
|
||||||
from .const import DOMAIN, DATA_DEVICES, DATA_ADDERS, WS_CONNECT, WS_UPDATE
|
from .const import DOMAIN, WS_CONNECT, WS_UPDATE
|
||||||
|
from .helpers import get_devices, create_entity
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
async def setup_connection(hass, config):
|
||||||
|
_LOGGER.error("--------------------")
|
||||||
|
_LOGGER.error("Setting up BM connection")
|
||||||
|
|
||||||
|
@websocket_command({
|
||||||
|
vol.Required("type"): WS_CONNECT,
|
||||||
|
vol.Required("deviceID"): str,
|
||||||
|
})
|
||||||
|
def handle_connect(hass, connection, msg):
|
||||||
|
_LOGGER.error("--------------------")
|
||||||
|
_LOGGER.error("CONNECTING BM")
|
||||||
|
deviceID = msg["deviceID"]
|
||||||
|
|
||||||
|
device = get_devices(hass).get(deviceID, BrowserModConnection(hass, deviceID))
|
||||||
|
device.connect(connection, msg["id"])
|
||||||
|
get_devices(hass)[deviceID] = device
|
||||||
|
|
||||||
|
_LOGGER.error("DONE")
|
||||||
|
connection.send_message(result_message(msg["id"]))
|
||||||
|
|
||||||
|
@websocket_command({
|
||||||
|
vol.Required("type"): WS_UPDATE,
|
||||||
|
vol.Required("deviceID"): str,
|
||||||
|
vol.Optional("data"): dict,
|
||||||
|
})
|
||||||
|
def handle_update( hass, connection, msg):
|
||||||
|
_LOGGER.error("--------------------")
|
||||||
|
_LOGGER.error("UPDATING BM")
|
||||||
|
_LOGGER.error(msg)
|
||||||
|
devices = get_devices(hass)
|
||||||
|
deviceID = msg["deviceID"]
|
||||||
|
if deviceID in devices:
|
||||||
|
devices[deviceID].update(msg.get("data", None))
|
||||||
|
|
||||||
def setup_connection(hass):
|
|
||||||
async_register_command(hass, handle_connect)
|
async_register_command(hass, handle_connect)
|
||||||
async_register_command(hass, handle_update)
|
async_register_command(hass, handle_update)
|
||||||
|
|
||||||
|
|
||||||
@websocket_command({
|
class BrowserModConnection:
|
||||||
vol.Required("type"): WS_CONNECT,
|
def __init__(self, hass, deviceID):
|
||||||
vol.Required("deviceID"): str,
|
self.hass = hass
|
||||||
})
|
self.deviceID = deviceID
|
||||||
def handle_connect(hass, connection, msg):
|
self.connection = []
|
||||||
|
|
||||||
devices = hass.data[DOMAIN][DATA_DEVICES]
|
self.media_player = None
|
||||||
deviceID = msg["deviceID"]
|
self.screen = None
|
||||||
if deviceID in devices:
|
self.sensor = None
|
||||||
devices[deviceID].ws_connect(connection, msg["id"])
|
|
||||||
else:
|
|
||||||
adder = hass.data[DOMAIN][DATA_ADDERS][0]
|
|
||||||
devices[deviceID] = adder(hass, deviceID, connection, msg["id"])
|
|
||||||
connection.send_message(result_message(msg["id"]))
|
|
||||||
|
|
||||||
|
def connect(self, connection, cid):
|
||||||
|
self.connection.append((connection, cid))
|
||||||
|
_LOGGER.error("********************")
|
||||||
|
_LOGGER.error("Connected %s", self.deviceID)
|
||||||
|
self.send("update")
|
||||||
|
|
||||||
@websocket_command({
|
def disconnect():
|
||||||
vol.Required("type"): WS_UPDATE,
|
self.connection.remove((connection, cid))
|
||||||
vol.Required("deviceID"): str,
|
|
||||||
vol.Optional("data"): dict,
|
|
||||||
})
|
|
||||||
def handle_update(hass, connection, msg):
|
|
||||||
devices = hass.data[DOMAIN][DATA_DEVICES]
|
|
||||||
deviceID = msg["deviceID"]
|
|
||||||
if deviceID in devices:
|
|
||||||
devices[deviceID].ws_update(msg.get("data", None))
|
|
||||||
|
|
||||||
|
connection.subscriptions[cid] = disconnect
|
||||||
|
|
||||||
class BrowserModEntity(Entity):
|
def send(self, command, **kwargs):
|
||||||
def __init__(self, hass, deviceID, alias=None):
|
if self.connection:
|
||||||
self._deviceID = deviceID
|
connection, cid = self.connection[-1]
|
||||||
self._alias = alias
|
connection.send_message(event_message(cid, {
|
||||||
self._ws_data = {}
|
|
||||||
self._ws_connection = None
|
|
||||||
self.entity_id = async_generate_entity_id("media_player.{}", alias or deviceID, hass=hass)
|
|
||||||
|
|
||||||
def ws_send(self, command, **kwargs):
|
|
||||||
if self._ws_connection:
|
|
||||||
self._ws_connection.send_message(event_message(self._ws_cid, {
|
|
||||||
"command": command,
|
"command": command,
|
||||||
**kwargs,
|
**kwargs,
|
||||||
}))
|
}))
|
||||||
|
|
||||||
def ws_connect(self, connection, cid):
|
def update(self, data):
|
||||||
self._ws_cid = cid
|
_LOGGER.error("********************")
|
||||||
self._ws_connection = connection
|
_LOGGER.error("Got update %s for %s", data, self.deviceID)
|
||||||
self.ws_send("update", entity_id=self.entity_id)
|
if data.get('player'):
|
||||||
connection.subscriptions[cid] = self.ws_disconnect
|
self.media_player = self.media_player or create_entity(
|
||||||
if self.hass:
|
self.hass,
|
||||||
self.schedule_update_ha_state()
|
'media_player',
|
||||||
|
self.deviceID,
|
||||||
|
self)
|
||||||
|
self.media_player.data = data.get('player')
|
||||||
|
if data.get('browser'):
|
||||||
|
self.sensor = self.sensor or create_entity(
|
||||||
|
self.hass,
|
||||||
|
'sensor',
|
||||||
|
self.deviceID,
|
||||||
|
self)
|
||||||
|
self.sensor.data = data.get('browser')
|
||||||
|
if data.get('screen'):
|
||||||
|
self.screen = self.screen or create_entity(
|
||||||
|
self.hass,
|
||||||
|
'light',
|
||||||
|
self.deviceID,
|
||||||
|
self)
|
||||||
|
self.screen.data = data.get('screen')
|
||||||
|
|
||||||
def ws_disconnect(self):
|
|
||||||
self._ws_cid = None
|
|
||||||
self._ws_connection = None
|
|
||||||
if self.hass:
|
|
||||||
self.schedule_update_ha_state()
|
|
||||||
|
|
||||||
def ws_update(self, data):
|
|
||||||
self._ws_data = data
|
|
||||||
if self.hass:
|
|
||||||
self.schedule_update_ha_state()
|
|
||||||
|
|
||||||
@property
|
|
||||||
def device_id(self):
|
|
||||||
return self._deviceID
|
|
||||||
|
58
custom_components/browser_mod/helpers.py
Normal file
58
custom_components/browser_mod/helpers.py
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
import logging
|
||||||
|
|
||||||
|
from homeassistant.helpers.entity import Entity, async_generate_entity_id
|
||||||
|
|
||||||
|
from .const import DOMAIN, DATA_DEVICES, DATA_ALIASES, DATA_ADDERS, CONFIG_DEVICES
|
||||||
|
|
||||||
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
def get_devices(hass):
|
||||||
|
return hass.data[DOMAIN][DATA_DEVICES]
|
||||||
|
|
||||||
|
def get_alias(hass, deviceID):
|
||||||
|
for k,v in hass.data[DOMAIN][DATA_ALIASES].items():
|
||||||
|
if v == deviceID:
|
||||||
|
return k
|
||||||
|
return None
|
||||||
|
|
||||||
|
def create_entity(hass, platform, deviceID, connection):
|
||||||
|
_LOGGER.error("********************")
|
||||||
|
_LOGGER.error("Creating %s for %s", platform, deviceID)
|
||||||
|
adder = hass.data[DOMAIN][DATA_ADDERS][platform]
|
||||||
|
entity = adder(hass, deviceID, connection, get_alias(hass, deviceID))
|
||||||
|
return entity
|
||||||
|
|
||||||
|
def setup_platform(hass, config, async_add_devices, platform, cls):
|
||||||
|
def adder(hass, deviceID, connection, alias=None):
|
||||||
|
entity = cls(hass, connection, deviceID, alias)
|
||||||
|
async_add_devices([entity])
|
||||||
|
return entity
|
||||||
|
hass.data[DOMAIN][DATA_ADDERS][platform] = adder
|
||||||
|
return True
|
||||||
|
|
||||||
|
class BrowserModEntity(Entity):
|
||||||
|
|
||||||
|
def __init__(self, hass, connection, deviceID, alias=None):
|
||||||
|
self.hass = hass
|
||||||
|
self.connection = connection
|
||||||
|
self.deviceID = deviceID
|
||||||
|
self._data = {}
|
||||||
|
self.entity_id = async_generate_entity_id(self.domain+".{}", alias or deviceID, hass=hass)
|
||||||
|
|
||||||
|
def updated(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@property
|
||||||
|
def data(self):
|
||||||
|
return self._data
|
||||||
|
@data.setter
|
||||||
|
def data(self, data):
|
||||||
|
self._data = data
|
||||||
|
self.updated()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def device_id(self):
|
||||||
|
return self.deviceID
|
||||||
|
|
||||||
|
def send(self, command, **kwargs):
|
||||||
|
self.connection.send(command, **kwargs)
|
52
custom_components/browser_mod/light.py
Normal file
52
custom_components/browser_mod/light.py
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
import logging
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
from homeassistant.const import STATE_UNAVAILABLE, STATE_ON, STATE_OFF
|
||||||
|
from homeassistant.components.light import Light, SUPPORT_BRIGHTNESS
|
||||||
|
|
||||||
|
from .helpers import setup_platform, BrowserModEntity
|
||||||
|
|
||||||
|
PLATFORM = 'light'
|
||||||
|
|
||||||
|
async def async_setup_platform(hass, config, async_add_devices, discovery_info=None):
|
||||||
|
return setup_platform(hass, config, async_add_devices, PLATFORM, BrowserModLight)
|
||||||
|
|
||||||
|
class BrowserModLight(Light, BrowserModEntity):
|
||||||
|
domain = PLATFORM
|
||||||
|
|
||||||
|
def __init__(self, hass, connection, deviceID, alias=None):
|
||||||
|
super().__init__(hass, connection, deviceID, alias)
|
||||||
|
|
||||||
|
def updated(self):
|
||||||
|
self.last_seen = datetime.now()
|
||||||
|
self.schedule_update_ha_state()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def state(self):
|
||||||
|
if not self.connection.connection:
|
||||||
|
return STATE_UNAVAILABLE
|
||||||
|
if self.data.get('blackout', False):
|
||||||
|
return STATE_OFF
|
||||||
|
return STATE_ON
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_on(self):
|
||||||
|
return not self.data.get('blackout', False)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def device_state_attributes(self):
|
||||||
|
return {
|
||||||
|
"type": "browser_mod",
|
||||||
|
}
|
||||||
|
|
||||||
|
@property
|
||||||
|
def supported_features(self):
|
||||||
|
if self.data.get('brightness', False):
|
||||||
|
return SUPPORT_BRIGHTNESS
|
||||||
|
return 0
|
||||||
|
|
||||||
|
def turn_on(self, **kwargs):
|
||||||
|
self.connection.send("no-blackout", **kwargs)
|
||||||
|
|
||||||
|
def turn_off(self, **kwargs):
|
||||||
|
self.connection.send("blackout")
|
@ -13,48 +13,36 @@ from homeassistant.const import (
|
|||||||
STATE_UNKNOWN,
|
STATE_UNKNOWN,
|
||||||
)
|
)
|
||||||
|
|
||||||
from .const import DOMAIN, DATA_DEVICES, DATA_ADDERS, DATA_ALIASES
|
from .helpers import setup_platform, BrowserModEntity
|
||||||
from .connection import BrowserModEntity
|
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
PLATFORM = 'media_player'
|
||||||
|
|
||||||
async def async_setup_platform(hass, config, async_add_devices, discovery_info=None):
|
async def async_setup_platform(hass, config, async_add_devices, discovery_info=None):
|
||||||
def adder(hass, deviceID, connection, cid):
|
return setup_platform(hass, config, async_add_devices, PLATFORM, BrowserModPlayer)
|
||||||
player = BrowserModPlayer(hass, deviceID)
|
|
||||||
if connection:
|
|
||||||
player.ws_connect(connection, cid)
|
|
||||||
async_add_devices([player])
|
|
||||||
return player
|
|
||||||
hass.data[DOMAIN][DATA_ADDERS].append(adder)
|
|
||||||
|
|
||||||
for k,v in hass.data[DOMAIN][DATA_ALIASES].items():
|
|
||||||
devices = hass.data[DOMAIN][DATA_DEVICES]
|
|
||||||
devices[v] = BrowserModPlayer(hass, v, k)
|
|
||||||
async_add_devices([devices[v]])
|
|
||||||
|
|
||||||
|
|
||||||
class BrowserModPlayer(MediaPlayerDevice, BrowserModEntity):
|
class BrowserModPlayer(MediaPlayerDevice, BrowserModEntity):
|
||||||
|
domain = PLATFORM
|
||||||
|
|
||||||
def __init__(self, hass, deviceID, alias=None):
|
def __init__(self, hass, connection, deviceID, alias=None):
|
||||||
super().__init__(hass, deviceID, alias)
|
super().__init__(hass, connection, deviceID, alias)
|
||||||
|
|
||||||
|
def updated(self):
|
||||||
|
self.schedule_update_ha_state()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def device_state_attributes(self):
|
def device_state_attributes(self):
|
||||||
return {
|
return {
|
||||||
"type": "browser",
|
"type": "browser_mod",
|
||||||
**self._ws_data.get("browser", {}),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@property
|
|
||||||
def _player_data(self):
|
|
||||||
return self._ws_data.get("player", {})
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def state(self):
|
def state(self):
|
||||||
if not self._ws_connection:
|
if not self.connection.connection:
|
||||||
return STATE_UNAVAILABLE
|
return STATE_UNAVAILABLE
|
||||||
state = self._player_data.get("state", "unknown")
|
state = self.data.get("state", "unknown")
|
||||||
return {
|
return {
|
||||||
"playing": STATE_PLAYING,
|
"playing": STATE_PLAYING,
|
||||||
"paused": STATE_PAUSED,
|
"paused": STATE_PAUSED,
|
||||||
@ -69,24 +57,24 @@ class BrowserModPlayer(MediaPlayerDevice, BrowserModEntity):
|
|||||||
)
|
)
|
||||||
@property
|
@property
|
||||||
def volume_level(self):
|
def volume_level(self):
|
||||||
return self._player_data.get("volume", 0)
|
return self.data.get("volume", 0)
|
||||||
@property
|
@property
|
||||||
def is_volume_muted(self):
|
def is_volume_muted(self):
|
||||||
return self._player_data.get("muted", False)
|
return self.data.get("muted", False)
|
||||||
@property
|
@property
|
||||||
def media_content_id(self):
|
def media_content_id(self):
|
||||||
return self._player_data.get("src", "")
|
return self.data.get("src", "")
|
||||||
|
|
||||||
def set_volume_level(self, volume):
|
def set_volume_level(self, volume):
|
||||||
self.ws_send("set_volume", volume_level=volume)
|
self.connection.send("set_volume", volume_level=volume)
|
||||||
def mute_volume(self, mute):
|
def mute_volume(self, mute):
|
||||||
self.ws_send("mute", mute=mute)
|
self.connection.send("mute", mute=mute)
|
||||||
|
|
||||||
def play_media(self, media_type, media_id, **kwargs):
|
def play_media(self, media_type, media_id, **kwargs):
|
||||||
self.ws_send("play", media_content_id=media_id)
|
self.connection.send("play", media_content_id=media_id)
|
||||||
def media_play(self):
|
def media_play(self):
|
||||||
self.ws_send("play")
|
self.connection.send("play")
|
||||||
def media_pause(self):
|
def media_pause(self):
|
||||||
self.ws_send("pause")
|
self.connection.send("pause")
|
||||||
def media_stop(self):
|
def media_stop(self):
|
||||||
self.ws_send("stop")
|
self.connection.send("stop")
|
||||||
|
36
custom_components/browser_mod/sensor.py
Normal file
36
custom_components/browser_mod/sensor.py
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
import logging
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
from homeassistant.const import STATE_UNAVAILABLE
|
||||||
|
|
||||||
|
from .helpers import setup_platform, BrowserModEntity
|
||||||
|
|
||||||
|
PLATFORM = 'sensor'
|
||||||
|
|
||||||
|
async def async_setup_platform(hass, config, async_add_devices, discovery_info=None):
|
||||||
|
return setup_platform(hass, config, async_add_devices, PLATFORM, BrowserModSensor)
|
||||||
|
|
||||||
|
class BrowserModSensor(BrowserModEntity):
|
||||||
|
domain = PLATFORM
|
||||||
|
|
||||||
|
def __init__(self, hass, connection, deviceID, alias=None):
|
||||||
|
super().__init__(hass, connection, deviceID, alias)
|
||||||
|
self.last_seen = None
|
||||||
|
|
||||||
|
def updated(self):
|
||||||
|
self.last_seen = datetime.now()
|
||||||
|
self.schedule_update_ha_state()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def state(self):
|
||||||
|
if not self.connection.connection:
|
||||||
|
return STATE_UNAVAILABLE
|
||||||
|
return len(self.connection.connection)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def device_state_attributes(self):
|
||||||
|
return {
|
||||||
|
"type": "browser_mod",
|
||||||
|
"last_seen": self.last_seen,
|
||||||
|
**self.data
|
||||||
|
}
|
15
js/main.js
15
js/main.js
@ -84,6 +84,7 @@ class BrowserMod {
|
|||||||
conn.subscribeMessage((msg) => this.callback(msg), {
|
conn.subscribeMessage((msg) => this.callback(msg), {
|
||||||
type: 'browser_mod/connect',
|
type: 'browser_mod/connect',
|
||||||
deviceID: deviceID,
|
deviceID: deviceID,
|
||||||
|
fully: window.fully ? true : undefined,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -267,12 +268,7 @@ class BrowserMod {
|
|||||||
visibility: document.visibilityState,
|
visibility: document.visibilityState,
|
||||||
userAgent: navigator.userAgent,
|
userAgent: navigator.userAgent,
|
||||||
currentUser: this._hass && this._hass.user && this._hass.user.name,
|
currentUser: this._hass && this._hass.user && this._hass.user.name,
|
||||||
blackout: this.is_blackout(),
|
|
||||||
fullyKiosk: window.fully ? true : undefined,
|
fullyKiosk: window.fully ? true : undefined,
|
||||||
brightness: window.fully ? fully.getScreenBrightness() : undefined,
|
|
||||||
battery: window.fully ? fully.getBatteryLevel() : undefined,
|
|
||||||
charging: window.fully ? fully.isPlugged(): undefined,
|
|
||||||
motion: window.fully ? this._fullyMotion : undefined,
|
|
||||||
},
|
},
|
||||||
player: {
|
player: {
|
||||||
volume: this.player.volume,
|
volume: this.player.volume,
|
||||||
@ -280,6 +276,15 @@ class BrowserMod {
|
|||||||
src: this.player.src,
|
src: this.player.src,
|
||||||
state: this.player_state,
|
state: this.player_state,
|
||||||
},
|
},
|
||||||
|
screen: {
|
||||||
|
blackout: this.is_blackout(),
|
||||||
|
brightness: window.fully ? fully.getScreenBrightness() : undefined,
|
||||||
|
},
|
||||||
|
fully: window.fully ? {
|
||||||
|
battery: window.fully ? fully.getBatteryLevel() : undefined,
|
||||||
|
charging: window.fully ? fully.isPlugged(): undefined,
|
||||||
|
motion: window.fully ? this._fullyMotion : undefined,
|
||||||
|
} : undefined,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user