diff --git a/CODEOWNERS b/CODEOWNERS index 7ddb9b7f839..5a34fab49a9 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -973,8 +973,8 @@ homeassistant/components/tuya/* @Tuya @zlinoliver @METISU @frenck tests/components/tuya/* @Tuya @zlinoliver @METISU @frenck homeassistant/components/twentemilieu/* @frenck tests/components/twentemilieu/* @frenck -homeassistant/components/twinkly/* @dr1rrb -tests/components/twinkly/* @dr1rrb +homeassistant/components/twinkly/* @dr1rrb @Robbie1221 +tests/components/twinkly/* @dr1rrb @Robbie1221 homeassistant/components/ubus/* @noltari homeassistant/components/unifi/* @Kane610 tests/components/unifi/* @Kane610 diff --git a/homeassistant/components/twinkly/__init__.py b/homeassistant/components/twinkly/__init__.py index bd9e8d85591..a8347889895 100644 --- a/homeassistant/components/twinkly/__init__.py +++ b/homeassistant/components/twinkly/__init__.py @@ -11,7 +11,7 @@ from homeassistant.core import HomeAssistant from homeassistant.exceptions import ConfigEntryNotReady from homeassistant.helpers.aiohttp_client import async_get_clientsession -from .const import CONF_ENTRY_HOST, CONF_ENTRY_ID, DATA_CLIENT, DATA_DEVICE_INFO, DOMAIN +from .const import CONF_HOST, DATA_CLIENT, DATA_DEVICE_INFO, DOMAIN PLATFORMS = [Platform.LIGHT] @@ -22,10 +22,9 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: # We setup the client here so if at some point we add any other entity for this device, # we will be able to properly share the connection. - uuid = entry.data[CONF_ENTRY_ID] - host = entry.data[CONF_ENTRY_HOST] + host = entry.data[CONF_HOST] - hass.data[DOMAIN].setdefault(uuid, {}) + hass.data[DOMAIN].setdefault(entry.entry_id, {}) client = Twinkly(host, async_get_clientsession(hass)) @@ -34,8 +33,8 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: except (asyncio.TimeoutError, ClientError) as exception: raise ConfigEntryNotReady from exception - hass.data[DOMAIN][uuid][DATA_CLIENT] = client - hass.data[DOMAIN][uuid][DATA_DEVICE_INFO] = device_info + hass.data[DOMAIN][entry.entry_id][DATA_CLIENT] = client + hass.data[DOMAIN][entry.entry_id][DATA_DEVICE_INFO] = device_info hass.config_entries.async_setup_platforms(entry, PLATFORMS) @@ -45,9 +44,8 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: """Remove a twinkly entry.""" - # For now light entries don't have unload method, so we don't have to async_forward_entry_unload - # However we still have to cleanup the shared client! - uuid = entry.data[CONF_ENTRY_ID] - hass.data[DOMAIN].pop(uuid) + unload_ok = await hass.config_entries.async_unload_platforms(entry, PLATFORMS) + if unload_ok: + hass.data[DOMAIN].pop(entry.entry_id) - return True + return unload_ok diff --git a/homeassistant/components/twinkly/config_flow.py b/homeassistant/components/twinkly/config_flow.py index 019f2d9ac53..8320e18c960 100644 --- a/homeassistant/components/twinkly/config_flow.py +++ b/homeassistant/components/twinkly/config_flow.py @@ -14,16 +14,7 @@ from homeassistant.components import dhcp from homeassistant.const import CONF_HOST from homeassistant.helpers.aiohttp_client import async_get_clientsession -from .const import ( - CONF_ENTRY_HOST, - CONF_ENTRY_ID, - CONF_ENTRY_MODEL, - CONF_ENTRY_NAME, - DEV_ID, - DEV_MODEL, - DEV_NAME, - DOMAIN, -) +from .const import CONF_ID, CONF_MODEL, CONF_NAME, DEV_ID, DEV_MODEL, DEV_NAME, DOMAIN _LOGGER = logging.getLogger(__name__) @@ -49,16 +40,14 @@ class TwinklyConfigFlow(config_entries.ConfigFlow, domain=DOMAIN): device_info = await Twinkly( host, async_get_clientsession(self.hass) ).get_details() - + except (asyncio.TimeoutError, ClientError): + errors[CONF_HOST] = "cannot_connect" + else: await self.async_set_unique_id(device_info[DEV_ID]) self._abort_if_unique_id_configured() return self._create_entry_from_device(device_info, host) - except (asyncio.TimeoutError, ClientError) as err: - _LOGGER.info("Cannot reach Twinkly '%s' (client)", host, exc_info=err) - errors[CONF_HOST] = "cannot_connect" - return self.async_show_form( step_id="user", data_schema=Schema(schema), errors=errors ) @@ -67,14 +56,12 @@ class TwinklyConfigFlow(config_entries.ConfigFlow, domain=DOMAIN): self, discovery_info: dhcp.DhcpServiceInfo ) -> data_entry_flow.FlowResult: """Handle dhcp discovery for twinkly.""" - self._async_abort_entries_match({CONF_ENTRY_HOST: discovery_info.ip}) + self._async_abort_entries_match({CONF_HOST: discovery_info.ip}) device_info = await Twinkly( discovery_info.ip, async_get_clientsession(self.hass) ).get_details() await self.async_set_unique_id(device_info[DEV_ID]) - self._abort_if_unique_id_configured( - updates={CONF_ENTRY_HOST: discovery_info.ip} - ) + self._abort_if_unique_id_configured(updates={CONF_HOST: discovery_info.ip}) self._discovered_device = (device_info, discovery_info.ip) return await self.async_step_discovery_confirm() @@ -106,9 +93,9 @@ class TwinklyConfigFlow(config_entries.ConfigFlow, domain=DOMAIN): return self.async_create_entry( title=device_info[DEV_NAME], data={ - CONF_ENTRY_HOST: host, - CONF_ENTRY_ID: device_info[DEV_ID], - CONF_ENTRY_NAME: device_info[DEV_NAME], - CONF_ENTRY_MODEL: device_info[DEV_MODEL], + CONF_HOST: host, + CONF_ID: device_info[DEV_ID], + CONF_NAME: device_info[DEV_NAME], + CONF_MODEL: device_info[DEV_MODEL], }, ) diff --git a/homeassistant/components/twinkly/const.py b/homeassistant/components/twinkly/const.py index b2754592454..c266412432b 100644 --- a/homeassistant/components/twinkly/const.py +++ b/homeassistant/components/twinkly/const.py @@ -3,10 +3,10 @@ DOMAIN = "twinkly" # Keys of the config entry -CONF_ENTRY_ID = "id" -CONF_ENTRY_HOST = "host" -CONF_ENTRY_NAME = "name" -CONF_ENTRY_MODEL = "model" +CONF_ID = "id" +CONF_HOST = "host" +CONF_NAME = "name" +CONF_MODEL = "model" # Strongly named HA attributes keys ATTR_HOST = "host" diff --git a/homeassistant/components/twinkly/light.py b/homeassistant/components/twinkly/light.py index 65592a72b60..6675461c06b 100644 --- a/homeassistant/components/twinkly/light.py +++ b/homeassistant/components/twinkly/light.py @@ -3,6 +3,7 @@ from __future__ import annotations import asyncio import logging +from typing import Any from aiohttp import ClientError from ttls.client import Twinkly @@ -22,11 +23,10 @@ from homeassistant.helpers.entity import DeviceInfo from homeassistant.helpers.entity_platform import AddEntitiesCallback from .const import ( - ATTR_HOST, - CONF_ENTRY_HOST, - CONF_ENTRY_ID, - CONF_ENTRY_MODEL, - CONF_ENTRY_NAME, + CONF_HOST, + CONF_ID, + CONF_MODEL, + CONF_NAME, DATA_CLIENT, DATA_DEVICE_INFO, DEV_LED_PROFILE, @@ -48,8 +48,8 @@ async def async_setup_entry( ) -> None: """Setups an entity from a config entry (UI config flow).""" - client = hass.data[DOMAIN][config_entry.data[CONF_ENTRY_ID]][DATA_CLIENT] - device_info = hass.data[DOMAIN][config_entry.data[CONF_ENTRY_ID]][DATA_DEVICE_INFO] + client = hass.data[DOMAIN][config_entry.entry_id][DATA_CLIENT] + device_info = hass.data[DOMAIN][config_entry.entry_id][DATA_DEVICE_INFO] entity = TwinklyLight(config_entry, client, device_info) @@ -66,7 +66,7 @@ class TwinklyLight(LightEntity): device_info, ) -> None: """Initialize a TwinklyLight entity.""" - self._id = conf.data[CONF_ENTRY_ID] + self._id = conf.data[CONF_ID] self._conf = conf if device_info.get(DEV_LED_PROFILE) == DEV_PROFILE_RGBW: @@ -84,20 +84,15 @@ class TwinklyLight(LightEntity): # Those are saved in the config entry in order to have meaningful values even # if the device is currently offline. # They are expected to be updated using the device_info. - self.__name = conf.data[CONF_ENTRY_NAME] - self.__model = conf.data[CONF_ENTRY_MODEL] + self._name = conf.data[CONF_NAME] + self._model = conf.data[CONF_MODEL] self._client = client # Set default state before any update self._is_on = False self._is_available = False - self._attributes = {ATTR_HOST: self._client.host} - - @property - def should_poll(self) -> bool: - """Get a boolean which indicates if this entity should be polled.""" - return True + self._attributes: dict[Any, Any] = {} @property def available(self) -> bool: @@ -112,12 +107,12 @@ class TwinklyLight(LightEntity): @property def name(self) -> str: """Name of the device.""" - return self.__name if self.__name else "Twinkly light" + return self._name if self._name else "Twinkly light" @property def model(self) -> str: """Name of the device.""" - return self.__model + return self._model @property def icon(self) -> str: @@ -127,15 +122,11 @@ class TwinklyLight(LightEntity): @property def device_info(self) -> DeviceInfo | None: """Get device specific attributes.""" - return ( - DeviceInfo( - identifiers={(DOMAIN, self._id)}, - manufacturer="LEDWORKS", - model=self.model, - name=self.name, - ) - if self._id - else None # device_info is available only for entities configured from the UI + return DeviceInfo( + identifiers={(DOMAIN, self._id)}, + manufacturer="LEDWORKS", + model=self.model, + name=self.name, ) @property @@ -149,10 +140,6 @@ class TwinklyLight(LightEntity): attributes = self._attributes - # Make sure to update any normalized property - attributes[ATTR_HOST] = self._client.host - attributes[ATTR_BRIGHTNESS] = self._attr_brightness - return attributes async def async_turn_on(self, **kwargs) -> None: @@ -204,7 +191,7 @@ class TwinklyLight(LightEntity): async def async_update(self) -> None: """Asynchronously updates the device properties.""" - _LOGGER.info("Updating '%s'", self._client.host) + _LOGGER.debug("Updating '%s'", self._client.host) try: self._is_on = await self._client.is_on() @@ -224,25 +211,24 @@ class TwinklyLight(LightEntity): DEV_NAME in device_info and DEV_MODEL in device_info and ( - device_info[DEV_NAME] != self.__name - or device_info[DEV_MODEL] != self.__model + device_info[DEV_NAME] != self._name + or device_info[DEV_MODEL] != self._model ) ): - self.__name = device_info[DEV_NAME] - self.__model = device_info[DEV_MODEL] + self._name = device_info[DEV_NAME] + self._model = device_info[DEV_MODEL] - if self._conf is not None: - # If the name has changed, persist it in conf entry, - # so we will be able to restore this new name if hass is started while the LED string is offline. - self.hass.config_entries.async_update_entry( - self._conf, - data={ - CONF_ENTRY_HOST: self._client.host, # this cannot change - CONF_ENTRY_ID: self._id, # this cannot change - CONF_ENTRY_NAME: self.__name, - CONF_ENTRY_MODEL: self.__model, - }, - ) + # If the name has changed, persist it in conf entry, + # so we will be able to restore this new name if hass is started while the LED string is offline. + self.hass.config_entries.async_update_entry( + self._conf, + data={ + CONF_HOST: self._client.host, # this cannot change + CONF_ID: self._id, # this cannot change + CONF_NAME: self._name, + CONF_MODEL: self._model, + }, + ) for key, value in device_info.items(): if key not in HIDDEN_DEV_VALUES: diff --git a/homeassistant/components/twinkly/manifest.json b/homeassistant/components/twinkly/manifest.json index bde8e799a55..c78f5152f13 100644 --- a/homeassistant/components/twinkly/manifest.json +++ b/homeassistant/components/twinkly/manifest.json @@ -3,8 +3,7 @@ "name": "Twinkly", "documentation": "https://www.home-assistant.io/integrations/twinkly", "requirements": ["ttls==1.4.2"], - "dependencies": [], - "codeowners": ["@dr1rrb"], + "codeowners": ["@dr1rrb", "@Robbie1221"], "config_flow": true, "dhcp": [{ "hostname": "twinkly_*" }], "iot_class": "local_polling" diff --git a/homeassistant/components/twinkly/strings.json b/homeassistant/components/twinkly/strings.json index bda6cdee519..6dc7cc2eb97 100644 --- a/homeassistant/components/twinkly/strings.json +++ b/homeassistant/components/twinkly/strings.json @@ -5,7 +5,7 @@ "title": "Twinkly", "description": "Set up your Twinkly led string", "data": { - "host": "Host (or IP address) of your twinkly device" + "host": "[%key:common::config_flow::data::host%]" } }, "discovery_confirm": { diff --git a/tests/components/twinkly/test_config_flow.py b/tests/components/twinkly/test_config_flow.py index 02a2831d25d..e29bd1c3fc1 100644 --- a/tests/components/twinkly/test_config_flow.py +++ b/tests/components/twinkly/test_config_flow.py @@ -4,10 +4,10 @@ from unittest.mock import patch from homeassistant import config_entries from homeassistant.components import dhcp from homeassistant.components.twinkly.const import ( - CONF_ENTRY_HOST, - CONF_ENTRY_ID, - CONF_ENTRY_MODEL, - CONF_ENTRY_NAME, + CONF_HOST, + CONF_ID, + CONF_MODEL, + CONF_NAME, DOMAIN as TWINKLY_DOMAIN, ) @@ -31,12 +31,12 @@ async def test_invalid_host(hass): assert result["errors"] == {} result = await hass.config_entries.flow.async_configure( result["flow_id"], - {CONF_ENTRY_HOST: "dummy"}, + {CONF_HOST: "dummy"}, ) assert result["type"] == "form" assert result["step_id"] == "user" - assert result["errors"] == {CONF_ENTRY_HOST: "cannot_connect"} + assert result["errors"] == {CONF_HOST: "cannot_connect"} async def test_success_flow(hass): @@ -55,16 +55,16 @@ async def test_success_flow(hass): result = await hass.config_entries.flow.async_configure( result["flow_id"], - {CONF_ENTRY_HOST: "dummy"}, + {CONF_HOST: "dummy"}, ) assert result["type"] == "create_entry" assert result["title"] == client.id assert result["data"] == { - CONF_ENTRY_HOST: "dummy", - CONF_ENTRY_ID: client.id, - CONF_ENTRY_NAME: client.id, - CONF_ENTRY_MODEL: TEST_MODEL, + CONF_HOST: "dummy", + CONF_ID: client.id, + CONF_NAME: client.id, + CONF_MODEL: TEST_MODEL, } @@ -114,10 +114,10 @@ async def test_dhcp_success(hass): assert result["type"] == "create_entry" assert result["title"] == client.id assert result["data"] == { - CONF_ENTRY_HOST: "1.2.3.4", - CONF_ENTRY_ID: client.id, - CONF_ENTRY_NAME: client.id, - CONF_ENTRY_MODEL: TEST_MODEL, + CONF_HOST: "1.2.3.4", + CONF_ID: client.id, + CONF_NAME: client.id, + CONF_MODEL: TEST_MODEL, } @@ -128,10 +128,10 @@ async def test_dhcp_already_exists(hass): entry = MockConfigEntry( domain=TWINKLY_DOMAIN, data={ - CONF_ENTRY_HOST: "1.2.3.4", - CONF_ENTRY_ID: client.id, - CONF_ENTRY_NAME: client.id, - CONF_ENTRY_MODEL: TEST_MODEL, + CONF_HOST: "1.2.3.4", + CONF_ID: client.id, + CONF_NAME: client.id, + CONF_MODEL: TEST_MODEL, }, unique_id=client.id, ) diff --git a/tests/components/twinkly/test_init.py b/tests/components/twinkly/test_init.py index 415b897f488..573bf5fbc86 100644 --- a/tests/components/twinkly/test_init.py +++ b/tests/components/twinkly/test_init.py @@ -3,12 +3,11 @@ from unittest.mock import patch from uuid import uuid4 -from homeassistant.components.twinkly import async_setup_entry, async_unload_entry from homeassistant.components.twinkly.const import ( - CONF_ENTRY_HOST, - CONF_ENTRY_ID, - CONF_ENTRY_MODEL, - CONF_ENTRY_NAME, + CONF_HOST, + CONF_ID, + CONF_MODEL, + CONF_NAME, DOMAIN as TWINKLY_DOMAIN, ) from homeassistant.config_entries import ConfigEntryState @@ -23,7 +22,7 @@ from tests.components.twinkly import ( ) -async def test_setup_entry(hass: HomeAssistant): +async def test_load_unload_entry(hass: HomeAssistant): """Validate that setup entry also configure the client.""" client = ClientMock() @@ -31,47 +30,24 @@ async def test_setup_entry(hass: HomeAssistant): config_entry = MockConfigEntry( domain=TWINKLY_DOMAIN, data={ - CONF_ENTRY_HOST: TEST_HOST, - CONF_ENTRY_ID: id, - CONF_ENTRY_NAME: TEST_NAME_ORIGINAL, - CONF_ENTRY_MODEL: TEST_MODEL, + CONF_HOST: TEST_HOST, + CONF_ID: id, + CONF_NAME: TEST_NAME_ORIGINAL, + CONF_MODEL: TEST_MODEL, }, entry_id=id, ) - def setup_mock(_, __): - return True + config_entry.add_to_hass(hass) - with patch( - "homeassistant.config_entries.ConfigEntries.async_forward_entry_setup", - side_effect=setup_mock, - ), patch("homeassistant.components.twinkly.Twinkly", return_value=client): - await async_setup_entry(hass, config_entry) + with patch("homeassistant.components.twinkly.Twinkly", return_value=client): + await hass.config_entries.async_setup(config_entry.entry_id) - assert hass.data[TWINKLY_DOMAIN][id] is not None + assert config_entry.state == ConfigEntryState.LOADED + await hass.config_entries.async_unload(config_entry.entry_id) -async def test_unload_entry(hass: HomeAssistant): - """Validate that unload entry also clear the client.""" - - id = str(uuid4()) - config_entry = MockConfigEntry( - domain=TWINKLY_DOMAIN, - data={ - CONF_ENTRY_HOST: TEST_HOST, - CONF_ENTRY_ID: id, - CONF_ENTRY_NAME: TEST_NAME_ORIGINAL, - CONF_ENTRY_MODEL: TEST_MODEL, - }, - entry_id=id, - ) - - # Put random content at the location where the client should have been placed by setup - hass.data.setdefault(TWINKLY_DOMAIN, {})[id] = config_entry - - await async_unload_entry(hass, config_entry) - - assert hass.data[TWINKLY_DOMAIN].get(id) is None + assert config_entry.state == ConfigEntryState.NOT_LOADED async def test_config_entry_not_ready(hass: HomeAssistant): @@ -82,10 +58,10 @@ async def test_config_entry_not_ready(hass: HomeAssistant): config_entry = MockConfigEntry( domain=TWINKLY_DOMAIN, data={ - CONF_ENTRY_HOST: TEST_HOST, - CONF_ENTRY_ID: id, - CONF_ENTRY_NAME: TEST_NAME_ORIGINAL, - CONF_ENTRY_MODEL: TEST_MODEL, + CONF_HOST: TEST_HOST, + CONF_ID: id, + CONF_NAME: TEST_NAME_ORIGINAL, + CONF_MODEL: TEST_MODEL, }, ) diff --git a/tests/components/twinkly/test_twinkly.py b/tests/components/twinkly/test_light.py similarity index 79% rename from tests/components/twinkly/test_twinkly.py rename to tests/components/twinkly/test_light.py index c1e12523865..7072d7c2eec 100644 --- a/tests/components/twinkly/test_twinkly.py +++ b/tests/components/twinkly/test_light.py @@ -3,11 +3,12 @@ from __future__ import annotations from unittest.mock import patch +from homeassistant.components.light import ATTR_BRIGHTNESS from homeassistant.components.twinkly.const import ( - CONF_ENTRY_HOST, - CONF_ENTRY_ID, - CONF_ENTRY_MODEL, - CONF_ENTRY_NAME, + CONF_HOST, + CONF_ID, + CONF_MODEL, + CONF_NAME, DOMAIN as TWINKLY_DOMAIN, ) from homeassistant.core import HomeAssistant @@ -16,25 +17,19 @@ from homeassistant.helpers.device_registry import DeviceEntry from homeassistant.helpers.entity_registry import RegistryEntry from tests.common import MockConfigEntry -from tests.components.twinkly import ( - TEST_HOST, - TEST_MODEL, - TEST_NAME_ORIGINAL, - ClientMock, -) +from tests.components.twinkly import TEST_MODEL, TEST_NAME_ORIGINAL, ClientMock async def test_initial_state(hass: HomeAssistant): """Validate that entity and device states are updated on startup.""" - entity, device, _ = await _create_entries(hass) + entity, device, _, _ = await _create_entries(hass) state = hass.states.get(entity.entity_id) # Basic state properties assert state.name == entity.unique_id assert state.state == "on" - assert state.attributes["host"] == TEST_HOST - assert state.attributes["brightness"] == 26 + assert state.attributes[ATTR_BRIGHTNESS] == 26 assert state.attributes["friendly_name"] == entity.unique_id assert state.attributes["icon"] == "mdi:string-lights" @@ -54,7 +49,7 @@ async def test_turn_on_off(hass: HomeAssistant): client = ClientMock() client.state = False client.brightness = {"mode": "enabled", "value": 20} - entity, _, _ = await _create_entries(hass, client) + entity, _, _, _ = await _create_entries(hass, client) assert hass.states.get(entity.entity_id).state == "off" @@ -66,7 +61,7 @@ async def test_turn_on_off(hass: HomeAssistant): state = hass.states.get(entity.entity_id) assert state.state == "on" - assert state.attributes["brightness"] == 51 + assert state.attributes[ATTR_BRIGHTNESS] == 51 async def test_turn_on_with_brightness(hass: HomeAssistant): @@ -74,7 +69,7 @@ async def test_turn_on_with_brightness(hass: HomeAssistant): client = ClientMock() client.state = False client.brightness = {"mode": "enabled", "value": 20} - entity, _, _ = await _create_entries(hass, client) + entity, _, _, _ = await _create_entries(hass, client) assert hass.states.get(entity.entity_id).state == "off" @@ -88,7 +83,7 @@ async def test_turn_on_with_brightness(hass: HomeAssistant): state = hass.states.get(entity.entity_id) assert state.state == "on" - assert state.attributes["brightness"] == 255 + assert state.attributes[ATTR_BRIGHTNESS] == 255 await hass.services.async_call( "light", @@ -100,7 +95,6 @@ async def test_turn_on_with_brightness(hass: HomeAssistant): state = hass.states.get(entity.entity_id) assert state.state == "off" - assert state.attributes["brightness"] == 0 async def test_turn_on_with_color_rgbw(hass: HomeAssistant): @@ -109,7 +103,7 @@ async def test_turn_on_with_color_rgbw(hass: HomeAssistant): client.state = False client.device_info["led_profile"] = "RGBW" client.brightness = {"mode": "enabled", "value": 255} - entity, _, _ = await _create_entries(hass, client) + entity, _, _, _ = await _create_entries(hass, client) assert hass.states.get(entity.entity_id).state == "off" @@ -132,7 +126,7 @@ async def test_turn_on_with_color_rgb(hass: HomeAssistant): client.state = False client.device_info["led_profile"] = "RGB" client.brightness = {"mode": "enabled", "value": 255} - entity, _, _ = await _create_entries(hass, client) + entity, _, _, _ = await _create_entries(hass, client) assert hass.states.get(entity.entity_id).state == "off" @@ -151,7 +145,7 @@ async def test_turn_on_with_color_rgb(hass: HomeAssistant): async def test_turn_off(hass: HomeAssistant): """Test support of the light.turn_off service.""" - entity, _, _ = await _create_entries(hass) + entity, _, _, _ = await _create_entries(hass) assert hass.states.get(entity.entity_id).state == "on" @@ -163,7 +157,6 @@ async def test_turn_off(hass: HomeAssistant): state = hass.states.get(entity.entity_id) assert state.state == "off" - assert state.attributes["brightness"] == 0 async def test_update_name(hass: HomeAssistant): @@ -174,15 +167,7 @@ async def test_update_name(hass: HomeAssistant): then the name of the entity is updated and it's also persisted, so it can be restored when starting HA while Twinkly is offline. """ - entity, _, client = await _create_entries(hass) - - updated_config_entry = None - - async def on_update(ha, co): - nonlocal updated_config_entry - updated_config_entry = co - - hass.config_entries.async_get_entry(entity.unique_id).add_update_listener(on_update) + entity, _, client, config_entry = await _create_entries(hass) client.change_name("new_device_name") await hass.services.async_call( @@ -192,15 +177,14 @@ async def test_update_name(hass: HomeAssistant): state = hass.states.get(entity.entity_id) - assert updated_config_entry is not None - assert updated_config_entry.data[CONF_ENTRY_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): """Validate that entities can be unloaded from the UI.""" - _, _, client = await _create_entries(hass) + _, _, client, _ = await _create_entries(hass) entry_id = client.id assert await hass.config_entries.async_unload(entry_id) @@ -215,10 +199,10 @@ async def _create_entries( config_entry = MockConfigEntry( domain=TWINKLY_DOMAIN, data={ - CONF_ENTRY_HOST: client, - CONF_ENTRY_ID: client.id, - CONF_ENTRY_NAME: TEST_NAME_ORIGINAL, - CONF_ENTRY_MODEL: TEST_MODEL, + CONF_HOST: client, + CONF_ID: client.id, + CONF_NAME: TEST_NAME_ORIGINAL, + CONF_MODEL: TEST_MODEL, }, entry_id=client.id, ) @@ -230,10 +214,10 @@ async def _create_entries( entity_registry = er.async_get(hass) entity_id = entity_registry.async_get_entity_id("light", TWINKLY_DOMAIN, client.id) - entity = entity_registry.async_get(entity_id) + entity_entry = entity_registry.async_get(entity_id) device = device_registry.async_get_device({(TWINKLY_DOMAIN, client.id)}) - assert entity is not None + assert entity_entry is not None assert device is not None - return entity, device, client + return entity_entry, device, client, config_entry