mirror of
https://github.com/home-assistant/core.git
synced 2025-06-25 01:21:51 +02:00
Support Sonos announcements using websockets (#91145)
This commit is contained in:
@ -8,7 +8,7 @@
|
||||
"documentation": "https://www.home-assistant.io/integrations/sonos",
|
||||
"iot_class": "local_push",
|
||||
"loggers": ["soco"],
|
||||
"requirements": ["soco==0.29.1"],
|
||||
"requirements": ["soco==0.29.1", "sonos-websocket==0.0.5"],
|
||||
"ssdp": [
|
||||
{
|
||||
"st": "urn:schemas-upnp-org:device:ZonePlayer:1"
|
||||
|
@ -1,8 +1,8 @@
|
||||
"""Support to interface with Sonos players."""
|
||||
from __future__ import annotations
|
||||
|
||||
from asyncio import run_coroutine_threadsafe
|
||||
import datetime
|
||||
from functools import partial
|
||||
import logging
|
||||
from typing import Any
|
||||
|
||||
@ -14,11 +14,13 @@ from soco.core import (
|
||||
PLAY_MODES,
|
||||
)
|
||||
from soco.data_structures import DidlFavorite
|
||||
from sonos_websocket.exception import SonosWebsocketError
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.components import media_source, spotify
|
||||
from homeassistant.components.media_player import (
|
||||
ATTR_INPUT_SOURCE,
|
||||
ATTR_MEDIA_ANNOUNCE,
|
||||
ATTR_MEDIA_ENQUEUE,
|
||||
BrowseMedia,
|
||||
MediaPlayerDeviceClass,
|
||||
@ -491,8 +493,7 @@ class SonosMediaPlayerEntity(SonosEntity, MediaPlayerEntity):
|
||||
"""Clear players playlist."""
|
||||
self.coordinator.soco.clear_queue()
|
||||
|
||||
@soco_error()
|
||||
def play_media( # noqa: C901
|
||||
async def async_play_media(
|
||||
self, media_type: MediaType | str, media_id: str, **kwargs: Any
|
||||
) -> None:
|
||||
"""Send the play_media command to the media player.
|
||||
@ -505,8 +506,21 @@ class SonosMediaPlayerEntity(SonosEntity, MediaPlayerEntity):
|
||||
If media_type is "playlist", media_id should be a Sonos
|
||||
Playlist name. Otherwise, media_id should be a URI.
|
||||
"""
|
||||
# Use 'replace' as the default enqueue option
|
||||
enqueue = kwargs.get(ATTR_MEDIA_ENQUEUE, MediaPlayerEnqueue.REPLACE)
|
||||
if kwargs.get(ATTR_MEDIA_ANNOUNCE):
|
||||
volume = kwargs.get("extra", {}).get("volume")
|
||||
_LOGGER.debug("Playing %s using websocket audioclip", media_id)
|
||||
try:
|
||||
assert self.speaker.websocket
|
||||
response, _ = await self.speaker.websocket.play_clip(
|
||||
media_id,
|
||||
volume=volume,
|
||||
)
|
||||
except SonosWebsocketError as exc:
|
||||
raise HomeAssistantError(
|
||||
f"Error when calling Sonos websocket: {exc}"
|
||||
) from exc
|
||||
if response["success"]:
|
||||
return
|
||||
|
||||
if spotify.is_spotify_media_type(media_type):
|
||||
media_type = spotify.resolve_spotify_media_type(media_type)
|
||||
@ -517,16 +531,21 @@ class SonosMediaPlayerEntity(SonosEntity, MediaPlayerEntity):
|
||||
if media_source.is_media_source_id(media_id):
|
||||
is_radio = media_id.startswith("media-source://radio_browser/")
|
||||
media_type = MediaType.MUSIC
|
||||
media_id = (
|
||||
run_coroutine_threadsafe(
|
||||
media_source.async_resolve_media(
|
||||
self.hass, media_id, self.entity_id
|
||||
),
|
||||
self.hass.loop,
|
||||
)
|
||||
.result()
|
||||
.url
|
||||
media = await media_source.async_resolve_media(
|
||||
self.hass, media_id, self.entity_id
|
||||
)
|
||||
media_id = media.url
|
||||
|
||||
await self.hass.async_add_executor_job(
|
||||
partial(self._play_media, media_type, media_id, is_radio, **kwargs)
|
||||
)
|
||||
|
||||
@soco_error()
|
||||
def _play_media(
|
||||
self, media_type: MediaType | str, media_id: str, is_radio: bool, **kwargs: Any
|
||||
) -> None:
|
||||
"""Wrap sync calls to async_play_media."""
|
||||
enqueue = kwargs.get(ATTR_MEDIA_ENQUEUE, MediaPlayerEnqueue.REPLACE)
|
||||
|
||||
if media_type == "favorite_item_id":
|
||||
favorite = self.speaker.favorites.lookup_by_item_id(media_id)
|
||||
|
@ -18,12 +18,14 @@ from soco.exceptions import SoCoException, SoCoUPnPException
|
||||
from soco.plugins.plex import PlexPlugin
|
||||
from soco.plugins.sharelink import ShareLinkPlugin
|
||||
from soco.snapshot import Snapshot
|
||||
from sonos_websocket import SonosWebsocket
|
||||
|
||||
from homeassistant.components.media_player import DOMAIN as MP_DOMAIN
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.exceptions import HomeAssistantError
|
||||
from homeassistant.helpers import entity_registry as er
|
||||
from homeassistant.helpers.aiohttp_client import async_get_clientsession
|
||||
from homeassistant.helpers.dispatcher import (
|
||||
async_dispatcher_connect,
|
||||
async_dispatcher_send,
|
||||
@ -97,6 +99,7 @@ class SonosSpeaker:
|
||||
"""Initialize a SonosSpeaker."""
|
||||
self.hass = hass
|
||||
self.soco = soco
|
||||
self.websocket: SonosWebsocket | None = None
|
||||
self.household_id: str = soco.household_id
|
||||
self.media = SonosMedia(hass, soco)
|
||||
self._plex_plugin: PlexPlugin | None = None
|
||||
@ -170,8 +173,13 @@ class SonosSpeaker:
|
||||
self.snapshot_group: list[SonosSpeaker] = []
|
||||
self._group_members_missing: set[str] = set()
|
||||
|
||||
async def async_setup_dispatchers(self, entry: ConfigEntry) -> None:
|
||||
"""Connect dispatchers in async context during setup."""
|
||||
async def async_setup(self, entry: ConfigEntry) -> None:
|
||||
"""Complete setup in async context."""
|
||||
self.websocket = SonosWebsocket(
|
||||
self.soco.ip_address,
|
||||
player_id=self.soco.uid,
|
||||
session=async_get_clientsession(self.hass),
|
||||
)
|
||||
dispatch_pairs: tuple[tuple[str, Callable[..., Any]], ...] = (
|
||||
(SONOS_CHECK_ACTIVITY, self.async_check_activity),
|
||||
(SONOS_SPEAKER_ADDED, self.update_group_for_uid),
|
||||
@ -198,7 +206,7 @@ class SonosSpeaker:
|
||||
self.media.poll_media()
|
||||
|
||||
future = asyncio.run_coroutine_threadsafe(
|
||||
self.async_setup_dispatchers(entry), self.hass.loop
|
||||
self.async_setup(entry), self.hass.loop
|
||||
)
|
||||
future.result(timeout=10)
|
||||
|
||||
|
@ -2378,6 +2378,9 @@ solax==0.3.0
|
||||
# homeassistant.components.somfy_mylink
|
||||
somfy-mylink-synergy==1.0.6
|
||||
|
||||
# homeassistant.components.sonos
|
||||
sonos-websocket==0.0.5
|
||||
|
||||
# homeassistant.components.marytts
|
||||
speak2mary==1.4.0
|
||||
|
||||
|
@ -1702,6 +1702,9 @@ solax==0.3.0
|
||||
# homeassistant.components.somfy_mylink
|
||||
somfy-mylink-synergy==1.0.6
|
||||
|
||||
# homeassistant.components.sonos
|
||||
sonos-websocket==0.0.5
|
||||
|
||||
# homeassistant.components.marytts
|
||||
speak2mary==1.4.0
|
||||
|
||||
|
Reference in New Issue
Block a user