Files
core/homeassistant/components/melcloud/__init__.py
2026-01-14 00:38:41 +01:00

78 lines
3.0 KiB
Python

"""The MELCloud Climate integration."""
from __future__ import annotations
import asyncio
from datetime import timedelta
from http import HTTPStatus
from aiohttp import ClientConnectionError, ClientResponseError
from pymelcloud import get_devices
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_TOKEN, Platform
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import ConfigEntryAuthFailed
from homeassistant.helpers import device_registry as dr
from homeassistant.helpers.aiohttp_client import async_get_clientsession
from homeassistant.helpers.update_coordinator import UpdateFailed
from .coordinator import MelCloudConfigEntry, MelCloudDeviceUpdateCoordinator
PLATFORMS = [Platform.CLIMATE, Platform.SENSOR, Platform.WATER_HEATER]
async def async_setup_entry(hass: HomeAssistant, entry: MelCloudConfigEntry) -> bool:
"""Establish connection with MELCloud."""
try:
async with asyncio.timeout(10):
all_devices = await get_devices(
token=entry.data[CONF_TOKEN],
session=async_get_clientsession(hass),
conf_update_interval=timedelta(minutes=30),
device_set_debounce=timedelta(seconds=2),
)
except ClientResponseError as ex:
if ex.status in (HTTPStatus.UNAUTHORIZED, HTTPStatus.FORBIDDEN):
raise ConfigEntryAuthFailed from ex
if ex.status == HTTPStatus.TOO_MANY_REQUESTS:
raise UpdateFailed(
"MELCloud rate limit exceeded. Your account may be temporarily blocked"
) from ex
raise UpdateFailed(f"Error communicating with MELCloud: {ex}") from ex
except (TimeoutError, ClientConnectionError) as ex:
raise UpdateFailed(f"Error communicating with MELCloud: {ex}") from ex
# Create per-device coordinators
coordinators: dict[str, list[MelCloudDeviceUpdateCoordinator]] = {}
device_registry = dr.async_get(hass)
for device_type, devices in all_devices.items():
# Build coordinators for this device_type
coordinators[device_type] = [
MelCloudDeviceUpdateCoordinator(hass, device, entry) for device in devices
]
# Perform initial refreshes concurrently
await asyncio.gather(
*(
coordinator.async_config_entry_first_refresh()
for coordinator in coordinators[device_type]
)
)
# Register parent devices so zone entities can reference via_device
for coordinator in coordinators[device_type]:
device_registry.async_get_or_create(
config_entry_id=entry.entry_id,
**coordinator.device_info,
)
entry.runtime_data = coordinators
await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
return True
async def async_unload_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> bool:
"""Unload a config entry."""
return await hass.config_entries.async_unload_platforms(config_entry, PLATFORMS)