"""Test the UniFi Protect media_player platform.""" from __future__ import annotations from unittest.mock import AsyncMock, Mock, patch import pytest from pyunifiprotect.data import Camera from pyunifiprotect.exceptions import StreamError from homeassistant.components.media_player import ( ATTR_MEDIA_CONTENT_TYPE, ATTR_MEDIA_VOLUME_LEVEL, ) from homeassistant.components.unifiprotect.const import DEFAULT_ATTRIBUTION from homeassistant.const import ( ATTR_ATTRIBUTION, ATTR_ENTITY_ID, ATTR_SUPPORTED_FEATURES, STATE_IDLE, STATE_PLAYING, Platform, ) from homeassistant.core import HomeAssistant from homeassistant.exceptions import HomeAssistantError from homeassistant.helpers import entity_registry as er from .utils import ( MockUFPFixture, adopt_devices, assert_entity_counts, init_entry, remove_entities, ) async def test_media_player_camera_remove( hass: HomeAssistant, ufp: MockUFPFixture, doorbell: Camera ) -> None: """Test removing and re-adding a light device.""" await init_entry(hass, ufp, [doorbell]) assert_entity_counts(hass, Platform.MEDIA_PLAYER, 1, 1) await remove_entities(hass, ufp, [doorbell]) assert_entity_counts(hass, Platform.MEDIA_PLAYER, 0, 0) await adopt_devices(hass, ufp, [doorbell]) assert_entity_counts(hass, Platform.MEDIA_PLAYER, 1, 1) async def test_media_player_setup( hass: HomeAssistant, ufp: MockUFPFixture, doorbell: Camera, unadopted_camera: Camera, ) -> None: """Test media_player entity setup.""" await init_entry(hass, ufp, [doorbell, unadopted_camera]) assert_entity_counts(hass, Platform.MEDIA_PLAYER, 1, 1) unique_id = f"{doorbell.mac}_speaker" entity_id = "media_player.test_camera_speaker" entity_registry = er.async_get(hass) entity = entity_registry.async_get(entity_id) assert entity assert entity.unique_id == unique_id expected_volume = float(doorbell.speaker_settings.volume / 100) state = hass.states.get(entity_id) assert state assert state.state == STATE_IDLE assert state.attributes[ATTR_ATTRIBUTION] == DEFAULT_ATTRIBUTION assert state.attributes[ATTR_SUPPORTED_FEATURES] == 136708 assert state.attributes[ATTR_MEDIA_CONTENT_TYPE] == "music" assert state.attributes[ATTR_MEDIA_VOLUME_LEVEL] == expected_volume async def test_media_player_update( hass: HomeAssistant, ufp: MockUFPFixture, doorbell: Camera, unadopted_camera: Camera, ) -> None: """Test media_player entity update.""" await init_entry(hass, ufp, [doorbell, unadopted_camera]) assert_entity_counts(hass, Platform.MEDIA_PLAYER, 1, 1) new_camera = doorbell.copy() new_camera.talkback_stream = Mock() new_camera.talkback_stream.is_running = True mock_msg = Mock() mock_msg.changed_data = {} mock_msg.new_obj = new_camera ufp.api.bootstrap.cameras = {new_camera.id: new_camera} ufp.ws_msg(mock_msg) await hass.async_block_till_done() state = hass.states.get("media_player.test_camera_speaker") assert state assert state.state == STATE_PLAYING async def test_media_player_set_volume( hass: HomeAssistant, ufp: MockUFPFixture, doorbell: Camera, unadopted_camera: Camera, ) -> None: """Test media_player entity test set_volume_level.""" await init_entry(hass, ufp, [doorbell, unadopted_camera]) assert_entity_counts(hass, Platform.MEDIA_PLAYER, 1, 1) doorbell.__fields__["set_speaker_volume"] = Mock(final=False) doorbell.set_speaker_volume = AsyncMock() await hass.services.async_call( "media_player", "volume_set", {ATTR_ENTITY_ID: "media_player.test_camera_speaker", "volume_level": 0.5}, blocking=True, ) doorbell.set_speaker_volume.assert_called_once_with(50) async def test_media_player_stop( hass: HomeAssistant, ufp: MockUFPFixture, doorbell: Camera, unadopted_camera: Camera, ) -> None: """Test media_player entity test media_stop.""" await init_entry(hass, ufp, [doorbell, unadopted_camera]) assert_entity_counts(hass, Platform.MEDIA_PLAYER, 1, 1) new_camera = doorbell.copy() new_camera.talkback_stream = AsyncMock() new_camera.talkback_stream.is_running = True mock_msg = Mock() mock_msg.changed_data = {} mock_msg.new_obj = new_camera ufp.api.bootstrap.cameras = {new_camera.id: new_camera} ufp.ws_msg(mock_msg) await hass.async_block_till_done() await hass.services.async_call( "media_player", "media_stop", {ATTR_ENTITY_ID: "media_player.test_camera_speaker"}, blocking=True, ) new_camera.talkback_stream.stop.assert_called_once() async def test_media_player_play( hass: HomeAssistant, ufp: MockUFPFixture, doorbell: Camera, unadopted_camera: Camera, ) -> None: """Test media_player entity test play_media.""" await init_entry(hass, ufp, [doorbell, unadopted_camera]) assert_entity_counts(hass, Platform.MEDIA_PLAYER, 1, 1) doorbell.__fields__["stop_audio"] = Mock(final=False) doorbell.__fields__["play_audio"] = Mock(final=False) doorbell.__fields__["wait_until_audio_completes"] = Mock(final=False) doorbell.stop_audio = AsyncMock() doorbell.play_audio = AsyncMock() doorbell.wait_until_audio_completes = AsyncMock() await hass.services.async_call( "media_player", "play_media", { ATTR_ENTITY_ID: "media_player.test_camera_speaker", "media_content_id": "http://example.com/test.mp3", "media_content_type": "music", }, blocking=True, ) doorbell.play_audio.assert_called_once_with( "http://example.com/test.mp3", blocking=False ) doorbell.wait_until_audio_completes.assert_called_once() async def test_media_player_play_media_source( hass: HomeAssistant, ufp: MockUFPFixture, doorbell: Camera, unadopted_camera: Camera, ) -> None: """Test media_player entity test play_media.""" await init_entry(hass, ufp, [doorbell, unadopted_camera]) assert_entity_counts(hass, Platform.MEDIA_PLAYER, 1, 1) doorbell.__fields__["stop_audio"] = Mock(final=False) doorbell.__fields__["play_audio"] = Mock(final=False) doorbell.__fields__["wait_until_audio_completes"] = Mock(final=False) doorbell.stop_audio = AsyncMock() doorbell.play_audio = AsyncMock() doorbell.wait_until_audio_completes = AsyncMock() with patch( "homeassistant.components.media_source.async_resolve_media", return_value=Mock(url="http://example.com/test.mp3"), ): await hass.services.async_call( "media_player", "play_media", { ATTR_ENTITY_ID: "media_player.test_camera_speaker", "media_content_id": "media-source://some_source/some_id", "media_content_type": "audio/mpeg", }, blocking=True, ) doorbell.play_audio.assert_called_once_with( "http://example.com/test.mp3", blocking=False ) doorbell.wait_until_audio_completes.assert_called_once() async def test_media_player_play_invalid( hass: HomeAssistant, ufp: MockUFPFixture, doorbell: Camera, unadopted_camera: Camera, ) -> None: """Test media_player entity test play_media, not music.""" await init_entry(hass, ufp, [doorbell, unadopted_camera]) assert_entity_counts(hass, Platform.MEDIA_PLAYER, 1, 1) doorbell.__fields__["play_audio"] = Mock(final=False) doorbell.play_audio = AsyncMock() with pytest.raises(HomeAssistantError): await hass.services.async_call( "media_player", "play_media", { ATTR_ENTITY_ID: "media_player.test_camera_speaker", "media_content_id": "/test.png", "media_content_type": "image", }, blocking=True, ) assert not doorbell.play_audio.called async def test_media_player_play_error( hass: HomeAssistant, ufp: MockUFPFixture, doorbell: Camera, unadopted_camera: Camera, ) -> None: """Test media_player entity test play_media, not music.""" await init_entry(hass, ufp, [doorbell, unadopted_camera]) assert_entity_counts(hass, Platform.MEDIA_PLAYER, 1, 1) doorbell.__fields__["play_audio"] = Mock(final=False) doorbell.__fields__["wait_until_audio_completes"] = Mock(final=False) doorbell.play_audio = AsyncMock(side_effect=StreamError) doorbell.wait_until_audio_completes = AsyncMock() with pytest.raises(HomeAssistantError): await hass.services.async_call( "media_player", "play_media", { ATTR_ENTITY_ID: "media_player.test_camera_speaker", "media_content_id": "/test.mp3", "media_content_type": "music", }, blocking=True, ) assert doorbell.play_audio.called assert not doorbell.wait_until_audio_completes.called