1 """Init the tedee component."""
3 from collections.abc
import Awaitable, Callable
4 from http
import HTTPStatus
8 from aiohttp.hdrs
import METH_POST
9 from aiohttp.web
import Request, Response
10 from aiotedee.exception
import TedeeDataUpdateException, TedeeWebhookException
14 async_generate_id
as webhook_generate_id,
15 async_generate_url
as webhook_generate_url,
16 async_register
as webhook_register,
17 async_unregister
as webhook_unregister,
25 from .const
import DOMAIN, NAME
26 from .coordinator
import TedeeApiCoordinator, TedeeConfigEntry
29 Platform.BINARY_SENSOR,
34 _LOGGER = logging.getLogger(__name__)
38 """Integration setup."""
42 await coordinator.async_config_entry_first_refresh()
44 device_registry = dr.async_get(hass)
45 device_registry.async_get_or_create(
46 config_entry_id=entry.entry_id,
47 identifiers={(DOMAIN, coordinator.bridge.serial)},
49 name=coordinator.bridge.name,
51 serial_number=coordinator.bridge.serial,
54 entry.runtime_data = coordinator
56 async
def unregister_webhook(_: Any) ->
None:
57 await coordinator.async_unregister_webhook()
58 webhook_unregister(hass, entry.data[CONF_WEBHOOK_ID])
60 async
def register_webhook() -> None:
61 instance_url =
get_url(hass, allow_ip=
True, allow_external=
False)
64 await coordinator.tedee_client.cleanup_webhooks_by_host(instance_url)
65 except (TedeeDataUpdateException, TedeeWebhookException)
as ex:
66 _LOGGER.warning(
"Failed to cleanup Tedee webhooks by host: %s", ex)
68 webhook_url = webhook_generate_url(
69 hass, entry.data[CONF_WEBHOOK_ID], allow_external=
False, allow_ip=
True
71 webhook_name =
"Tedee"
72 if entry.title != NAME:
73 webhook_name = f
"{NAME} {entry.title}"
79 entry.data[CONF_WEBHOOK_ID],
81 allowed_methods=[METH_POST],
83 _LOGGER.debug(
"Registered Tedee webhook at hass: %s", webhook_url)
86 await coordinator.async_register_webhook(webhook_url)
87 except TedeeWebhookException:
88 _LOGGER.exception(
"Failed to register Tedee webhook from bridge")
90 entry.async_on_unload(
91 hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, unregister_webhook)
94 entry.async_create_background_task(
95 hass, register_webhook(),
"tedee_register_webhook"
97 await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
103 """Unload a config entry."""
104 return await hass.config_entries.async_unload_platforms(entry, PLATFORMS)
108 coordinator: TedeeApiCoordinator,
109 ) -> Callable[[HomeAssistant, str, Request], Awaitable[Response |
None]]:
110 """Return webhook handler."""
112 async
def async_webhook_handler(
113 hass: HomeAssistant, webhook_id: str, request: Request
114 ) -> Response |
None:
116 if not request.body_exists:
117 return HomeAssistantView.json(
118 result=
"No Body", status_code=HTTPStatus.BAD_REQUEST
121 body = await request.json()
123 coordinator.webhook_received(body)
124 except TedeeWebhookException
as ex:
125 return HomeAssistantView.json(
126 result=
str(ex), status_code=HTTPStatus.BAD_REQUEST
129 return HomeAssistantView.json(result=
"OK", status_code=HTTPStatus.OK)
131 return async_webhook_handler
135 """Migrate old entry."""
136 if config_entry.version > 1:
140 version = config_entry.version
141 minor_version = config_entry.minor_version
143 if version == 1
and minor_version == 1:
145 "Migrating Tedee config entry from version %s.%s", version, minor_version
147 data = {**config_entry.data, CONF_WEBHOOK_ID: webhook_generate_id()}
148 hass.config_entries.async_update_entry(config_entry, data=data, minor_version=2)
149 _LOGGER.debug(
"Migration to version 1.2 successful")
bool async_setup_entry(HomeAssistant hass, TedeeConfigEntry entry)
bool async_unload_entry(HomeAssistant hass, ConfigEntry entry)
bool async_migrate_entry(HomeAssistant hass, ConfigEntry config_entry)
Callable[[HomeAssistant, str, Request], Awaitable[Response|None]] get_webhook_handler(TedeeApiCoordinator coordinator)
str get_url(HomeAssistant hass, *bool require_current_request=False, bool require_ssl=False, bool require_standard_port=False, bool require_cloud=False, bool allow_internal=True, bool allow_external=True, bool allow_cloud=True, bool|None allow_ip=None, bool|None prefer_external=None, bool prefer_cloud=False)