mirror of
https://github.com/home-assistant/core.git
synced 2026-09-24 23:41:48 -05:00
Migrate the Lyngdorf select platform to the lyngdorf 2.0 API (#180703)
This commit is contained in:
@@ -1,10 +1,10 @@
|
||||
"""Select platform for Lyngdorf integration."""
|
||||
|
||||
from collections.abc import Callable
|
||||
from collections.abc import Awaitable, Callable
|
||||
from dataclasses import dataclass
|
||||
from typing import TYPE_CHECKING, override
|
||||
|
||||
from lyngdorf.device import Receiver
|
||||
from lyngdorf import LyngdorfReceiver
|
||||
|
||||
from homeassistant.components.select import SelectEntity, SelectEntityDescription
|
||||
from homeassistant.core import HomeAssistant
|
||||
@@ -21,9 +21,10 @@ PARALLEL_UPDATES = 1
|
||||
class LyngdorfSelectEntityDescription(SelectEntityDescription):
|
||||
"""Describe a Lyngdorf select entity."""
|
||||
|
||||
current_option_fn: Callable[[Receiver], str | None]
|
||||
options_fn: Callable[[Receiver], list[str]]
|
||||
select_option_fn: Callable[[Receiver, str], None]
|
||||
current_option_fn: Callable[[LyngdorfReceiver], str | None]
|
||||
options_fn: Callable[[LyngdorfReceiver], list[str]]
|
||||
# None on the pinned library, a coroutine on 2.x: await whichever it is.
|
||||
select_option_fn: Callable[[LyngdorfReceiver, str], Awaitable[None] | None]
|
||||
|
||||
|
||||
SELECT_ENTITIES: tuple[LyngdorfSelectEntityDescription, ...] = (
|
||||
@@ -31,14 +32,14 @@ SELECT_ENTITIES: tuple[LyngdorfSelectEntityDescription, ...] = (
|
||||
key="room_perfect_position",
|
||||
translation_key="room_perfect_position",
|
||||
current_option_fn=lambda r: r.room_perfect_position,
|
||||
options_fn=lambda r: r.available_room_perfect_positions,
|
||||
options_fn=lambda r: r.room_perfect_positions,
|
||||
select_option_fn=lambda r, o: r.set_room_perfect_position(o),
|
||||
),
|
||||
LyngdorfSelectEntityDescription(
|
||||
key="voicing",
|
||||
translation_key="voicing",
|
||||
current_option_fn=lambda r: r.voicing,
|
||||
options_fn=lambda r: r.available_voicings,
|
||||
options_fn=lambda r: r.voicings,
|
||||
select_option_fn=lambda r, o: r.set_voicing(o),
|
||||
),
|
||||
)
|
||||
@@ -67,7 +68,7 @@ class LyngdorfSelect(LyngdorfEntity, SelectEntity):
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
receiver: Receiver,
|
||||
receiver: LyngdorfReceiver,
|
||||
config_entry: LyngdorfConfigEntry,
|
||||
device_info: DeviceInfo,
|
||||
description: LyngdorfSelectEntityDescription,
|
||||
@@ -94,4 +95,6 @@ class LyngdorfSelect(LyngdorfEntity, SelectEntity):
|
||||
@override
|
||||
async def async_select_option(self, option: str) -> None:
|
||||
"""Set the selected option."""
|
||||
self.entity_description.select_option_fn(self._receiver, option)
|
||||
result = self.entity_description.select_option_fn(self._receiver, option)
|
||||
if result is not None:
|
||||
await result
|
||||
|
||||
@@ -115,8 +115,13 @@ def mock_receiver(mock_create_receiver: MagicMock) -> MagicMock:
|
||||
receiver.max_volume = 0.0
|
||||
receiver.room_perfect_position = "Focus 1"
|
||||
receiver.available_room_perfect_positions = ["Global", "Focus 1"]
|
||||
receiver.room_perfect_positions = ["Global", "Focus 1"]
|
||||
receiver.voicing = "Neutral"
|
||||
receiver.available_voicings = ["Neutral", "Music", "Movie"]
|
||||
receiver.voicings = ["Neutral", "Music", "Movie"]
|
||||
# Sync on the pinned library: they return None rather than a coroutine.
|
||||
receiver.set_voicing.return_value = None
|
||||
receiver.set_room_perfect_position.return_value = None
|
||||
receiver.lipsync = None
|
||||
receiver.lipsync_range = NumericRange(0, 500, 1)
|
||||
for _t in ("bass", "treble"):
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
"""Tests for the Lyngdorf select platform."""
|
||||
|
||||
from unittest.mock import MagicMock
|
||||
from unittest.mock import AsyncMock, MagicMock
|
||||
|
||||
import pytest
|
||||
from syrupy.assertion import SnapshotAssertion
|
||||
@@ -46,7 +46,7 @@ async def test_room_perfect_select_option(
|
||||
) -> None:
|
||||
"""Test selecting a RoomPerfect position."""
|
||||
mock_receiver.room_perfect_position = "focus"
|
||||
mock_receiver.available_room_perfect_positions = ["focus", "global"]
|
||||
mock_receiver.room_perfect_positions = ["focus", "global"]
|
||||
|
||||
notify_receiver_update(mock_receiver)
|
||||
await hass.async_block_till_done()
|
||||
@@ -64,6 +64,28 @@ async def test_room_perfect_select_option(
|
||||
mock_receiver.set_room_perfect_position.assert_called_once_with("global")
|
||||
|
||||
|
||||
async def test_select_option_awaits_an_awaitable_setter(
|
||||
hass: HomeAssistant,
|
||||
init_integration: MockConfigEntry,
|
||||
mock_receiver: MagicMock,
|
||||
) -> None:
|
||||
"""Test a setter that returns a coroutine is awaited rather than dropped."""
|
||||
mock_receiver.set_voicing = AsyncMock()
|
||||
mock_receiver.voicing = "Neutral"
|
||||
mock_receiver.voicings = ["Neutral", "Music", "Movie"]
|
||||
notify_receiver_update(mock_receiver)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
await hass.services.async_call(
|
||||
SELECT_DOMAIN,
|
||||
SERVICE_SELECT_OPTION,
|
||||
{ATTR_ENTITY_ID: VOICING_ENTITY_ID, ATTR_OPTION: "Music"},
|
||||
blocking=True,
|
||||
)
|
||||
|
||||
mock_receiver.set_voicing.assert_awaited_once_with("Music")
|
||||
|
||||
|
||||
async def test_voicing_select_option(
|
||||
hass: HomeAssistant,
|
||||
init_integration: MockConfigEntry,
|
||||
@@ -71,7 +93,7 @@ async def test_voicing_select_option(
|
||||
) -> None:
|
||||
"""Test selecting a voicing."""
|
||||
mock_receiver.voicing = "Neutral"
|
||||
mock_receiver.available_voicings = ["Neutral", "Music", "Movie"]
|
||||
mock_receiver.voicings = ["Neutral", "Music", "Movie"]
|
||||
|
||||
notify_receiver_update(mock_receiver)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
Reference in New Issue
Block a user