Files
core/homeassistant/components/roku/__init__.py
Chris Talkington cf8dfdae47 Add config flow to roku (#31988)
* create a dedicated const.py

* add DEFAULT_PORT to const.py

* work on config flow conversion.

* remove discovery.

* work on config flow and add tests. other cleanup.

* work on config flow and add tests. other cleanup.

* add quality scale to manifest.

* work on config flow and add tests. other cleanup.

* review tweaks.

* Update manifest.json

* catch more specific errors

* catch more errors.

* impprt specific exceptions

* import specific exceptions

* Update __init__.py

* Update config_flow.py

* Update media_player.py

* Update remote.py

* Update media_player.py

* Update remote.py

* Update media_player.py

* Update remote.py

* Update config_flow.py

* Update config_flow.py

* Update media_player.py

* Update __init__.py

* Update __init__.py

* Update config_flow.py

* Update test_config_flow.py

* Update config_flow.py

* Update __init__.py

* Update test_config_flow.py

* Update remote.py

* Update test_init.py

* Update test_init.py

* Update media_player.py

* Update media_player.py

* Update media_player.py
2020-03-15 21:13:04 -07:00

94 lines
2.6 KiB
Python

"""Support for Roku."""
import asyncio
from datetime import timedelta
from socket import gaierror as SocketGIAError
from typing import Dict
from requests.exceptions import RequestException
from roku import Roku, RokuException
import voluptuous as vol
from homeassistant.components.media_player import DOMAIN as MEDIA_PLAYER_DOMAIN
from homeassistant.components.remote import DOMAIN as REMOTE_DOMAIN
from homeassistant.config_entries import SOURCE_IMPORT, ConfigEntry
from homeassistant.const import CONF_HOST
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import ConfigEntryNotReady
from homeassistant.helpers import config_validation as cv
from .const import DATA_CLIENT, DATA_DEVICE_INFO, DOMAIN
CONFIG_SCHEMA = vol.Schema(
{
DOMAIN: vol.All(
cv.ensure_list, [vol.Schema({vol.Required(CONF_HOST): cv.string})]
)
},
extra=vol.ALLOW_EXTRA,
)
PLATFORMS = [MEDIA_PLAYER_DOMAIN, REMOTE_DOMAIN]
SCAN_INTERVAL = timedelta(seconds=30)
def get_roku_data(host: str) -> dict:
"""Retrieve a Roku instance and version info for the device."""
roku = Roku(host)
roku_device_info = roku.device_info
return {
DATA_CLIENT: roku,
DATA_DEVICE_INFO: roku_device_info,
}
async def async_setup(hass: HomeAssistant, config: Dict) -> bool:
"""Set up the Roku integration."""
hass.data.setdefault(DOMAIN, {})
if DOMAIN in config:
for entry_config in config[DOMAIN]:
hass.async_create_task(
hass.config_entries.flow.async_init(
DOMAIN, context={"source": SOURCE_IMPORT}, data=entry_config,
)
)
return True
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
"""Set up Roku from a config entry."""
try:
roku_data = await hass.async_add_executor_job(
get_roku_data, entry.data[CONF_HOST],
)
except (SocketGIAError, RequestException, RokuException) as exception:
raise ConfigEntryNotReady from exception
hass.data[DOMAIN][entry.entry_id] = roku_data
for component in PLATFORMS:
hass.async_create_task(
hass.config_entries.async_forward_entry_setup(entry, component)
)
return True
async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
"""Unload a config entry."""
unload_ok = all(
await asyncio.gather(
*[
hass.config_entries.async_forward_entry_unload(entry, component)
for component in PLATFORMS
]
)
)
if unload_ok:
hass.data[DOMAIN].pop(entry.entry_id)
return unload_ok