mirror of
https://github.com/home-assistant/core.git
synced 2025-08-10 08:05:06 +02:00
Add unique_id to MPD (#120495)
This commit is contained in:
committed by
GitHub
parent
bff9d12cc0
commit
5a0841155e
@@ -31,6 +31,7 @@ from homeassistant.const import CONF_HOST, CONF_NAME, CONF_PASSWORD, CONF_PORT
|
|||||||
from homeassistant.core import DOMAIN as HOMEASSISTANT_DOMAIN, HomeAssistant
|
from homeassistant.core import DOMAIN as HOMEASSISTANT_DOMAIN, HomeAssistant
|
||||||
from homeassistant.data_entry_flow import FlowResultType
|
from homeassistant.data_entry_flow import FlowResultType
|
||||||
import homeassistant.helpers.config_validation as cv
|
import homeassistant.helpers.config_validation as cv
|
||||||
|
from homeassistant.helpers.device_registry import DeviceEntryType, DeviceInfo
|
||||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||||
from homeassistant.helpers.issue_registry import IssueSeverity, async_create_issue
|
from homeassistant.helpers.issue_registry import IssueSeverity, async_create_issue
|
||||||
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
|
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
|
||||||
@@ -129,7 +130,7 @@ async def async_setup_entry(
|
|||||||
entry.data[CONF_HOST],
|
entry.data[CONF_HOST],
|
||||||
entry.data[CONF_PORT],
|
entry.data[CONF_PORT],
|
||||||
entry.data.get(CONF_PASSWORD),
|
entry.data.get(CONF_PASSWORD),
|
||||||
entry.title,
|
entry.entry_id,
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
True,
|
True,
|
||||||
@@ -140,23 +141,26 @@ class MpdDevice(MediaPlayerEntity):
|
|||||||
"""Representation of a MPD server."""
|
"""Representation of a MPD server."""
|
||||||
|
|
||||||
_attr_media_content_type = MediaType.MUSIC
|
_attr_media_content_type = MediaType.MUSIC
|
||||||
|
_attr_has_entity_name = True
|
||||||
|
_attr_name = None
|
||||||
|
|
||||||
def __init__(self, server, port, password, name):
|
def __init__(
|
||||||
|
self, server: str, port: int, password: str | None, unique_id: str
|
||||||
|
) -> None:
|
||||||
"""Initialize the MPD device."""
|
"""Initialize the MPD device."""
|
||||||
self.server = server
|
self.server = server
|
||||||
self.port = port
|
self.port = port
|
||||||
self._name = name
|
self._attr_unique_id = unique_id
|
||||||
|
self._attr_device_info = DeviceInfo(
|
||||||
|
identifiers={(DOMAIN, unique_id)},
|
||||||
|
entry_type=DeviceEntryType.SERVICE,
|
||||||
|
)
|
||||||
self.password = password
|
self.password = password
|
||||||
|
|
||||||
self._status = {}
|
self._status: dict[str, Any] = {}
|
||||||
self._currentsong = None
|
self._currentsong = None
|
||||||
self._playlists = None
|
self._current_playlist: str | None = None
|
||||||
self._currentplaylist = None
|
|
||||||
self._is_available = None
|
|
||||||
self._muted = False
|
|
||||||
self._muted_volume = None
|
self._muted_volume = None
|
||||||
self._media_position_updated_at = None
|
|
||||||
self._media_position = None
|
|
||||||
self._media_image_hash = None
|
self._media_image_hash = None
|
||||||
# Track if the song changed so image doesn't have to be loaded every update.
|
# Track if the song changed so image doesn't have to be loaded every update.
|
||||||
self._media_image_file = None
|
self._media_image_file = None
|
||||||
@@ -188,7 +192,7 @@ class MpdDevice(MediaPlayerEntity):
|
|||||||
raise TimeoutError("Connection attempt timed out") from error
|
raise TimeoutError("Connection attempt timed out") from error
|
||||||
if self.password is not None:
|
if self.password is not None:
|
||||||
await self._client.password(self.password)
|
await self._client.password(self.password)
|
||||||
self._is_available = True
|
self._attr_available = True
|
||||||
yield
|
yield
|
||||||
except (
|
except (
|
||||||
TimeoutError,
|
TimeoutError,
|
||||||
@@ -199,12 +203,12 @@ class MpdDevice(MediaPlayerEntity):
|
|||||||
# Log a warning during startup or when previously connected; for
|
# Log a warning during startup or when previously connected; for
|
||||||
# subsequent errors a debug message is sufficient.
|
# subsequent errors a debug message is sufficient.
|
||||||
log_level = logging.DEBUG
|
log_level = logging.DEBUG
|
||||||
if self._is_available is not False:
|
if self._attr_available is not False:
|
||||||
log_level = logging.WARNING
|
log_level = logging.WARNING
|
||||||
LOGGER.log(
|
LOGGER.log(
|
||||||
log_level, "Error connecting to '%s': %s", self.server, error
|
log_level, "Error connecting to '%s': %s", self.server, error
|
||||||
)
|
)
|
||||||
self._is_available = False
|
self._attr_available = False
|
||||||
self._status = {}
|
self._status = {}
|
||||||
# Also yield on failure. Handling mpd.ConnectionErrors caused by
|
# Also yield on failure. Handling mpd.ConnectionErrors caused by
|
||||||
# attempting to control a disconnected client is the
|
# attempting to control a disconnected client is the
|
||||||
@@ -228,24 +232,14 @@ class MpdDevice(MediaPlayerEntity):
|
|||||||
if isinstance(position, str) and ":" in position:
|
if isinstance(position, str) and ":" in position:
|
||||||
position = position.split(":")[0]
|
position = position.split(":")[0]
|
||||||
|
|
||||||
if position is not None and self._media_position != position:
|
if position is not None and self._attr_media_position != position:
|
||||||
self._media_position_updated_at = dt_util.utcnow()
|
self._attr_media_position_updated_at = dt_util.utcnow()
|
||||||
self._media_position = int(float(position))
|
self._attr_media_position = int(float(position))
|
||||||
|
|
||||||
await self._update_playlists()
|
await self._update_playlists()
|
||||||
except (mpd.ConnectionError, ValueError) as error:
|
except (mpd.ConnectionError, ValueError) as error:
|
||||||
LOGGER.debug("Error updating status: %s", error)
|
LOGGER.debug("Error updating status: %s", error)
|
||||||
|
|
||||||
@property
|
|
||||||
def available(self) -> bool:
|
|
||||||
"""Return true if MPD is available and connected."""
|
|
||||||
return self._is_available is True
|
|
||||||
|
|
||||||
@property
|
|
||||||
def name(self):
|
|
||||||
"""Return the name of the device."""
|
|
||||||
return self._name
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def state(self) -> MediaPlayerState:
|
def state(self) -> MediaPlayerState:
|
||||||
"""Return the media state."""
|
"""Return the media state."""
|
||||||
@@ -260,11 +254,6 @@ class MpdDevice(MediaPlayerEntity):
|
|||||||
|
|
||||||
return MediaPlayerState.OFF
|
return MediaPlayerState.OFF
|
||||||
|
|
||||||
@property
|
|
||||||
def is_volume_muted(self):
|
|
||||||
"""Boolean if volume is currently muted."""
|
|
||||||
return self._muted
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def media_content_id(self):
|
def media_content_id(self):
|
||||||
"""Return the content ID of current playing media."""
|
"""Return the content ID of current playing media."""
|
||||||
@@ -282,20 +271,6 @@ class MpdDevice(MediaPlayerEntity):
|
|||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
@property
|
|
||||||
def media_position(self):
|
|
||||||
"""Position of current playing media in seconds.
|
|
||||||
|
|
||||||
This is returned as part of the mpd status rather than in the details
|
|
||||||
of the current song.
|
|
||||||
"""
|
|
||||||
return self._media_position
|
|
||||||
|
|
||||||
@property
|
|
||||||
def media_position_updated_at(self):
|
|
||||||
"""Last valid time of media position."""
|
|
||||||
return self._media_position_updated_at
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def media_title(self):
|
def media_title(self):
|
||||||
"""Return the title of current playing media."""
|
"""Return the title of current playing media."""
|
||||||
@@ -436,7 +411,7 @@ class MpdDevice(MediaPlayerEntity):
|
|||||||
| MediaPlayerEntityFeature.VOLUME_STEP
|
| MediaPlayerEntityFeature.VOLUME_STEP
|
||||||
| MediaPlayerEntityFeature.VOLUME_MUTE
|
| MediaPlayerEntityFeature.VOLUME_MUTE
|
||||||
)
|
)
|
||||||
if self._playlists is not None:
|
if self._attr_source_list is not None:
|
||||||
supported |= MediaPlayerEntityFeature.SELECT_SOURCE
|
supported |= MediaPlayerEntityFeature.SELECT_SOURCE
|
||||||
|
|
||||||
return supported
|
return supported
|
||||||
@@ -444,7 +419,7 @@ class MpdDevice(MediaPlayerEntity):
|
|||||||
@property
|
@property
|
||||||
def source(self):
|
def source(self):
|
||||||
"""Name of the current input source."""
|
"""Name of the current input source."""
|
||||||
return self._currentplaylist
|
return self._current_playlist
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def source_list(self):
|
def source_list(self):
|
||||||
@@ -459,12 +434,12 @@ class MpdDevice(MediaPlayerEntity):
|
|||||||
async def _update_playlists(self, **kwargs: Any) -> None:
|
async def _update_playlists(self, **kwargs: Any) -> None:
|
||||||
"""Update available MPD playlists."""
|
"""Update available MPD playlists."""
|
||||||
try:
|
try:
|
||||||
self._playlists = []
|
self._attr_source_list = []
|
||||||
with suppress(mpd.ConnectionError):
|
with suppress(mpd.ConnectionError):
|
||||||
for playlist_data in await self._client.listplaylists():
|
for playlist_data in await self._client.listplaylists():
|
||||||
self._playlists.append(playlist_data["playlist"])
|
self._attr_source_list.append(playlist_data["playlist"])
|
||||||
except mpd.CommandError as error:
|
except mpd.CommandError as error:
|
||||||
self._playlists = None
|
self._attr_source_list = None
|
||||||
LOGGER.warning("Playlists could not be updated: %s:", error)
|
LOGGER.warning("Playlists could not be updated: %s:", error)
|
||||||
|
|
||||||
async def async_set_volume_level(self, volume: float) -> None:
|
async def async_set_volume_level(self, volume: float) -> None:
|
||||||
@@ -527,7 +502,7 @@ class MpdDevice(MediaPlayerEntity):
|
|||||||
await self.async_set_volume_level(0)
|
await self.async_set_volume_level(0)
|
||||||
elif self._muted_volume is not None:
|
elif self._muted_volume is not None:
|
||||||
await self.async_set_volume_level(self._muted_volume)
|
await self.async_set_volume_level(self._muted_volume)
|
||||||
self._muted = mute
|
self._attr_is_volume_muted = mute
|
||||||
|
|
||||||
async def async_play_media(
|
async def async_play_media(
|
||||||
self, media_type: MediaType | str, media_id: str, **kwargs: Any
|
self, media_type: MediaType | str, media_id: str, **kwargs: Any
|
||||||
@@ -543,17 +518,17 @@ class MpdDevice(MediaPlayerEntity):
|
|||||||
|
|
||||||
if media_type == MediaType.PLAYLIST:
|
if media_type == MediaType.PLAYLIST:
|
||||||
LOGGER.debug("Playing playlist: %s", media_id)
|
LOGGER.debug("Playing playlist: %s", media_id)
|
||||||
if media_id in self._playlists:
|
if self._attr_source_list and media_id in self._attr_source_list:
|
||||||
self._currentplaylist = media_id
|
self._current_playlist = media_id
|
||||||
else:
|
else:
|
||||||
self._currentplaylist = None
|
self._current_playlist = None
|
||||||
LOGGER.warning("Unknown playlist name %s", media_id)
|
LOGGER.warning("Unknown playlist name %s", media_id)
|
||||||
await self._client.clear()
|
await self._client.clear()
|
||||||
await self._client.load(media_id)
|
await self._client.load(media_id)
|
||||||
await self._client.play()
|
await self._client.play()
|
||||||
else:
|
else:
|
||||||
await self._client.clear()
|
await self._client.clear()
|
||||||
self._currentplaylist = None
|
self._current_playlist = None
|
||||||
await self._client.add(media_id)
|
await self._client.add(media_id)
|
||||||
await self._client.play()
|
await self._client.play()
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user