mirror of
https://github.com/home-assistant/supervisor.git
synced 2025-04-21 19:57:15 +00:00
122 lines
3.9 KiB
Python
122 lines
3.9 KiB
Python
"""Handle discover message for Home Assistant."""
|
|
import logging
|
|
from contextlib import suppress
|
|
from uuid import uuid4
|
|
|
|
import attr
|
|
import voluptuous as vol
|
|
from voluptuous.humanize import humanize_error
|
|
|
|
from .const import FILE_HASSIO_DISCOVERY, ATTR_CONFIG, ATTR_DISCOVERY
|
|
from .coresys import CoreSysAttributes
|
|
from .exceptions import DiscoveryError, HomeAssistantAPIError
|
|
from .validate import SCHEMA_DISCOVERY_CONFIG
|
|
from .utils.json import JsonConfig
|
|
from .services.validate import DISCOVERY_SERVICES
|
|
|
|
_LOGGER = logging.getLogger(__name__)
|
|
|
|
CMD_NEW = 'post'
|
|
CMD_DEL = 'delete'
|
|
|
|
|
|
class Discovery(CoreSysAttributes, JsonConfig):
|
|
"""Home Assistant Discovery handler."""
|
|
|
|
def __init__(self, coresys):
|
|
"""Initialize discovery handler."""
|
|
super().__init__(FILE_HASSIO_DISCOVERY, SCHEMA_DISCOVERY_CONFIG)
|
|
self.coresys = coresys
|
|
self.message_obj = {}
|
|
|
|
async def load(self):
|
|
"""Load exists discovery message into storage."""
|
|
messages = {}
|
|
for message in self._data[ATTR_DISCOVERY]:
|
|
discovery = Message(**message)
|
|
messages[discovery.uuid] = discovery
|
|
|
|
self.message_obj = messages
|
|
|
|
def save(self):
|
|
"""Write discovery message into data file."""
|
|
messages = []
|
|
for message in self.list_messages:
|
|
messages.append(attr.asdict(message))
|
|
|
|
self._data[ATTR_DISCOVERY].clear()
|
|
self._data[ATTR_DISCOVERY].extend(messages)
|
|
self.save_data()
|
|
|
|
def get(self, uuid):
|
|
"""Return discovery message."""
|
|
return self.message_obj.get(uuid)
|
|
|
|
@property
|
|
def list_messages(self):
|
|
"""Return list of available discovery messages."""
|
|
return list(self.message_obj.values())
|
|
|
|
def send(self, addon, service, config):
|
|
"""Send a discovery message to Home Assistant."""
|
|
try:
|
|
DISCOVERY_SERVICES[service](config)
|
|
except vol.Invalid as err:
|
|
_LOGGER.error(
|
|
"Invalid discovery %s config", humanize_error(config, err))
|
|
raise DiscoveryError() from None
|
|
|
|
# Create message
|
|
message = Message(addon.slug, service, config)
|
|
|
|
# Already exists?
|
|
for old_message in self.list_messages:
|
|
if old_message != message:
|
|
continue
|
|
_LOGGER.warning("Duplicate discovery message from %s", addon.slug)
|
|
return old_message
|
|
|
|
_LOGGER.info("Send discovery to Home Assistant %s from %s",
|
|
service, addon.slug)
|
|
self.message_obj[message.uuid] = message
|
|
self.save()
|
|
|
|
self.sys_create_task(self._push_discovery(message, CMD_NEW))
|
|
return message
|
|
|
|
def remove(self, message):
|
|
"""Remove a discovery message from Home Assistant."""
|
|
self.message_obj.pop(message.uuid, None)
|
|
self.save()
|
|
|
|
_LOGGER.info("Delete discovery to Home Assistant %s from %s",
|
|
message.service, message.addon)
|
|
self.sys_create_task(self._push_discovery(message, CMD_DEL))
|
|
|
|
async def _push_discovery(self, message, command):
|
|
"""Send a discovery request."""
|
|
if not await self.sys_homeassistant.check_api_state():
|
|
_LOGGER.info("Discovery %s mesage ignore", message.uuid)
|
|
return
|
|
|
|
data = attr.asdict(message)
|
|
data.pop(ATTR_CONFIG)
|
|
|
|
with suppress(HomeAssistantAPIError):
|
|
async with self.sys_homeassistant.make_request(
|
|
command, f"api/hassio_push/discovery/{message.uuid}",
|
|
json=data, timeout=10):
|
|
_LOGGER.info("Discovery %s message send", message.uuid)
|
|
return
|
|
|
|
_LOGGER.warning("Discovery %s message fail", message.uuid)
|
|
|
|
|
|
@attr.s
|
|
class Message:
|
|
"""Represent a single Discovery message."""
|
|
uuid = attr.ib(factory=lambda: uuid4().hex, cmp=False, init=False)
|
|
addon = attr.ib()
|
|
service = attr.ib()
|
|
config = attr.ib(cmp=False)
|