Add WLED Live Override controls (#59783)

This commit is contained in:
Franck Nijhof 2021-11-20 16:15:47 +01:00 committed by GitHub
parent 1d63ae8696
commit 70990ebf81
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 145 additions and 3 deletions

View File

@ -1,6 +1,7 @@
"""Constants for the WLED integration.""" """Constants for the WLED integration."""
from datetime import timedelta from datetime import timedelta
import logging import logging
from typing import Final
# Integration domain # Integration domain
DOMAIN = "wled" DOMAIN = "wled"
@ -30,3 +31,6 @@ ATTR_UDP_PORT = "udp_port"
# Services # Services
SERVICE_EFFECT = "effect" SERVICE_EFFECT = "effect"
SERVICE_PRESET = "preset" SERVICE_PRESET = "preset"
# Device classes
DEVICE_CLASS_WLED_LIVE_OVERRIDE: Final = "wled__live_override"

View File

@ -3,7 +3,7 @@ from __future__ import annotations
from functools import partial from functools import partial
from wled import Playlist, Preset from wled import Live, Playlist, Preset
from homeassistant.components.select import SelectEntity from homeassistant.components.select import SelectEntity
from homeassistant.config_entries import ConfigEntry from homeassistant.config_entries import ConfigEntry
@ -11,7 +11,7 @@ from homeassistant.const import ENTITY_CATEGORY_CONFIG
from homeassistant.core import HomeAssistant, callback from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.entity_platform import AddEntitiesCallback
from .const import DOMAIN from .const import DEVICE_CLASS_WLED_LIVE_OVERRIDE, DOMAIN
from .coordinator import WLEDDataUpdateCoordinator from .coordinator import WLEDDataUpdateCoordinator
from .helpers import wled_exception_handler from .helpers import wled_exception_handler
from .models import WLEDEntity from .models import WLEDEntity
@ -27,7 +27,13 @@ async def async_setup_entry(
"""Set up WLED select based on a config entry.""" """Set up WLED select based on a config entry."""
coordinator: WLEDDataUpdateCoordinator = hass.data[DOMAIN][entry.entry_id] coordinator: WLEDDataUpdateCoordinator = hass.data[DOMAIN][entry.entry_id]
async_add_entities([WLEDPlaylistSelect(coordinator), WLEDPresetSelect(coordinator)]) async_add_entities(
[
WLEDLiveOverrideSelect(coordinator),
WLEDPlaylistSelect(coordinator),
WLEDPresetSelect(coordinator),
]
)
update_segments = partial( update_segments = partial(
async_update_segments, async_update_segments,
@ -39,6 +45,32 @@ async def async_setup_entry(
update_segments() update_segments()
class WLEDLiveOverrideSelect(WLEDEntity, SelectEntity):
"""Defined a WLED Live Override select."""
_attr_device_class = DEVICE_CLASS_WLED_LIVE_OVERRIDE
_attr_entity_category = ENTITY_CATEGORY_CONFIG
_attr_icon = "mdi:theater"
def __init__(self, coordinator: WLEDDataUpdateCoordinator) -> None:
"""Initialize WLED ."""
super().__init__(coordinator=coordinator)
self._attr_name = f"{coordinator.data.info.name} Live Override"
self._attr_unique_id = f"{coordinator.data.info.mac_address}_live_override"
self._attr_options = [str(live.value) for live in Live]
@property
def current_option(self) -> str:
"""Return the current selected live override."""
return str(self.coordinator.data.state.lor.value)
@wled_exception_handler
async def async_select_option(self, option: str) -> None:
"""Set WLED state to the selected live override state."""
await self.coordinator.wled.live(live=Live(int(option)))
class WLEDPresetSelect(WLEDEntity, SelectEntity): class WLEDPresetSelect(WLEDEntity, SelectEntity):
"""Defined a WLED Preset select.""" """Defined a WLED Preset select."""

View File

@ -0,0 +1,9 @@
{
"state": {
"wled__live_override": {
"0": "[%key:common::state::off%]",
"1": "[%key:common::state::on%]",
"2": "Until device restarts"
}
}
}

View File

@ -0,0 +1,9 @@
{
"state": {
"wled__live_override": {
"0": "Off",
"1": "On",
"2": "Until device restart"
}
}
}

View File

@ -451,3 +451,91 @@ async def test_playlist_select_connection_error(
assert "Error communicating with API" in caplog.text assert "Error communicating with API" in caplog.text
assert mock_wled.playlist.call_count == 1 assert mock_wled.playlist.call_count == 1
mock_wled.playlist.assert_called_with(playlist="Playlist 2") mock_wled.playlist.assert_called_with(playlist="Playlist 2")
async def test_live_override(
hass: HomeAssistant,
init_integration: MockConfigEntry,
mock_wled: MagicMock,
) -> None:
"""Test the creation and values of the WLED selects."""
entity_registry = er.async_get(hass)
state = hass.states.get("select.wled_rgb_light_live_override")
assert state
assert state.attributes.get(ATTR_ICON) == "mdi:theater"
assert state.attributes.get(ATTR_OPTIONS) == ["0", "1", "2"]
assert state.state == "0"
entry = entity_registry.async_get("select.wled_rgb_light_live_override")
assert entry
assert entry.unique_id == "aabbccddeeff_live_override"
await hass.services.async_call(
SELECT_DOMAIN,
SERVICE_SELECT_OPTION,
{
ATTR_ENTITY_ID: "select.wled_rgb_light_live_override",
ATTR_OPTION: "2",
},
blocking=True,
)
await hass.async_block_till_done()
assert mock_wled.live.call_count == 1
mock_wled.live.assert_called_with(live=2)
async def test_live_select_error(
hass: HomeAssistant,
init_integration: MockConfigEntry,
mock_wled: MagicMock,
caplog: pytest.LogCaptureFixture,
) -> None:
"""Test error handling of the WLED selects."""
mock_wled.live.side_effect = WLEDError
await hass.services.async_call(
SELECT_DOMAIN,
SERVICE_SELECT_OPTION,
{
ATTR_ENTITY_ID: "select.wled_rgb_light_live_override",
ATTR_OPTION: "1",
},
blocking=True,
)
await hass.async_block_till_done()
state = hass.states.get("select.wled_rgb_light_live_override")
assert state
assert state.state == "0"
assert "Invalid response from API" in caplog.text
assert mock_wled.live.call_count == 1
mock_wled.live.assert_called_with(live=1)
async def test_live_select_connection_error(
hass: HomeAssistant,
init_integration: MockConfigEntry,
mock_wled: MagicMock,
caplog: pytest.LogCaptureFixture,
) -> None:
"""Test error handling of the WLED selects."""
mock_wled.live.side_effect = WLEDConnectionError
await hass.services.async_call(
SELECT_DOMAIN,
SERVICE_SELECT_OPTION,
{
ATTR_ENTITY_ID: "select.wled_rgb_light_live_override",
ATTR_OPTION: "2",
},
blocking=True,
)
await hass.async_block_till_done()
state = hass.states.get("select.wled_rgb_light_live_override")
assert state
assert state.state == STATE_UNAVAILABLE
assert "Error communicating with API" in caplog.text
assert mock_wled.live.call_count == 1
mock_wled.live.assert_called_with(live=2)