diff --git a/homeassistant/components/tplink/entity.py b/homeassistant/components/tplink/entity.py index 30c0fd60add..3038e93ac25 100644 --- a/homeassistant/components/tplink/entity.py +++ b/homeassistant/components/tplink/entity.py @@ -38,13 +38,9 @@ class CoordinatedTPLinkEntity(CoordinatorEntity): """Initialize the switch.""" super().__init__(coordinator) self.device: SmartDevice = device + self._attr_name = self.device.alias self._attr_unique_id = self.device.device_id - @property - def name(self) -> str: - """Return the name of the Smart Plug.""" - return cast(str, self.device.alias) - @property def device_info(self) -> DeviceInfo: """Return information about the device.""" diff --git a/homeassistant/components/tplink/switch.py b/homeassistant/components/tplink/switch.py index f0d299e21c8..927765d15f7 100644 --- a/homeassistant/components/tplink/switch.py +++ b/homeassistant/components/tplink/switch.py @@ -8,6 +8,7 @@ from kasa import SmartDevice from homeassistant.components.switch import SwitchEntity from homeassistant.config_entries import ConfigEntry +from homeassistant.const import ENTITY_CATEGORY_CONFIG from homeassistant.core import HomeAssistant from homeassistant.helpers.entity_platform import AddEntitiesCallback @@ -29,7 +30,7 @@ async def async_setup_entry( device = coordinator.device if not device.is_plug and not device.is_strip: return - entities = [] + entities: list = [] if device.is_strip: # Historically we only add the children if the device is a strip _LOGGER.debug("Initializing strip with %s sockets", len(device.children)) @@ -38,9 +39,48 @@ async def async_setup_entry( else: entities.append(SmartPlugSwitch(device, coordinator)) + entities.append(SmartPlugLedSwitch(device, coordinator)) + async_add_entities(entities) +class SmartPlugLedSwitch(CoordinatedTPLinkEntity, SwitchEntity): + """Representation of switch for the LED of a TPLink Smart Plug.""" + + coordinator: TPLinkDataUpdateCoordinator + + _attr_entity_category = ENTITY_CATEGORY_CONFIG + + def __init__( + self, device: SmartDevice, coordinator: TPLinkDataUpdateCoordinator + ) -> None: + """Initialize the LED switch.""" + super().__init__(device, coordinator) + + self._attr_name = f"{device.alias} LED" + self._attr_unique_id = f"{self.device.mac}_led" + + @property + def icon(self) -> str: + """Return the icon for the LED.""" + return "mdi:led-on" if self.is_on else "mdi:led-off" + + @async_refresh_after + async def async_turn_on(self, **kwargs: Any) -> None: + """Turn the LED switch on.""" + await self.device.set_led(True) + + @async_refresh_after + async def async_turn_off(self, **kwargs: Any) -> None: + """Turn the LED switch off.""" + await self.device.set_led(False) + + @property + def is_on(self) -> bool: + """Return true if LED switch is on.""" + return bool(self.device.led) + + class SmartPlugSwitch(CoordinatedTPLinkEntity, SwitchEntity): """Representation of a TPLink Smart Plug switch.""" diff --git a/tests/components/tplink/__init__.py b/tests/components/tplink/__init__.py index 4e6dbb9dae7..50249f54f03 100644 --- a/tests/components/tplink/__init__.py +++ b/tests/components/tplink/__init__.py @@ -91,6 +91,7 @@ def _mocked_plug() -> SmartPlug: plug.hw_info = {"sw_ver": "1.0.0"} plug.turn_off = AsyncMock() plug.turn_on = AsyncMock() + plug.set_led = AsyncMock() plug.protocol = _mock_protocol() return plug @@ -111,6 +112,7 @@ def _mocked_strip() -> SmartStrip: strip.hw_info = {"sw_ver": "1.0.0"} strip.turn_off = AsyncMock() strip.turn_on = AsyncMock() + strip.set_led = AsyncMock() strip.protocol = _mock_protocol() plug0 = _mocked_plug() plug0.alias = "Plug0" diff --git a/tests/components/tplink/test_switch.py b/tests/components/tplink/test_switch.py index 9e7f9189aab..03dc98f9799 100644 --- a/tests/components/tplink/test_switch.py +++ b/tests/components/tplink/test_switch.py @@ -53,6 +53,38 @@ async def test_plug(hass: HomeAssistant) -> None: plug.turn_on.reset_mock() +async def test_plug_led(hass: HomeAssistant) -> None: + """Test a smart plug LED.""" + already_migrated_config_entry = MockConfigEntry( + domain=DOMAIN, data={}, unique_id=MAC_ADDRESS + ) + already_migrated_config_entry.add_to_hass(hass) + plug = _mocked_plug() + with _patch_discovery(device=plug), _patch_single_discovery(device=plug): + await async_setup_component(hass, tplink.DOMAIN, {tplink.DOMAIN: {}}) + await hass.async_block_till_done() + + entity_id = "switch.my_plug" + state = hass.states.get(entity_id) + + led_entity_id = f"{entity_id}_led" + led_state = hass.states.get(led_entity_id) + assert led_state.state == STATE_ON + assert led_state.name == f"{state.name} LED" + + await hass.services.async_call( + SWITCH_DOMAIN, "turn_off", {ATTR_ENTITY_ID: led_entity_id}, blocking=True + ) + plug.set_led.assert_called_once_with(False) + plug.set_led.reset_mock() + + await hass.services.async_call( + SWITCH_DOMAIN, "turn_on", {ATTR_ENTITY_ID: led_entity_id}, blocking=True + ) + plug.set_led.assert_called_once_with(True) + plug.set_led.reset_mock() + + async def test_plug_unique_id(hass: HomeAssistant) -> None: """Test a plug unique id.""" already_migrated_config_entry = MockConfigEntry( @@ -124,6 +156,35 @@ async def test_strip(hass: HomeAssistant) -> None: strip.children[plug_id].turn_on.reset_mock() +async def test_strip_led(hass: HomeAssistant) -> None: + """Test a smart strip LED.""" + already_migrated_config_entry = MockConfigEntry( + domain=DOMAIN, data={}, unique_id=MAC_ADDRESS + ) + already_migrated_config_entry.add_to_hass(hass) + strip = _mocked_strip() + with _patch_discovery(device=strip), _patch_single_discovery(device=strip): + await async_setup_component(hass, tplink.DOMAIN, {tplink.DOMAIN: {}}) + await hass.async_block_till_done() + + # We should have a LED entity for the strip + led_entity_id = "switch.my_strip_led" + led_state = hass.states.get(led_entity_id) + assert led_state.state == STATE_ON + + await hass.services.async_call( + SWITCH_DOMAIN, "turn_off", {ATTR_ENTITY_ID: led_entity_id}, blocking=True + ) + strip.set_led.assert_called_once_with(False) + strip.set_led.reset_mock() + + await hass.services.async_call( + SWITCH_DOMAIN, "turn_on", {ATTR_ENTITY_ID: led_entity_id}, blocking=True + ) + strip.set_led.assert_called_once_with(True) + strip.set_led.reset_mock() + + async def test_strip_unique_ids(hass: HomeAssistant) -> None: """Test a strip unique id.""" already_migrated_config_entry = MockConfigEntry(