Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions homeassistant/components/music_assistant/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@
ATTR_ARTIST = "artist"
ATTR_ALBUM = "album"
ATTR_URL = "url"
ATTR_MESSAGE = "message"
ATTR_TTS_ENTITY_ID = "tts_entity_id"
ATTR_USE_PRE_ANNOUNCE = "use_pre_announce"
ATTR_ANNOUNCE_VOLUME = "announce_volume"
ATTR_PRE_ANNOUNCE_URL = "pre_announce_url"
Expand Down
2 changes: 1 addition & 1 deletion homeassistant/components/music_assistant/manifest.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"domain": "music_assistant",
"name": "Music Assistant",
"after_dependencies": ["media_source"],
"after_dependencies": ["media_source", "tts"],
"codeowners": ["@music-assistant", "@arturpragacz"],
"config_flow": true,
"dependencies": ["auth"],
Expand Down
26 changes: 23 additions & 3 deletions homeassistant/components/music_assistant/media_player.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
from music_assistant_models.media_items import ItemMapping, MediaItemType
from music_assistant_models.player_queue import PlayerQueue

from homeassistant.components import media_source
from homeassistant.components import media_source, tts
from homeassistant.components.media_player import (
ATTR_MEDIA_EXTRA,
BrowseMedia,
Expand All @@ -38,7 +38,7 @@
SearchMediaQuery,
async_process_play_media_url,
)
from homeassistant.const import ATTR_NAME, STATE_OFF, Platform
from homeassistant.const import ATTR_NAME, STATE_OFF, STATE_UNAVAILABLE, Platform
from homeassistant.core import HomeAssistant, ServiceResponse
from homeassistant.exceptions import HomeAssistantError, ServiceValidationError
from homeassistant.helpers import entity_registry as er
Expand Down Expand Up @@ -563,12 +563,32 @@ async def _async_handle_play_media(
@catch_musicassistant_error
async def _async_handle_play_announcement(
self,
url: str,
url: str | None = None,
message: str | None = None,
tts_entity_id: str | None = None,
use_pre_announce: bool | None = None,
pre_announce_url: str | None = None,
announce_volume: int | None = None,
) -> None:
"""Send the play_announcement command to the media player."""
if url is None:
if TYPE_CHECKING:
assert message is not None
assert tts_entity_id is not None
# a gone or unavailable entity would otherwise yield a url that plays nothing
tts_state = self.hass.states.get(tts_entity_id)
if tts_state is None or tts_state.state == STATE_UNAVAILABLE:
raise ServiceValidationError(
translation_domain=DOMAIN,
translation_key="tts_entity_not_available",
translation_placeholders={"entity_id": tts_entity_id},
)
sourced_media = await media_source.async_resolve_media(
self.hass,
tts.generate_media_source_id(self.hass, message, engine=tts_entity_id),
self.entity_id,
)
url = async_process_play_media_url(self.hass, sourced_media.url)
await self.mass.players.play_announcement(
self.player_id,
url,
Expand Down
25 changes: 19 additions & 6 deletions homeassistant/components/music_assistant/services.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
ATTR_MEDIA_ENQUEUE,
DOMAIN as MEDIA_PLAYER_DOMAIN,
)
from homeassistant.components.tts import DOMAIN as TTS_DOMAIN
from homeassistant.const import ATTR_CONFIG_ENTRY_ID
from homeassistant.core import (
HomeAssistant,
Expand Down Expand Up @@ -36,6 +37,7 @@
ATTR_LIMIT,
ATTR_MEDIA_ID,
ATTR_MEDIA_TYPE,
ATTR_MESSAGE,
ATTR_OFFSET,
ATTR_ORDER_BY,
ATTR_PLAYLISTS,
Expand All @@ -49,6 +51,7 @@
ATTR_SEARCH_NAME,
ATTR_SOURCE_PLAYER,
ATTR_TRACKS,
ATTR_TTS_ENTITY_ID,
ATTR_URL,
ATTR_USE_PRE_ANNOUNCE,
ATTR_USERNAME,
Expand Down Expand Up @@ -150,12 +153,22 @@ def register_actions(hass: HomeAssistant) -> None:
DOMAIN,
SERVICE_PLAY_ANNOUNCEMENT,
entity_domain=MEDIA_PLAYER_DOMAIN,
schema={
vol.Required(ATTR_URL): cv.string,
vol.Optional(ATTR_USE_PRE_ANNOUNCE): vol.Coerce(bool),
vol.Optional(ATTR_PRE_ANNOUNCE_URL): cv.string,
vol.Optional(ATTR_ANNOUNCE_VOLUME): vol.Coerce(int),
},
schema=vol.All(
cv.make_entity_service_schema(
{
vol.Optional(ATTR_URL): cv.string,
vol.Inclusive(ATTR_MESSAGE, "spoken_announcement"): cv.string,
vol.Inclusive(ATTR_TTS_ENTITY_ID, "spoken_announcement"): vol.All(
cv.entity_id, cv.entity_domain(TTS_DOMAIN)
),
vol.Optional(ATTR_USE_PRE_ANNOUNCE): vol.Coerce(bool),
vol.Optional(ATTR_PRE_ANNOUNCE_URL): cv.string,
vol.Optional(ATTR_ANNOUNCE_VOLUME): vol.Coerce(int),
}
),
cv.has_at_least_one_key(ATTR_URL, ATTR_MESSAGE),
cv.has_at_most_one_key(ATTR_URL, ATTR_MESSAGE),
),
func="_async_handle_play_announcement",
)
service.async_register_platform_entity_service(
Expand Down
14 changes: 13 additions & 1 deletion homeassistant/components/music_assistant/services.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,20 @@ play_announcement:
- media_player.MediaPlayerEntityFeature.PLAY_MEDIA
- media_player.MediaPlayerEntityFeature.MEDIA_ANNOUNCE
fields:
message:
required: false
example: "Dinner is ready!"
selector:
text:
multiline: true
tts_entity_id:
required: false
example: "tts.piper"
selector:
entity:
domain: tts
url:
required: true
required: false
example: "http://someremotesite.com/doorbell.mp3"
selector:
text:
Expand Down
13 changes: 12 additions & 1 deletion homeassistant/components/music_assistant/strings.json
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,9 @@
"exceptions": {
"invalid_username": {
"message": "The username {username} does not exist on the Music Assistant server."
},
"tts_entity_not_available": {
"message": "The text-to-speech entity {entity_id} is not available."
}
},
"issues": {
Expand Down Expand Up @@ -387,12 +390,20 @@
"description": "Use a forced volume level for the announcement. Omit to use player default.",
"name": "Announce volume"
},
"message": {
"description": "Text to announce, spoken by the selected text-to-speech entity. Provide either a message or a URL.",
"name": "Message"
},
"pre_announce_url": {
"description": "URL to the pre-announcement sound.",
"name": "Pre-announce URL"
},
"tts_entity_id": {
"description": "Text-to-speech entity that speaks the message. Required when a message is given.",
"name": "Text-to-speech entity"
},
"url": {
"description": "URL to the notification sound.",
"description": "URL to the notification sound. Provide either a message or a URL.",
"name": "URL"
},
"use_pre_announce": {
Expand Down
2 changes: 1 addition & 1 deletion homeassistant/package_constraints.txt
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ standard-telnetlib==3.13.0
typing-extensions>=4.16.0,<5.0
ulid-transform==2.2.9
urllib3>=2.0
uv==0.12.5
uv==0.12.6
webrtc-models==0.3.0
yarl==1.24.5
zeroconf==0.151.1
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ dependencies = [
"typing-extensions>=4.16.0,<5.0",
"ulid-transform==2.2.9",
"urllib3>=2.0",
"uv==0.12.5",
"uv==0.12.6",
"probatio==0.11.4",
"yarl==1.24.5",
"webrtc-models==0.3.0",
Expand Down
2 changes: 1 addition & 1 deletion requirements.txt

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading