Migrate Twinkly to has entity naming (#97206)

* Migrate Twinkly to has entity naming

* Update the device name after sync

* Fix tests

---------

Co-authored-by: Franck Nijhof <git@frenck.dev>
This commit is contained in:
Joost Lekkerkerker 2024-02-14 16:43:29 +01:00 committed by GitHub
parent 538ef7764e
commit 0e833c5fe3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 27 additions and 15 deletions

View File

@ -64,6 +64,8 @@ async def async_setup_entry(
class TwinklyLight(LightEntity): class TwinklyLight(LightEntity):
"""Implementation of the light for the Twinkly service.""" """Implementation of the light for the Twinkly service."""
_attr_has_entity_name = True
_attr_name = None
_attr_icon = "mdi:string-lights" _attr_icon = "mdi:string-lights"
def __init__( def __init__(
@ -92,7 +94,7 @@ class TwinklyLight(LightEntity):
# Those are saved in the config entry in order to have meaningful values even # Those are saved in the config entry in order to have meaningful values even
# if the device is currently offline. # if the device is currently offline.
# They are expected to be updated using the device_info. # They are expected to be updated using the device_info.
self._name = conf.data[CONF_NAME] self._name = conf.data[CONF_NAME] or "Twinkly light"
self._model = conf.data[CONF_MODEL] self._model = conf.data[CONF_MODEL]
self._client = client self._client = client
@ -106,11 +108,6 @@ class TwinklyLight(LightEntity):
# We guess that most devices are "new" and support effects # We guess that most devices are "new" and support effects
self._attr_supported_features = LightEntityFeature.EFFECT self._attr_supported_features = LightEntityFeature.EFFECT
@property
def name(self) -> str:
"""Name of the device."""
return self._name if self._name else "Twinkly light"
@property @property
def device_info(self) -> DeviceInfo | None: def device_info(self) -> DeviceInfo | None:
"""Get device specific attributes.""" """Get device specific attributes."""
@ -118,7 +115,7 @@ class TwinklyLight(LightEntity):
identifiers={(DOMAIN, self._attr_unique_id)}, identifiers={(DOMAIN, self._attr_unique_id)},
manufacturer="LEDWORKS", manufacturer="LEDWORKS",
model=self._model, model=self._model,
name=self.name, name=self._name,
sw_version=self._software_version, sw_version=self._software_version,
) )
@ -271,6 +268,15 @@ class TwinklyLight(LightEntity):
}, },
) )
device_registry = dr.async_get(self.hass)
device_entry = device_registry.async_get_device(
{(DOMAIN, self._attr_unique_id)}
)
if device_entry:
device_registry.async_update_device(
device_entry.id, name=self._name, model=self._model
)
if LightEntityFeature.EFFECT & self.supported_features: if LightEntityFeature.EFFECT & self.supported_features:
await self.async_update_movies() await self.async_update_movies()
await self.async_update_current_movie() await self.async_update_current_movie()

View File

@ -1,8 +1,11 @@
"""Tests for the integration of a twinly device.""" """Tests for the integration of a twinly device."""
from __future__ import annotations from __future__ import annotations
from datetime import timedelta
from unittest.mock import patch from unittest.mock import patch
from freezegun.api import FrozenDateTimeFactory
from homeassistant.components.light import ATTR_BRIGHTNESS, LightEntityFeature from homeassistant.components.light import ATTR_BRIGHTNESS, LightEntityFeature
from homeassistant.components.twinkly.const import DOMAIN as TWINKLY_DOMAIN from homeassistant.components.twinkly.const import DOMAIN as TWINKLY_DOMAIN
from homeassistant.const import CONF_HOST, CONF_ID, CONF_MODEL, CONF_NAME from homeassistant.const import CONF_HOST, CONF_ID, CONF_MODEL, CONF_NAME
@ -13,7 +16,7 @@ from homeassistant.helpers.entity_registry import RegistryEntry
from . import TEST_MODEL, TEST_NAME, TEST_NAME_ORIGINAL, ClientMock from . import TEST_MODEL, TEST_NAME, TEST_NAME_ORIGINAL, ClientMock
from tests.common import MockConfigEntry from tests.common import MockConfigEntry, async_fire_time_changed
async def test_initial_state(hass: HomeAssistant) -> None: async def test_initial_state(hass: HomeAssistant) -> None:
@ -29,7 +32,6 @@ async def test_initial_state(hass: HomeAssistant) -> None:
assert state.attributes["friendly_name"] == TEST_NAME assert state.attributes["friendly_name"] == TEST_NAME
assert state.attributes["icon"] == "mdi:string-lights" assert state.attributes["icon"] == "mdi:string-lights"
assert entity.original_name == TEST_NAME
assert entity.original_icon == "mdi:string-lights" assert entity.original_icon == "mdi:string-lights"
assert device.name == TEST_NAME assert device.name == TEST_NAME
@ -283,7 +285,11 @@ async def test_turn_off(hass: HomeAssistant) -> None:
assert state.state == "off" assert state.state == "off"
async def test_update_name(hass: HomeAssistant) -> None: async def test_update_name(
hass: HomeAssistant,
device_registry: dr.DeviceRegistry,
freezer: FrozenDateTimeFactory,
) -> None:
"""Validate device's name update behavior. """Validate device's name update behavior.
Validate that if device name is changed from the Twinkly app, Validate that if device name is changed from the Twinkly app,
@ -293,14 +299,14 @@ async def test_update_name(hass: HomeAssistant) -> None:
entity, _, client, config_entry = await _create_entries(hass) entity, _, client, config_entry = await _create_entries(hass)
client.change_name("new_device_name") client.change_name("new_device_name")
await hass.services.async_call( freezer.tick(timedelta(seconds=30))
"light", "turn_off", service_data={"entity_id": entity.entity_id}, blocking=True async_fire_time_changed(hass)
) # We call turn_off which will automatically cause an async_update await hass.async_block_till_done()
state = hass.states.get(entity.entity_id) dev_entry = device_registry.async_get_device({(TWINKLY_DOMAIN, client.id)})
assert dev_entry.name == "new_device_name"
assert config_entry.data[CONF_NAME] == "new_device_name" assert config_entry.data[CONF_NAME] == "new_device_name"
assert state.attributes["friendly_name"] == "new_device_name"
async def test_unload(hass: HomeAssistant) -> None: async def test_unload(hass: HomeAssistant) -> None: