SpotifyPlus Custom Integration

@stennajay
I agree that it seems like a chromecast problem trying to play the spotify content.

The doorbell play that you mentioned is odd to me though; why would it work, and the spotify not work if they are both in “sleep” mode? I want to dive deeper into that if you have the time to help. If we can determine how the doorbell is being “re-awakened” from sleep, then we should be able to mimic that functionality for the device that spotifyplus is trying to play media on.

Can you provide the yaml that’s used to call the media_player.play_media service to your doorbell, which re-awakens it? Can you also supply the Developer Tools \ States display for the doorbell both BEFORE you issue the service call (when it’s “sleeping”) as well as AFTER the service call (when it’s re-awakened)? I would like to compare the before and after states. Here’s an example of state display (my spotifyplus media player when it’s off) in case you have never used the developer tools states display:

Also, are there any special definitions in your Google Cast Integration settings for the doorbell device?


I assume that the doorbell is defined using the Google Cast integration; if not, what integration does it use?

With all that said, keep in mind that I do not own any ChromeCast devices and “flying blind” so to speak.

I’m experiencing an issue when performing the following:

  1. Press play on the Spotify desktop application – music plays through MacBook
  2. Change Spotify Connect device to iPhone – music now plays through iPhone
  3. Call “media_player.media_play” – music now plays through MacBook instead of iPhone

This behaviour occurs regardless of the setting of “Default Spotify Connect Player Device ID”. Is this expected/intended behaviour? This does not occur with the official Spotify integration.

@sowingseeds
When play_media is called, the integration verifies that a device name was selected from the source list. If no source was selected then the SpotifyPlus default device is activated.

If a source WAS selected, then a device name lookup is performed on the Spotify Connect Player device list to get the device ID. I believe this is what’s happening in your case.

The problem is that the Spotify Connect Player device list in the SpotifyPlus integration is only refreshed every 5 minutes if no actions are received by the HA media player. Since you are controlling the Spotify Connect Player OUTSIDE of HA (e.g. via your desktop app, mobile app, etc), the device list does not reflect the most current state.

I think I can correct this by refreshing the device list prior to playing the media. Let me see what I can do.

@sowingseeds
FYI - just released v1.0.18 of the SpotifyPlus integration

  • Updated various media_player services that control playback to verify a Spotify Connect Player device is active. If there is no active device, or the default device was specified (e.g. “*”), then we will force the configuration option default device to be used and transfer playback to it. If an active device was found, then we will use it without transferring playback for services that do not specify a deviceId argument (e.g. play, pause, seek, etc). For services that can supply a deviceId argument (e.g. play favorites, play context, play tracks), we will issue a transfer playback command if a device id (or name) was specified.

Thank you so much Todd for sorting this within hours! The update has fixed the issue and the integration is now perfect for my use case. Thanks again!

1 Like

@thlucas Thank you for this! I am having issues getting past Step 4a. I have entered my Client ID and Client Secret in to the Applications Credentials page. When I go back to Devices & services and then click on “Add Integration”, I click on Spotifyplus. That brings up a pop up to open an external website. When I click on that, I get a page with the following error:

INVALID_CLIENT: Invalid redirect URL

I have removed my client ID and client secret information from the following URL but this is what Home Assistant is trying to load once I click on that link:

https://accounts.spotify.com/authorize?response_type=code&client_id=xxxxxxxxxxxxxxxxxx&redirect_uri=https://my.home-assistant.io/redirect/oauth&state=xxxxxxxxxx.xxxxxxxxxx.xxxxxxxxxxx.xxxxxxxxxx.xxxxxxxxxx&scope=playlist-modify-private,playlist-modify-public,playlist-read-collaborative,playlist-read-private,ugc-image-upload,user-follow-modify,user-follow-read,user-library-modify,user-library-read,user-modify-playback-state,user-read-currently-playing,user-read-email,user-read-playback-position,user-read-playback-state,user-read-private,user-read-recently-played,user-top-read&show_dialog=true

Any thoughts why this is occurring? I’m sure I’ve done something wrong being somewhat of a noob here, but for the life of me I cannot figure out what I’ve done wrong. I have removed ALL of my current Spotify integrations and started over again but I simply cannot get this working.

Just a further update, it looks like the Developer Page is not happy with the redirect URI

https://my.home-assistant.io/redirect/oauth

@staceydodds
You are on the right track … the problem is the Redirect URI in your Spotify Developer App settings.

Just to verify, you did complete Step 2b Create Application as well as Step 3a - Add Application Credential(s) to add the application credentials? I assume so as you mentioned you had the client id and secret values, but wanted to confirm.

As for the Redirect URI, the https://my.home-assistant.io/redirect/oauth is the correct value. If you are copying / pasting, then make sure that you paste as “plain text” (to remove html formatting) and that there are no extra spaces before / after the value. Also ensure there is no trailing slash on the redirect uri value.

