core/homeassistant/components/emulated_roku/binding.py

148 lines
5.0 KiB
Python

"""Bridge between emulated_roku and Home Assistant."""
import logging
from homeassistant.const import (
EVENT_HOMEASSISTANT_START, EVENT_HOMEASSISTANT_STOP)
from homeassistant.core import CoreState, EventOrigin
LOGGER = logging.getLogger('.')
EVENT_ROKU_COMMAND = 'roku_command'
ATTR_COMMAND_TYPE = 'type'
ATTR_SOURCE_NAME = 'source_name'
ATTR_KEY = 'key'
ATTR_APP_ID = 'app_id'
ROKU_COMMAND_KEYDOWN = 'keydown'
ROKU_COMMAND_KEYUP = 'keyup'
ROKU_COMMAND_KEYPRESS = 'keypress'
ROKU_COMMAND_LAUNCH = 'launch'
class EmulatedRoku:
"""Manages an emulated_roku server."""
def __init__(self, hass, name, host_ip, listen_port,
advertise_ip, advertise_port, upnp_bind_multicast):
"""Initialize the properties."""
self.hass = hass
self.roku_usn = name
self.host_ip = host_ip
self.listen_port = listen_port
self.advertise_port = advertise_port
self.advertise_ip = advertise_ip
self.bind_multicast = upnp_bind_multicast
self._api_server = None
self._unsub_start_listener = None
self._unsub_stop_listener = None
async def setup(self):
"""Start the emulated_roku server."""
from emulated_roku import EmulatedRokuServer, \
EmulatedRokuCommandHandler
class EventCommandHandler(EmulatedRokuCommandHandler):
"""emulated_roku command handler to turn commands into events."""
def __init__(self, hass):
self.hass = hass
def on_keydown(self, roku_usn, key):
"""Handle keydown event."""
self.hass.bus.async_fire(EVENT_ROKU_COMMAND, {
ATTR_SOURCE_NAME: roku_usn,
ATTR_COMMAND_TYPE: ROKU_COMMAND_KEYDOWN,
ATTR_KEY: key
}, EventOrigin.local)
def on_keyup(self, roku_usn, key):
"""Handle keyup event."""
self.hass.bus.async_fire(EVENT_ROKU_COMMAND, {
ATTR_SOURCE_NAME: roku_usn,
ATTR_COMMAND_TYPE: ROKU_COMMAND_KEYUP,
ATTR_KEY: key
}, EventOrigin.local)
def on_keypress(self, roku_usn, key):
"""Handle keypress event."""
self.hass.bus.async_fire(EVENT_ROKU_COMMAND, {
ATTR_SOURCE_NAME: roku_usn,
ATTR_COMMAND_TYPE: ROKU_COMMAND_KEYPRESS,
ATTR_KEY: key
}, EventOrigin.local)
def launch(self, roku_usn, app_id):
"""Handle launch event."""
self.hass.bus.async_fire(EVENT_ROKU_COMMAND, {
ATTR_SOURCE_NAME: roku_usn,
ATTR_COMMAND_TYPE: ROKU_COMMAND_LAUNCH,
ATTR_APP_ID: app_id
}, EventOrigin.local)
LOGGER.debug("Intializing emulated_roku %s on %s:%s",
self.roku_usn, self.host_ip, self.listen_port)
handler = EventCommandHandler(self.hass)
self._api_server = EmulatedRokuServer(
self.hass.loop, handler,
self.roku_usn, self.host_ip, self.listen_port,
advertise_ip=self.advertise_ip,
advertise_port=self.advertise_port,
bind_multicast=self.bind_multicast
)
async def emulated_roku_stop(event):
"""Wrap the call to emulated_roku.close."""
LOGGER.debug("Stopping emulated_roku %s", self.roku_usn)
self._unsub_stop_listener = None
await self._api_server.close()
async def emulated_roku_start(event):
"""Wrap the call to emulated_roku.start."""
try:
LOGGER.debug("Starting emulated_roku %s", self.roku_usn)
self._unsub_start_listener = None
await self._api_server.start()
except OSError:
LOGGER.exception("Failed to start Emulated Roku %s on %s:%s",
self.roku_usn, self.host_ip, self.listen_port)
# clean up inconsistent state on errors
await emulated_roku_stop(None)
else:
self._unsub_stop_listener = self.hass.bus.async_listen_once(
EVENT_HOMEASSISTANT_STOP,
emulated_roku_stop)
# start immediately if already running
if self.hass.state == CoreState.running:
await emulated_roku_start(None)
else:
self._unsub_start_listener = self.hass.bus.async_listen_once(
EVENT_HOMEASSISTANT_START,
emulated_roku_start)
return True
async def unload(self):
"""Unload the emulated_roku server."""
LOGGER.debug("Unloading emulated_roku %s", self.roku_usn)
if self._unsub_start_listener:
self._unsub_start_listener()
self._unsub_start_listener = None
if self._unsub_stop_listener:
self._unsub_stop_listener()
self._unsub_stop_listener = None
await self._api_server.close()
return True