core/homeassistant/components/sisyphus/__init__.py

127 lines
4.0 KiB
Python

"""Support for controlling Sisyphus Kinetic Art Tables."""
import asyncio
import logging
from sisyphus_control import Table
import voluptuous as vol
from homeassistant.const import CONF_HOST, CONF_NAME, EVENT_HOMEASSISTANT_STOP, Platform
from homeassistant.core import HomeAssistant
from homeassistant.helpers.aiohttp_client import async_get_clientsession
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.discovery import async_load_platform
from homeassistant.helpers.typing import ConfigType
_LOGGER = logging.getLogger(__name__)
DATA_SISYPHUS = "sisyphus"
DOMAIN = "sisyphus"
AUTODETECT_SCHEMA = vol.Schema({})
TABLE_SCHEMA = vol.Schema(
{vol.Required(CONF_NAME): cv.string, vol.Required(CONF_HOST): cv.string}
)
TABLES_SCHEMA = vol.Schema([TABLE_SCHEMA])
CONFIG_SCHEMA = vol.Schema(
{DOMAIN: vol.Any(AUTODETECT_SCHEMA, TABLES_SCHEMA)}, extra=vol.ALLOW_EXTRA
)
# Silence these loggers by default. Their INFO level is super chatty and we
# only need error-level logging from the integration itself by default.
logging.getLogger("socketio.client").setLevel(logging.CRITICAL + 1)
logging.getLogger("engineio.client").setLevel(logging.CRITICAL + 1)
async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
"""Set up the sisyphus component."""
tables = hass.data.setdefault(DATA_SISYPHUS, {})
table_configs = config[DOMAIN]
session = async_get_clientsession(hass)
async def add_table(host, name=None):
"""Add platforms for a single table with the given hostname."""
tables[host] = TableHolder(hass, session, host, name)
hass.async_create_task(
async_load_platform(hass, Platform.LIGHT, DOMAIN, {CONF_HOST: host}, config)
)
hass.async_create_task(
async_load_platform(
hass, Platform.MEDIA_PLAYER, DOMAIN, {CONF_HOST: host}, config
)
)
if isinstance(table_configs, dict): # AUTODETECT_SCHEMA
for ip_address in await Table.find_table_ips(session):
await add_table(ip_address)
else: # TABLES_SCHEMA
for conf in table_configs:
await add_table(conf[CONF_HOST], conf[CONF_NAME])
async def close_tables(*args):
"""Close all table objects."""
tasks = [table.close() for table in tables.values()]
if tasks:
await asyncio.wait(tasks)
hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, close_tables)
return True
class TableHolder:
"""Holds table objects and makes them available to platforms."""
def __init__(self, hass, session, host, name):
"""Initialize the table holder."""
self._hass = hass
self._session = session
self._host = host
self._name = name
self._table = None
self._table_task = None
@property
def available(self):
"""Return true if the table is responding to heartbeats."""
if self._table_task and self._table_task.done():
return self._table_task.result().is_connected
return False
@property
def name(self):
"""Return the name of the table."""
return self._name
async def get_table(self):
"""Return the Table held by this holder, connecting to it if needed."""
if self._table:
return self._table
if not self._table_task:
self._table_task = self._hass.async_create_task(self._connect_table())
return await self._table_task
async def _connect_table(self):
try:
self._table = await Table.connect(self._host, self._session)
if self._name is None:
self._name = self._table.name
_LOGGER.debug("Connected to %s at %s", self._name, self._host)
return self._table
finally:
self._table_task = None
async def close(self):
"""Close the table held by this holder, if any."""
if self._table:
await self._table.close()
self._table = None
self._table_task = None