Velbus code cleanup (#97584)

* Some cleanup and code improvements for the velbus integration

* Comments

* More comments

* Update homeassistant/components/velbus/entity.py

Co-authored-by: G Johansson <goran.johansson@shiftit.se>

* More comments

---------

Co-authored-by: G Johansson <goran.johansson@shiftit.se>
This commit is contained in:
Maikel Punie 2023-08-06 19:12:19 +02:00 committed by GitHub
parent 6bc5b8989d
commit 0535578440
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 52 additions and 18 deletions

View File

@ -18,10 +18,9 @@ async def async_setup_entry(
"""Set up Velbus switch based on config_entry.""" """Set up Velbus switch based on config_entry."""
await hass.data[DOMAIN][entry.entry_id]["tsk"] await hass.data[DOMAIN][entry.entry_id]["tsk"]
cntrl = hass.data[DOMAIN][entry.entry_id]["cntrl"] cntrl = hass.data[DOMAIN][entry.entry_id]["cntrl"]
entities = [] async_add_entities(
for channel in cntrl.get_all("binary_sensor"): VelbusBinarySensor(channel) for channel in cntrl.get_all("binary_sensor")
entities.append(VelbusBinarySensor(channel)) )
async_add_entities(entities)
class VelbusBinarySensor(VelbusEntity, BinarySensorEntity): class VelbusBinarySensor(VelbusEntity, BinarySensorEntity):

View File

@ -13,7 +13,7 @@ from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.entity_platform import AddEntitiesCallback
from .const import DOMAIN from .const import DOMAIN
from .entity import VelbusEntity from .entity import VelbusEntity, api_call
async def async_setup_entry( async def async_setup_entry(
@ -24,10 +24,7 @@ async def async_setup_entry(
"""Set up Velbus switch based on config_entry.""" """Set up Velbus switch based on config_entry."""
await hass.data[DOMAIN][entry.entry_id]["tsk"] await hass.data[DOMAIN][entry.entry_id]["tsk"]
cntrl = hass.data[DOMAIN][entry.entry_id]["cntrl"] cntrl = hass.data[DOMAIN][entry.entry_id]["cntrl"]
entities = [] async_add_entities(VelbusButton(channel) for channel in cntrl.get_all("button"))
for channel in cntrl.get_all("button"):
entities.append(VelbusButton(channel))
async_add_entities(entities)
class VelbusButton(VelbusEntity, ButtonEntity): class VelbusButton(VelbusEntity, ButtonEntity):
@ -37,6 +34,7 @@ class VelbusButton(VelbusEntity, ButtonEntity):
_attr_entity_registry_enabled_default = False _attr_entity_registry_enabled_default = False
_attr_entity_category = EntityCategory.CONFIG _attr_entity_category = EntityCategory.CONFIG
@api_call
async def async_press(self) -> None: async def async_press(self) -> None:
"""Handle the button press.""" """Handle the button press."""
await self._channel.press() await self._channel.press()

View File

@ -16,7 +16,7 @@ from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.entity_platform import AddEntitiesCallback
from .const import DOMAIN, PRESET_MODES from .const import DOMAIN, PRESET_MODES
from .entity import VelbusEntity from .entity import VelbusEntity, api_call
async def async_setup_entry( async def async_setup_entry(
@ -27,10 +27,7 @@ async def async_setup_entry(
"""Set up Velbus switch based on config_entry.""" """Set up Velbus switch based on config_entry."""
await hass.data[DOMAIN][entry.entry_id]["tsk"] await hass.data[DOMAIN][entry.entry_id]["tsk"]
cntrl = hass.data[DOMAIN][entry.entry_id]["cntrl"] cntrl = hass.data[DOMAIN][entry.entry_id]["cntrl"]
entities = [] async_add_entities(VelbusClimate(channel) for channel in cntrl.get_all("climate"))
for channel in cntrl.get_all("climate"):
entities.append(VelbusClimate(channel))
async_add_entities(entities)
class VelbusClimate(VelbusEntity, ClimateEntity): class VelbusClimate(VelbusEntity, ClimateEntity):
@ -67,6 +64,7 @@ class VelbusClimate(VelbusEntity, ClimateEntity):
"""Return the current temperature.""" """Return the current temperature."""
return self._channel.get_state() return self._channel.get_state()
@api_call
async def async_set_temperature(self, **kwargs: Any) -> None: async def async_set_temperature(self, **kwargs: Any) -> None:
"""Set new target temperatures.""" """Set new target temperatures."""
if (temp := kwargs.get(ATTR_TEMPERATURE)) is None: if (temp := kwargs.get(ATTR_TEMPERATURE)) is None:
@ -74,6 +72,7 @@ class VelbusClimate(VelbusEntity, ClimateEntity):
await self._channel.set_temp(temp) await self._channel.set_temp(temp)
self.async_write_ha_state() self.async_write_ha_state()
@api_call
async def async_set_preset_mode(self, preset_mode: str) -> None: async def async_set_preset_mode(self, preset_mode: str) -> None:
"""Set the new preset mode.""" """Set the new preset mode."""
await self._channel.set_preset(PRESET_MODES[preset_mode]) await self._channel.set_preset(PRESET_MODES[preset_mode])

View File

@ -15,7 +15,7 @@ from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.entity_platform import AddEntitiesCallback
from .const import DOMAIN from .const import DOMAIN
from .entity import VelbusEntity from .entity import VelbusEntity, api_call
async def async_setup_entry( async def async_setup_entry(
@ -81,18 +81,22 @@ class VelbusCover(VelbusEntity, CoverEntity):
return 100 - pos return 100 - pos
return None return None
@api_call
async def async_open_cover(self, **kwargs: Any) -> None: async def async_open_cover(self, **kwargs: Any) -> None:
"""Open the cover.""" """Open the cover."""
await self._channel.open() await self._channel.open()
@api_call
async def async_close_cover(self, **kwargs: Any) -> None: async def async_close_cover(self, **kwargs: Any) -> None:
"""Close the cover.""" """Close the cover."""
await self._channel.close() await self._channel.close()
@api_call
async def async_stop_cover(self, **kwargs: Any) -> None: async def async_stop_cover(self, **kwargs: Any) -> None:
"""Stop the cover.""" """Stop the cover."""
await self._channel.stop() await self._channel.stop()
@api_call
async def async_set_cover_position(self, **kwargs: Any) -> None: async def async_set_cover_position(self, **kwargs: Any) -> None:
"""Move the cover to a specific position.""" """Move the cover to a specific position."""
await self._channel.set_position(100 - kwargs[ATTR_POSITION]) await self._channel.set_position(100 - kwargs[ATTR_POSITION])

View File

@ -1,8 +1,13 @@
"""Support for Velbus devices.""" """Support for Velbus devices."""
from __future__ import annotations from __future__ import annotations
from collections.abc import Awaitable, Callable, Coroutine
from functools import wraps
from typing import Any, Concatenate, ParamSpec, TypeVar
from velbusaio.channels import Channel as VelbusChannel from velbusaio.channels import Channel as VelbusChannel
from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers.entity import DeviceInfo, Entity from homeassistant.helpers.entity import DeviceInfo, Entity
from .const import DOMAIN from .const import DOMAIN
@ -35,3 +40,25 @@ class VelbusEntity(Entity):
async def _on_update(self) -> None: async def _on_update(self) -> None:
self.async_write_ha_state() self.async_write_ha_state()
_T = TypeVar("_T", bound="VelbusEntity")
_P = ParamSpec("_P")
def api_call(
func: Callable[Concatenate[_T, _P], Awaitable[None]]
) -> Callable[Concatenate[_T, _P], Coroutine[Any, Any, None]]:
"""Catch command exceptions."""
@wraps(func)
async def cmd_wrapper(self: _T, *args: _P.args, **kwargs: _P.kwargs) -> None:
"""Wrap all command methods."""
try:
await func(self, *args, **kwargs)
except OSError as exc:
raise HomeAssistantError(
f"Could not execute {func.__name__} service for {self.name}"
) from exc
return cmd_wrapper

View File

@ -26,7 +26,7 @@ from homeassistant.helpers.entity import Entity
from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.entity_platform import AddEntitiesCallback
from .const import DOMAIN from .const import DOMAIN
from .entity import VelbusEntity from .entity import VelbusEntity, api_call
async def async_setup_entry( async def async_setup_entry(
@ -63,6 +63,7 @@ class VelbusLight(VelbusEntity, LightEntity):
"""Return the brightness of the light.""" """Return the brightness of the light."""
return int((self._channel.get_dimmer_state() * 255) / 100) return int((self._channel.get_dimmer_state() * 255) / 100)
@api_call
async def async_turn_on(self, **kwargs: Any) -> None: async def async_turn_on(self, **kwargs: Any) -> None:
"""Instruct the Velbus light to turn on.""" """Instruct the Velbus light to turn on."""
if ATTR_BRIGHTNESS in kwargs: if ATTR_BRIGHTNESS in kwargs:
@ -83,6 +84,7 @@ class VelbusLight(VelbusEntity, LightEntity):
) )
await getattr(self._channel, attr)(*args) await getattr(self._channel, attr)(*args)
@api_call
async def async_turn_off(self, **kwargs: Any) -> None: async def async_turn_off(self, **kwargs: Any) -> None:
"""Instruct the velbus light to turn off.""" """Instruct the velbus light to turn off."""
attr, *args = ( attr, *args = (
@ -113,6 +115,7 @@ class VelbusButtonLight(VelbusEntity, LightEntity):
"""Return true if the light is on.""" """Return true if the light is on."""
return self._channel.is_on() return self._channel.is_on()
@api_call
async def async_turn_on(self, **kwargs: Any) -> None: async def async_turn_on(self, **kwargs: Any) -> None:
"""Instruct the Velbus light to turn on.""" """Instruct the Velbus light to turn on."""
if ATTR_FLASH in kwargs: if ATTR_FLASH in kwargs:
@ -126,6 +129,7 @@ class VelbusButtonLight(VelbusEntity, LightEntity):
attr, *args = "set_led_state", "on" attr, *args = "set_led_state", "on"
await getattr(self._channel, attr)(*args) await getattr(self._channel, attr)(*args)
@api_call
async def async_turn_off(self, **kwargs: Any) -> None: async def async_turn_off(self, **kwargs: Any) -> None:
"""Instruct the velbus light to turn off.""" """Instruct the velbus light to turn off."""
attr, *args = "set_led_state", "off" attr, *args = "set_led_state", "off"

View File

@ -8,7 +8,7 @@ from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.entity_platform import AddEntitiesCallback
from .const import DOMAIN from .const import DOMAIN
from .entity import VelbusEntity from .entity import VelbusEntity, api_call
async def async_setup_entry( async def async_setup_entry(
@ -37,6 +37,7 @@ class VelbusSelect(VelbusEntity, SelectEntity):
self._attr_options = self._channel.get_options() self._attr_options = self._channel.get_options()
self._attr_unique_id = f"{self._attr_unique_id}-program_select" self._attr_unique_id = f"{self._attr_unique_id}-program_select"
@api_call
async def async_select_option(self, option: str) -> None: async def async_select_option(self, option: str) -> None:
"""Update the program on the module.""" """Update the program on the module."""
await self._channel.set_selected_program(option) await self._channel.set_selected_program(option)

View File

@ -9,7 +9,7 @@ from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.entity_platform import AddEntitiesCallback
from .const import DOMAIN from .const import DOMAIN
from .entity import VelbusEntity from .entity import VelbusEntity, api_call
async def async_setup_entry( async def async_setup_entry(
@ -36,10 +36,12 @@ class VelbusSwitch(VelbusEntity, SwitchEntity):
"""Return true if the switch is on.""" """Return true if the switch is on."""
return self._channel.is_on() return self._channel.is_on()
@api_call
async def async_turn_on(self, **kwargs: Any) -> None: async def async_turn_on(self, **kwargs: Any) -> None:
"""Instruct the switch to turn on.""" """Instruct the switch to turn on."""
await self._channel.turn_on() await self._channel.turn_on()
@api_call
async def async_turn_off(self, **kwargs: Any) -> None: async def async_turn_off(self, **kwargs: Any) -> None:
"""Instruct the switch to turn off.""" """Instruct the switch to turn off."""
await self._channel.turn_off() await self._channel.turn_off()