Add WLED Live Override controls (#59783)

pull/60038/head
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."""
from datetime import timedelta
import logging
from typing import Final
# Integration domain
DOMAIN = "wled"
@ -30,3 +31,6 @@ ATTR_UDP_PORT = "udp_port"
# Services
SERVICE_EFFECT = "effect"
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 wled import Playlist, Preset
from wled import Live, Playlist, Preset
from homeassistant.components.select import SelectEntity
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.helpers.entity_platform import AddEntitiesCallback
from .const import DOMAIN
from .const import DEVICE_CLASS_WLED_LIVE_OVERRIDE, DOMAIN
from .coordinator import WLEDDataUpdateCoordinator
from .helpers import wled_exception_handler
from .models import WLEDEntity
@ -27,7 +27,13 @@ async def async_setup_entry(
"""Set up WLED select based on a config entry."""
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(
async_update_segments,
@ -39,6 +45,32 @@ async def async_setup_entry(
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):
"""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 mock_wled.playlist.call_count == 1
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)