Add ecobee ventilator (#83645)

Co-authored-by: G Johansson <goran.johansson@shiftit.se>
Co-authored-by: J. Nick Koston <nick@koston.org>
This commit is contained in:
Marc-Olivier Arsenault 2023-02-07 08:54:23 -05:00 committed by GitHub
parent 4aa61b0d64
commit fe9f6823c3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 299 additions and 4 deletions

View file

@ -91,7 +91,9 @@ class EcobeeData:
Also handle refreshing tokens and updating config entry with refreshed tokens.
"""
def __init__(self, hass, entry, api_key, refresh_token):
def __init__(
self, hass: HomeAssistant, entry: ConfigEntry, api_key: str, refresh_token: str
) -> None:
"""Initialize the Ecobee data object."""
self._hass = hass
self._entry = entry

View file

@ -45,6 +45,7 @@ PLATFORMS = [
Platform.BINARY_SENSOR,
Platform.CLIMATE,
Platform.HUMIDIFIER,
Platform.NUMBER,
Platform.SENSOR,
Platform.WEATHER,
]

View file

@ -0,0 +1,39 @@
"""Base classes shared among Ecobee entities."""
from __future__ import annotations
import logging
from typing import Any
from homeassistant.helpers.entity import DeviceInfo, Entity
from . import EcobeeData
from .const import DOMAIN, ECOBEE_MODEL_TO_NAME, MANUFACTURER
_LOGGER = logging.getLogger(__name__)
class EcobeeBaseEntity(Entity):
"""Base methods for Ecobee entities."""
def __init__(self, data: EcobeeData, thermostat_index: int) -> None:
"""Initiate base methods for Ecobee entities."""
self.data = data
self.thermostat_index = thermostat_index
thermostat = self.thermostat
self.base_unique_id = thermostat["identifier"]
self._attr_device_info = DeviceInfo(
identifiers={(DOMAIN, thermostat["identifier"])},
manufacturer=MANUFACTURER,
model=ECOBEE_MODEL_TO_NAME.get(thermostat["modelNumber"]),
name=thermostat["name"],
)
@property
def thermostat(self) -> dict[str, Any]:
"""Return the thermostat data for the entity."""
return self.data.ecobee.get_thermostat(self.thermostat_index)
@property
def available(self) -> bool:
"""Return if device is available."""
return self.thermostat["runtime"]["connected"]

View file

@ -4,7 +4,7 @@
"config_flow": true,
"documentation": "https://www.home-assistant.io/integrations/ecobee",
"requirements": ["python-ecobee-api==0.2.14"],
"codeowners": ["@marthoc"],
"codeowners": ["@marthoc", "@marcolivierarsenault"],
"homekit": {
"models": ["EB-*", "ecobee*"]
},

View file

@ -0,0 +1,107 @@
"""Support for using number with ecobee thermostats."""
from __future__ import annotations
from collections.abc import Awaitable, Callable
from dataclasses import dataclass
import logging
from homeassistant.components.number import NumberEntity, NumberEntityDescription
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import UnitOfTime
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from . import EcobeeData
from .const import DOMAIN
from .entity import EcobeeBaseEntity
_LOGGER = logging.getLogger(__name__)
@dataclass
class EcobeeNumberEntityDescriptionBase:
"""Required values when describing Ecobee number entities."""
ecobee_setting_key: str
set_fn: Callable[[EcobeeData, int, int], Awaitable]
@dataclass
class EcobeeNumberEntityDescription(
NumberEntityDescription, EcobeeNumberEntityDescriptionBase
):
"""Class describing Ecobee number entities."""
VENTILATOR_NUMBERS = (
EcobeeNumberEntityDescription(
key="home",
name="home",
ecobee_setting_key="ventilatorMinOnTimeHome",
set_fn=lambda data, id, min_time: data.ecobee.set_ventilator_min_on_time_home(
id, min_time
),
),
EcobeeNumberEntityDescription(
key="away",
name="away",
ecobee_setting_key="ventilatorMinOnTimeAway",
set_fn=lambda data, id, min_time: data.ecobee.set_ventilator_min_on_time_away(
id, min_time
),
),
)
async def async_setup_entry(
hass: HomeAssistant,
config_entry: ConfigEntry,
async_add_entities: AddEntitiesCallback,
) -> None:
"""Set up the ecobee thermostat number entity."""
data: EcobeeData = hass.data[DOMAIN]
entities = []
_LOGGER.debug("Adding min time ventilators numbers (if present)")
for index, thermostat in enumerate(data.ecobee.thermostats):
if thermostat["settings"]["ventilatorType"] == "none":
continue
_LOGGER.debug("Adding %s's ventilator min times number", thermostat["name"])
for numbers in VENTILATOR_NUMBERS:
entities.append(EcobeeVentilatorMinTime(data, index, numbers))
async_add_entities(entities, True)
class EcobeeVentilatorMinTime(EcobeeBaseEntity, NumberEntity):
"""A number class, representing min time for an ecobee thermostat with ventilator attached."""
entity_description: EcobeeNumberEntityDescription
_attr_native_min_value = 0
_attr_native_max_value = 60
_attr_native_step = 5
_attr_native_unit_of_measurement = UnitOfTime.MINUTES
_attr_has_entity_name = True
def __init__(
self,
data: EcobeeData,
thermostat_index: int,
description: EcobeeNumberEntityDescription,
) -> None:
"""Initialize ecobee ventilator platform."""
super().__init__(data, thermostat_index)
self.entity_description = description
self._attr_name = f"Ventilator min time {description.name}"
self._attr_unique_id = f"{self.base_unique_id}_ventilator_{description.key}"
async def async_update(self) -> None:
"""Get the latest state from the thermostat."""
await self.data.update()
self._attr_native_value = self.thermostat["settings"][
self.entity_description.ecobee_setting_key
]
def set_native_value(self, value: float) -> None:
"""Set new ventilator Min On Time value."""
self.entity_description.set_fn(self.data, self.thermostat_index, int(value))