Example #1
0
    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()
Example #2
0
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
Example #3
0
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)
Example #4
0
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")
Example #5
0
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
Example #6
0
async def mock_discover(_discovery_callback):
    """Mock discovering a Logitech Media Server."""
    _discovery_callback(Server(None, HOST, PORT, uuid=UUID))
Example #7
0
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
Example #8
0
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")
Example #9
0
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