Address feedback to Overkiz integration (round 2) (#63036)

* Address feedback in multiple files

* Add missing return statement

* Improve sensor descriptions

* Improve typing

* Move to new device registry

* Disable RSSI sensor by default

* Improve typing
This commit is contained in:
Mick Vleeshouwer 2021-12-30 06:22:35 -08:00 committed by GitHub
parent 52ca06c750
commit 8599ddf51e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 30 additions and 33 deletions

View file

@ -41,7 +41,7 @@ class HomeAssistantOverkizData:
"""Overkiz data stored in the Home Assistant data object.""" """Overkiz data stored in the Home Assistant data object."""
coordinator: OverkizDataUpdateCoordinator coordinator: OverkizDataUpdateCoordinator
platforms: dict[Platform, Device | Scenario] platforms: defaultdict[Platform, list[Device | Scenario]]
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
@ -74,9 +74,6 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
raise ConfigEntryNotReady("Failed to connect") from exception raise ConfigEntryNotReady("Failed to connect") from exception
except MaintenanceException as exception: except MaintenanceException as exception:
raise ConfigEntryNotReady("Server is down for maintenance") from exception raise ConfigEntryNotReady("Server is down for maintenance") from exception
except Exception as exception: # pylint: disable=broad-except
_LOGGER.exception(exception)
return False
coordinator = OverkizDataUpdateCoordinator( coordinator = OverkizDataUpdateCoordinator(
hass, hass,
@ -98,7 +95,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
) )
coordinator.update_interval = UPDATE_INTERVAL_ALL_ASSUMED_STATE coordinator.update_interval = UPDATE_INTERVAL_ALL_ASSUMED_STATE
platforms: dict[Platform, Device | Scenario] = defaultdict(list) platforms: defaultdict[Platform, list[Device | Scenario]] = defaultdict(list)
hass.data.setdefault(DOMAIN, {})[entry.entry_id] = HomeAssistantOverkizData( hass.data.setdefault(DOMAIN, {})[entry.entry_id] = HomeAssistantOverkizData(
coordinator=coordinator, coordinator=coordinator,
@ -121,7 +118,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
hass.config_entries.async_setup_platforms(entry, PLATFORMS) hass.config_entries.async_setup_platforms(entry, PLATFORMS)
device_registry = await dr.async_get_registry(hass) device_registry = dr.async_get(hass)
for gateway in setup.gateways: for gateway in setup.gateways:
_LOGGER.debug("Added gateway (%s)", gateway) _LOGGER.debug("Added gateway (%s)", gateway)

View file

@ -46,7 +46,7 @@ async def async_setup_entry(
hass: HomeAssistant, hass: HomeAssistant,
entry: ConfigEntry, entry: ConfigEntry,
async_add_entities: AddEntitiesCallback, async_add_entities: AddEntitiesCallback,
): ) -> None:
"""Set up the Overkiz button from a config entry.""" """Set up the Overkiz button from a config entry."""
data: HomeAssistantOverkizData = hass.data[DOMAIN][entry.entry_id] data: HomeAssistantOverkizData = hass.data[DOMAIN][entry.entry_id]
entities: list[ButtonEntity] = [] entities: list[ButtonEntity] = []

View file

@ -19,6 +19,7 @@ from homeassistant import config_entries
from homeassistant.components import dhcp from homeassistant.components import dhcp
from homeassistant.const import CONF_PASSWORD, CONF_USERNAME from homeassistant.const import CONF_PASSWORD, CONF_USERNAME
from homeassistant.data_entry_flow import FlowResult from homeassistant.data_entry_flow import FlowResult
from homeassistant.helpers.aiohttp_client import async_get_clientsession
from .const import CONF_HUB, DEFAULT_HUB, DOMAIN from .const import CONF_HUB, DEFAULT_HUB, DOMAIN
@ -35,9 +36,13 @@ class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
username = user_input[CONF_USERNAME] username = user_input[CONF_USERNAME]
password = user_input[CONF_PASSWORD] password = user_input[CONF_PASSWORD]
server = SUPPORTED_SERVERS[user_input[CONF_HUB]] server = SUPPORTED_SERVERS[user_input[CONF_HUB]]
session = async_get_clientsession(self.hass)
async with OverkizClient( async with OverkizClient(
username=username, password=password, server=server username=username,
password=password,
server=server,
session=session,
) as client: ) as client:
await client.login() await client.login()

View file

@ -19,7 +19,7 @@ from pyoverkiz.exceptions import (
from pyoverkiz.models import DataType, Device, Place, State from pyoverkiz.models import DataType, Device, Place, State
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from homeassistant.helpers import device_registry from homeassistant.helpers import device_registry as dr
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
from .const import DOMAIN, UPDATE_INTERVAL from .const import DOMAIN, UPDATE_INTERVAL
@ -97,9 +97,6 @@ class OverkizDataUpdateCoordinator(DataUpdateCoordinator):
raise UpdateFailed("Too many requests, try again later.") from exception raise UpdateFailed("Too many requests, try again later.") from exception
return self.devices return self.devices
except Exception as exception:
_LOGGER.debug(exception)
raise UpdateFailed(exception) from exception
for event in events: for event in events:
_LOGGER.debug(event) _LOGGER.debug(event)
@ -123,7 +120,7 @@ class OverkizDataUpdateCoordinator(DataUpdateCoordinator):
elif event.name == EventName.DEVICE_REMOVED: elif event.name == EventName.DEVICE_REMOVED:
base_device_url, *_ = event.device_url.split("#") base_device_url, *_ = event.device_url.split("#")
registry = await device_registry.async_get_registry(self.hass) registry = dr.async_get(self.hass)
if registered_device := registry.async_get_device( if registered_device := registry.async_get_device(
{(DOMAIN, base_device_url)} {(DOMAIN, base_device_url)}
@ -176,7 +173,7 @@ class OverkizDataUpdateCoordinator(DataUpdateCoordinator):
cast_to_python = DATA_TYPE_TO_PYTHON[data_type] cast_to_python = DATA_TYPE_TO_PYTHON[data_type]
return cast_to_python(state.value) return cast_to_python(state.value)
def places_to_area(self, place): def places_to_area(self, place: Place) -> dict[str, str]:
"""Convert places with sub_places to a flat dictionary.""" """Convert places with sub_places to a flat dictionary."""
areas = {} areas = {}
if isinstance(place, Place): if isinstance(place, Place):

View file

@ -74,7 +74,7 @@ class OverkizEntity(CoordinatorEntity):
), ),
hw_version=self.device.controllable_name, hw_version=self.device.controllable_name,
suggested_area=self.coordinator.areas[self.device.place_oid], suggested_area=self.coordinator.areas[self.device.place_oid],
via_device=self.executor.get_gateway_id(), via_device=(DOMAIN, self.executor.get_gateway_id()),
configuration_url=self.coordinator.client.server.configuration_url, configuration_url=self.coordinator.client.server.configuration_url,
) )

View file

@ -37,7 +37,7 @@ class OverkizExecutor:
"""Return True if a command exists in a list of commands.""" """Return True if a command exists in a list of commands."""
return self.select_command(*commands) is not None return self.select_command(*commands) is not None
def select_state(self, *states) -> str | None: def select_state(self, *states: str) -> str | None:
"""Select first existing active state in a list of states.""" """Select first existing active state in a list of states."""
for state in states: for state in states:
if current_state := self.device.states[state]: if current_state := self.device.states[state]:
@ -49,7 +49,7 @@ class OverkizExecutor:
"""Return True if a state exists in self.""" """Return True if a state exists in self."""
return self.select_state(*states) is not None return self.select_state(*states) is not None
def select_attribute(self, *attributes) -> str | None: def select_attribute(self, *attributes: str) -> str | None:
"""Select first existing active state in a list of states.""" """Select first existing active state in a list of states."""
for attribute in attributes: for attribute in attributes:
if current_attribute := self.device.attributes[attribute]: if current_attribute := self.device.attributes[attribute]:
@ -57,7 +57,7 @@ class OverkizExecutor:
return None return None
async def async_execute_command(self, command_name: str, *args: Any): async def async_execute_command(self, command_name: str, *args: Any) -> None:
"""Execute device command in async context.""" """Execute device command in async context."""
try: try:
exec_id = await self.coordinator.client.execute_command( exec_id = await self.coordinator.client.execute_command(
@ -118,11 +118,11 @@ class OverkizExecutor:
return False return False
async def async_cancel_execution(self, exec_id: str): async def async_cancel_execution(self, exec_id: str) -> None:
"""Cancel running execution via execution id.""" """Cancel running execution via execution id."""
await self.coordinator.client.cancel_command(exec_id) await self.coordinator.client.cancel_command(exec_id)
def get_gateway_id(self): def get_gateway_id(self) -> str:
""" """
Retrieve gateway id from device url. Retrieve gateway id from device url.

View file

@ -28,7 +28,7 @@ async def async_setup_entry(
hass: HomeAssistant, hass: HomeAssistant,
entry: ConfigEntry, entry: ConfigEntry,
async_add_entities: AddEntitiesCallback, async_add_entities: AddEntitiesCallback,
): ) -> None:
"""Set up the Overkiz lights from a config entry.""" """Set up the Overkiz lights from a config entry."""
data: HomeAssistantOverkizData = hass.data[DOMAIN][entry.entry_id] data: HomeAssistantOverkizData = hass.data[DOMAIN][entry.entry_id]

View file

@ -20,7 +20,7 @@ async def async_setup_entry(
hass: HomeAssistant, hass: HomeAssistant,
entry: ConfigEntry, entry: ConfigEntry,
async_add_entities: AddEntitiesCallback, async_add_entities: AddEntitiesCallback,
): ) -> None:
"""Set up the Overkiz locks from a config entry.""" """Set up the Overkiz locks from a config entry."""
data: HomeAssistantOverkizData = hass.data[DOMAIN][entry.entry_id] data: HomeAssistantOverkizData = hass.data[DOMAIN][entry.entry_id]

View file

@ -54,7 +54,7 @@ async def async_setup_entry(
hass: HomeAssistant, hass: HomeAssistant,
entry: ConfigEntry, entry: ConfigEntry,
async_add_entities: AddEntitiesCallback, async_add_entities: AddEntitiesCallback,
): ) -> None:
"""Set up the Overkiz number from a config entry.""" """Set up the Overkiz number from a config entry."""
data: HomeAssistantOverkizData = hass.data[DOMAIN][entry.entry_id] data: HomeAssistantOverkizData = hass.data[DOMAIN][entry.entry_id]
entities: list[OverkizNumber] = [] entities: list[OverkizNumber] = []
@ -89,12 +89,12 @@ class OverkizNumber(OverkizDescriptiveEntity, NumberEntity):
entity_description: OverkizNumberDescription entity_description: OverkizNumberDescription
@property @property
def value(self) -> float: def value(self) -> float | None:
"""Return the entity value to represent the entity state.""" """Return the entity value to represent the entity state."""
if state := self.device.states.get(self.entity_description.key): if state := self.device.states.get(self.entity_description.key):
return state.value return state.value
return 0 return None
async def async_set_value(self, value: float) -> None: async def async_set_value(self, value: float) -> None:
"""Set new value.""" """Set new value."""

