Add base entity for Sensibo (#67696)

This commit is contained in:
G Johansson 2022-03-05 22:37:44 +01:00 committed by GitHub
parent ca32c38859
commit af7670a5a5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 96 additions and 78 deletions

View File

@ -1015,6 +1015,7 @@ omit =
homeassistant/components/sensibo/climate.py
homeassistant/components/sensibo/coordinator.py
homeassistant/components/sensibo/diagnostics.py
homeassistant/components/sensibo/entity.py
homeassistant/components/sensibo/number.py
homeassistant/components/serial/sensor.py
homeassistant/components/serial_pm/sensor.py

View File

@ -1,11 +1,6 @@
"""Support for Sensibo wifi-enabled home thermostats."""
from __future__ import annotations
import asyncio
from aiohttp.client_exceptions import ClientConnectionError
import async_timeout
from pysensibo.exceptions import AuthenticationError, SensiboError
import voluptuous as vol
from homeassistant.components.climate import (
@ -36,15 +31,13 @@ from homeassistant.const import (
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers import config_validation as cv, entity_platform
from homeassistant.helpers.device_registry import CONNECTION_NETWORK_MAC
from homeassistant.helpers.entity import DeviceInfo
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
from homeassistant.helpers.update_coordinator import CoordinatorEntity
from homeassistant.util.temperature import convert as convert_temperature
from .const import ALL, DOMAIN, LOGGER, TIMEOUT
from .const import ALL, DOMAIN, LOGGER
from .coordinator import SensiboDataUpdateCoordinator
from .entity import SensiboBaseEntity
SERVICE_ASSUME_STATE = "assume_state"
@ -126,17 +119,14 @@ async def async_setup_entry(
)
class SensiboClimate(CoordinatorEntity, ClimateEntity):
class SensiboClimate(SensiboBaseEntity, ClimateEntity):
"""Representation of a Sensibo device."""
coordinator: SensiboDataUpdateCoordinator
def __init__(
self, coordinator: SensiboDataUpdateCoordinator, device_id: str
) -> None:
"""Initiate SensiboClimate."""
super().__init__(coordinator)
self._client = coordinator.client
super().__init__(coordinator, device_id)
self._attr_unique_id = device_id
self._attr_name = coordinator.data[device_id]["name"]
self._attr_temperature_unit = (
@ -146,17 +136,6 @@ class SensiboClimate(CoordinatorEntity, ClimateEntity):
)
self._attr_supported_features = self.get_features()
self._attr_precision = PRECISION_TENTHS
self._attr_device_info = DeviceInfo(
identifiers={(DOMAIN, coordinator.data[device_id]["id"])},
name=coordinator.data[device_id]["name"],
connections={(CONNECTION_NETWORK_MAC, coordinator.data[device_id]["mac"])},
manufacturer="Sensibo",
configuration_url="https://home.sensibo.com/",
model=coordinator.data[device_id]["model"],
sw_version=coordinator.data[device_id]["fw_ver"],
hw_version=coordinator.data[device_id]["fw_type"],
suggested_area=coordinator.data[device_id]["name"],
)
def get_features(self) -> int:
"""Get supported features."""
@ -309,26 +288,14 @@ class SensiboClimate(CoordinatorEntity, ClimateEntity):
self, name: str, value: str | int | bool, assumed_state: bool = False
) -> None:
"""Set AC state."""
result = {}
try:
async with async_timeout.timeout(TIMEOUT):
result = await self._client.async_set_ac_state_property(
self.unique_id,
name,
value,
self.coordinator.data[self.unique_id]["ac_states"],
assumed_state,
)
except (
ClientConnectionError,
asyncio.TimeoutError,
AuthenticationError,
SensiboError,
) as err:
raise HomeAssistantError(
f"Failed to set AC state for device {self.name} to Sensibo servers: {err}"
) from err
LOGGER.debug("Result: %s", result)
params = {
"name": name,
"value": value,
"ac_states": self.coordinator.data[self.unique_id]["ac_states"],
"assumed_state": assumed_state,
}
result = await self.async_send_command("set_ac_state", params)
if result["result"]["status"] == "Success":
self.coordinator.data[self.unique_id][AC_STATE_TO_DATA[name]] = value
self.async_write_ha_state()

View File

@ -0,0 +1,77 @@
"""Base entity for Sensibo integration."""
from __future__ import annotations
from typing import Any
import async_timeout
from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers.device_registry import CONNECTION_NETWORK_MAC
from homeassistant.helpers.entity import DeviceInfo
from homeassistant.helpers.update_coordinator import CoordinatorEntity
from .const import DOMAIN, LOGGER, SENSIBO_ERRORS, TIMEOUT
from .coordinator import SensiboDataUpdateCoordinator
class SensiboBaseEntity(CoordinatorEntity):
"""Representation of a Sensibo numbers."""
coordinator: SensiboDataUpdateCoordinator
def __init__(
self,
coordinator: SensiboDataUpdateCoordinator,
device_id: str,
) -> None:
"""Initiate Sensibo Number."""
super().__init__(coordinator)
self._device_id = device_id
self._client = coordinator.client
device = coordinator.data[device_id]
self._attr_device_info = DeviceInfo(
identifiers={(DOMAIN, device["id"])},
name=device["name"],
connections={(CONNECTION_NETWORK_MAC, device["mac"])},
manufacturer="Sensibo",
configuration_url="https://home.sensibo.com/",
model=device["model"],
sw_version=device["fw_ver"],
hw_version=device["fw_type"],
suggested_area=device["name"],
)
async def async_send_command(
self, command: str, params: dict[str, Any]
) -> dict[str, Any]:
"""Send command to Sensibo api."""
try:
async with async_timeout.timeout(TIMEOUT):
result = await self.async_send_api_call(command, params)
except SENSIBO_ERRORS as err:
raise HomeAssistantError(
f"Failed to send command {command} for device {self.name} to Sensibo servers: {err}"
) from err
LOGGER.debug("Result: %s", result)
return result
async def async_send_api_call(
self, command: str, params: dict[str, Any]
) -> dict[str, Any]:
"""Send api call."""
result: dict[str, Any] = {"status": None}
if command == "set_calibration":
result = await self._client.async_set_calibration(
self._device_id,
params["data"],
)
if command == "set_ac_state":
result = await self._client.async_set_ac_state_property(
self._device_id,
params["name"],
params["value"],
params["ac_states"],
params["assumed_state"],
)
return result

View File

@ -3,19 +3,16 @@ from __future__ import annotations
from dataclasses import dataclass
import async_timeout
from homeassistant.components.number import NumberEntity, NumberEntityDescription
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers.device_registry import CONNECTION_NETWORK_MAC
from homeassistant.helpers.entity import DeviceInfo, EntityCategory
from homeassistant.helpers.entity import EntityCategory
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.update_coordinator import CoordinatorEntity
from .const import DOMAIN, LOGGER, SENSIBO_ERRORS, TIMEOUT
from .const import DOMAIN
from .coordinator import SensiboDataUpdateCoordinator
from .entity import SensiboBaseEntity
@dataclass
@ -73,10 +70,9 @@ async def async_setup_entry(
)
class SensiboNumber(CoordinatorEntity, NumberEntity):
class SensiboNumber(SensiboBaseEntity, NumberEntity):
"""Representation of a Sensibo numbers."""
coordinator: SensiboDataUpdateCoordinator
entity_description: SensiboNumberEntityDescription
def __init__(
@ -86,25 +82,12 @@ class SensiboNumber(CoordinatorEntity, NumberEntity):
entity_description: SensiboNumberEntityDescription,
) -> None:
"""Initiate Sensibo Number."""
super().__init__(coordinator)
super().__init__(coordinator, device_id)
self.entity_description = entity_description
self._device_id = device_id
self._client = coordinator.client
self._attr_unique_id = f"{device_id}-{entity_description.key}"
self._attr_name = (
f"{coordinator.data[device_id]['name']} {entity_description.name}"
)
self._attr_device_info = DeviceInfo(
identifiers={(DOMAIN, coordinator.data[device_id]["id"])},
name=coordinator.data[device_id]["name"],
connections={(CONNECTION_NETWORK_MAC, coordinator.data[device_id]["mac"])},
manufacturer="Sensibo",
configuration_url="https://home.sensibo.com/",
model=coordinator.data[device_id]["model"],
sw_version=coordinator.data[device_id]["fw_ver"],
hw_version=coordinator.data[device_id]["fw_type"],
suggested_area=coordinator.data[device_id]["name"],
)
@property
def value(self) -> float:
@ -114,17 +97,7 @@ class SensiboNumber(CoordinatorEntity, NumberEntity):
async def async_set_value(self, value: float) -> None:
"""Set value for calibration."""
data = {self.entity_description.remote_key: value}
try:
async with async_timeout.timeout(TIMEOUT):
result = await self._client.async_set_calibration(
self._device_id,
data,
)
except SENSIBO_ERRORS as err:
raise HomeAssistantError(
f"Failed to set calibration for device {self.name} to Sensibo servers: {err}"
) from err
LOGGER.debug("Result: %s", result)
result = await self.async_send_command("set_calibration", {"data": data})
if result["status"] == "success":
self.coordinator.data[self._device_id][self.entity_description.key] = value
self.async_write_ha_state()