Here is what I have for my redirect uri settings - note that the localhost entries are not required, as I use those for testing the underlying API from Python processes outside of home assistant. Also, the website value can be any valid web site, so the https://www.home-assistant.io/ value you have is fine.

@staceydodds
You will also want to ensure you have the Web API checked in your Spotify Developer App settings.
image

Thank you @thlucas unfortunately none of those suggestions helped. I have deleted and created too many Spotify Apps today and I’m on a 24 hold now LOL. I guess I will keep testing tomorrow.

I even went so far as to remove my regular Spotify Integration completely. I was able to re-add it back with no difficultly but I am still having issues with the INVALID_CLIENT: Invalid redirect URL error and I’m at a total loss.

@thlucas the plot thickens. Just for fun, I completely killed off my basic Spotify integration and wiped all of my Spotify application credentials and started over. This time, I used the basic Spotify App credentials I had created for my original Integration, however I used them for the SpotifyPlus integration. That worked perfectly fine. Now I’m totally baffled.

@staceydodds
You can use the same Spotify Developer Application (Client ID and Secret) that you use for the HA Spotify (not SpotifyPlus) integration. You just have to create two separate HA OAuth Application Credentials (one for Spotify and one for SpotifyPlus) as each integration requires a separate token value to access the Spotify Web API. This allows you to use both Spotify and SpotifyPlus integrations at the same time for comparison if you like. You also have to make sure that the https://my.home-assistant.io/redirect/oauth is in the Redirect URI list of the Spotify Developer Application.

If using multiple Spotify user accounts … you will need to create a separate Spotify Developer Application for each Spotify user account that you wish to access from HA, regardless of membership level (premium or free). This allows you to access the Spotify Web API for each account separately.

For example, here are the HA OAuth Application Credentials I have defined in my environment:

I share my PREMIUM account between Spotify and SpotifyPlus (same Client ID and Secret, two separate HA OAuth Application Credentials), and also have a FREE account defined for SpotifyPlus (for testing - cannot use a FREE account to control the player).

This allows me to run both the Spotify and SpotifyPlus media players at the same time, like so:

SpotifyPlus Dashboard YAML:

type: media-control
entity: media_player.spotifyplus_todd_l

Spotify Dashboard YAML:

type: media-control
entity: media_player.spotify_todd_l
1 Like

@thlucas brilliant Todd. Thank you for explaining that. Once I am able to make another Spotify App on my main account I will try that out. I have this working with my family account (I have Spotify Premium Duo) and I have to say the first thing I noticed is how much faster this works! If I skip tracks using my phone, the “Now Playing” media card I have on my dashboard updates nearly immediately. With the standard Spotify integration, that refresh time was much, much longer. Fascinating that your integration is working so much faster.

1 Like

@staceydodds
Thank you for the kind words.

The Player Status wiki document explains in more detail how the status update logic works if you are interested. Note that it can still take up to 30 seconds to update the HA media player status if you are controlling the Spotify Connect Player outside of the HA UI (e.g. via Spotify mobile / desktop / web app).

1 Like

FYI - just released v1.0.19 of the SpotifyPlus integration

  • Changed all media_player.async_write_ha_state() calls to schedule_update_ha_state(force_refresh=True) calls due to HA 2024.5 release requirements. This fixes the issue of “Failed to call service X. Detected that custom integration ‘Y’ calls async_write_ha_state from a thread at Z. Please report it to the author of the ‘Y’ custom integration.”.
  • Added more information to system health display (version, integration configs, etc).
  • Updated Python version from 3.11 to 3.12.3 due to HA 2024.5 release requirements.

Account Linking is not possible (Step 4e)
image

I found the issue, if you use https you need to change http to https in this Screen Window

@stephanschleichstr13
I did not see any links in your response - are you talking about this window:

If so, that is the redirect uri and it should contain an https:// prefix (e.g. https://my.home-assistant.io/redirect/oauth).

Are you saying you had to switch it to an http:// prefix?

Just want to confirm so that I can update my documentation if need be.

Please let me know, and thanks.

On the bottom you See your Instant Link ishttp://homeassistent.local…
When you use HTTPS you need to correct this URL manually than it works or Update the URL to HTTPS on the Screen later

Ahhhh, I see it now. Thanks for bringing that to my attention. I will update the documentation.

Edit: docs updated. Thanks again @stephanschleichstr13

1 Like

EDIT: don’t consider my message, I didn’t have the latest update, now after updating to 1.0.19 everything is ok no log errors on startup

My message is now useless:
I’m getting these 2 errors in the logs, which I don’t know how to understand, I thought I’d share it if it helps.
For me, despite this error in the log, this morning the integration worked.

Registratore: homeassistant
Fonte: helpers/frame.py:203
Prima occorrenza: 08:00:49 (1 occorrenze)
Ultima registrazione: 08:00:49

