Exemple #1
0
async def async_setup_entry(hass, entry):
    """Set up Plex from a config entry."""
    server_config = entry.data[PLEX_SERVER_CONFIG]

    if MP_DOMAIN not in entry.options:
        options = dict(entry.options)
        options.setdefault(
            MP_DOMAIN,
            hass.data.get(PLEX_MEDIA_PLAYER_OPTIONS)
            or MEDIA_PLAYER_SCHEMA({}),
        )
        hass.config_entries.async_update_entry(entry, options=options)

    plex_server = PlexServer(hass, server_config, entry.options)
    try:
        await hass.async_add_executor_job(plex_server.connect)
    except requests.exceptions.ConnectionError as error:
        _LOGGER.error(
            "Plex server (%s) could not be reached: [%s]",
            server_config[CONF_URL],
            error,
        )
        raise ConfigEntryNotReady
    except (
            plexapi.exceptions.BadRequest,
            plexapi.exceptions.Unauthorized,
            plexapi.exceptions.NotFound,
    ) as error:
        _LOGGER.error(
            "Login to %s failed, verify token and SSL settings: [%s]",
            entry.data[CONF_SERVER],
            error,
        )
        return False

    _LOGGER.debug("Connected to: %s (%s)", plex_server.friendly_name,
                  plex_server.url_in_use)
    server_id = plex_server.machine_identifier
    hass.data[PLEX_DOMAIN][SERVERS][server_id] = plex_server
    hass.data[PLEX_DOMAIN][PLATFORMS_COMPLETED][server_id] = set()

    entry.add_update_listener(async_options_updated)

    unsub = async_dispatcher_connect(
        hass,
        PLEX_UPDATE_PLATFORMS_SIGNAL.format(server_id),
        plex_server.update_platforms,
    )
    hass.data[PLEX_DOMAIN][DISPATCHERS].setdefault(server_id, [])
    hass.data[PLEX_DOMAIN][DISPATCHERS][server_id].append(unsub)

    def update_plex():
        async_dispatcher_send(hass,
                              PLEX_UPDATE_PLATFORMS_SIGNAL.format(server_id))

    session = async_get_clientsession(hass)
    verify_ssl = server_config.get(CONF_VERIFY_SSL)
    websocket = PlexWebsocket(plex_server.plex_server,
                              update_plex,
                              session=session,
                              verify_ssl=verify_ssl)
    hass.data[PLEX_DOMAIN][WEBSOCKETS][server_id] = websocket

    def start_websocket_session(platform, _):
        hass.data[PLEX_DOMAIN][PLATFORMS_COMPLETED][server_id].add(platform)
        if hass.data[PLEX_DOMAIN][PLATFORMS_COMPLETED][server_id] == PLATFORMS:
            hass.loop.create_task(websocket.listen())

    def close_websocket_session(_):
        websocket.close()

    unsub = hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP,
                                       close_websocket_session)
    hass.data[PLEX_DOMAIN][DISPATCHERS][server_id].append(unsub)

    for platform in PLATFORMS:
        task = hass.async_create_task(
            hass.config_entries.async_forward_entry_setup(entry, platform))
        task.add_done_callback(
            functools.partial(start_websocket_session, platform))

    return True
