Optimize async executor use in ViCare integration (#104645)

* use one async executor

* use list comprehension

* simplify

* simplify

* simplify

* simplify

* simplify

* simplify

* simplify

* simplify

* add type

* Apply suggestions from code review

* fix ruff findings
This commit is contained in:
Christopher Fenner 2023-11-29 09:28:56 +01:00 committed by GitHub
parent 2663a4d617
commit c4e3ae84f4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 218 additions and 146 deletions

View File

@ -7,6 +7,9 @@ import logging
from PyViCare.PyViCareDevice import Device as PyViCareDevice from PyViCare.PyViCareDevice import Device as PyViCareDevice
from PyViCare.PyViCareDeviceConfig import PyViCareDeviceConfig from PyViCare.PyViCareDeviceConfig import PyViCareDeviceConfig
from PyViCare.PyViCareHeatingDevice import (
HeatingDeviceWithComponent as PyViCareHeatingDeviceWithComponent,
)
from PyViCare.PyViCareUtils import ( from PyViCare.PyViCareUtils import (
PyViCareInvalidDataError, PyViCareInvalidDataError,
PyViCareNotSupportedFeatureError, PyViCareNotSupportedFeatureError,
@ -104,39 +107,67 @@ GLOBAL_SENSORS: tuple[ViCareBinarySensorEntityDescription, ...] = (
) )
def _build_entity( def _build_entities(
vicare_api: PyViCareDevice, device: PyViCareDevice,
device_config: PyViCareDeviceConfig, device_config: PyViCareDeviceConfig,
entity_description: ViCareBinarySensorEntityDescription, ) -> list[ViCareBinarySensor]:
): """Create ViCare binary sensor entities for a device."""
"""Create a ViCare binary sensor entity."""
if is_supported(entity_description.key, entity_description, vicare_api): entities: list[ViCareBinarySensor] = _build_entities_for_device(
return ViCareBinarySensor( device, device_config
vicare_api,
device_config,
entity_description,
) )
return None entities.extend(
_build_entities_for_component(
get_circuits(device), device_config, CIRCUIT_SENSORS
)
)
entities.extend(
_build_entities_for_component(
get_burners(device), device_config, BURNER_SENSORS
)
)
entities.extend(
_build_entities_for_component(
get_compressors(device), device_config, COMPRESSOR_SENSORS
)
)
return entities
async def _entities_from_descriptions( def _build_entities_for_device(
hass: HomeAssistant, device: PyViCareDevice,
entities: list[ViCareBinarySensor], device_config: PyViCareDeviceConfig,
sensor_descriptions: tuple[ViCareBinarySensorEntityDescription, ...], ) -> list[ViCareBinarySensor]:
iterables, """Create device specific ViCare binary sensor entities."""
config_entry: ConfigEntry,
) -> None: return [
"""Create entities from descriptions and list of burners/circuits.""" ViCareBinarySensor(
for description in sensor_descriptions: device,
for current in iterables: device_config,
entity = await hass.async_add_executor_job(
_build_entity,
current,
hass.data[DOMAIN][config_entry.entry_id][VICARE_DEVICE_CONFIG],
description, description,
) )
if entity: for description in GLOBAL_SENSORS
entities.append(entity) if is_supported(description.key, description, device)
]
def _build_entities_for_component(
components: list[PyViCareHeatingDeviceWithComponent],
device_config: PyViCareDeviceConfig,
entity_descriptions: tuple[ViCareBinarySensorEntityDescription, ...],
) -> list[ViCareBinarySensor]:
"""Create component specific ViCare binary sensor entities."""
return [
ViCareBinarySensor(
component,
device_config,
description,
)
for component in components
for description in entity_descriptions
if is_supported(description.key, description, component)
]
async def async_setup_entry( async def async_setup_entry(
@ -146,36 +177,16 @@ async def async_setup_entry(
) -> None: ) -> None:
"""Create the ViCare binary sensor devices.""" """Create the ViCare binary sensor devices."""
api = hass.data[DOMAIN][config_entry.entry_id][VICARE_API] api = hass.data[DOMAIN][config_entry.entry_id][VICARE_API]
device_config = hass.data[DOMAIN][config_entry.entry_id][VICARE_DEVICE_CONFIG]
entities = [] async_add_entities(
await hass.async_add_executor_job(
for description in GLOBAL_SENSORS: _build_entities,
entity = await hass.async_add_executor_job(
_build_entity,
api, api,
hass.data[DOMAIN][config_entry.entry_id][VICARE_DEVICE_CONFIG], device_config,
description,
) )
if entity:
entities.append(entity)
circuits = await hass.async_add_executor_job(get_circuits, api)
await _entities_from_descriptions(
hass, entities, CIRCUIT_SENSORS, circuits, config_entry
) )
burners = await hass.async_add_executor_job(get_burners, api)
await _entities_from_descriptions(
hass, entities, BURNER_SENSORS, burners, config_entry
)
compressors = await hass.async_add_executor_job(get_compressors, api)
await _entities_from_descriptions(
hass, entities, COMPRESSOR_SENSORS, compressors, config_entry
)
async_add_entities(entities)
class ViCareBinarySensor(ViCareEntity, BinarySensorEntity): class ViCareBinarySensor(ViCareEntity, BinarySensorEntity):
"""Representation of a ViCare sensor.""" """Representation of a ViCare sensor."""

View File

@ -47,19 +47,21 @@ BUTTON_DESCRIPTIONS: tuple[ViCareButtonEntityDescription, ...] = (
) )
def _build_entity( def _build_entities(
vicare_api: PyViCareDevice, api: PyViCareDevice,
device_config: PyViCareDeviceConfig, device_config: PyViCareDeviceConfig,
entity_description: ViCareButtonEntityDescription, ) -> list[ViCareButton]:
): """Create ViCare button entities for a device."""
"""Create a ViCare button entity."""
if is_supported(entity_description.key, entity_description, vicare_api): return [
return ViCareButton( ViCareButton(
vicare_api, api,
device_config, device_config,
entity_description, description,
) )
return None for description in BUTTON_DESCRIPTIONS
if is_supported(description.key, description, api)
]
async def async_setup_entry( async def async_setup_entry(
@ -69,20 +71,15 @@ async def async_setup_entry(
) -> None: ) -> None:
"""Create the ViCare button entities.""" """Create the ViCare button entities."""
api = hass.data[DOMAIN][config_entry.entry_id][VICARE_API] api = hass.data[DOMAIN][config_entry.entry_id][VICARE_API]
device_config = hass.data[DOMAIN][config_entry.entry_id][VICARE_DEVICE_CONFIG]
entities = [] async_add_entities(
await hass.async_add_executor_job(
for description in BUTTON_DESCRIPTIONS: _build_entities,
entity = await hass.async_add_executor_job(
_build_entity,
api, api,
hass.data[DOMAIN][config_entry.entry_id][VICARE_DEVICE_CONFIG], device_config,
description, )
) )
if entity:
entities.append(entity)
async_add_entities(entities)
class ViCareButton(ViCareEntity, ButtonEntity): class ViCareButton(ViCareEntity, ButtonEntity):

View File

@ -95,25 +95,30 @@ HA_TO_VICARE_PRESET_HEATING = {
} }
def _build_entities(
api: PyViCareDevice,
device_config: PyViCareDeviceConfig,
) -> list[ViCareClimate]:
"""Create ViCare climate entities for a device."""
return [
ViCareClimate(
api,
circuit,
device_config,
"heating",
)
for circuit in get_circuits(api)
]
async def async_setup_entry( async def async_setup_entry(
hass: HomeAssistant, hass: HomeAssistant,
config_entry: ConfigEntry, config_entry: ConfigEntry,
async_add_entities: AddEntitiesCallback, async_add_entities: AddEntitiesCallback,
) -> None: ) -> None:
"""Set up the ViCare climate platform.""" """Set up the ViCare climate platform."""
entities = []
api = hass.data[DOMAIN][config_entry.entry_id][VICARE_API] api = hass.data[DOMAIN][config_entry.entry_id][VICARE_API]
device_config = hass.data[DOMAIN][config_entry.entry_id][VICARE_DEVICE_CONFIG] device_config = hass.data[DOMAIN][config_entry.entry_id][VICARE_DEVICE_CONFIG]
circuits = await hass.async_add_executor_job(get_circuits, api)
for circuit in circuits:
entity = ViCareClimate(
api,
circuit,
device_config,
"heating",
)
entities.append(entity)
platform = entity_platform.async_get_current_platform() platform = entity_platform.async_get_current_platform()
@ -123,7 +128,13 @@ async def async_setup_entry(
"set_vicare_mode", "set_vicare_mode",
) )
async_add_entities(entities) async_add_entities(
await hass.async_add_executor_job(
_build_entities,
api,
device_config,
)
)
class ViCareClimate(ViCareEntity, ClimateEntity): class ViCareClimate(ViCareEntity, ClimateEntity):

View File

@ -80,19 +80,22 @@ CIRCUIT_ENTITY_DESCRIPTIONS: tuple[ViCareNumberEntityDescription, ...] = (
) )
def _build_entity( def _build_entities(
vicare_api: PyViCareHeatingDeviceComponent, api: PyViCareDevice,
device_config: PyViCareDeviceConfig, device_config: PyViCareDeviceConfig,
entity_description: ViCareNumberEntityDescription, ) -> list[ViCareNumber]:
) -> ViCareNumber | None: """Create ViCare number entities for a component."""
"""Create a ViCare number entity."""
if is_supported(entity_description.key, entity_description, vicare_api): return [
return ViCareNumber( ViCareNumber(
vicare_api, circuit,
device_config, device_config,
entity_description, description,
) )
return None for circuit in get_circuits(api)
for description in CIRCUIT_ENTITY_DESCRIPTIONS
if is_supported(description.key, description, circuit)
]
async def async_setup_entry( async def async_setup_entry(
@ -101,23 +104,16 @@ async def async_setup_entry(
async_add_entities: AddEntitiesCallback, async_add_entities: AddEntitiesCallback,
) -> None: ) -> None:
"""Create the ViCare number devices.""" """Create the ViCare number devices."""
entities: list[ViCareNumber] = []
api = hass.data[DOMAIN][config_entry.entry_id][VICARE_API] api = hass.data[DOMAIN][config_entry.entry_id][VICARE_API]
device_config = hass.data[DOMAIN][config_entry.entry_id][VICARE_DEVICE_CONFIG] device_config = hass.data[DOMAIN][config_entry.entry_id][VICARE_DEVICE_CONFIG]
circuits = await hass.async_add_executor_job(get_circuits, api) async_add_entities(
for circuit in circuits: await hass.async_add_executor_job(
for description in CIRCUIT_ENTITY_DESCRIPTIONS: _build_entities,
entity = await hass.async_add_executor_job( api,
_build_entity,
circuit,
device_config, device_config,
description,
) )
if entity: )
entities.append(entity)
async_add_entities(entities)
class ViCareNumber(ViCareEntity, NumberEntity): class ViCareNumber(ViCareEntity, NumberEntity):

View File

@ -6,8 +6,11 @@ from contextlib import suppress
from dataclasses import dataclass from dataclasses import dataclass
import logging import logging
from PyViCare.PyViCareDevice import Device from PyViCare.PyViCareDevice import Device as PyViCareDevice
from PyViCare.PyViCareDeviceConfig import PyViCareDeviceConfig from PyViCare.PyViCareDeviceConfig import PyViCareDeviceConfig
from PyViCare.PyViCareHeatingDevice import (
HeatingDeviceWithComponent as PyViCareHeatingDeviceWithComponent,
)
from PyViCare.PyViCareUtils import ( from PyViCare.PyViCareUtils import (
PyViCareInvalidDataError, PyViCareInvalidDataError,
PyViCareNotSupportedFeatureError, PyViCareNotSupportedFeatureError,
@ -59,7 +62,7 @@ VICARE_UNIT_TO_DEVICE_CLASS = {
class ViCareSensorEntityDescription(SensorEntityDescription, ViCareRequiredKeysMixin): class ViCareSensorEntityDescription(SensorEntityDescription, ViCareRequiredKeysMixin):
"""Describes ViCare sensor entity.""" """Describes ViCare sensor entity."""
unit_getter: Callable[[Device], str | None] | None = None unit_getter: Callable[[PyViCareDevice], str | None] | None = None
GLOBAL_SENSORS: tuple[ViCareSensorEntityDescription, ...] = ( GLOBAL_SENSORS: tuple[ViCareSensorEntityDescription, ...] = (
@ -628,45 +631,86 @@ async def _entities_from_descriptions(
entities.append(entity) entities.append(entity)
def _build_entities(
device: PyViCareDevice,
device_config: PyViCareDeviceConfig,
) -> list[ViCareSensor]:
"""Create ViCare sensor entities for a device."""
entities: list[ViCareSensor] = _build_entities_for_device(device, device_config)
entities.extend(
_build_entities_for_component(
get_circuits(device), device_config, CIRCUIT_SENSORS
)
)
entities.extend(
_build_entities_for_component(
get_burners(device), device_config, BURNER_SENSORS
)
)
entities.extend(
_build_entities_for_component(
get_compressors(device), device_config, COMPRESSOR_SENSORS
)
)
return entities
def _build_entities_for_device(
device: PyViCareDevice,
device_config: PyViCareDeviceConfig,
) -> list[ViCareSensor]:
"""Create device specific ViCare sensor entities."""
return [
ViCareSensor(
device,
device_config,
description,
)
for description in GLOBAL_SENSORS
if is_supported(description.key, description, device)
]
def _build_entities_for_component(
components: list[PyViCareHeatingDeviceWithComponent],
device_config: PyViCareDeviceConfig,
entity_descriptions: tuple[ViCareSensorEntityDescription, ...],
) -> list[ViCareSensor]:
"""Create component specific ViCare sensor entities."""
return [
ViCareSensor(
component,
device_config,
description,
)
for component in components
for description in entity_descriptions
if is_supported(description.key, description, component)
]
async def async_setup_entry( async def async_setup_entry(
hass: HomeAssistant, hass: HomeAssistant,
config_entry: ConfigEntry, config_entry: ConfigEntry,
async_add_entities: AddEntitiesCallback, async_add_entities: AddEntitiesCallback,
) -> None: ) -> None:
"""Create the ViCare sensor devices.""" """Create the ViCare sensor devices."""
api: Device = hass.data[DOMAIN][config_entry.entry_id][VICARE_API] api: PyViCareDevice = hass.data[DOMAIN][config_entry.entry_id][VICARE_API]
device_config: PyViCareDeviceConfig = hass.data[DOMAIN][config_entry.entry_id][ device_config: PyViCareDeviceConfig = hass.data[DOMAIN][config_entry.entry_id][
VICARE_DEVICE_CONFIG VICARE_DEVICE_CONFIG
] ]
entities = [] async_add_entities(
for description in GLOBAL_SENSORS: await hass.async_add_executor_job(
entity = await hass.async_add_executor_job( _build_entities,
_build_entity,
api, api,
device_config, device_config,
description,
) )
if entity:
entities.append(entity)
circuits = await hass.async_add_executor_job(get_circuits, api)
await _entities_from_descriptions(
hass, entities, CIRCUIT_SENSORS, circuits, config_entry
) )
burners = await hass.async_add_executor_job(get_burners, api)
await _entities_from_descriptions(
hass, entities, BURNER_SENSORS, burners, config_entry
)
compressors = await hass.async_add_executor_job(get_compressors, api)
await _entities_from_descriptions(
hass, entities, COMPRESSOR_SENSORS, compressors, config_entry
)
async_add_entities(entities)
class ViCareSensor(ViCareEntity, SensorEntity): class ViCareSensor(ViCareEntity, SensorEntity):
"""Representation of a ViCare sensor.""" """Representation of a ViCare sensor."""

View File

@ -1,4 +1,6 @@
"""Viessmann ViCare water_heater device.""" """Viessmann ViCare water_heater device."""
from __future__ import annotations
from contextlib import suppress from contextlib import suppress
import logging import logging
from typing import Any from typing import Any
@ -58,27 +60,38 @@ HA_TO_VICARE_HVAC_DHW = {
} }
def _build_entities(
api: PyViCareDevice,
device_config: PyViCareDeviceConfig,
) -> list[ViCareWater]:
"""Create ViCare water entities for a device."""
return [
ViCareWater(
api,
circuit,
device_config,
"water",
)
for circuit in get_circuits(api)
]
async def async_setup_entry( async def async_setup_entry(
hass: HomeAssistant, hass: HomeAssistant,
config_entry: ConfigEntry, config_entry: ConfigEntry,
async_add_entities: AddEntitiesCallback, async_add_entities: AddEntitiesCallback,
) -> None: ) -> None:
"""Set up the ViCare climate platform.""" """Set up the ViCare climate platform."""
entities = []
api = hass.data[DOMAIN][config_entry.entry_id][VICARE_API] api = hass.data[DOMAIN][config_entry.entry_id][VICARE_API]
device_config = hass.data[DOMAIN][config_entry.entry_id][VICARE_DEVICE_CONFIG] device_config = hass.data[DOMAIN][config_entry.entry_id][VICARE_DEVICE_CONFIG]
circuits = await hass.async_add_executor_job(get_circuits, api)
for circuit in circuits: async_add_entities(
entity = ViCareWater( await hass.async_add_executor_job(
_build_entities,
api, api,
circuit,
device_config, device_config,
"water",
) )
entities.append(entity) )
async_add_entities(entities)
class ViCareWater(ViCareEntity, WaterHeaterEntity): class ViCareWater(ViCareEntity, WaterHeaterEntity):