Add switch to enable/disable music mode in Magic Home/flux_led (#62320)
This commit is contained in:
parent
5d5b6bef55
commit
c3a963e12a
3 changed files with 95 additions and 9 deletions
|
@ -5,6 +5,7 @@ from typing import Any
|
||||||
|
|
||||||
from flux_led import DeviceType
|
from flux_led import DeviceType
|
||||||
from flux_led.aio import AIOWifiLedBulb
|
from flux_led.aio import AIOWifiLedBulb
|
||||||
|
from flux_led.const import MODE_MUSIC
|
||||||
|
|
||||||
from homeassistant import config_entries
|
from homeassistant import config_entries
|
||||||
from homeassistant.components.switch import SwitchEntity
|
from homeassistant.components.switch import SwitchEntity
|
||||||
|
@ -22,7 +23,7 @@ from .const import (
|
||||||
)
|
)
|
||||||
from .coordinator import FluxLedUpdateCoordinator
|
from .coordinator import FluxLedUpdateCoordinator
|
||||||
from .discovery import async_clear_discovery_cache
|
from .discovery import async_clear_discovery_cache
|
||||||
from .entity import FluxBaseEntity, FluxOnOffEntity
|
from .entity import FluxBaseEntity, FluxEntity, FluxOnOffEntity
|
||||||
|
|
||||||
|
|
||||||
async def async_setup_entry(
|
async def async_setup_entry(
|
||||||
|
@ -32,20 +33,19 @@ async def async_setup_entry(
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Set up the Flux lights."""
|
"""Set up the Flux lights."""
|
||||||
coordinator: FluxLedUpdateCoordinator = hass.data[DOMAIN][entry.entry_id]
|
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:
|
if coordinator.device.device_type == DeviceType.Switch:
|
||||||
entities.append(
|
entities.append(FluxSwitch(coordinator, unique_id, name))
|
||||||
FluxSwitch(
|
|
||||||
coordinator,
|
|
||||||
entry.unique_id,
|
|
||||||
entry.data[CONF_NAME],
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
if entry.data.get(CONF_REMOTE_ACCESS_HOST):
|
if entry.data.get(CONF_REMOTE_ACCESS_HOST):
|
||||||
entities.append(FluxRemoteAccessSwitch(coordinator.device, entry))
|
entities.append(FluxRemoteAccessSwitch(coordinator.device, entry))
|
||||||
|
|
||||||
|
if coordinator.device.microphone:
|
||||||
|
entities.append(FluxMusicSwitch(coordinator, unique_id, name))
|
||||||
|
|
||||||
if entities:
|
if entities:
|
||||||
async_add_entities(entities)
|
async_add_entities(entities)
|
||||||
|
|
||||||
|
@ -107,3 +107,43 @@ class FluxRemoteAccessSwitch(FluxBaseEntity, SwitchEntity):
|
||||||
def icon(self) -> str:
|
def icon(self) -> str:
|
||||||
"""Return icon based on state."""
|
"""Return icon based on state."""
|
||||||
return "mdi:cloud-outline" if self.is_on else "mdi:cloud-off-outline"
|
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"
|
||||||
|
|
|
@ -73,6 +73,7 @@ def _mocked_bulb() -> AIOWifiLedBulb:
|
||||||
bulb.requires_turn_on = True
|
bulb.requires_turn_on = True
|
||||||
bulb.async_setup = AsyncMock(side_effect=_save_setup_callback)
|
bulb.async_setup = AsyncMock(side_effect=_save_setup_callback)
|
||||||
bulb.effect_list = ["some_effect"]
|
bulb.effect_list = ["some_effect"]
|
||||||
|
bulb.async_set_music_mode = AsyncMock()
|
||||||
bulb.async_set_custom_pattern = AsyncMock()
|
bulb.async_set_custom_pattern = AsyncMock()
|
||||||
bulb.async_set_preset_pattern = AsyncMock()
|
bulb.async_set_preset_pattern = AsyncMock()
|
||||||
bulb.async_set_effect = AsyncMock()
|
bulb.async_set_effect = AsyncMock()
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
"""Tests for switch platform."""
|
"""Tests for switch platform."""
|
||||||
|
from flux_led.const import MODE_MUSIC
|
||||||
|
|
||||||
from homeassistant.components import flux_led
|
from homeassistant.components import flux_led
|
||||||
from homeassistant.components.flux_led.const import CONF_REMOTE_ACCESS_ENABLED, DOMAIN
|
from homeassistant.components.flux_led.const import CONF_REMOTE_ACCESS_ENABLED, DOMAIN
|
||||||
from homeassistant.components.switch import DOMAIN as SWITCH_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 hass.states.get(entity_id).state == STATE_ON
|
||||||
assert config_entry.data[CONF_REMOTE_ACCESS_ENABLED] is True
|
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
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue