1 """MediaPlayer platform for SlimProto Player integration."""
3 from __future__
import annotations
8 from aioslimproto.client
import PlayerState, SlimClient
9 from aioslimproto.models
import EventType, SlimEvent
10 from aioslimproto.server
import SlimServer
15 MediaPlayerDeviceClass,
17 MediaPlayerEntityFeature,
20 async_process_play_media_url,
28 from .const
import DEFAULT_NAME, DOMAIN, PLAYER_EVENT
31 PlayerState.STOPPED: MediaPlayerState.IDLE,
32 PlayerState.PLAYING: MediaPlayerState.PLAYING,
33 PlayerState.BUFFER_READY: MediaPlayerState.PLAYING,
34 PlayerState.BUFFERING: MediaPlayerState.PLAYING,
35 PlayerState.PAUSED: MediaPlayerState.PAUSED,
41 config_entry: ConfigEntry,
42 async_add_entities: AddEntitiesCallback,
44 """Set up SlimProto MediaPlayer(s) from Config Entry."""
45 slimserver: SlimServer = hass.data[DOMAIN]
48 async
def async_add_player(player: SlimClient) ->
None:
49 """Add MediaPlayerEntity from SlimClient."""
55 if player.player_id
not in player.name:
57 await asyncio.sleep(0.1)
60 async
def on_slim_event(event: SlimEvent) ->
None:
61 """Handle player added/connected event."""
62 if event.player_id
in added_ids:
64 added_ids.add(event.player_id)
65 player = slimserver.get_player(event.player_id)
66 await async_add_player(player)
69 config_entry.async_on_unload(
70 slimserver.subscribe(on_slim_event, EventType.PLAYER_CONNECTED)
74 await asyncio.gather(*(async_add_player(player)
for player
in slimserver.players))
78 """Representation of MediaPlayerEntity from SlimProto Player."""
80 _attr_has_entity_name =
True
81 _attr_should_poll =
False
82 _attr_supported_features = (
83 MediaPlayerEntityFeature.PAUSE
84 | MediaPlayerEntityFeature.VOLUME_SET
85 | MediaPlayerEntityFeature.STOP
86 | MediaPlayerEntityFeature.TURN_ON
87 | MediaPlayerEntityFeature.TURN_OFF
88 | MediaPlayerEntityFeature.PLAY
89 | MediaPlayerEntityFeature.PLAY_MEDIA
90 | MediaPlayerEntityFeature.VOLUME_MUTE
91 | MediaPlayerEntityFeature.BROWSE_MEDIA
93 _attr_device_class = MediaPlayerDeviceClass.SPEAKER
96 def __init__(self, slimserver: SlimServer, player: SlimClient) ->
None:
97 """Initialize MediaPlayer entity."""
102 identifiers={(DOMAIN, self.
playerplayer.player_id)},
103 manufacturer=DEFAULT_NAME,
104 model=self.
playerplayer.device_model
or self.
playerplayer.device_type,
105 name=self.
playerplayer.name,
106 hw_version=self.
playerplayer.firmware,
109 if "-pCP" in self.
playerplayer.firmware
or self.
playerplayer.device_model ==
"SqueezeESP32":
111 f
"http://{self.player.device_address}"
116 """Register callbacks."""
122 EventType.PLAYER_UPDATED,
123 EventType.PLAYER_CONNECTED,
124 EventType.PLAYER_DISCONNECTED,
125 EventType.PLAYER_NAME_RECEIVED,
126 EventType.PLAYER_CLI_EVENT,
128 player_filter=self.
playerplayer.player_id,
134 """Return availability of entity."""
135 return self.
playerplayer.connected
138 def state(self) -> MediaPlayerState:
139 """Return current state."""
140 if not self.
playerplayer.powered:
141 return MediaPlayerState.OFF
142 return STATE_MAPPING[self.
playerplayer.state]
146 """Handle player updates."""
151 if (current_media := self.
playerplayer.current_media)
and (
152 metadata := current_media.metadata
168 """Send play command to device."""
169 await self.
playerplayer.play()
172 """Send pause command to device."""
173 await self.
playerplayer.pause()
176 """Send stop command to device."""
177 await self.
playerplayer.stop()
180 """Send new volume_level to device."""
181 volume = round(volume * 100)
182 await self.
playerplayer.volume_set(volume)
185 """Mute the volume."""
186 await self.
playerplayer.mute(mute)
189 """Turn on device."""
190 await self.
playerplayer.power(
True)
193 """Turn off device."""
194 await self.
playerplayer.power(
False)
197 self, media_type: MediaType | str, media_id: str, **kwargs: Any
199 """Send the play_media command to the media player."""
200 to_send_media_type: str |
None = media_type
202 if media_source.is_media_source_id(media_id):
203 sourced_media = await media_source.async_resolve_media(
206 media_id = sourced_media.url
207 to_send_media_type = sourced_media.mime_type
209 if to_send_media_type
and not to_send_media_type.startswith(
"audio/"):
210 to_send_media_type =
None
213 await self.
playerplayer.play_url(media_id, mime_type=to_send_media_type)
217 media_content_type: MediaType | str |
None =
None,
218 media_content_id: str |
None =
None,
220 """Implement the websocket media browsing helper."""
221 return await media_source.async_browse_media(
224 content_filter=
lambda item: item.media_content_type.startswith(
"audio/"),
228 """Call when we receive an event from SlimProto."""
229 if event.type == EventType.PLAYER_CONNECTED:
232 if event.type == EventType.PLAYER_CLI_EVENT:
241 self.
hasshass.bus.async_fire(PLAYER_EVENT, evt_data)
None async_write_ha_state(self)
None async_on_remove(self, CALLBACK_TYPE func)
Callable[[], None] subscribe(HomeAssistant hass, str topic, MessageCallbackType msg_callback, int qos=DEFAULT_QOS, str encoding="utf-8")