Exemple #2
0
async def async_setup_entry(hass, entry):
    """Set up Plex from a config entry."""
    server_config = entry.data[PLEX_SERVER_CONFIG]

    if entry.unique_id is None:
        hass.config_entries.async_update_entry(
            entry, unique_id=entry.data[CONF_SERVER_IDENTIFIER])

    if MP_DOMAIN not in entry.options:
        options = dict(entry.options)
        options.setdefault(MP_DOMAIN, {})
        hass.config_entries.async_update_entry(entry, options=options)

    plex_server = PlexServer(
        hass,
        server_config,
        entry.data[CONF_SERVER_IDENTIFIER],
        entry.options,
        entry.entry_id,
    )
    try:
        await hass.async_add_executor_job(plex_server.connect)
    except ShouldUpdateConfigEntry:
        new_server_data = {
            **entry.data[PLEX_SERVER_CONFIG],
            CONF_URL: plex_server.url_in_use,
            CONF_SERVER: plex_server.friendly_name,
        }
        hass.config_entries.async_update_entry(
            entry, data={
                **entry.data, PLEX_SERVER_CONFIG: new_server_data
            })
    except requests.exceptions.ConnectionError as error:
        if entry.state != ENTRY_STATE_SETUP_RETRY:
            _LOGGER.error(
                "Plex server (%s) could not be reached: [%s]",
                server_config[CONF_URL],
                error,
            )
        raise ConfigEntryNotReady from error
    except plexapi.exceptions.Unauthorized:
        hass.async_create_task(
            hass.config_entries.flow.async_init(
                PLEX_DOMAIN,
                context={CONF_SOURCE: SOURCE_REAUTH},
                data=entry.data,
            ))
        _LOGGER.error(
            "Token not accepted, please reauthenticate Plex server '%s'",
            entry.data[CONF_SERVER],
        )
        return False
    except (
            plexapi.exceptions.BadRequest,
            plexapi.exceptions.NotFound,
    ) as error:
        _LOGGER.error(
            "Login to %s failed, verify token and SSL settings: [%s]",
            entry.data[CONF_SERVER],
            error,
        )
        return False

    _LOGGER.debug("Connected to: %s (%s)", plex_server.friendly_name,
                  plex_server.url_in_use)
    server_id = plex_server.machine_identifier
    hass.data[PLEX_DOMAIN][SERVERS][server_id] = plex_server
    hass.data[PLEX_DOMAIN][PLATFORMS_COMPLETED][server_id] = set()

    entry.add_update_listener(async_options_updated)

    async def async_update_plex():
        await hass.data[PLEX_DOMAIN][GDM_DEBOUNCER]()
        await plex_server.async_update_platforms()

    unsub = async_dispatcher_connect(
        hass,
        PLEX_UPDATE_PLATFORMS_SIGNAL.format(server_id),
        async_update_plex,
    )
    hass.data[PLEX_DOMAIN][DISPATCHERS].setdefault(server_id, [])
    hass.data[PLEX_DOMAIN][DISPATCHERS][server_id].append(unsub)

    @callback
    def plex_websocket_callback(signal, data, error):
        """Handle callbacks from plexwebsocket library."""
        if signal == SIGNAL_CONNECTION_STATE:

            if data == STATE_CONNECTED:
                _LOGGER.debug("Websocket to %s successful",
                              entry.data[CONF_SERVER])
            elif data == STATE_DISCONNECTED:
                _LOGGER.debug("Websocket to %s disconnected, retrying",
                              entry.data[CONF_SERVER])
            # Stopped websockets without errors are expected during shutdown and ignored
            elif data == STATE_STOPPED and error:
                _LOGGER.error(
                    "Websocket to %s failed, aborting [Error: %s]",
                    entry.data[CONF_SERVER],
                    error,
                )
                hass.async_create_task(
                    hass.config_entries.async_reload(entry.entry_id))

        elif signal == SIGNAL_DATA:
            async_dispatcher_send(
                hass, PLEX_UPDATE_PLATFORMS_SIGNAL.format(server_id))

    session = async_get_clientsession(hass)
    verify_ssl = server_config.get(CONF_VERIFY_SSL)
    websocket = PlexWebsocket(
        plex_server.plex_server,
        plex_websocket_callback,
        session=session,
        verify_ssl=verify_ssl,
    )
    hass.data[PLEX_DOMAIN][WEBSOCKETS][server_id] = websocket

    def start_websocket_session(platform, _):
        hass.data[PLEX_DOMAIN][PLATFORMS_COMPLETED][server_id].add(platform)
        if hass.data[PLEX_DOMAIN][PLATFORMS_COMPLETED][server_id] == PLATFORMS:
            hass.loop.create_task(websocket.listen())

    def close_websocket_session(_):
        websocket.close()

    unsub = hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP,
                                       close_websocket_session)
    hass.data[PLEX_DOMAIN][DISPATCHERS][server_id].append(unsub)

    for platform in PLATFORMS:
        task = hass.async_create_task(
            hass.config_entries.async_forward_entry_setup(entry, platform))
        task.add_done_callback(
            functools.partial(start_websocket_session, platform))

    async def async_play_on_sonos_service(service_call):
        await hass.async_add_executor_job(play_on_sonos, hass, service_call)

    play_on_sonos_schema = vol.Schema({
        vol.Required(ATTR_ENTITY_ID):
        cv.entity_id,
        vol.Required(ATTR_MEDIA_CONTENT_ID):
        cv.string,
        vol.Optional(ATTR_MEDIA_CONTENT_TYPE):
        vol.In("music"),
    })

    def get_plex_account(plex_server):
        try:
            return plex_server.account
        except (plexapi.exceptions.BadRequest,
                plexapi.exceptions.Unauthorized):
            return None

    plex_account = await hass.async_add_executor_job(get_plex_account,
                                                     plex_server)
    if plex_account:
        hass.services.async_register(
            PLEX_DOMAIN,
            SERVICE_PLAY_ON_SONOS,
            async_play_on_sonos_service,
            schema=play_on_sonos_schema,
        )

    return True
