119 lines
3.6 KiB
Python
119 lines
3.6 KiB
Python
"""Support for Honeywell (US) Total Connect Comfort climate systems."""
|
|
import asyncio
|
|
from dataclasses import dataclass
|
|
|
|
import aiosomecomfort
|
|
|
|
from homeassistant.config_entries import ConfigEntry
|
|
from homeassistant.const import CONF_PASSWORD, CONF_USERNAME, Platform
|
|
from homeassistant.core import HomeAssistant, callback
|
|
from homeassistant.exceptions import ConfigEntryAuthFailed, ConfigEntryNotReady
|
|
from homeassistant.helpers.aiohttp_client import async_get_clientsession
|
|
|
|
from .const import (
|
|
_LOGGER,
|
|
CONF_COOL_AWAY_TEMPERATURE,
|
|
CONF_DEV_ID,
|
|
CONF_HEAT_AWAY_TEMPERATURE,
|
|
CONF_LOC_ID,
|
|
DOMAIN,
|
|
)
|
|
|
|
UPDATE_LOOP_SLEEP_TIME = 5
|
|
PLATFORMS = [Platform.CLIMATE, Platform.SENSOR]
|
|
|
|
MIGRATE_OPTIONS_KEYS = {CONF_COOL_AWAY_TEMPERATURE, CONF_HEAT_AWAY_TEMPERATURE}
|
|
|
|
|
|
@callback
|
|
def _async_migrate_data_to_options(
|
|
hass: HomeAssistant, config_entry: ConfigEntry
|
|
) -> None:
|
|
if not MIGRATE_OPTIONS_KEYS.intersection(config_entry.data):
|
|
return
|
|
hass.config_entries.async_update_entry(
|
|
config_entry,
|
|
data={
|
|
k: v for k, v in config_entry.data.items() if k not in MIGRATE_OPTIONS_KEYS
|
|
},
|
|
options={
|
|
**config_entry.options,
|
|
**{k: config_entry.data.get(k) for k in MIGRATE_OPTIONS_KEYS},
|
|
},
|
|
)
|
|
|
|
|
|
async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> bool:
|
|
"""Set up the Honeywell thermostat."""
|
|
_async_migrate_data_to_options(hass, config_entry)
|
|
|
|
username = config_entry.data[CONF_USERNAME]
|
|
password = config_entry.data[CONF_PASSWORD]
|
|
|
|
client = aiosomecomfort.AIOSomeComfort(
|
|
username, password, session=async_get_clientsession(hass)
|
|
)
|
|
try:
|
|
await client.login()
|
|
await client.discover()
|
|
|
|
except aiosomecomfort.device.AuthError as ex:
|
|
raise ConfigEntryAuthFailed("Incorrect Password") from ex
|
|
|
|
except (
|
|
aiosomecomfort.device.ConnectionError,
|
|
aiosomecomfort.device.ConnectionTimeout,
|
|
aiosomecomfort.device.SomeComfortError,
|
|
asyncio.TimeoutError,
|
|
) as ex:
|
|
raise ConfigEntryNotReady(
|
|
"Failed to initialize the Honeywell client: Connection error"
|
|
) from ex
|
|
|
|
loc_id = config_entry.data.get(CONF_LOC_ID)
|
|
dev_id = config_entry.data.get(CONF_DEV_ID)
|
|
|
|
devices = {}
|
|
for location in client.locations_by_id.values():
|
|
if not loc_id or location.locationid == loc_id:
|
|
for device in location.devices_by_id.values():
|
|
if not dev_id or device.deviceid == dev_id:
|
|
devices[device.deviceid] = device
|
|
|
|
if len(devices) == 0:
|
|
_LOGGER.debug("No devices found")
|
|
return False
|
|
|
|
data = HoneywellData(config_entry.entry_id, client, devices)
|
|
hass.data.setdefault(DOMAIN, {})
|
|
hass.data[DOMAIN][config_entry.entry_id] = data
|
|
await hass.config_entries.async_forward_entry_setups(config_entry, PLATFORMS)
|
|
|
|
config_entry.async_on_unload(config_entry.add_update_listener(update_listener))
|
|
|
|
return True
|
|
|
|
|
|
async def update_listener(hass: HomeAssistant, config_entry: ConfigEntry) -> None:
|
|
"""Update listener."""
|
|
await hass.config_entries.async_reload(config_entry.entry_id)
|
|
|
|
|
|
async def async_unload_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> bool:
|
|
"""Unload the config and platforms."""
|
|
unload_ok = await hass.config_entries.async_unload_platforms(
|
|
config_entry, PLATFORMS
|
|
)
|
|
if unload_ok:
|
|
hass.data.pop(DOMAIN)
|
|
return unload_ok
|
|
|
|
|
|
@dataclass
|
|
class HoneywellData:
|
|
"""Shared data for Honeywell."""
|
|
|
|
entry_id: str
|
|
client: aiosomecomfort.AIOSomeComfort
|
|
devices: dict[str, aiosomecomfort.device.Device]
|