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
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
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
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