Exemple #3
0
async def async_setup_entry(hass, entry):
    """Set up Plex from a config entry."""
    server_config = entry.data[PLEX_SERVER_CONFIG]

    if entry.unique_id is None:
        hass.config_entries.async_update_entry(
            entry, unique_id=entry.data[CONF_SERVER_IDENTIFIER])

    plex_server = PlexServer(hass, server_config,
                             entry.data[CONF_SERVER_IDENTIFIER], entry.options)
    try:
        await hass.async_add_executor_job(plex_server.connect)
    except ShouldUpdateConfigEntry:
        new_server_data = {
            **entry.data[PLEX_SERVER_CONFIG],
            CONF_URL: plex_server.url_in_use,
            CONF_SERVER: plex_server.friendly_name,
        }
        hass.config_entries.async_update_entry(
            entry, data={
                **entry.data, PLEX_SERVER_CONFIG: new_server_data
            })
    except requests.exceptions.ConnectionError as error:
        _LOGGER.error(
            "Plex server (%s) could not be reached: [%s]",
            server_config[CONF_URL],
            error,
        )
        raise ConfigEntryNotReady
    except (
            plexapi.exceptions.BadRequest,
            plexapi.exceptions.Unauthorized,
            plexapi.exceptions.NotFound,
    ) as error:
        _LOGGER.error(
            "Login to %s failed, verify token and SSL settings: [%s]",
            entry.data[CONF_SERVER],
            error,
        )
        return False

    _LOGGER.debug("Connected to: %s (%s)", plex_server.friendly_name,
                  plex_server.url_in_use)
    server_id = plex_server.machine_identifier
    hass.data[PLEX_DOMAIN][SERVERS][server_id] = plex_server
    hass.data[PLEX_DOMAIN][PLATFORMS_COMPLETED][server_id] = set()

    entry.add_update_listener(async_options_updated)

    unsub = async_dispatcher_connect(
        hass,
        PLEX_UPDATE_PLATFORMS_SIGNAL.format(server_id),
        plex_server.async_update_platforms,
    )
    hass.data[PLEX_DOMAIN][DISPATCHERS].setdefault(server_id, [])
    hass.data[PLEX_DOMAIN][DISPATCHERS][server_id].append(unsub)

    def update_plex():
        async_dispatcher_send(hass,
                              PLEX_UPDATE_PLATFORMS_SIGNAL.format(server_id))

    session = async_get_clientsession(hass)
    verify_ssl = server_config.get(CONF_VERIFY_SSL)
    websocket = PlexWebsocket(plex_server.plex_server,
                              update_plex,
                              session=session,
                              verify_ssl=verify_ssl)
    hass.data[PLEX_DOMAIN][WEBSOCKETS][server_id] = websocket

    def start_websocket_session(platform, _):
        hass.data[PLEX_DOMAIN][PLATFORMS_COMPLETED][server_id].add(platform)
        if hass.data[PLEX_DOMAIN][PLATFORMS_COMPLETED][server_id] == PLATFORMS:
            hass.loop.create_task(websocket.listen())

    def close_websocket_session(_):
        websocket.close()

    unsub = hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP,
                                       close_websocket_session)
    hass.data[PLEX_DOMAIN][DISPATCHERS][server_id].append(unsub)

    for platform in PLATFORMS:
        task = hass.async_create_task(
            hass.config_entries.async_forward_entry_setup(entry, platform))
        task.add_done_callback(
            functools.partial(start_websocket_session, platform))

    async def async_play_on_sonos_service(service_call):
        await hass.async_add_executor_job(play_on_sonos, hass, service_call)

    play_on_sonos_schema = vol.Schema({
        vol.Required(ATTR_ENTITY_ID):
        cv.entity_id,
        vol.Required(ATTR_MEDIA_CONTENT_ID):
        str,
        vol.Optional(ATTR_MEDIA_CONTENT_TYPE):
        vol.In("music"),
    })

    hass.services.async_register(
        PLEX_DOMAIN,
        SERVICE_PLAY_ON_SONOS,
        async_play_on_sonos_service,
        schema=play_on_sonos_schema,
    )

    return True