Error doing job: Task exception was never retrieved
Traceback (most recent call last):
  File "/usr/src/homeassistant/homeassistant/components/script/__init__.py", line 643, in _async_run
    return await self.script.async_run(script_vars, context)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 1731, in async_run
    return await asyncio.shield(create_eager_task(run.async_run()))
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 451, in async_run
    await self._async_step(log_exceptions=False)
  File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 503, in _async_step
    self._handle_exception(
  File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 533, in _handle_exception
    raise exception
  File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 501, in _async_step
    await getattr(self, handler)()
  File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 736, in _async_call_service_step
    response_data = await self._async_run_long_action(
                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 699, in _async_run_long_action
    return await long_task
           ^^^^^^^^^^^^^^^
  File "/usr/src/homeassistant/homeassistant/core.py", line 2738, in async_call
    response_data = await coro
                    ^^^^^^^^^^
  File "/usr/src/homeassistant/homeassistant/core.py", line 2779, in _execute_service
    return await target(service_call)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/config/custom_components/spotifyplus/__init__.py", line 702, in service_handle_spotify_command
    await hass.async_add_executor_job(entity.service_spotify_player_transfer_playback, device_id, play)
  File "/usr/local/lib/python3.12/concurrent/futures/thread.py", line 58, in run
    result = self.fn(*self.args, **self.kwargs)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/config/custom_components/spotifyplus/media_player.py", line 2960, in service_spotify_player_transfer_playback
    self.async_write_ha_state()
  File "/usr/src/homeassistant/homeassistant/helpers/entity.py", line 1008, in async_write_ha_state
    self.hass.verify_event_loop_thread("async_write_ha_state")
  File "/usr/src/homeassistant/homeassistant/core.py", line 440, in verify_event_loop_thread
    frame.report(
  File "/usr/src/homeassistant/homeassistant/helpers/frame.py", line 162, in report
    _report_integration(what, integration_frame, level, error_if_integration)
  File "/usr/src/homeassistant/homeassistant/helpers/frame.py", line 203, in _report_integration
    raise RuntimeError(
RuntimeError: Detected that custom integration 'spotifyplus' calls async_write_ha_state from a thread at custom_components/spotifyplus/media_player.py, line 2960: self.async_write_ha_state(). Please report it to the author of the 'spotifyplus' custom integration.
Registratore: homeassistant.components.script.bose_spotify_diegocampy
Fonte: helpers/script.py:501
Integrazione: Script (documentazione, problemi)
Prima occorrenza: 08:00:49 (1 occorrenze)
Ultima registrazione: 08:00:49

Bose Spotify Diegocampy: Error executing script. Unexpected error for call_service at pos 1: Detected that custom integration 'spotifyplus' calls async_write_ha_state from a thread at custom_components/spotifyplus/media_player.py, line 2960: self.async_write_ha_state(). Please report it to the author of the 'spotifyplus' custom integration.
Traceback (most recent call last):
  File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 501, in _async_step
    await getattr(self, handler)()
  File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 736, in _async_call_service_step
    response_data = await self._async_run_long_action(
                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 699, in _async_run_long_action
    return await long_task
           ^^^^^^^^^^^^^^^
  File "/usr/src/homeassistant/homeassistant/core.py", line 2738, in async_call
    response_data = await coro
                    ^^^^^^^^^^
  File "/usr/src/homeassistant/homeassistant/core.py", line 2779, in _execute_service
    return await target(service_call)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/config/custom_components/spotifyplus/__init__.py", line 702, in service_handle_spotify_command
    await hass.async_add_executor_job(entity.service_spotify_player_transfer_playback, device_id, play)
  File "/usr/local/lib/python3.12/concurrent/futures/thread.py", line 58, in run
    result = self.fn(*self.args, **self.kwargs)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/config/custom_components/spotifyplus/media_player.py", line 2960, in service_spotify_player_transfer_playback
    self.async_write_ha_state()
  File "/usr/src/homeassistant/homeassistant/helpers/entity.py", line 1008, in async_write_ha_state
    self.hass.verify_event_loop_thread("async_write_ha_state")
  File "/usr/src/homeassistant/homeassistant/core.py", line 440, in verify_event_loop_thread
    frame.report(
  File "/usr/src/homeassistant/homeassistant/helpers/frame.py", line 162, in report
    _report_integration(what, integration_frame, level, error_if_integration)
  File "/usr/src/homeassistant/homeassistant/helpers/frame.py", line 203, in _report_integration
    raise RuntimeError(
RuntimeError: Detected that custom integration 'spotifyplus' calls async_write_ha_state from a thread at custom_components/spotifyplus/media_player.py, line 2960: self.async_write_ha_state(). Please report it to the author of the 'spotifyplus' custom integration.
1 Like