View file

@ -20,7 +20,7 @@ async def async_setup_entry(
hass: HomeAssistant, hass: HomeAssistant,
entry: ConfigEntry, entry: ConfigEntry,
async_add_entities: AddEntitiesCallback, async_add_entities: AddEntitiesCallback,
): ) -> None:
"""Set up the Overkiz scenes from a config entry.""" """Set up the Overkiz scenes from a config entry."""
data: HomeAssistantOverkizData = hass.data[DOMAIN][entry.entry_id] data: HomeAssistantOverkizData = hass.data[DOMAIN][entry.entry_id]

View file

@ -28,6 +28,7 @@ from homeassistant.const import (
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity import DeviceInfo, EntityCategory from homeassistant.helpers.entity import DeviceInfo, EntityCategory
from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.typing import StateType
from . import HomeAssistantOverkizData from . import HomeAssistantOverkizData
from .const import DOMAIN, IGNORED_OVERKIZ_DEVICES from .const import DOMAIN, IGNORED_OVERKIZ_DEVICES
@ -54,7 +55,6 @@ SENSOR_DESCRIPTIONS: list[OverkizSensorDescription] = [
OverkizSensorDescription( OverkizSensorDescription(
key=OverkizState.CORE_BATTERY, key=OverkizState.CORE_BATTERY,
name="Battery", name="Battery",
device_class=SensorDeviceClass.BATTERY,
native_value=lambda value: str(value).capitalize(), native_value=lambda value: str(value).capitalize(),
entity_category=EntityCategory.DIAGNOSTIC, entity_category=EntityCategory.DIAGNOSTIC,
), ),
@ -66,6 +66,7 @@ SENSOR_DESCRIPTIONS: list[OverkizSensorDescription] = [
state_class=SensorStateClass.MEASUREMENT, state_class=SensorStateClass.MEASUREMENT,
native_value=lambda value: round(float(value)), native_value=lambda value: round(float(value)),
entity_category=EntityCategory.DIAGNOSTIC, entity_category=EntityCategory.DIAGNOSTIC,
entity_registry_enabled_default=False,
), ),
OverkizSensorDescription( OverkizSensorDescription(
key=OverkizState.CORE_EXPECTED_NUMBER_OF_SHOWER, key=OverkizState.CORE_EXPECTED_NUMBER_OF_SHOWER,
@ -126,7 +127,6 @@ SENSOR_DESCRIPTIONS: list[OverkizSensorDescription] = [
OverkizSensorDescription( OverkizSensorDescription(
key=OverkizState.CORE_FOSSIL_ENERGY_CONSUMPTION, key=OverkizState.CORE_FOSSIL_ENERGY_CONSUMPTION,
name="Fossil Energy Consumption", name="Fossil Energy Consumption",
device_class=SensorDeviceClass.ENERGY,
), ),
OverkizSensorDescription( OverkizSensorDescription(
key=OverkizState.CORE_GAS_CONSUMPTION, key=OverkizState.CORE_GAS_CONSUMPTION,
@ -292,7 +292,6 @@ SENSOR_DESCRIPTIONS: list[OverkizSensorDescription] = [
key=OverkizState.CORE_SUN_ENERGY, key=OverkizState.CORE_SUN_ENERGY,
name="Sun Energy", name="Sun Energy",
native_value=lambda value: round(float(value), 2), native_value=lambda value: round(float(value), 2),
device_class=SensorDeviceClass.ENERGY,
icon="mdi:solar-power", icon="mdi:solar-power",
state_class=SensorStateClass.MEASUREMENT, state_class=SensorStateClass.MEASUREMENT,
), ),
@ -330,7 +329,6 @@ SENSOR_DESCRIPTIONS: list[OverkizSensorDescription] = [
name="Discrete RSSI Level", name="Discrete RSSI Level",
entity_registry_enabled_default=False, entity_registry_enabled_default=False,
native_value=lambda value: str(value).capitalize(), native_value=lambda value: str(value).capitalize(),
device_class=SensorDeviceClass.SIGNAL_STRENGTH,
entity_category=EntityCategory.DIAGNOSTIC, entity_category=EntityCategory.DIAGNOSTIC,
), ),
# DomesticHotWaterProduction/WaterHeatingSystem # DomesticHotWaterProduction/WaterHeatingSystem
@ -349,7 +347,7 @@ async def async_setup_entry(
hass: HomeAssistant, hass: HomeAssistant,
entry: ConfigEntry, entry: ConfigEntry,
async_add_entities: AddEntitiesCallback, async_add_entities: AddEntitiesCallback,
): ) -> None:
"""Set up the Overkiz sensors from a config entry.""" """Set up the Overkiz sensors from a config entry."""
data: HomeAssistantOverkizData = hass.data[DOMAIN][entry.entry_id] data: HomeAssistantOverkizData = hass.data[DOMAIN][entry.entry_id]
entities: list[SensorEntity] = [] entities: list[SensorEntity] = []
@ -392,7 +390,7 @@ class OverkizStateSensor(OverkizDescriptiveEntity, SensorEntity):
entity_description: OverkizSensorDescription entity_description: OverkizSensorDescription
@property @property
def native_value(self): def native_value(self) -> StateType:
"""Return the value of the sensor.""" """Return the value of the sensor."""
state = self.device.states.get(self.entity_description.key) state = self.device.states.get(self.entity_description.key)
@ -420,7 +418,7 @@ class OverkizHomeKitSetupCodeSensor(OverkizEntity, SensorEntity):
self._attr_name = "HomeKit Setup Code" self._attr_name = "HomeKit Setup Code"
@property @property
def native_value(self): def native_value(self) -> str:
"""Return the value of the sensor.""" """Return the value of the sensor."""
return self.device.attributes.get(OverkizAttribute.HOMEKIT_SETUP_CODE).value return self.device.attributes.get(OverkizAttribute.HOMEKIT_SETUP_CODE).value