Cleanup constants in Tradfri integration (#69125)

Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
This commit is contained in:
Patrik Lindgren 2022-04-05 14:00:45 +02:00 committed by GitHub
parent c8b4696ba2
commit 04fc3a1f25
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 70 additions and 133 deletions

View File

@ -2,7 +2,6 @@
from __future__ import annotations from __future__ import annotations
from datetime import datetime, timedelta from datetime import datetime, timedelta
import logging
from typing import Any from typing import Any
from pytradfri import Gateway, RequestError from pytradfri import Gateway, RequestError
@ -11,7 +10,7 @@ from pytradfri.command import Command
from pytradfri.device import Device from pytradfri.device import Device
from homeassistant.config_entries import ConfigEntry from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_HOST, EVENT_HOMEASSISTANT_STOP from homeassistant.const import CONF_HOST, EVENT_HOMEASSISTANT_STOP, Platform
from homeassistant.core import Event, HomeAssistant, callback from homeassistant.core import Event, HomeAssistant, callback
from homeassistant.exceptions import ConfigEntryNotReady from homeassistant.exceptions import ConfigEntryNotReady
import homeassistant.helpers.config_validation as cv import homeassistant.helpers.config_validation as cv
@ -23,28 +22,28 @@ from homeassistant.helpers.dispatcher import (
from homeassistant.helpers.event import async_track_time_interval from homeassistant.helpers.event import async_track_time_interval
from .const import ( from .const import (
ATTR_TRADFRI_GATEWAY,
ATTR_TRADFRI_GATEWAY_MODEL,
ATTR_TRADFRI_MANUFACTURER,
CONF_GATEWAY_ID, CONF_GATEWAY_ID,
CONF_IDENTITY, CONF_IDENTITY,
CONF_KEY, CONF_KEY,
COORDINATOR, COORDINATOR,
COORDINATOR_LIST, COORDINATOR_LIST,
DOMAIN, DOMAIN,
FACTORY,
KEY_API, KEY_API,
PLATFORMS, LOGGER,
SIGNAL_GW,
TIMEOUT_API,
) )
from .coordinator import TradfriDeviceDataUpdateCoordinator from .coordinator import TradfriDeviceDataUpdateCoordinator
_LOGGER = logging.getLogger(__name__)
FACTORY = "tradfri_factory"
LISTENERS = "tradfri_listeners"
CONFIG_SCHEMA = cv.removed(DOMAIN, raise_if_present=False) CONFIG_SCHEMA = cv.removed(DOMAIN, raise_if_present=False)
PLATFORMS = [
Platform.COVER,
Platform.FAN,
Platform.LIGHT,
Platform.SENSOR,
Platform.SWITCH,
]
SIGNAL_GW = "tradfri.gw_status"
TIMEOUT_API = 30
async def async_setup_entry( async def async_setup_entry(
@ -54,7 +53,6 @@ async def async_setup_entry(
"""Create a gateway.""" """Create a gateway."""
tradfri_data: dict[str, Any] = {} tradfri_data: dict[str, Any] = {}
hass.data.setdefault(DOMAIN, {})[entry.entry_id] = tradfri_data hass.data.setdefault(DOMAIN, {})[entry.entry_id] = tradfri_data
listeners = tradfri_data[LISTENERS] = []
factory = await APIFactory.init( factory = await APIFactory.init(
entry.data[CONF_HOST], entry.data[CONF_HOST],
@ -68,7 +66,9 @@ async def async_setup_entry(
await factory.shutdown() await factory.shutdown()
# Setup listeners # Setup listeners
listeners.append(hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, on_hass_stop)) entry.async_on_unload(
hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, on_hass_stop)
)
api = factory.request api = factory.request
gateway = Gateway() gateway = Gateway()
@ -89,10 +89,10 @@ async def async_setup_entry(
config_entry_id=entry.entry_id, config_entry_id=entry.entry_id,
connections=set(), connections=set(),
identifiers={(DOMAIN, entry.data[CONF_GATEWAY_ID])}, identifiers={(DOMAIN, entry.data[CONF_GATEWAY_ID])},
manufacturer=ATTR_TRADFRI_MANUFACTURER, manufacturer="IKEA of Sweden",
name=ATTR_TRADFRI_GATEWAY, name="Gateway",
# They just have 1 gateway model. Type is not exposed yet. # They just have 1 gateway model. Type is not exposed yet.
model=ATTR_TRADFRI_GATEWAY_MODEL, model="E1526",
sw_version=gateway_info.firmware_version, sw_version=gateway_info.firmware_version,
) )
@ -126,12 +126,12 @@ async def async_setup_entry(
try: try:
await api(gateway.get_gateway_info()) await api(gateway.get_gateway_info())
except RequestError: except RequestError:
_LOGGER.error("Keep-alive failed") LOGGER.error("Keep-alive failed")
gw_status = False gw_status = False
async_dispatcher_send(hass, SIGNAL_GW, gw_status) async_dispatcher_send(hass, SIGNAL_GW, gw_status)
listeners.append( entry.async_on_unload(
async_track_time_interval(hass, async_keep_alive, timedelta(seconds=60)) async_track_time_interval(hass, async_keep_alive, timedelta(seconds=60))
) )
@ -147,9 +147,6 @@ async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
tradfri_data = hass.data[DOMAIN].pop(entry.entry_id) tradfri_data = hass.data[DOMAIN].pop(entry.entry_id)
factory = tradfri_data[FACTORY] factory = tradfri_data[FACTORY]
await factory.shutdown() await factory.shutdown()
# unsubscribe listeners
for listener in tradfri_data[LISTENERS]:
listener()
return unload_ok return unload_ok

View File

@ -4,7 +4,6 @@ from __future__ import annotations
from abc import abstractmethod from abc import abstractmethod
from collections.abc import Callable from collections.abc import Callable
from functools import wraps from functools import wraps
import logging
from typing import Any, cast from typing import Any, cast
from pytradfri.command import Command from pytradfri.command import Command
@ -15,11 +14,9 @@ from homeassistant.core import callback
from homeassistant.helpers.entity import DeviceInfo from homeassistant.helpers.entity import DeviceInfo
from homeassistant.helpers.update_coordinator import CoordinatorEntity from homeassistant.helpers.update_coordinator import CoordinatorEntity
from .const import DOMAIN from .const import DOMAIN, LOGGER
from .coordinator import TradfriDeviceDataUpdateCoordinator from .coordinator import TradfriDeviceDataUpdateCoordinator
_LOGGER = logging.getLogger(__name__)
def handle_error( def handle_error(
func: Callable[[Command | list[Command]], Any] func: Callable[[Command | list[Command]], Any]
@ -32,7 +29,7 @@ def handle_error(
try: try:
await func(command) await func(command)
except RequestError as err: except RequestError as err:
_LOGGER.error("Unable to execute command %s: %s", command, err) LOGGER.error("Unable to execute command %s: %s", command, err)
return wrapper return wrapper

View File

@ -16,14 +16,10 @@ from homeassistant.const import CONF_HOST
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from homeassistant.data_entry_flow import FlowResult from homeassistant.data_entry_flow import FlowResult
from .const import ( from .const import CONF_GATEWAY_ID, CONF_IDENTITY, CONF_KEY, DOMAIN
CONF_GATEWAY_ID,
CONF_IDENTITY, CONF_IMPORT_GROUPS = "import_groups"
CONF_IMPORT_GROUPS, KEY_SECURITY_CODE = "security_code"
CONF_KEY,
DOMAIN,
KEY_SECURITY_CODE,
)
class AuthError(Exception): class AuthError(Exception):

View File

@ -1,45 +1,13 @@
"""Consts used by Tradfri.""" """Consts used by Tradfri."""
from typing import Final import logging
from homeassistant.components.light import SUPPORT_TRANSITION LOGGER = logging.getLogger(__package__)
from homeassistant.const import ( # noqa: F401 pylint: disable=unused-import
CONF_HOST,
Platform,
)
ATTR_AUTO = "Auto"
ATTR_DIMMER = "dimmer"
ATTR_HUE = "hue"
ATTR_SAT = "saturation"
ATTR_TRADFRI_GATEWAY = "Gateway"
ATTR_TRADFRI_GATEWAY_MODEL = "E1526"
ATTR_TRADFRI_MANUFACTURER = "IKEA of Sweden"
ATTR_TRANSITION_TIME = "transition_time"
ATTR_MODEL = "model"
CONF_IDENTITY = "identity"
CONF_IMPORT_GROUPS = "import_groups"
CONF_GATEWAY_ID = "gateway_id" CONF_GATEWAY_ID = "gateway_id"
CONF_IDENTITY = "identity"
CONF_KEY = "key" CONF_KEY = "key"
DOMAIN = "tradfri"
KEY_API = "tradfri_api"
DEVICES = "tradfri_devices"
SIGNAL_GW = "tradfri.gw_status"
KEY_SECURITY_CODE = "security_code"
SUPPORTED_LIGHT_FEATURES = SUPPORT_TRANSITION
PLATFORMS = [
Platform.COVER,
Platform.FAN,
Platform.LIGHT,
Platform.SENSOR,
Platform.SWITCH,
]
TIMEOUT_API = 30
ATTR_MAX_FAN_STEPS = 49
SCAN_INTERVAL = 60 # Interval for updating the coordinator
COORDINATOR = "coordinator" COORDINATOR = "coordinator"
COORDINATOR_LIST = "coordinator_list" COORDINATOR_LIST = "coordinator_list"
DOMAIN = "tradfri"
ATTR_FILTER_LIFE_REMAINING: Final = "filter_life_remaining" FACTORY = "tradfri_factory"
KEY_API = "tradfri_api"

View File

@ -3,7 +3,6 @@ from __future__ import annotations
from collections.abc import Callable from collections.abc import Callable
from datetime import timedelta from datetime import timedelta
import logging
from typing import Any from typing import Any
from pytradfri.command import Command from pytradfri.command import Command
@ -13,9 +12,9 @@ from pytradfri.error import RequestError
from homeassistant.core import HomeAssistant, callback from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
from .const import SCAN_INTERVAL from .const import LOGGER
_LOGGER = logging.getLogger(__name__) SCAN_INTERVAL = 60 # Interval for updating the coordinator
class TradfriDeviceDataUpdateCoordinator(DataUpdateCoordinator[Device]): class TradfriDeviceDataUpdateCoordinator(DataUpdateCoordinator[Device]):
@ -35,7 +34,7 @@ class TradfriDeviceDataUpdateCoordinator(DataUpdateCoordinator[Device]):
super().__init__( super().__init__(
hass, hass,
_LOGGER, LOGGER,
name=f"Update coordinator for {device}", name=f"Update coordinator for {device}",
update_interval=timedelta(seconds=SCAN_INTERVAL), update_interval=timedelta(seconds=SCAN_INTERVAL),
) )
@ -62,7 +61,7 @@ class TradfriDeviceDataUpdateCoordinator(DataUpdateCoordinator[Device]):
# Store exception so that it gets raised in _async_update_data # Store exception so that it gets raised in _async_update_data
self._exception = exc self._exception = exc
_LOGGER.debug( LOGGER.debug(
"Observation failed for %s, trying again", self.device, exc_info=exc "Observation failed for %s, trying again", self.device, exc_info=exc
) )
# Change interval so we get a swift refresh # Change interval so we get a swift refresh

View File

@ -12,14 +12,7 @@ from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.entity_platform import AddEntitiesCallback
from .base_class import TradfriBaseEntity from .base_class import TradfriBaseEntity
from .const import ( from .const import CONF_GATEWAY_ID, COORDINATOR, COORDINATOR_LIST, DOMAIN, KEY_API
ATTR_MODEL,
CONF_GATEWAY_ID,
COORDINATOR,
COORDINATOR_LIST,
DOMAIN,
KEY_API,
)
from .coordinator import TradfriDeviceDataUpdateCoordinator from .coordinator import TradfriDeviceDataUpdateCoordinator
@ -70,7 +63,7 @@ class TradfriCover(TradfriBaseEntity, CoverEntity):
@property @property
def extra_state_attributes(self) -> dict[str, str] | None: def extra_state_attributes(self) -> dict[str, str] | None:
"""Return the state attributes.""" """Return the state attributes."""
return {ATTR_MODEL: self._device.device_info.model_number} return {"model": self._device.device_info.model_number}
@property @property
def current_cover_position(self) -> int | None: def current_cover_position(self) -> int | None:

View File

@ -17,17 +17,12 @@ from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.entity_platform import AddEntitiesCallback
from .base_class import TradfriBaseEntity from .base_class import TradfriBaseEntity
from .const import ( from .const import CONF_GATEWAY_ID, COORDINATOR, COORDINATOR_LIST, DOMAIN, KEY_API
ATTR_AUTO,
ATTR_MAX_FAN_STEPS,
CONF_GATEWAY_ID,
COORDINATOR,
COORDINATOR_LIST,
DOMAIN,
KEY_API,
)
from .coordinator import TradfriDeviceDataUpdateCoordinator from .coordinator import TradfriDeviceDataUpdateCoordinator
ATTR_AUTO = "Auto"
ATTR_MAX_FAN_STEPS = 49
def _from_fan_percentage(percentage: int) -> int: def _from_fan_percentage(percentage: int) -> int:
"""Convert percent to a value that the Tradfri API understands.""" """Convert percent to a value that the Tradfri API understands."""

View File

@ -14,6 +14,7 @@ from homeassistant.components.light import (
SUPPORT_BRIGHTNESS, SUPPORT_BRIGHTNESS,
SUPPORT_COLOR, SUPPORT_COLOR,
SUPPORT_COLOR_TEMP, SUPPORT_COLOR_TEMP,
SUPPORT_TRANSITION,
LightEntity, LightEntity,
) )
from homeassistant.config_entries import ConfigEntry from homeassistant.config_entries import ConfigEntry
@ -22,20 +23,11 @@ from homeassistant.helpers.entity_platform import AddEntitiesCallback
import homeassistant.util.color as color_util import homeassistant.util.color as color_util
from .base_class import TradfriBaseEntity from .base_class import TradfriBaseEntity
from .const import ( from .const import CONF_GATEWAY_ID, COORDINATOR, COORDINATOR_LIST, DOMAIN, KEY_API
ATTR_DIMMER,
ATTR_HUE,
ATTR_SAT,
ATTR_TRANSITION_TIME,
CONF_GATEWAY_ID,
COORDINATOR,
COORDINATOR_LIST,
DOMAIN,
KEY_API,
SUPPORTED_LIGHT_FEATURES,
)
from .coordinator import TradfriDeviceDataUpdateCoordinator from .coordinator import TradfriDeviceDataUpdateCoordinator
SUPPORTED_LIGHT_FEATURES = SUPPORT_TRANSITION
async def async_setup_entry( async def async_setup_entry(
hass: HomeAssistant, hass: HomeAssistant,
@ -142,8 +134,11 @@ class TradfriLight(TradfriBaseEntity, LightEntity):
if ATTR_TRANSITION in kwargs: if ATTR_TRANSITION in kwargs:
transition_time = int(kwargs[ATTR_TRANSITION]) * 10 transition_time = int(kwargs[ATTR_TRANSITION]) * 10
dimmer_data = {ATTR_DIMMER: 0, ATTR_TRANSITION_TIME: transition_time} await self._api(
await self._api(self._device_control.set_dimmer(**dimmer_data)) self._device_control.set_dimmer(
dimmer=0, transition_time=transition_time
)
)
else: else:
await self._api(self._device_control.set_state(False)) await self._api(self._device_control.set_state(False))
@ -160,8 +155,8 @@ class TradfriLight(TradfriBaseEntity, LightEntity):
brightness = kwargs[ATTR_BRIGHTNESS] brightness = kwargs[ATTR_BRIGHTNESS]
brightness = min(brightness, 254) brightness = min(brightness, 254)
dimmer_data = { dimmer_data = {
ATTR_DIMMER: brightness, "dimmer": brightness,
ATTR_TRANSITION_TIME: transition_time, "transition_time": transition_time,
} }
dimmer_command = self._device_control.set_dimmer(**dimmer_data) dimmer_command = self._device_control.set_dimmer(**dimmer_data)
transition_time = None transition_time = None
@ -175,9 +170,9 @@ class TradfriLight(TradfriBaseEntity, LightEntity):
kwargs[ATTR_HS_COLOR][1] * (self._device_control.max_saturation / 100) kwargs[ATTR_HS_COLOR][1] * (self._device_control.max_saturation / 100)
) )
color_data = { color_data = {
ATTR_HUE: hue, "hue": hue,
ATTR_SAT: sat, "saturation": sat,
ATTR_TRANSITION_TIME: transition_time, "transition_time": transition_time,
} }
color_command = self._device_control.set_hsb(**color_data) color_command = self._device_control.set_hsb(**color_data)
transition_time = None transition_time = None
@ -195,7 +190,7 @@ class TradfriLight(TradfriBaseEntity, LightEntity):
temp = self.min_mireds temp = self.min_mireds
temp_data = { temp_data = {
ATTR_COLOR_TEMP: temp, ATTR_COLOR_TEMP: temp,
ATTR_TRANSITION_TIME: transition_time, "transition_time": transition_time,
} }
temp_command = self._device_control.set_color_temp(**temp_data) temp_command = self._device_control.set_color_temp(**temp_data)
transition_time = None transition_time = None
@ -207,9 +202,9 @@ class TradfriLight(TradfriBaseEntity, LightEntity):
hue = int(hs_color[0] * (self._device_control.max_hue / 360)) hue = int(hs_color[0] * (self._device_control.max_hue / 360))
sat = int(hs_color[1] * (self._device_control.max_saturation / 100)) sat = int(hs_color[1] * (self._device_control.max_saturation / 100))
color_data = { color_data = {
ATTR_HUE: hue, "hue": hue,
ATTR_SAT: sat, "saturation": sat,
ATTR_TRANSITION_TIME: transition_time, "transition_time": transition_time,
} }
color_command = self._device_control.set_hsb(**color_data) color_command = self._device_control.set_hsb(**color_data)
transition_time = None transition_time = None

View File

@ -3,7 +3,6 @@ from __future__ import annotations
from collections.abc import Callable from collections.abc import Callable
from dataclasses import dataclass from dataclasses import dataclass
import logging
from typing import Any, cast from typing import Any, cast
from pytradfri.command import Command from pytradfri.command import Command
@ -28,17 +27,15 @@ from homeassistant.helpers.entity_platform import AddEntitiesCallback
from .base_class import TradfriBaseEntity from .base_class import TradfriBaseEntity
from .const import ( from .const import (
ATTR_FILTER_LIFE_REMAINING,
CONF_GATEWAY_ID, CONF_GATEWAY_ID,
COORDINATOR, COORDINATOR,
COORDINATOR_LIST, COORDINATOR_LIST,
DOMAIN, DOMAIN,
KEY_API, KEY_API,
LOGGER,
) )
from .coordinator import TradfriDeviceDataUpdateCoordinator from .coordinator import TradfriDeviceDataUpdateCoordinator
_LOGGER = logging.getLogger(__name__)
@dataclass @dataclass
class TradfriSensorEntityDescriptionMixin: class TradfriSensorEntityDescriptionMixin:
@ -91,7 +88,7 @@ SENSOR_DESCRIPTIONS_FAN: tuple[TradfriSensorEntityDescription, ...] = (
value=_get_air_quality, value=_get_air_quality,
), ),
TradfriSensorEntityDescription( TradfriSensorEntityDescription(
key=ATTR_FILTER_LIFE_REMAINING, key="filter_life_remaining",
name="filter time left", name="filter time left",
state_class=SensorStateClass.MEASUREMENT, state_class=SensorStateClass.MEASUREMENT,
native_unit_of_measurement=TIME_HOURS, native_unit_of_measurement=TIME_HOURS,
@ -116,14 +113,14 @@ def _migrate_old_unique_ids(hass: HomeAssistant, old_unique_id: str, key: str) -
try: try:
ent_reg.async_update_entity(entity_id, new_unique_id=new_unique_id) ent_reg.async_update_entity(entity_id, new_unique_id=new_unique_id)
except ValueError: except ValueError:
_LOGGER.warning( LOGGER.warning(
"Skip migration of id [%s] to [%s] because it already exists", "Skip migration of id [%s] to [%s] because it already exists",
old_unique_id, old_unique_id,
new_unique_id, new_unique_id,
) )
return return
_LOGGER.debug( LOGGER.debug(
"Migrating unique_id from [%s] to [%s]", "Migrating unique_id from [%s] to [%s]",
old_unique_id, old_unique_id,
new_unique_id, new_unique_id,

View File

@ -37,9 +37,9 @@ async def test_entry_setup_unload(hass, mock_api_factory):
assert dev_entry.identifiers == { assert dev_entry.identifiers == {
(tradfri.DOMAIN, entry.data[tradfri.CONF_GATEWAY_ID]) (tradfri.DOMAIN, entry.data[tradfri.CONF_GATEWAY_ID])
} }
assert dev_entry.manufacturer == tradfri.ATTR_TRADFRI_MANUFACTURER assert dev_entry.manufacturer == "IKEA of Sweden"
assert dev_entry.name == tradfri.ATTR_TRADFRI_GATEWAY assert dev_entry.name == "Gateway"
assert dev_entry.model == tradfri.ATTR_TRADFRI_GATEWAY_MODEL assert dev_entry.model == "E1526"
with patch.object( with patch.object(
hass.config_entries, "async_forward_entry_unload", return_value=True hass.config_entries, "async_forward_entry_unload", return_value=True
@ -85,6 +85,6 @@ async def test_remove_stale_devices(hass, mock_api_factory):
assert dev_entry.identifiers == { assert dev_entry.identifiers == {
(tradfri.DOMAIN, entry.data[tradfri.CONF_GATEWAY_ID]) (tradfri.DOMAIN, entry.data[tradfri.CONF_GATEWAY_ID])
} }
assert dev_entry.manufacturer == tradfri.ATTR_TRADFRI_MANUFACTURER assert dev_entry.manufacturer == "IKEA of Sweden"
assert dev_entry.name == tradfri.ATTR_TRADFRI_GATEWAY assert dev_entry.name == "Gateway"
assert dev_entry.model == tradfri.ATTR_TRADFRI_GATEWAY_MODEL assert dev_entry.model == "E1526"