mirror of
https://github.com/home-assistant/core.git
synced 2025-07-19 03:07:37 +00:00
Fix Sonos going offline with 13.3 firmware (#56590)
This commit is contained in:
parent
915afedcfc
commit
0363c22dd8
@ -90,6 +90,7 @@ class SonosData:
|
|||||||
self.discovery_ignored: set[str] = set()
|
self.discovery_ignored: set[str] = set()
|
||||||
self.discovery_known: set[str] = set()
|
self.discovery_known: set[str] = set()
|
||||||
self.boot_counts: dict[str, int] = {}
|
self.boot_counts: dict[str, int] = {}
|
||||||
|
self.mdns_names: dict[str, str] = {}
|
||||||
|
|
||||||
|
|
||||||
async def async_setup(hass, config):
|
async def async_setup(hass, config):
|
||||||
@ -273,12 +274,12 @@ class SonosDiscoveryManager:
|
|||||||
if uid.startswith("uuid:"):
|
if uid.startswith("uuid:"):
|
||||||
uid = uid[5:]
|
uid = uid[5:]
|
||||||
self.async_discovered_player(
|
self.async_discovered_player(
|
||||||
"SSDP", info, discovered_ip, uid, boot_seqnum, info.get("modelName")
|
"SSDP", info, discovered_ip, uid, boot_seqnum, info.get("modelName"), None
|
||||||
)
|
)
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
def async_discovered_player(
|
def async_discovered_player(
|
||||||
self, source, info, discovered_ip, uid, boot_seqnum, model
|
self, source, info, discovered_ip, uid, boot_seqnum, model, mdns_name
|
||||||
):
|
):
|
||||||
"""Handle discovery via ssdp or zeroconf."""
|
"""Handle discovery via ssdp or zeroconf."""
|
||||||
if model in DISCOVERY_IGNORED_MODELS:
|
if model in DISCOVERY_IGNORED_MODELS:
|
||||||
@ -287,6 +288,9 @@ class SonosDiscoveryManager:
|
|||||||
if boot_seqnum:
|
if boot_seqnum:
|
||||||
boot_seqnum = int(boot_seqnum)
|
boot_seqnum = int(boot_seqnum)
|
||||||
self.data.boot_counts.setdefault(uid, boot_seqnum)
|
self.data.boot_counts.setdefault(uid, boot_seqnum)
|
||||||
|
if mdns_name:
|
||||||
|
self.data.mdns_names[uid] = mdns_name
|
||||||
|
|
||||||
if uid not in self.data.discovery_known:
|
if uid not in self.data.discovery_known:
|
||||||
_LOGGER.debug("New %s discovery uid=%s: %s", source, uid, info)
|
_LOGGER.debug("New %s discovery uid=%s: %s", source, uid, info)
|
||||||
self.data.discovery_known.add(uid)
|
self.data.discovery_known.add(uid)
|
||||||
|
@ -4,7 +4,7 @@ import logging
|
|||||||
import soco
|
import soco
|
||||||
|
|
||||||
from homeassistant import config_entries
|
from homeassistant import config_entries
|
||||||
from homeassistant.const import CONF_HOST
|
from homeassistant.const import CONF_HOST, CONF_NAME
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
from homeassistant.data_entry_flow import FlowResult
|
from homeassistant.data_entry_flow import FlowResult
|
||||||
from homeassistant.helpers.config_entry_flow import DiscoveryFlowHandler
|
from homeassistant.helpers.config_entry_flow import DiscoveryFlowHandler
|
||||||
@ -38,13 +38,14 @@ class SonosDiscoveryFlowHandler(DiscoveryFlowHandler):
|
|||||||
return self.async_abort(reason="not_sonos_device")
|
return self.async_abort(reason="not_sonos_device")
|
||||||
await self.async_set_unique_id(self._domain, raise_on_progress=False)
|
await self.async_set_unique_id(self._domain, raise_on_progress=False)
|
||||||
host = discovery_info[CONF_HOST]
|
host = discovery_info[CONF_HOST]
|
||||||
|
mdns_name = discovery_info[CONF_NAME]
|
||||||
properties = discovery_info["properties"]
|
properties = discovery_info["properties"]
|
||||||
boot_seqnum = properties.get("bootseq")
|
boot_seqnum = properties.get("bootseq")
|
||||||
model = properties.get("model")
|
model = properties.get("model")
|
||||||
uid = hostname_to_uid(hostname)
|
uid = hostname_to_uid(hostname)
|
||||||
if discovery_manager := self.hass.data.get(DATA_SONOS_DISCOVERY_MANAGER):
|
if discovery_manager := self.hass.data.get(DATA_SONOS_DISCOVERY_MANAGER):
|
||||||
discovery_manager.async_discovered_player(
|
discovery_manager.async_discovered_player(
|
||||||
"Zeroconf", properties, host, uid, boot_seqnum, model
|
"Zeroconf", properties, host, uid, boot_seqnum, model, mdns_name
|
||||||
)
|
)
|
||||||
return await self.async_step_discovery(discovery_info)
|
return await self.async_step_discovery(discovery_info)
|
||||||
|
|
||||||
|
@ -41,16 +41,6 @@ def soco_error(errorcodes: list[str] | None = None) -> Callable:
|
|||||||
return decorator
|
return decorator
|
||||||
|
|
||||||
|
|
||||||
def uid_to_short_hostname(uid: str) -> str:
|
|
||||||
"""Convert a Sonos uid to a short hostname."""
|
|
||||||
hostname_uid = uid
|
|
||||||
if hostname_uid.startswith(UID_PREFIX):
|
|
||||||
hostname_uid = hostname_uid[len(UID_PREFIX) :]
|
|
||||||
if hostname_uid.endswith(UID_POSTFIX):
|
|
||||||
hostname_uid = hostname_uid[: -len(UID_POSTFIX)]
|
|
||||||
return f"Sonos-{hostname_uid}"
|
|
||||||
|
|
||||||
|
|
||||||
def hostname_to_uid(hostname: str) -> str:
|
def hostname_to_uid(hostname: str) -> str:
|
||||||
"""Convert a Sonos hostname to a uid."""
|
"""Convert a Sonos hostname to a uid."""
|
||||||
baseuid = hostname.split("-")[1].replace(".local.", "")
|
baseuid = hostname.split("-")[1].replace(".local.", "")
|
||||||
|
@ -59,7 +59,7 @@ from .const import (
|
|||||||
SUBSCRIPTION_TIMEOUT,
|
SUBSCRIPTION_TIMEOUT,
|
||||||
)
|
)
|
||||||
from .favorites import SonosFavorites
|
from .favorites import SonosFavorites
|
||||||
from .helpers import soco_error, uid_to_short_hostname
|
from .helpers import soco_error
|
||||||
|
|
||||||
EVENT_CHARGING = {
|
EVENT_CHARGING = {
|
||||||
"CHARGING": True,
|
"CHARGING": True,
|
||||||
@ -524,11 +524,10 @@ class SonosSpeaker:
|
|||||||
self, callback_timestamp: datetime.datetime | None = None
|
self, callback_timestamp: datetime.datetime | None = None
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Make this player unavailable when it was not seen recently."""
|
"""Make this player unavailable when it was not seen recently."""
|
||||||
if callback_timestamp:
|
data = self.hass.data[DATA_SONOS]
|
||||||
|
if callback_timestamp and (zcname := data.mdns_names.get(self.soco.uid)):
|
||||||
# Called by a _seen_timer timeout, check mDNS one more time
|
# Called by a _seen_timer timeout, check mDNS one more time
|
||||||
# This should not be checked in an "active" unseen scenario
|
# This should not be checked in an "active" unseen scenario
|
||||||
hostname = uid_to_short_hostname(self.soco.uid)
|
|
||||||
zcname = f"{hostname}.{MDNS_SERVICE}"
|
|
||||||
aiozeroconf = await zeroconf.async_get_async_instance(self.hass)
|
aiozeroconf = await zeroconf.async_get_async_instance(self.hass)
|
||||||
if await aiozeroconf.async_get_service_info(MDNS_SERVICE, zcname):
|
if await aiozeroconf.async_get_service_info(MDNS_SERVICE, zcname):
|
||||||
# We can still see the speaker via zeroconf check again later.
|
# We can still see the speaker via zeroconf check again later.
|
||||||
|
@ -45,6 +45,7 @@ async def test_zeroconf_form(hass: core.HomeAssistant):
|
|||||||
context={"source": config_entries.SOURCE_ZEROCONF},
|
context={"source": config_entries.SOURCE_ZEROCONF},
|
||||||
data={
|
data={
|
||||||
"host": "192.168.4.2",
|
"host": "192.168.4.2",
|
||||||
|
"name": "Sonos-aaa@Living Room._sonos._tcp.local.",
|
||||||
"hostname": "Sonos-aaa",
|
"hostname": "Sonos-aaa",
|
||||||
"properties": {"bootseq": "1234"},
|
"properties": {"bootseq": "1234"},
|
||||||
},
|
},
|
||||||
|
@ -1,15 +1,7 @@
|
|||||||
"""Test the sonos config flow."""
|
"""Test the sonos config flow."""
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from homeassistant.components.sonos.helpers import (
|
from homeassistant.components.sonos.helpers import hostname_to_uid
|
||||||
hostname_to_uid,
|
|
||||||
uid_to_short_hostname,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
async def test_uid_to_short_hostname():
|
|
||||||
"""Test we can convert a uid to a short hostname."""
|
|
||||||
assert uid_to_short_hostname("RINCON_347E5C0CF1E301400") == "Sonos-347E5C0CF1E3"
|
|
||||||
|
|
||||||
|
|
||||||
async def test_uid_to_hostname():
|
async def test_uid_to_hostname():
|
||||||
|
Loading…
x
Reference in New Issue
Block a user