diff --git a/homeassistant/components/flux_led/switch.py b/homeassistant/components/flux_led/switch.py index 8dc5079d7ec..37f5f057353 100644 --- a/homeassistant/components/flux_led/switch.py +++ b/homeassistant/components/flux_led/switch.py @@ -5,6 +5,7 @@ from typing import Any from flux_led import DeviceType from flux_led.aio import AIOWifiLedBulb +from flux_led.const import MODE_MUSIC from homeassistant import config_entries from homeassistant.components.switch import SwitchEntity @@ -22,7 +23,7 @@ from .const import ( ) from .coordinator import FluxLedUpdateCoordinator from .discovery import async_clear_discovery_cache -from .entity import FluxBaseEntity, FluxOnOffEntity +from .entity import FluxBaseEntity, FluxEntity, FluxOnOffEntity async def async_setup_entry( @@ -32,20 +33,19 @@ async def async_setup_entry( ) -> None: """Set up the Flux lights.""" coordinator: FluxLedUpdateCoordinator = hass.data[DOMAIN][entry.entry_id] - entities: list[FluxSwitch | FluxRemoteAccessSwitch] = [] + entities: list[FluxSwitch | FluxRemoteAccessSwitch | FluxMusicSwitch] = [] + unique_id = entry.unique_id + name = entry.data[CONF_NAME] if coordinator.device.device_type == DeviceType.Switch: - entities.append( - FluxSwitch( - coordinator, - entry.unique_id, - entry.data[CONF_NAME], - ) - ) + entities.append(FluxSwitch(coordinator, unique_id, name)) if entry.data.get(CONF_REMOTE_ACCESS_HOST): entities.append(FluxRemoteAccessSwitch(coordinator.device, entry)) + if coordinator.device.microphone: + entities.append(FluxMusicSwitch(coordinator, unique_id, name)) + if entities: async_add_entities(entities) @@ -107,3 +107,43 @@ class FluxRemoteAccessSwitch(FluxBaseEntity, SwitchEntity): def icon(self) -> str: """Return icon based on state.""" return "mdi:cloud-outline" if self.is_on else "mdi:cloud-off-outline" + + +class FluxMusicSwitch(FluxEntity, SwitchEntity): + """Representation of a Flux music switch.""" + + def __init__( + self, + coordinator: FluxLedUpdateCoordinator, + unique_id: str | None, + name: str, + ) -> None: + """Initialize the flux music switch.""" + super().__init__(coordinator, unique_id, name) + self._attr_name = f"{name} Music" + if unique_id: + self._attr_unique_id = f"{unique_id}_music" + + async def async_turn_on(self, **kwargs: Any) -> None: + """Turn the microphone on.""" + if self._device.requires_turn_on and not self._device.is_on: + await self._device.async_turn_on() + await self._device.async_set_music_mode() + self.async_write_ha_state() + await self.coordinator.async_request_refresh() + + async def async_turn_off(self, **kwargs: Any) -> None: + """Turn the microphone off.""" + await self._device.async_set_levels(*self._device.rgb, brightness=255) + self.async_write_ha_state() + await self.coordinator.async_request_refresh() + + @property + def is_on(self) -> bool: + """Return true if microphone is is on.""" + return self._device.is_on and self._device.effect == MODE_MUSIC + + @property + def icon(self) -> str: + """Return icon based on state.""" + return "mdi:microphone" if self.is_on else "mdi:microphone-off" diff --git a/tests/components/flux_led/__init__.py b/tests/components/flux_led/__init__.py index 5efeba1da94..d23c4281481 100644 --- a/tests/components/flux_led/__init__.py +++ b/tests/components/flux_led/__init__.py @@ -73,6 +73,7 @@ def _mocked_bulb() -> AIOWifiLedBulb: bulb.requires_turn_on = True bulb.async_setup = AsyncMock(side_effect=_save_setup_callback) bulb.effect_list = ["some_effect"] + bulb.async_set_music_mode = AsyncMock() bulb.async_set_custom_pattern = AsyncMock() bulb.async_set_preset_pattern = AsyncMock() bulb.async_set_effect = AsyncMock() diff --git a/tests/components/flux_led/test_switch.py b/tests/components/flux_led/test_switch.py index fbbdc76727c..ce2855a53ed 100644 --- a/tests/components/flux_led/test_switch.py +++ b/tests/components/flux_led/test_switch.py @@ -1,4 +1,6 @@ """Tests for switch platform.""" +from flux_led.const import MODE_MUSIC + from homeassistant.components import flux_led from homeassistant.components.flux_led.const import CONF_REMOTE_ACCESS_ENABLED, DOMAIN from homeassistant.components.switch import DOMAIN as SWITCH_DOMAIN @@ -95,3 +97,46 @@ async def test_remote_access_on_off(hass: HomeAssistant) -> None: assert hass.states.get(entity_id).state == STATE_ON assert config_entry.data[CONF_REMOTE_ACCESS_ENABLED] is True + + +async def test_music_mode_switch(hass: HomeAssistant) -> None: + """Test music mode switch.""" + config_entry = MockConfigEntry( + domain=DOMAIN, + data={CONF_HOST: IP_ADDRESS, CONF_NAME: DEFAULT_ENTRY_TITLE}, + unique_id=MAC_ADDRESS, + ) + config_entry.add_to_hass(hass) + bulb = _mocked_bulb() + bulb.raw_state = bulb.raw_state._replace(model_num=0xA3) # has music mode + bulb.microphone = True + with _patch_discovery(), _patch_wifibulb(device=bulb): + await async_setup_component(hass, flux_led.DOMAIN, {flux_led.DOMAIN: {}}) + await hass.async_block_till_done() + + entity_id = "switch.bulb_rgbcw_ddeeff_music" + + assert hass.states.get(entity_id).state == STATE_OFF + + bulb.effect = MODE_MUSIC + bulb.is_on = False + await hass.services.async_call( + SWITCH_DOMAIN, "turn_on", {ATTR_ENTITY_ID: entity_id}, blocking=True + ) + bulb.async_set_music_mode.assert_called_once() + assert hass.states.get(entity_id).state == STATE_OFF + + bulb.async_set_music_mode.reset_mock() + bulb.is_on = True + await hass.services.async_call( + SWITCH_DOMAIN, "turn_on", {ATTR_ENTITY_ID: entity_id}, blocking=True + ) + bulb.async_set_music_mode.assert_called_once() + assert hass.states.get(entity_id).state == STATE_ON + + bulb.effect = None + await hass.services.async_call( + SWITCH_DOMAIN, "turn_off", {ATTR_ENTITY_ID: entity_id}, blocking=True + ) + bulb.async_set_levels.assert_called_once() + assert hass.states.get(entity_id).state == STATE_OFF