async def _validate_input(self, data): """ Validate the user input allows us to connect. Retrieve unique id and abort if already configured. """ server = Server( async_get_clientsession(self.hass), data[CONF_HOST], data[CONF_PORT], data.get(CONF_USERNAME), data.get(CONF_PASSWORD), ) try: status = await server.async_query("serverstatus") if not status: if server.http_status == HTTP_UNAUTHORIZED: return "invalid_auth" return "cannot_connect" except Exception: # pylint: disable=broad-except return "unknown" if "uuid" in status: await self.async_set_unique_id(status["uuid"]) self._abort_if_unique_id_configured()
async def test_get_players(): """Test async_get_players() method.""" with patch.object(Server, "async_query", CoroutineMock(return_value=False)): mock_lms = Server(None, None) await mock_lms.async_get_players() assert await mock_lms.async_get_player() is None
async def async_setup_entry( hass: HomeAssistant, config_entry: ConfigEntry, async_add_entities: AddEntitiesCallback, ) -> None: """Set up an LMS Server from a config entry.""" config = config_entry.data _LOGGER.debug("Reached async_setup_entry for host=%s", config[CONF_HOST]) username = config.get(CONF_USERNAME) password = config.get(CONF_PASSWORD) host = config[CONF_HOST] port = config[CONF_PORT] hass.data.setdefault(DOMAIN, {}) hass.data[DOMAIN].setdefault(config_entry.entry_id, {}) known_players = hass.data[DOMAIN].setdefault(KNOWN_PLAYERS, []) session = async_get_clientsession(hass) _LOGGER.debug("Creating LMS object for %s", host) lms = Server(session, host, port, username, password) async def _discovery(now=None): """Discover squeezebox players by polling server.""" async def _discovered_player(player): """Handle a (re)discovered player.""" entity = next( ( known for known in known_players if known.unique_id == player.player_id ), None, ) if entity: await player.async_update() async_dispatcher_send( hass, SIGNAL_PLAYER_REDISCOVERED, player.player_id, player.connected ) if not entity: _LOGGER.debug("Adding new entity: %s", player) entity = SqueezeBoxEntity(player) known_players.append(entity) async_add_entities([entity]) if players := await lms.async_get_players(): for player in players: hass.async_create_task(_discovered_player(player)) hass.data[DOMAIN][config_entry.entry_id][ PLAYER_DISCOVERY_UNSUB ] = async_call_later(hass, DISCOVERY_INTERVAL, _discovery)
async def test_async_query(): """Test async_query failure modes (successful queries tested by test_integration.py).""" lms = Server(None, None) with pytest.raises(ValueError): assert await lms.async_query("serverstatus") response = Mock(status="404", text="could not find page") with patch.object(ClientSession, "post", AsyncMock(return_value=response)): mock_lms = Server(ClientSession(), None) assert not await mock_lms.async_query("serverstatus") with patch.object(ClientSession, "post", AsyncMock(side_effect=asyncio.TimeoutError)): mock_lms = Server(ClientSession(), None) assert not await mock_lms.async_query("serverstatus") data = {"bogus_key": "bogus_value"} response = Mock(status=200, json=AsyncMock(return_value=data)) with patch.object(ClientSession, "post", AsyncMock(return_value=response)): mock_lms = Server(ClientSession(), None) assert not await mock_lms.async_query("serverstatus")
async def fixture_lms(request): """Return a working Server object.""" # Get the ip address and port from the command line ip = IP if IP else request.config.option.IP port = request.config.option.PORT if ip is None: pytest.fail("No ip address specified. Use the --ip option.") async with aiohttp.ClientSession() as session: server = Server(session, ip, port) # confirm server is working assert await server.async_status() yield server
async def mock_discover(_discovery_callback): """Mock discovering a Logitech Media Server.""" _discovery_callback(Server(None, HOST, PORT, uuid=UUID))
async def async_setup_entry(hass, config_entry, async_add_entities): """Set up an LMS Server from a config entry.""" config = config_entry.data _LOGGER.debug("Reached async_setup_entry for host=%s", config[CONF_HOST]) username = config.get(CONF_USERNAME) password = config.get(CONF_PASSWORD) host = config[CONF_HOST] port = config[CONF_PORT] hass.data.setdefault(DOMAIN, {}) hass.data[DOMAIN].setdefault(config_entry.entry_id, {}) known_players = hass.data[DOMAIN].setdefault(KNOWN_PLAYERS, []) _LOGGER.debug("Creating LMS object for %s", host) lms = Server(async_get_clientsession(hass), host, port, username, password) async def _discovery(now=None): """Discover squeezebox players by polling server.""" async def _discovered_player(player): """Handle a (re)discovered player.""" entity = next( ( known for known in known_players if known.unique_id == player.player_id ), None, ) if entity: await player.async_update() async_dispatcher_send( hass, SIGNAL_PLAYER_REDISCOVERED, player.player_id, player.connected ) if not entity: _LOGGER.debug("Adding new entity: %s", player) entity = SqueezeBoxEntity(player) known_players.append(entity) async_add_entities([entity]) players = await lms.async_get_players() if players: for player in players: hass.async_create_task(_discovered_player(player)) hass.data[DOMAIN][config_entry.entry_id][ PLAYER_DISCOVERY_UNSUB ] = hass.helpers.event.async_call_later(DISCOVERY_INTERVAL, _discovery) _LOGGER.debug("Adding player discovery job for LMS server: %s", host) asyncio.create_task(_discovery()) # Register entity services platform = entity_platform.current_platform.get() platform.async_register_entity_service( SERVICE_CALL_METHOD, { vol.Required(ATTR_COMMAND): cv.string, vol.Optional(ATTR_PARAMETERS): vol.All( cv.ensure_list, vol.Length(min=1), [cv.string] ), }, "async_call_method", ) platform.async_register_entity_service( SERVICE_CALL_QUERY, { vol.Required(ATTR_COMMAND): cv.string, vol.Optional(ATTR_PARAMETERS): vol.All( cv.ensure_list, vol.Length(min=1), [cv.string] ), }, "async_call_query", ) platform.async_register_entity_service( SERVICE_SYNC, {vol.Required(ATTR_OTHER_PLAYER): cv.string}, "async_sync", ) platform.async_register_entity_service(SERVICE_UNSYNC, None, "async_unsync") # Start server discovery task if not already running if hass.is_running: asyncio.create_task(start_server_discovery(hass)) else: hass.bus.async_listen_once( EVENT_HOMEASSISTANT_START, start_server_discovery(hass) ) return True
async def test_image_url(): """Test creating image urls.""" lms = Server(None, "192.168.1.1", username="******", password="******") player = Player(lms, "00:11:22:33:44:55", "Test Player") assert (player.image_url == "http://*****:*****@192.168.1.1:9000/music/unknown/cover.jpg")
async def async_setup_platform(hass, config, async_add_entities, discovery_info=None): """Set up the squeezebox platform.""" known_servers = hass.data.get(KNOWN_SERVERS) if known_servers is None: hass.data[KNOWN_SERVERS] = known_servers = set() if DATA_SQUEEZEBOX not in hass.data: hass.data[DATA_SQUEEZEBOX] = [] username = config.get(CONF_USERNAME) password = config.get(CONF_PASSWORD) if discovery_info is not None: host = discovery_info.get("host") port = discovery_info.get("port") else: host = config.get(CONF_HOST) port = config.get(CONF_PORT) # In case the port is not discovered if port is None: port = DEFAULT_PORT # Get IP of host, to prevent duplication of same host (different DNS names) try: ipaddr = await hass.async_add_executor_job(socket.gethostbyname, host) except OSError as error: _LOGGER.error("Could not communicate with %s:%d: %s", host, port, error) raise PlatformNotReady from error if ipaddr in known_servers: return _LOGGER.debug("Creating LMS object for %s", ipaddr) lms = Server(async_get_clientsession(hass), host, port, username, password) known_servers.add(ipaddr) players = await lms.async_get_players() if players is None: raise PlatformNotReady media_players = [] for player in players: media_players.append(SqueezeBoxDevice(player)) hass.data[DATA_SQUEEZEBOX].extend(media_players) async_add_entities(media_players) platform = entity_platform.current_platform.get() platform.async_register_entity_service( SERVICE_CALL_METHOD, { vol.Required(ATTR_COMMAND): cv.string, vol.Optional(ATTR_PARAMETERS): vol.All( cv.ensure_list, vol.Length(min=1), [cv.string] ), }, "async_call_method", ) platform.async_register_entity_service( SERVICE_CALL_QUERY, { vol.Required(ATTR_COMMAND): cv.string, vol.Optional(ATTR_PARAMETERS): vol.All( cv.ensure_list, vol.Length(min=1), [cv.string] ), }, "async_call_query", ) platform.async_register_entity_service( SERVICE_SYNC, {vol.Required(ATTR_OTHER_PLAYER): cv.string}, "async_sync", ) platform.async_register_entity_service(SERVICE_UNSYNC, None, "async_unsync") return True