1 """Support for Ubiquiti's UniFi Protect NVR."""
3 from __future__
import annotations
8 from uiprotect.data
import Camera, ProtectAdoptableDeviceModel, StateType
9 from uiprotect.exceptions
import StreamError
14 MediaPlayerDeviceClass,
16 MediaPlayerEntityDescription,
17 MediaPlayerEntityFeature,
20 async_process_play_media_url,
26 from .data
import ProtectDeviceType, UFPConfigEntry
27 from .entity
import ProtectDeviceEntity
29 _LOGGER = logging.getLogger(__name__)
32 key=
"speaker", name=
"Speaker", device_class=MediaPlayerDeviceClass.SPEAKER
38 entry: UFPConfigEntry,
39 async_add_entities: AddEntitiesCallback,
41 """Discover cameras with speakers on a UniFi Protect NVR."""
42 data = entry.runtime_data
45 def _add_new_device(device: ProtectAdoptableDeviceModel) ->
None:
46 if isinstance(device, Camera)
and (
47 device.has_speaker
or device.has_removable_speaker
51 data.async_subscribe_adopt(_add_new_device)
54 for device
in data.get_cameras()
55 if device.has_speaker
or device.has_removable_speaker
60 """A Ubiquiti UniFi Protect Speaker."""
63 entity_description: MediaPlayerEntityDescription
64 _attr_supported_features = (
65 MediaPlayerEntityFeature.PLAY_MEDIA
66 | MediaPlayerEntityFeature.VOLUME_SET
67 | MediaPlayerEntityFeature.VOLUME_STEP
68 | MediaPlayerEntityFeature.STOP
69 | MediaPlayerEntityFeature.BROWSE_MEDIA
71 _attr_media_content_type = MediaType.MUSIC
72 _state_attrs = (
"_attr_available",
"_attr_state",
"_attr_volume_level")
77 updated_device = self.
devicedevice
81 updated_device.talkback_stream
is not None
82 and updated_device.talkback_stream.is_running
88 is_connected = self.
datadata.last_update_success
and (
89 updated_device.state
is StateType.CONNECTED
90 or (
not updated_device.is_adopted_by_us
and updated_device.can_adopt)
95 """Set volume level, range 0..1."""
97 volume_int =
int(volume * 100)
98 await self.
devicedevice.set_speaker_volume(volume_int)
101 """Send stop command."""
104 self.
devicedevice.talkback_stream
is not None
105 and self.
devicedevice.talkback_stream.is_running
107 _LOGGER.debug(
"Stopping playback for %s Speaker", self.
devicedevice.display_name)
108 await self.
devicedevice.stop_audio()
112 self, media_type: MediaType | str, media_id: str, **kwargs: Any
114 """Play a piece of media."""
115 if media_source.is_media_source_id(media_id):
116 media_type = MediaType.MUSIC
117 play_item = await media_source.async_resolve_media(
122 if media_type != MediaType.MUSIC:
126 "Playing Media %s for %s Speaker", media_id, self.
devicedevice.display_name
130 await self.
devicedevice.play_audio(media_id, blocking=
False)
131 except StreamError
as err:
137 await self.
devicedevice.wait_until_audio_completes()
143 media_content_type: MediaType | str |
None =
None,
144 media_content_id: str |
None =
None,
146 """Implement the websocket media browsing helper."""
147 return await media_source.async_browse_media(
150 content_filter=
lambda item: item.media_content_type.startswith(
"audio/"),
None _async_updated_event(self, ProtectDeviceType device)