1
0
mirror of https://github.com/home-assistant/core.git synced 2025-12-25 05:26:47 +00:00

Fix Sonos Dialog Select type conversion part II (#152491)

Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com>
This commit is contained in:
Pete Sage
2025-09-30 14:25:19 -04:00
committed by GitHub
parent b93f4aabf1
commit dbc4a65d48
3 changed files with 66 additions and 17 deletions

View File

@@ -59,17 +59,12 @@ async def async_setup_entry(
for select_data in SELECT_TYPES:
if select_data.speaker_model == speaker.model_name.upper():
if (
state := getattr(speaker.soco, select_data.soco_attribute, None)
) is not None:
try:
setattr(speaker, select_data.speaker_attribute, int(state))
features.append(select_data)
except ValueError:
_LOGGER.error(
"Invalid value for %s %s",
select_data.speaker_attribute,
state,
)
speaker.update_soco_int_attribute(
select_data.soco_attribute, select_data.speaker_attribute
)
is not None
):
features.append(select_data)
return features
async def _async_create_entities(speaker: SonosSpeaker) -> None:
@@ -112,8 +107,9 @@ class SonosSelectEntity(SonosEntity, SelectEntity):
@soco_error()
def poll_state(self) -> None:
"""Poll the device for the current state."""
state = getattr(self.soco, self.soco_attribute)
setattr(self.speaker, self.speaker_attribute, state)
self.speaker.update_soco_int_attribute(
self.soco_attribute, self.speaker_attribute
)
@property
def current_option(self) -> str | None:

View File

@@ -275,6 +275,29 @@ class SonosSpeaker:
"""Write states for associated SonosEntity instances."""
async_dispatcher_send(self.hass, f"{SONOS_STATE_UPDATED}-{self.soco.uid}")
def update_soco_int_attribute(
self, soco_attribute: str, speaker_attribute: str
) -> int | None:
"""Update an integer attribute from SoCo and set it on the speaker.
Returns the integer value if successful, otherwise None. Do not call from
async context as it is a blocking function.
"""
value: int | None = None
if (state := getattr(self.soco, soco_attribute, None)) is None:
_LOGGER.error("Missing value for %s", speaker_attribute)
else:
try:
value = int(state)
except (TypeError, ValueError):
_LOGGER.error(
"Invalid value for %s %s",
speaker_attribute,
state,
)
setattr(self, speaker_attribute, value)
return value
#
# Properties
#

View File

@@ -88,6 +88,36 @@ async def test_select_dialog_invalid_level(
assert dialog_level_state.state == STATE_UNKNOWN
@pytest.mark.parametrize(
("value", "result"),
[
("invalid_integer", "Invalid value for dialog_level_enum invalid_integer"),
(None, "Missing value for dialog_level_enum"),
],
)
async def test_select_dialog_value_error(
hass: HomeAssistant,
async_setup_sonos,
soco,
entity_registry: er.EntityRegistry,
speaker_info: dict[str, str],
caplog: pytest.LogCaptureFixture,
value: str | None,
result: str,
) -> None:
"""Test receiving a value from Sonos that is not convertible to an integer."""
speaker_info["model_name"] = MODEL_SONOS_ARC_ULTRA.lower()
soco.get_speaker_info.return_value = speaker_info
soco.dialog_level = value
with caplog.at_level(logging.WARNING):
await async_setup_sonos()
assert result in caplog.text
assert SELECT_DIALOG_LEVEL_ENTITY not in entity_registry.entities
@pytest.mark.parametrize(
("result", "option"),
[
@@ -149,12 +179,12 @@ async def test_select_dialog_level_event(
speaker_info["model_name"] = MODEL_SONOS_ARC_ULTRA.lower()
soco.get_speaker_info.return_value = speaker_info
soco.dialog_level = 0
soco.dialog_level = "0"
await async_setup_sonos()
event = create_rendering_control_event(soco)
event.variables[ATTR_DIALOG_LEVEL] = 3
event.variables[ATTR_DIALOG_LEVEL] = "3"
soco.renderingControl.subscribe.return_value._callback(event)
await hass.async_block_till_done(wait_background_tasks=True)
@@ -175,11 +205,11 @@ async def test_select_dialog_level_poll(
speaker_info["model_name"] = MODEL_SONOS_ARC_ULTRA.lower()
soco.get_speaker_info.return_value = speaker_info
soco.dialog_level = 0
soco.dialog_level = "0"
await async_setup_sonos()
soco.dialog_level = 4
soco.dialog_level = "4"
freezer.tick(SCAN_INTERVAL)
async_fire_time_changed(hass)