Exemple #4
0
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
    """Set up Plex from a config entry."""
    server_config = entry.data[PLEX_SERVER_CONFIG]

    if entry.unique_id is None:
        hass.config_entries.async_update_entry(
            entry, unique_id=entry.data[CONF_SERVER_IDENTIFIER])

    if MP_DOMAIN not in entry.options:
        options = dict(entry.options)
        options.setdefault(MP_DOMAIN, {})
        hass.config_entries.async_update_entry(entry, options=options)

    plex_server = PlexServer(
        hass,
        server_config,
        entry.data[CONF_SERVER_IDENTIFIER],
        entry.options,
        entry.entry_id,
    )
    try:
        await hass.async_add_executor_job(plex_server.connect)
    except ShouldUpdateConfigEntry:
        new_server_data = {
            **entry.data[PLEX_SERVER_CONFIG],
            CONF_URL: plex_server.url_in_use,
            CONF_SERVER: plex_server.friendly_name,
        }
        hass.config_entries.async_update_entry(
            entry, data={
                **entry.data, PLEX_SERVER_CONFIG: new_server_data
            })
    except requests.exceptions.ConnectionError as error:
        if entry.state is not ConfigEntryState.SETUP_RETRY:
            _LOGGER.error(
                "Plex server (%s) could not be reached: [%s]",
                server_config[CONF_URL],
                error,
            )
        raise ConfigEntryNotReady from error
    except plexapi.exceptions.Unauthorized as ex:
        raise ConfigEntryAuthFailed(
            f"Token not accepted, please reauthenticate Plex server '{entry.data[CONF_SERVER]}'"
        ) from ex
    except (
            plexapi.exceptions.BadRequest,
            plexapi.exceptions.NotFound,
    ) as error:
        _LOGGER.error(
            "Login to %s failed, verify token and SSL settings: [%s]",
            entry.data[CONF_SERVER],
            error,
        )
        return False

    _LOGGER.debug("Connected to: %s (%s)", plex_server.friendly_name,
                  plex_server.url_in_use)
    server_id = plex_server.machine_identifier
    hass.data[PLEX_DOMAIN][SERVERS][server_id] = plex_server
    hass.data[PLEX_DOMAIN][PLATFORMS_COMPLETED][server_id] = set()

    entry.add_update_listener(async_options_updated)

    unsub = async_dispatcher_connect(
        hass,
        PLEX_UPDATE_PLATFORMS_SIGNAL.format(server_id),
        plex_server.async_update_platforms,
    )
    hass.data[PLEX_DOMAIN][DISPATCHERS].setdefault(server_id, [])
    hass.data[PLEX_DOMAIN][DISPATCHERS][server_id].append(unsub)

    @callback
    def plex_websocket_callback(msgtype, data, error):
        """Handle callbacks from plexwebsocket library."""
        if msgtype == SIGNAL_CONNECTION_STATE:

            if data == STATE_CONNECTED:
                _LOGGER.debug("Websocket to %s successful",
                              entry.data[CONF_SERVER])
                hass.async_create_task(plex_server.async_update_platforms())
            elif data == STATE_DISCONNECTED:
                _LOGGER.debug("Websocket to %s disconnected, retrying",
                              entry.data[CONF_SERVER])
            # Stopped websockets without errors are expected during shutdown and ignored
            elif data == STATE_STOPPED and error:
                _LOGGER.error(
                    "Websocket to %s failed, aborting [Error: %s]",
                    entry.data[CONF_SERVER],
                    error,
                )
                hass.async_create_task(
                    hass.config_entries.async_reload(entry.entry_id))

        elif msgtype == "playing":
            hass.async_create_task(plex_server.async_update_session(data))
        elif msgtype == "status":
            if data["StatusNotification"][0][
                    "title"] == "Library scan complete":
                async_dispatcher_send(
                    hass,
                    PLEX_UPDATE_LIBRARY_SIGNAL.format(server_id),
                )

    session = async_get_clientsession(hass)
    subscriptions = ["playing", "status"]
    verify_ssl = server_config.get(CONF_VERIFY_SSL)
    websocket = PlexWebsocket(
        plex_server.plex_server,
        plex_websocket_callback,
        subscriptions=subscriptions,
        session=session,
        verify_ssl=verify_ssl,
    )
    hass.data[PLEX_DOMAIN][WEBSOCKETS][server_id] = websocket

    def start_websocket_session(platform, _):
        hass.data[PLEX_DOMAIN][PLATFORMS_COMPLETED][server_id].add(platform)
        if hass.data[PLEX_DOMAIN][PLATFORMS_COMPLETED][server_id] == PLATFORMS:
            hass.loop.create_task(websocket.listen())

    def close_websocket_session(_):
        websocket.close()

    unsub = hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP,
                                       close_websocket_session)
    hass.data[PLEX_DOMAIN][DISPATCHERS][server_id].append(unsub)

    for platform in PLATFORMS:
        task = hass.async_create_task(
            hass.config_entries.async_forward_entry_setup(entry, platform))
        task.add_done_callback(partial(start_websocket_session, platform))

    async_cleanup_plex_devices(hass, entry)

    def get_plex_account(plex_server):
        try:
            return plex_server.account
        except (plexapi.exceptions.BadRequest,
                plexapi.exceptions.Unauthorized):
            return None

    await hass.async_add_executor_job(get_plex_account, plex_server)

    return True